Added Gnus pkg subtree
authorSteve Youngs <steve@sxemacs.org>
Sun, 12 Jun 2016 11:03:27 +0000 (21:03 +1000)
committerSteve Youngs <steve@sxemacs.org>
Sun, 12 Jun 2016 11:03:27 +0000 (21:03 +1000)
Signed-off-by: Steve Youngs <steve@sxemacs.org>
666 files changed:
xemacs-packages/gnus/.arch-inventory [new file with mode: 0644]
xemacs-packages/gnus/.dir-locals.el [new file with mode: 0644]
xemacs-packages/gnus/.gitignore [new file with mode: 0644]
xemacs-packages/gnus/COPYING [new file with mode: 0644]
xemacs-packages/gnus/ChangeLog [new file with mode: 0644]
xemacs-packages/gnus/GNUS-NEWS [new file with mode: 0644]
xemacs-packages/gnus/Makefile.in [new file with mode: 0644]
xemacs-packages/gnus/README [new file with mode: 0644]
xemacs-packages/gnus/aclocal.m4 [new file with mode: 0644]
xemacs-packages/gnus/configure [new file with mode: 0755]
xemacs-packages/gnus/configure.in [new file with mode: 0644]
xemacs-packages/gnus/contrib/ChangeLog [new file with mode: 0644]
xemacs-packages/gnus/contrib/README [new file with mode: 0644]
xemacs-packages/gnus/contrib/compface.el [new file with mode: 0644]
xemacs-packages/gnus/contrib/gnus-kill-to-score.el [new file with mode: 0644]
xemacs-packages/gnus/contrib/gnus-namazu.el [new file with mode: 0644]
xemacs-packages/gnus/contrib/smime-card.el [new file with mode: 0644]
xemacs-packages/gnus/contrib/vcard.el [new file with mode: 0644]
xemacs-packages/gnus/etc/ChangeLog [new file with mode: 0644]
xemacs-packages/gnus/etc/Makefile.in [new file with mode: 0644]
xemacs-packages/gnus/etc/gnus-tut.txt [new file with mode: 0644]
xemacs-packages/gnus/etc/gnus/gnus-setup.ast [new file with mode: 0644]
xemacs-packages/gnus/etc/gnus/news-server.ast [new file with mode: 0644]
xemacs-packages/gnus/etc/images/GNUS-README [new file with mode: 0644]
xemacs-packages/gnus/etc/images/README [new file with mode: 0644]
xemacs-packages/gnus/etc/images/attach.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/cancel.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/close.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/connect.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/contact.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/contact.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/copy.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/cut.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/delete.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/delete.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/describe.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/diropen.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/disconnect.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/exit.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/README [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/catchup.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/catchup.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/cu-exit.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/cu-exit.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/describe-group.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/describe-group.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/exit-gnus.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/exit-gnus.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/exit-summ.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/exit-summ.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/followup.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/followup.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/fuwo.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/fuwo.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/get-news.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/get-news.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnntg.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnntg.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-group-catchup-current-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-group-catchup-current-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-group-catchup-current.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-group-catchup-current.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-group-describe-group-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-group-describe-group-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-group-exit-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-group-exit-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-group-get-new-news-this-group-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-group-get-new-news-this-group-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-group-get-new-news-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-group-get-new-news-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-group-kill-group-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-group-kill-group-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-group-subscribe-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-group-subscribe-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-group-unsubscribe-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-group-unsubscribe-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-pointer.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-pointer.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-caesar-message-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-caesar-message-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-cancel-article-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-cancel-article-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-catchup-and-exit-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-catchup-and-exit-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-catchup-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-catchup-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-exit-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-exit-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-followup-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-followup-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-followup-with-original-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-followup-with-original-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-copy-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-copy-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-delete-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-delete-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-forward-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-forward-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-get-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-get-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-originate-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-originate-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-reply-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-reply-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-save-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-save-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-next-unread-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-next-unread-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-post-news-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-post-news-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-prev-unread-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-prev-unread-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-reply-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-reply-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-reply-with-original-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-reply-with-original-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-save-article-file-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-save-article-file-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-save-article-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-summary-save-article-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-uu-decode-uu-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-uu-decode-uu-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-uu-post-news-up.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus-uu-post-news-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus.png [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus.svg [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/gnus.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/important.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/kill-group.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/kill-group.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/mail-reply.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/mail-reply.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/mail-send.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/next-ur.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/next-ur.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/oort.xface [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/post.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/post.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/prev-ur.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/prev-ur.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/preview.xbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/preview.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/receipt.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/reply-wo.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/reply-wo.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/reply.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/reply.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/rot13.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/rot13.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/save-aif.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/save-aif.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/save-art.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/save-art.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/subscribe.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/subscribe.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/toggle-subscription.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/unimportant.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/unsubscribe.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/unsubscribe.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/uu-decode.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/uu-decode.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/uu-post.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/gnus/uu-post.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/help.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/home.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/index.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/jump-to.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/left-arrow.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/lock-broken.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/lock-ok.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/lock.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/mail/README [new file with mode: 0644]
xemacs-packages/gnus/etc/images/mail/compose.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/mail/copy.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/mail/forward.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/mail/inbox.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/mail/inbox.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/mail/move.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/mail/move.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/mail/not-spam.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/mail/outbox.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/mail/preview.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/mail/reply-all.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/mail/reply.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/mail/save-draft.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/mail/save.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/mail/send.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/mail/spam.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/new.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/next-node.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/next-page.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/next-page.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/open.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/paste.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/preferences.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/prev-node.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/print.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/redo.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/refresh.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/right-arrow.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/save.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/saveas.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/search.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/separator.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/README [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/blink.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/blink.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/braindamaged.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/cry.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/dead.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/evil.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/forced.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/frown.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/frown.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/grayscale/README [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/grayscale/blink.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/grayscale/braindamaged.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/grayscale/cry.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/grayscale/dead.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/grayscale/evil.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/grayscale/forced.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/grayscale/frown.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/grayscale/grin.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/grayscale/indifferent.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/grayscale/reverse-smile.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/grayscale/sad.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/grayscale/smile.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/grayscale/wry.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/grin.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/indifferent.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/medium/README [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/medium/blink.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/medium/braindamaged.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/medium/cry.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/medium/dead.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/medium/evil.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/medium/forced.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/medium/frown.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/medium/grin.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/medium/indifferent.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/medium/reverse-smile.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/medium/sad.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/medium/smile.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/medium/wry.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/sad.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/sad.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/smile.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/smile.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/wry.pbm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/smilies/wry.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/sort-ascending.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/sort-column-ascending.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/sort-criteria.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/sort-descending.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/sort-row-ascending.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/spell.xpm [new file with mode: 0644]
xemacs-packages/gnus/etc/images/splash.png [new file with mode: 0644]
xemacs-packages/gnus/etc/images/splash.svg [new file with mode: 0644]
xemacs-packages/gnus/etc/post-receive [new file with mode: 0755]
xemacs-packages/gnus/install-sh [new file with mode: 0755]
xemacs-packages/gnus/lisp/.dir-locals.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/ChangeLog [new file with mode: 0644]
xemacs-packages/gnus/lisp/ChangeLog.1 [new file with mode: 0644]
xemacs-packages/gnus/lisp/ChangeLog.2 [new file with mode: 0644]
xemacs-packages/gnus/lisp/Makefile.in [new file with mode: 0644]
xemacs-packages/gnus/lisp/assistant.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/auth-source.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/binhex.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/canlock.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/color.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/compface.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/deuglify.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/dgnushack.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/dig.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/dns-mode.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/dns.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/ecomplete.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/flow-fill.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/format-spec.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gmm-utils.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-agent.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-art.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-async.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-bcklg.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-bookmark.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-cache.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-cite.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-cloud.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-compat.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-cus.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-delay.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-demon.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-diary.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-dired.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-draft.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-dup.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-eform.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-ems.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-fallback-lib/eieio/eieio-base.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-fallback-lib/eieio/eieio-comp.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-fallback-lib/eieio/eieio-custom.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-fallback-lib/eieio/eieio-datadebug.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-fallback-lib/eieio/eieio-opt.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-fallback-lib/eieio/eieio-speedbar.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-fallback-lib/eieio/eieio.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-fallback-lib/json.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-fun.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-gravatar.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-group.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-html.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-icalendar.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-int.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-kill.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-logic.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-mh.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-ml.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-mlspl.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-msg.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-notifications.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-picon.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-range.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-registry.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-salt.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-score.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-sieve.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-spec.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-srvr.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-start.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-sum.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-sync.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-topic.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-undo.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-util.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-uu.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-vm.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-win.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus-xmas.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gnus.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gravatar.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/gssapi.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/hashcash.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/hex-util.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/hmac-def.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/hmac-md5.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/html2text.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/ietf-drums.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/imap.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/legacy-gnus-agent.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/lpath.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/mail-parse.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/mail-prsvr.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/mail-source.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/mailcap.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/md4.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/message.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/messagexmas.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/messcompat.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/mm-archive.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/mm-bodies.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/mm-decode.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/mm-encode.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/mm-extern.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/mm-partial.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/mm-url.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/mm-util.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/mm-uu.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/mm-view.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/mml-sec.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/mml-smime.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/mml.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/mml1991.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/mml2015.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/netrc.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nnagent.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nnbabyl.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nndiary.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nndir.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nndoc.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nndraft.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nneething.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nnfolder.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nngateway.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nnheader.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nnheaderxm.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nnimap.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nnir.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nnmail.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nnmaildir.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nnmairix.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nnmbox.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nnmh.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nnml.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nnnil.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nnoo.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nnregistry.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nnrss.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nnspool.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nntp.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nnvirtual.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/nnweb.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/ntlm.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/parse-time.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/password-cache.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/plstore.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/pop3.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/proto-stream.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/qp.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/registry.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/rfc1843.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/rfc2045.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/rfc2047.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/rfc2104.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/rfc2231.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/rtree.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/sasl-cram.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/sasl-digest.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/sasl-ntlm.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/sasl-scram-rfc.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/sasl.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/score-mode.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/sha1.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/sieve-manage.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/sieve-mode.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/sieve.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/smiley.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/smime-ldap.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/smime.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/spam-report.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/spam-stat.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/spam-wash.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/spam.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/starttls.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/gnustest-gnus-util.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/gnustest-mml-sec.README [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/gnustest-mml-sec.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/gnustest-nntp.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/gnustest-registry.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/.gpg-v21-migrated [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/gpg-agent.conf [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/02089CDDC6DFE93B8EA10D9E876F983E61FEC476.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/171B444DE92BEF997229000D9784118A94EEC1C9.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/19FFEBC04DF3E037E16F6A4474DCB7984406975D.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/1E36D27DF9DAB96302D35268DADC5CE73EF45A2A.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/293109315BE584AB2EFEFCFCAD64666221D8B36C.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/335689599E1C0F66D73ADCF51E03EE36C97D121F.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/40BF94E540E3726CB150A1ADF7C1B514444B3FA6.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/515D4637EFC6C09DB1F78BE8C2F2A3D63E7756C3.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/5A11B1935C46D0B227A73978DCA1293A85604F1D.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/62643CEBC7AEBE6817577A34399483700D76BD64.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/680D01F368916A0021C14E3453B27B3C5F900683.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/6DF2D9DF7AED06F0524BEB642DF0FB48EFDBDB93.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/78C17E134E86E691297F7B719B2F2CDF41976234.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/7F714F4D9D9676638214991E96D45704E4FFC409.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/854752F5D8090CA36EFBDD79C72BDFF6FA2D1FF0.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/93FF37C268FDBF0767F5FFDC49409DDAC9388B2C.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/A3BA94EAE83509CC90DB1B77B54A51959D8DABEA.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/A73E9D01F0465B518E8E7D5AD529077AAC1603B4.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/AE6A24B17A8D0CAF9B7E000AA77F0B41D7BFFFCF.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/C072AF82DCCCB9A7F1B85FFA10B802DC4ED16703.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/C43E1A079B28DFAEBB39CBA01793BDE11EF4B490.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/C67DAD345455EAD6D51368008FC3A53B8D195B5A.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/CB5E00CE582C2645D2573FC16B2F14F85A7F47AA.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/CC68630A06B048F5A91136C162C7A3273E20DE6F.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/E7E73903E1BF93481DE0E7C9769D6C31E1863CFF.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/F0117468BE801ED4B81972E159A98FDD4814DCEC.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/F4C5EFD5779BE892CAFD5B721D68DED677C9B151.key [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/pubring.gpg [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/pubring.gpg~ [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/pubring.kbx [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/pubring.kbx~ [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/secring.gpg [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/trustdb.gpg [new file with mode: 0644]
xemacs-packages/gnus/lisp/tests/mml-gpghome/trustlist.txt [new file with mode: 0644]
xemacs-packages/gnus/lisp/time-date.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/tls.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/utf7.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/uudecode.el [new file with mode: 0644]
xemacs-packages/gnus/lisp/yenc.el [new file with mode: 0644]
xemacs-packages/gnus/make.bat [new file with mode: 0644]
xemacs-packages/gnus/makepub [new file with mode: 0755]
xemacs-packages/gnus/mkinstalldirs [new file with mode: 0755]
xemacs-packages/gnus/texi/.gitignore [new file with mode: 0644]
xemacs-packages/gnus/texi/ChangeLog [new file with mode: 0644]
xemacs-packages/gnus/texi/Makefile.in [new file with mode: 0644]
xemacs-packages/gnus/texi/auth.texi [new file with mode: 0644]
xemacs-packages/gnus/texi/dir [new file with mode: 0644]
xemacs-packages/gnus/texi/doclicense.texi [new file with mode: 0644]
xemacs-packages/gnus/texi/docstyle.texi [new file with mode: 0644]
xemacs-packages/gnus/texi/emacs-mime.texi [new file with mode: 0644]
xemacs-packages/gnus/texi/epa.texi [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/bar.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-group-catchup-current-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-group-catchup-current.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-group-describe-group-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-group-exit-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-group-get-new-news-this-group-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-group-get-new-news-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-group-kill-group-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-group-subscribe-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-group-unsubscribe-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-summary-caesar-message-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-summary-cancel-article-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-summary-catchup-and-exit-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-summary-catchup-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-summary-exit-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-summary-followup-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-summary-followup-with-original-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-summary-mail-copy-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-summary-mail-delete-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-summary-mail-forward-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-summary-mail-get-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-summary-mail-originate-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-summary-mail-reply-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-summary-mail-save-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-summary-next-unread-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-summary-post-news-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-summary-prev-unread-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-summary-reply-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-summary-reply-with-original-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-summary-save-article-file-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-summary-save-article-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-uu-decode-uu-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus-uu-post-news-up.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/etc/gnus.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/gnus-coding.texi [new file with mode: 0644]
xemacs-packages/gnus/texi/gnus-faq.texi [new file with mode: 0644]
xemacs-packages/gnus/texi/gnus-logo.eps [new file with mode: 0644]
xemacs-packages/gnus/texi/gnus-news.el [new file with mode: 0644]
xemacs-packages/gnus/texi/gnus-news.texi [new file with mode: 0644]
xemacs-packages/gnus/texi/gnus-overrides.texi [new file with mode: 0644]
xemacs-packages/gnus/texi/gnus-refcard.tex [new file with mode: 0644]
xemacs-packages/gnus/texi/gnus.texi [new file with mode: 0644]
xemacs-packages/gnus/texi/gnusconfig.tex.in [new file with mode: 0644]
xemacs-packages/gnus/texi/herds/convol11.pnm [new file with mode: 0644]
xemacs-packages/gnus/texi/herds/convol5.pnm [new file with mode: 0644]
xemacs-packages/gnus/texi/herds/gnus-herd-bw.png [new file with mode: 0644]
xemacs-packages/gnus/texi/herds/gnus-herd-new.png [new file with mode: 0644]
xemacs-packages/gnus/texi/herds/new-herd-1.png [new file with mode: 0644]
xemacs-packages/gnus/texi/herds/new-herd-2.png [new file with mode: 0644]
xemacs-packages/gnus/texi/herds/new-herd-3.png [new file with mode: 0644]
xemacs-packages/gnus/texi/herds/new-herd-4.png [new file with mode: 0644]
xemacs-packages/gnus/texi/herds/new-herd-5.png [new file with mode: 0644]
xemacs-packages/gnus/texi/herds/new-herd-6.png [new file with mode: 0644]
xemacs-packages/gnus/texi/herds/new-herd-7.png [new file with mode: 0644]
xemacs-packages/gnus/texi/herds/new-herd-8.png [new file with mode: 0644]
xemacs-packages/gnus/texi/herds/new-herd-9.png [new file with mode: 0644]
xemacs-packages/gnus/texi/herds/new-herd-section.png [new file with mode: 0644]
xemacs-packages/gnus/texi/herds/new-herd.png [new file with mode: 0644]
xemacs-packages/gnus/texi/herds/new-herd2.png [new file with mode: 0644]
xemacs-packages/gnus/texi/infohack.el [new file with mode: 0644]
xemacs-packages/gnus/texi/message.texi [new file with mode: 0644]
xemacs-packages/gnus/texi/misc/ered.tif [new file with mode: 0644]
xemacs-packages/gnus/texi/misc/eseptember.tif [new file with mode: 0644]
xemacs-packages/gnus/texi/misc/fred.tif [new file with mode: 0644]
xemacs-packages/gnus/texi/misc/fseptember.tif [new file with mode: 0644]
xemacs-packages/gnus/texi/misc/larsi.png [new file with mode: 0644]
xemacs-packages/gnus/texi/misc/red.png [new file with mode: 0644]
xemacs-packages/gnus/texi/misc/red.ps [new file with mode: 0644]
xemacs-packages/gnus/texi/misc/september.png [new file with mode: 0644]
xemacs-packages/gnus/texi/pagestyle.sty [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/att.png [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/berkeley.png [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/caltech.png [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/canada.png [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/cr.png [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/cygnus.xbm [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/gnu.xbm [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/gov.xbm [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/laurie.png [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/mit.png [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/nasa.png [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/qmw.xbm [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/rms.png [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/ruu.xbm [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/seuu.xbm [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/stanford.png [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/sun.png [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/ubc.xbm [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/ufl.png [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/uio.png [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/unit.png [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/upenn.xbm [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/wesleyan.xbm [new file with mode: 0644]
xemacs-packages/gnus/texi/picons/yale.xbm [new file with mode: 0644]
xemacs-packages/gnus/texi/pixidx.sty [new file with mode: 0644]
xemacs-packages/gnus/texi/postamble.tex [new file with mode: 0644]
xemacs-packages/gnus/texi/ps/Makefile.in [new file with mode: 0644]
xemacs-packages/gnus/texi/ps/gnus-big-logo.eps [new file with mode: 0644]
xemacs-packages/gnus/texi/ps/gnus-head.eps [new file with mode: 0644]
xemacs-packages/gnus/texi/sasl.texi [new file with mode: 0644]
xemacs-packages/gnus/texi/screen/group-topic.png [new file with mode: 0644]
xemacs-packages/gnus/texi/screen/group.png [new file with mode: 0644]
xemacs-packages/gnus/texi/screen/server.png [new file with mode: 0644]
xemacs-packages/gnus/texi/screen/summary-adopt.png [new file with mode: 0644]
xemacs-packages/gnus/texi/screen/summary-article-c-ug.png [new file with mode: 0644]
xemacs-packages/gnus/texi/screen/summary-article.png [new file with mode: 0644]
xemacs-packages/gnus/texi/screen/summary-dummy.png [new file with mode: 0644]
xemacs-packages/gnus/texi/screen/summary-empty.png [new file with mode: 0644]
xemacs-packages/gnus/texi/screen/summary-none.png [new file with mode: 0644]
xemacs-packages/gnus/texi/screen/summary-unthreaded.png [new file with mode: 0644]
xemacs-packages/gnus/texi/screen/summary.png [new file with mode: 0644]
xemacs-packages/gnus/texi/sieve.texi [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/BigFace.tif [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/FaceAngry.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/FaceDevilish.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/FaceGoofy.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/FaceGrinning.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/FaceHappy.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/FaceIronic.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/FaceKOed.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/FaceNyah.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/FaceSad.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/FaceStartled.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/FaceStraight.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/FaceTalking.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/FaceTasty.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/FaceWinking.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/FaceWry.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/FaceYukky.xpm [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/WideFaceAse1.xbm [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/WideFaceAse2.xbm [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/WideFaceAse3.xbm [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/WideFaceSmile.xbm [new file with mode: 0644]
xemacs-packages/gnus/texi/smilies/WideFaceWeep.xbm [new file with mode: 0644]
xemacs-packages/gnus/texi/splitindex [new file with mode: 0755]
xemacs-packages/gnus/texi/texi2latex.el [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/abrahamsen.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/aichner.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/blanks.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/cosgriff.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/drazen.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/gertzfield.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/goldberg.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/graf.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/hardaker.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/hedbor.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/ingrand.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/kaplan.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/karlheg.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/kleinpaste.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/kyle.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/love.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/moll.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/niksic.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/olsen.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/patch.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/petersen.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/pjf.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/riocreux.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/schauer.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/simmonmt.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/simmons.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/siu.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/smb.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/sobek.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/thomas.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/valdis.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/verna1.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/verna2.png [new file with mode: 0644]
xemacs-packages/gnus/texi/xface/yamaoka.png [new file with mode: 0644]
xemacs-packages/gnus/todo [new file with mode: 0644]
xemacs-packages/gnus/www/ChangeLog [new file with mode: 0644]
xemacs-packages/gnus/www/git.gnus.org/gnus-cgit.png [new file with mode: 0644]
xemacs-packages/gnus/www/git.gnus.org/gnus-icon.png [new file with mode: 0644]
xemacs-packages/gnus/www/git.gnus.org/index.html [new file with mode: 0644]

diff --git a/xemacs-packages/gnus/.arch-inventory b/xemacs-packages/gnus/.arch-inventory
new file mode 100644 (file)
index 0000000..059a4f0
--- /dev/null
@@ -0,0 +1,4 @@
+# Generated files
+precious ^(configure|config\.status|config\.cache)$
+
+# arch-tag: 62f59105-7e14-4869-a14d-1030bd187a09
diff --git a/xemacs-packages/gnus/.dir-locals.el b/xemacs-packages/gnus/.dir-locals.el
new file mode 100644 (file)
index 0000000..5c23097
--- /dev/null
@@ -0,0 +1,7 @@
+((nil . ((tab-width . 8)
+         (fill-column . 70)))
+ (c-mode . ((c-file-style . "GNU")))
+ (change-log-mode . ((add-log-time-zone-rule . t)
+                    (fill-column . 74)
+                    (bug-reference-url-format
+                      . "http://emacsbugs.donarmstrong.com/cgi-bin/bugreport.cgi?bug=%s"))))
diff --git a/xemacs-packages/gnus/.gitignore b/xemacs-packages/gnus/.gitignore
new file mode 100644 (file)
index 0000000..5e2b6b7
--- /dev/null
@@ -0,0 +1,80 @@
+/Makefile
+/autom4te.cache
+/config.cache
+/config.log
+/config.status
+/diff-lisp.el
+/diffit
+/cvs-access
+/cup-page
+/admin
+/oort
+/pgg
+/smilies
+/makepub-beta
+contrib/gnus-mdrtn.el
+contrib/on-loginfo
+contrib/request-assign.future
+etc/Makefile
+.gitattributes
+lisp/.gitattributes
+lisp/*.elc
+lisp/*.rej
+lisp/Makefile
+lisp/TAGS
+lisp/auto-autoloads.el
+lisp/custom-load.el
+lisp/gnus-load.el
+lisp/old
+lisp/semantic.cache
+lisp/version
+texi/.gitattributes
+texi/Makefile
+texi/auth
+texi/emacs-mime
+texi/gnus
+texi/gnus-[0-9]*
+texi/message
+texi/message-[0-9]*
+texi/sasl
+texi/sieve
+texi/pgg
+texi/gnustmp.texi
+texi/*.dvi
+texi/*.dvi-x
+texi/*.pdf-x
+texi/*.log
+texi/*.aux
+texi/*.latexi
+texi/gnus.ps
+texi/gnus.pdf
+texi/gnus.out
+texi/gnusmail.texi
+texi/pspackage.tar.gz
+texi/gnus.tmplatexi
+texi/gnus.gind
+texi/gnus.cind
+texi/gnus.ilg
+texi/gnus.kind
+texi/gnus.cidx
+texi/gnus.gidx
+texi/gnus.kidx
+texi/gnus.toc
+texi/gnus.idx
+texi/gnus.tmplatexi1
+texi/picons.tex
+texi/xface.tex
+texi/smiley.tex
+texi/gnusconfig.tex
+texi/old
+texi/thumb*
+texi/auto
+texi/*.tpt
+texi/gnus-coding
+texi/ps/*.ps
+texi/ps/*.pdf
+texi/ps/Makefile
+lisp/*.orig
+texi/*.orig
+texi/*.info
+++log
diff --git a/xemacs-packages/gnus/COPYING b/xemacs-packages/gnus/COPYING
new file mode 100644 (file)
index 0000000..94a9ed0
--- /dev/null
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/xemacs-packages/gnus/ChangeLog b/xemacs-packages/gnus/ChangeLog
new file mode 100644 (file)
index 0000000..5f41b90
--- /dev/null
@@ -0,0 +1,913 @@
+2014-06-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * configure.in: Add --without-compress-install option; check for gzip.
+
+       * Makefile.in (GZIP_PROG): Be substituted by configure.
+
+2014-01-31  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * make.bat (REM FIXME): Remove mention of outdated w3.
+
+       * aclocal.m4 (AC_EMACS_CHECK_LIB): Remove checks for w3 and url.  w3 is
+       outdated, and all Emacs versions Ma Gnus builds against has url.el.
+
+2013-06-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * configure.in: Work for term-mode running in Emacs.
+
+2011-11-20  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * etc/gnus/news-server.ast (Setting up the news server name and port
+       number): Spelling fix.
+
+2011-11-15  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * etc/gnus-tut.txt (<lars-doc6@eyesore.no>): Spelling fix.
+
+2011-04-07  David Engster  <dengste@eml.cc>
+
+       * Makefile.in (check): New rule for starting test-suite.
+
+2011-04-06  David Engster  <dengste@eml.cc>
+
+       * Makefile.in (lick-fail-on-warning): New rule to compile with warnings
+       as errors.
+       (fail-on-warning): Use it.
+
+2011-03-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * Makefile.in (warn): Add a dummy "warn" target.
+
+2010-10-21  Julien Danjou  <julien@danjou.info>
+
+       * todo: Remove done and duplicate items.
+
+2010-10-06  Julien Danjou  <julien@danjou.info>
+
+       * todo: Remove other broken links
+
+       * make.bat: Remove Windows 98 stuff and reference to my.gnus.org.
+
+2010-10-04  Andreas Schwab  <schwab@linux-m68k.org>
+
+       * configure.in: Fix help strings.
+
+2010-04-23  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * .gitignore: Remove configure from ignores.
+
+2010-04-22  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * configure: Regenerated from configure.in using Autoconf 2.65.
+
+2009-08-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * GNUS-NEWS: Generated.
+
+2009-01-22  Dan Nicolaescu  <dann@ics.uci.edu>
+
+       * .dir-locals.el: New file.
+
+2009-01-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * README: Add outline.  Clarify Emacs versions.
+
+2008-05-01  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * README: Bump version to 0.11
+
+2008-04-12  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Makefile.in (release-check-settings): Clarify codename.
+       (release-help): New target.
+       (release-cvs-export): Add umask.  Suggested by Sven Joachim.
+
+2008-04-11  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * README: Bump version to 0.9.
+
+2008-04-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * README: No Gnus v0.8 is released.
+
+2008-03-01  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Update copyright years.
+
+2008-02-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * GNUS-NEWS: Generated.
+
+       * Makefile.in (datarootdir): Define.
+
+       * aclocal.m4 (AC_PATH_LISPDIR): Quote directory name that might contain
+       whitespace.
+
+       * configure: Regenerate.
+
+       * mkinstalldirs: Replace it with the 2006-05-11.19 version.
+
+2008-01-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * GNUS-NEWS: Generated.
+
+2008-01-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * GNUS-NEWS: Generated.
+
+2007-11-18  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * GNUS-NEWS: Generated.
+
+2007-11-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Makefile.in (RELEASE_COMMIT_FILES): Add etc/ChangeLog.
+       (release-check-settings): Add release-add-changelog
+       (release-bump-version): Add check for CODENAME_TO_STABLE.  Split off
+       release-add-changelog.
+       (release-add-changelog): New target.  Separate some commands from
+       release-bump-version.  Add etc/ChangeLog.
+       (release-diff-commit-files): New target.
+       (RELEASE_COMMIT_FILES): Reorder files.
+
+2007-11-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * COPYING: GPLv3 from Emacs repository.
+
+2007-10-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Makefile.in (SED_I, CODENAME_PATTERN): New.
+       (OLD_PATTERN): Adjust.
+       (release-bump-version): Use new variables.  Allow going from
+       development version to release.
+
+2007-10-27  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Makefile.in (release-bump-version): Adjust version
+       in (gnus)Troubleshooting.
+
+2007-10-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * GNUS-NEWS: Generated.
+
+2007-10-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+        * Relicense "GPLv2 or later" files to "GPLv3 or later".
+
+2007-09-17  Alexander Solovyov  <piranha@piranha.org.ua>  (tiny change)
+
+       * make.bat: Initial check didn't work if path contained spaces.
+
+2007-07-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Makefile.in (COMMIT_STRING): New variable.
+       (release-bump-version): Use it.
+       (bump-version, bump-version-commit): New targets.
+
+2007-06-06  Andreas Seltenreich  <andreas@gate450.dyndns.org>
+
+       * todo: Add comment.  Remove duplicate item.
+
+2007-05-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * README: Bump version number.
+
+2007-04-11  Didier Verna  <didier@xemacs.org>
+
+       * GNUS-NEWS: Generated.
+
+2007-04-01  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * GNUS-NEWS: Generated.
+
+2007-03-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * README: Bump ngnus version.
+
+2006-12-26  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * GNUS-NEWS: Generated.
+
+2006-10-09  Romain Francoise  <romain@orebokech.com>
+
+       * todo: Fix some typos.
+
+2006-04-19  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * make.bat: Use "echo *" to clarify the output.
+       (:lisp, :infotest): Avoid "not found" errors
+       (:etc): Remove etc\gnus.  Be more verbose.  Add new smilies.
+       Simplify.
+
+2006-04-11  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * etc/Makefile.in (install): Install new smileys.
+
+2006-04-11  Adam Sj\e,Ax\e(Bgren  <asjo@koldfront.dk>
+
+       * etc/images/smilies/grayscale/*.xpm: New larger grayscale smileys.
+
+       * etc/images/smilies/medium/*.xpm: New colorful smileys.
+
+2006-04-11  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * README: No Gnus v0.4 is released.
+
+2006-04-11  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Makefile.in (release-sign-files): Use rm -f.
+       (RELEASE_COMMIT_FILES): Add ./ChangeLog.
+       (release-bump-version): Add README.
+       (release-check-settings): OLD_TAG, not OLDTAG.
+       (release-commit): Echo command lines before prompt.
+       (RELEASE_COMMIT_FILES): Add README.
+       (OLD_PATTERN): Fix.
+       (release-bump-version): Fix gnusversionname substitution.
+       (OLD_PATTERN): Add grouping.
+
+2006-04-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Makefile.in (GZIP_PROG): Use gzip -f.
+       (release-bump-version, RELEASE_COMMIT_FILES): Add README.
+       (release-sign-files): Remove old *.sig files.
+
+       * README: Say "development version".  Let sentences end with
+       double space.
+
+2006-04-07  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Makefile.in (GZIP_PROG): New variable.
+       (release-diff): Use it.
+       (release-sign-files): New sign-only target.  Use GPG_AGENT_INFO.
+
+2006-04-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Makefile.in (TAR_BALL_EXTRA, release-make-tar-ball, README):
+       Remove; README is in CVS now.
+       (release-files, release-files-signed, release-cvs-export)
+       (release-make-tar-ball): Use $(VERSION) instead of $(TAG).
+       (OLD_PATTERN): Catch stable and trunk.
+       (CIN): New variable.
+       (release-files, release-files-signed, release-cvs-export)
+       (release-make-tar-ball, release-diff, release-post-clean): Add
+       CIN.
+       (OLD_PATTERN): Remove quotes.
+       (release-bump-version): Fix typo.
+
+       * etc/images/README: Add more Emacs 22 icons.  Add suggestion on
+       how to use those in Emacs 21.
+
+       * etc/images/close.xpm, etc/images/cut.xpm, etc/images/home.xpm,
+       etc/images/index.xpm, etc/images/jump-to.xpm, etc/images/new.xpm,
+       etc/images/next-node.xpm, etc/images/open.xpm,
+       etc/images/preferences.xpm, etc/images/prev-node.xpm,
+       etc/images/saveas.xpm, etc/images/spell.xpm: New icons duplicated
+       from Emacs 22.
+
+       * README: Addition from 5.10.6 tar ball.  Clarify "beta".
+       Simplify Info directory setting.  Update required Emacs and XEmacs
+       version.  Use current Gnus version in examples.
+
+2006-03-31  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * GNUS-NEWS: Generated.
+
+       * Makefile.in (CVS_IGNORE_FILES): Additions.
+       (release-files-signed): New target.
+
+       * etc/images/README: Update separator.xpm.
+
+2006-03-30  Romain Francoise  <romain@orebokech.com>
+
+       * GNUS-NEWS: Generated.
+
+2006-03-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * etc/images/separator.xpm: Update from Emacs CVS.
+
+       * GNUS-NEWS: Generated.
+
+2006-03-29  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Makefile.in (release-bump-version): Consider named Gnus versions
+       in replacements.
+
+       * todo: Update "tool bar icons".
+
+2006-03-27  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Makefile.in (release-revert-files): Replace
+       release-revert-changelog.
+       (release-diff): Remove garbage.
+
+2006-03-07  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * etc/images/README: Add GIMP script.
+       (attach.xpm): Move to top level.
+       (sort-*.xpm) Add.
+
+       * etc/images/sort-ascending.xpm,
+       etc/images/sort-column-ascending.xpm,
+       etc/images/sort-criteria.xpm, etc/images/sort-descending.xpm,
+       etc/images/sort-row-ascending.xpm: New icons from GNOME 2.6.
+
+2006-03-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Makefile.in (release-check-settings): Add status and
+       suggestions.
+       (release-files): Remove duplicate release-cvs-export.
+       (README): New target.
+       (release-files, release-make-tar-ball, release-diff): List files.
+       (README, release-make-tar-ball): Fix.
+
+2006-03-06  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * GNUS-NEWS: Generated.
+
+       * Makefile.in (release-*): New targets.
+
+2006-02-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * todo: Remove nnweb.  Add: widget for posting styles, doc string
+       for utility functions, LIST SUBSCRIPTIONS, divide emacs-mime.texi,
+       change servers.
+
+       * etc/images/README (next-page.xpm): From Gnome, not from Emacs
+       22.
+
+       * cancel.xpm, copy.xpm, diropen.xpm, help.xpm, left-arrow.xpm,
+       next-page.xpm, paste.xpm, print.xpm, redo.xpm, right-arrow.xpm,
+       save.xpm, search.xpm: New icons duplicated from Emacs 22.
+
+       * etc/images/README: Add these icons.
+
+       * etc/images/README: Describe the new images.
+
+       * etc/gnus/gnus-setup.ast, etc/gnus/news-server.ast: Use
+       texinfo-mode.
+
+       * etc/images/mail/save.xpm, etc/images/mail/preview.xpm: Rename
+       char*.
+
+2006-03-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * xemacs.mak: Remove outdated file.  Use make.bat instead.
+
+2006-03-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * make.bat: Add note about "Out of environment space" on Windows
+       98 SE.  Avoid `>' in echo.
+
+2006-02-27  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * ChangeLog, texi/ChangeLog, lisp/ChangeLog: Fix "From so-and-so"
+       and "(tiny change)" entries.
+
+2006-02-22  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * etc/images/gnus/mail_send.xpm: Emacs 21 icon for
+       message-tool-bar-retro.
+
+2006-02-21  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * make.bat (:etc): Also consider images in images/mail and
+       images/.
+
+       * etc/Makefile.in (install, uninstall): Also consider images in
+       images/mail and images/.
+
+       * etc/images/connect.xpm, etc/images/contact.xpm,
+       etc/images/delete.xpm, etc/images/describe.xpm,
+       etc/images/disconnect.xpm, etc/images/exit.xpm,
+       etc/images/lock-broken.xpm, etc/images/lock-ok.xpm,
+       etc/images/lock.xpm, etc/images/refresh.xpm,
+       etc/images/gnus/toggle-subscription.xpm,
+       etc/images/mail/attach.xpm, etc/images/mail/compose.xpm,
+       etc/images/mail/copy.xpm, etc/images/mail/forward.xpm,
+       etc/images/mail/inbox.xpm, etc/images/mail/move.xpm,
+       etc/images/mail/not-spam.xpm, etc/images/mail/outbox.xpm,
+       etc/images/mail/reply-all.xpm, etc/images/mail/reply.xpm,
+       etc/images/mail/save-draft.xpm, etc/images/mail/send.xpm,
+       etc/images/mail/spam.xpm: New icons from GNOME 2.6.
+
+2006-02-21  Miguel Frasson  <frasson@math.leidenuniv.nl>
+
+       * etc/images/separator.xpm: Copy of sep.xpm from AUCTeX.
+
+2006-02-21  Adam Sj\e,Ax\e(Bgren  <asjo@koldfront.dk>
+
+       * etc/images/mail/save.xpm, etc/images/mail/preview.xpm: New icons.
+
+2006-01-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * Makefile.in (clean): Clean all subdirectories; remove *~.
+       (elclean): Remove lisp/auto-autoloads.el, lisp/custom-load.el, and
+       lisp/gnus-load.el.
+       (distclean): Don't use sub-make to run clean; use $(MAKE) instead
+       of make.
+
+       * etc/Makefile.in (clean): New rule.
+       (distclean): Use it; remove Makefile.
+
+2005-12-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * GNUS-NEWS: Generated.
+
+2005-10-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * Testing CVS setup.  Yes.  Yes.  Yes.  Yes.
+
+2005-10-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * aclocal.m4 (AC_PATH_LISPDIR): Default to .../site-lisp/gnus for
+       Emacs.
+       (AC_PATH_ETCDIR): Don't change the default value for Emacs.
+
+       * configure: Generated.
+
+       * Makefile.in (list-installed-shadows): New entry.
+       (remove-installed-shadows): New entry.
+
+       * GNUS-NEWS: Generated.
+
+2005-09-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * todo: Remove some items that are already done.  Add some new
+       items.  Add some comments.
+
+2005-08-10  Romain Francoise  <romain@orebokech.com>
+
+       * GNUS-NEWS: Generated.
+
+2005-07-18  Romain Francoise  <romain@orebokech.com>
+
+       * GNUS-NEWS: Generated.
+
+2005-02-19  Miles Bader  <miles@gnu.org>
+
+       * etc/Makefile.in (install): Create $(etcdir)/images/gnus dir.
+
+       * etc/Makefile.in (install, uninstall): Fix installed image dirs.
+
+       * etc/Makefile.in (install): Put gnus-tut.txt in the right place.
+
+       * Makefile.in (all): Don't do sub-make in etc.
+       * etc/Makefile.in (all): Remove target.
+
+       * make.bat: Do image copies properly.
+
+2005-02-18  Miles Bader  <miles@gnu.org>
+
+       Move all remaining images from etc/gnus to etc/images/gnus.
+
+2004-06-18  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Makefile.in (all): Do sub-make in etc.
+       * etc/Makefile.in (all): Link . to images.
+       (install, uninstall): Use $(etcdir)/images for images.
+       * make.bat: Likewise.
+
+2005-01-02  Romain Francoise  <romain@orebokech.com>
+
+       * GNUS-NEWS: Generated.
+
+2004-12-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * GNUS-NEWS: Generated.
+
+2004-12-06  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * GNUS-NEWS: Generated.
+
+2004-09-30  Simon Josefsson  <jas@extundo.com>
+
+       * Makefile.in (GNUS-NEWS): Depend on texi/gnus-news.texi.
+
+       * GNUS-NEWS: Generated.
+
+2004-09-29  Simon Josefsson  <jas@extundo.com>
+
+       * GNUS-NEWS: Generated.
+
+       * Makefile.in (GNUS-NEWS): Add.
+
+2004-09-11  Simon Josefsson  <jas@extundo.com>
+
+       * GNUS-NEWS: Generated.
+
+2004-09-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * etc/.cvsignore: Remove unused.
+
+2004-06-16  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * make.bat: Fix line endings around arch-tag.
+
+2004-06-03  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * etc/gnus/gnus-setup.ast (Setting up a NNTP server)
+       (Setting up local mail storage (nnml)): fixed some bugs, added a
+       new screen - still testing
+
+2004-06-01  Simon Josefsson  <jas@extundo.com>
+
+       * make.bat: Add SASL manual.
+
+2004-05-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * etc/gnus/news-server.ast: Use library validation.
+
+2004-03-08  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * make.bat: Make sure that gnus-load.el and sieve are writable to
+       avoid breakage.
+
+2004-03-01  Michael Schierl  <schierlm-public@gmx.de>  (tiny change)
+
+       * make.bat: Fix directory test for Windows 9x/ME.
+
+2004-01-07  Hiroshi Fujishima  <pooh@nature.tsukuba.ac.jp>  (tiny change)
+
+       * etc/gnus-tut.txt: `G m' instead of `G V'
+
+2004-01-05  Jesper Harder  <harder@ifa.au.dk>
+
+       * make.bat: Add missing parens.  From Robert Marshall
+       <spam@chezmarshall.freeserve.co.uk>.
+
+2004-01-05  Simon Josefsson  <jas@extundo.com>
+
+       * GNUS-NEWS: Mention SASL, and that sieve-manage uses it.
+       Mention password.el.
+       Mention NTLM.
+
+2004-01-04  Simon Josefsson  <jas@extundo.com>
+
+       * GNUS-NEWS: Add IMAP ID (RFC 2971) support.
+       Mention `W e' for editing all.SCORE.
+
+2004-01-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * GNUS-NEWS: Update copyright.
+
+       * etc/gnus-tut.txt (Gnus FAQ): Remove text version.  Refer to info
+       documentation and online version instead.
+
+       * GNUS-NEWS: Changed "Dired integration"
+
+2004-01-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * GNUS-NEWS: Add `gnus-group-read-ephemeral-group'.
+
+2003-12-23  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * GNUS-NEWS: Mention change of `e' in draft groups.
+
+2003-05-01  Jesper Harder  <harder@ifa.au.dk>
+
+       * etc/gnus-tut.txt (http): Update.
+
+2003-05-01  Simon Josefsson  <jas@extundo.com>
+
+       * GNUS-NEWS: Add prefix limit feature.
+
+2003-04-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * GNUS-NEWS: Added Article Buttons.  Added Upgrading (from Simon
+       Josefsson).  Add gnus-mime-delete-part, markup fixes and some
+       other corrections.  Mention Gnus FAQ.
+
+
+2003-04-30  Jesper Harder  <harder@ifa.au.dk>
+
+       * GNUS-NEWS: Additions.
+
+2003-04-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * GNUS-NEWS: Fixed X-Draft-Headers entry.
+
+2003-04-27  Simon Josefsson  <jas@extundo.com>
+
+       * GNUS-NEWS: Fix PGP entry.  Doc GCC variable change.
+
+2003-04-22  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * make.bat: Flag as binary to ensure DOS line terminators.  Delete
+       trailing whitespace.
+
+2003-04-21  Reiner Steib  <Reiner.Steib@gmx.de>
+       From Frank Schmitt  <ich@frank-schmitt.net>
+
+       * etc/gnus-tut.txt: Update Gnus FAQ, delete trailing whitespace.
+
+2003-04-17  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * make.bat: Cleaned up end-of-line characters.
+
+2003-04-17  Steve Youngs  <youngs@xemacs.org>
+
+       * Makefile.in (XEMACS): Use @EMACS@.
+
+       * aclocal.m4 (AC_PATH_LISPDIR): Set $datadir to $prefix/lib if
+       building with XEmacs.
+
+       * aclocal.m4 (AC_SET_BUILD_FLAGS): New.  So we can set XEmacs
+       command line options to '-batch -no-autoloads...' for a cleaner
+       build environment.
+
+       * configure.in: Use it.
+
+       * configure: Regenerate.
+
+2003-04-16  Reiner Steib  <Reiner.Steib@gmx.de>
+       From Frank Schmitt  <ich@frank-schmitt.net>
+
+       * make.bat: New variable EMACS_ARGS.  Changed XEmacs args.
+
+2003-03-23  Simon Josefsson  <jas@extundo.com>
+
+       * GNUS-NEWS: Add IDNA.  Add TLS.  Fix USEFOR reference.
+
+2003-03-22  Frank Schmitt  <ich@frank-schmitt.net>
+
+       * make.bat: Redone from scratch; supports both Emacs and XEmacs
+       now; correctly generate gnus-load.el; check for errors; use
+       makeinfo if available, infohack.el if it isn't; be less verbose
+       when copying files; copy files from etc/gnus and etc/smilies, too
+
+2003-03-22  Frank Schmitt  <ich@frank-schmitt.net>
+
+       * make-x.bat: Removed, make.bat does its job now.
+
+2003-03-22  Frank Schmitt  <ich@frank-schmitt.net>
+
+       * etc/gnus-tut.txt: Include Gnus FAQ from http://my.gnus.org.
+
+2003-02-19  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * GNUS-NEWS: Renamed `gnus-unsightly-citation-regexp' to
+       `gnus-cite-unsightly-citation-regexp'.
+
+2003-02-18  Simon Josefsson  <jas@extundo.com>
+
+       * GNUS-NEWS: Talk about canlock more.
+
+2003-02-13  Kai Gro\e,A_\e(Bjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * GNUS-NEWS: Add user visible changes from Michael Shields from
+       the past couple of days.  Actual text from Michael.
+
+2003-01-24  Jesper Harder  <harder@ifa.au.dk>
+
+       * etc/gnus-tut.txt: Update.
+
+2003-01-15  Simon Josefsson  <jas@extundo.com>
+
+       * GNUS-NEWS: Add.  Fix from Reiner Steib
+       <4uce.02.r.steib@gmx.net>.
+
+2003-01-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * make.bat: Removed "-no-init-file" (it's the same as "-q").  Use
+       new variables EMACSBATCH and GNUS_INFO_DIR.  Install gnus-?,
+       message-?, sieve and pgg (in texi).  Added hint for dir entries.
+
+       * make-x.bat: Ditto.
+
+2003-01-13  Simon Josefsson  <jas@extundo.com>
+
+       * GNUS-NEWS: Add smileys, Sender:, message-utils.
+       Expand anti-spam.  Fixes.
+
+2003-01-09  Simon Josefsson  <jas@extundo.com>
+
+       * etc/gnus/preview.xpm: Add.
+
+2003-01-06  Simon Josefsson  <jas@extundo.com>
+
+       * etc/gnus/receipt.xpm: Add.
+
+2003-01-10  Jesper Harder  <harder@ifa.au.dk>
+
+       * etc/gnus/preview.xbm: Add.
+
+2003-01-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * etc/gnus/gnus.xpm (oort): Make the color replaceable.
+
+2002-12-05  Kai Gro\e,A_\e(Bjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * etc/smilies/*.pbm: Made them binary.
+
+2002-11-13  Kai Gro\e,A_\e(Bjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * etc/smilies/blink.xpm: Changed smileys and some new ones from
+       Alex Schroeder <alex@emacswiki.org>.
+
+2002-04-26  Steve Youngs  <youngs@xemacs.org>
+
+       * aclocal.m4 (AC_PATH_INFODIR): New.  Defaults to '$prefix/info'
+       for Emacs and 'site-packages/info' for XEmacs.
+       (AC_PATH_ETCDIR): Drop 'gnus' off the end of the default directory
+       for XEmacs.
+
+       * configure.in: Use 'AC_PATH_INFO_DIR'.
+
+2002-02-22  Steve Youngs  <youngs@xemacs.org>
+
+       * aclocal.m4 (AC_PATH_LISPDIR): Default to
+       .../site-packages/lisp/gnus for XEmacs.
+       (AC_PATH_ETCDIR): Default to .../site-packages/etc/gnus for
+       XEmacs.
+
+2002-02-01  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * etc/gnus/gnus.xpm: Remove some garbages at the end of the file.
+
+2002-01-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * etc/gnus/oort.xface (X-Face): Oort X-Face from
+       Raymond Scholz <ray-2002@zonix.de>.
+
+2002-01-02  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * etc/gnus/describe-group.xpm: Set pixels of first line to
+       background color. A bug in Emacs?
+
+2001-12-18  Josh Huber  <huber@alum.wpi.edu>
+
+       * ChangeLog, todo: (oops) changed buffer-file-coding-system back
+       to coding.
+
+2001-12-18  Kai Gro\e,A_\e(Bjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * make-x.bat: Ensure nonempty variable value.  Reported by Frank
+       Haun <pille3000@gmx.net>.
+
+2001-12-18 01:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * ChangeLog, todo: Add `coding'.
+
+2001-12-17  Josh Huber  <huber@alum.wpi.edu>
+
+       * ChangeLog: changed coding to buffer-file-coding-system
+       * todo: same
+
+2001-12-10  Kai Gro\e,A_\e(Bjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * make-x.bat: Code cleanup.  Fix a bug with "/copy".  From Frank
+       Schmitt <ich@Frank-Schmitt.net>.
+
+2001-11-26  Kai Gro\e,A_\e(Bjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * make-x.bat: Use parameter "/copy" rather than "copy" for increased
+       dwimishness for old-time DOS users.  From Frank Schmitt
+       <ich@Frank-Schmitt.net>.
+
+2001-11-15  Simon Josefsson  <jas@extundo.com>
+
+       * etc/gnus/unimportant.xpm, etc/gnus/important.xpm: New files.
+
+2001-11-11  Simon Josefsson  <jas@extundo.com>
+
+       * make-x.bat: Don't use -nw.  Suggested by Frank Haun
+       <pille3000@gmx.net>.
+
+2001-11-01 07:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * etc/smilies/blink.xpm: New set of xpm. From Oliver Scholz
+       <oscholz@my.gnus.org>.
+
+2001-10-29  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * etc/smilies/sad.pbm: New bitmap.
+       * etc/smilies/blink.pbm: Ditto.
+       Contributed by Kim F. Storm <storm@cua.dk>.
+
+2001-10-19  Kai Gro\e,A_\e(Bjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+       From Frank Schmitt <ich@Frank-Schmitt.net>.
+
+       * make-x.bat: Use correct directory structure for XEmacs on Windows.
+
+2001-10-06 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * Makefile.in (uninstall): Add.
+
+       * etc/Makefile.in (uninstall): Add.
+
+2001-09-27 14:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * aclocal.m4 (GNUS_CHECK_FONTS): Typo. Use /dev/null as latex input.
+
+2001-09-27 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * aclocal.m4, configure.in: Check commercial fonts.
+
+2001-09-24 19:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * configure.in: Generate texi/ps/Makefile.
+
+2001-09-21  Kai Gro\e,A_\e(Bjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * make.bat: Use parameter "/copy" rather than "copy" for increased
+       dwimishness for old-time DOS users.
+
+2001-09-18 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * make-x.bat: New.
+
+2001-07-04  Yair Friedman  <yairfr@Amdocs.com>
+
+       * make.bat: Use infohack.el to create info files.
+
+2001-05-17  Kai Gro\e,A_\e(Bjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * etc/Makefile.in (datadir): Set this variable, like in the other
+       Makefile.in's.  Patch from Gaute B Strokkenes <gs234@cam.ac.uk>.
+
+2001-02-11 18:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * GNUS-NEWS: Copyright and others.
+
+2001-02-09 20:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * aclocal.m4 (AC_CHECK_URL): Add.
+
+       * configure.in: Use it.
+
+2001-01-15  Jesper Harder  <harder@ifa.au.dk>
+
+       * make.bat: Fix doc.
+
+2000-12-22 03:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * configure.in: Add etc/Makefile.
+
+2000-12-20  Jesper Harder  <jesper_harder@hotmail.com>
+
+       * make.bat: set max-lisp-eval-depth.
+
+2000-10-12  Jesper Harder  <jesper_harder@hotmail.com>
+
+       * make.bat: Makes it possible to generate the Info files on
+       windows again.
+
+2000-08-24 Jesper Harder  <jesper_harder@hotmail.com>
+
+       * make.bat: Use emacs.exe if emacs.bat does not exist.
+
+2000-05-07  Pavel Janik  <Pavel.Janik@inet.cz>
+
+       * gnus.texi: direntry added.
+
+       * message.texi: direntry added.
+
+       * emacs-mime.texi: direntry added.
+
+2000-07-13 10:09:52  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * aclocal.m4 (AC_CHECK_W3): Fix typo.
+
+2000-07-12 15:47:06  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * aclocal.m4: Stolen macros from w3.
+       * configure.in: Use them.
+       * configure: Generate it.
+
+2000-04-22 20:25:20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * GNUS-NEWS: Outline.
+
+2000-01-06  Dave Love  <fx@gnu.org>
+
+       * aclocal.m4 (AM_PATH_LISPDIR): Check for user's EMACS setting.
+
+1999-11-13  Adrian Aichner  <aichner@ecf.teradyne.com>
+
+       * xemacs.mak: New NMAKE file to support build and install on
+       Windows NT.
+
+  Copyright (C) 1999-2011 Free Software Foundation, Inc.
+
+  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 3, 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.  If not, see <http://www.gnu.org/licenses/>.
+
+;; Local Variables:
+;; coding: iso-2022-7bit
+;; fill-column: 79
+;; add-log-time-zone-rule: t
+;; End:
+
+;;; arch-tag: 60301ba8-b152-41b3-8fb2-173bba77f2a8
diff --git a/xemacs-packages/gnus/GNUS-NEWS b/xemacs-packages/gnus/GNUS-NEWS
new file mode 100644 (file)
index 0000000..4efb53e
--- /dev/null
@@ -0,0 +1,67 @@
+GNUS NEWS -- history of user-visible changes.
+
+Copyright (C) 1999-2016 Free Software Foundation, Inc.
+See the end of the file for license conditions.
+
+Please send Gnus bug reports to bugs@gnus.org.
+For older news, see Gnus info node "New Features".
+
+\f
+* New features
+
+** nnimap can request and use the Gmail "X-GM-LABELS".
+
+** New package `gnus-notifications.el' can send notifications when you
+   receive new messages.
+
+** If you have the "tnef" program installed, Gnus will display ms-tnef
+   files, aka "winmail.dat".
+
+** Archives (like tar and zip files) will be automatically unpacked,
+   and the files inside the packages will be displayed as MIME parts.
+
+** shr has a new command `z' that cycles through image sizes.
+
+** `backtab' in the summary buffer now selects the previous link in
+   the article buffer.
+
+** Using the "X-Message-SMTP-Method" header in Message buffers now
+   allows specifying how messages are to be sent.  For example:
+
+   X-Message-SMTP-Method: smtp smtp.fsf.org 587
+
+** Gnus keeps track of non-existent articles for nnimap groups, so
+   that sparse IMAP folders now list a correct number of messages in
+   them.
+
+** Gnus will guess the real type of MIME parts of type
+   application/octet-stream based on the file suffix.  So an
+   application/octet-stream with a name of "rms.jpg" will be displayed
+   as an image/jpeg type by default, for instance.
+
+** `nnimap-inbox' can now be a list of mail box names.
+   
+* For older news, see Gnus info node "New Features".
+
+----------------------------------------------------------------------
+\f
+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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+\f
+Local variables:
+mode: outline
+paragraph-separate: "[         \f]*$"
+end:
diff --git a/xemacs-packages/gnus/Makefile.in b/xemacs-packages/gnus/Makefile.in
new file mode 100644 (file)
index 0000000..ad78f7a
--- /dev/null
@@ -0,0 +1,295 @@
+prefix = @prefix@
+# Avoid "WARNING:  Makefile.in seems to ignore the --datarootdir setting":
+datarootdir = @datarootdir@
+datadir = @datadir@
+lispdir = @lispdir@
+srcdir = @srcdir@
+
+@SET_MAKE@
+EMACS = @EMACS@
+XEMACS = @EMACS@
+
+GZIP_PROG = @GZIP_PROG@
+
+SED_I = sed -i -e
+
+# # # # # # # # # # Release variables (for maintainer only):
+#
+# Files removed from `cvs export' output before creating the tar-ball:
+CVS_IGNORE_FILES = .cvsignore contrib/.cvsignore etc/.cvsignore        \
+  lisp/.cvsignore texi/.cvsignore texi/ps/.cvsignore .arch-inventory
+# Name and mail address in ChangeLog format for the release commit:
+COMMITTER = Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+# CODENAME for development releases (CODENAME must have a trailing space,
+# (e.g. "Oort ")
+CODENAME = 
+# Codename initial (lower case), e.g. 'n' for "No Gnus".
+CIN =
+# Files with hard-coded versions numbers:
+RELEASE_COMMIT_FILES = ChangeLog \
+  etc/ChangeLog lisp/ChangeLog texi/ChangeLog \
+  README lisp/gnus.el \
+  texi/gnus.texi texi/message.texi texi/gnus-faq.texi
+# Pattern matching previous version numbers:
+OLD_PATTERN = \(5\.[0-9][0-9]\.[0-9]*\|5\.[0-9][0-9]\|0\.[1-9][0-9]*\)
+# Codename pattern
+CODENAME_PATTERN = [A-Z]*[a-z]* *
+# CVS tag of the previous version:
+OLD_TAG     = v5-10-6
+# CVS tag of the current release:
+TAG  = v5-10
+#
+COMMIT_STRING = $(CODENAME)Gnus v$(VERSION) is released.
+# # # # # # # # # # End of release variables
+
+all: lick info
+
+fail-on-warning: lick-fail-on-warning info
+
+lick:
+       cd lisp && $(MAKE) EMACS="$(EMACS)" lispdir="$(lispdir)" all
+
+lick-fail-on-warning:
+       cd lisp && $(MAKE) EMACS="$(EMACS)" lispdir="$(lispdir)" fail-on-warning
+
+install:
+       cd lisp && $(MAKE) EMACS="$(EMACS)" lispdir="$(lispdir)" install
+       cd texi && $(MAKE) EMACS="$(EMACS)" install
+       cd etc && $(MAKE) EMACS="$(EMACS)" install
+
+list-installed-shadows:
+       cd lisp && $(MAKE) EMACS="$(EMACS)" lispdir="$(lispdir)" list-installed-shadows
+
+remove-installed-shadows:
+       cd lisp && $(MAKE) EMACS="$(EMACS)" lispdir="$(lispdir)" remove-installed-shadows
+
+uninstall:
+       cd lisp && $(MAKE) lispdir="$(lispdir)" uninstall
+       cd texi && $(MAKE) uninstall
+       cd etc && $(MAKE) uninstall
+
+GNUS-NEWS: texi/gnus-news.texi
+       cd texi && $(MAKE) GNUS-NEWS
+
+check: 
+       cd lisp && $(MAKE) EMACS="$(EMACS)" lispdir="$(lispdir)" check
+
+# Rule for Lars and nobody else.
+some:
+       cd lisp && $(MAKE) EMACS="$(EMACS)" some
+l:
+       cd lisp && $(MAKE) EMACS="$(EMACS)" clever
+
+info:
+       cd texi && $(MAKE) EMACS="$(EMACS)" all
+
+clean:
+       for i in lisp texi etc texi/ps; do (cd $$i; $(MAKE) clean); done
+       rm -f *.orig *.rej *~
+
+elclean:
+       cd lisp && rm -f *.elc auto-autoloads.el custom-load.el gnus-load.el
+
+x:
+       $(MAKE) EMACS=$(XEMACS)
+
+xsome:
+       $(MAKE) EMACS="$(XEMACS)" some
+
+distclean: clean
+       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
+       $(SHELL) ./config.status --recheck
+$(srcdir)/configure: $(srcdir)/configure.in
+       cd $(srcdir) && autoconf
+Makefile: $(srcdir)/Makefile.in config.status
+       CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+# # # # # # # # # # Release targets (for maintainer only):
+
+release-check-settings:
+       @echo
+       @echo "COMMITTER = '$(COMMITTER)'"
+       @echo "  (example: 'Foo Bar  <foo.bar@somewhere.invalid>')"
+       @echo "VERSION   = '$(VERSION)' (example: '5.10.6')"
+       @echo "TAG       = '$(TAG)' (example: 'v5-10-6')"
+       @echo "OLD_TAG   = '$(OLD_TAG)' (example: 'v5-10-5')"
+       @echo
+       @echo "# Only for development versions:"
+       @echo "CODENAME  = '$(CODENAME)' (example: 'No ')"
+       @echo "CIN       = '$(CIN)' (example: 'n', codename initial)"
+       @echo
+       @if [ x"$(VERSION)" = x ]; then echo "error: No VERSION given."; exit 1; else :; fi
+       @if [ x"$(TAG)" = x ]; then echo "error: No TAG given."; exit 1; else :; fi
+       @echo
+       @echo Settings checked successfully.
+       @echo
+       @echo You may now make...
+       @echo   release-bump-version
+       @echo   release-add-changelog
+       @echo   release-commit
+       @echo   release-files or release-files-signed
+
+release-help:
+       @echo "Available targets for releases:"
+       @echo
+       @echo "[0]  release-help"
+       @echo "         Display this help message."
+       @echo
+       @echo "[1]  release-check-settings"
+       @echo "         Check it all required variables are specified on the command line."
+       @echo "         Run this target to display the variable names and current values."
+       @echo
+       @echo "[2]  release-bump-version"
+       @echo "         Bump the version to VERSION"
+       @echo
+       @echo "[3]  release-add-changelog"
+       @echo "         Add COMMITTER and COMMIT_STRING to the ChangeLogs."
+       @echo
+       @echo "[4]  release-commit"
+       @echo "         Commit the ChangeLogs and tag repository with TAG."
+       @echo
+       @echo "[5]  release-files or release-files-signed"
+       @echo "         Create the release tar-ball and diff file."
+       @echo "         release-files-signed creates detached GPG signature files as well."
+       @echo
+       @echo "For a release, steps [1]-[5] need to be done.  Immediately after"
+       @echo "the release, we bump the version again by performing steps [1]-[4]"
+       @echo "with the next VERSION and TAG."
+       @echo
+
+bump-version:
+       $(MAKE) COMMIT_STRING='Bump version to $(VERSION).' release-bump-version
+
+bump-version-commit:
+       $(MAKE) COMMIT_STRING='Bump version to $(VERSION).' release-commit
+
+# Needs GNU grep and a recent GNU sed:
+release-bump-version:  release-check-settings
+       $(SED_I) '/^(defconst gnus-version-number /s,"$(OLD_PATTERN)","$(VERSION)",' lisp/gnus.el
+       $(SED_I) '/^.newcommand{.gnusversionname}{$(CODENAME_PATTERN)Gnus v/s,$(OLD_PATTERN),$(VERSION),' texi/gnus.texi
+       $(SED_I) '/^This manual corresponds to $(CODENAME_PATTERN)Gnus v/s,$(OLD_PATTERN),$(VERSION),' texi/gnus.texi
+       $(SED_I) '/^@samp.{$(CODENAME_PATTERN)Gnus v.*@c Adjust Makefile/s,$(OLD_PATTERN),$(VERSION),' texi/gnus.texi
+       $(SED_I) '/^corresponding to this manual is $(CODENAME_PATTERN)Gnus v/s,$(OLD_PATTERN),$(VERSION),' texi/message.texi
+       $(SED_I) 's,/[a-z]*gnus-[0-9.]*/,/$(CIN)gnus-$(VERSION)/,' README
+       if [ "x$(CODENAME)" = "x" ]; then \
+         $(SED_I) '/The current release ($(OLD_PATTERN)) should/s,$(OLD_PATTERN),$(VERSION),' texi/gnus-faq.texi; \
+       else \
+         true; \
+       fi
+# Only for going from the development version to release...
+       if [ "x$(CODENAME)" = "x" -a "$(CODENAME_TO_STABLE)" = t ]; then \
+         $(SED_I) '/^(defconst gnus-version /s,"$(CODENAME_PATTERN)Gnus v,"Gnus v,' lisp/gnus.el; \
+         $(SED_I) '/^.newcommand{.gnusversionname}{$(CODENAME_PATTERN)Gnus v/s,$(CODENAME_PATTERN)Gnus v$(OLD_PATTERN),Gnus v$(VERSION),' texi/gnus.texi; \
+         $(SED_I) '/^This manual corresponds to $(CODENAME_PATTERN)Gnus v/s,$(CODENAME_PATTERN)Gnus v$(OLD_PATTERN),Gnus v$(VERSION),' texi/gnus.texi; \
+         $(SED_I) '/^corresponding to this manual is $(CODENAME_PATTERN)Gnus v/s,$(CODENAME_PATTERN)Gnus v$(OLD_PATTERN),Gnus v$(VERSION),' texi/message.texi; \
+       else \
+         true; \
+       fi
+       $(MAKE) release-diff-commit-files
+
+# Add ChangeLog entry...
+release-add-changelog: release-check-settings
+       @echo "Updating ChangeLog files..."
+       @if grep -q "$(CODENAME)Gnus v$(VERSION) is released" ChangeLog; then \
+         echo "ChangeLog is already updated"; \
+       else \
+         $(SED_I) "1s|^|`date -I`  $(COMMITTER)\n\n\t* README: $(COMMIT_STRING)\n\n|" ChangeLog; \
+       fi
+       @if grep -q "$(CODENAME)Gnus v$(VERSION) is released" etc/ChangeLog; then \
+         echo "etc/ChangeLog is already updated"; \
+       else \
+         $(SED_I) "1s|^|`date -I`  $(COMMITTER)\n\n\t* ChangeLog: $(COMMIT_STRING)\n\n|" etc/ChangeLog; \
+       fi
+       @if grep -q "$(CODENAME)Gnus v$(VERSION) is released" texi/ChangeLog; then \
+         echo "texi/ChangeLog is already updated"; \
+       else \
+         $(SED_I) "1s|^|`date -I`  $(COMMITTER)\n\n\t* gnus.texi, gnus-faq.texi, message.texi: $(COMMIT_STRING)\n\n|" texi/ChangeLog; \
+       fi
+       @if grep -q "$(CODENAME)Gnus v$(VERSION) is released" lisp/ChangeLog; then \
+         echo "lisp/ChangeLog is already updated"; \
+       else \
+         $(SED_I) "1s|^|`date -I`  $(COMMITTER)\n\n\t* gnus.el: $(COMMIT_STRING)\n\n|" lisp/ChangeLog; \
+       fi
+       $(MAKE) release-diff-commit-files
+
+release-diff-commit-files: release-check-settings
+       cvs diff -U0 $(RELEASE_COMMIT_FILES); sleep 2
+
+release-revert-files:
+       rm -i      $(RELEASE_COMMIT_FILES)
+       cvs update $(RELEASE_COMMIT_FILES)
+
+release-commit:        release-check-settings
+       @echo -e '\007'
+       @echo
+       @echo "Really do the release-commit for $(CODENAME)Gnus v$(VERSION)?"
+       @echo "Command line:"
+       @echo "  " cvs commit -m "$(COMMIT_STRING)" $(RELEASE_COMMIT_FILES)
+       @echo
+       @echo "Hit RET to continue or Ctrl-C to abort."
+       @echo
+       @read dummy
+       cvs commit -m "$(COMMIT_STRING)" $(RELEASE_COMMIT_FILES)
+       @echo
+       @echo "Add tag $(TAG) to CVS?"
+       @echo "Command line:"
+       @echo "  " cvs tag $(TAG)
+       @echo "Hit RET to continue or Ctrl-C to abort."
+       @echo
+       @read dummy
+       cvs tag $(TAG)
+
+release-files: release-make-tar-ball release-diff
+       @echo "Release files have been created:"
+       @ls -l $(CIN)gnus-$(VERSION).tar.gz
+       @ls -l $(CIN)gnus-`echo $(OLD_TAG)%$(TAG)|tr - .|tr -d v|tr % -`.diff.gz
+
+release-files-signed:  release-files release-sign-files
+
+# Sign prepared files:
+release-sign-files:
+       if [ "x$$GPG_AGENT_INFO" = "x" ]; then \
+         read -sp "Enter pass phrase: " phrase ; \
+         gpg_opt="--passphrase-fd 0"; \
+       else \
+         gpg_opt=""; phrase=""; \
+       fi; \
+       for i in $(CIN)gnus-$(VERSION).tar.gz \
+                $(CIN)gnus-`echo $(OLD_TAG)%$(TAG)|tr - .|tr -d v|tr % -`.diff.gz; do \
+          rm -f $$i.sig; \
+          echo "$$phrase" | gpg --detach-sign $$gpg_opt $$i; \
+       done; true
+       @ls -l $(CIN)gnus-$(VERSION).tar.gz{.sig,}
+       @ls -l $(CIN)gnus-`echo $(OLD_TAG)%$(TAG)|tr - .|tr -d v|tr % -`.diff.gz{.sig,}
+       @gpg --verify $(CIN)gnus-$(VERSION).tar.gz{.sig,}
+       @gpg --verify $(CIN)gnus-`echo $(OLD_TAG)%$(TAG)|tr - .|tr -d v|tr % -`.diff.gz{.sig,}
+
+release-cvs-export $(CIN)gnus-$(VERSION):      release-check-settings
+       rm -fr $(CIN)gnus-$(VERSION)
+       umask 0022; cvs export -d $(CIN)gnus-$(VERSION) -r $(TAG) gnus
+
+release-make-tar-ball: $(CIN)gnus-$(VERSION)
+       [ -d $(CIN)gnus-$(VERSION) ] && cd $(CIN)gnus-$(VERSION) && \
+         rm $(CVS_IGNORE_FILES) || true
+       tar zcvf $(CIN)gnus-$(VERSION).tar.gz $(CIN)gnus-$(VERSION)
+       ls -l $(CIN)gnus-$(VERSION).tar.gz
+
+# Make a diff between current and previous release.  Example:
+# ftp://quimby.gnus.org/pub/gnus/ding-patches/gnus-5.10.5-5.10.6.diff.gz
+release-diff:  release-check-settings
+       cvs diff -r $(OLD_TAG) -r $(TAG) | sed -e '/^\? /d' > temp.diff || true
+       mv temp.diff $(CIN)gnus-`echo $(OLD_TAG)%$(TAG)|tr - .|tr -d v|tr % -`.diff
+       $(GZIP_PROG) -f $(CIN)gnus-`echo $(OLD_TAG)%$(TAG)|tr - .|tr -d v|tr % -`.diff
+       ls -l        $(CIN)gnus-`echo $(OLD_TAG)%$(TAG)|tr - .|tr -d v|tr % -`.diff.gz
+
+release-post-clean:    release-check-settings
+       rm -fr $(CIN)gnus-$(TAG) temp.diff
+
+# # # # # # # # # # End of release targets
+
+# 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/xemacs-packages/gnus/README b/xemacs-packages/gnus/README
new file mode 100644 (file)
index 0000000..f421620
--- /dev/null
@@ -0,0 +1,71 @@
+* Content
+
+This package contains a development version of Gnus.  The lisp directory
+contains the source lisp files, and the texi directory contains the Gnus info
+pages.
+
+* Emacsen
+
+No Gnus does absolutely not work with anything older than Emacs 21 or
+XEmacs 21.4.
+
+Users of the Emacs development version (Emacs 23) are strongly encouraged to
+also use the version bundled with Emacs.
+
+* Setup
+
+To use Gnus you first have to unpack the files, which you've obviously
+done, because you are reading this.
+
+You should definitely byte-compile the source files.  To do that, you
+can simply say "./configure && make" in this directory.
+
+Do not say "make install".  I repeat, do *NOT* say "make install".  If
+you say "make install" and then complain about things not working,
+I'll be very annoyed.  If you say "make install" and things happen to
+work, that's all fine and dandy for you, but it's quite likely that it
+won't.
+
+If you are using XEmacs, you *must* say "./configure && make EMACS=xemacs".
+
+Then you have to tell Emacs where Gnus is.  You might put something
+like
+
+   (setq load-path (cons (expand-file-name "~/ngnus-0.11/lisp") load-path))
+   (require 'gnus-load)
+
+in your .emacs file, or wherever you keep such things.  
+
+To enable reading the Gnus manual, you could say something like:
+
+  (require 'info)
+  (if (featurep 'xemacs)
+      (add-to-list 'Info-directory-list "~/ngnus-0.11/texi/")
+    (add-to-list 'Info-default-directory-list "~/ngnus-0.11/texi/"))
+
+To compile the Gnus manual, you either need a pretty new Emacs, or a
+pretty new version of the texinfo tools.
+
+Then you do a `M-x gnus', and everything should... uhm... it should
+work, but it might not.  Set `debug-on-error' to t, and mail me the
+backtraces, or, better yet, find out why Gnus does something wrong,
+fix it, and send me the diffs.  :-)
+
+There are four main things I want your help and input on:
+
+1) Startup.  Does everything go smoothly, and why not?
+
+2) Any errors while you read news normally?
+
+3) Any errors if you do anything abnormal?
+
+4) Features you do not like, or do like, but would like to tweak a
+   bit, and features you would like to see.
+
+Send any comments and all your bug fixes/complaints to
+`bugs@gnus.org'.
+
+
+Local variables:
+mode: outline
+End:
diff --git a/xemacs-packages/gnus/aclocal.m4 b/xemacs-packages/gnus/aclocal.m4
new file mode 100644 (file)
index 0000000..9a5da0d
--- /dev/null
@@ -0,0 +1,276 @@
+# serial 1
+
+AC_DEFUN(AM_PATH_LISPDIR,
+ [# If set to t, that means we are running in a shell under Emacs.
+  # 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
+    AC_MSG_CHECKING([where .elc files should go])
+    dnl Set default value
+    lispdir="\$(datadir)/emacs/site-lisp"
+    if test "x$prefix" = "xNONE"; then
+      if test -d $ac_default_prefix/share/emacs/site-lisp; then
+       lispdir="\$(prefix)/share/emacs/site-lisp"
+      else
+       if test -d $ac_default_prefix/lib/emacs/site-lisp; then
+         lispdir="\$(prefix)/lib/emacs/site-lisp"
+       fi
+      fi
+    else
+      if test -d $prefix/share/emacs/site-lisp; then
+       lispdir="\$(prefix)/share/emacs/site-lisp"
+      else
+       if test -d $prefix/lib/emacs/site-lisp; then
+         lispdir="\$(prefix)/lib/emacs/site-lisp"
+       fi
+      fi
+    fi
+    AC_MSG_RESULT($lispdir)
+  fi
+  AC_SUBST(lispdir)])
+
+dnl AC_EMACS_LIST AC_XEMACS_P AC_PATH_LISPDIR and AC_EMACS_CHECK_LIB
+dnl are stolen from w3.
+dnl AC_PATH_LISPDIR obsoletes AM_PATH_LISPDIR.
+
+AC_DEFUN(AC_EMACS_LISP, [
+elisp="$2"
+if test -z "$3"; then
+       AC_MSG_CHECKING(for $1)
+fi
+AC_CACHE_VAL(EMACS_cv_SYS_$1,[
+       OUTPUT=./conftest-$$
+       echo ${EMACS} -batch -eval "(let ((x ${elisp})) (write-region (if (stringp x) (princ x) (prin1-to-string x)) nil \"${OUTPUT}\"))" >& AC_FD_CC 2>&1  
+       ${EMACS} -batch -eval "(let ((x ${elisp})) (write-region (if (stringp x) (princ x 'ignore) (prin1-to-string x)) nil \"${OUTPUT}\"nil 5))" >& AC_FD_CC 2>&1
+       retval=`cat ${OUTPUT}`
+       echo "=> ${retval}" >& AC_FD_CC 2>&1
+       rm -f ${OUTPUT}
+       EMACS_cv_SYS_$1=$retval
+])
+$1=${EMACS_cv_SYS_$1}
+if test -z "$3"; then
+       AC_MSG_RESULT($$1)
+fi
+])
+
+AC_DEFUN(AC_XEMACS_P, [
+  AC_MSG_CHECKING([if $EMACS is really XEmacs])
+  AC_EMACS_LISP(xemacsp,(if (string-match \"XEmacs\" emacs-version) \"yes\" \"no\") ,"noecho")
+  XEMACS=${EMACS_cv_SYS_xemacsp}
+  EMACS_FLAVOR=emacs
+  if test "$XEMACS" = "yes"; then
+     EMACS_FLAVOR=xemacs
+  fi
+  AC_MSG_RESULT($XEMACS)
+  AC_SUBST(XEMACS)
+  AC_SUBST(EMACS_FLAVOR)
+])
+
+AC_DEFUN(AC_PATH_LISPDIR, [
+  AC_XEMACS_P
+  if test "$prefix" = "NONE"; then
+       AC_MSG_CHECKING([prefix for your Emacs])
+       AC_EMACS_LISP(prefix,(expand-file-name \"..\" invocation-directory),"noecho")
+       prefix=${EMACS_cv_SYS_prefix}
+       AC_MSG_RESULT($prefix)
+  fi
+  AC_ARG_WITH(lispdir,[  --with-lispdir=DIR      Where to install lisp files], lispdir=${withval})
+  AC_MSG_CHECKING([where .elc files should go])
+  if test -z "$lispdir"; then
+    dnl Set default value
+    theprefix=$prefix
+    if test "x$theprefix" = "xNONE"; then
+       theprefix=$ac_default_prefix
+    fi
+    if test "$EMACS_FLAVOR" = "xemacs"; then
+        datadir="\$(prefix)/lib"
+        lispdir="\$(datadir)/${EMACS_FLAVOR}/site-packages/lisp/gnus"
+    else
+    lispdir="\$(datadir)/${EMACS_FLAVOR}/site-lisp/gnus"
+    fi
+    for thedir in share lib; do
+       potential=
+       dnl The directory name should be quoted because it might contain spaces.
+       if test -d "${theprefix}/${thedir}/${EMACS_FLAVOR}/site-lisp"; then
+           if test "$EMACS_FLAVOR" = "xemacs"; then
+              lispdir="\$(prefix)/${thedir}/${EMACS_FLAVOR}/site-packages/lisp/gnus"
+           else
+               lispdir="\$(datadir)/${EMACS_FLAVOR}/site-lisp/gnus"
+           fi
+          break
+       fi
+    done
+  fi
+  AC_MSG_RESULT($lispdir)
+  AC_SUBST(lispdir)
+])
+
+AC_DEFUN(AC_PATH_ETCDIR, [
+  AC_ARG_WITH(etcdir,[  --with-etcdir=DIR       Where to install etc files], etcdir=${withval})
+  AC_MSG_CHECKING([where etc files should go])
+  if test -z "$etcdir"; then
+    dnl Set default value.
+    if test "$EMACS_FLAVOR" = "xemacs"; then
+      etcdir="\$(lispdir)/../../etc"
+    else
+      etcdir="\$(lispdir)/../../etc"
+    fi
+  fi
+  AC_MSG_RESULT($etcdir)
+  AC_SUBST(etcdir)
+])
+
+dnl 
+dnl This is a bit on the "evil hack" side of things.  It is so we can
+dnl have a different default infodir for XEmacs.  A user can still specify
+dnl someplace else with '--infodir=DIR'.
+dnl
+AC_DEFUN(AC_PATH_INFO_DIR, [
+  AC_MSG_CHECKING([where the TeXinfo docs should go])
+  dnl Set default value.  This must be an absolute path.
+  if test "$infodir" = "\${prefix}/info"; then
+    if test "$EMACS_FLAVOR" = "xemacs"; then
+      info_dir="\$(prefix)/${thedir}/${EMACS_FLAVOR}/site-packages/info"
+    else
+      info_dir="\$(prefix)/info"
+    fi
+  else
+    info_dir=$infodir
+  fi
+  AC_MSG_RESULT($info_dir)
+  AC_SUBST(info_dir)
+])
+
+dnl
+dnl This will set the XEmacs command line options to be slightly different
+dnl from the Emacs ones.  If building with XEmacs the options will be
+dnl "-batch -no-autoloads..." to give a much cleaner build environment.
+dnl
+AC_DEFUN(AC_SET_BUILD_FLAGS, [
+  AC_MSG_CHECKING([which options to pass on to (X)Emacs])
+  if test "x$FLAGS" = "x"; then
+    if test "$EMACS_FLAVOR" = "xemacs"; then
+      FLAGS="-batch -no-autoloads -l \$(srcdir)/dgnushack.el"
+    else
+      FLAGS="-batch -q -no-site-file -l \$(srcdir)/dgnushack.el"
+    fi
+  else
+    FLAGS=$FLAGS
+  fi
+  AC_MSG_RESULT($FLAGS)
+  AC_SUBST(FLAGS)
+])
+
+dnl
+dnl Check whether a function exists in a library
+dnl All '_' characters in the first argument are converted to '-'
+dnl
+AC_DEFUN(AC_EMACS_CHECK_LIB, [
+if test -z "$3"; then
+       AC_MSG_CHECKING(for $2 in $1)
+fi
+library=`echo $1 | tr _ -`
+AC_EMACS_LISP($1,(progn (fmakunbound '$2) (condition-case nil (progn (require '$library) (fboundp '$2)) (error (prog1 nil (message \"$library not found\"))))),"noecho")
+if test "${EMACS_cv_SYS_$1}" = "nil"; then
+       EMACS_cv_SYS_$1=no
+fi
+if test "${EMACS_cv_SYS_$1}" = "t"; then
+       EMACS_cv_SYS_$1=yes
+fi
+HAVE_$1=${EMACS_cv_SYS_$1}
+AC_SUBST(HAVE_$1)
+if test -z "$3"; then
+       AC_MSG_RESULT($HAVE_$1)
+fi
+])
+
+dnl
+dnl Perform checking available fonts: Adobe Bembo, Adobe Futura and 
+dnl Bitstream Courier.
+dnl
+
+AC_DEFUN(GNUS_CHECK_FONTS, [
+test "$LATEX" = t && LATEX=
+test "$LATEX" || AC_PATH_PROGS(LATEX, latex, no)
+AC_MSG_CHECKING(for available fonts)
+AC_ARG_WITH(fonts,[  --with-fonts            Assume all fonts required are available],[USE_FONTS="$withval"])
+WITH_FONTS_bembo='%'
+WITHOUT_FONTS_bembo=
+WITH_FONTS_pfu='%'
+WITHOUT_FONTS_pfu=
+WITH_FONTS_bcr='%'
+WITHOUT_FONTS_bcr=
+if test -z "${USE_FONTS}"; then
+  if test "${LATEX}" = no; then
+       :
+  else
+    OUTPUT=./conftest-$$
+    echo '\nonstopmode\documentclass{article}\usepackage{bembo}\begin{document}\end{document}' > ${OUTPUT}
+    if ${LATEX} ${OUTPUT} </dev/null >& AC_FD_CC 2>&1  ; then  
+      if test -z "${USE_FONTS}"; then
+       USE_FONTS="Adobe Bembo"
+      else
+       USE_FONTS="${USE_FONTS}, Adobe Bembo"
+      fi
+      WITH_FONTS_bembo=
+      WITHOUT_FONTS_bembo='%'
+    fi
+    echo '\nonstopmode\documentclass{article}\begin{document}{\fontfamily{pfu}\fontsize{10pt}{10}\selectfont test}\end{document}' > ${OUTPUT}
+    if retval=`${LATEX} ${OUTPUT} </dev/null 2>& AC_FD_CC`; then
+      if echo "$retval" | grep 'Some font shapes were not available' >& AC_FD_CC 2>&1  ; then  
+       :
+      else
+        if test -z "${USE_FONTS}"; then
+         USE_FONTS="Adobe Futura"
+        else
+         USE_FONTS="${USE_FONTS}, Adobe Futura"
+        fi
+        WITH_FONTS_pfu=
+        WITHOUT_FONTS_pfu='%'
+      fi
+    fi
+    echo '\nonstopmode\documentclass{article}\begin{document}{\fontfamily{bcr}\fontsize{10pt}{10}\selectfont test}\end{document}' > ${OUTPUT}
+    if retval=`${LATEX} ${OUTPUT} </dev/null 2>& AC_FD_CC`; then
+      if echo "$retval" | grep 'Some font shapes were not available' >& AC_FD_CC 2>&1  ; then  
+       :
+      else
+        if test -z "${USE_FONTS}"; then
+         USE_FONTS="Bitstream Courier"
+        else
+         USE_FONTS="${USE_FONTS}, Bitstream Courier"
+        fi
+        WITH_FONTS_bcr=
+        WITHOUT_FONTS_bcr='%'
+      fi
+    fi
+    rm -f ${OUTPUT} ${OUTPUT}.aux ${OUTPUT}.log ${OUTPUT}.dvi
+  fi
+elif test "${USE_FONTS}" = yes ; then
+  WITH_FONTS_bembo=
+  WITHOUT_FONTS_bembo='%'
+  WITH_FONTS_pfu=
+  WITHOUT_FONTS_pfu='%'
+  WITH_FONTS_bcr=
+  WITHOUT_FONTS_bcr='%'
+fi
+AC_SUBST(WITH_FONTS_bembo)
+AC_SUBST(WITHOUT_FONTS_bembo)
+AC_SUBST(WITH_FONTS_pfu)
+AC_SUBST(WITHOUT_FONTS_pfu)
+AC_SUBST(WITH_FONTS_bcr)
+AC_SUBST(WITHOUT_FONTS_bcr)
+if test -z "${USE_FONTS}" ; then
+  USE_FONTS=no
+fi
+USE_FONTS=`echo "${USE_FONTS}" | sed 's/,\([[^,]]*\)$/ and\1/'`
+AC_MSG_RESULT("${USE_FONTS}")
+if test "${USE_FONTS}" = yes ; then
+  USE_FONTS='Set in Adobe Bembo, Adobe Futura and Bitstream Courier.'
+elif test "${USE_FONTS}" = no ; then
+  USE_FONTS=''
+else
+  USE_FONTS="Set in ${USE_FONTS}."
+fi
+AC_SUBST(USE_FONTS)
+])
diff --git a/xemacs-packages/gnus/configure b/xemacs-packages/gnus/configure
new file mode 100755 (executable)
index 0000000..d695604
--- /dev/null
@@ -0,0 +1,3476 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+       expr "X$arg" : "X\\(.*\\)$as_nl";
+       arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+  # into an infinite loop, continuously re-executing ourselves.
+  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+    _as_can_reexec=no; export _as_can_reexec;
+    # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+  fi
+  # We don't want this to propagate to other subprocesses.
+          { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+        /*)
+          for as_base in sh bash ksh sh5; do
+            # Try only shells that exist, to save several forks.
+            as_shell=$as_dir/$as_base
+            if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+                   { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+                  if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+          done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+             { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='        ';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="lisp/gnus.el"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+COMPRESS_INSTALL
+GZIP_PROG
+USE_FONTS
+WITHOUT_FONTS_bcr
+WITH_FONTS_bcr
+WITHOUT_FONTS_pfu
+WITH_FONTS_pfu
+WITHOUT_FONTS_bembo
+WITH_FONTS_bembo
+LATEX
+FLAGS
+info_dir
+etcdir
+lispdir
+EMACS_FLAVOR
+XEMACS
+EMACS
+MAKEINFO
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+SET_MAKE
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_xemacs
+with_emacs
+with_lispdir
+with_etcdir
+with_fonts
+with_compress_install
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *=)   ac_optarg= ;;
+  *)    ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+    esac
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in  exec_prefix prefix bindir sbindir libexecdir datarootdir \
+               datadir sysconfdir sharedstatedir localstatedir includedir \
+               oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+               libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_myself" : 'X\(//\)[^/]' \| \
+        X"$as_myself" : 'X\(//\)$' \| \
+        X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+       cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+       pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking ...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/PACKAGE]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+  cat <<\_ACEOF
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-xemacs[=PROG]    use XEmacs to build (default: PROG=xemacs)
+  --with-emacs[=PROG]     use Emacs to build (default: PROG=emacs)
+  --with-lispdir=DIR      Where to install lisp files
+  --with-etcdir=DIR       Where to install etc files
+  --with-fonts            Assume all fonts required are available
+  --without-compress-install
+                          do not compress .el and .info files when installing.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+    2)
+      as_fn_append ac_configure_args1 " '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+       ac_must_keep_next=false # Got value, back to normal.
+      else
+       case $ac_arg in
+         *=* | --config-cache | -C | -disable-* | --disable-* \
+         | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+         | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+         | -with-* | --with-* | -without-* | --without-* | --x)
+           case "$ac_configure_args0 " in
+             "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+           esac
+           ;;
+         -* ) ac_must_keep_next=true ;;
+       esac
+      fi
+      as_fn_append ac_configure_args " '$ac_arg'"
+      ;;
+    esac
+  done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+       "s/'\''/'\''\\\\'\'''\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+      echo
+      for ac_var in $ac_subst_files
+      do
+       eval ac_val=\$$ac_var
+       case $ac_val in
+       *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+       esac
+       $as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  # We do not want a PATH search for config.site.
+  case $CONFIG_SITE in #((
+    -*)  ac_site_file1=./$CONFIG_SITE;;
+    */*) ac_site_file1=$CONFIG_SITE;;
+    *)   ac_site_file1=./$CONFIG_SITE;;
+  esac
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file" \
+      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special files
+  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+       # differences in whitespace do not lead to failure.
+       ac_old_val_w=`echo x $ac_old_val`
+       ac_new_val_w=`echo x $ac_new_val`
+       if test "$ac_old_val_w" != "$ac_new_val_w"; then
+         { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+         ac_cache_corrupted=:
+       else
+         { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+         eval $ac_var=\$ac_old_val
+       fi
+       { $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+       { $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+       @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+  *@@@%%%=?*=@@@%%%*)
+    eval ac_cv_prog_make_${ac_make}_set=yes;;
+  *)
+    eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  SET_MAKE=
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+  ./ | .// | /[cC]/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+       if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+         if test $ac_prog = install &&
+           grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # AIX install.  It has an incompatible calling convention.
+           :
+         elif test $ac_prog = install &&
+           grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # program-specific install script used by HP pwplus--don't use.
+           :
+         else
+           rm -rf conftest.one conftest.two conftest.dir
+           echo one > conftest.one
+           echo two > conftest.two
+           mkdir conftest.dir
+           if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+             test -s conftest.one && test -s conftest.two &&
+             test -s conftest.dir/conftest.one &&
+             test -s conftest.dir/conftest.two
+           then
+             ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+             break 3
+           fi
+         fi
+       fi
+      done
+    done
+    ;;
+esac
+
+  done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+
+if test "${EMACS}" = "t" -o -n "${INSIDE_EMACS}"; then
+   EMACS=""
+fi
+
+
+# Check whether --with-xemacs was given.
+if test "${with_xemacs+set}" = set; then :
+  withval=$with_xemacs;  if test "${withval}" = "yes"; then EMACS=xemacs; else EMACS=${withval}; fi
+fi
+
+
+# Check whether --with-emacs was given.
+if test "${with_emacs+set}" = set; then :
+  withval=$with_emacs;  if test "${withval}" = "yes"; then EMACS=emacs; else EMACS=${withval}; fi
+fi
+
+# Extract the first word of "makeinfo", so it can be a program name with args.
+set dummy makeinfo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_MAKEINFO+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$MAKEINFO"; then
+  ac_cv_prog_MAKEINFO="$MAKEINFO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_MAKEINFO="makeinfo"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_prog_MAKEINFO" && ac_cv_prog_MAKEINFO="no"
+fi
+fi
+MAKEINFO=$ac_cv_prog_MAKEINFO
+if test -n "$MAKEINFO"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAKEINFO" >&5
+$as_echo "$MAKEINFO" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+# Extract the first word of "emacs", so it can be a program name with args.
+set dummy emacs; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_EMACS+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$EMACS"; then
+  ac_cv_prog_EMACS="$EMACS" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_EMACS="emacs"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_prog_EMACS" && ac_cv_prog_EMACS="xemacs"
+fi
+fi
+EMACS=$ac_cv_prog_EMACS
+if test -n "$EMACS"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $EMACS" >&5
+$as_echo "$EMACS" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $EMACS is really XEmacs" >&5
+$as_echo_n "checking if $EMACS is really XEmacs... " >&6; }
+
+elisp="(if (string-match \"XEmacs\" emacs-version) \"yes\" \"no\") "
+if test -z ""noecho""; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for xemacsp" >&5
+$as_echo_n "checking for xemacsp... " >&6; }
+fi
+if ${EMACS_cv_SYS_xemacsp+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+       OUTPUT=./conftest-$$
+       echo ${EMACS} -batch -eval "(let ((x ${elisp})) (write-region (if (stringp x) (princ x) (prin1-to-string x)) nil \"${OUTPUT}\"))" >& 5 2>&1
+       ${EMACS} -batch -eval "(let ((x ${elisp})) (write-region (if (stringp x) (princ x 'ignore) (prin1-to-string x)) nil \"${OUTPUT}\"nil 5))" >& 5 2>&1
+       retval=`cat ${OUTPUT}`
+       echo "=> ${retval}" >& 5 2>&1
+       rm -f ${OUTPUT}
+       EMACS_cv_SYS_xemacsp=$retval
+
+fi
+
+xemacsp=${EMACS_cv_SYS_xemacsp}
+if test -z ""noecho""; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xemacsp" >&5
+$as_echo "$xemacsp" >&6; }
+fi
+
+  XEMACS=${EMACS_cv_SYS_xemacsp}
+  EMACS_FLAVOR=emacs
+  if test "$XEMACS" = "yes"; then
+     EMACS_FLAVOR=xemacs
+  fi
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XEMACS" >&5
+$as_echo "$XEMACS" >&6; }
+
+
+
+  if test "$prefix" = "NONE"; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking prefix for your Emacs" >&5
+$as_echo_n "checking prefix for your Emacs... " >&6; }
+
+elisp="(expand-file-name \"..\" invocation-directory)"
+if test -z ""noecho""; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for prefix" >&5
+$as_echo_n "checking for prefix... " >&6; }
+fi
+if ${EMACS_cv_SYS_prefix+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+       OUTPUT=./conftest-$$
+       echo ${EMACS} -batch -eval "(let ((x ${elisp})) (write-region (if (stringp x) (princ x) (prin1-to-string x)) nil \"${OUTPUT}\"))" >& 5 2>&1
+       ${EMACS} -batch -eval "(let ((x ${elisp})) (write-region (if (stringp x) (princ x 'ignore) (prin1-to-string x)) nil \"${OUTPUT}\"nil 5))" >& 5 2>&1
+       retval=`cat ${OUTPUT}`
+       echo "=> ${retval}" >& 5 2>&1
+       rm -f ${OUTPUT}
+       EMACS_cv_SYS_prefix=$retval
+
+fi
+
+prefix=${EMACS_cv_SYS_prefix}
+if test -z ""noecho""; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $prefix" >&5
+$as_echo "$prefix" >&6; }
+fi
+
+       prefix=${EMACS_cv_SYS_prefix}
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $prefix" >&5
+$as_echo "$prefix" >&6; }
+  fi
+
+# Check whether --with-lispdir was given.
+if test "${with_lispdir+set}" = set; then :
+  withval=$with_lispdir; lispdir=${withval}
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking where .elc files should go" >&5
+$as_echo_n "checking where .elc files should go... " >&6; }
+  if test -z "$lispdir"; then
+        theprefix=$prefix
+    if test "x$theprefix" = "xNONE"; then
+       theprefix=$ac_default_prefix
+    fi
+    if test "$EMACS_FLAVOR" = "xemacs"; then
+        datadir="\$(prefix)/lib"
+        lispdir="\$(datadir)/${EMACS_FLAVOR}/site-packages/lisp/gnus"
+    else
+    lispdir="\$(datadir)/${EMACS_FLAVOR}/site-lisp/gnus"
+    fi
+    for thedir in share lib; do
+       potential=
+               if test -d "${theprefix}/${thedir}/${EMACS_FLAVOR}/site-lisp"; then
+           if test "$EMACS_FLAVOR" = "xemacs"; then
+              lispdir="\$(prefix)/${thedir}/${EMACS_FLAVOR}/site-packages/lisp/gnus"
+           else
+               lispdir="\$(datadir)/${EMACS_FLAVOR}/site-lisp/gnus"
+           fi
+          break
+       fi
+    done
+  fi
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lispdir" >&5
+$as_echo "$lispdir" >&6; }
+
+
+
+
+# Check whether --with-etcdir was given.
+if test "${with_etcdir+set}" = set; then :
+  withval=$with_etcdir; etcdir=${withval}
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking where etc files should go" >&5
+$as_echo_n "checking where etc files should go... " >&6; }
+  if test -z "$etcdir"; then
+        if test "$EMACS_FLAVOR" = "xemacs"; then
+      etcdir="\$(lispdir)/../../etc"
+    else
+      etcdir="\$(lispdir)/../../etc"
+    fi
+  fi
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $etcdir" >&5
+$as_echo "$etcdir" >&6; }
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking where the TeXinfo docs should go" >&5
+$as_echo_n "checking where the TeXinfo docs should go... " >&6; }
+    if test "$infodir" = "\${prefix}/info"; then
+    if test "$EMACS_FLAVOR" = "xemacs"; then
+      info_dir="\$(prefix)/${thedir}/${EMACS_FLAVOR}/site-packages/info"
+    else
+      info_dir="\$(prefix)/info"
+    fi
+  else
+    info_dir=$infodir
+  fi
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $info_dir" >&5
+$as_echo "$info_dir" >&6; }
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking which options to pass on to (X)Emacs" >&5
+$as_echo_n "checking which options to pass on to (X)Emacs... " >&6; }
+  if test "x$FLAGS" = "x"; then
+    if test "$EMACS_FLAVOR" = "xemacs"; then
+      FLAGS="-batch -no-autoloads -l \$(srcdir)/dgnushack.el"
+    else
+      FLAGS="-batch -q -no-site-file -l \$(srcdir)/dgnushack.el"
+    fi
+  else
+    FLAGS=$FLAGS
+  fi
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FLAGS" >&5
+$as_echo "$FLAGS" >&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
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_LATEX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $LATEX in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_LATEX="$LATEX" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_LATEX="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+LATEX=$ac_cv_path_LATEX
+if test -n "$LATEX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LATEX" >&5
+$as_echo "$LATEX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$LATEX" && break
+done
+test -n "$LATEX" || LATEX="no"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for available fonts" >&5
+$as_echo_n "checking for available fonts... " >&6; }
+
+# Check whether --with-fonts was given.
+if test "${with_fonts+set}" = set; then :
+  withval=$with_fonts; USE_FONTS="$withval"
+fi
+
+WITH_FONTS_bembo='%'
+WITHOUT_FONTS_bembo=
+WITH_FONTS_pfu='%'
+WITHOUT_FONTS_pfu=
+WITH_FONTS_bcr='%'
+WITHOUT_FONTS_bcr=
+if test -z "${USE_FONTS}"; then
+  if test "${LATEX}" = no; then
+       :
+  else
+    OUTPUT=./conftest-$$
+    echo '\nonstopmode\documentclass{article}\usepackage{bembo}\begin{document}\end{document}' > ${OUTPUT}
+    if ${LATEX} ${OUTPUT} </dev/null >& 5 2>&1  ; then
+      if test -z "${USE_FONTS}"; then
+       USE_FONTS="Adobe Bembo"
+      else
+       USE_FONTS="${USE_FONTS}, Adobe Bembo"
+      fi
+      WITH_FONTS_bembo=
+      WITHOUT_FONTS_bembo='%'
+    fi
+    echo '\nonstopmode\documentclass{article}\begin{document}{\fontfamily{pfu}\fontsize{10pt}{10}\selectfont test}\end{document}' > ${OUTPUT}
+    if retval=`${LATEX} ${OUTPUT} </dev/null 2>& 5`; then
+      if echo "$retval" | grep 'Some font shapes were not available' >& 5 2>&1  ; then
+       :
+      else
+        if test -z "${USE_FONTS}"; then
+         USE_FONTS="Adobe Futura"
+        else
+         USE_FONTS="${USE_FONTS}, Adobe Futura"
+        fi
+        WITH_FONTS_pfu=
+        WITHOUT_FONTS_pfu='%'
+      fi
+    fi
+    echo '\nonstopmode\documentclass{article}\begin{document}{\fontfamily{bcr}\fontsize{10pt}{10}\selectfont test}\end{document}' > ${OUTPUT}
+    if retval=`${LATEX} ${OUTPUT} </dev/null 2>& 5`; then
+      if echo "$retval" | grep 'Some font shapes were not available' >& 5 2>&1  ; then
+       :
+      else
+        if test -z "${USE_FONTS}"; then
+         USE_FONTS="Bitstream Courier"
+        else
+         USE_FONTS="${USE_FONTS}, Bitstream Courier"
+        fi
+        WITH_FONTS_bcr=
+        WITHOUT_FONTS_bcr='%'
+      fi
+    fi
+    rm -f ${OUTPUT} ${OUTPUT}.aux ${OUTPUT}.log ${OUTPUT}.dvi
+  fi
+elif test "${USE_FONTS}" = yes ; then
+  WITH_FONTS_bembo=
+  WITHOUT_FONTS_bembo='%'
+  WITH_FONTS_pfu=
+  WITHOUT_FONTS_pfu='%'
+  WITH_FONTS_bcr=
+  WITHOUT_FONTS_bcr='%'
+fi
+
+
+
+
+
+
+if test -z "${USE_FONTS}" ; then
+  USE_FONTS=no
+fi
+USE_FONTS=`echo "${USE_FONTS}" | sed 's/,\([^,]*\)$/ and\1/'`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: \"${USE_FONTS}\"" >&5
+$as_echo "\"${USE_FONTS}\"" >&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
+
+
+
+# Extract the first word of "gzip", so it can be a program name with args.
+set dummy gzip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_GZIP_PROG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $GZIP_PROG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_GZIP_PROG="$GZIP_PROG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_GZIP_PROG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+GZIP_PROG=$ac_cv_path_GZIP_PROG
+if test -n "$GZIP_PROG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GZIP_PROG" >&5
+$as_echo "$GZIP_PROG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+# Check whether --with-compress-install was given.
+if test "${with_compress_install+set}" = set; then :
+  withval=$with_compress_install;  if test "${withval}" = no; then
+               COMPRESS_INSTALL=no;
+         else
+               if test -n "${GZIP_PROG}"; then
+                       COMPRESS_INSTALL=yes;
+               else
+                       COMPRESS_INSTALL=no;
+               fi;
+         fi
+else
+   if test -n "${GZIP_PROG}"; then
+               COMPRESS_INSTALL=yes;
+         else
+               COMPRESS_INSTALL=no;
+         fi
+fi
+
+
+
+ac_config_files="$ac_config_files Makefile etc/Makefile lisp/Makefile texi/Makefile texi/gnusconfig.tex texi/ps/Makefile"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes: double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
+      sed -n \
+       "s/'/'\\\\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    if test "x$cache_file" != "x/dev/null"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+      if test ! -f "$cache_file" || test -h "$cache_file"; then
+       cat confcache >"$cache_file"
+      else
+        case $cache_file in #(
+        */* | ?:*)
+         mv -f confcache "$cache_file"$$ &&
+         mv -f "$cache_file"$$ "$cache_file" ;; #(
+        *)
+         mv -f confcache "$cache_file" ;;
+       esac
+      fi
+    fi
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section.  Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[    ]*#[    ]*define[       ][      ]*\([^  (][^    (]*([^)]*)\)[   ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[    ]*#[    ]*define[       ][      ]*\([^  ][^     ]*\)[   ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[     `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+       g
+       s/^\n//
+       s/\n/ /g
+       p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+       expr "X$arg" : "X\\(.*\\)$as_nl";
+       arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='        ';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+  with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=?*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  --*=)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    '') as_fn_error $? "missing file argument" ;;
+    esac
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h |  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+  *) as_fn_append ac_config_targets " $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "etc/Makefile") CONFIG_FILES="$CONFIG_FILES etc/Makefile" ;;
+    "lisp/Makefile") CONFIG_FILES="$CONFIG_FILES lisp/Makefile" ;;
+    "texi/Makefile") CONFIG_FILES="$CONFIG_FILES texi/Makefile" ;;
+    "texi/gnusconfig.tex") CONFIG_FILES="$CONFIG_FILES texi/gnusconfig.tex" ;;
+    "texi/ps/Makefile") CONFIG_FILES="$CONFIG_FILES texi/ps/Makefile" ;;
+
+  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp= ac_tmp=
+  trap 'exit_status=$?
+  : "${ac_tmp:=$tmp}"
+  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = "\a"
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[         ]*VPATH[        ]*=[    ]*/{
+h
+s///
+s/^/:/
+s/[     ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[  ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[      ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X "  :F $CONFIG_FILES      "
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$ac_tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+        # (if the path is not absolute).  The absolute path cannot be DOS-style,
+        # because $ac_f cannot contain `:'.
+        test -f "$ac_f" ||
+          case $ac_f in
+          [\\/$]*) false;;
+          *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+          esac ||
+          as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append ac_file_inputs " '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+         $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+       `' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$ac_tmp/stdin" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$ac_file" : 'X\(//\)[^/]' \| \
+        X"$ac_file" : 'X\(//\)$' \| \
+        X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+  as_dir="$ac_dir"; as_fn_mkdir_p
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+  s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[         ]*datarootdir[  ]*:*=/p' \
+      "$ac_tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&2;}
+
+  rm -f "$ac_tmp/stdin"
+  case $ac_file in
+  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+  esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/xemacs-packages/gnus/configure.in b/xemacs-packages/gnus/configure.in
new file mode 100644 (file)
index 0000000..f516395
--- /dev/null
@@ -0,0 +1,52 @@
+AC_INIT(lisp/gnus.el)
+AC_SET_MAKE
+AC_PROG_INSTALL
+
+dnl
+dnl Apparently, if you run a shell window or a term window in Emacs,
+dnl it sets the EMACS environment variable to 't' or a version number
+dnl of Emacs.  Lets undo the damage.
+dnl
+if test "${EMACS}" = "t" -o -n "${INSIDE_EMACS}"; then
+   EMACS=""
+fi
+
+AC_ARG_WITH(xemacs,
+       [AS_HELP_STRING([[--with-xemacs[=PROG]]],
+                       [use XEmacs to build (default: PROG=xemacs)])],
+       [ if test "${withval}" = "yes"; then EMACS=xemacs; else EMACS=${withval}; fi ])
+AC_ARG_WITH(emacs,
+       [AS_HELP_STRING([[--with-emacs[=PROG]]],
+                       [use Emacs to build (default: PROG=emacs)])],
+       [ if test "${withval}" = "yes"; then EMACS=emacs; else EMACS=${withval}; fi ])
+AC_CHECK_PROG(MAKEINFO, makeinfo, makeinfo, no)
+
+AC_CHECK_PROG(EMACS, emacs, emacs, xemacs)
+
+AC_PATH_LISPDIR
+AC_PATH_ETCDIR
+AC_PATH_INFO_DIR
+AC_SET_BUILD_FLAGS
+GNUS_CHECK_FONTS
+
+AC_PATH_PROG(GZIP_PROG, gzip)
+AC_ARG_WITH(compress-install,
+       [AS_HELP_STRING([[--without-compress-install]],
+               [do not compress .el and .info files when installing.])],
+       [ if test "${withval}" = no; then
+               COMPRESS_INSTALL=no;
+         else
+               if test -n "${GZIP_PROG}"; then
+                       COMPRESS_INSTALL=yes;
+               else
+                       COMPRESS_INSTALL=no;
+               fi;
+         fi ],
+       [ if test -n "${GZIP_PROG}"; then
+               COMPRESS_INSTALL=yes;
+         else
+               COMPRESS_INSTALL=no;
+         fi ])
+AC_SUBST(COMPRESS_INSTALL)
+
+AC_OUTPUT(Makefile etc/Makefile lisp/Makefile texi/Makefile texi/gnusconfig.tex texi/ps/Makefile)
diff --git a/xemacs-packages/gnus/contrib/ChangeLog b/xemacs-packages/gnus/contrib/ChangeLog
new file mode 100644 (file)
index 0000000..05b3527
--- /dev/null
@@ -0,0 +1,716 @@
+2012-12-12  Eric Abrahamsen  <eric@ericabrahamsen.net>
+
+       * gnus-namazu.el: Fix typo: (require 'gmm-util) -> (require 'gmm-utils)
+
+2012-12-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-namazu.el (gnus-namazu/update-p): Use gmm-labels.
+
+2012-11-08  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * gnus-namazu.el (gnus-namazu/make-directory-table): Bind
+       file-name-handler-alist to nil, in order to avoid that semicolons
+       included in group names trigger tramp related handlers.
+
+2011-12-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * compface.el (uncompface): Update the header format of icon data for
+       the most recent icontopbm program.
+
+2010-09-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * smtpmail.el: Removed.
+
+       * ucs-tables.el: Removed.
+
+       * sendmail.el: Removed.
+
+2010-09-26  Julien Danjou  <julien@danjou.info>
+
+       * ssl.el: Removed.
+
+       * xml.el: Removed.
+
+2010-09-26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gpg.el: Removed -- seems unused.
+
+2009-04-09  Richard M Stallman  <rms@gnu.org>
+
+       * sendmail.el (sendmail-send-it): Replace any
+       pre-existing Content-type header if we insert one.
+
+2009-03-15  Glenn Morris  <rgm@gnu.org>
+
+       * sendmail.el (mail-yank-prefix): Doc fix.
+       (mail-mode-map): Only enable the "Cite Original" menu-item when
+       appropriate.  Standardize the text used for other headers re hyphens.
+
+2009-03-14  Glenn Morris  <rgm@gnu.org>
+
+       * sendmail.el (mail-interactive): Doc fix.
+       (mail-yank-ignored-headers): Add X-RMAIL- headers, bump :version.
+       (mail-setup): Use the function mail-signature.
+       (mail-mode-hook): Doc fix.
+       (mail-to, mail-subject, mail-cc, mail-bcc, mail-reply-to)
+       (mail-mail-reply-to, mail-mail-followup-to): Doc fixes.
+       (mail-signature): Check the signature file is readable.
+       With the argument ATPOINT, really insert at point.
+       Handle the case when the variable mail-signature is an expression.
+
+2009-03-10  Glenn Morris  <rgm@gnu.org>
+
+       * sendmail.el (mail-archive-file-name, mail-default-headers):
+       Doc fixes.
+       (mail-mailing-lists): Remove leading `*' from defcustom doc.
+
+2009-03-03  Simon Josefsson  <simon@josefsson.org>
+
+       * smtpmail.el (smtpmail-auth-supported): Mention that list is
+       in preference order.
+       (smtpmail-try-auth-methods): Improve which authentication
+       mechanism to use, so that the locally most preferred and mutually
+       supported mechanism is used.
+
+009-02-26  Tobias C. Rittweiler  <tcr@freebits.de>  (tiny change)
+
+       * sendmail.el (sendmail-send-it): `call-process-region' can return a
+       string.  (Bug#2428)
+
+2009-02-07  Glenn Morris  <rgm@gnu.org>
+
+       * sendmail.el (mail-bury-selects-summary, mail-yank-original): Doc fix.
+       (rmail-output-to-rmail-buffer): Autoload it.
+       (mail-do-fcc): Give it a doc string.  Update for mbox Rmail, simplify.
+
+2009-01-23  Glenn Morris  <rgm@gnu.org>
+
+       * sendmail.el (mail-bury): Revert previous change now pmail is no more.
+
+2008-12-26  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * README: Add gnus-kill-to-score.el.
+
+       * gnus-kill-to-score.el: New file from
+       <http://heim.ifi.uio.no/~larsi/ding-various/gnus-kill-to-score.el>.
+
+2008-11-10  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * smtpmail.el (smtpmail-open-stream): Use
+       `starttls-any-program-available'.  Auto-load starttls.el for it.
+
+2008-06-06  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * sendmail.el (mail-interactive): Change default.
+
+2008-06-05  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * README: Remove entry about nnir.el.
+
+       * nnir.el: Move to ../lisp.
+
+2008-05-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * compface.el (uncompface): Make buffer, in which uncompface program
+       runs, unibyte.
+
+2008-05-19  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * smtpmail.el: Add autoload for `auth-source-user-or-password'.
+       (smtpmail-try-auth-methods): Use it.
+
+2008-05-15  Andreas Schwab  <schwab@suse.de>
+
+       * nnir.el (nnir-add-result): Properly substitute the parameters.
+
+2008-05-08  Reiner Steib  <reiner.steib@gmx.de>
+
+       * nnir.el (nnir-run-waissearch, nnir-run-swish++): Remove unused local
+       variable.
+       (nnimap-server-buffer): Silence compiler warning.
+
+2008-04-24  Christoph Conrad  <christoph.conrad@gmx.de>
+
+       * nnir.el: Fix byte compiler warnings.
+       (nnir-retrieve-headers): Don't set let-bound vars to nil.  Replace
+       mapcar called for effect with mapc.
+       (nnir-compose-result): Bind `group'.  Don't set let-bound vars to nil.
+       (nnir-run-imap, nnir-artlist-groups): Replace mapcar called for effect
+       with mapc.
+       (nnir-run-swish++, nnir-run-swish-e, nnir-run-namazu): Don't set
+       let-bound vars to nil.
+
+2008-04-21  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnir.el: Don't require cl at runtime.  Require gnus-util at runtime.
+       Autoload nnimap and imap functions.
+
+2008-04-21  Justus Piater  <Justus-bulk@Piater.name>
+
+       * nnir.el (nnir-compose-result): Use `gnus-replace-in-string' instead
+       of `substitute' to avoid using cl at runtime.
+
+2008-04-19  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnir.el: Don't require edmacro anymore.  Remove bogus Emacs 19
+       compatibility code for `kbd'.  Replace `string-to-int' with
+       `string-to-number'.
+       (nnmaildir-base-name-to-article-number): Autoload.
+       (nnir-compose-result): Simplify the code.
+
+2008-04-19  Justus Piater  <Justus-bulk@Piater.name>
+
+       * nnir.el (nnir-add-result): New helper macro.
+       (nnir-compose-result): Use it.  Fix inexistent file check for maildir.
+
+2008-04-15  Christoph Conrad  <christoph.conrad@gmx.de>
+
+       * nnir.el (nnir-run-swish++): Fix inexistent file check for nnml.
+
+2008-04-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnir.el (nnir-run-swish++): Fix typo in doc string.  Move comment on
+       nnml-use-compressed-files to more suitable place.
+
+2008-04-13  Daniel Pittman  <daniel@rimspace.net>
+
+       * nnir.el (nnir-run-imap): Add doc string.  Use `nnir-imap-make-query'.
+       (nnir-imap-make-query, nnir-imap-query-to-imap)
+       (nnir-imap-expr-to-imap, nnir-imap-parse-query, nnir-imap-next-expr)
+       (nnir-imap-peek-symbol, nnir-imap-next-symbol)
+       (nnir-imap-delimited-string, nnir-imap-end-of-input): New functions.
+       Implement a query language for IMAP search, parse that and compose the
+       back-end query from it.  This allows searches with AND, OR and fixed
+       strings, not just a single substring.
+
+2008-04-13  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnir.el: Add assignment status.
+       (nnir-group-mode-hook): Remove XEmacs 19 compatibility code.
+
+2008-04-13  Justus Piater  <Justus-bulk@Piater.name>
+
+       * nnir.el (nnir-run-swish++): Suppress non-existing files.
+       (nnir-group-server): For native groups, obtain the server name from
+       gnus-select-method.
+       (nnir-run-swish++, nnir-run-namazu): Support nnmaildir.
+       (nnir-compose-result): New function unifying some code formerly
+       duplicated between nnir-run-swish++ and nnir-run-namazu.
+
+2008-02-06  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * README: Clarify relevant Emacs versions for sendmail.el and
+       smtpmail.el.  Add fill-column.  Refill paragraphs.  Typographic fixes.
+       Add comment about gpg-ring.el and gpg.el.
+
+2007-12-09  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * README: Remove hashcash.el.
+
+2007-12-09  Dan Nicolaescu  <dann@ics.uci.edu>
+
+       * sendmail.el (dired-view-file, dired-get-filename): Declare as
+       functions.
+
+2007-11-24  Kenichi Handa  <handa@m17n.org>
+
+       * ucs-tables.el (ucs-8859-7-alist): Update the table.
+
+2007-11-20  Noah S. Friedman  <friedman@splode.com>
+
+       * vcard.el: Update to revision 1.11 2000/06/29.
+
+2007-10-15  Sam Steingold  <sds@gnu.org>
+
+       * sendmail.el (sendmail-error-reporting-interactive)
+       (sendmail-error-reporting-non-interactive): New variables for
+       sendmail error reporting options to simplify support for imperfect
+       sendmail emulators.
+       (sendmail-send-it): Use them instead of list literals.
+
+2007-10-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Relicense "GPLv2 or later" files to "GPLv3 or later".
+
+2007-09-23  Richard Stallman  <rms@gnu.org>
+
+       * sendmail.el (mail-bury): Delete the frame if this frame looks
+       like it was made for this message.
+
+2007-09-16  Andreas Seltenreich  <andreas@gate450.dyndns.org>
+
+       * nnir.el (nnir-run-query): Add a find-grep engine.
+
+2007-04-06  Chong Yidong  <cyd@stupidchicken.com>
+
+       * sendmail.el (mail-text, mail-mode): Revert extant pieces of
+       1995-05-19 doc changes.
+
+2007-03-26  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * nnir.el (gnus-group-make-nnir-group): Put a message-unique-id into
+       names of ephemeral groups to avoid gnus-backlog related caching
+       problems on repeated searches.
+
+2007-03-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * smtpmail.el: Signal an error when used with Emacs 22+ or XEmacs.
+       (smtpmail-send-it): Remove NOMODIFY argument of
+       `set-buffer-file-coding-system' for compatibility with Emacs 21.
+
+2007-02-20  Juanma Barranquero  <lekktu@gmail.com>
+
+       * smtpmail.el (smtpmail-smtp-service, smtpmail-queue-index-file):
+       Fix typos in docstrings.
+       (smtpmail-local-domain, smtpmail-queue-mail): Doc fixes.
+
+2007-01-06  Simon Josefsson  <simon@josefsson.org>
+
+       * README: Mention that smtpmail.el doesn't work on XEmacs.
+
+2006-11-24  Eli Zaretskii  <eliz@gnu.org>
+
+       * smtpmail.el (smtpmail-send-it):
+       Copy buffer-file-coding-system from the mail buffer.  Possibly add a
+       MIME header for the message encoding.
+       Bind coding-system-for-write around the call to mail-do-fcc.
+       Use smtpmail-code-conv-from to encode queued mail messages.
+
+2006-10-02  MIYOSHI Masanori  <miyoshi@meadowy.org>  (tiny change)
+
+       * smtpmail.el (smtpmail-try-auth-methods): Fix typo in
+       2006-09-28 commit.
+
+2006-09-28  Osamu Yamane  <yamane@green.ocn.ne.jp> (tiny change)
+
+       * smtpmail.el (smtpmail-try-auth-methods): Do not break long
+       lines in base64-encoded authentication response.
+
+2006-09-04  Chong Yidong  <cyd@stupidchicken.com>
+
+       * sendmail.el (sendmail-program): Moved here from pathe.el.
+
+2006-08-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * compface.el (uncompface): Use binary rather than raw-text-unix.
+
+2006-08-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * compface.el (uncompface): Make sure the eol conversion doesn't take
+       place when communicating with the external programs.  Reported by
+       ARISAWA Akihiro <ari@mbf.ocn.ne.jp>.
+
+2006-07-17  Sascha Wilde  <wilde@sha-bang.de>
+
+       * nnir.el: Removed support for non free backends glimpse and excite.
+       Changed and updated copyright to Free Software Foundation.  Moved all
+       authors to head.
+
+2006-06-15  Chong Yidong  <cyd@stupidchicken.com>
+
+       * sendmail.el (mail-send): Search explicitly for
+       mail-header-separator when checking for corrupted header lines.
+
+2006-06-10  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * nnir.el (nnir-read-server-parm): Do not unconditionally fall back to
+       global variables if nnir-mail-backend is nil.
+       (nnir-retrieve-headers): Error on void novitem.  It would just result
+       in a more obscure error later.
+
+2006-06-09  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * nnir.el (nnir-group-server): DTRT when called on native groups.  The
+       macro is called on groups without checking for foreigness, although the
+       docstring stated it was only for foreign ones.
+
+2006-06-08  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * nnir.el (nnir-retrieve-headers): Bind gnus-override-method before
+       calling gnus-retrieve-headers.  If we hit a group that isn't in
+       gnus-newsrc-hashtb, gnus-find-method-for-group invented a new select
+       method with empty parameters, possibly corrupting
+       gnus-server-method-cache on the next call to gnus-method-to-server.
+
+2006-06-01  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * nnir.el (nnir-retrieve-headers): Revert last change; we might as well
+       see message-ids instead of article numbers.
+       (nnir-request-article): Actually check for message-ids.
+
+2006-06-01  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnir.el (nnir-run-swish++): Compressed files might not have .gz
+       extension.
+
+2006-05-31  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * nnir.el (nnir-retrieve-headers, nnir-request-article): Move check for
+       message-id request.
+
+2006-05-30  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * nnir.el (nnir-retrieve-headers): Return correct article numbers when
+       less than the full range is selected.
+
+2006-05-12  Simon Josefsson  <jas@extundo.com>
+
+       * nnir.el: Compare servers using gnus-server-equal, otherwise
+       string methods in nnir-mail-backend won't work.
+
+2006-04-11  Sascha Wilde  <wilde@sha-bang.de>
+
+       * nnir.el (nnir-run-swish++): Allow matching gzipped files.
+
+2006-02-11  Miles Bader  <miles@gnu.org>
+
+       * sendmail.el, smtpmail.el: New files, from Emacs tree.
+
+2005-12-22  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * gnus-namazu.el (gnus-namazu-remote-groups): Accept `t' as an
+       symbol that matches the method specified by `gnus-select-method'.
+       (gnus-namazu/make-directory-table): Follow the above change.
+       (gnus-namazu/call-namazu): Wrap a query string with quotes.
+
+2005-12-05  Adrian Aichner  <adrian@xemacs.org>
+
+       * nnir.el: New variable nnir-swish-e-index-files to support
+       multiple swish-e index files.
+       * nnir.el (nnir-swish-e-index-file): Make obsolete.
+       * nnir.el (nnir-swish-e-index-files): New.
+       * nnir.el (nnir-run-swish-e): Use nnir-swish-e-index-files.
+
+2005-05-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnir.el (nnir): Add :group.
+
+2005-01-26  Steve Youngs  <steve@sxemacs.org>
+
+       * gpg.el: Add timer/itimer compatibility.
+
+2004-10-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * README (compface.el): Describe.
+
+2004-10-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * compface.el: Move the version of ELisp-based uncompface program
+       from the lisp directory because of the copyright problem.
+
+2004-09-27  Simon Josefsson  <jas@extundo.com>
+
+       * hashcash.el: Move to ../lisp/.
+
+2004-07-30  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * gnus-namazu.el (gnus-namazu/make-directory-table): Treat drive
+       letters when calcurating pathnames of remote groups.
+       From KOSEKI Yoshinori <kose@meadowy.org> (tiny change).
+
+2004-05-27  Simon Josefsson  <jas@extundo.com>
+
+       * starttls.el: Moved to ../lisp/.
+
+2004-05-26  Simon Josefsson  <jas@extundo.com>
+
+       * starttls.el: Sync with proposed Emacs version.
+
+2004-05-13  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * gnus-namazu.el (gnus-namazu/setup): Do not update indices
+       `gnus-namazu-command-prefix' is non-nil.
+
+2004-05-12  Kai Grossjohann  <kai@emptydomain.de>
+
+       * README (nnir.el): Describe.
+
+2004-05-11  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * README (gnus-namazu.el): Describe.
+
+       * gnus-namazu.el: New file.
+
+2004-04-05  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnir.el (nnir-group-server): Fix doc-string, indent.
+
+2004-04-05  Andreas Schwab  <schwab@suse.de>
+
+       * nnir.el (nnir-group-server): Move before first use.
+
+2004-03-15  Adrian Lanz  <lanz@fowi.ethz.ch>  (tiny change)
+
+       * nnir.el (nnir-run-swish-e): Fixed typo.
+
+2004-01-23  Jesper Harder  <harder@ifa.au.dk>
+
+       * README: update.
+
+       * md5.el: Remove.
+
+       * base64.el: Remove.
+
+2004-01-16  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnir.el (nnir-run-glimpse): Fixed typo.  Reported by Patrick
+       Drechsler <patrick.drechsler@gmx.net>.
+
+2003-11-15  Simon Josefsson  <jas@extundo.com>
+
+       * starttls.el: Sync with recent gnu.emacs.sources post.
+
+2003-10-24  Steve Youngs  <sryoungs@bigpond.net.au>
+
+       * nnir.el: Autoload `read-kbd-macro' at compile time.
+
+2003-09-30  Torsten Hilbrich  <torsten.hilbrich@gmx.net>
+
+       * nnir.el (nnir-imap-search-field, nnir-imap-search-arguments)
+       (nnir-imap-search-argument-history): New variables.
+       (nnir-engines, nnir-run-imap): Use them.
+       (nnir-read-parm): Support reading the new IMAP query parameters.
+
+2003-06-03  Kai Gro\e,A_\e(Bjohann  <kai.grossjohann@gmx.net>
+
+       * README: Explain purpose of each file (well, most files).
+
+2003-05-01  Vasily Korytov  <deskpot@despammed.com>
+
+       * gpg.el (gpg-passphrase-forget): Check that gpg-passphrase is
+       set.
+
+2003-04-17  Steve Youngs  <youngs@xemacs.org>
+
+       * hashcash.el (hashcash-point-at-bol): Move the fbound test
+       outside of the defalias.
+       (hashcash-point-at-eol): Ditto.
+
+2003-03-19  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-idna.el: Update.
+
+2003-03-11  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * hashcash.el (hashcash-version, hashcash-insert-payment): patch
+       from Paul Foley
+
+2003-03-07  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-idna.el (gnus-idna-to-ascii-rhs-1): Narrow to
+       head (otherwise forwarded mail break havoc).
+
+2003-03-07  Teodor Zlatanov  <tzz@bwh.harvard.edu>
+
+       * hashcash.el: New version from Paul Foley with better variable
+       names, executable-find support, and no errors in GNU Emacs
+       (hashcash-version): return nil when invoked with a
+       nil token
+
+2003-02-21  Simon Josefsson  <jas@extundo.com>
+
+       * hashcash.el (hashcash-point-at-bol):
+       (hashcash-point-at-eol): Defalias.
+       (hashcash-generate-payment):
+       (mail-check-payment): Use it.
+
+2002-12-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * hashcash.el: New version from Paul Foley with new
+       mail-check-payment function.
+
+2002-06-22  Simon Josefsson  <jas@extundo.com>
+
+       * hashcash.el: New file.
+       (hashcash-default-payment, hashcash-payment-alist, hashcash):
+       Defcustom.
+       (hashcash-generate-payment): Update to recent hashcode command
+       line syntax.
+       (hashcash-insert-payment): Use X-Hashcode:.
+       (mail-add-payment): Also look at Newsgroups.
+       (top-level): Add provide and EOF comment.
+       (mail-add-payment): Autoload.
+       (hashcash-insert-payment): s/Hashcode/Hashcash/
+       (mail-add-payment): Doc fix.
+
+2002-05-20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-mdrtn.el (gnus-moderated-groups): Removed (require 'gnus-load).
+
+2002-04-24  Kai Gro\e,A_\e(Bjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * ucs-tables.el (featurep): Barf on XEmacs.
+
+2002-03-06  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * ucs-tables.el: Copy from Emacs 21.
+
+2002-03-05  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * xml.el: Sync with Emacs 21.
+
+2002-01-25  Josh Huber  <huber@alum.wpi.edu>
+
+       * gpg.el (gpg-command-decrypt): Enable the status-fd command line
+       option to gpg when decrypting so `mml2015-mailcrypt-decrypt' can
+       parse and display the output.
+
+2002-01-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-mdrtn.el (gnus-moderation-cancel-article): Insert an extra
+       newline.
+
+2001-12-26  Florian Weimer  <fw@deneb.enyo.de>
+
+       * gpg.el (gpg-command-default-alist): Using gpg-2comp is no longer
+       the default.
+
+2001-12-18  Josh Huber  <huber@alum.wpi.edu>
+
+       * ChangeLog: changed buffer-file-coding-system back to
+       coding. (oops)
+
+2001-12-17  Josh Huber  <huber@alum.wpi.edu>
+
+       * ChangeLog: changed coding to buffer-file-coding-system
+
+2001-11-22  Simon Josefsson  <jas@extundo.com>
+
+       * sha1.el: Removed. (A FSF copyrighted sha1-el.el file is in
+       ../lisp/).
+
+2001-10-30 21:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * canlock.el, hex-util.el, sha1-el.el: Move to lisp.
+
+2001-10-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * canlock.el (canlock-base64-encode-function): Removed.
+       (canlock-mmencode-program): Removed.
+       (canlock-mmencode-args-for-encoding): Removed.
+       (canlock-openssl-program): Renamed from `canlock-ssleay-program'.
+       (canlock-openssl-args): Renamed from `canlock-ssleay-args'.
+       (canlock-load-hook): Removed.
+       (canlock-base64-encode-string-with-mmencode): Removed.
+       (canlock-sha1-with-openssl): Renamed from
+       `canlock-sha1-with-ssleay'.
+       (canlock-hex-string-to-int): Removed.
+       (canlock-fetch-fields): Don't use `mapcar'.
+       (canlock-fetch-id-for-key): Don't use Cancel header if there is no
+       cancel command.
+       (gnus-summary-canlock-verify): Removed.
+       (wl-summary-canlock-verify): Removed.
+       (canlock-mew-summary-display): Removed.
+       (mew-summary-canlock-verify): Removed.
+       (mh-summary-canlock-verify): Removed.
+       (vm-summary-canlock-verify): Removed.
+       (cmail-summary-canlock-verify): Removed.
+       (rmail-summary-canlock-verify): Removed.
+
+2001-10-25  Simon Josefsson  <jas@extundo.com>
+
+       * canlock.el (canlock-password, canlock-password-for-verify)
+       (canlock-force-insert-header): Defcustom.
+
+2001-10-17  Simon Josefsson  <jas@extundo.com>
+
+       * canlock.el (sha1-binary): Autoload `sha1-binary'.
+       (canlock-sha1-function): Use it.
+       (canlock-sha1-function-for-verify): Ditto.
+
+       * sha1-el.el: New file.
+
+       * hex-util.el: Ditto.
+
+2001-08-24 16:09:14  Fabien Penso  <penso@linuxfr.org>
+
+       * gpg.el (gpg-command-sign-detached): Doc fix.
+
+2001-08-07  Andreas Jaeger  <aj@suse.de>
+
+       * gpg.el (gpg-passphrase-forget): Don't cache
+       gpg-passphrase-timer.
+       (gpg-passphrase-store): Check if gpg-passphrase-timer is
+       initialized already.
+
+2001-07-30 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+       From Andreas Fuchs <asf@void.at>
+
+       * gpg.el (gpg-command-verify): --status-fd 1
+       (gpg-unabbrev-trust-alist): New.
+
+2001-01-18  Colin Marquardt  <colin.marquardt@usa.alcatel.com>
+
+       * gpg.el (gpg-make-temp-file): Error info.
+
+2001-01-13 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gpg.el (gpg-build-arg-list): Use copy-sequence.
+
+2000-12-19 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gpg.el (defalias): Use eval-and-compile.
+       (gpg-command-all-arglist): Suggest by Jeff Senn <senn@maya.com>.
+
+2000-12-15 00:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gpg.el (gpg-command-alist): Alist may not be defined.
+
+2000-12-14 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gpg.el (gpg-make-temp-file): Don't check file-modes of M$Windows.
+
+2000-12-14 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gpg.el (gpg-passphrase-store): Don't activate timer if it is live.
+
+2000-11-30 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gpg.el (gpg-make-temp-file): Use expand-file-name.
+       (gpg-point-at-eol): New function.
+       (gpg-call-process): Use it.
+       (gpg-key-list-keys-parse-line): Ditto.
+       (gpg-with-passphrase-env): edebug-form-spec.
+       (gpg-with-temp-files): Ditto.
+       (gpg-show-result): Ditto.
+
+2000-11-08  Bj\e,Av\e(Brn Torkelsson  <torkel@hpc2n.umu.se>
+
+       * gpg.el: In Xemacs it is called point-at-eol, not
+       line-end-position
+
+       * gpg.el (gpg-key-lessp): use string-lessp instead of
+       compare-strings (not available on XEmacs)
+
+2000-11-16  Simon Josefsson  <sj@extundo.com>
+
+       * gpg.el (gpg-command-verify-cleartext): New variable.
+       (gpg-verify-cleartext): New function.
+
+2000-10-31 17:32:02  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gpg.el (gpg-verify): The last argument of apply is a list.
+       (gpg-encrypt): Add passphrase as a parameter.
+
+  Copyright (C) 2000-2016 Free Software Foundation, Inc.
+
+  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 3, 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.  If not, see <http://www.gnu.org/licenses/>.
+
+;; Local Variables:
+;; coding: iso-2022-7bit
+;; fill-column: 79
+;; add-log-time-zone-rule: t
+;; End:
diff --git a/xemacs-packages/gnus/contrib/README b/xemacs-packages/gnus/contrib/README
new file mode 100644 (file)
index 0000000..bf648ed
--- /dev/null
@@ -0,0 +1,36 @@
+The files in this directory are not (yet) part of the Gnus distribution proper.
+They may later become part of the distribution, or they may disappear
+altogether.
+
+Please note that it is NOT good to just add this directory to `load-path': a
+number of files in this directory will become part of more recent Emacs
+versions, so that you might be running obsolete libraries with all kinds of ill
+effects (cf. `list-load-path-shadows').
+
+The suggested method for installation is to copy those files that you need to a
+directory which is in `load-path'.
+
+Here is an overview of the files:
+
+compface.el
+
+       Provides the ELisp-based uncompface program.  It is excellent and
+       practical (actually you can replace lisp/compface.el with it), however
+       the author is missing and the copyright has not been assigned yet.
+
+gnus-namazu.el
+
+       This file defines the command to search mails and persistent articles
+       with Namazu, which is a full-text search engine distributed at
+       <http://namazu.org>, and to browse its results with Gnus.
+
+gnus-kill-to-score.el
+
+       Convert kill files to score files.  See (info "(gnus)Converting Kill
+       Files").
+
+vcard.el
+
+;; Local Variables:
+;; fill-column: 79
+;; End:
diff --git a/xemacs-packages/gnus/contrib/compface.el b/xemacs-packages/gnus/contrib/compface.el
new file mode 100644 (file)
index 0000000..09a4e7c
--- /dev/null
@@ -0,0 +1,752 @@
+;;; compface.el --- functions for converting X-Face headers
+;; Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;;     TAKAI Kousuke <tak@kmc.gr.jp>
+;; Keywords: 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 3, 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.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(defgroup compface nil
+  "X-Face image conversion."
+  :group 'extensions)
+
+(defcustom uncompface-use-external (and (not noninteractive)
+                                       (executable-find "uncompface")
+                                       (executable-find "icontopbm")
+                                       'undecided)
+  "*Specify which of the internal or the external decoder should be used.
+nil means to use the internal ELisp-based uncompface program.  t means
+to use the external decoder.  In the later case, you need to have the
+external `uncompface' and `icontopbm' programs installed.  The default
+value is nil if those external programs aren't available, otherwise
+`undecided' which means to determine it by checking whether the host
+machine is slow.  See also `uncompface-use-external-threshold'.  You
+can skip that check by setting this value as nil or t explicitly."
+  :type '(choice (const :tag "Use the internal decoder" nil)
+                (const :tag "Use the external decoder" t)
+                (const :tag "Autodetection" undecided))
+  :group 'compface)
+
+(defcustom uncompface-use-external-threshold 0.1
+  "*Number of seconds to check whether the host machine is slow.
+If the host takes time larger than this value for decoding an X-Face
+using the internal ELisp-based uncompface program, it will be changed
+to using the external `uncompface' and `icontopbm' programs if they
+are available.  Note that the measurement may never be exact."
+  :type 'number
+  :group 'compface)
+
+(eval-when-compile
+  (defmacro uncompface-float-time (&optional specified-time)
+    (if (fboundp 'float-time)
+       `(float-time ,specified-time)
+      `(let ((time (or ,specified-time (current-time))))
+        (+ (* (car time) 65536.0)
+           (cadr time)
+           (cond ((consp (setq time (cddr time)))
+                  (/ (car time) 1000000.0))
+                 (time
+                  (/ time 1000000.0))
+                 (t
+                  0)))))))
+
+(defun uncompface (face)
+  "Convert FACE to pbm.
+If `uncompface-use-external' is t, it requires the external programs
+`uncompface', and `icontopbm'.  On a GNU/Linux system these might be
+in packages with names like `compface' or `faces-xface' and `netpbm'
+or `libgr-progs', for instance."
+  (cond ((eq uncompface-use-external nil)
+        (uncompface-internal face))
+       ((eq uncompface-use-external t)
+        (with-temp-buffer
+          (unless (featurep 'xemacs) (set-buffer-multibyte nil))
+          (insert face)
+          (let ((coding-system-for-read 'raw-text)
+                ;; At least "icontopbm" doesn't work with Windows because
+                ;; the line-break code is converted into CRLF by default.
+                (coding-system-for-write 'binary))
+            (and (eq 0 (apply 'call-process-region (point-min) (point-max)
+                              "uncompface"
+                              'delete '(t nil) nil))
+                 (progn
+                   (goto-char (point-min))
+                   (insert "/* Format_version=1, Width=48, Height=48,\
+ Depth=1, Valid_bits_per_item=16 */\n")
+                   ;; I just can't get "icontopbm" to work correctly on its
+                   ;; own in XEmacs.  And Emacs doesn't understand un-raw pbm
+                   ;; files.
+                   (if (not (featurep 'xemacs))
+                       (eq 0 (call-process-region (point-min) (point-max)
+                                                  "icontopbm"
+                                                  'delete '(t nil)))
+                     (shell-command-on-region (point-min) (point-max)
+                                              "icontopbm | pnmnoraw"
+                                              (current-buffer) t)
+                     t))
+                 (buffer-string)))))
+       (t
+        (let* ((gc-cons-threshold (eval '(lsh -1 -1)))
+               (start (current-time)))
+          (prog1
+              (uncompface-internal face)
+            (setq uncompface-use-external
+                  (and (> (- (uncompface-float-time (current-time))
+                             (uncompface-float-time start))
+                          uncompface-use-external-threshold)
+                       (executable-find "uncompface")
+                       (executable-find "icontopbm")
+                       t))
+            (message "Setting `uncompface-use-external' to `%s'"
+                     uncompface-use-external))))))
+
+;; The following section is a bug-for-bug compatible version of
+;; `uncompface' program entirely implemented in Emacs-Lisp.
+
+(eval-when-compile
+  ;; The size of 48x48 is actually hard-coded into the code itself,
+  ;; so you cannot simply change those values.  So we hard-code
+  ;; them into the compiled code.
+  (defconst uncompface-width 48
+    "Width of X-Face bitmap image.")
+  (defconst uncompface-height 48
+    "Height of X-Face bitmap image.")
+
+  ;; Again, this is also hard-coded into the compiled code.
+  (defconst uncompface-guesses
+    (mapcar (lambda (x)
+             (mapcar (lambda (x)
+                       (let ((vector (make-vector (length x) nil))
+                             (i 0))
+                         (while x
+                           (or (zerop (car x))
+                               (aset vector i t))
+                           (setq x (cdr x)
+                                 i (1+ i)))
+                         vector))
+                     x))
+           '((;; g_00
+              (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1
+               0 0 0 0 0 1 0 1 0 0 0 1 0 1 1 1
+               0 0 0 0 0 1 0 1 0 0 0 0 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 1
+               0 0 0 0 1 1 1 1 1 1 0 1 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 1 1 0 1 0 0 0 0 1 1 1 1
+               0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
+               0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1
+               0 1 0 0 0 1 0 1 0 0 1 0 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1
+               0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
+               0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1
+               0 0 0 0 0 0 0 1 0 0 1 1 1 1 1 1
+               1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1
+               1 0 0 0 0 0 0 0 1 1 0 0 1 0 0 1
+               0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 1 1 0 1 1 0 0 0 1 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 1 0 0 1 1 1 1 0 1 0 1 0 1 0 0
+               0 0 0 0 0 1 1 1 0 0 0 1 1 1 1 1
+               0 1 0 1 0 1 1 1 0 1 0 0 0 1 1 1
+               1 1 0 1 0 1 1 1 0 0 1 1 1 1 0 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 1 0 1 1 1 1 1 0 0 0 1 1 1 1 1
+               0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1
+               0 0 0 0 0 1 0 1 0 0 0 0 1 1 1 1
+               0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 1
+               0 0 0 0 1 1 1 1 0 1 0 1 1 1 1 1
+               1 0 0 1 1 0 1 1 1 1 0 1 1 1 1 1
+               0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 1 0 1 1 1 1 1 0 0 0 1 1 1 0 1
+               0 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 1 1 1 1 0 0 0 1 1 1 1 1
+               0 0 0 0 1 1 1 1 0 1 0 1 1 1 1 1
+               0 0 0 0 0 0 1 1 0 0 0 1 1 1 1 1
+               0 1 0 0 1 1 1 1 0 1 0 1 1 1 1 1
+               1 1 1 1 0 1 1 1 0 1 1 1 1 1 1 1
+               0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 1 1 0 1 0 0 0 0 1 1 1 1
+               1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1
+               1 1 1 1 0 1 1 1 1 0 1 1 1 1 1 1
+               0 0 0 0 1 1 1 1 0 1 0 0 1 1 1 1
+               1 1 0 1 0 1 1 1 0 0 1 1 1 1 1 1
+               0 1 0 0 1 1 1 1 0 1 1 1 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 1 1 0 0 1 1 1 1 0 1 1 1 1 1 1
+               0 1 0 1 0 1 1 0 0 0 1 0 0 1 0 1
+               0 0 0 1 1 1 1 1 0 1 1 1 1 1 1 1
+               1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1
+               0 1 0 1 1 1 1 1 0 1 1 1 1 1 1 1
+               0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 1
+               0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 1 0 1 0 0 0 0 1 1 1 1
+               0 0 0 0 0 1 1 1 1 0 1 0 0 0 1 0
+               0 0 0 0 1 0 0 1 0 0 0 0 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 1 1 1 1 0 1 0 1 1 1 1 1
+               0 0 0 1 1 0 0 0 1 1 0 1 0 1 1 1
+               1 0 0 1 0 1 0 0 0 1 1 1 0 0 0 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1
+               0 0 0 1 1 1 1 1 1 0 1 1 0 1 1 1
+               0 0 0 0 1 1 0 0 0 0 0 0 0 1 1 1
+               0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
+               0 0 0 0 1 1 1 1 0 0 0 1 1 1 1 1
+               1 0 0 0 0 1 0 0 1 0 0 0 1 1 1 1
+               0 0 0 0 0 1 0 1 0 0 0 1 0 1 0 1
+               0 0 0 0 0 1 0 1 0 0 0 0 1 1 1 1
+               0 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1
+               1 0 0 0 0 1 1 1 1 1 0 1 1 1 1 1
+               0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1
+               0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
+               0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 0
+               0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1
+               0 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1
+               1 0 0 1 1 1 1 1 1 0 0 0 1 1 1 1
+               0 1 0 0 1 0 1 0 0 1 0 0 0 0 0 0
+               0 1 0 1 1 1 1 1 0 1 0 1 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
+               1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1
+               1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 1
+               1 1 0 1 0 1 1 1 0 1 0 1 1 1 1 1
+               0 1 0 0 1 1 1 1 0 1 1 1 1 1 1 1
+               0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               1 1 1 1 1 1 1 1 0 1 1 1 0 1 1 1
+               1 1 0 1 1 1 1 1 0 1 1 1 1 1 1 1
+               0 1 0 0 1 1 1 1 1 1 1 0 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 1 1 1 1 0 1 0 0 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               1 0 0 1 1 1 0 1 1 1 1 1 1 1 1 1
+               0 0 0 0 1 1 1 1 1 1 1 0 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1
+               0 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1
+               1 1 0 0 1 1 0 1 0 0 0 0 1 1 1 1
+               0 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1
+               0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0
+               0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 1
+               0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0
+               0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0
+               0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
+               0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 1 0 1 0 0 0 0 1 1 1 1
+               0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
+               0 0 0 0 1 1 0 0 0 0 0 0 1 1 1 1
+               0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
+               1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0
+               0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 1
+               0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 1
+               1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
+               0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
+               0 1 0 0 0 1 1 0 0 0 0 0 1 1 0 0
+               0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
+               1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 1 1 1 1 0 0 0 1 0 1 0 1
+               1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1
+               0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
+               0 1 1 1 1 1 1 1 0 1 0 1 1 1 1 1
+               1 1 0 1 1 0 1 1 1 1 1 1 1 1 1 1
+               0 1 0 0 1 1 1 1 0 0 1 1 1 1 1 0
+               0 0 0 0 0 1 0 1 0 0 0 0 1 1 1 1
+               0 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1
+               1 0 0 1 0 1 0 1 0 1 0 0 1 1 1 1
+               0 0 0 0 1 1 0 1 0 0 0 0 1 1 1 1
+               0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 1
+               0 1 0 0 1 1 1 1 0 1 0 1 1 1 1 1
+               1 0 0 1 1 1 1 1 1 1 0 1 1 1 1 1
+               0 0 1 0 0 1 0 1 0 0 0 0 1 1 1 0
+               0 0 0 0 1 1 0 1 0 0 0 0 1 1 0 1
+               0 1 0 0 1 1 1 1 0 1 1 1 1 1 1 1
+               1 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
+               0 0 0 0 1 1 1 1 1 1 1 1 1 0 1 0
+               0 0 0 0 0 1 0 0 0 1 0 0 1 1 1 1
+               0 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1
+               1 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1
+               0 1 0 0 0 1 1 1 1 1 1 0 1 1 0 1
+               0 0 0 0 0 1 0 1 0 0 0 0 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 1 0 0 1 1 1 1 0 1 1 0 1 1 1 1
+               1 1 0 1 1 0 0 0 0 1 0 1 1 1 1 1
+               0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1
+               1 1 0 1 1 1 1 1 0 1 0 1 1 1 1 1
+               0 0 0 0 0 1 1 1 0 0 0 0 1 1 1 1
+               1 0 0 1 0 1 0 0 0 0 0 0 1 1 0 1
+               0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1
+               0 1 0 0 0 1 1 0 0 1 0 1 0 1 1 1
+               0 0 0 0 0 0 0 1 0 0 0 0 1 1 0 1
+               0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0
+               0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 1
+               0 1 0 0 0 1 1 1 0 1 1 0 1 1 0 0
+               0 0 0 0 1 1 0 1 0 0 0 0 1 1 1 1
+               0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 1 0 1 1 0 1 0 0 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
+               0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0
+               1 0 0 1 0 1 0 1 0 0 0 0 0 0 0 1
+               0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1
+               0 0 0 0 1 1 0 0 0 0 0 0 1 1 1 1
+               0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 1 1 1 1 0 1 0 0 0 0 0 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 1 0 0 0 0 1 0 0 1 0 0
+               0 0 0 0 1 1 0 1 0 0 0 0 1 1 1 1
+               0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1
+               1 1 0 0 1 1 1 1 1 1 0 1 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 1 1 0 0 0 1 0 0 1 1 0
+               1 1 0 0 1 1 1 1 0 0 0 0 0 1 0 1
+               1 1 0 0 1 1 1 1 0 1 1 1 1 1 1 1
+               1 1 0 1 1 1 1 1 1 1 0 1 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 1 0 1 1 1 0 1 0 1 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 1 0 0 0 1 1 0 0 0 0 0 1 0 0 1
+               0 1 0 0 1 1 1 1 0 1 0 1 1 1 1 1
+               0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1
+               1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 1 0 1 0 1 0 0 0 1 0 0 0
+               1 0 1 0 0 1 1 1 0 1 1 1 1 1 1 1
+               0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 1 1 1 1 0 0 0 0 0 1 0 0
+               1 1 0 1 1 1 1 1 0 1 1 1 1 1 1 1
+               0 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1
+               1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 1 1 1 0 1 1 1 0 0 1 1 0
+               1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 1 1 1 1 1 1 1 0 1 1 0 0
+               1 0 0 0 1 1 1 1 0 1 0 0 1 1 1 1
+               0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 1 1 1 1 1 1 0 0 1 1 1 1
+               1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 1 1 0 1 1 1 1 0 1 1 1 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0
+               1 0 0 1 1 1 0 1 0 0 0 0 1 1 1 1
+               0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
+              ;; g_10
+              (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0
+               1 1 1 1 0 0 1 1 0 1 0 1 1 1 1 1
+               1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0
+               0 0 0 1 0 1 1 1 1 0 0 1 1 1 1 1
+               0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 1
+               0 0 0 0 0 1 0 1 1 1 1 1 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
+               0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1
+               0 0 1 1 0 0 1 1 1 1 0 1 0 1 1 1
+               0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 1
+               0 1 0 1 1 1 1 1 0 0 1 1 1 1 1 1
+               0 0 0 1 0 1 1 1 0 0 1 1 0 0 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
+               0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0
+               0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0
+               0 0 0 1 0 0 0 1 0 1 0 1 0 1 1 1
+               0 0 0 0 0 1 0 1 0 0 1 0 0 1 0 1
+               0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 1
+               0 0 1 1 0 1 0 1 1 0 1 1 1 1 1 1
+               1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 0 1 1 1 0 1 1 0 1 1 1 1
+               0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0
+               0 0 0 1 0 1 1 1 0 0 0 0 0 1 1 0
+               1 1 1 1 1 0 1 0 1 1 1 0 1 0 0 0
+               0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1
+               0 0 0 1 1 1 1 1 1 0 0 1 1 1 1 1
+               0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
+              ;; g_20
+              (0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1
+               0 1 0 0 0 0 1 1 0 0 1 0 1 1 1 0
+               1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1)
+              ;; g_40
+              (0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1
+               0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1
+               0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1
+               0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
+               0 0 0 0 0 0 0 0 0 1 0 0 1 1 1 0
+               1 1 1 0 0 1 0 0 0 0 0 0 1 1 0 1
+               0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
+               0 1 0 0 0 1 0 0 0 1 0 0 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0
+               0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
+               1 0 1 0 1 1 1 0 1 0 1 0 1 1 1 1
+               0 1 0 0 0 1 0 1 0 1 1 1 1 1 1 1
+               1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1
+               0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
+               0 0 0 1 1 1 0 0 1 1 0 1 1 1 0 1
+               0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1
+               0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
+               0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 1
+               0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
+               0 1 0 0 1 1 1 1 0 1 0 1 1 1 1 1
+               0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 1 1 1 0 0 1 1 1 1 1 1 1 1
+               1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+               1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1
+               0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
+               0 0 0 0 0 0 1 0 0 0 0 1 1 1 1 1
+               0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1
+               0 0 0 0 0 1 0 1 0 1 1 1 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1
+               0 1 0 0 0 0 0 1 0 1 0 1 0 1 1 1
+               0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 0 1 0 1 0 1 1 1 0 1 1 1
+               0 0 0 0 1 1 0 1 0 1 0 1 1 1 1 1
+               0 1 0 0 1 1 0 1 1 1 1 1 1 1 1 1
+               0 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1
+               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+               0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 1
+               0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1
+               0 0 0 0 0 1 0 1 0 1 1 1 1 1 0 1
+               0 0 0 1 0 0 0 0 0 0 0 1 0 1 0 1
+               0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 1
+               0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 0
+               0 0 0 0 1 1 0 1 1 1 1 1 1 1 0 1
+               0 0 0 0 0 1 0 0 0 0 0 0 1 1 1 1
+               0 0 0 0 0 1 1 1 0 0 0 1 1 1 1 1
+               0 0 0 0 0 1 1 1 0 1 1 1 1 1 1 1
+               0 0 0 0 1 1 1 1 1 0 1 1 1 1 1 1
+               0 0 0 0 1 1 0 1 0 1 1 1 1 1 1 1
+               0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1
+               0 1 0 0 1 1 0 1 0 1 1 1 1 1 0 1
+               0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1))
+             (;; g_01
+              (0 0 1 1 0 1 1 1 0 1 1 1 0 0 1 1
+               0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1
+               0 1 0 1 0 1 1 1 0 1 1 1 1 1 1 1
+               1 1 1 1 0 1 0 1 1 1 1 1 1 0 1 1
+               0 1 1 1 0 0 0 0 0 0 1 1 0 0 1 1
+               1 1 1 1 0 0 0 0 1 1 1 1 1 0 0 1
+               0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
+              ;; g_11
+              (0 0 0 0 0 0 0 1 0 0 0 1 0 0 1 1
+               0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 1)
+              ;; g_21
+              (0 0 0 1 0 1 1 1)
+              ;; g_41
+              (0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1
+               0 0 0 0 0 0 0 1 0 0 0 1 1 1 1 1
+               0 0 0 0 0 0 1 1 0 0 0 1 1 1 1 1
+               0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1))
+             (;; g_02
+              (0 1 0 1)
+              ;; g_12
+              (0 1)
+              ;; g_22
+              (0)
+              ;; g_42
+              (0 0 0 1))))
+    "Static prediction table for X-Face image compression algorithm.")
+
+  ;; Macros for inlining critical values. 
+  (defmacro uncompface-width () (list 'quote uncompface-width))
+  (defmacro uncompface-height () (list 'quote uncompface-height))
+  (defmacro uncompface-guesses () (list 'quote uncompface-guesses))
+
+  (defmacro uncompface-loop (&rest body)
+    "Eval BODY and repeat if last expression of BODY yields non-nil."
+    (list 'while (cons 'progn body))))
+
+;; (defun uncompface-print-bignum (bignum &optional prefix)
+;;   (princ (format (concat prefix "<%s>\n")
+;;              (mapconcat (lambda (x) (format "%02x" x))
+;;                         (reverse bignum) " "))))
+
+;; Shut up the byte-compiler.
+;; These variables are once bound in `uncompface' and all subfunctions
+;; accesses them directly rather than creating their own bindings.
+(eval-when-compile
+  (defvar bignum)
+  (defvar face))
+
+;; Big-number facilities.
+;; These functions were used to be implemented with `lsh' and `logand',
+;; but rewritten to use `/' and `%'.  The last two are mapped into
+;; byte-code directly, but the formers are normal functions even in
+;; compiled code which involve expensive `funcall' operations.
+(eval-when-compile
+  (defsubst uncompface-big-mul-add (multiplier adder)
+    "Multiply BIGNUM by MULTIPLIER and add ADDER and put result in `bignum'."
+    (setq bignum (if (= multiplier 0)
+                    (cons 0 bignum)
+                  (prog1 bignum
+                    (while (progn
+                             (setcar bignum (% (setq adder (+ (* (car bignum)
+                                                                 multiplier)
+                                                              adder))
+                                               256))
+                             (setq adder (/ adder 256))
+                             (cdr bignum))
+                      (setq bignum (cdr bignum)))
+                    (or (= adder 0)
+                        (setcdr bignum (list adder))))))))
+
+;; This trick is for XEmacs 21.4 which doesn't allow inlining a function
+;; using `defsubst' into another function also defined with `defsubst'.
+(eval-when-compile
+  (when (featurep 'xemacs)
+    (defvar uncompface-big-mul-add (symbol-function 'uncompface-big-mul-add))
+    (defmacro uncompface-big-mul-add (multiplier adder)
+      `(,uncompface-big-mul-add ,multiplier ,adder))))
+
+;; Separate `eval-when-compile' for the byte compiler
+;; to properly define `uncompface-big-mul-add' before `uncompface-big-pop'.
+(eval-when-compile
+  (defsubst uncompface-big-pop (prob)
+    (let ((n (car bignum)) (i 0))
+      (if (cdr bignum)
+         (setq bignum (cdr bignum))
+       (setcar bignum 0))
+      (while (or (< n (cdr (car prob)))
+                (>= n (+ (cdr (car prob)) (car (car prob)))))
+       (setq prob (cdr prob)
+             i (1+ i)))
+      (uncompface-big-mul-add (car (car prob)) (- n (cdr (car prob))))
+      i)))
+
+;; This function cannot be inlined due to recursive calls.
+(defun uncompface-pop-grays (offset size)
+  (if (<= size 3)
+      (let ((bits (uncompface-big-pop
+                  ;; This is freqs[16] in compface_private.h.
+                  '(( 0 .   0) (38 .   0) (38 .  38) (13 . 152)
+                    (38 .  76) (13 . 165) (13 . 178) ( 6 . 230)
+                    (38 . 114) (13 . 191) (13 . 204) ( 6 . 236)
+                    (13 . 217) ( 6 . 242) ( 5 . 248) ( 3 . 253)))))
+;;     (if (/= (logand bits 1) 0)
+;;         (aset face offset t))
+;;     (if (/= (logand bits 2) 0)
+;;         (aset face (1+ offset) t))
+;;     (if (/= (logand bits 4) 0)
+;;         (aset face (+ offset (uncompface-width)) t))
+;;     (if (/= (logand bits 8) 0)
+;;         (aset face (+ offset (uncompface-width) 1) t))
+       (when (>= bits 8)
+         (aset face (+ offset (uncompface-width) 1) t)
+         (setq bits (- bits 8)))
+       (when (>= bits 4)
+         (aset face (+ offset (uncompface-width)) t)
+         (setq bits (- bits 4)))
+       (or (eq (if (< bits 2)
+                   bits
+                 (aset face (1+ offset) t)
+                 (- bits 2))
+               0)
+           (aset face offset t))
+       )
+    (setq size (/ size 2))
+    (uncompface-pop-grays offset size)
+    (uncompface-pop-grays (+ offset size) size)
+    (uncompface-pop-grays (+ offset (* (uncompface-width) size)) size)
+    (uncompface-pop-grays (+ offset (* (uncompface-width) size) size) size)))
+
+;; Again, this function call itself recursively.
+(defun uncompface-uncompress (offset size level)
+  ;; This used to be (funcall (aref [(lambda ...) ...] (u-big-pop ...)))
+  ;; but this was slow due to function call.
+  (let ((i (uncompface-big-pop (car level))))
+    (cond ((eq i 0)                    ; black
+          (uncompface-pop-grays offset size))
+         ((eq i 1)                     ; gray
+          (setq size (/ size 2)
+                level (cdr level))
+          (uncompface-uncompress offset size level)
+          (uncompface-uncompress (+ offset size) size level)
+          (uncompface-uncompress (+ offset (* size (uncompface-width)))
+                                 size level)
+          (uncompface-uncompress (+ offset (* size (uncompface-width)) size)
+                                 size level))
+         ;; ((eq i 2) nil)
+         ;; (t (error "Cannot happen"))
+         )))
+
+(eval-when-compile
+  (defmacro uncompface-shift-in (k dy dx)
+    `(+ k k (if (aref face (+ i (* ,dy (uncompface-width)) ,dx)) 1 0))))
+
+(defun uncompface-internal (string &optional raw)
+  "Decode X-Face data STRING and return an image in the pbm format.
+If the optional RAW is non-nil, return a raw bitmap as a vector."
+  (let (;; `bignum' and `face' are semi-global variables.
+       ;; Do not use '(0) below, because BIGNUM is modified in-place.
+       (bignum (list 0))
+       (face (make-vector (* (uncompface-width) (uncompface-height)) nil))
+       ;;(uncompface-big-shift -16)
+       ;;(uncompface-big-mask 65535)
+       (y 0) x)
+    (mapc (lambda (c)
+           (and (>= c ?!) (<= c ?~)
+                (uncompface-big-mul-add (1+ (- ?~ ?!)) (- c ?!))))
+         string)
+    ;;(uncompface-print-bignum bignum)
+    ;;(setq y 0)
+    (uncompface-loop
+      (setq x 0)
+      (uncompface-loop
+       (uncompface-uncompress (+ (* (uncompface-width) y) x) 16
+                              ;; This is levels[4][3] in compface_private.h.
+                              '(;; Top of tree almost always grey
+                                ((  1 . 255) (251 .   0) (  4 . 251))
+                                ((  1 . 255) (200 .   0) ( 55 . 200))
+                                (( 33 . 223) (159 .   0) ( 64 . 159))
+                                ;; Grey disallowed at bottom
+                                ((131 .   0) (  0 .   0) (125 . 131))))
+       (< (setq x (+ x 16)) (uncompface-width)))
+      (< (setq y (+ y 16)) (uncompface-height)))
+    (setq y 0)
+    (let ((i 0) guesses k)
+      (uncompface-loop
+       (setq guesses (cond ((= y 1) (nth 2 (uncompface-guesses)))
+                           ((= y 2) (nth 1 (uncompface-guesses)))
+                           (t       (nth 0 (uncompface-guesses))))
+             x 0)
+       (uncompface-loop
+         (setq k 0)
+         (when (>= x 1)
+           (when (>= x 2)
+             (when (>= x 3)
+               (when (>= y 1)
+                 (when (>= y 2)
+                   (when (>= y 3)
+                     (setq k (uncompface-shift-in k -2 -2)))
+                   (setq k (uncompface-shift-in k -1 -2)))
+                 (setq k (uncompface-shift-in k 0 -2))))
+             (when (>= y 1)
+               (when (>= y 2)
+                 (when (>= y 3)
+                   (setq k (uncompface-shift-in k -2 -1)))
+                 (setq k (uncompface-shift-in k -1 -1)))
+               (setq k (uncompface-shift-in k 0 -1))))
+           (when (>= y 2)
+             (when (>= y 3)
+               (setq k (uncompface-shift-in k -2 0)))
+             (setq k (uncompface-shift-in k -1 0)))
+           (when (>= y 2)
+             (when (>= y 3)
+               (setq k (uncompface-shift-in k -2 1)))
+             (setq k (uncompface-shift-in k -1 1)))
+           (when (<= x (- (uncompface-width) 2))
+             (when (>= y 2)
+               (when (>= y 3)
+                 (setq k (uncompface-shift-in k -2 2)))
+               (setq k (uncompface-shift-in k -1 2)))))
+         (if (aref (car (cond ((= x 1)
+                               (cdr (cdr guesses)))
+                              ((= x 2)
+                               (cdr guesses))
+                              ((= x (1- (uncompface-width)))
+                               (cdr (cdr (cdr guesses))))
+                              (t
+                               guesses))) k)
+             (aset face i (not (aref face i))))
+         (setq i (1+ i))
+         (< (setq x (1+ x)) (uncompface-width)))
+       (< (setq y (1+ y)) (uncompface-height))))
+    (if raw
+       face
+      (concat (eval-when-compile
+               (format "P1\n%d %d\n" uncompface-width uncompface-height))
+             (mapconcat (lambda (bit) (if bit "1" "0")) face " ")
+             "\n"))))
+
+(provide 'compface)
+
+;; Local variables:
+;; eval: (put 'uncompface-loop 'lisp-indent-hook 0)
+;; End:
+
+;;; compface.el ends here
diff --git a/xemacs-packages/gnus/contrib/gnus-kill-to-score.el b/xemacs-packages/gnus/contrib/gnus-kill-to-score.el
new file mode 100644 (file)
index 0000000..a5ce90c
--- /dev/null
@@ -0,0 +1,204 @@
+;;; gnus-kill-to-score.el --- translate simple kill files to score files
+;; Copyright (C) 1995 Free Software Foundation, Inc.
+
+;; Author: Ethan Bradford <ethanb@phys.washington.edu>
+;; Keywords: news
+
+;; This file is not 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Commentary:
+
+;;; If you don't like the changes which were made, edit out the new code from
+;;; the SCORE file and revert the kill file from the backup (.KILL~).
+
+;;; Caveats:
+;;;  -> Sometimes commands in a kill file work together.  For example, killing
+;;;     the negative of a pattern used to be done by killing all, then
+;;;     unkilling.  If the unkill fails to translate (which is likely), the
+;;;     configuration will be invalid, with the kill translated to a
+;;;     score entry and the unkill left as a kill.
+;;;  -> The score entries are always applied to all entries in a file, unlike
+;;;     gnus-kill, which only applies to marked entries if the fourth argument
+;;;     is t.
+;;;  -> If the kill file did anything funny with marks, it will be translated
+;;;     wrong.
+;;;  -> Doesn't delete comments, so won't delete file w/ only comments.
+
+;;; Code:
+
+(require 'gnus)
+(require 'gnus-score)
+(load-library "gnus-kill")
+
+(defvar gnus-convert-loads nil
+  "If t, kill-file loads are converted to score-file loads.
+If nil, we ask whether to convert.  Otherwise we don't load or ask.")
+
+(defun gnus-convert-kill-name-to-score-name (kill-file)
+  (concat
+   (if (string-equal (file-name-nondirectory kill-file) "KILL")
+       (concat (file-name-directory kill-file) "all")
+     (substring kill-file 0 (string-match ".KILL$" kill-file)))
+   ".SCORE"))
+
+(defun gnus-convert-one-kill-file (kill-file)
+  "Convert (as far as possible) the elements of KILL-FILE into a score file.
+See also the variable gnus-convert-loads."
+  (interactive "f")
+  (let* ((mark-below (or gnus-summary-mark-below gnus-summary-default-score 0))
+        (expunge-below gnus-summary-expunge-below)
+        (score-file-name (gnus-convert-kill-name-to-score-name kill-file))
+        beg form command recognized)
+    (message "Converting kill file %s..." kill-file)
+    (gnus-score-load score-file-name)
+    (find-file kill-file)
+    (goto-char (point-min))
+    (gnus-kill-file-mode)
+    (while (progn
+            (setq beg (point))
+            (setq recognized nil)
+            (setq form (condition-case nil
+                           (read (current-buffer))
+                         (error nil))))
+      (setq command (car form))
+
+      (if (eq command 'load)
+         (let ((loaded-kill-file-name
+                (condition-case nil
+                    (expand-file-name
+                     (gnus-convert-kill-name-to-score-name
+                      (eval (nth 1 form))))
+                  (error nil))))
+           (if (stringp loaded-kill-file-name)
+               (progn
+                 (if (string-match
+                      (expand-file-name
+                       (or (file-name-directory gnus-kill-files-directory)
+                          "~/News/"))
+                      loaded-kill-file-name)
+                     (setq loaded-kill-file-name
+                           (substring loaded-kill-file-name (match-end 0))))
+                 (if (or (eq gnus-convert-loads t)
+                         (and (not gnus-convert-loads)
+                              (message
+                               "Convert kill-file load to score-file load for %s (y, n, a=always, v=never)? " loaded-kill-file-name)
+                              (let ((c (upcase (read-char-exclusive))))
+                                (if (= c ?A)
+                                    (setq gnus-convert-loads t)
+                                  (if (= c ?V)
+                                      (setq gnus-convert-loads 'never)))
+                                (or (= c ?A) (= c ?Y) (= c ?\ )))))
+                     (progn
+                       (gnus-score-set 'files (list loaded-kill-file-name))
+                       (setq recognized t))))))
+
+       ;; The only other thing we understand is some form of gnus-kill
+       ;; Check all the fields because they influence whether we recognize.
+       (let
+           ((header (condition-case nil (eval (nth 1 form)) (error nil)))
+            (match (condition-case nil (eval (nth 2 form)) (error nil)))
+            (cmd (nth 3 form))
+            (all (condition-case nil (eval (nth 4 form)) (error nil)))
+            (date nil)
+            (score nil))               ;score also indicates if a cmd was
+                                     ;recognized.
+         (if (and (listp cmd) (or (eq (car cmd) 'quote)
+                                  (eq (car cmd) 'function)))
+             (setq cmd (nth 1 cmd)))
+         (if (and (listp cmd) (eq (car cmd) 'lambda))
+             (setq cmd (nth 2 cmd)))
+         (if (and (listp cmd) (eq (length cmd) 1))
+             (setq cmd (car cmd)))
+         (cond
+          ((eq command 'gnus-kill)
+           (cond
+            ((not cmd) ;; Simple kill
+             (setq score (- gnus-score-interactive-default-score)))
+
+            ((and (eq cmd 'gnus-summary-unkill) all) ;; An unkill
+             (setq score gnus-score-interactive-default-score))
+
+            ((not (listp cmd))) ; Only cmds w/ args from here on.
+
+            ((and (eq (car cmd) 'gnus-summary-mark-as-read) ;mod of standard
+                  (not (nth 1 cmd)))
+             (if (eqs (nth 2 cmd) " ")
+                 (if all 
+                     (setq score gnus-score-interactive-default-score))
+               (setq score (- gnus-score-interactive-default-score))))
+
+            ((apply (lambda (c)        ; Matching the unkill in the FAQ
+                     (and (listp c)
+                          (eq (car c) 'gnus-summary-clear-mark-forward)
+                          (= (nth 1 c) 1)))
+                    (list (if (eq (car cmd) 'if) (nth 2 cmd) cmd)))
+             (setq score gnus-score-interactive-default-score))
+
+            ((and ;; Old (ding) gnus kill form.
+              (= (length cmd) 2)
+              (eq (car cmd) 'gnus-summary-raise-score))
+             (setq score (nth 1 cmd)))
+            ))
+          ((eq command 'gnus-raise)
+           (setq score (nth 2 form)))
+          ((eq command 'gnus-lower)
+           (setq score (- (nth 2 form))))
+          ((eq command 'expire-kill)
+           (if (= (length form) 3)
+               (progn
+                 (setq date (nth 2 form))
+                 (setq score (- gnus-score-interactive-default-score))))))
+         (if (and score (stringp header) (stringp match))
+             (progn
+               (gnus-summary-score-entry
+                header match 'r score date nil t)
+               (setq recognized t)))))
+      (if recognized
+         (delete-region beg (point))
+       (message "Cannot convert this form:") (sit-for 0 500)
+       (print form) (sit-for 0 500)))
+
+    ;; Eliminate white space and delete the file if it is empty, else save.
+    (goto-char (point-min))
+    (delete-region (point)
+                  (progn
+                    (if (re-search-forward "[^ \t\n]" nil 'end)
+                        (backward-char 1))
+                    (point)))
+    (and (buffer-modified-p) (save-buffer))
+    (if (= (point-min) (point-max))
+       (progn
+         (message "Deleting %s; it is now empty." kill-file)
+         (delete-file kill-file))
+      (message "%s was not completed converted." kill-file))
+
+    (gnus-score-save)
+    (kill-buffer (current-buffer))))
+
+(defun gnus-convert-kill-file-directory (kill-directory)
+  "Convert kill files in KILL-DIRECTORY into score files.
+Uses gnus-convert-one-kill-file.
+See also the variable gnus-convert-loads."
+  (interactive "DDirectory to convert (empty string = current kill directory): ")
+  (if (string= kill-directory "")
+      (setq kill-directory (or gnus-kill-files-directory "~/News")))
+  (let ((all-kill-files (directory-files kill-directory)))
+    (while all-kill-files
+      (if (string-match "\\(.\\|^\\)KILL$" (car all-kill-files))
+         (gnus-convert-one-kill-file
+          (expand-file-name (car all-kill-files) kill-directory)))
+      (setq all-kill-files (cdr all-kill-files)))))
diff --git a/xemacs-packages/gnus/contrib/gnus-namazu.el b/xemacs-packages/gnus/contrib/gnus-namazu.el
new file mode 100644 (file)
index 0000000..91db91d
--- /dev/null
@@ -0,0 +1,912 @@
+;;; gnus-namazu.el --- Search mail with Namazu -*- coding: iso-2022-7bit; -*-
+
+;; Copyright (C) 2000, 2001, 2002, 2003, 2004
+;; TSUCHIYA Masatoshi <tsuchiya@namazu.org>
+
+;; Author: TSUCHIYA Masatoshi <tsuchiya@namazu.org>
+;; Keywords: mail searching namazu
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+
+;; This file defines the command to search mails and persistent
+;; articles with Namazu and to browse its results with Gnus.
+;;
+;; Namazu is a full-text search engine intended for easy use.  For
+;; more detail about Namazu, visit the following page:
+;;
+;;     http://namazu.org/
+
+
+;;; Quick Start:
+
+;; If this module has already been installed, only four steps are
+;; required to search articles with this module.
+;;
+;;   (1) Install Namazu.
+;;
+;;   (2) Put this expression into your ~/.gnus.
+;;
+;;          (gnus-namazu-insinuate)
+;;
+;;   (3) Start Gnus and type M-x gnus-namazu-create-index RET to make
+;;       index of articles.
+;;
+;;   (4) In group buffer or in summary buffer, type C-c C-n query RET.
+
+
+;;; Install:
+
+;; Before installing this module, you must install Namazu.
+;;
+;; When you would like to byte-compile this module in Gnus, put this
+;; file into the lisp/ directory in the Gnus source tree and run `make
+;; install'.  And then, put the following expression into your
+;; ~/.gnus.
+;;
+;;      (gnus-namazu-insinuate)
+;;
+;; In order to make index of articles with Namazu before using this
+;; module, type M-x gnus-namazu-create-index RET.  Otherwise, you can
+;; create index by yourself with the following commands:
+;;
+;;      % mkdir ~/News/namazu
+;;      % mknmz -a -h -O ~/News/namazu ~/Mail ~/News/cache
+;;
+;; The first command makes the directory for index files, and the
+;; second command generates index files of mails and persistent
+;; articles.
+;;
+;; In order to update indices for incoming articles, this module
+;; automatically runs mknmz, the indexer of Namazu, at an interval of
+;; 3 days; this period is set to `gnus-namazu-index-update-interval'.
+;;
+;; Indices will be updated when `gnus-namazu-search' is called.  If
+;; you want to update indices everywhen Gnus is started, you can put
+;; the following expression to your ~/.gnus.
+;;
+;;      (add-hook 'gnus-startup-hook 'gnus-namazu-update-all-indices)
+;;
+;; In order to control mknmz closely, disable the automatic updating
+;; feature and run mknmz by yourself.  In this case, set nil to the
+;; above option.
+;;
+;;      (setq gnus-namazu-index-update-interval nil)
+;;
+;; When your index is put into the directory other than the default
+;; one (~/News/namazu), it is necessary to set its place to
+;; `gnus-namazu-index-directories' as follows:
+;;
+;;      (setq gnus-namazu-index-directories
+;;            (list (expand-file-name "~/namazu")))
+
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(require 'nnoo)
+(require 'nnheader)
+(require 'nnmail)
+(require 'gnus-sum)
+(require 'gmm-utils)
+
+;; To suppress byte-compile warning.
+(eval-when-compile
+  (defvar nnml-directory)
+  (defvar nnmh-directory))
+
+
+(defgroup gnus-namazu nil
+  "Search nnmh and nnml groups in Gnus with Namazu."
+  :group 'namazu
+  :group 'gnus
+  :prefix "gnus-namazu-")
+
+(defconst gnus-namazu-default-index-directory
+  (expand-file-name "namazu" gnus-directory)
+  "Default place of Namazu index files.")
+
+(defcustom gnus-namazu-index-directories
+  (list
+   (or (and (boundp 'gnus-namazu-index-directory)
+           (symbol-value 'gnus-namazu-index-directory))
+       (and (boundp 'nnir-namazu-index-directory)
+           (symbol-value 'nnir-namazu-index-directory))
+       gnus-namazu-default-index-directory))
+  "*Places of Namazu index files."
+  :type '(repeat directory)
+  :group 'gnus-namazu)
+
+(defcustom gnus-namazu-command
+  (or (and (boundp 'namazu-command)
+          (symbol-value 'namazu-command))
+      (and (boundp 'nnir-namazu-program)
+          (symbol-value 'nnir-namazu-program))
+      "namazu")
+  "*Name of the executable file of Namazu."
+  :type 'string
+  :group 'gnus-namazu)
+
+(defcustom gnus-namazu-command-prefix nil
+  "*Prefix commands to execute Namazu.
+If you put your index on a remote server, set this option as follows:
+
+    (setq gnus-namazu-command-prefix
+          '(\"ssh\" \"-x\" \"remote-server\"))
+
+This makes gnus-namazu execute \"ssh -x remote-server namazu ...\"
+instead of executing \"namazu\" directly."
+  :type '(repeat string)
+  :group 'gnus-namazu)
+
+(defcustom gnus-namazu-additional-arguments nil
+  "*Additional arguments of Namazu.
+The options `-q', `-a', and `-l' are always used, very few other
+options make any sense in this context."
+  :type '(repeat string)
+  :group 'gnus-namazu)
+
+(defcustom gnus-namazu-index-update-interval
+  259200                               ; 3 days == 259200 seconds.
+  "*Number of seconds between running the indexer of Namazu."
+  :type '(choice (const :tag "Never run the indexer" nil)
+                (integer :tag "Number of seconds"))
+  :group 'gnus-namazu)
+
+(defcustom gnus-namazu-make-index-command "mknmz"
+  "*Name of the executable file of the indexer of Namazu."
+  :type 'string
+  :group 'gnus-namazu)
+
+(defcustom gnus-namazu-make-index-arguments
+  (nconc
+   (list "--all" "--mailnews" "--deny=^.*[^0-9].*$")
+   (when (and (boundp 'current-language-environment)
+             (string= "Japanese"
+                      (symbol-value 'current-language-environment)))
+     (list "--indexing-lang=ja")))
+  "*Arguments of the indexer of Namazu."
+  :type '(repeat string)
+  :group 'gnus-namazu)
+
+(defcustom gnus-namazu-field-keywords
+  '("date" "from" "newsgroups" "size" "subject" "summary" "to" "uri")
+  "*List of keywords to do field-search."
+  :type '(repeat string)
+  :group 'gnus-namazu)
+
+(defcustom gnus-namazu-coding-system
+  (if (memq system-type '(windows-nt OS/2 emx))
+      'shift_jis
+    'euc-japan)
+  "*Coding system for Namazu process."
+  :type 'coding-system
+  :group 'gnus-namazu)
+
+(defcustom gnus-namazu-need-path-normalization
+  (and (memq system-type '(windows-nt OS/2 emx)) t)
+  "*Non-nil means that outputs of namazu may contain drive letters."
+  :type 'boolean
+  :group 'gnus-namazu)
+
+(defcustom gnus-namazu-case-sensitive-filesystem
+  (not (eq system-type 'windows-nt))
+  "*Non-nil means that the using file system distinguishes cases of characters."
+  :type 'boolean
+  :group 'gnus-namazu)
+
+(defcustom gnus-namazu-query-highlight t
+  "Non-nil means that queried words is highlighted."
+  :type 'boolean
+  :group 'gnus-namazu)
+
+(defface gnus-namazu-query-highlight-face
+  '((((type tty pc) (class color))
+     (:background "magenta4" :foreground "cyan1"))
+    (((class color) (background light))
+     (:background "magenta4" :foreground "lightskyblue1"))
+    (((class color) (background dark))
+     (:background "palevioletred2" :foreground "brown4"))
+    (t (:inverse-video t)))
+  "Face used for namazu query matching words."
+  :group 'gnus-namazu)
+
+(defcustom gnus-namazu-remote-groups nil
+  "*Alist of regular expressions matching remote groups and their base paths.
+If you use an IMAP server and have a special index, set this option as
+follows:
+
+    (setq gnus-namazu-remote-groups
+          '((\"^nnimap\\\\+server:INBOX\\\\.\" . \"~/Maildir/.\")))
+
+This means that the group \"nnimap+server:INBOX.group\" is placed in
+\"~/Maildir/.group\"."
+  :group 'gnus-namazu
+  :type '(repeat
+         (cons (choice (regexp :tag "Regexp of group name")
+                       (const :tag "Groups served by `gnus-select-method'" t))
+               (string :tag "Base path of groups")))
+  :set (lambda (symbol value)
+        (prog1 (set-default symbol value)
+          (when (featurep 'gnus-namazu)
+            (gnus-namazu/make-directory-table t)))))
+
+;;; Internal Variable:
+(defconst gnus-namazu/group-name-regexp "\\`nnvirtual:namazu-search\\?")
+
+;; Multibyte group name:
+(and
+ (fboundp 'gnus-group-decoded-name)
+ (let ((gnus-group-name-charset-group-alist
+       (list (cons gnus-namazu/group-name-regexp gnus-namazu-coding-system)))
+       (query (decode-coding-string (string 27 36 66 52 65 59 122 27 40 66)
+                                   'iso-2022-7bit)))
+   (not (string-match query
+                     (gnus-summary-buffer-name
+                      (encode-coding-string
+                       (concat "nnvirtual:namazu-search?query=" query)
+                       gnus-namazu-coding-system)))))
+ (let (current-load-list)
+   (defadvice gnus-summary-buffer-name
+     (before gnus-namazu-summary-buffer-name activate compile)
+     "Advised by `gnus-namazu' to handle encoded group names."
+     (ad-set-arg 0 (gnus-group-decoded-name (ad-get-arg 0))))))
+
+(defmacro gnus-namazu/make-article (group number)
+  `(cons ,group ,number))
+(defmacro gnus-namazu/article-group  (x) `(car ,x))
+(defmacro gnus-namazu/article-number (x) `(cdr ,x))
+
+(defsubst gnus-namazu/indexed-servers ()
+  "Choice appropriate servers from opened ones, and return thier list."
+  (append
+   (gnus-servers-using-backend 'nnml)
+   (gnus-servers-using-backend 'nnmh)))
+
+(defsubst gnus-namazu/default-index-directory ()
+  (if (member gnus-namazu-default-index-directory
+             gnus-namazu-index-directories)
+      gnus-namazu-default-index-directory
+    (car gnus-namazu-index-directories)))
+
+(defun gnus-namazu/setup ()
+  (and (boundp 'gnus-group-name-charset-group-alist)
+       (not (member (cons gnus-namazu/group-name-regexp
+                         gnus-namazu-coding-system)
+                   gnus-group-name-charset-group-alist))
+       (let ((pair (assoc gnus-namazu/group-name-regexp
+                         gnus-group-name-charset-group-alist)))
+        (if pair
+            (setcdr pair gnus-namazu-coding-system)
+          (push (cons gnus-namazu/group-name-regexp
+                      gnus-namazu-coding-system)
+                gnus-group-name-charset-group-alist))))
+  (unless gnus-namazu-command-prefix
+    (gnus-namazu-update-all-indices)))
+
+(defun gnus-namazu/server-directory (server)
+  "Return the top directory of the server SERVER."
+  (and (memq (car server) '(nnml nnmh))
+       (nnoo-change-server (car server) (nth 1 server) (nthcdr 2 server))
+       (file-name-as-directory
+       (expand-file-name (if (eq 'nnml (car server))
+                             nnml-directory
+                           nnmh-directory)))))
+
+;;; Functions to call Namazu.
+(defsubst gnus-namazu/normalize-results ()
+  "Normalize file names returned by Namazu in this current buffer."
+  (goto-char (point-min))
+  (while (not (eobp))
+    (when (looking-at "file://")
+      (delete-region (point) (match-end 0)))
+    (when (if gnus-namazu-need-path-normalization
+             (or (not (looking-at "/\\(.\\)|/"))
+                 (replace-match "\\1:/"))
+           (eq ?~ (char-after (point))))
+      (insert (expand-file-name
+              (buffer-substring (point-at-bol) (point-at-eol))))
+      (delete-region (point) (point-at-eol)))
+    (forward-line 1)))
+
+(defsubst gnus-namazu/call-namazu (query)
+  (let ((coding-system-for-read gnus-namazu-coding-system)
+       (coding-system-for-write gnus-namazu-coding-system)
+       (default-process-coding-system
+         (cons gnus-namazu-coding-system gnus-namazu-coding-system))
+       program-coding-system-alist
+       (file-name-coding-system gnus-namazu-coding-system)
+       (commands
+        (append gnus-namazu-command-prefix
+                (list gnus-namazu-command
+                      "-q"             ; don't be verbose
+                      "-a"             ; show all matches
+                      "-l")            ; use list format
+                gnus-namazu-additional-arguments
+                (list (if gnus-namazu-command-prefix
+                          (concat "'" query "'")
+                        query))
+                gnus-namazu-index-directories)))
+    (apply 'call-process (car commands) nil t nil (cdr commands))))
+
+(defvar gnus-namazu/directory-table nil)
+(defun gnus-namazu/make-directory-table (&optional force)
+  (interactive (list t))
+  (unless (and (not force)
+              gnus-namazu/directory-table
+              (eq gnus-namazu-case-sensitive-filesystem
+                  (car gnus-namazu/directory-table)))
+    (let ((table (make-vector (length gnus-newsrc-hashtb) 0))
+         cache agent alist dir method)
+      (mapatoms
+       (lambda (group)
+        (unless (gnus-ephemeral-group-p (setq group (symbol-name group)))
+          (when (file-directory-p
+                 (setq dir (file-name-as-directory
+                            (gnus-cache-file-name group ""))))
+            (push (cons dir group) cache))
+          (when (file-directory-p
+                 (setq dir (gnus-agent-group-pathname group)))
+            (push (cons dir group) agent))
+          (when (memq (car (setq method (gnus-find-method-for-group group)))
+                      '(nnml nnmh))
+            (when (file-directory-p
+                   (setq dir (let (file-name-handler-alist)
+                               (nnmail-group-pathname
+                                (gnus-group-short-name group)
+                                (gnus-namazu/server-directory method)))))
+              (push (cons dir group) alist)))
+          (dolist (pair gnus-namazu-remote-groups)
+            (when (setq dir
+                        (or (and (eq t (car pair))
+                                 (gnus-method-equal method gnus-select-method)
+                                 group)
+                            (and (stringp (car pair))
+                                 (string-match (car pair) group)
+                                 (substring group (match-end 0)))))
+              (setq dir (let (file-name-handler-alist)
+                          (nnmail-group-pathname dir "/")))
+              (push (cons (concat (cdr pair)
+                                  ;; nnmail-group-pathname() on some
+                                  ;; systems returns pathnames which
+                                  ;; have drive letters at their top.
+                                  (substring dir (1+ (string-match "/" dir))))
+                          group)
+                    alist)))))
+       gnus-newsrc-hashtb)
+      (dolist (pair (nconc agent cache alist))
+       (set (intern (if gnus-namazu-case-sensitive-filesystem
+                        (car pair)
+                      (downcase (car pair)))
+                    table)
+            (cdr pair)))
+      (setq gnus-namazu/directory-table
+           (cons gnus-namazu-case-sensitive-filesystem table)))))
+
+(defun gnus-namazu/search (groups query)
+  (gnus-namazu/make-directory-table)
+  (with-temp-buffer
+    (let ((exit-status (gnus-namazu/call-namazu query)))
+      (unless (zerop exit-status)
+       (error "Namazu finished abnormally: %d" exit-status)))
+    (gnus-namazu/normalize-results)
+    (goto-char (point-min))
+    (let (articles group)
+      (while (not (eobp))
+       (setq group (buffer-substring-no-properties
+                    (point)
+                    (progn
+                      (end-of-line)
+                      ;; NOTE: Only numeric characters are permitted
+                      ;; as file names of articles.
+                      (skip-chars-backward "0-9")
+                      (point))))
+       (and (setq group
+                  (symbol-value
+                   (intern-soft (if gnus-namazu-case-sensitive-filesystem
+                                    group
+                                  (downcase group))
+                                (cdr gnus-namazu/directory-table))))
+            (or (not groups)
+                (member group groups))
+            (push (gnus-namazu/make-article
+                   group
+                   (string-to-number
+                    (buffer-substring-no-properties (point)
+                                                    (point-at-eol))))
+                  articles))
+       (forward-line 1))
+      (nreverse articles))))
+
+;;; User Interface:
+(defun gnus-namazu/get-target-groups ()
+  (cond
+   ((eq major-mode 'gnus-group-mode)
+    ;; In Group buffer.
+    (cond
+     (current-prefix-arg
+      (gnus-group-process-prefix current-prefix-arg))
+     (gnus-group-marked
+      (prog1 gnus-group-marked (gnus-group-unmark-all-groups)))))
+   ((eq major-mode 'gnus-summary-mode)
+    ;; In Summary buffer.
+    (if current-prefix-arg
+       (list (gnus-read-group "Group: "))
+      (if (and
+          (gnus-ephemeral-group-p gnus-newsgroup-name)
+          (string-match gnus-namazu/group-name-regexp gnus-newsgroup-name))
+         (cadr (assq 'gnus-namazu-target-groups
+                     (gnus-info-method (gnus-get-info gnus-newsgroup-name))))
+       (list gnus-newsgroup-name))))))
+
+(defun gnus-namazu/get-current-query ()
+  (and (eq major-mode 'gnus-summary-mode)
+       (gnus-ephemeral-group-p gnus-newsgroup-name)
+       (string-match gnus-namazu/group-name-regexp gnus-newsgroup-name)
+       (cadr (assq 'gnus-namazu-current-query
+                  (gnus-info-method (gnus-get-info gnus-newsgroup-name))))))
+
+(defvar gnus-namazu/read-query-original-buffer nil)
+(defvar gnus-namazu/read-query-prompt nil)
+(defvar gnus-namazu/read-query-history nil)
+
+(defun gnus-namazu/get-current-subject ()
+  (and gnus-namazu/read-query-original-buffer
+       (bufferp gnus-namazu/read-query-original-buffer)
+       (with-current-buffer gnus-namazu/read-query-original-buffer
+        (when (eq major-mode 'gnus-summary-mode)
+          (let ((s (gnus-summary-article-subject)))
+            ;; Remove typically prefixes of mailing lists.
+            (when (string-match
+                   "^\\(\\[[^]]*[0-9]+\\]\\|([^)]*[0-9]+)\\)\\s-*" s)
+              (setq s (substring s (match-end 0))))
+            (when (string-match
+                   "^\\(Re\\(\\^?\\([0-9]+\\|\\[[0-9]+\\]\\)\\)?:\\s-*\\)+" s)
+              (setq s (substring s (match-end 0))))
+            (when (string-match "\\s-*(\\(re\\|was\\)\\b" s)
+              (setq s (substring s 0 (match-beginning 0))))
+            s)))))
+
+(defun gnus-namazu/get-current-from ()
+  (and gnus-namazu/read-query-original-buffer
+       (bufferp gnus-namazu/read-query-original-buffer)
+       (with-current-buffer gnus-namazu/read-query-original-buffer
+        (when (eq major-mode 'gnus-summary-mode)
+          (cadr (mail-extract-address-components
+                 (mail-header-from
+                  (gnus-summary-article-header))))))))
+
+(defun gnus-namazu/get-current-to ()
+  (and gnus-namazu/read-query-original-buffer
+       (bufferp gnus-namazu/read-query-original-buffer)
+       (with-current-buffer gnus-namazu/read-query-original-buffer
+        (when (eq major-mode 'gnus-summary-mode)
+          (cadr (mail-extract-address-components
+                 (cdr (assq 'To (mail-header-extra
+                                 (gnus-summary-article-header))))))))))
+
+(defmacro gnus-namazu/minibuffer-prompt-end ()
+  (if (fboundp 'minibuffer-prompt-end)
+      '(minibuffer-prompt-end)
+    '(point-min)))
+
+(defun gnus-namazu/message (string &rest arguments)
+  (let* ((s1 (concat
+             gnus-namazu/read-query-prompt
+             (buffer-substring (gnus-namazu/minibuffer-prompt-end)
+                               (point-max))))
+        (s2 (apply (function format) string arguments))
+        (w (- (window-width)
+              (string-width s1)
+              (string-width s2)
+              1)))
+    (message (if (>= w 0)
+                (concat s1 (make-string w ?\ ) s2)
+              s2))
+    (if (sit-for 0.3) (message s1))
+    s2))
+
+(defun gnus-namazu/complete-query ()
+  (interactive)
+  (let ((pos (point)))
+    (cond
+     ((and (re-search-backward "\\+\\([-a-z]*\\)" nil t)
+          (= pos (match-end 0)))
+      (let* ((partial (match-string 1))
+            (completions
+             (all-completions
+              partial
+              (mapcar 'list gnus-namazu-field-keywords))))
+       (cond
+        ((null completions)
+         (gnus-namazu/message "No completions of %s" partial))
+        ((= 1 (length completions))
+         (goto-char (match-beginning 1))
+         (delete-region (match-beginning 1) (match-end 1))
+         (insert (car completions) ":")
+         (setq pos (point))
+         (gnus-namazu/message "Completed"))
+        (t
+         (let ((x (try-completion partial (mapcar 'list completions))))
+           (if (string= x partial)
+               (if (and (eq last-command
+                            'gnus-namazu/field-keyword-completion)
+                        completion-auto-help)
+                   (with-output-to-temp-buffer "*Completions*"
+                     (display-completion-list completions))
+                 (gnus-namazu/message "Sole completion"))
+             (goto-char (match-beginning 1))
+             (delete-region (match-beginning 1) (match-end 1))
+             (insert x)
+             (setq pos (point))))))))
+     ((and (looking-at "\\+subject:")
+          (= pos (match-end 0)))
+      (let ((s (gnus-namazu/get-current-subject)))
+       (when s
+         (goto-char pos)
+         (insert "\"" s "\"")
+         (setq pos (point)))))
+     ((and (looking-at "\\+from:")
+          (= pos (match-end 0)))
+      (let ((f (gnus-namazu/get-current-from)))
+       (when f
+         (goto-char pos)
+         (insert "\"" f "\"")
+         (setq pos (point)))))
+     ((and (looking-at "\\+to:")
+          (= pos (match-end 0)))
+      (let ((to (gnus-namazu/get-current-to)))
+       (when to
+         (goto-char pos)
+         (insert "\"" to "\"")
+         (setq pos (point))))))
+    (goto-char pos)))
+
+(defvar gnus-namazu/read-query-map
+  (let ((keymap (copy-keymap minibuffer-local-map)))
+    (define-key keymap "\t" 'gnus-namazu/complete-query)
+    keymap))
+
+(defun gnus-namazu/read-query (prompt &optional initial)
+  (let ((gnus-namazu/read-query-original-buffer (current-buffer))
+       (gnus-namazu/read-query-prompt prompt))
+    (unless initial
+      (when (setq initial (gnus-namazu/get-current-query))
+       (setq initial (cons initial 0))))
+    (read-from-minibuffer prompt initial gnus-namazu/read-query-map nil
+                         'gnus-namazu/read-query-history)))
+
+(defun gnus-namazu/highlight-words (query)
+  (with-temp-buffer
+    (insert " " query)
+    ;; Remove tokens for NOT search
+    (goto-char (point-min))
+    (while (re-search-forward "[\e$B!!\e(B \t\r\f\n]+not[\e$B!!\e(B \t\r\f\n]+\
+\\([^\e$B!!\e(B \t\r\f\n\"{(/]+\\|\"[^\"]+\"\\|{[^}]+}\\|([^)]+)\\|/[^/]+/\\)+" nil t)
+      (delete-region (match-beginning 0) (match-end 0)))
+    ;; Remove tokens for Field search
+    (goto-char (point-min))
+    (while (re-search-forward "[\e$B!!\e(B \t\r\f\n]+\\+[^\e$B!!\e(B \t\r\f\n:]+:\
+\\([^\e$B!!\e(B \t\r\f\n\"{(/]+\\|\"[^\"]+\"\\|{[^}]+}\\|([^)]+)\\|/[^/]+/\\)+" nil t)
+      (delete-region (match-beginning 0) (match-end 0)))
+    ;; Remove tokens for Regexp search
+    (goto-char (point-min))
+    (while (re-search-forward "/[^/]+/" nil t)
+      (delete-region (match-beginning 0) (match-end 0)))
+    ;; Remove brackets, double quote, asterisk and operators
+    (goto-char (point-min))
+    (while (re-search-forward "\\([(){}\"*]\\|\\b\\(and\\|or\\)\\b\\)" nil t)
+      (delete-region (match-beginning 0) (match-end 0)))
+    ;; Collect all keywords
+    (setq query nil)
+    (goto-char (point-min))
+    (while (re-search-forward "[^\e$B!!\e(B \t\r\f\n]+" nil t)
+      (push (match-string 0) query))
+    (when query
+      (let (en ja)
+       (dolist (q query)
+         (if (string-match "\\cj" q)
+             (push q ja)
+           (push q en)))
+       (append
+        (when en
+          (list (list (concat "\\b\\(" (regexp-opt en) "\\)\\b")
+                      0 0 'gnus-namazu-query-highlight-face)))
+        (when ja
+          (list (list (regexp-opt ja)
+                      0 0 'gnus-namazu-query-highlight-face))))))))
+
+(defun gnus-namazu/truncate-article-list (articles)
+  (let ((hit (length articles)))
+    (when (and gnus-large-newsgroup
+              (> hit gnus-large-newsgroup))
+      (let* ((cursor-in-echo-area nil)
+            (input (read-from-minibuffer
+                    (format "\
+Too many articles were retrieved.  How many articles (max %d): "
+                            hit)
+                    (cons (number-to-string gnus-large-newsgroup) 0))))
+       (unless (string-match "\\`[ \t]*\\'" input)
+         (setcdr (nthcdr (min (1- (string-to-number input)) hit) articles)
+                 nil)))))
+  articles)
+
+;;;###autoload
+(defun gnus-namazu-search (groups query)
+  "Search QUERY through GROUPS with Namazu,
+and make a virtual group contains its results."
+  (interactive
+   (list
+    (gnus-namazu/get-target-groups)
+    (gnus-namazu/read-query "Enter query: ")))
+  (gnus-namazu/setup)
+  (let ((articles (gnus-namazu/search groups query)))
+    (if articles
+       (let ((real-groups groups)
+             (vgroup
+              (apply (function format)
+                     "nnvirtual:namazu-search?query=%s&groups=%s&id=%d%d%d"
+                     query
+                     (if groups (mapconcat 'identity groups ",") "ALL")
+                     (current-time))))
+         (gnus-namazu/truncate-article-list articles)
+         (unless real-groups
+           (dolist (a articles)
+             (add-to-list 'real-groups (gnus-namazu/article-group a))))
+         ;; Generate virtual group which includes all results.
+         (when (fboundp 'gnus-group-decoded-name)
+           (setq vgroup
+                 (encode-coding-string vgroup gnus-namazu-coding-system)))
+         (setq vgroup
+               (gnus-group-read-ephemeral-group
+                vgroup
+                `(nnvirtual ,vgroup
+                            (nnvirtual-component-groups ,real-groups)
+                            (gnus-namazu-target-groups ,groups)
+                            (gnus-namazu-current-query ,query))
+                t (cons (current-buffer) (current-window-configuration)) t))
+         (when gnus-namazu-query-highlight
+           (gnus-group-set-parameter vgroup 'highlight-words
+                                     (gnus-namazu/highlight-words query)))
+         ;; Generate new summary buffer which contains search results.
+         (gnus-group-read-group
+          t t vgroup
+          (sort (delq nil ;; Ad-hoc fix, to avoid wrong-type-argument error.
+                      (mapcar
+                       (lambda (a)
+                         (nnvirtual-reverse-map-article
+                          (gnus-namazu/article-group a)
+                          (gnus-namazu/article-number a)))
+                       articles))
+                '<)))
+      (message "No entry."))))
+
+(defmacro gnus-namazu/lock-file-name (&optional directory)
+  `(expand-file-name "NMZ.lock2" ,directory))
+
+(defmacro gnus-namazu/status-file-name (&optional directory)
+  `(expand-file-name "NMZ.status" ,directory))
+
+(defmacro gnus-namazu/index-file-name (&optional directory)
+  `(expand-file-name "NMZ.i" ,directory))
+
+(defun gnus-namazu/mknmz-cleanup (directory)
+  (let ((lockfile (gnus-namazu/lock-file-name directory)))
+    (when (file-exists-p lockfile)
+      (delete-file lockfile)
+      (dolist (tmpfile (directory-files directory t "\\`NMZ\\..*\\.tmp\\'" t))
+       (delete-file tmpfile)))))
+
+;;;###autoload
+(defun gnus-namazu-create-index (directory &optional target-directories force)
+  "Create index under DIRECTORY."
+  (interactive
+   (list
+    (if (and current-prefix-arg (> (length gnus-namazu-index-directories) 1))
+       (completing-read "Directory: "
+                        (mapcar 'list gnus-namazu-index-directories) nil t)
+      (gnus-namazu/default-index-directory))
+    nil t))
+  (setq directory (file-name-as-directory (expand-file-name directory)))
+  (unless target-directories
+    (setq target-directories
+         (delq nil
+               (mapcar (lambda (dir)
+                         (when (file-directory-p dir) dir))
+                       (append
+                        (mapcar 'gnus-namazu/server-directory
+                                (gnus-namazu/indexed-servers))
+                        (list
+                         (expand-file-name gnus-cache-directory)
+                         (expand-file-name gnus-agent-directory)))))))
+  (if (file-exists-p (gnus-namazu/lock-file-name directory))
+      (when force
+       (error "Found lock file: %s" (gnus-namazu/lock-file-name directory)))
+    (with-current-buffer
+       (get-buffer-create (concat " *mknmz*" directory))
+      (erase-buffer)
+      (unless (file-directory-p directory)
+       (make-directory directory t))
+      (setq default-directory directory)
+      (let ((args (append gnus-namazu-make-index-arguments
+                         target-directories)))
+       (insert "% " gnus-namazu-make-index-command " "
+               (mapconcat 'identity args " ") "\n")
+       (goto-char (point-max))
+       (when force
+         (pop-to-buffer (current-buffer)))
+       (message "Make index at %s..." directory)
+       (unwind-protect
+           (apply 'call-process gnus-namazu-make-index-command nil t t args)
+         (gnus-namazu/mknmz-cleanup directory))
+       (message "Make index at %s...done" directory)
+       (unless force
+         (kill-buffer (current-buffer)))))
+    (gnus-namazu/make-directory-table t)))
+
+(defun gnus-namazu/lapse-seconds (start end)
+  "Return lapse seconds from START to END.
+START and END are lists which represent time in Emacs-style."
+  (+ (* (- (car end) (car start)) 65536)
+     (cadr end)
+     (- (cadr start))))
+
+(defun gnus-namazu/index-old-p (directory)
+  "Return non-nil value when the index under the DIRECTORY is older
+than the period that is set to `gnus-namazu-index-update-interval'"
+  (let ((file (gnus-namazu/index-file-name directory)))
+    (or (not (file-exists-p file))
+       (and (integerp gnus-namazu-index-update-interval)
+            (>= (gnus-namazu/lapse-seconds
+                 (nth 5 (file-attributes file))
+                 (current-time))
+                gnus-namazu-index-update-interval)))))
+
+(defvar gnus-namazu/update-directories nil)
+(defvar gnus-namazu/update-process nil)
+
+(defun gnus-namazu/update-p (directory &optional force)
+  "Return the DIRECTORY when the index undef the DIRECTORY should be updated."
+  (setq directory (file-name-as-directory (expand-file-name directory)))
+  (gmm-labels ((error-message (format &rest args)
+                             (apply (if force 'error 'message) format args)
+                             nil))
+    (if gnus-namazu/update-process
+       (error-message "%s" "Can not run two update processes simultaneously")
+      (and (or force
+              (gnus-namazu/index-old-p directory))
+          (let ((status-file (gnus-namazu/status-file-name directory)))
+            (or (file-exists-p status-file)
+                (error-message "Can not find status file: %s" status-file)))
+          (let ((lock-file (gnus-namazu/lock-file-name directory)))
+            (or (not (file-exists-p lock-file))
+                (error-message "Found lock file: %s" lock-file)))
+          directory))))
+
+;;;###autoload
+(defun gnus-namazu-update-index (directory &optional force)
+  "Update the index under the DIRECTORY."
+  (interactive
+   (list
+    (if (and current-prefix-arg (> (length gnus-namazu-index-directories) 1))
+       (completing-read "Directory: "
+                        (mapcar 'list gnus-namazu-index-directories) nil t)
+      (gnus-namazu/default-index-directory))
+    t))
+  (when (setq directory (gnus-namazu/update-p directory force))
+    (with-current-buffer (get-buffer-create (concat " *mknmz*" directory))
+      (buffer-disable-undo)
+      (erase-buffer)
+      (unless (file-directory-p directory)
+       (make-directory directory t))
+      (setq default-directory directory)
+      (let ((proc (start-process gnus-namazu-make-index-command
+                                (current-buffer)
+                                gnus-namazu-make-index-command
+                                (format "--update=%s" directory))))
+       (if (processp proc)
+           (prog1 (setq gnus-namazu/update-process proc)
+             (process-kill-without-query proc)
+             (set-process-sentinel proc 'gnus-namazu/update-sentinel)
+             (add-hook 'kill-emacs-hook 'gnus-namazu-stop-update)
+             (message "Update index at %s..." directory))
+         (goto-char (point-min))
+         (if (re-search-forward "^ERROR:.*$" nil t)
+             (progn
+               (pop-to-buffer (current-buffer))
+               (funcall (if force 'error 'message)
+                        "Update index at %s...%s" directory (match-string 0)))
+           (kill-buffer (current-buffer))
+           (funcall (if force 'error 'message)
+                    "Can not start %s" gnus-namazu-make-index-command))
+         nil)))))
+
+;;;###autoload
+(defun gnus-namazu-update-all-indices (&optional force)
+  "Update all indices which is set to `gnus-namazu-index-directories'."
+  (interactive (list t))
+  (gnus-namazu-update-indices gnus-namazu-index-directories force))
+
+(defun gnus-namazu-update-indices (&optional directories force)
+  (when (setq directories
+             (delq nil (mapcar (lambda (d)
+                                 (gnus-namazu/update-p d force))
+                               directories)))
+    (setq gnus-namazu/update-directories (cons force (cdr directories)))
+    (gnus-namazu-update-index (car directories) force)))
+
+(defun gnus-namazu/update-sentinel (process event)
+  (let ((buffer (process-buffer process)))
+    (when (buffer-name buffer)
+      (with-current-buffer buffer
+       (gnus-namazu/mknmz-cleanup default-directory)
+       (goto-char (point-min))
+       (cond
+        ((re-search-forward "^ERROR:.*$" nil t)
+         (pop-to-buffer (current-buffer))
+         (message "Update index at %s...%s"
+                  default-directory (match-string 0))
+         (setq gnus-namazu/update-directories nil))
+        ((and (eq 'exit (process-status process))
+              (zerop (process-exit-status process)))
+         (message "Update index at %s...done" default-directory)
+         (unless (or debug-on-error debug-on-quit)
+           (kill-buffer buffer)))))))
+  (setq gnus-namazu/update-process nil)
+  (unless (gnus-namazu-update-indices (cdr gnus-namazu/update-directories)
+                                     (car gnus-namazu/update-directories))
+    (gnus-namazu/make-directory-table t)))
+
+;;;###autoload
+(defun gnus-namazu-stop-update ()
+  "Stop the running indexer of Namazu."
+  (interactive)
+  (setq gnus-namazu/update-directories nil)
+  (and gnus-namazu/update-process
+       (processp gnus-namazu/update-process)
+       (kill-process gnus-namazu/update-process)))
+
+(let (current-load-list)
+  (defadvice gnus-offer-save-summaries
+    (before gnus-namazu-kill-summary-buffers activate compile)
+    "Advised by `gnus-namazu'.
+In order to avoid annoying questions, kill summary buffers which
+generated by `gnus-namazu' itself before `gnus-offer-save-summaries'
+is called."
+    (let ((buffers (buffer-list)))
+      (while buffers
+       (when (with-current-buffer (car buffers)
+               (and (eq major-mode 'gnus-summary-mode)
+                    (gnus-ephemeral-group-p gnus-newsgroup-name)
+                    (string-match gnus-namazu/group-name-regexp
+                                  gnus-newsgroup-name)))
+         (kill-buffer (car buffers)))
+       (setq buffers (cdr buffers))))))
+
+;;;###autoload
+(defun gnus-namazu-insinuate ()
+  (add-hook
+   'gnus-group-mode-hook
+   (lambda ()
+     (define-key gnus-group-mode-map "\C-c\C-n" 'gnus-namazu-search)))
+  (add-hook
+   'gnus-summary-mode-hook
+   (lambda ()
+     (define-key gnus-summary-mode-map "\C-c\C-n" 'gnus-namazu-search))))
+
+(provide 'gnus-namazu)
+
+;; gnus-namazu.el ends here.
diff --git a/xemacs-packages/gnus/contrib/smime-card.el b/xemacs-packages/gnus/contrib/smime-card.el
new file mode 100644 (file)
index 0000000..a0fcab4
--- /dev/null
@@ -0,0 +1,195 @@
+;;; smime-card.el --- Make smime.el work with card readers
+
+;; Copyright (C) 2005 Brailcom, o.p.s.
+;; Author: Milan Zamazal <pdm@zamazal.org>
+
+;; COPYRIGHT NOTICE
+;;
+;; 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; if not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This is a simple wrapper around smime.el allowing to use private keys stored
+;; on a smard card.
+;;
+;; To use it, just put (require 'smime-card) to you Emacs startup file and
+;; customize the variable `smime-card-file-keys'.
+
+;;; Code:
+
+(require 'smime)
+
+;;; Configuration
+
+(defcustom smime-card-file-keys '()
+  "Alist of certificate files and their corresponding private key card ids.
+Each element of the list is of the form (FILE . KEY-ID), where FILE is a
+certificate file stored on a regular file system and KEY-ID is the identifier
+of the corresponding private key stored on the card.
+If FILE begins with the prefix `card:', the certificate is retrieved from the
+card under the id following the `card:' prefix in FILE."
+  :type '(alist :key-type (file :tag "Certificate file")
+                :value-type (string :tag "Key identifier"))
+  :group 'smime)
+
+(defcustom smime-card-fetch-certificates nil
+  "If non-nil, fetch certificates from the card before verifying messages."
+  :type 'boolean
+  :group 'smime)
+
+;;; Internals
+
+(defvar smime-card-key nil)
+
+(defun smime-card-key (keyfile)
+  (cdr (assoc keyfile smime-card-file-keys)))
+
+(defvar smime-card-engine-command
+  "engine dynamic -pre SO_PATH:/usr/lib/opensc/engine_pkcs11.so -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD\n")
+
+(defvar smime-card-process-output "")
+
+(defun smime-card-process-filter (process string)
+  (setq smime-card-process-output (concat smime-card-process-output string)))
+
+(defun smime-card-wait-for-prompt (process)
+  (while (not (string-match "\\(OpenSSL> \\|PIN: \\)$"
+                            smime-card-process-output))
+    (unless (accept-process-output process 5)
+      (message "OpenSSL: Timeout")
+      (throw 'error nil)))
+  (prog1 (if (string= (match-string 1 smime-card-process-output) "PIN: ")
+             'pin
+           t)
+    (setq smime-card-process-output "")))
+
+(defun smime-card-call-openssl-region (b e buf &rest args)
+  (let* ((infile (make-temp-file "smime-card-in"))
+         (outfile (make-temp-file "smime-card-out"))
+         (cert-on-card (and (string-match "^card:\\(.*\\)$" keyfile)
+                            (match-string 1 keyfile)))
+         (certfile (and cert-on-card (make-temp-file "smime-card-cert")))
+         (args (append args
+                       (list "-engine" "pkcs11"
+                             "-keyform" "engine"
+                             "-inkey" smime-card-key
+                             "-in" infile "-out" outfile)))
+         (process (start-process "openssl" " *openssl*" smime-openssl-program)))
+    (unwind-protect
+        (catch 'error
+          (when certfile
+            (unless (= (call-process "pkcs15-tool" nil nil nil
+                                     "-r" cert-on-card "-o" certfile)
+                       0)
+              (message "pkcs15: Error")
+              (throw 'error nil))
+            (let ((args* args))
+              (while (and args* (not (string= (car args*) "-signer")))
+                (setq args* (cdr args*)))
+              (setq args* (cdr args*))
+              (when args*
+                (setcar args* certfile))))
+          (setq smime-card-process-output "")
+          (set-process-filter process 'smime-card-process-filter)
+          (unless (eq (smime-card-wait-for-prompt process) t)
+            (message "OpenSSL: Error on startup")
+            (throw 'error nil))
+          (process-send-string process smime-card-engine-command)
+          (unless (eq (smime-card-wait-for-prompt process) t)
+            (message "OpenSSL: Error in pkcs11 loading")
+            (throw 'error nil))
+          (write-region b e infile nil 0)
+          (process-send-string process
+                               (concat (mapconcat 'identity args " ") "\n"))
+          (let ((answer (smime-card-wait-for-prompt process)))
+            (cond
+             ((eq answer 'pin)
+              (process-send-string process (concat (read-passwd "Smartcard PIN: ") "\n"))
+              (unless (eq (smime-card-wait-for-prompt process) t)
+                (message "OpenSSL: Error after passphrase")
+                (throw 'error nil)))
+             ((eq answer t)
+              nil)
+             (t
+              (message "OpenSSL: Error in processing")
+              (throw 'error nil))))
+          (process-send-eof process)
+          (with-current-buffer (car buf)
+            (when (= (cadr (insert-file-contents outfile)) 0)
+              (message "OpenSSL: Empty output")
+              (throw 'error nil)))
+          t)
+      (delete-file infile)
+      (delete-file outfile)
+      (when certfile (delete-file certfile))
+      (delete-process process)
+      (kill-buffer " *openssl*"))))
+
+;;; smime.el advices
+
+(defadvice smime-sign-region (around smime-card-sign-region activate)
+  (let ((smime-card-key (smime-card-key (ad-get-arg 2))))
+    ad-do-it))
+
+(defadvice smime-decrypt-region (around smime-card-decrypt-region activate)
+  (let ((smime-card-key (smime-card-key (ad-get-arg 2))))
+    ad-do-it))
+
+(defadvice smime-call-openssl-region (around smime-card-openssl activate)
+  (if smime-card-key
+      (setq ad-return-value
+            (apply 'smime-card-call-openssl-region (ad-get-args 0)))
+    ad-do-it))
+
+(defadvice smime-verify-region (around smime-card-verify-region activate)
+  (if smime-card-fetch-certificates
+      (let ((cert-ids '()))
+        (with-temp-buffer
+          (unless (= (call-process
+                      "pkcs15-tool" nil t nil "--list-certificates")
+                     0)
+            (error "pkcs15: Certificate listing"))
+          (goto-char (point-min))
+          (while (re-search-forward "^[\t ]+ID[ ]+: \\([0-9]+\\) *$" nil t)
+            (setq cert-ids (cons (match-string 1) cert-ids))))
+        (let ((certfile (make-temp-file "smime-card")))
+          (unwind-protect
+              (progn
+                (with-temp-file certfile
+                  (when smime-CA-file
+                    (insert-file-contents smime-CA-file))
+                  (mapc (lambda (id)
+                          (unless (= (call-process "pkcs15-tool" nil t nil
+                                                   "-r" id)
+                                     0)
+                            (error "pkcs15: Certificat read")))
+                        cert-ids))
+                (let ((smime-CA-file certfile))
+                  ad-do-it))
+            (delete-file certfile))))
+    ad-do-it))
+
+(defadvice mml-smime-verify (around smime-card-mml-smime-verify activate)
+  ;; If both smime-CA-directory and smime-CA-file are unset, `mml-smime-verify'
+  ;; refuses to perform certificate verification.
+  (let ((smime-CA-file (if smime-card-fetch-certificates
+                           (or smime-CA-file "/dev/null")
+                         smime-CA-file)))
+    ad-do-it))
+
+;;; Announce
+
+(provide 'smime-card)
+
+;;; smime-card.el ends here
diff --git a/xemacs-packages/gnus/contrib/vcard.el b/xemacs-packages/gnus/contrib/vcard.el
new file mode 100644 (file)
index 0000000..ed5c7da
--- /dev/null
@@ -0,0 +1,703 @@
+;;; vcard.el --- vcard parsing and display routines
+
+;; Copyright (C) 1997, 1999, 2000 Noah S. Friedman
+
+;; Author: Noah Friedman <friedman@splode.com>
+;; Maintainer: friedman@splode.com
+;; Keywords: vcard, mail, news
+;; Created: 1997-09-27
+
+;; <http://www.splode.com/users/friedman/software/emacs-lisp/>
+;; Id: vcard.el,v 1.11 2000/06/29 17:07:55 friedman 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
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Unformatted vcards are just plain ugly.  But if you live in the MIME
+;; world, they are a better way of exchanging contact information than
+;; freeform signatures since the former can be automatically parsed and
+;; stored in a searchable index.
+;;
+;; This library of routines provides the back end necessary for parsing
+;; vcards so that they can eventually go into an address book like BBDB
+;; (although this library does not implement that itself).  Also included
+;; is a sample pretty-printer which MUAs can use which do not provide their
+;; own vcard formatters.
+
+;; This library does not interface directly with any mail user agents.  For
+;; an example of bindings for the VM MUA, see vm-vcard.el available from
+;;
+;;    http://www.splode.com/~friedman/software/emacs-lisp/index.html#mail
+;;
+;; Updates to vcard.el should be available there too.
+
+;; The main entry point to this package is `vcard-pretty-print' although
+;; any documented variable or function is considered part of the API for
+;; operating on vcard data.
+
+;; The vcard 2.1 format is defined by the versit consortium.
+;; See http://www.imc.org/pdi/vcard-21.ps
+;;
+;; RFC 2426 defines the vcard 3.0 format.
+;; See ftp://ftp.rfc-editor.org/in-notes/rfc2426.txt
+
+;; A parsed vcard is a list of attributes of the form
+;;
+;;     (proplist value1 value2 ...)
+;;
+;; Where proplist is a list of property names and parameters, e.g.
+;;
+;;     (property1 (property2 . parameter2) ...)
+;;
+;; Each property has an associated implicit or explicit parameter value
+;; (not to be confused with attribute values; in general this API uses
+;; `parameter' to refer to property values and `value' to refer to attribute
+;; values to avoid confusion).  If a property has no explicit parameter value,
+;; the parameter value is considered to be `t'.  Any property which does not
+;; exist for an attribute is considered to have a nil parameter.
+
+;; TODO:
+;;   * Finish supporting the 3.0 extensions.
+;;     Currently, only the 2.1 standard is supported.
+;;   * Handle nested vcards and grouped attributes?
+;;     (I've never actually seen one of these in use.)
+;;   * Handle multibyte charsets.
+;;   * Inverse of vcard-parse-string: write .VCF files from alist
+;;   * Implement a vcard address book?  Or is using BBDB preferable?
+;;   * Improve the sample formatter.
+
+;;; Code:
+
+(defgroup vcard nil
+  "Support for the vCard electronic business card format."
+  :group 'vcard
+  :group 'mail
+  :group 'news)
+
+;;;###autoload
+(defcustom vcard-pretty-print-function 'vcard-format-sample-box
+  "*Formatting function used by `vcard-pretty-print'."
+  :type 'function
+  :group 'vcard)
+
+;;;###autoload
+(defcustom vcard-standard-filters
+  '(vcard-filter-html
+    vcard-filter-adr-newlines
+    vcard-filter-tel-normalize
+    vcard-filter-textprop-cr)
+  "*Standard list of filters to apply to parsed vcard data.
+These filters are applied sequentially to vcard attributes when
+the function `vcard-standard-filter' is supplied as the second argument to
+`vcard-parse'."
+  :type 'hook
+  :group 'vcard)
+
+\f
+;;; No user-settable options below.
+
+;; XEmacs 21 ints and chars are disjoint types.
+;; For all else, treat them as the same.
+(defalias 'vcard-char-to-int
+  (if (fboundp 'char-to-int) 'char-to-int 'identity))
+
+;; This is just the version number for this package; it does not refer to
+;; the vcard format specification.  Currently, this package does not yet
+;; support the full vcard 3.0 specification.
+;;
+;; Whenever any part of the API defined in this package change in a way
+;; that is not backward-compatible, the major version number here should be
+;; incremented.  Backward-compatible additions to the API should be
+;; indicated by increasing the minor version number.
+(defconst vcard-api-version "2.0")
+
+;; The vcard standards allow specifying the encoding for an attribute using
+;; these values as immediate property names, rather than parameters of the
+;; `encoding' property.  If these are encountered while parsing, associate
+;; them as parameters of the `encoding' property in the returned structure.
+(defvar vcard-encoding-tags
+  '("quoted-printable" "base64" "8bit" "7bit"))
+
+;; The vcard parser will auto-decode these encodings when they are
+;; encountered.  These methods are invoked via vcard-parse-region-value.
+(defvar vcard-region-decoder-methods
+  '(("quoted-printable" . vcard-region-decode-quoted-printable)
+    ("base64"           . vcard-region-decode-base64)))
+
+;; This is used by vcard-region-decode-base64
+(defvar vcard-region-decode-base64-table
+  (let* ((a "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
+         (len (length a))
+         (tbl (make-vector 123 nil))
+         (i 0))
+    (while (< i len)
+      (aset tbl (vcard-char-to-int (aref a i)) i)
+      (setq i (1+ i)))
+    tbl))
+
+\f
+;;; This function can be used generically by applications to obtain
+;;; a printable representation of a vcard.
+
+;;;###autoload
+(defun vcard-pretty-print (vcard)
+  "Format VCARD into a string suitable for display to user.
+VCARD can be an unparsed string containing raw VCF vcard data
+or a parsed vcard alist as returned by `vcard-parse-string'.
+
+The result is a string with formatted vcard information suitable for
+insertion into a mime presentation buffer.
+
+The function specified by the variable `vcard-pretty-print-function'
+actually performs the formatting.  That function will always receive a
+parsed vcard alist."
+  (and (stringp vcard)
+       (setq vcard (vcard-parse-string vcard)))
+  (funcall vcard-pretty-print-function vcard))
+
+\f
+;;; Parsing routines
+
+;;;###autoload
+(defun vcard-parse-string (raw &optional filter)
+  "Parse RAW vcard data as a string, and return an alist representing data.
+
+If the optional function FILTER is specified, apply that filter to each
+attribute.  If no filter is specified, `vcard-standard-filter' is used.
+
+Filters should accept two arguments: the property list and the value list.
+Modifying in place the property or value list will affect the resulting
+attribute in the vcard alist.
+
+Vcard data is normally in the form
+
+    begin:                        vcard
+    prop1a:                       value1a
+    prop2a;prop2b;prop2c=param2c: value2a
+    prop3a;prop3b:                value3a;value3b;value3c
+    end:                          vcard
+
+\(Whitespace around the `:' separating properties and values is optional.\)
+If supplied to this function an alist of the form
+
+    \(\(\(\"prop1a\"\) \"value1a\"\)
+     \(\(\"prop2a\" \"prop2b\" \(\"prop2c\" . \"param2c\"\)\) \"value2a\"\)
+     \(\(\"prop3a\" \"prop3b\"\) \"value3a\" \"value3b\" \"value3c\"\)\)
+
+would be returned."
+  (let ((vcard nil)
+        (buf (generate-new-buffer " *vcard parser work*")))
+    (unwind-protect
+        (save-excursion
+          (set-buffer buf)
+          ;; Make sure last line is newline-terminated.
+          ;; An extra trailing newline is harmless.
+          (insert raw "\n")
+          (setq vcard (vcard-parse-region (point-min) (point-max) filter)))
+      (kill-buffer buf))
+    vcard))
+
+;;;###autoload
+(defun vcard-parse-region (beg end &optional filter)
+  "Parse the raw vcard data in region, and return an alist representing data.
+This function is just like `vcard-parse-string' except that it operates on
+a region of the current buffer rather than taking a string as an argument.
+
+Note: this function modifies the buffer!"
+  (or filter
+      (setq filter 'vcard-standard-filter))
+  (let ((case-fold-search t)
+        (vcard-data nil)
+        (pos (make-marker))
+        (newpos (make-marker))
+        properties value)
+    (save-restriction
+      (narrow-to-region beg end)
+      (save-match-data
+        ;; Unfold folded lines and delete naked carriage returns
+        (goto-char (point-min))
+        (while (re-search-forward "\r$\\|\n[ \t]" nil t)
+          (goto-char (match-beginning 0))
+          (delete-char 1))
+
+        (goto-char (point-min))
+        (re-search-forward "^begin:[ \t]*vcard[ \t]*\n")
+        (set-marker pos (point))
+        (while (and (not (looking-at "^end[ \t]*:[ \t]*vcard[ \t]*$"))
+                    (re-search-forward ":[ \t]*" nil t))
+          (set-marker newpos (match-end 0))
+          (setq properties
+                (vcard-parse-region-properties pos (match-beginning 0)))
+          (set-marker pos (marker-position newpos))
+          (re-search-forward "[ \t]*\n")
+          (set-marker newpos (match-end 0))
+          (setq value
+                (vcard-parse-region-value properties pos (match-beginning 0)))
+          (set-marker pos (marker-position newpos))
+          (goto-char pos)
+          (funcall filter properties value)
+          (setq vcard-data (cons (cons properties value) vcard-data)))))
+    (nreverse vcard-data)))
+
+(defun vcard-parse-region-properties (beg end)
+  (downcase-region beg end)
+  (let* ((proplist (vcard-split-string (buffer-substring beg end) ";"))
+         (props proplist)
+         split)
+    (save-match-data
+      (while props
+        (cond ((string-match "=" (car props))
+               (setq split (vcard-split-string (car props) "=" 2))
+               (setcar props (cons (car split) (car (cdr split)))))
+              ((member (car props) vcard-encoding-tags)
+               (setcar props (cons "encoding" (car props)))))
+        (setq props (cdr props))))
+    proplist))
+
+(defun vcard-parse-region-value (proplist beg end)
+  (let* ((encoding (vcard-get-property proplist "encoding"))
+         (decoder (cdr (assoc encoding vcard-region-decoder-methods)))
+         result pos match-beg match-end)
+    (save-restriction
+      (narrow-to-region beg end)
+      (cond (decoder
+             ;; Each `;'-separated field needs to be decoded and saved
+             ;; separately; if the entire region were decoded at once, we
+             ;; would not be able to distinguish between the original `;'
+             ;; chars and those which were encoded in order to quote them
+             ;; against being treated as field separators.
+             (goto-char beg)
+             (setq pos (set-marker (make-marker) (point)))
+             (setq match-beg (make-marker))
+             (setq match-end (make-marker))
+             (save-match-data
+               (while (< pos (point-max))
+                 (cond ((search-forward ";" nil t)
+                        (set-marker match-beg (match-beginning 0))
+                        (set-marker match-end (match-end 0)))
+                       (t
+                        (set-marker match-beg (point-max))
+                        (set-marker match-end (point-max))))
+                 (funcall decoder pos match-beg)
+                 (setq result (cons (buffer-substring pos match-beg) result))
+                 (set-marker pos (marker-position match-end))))
+             (setq result (nreverse result))
+             (vcard-set-property proplist "encoding" nil))
+            (t
+             (setq result (vcard-split-string (buffer-string) ";")))))
+    (goto-char (point-max))
+    result))
+
+\f
+;;; Functions for retrieving property or value information from parsed
+;;; vcard attributes.
+
+(defun vcard-values (vcard have-props &optional non-props limit)
+  "Return the values in VCARD.
+This function is like `vcard-ref' and takes the same arguments, but return
+only the values, not the associated property lists."
+  (mapcar 'cdr (vcard-ref vcard have-props non-props limit)))
+
+(defun vcard-ref (vcard have-props &optional non-props limit)
+  "Return the attributes in VCARD with HAVE-PROPS properties.
+Optional arg NON-PROPS is a list of properties which candidate attributes
+must not have.
+Optional arg LIMIT means return no more than that many attributes.
+
+The attributes in VCARD which have all properties specified by HAVE-PROPS
+but not having any specified by NON-PROPS are returned.  The first element
+of each attribute is the actual property list; the remaining elements are
+the values.
+
+If a specific property has an associated parameter \(e.g. an encoding\),
+use the syntax \(\"property\" . \"parameter\"\) to specify it.  If property
+parameter is not important or it has no specific parameter, just specify
+the property name as a string."
+  (let ((attrs vcard)
+        (result nil)
+        (count 0))
+    (while (and attrs (or (null limit) (< count limit)))
+      (and (vcard-proplist-all-properties (car (car attrs)) have-props)
+           (not (vcard-proplist-any-properties (car (car attrs)) non-props))
+           (setq result (cons (car attrs) result)
+                 count (1+ count)))
+      (setq attrs (cdr attrs)))
+    (nreverse result)))
+
+(defun vcard-proplist-all-properties (proplist props)
+  "Returns nil unless PROPLIST contains all properties specified in PROPS."
+  (let ((result t))
+    (while (and result props)
+      (or (vcard-get-property proplist (car props))
+          (setq result nil))
+      (setq props (cdr props)))
+    result))
+
+(defun vcard-proplist-any-properties (proplist props)
+  "Returns `t' if PROPLIST contains any of the properties specified in PROPS."
+  (let ((result nil))
+    (while (and (not result) props)
+      (and (vcard-get-property proplist (car props))
+           (setq result t))
+      (setq props (cdr props)))
+    result))
+
+(defun vcard-get-property (proplist property)
+  "Return the value from PROPLIST of PROPERTY.
+PROPLIST is a vcard attribute property list, which is normally the first
+element of each attribute entry in a vcard."
+  (or (and (member property proplist) t)
+      (cdr (assoc property proplist))))
+
+(defun vcard-set-property (proplist property value)
+  "In PROPLIST, set PROPERTY to VALUE.
+PROPLIST is a vcard attribute property list.
+If VALUE is nil, PROPERTY is deleted."
+  (let (elt)
+    (cond ((null value)
+           (vcard-delete-property proplist property))
+          ((setq elt (member property proplist))
+           (and value (not (eq value t))
+                (setcar elt (cons property value))))
+          ((setq elt (assoc property proplist))
+           (cond ((eq value t)
+                  (setq elt (memq elt proplist))
+                  (setcar elt property))
+                 (t
+                  (setcdr elt value))))
+          ((eq value t)
+           (nconc proplist (cons property nil)))
+          (t
+           (nconc proplist (cons (cons property value) nil))))))
+
+(defun vcard-delete-property (proplist property)
+  "Delete from PROPLIST the specified property PROPERTY.
+This will not succeed in deleting the first member of the proplist, but
+that element should never be deleted since it is the primary key."
+  (let (elt)
+    (cond ((setq elt (member property proplist))
+           (delq (car elt) proplist))
+          ((setq elt (assoc property proplist))
+           (delq (car (memq elt proplist)) proplist)))))
+
+\f
+;;; Vcard data filters.
+;;;
+;;; Filters receive both the property list and value list and may modify
+;;; either in-place.  The return value from the filters are ignored.
+;;;
+;;; These filters can be used for purposes such as removing HTML tags or
+;;; normalizing phone numbers into a standard form.
+
+(defun vcard-standard-filter (proplist values)
+  "Apply filters in `vcard-standard-filters' to attributes."
+  (vcard-filter-apply-filter-list vcard-standard-filters proplist values))
+
+;; This function could be used to dispatch other filter lists.
+(defun vcard-filter-apply-filter-list (filter-list proplist values)
+  (while filter-list
+    (funcall (car filter-list) proplist values)
+    (setq filter-list (cdr filter-list))))
+
+;; Some lusers put HTML (or even javascript!) in their vcards under the
+;; misguided notion that it's a standard feature of vcards just because
+;; Netscape supports this feature.  That is wrong; the vcard specification
+;; does not define any html content semantics and most MUAs cannot do
+;; anything with html text except display them unparsed, which is ugly.
+;;
+;; Thank Netscape for abusing the standard and damned near rendering it
+;; useless for interoperability between MUAs.
+;;
+;; This filter does a very rudimentary job.
+(defun vcard-filter-html (proplist values)
+  "Remove HTML tags from attribute values."
+  (save-match-data
+    (while values
+      (while (string-match "<[^<>\n]+>" (car values))
+        (setcar values (replace-match "" t t (car values))))
+      (setq values (cdr values)))))
+
+(defun vcard-filter-adr-newlines (proplist values)
+  "Replace newlines with \"; \" in `adr' values."
+  (and (vcard-get-property proplist "adr")
+       (save-match-data
+         (while values
+           (while (string-match "[\r\n]+" (car values))
+             (setcar values (replace-match "; " t t (car values))))
+           (setq values (cdr values))))))
+
+(defun vcard-filter-tel-normalize (proplist values)
+  "Normalize telephone numbers in `tel' values.
+Spaces and hyphens are replaced with `.'.
+US domestic telephone numbers are replaced with international format."
+  (and (vcard-get-property proplist "tel")
+       (save-match-data
+         (while values
+           (while (string-match "[\t._-]+" (car values))
+             (setcar values (replace-match " " t t (car values))))
+           (and (string-match "^(?\\(\\S-\\S-\\S-\\))? ?\
+\\(\\S-\\S-\\S- \\S-\\S-\\S-\\S-\\)"
+                              (car values))
+                (setcar values
+                        (replace-match "+1 \\1 \\2" t nil (car values))))
+           (setq values (cdr values))))))
+
+(defun vcard-filter-textprop-cr (proplist values)
+  "Strip carriage returns from text values."
+  (and (vcard-proplist-any-properties
+        proplist '("adr" "email" "fn" "label" "n" "org" "tel" "title" "url"))
+       (save-match-data
+         (while values
+           (while (string-match "\r+" (car values))
+             (setcar values (replace-match "" t t (car values))))
+           (setq values (cdr values))))))
+
+\f
+;;; Decoding methods.
+
+(defmacro vcard-hexstring-to-ascii (s)
+  (if (string-lessp emacs-version "20")
+      `(format "%c" (car (read-from-string (format "?\\x%s" ,s))))
+    `(format "%c" (string-to-number ,s 16))))
+
+(defun vcard-region-decode-quoted-printable (&optional beg end)
+  (save-excursion
+    (save-restriction
+      (save-match-data
+        (narrow-to-region (or beg (point-min)) (or end (point-max)))
+        (goto-char (point-min))
+        (while (re-search-forward "=\n" nil t)
+          (delete-region (match-beginning 0) (match-end 0)))
+        (goto-char (point-min))
+        (while (re-search-forward "=[0-9A-Za-z][0-9A-Za-z]" nil t)
+          (let ((s (buffer-substring (1+ (match-beginning 0)) (match-end 0))))
+            (replace-match (vcard-hexstring-to-ascii s) t t)))))))
+
+(defun vcard-region-decode-base64 (&optional beg end)
+  (save-restriction
+    (narrow-to-region (or beg (point-min)) (or end (point-max)))
+    (save-match-data
+      (goto-char (point-min))
+      (while (re-search-forward "[ \t\r\n]+" nil t)
+        (delete-region (match-beginning 0) (match-end 0))))
+    (goto-char (point-min))
+    (let ((count 0)
+          (n 0)
+          (c nil))
+      (while (not (eobp))
+        (setq c (char-after (point)))
+        (delete-char 1)
+        (cond ((char-equal c ?=)
+               (if (= count 2)
+                   (insert (lsh n -10))
+                 ;; count must be 3
+                 (insert (lsh n -16) (logand 255 (lsh n -8))))
+               (delete-region (point) (point-max)))
+              (t
+               (setq n (+ n (aref vcard-region-decode-base64-table
+                                  (vcard-char-to-int c))))
+               (setq count (1+ count))
+               (cond ((= count 4)
+                      (insert (logand 255 (lsh n -16))
+                              (logand 255 (lsh n -8))
+                              (logand 255 n))
+                      (setq n 0 count 0))
+                     (t
+                      (setq n (lsh n 6))))))))))
+
+\f
+(defun vcard-split-string (string &optional separator limit)
+  "Split STRING at occurences of SEPARATOR.  Return a list of substrings.
+Optional argument SEPARATOR can be any regexp, but anything matching the
+ separator will never appear in any of the returned substrings.
+ If not specified, SEPARATOR defaults to \"[ \\f\\t\\n\\r\\v]+\".
+If optional arg LIMIT is specified, split into no more than that many
+ fields \(though it may split into fewer\)."
+  (or separator (setq separator "[ \f\t\n\r\v]+"))
+  (let ((string-list nil)
+        (len (length string))
+        (pos 0)
+        (splits 0)
+        str)
+    (save-match-data
+      (while (<= pos len)
+        (setq splits (1+ splits))
+        (cond ((and limit
+                    (>= splits limit))
+               (setq str (substring string pos))
+               (setq pos (1+ len)))
+              ((string-match separator string pos)
+               (setq str (substring string pos (match-beginning 0)))
+               (setq pos (match-end 0)))
+              (t
+               (setq str (substring string pos))
+               (setq pos (1+ len))))
+        (setq string-list (cons str string-list))))
+    (nreverse string-list)))
+
+(defun vcard-copy-tree (tree)
+  "Make a deep copy of nested conses."
+  (cond
+   ((consp tree)
+    (cons (vcard-copy-tree (car tree))
+          (vcard-copy-tree (cdr tree))))
+   (t tree)))
+
+(defun vcard-flatten (l)
+  (if (consp l)
+      (apply 'nconc (mapcar 'vcard-flatten l))
+    (list l)))
+
+\f
+;;; Sample formatting routines.
+
+(defun vcard-format-sample-box (vcard)
+  "Like `vcard-format-sample-string', but put an ascii box around text."
+  (let* ((lines (vcard-format-sample-lines vcard))
+         (len (vcard-format-sample-max-length lines))
+         (edge (concat "\n+" (make-string (+ len 2) ?-) "+\n"))
+         (line-fmt (format "| %%-%ds |" len))
+         (formatted-lines
+          (mapconcat (function (lambda (s) (format line-fmt s))) lines "\n")))
+    (if (string= formatted-lines "")
+        formatted-lines
+      (concat edge formatted-lines edge))))
+
+(defun vcard-format-sample-string (vcard)
+  "Format VCARD into a string suitable for display to user.
+VCARD should be a parsed vcard alist.  The result is a string
+with formatted vcard information which can be inserted into a mime
+presentation buffer."
+  (mapconcat 'identity (vcard-format-sample-lines vcard) "\n"))
+
+(defun vcard-format-sample-lines (vcard)
+  (let* ((name  (vcard-format-sample-get-name vcard))
+         (title (vcard-format-sample-values-concat vcard '("title") 1 "; "))
+         (org   (vcard-format-sample-values-concat vcard '("org")   1 "; "))
+         (addr  (vcard-format-sample-get-address vcard))
+         (tel   (vcard-format-sample-get-telephone vcard))
+         (lines (delete nil (vcard-flatten (list name title org addr))))
+         (col-template (format "%%-%ds%%s"
+                               (vcard-format-sample-offset lines tel)))
+         (l lines))
+    (while tel
+      (setcar l (format col-template (car l) (car tel)))
+      ;; If we stripped away too many nil slots from l, add empty strings
+      ;; back in so setcar above will work on next iteration.
+      (and (cdr tel)
+           (null (cdr l))
+           (setcdr l (cons "" nil)))
+      (setq l (cdr l))
+      (setq tel (cdr tel)))
+    lines))
+
+(defun vcard-format-sample-get-name (vcard)
+  (let ((name (car (car (vcard-values vcard '("fn") nil 1))))
+        (email (car (vcard-format-sample-values
+                     vcard '((("email" "pref"))
+                             (("email" "internet"))
+                             (("email"))) 1))))
+    (cond ((and name email)
+           (format "%s <%s>" name email))
+          (email)
+          (name)
+          (""))))
+
+(defun vcard-format-sample-get-telephone (vcard)
+  (let ((fields '(("Work: "
+                   (("tel" "work" "pref")  . ("fax" "pager" "cell"))
+                   (("tel" "work" "voice") . ("fax" "pager" "cell"))
+                   (("tel" "work")         . ("fax" "pager" "cell")))
+                  ("Home: "
+                   (("tel" "home" "pref")  . ("fax" "pager" "cell"))
+                   (("tel" "home" "voice") . ("fax" "pager" "cell"))
+                   (("tel" "home")         . ("fax" "pager" "cell"))
+                   (("tel")                . ("fax" "pager" "cell" "work")))
+                  ("Cell: "
+                   (("tel" "cell" "pref"))
+                   (("tel" "cell")))
+                  ("Fax:  "
+                   (("tel" "pref" "fax"))
+                   (("tel" "work" "fax"))
+                   (("tel" "home" "fax"))
+                   (("tel" "fax")))))
+        (phones nil)
+        result)
+    (while fields
+      (setq result (vcard-format-sample-values vcard (cdr (car fields))))
+      (while result
+        (setq phones
+              (cons (concat (car (car fields)) (car (car result))) phones))
+        (setq result (cdr result)))
+      (setq fields (cdr fields)))
+    (nreverse phones)))
+
+(defun vcard-format-sample-get-address (vcard)
+  (let* ((addr (vcard-format-sample-values vcard '((("adr" "pref" "work"))
+                                                   (("adr" "pref"))
+                                                   (("adr" "work"))
+                                                   (("adr"))) 1))
+         (street (delete "" (list (nth 0 addr) (nth 1 addr) (nth 2 addr))))
+         (city-list (delete "" (nthcdr 3 addr)))
+         (city (cond ((null (car city-list)) nil)
+                     ((cdr city-list)
+                      (format "%s, %s"
+                              (car city-list)
+                              (mapconcat 'identity (cdr city-list) " ")))
+                     (t (car city-list)))))
+    (delete nil (if city
+                    (append street (list city))
+                  street))))
+
+(defun vcard-format-sample-values-concat (vcard have-props limit sep)
+  (let ((l (car (vcard-values vcard have-props nil limit))))
+    (and l (mapconcat 'identity (delete "" (vcard-copy-tree l)) sep))))
+
+(defun vcard-format-sample-values (vcard proplists &optional limit)
+  (let ((result (vcard-format-sample-ref vcard proplists limit)))
+    (if (equal limit 1)
+        (cdr result)
+      (mapcar 'cdr result))))
+
+(defun vcard-format-sample-ref (vcard proplists &optional limit)
+  (let ((result nil))
+    (while (and (null result) proplists)
+      (setq result (vcard-ref vcard
+                              (car (car proplists))
+                              (cdr (car proplists))
+                              limit))
+      (setq proplists (cdr proplists)))
+    (if (equal limit 1)
+        (vcard-copy-tree (car result))
+      (vcard-copy-tree result))))
+
+(defun vcard-format-sample-offset (row1 row2 &optional maxwidth)
+  (or maxwidth (setq maxwidth (frame-width)))
+  (let ((max1 (vcard-format-sample-max-length row1))
+        (max2 (vcard-format-sample-max-length row2)))
+    (if (zerop max1)
+        0
+      (+ max1 (min 5 (max 1 (- maxwidth (+ max1 max2))))))))
+
+(defun vcard-format-sample-max-length (strings)
+  (let ((maxlen 0))
+    (while strings
+      (setq maxlen (max maxlen (length (car strings))))
+      (setq strings (cdr strings)))
+    maxlen))
+
+(provide 'vcard)
+
+;;; vcard.el ends here
diff --git a/xemacs-packages/gnus/etc/ChangeLog b/xemacs-packages/gnus/etc/ChangeLog
new file mode 100644 (file)
index 0000000..6fa45a6
--- /dev/null
@@ -0,0 +1,106 @@
+2015-01-29  Francesc Rocher  <francesc.rocher@gmail.com>
+
+       * images/splash.svg, images/splash.png, images/README:
+       Splash images refurbished.
+
+2014-01-31  Alex Schroeder  <alex@gnu.org>  (tiny change)
+
+       * gnus-tut.txt (Message-ID): Typo fix (bug#15556).
+
+2011-11-22  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * post-receive: Get the user name and e-mail correct.
+
+2011-02-25  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * post-receive: Always show the commit messages and the "git describe"
+       output.
+
+2011-02-18  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * post-receive: Fix $(( bug.  Note that the user name and address are
+       incorrect if the last commit was on a branch.
+
+2010-11-22  Julien Danjou  <julien@danjou.info>
+
+       * post-receive: Use commiter name and email address.
+
+2010-09-24  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * post-receive: Use the emailprefix again.
+
+2010-09-23  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * post-receive: Add log count to header.
+
+2010-09-02  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * post-receive: More subject formatting.
+
+2010-09-01  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * post-receive: Add modified post-receive hook for Git.  Comment.  Put
+       the update message after the diff.  Join multiple oneline logs into one
+       long subject.
+
+2010-03-22  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus/gnus-setup.ast: Add finish links to the top nodes.
+
+       * gnus/news-server.ast: Add some trivial validation.
+
+2008-07-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * Makefile.in (install): Install png and svg files.
+       (uninstall): Uninstall png and svg files.
+
+2008-05-01  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * ChangeLog: Bump version to 0.11
+
+2008-04-11  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * ChangeLog: Bump version to 0.9.
+
+2008-04-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * ChangeLog: No Gnus v0.8 is released.
+
+2008-02-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * Makefile.in (datarootdir): Define.
+       (install, uninstall): Quote directory name that might contain
+       whitespace.
+
+2007-11-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * images/GNUS-README: Rename from README.  Add some information
+       about the purpose of the various README files.
+
+       * images/README: New.  `emacs/etc/images/README' from Emacs.
+
+       * ChangeLog: New ChangeLog for `./etc'.  Should simplify syncing with
+       Emacs a little bit.
+
+  Copyright (C) 2007-2016 Free Software Foundation, Inc.
+
+  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 3, 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.  If not, see <http://www.gnu.org/licenses/>.
+
+;; Local Variables:
+;; coding: iso-2022-7bit
+;; fill-column: 79
+;; add-log-time-zone-rule: t
+;; End:
diff --git a/xemacs-packages/gnus/etc/Makefile.in b/xemacs-packages/gnus/etc/Makefile.in
new file mode 100644 (file)
index 0000000..cd542ec
--- /dev/null
@@ -0,0 +1,104 @@
+prefix = @prefix@
+datarootdir = @datarootdir@
+datadir = @datadir@
+infodir = @infodir@
+srcdir = @srcdir@
+subdir = etc
+top_srcdir = @top_srcdir@
+lispdir = @lispdir@
+etcdir = @etcdir@
+
+VPATH=$(srcdir)
+EMACS=@EMACS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+SHELL = /bin/sh
+
+install:
+       $(SHELL) $(top_srcdir)/mkinstalldirs "$(DESTDIR)$(etcdir)"
+       @cd $(srcdir) \
+       && for p in gnus-tut.txt; do \
+         echo "$(INSTALL_DATA) \"$$p $(DESTDIR)$(etcdir)/$$p\""; \
+         $(INSTALL_DATA) $$p "$(DESTDIR)$(etcdir)/$$p"; \
+       done
+       $(SHELL) $(top_srcdir)/mkinstalldirs "$(DESTDIR)$(etcdir)/images/gnus" "$(DESTDIR)$(etcdir)/images/mail"
+       @cd $(srcdir) \
+       && for p in images/gnus/*.pbm images/gnus/*.png images/gnus/*.svg \
+                   images/gnus/*.xbm images/gnus/*.xpm \
+                   images/mail/*.pbm images/mail/*.png images/mail/*.svg \
+                   images/mail/*.xbm images/mail/*.xpm \
+                   images/*.pbm images/*.png images/*.svg images/*.xbm \
+                   images/*.xpm; do \
+         if test -f $$p; then \
+           echo "$(INSTALL_DATA) $$p \"$(DESTDIR)$(etcdir)/$$p\""; \
+           $(INSTALL_DATA) $$p "$(DESTDIR)$(etcdir)/$$p"; \
+         fi; \
+       done
+       $(SHELL) $(top_srcdir)/mkinstalldirs "$(DESTDIR)$(etcdir)/images/smilies" \
+         "$(DESTDIR)$(etcdir)/images/smilies/grayscale" "$(DESTDIR)$(etcdir)/images/smilies/medium"
+       @cd $(srcdir) \
+       && for p in images/smilies/*.pbm images/smilies/*.png \
+                   images/smilies/*.svg images/smilies/*.xbm \
+                   images/smilies/*.xpm \
+                   images/smilies/grayscale/*.pbm \
+                   images/smilies/grayscale/*.png \
+                   images/smilies/grayscale/*.svg \
+                   images/smilies/grayscale/*.xbm \
+                   images/smilies/grayscale/*.xpm \
+                   images/smilies/medium/*.pbm images/smilies/medium/*.png \
+                   images/smilies/medium/*.svg images/smilies/medium/*.xbm \
+                   images/smilies/medium/*.xpm; do \
+         if test -f $$p; then \
+           echo "$(INSTALL_DATA) $$p \"$(DESTDIR)$(etcdir)/$$p\""; \
+           $(INSTALL_DATA) $$p "$(DESTDIR)$(etcdir)/$$p"; \
+         fi; \
+       done
+
+uninstall:
+       rm -f "$(etcdir)/gnus-tut.txt"
+       @cd $(srcdir) \
+       && for p in images/gnus/*.pbm images/gnus/*.png images/gnus/*.svg \
+                   images/gnus/*.xbm images/gnus/*.xpm \
+                   images/mail/*.pbm images/mail/*.png images/mail/*.svg \
+                   images/mail/*.xbm images/mail/*.xpm \
+                   images/*.pbm images/*.png images/*.svg images/*.xbm \
+                   images/*.xpm; do \
+         if test -f $$p; then \
+           echo "rm -f \"$(etcdir)/$$p\""; \
+           rm -f "$(etcdir)/$$p"; \
+         fi; \
+       done
+       rmdir "$(etcdir)/images/gnus" 2> /dev/null || true
+       @cd $(srcdir) \
+       && for p in images/smilies/*.pbm images/smilies/*.png \
+                   images/smilies/*.svg images/smilies/*.xbm \
+                   images/smilies/*.xpm \
+                   images/smilies/grayscale/*.pbm \
+                   images/smilies/grayscale/*.png \
+                   images/smilies/grayscale/*.svg \
+                   images/smilies/grayscale/*.xbm \
+                   images/smilies/grayscale/*.xpm \
+                   images/smilies/medium/*.pbm images/smilies/medium/*.png \
+                   images/smilies/medium/*.svg images/smilies/medium/*.xbm \
+                   images/smilies/medium/*.xpm; do \
+         if test -f $$p; then \
+           echo "rm -f \"$(etcdir)/$$p\""; \
+           rm -f "$(etcdir)/$$p"; \
+         fi; \
+       done
+       rmdir "$(etcdir)/images/smilies" 2> /dev/null || true
+       rmdir "$(etcdir)/images" 2> /dev/null || true
+
+Makefile: $(srcdir)/Makefile.in ../config.status
+       cd .. \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+clean:
+       rm -f *~
+
+distclean: clean
+       rm -f Makefile
+
+# 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/xemacs-packages/gnus/etc/gnus-tut.txt b/xemacs-packages/gnus/etc/gnus-tut.txt
new file mode 100644 (file)
index 0000000..9bb9a84
--- /dev/null
@@ -0,0 +1,314 @@
+From lars Thu Feb 23 23:20:38 1995
+From: larsi@gnus.org (ding)
+Date: Fri Feb 24 13:40:45 1995
+Subject: So you want to use the new Gnus
+Message-ID: <lars-doc1@eyesore.no>
+
+Actually, since you are reading this, chances are you are already
+using the new Gnus.  Congratulations.
+
+This entire newsgroup you are reading is, in fact, no real newsgroup
+at all, in the traditional sense.  It is an example of one of the
+"foreign" select methods that Gnus may use.
+
+The text you are now reading is stored in the "etc" directory with the
+rest of the Emacs sources.  You are using the "nndoc" backend for
+accessing it.  Scary, isn't it?
+
+This isn't the real documentation.  `M-x info', `m gnus <RET>' to read
+that.  This "newsgroup" is intended as a kinder, gentler way of getting
+people started.
+
+Gnus is a rewrite of GNUS 4.1, written by Masanobu Umeda.  The rewrite
+was done by moi, yours truly, your humble servant, Lars Magne
+Ingebrigtsen.  If you have a WWW browser, you can investigate to your
+heart's delight at <URL:http://www.gnus.org/> and
+<URL:http://quimby.gnus.org/lmi/>.
+
+;; Copyright (C) 1995, 2001-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+From lars Thu Feb 23 23:20:38 1995
+From: larsi@gnus.org (ding)
+Date: Fri Feb 24 13:40:45 1995
+Subject: Starting up
+Message-ID: <lars-doc2@eyesore.no>
+
+If you are having problems with Gnus not finding your server, you have
+to set `gnus-select-method'.  A "method" is a way of specifying *how*
+the news is to be found, and from *where*.
+
+Say you want to read news from you local, friendly nntp server
+"news.my.local.server".
+
+(setq gnus-select-method '(nntp "news.my.local.server"))
+
+Quite easy, huh?
+
+From the news spool:
+
+(setq gnus-select-method '(nnspool ""))
+
+From your mh-e spool:
+
+(setq gnus-select-method '(nnmh ""))
+
+There's a whole bunch of other methods for reading mail and news, see
+the "Foreign groups" article for that.
+
+
+From lars Thu Feb 23 23:20:38 1995
+From: larsi@gnus.org (ding)
+Date: Fri Feb 24 13:40:45 1995
+Subject: Where are all the groups, then?
+Message-ID: <lars-doc3@eyesore.no>
+
+If this is the first time you have used a newsreader, you won't have a
+.newsrc file.  This means that Gnus will think that all the newsgroups
+on the server are "new", and kill them all.
+
+If you have a .newsrc file, the new groups will be processed with the
+function in the `gnus-subscribe-newsgroup-method' variable, which is
+`gnus-subscribe-zombies' by default.
+
+This means that all the groups have been made into "zombies" - not
+quite dead, but not exactly alive, either.
+
+Jump back to the *Group* buffer, and type `A z' to list all the zombie
+groups.  Look though the list, and subscribe to the groups you want to
+read by pressing `u' on the one you think look interesting.
+
+If all the groups have been killed, type `A k' to list all the killed
+groups.  Subscribe to them the same way.
+
+When you are satisfied, press `S z' to kill all the zombie groups.
+
+Now you should have a nice list of all groups you are interested in.
+
+(If you later want to subscribe to more groups, press `A k' to
+list all the kill groups, and repeat.  You can also type `U' and be
+prompted for groups to subscribe to.)
+
+
+From lars Thu Feb 23 23:20:38 1995
+From: larsi@gnus.org (ding)
+Date: Fri Feb 24 13:40:45 1995
+Subject: I want to read my mail!
+Message-ID: <lars-doc4@eyesore.no>
+
+Yes, Virginia, you can read mail with Gnus.
+
+First you have to decide which mail backend you want to use.  You have
+nnml, which is a one-file-one-mail backend, which is quite nice, but
+apt to make your systems administrator go crazy and come after you
+with a shotgun.
+
+nnmbox uses a Unix mail box to store mail.  Nice, but slow.
+
+nnmh uses mh-e folders, which is also a one-file-one-mail thingie, but
+slower than nnml.  (It doesn't support NOV files.)
+
+So if you want to go with nnmbox, you can simply say:
+
+(setq gnus-secondary-select-methods '((nnmbox "")))
+
+(The same for the other methods, kind of.)
+
+You should also set `nnmail-split-methods' to something sensible:
+
+(setq nnmail-split-methods
+      '(("mail.junk" "From:.*Lars")
+       ("mail.misc "")))
+
+This will put all mail from me in you junk mail group, and the rest in
+"mail.misc".
+
+These groups will be subscribe the same way as the normal groups, so
+you will probably find them among the zombie groups after you set
+these variables and re-start Gnus.
+
+
+From lars Thu Feb 23 23:20:38 1995
+From: larsi@gnus.org (ding)
+Date: Fri Feb 24 13:40:45 1995
+Subject: Foreign newsgroups
+Message-ID: <lars-doc5@eyesore.no>
+
+These are groups that do not come from `gnus-select-method'.
+
+Say you want to read "alt.furniture.couches" from "news.funet.fi".  You
+can then either type `B news.funet.fi <RET>' to browse that server and
+subscribe to that group, or you can type
+`G m alt.furniture.couches<RET>nntp<RET>news.funet.fi<RET>', if you
+like to type a lot.
+
+If you want to read a directory as a newsgroup, you can create an
+nndir group, much the same way.  There's a shorthand for that,
+though.  If, for instance, you want to read the (ding) list archives,
+you could type `G d /ftp <RET>'.
+
+There's lots more to know about foreign groups, but you have to read
+the info pages to find out more.
+
+
+From lars Thu Feb 23 23:20:38 1995
+From: larsi@gnus.org (ding)
+Date: Fri Feb 24 13:40:45 1995
+Subject: Low level changes in GNUS, or, Wrong type argument: stringp, nil
+Message-ID: <lars-doc6@eyesore.no>
+
+Gnus really isn't GNUS, even though it looks like it.  If you scrape
+the surface, you'll find that most things have changed.
+
+This means that old code that relies on GNUS internals will fail.
+
+In particular, `gnus-newsrc-hashtb', `gnus-newsrc-assoc',
+`gnus-killed-list', the `nntp-header-' macros and the display formats
+have all changed.  If you have some code lying around that depend on
+these, or change these, you'll have to re-write your code.
+
+Old hilit19 code does not work at all.  In fact, you should probably
+remove all hilit code from all the Gnus hooks
+(`gnus-group-prepare-hook', `gnus-summary-prepare-hook' and
+`gnus-summary-article-hook').  (Well, at the very least the first
+two.)  Gnus provides various integrated functions for highlighting,
+which are both faster and more accurate.
+
+There is absolutely no chance, whatsoever, of getting Gnus to work
+with Emacs 18.  It won't even work on Emacsen older than Emacs
+20.7/XEmacs 21.1.  Upgrade your Emacs or die.
+
+
+From lars Thu Feb 23 23:20:38 1995
+From: larsi@gnus.org (ding)
+Date: Fri Feb 24 13:40:45 1995
+Subject: How do I re-scan my mail groups?
+Message-ID: <lars-doc8@eyesore.no>
+
+Reading the active file from the nntp server is a drag.
+
+Just press `M-g' on the mail groups, and they will be re-scanned.
+
+You can also re-scan all the mail groups by putting them on level 1
+(`S l 1'), and saying `1 g' to re-scan all level 1 groups.
+
+
+From lars Thu Feb 23 23:20:38 1995
+From: larsi@gnus.org (ding)
+Date: Fri Feb 24 13:40:45 1995
+Subject: How do I set up virtual newsgroups?
+Message-ID: <lars-doc9@eyesore.no>
+
+Virtual newsgroups are collections of other newsgroups.  Why people
+want this is beyond me, but here goes:
+
+Create the group by saying
+
+`G m my.virtual.newsgroup<RET>nnvirtual<RET>^rec\.aquaria\.*<RET>'
+
+This will create the group "nnvirtual:my.virtual.newsgroup", which
+will collect all articles from all the groups in the "rec.aquaria"
+hierarchy.
+
+If you want to edit the regular expression, just type `M-e' on the
+group line.
+
+Note that all the groups that are part of the virtual group have to be
+alive.  This means that the cannot, absolutely not, be zombie or
+killed.  They can be unsubscribed; that's no problem.
+
+You can combine groups from different servers in the same virtual
+newsgroup, something that may actually be useful.  Say you have the
+group "comp.headers" on the server "news.server.no" and the same group
+on "news.server.edu".  If people have posted articles with Distribution
+headers that stop propagation of their articles, combining these two
+newsgroups into one virtual newsgroup should give you a better view of
+what's going on.
+
+One caveat, though: The virtual group article numbers from the first
+source group (group A) will always be lower than the article numbers
+from the second (group B).  This means that Gnus will believe that
+articles from group A are older than articles from group B.  Threading
+will lessen these problems, but it might be a good idea to sort the
+threads over the date of the articles to get a correct feel for the
+flow of the groups:
+
+(setq gnus-thread-sort-functions '(gnus-thread-sort-by-date))
+
+If you only want this in virtual groups, you could say something along
+the lines of:
+
+(setq gnus-select-group-hook
+      (lambda ()
+       (if (eq 'nnvirtual (car (gnus-find-method-for-group
+                                 gnus-newsgroup-name)))
+           (progn
+             (make-local-variable 'gnus-thread-sort-functions)
+             (setq gnus-thread-sort-functions '(gnus-thread-sort-by-date))))))
+
+
+From lars Thu Feb 23 23:20:38 1995
+From: larsi@gnus.org (ding)
+Date: Fri Feb 24 13:40:45 1995
+Subject: Bugs & stuff
+Message-ID: <lars-doc7@eyesore.no>
+
+If you want to report a bug, please type `M-x gnus-bug'.  This will
+give me a precise overview of your Gnus and Emacs version numbers,
+along with a look at all Gnus variables you have changed.
+
+Do not expect a reply back, but your bug should be fixed in the next
+version.  If the bug persists, please re-submit your bug report.
+
+When a bug occurs, I need a recipe for how to trigger the bug.  You
+have to tell me exactly what you do to uncover the bug, and you should
+(setq debug-on-error t) and send me the backtrace along with the bug
+report.
+
+If I am not able to reproduce the bug, I won't be able to fix it.
+
+I would, of course, prefer that you locate the bug, fix it, and mail
+me the patches, but one can't have everything.
+
+If you have any questions on usage, the "ding@gnus.org" mailing list
+is where to post the questions.
+
+
+From fschmitt Sat Mar 22 18:13:00 2003
+From: faq@my.gnus.org (Gnus FAQ team)
+Date: Sat Mar 22 18:13:00 2003
+Subject: Gnus FAQ (Frequently Asked Questions)
+Message-ID: <lars-doc9@eyesore.no>
+
+The Gnus FAQ is distributed within the Gnus manual.  The home page of
+the Gnus FAQ is <URL:http://my.gnus.org/FAQ/>, where you can find the
+most recent version in HTML various other formats.
+
+To browse the FAQ now, put the cursor at the end of the following line
+and press `C-x C-e':
+
+  (info "(gnus)Frequently Asked Questions")
+
+On older XEmacs version, use:
+
+  (Info-goto-node "(gnus)Frequently Asked Questions")
+
+Or simply use RET or the middle mouse button, if the above is displayed
+as a clickable button.
diff --git a/xemacs-packages/gnus/etc/gnus/gnus-setup.ast b/xemacs-packages/gnus/etc/gnus/gnus-setup.ast
new file mode 100644 (file)
index 0000000..f2493b8
--- /dev/null
@@ -0,0 +1,50 @@
+@title Configuring Gnus for the first time
+
+@node What do you want to do with Gnus?
+
+@variable outbound (:radio ((item :tag "Send mail via sendmail" "sendmail") (item :tag "Send mail via SMTP" "smtp"))) "sendmail"
+
+@variable backends (:set ((item :tag "Read news via NNTP" "nntp") (item :tag "Read mail, store it locally" "nnml") (item :tag "Read mail and store it on an IMAP server" "nnimap"))) (list "nnml")
+@result primary-mail-selections (list backends outbound)
+
+@text
+Welcome to Gnus.  You need to tell us what you want to do with Gnus
+before we go on to specific configurations.
+
+Choose the tasks you want to set up: 
+@variable{backends}
+
+Choose the method Gnus will use to send mail: 
+@variable{outbound}
+
+@end text
+
+@next (member "nnml" backends) "Setting up local mail storage (nnml)"
+@next (member "nntp" backends) "Setting up a NNTP server"
+
+@node Setting up local mail storage (nnml)
+@variable mechanism (:radio ((item :tag "Get mail from your Unix mbox" "mbox") (item :tag "Use POP3 to retrieve mail" "pop3"))) "mbox"
+@result nnml-mechanism (list mechanism)
+@text
+You are setting up local mail storage, using the nnml backend in Gnus terms.
+
+Your mail can be downloaded into Gnus in several ways, choose one:
+@variable{mechanism}
+
+@end text
+
+@next 'finish
+
+@node Setting up a NNTP server
+
+@text
+TODO: this will be a real link.
+Run M-x assistant and use the news-server.ast file as input.
+@end text
+
+@next 'finish
+
+\f
+@c Local variables:
+@c mode: texinfo
+@c End:
diff --git a/xemacs-packages/gnus/etc/gnus/news-server.ast b/xemacs-packages/gnus/etc/gnus/news-server.ast
new file mode 100644 (file)
index 0000000..df0bab4
--- /dev/null
@@ -0,0 +1,63 @@
+@title Configuring Gnus for reading news
+
+
+@node Setting up the news server name and port number
+@variable server :string (or (gnus-getenv-nntpserver) "your-server-here")
+@variable port :number 119
+@validate (or (assistant-validate-connect-to-server server port) (y-or-n-p "Do you want to use the server anyway, although you can't confirm it's valid?"))
+@result gnus-select-method (list 'nntp server (list 'nntp-server port))
+@text
+Usenet news is usually read from your Internet service provider's news
+server.  If you don't know the name of this server, contact your ISP.
+
+As a guess, the name of the server might be news.yourisp.com.
+
+Server name: @variable{server}
+Port number: @variable{port}
+
+@end text
+@next t "User name and password"
+
+@node User name and password
+@type interstitial
+@next 
+(if (assistant-password-required-p)
+    "Enter user name and password"
+  "Want user name and password?")
+@end next
+
+
+@node Want user name and password?
+@variable passwordp (:radio ((item "Yes") (item "No"))) "No"
+@text
+Some news servers require that you enter a user name and a password.
+It doesn't look like your news server is one of them.
+
+Do you want to enter user name and password anyway?
+
+@variable{passwordp}
+
+@end text
+
+@next (equal passwordp "No") finish
+@next (not (equal passwordp "No")) "Enter user name and password"
+
+
+@node Enter user name and password
+@variable user-name :string (user-login-name)
+@variable password :password (or (assistant-authinfo-data server port 'password) "")
+@text
+
+It looks like your news server requires you to enter a user name
+and a password:
+
+User name: @variable{user-name}
+Password: @variable{user-name}
+
+@end text
+
+@c Local variables:
+@c mode: texinfo
+@c End:
+
+@c arch tag is missing
diff --git a/xemacs-packages/gnus/etc/images/GNUS-README b/xemacs-packages/gnus/etc/images/GNUS-README
new file mode 100644 (file)
index 0000000..587c18e
--- /dev/null
@@ -0,0 +1,113 @@
+CONTENTS
+
+This file (GNUS-NEWS) contains some Gnus specific informations or other
+information that not relevant for Emacs.  For information relevant to Emacs,
+see README, smilies/README, mail/README, and gnus/README.  Don't modify these
+files in Gnus' repository unless the change should also be included in the
+Emacs incarnation of the files.
+
+
+COPYRIGHT AND LICENSE INFORMATION FOR IMAGE FILES
+
+See README, smilies/README, mail/README and gnus/README.
+
+
+ORIGIN OF THE IMAGE FILES
+
+The following icons are from GNOME 2.6:
+
+    attach.xpm (stock_attach)
+    connect.xpm (stock_connect)
+    contact.xpm (stock_contact)
+    delete.xpm (stock_delete)
+    describe.xpm (stock_properties)
+    disconnect.xpm (stock_disconnect)
+    exit.xpm (stock_exit)
+    lock-broken.xpm (stock_lock_broken)
+    lock-ok.xpm (stock_lock_ok)
+    lock.xpm (stock_lock)
+    next-page.xpm (stock_next-page)
+    refresh.xpm (stock_refresh)
+    sort-ascending.xpm (stock_sort-ascending)
+    sort-column-ascending.xpm (stock_sort-column-ascending)
+    sort-criteria.xpm (stock_sort-criteria)
+    sort-descending.xpm (stock_sort-descending)
+    sort-row-ascending.xpm (stock_sort-row-ascending)
+
+    gnus/toggle-subscription.xpm (stock_task-recurring)
+
+    mail/compose.xpm (stock_mail-compose)
+    mail/copy.xpm (stock_mail-copy)
+    mail/forward.xpm (stock_mail-forward)
+    mail/inbox.xpm (stock_inbox)
+    mail/move.xpm (stock_mail-move)
+    mail/not-spam.xpm (stock_not-spam)
+    mail/outbox.xpm (stock_outbox)
+    mail/reply-all.xpm (stock_mail-reply-to-all)
+    mail/reply.xpm (stock_mail-reply)
+    mail/save-draft.xpm (stock_mail-handling)
+    mail/send.xpm (stock_mail-send)
+    mail/spam.xpm (stock_spam)
+
+
+The following icons were contributed by Adam Sjøgren <asjo@koldfront.dk>:
+
+    mail/preview.xpm (combining stock_mail and stock_zoom)
+    mail/save.xpm    (combining stock_mail, stock_save and stock_convert) 
+
+
+The folling icon are duplicated from Emacs 22.  They are either not present in
+Emacs 21 or look different there.
+
+    cancel.xpm
+    close.xpm
+    copy.xpm
+    cut.xpm
+    diropen.xpm
+    help.xpm
+    home.xpm
+    index.xpm
+    jump-to.xpm
+    left-arrow.xpm
+    new.xpm
+    next-node.xpm
+    open.xpm
+    paste.xpm
+    preferences.xpm
+    prev-node.xpm
+    print.xpm
+    redo.xpm
+    right-arrow.xpm
+    save.xpm
+    saveas.xpm
+    search.xpm
+    separator.xpm
+    spell.xpm
+
+You might want to use the following code to get Gnome icons in Emacs 21:
+
+  ;; Only for Emacs 21:
+  (when (and (not (featurep 'xemacs))
+          (not (boundp 'image-load-path))
+          tool-bar-mode)
+    (push "/path/to/etc/images/" image-load-path)
+    (setq tool-bar-map (make-sparse-keymap))
+    (clear-image-cache)
+    (tool-bar-setup))
+
+
+CONVERSION OF PNG FILES TO XPM
+
+The GNOME's stock_*.png files were converted to XPM using the following GIMP
+script:
+
+;; -*- scheme -*-
+;; Put this file in ~/.gimp-*/scripts/
+;; gimp -i -b '(rs-save-as-xpm "foo.png" "foo.xpm" 127)'  '(gimp-quit 0)'
+(define (rs-save-as-xpm filename filename2 threshold)
+  (let* ((image (car (gimp-file-load RUN-NONINTERACTIVE filename filename)))
+        (drawable (car (gimp-image-get-active-layer image))))
+    (file-xpm-save RUN-NONINTERACTIVE image drawable
+                  filename2 filename2 threshold)
+    (gimp-image-delete image)))
+;; end
diff --git a/xemacs-packages/gnus/etc/images/README b/xemacs-packages/gnus/etc/images/README
new file mode 100644 (file)
index 0000000..94edfba
--- /dev/null
@@ -0,0 +1,99 @@
+* The default GTK icons were not overridden by the GNOME theme due to
+  a bug which was fixed in GNOME 2.15. Once GNOME 2.16 is in wide
+  circulation, the GTK icons should be replaced with the equivalent
+  GNOME icons.
+
+* Recipe for Creating PBM Versions
+
+1. Edit .xpm image in GIMP.
+2. Image > Mode > Indexed. Check Use Black/White Palette and No
+   Color Dithering.
+3. File > Save As file.xbm.
+4. Run xbmtopbm < file.xbm > file.pbm.
+
+Thanks to jan.h.d@swipnet.se for the help.
+
+
+COPYRIGHT AND LICENSE INFORMATION FOR IMAGE FILES
+
+* The following icons are part of Emacs.  All are licensed under the
+  GNU General Public License version 3 (see COPYING) or later.
+  The xpm and svg files contain copyright and license information, but
+  it is reproduced here for convenience.
+
+File: mh-logo.xpm
+  Author: Satyaki Das
+  Copyright (C) 2003-2016 Free Software Foundation, Inc.
+
+Files: gnus.pbm
+  Author: Luis Fernandes <elf@ee.ryerson.ca>
+  Copyright (C) 2001-2016 Free Software Foundation, Inc.
+
+Files: splash.png, splash.svg, splash.pbm, splash.xpm
+  Author: Francesc Rocher <francesc.rocher@gmail.com>
+  Copyright (C) 2008-2016 Free Software Foundation, Inc.
+
+Files: checked.xpm, unchecked.xpm
+  Author: Chong Yidong <cyd@stupidchicken.com>
+  Copyright (C) 2010-2016 Free Software Foundation, Inc.
+
+
+* The following icons are from GTK+ 2.x. They are not part of Emacs, but
+are distributed and used by Emacs.  They are licensed under the
+GNU Library General Public License version 2 or later.  See the source
+of the gtk+ package for more information.
+
+  close.xpm copy.xpm cut.xpm help.xpm home.xpm index.xpm info.pbm
+  info.xpm jump-to.xpm left-arrow.xpm new.xpm open.xpm paste.xpm
+  preferences.xpm print.xpm refresh.xpm right-arrow.xpm save.xpm
+  saveas.xpm search.xpm sort-ascending.xpm sort-descending.xpm
+  spell.xpm undo.xpm up-arrow.xpm
+
+  back-arrow.xpm and fwd-arrow.xpm are slightly modified undo and redo.
+  diropen.xpm is file-manager.png from Gnome hicolor theme.
+
+
+* The following icons are from GNOME 2.x. They are not part of Emacs,
+but are distributed and used by Emacs.  They are licensed under the
+GNU General Public License version 2 or later.  See the source of
+the gnome-icons-theme package for more information.
+
+Emacs images and their source in the GNOME icons stock/ directory:
+
+  attach.xpm                document/stock_attach
+  bookmark_add.xpm          actions/bookmark_add
+  cancel.xpm                slightly modified generic/stock_stop
+  connect.xpm               net/stock_connect
+  contact.xpm               net/stock_contact
+  data-save.xpm             data/stock_data-save
+  delete.xpm                generic/stock_delete
+  describe.xpm              generic/stock_properties
+  disconnect.xpm            net/stock_disconnect
+  exit.xpm                  generic/stock_exit
+  lock-broken.xpm           data/stock_lock-broken
+  lock-ok.xpm               data/stock_lock-ok
+  lock.xpm                  data/stock_lock
+  redo.xpm                  generic/stock_redo
+  search-replace.xpm        slightly modified generic/stock_search-and-replace
+  next-page.xpm             navigation/stock_next-page
+  refresh.xpm               generic/stock_refresh
+  separator.xpm             ?
+  show.xpm                  slightly modified document/stock_new
+  sort-ascending.xpm        slightly modified data/stock_sort-ascending
+  sort-column-ascending.xpm data/stock_sort-column-ascending
+  sort-criteria.xpm         data/stock_sort-criteria
+  sort-descending.xpm       slightly modified data/stock_sort-descending
+  sort-row-ascending.xpm    data/stock_sort-row-ascending
+  zoom-in.xpm               navigation/stock_zoom-in
+  zoom-out.xpm              navigation/stock_zoom-out
+
+  next-node.xpm and prev-node.xpm are from gthumb version 2.0 (part of
+  GNOME 2.x) where they are called next-image-24.png and prev-image-24.png.
+  up-node.xpm is just next-node.xpm rotated 90 degrees.
+
+  Some icons in the mail/ and gnus/ subdirectories are also taken
+  from this source (see their separate README files).
+
+The images in the low-color/ subdirectory are low-color versions of
+the files of the same name in this directory, and are subject to the
+same conditions.
diff --git a/xemacs-packages/gnus/etc/images/attach.xpm b/xemacs-packages/gnus/etc/images/attach.xpm
new file mode 100644 (file)
index 0000000..e3298c9
--- /dev/null
@@ -0,0 +1,126 @@
+/* XPM */
+static char * stock_attach_xpm[] = {
+"24 24 99 2",
+"      c None",
+".     c #000000",
+"+     c #010101",
+"@     c #515151",
+"#     c #9A9A9A",
+"$     c #CFCFCF",
+"%     c #6F6F6F",
+"&     c #464646",
+"*     c #A5A5A5",
+"=     c #E2E2E2",
+"-     c #FFFFFF",
+";     c #F6F6F6",
+">     c #8A8A8A",
+",     c #393939",
+"'     c #1C1C1C",
+")     c #8B8B8B",
+"!     c #E6E6E6",
+"~     c #EEEEEE",
+"{     c #E1E1E1",
+"]     c #F8F8F8",
+"^     c #F7F7F7",
+"/     c #CCCCCC",
+"(     c #565656",
+"_     c #3E3E3E",
+":     c #818181",
+"<     c #D4D4D4",
+"[     c #E7E7E7",
+"}     c #D7D7D7",
+"|     c #FAFAFA",
+"1     c #F9F9F9",
+"2     c #C2C2C2",
+"3     c #CBCBCB",
+"4     c #F5F5F5",
+"5     c #D9D9D9",
+"6     c #030303",
+"7     c #545454",
+"8     c #DEDEDE",
+"9     c #B3B3B3",
+"0     c #797979",
+"a     c #F4F4F4",
+"b     c #9D9D9D",
+"c     c #282828",
+"d     c #FBFBFB",
+"e     c #A6A6A6",
+"f     c #C5C5C5",
+"g     c #F0F0F0",
+"h     c #CACACA",
+"i     c #C7C7C7",
+"j     c #F2F2F2",
+"k     c #CECECE",
+"l     c #C4C4C4",
+"m     c #D5D5D5",
+"n     c #DADADA",
+"o     c #F3F3F3",
+"p     c #858585",
+"q     c #BEBEBE",
+"r     c #D3D3D3",
+"s     c #DCDCDC",
+"t     c #9C9C9C",
+"u     c #484848",
+"v     c #A7A7A7",
+"w     c #D6D6D6",
+"x     c #C8C8C8",
+"y     c #C6C6C6",
+"z     c #4C4C4C",
+"A     c #EAEAEA",
+"B     c #E5E5E5",
+"C     c #D8D8D8",
+"D     c #ADADAD",
+"E     c #BCBCBC",
+"F     c #E0E0E0",
+"G     c #F1F1F1",
+"H     c #909090",
+"I     c #686868",
+"J     c #A2A2A2",
+"K     c #C0C0C0",
+"L     c #C1C1C1",
+"M     c #787878",
+"N     c #AEAEAE",
+"O     c #151515",
+"P     c #D0D0D0",
+"Q     c #979797",
+"R     c #727272",
+"S     c #4A4A4A",
+"T     c #ECECEC",
+"U     c #ACACAC",
+"V     c #BABABA",
+"W     c #DDDDDD",
+"X     c #DBDBDB",
+"Y     c #B1B1B1",
+"Z     c #232323",
+"`     c #696969",
+" .    c #B7B7B7",
+"..    c #828282",
+"+.    c #404040",
+"@.    c #969696",
+"#.    c #323232",
+"$.    c #E8E8E8",
+"%.    c #121212",
+"                                                ",
+"                  . . . . .                     ",
+"                .           .   . .             ",
+"                .         + @ # $ % .           ",
+"                .   . & * = - - ; > ,           ",
+"              . ' ) ! ~ { - ] ^ ; / (           ",
+"        . _ : < ' [ } | 1 ] 2 3 4 5 : .         ",
+"    6 7 ! - - - . } 8 9 0 . = ; 4 a b c         ",
+"  . ; - - | | d . e f g ] . = 2 h a i (         ",
+"  . j ] 1 k l f . m 1 ] ] . 9 n a o o 0 .       ",
+"    p - ] q 1 1 . r s 2 2 . = 4 a o j t c       ",
+"    u - ^ ^ ] ] . v w ^ ; . = a l x j y z       ",
+"    . A - ; q 2 . B C ; 4 . D E A F G A H .     ",
+"      I - 4 ; ; J . K L . M w o j G G m N O     ",
+"      , - a 4 4 n # . . 0 w j j G w P Q R S     ",
+"      . T - a U V W o k X T } w Y : ( Z .       ",
+"        ` - o o o o j j }  ...+.Z . .           ",
+"        c - o j j } q @.#.Z .                   ",
+"        . ! $./ # +.Z . .                       ",
+"          , .., %..                             ",
+"          . .                                   ",
+"                                                ",
+"                                                ",
+"                                                "};
diff --git a/xemacs-packages/gnus/etc/images/cancel.xpm b/xemacs-packages/gnus/etc/images/cancel.xpm
new file mode 100644 (file)
index 0000000..1a9c80a
--- /dev/null
@@ -0,0 +1,35 @@
+/* XPM */
+static char *magick[] = {
+/* columns rows colors chars-per-pixel */
+"24 24 5 1",
+"  c #01c601c601c6",
+". c Gray40",
+"X c #a527a527a527",
+"o c #da22da22da22",
+"O c None",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOO       OOOOOOOOO",
+"OOOOOO  XXooXX.  OOOOOOO",
+"OOOOO XooooooooX. OOOOOO",
+"OOOOO oooooooooo. OOOOOO",
+"OOOO Xooo ooo XoX. OOOOO",
+"OOOO Xoo   o   XXX OOOOO",
+"OOOO oooo     XoXX OOOOO",
+"OOOO Xoooo   ooXXX OOOOO",
+"OOOO Xooo     OXX. OOOOO",
+"OOOO Xoo   o   XX. OOOOO",
+"OOOO .Xoo ooX XX.. OOOOO",
+"OOOOO XXOoXoXXX.. OOOOOO",
+"OOOOO XXXXXXXXX.. OOOOOO",
+"OOOOOO  XXXX...  OOOOOOO",
+"OOOOOOOO       OOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOO"
+};
diff --git a/xemacs-packages/gnus/etc/images/close.xpm b/xemacs-packages/gnus/etc/images/close.xpm
new file mode 100644 (file)
index 0000000..498843b
--- /dev/null
@@ -0,0 +1,29 @@
+/* XPM */
+static char * close_xpm[] = {
+"24 24 2 1",
+"      c None",
+".     c #000000",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"       .      .         ",
+"        .    ...        ",
+"        ..  ....        ",
+"         .. ...         ",
+"         .....          ",
+"          ...           ",
+"         .....          ",
+"        .......         ",
+"       ...  ....        ",
+"      ...    ....       ",
+"     ...      ..        ",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/connect.xpm b/xemacs-packages/gnus/etc/images/connect.xpm
new file mode 100644 (file)
index 0000000..f58e8b3
--- /dev/null
@@ -0,0 +1,85 @@
+/* XPM */
+static char * stock_connect_xpm[] = {
+"24 24 58 1",
+"      c None",
+".     c #000000",
+"+     c #989389",
+"@     c #807D74",
+"#     c #C6C2BA",
+"$     c #34332D",
+"%     c #B7B3AA",
+"&     c #C4C2BD",
+"*     c #EAE8E3",
+"=     c #9C978D",
+"-     c #BCB9B2",
+";     c #363433",
+">     c #E2E1DD",
+",     c #F0EFEC",
+"'     c #AAA7A0",
+")     c #F0EEEB",
+"!     c #B2B0AB",
+"~     c #F9F9F8",
+"{     c #C5C3BD",
+"]     c #0F0F0D",
+"^     c #F2F0ED",
+"/     c #EBEAE6",
+"(     c #8A857B",
+"_     c #ECEBE8",
+":     c #EEECEA",
+"<     c #9F9C93",
+"[     c #F3F2F0",
+"}     c #E8E7E4",
+"|     c #E3E1DD",
+"1     c #78756B",
+"2     c #BEBBB5",
+"3     c #B3B1AA",
+"4     c #7D786E",
+"5     c #E1DFDB",
+"6     c #D1D0CC",
+"7     c #938E84",
+"8     c #C8C5BF",
+"9     c #A7A298",
+"0     c #010101",
+"a     c #8C8981",
+"b     c #A6A29B",
+"c     c #726D63",
+"d     c #CECAC3",
+"e     c #A7A49E",
+"f     c #7E7A70",
+"g     c #A09D94",
+"h     c #817D73",
+"i     c #6C685E",
+"j     c #3C3933",
+"k     c #8B877E",
+"l     c #706C62",
+"m     c #B1ADA4",
+"n     c #97938A",
+"o     c #625E54",
+"p     c #6A655B",
+"q     c #37342D",
+"r     c #646056",
+"s     c #8B877D",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"          .. ..         ",
+"        ..+@.#@..       ",
+"       $%&*@.*@=-;      ",
+"      .>,'*@.)@!~{]     ",
+"......@>,'*@.)@!~{@.....",
+"*******^/(_@.:@<[}|*****",
+"@@@@@1123451.6@789@@@@@@",
+".....01abcd1.e@fghi.....",
+"      ]abcd1.e@fgh]     ",
+"      ]jklmi.n@opq.     ",
+"        ]]+r.s@..       ",
+"          ]] ].         ",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/contact.pbm b/xemacs-packages/gnus/etc/images/contact.pbm
new file mode 100644 (file)
index 0000000..64a50b5
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/contact.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/contact.xpm b/xemacs-packages/gnus/etc/images/contact.xpm
new file mode 100644 (file)
index 0000000..b3cf61f
--- /dev/null
@@ -0,0 +1,129 @@
+/* XPM */
+static char * stock_contact_xpm[] = {
+"24 24 102 2",
+"      c None",
+".     c #000000",
+"+     c #E3E1DE",
+"@     c #ECEBE7",
+"#     c #F0EEEB",
+"$     c #D2CFC9",
+"%     c #81817F",
+"&     c #4C4C4A",
+"*     c #ECEAE6",
+"=     c #ECEAE5",
+"-     c #EBE9E5",
+";     c #D2CEC8",
+">     c #D9C7B8",
+",     c #D9C7B9",
+"'     c #D8C5B8",
+")     c #D1C0B3",
+"!     c #D6C5B7",
+"~     c #EBEAE5",
+"{     c #D3D0C9",
+"]     c #CDBCAC",
+"^     c #AFA093",
+"/     c #3A3531",
+"(     c #443F3A",
+"_     c #AE9F93",
+":     c #CBBAAB",
+"<     c #4E4E4C",
+"[     c #595957",
+"}     c #595857",
+"|     c #7D7C7A",
+"1     c #D3D0CA",
+"2     c #C6B5A4",
+"3     c #3D3833",
+"4     c #433D37",
+"5     c #C2B0A2",
+"6     c #D4D1CA",
+"7     c #B0A08E",
+"8     c #261F18",
+"9     c #D37D1E",
+"0     c #D68021",
+"a     c #B26616",
+"b     c #27241F",
+"c     c #9C8E7F",
+"d     c #EAE9E5",
+"e     c #A29281",
+"f     c #2E2012",
+"g     c #CC751A",
+"h     c #CC761A",
+"i     c #BF6C16",
+"j     c #24211C",
+"k     c #8E8170",
+"l     c #EAE8E3",
+"m     c #E9E8E3",
+"n     c #E9E7E3",
+"o     c #8E7F6C",
+"p     c #221E17",
+"q     c #C56D14",
+"r     c #7D450D",
+"s     c #AF5F11",
+"t     c #221E19",
+"u     c #7F7260",
+"v     c #E9E7E2",
+"w     c #E8E6E1",
+"x     c #E7E5E1",
+"y     c #E7E5E0",
+"z     c #D5D1CB",
+"A     c #3E372C",
+"B     c #1C1F1F",
+"C     c #301B06",
+"D     c #542D07",
+"E     c #291B0E",
+"F     c #151412",
+"G     c #473F33",
+"H     c #E8E6E2",
+"I     c #546371",
+"J     c #849CB4",
+"K     c #56687C",
+"L     c #343332",
+"M     c #495868",
+"N     c #566D85",
+"O     c #293643",
+"P     c #E6E4DF",
+"Q     c #E5E4DE",
+"R     c #EEEDE9",
+"S     c #7B95AF",
+"T     c #7B96B0",
+"U     c #68819B",
+"V     c #8999AA",
+"W     c #5A7088",
+"X     c #607A96",
+"Y     c #5B7691",
+"Z     c #E5E3DE",
+"`     c #4B4A48",
+" .    c #757471",
+"..    c #E6E3DE",
+"+.    c #3B3A39",
+"@.    c #747371",
+"#.    c #D3CFC8",
+"$.    c #E2E1DD",
+"%.    c #E7E4E0",
+"&.    c #D2CFC8",
+"*.    c #D1D0CA",
+"=.    c #C2C0B9",
+"                                                ",
+"                                                ",
+"                                                ",
+"    . . . . . . . . . . . . . . . . . . . .     ",
+"  . + @ # # # # # # # # # # # # # # # # # $ .   ",
+"  . # % . . . . . . . & * = - - - - - - - ; .   ",
+"  . # . > , ' ) ! > , . * * ~ ~ ~ ~ - - ~ { .   ",
+"  . # . ] ^ / . ( _ : . * < [ ~ } } | - ~ 1 .   ",
+"  . # . 2 3 . . . 4 5 . * * ~ ~ - - - - - 6 .   ",
+"  . # . 7 8 9 0 a b c . * [ < | [ - } | d 6 .   ",
+"  . # . e f g h i j k . * * l l m n n n n 6 .   ",
+"  . # . o p q r s t u . v v w w w x y y y z .   ",
+"  . # . A B C D E F G . H H y y y y y y y 6 .   ",
+"  . # . I J K L M N O . y y P P P P P P Q { .   ",
+"  . R . S T U V W X Y . y y P P P P Z Z Z { .   ",
+"  . d ` . . . . . . . ` y y  ...+.+.Z @.Z #..   ",
+"  . $.y y y y y y y y y %.P Z Z Z Z Z Z Z &..   ",
+"  . *.6 z 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 =..   ",
+"    . . . . . . . . . . . . . . . . . . . . .   ",
+"                                                ",
+"                                                ",
+"                                                ",
+"                                                ",
+"                                                "};
diff --git a/xemacs-packages/gnus/etc/images/copy.xpm b/xemacs-packages/gnus/etc/images/copy.xpm
new file mode 100644 (file)
index 0000000..750aebb
--- /dev/null
@@ -0,0 +1,53 @@
+/* XPM */
+static char * copy_xpm[] = {
+"24 24 26 1",
+"      c None",
+".     c #000000",
+"+     c #B4B4B4",
+"@     c #F8F8F8",
+"#     c #F6F6F6",
+"$     c #C3C3C3",
+"%     c #E9E9E9",
+"&     c #989898",
+"*     c #828282",
+"=     c #8A8A8A",
+"-     c #E8E8E8",
+";     c #636363",
+">     c #5A5A5A",
+",     c #6B6B6B",
+"'     c #B3B3B3",
+")     c #FFFFFF",
+"!     c #D6D6D6",
+"~     c #818181",
+"{     c #A7A7A7",
+"]     c #8F8F8F",
+"^     c #C6C6C6",
+"/     c #808080",
+"(     c #E7E7E7",
+"_     c #6D6D6D",
+":     c #767676",
+"<     c #F5F5F5",
+"                        ",
+"                        ",
+"                        ",
+".............           ",
+".+@@@@@@@@@#$.          ",
+".@%%%%%%%%%%%.          ",
+".@&**=%+*%*+%.          ",
+".@%%%%%%%%---.          ",
+".@;>%,*+-............   ",
+".@%%%%%%.'))))))))))!.  ",
+".@&**%*~.)))))))))))).  ",
+".@%%%%%-.){]]&)^])]^).  ",
+".@;>>%,/.)))))))))))).  ",
+".@%%%%%(.)_;):]^)^])).  ",
+".@&**%*~.)))))))))))).  ",
+".<%%%%%-.){]])]]^)&]).  ",
+".$%%%%%-.)))))))))))).  ",
+" ........)_;;):]^)^]).  ",
+"        .)))))))))))).  ",
+"        .){]])]]^)&]).  ",
+"        .)))))))))))).  ",
+"        .!))))))))))!.  ",
+"        ..............  ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/cut.xpm b/xemacs-packages/gnus/etc/images/cut.xpm
new file mode 100644 (file)
index 0000000..3f8e71d
--- /dev/null
@@ -0,0 +1,67 @@
+/* XPM */
+static char * cut_xpm[] = {
+"24 24 40 1",
+"      c None",
+".     c #000000",
+"+     c #C9C7C2",
+"@     c #E6E4E0",
+"#     c #EFEEED",
+"$     c #494946",
+"%     c #73726E",
+"&     c #F0EEED",
+"*     c #7F7D75",
+"=     c #F2F1EF",
+"-     c #D2CFC8",
+";     c #E7E7E4",
+">     c #BAB5AB",
+",     c #565653",
+"'     c #EDECE9",
+")     c #A4A097",
+"!     c #817F7E",
+"~     c #4E4C48",
+"{     c #F6F5F4",
+"]     c #474541",
+"^     c #EFEEEC",
+"/     c #8C8B8A",
+"(     c #F3F2F0",
+"_     c #77746D",
+":     c #323232",
+"<     c #EBEBEA",
+"[     c #605D58",
+"}     c #F5F4F3",
+"|     c #CECCC7",
+"1     c #363634",
+"2     c #6F6E6D",
+"3     c #BEBDBB",
+"4     c #EAE7E4",
+"5     c #B8B5B1",
+"6     c #474747",
+"7     c #DAD8D4",
+"8     c #9B9996",
+"9     c #161615",
+"0     c #6D6B6A",
+"a     c #3A3837",
+"                        ",
+"                        ",
+"      .        .        ",
+"      .        .        ",
+"     .+.      .@.       ",
+"     .#$      %@.       ",
+"     .&*.    .=-.       ",
+"     .;>,    %').       ",
+"      !#*.  .=-~        ",
+"      .{>]  ~^>.        ",
+"       /(_.:<-[         ",
+"       .}|123>.         ",
+"        .456>.          ",
+"         .78..          ",
+"         .90a.          ",
+"     .............      ",
+"     . ...  ... ...     ",
+"    ..  ..   ..  ..     ",
+"    .    .   .    .     ",
+"    ..  ..   ..  ..     ",
+"     ....     .. .      ",
+"     ....     ....      ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/delete.pbm b/xemacs-packages/gnus/etc/images/delete.pbm
new file mode 100644 (file)
index 0000000..886be51
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/delete.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/delete.xpm b/xemacs-packages/gnus/etc/images/delete.xpm
new file mode 100644 (file)
index 0000000..e2d1d90
--- /dev/null
@@ -0,0 +1,270 @@
+/* XPM */
+static char * stock_delete_xpm[] = {
+"24 24 243 2",
+"      c None",
+".     c #000000",
+"+     c #1C1C1C",
+"@     c #767676",
+"#     c #E6E6E6",
+"$     c #D3D3D3",
+"%     c #C3C3C3",
+"&     c #909090",
+"*     c #494949",
+"=     c #48473D",
+"-     c #BAB8A6",
+";     c #E2E2DF",
+">     c #F1F1F0",
+",     c #EAE9E6",
+"'     c #F2F2EE",
+")     c #EBEAE5",
+"!     c #C1C0B5",
+"~     c #57564A",
+"{     c #525146",
+"]     c #A8A68F",
+"^     c #BDBBA1",
+"/     c #C0BEA3",
+"(     c #A3A18A",
+"_     c #6D6C5C",
+":     c #7C7C72",
+"<     c #4C4C49",
+"[     c #45453F",
+"}     c #44433A",
+"|     c #6F6F67",
+"1     c #C6C5B9",
+"2     c #B6B59B",
+"3     c #6D6C5D",
+"4     c #B3B19B",
+"5     c #A7A68E",
+"6     c #908F7A",
+"7     c #AAA993",
+"8     c #CCCBB5",
+"9     c #D0CEBA",
+"0     c #D5D3C1",
+"a     c #AEADA3",
+"b     c #94938A",
+"c     c #454442",
+"d     c #232321",
+"e     c #353431",
+"f     c #292823",
+"g     c #1E1E1A",
+"h     c #535246",
+"i     c #ADAC93",
+"j     c #929189",
+"k     c #C2C1AF",
+"l     c #B1AF96",
+"m     c #ACAA92",
+"n     c #93927D",
+"o     c #080808",
+"p     c #D1D0C1",
+"q     c #D6D5C4",
+"r     c #DFDED1",
+"s     c #CECDC0",
+"t     c #ACACA6",
+"u     c #908F8A",
+"v     c #7E7D77",
+"w     c #5C5C55",
+"x     c #47463E",
+"y     c #656456",
+"z     c #777665",
+"A     c #807E6F",
+"B     c #BEBDA7",
+"C     c #B5B39A",
+"D     c #A19F88",
+"E     c #D9D8CC",
+"F     c #F6F5F2",
+"G     c #DBDAD1",
+"H     c #DAD9CE",
+"I     c #E5E4D9",
+"J     c #D0CFC3",
+"K     c #D3D3C9",
+"L     c #CAC9BC",
+"M     c #B7B6A6",
+"N     c #B8B6A1",
+"O     c #B0AF96",
+"P     c #B9B89D",
+"Q     c #B9B79D",
+"R     c #B8B69C",
+"S     c #C4C2A9",
+"T     c #AFAD97",
+"U     c #8B8976",
+"V     c #AAA998",
+"W     c #B6B6B2",
+"X     c #F9F9F7",
+"Y     c #FAFAF8",
+"Z     c #F4F4F0",
+"`     c #E2E1DA",
+" .    c #D9D9CE",
+"..    c #DBDACF",
+"+.    c #D3D1BE",
+"@.    c #C5C4AC",
+"#.    c #D6D5C3",
+"$.    c #CDCCBF",
+"%.    c #BBBAAD",
+"&.    c #7C7A69",
+"*.    c #717060",
+"=.    c #131313",
+"-.    c #999882",
+";.    c #AFAE9D",
+">.    c #C3C3BE",
+",.    c #DEDEDC",
+"'.    c #E9E9E8",
+").    c #FBFBFA",
+"!.    c #FDFDFC",
+"~.    c #FDFDFD",
+"{.    c #FCFBFA",
+"].    c #F2F2EF",
+"^.    c #EAE9E3",
+"/.    c #C0BFB1",
+"(.    c #959484",
+"_.    c #787766",
+":.    c #6E6D5D",
+"<.    c #5B5B4D",
+"[.    c #5D5C4F",
+"}.    c #A3A293",
+"|.    c #B8B7A6",
+"1.    c #D8D7D0",
+"2.    c #DBDBD4",
+"3.    c #D3D2CA",
+"4.    c #C8C8C3",
+"5.    c #C6C5BD",
+"6.    c #BDBCAD",
+"7.    c #BAB8A8",
+"8.    c #9F9E8B",
+"9.    c #8E8C78",
+"0.    c #8C8B77",
+"a.    c #7A7968",
+"b.    c #6C6B5D",
+"c.    c #4E4D45",
+"d.    c #424242",
+"e.    c #7B7B73",
+"f.    c #9F9F96",
+"g.    c #D2D1C7",
+"h.    c #DCDBD2",
+"i.    c #CCCBBE",
+"j.    c #D1D0C2",
+"k.    c #C4C3B6",
+"l.    c #9A9883",
+"m.    c #807F6D",
+"n.    c #7D7C6B",
+"o.    c #6A695E",
+"p.    c #40403E",
+"q.    c #37372D",
+"r.    c #0F0F0F",
+"s.    c #383734",
+"t.    c #787875",
+"u.    c #999893",
+"v.    c #8A897E",
+"w.    c #B3B2A4",
+"x.    c #AAAA9E",
+"y.    c #878673",
+"z.    c #8F8D79",
+"A.    c #626155",
+"B.    c #545451",
+"C.    c #31312E",
+"D.    c #2B2B23",
+"E.    c #71715D",
+"F.    c #57574B",
+"G.    c #42423A",
+"H.    c #262620",
+"I.    c #212121",
+"J.    c #1B1B1B",
+"K.    c #242424",
+"L.    c #161613",
+"M.    c #2A2A22",
+"N.    c #303027",
+"O.    c #3F3F34",
+"P.    c #7A7A65",
+"Q.    c #5B5B51",
+"R.    c #858576",
+"S.    c #76766B",
+"T.    c #98988E",
+"U.    c #75756B",
+"V.    c #515146",
+"W.    c #7F7F74",
+"X.    c #6A6A58",
+"Y.    c #404035",
+"Z.    c #626251",
+"`.    c #545445",
+" +    c #3E3E33",
+".+    c #555546",
+"++    c #34342B",
+"@+    c #515143",
+"#+    c #85856E",
+"$+    c #5D5D54",
+"%+    c #919182",
+"&+    c #828278",
+"*+    c #AAAAA3",
+"=+    c #7A7A71",
+"-+    c #4E4E45",
+";+    c #8A8A80",
+">+    c #7C7C6D",
+",+    c #424237",
+"'+    c #606052",
+")+    c #5A5A4A",
+"!+    c #3C3C32",
+"~+    c #4E4E41",
+"{+    c #35352C",
+"]+    c #ACAC9C",
+"^+    c #85857B",
+"/+    c #BBBBB3",
+"(+    c #A3A39A",
+"_+    c #54544B",
+":+    c #93938A",
+"<+    c #919185",
+"[+    c #686856",
+"}+    c #414136",
+"|+    c #434337",
+"1+    c #A4A493",
+"2+    c #C1C1B6",
+"3+    c #B1B1A2",
+"4+    c #6B6B5F",
+"5+    c #9D9D8B",
+"6+    c #848470",
+"7+    c #71715E",
+"8+    c #A5A594",
+"9+    c #C2C2B7",
+"0+    c #7B7B65",
+"a+    c #5F5F4F",
+"b+    c #666654",
+"c+    c #49493C",
+"d+    c #575748",
+"e+    c #57574A",
+"f+    c #7D7D6D",
+"g+    c #767669",
+"h+    c #B3B3A8",
+"i+    c #A1A194",
+"j+    c #6D6D61",
+"k+    c #B3B3A5",
+"l+    c #696957",
+"m+    c #414135",
+"n+    c #565647",
+"o+    c #444438",
+"p+    c #595951",
+"q+    c #585849",
+"r+    c #4E4E40",
+"s+    c #747467",
+"t+    c #616153",
+"                  . . . . . .                   ",
+"              . + @ # $ % & * . .               ",
+"        . . . = - ; > , ' ) ! ~ { . . .         ",
+"      . ] ^ / ( _ : < [ } | 1 2 3 4 5 6 .       ",
+"    . 7 8 9 0 a b c d e f g h i j k l m n .     ",
+"    o p 8 q r s t u v w x y z A B C 2 C D .     ",
+"    . E F G H I J K L M N O D P Q R S T U .     ",
+"    . V W X Y Z `  ...0 +.S / @.#.$.%.&.*..     ",
+"    =.-.;.>.,.'.).!.~.{.X ].^.G /.(._.:.<..     ",
+"    . [.n }.|.1.2.3.4.5.6.7.8.9.0.9.a.b.c.      ",
+"      . d.e.f.g.h.i.j.k.l l l 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.`. +.+++@+.       ",
+"      . #+$+%+&+*+=+-+;+>+,+'+)+!+~+{+`..       ",
+"      . #+Q.]+^+/+(+_+:+<+,+'+[+}+X.|+X..       ",
+"      . #+Q.1+^+2+3+4+3+5+`.6+7+|+X.|+X..       ",
+"      . #+Q.8+^+9+3+4+3+5+`.6+7+|+X.|+X..       ",
+"      . #+Q.5+^+2+3+4+3+5+`.6+7+|+X.|+X..       ",
+"      . 0+Q.1+^+2+3+4+3+5+`.6+7+|+X.|+a+.       ",
+"      . b+Q.1+&+2+3+4+3+5+`.6+7+|+X.c+d+.       ",
+"        . e+f+g+h+i+j+k+5+`.6+l+m+n+o+. .       ",
+"          . . . p+q+r+s+t+~+c+c+. . .           ",
+"              . . . . . . . . . .               "};
diff --git a/xemacs-packages/gnus/etc/images/describe.xpm b/xemacs-packages/gnus/etc/images/describe.xpm
new file mode 100644 (file)
index 0000000..38062d5
--- /dev/null
@@ -0,0 +1,95 @@
+/* XPM */
+static char * stock_properties_xpm[] = {
+"24 24 68 1",
+"      c None",
+".     c #000000",
+"+     c #74716E",
+"@     c #C9C4BD",
+"#     c #DFDAD2",
+"$     c #F4EFE5",
+"%     c #F2ECE1",
+"&     c #FFFFFF",
+"*     c #4C4B48",
+"=     c #EEE5D4",
+"-     c #ECE2CF",
+";     c #EADFC9",
+">     c #F9F9F9",
+",     c #E2D2B1",
+"'     c #F4F4F4",
+")     c #EEEEEE",
+"!     c #959595",
+"~     c #F5F5F5",
+"{     c #F6F6F6",
+"]     c #D9D9D9",
+"^     c #C7B99C",
+"/     c #E9E9E9",
+"(     c #787878",
+"_     c #E1E1E1",
+":     c #E2E2E2",
+"<     c #C8C8C8",
+"[     c #877E69",
+"}     c #9A8F78",
+"|     c #DEDEDE",
+"1     c #E3E3E3",
+"2     c #929292",
+"3     c #AFA389",
+"4     c #ACACAC",
+"5     c #A2A2A2",
+"6     c #E4E4E4",
+"7     c #BCBCBC",
+"8     c #939393",
+"9     c #EDEDED",
+"0     c #EFEFEF",
+"a     c #F0F0F0",
+"b     c #E5E5E5",
+"c     c #E7E7E7",
+"d     c #E8E8E8",
+"e     c #EAEAEA",
+"f     c #EBEBEB",
+"g     c #BEBEBE",
+"h     c #F1F1F1",
+"i     c #DFDFDF",
+"j     c #F3F3F3",
+"k     c #E0E0E0",
+"l     c #ABABAB",
+"m     c #AEAEAE",
+"n     c #AFAFAF",
+"o     c #ADADAD",
+"p     c #B0B0B0",
+"q     c #B1B1B1",
+"r     c #F7F7F7",
+"s     c #B3B3B3",
+"t     c #F8F8F8",
+"u     c #B4B4B4",
+"v     c #B5B5B5",
+"w     c #B6B6B6",
+"x     c #FAFAFA",
+"y     c #FBFBFB",
+"z     c #DCDCDC",
+"A     c #DDDDDD",
+"B     c #E6E6E6",
+"C     c #969696",
+"                        ",
+"                        ",
+"                        ",
+"           .........    ",
+"          .+@#$%.&&.    ",
+"          *=---;.&>.    ",
+"   .......;.,,,,.').    ",
+"   !~~{].;.^.,^^./(..   ",
+"  .~_:<.;.[.^.}..|]..   ",
+"  .~:1.;.2.[.3.4...5.   ",
+"  .{16..7/8.[.49)0a|.   ",
+"  .{6bcd/ef8.g9)0ahi.   ",
+"  .{bcd/ef9ef9)0ahjk.   ",
+"  .{cllefmnomnppqj'_.   ",
+"  .rd/ef9)09)0ahj'~:.   ",
+"  .r/4o9)ppnppqss~{1.   ",
+"  .tef9)0ah0ahj'~{rb.   ",
+"  .>9npahssqssuvw>xc.   ",
+"  .>)0ahj'~j'~{r>xyd.   ",
+"  .nzA|ik_:k_:1bBcdC.   ",
+"   .................    ",
+"                        ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/diropen.xpm b/xemacs-packages/gnus/etc/images/diropen.xpm
new file mode 100644 (file)
index 0000000..6937b99
--- /dev/null
@@ -0,0 +1,44 @@
+/* XPM */
+static char * diropen_xpm[] = {
+"19 24 17 1",
+"      c None",
+".     c #000100",
+"+     c #C6C9A6",
+"@     c #D0D3AF",
+"#     c #93997C",
+"$     c #E6E7D0",
+"%     c #BEC19E",
+"&     c #B4B895",
+"*     c #A7AA88",
+"=     c #6B6D59",
+"-     c #4A4E40",
+";     c #7C8166",
+">     c #898E72",
+",     c #3C4032",
+"'     c #575845",
+")     c #34332C",
+"!     c #24231D",
+"  ...............  ",
+" .+@@@@@@@@@@@@@#. ",
+".$@@@@@@@@@@@@@@@#.",
+".++++%%%%%%%%%&&&*.",
+".&&&&&&&&&&******#.",
+".*%+++%%%%%%%%%&=#.",
+".*+***********##-#.",
+".*+****;===;####-#.",
+".*+****=*****###-#.",
+".*+****;*****###-#.",
+".*+****########>-#.",
+".*&######>>>>>>>,>.",
+".*#-------------'>)",
+".*&&&&&&&&&&&&&*#>)",
+".*&************#'>)",
+".*&***********##,>)",
+".*&****====;###>,>)",
+".#&****=**#**##>,;)",
+".#&****>****###>,;)",
+".#&****########>,;)",
+".##''''''''''''',;)",
+".#>==============;)",
+".''''''''''''''''-!",
+" ................. "};
diff --git a/xemacs-packages/gnus/etc/images/disconnect.xpm b/xemacs-packages/gnus/etc/images/disconnect.xpm
new file mode 100644 (file)
index 0000000..e08b282
--- /dev/null
@@ -0,0 +1,69 @@
+/* XPM */
+static char * stock_disconnect_xpm[] = {
+"24 24 42 1",
+"      c None",
+".     c #000000",
+"+     c #989389",
+"@     c #807D74",
+"#     c #C6C2BA",
+"$     c #43423C",
+"%     c #B7B3AA",
+"&     c #C4C2BD",
+"*     c #EAE8E3",
+"=     c #E2E1DD",
+"-     c #F0EFEC",
+";     c #AAA7A0",
+">     c #C5D2C8",
+",     c #E9EEEA",
+"'     c #F0EEEB",
+")     c #F2F0ED",
+"!     c #EBEAE6",
+"~     c #8A857B",
+"{     c #ECEBE8",
+"]     c #EEECEA",
+"^     c #78756B",
+"/     c #BEBBB5",
+"(     c #B3B1AA",
+"_     c #7D786E",
+":     c #E1DFDB",
+"<     c #D1D0CC",
+"[     c #010101",
+"}     c #8C8981",
+"|     c #A6A29B",
+"1     c #726D63",
+"2     c #CECAC3",
+"3     c #A7A49E",
+"4     c #0F0F0D",
+"5     c #F0F3F1",
+"6     c #272622",
+"7     c #8B877E",
+"8     c #706C62",
+"9     c #B1ADA4",
+"0     c #6C685E",
+"a     c #97938A",
+"b     c #646056",
+"c     c #8B877D",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"         ..           ..",
+"       ..+@.         .#@",
+"      $%&*@....      .*@",
+"     .=-;*@.>>,.     .'@",
+".....@=-;*@....      .'@",
+"******)!~{@.         .]@",
+"@@@@^^/(_:^.         .<@",
+"....[^}|12^....      .3@",
+"     4}|12^.>>5.     .3@",
+"      67890....      .a@",
+"       44+b.         .c@",
+"         44           4.",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/exit.xpm b/xemacs-packages/gnus/etc/images/exit.xpm
new file mode 100644 (file)
index 0000000..7f9daf1
--- /dev/null
@@ -0,0 +1,167 @@
+/* XPM */
+static char * stock_exit_xpm[] = {
+"24 24 140 2",
+"      c None",
+".     c #000000",
+"+     c #D6D6D4",
+"@     c #BDBDBC",
+"#     c #A8A8A4",
+"$     c #92928F",
+"%     c #727370",
+"&     c #61615E",
+"*     c #20201F",
+"=     c #F1F1EF",
+"-     c #E6E6E4",
+";     c #DADAD7",
+">     c #CFCFCD",
+",     c #C4C4C1",
+"'     c #A8A8A5",
+")     c #767674",
+"!     c #777774",
+"~     c #1E1E1D",
+"{     c #B9B9B7",
+"]     c #AEAEAC",
+"^     c #8F8F8D",
+"/     c #262626",
+"(     c #414140",
+"_     c #E9836C",
+":     c #DEDEDC",
+"<     c #C5C5C2",
+"[     c #636362",
+"}     c #040504",
+"|     c #040604",
+"1     c #050705",
+"2     c #E87B62",
+"3     c #E67056",
+"4     c #D5D5D3",
+"5     c #DBDBD8",
+"6     c #D0D0CE",
+"7     c #080A07",
+"8     c #0A0C09",
+"9     c #0A0D09",
+"0     c #0B0E0A",
+"a     c #F0B0A1",
+"b     c #EB8D77",
+"c     c #DF421E",
+"d     c #E97E66",
+"e     c #CBCBC8",
+"f     c #0C0F0B",
+"g     c #0F130D",
+"h     c #10140E",
+"i     c #11150F",
+"j     c #EFA392",
+"k     c #BFBFBD",
+"l     c #5D5D5C",
+"m     c #10150F",
+"n     c #141912",
+"o     c #161C14",
+"p     c #171D15",
+"q     c #B7B7B4",
+"r     c #0C0C0C",
+"s     c #192017",
+"t     c #1C2319",
+"u     c #1D241A",
+"v     c #CD8484",
+"w     c #990000",
+"x     c #701616",
+"y     c #A6A6A5",
+"z     c #181E16",
+"A     c #1E261B",
+"B     c #212A1E",
+"C     c #222B1F",
+"D     c #4F0000",
+"E     c #AEAEAB",
+"F     c #1D261B",
+"G     c #242E21",
+"H     c #273224",
+"I     c #283325",
+"J     c #580000",
+"K     c #B5B5B3",
+"L     c #293426",
+"M     c #2D3929",
+"N     c #2E3A2A",
+"O     c #7C4343",
+"P     c #6A0000",
+"Q     c #720000",
+"R     c #BDBDBB",
+"S     c #232C20",
+"T     c #2A3526",
+"U     c #303C2B",
+"V     c #33402E",
+"W     c #C5C5C3",
+"X     c #1E261C",
+"Y     c #303D2C",
+"Z     c #374532",
+"`     c #394834",
+" .    c #500000",
+"..    c #CDCDCB",
+"+.    c #1B2319",
+"@.    c #253022",
+"#.    c #303E2D",
+"$.    c #394934",
+"%.    c #3D4E38",
+"&.    c #9D9D9B",
+"*.    c #565655",
+"=.    c #2C3828",
+"-.    c #40503A",
+";.    c #43553E",
+">.    c #BABAB7",
+",.    c #777776",
+"'.    c #323830",
+").    c #232C1F",
+"!.    c #313E2D",
+"~.    c #3B4A36",
+"{.    c #43553D",
+"].    c #485B42",
+"^.    c #4A5E44",
+"/.    c #F0F0EE",
+"(.    c #E5E5E3",
+"_.    c #C6C6C3",
+":.    c #ACACAB",
+"<.    c #8B8B8A",
+"[.    c #32392F",
+"}.    c #2C3728",
+"|.    c #3F503A",
+"1.    c #465840",
+"2.    c #4B5E44",
+"3.    c #4E6347",
+"4.    c #506549",
+"5.    c #DADAD8",
+"6.    c #7A7D78",
+"7.    c #333C30",
+"8.    c #475A41",
+"9.    c #4F6348",
+"0.    c #53694C",
+"a.    c #566C4E",
+"b.    c #576D4F",
+"c.    c #91968F",
+"d.    c #3B4736",
+"e.    c #42543C",
+"f.    c #51674A",
+"g.    c #586F50",
+"h.    c #5B7353",
+"i.    c #5C7454",
+"                                                ",
+"              . . . . . . . . . . . . . . . .   ",
+"              . + @ # $ % & & & * . . . . . .   ",
+"              . = - ; > , ' ) ! ~ . . . . . .   ",
+"          .   . = - ; > , { ] ^ / . . . . . .   ",
+"          . . . = - ; > , { { { ( . . . . . .   ",
+"          . _ . : - ; > < { { { [ } | 1 1 1 .   ",
+". . . . . . 2 3 . 4 5 6 < { { { [ 7 8 9 0 0 .   ",
+". a 2 2 2 2 b c d . e 6 < { { { [ f g h i i .   ",
+". j c c c c c c c 3 . k < { l { [ m n o p p .   ",
+". j c c c c c c c c 3 . q { l r [ n s t u u .   ",
+". v w w w w w w w w w x . y r { [ z A B C C .   ",
+". v w w w w w w w w D . E { { { [ F G H I I .   ",
+". v w w w w w w w J . K < { { { [ C L M N N .   ",
+". O P P P P Q w J . R 6 < { { { [ S T U V V .   ",
+". . . . . . Q J . W 5 6 < { { { [ X H Y Z ` .   ",
+"          .  .. ..- 5 6 < { { { [ +.@.#.$.%..   ",
+"          . . . = - 5 6 < { ] &.*.B =.Z -.;..   ",
+"          .   . = - 5 6 >.&.,.'.).!.~.{.].^..   ",
+"              . /.(._.:.<.[.}.Z |.1.2.3.4.4..   ",
+"              . 5.k 6.7.Z -.8.9.0.a.a.b.b.b..   ",
+"              . c.d.e.^.f.g.h.i.i.i.i.i.i.i..   ",
+"              . . . . . . . . . . . . . . . .   ",
+"                                                "};
diff --git a/xemacs-packages/gnus/etc/images/gnus/README b/xemacs-packages/gnus/etc/images/gnus/README
new file mode 100644 (file)
index 0000000..6399c1b
--- /dev/null
@@ -0,0 +1,39 @@
+COPYRIGHT AND LICENSE INFORMATION FOR IMAGE FILES
+
+* The following icons are part of Emacs.  All are licensed under the
+  GNU General Public License version 3 (see COPYING) or later.
+  The file gnus.svg contains copyright and license information, but it
+  is reproduced here for convenience.
+
+Files: important.xpm, unimportant.xpm
+Author: Simon Josefsson <simon@josefsson.org>
+Copyright (C) 2001-2016 Free Software Foundation, Inc.
+
+Files: catchup.pbm catchup.xpm cu-exit.pbm cu-exit.xpm
+  describe-group.pbm describe-group.xpm exit-gnus.pbm exit-gnus.xpm
+  exit-summ.pbm exit-summ.xpm followup.pbm followup.xpm fuwo.pbm
+  fuwo.xpm get-news.pbm get-news.xpm gnntg.pbm gnntg.xpm gnus.xbm
+  gnus.xpm gnus-pointer.xbm gnus-pointer.xpm mail-reply.pbm
+  mail-reply.xpm next-ur.pbm next-ur.xpm post.pbm post.xpm prev-ur.pbm
+  prev-ur.xpm preview.xbm preview.xpm receipt.xpm reply-wo.pbm
+  reply-wo.xpm reply.pbm reply.xpm save-aif.pbm save-aif.xpm
+  save-art.pbm save-art.xpm subscribe.pbm subscribe.xpm
+  unsubscribe.pbm unsubscribe.xpm uu-decode.pbm uu-decode.xpm
+  uu-post.pbm uu-post.xpm
+Author: Luis Fernandes <elf@ee.ryerson.ca>
+Copyright (C) 2001-2016 Free Software Foundation, Inc.
+
+Files: gnus.png, gnus.svg
+  Author: Francesc Rocher <francesc.rocher@gmail.com>
+  Copyright (C) 2008-2016 Free Software Foundation, Inc.
+
+
+* The following icons are from GNOME 2.x. They are not part of Emacs,
+but are distributed and used by Emacs.  They are licensed under the
+GNU General Public License version 2 or later.  See the source of the
+gnome-icons-theme package for more information.
+
+  toggle-subscription.xpm       (GNOME stock/document/stock_task-recurring)
+  kill-group.pbm and kill-group.xpm are converted from close.xpm
+  rot13.pbm and rot13.xpm are converted from lock.xpm
+  mail-send.xpm  ?
diff --git a/xemacs-packages/gnus/etc/images/gnus/catchup.pbm b/xemacs-packages/gnus/etc/images/gnus/catchup.pbm
new file mode 100644 (file)
index 0000000..3fc571b
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/catchup.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/catchup.xpm b/xemacs-packages/gnus/etc/images/gnus/catchup.xpm
new file mode 100644 (file)
index 0000000..cba8497
--- /dev/null
@@ -0,0 +1,33 @@
+/* XPM */
+static char * catchup_xpm[] = {
+"24 24 6 1",
+"      c None",
+".     c #FFFFFFFFFFFF",
+"X     c #E1E1E0E0E0E0",
+"o     c #A5A5A5A59595",
+"O     c #999999999999",
+"+     c #000000000000",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"            .           ",
+"         .  .X          ",
+"       ...  .oX  .      ",
+"     ..oooX.oXo  .X     ",
+"    .oooXXXX..oXXoXX    ",
+"    .oXXXX.XoX.oXooX    ",
+"     X...X.X.XX.XoXX    ",
+"     Xo..X.XXX.XXXX     ",
+"   . Xo.oXX..XXXXXX     ",
+"OOOOXoXXXXXo.XXXXX++OOOO",
+"OOOOOX..X.XXXXXXXX++OOOO",
+"OOOOOX..XXXXXXXXX++OOOOO",
+"OOOOOOXXXXXXXXX+++OOOOOO",
+"OOOOOOOOOXXXX++++OOOOOOO",
+"OOOOOOOOO+++++OOOOOOOOOO",
+"OOOOOOOOOO+OOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOO"};
diff --git a/xemacs-packages/gnus/etc/images/gnus/cu-exit.pbm b/xemacs-packages/gnus/etc/images/gnus/cu-exit.pbm
new file mode 100644 (file)
index 0000000..210869c
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/cu-exit.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/cu-exit.xpm b/xemacs-packages/gnus/etc/images/gnus/cu-exit.xpm
new file mode 100644 (file)
index 0000000..1723622
--- /dev/null
@@ -0,0 +1,31 @@
+/* XPM */
+static char * cu_exit_xpm[] = {
+"24 24 4 1",
+"      c None",
+".     c #000000000000",
+"X     c #FFFFFFFFFFFF",
+"o     c #999999999999",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"           .....        ",
+"        .. .XXX.        ",
+"      ..X..XXXX...      ",
+"     .XXXX.XXXX.X...    ",
+"    ..XXXX.XXX.XXX..    ",
+"     .XXX..........     ",
+"     .XXX.XXX.XXX..     ",
+"      .XX.XXX.XXX.      ",
+"      .XX.XXX.XX..      ",
+"      ............      ",
+"       .X.X.X.X..       ",
+"ooooooo..........ooooooo",
+"ooooooo.X.X.X.X.oooooooo",
+"ooooooo.........oooooooo",
+"ooooooo..X...X..oooooooo",
+"ooooooo...X.X...oooooooo",
+"ooooooo........ooooooooo",
+"ooooooooo.....oooooooooo",
+"oooooooooooooooooooooooo"};
diff --git a/xemacs-packages/gnus/etc/images/gnus/describe-group.pbm b/xemacs-packages/gnus/etc/images/gnus/describe-group.pbm
new file mode 100644 (file)
index 0000000..de7bf11
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/describe-group.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/describe-group.xpm b/xemacs-packages/gnus/etc/images/gnus/describe-group.xpm
new file mode 100644 (file)
index 0000000..b4a6f42
--- /dev/null
@@ -0,0 +1,32 @@
+/* XPM */
+static char * describe_group_xpm[] = {
+"24 24 5 1",
+".     c None",
+"      c #000000000000",
+"o     c #FFFFF5F5ACAC",
+"+     c #E1E1E0E0E0E0",
+"@     c #C7C7C6C6C6C6",
+"........................",
+"........................",
+".................oooo...",
+" .. .. .. .. .. oo oo o.",
+"..............oooooooooo",
+".............ooooooooooo",
+" .. .. .. .. oo oo oo oo",
+"............oooooooooooo",
+"............oooooooooooo",
+" .. .. .. .. oo oo oo oo",
+"............oooooooooooo",
+"............oooooooooooo",
+" .. .. .. .. oo oo oo oo",
+"............oooooooooooo",
+".....    ...oooooooooooo",
+" ..   ++  .. .o oo oo oo",
+"...  @@@+  ....ooooooooo",
+"...     @  ....oooooooo.",
+" .         . .. .. .. ..",
+".         ..............",
+"        ................",
+"       .. .. .. .. .. ..",
+"      ..................",
+"    ...................."};
diff --git a/xemacs-packages/gnus/etc/images/gnus/exit-gnus.pbm b/xemacs-packages/gnus/etc/images/gnus/exit-gnus.pbm
new file mode 100644 (file)
index 0000000..32ad0e0
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/exit-gnus.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/exit-gnus.xpm b/xemacs-packages/gnus/etc/images/gnus/exit-gnus.xpm
new file mode 100644 (file)
index 0000000..534f3c2
--- /dev/null
@@ -0,0 +1,33 @@
+/* XPM */
+static char * exit_gnus_xpm[] = {
+"24 24 6 1",
+"      c None",
+".     c #8686ADAD7D7D",
+"X     c #919187876969",
+"o     c #C2C2B9B99C9C",
+"O     c #A8A8F0F0ECEC",
+"+     c #EFEFEFEFEFEF",
+"                        ",
+"     ....  .            ",
+"        .. .. .         ",
+"  .............         ",
+"   . . . ....           ",
+"     .............      ",
+"  .............. ..     ",
+"  . . ..........  .     ",
+"      .XXXX... ..       ",
+"       o.XXX. . ..      ",
+"      oo.X. ..  ...     ",
+"     ooX. . ...         ",
+"     oXo.     ..        ",
+"    ooX      . .        ",
+"    ooX                 ",
+"OOOOoXXOOOOOOOOOOOOOOOOO",
+"OOOoXoXOOOOOOOOOOOOOOOOO",
+"OOOooXXOOOO+OOOOOOOOOOOO",
+"O+OoooXOO+OOO+OO+OOO+OOO",
+"OXXoXoXoXOO++O++OO++OO+O",
+"XXXXXXXXXXXX+OOOOOOOOOOO",
+"XXXXXXXXXXXXXX+O++OO++OO",
+"XXXXXXXXXXXXXXXXOOOOOOOO",
+"O++O++++O+OO++OOOO++OOO+"};
diff --git a/xemacs-packages/gnus/etc/images/gnus/exit-summ.pbm b/xemacs-packages/gnus/etc/images/gnus/exit-summ.pbm
new file mode 100644 (file)
index 0000000..d019231
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/exit-summ.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/exit-summ.xpm b/xemacs-packages/gnus/etc/images/gnus/exit-summ.xpm
new file mode 100644 (file)
index 0000000..5234ccb
--- /dev/null
@@ -0,0 +1,30 @@
+/* XPM */
+static char * exit_summ_xpm[] = {
+"24 24 3 1",
+".     c None",
+"      c #000000000000",
+"X     c #E1E1E0E0E0E0",
+" .. .. .. .. .. .. .. ..",
+"........................",
+"........................",
+" .. ..             .. ..",
+"......  XXXX       .....",
+"......  XXXXXXX    .....",
+" .. .. XX XX XX    .. ..",
+"...... XXXXXXXX    .....",
+"......  XXXXXXX    .....",
+" .. ..  X XX       .. ..",
+"......  XXXX       .....",
+"......  XXXX       .....",
+" .. ..  X XXXXX    .. ..",
+"......  XXXXXXX    .....",
+"...... XXXXX XX    .....",
+" .. ..  X XXXXX    .. ..",
+"......  XXXXX      .....",
+"......  X          .....",
+" .. . .            .. ..",
+"........................",
+"........................",
+" .. .. .. .. .. .. .. ..",
+"........................",
+"........................"};
diff --git a/xemacs-packages/gnus/etc/images/gnus/followup.pbm b/xemacs-packages/gnus/etc/images/gnus/followup.pbm
new file mode 100644 (file)
index 0000000..61be114
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/followup.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/followup.xpm b/xemacs-packages/gnus/etc/images/gnus/followup.xpm
new file mode 100644 (file)
index 0000000..444895a
--- /dev/null
@@ -0,0 +1,31 @@
+/* XPM */
+static char * followup_xpm[] = {
+"24 24 4 1",
+"      c None",
+".     c #A5A5A5A59595",
+"X     c #C7C7C6C6C6C6",
+"o     c #E1E1E0E0E0E0",
+"                        ",
+"          .             ",
+"        ..X.            ",
+"      ..XXX.            ",
+"    ..XXXXXo.           ",
+" ...XXXXXXooo.  .       ",
+" .o.XXXXXooooo..X.      ",
+" .oo.XXXoooo..XXX.      ",
+" .oo..Xooo..XXXXXo.     ",
+" .oo.XX...XXXXXXooo.    ",
+" .o.Xoo.o.XXXXXoooo.    ",
+"  .XXoo.oo.XXXoooooo.   ",
+"  .Xooo.oo..XXooooooo.  ",
+"   .ooo.oo.XXooooooooo. ",
+"   .ooo.o.XoooooooooooX.",
+"    .ooo.XXoooooooooooo.",
+"    .ooo.Xoooooooooooo. ",
+"     .ooo.ooooooooooo.  ",
+"     .oo..oooooooooo.   ",
+"      ..  .ooooooo..    ",
+"          .oooooo.      ",
+"           .ooo..       ",
+"           .oo.         ",
+"            ..          "};
diff --git a/xemacs-packages/gnus/etc/images/gnus/fuwo.pbm b/xemacs-packages/gnus/etc/images/gnus/fuwo.pbm
new file mode 100644 (file)
index 0000000..b81af10
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/fuwo.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/fuwo.xpm b/xemacs-packages/gnus/etc/images/gnus/fuwo.xpm
new file mode 100644 (file)
index 0000000..362cbc5
--- /dev/null
@@ -0,0 +1,31 @@
+/* XPM */
+static char * fuwo_xpm[] = {
+"24 24 4 1",
+"      c None",
+".     c #A5A5A5A59595",
+"X     c #C7C7C6C6C6C6",
+"o     c #E1E1E0E0E0E0",
+"                        ",
+"          .             ",
+"        .. .            ",
+"      ..   .            ",
+"    ..      .           ",
+" ...         .  .       ",
+" . .          ..X.      ",
+" .  .       ..XXX.      ",
+" .  ..    ..XXXXXo.     ",
+" .  .  ...XXXXXXooo.    ",
+" . .X  .o.XXXXXoooo.    ",
+"  .XX  .oo.XXXoooooo.   ",
+"  .X   .oo..XXooooooo.  ",
+"   .   .oo.XXooooooooo. ",
+"   .   .o.XoooooooooooX.",
+"    .   .XXoooooooooooo.",
+"    .   .Xoooooooooooo. ",
+"     .   .ooooooooooo.  ",
+"     .  ..oooooooooo.   ",
+"      ..  .ooooooo..    ",
+"          .oooooo.      ",
+"           .ooo..       ",
+"           .oo.         ",
+"            ..          "};
diff --git a/xemacs-packages/gnus/etc/images/gnus/get-news.pbm b/xemacs-packages/gnus/etc/images/gnus/get-news.pbm
new file mode 100644 (file)
index 0000000..c008071
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/get-news.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/get-news.xpm b/xemacs-packages/gnus/etc/images/gnus/get-news.xpm
new file mode 100644 (file)
index 0000000..d7e7b4a
--- /dev/null
@@ -0,0 +1,31 @@
+/* XPM */
+static char * get_news_xpm[] = {
+"24 24 4 1",
+".     c None",
+"X     c #A5A5A5A59595",
+"o     c #E1E1E0E0E0E0",
+"O     c #C7C7C6C6C6C6",
+"........................",
+"........................",
+"........................",
+".....XXX................",
+"...XXoooXXXXX...........",
+"XXXoooooXXoooX.XXX......",
+"XoXooXXXooooXXXoooX.....",
+"XooXoXoXooXXXoooooX.....",
+"XooXXXooXoXoXooooooX....",
+"XooXOXooXXXooXooooooX...",
+"XoXOOXooXOXooXXooooooX..",
+"OXOOOXoXOOXooXoooooooX..",
+"OXOooOXOOOXoXOooooooooX.",
+".OXooOXOooOXOOooooooooX.",
+".OXoooOXooOXOooooooooooX",
+"..OXooOXoooOXooooooooooX",
+"..OXooOOXooOXooooooooooX",
+"...OXooOXoooOXoooooooXXX",
+"...OXooXOXooOXooooooXOO.",
+"....OXXOOXooXOXoooXXO...",
+".....OO..OXXOOXooXOO....",
+"..........OO..OXXO......",
+"...............OO.......",
+"........................"};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnntg.pbm b/xemacs-packages/gnus/etc/images/gnus/gnntg.pbm
new file mode 100644 (file)
index 0000000..2f5e526
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/gnntg.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnntg.xpm b/xemacs-packages/gnus/etc/images/gnus/gnntg.xpm
new file mode 100644 (file)
index 0000000..21bc5f1
--- /dev/null
@@ -0,0 +1,31 @@
+/* XPM */
+static char * gnntg_xpm[] = {
+"24 24 4 1",
+"      c None",
+".     c #000000000000",
+"X     c #FFFFFFFFFFFF",
+"o     c #C7C7C6C6C6C6",
+"                        ",
+" .......                ",
+" .XXXXX.                ",
+" .XXXXX.       ...      ",
+" .XXXXX...    .ooo.     ",
+" .XXXXX....  ..ooo..    ",
+" .XXXXX..o.. ..ooo..    ",
+" .XXXXX...o.. ..o..     ",
+" .XXXXX. ..o........    ",
+" .XXXXX.  ..oooooooo.   ",
+" .......   .oooooooo..  ",
+"            .ooooo..o.  ",
+"             .oooo..o.  ",
+"             .oooo..o.  ",
+"             .oooo..o.  ",
+"             .oooo..o.  ",
+"             .........  ",
+"            ......oo.   ",
+"            .ooooo...   ",
+"            .oo..o...   ",
+"            .oo..o..    ",
+"            ........    ",
+"            .... ...    ",
+"            ...  ...    "};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-group-catchup-current-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-group-catchup-current-up.xbm
new file mode 100644 (file)
index 0000000..f801fea
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x20,0x40,0x10,0x20,0x0a,0x15,0x85,0x0a,0x20,0x20,0x28,0x50,0x8a,0x8a,0x02,
+ 0x05,0x10,0x5e,0x54,0xa8,0xa5,0x35,0x01,0x7a,0x00,0x33,0x54,0x95,0xaa,0xaa,
+ 0x02,0xcc,0xfe,0x17,0xa8,0xd8,0x01,0xac,0xfa,0x4f,0x3d,0xf8,0x05,0x30,0x22,
+ 0x80,0xf6,0x60,0x2b,0xfc,0x8f,0x20,0x11,0x82,0xca,0x60,0x1a,0x2a,0x6e,0x28,
+ 0x08,0x85,0x42,0x68,0xfa,0x11,0x28,0xc8,0x04,0x8b,0xe2,0xb7,0x06,0x21,0x14,
+ 0xd4,0x1a,0x11,0x31,0x04,0x31,0x56,0x6d,0xdc,0x58,0xea,0xc7,0x28,0x64,0x66,
+ 0x60,0xa9,0x57,0x72,0x90,0x49,0xc8,0xec,0x5f,0x99,0xa6,0x7f,0x95,0x52,0xaa,
+ 0x64,0x22,0xbf,0x49,0x2a,0xa9,0x7e,0x92,0x52,0x55,0x55,0x54,0x49,0x4a,0xa4,
+ 0x49,0xaa,0xa4,0x4a,0x2a,0x49,0x2a,0x25};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-group-catchup-current-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-group-catchup-current-up.xpm
new file mode 100644 (file)
index 0000000..0504f9d
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-group-catchup-current.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-group-catchup-current.xbm
new file mode 100644 (file)
index 0000000..2218640
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x84,0x20,0x00,0x04,0x21,0x88,0x54,0x51,0x84,0x22,0x02,0x04,0x51,0x88,0xa0,
+ 0x42,0x04,0x1f,0x0a,0x28,0x51,0x75,0xa1,0x7a,0x04,0x23,0x04,0xcc,0xa1,0x76,
+ 0xa9,0xa6,0xfe,0x1b,0x00,0xd8,0x01,0x0c,0xfd,0x5f,0x3d,0xf8,0x05,0x30,0x26,
+ 0x80,0xf7,0x60,0x33,0xfc,0xdb,0x20,0x11,0x22,0x8e,0x20,0x14,0x8a,0x66,0x68,
+ 0x09,0x45,0x48,0x28,0xfc,0x11,0x21,0xc8,0x04,0x45,0xf4,0xf7,0x06,0x89,0x10,
+ 0xc4,0x1a,0x23,0x35,0x2c,0x31,0xaa,0x6c,0x54,0x58,0xea,0xc7,0x48,0x64,0x66,
+ 0xa0,0x99,0x57,0x72,0x50,0x59,0xc8,0xec,0x2f,0x49,0xa6,0x7f,0xaa,0x52,0xaa,
+ 0x64,0x49,0xbf,0x49,0x2a,0xa5,0x7e,0x92,0xa4,0x14,0x55,0xa9,0x52,0xaa,0x92,
+ 0x4a,0xa5,0x24,0x25,0xa5,0x94,0xaa,0xa8};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-group-catchup-current.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-group-catchup-current.xpm
new file mode 100644 (file)
index 0000000..bea4643
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-group-describe-group-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-group-describe-group-up.xbm
new file mode 100644 (file)
index 0000000..0054d63
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x55,0xb5,0x55,0xb5,0xaa,0x12,0xa9,0x12,0x12,0x55,0x12,0x65,0xa9,0xa4,0x4a,
+ 0x10,0x55,0x9b,0x15,0xc1,0x55,0x51,0x09,0x00,0x92,0x4a,0x02,0x00,0xa9,0x24,
+ 0x01,0x00,0x55,0x5b,0x11,0x11,0x92,0xa4,0x00,0x00,0x2a,0x49,0x00,0x00,0x49,
+ 0x55,0x00,0x00,0x35,0x55,0x11,0x11,0xaa,0xaa,0x00,0x00,0x92,0x44,0x00,0x00,
+ 0xa5,0x32,0x00,0x00,0x55,0x55,0x11,0x11,0x29,0x55,0x01,0x00,0xaa,0x24,0x01,
+ 0x00,0x92,0x97,0x00,0x00,0x75,0xba,0x13,0x11,0x2a,0x51,0x04,0x00,0xb2,0xaa,
+ 0x0a,0x40,0x59,0x75,0x25,0x40,0xb5,0x3d,0x59,0xb5,0xfa,0x77,0xa5,0x2a,0xae,
+ 0x9a,0x2a,0x49,0xd6,0x5f,0x49,0xa5,0xf7,0x57,0x35,0x55,0x7d,0x29,0x95,0x2a,
+ 0x7e,0x55,0xa9,0x54,0x5f,0x92,0x94,0x92};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-group-describe-group-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-group-describe-group-up.xpm
new file mode 100644 (file)
index 0000000..e0ffde7
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-group-exit-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-group-exit-up.xbm
new file mode 100644 (file)
index 0000000..c03e1fa
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x00,0x00,0x40,0x00,0x00,0x30,0x30,0x00,0x00,0x68,0x38,0x00,0x38,0x60,0x48,
+ 0x00,0xd4,0x91,0xde,0x07,0x68,0xcf,0xb7,0x1a,0x80,0xb4,0x6e,0x05,0x00,0xe2,
+ 0x07,0x00,0x00,0xde,0x1d,0x00,0xe0,0xfd,0x77,0x00,0xb0,0x6a,0xf3,0x00,0x20,
+ 0x9c,0xa5,0x03,0x00,0xaa,0x86,0x02,0x00,0x65,0x06,0x02,0xab,0x6f,0xaf,0x59,
+ 0x80,0x62,0x0c,0x00,0xaa,0xab,0xba,0x4a,0x40,0x21,0x10,0x10,0xea,0x45,0x4a,
+ 0x42,0x40,0x89,0x90,0x28,0xd2,0x21,0x02,0x82,0xa4,0x8a,0x44,0x20,0xf0,0x10,
+ 0x10,0x85,0xa4,0x04,0x4a,0x20,0xe2,0x22,0x80,0x80,0xbc,0x4b,0x09,0x2a,0xee,
+ 0x8e,0x32,0x80,0xeb,0x73,0x85,0x28,0x56,0xaa,0xb5,0x02,0xff,0xff,0x85,0x48,
+ 0x08,0x94,0x11,0x01,0x42,0x02,0x48,0x54};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-group-exit-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-group-exit-up.xpm
new file mode 100644 (file)
index 0000000..1b8982f
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-group-get-new-news-this-group-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-group-get-new-news-this-group-up.xbm
new file mode 100644 (file)
index 0000000..2f354f4
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x20,0x00,0x40,0x88,0xff,0x57,0x15,0x22,0x02,0x0c,0xa0,0x88,0x02,0xa4,0x0a,
+ 0x22,0x02,0x04,0xf0,0x84,0x03,0x54,0xdd,0x21,0x02,0x1e,0x14,0x97,0x02,0x66,
+ 0xcd,0x02,0x02,0x7c,0x14,0x2b,0x03,0x9c,0xad,0x41,0x02,0x54,0xb1,0x0a,0x02,
+ 0x2c,0xff,0x47,0x02,0xe4,0x14,0x2d,0xff,0x4f,0xa5,0x0a,0x48,0xa0,0x4a,0xb4,
+ 0x12,0x0a,0x51,0x1b,0x40,0xa1,0x96,0x36,0x2a,0x10,0x4a,0x56,0x80,0x4a,0x57,
+ 0x1b,0x55,0x00,0x92,0x52,0x00,0x55,0x26,0x17,0xa9,0x00,0xab,0x5a,0x04,0x2a,
+ 0xfe,0x1f,0x41,0x41,0xcb,0x48,0x14,0x14,0x95,0x2f,0x82,0x42,0x53,0x09,0x28,
+ 0x08,0xa5,0xaf,0x84,0xa2,0x75,0x06,0x12,0x04,0xd3,0x54,0x40,0x51,0xdf,0x0f,
+ 0x0a,0x82,0xae,0x23,0xa0,0x28,0x8a,0x4a};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-group-get-new-news-this-group-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-group-get-new-news-this-group-up.xpm
new file mode 100644 (file)
index 0000000..918fd2e
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-group-get-new-news-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-group-get-new-news-up.xbm
new file mode 100644 (file)
index 0000000..bea7a56
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x00,0x81,0x00,0x08,0xff,0x2b,0xa8,0x42,0x01,0x42,0x05,0x14,0x01,0x16,0x50,
+ 0x41,0x01,0xa2,0x7a,0x0a,0x01,0x0a,0xcc,0x40,0x01,0xaf,0x92,0x15,0x01,0x13,
+ 0x56,0x43,0x01,0xbe,0x2a,0x09,0x01,0x6e,0xcc,0x52,0x01,0xca,0x69,0x80,0x01,
+ 0x32,0xdf,0x2b,0x01,0x66,0x55,0x85,0xff,0x33,0xa9,0x2e,0x24,0xc9,0x92,0x88,
+ 0x09,0x82,0x4a,0x2e,0xa0,0x28,0xfd,0xf9,0x14,0x42,0x07,0x8d,0x42,0x08,0x85,
+ 0x8d,0x20,0x52,0x87,0x85,0x8a,0x80,0x45,0x86,0x20,0x2a,0xc7,0x82,0x8a,0x00,
+ 0xe7,0x82,0x41,0xd4,0x15,0x81,0x14,0x81,0xe6,0x81,0x81,0xa8,0x3d,0xff,0x14,
+ 0x82,0xfa,0x02,0x42,0xd1,0x52,0x57,0x08,0x8a,0xad,0x82,0xa2,0xa0,0xef,0x2b,
+ 0x04,0x05,0x55,0x81,0x51,0x50,0xc7,0x2b};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-group-get-new-news-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-group-get-new-news-up.xpm
new file mode 100644 (file)
index 0000000..d324784
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-group-kill-group-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-group-kill-group-up.xbm
new file mode 100644 (file)
index 0000000..8c3526d
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x00,0x04,0x20,0x20,0x54,0xa1,0x0a,0x4a,0x02,0x0a,0x50,0x01,0xa0,0x40,0x05,
+ 0x54,0xca,0xff,0x7f,0x00,0x50,0x00,0x60,0x55,0x42,0x00,0xa0,0x80,0x68,0xc0,
+ 0x21,0x2b,0x42,0xe0,0xe3,0x83,0x50,0xb0,0x06,0x2a,0x4a,0xf0,0x07,0x42,0x60,
+ 0x70,0x07,0x16,0x42,0xe0,0x03,0x42,0x68,0x40,0x01,0x2a,0x42,0x40,0x01,0x82,
+ 0x50,0xc8,0x05,0x2a,0x4a,0x0c,0x0c,0x82,0x60,0x30,0x03,0x2a,0x4a,0xc0,0x00,
+ 0x82,0x40,0xc0,0x00,0x2a,0x6a,0x30,0x03,0x42,0x41,0x0c,0x0c,0x16,0x54,0x08,
+ 0x04,0x22,0x41,0x00,0x00,0x4a,0x54,0x00,0x00,0x02,0x41,0x00,0x00,0x56,0x54,
+ 0x00,0x00,0x02,0x42,0x00,0x00,0x52,0xe8,0xff,0xff,0x0b,0x04,0x84,0x00,0x42,
+ 0x52,0x11,0xaa,0x28,0x00,0xa4,0x04,0x04};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-group-kill-group-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-group-kill-group-up.xpm
new file mode 100644 (file)
index 0000000..e728bf5
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-group-subscribe-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-group-subscribe-up.xbm
new file mode 100644 (file)
index 0000000..98819e5
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x08,0x04,0x00,0x40,0x22,0x51,0x55,0x15,0x88,0x04,0x00,0x20,0x22,0xa0,0xaa,
+ 0x4a,0xc4,0xff,0x3f,0x00,0x61,0x80,0x60,0x55,0x54,0x8a,0xa0,0x80,0x42,0x84,
+ 0x20,0x2b,0x68,0x8a,0xe0,0x83,0x42,0x80,0x00,0x2a,0xd4,0xff,0x00,0x42,0x41,
+ 0x80,0x00,0x16,0x54,0x8a,0x00,0x42,0x41,0x84,0x00,0x2a,0x54,0x8a,0x00,0x82,
+ 0x41,0x80,0x00,0x2a,0xd4,0xff,0x00,0x82,0x42,0x80,0x00,0x2a,0x68,0x8a,0x00,
+ 0x82,0x44,0x84,0x00,0x2a,0x52,0x8a,0x00,0x42,0x40,0x80,0x00,0x16,0xea,0xff,
+ 0x00,0x22,0x40,0x80,0x00,0x4a,0x4a,0x80,0x00,0x02,0x61,0x80,0x00,0x56,0x44,
+ 0x80,0x00,0x02,0x51,0x80,0x00,0x52,0xc4,0xff,0xff,0x0b,0xa1,0x04,0x00,0x42,
+ 0x14,0xa8,0xaa,0x88,0x82,0x02,0x00,0x22};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-group-subscribe-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-group-subscribe-up.xpm
new file mode 100644 (file)
index 0000000..15f7d43
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-group-unsubscribe-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-group-unsubscribe-up.xbm
new file mode 100644 (file)
index 0000000..9edc6b8
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x08,0x04,0x00,0x40,0x22,0x51,0x55,0x15,0x88,0x04,0x00,0x20,0x22,0xa0,0xaa,
+ 0x4a,0xc4,0xff,0x3f,0x00,0x61,0x80,0x60,0x55,0x54,0xa0,0xa0,0x80,0x42,0x90,
+ 0x20,0x2b,0x68,0x8a,0xe0,0x83,0x42,0x84,0x00,0x2a,0xd4,0xff,0x00,0x42,0x41,
+ 0x80,0x00,0x16,0x54,0xa0,0x00,0x42,0x41,0x90,0x00,0x2a,0x54,0x8a,0x00,0x82,
+ 0x41,0x84,0x00,0x2a,0xd4,0xff,0x00,0x82,0x42,0x80,0x00,0x2a,0x68,0xa0,0x00,
+ 0x82,0x44,0x90,0x00,0x2a,0x52,0x8a,0x00,0x42,0x40,0x84,0x00,0x16,0xea,0xff,
+ 0x00,0x22,0x40,0x80,0x00,0x4a,0x4a,0x80,0x00,0x02,0x61,0x80,0x00,0x56,0x44,
+ 0x80,0x00,0x02,0x51,0x80,0x00,0x52,0xc4,0xff,0xff,0x0b,0xa1,0x04,0x00,0x42,
+ 0x14,0xa8,0xaa,0x88,0x82,0x02,0x00,0x22};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-group-unsubscribe-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-group-unsubscribe-up.xpm
new file mode 100644 (file)
index 0000000..7c7ce5b
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-pointer.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-pointer.xbm
new file mode 100644 (file)
index 0000000..94e9154
--- /dev/null
@@ -0,0 +1,6 @@
+#define noname_width 18
+#define noname_height 13
+static char noname_bits[] = {
+ 0x00,0x00,0x00,0xc0,0x0c,0x00,0xe0,0x1f,0x00,0x92,0x39,0x00,0x0e,0x71,0x02,
+ 0x46,0xe0,0x03,0x20,0xc0,0x01,0x00,0x08,0x00,0x10,0x0d,0x00,0xc4,0x08,0x00,
+ 0x78,0x08,0x00,0x18,0x89,0x00,0x00,0x08,0x00};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-pointer.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-pointer.xpm
new file mode 100644 (file)
index 0000000..c47443d
--- /dev/null
@@ -0,0 +1,22 @@
+/* XPM */
+static char *gnus-pointer[] = {
+/* width height num_colors chars_per_pixel */
+"    18    13        2            1",
+/* colors */
+". c #0000ff",
+"# c None s None",
+/* pixels */
+"##################",
+"######..##..######",
+"#####........#####",
+"#.##.##..##...####",
+"#...####.###...##.",
+"#..###.######.....",
+"#####.########...#",
+"###########.######",
+"####.###.#..######",
+"######..###.######",
+"###....####.######",
+"###..######.######",
+"###########.######"
+};
\ No newline at end of file
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-caesar-message-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-caesar-message-up.xbm
new file mode 100644 (file)
index 0000000..0de8759
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x40,0x40,0x10,0x01,0x15,0x15,0x45,0x50,0x40,0x40,0x08,0x05,0x14,0x14,0xa2,
+ 0x50,0xe2,0xff,0x3f,0x82,0x48,0x00,0xe0,0x28,0x62,0xe6,0xb8,0x82,0x48,0x29,
+ 0x25,0x29,0x62,0xa9,0xe4,0x83,0x48,0x2f,0x05,0x2a,0x42,0xe9,0x38,0x42,0x60,
+ 0x00,0x00,0x16,0x4a,0x82,0x10,0x22,0x50,0x00,0x00,0x4a,0x42,0xcb,0x1c,0x02,
+ 0x68,0x2b,0x25,0x56,0x42,0x2d,0x1d,0x02,0x50,0x2d,0x05,0x52,0x4a,0xc9,0x04,
+ 0x0a,0x40,0x00,0x00,0x42,0x6a,0x18,0x00,0x16,0x41,0x3c,0x00,0x42,0x54,0xe6,
+ 0x3f,0x0a,0x41,0xe6,0x3f,0x52,0x54,0x3c,0x2a,0x06,0x42,0x18,0x2a,0x42,0x68,
+ 0x00,0x08,0x2a,0x44,0x00,0x00,0x06,0xd2,0xff,0xff,0x53,0x20,0x84,0x20,0x04,
+ 0x8a,0x10,0x8a,0xa8,0x20,0x4a,0x21,0x02};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-caesar-message-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-caesar-message-up.xpm
new file mode 100644 (file)
index 0000000..6f56aa9
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-summary-cancel-article-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-cancel-article-up.xbm
new file mode 100644 (file)
index 0000000..e8d8d68
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x11,0x11,0x01,0x11,0x54,0x4a,0xa9,0x52,0x82,0x10,0x04,0x08,0x28,0x24,0xa1,
+ 0x42,0x91,0x91,0x0f,0x19,0x25,0xaa,0xa9,0x44,0x88,0x60,0x18,0x11,0x42,0x1c,
+ 0x56,0x44,0x19,0x07,0x97,0x31,0x44,0x01,0x23,0x0a,0x12,0x81,0x60,0x50,0x80,
+ 0x02,0x42,0x05,0x3b,0x05,0x78,0x59,0x00,0x0a,0x56,0x12,0xaa,0xf4,0x05,0x41,
+ 0x00,0x54,0x51,0x10,0x5b,0x51,0x95,0x55,0x10,0x15,0x00,0x11,0x42,0x40,0x55,
+ 0x44,0x10,0x2a,0x00,0x21,0x5b,0x91,0x5b,0x95,0x80,0x24,0x00,0x21,0x12,0x92,
+ 0x2a,0x14,0x44,0x01,0x80,0x42,0x11,0xb5,0x35,0x19,0x54,0x11,0x08,0x42,0x02,
+ 0x44,0xa1,0x08,0xa8,0x22,0x14,0x52,0x11,0x99,0x51,0x11,0x4a,0x22,0x14,0x4a,
+ 0x20,0x89,0x42,0x10,0x15,0x40,0x20,0x45};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-cancel-article-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-cancel-article-up.xpm
new file mode 100644 (file)
index 0000000..fa7c639
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-summary-catchup-and-exit-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-catchup-and-exit-up.xbm
new file mode 100644 (file)
index 0000000..4adec42
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x08,0x81,0x00,0x04,0x42,0x28,0x52,0x51,0x14,0x85,0x08,0x04,0x81,0x20,0x42,
+ 0x49,0x14,0x8a,0x08,0x20,0x41,0x21,0x52,0x15,0x14,0x44,0x00,0x40,0x41,0x91,
+ 0xbf,0x2a,0x14,0xda,0x10,0x80,0x81,0x94,0x90,0x2a,0x14,0x73,0xf0,0x80,0xe1,
+ 0x60,0x90,0x2b,0xc4,0x60,0x08,0x43,0xa2,0xf0,0x0f,0x15,0x88,0x11,0xfc,0x21,
+ 0xd2,0x11,0x8c,0x4a,0x80,0x12,0x84,0x00,0xd5,0x13,0x84,0x55,0x00,0x17,0x74,
+ 0x80,0x54,0xfb,0xcf,0x2a,0x02,0x9a,0x24,0x40,0x54,0x9f,0xbc,0x36,0xa9,0xf4,
+ 0x77,0x49,0x94,0x96,0x94,0xa4,0x25,0x95,0x35,0x15,0xa9,0xfe,0xbf,0xa4,0x92,
+ 0xdc,0x5c,0x29,0x4a,0x9e,0x3d,0x95,0xaa,0xfe,0x4f,0x52,0x24,0xf9,0xaf,0x4a,
+ 0xa9,0x52,0x91,0x94,0x25,0x29,0x55,0x52};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-catchup-and-exit-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-catchup-and-exit-up.xpm
new file mode 100644 (file)
index 0000000..a5d8ba6
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-summary-catchup-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-catchup-up.xbm
new file mode 100644 (file)
index 0000000..ca093e1
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x11,0x91,0x11,0x95,0x54,0x25,0x54,0x21,0x02,0x90,0x00,0x84,0xa0,0x0a,0x54,
+ 0x29,0x1b,0xb1,0x11,0x91,0x40,0x0a,0x4a,0x25,0x8a,0xa0,0x20,0x88,0x20,0x14,
+ 0x0e,0x22,0x9b,0x51,0xb7,0x99,0x20,0x14,0x0b,0x02,0x42,0xc1,0x22,0x28,0x14,
+ 0x92,0x48,0x45,0x51,0x19,0x11,0x11,0x14,0x42,0xaa,0x54,0x42,0x88,0x00,0x02,
+ 0x90,0x72,0xaa,0x56,0x15,0x71,0x11,0x17,0x42,0x3a,0x49,0x4b,0x28,0x49,0xa4,
+ 0x22,0x04,0x30,0x02,0x09,0xb1,0xdb,0x59,0xb5,0x15,0xa0,0xd3,0xff,0x40,0x05,
+ 0xbf,0x02,0x2a,0xd3,0x08,0x54,0x91,0x53,0x77,0x7f,0xc8,0xa9,0xd4,0x8a,0x62,
+ 0x22,0x86,0x35,0xc8,0x5b,0x4b,0x67,0x93,0xfd,0x91,0x39,0x24,0x18,0xff,0x7a,
+ 0x90,0x46,0xc5,0xcf,0x25,0x94,0x21,0xf1};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-catchup-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-catchup-up.xpm
new file mode 100644 (file)
index 0000000..9de9baf
--- /dev/null
@@ -0,0 +1,37 @@
+/* XPM */
+static char * icon-catchup2_xpm[] = {
+"32 32 2 1",
+"      c #000000000000",
+".     c #BFBFBFBFBFBF s backgroundToolBarColor",
+" ... ... ... ... ... ... ... ...",
+"................................",
+"................................",
+"................................",
+" ... ... ... ... ... ... ... ...",
+"................................",
+"................................",
+".................  .............",
+" ... ... ... ...   . ... ... ...",
+"................  ..............",
+"............... ................",
+"................................",
+" ... ... ... ... ... ... ... ...",
+"................................",
+"................................",
+".............  ..........  .....",
+" ... ... ...   . ... ...   . ...",
+"............  ..........  ......",
+"........... ........... ........",
+"............  .......... .......",
+" ... ... ... . . ... ... ... ...",
+"...............  .....          ",
+"................      ... ......",
+"........  ..... ... ...... .....",
+" ... ..   .. . . . .  .. .     .",
+".......  .... .... ... .. . ... ",
+"...... ...... ... .....  ... ...",
+"......    .. .... ......   .. ..",
+" ... ... .       ... ..  ..   ..",
+"........... ....      . ....   .",
+".......... ..... .....      .. .",
+".......... ..... ....... ...    "};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-exit-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-exit-up.xbm
new file mode 100644 (file)
index 0000000..4d55755
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x19,0x51,0x91,0x11,0x82,0x14,0x2a,0x48,0x28,0x42,0x40,0x25,0x82,0x10,0x15,
+ 0x00,0x59,0xfa,0xff,0x5b,0x12,0x4b,0xfe,0x21,0x40,0x21,0xf1,0x93,0x2a,0x0b,
+ 0xf8,0x05,0x91,0xb5,0xf2,0x31,0x24,0x01,0xf1,0x4b,0x12,0x54,0xfa,0x01,0x80,
+ 0x83,0xf0,0x55,0x5b,0x35,0xf2,0x11,0x00,0x8b,0xfe,0x4b,0x2a,0x21,0xf7,0x21,
+ 0x80,0x0b,0xf6,0x13,0x5b,0xb5,0xf4,0x59,0x10,0x03,0xf1,0x01,0x42,0x2b,0xf4,
+ 0x55,0x90,0x40,0xf3,0x03,0x13,0x1a,0xf8,0x59,0xa8,0x83,0xf2,0x11,0x02,0x2b,
+ 0x5c,0x43,0x50,0xe3,0xee,0x10,0x93,0xfc,0x55,0x5b,0x48,0x92,0x92,0x00,0x22,
+ 0x49,0x48,0xaa,0x08,0x00,0x84,0x00,0xb5,0xbb,0x31,0x5b,0x01,0x00,0x0a,0x00,
+ 0x54,0x25,0x51,0x55,0x01,0x48,0x04,0x00};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-exit-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-exit-up.xpm
new file mode 100644 (file)
index 0000000..d1ab26a
--- /dev/null
@@ -0,0 +1,37 @@
+/* XPM */
+static char * icon-exit-summary_xpm[] = {
+"32 32 2 1",
+"      c #000000000000",
+".     c #BFBFBFBFBFBF s backgroundToolBarColor",
+" ... ... ... ... ... ... ... ...",
+"................................",
+"................................",
+"................................",
+" ... ......              ... ...",
+"........  .......        .......",
+"........ ...........     .......",
+"........  ..........     .......",
+" ... ... ... .......     ... ...",
+"................ ...     .......",
+"....................     .......",
+"........  ..........     .......",
+" ... ... ... .......     ... ...",
+"........  .......  .     .......",
+"........ .......   .     .......",
+"........  .......  .     .......",
+" ... ... ... .......     ... ...",
+"........  ..........     .......",
+"........ ...........     .......",
+"................ ...     .......",
+" ... ....... .......     ... ...",
+"........  ..........     .......",
+"........  ........   . . .......",
+"........ ....   . . . . ........",
+" ... .. ..       . . . . ... ...",
+"................................",
+"................................",
+"................................",
+" ... ... ... ... ... ... ... ...",
+"................................",
+"................................",
+"................................"};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-followup-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-followup-up.xbm
new file mode 100644 (file)
index 0000000..c6ba686
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x00,0x00,0x40,0x08,0xb6,0x76,0x37,0x63,0x20,0x02,0x00,0x04,0x8a,0x48,0x55,
+ 0x51,0x10,0x22,0x0e,0x82,0xa6,0xaa,0xa9,0x36,0x12,0x62,0x38,0x20,0xa0,0x18,
+ 0x96,0x4a,0x0a,0x07,0x17,0x00,0xa2,0x01,0xa3,0x76,0x6a,0x80,0x60,0x00,0x60,
+ 0x00,0x40,0x55,0x52,0x00,0x40,0x00,0xa6,0x00,0x80,0x6b,0x90,0xe1,0x80,0x04,
+ 0x24,0x9a,0x00,0x51,0x82,0x86,0x01,0x85,0xaa,0x61,0x01,0x32,0x60,0x70,0x01,
+ 0x42,0x1d,0x30,0x02,0x14,0x04,0x08,0x02,0x4c,0x06,0x00,0x02,0x28,0x06,0x00,
+ 0x04,0xac,0x08,0x00,0x08,0x0b,0x0a,0x00,0xc8,0x22,0x12,0x00,0x70,0x6a,0x1a,
+ 0x00,0x10,0x01,0x20,0x00,0x60,0x52,0x32,0x00,0x20,0x08,0x46,0x00,0x40,0x63,
+ 0x50,0x00,0x40,0x04,0x85,0x00,0x80,0x52};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-followup-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-followup-up.xpm
new file mode 100644 (file)
index 0000000..3cee12e
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-summary-followup-with-original-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-followup-with-original-up.xbm
new file mode 100644 (file)
index 0000000..a0e6dfe
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x04,0x40,0x10,0x00,0xa3,0x36,0xa6,0x76,0x54,0x40,0x11,0x02,0x01,0x2a,0x88,
+ 0x48,0x54,0x81,0x22,0x22,0x22,0x6a,0xaa,0x2a,0x4a,0x02,0x21,0xa0,0x90,0x50,
+ 0x8e,0x0a,0x02,0x0a,0x27,0x50,0xb2,0xa2,0xab,0x26,0x42,0xaa,0x00,0x92,0x94,
+ 0x00,0xaa,0x20,0x00,0xaa,0x00,0x85,0xb6,0x22,0x76,0x32,0x20,0xea,0x80,0x44,
+ 0x8a,0x98,0x2a,0x11,0x10,0x87,0x00,0x44,0xa6,0x71,0x6b,0x33,0x60,0xcc,0x22,
+ 0x44,0x1d,0xe3,0x0a,0x11,0xc8,0xe0,0x24,0x44,0x3e,0x90,0x6c,0x2b,0x08,0x00,
+ 0x09,0xa0,0x06,0x00,0x49,0x0a,0x04,0x00,0x92,0x50,0x0b,0x00,0x32,0x26,0x0c,
+ 0x00,0xa4,0x90,0x11,0x00,0x24,0x24,0x14,0x00,0xc8,0x82,0x22,0x00,0x48,0x32,
+ 0x2a,0x00,0x90,0x42,0x50,0x00,0x90,0x28};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-followup-with-original-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-followup-with-original-up.xpm
new file mode 100644 (file)
index 0000000..baffb6b
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-copy-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-copy-up.xbm
new file mode 100644 (file)
index 0000000..a1eea6b
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x00,0x20,0x20,0x40,0xaa,0x8a,0x0a,0x15,0xfe,0xff,0xff,0x27,0x0e,0x00,0x80,
+ 0x4d,0x32,0x00,0x60,0x04,0xc2,0x00,0x18,0x54,0x02,0x03,0x06,0x04,0x03,0x8c,
+ 0x01,0x54,0x02,0x74,0x02,0x04,0x02,0x03,0x0c,0x54,0x82,0x00,0x10,0x84,0xf2,
+ 0xff,0xff,0x3f,0x52,0x00,0x00,0x6c,0x9b,0x01,0x00,0x23,0x16,0x06,0xc0,0x60,
+ 0x1e,0x18,0x30,0x20,0x14,0x60,0x0c,0xa0,0x11,0xa0,0x0b,0x20,0x14,0x10,0x30,
+ 0x60,0x11,0x0c,0x40,0x20,0x14,0x02,0x80,0xa0,0x12,0x01,0x00,0x23,0xd8,0x00,
+ 0x00,0x64,0x32,0x00,0x00,0x38,0xf8,0xff,0xff,0xbf,0x02,0x00,0x40,0x24,0x54,
+ 0x55,0x15,0x11,0x01,0x00,0x40,0x44,0x54,0x55,0x15,0x11,0x01,0x00,0x40,0x44,
+ 0x54,0x55,0x05,0x11,0x02,0x00,0x50,0x44};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-copy-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-copy-up.xpm
new file mode 100644 (file)
index 0000000..e73e6d5
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-delete-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-delete-up.xbm
new file mode 100644 (file)
index 0000000..9d1c637
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x08,0x00,0x80,0x00,0xa2,0xaa,0x2a,0x54,0x08,0x00,0x40,0x81,0xf2,0xab,0x2a,
+ 0x28,0x5c,0x03,0x80,0x82,0x2d,0x56,0xf5,0x28,0x84,0x06,0x98,0x8b,0x5d,0x5e,
+ 0xe7,0x2c,0x1c,0x1f,0x1f,0xba,0xf1,0xf3,0xa7,0xc9,0x44,0xa8,0x90,0x88,0xf1,
+ 0xf3,0x8b,0x08,0x1c,0x5f,0x7f,0x09,0xad,0x1e,0xff,0x08,0x04,0x46,0x08,0x04,
+ 0xae,0x26,0x06,0x04,0x18,0x8b,0x02,0x06,0xfa,0x23,0xc1,0x01,0x20,0x88,0x38,
+ 0x00,0x95,0x62,0x07,0x80,0x40,0xe4,0x00,0x40,0x14,0xd1,0x00,0x20,0x42,0x44,
+ 0x03,0x60,0x10,0x11,0x05,0x10,0x4a,0x44,0x1c,0xa8,0x00,0x11,0x61,0x0c,0x2a,
+ 0x42,0xa4,0x25,0x81,0x14,0x09,0x42,0x14,0x20,0x50,0x15,0xa1,0x4a,0x05,0x40,
+ 0x04,0x00,0xa8,0x0a,0x51,0x55,0x05,0x50};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-delete-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-delete-up.xpm
new file mode 100644 (file)
index 0000000..932d8f2
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-forward-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-forward-up.xbm
new file mode 100644 (file)
index 0000000..1b66f5b
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x10,0x42,0x80,0x20,0x84,0x10,0x2a,0x14,0x3a,0xa5,0x40,0x41,0x64,0x08,0x14,
+ 0x28,0xd6,0xa0,0x62,0x85,0x80,0x15,0xe8,0x20,0xca,0x41,0x39,0x8b,0xb0,0x2a,
+ 0x24,0x22,0xd2,0x86,0x12,0x86,0x58,0x24,0x11,0x2c,0xd2,0x8c,0x08,0x98,0x34,
+ 0x75,0x08,0x10,0x30,0x14,0x08,0x60,0x8a,0x0e,0x04,0x20,0x10,0x05,0xfc,0x7f,
+ 0x45,0x02,0x02,0x60,0x10,0x01,0x03,0x18,0xca,0xe0,0x01,0x44,0x20,0x3e,0x00,
+ 0x0a,0xf4,0x21,0x00,0x53,0x32,0x20,0x80,0x80,0x10,0x10,0x40,0x2a,0x2a,0x10,
+ 0xb0,0x80,0x60,0x10,0x28,0x2a,0xea,0x10,0x84,0x40,0x81,0x10,0x2a,0x14,0x94,
+ 0x11,0x41,0x21,0x21,0xca,0x2a,0x48,0x84,0xac,0x80,0x02,0x21,0x3d,0x54,0x50,
+ 0x14,0x84,0x00,0x05,0x42,0x21,0xaa,0x50};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-forward-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-forward-up.xpm
new file mode 100644 (file)
index 0000000..19db803
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-get-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-get-up.xbm
new file mode 100644 (file)
index 0000000..0d0e212
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x48,0x00,0x11,0x02,0x12,0x54,0x84,0x50,0x40,0x81,0x50,0x82,0x2a,0x28,0x0a,
+ 0x28,0x80,0x42,0xa0,0x82,0xaa,0x13,0x3d,0x28,0x40,0x46,0xd4,0x42,0xb5,0x28,
+ 0x86,0x10,0x50,0xda,0x51,0x47,0x99,0xb0,0x09,0x13,0x14,0x50,0x01,0x45,0x21,
+ 0x18,0x82,0x21,0x74,0x4c,0xc7,0x94,0x81,0x13,0x78,0x02,0x94,0x44,0x05,0x29,
+ 0xf1,0xff,0xff,0x7f,0x74,0x00,0x00,0x2c,0x91,0x01,0x00,0x23,0x14,0x06,0xc0,
+ 0xa0,0x11,0x18,0x30,0x20,0x14,0x60,0x0c,0x60,0x12,0x90,0x0b,0x20,0x18,0x0c,
+ 0x30,0xa0,0x12,0x02,0x40,0x20,0x18,0x01,0x80,0xa0,0xd2,0x00,0x00,0x23,0x38,
+ 0x00,0x00,0x64,0x12,0x00,0x00,0x38,0xf8,0xff,0xff,0xbf,0x02,0x00,0x00,0x20,
+ 0xa8,0xaa,0xaa,0x8a,0x05,0x00,0x40,0x20};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-get-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-get-up.xpm
new file mode 100644 (file)
index 0000000..ffdb84c
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-originate-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-originate-up.xbm
new file mode 100644 (file)
index 0000000..6d25e12
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x04,0x42,0x08,0x10,0xa1,0x10,0x42,0x05,0x14,0xa2,0xff,0xaf,0x01,0x89,0x00,
+ 0x14,0x54,0xa4,0x00,0x64,0x02,0xc1,0x00,0x3c,0xf8,0xff,0x1f,0xa0,0x6d,0x10,
+ 0x68,0x20,0xf8,0xff,0x1f,0x60,0x12,0x84,0x00,0x20,0x48,0xd1,0x00,0xa0,0x02,
+ 0x88,0xfc,0x21,0xfc,0xff,0x00,0x60,0x1e,0x80,0x6c,0x21,0x64,0x80,0x00,0xa0,
+ 0x86,0x81,0x00,0x20,0x04,0x86,0x00,0x60,0x05,0x98,0x00,0x20,0x04,0xe4,0x00,
+ 0xa0,0x06,0x83,0x80,0x25,0x84,0x80,0x00,0x60,0x46,0x80,0x00,0x20,0x34,0x80,
+ 0x00,0xa0,0x0d,0x80,0xff,0x3f,0x04,0x00,0x00,0x2e,0xfe,0xff,0xff,0x4f,0x48,
+ 0x92,0x44,0x12,0x92,0x08,0x11,0x44,0x00,0x21,0x44,0x11,0x55,0x48,0x21,0x44,
+ 0x80,0x02,0x8a,0x10,0x2a,0xa8,0x40,0x44};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-originate-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-originate-up.xpm
new file mode 100644 (file)
index 0000000..8ba8bc2
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-reply-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-reply-up.xbm
new file mode 100644 (file)
index 0000000..e16ec66
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x00,0x40,0x40,0x20,0xaa,0x2a,0x7a,0x0a,0x00,0x80,0x88,0x51,0xaa,0x2a,0x06,
+ 0x06,0x00,0xc0,0x05,0x58,0xaa,0x3a,0x12,0x08,0x00,0x0c,0x11,0x2c,0xaa,0x03,
+ 0x09,0x42,0xc0,0x80,0x04,0x06,0x35,0x40,0x04,0x57,0x98,0x49,0x80,0x18,0x3a,
+ 0x20,0x41,0x56,0xc8,0x10,0xc1,0x11,0x0c,0x93,0x60,0x50,0x0a,0x1c,0x18,0x90,
+ 0x08,0x30,0x06,0x30,0x0a,0xc8,0x05,0x90,0x08,0x06,0x18,0x30,0x0a,0x01,0x20,
+ 0x10,0x88,0x00,0x40,0x50,0x6a,0x00,0x80,0x11,0x19,0x00,0x00,0x52,0x0c,0x00,
+ 0x00,0x1c,0xf9,0xff,0xff,0x5f,0x44,0x44,0x44,0x24,0x11,0x11,0x11,0x09,0x44,
+ 0x44,0x44,0xa0,0x11,0x11,0x11,0x15,0x44,0x44,0x44,0x40,0x11,0x11,0x91,0x14,
+ 0x44,0x44,0x04,0xa2,0x11,0x22,0xa2,0x08};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-reply-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-reply-up.xpm
new file mode 100644 (file)
index 0000000..20fe672
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-save-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-save-up.xbm
new file mode 100644 (file)
index 0000000..0601dfb
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x00,0x10,0x10,0x00,0x55,0x45,0x45,0x55,0x00,0x10,0x08,0x00,0xd4,0xff,0xff,
+ 0x7f,0x82,0x03,0x00,0xf0,0xd0,0x0c,0x00,0x4c,0x82,0x30,0x00,0x43,0xd4,0xc0,
+ 0xc0,0x40,0x80,0x80,0x33,0xc0,0xaa,0x60,0xcc,0x40,0xc0,0x10,0x00,0x41,0x95,
+ 0x08,0x00,0x46,0xc0,0x06,0x00,0xd8,0xfe,0xff,0x0f,0x60,0x2c,0x00,0x0b,0x40,
+ 0x35,0x10,0xfd,0x7f,0x2c,0x02,0x2b,0x49,0x35,0x40,0x4d,0x12,0xac,0x00,0x0b,
+ 0xa0,0x35,0x00,0xad,0x0a,0x2c,0x24,0x09,0x90,0x2d,0x00,0x5d,0x25,0xf4,0xff,
+ 0x0b,0x80,0xa6,0x55,0xad,0x2a,0x4c,0xaa,0x08,0x40,0xf5,0xff,0x5d,0x15,0x6c,
+ 0x35,0x0b,0x20,0x66,0x37,0xab,0x4a,0x6c,0x2d,0x0d,0x00,0xb9,0x35,0x4b,0x55,
+ 0xf4,0xff,0x1f,0x80,0x01,0x40,0x80,0x2a};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-save-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-mail-save-up.xpm
new file mode 100644 (file)
index 0000000..fd4824b
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-summary-next-unread-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-next-unread-up.xbm
new file mode 100644 (file)
index 0000000..a6c17a9
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x08,0x10,0x20,0x00,0xa3,0x66,0xab,0x76,0x14,0x11,0x04,0x02,0x41,0x04,0xa1,
+ 0x48,0x14,0x51,0x1e,0x22,0x62,0xa6,0xa9,0x2a,0x0a,0x71,0x18,0xa0,0x40,0x18,
+ 0xb6,0x0a,0x8a,0x06,0x17,0x50,0xb2,0x01,0x63,0x27,0x62,0x80,0x20,0x90,0x50,
+ 0x00,0x40,0x25,0x4a,0x00,0x40,0x80,0xe2,0x00,0x80,0x36,0x12,0xe1,0x80,0x41,
+ 0x84,0x9a,0x00,0x29,0x10,0x87,0x01,0x85,0xa6,0x61,0x01,0x32,0x62,0x70,0x01,
+ 0x42,0x18,0x30,0x02,0x14,0x06,0x08,0x02,0x4c,0x06,0x00,0x02,0x28,0x04,0x00,
+ 0x04,0xac,0xca,0x07,0x7c,0x0b,0x68,0x0d,0xea,0x20,0x1b,0x12,0x93,0x6b,0xb4,
+ 0x54,0x29,0x03,0x91,0xba,0x95,0x51,0x74,0x19,0x53,0x0b,0x6a,0x0a,0xd6,0x62,
+ 0xe0,0x07,0x7c,0x09,0x8a,0x00,0x80,0x42};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-next-unread-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-next-unread-up.xpm
new file mode 100644 (file)
index 0000000..e525816
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-summary-post-news-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-post-news-up.xbm
new file mode 100644 (file)
index 0000000..8eb4c33
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x00,0x10,0x10,0x01,0x6b,0xa7,0x66,0x72,0x04,0x10,0x02,0x05,0xa1,0x8a,0x50,
+ 0x48,0x04,0x20,0x8f,0x20,0x72,0xab,0x39,0x2b,0x02,0x64,0x58,0xa4,0x50,0x19,
+ 0x16,0x01,0x0a,0x06,0x57,0x54,0xe2,0x01,0x23,0x23,0x72,0x80,0x20,0x94,0x44,
+ 0x00,0x40,0x01,0x50,0x00,0xc0,0x54,0xa6,0x00,0x80,0x22,0x92,0x00,0x80,0x4a,
+ 0x40,0x01,0x00,0x11,0x8a,0x01,0x00,0x45,0x32,0x02,0x00,0x2a,0x42,0x02,0x00,
+ 0xa2,0x10,0x05,0x00,0x0c,0x4a,0x06,0x00,0x24,0x22,0x0a,0x00,0x68,0xaa,0x0c,
+ 0x00,0x0c,0x00,0x11,0x80,0x53,0x2a,0x14,0x40,0x05,0x22,0x23,0x70,0x62,0x92,
+ 0x34,0x0e,0x09,0x24,0xc0,0x4b,0x52,0x80,0x0a,0x21,0x80,0x6b,0x62,0xaa,0x36,
+ 0x04,0x15,0x01,0x42,0x51,0x80,0xa8,0x28};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-post-news-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-post-news-up.xpm
new file mode 100644 (file)
index 0000000..46be7c1
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-summary-prev-unread-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-prev-unread-up.xbm
new file mode 100644 (file)
index 0000000..6cf240e
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x08,0x08,0x40,0x20,0x23,0x63,0x2b,0x2b,0x54,0x14,0x24,0xa4,0x01,0x02,0x09,
+ 0x01,0x54,0xa9,0x2e,0x2a,0x22,0xa2,0xa9,0x62,0x4a,0x6a,0x18,0x12,0x90,0x18,
+ 0xb6,0x04,0x02,0x06,0x17,0x50,0xea,0x01,0x63,0x2b,0x64,0x80,0x20,0x44,0x51,
+ 0x00,0x40,0x21,0x44,0x00,0x40,0x8a,0xe2,0x00,0xc0,0x22,0x0a,0xe1,0xc0,0x2f,
+ 0xd0,0x9f,0x20,0x4d,0x42,0x87,0xb1,0x1a,0xea,0x61,0x15,0x72,0x60,0x70,0xbb,
+ 0x14,0x1d,0x30,0xb1,0x5a,0x04,0x08,0x22,0x0d,0x06,0x00,0xc2,0x6f,0x06,0x00,
+ 0x84,0x20,0x08,0x00,0x64,0x0a,0x0a,0x00,0x58,0x50,0x12,0x00,0x10,0x27,0x1a,
+ 0x00,0x50,0x90,0x20,0x00,0xa0,0x24,0x32,0x00,0x20,0x82,0x26,0x00,0xc0,0x32,
+ 0x40,0x00,0x40,0x44,0xaa,0x00,0x80,0x11};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-prev-unread-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-prev-unread-up.xpm
new file mode 100644 (file)
index 0000000..b2088fb
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-summary-reply-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-reply-up.xbm
new file mode 100644 (file)
index 0000000..61dad9a
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x10,0x00,0x11,0x88,0x45,0x55,0x84,0x22,0x08,0x80,0x10,0x88,0x42,0x55,0xa4,
+ 0x22,0x28,0x00,0x01,0x84,0x05,0x55,0x5a,0x21,0x50,0x00,0x35,0x8a,0x09,0xf5,
+ 0xc2,0x20,0x24,0x18,0x81,0x85,0x01,0x87,0x00,0x2a,0xd4,0x41,0x00,0x43,0x61,
+ 0x40,0x80,0x17,0x1c,0x20,0x80,0x58,0xb5,0x1a,0xc0,0x3f,0x0c,0x08,0x60,0xb0,
+ 0x75,0x08,0xb0,0x2e,0x84,0x04,0xb8,0xa1,0x06,0x03,0x4c,0x20,0x04,0x0c,0x36,
+ 0x60,0x06,0x10,0x0f,0x20,0x06,0x70,0x07,0x60,0x05,0xc8,0x09,0xa0,0x04,0x04,
+ 0x10,0xa0,0x06,0x02,0x20,0x60,0x85,0x01,0xc0,0xa0,0x44,0x00,0x00,0x61,0x25,
+ 0x00,0x00,0x22,0x1e,0x00,0x00,0xbc,0x0e,0x00,0x00,0x70,0xfd,0xff,0xff,0x3f,
+ 0x94,0x52,0x55,0x55,0x4a,0x29,0x22,0xa2};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-reply-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-reply-up.xpm
new file mode 100644 (file)
index 0000000..255f7a1
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-summary-reply-with-original-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-reply-with-original-up.xbm
new file mode 100644 (file)
index 0000000..37b0d73
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x00,0x08,0x00,0x20,0xaa,0x82,0xaa,0x4a,0x00,0x54,0x00,0x00,0xaa,0x02,0x54,
+ 0x55,0x00,0xa8,0x07,0x00,0x54,0x85,0x5a,0x55,0x02,0x50,0x32,0x80,0x50,0x25,
+ 0xc2,0x2a,0x02,0x18,0x81,0x41,0x54,0x17,0x01,0x17,0x80,0x09,0xc1,0x23,0x75,
+ 0x04,0x3d,0x4f,0x18,0xc3,0x83,0x18,0x85,0x40,0xc0,0x61,0x4c,0x7c,0x60,0x30,
+ 0xf6,0x23,0xb0,0x6e,0x84,0x20,0x98,0x21,0x05,0x13,0x5c,0x20,0x04,0x1c,0x36,
+ 0x60,0x06,0x30,0x0f,0x60,0x06,0x70,0x07,0xa0,0x05,0xc8,0x09,0x20,0x06,0x04,
+ 0x10,0x60,0x04,0x02,0x20,0xa0,0x85,0x01,0xc0,0x20,0x46,0x00,0x00,0xa1,0x24,
+ 0x00,0x00,0x62,0x1e,0x00,0x00,0x7c,0x0d,0x00,0x00,0xb0,0xfc,0xff,0xff,0x3f,
+ 0x55,0x55,0x4a,0x55,0x24,0x89,0x52,0xa2};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-reply-with-original-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-reply-with-original-up.xpm
new file mode 100644 (file)
index 0000000..1135bfa
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-summary-save-article-file-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-save-article-file-up.xbm
new file mode 100644 (file)
index 0000000..a14e003
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x20,0x08,0x08,0x82,0x8a,0x82,0xa2,0x20,0x20,0x14,0x04,0x15,0x14,0xfd,0xff,
+ 0x43,0x42,0x04,0x00,0x0d,0x10,0x05,0x00,0x49,0x22,0x06,0x00,0x31,0x88,0x04,
+ 0x00,0x1f,0x22,0x06,0x00,0x50,0x88,0x04,0x00,0x10,0x22,0x04,0x00,0xb0,0x88,
+ 0x06,0x00,0x10,0x22,0x04,0x00,0x50,0xfc,0xff,0x0f,0x10,0x36,0x00,0x0b,0xb0,
+ 0x2c,0x02,0x0d,0x10,0x34,0x10,0x0b,0x50,0x2d,0x00,0x0b,0x10,0x34,0x41,0x0d,
+ 0xb0,0x2d,0x08,0x09,0x10,0x34,0x00,0x0b,0x50,0x2d,0x01,0x0d,0x10,0xf4,0xff,
+ 0x0b,0xb0,0xad,0xda,0x0a,0x10,0x44,0x22,0x0d,0x50,0xf6,0xff,0xf9,0x1f,0x6c,
+ 0x3b,0x4b,0x52,0xb5,0x2d,0x1d,0x08,0x6c,0x35,0x4b,0xa1,0x6a,0x3b,0x29,0x14,
+ 0xf8,0xff,0x8f,0x40,0x02,0x40,0x2a,0x15};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-save-article-file-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-save-article-file-up.xpm
new file mode 100644 (file)
index 0000000..ea30122
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-summary-save-article-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-save-article-up.xbm
new file mode 100644 (file)
index 0000000..94e51d1
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x10,0x81,0x04,0x01,0x45,0x28,0x40,0x50,0x88,0x42,0x15,0x05,0xa2,0xff,0xff,
+ 0x7f,0x88,0x03,0x00,0xf0,0xa2,0x0c,0x00,0x4c,0x88,0x30,0x00,0x43,0xc5,0xc0,
+ 0xc0,0x40,0x90,0x80,0x33,0xc0,0xa4,0x60,0xcc,0x40,0x82,0x10,0x00,0x41,0xd0,
+ 0x08,0x00,0x46,0x82,0x06,0x00,0xd8,0xfc,0xff,0x0f,0x60,0x2e,0x00,0x0d,0x40,
+ 0x34,0x02,0xfb,0x7f,0x36,0x10,0x0d,0x91,0xac,0x00,0x4b,0x24,0x34,0x00,0x2d,
+ 0x81,0x2d,0x48,0x4b,0x28,0x34,0x02,0x0d,0x85,0x2d,0x00,0xab,0x20,0xf4,0xff,
+ 0x0d,0x8a,0xa6,0xaa,0xaa,0x20,0x4c,0x55,0x0a,0x85,0xf5,0xff,0x5b,0x20,0x6c,
+ 0x35,0x8d,0x8a,0xad,0x36,0x2b,0x20,0xf4,0x2a,0x89,0x8a,0x6a,0x3b,0x5d,0x20,
+ 0xf8,0xff,0x0f,0x85,0x02,0x40,0xa2,0x20};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-summary-save-article-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-summary-save-article-up.xpm
new file mode 100644 (file)
index 0000000..fd4824b
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-uu-decode-uu-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-uu-decode-uu-up.xbm
new file mode 100644 (file)
index 0000000..705eb76
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x00,0x08,0x10,0x01,0xaa,0x42,0x45,0x54,0x00,0x14,0x10,0x01,0x55,0x41,0x45,
+ 0x50,0x00,0x0a,0x88,0x0a,0xaa,0xa0,0x22,0x40,0x80,0xff,0xff,0x17,0xaa,0x95,
+ 0x54,0x43,0x80,0x2a,0xa5,0x0a,0xaa,0xfd,0x7f,0x53,0xc0,0x06,0x40,0x06,0x94,
+ 0x04,0x40,0x43,0xc2,0x05,0xc0,0x2a,0x90,0x86,0xc0,0x06,0xa2,0x64,0x4b,0x53,
+ 0x88,0x96,0x44,0x06,0xd2,0x45,0xc0,0x52,0x84,0x25,0xc1,0x06,0x90,0xe6,0x41,
+ 0x53,0x8a,0x05,0x42,0x06,0xa0,0x06,0xc4,0x52,0x95,0x04,0xc0,0x06,0xc0,0x05,
+ 0x40,0x53,0x94,0x06,0x40,0x06,0xa2,0x05,0xc0,0x52,0x88,0xfc,0xff,0x06,0xa2,
+ 0x95,0x12,0x53,0x88,0x4a,0xa9,0x06,0xa2,0xff,0xff,0x53,0x90,0x10,0x00,0x04,
+ 0x42,0x42,0x55,0x50,0x14,0x28,0x80,0x0a};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-uu-decode-uu-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-uu-decode-uu-up.xpm
new file mode 100644 (file)
index 0000000..568315c
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus-uu-post-news-up.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus-uu-post-news-up.xbm
new file mode 100644 (file)
index 0000000..e0528e9
--- /dev/null
@@ -0,0 +1,12 @@
+#define noname_width 32
+#define noname_height 32
+static char noname_bits[] = {
+ 0x11,0x11,0x19,0x51,0x4a,0x95,0x82,0x14,0x20,0x40,0x29,0x42,0x0a,0xd5,0x86,
+ 0x10,0x31,0x31,0x3b,0x53,0x08,0x9d,0xe8,0x10,0xa2,0x43,0x82,0x4b,0x88,0xff,
+ 0xff,0x03,0xb3,0xaa,0x54,0xbb,0x88,0x55,0xaa,0x02,0xa2,0xfc,0x7f,0x4b,0x88,
+ 0x06,0xc0,0x12,0xb1,0x05,0x40,0x56,0x8a,0x05,0x40,0x03,0xd0,0x86,0xc0,0xaa,
+ 0x85,0x64,0x4b,0x06,0xb1,0x95,0xc4,0x32,0x8a,0x46,0x40,0x4b,0xd0,0x24,0x41,
+ 0x03,0x84,0xe6,0xc1,0x56,0xd9,0x05,0x42,0x12,0x82,0x04,0x44,0x4b,0x94,0x07,
+ 0xc0,0x22,0xc1,0x04,0x40,0x16,0x95,0x05,0xc0,0x52,0xa0,0x06,0x40,0x13,0x8a,
+ 0xfd,0xff,0x46,0xd0,0x94,0x52,0x12,0x93,0x29,0xa5,0x5a,0xa4,0xff,0xff,0x03,
+ 0x10,0x02,0x08,0x55,0x85,0xa8,0xa2,0x00};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus-uu-post-news-up.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus-uu-post-news-up.xpm
new file mode 100644 (file)
index 0000000..f4a7e3a
--- /dev/null
@@ -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/xemacs-packages/gnus/etc/images/gnus/gnus.png b/xemacs-packages/gnus/etc/images/gnus/gnus.png
new file mode 100644 (file)
index 0000000..f497993
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/gnus.png differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus.svg b/xemacs-packages/gnus/etc/images/gnus/gnus.svg
new file mode 100644 (file)
index 0000000..021841c
--- /dev/null
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Gnu Emacs Logo
+
+   Copyright (C) 2008-2016 Free Software Foundation, Inc.
+
+   Author: Francesc Rocher <francesc.rocher@gmail.com>
+
+   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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+-->
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   id="svg2182"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   width="260.05341"
+   height="264.41125"
+   version="1.0"
+   sodipodi:docname="gnus.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:docbase="/home/rocher/local/fret/devel/emacs/etc/images/gnus"
+   style="display:inline">
+  <metadata
+     id="metadata2166">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <cc:license
+           rdf:resource="http://www.gnu.org/copyleft/gpl.html" />
+        <dc:title>gnus</dc:title>
+        <dc:date>2008/06/28</dc:date>
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Francesc Rocher</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:rights>
+          <cc:Agent>
+            <dc:title>GPL</dc:title>
+          </cc:Agent>
+        </dc:rights>
+        <dc:description>gnus splash image</dc:description>
+        <cc:license
+           rdf:resource="http://www.gnu.org/copyleft/gpl.html" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <sodipodi:namedview
+     inkscape:window-height="768"
+     inkscape:window-width="872"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0.0"
+     guidetolerance="10.0"
+     gridtolerance="10.0"
+     objecttolerance="10.0"
+     borderopacity="1.0"
+     bordercolor="#666666"
+     pagecolor="#ffffff"
+     id="base"
+     inkscape:zoom="2.0914389"
+     inkscape:cx="130.0267"
+     inkscape:cy="132.20563"
+     inkscape:window-x="1620"
+     inkscape:window-y="48"
+     inkscape:current-layer="layer1"
+     showgrid="false" />
+  <defs
+     id="defs2184" />
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-212.83046,-131.30737)">
+    <path
+       style="fill:#ffcc00;fill-opacity:1"
+       d="M 260.5116,393.86288 C 262.4558,387.05826 267.2179,379.59417 297.5589,335.79513 C 319.8161,303.66546 330.6302,287.20557 331.3011,284.43711 C 333.0433,277.24717 333.8671,278.40273 332.422,286.00932 C 331.6536,290.05378 330.814,293.91798 330.5562,294.59643 C 329.9147,296.28421 263.0752,392.98791 261.2542,394.86288 C 259.97,396.18503 259.882,396.06646 260.5116,393.86288 z M 329.012,337.40194 C 329.012,329.74759 337.5126,308.05531 346.2698,293.36288 C 352.585,282.76738 356.0658,278.66265 357.6327,279.96306 C 360.1959,282.09035 360.2435,284.91669 357.7795,288.68079 C 348.0751,303.50587 344.2235,309.82445 343.039,312.86288 C 342.2885,314.78788 339.997,319.28788 337.9468,322.86288 C 335.8965,326.43788 333.6994,331.01438 333.0643,333.03289 C 331.7287,337.27788 329.012,340.20698 329.012,337.40194 z M 433.7142,310.70702 C 432.4323,301.35502 439.5948,263.14948 445.9643,245.36288 C 453.3999,224.59932 462.3035,187.01802 464.5939,166.7291 C 466.2806,151.78888 466.39427,150.80924 464.5937,145.48334 C 462.93203,140.5683 461.13308,138.66246 458.2794,135.86712 L 453.27086,132.20754 L 456.6769,131.86288 C 461.6112,131.86288 468.5389,137.86276 471.5396,144.73501 C 475.9375,154.80727 469.1008,193.79566 457.4889,224.86288 C 456.1527,228.43788 453.9429,236.08788 452.5782,241.86288 C 451.2135,247.63788 449.3929,254.61288 448.5324,257.36288 C 446.2294,264.72267 441.012,292.37437 441.012,297.21983 C 441.012,299.89703 439.8131,303.91285 437.6813,308.3766 L 434.3507,315.35061 L 433.7142,310.70702 z M 365.0631,287.61288 C 364.3799,285.87462 364.6166,285.04955 366.1039,283.98525 C 369.6205,281.46876 374.6693,273.55113 384.4649,255.19145 C 394.0909,237.14958 397.4834,232.60267 396.4281,239.15726 C 396.1442,240.92035 395.6983,243.71288 395.4372,245.36288 C 395.1761,247.01288 393.3158,250.83788 391.3032,253.86288 C 389.2906,256.88788 384.5367,265.43788 380.7391,272.86288 C 376.9414,280.28788 373.1295,287.15038 372.2681,288.11288 C 370.0173,290.62794 366.1425,290.35905 365.0631,287.61288 z M 320.6995,262.21705 C 320.3213,261.83892 320.0085,256.09205 320.0042,249.44621 C 319.9968,237.8214 319.8735,237.11784 316.7542,230.90534 C 314.6707,226.75574 312.0521,223.33733 309.4273,221.34075 L 305.3427,218.23371 L 307.5276,215.04493 L 309.7126,211.85615 L 312.2239,214.18355 C 318.5615,220.05696 320.0866,224.73813 320.89,240.78293 C 321.2726,248.42216 321.9363,253.34314 322.6144,253.56709 C 323.5922,253.89002 325.7193,249.88561 329.6283,240.36288 C 330.5606,238.09183 330.8754,237.84885 330.924,239.36288 C 331.0132,242.14152 328.403,251.64049 326.3917,255.85659 C 325.4718,257.78505 324.4153,260.0111 324.0441,260.80336 C 323.2442,262.51029 321.6616,263.17921 320.6995,262.21705 z M 245.1628,252.33639 C 242.7335,250.29224 242.012,248.8836 242.012,246.18509 L 242.012,242.68509 L 245.0499,245.24139 C 247.4506,247.26142 248.7618,247.66988 251.2999,247.18844 C 261.6191,245.23115 277.1998,234.54682 293.4888,218.25787 C 305.9223,205.82438 308.2914,205.51694 300.9064,217.2953 C 297.7695,222.29833 293.4637,226.68597 282.6564,235.89191 C 268.2506,248.16321 260.2183,253.05838 252.4128,254.32337 C 248.8949,254.8935 247.867,254.6118 245.1628,252.33639 z M 253.5564,224.18379 C 252.8479,221.3612 255.3686,216.65779 265.7868,201.36288 C 274.8859,188.00461 280.3419,181.70108 281.3091,183.42939 C 282.2829,185.16947 280.4642,188.16253 267.644,205.91868 C 262.7666,212.67391 257.7486,220.13306 256.493,222.49457 C 254.2534,226.70659 254.1976,226.73871 253.5564,224.18379 z M 384.1421,211.31896 C 380.7719,208.48314 379.5828,205.79041 380.4684,203.00013 C 381.0442,201.18604 381.1572,201.18566 384.7957,202.98583 C 389.6343,205.37981 394.2581,204.2146 402.3056,198.57322 C 408.5766,194.17721 413.0548,188.59621 417.4561,179.69171 C 419.3087,175.94368 420.7236,174.19872 421.6285,174.54597 C 423.516,175.27026 422.6184,178.34159 417.0017,190.37802 C 413.2533,198.41088 411.2578,201.35952 406.9201,205.27556 C 397.3226,213.94009 389.6701,215.97043 384.1421,211.31896 z M 349.133,205.78403 C 347.8246,205.26039 339.6679,197.95186 331.007,189.54285 C 314.4595,173.47664 311.9119,171.8466 303.3959,171.87654 C 296.4656,171.9009 295.032,172.81115 290.3019,180.19054 L 285.7873,187.23384 L 284.2923,183.79836 C 283.47,181.90885 282.4863,179.27759 282.1062,177.95112 C 281.7262,176.62464 280.6639,175.42908 279.7456,175.2943 C 278.8273,175.15952 276.1491,173.50192 273.794,171.61075 C 271.4389,169.71957 268.6984,167.88177 267.7041,167.52675 C 265.0385,166.57501 258.442,170.33611 255.7003,174.37086 C 252.3997,179.22817 236.1965,193.87325 232.3241,195.49923 C 229.2026,196.80994 224.2969,196.49006 220.8863,194.75342 C 219.99224,194.29815 217.81391,191.671 216.04559,188.91531 L 212.83046,183.90496 L 214.80788,178.98414 C 217.15719,174.46058 217.72614,175.73223 218.2264,179.21246 C 219.18564,185.88569 227.68275,189.64961 233.5992,186.55932 C 236.89108,184.8399 252.69001,170.52231 255.8597,166.33149 C 257.20184,164.55698 260.1603,162.00113 262.5471,160.73493 C 266.7567,158.50172 266.9938,158.48379 270.4593,160.13637 C 275.6317,162.60292 282.7604,169.52516 284.1848,173.46442 C 284.8607,175.33358 285.6949,176.86288 286.0385,176.86288 C 287.1145,176.86288 290.7063,172.50475 292.4119,169.12981 C 295.3372,163.34131 302.301,161.46605 311.3959,164.01764 C 314.6954,164.9433 318.6863,168.30161 331.512,180.94492 C 344.6932,193.93873 348.2487,196.90999 351.6941,197.81043 C 358.8294,199.67523 363.2588,198.02956 373.0854,189.86288 C 374.0781,189.03788 375.8498,185.88788 377.0226,182.86288 C 379.1772,177.30564 381.012,174.43132 381.012,176.61327 C 381.012,179.76831 373.6837,197.57365 371.7267,199.17339 C 363.2349,206.11521 361.752,206.86338 356.6119,206.7995 C 353.8069,206.76463 350.4414,206.30768 349.133,205.78403 z M 433.3755,165.01518 C 432.4887,162.66574 432.7313,161.09102 434.7622,156.01518 C 436.967,150.50427 437.5192,149.86288 440.0588,149.86288 C 443.1917,149.86288 445.26134,150.88627 443.04984,151.7349 C 442.27424,152.03251 440.6717,155.12671 440.0503,158.04922 C 439.1073,162.48386 436.241,167.86288 434.8209,167.86288 C 434.6171,167.86288 433.9667,166.58142 433.3755,165.01518 z "
+       id="path2180"
+       sodipodi:nodetypes="csssssccssssssccssscccsssssccccsssssssccsscccccsssssscccccsssssccssssccsssssssccsscccssssssscccssssssssssssssssccsssssc" />
+    <path
+       style="fill:#bf9900;fill-opacity:1"
+       d="M 260.04229,388.62496 C 260.04229,388.26779 262.41982,381.75886 265.3257,374.16067 L 270.60912,360.34578 L 302.0757,315.68057 C 319.38233,291.1147 333.61856,271.09097 333.71178,271.18339 C 333.80501,271.27582 333.11629,275.17516 332.1813,279.84861 L 330.48132,288.34578 L 296.61135,337.34578 C 264.11074,384.3647 260.04229,390.06972 260.04229,388.62496 z M 335.05416,340.71822 C 335.08273,332.59962 342.90077,312.31861 351.0582,299.20165 C 361.32924,282.68606 362.26372,281.87063 364.84686,287.16962 C 366.25843,290.0653 369.41495,290.67354 372.08298,288.56398 C 375.51683,285.84889 380.03165,278.64484 389.67374,260.49539 C 395.24604,250.00657 400.36753,241.23737 401.05483,241.00827 C 402.01257,240.68902 402.13639,241.96455 401.58489,246.46875 C 401.0637,250.72541 399.8145,254.01845 397.05407,258.4125 C 394.95789,261.7492 390.67229,269.6242 387.5305,275.9125 C 384.38872,282.2008 380.31753,289.451 378.48342,292.02406 C 376.64931,294.59711 373.9974,298.97426 372.59029,301.75106 C 368.67817,309.47125 362.50895,311.98005 358.85614,307.33625 C 357.77044,305.95601 356.44994,305.09384 355.9217,305.42031 C 354.21874,306.4728 350.06567,313.70826 348.00838,319.20686 C 346.90756,322.14908 344.70815,326.53397 343.1208,328.95106 C 341.53346,331.36816 339.66859,335.26362 338.97666,337.60766 C 338.28473,339.95169 337.11643,342.36929 336.38044,342.9801 C 335.30763,343.87046 335.04464,343.42196 335.05416,340.71822 z M 426.51573,311.58247 C 424.295,305.9694 431.46333,266.71003 438.975,243.34578 C 449.77938,209.73992 452.64775,197.05569 454.04936,176.68519 C 454.96702,163.34843 454.96666,163.3447 452.25475,157.85768 C 449.80808,152.90735 449.07425,152.22791 444.7659,150.92392 C 437.56998,148.74594 435.05822,150.01328 433.02221,156.8493 C 431.37096,162.3935 429.09988,166.84578 427.92306,166.84578 C 427.57209,166.84578 426.72504,165.4941 426.04074,163.84204 C 424.90188,161.09259 425.14703,160.10787 428.93648,152.21044 C 436.06395,137.3564 443.83129,130.05358 450.98168,131.48366 C 456.22602,132.53253 462.61341,139.07407 464.61888,145.44997 C 466.30125,150.79865 466.29973,151.75864 464.58462,167.19573 C 463.13938,180.20371 461.75469,186.94649 457.46738,201.85317 C 454.53978,212.03223 451.15045,222.60723 449.93555,225.35317 C 446.1278,233.95946 435.54286,279.84531 433.44365,296.84578 C 432.61201,303.58079 427.5826,314.27908 426.51573,311.58247 z M 321.70896,253.17911 C 321.34229,252.81245 321.03695,247.97495 321.03042,242.42911 C 321.01146,226.31633 317.22788,216.41482 309.49941,212.25276 C 307.59799,211.22878 306.04229,210.18189 306.04229,209.92634 C 306.04229,208.49277 316.49525,193.84578 317.51833,193.84578 C 319.99152,193.84578 326.75558,199.72182 328.49015,203.37716 C 333.52767,213.99294 332.83118,233.93705 326.98086,246.59578 C 323.69212,253.71184 323.04713,254.51728 321.70896,253.17911 z M 244.54744,244.71616 C 240.09276,240.8049 240.10279,238.80779 244.62887,228.50779 C 251.12687,213.72028 279.13707,173.54057 281.38247,175.78597 C 282.70155,177.10505 279.80235,182.49237 274.46237,188.64499 C 269.3537,194.5311 259.18508,209.65448 255.66693,216.5987 C 252.14831,223.54384 252.80477,226.43547 258.23185,227.89683 C 260.41964,228.48594 263.56598,228.67004 265.22372,228.30593 C 271.51092,226.92503 284.00526,217.92955 300.05241,203.23049 C 301.68769,201.73258 303.03384,201.22253 303.91486,201.76703 C 306.03123,203.07502 296.56646,216.17624 288.01264,223.77902 C 271.80417,238.18538 260.40653,245.44918 251.29744,247.17791 C 248.61178,247.6876 247.44854,247.26336 244.54744,244.71616 z M 385.05208,203.08715 C 383.14399,202.1294 380.92795,200.16456 380.12756,198.72084 C 378.77163,196.27507 378.93462,195.50718 382.51548,187.47084 C 386.47833,178.57722 388.11251,177.21384 390.15681,181.09578 C 392.28002,185.12758 395.18904,185.76578 402.36307,183.77366 C 406.32748,182.67281 414.04229,176.5005 414.04229,174.42959 C 414.04229,172.88138 419.26037,164.84578 420.26573,164.84578 C 421.92875,164.84578 420.892,169.30215 417.54229,176.55216 C 415.61729,180.71857 414.04229,184.60238 414.04229,185.18286 C 414.04229,189.11353 400.4626,201.51494 394.28759,203.2235 C 393.0475,203.56662 391.24279,204.06811 390.27712,204.33793 C 389.31144,204.60775 386.96018,204.0449 385.05208,203.08715 z M 351.04229,197.71284 C 348.53009,196.99762 343.02663,192.26267 331.54229,180.93585 C 318.71242,168.28195 314.72677,164.92651 311.42627,164.00055 C 302.33137,161.44895 295.36758,163.32421 292.44224,169.11271 C 290.73664,172.48766 287.1448,176.84578 286.06886,176.84578 C 285.72522,176.84578 284.89106,175.31648 284.21516,173.44732 C 282.79071,169.50806 275.66202,162.58582 270.4896,160.11927 C 267.0241,158.46669 266.78705,158.48462 262.5774,160.71783 C 260.19059,161.98404 257.18126,164.50249 255.89001,166.31439 C 252.89963,170.51055 237.46336,184.53731 233.62954,186.54223 C 229.94244,188.47042 223.46343,187.71137 220.79008,185.03803 C 219.53025,183.77819 218.15867,179.73726 216.94597,173.71255 C 215.909,168.56083 214.85791,163.44578 214.61023,162.34578 C 214.36254,161.24578 214.77878,159.51283 215.5352,158.49477 C 216.86599,156.70366 217.03603,156.7143 220.78906,158.82362 C 222.92227,160.02255 225.74927,162.75363 227.07128,164.8927 C 229.98826,169.61248 233.49513,170.68159 238.2193,168.2913 C 243.83735,165.44874 252.09545,158.65646 255.73355,153.88584 C 261.53439,146.27922 267.01031,140.89191 269.60251,140.24131 C 270.95713,139.90132 274.42274,140.39104 277.30387,141.32958 C 281.31123,142.63498 283.68866,144.31886 287.42036,148.49485 L 292.29844,153.9537 L 294.13431,150.93486 C 296.60368,146.8743 304.74442,142.84578 310.48053,142.84578 C 318.1271,142.84578 324.55144,146.55377 334.0772,156.46527 C 338.7714,161.34955 343.75341,166.74716 345.14834,168.45995 C 354.26564,179.65481 368.97614,182.16041 374.81884,173.51365 C 376.07095,171.66063 378.24823,169.06481 379.65725,167.74515 L 382.2191,165.34578 L 381.49679,169.21635 C 380.17312,176.3093 374.99275,188.27876 372.22815,190.63193 C 364.00605,197.63042 357.90971,199.66799 351.04229,197.71284 z "
+       id="path2169" />
+  </g>
+</svg>
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus.xbm b/xemacs-packages/gnus/etc/images/gnus/gnus.xbm
new file mode 100644 (file)
index 0000000..58d1ac8
--- /dev/null
@@ -0,0 +1,622 @@
+#define noname_width 271
+#define noname_height 273
+static char noname_bits[] = {
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xff,0xff,0x7f,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x49,0xe0,0xff,
+ 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x97,0xaa,0x8a,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0x57,0x2a,0x41,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa9,0x52,0x16,0xfe,0x7f,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4a,0x49,0x05,
+ 0xf9,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x7f,0x95,0xaa,0x58,0xf4,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0x7f,0xa5,0x54,0x26,0xe1,0x7f,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x54,0x49,0x49,0xe4,0x7f,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x2a,0xa5,
+ 0x2a,0xd1,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2f,0xd5,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xaf,0x52,0x95,0x54,0xc4,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xab,
+ 0x24,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x57,0x29,0xa9,0x92,0x11,0x7f,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0x57,0xd5,0xfa,0xff,0xff,0xab,0xea,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x97,0x4a,0x55,0x2a,0x41,0x7f,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x25,0x29,0xe5,0xff,0xff,0x95,0xa4,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa7,0xa4,
+ 0x24,0xa5,0x14,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4a,0xa5,0xd4,0xff,
+ 0x3f,0x52,0xa9,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x29,0x55,0x55,0x55,0x41,0x7e,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+ 0xa9,0x54,0xea,0xff,0xdf,0x2a,0x55,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0x55,0x55,0x4a,0x49,0x12,0x7e,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0x7f,0x55,0xa5,0x92,0xff,0x23,0xa5,0x4a,0xd6,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa5,0xa4,0x94,0xaa,0x42,
+ 0x7d,0xff,0xff,0xff,0xff,0xff,0xff,0x9f,0x4a,0x2a,0xa9,0xff,0xad,0x92,0x24,
+ 0xa9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2a,
+ 0x95,0x52,0x52,0x29,0x7c,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x52,0x49,0x55,
+ 0xfe,0x91,0x54,0x55,0x55,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x7f,0x49,0x29,0x55,0x25,0x85,0x7c,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x4f,0x95,0xaa,0x92,0x7e,0x55,0x55,0xa9,0x4a,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2a,0x50,0x95,0xaa,0x24,0x7e,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0x57,0x2a,0x95,0x54,0x79,0x95,0x92,0x92,0x94,0xfc,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xb9,0x62,0x29,0x49,
+ 0x85,0x7c,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,0x49,0x49,0x95,0xba,0xa4,0x54,
+ 0xaa,0x52,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,
+ 0x1a,0xf8,0xa7,0xaa,0x22,0x7c,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0x55,0x52,
+ 0x2a,0x75,0x55,0xa5,0x24,0xa5,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xbf,0x5a,0xfd,0x57,0x92,0x94,0x7e,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0x4a,0x4a,0x55,0x49,0x89,0x92,0x94,0xaa,0x94,0xf4,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x1a,0xfc,0x2f,0x55,0x05,0x7c,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x55,0xa9,0x4a,0x55,0x2a,0x55,0x55,0x55,0x55,0xe5,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0x4e,0xfd,0x5f,
+ 0x29,0xa5,0x7c,0xff,0xff,0xff,0xff,0xff,0xff,0xa4,0x54,0x52,0x4a,0x55,0xa9,
+ 0xa4,0x24,0xa5,0x94,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x2f,0x1d,0xfe,0x3f,0x95,0x04,0x7c,0xff,0xfd,0xff,0xff,0xff,0x3f,0x49,0xa5,
+ 0x54,0xa9,0xa4,0x92,0x4a,0x49,0x4a,0x55,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xaf,0x44,0xfe,0x5f,0xa9,0x52,0x7d,0xff,0xe5,0xff,0xff,
+ 0xff,0x5f,0x55,0x92,0x2a,0x95,0x52,0x4a,0x52,0xaa,0x52,0x4a,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x97,0x16,0xff,0xbf,0x4a,0x05,0x7c,
+ 0xff,0xd9,0xff,0xff,0xff,0x5f,0x95,0x42,0xa5,0x52,0x95,0xaa,0xaa,0xaa,0x94,
+ 0x54,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x57,0x43,0xfe,
+ 0xbf,0x54,0x52,0x7d,0x7f,0x25,0xff,0xff,0xff,0xa7,0xa4,0x28,0x92,0x54,0x4a,
+ 0xa5,0x4a,0x92,0xaa,0x4a,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xab,0x12,0xfe,0x7f,0xa5,0x02,0x7c,0x7f,0x55,0xfd,0xff,0xff,0x95,0x2a,
+ 0x82,0x54,0xa5,0x54,0x2a,0xa9,0x2a,0xa5,0x52,0xf5,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x27,0x4b,0xff,0xff,0x4a,0x29,0x7d,0xff,0x92,0xfe,
+ 0xff,0xff,0x55,0x92,0x20,0xa8,0x94,0x2a,0xa5,0x94,0x52,0x29,0xa9,0xf4,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x97,0x01,0xff,0x7f,0x52,0x42,
+ 0x7c,0xff,0x25,0xf9,0xff,0x7f,0xaa,0x02,0x8a,0x40,0x29,0x49,0x09,0x41,0x4a,
+ 0x55,0x25,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x57,0x57,
+ 0xff,0xff,0x95,0x12,0x7d,0xff,0xa9,0xfa,0xff,0x7f,0x25,0xa9,0x20,0x2a,0xa5,
+ 0xaa,0x42,0x92,0x54,0x92,0x54,0x95,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xaf,0x83,0xff,0xff,0xa9,0x42,0x7e,0xff,0xaa,0xf4,0xff,0xaf,0x54,
+ 0x01,0x82,0x80,0xaa,0x54,0x14,0x08,0xa2,0xaa,0x4a,0xd2,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xef,0xcf,0xd7,0xff,0xff,0x52,0x12,0x7f,0xff,0x4a,
+ 0xea,0xff,0x57,0x92,0xaa,0x28,0x24,0x29,0x25,0x81,0x82,0x08,0x49,0x52,0x55,
+ 0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xff,0xdf,0xef,0xe7,0xff,0xff,0x2a,
+ 0x05,0x7e,0xff,0x55,0xd5,0xff,0xa5,0x2a,0x00,0x8e,0x10,0x4a,0x89,0x24,0x28,
+ 0xa0,0xaa,0x2a,0x49,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xff,0xe7,0xff,
+ 0xef,0xff,0xff,0xa5,0x50,0x7e,0xff,0x25,0xe5,0xff,0x2a,0xa5,0x52,0x7f,0x85,
+ 0x54,0x35,0x08,0x82,0x0a,0x55,0x95,0xaa,0xfc,0xff,0xff,0xff,0xcf,0xff,0xff,
+ 0xff,0xff,0xd7,0xff,0xff,0xff,0x7f,0x52,0x85,0x7e,0xff,0xab,0x94,0x1e,0x55,
+ 0x2a,0xc8,0xff,0x10,0x90,0x92,0xa0,0x08,0x20,0x24,0x52,0x25,0xfd,0xff,0xff,
+ 0xff,0xef,0xff,0xff,0xff,0xff,0xe9,0xff,0xff,0xff,0xff,0x94,0x10,0x7e,0xff,
+ 0x93,0xaa,0x6a,0x49,0x49,0xf2,0xff,0x85,0x52,0x09,0x0a,0xa2,0x4a,0x92,0x29,
+ 0xa9,0xf2,0xff,0xff,0xff,0xd3,0xff,0xff,0xff,0xff,0xeb,0xff,0xff,0xff,0x7f,
+ 0x55,0x25,0x7f,0xff,0x55,0x49,0x49,0x95,0x0a,0xf9,0xff,0x17,0x48,0x26,0x50,
+ 0x08,0x00,0xa9,0x4a,0x95,0xfa,0xff,0xff,0xff,0xeb,0xff,0xff,0xff,0xff,0xf2,
+ 0xff,0xff,0xff,0xff,0x92,0x80,0x7e,0xff,0xa7,0x54,0xaa,0xa4,0x52,0xfc,0xff,
+ 0xaf,0x42,0x89,0xfa,0xbf,0x54,0x20,0xa9,0xa4,0xd4,0xff,0xff,0xff,0xcb,0xff,
+ 0xff,0xff,0xff,0xf5,0xff,0xff,0xff,0xff,0x54,0x29,0x7f,0xff,0x4b,0xa5,0x92,
+ 0x2a,0x01,0xff,0xff,0x1f,0xa8,0x22,0xff,0xff,0x01,0xa5,0x2a,0x55,0xa9,0xff,
+ 0xff,0xff,0xd4,0xff,0xff,0xff,0x7f,0xfa,0xff,0xff,0xff,0x7f,0xa5,0x04,0x7f,
+ 0xff,0x57,0x2a,0x55,0xa9,0x54,0xfe,0xff,0x3f,0x05,0x89,0xff,0xff,0x5f,0x48,
+ 0x92,0x2a,0x95,0xff,0xff,0xff,0xea,0xff,0xff,0xff,0xff,0xd2,0xff,0xff,0xff,
+ 0x7f,0x2a,0x91,0x7f,0xff,0xa9,0x54,0x4a,0x52,0x02,0xff,0xff,0xff,0x50,0xd1,
+ 0xff,0xff,0x1f,0x81,0xaa,0xa4,0x52,0xfe,0xff,0x3f,0xe9,0xff,0xff,0xff,0x7f,
+ 0x1d,0xff,0xff,0xff,0xff,0x54,0x41,0x7f,0xff,0x93,0x92,0x52,0x95,0xc8,0xff,
+ 0xff,0xff,0x8b,0xc4,0xff,0xff,0x7f,0x24,0xa5,0x2a,0x49,0xf9,0xff,0x7f,0xd5,
+ 0xff,0xff,0xff,0xbf,0x4a,0xff,0xff,0xff,0xff,0x4a,0x14,0x7f,0xff,0x28,0xa5,
+ 0x94,0x2a,0xa0,0xff,0xff,0x7f,0x22,0xf0,0xff,0xff,0x7f,0x12,0x94,0xa4,0xaa,
+ 0xea,0xff,0xaf,0xea,0xff,0xff,0xff,0x5f,0x8e,0xff,0xff,0xff,0x7f,0xa9,0x40,
+ 0x7f,0xff,0x48,0x55,0x55,0x12,0xca,0xff,0xff,0xff,0x0a,0xf5,0xff,0xff,0xff,
+ 0x80,0x52,0x95,0x54,0xaa,0xfe,0x55,0xc4,0xff,0xff,0xff,0x5f,0xa5,0xff,0xff,
+ 0xff,0xff,0x94,0x14,0x7f,0xff,0x52,0x2a,0xa9,0x4a,0xe1,0xff,0xff,0xbf,0x24,
+ 0xf0,0xff,0xff,0xff,0x0b,0x28,0xa9,0x92,0x24,0x55,0x49,0xe5,0xd7,0xff,0xff,
+ 0xa7,0x8a,0xff,0xff,0xff,0x7f,0xa5,0xc0,0x7f,0xff,0x50,0x49,0x95,0x04,0xf8,
+ 0xff,0xff,0x5f,0x1f,0xfd,0xff,0xff,0xff,0x47,0x45,0x55,0xaa,0xaa,0x4a,0xaa,
+ 0xea,0xaf,0xff,0xff,0x2b,0xc3,0xff,0xff,0xff,0x7f,0x55,0x94,0x7f,0x7f,0x4a,
+ 0x55,0x52,0x51,0xfe,0xff,0xff,0x5f,0x4e,0xf8,0xff,0xff,0xff,0x1f,0x50,0x92,
+ 0x52,0x49,0xa9,0x92,0xe4,0xd3,0xff,0xff,0x4b,0xd5,0xff,0xff,0xff,0xff,0x94,
+ 0xc0,0x7f,0x3f,0xa0,0xa4,0xaa,0x04,0xfe,0xff,0xff,0xa7,0x1d,0xfd,0xff,0xff,
+ 0xff,0x9f,0x84,0xaa,0x4a,0xaa,0x24,0x55,0xf2,0x2b,0xff,0x7f,0xa9,0xc1,0xff,
+ 0xff,0xff,0x7f,0x4a,0x95,0x7f,0xbf,0x2a,0x95,0x24,0x50,0xff,0xff,0xff,0x97,
+ 0x5e,0xfe,0xff,0xff,0xff,0x3f,0x92,0x24,0x95,0x92,0xaa,0xa4,0xf2,0xcb,0xff,
+ 0x5f,0xd5,0xe5,0xff,0xff,0xff,0xff,0x52,0x80,0x7f,0x3f,0xa0,0x52,0x15,0x85,
+ 0xff,0xff,0xff,0xd7,0x38,0xfe,0xff,0xff,0xff,0xff,0x20,0xaa,0x52,0x55,0x55,
+ 0x55,0xf9,0x29,0xfd,0xab,0xa4,0xf0,0xff,0xff,0xff,0x7f,0x29,0xa9,0x7f,0xff,
+ 0x42,0x25,0x49,0xe8,0xff,0xff,0xff,0x69,0x7a,0xff,0xff,0xff,0xff,0xff,0x82,
+ 0x52,0xaa,0x24,0x89,0x4a,0xf8,0x55,0x2a,0x49,0x95,0xf5,0xff,0xff,0xff,0xbf,
+ 0x2a,0xc4,0x7f,0x7f,0x90,0x54,0x15,0xe2,0xff,0xff,0xff,0x25,0xbc,0xff,0xff,
+ 0xff,0xff,0xff,0x29,0x48,0x49,0xaa,0xaa,0xa4,0xfa,0x95,0x92,0x54,0x52,0xf0,
+ 0xff,0xff,0xff,0xbf,0x4a,0xd1,0x7f,0xff,0x05,0xaa,0x40,0xf8,0xff,0xff,0x7f,
+ 0xaa,0xfc,0xff,0xff,0xff,0xff,0xff,0x43,0xa9,0xaa,0x4a,0x52,0xa9,0xf8,0xa4,
+ 0xaa,0x52,0x95,0xfc,0xff,0xff,0xff,0x7f,0x52,0xc0,0x7f,0xff,0xa1,0x00,0x24,
+ 0xfa,0xff,0xff,0xff,0x0a,0xfe,0xff,0xff,0xff,0xff,0xff,0x17,0x92,0x24,0xa5,
+ 0x2a,0x55,0xfe,0xaa,0xa4,0x2a,0x29,0xf9,0xff,0xff,0xff,0xbf,0x2a,0xea,0x7f,
+ 0xff,0x05,0x92,0x90,0xfc,0xff,0xff,0xbf,0xa4,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x4f,0xa0,0xaa,0x54,0x49,0x25,0x7c,0x49,0x95,0xa4,0x12,0xfc,0xff,0xff,0xff,
+ 0x7f,0x8a,0xe0,0x7f,0xff,0xa3,0x04,0x05,0xfe,0xff,0xff,0xbf,0x06,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0x1f,0x49,0x95,0x52,0xaa,0x12,0x7f,0x55,0x52,0x55,0x0a,
+ 0xfd,0xff,0xff,0xff,0x3f,0x29,0xe8,0x7f,0xff,0x0f,0x50,0x50,0xff,0xff,0xff,
+ 0x5f,0xca,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x04,0xa9,0x4a,0x25,0x45,0x3e,
+ 0xa9,0x2a,0xa9,0xa2,0xfc,0xff,0xff,0xff,0x7f,0x55,0xe1,0x7f,0xff,0x27,0x05,
+ 0xc4,0xff,0xff,0xff,0x9f,0x91,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x41,0x4a,
+ 0x29,0xa9,0x12,0x5e,0x95,0x94,0x4a,0x0a,0xfe,0xff,0xff,0xff,0xbf,0x12,0xf4,
+ 0x7f,0xff,0x8f,0x50,0xf1,0xff,0xff,0xff,0xa7,0xc2,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x14,0x92,0xaa,0x4a,0xa2,0xbf,0xa4,0x52,0x95,0x22,0xff,0xff,0xff,
+ 0xff,0x3f,0x45,0xf2,0x7f,0xff,0x3f,0x04,0xf4,0xff,0xff,0xff,0xd7,0xe8,0xff,
+ 0xff,0xff,0xff,0x5f,0xff,0xff,0x83,0xa8,0x94,0x54,0x09,0x2f,0x55,0x4a,0x52,
+ 0x49,0xff,0xff,0xff,0xff,0x5f,0x99,0xf0,0x7f,0xff,0x7f,0x51,0xfc,0xff,0xff,
+ 0xff,0x6b,0xf1,0xff,0xff,0xff,0xff,0x5f,0xfd,0xff,0x2b,0x2a,0xa9,0x12,0x20,
+ 0x5f,0xa9,0xaa,0x54,0x00,0xff,0xff,0xff,0xff,0x5f,0x15,0xf2,0x7f,0xff,0xff,
+ 0x8f,0xff,0xff,0xff,0xff,0x2b,0xfc,0xff,0xff,0xff,0xff,0x2f,0xfd,0xff,0x87,
+ 0xa0,0x4a,0xaa,0x8a,0x9f,0x4a,0x52,0x15,0xa9,0xff,0xff,0xff,0xff,0x5f,0x8a,
+ 0xfc,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x94,0xf8,0xff,0xff,0xff,0xff,
+ 0x57,0xf2,0xff,0x2f,0x82,0x52,0x05,0xd0,0x2f,0x95,0x4a,0x49,0x84,0xff,0xff,
+ 0xff,0xff,0xbf,0x24,0xf8,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x12,0xfd,
+ 0xff,0xff,0xff,0xff,0x4b,0xd5,0xff,0x9f,0x28,0x54,0x48,0xc5,0xbf,0x52,0x55,
+ 0x0a,0xe1,0xff,0xff,0xff,0xff,0x9f,0x4a,0xfa,0x7f,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x1a,0xfe,0xff,0xff,0xff,0xff,0x57,0xa9,0xff,0x3f,0x82,0x00,0x21,
+ 0xf0,0x5f,0x2a,0x49,0x21,0xc4,0xff,0xff,0xff,0xff,0xaf,0x1a,0xfd,0x7f,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x3f,0x85,0xff,0xff,0xff,0xff,0xff,0x29,0xa5,0xff,
+ 0xff,0x24,0x52,0x88,0xfc,0xbf,0x92,0x2a,0x09,0xf1,0xff,0xff,0xff,0xff,0x9f,
+ 0x4c,0xfc,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x15,0xff,0xff,0xff,0x7f,
+ 0xff,0xa5,0x4a,0xff,0xff,0x90,0x08,0x01,0xfe,0x3f,0x55,0x52,0x24,0xf4,0xff,
+ 0xff,0xff,0xff,0xaf,0x02,0xfd,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xc6,
+ 0xff,0xff,0xff,0xbf,0xfe,0x95,0x54,0xff,0xff,0x05,0x42,0xa8,0xfe,0xbf,0xa4,
+ 0x2a,0x41,0xf9,0xff,0xff,0xff,0xff,0x5f,0x55,0xfc,0x7f,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x4f,0xd0,0xff,0xff,0xff,0xbf,0x7c,0xaa,0x92,0xfc,0xff,0x53,0x08,
+ 0x01,0xff,0x1f,0x4a,0x01,0x04,0xfc,0xff,0xff,0xff,0xff,0x27,0x05,0xff,0x7f,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0xc5,0xff,0xff,0xff,0x4f,0xbf,0x52,0xaa,
+ 0xfe,0xff,0x07,0x42,0xea,0xff,0xbf,0x50,0x54,0x51,0xff,0xff,0xff,0xff,0xff,
+ 0x97,0x56,0xfe,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0xf0,0xff,0xff,0xff,
+ 0x2f,0x7f,0xa5,0x54,0xfd,0xff,0x3f,0x09,0xe0,0xff,0x1f,0x02,0x01,0x04,0xff,
+ 0xff,0xff,0xff,0xff,0xaf,0x02,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,
+ 0xf5,0xff,0xff,0xff,0xab,0x9f,0x94,0x92,0xfc,0xff,0xff,0x40,0xfd,0xff,0x9f,
+ 0x48,0x48,0xa1,0xff,0xff,0xff,0xff,0xff,0xa7,0x56,0xff,0x7f,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0x6b,0xf8,0xff,0xff,0xff,0xa4,0x5f,0xa9,0x2a,0xfd,0xff,0xff,
+ 0xff,0xff,0xff,0x3f,0x22,0x21,0xc4,0xff,0xff,0xff,0xff,0xff,0x2f,0x03,0xff,
+ 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x2b,0xfa,0xff,0xff,0x7f,0xd5,0x2f,0xa5,
+ 0xa4,0xfa,0xff,0xff,0xff,0xff,0xff,0xbf,0x08,0x08,0xf9,0xff,0xff,0xff,0xff,
+ 0xff,0x97,0x4a,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x94,0xfc,0xff,0xff,
+ 0x7f,0x69,0xac,0x2a,0x55,0xf9,0xff,0xff,0xff,0xff,0xff,0x7f,0xa2,0x22,0xf8,
+ 0xff,0xff,0xff,0xff,0xff,0x53,0x21,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x15,0xfe,0xff,0xff,0x9f,0x2a,0x95,0x94,0x92,0xf4,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0x08,0x88,0xfe,0xff,0xff,0xff,0xff,0xff,0x57,0x8b,0xff,0x7f,0xff,0xff,
+ 0xff,0xff,0xff,0x7f,0xa9,0xfe,0xff,0xff,0x5f,0x52,0xbc,0x52,0x55,0xf5,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x21,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,0xa1,
+ 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0x7f,0x0d,0xff,0xff,0xff,0x57,0x15,0x3f,
+ 0x55,0x49,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,0xc8,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xd7,0x89,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xbf,0xd6,0xff,0xff,
+ 0xff,0x4b,0x45,0x3f,0x49,0xaa,0xf4,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf9,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xc9,0xe2,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,
+ 0x3f,0x81,0xff,0xff,0xff,0x29,0x11,0x5f,0x28,0x55,0xf5,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xab,0xc8,0xff,0x7f,0xff,
+ 0xff,0xff,0xff,0xff,0x5f,0xd6,0xff,0xff,0x7f,0xaa,0xc2,0x0f,0x55,0x49,0xea,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa5,
+ 0xe2,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0x9f,0xe1,0xff,0xff,0xbf,0x4a,0xd1,
+ 0x5f,0x48,0xa5,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xe9,0xe0,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0x27,0xf4,0xff,
+ 0xff,0xbf,0x94,0xc4,0x07,0x91,0x2a,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xca,0xea,0xff,0x7f,0xff,0xff,0xff,0xff,
+ 0xff,0xaf,0xf1,0xff,0xff,0x9f,0x52,0xe0,0x4b,0x44,0x52,0xe9,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x6a,0xe0,0xff,0x7f,
+ 0xff,0xff,0xff,0xff,0xff,0x4b,0xfc,0xff,0xff,0xab,0x2a,0xf5,0x0f,0x51,0xa5,
+ 0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+ 0x69,0xe5,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0x55,0xf8,0xff,0xff,0x95,0x14,
+ 0xf0,0x5f,0x84,0x54,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0x7f,0x75,0xf0,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0x13,0xfd,
+ 0xff,0xff,0xa5,0x42,0xf9,0x7f,0x91,0x4a,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xb2,0xfa,0xff,0x7f,0xff,0xff,0xff,
+ 0xff,0xff,0x54,0xfe,0xff,0x7f,0x52,0x12,0xfa,0xff,0x20,0xa5,0xe4,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x34,0xf8,0xff,
+ 0x7f,0xff,0xff,0xff,0xff,0xff,0x25,0xff,0xff,0xaf,0xaa,0x48,0xfc,0xff,0x0b,
+ 0x29,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x7f,0xb5,0xf8,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0x52,0xff,0xff,0x2f,0x49,
+ 0x02,0xfe,0xff,0x43,0xaa,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0x3f,0x3a,0xfa,0xff,0x7f,0xff,0xff,0xff,0xff,0x7f,0x4a,
+ 0xff,0xff,0xa5,0x2a,0xa9,0xff,0xff,0x17,0x25,0xe9,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x9a,0xfc,0xff,0x7f,0xff,0xff,
+ 0xff,0xff,0xff,0x2a,0xff,0x7f,0x95,0x54,0x80,0xff,0xff,0x07,0xa9,0xea,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x1d,0xfc,
+ 0xff,0x7f,0xff,0xff,0xff,0xff,0x3f,0xa9,0xfe,0x7f,0xa9,0x12,0xe5,0xff,0xff,
+ 0x5f,0x4a,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0x5f,0xad,0xfe,0xff,0x7f,0xff,0xff,0xff,0xff,0x7f,0x95,0xea,0x97,0x54,
+ 0x4a,0xf0,0xff,0xff,0x1f,0xa8,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x5f,0x0e,0xfe,0xff,0x7f,0xff,0xff,0xff,0xff,0x5f,
+ 0x52,0x55,0xa9,0x92,0x02,0xfd,0xff,0xff,0x5f,0x53,0xf5,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0x5e,0xfe,0xff,0x7f,0xff,
+ 0xff,0xff,0xff,0xbf,0x2a,0x49,0x4a,0x55,0x49,0xfc,0xff,0xff,0x3f,0x94,0xf8,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2f,0x0f,
+ 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x4f,0xa5,0xaa,0x92,0xa4,0x20,0xff,0xff,
+ 0xff,0xbf,0xa4,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x5f,0x57,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x5f,0x52,0x52,0xaa,
+ 0x2a,0x0a,0xff,0xff,0xff,0x7f,0x54,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0x8f,0x07,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,
+ 0xa7,0x94,0x4a,0x55,0x4a,0xa0,0xff,0xff,0xff,0xff,0xa8,0xfa,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x57,0x57,0xff,0xff,0x7f,
+ 0xff,0xff,0xff,0xff,0x2f,0x55,0xa9,0x92,0x12,0xe9,0xff,0xff,0xff,0x7f,0x24,
+ 0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,
+ 0x87,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x57,0xa5,0x4a,0xaa,0x44,0xf4,0xff,
+ 0xff,0xff,0xff,0x55,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xa7,0xab,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xab,0x94,0xa4,
+ 0x92,0x12,0xf9,0xff,0xff,0xff,0xff,0xa8,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xab,0x83,0xff,0xff,0x7f,0xff,0xff,0xff,
+ 0xff,0x47,0xa9,0x2a,0x55,0x40,0xfc,0xff,0xff,0xff,0xff,0x25,0xf5,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xe7,0xff,0xff,0xff,0xff,0xff,0xd7,0x97,0xff,0xff,
+ 0x7f,0xff,0xff,0xff,0xff,0x33,0x55,0xa9,0x24,0x15,0xfe,0xff,0xff,0xff,0xff,
+ 0x95,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xeb,0xff,0xff,0xff,0xff,0xff,
+ 0x93,0xc3,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x57,0x25,0xa5,0x2a,0x40,0xff,
+ 0xff,0xff,0xff,0xff,0xa9,0xf4,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe3,0xff,
+ 0xff,0xff,0xff,0xff,0xe7,0xd5,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x4b,0x92,
+ 0x54,0x92,0xd4,0xff,0xff,0xff,0xff,0xff,0x55,0xf5,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xe9,0xff,0xff,0xff,0xff,0xff,0xd5,0xc1,0xff,0xff,0x7f,0xff,0xff,
+ 0xff,0xff,0x97,0xaa,0x4a,0x05,0xe2,0xff,0xff,0xff,0xff,0xff,0x25,0xf1,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xe3,0xfd,0xff,0xff,0xff,0xff,0xd5,0xea,0xff,
+ 0xff,0x7f,0xff,0xff,0xff,0xff,0x57,0x55,0x25,0xa1,0xf0,0xff,0xff,0xff,0xff,
+ 0xff,0x95,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe8,0xfa,0xff,0xff,0xff,
+ 0xff,0xea,0xe0,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xa7,0x24,0x59,0x04,0xfa,
+ 0xff,0xff,0xff,0xff,0xff,0xa9,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe2,
+ 0xfd,0xff,0xff,0xff,0xff,0xc9,0xe9,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x4f,
+ 0x52,0x05,0xa1,0xfc,0xff,0xff,0xff,0xff,0xff,0xa5,0xfa,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0x70,0xf9,0xff,0xff,0xff,0xff,0x74,0xe2,0xff,0xff,0x7f,0xff,
+ 0xff,0xff,0xff,0x47,0x95,0x92,0x04,0xff,0xff,0xff,0xff,0xff,0xff,0x95,0xf8,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xe2,0xfa,0xff,0xff,0xff,0xff,0x72,0xe8,
+ 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x97,0xaa,0x20,0xd0,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x55,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xb8,0xfc,0xff,0xff,
+ 0xff,0xff,0xea,0xe2,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x07,0x04,0x82,0xc2,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0x29,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+ 0x71,0xfd,0xff,0xff,0xff,0x7f,0x2a,0xf8,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,
+ 0x4f,0x91,0x28,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,0xfc,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0x1f,0x54,0xfe,0xff,0xff,0xff,0x7f,0x75,0xf2,0xff,0xff,0x7f,
+ 0xff,0xff,0xff,0xff,0x27,0x44,0x82,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0x29,
+ 0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0xb8,0xfc,0xff,0xff,0xff,0xbf,0x14,
+ 0xf1,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x0f,0x11,0x20,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0x55,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x9a,0xfe,0xff,
+ 0xff,0xff,0x7f,0x5a,0xf8,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x5f,0x40,0x85,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x09,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x4f,0x2d,0xfd,0xff,0xff,0xff,0x9f,0x12,0xf9,0xff,0xff,0x7f,0xff,0xff,0xff,
+ 0xff,0x3f,0x14,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0xfe,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0x07,0xa6,0xfe,0xff,0xff,0xff,0x5f,0x4d,0xfa,0xff,0xff,
+ 0x7f,0xff,0xff,0xff,0xff,0xff,0x40,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x09,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2b,0x4b,0xfe,0xff,0xff,0xff,0xbf,
+ 0x2c,0xf8,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xf5,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0x43,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x57,0xff,
+ 0xff,0xff,0xff,0x5f,0x0a,0xfe,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x89,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xd5,0xa9,0xff,0xff,0xff,0xff,0xaf,0x5a,0xfc,0xff,0xff,0x7f,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa3,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x81,0x95,0xff,0xff,0xff,0xff,0x9f,0x06,0xfd,0xff,
+ 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xc9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xca,0xa5,0xff,0xff,0xff,0xff,
+ 0x2f,0x95,0xfc,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xc1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0xea,
+ 0xff,0xff,0xff,0xff,0xaf,0x26,0xfe,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd5,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0x7f,0xf5,0xf4,0xff,0xff,0xff,0xff,0xaf,0x86,0xfe,0xff,0xff,0x7f,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc1,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x7f,0x70,0xe5,0xff,0xff,0xff,0xff,0x4f,0x2e,0xfe,
+ 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xb2,0xfa,0xff,0xff,0xff,
+ 0xff,0x57,0x83,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xf3,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x78,
+ 0xf2,0xff,0xff,0xff,0xff,0xa7,0x22,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x5f,0x5d,0xfd,0xff,0xff,0xff,0xff,0x97,0x87,0xff,0xff,0xff,0x7f,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x3c,0xfd,0xff,0xff,0xff,0xff,0x53,0xa3,
+ 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0xac,0xfe,0xff,0xff,
+ 0xff,0xff,0x57,0x95,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,
+ 0x9e,0xfe,0xff,0xff,0xff,0xff,0x97,0x81,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xa7,0x57,0xfe,0xff,0xff,0xff,0xff,0xa9,0xa5,0xff,0xff,0xff,
+ 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0xaf,0xff,0xff,0xff,0xff,0xff,0x4b,
+ 0x89,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xab,0x93,0xff,0xff,
+ 0xff,0xff,0xff,0x95,0xa2,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x83,0xab,0xff,0xff,0xff,0xff,0xff,0xd3,0xc8,0xff,0xff,0xff,0x7f,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xff,
+ 0xff,0xff,0xff,0xff,0xe9,0xa5,0xff,0xff,0xff,0xff,0xff,0xa5,0xe1,0xff,0xff,
+ 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0xd5,0xff,0xff,0xff,0xff,0xff,
+ 0xd5,0xc8,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xea,0xea,0xff,
+ 0xff,0xff,0xff,0xff,0x14,0xc1,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xff,0xff,0xff,0xff,
+ 0xff,0xe0,0xe4,0xff,0xff,0xff,0xff,0xff,0x65,0xe8,0xff,0xff,0xff,0x7f,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcf,
+ 0xff,0xff,0xff,0xff,0x3f,0x72,0xe9,0xff,0xff,0xff,0xff,0xff,0x6a,0xe1,0xff,
+ 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xef,0xff,0xff,0xff,0xff,0xbf,0xb8,0xfa,0xff,0xff,0xff,0xff,
+ 0xff,0x52,0xea,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd3,0xff,0xff,0xff,0xff,0x1f,0x7a,0xf5,
+ 0xff,0xff,0xff,0xff,0x7f,0x2a,0xe0,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xeb,0xff,0xff,0xff,
+ 0xff,0x8f,0x58,0xfa,0xff,0xff,0xff,0xff,0x7f,0x25,0xf5,0xff,0xff,0xff,0x7f,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xb5,0xff,0xff,0xdf,0xff,0x57,0x5e,0xfd,0xff,0xff,0xff,0xff,0xff,0x34,0xe0,
+ 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xca,0xff,0xff,0x8f,0xff,0x07,0xac,0xfc,0xff,0xff,0xff,
+ 0xff,0x7f,0x2a,0xf5,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd4,0xff,0xff,0x57,0xff,0x2b,0x2d,
+ 0xfd,0xff,0xff,0xff,0xff,0xff,0xb2,0xf0,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd2,0xff,0xff,
+ 0x07,0xff,0x43,0x4a,0xff,0xff,0xff,0xff,0xff,0xbf,0x2a,0xf8,0xff,0xff,0xff,
+ 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x3f,0xc5,0xff,0xff,0x2b,0xfe,0x08,0xab,0xfe,0xff,0xff,0xff,0xff,0x7f,0xaa,
+ 0xf2,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xbf,0xea,0xff,0xff,0x83,0x36,0x20,0x55,0xff,0xff,0xff,
+ 0xff,0xff,0x3f,0x15,0xf0,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4f,0xc2,0xff,0xff,0x48,0x4a,0x85,
+ 0x49,0xff,0xff,0xff,0xff,0xff,0x7f,0x59,0xfa,0xff,0xff,0xff,0x7f,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0xf5,0xff,
+ 0x7f,0x10,0x29,0x50,0xa5,0xff,0xff,0xff,0xff,0xff,0x3f,0x15,0xf9,0xff,0xff,
+ 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0x97,0xe4,0xff,0x7f,0x05,0x95,0x42,0xd5,0xff,0xff,0xff,0xff,0xff,0x7f,
+ 0x35,0xfc,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xab,0xea,0xff,0xbf,0xa0,0x24,0xa8,0xd4,0xff,0xff,
+ 0xff,0xff,0xff,0x7f,0x19,0xf9,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x27,0xe5,0xff,0x3f,0x92,0xaa,
+ 0x50,0xe9,0xff,0xff,0xff,0xff,0xff,0x9f,0x4a,0xfc,0xff,0xff,0xff,0x7f,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa9,0xe2,
+ 0xff,0x9f,0xa0,0xaa,0x2a,0xf5,0xff,0xff,0xff,0xff,0xff,0x5f,0x1a,0xf9,0xff,
+ 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x95,0xf8,0xff,0x5f,0x4a,0x92,0x4a,0xf5,0xff,0xff,0xff,0xff,0xff,
+ 0xbf,0x4a,0xfc,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x7f,0x52,0xf2,0xff,0x1f,0x20,0x49,0xa5,0xfa,0xff,
+ 0xff,0xff,0xff,0xff,0x5f,0x1a,0xfd,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaa,0xf8,0xff,0x47,0xa9,
+ 0x2a,0x29,0xf9,0xff,0xff,0xff,0xff,0xff,0xbf,0x0a,0xfc,0xff,0xff,0xff,0x7f,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x49,
+ 0xf2,0xff,0x17,0x92,0xaa,0xaa,0xfe,0xff,0xff,0xff,0xff,0xff,0x9f,0xac,0xfe,
+ 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x9f,0x2a,0xf8,0xff,0x43,0xa8,0x24,0x25,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xaf,0x0a,0xfc,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x94,0xfa,0xff,0x91,0x54,0xaa,0x52,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x2f,0x4d,0xfd,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2f,0x45,0xfc,0xff,0x03,
+ 0x92,0x52,0xaa,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x06,0xfc,0xff,0xff,0xff,
+ 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,
+ 0x12,0xfe,0xff,0x50,0xaa,0x2a,0x95,0xff,0xff,0xff,0xff,0xff,0xff,0x4f,0xa5,
+ 0xfe,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xa7,0x44,0xff,0xff,0x0a,0x25,0xa5,0xa4,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x97,0x06,0xfc,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2b,0x15,0xff,0xff,0x40,0xa9,0x92,0xea,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0x57,0x55,0xfd,0xff,0xff,0xff,0x7f,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0xa1,0xff,0x7f,
+ 0x92,0x4a,0xaa,0xd4,0xff,0xff,0xff,0xff,0xff,0xff,0x57,0x06,0xfc,0xff,0xff,
+ 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x95,0x8a,0xff,0x3f,0x84,0x54,0xa9,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0x2f,
+ 0x25,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0x52,0xe0,0xff,0xbf,0x50,0xa9,0x4a,0xf2,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xa7,0x8e,0xfe,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xa9,0xea,0xff,0x3f,0x24,0x95,0x54,
+ 0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0x57,0x23,0xfe,0xff,0xff,0xff,0x7f,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x4a,0xf0,0xff,
+ 0x9f,0x50,0x69,0x49,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0x4f,0x8b,0xff,0xff,
+ 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x7f,0xa5,0xf4,0xff,0x0f,0x2d,0x75,0xaa,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xaf,0x03,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0x9f,0x14,0xfa,0xff,0x2f,0xa8,0xfa,0x25,0xfd,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0x97,0xd7,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0xaa,0xfc,0xff,0x0f,0x4d,0xfd,
+ 0xa9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcf,0x83,0xff,0xff,0xff,0xff,0x7f,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x12,0xfc,
+ 0xff,0x27,0x92,0xfe,0xcb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd7,0xd7,0xff,
+ 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0x97,0x0a,0xff,0xff,0x83,0x56,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xef,0xc7,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xab,0x24,0xff,0xff,0x2b,0xaa,0xfe,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xe7,0xef,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,0x45,0xff,0xff,0x05,0x95,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe7,0xff,0xff,0xff,0xff,
+ 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x95,0x82,
+ 0xff,0xff,0x51,0xa9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,
+ 0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xa9,0xe8,0xff,0xff,0x85,0xca,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x7f,0x52,0xc1,0xff,0xff,0x90,0xd5,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x4d,0xe8,0xff,0xff,0xa5,
+ 0xe4,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x51,
+ 0xf2,0xff,0x7f,0x40,0xd5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x3f,0x95,0xf8,0xff,0x7f,0xa9,0xea,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0x4f,0x15,0xfa,0xff,0x3f,0xa4,0xf4,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0xa4,0xfc,0xff,0x7f,
+ 0x71,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2f,
+ 0x15,0xfe,0xff,0x3f,0x94,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xa7,0x0a,0xff,0xff,0x1f,0x79,0xf2,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xab,0xa4,0xff,0xff,0x5f,0x8c,0xfa,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x53,0x82,0xff,0xff,
+ 0x1f,0x5c,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xa4,0x92,0xff,0xff,0xbf,0x56,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0x9a,0xc4,0xff,0xff,0x0f,0x2e,0xfd,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa2,0xf0,0xff,0xff,0xaf,0xa7,0xfe,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x55,0xe4,0xff,
+ 0xff,0x0f,0x57,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xbf,0x54,0xf2,0xff,0xff,0x9f,0x4b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0x9f,0x92,0xf8,0xff,0xff,0xc7,0xab,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x15,0xfe,0xff,0xff,0x97,0xd7,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa7,0x94,0xfc,
+ 0xff,0xff,0xc7,0xe3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0x2f,0x05,0xfe,0xff,0xff,0xcf,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x53,0xa9,0xff,0xff,0xff,0xd3,0xeb,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,0x05,0xff,0xff,0xff,0xe3,
+ 0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x54,0xc2,
+ 0xff,0xff,0xff,0xeb,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x95,0xc8,0xff,0xff,0xff,0xf3,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x7f,0xa5,0xd2,0xff,0xff,0xff,0xff,0xf5,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xaa,0xe0,0xff,0xff,0xff,
+ 0xff,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x49,
+ 0xf8,0xff,0xff,0xff,0xff,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x9f,0x2a,0xf5,0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x4a,0xf8,0xff,0xff,0xff,0xff,0xfc,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0x14,0xfd,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x97,
+ 0x4a,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xab,0x04,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x95,0x52,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x53,0x85,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x54,0xa2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0x4a,0xc9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xa5,0xe0,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x94,0xe4,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x5f,0x55,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xbf,0x12,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4f,0x54,0xfa,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0x0a,0xfc,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0x53,0x45,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x97,0x14,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,0x45,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x54,0x82,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x4a,0xe9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0x52,0xc1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x55,0xe8,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x24,
+ 0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x7f,0x55,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x24,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x15,0xfe,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,
+ 0x49,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0x2f,0x95,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x01,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2f,0xd5,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x57,0x81,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0x97,0xd4,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0xe0,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x93,0xf4,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0x57,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x2b,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x89,0xfc,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0xfc,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x05,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0x49,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x89,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x7f,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xc1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xe9,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+ 0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0x9f,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xfc,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x6f,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xbf,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0x9f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f};
diff --git a/xemacs-packages/gnus/etc/images/gnus/gnus.xpm b/xemacs-packages/gnus/etc/images/gnus/gnus.xpm
new file mode 100644 (file)
index 0000000..b6ee4d0
--- /dev/null
@@ -0,0 +1,284 @@
+/* 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 s None 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/xemacs-packages/gnus/etc/images/gnus/important.xpm b/xemacs-packages/gnus/etc/images/gnus/important.xpm
new file mode 100644 (file)
index 0000000..e972fac
--- /dev/null
@@ -0,0 +1,32 @@
+/* XPM */
+static char *magick[] = {
+/* columns rows colors chars-per-pixel */
+"24 24 2  1",
+"! c red",
+"w c Gray75",
+/* pixels */
+"wwwwwwwwwwwwwwwwwwwwwwww",
+"wwwwwwwwwwwwwwwwwwwwwwww",
+"wwwwwwwww!!!wwwwwwwwwwww",
+"wwwwwwwww!!!wwwwwwwwwwww",
+"wwwwwwww!!!!!wwwwwwwwwww",
+"wwwwwwww!!!!!wwwwwwwwwww",
+"wwwwwww!!!!!!!wwwwwwwwww",
+"wwwwwww!!!!!!!wwwwwwwwww",
+"wwwwwww!!!!!!!wwwwwwwwww",
+"wwwwwww!!!!!!!wwwwwwwwww",
+"wwwwwww!!!!!!!wwwwwwwwww",
+"wwwwwww!!!!!!!wwwwwwwwww",
+"wwwwwww!!!!!!!wwwwwwwwww",
+"wwwwwwww!!!!!wwwwwwwwwww",
+"wwwwwwww!!!!!wwwwwwwwwww",
+"wwwwwwww!!!!!wwwwwwwwwww",
+"wwwwwwwww!!!wwwwwwwwwwww",
+"wwwwwwwwwwwwwwwwwwwwwwww",
+"wwwwwwwww!!!wwwwwwwwwwww",
+"wwwwwwww!!!!!wwwwwwwwwww",
+"wwwwwwww!!!!!wwwwwwwwwww",
+"wwwwwwwww!!!wwwwwwwwwwww",
+"wwwwwwwwwwwwwwwwwwwwwwww",
+"wwwwwwwwwwwwwwwwwwwwwwww"
+};
diff --git a/xemacs-packages/gnus/etc/images/gnus/kill-group.pbm b/xemacs-packages/gnus/etc/images/gnus/kill-group.pbm
new file mode 100644 (file)
index 0000000..5083144
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/kill-group.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/kill-group.xpm b/xemacs-packages/gnus/etc/images/gnus/kill-group.xpm
new file mode 100644 (file)
index 0000000..1ee4fa4
--- /dev/null
@@ -0,0 +1,30 @@
+/* XPM */
+static char * kill_group_xpm[] = {
+"24 24 3 1",
+".     c None",
+"o     c #000000000000",
+"+     c #9A9A6C6C4E4E",
+"o..o..o..o..o..o..o..o..",
+"........................",
+"........................",
+"o..o..o..o..o..o..o..o..",
+"........................",
+"........................",
+"o..o..o..o..++.o..o..o..",
+".......++..++++.........",
+"........++.+++..........",
+"o..o..o.+++++..o..o..o..",
+".........+++............",
+".........++++...........",
+"o..o..o.++++++.o..o..o..",
+"........++.++++.........",
+".......++...++++........",
+"o..o...+.o...++o..o..o..",
+"........................",
+"........................",
+"o..o..o..o..o..o..o..o..",
+"........................",
+"........................",
+"o..o..o..o..o..o..o..o..",
+"........................",
+"........................"};
diff --git a/xemacs-packages/gnus/etc/images/gnus/mail-reply.pbm b/xemacs-packages/gnus/etc/images/gnus/mail-reply.pbm
new file mode 100644 (file)
index 0000000..9ca7659
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/mail-reply.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/mail-reply.xpm b/xemacs-packages/gnus/etc/images/gnus/mail-reply.xpm
new file mode 100644 (file)
index 0000000..a87f784
--- /dev/null
@@ -0,0 +1,32 @@
+/* XPM */
+static char * mail_reply_xpm[] = {
+"24 24 5 1",
+"      c None",
+".     c #000000000000",
+"X     c #E1E1E0E0E0E0",
+"O     c #FFFFFFFFFFFF",
+"o     c #C7C7C6C6C6C6",
+"               ..       ",
+"               .X.      ",
+"              ..XX.     ",
+"         ......XoXX..   ",
+"       ...OOO.XooXXX.   ",
+"      ..OOOO.XooXXX.    ",
+"   ...OOOOO.XooXXX...   ",
+"  ..OOOOOO.XXooXX.OO..  ",
+"  ...OOOO.oooXXX......  ",
+"  .O...O.oXooXXX...OO.  ",
+"  .OOO...oXoXX...OOOO.  ",
+"  .OOOOO...X...OOOOOO.  ",
+"  .OOOOO.O...OO.OOOOO.  ",
+"  .OOO..OOOOOOOO..OOO.  ",
+"  .OO.OOOOOOOOOOOO.OO.  ",
+"  .O.OOOOOOOOOOOOOO.O.  ",
+"  ..OOOOOOOOOOOOOOOO..  ",
+"  ....................  ",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/gnus/mail-send.xpm b/xemacs-packages/gnus/etc/images/gnus/mail-send.xpm
new file mode 100644 (file)
index 0000000..f1d2282
--- /dev/null
@@ -0,0 +1,39 @@
+/* XPM */
+static char *magick[] = {
+/* columns rows colors chars-per-pixel */
+"24 24 9 1",
+"  c Gray0",
+". c #675e6580613e",
+"X c #8c8c7c7c6969",
+"o c #9b458d377822",
+"O c #a941a6459f3e",
+"+ c #c8c8b2b29898",
+"@ c #dadac2c2a5a5",
+"# c #eb4dea2fe4ad",
+"$ c None",
+/* pixels */
+"$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$    $$$$$$$",
+"$$$$$$$$     .@#+ $$$$$$",
+"$$$     .+#####@O $$$$$$",
+"$$ .+##########.+O $$$$$",
+"$$ @..########O.+# $$$$$",
+"$$ O@O..@#####.+## $$$$$",
+"$$$ ###+O.O##...##O $$$$",
+"$$$ @####@+..O#O.+# $$$$",
+"$$$ O####.#######.O $$$$",
+"$$$$ ###+O########.O $$$",
+"$$$$ ###.########@O  $$$",
+"$$$$ +#+O#####@O   $$$$$",
+"$$$$$ #.###@O     $$$$$$",
+"$$$$$ .O@O   $$ .. $$$$$",
+"$$$$$ ..  $$$$ .oo. $$$$",
+"$$$$$$  $$$$$   oo   $$$",
+"$$$$$$$$$$$$$$$ Oo $$$$$",
+"$$$$$$$$$$$$$$ oOOX $$$$",
+"$$$$$$$$$$$$$$ ++++ $$$$",
+"$$$$$$$$$$$$$ O@@@@O $$$",
+"$$$$$$$$$$$$$        $$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$"
+};
diff --git a/xemacs-packages/gnus/etc/images/gnus/next-ur.pbm b/xemacs-packages/gnus/etc/images/gnus/next-ur.pbm
new file mode 100644 (file)
index 0000000..678bbb0
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/next-ur.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/next-ur.xpm b/xemacs-packages/gnus/etc/images/gnus/next-ur.xpm
new file mode 100644 (file)
index 0000000..bea1328
--- /dev/null
@@ -0,0 +1,35 @@
+/* XPM */
+static char * next_ur_xpm[] = {
+"24 24 8 1",
+".     c None",
+"      c #000000000000",
+"X     c #A5A5A5A59595",
+"o     c #C7C7C6C6C6C6",
+"O     c #FFFF00000000",
+"+     c #9A9A6C6C4E4E",
+"@     c #E1E1E0E0E0E0",
+"#     c #FFFFFFFFFFFF",
+" .. .. .. .. .. .. .. ..",
+"........................",
+"............X...........",
+" .. .. .. .XXX. .. .. ..",
+".........XXooOX.........",
+".......XXooo+O@X........",
+" .. XXXoooo++@@@X. .. ..",
+"....X@Xoooooo@@@X.......",
+"....X@@Xooo@@@@@@X......",
+" .. X@@XXoo@@@@@@@X.. ..",
+"....X@@Xoo@@@@@@@@@X....",
+"....X@Xo@@@XX@@@@@@oX...",
+" .. oXoo@XXooO@@@@@@X ..",
+"....oXoXXooo+OX@@@@Xo...",
+"....XXXoooo++@@X@@Xo....",
+" .. X@Xoooooo@@@XX .. ..",
+"....X@@Xooo@@@@@@X......",
+"....X@@XXoo@@@@@@@X.....",
+" .. X@@Xoo@@@@@@@@@X. ..",
+"....X@Xo@  @@@@@@@  X...",
+"... oXoo ## @@ @@ ## ...",
+" .. oXo ####  @  #### ..",
+".....oX #### @@@ #### ..",
+".....oX@ ## @@@@X ## ..."};
diff --git a/xemacs-packages/gnus/etc/images/gnus/oort.xface b/xemacs-packages/gnus/etc/images/gnus/oort.xface
new file mode 100644 (file)
index 0000000..6444b55
--- /dev/null
@@ -0,0 +1,3 @@
+X-Face: $BP*2z+\?fNM."!*~JsIgw(Y]n?WG!KMc;^jL$SLrt@X4%uMguO/$3HO<5@43P@[~'kE'fG
+ #YdP[sb6IJ5|Sm[z#9sI|)iJ})U5;Rt-?jI3i24zoJmonTV}kTVOm/5wMCnc3P~d#+BF1c&N6mdF{u
+ CE+<;lN!v~JRyR"q0d5<\y]faXpTC4,wpQ{=<==?LRA`}3qqIgr
diff --git a/xemacs-packages/gnus/etc/images/gnus/post.pbm b/xemacs-packages/gnus/etc/images/gnus/post.pbm
new file mode 100644 (file)
index 0000000..577d623
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/post.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/post.xpm b/xemacs-packages/gnus/etc/images/gnus/post.xpm
new file mode 100644 (file)
index 0000000..7a3eaa5
--- /dev/null
@@ -0,0 +1,35 @@
+/* XPM */
+static char * post_xpm[] = {
+"24 24 8 1",
+".     c None",
+"      c #434343434343",
+"X     c #A5A5A5A59595",
+"O     c #000000000000",
+"+     c #C7C7C6C6C6C6",
+"@     c #FFFF00000000",
+"#     c #9A9A6C6C4E4E",
+"$     c #E1E1E0E0E0E0",
+"O..O..O..O..O..O..O..O..",
+"........................",
+"............X...........",
+"O..O..O..O.XXX.O..O..O..",
+".........XX++@X.........",
+".......XX+++#@$X........",
+"O..OXXX++++##$$$X.O..O..",
+"....X$X++++++$$$X.......",
+"....X$$X+++$$$$$$X......",
+"O..OX$$XX++$$$$$$$X..O..",
+"....X$$X++$$$$$$$$$X....",
+"....X$X+$$$$$$$$$$$+X...",
+"O..O+X++$$$$$$$$$$$$XO..",
+"....+X+$$$$$$$$$$$$X+...",
+".....+X$$$$$$$$$$$X+....",
+"O..O.+X$$$$$$$$$XXO..O..",
+"......+X$$$$$$$X++......",
+"......+X$$$$$XX+........",
+"O..O..O+X$$$X++O..O..O..",
+".......+X$$X++..........",
+"........+XX+............",
+"O..O..O..O+.O..O..O..O..",
+"........................",
+"........................"};
diff --git a/xemacs-packages/gnus/etc/images/gnus/prev-ur.pbm b/xemacs-packages/gnus/etc/images/gnus/prev-ur.pbm
new file mode 100644 (file)
index 0000000..4938919
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/prev-ur.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/prev-ur.xpm b/xemacs-packages/gnus/etc/images/gnus/prev-ur.xpm
new file mode 100644 (file)
index 0000000..8013133
--- /dev/null
@@ -0,0 +1,35 @@
+/* XPM */
+static char * prev_ur_xpm[] = {
+"24 24 8 1",
+".     c None",
+"      c #000000000000",
+"X     c #A5A5A5A59595",
+"o     c #C7C7C6C6C6C6",
+"O     c #FFFF00000000",
+"+     c #9A9A6C6C4E4E",
+"@     c #E1E1E0E0E0E0",
+"#     c #FFFFFFFFFFFF",
+" .. .. .. .. .. .. .. ..",
+"........................",
+"............X...........",
+" .. .. .. .XXX. .. .. ..",
+".........XXooOX.........",
+".......XXooo+O@X........",
+" .. XXXoooo++@@@X. .. ..",
+"....X@Xoooooo@@@X.......",
+"....X@@Xooo@@@@@@X......",
+" .. X@@XXoo@@@@@@@X.. ..",
+"....X@@Xo  @@@@@@  X....",
+"....X@Xo ## X  @ ## X...",
+" .. oXo #XXXoO@ ####  ..",
+"....oXoXXooo+OX #### ...",
+"....XXXoooo++@@X ## ....",
+" .. X@Xoooooo@@@X  .. ..",
+"....X@@Xooo@@@@@@X......",
+"....X@@XXoo@@@@@@@X.....",
+" .. X@@Xoo@@@@@@@@@X. ..",
+"....X@Xo@@@@@@@@@@@@X...",
+"... oXoo@@@@@@@@@@@@X...",
+" .. oXo@@@@@@@@@@@@X....",
+".....oX@@@@@@@@@@@X.....",
+".....oX@@@@@@@@@@X......"};
diff --git a/xemacs-packages/gnus/etc/images/gnus/preview.xbm b/xemacs-packages/gnus/etc/images/gnus/preview.xbm
new file mode 100644 (file)
index 0000000..a42e153
--- /dev/null
@@ -0,0 +1,10 @@
+#define preview_width 24
+#define preview_height 24
+static char preview_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0xc0,0x03,0x00,0x3e,0x06,0xf0,0x03,0x04,0x08,0x00,0x0a,0x78,0x00,0x09,
+ 0x88,0xf9,0x08,0x10,0xc6,0x10,0x10,0x3a,0x13,0x10,0x06,0x15,0x20,0x02,0x29,
+ 0x20,0x02,0x31,0x20,0xad,0x0f,0x40,0xf9,0x03,0xc0,0xb8,0x07,0x80,0x07,0x0e,
+ 0x80,0x01,0x1c,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x00,
+ 0x00,0x00,0x39,0x00,0x00,0x00,0x08,0xc0,0x12,0x42,0x00,0x00,0x00,0x00,0x38,
+ 0x82,0x18,0x08,0x00,0x00,0x00 };
diff --git a/xemacs-packages/gnus/etc/images/gnus/preview.xpm b/xemacs-packages/gnus/etc/images/gnus/preview.xpm
new file mode 100644 (file)
index 0000000..f5743f9
--- /dev/null
@@ -0,0 +1,33 @@
+/* XPM */
+static char *prev1[]={
+"24 24 6 1",
+". c None",
+"# c #000000",
+"d c #46463e",
+"a c #676663",
+"c c #a8a7a3",
+"b c #ebeae4",
+"........................",
+"........................",
+"........................",
+"........................",
+"........................",
+"..............####......",
+".........#####abbc#.....",
+"....#####acbbbbbbc#.....",
+"...#acbbbbbbbbbbacc#....",
+"...#baabbbbbbbbcacb#....",
+"...#cbcaabbd##dacbb#....",
+"....#bbbccdcbbcdabbc#...",
+"....#bbbbdccaaccdacb#...",
+"....#cbbb#abbbbb#bac#...",
+".....#bbb#cbbbbc#bbac#..",
+".....#bbbdcbbbbddbbc##..",
+".....#cbccdcbbd#####....",
+"......#babbd##dd##......",
+"......#acbc###.####.....",
+"......#aa##......###....",
+".......##.........###...",
+"...................##...",
+"........................",
+"........................"};
diff --git a/xemacs-packages/gnus/etc/images/gnus/receipt.xpm b/xemacs-packages/gnus/etc/images/gnus/receipt.xpm
new file mode 100644 (file)
index 0000000..18caaf1
--- /dev/null
@@ -0,0 +1,32 @@
+/* XPM */
+static char * receipt_xpm[] = {
+"24 24 5 1",
+"      c None",
+".     c #FFFFFFFFFFFF",
+"X     c #676766666363",
+"o     c #FFFF00000000",
+"O     c #AEAE3E3E4848",
+"                        ",
+"                        ",
+"                   ..   ",
+"                    .   ",
+"                     .  ",
+"                     .  ",
+"                   ..   ",
+"           Xooo  ..     ",
+"      Xoooooooo..       ",
+" Xoooooooooooooo  ...   ",
+" oooooooooooOOoo .      ",
+" ooooooooooOOOOo.       ",
+"  oooooooooOO...o       ",
+"  ooooooooooOOooo       ",
+"  ooooooooooooooo       ",
+"   ooooooooooooooo      ",
+"   oooooooooooooo       ",
+"   ooooooooooo          ",
+"    ooooooo             ",
+"    oooo                ",
+"    oo                  ",
+"                        ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/gnus/reply-wo.pbm b/xemacs-packages/gnus/etc/images/gnus/reply-wo.pbm
new file mode 100644 (file)
index 0000000..def54da
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/reply-wo.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/reply-wo.xpm b/xemacs-packages/gnus/etc/images/gnus/reply-wo.xpm
new file mode 100644 (file)
index 0000000..370678a
--- /dev/null
@@ -0,0 +1,31 @@
+/* XPM */
+static char * reply_wo_xpm[] = {
+"24 24 4 1",
+"      c None",
+".     c #000000000000",
+"X     c #E1E1E0E0E0E0",
+"O     c #FFFFFFFFFFFF",
+"                        ",
+"                        ",
+"                        ",
+"           ....         ",
+"          ..X....       ",
+"         ..XX.XX..      ",
+"       .O.XX.XXXX..     ",
+"     ..O.XXX.XXXX...    ",
+"    .OO.XXXX.X.......   ",
+"   .OO.XXXX...XXX.OO..  ",
+" ..OO.XX....XXXX.OOOO.. ",
+" .......XX.XXXX.OOO.... ",
+" .OOO.XXX.XXXX.OO..OOO. ",
+" .OOOO....XXX....OOOOO. ",
+" .OOOOOOO..XX..OOOOOOO. ",
+" .OOOOOOO......OOOOOOO. ",
+" .OOOOOO.OO..O..OOOOOO. ",
+" .OOOOO.OOOOOOOO.OOOOO. ",
+" .OOOO.OOOOOOOOOO.OOOO. ",
+" .OOO.OOOOOOOOOOOO.OOO. ",
+" .O..OOOOOOOOOOOOOO..O. ",
+" ..OOOOOOOOOOOOOOOOOO.. ",
+" ...................... ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/gnus/reply.pbm b/xemacs-packages/gnus/etc/images/gnus/reply.pbm
new file mode 100644 (file)
index 0000000..ee181e6
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/reply.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/reply.xpm b/xemacs-packages/gnus/etc/images/gnus/reply.xpm
new file mode 100644 (file)
index 0000000..a458848
--- /dev/null
@@ -0,0 +1,31 @@
+/* XPM */
+static char * reply_xpm[] = {
+"24 24 4 1",
+"      c None",
+".     c #000000000000",
+"X     c #E1E1E0E0E0E0",
+"O     c #FFFFFFFFFFFF",
+"                        ",
+"                        ",
+"                        ",
+"           ....         ",
+"          ..XXX..       ",
+"         ..XXXXX..      ",
+"       .O.XXXXXXX..     ",
+"     ..O.XXXXXXXXX..    ",
+"    .OO.XXXXXXXXXX...   ",
+"   .OO.XXXXXXXXXX.OO..  ",
+" ..OO.XXXXXXXXXX.OOOO.. ",
+" .....XXXXXXXXX.OOO.... ",
+" .OOO.XXXXXXXX.OO..OOO. ",
+" .OOOO...XXXXX...OOOOO. ",
+" .OOOOOOO..XX..OOOOOOO. ",
+" .OOOOOOO......OOOOOOO. ",
+" .OOOOOO.OO..O..OOOOOO. ",
+" .OOOOO.OOOOOOOO.OOOOO. ",
+" .OOOO.OOOOOOOOOO.OOOO. ",
+" .OOO.OOOOOOOOOOOO.OOO. ",
+" .O..OOOOOOOOOOOOOO..O. ",
+" ..OOOOOOOOOOOOOOOOOO.. ",
+" ...................... ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/gnus/rot13.pbm b/xemacs-packages/gnus/etc/images/gnus/rot13.pbm
new file mode 100644 (file)
index 0000000..800d9d6
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/rot13.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/rot13.xpm b/xemacs-packages/gnus/etc/images/gnus/rot13.xpm
new file mode 100644 (file)
index 0000000..18faa3e
--- /dev/null
@@ -0,0 +1,128 @@
+/* XPM */
+static char * rot13_xpm[] = {
+"24 24 101 2",
+"      g None",
+".     g #000000",
+"+     g #212121",
+"@     g #9E9E9E",
+"#     g #E6E6E6",
+"$     g #E7E7E7",
+"%     g #C8C8C8",
+"&     g #A0A0A0",
+"*     g #131313",
+"=     g #5F5F5F",
+"-     g #EDEDED",
+";     g #D6D6D6",
+">     g #D5D5D5",
+",     g #DDDDDD",
+"'     g #D8D8D8",
+")     g #A1A1A1",
+"!     g #3C3C3C",
+"~     g #353535",
+"{     g #EFEFEF",
+"]     g #CFCFCF",
+"^     g #4C4C4C",
+"/     g #141414",
+"(     g #6A6A6A",
+"_     g #D0D0D0",
+":     g #B2B2B2",
+"<     g #454545",
+"[     g #E2E2E2",
+"}     g #292929",
+"|     g #0F0F0F",
+"1     g #949494",
+"2     g #E9E9E9",
+"3     g #C3C3C3",
+"4     g #1C1C1C",
+"5     g #E1E1E1",
+"6     g #272727",
+"7     g #DEDEDE",
+"8     g #B6B6B6",
+"9     g #0C0C0C",
+"0     g #262626",
+"a     g #1F1F1F",
+"b     g #616161",
+"c     g #5B5B5B",
+"d     g #232323",
+"e     g #111111",
+"f     g #181818",
+"g     g #3D3D3D",
+"h     g #636363",
+"i     g #545454",
+"j     g #2E2E2E",
+"k     g #242424",
+"l     g #070707",
+"m     g #DCDCDC",
+"n     g #D3D3D3",
+"o     g #C5C5C5",
+"p     g #C2C2C2",
+"q     g #BFBFBF",
+"r     g #B5B5B5",
+"s     g #696969",
+"t     g #ACACAC",
+"u     g #999999",
+"v     g #8F8F8F",
+"w     g #868686",
+"x     g #686868",
+"y     g #B1B1B1",
+"z     g #9A9A9A",
+"A     g #909090",
+"B     g #878787",
+"C     g #DBDBDB",
+"D     g #A6A6A6",
+"E     g #979797",
+"F     g #8A8A8A",
+"G     g #8D8D8D",
+"H     g #838383",
+"I     g #666666",
+"J     g #BBBBBB",
+"K     g #9F9F9F",
+"L     g #8B8B8B",
+"M     g #828282",
+"N     g #676767",
+"O     g #A3A3A3",
+"P     g #8E8E8E",
+"Q     g #888888",
+"R     g #8C8C8C",
+"S     g #BABABA",
+"T     g #818181",
+"U     g #757575",
+"V     g #DADADA",
+"W     g #AFAFAF",
+"X     g #848484",
+"Y     g #7F7F7F",
+"Z     g #7B7B7B",
+"`     g #B8B8B8",
+" .    g #D9D9D9",
+"..    g #ABABAB",
+"+.    g #929292",
+"@.    g #939393",
+"#.    g #808080",
+"$.    g #919191",
+"%.    g #ADADAD",
+"&.    g #969696",
+"*.    g #4A4A4A",
+"                                                ",
+"                                                ",
+"                    . . . . .                   ",
+"                . + @ # $ % & *                 ",
+"              . = - # ; > , ' ) ! .             ",
+"              ~ { ] ^ . . / ( _ : <             ",
+"            . [ ' } .       | ( % 1 .           ",
+"            * 2 3 .           4 5 @ .           ",
+"            6 7 8 .           . $ 8 .           ",
+"        9 0 a b c d e 6 a f a g h i j k l       ",
+"        . 7 m ' ; n o p p p p q r r r s .       ",
+"        . 7 p 8 : t t t t t t t u v w x .       ",
+"        . m p 8 y t t t t t t t z A B s .       ",
+"        . C p r D E E E E E E A F G H I .       ",
+"        . , p 8 J t t t t t t t K L M N .       ",
+"        . m p y O E E E E E E P Q R H ( .       ",
+"        . m p r S t t t t t t t K L T U .       ",
+"        . V p W & E E E E E E F X B Y Z .       ",
+"        . C p y ` t t t t t t t K F B T .       ",
+"        .  .p W ..E E E E E E E +.G @.#..       ",
+"        . $.%.z &.A L F F G $.A A P X *..       ",
+"          . . . . . . . . . . . . . . .         ",
+"                                                ",
+"                                                "};
diff --git a/xemacs-packages/gnus/etc/images/gnus/save-aif.pbm b/xemacs-packages/gnus/etc/images/gnus/save-aif.pbm
new file mode 100644 (file)
index 0000000..15829c2
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/save-aif.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/save-aif.xpm b/xemacs-packages/gnus/etc/images/gnus/save-aif.xpm
new file mode 100644 (file)
index 0000000..f0325ac
--- /dev/null
@@ -0,0 +1,33 @@
+/* XPM */
+static char * save_aif_xpm[] = {
+"24 24 6 1",
+"      c None",
+".     c #999999999999",
+"X     c #E1E1E0E0E0E0",
+"o     c #C7C7C6C6C6C6",
+"O     c #000000000000",
+"+     c #FFFFFFFFFFFF",
+"                        ",
+"                        ",
+"       .............    ",
+"       .XXXXXXXXXX.X..  ",
+"       .XXXXXXXXXX.XX.  ",
+"       .XXXXXXXXXX....  ",
+"       .XXXXXXXXXXooo.  ",
+"       .XXXXXXXXXXXXX.  ",
+"       .XXXXXXXXXXXXX.  ",
+"       .XXXXXXXXXXXXX.  ",
+" OOOOOOOOOOOOOOXXXXXX.  ",
+" O..O+++++++O.OXXXXXX.  ",
+" O..O+++++++O.OXXXXXX.  ",
+" O..O+++++++O.OXXXXXX.  ",
+" O..O+++++++O.OXXXXXX.  ",
+" O..O+++++++O.OXXXXXX.  ",
+" O..OOOOOOOOO.OXXXXXX.  ",
+" O............OXXXXXX.  ",
+" O............OXXXXXX.  ",
+" O..OOOOOOOOO.O.......  ",
+" O..OoooooO++.O         ",
+" O..OoooooO++.O         ",
+"  O.OoooooO++.O         ",
+"   OOOOOOOOOOOO         "};
diff --git a/xemacs-packages/gnus/etc/images/gnus/save-art.pbm b/xemacs-packages/gnus/etc/images/gnus/save-art.pbm
new file mode 100644 (file)
index 0000000..68fe0cb
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/save-art.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/save-art.xpm b/xemacs-packages/gnus/etc/images/gnus/save-art.xpm
new file mode 100644 (file)
index 0000000..fe9726f
--- /dev/null
@@ -0,0 +1,32 @@
+/* XPM */
+static char * save_art_xpm[] = {
+"24 24 5 1",
+"      c None",
+".     c #000000000000",
+"X     c #FFFFFFFFFFFF",
+"o     c #999999999999",
+"O     c #C7C7C6C6C6C6",
+"                        ",
+"                        ",
+"     .................. ",
+"     ...XXXXXXXXXXXXX.. ",
+"     .XX..XXXXXXXXX..X. ",
+"     .XXXX..XXXXX..XXX. ",
+"     .XXXXX......XXXXX. ",
+"     .XXX..XX..XX..XXX. ",
+"     .XX..XXXXXXXX..XX. ",
+"     ...XXXXXXXXXXXX... ",
+" ..............XXXXXXX. ",
+" .oo.XXXXXXX.o......... ",
+" .oo.XXXXXXX.o.         ",
+" .oo.XXXXXXX.o.         ",
+" .oo.XXXXXXX.o.         ",
+" .oo.XXXXXXX.o.         ",
+" .oo.........o.         ",
+" .oooooooooooo.         ",
+" .oooooooooooo.         ",
+" .oo.........o.         ",
+" .oo.OOOOO.XXo.         ",
+" .oo.OOOOO.XXo.         ",
+"  .o.OOOOO.XXo.         ",
+"   ............         "};
diff --git a/xemacs-packages/gnus/etc/images/gnus/subscribe.pbm b/xemacs-packages/gnus/etc/images/gnus/subscribe.pbm
new file mode 100644 (file)
index 0000000..fe6b392
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/subscribe.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/subscribe.xpm b/xemacs-packages/gnus/etc/images/gnus/subscribe.xpm
new file mode 100644 (file)
index 0000000..ff193a9
--- /dev/null
@@ -0,0 +1,32 @@
+/* XPM */
+static char * subscribe_xpm[] = {
+"24 24 5 1",
+"      c None",
+".     c #A5A5A5A59595",
+"X     c #E1E1E0E0E0E0",
+"o     c #C7C7C6C6C6C6",
+"O     c #8686ADAD7D7D",
+"                        ",
+"                        ",
+"                        ",
+"     ...                ",
+"   ..XXX.....           ",
+"...XXXXX..XXX. ...      ",
+".X.XX...XXXX...XXX.     ",
+".XX.X.X.XX...XXXXX.     ",
+".XX...XX.X.X.XXXXXX.    ",
+".XX.o.XX...XX.XXXXXX.   ",
+".X.oo.XX.o.XX..XXXXXX.  ",
+"o.ooo.X.oo.XX.XXXOXXX.  ",
+"o.oXXo.ooo.X.oXXOXXXXX. ",
+" o.XXo.oXXo.ooXXOXXXXX. ",
+" o.XXXo.XXo.oXXXOXXXXXX.",
+"  o.XXo.XXXo.XOOOOXXXXX.",
+"  o.XXoo.XXo.XXXOOXXXXX.",
+"   o.XXo.XXXo.XXXXXXX...",
+"   o.XX.o.XXo.XXXXXX.oo ",
+"    o..oo.XX.o.XXX..o   ",
+"     oo  o..oo.XX.oo    ",
+"          oo  o..o      ",
+"               oo       ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/gnus/toggle-subscription.xpm b/xemacs-packages/gnus/etc/images/gnus/toggle-subscription.xpm
new file mode 100644 (file)
index 0000000..c067468
--- /dev/null
@@ -0,0 +1,58 @@
+/* XPM */
+static char * stock_task_recurring_xpm[] = {
+"24 24 31 1",
+"      c None",
+".     c #000000",
+"+     c #FFFFFF",
+"@     c #F4E2BC",
+"#     c #F4D597",
+"$     c #434343",
+"%     c #F0CC84",
+"&     c #EBB13D",
+"*     c #4B4B4B",
+"=     c #535353",
+"-     c #C8C8C8",
+";     c #7D7D7D",
+">     c #7C7C7C",
+",     c #858585",
+"'     c #5C5C5C",
+")     c #949494",
+"!     c #F2F2F2",
+"~     c #B6B6B6",
+"{     c #BDBDBD",
+"]     c #818181",
+"^     c #878787",
+"/     c #B2B2B2",
+"(     c #FDFDFD",
+"_     c #DBDBDB",
+":     c #CCCCCC",
+"<     c #ECECEC",
+"[     c #7F7F99",
+"}     c #333366",
+"|     c #8F8FA9",
+"1     c #59597F",
+"2     c #EEEEEE",
+"                        ",
+"     . . . . . . .      ",
+"    .+.+.+.+.+.+.+.     ",
+"    .@.#.#.#.#.#.#.     ",
+"   .$%$&*&*&=&=&$&*.    ",
+"   .-*;*>*>*>*>=,').    ",
+"   .!>~>{]{]{]{]{^/.    ",
+"   .(_:::::::::::_/.    ",
+"   .+<<<<<<<<<<<<</.    ",
+"   .+_::[}::}}}}:_/.    ",
+"   .+<<|}<<<}}}<<</.    ",
+"   .+_:}[:::}}1[:_/.    ",
+"   .+<<}<<<<}<|}<</.    ",
+"   .+_:}[:}::::}:_/.    ",
+"   .+<<|}}}<<<|}<</.    ",
+"   .+_::}}}:::}[:_/.    ",
+"   .+<<}}}}<<}|<<</.    ",
+"   .+_:::::::::::_/.    ",
+"   .+<<<<<<<<<<<<</.    ",
+"   .2//////////////.    ",
+"   .................    ",
+"                        ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/gnus/unimportant.xpm b/xemacs-packages/gnus/etc/images/gnus/unimportant.xpm
new file mode 100644 (file)
index 0000000..4298224
--- /dev/null
@@ -0,0 +1,32 @@
+/* XPM */
+static char *magick[] = {
+/* columns rows colors chars-per-pixel */
+"24 24 2  1",
+"! c blue",
+"w c Gray75",
+/* pixels */
+"wwwwwwwwwwwwwwwwwwwwwwww",
+"wwwwwwwwwwwwwwwwwwwwwwww",
+"wwwwwwwwwww!!!wwwwwwwwww",
+"wwwwwwwwwww!!!wwwwwwwwww",
+"wwwwwwwwwww!!!wwwwwwwwww",
+"wwwwwwwwwww!!!wwwwwwwwww",
+"wwwwwwwwwww!!!wwwwwwwwww",
+"wwwwwwwwwww!!!wwwwwwwwww",
+"wwwwwwwwwww!!!wwwwwwwwww",
+"wwwwwwwwwww!!!wwwwwwwwww",
+"wwwwwwwwwww!!!wwwwwwwwww",
+"wwwwwwwwwww!!!wwwwwwwwww",
+"ww!!!wwwwww!!!wwwwww!!!w",
+"www!!!wwwww!!!wwwww!!!ww",
+"wwww!!!wwww!!!wwww!!!www",
+"wwwww!!!www!!!www!!!wwww",
+"wwwwww!!!ww!!!ww!!!wwwww",
+"wwwwwww!!!w!!!w!!!wwwwww",
+"wwwwwwww!!!!!!!!!wwwwwww",
+"wwwwwwwww!!!!!!!wwwwwwww",
+"wwwwwwwwww!!!!!wwwwwwwww",
+"wwwwwwwwwww!!!wwwwwwwwww",
+"wwwwwwwwwwwwwwwwwwwwwwww",
+"wwwwwwwwwwwwwwwwwwwwwwww"
+};
diff --git a/xemacs-packages/gnus/etc/images/gnus/unsubscribe.pbm b/xemacs-packages/gnus/etc/images/gnus/unsubscribe.pbm
new file mode 100644 (file)
index 0000000..7d869fb
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/unsubscribe.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/unsubscribe.xpm b/xemacs-packages/gnus/etc/images/gnus/unsubscribe.xpm
new file mode 100644 (file)
index 0000000..a91180d
--- /dev/null
@@ -0,0 +1,32 @@
+/* XPM */
+static char * unsubscribe_xpm[] = {
+"24 24 5 1",
+"      c None",
+".     c #A5A5A5A59595",
+"X     c #E1E1E0E0E0E0",
+"o     c #C7C7C6C6C6C6",
+"O     c #FFFF00000000",
+"                        ",
+"                        ",
+"                        ",
+"     ...                ",
+"   ..XXX.....           ",
+"...XXXXX..XXX. ...      ",
+".X.XX...XXXX...XXX.     ",
+".XX.X.X.XX...XXXXX.     ",
+".XX...XX.X.X.XXXXXX.    ",
+".XX.o.XX...XX.XXXXXX.   ",
+".X.oo.XX.o.XX..XXXXXX.  ",
+"o.ooo.X.oo.XX.XXXXXXX.  ",
+"o.oXXo.ooo.X.oXXXXXXXX. ",
+" o.XXo.oXXo.ooXXOXXXXX. ",
+" o.XXXo.XXo.oXXXOXXXXXX.",
+"  o.XXo.XXXo.XOOOXXXXXX.",
+"  o.XXoo.XXo.XoOOOXXXXX.",
+"   o.XXo.XXXo.XOoOXXX...",
+"   o.XX.o.XXo.XOXoXX.oo ",
+"    o..oo.XX.o.oXX..o   ",
+"     oo  o..oo.XX.oo    ",
+"          oo  o..o      ",
+"               oo       ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/gnus/uu-decode.pbm b/xemacs-packages/gnus/etc/images/gnus/uu-decode.pbm
new file mode 100644 (file)
index 0000000..2b7fada
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/uu-decode.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/uu-decode.xpm b/xemacs-packages/gnus/etc/images/gnus/uu-decode.xpm
new file mode 100644 (file)
index 0000000..b9d940c
--- /dev/null
@@ -0,0 +1,36 @@
+/* XPM */
+static char * uu_decode_xpm[] = {
+"24 24 9 1",
+"      c None",
+".     c #919187876969",
+"X     c #C2C2B9B99C9C",
+"o     c #868686868686",
+"O     c #8F8F8F8F8F8F",
+"+     c #000000000000",
+"@     c #4C4C4C4C4C4C",
+"#     c #E9E9EFEFE8E8",
+"$     c #8686ADAD7D7D",
+"                        ",
+"                        ",
+"                        ",
+"    ..............      ",
+"    X.o.........O.++    ",
+"    XX++++++++++..++    ",
+"    XX@########+..++    ",
+"    XX@########+..++    ",
+"    XX@$#$$$#$#+..++    ",
+"    XX@#$$$$$$#+..++    ",
+"    XX@##$#####+..++    ",
+"    XX@##$#$$##+..++    ",
+"    XX@##$#$$##+..++    ",
+"    XX@##$$#$$#+..++    ",
+"    XX@######$#+..++    ",
+"    XX@########+..++    ",
+"    XX@########+..++    ",
+"    XX.@@@@@@@@@..++    ",
+"    X.XXXXXXXXXX..++    ",
+"    .XXXXXXXXXXXX.++    ",
+"     +++++++++++++++    ",
+"     +++++++++++++++    ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/gnus/uu-post.pbm b/xemacs-packages/gnus/etc/images/gnus/uu-post.pbm
new file mode 100644 (file)
index 0000000..a5face7
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/gnus/uu-post.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/gnus/uu-post.xpm b/xemacs-packages/gnus/etc/images/gnus/uu-post.xpm
new file mode 100644 (file)
index 0000000..7c4204c
--- /dev/null
@@ -0,0 +1,35 @@
+/* XPM */
+static char * uu_post_xpm[] = {
+"24 24 8 1",
+".     c None",
+"X     c #000000000000",
+"+     c #C2C2B9B99C9C",
+"@     c #919187876969",
+"#     c #868686868686",
+"%     c #4C4C4C4C4C4C",
+"&     c #E9E9EFEFE8E8",
+"*     c #8686ADAD7D7D",
+"X..X..X..X.XX..X..X..X..",
+"..........X.X...........",
+".........X...X..........",
+"X..X..X.XX..X.XX..X..X..",
+".......X.......X........",
+"......X.........X.......",
+"X..X+X@@@@@@@@@@@XX..X..",
+"....+@@@@@@@@@@@@@......",
+"....++XXXXXXXXXX@@......",
+"X..X++%&&&&&&&&X@@X..X..",
+"....++%&&&&&&&&X@@......",
+"....++%*&***&*&X@@......",
+"X..X++%&******&X@@X..X..",
+"....++%&&*&&&&&X@@......",
+"....++%&&*&**&&X@@......",
+"X..X++%&&*&**&&X@@X..X..",
+"....++%&&**&**&X@@......",
+"....++%&&&&&&*&X@@......",
+"X..X++%&&&&&&&&X@@X..X..",
+"....++%&&&&&&&&X@@......",
+"....++@%%%%%%%%%@@......",
+"X..X+@++++++++++@@X..X..",
+"....+++++++++++++@......",
+"........................"};
diff --git a/xemacs-packages/gnus/etc/images/help.xpm b/xemacs-packages/gnus/etc/images/help.xpm
new file mode 100644 (file)
index 0000000..1d65ce0
--- /dev/null
@@ -0,0 +1,271 @@
+/* XPM */
+static char * help_xpm[] = {
+"24 24 244 2",
+"      c None",
+".     c #000000",
+"+     c #454442",
+"@     c #1D1D1C",
+"#     c #040404",
+"$     c #1B1B1B",
+"%     c #3D3C3A",
+"&     c #4D4C4B",
+"*     c #2F2F2D",
+"=     c #C1BFBB",
+"-     c #ECEAE7",
+";     c #F5F3F0",
+">     c #F2F0EC",
+",     c #E1DFDC",
+"'     c #AFADAA",
+")     c #272726",
+"!     c #020202",
+"~     c #3F3E3E",
+"{     c #36302D",
+"]     c #181818",
+"^     c #FBF8F5",
+"/     c #FEFCF8",
+"(     c #FAF8F5",
+"_     c #F5F4F1",
+":     c #F2F1ED",
+"<     c #F1EFEB",
+"[     c #F1EEEB",
+"}     c #EAE9E6",
+"|     c #DAD8D4",
+"1     c #100E0E",
+"2     c #1F100E",
+"3     c #AF3A1E",
+"4     c #FBAB93",
+"5     c #FAE9E3",
+"6     c #F0EFEB",
+"7     c #E9E8E5",
+"8     c #EAE8E6",
+"9     c #ECEAE8",
+"0     c #EDEBE9",
+"a     c #EDEBE8",
+"b     c #EACFC6",
+"c     c #D5340A",
+"d     c #751904",
+"e     c #100806",
+"f     c #34160D",
+"g     c #AF3C20",
+"h     c #FCCCBD",
+"i     c #F7BEAD",
+"j     c #E67554",
+"k     c #DFDDDB",
+"l     c #DBD9D6",
+"m     c #D8D7D3",
+"n     c #DBDAD6",
+"o     c #E3E2DE",
+"p     c #ECEBE8",
+"q     c #E5572D",
+"r     c #E33A0B",
+"s     c #D4340A",
+"t     c #691504",
+"u     c #100504",
+"v     c #582C22",
+"w     c #0F0F0F",
+"x     c #FDD4C8",
+"y     c #F7BFAF",
+"z     c #E87554",
+"A     c #D5512B",
+"B     c #C68270",
+"C     c #BEBDBA",
+"D     c #A5A3A0",
+"E     c #9C9A95",
+"F     c #B9B7B2",
+"G     c #D7D6D2",
+"H     c #E7E5E2",
+"I     c #E79A85",
+"J     c #E53C0B",
+"K     c #E43C0B",
+"L     c #E23A0B",
+"M     c #C93009",
+"N     c #010000",
+"O     c #040100",
+"P     c #FAB19C",
+"Q     c #FACCBE",
+"R     c #EB8264",
+"S     c #D8532D",
+"T     c #C0340F",
+"U     c #932006",
+"V     c #141412",
+"W     c #857974",
+"X     c #DA370B",
+"Y     c #EC7C5B",
+"Z     c #E95B32",
+"`     c #DE380B",
+" .    c #9D2306",
+"..    c #626261",
+"+.    c #FEF1ED",
+"@.    c #F09479",
+"#.    c #DC532B",
+"$.    c #C0350F",
+"%.    c #942006",
+"&.    c #621404",
+"*.    c #E2522B",
+"=.    c #F2A690",
+"-.    c #E74E21",
+";.    c #E23B0B",
+">.    c #C99181",
+",.    c #454342",
+"'.    c #E5E4E2",
+").    c #FCFBFA",
+"!.    c #E2D8D3",
+"~.    c #C34C2A",
+"{.    c #B02B07",
+"].    c #9E2D12",
+"^.    c #EF8D71",
+"/.    c #F09B83",
+"(.    c #EADDD7",
+"_.    c #272724",
+":.    c #F0EEEC",
+"<.    c #F3F2EF",
+"[.    c #D7D6D3",
+"}.    c #BFBEBB",
+"|.    c #9E6153",
+"1.    c #3F0D02",
+"2.    c #F0B9A9",
+"3.    c #F6F5F4",
+"4.    c #E8E7E4",
+"5.    c #DAD8D5",
+"6.    c #585652",
+"7.    c #F6F4F0",
+"8.    c #DAD8D6",
+"9.    c #C2C1BE",
+"0.    c #989691",
+"a.    c #0A0A08",
+"b.    c #F6F4F2",
+"c.    c #F4F3F1",
+"d.    c #E4E3E0",
+"e.    c #D3D2CE",
+"f.    c #63625D",
+"g.    c #DCDAD8",
+"h.    c #C7C6C2",
+"i.    c #ABAAA5",
+"j.    c #0A0A0A",
+"k.    c #FAF8F6",
+"l.    c #EFEDEA",
+"m.    c #DDDCD8",
+"n.    c #C6C4C2",
+"o.    c #3E3E39",
+"p.    c #1B1B19",
+"q.    c #F0EEEA",
+"r.    c #E0DFDD",
+"s.    c #CCCBC9",
+"t.    c #C0BFBB",
+"u.    c #131311",
+"v.    c #676663",
+"w.    c #FCFAF8",
+"x.    c #D6D4D2",
+"y.    c #BCBAB7",
+"z.    c #3C3C3A",
+"A.    c #DEDCD9",
+"B.    c #7E4B3E",
+"C.    c #232323",
+"D.    c #CC9385",
+"E.    c #FAFAF7",
+"F.    c #E6E6E2",
+"G.    c #CDCCCA",
+"H.    c #B0B0AC",
+"I.    c #EDE3DF",
+"J.    c #E78468",
+"K.    c #DF5D3A",
+"L.    c #631909",
+"M.    c #282828",
+"N.    c #B46E5E",
+"O.    c #FCC3B2",
+"P.    c #F1A691",
+"Q.    c #DCD2CC",
+"R.    c #C8C6C3",
+"S.    c #7E7C78",
+"T.    c #E8AD9C",
+"U.    c #E96139",
+"V.    c #EB7452",
+"W.    c #EF8E72",
+"X.    c #EA8063",
+"Y.    c #9E2E13",
+"Z.    c #3F1811",
+"`.    c #121212",
+" +    c #6B433B",
+".+    c #E0A191",
+"++    c #FDD3C7",
+"@+    c #F4AD98",
+"#+    c #DE532B",
+"$+    c #C83409",
+"%+    c #B48274",
+"&+    c #383534",
+"*+    c #D6340A",
+"=+    c #E43D0F",
+"-+    c #E8582E",
+";+    c #ED7957",
+">+    c #F4B6A4",
+",+    c #F4B09D",
+"'+    c #F0E5E0",
+")+    c #F4F3EF",
+"!+    c #FDF8F6",
+"~+    c #FBCEC1",
+"{+    c #F28B6E",
+"]+    c #E44E23",
+"^+    c #D3370A",
+"/+    c #BF2F09",
+"(+    c #260800",
+"_+    c #190F0B",
+":+    c #D5350A",
+"<+    c #E43D0C",
+"[+    c #E74C1F",
+"}+    c #EFBBAB",
+"|+    c #F5F4F3",
+"1+    c #F5F3F1",
+"2+    c #EAB1A0",
+"3+    c #DE4316",
+"4+    c #C5310A",
+"5+    c #591202",
+"6+    c #0E0504",
+"7+    c #C83009",
+"8+    c #E0532B",
+"9+    c #E7E6E3",
+"0+    c #E7E6E2",
+"a+    c #DDDCD9",
+"b+    c #CFCECA",
+"c+    c #C14724",
+"d+    c #AE2907",
+"e+    c #290800",
+"f+    c #0F0705",
+"g+    c #9B2205",
+"h+    c #C1A89F",
+"i+    c #D1D0CC",
+"j+    c #CFCDCA",
+"k+    c #C7C6C3",
+"l+    c #BBBAB7",
+"m+    c #B5B4B1",
+"n+    c #A7A6A2",
+"o+    c #66564F",
+"p+    c #0B0908",
+"q+    c #010100",
+"r+    c #222221",
+"s+    c #51504B",
+"t+    c #5D5C57",
+"u+    c #3B3B37",
+"    . .         + @ # # $ %                     ",
+"  . . . . & # * = - ; > , ' ) ! ~ . . . .       ",
+". .     { ] ^ / ( _ : > < [ } | . 1     . .     ",
+"  .   2 3 4 5 6 - 7 8 9 0 0 a b c d e     .     ",
+"  . f g h i j k l m n o } p a 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 K `  ..       ",
+"  ..+.@.#.$.%.. .         . &.*.=.-.;.>.! .     ",
+",.'.).!.~.{.. .             . ].^./.(.n _..     ",
+"@ :.<.[.}.|..                 1.2.3.4.5.6..     ",
+"# 7.6 8.9.0..                 a.b.c.d.e.f..     ",
+"# > < g.h.i..                 j.k.l.m.n.o..     ",
+"p., q.r.s.t.u.                v.w.9 x.y.. .     ",
+"z.' [ 7 A.[.B..             C.D.E.F.G.H.. .     ",
+"  ) } 0 I.J.K.L..         M.N.O.P.Q.R.S.. .     ",
+"  ! | T.U.V.W.X.Y.Z.a.`. +.+++@+#+$+%+. .       ",
+"  &+. *+=+-+;+>+,+'+)+k.!+~+{+]+^+/+(+. .       ",
+"  . _+d :+L <+[+}+|+l.1+|+2+3+^+4+5+. . .       ",
+"  .   6+t 7+` 8+9+0+o a+[.b+c+d+e+. .   .       ",
+"  .     f+. g+h+i+j+k+l+m+n+o+. . .     .       ",
+"    . . . p+. q+r+s+t+u+. . . . .     . .       ",
+"              . . . . . . . .   . . . .         ",
+"                                                ",
+"                                                "};
diff --git a/xemacs-packages/gnus/etc/images/home.xpm b/xemacs-packages/gnus/etc/images/home.xpm
new file mode 100644 (file)
index 0000000..57e8f9c
--- /dev/null
@@ -0,0 +1,128 @@
+/* XPM */
+static char * home_xpm[] = {
+"24 24 101 2",
+"      c None",
+".     c #000000",
+"+     c #212121",
+"@     c #2C2C2C",
+"#     c #C1665A",
+"$     c #924B37",
+"%     c #2A2A2A",
+"&     c #333333",
+"*     c #343434",
+"=     c #242424",
+"-     c #944D3A",
+";     c #A05443",
+">     c #181818",
+",     c #474747",
+"'     c #555555",
+")     c #8D8D8D",
+"!     c #383838",
+"~     c #191919",
+"{     c #974F3C",
+"]     c #222222",
+"^     c #313131",
+"/     c #A1A1A1",
+"(     c #676767",
+"_     c #ACACAC",
+":     c #BCBCBC",
+"<     c #585858",
+"[     c #141414",
+"}     c #1C1C1C",
+"|     c #464646",
+"1     c #666666",
+"2     c #BABABA",
+"3     c #7E7E7E",
+"4     c #D2D2D2",
+"5     c #FFFFFF",
+"6     c #4F4F4F",
+"7     c #262626",
+"8     c #232323",
+"9     c #505050",
+"0     c #B2B2B2",
+"a     c #909090",
+"b     c #9A9A9A",
+"c     c #838383",
+"d     c #171717",
+"e     c #202020",
+"f     c #717171",
+"g     c #A6A6A6",
+"h     c #616161",
+"i     c #1D1D1D",
+"j     c #1F1F1F",
+"k     c #C4C4C4",
+"l     c #CACACA",
+"m     c #AEAEAE",
+"n     c #D1D1D1",
+"o     c #7C7C7C",
+"p     c #BFBFBF",
+"q     c #6C6C6C",
+"r     c #EEEEEE",
+"s     c #949494",
+"t     c #C7C7C7",
+"u     c #EBEBEB",
+"v     c #7D7D7D",
+"w     c #6E6E6E",
+"x     c #A9A9A9",
+"y     c #E99E8F",
+"z     c #DD806D",
+"A     c #9B5343",
+"B     c #CECECE",
+"C     c #626262",
+"D     c #858585",
+"E     c #ECA292",
+"F     c #D0533A",
+"G     c #934F3E",
+"H     c #6D6D6D",
+"I     c #ECA291",
+"J     c #CF543C",
+"K     c #371D16",
+"L     c #5D5D5D",
+"M     c #868686",
+"N     c #787878",
+"O     c #ECA696",
+"P     c #C95C49",
+"Q     c #E17C66",
+"R     c #924E3D",
+"S     c #888888",
+"T     c #A0A0A0",
+"U     c #3D1208",
+"V     c #D15137",
+"W     c #919191",
+"X     c #879981",
+"Y     c #82947C",
+"Z     c #8A9B85",
+"`     c #6E8467",
+" .    c #5D7555",
+"..    c #4C6042",
+"+.    c #3F4F37",
+"@.    c #303D2A",
+"#.    c #7F8F7A",
+"$.    c #64785E",
+"%.    c #44563E",
+"&.    c #657460",
+"*.    c #40503A",
+"                                                ",
+"                      . .                       ",
+"          . . . .   . + @ .                     ",
+"          . # $ . . % & * = .                   ",
+"          . - ; . > , ' ) ! ~ .                 ",
+"          . { . ] ^ / ( _ : < [ .               ",
+"          . . } | 1 2 3 4 : 5 6 7 .             ",
+"          . 8 9 0 a 4 b 5 : 5 : c d .           ",
+"        . e f g 4 b 5 : 5 : 5 : 5 h i .         ",
+"      . j k k l 5 m 5 2 5 2 5 : 5 n o } .       ",
+"    . 8 m p p p p p p p p . . . . . a q = .     ",
+"  . . . . r 5 5 5 5 5 5 5 . s t u . v . . . .   ",
+"        . 4 5 . . . . . 5 . : 5 5 . w .         ",
+"        . x 5 . y z A . 5 . B 5 5 . C .         ",
+"        . D 5 . E F G . 5 . . . . . H .         ",
+"        . . 5 . I J K . k s L L M N . .         ",
+"        . . r . O P G . 5 5 5 5 5 2 .           ",
+"          . 2 . Q # R . : : : : : S .           ",
+"          . T U V # A . 5 5 5 5 5 W .           ",
+"  . . . . . . . . . . . . . . . . . . . .   .   ",
+"        } X Y Z X `  ...+.@.. Y #.$.%.&.*..     ",
+"    . .   . . . . . . . . .   . . . . . .       ",
+"                . . .                           ",
+"                                                "};
diff --git a/xemacs-packages/gnus/etc/images/index.xpm b/xemacs-packages/gnus/etc/images/index.xpm
new file mode 100644 (file)
index 0000000..7e1de12
--- /dev/null
@@ -0,0 +1,201 @@
+/* XPM */
+static char * index_xpm[] = {
+"24 24 174 2",
+"      c None",
+".     c #000000",
+"+     c #FDFDFD",
+"@     c #F5F5F5",
+"#     c #F6F6F6",
+"$     c #D0D0D0",
+"%     c #C1C1C1",
+"&     c #C3C3C3",
+"*     c #C6C6C6",
+"=     c #C8C8C8",
+"-     c #8D8D8D",
+";     c #CACACA",
+">     c #919191",
+",     c #EFEFEF",
+"'     c #878787",
+")     c #8A8A8A",
+"!     c #5C5C5C",
+"~     c #F8F8F8",
+"{     c #EAEAEA",
+"]     c #CCCCCC",
+"^     c #CECECE",
+"/     c #979797",
+"(     c #CDCDCD",
+"_     c #A1A1A1",
+":     c #090600",
+"<     c #A3A3A3",
+"[     c #C5C5C5",
+"}     c #C4C4C4",
+"|     c #D1D1D1",
+"1     c #D2D2D1",
+"2     c #D2D2D2",
+"3     c #9A9A9A",
+"4     c #E8E8E8",
+"5     c #949494",
+"6     c #939393",
+"7     c #574F4F",
+"8     c #FDFDFC",
+"9     c #777777",
+"0     c #7E7E7E",
+"a     c #9D9D9D",
+"b     c #6B6B6B",
+"c     c #F1F1F1",
+"d     c #ECECEC",
+"e     c #CFCFCF",
+"f     c #575050",
+"g     c #FDFAF8",
+"h     c #A5A5A5",
+"i     c #B9B9B9",
+"j     c #EEEEEE",
+"k     c #EDEDED",
+"l     c #D5D5D5",
+"m     c #BABABA",
+"n     c #6D6767",
+"o     c #F9F1EA",
+"p     c #9E9E9E",
+"q     c #B5B5B5",
+"r     c #D9D9D9",
+"s     c #D7D7D7",
+"t     c #BCBCBC",
+"u     c #625C5B",
+"v     c #F9EEE4",
+"w     c #4F4D4A",
+"x     c #646464",
+"y     c #747474",
+"z     c #D6D6D5",
+"A     c #DFDFDF",
+"B     c #A0A0A0",
+"C     c #615C5B",
+"D     c #F9F0E4",
+"E     c #746C67",
+"F     c #FEFDFC",
+"G     c #FFFEFD",
+"H     c #131210",
+"I     c #636363",
+"J     c #7C7C7C",
+"K     c #F3F2F2",
+"L     c #98948F",
+"M     c #F9EFE3",
+"N     c #A09489",
+"O     c #FEFDFD",
+"P     c #766D68",
+"Q     c #736961",
+"R     c #A3A3A2",
+"S     c #A6A6A6",
+"T     c #DBDBDB",
+"U     c #C7C7C7",
+"V     c #E8E5E2",
+"W     c #97938E",
+"X     c #F6E9D8",
+"Y     c #84817A",
+"Z     c #FBF3EA",
+"`     c #908C86",
+" .    c #F1EDE7",
+"..    c #7B7975",
+"+.    c #878786",
+"@.    c #070000",
+"#.    c #FAFAFA",
+"$.    c #DDDDDD",
+"%.    c #E2DFDC",
+"&.    c #A8A199",
+"*.    c #F0E0CE",
+"=.    c #C8BFB4",
+"-.    c #D5CCBF",
+";.    c #DFD7CD",
+">.    c #DAD3C9",
+",.    c #DDCFC4",
+"'.    c #928C84",
+").    c #A8A8A8",
+"!.    c #959595",
+"~.    c #040000",
+"{.    c #D9D5D2",
+"].    c #D9CABB",
+"^.    c #D7C8B8",
+"/.    c #DECFBF",
+"(.    c #D8C9B9",
+"_.    c #E3D3C2",
+":.    c #C9BBAC",
+"<.    c #D9CEC2",
+"[.    c #7F766D",
+"}.    c #909090",
+"|.    c #D3D3D3",
+"1.    c #060100",
+"2.    c #C0BDBA",
+"3.    c #8C8782",
+"4.    c #C2B5A7",
+"5.    c #BFB4A6",
+"6.    c #B8AB9D",
+"7.    c #BAAD9E",
+"8.    c #BEB0A2",
+"9.    c #948A7F",
+"0.    c #716860",
+"a.    c #E2E2E2",
+"b.    c #A9A9A8",
+"c.    c #332C2B",
+"d.    c #5D5954",
+"e.    c #79736C",
+"f.    c #958C80",
+"g.    c #8D8379",
+"h.    c #988D82",
+"i.    c #706760",
+"j.    c #787878",
+"k.    c #E4E4E4",
+"l.    c #C2C2C2",
+"m.    c #201A1A",
+"n.    c #57514F",
+"o.    c #625C59",
+"p.    c #625A53",
+"q.    c #6B625A",
+"r.    c #585251",
+"s.    c #696764",
+"t.    c #080000",
+"u.    c #989898",
+"v.    c #B0B0B0",
+"w.    c #AFAFAF",
+"x.    c #999999",
+"y.    c #9D9897",
+"z.    c #050000",
+"A.    c #0C0303",
+"B.    c #080100",
+"C.    c #030000",
+"D.    c #282523",
+"E.    c #5A5A5A",
+"F.    c #868686",
+"G.    c #ECE4E2",
+"H.    c #DED7D5",
+"I.    c #D8D1D0",
+"J.    c #E0DBD7",
+"K.    c #E9E6E3",
+"L.    c #FCFBFA",
+"M.    c #030500",
+"N.    c #0B0505",
+"O.    c #14100F",
+"P.    c #090806",
+"Q.    c #000100",
+"                                                ",
+"    . . . . . . . . . . . . . . . . . . . .     ",
+"    . + @ @ @ @ @ @ @ # # # # # # # # # $ .     ",
+"    . @ % % % & & & & * * * * * = = = = - .     ",
+"    . # & & & * * * * = = = = = ; ; ; ; > .     ",
+"    . , ' ' ' ) ) ) ) - - - - - > > > > ! .     ",
+"    . ~ { { { { { { { { { { { { { { { { ; .     ",
+"    . # ; ; ; ] ] ] ] ] ^ ^ ^ ^ $ $ $ $ / .     ",
+"    . # ] ] ] ( ^ ^ ^ _ : < [ } | 1 | 2 3 .     ",
+"    . 4 5 5 5 / / / 6 7 8 . 9 0 - a a a b .     ",
+"    . ~ c d d d d d e f g . h i $ j j k * .     ",
+"    . ~ 2 2 2 2 l l m n o . > p q r r r < .     ",
+"    . ~ l l l l s s t u v w . x . y p z < .     ",
+"    . A B B B B < 9 . C D E F . G H . I J .     ",
+"    . ~ @ , , , j . K L M N O P F Q R . S .     ",
+"    . ~ T T T T U . V W X Y Z `  ...+.@.< .     ",
+"    . #.$.$.$.$.& . %.&.*.=.-.;.>.,.'.@.p .     ",
+"    . { ).).).).!.~.{.].^./.(._.:.<.[.@.}..     ",
+"    . #.@ c c c |.1.2.3.4.5.6.7.8.9.0.@.] .     ",
+"    . #.a.a.a.a.l b.c.d.e.f.g.9.h.i.. j.q .     ",
+"    . #.a.a.a.a.k.l.j.m.n.o.p.q.r.s.t.u.q .     ",
+"    . a.v.v.v.v.v.w.x.y.z.A.t.B.C.D.E.F.m .     ",
+"    . . . . . . . . . ~.G.H.I.J.K.L.M.. . .     ",
+"                      ~.N.z.O.C.P.. Q.          "};
diff --git a/xemacs-packages/gnus/etc/images/jump-to.xpm b/xemacs-packages/gnus/etc/images/jump-to.xpm
new file mode 100644 (file)
index 0000000..8f98979
--- /dev/null
@@ -0,0 +1,171 @@
+/* XPM */
+static char * jump_to_xpm[] = {
+"24 24 144 2",
+"      c None",
+".     c #000000",
+"+     c #9ABC82",
+"@     c #C1E3AA",
+"#     c #A0C487",
+"$     c #8F6508",
+"%     c #AD671D",
+"&     c #D6AF41",
+"*     c #E1B744",
+"=     c #B86F20",
+"-     c #7E5907",
+";     c #D8E7CD",
+">     c #D9E7CF",
+",     c #DDEAD2",
+"'     c #E4EFDA",
+")     c #EBF6DF",
+"!     c #C8EBB0",
+"~     c #A2C688",
+"{     c #986F26",
+"]     c #E2B946",
+"^     c #EFCD64",
+"/     c #F4D268",
+"(     c #F6D469",
+"_     c #E7C24A",
+":     c #D5B044",
+"<     c #BC8C31",
+"[     c #1A0700",
+"}     c #D7E6CD",
+"|     c #B2D29C",
+"1     c #B6D69F",
+"2     c #BDDEA5",
+"3     c #C4E7AC",
+"4     c #CAEEB1",
+"5     c #A1C387",
+"6     c #CBB86E",
+"7     c #EDD97E",
+"8     c #FEE882",
+"9     c #FEE77E",
+"0     c #FDDF60",
+"a     c #FBD14F",
+"b     c #E4BF49",
+"c     c #BB8C31",
+"d     c #CFE2C3",
+"e     c #B2D19C",
+"f     c #B5D59F",
+"g     c #BBDBA4",
+"h     c #C1E3A9",
+"i     c #C6E9AE",
+"j     c #C3E6AB",
+"k     c #A9CE8D",
+"l     c #DCBA5C",
+"m     c #FBE46B",
+"n     c #FFEB64",
+"o     c #FFE054",
+"p     c #FED952",
+"q     c #F8CF4E",
+"r     c #C4A13E",
+"s     c #8BA27B",
+"t     c #618249",
+"u     c #628349",
+"v     c #64864B",
+"w     c #66894D",
+"x     c #688B4E",
+"y     c #678B4D",
+"z     c #6B9251",
+"A     c #719755",
+"B     c #55833A",
+"C     c #ECC75E",
+"D     c #FFED59",
+"E     c #FFE757",
+"F     c #FFDF54",
+"G     c #FBD44F",
+"H     c #E1BD48",
+"I     c #B36C1F",
+"J     c #608148",
+"K     c #628449",
+"L     c #63854A",
+"M     c #65894C",
+"N     c #6C9151",
+"O     c #527E39",
+"P     c #B39237",
+"Q     c #F0C248",
+"R     c #FFF25B",
+"S     c #FFEB58",
+"T     c #FFE155",
+"U     c #FBD450",
+"V     c #E3BD49",
+"W     c #BC983B",
+"X     c #618349",
+"Y     c #628549",
+"Z     c #65884B",
+"`     c #4D7735",
+" .    c #907934",
+"..    c #DCB444",
+"+.    c #FCDB52",
+"@.    c #FFEF5A",
+"#.    c #FFE957",
+"$.    c #FEDF54",
+"%.    c #F9D24F",
+"&.    c #E0BA48",
+"*.    c #B08F37",
+"=.    c #52743B",
+"-.    c #456A2F",
+";.    c #608248",
+">.    c #628448",
+",.    c #476F31",
+"'.    c #7F6B32",
+").    c #D0AF4B",
+"!.    c #F5CF4E",
+"~.    c #FFE255",
+"{.    c #FEDA52",
+"].    c #EAC54B",
+"^.    c #D0AC42",
+"/.    c #9C5D1A",
+"(.    c #5A7B42",
+"_.    c #456C2F",
+":.    c #6F5C23",
+"<.    c #A78833",
+"[.    c #F0C54A",
+"}.    c #FFDA52",
+"|.    c #FFDE53",
+"1.    c #C39032",
+"2.    c #886423",
+"3.    c #BC9D3B",
+"4.    c #F0C84E",
+"5.    c #FFD551",
+"6.    c #FED751",
+"7.    c #FDD550",
+"8.    c #EDC74C",
+"9.    c #E5BF49",
+"0.    c #CCA941",
+"a.    c #AB7727",
+"b.    c #B1822D",
+"c.    c #DCB746",
+"d.    c #DFBA47",
+"e.    c #EDC64C",
+"f.    c #E9C34B",
+"g.    c #D6B144",
+"h.    c #C19D3D",
+"i.    c #AB7C2B",
+"j.    c #BC7222",
+"k.    c #BB983B",
+"l.    c #B09638",
+"m.    c #A2621B",
+"                                                ",
+"                                                ",
+"            .                                   ",
+"            . .                                 ",
+"            . + .       . . . . . .             ",
+"  . . . . . . @ # .   . $ % & * = - . .         ",
+"  . ; > , ' ) ! ! ~ . { ] ^ / ( _ : < [ .       ",
+"  . } | 1 2 3 4 4 3 5 . 6 7 8 9 0 a b c .       ",
+"  . d e f g h i i h j k . l m n o p q r - .     ",
+"  . s t u v w x x y z A B . C D E F G H I .     ",
+"  . s J t K L v v M N O . P Q R S T U V W .     ",
+"  . s J J t X u Y Z ` .  ...+.@.#.$.%.&.*..     ",
+"  . =.-.-.-.-.;.>.,.. '.).!.E E ~.{.].^./..     ",
+"  . . . . . . (._.. :.<.[.}.|.|.{.%.V 1.$ .     ",
+"            . -.. . 2.3.4.5.6.7.8.9.0.a..       ",
+"            . .   . . b.c.d.e.f.g.h.i.. .       ",
+"            .         . $ j.k.l.m.$ . .         ",
+"                        . . . . . .             ",
+"                                                ",
+"                                                ",
+"                                                ",
+"                                                ",
+"                                                ",
+"                                                "};
diff --git a/xemacs-packages/gnus/etc/images/left-arrow.xpm b/xemacs-packages/gnus/etc/images/left-arrow.xpm
new file mode 100644 (file)
index 0000000..586fe44
--- /dev/null
@@ -0,0 +1,70 @@
+/* XPM */
+static char * left_arrow_xpm[] = {
+"24 24 43 1",
+"      c None",
+".     c #000000",
+"+     c #B9D0B9",
+"@     c #CDDECB",
+"#     c #B6C7B6",
+"$     c #B1C9B0",
+"%     c #B3C4B3",
+"&     c #B4CBB2",
+"*     c #B5CEB5",
+"=     c #B7CCB5",
+"-     c #B9CEB7",
+";     c #BAD1BA",
+">     c #BBCFBA",
+",     c #BBD0B9",
+"'     c #B2C9B0",
+")     c #7EAB78",
+"!     c #AAC7A8",
+"~     c #B3CAB1",
+"{     c #B0C9B0",
+"]     c #B0C9AE",
+"^     c #AEC7AC",
+"/     c #AAC5A8",
+"(     c #A9C4A7",
+"_     c #698267",
+":     c #2D2D2D",
+"<     c #CFDFCC",
+"[     c #ADC8AB",
+"}     c #B0C7AE",
+"|     c #ADC6AB",
+"1     c #678C63",
+"2     c #9BAD9A",
+"3     c #85AE81",
+"4     c #87AF84",
+"5     c #87B083",
+"6     c #88AF84",
+"7     c #88B085",
+"8     c #86AF82",
+"9     c #547150",
+"0     c #3C5235",
+"a     c #5B7950",
+"b     c #4A6342",
+"c     c #3B5035",
+"d     c #415639",
+"                        ",
+"                        ",
+"                        ",
+"            .           ",
+"           ..           ",
+"          .+.           ",
+"         .@#.           ",
+"        .@$%........    ",
+"       .@&*=-;->,').    ",
+"      .@!~{]^///^(_.    ",
+"     :<[}||[!^^}^[1.    ",
+"    .23444445645789.    ",
+"     .0aaaaaaaaaaab.    ",
+"      .0aaaaaaaaaab.    ",
+"       .0aabccccccd.    ",
+"        .0ab........    ",
+"         .0b.           ",
+"          .b.           ",
+"           ..           ",
+"            .           ",
+"                        ",
+"                        ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/lock-broken.xpm b/xemacs-packages/gnus/etc/images/lock-broken.xpm
new file mode 100644 (file)
index 0000000..15676bd
--- /dev/null
@@ -0,0 +1,231 @@
+/* XPM */
+static char * stock_lock_broken_xpm[] = {
+"24 24 204 2",
+"      c None",
+".     c #0E0E0E",
+"+     c #262626",
+"@     c #464646",
+"#     c #3C3C3C",
+"$     c #3B3B3B",
+"%     c #212121",
+"&     c #252525",
+"*     c #ADADAD",
+"=     c #F0F0F0",
+"-     c #EAEAEA",
+";     c #1A1A1A",
+">     c #000000",
+",     c #FAFAFA",
+"'     c #F4F4F4",
+")     c #4D4D4D",
+"!     c #303030",
+"~     c #D8D8D8",
+"{     c #E5E5E5",
+"]     c #B0B0B0",
+"^     c #414141",
+"/     c #484848",
+"(     c #030303",
+"_     c #DADADA",
+":     c #E4E4E4",
+"<     c #353535",
+"[     c #070707",
+"}     c #A6A6A6",
+"|     c #E6E6E6",
+"1     c #686868",
+"2     c #020202",
+"3     c #3E3E3E",
+"4     c #EFEFEF",
+"5     c #9B9B9B",
+"6     c #343434",
+"7     c #F8F8F8",
+"8     c #999999",
+"9     c #F1F1F1",
+"0     c #C4C4C4",
+"a     c #232323",
+"b     c #535353",
+"c     c #AEAEAE",
+"d     c #F3F3F3",
+"e     c #D3D3D3",
+"f     c #242424",
+"g     c #4E4E4E",
+"h     c #EEEEEE",
+"i     c #B5B5B5",
+"j     c #0F0601",
+"k     c #200E03",
+"l     c #765E49",
+"m     c #7D6A56",
+"n     c #38291D",
+"o     c #180A03",
+"p     c #D6CBC1",
+"q     c #A09E9D",
+"r     c #1D1109",
+"s     c #2A1E13",
+"t     c #3D2E21",
+"u     c #3F3123",
+"v     c #47423D",
+"w     c #DBB98E",
+"x     c #D6B183",
+"y     c #D3AC7E",
+"z     c #CFA573",
+"A     c #CD9E67",
+"B     c #C39056",
+"C     c #46270A",
+"D     c #281F14",
+"E     c #675643",
+"F     c #A48367",
+"G     c #D8AB7C",
+"H     c #BF9E7C",
+"I     c #DCBB93",
+"J     c #DCB786",
+"K     c #D1A872",
+"L     c #231B12",
+"M     c #7B6C58",
+"N     c #C69B63",
+"O     c #C39860",
+"P     c #C09257",
+"Q     c #BD8A4A",
+"R     c #B9803D",
+"S     c #AA6E28",
+"T     c #412409",
+"U     c #100B07",
+"V     c #CDB598",
+"W     c #E8CCA9",
+"X     c #DAB587",
+"Y     c #D4AC7D",
+"Z     c #D1A775",
+"`     c #C99F6A",
+" .    c #AF8B5B",
+"..    c #2E2517",
+"+.    c #1E1910",
+"@.    c #0B0805",
+"#.    c #594B39",
+"$.    c #2A2015",
+"%.    c #C2975E",
+"&.    c #BE8D50",
+"*.    c #BB823F",
+"=.    c #AE722C",
+"-.    c #422409",
+";.    c #0E0B07",
+">.    c #AB957E",
+",.    c #E9CEAC",
+"'.    c #DBB68A",
+").    c #D5AD7E",
+"!.    c #D0A975",
+"~.    c #C9A26F",
+"{.    c #B99667",
+"].    c #AA895F",
+"^.    c #31291C",
+"/.    c #322A1C",
+"(.    c #54493B",
+"_.    c #C69C64",
+":.    c #C2965E",
+"<.    c #BE8E50",
+"[.    c #C29156",
+"}.    c #9E692A",
+"|.    c #1A150D",
+"1.    c #887762",
+"2.    c #EAD1AF",
+"3.    c #DDB98E",
+"4.    c #D4AC7E",
+"5.    c #D2A876",
+"6.    c #C39E6D",
+"7.    c #927751",
+"8.    c #15110C",
+"9.    c #988468",
+"0.    c #C2945A",
+"a.    c #BE8F51",
+"b.    c #BC8544",
+"c.    c #BE8A4F",
+"d.    c #9A6526",
+"e.    c #70604D",
+"f.    c #EFD6B5",
+"g.    c #DEBD93",
+"h.    c #D4AC7C",
+"i.    c #D0A672",
+"j.    c #C9A069",
+"k.    c #9D7E53",
+"l.    c #140F09",
+"m.    c #1F1710",
+"n.    c #EFD8B9",
+"o.    c #E3C39C",
+"p.    c #D7B080",
+"q.    c #D4AC79",
+"r.    c #CDA46F",
+"s.    c #3A2C1B",
+"t.    c #FFFFFF",
+"u.    c #1C160D",
+"v.    c #B29E85",
+"w.    c #E6C8A3",
+"x.    c #D7B081",
+"y.    c #D1A874",
+"z.    c #CBA16A",
+"A.    c #BA905A",
+"B.    c #251C10",
+"C.    c #DF421E",
+"D.    c #F7F7F7",
+"E.    c #DFDFDF",
+"F.    c #2F2619",
+"G.    c #92806A",
+"H.    c #E6C7A2",
+"I.    c #D6AF7E",
+"J.    c #CCA26C",
+"K.    c #53422A",
+"L.    c #211910",
+"M.    c #2A2014",
+"N.    c #E1E1E1",
+"O.    c #6A5C4A",
+"P.    c #EAD0AD",
+"Q.    c #DAB68B",
+"R.    c #D2A978",
+"S.    c #CEA56E",
+"T.    c #C89D66",
+"U.    c #856740",
+"V.    c #534026",
+"W.    c #F9F9F9",
+"X.    c #FBFBFB",
+"Y.    c #E2E2E2",
+"Z.    c #42362B",
+"`.    c #D1BA9B",
+" +    c #DCBA8E",
+".+    c #D1A773",
+"++    c #C4975C",
+"@+    c #BE8C4C",
+"#+    c #B4813F",
+"$+    c #281B0B",
+"%+    c #E3E3E3",
+"&+    c #372416",
+"*+    c #74654F",
+"=+    c #B68E5C",
+"-+    c #926231",
+";+    c #452B11",
+">+    c #341E09",
+",+    c #221205",
+"'+    c #150802",
+")+    c #FDFDFD",
+"!+    c #030000",
+"~+    c #050000",
+"{+    c #010000",
+"]+    c #C3C3C3",
+"                                                ",
+"                                                ",
+"            . + @ #           $ %               ",
+"          & * = - ;         > , ' ) >           ",
+"        ! ~ { ] ^ /         ( $ _ : <           ",
+"      [ } | 1 2                 3 4 5 >         ",
+"      6 7 8 >                   > 9 0 a         ",
+"      b 9 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 `  ...+.      @.#.$.%.&.*.=.-.    ",
+"  ;.>.,.'.).!.~.{.].^./.      (._.:.<.[.}.-.    ",
+"  |.1.2.3.4.5.6.7.8.        > 9.0.a.b.c.d.T     ",
+"    e.f.g.h.i.j.k.l.>     > > > > > > > > >     ",
+"    m.n.o.p.q.r._.s.      > t.t.t.t.t.t.t.>     ",
+"    u.v.w.x.y.z.A.B.>     > t.C.C.D.C.C.E.>     ",
+"    F.G.H.I.i.J.K.L.M.    > t.C.C.C.C.C.N.>     ",
+"      O.P.Q.R.S.T.U.V.    > t.W.C.C.C.X.Y.>     ",
+"      Z.`. +.+z.++@+#+$+> > t.C.C.C.C.C.%+>     ",
+"      &+*+=+-+;+>+,+'+    > t.C.C.)+C.C.{ >     ",
+"        !+~+{+>           > - %+%+: { { ]+>     ",
+"                          > > > > > > > > >     ",
+"                                                "};
diff --git a/xemacs-packages/gnus/etc/images/lock-ok.xpm b/xemacs-packages/gnus/etc/images/lock-ok.xpm
new file mode 100644 (file)
index 0000000..630d9b4
--- /dev/null
@@ -0,0 +1,215 @@
+/* XPM */
+static char * stock_lock_ok_xpm[] = {
+"24 24 188 2",
+"      c None",
+".     c #000000",
+"+     c #212121",
+"@     c #9E9E9E",
+"#     c #E6E6E6",
+"$     c #E7E7E7",
+"%     c #C8C8C8",
+"&     c #A0A0A0",
+"*     c #131313",
+"=     c #5F5F5F",
+"-     c #EDEDED",
+";     c #D6D6D6",
+">     c #D5D5D5",
+",     c #DDDDDD",
+"'     c #D8D8D8",
+")     c #A1A1A1",
+"!     c #3C3C3C",
+"~     c #353535",
+"{     c #EFEFEF",
+"]     c #CFCFCF",
+"^     c #4C4C4C",
+"/     c #141414",
+"(     c #6A6A6A",
+"_     c #D0D0D0",
+":     c #B2B2B2",
+"<     c #454545",
+"[     c #E2E2E2",
+"}     c #292929",
+"|     c #0F0F0F",
+"1     c #949494",
+"2     c #E9E9E9",
+"3     c #C3C3C3",
+"4     c #1C1C1C",
+"5     c #E1E1E1",
+"6     c #272727",
+"7     c #DEDEDE",
+"8     c #B6B6B6",
+"9     c #B7B6B6",
+"0     c #150902",
+"a     c #2E2419",
+"b     c #251D15",
+"c     c #616160",
+"d     c #5E5A56",
+"e     c #29211A",
+"f     c #15100C",
+"g     c #2F251B",
+"h     c #1D1710",
+"i     c #4A392B",
+"j     c #656361",
+"k     c #565352",
+"l     c #392B1D",
+"m     c #322110",
+"n     c #0C0500",
+"o     c #EFDBBF",
+"p     c #EDD9C0",
+"q     c #E9D5BE",
+"r     c #E7D2B9",
+"s     c #E5D0B3",
+"t     c #DCC09D",
+"u     c #D9BE99",
+"v     c #DABE99",
+"w     c #D7BB95",
+"x     c #D5B68E",
+"y     c #D2AF85",
+"z     c #CFA77C",
+"A     c #9A5E1B",
+"B     c #F0DABF",
+"C     c #E4C6A0",
+"D     c #D6AF80",
+"E     c #D3AC7B",
+"F     c #D0A570",
+"G     c #C99F68",
+"H     c #C69B64",
+"I     c #C69C64",
+"J     c #C89D66",
+"K     c #C79C65",
+"L     c #C39860",
+"M     c #C09256",
+"N     c #BC8645",
+"O     c #B67C36",
+"P     c #985E1A",
+"Q     c #EED8BC",
+"R     c #E3C39C",
+"S     c #D3AA7B",
+"T     c #CFA670",
+"U     c #CA9F68",
+"V     c #C89E66",
+"W     c #C89F68",
+"X     c #C49961",
+"Y     c #C09358",
+"Z     c #BC8746",
+"`     c #B77D39",
+" .    c #EED8BB",
+"..    c #E2C29B",
+"+.    c #D6AE7F",
+"@.    c #CA9E6D",
+"#.    c #C69861",
+"$.    c #BF925A",
+"%.    c #BB8E56",
+"&.    c #BD8E56",
+"*.    c #5C7354",
+"=.    c #EFDABE",
+"-.    c #E4C49D",
+";.    c #D7B080",
+">.    c #DAB685",
+",.    c #D4B07C",
+"'.    c #D0A971",
+").    c #CEA46B",
+"!.    c #CDA46D",
+"~.    c #FFFFFF",
+"{.    c #DBE0D9",
+"].    c #52684B",
+"^.    c #4E6346",
+"/.    c #52674A",
+"(.    c #EFD8BB",
+"_.    c #E0C199",
+":.    c #D3AA7A",
+"<.    c #C89B67",
+"[.    c #C3965F",
+"}.    c #BC8E56",
+"|.    c #BA8B52",
+"1.    c #BA8C54",
+"2.    c #F6F6F6",
+"3.    c #F7F7F7",
+"4.    c #F8F8F8",
+"5.    c #E6E9E5",
+"6.    c #6B8064",
+"7.    c #4B5F45",
+"8.    c #44553D",
+"9.    c #E3C29C",
+"0.    c #D9B484",
+"a.    c #D4AE77",
+"b.    c #CFA770",
+"c.    c #CCA46B",
+"d.    c #CBA36B",
+"e.    c #B6BEB3",
+"f.    c #4E6047",
+"g.    c #788274",
+"h.    c #CBD2C9",
+"i.    c #6A8063",
+"j.    c #384834",
+"k.    c #EDD6B8",
+"l.    c #E1BD94",
+"m.    c #D1A874",
+"n.    c #BD9058",
+"o.    c #B7874E",
+"p.    c #B48349",
+"q.    c #B5844C",
+"r.    c #8F9C8A",
+"s.    c #53684B",
+"t.    c #475841",
+"u.    c #657C5E",
+"v.    c #4A5D44",
+"w.    c #626E5D",
+"x.    c #EED8BA",
+"y.    c #E0C099",
+"z.    c #D8B37F",
+"A.    c #D2AD76",
+"B.    c #CEA66F",
+"C.    c #CCA46D",
+"D.    c #FAFAFA",
+"E.    c #6A7E63",
+"F.    c #63715E",
+"G.    c #E3E3E3",
+"H.    c #EED5B7",
+"I.    c #DFC096",
+"J.    c #D2A776",
+"K.    c #CEA46E",
+"L.    c #C89D65",
+"M.    c #C49960",
+"N.    c #C1955C",
+"O.    c #C2955C",
+"P.    c #FBFBFB",
+"Q.    c #FCFCFC",
+"R.    c #80937A",
+"S.    c #6D796A",
+"T.    c #FEFEFE",
+"U.    c #E5E5E5",
+"V.    c #AC8C65",
+"W.    c #CFA772",
+"X.    c #C49256",
+"Y.    c #C08D51",
+"Z.    c #BA8849",
+"`.    c #B78342",
+" +    c #B48240",
+".+    c #B68241",
+"++    c #EAEAEA",
+"@+    c #E4E4E4",
+"                                                ",
+"                                                ",
+"                    . . . . .                   ",
+"                . + @ # $ % & *                 ",
+"              . = - # ; > , ' ) ! .             ",
+"              ~ { ] ^ . . / ( _ : <             ",
+"            . [ ' } .       | ( % 1 .           ",
+"            * 2 3 .           4 5 @ .           ",
+"            6 7 8 .           . $ 9 .           ",
+"        0 a b c d e f g b h b i j k l m n       ",
+"        . o p q r s t u u v u w x y z A .       ",
+"        . B C D E F G H I J K L M N O P .       ",
+"        . Q R D S T U I V W V X Y Z ` A .       ",
+"        .  ...+.@.#.$.%.&.. . . . . . . . . *.  ",
+"        . =.-.;.>.,.'.).!.. ~.~.~.~.~.~.{.].^./.",
+"        . (._.:.<.[.}.|.1.. ~.2.3.3.4.5.6.7.8.  ",
+"        . Q 9.+.0.a.b.c.d.. ~.e.f.g.h.i.7.j.    ",
+"        . k.l.m.#.n.o.p.q.. ~.r.s.t.u.v.w..     ",
+"        . x.y.S z.A.B.c.C.. ~.D.E.s./.F.G..     ",
+"        . H.I.J.K.L.M.N.O.. ~.P.Q.R.S.T.U..     ",
+"        . V.W.X.Y.Z.`. +.+. ++G.G.@+U.U.3 .     ",
+"          . . . . . . . . . . . . . . . . .     ",
+"                                                ",
+"                                                "};
diff --git a/xemacs-packages/gnus/etc/images/lock.xpm b/xemacs-packages/gnus/etc/images/lock.xpm
new file mode 100644 (file)
index 0000000..c9aa18d
--- /dev/null
@@ -0,0 +1,227 @@
+/* XPM */
+static char * stock_lock_xpm[] = {
+"24 24 200 2",
+"      c None",
+".     c #000000",
+"+     c #212121",
+"@     c #9E9E9E",
+"#     c #E6E6E6",
+"$     c #E7E7E7",
+"%     c #C8C8C8",
+"&     c #A0A0A0",
+"*     c #131313",
+"=     c #5F5F5F",
+"-     c #EDEDED",
+";     c #D6D6D6",
+">     c #D5D5D5",
+",     c #DDDDDD",
+"'     c #D8D8D8",
+")     c #A1A1A1",
+"!     c #3C3C3C",
+"~     c #353535",
+"{     c #EFEFEF",
+"]     c #CFCFCF",
+"^     c #4C4C4C",
+"/     c #141414",
+"(     c #6A6A6A",
+"_     c #D0D0D0",
+":     c #B2B2B2",
+"<     c #454545",
+"[     c #E2E2E2",
+"}     c #292929",
+"|     c #0F0F0F",
+"1     c #949494",
+"2     c #E9E9E9",
+"3     c #C3C3C3",
+"4     c #1C1C1C",
+"5     c #E1E1E1",
+"6     c #272727",
+"7     c #DEDEDE",
+"8     c #B6B6B6",
+"9     c #B7B6B6",
+"0     c #150902",
+"a     c #2E2419",
+"b     c #251D15",
+"c     c #616160",
+"d     c #5E5A56",
+"e     c #29211A",
+"f     c #15100C",
+"g     c #2F251B",
+"h     c #1D1710",
+"i     c #4A392B",
+"j     c #656361",
+"k     c #565352",
+"l     c #392B1D",
+"m     c #322110",
+"n     c #0C0500",
+"o     c #EFDBBF",
+"p     c #EDD9C0",
+"q     c #E9D5BE",
+"r     c #E7D2B9",
+"s     c #E5D0B3",
+"t     c #DCC09D",
+"u     c #D9BE99",
+"v     c #DABE99",
+"w     c #D7BB95",
+"x     c #D5B68E",
+"y     c #D2AF85",
+"z     c #CFA77C",
+"A     c #9A5E1B",
+"B     c #F0DABF",
+"C     c #E4C6A0",
+"D     c #D6AF80",
+"E     c #D3AC7B",
+"F     c #D0A570",
+"G     c #C99F68",
+"H     c #C69B64",
+"I     c #C69C64",
+"J     c #C89D66",
+"K     c #C79C65",
+"L     c #C39860",
+"M     c #C09256",
+"N     c #BC8645",
+"O     c #B67C36",
+"P     c #985E1A",
+"Q     c #EED8BC",
+"R     c #E3C39C",
+"S     c #D3AA7B",
+"T     c #CFA670",
+"U     c #CA9F68",
+"V     c #C89E66",
+"W     c #C89F68",
+"X     c #C49961",
+"Y     c #C09358",
+"Z     c #BC8746",
+"`     c #B77D39",
+" .    c #EED8BB",
+"..    c #E2C29B",
+"+.    c #D6AE7F",
+"@.    c #CA9E6D",
+"#.    c #C69861",
+"$.    c #BF925A",
+"%.    c #BB8E56",
+"&.    c #BD8E56",
+"*.    c #BD9058",
+"=.    c #BC8F58",
+"-.    c #B9884E",
+";.    c #B48145",
+">.    c #BA8442",
+",.    c #B47834",
+"'.    c #975C1A",
+").    c #EFDABE",
+"!.    c #E4C49D",
+"~.    c #D7B080",
+"{.    c #DAB685",
+"].    c #D4B07C",
+"^.    c #D0A971",
+"/.    c #CEA46B",
+"(.    c #CDA46D",
+"_.    c #CCA66D",
+":.    c #CCA46B",
+"<.    c #CA9F63",
+"[.    c #C79858",
+"}.    c #B9813F",
+"|.    c #B37834",
+"1.    c #975D1A",
+"2.    c #EFD8BB",
+"3.    c #E0C199",
+"4.    c #D3AA7A",
+"5.    c #C89B67",
+"6.    c #C3965F",
+"7.    c #BC8E56",
+"8.    c #BA8B52",
+"9.    c #BA8C54",
+"0.    c #BB8D55",
+"a.    c #BA8C55",
+"b.    c #B6864C",
+"c.    c #B47F43",
+"d.    c #BA833F",
+"e.    c #B37934",
+"f.    c #9B601E",
+"g.    c #E3C29C",
+"h.    c #D9B484",
+"i.    c #D4AE77",
+"j.    c #CFA770",
+"k.    c #CBA36B",
+"l.    c #CCA46C",
+"m.    c #CA9D61",
+"n.    c #C69856",
+"o.    c #BA813E",
+"p.    c #B27733",
+"q.    c #A36B2F",
+"r.    c #EDD6B8",
+"s.    c #E1BD94",
+"t.    c #D1A874",
+"u.    c #B7874E",
+"v.    c #B48349",
+"w.    c #B5844C",
+"x.    c #B5884D",
+"y.    c #B48146",
+"z.    c #B27A3C",
+"A.    c #B67D3A",
+"B.    c #B07530",
+"C.    c #A67137",
+"D.    c #EED8BA",
+"E.    c #E0C099",
+"F.    c #D8B37F",
+"G.    c #D2AD76",
+"H.    c #CEA66F",
+"I.    c #CCA46D",
+"J.    c #CCA56D",
+"K.    c #C99D61",
+"L.    c #C69858",
+"M.    c #B9803D",
+"N.    c #B67D38",
+"O.    c #AB783F",
+"P.    c #EED5B7",
+"Q.    c #DFC096",
+"R.    c #D2A776",
+"S.    c #CEA46E",
+"T.    c #C89D65",
+"U.    c #C49960",
+"V.    c #C1955C",
+"W.    c #C2955C",
+"X.    c #C2965C",
+"Y.    c #C09155",
+"Z.    c #BC8A4B",
+"`.    c #BE8A4C",
+" +    c #A9773C",
+".+    c #AC8C65",
+"++    c #CFA772",
+"@+    c #C49256",
+"#+    c #C08D51",
+"$+    c #BA8849",
+"%+    c #B78342",
+"&+    c #B48240",
+"*+    c #B68241",
+"=+    c #B88544",
+"-+    c #BB8949",
+";+    c #BC8748",
+">+    c #BA874A",
+",+    c #B98548",
+"'+    c #B27B3B",
+")+    c #6D4215",
+"                                                ",
+"                                                ",
+"                    . . . . .                   ",
+"                . + @ # $ % & *                 ",
+"              . = - # ; > , ' ) ! .             ",
+"              ~ { ] ^ . . / ( _ : <             ",
+"            . [ ' } .       | ( % 1 .           ",
+"            * 2 3 .           4 5 @ .           ",
+"            6 7 8 .           . $ 9 .           ",
+"        0 a b c d e f g b h b i j k l m n       ",
+"        . o p q r s t u u v u w x y z A .       ",
+"        . B C D E F G H I J K L M N O P .       ",
+"        . Q R D S T U I V W V X Y Z ` A .       ",
+"        .  ...+.@.#.$.%.&.*.=.-.;.>.,.'..       ",
+"        . ).!.~.{.].^./.(._.:.<.[.}.|.1..       ",
+"        . 2.3.4.5.6.7.8.9.0.a.b.c.d.e.f..       ",
+"        . Q g.+.h.i.j.:.k.l.k.m.n.o.p.q..       ",
+"        . r.s.t.#.*.u.v.w.x.b.y.z.A.B.C..       ",
+"        . D.E.S F.G.H.:.I.J.l.K.L.M.N.O..       ",
+"        . P.Q.R.S.T.U.V.W.X.X.Y.Z.>.`. +.       ",
+"        . .+++@+#+$+%+&+*+=+-+;+>+,+'+)+.       ",
+"          . . . . . . . . . . . . . . .         ",
+"                                                ",
+"                                                "};
diff --git a/xemacs-packages/gnus/etc/images/mail/README b/xemacs-packages/gnus/etc/images/mail/README
new file mode 100644 (file)
index 0000000..962206e
--- /dev/null
@@ -0,0 +1,37 @@
+COPYRIGHT AND LICENSE INFORMATION FOR IMAGE FILES
+
+The following icons are from GNOME 2.x. They are not part of Emacs,
+but are distributed and used by Emacs.  They are licensed under the
+GNU General Public License version 2 or later.  See the source of the
+gnome-icons-theme package for more information.
+
+Emacs images and their GNOME source (GNOME icons are from stock/net/
+directory unless otherwise stated):
+
+compose.xpm                 stock_mail-compose
+copy.xpm                    stock_mail-copy
+flag-for-followup.xpm       stock_mail-flag-for-followup
+forward.xpm                 stock_mail-forward
+inbox.xpm                   stock_inbox
+move.xpm                    stock_mail-move
+not-spam.xpm                stock_not-spam
+outbox.xpm                  stock_outbox
+preview.xpm                 combines stock_mail and navigation/stock_zoom
+reply-all.xpm               stock_mail-reply-to-all
+reply.xpm                   stock_mail-reply
+save-draft.xpm              stock_mail-handling
+save.xpm                    combines stock_mail, io/stock_save and
+                              stock_convert (from gnome-themes)
+send.xpm                    stock_mail-send
+spam.xpm                    stock_spam
+
+(preview and save were contributed by Adam Sjøgren <asjo@koldfront.dk>)
+
+repack is a slightly modified version of package-x-generic.
+reply-from is a slightly modified version of reply.
+reply-to is a slightly modified version of reply-all.
+
+
+The pbm versions (where present) were converted from the xpm versions
+via an essentially automatic procedure (see the README file in the
+parent of this directory).
diff --git a/xemacs-packages/gnus/etc/images/mail/compose.xpm b/xemacs-packages/gnus/etc/images/mail/compose.xpm
new file mode 100644 (file)
index 0000000..2329b3d
--- /dev/null
@@ -0,0 +1,225 @@
+/* XPM */
+static char * stock_mail_compose_xpm[] = {
+"24 24 198 2",
+"      c None",
+".     c #000000",
+"+     c #D1AF61",
+"@     c #F1E3AC",
+"#     c #FBA90F",
+"$     c #FFFFFF",
+"%     c #B5B5B5",
+"&     c #A06B09",
+"*     c #816000",
+"=     c #E0E0E0",
+"-     c #C1C1C1",
+";     c #F4F4F4",
+">     c #FDFDFD",
+",     c #E6C370",
+"'     c #F1D387",
+")     c #D58F0C",
+"!     c #B2B2B2",
+"~     c #C3C3C3",
+"{     c #FBFBFB",
+"]     c #A8A8A8",
+"^     c #F6F6F6",
+"/     c #B3B3B3",
+"(     c #FAFAFA",
+"_     c #ADADAD",
+":     c #767676",
+"<     c #5D5D5D",
+"[     c #404040",
+"}     c #F8F8F8",
+"|     c #F1D07E",
+"1     c #ACACAC",
+"2     c #F8F8F6",
+"3     c #E2E2E2",
+"4     c #858585",
+"5     c #4B4B49",
+"6     c #161616",
+"7     c #FBFBFA",
+"8     c #7D7D7D",
+"9     c #F2F2F2",
+"0     c #F0F0F0",
+"a     c #EFEFEF",
+"b     c #D5D5D5",
+"c     c #F9F9F9",
+"d     c #F6F6F3",
+"e     c #F3F3F3",
+"f     c #878786",
+"g     c #E5E5E5",
+"h     c #DFDFDF",
+"i     c #EBEBEB",
+"j     c #AEAEAE",
+"k     c #7B5307",
+"l     c #EDEDED",
+"m     c #EBEBE9",
+"n     c #E9E9E7",
+"o     c #E0E0DE",
+"p     c #BFBFBF",
+"q     c #F0F0ED",
+"r     c #F1D284",
+"s     c #CA870B",
+"t     c #9E9E9C",
+"u     c #DCDCD9",
+"v     c #D9D9D9",
+"w     c #D9D9D6",
+"x     c #D6D6D4",
+"y     c #E5E5E4",
+"z     c #D9D9D7",
+"A     c #BABABA",
+"B     c #AAAAAA",
+"C     c #E7E7E5",
+"D     c #E4E4E2",
+"E     c #E2E2E0",
+"F     c #EEEEEC",
+"G     c #979796",
+"H     c #D4D4D1",
+"I     c #DEDEDC",
+"J     c #DEDEDB",
+"K     c #BDBDBC",
+"L     c #E7E7E7",
+"M     c #EFEFED",
+"N     c #A6A6A5",
+"O     c #BA7C0A",
+"P     c #7A5B00",
+"Q     c #DBDBD9",
+"R     c #D5D5D3",
+"S     c #BCBCBC",
+"T     c #E3E3E3",
+"U     c #F2E6B6",
+"V     c #7B7B7B",
+"W     c #704B05",
+"X     c #676764",
+"Y     c #CBCBC7",
+"Z     c #C9C9C7",
+"`     c #DBDBD7",
+" .    c #D7D7D5",
+"..    c #D7D7D3",
+"+.    c #B4B4B4",
+"@.    c #E4E4E4",
+"#.    c #DBD5C1",
+"$.    c #7E6F57",
+"%.    c #755800",
+"&.    c #D9D9D5",
+"*.    c #D5D5D1",
+"=.    c #D0D0CE",
+"-.    c #BABAB8",
+";.    c #DDDDDB",
+">.    c #D1D1CF",
+",.    c #0E0E0E",
+"'.    c #535353",
+").    c #8D8D8B",
+"!.    c #C4C4C1",
+"~.    c #C4C4BF",
+"{.    c #C1C1BC",
+"].    c #D3D3D0",
+"^.    c #D1D1D0",
+"/.    c #DCDCDB",
+"(.    c #E0E0DC",
+"_.    c #898987",
+":.    c #C9C9C6",
+"<.    c #CDCDCA",
+"[.    c #D0D0CD",
+"}.    c #CECECB",
+"|.    c #CFCFCC",
+"1.    c #D0D0CC",
+"2.    c #B6B6B6",
+"3.    c #D4D4D0",
+"4.    c #C3C3C0",
+"5.    c #5B5B5B",
+"6.    c #91918D",
+"7.    c #91918F",
+"8.    c #9F9F9D",
+"9.    c #AFAFAC",
+"0.    c #B9B9B6",
+"a.    c #BEBEBB",
+"b.    c #C5C5C2",
+"c.    c #C8C8C5",
+"d.    c #CACAC7",
+"e.    c #CBCBC8",
+"f.    c #CCCCC9",
+"g.    c #CCCCC8",
+"h.    c #D2D2D0",
+"i.    c #D2D2CF",
+"j.    c #BFBFBD",
+"k.    c #9F9F9C",
+"l.    c #888886",
+"m.    c #878785",
+"n.    c #8C8C8A",
+"o.    c #959593",
+"p.    c #9C9C9A",
+"q.    c #A8A8A5",
+"r.    c #B1B1AE",
+"s.    c #B5B5B3",
+"t.    c #BBBBB8",
+"u.    c #BFBFBC",
+"v.    c #C2C2BE",
+"w.    c #D1D1CE",
+"x.    c #AEAEAB",
+"y.    c #9D9D9A",
+"z.    c #979794",
+"A.    c #949491",
+"B.    c #9A9A97",
+"C.    c #A3A3A0",
+"D.    c #AAAAA7",
+"E.    c #B0B0AC",
+"F.    c #B8B8B5",
+"G.    c #B0B0AE",
+"H.    c #CFCFCD",
+"I.    c #BEBEBC",
+"J.    c #B4B4B0",
+"K.    c #ACACA8",
+"L.    c #A4A4A2",
+"M.    c #A0A09C",
+"N.    c #A4A4A0",
+"O.    c #A8A8A6",
+"P.    c #ABABA7",
+"Q.    c #B2B2AE",
+"R.    c #A4A4A4",
+"S.    c #CECECC",
+"T.    c #CECECA",
+"U.    c #C6C6C2",
+"V.    c #BCBCB9",
+"W.    c #B3B3AF",
+"X.    c #ABABA9",
+"Y.    c #A6A6A3",
+"Z.    c #A0A09D",
+"`.    c #ACACA9",
+" +    c #A1A1A1",
+".+    c #B1B1AF",
+"++    c #B4B4B3",
+"@+    c #B4B4B1",
+"#+    c #B3B3B1",
+"$+    c #AEAEAA",
+"%+    c #A7A7A4",
+"&+    c #A2A2A0",
+"*+    c #A5A5A1",
+"=+    c #999997",
+"-+    c #929290",
+";+    c #949490",
+">+    c #9D9D9B",
+",+    c #858583",
+"                            . . .               ",
+"    . . . . . . . . . . . . + @ # . . .         ",
+"    . $ $ $ $ $ $ $ $ $ % & @ # * . = - .       ",
+"    . $ ; $ $ $ $ $ > > . , ' ) . ! ~ { ] .     ",
+"    . $ ^ $ $ $ > > > / & @ # * . ( _ : < [ .   ",
+"    . $ ^ $ { { { { } . , | ) . 1 2 3 4 5 6 .   ",
+"    . $ ; > > { { 7 8 & @ # * . ; 9 0 a b _ .   ",
+"    . $ 9 c ^ ^ d e . , | ) . f g 3 h i 3 - .   ",
+"    . $ 0 } } } 2 j k @ # * . l i m n n o p .   ",
+"    . $ a e 0 q l . , r s . t u v w x y z A .   ",
+"    . $ l ; ; 9 B & @ # * . C y y D o E z A .   ",
+"    . $ i F C g . , r s . G H E o I J I z K .   ",
+"    . $ L M i N O # # P . E o I J u Q Q R S .   ",
+"    . $ g T v . U V W . X Y Z u ` z  .z ..+..   ",
+"    . $ E y @.. #.$.%.. u Q ` &...R *...=.-..   ",
+"    . $ I ;.>.,.'.. . ).!.~.{.*.*.].^.].=.-..   ",
+"    . $ /.(.;.. . _.:.<.[.}.[.[.[.[.|.[.1.2..   ",
+"    . $ Q 3.4.5.6.7.8.9.0.a.4.b.c.d.e.f.g.! .   ",
+"    . $ h.i.|.j.k.l.m.n.o.p.q.r.s.t.a.u.v.! .   ",
+"    . $ w.1.f.|.4.x.y.z.z.A.B.k.C.q.D.E.F.G..   ",
+"    . $ i.w.w.w.H.e.I.J.K.L.M.M.N.L.O.P.Q.R..   ",
+"    . $ ^.w.=.S.T.T.g.U.V.W.J.X.Y.Z.Y.D.`. +.   ",
+"    . $ .+++@+@+@+#+#+Q.$+%+&+*+*+=+-+;+>+,+.   ",
+"    . . . . . . . . . . . . . . . . . . . .     "};
diff --git a/xemacs-packages/gnus/etc/images/mail/copy.xpm b/xemacs-packages/gnus/etc/images/mail/copy.xpm
new file mode 100644 (file)
index 0000000..25ccc17
--- /dev/null
@@ -0,0 +1,104 @@
+/* XPM */
+static char * stock_mail_copy_xpm[] = {
+"24 24 77 1",
+"      c None",
+".     c #010101",
+"+     c #2F2F2F",
+"@     c #E3E2E1",
+"#     c #FCFCFC",
+"$     c #B3B2B1",
+"%     c #95938E",
+"&     c #F7F7F7",
+"*     c #F5F4F2",
+"=     c #F8F8F8",
+"-     c #F7F6F6",
+";     c #EAE9E5",
+">     c #7B7976",
+",     c #D2CFCA",
+"'     c #E1E0DD",
+")     c #908E8B",
+"!     c #EBEAEA",
+"~     c #F1F0EE",
+"{     c #E2E0DD",
+"]     c #7C7B78",
+"^     c #C6C3C0",
+"/     c #E5E3DE",
+"(     c #DCDAD7",
+"_     c #8F8C88",
+":     c #EBEBEA",
+"<     c #EFEDEA",
+"[     c #DFDDDA",
+"}     c #787774",
+"|     c #C1BEBA",
+"1     c #E6E3E0",
+"2     c #EFEEEC",
+"3     c #CBCAC6",
+"4     c #ECECEC",
+"5     c #F3F2F0",
+"6     c #DCDCDC",
+"7     c #7D7C79",
+"8     c #B4B2AE",
+"9     c #E7E5E1",
+"0     c #F0EFEB",
+"a     c #E4E2DD",
+"b     c #7B7874",
+"c     c #AFACA6",
+"d     c #ABA8A3",
+"e     c #F9F8F6",
+"f     c #EAE9E8",
+"g     c #B0ADA7",
+"h     c #F5F3F0",
+"i     c #B9B8B6",
+"j     c #CBC9C4",
+"k     c #DEDBD5",
+"l     c #9D9994",
+"m     c #DBD9D6",
+"n     c #747370",
+"o     c #A09C97",
+"p     c #DAD8D5",
+"q     c #E7E6E3",
+"r     c #E8E6E1",
+"s     c #E0DED9",
+"t     c #F7F6F4",
+"u     c #D3D1CF",
+"v     c #868480",
+"w     c #C2BFBD",
+"x     c #DAD9D5",
+"y     c #F6F5F1",
+"z     c #D8D6D1",
+"A     c #F7F5F2",
+"B     c #92908B",
+"C     c #CCCAC5",
+"D     c #F7F6F2",
+"E     c #F5F4F0",
+"F     c #EAE8E3",
+"G     c #D2D0CB",
+"H     c #D9D7D2",
+"I     c #DAD8D3",
+"J     c #D5D3CE",
+"K     c #D6D4CF",
+"L     c #040404",
+"                        ",
+"                        ",
+"                        ",
+"   .+...........        ",
+"  .@###########$.       ",
+"  .#%&*=*-*-*;>,.       ",
+"  .#')!~-*-*{]^/.       ",
+"  .#~(_:~<~[}|1/.       ",
+"  .#~23]4567890a.       ",
+"  .#22~b.+...........   ",
+"  .#~2c.@###########$.  ",
+"  .#2de.#%&*=*-*-*;>,.  ",
+"  .fgeh.#')!~-*-*{]^/.  ",
+"  .ijkk.#~(_:~<~[}|1/.  ",
+"   .....#~23]4567890a.  ",
+"       .#22~l]mnopqrs.  ",
+"       .#~2ctuvwxoy0z.  ",
+"       .#2deetptAABrC.  ",
+"       .fgehDEAEAhFBG.  ",
+"       .ijkkkHIJKGGGB.  ",
+"        ............L   ",
+"                        ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/mail/forward.xpm b/xemacs-packages/gnus/etc/images/mail/forward.xpm
new file mode 100644 (file)
index 0000000..07af5fd
--- /dev/null
@@ -0,0 +1,92 @@
+/* XPM */
+static char * stock_mail_forward_xpm[] = {
+"24 24 65 1",
+"      c None",
+".     c #000000",
+"+     c #535353",
+"@     c #FFFFFF",
+"#     c #FEFEFE",
+"$     c #FDFDFD",
+"%     c #FCFCFC",
+"&     c #FBFBFB",
+"*     c #F9F9F9",
+"=     c #F8F8F8",
+"-     c #F7F7F7",
+";     c #F6F6F6",
+">     c #F5F5F5",
+",     c #F4F4F4",
+"'     c #E3E3E3",
+")     c #EEEEEE",
+"!     c #4F4F4F",
+"~     c #F3F3F3",
+"{     c #F2F2F2",
+"]     c #F1F1F1",
+"^     c #F0F0F0",
+"/     c #EFEFEF",
+"(     c #EDEDED",
+"_     c #AEAEAE",
+":     c #E4E4E4",
+"<     c #434343",
+"[     c #ACACAC",
+"}     c #C8C8C8",
+"|     c #A0A0A0",
+"1     c #D4D4D4",
+"2     c #ECECEC",
+"3     c #959595",
+"4     c #3E3E3E",
+"5     c #4D4D4D",
+"6     c #818181",
+"7     c #C6C6C6",
+"8     c #6A6A6A",
+"9     c #636363",
+"0     c #B9B9B9",
+"a     c #737373",
+"b     c #7C7C7C",
+"c     c #5B88B2",
+"d     c #9EB8D1",
+"e     c #5080AD",
+"f     c #B5C9DC",
+"g     c #AFC5DA",
+"h     c #B2C7DB",
+"i     c #B6CADD",
+"j     c #A4BDD5",
+"k     c #9CB7D1",
+"l     c #080D11",
+"m     c #BCBCBC",
+"n     c #9BB6D0",
+"o     c #A0BAD3",
+"p     c #9AB5CF",
+"q     c #97B3CE",
+"r     c #5F8BB4",
+"s     c #91B0CC",
+"t     c #95B2CE",
+"u     c #4C79A3",
+"v     c #49749C",
+"w     c #3F6588",
+"x     c #2A435B",
+"y     c #456F96",
+"z     c #375978",
+"                        ",
+"                        ",
+"                        ",
+"  .................     ",
+" .+@@@@#$%&*=-;>,'+.    ",
+" .)!@>,~{{]^^/)('!_.    ",
+" .@:<$~{{]^/))('![}.    ",
+" .@>:!&]^^/)(('<|1}.    ",
+" .@&>:<=^/)(2'!31:}.    ",
+" .@>>>:4>)(2'567::}.    ",
+" .@&>>:8<~2'!877>.}.    ",
+" .@>>:9@0!^!37a7>...    ",
+" .@&:9@>:1![7::b:.c.    ",
+" .@:a@>>>>:.......de.   ",
+" .@b@::::::.fghiiijkel  ",
+" .ammmmmmmm.nokknpokqr. ",
+"  ..........sdppnkkkotu.",
+"           .vwwwwwwwwx. ",
+"           .yzzzzzwwx.  ",
+"           .......wx.   ",
+"                 .x.    ",
+"                 ..     ",
+"                 .      ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/mail/inbox.pbm b/xemacs-packages/gnus/etc/images/mail/inbox.pbm
new file mode 100644 (file)
index 0000000..2c93e3c
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/mail/inbox.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/mail/inbox.xpm b/xemacs-packages/gnus/etc/images/mail/inbox.xpm
new file mode 100644 (file)
index 0000000..5774e3a
--- /dev/null
@@ -0,0 +1,103 @@
+/* XPM */
+static char * stock_inbox_xpm[] = {
+"24 24 76 1",
+"      c None",
+".     c #000000",
+"+     c #B5CADD",
+"@     c #BFD1E1",
+"#     c #C3D4E3",
+"$     c #C7D7E5",
+"%     c #B0C6DA",
+"&     c #6B94BB",
+"*     c #131E29",
+"=     c #739ABF",
+"-     c #7EA2C4",
+";     c #9AB6D0",
+">     c #E4EBF2",
+",     c #DDE6EF",
+"'     c #8CACCA",
+")     c #5C8AB4",
+"!     c #090F15",
+"~     c #B1C7DB",
+"{     c #D0DDEA",
+"]     c #D9E3ED",
+"^     c #88A9C8",
+"/     c #4D7CA7",
+"(     c #030405",
+"_     c #41688D",
+":     c #32506C",
+"<     c #C4D5E4",
+"[     c #A5BED5",
+"}     c #456F97",
+"|     c #3B5F81",
+"1     c #C8D8E6",
+"2     c #9CB8D2",
+"3     c #395B7B",
+"4     c #C6D6E4",
+"5     c #BBCEDF",
+"6     c #3D6183",
+"7     c #B6CBDE",
+"8     c #426A90",
+"9     c #E2C6A9",
+"0     c #E5CDB4",
+"a     c #D5AA7F",
+"b     c #9D6733",
+"c     c #CB9967",
+"d     c #ADC4D9",
+"e     c #B99877",
+"f     c #CFBAA4",
+"g     c #9A7149",
+"h     c #CDA378",
+"i     c #D2A87E",
+"j     c #608DB6",
+"k     c #AA7B4B",
+"l     c #C2A588",
+"m     c #996633",
+"n     c #BB9978",
+"o     c #C3976B",
+"p     c #D2A980",
+"q     c #D1A77D",
+"r     c #E0C4A8",
+"s     c #C9B097",
+"t     c #D7B38E",
+"u     c #DAC2A9",
+"v     c #BD9063",
+"w     c #CEA57C",
+"x     c #E5CFBB",
+"y     c #393633",
+"z     c #E0C8B1",
+"A     c #C9A480",
+"B     c #D1A87E",
+"C     c #D0A67B",
+"D     c #E1CAB4",
+"E     c #52504D",
+"F     c #D8C6B5",
+"G     c #CBA988",
+"H     c #CCAF93",
+"I     c #D2B496",
+"J     c #A67D51",
+"K     c #E2CFBD",
+"     ......             ",
+"    .+@#$%&*.           ",
+"    .=-;$>,')!          ",
+"     ...=~{]^/(         ",
+"        .=+#$_:.        ",
+"         .<[@}|.        ",
+"         .12@}3.        ",
+"      ....425}6....     ",
+"       .=2527}8}:.      ",
+"     ..9.=227}}:.       ",
+"   ..0abb.=2~}:..       ",
+" ..0abbbbc.=d:.ef..     ",
+".0abbbbghii.j.kkklf..   ",
+".mnabgopqqqi.iokkkkef.  ",
+".mmmnrooqiqqqiiiokkkks. ",
+".mmmmmnrooqiqqqiiiokkl. ",
+" ..mmmmmnrooqiqqiiituf. ",
+"   ..mmmmmnrvwiqqtxxy.  ",
+"     ..mmmmmzABCDxE..   ",
+"      ...mmmFGHIE..     ",
+"        ...mJK...       ",
+"          .....         ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/mail/move.pbm b/xemacs-packages/gnus/etc/images/mail/move.pbm
new file mode 100644 (file)
index 0000000..b765cc2
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/mail/move.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/mail/move.xpm b/xemacs-packages/gnus/etc/images/mail/move.xpm
new file mode 100644 (file)
index 0000000..ed478eb
--- /dev/null
@@ -0,0 +1,103 @@
+/* XPM */
+static char * stock_mail_move_xpm[] = {
+"24 24 76 1",
+"      c None",
+".     c #010101",
+"+     c #2F2F2F",
+"@     c #E3E2E1",
+"#     c #FCFCFC",
+"$     c #B3B2B1",
+"%     c #95938E",
+"&     c #F7F7F7",
+"*     c #F5F4F2",
+"=     c #F8F8F8",
+"-     c #F7F6F6",
+";     c #EAE9E5",
+">     c #7B7976",
+",     c #D2CFCA",
+"'     c #E1E0DD",
+")     c #908E8B",
+"!     c #EBEAEA",
+"~     c #F1F0EE",
+"{     c #E2E0DD",
+"]     c #7C7B78",
+"^     c #C6C3C0",
+"/     c #E5E3DE",
+"(     c #DCDAD7",
+"_     c #8F8C88",
+":     c #EBEBEA",
+"<     c #EFEDEA",
+"[     c #DFDDDA",
+"}     c #787774",
+"|     c #C1BEBA",
+"1     c #E6E3E0",
+"2     c #EFEEEC",
+"3     c #CBCAC6",
+"4     c #ECECEC",
+"5     c #F3F2F0",
+"6     c #DCDCDC",
+"7     c #7D7C79",
+"8     c #B4B2AE",
+"9     c #E7E5E1",
+"0     c #F0EFEB",
+"a     c #E4E2DD",
+"b     c #9D9994",
+"c     c #DBD9D6",
+"d     c #747370",
+"e     c #A09C97",
+"f     c #DAD8D5",
+"g     c #E7E6E3",
+"h     c #E8E6E1",
+"i     c #E0DED9",
+"j     c #AFACA6",
+"k     c #F7F6F4",
+"l     c #D3D1CF",
+"m     c #868480",
+"n     c #C2BFBD",
+"o     c #DAD9D5",
+"p     c #F6F5F1",
+"q     c #D8D6D1",
+"r     c #ABA8A3",
+"s     c #F9F8F6",
+"t     c #F7F5F2",
+"u     c #92908B",
+"v     c #CCCAC5",
+"w     c #EAE9E8",
+"x     c #B0ADA7",
+"y     c #F5F3F0",
+"z     c #F7F6F2",
+"A     c #F5F4F0",
+"B     c #EAE8E3",
+"C     c #D2D0CB",
+"D     c #B9B8B6",
+"E     c #CBC9C4",
+"F     c #DEDBD5",
+"G     c #D9D7D2",
+"H     c #DAD8D3",
+"I     c #D5D3CE",
+"J     c #D6D4CF",
+"K     c #040404",
+"                        ",
+"                        ",
+"                        ",
+"   . . . . . . .        ",
+"  .             .       ",
+"                        ",
+"  .             .       ",
+"                        ",
+"  .             .       ",
+"        .+...........   ",
+"  .    .@###########$.  ",
+"       .#%&*=*-*-*;>,.  ",
+"  .    .#')!~-*-*{]^/.  ",
+"       .#~(_:~<~[}|1/.  ",
+"   . . .#~23]4567890a.  ",
+"       .#22~b]cdefghi.  ",
+"       .#~2jklmnoep0q.  ",
+"       .#2rsskfkttuhv.  ",
+"       .wxsyzAtAtyBuC.  ",
+"       .DEFFFGHIJCCCu.  ",
+"        ............K   ",
+"                        ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/mail/not-spam.xpm b/xemacs-packages/gnus/etc/images/mail/not-spam.xpm
new file mode 100644 (file)
index 0000000..f8db326
--- /dev/null
@@ -0,0 +1,149 @@
+/* XPM */
+static char * stock_not_spam_xpm[] = {
+"24 24 122 2",
+"      c None",
+".     c #1D1E1E",
+"+     c #333839",
+"@     c #393F40",
+"#     c #171819",
+"$     c #B2B8B9",
+"%     c #D5E3E7",
+"&     c #AABABD",
+"*     c #64696A",
+"=     c #0C0D0D",
+"-     c #929C9E",
+";     c #E7F0F3",
+">     c #EDF0F1",
+",     c #E5EDEF",
+"'     c #C5D9DD",
+")     c #2E3132",
+"!     c #3F4343",
+"~     c #1F2121",
+"{     c #DFEBEE",
+"]     c #B7C4C8",
+"^     c #D2D9DA",
+"/     c #E1EFF2",
+"(     c #B6CBCF",
+"_     c #3C4547",
+":     c #1E2223",
+"<     c #191E1F",
+"[     c #2D2E2F",
+"}     c #191A1A",
+"|     c #252829",
+"1     c #7E8E92",
+"2     c #B7C2C3",
+"3     c #C3D9DD",
+"4     c #9CACB0",
+"5     c #C3CDCE",
+"6     c #C7E1E7",
+"7     c #668F97",
+"8     c #90ACB2",
+"9     c #CDDDE1",
+"0     c #485559",
+"a     c #88A6AC",
+"b     c #1F2223",
+"c     c #3F4545",
+"d     c #242728",
+"e     c #313B3E",
+"f     c #A8C2C8",
+"g     c #B2BDC0",
+"h     c #CFE5E9",
+"i     c #C2D9DE",
+"j     c #81989C",
+"k     c #A2C0C5",
+"l     c #85A9B1",
+"m     c #E5ECEE",
+"n     c #E7F2F4",
+"o     c #9BAEB3",
+"p     c #C8E1E7",
+"q     c #3A3E3F",
+"r     c #0C0E0E",
+"s     c #000000",
+"t     c #333737",
+"u     c #B3C2C5",
+"v     c #DDEDF0",
+"w     c #D8E4E6",
+"x     c #DAECEF",
+"y     c #D5E9ED",
+"z     c #D2E7EC",
+"A     c #95ADB2",
+"B     c #DBE2E2",
+"C     c #EDEFF0",
+"D     c #A2B1B3",
+"E     c #8FA4A8",
+"F     c #D7E2E5",
+"G     c #798F94",
+"H     c #151819",
+"I     c #F3B5A7",
+"J     c #865E55",
+"K     c #AFB9BB",
+"L     c #F1F8F9",
+"M     c #F7FBFB",
+"N     c #D9EBEF",
+"O     c #ECF4F6",
+"P     c #F3F7F7",
+"Q     c #E9F2F4",
+"R     c #EEF2F3",
+"S     c #E9EDEE",
+"T     c #C5C8C9",
+"U     c #C2C6C8",
+"V     c #E0E7E7",
+"W     c #DDEAED",
+"X     c #7A9DA5",
+"Y     c #EB8169",
+"Z     c #B83618",
+"`     c #924E3C",
+" .    c #9FA5A6",
+"..    c #E3EEF0",
+"+.    c #ECF5F7",
+"@.    c #D6EAED",
+"#.    c #CBE4E9",
+"$.    c #747C7D",
+"%.    c #B43518",
+"&.    c #E76A4D",
+"*.    c #B53F24",
+"=.    c #CB705A",
+"-.    c #C4D8DB",
+";.    c #D2E6E9",
+">.    c #CAE3E8",
+",.    c #A9C8CF",
+"'.    c #EC927D",
+").    c #E66F54",
+"!.    c #D26951",
+"~.    c #F1A897",
+"{.    c #E76547",
+"].    c #C58B7D",
+"^.    c #A8ABAC",
+"/.    c #70A1AB",
+"(.    c #DF421E",
+"_.    c #C43A1A",
+":.    c #E17055",
+"<.    c #DD8D7A",
+"[.    c #FFFFFF",
+"}.    c #030505",
+"|.    c #A2432E",
+"1.    c #AC3316",
+"                                                ",
+"                                                ",
+"              . + @                             ",
+"            # $ % & * .                         ",
+"            = - ; > , ' ) !                     ",
+"              ~ { ] ^ / ( _ : < [ }             ",
+"            | 1 2 3 4 5 6 7 8 9 0 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         ",
+"  s s I J K L M N O P Q R S T U V W X <         ",
+"s I Y Z `  ...+.@.#.$.s s s s s s s s s s s s   ",
+"s %.&.Y *.=.-.;.>.,.s '.).).).).).).).).).).!.s ",
+"s %.%.%.&.~.{.].^./.s ).(.(.(.(.(.(.(.(.(.(._.s ",
+"s %.%.%.%.%.&.~.:.<.s ).(.[.[.(.(.(.(.[.[.(._.s ",
+"  s s %.%.%.%.%.&.~.s ).(.[.[.[.(.(.[.[.[.(._.s ",
+"      s s %.%.%.%.%.s ).(.(.[.[.[.[.[.[.(.(._.s ",
+"          s s %.%.%.s ).(.(.(.[.[.[.[.(.(.(._.s ",
+"            }.s s |.s ).(.(.(.[.[.[.[.(.(.(._.s ",
+"                s s s ).(.(.[.[.[.[.[.[.(.(._.s ",
+"                    s ).(.[.[.[.(.(.[.[.[.(._.s ",
+"                    s ).(.[.[.(.(.(.(.[.[.(._.s ",
+"                    s ).(.(.(.(.(.(.(.(.(.(._.s ",
+"                    s !._._._._._._._._._._.1.s ",
+"                      s s s s s s s s s s s s   "};
diff --git a/xemacs-packages/gnus/etc/images/mail/outbox.xpm b/xemacs-packages/gnus/etc/images/mail/outbox.xpm
new file mode 100644 (file)
index 0000000..58b5212
--- /dev/null
@@ -0,0 +1,96 @@
+/* XPM */
+static char * stock_outbox_xpm[] = {
+"24 24 69 1",
+"      c None",
+".     c #000000",
+"+     c #E66040",
+"@     c #EE937E",
+"#     c #E55E3F",
+"$     c #E1431F",
+"%     c #EC8770",
+"&     c #F0A08E",
+"*     c #F3B7A9",
+"=     c #EF9985",
+"-     c #E76749",
+";     c #ED8C75",
+">     c #F5BEB1",
+",     c #F3B4A5",
+"'     c #F4B8AA",
+")     c #F1A593",
+"!     c #E55B3B",
+"~     c #E45534",
+"{     c #F4BDB0",
+"]     c #F4BAAC",
+"^     c #EF9C89",
+"/     c #E34E2B",
+"(     c #C0391A",
+"_     c #8A2912",
+":     c #3E3E3C",
+"<     c #D4D3D2",
+"[     c #DB411D",
+"}     c #F1A999",
+"|     c #D23E1C",
+"1     c #812611",
+"2     c #C7C7C5",
+"3     c #ACABA8",
+"4     c #6A6966",
+"5     c #E9775D",
+"6     c #CECDCC",
+"7     c #A93217",
+"8     c #9B9A97",
+"9     c #494846",
+"0     c #9A9996",
+"a     c #BBBBB9",
+"b     c #747370",
+"c     c #A5A4A1",
+"d     c #AAA9A6",
+"e     c #686765",
+"f     c #7D7C79",
+"g     c #686764",
+"h     c #9C9B98",
+"i     c #999895",
+"j     c #ABAAA7",
+"k     c #A9A8A5",
+"l     c #AF3417",
+"m     c #E55D3D",
+"n     c #C5C5C3",
+"o     c #8D8C89",
+"p     c #626260",
+"q     c #B2B1AE",
+"r     c #A7A6A3",
+"s     c #B4B4B2",
+"t     c #C3C3C1",
+"u     c #92918E",
+"v     c #D1D0CF",
+"w     c #373735",
+"x     c #CACAC8",
+"y     c #A8A7A4",
+"z     c #CCCCCA",
+"A     c #52514E",
+"B     c #C8C8C6",
+"C     c #B5B5B3",
+"D     c #7E7D7A",
+"                 .      ",
+"                 ..     ",
+"                 .+.    ",
+"              ....@#.   ",
+"             .$%&*=@-.  ",
+"            .;>,')@@@!. ",
+"           .~{]*^@@@@@-.",
+"         ...@>/((((((_. ",
+"       .:<.[}|((((((1.  ",
+"     ..234.5+(_...(1.   ",
+"   ..63444.@(7...._.    ",
+" ..6344448.@(.90a..     ",
+".634444bcd.#$.eff.a..   ",
+".gh34bijkk.lm.iffff0a.  ",
+".ggghniikdo..pddiffffq. ",
+".ggggghniikdkkkdddiffr. ",
+" ..ggggghniikdkkdddsta. ",
+"   ..ggggghnurdkksvvw.  ",
+"     ..gggggxrdyzvA..   ",
+"      ...gggB3qCA..     ",
+"        ...gDv...       ",
+"          .....         ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/mail/preview.xpm b/xemacs-packages/gnus/etc/images/mail/preview.xpm
new file mode 100644 (file)
index 0000000..563a267
--- /dev/null
@@ -0,0 +1,178 @@
+/* XPM */
+static char * mail_preview_xpm[] = {
+"24 24 151 2",
+"      c None",
+".     c #343434",
+"+     c #2D2D2D",
+"@     c #292929",
+"#     c #262626",
+"$     c #2E2E2E",
+"%     c #303030",
+"&     c #737373",
+"*     c #A1A1A1",
+"=     c #B4B4B4",
+"-     c #B2B2B2",
+";     c #9D9D9D",
+">     c #676767",
+",     c #202020",
+"'     c #1C1C1C",
+")     c #272727",
+"!     c #616161",
+"~     c #CACACA",
+"{     c #CFCFCF",
+"]     c #D0D0D0",
+"^     c #CECECE",
+"/     c #C9C9C9",
+"(     c #C1C1C1",
+"_     c #A7A7A7",
+":     c #4C4C4C",
+"<     c #131313",
+"[     c #222222",
+"}     c #757575",
+"|     c #D3D3D3",
+"1     c #DBDBDB",
+"2     c #E7E7E7",
+"3     c #EFEFEF",
+"4     c #F3F3F3",
+"5     c #F1F1F1",
+"6     c #E5E5E5",
+"7     c #D2D2D2",
+"8     c #BCBCBC",
+"9     c #5E5E5E",
+"0     c #101010",
+"a     c #212121",
+"b     c #5B5B5B",
+"c     c #CCCCCC",
+"d     c #D7D7D7",
+"e     c #F5F5F5",
+"f     c #FAFAFA",
+"g     c #FBFBFB",
+"h     c #F8F8F8",
+"i     c #F0F0F0",
+"j     c #E1E1E1",
+"k     c #C2C2C2",
+"l     c #434343",
+"m     c #0F0F0F",
+"n     c #1F1F1F",
+"o     c #B9B9B9",
+"p     c #D4D4D4",
+"q     c #F7F7F7",
+"r     c #F9F9F9",
+"s     c #F6F6F6",
+"t     c #EAEAEA",
+"u     c #E2E2E2",
+"v     c #ABABAB",
+"w     c #0E0E0E",
+"x     c #000000",
+"y     c #111111",
+"z     c #686868",
+"A     c #9C9C9C",
+"B     c #808080",
+"C     c #8E8E8E",
+"D     c #919191",
+"E     c #929292",
+"F     c #949494",
+"G     c #939393",
+"H     c #8B8B8B",
+"I     c #838383",
+"J     c #A3A3A3",
+"K     c #555555",
+"L     c #080808",
+"M     c #535353",
+"N     c #333333",
+"O     c #AFAFAF",
+"P     c #E6E6E6",
+"Q     c #FDFDFD",
+"R     c #FEFEFE",
+"S     c #FCFCFC",
+"T     c #A8A8A8",
+"U     c #8D8D8D",
+"V     c #050505",
+"W     c #EEEEEE",
+"X     c #A6A6A6",
+"Y     c #C8C8C8",
+"Z     c #FFFFFF",
+"`     c #B6B6B6",
+" .    c #F4F4F4",
+"..    c #F2F2F2",
+"+.    c #A9A9A9",
+"@.    c #040404",
+"#.    c #2A2A2A",
+"$.    c #AAAAAA",
+"%.    c #ECECEC",
+"&.    c #A5A5A5",
+"*.    c #C7C7C7",
+"=.    c #D8D8D8",
+"-.    c #CDCDCD",
+";.    c #858585",
+">.    c #010101",
+",.    c #606060",
+"'.    c #646464",
+").    c #C3C3C3",
+"!.    c #DADADA",
+"~.    c #494949",
+"{.    c #ADADAD",
+"].    c #0A0A0A",
+"^.    c #BABABA",
+"/.    c #DCDCDC",
+"(.    c #989898",
+"_.    c #E9E9E9",
+":.    c #EBEBEB",
+"<.    c #A4A4A4",
+"[.    c #B7B7B7",
+"}.    c #D1D1D1",
+"|.    c #414141",
+"1.    c #3D3D3D",
+"2.    c #969696",
+"3.    c #A0A0A0",
+"4.    c #BEBEBE",
+"5.    c #D9D9D9",
+"6.    c #C5C5C5",
+"7.    c #515151",
+"8.    c #C0C0C0",
+"9.    c #959595",
+"0.    c #DDDDDD",
+"a.    c #484848",
+"b.    c #030303",
+"c.    c #454545",
+"d.    c #060606",
+"e.    c #B5B5B5",
+"f.    c #C6C6C6",
+"g.    c #C4C4C4",
+"h.    c #A2A2A2",
+"i.    c #828282",
+"j.    c #1E1E1E",
+"k.    c #191919",
+"l.    c #7C7C7C",
+"m.    c #E4E4E4",
+"n.    c #9E9E9E",
+"o.    c #525252",
+"p.    c #B0B0B0",
+"q.    c #6C6C6C",
+"r.    c #565656",
+"s.    c #797979",
+"t.    c #3A3A3A",
+"                                                ",
+"                                                ",
+"                . + @ # # #                     ",
+"            $ % & * = - ; > , '                 ",
+"          ) ! = ~ { ] ^ / ( _ : <               ",
+"        [ } ~ | 1 2 3 4 5 6 7 8 9 0             ",
+"      a b c d 6 e f g f h e i j k l m           ",
+"      n o p 6 q r g g f r s i t u v w           ",
+"  x y z A B C D E F F G G D C H I J K L         ",
+"x M N O P e r g Q R R Q S f h e i T U V         ",
+"x W y ~ t 5 q q g r S r f q e i X Y _ V         ",
+"x Z y ` t 3 4 e s q q q s  ...+.~ ] J @.        ",
+"x Z #.$.v %.i .. .e e e 4 5 &.*.=.-.;.>.        ",
+"x Z ,.'.1 ; %.3 i 5 5 i i T ).=.!./ ~.x         ",
+"x Z {.].^./.(._.:.%.%.%.<.[.}.!.p &.>.          ",
+"x Z /.|.1.7 +.2.6 6 6 3.$.4.=.5.).% x           ",
+"x Z e 6.L 7.8.( 9.0.(.= Y J ).( a.b.x           ",
+"x Z g d c.d.. 3.( F e.8.~ f.U + b.].x x         ",
+"x Z e & ^.g.1.b.a.I h.&.i.l x j.[.k.x x x       ",
+"x Z l.p m.m.Y n.o.j.b.b.j.o.n.p.q.O j.n x x     ",
+"x & 8 8 8 8 8 8 &.&.&.&.&.&.&.8 8 r.x > N x x   ",
+"  x x x x x x x x x x x x x x x x x x x s.t.x x ",
+"                                        x z n x ",
+"                                          x x   "};
diff --git a/xemacs-packages/gnus/etc/images/mail/reply-all.xpm b/xemacs-packages/gnus/etc/images/mail/reply-all.xpm
new file mode 100644 (file)
index 0000000..dfd560d
--- /dev/null
@@ -0,0 +1,176 @@
+/* XPM */
+static char * stock_mail_reply_to_all_xpm[] = {
+"24 24 149 2",
+"      c None",
+".     c #000000",
+"+     c #ADA99C",
+"@     c #E6E1D0",
+"#     c #F0EAD9",
+"$     c #A9A598",
+"%     c #141416",
+"&     c #161618",
+"*     c #080809",
+"=     c #DBD6C7",
+"-     c #1B1B1C",
+";     c #050505",
+">     c #5A5A5A",
+",     c #676767",
+"'     c #020202",
+")     c #807D76",
+"!     c #D49A3E",
+"~     c #D2973B",
+"{     c #040402",
+"]     c #6D6B6B",
+"^     c #7A7979",
+"/     c #030100",
+"(     c #040100",
+"_     c #282724",
+":     c #DD9831",
+"<     c #DA962F",
+"[     c #1A0E01",
+"}     c #BC6D1B",
+"|     c #BE6E13",
+"1     c #BE6D13",
+"2     c #BD6C13",
+"3     c #3E3C36",
+"4     c #D69029",
+"5     c #D18D27",
+"6     c #737067",
+"7     c #110900",
+"8     c #CF791C",
+"9     c #CE791C",
+"0     c #CD761A",
+"a     c #C47013",
+"b     c #4A4136",
+"c     c #A0731E",
+"d     c #96691A",
+"e     c #000100",
+"f     c #291703",
+"g     c #BA6613",
+"h     c #8C4E0D",
+"i     c #844A0D",
+"j     c #BF6D13",
+"k     c #1F2A0D",
+"l     c #306220",
+"m     c #4F7242",
+"n     c #448D44",
+"o     c #2E802E",
+"p     c #3A6F3A",
+"q     c #FFFFFF",
+"r     c #535353",
+"s     c #171009",
+"t     c #AC600C",
+"u     c #713F0A",
+"v     c #693A0A",
+"w     c #AA5F0A",
+"x     c #192B10",
+"y     c #275926",
+"z     c #68A769",
+"A     c #358A36",
+"B     c #2D812D",
+"C     c #FBFBFB",
+"D     c #F7F7F7",
+"E     c #FAFAFA",
+"F     c #F5F5F5",
+"G     c #4F4F4F",
+"H     c #AEAEAE",
+"I     c #141517",
+"J     c #6F767C",
+"K     c #534C46",
+"L     c #241609",
+"M     c #23180E",
+"N     c #484644",
+"O     c #354A4D",
+"P     c #050B07",
+"Q     c #4F7E4F",
+"R     c #399239",
+"S     c #2D852D",
+"T     c #297F29",
+"U     c #ACACAC",
+"V     c #C8C8C8",
+"W     c #151618",
+"X     c #6C7C8B",
+"Y     c #728EA9",
+"Z     c #5D6B78",
+"`     c #C8CBCD",
+" .    c #C3C7CD",
+"..    c #8090A2",
+"+.    c #5A728B",
+"@.    c #4E6479",
+"#.    c #111714",
+"$.    c #328732",
+"%.    c #2B7F2C",
+"&.    c #2B772C",
+"*.    c #434343",
+"=.    c #A0A0A0",
+"-.    c #D4D4D4",
+";.    c #25282A",
+">.    c #8A9EB4",
+",.    c #6A86A1",
+"'.    c #596A7C",
+").    c #DDE1E4",
+"!.    c #DCE2E7",
+"~.    c #899CAC",
+"{.    c #687E96",
+"].    c #546D87",
+"^.    c #10161D",
+"/.    c #8C8C8C",
+"(.    c #959595",
+"_.    c #E4E4E4",
+":.    c #23282D",
+"<.    c #8096AB",
+"[.    c #5D7996",
+"}.    c #53687D",
+"|.    c #CDD3D9",
+"1.    c #CBD2DC",
+"2.    c #899BAB",
+"3.    c #CCD4DC",
+"4.    c #5C748C",
+"5.    c #111820",
+"6.    c #4D4D4D",
+"7.    c #818181",
+"8.    c #C6C6C6",
+"9.    c #1F252B",
+"0.    c #6B8197",
+"a.    c #536D89",
+"b.    c #4A5D6F",
+"c.    c #81919F",
+"d.    c #8293A4",
+"e.    c #5A7087",
+"f.    c #496481",
+"g.    c #445D79",
+"h.    c #0E151B",
+"i.    c #6A6A6A",
+"j.    c #0E141A",
+"k.    c #0D1319",
+"l.    c #0E141B",
+"m.    c #0E131A",
+"n.    c #0F141A",
+"o.    c #636363",
+"p.    c #737373",
+"q.    c #7C7C7C",
+"r.    c #BCBCBC",
+"                                                ",
+"                  . .                           ",
+"                + @ # $ .                       ",
+"          % & * = # # # .                       ",
+"      - ; > , ' ) ! ~ # .                       ",
+"      { ] ^ / ( _ : < # .                       ",
+"      [ } | 1 2 3 4 5 # 6                       ",
+"      7 8 9 0 a b c d # # . e . . . . . .       ",
+"      f g h i j k l m n o p . q q q q q r .     ",
+"      s t u v w x y z A o B . C D E F G H .     ",
+"    I J K L M N O P Q R S T . F F F G U V .     ",
+"  W X Y Z `  ...+.@.#.$.%.&.. F F *.=.-.V .     ",
+"  ;.>.,.'.).!.~.{.].^.. . . /.F G (.-._.V .     ",
+"  :.<.[.}.|.1.2.3.4.5.F F F F 6.7.8._._.V .     ",
+"  9.0.a.b.c.d.e.f.g.h.F F F G i.=._.F _.V .     ",
+"    j.k.l.l.l.j.m.n.o.G F G (.8.p.8.F _.V .     ",
+"      . q C F o.8.F _.-.G U 8._.F q._._.V .     ",
+"      . q F p.-.F F F F _._.F F F F q._.V .     ",
+"      . q q.-._._._._._._._._._._._._.q.V .     ",
+"      . p.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.o..     ",
+"        . . . . . . . . . . . . . . . . . .     ",
+"                                                ",
+"                                                ",
+"                                                "};
diff --git a/xemacs-packages/gnus/etc/images/mail/reply.xpm b/xemacs-packages/gnus/etc/images/mail/reply.xpm
new file mode 100644 (file)
index 0000000..4925041
--- /dev/null
@@ -0,0 +1,94 @@
+/* XPM */
+static char * stock_mail_reply_xpm[] = {
+"24 24 67 1",
+"      c None",
+".     c #000000",
+"+     c #535353",
+"@     c #FFFFFF",
+"#     c #FEFEFE",
+"$     c #FDFDFD",
+"%     c #FCFCFC",
+"&     c #FBFBFB",
+"*     c #F9F9F9",
+"=     c #F8F8F8",
+"-     c #F7F7F7",
+";     c #F6F6F6",
+">     c #F5F5F5",
+",     c #F4F4F4",
+"'     c #E3E3E3",
+")     c #EEEEEE",
+"!     c #4F4F4F",
+"~     c #F3F3F3",
+"{     c #F2F2F2",
+"]     c #F1F1F1",
+"^     c #F0F0F0",
+"/     c #EFEFEF",
+"(     c #EDEDED",
+"_     c #AEAEAE",
+":     c #E4E4E4",
+"<     c #434343",
+"[     c #ACACAC",
+"}     c #C8C8C8",
+"|     c #A0A0A0",
+"1     c #D4D4D4",
+"2     c #ECECEC",
+"3     c #959595",
+"4     c #3E3E3E",
+"5     c #4D4D4D",
+"6     c #818181",
+"7     c #C6C6C6",
+"8     c #3D1A13",
+"9     c #6A6A6A",
+"0     c #636363",
+"a     c #B9B9B9",
+"b     c #737373",
+"c     c #EAC0BA",
+"d     c #7C7C7C",
+"e     c #DF9E95",
+"f     c #E0A198",
+"g     c #E1A59D",
+"h     c #E2A79E",
+"i     c #E3ABA3",
+"j     c #E3AAA2",
+"k     c #CC6253",
+"l     c #DD978D",
+"m     c #DF9F97",
+"n     c #DE9A90",
+"o     c #DD968C",
+"p     c #DD948A",
+"q     c #B14334",
+"r     c #BCBCBC",
+"s     c #431913",
+"t     c #EAC2BC",
+"u     c #DF9C92",
+"v     c #DD998F",
+"w     c #B54535",
+"x     c #65261D",
+"y     c #983A2C",
+"z     c #7C2F24",
+"A     c #63251D",
+"B     c #6C291F",
+"                        ",
+"                        ",
+"                        ",
+"    .................   ",
+"   .+@@@@#$%&*=-;>,'+.  ",
+"   .)!@>,~{{]^^/)('!_.  ",
+"   .@:<$~{{]^/))('![}.  ",
+"   .@>:!&]^^/)(('<|1}.  ",
+"   .@&>:<=^/)(2'!31:}.  ",
+"   .@>>>:4>)(2'567::}.  ",
+"   .@&8>:9<~2'!977>:}.  ",
+"   .@..:0@a!^!37b7>:}.  ",
+"   ..c.0@>:1![7::d::}.  ",
+"   .ce.......:>>>:d:}.  ",
+"  .cfghihjek.::::::d}.  ",
+" .clmenoonpq.rrrrrrr0.  ",
+"stnuvvlnnnnw..........  ",
+" .xyyyyyyyyz.           ",
+"  .xyyAAAAAB.           ",
+"   .xy.......           ",
+"    .x.                 ",
+"     ..                 ",
+"      .                 ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/mail/save-draft.xpm b/xemacs-packages/gnus/etc/images/mail/save-draft.xpm
new file mode 100644 (file)
index 0000000..9b37491
--- /dev/null
@@ -0,0 +1,99 @@
+/* XPM */
+static char * stock_mail_handling_xpm[] = {
+"24 24 72 1",
+"      c None",
+".     c #000000",
+"+     c #BCBCBC",
+"@     c #FFFFFF",
+"#     c #535353",
+"$     c #EEEEEE",
+"%     c #4F4F4F",
+"&     c #F5F5F5",
+"*     c #FBFBFB",
+"=     c #F7F7F7",
+"-     c #FAFAFA",
+";     c #AEAEAE",
+">     c #E4E4E4",
+",     c #434343",
+"'     c #ACACAC",
+")     c #C8C8C8",
+"!     c #A0A0A0",
+"~     c #D4D4D4",
+"{     c #959595",
+"]     c #3E3E3E",
+"^     c #4D4D4D",
+"/     c #818181",
+"(     c #C6C6C6",
+"_     c #6A6A6A",
+":     c #636363",
+"<     c #B9B9B9",
+"[     c #737373",
+"}     c #010101",
+"|     c #AAAAAA",
+"1     c #0B0B0B",
+"2     c #0C0C0C",
+"3     c #060606",
+"4     c #E4E3E1",
+"5     c #050505",
+"6     c #B3B3B1",
+"7     c #484641",
+"8     c #9F9D96",
+"9     c #888781",
+"0     c #7C7C7C",
+"a     c #B0AFAD",
+"b     c #A8A7A1",
+"c     c #908E86",
+"d     c #97958E",
+"e     c #807D74",
+"f     c #969696",
+"g     c #090909",
+"h     c #595854",
+"i     c #605E57",
+"j     c #898883",
+"k     c #76746B",
+"l     c #43423F",
+"m     c #282724",
+"n     c #363430",
+"o     c #6D6B63",
+"p     c #E2E2E1",
+"q     c #B6B5AF",
+"r     c #21201E",
+"s     c #0A0908",
+"t     c #181816",
+"u     c #E6E6E4",
+"v     c #65635C",
+"w     c #161614",
+"x     c #8C8B89",
+"y     c #DFDEDC",
+"z     c #B0AFA9",
+"A     c #D5D4D1",
+"B     c #93918B",
+"C     c #D6D5D2",
+"D     c #ABA9A3",
+"E     c #5D5C55",
+"F     c #494943",
+"G     c #42413C",
+"                        ",
+"  .................     ",
+" .+@@@@@@@@@@@@@@@#.    ",
+" .$%&*&*=*&*&*=-&%;.    ",
+" .@>,&&&&&&&&&&&%').    ",
+" .@&>%&&&&&&&&&,!~).    ",
+" .@*&>,&&&&&&&%{~>).    ",
+" .@&&&>]&&&&&^/(>>).    ",
+" .@*&&&_,&&&%_!>&>).    ",
+" .@&&&:<<%&%{([(}}}.    ",
+" .@*&:(&>~%'|12:345...  ",
+" .@&[~&&&&>>2>62787.9.. ",
+" .@0~>>>>>>>1ab888cde7. ",
+" .[+++++++++fg88hijek.  ",
+"  ...........78ilmn8o7..",
+"           .pq8hrstuevi.",
+"           ..78jnwxyv7..",
+"             .zequABv.  ",
+"            .CD8eekkE7. ",
+"            ..h.7k7.F.. ",
+"             .. .G. ..  ",
+"                ...     ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/mail/save.xpm b/xemacs-packages/gnus/etc/images/mail/save.xpm
new file mode 100644 (file)
index 0000000..0001716
--- /dev/null
@@ -0,0 +1,291 @@
+/* XPM */
+static char * mail_save_xpm[] = {
+"24 24 264 2",
+"      c None",
+".     c #000000",
+"+     c #141414",
+"@     c #262626",
+"#     c #212121",
+"$     c #1F1F1F",
+"%     c #1E1E1E",
+"&     c #1D1D1D",
+"*     c #202020",
+"=     c #232323",
+"-     c #292929",
+";     c #171717",
+">     c #121212",
+",     c #B8B8B8",
+"'     c #FFFFFF",
+")     c #A8A8A8",
+"!     c #0E0E0E",
+"~     c #595959",
+"{     c #444444",
+"]     c #4F4F4F",
+"^     c #050505",
+"/     c #222222",
+"(     c #3D3D3D",
+"_     c #FEFEFE",
+":     c #FCFCFC",
+"<     c #FDFDFD",
+"[     c #CACACA",
+"}     c #191919",
+"|     c #B3B1B0",
+"1     c #EEECEB",
+"2     c #F0DCAA",
+"3     c #E5C470",
+"4     c #DFB84F",
+"5     c #8A681F",
+"6     c #100E09",
+"7     c #FBFBFB",
+"8     c #515151",
+"9     c #F0F0F0",
+"0     c #D6D6D6",
+"a     c #EEECE9",
+"b     c #E6D498",
+"c     c #EED682",
+"d     c #EED680",
+"e     c #E3C15E",
+"f     c #D29815",
+"g     c #976E15",
+"h     c #7F5B0A",
+"i     c #1C190F",
+"j     c #D9D9D9",
+"k     c #424242",
+"l     c #F1F1F1",
+"m     c #F3F3F3",
+"n     c #EBE9E5",
+"o     c #CBB771",
+"p     c #735817",
+"q     c #C6A546",
+"r     c #E3C05D",
+"s     c #BC8710",
+"t     c #AD7C10",
+"u     c #6B6B6B",
+"v     c #A0A0A0",
+"w     c #535353",
+"x     c #505050",
+"y     c #AE9C5C",
+"z     c #292928",
+"A     c #CECDCA",
+"B     c #CAC9C7",
+"C     c #1A1917",
+"D     c #9C7E2B",
+"E     c #AB7C12",
+"F     c #242012",
+"G     c #555555",
+"H     c #DEDEDE",
+"I     c #E8E8E8",
+"J     c #3B3B3B",
+"K     c #D7D6D6",
+"L     c #656462",
+"M     c #DAD9D7",
+"N     c #E1E0DF",
+"O     c #1A1A19",
+"P     c #3D351F",
+"Q     c #A37819",
+"R     c #231F13",
+"S     c #282828",
+"T     c #898989",
+"U     c #EFEFEF",
+"V     c #FAFAFA",
+"W     c #E8E7E6",
+"X     c #8B8B8A",
+"Y     c #0B0B06",
+"Z     c #A97C1A",
+"`     c #1B1B1B",
+" .    c #C9C9C9",
+"..    c #DFDFDF",
+"+.    c #EBEBEB",
+"@.    c #ECECEC",
+"#.    c #E1E1E1",
+"$.    c #221E11",
+"%.    c #EAE8E3",
+"&.    c #C58F13",
+"*.    c #B68411",
+"=.    c #826321",
+"-.    c #302C19",
+";.    c #131313",
+">.    c #1A1A1A",
+",.    c #161616",
+"'.    c #151515",
+").    c #181818",
+"!.    c #1B1B1A",
+"~.    c #141413",
+"{.    c #363220",
+"].    c #916F25",
+"^.    c #322F1E",
+"/.    c #98B4C8",
+"(.    c #25313B",
+"_.    c #A9CCE0",
+":.    c #545A68",
+"<.    c #BC6A60",
+"[.    c #AD5A51",
+"}.    c #A4574D",
+"|.    c #2B2719",
+"1.    c #353120",
+"2.    c #5A4D51",
+"3.    c #6E8DA2",
+"4.    c #0C1820",
+"5.    c #BAE5FF",
+"6.    c #696E6F",
+"7.    c #F9F9F9",
+"8.    c #EBEBEA",
+"9.    c #937025",
+"0.    c #CDCAC1",
+"a.    c #73726E",
+"b.    c #7496AF",
+"c.    c #0A131A",
+"d.    c #BAE0FD",
+"e.    c #6A6E71",
+"f.    c #ECEDEC",
+"g.    c #DEDFDF",
+"h.    c #DBDDDD",
+"i.    c #D8DBDB",
+"j.    c #CDCFCF",
+"k.    c #312E1B",
+"l.    c #2F2C19",
+"m.    c #B2B3B0",
+"n.    c #C0C0BE",
+"o.    c #6F6D6B",
+"p.    c #7C9FBB",
+"q.    c #050F15",
+"r.    c #B7DDFC",
+"s.    c #54575A",
+"t.    c #F4F4F3",
+"u.    c #ECECEB",
+"v.    c #F3F3F2",
+"w.    c #7F7D7A",
+"x.    c #7EA0BB",
+"y.    c #020A10",
+"z.    c #B1D7F7",
+"A.    c #FDFCFB",
+"B.    c #EFEFEE",
+"C.    c #EDEDEC",
+"D.    c #EBECEB",
+"E.    c #EBECEC",
+"F.    c #F7F7F6",
+"G.    c #7D7977",
+"H.    c #7F9FB9",
+"I.    c #050B0E",
+"J.    c #B3DDF7",
+"K.    c #685050",
+"L.    c #847F7C",
+"M.    c #7E9DB7",
+"N.    c #0A0B0C",
+"O.    c #A9D3F0",
+"P.    c #7B99AB",
+"Q.    c #6B6E70",
+"R.    c #63696C",
+"S.    c #60666B",
+"T.    c #5E6569",
+"U.    c #555E67",
+"V.    c #5D6267",
+"W.    c #61676B",
+"X.    c #64696D",
+"Y.    c #62666A",
+"Z.    c #6B747E",
+"`.    c #7D9CB4",
+" +    c #000508",
+".+    c #A8CBED",
+"++    c #7498B7",
+"@+    c #6F92B0",
+"#+    c #3F5160",
+"$+    c #4A5E70",
+"%+    c #566E82",
+"&+    c #4D6779",
+"*+    c #52697C",
+"=+    c #52697A",
+"-+    c #54687A",
+";+    c #455E70",
+">+    c #7697B4",
+",+    c #92A9BC",
+"'+    c #000205",
+")+    c #A8CEEB",
+"!+    c #7196B3",
+"~+    c #4D5152",
+"{+    c #D7D2CB",
+"]+    c #F1EEEA",
+"^+    c #FAF8F5",
+"/+    c #F9F8F5",
+"(+    c #E8E4DF",
+"_+    c #D8D4CD",
+":+    c #9D968B",
+"<+    c #425563",
+"[+    c #446783",
+"}+    c #A7C4DA",
+"|+    c #000101",
+"1+    c #A5CDEA",
+"2+    c #7196B1",
+"3+    c #57595C",
+"4+    c #534F46",
+"5+    c #2E281F",
+"6+    c #CAC7C2",
+"7+    c #C9C4BD",
+"8+    c #C2BBB1",
+"9+    c #E3E0DC",
+"0+    c #314353",
+"a+    c #40647C",
+"b+    c #B6C9DA",
+"c+    c #A3CDEB",
+"d+    c #7695B1",
+"e+    c #525455",
+"f+    c #474239",
+"g+    c #3B372D",
+"h+    c #C0BCB5",
+"i+    c #C7C2BA",
+"j+    c #E2DFD9",
+"k+    c #F8F6F3",
+"l+    c #344652",
+"m+    c #406479",
+"n+    c #A6C3DA",
+"o+    c #010000",
+"p+    c #708798",
+"q+    c #6A8DA7",
+"r+    c #4F5052",
+"s+    c #F7F2EC",
+"t+    c #59534B",
+"u+    c #57524A",
+"v+    c #C1BCB4",
+"w+    c #EBE9E4",
+"x+    c #FFFFFD",
+"y+    c #30414E",
+"z+    c #415C6F",
+"A+    c #A2C4DC",
+"B+    c #020000",
+"C+    c #030406",
+"D+    c #141A1F",
+"E+    c #151718",
+"F+    c #35332F",
+"G+    c #393634",
+"H+    c #41403E",
+"I+    c #3F3E3D",
+"J+    c #454344",
+"K+    c #434241",
+"L+    c #312F2C",
+"M+    c #02070A",
+"N+    c #070E12",
+"O+    c #465A69",
+". + @ # $ % & & & % * = - ; .                   ",
+"> , ' ' ' ' ' ' ' ' ' ' ' ) !                   ",
+"@ ' ~ ' ' ' ' ' ' ' ' ' { ] ^ . . .             ",
+"/ ' ' ( ' _ : < < ' [ } | 1 2 3 4 5 . 6         ",
+"* ' ' 7 8 9 < 7 _ 0 @ a b c d d e f g h i       ",
+"$ ' ' ' j k l : m $ n o . . . p q r s t i       ",
+"* ' ' ' u v w ' x . y z A B C   D d f E F       ",
+"/ ' ' G H 7 I J , K > L M N O   P d f Q R       ",
+"S ' T U ' ' ' _ V ' < W X Y . . . d f Z . . .   ",
+"`  ...U +.+.+.@.@.+.@.+.#.$.%.d d d f &.*.=.-.. ",
+". ;.>.; ,.'.'.'.'.'.,.).!.~.{.%.d d f f ].^./.(.",
+"                  . _.:.<.[.}.|.%.d f ].1.2.3.4.",
+"                  . 5.6.' ' 7.8.-.%.9.^.0.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.6.A.B.C.D.+.E.C.U F.G.H.I.",
+"                  . J.K.' ' ' ' ' ' ' ' ' L.M.N.",
+"                  . O.P.Q.R.S.T.U.V.W.X.Y.Z.`. +",
+"                  . .+++@+#+$+%+&+*+=+-+;+>+,+'+",
+"                  . )+!+~+{+]+^+/+(+_+:+<+[+}+|+",
+"                  . 1+2+3+' 4+5+6+7+8+9+0+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+. "};
diff --git a/xemacs-packages/gnus/etc/images/mail/send.xpm b/xemacs-packages/gnus/etc/images/mail/send.xpm
new file mode 100644 (file)
index 0000000..44ee493
--- /dev/null
@@ -0,0 +1,85 @@
+/* XPM */
+static char * stock_mail_send_xpm[] = {
+"24 24 58 1",
+"      c None",
+".     c #4F3F0A",
+"+     c #000000",
+"@     c #F4E6B5",
+"#     c #F4E5B3",
+"$     c #EDD684",
+"%     c #755F10",
+"&     c #EDD580",
+"*     c #EED685",
+"=     c #AF8D18",
+"-     c #EFD98C",
+";     c #EED88B",
+">     c #EDD582",
+",     c #EED889",
+"'     c #EFDA92",
+")     c #F0DB93",
+"!     c #735D10",
+"~     c #535353",
+"{     c #FFFFFF",
+"]     c #F0DC97",
+"^     c #F6F6F6",
+"/     c #F5F5F5",
+"(     c #F4F4F4",
+"_     c #E3E3E3",
+":     c #EEEEEE",
+"<     c #4F4F4F",
+"[     c #EDD37C",
+"}     c #EDEDED",
+"|     c #AEAEAE",
+"1     c #E4E4E4",
+"2     c #434343",
+"3     c #FDFDFD",
+"4     c #F3F3F3",
+"5     c #E4BF3D",
+"6     c #CBA41C",
+"7     c #D1A81C",
+"8     c #907413",
+"9     c #7C6411",
+"0     c #ACACAC",
+"a     c #C8C8C8",
+"b     c #FBFBFB",
+"c     c #A0A0A0",
+"d     c #D4D4D4",
+"e     c #F8F8F8",
+"f     c #F0F0F0",
+"g     c #EFEFEF",
+"h     c #ECECEC",
+"i     c #959595",
+"j     c #3E3E3E",
+"k     c #4D4D4D",
+"l     c #818181",
+"m     c #C6C6C6",
+"n     c #6A6A6A",
+"o     c #636363",
+"p     c #B9B9B9",
+"q     c #737373",
+"r     c #7C7C7C",
+"s     c #BCBCBC",
+"                        ",
+"           .            ",
+"          +@+           ",
+"         +#$%+          ",
+"        +#&*=%+         ",
+"       +#-;>==%+        ",
+"      +#,',>===%+       ",
+"   ++++++)$&=!++++++    ",
+"  +~{{{{+]$$=!+^/(_~+   ",
+"  +:<{/(+,[$=!+:}_<|+   ",
+"  +{1234+56789+}_<0a+   ",
+"  +{/1<b+++++++_2cda+   ",
+"  +{b/12efg:}h_<id1a+   ",
+"  +{///1j/:}h_klm11a+   ",
+"  +{b//1n24h_<nmm/1a+   ",
+"  +{//1o{p<f<imqm/1a+   ",
+"  +{b1o{/1d<0m11r11a+   ",
+"  +{1q{////11///1r1a+   ",
+"  +{r{111111111111ra+   ",
+"  +qssssssssssssssso+   ",
+"   ++++++++++++++++++   ",
+"                        ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/mail/spam.xpm b/xemacs-packages/gnus/etc/images/mail/spam.xpm
new file mode 100644 (file)
index 0000000..aee8383
--- /dev/null
@@ -0,0 +1,217 @@
+/* XPM */
+static char * stock_spam_xpm[] = {
+"24 24 190 2",
+"      c None",
+".     c #1D1E1E",
+"+     c #333839",
+"@     c #393F40",
+"#     c #171819",
+"$     c #B2B8B9",
+"%     c #D5E3E7",
+"&     c #AABABD",
+"*     c #64696A",
+"=     c #0C0D0D",
+"-     c #929C9E",
+";     c #E7F0F3",
+">     c #EDF0F1",
+",     c #E5EDEF",
+"'     c #C5D9DD",
+")     c #2E3132",
+"!     c #3F4343",
+"~     c #1F2121",
+"{     c #DFEBEE",
+"]     c #B7C4C8",
+"^     c #D2D9DA",
+"/     c #E1EFF2",
+"(     c #B6CBCF",
+"_     c #3C4547",
+":     c #1E2223",
+"<     c #191E1F",
+"[     c #2D2E2F",
+"}     c #191A1A",
+"|     c #252829",
+"1     c #7E8E92",
+"2     c #B7C2C3",
+"3     c #C3D9DD",
+"4     c #9CACB0",
+"5     c #C3CDCE",
+"6     c #C7E1E7",
+"7     c #668F97",
+"8     c #90ACB2",
+"9     c #CDDDE1",
+"0     c #485559",
+"a     c #88A6AC",
+"b     c #1F2223",
+"c     c #3F4545",
+"d     c #242728",
+"e     c #313B3E",
+"f     c #A8C2C8",
+"g     c #B2BDC0",
+"h     c #CFE5E9",
+"i     c #C2D9DE",
+"j     c #81989C",
+"k     c #A2C0C5",
+"l     c #85A9B1",
+"m     c #E5ECEE",
+"n     c #E7F2F4",
+"o     c #9BAEB3",
+"p     c #C8E1E7",
+"q     c #3A3E3F",
+"r     c #0C0E0E",
+"s     c #000000",
+"t     c #333737",
+"u     c #B3C2C5",
+"v     c #DDEDF0",
+"w     c #D8E4E6",
+"x     c #DAECEF",
+"y     c #D5E9ED",
+"z     c #D2E7EC",
+"A     c #95ADB2",
+"B     c #DBE2E2",
+"C     c #EDEFF0",
+"D     c #A2B1B3",
+"E     c #8FA4A8",
+"F     c #D7E2E5",
+"G     c #798F94",
+"H     c #151819",
+"I     c #F3B5A7",
+"J     c #865E55",
+"K     c #AFB9BB",
+"L     c #F1F8F9",
+"M     c #F7FBFB",
+"N     c #D9EBEF",
+"O     c #ECF4F6",
+"P     c #F3F7F7",
+"Q     c #E9F2F4",
+"R     c #EEF2F3",
+"S     c #E9EDEE",
+"T     c #C5C8C9",
+"U     c #C2C6C8",
+"V     c #E0E7E7",
+"W     c #DDEAED",
+"X     c #7A9DA5",
+"Y     c #EB8169",
+"Z     c #B83618",
+"`     c #924E3C",
+" .    c #9FA5A6",
+"..    c #E3EEF0",
+"+.    c #ECF5F7",
+"@.    c #D6EAED",
+"#.    c #CBE4E9",
+"$.    c #D9E7E9",
+"%.    c #E1EBED",
+"&.    c #B8CBD0",
+"*.    c #BDCBCF",
+"=.    c #ABB3B5",
+"-.    c #E3E5E5",
+";.    c #DCEBEF",
+">.    c #6A979F",
+",.    c #131819",
+"'.    c #B43518",
+").    c #E76A4D",
+"!.    c #B53F24",
+"~.    c #CB705A",
+"{.    c #C4D8DB",
+"].    c #D2E6E9",
+"^.    c #CAE3E8",
+"/.    c #A9C8CF",
+"(.    c #7FA4AA",
+"_.    c #82B4BE",
+":.    c #E2EFF0",
+"<.    c #D3E7EA",
+"[.    c #AFD5DE",
+"}.    c #C7E2E7",
+"|.    c #E7F1F2",
+"1.    c #97C3CB",
+"2.    c #637F86",
+"3.    c #191311",
+"4.    c #EF9985",
+"5.    c #F1A897",
+"6.    c #E76547",
+"7.    c #C58B7D",
+"8.    c #A8ABAC",
+"9.    c #70A1AB",
+"0.    c #88B5BE",
+"a.    c #95C7D1",
+"b.    c #ADD4DC",
+"c.    c #DCEAEF",
+"d.    c #B5D8E0",
+"e.    c #CAE4E9",
+"f.    c #95BEC6",
+"g.    c #6696A0",
+"h.    c #585857",
+"i.    c #51190C",
+"j.    c #D9401D",
+"k.    c #EC8A74",
+"l.    c #E17055",
+"m.    c #DD8D7A",
+"n.    c #D8E7EA",
+"o.    c #D8E9ED",
+"p.    c #D6EAEE",
+"q.    c #D9EBEE",
+"r.    c #E4F0F3",
+"s.    c #CFE3E8",
+"t.    c #5B94A0",
+"u.    c #5C7E85",
+"v.    c #3D221D",
+"w.    c #782310",
+"x.    c #EA7A60",
+"y.    c #E5A293",
+"z.    c #EBD9D5",
+"A.    c #C6D3D6",
+"B.    c #799FA8",
+"C.    c #558C98",
+"D.    c #45686E",
+"E.    c #27201F",
+"F.    c #5D3228",
+"G.    c #B86F5D",
+"H.    c #F1A593",
+"I.    c #E58D78",
+"J.    c #C0C0C1",
+"K.    c #32464B",
+"L.    c #4A6E75",
+"M.    c #282121",
+"N.    c #4A2E27",
+"O.    c #C6968B",
+"P.    c #DDA89B",
+"Q.    c #5F1C0D",
+"R.    c #F2AFA0",
+"S.    c #A36F63",
+"T.    c #341C17",
+"U.    c #301A15",
+"V.    c #674C45",
+"W.    c #E4AEA1",
+"X.    c #8D2A13",
+"Y.    c #030505",
+"Z.    c #A2432E",
+"`.    c #E4A799",
+" +    c #D97C67",
+".+    c #B66A59",
+"++    c #B26C5C",
+"@+    c #882812",
+"#+    c #DB411D",
+"$+    c #F4BAAC",
+"                                                ",
+"                                                ",
+"                                                ",
+"                                                ",
+"              . + @                             ",
+"            # $ % & * .                         ",
+"            = - ; > , ' ) !                     ",
+"              ~ { ] ^ / ( _ : < [ }             ",
+"            | 1 2 3 4 5 6 7 8 9 0 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         ",
+"  s s I J K L M N O P Q R S T U V W X <         ",
+"s I Y Z `  ...+.@.#.$.%.h &.*.=.-.;.>.,.s       ",
+"s '.).Y !.~.{.].^./.(._.:.<.[.}.|.1.2.3.4.s     ",
+"s '.'.'.).5.6.7.8.9.0.a.b.c.d.e.f.g.h.i.j.k.s   ",
+"s '.'.'.'.'.).5.l.m.n.o.p.q.r.s.t.u.v.w.j.x.s   ",
+"  s s '.'.'.'.'.).5.6.y.z.A.B.C.D.E.F.G.H.4.s   ",
+"      s s '.'.'.'.'.).5.I.J.K.L.M.N.O.P.Q.s     ",
+"          s s '.'.'.'.'.R.S.T.U.V.W.X.s s       ",
+"            Y.s s Z.'.'.`. +.+++@+s s           ",
+"                s s s '.#+$+s s s               ",
+"                    s s s s s                   ",
+"                                                ",
+"                                                "};
diff --git a/xemacs-packages/gnus/etc/images/new.xpm b/xemacs-packages/gnus/etc/images/new.xpm
new file mode 100644 (file)
index 0000000..2d4690e
--- /dev/null
@@ -0,0 +1,154 @@
+/* XPM */
+static char * new_xpm[] = {
+"24 24 127 2",
+"      c None",
+".     c #000000",
+"+     c #D3D3D3",
+"@     c #F6F6F6",
+"#     c #FFFFFF",
+"$     c #F9F9F9",
+"%     c #DADADA",
+"&     c #585858",
+"*     c #C7C7C7",
+"=     c #D1D1D1",
+"-     c #D6D6D6",
+";     c #FEFEFE",
+">     c #FDFDFD",
+",     c #C0C0C0",
+"'     c #E1E1E1",
+")     c #F0F0F0",
+"!     c #9B9B9B",
+"~     c #FCFCFB",
+"{     c #FBFBFB",
+"]     c #AFAFAE",
+"^     c #E9E9E9",
+"/     c #DFDFDF",
+"(     c #8F8F8F",
+"_     c #FAFAF9",
+":     c #F9F9F8",
+"<     c #A4A4A3",
+"[     c #F4F4F4",
+"}     c #CFCFCF",
+"|     c #A2A2A2",
+"1     c #F8F8F7",
+"2     c #F8F7F6",
+"3     c #9E9E9E",
+"4     c #F7F6F5",
+"5     c #F6F6F4",
+"6     c #F4F3F2",
+"7     c #DEDDDC",
+"8     c #D3D2D0",
+"9     c #B7B7B5",
+"0     c #9F9E9D",
+"a     c #706F6F",
+"b     c #65625A",
+"c     c #F5F4F3",
+"d     c #F2F2F0",
+"e     c #E4E4E2",
+"f     c #DAD9D7",
+"g     c #D8D8D6",
+"h     c #CDCCCA",
+"i     c #AFAEAC",
+"j     c #88847B",
+"k     c #F3F3F1",
+"l     c #EFEFED",
+"m     c #EEEDEB",
+"n     c #EDECEA",
+"o     c #E9E8E6",
+"p     c #D5D4D3",
+"q     c #C4C3C2",
+"r     c #8F8A81",
+"s     c #F6F5F4",
+"t     c #F5F5F3",
+"u     c #F1F1EF",
+"v     c #F1F0EE",
+"w     c #ECEBE9",
+"x     c #EAE9E7",
+"y     c #E5E4E2",
+"z     c #E4E3E0",
+"A     c #D2D1CE",
+"B     c #8D887E",
+"C     c #F3F2F1",
+"D     c #F0F0EE",
+"E     c #F0EFED",
+"F     c #EFEEEC",
+"G     c #E8E7E5",
+"H     c #E5E4E1",
+"I     c #E2E1DE",
+"J     c #E1DFDC",
+"K     c #979288",
+"L     c #A49E93",
+"M     c #E8E7E4",
+"N     c #E7E6E3",
+"O     c #E3E2DF",
+"P     c #E2E0DD",
+"Q     c #E1E0DC",
+"R     c #E0DFDB",
+"S     c #A19C90",
+"T     c #EDEDEB",
+"U     c #EBEAE8",
+"V     c #E9E8E5",
+"W     c #E6E4E1",
+"X     c #E3E2DE",
+"Y     c #DFDEDA",
+"Z     c #DEDDD9",
+"`     c #DDDCD8",
+" .    c #A19B90",
+"..    c #E7E5E2",
+"+.    c #E4E3DF",
+"@.    c #DCDBD7",
+"#.    c #E6E5E2",
+"$.    c #E5E4E0",
+"%.    c #E2E1DD",
+"&.    c #DBD9D5",
+"*.    c #D9D7D3",
+"=.    c #9F998D",
+"-.    c #E4E2DF",
+";.    c #DDDBD7",
+">.    c #DCDAD6",
+",.    c #D8D6D2",
+"'.    c #9E988D",
+").    c #EDEDED",
+"!.    c #E1E0DD",
+"~.    c #E0DEDA",
+"{.    c #D8D6D1",
+"].    c #D7D5D1",
+"^.    c #9D978B",
+"/.    c #E1DFDB",
+"(.    c #DEDCD8",
+"_.    c #D7D6D1",
+":.    c #D5D3CE",
+"<.    c #9B958A",
+"[.    c #999891",
+"}.    c #A39E92",
+"|.    c #A39D92",
+"1.    c #A39D91",
+"2.    c #A29C90",
+"3.    c #A19B8F",
+"4.    c #9D978C",
+"5.    c #9B968A",
+"6.    c #676359",
+"                                                ",
+"      . . . . . . . . . . . . .                 ",
+"    . + @ # # # # # # # # $ % & .               ",
+"    . @ # # # # # # # # # # * = - .             ",
+"    . # # # # # # # ; # ; > , ' ) ! .           ",
+"    . # # # # # ; > ~ > ~ { ] ^ # / ( .         ",
+"    . # # # ; > ~ { _ { _ : < ) # [ } | .       ",
+"    . # ; > ~ { _ : 1 : 1 2 3 . . . . . . .     ",
+"    . # ~ { _ : 1 2 4 2 4 5 6 7 8 9 0 a b .     ",
+"    . # _ : 1 2 4 5 c 5 c 6 d e f g h i j .     ",
+"    . # 1 2 4 5 c 6 k 6 k d l m n o p q r .     ",
+"    . # s t 6 6 k d u d u v m w x y z A B .     ",
+"    . # 6 C d D l v E v E F w G H z I J K .     ",
+"    . # 6 C d D l v E v E F w G H z I J L .     ",
+"    . # D l l F m n n n n w M N O P Q R S .     ",
+"    . # T n w w w U V U V V H W X Y Z `  ..     ",
+"    . # U o o G M M N M N ..+.X R Z ` @. ..     ",
+"    . # N #.#.#.H W $.W $.+.%.R Z @.&.*.=..     ",
+"    . $ z O X -.+.%.X %.X Q Q Z ;.>.*.,.'..     ",
+"    . ).!.J Q R %.R Q R Q Y ~.;.>.*.{.].^..     ",
+"    . = /.~.Y Z R Z ~.Z ~.(.(.>.>.,._.:.<..     ",
+"    . [.}.L |.1.|.S 2.S 2.3. .=.=.4.4.5.6..     ",
+"      . . . . . . . . . . . . . . . . . .       ",
+"                                                "};
diff --git a/xemacs-packages/gnus/etc/images/next-node.xpm b/xemacs-packages/gnus/etc/images/next-node.xpm
new file mode 100644 (file)
index 0000000..385766e
--- /dev/null
@@ -0,0 +1,45 @@
+/* XPM */
+static char * next_node2_xpm[] = {
+"24 24 18 1",
+"      c None",
+".     c #000000",
+"+     c #FFFFFF",
+"@     c #DADAD6",
+"#     c #BCBCB8",
+"$     c #506B46",
+"%     c #778E6F",
+"&     c #0F1308",
+"*     c #77A16E",
+"=     c #C2D7BE",
+"-     c #6B9060",
+";     c #A9C7A6",
+">     c #C1D6BD",
+",     c #BDD3B8",
+"'     c #B0CAAD",
+")     c #A4C3A2",
+"!     c #445B2C",
+"~     c #8CA782",
+"  ..................    ",
+"  .+++++++++++++++@#.   ",
+"  .+++++++++++++++#+#.  ",
+"  .+++$#++++++++++#%$&. ",
+"  .+++..#@++++++++@%$&. ",
+"  .+++.*.#@@+@++++++@#. ",
+"  .+@@.=-.#@@++@@@@@@#. ",
+".......=;-.#@@@+@@@@@#. ",
+".=>>>>>,;;-.#@@@@@@@@#. ",
+".=;;;;';;;;-.##@@@@@@#. ",
+".@>,,,>,,,,;-.#@@@@@@#. ",
+".)----------!.%#@@@@@#. ",
+".~---------!.%##@@@@##. ",
+".*--------!.$%##@@@@@#. ",
+".......--!.%####@@@@@#. ",
+"  .##%.-!.$%####@@@@##. ",
+"  .@##.!.%####@####@##. ",
+"  .+##..%%#####@@@@@@#. ",
+"  .+@#.#####@@@####@@#. ",
+"  .+@@#####@@@@####@##. ",
+"  .+##################. ",
+"  ..................... ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/next-page.pbm b/xemacs-packages/gnus/etc/images/next-page.pbm
new file mode 100644 (file)
index 0000000..fbf7eae
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/next-page.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/next-page.xpm b/xemacs-packages/gnus/etc/images/next-page.xpm
new file mode 100644 (file)
index 0000000..75236fe
--- /dev/null
@@ -0,0 +1,119 @@
+/* XPM */
+static char * stock_next_page_xpm[] = {
+"24 24 92 2",
+"      c None",
+".     c #000000",
+"+     c #5B7289",
+"@     c #FFFFFF",
+"#     c #F2F2F2",
+"$     c #E5E5E5",
+"%     c #D8D8D8",
+"&     c #CCCCCC",
+"*     c #B0B0B0",
+"=     c #8B8B8B",
+"-     c #6A6A6A",
+";     c #494949",
+">     c #888888",
+",     c #C9C9C9",
+"'     c #E3E3E3",
+")     c #EEEEEE",
+"!     c #E6E6E6",
+"~     c #DEDEDE",
+"{     c #D6D6D6",
+"]     c #ADADAD",
+"^     c #556D85",
+"/     c #47617B",
+"(     c #BFBFBF",
+"_     c #B2B2B2",
+":     c #ACACAC",
+"<     c #A6A6A6",
+"[     c #F6F6F6",
+"}     c #384F66",
+"|     c #3A5067",
+"1     c #DADADA",
+"2     c #3A5168",
+"3     c #D3D3D3",
+"4     c #3B5269",
+"5     c #47617C",
+"6     c #3D526A",
+"7     c #48627D",
+"8     c #B6B6B6",
+"9     c #959595",
+"0     c #7C7C7C",
+"a     c #616161",
+"b     c #464646",
+"c     c #262626",
+"d     c #C5C5C5",
+"e     c #3E546A",
+"f     c #49637D",
+"g     c #3F556B",
+"h     c #4B647E",
+"i     c #40566C",
+"j     c #4C647F",
+"k     c #41576D",
+"l     c #4C657F",
+"m     c #42586E",
+"n     c #4E6780",
+"o     c #44586F",
+"p     c #4F6881",
+"q     c #B5B5B5",
+"r     c #45596F",
+"s     c #506982",
+"t     c #77838F",
+"u     c #9C9FA1",
+"v     c #91969C",
+"w     c #91979C",
+"x     c #92979C",
+"y     c #92979D",
+"z     c #A2A3A4",
+"A     c #9D9FA2",
+"B     c #8F9296",
+"C     c #8F9396",
+"D     c #8F9397",
+"E     c #909397",
+"F     c #868788",
+"G     c #465B70",
+"H     c #526A83",
+"I     c #3E5975",
+"J     c #3F5A76",
+"K     c #415B77",
+"L     c #425C78",
+"M     c #435E79",
+"N     c #445F7A",
+"O     c #46607B",
+"P     c #68727D",
+"Q     c #7D8185",
+"R     c #616A73",
+"S     c #3B4F63",
+"T     c #3C5064",
+"U     c #3C5065",
+"V     c #3E5166",
+"W     c #3F5266",
+"X     c #405367",
+"Y     c #405468",
+"Z     c #344353",
+"`     c #2F4050",
+"                                                ",
+"                                                ",
+"    . . . . . . . .       . . . . . . . .       ",
+"  . + @ # $ % & * = - ; > , ' ) ! ~ { ] ^ .     ",
+"  . / @ # $ % & ( _ : < @ @ [ ) ! ~ { _ } .     ",
+"  . / @ # $ % & ( _ : < @ ' [ ) ! ~ { _ | .     ",
+"  . / @ # $ % & ( _ : < @ . 1 ) ! ~ { * 2 .     ",
+"  . / @ # $ % & ( _ : < @ . . 3 ! ~ { * 4 .     ",
+"  . 5 @ # $ % & ( _ : < @ . . . & ~ { * 6 .     ",
+"  . 7 @ # $ 8 9 0 a b c . . . . . d { * e .     ",
+"  . f @ # $ % & ( _ : < @ . . . & ~ { * g .     ",
+"  . h @ # $ % & ( _ : < @ . . 3 ! ~ { * i .     ",
+"  . j @ # $ % & ( _ : < @ . 1 ) ! ~ { * k .     ",
+"  . l @ # $ % & ( _ : < @ ' [ ) ! ~ { * m .     ",
+"  . n @ # $ % & ( _ : < @ @ [ ) ! ~ { * o .     ",
+"  . p @ # $ % & ( _ : < @ @ [ ) ! ~ { q r .     ",
+"  . s t u v w x y y z < A B C C D D E F G .     ",
+"  . H I J K L M N O P Q R S T U V W X Y Z .     ",
+"    . . . . . . . . . ` . . . . . . . . . .     ",
+"                    . . .                       ",
+"                                                ",
+"                                                ",
+"                                                ",
+"                                                "};
diff --git a/xemacs-packages/gnus/etc/images/open.xpm b/xemacs-packages/gnus/etc/images/open.xpm
new file mode 100644 (file)
index 0000000..6b95c7e
--- /dev/null
@@ -0,0 +1,200 @@
+/* XPM */
+static char * open_xpm[] = {
+"24 24 173 2",
+"      c None",
+".     c #000000",
+"+     c #010100",
+"@     c #B5B8A5",
+"#     c #E4E7D2",
+"$     c #878A76",
+"%     c #33342B",
+"&     c #0B0B0B",
+"*     c #E2E5CF",
+"=     c #CFD4AF",
+"-     c #CED3AE",
+";     c #B2B696",
+">     c #2D2D25",
+",     c #23241D",
+"'     c #9D9F90",
+")     c #C6CAA6",
+"!     c #C4C9A5",
+"~     c #C6CBA7",
+"{     c #C7CCA8",
+"]     c #C9CEA9",
+"^     c #555847",
+"/     c #1A1B15",
+"(     c #20201A",
+"_     c #D4D6C2",
+":     c #BEC2A0",
+"<     c #B3B896",
+"[     c #B0B595",
+"}     c #B3B797",
+"|     c #B6BB99",
+"1     c #BBC09E",
+"2     c #BCC19F",
+"3     c #81856C",
+"4     c #3E3F32",
+"5     c #010101",
+"6     c #DADDC8",
+"7     c #AFB494",
+"8     c #AAAF8F",
+"9     c #A3A789",
+"0     c #A6AA8B",
+"a     c #A9AD8E",
+"b     c #A7AB8D",
+"c     c #A4A88A",
+"d     c #A1A588",
+"e     c #AAAD96",
+"f     c #B3B5A5",
+"g     c #B8BBAA",
+"h     c #BABCAB",
+"i     c #C1C3B2",
+"j     c #C7CAB7",
+"k     c #CACDBB",
+"l     c #BABDA8",
+"m     c #0C0C09",
+"n     c #DDDFCB",
+"o     c #969B7E",
+"p     c #9DA286",
+"q     c #95987C",
+"r     c #96997E",
+"s     c #9A9D81",
+"t     c #999D80",
+"u     c #9DA184",
+"v     c #A5AA8B",
+"w     c #A4A98A",
+"x     c #A3A889",
+"y     c #A2A588",
+"z     c #A2A587",
+"A     c #9FA386",
+"B     c #9B9E83",
+"C     c #898D74",
+"D     c #D8DBC9",
+"E     c #84866E",
+"F     c #7D8169",
+"G     c #151612",
+"H     c #D7DAC9",
+"I     c #797D67",
+"J     c #3D3F34",
+"K     c #E0E0D9",
+"L     c #EBEDDD",
+"M     c #E8EBD9",
+"N     c #E7EAD8",
+"O     c #E3E6D4",
+"P     c #DEE1D0",
+"Q     c #DADCCC",
+"R     c #DADCD1",
+"S     c #2B2C28",
+"T     c #D7DAC6",
+"U     c #6F735E",
+"V     c #0D0D0D",
+"W     c #F4F4EC",
+"X     c #CACFAB",
+"Y     c #C6CBA8",
+"Z     c #C2C6A4",
+"`     c #ABB091",
+" .    c #23251E",
+"..    c #494B3D",
+"+.    c #DCDCD4",
+"@.    c #EAECDD",
+"#.    c #CDD2AD",
+"$.    c #CCD1AC",
+"%.    c #CACFAA",
+"&.    c #BABF9D",
+"*.    c #B5B999",
+"=.    c #81836C",
+"-.    c #070806",
+";.    c #D5D8C4",
+">.    c #161616",
+",.    c #F2F2EA",
+"'.    c #C9CEAA",
+").    c #C8CDA9",
+"!.    c #C4C9A6",
+"~.    c #C1C5A3",
+"{.    c #BCC09F",
+"].    c #B6BB9A",
+"^.    c #B0B494",
+"/.    c #9DA185",
+"(.    c #535445",
+"_.    c #B6B8A7",
+":.    c #747470",
+"<.    c #ECECE2",
+"[.    c #C3C8A5",
+"}.    c #C2C7A4",
+"|.    c #C0C5A2",
+"1.    c #BFC4A1",
+"2.    c #BDC2A0",
+"3.    c #B9BD9C",
+"4.    c #B9BE9D",
+"5.    c #A9AD8F",
+"6.    c #A3A78A",
+"7.    c #80836D",
+"8.    c #020201",
+"9.    c #A6A998",
+"0.    c #B8BC9B",
+"a.    c #AFB394",
+"b.    c #ACB091",
+"c.    c #A8AC8E",
+"d.    c #A6AA8C",
+"e.    c #9FA286",
+"f.    c #9B9F83",
+"g.    c #9A9D82",
+"h.    c #8A8D75",
+"i.    c #4F5243",
+"j.    c #070705",
+"k.    c #9E9F91",
+"l.    c #E5E6DA",
+"m.    c #ADB192",
+"n.    c #A5A98C",
+"o.    c #9FA387",
+"p.    c #999D81",
+"q.    c #95987E",
+"r.    c #92957B",
+"s.    c #8C8F76",
+"t.    c #8A8D74",
+"u.    c #71735F",
+"v.    c #080908",
+"w.    c #E3E5D9",
+"x.    c #C0C3AF",
+"y.    c #94987C",
+"z.    c #8F9379",
+"A.    c #8B8F75",
+"B.    c #8A8E74",
+"C.    c #888C73",
+"D.    c #858970",
+"E.    c #868971",
+"F.    c #82866E",
+"G.    c #80836C",
+"H.    c #7D8069",
+"I.    c #797C66",
+"J.    c #727560",
+"K.    c #717460",
+"L.    c #71745F",
+"M.    c #6A6D59",
+"N.    c #434538",
+"O.    c #080907",
+"P.    c #050504",
+"                                                ",
+"                                                ",
+"                                                ",
+"    . . . . . . .                               ",
+"  + @ # # # # # $ %                             ",
+"  & * = = = - - ; >                             ",
+", ' * ) ! ~ { ] ] ^ /                           ",
+"( _ : < [ } | 1 2 3 4 5 . . . . . . .           ",
+", 6 7 8 9 0 8 a b c d e f g h i j k l .         ",
+"m n o p q r s t r u v w x y 9 z A B C .         ",
+". D E F G . . . . . . . . . . . . . . . 5 5     ",
+". H I J K L M M M M M M M M M M M N O P Q R S   ",
+". T U V W = = = = = = = = = - - - X Y Z 1 `  .  ",
+". T ..+.@.#.- - #.- #.#.#.#.#.$.%.Y Z &.*.=.-.  ",
+". ;.>.,.X %.X %.'.%.'.{ ).).Y !.~.{.].^./.(.m   ",
+". _.:.<.[.}.}.Z |.Z 1.2.|.2.3.4.} [ 5.6.7.8.    ",
+". 9.+.0.0.*.} } [ [ a.a.a.b.c.d.e.f.g.h.i.j.    ",
+". k.l.m.5.d.n.6.6.d o.e.f.p.q.r.s.t.t.u.v.      ",
+". w.x.y.z.A.B.C.C.D.E.F.G.H.I.J.K.L.M.N.O.      ",
+"  . . . . . . . . . . . . . . . . . . P.        ",
+"                                                ",
+"                                                ",
+"                                                ",
+"                                                "};
diff --git a/xemacs-packages/gnus/etc/images/paste.xpm b/xemacs-packages/gnus/etc/images/paste.xpm
new file mode 100644 (file)
index 0000000..cdd8636
--- /dev/null
@@ -0,0 +1,116 @@
+/* XPM */
+static char * paste_xpm[] = {
+"24 24 89 1",
+"      c None",
+".     c #000000",
+"+     c #B9B9B9",
+"@     c #FEFEFE",
+"#     c #F9F9F9",
+"$     c #757575",
+"%     c #F5F5E8",
+"&     c #565651",
+"*     c #FFFFFF",
+"=     c #A0A0A0",
+"-     c #939393",
+";     c #7C7C7C",
+">     c #C5C5BB",
+",     c #CFC6A0",
+"'     c #D7CEAA",
+")     c #ADA689",
+"!     c #4B483C",
+"~     c #6D6D6D",
+"{     c #6C6C6C",
+"]     c #A9A9A9",
+"^     c #3D3A30",
+"/     c #979178",
+"(     c #C1B898",
+"_     c #8A793D",
+":     c #C3BB9A",
+"<     c #AFA78A",
+"[     c #444236",
+"}     c #FAFAFA",
+"|     c #EFEFEF",
+"1     c #C7C7C7",
+"2     c #D8D8D8",
+"3     c #D2D2D2",
+"4     c #7B7B7B",
+"5     c #302E26",
+"6     c #89846C",
+"7     c #C4BC9A",
+"8     c #847235",
+"9     c #C5C5C5",
+"0     c #A7A7A7",
+"a     c #ADADAD",
+"b     c #9A9A9A",
+"c     c #9B9B9B",
+"d     c #868686",
+"e     c #424242",
+"f     c #847033",
+"g     c #C9C09E",
+"h     c #464337",
+"i     c #35332A",
+"j     c #2D2B23",
+"k     c #C6BE9D",
+"l     c #826F33",
+"m     c #7F7964",
+"n     c #4C493C",
+"o     c #171612",
+"p     c #13120F",
+"q     c #3E3B31",
+"r     c #282210",
+"s     c #474438",
+"t     c #B3B3B3",
+"u     c #D6D6D6",
+"v     c #B7AE90",
+"w     c #B1AA8C",
+"x     c #37352B",
+"y     c #151410",
+"z     c #8F8F8F",
+"A     c #989898",
+"B     c #C6C6C6",
+"C     c #B9B293",
+"D     c #11100D",
+"E     c #434035",
+"F     c #636363",
+"G     c #767676",
+"H     c #AAA48B",
+"I     c #A5A086",
+"J     c #A19A7F",
+"K     c #312F26",
+"L     c #AFA88C",
+"M     c #050403",
+"N     c #12110E",
+"O     c #A9A489",
+"P     c #A39E85",
+"Q     c #EBE7D0",
+"R     c #D2C9A5",
+"S     c #A29053",
+"T     c #8E7C3D",
+"U     c #88793B",
+"V     c #806C2F",
+"W     c #78652B",
+"X     c #251F0C",
+"       ....             ",
+" ......+@#$......       ",
+".%%%%%&*=-;&>%%%,.      ",
+".%''')!*~{]^/(''_.      ",
+".%::<[}|123456<78.      ",
+".%''!900abcde!)'f.      ",
+".%g:6hijjjjj56<kl.      ",
+".%'''////////(''l.      ",
+".%g::::mnopppp^qr....   ",
+".%'''''st***********u.  ",
+".%vwwwwx*************.  ",
+".%'''''y*0zzA**Bz*zB*.  ",
+".%CwwwwD*************.  ",
+".%'''''E*~F*GzzB*Bz**.  ",
+".%HIJJJK*************.  ",
+".%'''''E*0zz*zzzB*Az*.  ",
+".%LIJJJM*************.  ",
+".%'''''N*~F*GzzB*Bz**.  ",
+".%OPJJJK*************.  ",
+".Q'''''E*0zz*zzzB*Az*.  ",
+".RSTUVWX*************.  ",
+" .......u***********u.  ",
+"        .............   ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/preferences.xpm b/xemacs-packages/gnus/etc/images/preferences.xpm
new file mode 100644 (file)
index 0000000..3cdc884
--- /dev/null
@@ -0,0 +1,114 @@
+/* XPM */
+static char * preferences_xpm[] = {
+"24 24 87 1",
+"      c None",
+".     c #000000",
+"+     c #BAB5AB",
+"@     c #D0CDC6",
+"#     c #88857D",
+"$     c #C9C6BE",
+"%     c #CCC8C1",
+"&     c #E5E3E0",
+"*     c #FFFFFF",
+"=     c #757575",
+"-     c #2E2E2E",
+";     c #F6F5F5",
+">     c #CCCCCC",
+",     c #AFAFAF",
+"'     c #D3D1CB",
+")     c #C1C0BF",
+"!     c #F0EFED",
+"~     c #797772",
+"{     c #DCDCDC",
+"]     c #A5A19C",
+"^     c #EAE9E5",
+"/     c #F3F1F0",
+"(     c #EDEDED",
+"_     c #A19D96",
+":     c #C1BDB4",
+"<     c #DBD8D3",
+"[     c #D9D6D1",
+"}     c #89857E",
+"|     c #FCFCFC",
+"1     c #EAE9E6",
+"2     c #F5F4F3",
+"3     c #C6C2BA",
+"4     c #F0EFEE",
+"5     c #F4F4F3",
+"6     c #CBC7C0",
+"7     c #ECECEB",
+"8     c #676560",
+"9     c #54524D",
+"0     c #777676",
+"a     c #797978",
+"b     c #85827E",
+"c     c #79756F",
+"d     c #7590AE",
+"e     c #A4BAD0",
+"f     c #90A6BE",
+"g     c #9F9F9E",
+"h     c #BEBDBC",
+"i     c #B8B4AD",
+"j     c #87837C",
+"k     c #D3DFEA",
+"l     c #A2AEBC",
+"m     c #9DB6CE",
+"n     c #637B95",
+"o     c #E2E2E2",
+"p     c #EEEEED",
+"q     c #849CB6",
+"r     c #D7E2ED",
+"s     c #8D98A5",
+"t     c #9DB8D2",
+"u     c #607791",
+"v     c #EDEDEC",
+"w     c #99ADC3",
+"x     c #DFE7F0",
+"y     c #8193A9",
+"z     c #586D84",
+"A     c #5B7189",
+"B     c #F1F1F1",
+"C     c #EEEDEB",
+"D     c #A7A6A5",
+"E     c #726F6A",
+"F     c #A1B4C8",
+"G     c #EEF3F6",
+"H     c #60768F",
+"I     c #DEDDDC",
+"J     c #787776",
+"K     c #4E4E4D",
+"L     c #91A6BE",
+"M     c #F0F4F7",
+"N     c #97A5B6",
+"O     c #BFBEBD",
+"P     c #AAAAA9",
+"Q     c #ACACAB",
+"R     c #B0C6DB",
+"S     c #EDF2F6",
+"T     c #818A95",
+"U     c #6C85A1",
+"V     c #C0D1E2",
+"       ..               ",
+"      .+@#.             ",
+"       .$%+.        ..  ",
+"        .&$.       .*=. ",
+"    ..  -;$.      .*>,. ",
+"   .' ..)!+~.     .{,.  ",
+"   .]%%^/+++.    .(..   ",
+"    ._:%$<[+}.  .|.     ",
+"     .....123}..>.      ",
+"          .456.,.       ",
+"           .7.,..       ",
+"            .,.89.      ",
+"        ....,.0abc.     ",
+"       .def.. .ghij.    ",
+"      .dklmn.  .op6}.   ",
+"     .qrsntu.   .v/$}.  ",
+"    .wxyztdA.    .BCDE..",
+"   .FGyHtdA.      .IJK,.",
+"  .LMNHtdA.        .OPQ.",
+"  .RSTtdA..         ... ",
+"  .UtVLA..              ",
+"   .UUn..               ",
+"    ...                 ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/prev-node.xpm b/xemacs-packages/gnus/etc/images/prev-node.xpm
new file mode 100644 (file)
index 0000000..586bf9c
--- /dev/null
@@ -0,0 +1,44 @@
+/* XPM */
+static char * prev_node3_xpm[] = {
+"24 24 17 1",
+"      c None",
+".     c #000000",
+"+     c #0F1308",
+"@     c #FFFFFF",
+"#     c #BCBCB8",
+"$     c #DADAD6",
+"%     c #778E6F",
+"&     c #C2D7BE",
+"*     c #A6BFA0",
+"=     c #A9C7A6",
+"-     c #BDD3B8",
+";     c #B0CAAD",
+">     c #C1D6BD",
+",     c #8CA782",
+"'     c #5B7950",
+")     c #6B9060",
+"!     c #445B2C",
+"    ..................  ",
+"   +@#@@@@@@@@@@@@@@$.  ",
+"  +@@%$@@@@@@@@@@@@@$.  ",
+" .$#%%$@@@@@@@@@$.$$$.  ",
+" .%$##$@@@@@@@@#..$$$.  ",
+" .#@@@@@@@@@$$#.&.#$$.  ",
+" .$@@@@@@@@@@#.$*.##$.  ",
+" .@@@@@@@@$$#.$=*.......",
+" .@@@@@@@$$#.$==-&&&&&*.",
+" .@@@@@@@$#.@====;====%.",
+" .@$@$$$$#.$>>>>>>>>>>,.",
+" .@$@$$$$#.'))))))))))!.",
+" .@$$$$$$##.')))))))))!.",
+" .@$$$$$$##%.')))'!!!!!.",
+" .@$$$$$##$#%.')!.......",
+" .@$$$$$$$###%.'!.%%%.  ",
+" .@$$#####$$##%.!.%##.  ",
+" .@$$$$$$$#####%..###.  ",
+" .@$$#####$$$###%.###.  ",
+" .@$$$$$$$$$$$#######.  ",
+" .@##################.  ",
+" .....................  ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/print.xpm b/xemacs-packages/gnus/etc/images/print.xpm
new file mode 100644 (file)
index 0000000..95f2f40
--- /dev/null
@@ -0,0 +1,202 @@
+/* XPM */
+static char * print_xpm[] = {
+"24 24 175 2",
+"      c None",
+".     c #000000",
+"+     c #C7C7C7",
+"@     c #FAFAFA",
+"#     c #FCFCFC",
+"$     c #FBFBFB",
+"%     c #F8F8F8",
+"&     c #AFAFAF",
+"*     c #F9F9F9",
+"=     c #E5E5E5",
+"-     c #E3E3E3",
+";     c #E2E2E2",
+">     c #E0E0E0",
+",     c #DFDFDF",
+"'     c #DCDCDC",
+")     c #DBDBDB",
+"!     c #B6B6B6",
+"~     c #6B6B6B",
+"{     c #676767",
+"]     c #818181",
+"^     c #E7E7E7",
+"/     c #606060",
+"(     c #A0A0A0",
+"_     c #DADADA",
+":     c #E1E1E1",
+"<     c #B7B7B7",
+"[     c #FDFDFD",
+"}     c #EFEFEF",
+"|     c #EEEEEE",
+"1     c #EDEDED",
+"2     c #ECECEC",
+"3     c #EBEBEB",
+"4     c #E9E9E9",
+"5     c #E8E8E8",
+"6     c #BFBFBF",
+"7     c #8A8A8A",
+"8     c #6A6A6A",
+"9     c #9E9E9E",
+"0     c #F6F6F6",
+"a     c #909090",
+"b     c #A2A2A2",
+"c     c #AAAAAA",
+"d     c #F4F4F4",
+"e     c #CECECE",
+"f     c #ADADAD",
+"g     c #AEAEAE",
+"h     c #BEBEBE",
+"i     c #A6A6A6",
+"j     c #CDCDCD",
+"k     c #F5F5F5",
+"l     c #DEDEDE",
+"m     c #DDDDDD",
+"n     c #C9C9C9",
+"o     c #878787",
+"p     c #888888",
+"q     c #D0D0D0",
+"r     c #6E6E6E",
+"s     c #797979",
+"t     c #D1D1D1",
+"u     c #A1A1A1",
+"v     c #B3B3B3",
+"w     c #FFFFFF",
+"x     c #CACACA",
+"y     c #A7A7A7",
+"z     c #A5A5A5",
+"A     c #A4A4A4",
+"B     c #A3A3A3",
+"C     c #87847C",
+"D     c #EAE8E3",
+"E     c #8D8982",
+"F     c #53524C",
+"G     c #807D74",
+"H     c #AAA9A5",
+"I     c #BAB5AB",
+"J     c #F3F3F3",
+"K     c #C3C1BD",
+"L     c #8B8B89",
+"M     c #E6E5E1",
+"N     c #F9F9F8",
+"O     c #FAFAF9",
+"P     c #F9F9F7",
+"Q     c #F7F6F5",
+"R     c #F7F7F4",
+"S     c #F6F5F4",
+"T     c #F2F1EE",
+"U     c #F0EFEC",
+"V     c #E5E5E4",
+"W     c #9F9F9F",
+"X     c #DFDED9",
+"Y     c #A4A3A1",
+"Z     c #6C6B6A",
+"`     c #F5F4F3",
+" .    c #D5D5D5",
+"..    c #D3D3D3",
+"+.    c #D4D4D3",
+"@.    c #D4D4D4",
+"#.    c #A9A9A9",
+"$.    c #B5B5B5",
+"%.    c #CDCDCB",
+"&.    c #B5B5B4",
+"*.    c #DCDAD3",
+"=.    c #6B6B6A",
+"-.    c #999896",
+";.    c #918F87",
+">.    c #999895",
+",.    c #E6E4E1",
+"'.    c #F0EEEC",
+").    c #FAF9F9",
+"!.    c #F9F8F7",
+"~.    c #F8F7F6",
+"{.    c #F8F8F7",
+"].    c #F4F3F1",
+"^.    c #F2F1EF",
+"/.    c #565655",
+"(.    c #858482",
+"_.    c #9C9B99",
+":.    c #6B6A68",
+"<.    c #585858",
+"[.    c #5E5C57",
+"}.    c #524F4B",
+"|.    c #4A4845",
+"1.    c #4B4A46",
+"2.    c #4B4946",
+"3.    c #4A4844",
+"4.    c #494743",
+"5.    c #484642",
+"6.    c #474541",
+"7.    c #464440",
+"8.    c #514F4B",
+"9.    c #53514E",
+"0.    c #7B7A77",
+"a.    c #797771",
+"b.    c #949391",
+"c.    c #989694",
+"d.    c #868480",
+"e.    c #6E6C66",
+"f.    c #706D67",
+"g.    c #5C5955",
+"h.    c #67645F",
+"i.    c #5B5954",
+"j.    c #585651",
+"k.    c #5D5B56",
+"l.    c #595652",
+"m.    c #53504C",
+"n.    c #575450",
+"o.    c #595752",
+"p.    c #5C5956",
+"q.    c #5B5956",
+"r.    c #61615E",
+"s.    c #696861",
+"t.    c #77756F",
+"u.    c #7E7B77",
+"v.    c #979690",
+"w.    c #96938D",
+"x.    c #807E77",
+"y.    c #7D7A74",
+"z.    c #787770",
+"A.    c #716F6A",
+"B.    c #6E6C67",
+"C.    c #595753",
+"D.    c #63615C",
+"E.    c #686661",
+"F.    c #6F6E68",
+"G.    c #6D6C66",
+"H.    c #72716B",
+"I.    c #76746F",
+"J.    c #6A6963",
+"K.    c #8B8880",
+"L.    c #B2AFA8",
+"M.    c #B6B3AD",
+"N.    c #BFBDB6",
+"O.    c #BDBBB4",
+"P.    c #B0AEA6",
+"Q.    c #ABA8A2",
+"R.    c #9C9991",
+"                                                ",
+"            . . . . . . . . . . . .             ",
+"          . + @ # # # # # # # $ % & .           ",
+"          . * = - - - ; > , , ' ) ! .           ",
+"          . # ~ { ] ^ / ( _ : > > < .           ",
+"          . [ } | 1 1 | 2 2 3 4 5 6 .           ",
+"          . [ 7 8 9 0 a b 4 c a d + .           ",
+"          . [ # # # # $ $ # # $ $ e .           ",
+"          . [ f g = h % h i j 3 # j .           ",
+"          . k l l l m l l , l 5 : n .           ",
+"        . . @ o ~ p q r s t p u q v . .         ",
+"      . w . x y z A z z i B b u u 9 . C .       ",
+"    . w D E F . . . . . . . . . . G C H I .     ",
+"  . w w J w w w w w w w w w w w w w w w w D .   ",
+"  . K L M N O N P Q R O O S T T U V D W X I .   ",
+"  . Y Z ` h  .! ..! +.< @.#...$.%.&.*.=.-.;..   ",
+"  . >.=.,.'.Q N @ ).N !.~.{.{.].].].^./.(.;..   ",
+"  . _.:.<.[.}.|.1.2.2.2.3.4.5.6.4.7.8.9.0.a..   ",
+"  . b.c.d.e.f.g.h.i.j.i.k.l.m.n.o.p.q.r.s.t..   ",
+"  . u.v.w.;.x.y.z.t.A.t.A.B.C.D.E.F.G.H.I.J..   ",
+"    . . . . . . . . . . . . . . . . . . . .     ",
+"    . K.L.M.N.N.N.N.N.O.P.L.Q.P.R.R.R.G G .     ",
+"      . . . . . . . . . . . . . . . . . .       ",
+"                                                "};
diff --git a/xemacs-packages/gnus/etc/images/redo.xpm b/xemacs-packages/gnus/etc/images/redo.xpm
new file mode 100644 (file)
index 0000000..273aec5
--- /dev/null
@@ -0,0 +1,69 @@
+/* XPM */
+static char * stock_redo_xpm[] = {
+"24 24 42 1",
+"      c None",
+".     c #000000",
+"+     c #939A8D",
+"@     c #BAD09D",
+"#     c #92998C",
+"$     c #818F71",
+"%     c #ADBDA0",
+"&     c #C2D5AA",
+"*     c #D1DFBE",
+"=     c #BED2A3",
+"-     c #99A28F",
+";     c #A8BCA6",
+">     c #D5E1C6",
+",     c #CDDCBC",
+"'     c #D2E0BF",
+")     c #C5D7AE",
+"!     c #919889",
+"~     c #8C9A7F",
+"{     c #D4E0C5",
+"]     c #D3E0C1",
+"^     c #BFD3A6",
+"/     c #9BAA87",
+"(     c #B5C3A9",
+"_     c #92AD62",
+":     c #7C9B40",
+"<     c #59702D",
+"[     c #7F8E6B",
+"}     c #C8D9B2",
+"|     c #85A24D",
+"1     c #53692A",
+"2     c #A4B690",
+"3     c #9BB572",
+"4     c #6D8839",
+"5     c #95A77E",
+"6     c #8BA859",
+"7     c #657255",
+"8     c #98AF74",
+"9     c #AFC394",
+"0     c #6D7A5B",
+"a     c #9CAF84",
+"b     c #748261",
+"c     c #879772",
+"                        ",
+"                        ",
+"                        ",
+"            .           ",
+"            ..          ",
+"            .+.         ",
+"         ....@#.        ",
+"        .$%&*=@-.       ",
+"       .;>,')@@@!.      ",
+"      .~{]*^@@@@@/.     ",
+"      .(>_::::::<.      ",
+"     .[}|::::::1.       ",
+"     .23:<...:1.        ",
+"     .@:4.  .<.         ",
+"     .@:..  ..          ",
+"     .56.   .           ",
+"     .78.               ",
+"      .9.               ",
+"      .0a.              ",
+"       .bc.             ",
+"        ...             ",
+"                        ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/refresh.xpm b/xemacs-packages/gnus/etc/images/refresh.xpm
new file mode 100644 (file)
index 0000000..827ce3f
--- /dev/null
@@ -0,0 +1,153 @@
+/* XPM */
+static char * refresh_xpm[] = {
+"24 24 126 2",
+"      c None",
+".     c #000000",
+"+     c #F0FFEE",
+"@     c #CAE3C6",
+"#     c #F5FFF4",
+"$     c #0D110C",
+"%     c #729C6C",
+"&     c #A6CAA1",
+"*     c #CBE4C7",
+"=     c #EFFDEE",
+"-     c #172116",
+";     c #88B583",
+">     c #CCE5C8",
+",     c #CDE6C9",
+"'     c #CFE7CB",
+")     c #F3FFF2",
+"!     c #7FA879",
+"~     c #689063",
+"{     c #CDE5C9",
+"]     c #CFE7CA",
+"^     c #D0E9CC",
+"/     c #D4EAD0",
+"(     c #D5ECD1",
+"_     c #AED5A9",
+":     c #9ABC95",
+"<     c #63865F",
+"[     c #2B3A29",
+"}     c #8CB887",
+"|     c #70986A",
+"1     c #71986B",
+"2     c #729A6B",
+"3     c #759C6D",
+"4     c #759F6F",
+"5     c #76A170",
+"6     c #567453",
+"7     c #AFCBAC",
+"8     c #7EAB77",
+"9     c #78A472",
+"0     c #6F9669",
+"a     c #70976A",
+"b     c #71996B",
+"c     c #739B6D",
+"d     c #759F6E",
+"e     c #77A170",
+"f     c #526F4C",
+"g     c #B7D2B2",
+"h     c #60835B",
+"i     c #A5C9A0",
+"j     c #9AC195",
+"k     c #4F6B4C",
+"l     c #769F70",
+"m     c #516D4C",
+"n     c #B9D5B4",
+"o     c #7BA574",
+"p     c #C7E0C3",
+"q     c #6D9568",
+"r     c #51714E",
+"s     c #B6D3B2",
+"t     c #81AB7C",
+"u     c #C3DBBF",
+"v     c #6B9265",
+"w     c #C8EFC3",
+"x     c #A7CCA2",
+"y     c #B5D2B1",
+"z     c #80A87A",
+"A     c #90B68B",
+"B     c #79A674",
+"C     c #C6EAC1",
+"D     c #DEF7D9",
+"E     c #B3D7AE",
+"F     c #BBD9B8",
+"G     c #AFCCAB",
+"H     c #749E6D",
+"I     c #5B7B57",
+"J     c #8CB087",
+"K     c #BBE1B6",
+"L     c #DAF5D6",
+"M     c #E1F7DD",
+"N     c #DCF4D6",
+"O     c #D7F0D3",
+"P     c #CFECCB",
+"Q     c #C6E3C3",
+"R     c #BCD6B9",
+"S     c #7EA778",
+"T     c #64885F",
+"U     c #A6C1A3",
+"V     c #B3D5AE",
+"W     c #CDEAC9",
+"X     c #D0EBCB",
+"Y     c #CAE9C5",
+"Z     c #C7E6C3",
+"`     c #C3E3BF",
+" .    c #BDDCBA",
+"..    c #B5D2B2",
+"+.    c #96B991",
+"@.    c #76A071",
+"#.    c #3A4E37",
+"$.    c #5E7F5A",
+"%.    c #8FAF8B",
+"&.    c #9CBE97",
+"*.    c #C7E0C4",
+"=.    c #CBE3C6",
+"-.    c #CDE4C9",
+";.    c #CBE4C8",
+">.    c #C7E1C4",
+",.    c #C2DBBF",
+"'.    c #88AF82",
+").    c #6B9266",
+"!.    c #557451",
+"~.    c #63885E",
+"{.    c #759C70",
+"].    c #749E6F",
+"^.    c #72996B",
+"/.    c #739A6D",
+"(.    c #71996C",
+"_.    c #6E9668",
+":.    c #6C9367",
+"<.    c #5F815A",
+"[.    c #70996B",
+"}.    c #6E9467",
+"|.    c #698F63",
+"1.    c #6B9166",
+"2.    c #5D8059",
+"3.    c #4D6A49",
+"4.    c #6A8F64",
+"5.    c #283926",
+"              .                                 ",
+"              . .                               ",
+"              . + .                             ",
+"        . . . . @ # .                           ",
+"      $ % & @ @ * * = .           . .           ",
+"    - ; @ @ * * > , ' ) .       . ! ~ .         ",
+"  . % @ * * > { ] ^ / ( _ .       . : < .       ",
+"  [ & @ } | 1 2 3 4 5 6 .           . 7 .       ",
+". 8 @ 9 0 a b c d e f .             . g h .     ",
+". i j 0 k . . . l m .       .       . n o .     ",
+". p q h .     . 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 `  ...+.@.#..     ",
+"  . $.%..       . &.*.=., -.;.>.,.'.).!..       ",
+"    . ~.{..       . ].^.c /.(.| _.:.<.. .       ",
+"      . .           . [.}.|.~ 1.2.3.. .         ",
+"                      . q 4.. . . .             ",
+"                        5.)..                   ",
+"                          . .                   ",
+"                            .                   ",
+"                                                ",
+"                                                "};
diff --git a/xemacs-packages/gnus/etc/images/right-arrow.xpm b/xemacs-packages/gnus/etc/images/right-arrow.xpm
new file mode 100644 (file)
index 0000000..da81568
--- /dev/null
@@ -0,0 +1,68 @@
+/* XPM */
+static char * right_arrow_xpm[] = {
+"24 24 41 1",
+"      c None",
+".     c #000000",
+"+     c #8CA782",
+"@     c #B1CDAE",
+"#     c #77A16E",
+"$     c #B4CEB1",
+"%     c #ACC8A9",
+"&     c #709867",
+"*     c #C1D6BD",
+"=     c #BDD3B8",
+"-     c #BFD4BB",
+";     c #C2D7BE",
+">     c #B0CAAD",
+",     c #B2CBB0",
+"'     c #AAC7A8",
+")     c #0F1308",
+"!     c #AEC5A8",
+"~     c #AEC8AD",
+"{     c #ABC7A8",
+"]     c #AAC6A7",
+"^     c #A8C6A5",
+"/     c #ADC8AD",
+"(     c #A8C7A8",
+"_     c #A5C4A3",
+":     c #7F9F76",
+"<     c #A6BFA0",
+"[     c #ABC7AA",
+"}     c #A7C5A4",
+"|     c #A9C7A6",
+"1     c #AFC8AD",
+"2     c #A4C3A2",
+"3     c #6B9060",
+"4     c #778E6F",
+"5     c #698D60",
+"6     c #6B9063",
+"7     c #445B2C",
+"8     c #6B8661",
+"9     c #5B7950",
+"0     c #6C8562",
+"a     c #65815C",
+"b     c #506B46",
+"                        ",
+"                        ",
+"                        ",
+"           .            ",
+"           ..           ",
+"           .+.          ",
+"           .@#.         ",
+"    ........$%&.        ",
+"    .*=-;;;;>,'&)       ",
+"    .!~{{{]^'/(_:.      ",
+"    .<[^}^|{%'{123.     ",
+"    .45666666666657.    ",
+"    .8999999999997.     ",
+"    .099999999997.      ",
+"    .abbbbbb9997.       ",
+"    ........b97.        ",
+"           .b7.         ",
+"           .7.          ",
+"           ..           ",
+"           .            ",
+"                        ",
+"                        ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/save.xpm b/xemacs-packages/gnus/etc/images/save.xpm
new file mode 100644 (file)
index 0000000..6507e37
--- /dev/null
@@ -0,0 +1,247 @@
+/* XPM */
+static char * save_xpm[] = {
+"24 24 220 2",
+"      c None",
+".     c #000000",
+"+     c #C3D7F4",
+"@     c #A9CDE5",
+"#     c #75757A",
+"$     c #EFC5BB",
+"%     c #F1C8BE",
+"&     c #F0C6BC",
+"*     c #EEBCB2",
+"=     c #EEBEB5",
+"-     c #EEC1B8",
+";     c #EDBFB6",
+">     c #E9B7AD",
+",     c #E9B8AF",
+"'     c #E9B9B1",
+")     c #E5BFBA",
+"!     c #737277",
+"~     c #B3CDE3",
+"{     c #A1BED6",
+"]     c #BBD6E8",
+"^     c #8AAAC5",
+"/     c #605F68",
+"(     c #E08D7E",
+"_     c #E0826E",
+":     c #E0806E",
+"<     c #DC7A68",
+"[     c #DC8171",
+"}     c #DA7868",
+"|     c #D48173",
+"1     c #D47D6E",
+"2     c #CE7265",
+"3     c #CF7264",
+"4     c #CE7567",
+"5     c #C4675B",
+"6     c #C36558",
+"7     c #626169",
+"8     c #87A3B7",
+"9     c #567187",
+"0     c #BAD5E9",
+"a     c #88A7C3",
+"b     c #686670",
+"c     c #C8817B",
+"d     c #CB7C74",
+"e     c #CB7A73",
+"f     c #CB7B73",
+"g     c #CC7C72",
+"h     c #CB7D73",
+"i     c #BF6B64",
+"j     c #CC7A70",
+"k     c #C16A62",
+"l     c #CC7C73",
+"m     c #C2655B",
+"n     c #C36459",
+"o     c #BA6C6A",
+"p     c #819EB6",
+"q     c #547086",
+"r     c #B6D3E7",
+"s     c #87ABC1",
+"t     c #737373",
+"u     c #FFFFFF",
+"v     c #83A0B8",
+"w     c #526C80",
+"x     c #B9D3E7",
+"y     c #85A4BF",
+"z     c #4F697C",
+"A     c #B9D3E6",
+"B     c #84A3BF",
+"C     c #CECECE",
+"D     c #CDCDCD",
+"E     c #BFBFBF",
+"F     c #88A4BB",
+"G     c #486276",
+"H     c #B7D2E7",
+"I     c #82A0BB",
+"J     c #636363",
+"K     c #465E70",
+"L     c #B5CAE5",
+"M     c #7FA2B9",
+"N     c #87A3BA",
+"O     c #455C6D",
+"P     c #AECCE5",
+"Q     c #7DA0B6",
+"R     c #C5C5C5",
+"S     c #546069",
+"T     c #B0D1E4",
+"U     c #83A1B6",
+"V     c #735B5B",
+"W     c #515C64",
+"X     c #AACEE3",
+"Y     c #7B9BB2",
+"Z     c #7A8E9A",
+"`     c #7A7A7A",
+" .    c #6B6F72",
+"..    c #6F6F6F",
+"+.    c #696969",
+"@.    c #6F777E",
+"#.    c #86A2B9",
+"$.    c #3A515D",
+"%.    c #A9C9E2",
+"&.    c #7494AF",
+"*.    c #829FB7",
+"=.    c #7F9DB6",
+"-.    c #7E9CB5",
+";.    c #7998B2",
+">.    c #85A1B8",
+",.    c #8CA7BD",
+"'.    c #8AA5BB",
+").    c #364A59",
+"!.    c #ABC4E2",
+"~.    c #7294AD",
+"{.    c #6F90AC",
+"].    c #7192AE",
+"^.    c #414A4E",
+"/.    c #424A51",
+"(.    c #525B63",
+"_.    c #626F79",
+":.    c #5F6C76",
+"<.    c #5C6971",
+"[.    c #5A666F",
+"}.    c #58636B",
+"|.    c #57636A",
+"1.    c #3B5360",
+"2.    c #39424B",
+"3.    c #7897B3",
+"4.    c #A4B9CB",
+"5.    c #364853",
+"6.    c #AAC9E2",
+"7.    c #7091AA",
+"8.    c #6F8FA7",
+"9.    c #4A5359",
+"0.    c #97938C",
+"a.    c #DFDDDA",
+"b.    c #E3E1DE",
+"c.    c #EBEAE8",
+"d.    c #EAE9E7",
+"e.    c #CFCEC9",
+"f.    c #C9C6C0",
+"g.    c #9B968E",
+"h.    c #566168",
+"i.    c #4B657A",
+"j.    c #54738C",
+"k.    c #AAC6DD",
+"l.    c #34464E",
+"m.    c #AAC9E1",
+"n.    c #6C8EA6",
+"o.    c #6C8CA4",
+"p.    c #40474D",
+"q.    c #DAD8D3",
+"r.    c #E7E6E2",
+"s.    c #67655E",
+"t.    c #524F47",
+"u.    c #D9D7D4",
+"v.    c #C7C5BF",
+"w.    c #C0BCB5",
+"x.    c #B8B3AB",
+"y.    c #434C54",
+"z.    c #4D697F",
+"A.    c #4F6F84",
+"B.    c #B3CADC",
+"C.    c #313E49",
+"D.    c #A8C8E1",
+"E.    c #6B8DA6",
+"F.    c #728FA4",
+"G.    c #E2E1DD",
+"H.    c #F0EFEC",
+"I.    c #CDCAC6",
+"J.    c #C2BFB9",
+"K.    c #CAC6C0",
+"L.    c #DCDAD7",
+"M.    c #4B555D",
+"N.    c #4E697F",
+"O.    c #BACCDC",
+"P.    c #A4C4DE",
+"Q.    c #698BA3",
+"R.    c #708AA1",
+"S.    c #383E43",
+"T.    c #E0DEDA",
+"U.    c #514E46",
+"V.    c #4F4C44",
+"W.    c #C7C4BE",
+"X.    c #CBC8C2",
+"Y.    c #E1E0DC",
+"Z.    c #E9E8E6",
+"`.    c #475158",
+" +    c #4E6879",
+".+    c #4D6C80",
+"++    c #A3C3DB",
+"@+    c #383F43",
+"#+    c #778999",
+"$+    c #6E899E",
+"%+    c #65859C",
+"&+    c #33383C",
+"*+    c #D7D4D0",
+"=+    c #D6D4D0",
+"-+    c #4E4A43",
+";+    c #4D4942",
+">+    c #D1CEC9",
+",+    c #E6E5E2",
+"'+    c #EDECEA",
+")+    c #454F55",
+"!+    c #486173",
+"~+    c #4D6678",
+"{+    c #A1C1DA",
+"]+    c #373C40",
+"^+    c #0C0D0F",
+"/+    c #4E5E6A",
+"(+    c #5B6E7C",
+"_+    c #4F5B62",
+":+    c #A4A099",
+"<+    c #CCC9C3",
+"[+    c #D7D5D1",
+"}+    c #E4E2E0",
+"|+    c #DDDBD7",
+"1+    c #B8B5B0",
+"2+    c #3E474D",
+"3+    c #4A6176",
+"4+    c #4A6070",
+"5+    c #9BC3D8",
+"6+    c #363C41",
+"7+    c #28323E",
+"                                                ",
+"                                                ",
+"    . . . . . . . . . . . . . . . . . . .       ",
+"  . + @ # $ % & * = - ; > , > , ' ) ! ~ { .     ",
+"  . ] ^ / ( _ : < [ } | 1 2 3 4 5 6 7 8 9 .     ",
+"  . 0 a b c d e f g h i j k l m n o b p q .     ",
+"  . r s t u u u u u u u u u u u u u t v w .     ",
+"  . x y t u u u u u u u u u u u u u t v z .     ",
+"  . A B t C D D D D D D D D D D D E t F G .     ",
+"  . H I J u u u u u u u u u u u u u t F K .     ",
+"  . L M t u u u u u u u u u u u u u t N O .     ",
+"  . P Q t C D D D D D D D D D D D R t N S .     ",
+"  . T U V u u u u u u u u u u u u u t v W .     ",
+"  . X Y Z ` t t t t t  ...t t t t +.@.#.$..     ",
+"  . %.&.p v #.*.=.-.*.;.#.>.>.N *.,.v '.)..     ",
+"  . !.~.{.].^./.(._.:.<.[.}.|.(.1.2.3.4.5..     ",
+"  . 6.7.8.9.0.a.b.c.c.d.a.e.f.g.h.i.j.k.l..     ",
+"  . m.n.o.p.q.r.s.t.t.u.v.w.x.e.y.z.A.B.C..     ",
+"  . D.E.F.p.G.H.s.t.t.I.J.w.K.L.M.N.A.O.C..     ",
+"  . P.Q.R.S.T.c.U.V.V.W.w.X.Y.Z.`. +.+++@+.     ",
+"  . #+$+%+&+*+=+-+;+;+w.>+,+'+,+)+!+~+{+]+.     ",
+"    ^+/+(+_+:+w.x.<+<+[+}+d.|+1+2+3+4+5+6+.     ",
+"      . . . . . . . . . . . . . . . . 7+.       ",
+"                                                "};
diff --git a/xemacs-packages/gnus/etc/images/saveas.xpm b/xemacs-packages/gnus/etc/images/saveas.xpm
new file mode 100644 (file)
index 0000000..2830b06
--- /dev/null
@@ -0,0 +1,289 @@
+/* XPM */
+static char * saveas_xpm[] = {
+"24 24 262 2",
+"      c None",
+".     c #000000",
+"+     c #FBE73B",
+"@     c #F2B64D",
+"#     c #FCEB3D",
+"$     c #F7B544",
+"%     c #5D502C",
+"&     c #C3D7F4",
+"*     c #A9CDE5",
+"=     c #75757A",
+"-     c #EFC5BB",
+";     c #F1C8BE",
+">     c #F0C6BC",
+",     c #EEBCB2",
+"'     c #EEBEB5",
+")     c #EEC1B8",
+"!     c #EDBFB6",
+"~     c #E8B6AC",
+"{     c #FCE93B",
+"]     c #F7B545",
+"^     c #6C5F34",
+"/     c #434345",
+"(     c #92A7B9",
+"_     c #96B1C7",
+":     c #BBD6E8",
+"<     c #8AAAC5",
+"[     c #605F68",
+"}     c #E08D7E",
+"|     c #E0826E",
+"1     c #E0806E",
+"2     c #DC7A68",
+"3     c #DC8171",
+"4     c #DA7868",
+"5     c #D38072",
+"6     c #FAE43A",
+"7     c #F4B244",
+"8     c #615030",
+"9     c #783E35",
+"0     c #4D4C52",
+"a     c #7790A2",
+"b     c #526D82",
+"c     c #BAD5E9",
+"d     c #88A7C3",
+"e     c #686670",
+"f     c #C8817B",
+"g     c #CB7C74",
+"h     c #CB7A73",
+"i     c #CB7B73",
+"j     c #CC7C72",
+"k     c #CA7C72",
+"l     c #F9DF39",
+"m     c #F3AF42",
+"n     c #614F2F",
+"o     c #8F4941",
+"p     c #945554",
+"q     c #5B5A62",
+"r     c #7B97AE",
+"s     c #536F84",
+"t     c #B6D3E7",
+"u     c #87ABC1",
+"v     c #737373",
+"w     c #FFFFFF",
+"x     c #FEFEFE",
+"y     c #F9DC38",
+"z     c #EFB44D",
+"A     c #665A32",
+"B     c #BBBBBB",
+"C     c #CDCDCD",
+"D     c #E4E4E4",
+"E     c #6E6E6E",
+"F     c #819EB6",
+"G     c #526C80",
+"H     c #B9D3E7",
+"I     c #85A4BF",
+"J     c #F8D837",
+"K     c #F0A93F",
+"L     c #655930",
+"M     c #BABABA",
+"N     c #CCCCCC",
+"O     c #E5E5E5",
+"P     c #F7F7F7",
+"Q     c #727272",
+"R     c #83A0B8",
+"S     c #4F697C",
+"T     c #B9D3E6",
+"U     c #84A3BF",
+"V     c #CECECE",
+"W     c #F6D236",
+"X     c #EDA43E",
+"Y     c #5C5130",
+"Z     c #949494",
+"`     c #A3A3A3",
+" .    c #B7B7B7",
+"..    c #C6C6C6",
+"+.    c #BDBDBD",
+"@.    c #88A4BB",
+"#.    c #486276",
+"$.    c #B7D2E7",
+"%.    c #82A0BB",
+"&.    c #636363",
+"*.    c #FDFDFD",
+"=.    c #D7AE74",
+"-.    c #61562F",
+";.    c #465E70",
+">.    c #B5CAE5",
+",.    c #7FA2B9",
+"'.    c #4F4115",
+").    c #87A3BA",
+"!.    c #455C6D",
+"~.    c #AECCE5",
+"{.    c #7DA0B6",
+"].    c #CBCBCB",
+"^.    c #9B9B9B",
+"/.    c #9C9C9C",
+"(.    c #A7A7A7",
+"_.    c #B8B8B8",
+":.    c #C5C5C5",
+"<.    c #546069",
+"[.    c #B0D1E4",
+"}.    c #83A1B6",
+"|.    c #735B5B",
+"1.    c #F0F0F0",
+"2.    c #D9D9D9",
+"3.    c #D3D3D3",
+"4.    c #E1E1E1",
+"5.    c #EDEDED",
+"6.    c #F8F8F8",
+"7.    c #515C64",
+"8.    c #AACEE3",
+"9.    c #7B9BB2",
+"0.    c #7A8E9A",
+"a.    c #7A7A7A",
+"b.    c #707070",
+"c.    c #6C6C6C",
+"d.    c #6F6F6F",
+"e.    c #6A6E71",
+"f.    c #696969",
+"g.    c #6F777E",
+"h.    c #86A2B9",
+"i.    c #3A515D",
+"j.    c #A9C9E2",
+"k.    c #7494AF",
+"l.    c #7E9BB4",
+"m.    c #7D9AB3",
+"n.    c #7998B2",
+"o.    c #85A1B8",
+"p.    c #829FB7",
+"q.    c #8CA7BD",
+"r.    c #8AA5BB",
+"s.    c #364A59",
+"t.    c #ABC4E2",
+"u.    c #7294AD",
+"v.    c #6F90AC",
+"w.    c #7192AE",
+"x.    c #414A4E",
+"y.    c #424A51",
+"z.    c #525B63",
+"A.    c #626F79",
+"B.    c #5F6C76",
+"C.    c #5C6971",
+"D.    c #5A666F",
+"E.    c #58636B",
+"F.    c #57636A",
+"G.    c #3B5360",
+"H.    c #39424B",
+"I.    c #7897B3",
+"J.    c #A4B9CB",
+"K.    c #364853",
+"L.    c #AAC9E2",
+"M.    c #7091AA",
+"N.    c #6F8FA7",
+"O.    c #4A5359",
+"P.    c #97938C",
+"Q.    c #DFDDDA",
+"R.    c #E3E1DE",
+"S.    c #EBEAE8",
+"T.    c #EAE9E7",
+"U.    c #CFCEC9",
+"V.    c #C9C6C0",
+"W.    c #9B968E",
+"X.    c #566168",
+"Y.    c #4B657A",
+"Z.    c #54738C",
+"`.    c #AAC6DD",
+" +    c #34464E",
+".+    c #AAC9E1",
+"++    c #6C8EA6",
+"@+    c #6C8CA4",
+"#+    c #40474D",
+"$+    c #DAD8D3",
+"%+    c #E7E6E2",
+"&+    c #67655E",
+"*+    c #524F47",
+"=+    c #D9D7D4",
+"-+    c #C7C5BF",
+";+    c #C0BCB5",
+">+    c #B8B3AB",
+",+    c #434C54",
+"'+    c #4D697F",
+")+    c #4F6F84",
+"!+    c #B3CADC",
+"~+    c #313E49",
+"{+    c #A8C8E1",
+"]+    c #6B8DA6",
+"^+    c #728FA4",
+"/+    c #E2E1DD",
+"(+    c #F0EFEC",
+"_+    c #CDCAC6",
+":+    c #C2BFB9",
+"<+    c #CAC6C0",
+"[+    c #DCDAD7",
+"}+    c #4B555D",
+"|+    c #4E697F",
+"1+    c #BACCDC",
+"2+    c #A4C4DE",
+"3+    c #698BA3",
+"4+    c #708AA1",
+"5+    c #383E43",
+"6+    c #E0DEDA",
+"7+    c #514E46",
+"8+    c #4F4C44",
+"9+    c #C7C4BE",
+"0+    c #CBC8C2",
+"a+    c #E1E0DC",
+"b+    c #E9E8E6",
+"c+    c #475158",
+"d+    c #4E6879",
+"e+    c #4D6C80",
+"f+    c #A3C3DB",
+"g+    c #383F43",
+"h+    c #778999",
+"i+    c #6E899E",
+"j+    c #65859C",
+"k+    c #33383C",
+"l+    c #D7D4D0",
+"m+    c #D6D4D0",
+"n+    c #4E4A43",
+"o+    c #4D4942",
+"p+    c #D1CEC9",
+"q+    c #E6E5E2",
+"r+    c #EDECEA",
+"s+    c #454F55",
+"t+    c #486173",
+"u+    c #4D6678",
+"v+    c #A1C1DA",
+"w+    c #373C40",
+"x+    c #0C0D0F",
+"y+    c #4E5E6A",
+"z+    c #5B6E7C",
+"A+    c #4F5B62",
+"B+    c #A4A099",
+"C+    c #CCC9C3",
+"D+    c #D7D5D1",
+"E+    c #E4E2E0",
+"F+    c #DDDBD7",
+"G+    c #B8B5B0",
+"H+    c #3E474D",
+"I+    c #4A6176",
+"J+    c #4A6070",
+"K+    c #9BC3D8",
+"L+    c #363C41",
+"M+    c #28323E",
+"                                . .             ",
+"                              . + @ .           ",
+"    . . . . . . . . . . . . . # $ % . . .       ",
+"  . & * = - ; > , ' ) ! ~ . { ] ^ . / ( _ .     ",
+"  . : < [ } | 1 2 3 4 5 . 6 7 8 . 9 0 a b .     ",
+"  . c d e f g h i j k . l m n . o p q r s .     ",
+"  . t u v w w w w x . y z A . B C D E F G .     ",
+"  . H I v w w w x . J K L . M N O P Q R S .     ",
+"  . T U v V C N . W X Y . Z `  ...+.v @.#..     ",
+"  . $.%.&.w w *.. =.-.. M N D P *.w v @.;..     ",
+"  . >.,.v w x . '.. . M N D P *.w w v ).!..     ",
+"  . ~.{.v V ].. . ^./.(._...].C C :.v ).<..     ",
+"  . [.}.|.w *.1.2.3.4.5.6.x w w w w v R 7..     ",
+"  . 8.9.0.a.Q b.c.c.d.e.E v v v v f.g.h.i..     ",
+"  . j.k.F R h.F l.m.F n.h.o.o.).p.q.R r.s..     ",
+"  . t.u.v.w.x.y.z.A.B.C.D.E.F.z.G.H.I.J.K..     ",
+"  . L.M.N.O.P.Q.R.S.S.T.Q.U.V.W.X.Y.Z.`. +.     ",
+"  . .+++@+#+$+%+&+*+*+=+-+;+>+U.,+'+)+!+~+.     ",
+"  . {+]+^+#+/+(+&+*+*+_+:+;+<+[+}+|+)+1+~+.     ",
+"  . 2+3+4+5+6+S.7+8+8+9+;+0+a+b+c+d+e+f+g+.     ",
+"  . h+i+j+k+l+m+n+o+o+;+p+q+r+q+s+t+u+v+w+.     ",
+"    x+y+z+A+B+;+>+C+C+D+E+T.F+G+H+I+J+K+L+.     ",
+"      . . . . . . . . . . . . . . . . M+.       ",
+"                                                "};
diff --git a/xemacs-packages/gnus/etc/images/search.xpm b/xemacs-packages/gnus/etc/images/search.xpm
new file mode 100644 (file)
index 0000000..ad63005
--- /dev/null
@@ -0,0 +1,234 @@
+/* XPM */
+static char * search_xpm[] = {
+"24 24 207 2",
+"      c None",
+".     c #000000",
+"+     c #D3D3D3",
+"@     c #F6F6F6",
+"#     c #FFFFFF",
+"$     c #F9F9F9",
+"%     c #DADADA",
+"&     c #585858",
+"*     c #C7C7C7",
+"=     c #D1D1D1",
+"-     c #D6D6D6",
+";     c #FEFEFE",
+">     c #FDFDFD",
+",     c #C0C0C0",
+"'     c #E1E1E1",
+")     c #F0F0F0",
+"!     c #9B9B9B",
+"~     c #FCFCFB",
+"{     c #FBFBFB",
+"]     c #AFAFAE",
+"^     c #E9E9E9",
+"/     c #DFDFDF",
+"(     c #8F8F8F",
+"_     c #FAFAF9",
+":     c #F9F9F8",
+"<     c #A4A4A3",
+"[     c #F4F4F4",
+"}     c #CFCFCF",
+"|     c #A2A2A2",
+"1     c #B8B8B8",
+"2     c #47473F",
+"3     c #0A0A09",
+"4     c #4B4B43",
+"5     c #B4B4B3",
+"6     c #F7F6F5",
+"7     c #9E9E9E",
+"8     c #A9A9A8",
+"9     c #34342E",
+"0     c #9D9D8D",
+"a     c #CFCFB9",
+"b     c #C4C4AF",
+"c     c #8D8D7F",
+"d     c #353530",
+"e     c #ACACAA",
+"f     c #F1F0EF",
+"g     c #DEDDDC",
+"h     c #D3D2D0",
+"i     c #B7B7B5",
+"j     c #9F9E9D",
+"k     c #706F6F",
+"l     c #65625A",
+"m     c #46463F",
+"n     c #9C9C8C",
+"o     c #E2E2D0",
+"p     c #EDEDE7",
+"q     c #C0C0AC",
+"r     c #B2B29F",
+"s     c #828274",
+"t     c #4C4C44",
+"u     c #E4E4E2",
+"v     c #E1E1DF",
+"w     c #DAD9D7",
+"x     c #D8D8D6",
+"y     c #CDCCCA",
+"z     c #AFAEAC",
+"A     c #88847B",
+"B     c #F8F8F7",
+"C     c #090908",
+"D     c #D5D5BF",
+"E     c #FBFBFA",
+"F     c #C3C3AE",
+"G     c #B5B5A2",
+"H     c #A6A695",
+"I     c #9C9C8F",
+"J     c #080807",
+"K     c #CFCFCD",
+"L     c #E3E2E0",
+"M     c #ECEBE9",
+"N     c #E9E8E6",
+"O     c #D5D4D3",
+"P     c #C4C3C2",
+"Q     c #8F8A81",
+"R     c #F6F5F4",
+"S     c #F3F3F1",
+"T     c #090909",
+"U     c #CACAB5",
+"V     c #DDDDD0",
+"W     c #B7B7A4",
+"X     c #AAAA98",
+"Y     c #9B9B8B",
+"Z     c #AEAEA3",
+"`     c #BBBAB9",
+" .    c #E8E7E5",
+"..    c #E5E4E2",
+"+.    c #E4E3E0",
+"@.    c #D2D1CE",
+"#.    c #8D887E",
+"$.    c #F4F3F2",
+"%.    c #F0EFEE",
+"&.    c #474740",
+"*.    c #929283",
+"=.    c #BABAA7",
+"-.    c #ADAD9B",
+";.    c #9F9F8E",
+">.    c #ACACA1",
+",.    c #CFCFCB",
+"'.    c #4C4C45",
+").    c #B3B2B1",
+"!.    c #E2E1DE",
+"~.    c #E1DFDC",
+"{.    c #979288",
+"].    c #949493",
+"^.    c #34342F",
+"/.    c #878779",
+"(.    c #A0A090",
+"_.    c #AEAEA2",
+":.    c #C3C3BE",
+"<.    c #010101",
+"[.    c #B1B0AF",
+"}.    c #D2D1CF",
+"|.    c #A49E93",
+"1.    c #F0F0EE",
+"2.    c #EDEDEB",
+"3.    c #DDDDDB",
+"4.    c #898988",
+"5.    c #414141",
+"6.    c #737271",
+"7.    c #A4A3A1",
+"8.    c #DFDEDB",
+"9.    c #E2E0DD",
+"0.    c #E1E0DC",
+"a.    c #E0DFDB",
+"b.    c #A19C90",
+"c.    c #E1E0DE",
+"d.    c #CBCAC9",
+"e.    c #B2B1B0",
+"f.    c #A3A2A1",
+"g.    c #9D9C9A",
+"h.    c #9E9D9C",
+"i.    c #9F9F9D",
+"j.    c #ABAAA7",
+"k.    c #DCDBD7",
+"l.    c #DEDDD9",
+"m.    c #DDDCD8",
+"n.    c #A19B90",
+"o.    c #EBEAE8",
+"p.    c #E6E5E3",
+"q.    c #C8C7C4",
+"r.    c #B6B6B3",
+"s.    c #B0AFAD",
+"t.    c #B3B2B0",
+"u.    c #747371",
+"v.    c #9D9C99",
+"w.    c #DAD9D5",
+"x.    c #E7E6E3",
+"y.    c #E6E5E2",
+"z.    c #E3E2DF",
+"A.    c #DBDAD7",
+"B.    c #D4D3D0",
+"C.    c #D0CFCB",
+"D.    c #D1CFCC",
+"E.    c #D1D0CC",
+"F.    c #C9C8C4",
+"G.    c #6B6B69",
+"H.    c #CECDC9",
+"I.    c #D6D4D0",
+"J.    c #9F998D",
+"K.    c #E3E2DE",
+"L.    c #E4E2DF",
+"M.    c #DFDEDA",
+"N.    c #D5D4D0",
+"O.    c #C0BFBC",
+"P.    c #7B7A78",
+"Q.    c #BCBAB6",
+"R.    c #CECCC8",
+"S.    c #9D978C",
+"T.    c #EDEDED",
+"U.    c #E1E0DD",
+"V.    c #E2E1DD",
+"W.    c #DBDAD6",
+"X.    c #BBB9B6",
+"Y.    c #A6A4A1",
+"Z.    c #9E9C99",
+"`.    c #ACABA7",
+" +    c #C7C5C2",
+".+    c #9B9589",
+"++    c #E1DFDB",
+"@+    c #E0DEDA",
+"#+    c #DEDCD8",
+"$+    c #DAD8D4",
+"%+    c #BDBCB8",
+"&+    c #ACABA8",
+"*+    c #B2B1AD",
+"=+    c #C6C4C0",
+"-+    c #999388",
+";+    c #999891",
+">+    c #A39E92",
+",+    c #A39D92",
+"'+    c #A39D91",
+")+    c #A29C90",
+"!+    c #A19B8F",
+"~+    c #9D978B",
+"{+    c #989286",
+"]+    c #918C82",
+"^+    c #938D83",
+"/+    c #979286",
+"(+    c #666258",
+"                                                ",
+"      . . . . . . . . . . . . .                 ",
+"    . + @ # # # # # # # # $ % & .               ",
+"    . @ # # # # # # # # # # * = - .             ",
+"    . # # # # # # # ; # ; > , ' ) ! .           ",
+"    . # # # # # ; > ~ > ~ { ] ^ # / ( .         ",
+"    . # # # ; > ~ { _ { _ : < ) # [ } | .       ",
+"    . # ; > ~ 1 2 3 3 4 5 6 7 . . . . . . .     ",
+"    . # ~ { 8 9 0 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 6 C D E F G H I J K L M N O P Q .     ",
+"    . # R S T U V W X Y Z 3 ` w  ...+.@.#..     ",
+"    . # $.%.&.*.=.-.;.>.,.'.).h !.+.!.~.{..     ",
+"    . # $.%.].^./.(._.:.<.<.[.}.!.+.!.~.|..     ",
+"    . # 1.2.3.4.4 3 3 5.6.<.<.7.8.9.0.a.b..     ",
+"    . # 2.M c.d.e.f.g.h.i.<.<.<.j.k.l.m.n..     ",
+"    . # o.N p.w q.r.z s.t.u.. <.<.v.w.k.n..     ",
+"    . # x.y.y.z.A.B.C.D.E.F.G.<.<.<.H.I.J..     ",
+"    . $ +.z.K.L.K.a.a.M.M.N.O.P.<.<.Q.R.S..     ",
+"    . T.U.~.0.a.V.a.0.a.0.W.E.X.Y.Z.`. +.+.     ",
+"    . = ++@+M.l.a.l.@+l.@+#+$+R.%+&+*+=+-+.     ",
+"    . ;+>+|.,+'+,+b.)+b.)+!+n.~+{+]+^+/+(+.     ",
+"      . . . . . . . . . . . . . . . . . .       ",
+"                                                "};
diff --git a/xemacs-packages/gnus/etc/images/separator.xpm b/xemacs-packages/gnus/etc/images/separator.xpm
new file mode 100644 (file)
index 0000000..0c518fa
--- /dev/null
@@ -0,0 +1,30 @@
+/* XPM */
+static char * separator_xpm[] = {
+"2 24 3 1",
+"      c None",
+".     c #DBD3CB",
+"+     c #FCFBFA",
+"  ",
+"  ",
+"  ",
+".+",
+".+",
+".+",
+".+",
+".+",
+".+",
+".+",
+".+",
+".+",
+".+",
+".+",
+".+",
+".+",
+".+",
+".+",
+".+",
+".+",
+".+",
+"  ",
+"  ",
+"  "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/README b/xemacs-packages/gnus/etc/images/smilies/README
new file mode 100644 (file)
index 0000000..39cfaca
--- /dev/null
@@ -0,0 +1,7 @@
+Files: blink.pbm blink.xpm braindamaged.xpm cry.xpm dead.xpm evil.xpm
+       forced.xpm frown.pbm frown.xpm grin.xpm indifferent.xpm sad.pbm
+       sad.xpm smile.pbm smile.xpm wry.pbm wry.xpm
+Authors: Reiner Steib, Simon Josefsson, Kai Grossjohann, Alex
+         Schroeder, Oliver Scholz, Per Abrahamsen, Kim F. Storm.
+Copyright (C) 1999-2016 Free Software Foundation, Inc.
+License: GNU General Public License version 3 or later (see COPYING)
diff --git a/xemacs-packages/gnus/etc/images/smilies/blink.pbm b/xemacs-packages/gnus/etc/images/smilies/blink.pbm
new file mode 100644 (file)
index 0000000..6c7531b
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/smilies/blink.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/smilies/blink.xpm b/xemacs-packages/gnus/etc/images/smilies/blink.xpm
new file mode 100644 (file)
index 0000000..5035122
--- /dev/null
@@ -0,0 +1,20 @@
+/* XPM */
+static char * blink_xpm[] = {
+"13 14 3 1",
+"      c None",
+".     c #000000",
+"+     c #FFDD00",
+"   .......   ",
+"  ..+++++..  ",
+" .+++++++++. ",
+".+++++++++++.",
+".+++++++..++.",
+".+++++++..++.",
+".++...++++++.",
+".+++++++++++.",
+".++++++++.++.",
+".++.+++++.++.",
+".+++.....+++.",
+" .+++++++++. ",
+"  ..+++++..  ",
+"   .......   "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/braindamaged.xpm b/xemacs-packages/gnus/etc/images/smilies/braindamaged.xpm
new file mode 100644 (file)
index 0000000..25bd3e7
--- /dev/null
@@ -0,0 +1,20 @@
+/* XPM */
+static char * mad_xpm[] = {
+"13 14 3 1",
+"      c None",
+".     c #000000",
+"+     c #FFDD00",
+"   .......   ",
+"  ..+++++..  ",
+" .+++++++++. ",
+".++...++++++.",
+".++.+.+...++.",
+".++...+.+.++.",
+".++++++...++.",
+".+.+++++++.+.",
+".+.+++++++.+.",
+".++.+++++.++.",
+".+++.....+++.",
+" .+++++++++. ",
+"  ..+++++..  ",
+"   .......   "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/cry.xpm b/xemacs-packages/gnus/etc/images/smilies/cry.xpm
new file mode 100644 (file)
index 0000000..8d8558d
--- /dev/null
@@ -0,0 +1,20 @@
+/* XPM */
+static char * cry_xpm[] = {
+"13 14 3 1",
+"      c None",
+".     c #000000",
+"+     c #FFDD00",
+"   .......   ",
+"  ..+++++..  ",
+" .+++++++++. ",
+".+++++++++++.",
+".++..+++..++.",
+".++++++++.++.",
+".+++++++.+.+.",
+".+++++++.+.+.",
+".++++++++..+.",
+".+++.....+++.",
+".++.+++++.++.",
+" .+++++++++. ",
+"  ..+++++..  ",
+"   .......   "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/dead.xpm b/xemacs-packages/gnus/etc/images/smilies/dead.xpm
new file mode 100644 (file)
index 0000000..56463a7
--- /dev/null
@@ -0,0 +1,20 @@
+/* XPM */
+static char * dead_xpm[] = {
+"13 14 3 1",
+"      c None",
+".     c #000000",
+"+     c #FFDD00",
+"   .......   ",
+"  ..+++++..  ",
+" .+++++++++. ",
+".+++++++++++.",
+".++.+.+.+.++.",
+".+++.+++.+++.",
+".++.+.+.+.++.",
+".+++++++++++.",
+".+++++++++++.",
+".+.+++++++.+.",
+".++.......++.",
+" .+++++++++. ",
+"  ..+++++..  ",
+"   .......   "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/evil.xpm b/xemacs-packages/gnus/etc/images/smilies/evil.xpm
new file mode 100644 (file)
index 0000000..c364ac3
--- /dev/null
@@ -0,0 +1,20 @@
+/* XPM */
+static char * diabolic_xpm[] = {
+"13 14 3 1",
+"      c None",
+".     c #000000",
+"+     c #FFDD00",
+"   .......   ",
+"  ..+++++..  ",
+" .+++++++++. ",
+".++.+++++.++.",
+".++..+++..++.",
+".++...+...++.",
+".+++++++++++.",
+".+.+++++++.+.",
+".++.+++++.++.",
+".+++.+++.+++.",
+".++++...++++.",
+" .+++++++++. ",
+"  ..+++++..  ",
+"   .......   "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/forced.xpm b/xemacs-packages/gnus/etc/images/smilies/forced.xpm
new file mode 100644 (file)
index 0000000..43ba8d2
--- /dev/null
@@ -0,0 +1,20 @@
+/* XPM */
+static char * forced_xpm[] = {
+"13 14 3 1",
+"      c None",
+".     c #000000",
+"+     c #FFDD00",
+"   .......   ",
+"  ..+++++..  ",
+" .+++++++++. ",
+".+++++++++++.",
+".++..+++..++.",
+".++..+++..++.",
+".+++++++++++.",
+".+++++++++++.",
+".+.+++++++.+.",
+".+.+++++++.+.",
+".+.........+.",
+".+++++++++++.",
+" ...+++++... ",
+"   .......   "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/frown.pbm b/xemacs-packages/gnus/etc/images/smilies/frown.pbm
new file mode 100644 (file)
index 0000000..f51ea4f
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/smilies/frown.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/smilies/frown.xpm b/xemacs-packages/gnus/etc/images/smilies/frown.xpm
new file mode 100644 (file)
index 0000000..25ca99d
--- /dev/null
@@ -0,0 +1,20 @@
+/* XPM */
+static char * frown_xpm[] = {
+"13 14 3 1",
+"      c None",
+".     c #000000",
+"+     c #FFDD00",
+"   .......   ",
+"  ..+++++..  ",
+" .+++++++++. ",
+".++..+++..++.",
+".++++.+.++++.",
+".+...+++...+.",
+".+...+++...+.",
+".+++++++++++.",
+".+++.....+++.",
+".++.+++++.++.",
+".++.+++++.++.",
+" .+++++++++. ",
+"  ..+++++..  ",
+"   .......   "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/grayscale/README b/xemacs-packages/gnus/etc/images/smilies/grayscale/README
new file mode 100644 (file)
index 0000000..b649be5
--- /dev/null
@@ -0,0 +1,6 @@
+Files: blink.xpm braindamaged.xpm cry.xpm dead.xpm evil.xpm forced.xpm
+       frown.xpm grin.xpm indifferent.xpm reverse-smile.xpm sad.xpm
+       smile.xpm wry.xpm 
+Author: Adam Sjøgren
+Copyright (C) 2007-2016 Free Software Foundation, Inc.
+License: GNU General Public License version 3 or later (see COPYING)
diff --git a/xemacs-packages/gnus/etc/images/smilies/grayscale/blink.xpm b/xemacs-packages/gnus/etc/images/smilies/grayscale/blink.xpm
new file mode 100644 (file)
index 0000000..eec7209
--- /dev/null
@@ -0,0 +1,24 @@
+/* XPM */
+static char * blink_xpm[] = {
+"14 14 7 1",
+"      c None",
+".     c #484848",
+"+     c #000000",
+"@     c #6E6E6E",
+"#     c #515151",
+"$     c #ABABAB",
+"%     c #737373",
+"              ",
+"              ",
+"         .    ",
+"         +    ",
+"  @#$$#  +    ",
+"    ++   +    ",
+"              ",
+"  +        +  ",
+"  $+      +$  ",
+"   %+    +%   ",
+"    %++++%    ",
+"     $$$$     ",
+"              ",
+"              "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/grayscale/braindamaged.xpm b/xemacs-packages/gnus/etc/images/smilies/grayscale/braindamaged.xpm
new file mode 100644 (file)
index 0000000..cd47b32
--- /dev/null
@@ -0,0 +1,23 @@
+/* XPM */
+static char * braindamaged_xpm[] = {
+"14 14 6 1",
+"      c None",
+".     c #ABABAB",
+"+     c #000000",
+"@     c #515151",
+"#     c #171717",
+"$     c #737373",
+"              ",
+"              ",
+"   .++..++.   ",
+"   +@.++.@+   ",
+"   +.@#@@.+   ",
+"   +@.#@.@+   ",
+"   .++. ++.   ",
+"  +        +  ",
+"  .+      +.  ",
+"   $+    +$   ",
+"    $++++$    ",
+"     ....     ",
+"              ",
+"              "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/grayscale/cry.xpm b/xemacs-packages/gnus/etc/images/smilies/grayscale/cry.xpm
new file mode 100644 (file)
index 0000000..78bf666
--- /dev/null
@@ -0,0 +1,23 @@
+/* XPM */
+static char * cry_xpm[] = {
+"14 14 6 1",
+"      c None",
+".     c #484848",
+"+     c #000000",
+"@     c #ABABAB",
+"#     c #515151",
+"$     c #6E6E6E",
+"              ",
+"              ",
+"         .    ",
+"    ..  .+.   ",
+"   +++. +.+   ",
+"        +@+   ",
+"        @+#   ",
+"      @@      ",
+"    $++++$    ",
+"   .+@  @+.   ",
+"  @+@    @+@  ",
+"   @      @   ",
+"              ",
+"              "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/grayscale/dead.xpm b/xemacs-packages/gnus/etc/images/smilies/grayscale/dead.xpm
new file mode 100644 (file)
index 0000000..9be9883
--- /dev/null
@@ -0,0 +1,21 @@
+/* XPM */
+static char * dead_xpm[] = {
+"14 14 4 1",
+"      c None",
+".     c #737373",
+"+     c #ABABAB",
+"@     c #000000",
+"              ",
+"              ",
+"  .+ +. + +.  ",
+"  +@+@++@+@+  ",
+"   +@    @+   ",
+"  +@+@  @+@+  ",
+"   + +. + +   ",
+"              ",
+"  +@      @+  ",
+"   .@    @.   ",
+"    .@@@@.    ",
+"     ++++     ",
+"              ",
+"              "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/grayscale/evil.xpm b/xemacs-packages/gnus/etc/images/smilies/grayscale/evil.xpm
new file mode 100644 (file)
index 0000000..e358cf8
--- /dev/null
@@ -0,0 +1,23 @@
+/* XPM */
+static char * evil_xpm[] = {
+"14 14 6 1",
+"      c None",
+".     c #6E6E6E",
+"+     c #484848",
+"@     c #ABABAB",
+"#     c #000000",
+"$     c #737373",
+"              ",
+"              ",
+"   .+    +.   ",
+"   @#    #@   ",
+"    #+ @+#    ",
+"    #+ @+#    ",
+"              ",
+"  #        #  ",
+"  @#      #@  ",
+"   $#    #$   ",
+"    $####$    ",
+"     @@@@     ",
+"              ",
+"              "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/grayscale/forced.xpm b/xemacs-packages/gnus/etc/images/smilies/grayscale/forced.xpm
new file mode 100644 (file)
index 0000000..0950845
--- /dev/null
@@ -0,0 +1,23 @@
+/* XPM */
+static char * forced_xpm[] = {
+"14 14 6 1",
+"      c None",
+".     c #484848",
+"+     c #000000",
+"@     c #6E6E6E",
+"#     c #ABABAB",
+"$     c #171717",
+"              ",
+"              ",
+"    .    .    ",
+"    +    +    ",
+"    +    +    ",
+"    +    +    ",
+"              ",
+"  @        @  ",
+"  +#      #+  ",
+"  @@#    #@@  ",
+"  #$++++++$#  ",
+"   ########   ",
+"              ",
+"              "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/grayscale/frown.xpm b/xemacs-packages/gnus/etc/images/smilies/grayscale/frown.xpm
new file mode 100644 (file)
index 0000000..b513f4c
--- /dev/null
@@ -0,0 +1,22 @@
+/* XPM */
+static char * frown_xpm[] = {
+"14 14 5 1",
+"      c None",
+".     c #6E6E6E",
+"+     c #484848",
+"@     c #ABABAB",
+"#     c #000000",
+"              ",
+"              ",
+"   .+    +.   ",
+"   @#    #@   ",
+"    #+ @+#    ",
+"    #+@@+#    ",
+"              ",
+"      @@      ",
+"    .####.    ",
+"   +#@  @#+   ",
+"  @#@    @#@  ",
+"   +      +   ",
+"              ",
+"              "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/grayscale/grin.xpm b/xemacs-packages/gnus/etc/images/smilies/grayscale/grin.xpm
new file mode 100644 (file)
index 0000000..f6e4588
--- /dev/null
@@ -0,0 +1,25 @@
+/* XPM */
+static char * grin_xpm[] = {
+"14 14 8 1",
+"      c None",
+".     c #484848",
+"+     c #000000",
+"@     c #515151",
+"#     c #6E6E6E",
+"$     c #ABABAB",
+"%     c #FFFFFF",
+"&     c #737373",
+"              ",
+"              ",
+"    .    .    ",
+"    +    +    ",
+"    +    +    ",
+"    +    +    ",
+"              ",
+"  ++@@##@@++  ",
+"  $+%%%%%%+$  ",
+"   &+%%%%+&   ",
+"    &++++&    ",
+"     $$$$     ",
+"              ",
+"              "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/grayscale/indifferent.xpm b/xemacs-packages/gnus/etc/images/smilies/grayscale/indifferent.xpm
new file mode 100644 (file)
index 0000000..1e4f69e
--- /dev/null
@@ -0,0 +1,23 @@
+/* XPM */
+static char * indifferent_xpm[] = {
+"14 14 6 1",
+"      c None",
+".     c #484848",
+"+     c #000000",
+"@     c #515151",
+"#     c #ABABAB",
+"$     c #6E6E6E",
+"              ",
+"              ",
+"    .    .    ",
+"    +    +    ",
+"    +    +    ",
+"    +    +    ",
+"              ",
+" @         #@ ",
+"#+$+$   $  +  ",
+"$ +#+$#++$+$  ",
+"  $  ++# ++   ",
+"      +       ",
+"              ",
+"              "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/grayscale/reverse-smile.xpm b/xemacs-packages/gnus/etc/images/smilies/grayscale/reverse-smile.xpm
new file mode 100644 (file)
index 0000000..a62eab0
--- /dev/null
@@ -0,0 +1,22 @@
+/* XPM */
+static char * reverse_smile_xpm[] = {
+"14 14 5 1",
+"      c None",
+".     c #ABABAB",
+"+     c #737373",
+"@     c #000000",
+"#     c #484848",
+"              ",
+"              ",
+"     ....     ",
+"    +@@@@+    ",
+"   +@    @+   ",
+"  .@      @.  ",
+"  @        @  ",
+"              ",
+"    @    @    ",
+"    @    @    ",
+"    @    @    ",
+"    #    #    ",
+"              ",
+"              "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/grayscale/sad.xpm b/xemacs-packages/gnus/etc/images/smilies/grayscale/sad.xpm
new file mode 100644 (file)
index 0000000..3addb6b
--- /dev/null
@@ -0,0 +1,22 @@
+/* XPM */
+static char * sad_xpm[] = {
+"14 14 5 1",
+"      c None",
+".     c #484848",
+"+     c #000000",
+"@     c #ABABAB",
+"#     c #6E6E6E",
+"              ",
+"              ",
+"    .    .    ",
+"    +    +    ",
+"    +    +    ",
+"    +    +    ",
+"              ",
+"     @@@@     ",
+"    #++++#    ",
+"   .+@  @+.   ",
+"  @+@    @+@  ",
+"   .      .   ",
+"              ",
+"              "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/grayscale/smile.xpm b/xemacs-packages/gnus/etc/images/smilies/grayscale/smile.xpm
new file mode 100644 (file)
index 0000000..463785e
--- /dev/null
@@ -0,0 +1,22 @@
+/* XPM */
+static char * smile_xpm[] = {
+"14 14 5 1",
+"      c None",
+".     c #484848",
+"+     c #000000",
+"@     c #ABABAB",
+"#     c #737373",
+"              ",
+"              ",
+"    .    .    ",
+"    +    +    ",
+"    +    +    ",
+"    +    +    ",
+"              ",
+"  +        +  ",
+"  @+      +@  ",
+"   #+    +#   ",
+"    #++++#    ",
+"     @@@@     ",
+"              ",
+"              "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/grayscale/wry.xpm b/xemacs-packages/gnus/etc/images/smilies/grayscale/wry.xpm
new file mode 100644 (file)
index 0000000..79e2979
--- /dev/null
@@ -0,0 +1,23 @@
+/* XPM */
+static char * wry_xpm[] = {
+"14 14 6 1",
+"      c None",
+".     c #484848",
+"+     c #000000",
+"@     c #515151",
+"#     c #ABABAB",
+"$     c #6E6E6E",
+"              ",
+"              ",
+"    .    .    ",
+"    +    +    ",
+"    +    +    ",
+"    +    +    ",
+"              ",
+"          @   ",
+"    ##   $@   ",
+"   #++++++#   ",
+"   @$   ##    ",
+"   @          ",
+"              ",
+"              "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/grin.xpm b/xemacs-packages/gnus/etc/images/smilies/grin.xpm
new file mode 100644 (file)
index 0000000..292cb11
--- /dev/null
@@ -0,0 +1,21 @@
+/* XPM */
+static char * grin_xpm[] = {
+"13 14 4 1",
+"      c None",
+".     c #000000",
+"+     c #FFDD00",
+"@     c #FFFFFF",
+"   .......   ",
+"  ..+++++..  ",
+" .+++++++++. ",
+".+++++++++++.",
+".++..+++..++.",
+".++..+++..++.",
+".+++++++++++.",
+".+.........+.",
+".+.@@@@@@@.+.",
+".++.@@@@@.++.",
+".+++.....+++.",
+" .+++++++++. ",
+"  ..+++++..  ",
+"   .......   "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/indifferent.xpm b/xemacs-packages/gnus/etc/images/smilies/indifferent.xpm
new file mode 100644 (file)
index 0000000..6395238
--- /dev/null
@@ -0,0 +1,20 @@
+/* XPM */
+static char * indifferent_xpm[] = {
+"13 14 3 1",
+"      c None",
+".     c #000000",
+"+     c #FFDD00",
+"   .......   ",
+"  ..+++++..  ",
+" .+++++++++. ",
+".+++++++++++.",
+".++..+++..++.",
+".++..+++..++.",
+".+++++++++++.",
+".+++++++++++.",
+".+++++++++++.",
+".++.......++.",
+".+++++++++++.",
+" .+++++++++. ",
+"  ..+++++..  ",
+"   .......   "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/medium/README b/xemacs-packages/gnus/etc/images/smilies/medium/README
new file mode 100644 (file)
index 0000000..b649be5
--- /dev/null
@@ -0,0 +1,6 @@
+Files: blink.xpm braindamaged.xpm cry.xpm dead.xpm evil.xpm forced.xpm
+       frown.xpm grin.xpm indifferent.xpm reverse-smile.xpm sad.xpm
+       smile.xpm wry.xpm 
+Author: Adam Sjøgren
+Copyright (C) 2007-2016 Free Software Foundation, Inc.
+License: GNU General Public License version 3 or later (see COPYING)
diff --git a/xemacs-packages/gnus/etc/images/smilies/medium/blink.xpm b/xemacs-packages/gnus/etc/images/smilies/medium/blink.xpm
new file mode 100644 (file)
index 0000000..9bd48f7
--- /dev/null
@@ -0,0 +1,29 @@
+/* XPM */
+static char * blink_xpm[] = {
+"16 16 10 1",
+"      c None",
+".     c #000000",
+"+     c #1D1900",
+"@     c #887500",
+"#     c #D3B600",
+"$     c #FAD800",
+"%     c #645600",
+"&     c #FFDD00",
+"*     c #594D00",
+"=     c #8F7B00",
+"     ......     ",
+"   .+@#$$#@+.   ",
+"  .%$&&&&&&$%.  ",
+" .%&&&&&&&*&&%. ",
+" +$&&&&&&&.&&$+ ",
+".@&@%##%&&.&&&@.",
+".#&&&..&&&.&&&#.",
+".$&&&&&&&&&&&&$.",
+".$&.&&&&&&&&.&$.",
+".#&#.&&&&&&.#&#.",
+".@&&=.&&&&.=&&@.",
+" +$&&=....=&&$+ ",
+" .%&&&&&&&&&&%. ",
+"  .%$&&&&&&$%.  ",
+"   .+@#$$#@+.   ",
+"     ......     "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/medium/braindamaged.xpm b/xemacs-packages/gnus/etc/images/smilies/medium/braindamaged.xpm
new file mode 100644 (file)
index 0000000..e42259d
--- /dev/null
@@ -0,0 +1,28 @@
+/* XPM */
+static char * braindamaged_xpm[] = {
+"16 16 9 1",
+"      c None",
+".     c #000000",
+"+     c #1D1900",
+"@     c #887500",
+"#     c #D3B600",
+"$     c #FAD800",
+"%     c #645600",
+"&     c #FFDD00",
+"*     c #8F7B00",
+"     ......     ",
+"   .+@#$$#@+.   ",
+"  .%$&&&&&&$%.  ",
+" .%&#..##..#&%. ",
+" +$&.%#..#%.&$+ ",
+".@&&.#%+%%#.&&@.",
+".#&&.%#+%#%.&&#.",
+".$&&#..#&..#&&$.",
+".$&.&&&&&&&&.&$.",
+".#&#.&&&&&&.#&#.",
+".@&&*.&&&&.*&&@.",
+" +$&&*....*&&$+ ",
+" .%&&&&&&&&&&%. ",
+"  .%$&&&&&&$%.  ",
+"   .+@#$$#@+.   ",
+"     ......     "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/medium/cry.xpm b/xemacs-packages/gnus/etc/images/smilies/medium/cry.xpm
new file mode 100644 (file)
index 0000000..e7358ad
--- /dev/null
@@ -0,0 +1,28 @@
+/* XPM */
+static char * cry_xpm[] = {
+"16 16 9 1",
+"      c None",
+".     c #000000",
+"+     c #1D1900",
+"@     c #887500",
+"#     c #D3B600",
+"$     c #FAD800",
+"%     c #645600",
+"&     c #FFDD00",
+"*     c #594D00",
+"     ......     ",
+"   .+@#$$#@+.   ",
+"  .%$&&&&&&$%.  ",
+" .%&&&&&&&*&&%. ",
+" +$&&**&&*.*&$+ ",
+".@&&...*&.*.&&@.",
+".#&&&&&&&.#.&&#.",
+".$&&&&&&&#.%&&$.",
+".$&&&&&&&&&&&&$.",
+".#&&&@....@&&&#.",
+".@&&*.#&&#.*&&@.",
+" +$#.#&&&&#.#$+ ",
+" .%&*&&&&&&*&%. ",
+"  .%$&&&&&&$%.  ",
+"   .+@#$$#@+.   ",
+"     ......     "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/medium/dead.xpm b/xemacs-packages/gnus/etc/images/smilies/medium/dead.xpm
new file mode 100644 (file)
index 0000000..1d8fe12
--- /dev/null
@@ -0,0 +1,28 @@
+/* XPM */
+static char * dead_xpm[] = {
+"16 16 9 1",
+"      c None",
+".     c #000000",
+"+     c #1D1900",
+"@     c #887500",
+"#     c #D3B600",
+"$     c #FAD800",
+"%     c #645600",
+"&     c #FFDD00",
+"*     c #8F7B00",
+"     ......     ",
+"   .+@#$$#@+.   ",
+"  .%$&&&&&&$%.  ",
+" .%*#&#*$#&#*%. ",
+" +$#.#.##.#.#$+ ",
+".@&&#.$&&$.#&&@.",
+".#&#.#.$$.#.#&#.",
+".$&*#&#*$#&#*&$.",
+".$&.&&&&&&&&.&$.",
+".#&#.&&&&&&.#&#.",
+".@&&*.&&&&.*&&@.",
+" +$&&*....*&&$+ ",
+" .%&&&&&&&&&&%. ",
+"  .%$&&&&&&$%.  ",
+"   .+@#$$#@+.   ",
+"     ......     "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/medium/evil.xpm b/xemacs-packages/gnus/etc/images/smilies/medium/evil.xpm
new file mode 100644 (file)
index 0000000..b7a18f8
--- /dev/null
@@ -0,0 +1,29 @@
+/* XPM */
+static char * evil_xpm[] = {
+"16 16 10 1",
+"      c None",
+".     c #000000",
+"+     c #1D1900",
+"@     c #887500",
+"#     c #D3B600",
+"$     c #FAD800",
+"%     c #645600",
+"&     c #FFDD00",
+"*     c #594D00",
+"=     c #8F7B00",
+"     ......     ",
+"   .+@#$$#@+.   ",
+"  .%$&&&&&&$%.  ",
+" .%&@*&&&&*@&%. ",
+" +$&#.&&&&.#&$+ ",
+".@&&&.*&#*.&&&@.",
+".#&&&.*##*.&&&#.",
+".$&&&&&&&&&&&&$.",
+".$&.&&&&&&&&.&$.",
+".#&#.&&&&&&.#&#.",
+".@&&=.&&&&.=&&@.",
+" +$&&=....=&&$+ ",
+" .%&&&&&&&&&&%. ",
+"  .%$&&&&&&$%.  ",
+"   .+@#$$#@+.   ",
+"     ......     "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/medium/forced.xpm b/xemacs-packages/gnus/etc/images/smilies/medium/forced.xpm
new file mode 100644 (file)
index 0000000..df52a7e
--- /dev/null
@@ -0,0 +1,28 @@
+/* XPM */
+static char * forced_xpm[] = {
+"16 16 9 1",
+"      c None",
+".     c #000000",
+"+     c #1D1900",
+"@     c #887500",
+"#     c #D3B600",
+"$     c #FAD800",
+"%     c #645600",
+"&     c #FFDD00",
+"*     c #594D00",
+"     ......     ",
+"   .+@#$$#@+.   ",
+"  .%$&&&&&&$%.  ",
+" .%&&*&&&&*&&%. ",
+" +$&&.&&&&.&&$+ ",
+".@&&&.&&&&.&&&@.",
+".#&&&.&&&&.&&&#.",
+".$&&&&&&&&&&&&$.",
+".$&@&&&&&&&&@&$.",
+".#&.#&&&&&&#.&#.",
+".@&@@#&&&&#@@&@.",
+" +$#+......+#$+ ",
+" .%&&&&&&&&&&%. ",
+"  .%$&&&&&&$%.  ",
+"   .+@#$$#@+.   ",
+"     ......     "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/medium/frown.xpm b/xemacs-packages/gnus/etc/images/smilies/medium/frown.xpm
new file mode 100644 (file)
index 0000000..e4573ed
--- /dev/null
@@ -0,0 +1,28 @@
+/* XPM */
+static char * frown_xpm[] = {
+"16 16 9 1",
+"      c None",
+".     c #000000",
+"+     c #1D1900",
+"@     c #887500",
+"#     c #D3B600",
+"$     c #FAD800",
+"%     c #645600",
+"&     c #FFDD00",
+"*     c #594D00",
+"     ......     ",
+"   .+@#$$#@+.   ",
+"  .%$&&&&&&$%.  ",
+" .%&@*&&&&*@&%. ",
+" +$&#.&&&&.#&$+ ",
+".@&&&.*&#*.&&&@.",
+".#&&&.*##*.&&&#.",
+".$&&&&&&&&&&&&$.",
+".$&&&&&&&&&&&&$.",
+".#&&&@....@&&&#.",
+".@&&*.#&&#.*&&@.",
+" +$#.#&&&&#.#$+ ",
+" .%&*&&&&&&*&%. ",
+"  .%$&&&&&&$%.  ",
+"   .+@#$$#@+.   ",
+"     ......     "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/medium/grin.xpm b/xemacs-packages/gnus/etc/images/smilies/medium/grin.xpm
new file mode 100644 (file)
index 0000000..d8db415
--- /dev/null
@@ -0,0 +1,30 @@
+/* XPM */
+static char * grin_xpm[] = {
+"16 16 11 1",
+"      c None",
+".     c #000000",
+"+     c #1D1900",
+"@     c #887500",
+"#     c #D3B600",
+"$     c #FAD800",
+"%     c #645600",
+"&     c #FFDD00",
+"*     c #594D00",
+"=     c #FFFFFF",
+"-     c #8F7B00",
+"     ......     ",
+"   .+@#$$#@+.   ",
+"  .%$&&&&&&$%.  ",
+" .%&&*&&&&*&&%. ",
+" +$&&.&&&&.&&$+ ",
+".@&&&.&&&&.&&&@.",
+".#&&&.&&&&.&&&#.",
+".$&&&&&&&&&&&&$.",
+".$&..%%@@%%..&$.",
+".#&#.======.#&#.",
+".@&&-.====.-&&@.",
+" +$&&-....-&&$+ ",
+" .%&&&&&&&&&&%. ",
+"  .%$&&&&&&$%.  ",
+"   .+@#$$#@+.   ",
+"     ......     "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/medium/indifferent.xpm b/xemacs-packages/gnus/etc/images/smilies/medium/indifferent.xpm
new file mode 100644 (file)
index 0000000..98519c3
--- /dev/null
@@ -0,0 +1,28 @@
+/* XPM */
+static char * indifferent_xpm[] = {
+"16 16 9 1",
+"      c None",
+".     c #000000",
+"+     c #1D1900",
+"@     c #887500",
+"#     c #D3B600",
+"$     c #FAD800",
+"%     c #645600",
+"&     c #FFDD00",
+"*     c #594D00",
+"     ......     ",
+"   .+@#$$#@+.   ",
+"  .%$&&&&&&$%.  ",
+" .%&&*&&&&*&&%. ",
+" +$&&.&&&&.&&$+ ",
+".@&&&.&&&&.&&&@.",
+".#&&&.&&&&.&&&#.",
+".$&&&&&&&&&&&&$.",
+".$%&&&&&&&&&#%$.",
+".#.@.@&&&@&&.&#.",
+".@&.#.@#..@.@&@.",
+" +$@&&..#&..&$+ ",
+" .%&&&&.&&&&&%. ",
+"  .%$&&&&&&$%.  ",
+"   .+@#$$#@+.   ",
+"     ......     "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/medium/reverse-smile.xpm b/xemacs-packages/gnus/etc/images/smilies/medium/reverse-smile.xpm
new file mode 100644 (file)
index 0000000..9641c33
--- /dev/null
@@ -0,0 +1,29 @@
+/* XPM */
+static char * reverse_smile_xpm[] = {
+"16 16 10 1",
+"      c None",
+".     c #000000",
+"+     c #1D1900",
+"@     c #887500",
+"#     c #D3B600",
+"$     c #FAD800",
+"%     c #645600",
+"&     c #FFDD00",
+"*     c #8F7B00",
+"=     c #594D00",
+"     ......     ",
+"   .+@#$$#@+.   ",
+"  .%$&&&&&&$%.  ",
+" .%&&&&&&&&&&%. ",
+" +$&&*....*&&$+ ",
+".@&&*.&&&&.*&&@.",
+".#&#.&&&&&&.#&#.",
+".$&.&&&&&&&&.&$.",
+".$&&&&&&&&&&&&$.",
+".#&&&.&&&&.&&&#.",
+".@&&&.&&&&.&&&@.",
+" +$&&.&&&&.&&$+ ",
+" .%&&=&&&&=&&%. ",
+"  .%$&&&&&&$%.  ",
+"   .+@#$$#@+.   ",
+"     ......     "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/medium/sad.xpm b/xemacs-packages/gnus/etc/images/smilies/medium/sad.xpm
new file mode 100644 (file)
index 0000000..bc635c1
--- /dev/null
@@ -0,0 +1,28 @@
+/* XPM */
+static char * sad_xpm[] = {
+"16 16 9 1",
+"      c None",
+".     c #000000",
+"+     c #1D1900",
+"@     c #887500",
+"#     c #D3B600",
+"$     c #FAD800",
+"%     c #645600",
+"&     c #FFDD00",
+"*     c #594D00",
+"     ......     ",
+"   .+@#$$#@+.   ",
+"  .%$&&&&&&$%.  ",
+" .%&&*&&&&*&&%. ",
+" +$&&.&&&&.&&$+ ",
+".@&&&.&&&&.&&&@.",
+".#&&&.&&&&.&&&#.",
+".$&&&&&&&&&&&&$.",
+".$&&&&&&&&&&&&$.",
+".#&&&@....@&&&#.",
+".@&&*.#&&#.*&&@.",
+" +$#.#&&&&#.#$+ ",
+" .%&*&&&&&&*&%. ",
+"  .%$&&&&&&$%.  ",
+"   .+@#$$#@+.   ",
+"     ......     "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/medium/smile.xpm b/xemacs-packages/gnus/etc/images/smilies/medium/smile.xpm
new file mode 100644 (file)
index 0000000..b08129b
--- /dev/null
@@ -0,0 +1,29 @@
+/* XPM */
+static char * smile_xpm[] = {
+"16 16 10 1",
+"      c None",
+".     c #000000",
+"+     c #1D1900",
+"@     c #887500",
+"#     c #D3B600",
+"$     c #FAD800",
+"%     c #645600",
+"&     c #FFDD00",
+"*     c #594D00",
+"=     c #8F7B00",
+"     ......     ",
+"   .+@#$$#@+.   ",
+"  .%$&&&&&&$%.  ",
+" .%&&*&&&&*&&%. ",
+" +$&&.&&&&.&&$+ ",
+".@&&&.&&&&.&&&@.",
+".#&&&.&&&&.&&&#.",
+".$&&&&&&&&&&&&$.",
+".$&.&&&&&&&&.&$.",
+".#&#.&&&&&&.#&#.",
+".@&&=.&&&&.=&&@.",
+" +$&&=....=&&$+ ",
+" .%&&&&&&&&&&%. ",
+"  .%$&&&&&&$%.  ",
+"   .+@#$$#@+.   ",
+"     ......     "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/medium/wry.xpm b/xemacs-packages/gnus/etc/images/smilies/medium/wry.xpm
new file mode 100644 (file)
index 0000000..3bc841b
--- /dev/null
@@ -0,0 +1,28 @@
+/* XPM */
+static char * wry_xpm[] = {
+"16 16 9 1",
+"      c None",
+".     c #000000",
+"+     c #1D1900",
+"@     c #887500",
+"#     c #D3B600",
+"$     c #FAD800",
+"%     c #645600",
+"&     c #FFDD00",
+"*     c #594D00",
+"     ......     ",
+"   .+@#$$#@+.   ",
+"  .%$&&&&&&$%.  ",
+" .%&&*&&&&*&&%. ",
+" +$&&.&&&&.&&$+ ",
+".@&&&.&&&&.&&&@.",
+".#&&&.&&&&.&&&#.",
+".$&&&&&&&&&&&&$.",
+".$&&&&&&&&&%&&$.",
+".#&&&&&&&&@%&&#.",
+".@&&#......#&&@.",
+" +$&%@&&&&&&&$+ ",
+" .%&%&&&&&&&&%. ",
+"  .%$&&&&&&$%.  ",
+"   .+@#$$#@+.   ",
+"     ......     "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/sad.pbm b/xemacs-packages/gnus/etc/images/smilies/sad.pbm
new file mode 100644 (file)
index 0000000..892e343
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/smilies/sad.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/smilies/sad.xpm b/xemacs-packages/gnus/etc/images/smilies/sad.xpm
new file mode 100644 (file)
index 0000000..b0acef4
--- /dev/null
@@ -0,0 +1,20 @@
+/* XPM */
+static char * sad_xpm[] = {
+"13 14 3 1",
+"      c None",
+".     c #000000",
+"+     c #FFDD00",
+"   .......   ",
+"  ..+++++..  ",
+" .+++++++++. ",
+".+++++++++++.",
+".++..+++..++.",
+".++..+++..++.",
+".+++++++++++.",
+".+++++++++++.",
+".+++.....+++.",
+".++.+++++.++.",
+".++.+++++.++.",
+" .+++++++++. ",
+"  ..+++++..  ",
+"   .......   "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/smile.pbm b/xemacs-packages/gnus/etc/images/smilies/smile.pbm
new file mode 100644 (file)
index 0000000..f64e883
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/smilies/smile.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/smilies/smile.xpm b/xemacs-packages/gnus/etc/images/smilies/smile.xpm
new file mode 100644 (file)
index 0000000..374d240
--- /dev/null
@@ -0,0 +1,20 @@
+/* XPM */
+static char * smile_xpm[] = {
+"13 14 3 1",
+"      c None",
+".     c #000000",
+"+     c #FFDD00",
+"   .......   ",
+"  ..+++++..  ",
+" .+++++++++. ",
+".+++++++++++.",
+".++..+++..++.",
+".++..+++..++.",
+".+++++++++++.",
+".+++++++++++.",
+".++.+++++.++.",
+".++.+++++.++.",
+".+++.....+++.",
+" .+++++++++. ",
+"  ..+++++..  ",
+"   .......   "};
diff --git a/xemacs-packages/gnus/etc/images/smilies/wry.pbm b/xemacs-packages/gnus/etc/images/smilies/wry.pbm
new file mode 100644 (file)
index 0000000..5fa5e9f
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/smilies/wry.pbm differ
diff --git a/xemacs-packages/gnus/etc/images/smilies/wry.xpm b/xemacs-packages/gnus/etc/images/smilies/wry.xpm
new file mode 100644 (file)
index 0000000..8cd8ded
--- /dev/null
@@ -0,0 +1,20 @@
+/* XPM */
+static char * wry_xpm[] = {
+"13 14 3 1",
+"      c None",
+".     c #000000",
+"+     c #FFDD00",
+"   .......   ",
+"  ..+++++..  ",
+" .+++++++++. ",
+".+++++++++++.",
+".+++++++..++.",
+".++..+++..++.",
+".++..+++++++.",
+".+++++++++++.",
+".+++++++...+.",
+".+++++...+++.",
+".++++..+++++.",
+" .+++.+++++. ",
+"  ..+++++..  ",
+"   .......   "};
diff --git a/xemacs-packages/gnus/etc/images/sort-ascending.xpm b/xemacs-packages/gnus/etc/images/sort-ascending.xpm
new file mode 100644 (file)
index 0000000..7f5a880
--- /dev/null
@@ -0,0 +1,61 @@
+/* XPM */
+static char * sort_ascending_xpm[] = {
+"24 24 34 1",
+"      c None",
+".     c #000000",
+"+     c #FAFAFA",
+"@     c #DDDFD2",
+"#     c #8B8E7C",
+"$     c #E5E7DD",
+"%     c #84A77E",
+"&     c #586546",
+"*     c #81A57C",
+"=     c #EDEEE8",
+"-     c #81A57B",
+";     c #ECEDE6",
+">     c #7EA379",
+",     c #7DA377",
+"'     c #DDDFD3",
+")     c #7DA378",
+"!     c #C9D5C4",
+"~     c #7EA378",
+"{     c #7C7E73",
+"]     c #DFE7DE",
+"^     c #CCDACA",
+"/     c #90B08C",
+"(     c #76986D",
+"_     c #6C855E",
+":     c #22231E",
+"<     c #3F443B",
+"[     c #C8D8C7",
+"}     c #9DB89A",
+"|     c #76966B",
+"1     c #3D4237",
+"2     c #565B4E",
+"3     c #9EBA9A",
+"4     c #3C4237",
+"5     c #5E6154",
+"                        ",
+"                        ",
+"                        ",
+"               ....     ",
+"     .....    ..  ..    ",
+"     .+@#.    ..  ..    ",
+"     .$%&.    ......    ",
+"     .$*&.    ..  ..    ",
+"     .=-&.    ..  ..    ",
+"     .;-&.              ",
+"     .$*&.      ..      ",
+"     .$*&.      ..      ",
+"     .$>&.              ",
+"     .$,&.      ..      ",
+"     .')&.      ..      ",
+"   ...!~&...            ",
+"   .{]^/(_:.  ......    ",
+"    .<[}|1.      ...    ",
+"     .234.      ...     ",
+"      .5.      ...      ",
+"       .      ...       ",
+"              ......    ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/sort-column-ascending.xpm b/xemacs-packages/gnus/etc/images/sort-column-ascending.xpm
new file mode 100644 (file)
index 0000000..76d7f93
--- /dev/null
@@ -0,0 +1,29 @@
+/* XPM */
+static char * stock_sort_column_ascending_xpm[] = {
+"24 24 2 1",
+"      c None",
+".     c #000000",
+"                        ",
+"                        ",
+"    ...                 ",
+"   . ..                 ",
+"     ..                 ",
+"     ..                 ",
+"     ..                 ",
+"     ..                 ",
+"     ..                 ",
+"   .....   .            ",
+"                        ",
+"           .            ",
+"                        ",
+"           .            ",
+"    ....                ",
+"   ..  ..               ",
+"   ..  ..               ",
+"   ..  ..               ",
+"    .....               ",
+"       ..               ",
+"   .  ...               ",
+"   .....                ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/sort-criteria.xpm b/xemacs-packages/gnus/etc/images/sort-criteria.xpm
new file mode 100644 (file)
index 0000000..d1c83b8
--- /dev/null
@@ -0,0 +1,55 @@
+/* XPM */
+static char * stock_sort_criteria_xpm[] = {
+"24 24 28 1",
+"      c None",
+".     c #000000",
+"+     c #FFFFFF",
+"@     c #D3D3D3",
+"#     c #F2ECE1",
+"$     c #F4EFE5",
+"%     c #DFDAD2",
+"&     c #C9C4BD",
+"*     c #74716E",
+"=     c #FAFAFA",
+"-     c #EADFC9",
+";     c #ECE2CF",
+">     c #EEE5D4",
+",     c #4C4B48",
+"'     c #F5F5F5",
+")     c #C9C9C9",
+"!     c #E2D2B1",
+"~     c #CFC4B1",
+"{     c #BFBFBF",
+"]     c #C0C0C0",
+"^     c #C7B99C",
+"/     c #F0F0F0",
+"(     c #B7B7B7",
+"_     c #9A8F78",
+":     c #877E69",
+"<     c #AFA389",
+"[     c #A09889",
+"}     c #314E6C",
+"                        ",
+"                        ",
+"                ......  ",
+"                   ...  ",
+"                  ...   ",
+"                 ...    ",
+"  .........     ...     ",
+"  .+@.#$%&*.    ......  ",
+"  .=@.-;;;>,            ",
+"  .').!!!!.~.           ",
+"  .{].^^!.^.~.          ",
+"  ./(.._.^.:.~.         ",
+"   .....<.:...[.        ",
+"        .:..  ..        ",
+"         ..             ",
+"                        ",
+"                 }}}}   ",
+"                }}  }}  ",
+"                }}  }}  ",
+"                }}}}}}  ",
+"                }}  }}  ",
+"                }}  }}  ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/sort-descending.xpm b/xemacs-packages/gnus/etc/images/sort-descending.xpm
new file mode 100644 (file)
index 0000000..dddb6ed
--- /dev/null
@@ -0,0 +1,62 @@
+/* XPM */
+static char * sort_descending_xpm[] = {
+"24 24 35 1",
+"      c None",
+".     c #000000",
+"+     c #F8F0EE",
+"@     c #E5B9BB",
+"#     c #895F63",
+"$     c #E7BDBC",
+"%     c #C14B35",
+"&     c #922B34",
+"*     c #C24F3C",
+"=     c #942B32",
+"-     c #E8BFBE",
+";     c #E8C2BF",
+">     c #C34E3B",
+",     c #C24F3A",
+"'     c #C24D38",
+")     c #E5B8B9",
+"!     c #C24F38",
+"~     c #E2B1AA",
+"{     c #CC6B5A",
+"]     c #643C3E",
+"^     c #E3B5AC",
+"/     c #E3B3A9",
+"(     c #D07868",
+"_     c #982E19",
+":     c #7E261F",
+"<     c #120C0F",
+"[     c #2B1D1F",
+"}     c #DFAA9E",
+"|     c #D28575",
+"1     c #7D2617",
+"2     c #321C23",
+"3     c #3B262E",
+"4     c #D68A7A",
+"5     c #321C21",
+"6     c #3F2A35",
+"                        ",
+"                        ",
+"                        ",
+"              ......    ",
+"     .....       ...    ",
+"     .+@#.      ...     ",
+"     .$%&.     ...      ",
+"     .$*=.    ...       ",
+"     .-*=.    ......    ",
+"     .;>=.              ",
+"     .$*=.      ..      ",
+"     .$*=.      ..      ",
+"     .$,=.              ",
+"     .$'=.      ..      ",
+"     .)!=.      ..      ",
+"   ...~{=...            ",
+"   .]^/(_:<.   ....     ",
+"    .[}|12.   ..  ..    ",
+"     .345.    ..  ..    ",
+"      .6.     ......    ",
+"       .      ..  ..    ",
+"              ..  ..    ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/sort-row-ascending.xpm b/xemacs-packages/gnus/etc/images/sort-row-ascending.xpm
new file mode 100644 (file)
index 0000000..5200b97
--- /dev/null
@@ -0,0 +1,22 @@
+/* XPM */
+static char * stock_sort_row_ascending_xpm[] = {
+"21 17 2 1",
+"      c None",
+".     c #000000",
+"                     ",
+"                     ",
+"                     ",
+"                     ",
+"  ...         ....   ",
+" . ..        ..  ..  ",
+"   ..        ..  ..  ",
+"   ..        ..  ..  ",
+"   ..         .....  ",
+"   ..            ..  ",
+"   ..        .   ..  ",
+" ..... . . . .....   ",
+"                     ",
+"                     ",
+"                     ",
+"                     ",
+"                     "};
diff --git a/xemacs-packages/gnus/etc/images/spell.xpm b/xemacs-packages/gnus/etc/images/spell.xpm
new file mode 100644 (file)
index 0000000..b53f451
--- /dev/null
@@ -0,0 +1,64 @@
+/* XPM */
+static char * spell_xpm[] = {
+"24 24 37 1",
+"      c None",
+".     c #000000",
+"+     c #8BBB8C",
+"@     c #ABD0AC",
+"#     c #1A3B1A",
+"$     c #8ABA88",
+"%     c #B4D5B4",
+"&     c #70A770",
+"*     c #132C13",
+"=     c #77A676",
+"-     c #2D2D2D",
+";     c #CBDFCB",
+">     c #6FAE6E",
+",     c #A8CBA6",
+"'     c #6D9D6C",
+")     c #D0E4D0",
+"!     c #6FAF6F",
+"~     c #587055",
+"{     c #B8D6B8",
+"]     c #5B9159",
+"^     c #D4E4D4",
+"/     c #67AF67",
+"(     c #5D905B",
+"_     c #9FC59D",
+":     c #93BE92",
+"<     c #B5D1B5",
+"[     c #67AF68",
+"}     c #63A261",
+"|     c #BBD6BA",
+"1     c #82B881",
+"2     c #75AF74",
+"3     c #6B8868",
+"4     c #9DC39D",
+"5     c #7DB17B",
+"6     c #6BA368",
+"7     c #485C46",
+"8     c #89BA88",
+"                        ",
+"                        ",
+"                        ",
+"                        ",
+"  ...  ....   ...       ",
+" ..  . ..  . ..  .      ",
+" ..  . ....  ..         ",
+" ..... ..  . ..         ",
+" ..  . ..  . ..  .   .  ",
+" ..  . ....   ...   ... ",
+"                   .+.  ",
+"         ..       .@#   ",
+"         .$.     .%&.   ",
+"          *=.   -;>.    ",
+"          .,'. .)!~.    ",
+"           .{].^/(.     ",
+"           ._:<[}~.     ",
+"            .|123.      ",
+"            .4567.      ",
+"             .83.       ",
+"             .37.       ",
+"              ..        ",
+"                        ",
+"                        "};
diff --git a/xemacs-packages/gnus/etc/images/splash.png b/xemacs-packages/gnus/etc/images/splash.png
new file mode 100644 (file)
index 0000000..9d0eb37
Binary files /dev/null and b/xemacs-packages/gnus/etc/images/splash.png differ
diff --git a/xemacs-packages/gnus/etc/images/splash.svg b/xemacs-packages/gnus/etc/images/splash.svg
new file mode 100644 (file)
index 0000000..5b50af7
--- /dev/null
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Gnu Emacs Logo
+
+   Copyright (C) 2008-2016 Free Software Foundation, Inc.
+
+   Author: Francesc Rocher <francesc.rocher@gmail.com>
+   Based on the original work by Luis Fernandes <elf@ee.ryerson.ca>
+
+   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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+-->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.0"
+   width="333"
+   height="233"
+   id="svg6706"
+   style="display:inline"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="splash.svg"
+   inkscape:export-filename="/opt/src/emacs/etc/images/splash.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="1"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1920"
+     inkscape:window-height="1004"
+     id="namedview3107"
+     showgrid="false"
+     inkscape:showpageshadow="false"
+     inkscape:zoom="1"
+     inkscape:cx="-49.78722"
+     inkscape:cy="105.19797"
+     inkscape:window-x="0"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="layer1" />
+  <metadata
+     id="metadata2314">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+        <dc:date>2008/06/28</dc:date>
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Francesc Rocher</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:rights>
+          <cc:Agent>
+            <dc:title>GPL</dc:title>
+          </cc:Agent>
+        </dc:rights>
+        <dc:description>GNU Emacs splash image</dc:description>
+        <dc:contributor>
+          <cc:Agent>
+            <dc:title>Based on the original work by Luis Fernandes.</dc:title>
+          </cc:Agent>
+        </dc:contributor>
+        <cc:license
+           rdf:resource="http://www.gnu.org/copyleft/gpl.html" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs6709" />
+  <g
+     inkscape:groupmode="layer"
+     id="layer1"
+     inkscape:label="emacs"
+     style="display:inline">
+    <g
+       style="display:inline"
+       id="g3171"
+       transform="translate(-0.3199963,-16.05214)">
+      <path
+         inkscape:connector-curvature="0"
+         id="gnu-7-7-5"
+         d="m 91.501627,223.13422 c 2.44866,-7.38073 7.44672,-16.72109 12.277833,-22.94475 5.71059,-7.35667 7.37834,-9.3856 28.68987,-34.90319 16.87203,-20.20187 19.22297,-23.17963 22.55477,-28.56842 1.5428,-2.49527 3.17766,-4.53686 3.63304,-4.53686 1.18186,0 1.10043,0.30992 -1.63307,6.21531 -1.35357,2.92424 -2.46105,5.64533 -2.46105,6.04686 0,0.40153 -2.97647,4.90375 -6.6144,10.00493 -8.98843,12.6038 -10.76026,14.97181 -13.08231,17.48444 -1.0981,1.18822 -3.8535,4.49366 -6.1231,7.34539 -2.2696,2.85173 -4.58719,5.62332 -5.15019,6.15909 -0.56299,0.53575 -2.79558,3.19769 -4.9613,5.91542 -6.69122,8.39667 -16.09521,19.83397 -17.43166,21.20066 -0.69977,0.71561 -3.044273,3.91702 -5.209993,7.11426 -4.16128,6.14322 -5.79503,7.40513 -4.48844,3.46686 z m 66.481533,-23.7645 c 0.22279,-0.5941 1.5292,-4.28446 2.90315,-8.20081 3.44555,-9.82127 13.66236,-27.15831 19.73886,-33.49505 l 2.48602,-2.59251 2.25191,2.37646 c 2.67739,2.82543 3.88298,2.92758 8.02572,0.68 3.08741,-1.67502 7.69643,-8.22076 20.10229,-28.54929 4.55053,-7.45659 5.01229,-7.9395 5.0346,-5.26516 0.0415,4.9808 -22.21528,41.2544 -29.34472,47.82522 -4.11732,3.7947 -6.18823,4.04757 -8.84718,1.0802 -1.06473,-1.18822 -2.3151,-2.15972 -2.77861,-2.15886 -1.62142,0.003 -12.08302,16.59943 -16.47702,26.13939 -0.82094,1.78235 -1.9443,3.24062 -2.49635,3.24062 -0.55207,0 -0.82147,-0.48609 -0.59867,-1.08021 z m 84.56819,-24.82537 c -2.06645,-0.8019 1.13497,-15.11544 9.38534,-45.76041 8.25036,-30.64496 13.71984,-51.383787 14.84879,-58.25729 1.12895,-6.873503 2.03487,-14.092092 -4.36472,-16.458525 -6.39958,-2.366433 -16.77636,10.967049 -21.18571,12.891935 -1.80822,-0.98102 -3.1468,-0.58863 2.90016,-11.56546 6.04696,-10.97683 17.96376,-16.533598 24.45815,-14.02345 6.49439,2.510148 9.06627,8.870934 9.02208,16.2618 -0.0442,7.390866 -1.34227,9.483254 -10.57054,34.657444 -9.22827,25.174186 -15.27911,53.155486 -18.56738,69.382646 -1.67576,8.37809 -3.60972,13.73571 -5.92617,12.87131 z m -96.84888,-54.21518 c 1.40606,-16.35743 -4.16257,-18.77418 -12.79668,-25.53246 0,-1.55773 8.7013,-12.73719 9.91373,-12.73719 1.73907,0 4.26796,0.851938 9.50728,9.07372 5.23932,8.221782 2.81919,33.478 -4.79284,37.656 -1.73206,0.81373 -1.83075,0.3578 -1.83149,-8.46007 z m -67.235101,2.4601 C 66.149626,114.64118 107.1616,65.642805 109.89257,67.61866 c 1.43393,1.147042 -25.884213,36.7541 -19.110563,41.27888 6.77365,4.52478 36.496453,-21.773029 38.824823,-19.65206 2.32837,2.120969 -42.806145,38.90369 -51.139461,33.54379 z M 203.02623,89.36059 c -4.35468,-2.67753 -4.37646,-3.98287 -0.1931,-11.57676 l 3.90554,-7.08957 2.54785,2.65806 c 3.02363,3.15442 6.72598,3.45147 12.70923,1.01972 4.8079,-1.95406 8.30397,-5.19427 11.75211,-10.89203 l 2.61484,-4.32082 -0.49413,3.33468 c -0.73833,4.9825 -10.09007,19.20733 -14.90376,22.66994 -7.26038,5.22257 -13.78694,6.74948 -17.93858,4.19678 z m -30.4,-8.22399 C 157.50408,77.285901 148.7977,56.570002 130.36074,56.13461 c -4.30021,0 -9.89066,3.33457 -11.79031,7.03263 -2.74495,5.3436 -3.95008,5.711 -6.19677,1.88915 -3.1561,-5.36887 -12.746673,-12.37843 -16.936323,-12.37843 -0.62849,0 -6.18822,4.49121 -12.35495,9.98046 -11.48323,10.22167 -16.71895,13.29663 -22.702,13.33298 -3.49086,0.0212 -7.74406,-2.69911 -10.336349,-6.61109 -1.58653,-2.3942 -1.54623,-2.69169 1.09475,-8.08174 1.508069,-3.07782 3.079199,-6.37379 3.491429,-7.32437 0.65221,-1.50398 0.99078,-1.25829 2.60844,1.8928 1.91118,3.72288 6.32103,7.18093 9.15741,7.18093 4.15083,0 11.50453,-4.7246 21.3988,-13.7483 9.55523,-8.71448 10.82987,-9.58412 14.047543,-9.58412 4.29359,0 9.55637,2.77633 14.65637,7.73182 2.06945,2.0108 3.86226,3.5242 3.98403,3.36311 3.62266,-5.566805 10.90469,-9.699668 16.87635,-9.15074 16.82938,1.857986 31.50411,28.885923 47.63888,30.02986 6.12183,0.0506 13.64798,-10.853925 15.61976,-8.99729 0.1695,0.99261 -1.28406,4.87189 -3.23015,8.62062 -5.69216,10.252657 -13.63209,13.763692 -24.76142,9.82371 z"
+         style="fill:#c64e3b;fill-opacity:1;stroke:#c64e3b;stroke-width:0.9769991;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+         sodipodi:nodetypes="sssssssssscssssssscssscssssssczzzczzzzccccszcccczzcsscssscsssccssssssssssssscccccc" />
+      <path
+         sodipodi:nodetypes="cscszzczcsczzzssccssssssssssscssccsssssssssssccssccssssssssccssccccssscssssccsssscsscc"
+         inkscape:connector-curvature="0"
+         id="emacs-9-4-3"
+         d="m 33.019748,221.94909 c -6.110408,-9.38954 3.380608,-25.48422 15.35655,-34.75342 6.516165,-5.04342 14.224569,-9.82272 13.070959,-9.82483 -0.99658,-0.002 -3.28511,-0.79177 -5.08562,-1.75545 -6.217869,-3.328 -13.320748,-11.33731 7.05534,-28.37574 20.376088,-17.03843 58.074533,-25.26395 64.900723,-20.35237 6.82619,4.91158 -21.13643,22.39146 -22.51985,21.00884 -0.54574,-1.30268 16.61528,-10.7144 12.28657,-13.45436 -4.32871,-2.73996 -49.428283,10.06303 -49.047283,27.89807 0.71955,5.15612 9.09591,7.16542 19.10752,2.72826 7.00502,-3.10464 12.660323,-6.60408 12.285323,-4.56715 -13.758486,12.27671 -39.124345,23.59007 -45.869963,29.39978 -6.745618,5.80971 -7.543869,11.67601 -6.794789,14.18989 0.74908,2.51388 2.060512,5.22647 6.829019,5.51844 4.768507,0.29197 8.89581,0.12074 32.27058,-16.5637 5.16228,-3.68473 10.22809,-7.76323 13.653653,-9.77045 4.32602,-2.53484 10.05688,-4.56948 8.97699,-1.65526 -3.77936,7.61077 -5.74585,10.67934 -9.16756,16.15546 8.11118,-6.33235 15.74717,-14.15513 24.3066,-15.7298 2.0811,-0.38286 6.77241,-1.55766 8.63617,0.99596 0.76447,1.04743 -0.45512,5.1162 -2.21368,8.92266 -0.53908,1.16685 1.05142,0.38368 4.67533,-2.30213 7.44131,-5.51505 14.07912,-8.75072 17.95158,-8.75072 4.57712,0 4.83279,1.74832 1.24097,8.48622 -3.75741,7.04855 -6.75962,17.21422 -4.65148,19.88378 1.46622,1.85669 7.96734,-2.91147 10.3276,-4.31865 2.42293,-1.44454 6.05649,-3.67201 7.44149,-4.72955 10.37298,-7.92039 39.1617,-23.15505 40.99851,-21.53603 0.82449,0.72672 -1.6928,2.43145 -10.4509,7.07749 -14.25554,7.56231 -22.59862,14.9854 -22.60932,20.11619 -0.006,2.71011 4.1743,2.15203 7.26381,1.4275 4.40695,-1.03349 12.41622,-3.9676 -0.1736,3.14023 -13.16001,7.42974 -22.48474,6.17813 -16.63437,-3.95665 l 3.73574,-6.16441 -9.13253,6.55379 c -13.1916,9.46671 -19.35595,10.10807 -22.76505,7.11544 -2.61211,-2.29301 -1.99117,-8.56165 1.43897,-14.5266 2.74703,-4.77707 3.88176,-8.84229 2.46817,-8.84229 -2.38604,0 -7.35932,4.53611 -13.26994,10.69747 -9.97489,10.39803 -8.541,15.10079 -10.5912,15.36938 -1.2597,0.16503 -6.97748,-1.59412 -4.55589,-8.64068 1.80805,-5.26122 4.69288,-8.68747 6.82226,-11.55279 3.86672,-5.2031 1.48047,-5.97342 -3.79027,-3.77097 -3.05613,1.27704 -5.35016,4.83814 -17.152833,15.01371 -13.80489,11.90178 -18.19909,17.31989 -20.79043,11.99664 -1.27325,-2.61557 1.0176,-5.97434 3.23361,-9.57032 4.3675,-7.21553 10.68782,-13.92474 8.63284,-16.40083 -2.05019,0.66573 -5.70142,3.94706 -7.91742,5.72051 -2.21601,1.77344 -5.21691,3.98662 -6.66868,4.91816 -1.45175,0.93154 -5.75786,3.9162 -9.56912,6.63255 -12.148528,7.72218 -28.712254,17.824 -33.545099,10.89873 z m 160.303772,-8.81383 c -4.88506,-3.00364 -1.44968,-15.28518 5.948,-21.26421 3.32796,-2.68976 12.33843,-8.3073 13.32481,-8.3073 0.27463,0 -1.05354,2.61529 -2.9515,5.81174 -5.51025,9.28008 -4.30612,16.29397 2.79731,16.29397 5.95677,0 10.60291,-1.935 15.24759,-9.21089 3.95762,-6.19961 10.07679,-10.04817 15.75277,-13.07984 4.88528,-2.60934 16.10975,-4.00015 19.83723,-4.00272 5.28129,-0.004 5.07061,0.66399 -3.766,4.03459 -5.96006,1.81342 -23.41185,8.68768 -18.33848,20.56454 1.0883,2.49035 5.34941,2.76493 8.03403,2.5731 2.64994,-0.18935 5.81168,-1.7253 7.33518,-2.42296 1.52351,-0.69765 3.03519,0.21321 3.03519,0.61971 -5.88638,3.94569 -11.44839,6.45882 -14.00234,7.27145 -2.61375,0.96599 -7.35132,2.03318 -10.23523,1.93803 -5.03631,0.0339 -9.16147,-1.48631 -10.57379,-3.37846 -0.79608,-1.43217 -1.06163,-2.48284 -0.96262,-3.97903 0.2568,-3.8804 0.16517,-2.52343 -4.28527,0.23044 -13.102,8.10733 -21.40719,9.25285 -26.19688,6.30784 z m 75.29251,0.5386 c -1.38501,-0.41486 -3.99134,-0.79396 -5.79185,-0.84243 -5.99934,-0.16153 -3.6372,-2.26466 5.12716,-4.56493 2.24719,-0.58979 2.74693,-0.49039 2.32997,0.46346 -1.0714,2.45099 8.09297,3.14025 13.72804,1.0325 5.4798,-2.04969 7.70684,-5.31293 8.2153,-10.06119 0.16756,-8.34719 -12.6158,-6.31988 -18.32043,-6.36109 -12.98146,-0.0572 -14.34396,-1.01124 -7.14295,-5.00172 9.56822,-5.3023 20.88185,-11.1336 25.8426,-10.44585 5.86061,0.8125 5.42599,3.39743 -0.5575,3.43312 -3.92889,0.0234 -13.80136,5.14348 -14.97622,6.81223 -1.22979,1.74676 2.12319,2.47254 11.4854,2.48607 8.58743,0.0125 10.7826,1.48644 11.8355,2.18392 2.50203,1.65742 3.46341,8.67923 -0.80123,12.20836 -7.5132,6.21744 -19.30064,10.28748 -30.97375,8.65755 z"
+         style="fill:#3c74bd;fill-opacity:1;stroke:#3c74bd;stroke-width:0.99999905;stroke-opacity:1;display:inline" />
+    </g>
+  </g>
+</svg>
diff --git a/xemacs-packages/gnus/etc/post-receive b/xemacs-packages/gnus/etc/post-receive
new file mode 100755 (executable)
index 0000000..676b885
--- /dev/null
@@ -0,0 +1,714 @@
+#!/bin/sh
+
+# modified: 2010-09-01 and on by tzz@lifelogs.com
+
+# the remainder is the standard git-core post-receive-email with some changes:
+
+# - USER_EMAIL and USER_NAME are used in the header
+# - the update message is after the diff
+# - without annotations, we use `git log --format=oneline' to generate the change summary (joining multiples with semicolons)
+# - the subject is shorter
+
+# Copyright (c) 2007 Andy Parkins
+#
+# An example hook script to mail out commit update information.  This hook
+# sends emails listing new revisions to the repository introduced by the
+# change being reported.  The rule is that (for branch updates) each commit
+# will appear on one email and one email only.
+#
+# This hook is stored in the contrib/hooks directory.  Your distribution
+# will have put this somewhere standard.  You should make this script
+# executable then link to it in the repository you would like to use it in.
+# For example, on debian the hook is stored in
+# /usr/share/doc/git-core/contrib/hooks/post-receive-email:
+#
+#  chmod a+x post-receive-email
+#  cd /path/to/your/repository.git
+#  ln -sf /usr/share/doc/git-core/contrib/hooks/post-receive-email hooks/post-receive
+#
+# This hook script assumes it is enabled on the central repository of a
+# project, with all users pushing only to it and not between each other.  It
+# will still work if you don't operate in that style, but it would become
+# possible for the email to be from someone other than the person doing the
+# push.
+#
+# Config
+# ------
+# hooks.mailinglist
+#   This is the list that all pushes will go to; leave it blank to not send
+#   emails for every ref update.
+# hooks.announcelist
+#   This is the list that all pushes of annotated tags will go to.  Leave it
+#   blank to default to the mailinglist field.  The announce emails lists
+#   the short log summary of the changes since the last annotated tag.
+# hooks.envelopesender
+#   If set then the -f option is passed to sendmail to allow the envelope
+#   sender address to be set
+# hooks.emailprefix
+#   All emails have their subjects prefixed with this prefix, or "[SCM]"
+#   if emailprefix is unset, to aid filtering
+# hooks.showrev
+#   The shell command used to format each revision in the email, with
+#   "%s" replaced with the commit id.  Defaults to "git rev-list -1
+#   --pretty %s", displaying the commit id, author, date and log
+#   message.  To list full patches separated by a blank line, you
+#   could set this to "git show -C %s; echo".
+#   To list a gitweb/cgit URL *and* a full patch for each change set, use this:
+#     "t=%s; printf 'http://.../?id=%%s' \$t; echo;echo; git show -C \$t; echo"
+#   Be careful if "..." contains things that will be expanded by shell "eval"
+#   or printf.
+#
+# Notes
+# -----
+# All emails include the headers "X-Git-Refname", "X-Git-Oldrev",
+# "X-Git-Newrev", and "X-Git-Reftype" to enable fine tuned filtering and
+# give information for debugging.
+#
+
+# ---------------------------- Functions
+
+#
+# Top level email generation function.  This decides what type of update
+# this is and calls the appropriate body-generation routine after outputting
+# the common header
+#
+# Note this function doesn't actually generate any email output, that is
+# taken care of by the functions it calls:
+#  - generate_email_header
+#  - generate_create_XXXX_email
+#  - generate_update_XXXX_email
+#  - generate_delete_XXXX_email
+#  - generate_email_footer
+#
+generate_email()
+{
+       # --- Arguments
+       oldrev=$(git rev-parse $1)
+       newrev=$(git rev-parse $2)
+       refname="$3"
+
+       # --- Interpret
+       # 0000->1234 (create)
+       # 1234->2345 (update)
+       # 2345->0000 (delete)
+       if expr "$oldrev" : '0*$' >/dev/null
+       then
+               change_type="create"
+       else
+               if expr "$newrev" : '0*$' >/dev/null
+               then
+                       change_type="delete"
+               else
+                       change_type="update"
+               fi
+       fi
+
+       # --- Get the revision types
+       newrev_type=$(git cat-file -t $newrev 2> /dev/null)
+       oldrev_type=$(git cat-file -t "$oldrev" 2> /dev/null)
+       case "$change_type" in
+       create|update)
+               rev="$newrev"
+               rev_type="$newrev_type"
+               ;;
+       delete)
+               rev="$oldrev"
+               rev_type="$oldrev_type"
+               ;;
+       esac
+
+       # The revision type tells us what type the commit is, combined with
+       # the location of the ref we can decide between
+       #  - working branch
+       #  - tracking branch
+       #  - unannoted tag
+       #  - annotated tag
+       case "$refname","$rev_type" in
+               refs/tags/*,commit)
+                       # un-annotated tag
+                       refname_type="tag"
+                       short_refname=${refname##refs/tags/}
+                       ;;
+               refs/tags/*,tag)
+                       # annotated tag
+                       refname_type="annotated tag"
+                       short_refname=${refname##refs/tags/}
+                       # change recipients
+                       if [ -n "$announcerecipients" ]; then
+                               recipients="$announcerecipients"
+                       fi
+                       ;;
+               refs/heads/*,commit)
+                       # branch
+                       refname_type="branch"
+                       short_refname=${refname##refs/heads/}
+                       ;;
+               refs/remotes/*,commit)
+                       # tracking branch
+                       refname_type="tracking branch"
+                       short_refname=${refname##refs/remotes/}
+                       echo >&2 "*** Push-update of tracking branch, $refname"
+                       echo >&2 "***  - no email generated."
+                       exit 0
+                       ;;
+               *)
+                       # Anything else (is there anything else?)
+                       echo >&2 "*** Unknown type of update to $refname ($rev_type)"
+                       echo >&2 "***  - no email generated"
+                       exit 1
+                       ;;
+       esac
+
+       # Check if we've got anyone to send to
+       if [ -z "$recipients" ]; then
+               case "$refname_type" in
+                       "annotated tag")
+                               config_name="hooks.announcelist"
+                               ;;
+                       *)
+                               config_name="hooks.mailinglist"
+                               ;;
+               esac
+               echo >&2 "*** $config_name is not set so no email will be sent"
+               echo >&2 "*** for $refname update $oldrev->$newrev"
+               exit 0
+       fi
+
+       # Email parameters
+       # The email subject will contain the best description of the ref
+       # that we can build from the parameters
+       describe_commit=$( (git log --format="%s" $oldrev...$newrev | perl -e'@p = <>; chomp @p; print "=", scalar @p, "= ", join(" ; ", @p)') 2>/dev/null)
+       describe_last=$(git describe $rev 2>/dev/null)
+
+       if [ -z "$describe_last" ]; then
+           describe=$describe_commit
+        else
+            describe="$describe_last $describe_commit"
+       fi
+
+       if [ -z "$describe" ]; then
+               describe=$rev
+       fi
+
+       generate_email_header
+
+       # Call the correct body generation function
+       fn_name=general
+       case "$refname_type" in
+       "tracking branch"|branch)
+               fn_name=branch
+               ;;
+       "annotated tag")
+               fn_name=atag
+               ;;
+       esac
+       generate_${change_type}_${fn_name}_email
+
+       generate_email_footer
+}
+
+generate_email_header()
+{
+
+        # Use the email address of the author of the last commit.
+        export USER_EMAIL="$(git log -1 $short_refname --format=format:%ce HEAD)"
+        export USER_NAME="$(git log -1 $short_refname --format=format:%cn HEAD)"
+
+       # --- Email (all stdout will be the email)
+       # Generate header
+       cat <<-EOF
+       From: ${USER_NAME} <${USER_EMAIL}>
+       To: $recipients
+       Subject: $emailprefix $refname_type $short_refname ${change_type}d: $describe
+       X-Git-Refname: $refname
+       X-Git-Reftype: $refname_type
+       X-Git-Oldrev: $oldrev
+       X-Git-Newrev: $newrev
+
+       EOF
+}
+
+generate_email_footer()
+{
+       SPACE=" "
+       cat <<-EOF
+       
+       This is an automated email from the git hooks/post-receive script. It was
+       generated because a ref change was pushed to the repository containing
+       the project "$projectdesc".
+
+       The $refname_type, $short_refname has been ${change_type}d
+
+
+       hooks/post-receive
+       --${SPACE}
+       $projectdesc
+       EOF
+}
+
+# --------------- Branches
+
+#
+# Called for the creation of a branch
+#
+generate_create_branch_email()
+{
+       # This is a new branch and so oldrev is not valid
+       echo "        at  $newrev ($newrev_type)"
+       echo ""
+
+       echo $LOGBEGIN
+       show_new_revisions
+       echo $LOGEND
+}
+
+#
+# Called for the change of a pre-existing branch
+#
+generate_update_branch_email()
+{
+       # Consider this:
+       #   1 --- 2 --- O --- X --- 3 --- 4 --- N
+       #
+       # O is $oldrev for $refname
+       # N is $newrev for $refname
+       # X is a revision pointed to by some other ref, for which we may
+       #   assume that an email has already been generated.
+       # In this case we want to issue an email containing only revisions
+       # 3, 4, and N.  Given (almost) by
+       #
+       #  git rev-list N ^O --not --all
+       #
+       # The reason for the "almost", is that the "--not --all" will take
+       # precedence over the "N", and effectively will translate to
+       #
+       #  git rev-list N ^O ^X ^N
+       #
+       # So, we need to build up the list more carefully.  git rev-parse
+       # will generate a list of revs that may be fed into git rev-list.
+       # We can get it to make the "--not --all" part and then filter out
+       # the "^N" with:
+       #
+       #  git rev-parse --not --all | grep -v N
+       #
+       # Then, using the --stdin switch to git rev-list we have effectively
+       # manufactured
+       #
+       #  git rev-list N ^O ^X
+       #
+       # This leaves a problem when someone else updates the repository
+       # while this script is running.  Their new value of the ref we're
+       # working on would be included in the "--not --all" output; and as
+       # our $newrev would be an ancestor of that commit, it would exclude
+       # all of our commits.  What we really want is to exclude the current
+       # value of $refname from the --not list, rather than N itself.  So:
+       #
+       #  git rev-parse --not --all | grep -v $(git rev-parse $refname)
+       #
+       # Get's us to something pretty safe (apart from the small time
+       # between refname being read, and git rev-parse running - for that,
+       # I give up)
+       #
+       #
+       # Next problem, consider this:
+       #   * --- B --- * --- O ($oldrev)
+       #          \
+       #           * --- X --- * --- N ($newrev)
+       #
+       # That is to say, there is no guarantee that oldrev is a strict
+       # subset of newrev (it would have required a --force, but that's
+       # allowed).  So, we can't simply say rev-list $oldrev..$newrev.
+       # Instead we find the common base of the two revs and list from
+       # there.
+       #
+       # As above, we need to take into account the presence of X; if
+       # another branch is already in the repository and points at some of
+       # the revisions that we are about to output - we don't want them.
+       # The solution is as before: git rev-parse output filtered.
+       #
+       # Finally, tags: 1 --- 2 --- O --- T --- 3 --- 4 --- N
+       #
+       # Tags pushed into the repository generate nice shortlog emails that
+       # summarise the commits between them and the previous tag.  However,
+       # those emails don't include the full commit messages that we output
+       # for a branch update.  Therefore we still want to output revisions
+       # that have been output on a tag email.
+       #
+       # Luckily, git rev-parse includes just the tool.  Instead of using
+       # "--all" we use "--branches"; this has the added benefit that
+       # "remotes/" will be ignored as well.
+
+       # List all of the revisions that were removed by this update, in a
+       # fast-forward update, this list will be empty, because rev-list O
+       # ^N is empty.  For a non-fast-forward, O ^N is the list of removed
+       # revisions
+       fast_forward=""
+       rev=""
+       for rev in $(git rev-list $newrev..$oldrev)
+       do
+               revtype=$(git cat-file -t "$rev")
+               echo "  discards  $rev ($revtype)"
+       done
+       if [ -z "$rev" ]; then
+               fast_forward=1
+       fi
+
+       # List all the revisions from baserev to newrev in a kind of
+       # "table-of-contents"; note this list can include revisions that
+       # have already had notification emails and is present to show the
+       # full detail of the change from rolling back the old revision to
+       # the base revision and then forward to the new revision
+       for rev in $(git rev-list $oldrev..$newrev)
+       do
+               revtype=$(git cat-file -t "$rev")
+               echo "       via  $rev ($revtype)"
+       done
+
+       if [ "$fast_forward" ]; then
+               echo "      from  $oldrev ($oldrev_type)"
+       else
+               #  1. Existing revisions were removed.  In this case newrev
+               #     is a subset of oldrev - this is the reverse of a
+               #     fast-forward, a rewind
+               #  2. New revisions were added on top of an old revision,
+               #     this is a rewind and addition.
+
+               # (1) certainly happened, (2) possibly.  When (2) hasn't
+               # happened, we set a flag to indicate that no log printout
+               # is required.
+
+               echo ""
+
+               # Find the common ancestor of the old and new revisions and
+               # compare it with newrev
+               baserev=$(git merge-base $oldrev $newrev)
+               rewind_only=""
+               if [ "$baserev" = "$newrev" ]; then
+                       echo "This update discarded existing revisions and left the branch pointing at"
+                       echo "a previous point in the repository history."
+                       echo ""
+                       echo " * -- * -- N ($newrev)"
+                       echo "            \\"
+                       echo "             O -- O -- O ($oldrev)"
+                       echo ""
+                       echo "The removed revisions are not necessarilly gone - if another reference"
+                       echo "still refers to them they will stay in the repository."
+                       rewind_only=1
+               else
+                       echo "This update added new revisions after undoing existing revisions.  That is"
+                       echo "to say, the old revision is not a strict subset of the new revision.  This"
+                       echo "situation occurs when you --force push a change and generate a repository"
+                       echo "containing something like this:"
+                       echo ""
+                       echo " * -- * -- B -- O -- O -- O ($oldrev)"
+                       echo "            \\"
+                       echo "             N -- N -- N ($newrev)"
+                       echo ""
+                       echo "When this happens we assume that you've already had alert emails for all"
+                       echo "of the O revisions, and so we here report only the revisions in the N"
+                       echo "branch from the common base, B."
+               fi
+       fi
+
+       echo ""
+       if [ -z "$rewind_only" ]; then
+               echo ""
+               echo $LOGBEGIN
+               show_new_revisions
+
+               # XXX: Need a way of detecting whether git rev-list actually
+               # outputted anything, so that we can issue a "no new
+               # revisions added by this update" message
+
+               echo $LOGEND
+
+               echo "Those revisions listed above that are new to this repository have"
+               echo "not appeared on any other notification email; so we listed those"
+               echo "revisions in full, above."
+
+       else
+               echo "No new revisions were added by this update."
+       fi
+
+       # The diffstat is shown from the old revision to the new revision.
+       # This is to show the truth of what happened in this change.
+       # There's no point showing the stat from the base to the new
+       # revision because the base is effectively a random revision at this
+       # point - the user will be interested in what this revision changed
+       # - including the undoing of previous revisions in the case of
+       # non-fast-forward updates.
+       echo ""
+       echo "Summary of changes:"
+       git diff-tree --stat --summary --find-copies-harder $oldrev..$newrev
+}
+
+#
+# Called for the deletion of a branch
+#
+generate_delete_branch_email()
+{
+       echo "       was  $oldrev"
+       echo ""
+       echo $LOGEND
+       git show -s --pretty=oneline $oldrev
+       echo $LOGEND
+}
+
+# --------------- Annotated tags
+
+#
+# Called for the creation of an annotated tag
+#
+generate_create_atag_email()
+{
+       echo "        at  $newrev ($newrev_type)"
+
+       generate_atag_email
+}
+
+#
+# Called for the update of an annotated tag (this is probably a rare event
+# and may not even be allowed)
+#
+generate_update_atag_email()
+{
+       echo "        to  $newrev ($newrev_type)"
+       echo "      from  $oldrev (which is now obsolete)"
+
+       generate_atag_email
+}
+
+#
+# Called when an annotated tag is created or changed
+#
+generate_atag_email()
+{
+       # Use git for-each-ref to pull out the individual fields from the
+       # tag
+       eval $(git for-each-ref --shell --format='
+       tagobject=%(*objectname)
+       tagtype=%(*objecttype)
+       tagger=%(taggername)
+       tagged=%(taggerdate)' $refname
+       )
+
+       echo "   tagging  $tagobject ($tagtype)"
+       case "$tagtype" in
+       commit)
+
+               # If the tagged object is a commit, then we assume this is a
+               # release, and so we calculate which tag this tag is
+               # replacing
+               prevtag=$(git describe --abbrev=0 $newrev^ 2>/dev/null)
+
+               if [ -n "$prevtag" ]; then
+                       echo "  replaces  $prevtag"
+               fi
+               ;;
+       *)
+               echo "    length  $(git cat-file -s $tagobject) bytes"
+               ;;
+       esac
+       echo " tagged by  $tagger"
+       echo "        on  $tagged"
+
+       echo ""
+       echo $LOGBEGIN
+
+       # Show the content of the tag message; this might contain a change
+       # log or release notes so is worth displaying.
+       git cat-file tag $newrev | sed -e '1,/^$/d'
+
+       echo ""
+       case "$tagtype" in
+       commit)
+               # Only commit tags make sense to have rev-list operations
+               # performed on them
+               if [ -n "$prevtag" ]; then
+                       # Show changes since the previous release
+                       git rev-list --pretty=short "$prevtag..$newrev" | git shortlog
+               else
+                       # No previous tag, show all the changes since time
+                       # began
+                       git rev-list --pretty=short $newrev | git shortlog
+               fi
+               ;;
+       *)
+               # XXX: Is there anything useful we can do for non-commit
+               # objects?
+               ;;
+       esac
+
+       echo $LOGEND
+}
+
+#
+# Called for the deletion of an annotated tag
+#
+generate_delete_atag_email()
+{
+       echo "       was  $oldrev"
+       echo ""
+       echo $LOGEND
+       git show -s --pretty=oneline $oldrev
+       echo $LOGEND
+}
+
+# --------------- General references
+
+#
+# Called when any other type of reference is created (most likely a
+# non-annotated tag)
+#
+generate_create_general_email()
+{
+       echo "        at  $newrev ($newrev_type)"
+
+       generate_general_email
+}
+
+#
+# Called when any other type of reference is updated (most likely a
+# non-annotated tag)
+#
+generate_update_general_email()
+{
+       echo "        to  $newrev ($newrev_type)"
+       echo "      from  $oldrev"
+
+       generate_general_email
+}
+
+#
+# Called for creation or update of any other type of reference
+#
+generate_general_email()
+{
+       # Unannotated tags are more about marking a point than releasing a
+       # version; therefore we don't do the shortlog summary that we do for
+       # annotated tags above - we simply show that the point has been
+       # marked, and print the log message for the marked point for
+       # reference purposes
+       #
+       # Note this section also catches any other reference type (although
+       # there aren't any) and deals with them in the same way.
+
+       echo ""
+       if [ "$newrev_type" = "commit" ]; then
+               echo $LOGBEGIN
+               git show --no-color --root -s --pretty=medium $newrev
+               echo $LOGEND
+       else
+               # What can we do here?  The tag marks an object that is not
+               # a commit, so there is no log for us to display.  It's
+               # probably not wise to output git cat-file as it could be a
+               # binary blob.  We'll just say how big it is
+               echo "$newrev is a $newrev_type, and is $(git cat-file -s $newrev) bytes long."
+       fi
+}
+
+#
+# Called for the deletion of any other type of reference
+#
+generate_delete_general_email()
+{
+       echo "       was  $oldrev"
+       echo ""
+       echo $LOGEND
+       git show -s --pretty=oneline $oldrev
+       echo $LOGEND
+}
+
+
+# --------------- Miscellaneous utilities
+
+#
+# Show new revisions as the user would like to see them in the email.
+#
+show_new_revisions()
+{
+       # This shows all log entries that are not already covered by
+       # another ref - i.e. commits that are now accessible from this
+       # ref that were previously not accessible
+       # (see generate_update_branch_email for the explanation of this
+       # command)
+
+       # Revision range passed to rev-list differs for new vs. updated
+       # branches.
+       if [ "$change_type" = create ]
+       then
+               # Show all revisions exclusive to this (new) branch.
+               revspec=$newrev
+       else
+               # Branch update; show revisions not part of $oldrev.
+               revspec=$oldrev..$newrev
+       fi
+
+       other_branches=$(git for-each-ref --format='%(refname)' refs/heads/ |
+           grep -F -v $refname)
+       git rev-parse --not $other_branches |
+       if [ -z "$custom_showrev" ]
+       then
+               git rev-list --pretty --stdin $revspec
+       else
+               git rev-list --stdin $revspec |
+               while read onerev
+               do
+                       eval $(printf "$custom_showrev" $onerev)
+               done
+       fi
+}
+
+
+send_mail()
+{
+       if [ -n "$envelopesender" ]; then
+               /usr/sbin/sendmail -t -f "$envelopesender"
+       else
+               /usr/sbin/sendmail -t
+       fi
+}
+
+# ---------------------------- main()
+
+# --- Constants
+LOGBEGIN="- Log -----------------------------------------------------------------"
+LOGEND="-----------------------------------------------------------------------"
+
+# --- Config
+# Set GIT_DIR either from the working directory, or from the environment
+# variable.
+GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
+if [ -z "$GIT_DIR" ]; then
+       echo >&2 "fatal: post-receive: GIT_DIR not set"
+       exit 1
+fi
+
+projectdesc=$(sed -ne '1p' "$GIT_DIR/description")
+# Check if the description is unchanged from it's default, and shorten it to
+# a more manageable length if it is
+if expr "$projectdesc" : "Unnamed repository.*$" >/dev/null
+then
+       projectdesc="UNNAMED PROJECT"
+fi
+
+recipients=$(git config hooks.mailinglist)
+announcerecipients=$(git config hooks.announcelist)
+envelopesender=$(git config hooks.envelopesender)
+emailprefix=$(git config hooks.emailprefix || echo '[SCM] ')
+custom_showrev=$(git config hooks.showrev)
+
+# --- Main loop
+# Allow dual mode: run from the command line just like the update hook, or
+# if no arguments are given then run as a hook script
+if [ -n "$1" -a -n "$2" -a -n "$3" ]; then
+       # Output to the terminal in command line mode - if someone wanted to
+       # resend an email; they could redirect the output to sendmail
+       # themselves
+       PAGER= generate_email $2 $3 $1
+else
+       while read oldrev newrev refname
+       do
+               generate_email $oldrev $newrev $refname | send_mail
+       done
+fi
diff --git a/xemacs-packages/gnus/install-sh b/xemacs-packages/gnus/install-sh
new file mode 100755 (executable)
index 0000000..e843669
--- /dev/null
@@ -0,0 +1,250 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  M.I.T. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+       -c) instcmd="$cpprog"
+           shift
+           continue;;
+
+       -d) dir_arg=true
+           shift
+           continue;;
+
+       -m) chmodcmd="$chmodprog $2"
+           shift
+           shift
+           continue;;
+
+       -o) chowncmd="$chownprog $2"
+           shift
+           shift
+           continue;;
+
+       -g) chgrpcmd="$chgrpprog $2"
+           shift
+           shift
+           continue;;
+
+       -s) stripcmd="$stripprog"
+           shift
+           continue;;
+
+       -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+           shift
+           continue;;
+
+       -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+           shift
+           continue;;
+
+       *)  if [ x"$src" = x ]
+           then
+               src=$1
+           else
+               # this colon is to work around a 386BSD /bin/sh bug
+               :
+               dst=$1
+           fi
+           shift
+           continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+       echo "install:  no input file specified"
+       exit 1
+else
+       true
+fi
+
+if [ x"$dir_arg" != x ]; then
+       dst=$src
+       src=""
+       
+       if [ -d $dst ]; then
+               instcmd=:
+       else
+               instcmd=mkdir
+       fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+       if [ -f $src -o -d $src ]
+       then
+               true
+       else
+               echo "install:  $src does not exist"
+               exit 1
+       fi
+       
+       if [ x"$dst" = x ]
+       then
+               echo "install:  no destination specified"
+               exit 1
+       else
+               true
+       fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+       if [ -d $dst ]
+       then
+               dst="$dst"/`basename $src`
+       else
+               true
+       fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='   
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+       pathcomp="${pathcomp}${1}"
+       shift
+
+       if [ ! -d "${pathcomp}" ] ;
+        then
+               $mkdirprog "${pathcomp}"
+       else
+               true
+       fi
+
+       pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+       $doit $instcmd $dst &&
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+       if [ x"$transformarg" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               dstfile=`basename $dst $transformbasename | 
+                       sed $transformarg`$transformbasename
+       fi
+
+# don't allow the sed command to completely eliminate the filename
+
+       if [ x"$dstfile" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               true
+       fi
+
+# Make a temp file name in the proper directory.
+
+       dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+       $doit $instcmd $src $dsttmp &&
+
+       trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+       $doit $rmcmd -f $dstdir/$dstfile &&
+       $doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
diff --git a/xemacs-packages/gnus/lisp/.dir-locals.el b/xemacs-packages/gnus/lisp/.dir-locals.el
new file mode 100644 (file)
index 0000000..fb968e1
--- /dev/null
@@ -0,0 +1,4 @@
+((emacs-lisp-mode . ((show-trailing-whitespace . t))))
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
diff --git a/xemacs-packages/gnus/lisp/ChangeLog b/xemacs-packages/gnus/lisp/ChangeLog
new file mode 100644 (file)
index 0000000..5d9341f
--- /dev/null
@@ -0,0 +1,29107 @@
+2015-12-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml-sec.el (mml-secure-bcc-is-safe):
+       Don't use split-string with 4th arg for old Emacsen compatibility.
+
+2015-12-27  Jens Lechtenboerger  <jens.lechtenboerger@fsfe.org>
+
+       * gnus-util.el (gnus-subsetp): New function.
+
+       * mml-sec.el: Fix warnings by adding autoloads (bug#18718).
+       (mml-secure-safe-bcc-list): New variable.
+       (mml-secure-is-encrypted-p, mml-secure-bcc-is-safe): New functions.
+
+2015-12-27  Jens Lechtenboerger  <jens.lechtenboerger@fsfe.org>
+
+       * mml-sec.el (mml-secure-cust-record-keys):
+       Make gnus-union use `equal' to compare items in lists.
+
+2015-12-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       Fix `gnus-union' so as to behave like `cl-union'.
+
+       * gnus-group.el (gnus-group-prepare-flat):
+       Make gnus-union use `equal' to compare items in lists.
+
+       * gnus-util.el (gnus-union): Make it behave like cl-union partially.
+
+2015-12-17  Eli Zaretskii  <eliz@gnu.org>
+
+       * auth-source.el (auth-source-ensure-strings):
+       Don't make a list out of 't'.  (Bug#22188)
+
+2015-12-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (byte-optimize-apply): Make the use-mapcan advice work
+       for (function nconc) as well as (quote nconc).
+
+2015-12-17  Jens Lechtenboerger  <jens.lechtenboerger@fsfe.org>
+
+       * gnustest-mml-sec.el: Remove require cl.
+
+2015-12-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml-sec.el (mml-secure-smime-sign-with-sender): Remove duplicate.
+       (mml-secure-cust-record-keys): Use gnus-union instead of cl-union.
+       (mml1991-cache-passphrase, mml1991-passphrase-cache-expiry):
+       Suppress byte-compile warning for old (X)Emacsen.
+       (mml-secure-check-sub-key):
+       Use gnus-string-match-p instead of string-match-p.
+       (mml-secure-select-preferred-keys):
+       Don't use mapcan that is a cl runtime function.
+
+       * mml-smime.el (mml-smime-cache-passphrase)
+       (mml-smime-passphrase-cache-expiry):
+       * mml1991.el (mml1991-cache-passphrase)
+       (mml1991-passphrase-cache-expiry):
+       * mml2015.el (mml2015-cache-passphrase)
+       (mml2015-passphrase-cache-expiry):
+       Fix version that indicates when those variables were made obsolete.
+
+2015-12-13  Jens Lechtenboerger  <jens.lechtenboerger@fsfe.org>
+
+       Refactor mml-smime.el, mml1991.el, mml2015.el
+
+       Cf. discussion on ding mailing list, messages in
+       <http://thread.gmane.org/gmane.emacs.gnus.general/86228>.
+       Common code from the three files mml-smime.el, mml1991.el, and
+       mml2015.el is moved to mml-sec.el.  Auxiliary functions are added
+       to gnus-util.el.
+
+       The code is supported by test cases with necessary test keys.
+
+       Documentation in message.texi is updated.
+
+       * gnus-util.el (gnus-test-list, gnus-subsetp, gnus-setdiff):
+       New functions.
+
+       * mml-sec.el: Require gnus-util and epg.
+       (epa--select-keys): Autoload.
+       (mml-signencrypt-style-alist, mml-secure-cache-passphrase): Doc fix.
+       (mml-secure-openpgp-signers): New user option;
+       make mml1991-signers and mml2015-signers obsolete aliases to it.
+       (mml-secure-smime-signers): New user option;
+       make mml-smime-signers an obsolete alias to it.
+       (mml-secure-openpgp-encrypt-to-self): New user option;
+       make mml1991-encrypt-to-self and mml2015-encrypt-to-self obsolete
+       aliases to it.
+       (mml-secure-smime-encrypt-to-self): New user option;
+       make mml-smime-encrypt-to-self an obsolete alias to it.
+       (mml-secure-openpgp-sign-with-sender): New user option;
+       make mml2015-sign-with-sender an obsolete alias to it.
+       (mml-secure-smime-sign-with-sender): New user option;
+       make mml-smime-sign-with-sender an obsolete alias to it.
+       (mml-secure-openpgp-always-trust): New user option;
+       make mml2015-always-trust an obsolete alias to it.
+       (mml-secure-fail-when-key-problem, mml-secure-key-preferences):
+       New user options.
+       (mml-secure-cust-usage-lookup, mml-secure-cust-fpr-lookup)
+       (mml-secure-cust-record-keys, mml-secure-cust-remove-keys)
+       (mml-secure-add-secret-key-id, mml-secure-clear-secret-key-id-list)
+       (mml-secure-cache-passphrase-p, mml-secure-cache-expiry-interval)
+       (mml-secure-passphrase-callback, mml-secure-check-user-id)
+       (mml-secure-secret-key-exists-p, mml-secure-check-sub-key)
+       (mml-secure-find-usable-keys, mml-secure-select-preferred-keys)
+       (mml-secure-fingerprint, mml-secure-filter-keys)
+       (mml-secure-normalize-cust-name, mml-secure-select-keys)
+       (mml-secure-select-keys-1, mml-secure-signer-names, mml-secure-signers)
+       (mml-secure-self-recipients, mml-secure-recipients)
+       (mml-secure-epg-encrypt, mml-secure-epg-sign): New functions.
+
+       * mml-smime.el: Require epg;
+       refactor declaration and autoloading of epg functions.
+       (mml-smime-use): Doc fix.
+       (mml-smime-cache-passphrase, mml-smime-passphrase-cache-expiry):
+       Obsolete.
+       (mml-smime-get-dns-cert, mml-smime-get-ldap-cert):
+       Use format instead of gnus-format-message.
+       (mml-smime-epg-secret-key-id-list): Remove variable.
+       (mml-smime-epg-passphrase-callback, mml-smime-epg-find-usable-key)
+       (mml-smime-epg-find-usable-secret-key): Remove functions.
+       (mml-smime-epg-sign, mml-smime-epg-encrypt): Refactor.
+
+       * mml1991.el (mml1991-cache-passphrase)
+       (mml1991-passphrase-cache-expiry): Obsolete.
+       (mml1991-epg-secret-key-id-list): Remove variable.
+       (mml1991-epg-passphrase-callback, mml1991-epg-find-usable-key)
+       (mml1991-epg-find-usable-secret-key): Remove functions.
+       (mml1991-epg-sign, mml1991-epg-encrypt): Refactor.
+
+       * mml2015.el (mml2015-cache-passphrase)
+       (mml2015-passphrase-cache-expiry): Obsolete.
+       (mml2015-epg-secret-key-id-list): Remove variable.
+       (mml2015-epg-passphrase-callback, mml2015-epg-check-user-id)
+       (mml2015-epg-check-sub-key, mml2015-epg-find-usable-key)
+       (mml2015-epg-find-usable-secret-key): Remove functions.
+       (mml2015-epg-decrypt, mml2015-epg-clear-decrypt, mml2015-epg-sign)
+       (mml2015-epg-encrypt): Refactor.
+
+       * tests/gnustest-gnus-util.el:
+       * tests/gnustest-mml-sec.README:
+       * tests/gnustest-mml-sec.el:
+       * tests/mml-gpghome/gpg-agent.conf:
+       * tests/mml-gpghome/trustlist.txt: New files.
+
+2015-12-04  Daiki Ueno  <ueno@gnu.org>
+
+       * qp.el (quoted-printable-encode-region): Bind `case-fold-search' to
+       nil when looking for "^From ".  Problem reported by Simon Josefsson.
+
+2015-12-04  Artur Malabarba  <bruce.connor.am@gmail.com>
+
+       * sasl-scram-rfc.el: Add a "Package:" header.
+
+2015-11-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnml.el (nnml-retrieve-groups): Remove.  See:
+       <http://thread.gmane.org/gmane.emacs.gnus.general/86308> and
+       <http://thread.gmane.org/gmane.emacs.gnus.general/86321>
+
+2015-11-17  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Fix docstring quoting problems with ‘ '’
+
+       Problem reported by Artur Malabarba in:
+       http://lists.gnu.org/archive/html/emacs-devel/2015-11/msg01513.html
+       Most of these fixes are to documentation; many involve fixing
+       longstanding quoting glitches that are independent of the
+       recent substitute-command-keys changes.  The changes to code are:
+       * gnus-mlspl.el (gnus-group-split-fancy):
+       * hashcash.el (hashcash-extra-generate-parameters):
+       * message.el (message-qmail-inject-args, message-cite-reply-position):
+       * mm-decode.el (mm-inline-large-images):
+       * mm-util.el (mm-xemacs-find-mime-charset-1):
+
+2015-11-11  Eli Zaretskii  <eliz@gnu.org>
+
+       * mm-url.el (mm-url-form-encode-xwfu): Allow argument CHUNK to be nil.
+       (Bug#21881)
+
+2015-11-08  Michael Sperber  <mike@xemacs.org>
+
+       * gnus-sum.el (gnus-summary-backend-map): Bind B-backspace to
+       `gnus-summary-delete-article` in a way that also works on XEmacs.
+
+2015-11-01  Thomas Fitzsimmons  <fitzsim@fitzsim.org>
+
+       * ntlm.el: Change version to 2.0.0.
+
+2015-10-30  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       Silence lexical-binding warnings
+
+       * auth-source.el (auth-source-netrc-use-gpg-tokens):
+       Simplify (symbol-value 'VAR) to just VAR.
+       (auth-source-backend-parse): Use make-instance.
+       (auth-source-search): Remove unused key args.
+       Remove unused vars `accessor-key' and `backend'.  Avoid `eval'.
+       (auth-source-search-backends): Use slot names rather than their initarg.
+       (auth-source-netrc-create):
+       (auth-source-delete):
+       (auth-source-secrets-create, auth-source-plstore-search)
+       (auth-source-macos-keychain-create, auth-source-macos-keychain-search)
+       (auth-source-plstore-create, auth-source-netrc-search)
+       (auth-source-netrc-parse): Remove unused key args.
+       (auth-source-forget+): Simplify the arglist.
+       (auth-source-macos-keychain-search-items)
+       (auth-source-token-passphrase-callback-function): Mark unused args.
+       (auth-source-epa-extract-gpg-token): Remove unused var `plain'.
+       (pp-escape-newlines): Declare.
+       (auto-source--symbol-keyword): New function.
+       (auth-source-plstore-create, auth-source-netrc-create)
+       (auth-source-netrc-normalize): Use it.
+       (auth-source-netrc-search): Don't pass :delete to
+       auth-source-netrc-parse since it doesn't use it.
+       (auth-source-plstore-create, auth-source-netrc-create): Use plist-get
+       symbol-value to index in keyword args.
+       (auth-source-macos-keychain-result-append): Avoid setq.
+       (auth-source-netrc-create): Remove unused vars `file' and `add'.
+       (auth-source-user-or-password): Remove unused var `cname'.
+
+2015-10-28  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-topic.el (gnus-topic-prepare-topic): Remove unused var `topic'.
+       (gnus-topic-remove-topic): Mark unused arg `hide'.
+       (gnus-tmp-header): Declare.
+       (gnus-topic-goto-missing-group): Remove unused var `entry'.
+       (gnus-topic-unmark-topic): Mark unused arg `dummy'.
+       (gnus-topic-copy-matching): Mark unused arg `copyp'.
+       Move initialization of `topic' into its declaration.
+
+2015-10-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * auth-source.el: Revert.
+
+       * auth-source.el: Add eval-and-compile to autoloads for
+       epg-context-set-passphrase-callback, epg-decrypt-string,
+       epg-encrypt-string, and epg-context-set-armor.
+
+2015-10-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mailcap.el (mailcap-mime-data): Remove fboundp checks.
+       (mailcap-viewer-passes-test): Do it instead.  Thanks to Stefan Monnier.
+
+2015-10-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mailcap.el (mailcap-mailcap-entry-passes-test): Doc fix.
+
+2015-10-20  Michael Sperber  <mike@xemacs.org>
+
+       * mailcap.el (mailcap-mime-data): Conditonalize `doc-view-mode', which
+       does not exist on XEmacs.
+
+2015-10-18  Michael Sperber  <mike@xemacs.org>
+
+       * nnml.el (nnml-retrieve-groups, nnml-request-scan):
+       * nnmail.el (nnmail-get-new-mail-per-group):
+       (nnmail-get-new-mail-1): Unbreak `group' option for `mail-sources'.
+
+2015-10-18  Michael Sperber  <mike@xemacs.org>
+
+       * message.el (message-get-reply-headers): In addition to
+       `mail-dont-reply-to-names', bind `rmail-dont-reply-to-names', which is
+       used in XEmacs.
+
+2015-10-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * auth-source.el (auth-source-epa-make-gpg-token): Revert.
+
+2015-10-11  Nicolas Petton  <petton.nicolas@gmail.com>
+
+       * auth-source.el (auth-source-epa-make-gpg-token):
+       Replace an usage of `epg-context-set-armor' with `setf'.
+       (auth-source-do-debug, auth-source-do-trivia)
+       (auth-source-read-char-choice, auth-source-search)
+       (auth-source-pick-first-password, auth-source-netrc-parse)
+       (auth-source-netrc-search, auth-source-secrets-search)
+       (auth-source-macos-keychain-search)
+       (auth-source-macos-keychain-search-items, auth-source-plstore-search)
+       (auth-source-user-or-password): Use sharp-quoting with functions.
+
+2015-09-30  Wieland Hoffmann  <themineo@gmail.com>
+
+       * auth-source.el (auth-source-search): Clarify :create's meaning.
+
+2015-09-17  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Backslash cleanup in Elisp source files
+
+       This patch should not change behavior.  It typically omits backslashes
+       where they are redundant (e.g., in the string literal "^\$").
+       In a few places, insert backslashes where they make regular expressions
+       clearer: e.g., replace "^\*" (equivalent to "^*") with "^\\*", which
+       has the same effect as a regular expression.
+       Also, use ‘\ %’ instead of ‘\%’ when avoiding confusion with SCCS IDs,
+       and similarly use ‘\ $’ instead of ‘\$’ when avoiding confusion
+       with RCS IDs, as that makes it clearer that the backslash is intended.
+       * auth-source.el (auth-source-secrets-search)
+       (auth-source-macos-keychain-search):
+       * gnus-art.el (gnus-mime-action-on-part)
+       (gnus-mime-display-multipart-related-as-mixed)
+       (gnus-button-mid-or-mail-heuristic-alist)
+       (gnus-button-mid-or-mail-heuristic, gnus-article-extend-url-button):
+       * gnus-bookmark.el (gnus-bookmark-bmenu-toggle-infos)
+       (gnus-bookmark-bookmark-inline-details, gnus-bookmark-bookmark-details)
+       (gnus-bookmark-alist, gnus-bookmark-name-from-full-record)
+       (gnus-bookmark-bmenu-mode, gnus-bookmark-delete):
+       * gnus-cus.el (gnus-group-customize):
+       * gnus-group.el (gnus-group-line-format, gnus-group-mode-line-format)
+       (gnus-group-jump-to-group-prompt, gnus-group-name-at-point):
+       * gnus-mlspl.el (gnus-group-split-fancy):
+       * gnus-registry.el (gnus-registry-prune-factor):
+       * gnus-salt.el (gnus-summary-pick-line-format):
+       * gnus-sieve.el (gnus-sieve-update, gnus-sieve-generate)
+       (gnus-sieve-script):
+       * gnus-util.el (gnus-directory-sep-char-regexp):
+       * gnus.el (gnus-message-archive-group, gnus-user-agent):
+       * message.el (message-archive-header, message-reply-headers)
+       (message-send-method-alist):
+       * mm-decode.el (mm-add-meta-html-tag):
+       * nndoc.el (nndoc-generate-lanl-gov-head):
+       * nnheader.el (nnheader-max-head-length):
+       * registry.el (registry-db, registry-prune):
+       * rfc1843.el (rfc1843-hzp-word-regexp)
+       (rfc1843-hzp-word-regexp-strictly):
+       * rfc2047.el (rfc2047-encoded-word-regexp)
+       (rfc2047-encoded-word-regexp-loose):
+
+       Fix several backslash typos in Elisp strings
+       * gnus-art.el (gnus-button-handle-library):
+       * gnus-group.el (gnus-read-ephemeral-gmane-group-url):
+       * nntp.el (nntp-via-shell-prompt, nntp-telnet-shell-prompt):
+       * spam-report.el (spam-report-gmane-regex):
+       Fix typo by replacing ‘\’ with ‘\\’ in a string literal.
+       For example, to get the regular expression ‘\.’ use the string
+       literal "\\.", not "\." (which is equivalent to ".").
+
+       * auth-source.el (auth-source-read-char-choice):
+       * nnmaildir.el (NOV example):
+       * registry.el (registry-search): Doc fix.
+
+2015-09-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-compat.el: Require overlay for XEmacs.
+
+2015-09-12  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * message.el (message-hide-headers): Bind inhibit-modification-hooks to
+       t rather than after-change-functions to nil.
+
+2015-09-09  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * time-date.el (time-to-seconds, time-less-p):
+       Mark unused vars with underscore.
+
+2015-09-08  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * time-date.el (with-decoded-time-value): Fix debug spec.
+
+2015-09-08  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * nnmairix.el (nnmairix-widget-create-query):
+       * time-date.el (format-seconds): Prefer grave quoting in source-code
+       strings used to generate help and diagnostics.
+
+2015-09-07  Thomas Fitzsimmons  <fitzsim@fitzsim.org>
+
+       * ntlm.el: Bump version to 2.00.  New maintainer.  Add comm keyword.
+
+2015-09-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * ntlm.el (ntlm-unibyte-string): New compatibility function.
+
+2015-09-06  Thomas Fitzsimmons  <fitzsim@fitzsim.org>
+
+       Add support for NTLMv2 authentication.
+       * ntlm.el (ntlm): New customization group.
+       (ntlm-compatibility-level): New defcustom.
+       (ntlm-compute-timestamp): New function.
+       (ntlm-generate-nonce): Likewise.
+       (ntlm-build-auth-response): Add support for NTLMv2 authentication.
+
+2015-09-05  Eric Abrahamsen  <eric@ericabrahamsen.net>
+
+       * nnimap.el (nnimap-request-group): Handle nil "info" arg.  This arg
+       isn't always passed in, check it's not nil before making it into a
+       list.  The active arg will also be nil if the group is new, check for
+       that.
+
+2015-09-04  Adam Sjøgren  <asjo@koldfront.dk>
+
+       * mail-source.el (mail-source-fetch-imap): allow :mailbox to be a list.
+
+2015-09-03  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gmm-utils.el (gmm-image-load-path-for-library):
+       * gnus-art.el (gnus-boring-article-headers, gnus-split-methods):
+       * gnus-registry.el (gnus-registry-split-strategy):
+       * gnus-start.el (gnus-check-new-newsgroups):
+       * gnus-sum.el (gnus-select-group-hook):
+       * gnus-uu.el (gnus-uu-user-archive-rules):
+       * gnus.el (gnus-message-archive-group, gnus-visual):
+       * message.el (message-cite-style):
+       * nnir.el (nnir-swish++-additional-switches)
+       (nnir-swish-e-additional-switches, nnir-hyrex-additional-switches)
+       (nnir-namazu-additional-switches, nnir-notmuch-additional-switches):
+       * nnmail.el (nnmail-split-methods, nnmail-expiry-wait-function):
+       * nntp.el (nntp-server-action-alist):
+       * tls.el (tls-checktrust):
+       Fix some more docstring etc. quoting problems.
+       Mostly these fixes prevent the transliteration of apostrophes
+       that should stay apostrophes.  Also, prefer curved quotes in
+       Bahá’í proper names, as that’s the preferred Bahá’í style and
+       these names are chock-full of non-ASCII characters anyway.
+
+2015-09-02  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Escape ` and ' in doc
+       * gnus-art.el (gnus-article-address-banner-alist)
+       (gnus-face-properties-alist):
+       * gnus-sum.el (gnus-newsgroup-variables):
+       * nndiary.el (nndiary-reminders):
+       * nnmail.el (nnmail-fancy-expiry-targets, nnmail-split-fancy):
+       Escape apostrophes and grave accents in docstrings if they
+       are supposed to stand for themselves and are not quotes.  Remove
+       apostrophes from docstring examples like ‘'(calendar-nth-named-day
+       -1 0 10 year)’ that confuse source code with data.  Do some other
+       minor docstring fixups as well, e.g., insert a missing close
+       quote.
+
+2015-09-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-format-message):
+       * tls.el (tls-format-message): Use defalias at the top level so as to
+       make eval-and-compile unnecessary.  Thanks to Stefan Monnier.
+
+       * gnus-sum.el (gnus-summary-search-article):
+       Ensure that the article where the search word is found is displayed
+       and pointed to in the summary buffer.
+
+2015-08-31  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * tls.el (tls-format-message):
+       Alias to format-message, or format if not available.
+       (open-tls-stream): Use it.
+
+2015-08-31  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-agent.el (gnus-agent-possibly-synchronize-flags-server):
+       * gnus-art.el (gnus-article-browse-delete-temp-files):
+       * gnus-eform.el (gnus-edit-form):
+       * gnus-fun.el (gnus-display-x-face-in-from):
+       * gnus-group.el (gnus-group-edit-group, gnus-group-nnimap-edit-acl):
+       * gnus-topic.el (gnus-topic-edit-parameters):
+       * mail-source.el (mail-source-delete-old-incoming):
+       * message.el (message-strip-subject-encoded-words)
+       (message-check-recipients, message-send-form-letter):
+       * mm-decode.el (mm-display-part):
+       * mm-uu.el (mm-uu-pgp-signed-extract-1):
+       * mml-smime.el (mml-smime-get-dns-cert, mml-smime-get-ldap-cert):
+       * spam-report.el (spam-report-process-queue):
+       * tls.el (open-tls-stream):
+       Respect ‘text-quoting-style’ in diagnostics.
+       * gnus-art.el (article-display-face):
+       * gnus-fun.el (gnus-display-x-face-in-from):
+       Use straight quoting in email.
+       * rfc2231.el (rfc2231-decode-encoded-string):
+       Escape apostrophes in doc strings.
+
+2015-08-26  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Go back to grave quoting in Gnus
+
+       * auth-source.el (auth-source-netrc-parse-entries):
+       * gnus-agent.el (gnus-agent-check-overview-buffer)
+       (gnus-agent-fetch-headers):
+       * gnus-int.el (gnus-start-news-server):
+       * gnus-registry.el (gnus-registry--split-fancy-with-parent-internal)
+       (gnus-registry-post-process-groups):
+       * gnus-score.el (gnus-summary-increase-score):
+       * gnus-start.el (gnus-convert-old-newsrc):
+       * gnus-topic.el (gnus-topic-rename):
+       * legacy-gnus-agent.el (gnus-agent-unlist-expire-days):
+       * spam.el (spam-check-blackholes):
+       Stick with grave quoting in diagnostics strings.  This is more
+       portable to older Emacs, desirable for Gnus.
+
+2015-08-25  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Prefer directed to neutral quotes in docstings and diagnostics.
+       In docstrings, escape apostrophes that would otherwise be translated
+       to curved quotes using the newer, simpler rules.
+
+       * auth-source.el (auth-source-netrc-parse-entries):
+       * gnus-agent.el (gnus-agent-check-overview-buffer)
+       (gnus-agent-fetch-headers):
+       * gnus-int.el (gnus-start-news-server):
+       * gnus-registry.el (gnus-registry--split-fancy-with-parent-internal):
+       * gnus-score.el (gnus-summary-increase-score):
+       * gnus-start.el (gnus-convert-old-newsrc):
+       * gnus-topic.el (gnus-topic-rename):
+       * legacy-gnus-agent.el (gnus-agent-unlist-expire-days):
+       * nnmairix.el (nnmairix-widget-create-query):
+       * spam.el (spam-check-blackholes):
+       Use directed rather than neutral quotes in diagnostics.
+
+       * gnus-util.el (gnus-format-message):
+       Alias to format-message, or format if not available.
+
+2015-08-21  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * auth-source.el (auth-sources):
+       Prefer (substitute-command-keys "`\\[foo-command]'")
+       to "`M-x foo-command'" in docstring.
+
+       * time-date.el (format-seconds):
+       Use curved quotes in diagnostic format strings.
+
+       * nnmairix.el (nnmairix-propagate-marks-upon-close):
+       * pop3.el (pop3-authentication-scheme):
+       Don't quote symbols with apostrophes in doc strings.
+       Use asymmetric quotes instead.
+
+2015-08-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       Use overlay functions directly
+
+       * dgnushack.el (overlay): Autoload overlay functions for XEmacs.
+       * lpath.el (delete-overlay, overlay-lists): Remove Fbind.
+
+       * gnus-art.el (gnus-mime-inline-part, gnus-mm-display-part)
+       (gnus-insert-mime-button, gnus-mime-buttonize-attachments-in-header)
+       (gnus-article-highlight-signature, gnus-article-extend-url-button)
+       (gnus-article-add-button, gnus-insert-prev-page-button)
+       (gnus-insert-next-page-button, gnus-insert-mime-security-button):
+       * gnus-cite.el (gnus-cite-delete-overlays, gnus-cite-add-face):
+       * gnus-html.el (gnus-html-wash-tags):
+       * gnus-salt.el (gnus-tree-read-summary-keys, gnus-tree-recenter)
+       (gnus-highlight-selected-tree):
+       * gnus-sum.el (gnus-summary-show-all-threads, gnus-summary-show-thread)
+       (gnus-summary-hide-thread, gnus-highlight-selected-summary):
+       * gnus-util.el (gnus-put-overlay-excluding-newlines):
+       * message.el (message-fix-before-sending)
+       (message-toggle-image-thumbnails):
+       * mm-decode.el (mm-convert-shr-links):
+       * sieve.el (sieve-highlight, sieve-insert-scripts):
+       Use overlay functions directly instead of using gnus-overlay-*,
+       message-overlay-*, and sieve-overlay-*.
+
+       * gnus-sum.el (gnus-remove-overlays):
+       * gnus-xmas.el (gnus-xmas-move-overlay, gnus-xmas-overlays-at)
+       (gnus-xmas-overlays-in, gnus-make-overlay, gnus-copy-overlay)
+       (gnus-delete-overlay, gnus-overlay-get, gnus-overlay-put)
+       (gnus-move-overlay, gnus-overlay-buffer, gnus-overlay-start)
+       (gnus-overlay-end, gnus-overlays-at, gnus-overlays-in):
+       * gnus.el (gnus-make-overlay, gnus-copy-overlay, gnus-delete-overlay)
+       (gnus-overlay-get, gnus-overlay-put, gnus-move-overlay)
+       (gnus-overlay-buffer, gnus-overlay-start, gnus-overlay-end)
+       (gnus-overlays-at, gnus-overlays-in):
+       * message.el (message-delete-overlay, message-make-overlay)
+       (message-overlay-get, message-overlay-put, message-overlays-in):
+       * messagexmas.el (message-delete-overlay, message-make-overlay)
+       (message-overlay-get, message-overlay-put, message-overlays-in):
+       * sieve.el (sieve-make-overlay, sieve-overlay-put, sieve-overlays-at):
+       Remove.
+
+2015-08-19  Glenn Morris  <rgm@gnu.org>
+
+       * nnmaildir.el (nnmaildir-flag-mark-mapping): Add "P".
+
+2015-08-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-overlay-put, message-make-overlay)
+       (message-kill-all-overlays, message-overlays-in, message-overlay-get)
+       (message-delete-overlay, message-window-inside-pixel-edges):
+       Declare before using.
+
+2015-08-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-overlay-get, message-overlays-in)
+       (message-window-inside-pixel-edges):
+       * messagexmas.el (message-overlay-get, message-overlays-in):
+       XEmacs compatible functions.
+
+2015-08-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-toggle-image-thumbnails): New command.
+
+2015-08-06  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * message.el (message-send-form-letter): Change (message (format ...))
+       to (message ...).  This lessens the probability of confusion when
+       the output of `format' contains `%'.
+
+2015-08-04  David Kastrup  <dak@gnu.org>
+
+       * gnus-art.el (gnus-article-describe-key)
+       (gnus-article-describe-key-briefly):
+       Do not overwrite preexisting contents of unread-command-events.
+
+2015-08-02  Nikolaus Rath  <Nikolaus@rath.org>
+
+       * nnimap.el (nnimap-request-move-article)
+       (nnimap-process-expiry-targets, nnimap-split-incoming-mail): Use MOVE
+       extension if available.
+
+2015-08-02  Nikolaus Rath  <Nikolaus@rath.org>
+
+       * nnimap.el (nnimap-open-connection-1): explicitly ask server for
+       capabilities instead of relying on LOGIN response.
+
+2015-07-31  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * nnbabyl.el (nnbabyl-retrieve-headers):
+       * nndiary.el (nndiary-retrieve-headers):
+       * nneething.el (nneething-retrieve-headers):
+       * nnmbox.el (nnmbox-retrieve-headers):
+       * nnmh.el (nnmh-retrieve-headers):
+       * nnml.el (nnml-retrieve-headers):
+       * nnspool.el (nnspool-retrieve-headers):
+       * nntp.el (nntp-retrieve-headers, nntp-retrieve-articles):
+       Prefer (floor (* 100.0 NUMERATOR) DENOMINATOR) when calculating
+       progress-report percentages and the like.  This avoids problems
+       if (* 100 NUMERATOR) would overflow.
+
+       * gnus-registry.el (gnus-registry-import-eld):
+       * registry.el (registry-reindex):
+       Use (* 100.0 ...) rather than (* 100 ...) to avoid int overflow issues.
+
+2015-07-17  Julien Danjou  <jd@abydos>
+
+       * sieve-mode.el (sieve-font-lock-keywords): Add missing "body" test
+       command.
+
+2015-07-11  Eric Abrahamsen  <eric@ericabrahamsen.net>
+
+       * gnus-registry.el (gnus-registry--set/remove-mark): Correct the order
+       of function arguments.
+
+2015-07-10  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * nnimap.el: Clean up "unused var" warnings.
+       (auth-source-creation-prompts): Declare.
+       (nnimap-retrieve-headers, nnimap-status-message)
+       (nnimap-request-create-group, nnimap-request-delete-group)
+       (nnimap-close-group, nnimap-request-move-article)
+       (nnimap-request-accept-article, nnimap-request-newgroups)
+       (nnimap-request-post, nnimap-dummy-active-number)
+       (nnimap-save-mail-spec, nnimap-get-groups): Add _ to unused vars.
+       (nnimap-parse-flags): Remove unused var `p'.
+       (nnimap-retrieve-group-data-early): Remove unused var `groups'.
+       (nnimap-flags-to-marks): Remove unused var `totalp'.
+
+2015-07-09  Nikolaus Rath  <Nikolaus@rath.org>
+
+       * nnimap.el (nnimap-transform-headers): Don't assume that UID comes
+       before RFC822.SIZE.
+
+2015-07-09  Nikolaus Rath  <Nikolaus@rath.org>
+
+       * nnimap.el (nnimap-open-connection-1): Always query capabilities,
+       so that a 'plain value for the `nnimap-stream' server variable is
+       handled correctly.
+
+2015-07-08  Eric Abrahamsen  <eric@ericabrahamsen.net>
+
+       Remove unused let variables
+       * nnimap.el (nnimap-request-group): Variables are not used.
+
+       Check if group names are already strings
+       * gnus-group.el (gnus-group-group-name):
+       The group name may already be a string.
+       Specifically, in the group list reached from the *Server* buffer,
+       the 'gnus-group text property returns a string.  Everywhere else
+       it returns a symbol.
+
+2015-06-24  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * nnmaildir.el (nnmaildir--prepare): Use a more functional style.
+       (nnmaildir--update-nov): Remove unused var `numdir'.
+       (nnmaildir-request-type, nnmaildir--scan, nnmaildir-request-newgroups)
+       (nnmaildir-request-group, nnmaildir-request-create-group)
+       (nnmaildir-request-post, nnmaildir-request-move-article)
+       (nnmaildir-request-accept-article, nnmaildir-active-number):
+       Mark unused args.
+       (nnmaildir-get-new-mail, nnmaildir-group-alist, nnmaildir-active-file):
+       Declare.
+       (nnmaildir-request-scan): Remove unused vars `group' and `grp-dir'.
+       (nnmaildir-request-update-info): Remove unused vars `dotfile', `num',
+       `mark', `end', `new-mark', and `mark-sym'.
+       (nnmaildir-retrieve-headers):
+       Remove unused args `srv-dir', `dir', `nlist2'.
+       (nnmaildir-request-expire-articles):
+       Remove unused vars `article', `stop' and `nlist2'.
+       (nnmaildir-request-set-mark): Remove unused vars `begin', `article' and
+       `end'.  Use nnmaildir--article when dyn-binding is needed.
+       Give the value directly in the `let' for `del-mark', `del-action',
+       `add-action', and `set-action'.  Don't use `add-to-list' on a local var.
+       (nnmaildir-close-server):
+       Declare those local vars that need to be dyn-bound.
+
+2015-06-03  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-art.el (gnus-button-alist): Also support quotes 'like this'.
+
+2015-05-31  David Engster  <deng@randomsample.de>
+
+       * tests/gnustest-nntp.el (gnustest-ping-host): Call 'sleep' binary
+       instead of using `sleep-for', as the latter does not seem to reliably
+       wait (see for instance bug 15990).
+
+2015-05-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-button-alist): Re-revert last change.
+       cf. <http://news.gmane.org/group/gmane.emacs.devel/thread=186896>
+
+2015-05-28  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-art.el (gnus-button-alist): Revert last change.
+       It wasn't that important, and it caused a Gnus build to fail.  See:
+       http://www.randomsample.de:4456/builders/emacs-devel/builds/734
+
+       * gnus-art.el (gnus-button-alist):
+       Also treat "‘" and "’" as quoting chars.
+
+2015-05-19  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-art.el (gnus-treat-strip-list-identifiers)
+       (gnus-article-mode-syntax-table):
+       * gnus-group.el (gnus-group-nnimap-edit-acl):
+       * canlock.el, deuglify.el: Fix minor quoting problems in doc strings,
+       e.g., missing quote, ``x'' where `x' was meant, etc.
+
+2015-05-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * format-spec.el (format-spec, format-spec-make): Work for XEmacs.
+       Use (char-to-int c) instead of (+ c 0) that the byte compiler optimizes
+       into just c.
+
+2015-05-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * format-spec.el (format-spec, format-spec-make): Work for XEmacs.
+       Normalize characters into numbers in spec keys.
+
+2015-05-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (declare-function): Redefine it to use autoload.
+       * lpath.el (gnus-html-prefetch-images): Declare.
+
+2015-05-04  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-art.el (nneething-get-file-name): Declare rather than autoload.
+
+       * gnus-async.el (gnus-html-prefetch-images): Remove pointless autoload.
+
+       * gnus-sync.el (gnus-group-topic): Autoload at run-time.
+       (gnus-topic-create-topic, gnus-topic-enter-dribble):
+       Declare rather than autoload.
+
+       * mm-archive.el (gnus-recursive-directory-files)
+       (mailcap-extension-to-mime): Autoload at run-time.
+
+       * mm-util.el (latin-unity-massage-name)
+       (latin-unity-maybe-remap, latin-unity-representations-feasible-region)
+       (latin-unity-representations-present-region):
+       Declare rather than autoload.
+
+       * mml-smime.el (epg-make-context, epg-passphrase-callback-function):
+       Autoload at run-time.
+       (epg-context-set-signers, epg-context-result-for)
+       (epg-new-signature-digest-algorithm, epg-verify-result-to-string)
+       (epg-list-keys, epg-verify-string, epg-sign-string, epg-encrypt-string)
+       (epg-context-set-passphrase-callback, epg-sub-key-fingerprint)
+       (epg-configuration, epg-expand-group, epa-select-keys):
+       Declare rather than autoload.
+
+       * nnir.el (nnimap-change-group, nnimap-make-thread-query):
+       Autoload at run-time.
+       (gnus-group-topic-name, nnimap-buffer, nnimap-command)
+       (gnus-registry-get-id-key, gnus-registry-action):
+       Declare rather than autoload.
+
+       * nnmail.el (mail-send-and-exit): Autoload at run-time.
+
+       * spam.el (spam-stat-buffer-change-to-non-spam)
+       (spam-stat-buffer-change-to-spam, spam-stat-buffer-is-non-spam)
+       (spam-stat-buffer-is-spam, spam-stat-load, spam-stat-save)
+       (spam-stat-split-fancy): Remove pointless autoloads.
+
+       * mm-view.el (epg-decrypt-string): Autoload.
+       * mml-smime.el (epg-key-sub-key-list, epg-sub-key-capability)
+       (epg-sub-key-validity): Fix declarations.
+
+2015-05-01  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Ma Gnus v0.13 is released.
+
+2015-05-01  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-util.el (iswitchb-read-buffer):
+       * mm-decode.el (libxml-parse-html-region):
+       * mml.el (libxml-parse-html-region):
+       * nnrss.el (libxml-parse-html-region): Update declaration.
+
+2015-04-27  Glenn Morris  <rgm@gnu.org>
+
+       * message.el (gnus-extract-address-components):
+       Remove bogus declaration that was masking previous problem.
+
+2015-04-25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * hashcash.el (hashcash-insert-payment-async-2): Save the mark when
+       altering the buffer.
+       (hashcash-insert-payment-async-2): Revert previous change because it
+       still means that the mark is moving around.
+
+2015-04-15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-uu.el (gnus-uu-save-article):
+       Make the save-restriction/widen calls make more sense.
+
+2015-04-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-use-idna):
+       * gnus-sum.el (gnus-summary-idna-message):
+       * message.el (message-use-idna):
+       Catch the invalid-operation error that idna.el will issue.
+
+2015-04-14  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-group.el (gnus-group--setup-tool-bar-update):
+       cursor-sensor-functions should be a list of functions.
+
+2015-04-13  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-group.el (gnus-tmp-*): Declare.
+       (gnus-update-group-mark-positions): Remove unused `topic' var.
+       (gnus-group-insert-group-line): Remove unused var `header'.
+       (gnus-group--setup-tool-bar-update): New function.
+       (gnus-group-insert-group-line): Use it.
+       (gnus-group-update-eval-form): Declare local
+       dynamically-bound variables.
+       (gnus-group-unsubscribe-group): Use \` and \' to match string bounds.
+
+       * gnus-topic.el (gnus-topic-jump-to-topic)
+       (gnus-group-prepare-topics, gnus-topic-update-topic)
+       (gnus-topic-change-level, gnus-topic-catchup-articles)
+       (gnus-topic-remove-group, gnus-topic-delete, gnus-topic-indent):
+       Use inhibit-read-only.
+       (gnus-topic-prepare-topic): Use gnus-group--setup-tool-bar-update.
+       (gnus-topic-mode): Use define-minor-mode and derived-mode-p.
+
+2015-04-12  João Távora  <joaotavora@gmail.com>
+
+       * message.el (message-mode):
+       Use `set' and `make-local-variable' instead of `setq-local'.
+
+2015-04-12  Johan Bockgård  <bojohan@gnu.org>
+
+       * gnus-sum.el (gnus-summary-refer-thread):
+       Make sure gnus-newsgroup-unreads remains sorted.
+
+2015-04-12  João Távora  <joaotavora@gmail.com>
+
+       Improve sexp-based movement in message-mode
+       * message.el (message--syntax-propertize): New function.
+       (message-mode): Set syntax-related vars.d
+       (message-smileys): New variable.
+
+2015-04-10  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-art.el (gnus-hidden-properties): Simplify.
+       (gnus-article-hide-text, gnus-article-unhide-text)
+       (gnus-article-unhide-text-type): Remove special handling of
+       `intangible' since that property is not used any more.
+       (gnus-article-treat-body-boundary): Use gnus-hidden-properties.
+
+2015-04-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (define-obsolete-function-alias): Add a compiler-marco
+       and a runtime function for it, of which the XEmacs version takes only
+       two arguments.
+
+2015-04-06  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Use American spelling for 'normalize'
+       * rtree.el (rtree-normalize-range): Rename from rtree-normalise-range.
+       All uses changed.  Add an alias for obsolete usages.
+
+2015-04-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-browse-html-save-cid-content):
+       Always return relative file name.
+       (gnus-article-browse-html-parts):
+       Make external links absolute and cid file names relative.
+
+2015-04-01  Eric Abrahamsen  <eric@ericabrahamsen.net>
+
+       * registry.el (registry-prune): Re-use `registry-full' in
+       `registry-prune'.  It's a bit of redundant work, but safer.
+       Also ensure that target-size is an integer.
+
+2015-03-31  Daiki Ueno  <ueno@gnu.org>
+
+       * plstore.el (plstore--decrypt): Clear entry in
+       `plstore-passphrase-alist' if decryption failed (bug#20030).
+
+2015-03-28  Adam Sjøgren  <asjo@koldfront.dk>
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Add "Display HTML images"
+       to "Display" menu.
+
+2015-03-24  Eric Abrahamsen  <eric@ericabrahamsen.net>
+
+       * nnimap.el (nnimap-split-incoming-mail): If a message is already
+       in the group it should be split to, don't re-copy it into the group.
+
+2015-03-23  Ben Bacarisse  <ben.lists@bsb.me.uk>  (tiny change)
+
+       * nnmh.el (nnmh-request-expire-articles):
+       Work for the case nnmail-expiry-target is an nnmh group (bug#20170).
+
+2015-03-21  Eric Abrahamsen  <eric@ericabrahamsen.net>
+
+       * registry.el (registry-lookup-secondary, registry-full)
+       (registry-prune, registry-collect-prune-candidates):
+       * gnus-registry.el (gnus-registry-load): Use slot names rather than
+       initarg names in `oref' and `oset'.
+
+2015-03-19  Eric Abrahamsen  <eric@ericabrahamsen.net>
+
+       * registry.el (registry-prune): Allow registry to reach full size
+       before pruning.
+
+2015-03-19  Eric Abrahamsen  <eric@ericabrahamsen.net>
+
+       * registry.el (registry-collect-prune-candidates): Fix call to
+       cl-subseq.
+
+2015-03-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * registry.el (registry-db): Temporary fix old Emacsen compilation.
+
+2015-03-11  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-registry.el (gnus-registry-handle-action)
+       (gnus-registry-post-process-groups): Don't add-to-list on a local var.
+       (gnus-registry-keywords): Make it do something.
+       (gnus-registry-import-eld): Remove unused var `new-entry'.
+       (gnus-registry-action): Remove unused var `to-name'.
+       (gnus-registry-make-db): Prefer `make-instance' to avoid
+       compiler warnings.
+       (gnus-registry-load, gnus-registry-fixup-registry): Avoid `oset'.
+
+       * registry.el (registry-db): Don't oset-default an instance-allocated
+       slot.
+
+2015-03-10  Glenn Morris  <rgm@gnu.org>
+
+       * message.el (message-valid-fqdn-regexp): Bump :version for
+       2014-11-17 change.
+
+2015-03-07  Rasmus Pank Roulund  <rasmus@pank.eu>
+
+       * gnus-notifications.el (gnus-notifications-action): Raise window
+       frame.
+       (gnus-notifications-action): Allow mark as read.
+       (gnus-notifications-notify): Show uption to mark as read.
+
+2015-03-07  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * registry.el (registry-lookup-breaks-before-lexbind, registry-lookup)
+       (registry-search, registry-delete, registry-size, registry-insert)
+       (registry-reindex, registry-collect-prune-candidates):
+       * gnus-registry.el (gnus-registry-fixup-registry)
+       (gnus-registry-remove-extra-data): Use slot names rather than initarg
+       names in `oref' and `oset'.
+
+2015-02-27  Eric Abrahamsen  <eric@ericabrahamsen.net>
+       * lisp/nnimap.el (nnimap-split-incoming-mail): If a message is already
+       in the group it should be split to, don't re-copy it into the group.
+
+2015-02-25  Adam Sjøgren  <asjo@koldfront.dk>
+
+       * message.el (message-insert-formatted-citation-line): Change %F to
+       fall back to email address if no first name could be determined.
+
+2015-02-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-inline-part, gnus-mm-display-part):
+       Fix point motion when removing displayed MIME part.
+       (gnus-article-edit-part): Make jumping to the next part really work
+       when deleting or stripping.
+       (gnus-mime-buttonize-attachments-in-header): Make header attachment
+       buttons identical to the ones in the article body so as to work deleting
+       and stripping.
+
+2015-02-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-shr)
+       * mm-view.el (mm-inline-text-html-render-with-w3m):
+       Revert my bogus change that made the start marker of a part
+       the "moves after insertion" type.
+
+2015-02-23  Tassilo Horn  <tsdh@gnu.org>
+
+       * mailcap.el (mailcap-mime-data): Support `pdf-view-mode' (from PDF
+       Tools: https://github.com/politza/pdf-tools) for viewing PDF
+       attachments in emacs.
+
+2015-02-23  Magnus Henoch  <magnus.henoch@gmail.com>
+
+       * sasl.el (sasl-mechanism-alist): Refer to sasl-scram-rfc
+       instead of sasl-scram-sha-1, as the former is the name that can be
+       required.
+
+       * sasl-scram-rfc.el (sasl-scram-sha-1-steps)
+       (sasl-scram-sha-1-client-final-message)
+       (sasl-scram-sha-1-authenticate-server): Move to end of file.
+
+2015-02-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-display-single): Avoid "End of buffer" error.
+
+2015-02-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * sasl-scram-rfc.el (sasl-cl-coerce, sasl-cl-mapcar-many, sasl-cl-map)
+       (sasl-string-prefix-p): New compatibility functions.
+
+2015-02-15  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-compat.el (process-live-p): Added new compat function for Emacs
+       23.
+
+2015-02-14  Eric Abrahamsen  <eric@ericabrahamsen.net>
+
+       * nnimap.el (nnimap-get-groups): Correctly read unquoted group names
+       from the server LIST response.
+
+2015-02-14  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-retrieve-headers): If the server closes connection
+       during header retrieval, error out instead of interpreting the data in
+       the buffer as the only messages there.  This way, we don't mark
+       articles as read on a server hangup (bug#19035).
+
+       * mm-decode.el (mm-head-p): New function.
+       (mm-display-part): Go to a blank line when inserting parts internally.
+
+2015-02-13  Magnus Henoch  <magnus.henoch@gmail.com>
+
+       * sasl-scram-rfc.el: New file.
+
+       * sasl.el (sasl-mechanisms): Remove SCRAM-MD5.
+       Add SCRAM-SHA-1 first.
+       (sasl-mechanism-alist): Remove SCRAM-MD5 entry.  Add SCRAM-SHA-1
+       entry (bug#17636).
+
+2015-02-13  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-msg-mail): Don't let-bind `gnus-newsgroup-name' so
+       that we don't get a warning when setting the buffer-local variable
+       (bug#19573).
+
+       * nnmail.el (nnmail-expiry-target-group): Supply the info structure to
+       `gnus-request-group'.
+
+2015-02-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-browse-html-save-cid-content)
+       (gnus-article-browse-html-parts): Make cid file names relative if and
+       only if html doesn't specify <base> directory.
+
+2015-02-11  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-treat-buttonize): Don't re-buttonize URLs in HTML
+       parts, because that breaks filling (since buttons are in a bold face).
+
+2015-02-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-convert-shr-links): Delete useless variable `face';
+       use gnus-overlays-at and gnus-overlay-put.
+
+2015-02-10  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-shr): Only pass the fill column when not using
+       fonts, because limiting the width to what's appropriate for followups
+       doesn't really help when not using proportional fonts.
+
+2015-02-09  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-convert-shr-links): Don't overwrite the faces from
+       shr, beacause that breaks folding.
+       (mm-shr): Don't shorten the width when using fonts.
+
+2015-02-05  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-start.el (gnus-save-newsrc-file-check-timestamp): Remove
+       variable; always check the newrc timestamp.
+       (gnus-save-newsrc-file): Always check timestamp.
+
+2015-02-05  Timo Lilja  <timo.lilja@iki.fi>  (tiny change)
+
+       * mail-source.el (mail-source-call-script): If scripts exit with an
+       error, pop up an error buffer.
+
+2015-02-05  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-extra-headers): Add the popular Gmail X-GM-LABELS
+       as a default.
+
+       * nnimap.el (nnimap-request-group-scan): Ensure that we've selected the
+       correct server.
+
+2015-02-05  Vincent Bernat  <bernat@luffy.cx>  (tiny change)
+
+       * nnimap.el (nnimap-request-group-scan): Fix the function name.
+
+       * gnus-int.el (gnus-request-group-scan): Use the correct function name.
+
+2015-02-05  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-select-newsgroup): Pass the group info along so
+       that nnimap works for non-activated backends.
+
+2015-02-04  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * mm-util.el (mm-with-unibyte-current-buffer): Don't emit a warning
+       message, since we already get an obsolescence message.  Use `declare'.
+
+2015-02-04  Eric Abrahamsen  <eric@ericabrahamsen.net>
+
+       * nnir.el: Revert "Enable non-ASCII IMAP searches".
+
+2015-01-30  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-registry.el (gnus-registry-max-pruned-entries)
+       (gnus-registry-prune-factor, gnus-registry-default-sort-function):
+       Fix :version.
+       (gnus-registry-default-sort-function): Improve :type.
+
+2015-01-29  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-request-group): Allow running this function on
+       groups that don't exist in Gnus yet.
+       (nnimap-request-group): Revert previous patch since that made it
+       impossible to enter nnimap groups.
+
+       * message.el (message-smtpmail-send-it): Remove the mail header
+       separator before sending.
+
+2015-01-28  Elias Oltmanns  <eo@nebensachen.de>
+
+       * nnimap.el (nnimap-find-expired-articles): Fix handling of
+       (expiry-wait . never).
+
+2015-01-28  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-request-group): Clear the buffer before returning
+       the data.
+
+2015-01-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-compat.el (string-bytes): Work for XEmacs.
+
+2015-01-27  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-compat.el (string-bytes): Avoid compilation error on XEmacs.
+
+       * nnir.el (nnir-imap-expr-to-imap): Check for literal+ capability in
+       IMAP.
+
+2015-01-27  Eric Abrahamsen  <eric@ericabrahamsen.net>
+
+       * nnir.el (nnir-run-imap): Enable non-ASCII IMAP searches.
+
+       * nnmairix.el ("nnmairix"): Declare nnmairix as virtual.
+
+       * gnus-bcklg.el (gnus-backlog-enter-article): No virtual groups should
+       be added to the backlog.
+
+2015-01-26  Tassilo Horn  <tsdh@gnu.org>
+
+       * Makefile.in (all total, warn, fail-on-warning): Call gnus-load.el
+       target with a recursive make call.
+
+2015-01-26  Trevor Murphy  <trevor.m.murphy@gmail.com>
+
+       * nnimap.el (nnimap-header-parameters): Refactor and request
+       X-GM-LABELS if it's been announced.
+       (nnimap-transform-headers): Gather and output GM-LABELS.
+
+2014-12-30  Peder O. Klingenberg  <peder@klingenberg.no>
+
+       * mm-decode.el (mm-display-part): Make non-string methods work.
+       Non-string methods are funcalled and work just fine, the test was
+       bogus.
+       * mm-decode.el (mm-display-external): Show "external" lisp viewers in
+       whole frame.
+
+2015-01-26  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-request-accept-article): Allow respooling using
+       nnimap.
+
+       * gnus-group.el (gnus-group-get-new-news-this-group): Explicitly
+       request rescans when being run interactively.
+
+       * nnimap.el (nnimap-request-group): Don't rescan the group here,
+       because that can be very slow in large groups.
+
+       * gnus-int.el (gnus-request-group-scan): New backend function.
+
+       * nnimap.el (nnimap-request-scan-group): Implement in on IMAP.
+
+2015-01-25  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-suspend): Close all backends.
+
+2015-01-19  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * dgnushack.el (dgnushack-compile-file): New function.
+       (dgnushack-compile): Use it (bug#19514).
+
+2015-01-15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nntp.el (nntp-send-authinfo): Error out if the password is wrong.
+
+2015-01-08  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * registry.el: Don't use <class> as a variable.
+
+2014-12-29  Paul Eggert  <eggert@cs.ucla.edu>
+
+       system-name's returned value can vary
+       Also, the system-name variable is now obsolete.
+       Fixes Bug#19438.
+       * message.el (message-make-fqdn):
+       * nnvirtual.el (nnvirtual-retrieve-headers)
+       (nnvirtual-update-xref-header): Prefer (system-name) to system-name,
+       and avoid naming locals 'system-name'.
+
+2014-12-29  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-shr): Bind `shr-width' to `fill-column' so that
+       lines don't get overlong when responding.
+
+2014-12-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * registry.el (cl-remf, cl-loop, cl-subseq):
+       Alias to remf, loop, and subseq respectively for old Emacsen.
+
+2014-12-19  Andreas Schwab  <schwab@linux-m68k.org>
+
+       * gnus-group.el (gnus-read-ephemeral-bug-group):
+       Bind coding-system-for-read and coding-system-for-write only around
+       with-temp-file, and make buffer unibyte.  Don't write temp file twice.
+
+2014-12-18  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * registry.el (registry-db): Set default slot later.
+       This is because its value is not a literal integer.
+
+2014-12-18  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * registry.el (registry-db): Fix default registry-db max-size.
+
+2014-12-18  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * mm-util.el (mm-with-unibyte-current-buffer): Mark obsolete and
+       add warning.
+
+       * gnus-art.el: Fix up compiler warnings.
+       (article-display-face, article-display-x-face): Remove unused `face'.
+       (gnus-article-browse-html-save-cid-content): Remove unused var `type'.
+       (article-date-ut): Remove unused var `first'.
+       (gnus-article-prepare): Remove unused var `gnus-article'.
+       (gnus-mime-save-part-and-strip): Remove unused var `param'.
+       (gnus-mime-inline-part): Remove unused vars `charset', `contents', and
+       `coding-system' along with corresponding dead code.
+       (gnus-mime-view-part-externally): Remove unused var
+       `mm-user-display-methods'.
+       (gnus-insert-mime-button): Let-bind gnus-tmp-id explicitly.
+       (gnus-display-mime): Remove unused var `handle'.
+       (gnus-mime-display-alternative): Remove unused var `props'.
+       (gnus-article-read-summary-keys): Remove unused var `up-to-top'.
+       (gnus-article-edit-done): Remove unused var `p'.
+       (gnus-url-mailto): Remove unused var `to'.
+       (gnus-treat-article): Let-bind gnus-treat-condition, part-number,
+       total-parts, and gnus-treat-type explicitly.  Remove unused var `elem'.
+
+2014-12-18  Eric Abrahamsen  <eric@ericabrahamsen.net>
+
+       * registry.el (registry-db): Consolidate the :max-hard and :max-soft
+       slots into a :max-size slot.
+       (registry-db-version): Add new variable for database version number.
+       (registry-prune): Use :max-size slot. Accept and use a sort-function
+       argument.
+       (registry-collect-prune-candidates): Add new function for finding
+       non-precious pruning candidates.
+       (registry-prune-hard-candidates, registry-prune-soft-candidates):
+       Remove obsolete functions.
+       (initialize-instance): Upgrade registry version when starting.
+
+       * gnus-registry.el (gnus-registry-prune-factor): Add new variable.
+       (gnus-registry-max-pruned-entries): Remove obsolete variable.
+       (gnus-registry-cache-file): Change default
+       filename extension to "eieio".
+       (gnus-registry-read): Add new function, split out from
+       `gnus-registry-load', that does the actual object reading.
+       (gnus-registry-load): Use it. Add condition case handler to check for
+       old filename extension and rename to the new one.
+       (gnus-registry-default-sort-function): New variable to specify a sort
+       function to use when pruning.
+       (gnus-registry-save, gnus-registry-insert): Use it.
+       (gnus-registry-sort-by-creation-time): Define a default sort function.
+
+       * tests/gnustest-registry.el (gnustest-registry-make-testable-db):
+       Adjust test for new object signature.
+       (gnustest-registry-pruning-test): Add new pruning test.
+       (gnustest-registry-sort-function): Default sort function for testing.
+       (gnustest-registry-pruning-sort-test): New test for sorting.
+
+2014-12-09  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-mime-handles): Refactor out into own
+       function for reuse.
+       (gnus-mime-buttonize-attachments-in-header): Adjust.
+
+2014-12-07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-change-subject): Really check whether the subject
+       changed.
+
+2014-12-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mailcap.el (mailcap-mime-data): Add doc-view-mode as a viewer for
+       PDFs.
+       (mailcap-view-mime): New function.
+
+2014-12-01  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-cloud.el (gnus-cloud): Add :version tag.
+
+2014-11-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-use-idna):
+       * gnus-sum.el (gnus-summary-idna-message):
+       * message.el (message-use-idna):
+       Protect against nil value for idna-program.
+
+       * message.el (message-use-idna): Load Mule-UCS for XEmacs 21.4.
+
+2014-11-26  John Mastro  <john.b.mastro@gmail.com>  (tiny change)
+
+       * auth-source.el (auth-source-macos-keychain-search-items): Return
+       result of `auth-source-macos-keychain-result-append' (bug#19074).
+
+2014-11-25  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-start.el (gnus-save-newsrc-file-check-timestamp):
+       Add :version tag.
+
+2014-11-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * pop3.el (pop3-open-server): Warn unless encrypted.
+
+       * nnimap.el (nnimap-open-connection-1): Warn unless encrypted.
+
+2014-11-18  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Port new time stamp handling to Emacs 23.2.
+       This fix is for Gnus.  Problem reported by Katsumi Yamaoka.
+       * time-date.el (time-add, time-subtract, time-less-p):
+       Use eval-and-compile, not eval-when-compile.
+
+2014-11-17  Albert Krewinkel  <albert@zeitkraut.de>
+
+       * message.el (message-valid-fqdn-regexp): Add non-internaional new
+       TLDs.
+
+2014-11-17  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Port new time stamp handling to old Emacs and to XEmacs.
+       This is needed for Gnus, which copies time-date.el and which
+       runs on older Emacs implementations.
+       * time-date.el (with-decoded-time-value):
+       Handle 'nil' and floating-point arg more compatibly with new Emacs.
+       (encode-time-value, with-decoded-time-value):
+       Obsolete only if new Emacs.
+       (time-add, time-subtract, time-less-p): Define if not new Emacs.
+
+       Improve time stamp handling, and be more consistent about it.
+       This implements a suggestion made in:
+       http://lists.gnu.org/archive/html/emacs-devel/2014-10/msg00587.html
+       Among other things, this means timer.el no longer needs to
+       autoload the time-date module.
+       * time-date.el (seconds-to-time, days-to-time, time-since)
+       (with-decoded-time-value):
+       Treat 'nil' as current time.  This is mostly for XEmacs.
+       (encode-time-value, with-decoded-time-value): Obsolete.
+       (time-add, time-subtract, time-less-p): Use no-op autoloads, for
+       XEmacs.  Define only if XEmacs, as they're now C builtins in Emacs.
+
+2014-11-14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-exit-no-update): Don't query about
+       discarding changes in ephemeral groups.
+
+       * ietf-drums.el (ietf-drums-parse-address): Don't issue warnings about
+       things the user isn't interested in.
+
+2014-11-13  Julien Danjou  <jd@abydos>
+
+       * gnus-notifications.el (gnus-notifications-notify): Provide both
+       app-icon and image-path.
+
+2014-11-10  Kenjiro NAKAYAMA  <nakayamakenjiro@gmail.com>
+
+       * mm-url.el (mm-url-encode-multipart-form-data):
+       Restore to handle "multipart/form-data" by eww.
+
+2014-11-07  Tassilo Horn  <tsdh@gnu.org>
+
+       * gnus-start.el (gnus-activate-group): Fix typo reported by Tim
+       Landscheidt.
+
+2014-10-29  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Simplify use of current-time and friends.
+       * gnus-delay.el (gnus-delay-article):
+       * gnus-sum.el (gnus-summary-read-document):
+       * gnus-util.el (gnus-seconds-today, gnus-seconds-month):
+       * message.el (message-make-expires-date):
+       Omit unnecessary call to current-time.
+       * gnus-util.el (gnus-float-time): Simplify to an alias because
+       time-to-seconds now behaves like float-time with respect to nil arg.
+       (gnus-seconds-year): Don't call current-time twice to get the current
+       time stamp, as this can lead to inconsistent results.
+       * time-date.el (time-to-seconds) [!float-time]:
+       Use current time if arg is nil, to be compatible with float-time.
+       (time-date--day-in-year): New function, with most of the guts of
+       the old time-to-day-in-year.
+       (time-to-day-in-year): Use it.
+       (time-to-days): Use it, to avoid decoding the same time stamp twice.
+
+2014-10-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (gnus-mode-line-buffer-identification):
+       Don't add image data for a non-graphic display (bug#18813).
+
+2014-10-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (gnus-mode-line-buffer-identification): Don't shadow
+       load-path, it blocks autoloading of find-image (bug#18813).
+
+2014-10-24  enami tsugutomo  <tsugutomo.enami@jp.sony.com>
+
+       * nnimap.el (nnimap-wait-for-response): Ignore NOOP response requested
+       to keep connection open (bug#18728).
+
+2014-10-20  Glenn Morris  <rgm@gnu.org>
+
+       * Merge in all changes up to 24.4 release.
+
+2014-10-15  Jorge A. Alfaro-Murillo  <jorge.alfaro-murillo@yale.edu>  (tiny change)
+
+       * message.el (message-insert-signature): Use `newline' instead of
+       inserting explicit "\n".
+
+2014-10-15  Sylvain Chouleur  <sylvain.chouleur@gmail.com>
+
+       * gnus-icalendar.el: Support vcal format timezones.
+       (gnus-icalendar-event--decode-datefield): Use icalendar functions to
+       compute dates with associated timezone.
+       (gnus-icalendar-event-from-ical): Compute all timezones.
+
+2014-10-14  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-start.el (gnus-save-newsrc-file-check-timestamp): New option to
+       check the newsrc.eld file's timestamp before saving it.
+       (gnus-save-newsrc-file): Use it, with a prompt when the newsrc.eld
+       timestamp has changed to be newer.
+
+2014-10-06  Jan Tatarik  <jan.tatarik@gmail.com>
+
+       * gnus-icalendar.el (gnus-icalendar-identities):
+       Include message-alternative-emails.
+
+2014-10-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * ntlm.el (ntlm-string-make-unibyte, ntlm-secure-hash):
+       New compatibility functions.
+       (ntlm-build-auth-response): Use them.
+
+2014-10-04  Thomas Fitzsimmons  <fitzsim@fitzsim.org>
+
+       * ntlm.el (ntlm-build-auth-request):
+       Add NTLM2 Session support.  (Bug#15603)
+
+2014-10-04  Alan Schmitt  <alan.schmitt@polytechnique.org>  (tiny change)
+
+       * nnimap.el (nnimap-process-expiry-targets): Reverse the list of
+       expired messages only when it was built in reverse order.
+
+2014-10-04  Peter Münster  <pmlists@free.fr>  (tiny change)
+
+       * gnus-delay.el (gnus-delay-send-queue): Remove `gnus-delay-header'
+       last so it can be used in `message-send-hook'.
+
+2014-09-29  Daiki Ueno  <ueno@gnu.org>
+
+       * mml.el (mml-parse-1): Error out if unknown mode is specified in
+       <#secure> tag (bug#18513).
+
+2014-09-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * parse-time.el: Require cl when compiling.
+
+2014-09-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       Use cl-lib as much as possible following the 2014-09-26 change
+       in the Emacs trunk.
+       * parse-time.el: Try requiring cl-lib.
+       (parse-time-incf): Alias to cl-incf or incf.
+       (digit-char-p): Remove.
+       (parse-time-integer): Alias to cl-parse-integer or the one defined.
+       (parse-integer): Rename to parse-time-integer.
+       (parse-time-tokenize, parse-time-rules, parse-time-string)
+       Use parse-time-incf and parse-time-integer.
+
+2014-09-11  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-cloud.el (gnus-cloud-parse-version-1): Fix misspelling
+       of ":delete".
+
+2014-08-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-browse-html-save-cid-content)
+       (gnus-article-browse-html-parts):
+       Revert last change that breaks links other than cid contents.
+
+2014-08-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-browse-html-save-cid-content)
+       (gnus-article-browse-html-parts): Make cid file names relative.
+
+2014-08-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-view.el (mm-display-inline-fontify): Make the working buffer
+       temporarily displayed when running a mode function (at least org-mode
+       requires it).
+
+2014-08-14  Alan Schmitt  <alan.schmitt@polytechnique.org>
+
+       * gnus-sum.el (gnus-summary-expire-articles): Functions registered to
+       the gnus-summary-article-expire-hook should be told where the function
+       is going. In particular, the Gnus registry might want to know.
+
+2014-08-12  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-art.el (gnus-hidden-properties): Drop the evil `intangible'.
+
+2014-08-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-expire-articles): Revert.
+
+2014-08-05  Eric Abrahamsen  <eric@ericabrahamsen.net>
+
+       * gnus-sum.el (gnus-summary-expire-articles): Functions registered to
+       the gnus-summary-article-expire-hook should be told where the function
+       is going. In particular, the Gnus registry might want to know.
+
+2014-08-03  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Don't mishandle year-9999 dates (Bug#18176).
+       * parse-time.el (parse-time-rules):
+       Allow years up to most-positive-fixnum.
+       * time-date.el (date-to-time):
+       Pass "Specified time is not representable" errors through.
+
+2014-07-31  Tassilo Horn  <tsdh@gnu.org>
+
+       * gnus-msg.el (gnus-inews-insert-gcc): Allow `gcc-self' to be a list of
+       groups and t.
+
+2014-07-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-utils.el (gnus-recursive-directory-files):
+       Unify hard or symbolic links (bug#18063).
+
+2013-07-17  Albert Krewinkel  <albert@zeitkraut.de>
+
+       * gnus-msg.el (gnus-configure-posting-style):
+       Allow string replacements in values when matching against a header.
+
+2014-07-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-start.el (gnus-dribble-read-file): Don't stop the auto-saving of
+       the dribble buffer even when it is shrunk a lot.
+       <http://thread.gmane.org/gmane.emacs.gnus.user/16923>
+
+2014-06-26  Glenn Morris  <rgm@gnu.org>
+
+       * mm-util.el (help-function-arglist): Remove outdated declaration.
+
+2014-06-24  Andreas Schwab  <schwab@linux-m68k.org>
+
+       * html2text.el (html2text-get-attr): Rewrite to handle spaces in quoted
+       attribute values.  (Bug#17834)
+
+2013-06-22  Dmitry Antipov  <dmantipov@yandex.ru>
+
+       * gnus-sum.el (gnus-summary-edit-article-done):
+       Prefer point-marker to copy-marker of point.
+
+2014-06-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * Makefile.in (install-el, install-el-elc): Compress .el files.
+       (uninstall): Remove compressed .el files.
+
+2014-06-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-edit-part): Don't modifiy markers.
+       (gnus-article-read-summary-keys):
+       Don't bug out when there is no article in the summary buffer.
+       (gnus-mime-buttonize-attachments-in-header):
+       Improve criterion that finds parts to display.
+
+       * gnus-art.el (gnus-mm-display-part):
+       * mm-decode.el (mm-shr):
+       * mm-view.el (mm-inline-text-html-render-with-w3m, mm-inline-text)
+       (mm-insert-inline): Revert last changes.
+
+2014-06-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mm-display-part):
+       * mm-decode.el (mm-shr):
+       * mm-view.el (mm-inline-text-html-render-with-w3m, mm-inline-text)
+       (mm-insert-inline): Set insertion type of end-marker, not only
+       start-marker, of undisplayer so as to stay after inserted text.
+
+2014-06-02  Andreas Schwab  <schwab@linux-m68k.org>
+
+       * html2text.el (html2text-get-attr): Fix typo when splitting value from
+       attribute. (Bug#17613)
+
+2014-05-29  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * mm-view.el (mm-display-inline-fontify): Use font-lock-ensure.
+       * gnus-cite.el (gnus-message-citation-mode): Use font-lock-flush.
+
+2014-05-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-inline-part, gnus-mm-display-part):
+       Don't delete next part button; keep spacing between buttons.
+
+2014-05-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-inline-part, gnus-mm-display-part):
+       Work for the last MIME part in an article.
+       (gnus-mime-display-single): Suppress excessive newlines between parts.
+
+       * mm-uu.el (mm-uu-dissect): Assume that separators may be accompanied
+       by leading or trailing newline.
+
+2014-05-12  Sam Steingold  <sds@gnu.org>
+
+       * time-date.el (seconds-to-string): New function to pretty print time
+       delay in seconds.
+
+2014-05-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mm-display-part): Don't put article out of sight
+       while prompting a user for a file name, etc.
+       (gnus-mime-display-single): Display part with a common appearance no
+       matter whether MIME button is omitted or not; don't add duplicate entry
+       to gnus-article-mime-handle-alist.
+       (gnus-mime-buttonize-attachments-in-header): Use copied buttons.
+
+2014-05-08  Adam Sjøgren  <asjo@koldfront.dk>
+
+       * mml2015.el (mml2015-display-key-image): New variable.
+
+2014-05-08  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-fun.el (gnus-grab-cam-face):
+       Do not use predictable temp-file name.  (http://bugs.debian.org/747100)
+       This is CVE-2014-3421.
+
+2014-05-04  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-registry.el (gnus-registry-install-p): Doc fix.
+
+2014-05-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-inline-part): Redisplay a button so as to show
+       the displaying state of a part.
+       (gnus-mm-display-part): Don't insert a newline in the beginning of
+       a part like gnus-mime-inline-part doesn't; work for XEmacs.
+
+       * mm-decode.el (mm-display-part): Don't insert a newline in the top.
+       (mm-shr): Make undisplayer unbreakable.
+
+       * mm-view.el (mm-inline-image-emacs, mm-inline-image-xemacs):
+       Don't insert excessive newline.
+       (mm-inline-text-html-render-with-w3m, mm-inline-text)
+       (mm-insert-inline): Make undisplayer unbreakable.
+
+2014-05-01  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Ma Gnus v0.11 is released.
+
+2014-05-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mm-display-part):
+       Highlight header attachment buttons.
+
+2014-04-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mm-display-part): Don't move point while toggling
+       a part; redisplay a button (enbugged in 2014-02-05).
+
+2014-04-27  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-source-search, auth-source-search-backends):
+       Treat :max 0 as an indicator that a boolean return is wanted, as
+       documented. Reported by Joe Bloggs.
+
+2014-04-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-icalendar.el: Require gnus-art.
+
+2014-04-20  Jan Tatarik  <jan.tatarik@gmail.com>
+
+       * gnus-icalendar.el (gnus-icalendar-event->org-entry)
+       (gnus-icalendar--update-org-event): put event timestamp in
+       the org entry body instead of the drawer.
+       (gnus-icalendar-event--get-attendee-names): list of participants should
+       contain even attendees without common name attribute.
+       (gnus-icalendar--update-org-event): don't generate duplicates of empty
+       property tags in org drawers.
+
+2014-04-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gmm-utils.el (gmm-format-time-string): New function.
+
+       * message.el (message-insert-formatted-citation-line): Use the original
+       author's time zone to express a date string.
+
+2014-04-06  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-srvr.el (gnus-tmp-how, gnus-tmp-name, gnus-tmp-where)
+       (gnus-tmp-status, gnus-tmp-agent, gnus-tmp-cloud)
+       (gnus-tmp-news-server, gnus-tmp-news-method, gnus-tmp-user-defined):
+       Silence compiler warnings.
+       (gnus-server-insert-server-line): Don't use dyn-bind var as argument.
+
+2014-03-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml.el: Require url when compiling.
+
+       * gnus-cloud.el (gnus-cloud-parse-version-1):
+       Use plist-get rather than CL's getf.
+       (gnus-activate-group, gnus-subscribe-group): Declare.
+
+       * gnus-sum.el (gnus-mime-buttonize-attachments-in-header): Declare.
+
+2014-03-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-toggle-header): Display header attachment
+       buttons when toggling the header off.
+
+2014-03-14  Juanma Barranquero  <lekktu@gmail.com>
+
+       * tls.el (tls-program): Reflow docstring.
+
+2014-03-07  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-request-accept-article): Make respooling to nnimap
+       groups work again.
+
+2014-03-07  George McNinch  <gmcninch@gmail.com>  (tiny change)
+
+       * nnir.el (nnir-run-namazu): Parse namazu results that are larger than
+       999 correctly (i.e. "1,342").
+
+2014-03-07  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-agent.el (gnus-agent-update-files-total-fetched-for): Don't bug
+       out if the directory doesn't exist.
+
+2014-03-07  Daiki Ueno  <ueno@gnu.org>
+
+       * mml2015.el (mml2015-use): Don't check the availability of GnuPG
+       commands here; instead, only check if epg-config.el is available.
+
+2014-03-06  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * mml.el (mml-expand-html-into-multipart-related): Allow sending HTML
+       messages with embedded images.
+       (mml-generate-mime): Don't bug out if you don't have libxml.
+
+2014-03-06  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-make-html-message-with-image-files): New command.
+
+2014-03-05  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-make-group): Clarify prompt.
+
+       * mml.el (mml-insert-mime-headers): Allow `recipient-filename'.
+
+2014-02-23  David Engster  <deng@randomsample.de>
+
+       * auth-source.el (auth-source-netrc-saver): Do not depend on `cl-lib'
+       to stay compatible with older Emacsen, so replace `cl-loop' with
+       `loop'.
+
+2014-02-22  Daniel Colascione  <dancol@dancol.org>
+
+       * auth-source.el (auth-source-secrets-listify-pattern): New function.
+       (auth-source-secrets-search): Don't pass invalid patterns to secrets.el;
+       instead, build list of patterns.
+
+2014-02-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-prepare, gnus-article-prepare-display):
+       Display header attachment buttons by gnus-article-prepare-display
+       rather than gnus-article-prepare so as to view in mml-preview as well.
+
+2014-02-13  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-sources): Add pointer to what the .gpg extension
+       in `auth-sources' means and link to EPA docs.
+
+2014-02-12  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnmail.el (nnmail-expand-newtext): Further sub-match fixups
+       (bug#12375).
+
+2014-02-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-goto-part): Find a button in the body first.
+       (gnus-mime-buttonize-attachments-in-header): Number hidden buttons.
+
+2014-02-09  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-tab): Mention what happens on normal tabs
+       (bug#11297).
+
+2014-02-08  Glenn Morris  <rgm@gnu.org>
+
+       * auth-source.el (auth-sources): Doc fix.  (Bug#16642)
+
+2014-02-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-buttonize-attachments-in-header): Display
+       buttons that are hidden in unselected alternative part as well.
+       (gnus-mime-display-alternative): Redraw attachment buttons in header.
+
+       * gmm-utils.el (gmm-flet, gmm-labels): Add edebug spec.
+
+2014-02-07  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-srvr.el (gnus-server-toggle-cloud-server): New command and
+       keystroke.
+       (gnus-server-toggle-cloud-server): Only allow clouding applicable
+       types.
+
+       * ietf-drums.el (ietf-drums-parse-address): Don't bug out when called
+       with an empty string.
+
+2014-02-06  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-summary-cancel-article): `user-mail-address' is
+       buffer-local in some buffers, so bind it explicitly in the buffer we're
+       trying to cancel the article in (bug#10808).
+
+2014-02-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el, gnus-xmas.el (gnus-copy-overlay, gnus-overlays-at):
+       New functions.
+
+       * gnus-art.el (gnus-mime-display-attachment-buttons-in-header):
+       New user option.
+       (gnus-mime-buttonize-attachments-in-header): New function.
+       (gnus-article-prepare): Use it.
+       (gnus-mime-inline-part): Suppress extra newline.
+       (gnus-mm-display-part): Save excursion;
+       remove useless deleting and adding of buttons.
+       (gnus-insert-mime-button): Allow insertion in the middle of a line.
+
+       * gnus-sum.el (gnus-summary-wash-mime-map, gnus-summary-article-menu):
+       Add gnus-mime-buttonize-attachments-in-header.
+
+2014-02-05  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-request-articles): New command to download several
+       articles at once.
+
+       * gnus.el (gnus-variable-list): Save Cloud variables.
+
+       * gnus-int.el (gnus-request-accept-article): Doc fix.
+
+2014-02-04  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * parse-time.el (parse-time-iso8601-regexp)
+       (parse-iso8601-time-string): Copied from `url-dav' so that we can use
+       it more generally.
+
+2014-02-01  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-cloud.el: New file to provide the Emacs Cloud.
+
+       * dgnushack.el: Silence XEmacs w3 warning.
+
+       * gravatar.el (gravatar-retrieve-synchronously): XEmacs also has
+       `url-retrieve-synchronously', apparently.
+
+       * dgnushack.el: Silence XEmacs dns.el warning.
+
+       * gnus-compat.el (gnus-compat): Declare `declare-function' only here
+       instead of in all files.
+
+       * dns.el (network-interface-list): Define for XEmacs.
+
+       * gnus-notifications.el (gravatar-retrieve-synchronously): Declare for
+       XEmacs.
+
+       * nnrss.el (libxml-parse-html-region): Silence compilation error.
+
+2014-02-01  Daniel Dehennin  <daniel.dehennin@baby-gnu.org>
+
+       * gnus-mlspl.el (gnus-group-split-fancy): Use `gnus-parameters' in
+       `gnus-group-split-fancy'.
+
+2014-02-01  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-remove-header): Doc fix.
+       (message-forward-included-headers): New variable.
+       (message-remove-ignored-headers): Use it.
+
+2014-02-01  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnir.el (nnir-request-update-mark): Don't try to update the source
+       group if we can't find it (bug#16611).
+
+2014-01-31  Dave Abrahams  <dave@boostpro.com>
+
+       * gnus-sum.el (gnus-summary-open-group-with-article): New command.
+
+2014-01-31  Magnus Henoch  <magnus.henoch@gmail.com>
+
+       * dns.el (dns-servers-up-to-date-p): New function to see whether the
+       network interfaces changed.
+       (dns-query): Use it to flush the data.
+
+2013-09-04  Rasmus Pank Roulund  <emacs@pank.eu>
+
+       * gnus-fun.el (gnus-x-face-omit-files): Regexp to omit matched results
+       from random face commands.
+       (gnus-face-directory): Like `gnus-x-face-directory` for png files and
+       Face.
+       (gnus-face-omit-files): Like `gnus-x-face-omit-files` for Face.
+       (gnus--random-face-with-type): Generic function returning a face-type
+       as a string.
+       (gnus--insert-random-face-with-type): Generic function inserting a face
+       in a message buffer header.
+       (gnus-random-x-face): Rewritten to use `gnus--random-face-with-type`.
+       (gnus-insert-random-x-face-header): Rewritten to use
+       `gnus--insert-random-face-with-type`.
+       (gnus-random-face): Return random (png) Face as string.
+       (nus-insert-random-face-header): Insert random (png) Face in a message
+       buffer.
+
+2014-01-31  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-url.el: Remove all usage of w3.
+
+       * nnrss.el: Ditto.
+
+       * mm-decode.el: Ditto.
+
+       * mm-view.el: Ditto.
+
+       * dgnushack.el: Remove mentions of urldir and w3-dir, since w3 is
+       outdated and all Emacsen have url.el built-in.
+
+       * gnus-setup.el: Remove outdated file.
+
+2014-01-31  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Ma Gnus v0.9 is released.
+
+2014-01-31  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-transform-headers): Fix Davmail header parsing.
+
+2014-01-31  Dave Abrahams  <dave@boostpro.com>
+
+       * gnus-salt.el (gnus-tree-highlight-article): Don't move point around
+       in the summary buffer (bug#13769).
+
+2014-01-31  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-setup-buffer): Refresh the summary buffer
+       name if we're using a single article buffer.  Otherwise, it may point
+       to a killed buffer (bug#13756).
+
+2014-01-30  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnmail.el (nnmail-split-it): Instead of redoing the search to restore
+       the match data, just save and restore it explicitly (bug#12375).
+
+       * gnus-sum.el (gnus-summary-read-group-1): Initialize the spam code if
+       that's needed.
+
+       * spam.el (spam-initialize): Allow calling repeatedly, but only run the
+       the code once (bug#9069).
+
+2014-01-18  Steinar Bang  <sb@dod.no>
+
+       * gnus-setup.el (gnus-use-sendmail): We never use sendmail for mail
+       reading.
+
+2014-01-09  Ken Olum  <kdo@cosmos.phy.tufts.edu>  (tiny change)
+
+       * message.el (message-bury): Call bury-buffer with no argument
+       in the message-return-action case too.
+
+2014-01-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-article-stop-animations): Declare it before using.
+       (nnimap-split-fancy, nnimap-split-methods): Declare.
+
+       * mm-util.el (help-function-arglist): Declare.
+
+2013-12-28  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-sieve.el (gnus-sieve-select-method):
+       * gravatar.el (gravatar-automatic-caching, gravatar-cache-ttl)
+       (gravatar-rating, gravatar-size):
+       * message.el (message-minibuffer-local-map):
+       * sieve-manage.el (sieve-manage-authenticators)
+       (sieve-manage-authenticator-alist): Specify custom types.
+
+       * hashcash.el (hashcash-program): Rename from hashcash-path.
+       Update callers.
+
+       * gnus-icalendar.el (gnus-icalendar-org, gnus-icalendar):
+       * gnus-sum.el (gnus-subthread-sort-functions): Add version.
+       * gnus-sync.el (gnus-sync-file-encrypt-to): Add type and version.
+
+       * auth-source.el (auth-sources):
+       * nnmairix.el (nnmairix-propagate-marks-upon-close):
+       Fix custom types.
+
+       * tls.el (tls-certtool-program): Fix default value.
+
+2013-12-26  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-respool-query): Special-case nnimap so that
+       we get proper traces there, too.
+
+2013-12-26  Sean Connor  <sconnor005@allyinics.org>  (tiny change)
+
+       * gnus-sum.el (gnus-summary-enter-digest-group): Don't discard previous
+       value of the parameters if the current article has a Reply-To or From
+       field.
+
+2013-12-26  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-group-buffer): Remove duplicate definition.
+
+2013-12-25  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-exit): Stop animations.
+
+2013-12-19  Juri Linkov  <juri@jurta.org>
+
+       * gnus.el (gnus-suppress-keymap):
+       * gnus-art.el (gnus-article-mode-map):
+       * gnus-group.el (gnus-group-mode-map):
+       * gnus-sum.el (gnus-summary-mode-map, gnus-summary-backend-map):
+       Remove [backspace] key binding because it shadows DEL (bug#16035).
+
+       * mm-decode.el (mm-viewer-completion-map): Remove duplicate definition.
+
+2013-12-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-uu.el (gnus-uu-decode-binhex, gnus-uu-decode-binhex-view):
+       Make sure work directory exists.
+       (gnus-uu-digest-mail-forward): Store temporary files in work directory
+       rather than tmp directory.
+       (gnus-summary-prepare-exit-hook): Replace gnus-exit-group-hook, that is
+       not necessarily always run, with it.
+
+2013-12-18  Jan Tatarik  <jan.tatarik@gmail.com>
+
+       * gnus-icalendar.el (gnus-icalendar-identities): Make changing the
+       value of gnus-icalendar-additional-identities work without restart.
+
+2013-12-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-make-temp-file):
+       Alias to make-temp-file for modern Emacsen.
+
+2013-12-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-setup-message): Fix the type of argument passed to
+       nnir-article-number and nnir-article-group.
+
+2013-12-03  Vitalie Spinu  <spinuvit@gmail.com>
+
+       * message.el (message-send-mail-with-sendmail):
+       Don't kill error buffer if sending fails.
+
+2013-11-28  Jan Tatarik  <jan.tatarik@gmail.com>
+
+       * gnus-icalendar.el (gnus-icalendar-event-from-ical)
+       (gnus-icalendar-event->org-entry)
+       (gnus-icalendar--update-org-event)
+       (gnus-icalendar-event->gnus-calendar): Distinguish between
+       required/optional/non-participant attendee status.  Fix bug causing
+       the first required event participant to be omitted.
+
+2013-11-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-de-quoted-unreadable)
+       (article-de-base64-unreadable, gnus-mime-copy-part)
+       * gnus-html.el (gnus-article-html)
+       * mm-view.el (mm-inline-text-html-render-with-w3)
+       (mm-inline-text-html-render-with-w3m-standalone)
+       * rfc2231.el (rfc2231-decode-encoded-string):
+       Allow overriding charset by mm-charset-override-alist.
+
+       * gnus-art.el (gnus-article-browse-html-parts):
+       Replace LWSPs with `&nbsp;'s in header.
+
+       Work for broken Chinese articles.
+
+       * gnus-art.el (gnus-article-browse-html-save-cid-content):
+       Exclude broken handles that gnus-summary-enter-digest-group may create.
+       (gnus-article-browse-html-parts):
+       Allow overriding charset by mm-charset-override-alist.
+
+2013-11-21  Jan Tatarik  <jan.tatarik@gmail.com>
+
+       * gnus-icalendar.el (gnus-icalendar-additional-identities): New.
+       (gnus-icalendar-identities): Support additional-identities.
+
+2013-11-21  Jan Tatarik  <jan.tatarik@gmail.com>
+
+       * gnus-icalendar.el (gnus-icalendar-event:org-timestamp): Fix
+       org-timestamp for events ending at midnight.
+
+2013-11-21  Ivan Shmakov  <ivan@siamics.net>
+
+       * nndoc.el (nndoc-type-alist, nndoc-debbugs-db-type-p): Support debbugs
+       .log files.
+
+2013-11-20  David Engster  <deng@randomsample.de>
+
+       * lpath.el: Fix XEmacs warning for `beginning-of-visual-line'.
+
+2013-11-20  Dave Goldberg  <david.goldberg6@verizon.net>
+
+       * message.el (message-beginning-of-line):
+       Use beginning-of-visual-line when visual-line-mode is turned on.
+
+2013-11-15  Jan Tatarik  <jan.tatarik@gmail.com>
+
+       * gnus-icalendar.el (gnus-icalendar-event->gnus-calendar)
+       (gnus-icalendar-event-from-ical)
+       (gnus-icalendar-event->org-entry)
+       (gnus-icalendar--update-org-event): Required/optional participation,
+       list of attendees synced to org.
+
+2013-11-13  Jan Tatarik  <jan.tatarik@gmail.com>
+
+       * gnus-icalendar.el (gnus-icalendar-event:sync-to-org)
+       (gnus-icalendar-event:inline-org-buttons): Allow for appointment
+       cancellations to be synced to org if the original appt has an org
+       outline.
+
+2013-11-13  Jan Tatarik  <jan.tatarik@gmail.com>
+
+       * gnus-icalendar.el (gnus-icalendar--format-summary-line)
+       (gnus-icalendar-event->org-entry)
+       (gnus-icalendar--update-org-event)
+       (gnus-icalendar-event->gnus-calendar): Fix empty location handling.
+
+2013-11-12  Jan Tatarik  <jan.tatarik@gmail.com>
+
+       * gnus-icalendar.el (gnus-icalendar-event-from-ical):
+       Fix timezone handling in gnus-icalendar export to org.
+
+2013-11-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-salt.el (gnus--let-eval): Silence the Buildbot.
+
+2013-11-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-cite.el (gnus-cite-add-face): Make non-sticky overlays.
+
+2013-10-30  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-group.el (gnus-group-browse-foreign-server):
+       * gnus-int.el (gnus-start-news-server):
+       Silence compiler obsolescence warning.
+
+2013-10-29  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * nnimap.el (nnimap-open-connection-1): `auth-source-search' for the
+       `nnoo-current-server' first, then for the actual `nnimap-address' to
+       allow netrc entries for the nnoo server to coexist with netrc entries
+       for the `nnimap-address'.
+
+2013-10-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-dissect-buffer): Revert last change.
+       * nndoc.el (nndoc-dissect-mime-parts-sub): Ditto.
+       The problem that motivated those changes was attributed to a broken
+       mail sender, and has been fixed.
+
+2013-10-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-dissect-buffer): Guess content-type if the first
+       token is missing in the Content-Type header.
+
+       * nndoc.el (nndoc-dissect-mime-parts-sub): Ditto.
+
+2013-09-18  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-util.el (image-size): Declare.
+
+2013-09-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-icalendar.el (gnus-icalendar-event--find-attendee)
+       (gnus-icalendar-event-from-ical)
+       (gnus-icalendar-event--build-reply-event-body)
+       (gnus-icalendar-event-reply-from-buffer)
+       (gnus-icalendar-find-org-event-file)
+       (gnus-icalendar-event->gnus-calendar, gnus-icalendar-reply)
+       (gnus-icalendar-mm-inline): Use gmm-labels instead of labels or flet.
+
+       * mm-util.el (mm-special-display-p): Isolate XEmacs stuff.
+
+2013-09-17  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-salt.el (gnus-tree-mode): Use define-derived-mode.
+       Use save-current-buffer.
+       (gnus-tree-mode-map): Initialize in the declaration.
+       (gnus-pick-mouse-pick-region): Remove unused var `fun'.
+       (scroll-in-place): Defvar it.
+       (gnus-tmp-*): Defvar them.
+       (gnus-get-tree-buffer): Use derived-mode-p.
+       (gnus--let-eval): New macro.
+       (gnus-tree-highlight-node): Use it to avoid dynamic binding of
+       non-prefixed variables.
+       (gnus-tree-open, gnus-tree-close): Remove unused arg `group'.
+
+       * gnus-sum.el (gnus-summary-highlight): Remove `below' from the list of
+       vars since it doesn't seem to be available.
+       (gnus-set-global-variables, gnus-summary-read-group-1)
+       (gnus-select-newsgroup, gnus-handle-ephemeral-exit)
+       (gnus-summary-display-article, gnus-summary-select-article)
+       (gnus-summary-next-article, gnus-offer-save-summaries)
+       (gnus-summary-generic-mark): Use derived-mode-p.
+       (gnus-summary-read-group-1, gnus-summary-exit)
+       (gnus-summary-exit-no-update, gnus-kill-or-deaden-summary):
+       Adjust calls to gnus-tree-close and gnus-tree-open.
+
+       * gnus-eform.el (gnus-edit-form-mode): Use define-derived-mode.
+
+       * gnus-agent.el (gnus-category-mode): Use define-derived-mode.
+       (gnus-agent-mode): Use derived-mode-p.
+       (gnus-agent-rename-group, gnus-agent-delete-group): Don't bind
+       gnus-command-method and *-command-method to nil, but bind
+       gnus-command-method to *-command-method instead!
+       (gnus-agent-fetch-articles): Remove unused var `id'.
+       (gnus-agent-fetch-headers): Remove unused arg `force'.
+       (gnus-agent-braid-nov): Remove unused arg `group'.  Adjust callers.
+       (gnus-agent-save-alist, gnus-agent-save-local): Remove unused `item'.
+       (gnus-agent-short-article, gnus-agent-long-article)
+       (gnus-agent-low-score, gnus-agent-high-score): Move declaration before
+       first use.
+       (gnus-agent-fetch-group-1): Remove unused vars `arts', `category',
+       `score-param'.
+       (gnus-tmp-name, gnus-tmp-groups): Defvar them.
+       (gnus-get-predicate): Push in front of the cache, rather than end.
+       (gnus-agent-expire-current-dirs, gnus-agent-expire-stats): Defvar them.
+       (gnus-agent-expire-group-1): Use push.  Don't abuse dyn-binding.
+       (gnus-agent-expire-unagentized-dirs): Don't rebind
+       gnus-agent-expire-current-dirs since the defvar silences the warning.
+       (gnus-agent-retrieve-headers): Remove unused var `cached-articles'.
+       (gnus-agent-regenerate-group): Remove unused vars `point' and `dl'.
+       (gnus-agent-regenerate): Simplify interactive spec and doc.
+
+2013-09-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-int.el (gnus-open-server): Silence compiler.
+
+       * mm-decode.el (mm-add-meta-html-tag): Fix regexp matching meta tag.
+
+       * message.el (message-display-completion-list): Abolish.
+       (message-completion-in-region): Use display-completion-list.
+
+2013-09-17  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-util.el (gnus-message-with-timestamp-1):
+       Use `messages-buffer' function if available.  Ignore read-only.
+
+2013-09-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-expand-group, message-completion-in-region):
+       Correct the order of start and end of a region.
+
+2013-09-13  Glenn Morris  <rgm@gnu.org>
+
+       * mml2015.el (gnus-create-image): Autoload it.
+
+       * gnus-spec.el (gnus-xmas-format): Fix weird error call.
+
+       * gnus-html.el (declare-function): Add compat stub for ancient Emacs.
+       (image-size): Declare.
+
+2013-09-12  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-icalendar.el (gnus-icalendar-event--build-reply-event-body):
+       Avoid using `find', which i) might not be defined at runtime;
+       ii) does not work, since its default test is eql, not equal.
+       (gnus-mime-action-alist): Declare.
+
+2013-09-11  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * score-mode.el (gnus-score-mode-map): Move initialization
+       into declaration.
+       (gnus-score-mode): Use define-derived-mode.
+       * gnus-srvr.el (gnus-browse-mode): Use define-derived-mode.
+       * gnus-kill.el (gnus-kill-file-mode-map): Move initialization
+       into declaration.
+       (gnus-kill-file-mode): Use define-derived-mode.
+       (gnus-kill-file-edit-file, gnus-kill-file-enter-kill, gnus-kill):
+       Use derived-mode-p.
+       * gnus-group.el (gnus-group-mode): Use define-derived-mode.
+       (gnus-group-setup-buffer, gnus-group-name-at-point)
+       (gnus-group-make-web-group, gnus-group-enter-directory)
+       (gnus-group-suspend): Use derived-mode-p.
+       * gnus-cus.el (gnus-custom-mode): Use define-derived-mode.
+       * gnus-bookmark.el (gnus-bookmark-bmenu-mode): Use define-derived-mode.
+       * gnus-art.el (gnus-article-mode): Use define-derived-mode.
+       (gnus-article-setup-buffer, gnus-article-prepare)
+       (gnus-article-prepare-display, gnus-sticky-article)
+       (gnus-kill-sticky-article-buffer, gnus-kill-sticky-article-buffers)
+       (gnus-bind-safe-url-regexp, gnus-article-check-buffer)
+       (gnus-article-read-summary-keys): Use derived-mode-p.
+
+2013-08-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-temp-files-delete): Fix file deletion logic.
+
+2013-08-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-coding-system-priorities): Exclude iso-2022-jp-2 and
+       shift_jis from the default value set for Japanese users.
+
+2013-08-13  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-icalendar.el (gnus-icalendar-org-capture-file): Fix type.
+
+       * gnus.el (gnus-valid-select-methods): Fix type.
+
+       * nnimap.el (nnimap-request-articles-find-limit): Fix type, version.
+
+2013-08-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-display-external): Run a timer for the temp files
+       deletion after a viewer exits; add a deletion timer for the needsterm
+       case, too.
+
+       * mm-decode.el (mm-display-external): Try to delete temporary files by
+       using a 1-min. timer.
+
+2013-08-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-temp-files-to-be-deleted, mm-temp-files-cache-file):
+       New internal variables.
+       (mm-temp-files-delete): New function; add it to gnus-exit-gnus-hook.
+       (mm-display-external): Use it to delete temporary files instead of
+       using timers.
+
+2013-08-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * dgnushack.el (dgnushack-compile): Allow building on Emacs 23.
+
+2013-08-06  Jan Tatarik  <jan.tatarik@gmail.com>
+
+       * gnus-icalendar.el (gnus-icalendar-event-from-ical): Replace pcase
+       with cond for backwards compatability.
+
+2013-08-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-display-external): Bind process-connection-type to
+       nil; don't delete a temp file immediately even if a viewer finishes,
+       since it may be a shell script, like xdg-open, that launches a real
+       viewer program belatedly.
+
+2013-08-05  Dave Abrahams  <dave@boostpro.com>
+
+       * gnus-int.el (gnus-warp-to-article): Allow warping in all groups so
+       that we can create nndoc groups that excerpt other groups.
+
+2013-08-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-delay.el (gnus-delay-article): Fix typo.
+
+       * gnus-group.el (gnus-group-delete-articles): Allow deleting only "old"
+       articles.
+
+       * gnus-delay.el (gnus-delay-article): Run `message-send-hook' so that
+       we can get spell-checking etc.
+
+2013-08-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-encode-message-header): Unify charsets into
+       a single one used for encoding the whole text in a header.
+
+2013-08-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * dgnushack.el (dgnushack-compile): `icalendar--decode-isodatetime'
+       doesn't work properly on XEmacs.
+
+2013-08-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-ignored-news-headers): Delete X-Gnus-Delayed
+       before sending.
+
+       * dgnushack.el (dgnushack-compile): Add a temporary check for
+       gnus-icalendar.
+
+       * mm-decode.el (mm-command-output): New face.
+       (mm-display-external): Use it.
+
+2013-08-01  Kan-Ru Chen (陳侃如)  <kanru@kanru.info>  (tiny change)
+
+       * nnmbox.el (nnmbox-request-article): Don't change point.
+
+2013-08-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-icalendar.el (gnus-icalendar-event:inline-reply-buttons):
+       Include `handle' parameter.
+
+2013-08-01  Jan Tatarik  <jan.tatarik@gmail.com>
+
+       * gnus-icalendar.el: New file.
+
+2013-08-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-int.el (gnus-warp-to-article): Mention that warp means jump.
+
+       * gnus-uu.el (gnus-uu-mark-thread, gnus-uu-unmark-thread): Work with
+       dummy roots, too.
+
+2013-08-01  David Edmondson  <dme@dme.org>
+
+       * mml2015.el (mml2015-epg-key-image-to-string): Protect against bugging
+       out on ttys.
+
+2013-08-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-dribble-save): Only save the dribble file if it's
+       not empty.
+
+       * nnrss.el (nnrss-discover-feed): Indent.
+
+2013-08-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-emacs-completing-read): Isolate XEmacs stuff.
+
+2013-07-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-read-active-for-groups): Always mark the data as
+       dirty to ensure nnimap data being saved.
+
+2013-07-30  Tassilo Horn  <tsdh@gnu.org>
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Add "Current thread score"
+       menu entry.
+
+       * gnus-score.el (gnus-summary-current-score): Use prefix arg to show
+       the current thread's total score instead of the current article's
+       score.
+
+       * gnus-sum.el (gnus-subthread-sort-functions): New defcustom.
+       (gnus-sort-threads-recursively): Delete defcustom.
+       (gnus-sort-threads-recursive): Adapt accordingly.
+
+2013-07-30  Tassilo Horn  <tsdh@gnu.org>
+
+       * gnus-sum.el (gnus-sort-subthreads-recursive): New function.
+       (gnus-sort-threads-recursive): Use it.
+       (gnus-sort-threads): Unconditionally call `gnus-sort-threads-recursive'
+       again.  Now that determines how to sort subthreads.
+
+2013-07-26  Tassilo Horn  <tsdh@gnu.org>
+
+       * gnus-sum.el (gnus-sort-threads-recursively): New defcustom.
+       (gnus-sort-threads): Use it.
+
+2013-07-25  Andreas Schwab  <schwab@linux-m68k.org>
+
+       * gnus-art.el (gnus-button-url-regexp): Make it match url in which
+       punctuation characters follow parentheses (bug#14950).
+
+2013-07-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (gnus-continuum-version):
+       * gnus-msg.el (gnus-extended-version): Simplify.
+
+       * gnus.el (gnus-continuum-version-1): Remove.
+       * gnus-msg.el (gnus-bug): Revert.
+
+       Calculate gnus-version correctly on Cygwin.
+
+       * gnus.el (gnus-continuum-version): Do main calculations in integers.
+       (gnus-continuum-version-1): New function, return a string.
+
+       * gnus-msg.el (gnus-extended-version, gnus-bug):
+       Use gnus-continuum-version-1 instead of gnus-continuum-version.
+
+2013-07-19  Geoff Kuenning  <geoff@cs.hmc.edu>  (tiny change)
+
+       * gnus-art.el (gnus-treat-predicate): Allow functions as predicates
+       (bug#13384).
+
+2013-07-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-clean-old-newsrc): Remove the newsrc cleanups
+       that were only relevant in a development version a long time ago.
+
+2013-07-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-shr-put-image): Make it work as well for shr.el's
+       that the old Emacs 24s bundle.
+
+2013-07-10  David Engster  <deng@randomsample.de>
+
+       * gnus-start.el (gnus-clean-old-newsrc): Always remove 'unexist' marks
+       if `gnus-newsrc-file-version' does not match `gnus-version'.  This
+       fixes a bug in Emacs trunk where the 'unexist' marks were always
+       removed at startup because "Gnus v5.13" was considered smaller than "Ma
+       Gnus v0.03".
+
+2013-07-10  Tassilo Horn  <tsdh@gnu.org>
+
+       * gnus.el (gnus-summary-line-format): Reference
+       `gnus-user-date-format-alist' for the &user-date; format, not
+       `gnus-summary-user-date-format-alist'.
+
+2013-07-08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnml.el (nnml-request-compact-group): Don't bug out if we can't
+       delete files (bug#13481).
+
+2013-07-08  Tassilo Horn  <tsdh@gnu.org>
+
+       * gnus-registry.el (gnus-registry-remove-extra-data): New function.
+
+2013-07-06  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-block-private-groups): Allow `global' methods to
+       display images.
+
+       * gnus.el (gnus-valid-select-methods): Mark nnrss as global.
+
+       * message.el (message-cancel-news): According to
+       <mailman.216.1372942181.12400.help-gnu-emacs@gnu.org>, "cancel" is
+       preferred over "cmsg cancel" in the Subject.
+
+       * nnir.el (nnir-engines): Note that the group specs are regexps
+       (bug#13238).
+
+       * gnus-msg.el (gnus-copy-article-buffer): If the article buffer has
+       gotten read-only text properties, ensure that those aren't heeded when
+       copying stuff over (bug#13434).
+
+       * mm-view.el (mm-inline-text-html): Don't bug out on multipart messages
+       (bug#13762).
+
+2013-07-05  David Kastrup  <dak@gnu.org>
+
+       * auth-source.el (auth-source-netrc-parse-one): Allow empty strings in
+       authinfo file again (important for blank passwords).  This had been
+       broken with 2013-06-15 change.
+
+2013-07-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-from-or-to-or-newsgroups):
+       Revert 2013-01-14 change.
+
+2013-07-02  Daiki Ueno  <ueno@gnu.org>
+
+       * mml2015.el (mml2015-epg-key-image): Use 'gnus-create-image' instead
+       of 'create-image' for XEmacs compatibility; check errors when decoding
+       image.  Reported by Uwe Brauer.
+
+2013-06-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-extend-url-button): Make it work again with
+       gnus-button-push revised at 2011-01-19.
+
+2013-06-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * eww.el, shr.el, shr-color.el: Removed from the Gnus repository.  They
+       now live in the lisp/net Emacs 24 repository.
+
+2013-06-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * eww.el (eww-update-header-line-format): Quote % characters.
+
+2013-06-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * eww.el (eww-process-text-input): Display passwords as asterisks.
+
+       * shr.el (shr-make-table-1): Protect against invalid column-spans.
+
+2013-06-19  Tom Tromey  <tromey@redhat.com>
+
+       * eww.el (eww-top-url): Remove.
+       (eww-home-url, eww-start-url, eww-contents-url): New defvars.
+       (eww-render): Set new variables.  Don't set eww-top-url.
+       (eww-handle-link): Handle "prev", "home", and "contents".
+       Downcase the rel text.
+       (eww-top-url): Choose best top URL.
+
+2013-06-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * eww.el: Rewrite to implement form elements "by hand" instead of
+       relying in widget.el.  Using widget.el leads to too many
+       user interface inconsistencies.
+       (eww-self-insert): Implement entering commands in text fields.
+       (eww-process-text-input): New function to make text input field editing
+       work.
+       (eww-submit): Rewrite to use the new-style form methods.
+       (eww-select-display): Display the correct selected item.
+       (eww-change-select): Implement changing the select value.
+       (eww-toggle-checkbox): Implement radio/checkboxes.
+       (eww-update-field): Fix compilation error.
+       (eww-tag-textarea): Implement <textarea>.
+
+       * shr.el (shr-urlify): Use `keymap' instead of `local-map' so that we
+       don't shadow mode-specific bindings.
+
+       * eww.el (eww-browse-url): Don't push stuff onto history if there's
+       nothing to push.
+
+       * shr.el (shr-map): Bind [down-mouse-1] to browse URLs.
+
+2013-06-19  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-group.el (gnus-mark-article-as-read): Fix declaration.
+
+2013-06-18  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-source-netrc-parse-entries): Remove debugging.
+
+2013-06-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-make-table-1): Implement <td rowspan>.
+       (shr-table-horizontal-line): Allow nil as a value, and change the
+       default.
+       (shr-insert-table-ruler): Respect the nil value.
+
+2013-06-18  Tom Tromey  <tromey@barimba>
+
+       * eww.el (eww-next-url, eww-previous-url, eww-up-url, eww-top-url):
+       New defvars.
+       (eww-open-file): New defun.
+       (eww-render): Initialize new variables.
+       (eww-display-html): Handle "link" and "a".
+       (eww-handle-link, eww-tag-link, eww-tag-a): New defuns.
+       (eww-mode-map): Move "p" to "l".  Bind "p", "n", "t", and "u".
+       (eww-back-url): Rename from eww-previous-url.
+       (eww-next-url, eww-previous-url, eww-up-url, eww-top-url): New
+       defuns.
+
+2013-06-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-tag-table): Insert the images after the table, so that
+       they're not covered by the table colourisation, which often looked
+       awkward.
+       (shr-tag-dl, shr-tag-dt, shr-tag-dd): Add support for <dl>, <dt> and
+       <dd>.
+       (shr-make-table-1): Implement <td colspan=> support.
+       (shr-insert-document): Use one less than window width if `shr-width' is
+       nil, since otherwise things may get one character too wide.
+
+2013-06-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * eww.el (eww-detect-charset): Improve regexp; move backward.
+
+2013-06-18  Glenn Morris  <rgm@gnu.org>
+
+       * mm-decode.el (widget-convert-button): Autoload.
+
+       * sieve-manage.el (mm-enable-multibyte): Autoload.
+
+       * shr.el (libxml-parse-html-region): Declare.
+       (shr-render-buffer): Explicit error if no libxml2 support.
+
+2013-06-17  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-source-current-line): New function.
+       (auth-source-netrc-parse-entries): When a data token is "machine",
+       assume we're in the wrong place and abort parsing the current line.
+
+2013-06-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * eww.el (eww-tag-select): Don't render totally empty <select> forms.
+       (eww-convert-widgets): Don't bug out if the first widget starts at the
+       beginning of the buffer.
+       (eww-convert-widgets): Fix last patch.
+       (eww-tag-input): Support <input type=image>.
+
+       * shr.el (shr-insert-table): Respect border-collapse: collapse.
+       (shr-tag-base): Protect against base specs that are degenerate.
+       (shr-ensure-paragraph): Don't delete empty lines that have text
+       properties, because these may be input fields.
+
+       * eww.el (eww-convert-widgets): Put `help-echo' on input fields so that
+       we can navigate to them.
+
+       * shr.el (shr-colorize-region): Put the colours over the entire region.
+       (shr-inhibit-decoration): New variable.
+       (shr-add-font): Use it to inhibit text property decorations while doing
+       preliminary table renderings.  This speeds up typical Wikipedia page
+       renderings by 15%.
+       (shr-tag-span): Don't respect the <title>, because that overwrites the
+       help-echo from links inside the spans.
+       (shr-next-link): Use `help-echo' for navigation, so that we can
+       navigate to form elements, too.
+
+       * eww.el (eww-button): New face.
+       (eww-convert-widgets): Use it to make submit buttons more button-like.
+
+       * mm-decode.el (mm-convert-shr-links): Override the shr local map, so
+       that Gnus commands work.
+
+       * shr.el (shr-render-td): Support horizontal alignment.
+
+       * eww.el (eww-put-color): Removed.
+       (eww-colorize-region): Use `add-face-text-property'.
+
+       * shr.el (shr-add-font): Append face data, so that we get the correct
+       precedence: The innermost value (which is applied first) wins.
+       (shr-make-overlay): Obsolete function.
+
+       * mm-decode.el (mm-convert-shr-links): New function to convert
+       new-style shr URL links into widgets.
+       (mm-shr): Use it.
+
+       * eww.el (eww-mode-map): Use `shr-next-link' (etc) instead of the
+       widget commands, since we're no longer using widgets for links.
+
+       * shr.el (shr-next-link): New command.
+       (shr-previous-link): New command.
+       (shr-urlify): Don't use `widget-convert', because that's slow.
+       (shr-put-color-1): Use `add-face-text-property' instead of overlays,
+       because collecting the overlays and reapplying them when generating
+       tables is slow.
+       (shr-insert-table): Ditto.
+
+2013-06-17  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * sieve.el (sieve-edit-script): Avoid beginning-of-buffer.
+       * shr.el (browse-url): Require `url'.
+       * eww.el (url): Require format-spec.
+
+2013-06-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * eww.el (eww-display-html): Default to using the entire window width.
+       (eww-browse-url): Don't add a User-Agent header (twice), because that
+       makes Bing refuse connection.
+
+       * shr.el (shr-make-table): Cache the table rendering at the table
+       level, and not the <td> level.  This is a bit faster.
+
+       * eww.el (eww-render): Go to the correct ID when given URLs ending with
+       #id.
+
+       * shr.el (shr-tag-li): Don't require a new paragraph, since other
+       browsers don't.
+       (shr-expand-url): Respect #anchor links.
+       (shr-parse-base): Chop off the anchor before using.
+       (shr-descend): Respect display: none.
+       (shr-descend): Allow marking elements that have certain IDs.
+
+       * eww.el (eww-tag-textarea): Use `text' instead of `editable-field'.
+
+       * shr.el (shr-expand-url): Don't bug out on zero-length links.
+
+       * eww.el (eww-tag-textarea): Support <textarea>.
+
+2013-06-16  Rüdiger Sonderfeld  <ruediger@c-plusplus.de>
+
+       * shr.el (shr-dom-to-xml): Fixed function call.
+
+       * eww.el (eww): New group.
+       (eww-header-line-format): New custom variable.
+       (eww-current-title): New variable.
+       (eww-display-html): Update header and handle title tag.
+       (eww-update-header-line-format): New function.
+       (eww-tag-title): New function.
+
+       * shr.el (shr-dom-to-xml): New function.
+       (shr-tag-svg): Add support for the SVG tag.
+       (shr-bullet): New custom variable.
+       (shr-tag-li): Support custom bullet in unordered lists.
+
+2013-06-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-expand-url): Respect // URLs.
+
+       * eww.el (eww-tag-body): Override the shr body rendering so that we can
+       put a background colour onto the entire buffer.
+       (eww-render): When being redirected, use the redirect URL as the new
+       base URL.
+
+       * shr.el (shr-parse-base): Fix parsing error.
+
+       * eww.el (eww-submit): Pass the base in to `shr-expand-url'.
+
+       * shr.el (shr-parse-base): New function.
+       (shr-expand-url): Use it to expand relative URLs reliably.
+
+2013-06-15  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-source-search-collection): Fix docstring.
+       (auth-source-netrc-parse): Refactor and improve netrc parser to support
+       single-quoted strings and multiline entries.
+       (auth-source-netrc-parse-next-interesting)
+       (auth-source-netrc-parse-one, auth-source-netrc-parse-entries): New
+       functions to support parser.
+
+2013-06-14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * eww.el (eww-submit): Get submit button logic right when hitting RET
+       on non-submit buttons.
+
+       * shr.el: Remove shr-preliminary-table-render, since that can't really
+       be used for anything in practice.
+
+2013-06-13  Albert Krewinkel  <tarleb@moltkeplatz.de>
+
+       * sieve.el: Rebind q to (sieve-bury-buffer), bind Q to
+       (sieve-manage-quit).
+
+2013-06-14  Glenn Morris  <rgm@gnu.org>
+
+       * mml2015.el (mml2015-maximum-key-image-dimension): Add :version.
+
+2013-06-14  David Edmondson  <dme@dme.org>  (tiny change)
+
+       * mml2015.el (mml2015-maximum-key-image-dimension): New user option to
+       control the maximum size of photo ID image.
+       (mml2015-epg-key-image-to-string): Respect it.
+
+2013-06-13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-tag-table-1): Mark the preliminary table renderings
+       instead of the final one so that we can more easily distinguish them.
+
+       * eww.el (eww-submit): Compute the submission URL correctly.
+
+2013-06-13  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * sieve-manage.el (sieve-manage-open-server): Don't quote lambda.
+       Use plist-get rather than CL's getf.
+       (sieve-manage-parse-capability): Avoid CL's remove-if.
+
+2013-06-13  Albert Krewinkel  <tarleb@moltkeplatz.de>
+
+       * sieve.el: Rebind q to (sieve-bury-buffer), bind Q to
+       (sieve-manage-quit).
+
+2013-06-13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-expand-url): Expansion should chop off the bits after the
+       last slash.
+
+       * eww.el (eww-tag-select): Use the first value as the default value.
+
+2013-06-13  Rüdiger Sonderfeld  <ruediger@c-plusplus.de>
+
+       * eww.el (eww): Prepend urls with http:// if scheme is missing.
+       (eww-mode): Use `define-derived-mode'.
+       (eww-parse-headers): Parse headers from beginning of buffer so that
+       file:// links work.
+
+2013-06-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * eww.el (eww-detect-charset): Detect charset from the <meta> tag.
+
+2013-06-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-tag-svg): Ignore SVG elements, because we don't know how
+       to handle them at all.
+
+2013-06-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * eww.el (eww-convert-widgets): Make widgets from non-tabular layouts
+       work, too.
+       (eww-tag-select): Implement <select>.
+
+2013-06-10  Albert Krewinkel  <krewinkel@moltkeplatz.de>
+
+       * sieve-manage.el (sieve-manage-open): work with STARTTLS: shorten
+       stream managing functions by using open-protocol-stream to do most of
+       the work.  Has the nice benefit of enabling STARTTLS.
+       Wait for capabilities after STARTTLS: following RFC5804, the server
+       sends new capabilities after successfully establishing a TLS connection
+       with the client.  The client should update the cached list of
+       capabilities, but we just ignore the answer for now.
+       (sieve-manage-network-p, sieve-manage-network-open)
+       (sieve-manage-starttls-p, sieve-manage-starttls-open)
+       (sieve-manage-forward, sieve-manage-streams)
+       (sieve-manage-stream-alist): Remove unneeded functions neither in the
+       API, nor called by any other function.
+       Enable Multibyte for SieveManage buffers: The parser won't properly
+       handle umlauts and line endings unless multibyte is turned on in the
+       process buffer.
+
+2013-06-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * eww.el (eww-tag-input): Support password fields.
+       (eww-submit): Support POST.
+
+2013-06-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * eww.el (eww-tag-form): Protect against degenerate forms.
+
+       * shr.el (shr-expand-url): Expand URLs that start with a slash
+       correctly.
+
+       * eww.el (eww-submit): Get submit button logic right.
+
+       * shr.el (shr-final-table-render): New variable to signal when we're
+       doing the final table rendering so that we can collect more data at
+       that point.
+
+       * eww.el (eww-submit): Make form submission work.
+       (eww-tag-input): Implement submit buttons.
+       (eww-click-radio): Implement radio and checkboxes.
+       (eww-submit): Handle hidden elements.
+
+       * shr.el (shr-descend): Allow other packages to override (or provide)
+       rendering of elements.
+       (shr-expand-url): Strip query strings from URLs before expanding them.
+
+       * eww.el: Don't require cl-lib.
+       (eww-tag-form): Start form support.
+
+       * dgnushack.el (dgnushack-compile): Ignore eww on XEmacs.
+
+       * eww.el: Start writing a new, tiny web browser.
+       (eww-previous-url): New command.
+       (eww-quit): New command.
+
+2013-06-10  Albert Krewinkel  <krewinkel@moltkeplatz.de>
+
+       * sieve.el: Put point at beginning of buffer when viewing a script.
+       (sieve-open-server): Respect the PORT parameter.  Show the correct port
+       number in sieve-buffer's header.  Fixed code to also work with a string
+       as port specifier.  Properly close the connection on pressing 'q'.  Make
+       sieve-manage-quit close the connection and process buffer.  Also, remove
+       duplicate keybinding for 'q'.
+
+2013-06-10  Roy Hashimoto  <roy.hashimoto@gmail.com>  (tiny change)
+
+       * mm-view.el (mm-pkcs7-signed-magic): Allow newline in the regexp and
+       make it easier to read.
+       (mm-pkcs7-enveloped-magic): Ditto.
+
+2013-06-06  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-ems.el (gnus-image-type-available-p): Test `display-images-p'
+       before `image-type-available-p' to avoid loading the image libraries
+       needlessly.
+
+2013-06-05  David Engster  <deng@randomsample.de>
+
+       * gnus-sum.el (gnus-update-marks): Do not remove empty 'unexist'
+       ranges, since `nnimap-retrieve-group-data-early' also uses it as a flag
+       to see whether the group was synced before.
+
+2013-06-05  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * tls.el (open-tls-stream): Remove unneeded buffer contents up to point
+       when opening the connection.
+       Suggested by João Távora <joaotavora@gmail.com> in
+       <http://lists.gnu.org/archive/html/emacs-devel/2013-05/msg00464.html>.
+
+2013-06-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-date-ut, article-update-date-lapsed): Don't
+       assume Date header begins with "Date", that may be customized into
+       something like "X-Sent" using gnus-article-time-format.
+       (article-transform-date): Allow multi-line Date header.
+
+2013-06-02  David Engster  <deng@randomsample.de>
+
+       * registry.el (initialize-instance, registry-lookup)
+       (registry-lookup-breaks-before-lexbind, registry-lookup-secondary)
+       (registry-lookup-secondary-value, registry-search, registry-delete)
+       (registry-insert, registry-reindex, registry-size, registry-prune): Do
+       not wrap methods in `eval-and-compile'.  This breaks due to latest
+       changes in EIEIO (introduction of eieio-core.el).
+
+2013-05-30  Glenn Morris  <rgm@gnu.org>
+
+       * nnmail.el (nnmail-fancy-expiry-target):
+       Also bind mail-dont-reply-to-names.
+
+       * spam-stat.el (spam-stat-save):
+       No need to tweak font-lock in temp buffers.
+
+       * shr.el (shr-put-image): Silence compiler.
+
+2013-05-29  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-ems.el (set-process-plist): Every supported Emacs has this.
+
+       * gnus-group.el (gnus-sequence-of-unread-articles)
+       (gnus-summary-add-mark, gnus-mark-article-as-read)
+       (gnus-group-make-articles-read): Declare.
+
+       * gnus-sum.el (gnus-parameter-list-identifier)
+       (gnus-article-stop-animations, gnus-stop-downloads)
+       (gnus-article-only-boring-p, article-goto-body)
+       (gnus-flush-original-article-buffer, article-narrow-to-head)
+       (gnus-article-hidden-text-p, gnus-delete-wash-type)
+       (gnus-summary-save-in-pipe, gnus-article-show-summary): Declare.
+
+       * gnus.el: No need to eval-and-compile autoloads.
+
+       * gravatar.el (help-function-arglist): Autoload.
+
+       * nnimap.el (gnus-refer-thread-use-nnir): Declare.
+
+       * nnmail.el (nnmail-fancy-expiry-target): Maybe use mail-dont-reply-to.
+
+       * spam.el: No need to load spam-report when compiling.
+       No need to eval-and-compile autoloads.
+       (spam-report-resend-to): Declare.
+       (spam-report-resend-register-routine): Require 'spam-report.
+
+2013-05-24  Julien Danjou  <julien@danjou.info>
+
+       * sieve.el (sieve-setup-buffer): Fix default port value in sieve buffer
+       setup.
+
+2013-05-23  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-util.el (rmail-swap-buffers-maybe)
+       (rmail-maybe-set-message-counters, rmail-count-new-messages)
+       (rmail-summary-exists, rmail-show-message, rmail-summary-displayed)
+       (rmail-pop-to-buffer, rmail-maybe-display-summary): Declare.
+
+       * mm-decode.el: No need to load term when compiling.
+       (term-mode, term-char-mode): Declare.
+
+       * mm-util.el: No need to load jka-compr when compiling.
+       (jka-compr-acceptable-retval-list, jka-compr-make-temp-name): Declare.
+
+       * nnmaildir.el: Require is automatically eval-and-compile.
+       (nnmail): Require at run-time too.
+
+       * registry.el (registry-size): Move definition before use.
+
+2013-05-22  Daiki Ueno  <ueno@gnu.org>
+
+       * mml2015.el (mml2015-epg-sign): Make sure to insert newline after the
+       signed data to conform the standard.  (Bug#14232)
+
+2013-05-20  Adam Sjøgren  <asjo@koldfront.dk>
+
+       * gnus-spec.el (gnus-parse-complex-format): Use unicode escape for left
+       double angle quotation mark.
+
+2013-05-20  Glenn Morris  <rgm@gnu.org>
+
+       * format-spec.el (format-spec): Allow spec chars with nil.  (Bug#14420)
+
+2013-05-19  Adam Sjøgren  <asjo@koldfront.dk>
+
+       * message.el (message-insert-formatted-citation-line): handle finding
+       first/lastname when more than 2 names appear.
+
+2013-05-19  Adam Sjøgren  <asjo@koldfront.dk>
+
+       * shr.el (shr-tag-span): New function.
+
+2013-05-18  Glenn Morris  <rgm@gnu.org>
+
+       * message.el (message-mode): Use message-mode-abbrev-table,
+       with text-mode-abbrev-table as parent.  (Bug#14413)
+
+2013-05-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-expand-group): Decode group names.
+
+2013-05-16  Julien Danjou  <julien@danjou.info>
+
+       * gnus-notifications.el (gnus-notifications-notify): Use photo-file as
+       app-icon.
+
+2013-05-15  Glenn Morris  <rgm@gnu.org>
+
+       * shr-color.el (shr-color-visible-luminance-min)
+       (shr-color-visible-distance-min): Use shr-color group.
+
+2013-05-11  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-vm.el: Make it loadable without VM.
+       (gnus-vm-make-folder, gnus-summary-save-in-vm): Require 'vm.
+       (vm-forward-message, vm-reply, vm-mail): Remove unused autoloads.
+
+2013-05-09  Glenn Morris  <rgm@gnu.org>
+
+       * mml1991.el: Make it loadable.  (Bug#13456)
+
+       * gnus-art.el (gnus-article-date-headers, gnus-blocked-images):
+       * gnus-async.el (gnus-async-post-fetch-function):
+       * gnus-gravatar.el (gnus-gravatar-size, gnus-gravatar-properties):
+       * gnus-html.el (gnus-html-image-cache-ttl):
+       * gnus-notifications.el (gnus-notifications-timeout):
+       * gnus-picon.el (gnus-picon-properties):
+       * gnus-util.el (gnus-completion-styles):
+       * gnus.el (gnus-other-frame-resume-function):
+       * message.el (message-user-organization-file)
+       (message-cite-reply-position):
+       * nnir.el (nnir-summary-line-format)
+       (nnir-retrieve-headers-override-function):
+       * shr-color.el (shr-color-visible-luminance-min):
+       * shr.el (shr-blocked-images):
+       * spam-report.el (spam-report-resend-to):
+       * spam.el (spam-summary-exit-behavior): Fix custom types.
+
+       * gnus-salt.el (gnus-selected-tree-face): Fix default.
+
+2013-05-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-describe-bindings): Require help-mode
+       because of let-binding help-xref-following.  (Bug#14356)
+
+2013-05-06  Glenn Morris  <rgm@gnu.org>
+
+       * mml2015.el (mml2015-epg-sign): Add name="signature.asc".  (Bug#13465)
+
+2013-05-04  Andrew Cohen  <cohen@bu.edu>
+
+       * gnus-sum.el (gnus-read-header): Ensure groups are prefixed when
+       entering into the registry.
+
+2013-05-01  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Ma Gnus v0.7 is released.
+
+2013-05-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-emacs-completing-read): Fix a filter for XEmacs.
+       (Bug#14304)
+
+2013-04-27  Glenn Morris  <rgm@gnu.org>
+
+       * gnus.el (gnus-list-debbugs):
+       Use require rather than autoload.  (Bug#14262)
+
+2013-04-27  Julien Danjou  <julien@danjou.info>
+
+       * sieve-manage.el (sieve-manage-authenticator-alist): Update the sieve
+       port to "sieve" now that it has an official IANA port assigned.
+
+2013-04-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mail-source.el (mail-source-fetch-pop, mail-source-check-pop):
+       Don't set the MAILHOST environment variable permanently (Bug#14271).
+
+2013-04-26  Glenn Morris  <rgm@gnu.org>
+
+       * message.el (message-bury): Revert 2013-03-18 change.  (Bug#14117)
+
+2013-04-25  Andrew Cohen  <cohen@bu.edu>
+
+       * gnus-msg.el (gnus-inews-insert-gcc): Re-order conditional to work for
+       string values of 'gcc-self.  Thanks to Saroj Thirumalai.
+
+2013-04-24  Andrew Cohen  <cohen@bu.edu>
+
+       * nnir.el (nnir-close-group): Make sure we are in the right group.
+
+       * gnus-sum.el (gnus-summary-insert-articles): Force updates to the
+       dependency table from all newly retrieved headers.
+
+2013-04-16  David Edmondson  <dme@dme.org>
+
+       Support <img src="data:...">.
+
+       * shr.el (shr-image-from-data): New function.
+       (shr-tag-img): Use it.
+
+2013-04-14  Andrew Cohen  <cohen@bu.edu>
+
+       * nnir.el (nnir-request-set-mark): Make sure we are in the right
+       group.
+
+2013-04-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-msg-mail): Make it avoid using posting styles
+       corresponding to any existing group (Bug#14166).
+
+2013-04-10  Andrew Cohen  <cohen@bu.edu>
+
+       * nnir.el (number-sequence): No longer used.
+       (nnir-request-set-mark): New function.
+       (nnir-request-update-info): Improve marks updating.
+       (nnir-request-scan): Don't duplicate marks updating.
+       (gnus-group-make-nnir-group, nnir-run-imap, nnir-request-create-group):
+       Use 'assq rather than 'assoc.  Quote anonymous function.
+       (nnir-request-group, nnir-close-group, gnus-summary-create-nnir-group):
+       Use 'gnus-group-prefixed-p.
+       (gnus-summary-create-nnir-group): Make sure server for method is open.
+
+2013-04-04  Andrew Cohen  <cohen@bu.edu>
+
+       * nnir.el (gnus-nnir-group-p): New function.
+       (nnir-possibly-change-group): Use it.
+
+       * gnus-msg.el (gnus-setup-message): Use it.
+
+2013-04-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml.el (mml-minibuffer-read-description): Use `default' insted of
+       `initial-input' for the argument name.
+       Suggested by Stefan Monnier <monnier@iro.umontreal.ca>.
+
+2013-04-03  Kevin Layer  <layer@known.net>  (tiny change)
+
+       * mml.el (mml-minibuffer-read-description): Allow passing in a prefix
+       (used by MH-E).
+
+2013-04-01  Andrew Cohen  <cohen@bu.edu>
+
+       * nnir.el (nnir-request-update-mark): Improve mark updating in original
+       group.
+
+       * gnus-msg.el (nnir-article-number, nnir-article-group): Autoload to
+       fix compilation.
+
+2013-03-31  Andrew Cohen  <cohen@bu.edu>
+
+       * nnir.el (nnir-method-default-engines): And another typo.
+
+2013-03-30  Andrew Cohen  <cohen@bu.edu>
+
+       * nnir.el (nnir-method-default-engines): Fix typo.
+
+2013-03-29  Andrew Cohen  <cohen@bu.edu>
+
+       * nnir.el: Define 'number-sequence for xemacs.
+       (gnus-summary-create-nnir-group): New function to create an nnir group
+       from an nnir summary buffer based on the current query.
+       (nnir-request-create-group): Update to allow nnir group creation based
+       on the current query.
+
+2013-03-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nndraft.el (nndraft-request-expire-articles):
+       Make expiry target always `delete'.
+
+2013-03-27  Andrew Cohen  <cohen@bu.edu>
+
+       * gnus-msg.el (gnus-setup-message): When replying from an nnir summary
+       buffer use the posting-style and gcc of the original article group.
+       (gnus-inews-insert-gcc): Don't set gcc-self for virtual groups.
+
+       * nnir.el: Fix byte-compile warning.  nnoo-define-skeleton should come
+       after other deffoos.
+
+2013-03-25  Andrew Cohen  <cohen@bu.edu>
+
+       * nnir.el: Major rewrite.  Cleaner separation between searches and group
+       management.  Marks are now shown in nnir summary buffers.  Rudimentary
+       support for real (i.e. not ephemeral) nnir groups.
+       (gnus-summary-make-nnir-group): New function for initiating searches
+       from a summary buffer.
+
+2013-03-18  Sam Steingold  <sds@gnu.org>
+
+       * message.el (message-bury): Minor cleanup.
+
+2013-03-07  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-cite.el: Specify utf-8, not iso-8859-1, for ASCII file.
+
+2013-03-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nndir.el (nndir-request-list): Remove 2nd argument passed to
+       nnml-request-list.  (Bug#13873)
+       (nndir-request-newsgroups): Remove, unused.
+
+       * nndraft.el (nndraft-request-newsgroups): Remove, unused.
+
+2013-03-05  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * deuglify.el, gnus-delay.el, gnus-spec.el, gnus-sum.el, html2text.el,
+       message.el, mm-decode.el, mml1991.el, nnir.el, shr.el, utf7.el:
+       Prefer UTF-8 when the encoding shouldn't matter and changes are small.
+
+2013-03-03  Ted Phelps  <phelps@gnusto.com>
+
+       * shr.el: Make all the overlays set the `evaporate' property so that
+       they're removed properly.
+
+2013-02-25  Adam Sjøgren  <asjo@koldfront.dk>  (tiny change)
+
+       * mml2015.el (mml2015-epg-key-image): Wrap epg-gpg-program in
+       shell-quote-argument.
+
+2013-02-22  David Engster  <deng@randomsample.de>
+
+       * gnus-registry.el (gnus-registry-save): Provide class name when
+       calling `eieio-persistent-read' to avoid "unsafe call" warning.  Use
+       `condition-case' to stay compatible with older EIEIO versions which
+       only accept one argument.
+
+2013-02-17  Daiki Ueno  <ueno@gnu.org>
+
+       * mml2015.el (epg-key-user-id-list, epg-user-id-string)
+       (epg-user-id-validity): Autoload.
+       (mml2015-epg-check-user-id): New function.
+       (mml2015-epg-check-sub-key): New function split from
+       mml2015-epg-find-usable-key.
+       (mml2015-epg-find-usable-key): Accept context, name, usage, and
+       optional name-is-key-id, to handle the case when user-id is unusable.
+       Reported by Łukasz Stelmach <stlman@poczta.fm>.
+
+2013-02-17  Glenn Morris  <rgm@gnu.org>
+
+       * shr.el (shr-put-image): Use image-multi-frame-p if available.
+
+2013-02-16  Glenn Morris  <rgm@gnu.org>
+
+       * shr.el (shr-put-image): Only animate images that specify a delay.
+       This is consistent with the old image-animated-p behavior.
+
+2013-02-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-define-keys): Convert [?\S-\ ] to [(shift space)]
+       for XEmacs.
+
+2013-02-13  Juri Linkov  <juri@jurta.org>
+
+       * gnus-art.el (gnus-article-mode-map):
+       * gnus-sum.el (gnus-summary-mode-map, gnus-summary-article-map):
+       Make S-SPC scroll in the opposite sense to SPC.  (Bug#2145)
+
+2013-02-07  Gábor Vida  <gabor.v.vida@ericsson.com>  (tiny change)
+
+       * auth-source.el (auth-source-format-prompt): Don't get confused by
+       any "\" in replacement text.  (Bug#13637)
+
+2013-01-30  Christopher Schmidt  <christopher@ch.ristopher.com>
+
+       * gnus-int.el (gnus-backend-trace-elapsed): New variable.
+       (gnus-backend-trace): Honour gnus-backend-trace.
+
+       * mml.el (mml-insert-part): Insert closing tag.
+
+       * mm-decode.el (mm-save-part): Handle invalid read-file-name results.
+
+2013-01-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-read-group-1): Protect against not being
+       able to find the article, which can happen in debbugs groups,
+       apparently.
+
+2013-01-16  Glenn Morris  <rgm@gnu.org>
+
+       * smiley.el (smiley-style): Make the file loadable in batch mode.
+
+2013-01-15  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * nnimap.el (nnimap-keepalive): Don't throw an error if there's no more
+       imap process running.
+
+2013-01-14  Julien Danjou  <julien@danjou.info>
+
+       * gnus-sum.el (gnus-summary-from-or-to-or-newsgroups):
+       Compare addresses against addresses, not against the full From field.
+
+2013-01-13  Richard Stallman  <rms@gnu.org>
+
+       * message.el (message-forward-make-body-mime): New args BEG, END
+       specify what part of FORWARD-BUFFER to use.  Do the work directly
+       instead of calling `mml-insert-buffer'.
+
+2013-01-11  Aaron S. Hawley  <Aaron.Hawley@vtinfo.com>
+
+       * gnus-start.el (gnus-check-new-newsgroups): Fix ambiguous doc string
+       cross-reference(s).
+
+       * gnus-sum.el (gnus-summary-newsgroup-prefix): Fix ambiguous doc string
+       cross-reference(s).
+
+2013-01-11  Dmitry Antipov  <dmantipov@yandex.ru>
+
+       * gnus-art.el (gnus-mime-display-security): Use point-min-marker
+       and point-max-marker.
+       * gnus-async.el (gnus-async-article-callback): Use point-max-marker.
+
+2013-01-11  Julien Danjou  <julien@danjou.info>
+
+       * color.el (color-rgb-to-hsv): Fix conversion computing in case min and
+       max are almost equal.  Also return the correct value for V which is
+       already between 0 and 1.
+
+2013-01-10  Uwe Brauer  <oub@mat.ucm.es>  (tiny change)
+
+       * mml-smime.el (mml-smime-encrypt-to-self): New user option analogous
+       to mml2015-encrypt-to-self.
+       (mml-smime-epg-encrypt): Respect mml-smime-encrypt-to-self.
+
+2013-01-09  Daiki Ueno  <ueno@gnu.org>
+
+       * mml-smime.el (epg-sub-key-fingerprint): Autoload for
+       mml-smime-epg-find-usable-secret-key.
+
+2013-01-08  Glenn Morris  <rgm@gnu.org>
+
+       * mml-smime.el (mml-smime-sign-with-sender): Add :version.
+
+2013-01-07  Daiki Ueno  <ueno@gnu.org>
+
+       * mml-smime.el: Support signing by sender.
+       Requested by Uwe Brauer.
+       (mml-smime-sign-with-sender): New user option analogous
+       to mml2015-sign-with-sender.
+       (mml-smime-epg-sign): Respect mml-smime-sign-with-sender.
+       (mml-smime-epg-find-usable-secret-key): New helper function copied from
+       mml2015.el.
+
+2012-12-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-inews-insert-gcc): Don't insert Gcc headers if Gnus
+       isn't running, because Gnus will probably not know how to handle the
+       Gcc header (bug#11941).
+
+       * nnimap.el (nnimap-update-info): Treat \Deleted articles as \Read
+       articles.
+
+2012-12-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnfolder.el (nnfolder-recursive-directory-files): New function.
+       (nnfolder-generate-active-file): Make this function work with recursive
+       folder names.
+
+2012-12-27  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nntp.el (nntp-open-connection): Use HELP as the capability command
+       instead of CAPABILITY because Typhoon v2.2.2.503 chokes completely on
+       unknown commands.  And CAPABILITY is an unknown command (bug#12763).
+
+2012-12-27  Wolfgang Jenkner  <wjenkner@inode.at>
+
+       * gnus-spec.el (gnus-face-face-function): Don't use nil as no-op face
+       place holder since this gives `Invalid face reference: nil' messages.
+       Use the `default' face instead.  It has the same effect here, even
+       though it is not no-op.
+
+       * gnus-util.el
+       (gnus-put-text-property-excluding-characters-with-faces): Similarly.
+
+2012-12-27  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-summary-resend-message): Don't bug out on
+       non-string posting styles (bug#13285).
+
+2012-12-27  Glenn Morris  <rgm@gnu.org>
+
+       * plstore.el (plstore-passphrase-callback-function):
+       Use plstore-get-file.
+
+2012-12-27  Andreas Schwab  <schwab@linux-m68k.org>
+
+       * mml2015.el (mml2015-epg-key-image): Separate attribute stream from
+       stderr.
+
+2012-12-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml2015.el (mml2015-epg-key-image): Use mm-set-buffer-multibyte.
+
+       * gnus-compat.el (set-buffer-multibyte): Remove.
+
+2012-12-25  Adam Sjøgren  <asjo@koldfront.dk>
+
+       * mml2015.el (mml2015-epg-key-image): Use --attribute-fd rather than
+       temporary file to get PGP key image.  Pass no-show-photos when
+       extracting image to avoid having it pop up twice.
+
+2012-12-26  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-treat-types): Include text/html as parts
+       eligible for treatment.
+
+       * gnus-util.el (gnus-goto-colon): Move to the beginning of the visual
+       lines.  This makes summary commands with hidden threads work more
+       reliably.
+
+       * gnus-cite.el (gnus-article-hide-citation-maybe): Leave an expansion
+       button to mark the hidden citations (bug#9395).
+
+2012-12-26  Daiki Ueno  <ueno@gnu.org>
+
+       * mml2015.el (mml2015-epg-signature-to-string): New function.
+       (mml2015-epg-verify-result-to-string): New function.
+       (mml2015-epg-decrypt, mml2015-epg-clear-decrypt, mml2015-epg-verify)
+       (mml2015-epg-clear-verify): Use mml2015-epg-verify-result-to-string
+       instead of epg-verify-result-to-string.
+       (epg-signature-key-id, epg-signature-to-string): Autoload.
+       (epg-verify-result-to-string): Remove autoload.
+
+2012-12-25  Adam Sjøgren  <asjo@koldfront.dk>
+
+       * mml2015.el (mml2015-epg-key-image): New function, to retrieve photo
+       ID image from GPG public key.
+       (mml2015-epg-key-image-to-string): New function.
+
+2012-12-25  Leo Liu  <sdl.web@gmail.com>
+
+       * plstore.el (plstore-passphrase-callback-function): Fix error when
+       error when plstore-cache-passphrase-for-symmetric-encryption is set
+       (bug#13264).
+
+2012-12-25  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-set-global-variables): Don't copy over the summary
+       buffer to the article buffer here, because that clobbers multiple
+       article buffers.
+
+       * gnus-art.el (gnus-article-setup-buffer): Make sure that the article
+       buffer always points to the right summary buffer.
+
+2012-12-25  John Wiegley  <jwiegley@gmail.com>
+
+       * auth-source.el (auth-source-netrc-parse): Allow using "password" as
+       the password (bug#12097).
+
+2012-12-25  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-tag-a): Don't tagify <A> elements that don't have HREFs
+       (bug#13263).
+
+       * gnus-salt.el (gnus-highlight-selected-tree): Check whether the Tree
+       buffer exists before using it (bug#12475).
+
+       * gnus-agent.el (gnus-agent-fetch-articles): Don't fetch articles from
+       offline groups (bug#11937).
+
+       * message.el (message-yank-original): When using customize to set the
+       value of `message-cite-style', the variable it set to a symbol that's
+       the name of the variable, which must then be dereferenced (bug#12616).
+
+2012-09-13  Wolfgang Jenkner  <wjenkner@inode.at>
+
+       * lisp/gnus-spec.el (gnus-face-face-function): Initialize the value of
+       the `face' property with a list whose car is the face specified in the
+       format string and whose cdr is (nil).
+       * lisp/gnus-util.el
+       (gnus-put-text-property-excluding-characters-with-faces):
+       Change accordingly.
+       (gnus-get-text-property-excluding-characters-with-faces): New function.
+       * lisp/gnus-sum.el (gnus-summary-highlight-line):
+       * lisp/gnus-salt.el (gnus-tree-highlight-node):
+       * lisp/gnus-group.el (gnus-group-highlight-line): Use it.
+
+2012-12-25  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-authenticator): Expand to allow specifying the
+       login methods.
+       (nnimap-login): Respect the `nnimap-authenticator' variable.
+
+       * gnus-sum.el (gnus-summary-push-marks-to-backend): Push the complete
+       mark state when moving articles.  Otherwise unticked articles will get
+       their ticks back after moving.
+
+2012-12-24  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-srvr.el (gnus-browse-delete-group): Fix syntax error.
+
+       * message.el (message-ignored-news-headers): Always remove
+       X-Message-SMTP-Method to avoid information leakage if the user
+       mistakenly inserts the header into news messages.
+
+       * gnus-srvr.el (gnus-browse-delete-group): New command and keystroke.
+
+       * gnus-sum.el (gnus-summary-hide-thread): If point were further to the
+       right than four characters, this command would move point to
+       `point-max'.  Don't do that.
+
+       * gnus-group.el (gnus-group-read-ephemeral-group): Set the active data
+       to nil to allow re-selecting groups that gain articles.
+       (gnus-bug-group-download-format-alist): Update the URL.
+
+2012-12-23  Andreas Schwab  <schwab@suse.de>
+
+       * shr.el (shr-tag-em): Render em as italic, not bold.
+
+2012-12-23  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-int.el (gnus-backend-trace): Factor out into its own function
+       for reuse.
+       (gnus-open-server): Use it to add more tracing.
+       (gnus-finish-retrieve-group-infos): Add backend tracing.
+       (gnus-backend-trace): Also note the elapsed seconds.
+
+2012-12-22  Philipp Haselwarter  <philipp@haselwarter.org>
+
+       * gnus-sync.el (gnus-sync-file-encrypt-to, gnus-sync-save):
+       Set epa-file-encrypt-to from variable to avoid querying.
+
+2012-12-14  Akinori MUSHA  <knu@iDaemons.org>  (tiny change)
+
+       * sieve-mode.el (sieve-font-lock-keywords):
+       Keywords should be word delimited.  (Bug#13173)
+
+2012-12-13  Andreas Schwab  <schwab@suse.de>
+
+       * tls.el (tls-program): Update customize type.
+
+2012-12-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-browse-html-parts): Use <div align="left">
+       instead of <pre> to align message header.
+
+2012-12-12  Sam Steingold  <sds@gnu.org>
+
+       * gnus.el (gnus-other-frame-resume-function): Add user option.
+       (gnus-other-frame): Call `gnus-other-frame-resume-function' on resume.
+
+2012-12-06  Sam Steingold  <sds@gnu.org>
+
+       * gnus-start.el (gnus-before-resume-hook): Add.
+       (gnus-1): Run it when Gnus is alive.
+
+2012-12-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gmm-utils.el (gmm-called-interactively-p): Restore as a macro.
+       * gnus-art.el (article-unsplit-urls)
+       * gnus-bookmark.el (gnus-bookmark-bmenu-list)
+       * gnus-registry.el (gnus-registry-get-article-marks)
+       * message.el (message-goto-body): Use it.
+       (message-called-interactively-p): Remove.
+
+       * spam-stat.el (spam-stat-called-interactively-p): New macro.
+       (spam-stat-score-buffer): Use it.
+
+       * spam.el: Silence the warnings against BBDB functions when compiling.
+
+       * gnus-score.el (gnus-score-decode-text-parts):
+       Use append+mapcar instead of the cl function mapcan.
+
+2012-12-05  Sam Steingold  <sds@gnu.org>
+
+       * gnus.el (gnus-delete-gnus-frame): Extract from `gnus-other-frame'.
+       (gnus-other-frame): Add `gnus-delete-gnus-frame' to
+       `gnus-suspend-gnus-hook' in addition to `gnus-exit-gnus-hook'.
+
+2012-12-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gmm-utils.el (gmm-called-interactively-p): Revert.
+       This seems to cause Emacs to get stuck!
+       * gnus-art.el (article-unsplit-urls)
+       * gnus-bookmark.el (gnus-bookmark-bmenu-list)
+       * gnus-registry.el (gnus-registry-get-article-marks)
+       * message.el (message-goto-body)
+       (message-called-interactively-p): Revert.
+
+       * gmm-utils.el (gmm-called-interactively-p): New function.
+       * gnus-art.el (article-unsplit-urls)
+       * gnus-bookmark.el (gnus-bookmark-bmenu-list)
+       * gnus-registry.el (gnus-registry-get-article-marks)
+       * message.el (message-goto-body): Use it.
+       (message-called-interactively-p): Remove.
+
+       * gmm-utils.el (gmm-flet): Restore it using cl-letf.
+       * gnus-sync.el (gnus-sync-lesync-call)
+       * message.el (message-read-from-minibuffer): Use it.
+
+2012-12-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gmm-utils.el (gmm-flet): Remove.
+       * gnus-sync.el (gnus-sync-lesync-call)
+       * message.el (message-read-from-minibuffer): Don't use it.
+
+2012-12-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gmm-utils.el (gmm-labels): Use cl-labels if available.
+
+2012-12-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gmm-utils.el (gmm-flet, gmm-labels): New macros.
+
+       * gnus-sync.el (gnus-sync-lesync-call)
+       * message.el (message-read-from-minibuffer): Use gmm-flet.
+
+       * gnus-score.el (gnus-score-decode-text-parts): Use gmm-labels.
+
+       * gnus-util.el (gnus-macroexpand-all): Remove.
+
+2012-12-03  Andreas Schwab  <schwab@linux-m68k.org>
+
+       * gnus-sum.el (gnus-summary-mode-map): Bind gnus-summary-widget-forward
+       to TAB, not [tab].
+       (gnus-summary-article-map): Likewise.
+
+       * gnus-sync.el (gnus-sync-newsrc-offsets): Restore definition.
+       (gnus-sync-save): Use correct format for gnus-sync-newsrc-loader.
+
+2012-11-21  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * time-date.el: Commentary fix.
+
+2012-11-19  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * color.el: Don't require cl.
+       (color-complement): `caddr' -> `nth 2'.
+
+       * time-date.el (time-to-seconds): De-obsolete.
+
+2012-11-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-get-reply-headers):
+       Make sure the reply goes to the author if it is a wide reply.
+
+2012-11-16  Jan Tatarik  <jan.tatarik@gmail.com>
+
+       * gnus-score.el (gnus-score-body):
+       * gnus-logic.el (gnus-advanced-body): Don't score by headers when
+       scoring by body.
+
+2012-11-16  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-diary.el (nndiary-request-create-group-functions)
+       (nndiary-request-update-info-functions)
+       (gnus-subscribe-newsgroup-functions)
+       (nndiary-request-accept-article-functions):
+       Use new names for hooks rather than obsolete aliases.
+
+2012-11-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (define-obsolete-variable-alias): Simplify.
+
+2012-11-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-browse-html-parts): Always replace charset
+       in meta tag with the one the part specifies in its header.
+
+2012-10-25  Stephen Eglen  <S.J.Eglen@damtp.cam.ac.uk>
+
+       * gnus-dired.el (gnus-dired-attach): Attach to last used message buffer
+       by default.
+
+2012-10-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (define-compiler-macro): Add autoload for XEmacs 21.4
+       and SXEmacs.  Suggested by Nelson Ferreira <nelson.ferreira@ieee.org>.
+
+2012-10-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (define-obsolete-variable-alias): Add a compiler-marco
+       and a runtime function for it, of which the XEmacs version takes only
+       two arguments.
+
+2012-10-23  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * nndiary.el (nndiary-request-create-group-functions)
+       (nndiary-request-update-info-functions)
+       (nndiary-request-accept-article-functions):
+       * gnus-start.el (gnus-subscribe-newsgroup-functions): Don't use
+       "-hooks" suffix.
+
+2012-10-19  Julien Danjou  <julien@danjou.info>
+
+       * gnus-art.el: Require gnus-util because it uses
+       `gnus-timer--function'.
+
+2012-10-17  Kazuhiro Ito  <kzhr@d1.dion.ne.jp>  (tiny change)
+
+       * starttls.el (starttls-extra-arguments): Doc fix.
+
+2012-10-09  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-insert): \r is also not inserted, so don't try to delete
+       it.
+
+2012-10-06  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-notifications.el (gnus-notifications):
+       Add missing group :version tag.
+       * gnus-msg.el (gnus-gcc-pre-body-encode-hook)
+       (gnus-gcc-post-body-encode-hook):
+       * gnus-sync.el (gnus-sync-lesync-name)
+       (gnus-sync-lesync-install-topics): Add missing custom :version tags.
+
+2012-10-06  Julian Scheid  <julians37@gmail.com>  (tiny change)
+
+       * color.el (color-hsl-to-rgb): Fix incorrect results for
+       small and large hue values.  (Bug#12559)
+
+2012-10-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       New UIDL implementation.
+
+       * mail-source.el (mail-sources, mail-source-keyword-map):
+       Add :leave as a pop3 keyword.
+       (mail-source-fetch-pop): Bind pop3-leave-mail-on-server.
+
+       * pop3.el (pop3-leave-mail-on-server): Allow number.
+       (pop3-uidl-file, pop3-uidl-file-backup): New user options.
+       (pop3-movemail): Add UIDL support.
+       (pop3-send-streaming-command): Take a list of mail numbers instead of
+       the number of mails.
+       (pop3-write-to-file): Add X-UIDL header.
+       (pop3-uidl-stat, pop3-uidl-dele, pop3-uidl-load, pop3-uidl-save)
+       (pop3-uidl-add-xheader): New functions.
+
+       * message.el (message-ignored-resent-headers):
+       Add X-Content-Length and X-UIDL headers.
+
+2012-10-05  Glenn Morris  <rgm@gnu.org>
+
+       * color.el (color-name-to-rgb, color-rgb-to-hex)
+       (color-hue-to-rgb, color-hsl-to-rgb, color-rgb-to-hsv)
+       (color-rgb-to-hsl, color-srgb-to-xyz, color-saturate-hsl)
+       (color-desaturate-hsl, color-desaturate-name, color-lighten-hsl)
+       (color-lighten-name, color-darken-hsl, color-darken-name): Doc fixes.
+
+2012-09-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-browse-delete-temp-files): Never ask again
+       a user about whether to delete temp files if once a user answered as n.
+
+2012-09-25  Chong Yidong  <cyd@gnu.org>
+
+       * password-cache.el (password-read-and-add): Use a declare form to mark
+       this function obsolete.
+
+2012-09-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Bind mail-encode-mml for old Emacsen.
+
+2012-09-17  Richard Stallman  <rms@gnu.org>
+
+       * message.el (message-in-body-p): Don't set mark or modify buffer.
+
+       * mml.el (mml-attach-file): Doc fix.
+       (mml-attach-external, mml-attach-buffer, mml-attach-file):
+       Set mail-encode-mml when in Mail mode.
+       Simplify code to set HEAD and move back to HEAD.
+       (mml-insert-multipart, mml-insert-part):
+       Set mail-encode-mml when in Mail mode.
+
+2012-09-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-timer--function): New function.
+
+       * gnus-art.el (gnus-article-stop-animations): Use it.
+
+2012-09-13  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Fix glitches caused by addition of psec to timers.
+       * gnus-art.el (gnus-article-stop-animations): Use timer--function
+       rather than raw access to timer vector.
+
+2012-09-11  Julien Danjou  <julien@danjou.info>
+
+       * gnus-notifications.el (gnus-notifications): Check for nil values in
+       ignored addresses check.
+
+2012-09-10  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * qp.el (quoted-printable-decode-region): Inline+CSE+strength-reduction.
+
+2012-09-07  Chong Yidong  <cyd@gnu.org>
+
+       * gnus-util.el
+       (gnus-put-text-property-excluding-characters-with-faces): Restore.
+
+       * gnus-salt.el (gnus-tree-highlight-node):
+       * gnus-sum.el (gnus-summary-highlight-line):
+       * gnus-group.el (gnus-group-highlight-line): Revert use of add-face.
+
+2012-09-06  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-util.el: Fix compilation error on XEmacs 21.4.
+
+2012-09-06  Juri Linkov  <juri@jurta.org>
+
+       * gnus-group.el (gnus-read-ephemeral-gmane-group): Change the naming
+       scheme for buffer names to be more consistent with other group and
+       article buffer names in Gnus.
+
+2012-09-06  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-util.el
+       (gnus-put-text-property-excluding-characters-with-faces): Removed.
+
+       * gnus-compat.el: Define compat function `add-face' from Wolfgang
+       Jenkner.
+
+       * gnus-group.el (gnus-group-highlight-line): Use combining faces.
+
+       * gnus-sum.el (gnus-summary-highlight-line): Ditto.
+
+       * gnus-salt.el (gnus-tree-highlight-node): Ditto.
+
+2012-09-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-score.el (gnus-score-decode-text-parts): Use #' for
+       mm-text-parts used in labels macro to make it work with XEmacs 21.5.
+
+       * gnus-util.el (gnus-string-prefix-p): New function, an alias to
+       string-prefix-p in Emacs >=23.2.
+
+       * nnmaildir.el (nnmaildir--ensure-suffix, nnmaildir--add-flag)
+       (nnmaildir--remove-flag, nnmaildir--scan): Use gnus-string-match-p
+       instead of string-match-p.
+       (nnmaildir--scan): Use gnus-string-prefix-p instead of string-prefix-p.
+
+2012-09-06  Kenichi Handa  <handa@gnu.org>
+
+       * qp.el (quoted-printable-decode-region): Fix previous change; handle
+       lowercase a..f.
+
+2012-09-05  Magnus Henoch  <magnus.henoch@gmail.com>
+
+       * nnmaildir.el (nnmaildir--article-set-flags): Fix compilation error.
+
+2012-09-05  Martin Stjernholm  <mast@lysator.liu.se>
+
+       * nnimap.el (nnimap-request-move-article): Decode the group name when
+       doing internal moves to avoid charset issues.
+
+       * gnus-demon.el (gnus-demon-init): Fixed regression when IDLE is t and
+       TIME is set.
+
+2012-09-05  Juri Linkov  <juri@jurta.org>
+
+       * gnus-group.el (gnus-read-ephemeral-bug-group): Allow opening more
+       than one group at a time (bug#11961).
+
+2012-09-05  Julien Danjou  <julien@danjou.info>
+
+       * gnus-srvr.el (gnus-server-open-server): Don't message on failure:
+       this hide the real reason with a message giving absolutely no hint.
+
+2012-09-05  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-mark-article-read): Propagate the read mark
+       to the backend (bug#11804).
+
+       * message.el (message-insert-newsgroups): Don't insert newsgroup
+       duplicates (bug#12275).
+
+2012-09-05  John Wiegley  <johnw@newartisans.com>
+
+       * gnus.el (gnus-expand-group-parameters): Allow regexp substitutions in
+       sieve rules.
+
+2012-09-05  Jan Tatarik  <jan.tatarik@gmail.com>
+
+       * gnus-score.el (gnus-score-decode-text-parts): Use #' for the local
+       function.
+
+       * gnus-logic.el (gnus-advanced-body): Allow scoring on decoded bodies.
+
+       * gnus-score.el (gnus-score-decode-text-parts): Ditto.
+
+2012-09-05  Magnus Henoch  <magnus.henoch@gmail.com>
+
+       * nnmaildir.el: Make nnmaildir understand and write maildir flags.
+       That is, rename files from "unique:2," to "unique:2,S" for "seen", etc.
+       This should make nnmaildir more usable with offlineimap.
+
+2012-09-05  Julien Danjou  <julien@danjou.info>
+
+       * nnimap.el (nnimap-request-list): Revert change that made listing
+       synchronous.
+       (nnimap-get-responses): Restore.
+
+2012-09-03  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * dgnushack.el: XEmacs 21.5 compilation fix.
+
+       * gnus-notifications.el (gnus-notifications-notify): Use it.
+
+       * gnus-fun.el (gnus-funcall-no-warning): New function to silence
+       warnings on XEmacs.
+
+2012-09-01  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Better seeds for (random).
+       * gnus-sync.el (gnus-sync-lesync-setup):
+       * message.el (message-canlock-generate, message-unique-id):
+       Change (random t) to (random), now that the latter is more random.
+
+2012-08-31  Dave Abrahams  <dave@boostpro.com>
+
+       * nnimap.el (nnimap-change-group): Document result value
+
+       * auth-source.el (auth-sources): Fix macos keychain access.
+
+       * gnus-int.el (gnus-request-head): When gnus-override-method is set,
+       allow the backend `request-head' function to determine the group
+       name on its own.
+       (gnus-request-expire-articles): Filter out negative article numbers
+       during expiry (Bug#11980).
+
+       * gnus-range.el (gnus-set-difference): Change gnus-set-difference from
+       O(N^2) to O(N).  This makes warping into huge groups tolerable.
+
+       * gnus-registry.el (gnus-try-warping-via-registry): Don't act as though
+       you've found the article when you haven't.
+
+       * nnimap.el (nnimap-find-article-by-message-id): Account for the fact
+       that nnimap-change-group can return t.
+
+2012-08-31  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-notifications.el (gnus-notifications-action): Avoid CL-ism.
+
+2012-08-30  Julien Danjou  <julien@danjou.info>
+
+       * gnus-notifications.el (gnus-notifications-notify): Use timeout from
+       `gnus-notifications-timeout'.
+       (gnus-notifications-timeout): Add.
+       (gnus-notifications-action): New function.
+       (gnus-notifications-notify): Add :action using
+       `gnus-notifications-action'.
+       (gnus-notifications-id-to-msg): New variable.
+       (gnus-notifications): Use `gnus-notifications-id-to-msg' to map
+       notifications id to messages.
+
+2012-08-30  Kenichi Handa  <handa@gnu.org>
+
+       * qp.el (quoted-printable-decode-region): Decode multiple bytes at
+       once.
+
+2012-08-29  Julien Danjou  <julien@danjou.info>
+
+       * gnus-notifications.el: New file.
+       (gnus-notifications-notify): New function.
+       (gnus-notifications): Use `gnus-notifications-notify'.
+
+2012-08-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-enter-digest-group): Decode content
+       transfer encoding first; bind gnus-newsgroup-charset to the charset
+       that the article specifies (Bug#12209).
+
+2012-08-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-cus.el (gnus-group-customize): Decode values posting-style holds.
+       (gnus-group-customize-done): Encode values posting-style holds.
+
+       * gnus-msg.el (gnus-summary-resend-message)
+       (gnus-configure-posting-styles): Decode values posting-style group
+       parameter holds.
+
+2012-08-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-summary-resend-message): Honor posting-style for
+       `name' and `address' in Resent-From header.
+
+2012-08-14  Chong Yidong  <cyd@gnu.org>
+
+       * gnus-art.el (article-display-face): Handle failure in
+       gnus-create-image (Bug#11802).
+
+2012-08-10  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-agent.el (gnus-agent-cat-defaccessor, gnus-agent-cat-groups):
+       Use defsetf.
+
+2012-08-10  Daiki Ueno  <ueno@unixuser.org>
+
+       * auth-source.el (auth-source-plstore-search)
+       (auth-source-secrets-search): Ignore :require and :type in search spec.
+
+2012-08-06  Julien Danjou  <julien@danjou.info>
+
+       * nnimap.el (nnimap-request-head): Resture to-buffer parameter, used by
+       `nnimap-request-move-article'.
+
+       * gnus-demon.el (gnus-demon-add-handler, gnus-demon-remove-handler):
+       Remove autoload, already handled by gnus.el.
+
+       * nnimap.el (nnimap-request-head): Remove to-buffer argument.
+
+       * gnus-int.el (gnus-request-head): Remove to-buffer argument, only
+       supported by nnimap actually.  Reverts previous change.
+
+       * gnus-int.el (gnus-request-head): Add an optional to-buffer parameter
+       to mimic `gnus-request-article' and enjoy backends the nn*-request-head
+       to-buffer argument that is already supported.
+
+2012-08-05  Julien Danjou  <julien@danjou.info>
+
+       * gnus-demon.el (gnus-demon-add-handler, gnus-demon-remove-handler):
+       Add autoload.
+
+2012-07-31  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (gnus-valid-select-methods): Fix custom type.
+
+2012-07-29  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-sources, auth-source-backend-parse)
+       (auth-source-macos-keychain-search)
+       (auth-source-macos-keychain-search-items)
+       (auth-source-macos-keychain-result-append)
+       (auth-source-macos-keychain-create): Support Mac OS X Keychains in
+       auth-source.el through the /usr/bin/security utility.
+       (auth-sources): Fix syntax error.
+       (auth-source-macos-keychain-result-append): Fix variable name.
+       (auth-sources, auth-source-macos-keychain-result-append): More fixes.
+
+2012-07-27  Julien Danjou  <julien@danjou.info>
+
+       * message.el (fboundp): Add a defalias on `mail-dont-reply-to' for
+       Emacs < 24.1
+
+2012-07-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-kill-address): Don't kill last newline.
+       (message-skip-to-next-address): Don't move to the next header.
+       (message-fill-field-address): Work properly.
+
+2012-07-25  Julien Danjou  <julien@danjou.info>
+
+       * gnus-art.el (gnus-kill-sticky-article-buffers): Reintroduce.
+
+2012-07-24  Julien Danjou  <julien@danjou.info>
+
+       * mail-source.el (mail-source-movemail-and-remove): Remove, unused.
+
+       * nntp.el (nntp-send-nosy-authinfo, nntp-send-authinfo-from-file)
+       (nntp-async-timer-handler): Remove, unused.
+
+       * nnimap.el (nnimap-get-responses): Remove, unused.
+
+       * nnheader.el (mail-header-set-extra): Remove, unused.
+
+       * netrc.el (netrc-find-service-number, netrc-store-data): Remove,
+       unused.
+
+       * mm-view.el (mm-view-sound-file): Remove, unused.
+
+       * mm-url.el (mm-url-fetch-simple, mm-url-fetch-form)
+       (mm-url-encode-multipart-form-data): Remove, unused.
+
+       * message.el (message-remove-signature, message-make-host-name)
+       (message-fill-address): Remove, unused.
+
+       * gnus.el (gnus-writable-groups, gnus-group-guess-prefixed-name)
+       (gnus-group-guess-full-name, gnus-group-guess-prefixed-name): Remove,
+       unused.
+
+       * gnus-xmas.el (gnus-xmas-highlight-selected-summary)
+       (gnus-xmas-call-region): Remove, unused.
+
+       * gnus-uu.el (gnus-uu-find-name-in-shar): Remove, unused.
+
+       * gnus-util.el (gnus-extract-address-component-name)
+       (gnus-extract-address-component-email, gnus-sortable-date)
+       (gnus-alist-to-hashtable, gnus-hashtable-to-alist)
+       (gnus-process-live-p): Remove, unused.
+
+       * gnus-topic.el (gnus-group-parent-topic): Remove, unused.
+
+       * gnus-sum.el (gnus-score-set-default, gnus-article-parent-p)
+       (gnus-article-read-p, gnus-uncompress-marks): Remove, unused.
+       (gnus-summary-set-current-mark): Remove obsolete, empty and unused
+       function.
+
+       * gnus-start.el (gnus-kill-newsgroup): Remove unused obsolete function.
+
+       * gnus-score.el (gnus-summary-score-crossposting)
+       (gnus-score-regexp-bad-p): Remove, unused.
+
+       * gnus-salt.el (gnus-tree-goto-article): Remove, unused.
+
+       * gnus-range.el (gnus-sublist-p): Remove, unused.
+
+       * gnus-msg.el (gnus-mail-parse-comma-list, gnus-put-message): Remove,
+       unused.
+
+       * gnus-kill.el (gnus-Newsgroup-kill-file): Remove, unused.
+
+       * gnus-int.el (gnus-list-active-group, gnus-request-group-articles)
+       (gnus-request-associate-buffer): Remove, unused.
+
+       * gnus-group.el (gnus-group-set-method-info)
+       (gnus-group-set-params-info): Remove, unused.
+
+       * gnus-fun.el (gnus-shell-command-to-string)
+       (gnus-shell-command-on-region): Remove, unused.
+
+       * gnus-cite.el (gnus-cited-line-p): Remove, unused.
+
+       * gnus-art.el (gnus-article-text-type-exists-p)
+       (article-translate-characters, gnus-article-hide-text-of-type)
+       (gnus-kill-sticky-article-buffers, gnus-article-maybe-highlight):
+       Remove, unused.
+
+2012-07-22  Andrew Cohen  <cohen@bu.edu>
+
+       * nnir.el ("nnir"): Add 'virtual ability to nnir backend.
+
+2012-07-21  Julien Danjou  <julien@danjou.info>
+
+       * message.el (message-dont-reply-to-names): Replace deprecated
+       `rmail-dont-reply-to-names' with `mail-dont-reply-to-names'.
+       (message-get-reply-headers): Ditto.
+
+2012-07-18  Julien Danjou  <julien@danjou.info>
+
+       * sieve-mode.el (sieve-mode-map): Bind C-c C-c to
+       `sieve-upload-and-kill'.
+
+       * sieve.el (sieve-bury-buffer): Remove function.
+       (sieve-manage-mode-map): Map "q" to `kill-buffer'.
+       (sieve-upload-and-kill): New function, mapped to C-c C-c.
+
+2012-07-17  Andreas Schwab  <schwab@linux-m68k.org>
+
+       * shr.el (shr-expand-url): Handle URL starting with `//'.
+
+2012-07-13  Chong Yidong  <cyd@gnu.org>
+
+       * smime.el (smime-certificate-info): Set buffer-read-only directly,
+       instead of calling toggle-read-only with a (bogus) argument.
+
+2012-07-09  Tassilo Horn  <tassilo@member.fsf.org>
+
+       * gnus-sum.el (gnus-summary-limit-to-author): Use default value instead
+       of initial input when reading the author to restrict the summary to.
+
+2012-07-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-shr):
+       Allow overriding charset by mm-charset-override-alist.
+
+2012-07-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-view-part):
+       Toggle subparts of multipart/alternative part.
+
+2012-06-27  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * shr.el (shr-render-buffer): New command.
+       (shr-visit-file): Use it.
+
+2012-06-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * tests/gnustest-nntp.el, tests/gnustest-registry.el:
+       Set no-byte-compile and no-update-autoloads.
+
+2012-06-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el: Add coding cookie for a soft hyphen that mm-shr uses.
+
+2012-06-25  Julien Danjou  <julien@danjou.info>
+
+       * nnimap.el (nnimap-request-articles-find-limit): Rename from
+       `nnimap-request-move-articles-find-limit' since we do not use it only
+       for move operations.
+       (nnimap-request-accept-article): Use
+       `nnimap-request-articles-find-limit' to limit search by message-id.
+
+2012-06-22  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Support higher-resolution time stamps (Bug#9000).
+
+       * time-date.el (with-decoded-time-value): New arg PICO-SYMBOL in
+       VARLIST.  It's optional, for backward compatibility.
+       (encode-time-value): New optional arg PICO.  New type 3.
+       (time-to-seconds) [!float-time]: Support the new picoseconds
+       component if it's used.
+       (seconds-to-time, time-subtract, time-add):
+       Support ps-resolution time stamps as well.
+
+2012-06-19  Julien Danjou  <julien@danjou.info>
+
+       * nnir.el (nnir-run-imap): Fix, use `nnimap-change-group'.
+
+       * nnimap.el (nnimap-log-buffer): Check that
+       `window-point-insertion-type' is boundp, since it's not available in
+       XEmacs.
+
+2012-06-19  Michael Welsh Duggan  <md5i@md5i.com>  (tiny change)
+
+       * nnimap.el (nnimap-log-buffer): Add this, setting
+       `window-point-insertion-type' in the buffer to t.
+       (nnimap-log-command): Use nnimap-log-buffer.
+
+2012-06-19  Julien Danjou  <julien@danjou.info>
+
+       * nnimap.el (nnimap-find-article-by-message-id): Add an optional limit
+       argument to be able to limit the search.
+       (nnimap-request-move-article): Use `nnimap-request-move-articles-find-limit'.
+       (nnimap-request-move-articles-find-limit): Add this to limit the search
+       by Message-Id after a message move.
+       (nnimap): Add defgroup.
+
+2012-06-18  Nelson Ferreira  <nelson.ferreira@ieee.org>  (tiny change)
+
+       * gnus-win.el (gnus-configure-frame): Pass an arg to window-dedicated-p.
+
+2012-06-15  Julien Danjou  <julien@danjou.info>
+
+       * nnimap.el (nnimap-find-article-by-message-id): Use
+       `nnimap-possibly-change-group' rather than its own EXAMINE call.
+       (nnimap-possibly-change-group): Add read-only argument.
+       (nnimap-request-list): Use nnimap-possibly-change-group rather than
+       issuing EXAMINE manually.
+       (nnimap-find-article-by-message-id): Use `nnimap-possibly-change-group'
+       with read-only argument.
+       (nnimap-change-group): Rename from `nnimap-possibly-change-group'.  We
+       cannot possibly change because we need to be sure that it's either
+       read-write or read-only.
+
+2012-06-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-read-summary-keys): Protect against the key
+       being bound to a lambda form.
+
+2012-04-14  Wolfgang Jenkner  <wjenkner@inode.at>
+
+       * gnus-agent.el (gnus-agent-retrieve-headers): Recalculate the range of
+       articles when fetch-old is non-nil (bug#11370).
+
+2012-05-04  Wolfgang Jenkner  <wjenkner@inode.at>
+
+       * gnus-picon.el (gnus-picon-properties): New defcustom.
+       (gnus-picon-create-glyph): Use it.
+
+2012-06-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-get-new-news): Respect
+       `gnus-group-use-permanent-levels', as documented (bug#11638).
+
+2012-06-10  Dave Abrahams  <dave@boostpro.com>
+
+       * gnus-int.el (gnus-warp-to-article): Limit registry warping to real
+       groups (bug#11641).
+
+2012-06-10  Toke Høiland-Jørgensen  <toke@toke.dk>  (tiny change)
+
+       * nnmaildir.el (nnmaildir-request-expire-articles): Ensure that `time'
+       is an integer to avoid later problems.
+
+2012-06-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el: Add a iso-8859-1 cookie to make stuff work under other
+       locales.
+
+       * mm-decode.el (mm-display-part): Dissect archives when hitting `RET'
+       on a handle.
+
+       * gnus-sum.el (gnus-summary-limit-to-author): Use the current From
+       address as the default.
+       (gnus-summary-insert-old-articles): Don't include unexisting messages.
+
+       * nnfolder.el (nnfolder-save-buffer): Delete old versions silently.  It
+       makes no sense to query the user about internal files.
+
+       * gnus-spec.el: Remove all the byte-compilation stuff, since
+       benchmarking shows that it doesn't help when entering large summary
+       buffers.
+
+       * gnus-xmas.el (gnus-xmas-define): Remove.
+
+       * gnus-util.el (gnus-byte-code): Remove.
+
+       * gnus-spec.el (gnus-update-format-specifications): Remove outdated
+       grouplens stuff.
+
+2012-06-07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-msg-mail): Warn the user about Gnus not running
+       (bug#11514).
+
+2012-06-07  Stephen Eglen  <S.J.Eglen@damtp.cam.ac.uk>
+
+       * message.el (message-buffers): Return all buffers derived from Message
+       to make `gnus-dired-attach' work with mu4e.
+
+2012-06-01  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * nntp.el: Stop the `letf' madness.
+       (nntp--report-1): New var.
+       (nntp-report): Merge nntp-report-1 into it.
+       (nntp-with-open-group-function): Set nntp--report-1 instead of modifying
+       the nntp-report function.
+
+       * auth-source.el: Fix comment-style to follow the convention.
+
+2012-05-28  Daiki Ueno  <ueno@unixuser.org>
+
+       * mm-decode.el (mm-inhibit-auto-detect-attachment): New variable.
+       (mm-dissect-singlepart): Don't guess the MIME type of
+       application/octet-stream parts if mm-inhibit-auto-detect-attachment is
+       set.
+       (mm-dissect-multipart): Bind mm-inhibit-auto-detect-attachment if the
+       toplevel MIME type is multipart/encrypted.
+
+2012-05-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-msg-mail): Ensure that gnus-newsgroup-name is
+       a string so that Gcc works (bug#11514).
+
+2012-05-26  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * legacy-gnus-agent.el (gnus-agent-unhook-expire-days):
+       * gnus-demon.el (gnus-demon-init): Don't bother with type-of.
+
+2012-05-25  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-win.el (gnus-configure-frame): Don't signal an error when
+       jumping to *Server* from a dedicated *Group* window.
+       (gnus-configure-frame): CSE.
+
+       * gnus-registry.el: Minor style cleanup.
+       (gnus-registry--set/remove-mark): New function, extracted from
+       gnus-registry-install-shortcuts.
+       (gnus-registry-install-shortcuts): Use it.
+
+2012-05-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnspool.el (news-path): Use eval-and-compile.
+
+2012-05-24  Glenn Morris  <rgm@gnu.org>
+
+       * nnspool.el (news-directory, news-path, news-inews-program):
+       Move here from paths.el.  Don't see a need for these to be autoloaded.
+
+       * gnus.el (gnus-default-nntp-server): Make it a defcustom.
+       Merge in doc from paths.el version.  Don't see any need for this to be
+       autoloaded, or for the warning about users not setting it.
+
+2011-12-02  Wolfgang Jenkner  <wjenkner@inode.at>
+
+       * gnus-agent.el (gnus-agent-save-active): Deal with the "groups"
+       format.  In particular, add an optional argument and a docstring.
+
+       * gnus-start.el (gnus-groups-to-gnus-format): Use it.
+
+       * nntp.el (nntp-finish-retrieve-group-infos): Make `nntp-server-buffer'
+       current before calling `gnus-groups-to-gnus-format'.
+       Note that this was already the case for `gnus-active-to-gnus-format'.
+
+2012-05-04  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Fix minor Y10k bug.
+       * nnweb.el (nnweb-google-parse-1): Don't assume years have 4 digits.
+
+2012-05-01  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * nnimap.el (nnimap-open-connection-1): Don't leave an "opening..."
+       message once it's actually open.
+
+2012-05-01  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Ma Gnus v0.5 is released.
+
+2012-04-28  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * auth-source.el (auth-source--aput-1, auth-source--aput)
+       (auth-source--aget): New functions and macros.
+       Use them instead of aput/aget.
+
+2012-04-27  Andreas Schwab  <schwab@linux-m68k.org>
+
+       * gnus.el (debbugs-gnu): Don't override existing autoload definition.
+
+2012-04-26  Daiki Ueno  <ueno@unixuser.org>
+
+       * plstore.el (plstore-called-interactively-p): New compat macro copied
+       from message.el.
+       (plstore-mode): Use it.
+
+2012-04-26  Daiki Ueno  <ueno@unixuser.org>
+
+       * plstore.el: Revive the editing feature.
+       (plstore-mode): New mode to edit plstore file.
+       (plstore-mode-toggle-display, plstore-mode-original)
+       (plstore-mode-decoded): New command.
+       (plstore--encode, plstore--decode, plstore--write-contents-functions)
+       (plstore--insert-buffer, plstore--make): New function.
+       (plstore-open, plstore-save): Simplify by using them.
+
+2012-04-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * pop3.el (pop3-wait-for-messages): Fix retrieved data size calculation.
+
+2012-04-19  Juanma Barranquero  <lekktu@gmail.com>
+
+       * tls.el (open-tls-stream): Remove unused binding.
+
+2012-04-16  Glenn Morris  <rgm@gnu.org>
+
+       * nndraft.el (nndraft-request-list): Fix declaration.
+
+2012-04-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-dissect-buffer): Doc fix.
+
+       * gnus-msg.el (gnus-inews-insert-gcc): Don't do the alist stuff when we
+       don't have a current group.
+
+       * gnus-sum.el (gnus-handle-ephemeral-exit): Avoid creating the group
+       buffer if it doesn't exist.
+
+       * gnus-group.el (gnus-group-read-ephemeral-group): If no quit-config is
+       given, mark the group as ephemeral with the current window conf.
+
+       * gnus-sum.el (gnus-set-global-variables): Don't assume that the group
+       buffer exists, which it doesn't if we haven't started Gnus.
+       (gnus-summary-exit): Allow quitting when we don't have a group buffer.
+
+2012-04-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml.el (mml-generate-mime): Allow specifying what the top-level part
+       type is.
+
+       * gnus-start.el (gnus-clean-old-newsrc): Remove totally bogus
+       `unexists' entries.
+       (gnus-clean-old-newsrc): Fix last checkin.
+
+       * nnimap.el (nnimap-update-info): None of the articles below the active
+       low-water mark exist.
+
+       * dgnushack.el: Get rid of XEmacs compilation warning.
+
+       * gnus-msg.el (gnus-summary-cancel-article): See what From header we
+       would have gotten if we posted to the group, and use that to compare
+       against the message we want to cancel (bug#10808).
+
+       * gnus-sum.el (gnus-auto-center-summary): `scroll-margin' isn't defined
+       on XEmacs.
+
+2012-04-10  Philipp Haselwarter  <philipp.haselwarter@gmx.de>  (tiny change)
+
+       * gnus-sum.el (gnus-auto-center-summary): Set default to respect
+       `scroll-margin'.
+
+2012-04-10  Elias Oltmanns  <eo@nebensachen.de>  (tiny change)
+
+       * gnus-cite.el (gnus-dissect-cited-text): A single line without
+       citation prefix within a block of cited text should be considered part
+       of that block *only* if it is a blank line.
+
+2012-04-09  Chong Yidong  <cyd@gnu.org>
+
+       * binhex.el, hashcash.el, uudecode.el:
+       Remove * characters from the front of variable docstrings.
+
+2012-04-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el (shr-find-fill-point): Remove unused code; don't break a line
+       before kinsoku-bol characters nor within kinsoku-eol characters.
+
+2012-03-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sync.el (gnus-topic-alist, gnus-group-topic)
+       (gnus-topic-create-topic, gnus-topic-enter-dribble): Silence compiler.
+       (gnus-sync-read): Use mapc instead of mapcar.
+
+       * mm-archive.el: Require mm-decode for some macros.
+       (gnus-recursive-directory-files, mailcap-extension-to-mime): Silence
+       the byte compiler.
+       (mm-archive-decoders): New function that returns the value of
+       the mm-archive-decoders variable.
+
+       * mm-decode.el: Don't require mm-archive; autoload mm-archive functions
+       instead.
+       (mm-dissect-singlepart): Use the function mm-archive-decoders.
+
+       * nnimap.el (gnus-refer-thread-use-nnir):
+       * nnmail.el (mail-send-and-exit): Silence the byte compiler.
+
+2012-03-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-compat.el: Define `bound-and-true-p' for XEmacs.
+
+2012-03-12  Peter Münster  <pmrb@free.fr>
+
+       * gnus-demon.el (gnus-demon-timers): Now a plist (function -> timer).
+       (gnus-demon-cancel): Ditto.
+       (gnus-demon-run-callback): When function cannot be called due to low
+       idleness, call it when idleness reaches the expected value, instead of
+       waiting another timer period.
+       (gnus-demon-init): Add `time' to arguments of call-back.
+
+2012-03-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * dgnushack.el: Bind `gnus-registry-enabled' for XEmacs.
+
+       * gnus.el: Register gnus-registry functions.
+
+       * gnus-registry.el (gnus-try-warping-via-registry): Moved here and
+       indent.
+
+       * gnus-int.el (gnus-warp-to-article): Check whether the registry is
+       enabled before warping.
+
+2012-03-22  Dave Abrahams  <dave@boostpro.com>
+
+       * gnus-sum.el (gnus-summary-insert-subject): Record information in the
+       registry about each article retrieved.
+
+       * gnus-int.el (gnus-select-group-with-message-id): New function.
+       (gnus-try-warping-via-registry): Ditto.
+       (gnus-warp-to-article): Fall back on the registry.
+
+2012-03-22  Sergio Martínez  <samf0xb58@gmail.com>  (tiny change)
+
+       * nnimap.el (nnimap-request-scan): Allow `nnimap-inbox' to be a list of
+       inboxes.
+
+2012-03-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-fetch-partial-articles): Minor doc string fixup.
+
+2012-03-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-summary-resend-message-insert-gcc): Assume that
+       gnus-gcc-self-resent-messages may be a group parameter.
+       (gnus-summary-resend-message): Don't encode encoded words in header
+       when Gcc'ing resent message.
+
+2012-03-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-insert): Treat non-breaking space just like normal
+       space.  This seems to produce more pleasing results.
+       (shr-insert): Only insert a blank line if we're starting from an image.
+       (shr-tag-br): Allow <br> to end lines or to make a single blank line.
+       (shr-ensure-paragraph): Consider lines with white space to be blank.
+
+2012-03-15  Elias Pipping  <pipping@lavabit.com>
+
+       * Makefile.in: Respect DESTDIR.
+
+2012-03-14  Christopher Schmidt  <christopher@ch.ristopher.com>
+
+       * gnus-msg.el (gnus-inews-do-gcc): Add gnus-gcc-pre-body-encode-hook
+       and gnus-gcc-post-body-encode-hook.
+
+2012-03-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-expire-articles-1): Don't try to expire
+       messages that don't exist.
+
+       * gnus-sum.el (gnus-summary-expire-articles): Ditto.
+
+2012-04-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       pgg-def.el, pgg-gpg.el, pgg-parse.el, pgg-pgp.el, pgg-pgp5.el, pgg.el:
+       Remove.
+
+       dgnushack.el (pgg-snarf-keys-region): Remove autoload.
+
+       lpath.el (pgg-parse-crc24-string, pgg-parse-crc24): Remove declaration.
+
+2012-04-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-inews-insert-gcc): Protect against when we don't
+       have a group name.
+
+       * gnus-art.el (article-wash-html): Ensure that we insert the HTML into
+       a multibyte buffer (bug#7410).
+       (article-wash-html): Parse the original article buffer to get the
+       unencoded data (bug#7410).
+
+       * gnus-start.el (gnus-read-newsrc-el-file): Protect against broken
+       .newsrc.el files.
+
+2012-04-05  Bastien Guerry  <bzg@altern.org>
+
+       * color.el (color-lighten-name): Fix typo.
+
+2012-03-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * auth-source.el (auth-source-netrc-create): Quote tokens that contain
+       "#" to avoid having them interpreted as comments.
+
+2012-03-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-insert): Update the text state properly to avoid
+       inserting spurious paragraph starts.
+
+2012-03-14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-table-widths): Divide the extra width more fairly over
+       the TDs (bug#10973).
+       (shr-render-td): Don't delete too much padding.
+       (shr-natural-width): Compute the natural width more correctly.
+       (shr-insert): Allow the natural width to be computed for tables again.
+       (shr-tag-table-1): Rework how the natural widths are computed by
+       rendering the table a third time.
+       (shr-natural-width): Removed.
+       (shr-buffer-width): New function.
+       (shr-expand-newlines): Use it.
+
+       * gnus-msg.el (gnus-bug): Don't delete the other windows.  We may be
+       using a `gnus-use-full-window' setup (bug#11013).
+
+2012-03-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-int.el (gnus-backend-trace): Flip default to nil before Emacs
+       24.1 release.
+
+2012-03-10  David Edmondson  <dme@dme.org>
+
+       * mm-uu.el (mm-uu-forward-extract): Allow for blank lines between the
+       'Forwarded Message' header and the start of the message.
+
+2012-03-04  Thierry Volpiatto  <thierry.volpiatto@gmail.com>
+
+       * gnus-msg.el (gnus-msg-mail): Call `message-mail' correctly when Gnus
+       isn't running (bug#10897).
+
+2012-03-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * tls.el (open-tls-stream): Don't set the dont-query-on-exit flag.
+       This is inconsistent with all the other stream functions, which leave
+       the setting up to the higher levels (if so wanted) (bug#10931).
+
+2012-02-28  Glenn Morris  <rgm@gnu.org>
+
+       * gmm-utils.el, gnus-agent.el, gnus-score.el, messagexmas.el,
+       mm-decode.el: Standardize possessive apostrophe usage.
+
+2012-02-25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-column-specs): Protect against TDs with "width: 0%".
+
+2012-02-25  Andreas Schwab  <schwab@linux-m68k.org>
+
+       * parse-time.el (parse-time-string): Allow extractor to return nil.
+
+2012-02-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nntp.el (nntp-send-authinfo): Work for secure nntp entry in authinfo.
+
+2012-02-20  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-clean-old-newsrc): Allow a FORCE parameter.
+
+2012-02-20  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-shr): Remove "soft hyphens".
+
+       * nnimap.el (nnimap-request-list): Return the group names encoded as
+       utf8.  Otherwise non-European group names don't work.
+       (nnimap-request-newgroups): Ditto.
+
+       * gnus-sum.el (gnus-summary-insert-old-articles): Fix the syntax for
+       the default in `read-string' (bug#10757).
+
+       * gnus-msg.el (gnus-group-post-news): Don't bug out on `C-u a' on
+       topics (bug#10843).
+
+       * nnimap.el (nnimap-log-command): Add the IMAP address to the log
+       buffer.  Suggested by Herbert Valerio Riedel.
+       (nnimap-request-move-article): Delete the message from the correct IMAP
+       server.
+
+2012-02-19  Gábor Vida  <vidagabor@gmail.com>  (tiny change)
+
+       * gnus-demon.el (gnus-demon-init): Don't multiply time twice.
+       Reported by Peter Münster.
+
+2012-02-18  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-image-fetched): Make sure we really kill the right
+       buffer.
+
+2012-02-16  Leo Liu  <sdl.web@gmail.com>
+
+       * gnus-start.el (gnus-1): Avoid duplicate entries.
+
+2012-02-15  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * imap.el: Remove.
+
+       * nntp.el (nntp-coding-system-for-read): Remove.
+       (nntp-coding-system-for-write): Ditto.
+       (nntp-open-connection): Just use `binary' directly.
+
+       * gnus-start.el (gnus-clean-old-newsrc): Delete `unexist' from pre-Ma
+       Gnus 0.3.
+
+2012-02-16  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-dissect-singlepart): Guess what the type of
+       application/octet-stream parts really is.
+
+       * gnus-sum.el (gnus-propagate-marks): Remove.
+
+2012-02-15  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * shr.el (shr-rescale-image): Undo previous change; see
+       <http://lists.gnu.org/archive/html/emacs-devel/2012-02/msg00540.html>.
+
+2012-02-15  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Ma Gnus v0.3 is released.
+
+2012-02-15  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-local-variables): Make
+       `gnus-newsgroup-unexist' into a local variable.
+
+2012-02-14  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * registry.el (registry-usage-test, registry-persistence-test): Move to
+       tests/gnustest-registry.el.
+       (registry-make-testable-db, registry-match-test)
+       (registry-instantiation-test): Move to tests/gnustest-registry.el.
+
+       * gnus-registry.el (gnus-registry-misc-test)
+       (gnus-registry-usage-test): Move to tests/gnustest-registry.el.
+
+       * tests/gnustest-registry.el: New file with the registry and
+       gnus-registry ERT tests.
+
+2012-02-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-summary-resend-message): Make
+       gnus-summary-resend-message-insert-gcc be last item in
+       message-header-setup-hook.
+
+2012-02-13  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnfolder.el (nnfolder-marks-directory, nnfolder-marks-is-evil)
+       (nnfolder-marks, nnfolder-marks-file-suffix, nnfolder-marks-modtime):
+       Remove.
+       (nnfolder-open-server): Don't use marks.
+       (nnfolder-request-delete-group): Ditto.
+       (nnfolder-request-rename-group): Ditto.
+       (nnfolder-request-set-mark, nnfolder-request-marks)
+       (nnfolder-group-marks-pathname, nnfolder-marks-changed-p)
+       (nnfolder-save-marks, nnfolder-open-marks): Remove.
+
+       * nnml.el (nnml-marks-is-evil, nnml-marks-file-name, nnml-marks)
+       (nnml-marks-modtime): Remove.
+       (nnml-request-delete-group): Don't use marks.
+       (nnml-request-rename-group): Ditto.
+       (nnml-request-set-mark, nnml-request-marks, nnml-marks-changed-p)
+       (nnml-save-marks, nnml-open-marks): Remove.
+
+       * nntp.el (nntp-marks-is-evil, nntp-marks-file-name, nntp-marks)
+       (nntp-marks-modtime, nntp-marks-directory, nntp-request-set-mark)
+       (nntp-request-marks, nntp-marks-directory, nntp-marks-changed-p)
+       (nntp-save-marks, nntp-open-marks, nntp-possibly-create-directory)
+       (nntp-server-to-method-cache): Remove.
+
+       * shr.el (shr-rescale-image): Fix wrong merge.
+
+2012-02-15  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-remove-trailing-whitespace): Really delete the padding on
+       too-wide lines.
+
+2012-02-13  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-record-commands): New variable.
+       (nnimap-log-command): Use it.
+       (nnimap-make-process-buffer): Add a space to the process buffer.
+       (nnimap-transform-headers): Don't bug out on header lines containing
+       stuff that look like IMAP length encodings.
+
+       * shr.el (shr-rescale-image): Allow viewing large images.
+
+2012-02-12  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnml.el (nnml-request-compact-group): Delete the marks file after
+       compaction (bug#10800).
+
+       * gnus-art.el (gnus-stop-downloads): Stop `url-queue' downloads on
+       group exit.
+
+       * nnimap.el (nnimap-parse-flags): Parse correctly when we have mixed
+       QRESYNC/FETCH output.
+
+2012-02-11  Glenn Morris  <rgm@gnu.org>
+
+       * sieve-manage.el (sieve-manage-default-stream):
+       * shr.el (shr):
+       * nnir.el (nnir-ignored-newsgroups, nnir-summary-line-format)
+       (nnir-retrieve-headers-override-function)
+       (nnir-imap-default-search-key, nnir-notmuch-program)
+       (nnir-notmuch-additional-switches, nnir-notmuch-remove-prefix)
+       (nnir-method-default-engines):
+       * message.el (message-cite-reply-position):
+       * gssapi.el (gssapi-program):
+       * gravatar.el (gravatar):
+       * gnus-sum.el (gnus-refer-thread-use-nnir):
+       * gnus-registry.el (gnus-registry-unfollowed-addresses)
+       (gnus-registry-max-pruned-entries):
+       * gnus-picon.el (gnus-picon-inhibit-top-level-domains):
+       * gnus-int.el (gnus-after-set-mark-hook)
+       (gnus-before-update-mark-hook):
+       * gnus-async.el (gnus-async-post-fetch-function):
+       * auth-source.el (auth-source-cache-expiry):
+       Add missing :version tags to new defcustoms and defgroups.
+
+2012-02-11  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-adjust-marked-articles): Add to
+       `gnus-newsgroup-unexist'.
+
+       * gnus.el (gnus-article-mark-lists): Add `unexist' to the list of
+       marks.
+       (gnus-article-special-mark-lists): Put the `unexist' in the special
+       marks list instead.
+
+       * gnus-sum.el (gnus-articles-to-read): Don't include unexisting
+       articles in the list of articles to be selected.
+
+       * nnimap.el (nnimap-retrieve-group-data-early): Query for unexisting
+       articles.
+       (nnimap-update-info): Keep track of unexisting articles.
+       (nnimap-update-qresync-info): Ditto.
+
+2012-02-10  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-default-send-mail-function): Made into own
+       function for reuse by emacsbug.el.
+
+2012-02-09  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus.el (gnus-method-ephemeral-p): Move after declaration of defsubst
+       `gnus-sloppily-equal-method-parameters' to avoid a warning.
+
+2012-02-09  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-archive.el (mm-archive-dissect-and-inline): New function.
+       (mm-archive-dissect-and-inline): Fix up the undisplayer.
+
+       * gnus-compat.el: Define `timer-set-function'.
+
+       * mm-decode.el (mm-display-external): Output the text from the command
+       in the buffer after the command finished.  This makes text-based
+       commands behave better.
+
+2012-02-08  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-compat.el: Add a compat for the old `url-retrieve'.
+
+2012-02-07  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-compat.el: Make `help-function-arglist' be compatible on Emacs
+       23.1.
+
+2012-02-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-show-thread): Revert last two changes.
+
+2012-02-07  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (smtpmail-smtp-user): Silence compiler warning.
+
+2012-02-06  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-multi-smtp-send-mail): Also allow specifying the
+       SMTP user name.
+
+2012-02-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-show-thread):
+       next-single-char-property-change may return nil in XEmacs.
+       (gnus-summary-article-map): Fix typo.
+
+2012-02-09  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-msg-mail): Use `message-mail' if Gnus isn't
+       running.
+
+       * nnimap.el (nnimap-wait-for-response): Minor fixup of message string.
+
+       * gnus.el (gnus-server-extend-method): Don't add an -address component
+       if the method already has one (bug#9676).
+
+2012-02-08  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-insert-old-articles): Use a default instead
+       of an initial-input for consistency (bug#10757).
+
+       * dgnushack.el: Fix XEmacs compilation warning.
+
+       * shr.el: Inhibit getting and sending cookies when fetching pictures.
+
+       * gnus-html.el (gnus-html-schedule-image-fetching): Ditto.
+
+2012-02-07  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-remove-trailing-whitespace): Don't strip whitespace from
+       lines that are narrower than the window width.  Otherwise background
+       "blocks" will look less readable.
+
+2012-02-07  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-transform-headers): Remove unused variable.
+       (nnimap-transform-headers): Fix parsing BODYSTRUCTURE elements that
+       have newlines within the strings, and where the UID comes after the
+       BODYSTRUCTURE element (bug#10537).
+
+       * shr-color.el (shr-color-set-minimum-interval): Rename to add prefix
+       (bug#10732).
+
+       * shr.el (shr-insert-document): Add doc string.
+       (shr-visit-file): Ditto.
+       (shr-remove-trailing-whitespace): New function.
+       (shr-insert-document): Use it to clean up trailing whitespace as the
+       final step (bug#10714).
+
+2012-02-06  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-exit-no-update): Really deaden the summary
+       buffer if `gnus-kill-summary-on-exit' is nil.
+
+2012-02-06  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-handle-ephemeral-exit): Allow exiting from Gnus
+       when just reading a single group from "without" Gnus.
+
+2012-02-06  Chong Yidong  <cyd@gnu.org>
+
+       * gnus-sum.el (gnus-summary-show-thread):
+       next-single-char-property-change never returns nil (Bug#8657).
+
+2012-02-02  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-multi-smtp-send-mail): New function.
+       (message-multi-smtp-send-mail): Respect the X-Message-SMTP-Method
+       header to implement multi-SMTP functionality.
+
+       * gnus-agent.el (gnus-agent-send-mail-function): Removed.
+       (gnus-agentize): Don't set it.
+       (gnus-agent-send-mail): Don't use it.
+
+       * gnus-sum.el (gnus-summary-widget-backward): New function and
+       keystroke.
+
+       * gnus-compat.el: More the compat functions more compatible.
+
+       * shr.el (shr-put-image): Remove underlines from sliced images.
+       (shr-zoom-image): Compute the region to be replaced more correctly.
+
+2012-02-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-gcc-self-resent-messages): New user option.
+       (gnus-summary-resend-message-insert-gcc): New function.
+       (gnus-summary-resend-message): Modify message-header-setup-hook and
+       message-sent-hook to make it work for Gcc.
+       (gnus-inews-do-gcc): Update the number of unread articles of groups
+       that messages are Gcc'd to.
+
+       * message.el (message-resend): Run message-sent-hook to do Gcc.
+
+2012-02-01  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * lpath.el: Fix an XEmacs compilation warning.
+
+       * gnus-compat.el: Require `help-fns' to fix compilation error.
+
+       * gnus-registry.el (gnus-registry-fixup-registry): Move the message to
+       a higher level to silence compilation.
+
+       * gnus-art.el (gnus-shr-put-image): Take and pass on a `flags'
+       parameter to allow controlling the scaling.
+
+       * shr.el (shr-zoom-image): New command and keystroke.
+       (shr-put-image): Take a `size' flag to say how to scale the image.
+
+       * gnus-compat.el: Redefine `delete-directory' to provide recursive
+       deletion unless already defined.
+
+       * gnus.el (gnus-compat): Require it.
+
+       * gnus-compat.el: New file.
+
+       * gnus-start.el (gnus-clean-old-newsrc): New function.
+       (gnus-read-newsrc-file): Use it.
+
+       * mm-archive.el (mm-dissect-archive): Use it to get all file names.
+       Use recursive deletion.
+       (mm-dissect-archive): Add support for zip files.
+
+       * gnus-util.el (gnus-recursive-directory-files): New function.
+
+       * mm-archive.el (mm-archive-list-files): Inline text and image parts.
+       (mm-archive-decoders): Add tgz support.
+
+       * mm-decode.el (mm-shr): Make sure that the HTML ends with a newline.
+       Otherwise inserting text into the Gnus buffer can look odd.
+
+       * gnus-art.el (gnus-mime-inline-part): Slight clean-up.
+
+       * mm-archive.el (mm-archive-decoders): Add support for tar.
+
+       * gnus.el (gnus-logo-color-alist): Change the colours for Ma Gnus.
+
+       * nnmail.el (nnmail-extra-headers): Add Cc to the default.
+
+2012-01-31  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-dissect-singlepart): Check that the decoder exists.
+
+       * mm-archive.el: New file.
+
+       * mm-decode.el (mm-dissect-singlepart): Use it to decode ms-tnef files.
+
+       * mm-util.el (mm-find-buffer-file-coding-system): Comment fix.
+
+       * message.el (message-goto-*): Make all the `message-goto-*' commands
+       push the mark before moving point.  This makes it easier to go back to
+       where you came from after editing whatever you jumped to.
+
+2012-01-31  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Ma Gnus v0.1 is released.
+
+2012-02-05  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-open-server): Allow switching the nnoo server
+       without reconnecting.
+       (nnimap-possibly-change-group): Ditto.
+       (nnimap-finish-retrieve-group-infos): Don't reconnect if the server
+       connection has died before being called.
+
+2012-02-02  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-retrieve-group-data-early): Don't say we're doing
+       an initial sync unless we're really doing one.
+
+       * gnus-group.el (gnus-group-read-ephemeral-group): Don't add a new
+       address parameter if one already exists (bug#9676).
+
+       * gnus-msg.el (gnus-summary-mail-forward): Respect the process marks,
+       not the prefix, as documented (bug#10689).
+
+2012-02-01  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-valid-select-methods): nnmaildir also saves marks in
+       the "server".
+
+       * gnus-group.el (gnus-group-get-new-news-this-group): Don't overwrite
+       the real error message with the useless "previously known to be down".
+       Which isn't even correct.
+
+       * nntp.el (nntp-open-connection): Report the error message if the nntp
+       server can't be reached.
+
+       * nnimap.el (nnimap-retrieve-group-data-early): Keep track of how many
+       groups we do a total scan for.
+       (nnimap-wait-for-response): Say that we're doing a total scan, if we're
+       doing that.
+
+2012-01-31  Jim Meyering  <jim@meyering.net>
+
+       * gnus-agent.el (gnus-agent-expire-unagentized-dirs):
+       Correct a comment (insert "not") and hide nominally-doubled "to".
+
+2012-01-31  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version): Change name to "Ma Gnus".
+
+2012-01-30  Philipp Haselwarter  <philipp.haselwarter@gmx.de>  (tiny change)
+
+       * gnus-agent.el (gnus-agent-auto-agentize-methods): Point to the Agent
+       section in the manual.
+
+2012-01-30  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * rfc2047.el (rfc2047-encode-region): Allow not folding the encoded
+       words.
+       (rfc2047-encode-string): Ditto.
+       (rfc2047-encode-parameter): Don't fold parameters.  Some MUAs do not
+       understand folded filename="..." parameters, for instance.
+
+       * nnimap.el (nnimap-wait-for-response): Include the imap server name in
+       the message for greater debuggability.
+
+2012-01-28  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-view.el (mm-display-inline-fontify): Bind `font-lock-support-mode'
+       instead of setting it locally, since the latter doesn't seem to have
+       any effect (most of the time).
+
+2012-01-27  Elias Pipping  <pipping@lavabit.com>  (tiny change)
+
+       * shr.el (shr-browse-url): Fix the name of the `browse-url-mail'
+       function call.
+
+2012-01-27  Gábor Vida  <vidagabor@gmail.com>  (tiny change)
+
+       * gnus-demon.el (gnus-demon-run-callback, gnus-demon-init): Convert to
+       seconds, and make the repeat clause with HH:MM specs work as
+       documented.
+
+2012-01-27  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * proto-stream.el (proto-stream-capability-open): Fall back on
+       :end-of-command if :end-of-capability doesn't exist.
+
+2012-01-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-mode): Don't make bidi-paragraph-direction
+       bound globally in old Emacsen and XEmacsen.
+
+2012-01-27  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-get-unread-articles): Clear out "early" methods
+       so that previous errors don't prohibit getting new news.
+
+       * nnimap.el (nnimap-retrieve-group-data-early): Ditto.
+
+       * nntp.el (nntp-retrieve-group-data-early): Ditto.
+
+2012-01-26  Nick Alcock  <nick.alcock@oracle.com>  (tiny change)
+
+       * gnus.el (gnus-group-find-parameter): Check for liveness of the
+       buffer, not of the string which is its name.
+
+2012-01-26  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * proto-stream.el (proto-stream-capability-open): Wait for
+       :end-of-capability, not :end-of-command.
+
+       * gnus-sum.el (gnus-summary-move-article): Don't propagate marks to
+       non-server-marks groups.
+       (gnus-group-make-articles-read): Ditto.
+
+       * gnus-srvr.el (gnus-server-prepare): Use it to avoid showing ephemeral
+       methods (bug#9676).
+
+       * gnus.el (gnus-method-ephemeral-p): New function.
+
+2012-01-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-mode): Force paragraph direction to be
+       left-to-right.
+
+2012-01-26  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnir-search-thread): Autoload to avoid a compilation
+       warning.
+
+2012-01-25  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-line-format-alist): Don't try to
+       macroexpand the nnir things, since they haven't been defined yet, and
+       nnir requires gnus-sum.
+
+2012-01-24  Julien Danjou  <julien@danjou.info>
+
+       * color.el (color-rgb-to-hsl): Fix value computing.
+       (color-hue-to-rgb): New function.
+       (color-hsl-to-rgb): New function.
+       (color-clamp, color-saturate-hsl, color-saturate-name)
+       (color-desaturate-hsl, color-desaturate-name, color-lighten-hsl)
+       (color-lighten-name, color-darken-hsl, color-darken-name): New function.
+
+2012-01-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-interactively-view-part): Fix prompt.
+
+2012-01-19  Julien Danjou  <julien@danjou.info>
+
+       * color.el (color-name-to-rgb): Use the white color to find the max
+       color component value and return correctly computed values.
+       (color-name-to-rgb): Add missing float conversion for max value.
+
+2012-01-10  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * nntp.el (nntp-send-authinfo): Query `auth-source-search' with the
+       logical server name in addition to the actual machine address.
+
+       * auth-source.el (auth-source-user-and-password): Add convenience
+       wrapper to search by just host and optionally user.
+
+2012-01-07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-visit-file): Move point to the beginning of the buffer
+       after rendering.
+
+2012-01-07  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-sync.el (gnus-sync-newsrc-groups): Quote normally.
+       (gnus-sync-lesync-pre-save-group-entry): Remove invalid invlists.
+       (gnus-sync-lesync-normalize-group-entry): Ignore a few more keys.
+
+2012-01-07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-read-group): Document more parameters
+       (bug#9693).
+       (gnus-summary-setup-buffer): Document return value (bug#9697).
+
+       * mm-decode.el (mm-interactively-view-part): Use `completing-read',
+       since ido doesn't work on symbols (bug#9632).
+
+       * gnus.el (gnus-group-fast-parameter): Use the same precedence rules
+       when getting a single value as when getting all the values.  This means
+       that atoms like `gcc-self' work cumulatively, like variable settings,
+       instead of getting the value from the last matching clause.
+       (gnus-group-find-parameter): Protect against the group buffer not
+       existing (bug#9585).
+
+2012-01-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-activate-group): Document more parameters
+       (bug#9694).
+
+       * gnus-group.el (gnus-group-read-ephemeral-group): Doc clarification
+       (bug#9692).
+
+       * gnus-agent.el (gnus-agent-store-article): Tell the Agent when the
+       article was fetched, so that it can be expired later (bug#9958).
+       (gnus-agent-summary-fetch-series): Add doc string.
+       (gnus-agent-summary-fetch-group): Don't remove tick and dormant marks
+       (bug#9517).
+
+       * nntp.el (nntp-retrieve-groups): Refuse to do retrieval when an async
+       retrieval is happening.
+
+       * gnus.el (gnus-parameters): Doc fix.
+
+2012-01-06  Dave Abrahams  <dave@boostpro.com>
+
+       * gnus-sum.el (gnus-summary-refer-thread): If the subtree is hidden,
+       show the thread after expansion.
+
+2012-01-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-narrow-to-head): If the head is completely
+       empty, narrow to the empty region (bug#9764).
+
+       * gnus-sum.el (gnus-summary-mark-article-as-unread): Mark articles as
+       read, and then mark them as unread only when the unread mark is used.
+       This makes `C-- T k' actually work, even though it's confusing.
+
+       * gnus-win.el (gnus-all-windows-visible-p): Ensure that the buffer is
+       alive before we try to find its window.
+
+2012-01-06  Brian Sniffen  <bsniffen@akamai.com>  (tiny change)
+
+       * mm-decode.el (mm-display-external): Use a longer timeout for the
+       deletion to allow slow programs to display the file.
+
+2012-01-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-browse-delete-temp-files): Fix up the
+       prompt to be less confusing.
+
+       * gnus-msg.el (gnus-summary-reply): Do not give a `switch-to-buffer'
+       argument to `message-reply'.  This broke `special-display-*' frame
+       pop-uping (bug#10238).
+
+2012-01-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * starttls.el (starttls-available-p): Return nil on Windows/MS-DOS
+       systems, since these allegedly don't work there.
+
+2012-01-04  Chris Gray  <chrismgray@gmail.com>  (tiny change)
+
+       * mm-decode.el (mm-shr): Check that `gnus-summary-buffer' really is a
+       live buffer.
+
+2012-01-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnir.el (nnir-retrieve-headers): Protect against the article not
+       existing on the server (bug#10335).
+
+2012-01-04  Wolfgang Jenkner  <wjenkner@inode.at>  (tiny change)
+
+       * gnus-agent.el (gnus-agent-load-local): Recompute
+       gnus-agent-article-local on changing method.
+
+2012-01-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-parameters): Note precedence.
+
+2012-01-04  Leo Liu  <sdl.web@gmail.com>
+
+       * nndraft.el (nndraft-update-unread-articles): Don't move point around
+       in the group buffer.
+
+2012-01-04  Julien Danjou  <julien@danjou.info>
+
+       * nnimap.el (nnimap-update-info): Fix an error when all articles UIDs
+       change.
+
+2012-01-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-rescale-image): Add :ascent 100 to the rescaled picture,
+       too.
+
+       * nntp.el (nntp-retrieve-group-data-early): Use it.
+
+2012-01-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nntp.el (nntp-retrieval-in-progress): New variable.
+       (nntp-make-process-buffer): Make it buffer-local.
+
+       * gnus-demon.el (gnus-demon-time-to-step): Resurrect function lost in
+       2010.
+       (gnus-demon-init): Use it to compute the time if time is on the form
+       "04:23".
+
+       * gnus-topic.el (gnus-topic-history): Define `gnus-topic-history'.
+
+       * nnimap.el (nnimap-finish-retrieve-group-infos): Check the connection
+       status in the correct buffer.
+
+2012-01-03  Leo Liu  <sdl.web@gmail.com>
+
+       * gnus-topic.el (gnus-topic-goto-next-group): Don't move point around
+       when opening topics (bug#10407).
+
+2011-12-30  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-cus.el (gnus-score-customize):
+       * gnus-sum.el (gnus-sort-gathered-threads):
+       * message.el (message-shorten-references):
+       * nnmairix.el (nnmairix-request-group):
+       * uudecode.el (uudecode-decode-region-internal): Spelling fix.
+
+2011-12-29  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-agent.el (gnus-agent-regenerate-group):
+       * gnus-int.el (gnus-retrieve-group-data-early):
+       * mm-util.el (mm-codepage-ibm-list):
+       * nndiary.el (Commentary, nndiary-get-new-mail):
+       * nnir.el (nnir):
+       * pgg-parse.el (pgg-parse-symmetric-key-algorithm-alist): Spelling fix.
+
+2011-12-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-view.el (mm-display-inline-fontify): Add comment.
+
+2011-12-21  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * nndiary.el (nndiary-parse-schedule-value, nndiary-parse-schedule):
+       * ntlm.el (ntlm-smb-dohash): Spelling fix.
+
+2011-12-19  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-art.el (gnus-split-methods):
+       * gnus-msg.el (gnus-configure-posting-styles):
+       * gnus-spec.el (gnus-parse-simple-format):
+       * gnus-win.el (gnus-configure-frame, gnus-all-windows-visible-p):
+       * message.el (message-do-actions): Spelling fix.
+
+2011-12-15  Juri Linkov  <juri@jurta.org>
+
+       * mm-decode.el (mm-inline-media-tests): Add missing
+       `mm-handle-media-subtype'.
+
+2011-12-14  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-group.el (gnus-group-tool-bar):
+       * gnus-sum.el (gnus-summary-tool-bar):
+       * message.el (message-tool-bar):
+       * rfc2231.el (rfc2231-parse-string): Spelling fix.
+
+2011-12-12  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * plstore.el (plstore--insert-buffer): Spelling fix.
+
+2011-12-09  Tassilo Horn  <tassilo@member.fsf.org>
+
+       * message.el (message-valid-fqdn-regexp): Update with newly approved
+       top-level domain names ".tel" and ".asia".
+
+2011-12-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-show-article): Don't load shr
+       unconditionally.
+
+2011-12-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-pop-to-buffer): Use pop-to-buffer instead of
+       pop-to-buffer-same-window for old Emacsen.
+
+2011-12-06  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus-sum.el (gnus-summary-make-tool-bar): Fix typo.
+
+2011-12-05  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * netrc.el (netrc-credentials): Spelling fix.
+
+2011-12-04  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-fun.el (gnus-fun-ppm-change-string):
+       * gnus-msg.el (gnus-inews-do-gcc):
+       * gnus-sum.el (gnus-summary-find-for-reselect):
+       * gnus.el (gnus-summary-cancelled):
+       * message.el (message-cancel-hook, message-send-news):
+       * nndiary.el (nndiary-headers, nndiary-parse-schedule-value):
+       * nnir.el (nnir-run-hyrex):
+       * nntp.el (nntp-with-open-group-function):
+       * pgg.el (pgg-pending-timers): Spelling fix.
+
+2011-12-04  Chong Yidong  <cyd@gnu.org>
+
+       * message.el (message-pop-to-buffer): Partially revert 2011-11-30
+       change (Bug#10200).
+
+2011-12-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * compface.el (uncompface):
+       * gnus-art.el (gnus-article-x-face-command): Update the header format
+       of icon data for the most recent icontopbm program.
+
+2011-12-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-inews-do-gcc):
+       * message.el (message-send-mail):
+       * mml.el (mml-generate-mime): Share the value of the buffer-local
+       `message-options' variable between a draft buffer and temprary working
+       buffers.
+
+2011-11-30  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * message.el (message-pop-to-buffer): Revert 2011-09-11 change.
+
+2011-11-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-browse-html-parts): Convert link file names
+       for Cygwin.
+
+2011-11-27  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-group.el (gnus-group-prepare-flat):
+       * mm-bodies.el (mm-encode-body):
+       * mml.el (mml-preview):
+       * nnml.el (nnml-request-compact-group):
+       * pop3.el (pop3-stream-type): Spelling fix.
+
+2011-11-26  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-start.el (gnus-newsrc-to-gnus-format): Spelling fix.
+
+2011-11-25  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * color.el (color-rgb-to-hsl):
+       * gmm-utils.el (gmm-tool-bar-style):
+       * gnus-group.el (gnus-group-prepare-flat):
+       * gnus-topic.el (gnus-topic-prepare-topic):
+       * mm-decode.el (mm-discouraged-alternatives):
+       * rfc2047.el (rfc2047-encode-1):
+       * starttls.el: Spelling fix.
+
+2011-11-24  Glenn Morris  <rgm@gnu.org>
+
+       * binhex.el (binhex-begin-line): Give it basic doc-string.
+
+       * starttls.el, tls.el: Fix case of "GnuTLS".
+
+2011-11-24  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus-group.el (gnus-group-highlight): Fix typo.
+
+2011-11-24  Adam W  <adam_w67@yahoo.com>  (tiny change)
+
+       * mail-source.el (mail-source-fetch-maildir): Don't expect the return
+       value of `delete-file', that returns nil for a local file but returns t
+       for a remote file using ssh.
+
+2011-11-22  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-sum.el (gnus-summary-save-article): Spelling fix.
+
+2011-11-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-table-horizontal-line): Use "?\s" instead of "? " to
+       avoid later breakage.
+
+2011-11-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-setup-buffer): Decode group name used for
+       article buffers' name.
+
+2011-11-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-table-horizontal-line): Revert infinite loops introduced
+       by Paul Eggert's spellfixes two days ago.
+
+2011-11-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * dgnushack.el (fboundp): Define `with-demoted-errors' for Emacsen that
+       doesn't have it.
+
+       * mm-view.el (mm-display-inline-fontify): Make the font-lock variables
+       buffer-local instead of binding them to avoid warnings.  Also demote
+       errors (bug#10063).
+       (font-lock-mode-hook): Shut up byte compiler.
+
+2011-11-20  Juanma Barranquero  <lekktu@gmail.com>
+
+       * mm-util.el (mm-charset-after):
+       * nnir.el (nnir-run-hyrex):
+       * ntlm.el (ntlm-build-auth-request, ntlm-build-auth-response)
+       (ntlm-get-password-hashes, ntlm-md4hash):
+       * smime.el: Fix typo.
+
+2011-11-20  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-agent.el (gnus-agent-expire-group-1):
+       * nndiary.el (nndiary-last-occurence):
+       * nnimap.el (nnimap-request-set-mark):
+       * nnmairix.el (nnmairix-only-use-registry):
+       * gnus-group.el (gnus-group-prepare-flat):
+       * gnus-sum.el (gnus-decode-encoded-word-methods):
+       * message.el (message-wash-subject):
+       * nntp.el (nntp-retrieve-headers-with-xover):
+       * smime.el (smime-certificate-directory): Spelling fix.
+
+2011-11-19  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * nnmail.el (nnmail-get-new-mail-1): Remove unused local variables.
+
+       * color.el:
+       * gnus-agent.el (gnus-agent-possibly-alter-active):
+       * gnus-dired.el (gnus-dired-print):
+       * mail-parse.el:
+       * nnmairix.el (nnmairix-request-group):
+       * shr.el (shr-image-displayer):
+       * sieve-manage.el:
+       * spam.el (spam-autodetect-recheck-messages): Spelling fix.
+
+2011-11-18  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-sum.el (gnus-auto-select-subject):
+       * spam-report.el (spam-report-resend): Spelling fix.
+
+2011-11-17  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-agent.el (gnus-agent-get-undownloaded-list):
+       * gnus-art.el (gnus-default-article-saver):
+       * gnus-srvr.el (gnus-server-copy-server):
+       * gnus.el (gnus-sloppily-equal-method-parameters):
+       * html2text.el (html2text-format-tag-list):
+       * message.el (message-narrow-to-head):
+       * nndiary.el:
+       * nnmairix.el (nnmairix-determine-original-group-from-registry):
+       * sieve.el: Spelling fix.
+
+2011-11-16  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus-agent.el (gnus-agent-expire-unagentized-dirs):
+       * gnus-sum.el (gnus-summary-make-menu-bar):
+       * gnus-uu.el (gnus-uu-decode-postscript)
+       (gnus-uu-decode-postscript-and-save):
+       * mailcap.el (mailcap-print-command):
+       * registry.el (registry-lookup, registry-lookup-breaks-before-lexbind):
+       Fix typos.
+
+2011-11-15  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus-art.el (gnus-article-part-wrapper):
+       * html2text.el (html2text-fix-paragraphs):
+       * mm-decode.el (mm-image-fit-p):
+       * rfc2047.el (rfc2047-encode-message-header):
+       * shr-color.el (shr-color-visible-distance-min)
+       (shr-color-relative-to-absolute, set-minimum-interval)
+       (shr-color-visible): Fix typos.
+
+2011-11-15  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gmm-utils.el (gmm-tool-bar-item):
+       * gnus-art.el (gnus-treat-body-boundary):
+       * gnus-diary.el (gnus-user-format-function-d):
+       * gnus-start.el (gnus-get-unread-articles):
+       * pgg-gpg.el (pgg-gpg-update-agent):
+       * smime.el (smime-cert-by-ldap-1): Spelling fix.
+
+2011-11-14  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-topic.el (gnus-group-prepare-topics):
+       * gnus-uu.el (gnus-extract-view):
+       * gnus-win.el (gnus-use-frames-on-any-display): Spelling fix.
+
+2011-11-09  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el: Move BBDB autoloads.
+       (spam-exists-in-BBDB-p): New function to do the BBDB search directly in
+       BBDB 2 and 3.
+       (spam-check-BBDB): Use it.
+       (spam-enter-ham-BBDB): Use it.
+
+2011-11-09  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * smime.el (smime-draw-buffer): Spelling fix.
+
+2011-10-31  Peter Münster  <pmrb@free.fr>  (tiny change)
+
+       * gnus-group.el (gnus-group-get-new-news): New parameter `one-level'
+       for scanning exactly one level.
+       * gnus-start.el (gnus-get-unread-articles): Ditto.
+
+2011-11-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-articles-to-read): Change wording in prompt to be
+       slightly clearer.
+
+2011-11-03  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-sync.el: More commentary about setup.
+
+2011-11-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-send-and-exit): Document `arg'.
+
+2011-11-03  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * nnimap.el (nnimap-open-connection-1): Use tcp-keealive if possible.
+
+2011-11-02  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-sync.el: More commentary about `gnus-sync-read' issues.
+
+       * gnus-util.el (gnus-bound-and-true-p): Another comment to explain why
+       we don't use `bound-and-true-p'.
+
+2011-11-01  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-util.el (gnus-bound-and-true-p): Remove.
+       (gnus-bound-and-true-dumber-p): Rename to `gnus-bound-and-true-p'.
+       * nnir.el: Use it.
+       * nnmairix.el: Use it.
+
+2011-10-31  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-sync.el: Improve docs about CouchDB admins.
+
+       * gnus-util.el (gnus-bound-and-true-dumber-p): Define new, slower, dumb
+       function because `gnus-bound-and-true-p' doesn't work well in XEmacs
+       for reasons unknown.
+       * nnir.el: Use it.
+       * nnmairix.el: Use it.
+
+       * nnregistry.el: Remove unnecessary `gnus-registry-enabled' defvar.
+       * nnir.el: Ditto.
+       * nnmairix.el: Ditto.
+
+       * gnus-registry.el (gnus-registry-enabled): Default to nil.
+
+2011-10-29  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-sync.el (gnus-sync-lesync-setup): Fix salt when user setup is
+       not needed.  Provide xmlplistread list function to produce XML plist
+       output for non-Gnus LeSync clients.
+
+2011-10-27  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-fallback-lib/json.el: Add for XEmacs and Emacs 22 support.
+
+       * gnus-sync.el: Add LeSync synchronization backend and logic to read
+       and save against it.  Group subscriptions, read marks, other marks,
+       subscription levels, topic names, and topic offsets (the group's
+       position within the topic) are saved.  This is an experimental backend
+       and may change significantly.  Load json.el from the gnus-fallback-lib
+       if it's not available otherwise.
+       (gnus-sync-save): Don't use `apply-partially' because of XEmacs.
+
+2011-10-26  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * message.el (message-completion-function): Make sure
+       message-tab-body-function is not attempted if one of
+       message-completion-alist fails to find a completion (bug#9158).
+
+2011-10-26  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml.el (mml-quote-region): Quote <#secure> tag.
+       (mml-generate-mime-1): Unquote <#secure> tag.
+
+2011-10-20  Chong Yidong  <cyd@gnu.org>
+
+       * gnus-cite.el (gnus-message-citation-mode): Doc fix (in Emacs 24,
+       calling a minor mode from Lisp with nil arg enables it, so we have to
+       make the wording a bit ambiguous here).
+
+2011-10-18  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-util.el (gnus-bound-and-true-p): Macro for XEmacs compatibility.
+       * nnir.el (nnir-mode): Use it.
+       * nnmairix.el (nnmairix-determine-original-group-from-registry):
+       Use it.
+
+       * nnir.el (gnus-registry-enabled): Defvar to keep the compiler happy.
+       * nnmairix.el (gnus-registry-enabled): Ditto.
+
+2011-10-17  Dave Abrahams  <dave@boostpro.com>
+
+       * gnus-registry.el (gnus-registry-enabled): Add new variable (Bug#9691).
+       (gnus-registry-install-shortcuts): Set `gnus-registry-install' to 'ask
+       only while we need to find out if it should be t or nil.
+       (gnus-registry-initialize): Don't set `gnus-registry-install' to t.
+       (gnus-registry-install-hooks): Set `gnus-registry-enabled' to t when
+       the registry is installed.  Set it to nil when it's unloaded.
+       (gnus-registry-install-p): Provide user guidance for the initial value
+       of `gnus-registry-install' when it's 'ask, otherwise return its value.
+       * nnregistry.el (nnregistry-open-server, nnregistry-server-opened):
+       Use `gnus-registry-enabled' instead of `gnus-registry-install'.
+       * nnmairix.el (nnmairix-determine-original-group-from-registry):
+       Use `gnus-registry-enabled' instead of `gnus-registry-install'.
+       * nnir.el (nnir-mode): Use `gnus-registry-enabled' instead of
+       `gnus-registry-install'.
+
+2011-10-17  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el (mml2015-epg-find-usable-key): Add comment about the
+       previous change.
+       * mml1991.el (mml1991-epg-find-usable-key): Skip the whole key if the
+       primary key is marked as disabled.
+
+2011-10-17  Christian von Roques  <roques@mti.ag>  (tiny change)
+
+       * mml2015.el (mml2015-epg-find-usable-key): Skip the whole key if the
+       primary key is marked as disabled.
+
+2011-10-11  Andreas Schwab  <schwab@linux-m68k.org>
+
+       * html2text.el (html2text-clean-anchor): Check for quotes around
+       `href' value.
+
+2011-10-11  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-check-BBDB): Simplify and support BBDB 3.x when
+       searching.  Drop `bbdb-cache'.
+
+2011-10-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-signed-or-encrypted-p): Exclude header when
+       checking if there is signed or encrypted body in text/plain message.
+
+2011-10-09  Andreas Schwab  <schwab@linux-m68k.org>
+
+       * html2text.el (html2text-get-attr): Correctly handle attribute values
+       containing "=".
+
+2011-09-22  Kan-Ru Chen  <kanru@kanru.info>
+
+       * ecomplete.el (ecomplete-display-matches): Use a local keymap to
+       handle bindings.
+
+2011-10-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-win.el (gnus-configure-windows): Protect against reading
+       ephemeral groups outside of Gnus.
+
+2011-10-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el (shr-tag-img): Don't get images displayed in tables.
+
+2011-10-03  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-group.el (gnus-bug-group-download-format-alist): Once again get
+       the "maintainer" version of debbugs.gnu.org reports.
+
+2011-10-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-tag-img): Add a space at the end of an ALT image text to
+       make asynchronous adjacent image insertion work better.
+
+2011-09-27  Daiki Ueno  <ueno@unixuser.org>
+
+       * plstore.el (plstore-select-keys, plstore-encrypt-to): Clarify
+       documentation.
+
+2011-09-27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-uu.el (gnus-uu-grab-articles): Require gnus-async so that
+       `gnus-asynchronous' isn't shadowed.
+
+2011-09-26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-xmas.el (gnus-xmas-define): Add `member-ignore-case'.
+
+       * nnimap.el (nnimap-wait-for-response): Message less (bug#9540).
+       (nnimap-insert-partial-structure): The charset parameter isn't
+       case-sensitive.
+
+       * nnheader.el (nnheader-message-maybe): New function.
+
+       * shr.el (shr-tag-table): Render totally broken tables better.
+
+       * mml.el (mml-generate-mime-1): Don't alter the contents if we're
+       computing the boundary.
+
+2011-09-26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * pop3.el (pop3-number-of-responses): Remove.
+       (pop3-wait-for-messages): Rewrite to take linear time instead of
+       exponential time.
+
+2011-09-24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-show-article): Bind `shr-ignore-cache' to
+       re-fetch images.
+
+       * shr.el (shr-tag-img): Support a new variable `shr-ignore-cache' to
+       re-fetch images when hitting `g' in Gnus.
+
+2011-09-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml.el (mml-inhibit-compute-boundary): New internal variable.
+       (mml-compute-boundary): Don't check collision if it is non-nil.
+       (mml-compute-boundary-1): Use mml-generate-mime-1 to encode part
+       before checking collision.
+
+2011-09-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-indent-citation): Really make sure there's a
+       newline at the end.
+
+       * nnimap.el (nnimap-parse-flags): Make regexp less prone to overflows.
+       Fix suggested by John Wiegley.
+
+       * pop3.el (pop3-open-server): Fix +OK end-of-command regexp.
+
+       * gnus-art.el (gnus-treat-hide-citation): Add doc.
+
+       * message.el (message-default-send-rename-function): Break out into its
+       own function.
+
+       * ecomplete.el (ecomplete-display-matches): Revert patch since it
+       doesn't work under XEmacs.
+
+       * nnimap.el (nnimap-map-port): New function to connect to 993 instead
+       of "imaps" to word around Windows problems.
+       (nnimap-open-connection-1): Use it.
+
+       * message.el (message-indent-citation): Revert last change which made
+       `F' not work.
+
+2011-09-13  Kan-Ru Chen  <kanru@kanru.info>
+
+       * ecomplete.el (ecomplete-display-matches): Intercept key sequence from
+       terminal as well.
+
+2011-09-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-view.el (mm-display-inline-fontify): Don't run doc-view-mode
+       because it displays images using overlays that aren't easy to copy to
+       the article buffer.
+
+2011-09-20  Łukasz Stelmach  <lukasz.stelmach@iem.pw.edu.pl>  (tiny change)
+
+       * message.el (message-indent-citation): Fix empty line removal at the
+       end of the citation.
+
+2011-09-20  Julien Danjou  <julien@danjou.info>
+
+       * auth-source.el (auth-source-netrc-create): Use default value for
+       password if specified.  Evaluate default.
+       (auth-source-plstore-create): Ditto.
+       (auth-source-plstore-create, auth-source-netrc-create): Fix default
+       value evaluation.
+       (auth-source-netrc-create): Typo fix.
+       (auth-source-plstore-create): Ditto.
+
+       * password-cache.el (password-cache-remove): Remove entries even if the
+       value is nil, so that password with a nil value (negative caching) is
+       possible to invalidate.
+
+       * auth-source.el (auth-source-format-cache-entry): New function.
+
+2011-09-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-fun.el (gnus-convert-image-to-x-face-command): Doc fix.
+
+2011-09-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-inline-media-tests): Fix typo in regexp.
+
+2011-09-19  Julien Danjou  <julien@danjou.info>
+
+       * auth-source.el (auth-source-netrc-parse): Use an obfuscation method
+       which work with things that are not ASCII.
+
+2011-09-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-inline-media-tests): Support imagemagick images.
+
+2011-09-15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-read-group-1): Bump the "Retrieving"
+       message level.
+
+2011-09-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-read-from-minibuffer): Make abbrev expansion work.
+
+2011-09-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-interactive-exit): Update defcustom spec.
+
+2011-09-12  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus.el (gnus-nntp-server): Move to gnus-int.el to silence bytecomp.
+       * gnus-int.el (gnus-nntp-server): Move from gnus.el.
+
+2011-09-12  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * gnus-group.el (gnus-group-list-limit-map, gnus-group-list-flush-map)
+       (gnus-group-list-plus-map): Allow limiting, flushing and plusing ticked
+       articles.
+
+2011-09-11  Chong Yidong  <cyd@stupidchicken.com>
+
+       * message.el (message-pop-to-buffer): Default to switch-to-buffer.
+       (message-mail-other-window, message-mail-other-frame)
+       (message-news-other-window, message-news-other-frame):
+       Use switch-to-buffer-other-frame and switch-to-buffer-other-window
+       instead of setting buffer display varibles.
+
+2011-09-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-list-limit): Explain what the command does.
+
+       * gnus-sum.el (gnus-fetch-headers): Bump message level.
+
+2011-09-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-dup.el (gnus-dup-suppress-articles): Move "Suppressing
+       duplicates" to a higher level.
+
+       * gnus-util.el (gnus-verbose): Lower default to 6 to get rid of the
+       most egregious messages.
+
+2011-09-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-summary-mail-forward): Minuscule doc fix.
+
+2011-09-10  Tetsuo Tsukamoto  <tt.tetsuo.tsukamoto@gmail.com>  (tiny change)
+
+       * nnrss.el (nnrss-retrieve-groups): Decode the charset before looking
+       up the file (bug#9351).
+
+2011-09-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el: Redo the charset handling.  Let Gnus encode the names, as
+       it does with all other backends, but decode the names immediately after
+       getting them.
+
+       * gnus-group.el (gnus-group-name-charset): Always return `utf-7' when
+       decoding nnimap groups.
+
+       * gnus.el (gnus-variable-list): Don't save `gnus-format-specs' in the
+       newsrc file.  It doesn't seem like an important optimization any more.
+
+2011-09-10  Dave Abrahams  <dave@boostpro.com>
+
+       * nnimap.el (nnimap-transform-headers): Fix regexp to be less prone to
+       overflows.
+
+2011-09-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-article-mark-lists): Remove `recent'.
+       (gnus-interactive-exit): Extend to `quiet'.
+
+       * gnus-sum.el (gnus-offer-save-summaries): Use it.
+
+       * gnus-art.el (gnus-treat-hide-citation-maybe): Add more doc to the
+       string.
+
+       * plstore.el (plstore--get-buffer): Silence compiler warnings by
+       renaming function arguments from `this'.
+
+       * gnus-sum.el (gnus-newsgroup-recent): Remove.
+
+       * gnus-spec.el (gnus-lrm-string-p): `bidi-string-mark-left-to-right'
+       has been renamed.
+       (gnus-lrm-string-p): Include RLM and PDF, too.
+
+       * gnus-int.el (gnus-open-server): Make the "denied" message clearer
+       (bug#9225).
+
+2011-09-10  Eli Zaretskii  <eliz@gnu.org>
+
+       Add autoload cookies for functions used by sendmail.el.
+       * mm-encode.el (mm-default-file-encoding): Add autoload cookie.
+
+       * mml.el (mml-to-mime, mml-attach-file): Add autoload cookies.
+
+2011-09-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-date-ut): Work properly even when there are
+       things like Date header in the body; work for forwarded parts.
+
+2011-09-05  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * gnus-sum.el (gnus-summary-exit): Ensure we kill the proper
+       original-article-buffer.
+
+2011-09-05  Kan-Ru Chen  <kanru@kanru.info>
+
+       * nnir.el (nnir-compose-result): Fix matching of server type.
+       (nnir-run-swish++): Ditto.
+       (nnir-run-namazu): Ditto.
+       (nnir-run-notmuch): Ditto.
+
+2011-09-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-home-directory): Add warning about setting in .gnus.el
+       (bug#9405).
+
+       * gnus-score.el (gnus-summary-increase-score): Doc clarification
+       (bug#9421).
+
+       * gnus-spec.el (gnus-face-0): Make all the face specs into defcustoms
+       (bug#9425).
+
+       * gnus-art.el (gnus-treatment-function-alist): Remove CRs as the first
+       thing (bug#9426).
+
+2011-09-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-open-connection-1): Use the correct port number in
+       the error message.
+
+2011-09-02  Eli Zaretskii  <eliz@gnu.org>
+
+       * message.el (message-setup-1): Return t (Bug#9392).
+
+2011-09-01  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * gnus-sum.el: When adding article headers to a summary buffer also
+       update gnus-newsgroup-articles (bug#9386).
+
+2011-08-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * auth-source.el: Autoload help-mode.
+
+2011-08-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-name-charset): Don't bug out on server
+       names.
+
+2011-08-27  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml-smime.el (mml-smime-epg-verify): Don't use the 4th arg of
+       mm-replace-in-string for compatibility issues.
+       * mml2015.el (mml2015-epg-verify): Ditto.
+
+2011-08-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mailcap.el (mailcap-mime-data): Regexp-quote MIME subtype.
+
+       * gnus-msg.el (gnus-setup-message): Remove extra apostrophe.
+
+2011-08-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnmail.el (nnmail-get-new-mail-1): If one mail source bugs out,
+       continue on and do the clean-up phase (bug#9188).
+
+       * gnus-sum.el (gnus-summary-expire-articles): When expiring articles,
+       just ignore groups that can't be opened instead of erroring out
+       (bug#9225).
+
+       * gnus-art.el (gnus-article-update-date-headers): Flip the default to
+       nil since some many people are fuddy-duddies.
+
+       * gnus-html.el (gnus-html-image-fetched): Don't cache zero-length
+       images.
+
+       * nntp.el (nntp-authinfo-file): Mark as obsolete -- use auth-source
+       instead.
+
+       * pop3.el (pop3-wait-for-messages): Don't use Gnus functions here.
+
+       * gnus-util.el (gnus-process-live-p): Copy over compat function.
+
+       * pop3.el (pop3-wait-for-messages): If the pop3 process dies, stop
+       processing.
+
+       * nntp.el (nntp-kill-buffer): Kill the process before killing the
+       buffer to avoid warnings.
+
+2011-08-20  Simon Josefsson  <simon@josefsson.org>
+
+       * gnus-agent.el (gnus-agent-expire-done-message): Use %.f as format
+       specified to reduce precision.
+
+2011-08-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-transform-headers): Protect against (NIL ...)
+       bodystructures (bug#9314).
+
+2011-08-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-insert-mime-button, gnus-mime-display-alternative):
+       Make button keymap non-sticky after buttons.
+
+2011-08-18  David Engster  <dengste@eml.cc>
+
+       * nnmairix.el (nnmairix-request-set-mark)
+       (nnmairix-goto-original-article): Remove adding of article to registry,
+       since `gnus-registry-add-group' isn't available anymore.
+       (nnmairix-determine-original-group-from-registry):
+       Use `gnus-registry-get-id-key' since `gnus-registry-fetch-groups' isn't
+       available anymore.
+
+2011-08-12  Simon Josefsson  <simon@josefsson.org>
+
+       * starttls.el (starttls-any-program-available): Define as obsolete
+       function.
+
+2011-08-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-util.el (gnus-y-or-n-p): Reinstate the message-clearing y-or-n-p
+       versions which Gnus use when appropriate.
+
+       * gnus-group.el (gnus-group-clear-data): Add a y-or-n query, since it's
+       a pretty destructive command.
+
+       * nnmail.el (nnmail-extra-headers): Clarify slightly (bug#9302).
+
+2011-08-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-fix-before-sending): Make a different warning
+       about NUL characters (bug#9270).
+
+       * gnus-sum.el (gnus-auto-select-subject): Allow specifying a function
+       from custom (bug#9260).
+
+       * gnus-spec.el (gnus-lrm-string): Use 8206 instead of ?\x200e to make
+       things work in Emacs 22 and XEmacs, too.
+
+       * gnus-sum.el (gnus-summary-from-or-to-or-newsgroups): LRM-ify the
+       default From.
+
+       * gnus-spec.el (gnus-lrm-string-p): New macro.
+       (gnus-lrm-string): New constant.
+       (gnus-summary-line-format-spec): LRM-ify the from.
+       (gnus-tilde-max-form): LRM-ify string chopping.
+
+       * gnus-ems.el (gnus-string-mark-left-to-right): New function.
+
+       * message.el (message-is-yours-p): Allow disabling canlock checking
+       (bug#9295).
+       (message-shoot-gnksa-feet): Add `canlock-verify'.
+       (message-auto-save-directory): Use ~/ as the auto-save directory if the
+       message directory isn't writable (bug#9304).
+
+       * auth-source.el (auth-source-netrc-saver): Make the .authinfo file
+       non-world-readable.
+
+2011-08-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nndraft.el (nndraft-update-unread-articles): Don't send delayed
+       articles.
+
+2011-08-13  Andreas Schwab  <schwab@linux-m68k.org>
+
+       * gnus-score.el (gnus-all-score-files): Use copy-sequence instead of
+       copy-list.
+
+2011-08-12  Sam Steingold  <sds@gnu.org>
+
+       * gnus-score.el (gnus-score-find-alist): Keep the score files already
+       in the reverse order to avoid modifying the cache with `nreverse'.
+       (gnus-all-score-files): Do not modify the value returned by
+       `gnus-score-find-alist' because it lives in a cache variable.
+       (gnus-current-home-score-file): No need to `nreverse' the return value
+       of `gnus-score-find-alist', it is already in the correct order.
+
+2011-08-11  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnimap.el (nnimap-transform-headers): BODYSTRUCTURE for messages of
+       type MESSAGE and subtype RFC822 is slightly different from those of
+       type TEXT.
+
+2011-08-05  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * gnus-sum.el (gnus-summary-refer-article): Warp to article.
+       This allows article-referral to work from an nnir group.
+
+2011-08-04  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * gnus.el (registry-ignore): Add nnir groups to the ignore-list.
+
+2011-08-04  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml1991.el (mml1991-epg-find-usable-key)
+       (mml1991-epg-find-usable-secret-key): New function.
+       (mml1991-epg-sign): Check if signing key is usable.
+       (mml1991-epg-encrypt): Check if encrypting key is usable (bug#8955).
+
+2011-08-03  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-read-server-parm): Add an argument to restrict to
+       server-variables only.  This should fix a bug introduced with commit
+       e1889675b7f4adf057833c5513c9374134c4e053.
+       (nnir-run-query): 'nnir-search-engine should not be set from the global
+       environment.
+
+2011-08-02  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-search-thread): Position point on referring article
+       line.
+       (nnir-warp-to-article): Clean up summary buffers.
+
+       * nnimap.el (nnimap-request-thread): Whitespace fix.
+
+2011-08-02  Steve Purcell  <steve@sanityinc.com>  (tiny change)
+
+       * nnimap.el (nnimap-get-groups): Decode "&" correctly.
+
+2011-08-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * starttls.el (starttls-available-p): Rename from
+       `starttls-any-program-available' and changed return convention.
+
+2011-07-31  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnmaildir.el (nnmaildir-request-accept-article): Don't call
+       `unix-sync' unless it's defined.
+
+2011-07-31  Marcus Harnisch  <marcus.harnisch@gmx.net>  (tiny change)
+
+       * gnus-art.el (gnus-article-stop-animations): Use `elt' instead of
+       `aref' for XEmacs compatibiltiy.
+
+2011-07-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * spam.el (spam-fetch-field-fast): Rewrite slightly for clarity.
+
+2011-07-31  Dave Abrahams  <dave@boostpro.com>
+
+       * gnus-sum.el (gnus-summary-refer-thread): Since lambdas aren't
+       closures, quote the form properly (bug#9194).
+
+2011-07-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-insert-new-articles): Clean up slightly.
+       (gnus-summary-insert-new-articles): Protect against servers that are
+       down.
+
+2011-07-29  Daniel Dehennin  <daniel.dehennin@baby-gnu.org>
+
+       * mm-decode.el (mm-dissect-buffer): Add a default content-disposition
+       in mm handle if none is specified.
+
+2011-07-24  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnimap.el (nnimap-make-thread-query): Quote message-ids for gmail.
+
+2011-07-23  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-search-thread): New function to make an nnir group
+       based on a thread query.
+
+       * gnus-sum.el (gnus-refer-thread-use-nnir): New variable to control use
+       of nnir in thread referral.
+       (gnus-summary-refer-thread): Use it.
+
+       * nnimap.el (nnimap-request-thread): Use it.
+
+2011-07-20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-tag-comment): Ignore HTML comments.
+
+2011-07-20  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (gnus-group-make-nnir-group): Allow optional search query
+       argument.
+       (gnus-group-make-nnir-group, nnir-request-group, nnir-run-query):
+       Use `nnir-address' to handle server info rather than passing an arg.
+
+       * nnimap.el (nnimap-make-thread-query): New utility function to format
+       an imap thread search query.
+       (nnimap-request-thread): Use it.
+
+       * gnus-sum.el (gnus-handle-ephemeral-exit): Ensure we are setting the
+       right select-method if we are not going back to the group buffer.
+
+2011-07-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-read-ephemeral-group): Make sure we don't
+       enter invalid buffer configurations into the quit form (bug#9107).
+       (gnus-group-tool-bar-gnome): Replace connect/disconnect with
+       unplugged/plugged.
+
+       * gnus-sum.el (gnus-summary-refer-thread): When inserting new headers,
+       keep track of which ones are unread (bug#9061).
+
+       * gnus.el (gnus-refer-article-method): Allow entering any sexp
+       (bug#9055).
+
+       * gnus-art.el (gnus-article-show-images): Allow working if using w3m
+       (bug#9041).
+
+       * gnus-html.el (mm-util): Require (bug#9073).
+
+       * gnus-sum.el (gnus-delete-duplicate-headers): New function.
+       (gnus-summary-refer-thread): Use it to remove duplicates in the
+       un-threaded view (bug#9053).
+       (gnus-summary-insert-subject): Document USE-OLD-HEADER (bug#9070).
+
+2011-07-07  Kan-Ru Chen  <kanru@kanru.info>
+
+       * nnir.el (nnir-read-server-parm): Use default value from global
+       variable.  Without this the default search engine parameters aren't
+       used at all.
+
+2011-07-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-unique-id): Don't use the undocumented return
+       value from (random t) (bug#9118).
+
+2011-07-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-auto-save-directory): If the ~/Mail directory
+       doesn't exist, use ~ as the auto-save directory (bug#4432).
+
+       * gnus-group.el (gnus-group-read-ephemeral-group): Start Gnus if it
+       hasn't already been started.
+
+2011-07-15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (debbugs-gnu): Rename from debbugs-emacs.
+
+       * message.el (message-reply): Work around mysterious bug where
+       `message-mode' seems to overwrite the locally bound `subject' variable.
+
+2011-07-14  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnimap.el (nnimap-request-thread): Ensure search is performed in
+       correct group.
+
+       * gnus-int.el (gnus-request-thread): Add group argument.
+
+       * gnus-sum.el (gnus-summary-refer-thread): Use it.
+
+2011-07-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * dgnushack.el (debbugs-gnu-summary-mode): Update compat names, too.
+
+       * gnus-group.el (gnus-read-ephemeral-emacs-bug-group): `debbugs-*'
+       renamed to `debbugs-gnu-*'.
+
+2011-07-08  Daiki Ueno  <ueno@unixuser.org>
+
+       * plstore.el: Revert the editing feature since it is not urgent.
+       (plstore-mode, plstore-mode-toggle-display, plstore-mode-original)
+       (plstore-mode-decoded): Remove.
+
+2011-07-07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-bug): Don't insert user variables.  It usually
+       isn't very interesting any more, and it leaks potentially secret data.
+       (gnus-debug): Remove.
+
+       * gnus-art.el (gnus-ignored-headers): Remove obsolete and non-working
+       use of :custom-show.
+
+2011-07-07  Daiki Ueno  <ueno@unixuser.org>
+
+       * plstore.el: Add documentation.
+       (plstore-mode): New mode to edit plstore file.
+       (plstore-mode-toggle-display, plstore-mode-original)
+       (plstore-mode-decoded): New command.
+       (plstore--encode, plstore--decode, plstore--write-contents-functions)
+       (plstore--insert-buffer, plstore--make): New function.
+       (plstore-open, plstore-save): Simplify by using them.
+
+2011-07-06  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-group.el (gnus-read-ephemeral-emacs-bug-group): Silence compiler.
+
+2011-07-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-refer-article-method): Remove mention of nnspool, which
+       no longer is much used.
+       (gnus-summary-line-format): Link to "Marking Articles" instead of "Read
+       Articles".
+
+2011-04-03  Kan-Ru Chen  <kanru@kanru.info>
+
+       * nnir.el (nnir-notmuch-program, nnir-notmuch-additional-switches)
+       (nnir-notmuch-remove-prefix, nnir-engines, nnir-run-notmuch): New nnir
+       `notmuch' backend.
+
+2011-07-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-text-html-renderer): Doc fix.
+
+       * gnus-msg.el (gnus-bug): Fix the MML tag.
+
+       * pop3.el (pop3-open-server): -ERR is a valid response to CAPA.
+
+2011-07-05  Daiki Ueno  <ueno@unixuser.org>
+
+       * gnus-start.el (gnus-get-unread-articles): Don't connect to the
+       secondary methods if started with `gnus-no-server'.
+
+2011-07-05  Juanma Barranquero  <lekktu@gmail.com>
+
+       * message.el (message-return-action): Fix typo in docstring.
+
+2011-07-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-read-ephemeral-bug-group): Allow fetching several
+       bug reports at once.
+
+       * nnimap.el (nnimap-request-scan): Say that splitting has finished.
+
+2011-07-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nndraft.el: Require gnus-group.
+       (nndraft-request-list): Declare.
+
+       * nndraft.el (nndraft-update-unread-articles): Don't show group having
+       no unread article unless it matches gnus-permanently-visible-groups.
+
+       * nndraft.el (nndraft-update-unread-articles): New function.
+       (nndraft-request-associate-buffer): Use it to update the number of
+       unread articles for the nndraft groups in the group buffer when saving
+       or killing a draft message.
+
+2011-07-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-read-ephemeral-bug-group): Bind the coding
+       systems to binary before writing and reading the mbox files.
+
+       * gnus.el (gnus-summary-line-format): Link to the info node for %U
+       instead of trying to list them all (bug#8978).
+
+2011-07-03  Wolfgang Jenkner  <wjenkner@inode.at>  (tiny change)
+
+       * pop3.el (pop3-open-server): Use :end-of-capability.
+
+2011-07-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-read-ephemeral-emacs-bug-group): Make sure that
+       the id is always a number.
+
+       * dgnushack.el (debbugs-summary-mode): Shut up compiler about debbugs.
+
+       * gnus-group.el (gnus-read-ephemeral-emacs-bug-group): Hook into
+       debbugs mode, if possible.
+
+2011-07-02  Daiki Ueno  <ueno@unixuser.org>
+
+       * auth-source.el (auth-source-token-passphrase-callback-function):
+       Reindent.
+       (epg-context-operation): Remove unnecessary autoload.
+
+2011-07-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-list-debbugs): New command.
+
+       * gnus-group.el (gnus-bug-group-download-format-alist): Get the
+       mboxstat instead of the maintbox, since the stat seems to be fuller.
+
+       * gnus-msg.el (gnus-configure-posting-styles): Don't try to select dead
+       summary buffers.
+
+       * message.el (message-get-reply-headers): Delete all duplicates,
+       instead of the first.
+       (message-get-reply-headers): Ensure that we have progress while
+       deleting duplicates.
+
+       * gnus-msg.el (gnus-configure-posting-styles): Get the local
+       gnus-posting-style value from the summary buffer to make it easier to
+       make that a per-buffer conf.
+
+2011-07-02  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-run-imap): Allow halting a search when an article is
+       found by setting `shortcut' in 'query.
+       (nnir-request-article): Use `shortcut' setting when requesting article
+       by Message-ID.
+
+2011-07-02  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-msg.el (gnus-bug): Give the Version and Package headers to
+       debbugs with the X-Debbugs-Package and X-Debbugs-Version headers.
+       Bring the pseudo-headers back too.
+
+2011-07-01  Daiki Ueno  <ueno@unixuser.org>
+
+       * auth-source.el (auth-source-token-passphrase-callback-function):
+       Simplify and remove EPA dependency.
+
+2011-07-01  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-request-article): Fix error message text.
+
+2011-07-01  Daiki Ueno  <ueno@unixuser.org>
+
+       * auth-source.el (plstore-delete): Autoload.
+       (auth-source-plstore-search): Support delete operation.
+       * plstore.el (plstore-delete): New function.
+
+2011-07-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-draft.el (gnus-draft-clear-marks): Revert last change;
+       mark actually existing articles as unread rather than the ones that
+       active asserts.
+
+2011-07-01  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * nntp.el (nntp-record-command):
+       * gnus-util.el (gnus-message-with-timestamp-1):
+       Use format-time-string rather than decoding time stamps by hand.
+       This is simpler and insulates the code from potential changes to
+       current-time format.
+
+2011-07-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-draft.el (gnus-draft-clear-marks): Mark deleted articles as read.
+
+2011-07-01  Daiki Ueno  <ueno@unixuser.org>
+
+       * plstore.el (plstore-select-keys, plstore-encrypt-to): New variable.
+       (plstore-save): Support public key encryption.
+       (plstore--init-from-buffer): New function.
+       (plstore-open): Use it; fix error when opening a non-existent file.
+       (plstore-revert): Use plstore--init-from-buffer.
+
+2011-07-01  Daiki Ueno  <ueno@unixuser.org>
+
+       * auth-source.el (auth-source-backend): Fix :initarg for data slot.
+
+2011-06-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml2015.el (mml2015-use): Replace string-match-p with string-match
+       for old Emacsen.
+
+2011-06-30  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el (mml2015-use): Don't try to load PGG on Emacs 24, when EPG
+       is not fully working.
+
+2011-06-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * dgnushack.el: Autoload sha1 on XEmacs.
+
+       * gnus-group.el (gnus-read-ephemeral-emacs-bug-group): Take an optional
+       quit window configuration.
+
+       * auth-source.el (epg-context-set-passphrase-callback):
+       Remove duplicate autoload.
+
+2011-06-30  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-request-article): Allow requesting articles by
+       Message-ID with nnimap.
+
+       * gnus-sum.el (gnus-refer-article-methods): Allow (nnir) entry to use
+       current server.
+
+2011-06-30  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el: Autoload EPA/EPG functions.
+       (auth-source-netrc-use-gpg-tokens): Clarify that it should not be
+       changed when EPA/EPG is not available.
+       (auth-source-backend): Rename "arg" member to "data".
+       (auth-source-backend-parse, auth-source-plstore-search)
+       (auth-source-plstore-create): Use it.
+
+2011-06-30  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * gnus-art.el (gnus-request-article-this-buffer): Use existing function
+       `gnus-refer-article-methods'.
+
+2011-06-30  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el: Require EPA and EPG.
+       (auth-source-passphrase-alist): New variable.
+       (auth-source-passphrase-callback-function)
+       (auth-source-token-passphrase-callback-function): Callbacks for the
+       netrc field encryption (GPG tokens).
+       (auth-source-epa-extract-gpg-token, auth-source-epa-make-gpg-token):
+       Symmetric encryption and decryption of the netrc GPG tokens.
+       (auth-source-netrc-normalize): Use them, simplifying the closure.
+
+2011-06-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (dgnushack-compile): Don't compile plstore.el unless epg
+       is available.
+
+2011-06-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-split-incoming-mail): If `nnimap-split-fancy' is
+       non-nil, and `nnimap-split-methods' is nil, use the former.
+
+2011-06-30  Daiki Ueno  <ueno@unixuser.org>
+
+       * plstore.el (plstore-revert): New function.
+       (plstore-open): Use it; hide the buffer from user.
+
+2011-06-30  Daiki Ueno  <ueno@unixuser.org>
+
+       * auth-source.el (auth-source-backend): New member "arg".
+       (auth-source-backend-parse): Handle new backend 'plstore.
+       * plstore.el: New file.
+
+2011-06-30  Glenn Morris  <rgm@gnu.org>
+
+       * mm-util.el (mm-charset-synonym-alist): Move definition before use.
+
+2011-06-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-process-expiry-targets): Say what target we're
+       expiring articles to.
+
+       * mm-util.el (mm-charset-to-coding-system): Recognize all ANSI.x3.4
+       variations as ASCII (bug#5458).
+
+2011-06-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnmh.el (nnmh-request-list-1): Work on MS Windows.
+
+2011-06-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-point-in-header-p): Tweak the function to default
+       to saying that we're not in the headers if there is no separator at
+       all.  This makes it possible to use the Message version of `M-q' in
+       buffers with no headers (bug#7987).
+       (message-point-in-header-p): Fix last checkin to work with an empty
+       mail-header-separator, too.
+
+       * auth-source.el (auth-source-netrc-saver): If the user says "don't ask
+       again, save the choice via customize.
+
+2011-06-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-send-mail-function): Add `sendmail-query-once'.
+
+       * nnimap.el (nnimap-finish-retrieve-group-infos): If the server has
+       ended the connection, bail out before waiting infinitely on a new
+       connection.
+
+2011-06-28  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-msg.el (gnus-bug): Add Package and Version pseudo-headers to bug
+       reports.
+
+       * gnus.el (gnus-bug-package): Use "gnus."
+       (gnus-maintainer): Direct bug reports to submit@debbugs.gnu.org.
+
+2011-06-26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * dgnushack.el: Make the timer warning go away on XEmacs.
+
+       * gnus-art.el (gnus-article-stop-animations): New function to stop any
+       animations going on at article exit time.
+
+       * gnus-registry.el (gnus-registry-user-format-function-M): Reinstate,
+       since removing it breaks people upgrading.
+
+       * shr.el (shr-put-image): Use the new interface for animating images.
+       (shr-put-image): Animate for 60 seconds.
+
+       * dgnushack.el: Bind `gnutls-available-p' to `ignore' on XEmacs to
+       avoid compiler warnings.
+
+       * auth-source.el (with-auth-source-epa-overrides): Fix compilation
+       error with `find-file-hooks' on Emacs 22.
+       (with-auth-source-epa-overrides): Ugly hack to Wrap the
+       `find-file-hook' things in `symbol-value' to avoid compilation warnings
+       on all architectures.
+
+       * spam.el (spam-stat): Require in a normal fashion without binding
+       `spam-stat-install-hooks' to avoid compilation warnings.
+
+       * spam-stat.el (spam-stat-install-hooks): Remove.
+       (spam-stat-install-hooks): Don't run automatically.
+
+2011-06-26  Timo Juhani Lindfors  <timo.lindfors@iki.fi>  (tiny change)
+
+       * gnus-msg.el (gnus-summary-reply-to-list-with-original): New command
+       and keystroke.
+
+2011-06-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * auth-source.el (auth-source-netrc-cache): Move forward.
+
+2011-06-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * proto-stream.el (proto-stream-open-starttls): Use
+       `gnutls-available-p' to see whether we have built-in support.
+
+       * auth-source.el (auth-source-netrc-create): Don't query the bits that
+       we already know.
+       (auth-source-forget-all-cached): Clear auth-source-netrc-cache, too.
+       (auth-source-netrc-create): Don't prompt for the stuff we already know.
+
+2011-06-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * auth-source.el (auth-source-netrc-create): Don't print all tokens in
+       %S format, since that looks odd.
+       (auth-sources): Prefer the ~/.authinfo file over the ~/.authinfo.gpg
+       file, especially when saving.
+
+2011-06-21  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnimap.el (nnimap-find-article-by-message-id): return nil when no
+       article found.
+
+2011-06-18  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-source-netrc-use-gpg-tokens): Replace
+       `auth-source-save-secrets' with a more sensitive alist that can be
+       configured per file.  Experimental, so defaults to 'never.
+       (auth-source-netrc-create): Use it.  Still experimental code.
+       (with-auth-source-epa-overrides): Use `find-file-hooks' if
+       `find-file-hook' is unbound (XEmacs fix).  Fix backquoting bug.
+
+2011-06-16  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-source-save-secrets): New variable to control if
+       secret tokens should be saved encrypted.
+       (auth-source-netrc-parse, auth-source-netrc-search): Pass the file name
+       to `auth-source-netrc-normalize'.
+       (with-auth-source-epa-overrides): Add convenience macro.  Don't depend
+       on the EPA variables being defined.
+       (auth-source-epa-make-gpg-token): Convert text to a "gpg:" token.
+       (auth-source-netrc-normalize): Convert "gpg:" tokens back to text in
+       the lexical-let closure.
+       (auth-source-netrc-create): Create "gpg:" tokens according to
+       `auth-source-save-secrets'.
+
+2011-06-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el (gnus-group-update-group): Add new argument
+       `info-unchanged' that stops updating dribble buffer.
+
+       * gnus-start.el (gnus-dribble-enter): Add new argument `regexp' that
+       deletes lines matching to it in dribble buffer.
+
+       * gnus-agent.el (gnus-agent-fetch-group-1):
+       * gnus-group.el (gnus-group-update-group-line, gnus-group-make-group):
+       * gnus-srvr.el (gnus-server-update-server, gnus-server-set-info):
+       * gnus-start.el (gnus-group-change-level):
+       * gnus-sum.el (gnus-summary-move-article): Delete old dribble entry.
+
+       * gnus-sum.el (gnus-summary-update-info): Don't update dribble buffer
+       if newsgroup info is not changed.
+
+       * gnus-group.el (gnus-group-get-new-news-this-group):
+       * gnus-sum.el (gnus-summary-read-group-1, gnus-summary-exit-no-update):
+       Don't update dribble buffer.
+
+2011-06-01  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-remove-ignored): New function to
+       remove entries with groups we ignore.
+
+2011-05-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-rescale-image): Add an :ascent of 100 to images so that
+       the underline comes at the bottom.
+
+2011-05-31  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-article-marks-to-chars): Rename from
+       `gnus-registry-user-format-function-M' and declare the latter obsolete.
+       (gnus-registry-article-marks-to-names): Rename from
+       `gnus-registry-user-format-function-M2'.
+
+2011-05-31  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-exit): Make sure to kill article buffer in
+       ephemeral group.
+
+2011-05-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-browse-image): Copy the URL if called interactively.
+
+2011-05-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-mark-article-read): It's possible that we
+       want to have `gnus-newsgroup-unselected' kept sorted.  If this isn't
+       done, then unselected articles may be marked as read.
+
+       * pop3.el (pop3-open-server): Erase the buffer after the greeting,
+       since not doing this seems to lead to a race condition in pop3-logon.
+
+       * nnvirtual.el (nnvirtual-request-article): Bind `gnus-command-method'
+       so that the call chain it correct when we call "upwards".
+
+       * gnus-sum.el (gnus-select-newsgroup): Auto-expiry doesn't make sense
+       in read-only groups.
+
+       * gnus-group.el (gnus-group-mark-article-read): Ditto.
+
+       * message.el (message-cite-reply-position): Doc string fix.
+
+       * nnimap.el (nnimap-transform-headers): Simplify regexp to hopefully
+       avoid regexp overflow.
+       (nnimap-transform-split-mail): Ditto.
+
+       * pop3.el (pop3-retr): Error out if the server closes the connection.
+
+2011-05-30  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * mml1991.el (mml1991-mailcrypt-encrypt): Remove use of ill-designed
+       mm-with-unibyte-current-buffer.  The buffer should not contain any
+       multibyte chars anyway at this stage.
+
+2011-05-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-urlify): Use shr-add-font to make underlines be less ugly
+       at the end of lines.
+
+2011-05-29  Julien Danjou  <julien@danjou.info>
+
+       * smiley.el (gnus-smiley-file-types): Add gif as supported file type.
+
+2011-05-27  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-group.el (gnus-bug-group-download-format-alist):
+       Use the "maintainer" version of debian reports as well.
+
+2011-05-26  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-group.el (gnus-bug-group-download-format-alist):
+       Use the "maintainer" version of debbugs.gnu.org reports.
+
+2011-05-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-delete-part): Fix mm-handle-filename usage.
+
+2011-05-23  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-cus.el (gnus-agent-customize-category):
+       * gnus-delay.el (gnus-delay-send-queue):
+       * gnus.el (gnus-other-frame):
+       Don't quote lambda expressions with `quote'.
+
+2011-05-20  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-sum.el (gnus-summary-hide-thread): Fix bug where moving to hide
+       the thread moves us backwards and so we loop forever.
+
+2011-05-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding): Allow leading
+       whitespace in base64 data lines.
+
+2011-05-18  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-user-format-function-M):
+       Use `mapconcat'.
+       (gnus-registry-user-format-function-M2): Use to see the full text of
+       the marks.  Make "," the mark text separator.
+
+       * nntp.el (nntp-send-authinfo): Use the "force" token for NNTP
+       authentication with auth-source.
+
+2011-05-17  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-group.el (gnus-import-other-newsrc-file):
+       Use insert-file-contents.
+
+2011-05-16  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-sum.el (gnus-summary-hide-all-threads): Add update message every
+       1000 iterations.
+
+2011-05-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nntp.el (nntp-open-connection): Check if process-type is available.
+
+2011-05-16  Julien Danjou  <julien@danjou.info>
+
+       * shr.el (shr-tag-del): Add support for del tag.
+
+2011-05-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-html.el (gnus-html-put-image): Register a displayer.
+
+       * shr.el (shr-image-displayer): Don't remove text props from alt text.
+
+2011-05-13  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * registry.el (prune-factor): New initialization parameter defaulting
+       to 0.1.
+       (registry-prune-hard): Use it.
+
+       * gnus-registry.el (gnus-registry-fixup-registry): Set prune-factor to
+       0.1 expicitly.
+
+2011-05-13  Glenn Morris  <rgm@gnu.org>
+
+       * message.el (message-send-mail-with-sendmail): Assume sendmail-program
+       is bound, since this function requires sendmail.
+
+2011-05-11  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * registry.el (registry-usage-test): Disable pruning test.
+
+2011-05-11  David Engster  <dengste@eml.cc>
+
+       * lpath.el: Bind shr-put-image and process-type for Emacs22 and XEmacs.
+       Bind set-network-process-option for XEmacs.
+
+2011-05-10  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * registry.el (registry-prune-hard-candidates)
+       (registry-prune-soft-candidates): Helper methods for registry pruning.
+       (registry-prune): Use them.  Make the sort function optional.
+
+2011-05-10  Jim Meyering  <meyering@redhat.com>
+
+       * shr.el (shr-colorize-region): Fix typo "on on -> on".
+
+2011-05-10  Julien Danjou  <julien@danjou.info>
+
+       * shr.el (shr-put-color-1): Do not bug out when old-props is a face
+       symbol and not a list.
+
+2011-05-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-mode): Move binding of
+       shr-put-image-function here from gnus-article-prepare-display.
+
+       * shr.el (shr-put-image-function): New variable.
+       (shr-image-fetched, shr-image-displayer, shr-tag-img): Funcall it.
+       (shr-put-image): Return scaled image.
+
+       * gnus-art.el (gnus-shr-put-image): New function.
+       (gnus-article-prepare-display): Bind shr-put-image-function to it.
+
+       * gnus-html.el (gnus-html-wash-images): Register scaled images, not
+       original ones, as deletable.
+
+2011-05-09  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * nntp.el (nntp-open-connection): Set TCP keepalive option.
+
+2011-05-09  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * registry.el (registry-full): Add convenience method.  Fix logic.
+       (registry-insert): Use it.  Fix logic here too.
+
+       * gnus-registry.el (gnus-registry-insert): Add wrapper that calls
+       `registry-prune' if `registry-full' returns t.
+       (gnus-registry-handle-action)
+       (gnus-registry-get-or-make-entry, gnus-registry-set-id-key)
+       (gnus-registry-usage-test): Use it.
+
+2011-05-07  Julien Danjou  <julien@danjou.info>
+
+       * shr.el (shr-link): Make shr-link inherit from link by default.
+
+2011-05-06  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * shr.el (shr-urlify, shr-link): Fix shr-link face.
+
+2011-05-05  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * shr.el (shr-urlify, shr-link): Still broken but at least doesn't
+       error out because the face is not a list.
+
+2011-05-05  Glenn Morris  <rgm@gnu.org>
+
+       * proto-stream.el (gnutls-negotiate): Fix declarations.
+
+       * gnus-start.el (gnus-propagate-marks): Declare.
+
+2011-05-04  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * registry.el (registry-reindex): Fix percentage message.
+
+       * proto-stream.el (network-stream-open-starttls): Adjust to call
+       `gnutls-negotiate' with :process and :hostname arguments.
+
+2011-05-03  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * shr.el: Add shr-link face for links.
+       (shr-urlify): Use it.
+
+       * registry.el (registry-insert): Make error message more helpful.
+
+2011-05-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-html.el (gnus-html-schedule-image-fetching):
+       Use url-queue-retrieve, if it exists.
+
+       * shr.el (shr-tag-img): Ditto.
+
+       * gnus.el: Autoload more gnus-agent functions.
+
+       * gnus-art.el (gnus-request-article-this-buffer): Store articles in the
+       agent if we haven't already (bug#8502).
+
+       * gnus-async.el (gnus-async-article-callback): Put prefetched articles
+       into the Agent, too.
+
+       * gnus-agent.el (gnus-agent-store-article): New function.
+
+       * nnheader.el (nnheader-insert-buffer-substring): Rename from nntp-
+       and moved from that file for reuse.
+
+       * pop3.el (pop3-open-server): Error messages are "-ERR".
+
+2011-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * pop3.el (pop3-open-server): Upgrade opportunistically to STARTTLS.
+       (open-tls-stream): Remove superfluous tls/starttls autoloads.
+
+2011-05-01  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: No Gnus v0.17 is released.
+
+2011-05-01  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-sum.el (gnus-summary-next-article): Don't bug out if the summary
+       buffer has moved to a different frame.
+
+2011-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-request-article): Use nntp-insert-buffer-substring
+       to get the conversion from unibyte to multibyte buffers to work on
+       Emacs 22.
+
+       * nntp.el (nntp-request-article): Slight clean-up.
+
+2011-04-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-strike-through): New face.
+       (shr-tag-s): Use it to provide <s> support.
+       (shr-tag-s): Remove duplicate definition.
+
+2011-04-25  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-ignore-group-p): Don't call
+       `gnus-parameter-registry-ignore' if the *Group* buffer doesn't exist.
+
+2011-04-24  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * proto-stream.el (proto-stream-open-starttls): Give host parameter to
+       `gnutls-negotiate'.
+       (gnutls-negotiate): Adjust `gnutls-negotiate' declaration.
+
+2011-04-23  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-sum.el (gnus-extra-headers): Bump :version.
+
+2011-04-24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-tag-sup): New function.
+       (shr-tag-sub): Ditto.
+
+2011-04-22  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-ignore-group-p): Test specifically
+       for the case where `gnus-registry-ignored-groups' is a list of lists,
+       and don't call `gnus-parameter-registry-ignore' otherwise.
+
+2011-04-21  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * nnimap.el (nnimap-user): New backend variable.
+       (nnimap-open-connection-1): Use it.
+       (nnimap-credentials): Accept user parameter so it's explicit what user
+       name is desired.
+
+       * gnus-sum.el (gnus-extra-headers): Add Keywords, Cc, and Gcc to
+       default.
+
+       * gnus.el (gnus-registry-ignored-groups): Provide default in gnus.el,
+       not gnus-registry.el.
+
+       * gnus-registry.el: Mention in comments how to modify
+       `gnus-extra-headers' for proper recipient tracking and that it may
+       already have To and Cc recently, which it does as of this commit.
+       (gnus-registry-ignored-groups): Remove defcustom.
+       Explain why in comments.
+       (gnus-registry-action): Fix data-header reference to use the extra
+       headers.  Explain in package commentary how to add To and Cc headers to
+       the gnus-extra-headers.
+       (gnus-registry-ignored-groups): Adjust defaults to match the parameter.
+       (gnus-registry-ignore-group-p): Adjust to take either a group/topic
+       parameter list or a string list in `gnus-registry-ignored-groups'.
+       Fix logic error.
+
+2011-04-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-expand-url): Protect against null urls.
+
+2011-04-20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-base): New binding.
+       (shr-tag-base): Keep track of <base>.
+       (shr-expand-url): New function used throughout.
+
+2011-04-20  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el
+       (gnus-registry--split-fancy-with-parent-internal): Fix loop bugs.
+       (gnus-registry-ignored-groups): New variable.
+       (gnus-registry-ignore-group-p): Use it.
+       (gnus-registry-handle-action): Use `gnus-registry-ignore-group-p' and
+       set the destination group to nil (same as delete) if it's ignored.
+
+2011-04-20  David Engster  <dengste@eml.cc>
+
+       * tests/gnustest-nntp.el: New file for simple NNTP testing.
+
+       * Makefile.in (test-nntp): New rule.
+       (check): Add it.
+       (test-registry): Change '$(EMACS_COMP)' to '$(EMACS) $(FLAGS)'.
+
+2011-04-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-registry.el (gnus-registry-action)
+       (gnus-registry-fetch-header-fast):
+       Don't use mail-header that looks an internal function of mailheader.el.
+
+2011-04-19  Glenn Morris  <rgm@gnu.org>
+
+       * time-date.el (time-to-days): Remove unused local variables.
+
+2011-04-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-registry.el: Eliminate cl functions.
+       (gnus-registry-sort-addresses): New function that replaces mapcan.
+       (gnus-registry-action, gnus-registry-spool-action)
+       (gnus-registry-split-fancy-with-parent)
+       (gnus-registry-fetch-recipients-fast): Use it.
+       (gnus-registry-import-eld): Replace delete* with dolist + delq.
+
+       * registry.el (initialize-instance, registry-lookup)
+       (registry-lookup-breaks-before-lexbind, registry-lookup-secondary)
+       (registry-lookup-secondary-value, registry-search, registry-delete)
+       (registry-insert, registry-reindex, registry-size, registry-prune):
+       Use eval-and-compile.
+
+2011-04-16  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * registry.el (registry-reindex): New method to recreate the secondary
+       registry indices.
+
+       * gnus-registry.el (gnus-registry-fixup-registry): Use it if the
+       tracked field changes.
+       (gnus-registry-unfollowed-addresses, gnus-registry-track-extra)
+       (gnus-registry-action, gnus-registry-spool-action)
+       (gnus-registry-handle-action)
+       (gnus-registry--split-fancy-with-parent-internal)
+       (gnus-registry-split-fancy-with-parent)
+       (gnus-registry-register-message-ids): Add recipient tracking on spool,
+       move, and delete actions, and for fancy splitting with parent.
+       (gnus-registry-extract-addresses)
+       (gnus-registry-fetch-recipients-fast)
+       (gnus-registry-fetch-header-fast): Convenience functions.
+       (gnus-registry-misc-test): ERT test of
+       `gnus-registry-extract-addresses'.
+
+2011-04-15  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry--split-fancy-with-parent-internal):
+       Track by subject first, then sender.
+
+2011-04-15  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * message.el (message-bogus-system-names): Replace ^...$ => \`...\'.
+
+       * gnus.el (gnus-splash-svg-color-symbols): Don't use insert-file from
+       Lisp.
+
+       * gnus-draft.el (gnus-draft-setup): New arg `dont-pop'.
+       (gnus-draft-send): Use it to avoid popping
+       up frames from gnus-group-send-queue.
+
+2011-04-14  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el: Updated gnus-registry docs.
+
+2011-04-12  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry--split-fancy-with-parent-internal):
+       Fix logic bug.
+       (gnus-registry-post-process-groups): Fix logging of no results and
+       quote sender and subject.
+
+2011-04-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * proto-stream.el (proto-stream-open-starttls): Only do opportunistic
+       STARTTLS upgrades if we have built-in gnutls support.  Upgrades via
+       gnutls-cli are too slow to be done opportunistically.
+
+       * gnus-start.el (gnus-get-unread-articles): Slight cleanup.
+       (gnus-read-active-for-groups): Don't try to finish getting stuff where
+       we had no early-data returned.
+       (gnus-get-unread-articles): Add a sanity check so that we don't issue
+       two async commands to the same server at the same time.
+
+2011-04-12  Stig Sandbeck Mathisen  <ssm@fnord.no>  (tiny change)
+
+       * gnus-sum.el (gnus-summary-select-article-buffer): Doc fix.
+
+2011-04-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-registry.el (gnus-registry-remake-db): Put the warning on a
+       "warning" level.
+
+       * mm-url.el (mm-url-package-name): Remove to ease third-party reuse.
+       (mm-url-insert-file-contents): Don't set the package names.
+
+2011-04-11  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-action): Remove properties and
+       simplify subject in `gnus-registry-handle-action'.
+       (gnus-registry-spool-action): Get subject and sender from message if
+       they are not passed in.
+       (gnus-registry-handle-action): Remove properties and simplify subject
+       consistently.
+
+2011-04-11  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * registry.el: Require CL before using defmacro*.
+
+2011-04-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-treat-date): Assume that
+       gnus-article-date-headers may be a group parameter.
+
+2011-04-07  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-handle-action): More debugging.
+
+       * gnus-start.el (gnus-gnus-to-newsrc-format): Add a way to run
+       interactively so the newsrc file can contain foreign groups too.
+       Useful for debugging but not much for users.
+
+2011-04-07  David Engster  <dengste@eml.cc>
+
+       * registry.el (registry-usage-test): Only do
+       `registry-lookup-breaks-before-lexbind' testing for Emacs24 with
+       lexical binding.
+
+2011-04-07  David Engster  <dengste@eml.cc>
+
+       * Makefile.in (check, test-registry): New rules for test-suite.
+
+2011-04-06  David Engster  <dengste@eml.cc>
+
+       * registry.el, gnus-registry.el: Use `ignore-errors' instead of third
+       argument NOERROR for `require', since XEmacs 21.4 does not support it.
+
+2011-04-06  David Engster  <dengste@eml.cc>
+
+       * registry.el (initialize-instance): Change :after to :AFTER to be
+       compatible with old EIEIO version in XEmacs.
+
+2011-04-06  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-post-process-groups)
+       (gnus-registry--split-fancy-with-parent-internal): Fix splitting bugs
+       and provide better messaging.
+
+2011-04-06  David Engster  <dengste@eml.cc>
+
+       * Makefile.in (fail-on-warning): New rule to compile with warnings as
+       errors.
+
+       * dgnushack.el (dgnushack-compile-error-on-warn): New function to call
+       dgnushack-compile with error-on-warn enabled, and to signal an error if
+       clean compilation failed.
+       (dgnushack-compile): New argument 'error-on-warn'.  If non-nil, compile
+       with `byte-compile-error-on-warn'.  Return nil if errors occured.
+
+2011-04-06  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el: Don't use ERT if it's not available.  Load it
+       unconditionally anyway, discarding errors.
+       (gnus-registry-delete-entries): New convenience function.
+       (gnus-registry-import-eld): Import from old .eld registry.
+
+       * registry.el: Don't use ERT if it's not available.  Load it
+       unconditionally anyway, discarding errors.
+
+       * proto-stream.el (gnutls-negotiate): Revert inadvertent commit of the
+       version from the Claudio Bley GnuTLS patch (extra optional parameters
+       and host name).
+
+2011-04-05  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-fixup-registry): New function to
+       fixup the parameters that can be customized by the user between
+       save/read cycles.
+       (gnus-registry-read): Use it.
+       (gnus-registry-make-db): Use it.
+       (gnus-registry-spool-action, gnus-registry-handle-action):
+       Fix messaging.
+       (gnus-registry--split-fancy-with-parent-internal): Fix loop.
+       Map references to actual group names with sender and subject tracking.
+       (gnus-registry-post-process-groups): Use `cond' for better messaging.
+       (gnus-registry-usage-test): Add subject lookup test.
+
+       * registry.el (registry-db, initialize-instance): Set up constructor
+       instead of :initform arguments for the sake of older Emacsen.
+       (registry-lookup-breaks-before-lexbind): New method to demonstrate
+       pre-lexbind merge bug.
+       (registry-usage-test): Use it.
+       (initialize-instance, registry-db): Move the non-function initforms
+       back to the class definition.
+
+2011-04-03  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * registry.el: New library to manage gnus-registry-style data.
+
+       * gnus-registry.el: Use it (major rewrite).
+
+       * nnregistry.el: Use it.
+
+       * spam.el: Use it.
+
+2011-04-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-update-marks): Reinstate the code to not alter
+       marks on non-selected articles.
+
+2011-04-02  Chong Yidong  <cyd@stupidchicken.com>
+
+       * nnimap.el (nnimap-open-connection-1): Pass explicit :end-of-command
+       parameter to open-protocol-stream.
+
+2011-04-01  Julien Danjou  <julien@danjou.info>
+
+       * mm-view.el (mm-display-inline-fontify): Do not fontify with
+       fundamental-mode.
+
+2011-04-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-get-unread-articles): Don't try to contact denied
+       servers.
+
+2011-03-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-update-marks): Revert intersection change, which
+       made marks not propagate, again.
+
+2011-03-30  Chong Yidong  <cyd@stupidchicken.com>
+
+       * proto-stream.el (open-protocol-stream): Bring back `network' type.
+       Make this the default type.
+       (proto-stream-open-plain): Rename from proto-stream-open-default.
+       (open-protocol-stream, proto-stream-open-starttls)
+       (proto-stream-open-tls, proto-stream-open-shell): Replace `default'
+       with `plain'.
+
+       * nnimap.el (nnimap-stream, nnimap-open-connection-1): Accept `network'
+       value.
+
+       * nntp.el (nntp-open-connection-function): Document the fact that some
+       values are not functions but are instead handled specially.
+       Recognize nntp-open-plain-stream value.
+       (nntp-open-connection): Recognize that value.
+
+2011-03-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * dgnushack.el: Only do the defcustom compilation thing on XEmacs,
+       where it seems to be needed.
+
+2011-03-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gssapi.el (open-gssapi-stream): Remove the last mentions of the IMAP
+       stuff.
+
+       * gnus-score.el (gnus-score-string): Fix calling convention of
+       `gnus-simplify-buffer-fuzzy' after last patches.
+
+       * gnus-sum.el (gnus-update-marks): Don't send any marks updates to the
+       server for articles we didn't get any headers for.  This is a sanity
+       check.
+
+2011-03-29  Michael Welsh Duggan  <md5i@md5i.com>
+
+       * nnimap.el (nnimap-open-connection-1): Is the login responds with a
+       new CAPABILITY, use it.
+
+2011-03-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-agent.el (gnus-agent-fetch-headers): Don't message if we're not
+       downloading anything.
+
+       * gnus.el (gnus-splash-svg-color-symbols): Remove superfluous `and'.
+
+2011-03-29  Adam Sjøgren  <asjo@koldfront.dk>
+
+       * gnus.el (gnus-group-startup-message): Prefer svg file and replace
+       colors.
+       (gnus-splash-svg-color-symbols): New function.
+
+2011-03-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-simplify-buffer-fuzzy): Take the regexp explicitly
+       instead of using the global gnus-simplify-subject-fuzzy-regexp.
+       (gnus-simplify-subject-fuzzy): Use the local
+       gnus-simplify-subject-fuzzy-regex instead of the global one.
+       This makes using this variable in group parameters work.
+
+2011-03-29  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-unfollowed-groups):
+       Add "archive:sent" to the unfollowed group regex (for the recent Gnus
+       archive:sent-YYYY-MM-DD groups).
+       (gnus-registry-split-fancy-with-parent): Bail out early in sender
+       tracking if there are more than `gnus-registry-max-track-groups'
+       matches.
+
+2011-03-29  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * message.el (message--yank-original-internal): New function to do the
+       insertion cleanly inside eval in `message-yank-original'.
+       (message-yank-original): Use it.
+
+2011-03-29  Julien Danjou  <julien@danjou.info>
+
+       * mm-view.el (mm-display-inline-fontify): Use `set-normal-mode' with
+       local variables disabled rather than `normal-mode'.
+
+2011-03-28  Brian T. Sniffen  <bsniffen@akamai.com>  (tiny change)
+
+       * imap.el (imap-shell-open, imap-process-connection-type):
+       Use imap-process-connection-type for 'shell' streams as well as
+       Kerberos, SSL, other subprocesses.
+
+2011-03-26  Chong Yidong  <cyd@stupidchicken.com>
+
+       * proto-stream.el: Changes preparatory to merging open-protocol-stream
+       with open-network-stream.
+       (proto-stream-always-use-starttls): Option removed.
+       (open-protocol-stream): Return a process object by default.  Provide a
+       new parameter :return-list specifying a list-type return value, which
+       now has the form (PROP . PLIST) instead of a fixed-length list.  Change
+       :type `network' to `try-starttls', and `network-only' to `default'.
+       Make `default' the default, for compatibility with open-network-stream.
+       Handle the no-parameter case exactly as open-network-stream, with no
+       additional stream processing.  Search plists using plist-get.
+       Explicitly add :end-of-commend parameter if it is missing.
+       (proto-stream-open-default): Rename from
+       proto-stream-open-network-only.  Return 'default as the type.
+       (proto-stream-open-starttls): Rename from proto-stream-open-network.
+       Use plist-get.  Don't return `tls' as the type if STARTTLS negotiation
+       failed.  Always return a list with a (possibly dead) process as the
+       first element, for compatibility with open-network-stream.
+       (proto-stream-open-tls): Use plist-get.  Always return a list.
+       (proto-stream-open-shell): Return `default' as connection type.
+       (proto-stream-capability-open): Use plist-get.
+       (proto-stream-eoc): Function deleted.
+
+       * nnimap.el (nnimap-stream, nnimap-open-connection)
+       (nnimap-open-connection-1): Handle renaming of :type parameter for
+       open-protocol-stream.
+       (nnimap-open-connection-1): Pass a :return-list parameter
+       open-protocol-stream to obtain a list return value.  Parse this list
+       using plist-get.
+
+       * nntp.el (nntp-open-connection): Handle renaming of :type parameter
+       for open-protocol-stream.  Accept open-protocol-stream return value
+       that is a subprocess object instead of a list.  Handle the case of a
+       dead returned process.
+
+2011-03-25  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * mm-util.el (mm-handle-filename): Move to mm-decode.el (bug#8330).
+
+       * mm-decode.el (mm-handle-filename): Move from mm-util.el (bug#8330).
+
+2011-03-21  Julien Danjou  <julien@danjou.info>
+
+       * mm-view.el (mm-display-inline-fontify): Make mode optional, and call
+       normal-mode if not set.  Set temp buffer unmodified to avoid kill-buffer
+       query.
+       (mm-inline-text): Render normal text with fontification whenever
+       possible.
+
+       * gnus-sum.el (gnus-summary-save-parts-1):
+       * gnus-art.el (gnus-article-browse-html-save-cid-content)
+       (gnus-article-browse-html-parts, gnus-mime-delete-part)
+       (gnus-mime-copy-part, gnus-mime-inline-part, gnus-insert-mime-button):
+       Use `mm-handle-filename'.
+
+       * mm-util.el (mm-handle-filename): New function, return the filename of
+       an handle.
+
+2011-03-18  Julien Danjou  <julien@danjou.info>
+
+       * gnus-util.el (gnus-buffer-live-p): Simplify gnus-buffer-live-p.
+       (gnus-buffer-live-p): Check that buffer is not nil.
+
+2011-03-17  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: No Gnus v0.15 is released.
+
+2011-03-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * time-date.el (format-seconds): Use assoc instead of assoc-string to
+       avoid warning on XEmacs.
+
+       * dgnushack.el: Bind help-echo-owns-message to avoid a compiler warning
+       on XEmacs.
+
+       * gnus-art.el: Require mouse, which the build bot seems to say is
+       needed.
+
+       * dgnushack.el: Define url-retrieve-synchronously unless not defined.
+
+       * gravatar.el (gravatar-retrieve-synchronously): Use `url-retrieve' on
+       XEmacs, since it doesn't have url-retrieve-synchronously.
+
+       * time-date.el (format-seconds): Use assoc instead of assoc-string,
+       since assoc-string doesn't exist in XEmacs.
+
+2011-03-17  Antoine Levitt  <antoine.levitt@gmail.com>
+
+       * gnus-group.el (gnus-group-list-ticked): New function.
+       (gnus-group-make-menu-bar): Provide a menu entry for it.
+       (gnus-group-list-map): Provide a binding for it.
+
+2011-03-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-visit-file): New command.
+
+       * nnimap.el (nnimap-fetch-inbox): Rewrite slightly last patch.
+
+2011-03-17  Bjørn Mork  <bjorn@mork.no>
+
+       * nnimap.el (nnimap-fetch-inbox): Don't download bodies on ver4-capable
+       servers.
+
+2011-03-16  Julien Danjou  <julien@danjou.info>
+
+       * mm-uu.el (mm-uu-dissect-text-parts): Only dissect handle that are
+       inline.
+
+       * gnus-art.el (article-hide-list-identifiers):
+       Use gnus-group-get-list-identifiers.
+
+       * gnus-sum.el (gnus-group-get-list-identifiers): New function.
+       (gnus-summary-remove-list-identifiers):
+       Use gnus-group-get-list-identifiers to get regexp.
+       (gnus-select-newsgroup, gnus-summary-insert-subject)
+       (gnus-summary-insert-articles):
+       Call gnus-summary-remove-list-identifiers unconditionally.
+
+2011-03-15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-articles-to-read): Revert back to old behavior if
+       we're selecting a group with unread articles.
+
+       * nnimap.el (nnimap-open-connection-1): Allow `network-only', too.
+
+       * gssapi.el: New file separated out from imap.el to provide a general
+       Kerberos 5 connection facility for Emacs.
+
+       * message.el (message-elide-ellipsis): Document the format spec
+       ellipsis.
+
+2011-03-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-elide-region): Allow the ellipsis to say how many
+       lines were removed.
+
+2011-03-15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-win.el (gnus-configure-frame): Protect against trying to restore
+       window configurations containing buffers that are now dead.
+
+       * nnimap.el (nnimap-parse-flags): Remove all MODSEQ entries before
+       parsing to avoid integer overflows.
+       (nnimap-parse-flags): Simplify the last change.
+       (nnimap-parse-flags): Store HIGHESTMODSEQ as a string, since it may be
+       too large for 32-bit Emacsen.
+
+2011-03-15  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * auth-source.el (auth-source-netrc-create):
+       * message.el (message-yank-original): Fix use of `case'.
+
+2011-03-15  Nelson Ferreira  <nelson.ferreira@ieee.org>  (tiny change)
+
+       * gnus-art.el (gnus-article-treat-body-boundary): Fix boundary width on
+       XEmacs, which was one character too wide.
+
+2011-03-09  Antoine Levitt  <antoine.levitt@gmail.com>
+
+       * gnus-sum.el (gnus-articles-to-read): Use gnus-large-newsgroup as
+       default number of articles to display.
+       (gnus-articles-to-read): Use pretty names for prompt.
+
+2011-03-15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-int.el (gnus-open-server): Ditto.
+
+       * gnus-start.el (gnus-activate-group): Give a backtrace if
+       debug-on-quit is set and the user hits `C-g'.
+       (gnus-read-active-file): Ditto.
+
+       * gnus-group.el (gnus-group-read-ephemeral-group): Ditto.
+
+2011-03-15  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * message.el (message-yank-original): Use cond instead of CL case.
+
+2011-03-15  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * auth-source.el (auth-source-netrc-create): Use usual format for the
+       default in prompts.
+
+2011-03-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind read-char-choice for XEmacs.
+
+2011-03-13  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-source-netrc-create): Show the default in the
+       prompt when prompting for token creation.
+
+2011-03-12  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-source-format-prompt): Always convert the value
+       to a string to avoid evaluating non-string arguments.
+       (auth-source-netrc-create): Offer default properly, not as initial
+       content in `read-string'.
+       (auth-source-netrc-saver): Use a cache keyed by file name and MD5 hash
+       of line to determine if we've been run before.  If so, don't run again,
+       but print a trivial message to indicate the cache was hit instead.
+
+2011-03-11  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-sync.el (gnus-sync-install-hooks, gnus-sync-unload-hook):
+       Don't install `gnus-sync-read' to any hooks by default.  It's buggy.
+       The user will have to run `gnus-sync-read' manually and wait for Cloudy
+       Gnus.
+
+2011-03-11  Julien Danjou  <julien@danjou.info>
+
+       * mm-uu.el (mm-uu-type-alist): Add support for diff starting with "===
+       modified file".
+
+2011-03-09  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-source-read-char-choice): New function to read a
+       character choice using `dropdown-list', `read-char-choice', or
+       `read-char'.  It appends "[a/b/c] " to the prompt if the choices were
+       '(?a ?b ?c).  The `dropdown-list' support is disabled for now.  Use
+       `eval-when-compile' to load `dropdown-list'.  Remove `dropdown-list'.
+       (auth-source-netrc-saver): Use it.
+       (auth-source-pick-first-password): New convenience function.
+
+2011-03-08  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * nnimap.el (nnimap-credentials): Keep the :save-function as the third
+       parameter in the credentials.
+       (nnimap-open-connection-1): Use it after a successful login.
+       (nnimap-credentials): Add IMAP-specific user and password prompt.
+
+       * auth-source.el (auth-source-search): Add :require parameter, taking a
+       list.  Document it and the :save-function return token.  Pass :require
+       down.  Change the CREATED message from a warning to a debug statement.
+       (auth-source-search-backends): Pass :require down.
+       (auth-source-netrc-search): Pass :require down.
+       (auth-source-netrc-parse): Use :require, if it's given, as a filter.
+       Change save prompt to indicate all modifications saved here are
+       deletions.
+       (auth-source-netrc-create): Take user login name as default in user
+       prompt.  Move all the save functionality to a lexically bound function
+       under the :save-function token in the returned list.  Set up clearer
+       default prompts for user, host, port, and secret.
+       (auth-source-netrc-saver): New function, intended to be wrapped for
+       :save-function.
+
+2011-03-07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-table-horizontal-line): Change the defaults for the table
+       lines to be spaces instead.
+
+2011-03-07  Julien Danjou  <julien@danjou.info>
+
+       * sieve-manage.el (sieve-sasl-auth): Create auth-info if not found.
+       (sieve-sasl-auth): Check that auth-source-search did return something,
+       or just return an empty string.
+
+2011-03-05  Antoine Levitt  <antoine.levitt@gmail.com>
+
+       * gnus.el (gnus-interactive): Use read-directory-name.
+
+       * gnus-uu.el (gnus-uu-decode-uu-and-save)
+       (gnus-uu-decode-unshar-and-save, gnus-uu-decode-save)
+       (gnus-uu-decode-binhex, gnus-uu-decode-yenc)
+       (gnus-uu-decode-save-view, gnus-uu-decode-postscript-and-save):
+       Likewise.
+
+       * gnus-group.el (gnus-group-make-directory-group): Likewise.
+
+2011-03-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-group-change-level): Allow putting foreign groups
+       onto the list of killed groups, too.  This makes killed nnimap groups,
+       for instance, more reliably not reappear.
+
+       * nnimap.el (nnimap-request-thread): Don't bug out when we can't find
+       the parent.
+
+       * gnus-sum.el (gnus-update-read-articles): Fix typo.
+
+       * gnus.el (gnus-valid-select-methods): Mark nnimap as a backend that
+       really have server-side marks.
+
+       * gnus-sum.el (gnus-propagate-marks): Change default back to nil again,
+       since most backends do not usefully have server-side marks.
+       (gnus-update-read-articles): Propagate marks to all backends that
+       really have server-side marks.
+
+2011-03-05  Antoine Levitt  <antoine.levitt@gmail.com>
+
+       * message.el (message-cite-reply-position, message-cite-style):
+       New variables.
+       (message-yank-original): Use the new citation styles.
+
+2011-03-04  Daiki Ueno  <ueno@unixuser.org>
+
+       * message.el (message-options): Revert 22da67af (workaround for XEmacs
+       buffer-local issue); don't mark it buffer-local when running under
+       XEmacs.
+
+2011-03-03  Tassilo Horn  <tassilo@member.fsf.org>
+
+       * nnimap.el (nnimap-parse-flags): Add a workaround for FETCH lines with
+       numbers too big to be `read'.
+
+2011-03-02  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * password-cache.el (password-in-cache-p): Add autoload.
+
+       * message.el (message-options): Make buffer-local two ways to attempt
+       to fix a XEmacs bug.
+
+2011-03-02  Julien Danjou  <julien@danjou.info>
+
+       * gnus-art.el (gnus-with-article-buffer): Fix buffer live check.
+
+2011-03-01  Julien Danjou  <julien@danjou.info>
+
+       * gnus-art.el (list-identifier): Add list-identifier as a parameter
+       group.
+       (article-hide-list-identifiers): Use list-identifier group parameter.
+
+2011-02-28  Julien Danjou  <julien@danjou.info>
+
+       * sieve.el (sieve-buffer-script-name): New local variable to store
+       sieve script name.
+       (sieve-edit-script): Store sieve script name.
+       (sieve-upload): Use sieve script name when uploading.
+       (sieve-upload): Use substitute-command-keys.
+       (sieve-edit-script): Use substitute-command-keys.
+       (sieve-refresh-scriptlist): Use substitute-command-keys.
+       (sieve-manage-mode-map): Define keymap properly.
+       (sieve-manage-mode): Do not set mode name manually, change mode-name to
+       (sieve-refresh-scriptlist): Use substitute-command-keys."Sieve-manage".
+       Remove commented code about cvs.
+       (sieve-manage-quit): New function.
+       (sieve-manage-mode-map): Bind 'q' to sieve-manage-quit.
+
+2011-02-27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-import-other-newsrc-file): New function.
+
+2011-02-25  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-source-search): Cache empty result sets.
+
+       * password-cache.el (password-in-cache-p): Convenience function to
+       check if a key is in the cache, even if the value is nil.
+
+       * auth-source.el (auth-source-save-behavior): New variable to replace
+       `auth-source-never-create'.
+       (auth-source-netrc-create): Use it.
+       (auth-source-never-save): Remove.
+
+2011-02-25  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-stream): Doc fix.
+       (nnimap-open-connection-1): Reverse the order of the ports to that the
+       prompted-for port is first.
+
+       * gnus-start.el (gnus-get-unread-articles): Don't clobber the async
+       retrieval by the no-group selection.
+
+       * gnus-demon.el (gnus-demon-init): run-with-timer should be called with
+       numerical parameters.
+
+2011-02-25  Julien Danjou  <julien@danjou.info>
+
+       * gnus-gravatar.el: Use gnus-with-article-buffer.
+
+       * gnus-art.el (gnus-with-article-buffer): Check that the
+       gnus-article-buffer is alive.
+
+2011-02-24  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-source-creation-prompts): New variable to manage
+       creation-time prompts.
+       (auth-source-search): Document it.
+       (auth-source-format-prompt): Add utility function.
+       (auth-source-netrc-create): Don't default the user name to
+       user-login-name.  Use `auth-source-creation-prompts' and some default
+       prompts for user, host, port, and password (the default generic prompt
+       remains ugly).
+       (auth-source-never-save): Add customizable option to never save info.
+       (auth-source-netrc-create): Use it and improve save prompts.  Fix help
+       mode excursion.
+
+2011-02-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * auth-source.el (auth-source-netrc-create): Use `read-char' with no
+       argument that XEmacs doesn't support.
+
+       * dgnushack.el (dgnushack-compile): Exclude color.el from being
+       compiled for Emacsen having no `libxml-parse-html-region' support.
+
+       * gnus-xmas.el (gnus-xmas-define): Remove gnus-x-color-values.
+
+       * lpath.el: Bind buffer-save-without-query for XEmacs.
+
+2011-02-23  Julien Danjou  <julien@danjou.info>
+
+       * gnus-art.el (article-make-date-line): Ignore errors if time is
+       invalid and not convertible.
+       (article-make-date-line): Only add lapsed time if time is not nil.
+
+2011-02-23  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-source-netrc-create): Use `read-char' instead of
+       `read-char-choice' for backwards compatibility.
+       (auth-source-netrc-element-or-first): New function to DTRT for
+       parameter extraction.
+       (auth-source-netrc-create): Use it and fix multiple parameter print
+       bug.  Use the default passed from above (given-default) or the
+       built-in (user-login-name for :user).
+
+2011-02-23  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-dribble-read-file):
+       Set buffer-save-without-query, since we always want to save the dribble
+       file, probably.
+
+       * nnmail.el (nnmail-article-group): Allow a final "" split to work on
+       nnimap.
+
+       * gnus-sum.el (gnus-user-date-format-alist): Rename back again from
+       -summary- since it's a user-visible variable.
+
+       * nnimap.el (nnimap-retrieve-group-data-early): Don't do QRESYNC the
+       first time you use the new Gnus.
+
+2011-02-22  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el: Don't load netrc.el.
+       (auth-sources): Search ~/.netrc as well by default.
+       (auth-source-debug): Add 'trivia option for extra output.
+       (auth-source-do-trivia): Use it.
+       (auth-source-search): Simplify logic to use
+       `auth-source-search-backends'.  Use `auth-source-do-trivia' where
+       appropriate.  Don't keep a running count at this level.  Layer :create
+       and :delete options appropriately on the first and second passes.
+       Don't track the backend with the search results.
+       (auth-source-search-backends): New function to search a list of
+       backends for a processed spec.
+       (auth-source-netrc-parse): Cache all netrc files, making
+       auth-source-netrc-cache an alist keyed by the file name and using the
+       file mtime as the caching criterion.  Keep the obfuscated data secret
+       with a lexical bind.
+       (auth-source-netrc-search): Don't calculate the length of the results
+       unnecessarily.
+       (auth-source-search-backends): Fix bug.
+       (auth-source-netrc-create): Rework prompts.
+
+2011-02-22  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-imap-search-arguments, nnir-imap-default-search-key):
+       Lower case names of search constraints.
+       (nnir-run-query): Cache and reuse search constraints for all imap
+       servers.
+
+2011-02-22  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-inews-add-send-actions): Restore the winconf name
+       after exit.
+       (gnus-setup-message): Define missing variable from last checkin.
+
+       * gnus-sum.el (gnus-summary-show-article): When called with t as the
+       value, show the raw article.
+
+2011-02-22  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: No Gnus v0.13 is released.
+
+2011-02-21  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-open-connection-1): Revert last change, since
+       auth-source now accepts numbers.
+
+       * auth-source.el (auth-source-netrc-parse): Accept a number as the port
+       spec, too.
+       (auth-source-ensure-strings): New function.
+
+       * gnus-art.el (gnus-article-update-date-headers): Doc fix.
+       (gnus-article-setup-buffer): Always restart the date timer so that user
+       changes to the frequency is respected.
+
+       * nnimap.el (nnimap-open-connection-1): auth-source expects strings as
+       port numbers, so make sure it gets that if nnimap-server-port is
+       explicit.
+
+2011-02-21  Simon Josefsson  <simon@josefsson.org>
+
+       * nnimap.el (nnimap-inbox): Doc fix.
+
+2011-02-21  Chong Yidong  <cyd@stupidchicken.com>
+
+       * color.el (color-name-to-rgb): Rename from color-rgb->normalize.
+       Autoload.  Add optional arg FRAME, and pass it to color-values.
+       (color-complement): Caller changed.  Doc fix.
+       (color-gradient): Rewrite for better clarity and efficiency.
+
+2011-02-20  Chong Yidong  <cyd@stupidchicken.com>
+
+       * shr-color.el (shr-color->hexadecimal): Use renamed function names
+       color-rgb-to-hex, color-name-to-rgb, color-srgb-to-lab, and
+       color-lab-to-srgb.
+
+2011-02-20  Drew Adams  <drew.adams@oracle.com>
+
+       * color.el: First part of merge from hexrgb.el.
+       (color-rgb-to-hex): Rename from color-rgb->hex.
+       (color-rgb-to-hsv): Rename from color-rgb->hsv.  Force hue and
+       saturation to zero if the value is too small.
+       (color-rgb-to-hsl): Rename from color-rgb->hsl.
+       (color-srgb-to-xyz): Rename from color-srgb->xyz.  Doc fix.
+       (color-xyz-to-srgb): Rename from color-xyz->srgb.  Doc fix.
+       (color-xyz-to-lab): Rename from color-xyz->lab.  Doc fix.
+       (color-lab-to-xyz): Rename from color-lab->xyz.  Doc fix.
+       (color-lab-to-srgb): Rename from color-lab->srgb.  Doc fix.
+       (color-cie-de2000): Doc fix.
+
+2011-02-21  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nntp.el (nntp-finish-retrieve-group-infos): Add a kludge to use the
+       given method as in the group name if we're using an extended method.
+       (nntp-finish-retrieve-group-infos): Wait for the end of the LIST ACTIVE
+       command, if we're using that, instead of waiting for the beginning.
+
+       * gnus-start.el (gnus-get-unread-articles): Extend the methods so that
+       we're sure to get unique server names, and we don't output two async
+       commands in the same buffer.  This fixes an NNTP hang for some users.
+
+2011-02-21  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: No Gnus v0.11 is released.
+
+2011-02-21  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-next-article): Add a kludge to reselect the
+       summary buffer before reading going to the next buffer.  This avoids
+       putting the point in the group buffer if you `C-g' the command.
+
+       * auth-source.el (auth-source-netrc-parse): Add an in-memory netrc
+       cache (for now) to make ~/.authinfo.gpg files usable.
+
+       * nnfolder.el (copyright-update): Define for the compiler.
+
+       * auth-source.el (auth-source-search): Fix unbound variable.
+
+2011-02-19  Glenn Morris  <rgm@gnu.org>
+
+       * gnus.el (gnus-meta): Doc fix.
+
+2011-02-19  Chong Yidong  <cyd@stupidchicken.com>
+
+       * nnfolder.el (nnfolder-save-buffer): Don't let-bind copyright-update,
+       in case it's not yet loaded.
+
+2011-02-20  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-wait-for-response): Ensure that we get the entire
+       line we're waiting for.
+
+2011-02-19  Darren Hoo  <darren.hoo@gmail.com>  (tiny change)
+
+       * gnus-art.el (gnus-article-next-page-1): Because customized mode-line
+       face with line-width greater than zero will cause RET in gnus summary
+       buffer to scroll down article page-wise because auto vscroll happens,
+       it should be temporally disabled when doing a scroll-up.
+
+2011-02-19  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-parse-copied-articles): Allow for "<foo> OK"
+       outputs from the server.
+
+2011-02-18  Antoine Levitt  <antoine.levitt@gmail.com>  (tiny change)
+
+       * gnus-art.el (gnus-article-prepare): Run gnus-article-prepare-hook
+       later so that bbdb can hook in easier.
+
+2011-02-18  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * auth-source.el (auth-source-search): Don't try to create credentials
+       if the caller doesn't want that.
+       (auth-source-search): If we don't find a match, don't bug out on
+       non-bound variables.
+       (auth-source-search): Only ask a single backend to create the
+       credentials.
+
+       * nnimap.el (nnimap-log-command): Add a newline to the inhibited
+       logging.
+       (nnimap-credentials): Protect against auth-source-search returning nil.
+       (nnimap-request-list): Protect against not being able to open the
+       server.
+
+2011-02-17  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * auth-source.el (auth-source-search): Do a two-phase search, one with
+       no :create to get the responses from all backends.
+
+       * nnimap.el (nnimap-open-connection-1): Delete duplicate server names
+       when getting credentials.
+
+       * gnus-util.el (gnus-delete-duplicates): New function.
+
+2011-02-17  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * nnimap.el (nnimap-credentials): Instead of picking the first port as
+       a creation default, pass the whole port list down.  It will be
+       completed.
+
+       * auth-source.el (auth-source-search): Updated docs to talk about
+       multiple creation choices.
+       (auth-source-netrc-create): Accept a list as a value (from the search
+       parameters) and do completion on that list.  Keep a separate netrc line
+       with the password obscured for showing the user.
+
+       * nnimap.el (nnimap-open-connection-1): Make the `nnimap-address' the
+       first choice to `auth-source-search' so it will be used for entry
+       creation instead of the server's Gnus-specific name.
+       (nnimap-credentials): Rely on the auth-source library to select which
+       port is actually wanted in the new netrc entry, so don't override
+       `auth-source-creation-defaults'.
+
+       * auth-source.el (auth-source-netrc-parse): Use :port instead of
+       :protocol and accept a missing user, host, or port as a wildcard match.
+       (auth-source-debug): Default to off.
+
+       (auth-source-netrc-search, auth-source-netrc-create)
+       (auth-source-secrets-search, auth-source-secrets-create)
+       (auth-source-user-or-password, auth-source-backend, auth-sources)
+       (auth-source-backend-parse-parameters, auth-source-search): Use :port
+       instead of :protocol.
+
+       * nnimap.el (nnimap-credentials): Pass a port default to
+       `auth-source-search' in case an entry needs to be created.
+       (nnimap-open-connection-1): Use :port instead of :protocol.
+
+2011-02-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * auth-source.el: Bind load-path when loading EIEIO from
+       "gnus-fallback-lib/eieio"; don't pass more than two args, that XEmacs
+       21.4 doesn't support, to `require'.
+       (auth-source-secrets-search): Use mm-delete-duplicates instead of
+       delete-dups that is not available in XEmacs 21.4.
+
+2011-02-16  Raphael Kubo da Costa  <kubito@gmail.com>  (tiny change)
+
+       * auth-source.el: Correctly load EIEIO from "gnus-fallback-lib/eieio"
+       as EIEIO must also be loaded when auth-source.el is being
+       byte-compiled.
+
+2011-02-16  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-fallback-lib/eieio/eieio.el: Copy from Emacs.
+
+       * gnus-fallback-lib/eieio/eieio-speedbar.el: Copy from Emacs.
+
+       * gnus-fallback-lib/eieio/eieio-opt.el: Copy from Emacs.
+
+       * gnus-fallback-lib/eieio/eieio-datadebug.el: Copy from Emacs.
+
+       * gnus-fallback-lib/eieio/eieio-custom.el: Copy from Emacs.
+
+       * gnus-fallback-lib/eieio/eieio-comp.el: Copy from Emacs.
+
+       * gnus-fallback-lib/eieio/eieio-base.el: Copy from Emacs.
+
+       * auth-source.el: Load EIEIO from "gnus-fallback-lib/eieio" if
+       necessary.
+
+2011-02-16  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-propagate-marks): Change default to t again, since
+       nil means that nnimap doesn't get updated.
+
+2011-02-16  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-source-netrc-create): Return a synthetic search
+       result when the user doesn't want to write to the file.
+       (auth-source-netrc-search): Expect a synthetic result and proceed
+       accordingly.
+       (auth-source-cache-expiry): New variable to override
+       `password-cache-expiry'.
+       (auth-source-remember): Use it.
+
+       * nnimap.el (nnimap-credentials): Remove the `inhibit-create'
+       parameter.  Create entry if necessary by using :create t.
+       (nnimap-open-connection-1): Don't pass `inhibit-create'.
+
+2011-02-15  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-source-debug): Enable by default and don't
+       mention the obsolete `auth-source-hide-passwords'.
+       (auth-source-do-warn): New function to debug unconditionally.
+       (auth-source-do-debug): Use it.
+       (auth-source-backend-parse): Use it for invalid `auth-sources' entries
+       and for Secrets API entries when the secrets.el library is not
+       available.
+
+2011-02-14  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-propagate-marks): Default to nil.
+       (gnus-summary-exit): Kill the correct article buffer on exit from a
+       `C-d' group.
+
+       * gnus-start.el (gnus-use-backend-marks): Removed, since it duplicates
+       gnus-propagate-marks.
+
+       * gnus-sum.el (gnus-summary-exit-no-update): Restore the group conf
+       before killing the buffers so that a non-full window conf gets handled
+       correctly.
+       (gnus-summary-exit): Ditto.
+       (gnus-summary-read-group-1): Ditto.
+
+       * nntp.el (nntp-retrieve-group-data-early): Reinstate the two-part
+       async code again so that we can debug it properly.
+
+       * message.el (message-reply): Take an optional switch-buffer parameter
+       so that Gnus window confs are respected better.
+
+2011-02-14  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-source-backend-parse-parameters): Don't rely on
+       `plist-get' to accept non-list parameters (XEmacs issue).
+       Fix docstring.
+       (auth-source-secrets-search): Use `delete-dups', `append mapcar', and
+       `butlast' instead of `remove-duplicates', `mapcan', and `subseq'.
+       (auth-sources, auth-source-backend-parse, auth-source-secrets-search):
+       Login collection is "Login" and not "login".
+
+2011-02-14  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-update-date-lapsed): Don't bug out when updating
+       multiple headers.
+
+       * nnimap.el (nnimap-inhibit-logging): New variable.
+       (nnimap-log-command): Don't log login commands.
+
+       * auth-source.el (auth-source-netrc-search): The asserts seem to want
+       to have more parameters.
+
+       * nnimap.el (nnimap-send-command): Mark the command time for each
+       command, so that we don't get NOOPs stepping on our toes.
+
+       * gnus-art.el (article-date-ut): Get the date from the Date header on
+       `t'.
+
+2011-02-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * auth-source.el (auth-source-search): Use copy-sequence instead of
+       the cl.el copy-list.
+
+2011-02-13  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * imap.el: Bring it back (revert
+       84d800cd31de3064f0ed39617d725709a2f8f42f).
+
+2011-02-13  Adam Sjøgren  <asjo@koldfront.dk>
+
+       * gnus-delay.el (gnus-delay-article) Fix number of seconds per day.
+       Improve prompt.
+
+2011-02-13  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-mode-line-format): Remove the article
+       washing status from the default format.  It isn't very informative.
+
+2011-02-13  Tassilo Horn  <tassilo@member.fsf.org>  (tiny change)
+
+       * nnimap.el (nnimap-request-accept-article, nnimap-process-quirk):
+       Fix Gcc processing on imap.
+
+2011-02-13  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * imap.el: Remove file.  All the functionality is in nnimap.el.
+
+2011-02-10  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * message.el (message-bury): Don't pop up a new window when selected
+       window is dedicated.
+
+2011-02-10  Antoine Levitt  <antoine.levitt@gmail.com>  (tiny change)
+
+       * gnus-sum.el (gnus-summary-save-parts): Use read-directory-name.
+
+2011-02-10  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * sieve-manage.el: Autoload `auth-source-search'.
+       (sieve-sasl-auth): Use it.
+
+2011-02-09  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * nnimap.el: Autoload `auth-source-forget+'.
+       (nnimap-open-connection-1): Use it if the connection fails.
+
+       * auth-source.el: Require `password-cache'.
+       (auth-source-hide-passwords, auth-source-cache): Remove and mark
+       obsolete.
+       (auth-source-magic): Marker for `password-cache' keys.
+       (auth-source-do-cache): Update docstring.
+       (auth-source-search): Use and check cache.
+       (auth-source-forget-all-cached, auth-source-remember)
+       (auth-source-recall, auth-source-forget, auth-source-forget+)
+       (auth-source-specmatchp): Caching support functions.
+       (auth-source-forget-user-or-password, auth-source-forget-all-cached):
+       Remove and obsolete.
+       (auth-source-user-or-password): Remove caching to further discourage
+       using it.  Always hide passwords.
+
+       * password-cache.el (password-cache-remove): Accept secrets that are
+       not strings.
+
+2011-02-09  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nntp.el (nntp-retrieve-group-data-early-disabled): Disable the async
+       code for now, since it doesn't work for all users.
+
+2011-02-09  Julien Danjou  <julien@danjou.info>
+
+       * message.el (message-options): Make message-options really buffer
+       local.
+
+2011-02-08  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * mail-source.el: Autoload `auth-source-search'.
+       (mail-source-keyword-map): Note order matters.
+       (mail-source-set-1): Get all the mail-source source values and
+       defaults and search auth-source on those if needed.  This can all
+       probably be simplified.
+
+       * nnimap.el: Autoload `auth-source-search'.
+       (nnimap-credentials): Use it.
+       (nnimap-open-connection-1): Ask for the virtual server and physical
+       address in one shot.
+
+       * nntp.el: Autoload `auth-source-search'.
+       (nntp-send-authinfo): Use it.  Note TODO.
+
+2011-02-08  Julien Danjou  <julien@danjou.info>
+
+       * shr.el (shr-tag-body): Add support for text attribute in body
+       markups.
+
+       * message.el (message-options): Make message-options a local variable.
+
+2011-02-07  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-source-secrets-search)
+       (auth-source-user-or-password): Use `append' instead of `nconc'.
+       (auth-source-user-or-password): Build return list better and protect
+       against nil :secret.
+
+2011-02-07  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-update-info): Refactor slightly.
+       (nnimap-update-info): Tell Gnus whether there are any \Recent messages.
+       (nnimap-update-info): Clean up slightly.
+       (nnimap-quirk): Add quirk for Gmail IMAP which bugs out on NUL
+       characters.
+       (nnimap-process-quirk): Rename function to avoid collision.
+       (nnimap-update-info): Fix macrology bug-out.
+       (nnimap-update-info): Simplify split history test.
+
+2011-02-06  Michael Albinus  <michael.albinus@gmx.de>
+
+       * auth-source.el (top): Require 'eieio unconditionally.
+       Autoload `secrets-get-attributes' instead of `secrets-get-attribute'.
+       (auth-source-secrets-search): Limit search when `max' is greater than
+       number of results.
+
+2011-02-06  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nntp.el (nntp-finish-retrieve-group-infos): Protect against the first
+       part not returning any data.
+
+       * proto-stream.el (open-protocol-stream): Document the return value.
+
+2011-02-06  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-source-secrets-search): Add examples.
+
+2011-02-06  Julien Danjou  <julien@danjou.info>
+
+       * message.el (message-setup-1): Handle message-generate-headers-first
+       set to t.
+
+2011-02-06  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-sources): Allow for simpler defaults for Secrets
+       API with a string "secrets:collection-name" and with 'default.
+       (auth-source-backend-parse): Parse "secrets:collection-name" and
+       'default.  Recurse on parses instead of repeating code.  Use the
+       Secrets API is the source is not nil and 'ignore otherwise.  Emit a
+       message when ignoring a source.
+       (auth-source-search): List ignored search keys at the top level.
+       (auth-source-netrc-create): Use `case' instead of `cond'.
+       (auth-source-secrets-search): Created with TODOs.
+       (auth-source-secrets-create): Created with TODOs.
+       (auth-source-retrieve, auth-source-create, auth-source-delete)
+       (auth-source-protocol-defaults, auth-source-user-or-password-imap)
+       (auth-source-user-or-password-pop3, auth-source-user-or-password-ssh)
+       (auth-source-user-or-password-sftp)
+       (auth-source-user-or-password-smtp): Remove.
+       (auth-source-user-or-password): Deprecated and modified to be a wrapper
+       around `auth-source-search'.  Not tested thoroughly.
+
+2011-02-04  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el: Bring in assoc and eioeio libraries.
+       (secrets-enabled): New variable to track the status of the Secrets API.
+       (auth-source-backend): New EIOEIO class to represent a backend.
+       (auth-source-creation-defaults): New variable to set prompt defaults
+       during token creation (see the `auth-source-search' docstring for
+       details).
+       (auth-sources): Simplify to allow a simple string as a netrc backend
+       spec.
+       (auth-source-backend-parse): Parse a backend from an `auth-sources' spec.
+       (auth-source-backend-parse-parameters): Fill in the backend parameters.
+       (auth-source-search): Main auth-source API entry point.
+       (auth-source-delete): Wrapper around `auth-source-search' for deletion.
+       (auth-source-search-collection): Helper function for searching.
+       (auth-source-netrc-parse, auth-source-netrc-normalize)
+       (auth-source-netrc-search, auth-source-netrc-create): Netrc backend.
+       Supports search, create, and delete.
+       (auth-source-secrets-search, auth-source-secrets-create): Secrets API
+       backend stubs.
+       (auth-source-user-or-password): Call `auth-source-search' but it's not
+       ready yet.
+
+2011-02-04  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-setup-1): Remove the read-only stuff, since it
+       doesn't work under XEmacs, for some reason.
+
+       * gnus-sum.el (gnus-user-date): Rename back from
+       gnus-summary-user-date since user code refers to it.
+
+       * shr.el (shr-render-td): Store the actual background color used.
+
+       * message.el (message-setup-1): Don't bind the constant
+       -forbidden-properties.
+       (message-setup-1): Revert previous change, since it needs to bind the
+       props to insert them.
+       (message-resend): Allow removing the read-only separator line.
+
+2011-02-03  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-request-accept-article): Give an error message if
+       the APPEND wasn't successful.
+
+2011-02-03  Adam Sjøgren  <asjo@koldfront.dk>
+
+       * gnus-start.el (gnus-get-unread-articles): Fix the call to methods
+       that have no groups.
+
+2011-02-03  Julien Danjou  <julien@danjou.info>
+
+       * gnus-draft.el: Remove progn around gnus-draft-setup.
+
+2011-02-03  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-read-active-for-groups): This function is never
+       called with a nil `infos', so clean that up.
+       (gnus-get-unread-articles): Request active files from primary/secondary
+       methods that have no groups (yet).
+
+2011-02-03  Julien Danjou  <julien@danjou.info>
+
+       * message.el (message-setup-1): Always generate References first.
+       (message-mail): Return the return value of message-setup, not always t.
+       (message-setup-1): Insert mail-header-separator with read-only and
+       intangible properties set.
+
+       * gnus.el (gnus-summary-line-format): Add missing semi-colon for
+       user-date in docstring.
+
+       * gnus-art.el (gnus-article-jump-to-part): Remove useless sit-for.
+
+       * gnus.el (gnus-summary-line-format): Mention &user-date format in
+       docstring.
+
+       * gnus.el (gnus-user-date-format-alist): Change default value.
+       Use defcustom, with type and group.  Move from gnus-util.el.
+       Rename to gnus-summary-user-date-format-alist.
+
+2011-02-03  Glenn Morris  <rgm@gnu.org>
+
+       * nnimap.el (gnus-fetch-headers): Declare.
+
+       * nnheader.el (gnus-range-add, gnus-remove-from-range): Autoload.
+
+2011-02-03  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-forward-make-body-digest-plain)
+       (message-followup, message-reply): Clean up things noted by Stefan.
+
+       * gnus-art.el (gnus-article-setup-buffer): Stop the date timer if
+       gnus-article-update-date-headers is nil.
+       (gnus-article-date-headers): Rip out the old -treat-date-* stuff, since
+       it didn't really work with defcustom.
+       (article-update-date-lapsed): Make sure the window start doesn't move,
+       either.
+
+2011-02-01  Julien Danjou  <julien@danjou.info>
+
+       * mm-uu.el (mm-uu-type-alist): Add support for git format-patch diff
+       format.
+
+       * mm-decode.el (mm-inline-media-tests): Do not check for diff-mode it's
+       standard in Emacs nowadays.
+
+       * color.el (color-gradient): Add a color-gradient function.
+
+2011-02-01  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * message.el (message-expand-name): Don't trust the return value of
+       bbdb-complete-name.
+       (message-check-news-header-syntax): Remove unused var `start'.
+       (message-idna-to-ascii-rhs-1): Remove unused vars `rhs' and `address'.
+       (message-inhibit-body-encoding): Move to before first use.
+       (mail-abbrev-mode-regexp, Expires, User-Agent, Lines, Distribution)
+       (To, References, In-Reply-To, Newsgroups, Subject, Path, From)
+       (Organization, Message-ID, Date, mh-previous-window-config):
+       Defvar the vars using dynamic scoping.
+
+2011-02-01  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-render-td): Only do colors at the final rendering.
+       Should be slightly faster.
+       (shr-insert-table): Fix up TD background colors when doing the
+       vertical padding.
+
+       * gnus-art.el (article-date-ut): Protect against articles with no Date
+       header.
+       (article-update-date-lapsed): Don't use current-column to find the
+       horizontal position.  It's fragile in the presence of \003 characters.
+
+       * gnus-start.el (gnus-read-active-file-1): Remove dead parameter infos.
+
+2011-01-31  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-transform-date): Rewrite to still work when
+       there are several rfc2822 parts.
+       (article-transform-date): Fix infinite recursion.
+       (article-date-ut): Replace infinitely many Date headers with a single
+       one when called interactively.
+
+       * nnimap.el (nnimap-wait-for-response): Wait for results in a more
+       secure manner.
+
+       * gnus-art.el (article-update-date-lapsed): Try to avoid having point
+       move around by not using save-window-excursion.  It seems to work...
+
+2011-01-31  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-make-date-line): Work for user-defined format.
+
+2011-01-31  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nntp.el (nntp-retrieve-group-data-early)
+       (nntp-finish-retrieve-group-infos): Implement the asynchronous data
+       fetching functions.
+
+       * gnus-start.el (gnus-read-active-for-groups): Read the active files
+       thoroughly for all backends that have no known groups.  This should
+       allow new nnml methods to retrieve mail.
+
+       * gnus-group.el (gnus-group-jump-to-group): Allow jumping to groups
+       that Gnus doesn't know exists again.
+
+       * gnus-art.el (gnus-article-date-lapsed-new-header): Remove.
+       (gnus-treat-date-ut): Ditto.
+       (gnus-article-update-date-header): Rename.
+       (gnus-treat-date-local): Remove.
+       (gnus-treat-date-english): Remove.
+       (gnus-treat-date-lapsed): Remove.
+       (gnus-treat-date-combined-lapsed): Remove.
+       (gnus-treat-date-original): Remove.
+       (gnus-treat-date-iso8601): Remove.
+       (gnus-treat-date-user-defined): Remove.
+       (gnus-article-date-headers): New variable to control all the date
+       header options.
+       (article-date-ut): Rewrite to allow using the new way to format date
+       headers(s).
+
+2011-01-30  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnmail.el (nnmail-article-group): Check for a direct fancy split
+       method.
+       (nnmail-article-group): A better test for fanciness.
+
+       * nnimap.el (nnimap-request-head): Protect against not finding the
+       article by Message-ID.
+
+2011-01-29  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-update-date-lapsed): Try a better way to really
+       keep point at the "same place".
+
+2011-01-28  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-select-newsgroup): Don't try to alter the active
+       data if the group is inactive.
+
+2011-01-28  Julien Danjou  <julien@danjou.info>
+
+       * gnus-win.el: Remove dead function gnus-window-configuration-element.
+       (gnus-all-windows-visible-p): Remove old compatibility code.
+       (gnus-window-top-edge): Add docstring.
+
+       * gnus-group.el (gnus-group-jump-to-group): Set must match to t.
+
+2011-01-28  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-int.el (gnus-request-marks): Call *-request-marks instead of the
+       older request-update-info.
+
+       * gnus-art.el (article-make-date-line): Limit the length a bit more.
+
+2011-01-28  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el (mml2015-epg-sign, mml2015-epg-encrypt):
+       Give mml2015-signers higher precedence over mml2015-sign-with-sender.
+
+2011-01-27  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-refresh-group): Refresh even non-visible
+       groups.  This makes the nndraft:queue group pop up if it's not already
+       there.
+
+       * gnus-sum.el (gnus-summary-read-group-1): Fix the "contains no
+       messages" logic, which was reversed.
+
+       * gnus-art.el (article-update-date-lapsed): Ensure that point stays at
+       the "same place" even if point is on the line being replaced.
+       (article-update-date-lapsed): Allow updating both the combined lapsed
+       and the lapsed headers.
+       (article-update-date-lapsed): Skip past all the X-Sent/Date headers.
+       (article-make-date-line): Limit the number of segments dynamically to
+       avoid too-long lines.
+
+2011-01-27  Julien Danjou  <julien@danjou.info>
+
+       * mml2015.el (mml2015-epg-sign): Add and use mml2015-sign-with-sender.
+       (mml2015-epg-encrypt): Use mml2015-sign-with-sender.
+
+2011-01-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el (shr-expand-newlines, shr-previous-newline-padding-width):
+       Use plist-get instead of the cl function getf.
+
+2011-01-27  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-util.el (float-time): Get rid of compiler warning, again.
+
+2011-01-27  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-put-color): Special-case background colors: Do put them
+       at the blank parts at the front of the lines.
+
+       * gnus-draft.el (gnus-draft-clear-marks): New function to be run as an
+       exit hook to nix out all data on readedness on group exit.
+
+       * gnus-util.el (float-time): If float-time is bound, always use it on
+       all Emacsen.  It's unclear why the subrp check was there.
+       (time-date): Require to make some autoload issues on XEmacs go away.
+
+       * shr.el (shr-put-color): Don't do the box padding in tables, since
+       they're already padded.
+
+2011-01-26  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-next-page): When the last line of the
+       article is displayed, scroll down once more instead of going to the
+       next article at once.
+       (article-lapsed-string): Refactor out and allow specifying how many
+       segments you want.
+       (gnus-article-setup-buffer): Start updating the lapsed header directly.
+       (gnus-article-update-lapsed-header): New variable.
+
+       * shr.el: Revert change that made headings use different-sized faces.
+       The Emacs display engine isn't advanced enough that, for instance,
+       tables can comfortably use differently-sized faces.
+
+2011-01-25  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-open-connection-1): Store the actual stream type
+       used.
+       (nnimap-login): Prefer plain LOGIN if it's enabled (since it requires
+       fewer round trips than CRAM-MD5, and it's less likely to be buggy), and
+       we're using an encrypted connection.
+
+       * proto-stream.el: Alter the interface functions to also return the
+       actual stream type used: network or tls.
+
+2011-01-25  Julien Danjou  <julien@danjou.info>
+
+       * mm-view.el (mm-display-shell-script-inline): Fix typo in docstring.
+       (mm-display-javascript-inline): New function.
+
+       * mm-decode.el (mm-inline-media-tests): Add application/javascript
+       viewing function.
+
+2011-01-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el (shr-expand-newlines): Fix variable name.
+
+2011-01-25  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-expand-newlines): Make nested boxes work.
+
+2011-01-24  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-expand-newlines): Proof of concept implementation of boxy
+       backgrounds.
+       (shr-expand-newlines): Switch to using overlays to enable kill'n'yank
+       in a more sensible manner.
+
+2011-01-24  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * mml-smime.el (mml-smime-use): Make it a defcustom and default to 'epg
+       if EPG is loaded.
+
+2011-01-24  Julien Danjou  <julien@danjou.info>
+
+       * shr.el: Use defface to create shr-tag-h[1-6] faces to fontify h[1-6]
+       tags.
+
+2011-01-24  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-read-summary-keys): Don't call disabled
+       commands.
+
+       * gnus-gravatar.el (gnus-gravatar-insert): Don't move point around
+       in the article buffer.
+       (gnus-gravatar-insert): Use blank space from the current buffer to
+       avoid breaking text properties.  This makes X-Sent updating work again.
+
+       * gravatar.el (gravatar-retrieve): Be silent when retrieving.
+
+2011-01-23  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-html.el (gnus-html-image-fetched): Kill the buffer anyway, and
+       fix the bug in url-http.el instead.
+
+       * shr.el (shr-image-fetched): Ditto.
+
+       * shr.el (shr-image-fetched): Avoid having point move in the article
+       buffer.
+
+       * gnus-html.el (gnus-html-image-fetched): Don't kill the temporary
+       buffer after being called.  It's apparently being killed by url.el, and
+       killing it made point move to end-of-buffer in a random buffer.
+
+       * shr.el (shr-image-fetched): Ditto.
+
+2011-01-23  Julien Danjou  <julien@danjou.info>
+
+       * mm-decode.el (mm-inline-media-tests): Change text/org to text/x-org.
+
+       * mm-uu.el (mm-uu-org-src-code-block-extract): Change text/org to
+       text/x-org.
+
+2011-01-22  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-move-article): Protect against backends
+       (i.e., nnimap) returning nil as the article number.
+
+2011-01-22  Kazuhiro Ito  <kzhr@d1.dion.ne.jp>  (tiny change)
+
+       * flow-fill.el (fill-flowed): Make `delete-space' option correspond to
+       "DelSp" parameter in RFC3676.
+
+2011-01-22  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-check-recipients): Display the encoded version of
+       the bogus address if they differ.
+
+       * gnus-draft.el (gnus-group-send-queue): Really refresh the queue group
+       after sending.
+
+       * gnus-agent.el (gnus-agent-send-mail): Ditto.
+
+       * gnus-group.el (gnus-group-refresh-group): New convenience function.
+
+       * gnus-draft.el (gnus-group-send-queue): Update the queue group in the
+       group buffer after sending the queue.
+
+       * gnus-agent.el (gnus-agent-send-mail): Ditto.
+
+2011-01-22  Julien Danjou  <julien@danjou.info>
+
+       * mailcap.el (mailcap-mime-extensions): Rename text/org to text/x-org.
+
+2011-01-22  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-preferred-alternative-precedence): Don't bug out on
+       nested related parts.
+
+       * nnfolder.el (nnfolder-request-expire-articles): Return the list of
+       unexpired articles.  This fixes the regression that led expiry marks to
+       disappear from nnfolder groups.
+
+2011-01-21  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-art.el (gnus-button-alist, gnus-button-handle-info-keystrokes):
+       Don't confuse the "ret" of "retrograde" with RET.
+
+2011-01-21  Julien Danjou  <julien@danjou.info>
+
+       * gnus-art.el (gnus-mime-display-single): Use mm-display-inline rather
+       than mm-insert-inline.
+
+2011-01-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-remove-images, gnus-article-show-images):
+       Widen article buffer.
+
+2011-01-20  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * mm-util.el (mm-find-buffer-file-coding-system): Don't forget to kill
+       the temp buffer.
+       * message.el (message-mailer-swallows-blank-line): Use with-temp-buffer.
+
+2011-01-20  Julien Danjou  <julien@danjou.info>
+
+       * mm-decode.el (mm-inline-media-tests): Add text/x-sh.
+
+       * gnus-art.el (gnus-mime-inline-part): Use mm-display-inline rather
+       than mm-insert-inline to insert inline part: this respect
+       mm-inline-media-tests displayers.
+
+       * mm-view.el (mm-display-shell-script-inline): New function.
+
+       * mm-decode.el (mm-inline-media-tests): Add x-shellscript and x-sh.
+
+       * mm-uu.el (mm-uu-type-alist): Add org block.
+       (mm-uu-org-src-code-block-extract): New function.
+
+       * mm-view.el (mm-display-org-inline): New function.
+
+       * mm-decode.el (mm-automatic-display): Add text/org.
+
+       * mailcap.el (mailcap-mime-extensions): Add .org.
+
+2011-01-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-highlight): Remove argument passed to
+       gnus-article-add-buttons.
+
+2011-01-19  Tom Rauchenwald  <sehnsucht.nach.unendlichkeit@quantentunnel.de>  (tiny change)
+
+       * spam.el (spam-spamassassin-register-with-sa-learn): Insert a full
+       From header with a date and "nobody" as the sender.
+
+2011-01-19  Julien Danjou  <julien@danjou.info>
+
+       * gnus-art.el (gnus-article-add-buttons): Simplify condition.
+       (gnus-button-push): Remove gnus-button-entry function, it fails heavily
+       if you have the same regexp several times.
+       (gnus-button-push): Fix matching when regexp is symbol.
+
+2011-01-15  Glenn Morris  <rgm@gnu.org>
+
+       * message.el (message-mail): A compose-mail function should
+       accept headers as strings.
+
+2011-01-13  Chong Yidong  <cyd@stupidchicken.com>
+
+       * message.el (message-tool-bar-gnome): Tweak tool-bar items.
+       Add :vert-only tags.
+       (message-mail): New arg RETURN-ACTION.
+       (message-return-action): New var.
+       (message-bury): Use it.
+       (message-mode): Make it buffer-local.
+       (message-send-and-exit): Always call message-bury.
+
+       * gnus-msg.el (gnus-msg-mail): New arg RETURN-ACTION.  Pass it to
+       message-mail.
+
+2011-01-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-convert-partial-article): Protect against
+       zero-length body parts.
+
+       * mm-decode.el (mm-preferred-alternative-precedence):
+       Discourage showing empty parts.
+
+       * gnus-int.el (gnus-request-accept-article): Don't try to update marks
+       and stuff if the backend didn't return the article number.  This fixes
+       an Exchange-related nnimap bug.
+
+       * gnus-sum.el (gnus-summary-next-article): Remove hack to reselect
+       group window, because it does the wrong thing when a separate frame
+       displays the group buffer.
+
+       * proto-stream.el (open-protocol-stream): Protect against the low-level
+       transport functions returning nil.
+
+2011-01-07  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el (epg-sub-key-fingerprint): Autoload.
+       (mml2015-epg-find-usable-secret-key): New function.
+       (mml2015-epg-sign): Use mml2015-epg-find-usable-secret-key instead of
+       mml2015-epg-find-usable-key (Bug#7797).
+       (mml2015-epg-encrypt): Ditto.
+
+2011-01-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (rot13-string): Fix the way to get the argument.
+
+2011-01-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * flow-fill.el (fill-flowed-encode): Do encoding citation-aware.
+
+2011-01-03  Glenn Morris  <rgm@gnu.org>
+
+       * sieve-manage.el (sieve-manage-open): Correctly set sieve-manage-port.
+
+       * sieve.el (sieve-open-server): Give a more explicit error if
+       sieve-manage-open returns nil.  (Bug#7720)
+
+2011-01-02  Karl Fogel  <kfogel@red-bean.com>
+
+       * gnus-msg.el (gnus-message-replyencrypt): Default to `t'.
+
+2011-01-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-login): Prefer AUTH=CRAM-MD5, if it's available.
+       This avoids sending passwords in plain text over non-encrypted
+       channels.
+
+       * shr.el (shr-rescale-image): Display all GIF images as animated images.
+
+       * nnimap.el (nnimap-login): Refactored out into own function, and
+       implement CRAM-MD5.
+       (nnimap-wait-for-line): Refactored out.
+
+       * mm-view.el (mml-smime): Require.
+
+2010-12-20  David Engster  <deng@eml.cc>
+
+       * mm-view.el (mm-view-pkcs7-decrypt): If mml-smime-use is set to 'epg,
+       use EPG to decrypt S/MIME messages instead of openssl.
+
+2011-01-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-request-group): Avoid double SELECT on `M-g'.
+
+       * gnus-group.el (gnus-group-kill-group): Don't try to update the group
+       status is the group clearly is unreachable.
+
+       * auth-source.el (auth-source-create): Add the optional second
+       parameter to `local-variable-p' to be compatible with XEmacs.
+
+2011-01-02  Wang Diancheng  <dcwang@kingbase.com.cn>  (tiny change)
+
+       * nnml.el (nnml-request-article): Allow requesting by Message-ID to
+       work when using a compressed nnml folder.
+
+2011-01-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-select-newsgroup): Don't propagate marks to
+       backends after sanitising on entry, because this never makes sense:
+       If the articles have gone missing, then the data no longer exists on
+       the backend, and if they haven't, then Gnus is wrong, and shouldn't
+       overwrite anything anyway.
+
+       * shr.el (shr-insert-document): Bind shr-width dynamically to
+       window-width if it's nil.
+
+2010-12-30  Tassilo Horn  <tassilo@member.fsf.org>
+
+       * shr.el (shr-width, shr-insert-document): Allow nil as shr-width value
+       with the meaning of using the full emacs window width for rendering.
+
+2010-12-27  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el (mml2015-epg-sign, mml2015-epg-encrypt): Take care the
+       case when sender is not given.
+
+2010-12-23  Julien Danjou  <julien@danjou.info>
+
+       * gnus-gravatar.el (gnus-gravatar-transform-address): Set
+       `mail-extr-ignore-realname-equals-mailbox-name' to nil when extracting
+       the addresses, otherwise we might misplaced the gravatar.
+
+2010-12-21  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml1991.el (pgg-sign-region, pgg-encrypt-region):
+       * gnus-art.el (pgg-snarf-keys-region): Autoload since PGG is now
+       obsolete in Emacs.
+
+2010-12-20  Julien Danjou  <julien@danjou.info>
+
+       * gnus-util.el (gnus-rescale-image): Revert last change.
+
+2010-12-17  Chong Yidong  <cyd@stupidchicken.com>
+
+       * binhex.el: Improve commentary (Bug#7482).
+
+2010-12-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-delete-articles): New command.
+
+2010-12-17  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-mode): Make sure 'gnus-registry-install is bound.
+
+2010-12-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-get-newsgroup-headers): Revert the last change
+       here, since it's up to the backends to do CRLF removal if their
+       protocol has it.
+
+       * nnimap.el (nnimap-retrieve-headers): Remove CRLF from the headers.
+
+2010-12-17  Julien Danjou  <julien@danjou.info>
+
+       * gnus-util.el (gnus-rescale-image): Allow to resize images even if
+       they are from file.  Can also scale up.
+
+2010-12-17  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * gnus-sum.el (gnus-summary-refer-thread): Simplify code.
+       Restore gnus-use-agent.
+       (gnus-get-newsgroup-headers): Avoid unwanted spaces at eol.
+
+       * nnir.el (nnir-get-active): Ignore nnir-ignored-newsgroups if null.
+
+2010-12-17  Julien Danjou  <julien@danjou.info>
+
+       * gravatar.el (gravatar-retrieve-synchronously): New function.
+       (gravatar-get-data): Make more robust.
+
+2010-12-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Bind epa-file-encrypt-to for Emacs 22 and XEmacs.
+
+2010-12-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-wait-for-response): Fix the end-point calculation
+       to really consider the last line.
+
+2010-12-16  Daiki Ueno  <ueno@unixuser.org>
+
+       * auth-source.el (auth-source-gpg-encrypt-to): New variable to set the
+       list of recipient keys, or use symmetric encryption if not a list.
+       (auth-source-create): Use it to make `epa-file-encrypt-to' local for an
+       EPA override, replacing the call to `netrc-store-data'.
+
+2010-12-16  Dan Davison  <dandavison7@gmail.com>  (tiny change)
+
+       * gnus-srvr.el: Avoid passing nil regexp argument to
+       delete-matching-lines.
+
+2010-12-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-html.el (gnus-html-schedule-image-fetching): Make sure the HTML
+       fetching stops when Gnus exits.
+
+       * nnfolder.el (nnfolder-save-all-buffers): Refactor out into its own
+       function.
+       (nnfolder-request-expire-articles): Save all the buffers after doing
+       expiry.
+
+       * nnmail.el (nnmail-expiry-target-group): Revert the "all articles are
+       the last article", since that led to serious performance regressions
+       when expiring nnml groups.
+
+2010-12-16  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el: Improve customizations.
+
+2010-12-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-subscribe-newsgroup): Notify the backend.
+
+       * gnus-group.el (gnus-group-kill-group): Notify the backend that the
+       group has been killed.
+       (gnus-group-yank-group): Ditto.
+
+       * gnus-srvr.el (gnus-browse-unsubscribe-group): Ditto.
+
+       * nnimap.el (nnimap-request-update-group-status): New function.
+
+       * gnus-int.el (gnus-request-update-group-status): New interface
+       function.
+
+       * gnus-sum.el (gnus-summary-push-marks-to-backend): Fix the logic for
+       copying read-ness to the backends.
+
+       * nnimap.el (nnimap-quirk): New function.
+       (nnimap-retrieve-group-data-early): Use it.
+       (nnimap-quirks): New alist.
+
+2010-12-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el (shr-insert): Set shr-start after deleting trailing space;
+       don't delete it within indentation.
+
+2010-12-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-wait-for-response): Always look (at least) at the
+       previous line.
+
+2010-12-15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-retrieve-group-data-early): Fix the syntax of the
+       QRESYNC command by deleting a superfluous space which broke Cyrus
+       servers.  This change will break other servers that are buggy the other
+       way around.
+
+2010-12-14  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el: Reindent and fix long lines.
+       (spam-copy-or-move-routine): Exclude invalid move destinations.
+
+2010-12-14  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-mode): Don't install registry hooks if user hasn't
+       installed the registry.
+
+2010-12-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (rot13-string): New macro for XEmacs.  netrc.el uses it.
+
+2010-12-13  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-run-gmane): Better check for gmane groups: error out if
+       groupname doesn't contain "gmane".
+
+2010-12-13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * netrc.el (netrc-point-at-eol): Remove the unused netrc-point-at-old
+       and netrc-bound-and-true-p bindings.
+       (netrc-parse): Cache the netrc contents.
+
+       * gnus-start.el (gnus-matches-options-n): Fix typo in last change.
+       (gnus-1): Don't create the nndrafts group twice.
+       (gnus-setup-news): There's no need to read the active file here, since
+       that's done again later on a per-backend basis.
+       (gnus-start-draft-setup): Make sure that the new group is started out
+       empty.
+
+       * gnus-agent.el (gnus-agentize): Don't create the queue group
+       automatically on startup.  It'll be created later, if needed.
+
+       * gnus-start.el (gnus-auto-subscribed-groups): Add nnimap to the list
+       of automatically subscribed groups.
+       (gnus-auto-subscribed-categories): New variable.
+       (gnus-matches-options-n): Use it.
+       (gnus-default-subscribed-newsgroups): Remove unused variable.
+       (gnus-start-draft-setup): Message a bit less.
+
+2010-12-13  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-run-imap): Return article list in order of increasing
+       UID.
+
+2010-12-13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-enter-digest-group):
+       Mention gnus-auto-select-on-ephemeral-exit.
+
+       * proto-stream.el (proto-stream-open-network-only): Fix the calling
+       convention of the network-only option.
+
+2010-12-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * proto-stream.el (proto-stream-open-network-only): New function to
+       have a way to specify non-STARTTLS upgrade connections.
+
+2010-12-10  Julien Danjou  <julien@danjou.info>
+
+       * gnus-gravatar.el (gnus-gravatar-transform-address): Fix error when
+       email address is nil.
+
+       * message.el (message-bogus-recipient-p): Set address to "" if nil.
+
+2010-12-10  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-request-expire-articles): Ignore expiry except for
+       deletion.
+       (nnir-run-imap): Only need to parse list once.
+
+2010-12-09  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-tag-script): Ignore <script>.
+       (shr-tag-label): Add <label> support.
+
+2010-12-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-ucs-to-char): Use eval-and-compile.
+
+       * shr.el (shr-image-displayer): Work for images lined side by side.
+
+2010-12-08  Robert Pluim  <rpluim@gmail.com>
+
+       * gnus-demon.el (gnus-demon-init): Call run-with-timer with an integer
+       parameter, since XEmacs doesn't accept t as a parameter.
+
+2010-12-08  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-retrieve-headers): Use rassq when comparing article
+       ids.
+       (nnir-run-gmane): Simplify groupspec formatting.
+       (nnir-request-expire-articles): New function.
+
+2010-12-07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-parse-flags): Tweak VANISHED regexp to avoid regexp
+       overflow, possibly.
+
+       * shr.el (shr-tag-table-1): Use bg/gfcolor specs on tables.
+       (shr-render-td): Handle td style="" better.
+       (shr-tag-table): Use the color from the style sheet.
+       (shr-render-td): Make sure we copy over all the overlays, too.
+
+2010-12-07  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-run-gmane): Restore sub-optimal test for gmane server.
+       (nnir-request-article): Improve article retrieval.
+
+2010-12-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-extra-numeric-entities): New variable.
+
+       * mm-url.el (mm-url-decode-entities):
+       * mm-decode.el (mm-shr): Use it to decode extra numeric entities.
+
+       * lpath.el: Fbind completion-at-point for Emacs 22 and XEmacs.
+
+2010-12-07  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * message.el: Use completion-at-point.
+       (message-completion-function): New fun, extracted from message-tab.
+       (message-mode): Use it for completion-at-point-functions.
+       (message-tab): Use it and completion-at-point.
+
+2010-12-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el (shr-find-fill-point): Don't break a line after a kinsoku-bol
+       character if a non-breakable character follows.
+
+2010-12-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * proto-stream.el (proto-stream-open-tls): Return nil if we don't get
+       any stream.
+
+       * shr.el (shr-tag-font): Colorize the region.
+       (shr-tag-body): Ditto.
+       (shr-tag-font): Actually let the styles be inherited instead of
+       overwriting them.
+       (shr-tag-font): Get the background color right.
+       (shr-tag-style): Ignore all <style> tags for the moment.
+
+       * gnus-int.el (gnus-request-thread): Rework to take a header instead of
+       a Message-ID to avoid having nnimap depend on gnus-sum.
+
+       * shr.el (shr-descend): Only colorize something if we have a node that
+       sets colors.
+
+2010-12-06  Julien Danjou  <julien@danjou.info>
+
+       * shr.el (shr-render-td): Render td content with shr-descend, so style
+       will be applied to <td> too.
+       (shr-colorize-region): Colorize region even if we only have a background.
+       (shr-tag-body): Fix color and background color inheritance.
+       Do not recolorize after shr-generic.
+       (shr-tag-font): Let shr-generic colorize via inheritance.
+
+2010-12-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el (shr-find-fill-point): Don't regard apostrophe as kinsoku-bol.
+
+2010-12-06  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-request-move-article): Remove obsolete code.
+
+2010-12-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-macroexpand-all): Use eval-and-compile.
+
+2010-12-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-respool-article): The completion function
+       expects a list instead of an alist.
+
+       * nntp.el (nntp-snarf-error-message): nnheader-report takes a format
+       string as the parameter.
+
+       * gnus.el (gnus-valid-select-methods): Allow nnimap to respool.
+
+       * shr.el (shr-stylesheet): New dynamic variable for cascading the
+       styles.
+       (shr-colorize-region): New function.
+       (shr-insert-background-overlay): Remove.
+       (shr-render-td): Background setting should be taken care of on a higher
+       level.
+       (shr-tag-body): Use post-hoc colorizations.
+       (shr-tag-body): Set up a style sheet based on bgcolor/fgcolor.
+       (shr-put-color-1): Don't overwrite old colors.
+       (shr-colorize-region): When the background color isn't explicit, use
+       a fixed background.
+
+       * gnus-util.el (gnus-output-to-mail): Require nnmail before using
+       nnmail variables.
+
+2010-12-05  Bjørn Mork  <bjorn@mork.no>
+
+       * nnimap.el (nnimap-process-expiry-targets): Avoid downloading articles
+       unless necessary.
+
+2010-12-05  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-run-gmane): Use more careful test for gmane nntp
+       server.
+
+2010-12-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-html.el (gnus-html-put-image): Use widget instead of local maps
+       so that TAB works.
+
+       * gnus-sum.el (gnus-summary-show-article): Reverse the meanings of `C-u
+       C-u g' and `C-u g' so that `C-u g' does what it traditionally did.
+
+       * shr.el (shr-urlify): Show the URL before the title to avoid
+       misleading URLs.
+
+2010-12-04  Adam Sjøgren  <asjo@koldfront.dk>
+
+       * shr.el (shr-urlify): Display the title in <a> tags.
+
+2010-12-04  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-categorize): Replace mapcar with mapc.
+
+2010-12-03  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el: Rearrange code to allow macros to be autoloaded by
+       gnus-sum.el.
+       (nnir-retrieve-headers-override-function): Make this variable
+       customizable.
+       (nnir-retrieve-headers): Remove obsolete subject-mangling code.
+
+       * gnus-sum.el (nnir-article-group, nnir-article-rsv): Autoload macros
+       from nnir.el.
+
+2010-12-03  Julien Danjou  <julien@danjou.info>
+
+       * gnus-demon.el (gnus-demon-init): Fix time computing when time is nil.
+
+2010-12-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-macroexpand-all): Don't modify argument;
+       allow optional argument `environment'.
+
+2010-12-03  Glenn Morris  <rgm@gnu.org>
+
+       * mm-extern.el (message-goto-body): Update declaration.
+
+2010-12-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-macroexpand-all): New function.
+
+       * gnus-sum.el (gnus-summary-line-format-alist): Use gnus-macroexpand-all
+       instead of macroexpand-all that is unavailable in XEmacs.
+
+2010-12-02  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-summary-line-format): New variable.
+       (nnir-mode): Use it.
+       (nnir-artlist-*, nnir-aritem-*): Reimplement as macros.
+       (nnir-article-ids): Reimplement as defsubst.
+       (nnir-retrieve-headers): Don't mangle the subject header.
+       (nnir-run-imap): Use 100 as RSV score.
+       (nnir-run-find-grep): Fix for full server searching.
+       (nnir-run-gmane): Better restriction to gmane groups.
+
+       * gnus-sum.el (gnus-summary-line-format-alist): Add specs for nnir
+       summary buffers.
+
+2010-12-02  Julien Danjou  <julien@danjou.info>
+
+       * gnus-win.el (gnus-configure-frame): Remove old compatibility code.
+
+       * gnus-msg.el: Mark gnus-outgoing-message-group as obsolete.
+
+       * gnus-win.el (gnus-configure-windows): Remove Gnus 3.x setting
+       support.
+
+2010-12-01  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el: Update to handle the registry better.
+       (autoload): Silence byte-compiler.
+       (nnir-open-server): Add a hook for nnir groups.
+       (nnir-request-move-article): Don't mangle the header.  Better to use
+       formatting variables (which will be added in the future).
+       (nnir-registry-action): Update the registry using the original article
+       group name.
+       (nnir-mode): Install nnir-specific hooks for updating the registry.
+
+       * gnus-sum.el
+       (gnus-article-original-subject, gnus-newsgroup-original-name):
+       Remove obsolete variables.
+       (gnus-summary-move-article): Remove use of obsolete variables.
+       (gnus-summary-local-variables): Make move and delete hooks local to
+       summary buffers.
+
+2010-12-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * rtree.el: New file.
+
+2010-12-01  Julien Danjou  <julien@danjou.info>
+
+       * message.el (message-user-organization): Do not use
+       gnus-local-organization.
+
+       * gnus.el: Remove gnus-local-organization.
+
+       * gnus-msg.el: Remove nastygram thing.
+
+2010-12-01  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * nnmaildir.el (nnmaildir-request-set-mark): Add article to add-mark
+       funcall.
+
+2010-12-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-gravatar.el (gnus-gravatar-insert): Allow LWSP in the middle of
+       names.
+
+       * shr.el (shr-find-fill-point): Don't break line between kinsoku-bol
+       characters.
+
+       * gnus-gravatar.el (gnus-gravatar-insert): Delete unnecessary binding
+       to t of inhibit-read-only since it is inside gnus-with-article-headers.
+       Suggested by Štěpán Němec <stepnem@gmail.com>.
+       (gnus-gravatar-transform-address): Use mail-extract-address-components
+       that supports non-ASCII names rather than mail-header-parse-addresses.
+
+2010-11-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * proto-stream.el (open-protocol-stream): All starttls connections are
+       handled by the network handler.
+
+2010-11-30  Julien Danjou  <julien@danjou.info>
+
+       * nnimap.el (nnimap-open-connection-1): Use gnus-string-match-p.
+       (nnimap-open-connection-1): Fix PREAUTH.
+
+       * gnus-gravatar.el (gnus-gravatar-size): Set gnus-gravatar-size to nil.
+
+2010-11-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el (shr-char-breakable-p, shr-char-nospace-p)
+       (shr-char-kinsoku-bol-p, shr-char-kinsoku-eol-p): New macros.
+       (shr-insert): Use them.
+       (shr-find-fill-point): Work better for kinsoku chars and apostrophes.
+
+2010-11-29  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-request-move-article): Bail out if original group
+       doesn't support article moves.
+       (nnir-get-active): Improve active list retrieval.
+
+2010-11-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-find-fill-point): Don't break before apostrophes.
+
+2010-11-29  Binjo  <binjo.cn@gmail.com>  (tiny change)
+
+       * nnimap.el (nnimap-open-connection-1): w32 open-network-stream doesn't
+       seem to accept strings-with-numbers as port numbers.
+
+2010-11-29  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * gnus-sum.el (gnus-summary-delete-article): If delete fails don't
+       change the registry.
+
+2010-11-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnir.el (nnir-run-gmane): Use mm-delete-duplicates instead of
+       delete-dups that is not available in XEmacs 21.4.
+
+       * mm-util.el (mm-delete-duplicates): Add comment.
+
+2010-11-28  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-ignored-newsgroups): New variable.
+       (nnir-get-active): Use it.
+
+2010-11-28  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * proto-stream.el (proto-stream-open-network): Add some comments.
+
+       * nntp.el (nntp-open-connection): Provide a :success condition.
+
+       * nnimap.el (nnimap-open-connection-1): Ditto.
+
+       * proto-stream.el (proto-stream-open-network): See what the response to
+       the STARTTLS command is.
+
+       * nnimap.el (nnimap-open-connection-1): Always upgrade to STARTTLS (for
+       backwards compatibility).
+       (nnimap-open-connection-1): Really respect nnimap-server-port.
+
+       * proto-stream.el (proto-stream-open-network): When doing opportunistic
+       TLS upgrades we don't really care about the identity of the peer.
+       (proto-stream-open-network): Force starttls.el to use gnutls-cli, since
+       that what we've checked for.
+       (proto-stream-always-use-starttls): Only default to t if
+       open-gnutls-stream exists.
+       (proto-stream-open-network): If STARTTLS failed, then just open a
+       normal connection.
+       (proto-stream-open-network): Wait until the greeting before doing
+       STARTTLS.
+
+       * nntp.el (nntp-open-connection): Report what the connection error is.
+
+       * proto-stream.el (open-protocol-stream): Rename from
+       open-proto-stream.
+
+2010-11-27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-stream): Change default to `undecided'.
+       (nnimap-open-connection): If `nnimap-stream' is `undecided', try ssl
+       first, and then network.
+       (nnimap-open-connection-1): Respect nnimap-server-port.
+       (nnimap-open-connection): Be more backwards-compatible.
+
+       * proto-stream.el (proto-stream-always-use-starttls): New variable.
+       (proto-stream-open-starttls): De-duplicate the starttls code.
+       (proto-stream-open-starttls): Folded back into the main function.
+       (proto-stream-open-network): Fix typo in the gnutls path.
+       (proto-stream-command): Refactor out.
+
+       * nntp.el (nntp-open-connection): Fix the STARTTLS command syntax.
+
+       * proto-stream.el (proto-stream-open-starttls): Actually implement the
+       starttls.el STARTTLS.
+
+       * color.el (color-lab->srgb): Fix function call name.
+
+       * proto-stream.el (proto-stream-open-tls): Delete output from openssl
+       if we're using tls.el.
+       (proto-stream-open-network): If we don't have gnutls-cli or gnutls
+       built in, then don't try to establish a STARTTLS connection.
+
+       * nntp.el (nntp-open-connection): Switch on STARTTLS on supported
+       servers.
+
+       * proto-stream.el (open-proto-stream): Use network, not stream.
+       (open-proto-stream): Add a way to specify what the end of a command is.
+
+       * nntp.el (nntp-open-connection): Use proto-streams for the relevant
+       connections types.
+       (nntp-open-network-stream): Remove.
+       (nntp-open-ssl-stream): Remove.
+       (nntp-open-tls-stream): Remove.
+       (nntp-ssl-program): Remove.
+
+       * nnimap.el (nnimap-open-connection): Check for "OK" from the greeting.
+
+2010-11-27  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el: Fix typos.
+       (nnir-retrieve-headers-override-function): Rename variable to reflect
+       new semantics.
+       (nnir-article-group, nnir-article-number, nnir-article-rsv): New helper
+       macros.
+       (nnir-request-article, nnir-request-move-article): Use them.
+       (nnir-categorize): New function.
+       (nnir-run-query): Use it.
+       (nnir-retrieve-headers): Rewrite to batch header retrieval.
+       (nnir-run-gmane): nnir-retrieve-headers now returns the headers already
+       sorted.
+       (nnir-group-full-name): Use gnus-group-full-name instead.
+       (nnir-artlist-artitem-group, nnir-artlist-artitem-number)
+       (nnir-artlist-artitem-rsv, nnir-sort-groups-by-server): Obsolete.
+
+2010-11-27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-open-connection): Fix typo in STARTTLS command.
+
+       * proto-stream.el: New library to provide protocol-specific
+       TLS/STARTTLS connections for IMAP, NNTP, SMTP, POP3 and similar
+       protocols.
+       (open-proto-stream): Complete the documentation.
+       (proto-stream-open-network): Fix some typos.
+
+       * nnimap.el (nnimap-open-connection): Use it.
+
+2010-11-27  Yuri Karaban  <tech@askold.net>  (tiny change)
+
+       * pop3.el (pop3-open-server): Read server greeting before starting TLS
+       negotiation.
+
+2010-11-26  Julien Danjou  <julien@danjou.info>
+
+       * color.el: Rename various rgb functions to srgb.
+
+2010-11-26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-get-groups): Allow non-quoted strings as mailbox
+       names.
+
+2010-11-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el (shr-insert): Revert last change.
+       (shr-find-fill-point): Never leave point being at bol;
+       relax the kinsoku limitation when rendering tables.
+
+2010-11-26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnmail.el (nnmail-expiry-target-group): Protect against degenerate
+       results from -accept-article.
+
+       * shr-color.el: Require cl when compiling.
+
+       * nnheader.el (nnheader-update-marks-actions): Fix typo in last
+       checkin.
+
+       * gnus-art.el (gnus-url-mailto): Unfold URLs before using them.
+
+       * nnimap.el (nnimap-request-set-mark): Add is "+", not "-".
+
+       * gnus-sum.el (gnus-summary-push-marks-to-backend): Use 'set instead of
+       'add and 'delete to set backend marks.
+
+       * nnmaildir.el (nnmaildir-request-set-mark): Be explicit about 'set.
+
+       * nnheader.el (nnheader-update-marks-actions): Refactor out.
+
+       * nntp.el (nntp-request-set-mark): Use it.
+
+       * nnfolder.el (nnfolder-request-set-mark): Ditto.
+
+       * nnml.el (nnml-request-set-mark): Ditto.
+
+       * nnimap.el (nnimap-last-response-string): Remove the unfolding -- it
+       introduces regressions in article selection.
+       (nnimap-find-uid-response): New function.
+       (nnimap-request-accept-article): Use the UID returned, if any.
+       (nnimap-request-move-article): Use the UID returned, if any.
+       (nnimap-get-groups): Reimplement to work with folded lines.
+       (nnimap-find-uid-response): The UID is the last element in the list.
+       (nnimap-request-set-mark): Extend syntax with 'set.
+
+       * nnml.el (nnml-request-set-mark): Ditto.
+
+       * nnfolder.el (nnfolder-request-set-mark): Ditto.
+
+       * nntp.el (nntp-request-set-mark): Ditto.
+
+2010-11-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-called-interactively-p): A temporary macro.
+       (message-goto-body): Use it temporarily.
+
+2010-11-25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-unfold-quoted-lines): Refactor out.
+       (nnimap-last-response-string): Unfold quoted lines, if they exist.
+       (nnimap-last-response-string): Fix last unfolding fix.
+
+2010-11-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el (shr-insert): Fix the way to fold lines.
+
+2010-11-25  Julien Danjou  <julien@danjou.info>
+
+       * shr-color.el (shr-color->hexadecimal): Use color-rgb->hex.
+
+       * color.el: Rename from color-lab.el
+       (color-rgb->hex): Add.
+       (color-complement): Add.
+       (color-complement-hex): Add.
+
+       * gnus-sum.el (gnus-summary-widget-forward): Add, and bind to [tab].
+
+2010-11-25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr-color.el (shr-color-visible): Don't bug out if the color names
+       don't exist.
+
+2010-11-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml.el (mml-preview): Make sure to bind gnus-displaying-mime to nil,
+       assuming that article displaying or another mml-preview may be
+       interrupted for an error or for the like.
+
+       * shr.el (shr-get-background): Fix argument name.
+
+2010-11-24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-cache.el (gnus-summary-insert-cached-articles): Use it.
+
+       * gnus-sum.el (gnus-summary-include-articles): New function.
+
+       * message.el (message-goto-body): called-interactively-p needs a
+       parameter, so use `any'.
+
+       * nnimap.el (nnimap-request-move-article): It's no longer necessary to
+       clear marks before moving, since they're synced from the Gnus side
+       first.
+
+       * gnus-sum.el (gnus-summary-push-marks-to-backend): New function.
+       (gnus-summary-move-article): Copy over all marks before moving, so that
+       IMAP doesn't think a new article has arrived.
+
+2010-11-24  Julien Danjou  <julien@danjou.info>
+
+       * shr.el (shr-insert-background-overlay): Fix typo.
+       (shr-render-td): Copy the background before rendering.
+
+       * shr-color.el (shr-color-visible): Fix docstring.
+
+       * shr.el (shr-tag-table): Add bgcolor support.
+       (shr-render-td): Add bgcolor support.
+       (shr-get-background): Add.
+       (shr-insert-foreground-overlay): Use shr-get-background.
+
+       * message.el (message-goto-body): Use called-interactively-p.
+       (message-in-body-p): message-goto-body returns point.
+
+2010-11-24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-util.el (mm-enable-multibyte): Use `to' instead of t.  This fixes
+       Fixes something or other in Emacs 23, and is backwards compatible.
+
+       * message.el (message-goto-body): Remove the <#secure special-casing,
+       which is too special.
+
+       * shr.el (shr-parse-style): Drop !important from styles.
+
+2010-11-24  Daniel Schoepe  <daniel.schoepe@googlemail.com>  (tiny change)
+
+       * gnus-sum.el (gnus-summary-articles-in-thread): Fix a bug that causes
+       this function to return incorrect results when calling it with an
+       explicit article argument different from
+       (gnus-summary-article-number).
+
+2010-11-24  Julien Danjou  <julien@danjou.info>
+
+       * shr.el (shr-insert-color-overlay): Replace deprecated syntax.
+       (shr-tag-body): Add background support.
+       (shr-descend): Add background support.
+       (shr-tag-title): Add.
+
+       * shr-color.el (shr-color-visible): Really return original background
+       if fixed.
+
+2010-11-24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-color-check): Protect against non-existent color names.
+
+2010-11-24  Julien Danjou  <julien@danjou.info>
+
+       * color-lab.el: Require 'cl when compiling.
+
+       * shr.el (shr-insert-color-overlay): Remove specific rgb() check.
+
+       * shr-color.el (shr-color->hexadecimal): Only return the hexadecimal
+       matched part.
+
+       * color-lab.el: Fix all expt calls to use float type.
+
+2010-11-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el (shr-insert-color-overlay): Pass rgb(rrr, ggg, bbb) type color
+       expression to shr-color-check as is.
+
+       * shr-color.el (shr-color->hexadecimal): Ignore case of color names.
+
+       * color-lab.el: Add coding cookie.
+       (float-pi): Use eval-and-compile.
+
+       * dgnushack.el (dgnushack-compile): Exclude shr-color.el from being
+       compiled for Emacsen having no `libxml-parse-html-region' support.
+
+2010-11-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-insert-color-overlay): Split stuff like
+       "#444444 !important" to find the real color.
+       (shr-tag-font): Resurrect shr-tag-font again, since it's needed to
+       parse <font color="red"> entries.
+
+2010-11-23  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnheader.el (nnheader-parse-head): Bug fix.  Properly position
+       point when parsing headers.
+
+       * nnspool.el (nnspool-insert-nov-head): Bug fix.  Make sure point
+       is positioned properly when parsing headers.
+
+2010-11-23  Julien Danjou  <julien@danjou.info>
+
+       * color-lab.el (boundp): Bind float-pi for Emacs < 23.3.
+
+       * shr-color.el (shr-color->hexadecimal): Add support for color names.
+
+       * shr.el (shr-parse-style): Replace \n with space in style parsing.
+
+       * shr-color.el (shr-color-hsl-to-rgb-fractions):
+       Use shr-color-hue-to-rgb.
+       (shr-color->hexadecimal): Call shr-color-hsl-to-rgb-fractions.
+
+2010-11-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-color->hexadecimal): Autoload.
+       (shr-descend): Add color to all tags.
+
+2010-11-22  Julien Danjou  <julien@danjou.info>
+
+       * shr.el (shr-tag-color-check): Convert colors to hexadecimal with
+       shr-color->hexadecimal.
+
+       * shr-color.el (shr-color->hexadecimal): Add converting functions for
+       RGB() or HSL() color representation.
+
+       * shr.el (shr-tag-font): Add.
+       (shr-tag-color-check): New function to get better colors.
+       (shr-tag-insert-color-overlay): Factorize code between tag-font and
+       tag-span.
+
+       * shr-color.el: New file.
+
+       * color-lab.el: New file.
+
+       * gnus-art.el (gnus-url-mailto): Do not downcase args.
+
+2010-11-21  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el: Fix typo in comments.
+       (nnir-run-imap): Simplify code.  No need to reverse artlist.
+       (nnir-run-gmane): Use nnir-tmp-buffer for web results.
+
+2010-11-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-srvr.el (gnus-server-show-server): New command and keystroke.
+
+       * nnimap.el (nnimap-get-capabilities): Refactor out.
+       (nnimap-open-connection): Re-request capabilities after STARTTLS.
+
+2010-11-21  Ralf Angeli  <angeli@caeruleus.net>
+
+       * mm-uu.el (mm-uu-type-alist): Prevent spurious empty line from
+       appearing when `mm-uu-hide-markers' is nil.
+
+2010-11-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-unselect-group): Make into its own function.
+       (nnimap-request-rename-group): Unselect group before renaming.
+       This had gotten lost somewhere.
+       (nnimap-request-accept-article): Keep track of examined groups, and
+       unselect the group before APPENDing to read-only groups.
+       (nnimap-request-move-article): Clear flags before moving so that they
+       can be re-set later.
+
+2010-11-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-gravatar.el (gnus-gravatar-transform-address): Decode name again.
+       (gnus-gravatar-insert): Put avatar always in the beginning of the field.
+
+2010-11-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-display-single):
+       * gnus-html.el (gnus-html-wash-images, gnus-html-prefetch-images):
+       * mm-decode.el (mm-shr): Assume that gnus-inhibit-images may be a group
+       parameter.
+
+2010-11-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-table-horizontal-line): Rename from shr-table-line.
+       (shr-table-vertical-line): New variable.
+       (shr-insert-table): Use it.
+
+2010-11-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-html.el (gnus-html-wash-images): Don't display images if
+       gnus-inhibit-images is non-nil; register displayer for cid images.
+       (gnus-html-display-image): Work for cid image.
+       (gnus-html-insert-image): Allow arguments.
+       (gnus-html-put-image): Inhibit read-only.
+       (gnus-html-prefetch-images): Don't prefetch images if
+       gnus-inhibit-images is non-nil.
+
+2010-11-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-put-image): Break lines when inserting big pictures.
+
+2010-11-17  Daniel Dehennin  <daniel.dehennin@baby-gnu.org>
+
+       * mml2015.el (mml2015-epg-encrypt): Fix two cons with missing
+       sender, thanks Katsumi Yamaoka.
+
+2010-11-17  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-run-imap): Reverse the article list for each group
+       rather than the whole list.
+
+2010-11-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el (shr-image-displayer): Protect function against non-existent
+       image source.
+
+       * gnus-art.el (gnus-inhibit-images): New user option.
+       (gnus-mime-display-single): Don't display image if it is non-nil.
+
+       * mm-decode.el (mm-shr): Bind shr-inhibit-images to the value of
+       gnus-inhibit-images.
+
+       * shr.el (shr-image-displayer): New function.
+       (shr-tag-img): Use it.
+
+2010-11-16  Daniel Dehennin  <daniel.dehennin@baby-gnu.org>
+
+       * mml2015.el (mml2015-epg-sign): Use From header.
+
+2010-11-15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-html.el (gnus-html-wash-images): Register a displayer.
+
+       * gnus-util.el (gnus-find-text-property-region): Return markers.
+
+       * shr.el (shr-tag-img): Put a displayer in the text property.
+
+       * gnus-util.el (gnus-find-text-property-region): New utility function.
+
+       * gnus-html.el (gnus-html-display-image): Make the alt optional.
+       (gnus-html-show-images): Remove.
+
+       * gnus-art.el (gnus-article-show-images): New, more general function.
+
+       * gnus-html.el: Use image-url instead of gnus-image-url to unify the
+       image url text properties.
+
+       * shr.el: Ditto.
+
+       * gnus-agent.el (gnus-agentize): Only do the auto-agentizing if
+       gnus-agent-auto-agentize-methods is set.  Which it isn't.
+
+2010-11-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-move-article): Fix `while' loop to make it
+       work for two or more articles.
+
+2010-11-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-treat-non-ascii): Keep text properties not to
+       divide an image that's in an html article to two or more when washing
+       non-ASCII characters in alt text of it.
+
+2010-11-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-dissect-buffer): Pass sender's mail address to
+       smime-decrypt-region using function argument.
+       (mm-possibly-verify-or-decrypt, mm-dissect-multipart): Relay it.
+
+       * mm-view.el (mm-view-pkcs7, mm-view-pkcs7-decrypt): Relay it.
+
+       * smime.el (smime-decrypt-region): Catch it.
+
+2010-11-11  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * smime.el (smime-mode-map): Move initialization into declaration.
+       (gnus-run-mode-hooks): Don't autoload.
+       (smime-mode): Use define-derived-mode.
+
+2010-11-11  Glenn Morris  <rgm@gnu.org>
+
+       * smime.el (from): Restrict declaration to XEmacs.
+
+       * nnir.el (gnus-group-topic-name): Autoload.
+
+2010-11-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el (shr-insert): Don't break long line if it is because of
+       kinsoku-bol characters in the line end.
+
+2010-11-11  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-request-move-article): Fix to provide original group
+       and subject.
+       (nnir-warp-to-article): Don't fail on articles whose headers haven't
+       been retrieved.
+
+       * gnus-sum.el (gnus-summary-move-article): Use original group and
+       subject for virtual articles such as those in an nnir summary buffer.
+
+2010-11-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-treat-non-ascii): Make it work for XEmacs (at
+       least 21.5).
+
+       * smime.el (from): Declare it again for XEmacs.
+
+2010-11-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-resend): Don't disable encoding unless it's
+       already encoded.
+
+       * nnimap.el (nnimap-update-info): Fix problem with `g' chopping of
+       low-numbered articles.
+
+2010-11-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-syntax-table): Simplify.
+
+       * lpath.el: Fbind set-char-table-range for XEmacs 21.4 and SXEmacs 22.1.
+
+       * gnus-art.el (article-treat-non-ascii): Use put-char-table instead of
+       set-char-table-range for XEmacs.
+
+2010-11-10  Glenn Morris  <rgm@gnu.org>
+
+       * time-date.el (time-to-seconds): Always an alias on Emacs,
+       never a real function.
+       (with-no-warnings): Remove compat stub, now unused.
+       (time-less-p): Doc fix.
+       (time-to-number-of-days): Simplify.
+
+       * smime.el (from): Remove unused declaration.
+
+       * gnus-util.el (with-no-warnings): Remove compat stub, now unused.
+       (gnus-float-time): On Emacs, always an alias.
+
+       * ecomplete.el (with-no-warnings): Remove compat stub, now unused.
+       (ecomplete-add-item): Use float-time on Emacs, else gnus-float-time.
+
+2010-11-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el: Don't use ignore-errors in the top level form since it
+       is unavailable in XEmacs even if cl is loaded.
+
+       * gnus-art.el (org-entities): Declare it to silence the byte compiler.
+
+2010-11-09  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (browse-url-mailto): Autoload.
+
+       * gnus-art.el (article-treat-non-ascii): New command and keystroke.
+
+       * message.el (message-subject-trailing-was-ask-regexp): A ] in a []
+       regexp doesn't need quoting.
+
+2010-11-09  Sven Joachim  <svenjoac@gmx.de>
+
+       * message.el (message-subject-trailing-was-ask-regexp)
+       (message-subject-trailing-was-regexp): Match was: in addition to was.
+
+2010-11-09  Glenn Morris  <rgm@gnu.org>
+
+       * nnbabyl.el (nnbabyl-request-move-article, nnbabyl-delete-mail)
+       (nnbabyl-check-mbox): Use point-at-bol.
+
+2010-11-08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-browse-url): Call browse-url-mailto for mailto: links.
+
+       * message.el (message-mailto): New function.
+       (message-mailto): Should accept other parameters.
+       (message-mailto): Remove since it duplicates browse-url-mailto
+       functionality.
+
+2010-11-07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-get-unread-articles): Ignore totally non-existent
+       methods.
+       (gnus-read-active-file): Ditto.
+
+       * gnus-group.el (gnus-group-read-ephemeral-group): Remove superfluous
+       ": " from the prompt.
+       (gnus-group-make-group): Ditto.
+
+2010-11-07  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-bookmark.el (gnus-bookmark-bmenu-show-infos)
+       (gnus-bookmark-kill-line): Use point-at-eol.
+
+2010-11-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-gravatar.el (gnus-gravatar-transform-address): No need to skip
+       asterisks in From header.
+
+2010-11-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-ems.el (gnus-put-image): Use a blank text as the insertion
+       string to avoid making the From headers syntactically invalid.
+
+       * message.el (message-send-mail): Don't insert courtesy messages if the
+       message already has List-Post and List-ID messages.
+
+2010-11-06  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-art.el (gnus-treat-article): Give dynamic local variables
+       `condition', `type', `length' a prefix.
+       (gnus-treat-predicate): Update for above name changes.
+
+2010-11-06  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (gnus-summary-nnir-goto-thread): Remove function and
+       binding.  Handled by `gnus-summary-refer-thread' instead.
+       (nnir-warp-to-article): New backend function.
+
+       * nnimap.el (nnimap-request-thread): Force dependency updating.
+
+       * gnus-sum.el (gnus-fetch-headers): Allow more arguments.
+       (gnus-summary-refer-thread): Rework to improve thread-referral.
+
+       * gnus-int.el (gnus-warp-to-article): New function.
+
+       * gnus-sum.el (gnus-summary-article-map): Bind it.
+
+2010-11-04  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (gnus-summary-nnir-goto-thread): Limit work done by
+       gnus-summary-refer-thread.
+
+       * gnus-sum.el (gnus-build-all-threads): Force updating of dependency
+       headers.
+       (gnus-summary-limit-include-thread): Prevent articles in thread from
+       being cut in gnus-cut-threads.
+       (gnus-summary-refer-thread): Limit retrieved headers to those in
+       thread.
+
+2010-11-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-send-mail): Use the value of
+       message-courtesy-message from the message buffer.
+
+       * gnus-html.el (gnus-html-browse-url): Implement mailto: URLs.
+
+       * shr.el (shr-browse-url): Implement mailto: URLs.
+
+       * gnus-sum.el (gnus-summary-show-article): Take `t' as the arg to mean
+       "raw".
+
+       * nnimap.el (nnimap-find-article-by-message-id): Don't EXAMINE a group
+       if it's already selected.
+
+       * mm-decode.el (mm-save-part): Put the entire path in the `M-n' slot.
+
+2010-11-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el (shr-tag-img): Use string-width and truncate-string-to-width
+       to measure the length and truncate alt text.
+
+2010-11-03  Glenn Morris  <rgm@gnu.org>
+
+       * nndiary.el (nndiary-generate-nov-databases-1)
+       (nndiary-generate-active-info): Rename dynamic variable `files' to
+       something less generic.
+
+2010-11-03  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-request-move-article): Call the underlying backend to
+       move articles from nnir.
+
+2010-11-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-cite.el (gnus-article-natural-long-line-p): Remove.
+
+2010-11-02  Julien Danjou  <julien@danjou.info>
+
+       * nnir.el: Remove wais support.
+
+2010-11-02  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-html.el: Reorder requirements to quieten compiler.
+
+2010-11-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-cite.el (gnus-article-fill-cited-article): Make fill work
+       properly for XEmacs as well.
+       (gnus-article-fill-cited-article, gnus-article-foldable-buffer)
+       (gnus-article-natural-long-line-p): Use window-width rather than
+       frame-width.
+
+2010-11-01  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-run-gmane): Inhibit demon.  Return nil if no messages.
+       (nnir-read-parms): Don't modify query.
+       (nnir-run-query): Add ability to search topic on current line.
+       (nnir-get-active): Clean up.
+
+2010-11-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-cite.el (gnus-article-foldable-buffer): Protect against
+       degenerate articles.
+
+       * gnus-sum.el (gnus-print-buffer): Rewrite to use with-temp-buffer.
+       (gnus-print-buffer): Just print the buffer as is, without any copying
+       to a buffer and then re-highlighting.
+
+       * nnimap.el (nnimap-request-group): Store the new updated info.
+       (nnimap-request-group): Select the group when we don't know whether it
+       exists or not.
+
+       * gnus-start.el (gnus-ask-server-for-new-groups): Return the new
+       groups.
+
+       * gnus-group.el (gnus-group-find-new-groups): Display all the new
+       groups.
+
+       * gnus-start.el (gnus-find-new-newsgroups): Return the list of new
+       groups.
+
+       * gnus-cite.el (gnus-article-fill-cited-article): Minimize the
+       long-lines case by only filling the long lines.
+
+       * nnimap.el (nnimap-parse-line): Don't bug out oddly formed replies
+       (bug#7311).
+
+2010-11-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el: No need to declare `declare-function' since shr.el is for
+       only Emacsen that provide `libxml-parse-html-region'.
+
+       * dgnushack.el: Remove `(defvar iswitchb-temp-buflist)', that is
+       effective only in a file it is referred to.
+
+2010-11-01  Glenn Morris  <rgm@gnu.org>
+
+       * mm-util.el (gnus-completing-read): Autoload.
+       (mm-read-coding-system): Simplify Emacs definition.
+
+       * nnmail.el (gnus-activate-group):
+       * nnimap.el (gnutls-negotiate):
+       * nntp.el (netrc-parse): Fix declarations.
+
+2010-11-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-string-match-p): New function, that is an alias to
+       string-match-p in Emacs >=23.
+
+       * gnus-msg.el (gnus-configure-posting-styles):
+       * nnir.el (nnir-run-gmane): Use gnus-string-match-p.
+
+2010-11-01  Glenn Morris  <rgm@gnu.org>
+
+       * nnir.el (declare-function): Add compat stub.
+       (mm-url-insert, mm-url-encode-www-form-urlencoded): Declare.
+       (nnir-run-gmane): Require 'mm-url.
+
+       * mm-util.el (mm-string-to-multibyte): Simplify.
+
+       * shr.el (declare-function): Add compat stub.
+       (url-cache-create-filename): Declare.
+       (mm-disable-multibyte, widget-convert-button): Autoload.
+
+       * smime.el (ldap-search): Declare.
+       (smime-cert-by-ldap-1): Require ldap on Emacs.
+
+       * nnimap.el: Require nnmail, and gnus-sum when compiling.
+       (nnimap-keepalive): Use gnus-float-time.
+
+       * mail-source.el (nnheader-message, gnus-float-time): Autoload.
+       (mail-source-delete-crash-box): Use gnus-float-time.
+
+       * gnus-dired.el (gnus-completing-read): Autoload.
+
+       * mm-view.el (gnus-rescale-image): Autoload.
+
+       * mm-decode.el (gnus-completing-read, gnus-blocked-images): Autoload.
+
+       * gnus.el (gnus-sloppily-equal-method-parameters): Move defn before use.
+
+       * sieve-manage.el: Require 'cl when compiling.
+
+       * gnus-util.el (iswitchb-read-buffer): Declare rather than autoload.
+       (gnus-iswitchb-completing-read): Require iswitchb.
+       (gnus-select-frame-set-input-focus): Silence compiler.
+
+2010-10-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-subject-trailing-was-query): Change default to t,
+       since I think that's what most people want.
+
+       * nnimap.el (nnimap-request-accept-article): Erase buffer before
+       appending for easier debugging.
+       (nnimap-wait-for-connection): Take a regexp.
+       (nnimap-request-accept-article): Wait for the continuation line before
+       sending anything unless we're streaming.
+
+       * gnus-art.el (gnus-treat-article): Only inhibit body washing, and
+       leave the header washing to take place.
+
+2010-10-31  Daniel Dehennin  <daniel.dehennin@baby-gnu.org>
+
+       * gnus-msg.el (gnus-configure-posting-styles): Permit the use of
+       regular expression match and replace in posting styles.
+
+2010-10-31  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (gnus-group-make-nnir-group, nnir-run-query): Allow searching
+       an entire server.
+       (nnir-get-active): New function.
+       (nnir-run-imap): Use it.
+       (nnir-run-gmane): Who knew, gmane search returns an article score!
+
+       * gnus-srvr.el (gnus-server-mode-map): Add binding "G" to search the
+       server on the current line with nnir.
+
+2010-10-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-cite.el (gnus-article-foldable-buffer): Refactor out.
+       (gnus-article-foldable-buffer): Don't fold regions that have a ragged
+       left edge.
+       (gnus-article-foldable-buffer): Skip past the prefix when determining
+       raggedness.
+
+       * gnus-sum.el (gnus-summary-show-article): Add `C-u C-u g' for showing
+       the raw article, and change `C-u g' to show the article without doing
+       treatments.
+
+       * gnus-art.el (gnus-mime-display-alternative): Actually pass the type
+       on to `gnus-treat-article'.
+       (gnus-inhibit-article-treatments): New variable.
+
+       * gnus.el: Autoload gnus-article-fill-cited-long-lines.
+
+       * gnus-art.el (gnus-treatment-function-alist): Have
+       gnus-treat-fill-long-lines point to gnus-article-fill-cited-long-lines.
+       (gnus-treat-fill-long-lines): Change default to fill all text/plain
+       sections.
+
+       * gnus-cite.el (gnus-article-fill-cited-article): Remove unused `force'
+       parameter.
+       (gnus-article-fill-cited-long-lines): New function.
+       (gnus-article-fill-cited-article): Allow filling only long sections.
+
+       * shr.el (shr-find-fill-point): Don't break lines between punctuation
+       and non-punctuation (like after the apostrophe in "'We").
+
+       * gnus-sum.el (gnus-summary-select-article): Make sure
+       gnus-original-article-buffer is alive.
+
+       * nndoc.el (nndoc-dissect-buffer): Reverse the order of the articles to
+       reflect the order they're in in the digest.
+
+       * gnus.el (gnus-group-startup-message): Move point to the start of the
+       buffer.
+
+       * nnimap.el (nnimap-capability): New function.
+       (nnimap-open-connection): Only send AUTHENTICATE PLAIN if LOGINDISABLED
+       is set.
+
+2010-10-31  David Engster  <dengste@eml.cc>
+
+       * nnmairix.el (nnmairix-get-valid-servers): Return list of strings to
+       conform with changes to gnus-completing-read.
+
+2010-10-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-tag-img): Output "*" instead of "[img]".
+
+2010-10-30  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el: Move defvar, defcustom around to keep file organized
+       and keep byte-compiler quiet.
+       (nnir-read-parms): Accept search-engine as arg.
+       (nnir-run-query): Pass search-engine as arg.
+       (nnir-search-engine): Remove.
+
+2010-10-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-generic): The text nodes should be text, not :text.
+
+       * nnir.el (nnir-search-engine): Ressurect variable, since it's used
+       later in the file.
+
+2010-10-30  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el: General clean up.  Allow searching with multiple engines.
+       Allow separate extra-parameters for each engine.
+       Batch queries when possible.
+       (nnir-imap-default-search-key, nnir-method-default-engines):
+       Add customize interface.
+       (nnir-run-gmane): New engine.
+       (nnir-engines): Use it.  Qualify all prompts with engine name.
+       (nnir-search-engine): Remove global variable.
+       (nnir-run-hyrex): Restore for now.
+       (nnir-extra-parms, nnir-search-history): New variables.
+       (gnus-group-make-nnir-group): Use them.
+       (nnir-group-server): Remove in favor of gnus-group-server.
+       (nnir-request-group): Avoid searching twice.
+       (nnir-sort-groups-by-server): New function.
+
+2010-10-30  Julien Danjou  <julien@danjou.info>
+
+       * gnus-group.el: Remove gnus-group-fetch-control.
+
+       * gnus-start.el (gnus-find-new-newsgroups):
+       Remove gnus-check-first-time-used.
+
+       * gnus.el: Remove gnus-backup-default-subscribed-newsgroups.
+
+2010-10-30  Knut Anders Hatlen  <kahatlen@gmail.com>  (tiny change)
+
+       * nnimap.el (nnimap-update-info): Allow 'ticked and other flags to be
+       set on groups that don't have \* permanentflags.
+
+2010-10-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-tag-span): Drop colorization of regions since we don't
+       control the background color.
+       (shr-tag-img): Ignore very small web bug type images.
+       (shr-put-image): Add help-echo alt texts to the images.
+       (shr-tag-video): Show the video poster image.
+
+2010-10-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-table-depth): New variable.
+       (shr-tag-table-1): Only insert the images after the top-level table.
+
+       * nnimap.el (nnimap-split-incoming-mail): Fix typo.
+
+       * gnus-util.el (gnus-list-memq-of-list): New function.
+
+       * nnimap.el (nnimap-split-incoming-mail): Note that the INBOX has been
+       selected.
+       (nnimap-unsplittable-articles): New slot.
+       (nnimap-new-articles): Use it.
+
+2010-10-29  Stephen Berman  <stephen.berman@gmx.net>  (tiny change)
+
+       * gnus-group.el (gnus-group-get-new-news-this-group): Don't have point
+       move to the previous line on `M-g'.
+
+2010-10-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-inews-do-gcc): Don't have the backends do the slow
+       *-request-group, which seems unnecessary.
+
+       * nnimap.el (nnimap-quote-specials): Function copied over from
+       imap.el.
+       (nnimap-open-connection): Use AUTHENTICATE PLAIN on servers that say
+       they support that.  Suggested by Tom Regner.
+
+2010-10-29  Julien Danjou  <julien@danjou.info>
+
+       * gnus-sum.el (gnus-summary-delete-marked-as-read): Remove obsolete
+       defalias.
+       (gnus-summary-delete-marked-with): Remove obsolete defalias.
+
+       * gnus.el: Remove `gnus-nntp-service' variable.
+       (gnus-secondary-servers): Make obsolete.
+       (gnus-nntp-server): Make obsolete.
+
+       * gnus-start.el (gnus-1): Remove x-splash calls.
+
+       * gnus-ems.el (gnus-x-splash): Remove.
+
+       * gnus.el (gnus-group-startup-message): Simplify/update code.
+
+       * gnus-xmas.el (gnus-xmas-define): Remove unused gnus-characterp
+       definition.
+
+       * gnus-group.el (gnus-group-make-tool-bar): Check for display graphic
+       capability before doing anything.
+       (gnus-group-insert-group-line): Remove useless
+       gnus-group-remove-excess-properties.
+
+2010-10-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-goto-part): Work for article narrowed by ^L.
+
+2010-10-28  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-rescan-group): Try to restore the window
+       config after reselecting.
+
+2010-10-28  Julien Danjou  <julien@danjou.info>
+
+       * shr.el (shr-put-image): Use point even if only inserting text.
+       (shr-put-image): Save excursion when inserting alt text on non-graphic
+       display, so the behavior is the same when we are on a graphic display.
+
+       * nnir.el (nnir-run-swish-e): Remove hyrex support.
+
+2010-10-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-jump-to-part): Error on no part; fix prompt.
+       (gnus-mime-copy-part): Check coding system, not charset.
+       (gnus-mime-view-part-externally): Never remove part.
+       (gnus-mime-view-part-internally): Don't remove part here.
+       (gnus-article-part-wrapper): Make sure MIME tag is visible.
+       (gnus-article-goto-part): Go to displayed or preferred subpart if it is
+       multipart/alternative.
+
+       * mm-decode.el (mm-display-part): Take optional arg `force'.
+
+2010-10-26  Julien Danjou  <julien@danjou.info>
+
+       * gnus-group.el (gnus-group-default-list-level): Add this function to
+       compute the default list level.
+       (gnus-group-default-list-level): Add possibility to use a function.
+
+2010-10-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-shr): Add undisplayer to MIME handle.
+
+       * gnus-group.el (gnus-group-completing-read)
+       (gnus-read-ephemeral-bug-group): Replace replace-regexp-in-string with
+       gnus-replace-in-string.
+
+2010-10-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el (shr-tag-div): Add.
+
+       * lpath.el: Fbind current-idle-time for XEmacs 21.4 and SXEmacs 22.1.
+
+2010-10-25  Julien Danjou  <julien@danjou.info>
+
+       * gnus-util.el: Remove `gnus-with-local-quit'.
+
+       * gnus-demon.el (gnus-demon-init): Use run-with-idle-timer function.
+
+2010-10-25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-select-article): Fix type error in checking
+       the original article buffer.
+
+2010-10-24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-request-head): New function.
+       (nnimap-request-move-article): Try to be slightly faster by not
+       requesting the entire message when moving.
+       (nnimap-transform-headers): Don't bug out on bodiless articles.
+       (nnimap-send-command): Have no outstanding messages if the IMAP server
+       doesn't support streaming.
+       (nnimap-transform-headers): Fold {quoted} strings more sloppily.
+
+2010-10-24  Julien Danjou  <julien@danjou.info>
+
+       * message.el (message-default-headers): Fix type.
+
+2010-10-24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-html.el (gnus-html-prefetch-images): Decode entities before
+       prefetching images.
+
+       * gnus-sum.el (gnus-group-make-articles-read): Propagate marks to the
+       backend for unknown groups.  This is mainly useful for nnimap groups.
+
+       * gnus-agent.el (gnus-agent-fetch-group): Don't download stuff if the
+       group isn't covered by the agent.
+
+2010-10-22  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-method-default-engines): New variable.
+       (nnir-run-query): Use it.
+       (nnir-group-mode-hook): Remove key binding and move to gnus-group.el.
+       (gnus-summary-nnir-goto-thread): Change group if needed.
+
+       * gnus-group.el (gnus-group-group-map): Add key binding for
+       gnus-group-make-nnir-group.
+
+2010-10-24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-tag-object): Add.
+
+       * gnus-sum.el (gnus-summary-select-article): Make sure we have the
+       original article buffer live.
+       (gnus-summary-select-article-buffer):
+       Mention gnus-widen-article-buffer.
+
+2010-10-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-tag-strong): Add.
+
+2010-10-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-completing-read): Remove all newlines from
+       group names.  They mess up the group buffer badly.
+
+       * shr.el (shr-tag-img): Don't bug out on images that don't have a SRC.
+
+       * gnus-group.el (gnus-group-mark-group): Use gnus-group-position-point
+       instead of the summary one.
+
+2010-10-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml.el (mml-preview): Work properly when editing article.
+
+       * gnus-start.el (gnus-read-active-file-1): Don't add method to
+       gnus-have-read-active-file if it's already been in.
+
+2010-10-22  Tom Tromey  <tromey@redhat.com>
+
+       * gnus-group.el (gnus-group-unsubscribe-group): Fix args passed to
+       gnus-group-completing-read.
+
+2010-10-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-mode-map): Don't bind M-; to comment region, to
+       allow the global comment-dwim to work.
+
+2010-10-21  Julien Danjou  <julien@danjou.info>
+
+       * message.el (message-setup-1): Allow message-default-headers to be a
+       function.
+
+2010-10-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el (shr-tag-table): Simplify.
+
+2010-10-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-html.el (gnus-html-prefetch-images): Only prefetch http images
+       to avoid trying to snarf invalid stuff.
+
+       * gnus-sum.el (gnus-summary-edit-article-done): Bind free variable.
+
+       * gnus.el (gnus-message-archive-group): Quote value.
+       (gnus-message-archive-group): Mark as changed.
+
+       * shr.el (shr-add-font): Don't put the font properties on the newline
+       or the indentation.
+
+       * message.el (message-fix-before-sending): Change options when sending
+       non-printable characters.
+
+       * gnus.el (gnus-message-archive-method): Change the default to
+       monthly outgoing groups.
+
+       * gnus-sum.el (gnus-summary-edit-article-done): Try to replace articles
+       that have gotten new numbers.
+
+       * nnimap.el (nnimap-request-replace-article): New function.
+
+2010-10-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnrss.el (nnrss-wash-html-in-text-plain-parts): Remove.
+       (nnrss-request-article): Don't use special html washing code.
+
+2010-10-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el (shr-tag-table): Remove useless nconc.
+
+2010-10-20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-wash-html): Simplify and remove the charset
+       stuff.  Use the normal html rendering code instead of the special html
+       washing code.
+
+       * mm-view.el (mm-text-html-renderer-alist): Add the `shr' and
+       `gnus-w3m' symbols.
+       (mm-text-html-washer-alist): Remove.
+
+       * mm-decode.el (mm-inline-text-html-renderer): Remove.
+       (mm-inline-media-tests): Remove use.
+       (mm-text-html-renderer): Change default to the `shr' symbol.
+
+       * mm-view.el (mm-inline-text-html): Remove use.
+
+       * gnus-art.el (gnus-blocked-images): New function.  Allow the
+       `gnus-blocked-images' to be a function.
+       (gnus-article-wash-function): Remove.
+
+2010-10-20  Julien Danjou  <julien@danjou.info>
+
+       * spam.el (spam-list-of-processors): Mark as obsolete.
+
+       * nnimap.el (nnimap-request-article): Fix BODYSTRUCTURE retrieval.
+       (nnimap-insert-partial-structure): Fix boundary detection.
+
+2010-10-20  Andreas Seltenreich  <seltenreich@gmx.de>
+
+       * gnus-draft.el (gnus-draft-check-draft-articles): Don't unnecessarily
+       run file-truename on remote files.  This can be expensive and even
+       prevent one from editing drafts if some unrelated buffer has a stale
+       connection.
+
+2010-10-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el (shr-find-fill-point): Shorten line if the preceding char is
+       kinsoku-eol regardless of shr-kinsoku-shorten.
+       (shr-tag-table-1): Rename from shr-tag-table; make it a subroutine.
+       (shr-tag-table): Support caption, thead, and tfoot.
+
+2010-10-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-find-fill-point): Don't leave blanks at the start of some
+       lines.
+       (shr-save-contents): New command and keystroke.
+
+       * nndoc.el (nndoc-type-alist): Add git support.
+       (nndoc-git-type-p): New function.
+       (nndoc-transform-git-article): Ditto.
+       (nndoc-transform-git-headers): Ditto.
+       (nndoc-transform-git-headers): Generate Subject headers.
+
+       * shr.el (shr-parse-style): New function.
+       (shr-tag-span): Ditto.
+
+       * nnmairix.el (nnmairix-summary-mode-hook): Move nnmairix's `$' command
+       to `G G' to avoid collisions.
+
+2010-10-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el: Load kinsoku if necessary.
+       (shr-kinsoku-shorten): New internal variable.
+       (shr-find-fill-point): Make kinsoku shorten text line if
+       shr-kinsoku-shorten is bound to non-nil.
+       (shr-tag-table): Bild shr-kinsoku-shorten to t; refer to
+       shr-indentation too when testing if table is wider than frame width.
+       (shr-insert-table): Use `string-width' instead of `length' to measure
+       text width.
+       (shr-insert-table-ruler): Make sure indentation is done at bol.
+
+2010-10-19  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * nnimap.el (nnimap-request-move-article, nnimap-parse-line)
+       (nnimap-process-expiry-targets): Use unibyte for buffers that hold
+       undecoded network data.
+
+2010-10-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-agent.el (gnus-agent-toggle-plugged): Use the right minor mode
+       name in the mode line spec so that the mode line menu works
+       (bug#2431).
+
+       * message.el (message-get-reply-headers): If we're fed `to-address',
+       then always use that.
+
+       * gnus-art.el (gnus-article-make-menu-bar): The article/group menus
+       aren't so wide as to need to switch off the edit menu.
+
+       * gnus-delay.el (gnus-delay-article): Remove superfluous `group'
+       binding.  Suggested by Leo <sdl.web@gmail.com> (bug#6613).
+
+       * nnimap.el (nnimap-request-group): Don't SELECT the group twice on
+       `M-g'.
+       (nnimap-update-info): Update flags/read marks even if \* isn't part of
+       the permanent marks.
+
+2010-10-18  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * gnus-registry.el (gnus-registry-split-fancy-with-parent):
+       Splitting according to references/in-reply-to obeys the ignore-groups
+       variable, while splitting by sender and subject do not.
+
+2010-10-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-dumbquotes-map): Make into a char/string
+       alist, so that we can look for non-Unicode chars.
+       (article-translate-strings): Allow both character and string maps.
+
+2010-10-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el (shr-insert): Don't insert space behind a wide character
+       categorized as kinsoku-bol, or between characters both categorized as
+       nospace.
+
+2010-10-16  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * gnus-sum.el (gnus-summary-refer-thread): Bug fix.  Add the thread
+       headers to gnus-newsgroup-headers.
+
+2010-10-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-tag-img): Don't align images -- since we're not
+       rescaling, this often leads to ugly displays.
+
+2010-10-15  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * gnus-sum.el (gnus-summary-refer-thread): Unconditionally ignore
+       duplicates.
+
+2010-10-15  Kan-Ru Chen  <kanru@kanru.info>  (tiny change)
+
+       * gnus-diary.el (gnus-diary-check-message): Fix gnus-completing-read
+       call.
+
+2010-10-15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el: Autoload gnus-html-show-images.
+
+       * nnimap.el: Use nnheader-message throughout.
+
+       * shr.el (shr-tag-img): Ignore images with no data.
+
+2010-10-15  Julien Danjou  <julien@danjou.info>
+
+       * mml.el (mml-generate-mime-1): Add `mml-enable-flowed' variable to add
+       a possibility to disable format=flow encoding when using hard newlines.
+
+2010-10-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * shr.el (shr-insert): Remove space inserted before or after a
+       breakable character or at the beginning or the end of a line.
+       (shr-find-fill-point): Do kinsoku; find the second best point or give
+       it up if there's no breakable point.
+
+2010-10-14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-open-connection): Message when opening connection
+       for debugging purposes.
+
+       * gnus-art.el (gnus-article-setup-buffer): Set article mode truncation
+       on every setup buffer call to allow this to change from article to
+       article.
+
+       * shr.el (shr-tag-table): Experimental feature: Truncate lines in
+       buffers where we have a wide table.
+
+2010-10-14  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * gnus-sum.el (gnus-summary-refer-thread): Implement a version that
+       uses *-request-thread.
+
+2010-10-14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-open-connection): Remove %s from openssl
+       incantation, which is no longer valid.
+
+2010-10-14  Julien Danjou  <julien@danjou.info>
+
+       * shr.el: Fix defcustom type (char -> character).
+
+2010-10-14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-open-connection): tls-program should be a list of
+       programs.
+
+2010-10-14  Julien Danjou  <julien@danjou.info>
+
+       * shr.el (shr-tag-a): Use url-link as widget type.
+
+       * gnus-group.el (gnus-group-insert-group-line): Fix group argument to
+       `gnus-group-get-icon'.
+
+2010-10-13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-close-server): Forget the nnimap data on close.
+       This should make server editing work better.
+
+       * shr.el (shr-find-fill-point): Don't inloop on indented text.
+
+       * tls.el (tls-program): Remove spurious %s from openssl.
+
+       * nnimap.el (nnimap-open-connection): Fix open-tls-stream call.
+       (nnimap-parse-flags): Fix regexp.
+
+       * shr.el (shr-find-fill-point): Use a filling algorithm that should
+       probably work for CJVK text, too.
+
+       * nnimap.el (nnimap-extend-tls-programs): Remove.
+       (nnimap-open-connection): Bind STARTTLS to openssl explicitly.
+
+       * tls.el (tls-starttls-switches): Remove starttls hack.
+       (open-tls-stream): Ditto.
+       (tls-find-starttls-argument): Ditto.
+
+2010-10-13  Julien Danjou  <julien@danjou.info>
+
+       * nnimap.el (nnimap-parse-flags): Be more strict when looking for FETCH
+       responses.
+
+2010-10-13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-shr): Allow use from non-Gnus users.
+
+       * gnus-spec.el (gnus-parse-simple-format): princ doesn't really insert
+       anything in Emacs.
+
+       * shr.el (shr-current-column): Remove buggy and unnecessary function.
+
+2010-10-13  Julien Danjou  <julien@danjou.info>
+
+       * shr.el (shr-width): Make shr-width a defcustom with default to
+       fill-column.
+       (shr-tag-img): Use shr-width rather than fill-column.
+
+2010-10-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (byte-optimize-apply):
+       * gnus-dired.el (gnus-dired-attach): Silence XEmacs 21.5 when compiling.
+
+       * gnus-gravatar.el (gnus-gravatar-transform-address): Adjust avatars'
+       position when (X-)Faces exist.
+       (gnus-treat-from-gravatar, gnus-treat-mail-gravatar): Force displaying
+       avatars when called interactively.
+
+2010-10-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-gravatar.el (gnus-gravatar-too-ugly): Don't test if
+       gnus-article-x-face-too-ugly is bound.
+
+2010-10-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * rfc2231.el (rfc2231-parse-string): Ignore repeated parts.
+
+       * nnimap.el (nnimap-request-rename-group): Unselect by selecting a
+       mailbox that doesn't exist.
+
+2010-10-12  Julien Danjou  <julien@danjou.info>
+
+       * shr.el (shr-tag-img): Encode URL properly when retrieving.
+       (shr-get-image-data): Encode URL properly when fetching from cache.
+       (shr-tag-img): Use aligned-to spaces to align correctly images.
+
+       * gnus-gravatar.el (gnus-gravatar-insert): Check if buffer is alive
+       before inserting the Gravatar.
+
+       * shr.el (shr-tag-img): Add align attribute support for <img>.
+
+2010-10-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-gravatar.el (gnus-art): Require.
+
+       * gnus-sum.el (gnus-summary-mark-as-unread-forward)
+       (gnus-summary-mark-as-unread-backward, gnus-summary-mark-as-unread):
+       Remove long obsoleted functions.
+
+2010-10-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind gnutls-negotiate for Emacs 22 and XEmacsen.
+
+       * nnimap.el (gnutls-negotiate): Silence the byte compiler.
+
+       * gnus-art.el, gnus-cache.el, gnus-fun.el, gnus-group.el:
+       * gnus-picon.el, gnus-spec.el, gnus-sum.el, gnus-util.el, gnus.el:
+       * hashcash.el, imap.el, mail-source.el, message.el, mm-bodies.el:
+       * mm-decode.el, mm-extern.el, mm-util.el, mm-view.el, mml-smime.el:
+       * mml.el, mml1991.el, mml2015.el, nnfolder.el, nnheader.el, nnmail.el:
+       * nnmaildir.el, nnrss.el, nntp.el, pgg-parse.el, pgg.el, rfc1843.el:
+       * sieve-manage.el, smime.el, spam.el:
+       Fix comment for declare-function.
+
+2010-10-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-request-rename-group): Select group read-only
+       before renaming it.
+
+       * shr.el (shr-insert): Fix up the white space only regexp.
+
+       * nnimap.el (nnimap-transform-split-mail): Not all articles have
+       bodies.  Protect against this.  Reported by Michael Welsh Duggan.
+
+       * shr.el (shr-current-column): New function.
+       (shr-find-fill-point): New function.
+
+2010-10-11  Michael Welsh Duggan  <md5i@md5i.com>  (tiny change)
+
+       * sieve-manage.el (sieve-manage-open): Allow port names as well as port
+       numbers.
+
+2010-10-11  Julien Danjou  <julien@danjou.info>
+
+       * shr.el (shr-hr-line): Add.
+       (shr-tag-hr): Use shr-hr-line to specify which character to use to
+       display hr lines.
+       (shr-max-columns): Do not change state to nil if we just inserting
+       spaces.
+
+2010-10-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-topic.el (gnus-topic-read-group): If after the last group,
+       select the last group.
+
+2010-10-11  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-int.el (gnus-run-hook-with-args): Autoload from gnus-util.el.
+
+2010-10-10  Dan Nicolaescu  <dann@ics.uci.edu>
+
+       * dig.el (dig-mode-map): Declare and define in one step.
+
+2010-10-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-update-qresync-info): \Flagged messages are read
+       for Gnus.
+       (nnimap-retrieve-group-data-early): utf7-encode the group parameters.
+       (nnimap-update-qresync-info): Mark \Seen articles as read.
+
+       * gnus-sum.el (gnus-summary-set-local-parameters): Ignore the `active'
+       non-variable, too.
+
+       * nnimap.el (nnimap-open-connection): Use gnutls STARTTLS, if
+       available.
+       (nnimap-update-info): Rely more on the current active than the param
+       active to avoid marking articles as read too much.
+
+       * auth-source.el (auth-source-create): Use (user-login-name) for the
+       user name default.
+
+       * nnimap.el (nnimap-update-info): If the server doesn't return any
+       useful info, just use the previous info.
+       (nnimap-update-info): Prefer old info over start-article.
+       (nnimap-update-qresync-info): Finish implementing QRESYNC.
+
+2010-10-10  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (autoload): Clean up autoloads.
+       (nnir-imap-default-search-key): Rename from nnir-imap-search-field.
+       Use key rather than value.
+       (nnir-imap-search-other): New variable.
+       (nnir-read-parm): Use it.
+       (nnir-imap-expr-to-imap): Use %S rather than imap-quote-specials.
+       (gnus-summary-nnir-goto-thread): Modify to work with imap.
+
+2010-10-10  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * nnimap.el (nnimap-wait-for-response): If the user hits `C-g', kill
+       the process, too.
+
+2010-10-09  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * spam.el (gnus-summary-mode-map): Bind to "$".
+       Suggested by Russ Allbery.
+
+       * shr.el: Rework the way things are indented by <li> slightly.
+
+       * gnus.el (gnus-group-set-parameter): Fix typo.
+
+       * nnimap.el: Start implementing QRESYNC support.
+
+2010-10-09  Julien Danjou  <julien@danjou.info>
+
+       * nnir.el (nnir-engines): Fix too many arguments.
+
+2010-10-09  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnmail.el (nnmail-expiry-target-group): Say that every expiry target
+       group is the "last", so that the backends like nnfolder actually save
+       their folders.
+
+       * nnimap.el (nnimap-open-connection): If we have gnutls loaded, then
+       try to use that for the tls stream.
+       (nnimap-retrieve-group-data-early): Rework the marks code to heed
+       UIDVALIDITY and find out which groups are read-only and not.
+       (nnimap-get-flags): Use the same marks parsing code as the rest of
+       nnimap.
+
+2010-10-09  Julien Danjou  <julien@danjou.info>
+
+       * nnir.el (nnir-read-parm): Fix call to gnus-completing-read.
+
+       * gnus-gravatar.el (gnus-gravatar-transform-address): Error errors when
+       retrieving gravatars.
+
+       * shr.el (shr-table-corner): Add.
+       (shr-table-line): Add.
+       (shr-insert-table-ruler): Use the above defcustoms to insert tables.
+
+2010-10-08  Julien Danjou  <julien@danjou.info>
+
+       * mm-decode.el (mm-text-html-renderer): Add mm-shr in choice list.
+
+2010-10-08  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-util.el (gnus-alist-pull): Rename `gnus-pull'.
+
+       * gnus-sum.el (gnus-mark-article-as-unread)
+       (gnus-summary-mark-article-as-unread, gnus-summary-remove-bookmark)
+       (gnus-summary-set-bookmark): Use it.
+
+       * gnus-msg.el (gnus-setup-message): Use it.
+
+       * gnus-demon.el (gnus-demon-remove-handler): Use it.
+
+       * gnus.el (gnus-group-remove-parameter): Use it.
+
+       * gnus-group.el (gnus-group-make-web-group): Use it.
+
+       * gnus-demon.el (gnus-demon-remove-handler): Use it.
+
+       * nnregistry.el: Update docs to mention manual.
+
+       * gnus-registry.el: Update docs to mention nnregistry.el.
+       (gnus-registry-initialize): Don't install nnregistry refer method
+       automatically.
+       (gnus-registry-install-nnregistry): Remove it.
+
+2010-10-08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-insert): Don't insert double spaces.
+
+2010-10-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-gravatar.el (gnus-treat-from-gravatar)
+       (gnus-treat-mail-gravatar): Bind gnus-gravatar-too-ugly to nil when
+       called interactively.
+
+       * gnus-art.el (gnus-mime-view-part-externally)
+       (gnus-mime-view-part-internally): Make predicate function passed to
+       gnus-mime-view-part-as-type assume argument is a mime type, not a list
+       of a mime type.
+
+       * shr.el (shr-table-widths): Don't use cl function `reduce'.
+
+2010-10-07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (require): Require cl when compiling.
+       (shr-tag-hr): New function.
+
+       * nnimap.el (nnimap-update-info): Remove double setting of high.
+       (nnimap-update-info): Don't ignore groups that have no UIDNEXT.
+       This makes nnimap work properly on Courier again.
+
+       * gnus.el (gnus-carpal): The carpal mode has been removed, but define
+       the variable for backwards compatibility.
+
+       * mm-decode.el (mm-save-part): If given a non-directory result, expand
+       the file name before using to avoid setting mm-default-directory to
+       nil.
+
+       * gnus-start.el (gnus-get-unread-articles): Require gnus-agent before
+       bidning gnus-agent variables.
+
+       * shr.el (shr-render-td): Use a cache for the table rendering function
+       to avoid getting an exponential rendering behavior in nested tables.
+       (shr-insert): Rework the line-breaking algorithm.
+       (shr-insert): Don't leave trailing spaces.
+       (shr-insert-table): Also insert empty TDs.
+       (shr-tag-blockquote): Ensure paragraphs after </ul>.
+
+2010-10-07  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-sum.el (gnus-number): Rename from `number'.
+       (gnus-article-marked-p, gnus-summary-limit-to-display-predicate)
+       (gnus-summary-limit-children): Update uses correspondingly.
+
+2010-10-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-gravatar.el (gnus-gravatar-too-ugly): New user option.
+       (gnus-gravatar-transform-address): Don't show avatars of people of
+       which mail addresses match gnus-gravatar-too-ugly.
+
+2010-10-07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-table-widths): Expand TD elements to fill available
+       space.
+
+2010-10-07  Julien Danjou  <julien@danjou.info>
+
+       * nnimap.el (nnimap-request-rename-group): Add this method.
+
+2010-10-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-html.el (gnus-html-schedule-image-fetching): Remove function
+       name from XEmacs' function-arglist.
+
+       * gnus-gravatar.el (gnus-gravatar-insert): Don't add properties to
+       gravatar under XEmacs.
+
+2010-10-07  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el: Update docs with TODO items.
+
+       * gnus-sync.el: Update docs to explain state and plans.
+
+       * gnus-int.el (gnus-after-set-mark-hook, gnus-before-update-mark-hook):
+       Hooks for mark updates.
+       (gnus-request-set-mark, gnus-request-update-mark): Use them.
+
+       * gnus-util.el (gnus-run-hooks-with-args): Convenience function to run
+       hooks with arguments, which is needed for mark update hooks.
+
+2010-10-06  Julien Danjou  <julien@danjou.info>
+
+       * gnus.el (gnus-expand-group-parameter): Only return and act on what
+       was matched.
+
+       * sieve-manage.el: Update example in `Commentary'.
+
+       * sieve.el (sieve-open-server): Use sieve-manage-authenticate.
+
+       * sieve-manage.el (sieve-manage-open): Use sieve-manage-default-port,
+       not 2000.
+       (sieve-manage-authenticate): Re-add function.
+
+2010-10-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-insert): Get 'space transition right.
+       (shr-render-td): Only delete space at the end of the TD.
+
+       * nnimap.el (nnimap-open-connection): Prepare to support
+       open-gnutls-stream.
+
+       * shr.el: Rearrange function order to be more logical.
+
+2010-10-06  Julien Danjou  <julien@danjou.info>
+
+       * nnrss.el (nnrss-check-group): Remove 404 URL in comment.
+       (nnrss-discover-feed): Remove 404 URL in docstring.
+
+       * nnir.el: Fix Swish-E URL.
+       Fix Namazu URL.
+
+       * message.el (message-change-subject): Remove 404 URL in a comment.
+
+2010-10-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-view-part-as-type): Make it work when being
+       called interactively.
+
+       * gnus-util.el (gnus-remove-if): Allow hash table.
+       (gnus-remove-if-not): New function.
+
+       * gnus-art.el (gnus-mime-view-part-as-type):
+       * gnus-score.el (gnus-summary-score-effect):
+       * gnus-sum.el (gnus-read-move-group-name):
+       Replace remove-if-not with gnus-remove-if-not.
+
+       * gnus-group.el (gnus-group-completing-read):
+       Regard collection as a hash table if it is not a list.
+
+2010-10-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-render-td): Allow blank/missing <TD>s.
+
+       * shr.el: Document the table-rendering algorithm.
+
+2010-10-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (dgnushack-compile): Exclude shr.el from being compiled
+       for Emacsen having no `libxml-parse-html-region' support.
+
+2010-10-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-html.el (gnus-html-schedule-image-fetching): Protect against
+       invalid URLs.
+
+       * shr.el (shr-tag-img): Shorten ALT texts and allow them to be
+       line-broken.
+       (shr-tag-img): Ignore image fetching errors.
+       (shr-overlays-in-region): Compute overlay positions correctly.
+
+       * mm-decode.el (mm-shr): Require shr.
+
+       * gnus-art.el (gnus-blocked-images): Move variable here.
+
+       * shr.el (shr-insert-table): Bind free variable.
+
+       * mm-decode.el (mm-shr): Bind shr-content-function.
+
+       * shr.el (shr-content-function): New variable.
+
+       * gnus-sum.el (gnus-article-sort-by-most-recent-date): New function,
+       added for symmetry.
+
+       * nnir.el (nnir-retrieve-headers): Don't bug out on invalid data.
+
+       * gnus-group.el (gnus-group-make-group): Doc fix.
+
+       * nnimap.el (nnimap-request-newgroups): Return success.
+
+       * shr.el (shr-find-elements): New function.
+       (shr-tag-table): Put all the images after the table.
+       (shr-tag-table): Really inhibit images inside the table.
+       (shr-collect-overlays): Copy over overlays from the TD elements to the
+       main document.
+
+       * mm-decode.el (mm-shr): Bind shr-blocked-images to
+       gnus-blocked-images.
+
+2010-10-05  Julien Danjou  <julien@danjou.info>
+
+       * sieve-manage.el (sieve-sasl-auth): Use auth-source to authenticate.
+
+       * gnus-html.el (gnus-html-wash-images): Rescale image from cid too.
+       (gnus-html-maximum-image-size): Add this function.
+       (gnus-html-put-image): Use gnus-html-maximum-image-size.
+
+       * sieve-manage.el (sieve-manage-capability): Do not bug out when the
+       server-value of the capability is nil.
+
+2010-10-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-tag-em): Add <EM> tag.
+
+2010-10-05  Florian Ragwitz  <rafl@debian.org>  (tiny change)
+
+       * sieve-manage.el (sieve-manage-default-stream): Make default stream
+       customizable.
+
+       * gnus-html.el (gnus-html-wash-tags): Decode URL entities to avoid
+       handing broken links to browse-url.
+
+2010-10-05  Julien Danjou  <julien@danjou.info>
+
+       * gnus-util.el (gnus-emacs-completing-read)
+       (gnus-iswitchb-completing-read): Use autoload rather than require.
+
+2010-10-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind libxml-parse-html-region and shr-insert-document for
+       Emacs 22 and XEmacs; fbind help-function-arglist for XEmacs 21.4 and
+       SXEmacs; fbind ido-completing-read, and bind iswitchb-mode and
+       iswitchb-temp-buflist for XEmacs.
+
+       * gnus-util.el (gnus-completing-read-function): Exclude
+       gnus-icompleting-read and gnus-ido-completing-read from candidates for
+       XEmacs since iswitchb.el is very old and ido.el is unavailable in
+       XEmacs.
+
+       * gnus-registry.el (gnus-registry-install-nnregistry): Rewrite so as
+       not to use `delete-dups' that is unavailable in XEmacs 21.4.
+
+       * gnus-html.el: Don't require help-fns under XEmacs.
+       (gnus-html-schedule-image-fetching): Work for XEmacs.
+
+       * mm-decode.el (mm-shr): Decode contents by charset.
+
+2010-10-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-open-connection): Give an error if nnimap-stream is
+       unknown.
+
+       * shr.el (shr-tag-blockquote): Ensure paragraph after quote, too.
+       (shr-get-image-data): Ensure against the cache file missing.
+
+       * nnimap.el (nnimap-finish-retrieve-group-infos): Message while waiting
+       for data.
+
+       * spam-report.el (spam-report-url-ping-plain): Don't query about
+       killing the process.
+
+       * shr.el (shr-render-td): Protect against too-wide text.
+
+2010-10-04  Julien Danjou  <julien@danjou.info>
+
+       * mml-smime.el (mml-smime-openssl-encrypt-query): Fix choices.
+       (mml-smime-openssl-sign-query): Fix gnus-completing-read call.
+
+       * gravatar.el (gravatar-retrieved): Kill buffer when gravatar has been
+       retrieved.
+
+2010-10-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (browse-url): Require.
+       (shr-ensure-paragraph): Don't insert a new newline after empty-ish
+       lines.
+       (shr-show-alt-text, shr-browse-image): New commands.
+       (shr-browse-url, shr-copy-url): New commands.
+
+       * gnus-sum.el (gnus-widen-article-window): New variable.
+       (gnus-summary-select-article-buffer): Use it.
+
+       * message.el (message-idna-to-ascii-rhs-1): Don't bug out on addresses
+       without @ signs.
+
+2010-10-04  Michael Welsh Duggan  <md5i@md5i.com>  (tiny change)
+
+       * nnir.el (nnir-run-imap): Remove spurious space in search string.
+
+2010-10-04  Julien Danjou  <julien@danjou.info>
+
+       * gnus-util.el (gnus-emacs-completing-read): Mapcar collection to list,
+       for XEmacs.
+
+2010-10-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-salt.el: Remove all gnus-carpal stuff -- it's not useful.
+
+       * nnimap.el (nnimap-open-connection): Allow tls as a synonym for ssl.
+       (nnimap-close-server): Implement.
+
+       * dgnushack.el (iswitchb): Require to shut up the compiler.
+
+       * shr.el (shr-ensure-paragraph): Fix the non-empty line case.
+       (shr-insert): Tweak line breaking.
+       (shr-insert): Handle <pre> better.
+       (shr-tag-li): Get <li> indentation right.
+       (shr-tag-li): Get <li> indentation even righter.
+       (shr-tag-blockquote): Ensure paragraph start.
+       (shr-make-table): Tweak table generation.
+       (shr-make-table): Fix typo.
+
+       * shr.el: Implement table rendering.
+
+2010-10-04  Julien Danjou  <julien@danjou.info>
+
+       * gnus-html.el (gnus-html-put-image): Fix resize image code.
+
+2010-10-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-insert): Use string anchors instead of line anchors.
+
+2010-10-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el: Add headings.
+       (shr-ensure-paragraph): Actually work.
+       (shr-tag-li): Make <ul> prettier.
+       (shr-insert): Get white space at the beginning/end of elements right.
+       (shr-tag-p): Collapse subsequent <p>s.
+       (shr-ensure-paragraph): Don't insert double line feeds after blank
+       lines.
+       (shr-insert): \t is also space.
+       (shr-tag-s): Fix "s" tag name function.
+       (shr-tag-s): Fix face prop name.
+
+2010-10-03  Julien Danjou  <julien@danjou.info>
+
+       * gnus-html.el (gnus-html-put-image): Use gnus-rescale-image.
+
+       * mm-view.el (gnus-window-inside-pixel-edges): Add autoload for
+       gnus-window-inside-pixel-edges.
+
+       * gnus-ems.el (gnus-window-inside-pixel-edges): Move from gnus-html to
+       gnus-ems.
+
+       * mm-view.el (mm-inline-image-emacs): Support image resizing.
+
+       * gnus-util.el (gnus-rescale-image): Add generic gnus-rescale-image
+       function.
+
+       * mm-decode.el (mm-inline-large-images): Enhance defcustom and add
+       resize choice.
+
+2010-10-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-tag-p): Don't insert newlines on empty tags at the
+       beginning of the buffer.
+
+       * gnus-sum.el (gnus-summary-select-article-buffer): Really select the
+       article buffer again.
+
+       * shr.el (shr-tag-p): Don't insert newlines at the start of the buffer.
+
+       * mm-decode.el (mm-shr): Narrow before inserting, so that shr can know
+       when it's at the start of the buffer.
+
+       * shr.el (shr-tag-blockquote): Convert name.
+       (shr-rescale-image): Use the right image-size variant.
+
+       * gnus-sum.el (gnus-summary-select-article-buffer): If the article
+       buffer isn't shown, then select the current article first instead of
+       bugging out.
+       (gnus-summary-select-article-buffer): Show both the article and summary
+       buffers again.
+
+       * shr.el (shr-fontize-cont): Protect against regions with no text.
+       Rename tag functions to shr-tag-* for enhanced security.
+       (shr-tag-ul, shr-tag-ol, shr-tag-li, shr-tag-br): New functions.
+
+2010-10-03  Chong Yidong  <cyd@stupidchicken.com>
+
+       * shr.el (shr-insert):
+       * pop3.el (pop3-movemail):
+       * gnus-html.el (gnus-html-wash-tags): Don't use plusp, as cl may not be
+       loaded.
+
+2010-10-03  Glenn Morris  <rgm@gnu.org>
+
+       * nnmairix.el (nnmairix-replace-illegal-chars): Drop Emacs 20 code.
+
+       * smime.el (smime-cert-by-ldap-1): Drop Emacs 21 code.
+
+       * gnus-art.el (gnus-next-page-map): Drop Emacs 20 compat cruft.
+
+       * gmm-utils.el (gmm-write-region): Drop Emacs 20 compat cruft.
+
+       * gnus-util.el (gnus-make-local-hook): Simplify.
+
+2010-10-02  Julien Danjou  <julien@danjou.info>
+
+       * gnus-util.el (gnus-iswitchb-completing-read): New function.
+       (gnus-ido-completing-read): New function.
+       (gnus-emacs-completing-read): New function.
+       (gnus-completing-read): Use gnus-completing-read-function.
+       Add gnus-completing-read-function.
+
+2010-10-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el (shr-insert-document): Autoload.
+       (shr-img): Be silent.
+       (shr-insert): Add a newline after every picture before text.
+       (shr-add-font): Use overlays for combining faces.
+       (shr-insert): Pass upwards the text start point.
+
+       * mm-decode.el (mm-text-html-renderer): Default to shr.el rendering, if
+       possible.
+       (mm-shr): New function.
+
+2010-10-02  Julien Danjou  <julien@danjou.info>
+
+       * gnus-gravatar.el (gnus-gravatar-insert): Adjust character where we
+       should go backward.
+
+2010-10-02  Juanma Barranquero  <lekktu@gmail.com>
+
+       * shr.el (shr): Fix typo in provide call.
+
+2010-10-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * shr.el: New file.
+
+       * gnus-html.el (gnus-html-schedule-image-fetching): Be silent.
+
+       * gnus-topic.el (gnus-topic-move-group): Fix the syntax of the
+       completing read.
+
+2010-10-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-check-bogus-newsgroups): Say how many groups
+       we're being queried about.  Suggested by Dan Jacobson.
+
+       * nndoc.el (nndoc-type-alist): Do babyl before mime-parts.
+       Suggested by Jason Eisner.
+
+       * gnus-async.el (gnus-async-delete-prefetched-entry): Remove from hash
+       table, too.  Suggested by Stefan Wiens.
+       (gnus-async-prefetched-article-entry): Use intern-soft to avoid growing
+       the table unnecessary.  Suggested by Stefan Wiens.
+
+       * gnus-sum.el (gnus-summary-clear-local-variables): This is probably no
+       longer needed, and probably doesn't work either, as pointed out by
+       Stefan Wiens.
+       (gnus-summary-exit): Remove call to the clearing function.
+       (gnus-summary-exit-no-update): Ditto.
+
+       * gnus-art.el (gnus-summary-save-in-file): Use with-current-buffer
+       instead of gnus-eval-in-buffer-window to avoid popping up frames.
+       Reported by Stefan Monnier.
+       (gnus-summary-save-in-rmail): Ditto.
+
+       * gnus-sum.el (gnus-summary-select-article-buffer): Show only the
+       article buffer, instead of both the article buffer and the summary
+       buffer.  Sort of suggested by Dan Jacobson.
+
+       * gnus-win.el (gnus-buffer-configuration): Add an only-article spec.
+
+       * nnmbox.el (nnmbox-read-mbox): Mark buffer for deletion on Gnus exit.
+       Suggested by Dan Jacobson.
+
+       * mm-encode.el (mm-content-transfer-encoding-defaults): Try to make the
+       documentation clearer.
+
+       * message.el (message-shorten-references): Comment on the number "21".
+       Suggested by Stefan Monnier.
+
+       * gnus-sum.el (gnus-summary-scroll-up): Add more documentation.
+       Suggested by Dan Jacobson.
+
+       * gnus.el (gnus-large-newsgroup):
+       Mention gnus-large-ephemeral-newsgroup.  Suggested by Dan Jacobson.
+
+       * gnus-msg.el (gnus-summary-resend-message): When resending, don't
+       externalize attachments.  Bug reported by Steve Wen.
+
+       * gnus.el (gnus-continuum-version): Make inactive, since it doesn't
+       really message anything to the user.
+
+       * nnmail.el (nnmail-article-group): Allow using the fancy split method
+       directly.
+
+       * nnimap.el (nnimap-request-group): Low higher than high to signal no
+       messages in empty groups.
+
+2010-10-01  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * nnimap.el (nnimap-request-group): Don't bug out when there's an empty
+       non-UIDNEXT group.
+
+2010-10-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-completing-read): Return the symbol name,
+       not the value from the collection.
+
+       * nnimap.el (nnimap-update-info): Ignore groups that have no UIDNEXT
+       values.  This sometimes happens on some groups that have no info.
+       (nnimap-request-newgroups): New function.
+
+2010-10-01  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-install-nnregistry): Move the feature
+       check into `gnus-registry-initialize'.
+       (gnus-registry-initialize): Ditto.
+       Fix and extend header docs.
+
+2010-10-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-html.el (gnus-html-prefetch-images): Adjust regexp to avoid
+       regexp backtrace overflows.
+
+       * nnimap.el (nnimap-extend-tls-programs): Only extend those programs
+       for starttls that tls.el implements; i.e. openssl.
+
+       * tls.el (tls-starttls-switches): Give up on using starttls with
+       gnutls-cli.
+       (tls-program): Add --insecure to be consistent with the defaults from
+       openssl s_client.  Now all three commands are insecure.
+
+2010-10-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Bind completion-styles-alist for XEmacs.
+
+       * gravatar.el: Don't load image.el that XEmacs doesn't provide.
+       (gravatar-create-image): New function that's an alias to
+       gnus-xmas-create-image, gnus-create-image, or create-image.
+       (gravatar-data->image): Use it.
+
+2010-09-30  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-install-nnregistry): New function to
+       install the nnregistry refer method.
+       (gnus-registry-install-hooks): Use it.
+       (gnus-registry-unfollowed-groups): Add nnmairix to the default
+       unfollowed groups.
+
+2010-09-30  Jose A. Ortega Ruiz  <jao@gnu.org>  (tiny change)
+
+       * gnus-sum.el (gnus-summary-show-thread): Skip past invisible text when
+       expanding threads.
+
+2010-09-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnir.el: Use the server names without suffixes (bug#7009).
+
+       * nnimap.el (nnimap-open-connection): Reinstate the auto-upgrade from
+       unencrypted to STARTTLS, if possible.
+
+2010-09-30  Teemu Likonen  <tlikonen@iki.fi>  (tiny change)
+
+       * message.el (message-ignored-supersedes-headers): Strip Injection-*
+       headers before superseding.
+
+2010-09-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnrss.el (nnrss-use-local): Add documentation.
+
+       * nnimap.el (nnimap-extend-tls-programs): New function.
+       (nnimap-open-connection): Use tls.el exclusively, and not starttls.el.
+       (nnimap-wait-for-connection): Accept the greeting from the stupid
+       output from openssl s_client -starttls, too.
+
+       * tls.el (tls-starttls-switches): New variable.
+       (tls-find-starttls-argument): Use it.
+       (open-tls-stream): Ditto.
+
+       * netrc.el (netrc-credentials): Return the value of the "default" entry.
+       (netrc-machine): Ditto.
+
+       * nnimap.el (nnimap-find-article-by-message-id): Really return the
+       article number.
+       (nnimap-split-fancy): New variable.
+       (nnimap-split-incoming-mail): Use it.
+
+       * nntp.el (nntp-server-list-active-group): Document.
+
+       * nnimap.el (nnimap-find-article-by-message-id): Use EXAMINE instead of
+       SELECT to get the message-id.
+
+       * mail-source.el (mail-sources): Remove webmail support.
+       (defvar): Ditto.
+       (mail-source-fetcher-alist): Ditto.
+       (mail-source-fetch-webmail): Remove.
+
+       * webmail.el: Remove -- doesn't seem relevant any more.
+
+       * gnus.el: Fix up make-obsolete-variable declarations throughout.
+
+       * nnimap.el (nnimap-request-accept-article): Get the Message-ID without
+       the \r.
+
+2010-09-30  Julien Danjou  <julien@danjou.info>
+
+       * gnus-agent.el (gnus-agent-add-group): Fix call to
+       gnus-completing-read.
+
+2010-09-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nndoc.el (nndoc-retrieve-groups): New function.
+
+       * nnimap.el (nnimap-split-incoming-mail): If nnimap-split-methods is
+       `default', use nnmail-split-methods.
+       (nnimap-request-article): Downcase the NILs so that they are nil.
+
+       * gnus-sum.el (gnus-valid-move-group-p): Make sure that `group' is a
+       symbol.
+
+       * nnimap.el (nnimap-open-connection): Revert the auto-network->starttls
+       code, since if the user has requested network, that's what they ought
+       to get.
+       (nnimap-request-set-mark): Erase the buffer before issuing commands.
+       (nnimap-split-rule): Mark as obsolete.
+
+       * pop3.el (pop3-send-streaming-command, pop3-stream-length):
+       New variable.
+
+       * nnimap.el (nnimap-insert-partial-structure): Get the type from the
+       correct slot, too.
+
+2010-09-29  Julien Danjou  <julien@danjou.info>
+
+       * gnus.el (gnus-local-domain): Declare variable obsolete.
+
+       * gnus-util.el (gnus-icompleting-read): Require iswitchb.
+       Fix history computing.
+       (gnus-ido-completing-read): Require ido.
+
+2010-09-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-registry.el: Don't prompt on load, which makes it impossible to
+       build Gnus.
+
+       * nnimap.el (nnimap-insert-partial-structure): Be way more permissive
+       when interpreting the structures.
+       (nnimap-request-accept-article): Add \r\n to the lines to make this
+       work with Cyrus.
+
+       * nndraft.el (nndraft-request-expire-articles): Use the group name
+       instead if "nndraft".  Fix found by Nils Ackermann.
+
+2010-09-29  Ludovic Courtès  <ludo@gnu.org>
+
+       * nnregistry.el: Add.
+
+2010-09-29  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * nnmail.el (group, group-art-list, group-art):
+       Remove unneeded directives.
+
+2010-09-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-codepage-iso-8859-list, mm-charset-eval-alist)
+       (mm-mime-charset):
+       * rfc2047.el (rfc2047-syntax-table):
+       * utf7.el (utf7-utf-16-coding-system): Comment fix.
+
+       * nnrss.el (nnrss-read-server-data, nnrss-read-group-data): Use `load'
+       rather than `insert-file-contents' and `eval-region'.
+
+       * pgg.el (pgg-run-at-time-1): Define it for XEmacs only; fix if/else
+       construction.
+
+       * smime-ldap.el (smime-ldap-search): Remove Emacs 21 compatible code.
+
+       * time-date.el: No need to require cl for Emacs 21.
+
+2010-09-29  Julien Danjou  <julien@danjou.info>
+
+       * gnus-gravatar.el (gnus-gravatar-properties): Add this properties in
+       replacement of `gnus-gravatar-relief' to mimic
+       `gnus-faces-properties-alist'.
+       Add :version property.
+
+2010-09-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mail-source.el (mail-source-report-new-mail):
+       * message.el (message-default-mail-headers):
+       * mm-decode.el (mm-valid-image-format-p): Comment fix.
+
+       * mml2015.el (mml2015-use): Don't bind recursive-load-depth-limit.
+
+2010-09-28  Julien Danjou  <julien@danjou.info>
+
+       * gnus-gravatar.el (gnus-gravatar-insert): Fix search in case
+       mail-address contains the same string as real-name.
+
+       * gnus-ems.el (gnus-put-image): Revert Lars, change and insert
+       non-blank in header, otherwise it'll get stripped.
+
+       * gnus-gravatar.el (gnus-gravatar-insert): Search backward for
+       real-name, and then for mail address rather than doing : or , search.
+
+2010-09-27  Julien Danjou  <julien@danjou.info>
+
+       * gnus-util.el (gnus-completing-read): Use gnus-use-ido to apply the
+       right completing-read function.
+       (gnus-use-ido): New variable
+       (gnus-completing-read-with-default): Remove.
+       * gnus-agent.el (gnus-agent-read-group): Remove prompt computing.
+       (gnus-agent-add-group):
+       * gnus-srvr.el (gnus-server-add-server, gnus-server-goto-server):
+       * mm-view.el (mm-view-pkcs7-decrypt):
+       * mm-util.el (mm-codepage-setup):
+       * smime.el (smime-sign-buffer, smime-decrypt-buffer):
+       * mml-smime.el (mml-smime-openssl-sign-query):
+       * mml.el (mml-minibuffer-read-type, mml-minibuffer-read-disposition)
+       (mml-insert-multipart):
+       * gnus-msg.el (gnus-summary-yank-message):
+       * gnus-int.el (gnus-start-news-server):
+       * mm-decode.el (mm-interactively-view-part):
+       * gnus-dired.el (gnus-dired-attach):
+       * gnus.el (gnus-read-method):
+       * gnus-bookmark.el (gnus-bookmark-jump):
+       * gnus-art.el (gnus-mime-view-part-as-type)
+       (gnus-mime-action-on-part, gnus-article-encrypt-body):
+       * gnus-topic.el (gnus-topic-jump-to-topic, gnus-topic-move-matching)
+       (gnus-topic-copy-matching, gnus-topic-sort-topics, gnus-topic-move):
+       * nnmairix.el (nnmairix-create-server-and-default-group)
+       (nnmairix-update-groups, nnmairix-get-server)
+       (nnmairix-backend-to-server, nnmairix-goto-original-article)
+       (nnmairix-get-group-from-file-path):
+       * nnrss.el (nnrss-find-rss-via-syndic8):
+       * gnus-group.el (gnus-group-completing-read, gnus-group-make-web-group)
+       (gnus-group-make-useful-group, gnus-group-add-to-virtual)
+       (gnus-group-browse-foreign-server):
+       * gnus-sum.el (gnus-summary-goto-article, gnus-summary-limit-to-extra)
+       (gnus-summary-execute-command, gnus-summary-respool-article)
+       (gnus-read-move-group-name):
+       * gnus-score.el (gnus-summary-increase-score)
+       (gnus-summary-score-effect):
+       * gnus-registry.el (gnus-registry-read-mark): Use gnus-completing-read.
+
+2010-09-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Remove url-http-file-exists-p, w32-focus-frame, and
+       x-focus-frame.
+
+       * nnimap.el (auth-source-forget-user-or-password)
+       (auth-source-user-or-password): Autoload.
+
+       * message.el (message-from-style, message-interactive)
+       (message-cite-prefix-regexp, message-sendmail-envelope-from)
+       (message-yank-prefix, message-indentation-spaces, message-signature)
+       (message-signature-file): Add comment.
+
+2010-09-27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-read-group-1): Set gnus-newsgroup-highest.
+       (gnus-summary-insert-new-articles): Use gnus-newsgroup-highest to get
+       new articles.
+
+       * nnimap.el (nnimap-request-article): Don't partial-fetch single-part
+       parts.
+       (nnimap-request-article): Work with the t setting, too.
+
+       * gnus-sum.el (gnus-summary-exit): Kill the article buffer later, so
+       that you don't get flashes of other buffers.
+       (gnus-summary-show-complete-article): Intern before setting.
+
+2010-09-27  David Engster  <dengste@eml.cc>
+
+       * nnmairix.el (nnmairix-replace-group-and-numbers): Deal with NOV as
+       well as HEADERS.
+       (nnmairix-retrieve-headers): Provide new argument for the above.
+
+2010-09-27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-move-article): Don't alter
+       gnus-newsgroup-active.  This makes `/ N' work after copying to the same
+       group.
+
+       * nnimap.el (nnimap-update-info): Don't destructively alter active.
+
+       * message.el (message-cite-prefix-regexp): Revert my last edit.
+
+       * gnus-sum.el (gnus-summary-show-complete-article): Bind the server
+       variable instead of the Gnus variable.
+
+       * nnimap.el (nnimap-find-wanted-parts-1): Use it.
+
+       * gnus-art.el (gnus-fetch-partial-articles): Move back to nnimap again.
+
+       * nnimap.el (nnimap-request-accept-article): Remove the "." at the end,
+       since some servers don't like it.
+       (nnimap-open-connection): Forget credentials if the server says the
+       password was wrong.
+       (nnimap-parse-line): Protect against invalid data.
+
+       * gnus-sum.el (gnus-summary-move-article): Add comment.
+       (gnus-summary-insert-new-articles): Copy the old-high watermark so that
+       nothing alters it while scanning for new messages.
+
+       * nnimap.el (nnimap-request-accept-article): Send a "." at the end,
+       which may or may not help.
+       (nnimap-open-connection): If we're doing a stream connection, and then
+       discover we're on a STARTTLS-capable server, then open a STARTTLS
+       connection instead.
+
+2010-09-27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (utf7): Require.
+
+       * message.el (message-cite-prefix-regexp): Remove "}" from citation
+       prefix.
+
+2010-09-27  Juanma Barranquero  <lekktu@gmail.com>
+
+       * nnmail.el (nnmail-fancy-expiry-targets): Fix typo in docstring.
+
+2010-09-27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-request-accept-article): Message the error on
+       error.
+
+2010-09-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-delete-part): Fix Lisp type of byte(s).
+
+2010-09-26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nndoc.el (nndoc-request-list): Return success always.
+
+       * gnus-agent.el (gnus-agent-retrieve-headers): Don't propagate
+       `fetch-old' -- we only want to fetch the articles we've requested.
+       The rest are in the agent, probably.
+       (gnus-agent-read-servers-validate): Change the level for the "Ignoring
+       disappeared server" to something low.  It's not important.
+
+       * nnimap.el (nnimap-get-whole-article): Remove the data that may have
+       arrived before the FETCH data.
+
+       * nnmh.el (nnmh-request-expire-articles): Don't try to fetch the expiry
+       target here, because we don't know the Gnus name of the group.
+
+       * nndraft.el (nndraft-request-expire-articles): Fetch the expiry target
+       for the correct group.
+
+       * gnus-ems.el (gnus-create-image): Ignore all image-creation errors.
+
+       * gnus.el (gnus): Give a final warning after startup.
+
+       * gnus-util.el (gnus-action-message-log): New variable.
+       (gnus-message): Use it.
+       (gnus-final-warning): New function.
+
+       * nnimap.el (nnimap-open-connection): Record the greeting.
+       (nnimap): Add greeting.
+
+2010-09-26  Julien Danjou  <julien@danjou.info>
+
+       * gnus-html.el (gnus-html-show-images): Fix gnus-html-display-image
+       arguments.
+       (gnus-html-wash-images): Fix spec computing to include start/end.
+
+       * gnus-art.el (gnus-article-treat-body-boundary): Fix length computing.
+
+2010-09-26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-request-expire-articles): Compress ranges before
+       deletion.
+       (nnimap-retrieve-headers): Don't select the group, because that's
+       already done by nnimap-possibly-change-group.
+
+       * gnus-picon.el (gnus-picon-inhibit-top-level-domains): New variable.
+       (gnus-picon-transform-address): Use it.
+
+       * mail-source.el (mail-source-value): Revert previous patch.
+
+       * nnimap.el (nnimap-credentials): Allow inhibiting the password query
+       on failure.
+       (nnimap-open-connection): Look up both virtual and physical server name
+       credentials.
+
+       * gnus-win.el: Revert previous patch, since it made Gnus backtrace.
+
+2009-02-07  Dave Love  <fx@gnu.org>
+
+       * tls.el (open-tls-stream): Don't query killing process.
+
+2009-02-08  Dave Love  <fx@gnu.org>
+
+       * gnus-win.el (gnus-window-to-buffer-helper)
+       (gnus-all-windows-visible-p): Function needn't be a symbol.
+
+       * mail-source.el (mail-source-value): Function needn't be a symbol.
+
+2010-09-26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-cite-prefix-regexp): Remove } from the cite
+       prefix.
+
+       * gnus-art.el (gnus-treatment-function-alist): Do picons before
+       highlight again, so that the highlight is correct.
+
+       * gnus-picon.el (gnus-picon): Remove again.
+       (gnus-picon-create-glyph): Set the background XPM color explicitly.
+
+       * gnus-art.el (gnus-treatment-function-alist): Insert picons after
+       doing the header highlightling, so that the background color of the
+       picon is correct.
+
+       * gnus-picon.el (gnus-picon-xbm): Remove obsolete face.
+       (gnus-picon): Ditto.
+       (gnus-picon): Reinstate.  The background color for picons is white.
+       (gnus-picon-insert-glyph): Make the background white.
+
+       * nnml.el (nnml-open-nov): Don't return dead buffers.
+
+       * auth-source.el (auth-source-create): Query the user for whether to
+       store the credentials.
+
+       * netrc.el (netrc-store-data): New function.
+
+       * auth-source.el (auth-source-user-or-password): Use the existing auth
+       sources, if any, for creation.
+
+       * gnus.el (gnus-group-fast-parameter): Return the last matching
+       parameter instead of the first matching parameter.
+
+2010-09-26  Julien Danjou  <julien@danjou.info>
+
+       * gnus-sum.el (gnus-auto-center-group): Transform into a defcustom.
+
+2010-09-26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml2015.el (mml2015-use): Remove gpg support.
+
+       * mml1991.el (mml1991-function-alist): Remove gpg function.
+       (mml1991-gpg-sign): Remove.
+
+2010-09-26  Andreas Seltenreich  <seltenreich@gmx.de>
+
+       * gnus-srvr.el (gnus-browse-subscribe-newsgroup-method): New variable.
+       (gnus-browse-unsubscribe-current-group): Document it.
+       (gnus-browse-unsubscribe-group): Use it.
+
+2010-09-26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-read-ephemeral-bug-group): Add the bug email
+       address to the To list for easier response.
+
+       * gnus.el (gnus-play-startup-jingle): Remove.
+       (gnus-splash): Don't play jingle.
+       (gnus): Silence gnus-load message.
+
+       * gnus-art.el (gnus-treat-play-sounds): Remove.
+
+       * gnus.el (gnus-play-jingle): Remove audio support.
+
+       * gnus-cus.el (gnus-score-customize): Remove audio reference.
+
+       * earcon.el: Remove -- no users.
+
+       * gnus-audio.el: Remove -- no users of this package.
+
+       * gnus-sum.el (gnus-summary-limit-children): Remove nocem support.
+
+       * gnus-start.el (gnus-setup-news): Remove nocem support.
+
+       * gnus-group.el (gnus-group-get-new-news): Remove nocem call.
+
+       * gnus.el (gnus-use-nocem): Remove.
+
+       * gnus-demon.el (gnus-demon-add-nocem, gnus-demon-scan-nocem):
+       Remove.
+
+       * gnus-nocem.el (gnus-nocem-issuers): Remove file.  Apparently nobody
+       uses NoCeM any more.
+
+       * gnus-art.el (gnus-ctan-url): Seems not very useful -- removed.
+       (gnus-button-ctan-handler): Ditto.
+       (gnus-button-handle-ctan-bogus-regexp): Ditto.
+       (gnus-button-ctan-directory-regexp): Ditto.
+       (gnus-button-handle-ctan): Ditto.
+       (gnus-button-tex-level): Ditto.
+       (gnus-button-alist): Remove CTAN stuff.
+
+2010-09-25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-wait-for-response): Reverse logic in the
+       nnimap-streaming test.
+
+       * gnus-start.el (gnus-get-unread-articles): Don't try to open failed
+       servers twice.
+
+       * nnimap.el (nnimap-open-connection): Add more error reporting when
+       nnimap fails early.
+
+       * nnheader.el (nnheader-get-report-string): New function.
+       (nnheader-get-report): Use it.
+
+       * gnus-int.el (gnus-check-server): Say what the error was when opening
+       failed.
+
+       * nnimap.el (nnimap-wait-for-response): Search further when we're not
+       using streaming.
+
+2010-09-25  Julien Danjou  <julien@danjou.info>
+
+       * gnus-html.el (gnus-html-rescale-image): Use our defalias
+       gnus-window-inside-pixel-edges.
+
+2010-09-25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-srvr.el (gnus-server-copy-server): Add documentation.
+
+       * mm-decode.el (mm-save-part): Allow saving to other directories the
+       normal Emacs way.
+
+       * nndoc.el (nndoc-type-alist): Move mime-parts after mbox.
+       Suggested by Jay Berkenbilt.
+
+       * gnus-art.el (gnus-mime-delete-part): Fix plural for "byte" when
+       there isn't a single byte.
+
+       * gnus-int.el (gnus-open-server): Don't query whether to go offline --
+       just do it.  It doesn't really seem to matter what the user responds
+       here, I think, so it's just a confusing question.
+
+       * nnimap.el (nnimap-retrieve-group-data-early): Fix typo in the
+       non-streaming case.
+
+       * gnus-art.el (gnus-flush-original-article-buffer): Separate out.
+       (gnus-article-encrypt-body): Use it.
+
+       * gnus-sum.el (gnus-summary-show-complete-article): New command and
+       keystroke.
+
+       * nnimap.el (nnimap-find-wanted-parts-1):
+       Use gnus-fetch-partial-articles.
+
+       * gnus-art.el (gnus-fetch-partial-articles): New variable.
+
+       * nnimap.el (nnimap-insert-partial-structure): New function.
+       (nnimap-get-partial-article): New function.
+       (nnimap-request-article): Use it.
+       (nnimap-wait-for-response): Return whether the wait was successful.
+       (nnimap-finish-retrieve-group-infos): Don't do anything if the
+       retrieval wasn't successful.
+       (nnimap-retrieve-group-data-early): Allow throttling servers.
+       (nnimap-streaming): New variable.
+       (nnimap-fetch-partial-articles): Remove.
+
+       * mm-decode.el (mm-with-part): Protect against killed buffers.
+
+       * nndraft.el (nndraft-retrieve-headers): Insert Lines and Chars headers
+       for prettier summary display.
+
+2010-09-25  Andrew Cohen  <cohen@andy.bu.edu>  (tiny change)
+
+       * nnir.el (nnir-run-imap): Allow sending IMAP search patterns directly.
+
+2010-09-25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-local-domain): Put gnus-local-domain back again, since
+       apparently third-party libraries depend on it.
+
+       * nnimap.el (nnimap-open-connection): Wait for the response to STARTTLS
+       before starting negotiation.
+
+       * gnus-art.el (gnus-treat-from-gravatar): Change default to nil for
+       privacy reasons.
+       (gnus-treat-mail-gravatar): Ditto.
+
+       * gnus-ems.el (gnus-put-image): Don't put any non-blank text into the
+       buffer when inserting images.  Inserting text into the headers, for
+       instance, can make them invalid.
+
+2010-09-25  Julien Danjou  <julien@danjou.info>
+
+       * rfc1843.el: Remove useless rfc1843-old-gnus-decode-header-function
+       variables.
+
+       * nnheader.el: Remove useless variables news-reply-yank-from and
+       news-reply-yank-message-id.
+
+       * mml2015.el: Remove useless mc-default-scheme and mc-schemes
+       variables.
+
+       * mml1991.el: Remove useless mml1991-verbose.
+
+       * gnus.el: Remove useless variable gnus-use-generic-from.
+       Remove obsolete variable gnus-topic-indentation.
+
+       * gnus-uu.el: Remove useless gnus-uu-shar-file-name.
+
+       * gnus-sum.el: Remove useless gnus-newsgroup-none-id.
+
+       * gnus-picon.el: Remove useless gnus-picon-setup-p variable.
+
+       * gnus-group.el: Remove useless gnus-group-icon-cache.
+       Remove useless gnus-ephemeral-group-server.
+
+       * gnus-bookmark.el: Remove useless gnus-bookmark-after-jump-hook.
+
+       * mml2015.el: Remove useless mml2015-verbose.
+
+       * mml-smime.el: Remove useless mml-smime-verbose.
+
+       * gnus.el: Remove useless gnus-local-domain.
+
+       * gnus-gravatar.el (gnus-gravatar-transform-address):
+       Use gnus-gravatar-size.
+
+       * gnus-art.el: Remove useless gnus-treat-translate.
+
+2010-09-24  Julien Danjou  <julien@danjou.info>
+
+       * gnus-sum.el: Add support for Gravatars.
+
+       * gnus-art.el: Add support for Gravatars.
+
+       * gnus-gravatar.el: Add this file.
+
+       * gravatar.el: Add this file.
+
+2010-09-24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-fetch-faq): Remove.
+
+       * gnus-group.el (gnus-group-fetch-faq): Remove.
+
+       * gnus.el (gnus-group-faq-directory): Remove.
+
+       * gnus-group.el (gnus-group-fetch-charter): Remove.
+
+       * gnus.el (gnus-group-charter-alist): Remove.
+
+       * gnus-group.el (gnus-group-archive-directory): Remove.
+       (gnus-group-recent-archive-directory): Ditto.
+       (gnus-group-make-archive-group): Remove.
+
+       * nnimap.el (nnimap-update-info): Protect against nil uidnexts.
+
+       * gnus-cache.el (gnus-cache-braid-heads): When braiding heads, don't
+       use the same article number for all the cached articles.
+
+       * nnimap.el (nnimap-command): Register the last command time so
+       that we can use it for idling NOOPs.
+       (nnimap-open-connection): Start the keeplive timer.
+       (nnimap-make-process-buffer): Store all the process buffers.
+       (nnimap-keepalive): New function.
+
+       * starttls.el (starttls-open-stream): Add autoload cookie.
+
+2010-09-24  Michael Welsh Duggan  <md5i@md5i.com>  (tiny change)
+
+       * nnimap.el (nnimap-split-incoming-mail): Fix paren typo in the 'junk
+       handling.
+
+2010-09-24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnrss.el (nnrss-retrieve-groups): Change to the group before checking
+       its data structures.
+
+       * gnus.el (gnus-sloppily-equal-method-parameters): Use copy-sequence
+       instead of the cl.el copy-list.
+       (gnus-sloppily-equal-method-parameters): Use equal instead of the cl
+       equalp.
+
+2010-09-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gmm-utils.el (gmm-tool-bar-from-list): Always use tool-bar-local-item
+       and tool-bar-local-item-from-menu.
+
+       * gnus-agent.el (gnus-agent-make-mode-line-string): Always use
+       mode-line-highlight face for Emacs.
+
+       * gnus-art.el (toplevel): Don't bind recursive-load-depth-limit while
+       loading gnus-sum.elc; fix comment for canlock-verify.
+       (gnus-article-jump-to-part): Use read-number.
+       (gnus-insert-mime-button, gnus-insert-mime-security-button):
+       Remove Emacs pre-21 compatible code for help-echo.
+       (gnus-article-next-page-1): No need to adjust the number of lines.
+       (gnus-article-describe-bindings): Always use help-buffer.
+
+       * gnus-audio.el (gnus-audio-inline-sound):
+       * gnus-cus.el (gnus-custom-mode):
+       * gnus-group.el (gnus-group-update-tool-bar): Comment fix.
+
+       * gnus-sum.el (gnus-remove-overlays): Doc fix.
+
+       * gnus-util.el (gnus-select-frame-set-input-focus): Remove Emacs 21
+       compatible code.
+
+2010-09-24  Glenn Morris  <rgm@gnu.org>
+
+       * message.el (message-output): Use gnus-output-to-rmail if a buffer is
+       visiting the fcc file in rmail-mode.
+
+       * dns-mode.el: Move autoloaded auto-mode-alist entries to files.el.
+
+2010-09-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnir.el: Silence the byte compiler.
+
+       * gnus-html.el (gnus-html-encode-url-chars): New function, that's an
+       alias to browse-url-url-encode-chars if any.
+       (gnus-html-encode-url): Use it.
+
+2010-09-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-use-backend-marks): New variable.
+       (gnus-get-unread-articles-in-group): Use it.
+
+       * gnus-sum.el (gnus-summary-local-variables): Prepare for list/range
+       makeover.
+
+2010-09-23  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnimap.el (nnimap-retrieve-headers): Return 'headers.
+
+2010-09-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-fixup-nnimap-unread-after-getting-new-news):
+       Remove.
+       (gnus-setup-news-hook):
+       Remove gnus-fixup-nnimap-unread-after-getting-new-news.
+
+       * gnus-int.el (gnus-request-update-info): Protect against backends not
+       having the function.
+
+       * nnimap.el (nnimap-stream): Mention starttls.
+       (nnimap-open-connection): Add starttls support.
+
+2010-09-23  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * nnir.el (nnir-run-imap): Fix up nnir to work with the new nnimap.
+
+2010-09-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-transform-headers): Don't bug out on invalid
+       BODYSTRUCTUREs.
+       (nnimap-transform-headers): Unfold quoted {42} headers.
+
+       * gnus-start.el (gnus-get-unread-articles): Allow backends to update
+       the info.
+       (gnus-get-unread-articles): Only call updatep on backends that support
+       it.
+
+       * nnweb.el (nnweb-request-update-info): NOOP.
+
+       * nnmaildir.el (nnmaildir-request-marks): Rename from -update-info.
+
+       * nnfolder.el (nnfolder-request-marks): Rename from -update-info,
+       since it only deals with marks.
+
+       * gnus-int.el (gnus-request-marks): Rename gnus-request-update-info to
+       gnus-request-marks, and make a new gnus-request-update-info.
+
+       * nnimap.el (nnimap-update-info): When UIDNEXT is present, use that for
+       the active instead of the high number, which is usually too low.
+
+2010-09-23  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * netrc.el (netrc-parse): Remove encrypt.el mentions.
+       * encrypt.el: Remove.
+
+2010-09-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-update-info): Sync non-standard flags from the
+       server in symbolic form.
+
+       * gnus-html.el (gnus-max-image-proportion): Increase proportion to 0.9.
+
+2010-09-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-parse-flags): Parse the data in any order.
+       (nnimap-update-info): Fix up code slightly.
+
+       * gnus-int.el (gnus-open-server): Add tracing for performance
+       debugging.
+
+       * gnus-group.el (gnus-group-highlight-line): Typo fix: beg, not start.
+       (gnus-group-insert-group-line): Pass the real group name so that it
+       gets the right data.
+
+       * gnus-start.el (gnus-get-unread-articles): Don't have
+       `gnus-get-unread-articles-in-group' update info, since that can be
+       really slow and doesn't seem to be needed?
+
+2010-09-22  Dan Christensen  <jdc@uwo.ca>
+
+       * time-date.el (date-to-time): Try using parse-time-string first before
+       using the slower timezone-make-date-arpa-standard.
+
+2010-09-22  Julien Danjou  <julien@danjou.info>
+
+       * gnus-group.el (gnus-group-insert-group-line):
+       Call gnus-group-highlight-line.
+       (gnus-group-update-hook): Remove gnus-group-highlight-line from the
+       default hook list.
+       (gnus-group-update-eval-form): Add new function.
+       (gnus-group-highlight-line): Use gnus-group-update-eval-form.
+       (gnus-group-get-icon): Use gnus-group-update-eval-form.
+
+2010-09-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-request-expire-articles): If nnmail-expiry-wait is
+       immediate, then expire all articles.
+       (nnimap-update-info): Fix off-by-one errors.
+       (nnimap-flags-to-marks): Would return no marks lists for group with no
+       flags.  Instead return the other data.
+
+2010-09-22  Julien Danjou  <julien@danjou.info>
+
+       * gnus-group.el (gnus-group-get-icon): Rename gnus-group-add-icon that
+       Only return an icon.
+       (gnus-group-insert-group-line): Compute icon to return.
+
+       * gnus-html.el (gnus-html-image-automatic-caching): Add custom var.
+       (gnus-html-image-fetched): Only cache if
+       gnus-html-image-automatic-caching is set.
+       (gnus-html-image-fetched): Check for errors.
+
+2010-09-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-read-active-for-groups): Only run -request-scan
+       once per method on `g'.  This ensures that backends like nnfolder don't
+       open all their folders.
+
+       * nnimap.el (nnimap-split-incoming-mail): Delete 'junk.
+       (nnimap-request-list): Nix out group in the correct buffer.
+       (nnimap-parse-flags): Implement by using `read' instead of
+       hand-parsing.
+       (nnimap-flags-to-marks): Pass on permanent-flags.
+       (nnimap-make-process-buffer): Record the server name.
+       (nnimap-parse-flags): Fix typo.
+       (nnimap-request-scan): Run split on the server in general, not just a
+       single group.
+
+       * nnmail.el (nnmail-split-incoming): Take an optional junk-func
+       parameter, and propagate this downwards.
+
+       * nnimap.el (nnimap-request-list): Set the current nnimap group to nil,
+       since EXAMINE changes it on the server.
+
+       * gnus-int.el (gnus-request-expire-articles): Inhibit the daemon, since
+       this command might take a while.
+
+2010-09-22  Julien Danjou  <julien@danjou.info>
+
+       * gnus-html.el (gnus-html-put-image): Stop using markers.  They are
+       harmful if you have 2 images side-by-side, they can't be properly
+       update on text deletion.  Using text-property is safer here.
+       (gnus-html-image-fetched): Search also for \r\n\r\n to get the start of
+       data.
+
+2010-09-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-expunge-inbox): Remove.
+       (nnimap-mark-and-expunge-incoming): Use nnimap-expunge instead.
+       (nnimap-expunge): Flip default to t.
+
+       * gnus.el (gnus-method-to-server): Don't push things to the cache
+       unless it's unique.
+       (gnus-server-to-method): Ditto.
+
+2010-09-22  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * nnimap.el (nnimap-delete-article): Tell user if expunge won't happen.
+
+2010-09-22  Julien Danjou  <julien@danjou.info>
+
+       * gnus-html.el (gnus-html-get-image-data): Search also for \r\n\r\n to
+       get the start of data.
+       (gnus-html-encode-url): Add this function to encode special chars in
+       URL.
+       (gnus-html-wash-images): Use gnus-html-encode-url to encode URL.
+       (gnus-html-prefetch-images): Use gnus-html-encode-url to encode URL.
+
+       * gnus-group.el (gnus-group-update-hook): Call gnus-group-add-icon by
+       default.
+       (gnus-group-add-icon): Move to gnus-group.el, and rewrite so it works.
+
+       * gnus-html.el (gnus-html-wash-images): Use xml-substitute-special on
+       images alt-text.
+       (gnus-html-put-image): Put alt-text as help-echo.
+
+2010-09-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mailcap.el (mailcap-parse-mailcap, mailcap-parse-mimetypes):
+       * mm-util.el (mm-decompress-buffer):
+       * nnir.el (nnir-run-find-grep):
+       * pop3.el (pop3-list): Use 3rd arg of split-string.
+
+       * time-date.el (format-seconds): Comment fix.
+
+       * dgnushack.el (toplevel): Don't advise byte-optimize-form-code-walker
+       and byte-optimize-form-code-walker.
+       (dgnushack-make-auto-load): Don't advise make-autoload.
+
+       * lpath.el: Remove Emacs 21 stuff.
+
+2010-09-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-update-marks): Add sanity check to not delete marks
+       outside the active range.  Suggested by Dan Christensen.
+
+       * gnus-start.el (gnus-get-unread-articles): Get the extended method
+       slightly later to avoid double-getting it.
+
+       * nnml.el (nnml-generate-nov-file): Fix variable name clobbering from
+       previous patch.
+
+       * gnus-sum.el (gnus-adjust-marked-articles): Fix another typo.
+
+2010-09-21  Adam Sjøgren  <asjo@koldfront.dk>
+
+       * gnus-sum.el (gnus-adjust-marked-articles): Fix typo.
+
+2010-09-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-int.el (gnus-open-server): Give a better error message in the
+       "go offline" case.
+
+       * gnus-sum.el (gnus-adjust-marked-articles): Hack to avoid adjusting
+       marks for nnimap, which is seldom the right thing to do.
+
+       * gnus.el (gnus-sloppily-equal-method-parameters): Refactor out.
+       (gnus-same-method-different-name): New function.
+
+       * nnimap.el (parse-time): Require.
+
+       * gnus-start.el (gnus-get-unread-articles): Fix the prefixed select
+       method in the presence of many similar methods.
+
+       * nnmail.el (nnmail-expired-article-p): Fix typo: time-subtract.
+
+       * nnimap.el (nnimap-find-expired-articles): Don't refer to
+       nnml-inhibit-expiry.
+
+       * gnus-sum.el (gnus-summary-move-article): Use gnus-server-equal to
+       find out whether methods are equal.
+
+       * nnimap.el (nnimap-find-expired-articles): New function.
+       (nnimap-process-expiry-targets): New function.
+       (nnimap-request-move-article): Request the article before looking at
+       what the Message-ID is.  Fix found by Andrew Cohen.
+       (nnimap-mark-and-expunge-incoming): Wait for the last sequence.
+
+       * nnmail.el (nnmail-expired-article-p): Allow returning the cutoff time
+       for oldness in addition to being a predicate.
+
+       * nnimap.el (nnimap-request-group): When we have zero articles, return
+       the right data to Gnus.
+       (nnimap-request-expire-articles): Only delete articles immediately if
+       the target is 'delete.
+
+       * gnus-sum.el (gnus-summary-move-article): When respooling to the same
+       method, this would bug out.
+
+       * gnus-group.el (gnus-group-expunge-group): Rename from
+       gnus-group-nnimap-expunge, and implemented as a normal interface
+       function.
+
+       * gnus-int.el (gnus-request-expunge-group): New function.
+
+       * nnimap.el (nnimap-request-create-group): Implement.
+       (nnimap-request-expunge-group): New function.
+
+2010-09-21  Julien Danjou  <julien@danjou.info>
+
+       * gnus-html.el (gnus-html-image-cache-ttl): Add new variable.
+       (gnus-html-cache-expired): Add new function.
+       (gnus-html-wash-images): Use `gnus-html-cache-expired' to check
+       wethever we should display image for fetch it.
+       Compute alt-text earlier to pass it to the fetching function too.
+       (gnus-html-schedule-image-fetching): Change function argument to only
+       get one image at a time, not a list.
+       (gnus-html-image-fetched): Use `url-store-in-cache' to store image in
+       cache.
+       (gnus-html-get-image-data): New function to retrieve image data from
+       cache.
+       (gnus-html-put-image): Change buffer argument to use image data rather
+       than file, and place image above region rather than inserting a new
+       one.  Do not take alt-text as argument, since it's useless now: we place
+       the image above alt-text.
+       (gnus-html-prune-cache): Remove.
+       (gnus-html-show-images): Start to fetch image when we find one, do not
+       push into a temporary list.
+       (gnus-html-prefetch-images): Only fetch image if they have expired.
+       (gnus-html-browse-image): Fix, use 'gnus-image-url.
+       (gnus-html-image-map): Add "v" to browse-url on undisplayed image.
+
+2010-09-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-encode-parameter): Doc fix.
+
+2010-09-20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-line-format-alist): Have the ?U (unseen)
+       spec inser "*" if the group isn't active instead of 0.
+
+       * nnimap.el (nnimap-request-group): Don't select the imap buffer before
+       opening the server.
+       (nnimap-request-delete-group): Implement group deletion.
+       (nnimap-transform-headers): Return the size of the entire message in
+       the Bytes header, not just the size of the first part.
+       (nnimap-request-move-article): When moving an article from nnimap,
+       request the article first so the accepting form has an article to
+       accept.  Reported by Dan Christensen.
+       (nnimap-command): Make sure that the error message doesn't error out.
+
+2010-09-20  David Edmondson  <dme@dme.org>
+
+       * nnimap.el (nnimap-request-set-mark): Don't wait for a response when
+       we haven't requested anything.
+
+2010-09-20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-fetch-inbox): Use "[]" as the parameter instead of
+       "".  Fix found by Andrew Cohen.
+
+       * mail-parse.el (mail-header-encode-parameter): Use -encode-parameter
+       instead of -encode-string.
+
+2010-09-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-html.el (gnus-html-image-fetched): Pass arg to kill-buffer.
+
+       * gnus-sum.el (gnus-summary-update-mark): Replace subst-char-in-string
+       by mm-subst-char-in-string.
+
+2010-09-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-wait-for-connection): Avoid a race condition while
+       waiting for the connection string.
+
+       * gnus-html.el (gnus-html-image-fetched): Protect against the data not
+       arriving.
+
+       * gnus-start.el (gnus-ignored-newsgroups): Remove [] from the list of
+       bogus characters.  This allows selecting certain Gmail groups.
+
+       * nnimap.el (nnimap-find-wanted-parts-1): New function.
+       (nnimap-fetch-partial-articles): New variable.
+       (nnimap-open-connection): When looking for credentials, also use the
+       nnimap-server-port.
+       (nnimap-request-article): Return the group/article number, so that Gnus
+       `^' works as expected.
+       (nnimap-find-wanted-parts-1): Return the MIME parts as IMAP wants them.
+
+       * gnus.el (gnus-similar-server-opened): Refactor a bit and add
+       comments.
+       (gnus-methods-sloppily-equal): New function.
+       (gnus): When using the development version of Gnus, load the gnus-load
+       file.
+
+       * gnus-start.el (gnus-get-unread-articles): Make sure that we call
+       `gnus-open-server' on each method before trying to scan them etc.
+       This ensures that all the backend parameters are set correctly.
+
+       * nnimap.el (nnimap-authenticator): New variable.
+       (nnimap-open-connection): Allow anonymous login.
+       (nnimap-transform-headers): The chars header is called Chars not Bytes.
+       (nnimap-wait-for-response): Don't infloop if the IMAP connection drops.
+
+       * gnus-art.el (gnus-article-describe-briefly): Fix up typo in last
+       patch, found by Knut Anders Hatlen.
+
+2010-09-19  Andreas Schwab  <schwab@linux-m68k.org>
+
+       * gnus-agent.el (gnus-agent-batch-confirmation)
+       (gnus-agent-expire-group, gnus-agent-expire): Pass proper format string
+       to gnus-message.
+       * gnus-art.el (gnus-article-describe-briefly): Likewise.
+       * gnus-group.el (gnus-group-list-groups, gnus-group-describe-group)
+       (gnus-group-edit-global-kill, gnus-group-describe-briefly): Likewise.
+       * gnus-int.el (gnus-open-server): Likewise.
+       * gnus-score.el (gnus-score-edit-current-scores, gnus-score-edit-file)
+       (gnus-score-check-syntax): Likewise.
+       * gnus-srvr.el (gnus-browse-describe-briefly): Likewise.
+       * gnus-start.el (gnus-read-active-file-1, gnus-read-active-file-1):
+       Likewise.
+       * gnus-sum.el (gnus-summary-describe-briefly): Likewise.
+
+2010-09-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-html.el (gnus-html-prefetch-images): Fix up the url-retrieve
+       calling conventions so that prefetch doesn't bug out.
+
+2010-09-19  Julien Danjou  <julien@danjou.info>
+
+       * gnus-sum.el (gnus-summary-update-mark): Use `subst-char-in-string'
+       rather than `subst-char-in-region' in order to be able to replace ASCII
+       char by UTF-8 ones.
+
+       * gnus-html.el (gnus-html-prefetch-images): Use `url-retrieve' rather
+       than curl.
+       (gnus-html-image-fetched): Fix `gnus-html-put-image' call not setting
+       the right URL and ALT text on images.
+       (gnus-html-wash-tags): Fix tag case.
+       Add support for `s' and `ins' tags.  Use gnus-emphasis-* faces.
+       (gnus-article-html): Add -o display_ins_del=2 option.
+       (gnus-html-wash-tags): Add better support for <ul> tags symbols.
+
+2010-09-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnheader.el (nnheader-insert-nov): Protect against junk appearing in
+       the extra mail headers, which sometimes seem to happen for unknown
+       reasons.
+
+       * mail-parse.el (mail-header-encode-parameter): Define as
+       rfc2045-encode-string instead of as rfc2231-encode-string, since some
+       (or most, perhaps?) mail readers don't understand the latter, but do
+       understand the former.
+
+       * gnus-agent.el (gnus-agent-auto-agentize-methods): Switch the default
+       to nil, so that no methods are automatically agentized.  I think this
+       is probably what most users want.
+
+       * gnus-html.el (gnus-html-schedule-image-fetching): Ignore all errors
+       from url-retrieve, for instance about invalid URLs.
+
+       * nnimap.el (nnimap-finish-retrieve-group-infos): Protect against
+       groups that have no articles.
+       (nnimap-request-article): Check that we really got an article when we
+       requested one.
+
+       * gnus-agent.el (gnus-agent-load-alist): Nix out the alist if the file
+       doesn't exist.
+
+       * nnimap.el (nnimap-finish-retrieve-group-infos): Return data in the
+       nntp buffer so the agent can save it.
+       (nnimap-open-shell-stream): Bind `process-connection-type' to nil, so
+       that CRLF doesn't get translated to \n.
+       (nnimap-open-connection): Don't make 'shell commands only send \n.
+
+2010-09-19  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * nnml.el (nnml-files): Add prefix to dynamic var `files'.
+       (nnml-generate-nov-databases-directory, nnml-generate-active-info):
+       Update var name.
+       (nnml-generate-nov-file): Use dolist.
+       (nnml-directory-articles, nnml-current-group-article-to-file-alist):
+       Use with-current-buffer.
+
+2010-09-18  Julien Danjou  <julien@danjou.info>
+
+       * gnus-html.el (gnus-html-schedule-image-fetching): Fetch all images in
+       parallel.
+
+2010-09-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-update-info): When doing partial marks update, get
+       the range update right.
+       (nnimap-request-group): Don't make `M-g' bug out on group with no
+       marks.
+       (nnoo): Require, so that other packages can require nnimap.
+       (nnimap-wait-for-response): Be a bit more lax in finding the end of the
+       command we're looking for.  This helps when the server sends more
+       responses after we've gotten everything we expected.
+       (nnimap): Add a `newlinep' field to keep track of end-of-line
+       conventions.
+       Don't send CRLF to things that don't want it.
+       (nnimap-request-accept-article): Ditto.
+
+2010-09-18  Julien Danjou  <julien@danjou.info>
+
+       * gnus-html.el (gnus-html-schedule-image-fetching): Use `url' rather
+       than curl to retrieve images.
+
+2010-09-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-update-info): Extend the info so that we can set
+       the marks.
+       (nnimap-open-connection): Fix typo -- should be 'shell, not 'stream.
+       (nnimap-wait-for-connection): New function.
+       (nnimap-open-connection): If we have PREAUTH, don't query for login
+       credentials.
+       (nnimap-update-info): Fix off-by-one error when concatenating ranges
+       when doing a partial update.
+
+2010-09-18  Julien Danjou  <julien@danjou.info>
+
+       * gnus-html.el (gnus-html-wash-tags): Add support for i, b and u HTML
+       tags.
+
+2010-09-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-credentials): New function.
+       (nnimap-open-connection): Use the new function to look for credentials
+       also on the numeric equivalents of "imap" and "imaps".
+
+       * gnus-start.el (gnus-activate-group): Send the info to
+       gnus-request-group.
+
+       * nnimap.el (nnimap-request-group): Have the "check" version of the
+       function parse flags and update the info, so that a `M-g' get a total
+       resync of all flags from the group.
+
+       * gnus-int.el (gnus-request-group): Take an optional `info' parameter
+       to allow backends to alter the info on group selection.  Also alter all
+       the backend -request-group functions to take the parameter.
+
+       * nnimap.el (nnimap-store-info): New function.
+       (nnimap-update-info): Store the info for later usage.
+       (nnimap-request-group): Use the stored info for the dont-check case, so
+       that we don't retrieve all marks when we enter a group.
+
+       * nnimap.el: Use deffoo instead of defun for interface functions.
+
+       * gnus-start.el (gnus-get-unread-articles): Allow the backends to
+       update the group info.  This makes the nndraft groups, for instance, go
+       back to their old behavior.
+
+       * gnus-sum.el (gnus-select-newsgroup): Indent.
+
+       * nnimap.el (nnimap-possibly-change-group): Return nil if we can't log
+       in.
+       (nnimap-finish-retrieve-group-infos): Make sure we're not waiting for
+       nothing.
+
+       * gnus-start.el (gnus-get-unread-articles): Don't try to scan groups
+       from methods that are denied.
+
+       * gnus-int.el (gnus-method-denied-p): New function.
+
+       * nnimap.el (nnimap-open-connection): Use auth-sources to query and
+       store the password instead of netrc.
+       (nnimap-open-connection): Don't error out when we can't make a
+       connections.
+
+       * auth-source.el (auth-source-create): In the password prompt, say what
+       we're querying for.  Also prompt for user name if that hasn't been
+       given.
+
+       * nnimap.el (nnimap-with-process-buffer): Remove.
+
+2010-09-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-read-active-for-groups): Don't use the "finish"
+       method when we're reading from the agent.
+
+       * nnagent.el (nnagent-retrieve-group-data-early): New dummy method.
+
+       * auth-source.el (auth-sources): Add ~/.authinfo to the default, since
+       that's probably most useful for users.
+
+       * gnus-int.el (gnus-check-server): Save result so that it doesn't say
+       "failed" all the time.
+
+       * gnus.el: Throughout all files, replace (save-excursion (set-buffer
+       ...)) with (with-current-buffer ... ).
+
+       * nntp.el (nntp-open-server): Return whether the open was successful or
+       not.
+
+       * gnus-sum.el (gnus-summary-first-subject): Have `unseen-or-unread'
+       select an unread unseen article first.
+
+       * nnimap.el (nnimap-open-connection): If the user doesn't have a
+       /etc/services, supply some sensible port defaults.
+
+       * dgnushack.el: Define netrc-credentials.
+
+2010-09-17  Julien Danjou  <julien@danjou.info>
+
+       * mm-decode.el (mm-text-html-renderer): Document gnus-article-html.
+
+2010-09-17  Knut Anders Hatlen  <kahatlen@gmail.com>  (tiny change)
+
+       * nnimap.el (nnimap-get-groups): Don't bug out if the LIST command
+       doesn't have any parameters.
+
+2010-09-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnimap.el (nnimap-open-connection): Upcase all capabilities, and use
+       only upcased checks.
+
+       * nnmail.el (nnmail-article-group): Fix typo in "bogus" section.
+
+       * nnimap.el (nnimap-open-shell-stream): New function.
+       (nnimap-open-connection): Use it.
+       (nnimap-transform-headers): Get the number of lines in each message.
+       (nnimap-retrieve-headers): Query for BODYSTRUCTURE so that we get the
+       number of lines.
+       (nnimap-request-list): Not all servers return UIDNEXT.  Work past this
+       problem.
+
+       * utf7.el (utf7-encode): Autoload.
+
+       * nnmail.el (nnmail-inhibit-default-split-group): New internal variable
+       to allow the mail splitting to not return a default group.  This is
+       useful for nnimap, which will leave unmatched mail in the inbox.
+
+       * nnimap.el: Rewritten.
+
+       * gnus.el (gnus-article-special-mark-lists): Add uid/active tuples, for
+       nnimap usage.
+
+       * gnus-sum.el (gnus-summary-move-article): Pass the move-to group name
+       if the move is internal, so that nnimap can do fast internal moves.
+
+       * gnus-start.el (gnus-get-unread-articles): Support early retrieval of
+       data.
+       (gnus-read-active-for-groups): Support finishing the early retrieval of
+       data.
+
+       * gnus-range.el (gnus-range-nconcat): New function.
+
+       * gnus-int.el (gnus-finish-retrieve-group-infos)
+       (gnus-retrieve-group-data-early): New functions.
+
+2010-09-17  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * nnrss.el (nnrss-retrieve-headers, nnrss-request-list-newsgroups)
+       (nnrss-retrieve-groups):
+       * pop3.el (pop3-open-server, pop3-read-response, pop3-list, pop3-retr)
+       (pop3-quit): Use with-current-buffer.
+
+2010-09-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * pop3.el (pop3-wait-for-messages): Use pop3-accept-process-output
+       instead of nnheader-accept-process-output.
+
+       * dgnushack.el (dgnushack-compile): Add comment.
+
+       * lpath.el: No need to fbind propertize for XEmacs 21.4.
+
+       * gnus-html.el (gnus-html-schedule-image-fetching)
+       (gnus-html-prefetch-images): Replace process-kill-without-query by
+       gnus-set-process-query-on-exit-flag.
+
+2010-09-16  Romain Francoise  <romain@orebokech.com>
+
+       * gnus-html.el: Require gnus-art for `gnus-with-article-buffer'.
+
+2010-09-14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-registry.el (gnus-registry-install-shortcuts): The second
+       parameter to unintern is mandatory-ish in Emacs 24.
+
+       * gnus-html.el (gnus-html-schedule-image-fetching)
+       (gnus-html-prefetch-images): Check for curl before using it.
+
+       * mm-decode.el (mm-text-html-renderer): Don't have gnus-article-html
+       depend on curl, which isn't essential.
+
+       * imap.el: Revert back to version
+       cb950ed8ff3e0f40dac437a51b269166f9ffb60d, since some of the changes
+       seem problematic.
+
+2010-09-14  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus-registry.el (gnus-registry-install-shortcuts):
+       Explicitly pass `obarray' to `unintern' to avoid a warning.
+
+2010-09-14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-read-active-for-groups): Revert the previous
+       change.
+
+       * nnrss.el (nnrss-request-list): Remove this function and related
+       functions, including the moreover stuff.
+
+2010-09-14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnrss.el (nnrss-retrieve-groups): New function.
+
+2010-09-14  Juanma Barranquero  <lekktu@gmail.com>
+
+       * .dir-locals.el: Add no-byte-compile cookie.
+
+2010-09-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * time-date.el (format-seconds): Comment fix.
+
+       * gnus-start.el (gnus-read-active-for-groups): Run gnus-activate-group
+       for back end that doesn't support request-scan.
+
+2010-09-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-read-active-file-1): If gnus-agent isn't set,
+       then do request scans from the backends.
+
+       * netrc.el (netrc-credentials): New conveniency function.
+
+       * gnus-sum.el (gnus-summary-update-hook): Change default to nil, to
+       avoid running a hook per line, since this takes a lot of time,
+       profiling shows.
+       (gnus-summary-prepare-threads): Call `gnus-summary-highlight-line'
+       directly if gnus-visual-p is true.
+
+2010-09-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-start.el (gnus-read-active-for-groups): Check only subscribed
+       groups; replace mapcar with dolist which is a bit faster; pass groups
+       info to gnus-read-active-file-1.
+       (gnus-read-active-file-1): Scan only specified groups if the new
+       optional arg `infos' is given.
+
+2010-09-09  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-fetch-pop): Use pop3-movemail again.
+
+       * pop3.el (pop3-movemail): Remove.
+       (pop3-streaming-movemail): Rename to pop3-movemail.
+
+       * gnus-html.el (gnus-html-wash-tags): Refactor out the image bit, and
+       don't restrict end-tag searches to the end of the line.
+
+2010-09-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-start.el (gnus-get-unread-articles): Set the number of unread
+       articles of every unchecked group to t, which means unknown since the
+       server has never been opened.
+
+2010-09-08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-html.el (gnus-html-show-alt-text): New command.
+       (gnus-html-browse-image): Ditto.
+       (gnus-html-wash-tags): Add the data to allow showing the ALT text and
+       to browse the image directly.
+       (gnus-html-wash-tags): Search for images first, so that <a><img> works
+       better.
+
+       * gnus-async.el (gnus-async-article-callback):
+       Call `gnus-html-prefetch-images' unconditionally.
+
+       * gnus-html.el (gnus-html-schedule-image-fetching): Decode entities
+       before feeding URLs to curl.
+
+2010-09-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-html.el (gnus-html-wash-tags, gnus-html-put-image): Mark cid and
+       internal images as deletable by `W D D'.
+
+       * gnus-async.el (gnus-html-prefetch-images): Autoload it when compiling.
+       (gnus-async-article-callback): Fix typo.
+
+2010-09-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-html.el (gnus-html-wash-tags): Limit end-tag matching to the
+       current line to work around bugs in the output from w3m.
+
+       * gnus-async.el (gnus-async-article-callback): Always prefetch images
+       for groups that want that.
+
+       * nntp.el (nntp-wait-for-string): Supply a timeout for
+       accept-process-output to ensure progress.
+
+       * gnus-start.el (gnus-get-unread-articles): If being given an explicit
+       level to get unread articles from, then use that for foreign groups,
+       too.
+
+       * gnus-html.el (gnus-html-wash-tags): Remove <a name...> tags, which
+       confuses the rest of the function.
+
+       * gnus-start.el (gnus-read-active-for-groups): Do a `gnus-request-scan'
+       for the methods that support -retrieve-groups, too.
+
+       * nnml.el (nnml-save-nov): Remove some debugging-related messages.
+
+2010-09-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (dgnushack-compile, dgnushack-make-cus-load)
+       (dgnushack-make-auto-load): Exclude .dir-locals.el file.
+
+       * pop3.el: Require cl when compiling.
+       (pop3-number-of-responses): Search for "+OK", not "+OK ".
+
+2010-09-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-get-unread-articles): Don't bother with groups
+       that aren't going to be activated.
+       (gnus-get-unread-articles): Fix up the last commit.
+
+       * gnus-html.el (gnus-article-html): Allow calling without specifying
+       the handle.  In that case, dissect the buffer first.
+
+       * gnus-sum.el (gnus-set-mode-line): Don't pad the mode line string.
+
+       * nnimap.el (nnimap-open-connection): Revert the change that would look
+       into authinfo for imaps instead of imap.
+
+       * gnus-start.el (gnus-activate-group): Take an optional parameter to
+       say that you don't want to call gnus-request-group with don-check, but
+       do check the reponse.  This is for virtual groups only.
+       (gnus-get-unread-articles): Count the archive groups as secondary, so
+       that they're activated the same way as before.
+
+       * imap.el (imap-message-map): Removed optional buffer parameter, since
+       no callers use it.
+       (imap-message-get): Ditto.
+       (imap-message-put): Ditto.
+       (imap-mailbox-map): Ditto.
+       (imap-mailbox-put): Ditto.
+       (imap-mailbox-get): Ditto.
+       (imap-mailbox-get): Revert last change for this function.
+
+       * nnimap.el (nnimap-request-list): Servers may return \NoSelect
+       case-insensitively.
+       (nnimap-debug): Remove.
+
+       * net/imap.el (imap-fetch-safe): Remove function, and alter all
+       callers to use `imap-fetch' instead.  According to the comments, this
+       should be safe, since all other IMAP clients use the 1:* syntax.
+       (imap-enable-exchange-bug-workaround): Remove.
+       (imap-debug): Remove -- doesn't seem very useful.
+
+       * mail-source.el (mail-source-fetch): Don't message if we're fetching
+       mail from a file, and the file doesn't exist.
+
+       * imap.el (imap-log): New convenience function used throughout instead
+       of repeating the same code all over the place.
+
+       * pop3.el (pop3-streaming-movemail): Return t for success.
+
+       * nnimap.el (nnimap-open-connection): Look for the "imaps" entry in the
+       .authinfo if we're using ssl connection.
+
+       * nnvirtual.el (nnvirtual-create-mapping): Use the active info we
+       already have if we're in a main Gnus `g' run.
+
+       * gnus-start.el (gnus-method-rank): Get info for virtual groups last.
+
+2010-09-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-start.el (gnus-method-rank): Replace equalp with equal.
+
+       * nnmh.el (nnmh-request-list-1): Bind `file'.
+
+       * pop3.el (pop3-set-process-query-on-exit-flag): New function that's an
+       alias to set-process-query-on-exit-flag or process-kill-without-query.
+       (pop3-open-server): Use it.
+
+2010-09-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-delete-crash-box): Always move the crash
+       box to the Incoming file.  Fixes mistake in previous checkin.
+
+       * pop3.el (pop3-send-streaming-command): Off-by-one error on the
+       request loop (for debugging purposes) removed.
+
+       * nnml.el (nnml-save-nov): Message around nnml-save-nov so that the
+       culprit is more visible.
+       (nnml-save-incremental-nov, nnml-open-incremental-nov)
+       (nnml-add-incremental-nov): New functions to do "incremental" nov
+       updates, where we just append to the end of the existing nov files
+       without reading/writing them in full.
+
+       * mail-source.el (mail-source-delete-crash-box): Really only check the
+       incoming files once in a while.
+
+       * pop3.el (pop3-streaming-movemail): Always close the pop3 connection.
+
+       * mail-source.el (mail-source-delete-crash-box): Only check the
+       incoming files for deletion once per day to save a lot of file
+       accesses.
+
+       * pop3.el (pop3-logon): Fix up unbound variable typo.
+
+       * mail-source.el (pop3-streaming-movemail): Autoload.
+
+       * pop3.el (pop3-streaming-movemail):
+       Respect pop3-leave-mail-on-server.
+
+       * mail-source.el (mail-source-fetch-pop): Use streaming pop3
+       retrieval.
+
+       * pop3.el (pop3-process-filter): Remove unused function.
+       (pop3-streaming-movemail, pop3-send-streaming-command)
+       (pop3-wait-for-messages, pop3-write-to-file)
+       (pop3-number-of-responses): New functions for streaming pop3
+       retrieval.
+
+       * gnus-start.el (gnus-get-unread-articles): Protect against groups that
+       come from no known methods.
+       (gnus-make-hashtable-from-newsrc-alist): Remove duplicates from .newsrc
+       list.
+
+       * pop3.el (pop3-display-message-size-flag): Remove -- everybody wants
+       message sizes.
+       (pop3-movemail): Use erase-buffer instead of looping and deleting
+       regions, which seems rather odd.
+
+       * gnus-agent.el (gnus-agent-load-local): Only read the agent.lib/local
+       file once per `g' run.
+
+       * nnmh.el (nnmh-request-list-1): Output active lines also for empty
+       directories.  This makes the draft queue directory work.
+
+       * gnus-start.el (gnus-get-unread-articles): Rewrite the way we request
+       data from the backends, so that we only request the list of groups from
+       each method once.  This should speed things up considerably.
+
+       * nnvirtual.el (nnvirtual-request-list): Remove function so that we can
+       detect that it's not implemented.
+
+       * nnmh.el (nnmh-request-list-1): Fix up the recursion behavior so that
+       we actually do recurse down into the tree, but don't stat all leaf
+       nodes.
+
+       * gnus-html.el (gnus-html-show-images): If there are no images to show,
+       then say so instead of bugging out.
+
+       * gnus-agent.el (gnus-agent-load-alist): Check whether the agentview
+       files exist before trying to read them.
+
+       * gnus-html.el (gnus-html-wash-tags): Remove even more white space
+       around <pre_int>.
+
+       * gnus-art.el (gnus-article-copy-string): Say what data we copied.
+
+       * nnmh.el (nnmh-request-list-1): Optimize for speed.
+
+2010-09-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-util.el (mm-image-load-path): Just return the image directories,
+       not all directories in the path in addition to the image directories.
+       (mm-image-load-path): Maintain a cache of the image directories so that
+       the `g' command in Gnus doesn't have to stat dozens of directories each
+       time.
+
+       * gnus-html.el (gnus-html-put-image): Allow images to be removed.
+       (gnus-html-wash-tags): Add a new `i' command to insert images.
+       (gnus-html-insert-image): New command and keystroke.
+       (gnus-html-redisplay-with-images): New command and keystroke.
+       (gnus-html-show-images): Rename command.
+       (gnus-html-wash-tags): Remove more white space before <pre_int> image
+       spacers.
+       (gnus-html-wash-tags): Decode entities at the end, so that entities
+       inside the tags don't mess up the rest of the "parsing".
+
+       * gnus-agent.el (gnus-agent-auto-agentize-methods): Change the default
+       so that nnimap methods aren't agentized by default.  There's apparently
+       many problems related to agent/imap behavior.
+
+       * gnus-art.el (gnus-article-copy-string): New command and key binding.
+
+       * gnus-html.el: Doc fix.
+
+2010-09-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind device-on-window-system-p, glyph-image, glyphp, and
+       specifier-spec-list for Emacs 21.
+
+       * gnus-html.el (gnus-html-put-image): Use gnus-graphic-display-p,
+       glyph-width and glyph-height instead of display-graphic-p and
+       image-size; make avoidance of displaying small images work for XEmacs.
+
+       * gnus-util.el (gnus-graphic-display-p): Use device-on-window-system-p
+       for XEmacs.
+
+       * gnus-ems.el (gnus-set-process-plist, gnus-process-plist): Change name
+       of symbol that holds plist data.
+       (gnus-process-plist): Remove plist of process after getting it.
+
+2010-09-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-generate-hashcash): Change default to
+       'opportunistic if hashcash is installed.
+
+       * gnus-html.el (gnus-html-rescale-image): Fix up typo in rescaling.
+       (gnus-html-put-image): Only call image-size once, since it's somewhat
+       time-consuming on remote X servers.
+
+2010-09-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-xmas.el (gnus-xmas-create-image): Don't try to examine image
+       type on data, not a file name.
+
+       * lpath.el: Fbind w3-parse-buffer for Emacs <=22 and XEmacs; fbind
+       window-pixel-edges for Emacs 21.
+
+       * gnus-html.el (gnus-article-html): Make work buffer multibyte for
+       decoded contents.
+       (gnus-html-put-image, gnus-html-rescale-image): Pass `file' argument.
+
+2010-09-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-line-format): Remove %O (moderated) from
+       group line format, since it isn't very interesting.
+
+       * gnus-agent.el (gnus-agent-short-article),
+       (gnus-agent-long-article): Increase values for these two variables,
+       since most people are likely to have more network connection and
+       storage than before.
+
+       * gnus.el (gnus-refer-article-method): Change default to 'current.
+       When referring an article, the common behavior is to refer it from the
+       current select method, not the native select method.  The chances of
+       the native select method having the message in question is rather slim
+       these days.
+
+       * gnus-sum.el (gnus-auto-select-subject): Change default to
+       `unseen-or-unread'.  I think it's likely that most people want to
+       select an unseen article over a previously seen, but unread one.
+
+       * gnus.el (gnus-mode-non-string-length): Change default to 30.  nil
+       means that in the article buffer none of the minor mode elements will
+       be shown, usually, and this is not desirable in most cases.
+
+       * gnus-sum.el (gnus-summary-goto-unread): Change default to nil, so
+       that commands like `d' (and the like) go to the next line in the
+       buffer, instead of the next unread article.  I think this is the
+       behavior that is most natural for most users.
+       (gnus-single-article-buffer): Change default to nil, so that people can
+       have as many article buffers open as they have summary buffer.  I think
+       this is the most natural way for the groups to behave.
+
+       * message.el (message-generate-new-buffers): Change default to
+       `unsent', so that all new message buffers start their names with the
+       string "*unsent", and it's easier to find the buffers if you move from
+       them.
+
+2010-09-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-html.el (gnus-html-wash-tags): Don't show images that are really
+       small.  They're probably tracking images.
+       (gnus-html-wash-tags): Remove all <pre_int> place holders.
+       (gnus-html-rescale-image): Yet another try at getting the image sizing
+       right.
+
+       * nntp.el (nntp-request-set-mark): Refuse to do marks if
+       nntp-marks-file-name is nil.
+
+2010-09-01  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-html.el (gnus-html-wash-tags)
+       (gnus-html-schedule-image-fetching, gnus-html-image-url-blocked-p):
+       Better logging.
+
+2010-09-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nndoc.el (nndoc-type-alist): Add a new type for Google digests.
+
+       * gnus-html.el (gnus-html-wash-tags): Check the value of
+       gnus-blocked-images in the summary buffer.
+
+2010-09-01  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-html.el (gnus-html-image-url-blocked-p): Doc fix.
+
+2010-09-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-html.el (gnus-html-wash-tags): "A" is also used for links, just
+       like "a", it seems like.
+       (gnus-html-image-url-blocked-p): Take a parameter for blocked-images
+       since it needs to be picked from the correct buffer.
+
+       * nnwfm.el: Remove.
+
+       * nnlistserv.el: Remove.
+
+2010-09-01  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-html.el (gnus-html-image-url-blocked-p): New function.
+       (gnus-html-prefetch-images, gnus-html-wash-tags): Use it.
+
+2010-09-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnkiboze.el: Remove.
+
+       * nndb.el: Remove.
+
+       * gnus-html.el (gnus-html-put-image): Use the deleted text as the image
+       alt text.
+       (gnus-html-rescale-image): Try to get the rescaling logic right for
+       images that are just wide and not tall.
+
+       * gnus.el (gnus-string-or): Fix the syntax to not use eval or
+       overshadow variable bindings.
+
+2010-09-01  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-html.el (gnus-html-wash-tags)
+       (gnus-html-schedule-image-fetching, gnus-html-prefetch-images):
+       Add extra logging.
+
+2010-09-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-html.el (gnus-html-wash-tags): Delete the IMG_ALT region.
+       (gnus-max-image-proportion): New variable.
+       (gnus-html-rescale-image): New function.
+       (gnus-html-put-image): Rescale images.
+
+2010-09-01  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       Fix up some byte-compiler warnings.
+       * gnus.el (gnus-group-find-parameter, gnus-kill-save-kill-buffer):
+       * gnus-cite.el (gnus-article-highlight-citation, gnus-dissect-cited-text)
+       (gnus-article-fill-cited-article, gnus-article-hide-citation)
+       (gnus-article-hide-citation-in-followups, gnus-cite-toggle):
+       * gnus-group.el (gnus-group-set-mode-line, gnus-group-quit)
+       (gnus-group-set-info, gnus-add-mark): Use with-current-buffer.
+       (gnus-group-update-group): Use save-excursion and with-current-buffer.
+
+2010-09-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-html.el (gnus-article-html): Decode contents by charset.
+
+2010-09-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-html.el (gnus-html-cache-directory, gnus-html-cache-size)
+       (gnus-html-frame-width, gnus-blocked-images):
+       * message.el (message-prune-recipient-rules): Add custom version.
+       * gnus-sum.el (gnus-auto-expirable-marks): Bump custom version.
+
+       * gnus-ems.el (gnus-process-get, gnus-process-put): New compatibility
+       functions.
+
+       * gnus-html.el (gnus-html-curl-sentinel): Replace process-get with
+       gnus-process-get.
+
+2010-08-31  Julien Danjou  <julien@danjou.info>  (tiny change)
+
+       * nnimap.el (nnimap-request-newgroups): Use nnimap-request-list-method
+       instead of lsub directly.
+
+2010-08-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnwarchive.el: Remove.
+
+       * gnus-soup.el: Remove.
+
+       * nnsoup.el: Remove.
+
+       * nnultimate.el: Remove.
+
+       * gnus-html.el (gnus-blocked-images): New variable.
+
+       * message.el (message-prune-recipients): New function.
+       (message-prune-recipient-rules): New variable.
+
+       * gnus-cite.el (gnus-article-natural-long-line-p): New function to
+       guess whether a long line is natural text or not.
+
+       * gnus-html.el (gnus-html-schedule-image-fetching):
+       Use gnus-process-plist and friends for compatibility.
+
+2010-08-31  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-html.el: Require packages that define macros used in this file.
+       (gnus-article-mouse-face): Declare to silence byte-compiler.
+       (gnus-html-curl-sentinel): Use with-current-buffer, inhibit-read-only, and
+       process-get.
+       (gnus-html-put-image): Use plist-get to avoid getf.
+       (gnus-html-prefetch-images): Use with-current-buffer.
+
+2010-08-31  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-ems.el: Provide compatibility functions for
+       gnus-set-process-plist.
+
+       * lpath.el: Bind completion-styles for Emacs 21 and XEmacs; bind
+       header-line-format for XEmacs 21.4.
+
+       * gnus-sum.el (gnus-summary-stop-at-end-of-message):
+       * gnus.el (gnus-valid-select-methods):
+       * message.el (message-send-mail-partially-limit):
+       * mm-decode.el (mm-text-html-renderer):
+       * mml.el (mml-insert-mime-headers-always):
+       * smiley.el (smiley-regexp-alist): Bump custom version.
+
+2010-08-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-html.el: Require mm-url.
+       (gnus-html-wash-tags): Clarify the code a bit by renaming the variable
+       with the url to `url'.
+       (gnus-html-wash-tags): Support cid: URLs/images.
+
+2010-08-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el: As per discussion 3 years, 8 weeks, 3 days, 9 hours, 57
+       minutes, 56 seconds ago on the ding list, remove the `w' and `i'
+       bindings, as they aren't useful at all.  `w' is moved to `W w'.
+
+       * gnus-move.el: Remove file, since it doesn't really work.
+
+       * gnus-html.el (gnus-article-html): Tell w3m that the input is
+       UTF-8.  This seems to fix problems with some German web feeds.
+
+       * gnus.el (gnus-group-startup-message): Put the xpm version of the logo
+       at the top so that the proper colors are applied.
+
+       * gnus-xmas.el (gnus-xmas-create-image): Make this work on files that
+       don't have dots in their names.
+
+       * gnus-art.el (gnus-article-view-part): Doc fix.
+
+       * gnus-html.el (gnus-html-put-image): Use gnus-create-image to be
+       XEmacs-compatible.
+       (gnus-html-put-image): Don't do images on non-graphic displays.
+
+       * nnslashdot.el: Remove this unused backend.
+
+       * gnus-undo.el (gnus-undo-register-1): Limit the undo actions to 100
+       actions.
+       (gnus-undo-register-1): Revert last change.
+
+       * gnus-group.el (gnus-group-completing-read): Protect against not
+       having completion-styles bound.
+
+       * mml.el (mml-insert-mime-headers-always): Change the default to t, to
+       make broken recipients happier.
+
+       * gnus-html.el (gnus-html-put-image): Use gnus-put-image.
+
+       * gnus-ems.el (gnus-put-image): Have gnus-put-image take an optional
+       point parameter.
+
+       * gnus-xmas.el (gnus-xmas-put-image): Ditto.
+
+       * gnus-group.el (gnus-group-completing-read): Add 'substring to
+       completion-styles for group selection.
+
+2009-02-04  Andreas Schwab  <schwab@suse.de>
+
+       * gnus-score.el (gnus-score-string): Fix regex for matching extra
+       headers and regexp-quote the match if necessary.
+
+2009-03-24  Miles Bader  <miles@gnu.org>
+
+       * smiley.el (smiley-regexp-alist): Don't delete the semicolon before
+       the blinking smiley.
+
+2009-03-24  Simon Josefsson  <simon@josefsson.org>
+
+       * smiley.el (smiley-regexp-alist): Disallow ;;) from being treated as a
+       blink smiley.
+
+2010-08-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-dribble-read-file): Ensure that the directory
+       where the dribbel file lives exists.
+
+       * message.el (message-send-mail-partially-limit): Change the default to
+       nil, since most people don't want this.
+
+       * mm-url.el (mm-url-decode-entities): Also decode entities like
+       &#x3212.
+
+2009-07-16  Kevin Ryde  <user42@zip.com.au>  (tiny change)
+
+       * gnus-sum.el (gnus-summary-idna-message):
+       * nnrss.el (nnrss-normalize-date, nnrss-discover-feed):
+       Hyperlink urls in docstrings with URL `...'.
+
+2010-08-29  Adam Sjøgren  <asjo@koldfront.dk>
+
+       * gnus-html.el (gnus-html-put-image): Use XEmacs-compatible image
+       functions.
+
+2010-08-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-add-button): Take an optional parameter to
+       say what the mouseover text should be.
+
+       * gnus-html.el (gnus-html-prefetch-images): Use the summary-local
+       version of the mm-w3m-safe-url-regexp variable to only download images
+       in the groups where we want that to happen.
+
+       * gnus-sum.el (gnus-summary-stop-at-end-of-message): New variable.
+
+       * gnus-art.el (gnus-article-beginning-of-window): Make into defun for
+       easier debugging.
+       (gnus-article-beginning-of-window): Add kludge to allow spacing past
+       big pictures in the article buffer.
+
+       * mm-decode.el (mm-text-html-renderer): Default the html renderer to
+       gnus-article-html.
+       (mm-text-html-renderer): gnus-article-html needs curl in addition to
+       w3m.
+
+       * gnus-html.el: Start a new super-simple HTML renderer based on w3m.
+
+2010-08-28  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-valid-select-methods): Remove reference to nngoogle,
+       which doesn't exist.
+
+       * message.el (message-inhibit-ecomplete): New variable to allow some
+       function to inhibit ecomplete address storage.
+       (message-resend): Disable ecomplete message storage when resending
+       messages.
+
+       * nntp.el (nntp-async-kluge): Remove the Emacs 20.3-related kluge.
+
+2010-08-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-move-article, gnus-summary-delete-article):
+       Save excursion while copying, moving, and deleting articles in order to
+       prevent the cursor from jumping to unforeseen place.
+
+2010-08-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: No need to bind bookmark-current-buffer,
+       bookmark-yank-point and bookmark-make-record-function.
+
+2010-08-17  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-sync.el: Require gnus components whose functions are used.
+
+       * gnus-art.el (bookmark-make-record-function):
+       * gnus-sum.el (bookmark-yank-point, bookmark-current-bookmark):
+       Declare for compiler.
+
+       * mm-url.el (mml-compute-boundary): Autoload.
+
+2010-08-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-start.el (gnus-start-draft-setup): Move doc string forward.
+
+2010-08-14  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       Typo fix "hoo4a" -> "hook".
+
+       * gnus-sync.el (gnus-sync-install-hooks): Typo fix.
+
+2010-08-14  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-sync.el (gnus-sync): Fix defgroup version.
+
+2010-08-13  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       Doc fixes and keep unknown groups (ammended for nunion bug fix).
+
+       * gnus-sync.el: Fix docs.
+       (gnus-sync-save): Keep unknown groups in `gnus-sync-newsrc-loader'.
+       (gnus-sync-read): Don't wipe `gnus-sync-newsrc-loader' after reading.
+
+2010-08-12  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       Optimizations for gnus-sync.el.
+
+       * gnus-sync.el: Add docs about gnus-sync-backend
+       possibilities.
+       (gnus-sync-save): Remove unnecessary message.
+       (gnus-sync-read): Optimize and show what groups were skipped.
+
+2010-08-12  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       Minor bug fixes for gnus-sync.el.
+
+       * gnus-sync.el (gnus-sync-unload-hook, gnus-sync-install-hooks):
+       Don't read the sync on get-new-news.
+
+       * gnus-sync.el (gnus-sync-save): Define `variable' so the compiler is
+       quiet.
+
+       * gnus-sync.el (gnus-sync-read): Use `gnus-sync-newsrc-offsets'
+       (fix typo).
+
+2010-07-30  Lawrence Mitchell  <wence@gmx.li>
+
+       Make saving and restoring of hidden threads work with overlays.
+       Patch applied by Ted Zlatanov.
+
+       * gnus-sum.el (gnus-hidden-threads-configuration)
+       (gnus-restore-hidden-threads-configuration): Update to deal with text
+       properties, rather than searching for a magic character.
+
+2010-08-12  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       New gnus-sync.el library for synchronization of marks.
+
+       * gnus-sync.el: New library for synchronization of marks.
+
+       * gnus-util.el (gnus-grep-in-list): Move from gnus-registry.el and
+       renamed from `gnus-registry-grep-in-list'.
+
+       * gnus-registry.el (gnus-registry-follow-group-p):
+       Use `gnus-grep-in-list'.
+
+       * gnus-start.el (gnus-start-draft-setup): Make it interactive.
+
+2010-08-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-encode): Use utf-8 as a last resort if
+       determining charset of text fails.
+
+2010-08-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnmail.el (nnmail-get-new-mail-1): Revert.
+
+       * nnml.el (nnml-active-number): Make sure names of newly created groups
+       in nnml-group-alist are encoded.
+
+2010-07-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnmail.el (nnmail-get-new-mail-1): Encode group names possibly
+       containing non-ASCII characters in active file for nnml back end.
+
+2010-07-24  David Engster  <dengste@eml.cc>
+
+       * mml-smime.el (mml-smime-epg-verify): Also accept the older
+       x-pkcs7-signature MIME type as signature (RFC 2311, C.1).
+
+2010-07-21  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml.el (mml-parse-1): Collect "certfile" attributes in "<#secure>"
+       tag (Bug#6654).
+
+2010-07-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-bookmark-make-record): Bookmark position in
+       the article buffer, not the summary buffer.
+
+2010-07-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-bookmark-make-record): Make it work for
+       Emacs 23 as well.
+
+2010-07-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Bind bookmark-current-buffer, bookmark-yank-point for all
+       Emacs versions; bind bookmark-make-record-function for Emacs >=22.
+
+2010-07-13  Thierry Volpiatto  <thierry.volpiatto@gmail.com>
+
+       Allow C-w when setting a bookmark in a Gnus Article buffer (Bug#5975).
+       Patch applied by Karl Fogel.
+
+       * gnus-sum.el (gnus-summary-bookmark-make-record):
+       Set `bookmark-yank-point' and `bookmark-current-buffer' to allow C-w.
+
+2010-07-13  Thierry Volpiatto  <thierry.volpiatto@gmail.com>
+
+       Allow bookmarks to be set from Gnus Article buffers (Bug#5975).
+       Patch applied (with minor tweaks) by Karl Fogel.  Note this leaves
+       C-w still not working correctly from Article buffers; Thierry's
+       patch to fix that will be applied after this.
+
+       * gnus-art.el (bookmark-make-record-function): New local variable.
+
+       * gnus-sum.el (gnus-summary-bookmark-make-record): Allow setting from
+       article buffer.
+       (gnus-summary-bookmark-jump): Maybe jump to article buffer.
+
+2010-07-13  Karl Fogel  <kfogel@red-bean.com>
+
+       * gnus-sum.el (bookmark-make-record-default): Adjust declaration, based
+       on changes in bookmark.el.
+
+2010-07-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-xmas.el (gnus-xmas-read-event-char): Use display-message with
+       `no-log' instead of message not to log prompt string.
+
+2010-06-22  Mark A. Hershberger  <mah@everybody.org>
+
+       * mm-url.el (mm-url-encode-multipart-form-data): New function to handle
+       the *other* type of HTML form submission.
+
+2010-06-15  Michael Albinus  <michael.albinus@gmx.de>
+
+       * auth-source.el (auth-source-pick): If choice does not contain a
+       questioned keyword, set the check to t.
+
+2010-06-12  Romain Francoise  <romain@orebokech.com>
+
+       * gnus-util.el (gnus-date-get-time): Move up before first use.
+
+2010-06-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-buttonized-part-id): New internal variable.
+       (gnus-article-edit-part): Bind it to make last part that is substituted
+       or deleted visible.
+       (gnus-mime-display-single): Buttonize part of which id equals to
+       gnus-mime-buttonized-part-id.
+
+2010-06-10  Dan Christensen  <jdc@uwo.ca>
+
+       * gnus-util.el (gnus-user-date): Use gnus-date-get-time.
+       (gnus-dd-mmm): Use gnus-date-get-time.
+       * gnus-sum.el (gnus-thread-latest-date): Use gnus-date-get-time and
+       simplify logic.
+       (gnus-summary-limit-to-age): Use gnus-date-get-time.
+       (gnus-sort-threads): Emit message if gnus-sort-threads-loop used.
+
+2010-06-08  Michael Albinus  <michael.albinus@gmx.de>
+
+       * auth-source.el (top): Autoload `secrets-list-collections',
+       `secrets-create-item', `secrets-delete-item'.
+       (auth-sources): Fix tag string.
+       (auth-get-source, auth-source-retrieve, auth-source-create)
+       (auth-source-delete): New defuns.
+       (auth-source-pick): Rewrite in order to avoid 2 passes.
+       (auth-source-forget-user-or-password): New parameter USERNAME.
+       (auth-source-user-or-password): New parameters CREATE-MISSING and
+       DELETE-EXISTING.  Retrieve password interactively, if needed.
+
+2010-06-07  Teemu Likonen  <tlikonen@iki.fi>  (tiny change)
+
+       * gnus-agent.el (gnus-agent-expire-unagentized-dirs): Don't ask about
+       deleting unused directories when gnus-expert-user is t.
+
+2010-06-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-browse-delete-temp-files): Don't make query
+       for each temp file when gnus-article-browse-delete-temp is ask.
+
+2010-05-25  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-uu.el, imap.el, nndoc.el, nnrss.el, rfc2047.el, utf7.el:
+       Replace Lisp calls to delete-backward-char by calls to delete-char.
+
+2010-05-20  Kevin Ryde  <user42@zip.com.au>
+
+       * gnus-start.el (gnus-level-unsubscribed): Doc fix.  (Bug#6206)
+
+2010-05-19  Michael Albinus  <michael.albinus@gmx.de>
+
+       * password-cache.el (password-cache-remove): Fix docstring.
+
+2010-05-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-save-article): Don't bother to re-fetch
+       article unless decoding article to be saved.
+
+2010-05-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml1991.el (mml1991-mailcrypt-encrypt, mml1991-gpg-encrypt):
+       * mml2015.el (mml2015-gpg-encrypt): Disable multibyte in buffers
+       generated within the mm-with-unibyte-current-buffer macro.
+
+2010-05-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-bind-safe-url-regexp): Bind mm-w3m-safe-url-regexp
+       to nil when we're in a mml-preview buffer and no group is selected.
+
+2010-05-12  Andreas Seltenreich  <seltenreich@gmx.de>
+
+       * gnus-sum.el (gnus-summary-read-group-1): Don't jump to next group
+       when catching the `C-g'.  Reported by "Leo".
+
+2010-05-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-forward-make-body-plain)
+       (message-forward-make-body-mml): Use mm-multibyte-string-p instead of
+       multibyte-string-p.
+
+       * lpath.el: Revert.
+
+2010-05-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-forward-make-body-mml): Assume original message
+       is multibyte string; error on unibyte.
+       (message-forward-make-body-plain): Ditto; don't add excessive newline
+       in body end.
+
+       * lpath.el: Fbind multibyte-string-p for XEmacs 21.4 and SXEmacs.
+
+2010-05-11  Andreas Seltenreich  <seltenreich@gmx.de>
+
+       * gnus-sum.el (gnus-summary-kill-thread): Use gnus-summary-mark-article
+       instead of g-s-m-a-as-unread to set the expirable mark.  (Bug#5284)
+
+2010-05-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-extern.el (mm-extern-url): Don't use
+       mm-with-unibyte-current-buffer.
+       (mm-extern-cache-contents): Use with-current-buffer instead of
+       save-excursion + set-buffer.
+
+2010-05-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-emacs-mule): Remove.
+
+2010-05-10  Andreas Seltenreich  <seltenreich@gmx.de>
+
+       * gnus-sum.el (gnus-summary-mode): Don't make minor-mode-alist
+       buffer-local as it's incompatible with Stefan Monnier's 2010-05-03
+       change.
+
+2010-05-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-with-unibyte-current-buffer): Redefine it so as not to
+       bind the default value of enable-multibyte-characters to nil.
+
+2010-05-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-forward-make-body-plain)
+       (message-forward-make-body-mml):
+       Don't use mm-with-unibyte-current-buffer.
+
+2010-05-07  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * dns-mode.el (auto-mode-alist): Add entry for .zone files.
+
+2010-05-07  Christian von Roques  <roques@mti.ag>  (tiny change)
+
+       * mml2015.el (mml2015-epg-find-usable-key): Skip disabled key
+       (Bug#5592).
+
+2010-05-07  Julien Danjou  <julien@danjou.info>
+
+       * gnus-art.el (gnus-mime-pipe-part): Add optional argument `cmd'; pass
+       it to mm-pipe-part.
+
+       * mm-decode.el (mm-pipe-part): Add optional argument `cmd'; use it if
+       it is given.
+
+2010-05-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * binhex.el (binhex-decode-region-internal):
+       * dns.el (dns-read-string-name, dns-write, dns-read, dns-read-type):
+       (dns-query):
+       * nnweb.el (nnweb-gmane-search):
+       * pgg-parse.el (pgg-parse-armor):
+       * pgg.el (pgg-verify-region):
+       * sha1.el (sha1-string-external):
+       * uudecode.el (uudecode-decode-region-internal):
+       * yenc.el (yenc-decode-region): Don't run set-buffer-multibyte for
+       XEmacs.
+
+       * gnus-art.el (gnus-article-browse-html-parts):
+       * gnus-group.el (gnus-read-ephemeral-gmane-group):
+       (gnus-read-ephemeral-bug-grou): Use mm-make-temp-file instead of
+       make-temp-file.
+
+       * gnus-dired.el (gnus-dired-mode): Bind gnus-dired-mode-hook,
+       gnus-dired-mode-on-hook and gnus-dired-mode-off-hook for XEmacs when
+       compiling.
+
+       * gnus-ml.el (gnus-mailing-list-mode): Bind gnus-mailing-list-mode-hook,
+       gnus-mailing-list-mode-on-hook and gnus-mailing-list-mode-off-hook for
+       XEmacs when compiling.
+
+       * gnus-salt.el (gnus-pick-mode): Bind gnus-pick-mode-on-hook and
+       gnus-pick-mode-off-hook for XEmacs when compiling.
+       (gnus-binary-mode): Bind gnus-binary-mode-on-hook and
+       gnus-binary-mode-off-hook for XEmacs when compiling.
+
+       * gnus-sum.el (gnus-summary-limit-strange-charsets-predicate):
+       Return nil if char-charset is not available.
+
+       * imap.el (imap-disable-multibyte)
+       * sieve-manage.el (sieve-manage-disable-multibyte): Redefine them as
+       macros.
+
+       * mm-url.el (mm-url-form-encode-xwfu): Use mm-encode-coding-string
+       instead of encode-coding-string.
+
+       * mm-util.el (mm-enable-multibyte, mm-disable-multibyte): Use (featurep
+       'xemacs) instead of mm-emacs-mule to switch function definitions.
+       (mm-with-unibyte-current-buffer): Make it a progn macro for XEmacs.
+
+       * lpath.el: Fbind delete-overlay and overlay-lists for XEmacs;
+       bind temporary-file-directory for XEmacs;
+       fbind make-temp-file, set-buffer-multibyte, string-as-multibyte and
+       timer-set-function for XEmacs 21.4 and SXEmacs;
+       bind timer-list for XEmacs 21.4 and SXEmacs;
+       fbind char-charset and find-charset-region for non-Mule XEmacs;
+       fbind decode-coding-region, decode-coding-string, detect-coding-region,
+       encode-coding-region and encode-coding-string for XEmacs having no
+       file-coding feature.
+
+2010-05-06  Tommi Vainikainen  <thv@iki.fi>  (tiny change)
+
+       * mml-sec.el (mml-secure-message-sign): Fix cut and paste error.
+
+2010-05-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-dired.el, gnus-draft.el, gnus-ml.el, gnus-salt.el, gnus-sum.el,
+       gnus-undo.el, mml.el: Require easy-mmode for XEmacs when compiling.
+
+2010-05-03  Juanma Barranquero  <lekktu@gmail.com>
+
+       * mm-util.el (mm-decompress-buffer): Use `delete-file';
+       alias `jka-compr-delete-temp-file' no longer exists.
+
+2010-05-03  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       Use define-minor-mode in Gnus where applicable.
+       * mml.el (mml-mode): Use define-minor-mode.
+       * gnus-undo.el (gnus-undo-mode-map): Initialize in declaration.
+       (gnus-undo-mode): Use define-minor-mode.
+       * gnus-sum.el (gnus-dead-summary-mode-map): Initialize in declaration.
+       (gnus-dead-summary-mode): Use define-minor-mode.
+       * gnus-salt.el (gnus-pick-mode-map, gnus-binary-mode-map):
+       Initialize in declaration.
+       (gnus-pick-mode, gnus-binary-mode): Use define-minor-mode.
+       * gnus-ml.el (gnus-mailing-list-mode-map): Initialize in declaration.
+       (gnus-mailing-list-mode): Use define-minor-mode.
+       * gnus-draft.el (gnus-draft-mode-map): Initialize in declaration.
+       (gnus-draft-mode): Use define-minor-mode.
+       * gnus-dired.el (gnus-dired-mode-map): Initialize in declaration.
+       (gnus-dired-mode): Use define-minor-mode.
+
+2010-05-01  Andreas Seltenreich  <seltenreich@gmx.de>
+
+       * mml.el (mml-generate-mime-1, mml-compute-boundary-1): Update 'mml
+       handles on recursive mml-to-mime translation and check them for
+       boundary delimiter collisions.  Reported by Greg Troxel.
+
+2010-04-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el: Don't load tm and apel XEmacs packages when compiling.
+
+2010-04-23  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * mm-util.el (mm-find-buffer-file-coding-system):
+       * yenc.el (yenc-decode-region): Don't let-bind a read-only variable.
+
+2010-04-22  Andreas Seltenreich  <seltenreich@gmx.de>
+
+       * message.el (message-generate-headers): Record insertion of optional
+       headers as well.  Otherwise the check to prevent repeated insertion of
+       optional headers is a no-op.
+
+2010-04-17  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * smime.el: Don't mention CVS.
+
+       * nnrss.el (nnrss-fetch): Don't mention CVS.
+
+       * nnir.el: Don't mention CVS.
+
+2010-04-14  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-sum.el (gnus-summary-bookmark-make-record):
+       Add `location' field.
+
+2010-04-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind bookmark-default-handler,
+       bookmark-get-bookmark-record, bookmark-make-record-default,
+       bookmark-prop-get for Emacs <23 and XEmacs.
+
+2010-04-12  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-sum.el: Add bookmark declarations to silence the compiler.
+       (gnus-mark-xrefs-as-read, gnus-summary-limit-to-bodies):
+       Use with-current-buffer to silence the byte-compiler.
+       (gnus-summary-bookmark-make-record): Use derived-mode-p and don't
+       bother to require `gnus'.
+       (gnus-summary-bookmark-jump): Don't forget to autoload.  Simplify.
+
+2010-04-12  Thierry Volpiatto  <thierry.volpiatto@gmail.com>
+
+       * gnus-sum.el (gnus-summary-bookmark-make-record)
+       (gnus-summary-bookmark-jump): New functions.
+       (gnus-summary-mode): Setup bookmark support.
+
+2010-04-01  Andreas Schwab  <schwab@linux-m68k.org>
+
+       * mm-uu.el (mm-uu-pgp-signed-extract-1): Use buffer-file-coding-system
+       if set.
+
+2010-03-31  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-browse-html-save-cid-content): Rename from
+       gnus-article-browse-html-save-cid-image; make it work recursively for
+       forwarded messages as well.
+       (gnus-article-browse-html-parts): Work when prefix arg is given.
+       (gnus-article-browse-html-article): Doc fix.
+
+2010-03-30  Chong Yidong  <cyd@stupidchicken.com>
+
+       * message.el (message-default-mail-headers)
+       (message-default-headers): Carry the value mail-default-headers over
+       into message-default-mail-headers, rather than message-default-headers.
+
+2010-03-30  Martin Stjernholm  <mast@lysator.liu.se>
+
+       * mm-decode.el (mm-add-meta-html-tag): Add option to override the
+       charset.
+
+       * gnus-art.el (gnus-article-browse-html-parts): Force the correct
+       charset into the <meta> tag when the article is encoded to utf-8.
+
+2010-03-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-browse-delete-temp-files):
+       Delete directories as well.
+       (gnus-article-browse-html-parts): Work for images that do not specify
+       file names; delete temp directory when quitting; insert header at the
+       right place; use file: scheme for image files.
+
+2010-03-30  Eric Schulte  <schulte.eric@gmail.com>
+
+       * gnus-art.el (gnus-article-browse-html-save-cid-image): New function.
+       (gnus-article-browse-html-parts): Use it to make temporary cid image
+       files in addition to html file so that browser may display them.
+
+2010-03-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-add-meta-html-tag): Fix regexp matching meta tag.
+
+2010-03-29  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-source-pick): Fix for non-secrets specifier.
+
+2010-03-27  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-sources): Change default to be simpler.
+       Explain about Secret Service API sources.  Improve Customize options.
+       (auth-source-pick): Change to accept any number of search parameters.
+       Implement fallbacks iteratively, not recursively.  Add scoring on the
+       second pass and sort by score.  Call Secret Service API when needed.
+       (auth-source-user-or-password): Use it.  Call Secret Service API
+       directly when needed to get the user name and the password.
+
+2010-03-24  Juanma Barranquero  <lekktu@gmail.com>
+
+       * message.el (message-interactive): Doc fix.
+       (message-qmail-inject-args): Reflow.
+       (message-kill-to-signature): Fix typo in docstring.
+
+       * smiley.el (smiley-buffer): Fix typo in docstring.
+
+2010-03-24  Glenn Morris  <rgm@gnu.org>
+
+       * mail-source.el (gnus-message): Declare.
+       (mail-source-delete-old-incoming): Require gnus-util.
+
+2010-03-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (canlock-verify): Autoload it for Emacs 21.
+
+       * message.el (ecomplete-setup): Autoload it for Emacs <23.
+
+       * mml-sec.el (mml-secure-cache-passphrase): Default to t that is
+       password-cache's default if it is not bound.
+       (mml-secure-passphrase-cache-expiry): Default to 16 that is
+       password-cache-expiry's default if it is not bound.
+
+       * pop3.el (pop3-list): Don't use 3rd arg of `split-string' which is not
+       available in Emacs 21.
+
+       * lpath.el: Suppress compiler warnings for:
+       canlock-insert-header and smtpmail-default-smtp-server for Emacs 21 and
+       XEmacs;
+       ecomplete-add-item, ecomplete-save, hashcash-wait-async,
+       mail-add-payment, mail-add-payment-async, netrc-get, netrc-machine,
+       netrc-machine-user-or-password and netrc-parse for Emacs 22 and XEmacs.
+
+2010-03-23  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-sources): Fix up definition so extra parameters
+       are always inline.
+
+2010-03-22  Martin Stjernholm  <mast@lysator.liu.se>
+
+       * nnimap.el (nnimap-verify-uidvalidity): Fix bug where uidvalidity
+       wasn't updated after mismatch.  Clear cached mailbox info correctly
+       when uidvalidity changes.
+       (nnimap-group-prefixed-name): New function to avoid some code
+       duplication.
+       (nnimap-verify-uidvalidity, nnimap-group-overview-filename)
+       (nnimap-request-group): Use it.
+       (nnimap-retrieve-groups, nnimap-verify-uidvalidity)
+       (nnimap-update-unseen): Significantly improved speed of Gnus startup
+       with many imap folders.  This is done by caching the group status from
+       the imap server persistently in a group parameter `imap-status'.  (This
+       was cached before too if `nnimap-retrieve-groups-asynchronous' was set,
+       but not persistently, so every Gnus startup was still very slow.)
+
+2010-03-22  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * assistant.el (assistant-render-text): Run `widget-setup' and don't
+       delete the extra newline.  Otherwise editing of :string and :number
+       types don't work.
+
+2010-03-20  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el: Set up autoloads.  Bump to 23.2 because of the
+       secrets.el dependency.
+       (auth-sources): Add optional user name.  Add secrets.el configuration
+       choice (unused right now).
+
+2010-03-20  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-sum.el (gnus-summary-make-menu-bar):
+       Let `gnus-registry-install-shortcuts' fill in the functions.
+
+       * gnus-registry.el (gnus-summary-misc-menu): Declare to avoid
+       warnings.
+       (gnus-registry-misc-menus): Variable to hold registry mark menus.
+       (gnus-registry-install-shortcuts): Populate and use it in a
+       `gnus-summary-menu-hook' lambda, under "Gnus"->"Registry Marks".
+
+2010-03-20  Martin Stjernholm  <mast@lysator.liu.se>
+
+       * nnimap.el (nnimap-decode-group-name, nnimap-encode-group-name):
+       In-place substitutions for the group name encoding/decoding.
+       (nnimap-find-minmax-uid, nnimap-possibly-change-group)
+       (nnimap-retrieve-headers-progress, nnimap-possibly-change-group)
+       (nnimap-retrieve-headers-progress, nnimap-request-article-part)
+       (nnimap-update-unseen, nnimap-request-list)
+       (nnimap-retrieve-groups, nnimap-request-update-info-internal)
+       (nnimap-request-set-mark, nnimap-split-to-groups)
+       (nnimap-split-articles, nnimap-request-newgroups)
+       (nnimap-request-create-group, nnimap-request-accept-article)
+       (nnimap-request-delete-group, nnimap-request-rename-group)
+       (nnimap-acl-get, nnimap-acl-edit): Use them.  Replace `mbx' with
+       `encoded-mbx' for consistency.
+       (nnimap-close-group): Call `imap-current-mailbox' instead of using the
+       variable `imap-current-mailbox'.
+
+       * gnus-agent.el (gnus-agent-fetch-articles, gnus-agent-fetch-headers)
+       (gnus-agent-regenerate-group): Use `gnus-agent-decoded-group-name'.
+
+2010-03-20  Bojan Petrovic  <bpetrovi@f.bg.ac.rs>
+
+       * pop3.el (pop3-display-message-size-flag): Display message size byte
+       counts during POP3 download.
+       (pop3-movemail): Use it.
+       (pop3-list): Implement listing of available messages.
+
+2010-03-20  Mark Triggs  <mst@dishevelled.net>  (tiny change)
+
+       * nnir.el (nnir-get-article-nov-override-function): New function to
+       override the normal NOV retrieval.
+       (nnir-retrieve-headers): Use it.
+
+2010-03-19  Michael Albinus  <michael.albinus@gmx.de>
+
+       * auth-source.el (netrc-machine-user-or-password): Autoload.
+
+2010-03-19  Glenn Morris  <rgm@gnu.org>
+
+       Stop message.el from loading about 40 libraries it doesn't always need.
+       The general approach is to autoload rather than require, and to
+       require in the specific functions rather than the file.  (Bug#5642)
+
+       * gmm-utils.el: Don't require wid-edit.
+       (widget-create-child-value, widget-convert, widget-default-get):
+       Autoload.
+
+       * gnus-util.el: Don't require time-date, netrc.
+       (message-fetch-field, gnus-group-name-decode): Declare rather than
+       autoloading.
+       (gnus-fetch-field): Require message.
+       (gnus-decode-newsgroups): Require gnus-group.
+
+       * ietf-drums.el: Don't require time-date.
+
+       * message.el: Don't require hashcash, canlock, ecomplete.
+       Do require mail-utils.  Require nnheader only when compiling.
+       (smtpmail-default-smtp-server): Remove declaration.
+       (message-send-mail-function): Check smtpmail-default-smtp-server
+       is bound rather than requiring smtpmail.
+       (message-auto-save-directory, message-insert-signature):
+       Use expand-file-name rather than nnheader-concat.
+       (nnheader-insert-file-contents): Autoload.
+       (hashcash-wait-async): Declare.
+       (message-send-mail): Only call gnus-setup-posting-charset if
+       gnus-group-posting-charset-alist is bound.  Require hashcash if needed.
+       (message-send-mail-with-sendmail): Require sendmail.
+       (canlock-password, canlock-password-for-verify): Declare.
+       (message-canlock-password): Require canlock.
+       (nnheader-get-report): Autoload.
+       (gnus-setup-posting-charset): Declare.
+       (message-send-news): Require gnus-msg.
+       (message-make-references, message-make-in-reply-to): Use mail-header-id
+       rather than the alias mail-header-message-id.
+       (ecomplete-add-item, ecomplete-save): Declare.
+       (message-put-addresses-in-ecomplete): Require ecomplete.
+       (ecomplete-display-matches): Autoload.
+
+       * mm-decode.el: Don't require mailcap, gnus-util.
+       (gnus-map-function, gnus-replace-in-string, gnus-read-shell-command)
+       (message-fetch-field, mailcap-parse-mailcaps, mailcap-mime-info):
+       Autoload.
+       (mailcap-mime-extensions): Declare.
+
+       * mm-encode.el: Don't require mailcap.
+       (mailcap-extension-to-mime): Autoload.
+
+       * mml-sec.el: Don't require password-cache.
+
+       * mml.el (gnus-setup-posting-charset): Declare rather than autoload.
+       (mailcap-parse-mimetypes, mailcap-mime-types): Declare.
+       (mml-minibuffer-read-type): Require mailcap.
+       (mml-preview): Require gnus-msg.
+
+       * mml1991.el: Require password-cache.
+       (password-cache-expiry): Remove declaration.
+
+       * mml2015.el: Require password-cache.
+       (password-cache-expiry): Remove declaration.
+
+       * nneething.el (mailcap): Require mailcap.
+
+       * nnheader.el (declare-function): Add compatibility stub.
+       (message-remove-header): Declare rather than autoload.
+       (nnheader-replace-header): Require message.
+
+       * nnimap.el (declare-function): Add compatibility stub.
+       (netrc-parse, netrc-machine-user-or-password): Declare.
+       (nnimap-open-connection): Require netrc.
+
+       * nntp.el (declare-function): Add compatibility stub.
+       (netrc-parse, netrc-machine, netrc-get): Declare.
+       (nntp-send-authinfo): Require netrc.
+
+       * rfc2047.el: Don't require qp.
+       (quoted-printable-encode-region, quoted-printable-decode-string):
+       Autoload.
+
+       * sieve-mode.el: Don't require easymenu.
+       (easy-menu-add-item): Autoload it.
+
+       * spam-stat.el (time-to-number-of-days): Autoload it.
+
+2010-03-19  Glenn Morris  <rgm@gnu.org>
+
+       * password-cache.el (password-cache, password-cache-expiry): Autoload.
+
+2010-03-18  Glenn Morris  <rgm@gnu.org>
+
+       * hashcash.el (declare-function): Remove duplicate definition.
+
+2010-03-17  Kevin Ryde  <user42@zip.com.au>
+
+       * mml.el (mml-read-tag): Unquote values with `read' to reverse
+       prin1 in mml-insert-tag (just stripping the quotes gave wrong
+       value if any backslash escapes).
+
+2010-03-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-charset-to-coding-system): Use coding-system-from-name
+       if it is available.  (bug#5647)
+
+       * lpath.el: Suppress compiler warning for coding-system-from-name for
+       Emacs 21 and XEmacs.
+
+2010-03-14  Juri Linkov  <juri@jurta.org>
+
+       * hmac-def.el:
+       * hmac-md5.el:
+       * netrc.el: Fix keywords.
+
+2010-02-26  Glenn Morris  <rgm@gnu.org>
+
+       * message.el (message-send-mail-function): Change the default, so that
+       it inherits from a customized send-mail-function.  (Bug#5643)
+
+2010-02-24  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-art.el (gnus-treat-display-x-face): Don't burp if
+       shell-command-to-string signals an error (bug#5299).
+
+2010-02-24  Glenn Morris  <rgm@gnu.org>
+
+       * message.el (message-smtpmail-send-it)
+       (message-send-mail-with-mailclient): Doc fixes.
+
+2010-02-16  Glenn Morris  <rgm@gnu.org>
+
+       * message.el (message-default-mail-headers): Change the default value
+       to ease the transition from mail-mode to message-mode.  (Bug#5555)
+
+2010-01-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * parse-time.el (parse-time-syntax): Define it for only XEmacs.
+       (parse-time-string-chars): Implement 2009-08-16 change for Emacs.
+
+2010-01-18  Chong Yidong  <cyd@stupidchicken.com>
+
+       * time-date.el (date-to-time): Doc fix (Bug#5408).
+
+2010-01-17  Chong Yidong  <cyd@stupidchicken.com>
+
+       * message.el (message-mail): Just pass yank-action on to message-setup.
+       (message-setup): Handle (FUN . ARGS) form of yank-action.
+       (message-with-reply-buffer, message-widen-reply)
+       (message-yank-original): Handle non-buffer values of
+       message-reply-buffer (Bug#4080).
+       (message-setup-1): Prefer to save message-reply-buffer as a buffer.
+
+2010-01-17  Juanma Barranquero  <lekktu@gmail.com>
+
+       * nnmairix.el (nnmairix-group-delete-recreate-this-group):
+       Fix typo in docstring.
+
+2010-01-08  Jason Rumney  <jasonr@gnu.org>
+
+       * sieve-manage.el (sieve-manage-parse-capability-1): Loosely match OK
+       response.
+
+2010-01-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-describe-bindings): Work for prefix keys.
+
+       * gnus-xmas.el (gnus-xmas-article-describe-bindings): Ditto.
+
+       * message.el (message-check-news-header-syntax): Protect against a
+       string that `rfc822-addresses' returns when parsing fails.
+
+2010-01-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-invisible-p, gnus-next-char-property-change)
+       (gnus-previous-char-property-change): New functions.
+
+       * gnus-sum.el (gnus-forward-line-ignore-invisible): Use them.
+
+2010-01-05  Andreas Schwab  <schwab@linux-m68k.org>
+
+       * gnus-sum.el (gnus-forward-line-ignore-invisible): New function.
+       (gnus-summary-recenter): Use it instead of forward-line.  (Bug#5257)
+
+2010-01-02  Chong Yidong  <cyd@stupidchicken.com>
+
+       * message.el (message-exchange-point-and-mark): Rework last change to
+       avoid using optional arg of exchange-point-and-mark, for backward
+       compatibility.
+
+2010-01-01  Chong Yidong  <cyd@stupidchicken.com>
+
+       * message.el (message-exchange-point-and-mark):
+       Call exchange-point-and-mark with an argument rather than setting
+       mark-active by hand (Bug#5175).
+
+2009-12-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nntp.el (nntp-service-to-port): Work for service expressed with
+       numeric string; replace [:digit:] with [0-9] for XEmacs.
+
+2009-12-17  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-group.el (gnus-bug-group-download-format-alist):
+       Change emacs entry to debbugs.gnu.org.  Bump :version.
+
+2009-12-13  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-encode.el (mm-sign-option, mm-encrypt-option): Add :version tag.
+
+2009-12-12  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-info): Explain why we use `Info-goto-node'.
+
+2009-12-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Always bind default-file-name-coding-system for (S)XEmacs.
+
+2009-12-02  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * message.el (message-completion-in-region): New compatibility function.
+       (message-expand-group): Use it.
+
+2009-12-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el (gnus-group-prepare-flat): Check also whether groups
+       with no unread article should be listed if the 2nd arg `predicate' is
+       given.
+
+2009-11-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind recenter-top-bottom for Emacs 21, 22, and (S)XEmacs.
+
+2009-11-29  Juri Linkov  <juri@jurta.org>
+
+       * gnus-sum.el (gnus-recenter): Use `recenter-top-bottom'
+       when it is fboundp in GNU Emacs 23.1.  Put `isearch-scroll' property
+       on `gnus-recenter'.  (Bug#4698, Bug#4981)
+
+2009-11-26  Kevin Ryde  <user42@zip.com.au>
+
+       * sha1.el (sha1-string-external): default-directory "/" in case
+       otherwise non-existent.  process-connection-type pipe for touch of
+       efficiency recommended by elisp manual.  (An aside in Bug#3911.)
+
+2009-11-25  Kevin Ryde  <user42@zip.com.au>
+
+       * dns-mode.el: Add "Keywords: comm".  It's only an editing mode, but
+       it's comms related and sgml-mode.el has "comm" on that basis too.
+
+2009-11-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-decode-region): Don't quote decoded words
+       containing tspecial characters if they have been already quoted.
+
+2009-11-05  Dan Nicolaescu  <dann@ics.uci.edu>
+
+       * dns-mode.el (auto-mode-alist): Purecopy string.
+
+2009-11-03  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * hashcash.el (hashcash-generate-payment): Use with-current-buffer.
+
+2009-10-24  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-art.el (help-xref-stack-item): Define for compiler.
+
+2009-10-21  Kevin Ryde  <user42@zip.com.au>
+
+       * dns.el: Add "Keywords: comm", as per net/net-utils.el.
+
+2009-10-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-remove-overlays): eval-and-compile.
+
+2009-10-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-show-thread): Remove useless goto-char.
+       (gnus-summary-show-thread, gnus-summary-hide-thread): Indent.
+
+2009-10-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (gnus-overlay-get): New alias to overlay-get.
+       (gnus-overlays-in): New alias to overlays-in.
+
+       * gnus-sum.el (gnus-remove-overlays): Use gnus-overlays-in,
+       gnus-overlay-get, and gnus-delete-overlay.
+       (gnus-summary-show-thread): Make it work as well for systems in which
+       next-single-char-property-change is not available.
+       (gnus-summary-hide-thread): Use gnus-make-overlay and gnus-overlay-put.
+
+       * gnus-xmas.el (gnus-xmas-overlays-in): New function.
+       (gnus-overlay-get): New alias to extent-property.
+       (gnus-overlays-in): New alias to gnus-xmas-overlays-in.
+
+       * dgnushack.el: Autoload add-to-invisibility-spec for XEmacs 21.4 and
+       SXEmacs.
+
+       * lpath.el: Fbind next-single-char-property-change for XEmacs 21.4 and
+       SXEmacs.
+
+2009-10-14  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-remove-overlays): Add doc string and alias.
+
+2009-10-14  Dan Nicolaescu  <dann@ics.uci.edu>
+
+       * gnus-sum.el (gnus-remove-overlays): Compatibility code for Emacs 21
+       and XEmacs that don't have `remove-overlays'.
+
+2009-10-14  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-sum.el (gnus-summary-mode, gnus-summary-show-all-threads)
+       (gnus-summary-show-thread, gnus-summary-hide-thread): Get rid of
+       selective display.  Use overlays instead.
+
+2009-10-04  Juanma Barranquero  <lekktu@gmail.com>
+
+       * spam-stat.el (spam-stat-strip-xref): Fix typo in docstring.
+
+2009-09-29  Juanma Barranquero  <lekktu@gmail.com>
+
+       * spam-stat.el (spam-stat-load): Fix typo in message.
+
+2009-09-24  Juanma Barranquero  <lekktu@gmail.com>
+
+       * dig.el (dig-invoke): Fix typo in docstring.
+       (query-dig): Reflow docstring.
+
+2009-09-23  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus-art.el (gnus-article-encrypt-body):
+       * message.el (message-check-recipients):
+       * mm-util.el (mm-codepage-setup):
+       * nnir.el (gnus-summary-nnir-goto-thread, nnir-run-waissearch)
+       (nnir-run-swish++, nnir-run-swish-e): Fix typos in error messages.
+
+2009-09-22  Daiki Ueno  <ueno@unixuser.org>
+
+       * mm-encode.el (mm-sign-option, mm-encrypt-option): New user option.
+       * mml2015.el (mml2015-epg-sign, mml2015-epg-encrypt): Let users select
+       keys from the menu if mm-{sign,encrypt}-option is 'guided.
+       * mml-smime.el (mml-smime-epg-sign, mml-smime-epg-encrypt): Ditto.
+       * mml1991.el (mml1991-epg-sign, mml1991-epg-encrypt): Ditto.
+
+2009-09-21  Kevin Ryde  <user42@zip.com.au>
+
+       * dig.el: Add "Keywords: comm", as per net-utils.el.
+
+2009-09-21  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * dig.el (dig-mode): Use define-derived-mode.
+
+2009-09-19  Glenn Morris  <rgm@gnu.org>
+
+       * pgg-pgp.el (pgg-pgp-encrypt-region): Add missing mapconcat separator.
+
+2009-09-18  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-diary.el (gnus-diary-check-message):
+       * message.el (message-insert-formatted-citation-line):
+       * nnbabyl.el (top-level):
+       * nndiary.el (nndiary-schedule):
+       Fix typos in condition-case handlers.
+
+2009-09-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-edit-part): Work for the buffer
+       configuration that provides the sole article window in a frame;
+       position point correctly after deleting a part.
+
+2009-09-14  Adam Sjøgren  <asjo@koldfront.dk>
+
+       * spam.el (spam-unregister-on-reregister): Add boolean variable.
+       (spam-resolve-registrations-routine): Use it to unregister articles
+       that change status.
+
+2009-09-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * parse-time.el (parse-time-syntax): Restore it to keep compatibility
+       with XEmacs.
+       (parse-time-string-chars): Use it.
+
+2009-09-10  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * imap.el (imap-interactive-login): Better messages.
+       (imap-open): Fix bug with renamed buffer on reconnect.
+       (imap-authenticate): Add buffer-local imap-last-authenticator variable
+       for easier debugging and cleaner code.  On successful (guessed based on
+       server capabilities) secondary authentication, set imap-state
+       correctly.
+       (imap-last-authenticator): Define imap-last-authenticator as a variable
+       to avoid warnings.
+
+2009-09-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnrss.el (nnrss-request-article): Remove binding of
+       default-enable-multibyte-characters that has gotten needless by
+       the 2007-07-13 change in rfc2047-encode-message-header.
+
+       * mml.el (mml-insert-multipart): Error on the message header.
+       (mml-insert-part): Error on the message header; position point at
+       the end of a MIME tag.
+
+2009-09-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * time-date.el (autoload): Expand define-obsolete-function-alias into
+       defalias and make-obsolete for old Emacsen that Gnus supports.
+       (with-no-warnings): Define it for old Emacsen.
+       (time-to-seconds): Don't use (featurep 'xemacs) to check if float-time
+       is available.
+       (time-to-number-of-days): Don't use (featurep 'xemacs) to check if
+       float-time is available; suppress compile warning for time-to-seconds.
+
+       * gnus-util.el (with-no-warnings): Define it for old Emacsen.
+       (gnus-float-time): Alias to float-time if it exists.
+
+       * ecomplete.el (with-no-warnings): Define it for old Emacsen.
+       (ecomplete-add-item): Don't use (featurep 'xemacs) to check if
+       float-time is available; suppress compile warning for time-to-seconds.
+
+       * lpath.el: Fbind time-to-seconds for Emacs 21.; fbind float-time for
+       XEmacs.
+
+2009-09-09  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * imap.el (imap-message-map): Docstring fix.
+
+2009-09-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-encode.el (mm-encode-buffer): Don't force 7bit encoding since MTA
+       may break data.  Suggested by Dmitri Paduchikh <dpaduch@k66.ru>.
+       Add the optional argument `encoding' that overrides the default.
+
+       * mml.el (mml-generate-mime-1): Pass encoding defined by a user to
+       mm-encode-buffer.
+
+2009-09-04  Glenn Morris  <rgm@gnu.org>
+
+       * qp.el (quoted-printable-encode-string): Use mm-enable-multibyte, or
+       mm-disable-multibyte, rather than default-enable-multibyte-characters.
+       * utf7.el (utf7-encode, utf7-decode): Use mm-with-multibyte-buffer, or
+       mm-with-unibyte-buffer, rather than default-enable-multibyte-characters.
+       * mm-util.el (mm-with-unibyte-current-buffer)
+       (mm-find-buffer-file-coding-system):
+       * yenc.el (yenc-decode-region): Use default-value rather than
+       default-enable-multibyte-characters.
+
+2009-09-03  Glenn Morris  <rgm@gnu.org>
+
+       * mm-util.el (mm-emacs-mule, mm-default-multibyte-p):
+       * rfc2047.el (rfc2047-encode-message-header): Use default-value rather
+       than default-enable-multibyte-characters.
+
+2009-09-02  Karl Kleinpaste  <karl@kleinpaste.org>
+
+       * gnus-art.el (gnus-article-read-summary-keys):
+       Fix gnus-buffer-configuration's value temporarily used.
+
+2009-09-02  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-util.el (gnus-float-time): New function.
+       * gnus-delay.el (gnus-delay-article):
+       * gnus-sum.el (gnus-thread-latest-date):
+       * gnus-util.el (gnus-user-date): Use gnus-float-time.
+       * nnspool.el (nnspool-request-newgroups):
+       Use gnus-float-time rather than time-to-seconds.
+       * ecomplete.el (ecomplete-add-item): In Emacs, use float-time.
+
+       * gnus-art.el (gnus-signature-face, gnus-header-from-face)
+       (gnus-header-subject-face, gnus-header-newsgroups-face)
+       (gnus-header-name-face, gnus-header-content-face):
+       * gnus-cite.el (gnus-cite-attribution-face, gnus-cite-face-1)
+       (gnus-cite-face-2, gnus-cite-face-3, gnus-cite-face-4)
+       (gnus-cite-face-5, gnus-cite-face-6, gnus-cite-face-7)
+       (gnus-cite-face-8, gnus-cite-face-9, gnus-cite-face-10)
+       (gnus-cite-face-11):
+       * gnus-picon.el (gnus-picon-xbm-face, gnus-picon-face):
+       * gnus-srvr.el (gnus-server-agent-face, gnus-server-opened-face)
+       (gnus-server-closed-face, gnus-server-denied-face)
+       (gnus-server-offline-face):
+       * gnus.el (gnus-group-news-1-face, gnus-group-news-1-empty-face)
+       (gnus-group-news-2-face, gnus-group-news-2-empty-face)
+       (gnus-group-news-3-face, gnus-group-news-3-empty-face)
+       (gnus-group-news-4-face, gnus-group-news-4-empty-face)
+       (gnus-group-news-5-face, gnus-group-news-5-empty-face)
+       (gnus-group-news-6-face, gnus-group-news-6-empty-face)
+       (gnus-group-news-low-face, gnus-group-news-low-empty-face)
+       (gnus-group-mail-1-face, gnus-group-mail-1-empty-face)
+       (gnus-group-mail-2-face, gnus-group-mail-2-empty-face)
+       (gnus-group-mail-3-face, gnus-group-mail-3-empty-face)
+       (gnus-group-mail-low-face, gnus-group-mail-low-empty-face)
+       (gnus-summary-selected-face, gnus-summary-cancelled-face)
+       (gnus-summary-high-ticked-face, gnus-summary-low-ticked-face)
+       (gnus-summary-normal-ticked-face, gnus-summary-high-ancient-face)
+       (gnus-summary-low-ancient-face, gnus-summary-normal-ancient-face)
+       (gnus-summary-high-undownloaded-face)
+       (gnus-summary-low-undownloaded-face)
+       (gnus-summary-normal-undownloaded-face)
+       (gnus-summary-high-unread-face, gnus-summary-low-unread-face)
+       (gnus-summary-normal-unread-face, gnus-summary-high-read-face)
+       (gnus-summary-low-read-face, gnus-summary-normal-read-face)
+       (gnus-splash-face):
+       * message.el (message-header-to-face, message-header-cc-face)
+       (message-header-subject-face, message-header-newsgroups-face)
+       (message-header-other-face, message-header-name-face)
+       (message-header-xheader-face, message-separator-face)
+       (message-cited-text-face, message-mml-face):
+       * sieve-mode.el (sieve-control-commands-face)
+       (sieve-action-commands-face, sieve-test-commands-face)
+       (sieve-tagged-arguments-face):
+       * spam.el (spam-face):
+       Mark face aliases with "-face" in the name as obsolete.
+
+2009-09-01  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-salt.el (gnus-pick-mouse-pick-region): Use forward-line rather
+       than goto-line.
+
+2009-08-31  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml.el (mml-attach-file, mml-attach-buffer, mml-attach-external):
+       Don't move point if the command is invoked inside the message header.
+
+2009-08-30  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * imap.el (imap-send-command): Simplify.
+       (imap-wait-for-tag): point-max -> buffer-size.
+
+2009-08-29  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * spam.el (spam-ifile-path, spam-bogofilter-path, spam-sa-learn-path)
+       (spam-ifile-database-path, spam-bsfilter-path, spam-spamassassin-path):
+       * nnmail.el (nnmail-spool-file, nnmail-fix-eudora-headers):
+       * nnir.el (nnir-swish-e-index-file):
+       * gnus-sum.el (gnus-summary-delete-marked-as-read)
+       (gnus-summary-delete-marked-with, gnus-summary-mark-as-unread-forward)
+       (gnus-summary-mark-as-unread-backward, gnus-summary-mark-as-unread):
+       * gnus-msg.el (gnus-inews-mark-gcc-as-read):
+       * gnus-art.el (gnus-article-hide-pgp-hook, gnus-treat-strip-pgp)
+       (gnus-treat-display-xface): Add Emacs version of obsolescence.
+
+2009-08-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml.el (mml-attach-file, mml-attach-buffer, mml-attach-external):
+       Don't save excursion.
+
+2009-08-28  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * nnheader.el (nnheader-find-file-noselect):
+       * mm-util.el (mm-insert-file-contents):
+       Use (default-value 'major-mode) instead of default-major-mode.
+
+2009-08-27  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * nnrss.el (nnrss-request-article): Avoid default-fill-column.
+
+2009-08-26  Glenn Morris  <rgm@gnu.org>
+
+       * parse-time.el (parse-time-rules): Autoload riskiness here, rather
+       than placing in files.el.
+
+2009-08-25  Glenn Morris  <rgm@gnu.org>
+
+       * nnir.el (top-level): Don't require cl at run-time.
+       (nnir-run-waissearch, nnir-run-swish-e, nnir-run-hyrex):
+       Replace cl-function substitute with gnus-replace-in-string.
+       (nnir-run-waissearch, nnir-run-swish++, nnir-run-swish-e)
+       (nnir-run-hyrex, nnir-run-namazu): Replace cl-function sort* with sort.
+       (nnir-run-find-grep): Replace cl-functions find-if and subseq with
+       simplified expansions.
+
+2009-08-25  Kevin Ryde  <user42@zip.com.au>
+
+       * dig.el (dig): Add autoload cookie.
+
+2009-08-22  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-art.el (gnus-button-patch): Use forward-line rather than
+       goto-line.
+
+2009-08-16  Chong Yidong  <cyd@stupidchicken.com>
+
+       * parse-time.el (parse-time-string-chars): Save match data.
+
+2009-08-16  Jan Seeger  <jan.seeger@thenybble.de>  (tiny change)
+
+       * parse-time.el (parse-time-string-chars): Compute using character
+       classes, to handle non-ascii characters (Bug#3190).
+
+2009-08-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el (gnus-safe-html-newsgroups): New user option.
+
+       * gnus-art.el (gnus-bind-safe-url-regexp): New macro.
+       (gnus-mime-view-all-parts, gnus-mime-view-part-internally)
+       (gnus-mm-display-part, gnus-mime-display-single)
+       (gnus-mime-display-alternative): Use gnus-bind-safe-url-regexp to
+       override mm-w3m-safe-url-regexp according to gnus-safe-html-newsgroups.
+
+       * gnus-sum.el
+       (gnus-mark-copied-or-moved-articles-as-expirable): New user option.
+       (gnus-summary-move-article): Add expirable mark to articles copied or
+       moved to group that has auto-expire turned on if the option is non-nil.
+
+2009-07-24  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-demon.el (gnus-demon-add-nntp-close-connection):
+       Fix typo.  (Bug#3903)
+
+2009-07-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-mode-map): Bind the "e" key to
+       gnus-article-read-summary-keys rather than gnus-summary-edit-article
+       that should not be used for draft articles.
+       (gnus-article-read-summary-keys): Use key-binding instead of lookup-key
+       that has no concern in minor mode keys.
+       (gnus-article-summary-command, gnus-article-summary-command-nosave):
+       Abolish.
+
+2009-07-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnrss.el (nnrss-request-article): Allow mml-to-mime to generate MIME
+       article without making inquiry to a user for unknown encoding.
+
+       * nnmaildir.el (nnmaildir--group-maxnum, nnmaildir--new-number)
+       (nnmaildir--scan): Assume i-node and device number that file-attributes
+       returns might be cons-cell.
+
+       * dgnushack.el: Autoload thing-at-point for XEmacs 21.5.
+
+       * lpath.el: Fbind cp-supported-codepages for XEmacs 21.5.
+
+2009-07-16  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el: Remove docs now in auth.texi.  Don't use
+       `gnus-message' for logging.  Add new variables `auth-source-debug' and
+       `auth-source-hide-passwords' and use them.
+
+2009-07-15  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-spec.el (gnus-make-format-preserve-properties): Doc fix.
+
+2009-07-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el (gnus-group-make-rss-group): Strip newlines and
+       excessive whitespace from the default values of title and description.
+
+2009-06-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-dissect-buffer): Use message-fetch-field instead of
+       mail-fetch-field to fetch Content-Description header in order to
+       exclude newlines.
+
+2009-06-18  Ulrich Mueller  <ulm@gentoo.org>
+
+       * pgg-gpg.el (pgg-gpg-lookup-key-owner): Handle colon listings
+       format used by GnuPG 2.0.11.
+
+2009-06-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-delete-part): Specify gnus-decoded as charset
+       to deleted part.
+
+2009-05-30  David Engster  <dengste@eml.cc>
+
+       * nnmairix.el: Remove old documentation in the commentary block.
+       (nnmairix-request-group): Do not update active file for nnml back ends.
+       (nnmairix-retrieve-headers): Set gnus-nov-is-evil to t for nnimap back
+       end so that overview files are ignored.
+       (nnmairix-update-groups): Make updating the groups more robust by using
+       marks.
+       (nnmairix-determine-original-group-from-path): Circumvent mairix bug
+       with dollar characters in message-id.
+
+2009-04-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * spam.el: Use dns-query instead of query-dns.  Was renamed on
+       2008-12-25 in dns.el.
+
+2009-04-20  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * rfc2047.el (rfc2047-decode-region): Don't skip past `start', which
+       could happen if the text is only composed of spaces and/or tabs.
+
+2009-03-03  Brian Sniffen  <bts@evenmere.org>  (tiny change)
+
+       * gnus-draft.el (gnus-draft-send): Bind gnus-message-setup-hook to nil
+       when sending a queued message to avoid extra mml tags.
+
+2009-03-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml.el (mml-insert-mime): Don't break parts that mm-uu dissected.
+
+2009-02-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind rmail-swap-buffers-maybe for Emacs 21~22;
+       fbind rmail-msg-restore-non-pruned-header, rmail-swap-buffers-maybe and
+       rmail-toggle-header for XEmacs;
+       bind rmail-default-file and rmail-default-rmail-file for XEmacs.
+
+2009-02-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-dired.el: Remove autoload for gnus-setup-message.
+       (gnus-dired-attach): Fake this-command value to prevent Gnus from
+       displaying Gnus logo; always use compose-mail.
+
+2009-02-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-dired.el: Tell autoload that gnus-setup-message is a macro.
+
+2009-02-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-nocem.el (gnus-nocem-groups): Remove invalid NoCeM groups.
+       (gnus-nocem-issuers): List currently active issuers; fix custom type.
+       (gnus-nocem-verifyer): Default to gnus-nocem-epg-verify if EasyPG is
+       available.
+       (gnus-nocem-epg-verify): New function.
+
+2009-02-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button-alist): Recognize Konqueror info links.
+
+2009-02-15  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-util.el (rmail-insert-rmail-file-header)
+       (rmail-count-new-messages, rmail-show-message): Remove unnecessary
+       autoloads.
+       (rmail-default-rmail-file): Remove unnecessary declaration.
+       (gnus-output-to-rmail): Handle mbox Rmail as well as Babyl Rmail.
+
+2009-02-14  Glenn Morris  <rgm@gnu.org>
+
+       * gnus.el (rmail-default-rmail-file): Remove declaration of deleted
+       variable (only used in gnus-util, which declares it anyway).
+       (rmail-output-to-rmail-file): Remove autoload of deleted function,
+       which was only needed by gnus-art (changed to not use it any more).
+       (rmail-insert-rmail-file-header): Remove autoload of deleted function,
+       only used in gnus-util, which autoloads it itself.
+       (rmail-update-summary): Fix autoload.
+
+       * gnus-art.el (gnus-summary-save-in-mail): Use gnus-output-to-rmail
+       rather than rmail-output-to-rmail-file.
+
+2009-02-07  Glenn Morris  <rgm@gnu.org>
+
+       * message.el (rmail-msg-restore-non-pruned-header): Remove unneeded
+       autoload of function that no longer exists.
+       (rmail-toggle-header): Declare.
+       (message-forward-rmail-make-body): Handle mbox Rmail.
+
+2009-01-31  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-sum.el (gnus-summary-next-article): XEmacs-friendly version of
+       2009-01-09 change.
+
+2009-01-31  Dave Love  <fx@gnu.org>
+
+       * imap.el (imap-fetch-safe): Bind debug-on-error.
+       (imap-debug): Add imap-fetch-safe.
+
+2009-01-26  Teodor Zlatanov  <tzlatanov@jumptrading.com>
+
+       * auth-source.el (auth-source-forget-user-or-password): Clarify docs.
+       (auth-source-forget-all-cached): New convenience function.
+       (auth-source-user-or-password): Accept list of modes or a single mode.
+
+       * mail-source.el (mail-source-bind, mail-source-set-1): Use list of
+       auth-source modes.
+
+       * netrc.el (netrc-machine-user-or-password): Use list of
+       auth-source modes.
+
+       * nnimap.el (nnimap-open-connection): Use list of
+       auth-source modes.
+
+       * nntp.el (nntp-send-authinfo): Use list of
+       auth-source modes.
+
+2009-01-16  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el: Update docs to reflect epa-file-enable is to be used
+       now.
+
+2009-01-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnmail.el (nnmail-pathname-coding-system): Default to the `file-name'
+       coding system in XEmacs; add a workaround for XEmacs.
+
+       * lpath.el: Fbind coding-system-aliasee.
+
+2009-01-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-coding-system-priorities): Protect against nil value
+       of current-language-environment.
+
+2009-01-13  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnfolder.el (nnfolder-read-folder): Check if most-positive-fixnum is
+       available at runtime.
+
+2009-01-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-date-ut): Fix end point of narrowing.
+
+2009-01-11  Aidan Kehoe  <kehoea@parhasard.net>
+
+       * nnfolder.el (nnfolder-read-folder): The (lsh -1 -1) trick to generate
+       the greatest positive fixnum value doesn't work under an XEmacs with
+       bignum support; use the most-positive-fixnum constant instead,
+       available since Emacs 21.1 with cl and XEmacs 21.1.
+
+2009-01-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-next-article): Revert last change by which
+       XEmacs gets not to work.
+
+2009-01-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-coding-system-priorities): Allow the value like
+       "Japanese (UTF-8)" of current-language-environment.
+
+2009-01-09  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-sum.el (gnus-summary-next-article): Replace last-command-char
+       with last-command-event.
+
+2009-01-08  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * imap.el (imap-enable-exchange-bug-workaround): Explain auto-detection
+       in the doc string.
+
+       * message.el (message-fix-before-sending): Amend comment.
+
+2009-01-08  Dave Love  <fx@gnu.org>
+
+       * imap.el (imap-message-appenduid-1): Fix typo in imap-fetch-safe call.
+
+2009-01-07  David Engster  <dengste@eml.cc>
+
+       * gnus-msg.el (gnus-inews-do-gcc): Fix last patch to deal with
+       simplified server definitions by converting it via
+       gnus-server-to-method.
+
+2009-01-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-set-local-parameters): Always evaluate
+       parameter's operands.
+
+2009-01-06  David Engster  <dengste@eml.cc>
+
+       * gnus-msg.el (gnus-inews-do-gcc): Reduce to short group name when on
+       primary select method (for gnus-group-mark-article-as-read).
+
+2009-01-06  Tassilo Horn  <tassilo@member.fsf.org>
+
+       * gnus-art.el (gnus-treat-display-face): Fix docstring link to point to
+       `(gnus)Face', not `(gnus)X-Face'.
+
+2009-01-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-ucs-to-char): New function.
+
+       * mm-url.el (mm-url-decode-entities): Use it.
+
+       * lpath.el: Fbind decode-char, int-to-char, ucs-to-char and
+       unicode-to-char.
+
+2009-01-05  Dave Love  <fx@gnu.org>
+
+       * time-date.el: Require cl for `declare'.
+
+2009-01-05  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * time-date.el (format-seconds): Explain `assoc-string'.  Suggested by
+       Dave Love.
+
+2009-01-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-fix-before-sending): Add `eight-bit' to
+       illegible-text check.
+
+2009-01-03  Michael Olson  <mwolson@gnu.org>
+
+       * nnimap.el (nnimap-retrieve-headers-progress): Handle edge case where
+       `headers' is nil.  This can occur if the IMAP server does not have
+       permissions to read messages from a folder, but can write new messages
+       to the folder.
+       (nnimap-request-article-part): Do not insert `data' if it is nil.
+
+       * imap.el (imap-parse-fetch): Courier can insert spurious blank
+       characters which will confuse `read', so skip past them.
+
+2009-01-01  Dave Love  <fx@gnu.org>
+
+       * imap.el (imap-string-to-integer): Fix typo.
+       (imap-fetch-safe): New function.
+       (imap-message-copyuid-1, imap-message-appenduid-1): Use it.
+
+       * nnimap.el (nnimap-find-minmax-uid): Use imap-fetch-safe.
+
+       * imap.el (imap-process-connection-type, imap-debug, imap-open):
+       (imap-parse-greeting): Fix doc strings.
+       (imap-tls-open, imap-search, imap-message-appenduid-1): Add FIXMEs.
+       (imap-parse-flag-list): Make messages unique.
+       (imap-parse-body): Fix comments.  Add comment on Exchange 2007.
+
+       * nnimap.el: Fix author email.
+       (nnimap-split-rule): Add FIXME comment.
+       (nnimap-debug): Fix doc string.
+
+2008-12-26  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * dns.el (dns-set-servers): Check "Address".  Fix typo.
+
+2008-12-25  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * dns.el (dns-set-servers): Renamed from dns-parse-resolv-conf.  Call
+       nslookup if resolv.conf isn't available.
+       (dns-query): Rename from query-dns.
+       (dns-query-cached): Rename from query-dns-cached.
+
+2008-12-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-set-article-display-arrow): Make
+       overlay-arrow-position and overlay-arrow-string buffer-local; no need
+       to check if those variables exist (first appeared in Emacs 18.50).
+
+2008-12-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-line-number-at-pos): New function.
+
+       * spam-report.el (spam-report-process-queue): Use it.
+
+2008-12-24  David Engster  <dengste@eml.cc>
+
+       * gnus-sum.el (gnus-summary-set-local-parameters): Don't bind
+       parameters that haven't existed as variables as buffer-local variables.
+
+2008-12-23  Dave Love  <fx@gnu.org>
+
+       * legacy-gnus-agent.el (gnus-agent-unlist-expire-days): Don't use
+       cadar.
+
+       * sieve-manage.el (sieve-manage-starttls-p): Rename from
+       imap-starttls-p.
+       (sieve-manage-starttls-open): Rename from imap-starttls-open.
+
+2008-12-22  Dave Love  <fx@gnu.org>
+
+       * imap.el: Fix author email.  Doc fixes.
+       (imap-parse-body): Work around assertion failure in bogus Exchange 2007
+       reply.
+
+2008-12-22  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * spam-report.el (spam-report-gmane-max-requests): New constant.
+       (spam-report-gmane-wait): New variable.
+       (spam-report-gmane-ham, spam-report-gmane-spam)
+       (spam-report-url-ping-plain, spam-report-process-queue): Wait only if
+       spam-report-gmane-wait is non-nil should be sufficient to avoid DOS-ing
+       the server.
+
+       * nnheader.el (nnheader-read-timeout, nnheader-accept-process-output):
+       Add explanations.
+
+       * pop3.el (pop3-accept-process-output, pop3-read-timeout): Use
+       nnheader-accept-process-output and nnheader-read-timeout if available.
+       (pop3-movemail): Use it.
+
+       * message.el (message-check-news-body-syntax): Fix signature check if
+       there's an attachment.
+
+2008-12-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el: Add comments to the mm- emulating functions.
+
+2008-12-21  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-start.el (gnus-before-startup-hook): Fix doc string.
+       Reported by Stephen Berman <stephen.berman@gmx.net>.
+
+2008-12-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-substring-no-properties): New function.
+       (mm-read-charset, mm-subst-char-in-string, mm-replace-in-string)
+       (mm-special-display-p): Enable those lambda forms to be byte compiled.
+       (mm-string-to-multibyte): Doc fix.
+
+       * mml.el (mml-attach-file): Use mm-substring-no-properties.
+
+2008-12-18  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mml.el (mml-attach-file): Strip text properties from file name.
+       (Bug#1574)
+
+2008-12-16  Glenn Morris  <rgm@gnu.org>
+
+       * mm-util.el (mm-charset-override-alist): Declare for compiler.
+
+2008-12-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml.el (mml-generate-mime-1): Prefer the MIME charset that Emacs
+       knows since the charset specified might be a bogus alias that
+       mm-charset-synonym-alist provides.
+
+2008-12-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-util.el (mm-charset-synonym-alist): Add bogus names "UTF8" and
+       "ISO_8859-1".
+
+       * gnus-start.el (gnus-backup-startup-file): Improve doc string.
+
+2008-12-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-charset-eval-alist):
+       Define it before mm-charset-to-coding-system.
+       (mm-charset-to-coding-system): Add optional argument `silent';
+       define it before mm-charset-override-alist.
+       (mm-charset-override-alist): Add `(gb2312 . gbk)' to the
+       default value if it can be used in Emacs currently running;
+       silence mm-charset-to-coding-system.
+
+2008-12-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-charset-to-coding-system): Add new argument
+       `allow-override' which says whether to use `mm-charset-override-alist'.
+       (rfc2047-decode-encoded-words): Use it.
+
+       * mm-util.el (mm-charset-override-alist): Fix custom type;
+       add `(gb2312 . gbk)' to choices.
+
+2008-12-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-view.el (mm-inline-text-html-render-with-w3m): Make it simple and
+       fast.
+
+       * gnus-art.el (gnus-article-wash-html-with-w3m): Ditto.
+
+       * lpath.el: Bind w3m-link-map for Emacs 21, 22, and XEmacs.
+
+2008-12-04  Naohiro Aota  <nao.aota@gmail.com>
+
+       * mm-view.el (mm-inline-text-html-render-with-w3m): Put special keymap
+       on links.
+
+       * gnus-art.el (gnus-article-wash-html-with-w3m): Ditto.
+
+2008-12-03  Lute Kamstra  <lute@gnu.org>
+
+       * sha1.el: Remove leading * from docstrings of defcustoms,
+       deffaces, defconsts and defuns.
+
+2008-12-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-idna-to-ascii-rhs-1): Protect against local
+       users' addresses that don't have domain parts.
+       (message-idna-to-ascii-rhs): Use message-narrow-to-headers-or-head
+       rather than message-narrow-to-head since there will be the message
+       header separator.
+
+2008-12-02  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * nnimap.el (nnimap-retrieve-headers-progress): Don't use nnimap-demule
+       since the result is inserted in a unibyte buffer anyway.
+       (nnimap-demule-use-string-to-multibyte): Remove.
+       (nnimap-demule): Alias it to mm-string-to-multibyte.
+
+2008-11-29  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnimap.el (nnimap-demule-use-string-to-multibyte): New temporary
+       variable for debugging bug#464 and bug#1174.
+       (nnimap-demule): Use it.
+
+2008-11-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-score.el (gnus-score-find-trace): Handle default score in total
+       score calculation correctly.
+
+2008-11-21  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * message.el (message-send-mail): Just set the buffer to unibyte
+       rather than use mm-with-unibyte-current-buffer which does a lot more.
+       (message-send-mail-partially): Don't bother with
+       mm-with-unibyte-current-buffer since it's already been made unibyte by
+       message-send-mail.
+
+2008-11-11  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * nnrss.el (nnrss-make-hash-index): Debug message of full item.
+
+2008-11-10  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * netrc.el (netrc-parse): If a list is passed in as FILE, return it.
+
+2008-11-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * starttls.el (starttls-any-program-available): Rewritten so it doesn't
+       require itself and to remove `with-no-warnings'.
+
+2008-11-03  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * starttls.el (starttls-any-program-available): Get the name of the
+       available TLS layer program.
+       (starttls-open-steam-gnutls, starttls-open-stream): Put port number as
+       well as the host name in the "opening" message.
+
+       * auth-source.el (auth-source-cache, auth-source-do-cache)
+       (auth-source-user-or-password): Cache passwords and logins by default,
+       allow override with `auth-source-do-cache'.
+       (auth-source-forget-user-or-password): Allow users to remove cache
+       entries if needed.
+
+2008-11-01  Juanma Barranquero  <lekktu@gmail.com>
+
+       * md4.el (md4-buffer): Fix typo in docstring.
+       (md4, md4-64): Doc fixes.
+       (md4-pack-int32): Reflow docstring.
+
+2008-10-31  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * ietf-drums.el (ietf-drums-remove-comments): Localize second
+       condition-case to only the forward-sexp call.
+
+2008-10-31  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * ietf-drums.el (ietf-drums-remove-comments): Fix bug with single
+       quotes contained.  Make it more robust regardless by an extra
+       condition-case wrapper.
+
+2008-10-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: No need to fbind codepage-setup for Emacs 23.
+
+2008-10-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnml.el (nnml-request-expire-articles): Check if the function set to
+       `nnmail-expiry-target' returns the symbol `delete'.
+
+       * nnfolder.el (nnfolder-request-expire-articles): Ditto.
+
+       * nnmail.el (nnmail-expiry-target): Fix custom type.
+
+2008-10-02  Glenn Morris  <rgm@gnu.org>
+
+       * mm-util.el (mm-codepage-setup): Tweak codepage error.
+       Silence compiler warning.
+
+2008-10-01  Magnus Henoch  <mange@freemail.hu>
+
+       * tls.el (open-tls-stream): Show the actual command being
+       executed, instead of the format string.
+
+2008-10-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind codepage-setup for Emacs 23.
+
+2008-09-30  Chong Yidong  <cyd@stupidchicken.com>
+
+       * mml.el (mml-menu): Don't assume mml2015 is bound.
+
+2008-09-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-read-summary-keys): Check if summary window
+       exists.
+
+2008-09-27  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-util.el (mail-header-remove-comments): Autoload it.
+
+2008-09-27  Andreas Schwab  <schwab@suse.de>
+
+       * gnus-util.el (gnus-split-references): Strip comments.
+       (gnus-parent-id): Likewise.
+
+2008-09-26  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-confirm-send): Fix version.
+
+2008-09-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-idna-to-ascii-rhs-1): Use
+       mail-extract-address-components rather than mail-header-parse-addresses
+       that is an alias by default to ietf-drums-parse-addresses that does not
+       support non-ASCII names in headers' contents.
+
+2008-09-25  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * message.el (message-confirm-send): Fix variable documentation to
+       avoid the "y/n" wording.
+
+2008-09-25  Francis Litterio  <flitterio@gmail.com>  (tiny change)
+
+       * message.el (message-set-auto-save-file-name): Save to a different
+       filename so multiple messages (especially drafts) can be recovered.
+
+2008-09-24  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * message.el (message-confirm-send): Add appropriate version.
+
+2008-09-22  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * mm-view.el (mm-pkcs7-enveloped-magic): Fix extra parenthesis in
+       defvar.
+
+2008-09-22  Daiki Ueno  <ueno@unixuser.org>
+
+       * mm-view.el (mm-pkcs7-signed-magic): Use literals.
+       (mm-pkcs7-enveloped-magic): Ditto.
+
+2008-09-17  Simon Josefsson  <simon@josefsson.org>
+
+       * sieve-manage.el (sieve-manage-is-string): Accept literals too.
+       Reported by Arnt Gulbrandsen <arnt@oryx.com>.
+
+2008-09-16  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-use-long-group-names): Make t the
+       default, it's better.
+
+2008-09-11  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-sum.el (gnus-summary-insert-line): Trap errors on setting the
+       summary line gnus-number property and ignore them (with a warning
+       message).
+
+2008-09-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el (gnus-group-make-useful-group): Don't use the compiler
+       macro caddr in the interactive form since it won't be expanded.
+
+2008-09-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-set-charset-parameters): Add new argument
+       `charset'; fix name of function called recursively.
+       (gnus-mime-view-part-as-charset): Don't bind gnus-newsgroup-charset.
+
+2008-09-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-strip-charset-parameters): Remove.
+       (gnus-mime-set-charset-parameters): New function.
+       (gnus-mime-view-part-as-charset): Use it to correctly display part
+       specifying wrong charset.
+
+2008-09-08  David Engster  <dengste@eml.cc>
+
+       * nnmairix.el (nnmairix-create-server-and-default-group): Require match
+       in completing-read for back end server.
+
+2008-09-03  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * message.el (message-confirm-send): New variable to confirm sending a
+       message.
+       (message-send): Use it.
+
+2008-08-30  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-spec.el (gnus-parse-simple-format): Revert last patch.
+
+2008-08-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-spec.el (gnus-parse-simple-format): Remove trailing whitespace.
+
+2008-08-21  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-max-track-groups): New variable to
+       prevent tracking too many groups.
+       (gnus-registry-split-fancy-with-parent, gnus-registry-fetch-groups):
+       Use it.
+
+2008-08-11  Ralf Angeli  <angeli@caeruleus.net>
+
+       * gnus-art.el (gnus-article-next-page): Respect `scroll-margin' when
+       moving point to the bottom of the window in order to avoid recentering.
+
+2008-08-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Bind scroll-margin for XEmacs 21.4 and SXEmacs.
+
+       * gnus-art.el (gnus-article-next-page, gnus-article-prev-page)
+       (gnus-article-next-page-1): Use compiler directive (featurep 'xemacs).
+       (gnus-article-beginning-of-window): Fix calculation.
+
+2008-08-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-summary-supersede-article)
+       (gnus-summary-resend-message-edit): Bind mail-parse-charset to the
+       value of gnus-newsgroup-charset to decode non-MIME encoded text in
+       message header.
+
+2008-08-02  Chong Yidong  <cyd@stupidchicken.com>
+
+       * pgg-gpg.el (pgg-gpg-process-region): Accept any remaining
+       pending output coming after the status change.
+
+2008-07-31  Dan Nicolaescu  <dann@ics.uci.edu>
+
+       * message.el:
+       * gnus-start.el:
+       * gnus-registry.el: Remove VMS support.
+
+2008-07-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2104.el (rfc2104-string-make-unibyte): Define it as a compiler
+       macro.
+       (rfc2104-hash): Use it.
+
+2008-07-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-summary-sort-by-most-recent-number)
+       (gnus-summary-sort-by-most-recent-date): New commands.
+       (gnus-summary-mode-map, gnus-summary-make-menu-bar): Add key bindings
+       and menu entries.
+
+2008-07-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-summary-save-in-pipe): Generate work buffer always;
+       don't redisplay article for raw contents; remove plural articles stuff.
+
+       * gnus-sum.el (gnus-summary-pipe-output): Pipe raw articles by symbolic
+       prefix `r'; use gnus-summary-save-in-pipe directly instead of relying
+       on gnus-summary-save-article; display results properly.
+
+2008-07-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: No need to fbind ns-focus-frame.
+
+2008-07-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-summary-save-in-pipe): Add optional argument `raw'.
+
+2008-07-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-summary-save-in-pipe):
+       Consider gnus-save-all-headers.
+
+2008-07-21  Dan Nicolaescu  <dann@ics.uci.edu>
+
+       * gnus-util.el (ns-focus-frame): Remove declaration.
+       (gnus-select-frame-set-input-focus): Undo previous change.  Treat ns
+       like x.
+
+2008-07-21  Thien-Thi Nguyen  <ttn@gnuvola.org>
+
+       * rfc2104.el (rfc2104-zero): Delete defconst.
+       (rfc2104-hex-alist): Likewise.
+       (rfc2104-hex-to-int): Delete func.
+       (rfc2104-hexstring-to-bitstring): Likewise.
+       (rfc2104-nybbles): New defconst.
+       (rfc2104-hash): Rewrite for speed.
+
+2008-07-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * tls.el (open-tls-stream): Make it work with the 2nd argument
+       BUFFER that is a string but does not exist as a buffer object, as
+       mentioned in the doc-string.
+
+2008-07-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind ns-focus-frame for Emacs 21, 22, XEmacs 21.4, and
+       SXEmacs.
+
+2008-07-16  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-util.el (ns-focus-frame): Declare for compiler.
+
+2008-07-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-save): Ignore gnus-visible-headers that is
+       set as a group parameter.
+       (gnus-summary-save-in-pipe): Work when it is called independently.
+       (gnus-summary-pipe-to-muttprint): Don't modify
+       gnus-summary-pipe-output-default-command.
+
+2008-07-10  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * message.el (message-send-mail-with-sendmail):
+       Display the error message.
+
+2008-07-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-default-article-saver):
+       Add gnus-summary-save-in-pipe to choices.
+       (gnus-summary-save-in-pipe): Add :decode and :headers properties; use
+       gnus-summary-pipe-output-default-command as the default command.
+       (gnus-summary-pipe-to-muttprint): Update gnus-summary-muttprint-program
+       instead of gnus-last-shell-command.
+
+       * gnus-sum.el (gnus-summary-pipe-output-default-command):
+       New user option.
+       (gnus-summary-muttprint-program): Mention the value will be changed.
+       (gnus-summary-save-article): Force showing of all headers.
+       (gnus-summary-pipe-output): Work with the 2nd argument HEADERS.
+
+2008-07-01  Rupert Swarbrick  <rswarbrick@googlemail.com>  (tiny change)
+
+       * gnus-score.el (gnus-score-find-trace): Add "Total score" line.
+
+2008-07-02  Juanma Barranquero  <lekktu@gmail.com>
+
+       * nnimap.el (nnimap-id):
+       * sieve-manage.el (sieve-manage-open): Doc fixes.
+
+2008-07-02  Francesc Rocher  <rocher@member.fsf.org>
+
+       * gnus.el (gnus-group-startup-message): Prefer SVG or PNG image,
+       if available.
+
+2008-06-25  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * mm-util.el (mm-with-multibyte, mm-with-unibyte): Remove.
+
+       * nnkiboze.el (nnkiboze-generate-group):
+       Use explicit mm-disable-multibyte rather than mm-with-unibyte.
+
+       * nnmairix.el: Require CL.
+
+2008-06-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el: Autoload get-display-table and put-display-table for
+       XEmacs 21.5.
+
+       * lpath.el: Fbind get-display-table and put-display-table for XEmacs
+       21.4 and SXEmacs.
+
+2008-06-15  David Engster  <dengste@eml.cc>
+
+       * nnimap.el (nnimap-request-delete-group): Unselect group if necessary.
+
+2008-06-14  Aidan Kehoe  <kehoea@parhasard.net>
+
+       * gnus-util.el (gnus-put-display-table, gnus-get-display-table):
+       New macros that expand to an `aset'/`aref' call under Emacs, and to a
+       runtime choice under XEmacs.
+
+       * gnus-sum.el (gnus-summary-set-display-table):
+       Use `gnus-put-display-table', `gnus-get-display-table',
+       `gnus-set-display-table' for the display table, instead of `aset'.
+
+       * gnus-xmas.el (gnus-xmas-summary-set-display-table):
+       Use `gnus-put-display-table', `gnus-get-display-table',
+       `gnus-set-display-table' for the display table.
+
+2008-06-14  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnmairix.el: Add autoloads.
+
+2008-06-14  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnmairix.el (nnmairix-delete-recreate-group)
+       (nnmairix-update-and-clear-marks): Fix error messages.
+
+2008-06-14  David Engster  <dengste@eml.cc>
+
+       * nnmairix.el: Upgrade to version 0.6.
+       (nnmairix-group-toggle-propmarks-this-group)
+       (nnmairix-group-toggle-readmarks-this-group)
+       (nnmairix-group-delete-recreate-this-group)
+       (nnmairix-group-toggle-allowfast-this-group, nnmairix-propagate-marks)
+       (nnmairix-remove-tick-mark-original-article): New commands.
+       (nnmairix-mairix-search-options, nnmairix-propagate-marks-upon-close)
+       (nnmairix-propagate-marks-to-nnmairix-groups)
+       (nnmairix-only-use-registry, nnmairix-allowfast-default)
+       (nnmairix-marks-cache, nnmairix-version-output): New variables.
+       (nnmairix-request-set-mark, nnmairix-request-update-info): New back end
+       functions needed for marks propagation and manipulation of read marks.
+       (nnmairix-update-groups): New function.
+       (nnmairix-get-groups-from-server, nnmairix-delete-recreate-group)
+       (nnmairix-determine-original-group-from-registry)
+       (nnmairix-determine-original-group-from-path)
+       (nnmairix-get-group-from-file-path, nnmairix-map-range)
+       (nnmairix-check-mairix-version, nnmairix-group-toggle-parameter):
+       New helper functions.
+       (nnmairix-group-mode-hook, nnmairix-summary-mode-hook): Insert new
+       keystrokes for new commands.
+       (nnmairix-delete-and-create-on-change): Doc string cleanup.
+       (nnmairix-request-group): Check allow-fast group parameter.
+       (nnmairix-request-create-group): Set allow-fast group parameter if
+       nnmairix-allowfast-default is set.
+       (nnmairix-close-group): Propagate marks upon closing if needed.
+       (nnmairix-group-toggle-threads-this-group): Use new.
+       nnmairix-group-toggle-parameter helper function.
+       (nnmairix-search): Better check for empty search result.
+       (nnmairix-goto-original-article): Use new helper functions for
+       determining original article.
+       (nnmairix-show-original-article): Make sure message-id is in brackets.
+       (nnmairix-call-mairix-binary): Change variable name.
+       (nnmairix-update-and-clear-marks): Use nnmairix-delete-recreate-group
+       helper function.
+       (nnmairix-widget-toggle-activate): Fix doc string.
+
+2008-06-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnir.el: Require edmacro when compiling with XEmacs.
+       (nnir-run-find-grep): Don't use 3rd arg of `split-string' which is not
+       available in Emacs 21.
+
+2008-06-11  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-util.el (x-focus-frame):
+       * gnus.el (image-size):
+       * mm-decode.el (image-size): Declare.
+
+       * gnus-picon.el (declare-function): Add compat definition.
+       (image-size): Declare.
+
+       * gnus-group.el (tool-bar-map):
+       * gnus-sum.el (tool-bar-map): Define for compiler.
+
+       * gnus-ems.el (gnus-x-splash): Check tool-bar-mode is bound.
+
+       * nnfolder.el (gnus-intersection): Remove unnecessary autoload.
+
+       * gnus-agent.el, gnus-cache.el, gnus-ems.el, gnus-group.el:
+       * gnus-logic.el, gnus-msg.el, gnus-util.el, gnus.el, mail-source.el:
+       * message.el, mm-decode.el, mm-encode.el, mm-view.el, mml.el:
+       * mml1991.el, mml2015.el, nnfolder.el, nnheader.el, nnimap.el:
+       * nnmail.el, nnml.el, nnrss.el, nntp.el, nnvirtual.el:
+       * sieve-manage.el, spam-report.el, spam.el:
+       Remove unnecessary eval-and-compile of autoloads.
+
+2008-06-08  Michael Albinus  <michael.albinus@gmx.de>
+
+       * auth-source.el: Precise Tramp doc.
+
+2008-06-07  Glenn Morris  <rgm@gnu.org>
+
+       * nnmairix.el: Remove unnecessary eval-when-compile.
+
+2008-06-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind propertize for XEmacs 21.4.
+
+2008-06-05  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnir.el: Move here from ../contrib.
+
+2008-06-05  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-util.el (gnus-read-shell-command): New function.
+       * mm-decode.el (mm-pipe-part):
+       * gnus-art.el (gnus-summary-save-in-pipe): Use it.
+
+2008-06-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-disassociate-draft): Revert 2008-03-18 change.
+
+2008-06-03  Glenn Morris  <rgm@gnu.org>
+
+       * pop3.el (nnheader-accept-process-output): Autoload it.
+
+2008-05-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2231.el (rfc2231-decode-encoded-string): Don't decode things that
+       are not 2-digit hexadecimal characters that follow `%'s.
+
+2008-05-29  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-bogus-recipient-p): Fix type in doc string.
+       Reported by Stephen Eglen <S.J.Eglen@damtp.cam.ac.uk>.
+       (message-bogus-addresses): Rename from message-bogus-address-regexp.
+       Improve custom options.
+       (message-bogus-recipient-p): Adjust accordingly.
+
+2008-05-27  Chong Yidong  <cyd@stupidchicken.com>
+
+       * parse-time.el (parse-time-months, parse-time-weekdays): Add
+       long-form month and day names.
+
+2008-05-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el: Autoload debug, eudc-expand-inline and
+       pgg-snarf-keys-region for XEmacs.
+
+       * lpath.el: Fbind w3m-region, bind ps-print-color-p for XEmacs.
+
+       * nnmairix.el: Require edmacro when compiling with XEmacs.
+
+2008-05-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-summary-initial-limit): Use unless instead of if.
+       (gnus-fetch-old-headers): Warn about setting it to t for Gmane groups.
+
+2008-05-20  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el: Add more docs.
+
+       * netrc.el (netrc-machine): Always match if the port is not given.
+
+2008-05-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnheader.el (nnheader-read-timeout): Change the default timeout from
+       0.1 seconds to 0.01 seconds.  This will make nntp and pop3 article
+       retrieval faster in some cases, but might make CPU usage larger.
+       If this has any bad side effects, we might revert this change.
+
+       * pop3.el (pop3-movemail): Change the sit-for from 0.1 to 0.01, which
+       seems to make mail retrieval much, much faster.
+       (pop3-movemail): Use nnheader-accept-process-output instead of sleeping
+       unconditionally.
+
+       * gnus-draft.el (gnus-group-send-queue):
+       Bind message-send-mail-partially-limit to nil to avoid being prompted.
+
+2008-05-16  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mml.el (mml-attach-buffer): Prompt for `disposition'.
+
+       * message.el (message-bogus-address-regexp): Fix and improve custom
+       type.
+       (message-setup-hook): Add message-check-recipients as custom option.
+
+2008-05-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-cite-function): Remove bogus autoload which crept
+       in during merge from v5-10.
+
+2008-05-14  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * nnimap.el (nnimap-open-connection): Fix login/password bug.
+
+       * nnrss.el (nnrss-normalize-date): Accept Unix-style epoch timestamps.
+
+       * auth-source.el: Preliminary Tramp docs.
+       (auth-sources): Change the default auth-sources to use
+       EPA .gpg files.
+
+2008-05-09  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * nntp.el: Autoload `auth-source-user-or-password'.
+       (nntp-send-authinfo): Use it.
+
+       * nnimap.el: Autoload `auth-source-user-or-password'.
+       (nnimap-open-connection): Use it.
+
+       * auth-source.el: Add docs on using with url-auth.  Import gnus-util
+       for the gnus-message function.
+       (auth-source-user-or-password): Use it.
+
+2008-05-08  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * rfc2104.el (rfc2104-hexstring-to-bitstring): Rename it back from
+       rfc2104-hexstring-to-byte-list.  Return a unibyte string.
+       (rfc2104-hash): Use it.
+
+2008-05-08  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus-art.el (gnus-article-toggle-truncate-lines):
+       Don't use `iff' in docstring.
+
+2008-05-07  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el: Adjusted copyright dates and added a keyword.
+
+       * gnus-util.el (gnus-extract-address-component-name)
+       (gnus-extract-address-component-email): Convenience functions around
+       `gnus-extract-address-components'.
+
+       * gnus-registry.el (gnus-registry-split-fancy-with-parent):
+       Use `gnus-extract-address-component-email' to fix bug of comparing full
+       sender name to `user-mail-address'.
+
+2008-05-05  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-grep-in-list): Fix logic, use
+       catch/throw to optimize.
+       (gnus-registry-find-keywords): Just use member to find a keyword.
+
+2008-05-07  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-srvr.el (gnus-enter-server-buffer): Make sure the server-buffer
+       is current before calling gnus-server-prepare.
+       (gnus-server-setup-buffer, gnus-server-update-server)
+       (gnus-server-read-server, gnus-browse-exit): Use with-current-buffer.
+
+2008-05-04  Juri Linkov  <juri@jurta.org>
+
+       * mailcap.el (mailcap-replace-in-string): New compatibility alias.
+       (mailcap-file-default-commands): Use mailcap-replace-in-string
+       instead of replace-regexp-in-string, and mailcap-delete-duplicates
+       instead of delete-dups.  Use [ \t\n]* for whitespace in regexp.
+
+2008-05-03  Reiner Steib  <reiner.steib@gmx.de>
+
+       * gnus-sum.el (gnus-propagate-marks): Fix custom version.
+
+2008-05-01  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Bump version to 0.11.
+
+2008-05-01  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: No Gnus v0.10 is released.
+
+2008-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-save-parts): Inhibit even more treatment
+       hooks.
+       (gnus-update-read-articles): Speed up non-marks-using users.
+       (gnus-use-marks): Define gnus-use-marks.
+       (gnus-propagate-marks): Rename variable to something more sensible.
+
+2008-05-02  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gmm-utils.el (gmm, gmm-verbose, gmm-lazy, gmm-customize-mode)
+       (gmm-image-load-path-for-library): Fix typos in docstrings.
+       (gmm-message): Reflow docstring.
+
+2008-04-28  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * mail-source.el (mail-source-set-1, mail-source-bind):
+       Move auth-source code out of the macro to clean it up and fix bugs.
+
+2008-04-26  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-split-fancy-with-parent): Don't split
+       by sender if it's equal to user-mail-address, it's likely to be
+       useless.
+
+       * mail-source.el (mail-source-bind): Don't use user or password if they
+       are not bound.  Unintern them if they are nil.  Don't use server unless
+       it's bound, and default it to empty string otherwise.
+
+2008-04-25  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * mail-source.el: Load auth-source.el.
+       (mail-source-bind): Add comments.  Call auth-source-user-or-password to
+       get user name or password, if auth-sources is set up.
+
+       * gnus-registry.el (gnus-registry-split-strategy): New variable for
+       strategy of splitting with parent.
+       (gnus-registry-split-fancy-with-parent)
+       (gnus-registry-post-process-groups): Use it and fix prior
+       bug (returning a list as the split result).
+
+       * auth-source.el (auth-sources): Remove server parameter.
+       (auth-source-pick, auth-source-user-or-password)
+       (auth-source-user-or-password-imap)
+       (auth-source-user-or-password-pop3, auth-source-user-or-password-ssh)
+       (auth-source-user-or-password-sftp)
+       (auth-source-user-or-password-smtp): Remove server parameter.
+
+2008-04-25  Juanma Barranquero  <lekktu@gmail.com>
+
+       * smime.el (smime-sign-region, smime-encrypt-region)
+       (smime-decrypt-region):
+       Remove redundant calls to `generate-new-buffer-name'.
+
+2008-04-24  Luca Capello  <luca@pca.it>  (tiny change)
+
+       * mm-encode.el (mm-safer-encoding): Add optional argument `type'.
+       Don't use QP for message/rfc822.
+       (mm-content-transfer-encoding): Pass `type' to mm-safer-encoding.
+
+2008-04-24  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * sieve-manage.el (sieve-string-bytes): Remove.
+       (sieve-manage-putscript): Use length instead: `string-bytes' gives the
+       correct byte-length only if the process's coding-system is the same as
+       the one used internally by Emacs to represent strings.
+
+2008-04-22  Juri Linkov  <juri@jurta.org>
+
+       * mailcap.el (mailcap-file-default-commands): New function.
+
+2008-04-13  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-signature-separator, message-cite-function):
+       Change custom version.
+
+2008-04-13  Naohiro Aota  <nao.aota@gmail.com>  (tiny change)
+
+       * tls.el (tls-program): Add -ign_eof argument to call the openssl
+       commands.
+       (tls-checktrust): Ditto.
+
+2008-04-13  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-decode.el (mm-display-external): Make temp file read-only.
+
+2008-04-12  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-diary.el (gnus-article-edit-mode-map, message-mode-map): Remove
+       binding for `gnus-diary-version'.  Bind `gnus-diary-check-message' to
+       `C-c C-f d'.
+
+2008-04-12  Adrian Aichner  <adrian@xemacs.org>
+
+       * gnus-sum.el (gnus-summary-goto-subject): Typo fix.
+
+2008-04-11  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.el: Bump version to 0.9.
+
+2008-04-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.el: No Gnus v0.8 is released.
+
+2008-04-10  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * mail-source.el (mail-source-value):
+       Prefer fboundp to functionp so it works with macros as well.
+
+2008-04-10  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-win.el (gnus-configure-frame, gnus-all-windows-visible-p):
+       Fix last change in case the element is not even a symbol.
+
+2008-04-10  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-win.el (gnus-configure-frame, gnus-all-windows-visible-p):
+       Prefer fboundp to functionp so it works with macros as well.
+
+2008-04-09  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el: Add docs.
+       (auth-sources): Modify format to support server.
+       (auth-source-pick, auth-source-user-or-password)
+       (auth-source-user-or-password-imap)
+       (auth-source-user-or-password-pop3, auth-source-user-or-password-ssh)
+       (auth-source-user-or-password-sftp)
+       (auth-source-user-or-password-smtp): Add server parameter.
+
+2008-04-08  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el: Initialize the registry when gnus-registry-install
+       is t.
+
+2008-04-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * compface.el (uncompface): Make buffer unibyte.
+
+2008-04-07  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * mail-source.el (mail-source-value):
+       Prefer fboundp to functionp so it works with macros as well.
+
+2008-04-05  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-ems.el (mm-disable-multibyte): Autoload it.
+
+2008-04-05  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * mm-util.el (mm-with-unibyte-buffer, mm-with-multibyte-buffer):
+       Prefer mm-(en|dis)able-multibyte to default-enable-multibyte-characters.
+
+       * nnheader.el (nnheader-init-server-buffer): Change buffer's
+       multibyteness after rather than before erasing it.
+
+       * gnus-art.el (gnus-mime-replace-part): Remove unnecessary use of
+       mm-with-multibyte.
+       (gnus-request-article-this-buffer): Make sure the proper decoding is
+       used if gnus-original-article-buffer happens to be unibyte.
+
+       * gnus-ems.el (gnus-x-splash): Prefer mm-disable-multibyte to
+       default-enable-multibyte-characters.
+
+       * gnus-fun.el (gnus-display-x-face-in-from): Remove unnecessary use of
+       default-enable-multibyte-characters.
+
+       * mm-decode.el (mm-inline-media-tests): Add entry for x-diff.
+
+       * nnweb.el (nnweb-init): Avoid nn-with-unibyte.
+
+2008-04-03  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-win.el (gnus-configure-frame, gnus-all-windows-visible-p):
+       Fix last change in case the element is not even a symbol.
+
+2008-04-02  Simon Josefsson  <simon@josefsson.org>
+
+       * imap.el (imap-enable-exchange-bug-workaround): New variable.
+       (imap-message-copyuid-1): Use it.
+       (imap-message-appenduid-1): Likewise.  Based on patch by Nathan
+       J. Williams in
+       <http://permalink.gmane.org/gmane.emacs.gnus.general/65855>.
+
+       * nnimap.el (nnimap-enable-minmax-bug-workaround): Remove, replaced by
+       imap-enable-exchange-bug-workaround.
+       (nnimap-find-minmax-uid): Use imap-enable-exchange-bug-workaround.
+
+2008-04-01  Simon Josefsson  <simon@josefsson.org>
+
+       * nnimap.el (nnimap-find-minmax-uid): Revert last fix, the "fix" turns
+       a 100 byte status-checks into a 2-3MB transfer for each group.
+       (nnimap-enable-minmax-bug-workaround): New variable to toggle whether
+       to enable bug workaround or not.
+       (nnimap-find-minmax-uid): Only enable workaround conditionally.
+
+2008-03-31  Glenn Morris  <rgm@gnu.org>
+
+       * message.el (mml2015-use): Declare for compiler.
+       (message-info): Require mml2015 when appropriate.
+
+2008-03-31  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * Makefile.in (EMACS_COMP): Quote directory name that might contain
+       whitespace.
+
+2008-03-30  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * nntp.el (nntp-netcat-command): Rename from nntp-via-netcat-command.
+       (nntp-netcat-switches): Rename from nntp-via-netcat-switches.
+       (nntp-open-telnet, nntp-open-rlogin): Use with-current-buffer.
+       (nntp-service-to-port): New function.
+       (nntp-open-via-rlogin-and-netcat, nntp-open-via-telnet-and-telnet)
+       (nntp-open-telnet-stream, nntp-open-via-rlogin-and-telnet): Use it.
+       (nntp-open-netcat-stream): New function.
+       (nntp-open-via-rlogin-and-netcat): Don't use a pty.
+
+2008-03-29  Sven Joachim  <svenjoac@gmx.de>
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Add missing dots.
+
+2008-03-29  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * message.el (message-make-in-reply-to): Use mm-with-multibyte-buffer.
+
+2008-03-28  Magnus Henoch  <mange@freemail.hu>
+
+       * dns.el (dns-write): Use set-buffer-multibyte.
+
+2008-03-28  Michael Harnois  <mdharnois@gmail.com>  (tiny change)
+
+       * nnimap.el (nnimap-find-minmax-uid): Fix Exchange 2007 IMAP problem.
+
+2008-03-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-signature-separator): Change default.
+       Improve custom type.
+       (message-cite-function): Change default to
+       message-cite-original-without-signature.
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Add message-cite-function
+       toggle.
+
+       * message.el (message-check-news-body-syntax): Fix signature check.
+       (message-setup-1): Mark buffer as unmodified _after_ running
+       message-setup-hook and handling message-alternative-emails.
+       (message-shorten-references): Be more strict when building list of
+       valid references to comply with GNKSA.
+
+       * gnus-group.el (gnus-read-ephemeral-bug-group)
+       (gnus-read-ephemeral-debian-bug-group)
+       (gnus-read-ephemeral-emacs-bug-group): Use the correct variable.
+
+       * message.el (message-info): Don't use booleanp which isn't supported
+       in Emacs 21 and XEmacs.
+
+2008-03-22  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-group.el (gnus-gmane-group-download-format): Rename from
+       gnus-group-gmane-group-download-format.
+       (gnus-group-read-ephemeral-gmane-group): Rename from
+       gnus-group-read-ephemeral-gmane-group.
+       (gnus-read-ephemeral-gmane-group-url): Rename from
+       gnus-group-read-ephemeral-gmane-group-url.
+       (gnus-bug-group-download-format-alist): New variable.
+       (gnus-read-ephemeral-bug-group, gnus-read-ephemeral-debian-bug-group)
+       (gnus-read-ephemeral-emacs-bug-group): New commands.
+
+2008-03-21  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-article-browse-html-article): Fix documentation.
+       (gnus-visible-headers): Improve custom type.
+
+2008-03-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mml.el (mml-menu): Add workarounds for XEmacs.
+
+       * gnus-art.el (gnus-article-browse-html-article): Inhibit display of
+       X-Boundary header.
+
+       * message.el (message-simplify-recipients): Fix previous commit.
+
+2008-03-20  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * mm-util.el (mm-set-buffer-multibyte): New function.
+       * mm-decode.el (mm-copy-to-buffer): Use it.
+
+       * gnus-win.el (gnus-configure-frame, gnus-all-windows-visible-p):
+       Prefer fboundp to functionp so it works with macros as well.
+
+2008-03-19  Glenn Morris  <rgm@gnu.org>
+
+       * tls.el (open-tls-stream): Restore use of `tls-end-of-info'.
+       Accidentally removed in the sync process with Emacs.
+
+2008-03-19  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-alter-recipients-discard-bogus-full-name):
+       New function.
+       (message-alter-recipients-function): New variable.
+       (message-get-reply-headers): Use it.
+       (message-replace-header): New helper function.
+       (message-recipients-without-full-name): New variable.
+       (message-simplify-recipients): New command.
+
+       * mml.el (mml-menu): Add toggle for gnus-gcc-externalize-attachments.
+
+       * message.el (message-info): Handle EasyPG manual.
+
+       * mml.el (mml-menu): Add entry for EasyPG.
+
+2008-03-18  Nils Ackermann  <nils@ackermath.info>  (tiny change)
+
+       * nnmh.el (nnmh-request-expire-articles): Prefer expiry-target group
+       parameter.
+
+       * message.el (message-disassociate-draft): Specify drafts group name
+       fully.
+
+2008-03-17  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-split-fancy-with-parent):
+       Eliminate unnecessary duplicates from the match list.
+
+2008-03-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el: Autoload Info-index and Info-index-next for XEmacs.
+
+       * lpath.el: Fbind Info-index and Info-index-next for Emacs 21, 22.
+
+       * gnus-art.el (gnus-button-handle-info-keystrokes): Don't use optional
+       args of `how-many' of which the XEmacs version doesn't take; declare
+       Info-index-next as function.
+
+2008-03-16  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-score.el (gnus-score-headers): Fix handling of
+       gnus-inhibit-slow-scoring.
+
+       * gnus-art.el (gnus-article-browse-html-article): Fix type in doc
+       string.
+       (gnus-button-url-regexp): Improve handling of parenthesis.
+       (gnus-button-alist): Extend gnus-button-handle-info-keystrokes entry.
+       (gnus-button-handle-info-keystrokes): Handle index entries.
+
+2008-03-15  Glenn Morris  <rgm@gnu.org>
+
+       * parse-time.el (parse-time-string): Simplify.
+
+2008-03-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mail-source.el (mail-source-delete-old-incoming) Fix regexp to find
+       Incoming* files.
+
+2008-03-13  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-sources): Rename from auth-source-choices.
+       (auth-source-pick): Use it.
+
+2008-03-12  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * binhex.el (binhex-decode-region-internal):
+       * uudecode.el (uudecode-decode-region-internal):
+       * dns.el (dns-read-string-name, dns-read, dns-read-type, query-dns):
+       * sha1.el (sha1-string-external): Use set-buffer-multibyte rather than
+       setting default-enable-multibyte-characters.
+
+2008-03-12  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el (auth-source-protocols)
+       (auth-source-protocols-customize, auth-source-choices): Add and
+       modified variable customizations and defaults.
+       (auth-source-pick, auth-source-user-or-password)
+       (auth-source-protocol-defaults, auth-source-user-or-password-imap)
+       (auth-source-user-or-password-pop3, auth-source-user-or-password-ssh)
+       (auth-source-user-or-password-sftp)
+       (auth-source-user-or-password-smtp): Use new variables and provide an
+       interface to netrc.el.
+
+2008-03-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nntp.el (nntp-open-telnet-stream, nntp-open-via-rlogin-and-telnet)
+       (nntp-open-via-rlogin-and-netcat, nntp-open-via-telnet-and-telnet):
+       Make sure the nntp port to specify is a string.
+
+2008-03-12  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * nntp.el: Use with-current-buffer.
+       (nntp-send-buffer): Just set the buffer to unibyte rather than use the
+       dubious mm-with-unibyte-current-buffer.
+       (nntp-with-open-group-function): New function extracted from
+       nntp-with-open-group macro.
+       (nntp-with-open-group): Use the function, so it's easier to debug.
+       Add indentation and debugging info.
+       (nntp-open-telnet-stream, nntp-open-via-rlogin-and-telnet):
+       Recommend the use of the netcat alternatives.
+
+       * rfc2047.el (rfc2047-decode-string): Don't use `m'.
+       Avoid mm-string-as-multibyte as well.
+
+       * nnweb.el (nnweb-insert-html):
+       Remove use of nnheader-string-as-multibyte.
+
+       * nnheader.el (nnheader-init-server-buffer): Use with-current-buffer.
+       (nnheader-string-as-multibyte): Remove.
+
+       * mm-view.el: Use inhibit-read-only.
+       (mm-inline-text-html-render-with-w3, mm-inline-message): Use dolist.
+       (mm-pkcs7-signed-magic, mm-pkcs7-enveloped-magic): Use just string
+       or unibyte-string.
+
+       * mm-uu.el (mm-uu-copy-to-buffer): Preserve (uni/multi)byteness.
+       (mm-uu-yenc-extract): Use with-current-buffer.
+
+       * gnus-soup.el (gnus-soup-send-packet): Don't use
+       mm-with-unibyte-current-buffer since the buffer is unibyte anyway.
+
+       * nnmh.el: Use with-current-buffer.
+       (nnmh-request-list-1): Use mm-string-to-multibyte rather than
+       mm-string-as-multibyte on the output of mm-encode-coding-string.
+
+       * nnimap.el (nnimap-retrieve-headers-progress): Use a unibyte buffer.
+       (nnimap-request-move-article): Use with-current-buffer.
+
+       * mm-decode.el (mm-with-part): Set the buffer to unibyte before
+       inserting the handle-buffer's text, so the implicit multibyte->unibyte
+       conversion uses string-make-unibyte rather than string-as-unibyte.
+
+       * gnus-msg.el: Use with-current-buffer.
+
+       * message.el (message-ignored-resent-headers): Add "Delivered-To".
+
+2008-03-10  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el (mml2015-epg-passphrase-callback): Type cast KEY-ID to a
+       string for caching if it is 'PIN.
+
+2008-03-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Consider the case without Emacs/W3.
+
+2008-03-08  Glenn Morris  <rgm@gnu.org>
+
+       * time-date.el (date-to-time, time-subtract, time-add)
+       (safe-date-to-time): Doc fixes.
+
+2008-03-08  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mail-source.el (mail-source-delete-old-incoming-confirm):
+       Change default to nil.
+       (mail-source-delete-old-incoming): Make confirmation prompt more clear.
+
+2008-03-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Rearrange.
+
+       * gnus-art.el (gnus-narrow-to-page): Position point properly.
+       (gnus-article-goto-prev-page): Work for articles having ^L's.
+
+       * gnus-sum.el (gnus-summary-end-of-article): Remove needless narrowing.
+
+       * mm-view.el (mm-w3m-standalone-supports-m17n-p): Fix typo.
+
+2008-03-07  Karl Fogel  <kfogel@red-bean.com>
+
+       * gnus-bookmark.el: Adjust for renames in bookmark.el.
+       (gnus-bookmark-make-record): Was `gnus-bookmark-make-cell'.
+       (gnus-bookmark-jump): Adjust some variable names.
+
+2008-03-06  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth-source.el: New package.
+       (auth-source-choices): Add customization entry point variable.
+
+       * gnus-registry.el (gnus-registry-user-format-function-M): Fix concat
+       bug.
+
+2008-03-05  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-install): Allow 'ask as an option.
+       (gnus-registry-initialize, gnus-registry-install-p): Use it.
+       (gnus-registry-install-shortcuts): Rename from
+       gnus-registry-install-shortcuts-and-menus.  Installs the shortcuts in
+       the `gnus-registry-mark-map' keymap dynamically from
+       `gnus-registry-marks'.  The generated functions update the summary line
+       when a registry mark is added or deleted, and will call
+       `gnus-registry-install-p' (see the comments in the code).
+       (gnus-registry-user-format-function-M): Use concat intelligently.
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Add menu entries for all
+       the registry mark functions.
+
+2008-03-05  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-art.el (gnus-article-mode-line-format-alist): Move to gnus-sum.
+       * gnus-sum.el (gnus-article-mode-line-format-alist): Move here from
+       gnus-art.
+       (top-level): No need to load own source when compiling.
+
+2008-03-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-print-buffer): Honor ps-print-color-p.
+       Suggested by <chris.anderton@zetnet.co.uk>.
+
+2008-03-04  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-sum.el (top-level): No need to require gnus when compiling,
+       since unconditionally required near start of file.
+       (gnus-summary-display-while-building): Move definition before use.
+
+2008-03-04  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-user-format-function-M):
+       Add formatting function.
+
+2008-03-03  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-marks): Change format to be nicer
+       with plists.
+       (gnus-registry-do-marks, gnus-registry-install-shortcuts-and-menus):
+       Use new format.
+
+2008-03-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-describe-bindings): Work for the version of
+       `where-is-internal' that returns a range of key sequences.
+
+2008-03-03  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding): Simplify.
+
+       * gnus-sum.el: Use inhibit-read-only and with-current-buffer.
+       (gnus-summary-jump-to-group): Consider windows on other displayed
+       frames as well.  Similar changes might be needed elsewhere, but that's
+       the one I've bumped into during my use.
+
+       * nndoc.el (nndoc-oe-dbx-type-p):
+       * gnus-msg.el (gnus-debug):
+       * gnus-group.el (gnus-update-group-mark-positions):
+       Use mm-string-to-multibyte.
+
+2008-03-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mml2015.el (mml2015-extract-cleartext-signature): Explain that it
+       doesn't handle NotDashEscaped.
+
+       * mml.el (mml-menu): Improve help entries.  Move Sign/Encrypt Part.
+       (mml-dnd-attach-options): Fix typo in custom choice.
+
+       * gnus-group.el (gnus-group-read-ephemeral-gmane-group):
+       Change nndoc-article-type to mbox.
+       (gnus-group-read-ephemeral-gmane-group-url): Support permalink.
+
+       * mm-decode.el (mm-text-html-renderer): Prefer w3m over w3.  Fall back
+       to nil, instead of html2text.
+
+       * imap.el (imap-debug): Add `imap-ping-server'.
+
+       * gnus-bookmark.el: Add FIXMEs.
+
+       * message.el (message-form-letter-separator)
+       (message-send-form-letter-delay): New variables.
+       (message-send-form-letter): Use them.  New command to send form
+       letters.  Requested by Uwe Siart.
+       (message-send-mail-function): Doc fix.  Add "Other" custom option.
+
+2008-03-01  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Update copyright years.
+
+2008-03-01  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       Sync from EMACS_22_BASE.
+
+       * parse-time.el: Rename elt->parse-time-elt and val->parse-time-val.
+
+2008-02-29  Andreas Seltenreich  <andreas@gate450.dyndns.org>
+
+       * nnweb.el (nnweb-google-parse-1): Fix date parsing on articles with
+       empty author.
+
+2008-02-29  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-marks): Add variable for
+       customization of marks and their appearance.
+       (gnus-registry-read-mark): Use it.
+       (gnus-registry-do-marks): Add utility function to loop through
+       `gnus-registry-marks'.
+       (gnus-registry-install-shortcuts-and-menus): Add function to install
+       shortcuts and menus.
+       (gnus-registry-initialize): Use it.
+       (gnus-registry-default-mark): Clarify documentation.
+
+2008-02-29  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-art.el, gnus-bookmark.el, gnus-dired.el, gnus-draft.el:
+       * gnus-group.el, gnus-msg.el, gnus-score.el, gnus-sum.el, gnus-util.el:
+       * gnus.el, mail-source.el, message.el, mm-decode.el, mm-uu.el, mml.el:
+       * nnmail.el, pop3.el, smiley.el, smime.el, spam-report.el:
+       Change defcustom :version from 23.0 to 23.1.
+
+2008-02-28  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-follow-group-p)
+       (gnus-registry-post-process-groups): Add functions to aid registry
+       splitting and improve logging.  Clarify behavior in function
+       documentation.
+       (gnus-registry-split-fancy-with-parent): Use them.
+
+2008-02-28  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-art.el: Use with-current-buffer.
+
+2008-02-27  David Engster  <dengste@eml.cc>
+
+       * nnmairix.el (nnmairix-request-group-with-article-number-correction):
+       Express real group name in the response.
+
+2008-02-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnmairix.el (nnmairix-group-regexp, nnmairix-valid-backends)
+       (nnmairix-last-server, nnmairix-current-server): Defvar them.
+       (nnmairix-goto-original-article): Defvar gnus-registry-install and
+       autoload gnus-registry-fetch-group when compiling.
+       (nnmairix-request-group-with-article-number-correction):
+       Remove unreferenced argument passed to nnmairix-call-backend.
+
+2008-02-27  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-uu.el (mm-uu-type-alist): Fix message-marks non-hide arguments.
+       (mm-uu-extract): Improve face for low color ttys.
+       Reported by Sascha Wilde.
+
+2008-02-27  Glenn Morris  <rgm@gnu.org>
+
+       * nnmairix.el: Change defcustom :version from 23.0 to 23.1.
+       (nnmairix-group-regexp, nnmairix-valid-backends): Convert from free
+       variables to defconsts.  Convert comments to doc-strings.
+       (nnmairix-last-server, nnmairix-current-server): Convert from free
+       variables to defvars.  Convert comments to doc-strings.
+       (gnus-registry-fetch-group): Autoload.
+       (nnmairix-replace-group-and-numbers): Use mapc rather than mapcar.
+       (nnmairix-widget-get-values, nnmairix-widget-make-query-from-widgets)
+       (nnmairix-widget-build-editable-fields): Use car cddr rather than
+       caddr.
+       (nnmairix-request-group): Bind nnmairix-fast and nnmairix-group around
+       nnmairix-request-group-with-article-number-correction call.
+       (nnmairix-fast, nnmairix-group): New, less general names, for free
+       variables passed from nnmairix-request-group to
+       nnmairix-request-group-with-article-number-correction.  Declare.
+       (nnmairix-request-group-with-article-number-correction):
+       Use nnmairix-fast, nnmairix-group rather than fast, group.
+
+2008-02-26  David Engster  <dengste@eml.cc>
+
+       * nnmairix.el: New file.  Mairix back end for Gnus.  Initial import of
+       version 0.5.
+
+2008-02-26  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-register-message-ids): Use `id'
+       instead of making an extra function call.  Don't add the current group
+       to articles only when they have the group.  Use
+       `gnus-registry-fetch-groups' instead of `gnus-registry-fetch-group'.
+       Reported by David <de_bb@arcor.de>.
+
+2008-02-24  Miles Bader  <miles@gnu.org>
+
+       * mm-util.el (mm-hack-charsets, mm-iso-8859-15-compatible)
+       (mm-iso-8859-x-to-15-table, mm-iso-8859-x-to-15-region)
+       (mm-find-mime-charset-region):
+       * mm-bodies.el (mm-encode-body):
+       * mml.el (mml-parse-1): Revert removal of `mm-hack-charsets'.
+
+2008-02-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind pgg-display-output-buffer for systems in which EasyPG
+       has been installed; bind pgg-parse-crc24 for only non-Mule XEmacs.
+
+2008-02-16  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mail-source.el (mail-source-delete-incoming): Change default.
+       Supplement doc string.
+
+       * gnus-util.el (gnus-y-or-n-p, gnus-y-or-n-p): Update comments.
+
+2008-02-14  Glenn Morris  <rgm@gnu.org>
+
+       * time-date.el (format-seconds): New function.
+
+2008-02-14  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnmail.el (nnmail-message-id-cache-file): Derive from
+       `gnus-home-directory'.
+
+2008-02-11  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-topic.el (gnus-topic-select-group, gnus-topic-read-group):
+       Document negative prefix.
+
+       * gnus-group.el (gnus-group-read-group): Document negative prefix.
+
+2008-02-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-unsent-separator): Add the Exim bounce
+       separator.
+
+2008-02-10  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el (mml2015-epg-sign): Remove skipped signers from the signer
+       list.
+       (mml2015-epg-encrypt): Remove skipped recipients/signers from the
+       recipient/signer list.
+
+2008-02-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * Makefile.in (datarootdir): Define.
+       (EMACS_COMP, install-el, install-elc, install-el-elc): Quote directory
+       name that might contain whitespace.
+
+2008-02-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-util.el (mm-codepage-setup): If cp-supported-codepages isn't
+       fbound (Emacs 23 unicode), signal an error.
+
+2008-02-08  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-art.el (pgg-display-output-buffer): Declare as function.
+
+2008-02-07  Tassilo Horn  <tassilo@member.fsf.org>
+
+       * nnimap.el (nnimap-open-connection): Add "143" and "993" as default
+       ports to the calls to `netrc-machine-user-or-password' in addition to
+       "imap" and "imaps".
+
+2008-02-01  Zhang Wei  <id.brep@gmail.com>
+
+       * rfc2047.el (rfc2047-charset-encoding-alist): Add gbk and GB18030.
+
+       * mm-util.el (mm-mime-mule-charset-alist): Add gbk and GB18030.
+
+2008-02-01  Kenichi Handa  <handa@m17n.org>
+
+       * rfc2104.el (rfc2104-hexstring-to-byte-list): Rename from
+       rfc2104-hexstring-to-bitstring and changed to return a byte list.
+       (rfc2104-hash): Convert the result of concat to unibyte string.
+
+2008-02-01  Dave Love  <fx@gnu.org>
+
+       * gnus-start.el (gnus-read-newsrc-el-file): Don't bind
+       coding-system-for-read.
+       (gnus-gnus-to-quick-newsrc-format): Insert coding cookie.
+
+2008-02-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.el (gnus-group-startup-message): Add `find-image' call before
+       image-load-path is let-bound.  Reported by Harald Hanche-Olsen
+       <hanche@math.ntnu.no>.
+
+2008-02-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-describe-bindings): Work for draft group.
+
+       * gnus-xmas.el (gnus-xmas-article-describe-bindings): Ditto.
+
+2008-01-28  Dan Nicolaescu  <dann@ics.uci.edu>
+
+       * sieve.el (sieve-make-overlay, sieve-overlay-put, sieve-overlays-at):
+       * message.el (message-beginning-of-line): Use featurep instead of bound
+       tests in order to resolve conditionals at compile time.
+
+2008-01-24  Michael Sperber  <sperber@deinprogramm.de>
+
+       * mail-source.el (mail-sources): Add `group' choice.
+
+       * nnmail.el (nnmail-get-new-mail-1): Abstract this out to add another
+       parameter `in-group' to control into which group the articles go.
+       Add treatment of `group' mail-source.
+
+2008-01-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-insert-mime-button): Don't decode description.
+
+       * mm-decode.el (mm-dissect-buffer): Decode description.
+
+       * mml.el (mml-to-mime): Encode message header first.
+
+2008-01-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-describe-bindings): Make it possible to use
+       xrefs, i.e. [back] and [forward] buttons, in *Help* buffer.
+
+       * lpath.el: Fbind help-buffer for Emacs 21 and XEmacs; bind
+       help-xref-stack-item for Emacs 21, Emacs 22.1, and XEmacs.
+
+2008-01-18  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-trim): Use append, not concat.
+
+2008-01-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-read-summary-keys): Work for some `A'
+       prefix keys.
+       (gnus-article-read-summary-send-keys): Use gnus-character-to-event.
+       (gnus-article-describe-bindings): Simplify; move XEmacs stuff to
+       gnus-xmas.el.
+
+       * gnus-xmas.el: Bind gnus-agent-summary-mode when compiling.
+       (gnus-xmas-article-describe-bindings): New function.
+       (gnus-xmas-redefine): Make gnus-article-describe-bindings alias to
+       gnus-xmas-article-describe-bindings.
+
+       * lpath.el: Don't fbind character-to-event and map-keymap for Emacs 21.
+
+2008-01-16  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-marks, gnus-registry-default-mark):
+       Add new variables for article mark management.
+       (gnus-registry-extra-entries-precious, gnus-registry-trim): Define a
+       list of extra data entries which, when present, will indicate that the
+       article ID should not be trimmed from the registry.
+       (gnus-registry-mark-article, gnus-registry-article-marks): Remove these
+       functions.
+       (gnus-registry-read-mark): New function to read a mark name from the
+       user.
+       (gnus-registry-set-article-mark, gnus-registry-remove-article-mark)
+       (gnus-registry-set-article-mark-internal): New functions to add and
+       remove marks.
+       (gnus-registry-get-article-marks): New function to show the marks for
+       an article, or retrieve them for further use.
+
+2008-01-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-describe-bindings): Show all `S' prefix
+       keys when no argument is given.
+
+2008-01-14  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * imap.el (imap-ping-server): New variable.
+       (imap-opened): On add extra ping if imap-ping-server is non-nil.
+       (imap-ping-server): Minor doc string fixes.
+
+2008-01-14  Knut Anders Hatlen  <kahatlen@gmail.com>  (tiny change)
+
+       * imap.el (imap-ping-server): New function.
+       (imap-opened): Call imap-ping-server.
+
+2008-01-12  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-article-sort-by-random)
+       (gnus-thread-sort-by-random): Fix doc strings.
+       Reported by jidanni@jidanni.org.
+
+2008-01-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-describe-bindings): New function.
+       (gnus-article-read-summary-keys): Use it.
+       (gnus-article-mode-map): Bind `C-h b' to it.
+
+2008-01-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-read-summary-keys): Work for `C-h' on
+       XEmacs.
+       (gnus-article-describe-key, gnus-article-describe-key-briefly):
+       Protect against non-character events.
+
+       * lpath.el: Fbind map-keymap for Emacs 21.
+
+2008-01-09  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-group.el (gnus-group-read-ephemeral-gmane-group-url):
+       New command.
+       (gnus-group-read-ephemeral-gmane-group): Use optional argument RANGE
+       instead of END.  Change name of the temp file.
+       (gnus-group-gmane-group-download-format): Add doc string.  Make it
+       customizable.
+
+2008-01-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-send-map): New keymap for `S' prefix keys;
+       bind `S W' to gnus-article-wide-reply-with-original; set default
+       binding to gnus-article-read-summary-send-keys.
+       (gnus-article-read-summary-keys): Fix the order of keys; display
+       continuation keys correctly in the echo area; describe bindings
+       correctly when keys end with `C-h'.
+       (gnus-article-read-summary-send-keys): New function.
+       (gnus-article-describe-key, gnus-article-describe-key-briefly):
+       Work for gnus-article-read-summary-send-keys; display continuation keys
+       correctly in the echo area.
+       (gnus-article-reply-with-original): Ignore prefix argument.
+       (gnus-article-wide-reply-with-original): New function.
+
+       * lpath.el: Fbind character-to-event and set-keymap-default-binding for
+       Emacs 21.
+
+2008-01-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-bookmark.el (gnus-bookmark-mouse-available-p): Don't test for
+       display-color-p.  Reported by Reiner Steib <Reiner.Steib@gmx.de>.
+
+2008-01-06  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-group.el (gnus-group-gmane-group-download-format): New variable.
+       (gnus-group-read-ephemeral-gmane-group): New command.
+
+2008-01-06  Dan Nicolaescu  <dann@ics.uci.edu>
+
+       * gnus.el (gnus-use-long-file-name): Remove reference to xenix.
+
+2007-12-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-send-mail-function): Increase custom version.
+
+       * mml-sec.el, sieve-manage.el, smime.el: Simplify loading of
+       password-cache or password.  Suggested by Glenn Morris <rgm@gnu.org>.
+
+2007-12-21  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * imap.el (imap-authenticate): Use current-buffer instead of buffer,
+       for the cases where imap-authenticate is called with a nil buffer
+       parameter.
+
+2007-12-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-browse-html-parts): Work for two or more
+       html parts correctly; support forwarded messages.
+       (gnus-article-browse-html-article): Remove work buffers.
+
+       * netrc.el: Bind encrypt-file-alist for Emacs 21 and XEmacs when
+       compiling.
+       (netrc-bound-and-true-p): New macro.
+       (netrc-parse): Use it instead of bound-and-true-p that is not available
+       in XEmacs 21.4.
+
+2007-12-19  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-mark-article)
+       (gnus-registry-article-marks): Add functionality to mark articles
+       through the Gnus registry.
+
+       * encrypt.el: Clarify documentation for the new pgg method.
+       (encrypt-file-alist): Add PGG option.
+       (encrypt-insert-file-contents, encrypt-write-file-contents): Use PGG
+       functionality.  Abstract password key and messaging to external
+       functions.
+       (encrypt-password-key, encrypt-get-passphrase-if-needed)
+       (encrypt-message-method-and-cipher): Add new convenience external
+       functions.
+       (encrypt-pgg-encode-buffer, encrypt-pgg-decode-buffer)
+       (encrypt-pgg-process-buffer): Add PGG functionality glue.
+
+       * netrc.el: Autoload encrypt when encrypt-file-alist is set.
+       (netrc-parse): Use encrypt-file-alist to determine if
+       encrypt-find-model or encrypt-insert-file-contents should be used.
+
+       * encrypt.el: Clarify documentation.  Load password-cache or
+       password, whichever one is found first, instead of autoloading.
+
+2007-12-19  Glenn Morris  <rgm@gnu.org>
+
+       * mml.el (message-options-set, message-narrow-to-head)
+       (message-in-body-p, message-mail-p, message-encode-message-body):
+       Autoload.
+       (message-remove-header, message-narrow-to-headers-or-head)
+       (message-subscribed-p, message-make-mail-followup-to)
+       (message-position-on-field, message-news-p)
+       (message-options-set-recipient, message-generate-headers)
+       (message-sort-headers): Declare as functions.
+
+2007-12-18  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-draft.el (gnus-draft-send-message): Mention process/prefix
+       convention in doc string.
+
+2007-12-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-browse-html-parts): Add message header and
+       title to html parts.
+       (gnus-article-browse-html-article): Pass message header to it.
+
+       * mm-decode.el (mm-display-external): Use mm-add-meta-html-tag.
+
+2007-12-16  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mml-sec.el, sieve-manage.el, smime.el: Make loading of password-cache
+       or password compatible with XEmacs.
+
+2007-12-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (article-verify-x-pgp-sig): Add reference to X-PGP-Sig
+       format document.
+       (gnus-mime-delete-part): Don't write description line if empty.
+       (gnus-article-encrypt-body): Add confirmation for gnus-novice-user.
+
+2007-12-14  Johan Bockgård  <bojohan@gnu.org>
+
+       * gnus-sum.el (gnus-summary-mark-unread-as-read)
+       (gnus-summary-mark-read-and-unread-as-read)
+       (gnus-summary-mark-current-read-and-unread-as-read)
+       (gnus-summary-mark-unread-as-ticked): Doc fix.
+       `gnus-mark-article-hook', not `gnus-summary-mark-article-hook'.
+
+2007-12-14  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-summary-prev-article): Fix doc string.
+       Reported by Christoph Conrad <christoph.conrad@gmx.de>.
+
+2007-12-14  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-util.el (gnus-y-or-n-p, gnus-yes-or-no-p): Alias to y-or-n-p and
+       yes-or-no-p.
+
+2007-12-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-add-meta-html-tag): New function.
+       (mm-save-part-to-file, mm-pipe-part): Use it.
+
+       * gnus-art.el (gnus-article-browse-delete-temp-files):
+       Use gnus-y-or-n-p instead of y-or-n-p.
+       (gnus-article-browse-html-parts): Work with message/external-body; use
+       mm-add-meta-html-tag.
+
+2007-12-11  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-cache.el: Require gnus-sum not just when compiling.
+
+       * gnus-fun.el (gnus-display-x-face-in-from): Require gnus-art.
+
+       * gnus-int.el (gnus-server-opened, gnus-status-message):
+       Move definitions before use.
+
+       * mm-decode.el: Require gnus-util.
+       (mm-remove-part): Only call delete-annotation on XEmacs.
+
+       * mm-uu.el (gnus-original-article-buffer): Define for compiler.
+
+       * nnmail.el: Require gnus-int.
+
+       * spam.el: Move `require's before `eval-when-compile's.
+
+       * gnus-ems.el (gnus-alive-p):
+       * gnus-fun.el (message-goto-eoh):
+       * gnus-util.el (gnus-group-name-decode):
+       * mail-source.el (gnus-compress-sequence):
+       * message.el (Info-goto-node, format-spec):
+       * mm-bodies.el (message-options-get):
+       * mm-decode.el (mm-view-pkcs7):
+       * mm-util.el (gmm-write-region):
+       * mml-smime.el (mml-compute-boundary)
+       (gnus-completing-read-with-default):
+       * mml.el (widget-button-press, gnus-make-hashtable):
+       * mml1991.el (mm-decode-content-transfer-encoding)
+       (mm-encode-content-transfer-encoding)
+       (message-options-get, message-options-set):
+       * mml2015.el (gnus-buffer-live-p, gnus-get-buffer-create):
+       * nnfolder.el (gnus-request-group):
+       * nnheader.el (ietf-drums-unfold-fws):
+       * rfc1843.el (mail-header-parse-content-type, message-narrow-to-head):
+       * smime.el (gnus-run-mode-hooks):
+       * spam-stat.el (gnus-message): Autoload.
+
+       * gnus-cache.el, gnus-fun.el, gnus-group.el, gnus.el, mail-source.el:
+       * mm-bodies.el, mm-decode.el, mm-extern.el, mm-util.el:
+       * mml-smime.el, mml.el, mml1991.el, mml2015.el, nndb.el, nnfolder.el:
+       * nnmail.el, nnmaildir.el, nnrss.el, rfc1843.el, spam.el:
+       Add declare-function compatibility definition.
+
+       * gnus-cache.el (nnvirtual-find-group-art):
+       * gnus-fun.el (article-narrow-to-head, gnus-article-goto-header)
+       (gnus-add-image, gnus-add-wash-type):
+       * gnus-group.el (nnkiboze-score-file):
+       * gnus-sum.el (turn-on-gnus-mailing-list-mode)
+       (gnus-cache-write-active, mm-uu-dissect, idna-to-unicode):
+       * gnus-util.el (gnus-find-method-for-group, gnus-group-name-charset)
+       (message-tokenize-header, gnus-get-buffer-create)
+       (mm-enable-multibyte, gnus-put-text-property, gnus-overlay-put)
+       (gnus-make-overlay, mm-disable-multibyte, gnus-add-text-properties):
+       * gnus.el (gnus-group-decoded-name):
+       * mail-source.el (imap-capability):
+       * mm-bodies.el (message-options-set):
+       * mm-decode.el (gnus-configure-windows):
+       * mm-extern.el (message-goto-body):
+       * mm-util.el (mm-delete-duplicates, mm-detect-coding-region):
+       * mml-smime.el (epg-key-sub-key-list, epg-sub-key-capability)
+       (epg-sub-key-validity, message-options-set):
+       * mml.el (widget-event-point, gnus-configure-windows):
+       * mml1991.el (mc-encrypt-generic, gpg-sign-encrypt, gpg-encrypt):
+       * mml2015.el (epg-check-configuration, epg-configuration)
+       (message-options-set):
+       * nndb.el (nndb-request-article):
+       * nnfolder.el (gnus-request-create-group):
+       * nnmail.el (gnus-activate-group, gnus-group-mark-article-read):
+       * nnmaildir.el (gnus-group-mark-article-read):
+       * nnrss.el (w3-parse-buffer, gnus-group-make-rss-group):
+       * rfc1843.el (message-fetch-field):
+       * spam.el (gnus-extract-address-components):
+       Declare as functions.
+
+2007-12-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-browse-html-parts): Decode CTE.
+
+       * pgg.el (pgg-run-at-time, pgg-cancel-timer): Use eval-and-compile.
+
+       * lpath.el: Fbind run-mode-hooks for Emacs 21;
+       bind show-trailing-whitespace for XEmacs.
+
+2007-12-09  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * hashcash.el, imap.el, pgg.el, pgg-parse.el (declare-function): Add
+       new no-op macro for backward compatibility.
+
+       * imap.el (imap-string-to-integer): New function.
+
+2007-12-09  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-uu.el (gnus-uu-yenc-article): Use insert-buffer-substring.
+
+       * gnus-art.el, gnus-spec.el, gnus-sum.el, gnus-util.el:
+       * message.el, mm-view.el, sieve-manage.el, smime.el:
+       Add declare-function compatibility definition.
+
+       * gnus-art.el (w3-region, w3m-region, Info-menu):
+       * gnus-spec.el (gnus-summary-from-or-to-or-newsgroups):
+       * gnus-sum.el (gnus-get-predicate):
+       * gnus-util.el (mm-append-to-file, w32-focus-frame):
+       * message.el (mail-abbrev-in-expansion-header-p):
+       * mm-view.el (w3-do-setup, w3-region, w3-prepare-buffer)
+       (w3m-detect-meta-charset, w3m-region):
+       * sieve-manage.el (password-read, password-cache-add)
+       (password-cache-remove):
+       * smime.el (password-read-and-add): Declare as functions.
+
+2007-12-08  David Kastrup  <dak@gnu.org>
+
+       * gnus-sum.el (gnus-summary-simplify-subject-query):
+       * ecomplete.el (ecomplete-display-matches): Fix buggy call to
+       `message'.
+
+2007-12-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (dgnushack-emacs-compile-defcustom-p): New function; use
+       it to bind idna-program, installation-directory, defined-colors, and
+       face-attribute for XEmacs of the version that compiles defcustom forms.
+
+2007-12-07  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-art.el (article-make-date-line): Revert previous change.
+
+2007-12-06  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-start.el (gnus-load): Rename local variable to avoid confusion.
+
+2007-12-06  Christian Plate  <cplate@web.de>  (tiny change)
+
+       * nnmaildir.el (nnmaildir-request-update-info): Improve performance.
+       Call gnus-add-to-range ranges only once with a prepared article-list.
+
+2007-12-06  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir-request-list, nnmaildir-retrieve-groups)
+       (nnmaildir-request-group, nnmaildir-retrieve-headers): Escape spaces in
+       group names with backslashes.
+       Reported by Tassilo Horn <tassilo@member.fsf.org>.
+
+2007-12-06  Deepak Goel  <deego3@gmail.com>
+
+       * gnus-art.el (article-make-date-line):
+       * gnus-start.el (gnus-load):
+       * pop3.el (pop3-read-response): Fix buggy call to `error'.
+
+2007-12-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-use-idna):
+       * gnus-start.el (gnus-site-init-file):
+       * message.el (message-use-idna):
+       * mm-uu.el (mm-uu-hide-markers):
+       * smiley.el (smiley-style): Revert changes that suppress warnings.
+
+2007-12-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-browse-html-parts): Add meta html tag to
+       specify charset to html source.
+       Reported by Christoph Conrad <christoph.conrad@gmx.de>.
+
+2007-12-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-use-idna): Don't directly refer to the value of
+       idna-program in order to suppress byte compile warning issued by XEmacs
+       that came to byte compile the default value section of defcustom forms
+       recently.
+
+       * gnus-start.el (gnus-site-init-file): Don't directly refer to the
+       value of installation-directory.
+
+       * message.el (message-use-idna): Don't directly refer to the value of
+       idna-program.
+
+       * mm-uu.el (mm-uu-hide-markers): Don't directly call defined-colors.
+
+       * smiley.el (smiley-style): Don't directly call face-attribute.
+
+2007-12-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-group.el (gnus-group-highlight-line): Add FIXME.
+
+       * gnus-dired.el: Reduce Gnus dependencies.
+       (gnus-ems, gnus-msg, gnus-util, message, mm-decode, mml):
+       Don't require.  Use autoloads instead.
+       (mml-attach-file, mm-default-file-encoding, mailcap-extension-to-mime)
+       (mailcap-mime-info, mm-mailcap-command, ps-print-preprint)
+       (message-buffers, gnus-setup-message, gnus-print-buffer): Autoload.
+       (gnus-dired-mode): Adjust doc string.
+       (gnus-dired-mail-mode): New variable.
+       (gnus-dired-mode-map): Avoid using `gnus-define-keys'.
+       (gnus-dired-mode): Avoid using `gnus-run-hooks'.
+       (gnus-dired-mail-buffers): New function.  Return mail or message
+       composition buffers.
+       (gnus-dired-attach): Use it.
+       (gnus-dired-find-file-mailcap): Call `mailcap-mime-info' with
+       NO-DECODE.
+       (gnus-dired-print): Use `gnus-print-buffer' depending on
+       `gnus-dired-mail-mode'.
+
+2007-12-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-encoded-word-regexp)
+       (rfc2047-encoded-word-regexp-loose): Move forward; add comments
+       explaining what regexp patterns are for.
+
+2007-12-04  Glenn Morris  <rgm@gnu.org>
+
+       * password.el: Move to password-cache.el.
+
+       * mml1991.el (password-read, password-cache-add, password-cache-remove):
+       * mml2015.el (password-read, password-cache-add, password-cache-remove):
+       * mml-smime.el (password-read, password-cache-add)
+       (password-cache-remove):
+       No need to autoload, since mml-sec requires password.
+
+       * gnus.el (gnus-spam-resend-to, gnus-ham-resend-to):
+       * message.el (gnus-extract-address-components):
+       * mml-smime.el (gnus-extract-address-components): Define for compiler.
+
+       * mml-sec.el, sieve-manage.el, smime.el: Require password-cache or
+       password.
+
+2007-12-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mailcap.el: Reduce dependencies.
+       (mail-header-parse-content-type): Autoload.
+       (mailcap-delete-duplicates): New alias.
+       (mailcap-mime-info): Add optional argument NO-DECODE.
+       (mailcap-mime-types): Use mailcap-delete-duplicates.
+
+       * message.el (message-ignored-supersedes-headers): Add "X-ID".
+
+2007-12-03  Nathan J. Williams  <nathanw@MIT.EDU>  (tiny change)
+
+       * imap.el (imap-mailbox-status-asynch): Upcase STATUS items.
+       (imap-parse-status): Upcase status-att for servers that sends them
+       lower-case (e.g., MS Exchange 2007).
+
+2007-12-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-uu-extract-map): Add a command for the yenc
+       function.
+
+       * gnus-uu.el (gnus-uu-decode-yenc): New command.
+       (gnus-uu-yenc-article): New function.
+
+       * yenc.el (yenc-first-part-p, yenc-last-part-p): New functions.
+
+       * mm-uu.el (mm-uu-yenc-extract): Get the data from the original buffer.
+
+2007-12-02  Glenn Morris  <rgm@gnu.org>
+
+       * binhex.el (binhex): New custom group.
+       (binhex-decoder-program, binhex-decoder-switches)
+       (binhex-use-external): Move to the binhex custom group.
+
+       * uudecode.el (uudecode): New custom group.
+       (uudecode-decoder-program, uudecode-decoder-switches)
+       (uudecode-use-external): Move to the uudecode custom group.
+
+       * netrc.el (top-level): Don't load `encrypt' features.
+       (netrc-parse): Don't use encrypt.
+       (netrc-find-service-name, netrc-find-service-number): Don't use caddr.
+
+       * encrypt.el: Remove file.
+
+2007-12-01  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-cite-prefix-regexp): Remove `-' and `+' to avoid
+       matches on patches.
+
+       * gnus-art.el (gnus-article-browse-html-article):
+       Mention `mm-text-html-renderer' in the doc string.
+
+       * rfc2047.el (rfc2047-encode-max-chars): Refer to RFC 2047 in doc
+       string.  Add comments.
+
+       * message.el (message-idna-to-ascii-rhs-1): Don't call `idna-to-ascii'
+       if rhs is ASCII.
+
+2007-12-01  Glenn Morris  <rgm@gnu.org>
+
+       * mail-source.el (top-level): Require format-spec before
+       eval-when-compile.
+
+2007-11-30  Glenn Morris  <rgm@gnu.org>
+
+       * encrypt.el: Require password, rather than autoloading password-read.
+
+2007-11-29  Glenn Morris  <rgm@gnu.org>
+
+       * imap.el (sasl-find-mechanism, sasl-mechanism-name)
+       (sasl-make-client, sasl-next-step, sasl-step-data)
+       (sasl-step-set-data): Declare as functions.
+
+2007-11-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * tls.el (tls-hostmismatch, open-tls-stream): Checkdoc cleanup.
+
+2007-11-28  Elias Oltmanns  <eo@nebensachen.de>
+
+       * tls.el (open-tls-stream): Actually consult tls-checktrust to see if
+       certs should be verified and what is to be done in the event of a
+       verification failure.
+
+       * gnus.el (gnus-method-to-server): Add an optional parameter so the
+       caller can indicate whether the cache should be disregarded for this
+       call.  This way the result of the call is reproducible at all times and
+       can be considered a canonical server name for the supplied method.
+       (gnus-agent-method-p): Canonicalize server names by pushing their
+       method through `gnus-method-to-server' using the no-cache argument.
+
+       * gnus-srvr.el (gnus-server-insert-server-line):
+       Call `gnus-method-to-server' with `no-cache' argument.
+
+       * gnus-agent.el (gnus-agent-toggle-plugged): Don't call
+       gnus-agent-possibly-synchronize-flags as this should be called when the
+       server is actually being opened.
+       (gnus-agent-possibly-synchronize-flags)
+       (gnus-agent-possibly-synchronize-flags-server): Move check for the
+       flags file of an agentized server to the latter function.
+
+       * gnus-int.el (gnus-agent-possibly-synchronize-flags-server): Autoload.
+       (gnus-open-server): Call gnus-agent-possibly-synchronize-flags-server
+       after a connection has been established successfully.
+
+2007-11-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-display-face): Force to display face if called
+       interactively; check if gnus-article-x-face-too-ugly matches author.
+       (article-display-x-face): Display face even if From header is missing
+       as article-display-face does.
+
+2007-11-27  Dan Nicolaescu  <dann@ics.uci.edu>
+
+       * hashcash.el (message-narrow-to-headers-or-head)
+       (message-fetch-field, message-goto-eoh)
+       (message-narrow-to-headers): Declare as functions.
+
+2007-11-27  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mail-source.el (mail-sources): Default to fetch from file for
+       compatibility with default of nnmail-spool-file.
+
+2007-11-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-allow-irregular-q-encoded-words): New variable.
+       (rfc2047-encodable-p): Use rfc2047-encoded-word-regexp instead of "=?"
+       to look for encoded word that should be encoded again.
+       (rfc2047-encoded-word-regexp): Make B encoding pattern strict.
+       (rfc2047-encoded-word-regexp-loose): New constant that has loose Q
+       encoding pattern.
+       (rfc2047-decode-region): Switch strict regexp and loose one according
+       to rfc2047-allow-irregular-q-encoded-words.
+
+2007-11-25  Romain Francoise  <romain@orebokech.com>
+
+       * gnus-msg.el (gnus-summary-reply): Delete extra paren.
+
+2007-11-25  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * tls.el (tls-program): Provide more custom choices from
+       `tls-checktrust'.  Refer to `tls-checktrust' in doc string.
+       (tls-process-connection-type, tls-success): Remove "*" in doc string.
+
+2007-11-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnmail.el (nnmail-spool-file): Remove obsolete variable.
+       (nnmail-get-new-mail): Remove code using `nnmail-spool-file'.
+
+       * gnus-start.el (defvar, gnus-get-unread-articles): Remove code using
+       `nnmail-spool-file'.
+
+       * nnkiboze.el (nnkiboze-generate-groups): Don't bind obsolete
+       `nnmail-spool-file'.
+
+       * gnus-move.el (gnus-change-server): Ditto.
+
+       * gnus-kill.el (gnus-batch-score): Ditto.
+
+       * gnus-cache.el (gnus-jog-cache): Ditto.
+
+       * gnus-msg.el (gnus-summary-reply):
+       Ignore gnus-confirm-mail-reply-to-news for wide and very wide replies.
+
+2007-11-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * tls.el (tls-checktrust, tls-hostmismatch, tls-untrusted): Add custom
+       version.  Minor improvement to doc strings.
+       (tls-program): Add comment.
+
+2007-11-24  Elias Oltmanns  <eo@nebensachen.de>
+
+       * tls.el (tls-certtool-program, tls-hostmismatch): New variables.
+       (tls-checktrust): New variable.  Check if GNU TLS complained about a
+       mismatch between the hostname provided in the certificate and the name
+       of the host connnecting to.
+       (open-tls-stream): Use them.  Check certificates against trusted root
+       certificates.
+
+2007-11-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-cache.el (gnus-cache-generate-nov-databases):
+       Use nnml-generate-nov-databases-directory instead of
+       nnml-generate-nov-databases-1.
+
+2007-11-24  Glenn Morris  <rgm@gnu.org>
+
+       * message.el (message-tool-bar-retro): Update for rename
+       mail_send.xpm->mail-send.xpm.
+
+2007-11-22  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * smime.el (smime-cert-by-ldap-1): Use `ldap-search' instead of
+       `smime-ldap-search' for Emacs 22 and up.
+
+2007-11-22  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-art.el (gnus-article-truncate-lines): Use `truncate-lines'.
+
+       * message.el (message-send-mail-function): Fix error convention.
+       (message-mailer-swallows-blank-line, message-send-mail-with-sendmail)
+       (message-widen-reply, message-send-mail, message-talkative-question)
+       (message-with-reply-buffer, message-generate-new-buffer-clone-locals)
+       (message-clone-locals, message-send-news): Use with-current-buffer.
+       (message-insert-or-toggle-importance): Remove unused var `valid'.
+       (message-make-references): Remove unused var `new-references'.
+       (message-make-mail-followup-to): Remove unused var `subscribed-lists'.
+
+2007-11-22  Juanma Barranquero  <lekktu@gmail.com>
+
+       * spam.el (spam-find-spam, spam-enter-list): Doc fixes.
+       (spam-split-symbolic-return-positive): Reflow docstring.
+       (spam-backends, spam-summary-exit-behavior)
+       (spam-mark-ham-unread-before-move-from-spam-group)
+       (spam-summary-score-preferred-header, spam-sa-learn-spam-switch)
+       (spam-sa-learn-ham-switch, spam-sa-learn-unregister-switch)
+       (spam-clear-cache, spam-backend-check, spam-install-backend)
+       (spam-install-statistical-backend, spam-list-of-processors)
+       (spam-group-processor-p, spam-split, spam-bogofilter-score)
+       (spam-bsfilter-score, spam-check-bsfilter, spam-crm114-score)
+       (spam-check-crm114, spam-initialize, spam-unload-hook):
+       Fix typos in docstrings.
+
+2007-11-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-start.el (gnus-get-unread-articles): Mark groups as having never
+       been checked if they have never been read and those group levels are
+       higher than the one that a user specified.
+
+2007-11-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-start.el (gnus-get-unread-articles): Don't prevent from checking
+       foreign groups unless a group level is specified by a user.
+       Reported by Dan Nicolaescu <dann@ics.uci.edu>.
+
+2007-11-21  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-send-mail-function): Require sendmail.
+
+2007-11-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-send-mail-function): Check for smtpmail too.
+
+       * utf7.el (utf7-encode, utf7-decode): Use coding system
+       `utf-7'/`utf-7-imap' from utf-7.el' if available.
+
+       * message.el (message-send-mail-function): New function.
+       (message-send-mail-function): Set default using
+       message-send-mail-function.  Adjust doc string.
+       (message-send-mail-with-mailclient): New function.
+
+2007-11-16  Dan Nicolaescu  <dann@ics.uci.edu>
+
+       * smime.el (from):
+       * rfc2047.el (message-posting-charset):
+       * qp.el (mm-use-ultra-safe-encoding):
+       * pop3.el (parse-time-months):
+       * nnrss.el (mm-text-html-renderer, mm-text-html-washer-alist):
+       * nnml.el (files):
+       * nnheader.el (gnus-newsgroup-name, nnheader-file-coding-system)
+       (jka-compr-compression-info-list, ange-ftp-path-format)
+       (efs-path-regexp):
+       * nndiary.el (files):
+       * mml2015.el (mc-default-scheme, mc-schemes, pgg-default-user-id)
+       (pgg-errors-buffer, pgg-output-buffer, epg-user-id-alist)
+       (epg-digest-algorithm-alist, inhibit-redisplay)
+       (password-cache-expiry):
+       * mml1991.el (pgg-default-user-id, pgg-errors-buffer)
+       (pgg-output-buffer, password-cache-expiry):
+       * mml.el (mml-dnd-protocol-alist, ange-ftp-name-format)
+       (efs-path-regexp):
+       * mml-smime.el (epg-user-id-alist, epg-digest-algorithm-alist)
+       (inhibit-redisplay):
+       * mm-uu.el (file-name, start-point, end-point, entry)
+       (gnus-newsgroup-name, gnus-newsgroup-charset):
+       * mm-util.el (mm-mime-mule-charset-alist, latin-unity-coding-systems)
+       (latin-unity-ucs-list):
+       * mm-bodies.el (mm-uu-yenc-decode-function, mm-uu-decode-function)
+       (mm-uu-binhex-decode-function):
+       * message.el (gnus-message-group-art, gnus-list-identifiers)
+       (rmail-enable-mime-composing, gnus-local-organization)
+       (gnus-post-method, gnus-select-method, gnus-active-hashtb)
+       (gnus-read-active-file, facemenu-add-face-function)
+       (facemenu-remove-face-function, gnus-article-decoded-p)
+       (tool-bar-mode):
+       * mail-source.el (display-time-mail-function):
+       * gnus-util.el (nnmail-pathname-coding-system)
+       (nnmail-active-file-coding-system, gnus-emphasize-whitespace-regexp)
+       (gnus-original-article-buffer, gnus-user-agent)
+       (rmail-default-rmail-file, mm-text-coding-system, tool-bar-mode)
+       (xemacs-codename, sxemacs-codename, emacs-program-version):
+       * gnus-sum.el (tool-bar-mode, gnus-tmp-header, number):
+       * gnus-start.el (gnus-agent-covered-methods)
+       (gnus-agent-file-loading-local, gnus-agent-file-loading-cache)
+       (gnus-current-headers, gnus-thread-indent-array, gnus-newsgroup-name)
+       (gnus-newsgroup-headers, gnus-group-list-mode)
+       (gnus-group-mark-positions, gnus-newsgroup-data)
+       (gnus-newsgroup-unreads, nnoo-state-alist)
+       (gnus-current-select-method, mail-sources)
+       (nnmail-scan-directory-mail-source-once, nnmail-split-history)
+       (nnmail-spool-file, gnus-cache-active-hashtb):
+       * gnus-mh.el (mh-lib-progs):
+       * gnus-ems.el (gnus-tmp-unread, gnus-tmp-replied)
+       (gnus-tmp-score-char, gnus-tmp-indentation, gnus-tmp-opening-bracket)
+       (gnus-tmp-lines, gnus-tmp-name, gnus-tmp-closing-bracket)
+       (gnus-tmp-subject-or-nil, gnus-check-before-posting, gnus-mouse-face)
+       (gnus-group-buffer):
+       * gnus-cite.el (font-lock-defaults-computed, font-lock-keywords)
+       (font-lock-set-defaults):
+       * gnus-art.el (tool-bar-map, w3m-minor-mode-map)
+       (gnus-face-properties-alist, charset, gnus-summary-article-menu)
+       (gnus-summary-post-menu, total-parts, type, condition, length):
+       * gnus-agent.el (gnus-agent-read-agentview):
+       * flow-fill.el (show-trailing-whitespace):
+       * gnus-group.el (tool-bar-mode, nnrss-group-alist): Remove unnecessary
+       eval-and-compile wrappers for byte compiler pacifiers.
+
+       * mm-view.el (mm-inline-image-xemacs): Only do something for XEmacs.
+       (mm-display-inline-fontify): Check for featurep 'xemacs not
+       extent-list.
+
+       * mm-decode.el (mm-display-external): Check for featurep 'xemacs not
+       itimer-list.
+       (mm-create-image-xemacs): Only do something for XEmacs.
+       (mm-image-fit-p): Check for featurep 'xemacs not glyph-width.
+
+       * mm-util.el (mm-find-buffer-file-coding-system): Add check for XEmacs.
+
+       * gnus-registry.el (gnus-adaptive-word-syntax-table):
+       * gnus-fun.el (gnus-face-properties-alist): Pacify byte compiler.
+
+2007-11-15  Juanma Barranquero  <lekktu@gmail.com>
+
+       * nnimap.el (nnimap-split-download-body):
+       * gnus-demon.el (gnus-demon):
+       * gnus-uu.el (gnus-uu-default-view-rules): Fix typos in docstrings.
+
+2007-11-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nntp.el (nntp-insert-buffer-substring, nntp-copy-to-buffer):
+       New macros.
+       (nntp-wait-for, nntp-retrieve-articles, nntp-async-trigger)
+       (nntp-retrieve-headers-with-xover): Use nntp-insert-buffer-substring to
+       copy data from unibyte buffer to multibyte current buffer.
+       (nntp-retrieve-headers, nntp-retrieve-groups): Use nntp-copy-to-buffer
+       to copy data from unibyte current buffer to multibyte buffer.
+       (nntp-make-process-buffer): Make process buffer unibyte.
+
+       * pop3.el (pop3-open-server): Fix typo in Lisp code.
+
+2007-11-14  Denys Duchier  <denys.duchier@univ-orleans.fr>  (tiny change)
+
+       * pop3.el (pop3-open-server): Accept and process data more robustly at
+       connection start to avoid spurious "POP SSL connection failed" errors.
+
+2007-11-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-start.el (gnus-active-to-gnus-format): Use unibyte buffer to
+       read group names.
+
+2007-11-12  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-msg.el (gnus-confirm-mail-reply-to-news): Adjust :version.
+
+2007-11-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnmail.el (nnmail-parse-active): Make group names unibyte.
+       (nnmail-save-active): Use a unibyte buffer when saving active file,
+       which may contain non-ASCII group names.
+
+       * nnml.el (nnml-request-group): Decode group names in messages.
+
+2007-11-05  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-citation-line-function)
+       (message-insert-formatted-citation-line): Fix spelling of
+       `message-insert-formated-citation-line'.
+
+2007-11-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-summary-highlight): Mark as risky local variable.
+
+2007-11-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnml.el (nnml-request-rename-group): Bind file-name-coding-system to
+       nnmail-pathname-coding-system.
+
+       * gnus-group.el (gnus-group-rename-group): Encode non-ASCII group name
+       that a user enters; decode group names in messages.
+
+       * gnus-msg.el (gnus-inews-do-gcc): Encode non-ASCII group names.
+
+2007-11-01  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-util.el (mm-charset-eval-alist): Mark as risky local variable.
+
+       * gnus.el (gnus-group-charter-alist): Mark as risky local variable.
+
+       * gnus-art.el (gnus-button-alist, gnus-header-button-alist): Mark as
+       risky local variable.
+
+       * gnus-group.el (gnus-group-icon-list): Mark as risky local variable.
+
+2007-11-01  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * encrypt.el: Improve documentation to fix function name typo.
+       Reported by Daiki Ueno <ueno@unixuser.org>.
+
+2007-11-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-next-page): Honor gnus-article-over-scroll
+       even if the point is not in the last page of an article.
+       (gnus-article-prev-page): Honor gnus-article-over-scroll when moving
+       back to the previous page.
+
+2007-10-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * qp.el (quoted-printable-decode-string): Fix typo in doc string.
+
+2007-10-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-ems.el (gnus-x-splash): Work even if there's no scroll bar.
+
+2007-10-29  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * message.el (message-check-news-body-syntax):
+       Avoid mm-string-as-multibyte.
+       (message-hide-headers): Don't assume (point-min)==1.
+
+2007-10-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-remove-blank-cited-lines): Fix if remove is
+       given.
+       (message-bogus-address-regexp): New variable.
+       (message-bogus-recipient-p): New function.
+       (message-check-recipients): New command.
+       (message-syntax-checks): Add `bogus-recipient'.
+       (message-fix-before-sending): Add `bogus-recipient'.
+
+       * gnus-art.el (gnus-button-mid-or-mail-heuristic-alist): Add "alpine".
+       (gnus-treat-body-boundary): Don't test window-system.
+
+2007-10-28  Leo Liu  <sdl.web@gmail.com>
+
+       * gnus-art.el (gnus-treat-emphasize): Don't test window-system.
+
+2007-10-28  Miles Bader  <miles@gnu.org>
+
+       * nnheader.el (nnheader-uniquify-message-id): Make sure this is defined
+       at compile-time too.
+
+2007-10-27  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-msg.el (gnus-message-setup-hook):
+       Add `message-remove-blank-cited-lines' to options.
+
+2007-10-26  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-remove-blank-cited-lines): New function.
+       Suggested by Karl Plästerer.
+
+2007-10-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * hashcash.el (mail-add-payment): Replace mapcar called for effect with
+       mapc.
+
+       * imap.el (imap-open): Replace mapcar called for effect with mapc.
+       (top-level): Use mapc to set functions to be traced for debugging.
+
+       * legacy-gnus-agent.el (gnus-agent-convert-agentview): Replace mapcar
+       called for effect with while loop.
+
+       * message.el (message-talkative-question): Replace mapcar called for
+       effect with mapc.
+
+       * mm-util.el: Use mapc instead of mapcar to make compatible functions.
+       (mm-find-mime-charset-region, mm-find-charset-region): Replace mapcar
+       called for effect with dolist.
+
+       * mml.el (mml-insert-mime): Replace mapcar called for effect with mapc.
+
+       * nndiary.el: Use dolist instead of mapcar to add diary headers to
+       gnus-extra-headers and nnmail-extra-headers.
+
+       * nnimap.el (nnimap-request-update-info-internal): Replace mapcar
+       called for effect with dolist.
+       (top-level): Use mapc to set functions to be traced for debugging.
+
+       * nnmail.el (nnmail-read-incoming-hook): Doc fix.
+       (nnmail-split-fancy-with-parent): Replace mapcar called for effect with
+       dolist.
+
+       * nnmaildir.el (nnmaildir--delete-dir-files, nnmaildir-request-close):
+       Replace mapcar called for effect with mapc.
+       (nnmaildir--scan, nnmaildir-request-scan, nnmaildir-retrieve-groups)
+       (nnmaildir-request-update-info, nnmaildir-request-delete-group)
+       (nnmaildir-retrieve-headers, nnmaildir-request-set-mark)
+       (nnmaildir-close-group): Replace mapcar called for effect with dolist.
+
+       * nnrss.el (nnrss-make-hash-index): Use gnus-remove-if instead of
+       remove-if that's a cl function.
+
+       * webmail.el (webmail-debug): Replace mapcar called for effect with
+       dolist.
+
+       * gnus-xmas.el (gnus-group-add-icon): Replace mapcar called for effect
+       with mapc.
+
+2007-10-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-agent.el (gnus-agent-read-agentview, gnus-agent-save-alist)
+       (gnus-agent-expire-unagentized-dirs): Replace mapcar called for effect
+       with while loop.
+
+       * gnus-art.el: Use mapc instead of mapcar to make gnus-article-*
+       functions from article-* functions.
+       (gnus-multi-decode-header): Replace mapcar called for effect with
+       dolist.
+
+       * gnus-bookmark.el (gnus-bookmark-bmenu-list)
+       (gnus-bookmark-show-details): Replace mapcar called for effect with
+       while loop.
+
+       * gnus-diary.el (gnus-diary-update-group-parameters): Replace mapcar
+       called for effect with while loop.
+
+       * gnus-group.el (gnus-group-suspend): Replace mapcar called for effect
+       with dolist.
+
+       * gnus-registry.el (gnus-registry-split-fancy-with-parent):
+       Replace mapcar called for effect with dolist.
+
+       * gnus-spec.el (gnus-correct-length): Make it simple and fast.
+
+       * gnus-sum.el (gnus-multi-decode-encoded-word-string)
+       (gnus-build-sparse-threads, gnus-summary-limit-include-expunged):
+       Replace mapcar called for effect with dolist.
+       (gnus-simplify-buffer-fuzzy): Replace mapcar called for effect with
+       mapc.
+
+       * gnus-topic.el (gnus-topic-find-groups, gnus-topic-move-group):
+       Replace mapcar called for effect with dolist.
+       (gnus-topic-list): Replace mapcar called for effect with mapc.
+
+       * gnus.el: Use mapc instead of mapcar to add autoloads.
+
+2007-10-23  Richard Stallman  <rms@gnu.org>
+
+       * gnus-group.el (gnus-group-highlight): Mark as risky.
+
+2007-10-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (gnus-server-to-method): Return method found first in
+       gnus-newsrc-alist.
+
+       * gnus-art.el (gnus-article-highlight-signature)
+       (gnus-insert-prev-page-button, gnus-insert-next-page-button): Make a
+       button overlay without the front stickiness.
+
+2007-10-22  Kevin Greiner  <kevin.greiner@compsol.cc>
+
+       * gnus-agent.el (gnus-agent-expire-group-1): The check for an unsorted
+       overview buffer needed a catch to receive its throw.
+       (gnus-agent-flush-cache): Declare as interactive to make this function
+       easier to use.
+
+2007-10-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * html2text.el (html2text-fix-paragraph): Use `forward-line' instead of
+       `next-line'.
+
+2007-10-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnmail.el (nnmail-fancy-expiry-target): Use rmail-dont-reply-to to
+       exclude address matching message-dont-reply-to-names.
+
+2007-10-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-string<): New function.
+
+       * gnus-sum.el (gnus-article-sort-by-author)
+       (gnus-article-sort-by-recipient, gnus-article-sort-by-subject): Use it.
+
+2007-10-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-win.el (gnus-configure-windows): Focus on the frame for which
+       the frame-focus tag is set in gnus-buffer-configuration.
+
+2007-10-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-add-button): Make a button overlay without
+       the front stickiness.
+
+2007-10-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-button-alist): Exclude newline in RFC2396-compliant
+       url pattern; remove duplicate one.
+       (gnus-article-extend-url-button): New function.
+       (gnus-article-add-buttons): Use it.
+       (gnus-button-push): Use concatenated url that it makes.
+
+2007-10-04  Juanma Barranquero  <lekktu@gmail.com>
+
+       * sieve-manage.el (sieve-manage-interactive-login): Doc fix.
+
+2007-10-02  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-uu.el (gnus-uu-reginize-string, gnus-uu-expand-numbers):
+       Don't hardcode point-min==1.
+
+2007-10-08  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-util.el (mm-charset-synonym-alist): Alias gbk to cp936.
+       Fix comment about "iso8859-1".
+
+2007-10-08  Daiki Ueno  <ueno@unixuser.org>
+
+       * mm-decode.el (mm-possibly-verify-or-decrypt): Replace PARTS with the
+       ones returned from the verify-function.
+
+       * mm-uu.el (mm-uu-pgp-signed-extract-1):
+       Call mml2015-extract-cleartext-signature if extraction failed.
+
+2007-10-07  Daiki Ueno  <ueno@unixuser.org>
+
+       * mm-uu.el (mm-uu-pgp-signed-extract-1): Delete the first line
+       beginning with "-----BEGIN PGP SIGNED MESSAGE-----" if extraction
+       failed.
+
+2007-10-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Relicense "GPLv2 or later" files to "GPLv3 or later".
+
+2007-10-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * pgg.el, pgg-def.el, pgg-gpg.el: Revert to the version in v5-10.  The
+       trunk version of PGG was unmaintained.  The author of PGG, Daiki Ueno,
+       recommends to use EasyPG instead of PGG.
+
+       * pgg.el: Revert to revision 6.23.2.16.
+
+       * pgg-def.el: Revert to revision 6.6.2.14.
+
+       * pgg-gpg.el: Revert to revision 6.23.2.34.
+
+2007-09-27  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-sum.el (gnus-summary-kill-thread): Allow universal prefix zero
+       to mark a thread as expirable.  Add variable `hide' to handle hiding of
+       thread for both the null and zero (kill/expire thread) universal prefix
+       cases.
+       (gnus-summary-expire-thread): Add new function to expire a thread,
+       using gnus-summary-kill-thread.
+       (gnus-summary-mode-map, gnus-summary-thread-map): Add 'M-C-e' and 'T e'
+       shortcuts for gnus-summary-expire-thread.
+       (gnus-summary-mode-map, gnus-summary-thread-map): Remove `M-C-e' and `T
+       e' bindings for gnus-summary-expire-thread.  Add `T E' binding.
+
+2007-09-25  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-store-extra-entry): Allow for nil
+       extras value, so an extras entry can be deleted.
+       (gnus-registry-delete-extra-entry): Use it.
+       (gnus-registry-fetch-extra-flags, gnus-registry-has-extra-flag)
+       (gnus-registry-store-extra-flags, gnus-registry-delete-extra-flags)
+       (gnus-registry-delete-all-extra-flags): Allow for arbitrary flag symbol
+       storage through the gnus-registry, and provide an appropriate API for
+       it.
+
+2007-09-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-newsgroup-maximum-articles): Move from gnus.el.
+       Suggested by Leo <sdl.web@gmail.com>.
+
+       * gnus.el: Do.
+
+2007-09-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (gnus-newsgroup-maximum-articles): Rename from
+       gnus-maximum-newsgroup.  Suggested by Leo <sdl.web@gmail.com>.
+
+       * gnus-agent.el (gnus-agent-fetch-headers): Do.
+
+       * gnus-sum.el (gnus-articles-to-read, gnus-list-of-unread-articles)
+       (gnus-list-of-read-articles, gnus-sequence-of-unread-articles): Do.
+
+2007-09-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnmbox.el (nnmbox-request-article): Don't assume delim regexp matches
+       newline.
+       (nnmbox-request-accept-article): Don't change article in source buffer;
+       narrow to header to use message-fetch-field rather than
+       nnmail-fetch-field; use with-current-buffer instead of save-excursion.
+       (nnmbox-request-replace-article): Quote lines that'll be misidentified
+       as delimiters; make sure article ends with newline.
+       (nnmbox-delete-mail): Correct last position of article to be deleted;
+       ignore X-Gnus-Newsgroup header in article body.
+       (nnmbox-save-mail): Quote lines looking like delimiters at the right
+       positions; make sure article ends with newline.
+
+       * message.el (message-display-abbrev): Don't infloop when a user
+       inserts SPC in the beginning of header.
+
+       * lpath.el: Don't bind define-ccl-program for non-Mule XEmacs; bind
+       coding-system-for-read and coding-system-for-write for XEmacs having no
+       file-coding feature.
+
+       * dgnushack.el: Bind or autoload define-ccl-program for XEmacs.
+
+2007-09-12  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-unfollowed-groups): Add INBOX to the
+       list of groups not followed by default.  Fix type to be regexp.
+       (gnus-registry-grep-in-list): Fix inverted parameters to string-match.
+
+2007-09-06  Tassilo Horn  <tassilo@member.fsf.org>
+
+       * hmac-def.el (define-hmac-function): Switch from old-style to
+       new-style backquotes.
+
+       * md4.el (md4-make-step): Likewise.
+
+2007-09-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-start.el (gnus-gnus-to-newsrc-format): Use a unibyte buffer and
+       raw-text coding system when saving .newsrc file, which may contain
+       non-ASCII group names.
+
+2007-09-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-cus.el (gnus-score-extra): New widget.
+       (gnus-score-extra-convert): New function.
+       (gnus-score-customize): Use it for Extra.
+
+2007-08-31  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el (mml2015-extract-cleartext-signature): New function.
+       (mml2015-mailcrypt-clear-verify): Use it.
+       (mml2015-gpg-clear-verify): Use it.
+       (mml2015-pgg-clear-verify): Use it.
+       (mml2015-epg-clear-verify): Replace the current part with the output
+       from GnuPG; don't extract the plaintext by itself.
+
+       * mm-uu.el (mm-uu-pgp-beginning-signature): Abolish.
+       (mm-uu-pgp-signed-extract-1): Bind coding-system-for-read when calling
+       mml2015-clear-verify-function; don't touch the armor headers or
+       dash-escaped text here.
+
+2007-08-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-edit-part): Don't jump to nonexistent part.
+       (gnus-mime-view-part-as-type-internal): Default to text/plain for text
+       parts, or application/octet-stream as a last resort.
+       (gnus-mime-view-part-as-type): Don't toggle display.
+       (gnus-mime-view-part-as-charset): Don't turn off display before
+       querying charset.
+
+       * mm-view.el (mm-inline-text-html-render-with-w3): Don't add XEmacs
+       stuff to undisplayer function in Emacs.
+       (mm-inline-text-html-render-with-w3m): Remove Emacs/W3 stuff.
+
+       * mml.el (mml-generate-mime-1): Prefer utf-8 when encoding
+       text/calendar parts.
+
+2007-08-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-display-single): Use utf-8 by default for
+       decoding text/calendar parts.
+
+       * message.el (message-forward-make-body-mime): Always mark body as
+       having no illegible text; remove signed-or-encrypted argument.
+       (message-forward-make-body): Don't pass signed-or-encrypted arg to it.
+
+       * mml.el (mml-generate-mime): Make sure it uses multibyte temp buffer.
+       (mml-generate-mime-1): Don't encode body if it is specified to be in
+       raw form; don't make buffer be unibyte when inserting multibyte string.
+
+2007-08-23  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * sha1.el: Fix up comment style.
+       (sha1-F0, sha1-F1, sha1-F2, sha1-F3, sha1-S1, sha1-S5, sha1-S30)
+       (sha1-OP, sha1-add-to-H): Use new-style backquotes.
+
+       * hex-util.el: Fix up comment style.
+       (hex-char-to-num, num-to-hex-char): Use new-style backquotes.
+
+       * gnus-salt.el: Use with-current-buffer.
+       (gnus-pick-setup-message): Fix long-standing typo.
+
+2007-08-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * imap.el (imap-logout-timeout): New variable.
+       (imap-logout, imap-logout-wait): New functions.
+       (imap-kerberos4-open, imap-gssapi-open, imap-close): Use them.
+
+       * nnimap.el (nnimap-logout-timeout): New server variable.
+       (nnimap-open-server, nnimap-close-server): Bind imap-logout-timeout to
+       nnimap-logout-timeout.
+
+       * gnus-art.el (gnus-article-summary-command-nosave)
+       (gnus-article-read-summary-keys): Don't use 3rd arg of pop-to-buffer.
+
+2007-08-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (gnus-maximum-newsgroup): New variable.
+
+       * gnus-agent.el (gnus-agent-fetch-headers): Limit the range of articles
+       according to gnus-maximum-newsgroup.
+
+       * gnus-sum.el (gnus-articles-to-read, gnus-list-of-unread-articles)
+       (gnus-list-of-read-articles, gnus-sequence-of-unread-articles):
+       Limit the range of articles according to gnus-maximum-newsgroup.
+
+2007-08-14  Tassilo Horn  <tassilo@member.fsf.org>
+
+       * gnus-art.el (gnus-sticky-article): Fix problems described in
+       <b4mps1qitio.fsf@jpl.org> on ding.  Thanks to Katsumi.
+       Don't perform gnus-configure-windows here; reuse existing sticky
+       article buffer.
+
+       * gnus-sum.el (gnus-summary-display-article): Setup article buffer if
+       it doesn't exist in gnus-article-mode.
+
+2007-08-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-agent.el (gnus-agent-decoded-group-names): New variable.
+       (gnus-agent-decoded-group-name): New function.
+       (gnus-agent-group-path, gnus-agent-group-pathname): Use it.
+       (gnus-agent-expire-group-1): Use it; decode group name in messages.
+
+2007-08-12  Tassilo Horn  <tassilo@member.fsf.org>
+
+       * gnus-sum.el (gnus-summary-article-map, gnus-summary-make-menu-bar):
+       Add binding for gnus-sticky-article.
+       (gnus-summary-exit): Don't kill sticky article buffers.
+
+       * gnus-art.el (gnus-sticky-article-mode): New mode to generate a sticky
+       article buffer.
+       (gnus-sticky-article, gnus-kill-sticky-article-buffer)
+       (gnus-kill-sticky-article-buffers): New commands.
+
+2007-08-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nntp.el (nntp-xref-number-is-evil): New server variable.
+       (nntp-find-group-and-number): If it is non-nil, don't trust article
+       numbers in the Xref header.
+
+2007-08-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-agent.el (gnus-agent-read-group): New function.
+       (gnus-agent-flush-group, gnus-agent-expire-group)
+       (gnus-agent-regenerate-group): Use it.
+       (gnus-agent-expire-unagentized-dirs): Bind file-name-coding-system to
+       nnmail-pathname-coding-system.
+
+2007-08-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-ems.el (gnus-x-splash): Bind inhibit-read-only to t.
+
+       * gnus-sum.el (gnus-summary-insert-articles): Mark inserted articles
+       that are unread as unread, and also as selected so that information of
+       marks having been changed by a user may be updated when exiting group.
+
+2007-08-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (article-hide-headers): Bind inhibit-read-only to t.
+
+2007-08-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-display-single): Pass part number that is
+       calculated ignoring signature parts to gnus-treat-article.
+
+2007-08-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-security-verify-or-decrypt): Don't narrow to
+       a point here in order to keep the window start.
+       (gnus-insert-mime-security-button): Make a button overlay without the
+       front stickiness.
+       (gnus-mime-display-security): Goto the end of a button.
+
+       * gnus-group.el (gnus-group-name-at-point): Fix regexps.
+
+2007-08-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el (gnus-group-name-at-point): Rewrite; rename from
+       group-name-at-point.
+       (gnus-group-completing-read): New function that offers decoded
+       non-ASCII group names for completion.
+       (gnus-fetch-group, gnus-group-read-ephemeral-group)
+       (gnus-group-jump-to-group, gnus-group-make-group-simple)
+       (gnus-group-unsubscribe-group, gnus-group-fetch-charter)
+       (gnus-group-fetch-control): Use it.
+       (gnus-fetch-group): Use group-name-at-point for the initial value
+       rather than the default value; use gnus-alive-p.
+
+       * gnus-msg.el (gnus-group-mail, gnus-group-news, gnus-group-post-news)
+       (gnus-summary-mail-other-window, gnus-summary-news-other-window)
+       (gnus-summary-post-news): Use gnus-group-completing-read.
+
+       * gnus-sum.el (gnus-select-newsgroup): Decode group name in error msg.
+       (gnus-read-move-group-name): Decode group name for completion.
+
+2007-07-31  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-srvr.el (gnus-server-close-all-servers): Close servers not only
+       in gnus-inserted-opened-servers but also in gnus-server-alist (Katsumi
+       Yamaoka slightly modified the code).
+
+2007-07-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnmail.el (nnmail-group-names-not-encoded-p): New variable.
+       (nnmail-split-incoming): Bind it.
+
+       * nnml.el (nnml-group-name-charset): New function.
+       (nnml-decoded-group-name): Use it; don't decode group name if
+       nnmail-group-names-not-encoded-p is non-nil.
+       (nnml-encoded-group-name): New function.
+       (nnml-group-pathname): Inline nnml-decoded-group-name.
+       (nnml-request-expire-articles): Decode group name in message.
+       (nnml-request-delete-group): Ditto; bind file-name-coding-system to
+       nnmail-pathname-coding-system.
+       (nnml-save-mail, nnml-active-number): Work with decoded group names and
+       not decoded ones according to nnmail-group-names-not-encoded-p.
+       (nnml-generate-active-info): Use nnml-encoded-group-name.
+
+2007-08-08  Glenn Morris  <rgm@gnu.org>
+
+       * gmm-utils.el, gnus-async.el, gnus-msg.el, gnus-score.el
+       * gnus-util.el, imap.el, mailcap.el, nnimap.el: Replace `iff' in
+       doc-strings and comments.
+
+2007-07-25  Glenn Morris  <rgm@gnu.org>
+
+       * Relicense all FSF files to GPLv3 or later.
+
+2007-07-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-move-article):
+       Make gnus-summary-respool-article work.
+
+2007-07-21  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-uu.el (mm-uu-type-alist): Refer to mm-uu-configure-list in doc
+       string.
+
+2007-07-20  Michaël Cadilhac  <michael@cadilhac.name>
+
+       * nnrss.el (nnrss-ignore-article-fields): New variable.  List of fields
+       that should be ignored when comparing distant RSS articles with local
+       ones.
+       (nnrss-make-hash-index): New function.  Create a hash index according
+       to the ignored fields.
+       (nnrss-check-group): Use it.
+
+2007-07-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-agent.el (gnus-agent-group-pathname): Take notice of the method.
+
+       * gnus-art.el (article-decode-group-name): Decode Xref header too.
+
+       * gnus-group.el (gnus-group-make-group): Encode group name here unless
+       the new optional argument ENCODED is non-nil.
+       (gnus-group-make-doc-group): Use gnus-group-name-charset to determine
+       coding system for encoding group name.
+       (gnus-group-make-rss-group): Pass un-encoded group name to
+       gnus-group-make-group.
+       (gnus-group-set-info): Tell gnus-group-make-group that group name is
+       encoded.
+
+       * gnus-sum.el (gnus-summary-move-article, gnus-read-move-group-name):
+       Encode group name to which articles are moved or copied.
+       (gnus-summary-edit-article): Use gnus-group-name-charset to determine
+       coding system for encoding Newsgroup, Followup-To and Xref headers.
+
+       * nnagent.el (nnagent-request-set-mark): Use unibyte buffer to compose
+       marks; use nnheader-file-coding-system to write a file.
+       (nnagent-retrieve-headers): Bind file-name-coding-system to
+       nnmail-pathname-coding-system.
+
+       * nnmail.el (nnmail-insert-xref): Don't break non-ASCII group name.
+
+       * nnml.el (nnml-decoded-group-name, nnml-group-pathname): New functions.
+       (nnml-request-article, nnml-request-create-group)
+       (nnml-request-rename-group, nnml-find-id)
+       (nnml-possibly-change-directory, nnml-possibly-create-directory)
+       (nnml-save-mail, nnml-active-number, nnml-marks-changed-p)
+       (nnml-save-marks): Use nnml-group-pathname instead of
+       nnmail-group-pathname.
+
+       (nnml-request-create-group, nnml-request-expire-articles)
+       (nnml-request-move-article, nnml-request-delete-group)
+       (nnml-deletable-article-p, nnml-possibly-create-directory)
+       (nnml-get-nov-buffer, nnml-generate-nov-databases-directory)
+       (nnml-open-marks): Bind file-name-coding-system to
+       nnmail-pathname-coding-system.
+
+       (nnml-request-article): Pass server argument to nnml-find-group-number.
+       (nnml-request-create-group, nnml-active-number, nnml-save-marks):
+       Pass server argument to nnml-possibly-create-directory.
+       (nnml-request-accept-article): Pass server argument to
+       nnml-active-number and nnml-save-mail.
+       (nnml-find-group-number): Pass server argument to nnml-find-id.
+       (nnml-request-update-info): Pass server argument to
+       nnml-marks-changed-p.
+
+       (nnml-find-id, nnml-find-group-number, nnml-possibly-create-directory)
+       (nnml-save-mail, nnml-active-number): Add server argument.
+
+       (nnml-request-delete-group): Warn if group is missing.
+       (nnml-get-nov-buffer): Decode group name.
+       (nnml-generate-active-info): Encode group name.
+       (nnml-open-marks): Decode group name in messages.
+
+2007-07-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-part-wrapper): Work with the nearest part
+       if it is not specified.
+       (gnus-article-pipe-part, gnus-article-save-part)
+       (gnus-article-interactively-view-part, gnus-article-copy-part)
+       (gnus-article-view-part-as-charset, gnus-article-view-part-externally)
+       (gnus-article-inline-part, gnus-article-save-part-and-strip)
+       (gnus-article-replace-part, gnus-article-delete-part)
+       (gnus-article-view-part-as-type): Pass raw prefix argument to
+       gnus-article-part-wrapper.
+
+2007-07-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-agent.el (gnus-agent-save-active):
+       Bind nnheader-file-coding-system to gnus-agent-file-coding-system.
+
+       * gnus-cache.el (gnus-cache-save-buffers)
+       (gnus-cache-possibly-enter-article, gnus-cache-request-article)
+       (gnus-cache-retrieve-headers, gnus-cache-change-buffer)
+       (gnus-cache-possibly-remove-article, gnus-cache-articles-in-group)
+       (gnus-cache-braid-nov, gnus-cache-braid-heads)
+       (gnus-cache-generate-active, gnus-cache-rename-group)
+       (gnus-cache-delete-group, gnus-cache-update-file-total-fetched-for)
+       (gnus-cache-update-overview-total-fetched-for):
+       Bind file-name-coding-system to nnmail-pathname-coding-system.
+       (gnus-cache-decoded-group-names, gnus-cache-unified-group-names):
+       New variables.
+       (gnus-cache-decoded-group-name): New function.
+       (gnus-cache-file-name): Use it.
+       (gnus-cache-generate-active): Use non-decoded group name for active.
+
+       * gnus-util.el (gnus-write-buffer): Bind file-name-coding-system at the
+       right place.
+       (gnus-write-active-file): Don't break non-ASCII group names.
+
+       * nntp.el (nntp-marks-changed-p): Bind file-name-coding-system to
+       nnmail-pathname-coding-system.
+
+       * lpath.el: Bind default-file-name-coding-system,
+       file-name-coding-system and language-info-alist for XEmacs.
+
+       * gnus-uu.el (gnus-uu-decode-save): Typo.
+
+2007-07-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-srvr.el (gnus-server-font-lock-keywords): Quote faces.
+
+2007-07-14  David Kastrup  <dak@gnu.org>
+
+       * gnus-art.el (gnus-mime-delete-part): Don't go through article-edit
+       finishing actions if we did not edit the article.
+
+2007-07-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-agent.el (gnus-agent-rename-group, gnus-agent-delete-group)
+       (gnus-agent-fetch-articles, gnus-agent-unfetch-articles)
+       (gnus-agent-crosspost, gnus-agent-backup-overview-buffer)
+       (gnus-agent-flush-group, gnus-agent-flush-cache)
+       (gnus-agent-fetch-headers, gnus-agent-load-alist)
+       (gnus-agent-read-agentview, gnus-agent-expire-group-1)
+       (gnus-agent-retrieve-headers, gnus-agent-request-article)
+       (gnus-agent-regenerate-group)
+       (gnus-agent-update-files-total-fetched-for)
+       (gnus-agent-update-view-total-fetched-for):
+       Bind file-name-coding-system to nnmail-pathname-coding-system.
+       (gnus-agent-group-pathname): Don't encode file names by
+       nnmail-pathname-coding-system.
+       (gnus-agent-save-local): Bind file-name-coding-system correctly; bind
+       coding-system-for-write instead of buffer-file-coding-system to
+       gnus-agent-file-coding-system.
+
+       * gnus-msg.el (gnus-inews-make-draft, gnus-inews-insert-archive-gcc):
+       Decode group name.
+
+       * gnus-srvr.el (gnus-browse-foreign-server): Make group names unibyte.
+
+       * gnus-start.el (gnus-update-active-hashtb-from-killed)
+       (gnus-read-newsrc-el-file): Make group names unibyte.
+
+       * nnmail.el (nnmail-group-pathname): Don't encode file names by
+       nnmail-pathname-coding-system.
+
+       * nnrss.el (nnrss-file-coding-system): Doc fix; make it begin with *.
+       (nnrss-request-delete-group): Bind file-name-coding-system to
+       nnmail-pathname-coding-system.
+       (nnrss-read-server-data, nnrss-read-group-data):
+       Bind file-name-coding-system correctly.
+       (nnrss-check-group): Pass nnrss-file-coding-system to md5.
+
+       * nntp.el: Require gnus-group for the function gnus-group-name-charset.
+       (nntp-server-to-method-cache): New variable.
+       (nntp-group-pathname): New function that decodes non-ASCII group names.
+       (nntp-possibly-create-directory, nntp-marks-changed-p)
+       (nntp-save-marks, nntp-open-marks): Use it.
+       (nntp-possibly-create-directory, nntp-open-marks):
+       Bind file-name-coding-system to nnmail-pathname-coding-system.
+       (nntp-open-marks): Decode group names when bootstrapping marks.
+
+       * rfc2047.el (rfc2047-encode-message-header): Make XEmacs decode
+       Newsgroups and Followup-To headers.
+
+2007-07-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-srvr.el (gnus-server-agent-face, gnus-server-opened-face)
+       (gnus-server-closed-face, gnus-server-denied-face)
+       (gnus-server-offline-face): Remove variable.
+       (gnus-server-font-lock-keywords): Use faces that are not aliases.
+
+       * gnus-util.el (gnus-message-with-timestamp-1): Use log-message instead
+       of modifying message-stack directly for XEmacs.
+
+       * mm-util.el (mm-decode-coding-string, mm-encode-coding-string)
+       (mm-decode-coding-region, mm-encode-coding-region): Don't modify string
+       if the coding-system argument is nil for XEmacs.
+
+       * nnrss.el (nnrss-compatible-encoding-alist): Inherit the value of
+       mm-charset-override-alist.
+
+       * rfc2047.el: Don't require base64; require rfc2045 for the function
+       rfc2045-encode-string.
+       (rfc2047-encode-parameter): Use rfc2045-encode-string to quote or not
+       to quote the parameter value.
+
+2007-07-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el (gnus-group-name-charset): Allow a method of the short
+       form in gnus-group-name-charset-method-alist.
+
+       * gnus-eform.el (gnus-edit-form): Add optional argument layout which
+       overrides the default layout edit-form.
+
+       * gnus-win.el (gnus-buffer-configuration): Add edit-server.
+
+       * gnus-srvr.el (gnus-server-edit-server): Use edit-server layout.
+
+2007-07-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-catchup): Don't recognize cached articles
+       as unfetched articles.
+
+2007-07-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-start.el (gnus-level-unsubscribed): Improve doc string.
+
+2007-07-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnagent.el (nnagent-request-set-mark): Also set the marks for the
+       original back end that keeps marks in the local system.
+
+2007-06-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-summary-command-nosave): Don't set the 3rd
+       arg of pop-to-buffer for XEmacs.
+       (gnus-article-read-summary-keys): Ditto; don't restore window
+       configuration if summary command ends up with neither article buffer
+       nor summary buffer; describe bindings if summary keys end with C-h.
+
+2007-06-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-fix-before-sending): Skip raw message part to be
+       forwarded while checking illegible text.
+       (message-forward-make-body-mime, message-forward-make-body):
+       Mark signed or encrypted raw message as having no illegible text.
+
+2007-06-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-add-timestamp-to-message): New user option.
+       (gnus-message-with-timestamp-1): New macro.
+       (gnus-message-with-timestamp): New function.
+       (gnus-message): Use them.
+
+       * nnheader.el (nnheader-message): Use them.
+
+2007-06-16  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-start.el (gnus-gnus-to-quick-newsrc-format): Add newlines to
+       .newsrc.eld file.
+
+2007-06-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-agent.el (gnus-agent-fetch-headers)
+       (gnus-agent-retrieve-headers):
+       Bind gnus-decode-encoded-address-function to identity.
+
+       * nntp.el (nntp-send-xover-command): Recognize an xover command is
+       available also when the server returns simply a dot.
+
+       * gnus-ems.el (gnus-x-splash): Redisplay window before measuring it.
+
+2007-06-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-ems.el (gnus-x-splash): Fix calculation; error in tty.
+
+2007-06-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-ems.el (gnus-x-splash): Make it work.
+
+       * gnus-start.el (gnus-1): Relax restrictions that prevent gnus-x-splash
+       from being used.
+
+       * lpath.el: Bind line-spacing and tool-bar-mode for XEmacs.
+
+2007-06-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-xmas.el (gnus-xmas-define): Make gnus-make-overlay ignore the
+       4th and the 5th arguments.
+
+       * gnus-art.el (gnus-insert-mime-button): Make a button overlay without
+       the front stickiness.
+       (gnus-article-summary-command-nosave): Correct the order of the
+       arguments passed to pop-to-buffer.
+       (gnus-article-read-summary-keys): Ditto; make it work properly when the
+       summary command ends up with the article buffer.
+
+       * mm-decode.el (mm-insert-part): Separate the extracted parts that have
+       the same faces.
+
+2007-06-07  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus-art.el (gnus-split-methods): Fix typo in docstring.
+
+2007-06-06  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus-diary.el (gnus-diary-time-format, gnus-summary-sort-by-schedule):
+       * gnus-sum.el (gnus-summary-highlight):
+       * pgg.el (pgg-sign-region, pgg-sign):
+       * mail-source.el (mail-source-delete-old-incoming-confirm):
+       * nndiary.el (nndiary-reminders): Fix typos in docstrings.
+
+2007-06-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-view-part-externally)
+       (gnus-mime-view-part-internally): Fix predicate function passed to
+       completing-read.
+
+       * mm-decode.el (mm-image-fit-p): Return t if argument is not an image.
+
+       * gnus.el (gnus-update-message-archive-method): Add :version.
+
+2007-06-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (gnus-update-message-archive-method): New variable.
+
+       * gnus-start.el (gnus-setup-news): Update saved "archive" method
+       according to gnus-message-archive-method if
+       gnus-update-message-archive-method is non-nil.
+
+2007-05-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-limit-to-address): New function.
+       Suggested by Loic Dachary <loic@dachary.org>.
+       (gnus-summary-limit-map, gnus-summary-make-menu-bar): Add it.
+
+2007-05-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-pop-to-buffer): Add switch-function argument.
+       (message-mail): Pass switch-function argument to it.
+
+2007-05-25  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-decode.el (mm-file-name-rewrite-functions): Make it customizable.
+       Improve doc string.
+
+2007-05-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-header-from, gnus-header-subject, gnus-header-name)
+       (gnus-header-content):
+       * gnus-cite.el (gnus-cite-10):
+       * gnus-srvr.el (gnus-server-closed):
+       * gnus.el (gnus-group-mail-1, gnus-group-mail-1-empty)
+       (gnus-group-mail-2, gnus-group-mail-2-empty, gnus-group-mail-3)
+       (gnus-group-mail-3-empty, gnus-group-mail-low)
+       (gnus-group-mail-low-empty, gnus-splash):
+       * message.el (message-header-to, message-header-cc)
+       (message-header-subject, message-header-other, message-header-name)
+       (message-header-xheader, message-separator, message-cited-text)
+       (message-mml): Lighten colors of faces used for dark background.
+
+2007-05-24  Simon Josefsson  <simon@josefsson.org>
+
+       * nnimap.el (nnimap-need-unselect-to-notice-new-mail): Change default
+       to t as an experiment.  Suggested by Greg Troxel <gdt@work.lexort.com>.
+
+2007-05-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-narrow-to-headers-or-head):
+       Ignore mail-header-separator in the body.
+
+2007-05-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-image-fit-p): Return t if image size is just the
+       same as window size.
+
+2007-05-22  Kevin Ryde  <user42@zip.com.au>
+
+       * message.el (message-font-lock-keywords): Use message-header-xheader
+       face for "X-Foo", its apparent intended purpose.  Move "X-" pattern
+       ahead of the anything pattern, to get it recognized.
+
+2007-05-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el: Autoload ad-add-advice for XEmacs.  bbdb-com.el that
+       spam.el loads uses it in the compiled defadvice form.
+
+2007-05-12  Michaël Cadilhac  <michael@cadilhac.name>
+
+       * gnus-sum.el (gnus-articles-to-read)
+       (gnus-summary-insert-old-articles): Don't truncate group name for
+       `read-string'.
+
+       * gnus-util.el (gnus-limit-string): Delete this function.
+
+       * gnus-sum.el (gnus-simplify-subject-fully):
+       Use `truncate-string-to-width' instead.
+
+2007-05-11  Michaël Cadilhac  <michael@cadilhac.name>
+
+       * gnus-sum.el (gnus-summary-next-group-on-exit): New variable.
+       Tell if, on summary exit, the next group has to be selected.
+       (gnus-summary-exit): Use it.
+
+2007-05-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-article-mode): Fix comment about displaying
+       non-break space.
+
+2007-05-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnfolder.el (nnfolder-request-group, nnfolder-request-create-group):
+       Check if group is not a directory.
+       (nnfolder-request-expire-articles): Don't delete articles if the target
+       group is not available.
+
+       * nnml.el (nnml-request-create-group): Properly check if group is not a
+       file.
+       (nnml-request-expire-articles): Don't delete articles if the target
+       group is not available.
+
+       * rfc2047.el (rfc2047-quote-special-characters-in-quoted-strings):
+       Don't quote characters that are within parentheses.
+
+2007-05-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-auto-select-on-ephemeral-exit): New variable.
+       (gnus-handle-ephemeral-exit): Select article according to it.
+
+2007-05-08  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-insert-formated-citation-line): Remove newline.
+       (message-citation-line-format): Add final \n here so that the user can
+       avoid a blank line.
+
+2007-05-03  Dan Christensen  <jdc@uwo.ca>
+
+       * nndoc.el (nndoc-type-alist, nndoc-lanl-gov-announce-type-p)
+       (nndoc-transform-lanl-gov-announce, nndoc-generate-lanl-gov-head):
+       Update lanl/arXiv support.
+
+2007-05-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.el: Bump version number.
+
+2007-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Bump version.
+
+2007-05-01  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: No Gnus v0.6 is released.
+
+2007-04-27  Didier Verna  <didier@xemacs.org>
+
+       * gnus-util.el (gnus-orify-regexp): Move and rename to ...
+       * gmm-utils.el (gmm-regexp-concat): ... here.
+       * message.el: Don't require 'gnus-util.
+       (message-dont-reply-to-names): Handle name change above.
+       * gnus-sum.el (gnus-ignored-from-addresses): Ditto.
+
+2007-04-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-charset-synonym-alist): Don't make it a user option
+       since the initial value varies according to the system.
+
+2007-04-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-charset-synonym-alist): Defcustom.
+
+2007-04-25  NAKAJI Hiroyuki  <nakaji@jp.freebsd.org>  (tiny change)
+
+       * mm-util.el (mm-charset-synonym-alist): Map iso8859-1 to iso-8859-1.
+
+2007-04-24  Didier Verna  <didier@xemacs.org>
+
+       Improve the type of gnus-ignored-from-addresses.
+       * gnus-util.el (gnus-orify-regexp): New function.
+       * message.el (gnus-util): Require it.
+       * message.el (message-dont-reply-to-names): Use gnus-orify-regexp.
+       * gnus-sum.el (gnus-ignored-from-addresses): New function.
+       * gnus-sum.el (gnus-summary-from-or-to-or-newsgroups): Use it.
+
+2007-04-24  Didier Verna  <didier@xemacs.org>
+
+       * gnus-sum.el:
+       * gnus-utils.el: Fix some trailing whitespaces.
+
+2007-04-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-summary-resend-message-edit): Add Gcc header.
+       (gnus-summary-resend-bounced-mail): Ditto; search whole body for parent
+       article's Message-ID; refer parent article in summary buffer.
+
+       * message.el (message-bounce): Call mime-to-mml.
+
+       * dgnushack.el (byte-optimize-form-code-walker): Fix the form which was
+       not helpful to Emacs 21.1 and 21.2 for detecting a bug that does not
+       optimize and/or forms properly.
+
+2007-04-22  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * dgnushack.el (with-syntax-table): XEmacs bug has been fixed.  Add
+       URL.
+
+2007-04-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-summary-supersede-article): Add Gcc header.
+
+2007-04-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-strip-charset-parameters): New function.
+       (gnus-mime-view-part-as-charset): Use it; redisplay subpart currently
+       displayed of multipart/alternative part if it is invoked from summary
+       buffer.
+
+       * mm-view.el (mm-inline-text-html-render-with-w3m)
+       (mm-inline-text-html-render-with-w3m-standalone)
+       (mm-inline-render-with-function): Use mail-parse-charset by default.
+
+2007-04-18  Levin Du  <zslevin@gmail.com>  (tiny change)
+
+       * parse-time.el (parse-time-string-chars): Check if CHAR
+       is less than the length of parse-time-syntax.
+
+2007-04-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-uu.el (gnus-uu-digest-mail-forward): Pull articles processed
+       from gnus-newsgroup-processable.
+
+2007-04-16  Didier Verna  <didier@xemacs.org>
+
+       * gnus-msg.el (gnus-configure-posting-styles):
+       Handle message-signature-directory properly with :file syntax.
+       Reported by "Leo".
+
+2007-04-11  Didier Verna  <didier@xemacs.org>
+
+       New user option: message-signature-directory.
+       * gnus-msg.el (gnus-configure-posting-styles): Support it.
+       * message.el (message-insert-signature): Ditto.
+       * message.el (message-signature-file): Doc update.
+       * message.el (message-signature-directory): New.
+
+2007-04-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-inews-yank-articles):
+       Use message-exchange-point-and-mark instead of exchange-point-and-mark.
+
+2007-04-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-yank-original): Make sure cited text ends with
+       newline; don't exchange point and mark.
+
+2007-04-07  Chong Yidong  <cyd@stupidchicken.com>
+
+       * tls.el (open-tls-stream): Properly handle case where there
+       is no associated buffer.
+
+2007-04-03  Thien-Thi Nguyen  <ttn@gnu.org>
+
+       * gnus-msg.el (gnus-inews-yank-articles): Fix bug: After
+       message-yank-original, make sure (< mark TEXT point).
+
+2007-03-31  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-fill-column): New variable.
+       (message-mode): Use it.  Add comment on a possible new hook.
+
+       * nnmail.el (nnmail-spool-file): Mark as obsolete.
+       (nnmail-get-new-mail): Reformat.
+
+       * gnus-registry.el (gnus-registry-cache-save): Add FIXME comment.
+
+       * gmm-utils.el: Fix Commentary.
+       (gmm-tool-bar-from-list): Fix typo in doc string.
+
+2007-03-27  Thien-Thi Nguyen  <ttn@gnu.org>
+
+       * message.el (message-yank-original): Don't switch point and mark
+       unnecessarily to put point and mark as documented.
+
+2007-03-27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-put-addresses-in-ecomplete): Only fetch headers
+       from the message heads.
+
+2007-03-25  Kevin Greiner  <kevin.greiner@compsol.cc>
+
+       * gnus-art.el (gnus-article-set-window-start): Do nothing when the
+       article buffer does not have a window.  This may not be the best
+       solution but is certainly better than setting the start of the null,
+       that is the current, window.
+
+2007-03-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-draft.el (gnus-draft-setup-hook): New hook.
+       (gnus-draft-setup): Run it.
+
+       * gnus-score.el (gnus-inhibit-slow-scoring): New variable, renamed from
+       gnus-score-fast-scoring.  Allow regexp.
+       (gnus-score-headers): Use it.
+
+       * gnus-util.el (gnus-emacs-version): Include "no MULE" in no-MULE
+       XEmacs.
+
+       * gnus-art.el (gnus-article-browse-html-article): Fix typo in doc
+       string.
+       (gnus-button-alist): Also catch `<f1> k ...'.
+       (gnus-treat-display-x-face): Fix doc string.
+
+2007-03-25  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * gnus-msg.el (gnus-setup-message, gnus-inews-add-send-actions): Move
+       evaluation of gnus-extended-version to ensure correct generation of the
+       User-Agent header when message-generate-headers-first is used.
+
+2007-03-24  Simon Josefsson  <simon@josefsson.org>
+
+       * hashcash.el (hashcash-generate-payment-async): Don't crash if
+       hashcash-path is nil.  Don't call callback with incorrect number of
+       parameters if val is 0.
+
+2007-03-20  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * message.el (message-required-news-headers):
+       * gnus-util.el (gnus-intern-safe): Fix typo in docstring.
+
+2007-03-18  Thien-Thi Nguyen  <ttn@gnu.org>
+
+       * tls.el (open-tls-stream): In handshake-waiting loop,
+       don't wait more if there is output available to process.
+
+2007-03-17  Thien-Thi Nguyen  <ttn@gnu.org>
+
+       * tls.el (tls-program): Doc fix.
+
+2007-03-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-generate-new-buffers): Change the meaning of the
+       nil value; add `standard' to the choices; treat t as `unique'; improve
+       doc string.
+       (gnus-select-frame-set-input-focus): Autoload.
+       (message-buffer-name): Search for the existing message buffer if
+       message-generate-new-buffers is nil or `standard'; treat the value t of
+       message-generate-new-buffers as `unique'.
+       (message-pop-to-buffer): Raise the frame already displaying the message
+       buffer; clear the echo area after querying.
+       (message-setup): Pass the `continue' argument to compose-mail.
+       (message-mail): Prefer `switch-function' if it is given; search for the
+       existing message buffer if the `continue' argument is non-nil; pass
+       continue and switch-function arguments to compose-mail by way of
+       message-setup.
+       (message-mail-other-window): Adjust argument of message-setup.
+       (message-mail-other-frame): Ditto.
+
+2007-03-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-cite.el (font-lock-set-defaults): Autoload it for Emacs.
+       (gnus-message-citation-mode): Require font-lock for XEmacs; make sure
+       to turn font-lock on when turning gnus-message-citation-mode on.
+
+2007-03-06  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml-smime.el (mml-smime-use): New variable; default to use openssl.
+       (mml-smime-function-alist): New variable; add epg as the backend.
+       * mml-sec.el (mml-smime-sign): Don't require mml-smime, autoload
+       mml-smime- functions instead.
+       * mm-view.el: Require smime.
+
+2007-03-05  Didier Verna  <didier@xemacs.org>
+
+       * gnus-topic.el (gnus-topic-hierarchical-parameters): Perform merging
+       instead of just inheritance for posting styles.
+       * gnus.el (gnus-group-fast-parameter): Fix typo in comment.
+
+2007-02-24  Chris Moore  <dooglus@gmail.com>
+
+       * pgg-pgp5.el (pgg-pgp5-encrypt-region):
+       * pgg-pgp.el (pgg-pgp-encrypt-region):
+       * pgg-gpg.el (pgg-gpg-encrypt-region):
+       Check pgg-encrypt-for-me if no other recipients.
+
+2007-02-24  John Paul Wallington  <jpw@pobox.com>
+
+       * tls.el (tls-certtool-program): Fix custom type.
+
+2007-02-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-cite.el (gnus-message-search-citation-line): Use point-at-bol
+       and point-at-eol instead of line-(beginning|end)-position.
+
+       * assistant.el (assistant-parse-buffer): Ditto.
+
+       * netrc.el (netrc-parse-services): Ditto.
+
+2007-02-28  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el (mml2015-epg-find-usable-key): New function.
+       (mml2015-epg-sign): Use it.
+       (mml2015-epg-encrypt): Use it.
+
+2007-02-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-make-in-reply-to): Quote name containing
+       non-ASCII characters.  It will make the RFC2047 encoder cause an error
+       if there are special characters.  Reported by NAKAJI Hiroyuki
+       <nakaji@jp.freebsd.org>.
+
+2007-02-27  Didier Verna  <didier@xemacs.org>
+
+       Include the group parameters as well as the topic ones in the
+       inheritance filter process.
+       * gnus-topic.el (gnus-topic-hierarchical-parameters): New optional
+       argument GROUP-PARAMS-LIST.
+       * gnus-topic.el (gnus-group-topic-parameters): Use it.
+
+2007-02-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nntp.el (nntp-never-echoes-commands)
+       (nntp-open-connection-functions-never-echo-commands): New variables.
+       (nntp-send-command): Use them.
+
+2007-02-20  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el (mml2015-epg-verify): Simplify.
+
+2007-02-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml.el (mml-content-disposition-alist): New user option.
+       (mml-content-disposition): New function.
+       (mml-insert-mime-headers, mml-minibuffer-read-disposition): Use it.
+       (mml-attach-file, mml-dnd-attach-file): Pass file name to it.
+
+2007-02-19  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el (mml2015-epg-verify): Convert LF to CRLF before signature
+       verification.
+
+2007-02-15  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * nnweb.el (nnweb-google-parse-1): Fix date parsing to also match on
+       articles posted in the last 24 hours.
+
+2007-02-14  Chong Yidong  <cyd@stupidchicken.com>
+
+       * smiley.el (smiley-regexp-alist): Add "dead" smiley.
+
+2007-02-14  Michaël Cadilhac  <michael@cadilhac.name>
+
+       * nntp.el (nntp-send-command): Don't wait for echoes when
+       nntp-open-ssl-stream is used.
+
+2007-02-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-cite.el (gnus-test-font-lock-add-keywords)
+       (gnus-message-add-citation-keywords)
+       (gnus-message-remove-citation-keywords): Remove.
+       (gnus-message-citation-mode): Instead of modifying font-lock-keywords
+       directly, make the variables in font-lock-defaults buffer-local, add
+       gnus-message-citation-keywords to them and then update the value of
+       font-lock-keywords.
+
+2007-02-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-cite-original-1): Don't call
+       gnus-article-highlight-citation.
+
+       * gnus-cite.el (gnus-cite-parse): Work with two or more MS-type
+       citations; fix line count.
+
+2007-02-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-cite.el (gnus-test-font-lock-add-keywords): New function.
+       (gnus-message-add-citation-keywords)
+       (gnus-message-remove-citation-keywords): Use it; fix the emulating
+       versions of font-lock-add-keywords and font-lock-remove-keywords to
+       work with XEmacs correctly.
+
+2007-02-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-cite.el (gnus-cite-face-list): Set the values of
+       gnus-message-max-citation-depth and gnus-message-citation-keywords.
+       (gnus-message-max-citation-depth): Use defvar rather than defconst.
+       (gnus-message-cite-prefix-regexp): New variable.
+       (gnus-message-search-citation-line): Use it; protect against long
+       citation prefix; fill match data with nil rather than 0 for XEmacs; set
+       the 0th match data for Emacs.
+       (gnus-message-citation-keywords): Set LAXMATCH flag in every HIGHLIGHT.
+       (gnus-message-add-citation-keywords): Append keywords rather than
+       prepending; emulate font-lock-add-keywords if it is not available.
+       (gnus-message-remove-citation-keywords):
+       Emulate font-lock-remove-keywords if it is not available.
+
+       * gnus-msg.el (gnus-message-highlight-citation): Default to t.
+
+       * message.el (message-cite-prefix-regexp): Set the value of
+       gnus-message-cite-prefix-regexp.
+
+2007-02-01  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * nnweb.el (nnweb-google-parse-1): Update parser.
+
+2007-01-29  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus-art.el (gnus-button-prefer-mid-or-mail): Fix typo in docstring.
+
+2007-01-28  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * nnslashdot.el (nnslashdot-request-article): Update end-of-article
+       regexp.
+
+2007-01-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * uudecode.el (uudecode-string-to-multibyte): New function emulating
+       string-to-multibyte.
+       (uudecode-decode-region-internal): Use it.
+
+       * lpath.el: Fbind string-as-multibyte for XEmacs.
+
+2007-01-23  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-score.el (gnus-home-score-file, gnus-home-adapt-file):
+       Fix custom choice.
+
+       * gnus-art.el (gnus-signature-limit): Fix custom choice.
+
+2007-01-22  Daiki Ueno  <ueno@unixuser.org>
+
+       * mm-util.el (mm-inhibit-file-name-handlers): Add epa-file-handler.
+
+       * mm-decode.el (mm-save-part-to-file): Use `mm-write-region' instead of
+       `write-region' to respect `mm-inhibit-file-name-handlers'.
+
+2007-01-19  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnsoup.el (nnsoup-directory, nnsoup-packer, nnsoup-packet-directory):
+       Use gnus-home-directory instead of "~/" or "$HOME".
+
+2007-01-17  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * encrypt.el (encrypt-insert-file-contents): Add better prompt
+       to mention filename.
+       Add comments at beginning regarding usage.
+       (encrypt-write-file-contents): Change interactive so a string is
+       acceptable.  If the file has no associated model, show an error instead
+       of a nonsense prompt.
+
+2007-01-16  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * spam.el (spam-bsfilter-ham-switch): Fix typo.
+       Thanks to Yoshihiko Yamada for kind notification of this typo.
+
+2007-01-12  Kenichi Handa  <handa@m17n.org>
+
+       * uudecode.el (uudecode-decode-region-internal): Make it work in a
+       multibyte buffer.
+
+2007-01-14  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-score.el (gnus-score-fast-scoring): New variable.
+       (gnus-score-headers): Use it.
+
+       * gnus-sum.el (gnus-auto-select-first): Improve doc string.
+
+       * message.el (message-cite-original-1):
+       Call gnus-article-highlight-citation if requested.
+       (message-make-from): Allow name and address as optional arguments.
+
+       * gnus-cite.el (gnus-article-highlight-citation): Add SAME-BUFFER arg.
+
+       * gnus-art.el (gnus-article-browse-html-article): Add warning about web
+       bugs to doc string.
+       (gnus-button-alist): Add mid\\|message-id.
+       (gnus-button-fetch-group): Extend for use in
+       `browse-url-browser-function'.
+       (gnus-button-url-regexp): Try to catch paired parentheses like in
+       Wikipedia URLs.
+
+       * gnus-sum.el (gnus-summary-reparent-children): Another doc string fix.
+       Suggested by Simon Krahnke <overlord@gmx.li>.
+
+2007-01-13  Romain Francoise  <romain@orebokech.com>
+
+       * nnml.el (nnml-use-compressed-files): Fix typo in docstring.
+       Update copyright.
+
+2007-01-13  Patric Mueller  <bhaak@bigfoot.com>  (tiny change)
+
+       * gnus-sum.el (gnus-summary-reparent-children): Fix typo in doc string.
+
+2007-01-09  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-unfollowed-groups)
+       (gnus-registry-split-fancy-with-parent): Fix documentation.
+
+2007-01-08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * spam-report.el (spam-report-gmane-internal): Speed up spam reporting
+       from nnweb groups.
+
+2006-12-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * spam-report.el (spam-report-gmane-internal): Add necessary "/" to
+       Xref urls.  Erase buffer before requesting head.
+
+       * mm-decode.el (mm-display-external): Use itimer function for XEmacs.
+
+2007-01-07  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-soup.el (gnus-soup): New custom group.  Make user variables
+       customizable.
+
+2007-01-05  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el (mml2015-epg-sign): Ask user whether to skip or abort if
+       no signing key is found.
+       (mml2015-epg-encrypt): Ask user whether to skip or abort if
+       no encrypting and/or signing key is found.
+
+2007-01-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * spam-report.el (spam-report-gmane-spam): Remove redundant message.
+
+2007-01-01  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * nnweb.el (nnweb-gmane-create-mapping): Put back code to merge the
+       headers read from disk with the ones newly found in the current search.
+       This should no longer cause problems, because the article numbers in
+       Gmane's `nov.php' output are ignored since the previous change.
+
+2007-01-02  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * gmm-utils.el (gmm-tool-bar-style): Fix custom type.
+
+2007-01-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind clear-string and cp-supported-codepages; don't fbind
+       replace-regexp-in-string; bind url-version; fbind display-images-p and
+       timer-set-function for XEmacs; bind timer-list for XEmacs; fbind
+       find-face and set-itimer-function for Emacs; bind itimer-list for
+       Emacs.
+
+       * mm-decode.el (mm-display-external): Use itimer function for XEmacs.
+
+2007-01-01  Romain Francoise  <romain@orebokech.com>
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Fix typo.
+
+2006-12-31  Steve Youngs  <steve@sxemacs.org>
+
+       * gnus-cite.el: Load easy-mmode at compile time for (S)XEmacs to get
+       `define-minor-mode' macro definition expanded properly.
+       (gnus-message-citation-mode): This is now OK for (S)XEmacs so don't
+       exclude it there.
+
+       * gnus-msg.el (gnus-message-highlight-citation): Revert Reiner's patch
+       of 2006-12-30.  The default is nil on (S)XEmacs already because of the
+       `fboundp' test.
+       (gnus-message-citation-mode): Revert Reiner's patch of 2006-12-30.
+       This is OK to autoload in (S)XEmacs now.
+
+2006-12-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-limit-to-singletons): New command and
+       keystroke.
+       (gnus-summary-limit-to-singletons): Fix typo.
+
+       * spam-report.el (spam-report-gmane-internal): Fall back on Xref if all
+       else fails.
+
+2006-12-30  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * gnus-cite.el (turn-off-gnus-message-citation-mode): Fix typo in
+       docstring.
+
+       * gnus-sum.el (gnus-summary-insert-ticked-articles): New command.
+       (gnus-summary-make-menu-bar, gnus-summary-buffer-map): Bind it.
+       (gnus-summary-insert-dormant-articles): Fix typo in message.
+
+2006-12-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-msg.el (gnus-message-highlight-citation): Ensure default to be
+       nil for XEmacs.
+       (gnus-message-citation-mode): Don't autoload in XEmacs.
+
+       * gnus-cite.el (gnus-message-citation-mode): Don't define in XEmacs.
+
+2006-12-29  Jouni K. Seppänen  <jks@iki.fi>
+
+       * nnimap.el (nnimap-expunge-search-string):
+       Mention nnimap-search-uids-not-since-is-evil in docstring.
+
+2006-12-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * spam.el: Revert to make-obsolete-variable because
+       define-obsolete-variable-alias is not supported in Emacs 21.
+
+       * spam.el (spam-ifile-path, spam-ifile-database-path)
+       (spam-bogofilter-path): Use define-obsolete-variable-alias instead of
+       make-obsolete-variable.
+       (spam-bsfilter-path, spam-bsfilter-program)
+       (spam-spamassassin-path, spam-spamassassin-program)
+       (spam-sa-learn-path, spam-sa-learn-program): Rename variables.
+       Don't use "path" inappropriately.
+       (spam-check-spamassassin, spam-spamassassin-register-with-sa-learn)
+       (spam-check-bsfilter, spam-bsfilter-register-with-bsfilter): Use new
+       variable names.
+
+2006-12-28  Daiki Ueno  <ueno@unixuser.org>
+
+       * gnus-sum.el (gnus-summary-next-article): Make sure we are in the
+       summary buffer.
+
+       * password.el (password-cache-remove): Use clear-string to burn
+       password, if available.
+
+2006-12-26  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-msg.el (gnus-message-citation-mode): Fix autoload.
+
+       * gnus-cite.el (gnus-message-highlight-citation): Move to gnus-msg.el.
+
+       * gnus-msg.el (gnus-setup-message): Add gnus-message-citation-mode.
+       (gnus-message-highlight-citation): Move defcustom here from
+       gnus-cite.el.
+       (gnus-message-citation-mode): Autoload.
+
+       * gnus-cite.el: Adjust Oliver's code to Gnus namespace.  Add some
+       checks to make it compile with XEmacs.
+       (gnus-message-citation-mode): New minor mode.
+       (gnus-message-max-citation-depth, gnus-message-citation-keywords)
+       (gnus-message-highlight-citation): New variables.
+       (gnus-message-search-citation-line)
+       (gnus-message-add-citation-keywords)
+       (gnus-message-remove-citation-keywords)
+       (turn-on-gnus-message-citation-mode)
+       (turn-off-gnus-message-citation-mode): New functions.
+
+2006-12-26  Oliver Scholz  <epameinondas@gmx.de>
+
+       * gnus-cite.el: Enable highlighting of different citation levels in
+       message-mode.
+
+2006-12-26  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-make-fqdn): Fix comment.
+       (message-bogus-system-names): Add ".local".
+
+       * spam.el (spam-ifile-path, spam-ifile-program)
+       (spam-ifile-database-path, spam-ifile-database)
+       (spam-bogofilter-path, spam-bogofilter-program): Rename variables.
+       Don't use "path" inappropriately.
+       (spam-spamoracle-database, spam-get-ifile-database-parameter): Fix doc
+       strings.
+       (spam-check-ifile, spam-ifile-register-with-ifile)
+       (spam-check-bogofilter, spam-bogofilter-register-with-bogofilter):
+       Use new variable names.
+
+       * gnus-art.el (gnus-treat-display-x-face, gnus-treat-display-face)
+       (gnus-treat-display-smileys): Simplify using
+       gnus-image-type-available-p.
+
+       * gnus-ems.el (gnus-image-type-available-p): Use display-images-p if
+       available.
+
+       * gnus-xmas.el (gnus-xmas-image-type-available-p):
+       Use `display-images-p' if available.
+
+2006-12-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnrss.el (nnrss-fetch): Replace buffer's contents with the decoded
+       one after turning on the buffer's multibyteness instead of decoding
+       them directly in the unibyte buffer that causes unexpected conversion
+       in Emacs 23 (unicode).
+
+2006-12-21  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * message.el (message-generate-hashcash): Fix custom type.
+
+2006-12-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-summary-recenter): Remove debug messages.
+
+2006-12-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-group.el (gnus-group-tool-bar-gnome): Exchange connect and
+       disconnect icons.  Add help text.
+
+2006-12-20  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-extra-header-to-number): CRM114 spam score is
+       negated to be consistent with the others we handle.
+
+2006-12-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-setup-buffer): Actually set the local
+       version of gnus-summary-buffer to something, so that we can use two
+       article buffers at the same time.
+
+2006-12-18  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-necessary-extra-headers): Make spam-use-regex-headers
+       trigger all the extra headers.
+       (spam-extra-header-to-number): Don't require spam-use-crm114 for header
+       sorting.
+
+2006-12-14  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * nnweb.el (nnweb-gmane-create-mapping): Keep the mapping stable for
+       solid groups.
+
+2006-12-17  Chong Yidong  <cyd@stupidchicken.com>
+
+       * pgg-gpg.el (pgg-gpg-use-agent): Default to t.
+
+2006-12-13  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * legacy-gnus-agent.el: Add Copyright notice.
+
+2006-12-12  Chong Yidong  <cyd@stupidchicken.com>
+
+       * gnus-sum.el (gnus-make-thread-indent-array): Fix last change.
+
+2006-12-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnweb.el (nnweb-gmane-search): Placeholder TOPDOC setting.
+
+       * gnus-sum.el (gnus-summary-recenter): Force setting the window start
+       to make it work reliably in CVS Emacs.
+       (gnus-summary-limit-strange-charsets-predicate)
+       (gnus-summary-limit-to-predicate): New functions.
+
+2006-12-08  Chong Yidong  <cyd@stupidchicken.com>
+
+       * gnus-sum.el (gnus-make-thread-indent-array): New optional arg
+       specifying array size.
+       (gnus-summary-insert-line, gnus-summary-prepare-threads): Regrow indent
+       array if it is too small.
+       (gnus-sort-threads-recursive): Rename from gnus-sort-thread-1.
+       (gnus-sort-threads-loop): New function.
+
+2006-12-06  Chris Moore  <dooglus@gmail.com>
+
+       * gnus-sum.el (gnus-sort-threads, gnus-summary-limit-children):
+       Use `max' to avoid the value of `max-lisp-eval-depth' decreasing.
+
+2006-12-04  Jouni K. Seppänen  <jks@iki.fi>
+
+       * mm-url.el (mm-url-predefined-programs): Call curl with correct
+       options.
+
+2006-12-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * spam-report.el (spam-report-url-ping-plain): Wait for output to avoid
+       DOS-ing the recipient.
+
+       * nnweb.el (nnweb-gmane-create-mapping): Use the article number from
+       the headers when creating the mapping to avoid mismappings.
+       (nnweb-gmane-create-mapping): Always nix out old mapping.
+
+2006-11-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-signed-or-encrypted-p): Bind mm-decrypt-option
+       and mm-verify-option to never.
+
+2006-11-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-signed-or-encrypted-p): New function.
+       (message-forward-make-body): Use it.
+
+       * mml2015.el (mml2015-pgg-clear-verify, mml2015-epg-clear-verify):
+       Replace encode-coding-string with mm-encode-coding-string.
+
+2006-11-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nneething.el (nneething-decode-file-name):
+       Replace decode-coding-string with mm-decode-coding-string.
+
+       * gnus-int.el (gnus-open-server): Say failed server's name.
+
+2006-11-24  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * pgg-pgp.el (pgg-pgp-process-region): Change `args' from a list of
+       strings to a single string.  Quote `errors-file-name'.
+       (pgg-pgp-encrypt-region, pgg-pgp-decrypt-region, pgg-pgp-sign-region)
+       (pgg-pgp-verify-region, pgg-pgp-insert-key, pgg-pgp-snarf-keys-region):
+       Adjust calls.  Use `shell-quote-argument'.
+
+2006-11-24  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus-agent.el (gnus-agent-expire-unagentized-dirs)
+       (gnus-agent-regenerate-group): Fix space/tab mixup in messages.
+
+       * gnus-art.el (gnus-article-x-face-command, gnus-numeric-save-name):
+       * gnus-group.el (gnus-group-sort-function, gnus-group-line-format)
+       (gnus-group-mode, gnus-group-read-group, gnus-group-delete-group)
+       (gnus-group-make-directory-group, gnus-group-transpose-groups):
+       * gnus-start.el (gnus-options-subscribe, gnus-options-not-subscribe)
+       (gnus-subscribe-newsgroup, gnus-1):
+       * gnus-sum.el (gnus-summary-make-false-root, gnus-make-threads):
+       * gnus.el (gnus-nntp-server, gnus-use-cross-reference)
+       (gnus-valid-select-methods, total-expire, gnus-summary-line-format)
+       (gnus-group-read-only-p): Fix space/tab mixup in docstrings.
+
+2006-11-24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-limit-to-headers): New command and
+       keystroke.
+       (gnus-summary-limit-to-bodies): Implement headersp.
+
+2006-11-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * dns.el (query-dns): Protect against "Process dns deleted" strings.
+
+2006-11-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-string-to-multibyte): Alias to identity in XEmacs.
+
+2006-11-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-generate-hashcash): Expand range of values to
+       include `opportunistic'.
+       (message-send-mail): Use it.
+
+2006-11-18  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * mm-uu.el (mm-uu-pgp-signed-extract-1): Make last fix more thorough
+       and comment it.
+
+       * nnslashdot.el (nnslashdot-retrieve-headers-1): Update regexp.
+
+2006-11-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-util.el (gnus-extract-address-components): Improve comment.
+
+2006-11-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-extract-address-components): Work with address in
+       which the name portion contains @.
+
+       * lpath.el: Fbind custom-autoload.
+
+2006-11-14  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.el (gnus-start): Move custom group up.
+       (gnus-select-method): Don't autoload, but make it available for
+       `customize-variable'.
+       (gnus-getenv-nntpserver): Don't autoload.
+
+2006-11-14  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el: Revert to 7.82 (removed changes since 2006-10-16).
+
+2006-11-14  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-sendmail-extra-arguments): New variable.
+       (message-send-mail-with-sendmail): Use it.
+
+2006-11-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml.el (mml-generate-mime-1): Use mm-string-as-unibyte instead of
+       mm-with-unibyte-current-buffer to make string unibyte.
+
+       * mm-decode.el (mm-insert-part): Use mm-string-to-multibyte instead of
+       mm-string-as-multibyte.
+
+2006-11-14  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el (mml2015-epg-sign): Prefix "pgp-" to a micalg value.
+       Reported by Werner Koch <wk@gnupg.org>.
+
+2006-11-14  Daiki Ueno  <ueno@p360>
+
+       * mml2015.el: Autoload epa-select-keys when compiling.
+
+2006-11-13  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el (mml2015-epg-sign): Save the signing keys in
+       message-options.
+       (mml2015-epg-encrypt): Save the recipient keys in message-options.
+
+2006-11-13  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el (mml2015-epg-encrypt): Remove backward compatibility for
+       EasyPG (< 0.0.6).
+       (mml2015-always-trust): New user option.
+       (mml2015-epg-passphrase-callback): Display key ID on the passphrase
+       prompt.
+
+2006-11-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nntp.el (nntp-authinfo-force): New variable.
+       (nntp-send-authinfo): Use it.
+
+2006-11-09  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-strip-subject-encoded-words): Allow _not_ to
+       decode encoded words.  Improve prompt.  Add comment about forwarding.
+       (message-replacement-char): Move up.
+
+2006-11-08  Wolfgang Jenkner  <wjenkner@inode.at>  (tiny change)
+
+       * gnus-sum.el (gnus-summary-catchup): Use gnus-sorted-intersection
+       instead of gnus-intersection because arguments of gnus-sorted-nunion
+       must be sorted.  This avoids corruption of gnus-newsgroup-unreads.
+
+2006-11-07  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-strip-subject-encoded-words): Reformat prompt.
+       (message-simplify-subject-functions):
+       Enable message-strip-subject-encoded-words by default.
+
+2006-11-06  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-strip-subject-encoded-words): New function.
+       (message-simplify-subject-functions): New variable.
+       (message-simplify-subject): Use it.  Fix typo in doc string.
+       Support message-strip-subject-encoded-words.
+
+2006-11-03  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus-diary.el (gnus-diary-delay-format-function):
+       * nndiary.el (nndiary-reminders):
+       * nnsoup.el (nnsoup-always-save): Use "non-nil" in docstrings.
+
+2006-11-01  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (article-hide-boring-headers): Fetch date from
+       gnus-original-article-buffer to avoid problems with localized date
+       strings.
+
+2006-10-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * html2text.el (html2text-format-tags): Avoid infloop on open tags.
+
+2006-10-29  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-util.el (mm-codepage-iso-8859-list, mm-codepage-ibm-list):
+       New variables.
+       (mm-setup-codepage-iso-8859, mm-setup-codepage-ibm): New functions.
+       (mm-charset-synonym-alist): Move some entries to
+       mm-codepage-iso-8859-list.
+       (mm-charset-synonym-alist, mm-charset-override-alist):
+       Add iso-8859-8/windows-1255 and iso-8859-9/windows-1254.
+
+2006-10-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-set-mode-line): Quote % in group name.
+
+2006-10-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-agent.el (gnus-agent-make-mode-line-string): Make it compatible
+       with Emacs 21 and XEmacs.
+
+2006-10-27  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-parse-address): New function for better parsing,
+       catching errors, etc.
+       (spam-check-BBDB, spam-enter-ham-BBDB, spam-parse-list): Use it.
+
+2006-10-26  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-view.el: Add interactive arg to html2text autoload.
+
+2006-10-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-move-article): Use no-encode for `B B'.
+
+2006-10-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-util.el (mm-codepage-iso-8859-list, mm-codepage-ibm-list):
+       New variables.
+       (mm-setup-codepage-iso-8859, mm-setup-codepage-ibm): New functions.
+       (mm-charset-synonym-alist): Move some entries to
+       mm-codepage-iso-8859-list.
+
+       * gnus.el (gnus-getenv-nntpserver, gnus-select-method): Autoload.
+
+2006-10-23  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-citation-line-format)
+       (message-insert-formated-citation-line): Fix implementation of %E, %N
+       and %n according to the doc string.
+
+2006-10-20  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-check-BBDB, spam-enter-ham-BBDB, spam-parse-list):
+       Use car-safe to avoid bad parses.
+
+2006-10-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el (gnus-group-make-doc-group): Work for non-ASCII group
+       names.
+
+       * gnus-sum.el (gnus-select-newsgroup): Decode group name.
+
+2006-10-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-draft.el (gnus-draft-edit-message): Make sure to remove Date
+       header.
+
+       * message.el (message-draft-headers): Add Date.
+       (message-headers-to-generate): Fix typo in docstring.
+
+       * nndraft.el (nndraft-required-headers): New variable.
+       (nndraft-generate-headers): Use it.
+
+       * gnus-registry.el (gnus-registry-wash-for-keywords): Bind `word'.
+
+2006-10-16  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-wash-for-keywords)
+       (gnus-registry-find-keywords): New functions to allow easy searching of
+       articles that are in the registry.
+
+2006-10-16  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-check-BBDB, spam-enter-ham-BBDB, spam-parse-list):
+       Use ietf-drums-parse-address instead of gnus-extract-address-components.
+       Reported by Damien Elmes <damien@repose.cx>.
+
+2006-10-19  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.el (gnus-mime): Remove unused custom group.
+
+2006-10-13  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * mm-uu.el (mm-uu-pgp-signed-extract-1): Use RFC 2440 definition of
+       "blank line" when searching for end of armor headers.
+
+2006-10-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gmm-utils.el (gmm-write-region): Fix variable name.
+
+2006-10-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gmm-utils.el (gmm-write-region): New function based on compatibility
+       code from `mm-make-temp-file'.
+
+       * mm-util.el (mm-make-temp-file): Use `gmm-write-region'.
+
+       * nnmaildir.el (nnmaildir--update-nov)
+       (nnmaildir-request-replace-article, nnmaildir-request-accept-article):
+       Use `gmm-write-region'.
+
+2006-10-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-util.el (mm-charset-synonym-alist, mm-charset-override-alist):
+       Add iso-8859-8/windows-1255 and iso-8859-9/windows-1254.
+
+       * nnheader.el (nnheader-find-file-noselect): Inhibit version-control.
+
+       * message.el (message-replacement-char): New variable.
+       (message-fix-before-sending): Use it.
+       (message-simplify-subject): New function to remove duplicate code.
+       (message-reply, message-followup): Use it.
+
+       * gnus-sum.el (gnus-summary-make-menu-bar):
+       Clarify gnus-summary-limit-to-articles.
+
+2006-10-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-with-local-quit): New macro.
+
+       * gnus-demon.el (gnus-demon): Replace with-local-quit with it.
+
+2006-10-02  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-util.el (gnus-string-remove-all-properties): Another fix to
+       ignore non-string data.
+
+2006-09-29  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-util.el (gnus-string-remove-all-properties): Fix to ignore
+       non-string data (needs to be done in the registry too).
+
+2006-09-28  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-save, gnus-registry-cache-save)
+       (gnus-registry-remove-alist-text-properties, gnus-registry-action)
+       (gnus-registry-split-fancy-with-parent)
+       (gnus-registry-fetch-simplified-message-subject-fast)
+       (gnus-registry-fetch-sender-fast, gnus-registry-store-extra-entry):
+       Remove text properties on ingress into the registry and when it's saved.
+       (gnus-registry-clean-empty-function): Fix bug with cleaning the
+       registry from entries with no groups.
+
+2006-09-28  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-util.el (gnus-string-remove-all-properties): Add utility
+       function to remove string properties.
+
+2006-09-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gmm-utils.el (gmm): Adjust custom version.
+
+       * mm-util.el (mm-charset-override-alist, mm-charset-eval-alist):
+       Adjust custom version.
+
+       * gnus-draft.el (gnus-draft-mode): Don't call `mml-mode'.
+
+2006-09-27  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-insert-prev-page-button)
+       (gnus-insert-next-page-button): Simplify.  Reformat.
+
+2006-09-27  Maxime Edouard Robert Froumentin  <max@lapin-bleu.net>
+
+       * gnus-art.el (gnus-insert-prev-page-button)
+       (gnus-insert-next-page-button): Apply gnus-article-button-face.
+
+2006-09-25  Chong Yidong  <cyd@stupidchicken.com>
+
+       * gnus-demon.el (gnus-demon): Use with-local-quit to avoid hangs.
+
+2006-09-20  Maxime Edouard Robert Froumentin  <max@lapin-bleu.net>
+
+       * gnus-art.el (gnus-insert-mime-button)
+       (gnus-insert-mime-security-button):
+       Apply gnus-article-button-face to MIME and security buttons.
+
+2006-09-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button-url-regexp): Try to make the value more
+       readable.
+
+2006-09-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el: Autoload browse-url-of-file for XEmacs.
+
+2006-09-20  Steve Youngs  <steve@sxemacs.org>
+
+       * gnus-art.el (gnus-article-browse-html-parts): They're files, so use
+       `browse-url-of-file' instead of `browse-url'.
+
+2006-09-19  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * nnslashdot.el (nnslashdot-request-article): Update end-of-article
+       regexp.  Articles containing quotation were cut prematurely.
+
+2006-09-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-cite-original-1): Use nobody by default for the
+       value of From header.
+       (message-reply): Ditto.
+
+2006-09-11  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el (mml2015-epg-clear-decrypt): Don't append verify results
+       to the gnus-info.  This fixes a bug of inline-PGP message verification.
+       Reported by Michael Piotrowski <mxp@dynalabs.de>.
+
+2006-09-09  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * pop3.el (pop3-leave-mail-on-server): Mention problem of duplicate
+       mails in the doc string.  Add some URLs in comment.
+       (pop3-movemail): Warn about pop3-leave-mail-on-server.
+
+2006-09-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-quote-special-characters-in-quoted-strings): Fix
+       backslashes handling and the way to find boundaries of quoted strings.
+
+2006-09-07  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml1991.el (mml1991-epg-encrypt): Simply throw an error if
+       mml1991-encrypt-to-self is set and mml1991-signers is not set.
+       * mml2015.el (mml2015-epg-encrypt): Simply throw an error if
+       mml2015-encrypt-to-self is set and mml2015-signers is not set.
+
+2006-09-06  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button-marker-list): Move up.  Convert comment into
+       doc string.
+       (gnus-button-regexp, gnus-button-last): Remove unused variables.
+
+2006-09-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind epg-check-configuration.
+
+2006-09-06  Simon Josefsson  <jas@extundo.com>
+
+       * mml2015.el (mml2015-use): Doc fix, mention epg.
+
+2006-09-06  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el (mml2015-use): Default to epg, if available.
+
+2006-09-06  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml1991.el (mml1991-epg-sign): Don't lookup a private key by
+       message-sender.
+       (mml1991-epg-encrypt): Ditto.
+       * mml2015.el (mml2015-epg-sign): Don't lookup a private key by
+       message-sender.
+       (mml2015-epg-encrypt): Ditto.
+
+2006-09-04  Chong Yidong  <cyd@stupidchicken.com>
+
+       * message.el (message-send-mail-with-sendmail): Look for sendmail in
+       several common directories.
+
+2006-09-05  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el (mml2015-epg-encrypt): Expand group configuration.
+       * mml1991.el (mml1991-epg-encrypt): Expand group configuration.
+
+2006-09-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-decode-encoded-words): Make it fast.
+
+2006-09-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-decode-encoded-words): Don't infloop in XEmacs.
+
+       * rfc2047.el (rfc2047-strip-backslashes-in-quoted-strings): Decode `\\'
+       in quoted string into `\'.
+
+2006-09-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-quote-special-characters-in-quoted-strings):
+       Use standard-syntax-table.
+
+2006-09-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-decode-address-function): New variable.
+       (article-decode-encoded-words): Use it to decode headers which are
+       assumed to contain addresses.
+       (gnus-mime-delete-part): Remove useless `or'.
+
+       * gnus-sum.el (gnus-decode-encoded-address-function): New variable.
+       (gnus-summary-from-or-to-or-newsgroups): Use it to decode To header.
+       (gnus-nov-parse-line): Use it to decode From header.
+       (gnus-get-newsgroup-headers): Ditto.
+       (gnus-summary-enter-digest-group): Use it to decode `to-address'.
+
+       * mail-parse.el (mail-decode-encoded-address-region): New alias.
+       (mail-decode-encoded-address-string): New alias.
+
+       * rfc2047.el (rfc2047-quote-special-characters-in-quoted-strings):
+       New function.
+       (rfc2047-encode-message-header, rfc2047-encode-region): Use it.
+       (rfc2047-strip-backslashes-in-quoted-strings): New fnction.
+       (rfc2047-decode-region): Use it; add optional argument `address-mime'.
+       (rfc2047-decode-string): Ditto.
+       (rfc2047-decode-address-region): New function.
+       (rfc2047-decode-address-string): New function.
+
+2006-08-31  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-caesar-buffer-body): Allow rotating headers.
+
+       * gnus-sum.el (gnus-summary-caesar-message): Allow rotating headers.
+
+       * message.el (message-insert-formated-citation-line): Fix %f.
+       Reported by Torsten Bronger <bronger@physik.rwth-aachen.de> .
+
+2006-08-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-bookmark.el (gnus-bookmark-file-coding-system): New variable.
+       (gnus-bookmark-mouse-available-p): New macro.
+       (gnus-bookmark-bmenu-list): Use it; use gnus-mouse-2.
+       (gnus-bookmark-bmenu-show-infos): Use it.
+       (gnus-bookmark-insert-details): Use it; use gnus-mouse-2.
+       (gnus-bookmark-bmenu-hide-infos): Ditto.
+       (gnus-bookmark-remove-properties): New function.
+       (gnus-bookmark-set, gnus-bookmark-make-cell): Use it.
+       (gnus-bookmark-set-bookmark-name): Don't use 2nd arg of split-string.
+       (gnus-bookmark-write-file): Bind coding-system-for-write.
+       (gnus-bookmark-insert-file-format-version-stamp): Add coding cookie.
+       (gnus-bookmark-jump): Make completing-read work with XEmacs; activate
+       group before selecting it.
+       (gnus-bookmark-get-bookmark): Use assoc instead of assoc-string.
+       (gnus-bookmark-bmenu-mode-map): Bind `q' to bury-buffer instead of
+       quit-window if it is not available; use gnus-mouse-2 and bind it to
+       gnus-bookmark-bmenu-select-by-mouse.
+       (gnus-bookmark-show-details): Remove unused variable `details-list'.
+       (gnus-bookmark-bmenu-select-by-mouse): New function.
+
+2006-08-13  Romain Francoise  <romain@orebokech.com>
+
+       * mm-extern.el (mm-extern-mail-server): End `y-or-n-p' prompt with a
+       space.
+
+2006-08-10  Romain Francoise  <romain@orebokech.com>
+
+       * dns-mode.el: Alias `zone-mode' to `dns-mode'.
+       (dns-mode-soa-auto-increment-serial): New user option.
+       (dns-mode-soa-maybe-increment-serial): New function.
+       (dns-mode): Add the latter to `write-contents-functions'.
+
+2006-08-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * compface.el (uncompface): Use binary rather than raw-text-unix.
+
+2006-08-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * compface.el (uncompface): Make sure the eol conversion doesn't take
+       place when communicating with the external programs.
+       Reported by ARISAWA Akihiro <ari@mbf.ocn.ne.jp>.
+
+2006-07-31  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnheader.el (nnheader-insert-head): Fix typo in comment.
+
+2006-07-31  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * nnweb.el (nnweb-google-parse-1): Update regexp for author and date.
+       Make it more robust by parsing author and date independently.
+
+2006-07-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnheader.el (nnheader-insert-head): Make it work with Mac as well.
+
+2006-07-28  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el (mml2015-epg-sign): If mml2015-signers is not set, use the
+       first matching secret key.
+       (mml2015-epg-encrypt): Ditto.
+
+       * mml1991.el (mml1991-epg-sign): If mml1991-signers is not set, use the
+       first matching secret key.
+       (mml1991-epg-encrypt): Ditto.
+
+       * mml2015.el (mml2015-encrypt-to-self): New user option.
+       (mml2015-epg-encrypt): Append mml2015-signers to recipients list if
+       mml2015-epg-encrypt-to-self is set.
+
+       * mml1991.el (mml1991-encrypt-to-self): New variable.
+       (mml1991-epg-encrypt): Append mml1991-signers to recipients list if
+       mml1991-epg-encrypt-to-self is set.
+
+       * mml2015.el (mml2015-signers): New user option.
+       (mml2015-epg-sign): Reflect the value of mml2015-signers.
+       (mml2015-epg-encrypt): Allow to select signing keys.
+
+       * mml1991.el (mml1991-signers): New variable.
+       (mml1991-epg-sign): Reflect the value of mml1991-signers.
+       (mml1991-epg-encrypt): Allow to select signing keys.
+
+2006-07-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnheader.el (nnheader-insert-head): Make it work even if the file
+       uses CRLF for the line-break code.
+
+2006-07-25  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el: Require mml-sec instead of password.
+       (mml2015-verbose): Inherit the default value from mml-secure-verbose.
+       (mml2015-cache-passphrase): Inherit the default value from
+       mml-secure-cache-passphrase.
+       (mml2015-passphrase-cache-expiry): Inherit the default value from
+       mml-secure-passphrase-cache-expiry.
+
+       * mml1991.el: Require mml-sec instead of password.
+       (mml1991-verbose): Inherit the default value from mml-secure-verbose.
+       (mml1991-cache-passphrase): Inherit the default value from
+       mml-secure-cache-passphrase.
+       (mml1991-passphrase-cache-expiry): Inherit the default value from
+       mml-secure-passphrase-cache-expiry.
+
+       * mml-sec.el: Require password.
+       (mml-secure-verbose): New user option.
+       (mml-secure-cache-passphrase): New user option.
+       (mml-secure-passphrase-cache-expiry): New user option.
+
+2006-07-24  David Smith  <davidsmith@acm.org>  (tiny change)
+           Andreas Vögele  <andreas@altroot.de>   (tiny change)
+
+       * pgg-def.el (pgg-truncate-key-identifier):
+       Truncate the key ID to 8 letters from the end.
+
+2006-07-19  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * mm-url.el (mm-url-insert-file-contents): Inhibit Connection: close
+       workaround for the url package included with Emacs.
+
+       * nnweb.el (nnweb-google-create-mapping): Update regexp.
+
+2006-07-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-select-newsgroup): Setup the article buffer
+       correctly.  This fixes a bug caused by the 2006-05-12 change.
+
+2006-07-18  Karl Fogel  <kfogel@red-bean.com>
+
+       * nnmail.el (nnmail-article-group): If splitting raises an error, give
+       some information about the error when saying that the `bogus' mail
+       group will be used.
+
+2006-07-17  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-summary-delete-article): Don't use TAB in doc
+       string.
+
+2006-07-16  NAKAJI Hiroyuki  <nakaji@heimat.jp>  (tiny change)
+
+       * mm-util.el (mm-charset-synonym-alist): Map windows-31j to cp932.
+
+2006-07-14  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * gnus-start.el (gnus-subscribe-options-newsgroup-method): Doc fix.
+
+2006-07-10  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml1991.el (mml1991-function-alist): Add epg.
+       (mml1991-epg-passphrase-callback, mml1991-epg-sign)
+       (mml1991-epg-encrypt): New functions.
+
+2006-07-10  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el (mml2015-verbose): New variable.
+       (mml2015-cache-passphrase): Ditto.
+       (mml2015-passphrase-cache-expiry): Ditto.
+       (mml2015-function-alist): Add epg.
+       (mml2015-epg-passphrase-callback, mml2015-epg-decrypt)
+       (mml2015-epg-clear-decrypt, mml2015-epg-verify)
+       (mml2015-epg-clear-verify, mml2015-epg-sign, mml2015-epg-encrypt):
+       New functions.
+
+2006-07-08  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * message.el (message-cite-original-1): Preserve region when removing
+       quoted text due to X-No-Archive in order to avoid bogus attribution
+       when citing multiple messages.
+
+2006-06-27  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * gnus-group.el (gnus-group-sort-by-unread): Fix typo.
+       Reported by Kenneth Jacker <khj@be.cs.appstate.edu>.
+
+2006-06-26  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-diary.el (gnus-user-format-function-d)
+       (gnus-user-format-function-D): Autoload.
+
+       * imap.el (Commentary): Fix typo.
+
+       * gnus-util.el (kill-empty-logs, gnus-byte-compile): Remove anonymous
+       2006-04-22 contribution.
+
+2006-06-26  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * gnus.el (gnus-valid-select-methods): Revert last change for nnweb.
+       It didn't really fix the bogosity I'm seeing with solid web groups.
+
+2006-06-26  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * gnus.el (gnus-valid-select-methods): Declare nnweb with 'address.
+       Since revision 6.95 (2003-01-05) of gnus-group.el, solid web groups are
+       created using server names.  If we use the feature without declaring
+       it, Gnus does not properly manage server and group state.
+
+       * nnweb.el (nnweb-google-search): Respect nnweb-max-hits as upper
+       bound.
+
+2006-06-25  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * gnus.el (gnus-find-method-for-group): On killed/unknown groups, try
+       looking up the method using GROUP's prefix before inventing a new one.
+       It is used on killed/unknown groups in various places where returning
+       an all-new method isn't expected by the caller.
+
+       * gnus-util.el (gnus-group-server): Fix for empty virtual server names
+       and match semantics of gnus-group-real-prefix.
+
+2006-06-22  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnmail.el (nnmail-broken-references-mailers): New variable.
+       (nnmail-ignore-broken-references): New function generalizing
+       nnmail-fix-eudora-headers.
+       (nnmail-fix-eudora-headers): Now obsolete.
+
+       * gnus-art.el (gnus-button-handle-custom):
+       Support `customize-apropos*'.
+
+2006-06-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-hide-headers): Inhibit read-only stuff.
+
+       * gnus-group.el (gnus-fetch-group): Document ARTICLES and select those
+       articles.
+
+2006-06-21  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-cite-reply-above): New variable.
+       (message-yank-original): Use it.
+
+2006-06-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2231.el (rfc2231-parse-string): Allow `*'s in parameter values.
+
+2006-06-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-bookmark.el (gnus-bookmark-jump): Don't mark unrelated articles
+       as read.
+
+       * gnus-group.el (gnus-group-quick-select-group): Add GROUP argument.
+
+2006-06-19  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-bookmark.el: Fix Copyright, keywords, whitespace, etc.
+       (gnus-bookmark-default-file): Use gnus-directory.
+       (gnus-bookmark-bmenu-file-column, gnus-bookmark-use-annotations):
+       Remove "*" in doc string.
+       (gnus-bookmark-write-file): Simplify.
+       (gnus-bookmark-maybe-sort-alist): Use `when'.
+       (gnus-bookmark-get-bookmark): Fix typo in doc string.
+       (gnus-bookmark-set-bookmark-name, gnus-bookmark-get-bookmark):
+       Add FIXME about Emacs 21 and XEmacs compatibility.
+       (gnus-bookmark-set-bookmark-name): Use `gnus-replace-in-string' for
+       compatibility.
+       (gnus-bookmark-bmenu-mode): Use `gnus-run-mode-hooks' for
+       compatibility.
+       (gnus-bookmark-menu-heading): Fix version.
+
+2006-06-19  Bastien Guerry  <bzg@altern.org>
+
+       * gnus-bookmark.el: New file.
+
+2006-06-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-syntax-checks): Doc fix.
+
+2006-06-17  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * gnus-srvr.el (gnus-browse-unsubscribe-group): Don't subscribe
+       unsubscribed groups as if they were killed ones.  It causes duplicate
+       entries in gnus-newsrc-alist.
+
+2006-06-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-syntax-checks): Doc fix.
+       (message-send-mail): Add check for continuation headers.
+       (message-check-news-header-syntax): Fix regexp used to check for
+       continuation headers.
+
+2006-06-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-display-mime): Make sure body ends with newline.
+
+2006-06-11  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-article-toggle-truncate-lines): Fix code.
+
+2006-06-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-truncate-lines): Default to the value of
+       default-truncate-lines.
+
+2006-06-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-mime-mule-charset-alist): Use unicode-precedence-list
+       to fill the utf-8 entry.
+
+       * lpath.el: Fbind unicode-precedence-list.
+
+2006-06-01  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * nnweb.el (nnweb-google-parse-1): Update regexp for author and date.
+
+2006-05-30  Kevin Greiner  <kevin.greiner@compsol.cc>
+
+       * gnus-agent.el (directory-files-and-attributes): Move all the way
+       forward (the third and final move).
+       (gnus-agent-read-agentview): Trap reconstruction errors due to
+       nonexistent directory.  Handle by returning nil.
+
+2006-05-30  Didier Verna  <didier@xemacs.org>
+
+       * message.el (message-dont-reply-to-names): Update the custom type.
+       * message.el (message-dont-reply-to-names): New defsubst: potentially
+       convert a list of regexps into a single one.
+       * message.el (message-get-reply-headers): Use it.
+       * nnmail.el (nnmail-fancy-expiry-target): Ditto.
+
+2006-05-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-agent.el (directory-files-and-attributes): Move forward.
+
+2006-05-29  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-ml.el (gnus-mailing-list-subscribe)
+       (gnus-mailing-list-unsubscribe, gnus-mailing-list-owner)
+       (gnus-mailing-list-message): Fix doc strings.
+
+2006-05-29  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * gnus-ml.el (gnus-mailing-list-message): Use gnus-url-mailto instead
+       of doing it manually.
+
+2006-05-29  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-article-toggle-truncate-lines): Fix typo in
+       comment.
+
+2006-05-29  Kevin Greiner  <kevin.greiner@compsol.cc>
+
+       * gnus-agent.el: Add gnus-agent-flush* to purge agent info.
+       (gnus-agent-read-agentview): Fix handling of end-of-file error.
+       (gnus-agent-read-local): All symbols allocated in my-obarray.
+       (gnus-agent-set-local): Skip invalid entries (min and/or max is nil).
+       (gnus-agent-regenerate-group): Check numeric names to see if they are
+       messages or groups.
+       (gnus-agent-total-fetched-for): Ignore 'dummy.group' (there should be a
+       better way of do this...)
+
+       * gnus-cache.el (gnus-agent-total-fetched-for):
+       Ignore 'dummy.group' (there should be a better way of do this...)
+
+2006-05-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-save-all-headers): Mention it might be overridden.
+       (gnus-saved-headers): Ditto.
+       (gnus-default-article-saver): Mention functions may have properties.
+       (gnus-article-save): Override gnus-save-all-headers and
+       gnus-saved-headers by :headers property which saver function may have.
+       (gnus-summary-save-in-file): Add :headers property.
+       (gnus-summary-write-to-file): Ditto.
+
+       * gnus-sum.el (gnus-summary-save-article): Bind
+       gnus-prompt-before-saving to t when saving many articles in a file;
+       always show all headers.
+
+       * dgnushack.el: Autoload toggle-truncate-lines for XEmacs.
+
+2006-05-26  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * deuglify.el (gnus-outlook-rearrange-article): Add missing citation
+       marks.
+
+       * message.el (message-indent-citation): Add optional arguments to allow
+       using it outside of message buffers.
+
+       * gnus-art.el (gnus-article-unfold-long-headers): New variable.
+       (gnus-article-treat-unfold-headers): Use it.
+       (gnus-article-truncate-lines): New variable.
+       (gnus-article-mode): Use it.
+       (gnus-article-toggle-truncate-lines): New function.
+
+       * gnus-sum.el (gnus-summary-wash-map, gnus-summary-make-menu-bar):
+       Add gnus-article-toggle-truncate-lines.
+
+       * uudecode.el (uudecode-decode-region-external): nil isn't a valid
+       coding system in XEmacs, use binary.
+
+2006-05-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-enrich-utf-8-by-mule-ucs): Don't edit
+       after-load-alist.
+
+       * gnus-art.el (gnus-summary-save-in-file): Use property to specify
+       this function should save decoded articles.
+       (gnus-summary-write-to-file): Use property to specify this function
+       should save decoded articles and specify gnus-summary-save-in-file
+       should be used to save articles other than the first one when saving
+       many articles.
+       (gnus-summary-save-body-in-file): Use property to specify this
+       function should save decoded articles.
+       (gnus-summary-write-body-to-file): Use property to specify this
+       function should save decoded articles and specify
+       gnus-summary-save-body-in-file should be used to save articles other
+       than the first one when saving many articles.
+
+       * gnus-sum.el (gnus-summary-save-article): Simplify.
+
+2006-05-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-default-article-saver):
+       Add gnus-summary-write-body-to-file.
+       (gnus-article-save-coding-system): Don't use coding system object
+       in XEmacs.
+       (gnus-read-save-file-name): Add optional `dir-var' argument which
+       specifies directory in which files are saved; work even if optional
+       `variable' argument is not specified.
+       (gnus-summary-write-to-file): Read file name.
+       (gnus-summary-save-body-in-file): Add optional `overwrite' argument.
+       (gnus-summary-write-body-to-file): New function.
+
+       * gnus-sum.el (gnus-newsgroup-last-directory): New variable.
+       (gnus-summary-local-variables): Add it.
+       (gnus-summary-save-map): Add gnus-summary-write-article-body-file.
+       (gnus-summary-save-article): Remove optional `decode' argument;
+       determine whether to decode articles by the value of
+       gnus-default-article-saver; when saving many files using
+       gnus-summary-write-to-file or gnus-summary-write-body-to-file, use
+       it first and use gnus-summary-save-in-file or
+       gnus-summary-save-body-in-file thereafter unless
+       gnus-prompt-before-saving is always; move point to article which
+       will be saved.
+       (gnus-summary-save-article-file): Revert.
+       (gnus-summary-write-article-file): Revert.
+       (gnus-summary-save-article-body-file): Revert.
+       (gnus-summary-write-article-body-file): New function.
+
+2006-05-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-default-article-saver): Doc fix.
+       (gnus-article-save-coding-system): Move from gnus-sum.el, rename
+       from gnus-summary-save-article-coding-system, and default to a
+       certain coding system.
+       (gnus-output-to-file): Add coding cookie and encode text according
+       to gnus-article-save-coding-system; don't use mm-append-to-file.
+
+       * gnus-sum.el (gnus-summary-save-article-coding-system): Move to
+       gnus-art.el and rename to gnus-article-save-coding-system.
+       (gnus-summary-save-article): Require gnus-art; don't show all
+       headers if it decodes articles; don't add coding cookie here;
+       don't bind mm-text-coding-system-for-write.
+       (gnus-summary-save-article-file): Save decoded articles.
+       (gnus-summary-write-article-file): When saving many files, use
+       gnus-summary-write-to-file first and gnus-summary-save-in-file
+       thereafter unless gnus-prompt-before-saving is always.
+       (gnus-summary-save-article-body-file): Save decoded articles.
+
+       * lpath.el: Fbind select-safe-coding-system for XEmacs.
+
+2006-05-23  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnrss.el (nnrss-check-group): Bind hash-index.
+
+2006-05-23  Michaël Cadilhac  <michael.cadilhac@lrde.org>
+
+       * nnrss.el (nnrss-check-group): Use the md5sum of the whole RSS item as
+       its hash index.  Store this hash in `nnrss-group-data'.
+       (nnrss-read-group-data): Update accordingly.
+
+2006-05-23  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button-alist): Improve gnus-button-handle-symbol
+       entry.
+
+       * gnus-sum.el (gnus-summary-make-menu-bar):
+       Add gnus-article-browse-html-article.
+
+2006-05-23  Hynek Schlawack  <hynek@ularx.de>
+
+       * gnus-sum.el (gnus-summary-mime-map):
+       Add gnus-article-browse-html-article.
+
+       * gnus-art.el (gnus-article-browse-html-article): Remove comment.
+
+2006-05-23  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-summary-save-article-coding-system): Offer some
+       suitable coding systems in customize.
+
+2006-05-22  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mail-source.el (mail-sources): Fix custom type.
+
+2006-05-18  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-summary-save-article-mail): Clarify doc string.
+       (gnus-summary-expire-articles-now): Shorten prompt.
+
+       * gmm-utils.el (wid-edit): Require.
+       (defun-gmm): Rename from `gmm-defun-compat'.
+       (gmm-image-search-load-path): Use it.
+       (gmm-image-load-path-for-library): Use it.  Sync with `mh-compat.el'.
+
+2006-05-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-save-article-coding-system):
+       New variable.
+       (gnus-summary-save-article): Add optional `decode' argument.
+       If it is set and gnus-summary-save-article-coding-system is non-nil,
+       save decoded article.
+       (gnus-summary-write-article-file): Save decoded article if
+       gnus-summary-save-article-coding-system is non-nil.
+
+       * ecomplete.el (ecomplete-database-file-coding-system): Fix custom
+       type.
+
+2006-05-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (easy-menu-define): Use :active instead of :enable.
+
+2006-05-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-setup-buffer): Go to summary buffer
+       first to test gnus-single-article-buffer which may be buffer-local.
+
+       * gnus-sum.el (gnus-summary-setup-buffer):
+       Make gnus-single-article-buffer buffer-local and nil in ephemeral
+       group; make gnus-article-buffer, gnus-article-current, and
+       gnus-original-article-buffer always buffer-local.
+       (gnus-summary-exit): Kill article buffer belonging to ephemeral
+       group.
+       (gnus-handle-ephemeral-exit): Don't move to next summary line.
+
+2006-05-08  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnml.el (nnml-request-compact-group): Compressed files might not
+       have .gz extension.
+
+2006-05-04  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * mm-decode.el (mm-dissect-buffer): Remove spurious double assignment.
+       (mm-copy-to-buffer): Use with-current-buffer.
+       (mm-display-part): Simplify.
+       (mm-inlinable-p): Add optional arg `type'.
+
+2006-05-03  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-art.el (gnus-mime-view-part-as-type): Add optional PRED arg.
+       (gnus-mime-view-part-externally, gnus-mime-view-part-internally):
+       Try harder to show the attachment internally or externally using
+       gnus-mime-view-part-as-type.
+
+2006-05-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-from-style, message-signature-separator)
+       (message-user-organization-file, message-send-mail-function)
+       (message-citation-line-function, message-yank-prefix)
+       (message-indent-citation-function, message-signature)
+       (message-signature-file, message-signature-insert-empty-line):
+       Remove autoloads.
+
+       * gnus-art.el (gnus-buttonized-mime-types):
+       Remove "multipart/signed".  Revert 2006-04-26 change.
+
+2006-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Bump version.
+
+2006-05-01  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: No Gnus v0.5 is released.
+
+2006-04-30  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * nnweb.el (nnweb-request-article): Do proper xwfu encoding when
+       fetching articles by message-id.
+
+2006-04-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (hashcash): Require hashcash as normal.
+
+       * ecomplete.el (ecomplete-highlight-match-line):
+       Use point-at-eol.
+       (ecomplete-highlight-match-line): Use `highlight', because that
+       face exists in both Emacs and XEmacs.
+
+       * message.el (message-display-abbrev): Use point-at-bol.
+
+       * mail-source.el: Don't require timer/timer-funcs.
+
+       * gnus-async.el: Ditto.
+
+       * password.el: Ditto.
+
+       * nnheaderxm.el (nnheader-cancel-timer): Ditto.
+
+       * mm-url.el: Ditto.
+
+       * gnus-xmas.el: Don't require timer-funcs.
+
+       * mm-util.el: Require timer/timer-funcs.
+
+2006-04-23  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * mm-url.el (mm-url-insert-file-contents): Don't set Connection:
+       Close.
+
+2006-04-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-uu.el (mm-uu-pgp-encrypted-extract-1): Assume buffer is made
+       unibyte after clear-decrypt function runs.
+
+       * mml2015.el (mml2015-pgg-clear-decrypt): Treat data which pgg
+       returns as a unibyte string.
+
+2006-04-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Revert.
+
+       * pgg-gpg.el (pgg-string-to-multibyte): Remove.
+       (pgg-gpg-process-sentinel): Revert.
+
+       * pgg-pgp.el (pgg-pgp-process-region): Revert.
+       (pgg-pgp-lookup-key): Revert.
+
+       * pgg-pgp5.el (pgg-pgp5-process-region): Revert.
+       (pgg-pgp5-lookup-key): Revert.
+
+       * pgg.el (pgg-fetch-key): Revert.
+
+2006-04-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind string-as-multibyte for XEmacs.
+
+       * mml1991.el (mml1991-pgg-sign): No need to load pgg.el, which is
+       always loaded by way of gnus-art.el -> mm-uu.el -> mml2015.el.
+       (mml1991-pgg-encrypt): Ditto.
+
+       * pgg-gpg.el (pgg-string-to-multibyte): New function.
+       (pgg-gpg-process-sentinel): Make sure pgg-output-buffer is always
+       a multibyte buffer.
+
+       * pgg-pgp.el (pgg-pgp-process-region): Ditto.
+       (pgg-pgp-lookup-key): Ditto.
+
+       * pgg-pgp5.el (pgg-pgp5-process-region): Ditto.
+       (pgg-pgp5-lookup-key): Ditto.
+
+       * pgg.el (pgg-fetch-key): Ditto.
+
+2006-04-26  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-user-organization-file): Check several
+       locations of the organization file.
+
+       * gnus-sum.el (gnus-summary-mime-map, gnus-summary-make-menu-bar):
+       Add gnus-article-view-part-as-type.
+
+       * gnus-art.el (gnus-article-view-part-as-type): New function.
+
+       * message.el (message-valid-fqdn-regexp): Add TLDs .cat, jobs,
+       .mobi and .travel.  Remove .nato, .bitnet and .uucp.
+
+       * mml.el: Simplify autoload.
+       (mml-mode): defvar dnd-protocol-alist instead of using
+       symbol-value.
+       (mml-default-directory): New variable.
+       (mml-minibuffer-read-file): Use it.
+       (mml-dnd-protocol-alist, mml-dnd-attach-options): Adjust :version.
+
+       * message.el (message-citation-line-format): New variable.
+       (message-insert-formated-citation-line): New function.
+       (message-citation-line-function):
+       Add `message-insert-formated-citation-line' to custom type.
+
+       * mm-decode.el (mm-verify-option): Add gnus-buttonized-mime-types
+       to doc string.
+
+       * gnus-art.el (gnus-buttonized-mime-types): Add "multipart/signed"
+       depending on mm-verify-option.
+
+2006-04-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml1991.el (mml1991-pgg-sign): Make sure to load pgg.el before
+       binding pgg-* variables; reimplement the section which prevents
+       MIME header from being signed.
+       (mml1991-pgg-encrypt): Make sure to load pgg.el before binding
+       pgg-text-mode; remove a blank line at the top of body.
+
+       * mm-uu.el (mm-uu-pgp-encrypted-extract-1): Don't remove blank
+       lines at the top of body; use gnus-newsgroup-charset if there's no
+       Charset header.
+
+2006-04-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-self-insert-commands): Doc fix.
+
+       * mm-uu.el (mm-uu-pgp-signed-test): Erase prompt.
+       (mm-uu-pgp-encrypted-test): Ditto.
+       (mm-uu-pgp-encrypted-extract-1): Make sure there's a blank line
+       between header and body; return application/pgp-encrypted handle
+       if decryption failed; decode decrypted body by charset.
+
+       * mm-decode.el (mm-automatic-display): Don't make application/pgp
+       element match to application/pgp-*.
+
+2006-04-23  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * nnweb.el (nnweb-google-wash-article): Sync up to new Google
+       HTML.
+
+2006-04-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-call-script): Message the error
+       string.
+
+2006-04-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-util.el (gnus-byte-compile): Use it.
+
+2006-04-22  xyblor  <fake@invalid.email>  (tiny change)
+
+       * gnus-util.el (kill-empty-logs): New function.
+
+2006-04-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-mail-alias-type): Doc fix.
+       (message-mail-alias-type-p): New function.
+       (message-send): Use it.
+       (message-mode): Ditto.
+       (message-strip-forbidden-properties): Ditto.
+
+       * ecomplete.el (ecomplete-database-file-coding-system):
+       New variable.
+       (ecomplete-save): Use it.
+       (ecomplete-setup): Use it.
+
+2006-04-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-self-insert-commands): New variable.
+       (message-strip-forbidden-properties): Use it.
+
+2006-04-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-put-addresses-in-ecomplete): Use a regexp
+       that doesn't make XEmacs choke.
+
+2006-04-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-util.el (gnus-replace-in-string):
+       Prefer replace-regexp-in-string over of replace-in-string.
+
+2006-04-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-select-frame-set-input-focus):
+       Use select-frame-set-input-focus if it is available in XEmacs; use
+       definition defined in Emacs 22 for old Emacsen.
+
+       * dgnushack.el: Autoload unmorse-region for XEmacs.
+
+       * lpath.el: Bind cursor-in-non-selected-windows and
+       select-frame-set-input-focus for XEmacs.
+
+2006-04-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-view.el (mm-inline-text): Use equal instead of equalp.
+
+2006-04-18  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-cache-save): Remove text
+       properties when saving via the temp buffer.
+
+2006-04-18  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-generate-hashcash): Honor custom type.
+
+2006-04-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-generate-hashcash): Default to non-nil when
+       hashcash is found.
+
+       * gnus-sum.el (gnus-summary-expire-articles-now): Clarify prompt.
+       (gnus-refer-thread-limit): Increase default to 500.
+
+       * mm-view.el (mm-inline-text): Supply delsp to flow-fill.
+
+       * flow-fill.el (fill-flowed): Allow delete-space.
+
+2006-04-18  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * deuglify.el (gnus-outlook-deuglify-unwrap-min)
+       (gnus-outlook-deuglify-unwrap-max, gnus-outlook-display-hook):
+       Remove autoloads.
+
+2006-04-18  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-generate-hashcash): Default to.
+
+2006-04-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2231.el (rfc2231-parse-string): Decode encoded value after
+       concatenating segments rather than before concatenating them.
+
+2006-04-17  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-group.el: Move comment to gnus-group-update-tool-bar.
+
+2006-04-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * rfc2231.el (rfc2231-parse-string): Sort the parameters first.
+
+       * message.el (message-forward-make-body-plain):
+       Allow message-forward-ignored-headers to be a list.
+       (message-remove-ignored-headers): Factor out into function.
+       (message-forward-make-body-mml): Use it.
+
+       * imap.el (imap-quote-specials): New function.
+       (imap-login-auth): Quote specials.
+
+       * rfc2231.el (rfc2231-parse-string): Remove dead code.
+       (rfc2231-parse-string): Allow concatanation of parameters that
+       aren't contiguous.  The test case is
+         (mail-header-parse-content-type "message/external-body;
+           name*0*=us-ascii''~%2ffoo%2fbar%2fbaz%2fxyzzy%2f;
+           access-type=LOCAL-FILE;
+           name*1*=plugh%2fhello-sailor%2fbing.pdf")
+
+2006-04-17  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * nntp.el (nntp-accept-process-output): Return the value of
+       `nnheader-accept-process-output'.
+
+2006-04-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-treat-types): Add text/x-patch.
+       (gnus-button-alist): Recognize more diff formats.
+       (gnus-button-patch): Strip directory.
+
+2006-04-17  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-util.el (gnus-select-frame-set-input-focus): Check for
+       Emacs 22 when setting focus.
+
+2006-04-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-treat-types): Do treatment of
+       text/x-verbatim parts.
+       (gnus-button-patch): New command.
+
+       * ietf-drums.el (ietf-drums-parse-address): Attempt parsing
+       addresses that contain invalid characters.
+
+2006-04-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-put-addresses-in-ecomplete):
+       Use gnus-replace-in-string.
+       (message-is-yours-p): Use the more correct
+       mail-header-parse-address instead of
+       mail-extract-address-components.
+       (message-put-addresses-in-ecomplete): Fix typo.
+
+       * gnus-sum.el (gnus-summary-limit-to-bodies): New command and
+       keystroke.
+
+       * gnus-art.el (gnus-treatment-function-alist): Change order of
+       newsgroups/generic header folding to avoid double-folding.
+
+       * message.el (message-hidden-headers): Add X-Draft-From.
+
+       * gnus-sum.el (gnus-summary-repeat-search-article-forward):
+       New command.
+       (gnus-summary-repeat-search-article-backward): New command.
+
+       * gnus-topic.el (gnus-topic-display-missing-topic): Skip past
+       groups in the parent topic.
+
+2006-04-16  João Cachopo  <joao.cachopo@inesc-id.pt>  (tiny change)
+
+       * spam.el (spam-necessary-extra-headers): Add X-CRM114-Status.
+       (spam-extra-header-to-number): Return the CRM114 number as a
+       number instead of a string.
+
+2006-04-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-face-properties-alist): Move here from
+       gnus-fun.
+
+       * gnus-fun.el (gnus-face-properties-alist): Move to gnus-art.
+
+2006-04-15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-strip-forbidden-properties): Only display on
+       self-insert-command.
+
+       * hashcash.el (hashcash-insert-payment-async): Remove dead code;
+       reindent.
+       (hashcash-insert-payment-async-2): Make sure the buffer is alive.
+
+2006-04-15  NAKAJI Hiroyuki  <nakaji@takamatsu-nct.ac.jp>  (tiny change)
+
+       * smiley.el (smiley-style): Fix typo.
+
+2006-03-23  Kenichi Handa  <handa@m17n.org>
+
+       * rfc2231.el (rfc2231-encode-string): Use mm-disable-multibyte
+       instead of set-buffer-multibyte.
+
+2006-03-23  Kenichi Handa  <handa@m17n.org>
+
+       * rfc2231.el (rfc2231-decode-encoded-string): Work on unibyte
+       buffer and then decode the buffer text if necessary.
+       (rfc2231-encode-string): Be sure to work on multibyte buffer at
+       first, and after mm-encode-body, change the buffer to unibyte.
+
+2006-04-15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * hashcash.el (hashcash-insert-payment-async-2):
+       Use message-goto-eoh instead of doing it manually.
+       (mail-add-payment): Use message-narrow-to-header instead of trying
+       to do the same itself.
+
+       * message.el (message-hidden-headers): Add Face.
+
+       * gnus-sum.el (gnus-summary-reparent-thread): Factor out
+       reparenting code.
+       (gnus-summary-reparent-children): Refactored out code.
+       (gnus-summary-thread-map): New keystroke.
+       (gnus-summary-reparent-children): Make into command.
+
+       * smiley.el (smiley-style): Default to `medium' if using a large
+       font.
+
+       * gnus-sum.el (unmorse-region): Remove autoload, because morse.el
+       does it itself.
+
+       * message.el (message-point-in-header-p): Simplify definition.
+
+2006-04-14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnagent.el (nnagent-request-set-mark): Silence log file
+       writing.
+       (nnagent-request-set-mark): Use write-region instead of
+       append-to-file.
+
+       * gnus-sum.el (gnus-read-header): Fudge article number if using a
+       strange select method.
+
+       * ecomplete.el (ecomplete-display-matches): Get highlightling
+       right.
+       (ecomplete-display-matches): Use literals.
+       (ecomplete-display-matches): Disable message logging.
+
+       * message.el (message-display-abbrev): Small optimization.
+
+       * ecomplete.el (ecomplete-display-matches): Allow automatic
+       display.
+
+       * message.el (message-strip-forbidden-properties):
+       Display abbrevs.
+       (message-display-abbrev): Get automatic display right.
+
+       * ecomplete.el (ecomplete-display-matches): Use M-n/M-p
+       keystrokes.
+
+2006-04-13  Romain Francoise  <romain@orebokech.com>
+
+       TODO: Backport to v5-10!
+
+       * gnus-util.el (gnus-alist-to-hashtable, gnus-hashtable-to-alist):
+       Move here (and rename) from gnus-registry.el.
+
+       * gnus-registry.el: Require gnus-util.
+       Use `gnus-alist-to-hashtable' and `gnus-hashtable-to-alist'.
+
+2006-04-13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-catchup-current):
+       Change if-then-else-if-then-else into cond.
+       (gnus-group-catchup): Indent.
+       (group-name-at-point): New function.
+       (gnus-fetch-group): Provide default from thing at point.
+
+2006-04-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-display-abbrev): Fix regexp.
+
+       * ecomplete.el (ecomplete-highlight-match-line):
+       Reimplement choosing.
+       (ecomplete-highlight-match-line): Fix up code rewrite, remove
+       dead variables.
+
+       * message.el (message-newline-and-indent): Remove debugging.
+       (message-display-abbrev): Use new implementation.
+
+2006-04-12  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-article-mode):
+       Set cursor-in-non-selected-windows to nil.
+
+       * smiley.el: Revert previous change.
+       (smiley-data-directory): defvar it before using it in the
+       defcustom of `smiley-style'.
+
+2006-04-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-newline-and-indent): New function.
+
+       * ecomplete.el: Implement more bits.
+
+       * message.el (message-put-addresses-in-ecomplete): Clean up the
+       string.
+
+       * ecomplete.el (ecomplete-add-item): Chop off decimals.
+
+       * gnus-sum.el (gnus-summary-save-parts):
+       Bind gnus-summary-save-parts-counter and use it to make unique file
+       names.
+
+       * gnus-art.el (gnus-ignored-headers): Add some more headers.
+
+       * ietf-drums.el (ietf-drums-parse-addresses): Take a RAWP
+       parameter to say whether to actually parse the individual
+       addresses.
+
+       * message.el (message-put-addresses-in-ecomplete): New function.
+       (ecomplete): Require.
+       (message-mail-alias-type): Add ecomplete as an option.
+
+2006-04-12  Ralf Angeli  <angeli@iwi.uni-sb.de>
+
+       * flow-fill.el (fill-flowed): Remove trailing space from blank
+       quoted lines.
+
+2006-04-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * smiley.el (smiley-style): Move definition later to avoid a
+       compilation warning.
+
+2006-04-12  Kenichi Handa  <handa@m17n.org>
+
+       * rfc2231.el (rfc2231-decode-encoded-string): Work on unibyte
+       buffer and then decode the buffer text if necessary.
+       (rfc2231-encode-string): Be sure to work on multibyte buffer at
+       first, and after mm-encode-body, change the buffer to unibyte.
+       Use mm-disable-multibyte instead of set-buffer-multibyte.
+
+2006-04-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-copy-part): Find name parameter in
+       Content-Type header instead of Content-Disposition header.
+       (gnus-mime-inline-part): Ditto.
+       (gnus-mime-view-part-as-charset): Ignore charset that the part
+       specifies.
+
+       * mm-decode.el (mm-display-part): Work with external parts and
+       usual parts similarly.
+
+       * mm-extern.el (mm-inline-external-body): Use mm-display-part
+       instead of gnus-display-mime.
+
+       * mm-util.el (mm-decompress-buffer): Use mm-with-unibyte-buffer
+       instead of with-temp-buffer.
+
+       * gnus-uu.el (gnus-uu-save-article): Put mml tags instead of part
+       tag to summarized topics part in order to encode non-ASCII text.
+
+2006-04-11  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * smiley.el (smiley-style): New variable.
+       (smiley-directory): New function.
+       (smiley-data-directory): Derive from `smiley-style' using
+       `smiley-directory'.
+       (smiley-regexp-alist): Add new entries.
+
+       * gnus-art.el (gnus-button-valid-localpart-regexp): Exclude `@'.
+       (gnus-article-browse-delete-temp): Add :version.
+
+2006-04-11  Arne Jørgensen  <arne@arnested.dk>
+
+       * gnus-sieve.el (gnus-sieve-generate): Delete from the start of
+       the sieve region.
+
+2006-04-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Bump version.
+
+2006-04-11  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.el: No Gnus v0.4 is released.
+
+2006-04-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnslashdot.el (nnslashdot-retrieve-headers-1): Fix up to new
+       layout.
+
+       * rfc2047.el (rfc2047-decode-encoded-words): Don't message about
+       unknown charset.
+
+       * message.el (message-header-synonyms): Add Original-To to the
+       default.
+
+       * gnus-sum.el (gnus-get-newsgroup-headers-xover): group is an
+       optional parameter.
+
+2006-04-06  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-fun.el (gnus): Require it for gnus-directory.
+
+2006-04-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-fun.el (gnus-face-properties-alist): Add :version.
+
+2006-04-05  Daiki Ueno  <ueno@unixuser.org>
+
+       * pgg-gpg.el (pgg-gpg-process-filter): Fix.
+
+2006-04-05  Simon Josefsson  <jas@extundo.com>
+
+       * password.el (password-reset): New function.
+
+2006-04-05  Daiki Ueno  <ueno@unixuser.org>
+
+       * pgg-gpg.el (pgg-gpg-encrypt-region, pgg-gpg-sign-region):
+       Wait for BEGIN_SIGNING too, new in GnuPG 1.4.3.
+
+2006-04-04  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * nnweb.el (nnweb-google-create-mapping): Update regexp.
+       Some whitespace was matched into the url, which broke browsing hits
+       > 100 when mm-url-use-external was nil.
+
+2006-04-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-summary-from-or-to-or-newsgroups):
+       Check gnus-extra-headers for 'Newsgroups.
+
+       * message.el (message-tool-bar-gnome): Check if `flyspell-mode' is
+       bound.
+
+2006-04-04  Daiki Ueno  <ueno@unixuser.org>
+
+       * pgg-gpg.el: Clean up process buffers every time gpg processes
+       complete.
+
+2006-04-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-fun.el (gnus-convert-image-to-face-command): Fix typo in
+       doc string.
+
+2006-04-03  Daiki Ueno  <ueno@unixuser.org>
+
+       * pgg-gpg.el (pgg-gpg-process-filter)
+       (pgg-gpg-wait-for-completion): Check if buffer is alive.
+
+       * pgg-gpg.el (pgg-gpg-process-sentinel): Don't remove GNUPG:
+       lines, temporary fix.
+
+2006-03-31  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-group.el (gnus-group-update-tool-bar): Add :initialize and :set.
+
+2006-03-29  Daiki Ueno  <ueno@unixuser.org>
+
+       * pgg-gpg.el (pgg-gpg-start-process): Don't bind
+       default-enable-multibyte-characters.  This reverts the change from
+       revision 6.17 which is no longer necessary because the passphrase
+       is sent separately now.  GnuPG messages are unreadable under
+       multibyte locales with default-enable-multibyte-characters set to
+       nil.
+
+2006-03-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-tool-bar-gnome): Move "spell".
+
+2006-03-27  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-summary-from-or-to-or-newsgroups): Don't use
+       XEmacs-only `replace-in-string'.  Use `gnus-group-real-name'
+       instead.
+
+2006-03-27  Karl Kleinpaste  <karl@charcoal.com>
+
+       * gnus-sum.el (gnus-summary-from-or-to-or-newsgroups):
+       Improve newsgroups handling for NNTP overviews which don't include
+       Newsgroups.
+
+2006-03-26  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * message.el (message-resend): Bind message-generate-hashcash to nil.
+
+2006-03-26  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * hashcash.el (hashcash-already-paid-p): Bind case-fold-search
+       when searching for already-paid recipients.
+
+2006-03-27  Daiki Ueno  <ueno@unixuser.org>
+
+       * pgg-gpg.el: Invoke gpg asynchronous, to avoid querying for
+       passphrases when it is not needed.
+       (pgg-gpg-use-agent): Add, to hard code that pgg shouldn't wait for
+       passphrase stuff from gpg, should only be necessary when you use
+       gpg with a smartcard.
+
+2006-03-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml.el (mml-insert-mime): Ignore cached contents of
+       message/external-body part.
+
+       * mm-decode.el (mm-get-part): Add optional 'no-cache' argument.
+       (mm-insert-part): Ditto.
+
+2006-03-23  Simon Josefsson  <jas@extundo.com>
+
+       * pgg-gpg.el (pgg-gpg-update-agent): Add again, with fixes from
+       Reiner.
+       (pgg-gpg-use-agent-p): Use it again.
+
+2006-03-23  Simon Josefsson  <jas@extundo.com>
+
+       * pgg-gpg.el (pgg-gpg-update-agent): Remove, doesn't work with
+       older emacsen.
+       (pgg-gpg-use-agent-p): Don't use it.
+
+2006-03-23  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * pgg-gpg.el (pgg-gpg-update-agent): Only use make-network-process
+       if we can.
+
+2006-03-22  Sascha Wilde  <wilde@sha-bang.de>
+
+       * pgg-gpg.el (pgg-gpg-use-agent): Disable by default.
+       (pgg-gpg-update-agent): New function.
+       (pgg-gpg-use-agent-p): New function.
+       (pgg-gpg-process-region, pgg-gpg-encrypt-region)
+       (pgg-gpg-encrypt-symmetric-region, pgg-gpg-decrypt-region)
+       (pgg-gpg-sign-region): Use it.
+
+2006-03-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-map-articles): Don't funcall symbol macro.
+       Reported by Ralf Wachinger <rwachinger@gmx.de>.
+
+2006-03-21  Simon Josefsson  <jas@extundo.com>
+
+       * pgg-gpg.el: Ideas below based on patch from Sascha Wilde
+       <wilde@sha-bang.de>.
+       (pgg-gpg-use-agent): New variable.
+       (pgg-gpg-process-region): Use it.
+       (pgg-gpg-encrypt-region): Likewise.
+       (pgg-gpg-encrypt-symmetric-region): Likewise.
+       (pgg-gpg-decrypt-region): Likewise.
+       (pgg-gpg-sign-region): Likewise.
+       (pgg-gpg-possibly-cache-passphrase): Don't cache a nil password.
+
+2006-03-21  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-agent.el (gnus-agent-queue-mail): Fix custom tag for `t'.
+
+       * spam.el (spam-mark-new-messages-in-spam-group-as-spam):
+       Add comment on version.
+
+2006-03-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * smiley.el: Add missing test smiley.
+
+2006-03-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-with-part): New macro.
+       (mm-get-part): Use it; work with message/external-body as well.
+       (mm-save-part): Treat name and filename equally.
+
+       * mm-extern.el (mm-extern-cache-contents): New function.
+       (mm-inline-external-body): Use it; force the part to be displayed;
+       move undisplayer added to the cached handle to the parent.
+
+       * gnus-art.el (gnus-mime-save-part-and-strip): Add name parameter.
+       (gnus-mime-view-part-as-type): Work with message/external-body.
+
+       * gnus-util.el (gnus-tool-bar-update): Bind tool-bar-mode.
+
+2006-03-16  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gmm-utils.el (gmm-image-load-path-for-library): Prefer user's
+       images in image-load-path.  [Sync with image.el, revision 1.60, in
+       Emacs.]
+
+2006-03-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gmm-utils.el (gmm-image-load-path-for-library): Pass value of
+       path rather than symbol.  Always return list of directories.
+       Guarantee that image directory comes first.  [Sync with image.el,
+       revision 1.59, in Emacs.]
+
+       * message.el (message-make-tool-bar): Adjust to new API of
+       `gmm-image-load-path-for-library'.
+
+       * gnus-sum.el (gnus-summary-make-tool-bar): Ditto.
+
+       * gnus-group.el (gnus-group-make-tool-bar): Ditto.
+
+2006-03-15  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * gnus-art.el (gnus-article-only-boring-p):
+       Bind inhibit-point-motion-hooks to avoid infinite loop when entering
+       intangible text.
+       Reported by Ralf Wachinger <rwnewsmampfer@geekmail.de>.
+
+2006-03-14  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gmm-utils.el (gmm-image-load-path-for-library): Fix typo.
+       Use `defun' instead of `gmm-defun-compat'.
+
+2006-03-14  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-unique-id): Don't use message-number-base36
+       if (user-uid) is a float.
+       Reported by Bjorn Solberg <bjorn_ding1@hekneby.org>.
+
+2006-03-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-uu.el (mm-uu-dissect): Dissect all parts correctly.
+
+       * gnus-art.el (gnus-mime-display-single): Make sure there is an
+       empty line between a part and a message part.
+
+2006-03-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * smiley.el: Add more test smileys.
+       (smiley-data-directory, smiley-regexp-alist)
+       (gnus-smiley-file-types): Fix doc strings.
+       (smiley-update-cache): Clear smiley-cached-regexp-alist before
+       adding new elements.
+       (smiley-mouse-map): Unused code.  Make it a comment.
+
+2006-03-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-nocem.el (gnus-nocem-scan-groups): Add autoload cookie;
+       scan latest NoCeM messages instead of old ones.
+       (gnus-nocem-check-article): Fix regexps so as to match to PGP
+       delimiters that are recently used.
+       (gnus-nocem-load-cache): Add autoload cookie.
+
+       * gnus.el (gnus-use-nocem): Enable it to be set to also a number.
+
+       * gnus-start.el (gnus-setup-news): Scan NoCeM messages if a group
+       level which is larger than gnus-use-nocem is specified.
+
+       * gnus-group.el (gnus-group-get-new-news): Ditto.
+
+2006-03-08  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-util.el (gnus-tool-bar-update): New function.
+
+       * gnus-group.el (gnus-group-update-tool-bar): New variable.
+       (gnus-group-insert-group-line): Add gnus-tool-bar-update.
+
+       * gnus-topic.el (gnus-topic-prepare-topic): Add gnus-tool-bar-update.
+
+       * gnus-group.el (gnus-group-redraw-when-idle)
+       (gnus-group-redraw-check): Remove.
+       (gnus-group-make-tool-bar): Remove gnus-group-redraw-check.
+
+2006-03-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnmail.el (nnmail-split-it): Invert match-partial-words behavior
+       if optional last element is specified in splits (FIELD VALUE...).
+
+2006-03-07  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-make-tool-bar): Rename gmm-image-load-path
+       to gmm-image-load-path-for-library.  Call with no-error argument.
+       (message-tool-bar-gnome): Rename "mail/attach" to "attach".
+
+       * gnus-sum.el (gnus-summary-make-tool-bar): Ditto.
+
+       * gnus-group.el (gnus-group-make-tool-bar): Ditto.
+
+       * gmm-utils.el (gmm-image-load-path): Remove alias.
+
+2006-03-06  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gmm-utils.el (gmm-image-load-path): Add alias.
+
+       * nnml.el (nnml-generate-nov-databases-directory): Rename from
+       nnml-generate-nov-databases-1.
+       (nnml-generate-nov-databases): Use it.
+       (nnml-generate-nov-databases-directory): Document no-active
+       argument.
+
+       * gmm-utils.el (gmm-image-load-path-for-library): Return single
+       directory if path is t.  Add no-error.
+
+       * gnus-group.el (gnus-group-make-tool-bar): Use add-hook.
+       Suggested by Stefan Monnier <monnier@iro.umontreal.ca>.
+
+       * gnus-art.el (gnus-article-browse-delete-temp-files):
+       Simplify resetting gnus-article-browse-html-temp-list.
+
+       * gmm-utils.el (gmm-image-load-path-for-library): Sync with
+       mh-compat.el revision 1.9 in Emacs.  Rename `gmm-image-load-path'.
+       Add example to docstring.  Rename local variables.  Move error
+       checks to default case in cond and simplify.
+
+2006-03-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-view.el (mm-w3m-cid-retrieve-1): Check carefully whether
+       handle is multipart when calling it recursively.
+       (mm-w3m-cid-retrieve): Display warning if retrieving fails.
+
+2006-03-03  Daniel Pittman  <daniel@rimspace.net>
+
+       * nnimap.el (nnimap-request-update-info-internal): Optimize.
+       Don't `gnus-uncompress-range' to avoid excessive memory usage.
+
+2006-03-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el (gnus-group-tool-bar-gnome): Check if gnus-topic.el
+       is loaded.
+
+       * gnus-sum.el (gnus-summary-tool-bar-gnome): Check if spam.el is
+       loaded.
+
+2006-03-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-util.el (mm-with-unibyte-current-buffer): Change "Emacs 23"
+       to "Emacs 23 (unicode)" in doc string.
+
+       * gnus-sum.el (gnus-summary-set-display-table): Change "Emacs 23" to
+       "Emacs 23 (unicode)" in comment.
+
+2006-03-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-get-part): Don't use mm-with-unibyte-current-buffer.
+
+       * gnus-sum.el (gnus-summary-set-display-table): Don't nix out
+       characters 160 through 255 in Emacs 23.
+
+2006-03-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-article-browse-html-temp-list): Rename from
+       gnus-article-browse-html-temp.
+       (gnus-article-browse-delete-temp): Make it customizable.
+       Add `file'.  Adjust doc string.
+       (gnus-article-browse-delete-temp-files): Add argument.
+       Allow query for each file.  Adjust doc string.
+       (gnus-article-browse-html-parts):
+       Add `gnus-article-browse-delete-temp-files' to
+       `gnus-summary-prepare-exit-hook' and `gnus-exit-gnus-hook'.
+
+2006-03-02  Hynek Schlawack  <hynek@ularx.de>
+
+       * gnus-art.el (gnus-article-browse-html-temp)
+       (gnus-article-browse-delete-temp): New variables.
+       (gnus-article-browse-delete-temp-files): New function.
+       (gnus-article-browse-html-parts): Use it.
+
+2006-03-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-group.el (gnus-group-redraw-check): Remove redundant tests.
+
+       * gmm-utils.el (gmm-image-load-path): Mention ../etc search in doc
+       string.
+
+       * gnus-sum.el (gnus-summary-tool-bar-gnome): Don't use
+       gnus-summary-insert-new-articles when unplugged.
+       Remove gnus-summary-search-article-forward.
+
+       * gmm-utils.el (gmm-tool-bar-style): Test tool-bar-mode and
+       display-visual-class instead of display-color-cells.
+
+2006-03-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el: Autoload customize-group for XEmacs.
+
+       * mml.el (mml-generate-mime-1): Encode parts other than text/* or
+       message/* containing non-ASCII text properly.
+
+2006-03-01  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el: Require gmm-utils, remove autoloads.
+       (message-tool-bar): Set default based on
+       gmm-tool-bar-style.
+       (message-tool-bar-gnome): Add gmm-customize-mode.
+
+       * gnus-sum.el (gnus-summary-tool-bar): Set default based on
+       gmm-tool-bar-style.
+       (gnus-summary-tool-bar-gnome): Add gmm-customize-mode.
+
+       * gnus-group.el (gnus-group-tool-bar): Set default based on
+       gmm-tool-bar-style.
+       (gnus-group-tool-bar-gnome): Add gmm-customize-mode.
+
+       * gmm-utils.el (gmm-image-directory): Rename variable from
+       gmm-image-load-path.
+       (gmm-image-load-path): Use gmm-image-directory.
+       (gmm-customize-mode): New function.
+       (gmm-tool-bar-style): New variable.
+
+       * gnus-group.el (gnus-group-redraw-when-idle): Rename from
+       gnus-group-redraw-line-number.
+       (gnus-group-redraw-check): Simplify.
+       (gnus-group-tool-bar-update): Remove redraw check.
+       (gnus-group-make-tool-bar): Add redraw check.
+
+2006-03-01  Michael Piotrowski  <mxp@dynalabs.de>  (tiny change)
+
+       * gnus-art.el (gnus-button): Add missing parentheses.
+
+2006-03-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind line-number-at-pos.
+
+2006-02-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-with-unibyte-current-buffer): Add note.
+
+2006-02-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button): New face.
+       (gnus-article-button-face): Use it.
+
+       * gnus-sum.el (gnus-summary-tool-bar-gnome):
+       Add gnus-summary-next-page.  Re-order.
+
+       * gnus-group.el (gnus-group-tool-bar-gnome): prev-node and
+       next-node are now included.
+       (gnus-group-redraw-line-number): New internal variable.
+       (gnus-group-redraw-check): Helper function for updating the tool
+       bar.
+       (gnus-group-tool-bar-update): Add gnus-group-redraw-check.
+
+       * gmm-utils.el (gmm-tool-bar-item): Add TODO about modifiers.
+
+       * spam.el (spam-spamassassin-score-regexp): New internal variable.
+       (spam-extra-header-to-number, spam-check-spamassassin-headers):
+       Use it to match format of Spamassassin 3.0 and later.
+       Reported by IRIE Tetsuya <irie@t.email.ne.jp>.
+       (spam-check-bogofilter)
+       (spam-bogofilter-register-with-bogofilter): Fix args of
+       `gnus-error' calls.
+
+2006-02-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-draft.el (gnus-draft-send): Bind message-signature to avoid
+       unnecessary interaction when sending queued mails.
+       Reported by TAKAHASHI Yoshio <tkh@jp.fujitsu.com>.
+
+2006-02-27  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-sequence-of-unread-articles): Return nil if
+       first or last are nil.
+
+2006-02-24  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * nnweb.el (nnweb-gmane-create-mapping): Don't choke on ^M.
+
+2006-02-24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-int.el (gnus-open-server): Respect gnus-batch-mode.
+
+2006-02-24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * dns.el (query-dns): Protect more against buggy tcp output.
+
+2006-02-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnweb.el (nnweb-type-definition, nnweb-gmane-search): Use new
+       nov.php.
+
+2006-02-24  Andreas Seltenreich  <uwi7@stud.uni-karlsruhe.de>
+
+       * nnweb.el (nnweb-type-definition, nnweb-gmane-create-mapping)
+       (nnweb-gmane-wash-article, nnweb-gmane-search): Fix Gmane web
+       groups.  Kudos to Olly Betts <olly@survex.com> for providing NOV
+       output on the server side.
+       (nnweb-google-create-mapping): Update regexps and add some
+       progress indication.
+
+2006-02-23  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-group.el (gnus-group-tool-bar-gnome):
+       Fix gnus-agent-toggle-plugged.  Re-order icons.
+       (gnus-group-tool-bar-gnome):
+       Add gnus-group-{prev,next}-unread-group.
+       (gnus-group-tool-bar-gnome): Re-order icons.
+
+       * gnus-sum.el (gnus-summary-tool-bar-gnome):
+       Move gnus-summary-insert-new-articles.
+
+       * message.el (message-tool-bar-gnome, message-tool-bar-retro):
+       Fix comments.
+
+       * utf7.el (utf7-utf-16-coding-system): Fix comment.  utf-16-be is
+       also available in Emacs 21.3.
+
+       * message.el (message-fix-before-sending): Change "Emacs 22" to
+       "Emacs 23 (unicode)" in comment.
+
+       * qp.el (quoted-printable-encode-region): Change "Emacs 22" to
+       "Emacs 23 (unicode)" in comment.
+
+       * mm-util.el: Change "Emacs 22" to "Emacs 23 (unicode)" in
+       comment.
+       (mm-coding-system-p): Add comment about no-MULE XEmacs.
+
+       * mm-view.el (mm-fill-flowed): Add :version.
+
+2006-02-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gmm-utils.el (gmm-image-load-path): Don't modify image-load-path
+       and load-path.
+
+2006-02-22  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el: Autoload gmm-image-load-path.
+       (message-tool-bar-retro): Prepend "gnus/" subdirectory to some
+       icon file names.  Use old Emacs 21 "mail_send.xpm" icon for
+       consitency.
+
+       * gmm-utils.el (gmm-image-load-path): Also search in
+       "../etc/images".  Don't set gmm-image-load-path if we don't find
+       the image.
+
+2006-02-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gmm-utils.el (gmm-image-load-path): Don't make
+       `gmm-image-load-path' include subdirectories which the second arg
+       `image' might specify.
+
+       * gnus-group.el (gnus-group-tool-bar-retro): Prepend the "gnus/"
+       subdirectory to icon file names.
+
+       * gnus-sum.el (gnus-summary-tool-bar-retro): Ditto.
+
+2006-02-21  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-group.el (gnus-group-make-tool-bar): Add IMAGE argument to
+       gmm-image-load-path calls.
+
+       * gnus-sum.el (gnus-summary-make-tool-bar): Ditto.
+
+       * message.el (message-make-tool-bar): Ditto.
+
+       * mml.el (mml-preview): Add comment concerning tool bar icons.
+
+       * gnus-group.el (gnus-group-tool-bar-gnome): Use new icon names.
+       (gnus-group-make-tool-bar): Use `gmm-image-load-path'.
+
+       * gnus-sum.el (gnus-summary-tool-bar-gnome): Use new icon names.
+       (gnus-summary-make-tool-bar): Use `gmm-image-load-path'.
+
+       * message.el (message-tool-bar-gnome): Use new icon names.
+       (message-make-tool-bar): Use `gmm-image-load-path'.
+
+       * gmm-utils.el (gmm-defun-compat, gmm-image-search-load-path):
+       New functions from MH-E.
+       (gmm-image-load-path): New variable from MH-E.
+       (gmm-image-load-path): New function from MH-E.  Add arguments
+       LIBRARY, IMAGE and PATH.  Don't modify paths.  Don't use
+       *-image-load-path-called-flag.
+
+2006-02-21  Milan Zamazal  <pdm@brailcom.org>
+
+       * mm-view.el (mm-view-pkcs7-verify): Implement using smime.el.
+
+2006-02-21  Wolfram Fenske  <wolfram.fenske@student.uni-magdeburg.de>  (tiny change)
+
+       * nnimap.el (nnimap-request-move-article): Change folder back to
+       source group before deleting.
+
+2006-02-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-util.el (mm-charset-override-alist): Fix type in doc string.
+
+       * gnus-art.el (mm-url-insert-file-contents-external):
+       Autoload mm-url.
+
+       * mm-uu.el (mm-uu-type-alist): Improve `LaTeX'.
+
+2006-02-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-charset-to-coding-system): Don't check the
+       coding system which mm-charset-to-coding-system returns for a
+       given charset is valid.
+
+2006-02-16  Juanma Barranquero  <lekktu@gmail.com>
+
+       * html2text.el (html2text-remove-tag-list):
+       * spam-stat.el (spam-stat-buffer-words): Fix typo in docstring.
+
+2006-02-14  Chong Yidong  <cyd@stupidchicken.com>
+
+       * gnus-cus.el: Revert 2005-10-17 change.
+
+2006-02-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-strip-banner):
+       Call article-really-strip-banner only when the regexp match is made.
+
+2006-02-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-strip-banner):
+       Use gnus-extract-address-components instead of
+       mail-header-parse-addresses to make it work with non-ASCII text;
+       remove mail-encode-encoded-word-string.
+
+       * rfc2231.el (rfc2231-parse-string): Attempt to parse parameter
+       values which are surrounded with \"...\"; make it never cause a
+       Lisp error; give up parsing of parameters if it failed in
+       extracting type.
+
+2006-02-14  Arne Jørgensen  <arne@arnested.dk>
+
+       * smime.el (smime-cert-by-ldap-1): Fix bug where
+       `smime-ldap-search' returns results without userCertificates.
+
+2006-02-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-make-temp-file): Don't catch file-error in Emacs.
+
+2006-02-14  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * spam.el (spam-check-spamassassin-headers): Adapt format for
+       Spamassassin 3.0 or later.  Reported by ARISAWA Akihiro
+       <ari@mbf.ocn.ne.jp>.
+       (spam-list-of-processors): Add spam-use-gmane.
+
+2006-02-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-make-temp-file): Import the Emacs 22 version of
+       make-temp-file; make it work with XEmacs as well.
+
+       * gnus-art.el (gnus-article-browse-html-parts): Use the 3rd arg of
+       mm-make-temp-file.
+
+       * mm-decode.el (mm-display-external): Use the 3rd arg of
+       mm-make-temp-file.
+       (mm-create-image-xemacs): Ditto.
+
+2006-02-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-draft.el (gnus-draft-send): Replace message-narrow-to-head
+       with message-narrow-to-headers.
+       (gnus-draft-setup): Narrow to header to run message-fetch-field.
+       (gnus-draft-check-draft-articles): New function.
+       (gnus-draft-edit-message, gnus-draft-send-message): Use it.
+
+2006-02-13  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-article-browse-html-parts):
+       `hs-show-html-list' should read `gnus-article-browse-html-parts'.
+       Don't use suffix argument for mm-make-temp-file for Emacs 21
+       compatibility.  Remove useless `format'.
+
+2006-02-13  Andreas Seltenreich  <uwi7@stud.uni-karlsruhe.de>
+
+       * nnweb.el (nnweb-google-wash-article): Update regexps.
+       (nnweb-group-alist): Use defvoo instead of defvar.
+
+2006-02-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnoo.el (nnoo-declare): Don't generate duplicate entries when
+       re-loading nn* modules.
+
+2006-02-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-group.el (gnus-group-make-tool-bar): Remove duplicate check
+       for `tool-bar-mode' and don't check it's default-value.
+
+       * gnus-sum.el (gnus-summary-make-tool-bar): Ditto.
+
+       * message.el (message-make-tool-bar): Ditto.
+
+       * gnus-art.el (gnus-article-browse-html-parts): Remove useless
+       `substring'.  Shorten tmp-file name.
+
+       * gnus.el: Remove bogus comment.
+
+2006-02-10  Hynek Schlawack  <hynek@ularx.de>
+
+       * gnus-art.el (gnus-article-browse-html-parts): New function.
+       (gnus-article-browse-html-article): New function for viewing html
+       articles with a browser.
+
+2006-02-09  Daiki Ueno  <ueno@unixuser.org>
+
+       * pgg-gpg.el (pgg-gpg-encrypt-region): Don't convert line-endings
+       in elisp.
+       (pgg-gpg-encrypt-symmetric-region): Ditto.
+       (pgg-gpg-sign-region): Ditto.
+
+       * pgg-def.el (pgg-text-mode): New variable.
+
+       * mml2015.el (mml2015-pgg-sign): Enable pgg-text-mode.
+       (mml2015-pgg-encrypt): Ditto.
+
+       * mml1991.el (mml1991-pgg-sign): Enable pgg-text-mode.
+       (mml1991-pgg-encrypt): Ditto.
+
+2006-02-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnfolder.el (nnfolder-insert-newsgroup-line):
+       Use message-make-date instead of current-time-string.
+
+       * mm-view.el (mm-inline-message): Don't set gnus-newsgroup-charset
+       to gnus-decoded which mm-uu might set.
+
+2006-02-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2231.el (rfc2231-parse-string): Sort segmented parameters;
+       don't decode quoted parameters; remove misimported Emacs code.
+       Suggested by ARISAWA Akihiro <ari@mbf.ocn.ne.jp>.
+       (rfc2231-decode-encoded-string): Don't use split-string which
+       behaves differently according to Emacs version; use
+       mm-decode-coding-region to convert charset to coding-system.
+       Suggested by ARISAWA Akihiro <ari@mbf.ocn.ne.jp>.
+       (rfc2231-encode-string): Remove misimported Emacs code.
+
+2006-02-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-decode-charset): Don't use ignore-errors
+       when calling mail-header-parse-content-type.
+       (article-de-quoted-unreadable): Ditto.
+       (article-de-base64-unreadable): Ditto.
+       (article-wash-html): Ditto.
+
+       * mm-decode.el (mm-dissect-buffer): Don't use ignore-errors when
+       calling mail-header-parse-content-type and
+       mail-header-parse-content-disposition.
+       (mm-find-raw-part-by-type): Don't use ignore-errors when calling
+       mail-header-parse-content-type.
+
+       * mml.el (mml-insert-mime-headers): Use mml-insert-parameter to
+       insert charset and format parameters; encode description after
+       inserting it to buffer.
+       (mml-insert-parameter): Fold lines properly even if a parameter is
+       segmented into two or more lines; change the max column to 76.
+
+       * rfc1843.el (rfc1843-decode-article-body): Don't use
+       ignore-errors when calling mail-header-parse-content-type.
+
+       * rfc2231.el (rfc2231-parse-string): Return at least type if
+       possible; don't cause an error even if it fails in parsing of
+       parameters.  Suggested by ARISAWA Akihiro <ari@mbf.ocn.ne.jp>.
+       (rfc2231-encode-string): Don't break lines at the beginning, leave
+       it to mml-insert-parameter.
+
+       * webmail.el (webmail-yahoo-article): Don't use ignore-errors when
+       calling mail-header-parse-content-type.
+
+2006-02-06  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * spam-report.el (spam-report-gmane-use-article-number):
+       Improve doc string.
+       (spam-report-gmane-internal): Check if a suitable header was found
+       in the article.
+
+2006-02-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2231.el (rfc2231-parse-string): Revert 2006-02-03 change.
+       (rfc2231-encode-string): Make param*=value always begin with LWSP.
+
+2006-02-05  Romain Francoise  <romain@orebokech.com>
+
+       Update copyright notices of all files in the gnus directory.
+
+2006-02-03  Andreas Seltenreich  <uwi7@stud.uni-karlsruhe.de>
+
+       * nnweb.el (nnweb-request-group): Avoid growing overview files.
+
+2006-02-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2231.el (rfc2231-parse-string): Add missing semicolons to
+       segmented lines of parameter value to cope with Thunderbird 1.5
+       bug (cf. https://bugzilla.mozilla.org/show_bug.cgi?id=323318).
+       Suggested by ARISAWA Akihiro <ari@mbf.ocn.ne.jp>.
+       (rfc2231-encode-string): Don't make lines exceeding 76 column.
+
+2006-02-01  Max Froumentin  <max@lapin-bleu.net>  (tiny change)
+
+       * mml.el (mml-generate-mime-1): Correct the order of inline signed
+       parts.
+
+2006-01-31  Andreas Seltenreich  <uwi7@stud.uni-karlsruhe.de>
+
+       * nnweb.el (nnweb-group-alist): Use defvar instead of defvoo,
+       there's only one active file for all servers.
+       (nnweb-request-scan): Make sure nnweb-articles is initialized on
+       solid groups.  Gnus might have used a FAST request to select the group.
+       (nnweb-request-group, nnweb-google-parse-1): Don't keep nnweb-type
+       and nnweb-search redundantly in the active file.
+       (nnweb-request-list): Don't list bogus groups.  There can only be one.
+       (nnweb-request-create-group): Don't use ARGS.
+       (nnweb-possibly-change-server, nnweb-request-group): Remove some
+       initializations.  Let nnoo do the work.
+
+2006-01-31  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-uu.el (mm-uu-emacs-sources-extract, mm-uu-diff-extract):
+       Say the part has been decoded.
+
+       * mm-view.el (mm-display-inline-fontify): Get decoded part rightly.
+
+2006-01-31  Kevin Ryde  <user42@zip.com.au>
+
+       * mailcap.el (mailcap-viewer-passes-test): Don't put "(nil t)" into
+       mailcap-viewer-test-cache when there's no 'test clause, since that
+       will invert the meaning of a "nil" test previously determined by
+       mailcap-mailcap-entry-passes-test.
+
+2006-01-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el: Bind tool-bar-mode instead of tool-bar-map when
+       compiling.
+
+       * gnus-sum.el: Ditto.
+
+       * message.el: Don't bind tool-bar-map when compiling.
+
+2006-01-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnweb.el (nnweb-google-parse-1): Clarify some comments.
+
+2006-01-30  Andreas Seltenreich  <uwi7@stud.uni-karlsruhe.de>
+
+       * nnweb.el (nnweb-type-definition, nnweb-google-parse-1)
+       (nnweb-google-create-mapping, nnweb-google-search): Adapt to
+       current Google Groups.
+
+2006-01-26  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-summary-make-tool-bar): Add checks for XEmacs
+       and tool-bar-mode.
+
+       * gnus-group.el (gnus-group-make-tool-bar): Add checks for XEmacs
+       and tool-bar-mode.
+
+       * message.el (message-tool-bar-update): Simplify.
+       (message-make-tool-bar): Add checks for XEmacs and tool-bar-mode.
+
+       * gnus-sum.el (gnus-summary-tool-bar-update): Check for
+       gnus-summary-buffer.
+       (gnus-summary-tool-bar-gnome): Use "reply-author" icon for
+       gnus-summary-reply.
+
+       * gmm-utils.el (gmm): Add :version.
+
+2006-01-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * Makefile.in (clean): New rule.
+       (distclean): Use it.
+
+2006-01-26  Steve Youngs  <steve@sxemacs.org>
+
+       * gmm-utils.el (gmm-tool-bar-item, gmm-tool-bar-zap-list):
+       Don't autoload.
+
+2006-01-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gmm-utils.el (gmm-verbose): Add :group.
+
+2006-01-25  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el: Change some comments WRT tool-bars.
+
+       * gnus-sum.el (gnus-summary-tool-bar)
+       (gnus-summary-tool-bar-gnome, gnus-summary-tool-bar-retro)
+       (gnus-summary-tool-bar-zap-list): New variables.
+       (gnus-summary-make-tool-bar): Complete rewrite using
+       `gmm-tool-bar-from-list'.
+
+       * gnus-group.el (gnus-group-tool-bar, gnus-group-tool-bar-gnome)
+       (gnus-group-tool-bar-retro, gnus-group-tool-bar-zap-list):
+       New variables.
+       (gnus-group-make-tool-bar): Complete rewrite using
+       `gmm-tool-bar-from-list'.
+       (gnus-group-tool-bar-update): New function.
+
+       * message.el (message-mode-field-menu): Add "Show hidden Headers".
+
+2006-01-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-uu.el (mm-uu-dissect-text-parts): Ignore it if a given part
+       is dissected into a single part of which the type is the same as
+       the given one; decode charset.
+
+2006-01-21  Kevin Ryde  <user42@zip.com.au>
+
+       * mailcap.el (mailcap-parse-mailcap-extras): "test" key must go
+       into alists as symbol not string, since that's what
+       mailcap-viewer-passes-test and mailcap-mailcap-entry-passes-test
+       look for.
+
+2006-01-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gmm-utils.el (gmm-tool-bar-item): Add "Separator".
+       (gmm-tool-bar-from-list): Suppress tooltip for `gmm-ignore'.
+
+       * message.el (message-tool-bar-gnome): Use gmm-ignore.
+
+2006-01-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-xmas.el (gnus-mime-security-button-menu): New alias.
+       (gnus-xmas-mime-security-button-menu): New function.
+
+       * gnus-art.el (gnus-mime-security-button-commands): New variable.
+       (gnus-mime-security-button-menu): New definition.
+       (gnus-mime-security-button-map): Use them.
+       (gnus-mime-security-button-menu): New function.
+       (gnus-insert-mime-security-button): Addition to help echo.
+       (gnus-mime-security-run-function, gnus-mime-security-save-part)
+       (gnus-mime-security-pipe-part): New functions.
+
+       * mm-uu.el (mm-uu-buttonize-original-text-parts): Remove.
+       (mm-uu-dissect-text-parts): Revert a part of 2006-01-23 change.
+
+       * mm-decode.el (mm-handle-set-disposition): Remove.
+       (mm-handle-set-description): Remove.
+
+2006-01-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-view.el (mm-w3m-standalone-supports-m17n-p): New variable.
+       (mm-w3m-standalone-supports-m17n-p): New function.
+       (mm-inline-text-html-render-with-w3m-standalone): Use it to alter
+       w3m usage.
+
+       * gnus-art.el (gnus-article-wash-html-with-w3m-standalone):
+       Use mm-w3m-standalone-supports-m17n-p to alter w3m usage.
+
+2006-01-23  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-tool-bar-zap-list):
+       Use gmm-tool-bar-zap-list as custom type.
+       (message-tool-bar-update): New function.
+       (message-tool-bar, message-tool-bar-gnome)
+       (message-tool-bar-retro): Add message-tool-bar-update.
+       (message-tool-bar-gnome): Add flyspell-buffer.
+
+       * gnus-util.el (gnus-error): Describe `args'.
+
+       * gmm-utils.el (gmm-error): Describe `args'.
+       (gmm-tool-bar-zap-list): New widget.
+       (gmm-tool-bar-from-list): Improve description of `zap-list'.
+
+2006-01-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-uu.el (mm-uu-buttonize-original-text-parts): New variable.
+       (mm-uu-dissect-text-parts): Buttonize original text parts; reduce
+       the number of recursive calls.
+
+       * mm-decode.el (mm-handle-set-disposition): New macro.
+       (mm-handle-set-description): New macro.
+
+2006-01-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-uu.el (mm-uu-dissect-text-parts): Decode content transfer
+       encoding.
+
+2006-01-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-tool-bar-zap-list, message-tool-bar)
+       (message-tool-bar-gnome, message-tool-bar-retro): New variables.
+       (message-tool-bar-local-item-from-menu): Remove.
+       (message-tool-bar-map): Replace by `message-make-tool-bar'.
+       (message-make-tool-bar): New function.
+       (message-mode): Use `message-make-tool-bar'.
+
+       * gmm-utils.el: New file.
+       (gmm-verbose, gmm-message, gmm-error): From gnus-utils.el.
+       (gmm-lazy): New widget copied from `nnmail.el'.
+       (gmm-tool-bar-from-list): New function for creating customizable
+       tool bars.
+       (gmm-tool-bar-from-list): Fix typos in doc string.  Remove debug
+       output.
+       (gmm): Add :prefix to defgroup.
+
+2006-01-20  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gmm-utils.el (gmm-widget-p): New function.
+
+2006-01-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mml.el (mml-attach-file): Describe `description' in doc string.
+       (mml-menu): Add Emacs MIME manual and PGG manual.
+
+2006-01-20  Richard M. Stallman  <rms@gnu.org>
+
+       * mm-url.el (mm-url-load-url): Require url-parse and url-vars.
+
+2006-01-20  Kevin Greiner  <kevin.greiner@compsol.cc>
+
+       * nntp.el (nntp-end-of-line): Doc fix.
+
+2006-01-20  Chong Yidong  <cyd@stupidchicken.com>
+
+       * imap.el (imap-open): Handle case where buffer is a buffer
+       object.
+
+2005-01-20  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-delay.el (gnus-delay): Don't autoload.
+       It's useless and could trigger a bug in cus-dep.el causing ldefs-boot
+       to be re-loaded when customizing the `gnus-delay' group.
+
+2005-01-20  Chong Yidong  <cyd@stupidchicken.com>
+
+       * message.el (message-insert-citation-line): Use newlines.
+
+2006-01-19  Ken Manheimer  <ken.manheimer@gmail.com>
+
+       * pgg-pgp.el (pgg-pgp-encrypt-region, pgg-pgp-decrypt-region)
+       (pgg-pgp-sign-region): Add optional 'passphrase' argument to all
+       these routines, so the passphrase can be managed externally and
+       passed in to the system.
+       (pgg-pgp-decrypt-region, pgg-pgp-sign-region): Use new name for
+       pgg-add-passphrase-to-cache function.
+
+       * pgg-pgp5.el (pgg-pgp5-encrypt-region, pgg-pgp5-decrypt-region)
+       (pgg-pgp5-sign-region): Add optional 'passphrase' argument to all
+       these routines, so the passphrase can be managed externally and
+       passed in to the system.
+       (pgg-pgp5-sign-region): Use new name of
+       pgg-add-passphrase-to-cache function.
+
+2006-01-19  Ken Manheimer  <ken.manheimer@gmail.com>
+
+       * pgg-gpg.el (pgg-gpg-select-matching-key): Fix: look at the right
+       part of the decoded armor to find the key-identifier.
+       (pgg-gpg-lookup-key-owner): New function to return the
+       human-readable identifier of a key owner.
+       (pgg-gpg-key-id-from-key-owner): Make it easy to identify the key
+       itself.
+       (pgg-gpg-decrypt-region): Prompt with the key owner (rather than
+       the key value) if we have a key and can match it against a secret
+       key.  Also, added a note pointing out fact that the prompt only
+       indicates the first matching key.
+
+       * pgg.el (pgg-decrypt): Passing along 'passphrase' in call to
+       pgg-decrypt-region.
+       (pgg-add-passphrase-to-cache): Rename from
+       `pgg-add-passphrase-cache' to reduce confusion (all callers
+       changed).
+       (pgg-remove-passphrase-from-cache): Rename from
+       `pgg-remove-passphrase-cache' to reduce confusion (all callers
+       changed).
+       (pgg-read-passphrase, pgg-add-passphrase-cache)
+       (pgg-remove-passphrase-cache): Add informative docstrings.
+       (pgg-decrypt): Convey provided passphrase in subordinate call to
+       pgg-decrypt-region.
+
+2006-01-19  Ken Manheimer  <ken.manheimer+emacs@gmail.com>
+
+       * pgg.el (pgg-encrypt-region, pgg-encrypt-symmetric-region)
+       (pgg-encrypt-symmetric, pgg-encrypt, pgg-decrypt-region)
+       (pgg-decrypt, pgg-sign-region, pgg-sign): Add optional
+       'passphrase' argument, so the passphrase can be managed externally
+       and then passed in to the system.
+
+       * pgg.el (pgg-read-passphrase, pgg-add-passphrase-cache)
+       (pgg-remove-passphrase-cache): Add optional 'notruncate' argument,
+       so the passphrase cache can be used reliably with identifiers
+       besides a pgp packet's key id.
+
+       * pgg-gpg.el (pgg-gpg-encrypt-region)
+       (pgg-gpg-encrypt-symmetric-region, pgg-gpg-decrypt-region)
+       (pgg-gpg-sign-region): Add optional 'passphrase' argument to all
+       these routines, so the passphrase can be managed externally and
+       passed in to the system.
+
+       * pgg-gpg.el (pgg-gpg-possibly-cache-passphrase): Add optional
+       'notruncate' argument, so the passphrase cache can be used
+       reliably with identifiers besides a pgp packet's key id.
+
+2006-01-19  Sascha Wilde  <swilde@sha-bang.de>
+
+       * pgg-gpg.el (pgg-gpg-encrypt-symmetric-region): New function for
+       symmetric encryption.
+       (pgg-gpg-symmetric-key-p): New function to check for an symmetric
+       encrypted session key.
+       (pgg-gpg-decrypt-region): When decrypting a symmetric encrypted
+       message ask for the passphrase in a proper way.
+
+       * pgg.el (pgg-encrypt-symmetric, pgg-encrypt-symmetric-region):
+       New user commands for symmetric encryption.
+
+2006-01-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-bodies.el (mm-decode-body): Don't decode decoded body.
+
+       * mm-uu.el (mm-uu-dissect-text-parts): Dissect dissected parts.
+
+2006-01-19  Mark D. Baushke  <mdb@gnu.org>
+
+       * pgg-gpg.el (pgg-gpg-encrypt-region): Add --textmode to gpg args.
+
+2006-01-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-inlined-types): Add application/pgp.
+       (mm-automatic-display): Ditto.
+
+       * mm-uu.el (mm-uu-dissect-text-parts): Recognize application/pgp
+       part as text.
+
+2006-01-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnrss.el: Update copyright.
+       (nnrss-opml-import): Query whether to subscribe to each entry.
+
+       * gnus-art.el:
+       * gnus-sum.el:
+       * gnus-xmas.el:
+       * messagexmas.el:
+       * mm-uu.el:
+       * mm-view.el: Update copyright.
+
+2006-01-16  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-info): New function.
+       (message-mode-menu): Add it.
+       Update copyright.
+
+       * ChangeLog: Fix and update copyright.
+
+2006-01-13  Romain Francoise  <romain@orebokech.com>
+
+       * message.el (message-forward-subject-name-subject): Prefer the
+       address to 'nowhere' if the sender has no name.
+       Fix typo.  Update copyright year.
+
+2006-01-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-wash-html):
+       Use gnus-summary-show-article-charset-alist if a numeric arg is given.
+       (gnus-article-wash-html-with-w3m-standalone): New function.
+
+       * mm-view.el (mm-text-html-renderer-alist): Map w3m-standalone to
+       mm-inline-text-html-render-with-w3m-standalone.
+       (mm-text-html-washer-alist): Map w3m-standalone to
+       gnus-article-wash-html-with-w3m-standalone.
+       (mm-inline-text-html-render-with-w3m-standalone): New function.
+
+2006-01-12  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-uu.el (mm-uu-type-alist): Fix previous message-marks commit.
+       Improve LaTeX.
+
+2006-01-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnrss.el (nnrss-wash-html-in-text-plain-parts): New variable.
+       (nnrss-request-article): Render text/plain parts as HTML.
+
+       * gnus-art.el (gnus-article-wash-html-with-w3m): No need to narrow
+       the buffer.
+
+2006-01-08  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-cus.el (gnus-group-parameters): Sync posting-style with
+       custom definition of `gnus-posting-styles'.
+
+       * gnus-start.el (gnus-gnus-to-quick-newsrc-format):
+       Bind print-circle.  Suggested by Kalle Olavi Niemitalo <kon@iki.fi>.
+
+2006-01-05  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-group.el (gnus-useful-groups): Use Gmane for ding.
+       Use nntp for bug archive.
+
+2006-01-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnrss.el (nnrss-request-article): Fix the way to fill text/plain
+       parts.
+       (nnrss-normalize-date): New function converts ISO 8601 date into
+       RFC822 style.  Suggested by Mark Plaksin <happy@mcplaksin.org>.
+       (nnrss-check-group): Use it.
+
+2006-01-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-work-articles): Remove useless `min'.
+
+       * nnrss.el (nnrss-fetch): Make it fail gracefully when it can't
+       fetch a feed.  Suggested by Mark Plaksin <happy@mcplaksin.org>.
+       (nnrss-insert-w3): Ditto.
+
+2005-12-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-uu.el (gnus-uu-digest-mail-forward): Reverse the order of
+       the articles to be forwarded including the case where neither a
+       number of articles nor a region is specified.
+
+2005-12-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnrss.el (nnrss-request-article): Fix last change; fill
+       text/plain parts.
+
+2005-12-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnrss.el (nnrss-request-article): Replace <br />s with newlines
+       in text/plain part.
+       (nnrss-check-group): Don't add excessive newline to dc:subject.
+
+2005-12-19  Mark Plaksin  <happy@mcplaksin.org>  (tiny change)
+
+       * nnrss.el (nnrss-check-group): Put the RSS dc:subject in the
+       article.
+
+2005-12-18  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnml.el: Don't require gnus-bcklg.  Autoload it.
+       (nnml-use-compressed-files, nnml-save-mail): Support other
+       comression programs such as bzip2.
+
+2005-12-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * dns.el (query-dns): Make sure we check the buffer size before
+       removing tcp headers.
+
+2005-12-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-delete-text-of-type): Enable it to
+       remove MIME buttons associated with multipart/alternative parts.
+       (gnus-mime-display-alternative): Tag buttons using `article-type'
+       text property.
+
+       * gnus-msg.el (gnus-copy-article-buffer): Remove MIME buttons
+       associated with multipart/alternative parts.
+
+       * gnus-art.el (gnus-signature-separator): Fix custom type.
+
+       * mm-decode.el (mm-inlined-types): Fix custom type.
+       (mm-keep-viewer-alive-types): Ditto.
+       (mm-automatic-display): Ditto.
+       (mm-attachment-override-types): Ditto.
+       (mm-inline-override-types): Ditto.
+       (mm-automatic-external-display): Ditto.
+
+2005-12-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * spam-report.el (spam-report-user-mail-address)
+       (spam-report-user-agent): New variables.
+       (spam-report-url-ping-plain): Use spam-report-user-agent.
+
+2005-12-14  Ralf Angeli  <angeli@iwi.uni-sb.de>
+
+       * gnus-art.el (gnus-button-handle-custom): Do not just use
+       `customize-apropos' for any "M-x customize-*" button but the
+       function called for.  Accept both the function name and its
+       argument in order to achieve this.
+       (gnus-button-alist): Remove support for "custom:" URL's.
+       Pass function name to `gnus-button-handle-custom' in case of "M-x
+       customize-*" buttons.
+
+2005-12-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-buttonized-mime-types): Mention addition of
+       multipart/alternative and add xref to mm-discouraged-alternatives
+       in doc string.
+
+       * mm-decode.el (mm-discouraged-alternatives): Add xref to
+       gnus-buttonized-mime-types in doc string.
+
+2005-12-08  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-decode.el (mm-discouraged-alternatives): Fix custom type.
+       Suggest image/.* in the doc string.
+
+2005-12-12  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-uu.el (mm-uu-type-alist): Don't depend on message.el for
+       message-marks (Debian bug#342521).
+
+2005-12-12  Simon Josefsson  <jas@extundo.com>
+
+       * password.el (password-read-from-cache): Add.
+       (password-read): Use it.
+
+2005-12-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-charset-to-coding-system):
+       Recognize us-ascii as a MIME charset.
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding):
+       Protect against the case where the 2nd arg TYPE is nil.
+
+2005-12-09  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * pop3.el (pop3-stream-type): Fix custom version.
+
+       * mm-uu.el (mm-uu-type-alist): Simplify uu regexp.
+
+2005-12-09  ARISAWA Akihiro  <ari@mbf.ocn.ne.jp>  (tiny change)
+
+       * mm-decode.el (mm-display-external): Add missing cdr.
+
+2005-12-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-display-external): Use nametemplate (defined in
+       RFC1524) if it is in mailcap or add a suffix according to
+       mailcap-mime-extensions when generating a temp filename; postpone
+       deleting a temp file for 2 seconds for some wrappers, shell
+       scripts, and so on, which might exit right after having started a
+       viewer command as a background job.
+
+2005-12-06  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nntp.el (nntp-marks-directory): Fix custom group.
+
+       * gnus-fun.el (gnus-face-from-file): Decrease quant in smaller
+       steps when < 10.
+
+       * gnus-start.el (gnus-no-server-1):
+       Mention `gnus-level-default-subscribed' in doc string.
+
+2005-12-02  ARISAWA Akihiro  <ari@mbf.ocn.ne.jp>  (tiny change)
+
+       * mm-view.el (mm-inline-text-html-render-with-w3m): Fix misplaced
+       parens.
+
+2005-12-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-xmas.el (gnus-use-toolbar): Revert.
+       (gnus-xmas-setup-toolbar): Use global default-toolbar if
+       gnus-use-toolbar is default.
+
+       * messagexmas.el (message-use-toolbar): Revert.
+       (message-setup-toolbar): Use global default-toolbar if
+       message-use-toolbar is default.
+
+2005-11-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-xmas.el (gnus-use-toolbar): Determine the default value
+       according to default-toolbar-visible-p.
+
+       * messagexmas.el (message-use-toolbar): Ditto.
+
+2005-11-26  Dave Love  <fx@gnu.org>
+
+       * tls.el (open-tls-stream): Rename arg SERVICE to PORT.
+       (tls-program, tls-success): Provide openssl alternative.
+
+       * starttls.el: Doc fixes.
+       (starttls-open-stream-gnutls, starttls-open-stream): Rename arg
+       SERVICE to PORT.
+
+       * pop3.el (pop3-open-server) <ssl>: Clarify a loop.  Deal with
+       port null or service name.
+       (starttls-negotiate): Autoload.
+
+2005-11-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-kill-to-signature): Fix interactive spec.
+
+2005-11-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * pop3.el (pop3-open-server): Recognize a string as a service name.
+
+2005-11-24  Pascal Rigaux  <pixel@mandriva.com>  (tiny change)
+
+       * rfc2231.el (rfc2231-parse-string): Support non-ascii chars.
+
+2005-11-23  Dave Love  <fx@gnu.org>
+
+       Add pop3s, pop3/starttls.
+
+       * pop3.el (pop3-authentication-scheme): Clarify doc.
+       (open-tls-stream, starttls-open-stream): Autoload.
+       (pop3-stream-type): New.
+       (pop3-open-server): Use it.
+
+       * mail-source.el (mail-sources): Fix some :types.  Add stream type
+       for POP.
+       (mail-source-keyword-map): Add :stream for POP.
+       (mail-source-fetch-pop): Use pop3-stream-type.
+
+2005-11-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnmail.el (nnmail-fancy-expiry-target): Use current-time instead
+       of current-time-string.
+
+2005-11-20  Stefan Schimanski  <schimmi@debian.org>  (tiny change)
+
+       * nnmail.el (nnmail-fancy-expiry-target): Protect against invalid
+       date header.
+
+2005-11-19  Kevin Greiner  <kevin.greiner@compsol.cc>
+
+       * gnus-sum.el (gnus-fetch-old-headers): Updated docs to warn that
+       it can seriously impact performance as it bypasses the agent's
+       local caches.
+
+2005-11-19  Kevin Greiner  <kevin.greiner@compsol.cc>
+
+       * gnus-agent.el (gnus-agent-possibly-synchronize-flags): A server
+       must be explicitly online rather than "not explicitly offline" for
+       its flags to be synchronized.
+
+       * gnus-sum.el (gnus-summary-remove-process-mark): Always return t so
+       that gnus-uu-unmark-thread will function correctly.
+
+       * gnus-group.el (gnus-total-fetched-for): Reduced cutoff so that
+       1024K is instead displayed as 1M.
+
+2005-11-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * flow-fill.el (fill-flowed): Bind adaptive-fill-mode to nil.
+
+2005-11-16  Boris Samorodov  <bsam@ipt.ru>  (tiny change)
+
+       * imap.el (imap-kerberos4-open): Ignore SSL stuff.
+
+2005-11-13  Kevin Greiner  <kevin.greiner@compsol.cc>
+
+       * gnus-agent.el (gnus-agent-read-local): Trivial fix to format of
+       error message to display actual error condition.
+       (gnus-agent-save-local): Avoid saving symbols that are bound to
+       nil as they simply result in a warning message in
+       gnus-agent-read-local.
+
+2005-11-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-start.el (gnus-dribble-read-file): Use make-local-variable
+       rather than make-variable-buffer-local for file-precious-flag.
+
+2005-11-12  Kevin Greiner  <kevin.greiner@compsol.cc>
+
+       * gnus-agent.el (gnus-agent-braid-nov): Now tests new nov entries
+       for duplicates which are removed.  The invalid sort check then
+       triggers a rescan after the sort as sorting may have moved
+       duplicate entries such that they can be cheaply detected.
+
+2005-11-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-start.el (gnus-dribble-read-file): Quote file-precious-flag.
+
+2005-11-12  Kevin Greiner  <kevin.greiner@compsol.cc>
+
+       * gnus-agent.el (gnus-agent-article-alist-save-format):
+       Change internal variable to a custom variable.  Change default value
+       from compressed(2) to uncompressed(1).
+       (gnus-agent-read-agentview): Reversed revision 7.8 to restore
+       support for uncompressed agentview files.  Taken together, reading
+       the agentview file should now be 6-7 times faster.
+
+2005-11-11  Jan Nieuwenhuizen  <janneke@gnu.org>
+
+       * gnus-start.el (gnus-dribble-read-file): Set file-precious-flag,
+       as a buffer-local variable.  This avoids creating truncated
+       dribble files as a result of a hang up, eg.
+
+2006-01-03  Rodrigo Ventura  <yoda@isr.ist.utl.pt>  (tiny change)
+
+       * gnus-xmas.el (gnus-xmas-group-startup-message): Typo
+       gnus-splash-face -> gnus-splash.  Fixes starting from a TTY in
+       XEmacs.
+
+2005-12-09  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-start.el (gnus-start-draft-setup):
+       Enforce `gnus-draft-mode' for nndraft:drafts at startup.
+
+       * gnus.el (gnus-splash): Change custom group.
+       (gnus-group-get-parameter, gnus-group-parameter-value):
+       Describe allow-list argument.
+
+       * gnus-agent.el (gnus-agent-article-alist-save-format): Format doc
+       string.
+
+2005-12-06  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-default-article-saver): Add user-defined
+       `function' to custom type.
+
+2005-10-30  Chong Yidong  <cyd@stupidchicken.com>
+
+       * imap.el (imap-open): Handle case where buffer is a buffer
+       object.
+
+2005-11-29  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-cache.el (gnus-cache-rename-group): Wrap doc strings and
+       long lines.
+       (gnus-cache-delete-group): Wrap doc strings.
+
+       * gnus-agent.el (gnus-agent-rename-group)
+       (gnus-agent-delete-group): Wrap doc strings.
+
+2005-11-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * messagexmas.el (message-use-toolbar): Change the valid values
+       into default, top, bottom, left, and right.
+       (message-toolbar-thickness): New variable.
+       (message-xmas-setup-toolbar): Locate gnus-xmas-glyph-directory as
+       well.
+       (message-setup-toolbar): Make it work.
+
+       * gnus-xmas.el (gnus-xmas-update-toolbars): New function.
+       (gnus-use-toolbar): Change the valid values into default, top,
+       bottom, left, and right.
+       (gnus-toolbar-thickness): New variable.
+       (gnus-xmas-setup-toolbar): New function.
+       (gnus-xmas-setup-group-toolbar): Use it.
+       (gnus-xmas-setup-summary-toolbar): Use it.
+
+2005-11-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-1): Add "native" to
+       gnus-predefined-server-alist.
+
+       * gnus.el (gnus-method-to-server): Don't add "native" to the
+       lists here, because that leads to problems when
+       gnus-select-method is bound.
+
+2005-11-09  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-article-sort-by-date-reverse): Remove,
+       use (not sort-by-date) instead.
+
+2005-11-30  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-delay.el (gnus-delay-group): Don't autoload.
+       It's useless and could trigger a bug in cus-dep.el causing ldefs-boot
+       to be re-loaded when customizing the `gnus-delay' group.
+
+2005-11-19  Chong Yidong  <cyd@stupidchicken.com>
+
+       * message.el: Revert last changes.
+       (message-insert-citation-line): Use newlines.
+
+2005-11-17  Chong Yidong  <cyd@stupidchicken.com>
+
+       * message.el (message-courtesy-message)
+       (message-mark-insert-begin, message-mark-insert-end)
+       (message-elide-ellipsis, message-cancel-message)
+       (message-add-header, message-change-subject)
+       (message-cross-post-followup-to-header)
+       (message-cross-post-insert-note, message-reduce-to-to-cc)
+       (message-widen-reply, message-delete-not-region)
+       (message-kill-to-signature, message-insert-signature)
+       (message-insert-importance-high, message-insert-importance-low)
+       (message-insert-or-toggle-importance)
+       (message-insert-disposition-notification-to)
+       (message-indent-citation, message-yank-original)
+       (message-cite-original-without-signature, message-cite-original)
+       (message-insert-citation-line, message-position-on-field)
+       (message-fix-before-sending, message-send-mail-partially)
+       (message-send-mail, message-send-mail-with-sendmail)
+       (message-send-mail-with-qmail, message-send-news)
+       (message-check-news-header-syntax, message-generate-headers)
+       (message-insert-courtesy-copy, message-fill-address)
+       (message-fill-header, message-shorten-references)
+       (message-setup-1, message-cancel-news)
+       (message-forward-make-body-plain, message-forward-make-body-mime)
+       (message-forward-make-body-mml, message-encode-message-body)
+       (message-forward-make-body-digest-plain)
+       (message-forward-make-body-digest-mime)
+       (message-use-alternative-email-as-from): Insert `hard-newline'
+       instead of ordinary newlines.
+
+2005-11-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-generate-headers): Downcase the argument
+       given to message-check-element.
+
+2005-11-08  Kevin Greiner  <kevin.greiner@compsol.cc>
+
+       * nntp.el (nntp-authinfo-rejected): New error condition.
+       (nntp-wait-for): Use new error condition to signal authentication
+       error.
+       (nntp-retrieve-data): Rethrow new error condition to break out of
+       recursive call to nntp-send-authinfo.
+
+2005-11-08  Romain Francoise  <romain@orebokech.com>
+
+       * gnus-sum.el (gnus-summary-catchup-and-goto-prev-group): New function.
+       (gnus-summary-exit-map): Bind to `Z p'.
+       (gnus-summary-make-menu-bar): Add menu item.
+
+2005-11-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-article-treat-custom): Add `first'.
+       (gnus-treat-*): Add `first' in all doc strings.
+
+       * gnus-group.el (gnus-group-compact-group): Fix typo.
+
+2005-11-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (gnus-parameters-case-fold-search): New variable.
+       (gnus-parameters-get-parameter): Use it.
+
+       * gnus-score.el (gnus-home-score-file): Doc fix.
+
+2005-11-01  Xavier Maillard  <zedek@gnu-rox.org>  (tiny change)
+
+       * gnus-score.el (gnus-update-score-entry-dates): Doc fix.
+
+2005-10-31  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-special-display-p): New function.
+
+       * mml.el (mml-preview): Use it; doc fix.
+
+2005-10-30  Chong Yidong  <cyd@stupidchicken.com>
+
+       * imap.el (imap-open): Handle case where buffer is a buffer object.
+
+2005-10-29  Romain Francoise  <romain@orebokech.com>
+
+       * message.el (message-fix-before-sending): Fix comment.
+
+2005-10-29  Jari Aalto  <jari.aalto@cante.net>
+
+       * gnus-sum.el (gnus-article-sort-by-date-reverse): New function.
+
+2005-10-29  Jari Aalto  <jari.aalto@cante.net>
+
+       * score-mode.el (gnus-score-edit-done-hook): Introduce variable.
+       Used in gnus-score.el.
+
+2005-10-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-util.el (mm-codepage-setup): Remove bogus alias test.
+
+2005-10-27  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * flow-fill.el (fill-flowed-encode-tests): Restore trailing
+       whitespace removed in revision 7.8.  Use concatenated string to
+       protect trailing whitespace.
+
+2005-10-27  Jouni K. Seppänen  <jks@iki.fi>
+
+       * nnimap.el (nnimap-search-uids-not-since-is-evil): Add variable.
+       (nnimap-request-expire-articles): Use it to avoid sending 'UID
+       SEARCH UID ... NOT SINCE' queries, for inefficient servers like
+       Courier IMAP ("some version from 2004").  Mostly based on similar
+       code in the same function.
+
+2005-10-26  Didier Verna  <didier@xemacs.org>
+
+       * gnus-group.el (gnus-group-compact-group): Invalidate original
+       article buffer.
+       * gnus-srvr.el (gnus-server-compact-server): Ditto.
+       * nnml.el (nnml-request-compact-group): Handle self Xref: field in
+       NOV database and in article itself.
+       Invalidate article backlog.
+
+2005-10-26  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-uu.el (mm-uu-hide-markers): Fix XEmacs case.
+
+2005-10-26  Simon Josefsson  <jas@extundo.com>
+
+       * flow-fill.el (fill-flowed): Flow-fill unquoted lines too, revert
+       part of 2004-07-25 change.
+
+2005-10-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-display-completion-list): New function.
+       (message-expand-group): Use it; make sure the Completions buffer
+       is modifiable.
+2005-10-23  Chong Yidong  <cyd@stupidchicken.com>
+
+       * gnus-sum.el (gnus-ignored-from-addresses): Handle case where
+       user-mail-name is an empty string.
+
+2005-10-25  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-score.el (gnus-default-adaptive-score-alist): Set defaults
+       depending on gnus-score-decay-constant.
+
+       * encrypt.el (encrypt-insert-file-contents)
+       (encrypt-write-file-contents): Don't use `gnus-message'.
+
+       * mm-uu.el (mm-uu-verbatim-marks-extract): Add four start and end
+       arguments.
+       (mm-uu-type-alist): Add message-marks and insert-marks.
+       Pass arguments to mm-uu-verbatim-marks-extract.
+       (mm-uu-hide-markers): New variable.
+       (mm-uu-extract): Use face similar to `gnus-cite-3'.
+
+       * gnus-fun.el (gnus-convert-image-to-x-face-command)
+       (gnus-convert-image-to-face-command): Use "convert" by default to
+       allow other input image formats.
+       (gnus-x-face-from-file, gnus-face-from-file): Adjust doc strings
+       accordingly.
+
+2005-10-23  Simon Josefsson  <jas@extundo.com>
+
+       * imap.el (imap-gssapi-program): Align command line parameters
+       with latest GNU SASL.
+       (imap-gssapi-open): Ignore 'Trying ...' messages from GNU SASL.
+
+2005-10-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnslashdot.el (nnslashdot-retrieve-headers-1): Update to new
+       HTML.
+       (nnslashdot-request-article): Ditto.
+
+       * lpath.el (featurep): Add nobreak-char-display.
+
+2005-10-20  Hiroshi Fujishima  <hiroshi.fujishima@gmail.com>  (tiny change)
+
+       * mail-source.el (mail-source-fetch-pop): Require pop3.
+       (mail-source-check-pop): Ditto.
+
+2005-10-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-decode-encoded-words): Fix the handling of
+       errors.
+
+2005-10-19  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-treat-strip-trailing-blank-lines)
+       (gnus-treat-strip-leading-blank-lines): Improve doc string.
+
+       * message.el (message-tool-bar-local-item-from-menu): Fix comment.
+
+       * mm-bodies.el (mm-decode-string):
+       Call `mm-charset-to-coding-system' with allow-override argument.
+
+2005-10-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-allow-incomplete-encoded-text): New variable.
+       (rfc2047-charset-to-coding-system): New function.
+       (rfc2047-decode-encoded-words): New function.
+       (rfc2047-decode-region): Use them.
+       (rfc2047-decode-cte): Remove.
+       (rfc2047-parse-and-decode): Remove.
+       (rfc2047-decode): Remove.
+
+2005-10-15  Kenichi Handa  <handa@m17n.org>
+
+       * rfc2047.el (rfc2047-decode-cte): New function.
+       (rfc2047-decode-region): Change the way to decode successive
+       encoded-words: decode B- or Q-encoding in each encoded-word,
+       concatenate them, and decode it as charset.
+
+2005-10-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind codepage-setup for XEmacs.
+
+2005-10-17  Chong Yidong  <cyd@stupidchicken.com>
+
+       * gnus-cus.el (gnus-custom-map): New variable.  Bind mouse-1 to
+       widget-move-and-invoke.
+       (gnus-custom-mode): Use gnus-custom-map.
+
+2005-10-15  Bill Wohler  <wohler@newt.com>
+
+       * message.el (message-tool-bar-map): Rename image file from
+       mail_send to mail/send.
+
+2005-10-16  Masatake YAMATO  <jet@gyve.org>
+
+       * message.el (message-expand-group): Pass the common
+       prefix substring of completion to `display-completion-list'.
+
+2005-10-13  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mml-sec.el (mml-secure-method): New internal variable.
+       (mml-secure-sign, mml-secure-encrypt, mml-secure-message-sign)
+       (mml-secure-message-sign-encrypt, mml-secure-message-encrypt):
+       New functions using mml-secure-method.
+
+       * mml.el (mml-mode-map): Add key bindings for those functions.
+       (mml-menu): Simplify security menu entries.  Suggested by Jesper
+       Harder <harder@myrealbox.com>.
+       (mml-attach-file, mml-attach-buffer, mml-attach-external):
+       Goto end of message if point is the headers of the message.
+
+       * message.el (message-in-body-p): New function.
+
+       * assistant.el: Autoload gnus-util and netrc.
+
+       * mm-util.el (mm-charset-to-coding-system): Add allow-override.
+       Use `mm-charset-override-alist' only when decoding.
+
+       * mm-bodies.el (mm-decode-body):
+       Call `mm-charset-to-coding-system' with allow-override argument.
+
+       * gnus-art.el (gnus-mime-view-part-as-type-internal): Try to fetch
+       `filename' from Content-Disposition if Content-Type doesn't
+       provide `name'.
+       (gnus-mime-view-part-as-type): Set default instead of
+       initial-input.
+
+2005-10-09  Daniel Brockman  <daniel@brockman.se>
+
+       * format-spec.el (format-spec): Propagate text properties of % spec.
+
+2005-10-12  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-treat-predicate): Add `first'.
+
+2005-10-11  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-util.el (mm-charset-synonym-alist): Improve doc string.
+       (mm-charset-override-alist): New variable.
+       (mm-charset-to-coding-system): Use it.
+       (mm-codepage-setup): New helper function.
+       (mm-charset-eval-alist): New variable.
+       (mm-charset-to-coding-system): Use mm-charset-eval-alist.
+       Warn about unknown charsets.
+
+       * dgnushack.el (with-syntax-table): Add some URLs WRT the XEmacs bug.
+
+2005-10-04  David Hansen  <david.hansen@gmx.net>
+
+       * nnrss.el (nnrss-request-article): Add support for the comments tag.
+       (nnrss-check-group): Ditto.
+
+2005-10-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-uu.el (mm-uu-verbatim-marks-extract, mm-uu-latex-extract):
+       Rename x-gnus-verbatim to x-verbatim.
+       (mm-uu-type-alist): Fix regexp for verbatim-marks.
+
+       * mm-decode.el (mm-automatic-display): Rename x-gnus-verbatim to
+       x-verbatim.
+
+       * mm-url.el (mm-url-predefined-programs): Add switches for curl.
+
+       * gnus-util.el (gnus-remove-duplicates): Remove.
+
+       * nnmail.el (nnmail-article-group): Use mm-delete-duplicates
+       instead of gnus-remove-duplicates.
+
+       * message.el (message-remove-duplicates): Remove.
+       (message-idna-to-ascii-rhs-1): Use mm-delete-duplicates instead of
+       message-remove-duplicates.
+
+       * mm-util.el (mm-delete-duplicates): Use `delete-dups' if
+       available, else use implementation from `delete-dups'.
+
+       * message.el (message-insert-expires): New function.
+       (message-mode-map): Add key binding.
+       (message-mode-field-menu): Add menu entry.
+       (message-mode): Document it.
+       (message-make-expires-date): Use `message-make-date'.
+
+2005-10-04  Josh Huber  <huber@alum.wpi.edu>
+
+       * message.el (message-make-expires-date): New function.
+
+2005-10-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * Makefile.in (list-installed-shadows): New entry.
+       (install): Use it.
+       (remove-installed-shadows): New entry.
+
+       * dgnushack.el (dgnushack-default-load-path): New variable.
+       (dgnushack-find-lisp-shadows): New function.
+       (dgnushack-remove-lisp-shadows): New function.
+
+2005-10-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * Makefile.in (install-el-elc): New entry.
+       (install): Use it so that .el files are necessarily installed.
+
+2005-09-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * time-date.el: Autoload parse-time-string, XEmacs needs it.
+
+2005-09-30  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * mm-decode.el (mm-inline-media-tests): Check presence of the diff-mode
+       function rather than the diff-mode.el package.
+       (mm-display-external): Use with-current-buffer.
+       (mm-viewer-completion-map, mm-viewer-completion-map):
+       Move initialization inside declaration.
+
+2005-09-29  Simon Josefsson  <jas@extundo.com>
+
+       * spam.el: Load hashcash when compiling, to avoid warnings.
+       Don't autoload mail-check-payment.
+       (spam-check-hashcash): Define unconditionally, since hashcash.el
+       is part of Gnus now.  Ignore errors from payment checking.
+
+2005-09-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-bold-region, message-unbold-region):
+       Rename from `bold-region' and `unbold-region'.
+
+       * message.el: Remove useless autoloads.
+
+2005-09-28  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-use-idna): Default to t.
+       (message-use-idna): Test whether encoding works too.  Doc fix.
+
+2005-09-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nntp.el (nntp-warn-about-losing-connection): Remove.
+
+2005-09-27  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-uu.el (mm-uu-emacs-sources-regexp): Make variable
+       customizable.  Change default value.
+       (mm-uu-diff-groups-regexp): Change default value.
+       (mm-uu-type-alist): Add doc string.
+       (mm-uu-configure): Add doc string.  Make it interactive.
+       (mm-uu-tex-groups-regexp): New variable.
+       (mm-uu-latex-extract, mm-uu-latex-test): New functions.
+       (mm-uu-type-alist): Add LaTeX documents.
+       (mm-uu-verbatim-marks-extract): Use "text/x-gnus-verbatim" instead
+       of "text/verbatim".
+       (mm-uu-diff-groups-regexp): Fix missing quotes from previous commit.
+
+       * mm-decode.el (mm-automatic-display): Use "text/x-gnus-verbatim"
+       instead of "text/verbatim".
+
+       * message.el (message-mark-inserted-region)
+       (message-mark-insert-file): Use slrn style marks when called with
+       prefix argument.
+
+2005-09-27  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-idna-to-ascii-rhs-1): Reformat.
+
+2005-09-27  Arne Jørgensen  <arne@arnested.dk>
+
+       * message.el (message-remove-duplicates): New function.
+       Implementation borrowed from `gnus-remove-duplicates'.
+       (message-idna-to-ascii-rhs): Also encode idna addresses in
+       Reply-To:, Mail-Reply-To: and Mail-Followup-To:.
+       (message-idna-to-ascii-rhs-1): When `message-use-idna' is 'ask
+       only ask about the same idna domain once per header and also tell
+       in what header to replace the idna domain.
+
+       * gnus-art.el (article-decode-idna-rhs): Also decode idna
+       addresses in Reply-To:, Mail-Reply-To: and Mail-Followup-To:.
+       (article-decode-idna-rhs): Fix regexp so that all idna-address in
+       a header is decoded and not just the last one.
+
+2005-09-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-display-single): Don't modify text if it
+       has been decoded.
+
+       * mm-decode.el (mm-automatic-display): Add text/verbatim.
+       (mm-insert-part): Don't modify text if it has been decoded.
+
+       * mm-uu.el (mm-uu-verbatim-marks-extract): Say text has been
+       decoded.
+
+       * mm-view.el (mm-inline-text): Don't strip text props unless
+       decoding enriched or richtext parts.
+
+2005-09-25  Romain Francoise  <romain@orebokech.com>
+
+       * gnus-agent.el (gnus-agent-expire-group, gnus-agent-expire):
+       * gnus-start.el (gnus-subscribe-interactively):
+       * gnus-uu.el (gnus-uu-grab-articles):
+       End `yes-or-no-p' and `y-or-n-p' prompts with question mark and
+       space.
+
+2005-09-24  Emilio C. Lopes  <eclig@gmx.net>
+
+       * smime.el (smime-sign-buffer, smime-decrypt-buffer):
+       * mm-view.el (mm-view-pkcs7-decrypt):
+       * gnus-sum.el (gnus-summary-limit-to-extra)
+       (gnus-summary-respool-article, gnus-read-move-group-name):
+       * gnus-score.el (gnus-summary-increase-score):
+       * gnus-util.el (gnus-completing-read-with-default):
+       * gnus-art.el (gnus-read-save-file-name)
+       (gnus-summary-save-in-rmail, gnus-summary-save-in-mail)
+       (gnus-summary-save-in-file, gnus-summary-save-body-in-file):
+       * message.el (message-check-news-header-syntax):
+       Follow convention for reading with the minibuffer.
+
+2005-09-22  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * spam-report.el (spam-report-url-ping-plain):
+       Use gnus-extended-version as User-Agent.
+
+       * gnus-agent.el (gnus-agent-synchronize-flags): Explain why the
+       default value is nil.
+
+       * mm-uu.el (mm-uu-type-alist): Add slrn style verbatim-marks.
+       (mm-uu-verbatim-marks-extract): New function.
+       (mm-uu-extract): New face.
+       (mm-uu-copy-to-buffer): Use it.
+
+       * spam-report.el (spam-report-gmane-ham): Rename from
+       `spam-report-gmane-unspam'.
+       (spam-report-gmane-internal): Rename from `spam-report-gmane'.
+       Simplify use of UNSPAM argument.  Fetch "X-Report-Unspam" header.
+
+       * spam.el (spam-report-gmane-spam, spam-report-gmane-ham):
+       Autoload.
+       (spam-report-gmane-unregister-routine):
+       Rename `spam-report-gmane-unspam' to `spam-report-gmane-ham'.
+
+2005-09-21  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-use-gmane, spam-report-gmane-register-routine)
+       (spam-report-gmane-unregister-routine): Add support for gmane
+       unregistration.
+
+       * spam-report.el (spam-report-gmane-unspam)
+       (spam-report-gmane-spam): Add new wrappers around spam-report-gmane.
+       (spam-report-gmane): Change to take a single article and do unspam
+       registration.
+
+2005-09-19  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-url.el (mm-url-decode-entities): Fix regexp.
+
+2005-09-20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-agent.el (gnus-agent-synchronize-flags): Switch the
+       default to nil, to be able to use Gnus at all.  If the default
+       switches to something else, then the function should be fixed not
+       be exceedingly slow.
+
+2005-09-20  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-start.el (gnus-activate-group): If the server is nil, don't
+       fail hard.
+
+       * spam-report.el: Add better Keywords line.
+
+       * spam.el: Add Maintainer and better Keywords line.
+
+2005-09-19  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-article-replace-part)
+       (gnus-mime-replace-part): New functions.
+       (gnus-mime-action-alist, gnus-mime-button-commands)
+       (gnus-mime-save-part-and-strip): Add file argument.
+       (gnus-article-part-wrapper): Add interactive argument.
+
+       * gnus-sum.el (gnus-summary-mime-map):
+       Add `gnus-article-replace-part'.
+
+2005-09-19  Didier Verna  <didier@xemacs.org>
+
+       The nnml compaction feature:
+       * nnml.el (nnml-request-compact-group): New function.
+       * nnml.el (nnml-request-compact): New function.
+       * gnus-int.el (gnus-request-compact-group): New function.
+       * gnus-int.el (gnus-request-compact): New function.
+       * gnus-group.el (gnus-group-compact-group): New function.
+       * gnus-group.el (gnus-group-group-map): Bind it to 'G z'.
+       * gnus-group.el (gnus-group-make-menu-bar): Add an entry for it.
+       * gnus-srvr.el (gnus-server-compact-server): New function.
+       * gnus-srvr.el (gnus-server-mode-map): Bind it to 'z'.
+       * gnus-srvr.el (gnus-server-make-menu-bar): Add an entry for it.
+
+2005-09-18  Deepak Goel  <deego@gnufans.org>
+
+       * sieve.el (sieve-help): Fix `message' call: first arg should be a
+       format spec.
+
+2005-09-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (gnus-group-startup-message): Bind image-load-path.
+
+2005-09-15  Romain Francoise  <romain@orebokech.com>
+
+       * message.el (message-fill-paragraph): Clarify docstring.
+
+2005-09-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-display-part): Protect against broken
+       MIME messages.
+
+2005-09-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-edit-article-done): Remove text props
+       before parsing header.
+
+2005-09-11  Jari Aalto  <jari.aalto@cante.net>
+
+       * html2text.el (html2text-replace-list): Add new entities.
+
+2005-09-11  Romain Francoise  <romain@orebokech.com>
+
+       * message.el (message-alternative-emails): Improve docstring.
+       (message-setup-1): Call `message-use-alternative-email-as-from'
+       after `message-setup-hook' to give it precedence over posting
+       styles, etc.
+       (message-use-alternative-email-as-from): Add docstring.
+       Remove the original From header if present.
+
+       * nnml.el (nnml-compressed-files-size-threshold): New variable.
+       (nnml-save-mail): Use it.
+
+       * gnus-uu.el (gnus-uu-mark-series): Return number of marked
+       articles.  Add new argument `silent'.
+       (gnus-uu-mark-all): Report the total number of marked articles.
+
+2005-09-10  Romain Francoise  <romain@orebokech.com>
+
+       * gnus-uu.el (gnus-message-process-mark): Use gnus-message.
+       (gnus-uu-mark-series): Likewise.
+
+2005-09-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * spam-report.el (spam-report-gmane): Fix generation of spam
+       report URL.
+
+2005-09-10  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-agent.el (gnus-agent-synchronize-flags): Make the default
+       t, based on discussion on the ding list with Robert Epprecht
+       <epprecht@solnet.ch>.
+
+2005-09-07  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * spam-report.el (spam-report-gmane): Make it work without
+       X-Report-Spam header.  Gmane now only provides Archived-At.
+       This is only used if `spam-report-gmane-use-article-number' is nil.
+       (spam-report-gmane-spam-header): Remove.  Not used anymore.
+
+       * gnus-sum.el (gnus-thread-sort-by-recipient): New function to
+       make `gnus-summary-sort-by-recipient' work with threading.
+
+       * nnweb.el (nnweb-google-wash-article): Print a message if article
+       is not available.
+
+2005-09-07  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * gnus-art.el (gnus-mime-display-single): Revert 2004-10-07
+       change.  Decode text/* parts content before displaying.
+
+2005-09-06  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mml-smime.el: Remove defvar of gnus-extract-address-components.
+
+2005-09-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-view.el (mm-display-inline-fontify): Disable support modes.
+
+       * lpath.el: Don't bind mc-pgp-always-sign, url-current-object,
+       url-package-name, url-package-version,
+       w3m-cid-retrieve-function-alist, w3m-current-buffer,
+       w3m-display-inline-images, and w3m-minor-mode-map.
+
+2005-09-05  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-tab-body-function): Fix mismatched custom type.
+
+       * gnus.el (gnus-group-change-level-function): Ditto.
+
+       * gnus-msg.el (gnus-outgoing-message-group): Ditto.
+
+       * gnus-art.el (gnus-signature-limit)
+       (gnus-article-mime-part-function): Ditto.
+
+2005-09-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml.el (mml-mode): Silence the byte compiler.
+
+       * gnus-art.el (gnus-article-jump-to-part): Redisplay the article
+       using `(sit-for 0)' before moving the point to the specified part;
+       skip unbuttonized parts.
+       (gnus-article-part-wrapper): Don't use save-window-excursion; don't
+       return to the summary window if gnus-auto-select-part is non-nil.
+
+2005-09-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mml.el (mml-dnd-protocol-alist, mml-dnd-attach-options):
+       New variables.
+       (mml-dnd-attach-file, mml-mode): Use them.
+
+       * nnweb.el (nnweb-type-definition, nnweb-google-wash-article):
+       Make fetching article by MID work again for Google Groups.
+       Add FIXME concerning gnus-group-make-web-group.
+
+       * mml-smime.el (mml-smime-sign-query, mml-smime-get-dns-cert):
+       Don't depend on Gnus by using mail-extract-address-components if
+       gnus-extract-address-components is not bound.
+
+2005-09-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-mime-display-security): Don't display the
+       signature, but only the signed part.
+
+2005-09-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-thread-hide-subtree): Doc fix.
+
+       * gnus-msg.el (gnus-inews-insert-gcc): Fix the mistake of using
+       list, not listp.
+
+2005-09-02  Hrvoje Niksic  <hniksic@xemacs.org>
+
+       * mm-encode.el (mm-encode-content-transfer-encoding):
+       Likewise when encoding.
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding):
+       De-canonicalize CRLF for all text content types, not just
+       text/plain.
+
+2005-09-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-part-wrapper): Error if there's no
+       valid article; point arrow and cursor at the MIME button.
+
+2005-08-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-save-part-and-strip): Clarify prompt.
+       Suggested by Dan Christensen <jdc@uwo.ca>.
+
+       * mm-decode.el (mm-save-part): Enable change of prompt.
+
+2005-08-29  Jari Aalto  <jari.aalto@cante.net>
+
+       * gnus-msg.el (gnus-inews-add-send-actions):
+       Make `message-post-method' lambda parameter ARG `&optional'.
+
+2005-08-29  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-summary-mime-map):
+       Add gnus-article-save-part-and-strip, gnus-article-delete-part and
+       gnus-article-jump-to-part.
+
+       * gnus-art.el (gnus-article-edit-article): Add quiet argument.
+       (gnus-article-edit-part): Use it.
+       (gnus-article-part-wrapper): Add no-handle argument.
+       (gnus-article-save-part-and-strip, gnus-article-delete-part):
+       New functions.
+
+2005-08-29  Romain Francoise  <romain@orebokech.com>
+
+       * gnus-fun.el (gnus-convert-image-to-face-command): Fix typo in
+       docstring.
+       (gnus-face-from-file): Likewise.
+
+2005-08-29  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-mime-save-part-and-strip): Don't prompt.
+       (gnus-mime-delete-part): Don't prompt if `gnus-expert-user' is
+       non-nil.
+       (gnus-auto-select-part): New variable.
+       (gnus-article-jump-to-part): New function.
+       (gnus-article-edit-part, gnus-mime-save-part-and-strip)
+       (gnus-mime-delete-part): Allow selecting specified part after
+       deleting or stripping parts.
+       (gnus-article-jump-to-part): Don't use `read-number'.  Use last
+       part if argument is bogus.
+
+2005-08-31  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus-art.el (w3m-minor-mode-map):
+       * gnus-spec.el (gnus-newsrc-file-version):
+       * gnus-util.el (nnmail-active-file-coding-system)
+       (gnus-original-article-buffer, gnus-user-agent):
+       * gnus.el (gnus-ham-process-destinations)
+       (gnus-parameter-ham-marks-alist)
+       (gnus-parameter-spam-marks-alist, gnus-spam-autodetect)
+       (gnus-spam-autodetect-methods, gnus-spam-newsgroup-contents)
+       (gnus-spam-process-destinations, gnus-spam-process-newsgroups):
+       * mm-decode.el (gnus-current-window-configuration):
+       * mm-extern.el (gnus-article-mime-handles):
+       * mm-url.el (url-current-object, url-package-name)
+       (url-package-version):
+       * mm-view.el (gnus-article-mime-handles, gnus-newsgroup-charset)
+       (smime-keys, w3m-cid-retrieve-function-alist)
+       (w3m-current-buffer, w3m-display-inline-images)
+       (w3m-minor-mode-map):
+       * mml-smime.el (gnus-extract-address-components):
+       * mml.el (gnus-article-mime-handles, gnus-mouse-2)
+       (gnus-newsrc-hashtb, message-default-charset)
+       (message-deletable-headers, message-options)
+       (message-posting-charset, message-required-mail-headers)
+       (message-required-news-headers):
+       * mml1991.el (mc-pgp-always-sign):
+       * mml2015.el (mc-pgp-always-sign):
+       * nnheader.el (nnmail-extra-headers):
+       * rfc1843.el (gnus-decode-encoded-word-function)
+       (gnus-decode-header-function, gnus-newsgroup-name):
+       * spam-stat.el (gnus-original-article-buffer): Add defvars.
+
+2005-08-22  Karl Chen  <quarl@cs.berkeley.edu>
+
+       * gnus-art.el (gnus-treatment-function-alist): Move date-lapsed to
+       the end of the date treatments.
+
+2005-08-15  Simon Josefsson  <jas@extundo.com>
+
+       * pgg.el (url-insert-file-contents): Don't autoload it, Emacs has
+       it in url-handlers.el and XEmacs in url.el.  Reported by Luca
+       Capello and Romain Francoise.
+       (pgg-fetch-key-function): Remove, not used?
+       (pgg-insert-url-with-w3): Require url, to get
+       url-insert-file-contents regardless of where it is defined.
+
+2005-08-13  Romain Francoise  <romain@orebokech.com>
+
+       * message.el (message-cite-original-1): New function.
+       (message-cite-original): Use it.
+       (message-cite-original-without-signature): Ditto.
+
+2005-08-08  Romain Francoise  <romain@orebokech.com>
+
+       * message.el (message-yank-empty-prefix): New variable.
+       (message-indent-citation): Use it.
+       (message-cite-original-without-signature): Respect X-No-Archive.
+
+2005-08-08  Simon Josefsson  <jas@extundo.com>
+
+       * pgg.el: Autoload url-insert-file-contents instead of loading
+       w3/url.
+       (pgg-insert-url-with-w3): Don't load url here.
+
+2005-08-07  Jesper Harder  <harder@phys.au.dk>
+
+       * message.el (message-kill-to-signature): Don't insert newline at
+       bol.
+       (message-newline-and-reformat): Bind fill-paragraph-function to nil.
+
+2005-08-06  Romain Francoise  <romain@orebokech.com>
+
+       * message.el (message-user-fqdn): Fix typo in docstring.
+
+2005-08-05  Daiki Ueno  <ueno@unixuser.org>
+
+       * mml2015.el (mml2015-pgg-sign): Make sure micalg is correct.
+
+       * pgg-parse.el (pgg-parse-hash-algorithm-alist): Add SHA-2.
+
+2005-08-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-bodies.el (mm-encode-body): Use coding system rather than
+       charset to encode text.
+
+       * mm-util.el (mm-find-mime-charset-region): Attempt to reduce the
+       number of charsets if utf-8 is available (XEmacs).
+
+2005-08-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button-valid-localpart-regexp): New variable
+       taken from `gnus-button-mid-or-mail-regexp'.
+       (gnus-button-mid-or-mail-regexp, gnus-button-alist): Use it.
+       (gnus-button-alist): Improve regexp for domain part of the MIDs
+       for news:localpart@domain buttons.
+       (gnus-button-ctan-directory-regexp): Update.
+
+2005-08-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * sieve-manage.el (sieve-manage-interactive-login):
+       Use make-local-variable rather than make-variable-buffer-local.
+       (sieve-manage-open): Ditto.
+       (sieve-manage-authenticate): Ditto.
+
+       * mml.el (mml-generate-mime-1): Make the content type default to
+       text/plain if the filename is not specified.
+
+2005-08-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-uu.el (gnus-uu-save-article): Use insert-buffer-substring
+       instead of insert-buffer.
+
+       * message.el (message-yank-original): Ditto; set the mark at the
+       end of the yanked message.
+
+2005-07-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-next-page-1): Reduce the number of
+       lines to scroll rather than to stop it.
+
+       * mml.el (mml-generate-default-type): Add doc string.
+       (mml-generate-mime-1): Use mm-default-file-encoding or make it
+       default to application/octet-stream when determining the content
+       type if it is not specified for the part or the mml contents; add
+       a comment about mml-generate-default-type.
+
+2005-07-29  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mml.el (mml-generate-mime-1): Use mm-default-file-encoding or
+       make it default to application/octet-stream when determining the
+       content type if it is not specified for the external contents.
+
+2005-07-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2231.el (rfc2231-parse-string): Take care that not only a
+       segmented parameter but also other parameters might be there.
+
+2005-07-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-display-external): Delete temp file, directory
+       and buffer immediately if the external process is exited.
+
+2005-07-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-next-page-1): Don't scroll if there're
+       fewer lines than that of scroll-margin.
+       (gnus-article-prev-page): Narrow the range to bind scroll-in-place.
+
+2005-07-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-next-page): Revert.
+       (gnus-article-beginning-of-window): New macro.
+       (gnus-article-next-page-1): Use it.
+       (gnus-article-prev-page): Ditto.
+       (gnus-article-edit-part): Use insert-buffer-substring instead of
+       insert-buffer.
+       (gnus-article-edit-exit): Ditto.
+
+       * gnus-util.el (gnus-beginning-of-window): Remove.
+       (gnus-end-of-window): Remove.
+
+       * lpath.el: Don't bind header-line-format and scroll-margin.
+
+2005-07-25  Simon Josefsson  <jas@extundo.com>
+
+       * pgg.el (pgg-insert-url-with-w3): Don't load w3, it is possible
+       to have the url package without w3.  Reported by Daiki Ueno
+       <ueno@unixuser.org> and Luigi Panzeri <matley@muppetslab.org>.
+
+2005-07-20  Didier Verna  <didier@xemacs.org>
+
+       * gnus-diary.el: Remove the description comment (nndiary is now
+       properly documented in the Gnus manual).
+       Fix the spelling of "Back End".
+       * nndiary.el: Ditto.
+       Fix the copyright notice.
+
+2005-07-18  Romain Francoise  <romain@orebokech.com>
+
+       * gnus-sum.el (gnus-summary-to-prefix)
+       (gnus-summary-newsgroup-prefix): New variables.
+       (gnus-summary-from-or-to-or-newsgroups): Use them.
+
+2005-07-17  Romain Francoise  <romain@orebokech.com>
+
+       * mml2015.el (mml2015-clean-buffer): Prefix buffer name with a
+       space as it's generally not especially interesting to the user.
+
+2005-07-16  Romain Francoise  <romain@orebokech.com>
+
+       * nnfolder.el (nnfolder-save-buffer): Bind `copyright-update' to
+       nil to avoid prompting and file modification if one of the
+       messages at the top of the nnfolder file contains a copyright
+       notice.
+       Update copyright notice.
+
+       * gnus-uu.el (gnus-uu-save-article): Use `message-make-date'
+       instead of `current-time-string' as the latter creates a time
+       string that is not RFC 2822 compliant (it lacks the zone).
+       Update copyright notice.
+
+2005-07-21  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * mml.el (mml-minibuffer-read-disposition): Don't use inline by default
+       for text/rtf.  Display default in prompt.  Pass default for M-n.
+
+       * mm-uu.el (mm-uu-copy-to-buffer): Use with-current-buffer.
+
+2005-07-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-button-mailto):
+       Remove save-selected-window-window hackery because it relies on
+       save-selected-window internals.
+
+2005-07-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-next-page): Use gnus-end-of-window.
+       (gnus-article-next-page-1): Use gnus-beginning-of-window.
+       (gnus-article-prev-page): Ditto.
+
+       * gnus-util.el (gnus-beginning-of-window): New function.
+       (gnus-end-of-window): New function.
+
+       * lpath.el: Bind header-line-format and scroll-margin for XEmacs.
+
+2005-07-14  Hiroshi Fujishima  <hiroshi.fujishima@gmail.com>  (tiny change)
+
+       * gnus-score.el (gnus-score-edit-all-score):
+       Set gnus-score-edit-exit-function to gnus-score-edit-done and call
+       gnus-message.
+
+2005-07-14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-button-mailto):
+       Remove save-selected-window-window hackery because it relies on
+       save-selected-window internals.
+
+2005-07-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-salt.el (gnus-pick-mode): Remove the 5th arg of
+       add-minor-mode.
+       (gnus-binary-mode): Ditto.
+
+       * gnus-topic.el (gnus-topic-mode): Ditto.
+
+2005-07-08  Ralf Angeli  <angeli@iwi.uni-sb.de>
+
+       * gnus-art.el (gnus-article-next-page, gnus-article-next-page-1)
+       (gnus-article-prev-page): Take scroll-margin into consideration.
+
+2005-07-04  Lute Kamstra  <lute@gnu.org>
+
+       Update FSF's address in GPL notices.
+
+2005-07-04  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus.el (gnus-exit):
+       * gnus-group.el (gnus-group-icons):
+       * nnmail.el (nnmail-prepare): Fix typos in docstrings.
+
+       * gnus-nocem.el (gnus-nocem):
+       * message.el (message-various, message-buffers, message-sending)
+       (message-interface, message-forwarding, message-insertion)
+       (message-headers, message-news, message-mail):
+       * pgg-gpg.el (pgg-gpg):
+       * pgg-parse.el (pgg-parse):
+       * pgg-pgp.el (pgg-pgp):
+       * pgg-pgp5.el (pgg-pgp5):
+       * pop3.el (pop3): Finish `defgroup' description with period.
+
+2005-07-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-display-face): Improve the efficiency.
+       (article-display-x-face): Ditto; remove gray x-face stuff.
+
+2005-06-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-display-face): Correct the position in
+       which Faces are inserted.
+
+2005-06-29  Didier Verna  <didier@xemacs.org>
+
+       * gnus-art.el (article-display-face): Display faces in correct
+       order.
+
+2005-06-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-nocem.el (gnus-nocem-verifyer): Default to pgg-verify.
+       (gnus-fill-real-hashtb): Use hash table instead of obarray.
+       (gnus-nocem-check-article): Fetch the Type header.
+       (gnus-nocem-message-wanted-p): Fix the way to examine types.
+       (gnus-nocem-verify-issuer): Use functionp instead of fboundp.
+       (gnus-nocem-enter-article): Use hash tables rather than obarrays;
+       make sure gnus-nocem-hashtb is initialized.
+       (gnus-nocem-alist-to-hashtb): Use hash table instead of obarray.
+       (gnus-nocem-unwanted-article-p): Ditto.
+
+       * pgg.el (pgg-verify): Return the verification result.
+
+2005-06-27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-mime-copy-part): Check whether coding-system
+       is ascii.
+
+2005-06-24  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus-art.el (gnus-article-mode): Set `nobreak-char-display', not
+       `show-nonbreak-escape'.
+
+2005-06-23  Lute Kamstra  <lute@gnu.org>
+
+       * gnus-art.el (gnus-article-mode): Use kill-all-local-variables.
+
+       * dig.el (dig-mode):
+       * smime.el (smime-mode): Use gnus-run-mode-hooks.
+
+2005-06-21  Juanma Barranquero  <lekktu@gmail.com>
+
+       * nnimap.el (nnimap-split-download-body): Fix spellings.
+
+2005-06-16  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus-art.el (gnus-article-encrypt-body):
+       * gnus-cus.el (gnus-score-customize):
+       * mm-extern.el (mm-extern-local-file, mm-inline-external-body):
+       * pop3.el (pop3-user): Don't use `format' on `error' arguments.
+
+2005-06-16  Arne Jørgensen  <arne@arnested.dk>
+
+       * smime.el (smime-cert-by-ldap-1): Detect PEM format without
+       header by looking for magic "MII" at the beginning.
+
+2005-06-16  Miles Bader  <miles@gnu.org>
+
+       * gnus-xmas.el (gnus-xmas-group-startup-message):
+       Use renamed gnus-splash face.
+
+       * assistant.el (assistant-field): Remove "-face" suffix from face name.
+       (assistant-field-face): New backward-compatibility alias for renamed
+       face.
+       (assistant-render-text): Use renamed assistant-field face.
+
+       * spam.el (spam): Remove "-face" suffix from face name.
+       (spam-face): New backward-compatibility alias for renamed face.
+       (spam-face, spam-initialize): Use renamed spam face.
+
+       * message.el (message-header-to, message-header-cc)
+       (message-header-subject, message-header-newsgroups)
+       (message-header-other, message-header-name)
+       (message-header-xheader, message-separator, message-cited-text)
+       (message-mml): Remove "-face" suffix from face names.
+       (message-header-to-face, message-header-cc-face)
+       (message-header-subject-face, message-header-newsgroups-face)
+       (message-header-other-face, message-header-name-face)
+       (message-header-xheader-face, message-separator-face)
+       (message-cited-text-face, message-mml-face):
+       New backward-compatibility aliases for renamed faces.
+       (message-font-lock-keywords): Use renamed message faces.
+
+       * sieve-mode.el (sieve-control-commands, sieve-action-commands)
+       (sieve-test-commands, sieve-tagged-arguments):
+       Remove "-face" suffix from face names.
+       (sieve-control-commands-face, sieve-action-commands-face)
+       (sieve-test-commands-face, sieve-tagged-arguments-face):
+       New backward-compatibility aliases for renamed faces.
+       (sieve-control-commands-face, sieve-action-commands-face)
+       (sieve-test-commands-face, sieve-tagged-arguments-face):
+       Use renamed sieve faces.
+
+       * gnus.el (gnus-group-news-1, gnus-group-news-1-empty)
+       (gnus-group-news-2, gnus-group-news-2-empty, gnus-group-news-3)
+       (gnus-group-news-3-empty, gnus-group-news-4)
+       (gnus-group-news-4-empty, gnus-group-news-5)
+       (gnus-group-news-5-empty, gnus-group-news-6)
+       (gnus-group-news-6-empty, gnus-group-news-low)
+       (gnus-group-news-low-empty, gnus-group-mail-1)
+       (gnus-group-mail-1-empty, gnus-group-mail-2)
+       (gnus-group-mail-2-empty, gnus-group-mail-3)
+       (gnus-group-mail-3-empty, gnus-group-mail-low)
+       (gnus-group-mail-low-empty, gnus-summary-selected)
+       (gnus-summary-cancelled, gnus-summary-high-ticked)
+       (gnus-summary-low-ticked, gnus-summary-normal-ticked)
+       (gnus-summary-high-ancient, gnus-summary-low-ancient)
+       (gnus-summary-normal-ancient, gnus-summary-high-undownloaded)
+       (gnus-summary-low-undownloaded)
+       (gnus-summary-normal-undownloaded, gnus-summary-high-unread)
+       (gnus-summary-low-unread, gnus-summary-normal-unread)
+       (gnus-summary-high-read, gnus-summary-low-read)
+       (gnus-summary-normal-read, gnus-splash):
+       Remove "-face" suffix from face names.
+       (gnus-group-news-1-face, gnus-group-news-1-empty-face)
+       (gnus-group-news-2-face, gnus-group-news-2-empty-face)
+       (gnus-group-news-3-face, gnus-group-news-3-empty-face)
+       (gnus-group-news-4-face, gnus-group-news-4-empty-face)
+       (gnus-group-news-5-face, gnus-group-news-5-empty-face)
+       (gnus-group-news-6-face, gnus-group-news-6-empty-face)
+       (gnus-group-news-low-face, gnus-group-news-low-empty-face)
+       (gnus-group-mail-1-face, gnus-group-mail-1-empty-face)
+       (gnus-group-mail-2-face, gnus-group-mail-2-empty-face)
+       (gnus-group-mail-3-face, gnus-group-mail-3-empty-face)
+       (gnus-group-mail-low-face, gnus-group-mail-low-empty-face)
+       (gnus-summary-selected-face, gnus-summary-cancelled-face)
+       (gnus-summary-high-ticked-face, gnus-summary-low-ticked-face)
+       (gnus-summary-normal-ticked-face)
+       (gnus-summary-high-ancient-face, gnus-summary-low-ancient-face)
+       (gnus-summary-normal-ancient-face)
+       (gnus-summary-high-undownloaded-face)
+       (gnus-summary-low-undownloaded-face)
+       (gnus-summary-normal-undownloaded-face)
+       (gnus-summary-high-unread-face, gnus-summary-low-unread-face)
+       (gnus-summary-normal-unread-face, gnus-summary-high-read-face)
+       (gnus-summary-low-read-face, gnus-summary-normal-read-face)
+       (gnus-splash-face):
+       New backward-compatibility aliases for renamed faces.
+       (gnus-group-startup-message): Use renamed gnus faces.
+
+       * gnus-srvr.el (gnus-server-agent, gnus-server-opened)
+       (gnus-server-closed, gnus-server-denied, gnus-server-offline)
+       (gnus-server-agent): Remove "-face" suffix from face names.
+       (gnus-server-agent-face, gnus-server-opened-face)
+       (gnus-server-closed-face, gnus-server-denied-face)
+       (gnus-server-offline-face):
+       New backward-compatibility aliases for renamed faces.
+       (gnus-server-agent-face, gnus-server-opened-face)
+       (gnus-server-closed-face, gnus-server-denied-face)
+       (gnus-server-offline-face): Use renamed gnus faces.
+
+       * gnus-picon.el (gnus-picon-xbm, gnus-picon):
+       Remove "-face" suffix from face names.
+       (gnus-picon-xbm-face, gnus-picon-face):
+       New backward-compatibility aliases for renamed faces.
+
+       * gnus-cite.el (gnus-cite-attribution, gnus-cite-1, gnus-cite-2)
+       (gnus-cite-3, gnus-cite-4, gnus-cite-5, gnus-cite-6)
+       (gnus-cite-7, gnus-cite-8, gnus-cite-9, gnus-cite-10)
+       (gnus-cite-11): Remove "-face" suffix from face names.
+       (gnus-cite-attribution-face, gnus-cite-face-1, gnus-cite-face-2)
+       (gnus-cite-face-3, gnus-cite-face-4, gnus-cite-face-5)
+       (gnus-cite-face-6, gnus-cite-face-7, gnus-cite-face-8)
+       (gnus-cite-face-9, gnus-cite-face-10, gnus-cite-face-11):
+       New backward-compatibility aliases for renamed faces.
+       (gnus-cite-attribution-face, gnus-cite-face-list)
+       (gnus-article-boring-faces): Use renamed gnus faces.
+
+       * gnus-art.el (gnus-signature, gnus-header-from)
+       (gnus-header-subject, gnus-header-newsgroups, gnus-header-name)
+       (gnus-header-content): Remove "-face" suffix from face names.
+       (gnus-signature-face, gnus-header-from-face)
+       (gnus-header-subject-face, gnus-header-newsgroups-face)
+       (gnus-header-name-face, gnus-header-content-face):
+       New backward-compatibility aliases for renamed faces.
+       (gnus-signature-face, gnus-header-face-alist): Use renamed gnus faces.
+
+       * gnus-sum.el (gnus-summary-selected-face)
+       (gnus-summary-highlight): Use renamed gnus faces.
+       * gnus-group.el (gnus-group-highlight): Likewise.
+
+2005-06-14  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus-sieve.el (gnus-sieve-article-add-rule):
+       * legacy-gnus-agent.el (gnus-agent-unlist-expire-days):
+       * spam-stat.el (spam-stat-buffer-change-to-spam)
+       (spam-stat-buffer-change-to-non-spam): Follow error conventions.
+
+       * message.el (message-is-yours-p):
+       * gnus-sum.el (gnus-auto-select-subject): Fix quoting in docstring.
+
+2005-06-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-view.el (mm-inline-text): Withdraw the last change.
+
+2005-06-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-view.el (mm-inline-text): Turn off adaptive-fill-mode while
+       executing enriched-decode.
+
+2005-06-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-find-buffer-file-coding-system): Don't examine
+       charset of tar files.
+
+2005-06-04  Luc Teirlinck  <teirllm@auburn.edu>
+
+       * gnus-art.el (article-update-date-lapsed): Use `save-match-data'.
+
+2005-06-04  Lute Kamstra  <lute@gnu.org>
+
+       * nnfolder.el (nnfolder-read-folder): Make sure that undo
+       information is never recorded.
+
+2005-06-03  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-art.el (gnus-emphasis-alist): Disable the strikethru thingy.
+
+2005-06-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * pop3.el (pop3-apop): Run md5 in the binary mode.
+
+       * starttls.el (starttls-set-process-query-on-exit-flag):
+       Use eval-and-compile.
+
+2005-05-31  Simon Josefsson  <jas@extundo.com>
+
+       * smime.el (smime-replace-in-string): Define.
+       (smime-cert-by-ldap-1): Use it.
+
+2005-05-31  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-display-x-face): Replace
+       process-kill-without-query by gnus-set-process-query-on-exit-flag.
+
+       * gnus-util.el (gnus-set-process-query-on-exit-flag): Alias to
+       set-process-query-on-exit-flag or process-kill-without-query.
+
+       * html2text.el (html2text-fix-paragraphs): Use `while - re-search'
+       loop instead of replace-regexp.
+
+       * imap.el (imap-ssl-open): Use set-process-query-on-exit-flag
+       instead of process-kill-without-query if it is available.
+
+       * lpath.el: Fbind ldap-search-entries.
+
+       * mm-util.el (mm-insert-file-contents): Bind find-file-hook
+       instead of find-file-hooks if it is available.
+
+       * mml1991.el: Bind pgg-default-user-id when compiling.
+
+       * mml2015.el: Bind pgg-default-user-id when compiling.
+
+       * nndraft.el (nndraft-request-associate-buffer):
+       Use write-contents-functions instead of write-contents-hooks if it is
+       available.
+
+       * nnheader.el (nnheader-find-file-noselect): Bind find-file-hook
+       instead of find-file-hooks if it is available.
+
+       * nntp.el (nntp-open-connection): Replace
+       process-kill-without-query by gnus-set-process-query-on-exit-flag.
+       (nntp-open-ssl-stream): Ditto.
+       (nntp-open-tls-stream): Ditto.
+
+       * starttls.el (starttls-set-process-query-on-exit-flag): Alias to
+       set-process-query-on-exit-flag or process-kill-without-query.
+       (starttls-open-stream-gnutls): Use it instead of
+       process-kill-without-query.
+       (starttls-open-stream): Ditto.
+
+2005-05-31  Ulf Stegemann  <ulf@zeitform.de>  (tiny change)
+
+       * smime.el (smime-cert-by-ldap-1): Don't use
+       replace-regexp-in-string.
+
+2005-05-31  Arne Jørgensen  <arne@arnested.dk>
+
+       * smime-ldap.el (smime-ldap-search): Add compatibility for XEmacs.
+
+       * smime.el (smime-cert-by-ldap-1): Handle certificates distributed
+       in PEM format.  Adjust to the XEmacs compatibility.
+
+2005-05-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * encrypt.el (encrypt-xor-process-buffer): Replace `string-to-int'
+       by `string-to-number'.
+       * gnus-agent.el (gnus-agent-regenerate-group)
+       (gnus-agent-fetch-articles): Ditto.
+       * gnus-art.el (gnus-button-fetch-group): Ditto.
+       * gnus-cache.el (gnus-cache-generate-active)
+       (gnus-cache-articles-in-group): Ditto.
+       * gnus-group.el (gnus-group-set-current-level)
+       (gnus-group-insert-group-line): Ditto.
+       * gnus-score.el (gnus-score-set-expunge-below)
+       (gnus-score-set-mark-below, gnus-summary-score-effect)
+       (gnus-summary-score-entry): Ditto.
+       * gnus-soup.el (gnus-soup-send-packet, gnus-soup-parse-areas)
+       (gnus-soup-pack): Ditto.
+       * gnus-spec.el (gnus-xmas-format): Ditto.
+       * gnus-start.el (gnus-newsrc-to-gnus-format): Ditto.
+       * gnus-sum.el (gnus-create-xref-hashtb): Ditto.
+       * gnus-uu.el (gnus-uu-expand-numbers): Ditto.
+       * nnbabyl.el (nnbabyl-article-group-number): Ditto.
+       * nndb.el (nndb-get-remote-expire-response): Ditto.
+       * nndiary.el (nndiary-parse-schedule-value)
+       (nndiary-string-to-number, nndiary-request-replace-article)
+       (nndiary-request-article): Ditto.
+       * nndoc.el (nndoc-rnews-body-end, nndoc-mbox-body-end): Ditto.
+       * nndraft.el (nndraft-articles, nndraft-request-group): Ditto.
+       * nneething.el (nneething-make-head): Ditto.
+       * nnfolder.el (nnfolder-request-article)
+       (nnfolder-retrieve-headers): Ditto.
+       * nnheader.el (nnheader-file-to-number): Ditto.
+       * nnkiboze.el (nnkiboze-request-article): Ditto.
+       * nnmail.el (nnmail-process-unix-mail-format)
+       (nnmail-process-babyl-mail-format): Ditto.
+       * nnmbox.el (nnmbox-read-mbox, nnmbox-article-group-number): Ditto.
+       * nnmh.el (nnmh-update-gnus-unreads, nnmh-active-number)
+       (nnmh-request-create-group, nnmh-request-list-1)
+       (nnmh-request-group, nnmh-request-article): Ditto.
+       * nnml.el (nnml-request-replace-article, nnml-request-article): Ditto.
+       * nnrss.el (nnrss-find-rss-via-syndic8): Ditto.
+       * nnsoup.el (nnsoup-make-active): Ditto.
+       * nnspool.el (nnspool-find-id, nnspool-request-group): Ditto.
+       * nntp.el (nntp-find-group-and-number)
+       (nntp-retrieve-headers-with-xover): Ditto.
+       * pgg-gpg.el (pgg-gpg-snarf-keys-region): Ditto.
+       * pgg-parse.el (pgg-read-body, pgg-read-bytes)
+       (pgg-format-key-identifier): Ditto.
+       * pop3.el (pop3-last, pop3-stat): Ditto.
+       * qp.el (quoted-printable-decode-region): Ditto.
+
+       * spam-report.el (spam-report-url-ping-mm-url): Use format instead
+       of concat.
+
+2005-05-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-agent.el (gnus-category-mode): Use gnus-run-mode-hooks.
+
+       * gnus-art.el (gnus-article-mode): Use gnus-run-mode-hooks.
+
+       * gnus-cus.el (gnus-custom-mode): Use gnus-run-mode-hooks.
+
+       * gnus-eform.el (gnus-edit-form-mode): Use gnus-run-mode-hooks.
+
+       * gnus-group.el (gnus-group-mode): Use gnus-run-mode-hooks.
+
+       * gnus-kill.el (gnus-kill-file-mode): Use gnus-run-mode-hooks.
+
+       * gnus-salt.el (gnus-tree-mode): Use gnus-run-mode-hooks.
+       (gnus-carpal-mode): Ditto.
+
+       * gnus-srvr.el (gnus-server-mode): Use gnus-run-mode-hooks.
+       (gnus-browse-mode): Ditto.
+
+       * gnus-sum.el (gnus-summary-mode): Use gnus-run-mode-hooks.
+
+       * gnus-util.el (gnus-run-mode-hooks): Save current buffer.
+
+2005-05-29  Richard M. Stallman  <rms@gnu.org>
+
+       * gnus-cite.el (gnus-cite-add-face): Set overlay's evaporate property.
+
+2005-05-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-run-mode-hooks): New function.
+
+       * score-mode.el (gnus-score-mode): Use gnus-run-mode-hooks.
+
+       * dgnushack.el: Advise byte-optimize-form-code-walker to avoid the
+       ``...called for effect'' warnings for Emacs 21.4 as well as 21.3.
+
+2005-05-27  Lute Kamstra  <lute@gnu.org>
+
+       * dns-mode.el (dns-mode): Specify customization group.
+
+2005-05-26  Luc Teirlinck  <teirllm@auburn.edu>
+
+       * gnus-agent.el (gnus-agent-make-mode-line-string):
+       Use mode-line-highlight as mouse-face.
+
+2005-05-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * canlock.el (canlock): Change the parent group to news.
+
+       * deuglify.el (gnus-outlook-deuglify): Add :group.
+
+       * dig.el (dig): Add :group.
+
+       * dns-mode.el (dns-mode): Add :group.
+
+       * encrypt.el (encrypt): Add :group.
+
+       * gnus-cite.el (gnus-cite-attribution-face): Add :group.
+       (gnus-cite-face-1, gnus-cite-face-2, gnus-cite-face-3): Ditto.
+       (gnus-cite-face-4, gnus-cite-face-5, gnus-cite-face-6): Ditto.
+       (gnus-cite-face-7, gnus-cite-face-8, gnus-cite-face-9): Ditto.
+       (gnus-cite-face-10, gnus-cite-face-11): Ditto.
+
+       * gnus-diary.el (gnus-diary): Add :group.
+
+       * gnus.el (gnus-group-news-1-face): Add :group.
+       (gnus-group-news-1-empty-face): Ditto.
+       (gnus-group-news-2-face, gnus-group-news-2-empty-face): Ditto.
+       (gnus-group-news-3-face, gnus-group-news-3-empty-face): Ditto.
+       (gnus-group-news-4-face, gnus-group-news-4-empty-face): Ditto.
+       (gnus-group-news-5-face, gnus-group-news-5-empty-face): Ditto.
+       (gnus-group-news-6-face, gnus-group-news-6-empty-face): Ditto.
+       (gnus-group-news-low-face, gnus-group-news-low-empty-face): Ditto.
+       (gnus-group-mail-1-face, gnus-group-mail-1-empty-face): Ditto.
+       (gnus-group-mail-2-face, gnus-group-mail-2-empty-face): Ditto.
+       (gnus-group-mail-3-face, gnus-group-mail-3-empty-face): Ditto.
+       (gnus-group-mail-low-face, gnus-group-mail-low-empty-face): Ditto.
+       (gnus-summary-selected-face, gnus-summary-cancelled-face): Ditto.
+       (gnus-summary-high-ticked-face): Ditto.
+       (gnus-summary-low-ticked-face): Ditto.
+       (gnus-summary-normal-ticked-face): Ditto.
+       (gnus-summary-high-ancient-face): Ditto.
+       (gnus-summary-low-ancient-face): Ditto.
+       (gnus-summary-normal-ancient-face): Ditto.
+       (gnus-summary-high-undownloaded-face): Ditto.
+       (gnus-summary-low-undownloaded-face): Ditto.
+       (gnus-summary-normal-undownloaded-face): Ditto.
+       (gnus-summary-high-unread-face): Ditto.
+       (gnus-summary-low-unread-face): Ditto.
+       (gnus-summary-normal-unread-face): Ditto.
+       (gnus-summary-high-read-face, gnus-summary-low-read-face): Ditto.
+       (gnus-summary-normal-read-face, gnus-splash-face): Ditto.
+
+       * hashcash.el (hashcash): New custom group.
+       (hashcash-default-payment): Add :group.
+       (hashcash-payment-alist): Ditto.
+       (hashcash-default-accept-payment): Ditto.
+       (hashcash-accept-resources): Ditto.
+       (hashcash-path): Ditto.
+       (hashcash-extra-generate-parameters): Ditto.
+       (hashcash-double-spend-database): Ditto.
+       (hashcash-in-news): Ditto.
+
+       * message.el (message-minibuffer-local-map): Add :group.
+
+       * netrc.el (netrc): Add :group.
+
+       * sieve-manage.el (sieve-manage-log): Add :group.
+       (sieve-manage-default-user): Diito.
+       (sieve-manage-server-eol, sieve-manage-client-eol): Ditto.
+       (sieve-manage-streams, sieve-manage-stream-alist): Ditto.
+       (sieve-manage-authenticators): Ditto.
+       (sieve-manage-authenticator-alist): Ditto.
+       (sieve-manage-default-port): Ditto.
+
+       * sieve-mode.el (sieve-control-commands-face): Add :group.
+       (sieve-action-commands-face): Ditto.
+       (sieve-test-commands-face): Ditto.
+       (sieve-tagged-arguments-face): Ditto.
+
+       * smime.el (smime): Add :group.
+
+       * spam-report.el (spam-report): Add :group.
+
+       * spam.el (spam, spam-face): Add :group.
+
+2005-05-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nntp.el (nntp-next-result-arrived-p): Some news servers may
+       return \n.\n.\n at the end of articles.  Protect against that.
+       (nntp-with-open-group): Allow debugging.
+
+       * nnheader.el (mail-header-set-extra): Make into a function
+       because I just could't understand how to quote the list properly.
+
+       * dns.el (query-dns-cached): New function.
+
+2005-05-26  Lute Kamstra  <lute@gnu.org>
+
+       * score-mode.el (gnus-score-mode): Use run-mode-hooks.
+
+2005-05-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el: Autoload mail-extract-address-components for XEmacs.
+
+       * gnus-art.el: Don't autoload mail-extract-address-components.
+
+       * gnus.el: Remove duplicated autoload for message-y-or-n-p; use
+       eval-and-compile to evaluate it.
+
+       * hashcash.el: Don't autoload executable-find.
+
+       * nndb.el: Don't declare the nndb back end two or more times; don't
+       autoload news-reply-mode, news-setup, cancel-timer and telnet.
+
+       * nntp.el: Autoload format-spec instead of format; use
+       eval-and-compile to evaluate autoload forms.
+
+2005-05-09  Georg C. F. Greve  <greve@gnu.org>  (tiny change)
+
+       * pgg-gpg.el (pgg-gpg-possibly-cache-passphrase): Fix PIN caching.
+
+2005-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Bump version.
+
+2005-05-01  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: No Gnus v0.3 is released.
+
+2005-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * lpath.el (featurep): Bind show-nonbreak-escape.
+
+2005-04-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-edit-part): Disable undo.
+
+2005-04-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-date-ut): Don't delete X-Sent header when
+       gnus-article-date-lapsed-new-header is t if date timer is active;
+       skip headers in which the original date value is empty.
+       (gnus-article-save-original-date): Redefine it as a macro.
+       (gnus-display-mime): Use it.
+
+2005-04-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-date-ut): Support converting date in
+       forwarded parts as well.
+       (gnus-article-save-original-date): New function.
+       (gnus-display-mime): Use it.
+
+2005-04-22  David Hansen  <david.hansen@physik.fu-berlin.de>
+
+       * nnrss.el (nnrss-check-group, nnrss-request-article): Support the
+       enclosure element of <item>.
+
+2005-04-21  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-kill-buffer-query): Rename from
+       `message-kill-buffer-query-if-modified'.  Add :version.
+
+2005-04-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml.el (mml-preview): Bind gnus-message-buffer while setting the
+       window layout.
+
+2005-04-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml.el: Autoload dnd when compiling.
+
+2005-04-18  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mml.el (mml-mode, mml-dnd-attach-file): Use dnd-* instead of
+       x-dnd-*.
+
+2005-04-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * qp.el (quoted-printable-encode-region): Save excursion.
+
+2005-04-14  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * message.el (message-kill-buffer-query-if-modified): Add new variable
+       so the user can kill a modified message buffer quickly.
+       (message-kill-buffer): Use it.
+
+2005-04-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind display-time-event-handler; don't fbind
+       string-to-multibyte.
+
+       * qp.el (quoted-printable-encode-region): Use mm-string-to-multibyte.
+
+2005-04-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnrss.el (nnrss-node-text): Replace CRLFs (which might be
+       contained in text because xml.el decodes entities) with LFs.
+
+2005-04-11  Lute Kamstra  <lute@gnu.org>
+
+       * nnimap.el (nnimap-date-days-ago): Handle byte-compiler warnings
+       differently.
+
+2005-04-10  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * mm-util.el (mm-detect-coding-region): Typo.
+
+2005-04-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-read-summary-keys): Fix misplaced parens.
+
+2005-04-06  Deepak Goel  <deego@gnufans.org>
+
+       * spam-stat.el (spam-stat-score-buffer): Add a call to a
+       user-function allow user modifications of the scores.
+       (spam-stat-score-buffer-user): New function, to allow
+       user-computed modifications to the score.
+       (spam-stat-score-buffer-user-functions): List of additional
+       scoring functions.
+       (spam-stat-error-holder): Global temporary error holder.
+       (spam-stat-split-fancy): Use the new `spam-stat-error-holder'
+       variable.
+
+2005-04-06  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-clean-empty-function)
+       (gnus-registry-trim, gnus-registry-fetch-groups)
+       (gnus-registry-delete-group): Groups that match
+       `gnus-registry-ignored-groups' are removed from the registry
+       entries, not just ignored for splitting.  This helps clean up the
+       registry.  Also, `gnus-registry-fetch-groups' is a convenient way
+       to get all the groups a message ID is in.
+
+       * spam-stat.el (spam-stat-split-fancy-spam-threshold)
+       (spam-stat-split-fancy): Change "threshhold" to "threshold".
+       (spam-stat-score-buffer-user-functions): Add :number custom type.
+
+2005-04-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-coding-system-p): Don't return binary for the nil
+       argument in XEmacs.
+
+       * nnrss.el (nnrss-compatible-encoding-alist): New variable.
+       (nnrss-request-group): Decode group name first.
+       (nnrss-request-article): Make a text/plain article if mml-to-mime
+       failed.
+       (nnrss-get-encoding): Return a compatible encoding according to
+       nnrss-compatible-encoding-alist.
+       (nnrss-find-el): Use consp instead of listp.
+       (nnrss-opml-export, nnrss-order-hrefs, nnrss-find-el): Use dolist.
+
+2005-04-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * time-date.el (time-to-seconds): Don't use the #xhhhh syntax
+       which Emacs 20 doesn't support.
+       (seconds-to-time, days-to-time, time-subtract, time-add): Ditto.
+
+2005-04-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnimap.el (nnimap-date-days-ago): Add defvars in order to
+       silence the byte compiler inside the defun.
+
+       * gnus-demon.el (parse-time-string): Add autoload.
+
+       * gnus-delay.el (parse-time-string): Add autoload.
+
+       * gnus-art.el (parse-time-string): Add autoload.
+
+       * nnultimate.el (parse-time): Require for `parse-time-string'.
+
+2005-03-31  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-copy-article-ignored-headers): Update :version.
+
+       * gnus-score.el (gnus-adaptive-pretty-print): Ditto.
+
+       * smime.el (smime-ldap-host-list): Add :version.
+
+2005-03-21  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-srvr.el (gnus-browse-select-group): Add NUMBER argument and
+       pass it to `gnus-browse-read-group'.
+       (gnus-browse-read-group): Add NUMBER argument and pass it to
+       `gnus-group-read-ephemeral-group'.
+
+       * gnus-group.el (gnus-group-read-ephemeral-group): Add NUMBER
+       argument and pass it to `gnus-group-read-group'.
+
+2005-03-19  Aidan Kehoe  <kehoea@parhasard.net>
+
+       * mm-util.el (mm-xemacs-find-mime-charset): Only call
+       mm-xemacs-find-mime-charset-1 if we have the mule feature
+       available at runtime.
+
+2005-03-25  Werner Lemberg  <wl@gnu.org>
+
+       * nnmaildir.el: Replace `illegal' with `invalid'.
+
+2005-03-23  Lute Kamstra  <lute@gnu.org>
+
+       * time-date.el: Add comment on time value formats.
+       Don't require parse-time.
+       (with-decoded-time-value): New macro.
+       (encode-time-value): New function.
+       (time-to-seconds, time-less-p, time-subtract, time-add): Use them.
+       (days-to-time): Return a valid time value when arg is huge.
+       (time-since): Use time-subtract.
+       (time-to-number-of-days): Use time-to-seconds.
+
+2005-03-22  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-start.el (gnus-display-time-event-handler):
+       Check display-time-timer at runtime rather than only at load time
+       in case display-time-mode is turned off in the mean time.
+
+2005-03-16  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnimap.el (nnimap-open-connection): Print which authinfo file is
+       used.
+
+       * nneething.el (nneething-map-file-directory): Derive from
+       `gnus-directory'.
+
+       * gnus-art.el (gnus-header-button-alist): Use `gnus-msg-mail' for
+       the To/Cc button.
+
+2005-03-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnmaildir.el (nnmaildir-request-accept-article):
+       Use `nnheader-cancel-timer' for compatibility with current XEmacs.
+
+2005-03-13  Andrey Slusar  <anrays@gmail.com>  (tiny change)
+
+       * gnus-async.el: Require timer-funcs at compile time when in
+       XEmacs for `run-with-idle-timer'.
+
+2005-03-13  Andrey Slusar  <anrays@gmail.com>  (tiny change)
+
+       * gnus.el: Don't try and mark `gnus-agent-save-groups' as an
+       autoloaded function.
+
+2005-03-10  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * nnimap.el (nnimap-retrieve-headers-from-server): Fix last change.
+
+2005-03-10  Arne Jørgensen  <arne@arnested.dk>  (tiny change)
+
+       * nnimap.el (nnimap-retrieve-headers-from-server): Fix off-by-one flaw.
+
+2005-03-09  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-confirm-mail-reply-to-news):
+       Add gnus-expert-user to default.
+
+2005-03-08  Juergen Kreileder  <jk@blackdown.de>  (tiny change)
+
+       * nnimap.el (nnimap-open-server): Ditto.
+
+       * imap.el (imap-authenticate): Fix typo.
+
+2005-03-08  Bjorn Solberg  <bjorn_ding@hekneby.org>  (tiny change)
+
+       * nnimap.el (nnimap-retrieve-headers-from-server): Sort NOV
+       buffer (since IMAP server might return FETCH response out of
+       order, and the nntp buffer must be sorted).
+
+2005-03-06  Kevin Greiner  <kevin.greiner@compsol.cc>
+
+       * gnus-start.el (gnus-convert-old-newsrc): Fix numeric
+       comparison on string.
+
+       * gnus-agent.el (gnus-agent-long-article, gnus-agent-short-article)
+       (gnus-agent-score): Rename category keywords to match gnus-cus.
+       (gnus-agent-summary-fetch-series): Modify to protect against
+       gnus-agent-summary-fetch-group clearing processable flags.
+       (gnus-agent-synchronize-group-flags): Update live group buffer as
+       synchronization may occur due to the user toggle the plugged
+       status.
+       (gnus-agent-fetch-group-1): Clear downloadable flag when article
+       successfully downloaded.
+       (gnus-agent-expire-group-1): Avoid using markers when the overview
+       is in ascending order; greatly improves performance.
+       (gnus-agent-regenerate-group):
+       Use gnus-agent-synchronize-group-flags to reset read status in both
+       gnus and server.
+       (gnus-agent-update-files-total-fetched-for): Fix initial size.
+
+2005-03-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el: Don't autoload former message-utils variables.
+       (message-strip-subject-trailing-was): Change doc string.
+
+       * nnweb.el: Fixes for `gnus-group-make-web-group'.
+       (nnweb-type-definition): Don't add "hl=en" in `address'.  Add `base'.
+       (nnweb-google-search): Add "hl=en" here.
+       (nnweb-google-parse-1, nnweb-google-create-mapping):
+       Don't hardcode URL.
+
+2005-03-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-get-reply-headers, message-followup):
+       Mention related variables `message-use-followup-to' and
+       `message-use-mail-followup-to', in the information buffer.
+
+       * nnweb.el (nnweb-type-definition): Use groups.google.de instead
+       of broken groups(-beta).google.com.
+
+2005-03-03  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-sum.el (gnus-summary-move-article): Pass move-is-internal
+       parameter to invoked gnus-request-move-article; remove the
+       redundant gnus-sum-hint-move-is-internal variable; apply the marks
+       all at once instead of once per article.
+       (gnus-summary-remove-process-mark): Accept a list of articles as
+       well as a single article for processing.
+
+       * gnus-int.el (gnus-request-move-article): Add move-is-internal
+       parameter.
+
+       * nnml.el (nnml-request-move-article): Add move-is-internal parameter.
+
+       * nnmh.el (nnmh-request-move-article): Add move-is-internal parameter.
+
+       * nnmbox.el (nnmbox-request-move-article): Add move-is-internal
+       parameter.
+
+       * nnmaildir.el (nnmaildir-request-move-article): Add move-is-internal
+       parameter.
+
+       * nnimap.el (nnimap-request-move-article): Add move-is-internal
+       parameter and remove the gnus-sum-hint-move-is-internal variable.
+
+       * nnfolder.el (nnfolder-request-move-article): Add move-is-internal
+       parameter.
+
+       * nndraft.el (nndraft-request-move-article): Add move-is-internal
+       parameter.
+
+       * nndiary.el (nndiary-request-move-article): Add move-is-internal
+       parameter.
+
+       * nndb.el (nndb-request-move-article): Add move-is-internal parameter.
+
+       * nnbabyl.el (nnbabyl-request-move-article): Add move-is-internal
+       parameter.
+
+       * nnagent.el (nnagent-request-move-article): Add move-is-internal
+       parameter.
+
+2005-03-01  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-sum.el (gnus-summary-exit): Undo last change and fix it in
+       a more conservative way.
+
+2005-02-26  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-sum.el (gnus-summary-exit): Move point after displaying the
+       buffer, so it moves the window's cursor.
+
+2005-02-26  Arne Jørgensen  <arne@arnested.dk>
+
+       * mm-decode.el (mm-dissect-buffer): Pass the from field on to
+       `mm-dissect-multipart' and receive the from field as an (optional)
+       argument from `mm-dissect-multipart'.
+       (mm-dissect-multipart): Receive the from field as an argument and
+       pass it on when we call `mm-dissect-buffer' on MIME parts.
+       Fixes verification/decryption of signed/encrypted MIME parts.
+
+2005-02-25  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-sum.el (gnus-summary-move-article):
+       Set gnus-sum-hint-move-is-internal for gnus-request-move-article and
+       whatever it calls (right now, only nnimap-request-move article
+       respects it).
+
+       * nnimap.el (nnimap-request-move-article):
+       When gnus-sum-hint-move-is-internal is set, don't do the extra
+       nnimap-request-article.
+
+2005-02-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nnheader.el (nnheader-find-file-noselect): Add doc string.
+
+       * nnfolder.el (nnfolder-read-folder): Use RAWFILE for
+       `nnheader-find-file-noselect' to avoid `large-file-warning-threshold'.
+
+       * gnus-sum.el (gnus-summary-caesar-message):
+       Apply `gnus-treat-article' after rotation.
+
+       * gnus-group.el (gnus-group-clear-data): Mention process/prefix in
+       doc string.
+
+2005-02-22  Simon Josefsson  <jas@extundo.com>
+
+       * encrypt.el (encrypt-password-cache-expiry): Remove (use
+       `password-cache-expiry' instead).  Reported by Arne Jørgensen
+       <arne@arnested.dk>.
+       (encrypt): Add password-cache and password-cache-expiry as group
+       members.
+
+2005-02-22  Arne Jørgensen  <arne@arnested.dk>
+
+       * smime.el (smime-ldap-host-list): Doc fix.
+       (smime-ask-passphrase): Use `password-read-and-add' to read (and
+       cache) password.
+       (smime-sign-region): Use it.
+       (smime-decrypt-region): Use it.
+       (smime-sign-buffer): Signal an error if `smime-sign-region' fails.
+       (smime-encrypt-buffer): Signal an error if `smime-encrypt-region'
+       fails.
+       (smime-cert-by-ldap-1): Use `base64-encode-string' to convert
+       certificate from DER to PEM format rather than calling openssl.
+
+       * mml-smime.el (mml-smime-encrypt-query): Remove obsolete comment.
+
+       * mml-sec.el (mml-secure-message): Insert keyfile/certfile tags
+       for signing/encryption.
+
+       * mml.el (mml-parse-1): Use them.
+
+2005-02-21  Arne Jørgensen  <arne@arnested.dk>
+
+       * nnrss.el (nnrss-verbose): Remove.
+       (nnrss-request-group): Use `nnheader-message' instead.
+
+2005-02-19  Mark Plaksin  <happy@usg.edu>  (tiny change)
+
+       * nnrss.el (nnrss-verbose): New variable.
+       (nnrss-request-group): Make it say nnrss is requesting a group.
+
+2005-02-21  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-parse-news-url, gnus-button-handle-news):
+       Handle news URL with given port correctly.
+
+2005-02-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-copy-article-buffer): Quote decoded words
+       containing special characters.
+
+       * gnus-sum.el (gnus-summary-edit-article): Ditto.
+
+       * mml.el (mime-to-mml): Ditto.
+
+       * rfc2047.el (rfc2047-encode-parameter): Use ietf-drums-tspecials.
+       (rfc2047-quote-decoded-words-containing-tspecials): New variable.
+       (rfc2047-decode-region): Quote decoded words containing special
+       characters when rfc2047-quote-decoded-words-containing-tspecials
+       is non-nil.
+
+2005-02-16  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-delete-group): Add minor bug fix.
+
+       * gnus.el (gnus-install-group-spam-parameters): Add minor doc fix.
+
+2005-02-15  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap-debug): Doc fix.
+
+       * imap.el (imap-debug): Doc fix.
+
+2005-02-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el: Avoid "Recursive load suspected" error in Emacs 21.1.
+
+2005-02-14  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.el (spam-contents): Improve docs for spam-contents
+       parameter in its variable incarnation.
+
+2005-02-14  Simon Josefsson  <jas@extundo.com>
+
+       * smime-ldap.el: Use require instead of load-library for ldap.
+       (smime-ldap-search): Indent.
+       (smime-ldap-search-internal): Shorten line.
+
+       * smime.el (smime-cert-by-dns): Add doc-string.
+       (smime-cert-by-ldap-1): Indent.
+
+       * mml-smime.el (mml-smime-get-ldap-cert): Rename from
+       mml-smime-get-dns-ldap.
+       (mml-smime-encrypt-query): Use new function.  Default to ldap.
+
+2005-02-14  Arne Jørgensen  <arne@arnested.dk>
+
+       * smime.el: Require smime-ldap.
+       (smime-ldap-host-list): New variable.
+       (smime-cert-by-ldap, smime-cert-by-ldap-1): New functions.
+
+       * mml-smime.el (mml-smime-encrypt-query): New function.
+       (mml-smime-encrypt-query): Use it.
+
+       * smime-ldap.el: New file.
+
+2005-02-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-agent.el: Remove garbage made while merging the Emacs trunk.
+
+2005-02-14  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-group.el (gnus-group-make-doc-group): Mention prefix
+       argument in doc string.  Make query for type more clear.
+
+2005-02-13  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.el (gnus-group-startup-message): Search for gnus images in
+       etc/images/gnus.
+       * mm-util.el (mm-image-load-path): Likewise.
+       * smiley.el (smiley-data-directory): Search for smilies in
+       etc/images/smilies.
+
+2005-02-09  Kim F. Storm  <storm@cua.dk>
+
+       Change Emacs release version from 21.4 to 22.1 throughout.
+       Change Emacs development version from 21.3.50 to 22.0.50.
+
+2005-02-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-copy-part): Don't decode compressed parts.
+
+       * mm-util.el (mm-coding-system-to-mime-charset): Make it work with
+       non-Mule XEmacs as well.
+       (mm-decompress-buffer): Signal an error intentionally if it does
+       not decompress compressed data because auto-compression-mode is
+       disabled.
+
+2005-02-11  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-delete-group): Fix bug: leaves
+       an ID in the registry even if it has no groups.
+
+2005-02-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-jka-compr-maybe-uncompress): Remove;
+       merge it into mm-decompress-buffer.
+       (gnus-mime-copy-part): Use the MIME part charset, the value which
+       a user specified or gnus-newsgroup-charset for decoding, like
+       gnus-mime-inline-part does; set buffer-file-coding-system to tell
+       save-buffer what was used.  Suggested by Kevin Ryde
+       <user42@zip.com.au>.
+       (gnus-mime-inline-part): Allow the name parameter as well as the
+       filename parameter; force decompressing of compressed data; always
+       display contents being not decoded as unibyte.
+
+       * mm-view.el (mm-display-inline-fontify): Allow the name parameter
+       as well as the filename parameter.
+
+       * mm-util.el (mm-decompress-buffer):
+       Merge gnus-mime-jka-compr-maybe-uncompress.
+       (mm-find-buffer-file-coding-system): Doc fix; force decompressing
+       of compressed data.
+
+2005-02-08  Simon Josefsson  <jas@extundo.com>
+
+       * imap.el (imap-log): Doc fix.
+
+2005-02-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-inline-part): Decode parts according to
+       the coding cookies; decompress compressed parts.
+
+       * mml.el (mml-generate-mime-1): Add the charset parameter according
+       to the value which a user specified manually or the coding cookie.
+
+       * mm-util.el (mm-string-to-multibyte): New function.
+       (mm-detect-mime-charset-region): Work with Emacs 22 as well.
+       (mm-coding-system-to-mime-charset): New function.
+       (mm-decompress-buffer): New function.
+       (mm-find-buffer-file-coding-system): New function.
+
+       * mm-view.el (mm-insert-inline): Make sure a part ends with a newline.
+       (mm-display-inline-fontify): Rewrite for decoding and decompressing
+       parts.
+
+2005-02-07  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * mm-view.el (mm-display-inline-fontify): Decode a part according
+       to the charset parameter.
+
+2005-02-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-inline-part): Show the raw contents if a
+       prefix arg is neither nil nor a number, as info specifies.
+
+2005-02-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nntp.el (nntp-marks-changed-p): Use time-less-p to compare the
+       timestamps.
+
+2005-02-02  Jari Aalto  <jari.aalto@cante.net>
+
+       * gnus-sum.el (gnus-list-of-unread-articles): Improve active
+       groups error checking and notify user.
+
+2005-02-02  Jari Aalto  <jari.aalto@poboxes.com>
+
+       * message.el (message-send-mail-function): Check existence of
+       sendmail-program first before using default value
+       `message-send-mail-with-sendmail'.  Otherwise use more generic
+       `smtpmail-send-it'.
+
+2005-02-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nntp.el (nntp-request-update-info): Always return nil.
+
+2005-01-30  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-art.el (gnus-article-mode): Turn off the "\ " non-break space.
+
+2005-01-28  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * message.el (message-beginning-of-line): Change the behavior when
+       invoked between BOL and : so that it first moves backward.
+
+2005-01-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-setup-buffer): Kill and re-create the
+       article buffer when editing of the article is discarded.
+       (gnus-article-prepare): Revert.
+
+2005-01-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-prepare):
+       Remove message-strip-forbidden-properties from the local hook.
+
+2005-01-27  Simon Josefsson  <jas@extundo.com>
+
+       * password.el (password-cache-add): Only start one timer per key.
+       Reported by Derek Atkins <warlord@MIT.EDU>.
+
+2005-01-26  Steve Youngs  <steve@sxemacs.org>
+
+       * run-at-time.el: Remove.  It is no longer needed as
+       timer-funcs.el in the xemacs-base package has a working version of
+       `run-at-time'.
+
+       * gnus-xmas.el: Require timer-funcs instead of run-at-time.
+
+       * password.el: Require timer-funcs instead of run-at-time in
+       XEmacs.
+       Remove `password-run-at-time' macro.
+       (password-cache-add): Use `run-at-time' instead of
+       `password-run-at-time'.
+
+       * nnheaderxm.el: Require timer-funcs instead of run-at-time.
+       Remove `nnheader-cancel-function-timers' alias,
+       `cancel-function-timers' exists in XEmacs in timer-funcs.
+
+       * mail-source.el: Require timer-funcs instead of itimer in XEmacs
+       for `run-with-idle-timer'.
+
+       * gnus-demon.el: Require timer-funcs instead of itimer in XEmacs
+       for `run-at-time'.
+
+       * mm-url.el: Require timer-funcs at compile time when in XEmacs
+       for `with-timeout'.
+
+       * dgnushack.el: Autoload the correct `setenv' for SXEmacs which is
+       the same as for XEmacs 21.4.
+       No need to ignore `run-with-idle-timer', this function exists in
+       XEmacs now in timer-funcs.el in the xemacs-base package.
+       (dgnushack-compile): No need to delete
+       run-at-time.el from the list of files to compile because it
+       doesn't exist anymore.
+
+2005-01-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml.el (mml-generate-mime-1): Convert string into unibyte when
+       inserting " *mml*" buffer's contents into a unibyte temp buffer.
+
+2005-01-24  Harald Meland  <harald.meland@usit.uio.no>  (tiny change)
+
+       * mail-source.el (mail-source-fetch-imap): Search for ^From case
+       sensitively.
+
+2005-01-21  Derek Atkins  <warlord@MIT.EDU>  (tiny change)
+
+       * pgg-pgp.el (pgg-pgp-decrypt-region): Use passphrase cache.
+
+2005-01-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-insert-part): Switch the multibyteness of data
+       which will be inserted according to the multibyteness of a buffer
+       rather than the type of contents.  Suggested by ARISAWA Akihiro
+       <ari@mbf.ocn.ne.jp>.
+
+       * nnrss.el (nnrss-find-el): Check carefully whether there's a list
+       of string which old xml.el may return rather than a string.
+
+2005-01-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-idna-message): Silence byte compiler.
+
+2005-01-16  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-summary-idna-message): Fail gracefully if
+       idn/idna.el isn't available.
+       (gnus-summary-idna-message): Doc fix.  Suggested by Michael Cook
+       <michael@waxrat.com>.
+
+       * hashcash.el: Remove non-FSF copyright header.
+
+       * hashcash.el (hashcash-extra-generate-parameters): New variable.
+       (hashcash-generate-payment): Use it.
+       (hashcash-generate-payment-async): Use it.
+
+2005-01-15  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-idna-to-ascii-rhs): Decode Reply-To too.
+       Suggested by Raymond Scholz <ray-2005@zonix.de>.
+
+       * gnus-sum.el (gnus-summary-wash-map): Bind "W i" to
+       gnus-summary-idna-message.
+       (gnus-summary-make-menu-bar): Add De-IDNA menu entry.
+       (gnus-summary-idna-message): New function.
+
+2005-01-13  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-msg.el (gnus-confirm-mail-reply-to-news): Change default to
+       gnus-novice-user.
+
+2005-01-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnrss.el (nnrss-request-delete-group): Delete entries in
+       nnrss-group-alist as well.
+       (nnrss-save-server-data): Insert newline.
+
+2005-01-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.el (gnus-user-agent): Use list of symbols instead of
+       symbols.  Display full version number for (S)XEmacs.
+       Optionally display (S)XEmacs codename.
+
+       * gnus-util.el (gnus-emacs-version): Update for new
+       `gnus-user-agent'.
+
+       * gnus-msg.el (gnus-extended-version): Make it possible to omit
+       Gnus version.
+
+2005-01-05  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * spam.el (spam-face): New face.  Don't use `gnus-splash-face'
+       which is unreadable in some setups.
+
+2005-01-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-spec.el (gnus-update-format-specifications): Flush the
+       group format spec cache if it doesn't support decoded group names.
+
+2005-01-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-score.el (gnus-decay-scores, gnus-score-load-file):
+       Allow to apply decay on score files matching a regexp.
+
+2004-12-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el (gnus-group-line-format-alist): Keep the forward
+       compatibility in %g and %c.
+
+2004-12-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el (gnus-group-line-format-alist): Use decoded group
+       name for only %g and %c.
+       (gnus-group-insert-group-line): Bind gnus-tmp-decoded-group instead
+       of gnus-tmp-group to decoded group name.
+       (gnus-group-make-rss-group): Exclude `/'s from group names.
+
+2004-12-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnrss.el (nnrss-get-encoding): Fix regexp.
+
+2004-12-27  Simon Josefsson  <jas@extundo.com>
+
+       * mm-bodies.el (mm-body-encoding): Don't permit 7-bit to be used when
+       mm-use-ultra-safe-encoding is enabled (e.g., for PGP/MIME) and we have
+       trailing white space.  Reported by Werner Koch <wk@gnupg.org>.
+
+2004-12-17  Kim F. Storm  <storm@cua.dk>
+
+       * gnus-group.el (gnus-group-mode-map): Map follow-link to mouse-face.
+
+       * gnus-sum.el (gnus-summary-mode-map): Likewise.
+
+2004-12-26  Tsuyoshi AKIHO  <akiho@kawachi.zaq.ne.jp>
+
+       * gnus-sum.el (gnus-summary-walk-group-buffer): Decode group name.
+
+2004-12-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnrss.el: Require rfc2047 and mml.
+       (nnrss-file-coding-system): New variable.
+       (nnrss-format-string): Redefine it as an inline function.
+       (nnrss-decode-group-name): New function.
+       (nnrss-string-as-multibyte): Remove.
+       (nnrss-retrieve-headers): Decode group name; don't use
+       nnrss-format-string.
+       (nnrss-request-group): Decode group name.
+       (nnrss-request-article): Decode group name; allow a Message-ID as
+       well as an article number; don't use nnrss-format-string; encode a
+       Message-ID string which may contain non-ASCII characters; use
+       mml-to-mime to compose a MIME article.
+       (nnrss-request-expire-articles): Decode group name.
+       (nnrss-request-delete-group): Decode group name.
+       (nnrss-fetch): Clarify error message.
+       (nnrss-read-server-data): Use insert-file-contents instead of load;
+       bind file-name-coding-system; use multibyte buffer.
+       (nnrss-save-server-data): Bind coding-system-for-write to the
+       value of nnrss-file-coding-system; bind file-name-coding-system;
+       add coding cookie.
+       (nnrss-read-group-data): Use insert-file-contents instead of load;
+       bind file-name-coding-system; use multibyte buffer.
+       (nnrss-save-group-data): Bind coding-system-for-write to the
+       value of nnrss-file-coding-system; bind file-name-coding-system.
+       (nnrss-decode-entities-string): Rename from n-d-e-unibyte-string;
+       make it work with non-ASCII text.
+       (nnrss-find-el): Make it work with old xml.el as well.
+
+2004-12-26  Tsuyoshi AKIHO  <akiho@kawachi.zaq.ne.jp>
+
+       * nnrss.el (nnrss-get-encoding): New function.
+       (nnrss-fetch): Use unibyte buffer initially; bind
+       coding-system-for-read while performing mm-url-insert; remove ^Ms;
+       decode contents according to the encoding attribute.
+       (nnrss-save-group-data): Add coding cookie.
+       (nnrss-mime-encode-string): New function.
+       (nnrss-check-group): Use it to encode subject and author.
+
+2004-12-23  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-check-BBDB): Don't get the symbol-value of an
+       imaginary variable.
+
+2004-12-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-spec.el (gnus-spec-tab): Make a Lisp form which works
+       correctly even if there are wide characters.
+
+2004-12-21  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-check-BBDB): Fix the BBDB caching code to use
+       downcased symbol names; make a new cache instead of reusing
+       bbdb-hashtable.
+
+2004-12-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2231.el (rfc2231-parse-string): Decode encoded value after
+       concatenating segments rather than before concatenating them.
+       Suggested by ARISAWA Akihiro <ari@mbf.ocn.ne.jp>.
+
+       * message.el (message-get-reply-headers): Bind `extra'.
+
+2004-12-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-extra-wide-headers): New variable.
+       (message-get-reply-headers): Use it.
+
+2004-12-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-agent.el (gnus-agent-group-path): Decode group name.
+       (gnus-agent-group-pathname): Ditto.
+
+       * gnus-cache.el (gnus-cache-file-name): Decode group name.
+
+       * gnus-group.el (gnus-group-make-group): Decode group name.
+       (gnus-group-make-rss-group): Register the group data after opening
+       the nnrss group.
+
+2004-12-17  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir-request-expire-articles): Articles moved
+       by expiry now get marked as read.
+
+2004-12-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-xemacs-find-mime-charset): New macro.
+
+2004-12-17  Aidan Kehoe  <kehoea@parhasard.net>
+
+       * mm-util.el (mm-xemacs-find-mime-charset-1): New function used to
+       unify Latin characters in XEmacs.
+       (mm-find-mime-charset-region): Use it.
+
+2004-12-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-delete-directory): New function.
+
+       * gnus-agent.el (gnus-agent-delete-group): Use it.
+
+       * gnus-cache.el (gnus-cache-delete-group): Use it.
+
+2004-12-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el (gnus-group-make-rss-group): Unify non-ASCII group
+       names.
+
+2004-12-16  Simon Josefsson  <jas@extundo.com>
+
+       * hashcash.el (hashcash-payment-alist): Fix custom :type.
+
+2004-12-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-url.el (mm-url-predefined-programs): Add --silent arg to curl.
+
+       * gnus-group.el (gnus-group-expire-articles-1): Decode group name.
+       (gnus-group-set-current-level): Decode group name.
+
+2004-12-15  Maciek Pasternacki  <maciekp@japhy.fnord.org>  (tiny change)
+
+       * nnrss.el (nnrss-fetch): Signal an error if w3-parse-buffer also
+       failed.
+
+2004-12-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el (gnus-group-delete-group): Decode group name.
+       (gnus-group-make-rss-group): Encode group name.
+       (gnus-group-catchup-current): Decode group name.
+       (gnus-group-kill-group): Decode group name.
+
+2004-12-08  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-art.el (gnus-narrow-to-page): Don't hardcode point-min.
+
+2004-12-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el (gnus-group-make-rss-group):
+       Use gnus-group-make-group instead of gnus-group-unsubscribe-group.
+
+       * gnus-start.el (gnus-setup-news): Honor user's setting to
+       gnus-message-archive-method.  Suggested by Lute Kamstra
+       <lute@gnu.org>.
+
+2004-12-10  Arnaud Giersch  <arnaud.giersch@free.fr>  (tiny change)
+
+       * gnus-sum.el (gnus-summary-exit-no-update): Don't clear the
+       global counterparts of the buffer-local variables.
+
+2004-11-16  Romain Francoise  <romain@orebokech.com>
+
+       * gnus-sum.el (gnus-summary-exit): Don't clear the global
+       counterparts of the buffer-local variables.
+
+2004-11-25  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-forbidden-properties): Fix typo in doc
+       string.
+
+2004-11-25  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-util.el (gnus-replace-in-string): Add doc string.
+
+       * nnmail.el (nnmail-split-header-length-limit): Increase to 2048
+       to avoid problems when splitting mails with many recipients.
+
+2004-11-22  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-sum.el (gnus-summary-exit): Remove redundant and harmful
+       pop-to-buffer, covered by the subsequent gnus-configure-windows.
+
+2004-12-05  Nelson Ferreira  <nelson.ferreira@ieee.org>
+
+       * spam-stat.el (spam-stat-save): Load the hashtable from disk only
+       if there is no hashtable in memory or file modification time is
+       newer than cached timestamp.
+
+2004-12-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-summary-limit-to-recipient):
+       Implement not-matching option.
+
+2004-12-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-summary-limit-to-recipient): New function.
+       Suggested David Mazieres in analogy to rmail-summary-by-recipients.
+       (gnus-summary-limit-map, gnus-summary-make-menu-bar): Add it.
+       (gnus-article-sort-by-recipient, gnus-summary-sort-by-recipient):
+       New functions.  Suggested by Uwe Brauer <oub@mat.ucm.es>.
+       (gnus-summary-mode-map, gnus-summary-make-menu-bar): Add it.
+
+2004-12-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-forward-make-body-mml): Remove headers
+       according to message-forward-ignored-headers if a message is decoded.
+
+2004-12-02  Romain Francoise  <romain@orebokech.com>
+
+       * message.el (message-forward-make-body-plain): Always remove
+       headers according to message-forward-ignored-headers.
+
+2004-12-01  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-summary-prepare-exit): Remove the
+       gnus-summary-limit pop for now, it has problems with ham marks for
+       me.
+
+2004-11-29  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-summary-prepare-exit): Use gnus-summary-limit
+       correctly.
+
+2004-11-28  Carl Henrik Lunde  <chlunde+bugs+@ping.uio.no>  (tiny change)
+
+       * format-spec.el (format-spec): Message the char.
+
+2004-11-26  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-art.el (gnus-split-methods): Reformat comments.
+
+       * spam.el (spam-summary-prepare-exit): Remove article limits
+       before exiting the summary buffer.
+
+2004-11-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Remove bbdb-create-internal, bbdb-records,
+       spam-BBDB-register-routine and spam-enter-ham-BBDB.
+
+       * nnrss.el (nnrss-string-as-multibyte): Redefine it as a macro in
+       order to silence the byte compiler.
+
+       * spam.el: Fix the way to silence the byte compiler, which
+       complained about bbdb-buffer, bbdb-create-internal, bbdb-records,
+       bbdb-search-simple, spam-BBDB-register-routine,
+       spam-enter-ham-BBDB, spam-stat-buffer-change-to-non-spam,
+       spam-stat-buffer-change-to-spam, spam-stat-buffer-is-non-spam,
+       spam-stat-buffer-is-spam, spam-stat-load,
+       spam-stat-register-ham-routine, spam-stat-register-spam-routine,
+       spam-stat-save and spam-stat-split-fancy.
+
+2004-11-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * canlock.el (canlock-password): Remove `:size 0' or `:size 1'
+       which may confuse users.
+       (canlock-password-for-verify): Ditto.
+
+       * deuglify.el (gnus-outlook-deuglify-unwrap-stop-chars): Ditto.
+
+       * gnus-art.el (gnus-emphasis-alist): Ditto.
+
+       * gnus-registry.el (gnus-registry-max-entries): Ditto.
+
+       * gnus-score.el (gnus-adaptive-word-length-limit): Ditto.
+
+       * gnus-start.el (gnus-save-killed-list): Ditto.
+
+       * gnus-sum.el (gnus-thread-hide-subtree): Ditto.
+       (gnus-sum-thread-tree-root): Ditto.
+       (gnus-sum-thread-tree-false-root): Ditto.
+       (gnus-sum-thread-tree-single-indent): Ditto.
+
+       * message.el (message-courtesy-message): Ditto.
+       (message-archive-note): Ditto.
+       (message-subscribed-address-file): Ditto.
+       (message-user-fqdn): Ditto.
+
+       * spam-report.el (spam-report-gmane-regex): Ditto.
+
+       * spam.el (spam-blackhole-good-server-regex): Ditto.
+
+2004-11-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml.el (mml-preview): Widen the message buffer before copying
+       the contents to the preview buffer; sort headers before previewing.
+
+       * message.el (message-hidden-headers): Fix the way to avoid a bug
+       in the `repeat' widget in Emacs 21.3 or earlier.
+
+2004-11-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-hidden-headers): Default to "^References:".
+       Improve customization type.  Suggested by Reiner Steib
+       <Reiner.Steib@gmx.de>.
+
+2004-11-25  Romain Francoise  <romain@orebokech.com>
+
+       * message.el (message-strip-forbidden-properties): Remove check for
+       obsolete `message-hidden' text property, hidden headers are not
+       accessible in the buffer anymore.
+
+2004-11-22  Romain Francoise  <romain@orebokech.com>
+
+       * message.el (message-header-format-alist): Add `From' in list
+       so that it can be sorted.
+       (message-fix-before-sending): Widen and sort headers before
+       sending.
+       (message-hide-headers): Use narrowing to hide headers by moving
+       them to the top of the buffer and narrowing to the region
+       underneath.
+
+2004-11-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-strip-forbidden-properties):
+       Bind buffer-read-only (etc) to nil.
+
+2004-11-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-header-encoding-alist): Add In-Reply-To to
+       address-mime.  Suggested by ARISAWA Akihiro <ari@mbf.ocn.ne.jp>.
+
+2004-11-22  Marek Martin  <marek.martin@mum.pri.ee>  (tiny change)
+
+       * nnfolder.el (nnfolder-request-create-group): Save current buffer.
+
+2004-11-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * dns.el (query-dns): Use sit-for to time instead of
+       accept-process-output, since that doesn't seem to work on udp
+       sockets.
+
+2004-11-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-encode-region): Encode bogus delimiters.
+
+2004-11-15  Jesper Harder  <harder@ifa.au.dk>
+
+       * pop3.el (pop3-leave-mail-on-server): Don't quote nil in
+       doc string.  Improve doc string.
+
+2004-11-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nntp.el (nntp-request-update-info): Return nil if
+       nntp-marks-is-evil is true so that gnus-get-unread-articles-in-group
+       may not call gnus-activate-group which uselessly issues the GROUP
+       commands for all nntp groups and wastes time.  Reported by Romain
+       Francoise <romain@orebokech.com>.
+
+       * gnus-start.el (gnus-get-unread-articles): Remove redundant test.
+
+2004-11-15  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-art.el (gnus-header-button-alist): Handle URLs in OpenPGP:
+       headers separately.
+       (gnus-button-openpgp): New function, inspired by Jochen Küpper
+       <jochen-+It19tn3Rl9sbm7dSapR3bNAH6kLmebB@public.gmane.org>.
+
+2004-11-14  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-start.el (gnus-convert-old-newsrc):
+       Assign legacy-gnus-agent to 5.10.7.
+
+2004-11-14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-unsplit-urls): Don't anchor urls to the
+       start of the lines.
+
+2004-11-14  Magnus Henoch  <mange@freemail.hu>
+
+       * hashcash.el (hashcash-default-payment): Change default to 20.
+       (hashcash-default-accept-payment): Change default to 20.
+       (hashcash-process-alist): New variable.
+       (hashcash-generate-payment-async): Add.
+       (hashcash-already-paid-p): Add.
+       (hashcash-insert-payment): Don't generate payments twice.
+       (hashcash-insert-payment-async): Add.
+       (hashcash-insert-payment-async-2): Add.
+       (hashcash-cancel-async): Add.
+       (hashcash-wait-async): Add.
+       (hashcash-processes-running-p): Add.
+       (hashcash-wait-or-cancel): Add.
+       (mail-add-payment): New optional argument.  Conditionally start
+       asynchronous calculation.
+       (mail-add-payment-async): Add.
+
+       * message.el (message-send-mail): Wait for asynchronous hashcash
+       results.  Don't clobber existing X-Hashcash headers.
+       (message-setup-1): Call mail-add-payment-async when
+       message-generate-hashcash is non-nil.
+
+2004-11-11  ARISAWA Akihiro  <ari@mbf.ocn.ne.jp>  (tiny change)
+
+       * message.el (message-use-alternative-email-as-from): Examine the
+       From header as well; use message-make-from in order to include a
+       user's full name.
+
+2004-11-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-emphasis-alist): Don't hide asterisks by
+       default; improve customization type.
+       (gnus-emphasis-custom-with-format): New macro.
+       (gnus-emphasis-custom-value-to-external): New function.
+       (gnus-emphasis-custom-value-to-internal): New function.
+
+2004-11-09  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * dns.el (query-dns): Resolve reverse addresses.
+
+2004-10-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-get-new-news): Use it.
+
+       * gnus-start.el (gnus-check-reasonable-setup): New function.
+
+2004-11-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-configure-posting-styles): Don't cause the
+       "Args out of range" error.  Reported by Arnaud Giersch
+       <arnaud.giersch@free.fr>.
+
+2004-11-07  Stefan Wiens  <s.wi@gmx.net>  (tiny change)
+
+       * gnus-sum.el (gnus-summary-clear-local-variables): Use symbolp.
+
+2004-11-04  Richard M. Stallman  <rms@gnu.org>
+
+       * spam.el (spam group): Add :version.
+
+       * pgg-def.el (pgg group): Add :version.
+
+2004-11-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-edit-article): Don't associate the
+       article buffer with a draft file.  This is a temporary measure
+       against the 2004-08-22 change to gnus-article-edit-mode.
+
+2004-11-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * html2text.el (html2text-get-attr): Remove unused argument `tag'.
+       (html2text-format-tags): Remove unused variable `attr'.
+
+2004-11-01  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-msg.el (gnus-summary-resend-default-address): Add :version.
+
+       * tls.el (tls-process-connection-type, tls-success)
+       (tls-certtool-program): Add :version.
+
+       * starttls.el (starttls-gnutls-program, starttls-use-gnutls)
+       (starttls-extra-arguments, starttls-process-connection-type)
+       (starttls-connect, starttls-failure, starttls-success): Add :version.
+
+       * spam-stat.el (spam-stat): Add :version.
+
+       * sieve.el (sieve): Add :version.
+
+       * sha1.el (sha1): Add :version.
+       (sha1-use-external): Remove redundant version.
+
+       * nnmail.el (nnmail-split-fancy-with-parent-ignore-groups)
+       (nnmail-cache-ignore-groups, nnmail-spool-hook)
+       (nnmail-split-fancy-match-partial-words)
+       (nnmail-split-lowercase-expanded): Add :version.
+
+       * nndiary.el (nndiary): Add :version.
+
+       * mml2015.el (mml2015-unabbrev-trust-alist): Add :version.
+
+       * mml-sec.el (mml-default-sign-method)
+       (mml-default-encrypt-method, mml-signencrypt-style-alist):
+       Add :version.
+
+       * mm-uu.el (mm-uu-diff-groups-regexp): Add :version.
+
+       * mm-url.el (mm-url-use-external, mm-url-program)
+       (mm-url-arguments): Add :version.
+
+       * mm-decode.el (mm-inline-text-html-with-w3m-keymap)
+       (mm-attachment-file-modes, mm-decrypt-option)
+       (mm-w3m-safe-url-regexp): Add :version.
+
+       * message.el (message-cite-prefix-regexp)
+       (message-sendmail-envelope-from, message-minibuffer-local-map)
+       (message-user-fqdn, message-completion-alist): Add :version.
+
+       * gnus-win.el (gnus-configure-windows-hook)
+       (gnus-use-frames-on-any-display): Add :version.
+
+       * gnus-art.el (gnus-article-address-banner-alist)
+       (gnus-treat-unsplit-urls, gnus-treat-unfold-headers)
+       (gnus-treat-from-picon, gnus-treat-mail-picon)
+       (gnus-treat-x-pgp-sig): Add :version.
+
+       * gnus-sum.el (gnus-spam-mark, gnus-recent-mark)
+       (gnus-undownloaded-mark, gnus-summary-article-move-hook)
+       (gnus-summary-article-delete-hook)
+       (gnus-summary-display-while-building): Add :version.
+
+       * gnus-start.el (gnus-subscribe-newsgroup-hooks)
+       (gnus-get-top-new-news-hook): Add :version.
+
+       * gnus-srvr.el (gnus-server-agent-face, gnus-server-opened-face)
+       (gnus-server-closed-face, gnus-server-denied-face): Add :version.
+
+       * gnus-registry.el (gnus-registry): Add :version.
+
+       * gnus-spec.el (gnus-use-correct-string-widths)
+       (gnus-make-format-preserve-properties): Add :version.
+
+       * gnus.el (gnus-group-charter-alist)
+       (gnus-group-fetch-control-use-browse-url)
+       (gnus-install-group-spam-parameters): Add :version.
+
+       * gnus-diary.el (gnus-diary): Add :version.
+
+       * gnus-delay.el (gnus-delay): Add :version.
+
+       * gnus-cite.el (gnus-cite-unsightly-citation-regexp)
+       (gnus-cite-ignore-quoted-from, gnus-cite-attribution-face)
+       (gnus-cite-blank-line-after-header, gnus-article-boring-faces):
+       Add :version.
+
+       * gnus-agent.el (gnus-agent-max-fetch-size)
+       (gnus-agent-enable-expiration, gnus-agent-queue-mail)
+       (gnus-agent-prompt-send-queue): Add :version.
+
+       * deuglify.el (gnus-outlook-deuglify): Add :version.
+
+       * html2text.el: Beautify code.  Improve doc strings.
+       Some checkdoc cleanup.
+       (html2text-get-attr, html2text-fix-paragraph): Simplify code.
+
+2004-11-01  Alfred M. Szmidt  <ams@kemisten.nu>  (tiny change)
+
+       * html2text.el (html2text-format-tag-list): Add "strong" and "em".
+
+2004-10-29  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-hashtb): Create the registry
+       when package is loaded.
+
+       * spam.el (spam-summary-score-preferred-header): Add global preference
+       for people who want to override the default SpamAssassin over
+       Bogofilter preference (when both are set).
+       (spam-necessary-extra-headers): Add spam-use-bogofilter as an option.
+       (spam-user-format-function-S):
+       Check spam-summary-score-preferred-header.
+       (spam-extra-header-to-number): Add X-Bogosity header parsing.
+       (spam-user-format-function-S): Format the score correctly.
+
+2004-10-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-configure-posting-styles): Work with empty
+       signature file.  Suggested by Manoj Srivastava
+       <srivasta@golden-gryphon.com>.
+
+       * mm-util.el (mm-coding-system-priorities): Prefer iso-8859-1 than
+       iso-2022-jp even in the Japanese language environment.
+       Suggested by Jason Rumney <jasonr@gnu.org>.
+
+2004-10-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-update-summary-mark-positions): Allow users to
+       use the same characters as the dummy marks; make it free from
+       getting affected by the language environment.
+       (gnus-summary-read-group-1): Update mark positions only when the
+       format spec is updated.
+
+       * gnus-spec.el (gnus-update-format-specifications): Return a list
+       of updated types.
+
+2004-10-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-start.el (gnus-check-reasonable-setup): Use fboundp instead
+       of boundp to check if display-warning is available.
+
+2004-10-26  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * nnimap.el (nnimap-open-connection): Fix prog1/prog2 bug.
+
+2004-10-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnspool.el (nnspool-spool-directory): Use news-path if the
+       news-directory variable is not bound.
+
+       * gnus-start.el (gnus-check-reasonable-setup): Use an alternative
+       function instead of display-warning if it is not available.
+
+2004-10-26  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-agent.el (gnus-agent-expire-group-1): Fix last merge from
+       v5-10: Use `point-at-bol'.
+
+2004-10-26  Simon Josefsson  <jas@extundo.com>
+
+       * hashcash.el: Fix URL in comment, reported by Cheng Gao
+       <chenggao@gmail.com>.
+
+2004-10-25  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * html2text.el (html2text-buffer-head): Remove.  Use `goto-char'
+       instead.
+
+2004-10-25  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * nnimap.el (nnimap-remove-server-from-buffer-alist): Add function
+       to remove a server from the nnimap-server-buffer-alist.
+       (nnimap-open-connection, nnimap-close-server): Use it.
+
+       * gnus-encrypt.el: Remove file in favor of encrypt.el.
+
+2004-10-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-view.el (mm-display-inline-fontify): Inhibit font-lock when
+       running the major-mode function.
+
+2004-10-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-update-summary-mark-positions): Search for
+       dummy marks in the right way.
+
+2004-10-18  David Edmondson  <dme@dme.org>
+
+       * mm-view.el (mm-w3m-cid-retrieve-1): Don't use recursive call
+       excessively.
+
+2004-10-18  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-util.el (gnus-split-references): Accept a nil references
+       string and go on blissfully.
+
+       * gnus-registry.el (gnus-registry-split-fancy-with-parent): Catch
+       cases where the references string is non-nil but has no references.
+
+       * encrypt.el: Add autoload tags.
+
+       * spam.el (spam-resolve-registrations-routine): Remove article
+       from unregistration list too.  Reported by David Hanak
+       <dhanak@isis.vanderbilt.edu>
+
+2004-10-18  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-copy-article-ignored-headers): Default to
+       nil.  Change custom type.
+
+2004-10-17  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-copy-article-ignored-headers): New variable.
+
+       * gnus-sum.el (gnus-summary-move-article): Use it.
+
+2004-10-15  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * encrypt.el: Add autoload cookies.
+
+       * spam.el (spam-backend-article-list-property)
+       (spam-backend-get-article-todo-list)
+       (spam-backend-put-article-todo-list)
+       (spam-summary-prepare-exit, spam-resolve-registrations-routine):
+       Resolve registrations separately.
+       (spam-register-routine): Format comments.
+       (spam-unregister-routine, spam-register-routine): Always call with
+       specific-articles, no default list.
+       (spam-summary-prepare-exit): Use the spam-classifications function.
+
+       * netrc.el (autoload, netrc-parse): Use encrypt.el instead of
+       gnus-encrypt.el.
+
+       * encrypt.el: Copied from gnus-encrypt.el.
+
+       * gnus-encrypt.el: Commented that it's obsolete.
+
+2004-10-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-score.el (gnus-adaptive-pretty-print): New variable.
+       (gnus-score-save): Use it.
+
+       * message.el (message-bury): Use `window-dedicated-p'.
+
+2004-10-15  Simon Josefsson  <jas@extundo.com>
+
+       * pop3.el (top-level): Don't require nnheader.
+       (pop3-read-timeout): Add.
+       (pop3-accept-process-output): Add.
+       (pop3-read-response, pop3-retr): Use it.
+
+2004-10-14  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-register-routine): Move comment.
+       (spam-verify-bogofilter): Use 'unknown for the initial
+       spam-bogofilter-valid state, not 'never.
+
+       * netrc.el (netrc-machine-user-or-password): Add convenience wrapper
+       for netrc-machine.
+
+       * nnimap.el (nnimap-open-connection):
+       Use netrc-machine-user-or-password.
+
+2004-10-17  Richard M. Stallman  <rms@gnu.org>
+
+       * gnus-registry.el (gnus-registry-unload-hook):
+       Set as a variable with add-hook.
+
+       * nnspool.el (nnspool-spool-directory): Use news-directory instead
+       of news-path.
+
+       * spam-stat.el (spam-stat-unload-hook): Set as a variable w/ add-hook.
+
+       * spam.el: Delete duplicate `provide'.
+       (spam-unload-hook): Set as a variable with add-hook.
+
+2004-10-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * pop3.el (pop3-leave-mail-on-server): Describe possible problems
+       in the doc string.
+
+       * message.el (message-ignored-news-headers)
+       (message-ignored-supersedes-headers)
+       (message-ignored-resent-headers)
+       (message-forward-ignored-headers): Improve custom type.
+
+2004-10-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-tokenize-header): Fix 2004-09-06 change
+       which used point-min in the wrong place.
+
+2004-10-12  Simon Josefsson  <jas@extundo.com>
+
+       * tls.el (tls-certtool-program): New variable.
+       (tls-certificate-information): New function, based on
+       ssl-certificate-information.
+
+2004-10-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * compface.el: Move the version of ELisp-based uncompface program
+       to the contrib directory because of the copyright problem.
+
+2004-10-12  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-kill-buffer): Raise the current frame.
+
+2004-10-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el: Mention that multibyte characters don't work as marks.
+
+       * gnus.el (message-y-or-n-p): Autoload.
+
+       * pop3.el (pop3-maildrop, pop3-mailhost, pop3-port)
+       (pop3-password-required, pop3-authentication-scheme)
+       (pop3-leave-mail-on-server): Make customizable.
+       (pop3): New custom group.
+       (pop3-retr): Remove `sleep-for' statements.
+       Suggested by Dave Love <fx@gnu.org>.
+
+       * nnheader.el (nnheader-read-timeout): Explain 1.0 timeout for
+       Windows/DOS.
+
+       * imap.el (imap-parse-flag-list, imap-parse-body-extension)
+       (imap-parse-body): Fix incorrect use of `assert'.
+       Suggested by Dave Love <fx@gnu.org>.
+
+       * mml.el (mml-minibuffer-read-disposition): Require match.
+       Suggested by Dave Love <fx@gnu.org>.
+
+2004-10-11  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-group.el (gnus-group-delete-group): Change "\t." to "  " in
+       doc string.
+
+2004-10-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-uu.el (mm-uu-dissect-text-parts): Support all text/* types.
+
+2004-10-07  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * gnus-art.el (gnus-mime-display-single): Call `mm-display-inline'
+       instead of calling `mm-insert-inline', to decode text/* parts
+       before displaying them.
+
+2004-10-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-uu.el (mm-uu-text-plain-type): New variable.
+       (mm-uu-pgp-signed-extract-1): Use it.
+       (mm-uu-pgp-encrypted-extract-1): Use it.
+       (mm-uu-dissect): Allow MIME type and parameters as an optional arg;
+       bind mm-uu-text-plain-type with that value.
+       (mm-uu-dissect-text-parts): Pass MIME type and parameters to
+       mm-uu-dissect.
+
+2004-10-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el (gnus-update-group-mark-positions):
+       * gnus-sum.el (gnus-update-summary-mark-positions):
+       * message.el (message-check-news-body-syntax):
+       * gnus-msg.el (gnus-debug): Use mm-string-as-multibyte instead
+       of string-as-multibyte.
+
+2004-10-05  Juri Linkov  <juri@jurta.org>
+
+       * gnus-group.el (gnus-update-group-mark-positions):
+       * gnus-sum.el (gnus-update-summary-mark-positions):
+       * message.el (message-check-news-body-syntax):
+       * gnus-msg.el (gnus-debug): Use `string-as-multibyte' to convert
+       8-bit unibyte values to a multibyte string for search functions.
+
+2004-10-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-uu.el (mm-uu-dissect): Allow optional arg.
+       (mm-uu-dissect-text-parts): New function.
+
+       * gnus-art.el (gnus-display-mime): Use mm-uu-dissect-text-parts to
+       dissect text parts.
+
+       * gnus-sum.el (gnus-summary-insert-subject): Remove redundant setq.
+       (gnus-summary-force-verify-and-decrypt): Revert 2004-08-18 change.
+
+       * mm-decode.el (mm-dissect-singlepart): Revert 2004-08-18 change.
+
+       * gnus-topic.el (gnus-topic-hierarchical-parameters):
+       Use gnus-current-topics instead of gnus-current-topic.
+
+2004-10-06  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-summary-show-article): Use with-current-buffer.
+
+2004-10-05  Jesper Harder  <harder@ifa.au.dk>
+
+       * nnsoup.el (nnsoup-read-active-file): Use dolist, mapc or last
+       where appropriate.
+
+       * nnml.el (nnml-generate-active-info): do.
+
+       * nndiary.el (nndiary-generate-active-info): do.
+
+       * gnus-topic.el (gnus-topic-hierarchical-parameters): do.
+       (gnus-topic-move): do.
+
+       * gnus-sum.el (gnus-data-enter-list, gnus-summary-process-mark-set)
+       (gnus-summary-set-local-parameters, gnus-summary-read-document): do.
+
+       * gnus-srvr.el (gnus-server-prepare)
+       (gnus-server-open-all-servers): do.
+
+       * gnus-msg.el (gnus-summary-cancel-article)
+       (gnus-summary-resend-message)
+       (gnus-summary-mail-crosspost-complaint): do.
+
+       * gnus-move.el (gnus-change-server): do.
+
+       * gnus-group.el (gnus-group-unmark-all-groups)
+       (gnus-group-set-current-level): do.
+
+2004-10-04  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-generate-hashcash): Doc fix.
+
+2004-10-02  Kevin Greiner  <kgreiner@compsol.cc>
+
+       * nnagent.el (nnagent-request-type): Bind gnus-agent to nil to
+       avoid infinite recursion via gnus-get-function.
+
+2004-10-02  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-partial.el (mm-partial-find-parts): Use with-current-buffer.
+
+       * nnfolder.el (nnfolder-generate-active-file): Use dolist.
+
+       * nnmail.el (nnmail-split-history): do.
+
+       * nnml.el (nnml-generate-nov-databases-1, nnml-request-rename-group)
+       (nnml-request-delete-group): do.
+
+       * nnslashdot.el (nnslashdot-read-groups): do.
+
+       * nnsoup.el (nnsoup-delete-unreferenced-message-files): do.
+       (nnsoup-unpack-packets, nnsoup-make-active): Simplify.
+
+       * nnspool.el (nnspool-find-id): Use with-temp-buffer.
+       (nnspool-sift-nov-with-sed): Use last.
+       (nnspool-retrieve-headers-with-nov): Use mapc.
+       (nnspool-request-newgroups): Use dolist.
+       (nnspool-request-group): Use last.
+
+       * nntp.el (nntp-read-server-type): Use dolist.
+
+       * nnvirtual.el (nnvirtual-create-mapping)
+       (nnvirtual-update-read-and-marked): Use dolist.
+       (nnvirtual-convert-headers): Simplify.
+
+2004-10-01  Kevin Greiner  <kgreiner@compsol.cc>
+
+       * gnus-agent.el (gnus-agent-synchronize-group-flags):
+       Add support for sync'ing tick marks.
+
+2004-10-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-toggle-header): Make it work even if
+       there's no visible header.
+
+2004-10-01  Kevin Greiner  <kgreiner@compsol.cc>
+
+       * gnus-agent.el (gnus-agent-synchronize-group-flags):
+       When necessary, pass full group name to gnus-request-set-marks.
+
+2004-10-01  Simon Josefsson  <jas@extundo.com>
+
+       * mailcap.el (mailcap-mime-data): Add pdf.  Remove non-free
+       acroread.
+
+2004-10-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * spam-report.el (spam-report-gmane): Fix interactive.
+
+       * gnus-art.el (gnus-treat-body-boundary): Only do stuff under X.
+
+       * gnus-agent.el (gnus-agent-synchronize-flags-server): Be silent
+       when writing file.
+       (gnus-agent-synchronize-flags): Don't default to being
+       interactive.
+
+2004-09-30  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-generate-hashcash): Add.
+       (message-send-mail): Use it, call mail-add-payment.
+
+2004-09-29  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-verify-bogofilter): Use -V, not -sV option.
+
+2004-09-28  Kevin Greiner  <kgreiner@compsol.cc>
+
+       * gnus-agent.el (gnus-agent-synchronize-group-flags): Replace
+       gnus-requst-update-info with explicit code to sync the in-memory
+       info read flags with the marks being sync'd to the backend.
+
+       * gnus-util.el (gnus-pp): Add optional stream to match pp API.
+
+2004-09-28  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-verify-bogofilter): Add new function.
+       (spam-check-bogofilter)
+       (spam-bogofilter-register-with-bogofilter): Use it.
+       (spam-verify-bogofilter): Add small fixes.
+
+2004-09-28  Simon Josefsson  <jas@extundo.com>
+
+       * hashcash.el (hashcash-generate-payment): Revert.
+
+2004-09-28  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-split-fancy-with-parent):
+       Use gnus-extract-references instead of gnus-split-references.
+
+       * gnus-util.el (gnus-extract-references): Add new function, analogous
+       to gnus-split-references but extracts only the message-ID without
+       anything extra.
+
+       * hashcash.el (hashcash-generate-payment)
+       (hashcash-check-payment): Do the right thing if hashcash-path is
+       nil (because the hashcash program could not be found).
+
+       * spam.el (spam-use-hashcash): Remove comment.
+
+2004-09-27  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-cache.el (gnus-cache-possibly-remove-articles-1)
+       (gnus-cache-enter-article, gnus-cache-remove-article)
+       (gnus-cache-braid-heads, gnus-cache-generate-active): Use dolist.
+
+       * gnus-async.el (gnus-async-prefetch-remove-group): do.
+
+       * gnus-art.el (article-hide-boring-headers)
+       (article-translate-strings, article-display-face)
+       (gnus-article-mime-match-handle-first)
+       (gnus-article-highlight-headers)
+       (gnus-article-add-buttons-to-head): do.
+
+2004-09-27  Simon Josefsson  <jas@extundo.com>
+
+       * hashcash.el: New version, from
+       http://users.actrix.co.nz/mycroft/hashcash.el.  Previously in
+       ../contrib/.
+
+2004-09-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-copy-to-buffer): Don't use set-buffer-multibyte.
+
+2004-09-26  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-dup.el (gnus-dup-open): Use mapc.
+       (gnus-dup-enter-articles, gnus-dup-suppress-articles): Use dolist.
+
+       (gnus-dup-enter-articles): Remove excess ID's from gnus-dup-hashtb.
+       Reported by Stefan Wiens <s.wi@gmx.net>.
+
+       * gnus.el (gnus-shutdown): Use dolist.
+
+       * gnus-undo.el (gnus-undo): Use mapc.
+
+       * nnrss.el (nnrss-generate-active): do.
+
+       * message.el (message-cite-original-without-signature)
+       (message-cite-original): Use mapc.
+       (message-do-actions, message-make-forward-subject): Use dolist.
+
+2004-09-25  Kevin Greiner  <kgreiner@compsol.cc>
+
+       * gnus-agent.el (gnus-agent-check-overview-buffer): Fix range of
+       deletion to remove entire duplicate line.  Fixes merged article
+       number bug.
+
+2004-09-25  Kevin Greiner  <kgreiner@compsol.cc>
+
+       * gnus-agent.el (gnus-agent-possibly-synchronize-flags): Ignore
+       servers that are offline.  Avoids having gnus-agent-toggle-plugged
+       first ask if you want to open a server and then, even when you
+       responded with no, asking if you want to synchronize the server's
+       flags.
+       (gnus-agent-synchronize-flags-server): Rewrote read loop to handle
+       multi-line expressions.
+       (gnus-agent-synchronize-group-flags): New internal function.
+       Updates marks in memory (in the info structure) AND in the
+       backend.
+
+       * gnus-util.el (gnus-remassoc): Fix typo in documentation.
+
+       * nnagent.el (nnagent-request-set-mark):
+       Use gnus-agent-synchronize-group-flags, not backend's request-set-mark
+       method, to ensure that synchronization updates marks in the
+       backend and in the info (in memory) structure.
+
+2004-09-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-uu.el (gnus-uu-digest-mail-forward): Obey the process/prefix
+       convention fully; don't miss the root article of a thread; make
+       the X-Draft-From header with correct article numbers.
+
+2004-09-23  Kevin Greiner  <kgreiner@compsol.cc>
+
+       * gnus-agent.el (gnus-agent-synchronize-flags-server): Do nothing
+       unless plugged.  Disable the agent so that an open failure causes
+       an error.
+
+       * gnus-int.el (gnus-request-set-mark, gnus-request-update-mark):
+       Revert 2004-09-21 change.  The backend must be opened while
+       synchronizing flags even when the backend stores the flags
+       locally.
+
+2004-09-23  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-msg.el (gnus-configure-posting-styles): Narrow to headers
+       in `header' match.  Reported by Svend Tollak Munkejord.
+
+       * message.el (message-cite-original): Fix use of
+       `message-cite-articles-with-x-no-archive'.
+
+2004-09-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-win.el (gnus-buffer-configuration): Add mml-preview.
+       (gnus-window-to-buffer): Ditto.
+
+       * mml.el (mml-preview-buffer): New variable.
+       (mml-preview): Manage window layout with gnus-buffer-configuration.
+
+       * gnus-msg.el (gnus-setup-message): Put article numbers into the
+       X-Draft-From header even if those articles aren't quoted.
+
+2004-09-21  Kevin Greiner  <kgreiner@compsol.cc>
+
+       * gnus-int.el (gnus-servers-that-use-local-marks): New variable.
+       (gnus-request-set-mark, gnus-request-update-mark): Use new
+       g-s-t-u-l-m to decide to use backend even when unplugged.
+
+2004-09-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-inews-make-draft-meta-information): Don't add
+       a trailing whitespace.  Suggested by Cheng Gao <chenggao@gmail.com>.
+
+2004-09-20  Simon Josefsson  <jas@extundo.com>
+
+       * mm-util.el (mm-charset-synonym-alist): Map "unicode" to
+       "utf-16-le".
+
+2004-09-20  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * mm-decode.el (mm-copy-to-buffer): Preserve the data's unibyteness.
+
+2004-09-19  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * uudecode.el (uudecode-use-external): Add :version.
+
+       * smime.el (smime-CA-file, smime-encrypt-cipher)
+       (smime-dns-server): Add :version.
+
+       * smiley.el (gnus-smiley-file-types): Add :version.
+
+       * sha1.el (sha1-use-external): Add :version.
+
+       * pgg-def.el (pgg-query-keyserver): Add :version.
+
+       * nnmail.el (nnmail-fancy-expiry-targets)
+       (nnmail-mail-splitting-charset, nnmail-mail-splitting-decodes):
+       Add :version.
+
+       * nnimap.el (nnimap-split-download-body, nnimap-dont-close)
+       (nnimap-retrieve-groups-asynchronous): Add :version.
+       (nnimap-close-asynchronous): Add :version.  Fix typo in doc string.
+
+       * mml.el (mml-content-disposition-parameters)
+       (mml-insert-mime-headers-always): Add :version.
+
+       * mm-util.el (mm-coding-system-priorities): Add :version.
+
+       * mm-decode.el (mm-inline-text-html-with-images)
+       (mm-keep-viewer-alive-types, mm-external-terminal-program)
+       (mm-verify-option): Add :version.
+       (mm-text-html-renderer): Change :version.
+
+       * message.el (message-fcc-externalize-attachments)
+       (message-required-headers, message-draft-headers)
+       (message-subject-trailing-was-query)
+       (message-subject-trailing-was-ask-regexp)
+       (message-subject-trailing-was-regexp, message-mark-insert-begin)
+       (message-mark-insert-end, message-archive-header)
+       (message-archive-note, message-cross-post-default)
+       (message-cross-post-note, message-followup-to-note)
+       (message-cross-post-note-function, message-use-mail-followup-to)
+       (message-subscribed-address-functions)
+       (message-subscribed-address-file, message-subscribed-addresses)
+       (message-subscribed-regexps, message-allow-no-recipients)
+       (message-yank-cited-prefix, message-signature-insert-empty-line)
+       (message-hidden-headers, message-hierarchical-addresses)
+       (message-mail-user-agent, message-use-idna)
+       (message-valid-fqdn-regexp)
+       (message-strip-special-text-properties, message-header-synonyms)
+       (message-beginning-of-line, message-tab-body-function): Add :version.
+       (message-insert-canlock, message-wide-reply-confirm-recipients):
+       Change :version.
+
+       * mail-source.el (mail-source-ignore-errors): Add :group, :type
+       and :version.
+       (mail-source-delete-old-incoming-confirm)
+       (mail-source-movemail-program): Add :version.
+
+       * gnus.el (gnus-parameters, gnus-user-agent): Add :version.
+       (gnus-agent-cache, gnus-agent): Change :version.
+
+       * gnus-util.el (gnus-use-byte-compile): Change :version.
+
+       * gnus-sum.el (gnus-summary-make-false-root-always)
+       (gnus-summary-default-high-score)
+       (gnus-summary-default-low-score, gnus-auto-goto-ignores)
+       (gnus-forwarded-mark, gnus-unseen-mark, gnus-no-mark)
+       (gnus-read-all-available-headers, gnus-article-emulate-mime)
+       (gnus-sum-thread-tree-root, gnus-sum-thread-tree-false-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): Add :version.
+       (gnus-summary-display-arrow, gnus-summary-muttprint-program)
+       (gnus-article-loose-mime): Change :version.
+
+       * gnus-start.el (gnus-backup-startup-file)
+       (gnus-save-startup-file-via-temp-buffer): Add :version.
+
+       * gnus-srvr.el (gnus-server-browse-in-group-buffer)
+       (gnus-server-offline-face): Add :version.
+
+       * gnus-score.el (gnus-adaptive-word-length-limit): Add :version.
+
+       * gnus-msg.el (gnus-gcc-externalize-attachments)
+       (gnus-debug-files, gnus-debug-exclude-variables)
+       (gnus-discouraged-post-methods): Change :version.
+       (gnus-confirm-mail-reply-to-news)
+       (gnus-confirm-treat-mail-like-news): Add :version.
+
+       * gnus-int.el (gnus-server-unopen-status): Add :version.
+
+       * gnus-group.el (gnus-group-jump-to-group-prompt)
+       (gnus-large-ephemeral-newsgroup)
+       (gnus-fetch-old-ephemeral-headers): Add :version.
+
+       * gnus-fun.el (gnus-x-face-directory)
+       (gnus-convert-pbm-to-x-face-command)
+       (gnus-convert-image-to-x-face-command)
+       (gnus-convert-image-to-face-command): Add :version.
+
+       * gnus-delay.el (gnus-delay-default-hour): Add :version.
+
+       * gnus-cite.el (gnus-cite-blank-line-after-header)
+       (gnus-article-boring-faces): Add :version.
+
+       * gnus-art.el (gnus-buttonized-mime-types)
+       (gnus-inhibit-mime-unbuttonizing)
+       (gnus-treat-display-face)
+       (gnus-treat-body-boundary): Change :version.
+       (gnus-body-boundary-delimiter, gnus-picon-databases)
+       (gnus-treat-strip-cr, gnus-treat-leading-whitespace)
+       (gnus-treat-date-english, gnus-treat-fold-headers)
+       (gnus-article-skip-boring, gnus-treat-fold-newsgroups)
+       (gnus-treat-mail-picon, gnus-treat-wash-html)
+       (gnus-article-encrypt-protocol)
+       (gnus-use-idna, gnus-article-over-scroll)
+       (gnus-mime-display-multipart-alternative-as-mixed)
+       (gnus-mime-display-multipart-related-as-mixed)
+       (gnus-button-valid-fqdn-regexp, gnus-button-man-handler)
+       (gnus-ctan-url, gnus-button-ctan-handler)
+       (gnus-button-handle-ctan-bogus-regexp)
+       (gnus-button-ctan-directory-regexp)
+       (gnus-button-mid-or-mail-regexp, gnus-button-prefer-mid-or-mail)
+       (gnus-button-mid-or-mail-heuristic-alist, gnus-button-tex-level)
+       (gnus-button-man-level, gnus-button-emacs-level)
+       (gnus-button-message-level, gnus-button-browse-level): Add :version.
+
+       * gnus-agent.el (gnus-agent-fetched-hook): Add :version.
+       (gnus-agent-go-online): Change :version.
+       (gnus-agent-expire-unagentized-dirs)
+       (gnus-agent-auto-agentize-methods): Add :version.
+
+       * flow-fill.el (fill-flowed-display-column)
+       (fill-flowed-encode-column): Add :version.
+
+       * deuglify.el (gnus-outlook-deuglify-unwrap-min)
+       (gnus-outlook-deuglify-unwrap-max)
+       (gnus-outlook-deuglify-cite-marks)
+       (gnus-outlook-deuglify-unwrap-stop-chars)
+       (gnus-outlook-deuglify-no-wrap-chars)
+       (gnus-outlook-deuglify-attrib-cut-regexp)
+       (gnus-outlook-deuglify-attrib-verb-regexp)
+       (gnus-outlook-deuglify-attrib-end-regexp)
+       (gnus-outlook-display-hook): Add :version.
+
+       * binhex.el (binhex-use-external): Add :version.
+
+2004-09-16  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-fetch-old-headers): Add custom choices `t'
+       and `invisible'.
+
+2004-09-10  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-trim): Watch out for negatives
+       in gnus-registry-trim.
+
+2004-09-13  Simon Josefsson  <jas@extundo.com>
+
+       * dns-mode.el: Add XEmacs auto-mode-alist autoload cookie.
+
+       * nnimap.el (nnimap-demule): Revert 2004-08-30 change.
+
+       * dns-mode.el (dns-mode): Fix menu for XEmacs, reported by Steve
+       Youngs <steve@youngs.au.com> and suggested by Katsumi Yamaoka
+       <yamaoka@jpl.org>.
+       (dns-mode-font-lock-keywords): Fix faces, reported by Steve Youngs
+       <steve@youngs.au.com> and suggested by Katsumi Yamaoka
+       <yamaoka@jpl.org>.
+
+       * sieve.el (sieve-manage-mode): Ditto.
+
+2004-09-13  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-summary-copy-article): Fix doc string.
+
+2004-09-11  Simon Josefsson  <jas@extundo.com>
+
+       * dns-mode.el: Add.
+
+       * mm-view.el (mm-display-dns-inline): Add.
+
+       * mm-decode.el (mm-inline-media-tests): Add text/dns.
+       (mm-automatic-display): Ditto.
+
+       * mailcap.el (mailcap-mime-data): Add text/dns.
+       (mailcap-mime-extensions): Map .soa to text/dns.
+
+2004-09-10  Miles Bader  <miles@gnu.ai.mit.edu>
+
+       * gnus-art.el (article-decode-mime-words, article-babel)
+       (gnus-article-highlight-signature, gnus-article-add-buttons)
+       (gnus-signature-toggle): Remove unnecessary bindings of
+       `inhibit-read-only' inherited from v5.10 merge.
+
+2004-09-08  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nntp.el (nntp): New customization group.
+       (nntp-authinfo-file): Add customization group.
+
+       * mml2015.el (mml2015-unabbrev-trust-alist): Add customization group.
+
+       * mml-sec.el (mml-signencrypt-style-alist): Ditto.
+
+       * gnus.el (to-address, to-list, subscribed)
+       (large-newsgroup-initial): Ditto.
+
+       * flow-fill.el (fill-flowed-display-column)
+       (fill-flowed-encode-column): Ditto.
+
+2004-09-06  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * message.el (message-tokenize-header, message-send-mail-with-qmail):
+       Use point-min rather than 1.
+       (message-send-mail): Use buffer-size rather than point-max.
+
+       * gnus-sum.el (gnus-summary-search-article-forward):
+       Signal a specific `search-failed' rather than a generic `error'.
+
+       * gnus-salt.el (gnus-pick-mouse-pick-region): Switch 1 => point-min.
+       (gnus-generate-vertical-tree): Usue `bobp' rather than compare to 1.
+       (gnus-highlight-selected-tree): Use point-min rather than 1 and 2.
+
+2004-09-10  Simon Josefsson  <jas@extundo.com>
+
+       * nndb.el (require): Remove tcp and duplicate cl.
+
+2004-09-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-agent.el (directory-files-and-attributes): Move forward.
+
+2004-09-09  Kevin Greiner  <kgreiner@compsol.cc>
+
+       * gnus-agent.el (directory-files-and-attributes):
+       Optionally defined to support XEmacs.
+
+2004-09-09  Kevin Greiner  <kgreiner@compsol.cc>
+
+       * gnus-agent.el (gnus-agent-cat-groups): Rewrote avoiding defsetf
+       to avoid run-time CL dependencies.
+       (gnus-agent-unfetch-articles): New function.
+       (gnus-agent-fetch-headers): Use gnus-agent-braid-nov to validate
+       article numbers even when local .overview file is missing.
+       (gnus-agent-read-article-number): New function.  Only accepts
+       27-bit article numbers.
+       (gnus-agent-copy-nov-line, gnus-agent-uncached-articles):
+       Use gnus-agent-read-article-number.
+       (gnus-agent-braid-nov): Rewrote to validate article numbers coming
+       from backend while recognizing that article numbers in .overview
+       must be valid.
+       (gnus-agent-update-files-total-fetched-for):
+       Use directory-files-and-attributes to improve performance.
+       * gnus-int.el (gnus-request-move-article):
+       Use gnus-agent-unfetch-articles in place of gnus-agent-expire to
+       improve performance.
+
+       * gnus-start.el (gnus-convert-old-newsrc): Change message text as
+       some users confused by references to .newsrc when they only have a
+       .newsrc.eld file.
+       (gnus-convert-mark-converter-prompt)
+       (gnus-convert-converter-needs-prompt): Fix use of property list.
+       * legacy-gnus-agent.el (gnus-agent-convert-to-compressed-agentview-prompt):
+       New function.  Used internally to only display 'gnus converting
+       files' message when actually necessary.
+
+       * gnus-sum.el (): Remove (require 'gnus-agent) as required
+       methods now autoloaded.
+
+2004-09-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-insert-subject): Remove list
+       identifiers.
+
+2004-09-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-picon.el: Fix indentation and closing parenthesis.
+
+2004-09-01  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-canlock-generate): Require sha1, not
+       sha1-el.  (Can we get rid of this require altogether?  It is ugly
+       to require within a function.  Sadly, if sha1.el isn't loaded, the
+       let binding in m-c-g will hide the defcustom definition, which is
+       bad.)
+
+       * canlock.el: Require sha1, not sha1-el.
+
+       * message.el: Don't autoload sha1 (there is a autoload cookie in
+       sha1.el).
+
+       * sha1-el.el: Rename to sha1.el.
+
+2004-08-30  Juanma Barranquero  <lektu@terra.es>
+
+       * ietf-drums.el (ietf-drums-remove-whitespace): Fix character constant.
+
+2004-08-30  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * nnimap.el (nnimap-demule): Avoid string-as-multibyte.
+
+2004-08-30  Kim F. Storm  <storm@cua.dk>
+
+       * nntp.el (nntp-authinfo-file): Add :group 'nntp.
+
+       * nnimap.el (nnimap-authinfo-file, nnimap-prune-cache):
+       Add :group 'nnimap.
+
+2004-08-30  Andreas Schwab  <schwab@suse.de>
+
+       * rfc2231.el (rfc2231-parse-string): Restore whitespace syntax for
+       ?* and ?\;.
+
+       * ietf-drums.el (ietf-drums-syntax-table): Set syntax of ?* ?\;
+       and ?\' to symbol instead of whitespace.
+
+2004-08-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-agent.el (gnus-agent-restore-gcc): Use ^ and regexp-quote.
+
+       * gnus-sum.el (gnus-summary-morse-message): Use search-forward
+       instead of re-search-forward.
+
+       * gnus-uu.el (gnus-uu-save-article): Ditto.
+       (gnus-uu-post-encode-uuencode): Ditto.
+
+       * html2text.el (html2text-clean-list-items): Ditto.
+       (html2text-clean-dtdd): Ditto.
+       (html2text-format-tags): Ditto.
+
+       * message.el (message-send-mail-with-sendmail): Fix regexp.
+       (message-fill-field-general): Use search-forward instead of
+       re-search-forward.
+       (unbold-region): Ditto.
+
+       * nnrss.el (nnrss-request-article): Ditto.
+
+       * nnslashdot.el (nnslashdot-request-article): Ditto.
+
+       * nnweb.el (nnweb-gmane-wash-article): Ditto.
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Avoid the
+       "Unrecognized menu descriptor" error in XEmacs.
+
+2004-08-26  Stefan Wiens  <s.wi@gmx.net>  (tiny change)
+
+       * gnus-sum.el (gnus-read-header): Don't remove a header for the
+       parent article of a sparse article in the thread hashtb.
+
+2004-08-26  David Hedbor  <dhedbor@real.com>  (tiny change)
+
+       * nnmail.el (nnmail-split-lowercase-expanded): New user option.
+       (nnmail-expand-newtext): Lowercase expanded entries if
+       nnmail-split-lowercase-expanded is non-nil.
+
+2004-08-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nndoc.el (nndoc-type-alist): Fix regexp in the rfc822-forward entry.
+
+       * gnus-group.el (gnus-group-line-format-alist): Convert the value
+       of gnus-tmp-news-method into string under XEmacs.  It will be
+       passed to gnus-correct-length which takes only a string argument.
+
+2004-08-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-bind-print-variables): New macro.
+       (gnus-prin1): Use it.
+       (gnus-prin1-to-string): Use it.
+       (gnus-pp): New function.
+       (gnus-pp-to-string): New function.
+
+       * gnus-cus.el (gnus-agent-cat-prepare-category-field):
+       Replace pp-to-string with gnus-pp-to-string.
+       * gnus-eform.el (gnus-edit-form): Replace pp with gnus-pp.
+       * gnus-group.el (gnus-group-make-kiboze-group): Ditto.
+       * gnus-msg.el (gnus-debug): Ditto.
+       * gnus-score.el (gnus-score-save): Ditto.
+       * gnus-spec.el (gnus-update-format): Replace pp-to-string with
+       gnus-pp-to-string.
+       * legacy-gnus-agent.el (gnus-agent-unlist-expire-days): Replace pp
+       with gnus-pp.
+       * score-mode.el (gnus-score-pretty-print): Ditto.
+       * webmail.el (webmail-debug): Ditto.
+
+2004-08-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-display-face, article-display-x-face):
+       Use buffer-read-only.
+
+2004-08-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-hide-list-identifiers):
+       Bind inhibit-read-only as t.
+
+2004-08-22  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-mlspl.el (gnus-group-split-update): Fix docstring.
+
+2004-08-22  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus-art.el: Use inhibit-read-only instead of buffer-read-only.
+       (gnus-narrow-to-page): Don't assume point-min == 1.
+       (gnus-article-edit-mode): Derive from message-mode.
+
+       * gnus-score.el (gnus-score-find-bnews): Simplify and don't assume
+       point-min == 1.
+
+       * imap.el (imap-parse-address-list, imap-parse-body-ext):
+       Disable incorrect use of `assert'.
+
+       * message.el (message-mode): Set comment-start-skip.
+
+
+2004-08-22  Sam Steingold  <sds@gnu.org>
+
+       * pop3.el (pop3-leave-mail-on-server): New user variable.
+       (pop3-movemail): Delete mail only when it is nil.
+
+2004-08-21  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * nntp.el (nntp-marks-is-evil): Fix typo in docstring.
+
+       * mml.el (mml-preview): Use `pop-to-buffer'.
+
+       * message.el (message-goto-mail-followup-to): Insert after "To".
+       (message-carefully-insert-headers): Add comment.
+
+       * gnus.el: Remove unused variable `gnus-article-check-size'.
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Add help texts.
+
+       * gnus-art.el (gnus-button-alist):
+       Improve `gnus-button-handle-library' entry.
+
+2004-08-19  Sebastian Freundt  <hroptatyr@gna.org>  (tiny change)
+
+       * nnmaildir.el (nnmaildir--emlink-p, nnmaildir--enoent-p):
+       Use downcase, since XEmacs capitalizes error messages differently.
+
+2004-08-18  Jesper Harder  <harder@ifa.au.dk>
+
+       * nntp.el: Add (require 'gnus) due to reference to
+       `gnus-directory'.  Reported by Matt Swift <swift@alum.mit.edu>.
+
+2004-08-18  Florian Weimer  <fw@deneb.enyo.de>
+
+       * gnus-sum.el (gnus-summary-force-verify-and-decrypt):
+       Bind `mm-fill-flowed'.
+
+       * mm-decode.el (mm-dissect-singlepart): Check it.
+
+2004-08-17  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * nnimap.el (nnimap-open-connection): Add 'imaps' synonym to
+       'imap' for netrc parsing.
+
+2004-08-16  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mailcap.el (mailcap-mime-data): Mark as risky.
+
+2004-08-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-encode-region): Assume the close parenthesis
+       may be included in the encoded word.
+       (rfc2047-encode): Don't append a space if the encoded word
+       includes close parenthesis.
+
+2004-08-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-encode-1, rfc2047-encode): Improve encoding
+       of text within parentheses.
+
+2004-08-06  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-encrypt.el (gnus-encrypt-insert-file-contents)
+       (gnus-encrypt-write-file-contents): Make the password key the file
+       name PLUS the cipher, not just the cipher.  Also remove failed
+       passwords from the cache.
+
+2004-08-06  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-article-loose-mime): Change default to t.
+       Doc fix.
+
+2004-08-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-fold-region): Use trailing whitespace as
+       LWSP.
+
+2004-08-04  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-split-fancy-with-parent):
+       Try to append in-reply-to: data to the references: header.
+
+       * netrc.el: Remove old encryption support, autoload gnus-encrypt.el.
+       (netrc-parse): Use gnus-encrypt.el functions.
+
+       * gnus-encrypt.el: Add new file for encryption support; currently
+       does only a few GPG ciphers and an internal XOR cipher.
+
+       * password.el: Add comments on using password-read-and-add.
+       (password-read-and-add): Add function to read and add the
+       password to the cache at once.
+
+2004-07-28  Simon Josefsson  <jas@extundo.com>
+
+       * pgg-pgp5.el (pgg-pgp5-encrypt-region): Accept sign
+       parameter (but don't use it, for now).
+
+       * imap.el (imap-ssl-open): Use imap-process-connection-type,
+       instead of hard coding to nil.
+
+2004-07-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-view.el (mm-inline-image-emacs): Open lines under an image
+       as mm-inline-image-xemacs does.
+
+2004-07-26  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-group.el (gnus-group-group-map, gnus-group-make-menu-bar):
+       Revert part of 2004-07-17 change below.
+
+2004-07-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-encode-region): Don't infloop.
+       Suggested by Hiroshi Fujishima <pooh@nature.tsukuba.ac.jp>.
+
+2004-07-25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * flow-fill.el (fill-flowed): Remove space stuffing, and only do
+       quotes that actually start with ">" at the beginning of the
+       lines.
+
+2004-07-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-encode-region): Fix last change.
+       (rfc2047-encode-parameter): Remove useless concat.
+
+2004-07-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-encode-region): Check carefully whether to
+       encode special characters; fix some kind of misconfigured headers;
+       signal a real error if debug-on-quit or debug-on-error is non-nil.
+       (rfc2047-encode-max-chars): New variable.
+       (rfc2047-encode-1): Use it.
+       (rfc2047-encode-parameter): New function.
+
+       * mml.el (mml-insert-parameter): Remove an excessive space.
+
+2004-07-17  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-group.el (gnus-group-make-group-simple): Add, suggested by
+       Kai Grossjohann <kai@emptydomain.de>.
+       (gnus-group-group-map): Use it, instead of gnus-group-make-group.
+       (gnus-group-make-menu-bar): Ditto.
+
+       * gnus-util.el (gnus-group-server): Add.
+
+2004-07-16  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-clone-locals): Clone sendmail and smtp
+       variables.
+
+2004-07-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-encode-region): Fix last change.
+
+2004-07-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-encode-region): Treat backslash-quoted
+       characters as non-special.
+
+2004-07-09  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-agent.el (gnus-agent-synchronize-flags): Revert to ask.
+       Users will lose all flag changes made while unplugged with
+       e.g. nntp unless flag synchronization happens, thus `nil' is not a
+       good default.  See numerous reports on ding mailing list.
+
+2004-07-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nndoc.el (nndoc-type-alist): Improve regexp for article-begin,
+       add generate-head-function and generate-article-function to the
+       rfc822-forward entry.
+       (nndoc-rfc822-forward-generate-article): New function.
+       (nndoc-rfc822-forward-generate-head): New function.
+
+       * mm-decode.el (mm-dissect-buffer): Simplify cleaning of CTE.
+
+2004-07-06  Dan Christensen  <jdc@uwo.ca>
+
+       * gnus-sum.el (gnus-summary-read-group-1): When summary is unthreaded,
+       respect display group parameter and gnus-summary-expunge-below.
+       (gnus-articles-to-read): Remove unused reference to display group
+       parameter.
+
+2004-07-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnheader.el (nnheader-uniquify-message-id): New experimental
+       variable.
+       (nnheader-nov-read-message-id): Use it.
+
+       * spam-report.el (spam-report-gmane): Add interactive.
+
+2004-07-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-encode.el (mm-content-transfer-encoding-defaults):
+       Use qp-or-base64 for the application/* types.
+
+2004-07-02  Joakim Verona  <joakim@verona.se>  (tiny change)
+
+       * nnrss.el (nnrss-read-group-data): Fix off-by-one error.
+
+2004-06-30  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-trim): Don't allow a negative
+       trim value.
+
+2004-01-25  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir--condcase, nnmaildir--enoent-p):
+       New macro and function.
+       (nnmaildir--new-number, nnmaildir-request-set-mark): Use them.
+
+2004-06-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-enrich-utf-8-by-mule-ucs): Fix cleaning of
+       after-load-alist.
+
+2004-06-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-get-new-news-this-group):
+       Don't update info that isn't there.
+
+2004-06-29  Ilya N. Golubev  <gin@mo.msk.ru>
+
+       * mm-util.el (mm-mime-mule-charset-alist): Add the windows-1251
+       entry.
+
+2004-06-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-view.el (mm-inline-render-with-function): Use multibyte
+       buffer; decode html source by charset.
+
+       * mm-encode.el (mm-content-transfer-encoding-defaults): Doc fix.
+
+       * mm-util.el (mm-enrich-utf-8-by-mule-ucs): New function run when
+       Mule-UCS is loaded under XEmacs.
+       (mm-mime-mule-charset-alist): Avoid duplicated entries.
+
+2004-06-28  Jesper Harder  <harder@ifa.au.dk>
+
+       * nnheader.el (nnheader-max-head-length): Increase to 8192.
+
+2004-06-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-coding-system-p): Return a coding-system.
+       (mm-mime-mule-charset-alist): Use shift_jis instead of
+       iso-2022-jp-2 for the katakana-jisx0201 mule charset; add new
+       entries for the mime charsets iso-2022-jp-3 and shift_jis.
+       (mm-coding-system-priorities): Use shift_jis and iso-8859-1
+       instead of japanese-shift-jis and iso-latin-1 respectively in
+       order to share the default value with both Emacs and XEmacs-mule.
+       (mm-mule-charset-to-mime-charset):
+       Make mm-coding-system-priorities effective.
+       (mm-sort-coding-systems-predicate): Canonicalize coding-systems
+       while predicating of candidates upon the priorities.
+
+2004-06-27  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-summary-make-menu-bar):
+       Add gnus-uu-invert-processable.
+
+       * gnus.el: Autoload gnus-uu-invert-processable.
+
+2004-06-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-with-multibyte-buffer): New macro.
+
+       * rfc2047.el (rfc2047-encode-string): Use it.
+       (rfc2047-encode-region): Move point to the end of the region after
+       encoding.  Suggested by IRIE Tetsuya <irie@t.email.ne.jp>.
+
+2004-06-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-cite.el (gnus-cite-parse): Don't ignore case when finding
+       ">From ".  Thanks to Reiner Steib <Reiner.Steib@gmx.de>.
+
+2004-06-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-cite.el (gnus-cite-ignore-quoted-from): New user option.
+       (gnus-cite-parse): Ignore quoted envelope From_.
+       Suggested by Karl Chen <quarl@nospam.quarl.org>.
+
+2004-06-23  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-idna-to-ascii-rhs-1): Don't choke on
+       invalid addresses.
+
+2004-06-21  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el: Change section markers, revise TODO list.
+       (spam-backends): Make new master list of all installed backends.
+       (spam-summary-exit-behavior): Add new variable to determine how
+       messages moves are done at summary exit.
+       (spam-move-spam-nonspam-groups-only)
+       (spam-process-ham-in-nonham-groups)
+       (spam-process-ham-in-spam-groups): Remove variables, the
+       spam-summary-exit-behavior variable should be used to manage this
+       behavior.
+       (spam-old-ham-articles, spam-old-spam-articles): Remove.
+       (spam-old-articles): Add variable, replacing spam-old-ham-articles
+       and spam-old-spam-articles.
+       (spam-use-copy, spam-use-move, spam-use-gmane, spam-use-resend):
+       Add empty variables, placeholders for the backends they represent.
+       (spam-set-difference): Move, unchanged.
+       (spam-list-of-processors): Declare OBSOLETE, not used anymore
+       unless the user has a processor variable.
+       (spam-classifications, spam-classification-valid-p)
+       (spam-backend-properties, spam-backend-property-valid-p)
+       (spam-backend-function-type-valid-p)
+       (spam-process-type-valid-p, spam-list-articles): Add helper functions.
+       (spam-report-articles-gmane, spam-report-articles-resend):
+       Remove functions, they are not needed.
+       (spam-install-backend-super, spam-backend-list)
+       (spam-backend-check, spam-backend-valid-p, spam-backend-info)
+       (spam-backend-function, spam-backend-ham-registration-function)
+       (spam-backend-spam-registration-function)
+       (spam-backend-ham-unregistration-function)
+       (spam-backend-spam-unregistration-function)
+       (spam-backend-statistical-p, spam-backend-mover-p)
+       (spam-install-backend-alias, spam-install-checkonly-backend)
+       (spam-install-mover-backend, spam-install-nocheck-backend)
+       (spam-install-backend, spam-install-statistical-backend)
+       (spam-install-statistical-checkonly-backend): Add backend installation
+       support.
+       (spam-summary-prepare-exit): Rewrite to use the new backend code.
+       (spam-group-processor-p): Use the new backend code and respect the
+       summary exit behavior.
+       (spam-mark-spam-as-expired-and-move-routine): Remove.
+       (spam-summary-prepare): Change to use the new spam-old-articles
+       variable.
+       (spam-copy-or-move-routine, spam-copy-spam-routine)
+       (spam-move-spam-routine, spam-copy-ham-routine)
+       (spam-move-ham-routine): Add code to copy/move ham or spam.
+       (spam-fetch-field-fast): Improve doc and code, plus allow the
+       'number request.
+       (spam-list-of-checks, spam-list-of-statistical-checks):
+       Remove variables.
+       (spam-split, spam-find-spam): Use the new backend code.
+       (spam-registration-functions): Remove variable.
+       (spam-unregister-routine): Add convenience wrapper.
+       (spam-log-undo-registration, spam-register-routine)
+       (spam-log-processing-to-registry)
+       (spam-log-unregistration-needed-p): Rename "check" to "backend"
+       where possible.
+       (spam-check-gmane-xref, spam-check-regex-headers)
+       (spam-check-blackholes, spam-check-stat, spam-check-ifile)
+       (spam-check-BBDB, spam-check-whitelist, spam-check-blacklist)
+       (spam-check-bogofilter-headers, spam-check-spamoracle)
+       (spam-check-spamassassin-headers, spam-check-bsfilter-headers)
+       (spam-check-crm114-headers): Use the spam-split-group that
+       spam-split prepares, no need to determine it every time.
+
+       * nnimap.el (nnimap-retrieve-headers-progress): Add the message number
+       to the nnheader-parse-naked-head call.
+
+       * nnheader.el (nnheader-generate-fake-message-id): Fix indentation.
+
+       * gnus-sum.el (gnus-nov-parse-line): Add the message number to
+       the nnheader-nov-read-message-id call.
+
+2004-06-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el (gnus-group-get-new-news-this-group): Don't call
+       gnus-activate-group twice.  Suggested by Markus Peter
+       <warp@spin.de>.
+
+2004-06-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-time-format): Exchange the order of
+       day and month in the default value; fix customization type.
+       (article-date-ut): Use add-text-properties.
+       (article-make-date-line): Use message-make-date instead of
+       current-time-string.
+
+       * message.el (message-fetch-field): Don't use set-text-properties.
+       (message-make-date): Simplify.
+
+       * messagexmas.el (message-xmas-make-date): New function.
+       (message-xmas-redefine): Defalias message-make-date to it.
+
+2004-06-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-syntax-table): Treat `(' and `)' as is.
+       (rfc2047-encode-region): Treat text within parentheses as special;
+       show the original text when error has occurred.
+
+       * gnus-group.el (gnus-group-get-new-news-this-group): Pass the
+       already-computed method to gnus-activate-group.
+
+       * gnus-start.el (gnus-make-hashtable-from-newsrc-alist): Make the
+       same select-methods identical Lisp objects.
+
+       * gnus-srvr.el (gnus-server-set-info): Don't make a new Lisp
+       object when modifying the info.
+
+2004-06-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-srvr.el (gnus-server-set-info): Remove the server from
+       gnus-opened-servers since it has never been opened with the new
+       configuration yet.
+
+2004-06-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnheader.el (nnheader-nov-read-message-id): Pass the optional
+       arg to nnheader-generate-fake-message-id.
+
+2004-06-14  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * nnheader.el (nnheader-generate-fake-message-id): Accept a
+       number and build a fake message ID localized to a group and
+       article number (so it's repeatable from that point on).
+       (nnheader-fake-message-id-p): Change regex to accomodate new fake
+       ID format.
+
+       * gnus-sum.el (gnus-get-newsgroup-headers):
+       Call nnheader-generate-fake-message-id with the article number.
+
+2004-06-12  YAGI Tatsuya  <ynyaaa@ybb.ne.jp>  (tiny change)
+
+       * gnus-art.el (gnus-article-next-page): Fix the way to find a real
+       end-of-buffer.
+
+2004-06-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-ignored-supersedes-headers): Add Approved.
+
+2004-06-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-encode-message-header): Remove useless
+       goto-char.
+       (rfc2047-encode): Fold the line before encoding.
+
+2004-06-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * rfc2047.el (rfc2047-encode-message-header): Disabled header
+       folding -- not all headers can be folded, and this should be done
+       by the message composition mode.  Probably.  I think.
+
+2004-06-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-remove-text-with-property): Make it slightly
+       fast.
+
+       * gnus-ems.el (gnus-remove-image): Don't use
+       message-text-with-property; remove only the image found first.
+
+       * gnus-xmas.el (gnus-xmas-remove-image): Remove only the image
+       found first.
+
+2004-06-09  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-send-mail-with-sendmail): Use with-current-buffer.
+
+2004-06-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-text-with-property): Make it fast and accept
+       optional arguments.
+       (message-strip-forbidden-properties): Use it.
+       (message-fix-before-sending): Follow the m-t-w-p change.
+
+       * gnus-ems.el (gnus-remove-image): Follow the m-t-w-p change.
+
+2004-06-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-hide-headers): Don't change the buffer
+       mistakenly when performing mml-preview even if
+       gnus-single-article-buffer is nil.
+
+2004-06-08  Kai Grossjohann  <kgrossjo@eu.uu.net>
+
+       * message.el (message-expand-name-databases): New user option.
+       (message-expand-name): Use it.
+
+2004-06-07  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-report-articles-resend)
+       (spam-report-resend-register-routine): Allow ham reporting.
+       (spam-report-resend-register-ham-routine): Add wrapper.
+       (spam-registration-functions): Add ham resending functions.
+       (spam-list-of-processors): Add ham resend processor.
+
+       * gnus.el (ham-resend-to): Add new group parameter.
+       (spam-process): Add ham resend option.
+
+       * spam-report.el (spam-report-resend): Allow reporting ham.
+       (spam-report-resend-ham): Add wrapper.
+
+2004-06-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-cite-articles-with-x-no-archive):
+       New variable.
+       (message-cite-original): Use it.
+
+2004-06-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-cite-original): Respect X-No-Archive.
+
+2004-06-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-hide-headers): Refer to the values for
+       gnus-ignored-headers and gnus-visible-headers in the summary
+       buffer since a user may have set them as group parameters.
+
+2004-06-03  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * assistant.el (assistant-node-name): Add convenience function.
+       (assistant-render-text, assistant-render-node): Add error handling,
+       plus handle multiple next nodes.
+       (assistant-find-next-node): Comment out for now.
+       (assistant-find-next-nodes): Add function, returns list of next
+       nodes.
+
+2004-06-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mail-source.el (mail-source-directory): Fix doc-string.
+
+2004-05-29  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * assistant.el (assistant-render-text, assistant-eval): Add :set
+       widget type, which is different because it takes and returns a
+       list.  Much hilarity ensues.
+
+2004-05-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button-alist): Fix regexp for manual links.
+
+       * gnus-group.el (gnus-group-get-new-news-this-group):
+       Add doc-string.
+
+       * gnus-start.el (gnus-activate-group): Add doc-string.
+
+2004-05-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-encode.el (mm-safer-encoding): Consider 7bit is safe.
+
+2004-05-27  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * assistant.el (assistant-render-text): Try to add a :set
+       widget, more to come.
+
+       * spam.el (spam-group-spam-contents-p): Handle empty groupname
+       strings.
+       (spam-report-articles-resend)
+       (spam-register-routine): Do registration iff any articles warrant
+       it.
+       (spam-summary-prepare-exit): Change log message for nil group
+       destinations.
+
+2004-05-27  Daniel Pittman  <daniel@rimspace.net>
+
+       * spam.el (spam-report-resend-register-routine):
+       Allow spam-report-resend-to to be a group parameter or a global value.
+
+2004-05-26  Simon Josefsson  <jas@extundo.com>
+
+       * starttls.el: Merge with my GNUTLS based starttls.el.
+       (starttls-gnutls-program, starttls-use-gnutls)
+       (starttls-extra-arguments, starttls-process-connection-type)
+       (starttls-connect, starttls-failure, starttls-success):
+       New variables.
+       (starttls-program, starttls-extra-args): Doc fix.
+       (starttls-negotiate-gnutls, starttls-open-stream-gnutls):
+       New functions.
+       (starttls-negotiate, starttls-open-stream):
+       Check `starttls-use-gnutls' and pass on to corresponding *-gnutls
+       function if it is set.
+
+2004-05-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-encode-region): Encode encoded words in
+       structured fields.
+
+2004-05-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-resend): Bind rfc2047-encode-encoded-words.
+
+2004-05-26  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-mark-new-messages-in-spam-group-as-spam):
+       Add variable.
+       (spam-mark-junk-as-spam-routine): Use it.  Allow to disable
+       assigning the spam-mark to new messages.
+
+2004-05-26  Adam Sjøgren  <asjo@koldfront.dk>  (tiny change)
+
+       * spam.el (spam-ham-copy-or-move-routine): Don't declare `todo' twice.
+
+2004-05-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el: Autoload customize-set-variable for XEmacs.
+
+       * rfc2047.el (rfc2047-encodable-p): Don't move point.
+       (rfc2047-decode): Treat the ascii coding-system as raw-text by
+       default.
+
+2004-05-25  Anand Mitra  <mitramc@yahoo.com>  (tiny change)
+
+       * gnus-sum.el (gnus-summary-delete-article): Invoke hook with
+       correct data.
+
+2004-05-24  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-list-of-processors): Use nil for nonexistent processors.
+       (spam-group-processor-p): Fix function.
+       (spam-group-processor-multiple-p)
+       (spam-group-spam-processor-report-gmane-p)
+       (spam-group-spam-processor-report-resend-p)
+       (spam-group-spam-processor-bogofilter-p)
+       (spam-group-spam-processor-blacklist-p)
+       (spam-group-spam-processor-ifile-p)
+       (spam-group-ham-processor-ifile-p)
+       (spam-group-spam-processor-spamoracle-p)
+       (spam-group-spam-processor-crm114-p)
+       (spam-group-ham-processor-bogofilter-p)
+       (spam-group-spam-processor-stat-p)
+       (spam-group-ham-processor-stat-p)
+       (spam-group-ham-processor-whitelist-p)
+       (spam-group-ham-processor-BBDB-p)
+       (spam-group-ham-processor-spamoracle-p)
+       (spam-group-ham-processor-copy-p): Remove functions with some
+       prejudice against unneeded code.
+       (spam-report-articles-resend)
+       (spam-report-resend-register-routine): Allow the group/topic
+       spam-resend-to value to override spam-report-resend-to.
+       (spam-summary-prepare-exit): Invoke spam-group-processor-p
+       properly now.
+
+       * gnus.el (spam-resend-to): Add group/topic parameter.
+       (spam-process): Move the OBSOLETE processors to the end of the
+       choices.
+
+2004-05-24  Daniel Pittman  <daniel@rimspace.net>
+
+       * spam-report.el (spam-report-resend-to, spam-report-resend):
+       Start with resend-to set to nil, and then ask the user if necessary.
+       (spam-report-resend): spam-report-resend takes a list of articles, not
+       separate article numbers.
+
+2004-05-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-text-html-renderer): Make sure w3m exists in
+       addition to emacs-w3m.
+
+2004-05-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * assistant.el (assistant-authinfo-data): New function.
+       (assistant-eval): Eval for entire assistant.
+
+       * netrc.el (netrc-services-file): New variable.
+       (netrc-parse-services): New function.
+       (netrc-find-service-name): New function.
+       (netrc-find-service-number): New function.
+       (netrc-port-equal): New function.
+       (netrc-machine): Use it.
+
+       * nnimap.el (nnimap-open-connection): Use netrc.
+
+       * gnus-util.el (gnus-netrc-get): Remove aliases.
+
+       * gnus-sum.el (gnus-auto-center-summary): Change default to 2.
+
+       * assistant.el (wid-edit): Fix compilation.
+
+       * gnus-util.el (gnus-set-file-modes): Just ignore errors.
+
+2004-05-23  Paul Stodghill  <stodghil@cs.cornell.edu>
+
+       * gnus-util.el (gnus-set-file-modes): New function.  (small
+       patch).
+
+2004-05-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-topic.el (gnus-topic-jump-to-topic): Goto missing topic.
+
+       * assistant.el (assistant-render-node): Fix up rendering and
+       read-only text.
+       (assistant-render-node): Reset.
+       (assistant-make-read-only): Not sticky.
+
+2004-05-20  Danny Siu  <dsiu@adobe.com>
+
+       * gnus-sum.el (gnus-summary-recenter): Summary buffer was not auto
+       centered even when gnus-auto-center-summary is t.
+
+2004-05-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * dns.el (dns-get-txt-answer): New function.
+       (dns-read-txt): Ditto.
+       (query-dns): Use it.
+
+2004-05-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-start.el (gnus-get-unread-articles): Don't invalidate
+       active for foreign groups even if the group level is higher than
+       the specified value.
+
+2004-05-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-jump-to-group): Don't prompt for
+       non-active groups.
+
+       * gnus-art.el (gnus-picon-databases): Add /usr/share/picons.
+
+2004-05-20  Magnus Henoch  <mange@freemail.hu>
+
+       * dns.el (dns-read-type): Add support for SVR.  (small patch)
+
+2004-05-20  Adam Sjøgren  <asjo@koldfront.dk>
+
+       * spam.el (spam-use-crm114, spam-crm114, spam-crm114-program)
+       (spam-crm114-header, spam-crm114-spam-switch)
+       (spam-crm114-spam-strong-switch, spam-crm114-ham-strong-switch)
+       (spam-crm114-positive-spam-header)
+       (spam-crm114-database-directory, spam-list-of-processors)
+       (spam-group-spam-processor-crm114-p)
+       (spam-group-ham-processor-crm114-p, spam-extra-header-to-number)
+       (spam-generic-score, spam-list-of-checks)
+       (spam-list-of-statistical-checks, spam-registration-functions)
+       (spam-check-crm114-headers, spam-crm114-score)
+       (spam-check-crm114, spam-crm114-register-with-crm114)
+       (spam-crm114-register-spam-routine)
+       (spam-crm114-unregister-spam-routine)
+       (spam-crm114-register-ham-routine)
+       (spam-crm114-unregister-ham-routine): Add CRM114 support.
+
+2004-05-20  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.el: Add spam-use-crm114.
+
+       * spam.el (spam-list-of-processors, spam-registration-functions):
+       Add spam-use-resend.
+       (spam-group-spam-processor-report-resend-p): Add utility wrapper.
+       (spam-report-articles-gmane): Add doc fix.
+       (spam-report-articles-resend, spam-report-resend-register-routine):
+       Add wrappers around spam-report-resend-to.
+
+       * spam-report.el (spam-report-resend-to, spam-report-resend):
+       Add support for resending spam.
+       (spam-report-gmane): Fix line length >80.
+
+       * gnus.el (spam-process): Add spam-use-resend.
+
+2004-05-20  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * spam.el (spam-mark-spam-as-expired-and-move-routine): Return the
+       number of processed spam messages.
+       (spam-ham-copy-or-move-routine): Return the number of processed
+       ham messages.
+       (spam-summary-prepare-exit): Use the above values to decide
+       whether status messages should be displayed.
+
+2004-05-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-encode-function-alist): Rename from
+       `rfc2047-encoding-function-alist' in order to avoid conflicting
+       with the old version.
+       (rfc2047-encode-region): Concatenate words containing non-ASCII
+       characters in structured fields; don't encode space-delimited
+       ASCII words even in unstructured fields; don't break words at
+       char-category boundaries.
+       (rfc2047-encode-1): New function.
+       (rfc2047-encode): Use it; encode text so that it occupies the
+       maximum width within 76-column; work correctly on Q encoding for
+       iso-2022-* charsets.
+       (rfc2047-fold-region): Use existing whitespace for LWSP; make it
+       sure not to break a line just after the header name.
+       (rfc2047-b-encode-region): Remove.
+       (rfc2047-b-encode-string): New function.
+       (rfc2047-q-encode-region): Remove.
+       (rfc2047-q-encode-string): New function.
+
+       * mm-util.el (mm-replace-in-string): New function.
+
+2004-05-20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-inews-make-draft-meta-information):
+       Really get it right.
+       (gnus-inews-make-draft): Really.
+
+2004-05-19  Ben Menasha  <bmenasha@benmenasha.net>
+
+       * nnmh.el (nnmh-request-list-1): Don't check the link count
+       before descending.  (small patch)
+
+2004-05-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-inews-make-draft-meta-information): Fix quote
+       stuff.
+
+       * gnus-start.el (gnus-subscribe-hierarchical-interactive):
+       Match on real group name.
+
+       * gnus-art.el (gnus-signature-limit): Doc fix.
+
+       * gnus-msg.el (gnus-inews-make-draft): Quote list.
+
+       * pgg-pgp.el (pgg-pgp-verify-region): Clean up.
+
+2004-05-19  Michael Schierl  <schierlm-usenet@gmx.de>  (tiny change)
+
+       * pgg-pgp.el (pgg-pgp-verify-region): Default when signature
+       isn't a string.
+
+2004-05-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-draft.el (gnus-draft-send):
+       Bind rfc2047-encode-encoded-words.
+
+       * rfc2047.el (rfc2047-encode-region): Encode =? strings.
+       (rfc2047-encodable-p): Say that =? needs encoding.
+       (rfc2047-encode-encoded-words): New variable.
+
+       * gnus-group.el (gnus-group-select-group): Doc fix.
+
+       * gnus-draft.el (gnus-draft-setup): Mark all replied as replied.
+
+       * gnus-group.el (gnus-group-mode): Set show-trailing-whitespace
+       to nil.
+
+       * gnus-cache.el (gnus-cache-possibly-enter-article): Use it.
+
+       * nnheader.el (nnheader-get-lines-and-char): New function.
+
+2004-05-19  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-msg.el (gnus-summary-followup-with-original):
+       Document yanking of region when active.
+
+2004-05-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-start.el (gnus-get-unread-articles): Do nothing for foreign
+       groups if the group level is higher than the specified value.
+
+2004-05-18  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-group.el (gnus-group-jump-to-group-prompt): Allow an alist.
+       (gnus-group-jump-to-group): Add prefix argument using
+       `gnus-group-jump-to-group-prompt'.  Query before jumping to
+       non-active group.
+
+       * compface.el (uncompface): Be verbose when changing
+       `uncompface-use-external'.
+
+       * gnus-art.el (gnus-button-handle-man, gnus-button-alist): Try to
+       handle manual section.
+
+2004-05-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-button-alist): Revert previous change.
+
+2004-05-18  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-idna-to-ascii-rhs-1): Fix typo.
+
+2004-05-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-inews-do-gcc): Don't use read-only-p to see
+       whether backend can accept message.
+
+       * message.el (message-idna-to-ascii-rhs-1): Don't use equalp.
+
+2004-05-18  Kai Grossjohann  <kgrossjo@eu.uu.net>
+
+       * nntp.el (nntp-request-set-mark, nntp-request-update-info):
+       Avoid creating directory when nntp-marks-is-evil is true.
+       Reported by Reiner Steib.
+
+2004-05-18  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-picon.el (gnus-picon-insert-glyph):
+       Add optional `nostring' argument.
+
+2004-05-18  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-picon.el (gnus-picon-style): New variable.
+       (gnus-picon-transform-address): Support `gnus-picon-style'.
+
+2004-05-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-fill-field): Return point.
+       (message-generate-headers): Go to end of field.
+
+       * gnus-start.el (gnus-get-unread-articles-in-group): Don't do
+       stuff for non-living groups.
+
+2004-05-18  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-article-followup-with-original)
+       (gnus-article-reply-with-original): gnus-mark-active-p ->
+       gnus-region-active-p.
+
+2004-05-17  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-summary-prepare-exit): Fix messages, so they show
+       only when there is spam or ham to be processed.
+
+2004-05-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-delete-crash-box): Refactor.
+       (mail-source-fetch): Use it.
+       (mail-source-fetch-file): Ditto.
+       (mail-source-fetch-directory): Run postscript in loop.
+       (mail-source-fetch-pop): Delete.
+       (mail-source-fetch-maildir): Ditto.
+       (mail-source-fetch-imap): Ditto.
+
+       * imap.el (imap-authenticators): Comment out sasl.
+
+       * message.el (message-skip-to-next-address): New function.
+       (message-fill-header-address): Refactor.
+       (message-fill-address): Use it.
+       (message-delete-address): Use it.
+       (message-fill-header-general): Refactor.
+       (message-fill-field-address): Rename.
+       (message-narrow-to-field): Find the start of the header.
+       (message-header-format-alist): Don't pre-fill.
+       (message-fill-header): Remove.
+       (message-insert-header): New function.
+       (message-shorten-references): Use it.
+
+       * rfc2047.el (rfc2047-field-value): Strip props.
+
+       * mail-parse.el (mail-header-make-address): New alias.
+
+       * ietf-drums.el (ietf-drums-make-address): New function.
+
+       * imap.el: Add compiler directives.
+
+       * gnus-score.el (gnus-score-edit-done): run-hook->run-hooks.
+
+       * gnus-art.el (article-decode-idna-rhs): Don't use
+       message-idna-inside-rhs-p.
+
+2004-05-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-idna-inside-rhs-p): Remove.
+       (message-idna-to-ascii-rhs-1): Use proper address parsing.
+
+       * gnus-art.el (gnus-emphasis-alist): Remove strikethru; too many
+       false positives.
+
+2004-05-16  Kim-Minh Kaplan  <kmkaplan-AwwS6Bc0PDVoiYX5Tdu9fQ@public.gmane.org>
+
+       * imap.el (imap-sasl-make-mechanisms): Use sasl.
+
+2004-05-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nneething.el (nneething-file-name): Don't create spurious
+       files.
+
+       * gnus-msg.el (gnus-inews-do-gcc): Ignore read-only groups.
+       (gnus-inews-do-gcc): Remove sleep.
+
+       * gnus-art.el (gnus-mime-delete-part): Error message when no MIME
+       part under point.
+
+       * gnus-agent.el (gnus-agent-synchronize-flags): Default to nil.
+       (gnus-agent-regenerate-group): Using nil messages aren't valid.
+
+2004-05-15  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-summary-prepare-exit): Fix (length).
+
+2004-05-14  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-summary-prepare-exit): Fix to produce "marking spam
+       as expired without moving it" message when there are spam
+       messages left.
+
+2004-05-14  Nelson Ferreira  <nelson.ferreira@verizon.net>  (tiny change)
+
+       * gnus-dup.el (gnus-dup-unsuppress-article): Don't assume the mail
+       header is not nil.
+
+2004-05-14  Kai Grossjohann  <kgrossjo@eu.uu.net>
+
+       * nntp.el (nntp-request-set-mark, nntp-request-update-info):
+       Call nntp-possibly-create-directory, not nntp-possibly-change-group.
+       (nntp-marks-changed-p): New arg SERVER.
+       (nntp-request-update-info): Adjust caller.
+
+2004-05-14  Kai Grossjohann  <kai@emptydomain.de>
+
+       * nntp.el (nntp-save-marks): Pass missing arg.
+
+2004-05-13  Kai Grossjohann  <kai.grossjohann@gmx.net>
+
+       * nntp.el: Support marks.
+       (nntp-marks-is-evil, nntp-marks-file-name, nntp-marks)
+       (nntp-marks-modtime, nntp-marks-directory): New variables.
+       (nntp-request-set-mark, nntp-request-update-info)
+       (nntp-possibly-create-directory, nntp-marks-changed-p)
+       (nntp-save-marks, nntp-open-marks, nntp-marks-directory):
+       New functions.
+
+2004-05-12  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-xmas.el (gnus-xmas-select-lowest-window)
+       (gnus-xmas-redefine): Rename.
+
+       * gnus-score.el (gnus-score-insert-help):
+       Use gnus-select-lowest-window.
+
+       * gnus-ems.el (gnus-select-lowest-window): Copy definition of
+       appt-select-lowest-window and rename to gnus-select-lowest-window.
+
+       * gnus.el: do.
+
+2004-05-12  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * rfc2047.el (rfc2047-encode): Use uppercase letters to specify
+       encodings of MIME-encoded words, in order to improve
+       interoperability with several broken MUAs.
+
+2004-05-07  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * mm-view.el (mm-inline-text-html-render-with-w3): Check META
+       tags, only when charsets are not specified in headers.
+       (mm-inline-text-html-render-with-w3m): Ditto.
+
+       * lpath.el: Remove `w3m-meta-content-type-charset-regexp' and
+       `w3m-charset-to-coding-system'.  Add `w3m-detect-meta-charset'.
+
+2004-05-06  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * gnus-art.el (article-strip-banner): Use MIME-encoded from fields
+       instead of MIME-decoded from fields when checking
+       `gnus-article-address-banner-alist'.
+
+2004-05-03  Jesper Harder  <harder@ifa.au.dk>
+
+       * nnrss.el (nnrss-check-group, nnrss-read-group-data): Hash on
+       description rather than subject.
+
+2004-05-02  Steve Youngs  <steve@youngs.au.com>
+
+       * dgnushack.el: Autoload `mail-fetch-field' for XEmacs.
+
+2004-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Bump.
+
+2004-05-01  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: No Gnus v0.2 is released.
+
+2004-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-agent.el (gnus-agent-read-agentview):
+       Inline gnus-uncompress-range.
+
+2004-05-01  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * spam.el (spam-bsfilter-path): Use `executable-find' instead of
+       `exec-installed-p'.
+
+2004-04-30  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * gnus.el (spam-process, spam-autodetect-methods):
+       Add bsfilter and bsfilter-headers.
+
+       * spam.el (spam-bsfilter): New customize group.
+       (spam-use-bsfilter, spam-use-bsfilter-headers, spam-bsfilter-path)
+       (spam-bsfilter-header, spam-bsfilter-probability-header)
+       (spam-bsfilter-spam-switch, spam-bsfilter-ham-switch)
+       (spam-bsfilter-spam-strong-switch, spam-bsfilter-ham-strong-switch)
+       (spam-bsfilter-database-directory): New options.
+       (spam-install-hooks, spam-list-of-processors, spam-list-of-checks)
+       (spam-list-of-statistical-checks, spam-registration-functions):
+       Add `spam-use-bsfilter' and `spam-use-bsfilter-headers'.
+       (spam-bsfilter-score): New command.
+       (spam-check-bsfilter-headers, spam-check-bsfilter)
+       (spam-bsfilter-register-with-bsfilter)
+       (spam-bsfilter-register-spam-routine)
+       (spam-bsfilter-unregister-spam-routine)
+       (spam-bsfilter-register-ham-routine)
+       (spam-bsfilter-unregister-ham-routine): New functions.
+       (spam-generic-score): Support bsfilter; Accept an optional argument
+       to recalcurate spam score even if scoring header has already been
+       added.
+       (spam-bogofilter-score, spam-spamassassin-score): Accept an
+       optional argument to recalcurate spam score even if scoring header
+       has already been added.
+
+2004-04-29  Jesper Harder  <harder@ifa.au.dk>
+
+       * nnrss.el (nnrss-get-namespace-prefix): Use string= to compare
+       strings!  Reported by David D. Smith <davidsmith@acm.org>.
+       (nnrss-check-group, nnrss-read-group-data): Hash on Subject if
+       link is missing.
+
+2004-04-28  Jesper Harder  <harder@ifa.au.dk>
+
+       * html2text.el (html2text-replace-list): Add &amp; and &apos;.
+       (html2text-get-attr): Rewrite.
+
+       * message.el (message-setup-1): Remove redundant put-text-property
+       on mail-header-separator.
+
+2004-04-27  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-cache-whitespace)
+       (gnus-registry-action, gnus-registry-spool-action)
+       (gnus-registry-split-fancy-with-parent): Change message levels
+       from 5 to 3 or 7, as needed.
+
+       * spam.el (spam-summary-prepare-exit)
+       (spam-mark-junk-as-spam-routine, spam-fetch-field-fast)
+       (spam-split, spam-find-spam, spam-log-undo-registration)
+       (spam-check-blackholes, spam-enter-ham-BBDB): Change message
+       level from 5 to 6.
+
+2004-04-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-ems.el: Autoload appt-select-lowest-window (revert
+       2004-03-04 change).
+
+2004-04-25  Jesper Harder  <harder@ifa.au.dk>
+
+       * sieve-manage.el (sieve-manage-open):
+       * nnweb.el (nnweb-insert-html):
+       * nnvirtual.el (nnvirtual-catchup-group, nnvirtual-partition-sequence)
+       (nnvirtual-partition-sequence, nnvirtual-create-mapping):
+       * nnspool.el (nnspool-request-group):
+       * nnrss.el (nnrss-opml-export, nnrss-find-el, nnrss-order-hrefs):
+       * nnml.el (nnml-request-update-info):
+       * nnmh.el (nnmh-request-group, nnmh-request-list-1, nnmh-active-number)
+       (nnmh-request-create-group, nnmh-update-gnus-unreads):
+       * nnimap.el (nnimap-request-close, nnimap-acl-edit)
+       (nnimap-request-set-mark):
+       * nnfolder.el (nnfolder-request-update-info):
+       * mm-view.el (mm-pkcs7-signed-magic, mm-pkcs7-enveloped-magic):
+       * mml.el (mml-destroy-buffers, mml-compute-boundary-1):
+       * gnus-uu.el (gnus-uu-find-articles-matching):
+       * gnus-topic.el (gnus-topic-check-topology, gnus-topic-remove-group):
+       * gnus-sum.el (gnus-summary-fetch-faq, gnus-read-move-group-name):
+       * gnus-score.el (gnus-score-load-file, gnus-sort-score-files):
+       * gnus-nocem.el (gnus-nocem-scan-groups):
+       * gnus-int.el (gnus-start-news-server):
+       * gnus-group.el (gnus-group-make-kiboze-group)
+       (gnus-group-browse-foreign-server):
+       * spam-stat.el (spam-stat-score-buffer): Simplify mapcar usage.
+       Use mapc when appropriate.
+
+2004-04-22  Dan Christensen  <jdc@uwo.ca>
+           Adam Sjøgren  <asjo@koldfront.dk>
+           Wes Hardaker  <wes@hardakers.net>
+           Michael Shields  <shields@msrl.com>
+
+       * spam.el (spam-necessary-extra-headers): Get the extra headers we
+       may need for spam sorting and scoring.
+       (spam-user-format-function-S): Add user format function suitable for
+       general use.
+       (spam-article-sort-by-spam-status): Add sorting function for summary
+       sorting.
+       (spam-extra-header-to-number): Add function to get a score from a
+       header.
+       (spam-summary-score): Add function to get a numeric score from the
+       headers.
+       (spam-generic-score): Fix function doc, was in wrong place.
+       (spam-initialize): Take symbols when it's run, and install the
+       extra headers that spam-necessary-extra-headers thinks we need.
+
+2004-04-21  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-summary-prepare-exit): Add logic and message fix.
+       Reported by bojohan+news@dd.chalmers.se (Johan Bockgård).
+
+2004-04-17  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-set-global-variables)
+       (gnus-build-all-threads, gnus-get-newsgroup-headers)
+       (gnus-article-get-xrefs, gnus-summary-best-group)
+       (gnus-summary-next-article, gnus-summary-enter-digest-group)
+       (gnus-summary-set-bookmark, gnus-offer-save-summaries)
+       (gnus-summary-update-info, gnus-kill-or-deaden-summary):
+       Use with-current-buffer.
+
+2004-04-16  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-summary-prepare-exit): Simplify logic.
+       (spam-fetch-article-header): Read the article header if it's not
+       available.
+       (spam-list-articles): Simplify logic.
+       (spam-filelist-register-routine): Fix bug with unregister-list.
+
+       * gnus-registry.el: Fix comments at beginning.
+
+2004-04-16  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-cater-to-broken-inn): Remove.
+       (message-shorten-references): Make sure the total folded length of
+       References is shorter than 998 characters to cater to a bug in INN
+       2.3.  Also, don't pretend that references aren't folded -- this
+       hasn't worked for a while.
+
+2004-04-15  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agentize):
+       gnus-agent-send-mail-real-function no longer set to current value
+       of message-send-mail-function but rather a lambda that calls
+       message-send-mail-function.  The change makes the agent real-time
+       responsive to user changes to message-send-mail-function.
+
+2004-04-15  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * legacy-gnus-agent.el
+       (gnus-agent-convert-to-compressed-agentview): Fix typos with
+       help from Florian Weimer <fw@deneb.enyo.de>
+
+2004-04-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnmail.el (nnmail-cache-insert): Revert last change.
+
+2004-04-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnmail.el (nnmail-cache-insert): Always check whether
+       nnmail-cache-ignore-groups matches a group name.
+
+2004-04-13  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-fetch-field-fast, spam-generate-fake-headers)
+       (spam-find-spam, spam-log-processing-to-registry)
+       (spam-log-registered-p, spam-log-unregistration-needed-p)
+       (spam-log-undo-registration): Use gnus-message instead of
+       gnus-error, none of these errors are fatal.
+
+       * gnus-registry.el (gnus-registry-clean-empty-function)
+       (gnus-registry-clean-empty): Remove only empty entries without
+       extra data.
+
+2004-04-12  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam-stat.el (spam-stat-buffer-change-to-spam)
+       (spam-stat-buffer-change-to-non-spam): Change (error) to
+       (gnus-message 8) invocation.
+
+2004-04-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nntp.el (nntp-via-netcat-command): New variable.
+       (nntp-via-netcat-switches): New variable.
+       (nntp-open-via-rlogin-and-netcat): New function.
+       (nntp-open-connection-function): Doc fix.
+       (nntp-telnet-command): Doc fix.
+       (nntp-end-of-line): Doc fix.
+       (nntp-via-rlogin-command): Doc fix.
+       (nntp-via-user-name): Doc fix.
+       (nntp-via-address): Doc fix.
+
+2004-04-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml2015.el (mml2015-use): Avoid the "Recursive load suspected"
+       error in Emacs 21.1.
+
+2004-04-08  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-start.el (gnus-get-unread-articles): Fix last commit.
+
+2004-04-07  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-total-fetched-hashtb): New variable.
+       (gnus-agent-with-refreshed-group): New macro.
+       (gnus-agent-rename-group): New function.
+       (gnus-agent-delete-group): New function.
+       (gnus-agent-save-group-info): Use gnus-command-method when
+       `method' parameter is nil.  Don't write nil entries into the
+       active file.
+       (gnus-agent-get-group-info): New function.
+       (gnus-agent-fetch-articles):
+       Use gnus-agent-update-files-total-fetched-for to increment disk space
+       used.
+       (gnus-agent-fetch-headers, gnus-agent-save-alist):
+       Use gnus-agent-update-view-total-fetched-for to increment disk space
+       used.
+       (gnus-agent-get-local): Add optional parameters to avoid calling
+       gnus-group-real-name and gnus-find-method-for-group.
+       (gnus-agent-set-local): Delete stored entry if either min, or max,
+       are nil.
+       (gnus-agent-fetch-session): Reworded error/quit messages.
+       On quit, use gnus-agent-regenerate-group to record existance of any
+       articles fetched to disk before the quit occurred.
+       (gnus-agent-expire-group-1): Use gnus-agent-with-refreshed-group,
+       gnus-agent-update-view-total-fetched-for, and
+       gnus-agent-update-files-total-fetched-for to decrement disk space
+       used.
+       (gnus-agent-retrieve-headers):
+       Use gnus-agent-update-view-total-fetched-for to increment disk space
+       used.
+       (gnus-agent-regenerate-group): Replace gnus-group-update-group
+       with gnus-agent-update-files-total-fetched-for to decrement disk
+       space and fresh group buffer.
+       (gnus-agent-inhibit-update-total-fetched-for): New variable.
+       (gnus-agent-need-update-total-fetched-for): New variable.
+       (gnus-agent-update-files-total-fetched-for): New function.
+       (gnus-agent-update-view-total-fetched-for): New function.
+       (gnus-agent-total-fetched-for): New function.
+
+       * gnus-cache.el (gnus-cache-save-buffers):
+       Use gnus-cache-update-overview-total-fetched-for to change disk space
+       used by this group.
+       (gnus-cache-possibly-enter-article):
+       Use gnus-cache-update-file-total-fetched-for to increment disk space
+       used by this group.
+       (gnus-cache-possibly-remove-article):
+       Use gnus-cache-update-file-total-fetched-for to decrement disk space
+       used by this group.
+       (gnus-cache-generate-nov-databases): Purge total fetched cache.
+       (gnus-cache-rename-group): New function.
+       (gnus-cache-delete-group): New function.
+       (gnus-cache-inhibit-update-total-fetched-for): New variable.
+       (gnus-cache-need-update-total-fetched-for): New variable.
+       (gnus-cache-with-refreshed-group): New macro.
+       (gnus-cache-update-file-total-fetched-for): New function.
+       (gnus-cache-update-overview-total-fetched-for): New function.
+       (gnus-cache-rename-group-total-fetched-for): New function.
+       (gnus-cache-delete-group-total-fetched-for): New function.
+       (gnus-cache-total-fetched-for): New function.
+
+       * gnus-group.el: Require gnus-sum and autoload functions to
+       resolve warnings when gnus-group.el compiled alone.
+       (gnus-group-line-format): Document new %F.
+       (size of Fetched data) group line format; identifies disk space
+       used by agent and cache.
+       (gnus-group-line-format-alist): Define new F format.
+       (gnus-total-fetched-for): New function.
+       (gnus-group-delete-group): No longer update
+       gnus-cache-active-altered as gnus-request-delete-group now keeps
+       the cache in sync.
+       (gnus-group-list-active): Let the agent store a server's active
+       list if currently plugged.
+
+       * gnus-int.el (gnus-request-delete-group):
+       Use gnus-cache-delete-group and gnus-agent-delete-group to keep the
+       local disk in sync with the server.
+       (gnus-request-rename-group):
+       Use gnus-cache-rename-group and gnus-agent-rename-group to keep the
+       local disk in sync with the server.
+
+       * gnus-start.el (gnus-get-unread-articles):
+       Cosmetic simplification to logic.
+
+       * gnus-util.el (gnus-rename-file): New function.
+
+2004-04-07  Christian Neukirchen  <chneukirchen@yahoo.de>  (tiny change)
+
+       * mm-util.el (mm-image-load-path): Handle nil in load-path.
+
+2004-04-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * rfc2047.el (rfc2047-encoded-word-regexp): Remove unnecessary
+       '+'.  Reported by Stefan Wiens <s.wi@gmx.net>.
+
+2004-04-06  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-cache.el (gnus-cache-save-buffers): Check if buffer is
+       alive.  Reported by Laurent Martelli <laurent@aopsys.com>.
+
+2004-04-03  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.el (gnus-getenv-nntpserver): Strip whitespace.
+
+2004-04-02  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-set-difference): Add function to replace
+       gnus-set-difference in spam.el.
+       (spam-summary-prepare-exit): Use spam-set-difference.
+
+2004-03-29  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-cache-file): Update to use
+       gnus-dribble-directory OR gnus-home-directory OR ~.
+       (gnus-registry-split-fancy-with-parent): Fix doc.
+
+2004-03-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-exchange-point-and-mark):
+       Use message-mark-active-p.  Suggested by Jesper Harder
+       <harder@ifa.au.dk>.
+
+2004-03-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-exchange-point-and-mark): Don't activate
+       region if it was inactive.  Suggested by Hiroshi Fujishima
+       <pooh@nature.tsukuba.ac.jp>.
+
+2004-03-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-display-face): Display Faces in the same
+       order as X-Faces.
+
+2004-03-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nndoc.el (nndoc-forward-type-p): Recognize envelope From_.
+
+2004-03-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-recompute-hierarchical-structure): Remove.
+       (gnus-mime-multipart-functions): Revert 2004-03-19 change.
+       (gnus-article-mime-hierarchy): Remove.
+       (gnus-article-mime-hierarchy-next): Remove.
+       (gnus-article-mode): Revert 2004-03-19 change.
+       (gnus-article-setup-buffer): Revert 2004-03-19 change.
+       (gnus-insert-mime-button): Revert 2004-03-19 change.
+       (gnus-mime-accumulate-hierarchy): Remove.
+       (gnus-mime-enter-multipart): Remove.
+       (gnus-mime-leave-multipart): Remove.
+       (gnus-mime-display-part): Revert 2004-03-19 change.
+       (gnus-mime-display-alternative): Revert 2004-03-19 change.
+
+       * mml.el (mml-preview): Revert 2004-03-19 change.
+
+2004-03-18  Helmut Waitzmann  <Helmut.Waitzmann@web.de>  (tiny change)
+
+       * gnus-sum.el (gnus-newsgroup-variables): Doc fix.
+
+2004-03-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-save-part): Bind enable-multibyte-characters to
+       t while entering a file name using the mm-with-multibyte macro.
+       Suggested by Hiroshi Fujishima <pooh@nature.tsukuba.ac.jp>.
+
+       * mm-util.el (mm-with-multibyte): New macro.
+
+2004-03-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-recompute-hierarchical-structure):
+       New user option.
+       (gnus-mime-multipart-functions): Doc and customization fix.
+       (gnus-article-mime-hierarchy): New variable.
+       (gnus-article-mime-hierarchy-next): New variable.
+       (gnus-article-mode): Make gnus-article-mime-hierarchy buffer-local.
+       (gnus-article-setup-buffer): Set gnus-article-mime-hierarchy and
+       gnus-article-mime-hierarchy-next to nil.
+       (gnus-insert-mime-button): Show hierarchy numbers.
+       (gnus-mime-accumulate-hierarchy): New function.
+       (gnus-mime-enter-multipart): New function.
+       (gnus-mime-leave-multipart): New function.
+       (gnus-mime-display-part): Recompute hierarchical MIME structure.
+       (gnus-mime-display-alternative): Show hierarchy numbers.
+
+       * mml.el (mml-preview): Set gnus-article-mime-hierarchy and
+       gnus-article-mime-hierarchy-next to nil.
+
+2004-03-19  Steve Youngs  <sryoungs@bigpond.net.au>
+
+       * dns.el: Don't require gnus-xmas.
+
+2004-03-17  Jesper Harder  <harder@ifa.au.dk>
+
+       * mml.el (mml-generate-mime-1): Don't use format=flowed with
+       inline PGP.
+       (mml-menu): Disable mml-quote-region if mark is inactive.
+
+2004-03-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-agent.el (gnus-agent-regenerate-group): Activate the group
+       when the group's active is not available.
+
+2004-03-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-agent.el (gnus-agent-read-agentview): Add a missing arg to
+       error.
+
+2004-03-12  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * imap.el (imap-store-password): New variable.
+       (imap-interactive-login): Use it.
+       Suggested by Mark Plaksin <happy@mcplaksin.org>.
+
+2004-03-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-read-summary-keys): Restore new
+       window-start and hscroll to summary window.
+
+2004-03-12  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-start.el (gnus-convert-old-newsrc): Only write the
+       conversion message to newsrc-dribble when an actual conversion is
+       performed.
+
+2004-03-10  Malcolm Purvis  <malcolmpurvis@optushome.com.au>  (tiny change)
+
+       * spam-stat.el (spam-stat-coding-system): Use mm-coding-system-p.
+
+2004-03-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-complicated-handles): New function reviving
+       former definition of mm-multiple-handles.
+
+       * gnus-art.el (gnus-mime-save-part-and-strip): Use it.
+       (gnus-mime-delete-part): Use it.
+
+2004-03-09  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-read-local):
+       Bind nnheader-file-coding-system to gnus-agent-file-coding-system to
+       avoid the implicit assumption that they will always be equal.
+       (gnus-agent-save-local): Bind buffer-file-coding-system, not
+       coding-system-for-write, as the with-temp-file macro first prints
+       to a buffer then saves the buffer.
+
+2004-03-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-edit-part): New function.
+       (gnus-mime-save-part-and-strip): Use it; do query instead of
+       signaling an error; don't use mm-multiple-handles.
+       (gnus-mime-delete-part): Ditto.
+
+2004-03-08  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-read-agentview): Remove support for
+       old file versions.
+       (gnus-group-prepare-hook): Remove function that converted list
+       form of gnus-agent-expire-days to group properties.
+
+       * gnus-int.el: Autoload gnus-agent-regenerate-group.
+       (gnus-request-accept-article): Re-indented.
+
+       * gnus-start.el (gnus-convert-old-newsrc): Registered new
+       converters to handle old agent file formats.  Add logic for a
+       "backup before upgrading warning".
+       (gnus-convert-mark-converter-prompt): Developers can mark
+       functions as needing (default), or not needing,
+       gnus-convert-old-newsrc's "backup before upgrading warning".
+       (gnus-convert-converter-needs-prompt): Tests whether the user
+       should be protected from potentially irreversable changes by the
+       function.
+
+       * legacy-gnus-agent.el: New.  Provides converters that are only
+       loaded when gnus-convert-old-newsrc needs to call them.
+
+2004-03-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mail-source.el (mail-source-touch-pop): Doc fix.
+
+       * message.el (message-smtpmail-send-it): Doc fix.
+
+2004-03-05  Jesper Harder  <harder@ifa.au.dk>
+
+       * sha1-el.el (sha1-maximum-internal-length): Doc fix.
+
+       * nnmail.el (nnmail-split-fancy): do.
+
+       * gnus-kill.el (gnus-kill, gnus-execute): do.
+
+2004-03-05  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus-sum.el (gnus-widget-reversible-match)
+       (gnus-widget-reversible-to-internal)
+       (gnus-widget-reversible-to-external): New functions.
+       (gnus-widget-reversible): New widget.
+       (gnus-article-sort-functions, gnus-thread-sort-functions): Use it.
+
+2004-03-05  Kai Grossjohann  <kgrossjo@eu.uu.net>
+
+       * gnus-sum.el (gnus-thread-sort-functions)
+       (gnus-article-sort-functions): Document `(not F)' items.
+
+2004-03-04  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-use-gmane-xref): Add new backend.
+       (spam-gmane-xref-spam-group): Add variable to control the name of the
+       Gmane spam group.
+       (spam-blackhole-servers, spam-blackhole-good-server-regex)
+       (spam-regex-headers-spam, spam-regex-headers-ham)
+       (spam-regex-body-spam, spam-regex-body-ham): Clarify docs.
+       (spam-list-of-checks): Add spam-use-gmane-xref to list of
+       backends and checks.
+       (spam-check-gmane-xref): Add function for spam-use-gmane-xref.
+
+       * gnus.el (spam-autodetect-methods): Add spam-use-gmane-xref as
+       an autodetect method.
+
+2004-03-04  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-int.el (gnus-request-accept-article): Inform the agent that
+       articles are being added to a group.
+       (gnus-request-replace-article): Inform the agent that articles
+       need to be uncached as the cached contents are no longer valid.
+
+2004-03-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * binhex.el: Don't autoload executable-find.
+
+       * canlock.el: Don't autoload mail-fetch-field.
+
+       * dgnushack.el: Autoload c-mode for XEmacs.
+
+       * gnus-ems.el: Don't autoload appt-select-lowest-window.
+
+       * gnus-msg.el: Don't autoload news-reply-mode, news-setup,
+       rmail-dont-reply-to and rmail-output.
+
+       * gnus-score.el: Don't autoload ffap-string-at-point.
+
+       * gnus-setup.el: Don't autoload sc-cite-original.
+
+       * imap.el: Don't autoload base64-decode-string,
+       base64-encode-string and md5.
+
+       * message.el: Autoload rmail-dont-reply-to, rmail-msg-is-pruned
+       and rmail-msg-restore-non-pruned-header.
+
+       * mm-decode.el: Don't autoload executable-find.
+
+       * mm-url.el: Don't autoload executable-find.
+
+       * mm-view.el: Don't autoload diff-mode.
+
+       * nndb.el: Don't autoload news-reply-mode, news-setup,
+       cancel-timer and telnet.
+
+       * password.el: Don't autoload run-at-time for Emacs.
+
+       * sha1-el.el: Don't autoload executable-find.
+
+       * sieve-mode.el: Don't autoload c-mode.
+
+       * uudecode.el: Don't autoload executable-find.
+
+2004-03-04  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-file-header-cache): Remove.
+       (gnus-agent-possibly-alter-active): Avoid null in numeric
+       comparison.
+       (gnus-agent-set-local): Refuse to save null in local object table.
+       (gnus-agent-regenerate-group): The REREAD parameter can now be a
+       list of articles that will be marked as unread.
+
+2004-03-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-encoded-word-regexp): Mismatched paren.
+
+2004-03-04  Jesper Harder  <harder@ifa.au.dk>
+
+       * rfc2047.el (rfc2047-encoded-word-regexp): Support RFC 2231
+       language tags.
+
+2004-03-03  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus-agent.el (gnus-agent-read-local, gnus-agent-save-local):
+       Don't bind "obarray".
+
+       * gnus-sum.el (gnus-thread-sort-functions):
+       Add `gnus-thread-sort-by-most-recent-number' and
+       `gnus-thread-sort-by-most-recent-date'.
+       Reported by Kai Grossjohann <kai@emptydomain.de>.
+
+2004-03-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-cus.el (gnus-agent-customize-category): Mismatched paren.
+
+2004-03-02  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-cus.el (gnus-agent-customize-category):
+       Remove ignore-errors macro reference that required cl to be loaded at
+       run-time.
+
+       * gnus-range.el (gnus-sorted-range-intersection): Now accepts
+       single-interval range of the form (min . max).  Previously the
+       range had to look like ((min . max)).  Likewise, return
+       (min . max) rather than ((min . max)).
+       (gnus-range-map): Use gnus-range-normalize to accept
+       single-interval range.
+
+       * gnus-sum.el (gnus-summary-highlight-line): Articles stored in
+       the cache, but not the agent, now appear with their usual face.
+
+       * dgnushack.el (loaddir): New variable that is bound to the
+       directory containing the dgnushack.el file.  Use loaddir, rather
+       than srcdir, to update load-path.  Change lets dgnushack compile
+       code in directories other than GNUS/lisp.
+
+2004-03-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Don't bind w3m-safe-url-regexp.
+
+       * gnus-art.el (gnus-article-wash-html-with-w3m): Don't make the
+       w3m-safe-url-regexp variable buffer-local.
+
+       * mm-view.el (mm-inline-text-html-render-with-w3m): Ditto.
+
+2004-02-27  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-move-group-prefix-function): Add, default to
+       gnus-group-real-prefix.
+       (gnus-summary-move-article): Use it, instead of
+       gnus-group-real-prefix.
+
+2004-02-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Bind w3m-safe-url-regexp.
+
+       * gnus-art.el (gnus-article-wash-html-with-w3m): Make the
+       w3m-safe-url-regexp variable buffer-local and set it as the value
+       of mm-w3m-safe-url-regexp.
+
+       * mm-view.el (mm-inline-text-html-render-with-w3m): Ditto.
+
+       * gnus-msg.el (gnus-setup-message): Ignore an article copy while
+       parsing gnus-posting-styles when the message is not for replying.
+
+       * dgnushack.el: Autoload sgml-mode for XEmacs.
+
+       * nnrss.el (nnrss-opml-export):
+       Use mm-set-buffer-file-coding-system instead of
+       set-buffer-file-coding-system.
+
+2004-02-27  Jesper Harder  <harder@ifa.au.dk>
+
+       * spam-stat.el: Pedantic docstring and whitespace fixes (courtesy
+       of checkdoc.el).
+       * nnrss.el: do.
+       * gnus-mlspl.el: do.
+       * gnus-ml.el: do.
+       * gnus-srvr.el: do.
+
+       * nnrss.el (nnrss-opml-export): Turn on sgml-mode.
+
+2004-02-27  Kevin Ryde  <user42@zip.com.au>  (tiny change)
+
+       * gnus.el (gnus-group, gnus-summary, gnus-summary-sort):
+       Corrections to custom-manual links.
+
+       * gnus-art.el (gnus-article): Ditto.
+
+       * mm-decode.el (mime-display, mime-security): Ditto.
+
+2004-02-26  Jesper Harder  <harder@ifa.au.dk>
+
+       * flow-fill.el: Typo.
+
+2004-02-26  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * spam-wash.el: New file.
+
+2004-02-26  Mark A. Hershberger  <mah@everybody.org>
+
+       * nnrss.el (nnrss-opml-import, nnrss-opml-export): New functions.
+
+2004-02-26  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-summary-prepare-exit): Fix gnus-set-difference: needs
+       to be run with new-articles as LIST1, not LIST2.
+       (spam-registration-functions): Add spam-use-ham-copy as a nil
+       registration backend.
+
+2004-02-26  Jesper Harder  <harder@ifa.au.dk>
+
+       * spam-stat.el (spam-stat-washing-hook): New option.
+       (spam-stat-buffer-words): Use it.
+       (spam-stat-process-directory, spam-stat-test-directory):
+       Use insert-file-contents-literally.
+       (spam-stat-coding-system): New variable.
+       (spam-stat-load, spam-stat-save): Use it.
+
+2004-02-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * spam-report.el (spam-report-plug-agent):
+       Quote spam-report-url-to-file and spam-report-url-ping-plain.
+
+2004-02-25  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button-alist, gnus-header-button-alist):
+       Allow / in mailto URLs.
+
+2004-02-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * spam-report.el (spam-report-process-queue): Fix interactive use.
+       (spam-report-url-ping-temp-agent-function, spam-report-plug-agent)
+       (spam-report-unplug-agent): Doc fixes.
+       (spam-report-url-ping-mm-url, spam-report-url-to-file)
+       (spam-report-agentize, spam-report-deagentize): Autoload.
+
+2004-02-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (with-syntax-table): Redefine it for XEmacs 21.5.
+
+       * message.el (message-setup-fill-variables): Add mml tags to
+       paragraph-start and paragraph-separate.  Suggested by Andrew Korty
+       <ajk@iu.edu>.
+       (message-mode): Don't modify paragraph-separate there.
+
+2004-02-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * compface.el (uncompface-use-external): Default to undecided.
+       (uncompface-use-external-threshold): New variable.
+       (uncompface-float-time): New macro.
+       (uncompface): Determine whether to use the external decoder if
+       uncompface-use-external is undecided.
+
+2004-02-15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-view.el (mm-inline-image-emacs): Don't insert blank lines
+       after images.
+
+       * gnus-art.el (gnus-mime-display-single): Remove dead code.
+
+2004-02-14  Jesper Harder  <harder@ifa.au.dk>
+
+       * nnrss.el (nnrss-request-article, nnrss-find-el): Cleanup.
+
+       * html2text.el (html2text-get-attr, html2text-fix-paragraph): do.
+
+       * gnus-sum.el (gnus-summary-limit-to-age)
+       (gnus-summary-limit-children): do.
+
+       * gnus-int.el (gnus-request-scan): do.
+
+       * gnus-group.el (gnus-group-suspend): do.
+
+       * gnus-cus.el (gnus-agent-cat-prepare-category-field): do.
+
+       * gnus-cite.el (gnus-cite-parse-attributions): do.
+
+       * gnus-agent.el (gnus-summary-set-agent-mark)
+       (gnus-agent-regenerate-group): do.
+
+       * deuglify.el (gnus-article-outlook-unwrap-lines): do.
+
+       * binhex.el (binhex-decode-region-internal): do.
+
+2004-02-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-fun.el (gnus-face-properties-alist): New user option.
+       (gnus-display-x-face-in-from): Use it.
+
+       * gnus-art.el (article-display-face): Ditto.
+
+       * compface.el (uncompface-use-external): Default to nil.
+
+2004-02-12  Jesper Harder  <harder@ifa.au.dk>
+
+       * nntp.el (nntp-erase-buffer): New function.
+       (nntp-retrieve-data, nntp-send-command)
+       (nntp-send-buffer, nntp-retrieve-groups, nntp-handle-authinfo)
+       (nntp-possibly-change-group): Use it.
+
+       * nnnil.el (nnnil-retrieve-headers, nnnil-request-list):
+       Use with-current-buffer.
+
+2004-02-12  TAKAI Kousuke  <tak@kmc.gr.jp>
+
+       * compface.el: Merge the ELisp-based uncompface program.
+       (compface): New customization group.
+       (uncompface-use-external): New user option.
+       (uncompface): Call uncompface-internal if uncompface-use-external
+       is nil.
+       (uncompface-internal): New function.  Note that there are also
+       some other functions and variables added for this function.
+
+2004-02-10  Jesper Harder  <harder@ifa.au.dk>
+
+       * nnrss.el (nnrss-read-group-data): Initialize nnrss-group-hashtb
+       if necessary.
+
+2004-02-09  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam-report.el (spam-report-unplug-agent)
+       (spam-report-plug-agent, spam-report-deagentize)
+       (spam-report-agentize, spam-report-url-ping-temp-agent-function):
+       Add support for the Agent in spam-report: when unplugged, report to a
+       file; when plugged, submit all the requests.
+
+       * spam.el (spam-register-routine): Fix message about
+       registration.
+
+2004-02-09  Jesper Harder  <harder@ifa.au.dk>
+
+       * rfc2047.el (rfc2047-qp-or-base64): New function to reduce
+       dependencies.
+       (rfc2047-encode): Use it.
+
+       * gnus-art.el (gnus-button-marker-list): Move before first
+       reference.
+
+       * imap.el (imap-parse-flag-list, imap-parse-body-extension)
+       (imap-parse-body): Fix format string mismatch.
+
+       * gnus-score.el (gnus-summary-increase-score): do.
+
+       * nnrss.el (nnrss-close): New function.
+
+2004-02-08  Jesper Harder  <harder@ifa.au.dk>
+
+       * nnrss.el (nnrss-make-filename): New function.
+       (nnrss-request-delete-group, nnrss-read-server-data)
+       (nnrss-save-server-data, nnrss-read-group-data)
+       (nnrss-save-group-data): Use it.
+       (nnrss-save-server-data, nnrss-save-group-data): Use gnus-prin1.
+       (nnrss-read-server-data, nnrss-read-group-data): Use load.
+       (nnrss-group-hashtb): Make it a hash table rather than an obarray.
+
+2004-02-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * mml.el (mml-compute-boundary-1): Don't uncompress files.
+
+2004-02-06  Jesper Harder  <harder@ifa.au.dk>
+
+       * mml.el (mml-mode, mml-x-dnd-attach-file): Attach drop and drag
+       files.
+
+       * message.el (message-generate-headers-first): Don't quote nil
+       and t in docstrings.
+
+       * imap.el (imap-id): do.
+
+       * gnus-agent.el (gnus-agent-consider-all-articles)
+       (gnus-agent-queue-mail): do.
+
+2004-02-05  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * spam-report.el (spam-report-process-queue): New function.
+       Process requests from `spam-report-requests-file'.
+       (spam-report-process-queue): Doc fix.
+
+2004-02-05  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-register-routine)
+       (spam-log-processing-to-registry, spam-log-registered-p)
+       (spam-log-unregistration-needed-p, spam-log-undo-registration):
+       Change "check" to "spam-check" for semi-clarity.
+
+2004-02-05  Jesper Harder  <harder@ifa.au.dk>
+
+       * pop3.el: Require nnheader.
+
+       * mml-smime.el: Require cl.  Autoload message-fetch-field.
+
+       * mml-sec.el (mml-signencrypt-style): Don't depend on Gnus.
+
+       * gnus-picon.el: Require cl.
+
+       * gnus-fun.el: Require gnus-ems and gnus-util.
+
+       * gnus.el (gnus-method-to-server): Move defsubst before first use.
+
+       * gnus-diary.el (gnus-diary-header-schedule): caddr -> car (cddr.
+
+       * gnus-art.el (gnus-article-edit-mode): Define before first
+       reference.
+
+2004-02-04  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-uu.el (gnus-uu-check-correct-stripped-uucode): Simplify.
+       (gnus-uu-post-encoded): Use point-at-bol.
+
+       * gnus-topic.el (gnus-group-active-topic-p): do.
+
+       * gnus-start.el (gnus-newsrc-to-gnus-format): do.
+
+       * gnus-group.el (gnus-group-kill-region): do.
+
+       * gnus-art.el (article-date-ut): do.
+
+       * message.el (message-fetch-field): Remove redundant
+       case-fold-search binding.
+       (message-narrow-to-field): Simplify.
+
+2004-02-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * spam.el (spam-directory): Derive from `gnus-directory'.
+
+       * spam-report.el (spam-report-url-to-file)
+       (spam-report-requests-file): New function and variable for offline
+       reporting.
+       (spam-report-url-ping-function): Add `spam-report-url-to-file'
+       and user defined function.
+       (spam-report-url-ping-mm-url): Remove doubled slash.
+
+2004-02-03  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-list-of-processors): Fix spamassassin variable names.
+
+2004-02-03  Jesper Harder  <harder@ifa.au.dk>
+
+       * spam.el (spam-check-spamoracle, spam-spamoracle-learn):
+       Fix format string mismatch.
+
+       * sieve.el (sieve-deactivate-all): do.
+
+       * nnfolder.el (nnfolder-request-set-mark, nnfolder-save-marks): do.
+
+       * nnlistserv.el (nnlistserv-kk-wash-article): do.
+
+       * nnml.el (nnml-request-set-mark, nnml-save-marks): do.
+
+       * mm-bodies.el (mm-7bit-chars): Don't include \r.
+
+2004-02-02  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-list-of-checks): Add spam-use-BBDB-eclusive to
+       the list of checks.
+
+2004-01-31  Jesper Harder  <harder@ifa.au.dk>
+
+       * rfc2047.el (rfc2047-pad-base64): Deal with more cases of invalid
+       padding.
+
+2004-01-27  Ralf Angeli  <angeli@iwi.uni-sb.de>
+
+       * mm-view.el (mm-fill-flowed): New variable.
+       (mm-inline-text): Use it.
+
+2004-01-27  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-spamassassin-register-ham-routine)
+       (spam-spamassassin-register-spam-routine): Fix function names.
+
+2004-01-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (gnus-tmp-grouplens): Remove.
+       (gnus-summary-line-format): Remove grouplens.
+
+       * gnus-group.el (gnus-group-line-format): Ditto.
+
+       * gnus-spec.el (gnus-format-specs): Ditto.
+       (gnus-update-format-specifications): Flush the group format spec
+       cache if there's the grouplens stuff.
+       (gnus-parse-simple-format): Replace %l with the empty string.
+
+2004-01-27  Jerry James  <james@xemacs.org>  (tiny change)
+
+       * gnus-spec.el (gnus-parse-simple-format): Fix setq value
+       omission.
+
+2004-01-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-summary-resend-message-edit): Call mime-to-mml.
+       Suggested by Hiroshi Fujishima <pooh@nature.tsukuba.ac.jp>.
+
+2004-01-25  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir--num-file, nnmaildir--mkfile)
+       (nnmaildir--emlink-p, nnmaildir--eexist-p, nnmaildir--new-number):
+       New macros and functions.
+       * nnmaildir.el (nnmaildir--group-maxnum, nnmaildir--update-nov):
+       Handle > NLINK_MAX messages.
+       * nnmaildir.el (nnmaildir-request-set-mark):
+       Use nnmaildir--emlink-p and nnmaildir--eexist-p.
+
+2004-01-25  Alex Schroeder  <alex@gnu.org>
+
+       * spam-stat.el (spam-stat-process-directory-age): New option.
+       (spam-stat-process-directory): Use it.
+
+2004-01-24  Hiroshi Fujishima  <pooh@nature.tsukuba.ac.jp>  (tiny change)
+
+       * spam-stat.el (spam-stat-reduce-size): Set spam-stat-dirty.
+       (spam-stat-save): Accept prefix argument.
+
+2004-01-23  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir-request-set-mark): Handle the "too many
+       links" error.
+
+2004-01-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el: Advise byte-optimize-form-code-walker to optimize
+       the rest of the and/or forms.
+
+2004-01-23  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.el (gnus-tmp-grouplens): Define for the sake of backward
+       compatibility with old .newsrc.eld files.
+
+       * gnus-xmas.el (gnus-xmas-grouplens-menu-add): Remove.
+
+       * gnus-sum.el (gnus-summary-line-format-alist): Remove grouplens.
+
+       * gnus-start.el (gnus-1): do.
+
+       * gnus-group.el (gnus-group-line-format-alist): do.
+
+       * gnus.el (gnus-use-grouplens, gnus-visual): do.
+
+       * gnus-gl.el: Remove.
+
+2004-01-23  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-sum.el (gnus-adjust-marks): Now correctly handles a list of
+       marks consisting of a single range {for example, (3 . 5)} rather
+       than a list of a single range { ((3 . 5)) }.
+
+2004-01-23  Jesper Harder  <harder@ifa.au.dk>
+
+       * spam-stat.el (spam-stat-store-gnus-article-buffer):
+       Use with-current-buffer.
+       (spam-stat-store-current-buffer): Use insert-buffer-substring to
+       avoid consing a string.
+
+       * mm-util.el (mm-charset-synonym-alist): Add ks_c_5601-1987.
+       Remove obsolete entries for big5 and gb2312.
+
+2004-01-22  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-sum.el (gnus-adjust-marks): Avoid splicing null INTO the
+       uncompressed list.
+
+2004-01-22  Jesper Harder  <harder@ifa.au.dk>
+
+       * spam-stat.el (spam-stat-strip-xref): New function.
+       (spam-stat-process-directory): Use it.
+
+       * gnus-util.el (gnus-fetch-field): Don't bind case-fold-search
+       here -- it's done in message-fetch-field.
+
+2004-01-21  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-queue-mail)
+       (gnus-agent-prompt-send-queue): New variables.
+       (gnus-agent-send-mail): Use gnus-agent-queue-mail.
+       * gnus-draft.el (gnus-group-send-queue): Pass the group name
+       "nndraft:queue" along to gnus-draft-send.
+       Use gnus-agent-prompt-send-queue.
+       (gnus-draft-send): Rebind gnus-agent-queue-mail to nil when group
+       is "nndraft:queue".  Suggested by Gaute Strokkenes
+       <gs234@srcf.ucam.org>
+
+       * gnus-agent.el (agent-disable-undownloaded-faces): Remove.
+       (agent-enable-undownloaded-faces): Add.
+       (gnus-agent-cat-groups): Use eval-and-compile, not
+       eval-when-compile, to define gnus-agent-set-cat-groups as the setf
+       method of gnus-agent-cat-groups even when the buffer has been
+       evaled.
+       (gnus-agent-save-active, gnus-agent-save-active-1): Merge to
+       delete gnus-agent-save-active-1.
+       (gnus-agent-save-groups): Delete.  Identical to
+       gnus-agent-save-active.
+       (gnus-agent-write-active): No longer adjust agent's copy of active
+       file as agent's adjustments are now stored in their own
+       file.  Remove optional parameter.
+       (gnus-agent-possibly-alter-active): Ignore groups of unagentized
+       servers.  Add use of min/max range limits from server's local
+       file.
+       (gnus-agent-save-alist): Remove unused optional argument.
+       (gnus-agent-load-local, gnus-agent-read-and-cache-local)
+       (gnus-agent-read-local, gnus-agent-save-local, gnus-agent-get-local)
+       (gnus-agent-set-local): A per-server file that keeps min/max range
+       limits for articles known to the agent.  Provides a fast mechanism
+       for altering many active ranges.
+       (gnus-agent-expire-group, gnus-agent-expire): No longer save the
+       active file (local makes it unnecessary).
+       (gnus-agent-regenerate-group): Fix XEmacs compatibility.
+
+       * gnus-cus.el (agent-disable-undownloaded-faces): Remove.
+       (agent-enable-undownloaded-faces): Add.
+
+       * gnus-draft.el (gnus-draft-send): Bind gnus-agent-queue-mail to
+       disable it when sending to "nndraft:queue".
+       (gnus-group-send-queue): Add safety check to avoid sending queue
+       when unplugged.
+
+       * gnus-group.el (gnus-group-catchup): Use new
+       gnus-sequence-of-unread-articles, not
+       gnus-list-of-unread-articles, to avoid exhausting memory with huge
+       numbers of articles.  Use gnus-range-map to avoid having to
+       uncompress the unread list.
+       (gnus-group-archive-directory, gnus-group-recent-archive-directory):
+       Fix invalid ange-ftp reference.
+
+       * gnus-range.el (gnus-range-map): Iterate over list or sequence.
+       (gnus-sorted-range-intersection): Intersection of two ranges
+       without requiring that they first be uncompressed.
+
+       * gnus-start.el (gnus-activate-group): Unless blocked by the
+       caller, possibly expand the active range to include both cached
+       and agentized articles.
+       (gnus-convert-old-newsrc): Rewrote in anticipation of having
+       multiple version-dependent converters.
+       (gnus-groups-to-gnus-format): Replace gnus-agent-save-groups with
+       gnus-agent-save-active.
+       (gnus-save-newsrc-file): Save dirty agent range limits.
+
+       * gnus-sum.el (gnus-select-newgroup): Replace inline code with
+       gnus-agent-possibly-alter-active.
+       (gnus-adjust-marked-articles): Faster handling of simple lists.
+
+2004-01-21  Jesper Harder  <harder@ifa.au.dk>
+
+       * spam-stat.el (spam-stat-test-directory): New optional argument
+       displays a list of files detected.  Suggested by Andrew Cohen
+       <cohen@andy.bu.edu>.
+       (spam-stat-buffer-words-with-scores): Don't narrow and change
+       syntax table here.  Reported by Andrew Cohen <cohen@andy.bu.edu>.
+
+2004-01-20  Hubert Chan  <hubert@uhoreg.ca>
+
+       * spam.el (spam-use-spamassassin, spam-use-spamassassin-headers)
+       (spam-install-hooks, spam-spamassassin, spam-spamassassin-path)
+       (spam-spamassassin-arguments)
+       (spam-spamassassin-spam-flag-header)
+       (spam-spamassassin-positive-spam-flag-header)
+       (spam-spamassassin-spam-status-header, spam-sa-learn-path)
+       (spam-sa-learn-rebuild, spam-sa-learn-spam-switch)
+       (spam-sa-learn-ham-switch, spam-sa-learn-unregister-switch)
+       (spam-list-of-processors, spam-list-of-checks)
+       (spam-list-of-statistical-checks, spam-registration-functions)
+       (spam-check-spamassassin-headers, spam-check-spamassassin)
+       (spam-spamassassin-score)
+       (spam-spamassassin-register-with-sa-learn)
+       (spam-spamassassin-register-spam-routine)
+       (spam-spamassassin-register-ham-routine)
+       (spam-assassin-register-spam-routine)
+       (spam-assassin-register-ham-routine): Add SpamAssassin support.
+       (spam-bogofilter-score): Fix to show article before scoring.
+
+2004-01-20  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (gnus-summary-mode-map): Make spam-generic-score the
+       default scoring function.
+       (spam-generic-score): Call spam-spamassassin-score if
+       spam-use-spamassassin or spam-use-spamassassin-headers is on;
+       spam-bogofilter-score otherwise.
+
+       * gnus.el (spam-process, spam-autodetect-methods):
+       Add spamassassin and spamassassin-headers.
+
+2004-01-20  Nevin Kapur  <nkapur@cs.caltech.edu>
+
+       * gnus-registry.el (gnus-registry-split-fancy-with-parent):
+       Suppress unnecessary messages.
+
+2004-01-20  Jesper Harder  <harder@ifa.au.dk>
+
+       * spam-stat.el (spam-stat-to-hash-table): Use :size keyword in
+       make-hash-table.
+
+2004-01-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * canlock.el (base64-encode-string): Don't autoload it.
+
+2004-01-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * run-at-time.el: Remove useless (require 'itimer),
+       eval-and-compile and (featurep 'xemacs).
+
+2004-01-16  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-msg.el (gnus-post-news): Use blank Newsgroups line if
+       GROUP is a virtual group.
+
+2004-01-16  Steve Youngs  <sryoungs@bigpond.net.au>
+
+       * gnus.el: Autoload `message-y-or-n-p'.
+
+2004-01-15  Jesper Harder  <harder@ifa.au.dk>
+
+       * pgg-parse.el: Remove unnecessary (require 'custom).
+
+       * pgg-def.el: do.
+
+       * nnmail.el: do.
+
+       * gnus-undo.el: do.
+
+       * gnus-picon.el: do.
+
+       * gnus-util.el: do.
+
+2004-01-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-pick-line-number): Add autoload.
+
+2004-01-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-multiple-handles): Recognize a string as a mime
+       handle, as well as a list.
+
+       * mm-view.el (mm-w3m-cid-retrieve-1): Call itself recursively.
+       Suggested by ARISAWA Akihiro <ari@mbf.sphere.ne.jp>.
+       (mm-w3m-cid-retrieve): Simplify.
+
+2004-01-14  Vasily Korytov  <deskpot@myrealbox.com>
+
+       * message.el (message-kill-to-signature): Allow prefix arg to
+       specify number of lines to keep before signature.
+
+2004-01-14  Kai Grossjohann  <kai@emptydomain.de>
+
+       * message.el (message-kill-to-signature): Change docstring.
+
+2004-01-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * canlock.el: Always require sha1-el.
+       (canlock-sha1): Bind sha1-maximum-internal-length to nil.
+
+       * message.el: Autoload sha1 only when compiling.
+
+       * lpath.el: Bind eudc-protocol for both Emacs and XEmacs; fbind
+       eudc-expand-inline for XEmacs.
+
+2004-01-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-canlock-generate): Require sha1-el.
+
+2004-01-13  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-expand-name): Silence the byte compiler.
+
+       * lpath.el: Add detect-coding-system.
+
+       * dgnushack.el (dgnushack-compile): Remove obsolete check for
+       cus-edit.
+
+2004-01-13  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-score.el (gnus-score-edit-all-score): Fix prototype.
+       Invoke gnus-score-mode.
+       Reported by bojohan+news@dd.chalmers.se (Johan Bockgård).
+
+       * gnus-range.el (gnus-compress-sequence): Doc fix.
+       Suggested by Jim Blandy <jimb@redhat.com> (tiny change).
+
+2004-01-12  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-srvr.el (gnus-browse-foreign-server): Reduce consing.
+
+2004-01-12  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-get-article-as-string): Update to use
+       gnus-request-article-this-buffer, much simpler.
+       (spam-get-article-as-buffer): Remove.
+
+2004-01-12  Kai Grossjohann  <kai.grossjohann@mci.com>
+
+       * message.el (message-expand-name): Use EUDC if the user uses that.
+
+2004-01-12  Jesper Harder  <harder@ifa.au.dk>
+
+       * rfc2047.el (rfc2047-parse-and-decode, rfc2047-decode): Use a
+       character for the encoding to avoid consing a string.
+
+       * rfc2047.el (rfc2047-decode-string): Don't cons a string
+       unnecessarily.
+
+       * mm-util.el (mm-replace-chars-in-string): Remove.
+
+       * rfc2047.el (rfc2047-decode): Use mm-subst-char-in-string instead
+       of mm-replace-chars-in-string.
+
+2004-01-11  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.sum.el (gnus-remove-odd-characters): Don't cons two new strings.
+
+       * mm-util.el (mm-subst-char-in-string): Support inplace.
+
+       * gnus-sum.el (gnus-summary-remove-list-identifiers): Don't cons
+       a new string in every iteration.  Use shy groups.
+
+2004-01-10  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-srvr.el (gnus-browse-unsubscribe-group):
+       * gnus-soup.el (gnus-soup-group-brew):
+       * gnus-msg.el (gnus-put-message):
+       * gnus-move.el (gnus-group-move-group-to-server):
+       * gnus-kill.el (gnus-batch-score):
+       * gnus-group.el (gnus-group-prepare-flat, gnus-group-delete-group)
+       (gnus-group-update-group-line, gnus-group-insert-group-line-info)
+       (gnus-group-update-group, gnus-group-read-group)
+       (gnus-group-make-group, gnus-group-make-help-group)
+       (gnus-group-make-archive-group, gnus-group-make-directory-group)
+       (gnus-group-make-empty-virtual, gnus-group-sort-selected-flat)
+       (gnus-group-sort-by-unread, gnus-group-catchup)
+       (gnus-group-unsubscribe-group, gnus-group-kill-group)
+       (gnus-group-yank-group, gnus-group-set-info)
+       (gnus-group-list-groups):
+       * gnus.el (gnus-generate-new-group-name):
+       * gnus-delay.el (gnus-delay-send-queue):
+       * nnvirtual.el (nnvirtual-catchup-group):
+       * nnkiboze.el (nnkiboze-generate-group, nnkiboze-generate-group):
+       * gnus-topic.el (gnus-topic-find-groups, gnus-topic-clean-alist)
+       (gnus-group-prepare-topics, gnus-topic-check-topology):
+       * gnus-sum.el (gnus-update-read-articles, gnus-select-newsgroup)
+       (gnus-mark-xrefs-as-read, gnus-compute-read-articles)
+       (gnus-summary-walk-group-buffer, gnus-summary-move-article)
+       (gnus-group-make-articles-read):
+       * gnus-start.el (gnus-subscribe-newsgroup, gnus-start-draft-setup)
+       (gnus-group-change-level, gnus-kill-newsgroup)
+       (gnus-check-bogus-newsgroups, gnus-get-unread-articles-in-group)
+       (gnus-get-unread-articles, gnus-make-articles-unread)
+       (gnus-make-ascending-articles-unread): Use accessor
+       macros (gnus-group-entry, gnus-group-unread, gnus-info-marks etc.)
+       to get group information for improved readability.
+
+
+2004-01-09  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (article-decode-mime-words, article-babel)
+       (gnus-article-highlight-signature, gnus-article-add-buttons)
+       (gnus-signature-toggle): Use gnus-with-article-buffer.
+
+       * gnus-art.el (gnus-article-highlight-headers)
+       (gnus-article-add-buttons-to-head): Use gnus-with-article-headers.
+
+       * gnus-art.el (gnus-mm-display-part, gnus-article-wash-status)
+       (gnus-article-set-globals, gnus-request-article-this-buffer)
+       (gnus-button-message-id, gnus-article-maybe-hide-headers)
+       (gnus-mime-view-part-externally, gnus-mime-view-part-internally)
+       (gnus-mime-display-alternative): Use with-current-buffer.
+
+2004-01-09  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-generate-fake-headers): Rewrite to be simpler,
+       also under 80 char limit, and call gnus-error if needed.
+       (spam-fetch-article-header): Fix - it was a
+       buffer-local variable (gnus-newsgroup-data).
+       (spam-find-spam): Use spam-generate-fake-headers, forget about
+       spam-insert-fake-headers.
+       (spam-insert-fake-headers): Remove.
+
+2004-01-09  Jesper Harder  <harder@ifa.au.dk>
+
+       * deuglify.el (gnus-article-outlook-unwrap-lines)
+       (gnus-outlook-rearrange-article)
+       (gnus-outlook-repair-attribution-outlook)
+       (gnus-outlook-repair-attribution-block)
+       (gnus-outlook-repair-attribution-other): Remove redundant
+       save-excursion.
+
+2004-01-09  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-fetch-field-fast, spam-fetch-field-from-fast)
+       (spam-fetch-field-subject-fast)
+       (spam-fetch-field-message-id-fast, spam-generate-fake-headers)
+       (spam-fetch-article-header): Add functions to deal with Gnus
+       internals for fast retrieval of article header data.
+       (spam-initialize): Put spam-find-spam in the gnus-summary-prepared-hook.
+
+2004-01-09  Jesper Harder  <harder@ifa.au.dk>
+
+       * pop3.el (pop3-md5): Remove.
+       (pop3-apop): Replace pop3-md5 with md5.
+
+       * mm-bodies.el: base64 is always built-in.
+
+       * gnus-sum.el (gnus-summary-from-or-to-or-newsgroups):
+       Use with-current-buffer.
+
+2004-01-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * canlock.el (canlock-insert-header): Remove excessive grouping in
+       regexp.
+
+       * gnus-sum.el (gnus-summary-read-document): Ditto.
+
+       * gnus-uu.el (gnus-uu-part-number): Ditto.
+
+       * html2text.el (html2text-remove-tags): Ditto.
+       (html2text-format-tags): Ditto.
+       (html2text-format-single-elements): Ditto.
+
+       * mml.el (mml-parse-1): Ditto.
+
+2004-01-08  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-summary-update-mark): Revert previous change.
+
+       * gnus-group.el (gnus-group-mark-group): Fix for multibyte marks.
+
+       * gnus-sum.el (gnus-summary-update-mark): Fix for multibyte marks.
+
+       * gnus-util.el (gnus-replace-in-string): Remove Emacs 20 code.
+
+2003-11-15  Simon Josefsson  <jas@extundo.com>
+
+       * pgg-gpg.el (pgg-gpg-lookup-all-secret-keys)
+       (pgg-gpg-lookup-key): Use regexp match instead of
+       split-string (split-string is different between emacs 21.2 and
+       22.1).  Reported by ultrasoul@ultrasoul.com (David D. Smith).
+
+2004-01-08  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-mime-view-all-parts)
+       (gnus-article-part-wrapper, gnus-article-view-part):
+       Use with-current-buffer.
+
+2004-01-07  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-disable-spam-split-during-ham-respool)
+       (spam-spamoracle-database, spam-cache-lookups)
+       (spam-split-last-successful-check, spam-clear-cache, spam-xor)
+       (spam-group-ham-mark-p, spam-group-spam-mark-p)
+       (spam-group-ham-marks, spam-group-spam-marks)
+       (spam-group-spam-contents-p, spam-group-ham-contents-p)
+       (spam-list-of-processors, spam-list-of-statistical-checks): Fix doc,
+       also add spam-use-blackholes to the statistical checks.
+       (spam-fetch-field-fast): Add interface to fetching fields, may
+       become a macro.
+       (spam-fetch-field-from-fast, spam-fetch-field-subject-fast)
+       (spam-fetch-field-message-id-fast): Use spam-fetch-field-fast.
+       (spam-insert-fake-headers): Fake an article when needed.
+       (spam-find-spam): Fake article when possible.
+       (spam-check-blackholes, spam-check-BBDB, spam-from-listed-p)
+       (spam-check-bogofilter-headers): Use message-fetch-field instead
+       of nnmail-fetch-field.
+
+2004-01-07  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-score.el (gnus-score-find-trace): Add `k' (kill-buffer).
+
+2004-01-07  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-split): Do not require spam-use-CHECK to be
+       enabled if that check is passed to spam-split explicitly; also
+       fix so 'spam doesn't get converted to spam-split-group when
+       spam-split-symbolic-return is t.
+       (spam-find-spam): Find registrations of the article and use those
+       instead of re-running spam-split to find the spam/ham
+       classification of the article.
+       (spam-log-processing-to-registry, spam-log-registered-p)
+       (spam-log-unregistration-needed-p, spam-log-undo-registration):
+       Use gnus-error instead of gnus-message.
+       (spam-log-registration-type): Add function to determine the
+       classification of a message based on registry entries; will
+       return nil if both 'spam and 'ham are found.
+       (spam-check-BBDB): Expand all the BBDB macros here so we can have
+       a reasonably fast local cache without the loading errors.
+       (spam-cache-lookups): Set to t by default.
+       (spam-find-spam): Don't try to guess spam-cache-lookups.
+       (spam-enter-whitelist, spam-enter-blacklist): Clear the
+       spam-caches entry.
+       (spam-filelist-build-cache, spam-filelist-check-cache):
+       Fix caching of whitelist/blacklist entries.
+       (spam-check-whitelist, spam-check-blacklist):
+       Invoke spam-from-listed-p with a type, not a cache variable.
+       (spam-from-listed-p): Wrap around spam-filelist-check-cache.
+
+2004-01-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-cite-prefix-regexp): Use with-syntax-table.
+
+       * nnmail.el (nnmail-split-fancy): do.
+
+       * mml.el (mml-parse): do.
+
+       * gnus-score.el (gnus-enter-score-words-into-hashtb)
+       (gnus-score-adaptive): do.
+
+2004-01-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-treat-emphasize): Ignore Emacs version number.
+       (gnus-mime-button-map): Don't set keymap parent.
+       (gnus-button-ctan-directory-regexp): Use shy grouping.
+       (gnus-prev-page-map): Don't set keymap parent.
+       (gnus-prev-page-map): Remove duplicated one.
+       (gnus-next-page-map): Don't set keymap parent.
+       (gnus-mime-security-button-map): Ditto.
+
+       * nnheader.el (nnheader-directory-files-is-safe): Ignore Emacs
+       version number.
+
+       * sha1-el.el (sha1-string-external): Use with-temp-buffer.
+
+2004-01-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * canlock.el (canlock-sha1-function): Remove.
+       (canlock-sha1-function-for-verify): Remove.
+       (canlock-openssl-program): Remove.
+       (canlock-openssl-args): Remove.
+       (canlock-ignore-errors): Remove.
+       (canlock-sha1-with-openssl): Remove.
+       (canlock-sha1): Use sha1 instead of to call canlock-sha1-function.
+       (canlock-verify): Don't use canlock-ignore-errors.
+
+       * sha1-el.el (sha1-string-external): Make it can return a string
+       in binary form.
+       (sha1-region-external): Ditto.
+       (sha1-string-internal): Ditto.
+       (sha1-region-internal): Ditto.
+       (sha1-region): Ditto.
+       (sha1-string): Ditto.
+       (sha1): Ditto.
+
+2004-01-07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * spam.el (spam-report-articles-gmane): New command.
+
+2004-01-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el: Don't make unnecessary *Group* buffer when loading.
+
+       * run-at-time.el (run-at-time-saved): Remove.
+       (run-at-time): Doc fix.
+
+2004-01-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-summary-limit-to-replied): New command.
+       (gnus-summary-limit-map): Add it.
+       (gnus-summary-make-menu-bar): do.
+
+2004-01-06  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-cache-lookups, spam-caches, spam-clear-cache):
+       Make attempt at some caching support (done for BBDB only now).
+       (spam-find-spam): Set spam-cache-lookups if there are more than 2
+       addresses to be checked.
+       (spam-clear-cache-BBDB): Add function, to be invoked by
+       bbdb-change-hook, and triggering spam-clear-cache of 'spam-use-BBDB.
+       (spam-check-BBDB): Check and use the caches, if
+       spam-cache-lookups is on, remove superfluous (provide).
+
+2004-01-06  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-treat-ansi-sequences): Change default.
+
+2004-01-07  Steve Youngs  <sryoungs@bigpond.net.au>
+
+       * run-at-time.el (run-at-time-saved): Move to after the definition
+       of `run-at-time'.
+
+       * dgnushack.el: Autoload `font-lock-fontify-buffer' in XEmacs.
+
+2004-01-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-wash-html-with-w3m): Don't use
+       mm-w3m-local-map-property.
+
+       * mm-view.el (mm-w3m-mode-map): Remove.
+       (mm-w3m-local-map-property): Remove.
+       (mm-inline-text-html-render-with-w3m): Don't use
+       mm-w3m-local-map-property.
+
+2004-01-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * run-at-time.el: New file.
+
+       * dgnushack.el (dgnushack-compile): Don't compile run-at-time
+       under Emacs.
+
+       * gnus.el ((fboundp 'gnus-set-text-properties)): Remove definition
+       of gnus-set-text-properties.
+
+       * gnus-uu.el (gnus-uu-save-article): Ditto.
+
+       * gnus-salt.el (gnus-carpal-setup-buffer): Ditto.
+
+       * gnus-cite.el (gnus-cite-parse): Ditto.
+
+       * gnus-art.el (gnus-button-push): Use set-text-properties instead
+       of gnus-.
+
+       * gnus-xmas.el (run-at-time): Require run-at-time.
+
+       * gnus.el: Change calls to nnheader-run-at-time and
+       password-run-at-time throughout to use run-at-time directly.
+
+       * password.el: Remove definition of run-at-time.
+
+       * nnheaderxm.el: Remove definition of run-at-time.
+
+2004-01-05  Karl Pflästerer  <sigurd@12move.de>  (tiny change)
+
+       * mml.el (mml-minibuffer-read-disposition): Show attachment type
+       in prompt.
+
+2004-01-06  Steve Youngs  <sryoungs@bigpond.net.au>
+
+       * messagexmas.el (message-xmas-redefine): Alias
+       `message-make-caesar-translation-table' to
+       ``message-xmas-make-caesar-translation-table' regardless of XEmacs
+       version.
+
+       * gnus-xmas.el (gnus-xmas-set-text-properties): Removed.
+       (gnus-xmas-define): Don't alias `gnus-set-text-properties' to
+       `gnus-xmas-set-text-properties'.
+       (gnus-xmas-redefine): Don't alias `gnus-completing-read' to
+       `gnus-xmas-completing-read'.
+       (gnus-xmas-completing-read): Removed.
+       (gnus-xmas-open-network-stream): Removed.
+
+       * gnus-ems.el (gnus-mode-line-modified): Don't conditionalize on
+       XEmacs version.
+
+       * dns.el (dns-make-network-process): Use `open-network-stream'
+       instead of `gnus-xmas-open-network-stream'.
+
+       * dgnushack.el: Remove some XEmacs 21.1 specific stuff.
+
+       * .cvsignore: Add auto-autoloads.el, custom-load.el.
+
+2004-01-06  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-mime-display-alternative)
+       (gnus-insert-mime-button, gnus-insert-mime-security-button)
+       (gnus-insert-prev-page-button, gnus-insert-next-page-button):
+       Don't use gnus-local-map-property.
+
+       * gnus-util.el (gnus-local-map-property): Remove.
+
+       * mm-view.el (mm-view-pkcs7-decrypt):
+       Replace gnus-completing-read-maybe-default with completing-read.
+
+       * gnus-util.el (gnus-completing-read): do.
+       (gnus-completing-read-maybe-default): Remove.
+
+2004-01-06  Steve Youngs  <sryoungs@bigpond.net.au>
+
+       * password.el: Only autoload `run-at-time' if not XEmacs.
+       Only autoload the itimer functions if XEmacs.
+
+2004-01-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-xmas.el (gnus-xmas-define): Defun char-width for non-MULE
+       XEmacsen.
+
+       * dgnushack.el: Autoload executable-find for XEmacs.
+
+2004-01-06  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-read-string): Remove.
+       (gnus-summary-pipe-to-muttprint): Replace gnus-read-string with
+       read-string.
+
+2004-01-05  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * netrc.el: Autoload password-read.
+       (netrc): Add configuration group.
+       (netrc-encoding-method, netrc-openssl-path):
+       Add variables for encoding and decoding of files with symmetric
+       ciphers.
+       (netrc-encode): Add assistant function to encode a file with
+       netrc-encoding-method.
+       (netrc-parse): Add interactive parameter, added optional
+       decoding if netrc-encoding-method is non-nil but otherwise
+       behavior is standard.
+       (netrc-encrypting-method, netrc-encrypt, netrc-parse):
+       Do s/encode/encrypt/ everywhere.
+
+       * spam.el: Remove executable-find autoload.
+
+2004-01-05  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-registry.el: Remove Emacs 20 hash table compatibility code.
+
+       * gnus-uu.el (gnus-uu-post-encoded): bury-buffer is always fbound.
+
+2004-01-05  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-treat-ansi-sequences)
+       (article-treat-ansi-sequences): New variable and function.
+       Suggested by Dan Jacobson <jidanni@jidanni.org>.
+
+       * gnus-sum.el (gnus-summary-wash-map, gnus-summary-make-menu-bar):
+       Use it.
+
+2004-01-05  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-util.el (mm-quote-arg): Remove.
+
+       * mm-decode.el (mm-mailcap-command): Replace mm-quote-arg with
+       shell-quote-argument.
+
+       * gnus-uu.el (gnus-uu-command): do.
+
+       * gnus-sum.el (gnus-summary-insert-pseudos): do.
+
+       * ietf-drums.el (ietf-drums-token-to-list): Replace mm-make-char
+       with make-char.
+
+       * mm-util.el (mm-make-char): Remove.
+
+       * mml.el (mml-mode): Replace gnus-add-minor-mode with
+       add-minor-mode.
+
+       * gnus-undo.el (gnus-undo-mode): do.
+
+       * gnus-topic.el (gnus-topic-mode): do.
+
+       * gnus-sum.el (gnus-dead-summary-mode): do.
+
+       * gnus-start.el (gnus-slave-mode): do.
+
+       * gnus-salt.el (gnus-binary-mode, gnus-pick-mode): do.
+
+       * gnus-ml.el (gnus-mailing-list-mode): do.
+
+       * gnus-gl.el (gnus-grouplens-mode): do.
+
+       * gnus-draft.el (gnus-draft-mode): do.
+
+       * gnus-dired.el (gnus-dired-mode): do.
+
+       * gnus-ems.el (gnus-add-minor-mode): Remove.
+
+       * gnus-spec.el (gnus-correct-length, gnus-correct-substring):
+       Replace gnus-char-width with char-width.
+
+       * gnus-ems.el (gnus-char-width): Remove.
+
+       * gnus-spec.el (gnus-correct-length, gnus-correct-substring):
+       Replace gnus-char-width with char-width.
+
+       * gnus-ems.el (gnus-char-width): Remove.
+
+       * spam-stat.el (with-syntax-table): Remove with-syntax-table
+       definition.
+       Remove Emacs 20 hash table compatibility code.
+
+       * rfc2047.el (with-syntax-table): Remove with-syntax-table Emacs
+       20 compatibility code.
+
+       * spam.el (spam-point-at-eol): Replace with point-at-eol.
+
+       * smime.el (smime-point-at-eol): Replace with point-at-eol.
+
+       * rfc2047.el (rfc2047-point-at-bol, rfc2047-point-at-eol):
+       Replace with point-at-{eol,bol}.
+
+       * netrc.el (netrc-point-at-eol): Replace with point-at-eol.
+
+       * imap.el (imap-point-at-eol): Replace with point-at-eol.
+
+       * flow-fill.el (fill-flowed-point-at-bol)
+       (fill-flowed-point-at-eol): Replace with point-at-{eol,bol}.
+
+       * gnus-util.el (gnus-point-at-bol, gnus-point-at-eol): Remove.
+       Replace with point-at-{eol,bol} throughout all files.
+
+2004-01-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * ntlm.el (ntlm-string-as-unibyte): New macro.
+       (ntlm-build-auth-response): Use it.
+
+       Remove Emacs 20 stuff:
+       * dgnushack.el (dgnushack-compile): Don't modify max-specpdl-size.
+       (butlast, mapc, remove): Remove the compiler macros.
+       * gnus-msg.el (gnus-summary-news-other-window): Use remove instead
+       of delq and copy-sequence.
+       * gnus-art.el (popup-menu): Remove the compiler macro.
+       * nnmail.el (nnmail-split-fancy): Don't support customizing with
+       Emacs 20.
+
+2004-01-05  Simon Josefsson  <jas@extundo.com>
+
+       * ntlm.el: Fix namespace.  Change smb-passwd-hash into
+       ntlm-smb-passwd-hash, smb-owf-encrypt into ntlm-smb-owf-encrypt,
+       smb-passwd-hash into ntlm-smb-passwd-hash, smbdes-e-p16 into
+       ntlm-smb-des-e-p16, smbdes-e-p24 into ntlm-smb-des-e-p24, smbhash
+       into ntlm-smb-hash, smb-sp8 into ntlm-smb-sp8, smb-str-to-key into
+       ntlm-smb-str-to-key, smb-dohash into ntlm-smb-dohash, smb-perm1
+       into ntlm-smb-perm1, smb-perm2 into ntlm-smb-perm2, smb-perm3 into
+       ntlm-smb-perm3, smb-perm4 into ntlm-smb-perm4, smb-perm5 into
+       ntlm-smb-perm5, smb-perm6 into ntlm-smb-perm6, smb-sc into
+       ntlm-smb-sc, smb-sbox into ntlm-smb-sbox, string-permute into
+       ntlm-string-permute, string-lshift into ntlm-string-lshift,
+       string-xor into ntlm-string-xor.
+       Suggested by Jesper Harder <harder@myrealbox.com>.
+
+       * ntlm.el: Don't include poem.
+
+       * md4.el (print-int32, print-string-hexa): Remove.
+       Suggested by Jesper Harder <harder@myrealbox.com>.
+
+       * sasl-ntlm.el, ntlm.el, md4.el: New files.
+
+       * hmac-md5.el (md5-binary): Fix byte compile warning.  (This
+       probably breaks emacs with DL patch, but do we care? Is anyone
+       still using the DL stuff?)
+
+       * sieve-manage.el: Use the password package.
+       (sieve-manage-read-passwd): Remove.
+       (sieve-manage-interactive-login): Use password.  Re-add
+       condition-case around loop.
+
+       * pgg.el (pgg-passphrase-cache, pgg-run-at-time): Remove.
+       (pgg-add-passphrase-cache, pgg-remove-passphrase-cache):
+       Use the password package.
+
+2003-02-19  Simon Josefsson  <jas@extundo.com>
+
+       * sieve-manage.el (sieve-sasl-auth): Quote optional initial SASL
+       token.
+
+2002-08-07  Simon Josefsson  <jas@extundo.com>
+
+       * sieve-manage.el (require): Use SASL, not RFC2104/MD5.
+       (sieve-manage-authenticators)
+       (sieve-manage-authenticator-alist): Add some SASL mechs.
+       (sieve-sasl-auth): New function.
+       (sieve-manage-cram-md5-auth)
+       (sieve-manage-plain-auth): Rewrite using SASL library.
+       (sieve-manage-digest-md5-p, sieve-manage-digest-md5-auth)
+       (sieve-manage-scram-md5-p, sieve-manage-scram-md5-auth)
+       (sieve-manage-ntlm-p, sieve-manage-ntlm-auth)
+       (sieve-manage-login-p, sieve-manage-login-auth): Add wrappers.
+
+2004-01-05  Simon Josefsson  <jas@extundo.com>
+
+       * sasl.el, sasl-cram.el, sasl-digest.el, hmac-md5.el, hmac-def.el:
+       New files.
+
+2004-01-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-no-groups-message): Update.
+
+       * gnus-sum.el (gnus-summary-insert-new-articles): Remove .
+
+2003-11-09  Simon Josefsson  <jas@extundo.com>
+
+       * imap.el: Support for ID IMAP extension (RFC 2971).
+       (imap-local-variables): Add imap-id.
+       (imap-id): New variable.
+       (imap-id): New function.
+       (imap-parse-response): Parse untagged ID response.
+       * nnimap.el (nnimap-id): New variable.
+       (nnimap-open-connection): Use it.
+
+2003-12-28  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-score.el (gnus-score-edit-all-score): New.
+       * gnus-group.el (gnus-group-score-map): Bind it to W e.
+
+2004-01-04  Simon Josefsson  <jas@extundo.com>
+
+       * password.el: Add.
+
+2004-01-04  Mario Lang  <lang@zid.tugraz.at>
+
+       * dns.el (dns-query-types): Fix typo.
+       (dns-query-types): New function.
+       (dns-read-type): Add support for AAAA records, see RFC 3596.  Parse MX,
+       PTR and SOA replies, see RFC 1035.
+
+2004-01-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-logo-color-style): Change colors to `no'.
+
+       * Move to Changelog.2.
+
+2004-01-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Bump version.
+
+2004-01-04  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: No Gnus v0.1 is released.
+
+2004-01-04  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: No Gnus v0.0 is released.
+
+2004-01-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Bump.
+       (gnus-version): No.
+
+See ChangeLog.2 for earlier changes.
+
+  Copyright (C) 2004-2016 Free Software Foundation, Inc.
+
+  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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;; Local Variables:
+;; coding: utf-8
+;; fill-column: 79
+;; add-log-time-zone-rule: t
+;; End:
diff --git a/xemacs-packages/gnus/lisp/ChangeLog.1 b/xemacs-packages/gnus/lisp/ChangeLog.1
new file mode 100644 (file)
index 0000000..62c73b8
--- /dev/null
@@ -0,0 +1,10073 @@
+2000-10-27  Jason Rumney  <jasonr@gnu.org>
+
+       * gnus-art.el (gnus-signature-face): Use italic on any frame that
+       supports it.
+
+2000-10-27 14:19:53  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-mlspl.el: Require cl when compiling.
+       * messagexmas.el: Ditto.
+       * mm-util.el: Ditto.
+       * rfc2047.el: Ditto.
+       * rfc2231.el: Ditto.
+       * smiley-ems.el: Ditto.
+       * uudecode.el: Ditto.
+
+       * smiley-ems.el (smiley-region): Use mapcar.
+
+2000-10-27  Stefan Monnier  <monnier@cs.yale.edu>
+
+       * ietf-drums.el: Require cl when compiling.
+
+2000-10-27  Dave Love  <fx@gnu.org>
+
+       * mm-decode.el (mm-valid-and-fit-image-p): Don't test
+       window-system here.
+
+       * gnus-art.el (gnus-article-x-face-command): Check
+       gnus-article-compface-xbm.
+       (gnus-treat-display-xface): Check for uncompface.
+
+       * nnheader.el (nnheader-translate-file-chars): Only kludge things
+       under Doze with XEmacs.
+
+2000-10-26  Simon Josefsson  <sj@extundo.com>
+
+       * mail-source.el (mail-sources): IMAP predicate is a string.
+       (mail-sources): Add default values for IMAP mailbox, predicate and
+       fetchflag.
+
+2000-10-26  Dave Love  <fx@gnu.org>
+
+       * flow-fill.el: Require cl when compiling.
+
+       * mail-source.el: Require imap when compiling and defvar
+       display-time-mail-function.  Require mm-util.
+       (nnheader-cancel-timer): Autoload.
+       (mail-source-imap-authenticators, mail-source-imap-streams): New
+       variables.
+       (mail-sources): Use them.
+
+2000-10-25 20:13:02  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-viewer-completion-map): New.
+       (mm-interactively-view-part): Use it.
+
+2000-10-25 18:51:12  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-q-encode-region): Don't break if a QP-word
+       could be fitted in one line.
+
+2000-10-25  Dirk Meyer  <dischi@tzi.de>
+
+       * gnus-demon.el (gnus-demon-time-to-step): theHour was set to
+       seconds instead of hour.
+
+2000-10-25  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * mail-source.el (mail-sources): Better `:type'.
+
+2000-10-24 18:31:29  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-request-article-this-buffer):
+       gnus-refer-article-method might be a single method.
+       * gnus-sum.el (gnus-refer-article-methods): The second could be
+       a named method.
+
+2000-10-23  Simon Josefsson  <simon@josefsson.org>
+
+       * flow-fill.el (fill-flowed): Don't flow "-- " lines.
+       (fill-flowed): Make "quote-depth wins" rule work when first line
+       is at level 0.
+
+2000-10-21 11:23:21  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-multibyte-p): Test (featurep 'xemacs).
+
+2000-10-21 10:54:57  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-mime-total-parts): New function.
+       (gnus-mm-display-part): Use it.
+       (gnus-mime-display-single): Ditto.
+       (gnus-mime-display-alternative): Ditto.
+
+2000-10-21 09:38:27  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mailcap.el (mailcap-parse-mailcaps): Don't use parse-colon-path,
+       because they are files, not directories.
+       (mailcap-parse-mimetypes): Ditto.
+
+2000-10-20 19:55:59  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-inline-part): Check validity of charset.
+
+2000-10-18  Dave Love  <fx@gnu.org>
+
+       * mail-source.el (mm-util): Require.
+       (defvar): Use rmail-spool-directory unconditionally.
+
+       * gnus-nocem.el (gnus-nocem-issuers): Update.
+       (gnus-nocem-check-from): New option.
+       (gnus-nocem-scan-groups): Use it.
+       (gnus-nocem-check-article): Bind gnus-newsgroup-name.
+
+2000-10-18  Miles Bader  <miles@lsi.nec.co.jp>
+
+       * gnus-nocem.el (gnus-nocem-check-article-limit): New variable.
+       (gnus-nocem-scan-groups): Obey `gnus-nocem-check-article-limit'.
+
+2000-10-18  Simon Josefsson  <simon@josefsson.org>
+
+       * nnheader.el (nnheader-parse-head): Try both "from:" and "from: ".
+
+       * gnus-sum.el (gnus-get-newsgroup-headers): Ditto.
+
+2000-10-17  Simon Josefsson  <simon@josefsson.org>
+
+       * gnus-sum.el (gnus-get-newsgroup-headers): Search for "from:"
+       instead of "from: " for rfc822 compliance.
+
+       * gnus-uu.el (gnus-uu-digest-mail-forward): Ditto. Insert SPC.
+
+       * nnheader.el (nnheader-parse-head): Ditto.
+
+2000-10-13  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * mail-source.el (mail-source-keyword-map): Use
+       `rmail-spool-directory' as a default directory for the `file'
+       source, if the variable is defined.  Fall back to hardcoded
+       "/usr/spool/mail/", as before.  Suggestion by Steven E. Harris
+       <seh@speakeasy.org>.
+
+2000-10-13 12:01:15  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-send-mail-partially): Replace the header
+       delimiter with a blank line.
+
+2000-10-13  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-sum.el (gnus-get-split-value): Use first match only (Ed L
+       Cashin <ecashin@coe.uga.edu>).
+
+2000-10-13 10:52:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-ems.el (gnus-article-compface-xbm): Ignore errors.
+
+2000-10-11  John Wiegley  <johnw@gnu.org>
+
+       * gnus-topic.el (gnus-topic-mode): Use `setq' to clear
+       `gnus-group-change-level-function', instead of `remove-hook',
+       because it's not a hook!
+
+       * gnus-mlspl.el (gnus-group-split-update): Check the value of
+       `nnmail-crosspost', and use it to set the `no-crosspost'
+       argument when calling `gnus-group-split-fancy'.  Otherwise, it
+       assumes that cross-posting is always OK, no matter what
+       `nmail-crosspost' is set to.
+       (gnus-group-split-fancy): The argument order in the
+       second-to-last `push' call was wrong, but since `no-crosspost'
+       was always nil, it was never being triggered.
+
+       * gnus-art.el (gnus-treat-hide-citation-maybe): Added this
+       variable to correspond with `gnus-article-hide-citation-maybe'.
+       (gnus-treatment-function-alist): Added entry for the above
+       correlation.
+
+2000-10-12 08:26:30  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-with-unibyte-current-buffer): Revert to old.
+       (mm-with-unibyte-current-buffer-mule4): New function.
+       * qp.el (quoted-printable-encode-region): Use it.
+       * rfc2047.el (rfc2047-decode): Ditto.
+       * webmail.el (webmail-init): Revert to use mm-disable-multibyte.
+
+2000-10-10 08:44:13  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-fold-region): "=?=" is not a break point.
+
+2000-10-10 00:00:28  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el (webmail-init): Use mm-disable-multibyte-mule4.
+
+2000-10-09 22:50:05  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * base64.el (base64-decode-region): Just give a message if the end
+       is not sane.
+
+2000-10-09 20:09:11  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-encode-message-header): Move fold into
+       encode-region.
+       (rfc2047-dissect-region): Rewrite.
+       (rfc2047-encode-region): Rewrite.
+       (rfc2047-fold-region): Fold any line longer than 76.
+       (rfc2047-unfold-region): New function.
+       (rfc2047-decode-region): Use it.
+       (rfc2047-q-encode-region): Don't break at bob.
+
+2000-10-09 17:12:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nntp.el (nntp-open-connection): Kill process buffer when quit.
+       (nntp-connection-timeout): Add a note. SIGALRM is ignored in both
+       FSF Emacs 20 and XEmacs 21.
+       * gnus-agent.el (gnus-agent-fetch-session): Catch quit.
+
+2000-10-09  Dave Love  <fx@gnu.org>
+
+       * gnus-audio.el: Don't require cl.
+       (gnus-audio): New custom group.
+       (gnus-audio-inline-sound): Change to work with Emacs.
+       (gnus-audio-directory, gnus-audio-directory)
+       (gnus-audio-au-player): Customize.
+       (gnus-audio-play): Try external player if play-sound-file fails.
+       Use file-name-extension, not string-match.
+
+       * gnus-art.el (article-de-quoted-unreadable)
+       (article-de-base64-unreadable): Fold search case rather than
+       downcasing string.  Apply mm-charset-to-coding-system to arg of
+       quoted-printable-decode-region.
+       (gnus-article-dumbquotes-map): Fix dashes.
+       (gnus-button-mailto, gnus-button-embedded-url): Doc fix.
+       (gnus-button-reply): Just alias it.
+
+2000-10-09  Stefan Monnier  <monnier@cs.yale.edu>
+
+       * mm-encode.el: Require CL.  At least, for `incf'.
+
+       * nnfolder.el (nnfolder-ignore-active-file): Typos.
+
+       * gnus-mh.el (gnus-summary-save-in-folder): Obey mh-lib-progs.
+
+       * gnus-kill.el (gnus-kill): Typo.
+
+2000-10-09  Gerd Moellmann  <gerd@gnu.org>
+
+       * smiley-ems.el (smiley-update-cache): Use `:ascent center'.
+
+2000-10-09  Simon Josefsson  <simon@josefsson.org>
+
+       * nnimap.el (nnimap-group-overview-filename): Create directory for
+       newfile (when use long filenames is nil).  Copy+delete file if
+       rename didn't work.
+       (nnimap-group-overview-filename): `rename-file' and `copy-file'
+       doesn't return anything useful, use ignore-errors instead.
+
+2000-10-08 13:05:11  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * dgnushack.el (dgnushack-compile): Delete old elc files first.
+
+2000-10-08 10:59:13  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-ems.el (gnus-kill-all-overlays): Move here.
+       * gnus-util.el (gnus-kill-all-overlays): Move out.
+       * gnus-sum.el (gnus-cache-write-active): Auto load.
+       * lpath.el: Shut up.
+       * nnweb.el (nnweb-url-retrieve-asynch): url-retrieve is
+       asynchronous in Exp version.
+
+2000-10-08 08:57:13  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el, gnus-ems.el, gnus-start.el: Remove gnus-xemacs.
+       * gnus-ems.el: Autoload smiley.
+       * gnus-art.el (gnus-treat-display-smileys): Default value in Emacs 21.
+
+2000-10-08 08:45:48  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-display-article): Enable multibyte.
+       (gnus-summary-select-article): Don't enable multibyte here.
+       (gnus-summary-goto-article): Ditto.
+
+2000-10-08  Christoph Conrad  <christoph.conrad@gmx.de>
+
+       * gnus-draft.el (gnus-draft-send-message): Typo.
+
+2000-10-08  Simon Josefsson  <simon@josefsson.org>
+
+       * nnimap.el (nnimap-verify-uidvalidity): Delete overview file when
+       uid validity changes.
+       (nnimap-group-overview-filename): Store uidvalidity in filenames.
+       Rename old files into new format.
+
+2000-10-07 15:49:39  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-enable-multibyte-mule4): New.
+       (mm-disable-multibyte-mule4): New.
+       * gnus-sum.el (gnus-summary-mode): Use it.
+       (gnus-summary-select-article): Ditto.
+       (gnus-summary-goto-article): Use enable multibyte.
+       * rfc2047.el (rfc2047-decode): Use unibyte.
+
+2000-10-07 15:42:59  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-logic.el (gnus-advanced-string): Use "" if nil.
+
+2000-10-07 10:31:05  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-q-encode-region): Better calculation of
+       break point.
+       (rfc2047-fold-region): Don't break the first non-LWSP characters.
+
+2000-10-07 09:18:53  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el (gnus-agent-fetching): New variable.
+       * gnus-agent.el (gnus-agent-with-fetch): Bind it.
+       * gnus-score.el (gnus-score-body): Don't score body when
+       agent-fetching.
+       (gnus-score-followup): Don't score followup either.
+
+2000-10-07 08:19:17  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el: Define dynamic variables in eval-when-compile.
+       * message.el (message-sending-message): New variable.
+       (message-send): Use it.
+       * gnus-draft.el (gnus-draft-send-message): Ditto.
+       (gnus-group-send-drafts): Ditto.
+
+2000-10-06  Dave Love  <fx@gnu.org>
+
+       * gnus-audio.el: Don't require cl.
+       (gnus-audio): New custom group.
+       (gnus-audio-inline-sound): Change to work with Emacs.
+       (gnus-audio-directory, gnus-audio-directory)
+       (gnus-audio-au-player): Customize.
+       (gnus-audio-play): Try external player if play-sound-file fails.
+       Use file-name-extension, not string-match.
+
+2000-10-06 17:38:03  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-prepare): Configure it again.
+
+2000-10-06 15:11:07  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-default-charset): Default value for non-Mule
+       Emacsen.
+
+2000-10-06 14:28:50  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-alternative-emails): New.
+       (message-use-alternative-email-as-from): New.
+       (message-setup): Use them.
+
+2000-10-06 13:46:47  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * base64.el, dgnushack.el, gnus-spec.el, messagexmas.el
+       * gnus-xmas.el, nnheaderxm.el, nndraft.el: Use defalias.
+
+       * gnus-xmas.el (gnus-xmas-define): Defalias gnus-overlay-buffer,
+       gnus-overlay-start.
+       * gnus.el: Ditto.
+       * gnus-art.el (gnus-insert-mime-button): Use them.
+
+2000-10-06 10:01:08  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-with-unibyte-current-buffer): Don't set unibyte
+       if eight-bit-control is a charset, e.g. Mule 5.0 in Emacs 21.
+
+2000-10-06 09:38:54  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * qp.el (quoted-printable-encode-region): Use
+       mm-with-unibyte-current-buffer within narrowed region.
+
+2000-10-06 08:56:33  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el (webmail-type-definition): Fix my-deja open url.
+
+2000-10-06  Emerick Rogul  <emerick@csa.bu.edu>
+
+       * message.el (message-setup-fill-variables): New variable.
+       (message-mode): Use it.
+
+2000-10-05  Dave Love  <fx@gnu.org>
+
+       * rfc2047.el (rfc2047-fold-region): Use gnus-point-at-bol.
+       (rfc2047-charset-encoding-alist): Add iso-8859-1[45].
+
+       * binhex.el: Use defalias, not fset.
+
+       * rfc1843.el: Require cl when compiling.
+
+2000-10-05 12:25:08  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-fetch-group-1): Score-param could be nil.
+
+2000-10-05 11:43:25  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-encode-region): Merge only if regions are
+       adjacent.
+
+2000-10-05 09:41:33  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-multibyte-p): In XEmacs, it is (feature 'mule).
+       (mm-find-charset-region): Merge conditions, delete ascii.
+       (mm-charset-after): Rewrite.
+       * mm-bodies.el (mm-encode-body): Use it.
+
+2000-10-05 09:04:32  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el (webmail-hotmail-list): Fix.
+
+2000-10-05  Stefan Monnier  <monnier+gnu/emacs@rum.cs.yale.edu>
+
+       * nnimap.el (require): cl.
+
+2000-10-04 15:24:46  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-prepare): Configure windows before
+       gnus-article-prepare-display is called.  Otherwise, BBDB's popup
+       window might be overrided.
+
+2000-10-04  Dave Love  <fx@gnu.org>
+
+       * gnus-ems.el (gnus-article-display-xface)
+       [gnus-article-compface-xbm]: Fix.
+       (gnus-x-splash): Bind width, height.
+
+2000-10-04 11:45:04  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-inline-part): Use prefix argument only
+       when it is called interactively.
+
+2000-10-03 21:20:31  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-action-alist): New variable.
+       (gnus-mime-action-on-part): Use it.
+       (gnus-mime-button-commands): Add command ".".
+
+2000-10-03 20:37:42  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-inline-part): Support prefix argument.
+
+2000-10-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: "." is in the load-path because dgnushack.el.
+
+2000-10-03  Bjorn Torkelsson  <torkel@hpc2n.umu.se>
+
+       * uudecode.el: xemacs cleanup (use featurep ' xemacs).
+
+       * nnheader.el: ditto.
+
+       * mm-util.el: ditto.
+
+       * message.el: ditto.
+
+       * binhex.el: ditto.
+
+       * gnus-audio.el: removed unnecessary xemacs test.
+
+       * earcon.el: ditto.
+
+2000-10-03 19:55:55  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnweb.el (nnweb-decode-entities): Work for non-character
+       entities.
+
+2000-09-26 09:20:08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el: Message the quit parts.
+
+2000-10-03 08:08:29  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mail-source.el (mail-source-fetch-maildir): Don't insert
+       newlines.
+
+2000-10-02 20:14:27  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * dgnushack.el (dgnushack-compile): Don't compile dgnushack.el,
+       lpath.el. Don't compile base64.el if there is builtin base64.
+
+2000-10-02  Björn Torkelsson  <torkel@hpc2n.umu.se>
+
+       * base64.el (Repository): Use featurep for XEmacs test.
+
+2000-10-02 17:38:12  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nntp.el (nntp-retrieve-data): Don't ignore quit.
+
+2000-10-02 14:43:13  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-banner-alist): New variable.
+       (article-strip-banner): Use it.
+       * gnus-cus.el (gnus-group-parameters): Allow symbol.
+
+2000-10-02  Dave Love  <fx@gnu.org>
+
+       * smiley-ems.el: New file.
+
+       * gnus-ems.el (gnus-smiley-display): Autoload.
+       (mouse-set-point, set-face-foreground, set-face-background)
+       (x-popup-menu): Don't clobber these.
+       (gnus-article-compface-xbm): New variable.
+       (gnus-article-display-xface): Move graphic test.  Use unibyte.
+       Obey gnus-article-compface-xbm.  Use pbm, not xbm.
+
+       * mml.el (require): Fix typo.
+       (mml-parse-1): Modify unknown encoding prompt.
+
+       * mail-source.el (mail-sources): Revert to nil.
+
+       * nnmail.el (nnmail-spool-file): Revert previous change.
+
+       * gnus.el: Don't require custom, message.
+       (gnus-message-archive-method): Wrap initializer in progn and
+       require message here.
+
+2000-10-02  Gerd Moellmann  <gerd@gnu.org>
+
+       * gnus.el (gnus-mode-line-buffer-identification) [Emacs]: Change
+       image's :ascent to 80.  That gives a mode-line which is approx.
+       as tall as the normal one.
+
+2000-10-02 08:04:48  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el (webmail-hotmail-list): Fix.
+
+2000-10-01 20:55:53  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       Don't postpone GCC if none of GCC methods is agent-covered.  This
+       fix presumes that the post-method must be agent-covered if any Gcc
+       method is agent-covered.
+
+       * gnus-msg.el (gnus-inews-group-method): New function.
+       (gnus-inews-do-gcc): Use it.
+       * gnus-agent.el (gnus-agent-any-covered-gcc): New function.
+       (gnus-agent-possibly-save-gcc): Use it.
+       (gnus-agent-possibly-do-gcc): Ditto.
+
+2000-10-01 17:08:50  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mailcap.el (mailcap-mime-types): Use mailcap-mime-data.
+       * mml.el (mml-minibuffer-read-type): Use mailcap-mime-types.
+
+2000-10-01 13:07:21  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el (webmail-netscape-open, webmail-hotmail-article,
+       webmail-hotmail-list): Update.
+
+2000-10-01 08:36:09  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mail-source.el (mail-source-report-new-mail): Use
+       nnheader-cancel-timer.
+
+2000-10-01 08:35:38  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * lpath.el (overlay-*): Shut up.
+       * dgnushack.el: Two implementations of smiley.
+
+2000-10-01 08:32:42  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-ml.el: Usage.
+       (gnus-mailing-list-archive, gnus-mailing-list-owner,
+       gnus-mailing-list-post, gnus-mailing-list-unsubscribe,
+       gnus-mailing-list-subscribe, gnus-mailing-list-help): Bind list-*.
+       (gnus-mailing-list-menu): Define it.
+       (turn-on-gnus-mailing-list-mode, gnus-mailing-list-mode): Autoload.
+
+       * gnus-xmas.el (gnus-xmas-mailing-list-menu-add): Move here.
+
+2000-09-30 18:52:51  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el (webmail-my-deja-*): Rewrite.
+
+2000-09-30  Simon Josefsson  <simon@josefsson.org>
+
+       * nnimap.el (nnimap-request-accept-article): Remove \n's from
+       From_ lines.
+
+2000-08-05  Simon Josefsson  <simon@josefsson.org>
+
+       Make GCC to remote groups work when unplugged
+       (postpone GCC until message is actually sent).
+
+       * gnus-draft.el (gnus-draft-send): Call `gnus-agent-restore-gcc'.
+
+       * gnus-agent.el (gnus-agent-possibly-do-gcc):
+       (gnus-agent-restore-gcc):
+       (gnus-agent-possibly-save-gcc): New functions.
+
+       * gnus-msg.el (gnus-inews-add-send-actions): Use
+       `gnus-agent-possibly-do-gcc' if Agentized.
+       (gnus-inews-add-send-actions): Add `gnus-agent-possibly-save-gcc'
+       to `message-header-hook'.
+
+       * gnus.el (gnus-agent-gcc-header): New variable.
+
+2000-07-13  Simon Josefsson  <simon@josefsson.org>
+
+       Asks the user to synch flags with server when you plug in.
+
+       * gnus-agent.el (gnus-agent-synchronize-flags): New variable.
+       (gnus-agent-possibly-synchronize-flags-server): New function, use it.
+       (gnus-agent-toggle-plugged): Call it.
+       (gnus-agent-synchronize-flags): Renamed from `gnus-agent-synchronize'.
+       (gnus-agent-group-mode-map): `g-a-s' -> `g-a-s-flags'.
+       (gnus-agent-possibly-synchronize-flags): New function.
+       (gnus-agent-possibly-synchronize-flags-server): New function.
+
+2000-09-30  Simon Josefsson  <simon@josefsson.org>
+
+       * starttls.el: New file, by Daiki Ueno.
+
+2000-08-02  Stanislav Shalunov  <shalunov@internet2.edu>
+
+       * message.el (message-make-in-reply-to): In-Reply-To is message-id
+       (see DRUMS).
+
+2000-09-29  Simon Josefsson  <simon@josefsson.org>
+
+       * nntp.el (nntp-async-trigger): Fix authinfo in asynchronous
+       prefetch.
+
+2000-08-09 10:21:20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nntp.el (nntp-open-telnet): Wait for the telnet prompt before
+       sending a command; allow the rtelnet prompt as well.
+
+2000-09-29  Simon Josefsson  <simon@josefsson.org>
+
+       * message.el (message-send): Make sure error is signalled if no
+       send method is specified.
+
+2000-09-29  Florian Weimer  <fw@deneb.enyo.de>
+
+       * qp.el (quoted-printable-encode-region): Wrap with
+       `mm-with-unibyte-current-buffer'.
+
+2000-09-29 12:12:49  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-fetch-group-1): Reimplement Mike
+       McEwan's proposal.
+
+2000-09-29 12:06:40  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el: Revoke Mike McEwan's 1998-09-05 patch due to
+       the GNU assignment issue.
+
+2000-09-29 09:56:34  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nndoc.el (nndoc-dissect-mime-parts-sub): Correctly mark body-begin.
+
+2000-09-29 09:14:08  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-enter-digest-group): Decode to-address.
+
+2000-09-28  Andrei Elkin  <astro@sbor.ru>  (tiny change)
+
+       * gnus-art.el (article-strip-banner): Use
+       gnus-group-find-parameter rather than gnus-group-get-parameter, to
+       allow inheritance on the banner.
+
+2000-09-26  Richard M. Alderson III  <alderson@netcom2.netcom.com>
+
+       * gnus-art.el (gnus-read-save-file-name): expand-file-name.
+
+2000-09-26  Dave Love  <fx@gnu.org>
+
+       * gnus-draft.el: Don't require gnus-agent.
+
+       * mm-view.el: Use featurep for XEmacs test.
+       (mm-inline-message): Test for `remove-specifier'; don't use
+       condition-case.
+
+2000-09-24  Simon Josefsson  <simon@josefsson.org>
+
+       * nnimap.el (nnimap-request-accept-article): Remove From[^:] lines.
+
+       * gnus-group.el (gnus-group-nnimap-edit-acl): Check if server
+       support ACL's.
+
+       * nnimap.el (nnimap-acl-get): Check capability.
+
+       * mail-source.el (mail-source-imap-file-coding-system): New variable.
+       (mail-source-fetch-imap): Use it.
+
+       * rfc2104.el (rfc2104-hexstring-to-bitstring): New function.
+       (rfc2104-hash): Use it.
+
+       * imap.el (imap-starttls-p): Check for starttls binary.
+       (imap-starttls-open): More verbose.
+       (imap-gssapi-auth): Ditto.
+       (imap-kerberos4-auth): Ditto.
+       (imap-cram-md5-auth): Ditto.
+       (imap-login-auth): Ditto.
+       (imap-anonymous-auth): Ditto.
+       (imap-digest-md5-auth): Ditto.
+       (imap-open): Ditto.
+       (imap-digest-md5-p): Check capability first.
+
+2000-09-24  Simon Josefsson  <simon@josefsson.org>
+
+       * imap.el (imap-parse-flag-list): Correctly parse empty lists.
+       (imap-login-p): Support LOGINDISABLED.
+
+2000-09-23  Simon Josefsson  <jas@nada.kth.se>
+
+       * rfc2104.el: Add SHA-1 example.
+
+2000-09-22  Simon Josefsson  <simon@josefsson.org>
+
+       * imap.el (imap-parse-body): Work around bug in Sun SIMS.
+
+2000-09-21 21:54:48  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * lpath.el: Bind nnkiboze-score-file.
+
+2000-09-21 16:15:25  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-score.el (gnus-score-use-all-scores): New variable.
+       (gnus-all-score-files): Use it.
+       * nnkiboze.el (nnkiboze-generate-group): Use it. Inhibit list groups.
+       (nnkiboze-enter-nov): Fix it when there is no xref.
+       (nnkiboze-generate-groups): List groups.
+       * gnus-group.el (gnus-group-make-kiboze-group): Use
+       nnkiboze-score-file.
+
+       * nnkiboze.el (nnkiboze-request-article): Use
+       gnus-cache-request-article.
+       * gnus-group.el (gnus-group-make-kiboze-group): Fix prompt.
+
+2000-07-16  Dmitry Bely  <dbely@mail.ru>
+
+       * nnheader.el (nnheader-translate-file-chars): Path splitting on NT.
+
+2000-09-20 18:33:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-score.el (gnus-score-find-bnews): Use directory-sep-char.
+
+2000-09-20 17:37:46  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-default-charset): Set default value in
+       non-MULE XEmacsen as iso-8859-1.
+
+2000-09-20 12:02:24  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-demon.el: Use (featurep 'xemacs).
+       * gnus-agent.el: timer vs. itimer.
+       * mail-source.el: Ditto.
+
+2000-09-19 10:24:57  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-make-kiboze-group): Makedir.
+       * nnheader.el (nnheader-parse-nov): Remove Xref in mail-header-xref.
+       * gnus-sum.el (gnus-nov-parse-line): Ditto.
+       * nnkiboze.el (nnkiboze-file-coding-system): New.
+       (nnkiboze-retrieve-headers): Use it.
+       (nnkiboze-request-group): Ditto.
+       (nnkiboze-close-group): Ditto.
+       (nnkiboze-generate-group): Ditto.
+       (nnkiboze-enter-nov): Insert first Xref properly.
+
+2000-09-19  Dave Love  <fx@gnu.org>
+
+       * nnmail.el (nnmail-cache-accepted-message-ids): Default to nil.
+       (nnmail-get-new-mail): Test `sources' in top-level conditional.
+
+       * mail-source.el (mail-sources): Change default to '((file)).
+       Add useful custom type.
+
+2000-09-18  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-util.el (gnus-time-iso8601): Correct doc string (four digit
+       year).
+       (gnus-date-iso8601): Ditto.
+
+2000-09-18 09:05:46  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mail-source.el (mail-source-fetch-imap): Disable multibyte.
+
+2000-09-17 01:13:46  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-q-encoding-alist): Remove = and _ from the
+       pattern. Avoid using 8 bit chars.
+       * qp.el (quoted-printable-encode-region): Avoid using 8 bit chars.
+
+2000-09-16 15:57:42  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * smiley.el (smiley-buffer-ems, smiley-create-glyph-ems,
+       smiley-toggle-extent-ems, smiley-toggle-extents-ems,
+       smiley-toggle-buffer-ems): New functions for Emacs 21. Toggle
+       functions are not implemented yet.
+
+       * dgnushack.el (dgnushack-compile): Remove smiley.el and
+       x-overlay.el from the FSF Emacs black list.
+
+2000-09-15 21:10:20  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-inlined-types): Add application/emacs-lisp.
+       (mm-inline-media-tests): Ditto.
+       (mm-automatic-display): Ditto.
+       * mm-view.el (mm-display-inline-fontify): Generalize from
+       mm-display-patch-inline.
+       (mm-display-patch-inline): Use it.
+       (mm-display-elisp-inline): Ditto.
+
+2000-09-15 14:03:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-topic.el (gnus-topic-find-groups): Add recursive parameter.
+       (gnus-topic-unmark-topic): Ditto.
+       (gnus-topic-mark-topic): Ditto.
+       (gnus-topic-get-new-news-this-topic): Use it.
+
+2000-09-15 09:01:40  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-treat-display-xface): By default, Emacs 21
+       display xface.
+
+2000-08-23 02:54:46  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el (gnus-group-rename-group): Inhibit renaming of
+       zombie or killed groups.
+
+2000-09-15 00:09:56  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-preview): Reinsert unibyte content.
+       (mml-parse-1): Remove with-unibyte-current-buffer.
+       (mml-generate-mime-1): Ditto.
+       * gnus-msg.el (gnus-summary-mail-forward): Ditto.
+       * message.el (message-forward): Ditto.
+
+2000-09-14 23:13:50  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-de-quoted-unreadable): Guess charset from
+       original article buffer.
+       (article-de-base64-unreadable): Ditto.
+       (article-wash-html): Ditto.
+
+2000-09-14 18:55:30  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-summary-mail-forward): Disable multibyte
+       unless forward-show-mml.
+
+2000-09-14 14:48:57  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-save-parts-type-history): New.
+       (gnus-summary-save-parts-last-directory): New.
+       (gnus-summary-save-parts): Save history.
+
+2000-09-14  Ben Gertzfield  <che@debian.org>
+
+       * gnus-sum.el (gnus-summary-save-parts-default-mime): New
+       variable.
+       (gnus-summary-save-parts): Use it.
+
+2000-09-14 11:31:28  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-setup-buffer): Clean handle-alist.
+       * gnus-sum.el (gnus-summary-exit): Ditto.
+       (gnus-summary-exit-no-update): Ditto.
+       (gnus-summary-show-article): Ditto.
+
+2000-09-14 08:42:48  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nndoc.el (nndoc-dissect-mime-parts-sub): Remove
+       Content-Disposition.
+
+2000-09-13 23:58:40  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el: Hotmail updated. Add X-Gnus-Webmail.
+
+2000-09-13 21:41:25  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-setup-buffer): Set
+       gnus-article-mime-handles to nil.
+       * gnus-sum.el (gnus-summary-exit): Ditto.
+       (gnus-summary-exit-no-update): Ditto.
+       (gnus-summary-show-article): Ditto.
+       (gnus-summary-save-parts): Use gnus-article-mime-handles if
+       dissected.
+       * mm-partial.el (mm-partial-find-parts): Remove redundancy.
+
+2000-09-13 16:59:33  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-sort): Sort loose threads too.
+       (gnus-sort-threads-1): New function. Sort threads recursively.
+       (gnus-sort-threads): Use it.
+       (gnus-sort-gathered-threads): Doc fix.
+
+2000-09-13  Dave Love  <fx@gnu.org>
+
+       * gnus-salt.el (gnus-binary-mode): Fix call to gnus-add-minor-mode.
+
+       * gnus-ems.el (gnus-ems-redefine): Don't alias
+       gnus-summary-set-display-table.
+
+       * message.el (message-user-agent): Don't wrap ignore-errors around
+       it.
+
+       * mm-encode.el (mm-insert-multipart-headers): Avoid redundant
+       `format'.
+       (mm-content-transfer-encoding): Don't use cadar.
+
+       * uudecode.el (uudecode-decoder-program)
+       (uudecode-decoder-switches): Customize.
+
+       * gnus-score.el (gnus-home-score-file): Improve custom type.
+
+       * gnus-cus.el (gnus-custom-mode): Conditionally set local
+       variables for Emacs 21.
+       (gnus-group-customize): Disable undo while laying out the buffer.
+
+2000-09-13 09:38:26  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-util.el (gnus-write-active-file): Bind
+       coding-system-for-write.
+
+2000-09-13 09:14:57  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnmail.el (nnmail-get-new-mail): Don't test nnmail-spool-file.
+
+       * gnus-cache.el (gnus-jog-cache): Temporarily disable mail-sources.
+       * gnus-kill.el (gnus-batch-score): Ditto.
+       * gnus-move.el (gnus-change-server): Ditto.
+       * nnkiboze.el (nnkiboze-generate-groups): Ditto.
+
+2000-09-12  Simon Josefsson  <simon@josefsson.org>
+
+       * gnus-sum.el (gnus-update-read-articles): Undo
+       `gnus-request-set-mark' operation.
+
+2000-09-11  Dave Love  <fx@gnu.org>
+
+       * ChangeLog: Use iso-2022 coding.
+
+       * gnus-msg.el (gnus-msg-mail): New function.
+       (gnus-user-agent): New mail agent.
+
+2000-09-10  Dave Love  <fx@gnu.org>
+
+       * message.el: Require mail-abbrevs for XEmacs for a problem with
+       keybinding despite the autoloads for it.
+
+2000-09-08  Simon Josefsson  <simon@josefsson.org>
+
+       * imap.el (imap-kerberos4-open): Erase more (fixes race condition?).
+
+       * nnimap.el (nnimap-request-update-info-internal): Remove tick
+       marks from dormant articles. (See nnimap-request-set-mark.)
+       (nnimap-retrieve-headers-progress): Demule.
+       (nnimap-open-server): Call nnoo-change-server twice, once for
+       getting the nnimap-server-buffer and once for letting n-c-s set
+       the variables in that buffer.
+
+2000-09-08  David Edmondson  <dme@dme.org>
+
+       * gnus.el (gnus-short-group-name): Guess separator.
+
+2000-09-07  Tadashi Watanabe  <watanabe@sigmaitec.co.jp>
+
+       * smiley.el (smiley-buffer, smiley-create-glyph): Work with GTK
+       XEmacs as well.
+
+2000-09-06  Francis Litterio  <franl-removethis@world.omitthis.std.com>
+
+       * gnus-group.el (gnus-group-insert-group-line): Fix.
+
+2000-09-04  Dave Love  <fx@gnu.org>
+
+       * mm-decode.el (mime-display) <defgroup>: Add `multimedia' group.
+       (mm-get-image): Avoid the losing `make-glyph' from W3.
+
+2000-09-03  Simon Josefsson  <simon@josefsson.org>
+
+       * gnus-sum.el (gnus-summary-delete-article): Check server.
+
+2000-09-01  Simon Josefsson  <simon@josefsson.org>
+
+       * imap.el (imap-parse-flag-list): Rewrite.
+
+       * nnimap.el (nnimap-retrieve-headers-from-file): Ignore errors.
+
+       * imap.el (imap-parse-flag-list): Hack.
+
+2000-08-29  Dave Love  <fx@gnu.org>
+
+       * gnus-mlspl.el (gnus-group-split-fancy): Eschew mapcon.
+
+       * dgnushack.el (mapcon, union): Remove compiler macros.
+
+       * gnus-agent.el (gnus-agent-union): new function.
+       (gnus-agent-fetch-headers): Use it.
+
+       * gnus.el (gnus-group-startup-message): Modifications to last change.
+
+2000-08-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (gnus-group-startup-message): Specify foreground and
+       background for xpm image.  Centre image vertically.
+
+2000-08-24 23:49:23  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-send-mail): Narrow-to-headers.
+
+2000-08-24  Dave Love  <fx@gnu.org>
+
+       * gnus-art.el (gnus-insert-mime-button): Fix help-echo for Emacs
+       21.
+
+2000-08-23  Dave Love  <fx@gnu.org>
+
+       * dgnushack.el: Remove `member-if' compiler macro.
+
+2000-08-21  Dave Love  <fx@gnu.org>
+
+       * nnimap.el (nnimap-request-newgroups): Eschew member-if.
+
+2000-08-21 10:09:47  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-topic.el (gnus-topic-hide-topic): Use find-topology if
+       permanent is used.
+       (gnus-topic-show-topic): Read topic when to show permanent hidden
+       topic.
+       (gnus-topic-remove-topic): Revert to the old behavior, not using
+       hide.
+
+2000-08-21  Dave Love  <fx@gnu.org>
+
+       * gnus-ems.el (gnus-add-minor-mode): Add &rest arg.
+       (gnus-xemacs): Use featurep.
+
+       * mm-util.el (mm-read-charset): Maybe use builtin.
+       (mm-replace-chars-in-string): Maybe use subst-char-in-string.
+       (mm-multibyte-p, mm-with-unibyte-current-buffer)
+       (mm-with-unibyte): Use featurep, not string-match.
+       (mm-with-unibyte-buffer): Simplify.
+       (mm-quote-arg): Maybe use shell-quote-argument.
+
+       * mml.el (mml-make-string): Deleted (unused).
+
+       * gnus.el (gnus-mode-line-buffer-identification): Supply
+       definition for Emacs 21.
+
+       * gnus-salt.el: Small doc fixes.
+       (gnus-pick-mode, gnus-binary-mode): Supply a toggle-func arg to
+       gnus-add-minor-mode.
+
+       * gnus-topic.el (gnus-topic-mode): Supply a toggle-func arg to
+       gnus-add-minor-mode.
+
+2000-08-20  Simon Josefsson  <simon@josefsson.org>
+
+       * nnimap.el (nnimap-before-find-minmax-bugworkaround): New
+       function, thanks to Lloyd Zusman for debugging.
+       (nnimap-request-group):
+       (nnimap-request-list):
+       (nnimap-retrieve-groups):
+       (nnimap-request-newgroups): Use it.
+
+       * nnimap.el (nnimap-request-article-part): Less verbose.
+
+2000-08-19  Andreas Jaeger  <aj@suse.de>
+
+       * lpath.el ((string-match "XEmacs" emacs-version)): Remove
+       subst-char-in-string since we test elsewhere whether it's bound.
+
+2000-08-18  Dave Love  <fx@gnu.org>
+
+       * gnus-score.el (gnus-score-find-score-files-function): Fix doc,
+       custom type.
+
+       * gnus-xmas.el (gnus-group-icon-create-glyph): Don't test
+       gnus-group-running-xemacs.
+
+       * nnheader.el (nnheader-replace-chars-in-string): Use
+       subst-char-in-string if available.
+
+       * gnus-art.el (gnus-read-save-file-name, gnus-plain-save-name)
+       (gnus-request-article-this-buffer): Use expand-file-name.
+       (gnus-mime-view-part-as-type): Simplify interactive spec.
+       (gnus-mime-button-map): Define it all in defvar.
+
+2000-08-17  Dave Love  <fx@gnu.org>
+
+       * gnus-group.el (gnus-group-running-xemacs): Deleted.
+
+       * gnus-demon.el (gnus-demon): Bind use-dialog-box and
+       last-nonmenu-event.
+
+       * uudecode.el (char-int): Use defalias, not fset.
+
+       * score-mode.el: Don't require easymenu.  Require mm-util.
+       (score-mode-coding-system): Use mm-auto-save-coding-system.
+
+       * nneething.el (nneething-create-mapping): Don't use cadar & al.
+       (nneething-file-name): Use expand-file-name, not concat.
+
+2000-08-16 13:05:46  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnslashdot.el (nnslashdot-threaded-retrieve-headers):
+       Failure proof for email addresses.
+       (nnslashdot-sane-retrieve-headers): Ditto.
+
+2000-08-14 20:08:40  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-send-mail): Only insert courtesy message
+       when text/plain.
+
+2000-08-14 19:55:04  Jesper Harder  <jesper_harder@hotmail.com>
+
+       * message.el (message-cancel-news): Copy the From header from the
+       original article.
+
+2000-08-14 19:52:01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-async.el (gnus-asynchronous): Removed.
+
+2000-08-14 16:12:11  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mail-source.el (mail-source-fetch-maildir): Use MMDF mail
+       format.
+
+2000-08-14 19:12:22  Rod Whitby  <list.ding@rwhitby.net>
+
+       * nnmail.el (nnmail-expiry-target-group): Fixed.
+
+2000-08-14  Rod Whitby  <list.ding@rwhitby.net>
+
+       * nnmail.el (nnmail-expiry-target-group): Fix the call to
+       gnus-request-accept-article so that body encoding is *not* done.
+       Encoding is not done on incoming mail, so why should it be done on
+       expired mail?
+
+
+2000-08-14  Rod Whitby  <list.ding@rwhitby.net>
+
+       * nnml.el (nnml-request-expire-articles): Fix the calls to
+       nnml-request-article (the filename was being passed instead of the
+       article number) and nnmail-expiry-target-group
+       (nnml-current-directory is changed by nnml-request-accept-article,
+       causing it to be incorrect for the next article to be expired).
+
+2000-08-14  Rod Whitby  <list.ding@rwhitby.net>
+
+       * gnus-sum.el (gnus-summary-expire-articles): Fix the handling of
+       expiry-target group parameters.
+
+2000-08-13 18:53:08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-topic.el (gnus-topic-select-group): Touch the dribble
+       buffer.
+       (gnus-topic-hide-topic): Take a PERMANENT parameter.
+       (gnus-topic-show-topic): Ditto.
+
+       * gnus-dup.el (gnus-dup-suppress-articles): Do auto-expiry.
+
+2000-08-12 21:48:00  John H. Palmieri  <palmieri@math.washington.edu>
+
+       * mail-source.el (mail-source-incoming-file-prefix): New
+       variable.
+
+2000-08-12 20:29:53  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-check-first-time-used): Clean up a bit.
+
+       * mailcap.el (mailcap-maybe-eval): Be even more warning.
+
+2000-08-11  Florian Weimer  <fw@deneb.enyo.de>
+
+       * message.el (message-syntax-checks): New check quotin-style:
+       Text must be written below quoted text.
+       (message-check-news-body-syntax): Check it.
+
+2000-08-11  Simon Josefsson  <simon@josefsson.org>
+
+       * imap.el (imap-authenticator-alist): Fix typo.
+       (imap-gssapi-open): Copy krb4 fixes for modern imtest's, thanks to
+       Jonas Oberg for debugging.
+
+2000-08-11  Simon Josefsson  <simon@josefsson.org>
+
+       * gnus-async.el (gnus-asynchronous): Disable by default.
+
+2000-08-10 20:22:09  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-view.el (mm-inline-text): Bind fill-column.
+
+       * nnvirtual.el (nnvirtual-request-expire-articles): Return the
+       list of unexpired articles.
+
+       * gnus-group.el (gnus-group-expire-articles-1): Return the list of
+       un-expired articles.
+
+       * gnus-sum.el (gnus-summary-reparent-thread): Narrow to the
+       headers.
+
+       * gnus-topic.el (gnus-topic-kill-group): Move up one line so that
+       we update the right topic..
+
+       * mm-decode.el (mm-display-external): Put point at start.
+
+2000-08-10  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * nnmail.el (nnmail-expiry-target): More explicit documentation.
+
+       * gnus-cus.el (gnus-group-parameters): Add parameter `expiry-wait'.
+
+2000-08-09  Simon Josefsson  <simon@josefsson.org>
+
+       * imap.el (imap-parse-body):
+       (imap-parse-string-list): Add bug workarounds for Stalker
+       Communigate Pro 3.0 server.
+       (imap-body-lines): Remove bogus comment.
+
+       * imap.el (imap-range-to-message-set): Move from nnimap.el.
+
+       * nnimap.el (nnimap-retrieve-which-headers):
+       (nnimap-retrieve-headers-from-server):
+       (nnimap-request-set-mark):
+       (nnimap-request-expire-articles): Use `i-r-t-m-set' instead.
+
+2000-08-08 00:53:41  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-dont-reply-to-names):
+       rmail-dont-reply-to-names may not be defined.
+
+2000-08-07 09:37:01  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-iterate): Uncompiled function should
+       not use pop.
+
+2000-07-19  Dave Love  <fx@gnu.org>
+
+       * gnus-ems.el: Defalias some dummy funcs to `ignore'.
+       (gnus-x-splash): Use expand-file-name.  Remove redundant facep
+       check.
+       (gnus-article-display-xface): Special-case for dark backgrounds.
+
+2000-07-19  Kim-Minh Kaplan  <kmkaplan@galaxy.fr>
+
+       * imap.el (imap-calculate-literal-size-first): New variable.
+       (imap-local-variables): Add it.
+       (imap-kerberos4-open): Set it.
+       (imap-send-command): Use it.
+
+2000-07-17 14:18:16  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mailcap.el (mailcap-mimetypes-parsed-p): New variable.
+       (mailcap-parse-mimetypes): Use it.
+       (mailcap-extension-to-mime): Parse mimetype.
+       (mailcap-mime-types): Ditto.
+       * mml.el (mml-minibuffer-read-type): Ditto.
+
+2000-07-16 18:25:07  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nndoc.el (nndoc-type-alist): Add outlook.
+       (nndoc-outlook-type-p): New function.
+       (nndoc-outlook-article-begin): Ditto.
+
+2000-07-16  Daiki Ueno  <ueno@unixuser.org>
+
+       * gnus-sum.el (gnus-restore-hidden-threads-configuration): Save
+       excursion.
+
+2000-07-15  Simon Josefsson  <simon@josefsson.org>
+
+       * gnus-cus.el (gnus-group-parameters, banner): Type is regexp.
+
+       * imap.el (imap):
+       (imap-kerberos4-program):
+       (imap-gssapi-program):
+       (imap-ssl-program): Customization.
+       (imap-shell-program):
+       (imap-shell-host): New variables.
+       (imap-streams):
+       (imap-stream-alist): Add shell.
+       (imap-shell-p):
+       (imap-shell-open): New functions.
+       (imap-open): Don't call authenticator if preauth.
+       (imap-authenticate): Return t if already authenticated.
+
+2000-07-14  Simon Josefsson  <simon@josefsson.org>
+
+       * gnus.el (gnus-invalid-group-regexp): New variable.
+       (gnus-read-group): Use it.
+
+2000-07-14 12:40:51  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-fetch-group-1): mark-below,
+       expunge-below and orphan-score are "group variables".
+
+2000-07-13  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-srvr.el (gnus-browse-read-group): Don't pass fully
+       qualified group names to `gnus-group-read-ephemeral-group'.
+
+2000-07-13 07:40:39  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (srcdir): Define it before use it.
+
+2000-07-12 19:37:50  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el: `W t' is toggle-header in info.
+
+2000-07-12 16:50:06  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * lpath.el: Fbind subst-char-in-string.
+
+2000-07-12 15:48:29  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * Makefile.in: Use W3DIR and lispdir.
+       * dgnushack.el: Ditto.
+
+2000-07-12 10:12:31  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-de-base64-unreadable): Typo.
+
+2000-07-12  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-agent.el (require): Require timer.
+
+2000-07-11 18:29:50  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-bounce): Call mime-to-mml.
+
+2000-07-11 18:00:49  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnslashdot.el (nnslashdot-request-close): New function.
+
+2000-07-04 23:23:23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnslashdot.el (nnslashdot-threaded-retrieve-headers): Get the
+       right line number for the article.
+
+2000-07-10 22:41:58  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnslashdot.el (nnslashdot-threaded-retrieve-headers): Save point.
+       * webmail.el (webmail-fetch): Bind
+       url-http-silence-on-insecure-redirection.
+
+2000-07-10 11:43:22  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnslashdot.el (nnslashdot-threaded-retrieve-headers): Use
+       unibyte.
+       (nnslashdot-sane-retrieve-headers): Ditto.
+       (nnslashdot-request-article): Ditto.
+
+2000-07-10 11:12:32  William M. Perry  <wmperry@aventail.com>
+
+       * mailcap.el (mailcap-parse-mimetype-file):
+
+2000-07-07 23:46:22  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnweb.el (nnweb-insert): Stricter test.
+       * webmail.el (webmail-refresh-redirect): Ditto.
+
+2000-07-06 14:17:48  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-dissect-multipart): Match the EOL of boundary.
+
+2000-07-05 21:19:22  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnheader.el (nnheader-insert-nov): Remove EOLs of all fields.
+
+2000-07-05  Dave Love  <fx@gnu.org>
+
+       * utf7.el: Doc and header fixes.
+
+       * gnus-sum.el: Doc fixes.
+
+       * gnus-util.el (gnus-point-at-eol, gnus-point-at-bol): Use
+       defalias, not fset.
+
+       * flow-fill.el (fill-flowed-point-at-eol)
+       (fill-flowed-point-at-bol): Use defalias, not fset.
+
+       * gnus-art.el: Don't alias article-mime-decode-quoted-printable.
+       (gnus-Plain-save-name): Delete -- apparently bogus.
+
+2000-07-03 00:12:26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnsoup.el: Use expand-file-name throughout.
+
+2000-07-03 00:07:51  Kjetil Torgrim Homme  <kjetilho@ifi.uio.no>
+
+       * nnmail.el (nnmail-read-incoming-hook): New example.
+
+2000-07-02 23:17:23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-view.el (mm-inline-text): Check whether the text has already
+       been decoded.
+
+2000-07-04 15:17:05  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnslashdot.el (nnslashdot-sid-strip): To strip or not to strip?
+
+2000-07-03  Stainless Steel Rat  <ratinox@peorth.gweep.net>
+
+       * gnus-sum.el (gnus-recenter): Fix horizontal recenter.
+
+2000-07-03  Simon Josefsson  <simon@josefsson.org>
+
+       * gnus-sum.el (gnus-update-marks): Don't propagate download and
+       unsend flags.
+
+2000-07-03  Simon Josefsson  <jas@pdc.kth.se>
+
+       * nnimap.el (nnimap-open-connection): Don't look up virtual server
+       name in authinfo (.authinfo now support ports, no need for the
+       hack).
+       (nnimap-split-find-rule): Fix.
+       (nnimap-open-connection): Look for nnimap-server-address in authinfo.
+
+2000-07-03  Paul Stodghill  <stodghil@CS.Cornell.EDU>
+
+       * message.el (message-unquote-tokens): Remove all quotes.
+
+2000-07-03 00:29:08  Julien Gilles  <julien.gilles@bcv01y01.vz.cit.alcatel.fr>
+
+       * gnus-ml.el: New file.
+
+2000-07-02 16:11:25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnultimate.el (nnultimate-request-close): New function.
+
+       * gnus-start.el (gnus-clear-system): Clear nnmail-split-history.
+
+2000-06-18  Norbert Koch  <norbert@s.netic.de>
+
+       * Makefile.in: Better support for xemacs builds
+
+Sun Jul  2 15:11:35 2000  Lars Magne Ingebrigtsen  <lmi@quimbies.gnus.org>
+
+       * gnus.el: Gnus v5.8.7 is released.
+
+2000-05-19 06:32:52  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-insert-part): Characters doubly decoded.
+
+2000-07-01 10:23:08  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-do-fcc): Encode MIME.
+
+2000-06-28 13:52:57  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * lpath.el: Fbind image-size.
+
+2000-06-28  Simon Josefsson  <simon@josefsson.org>
+
+       * nnimap.el (nnimap-split-rule): Update doc with extended syntax.
+       (nnimap-assoc-match): New function.
+       (nnimap-split-find-rule): Support extended syntax.
+
+2000-06-28  Simon Josefsson  <simon@josefsson.org>
+
+       * nnimap.el (nnimap-open-connection): Use port stuff.
+
+       * gnus-util.el (gnus-netrc-machine): Add defaultport parameter,
+       document port and defaultport.
+
+2000-06-27  Paul Stodghill  <stodghil@CS.Cornell.EDU>
+
+       * gnus-agent.el (gnus-agent-synchronize): Kill flags buffer.
+
+2000-06-26  Dave Love  <fx@gnu.org>
+
+       * mm-decode.el (mm-image-fit-p): Use `image-size' in Emacs.
+
+       * message.el: Remove unnecessary `require'ments.  Defvar
+       gnus-list-identifiers when compiling.  Don't try to autoload
+       variable `gnus-list-identifiers'.  Autoload
+       gnus-group-name-charset.
+       (message-fetch-field): Don't assume `format' removes text
+       properties.
+       (message-strip-list-identifiers, message-reply, message-followup):
+       Require gnus-sum.
+       (message-mode): Tidy XEmacs conditionals.
+       (message-replace-chars-in-string): Use subst-char-in-string when
+       available.
+
+       * gnus-xmas.el (gnus-xmas-define) <match-string-no-properties>:
+       Define if necessary.
+
+       * gnus-art.el (gnus-article-edit-exit): Don't assume `format'
+       removes text properties.
+
+       * gnus-srvr.el (gnus-browse-group-name): Likewise.
+
+       * gnus-msg.el (gnus-copy-article-buffer): Likewise.
+
+       * gnus-score.el (gnus-summary-score-entry): Likewise.
+
+2000-06-26 11:18:57  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnimap.el (nnimap-request-post): Fix parenthesis.
+
+2000-06-26  Paul Stodghill  <stodghil@CS.Cornell.EDU>
+
+       * message.el (message-unquote-tokens): New function.
+
+       * gnus-msg.el (gnus-inews-do-gcc): Unquote gcc tokens.
+
+       * nnimap.el (nnimap-request-post): Ditto.
+
+2000-06-21  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus.el (gnus-asynchronous): Removed (defined in gnus-async.el).
+
+       * nnimap.el (nnimap-callback): Update for IMAP4rev1 servers (see
+       patch commited 2000-04-02).
+
+2000-06-20  Simon Josefsson  <jas@pdc.kth.se>
+
+       * imap.el (imap-mailbox-examine-1): New function.
+       (imap-message-copyuid-1):
+       (imap-message-appenduid-1): Use it, instead of
+       `imap-mailbox-examine' which would utf-7 encode mailbox name
+       twice.
+
+2000-06-19  Dave Love  <fx@gnu.org>
+
+       * mm-uu.el Don't require message.  Require cl when compiling.
+
+2000-06-17 18:58:46  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-local-variables): gnus-orphan-score is
+       a local variable.
+       * gnus-sum.el (gnus-orphan-score): Move here.
+
+2000-06-10 09:33:36  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-forward): Remove show-mml condition.
+       (message-forward-ignored-headers): Remove X-Gnus headers.
+
+2000-06-08  Simon Josefsson  <simon@josefsson.org>
+
+       * gnus-cus.el (gnus-extra-group-parameters): Add uidvalidity.
+
+2000-06-08 12:34:26  Urban Engberg  <ue@ccieurope.com>
+
+       * gnus-demon.el (gnus-demon-scan-mail): Bind nnmail-fetched-sources.
+
+2000-06-08 12:27:55  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-syntax-checks): Add type.
+
+2000-06-07  Dave Love  <fx@gnu.org>
+
+       * mm-view.el (mm-inline-image-emacs): Don't specify string for
+       put-image.
+       (mm-inline-image): Defalias, not fset.
+
+       * gnus.el (gnus-group-startup-message): Don't specify string for
+       insert-image.
+
+       * gnus-ems.el (gnus-add-minor-mode): Make it an alias if
+       add-minor-mode is available.
+       (gnus-article-display-xface): Don't specify string for
+       insert-image.
+
+2000-06-06 13:28:53  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-topic.el (gnus-topic-remove-topic): Set hidden.
+       (gnus-topic-insert-topic-line): Use shownp.
+       (gnus-topic-hide-topic): Don't use hidden.
+       (gnus-topic-show-topic): Don't use hidden.
+
+2000-06-05 22:25:12  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-cache.el (gnus-cache-possibly-enter-article): Bind coding
+       system.
+       * gnus-soup.el (gnus-soup-write-prefixes): Ditto.
+       * gnus-start.el (gnus-slave-save-newsrc): Ditto.
+       * gnus-util.el (gnus-output-to-rmail): Ditto.
+       (gnus-output-to-mail): Ditto.
+       (gnus-write-buffer): Ditto.
+       * gnus-uu.el (gnus-uu-save-article): Ditto.
+
+2000-06-04 15:05:16  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-read-from-minibuffer): Typo.
+
+2000-06-03 13:36:46  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-decode-charset): Override non-MIME forward
+       charset.
+
+2000-06-02 12:04:26  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-quote-region): Correct the regexp.
+       * gnus-msg.el (gnus-summary-reply): mml-quote it.
+
+2000-06-02 11:57:15  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-forward): Insert raw text.
+       * mml.el (mml-parse-1): Get raw text in unibyte mode.
+       (mml-generate-mime-1): Insert raw text in unibyte mode.
+
+2000-06-01  Florian Weimer  <fw@deneb.cygnus.argh.org>
+
+       * mm-bodies.el (mm-body-encoding): Always encoded if
+       `mm-use-ultra-safe-encoding' is set.
+
+2000-05-31 14:50:52  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (ange-ftp-name-format): Typo.
+
+2000-05-30  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-start.el (gnus-get-unread-articles): If
+       `gnus-activate-group' and/or `gnus-check-server' return nil, don't
+       try to do anything on that server.
+
+2000-05-25  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-group.el (gnus-group-nnimap-edit-acl): Help text updated
+       from latest draft.
+
+2000-05-08  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-group.el (gnus-group-expire-articles-1): Make sure server
+       is open.
+
+2000-05-24  Dave Love  <fx@gnu.org>
+
+       * mml.el (mml-parse-file-name): Fix ange-ftp part.
+
+2000-05-22  Didier Verna  <didier@lrde.epita.fr>
+
+       * gnus.el (gnus-redefine-select-method-widget): new function, call
+       it once. Add an "other" entry for unknown but editable backend
+       name symbols.
+       * gnus-start.el (gnus-declare-backend): use it.
+
+2000-05-19  Dave Love  <fx@gnu.org>
+
+       * gnus-art.el (gnus-article-next-page): Revert last change.
+
+2000-05-19 09:56:07  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-open-history): Open history in binary mode.
+
+2000-05-19  Dave Love  <fx@gnu.org>
+
+       * gnus-art.el (gnus-mime-externalize-part): Bind mm-inlined-types,
+       not mm-inline-large-images.
+
+2000-05-19 01:45:40  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-parse-1): Don't test multiple-charsets within mml tag.
+
+2000-05-18  Dave Love  <fx@gnu.org>
+
+       * gnus-art.el: Use defalias, not fset.
+       (gnus-article-x-face-command): Don't test for xbm.
+       (gnus-article-next-page): Redisplay before testing point in window.
+
+2000-05-17 21:16:54  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-mode-map): Add M-SPACE.
+       * mml.el (mml-mode-map): Comment out mml-narrow-to-part.
+
+2000-05-17 21:13:38  Jim Davidson  <jdavidson@acm.org>
+
+       * gnus-sum.el (gnus-summary-save-article-rmail): Use
+       gnus-summary-save-in-rmail.
+       * message.el (message-output): Ditto.
+
+2000-05-17 22:37:25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-emphasize-whitespace-regexp): Doc fix.
+
+2000-05-17 14:03:49  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-encode-message-header): Encode if the method
+       is a charset.
+       * message.el (message-send-news): Check group name charset.
+       * gnus-msg.el (gnus-post-news): Decode group name.
+       (gnus-inews-do-gcc): Encode group name.
+
+2000-05-17 10:16:32  Karl Kleinpaste  <karl@charcoal.com>
+
+       * gnus-art.el (gnus-emphasize-whitespace-regexp): New variable.
+       * gnus-util.el (gnus-put-text-property-excluding-newlines): Use it.
+
+2000-05-17 02:25:11  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-mark-line-p): New function.
+       (gnus-group-goto-group): New parameter.
+       (gnus-group-remove-mark): Use it.
+       * gnus-topic.el (gnus-topic-move-group): Ditto.
+       (gnus-topic-remove-group): Ditto.
+
+2000-05-17 00:49:09  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-list-dormant): New function.
+
+2000-05-16 23:20:42  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-synchronize): Use
+       nnheader-insert-file-contents.
+       (gnus-agent-save-active-1): Ditto.
+       (gnus-agent-write-active): Ditto.
+       (gnus-agent-expire): Ditto.
+       * gnus-cache.el (gnus-cache-read-active): Ditto.
+       * gnus-start.el (gnus-master-read-slave-newsrc): Ditto.
+       * gnus-sum.el (gnus-summary-import-article): Ditto.
+
+       * gnus-agent.el (gnus-agent-write-servers): Bind coding-system.
+       (gnus-agent-save-group-info): Ditto.
+       (gnus-agent-save-alist): Ditto.
+       * gnus-util.el (gnus-make-directory): Ditto.
+
+       * gnus-agent.el (gnus-agent-save-group-info): Disable multibyte.
+
+2000-05-16 21:13:24  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-generate-mime-preprocess-function): New variable.
+       (mml-generate-mime-postprocess-function): New variable.
+       (mml-generate-mime-1): Use them.
+
+2000-05-16 18:15:24  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-apropos): Group name charset.
+       * gnus-sum.el (gnus-set-mode-line): Ditto.
+       * gnus-group.el (gnus-group-decoded-name): New function.
+       (gnus-group-edit-group): Use it.
+       * gnus-cus.el (gnus-group-customize): Use it.
+
+2000-05-16 17:55:57  Karl Kleinpaste  <karl@charcoal.com>
+
+       * gnus-util.el (gnus-put-text-property-excluding-newlines): Improve.
+
+2000-05-16 16:22:17  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-name-charset-method-alist): New variable.
+       (gnus-group-name-charset-group-alist): Ditto.
+       (gnus-group-name-charset): New function.
+       (gnus-group-name-decode): New function.
+       (gnus-group-insert-group-line): Use them.
+       (gnus-group-prepare-flat-list-dead): Ditto.
+       (gnus-group-list-active): Ditto.
+       (gnus-group-describe-all-groups): Ditto.
+       (gnus-group-prepare-flat-list-dead-predicate): Ditto.
+       * gnus-srvr.el (gnus-browse-foreign-server): Decode group name and
+       add gnus-group property.
+       (gnus-browse-group-name): Read gnus-group property.
+
+2000-05-16 15:27:08  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnfolder.el (nnfolder-possibly-change-group): Use
+       file-name-coding-system instead of pathname-coding-system.
+       * nnmail.el (nnmail-find-file): Ditto.
+       (nnmail-write-region): Ditto.
+       * nnmh.el (nnmh-retrieve-headers): Ditto.
+       (nnmh-request-article): Ditto.
+       (nnmh-request-group): Ditto.
+       (nnmh-request-list): Ditto.
+       (nnmh-possibly-change-directory): Ditto.
+       (nnmh-active-number): Ditto.
+       * nnml.el (nnml-possibly-change-directory): Ditto.
+       (nnml-request-list): Ditto.
+       (nnml-request-article): Ditto.
+       (nnml-retrieve-headers): Ditto.
+
+2000-05-16  Simon Josefsson  <jas@pdc.kth.se>
+
+       * nnimap.el (nnimap-request-accept-article): Don't unselect
+       mailbox if no mailbox is selected.
+
+2000-05-15  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus-art.el (gnus-button-url-regexp): Revert earlier change.
+       Recognize domain names starting with `www.' as starting an URL.
+
+2000-05-15 09:46:47  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mail-source.el (mail-source-fetch-maildir): Insert "From ".
+       (mail-source-keyword-map): Add "subdirs" for maildir.
+
+2000-05-14 16:19:28  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnmail.el (nnmail-scan-directory-mail-source-once): New variable.
+       (nnmail-get-new-mail): Use it.
+       * gnus-start.el (gnus-get-unread-articles): Ditto.
+
+2000-05-14 14:02:12  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-edit-article): Better support for
+       nndraft:drafts.
+       * nndraft.el (nndraft-request-replace-article): New function,
+       bind nnmail-file-coding-system.
+
+2000-05-14  Dave Love  <fx@gnu.org>
+
+       * nnheader.el: Replace uses of `fset' with `defalias'.
+       (jka-compr-compression-info-list): Only defvar when compiling.
+
+2000-05-14 12:30:28  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el (webmail-netaddress-article): Refresh redirect.
+
+2000-05-13 20:41:10  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-view.el (mm-inline-text): w3 might not recognize utf-8.
+
+2000-05-13 16:49:41  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el: Translate &nbsp; to SP.
+
+2000-05-13 13:00:17  Robin S. Socha  <robin@socha.net>
+
+       * message.el (message-bounce): Doc typo.
+
+2000-05-13 12:25:21  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-soup.el (gnus-soup-encoding-type): u is USENET news format.
+       (gnus-soup-store): Ditto.
+       (gnus-soup-send-packet): Ditto.
+       * nnsoup.el (nnsoup-replies-format-type): Ditto.
+       (nnsoup-dissect-buffer): Ditto.
+       (nnsoup-narrow-to-article): Ditto.
+       (nnsoup-make-active): Ditto.
+
+2000-05-13 12:03:29  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-mode): Two parameters for local-variable-p.
+
+2000-05-13 00:54:46  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-strip-list-identifiers): New function.
+       (message-reply): Use it and use message-strip-subject-re.
+       (message-followup): Ditto.
+       * gnus-art.el (article-hide-list-identifiers): Remove more.
+       * gnus-sum.el (gnus-summary-remove-list-identifiers): Ditto.
+
+2000-05-12 22:28:54  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-uu.el (gnus-uu-digest-mail-forward): Bind
+       mail-parset-charset and use non-numeric argument.
+
+2000-05-12 20:54:11  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-buffer-list): New variable.
+       (mml-generate-new-buffer): New function.
+       (mml-destroy-buffers): Ditto.
+       (mml-insert-mime): Use them.
+       * gnus-msg.el (gnus-setup-message): mml-buffer leaks.
+       * gnus-sum.el (gnus-summary-edit-article): Ditto.
+       * message.el (message-mode): Ditto.
+       * gnus-uu.el (gnus-uu-digest-headers): Keep MIME headers.
+       (gnus-uu-save-article): Support show-as-mml.
+       * message.el (message-forward): Ditto.
+
+2000-05-12 15:15:55  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nndoc.el (nndoc-type-alist): mime-digest head-begin.
+       (nndoc-mime-digest-type-p): Locate article head precisely.
+       * mml.el (mml-generate-default-type): New variable.
+       (mml-generate-mime-1): Use it.
+       (mml-insert-mime-headers): Use it.
+       * gnus-uu.el (gnus-uu-digest-buffer): New variable.
+       (gnus-uu-digest-mail-forward): Use it and call message-forward
+       with argument digest.
+       (gnus-uu-save-article): Support message-forward-as-mime.
+       * message.el (message-forward): Add parameter digest.
+       * mm-decode.el (mm-dissect-default-type): New variable.
+       (mm-dissect-buffer): Use it.
+
+2000-05-11 11:08:03  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-parse-singlepart-with-multiple-charsets): Set space,
+       newline and paragraph to nil when got a non-ascii character. Test
+       paragraph before newline.
+
+2000-05-10 12:17:58  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * qp.el (quoted-printable-encode-region): Bind tab-width to 1. Set
+       limit to 76.
+
+2000-05-10 09:11:48  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnslashdot.el (nnslashdot-sid-strip): New function.
+       (nnslashdot-threaded-retrieve-headers): New format.
+       (nnslashdot-sane-retrieve-headers): Ditto.
+       (nnslashdot-request-article): Ditto.
+       (nnslashdot-threaded-retrieve-headers): Thread properly.
+       (nnslashdot-request-article): Be more lenient.
+       (nnslashdot-threaded-retrieve-headers): Regexp search.
+
+2000-05-09 13:23:50  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-with-article): Define it before use it.
+
+2000-05-08 22:34:19  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-supersede): Use mime-to-mml.
+       * mm-decode.el (mm-insert-part): Test the buffer if no encoding.
+
+2000-05-08 22:34:24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el (gnus-group-list-cached): Don't use
+       `subst-char-in-string'.
+
+2000-05-08  Dave Love  <fx@gnu.org>
+
+       * pop3.el (pop3-open-server): Fix creating name of trace buffer.
+
+2000-05-08 01:07:47  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-interactively-view-part): Append %s if the
+       method is a single word.
+       * nnwarchive.el (nnwarchive-type-definition): Typo.
+
+2000-05-07 17:24:01  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-prepare-flat-list-dead-predicate): New
+       function.
+       (gnus-group-prepare-flat-predicate): Use it.
+       (gnus-group-list-cached): List dead groups.
+
+2000-05-07 10:50:02  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-decode-charset): Don't decode message with
+       format.
+
+2000-05-07  Florian Weimer  <fw@deneb.cygnus.argh.org>
+
+       * mailcap.el (mailcap-maybe-eval): Honor user request not to
+       evaluate the Lisp code.
+
+2000-05-06 17:40:20  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-wash-html): New function.
+       (gnus-article-wash-html): Bind.
+       (gnus-article-make-menu-bar): Menu item.
+       * gnus-sum.el (gnus-summary-wash-map): Bind 'h'.
+       (gnus-summary-make-menu-bar): Menu item.
+       * gnus.el: Autoload.
+
+2000-05-06  Florian Weimer  <fw@deneb.cygnus.argh.org>
+
+       * gnus-uu.el (gnus-uu-unshar-warning): New variable.
+       (gnus-uu-unshar-article): Use it.
+
+       * mailcap.el (mailcap-maybe-eval-warning): New variable.
+       (mailcap-maybe-eval): Use it.
+
+       * gnus-msg.el (gnus-group-posting-charset-alist): Speling mistake
+       in docstring.
+
+       * mml.el (mml-generate-mime-1): Small comment.
+
+2000-05-05 12:27:53  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-de-base64-unreadable): New function.
+       (gnus-article-de-base64-unreadable): Bind.
+       (gnus-article-make-menu-bar): Menu item.
+       * gnus-sum.el (gnus-summary-wash-map): Bind '6' and 'Z'.
+       (gnus-summary-make-menu-bar): Menu item.
+       * gnus.el: Autoload.
+
+2000-05-05 10:32:27  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-show-article): Remove en/disable multibyte.
+       (gnus-summary-select-article): Add en/disable multibyte.
+
+2000-05-05 02:47:23  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-edit-article): Enable multibyte.
+       (gnus-summary-edit-article): New feature: editing raw articles.
+
+2000-05-05 00:30:12  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-encode-region): Insert a space before encoding.
+       Emacs MULE can not encode adjacent iso-2022-jp and cn-gb-2312.
+       * gnus-msg.el (gnus-summary-mail-forward): Use unibyte buffer.
+       Emacs MULE can not copy some 8bit characters in multibyte buffers.
+       * mm-decode.el (mm-insert-part): Ditto.
+
+2000-05-04 17:49:04  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nndoc.el (nndoc-type-alist): Extend forward regexp.
+       (nndoc-forward-type-p): Ditto.
+
+2000-05-04 17:13:04  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-with-unibyte-current-buffer): Set the default
+       value of enable-multibyte-characters.
+
+2000-05-04 10:31:24  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-show-article): En/disable multibyte.
+
+2000-05-03  Dave Love  <fx@gnu.org>
+
+       * gnus-ems.el (gnus-article-xface-ring-internal)
+       (gnus-article-xface-ring-size): New variable.
+       (gnus-article-display-xface): Use them to cache data.  Don't try
+       to use XPM.  Set up binary coding for PBM's sake.
+
+2000-05-03 14:23:38  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-inews-do-gcc): Set mail-parse-charset.
+       * gnus-int.el (gnus-request-accept-article): Ditto.
+       (gnus-request-replace-article): Ditto.
+       * mm-util.el (mm-mime-mule-charset-alist): Add a fake mule-charset.
+
+2000-05-03 14:11:23  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-encode): Test the validity of coding-system.
+
+2000-05-03 11:35:15  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-encode-message-header): Encode field by
+       field.
+       * mml.el (mml-to-mime): Use message-default-charset.
+       (mml-preview): Narrow to headers.
+       * message.el (message-send-mail): Use message-default-charset.
+       (message-send-news): Narrow to headers;
+       use message-default-charset.
+
+2000-05-03 08:09:14  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding): A better junk
+       detect.
+       * mml.el (mml-parse-singlepart-with-multiple-charsets): Save
+       restriction.
+       (mml-parse-1): Warning message.
+       (mml-preview): Disable multibyte.
+
+2000-05-03  Dave Love  <fx@gnu.org>
+
+       * gnus.el (gnus-group-startup-message): Add newline before image.
+
+2000-05-02 21:34:10  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-encode-message-header): Check the coding-system.
+       * message.el (message-send-mail): Use unibyte-buffer.
+       (message-send-mail): Ditto.
+
+Mon May  1 15:09:46 2000  Lars Magne Ingebrigtsen  <lmi@quimbies.gnus.org>
+
+       * gnus.el: Gnus v5.8.6 is released.
+
+2000-05-01 07:45:43  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-parse-1): Set no-markup-p and warn to nil.
+
+2000-04-28 21:14:21  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-q-encoding-alist): Encode HTAB.
+
+2000-04-28 16:37:09  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-send-mail-partially): Use forward-line.
+
+2000-04-28 16:01:09  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-button-menu): Use call-interactively.
+
+2000-04-28 15:30:17  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-generate-mime-1): Ignore 0x1b.
+       (mml-insert-mime): No markup only for text/plain.
+       (mime-to-mml): Remove MIME headers.
+
+2000-04-28 14:23:14  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-preview): Set gnus-newsgroup-charset.
+       * rfc2047.el (rfc2047-encode-message-header): Encode non-ascii
+       as 8-bit.
+       * lpath.el: Fbind image functions.
+
+2000-04-28  Dave Love  <fx@gnu.org>
+
+       * gnus.el (gnus-group-startup-message): Maybe use image in Emacs
+       21.
+
+       * mailcap.el (mailcap-parse-mailcaps): Revert last change to
+       search order.  Use parse-colon-path and remove some redundancy.
+       Doc fix.
+       (mailcap-parse-mimetypes): Code consistently with
+       mailcap-parse-mailcaps.  Doc fix.
+
+       * gnus-start.el (gnus-unload): Iterate over `features', not
+       `load-history'.
+
+2000-04-28 09:52:21  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-parse-1): Don't create blank parts.
+       (mml-read-part): Fix mml tag.
+       (mml-insert-mime): Convert message/rfc822.
+       (mml-insert-mml-markup): Add mmlp parameter.
+
+2000-04-28 01:16:10  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-send-mail-partially): Remove CTE.
+
+2000-04-28 00:31:53  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * lpath.el: Fbind put-image for XEmacs.
+       * mm-view.el (mm-inline-image): Fset it.
+
+2000-04-27 23:23:37  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nndoc.el (nndoc-type-alist): Change forward regexp.
+
+2000-04-27 21:57:10  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-send-mail-partially-limit): Change the
+       default value.
+
+2000-04-27 21:53:32  Erik Toubro Nielsen  <erik@ifad.dk>
+
+       * gnus-util.el (gnus-extract-address-components): Name might be
+       "".
+
+2000-04-27 20:32:06  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-summary-mail-forward): Use ARG.
+       (gnus-summary-post-forward): Ditto.
+       * message.el (message-forward-show-mml): New variable.
+       (message-forward): Use it.
+       * mml.el (mml-parse-1): Add tag mml.
+       (mml-read-part): Ditto.
+       (mml-generate-mime): Support reentance.
+       (mml-generate-mime-1): Support mml tag.
+
+2000-04-27  Dave Love  <fx@gnu.org>
+
+       * gnus-art.el: Don't bother to require custom, browse-url.
+       (gnus-article-x-face-command): Include gnus-article-display-xface.
+
+       * gnus-ems.el: Assume only (X)Emacs 20+.  Simplify XEmacs checks.
+       Use defalias, not fset.
+       (gnus-article-display-xface): New function.
+
+       * mm-view.el (mm-inline-image-emacs): Use put-image, remove-images.
+
+       * mm-decode.el: Small doc fixes.  Require cl when compiling.
+       (mm-xemacs-p): Deleted.
+       (mm-get-image-emacs, mm-get-image-xemacs): Deleted.
+       (mm-get-image): Amalgamate Emacs and XEmacs code here; for Emacs,
+       use create-image and don't special-case xbm.
+       (mm-valid-image-format-p): Use display-graphic-p.
+
+2000-04-27 15:27:54  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-send-mail-partially-limit): New variable.
+       (message-send-mail-partially): New function.
+       (message-send-mail): Use it.
+       * mm-bodies.el (mm-decode-content-transfer-encoding): Remove
+       all blank lines inside of base64.
+       * mm-partial.el (mm-inline-partial): Add an option. Remove tail
+       blank lines.
+
+2000-04-27 10:03:36  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-insert-tag): Match more special characters.
+
+2000-04-27 09:06:29  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-bug): Avoid attaching the external buffer.
+
+2000-04-27 00:58:43  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-inline-media-tests): Add message/partial.
+       (mm-inlined-types): Ditto.
+       * mm-partial.el: New file.
+
+2000-04-27  Dave Love  <fx@gnu.org>
+
+       * mailcap.el (mailcap-mime-data): Fix octet-stream syntax -- might
+       matter in Emacs 21.
+
+2000-04-26  Florian Weimer  <fw@deneb.cygnus.argh.org>
+
+       * mm-bodies.el (mm-encode-body): Remove reference to
+       mm-default-charset in comment.
+
+2000-04-24 00:56:00  Björn Torkelsson  <torkel@hpc2n.umu.se>
+
+       * rfc2047.el (rfc2047-encode-message-header): Fixing typo.
+
+2000-04-26 12:27:41  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-draft.el (gnus-draft-send): Move gnus-draft-setup inside of
+       let.
+
+2000-04-26 12:26:10  Pavel Janik ml.  <Pavel.Janik@inet.cz>
+
+       * gnus-draft.el (gnus-draft-setup): Fix comments.
+
+2000-04-26 10:06:12  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnmbox.el (nnmbox-create-mbox): Use nnmbox-file-coding-system,
+       if nnmbox-file-coding-system-for-write is nil.
+
+2000-04-26 02:17:44  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-configure-posting-styles): Just remove the
+       header if nil.
+
+2000-04-26 00:23:46  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-view.el (mm-inline-text): Insert directly if decoded.
+       * mml.el (autoload): Typo.
+
+2000-04-25 22:46:36  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-preview): Set up posting-charset.
+       * gnus-msg.el (gnus-group-posting-charset-alist): Add koi8-r.
+
+2000-04-25 21:23:54  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el: Fix yahoo mail.
+
+2000-04-25 20:12:17  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-dissect-region): Don't include LWS ahead of
+       word if not necessary.
+       (rfc2047-encode-region): Put space between encoded words.
+
+2000-04-24 21:11:48  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-util.el (gnus-netrc-machine): Another default to nntp.
+
+2000-04-24 18:14:12  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-draft.el (gnus-draft-setup): Restore mml only when
+       required.
+       (gnus-draft-edit-message): Require restoration.
+
+2000-04-24 16:51:04  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-score.el (gnus-score-headers): Copy gnus-newsgrou-scored
+       back.
+
+2000-04-24 16:01:15  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-treat-article): Make sure that the summary
+       buffer is live.
+
+2000-04-24 15:42:53  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mailcap.el (mailcap-parse-mailcaps): Reorder.
+       (mailcap-parse-mailcap): Backwards parsing.
+       (mailcap-possible-viewers): Remove nreverse.
+       (mailcap-mime-info): Ditto.
+       (mailcap-add-mailcap-entry): Keep alternative viewer.
+
+Mon Apr 24 21:12:06 2000  Lars Magne Ingebrigtsen  <lmi@quimbies.gnus.org>
+
+       * gnus.el: Gnus v5.8.5 is released.
+
+2000-04-24 16:29:07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * rfc2047.el (rfc2047-header-encoding-alist): Doc fix.
+
+       * gnus-util.el (gnus-netrc-machine): Default to nntp.
+
+       * mml.el (mml-generate-mime-1): Force 8bit on message/rfc822.
+
+2000-04-23 23:27:25  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-view.el (mm-inline-message): Disable prepare-hook.
+
+2000-04-23 00:32:32  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el: Fix copyright statements.
+
+       * gnus-sum.el (gnus-alter-articles-to-read-function): New
+       variable.
+       (gnus-articles-to-read): Use it.
+
+       * message.el (message-get-reply-headers): Bind free variable.
+
+2000-04-23 01:14:28  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-get-reply-headers): Fix to-address.
+
+2000-04-22 22:51:46  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el: Hotmail fix. Add a debug function.
+
+2000-04-23 00:32:32  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (t): M-down and M-up.
+
+2000-04-22 20:22:03  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-sum.el: Doc fix.
+
+2000-04-22 10:25:56  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnwarchive.el (nnwarchive-egroups-article): Remove < and >.
+
+2000-04-22 14:25:05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnweb.el (nnweb-dejanews-create-mapping): Remove the context
+       string.
+       (nnweb-request-group): Don't scan twice.
+       (nnweb-request-scan): Don't nix out the hashtb.
+
+       * message.el (message-get-reply-headers): Return a value.
+
+2000-04-22 14:12:41  David Aspinwall  <aspinwall@TimesTen.com>
+
+       * gnus-art.el (gnus-button-url-regexp): New value to match naked
+       urls.
+
+2000-04-22 01:23:59  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-cache.el (gnus-summary-insert-cached-articles): Reverse the
+       order messages are inserted.
+
+       * mml.el (mml-generate-mime-1): rfc2047-encode the heads of
+       message/rfc822 parts.
+
+       * gnus-art.el (gnus-article-read-summary-keys): Check for
+       numerical values.
+
+       * message.el (message-get-headers): Made into own function.
+       (message-reply): Use it.
+       (message-get-reply-headers): Renamed.
+       (message-widen-reply): New command.
+
+2000-04-21 20:52:09  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nntp.el (nntp-retrieve-data): Report the error and return nil.
+
+2000-04-21 19:38:43  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding): Don't remove
+       non-base64 text at the end if not found.
+
+2000-03-01  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-sum.el (gnus-read-move-group-name):
+       (gnus-summary-move-article): Use `gnus-group-method' to find out
+       what method the manually entered group belong to.
+       `gnus-group-name-to-method' doesn't return any method parameters
+       and `gnus-find-method-for-group' uses `gnus-group-name-to-method'
+       for new groups so they wouldn't work.
+
+2000-04-21 22:27:15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-configure-posting-styles): Allow nil values to
+       override.
+
+2000-04-21 21:58:20  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * nnmail.el (nnmail-cache-insert): Does some stuff that is
+       probably good to do, or something.  I dunno.  I just write these
+       ChangeLog entries, and my name is Lars.
+
+1999-12-06  Hrvoje Niksic  <hniksic@iskon.hr>
+
+       * message.el (message-caesar-region): Use translate-region.
+
+2000-04-21 21:20:32  Mike Fabian  <mike.fabian@gmx.de>
+
+       * gnus-group.el (gnus-group-catchup-current): Doc fix.
+
+2000-04-21 20:36:21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-setup-buffer): Don't kill local
+       variables, because that makes Emacs flash.
+
+       * gnus-group.el (gnus-group-insert-group-line): Don't call
+       gnus-group-add-icon unconditionally.
+
+       * gnus-xmas.el (gnus-group-add-icon): Moved here.
+
+       * gnus-group.el (gnus-group-glyph-directory): Don't depend on
+       xmas.
+       (gnus-group-glyph-directory): Removed.
+
+2000-04-21 20:26:23  Jaap-Henk Hoepman  <hoepman@cs.utwente.nl>
+
+       * gnus-msg.el (gnus-inews-insert-archive-gcc): Don't do stuff if
+       gnus-newsgroup-name is "".
+
+2000-04-21  Florian Weimer  <fw@deneb.cygnus.argh.org>
+
+       * mm-util.el (mm-mime-mule-charset-alist): Add support for UTF-8
+       in conjunction with MULE-UCS.
+
+1999-12-13  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * rfc2047.el (rfc2047-fold-region): Don't use the same break twice.
+
+1999-12-14 04:14:44  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (last, mapcon, member-if, union): New compiler
+       macros for emulating cl functions.
+
+1999-12-21  Jan Vroonhof  <vroonhof@math.ethz.ch>
+
+       * message.el (message-shorten-references): Only cater to broken
+       INN for news. This caters for broken smtpd.
+
+2000-04-21 18:20:10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mailcap.el (mailcap-mime-info): Use the first match; not the
+       last.
+
+       * gnus-agent.el (gnus-category-kill): Save the category list.
+
+2000-04-21 16:41:50  Chris Brierley  <brierley@pobox.com>
+
+       * gnus-sum.el (gnus-summary-move-article): Do something or other.
+
+2000-04-21 16:07:07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-add-icon): Fixed indentation.
+
+2000-04-21 16:07:07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-add-icon): Fixed indentation.
+
+2000-04-21 10:43:16  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-prepare-flat-predicate): New function.
+       (gnus-group-list-cached): Use it.
+
+2000-04-21 16:07:07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el: Update all the copyright notices.
+
+2000-04-21 15:38:06  Vladimir Volovich  <vvv@vvv.vsu.ru>
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding): Remove
+       non-base64 text at the end.
+
+2000-04-21 15:21:30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-bodies.el (mm-body-charset-encoding-alist): defcustomized.
+
+2000-04-21 15:15:41  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnheader.el: Don't autoload cancel-function-timers.
+
+       * message.el (message-fetch-field): Fold case.
+
+2000-04-21 15:11:09  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * message.el (message-forward-before-signature): New variable.
+
+2000-04-21 15:10:31  Alexandre Oliva  <oliva@lsd.ic.unicamp.br>
+
+       * gnus-mlspl.el: Fix stuff.
+
+2000-04-21 14:41:09  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-update-article-line): Don't hide
+       subjects when unthreaded.
+
+2000-04-21 14:11:39  David S. Goldberg  <dsg@mitre.org>
+
+       * gnus-art.el (gnus-boring-article-headers): Work on long CCs as
+       well.
+
+2000-04-21 14:06:43  Rui Zhu  <sprache@iname.com>
+
+       * gnus-art.el (gnus-article-mode): Fix variable name.
+
+2000-04-21 13:54:51  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-view.el: Fix autoload.
+
+       * flow-fill.el (flow-fill): Fix provide.
+
+       * gnus-draft.el (gnus-draft-send): Bind message-setup-hook to
+       nil.
+
+2000-04-20 22:24:04  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-win.el (gnus-configure-windows): Revert to switch-to-buffer.
+
+2000-04-21 05:22:18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-netrc-machine): Didn't work.
+
+2000-04-20 21:22:10  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-draft.el (gnus-draft-setup): Restore to mml.
+
+2000-04-21 01:24:41  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * flow-fill.el: Renamed from fill-flowed.
+
+       * message.el (message-forward-ignored-headers): Default to
+       removing CTE.
+
+2000-04-21 00:48:48  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * message.el (message-mode): Don't fill headers.
+
+2000-04-20 23:12:43  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-pipe-buffer-body): Use shell.
+
+2000-02-21  Yoshiki Hayashi  <yoshiki@xemacs.org>
+
+       * nnvirtual.el (nnvirtual-request-article):
+       Bind gnus-override-method to nil.
+       (nnvirtual-request-update-mark): Don't update mark when
+       article is not there.
+
+2000-04-20 16:35:41  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-uu.el (mm-uu-dissect): Check forwarded message.
+
+2000-04-20 21:17:48  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-util.el (gnus-parse-netrc): Allow "port".
+       (gnus-netrc-machine): Take a port param.
+       (gnus-netrc-machine):
+
+       * gnus-art.el (gnus-request-article-this-buffer): Allow
+       re-selecting referenced articles.
+
+       * message.el (message-cancel-news): Allow editing.
+       (message-cancel-message): Add newline.
+
+2000-04-20 21:03:54  William M. Perry  <wmperry@aventail.com>
+
+       * mm-view.el (mm-inline-image-emacs): New function.
+
+2000-04-20 20:44:55  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-delete-incoming): Change default in
+       cvs.
+
+2000-04-20 20:43:34  Kim-Minh Kaplan  <kmkaplan@vocatex.fr>
+
+       * gnus-art.el (gnus-mime-view-part-as-type-internal): New
+       function.
+
+2000-04-20 14:45:20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnml.el (nnml-request-expire-articles): Use it.
+
+       * nnmail.el (nnmail-expiry-target): New variable.
+       (nnmail-expiry-target-group): New function.
+
+2000-04-20 02:36:31  Emerick Rogul  <emerick@cs.bu.edu>
+
+       * message.el (message-forward): Add non-MIME separators.
+
+2000-04-20 02:25:39  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-generate-headers): Respect the syntax check
+       spec.
+
+       * gnus-sum.el (gnus-remove-thread-1): Show thread.
+       (gnus-remove-thread): Don't show all threads.
+
+Thu Apr 20 01:39:25 2000  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v5.8.4 is released.
+
+2000-04-19  Dave Love  <fx@gnu.org>
+
+       * mailcap.el (mailcap-parse-mimetypes): Add ...mime.types.
+
+2000-04-18 12:28:24  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnwarchive.el (nnwarchive-type-definition): New egroups html.
+       (nnwarchive-egroups-*): Ditto.
+       (nnwarchive-url): Unibyte buffer and single line cookie.
+
+2000-04-14 18:50:04  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-char-or-char-int-p): New alias.
+       * nnweb.el (nnweb-decode-entities): Check the validity of numeric
+       entities.
+
+2000-04-10  Daiki Ueno  <ueno@unixuser.org>
+
+       * imap.el (imap-body-lines): Check Content-Type: of the article case
+       insensitively.
+
+2000-04-10 20:35:46  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mail-source.el (mail-source-fetch-webmail): Use the default
+       password provided in mail-sources; use webmail:subtype:user as
+       the key.
+
+2000-04-10 20:35:46  John Wiegley  <johnw@gnu.org>
+
+       * mail-source.el (mail-source-fetch-webmail): Use
+       mail-source-password-cache.
+
+2000-04-09 18:13:47  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el: Add netscape mail and fix HotMail mail.
+
+2000-04-08  Simon Josefsson  <jas@pdc.kth.se>
+
+       * imap.el (imap-kerberos4-open): Work with recent `imtest's.
+
+2000-04-02  Simon Josefsson  <jas@pdc.kth.se>
+
+       * nnimap.el (nnimap-request-article): Use BODY.PEEK[] instead of
+       RFC822.PEEK if server support IMAP4rev1.
+       (nnimap-request-body): Use BODY.PEEK[TEXT] instead of
+       RFC822.TEXT.PEEK if server support IMAP4rev1.
+       (nnimap-request-head): Use BODY.PEEK[HEADER] instead of
+       RFC822.HEADER if server support IMAP4rev1.
+       (nnimap-request-article-part): Support bodydetail in response
+       data.
+
+2000-03-11  Simon Josefsson  <jas@pdc.kth.se>
+
+       * fill-flowed.el: New file.
+
+       * mm-decode.el (mm-dissect-singlepart): Create a MIME handle for
+       text/plain parts with `format' parameters.
+
+       * mm-view.el (autoload): Autoload fill-flowed.
+       (mm-inline-text): For "plain" parts with a format=flowed
+       parameter, call `fill-flowed'.
+
+2000-03-21 10:32:44  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnslashdot.el (nnslashdot-request-list): Fudge new-style
+       slashdot ids.
+
+2000-03-20 00:12:42  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnslashdot.el (nnslashdot-request-list): Use the new slashdot
+       format.
+
+2000-03-16  Simon Josefsson  <jas@pdc.kth.se>
+
+       * imap.el: GSSAPI support, support kerberos 4 with Cyrus v1.6.x
+       `imtest' too.
+       (imap-kerberos4-program): Renamed from `imap-imtest-program'.
+       (imap-gssapi-program): New variable.
+       (imap-streams): Add gssapi.
+       (imap-stream-alist): Ditto.
+       (imap-authenticators): Ditto.
+       (imap-authenticator-alist): Ditto.
+       (imap-kerberos4-stream-p): Rename from `imap-kerberos4s-p'.
+       (imap-kerberos4-open): Loop over imtest programs, support Cyrus
+       1.6.x `imtest' syntax.
+       (imap-gssapi-stream-p): New function.
+       (imap-gssapi-open): Ditto.
+       (imap-gssapi-auth-p): Ditto.
+       (imap-gssapi-auth): Ditto.
+       (imap-kerberos4-auth-p): Renamed from `imap-kerberos4a-p'.
+       (imap-send-command): Use buffer-local `imap-client-eol' value.
+
+       * nnimap.el (nnimap-retrieve-headers-progress): Fold continuation
+       lines and turn TAB into SPC before parsing.
+
+2000-03-15  Simon Josefsson  <jas@pdc.kth.se>
+
+       * nnheader.el (nnheader-group-pathname): Make sure to return a
+       directory.
+       * nnmail.el (nnmail-group-pathname): Ditto.
+
+2000-02-08  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * nnmail.el (nnmail-fix-eudora-headers): Fix `In-Reply-To' too, it
+       might split in the middle of a message-id.
+
+2000-03-13 13:51:38  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-srvr.el (gnus-server-kill-server): Offer to kill all the
+       groups from the server.
+
+       * gnus-sum.el (gnus-summary-save-parts): Fix interactive spec.
+       (gnus-summary-toggle-header): Update the wash status.
+
+       * gnus-uu.el ((gnus-uu-extract-map "X" gnus-summary-mode-map)):
+       Moved here.
+
+       * gnus-agent.el (gnus-agent-save-group-info): Respect old
+       setting.
+
+       * nnmail.el (nnmail-get-active): Use it.
+       (nnmail-parse-active): New function.
+
+       * mm-view.el (mm-inline-text): Support the new version of
+       vcard.el.
+
+       * gnus-sum.el (gnus-summary-move-article): Only delete article
+       when moving junk.
+       (gnus-deaden-summary): Bury the buffer.
+
+       * nnmail.el (nnmail-group-pathname): Ditto.
+
+       * nnheader.el (nnheader-group-pathname): Use expand-file-name.
+
+2000-03-13 20:23:06  Christoph Rohland  <hans-christoph.rohland@sap.com>
+
+       * rfc2047.el (rfc2047-encode-message-header): Encode no matter
+       whether Mule.
+
+2000-03-10 14:57:58  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-send-mail): Protect against unloaded Gnus.
+
+       * gnus-topic.el (gnus-topic-update-topic-line): Don't update the
+       parent.
+       (gnus-topic-update-topic-line): Yes, do.
+       (gnus-topic-goto-missing-group): Tally the correct number of
+       unread articles before inserting the topic line.
+
+2000-03-01 09:55:26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnultimate.el (nnultimate-retrieve-headers): Ignore errors.
+
+2000-02-13 13:53:08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-dissect-buffer): Ditto.
+
+       * gnus-art.el (article-decode-charset): Strip CTE.
+
+       * ietf-drums.el (ietf-drums-strip): New function.
+
+       * gnus-sum.el (gnus-summary-move-article): Don't use the prefix
+       when prompting in read-only groups.
+
+2000-02-23  Simon Josefsson  <jas@pdc.kth.se>
+
+       * imap.el (imap-send-command): Change EOL-chars when
+       `imap-client-eol' differs from default, not only for kerberos4.
+       (imap-mailbox-status): Get encoded mailbox's status.
+
+2000-02-19  Simon Josefsson  <jas@pdc.kth.se>
+
+       * mail-source.el (mail-source-fetch-imap): Copy `imap-password'
+       into `mail-source-password-cache'.
+
+2000-02-17  Florian Weimer  <fw@deneb.cygnus.argh.org>
+
+       * mm-util.el (mm-mime-charset): Check for presence of
+       `coding-system-get' and `get-charset-property' (recent XEmacs has
+       the former, but not the latter).
+
+2000-01-28  Dave Love  <fx@gnu.org>
+
+       * message.el (message-check-news-header-syntax): Fix typo
+       `newsgroyps'.
+       (message-talkative-question): Put temp buffer in fundamental-mode.
+       (message-recover): Use fundamental-mode in the right buffer.
+
+       * nnmail.el (nnmail-split-history): Use fundamental-mode in the
+       right buffer.
+
+2000-01-26 12:01:18  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * qp.el (quoted-printable-decode-region): Add charset parameter.
+       (quoted-printable-decode-string): Ditto.
+
+       * gnus-art.el (article-de-quoted-unreadable): Use it.
+
+2000-01-21  Simon Josefsson  <jas@pdc.kth.se>
+
+       * nnimap.el (nnimap-split-predicate): New variable.
+       (nnimap-split-articles): Use it.
+
+2000-01-20  Simon Josefsson  <jas@pdc.kth.se>
+
+       * utf7.el: Change email address.
+
+2000-01-18 22:03:51  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-catchup): Purge split history.
+
+2000-01-14 02:43:55  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnmail.el (nnmail-generate-active): Support extended group name.
+       (nnmail-get-active): Ditto.
+
+2000-01-13 15:16:10  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-write-active): Since no prefix in
+       group names, don't remove anything.
+
+2000-01-13 15:10:53  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el (webmail-my-deja-open): My-deja changes.
+
+2000-01-13  Simon Josefsson  <jas@pdc.kth.se>
+
+       * nnimap.el (nnimap-retrieve-headers-progress): Create xref field.
+
+2000-01-10 23:35:33  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-fetch-headers): Translate full path.
+
+2000-01-09 22:52:35  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el (gnus-other-frame): Fix typo.
+
+1999-06-25  Andreas Jaeger  <aj@arthur.rhein-neckar.de>
+
+       * gnus-cus.el (gnus-group-customize): Fix typo.
+
+2000-01-08 08:36:13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnweb.el (nnweb-insert): Simplified.
+
+2000-01-06 18:32:53  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-mode-map): "e" is
+       gnus-summary-edit-article.
+
+2000-01-06 18:25:37  Jari Aalto  <jari.aalto@poboxes.com>
+
+       * mailcap.el (mailcap-mime-extensions): Add .diff.
+
+2000-01-06 00:06:40  Kim-Minh Kaplan  <kmkaplan@vocatex.fr>
+
+       * mm-decode.el (mm-mailcap-command): handle "%%" and the case where
+       there is no "%s" in the method.
+
+2000-01-08 21:01:04  Kim-Minh Kaplan  <kmkaplan@vocatex.fr>
+
+       * gnus-sum.el (gnus-summary-select-article): Return 'old.
+
+2000-01-06 13:41:11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnfolder.el (nnfolder-read-folder): Use nnfolder-save-buffer.
+
+       * gnus.el: Really always pop up a new frame.
+
+       * parse-time.el (parse-time-rules): Allow 100-110 to be
+       2000-2010.
+
+       * time-date.el (date-to-time): Don't use timezone.
+
+2000-01-06  Dave Love  <fx@gnu.org>
+
+       * time-date.el: Add keywords.
+       (date-to-time): Add autoload cookie.  Canonicalize with
+       timezone-make-date-arpa-standard.
+       (time-to-seconds): Avoid caddr.
+       (safe-date-to-time): Add autoload cookie.
+
+       * base64.el: Require cl when compiling.
+
+2000-01-05  BrYan P. Johnson  <beej@mindspring.net>
+
+       * gnus-group.el (gnus-group-line-format-alist): Added %E for
+       eyecandy.
+       (gnus-group-insert-group-line): Now groks %E and inserts icon in
+       group line using gnus-group-add-icon.
+       (gnus-group-icons): Added customize group.
+       (gnus-group-icon-list): Added variable.
+       (gnus-group-glyph-directory): Added variable.
+       (gnus-group-icon-cache): Added variable.
+       (gnus-group-running-xemacs): Added variable.
+       (gnus-group-add-icon): Added function. Add an icon to the current
+       line according to gnus-group-icon-list.
+       (gnus-group-icon-create-glyph): Added function.
+
+2000-01-05 17:31:52  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-select-article): Return whether we
+       selected something new.
+       (gnus-summary-search-article): Start searching at the window
+       point.
+
+       * gnus-group.el (gnus-fetch-group): Complete over
+       gnus-active-hashtb.
+
+Wed Jan  5 17:06:41 2000  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v5.8.3 is released.
+
+2000-01-05 15:56:02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-preserve-marks): New variable.
+       (gnus-summary-move-article): Use it.
+       (gnus-group-charset-alist): Added more entries.
+
+2000-01-03 01:18:36  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-inline-override-types): Removed duplicate.
+
+       * gnus-uu.el (gnus-uu-mark-over): Use gnus-summary-default-score
+       as the default score.
+
+       * gnus-score.el (gnus-score-delta-default): Changed name.
+
+2000-01-04  Simon Josefsson  <jas@pdc.kth.se>
+
+       * imap.el (imap-parse-literal):
+       (imap-parse-flag-list): Don't care about props.
+       (imap-parse-string): Handle quoted characters.
+
+2000-01-02 08:37:03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-goto-unread): Doc fix.
+       (gnus-summary-mark-article): Doc fix.
+       (gnus-summary-mark-forward): Doc fix.
+       (t): Changed keystroke for gnus-summary-customize-parameters.
+
+       * gnus-art.el (gnus-article-mode-map): Use gnus-article-edit for
+       "e".
+       (gnus-article-mode-map): No, don't.
+
+       * gnus-sum.el (gnus-summary-next-subject): Don't show the thread
+       of the final article.
+
+       * mm-decode.el (mm-interactively-view-part): Error on no method.
+
+2000-01-02 06:10:32  Stefan Monnier  <monnier+gnu/emacs@tequila.cs.yale.edu>
+
+       * gnus-score.el (gnus-score-insert-help): Something.
+
+       * gnus-art.el (gnus-button-alist): Exclude < from <URL:
+
+       * gnus-win.el (gnus-configure-frame): Ditto.
+
+       * gnus-mh.el (gnus-summary-save-in-folder): Use
+       with-current-buffer.
+
+2000-01-02 05:00:13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnwarchive.el: Changed file perms.
+
+1999-12-19 21:42:15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-delete-groups): New command.
+       (gnus-group-delete-group): Extra no-prompt parameters.
+
+1999-12-14 10:18:30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnslashdot.el (nnslashdot-request-article): Translate <br> into
+       <p>.
+
+1999-12-28 12:20:18  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el (webmail-hotmail-article): Don't insert message id.
+
+1999-12-28  Kai.Grossjohann@CS.Uni-Dortmund.DE (Kai Großjohann)
+
+       * nnimap.el (nnimap-split-fancy): New variable.
+       (nnimap-split-fancy): New function.
+
+1999-12-28  Simon Josefsson  <jas@pdc.kth.se>
+
+       (nnimap-split-rule): Document symbol value.
+
+1999-12-28  Simon Josefsson  <jas@pdc.kth.se>
+
+       * nnimap.el (nnimap-retrieve-headers-progress): Let
+       `nnheader-parse-head' parse article.
+       (nnimap-retrieve-headers-from-server): Don't request ENVELOPE,
+       request headers needed by `nnheader-parse-head'.
+
+1999-12-23  Florian Weimer  <fw@s.netic.de>
+
+       * gnus-msg.el (gnus-group-posting-charset-alist): Correct default
+       value (crosspostings are handled), improve documentation.
+
+       * smiley.el: Declare file coding system as iso-8859-1.
+
+       * nnultimate.el: Dito.
+
+       * message.el: Dito.
+
+       * gnus-cite.el: Dito.
+
+       * gnus-spec.el: Dito.
+
+1999-12-21  Florian Weimer  <fw@s.netic.de>
+
+       * gnus-msg.el (gnus-group-posting-charset-alist): New layout.
+       (gnus-setup-message): No longer make `message-posting-charset'
+       buffer-local.
+       (gnus-setup-posting-charset): Reflect the new layout of
+       `gnus-group-posting-charset-alist' and `message-posting-charset'.
+
+       * message.el (message-send-mail): Bind `message-this-is-mail' and
+       `message-posting-charset'.
+       (message-send-news): Dito, and honour new layout of
+       `message-posting-charset'.
+       (message-encode-message-body): Ignore `message-posting-charset'.
+
+       * mm-bodies.el (mm-body-encoding): Consider
+       `message-posting-charset' when deciding whether to use 8bit.
+
+       * rfc2047.el (rfc2047-encode-message-header): Back out change.
+       (rfc2047-encodable-p): Now solely for headers; use
+       `message-posting-charset'.
+
+1999-12-20 14:10:39  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnwarchive.el (nnwarchive-type-definition): Set default value.
+
+1999-12-19 22:49:13  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnagent.el (nnagent-server-opened): Optional.
+       (nnagent-status-message): Optional.
+
+1999-12-19  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-cite.el (gnus-article-toggle-cited-text): Restore beg and
+       end (referenced by instructions in
+       `gnus-cited-opened-text-button-line-format-alist').
+
+1999-12-18  Simon Josefsson  <jas@pdc.kth.se>
+
+       * imap.el (imap-starttls-open): Typo.
+
+1999-12-18 16:43:37  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-charset-after): Non-MULE case.
+       * mail-prsvr.el (mail-parse-mule-charset): New variable.
+       * rfc2047.el (rfc2047-dissect-region): Bind it.
+
+1999-12-18  Florian Weimer  <fw@s.netic.de>
+
+       * mml.el (mml-generate-multipart-alist): Correct default value.
+
+       * mm-encode.el (mm-use-ultra-safe-encoding): New variable.
+       (mm-safer-encoding): New function.
+       (mm-content-transfer-encoding): Use both.
+
+       * mm-bodies.el (mm-body-encoding): Use mm-use-ultra-safe-encoding.
+       * qp.el (quoted-printable-encode-region): Dito.
+
+1999-12-18 14:08:48  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el (webmail-hotmail-article): Snarf the raw file.
+
+1999-12-18 14:08:12  Victor S. Miller  <victor@idaccr.org>
+
+       * webmail.el (webmail-hotmail-list): raw=0.
+
+1999-12-18 11:14:51  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-enter-history): Back-compatible in
+       group name.
+
+1999-12-18 11:02:00  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-expire): Convert to symbol if stringp.
+
+1999-12-18  Simon Josefsson  <jas@pdc.kth.se>
+
+       * imap.el: Don't autoload digest-md5.
+       (imap-starttls-open): Bind coding-system-for-{read,write}.
+       (imap-starttls-p): Check if we can find starttls.el.
+       (imap-digest-md5-p): Check if we can find digest-md5.el.
+
+1999-12-17  Daiki Ueno  <ueno@ueda.info.waseda.ac.jp>
+
+       * base64.el (base64-encode-string): Accept 2nd argument
+       `no-line-break'.
+
+       * imap.el: Require `digest-md5' when compiling; add autoload
+       settings for `digest-md5-parse-digest-challenge',
+       `digest-md5-digest-response', `starttls-open-stream' and
+       `starttls-negotiate'.
+       (imap-authenticators): Add `digest-md5'.
+       (imap-authenticator-alist): Setup for `digest-md5'.
+       (imap-digest-md5-p): New function.
+       (imap-digest-md5-auth): New function.
+       (imap-stream-alist): Add STARTTLS entry.
+       (imap-starttls-p): New function.
+       (imap-starttls-open): New function.
+
+1999-12-18 01:08:10  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-enter-history): Bad group name.
+
+1999-12-17 19:36:47  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-dissect-region): Use mapcar instead of
+       string-to-x function.
+
+1999-12-17 13:08:54  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-fold-region): Fold a line more than once.
+
+1999-12-17 11:54:41  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el: Enhance hotmail-snarf.
+
+1999-12-17 10:38:10  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-dissect-region): Rewrite.
+
+1999-12-16 22:59:22  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el (webmail-hotmail-list): Search no-error.
+
+1999-12-15 22:07:15  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnwarchive.el: Support nov-is-evil.
+       * gnus-bcklg.el (gnus-backlog-request-article): Buffer is optional.
+       Set it if non-nil.
+       * gnus-agent.el (gnus-agent-fetch-articles): Use it.
+
+1999-12-15 08:55:19  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnagent.el (nnagent-server-opened): Redefine.
+       (nnagent-status-message): Ditto.
+
+1999-12-14 23:37:44  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc1843.el (rfc1843-decode-region): Use
+       buffer-substring-no-properties.
+       * gnus-art.el (article-decode-HZ): New function.
+
+1999-12-14 22:07:26  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnheader.el (nnheader-translate-file-chars): Only in full path.
+
+1999-12-14 16:21:45  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-find-charset-region): mail-parse-charset is a
+       MIME charset not a MULE charset.
+
+1999-12-14 15:08:03  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-ems.el: Translate more ugly characters.
+       * nnheader.el (nnheader-translate-file-chars): Don't translate
+       the second ':'.
+
+1999-12-14 10:40:33  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-request-article-this-buffer): Use all refer
+       method if cannot find the article.
+
+1999-12-14 01:13:50  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-request-article-this-buffer): Don't use refer
+       method if overrided.
+
+1999-12-13 23:38:53  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mail-source.el (mail-source-fetch-webmail): Parameter
+       dontexpunge.
+
+1999-12-13 23:31:17  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el: Support my-deja. Better error report.
+
+1999-12-13 18:59:33  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnslashdot.el (nnslashdot-date-to-date): Error proof when input
+       is bad.
+       * gnus-sum.el (gnus-list-of-unread-articles): When (car read)
+       is not 1.
+
+1999-12-13 18:22:08  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnslashdot.el (nnslashdot-request-article): A space.
+
+1999-12-13 17:20:25  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnagent.el: Support different backend with same name.
+
+1999-12-13 13:14:42  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnslashdot.el (nnslashdot-threaded-retrieve-headers): Support
+       archived group.
+       (nnslashdot-sane-retrieve-headers): Ditto.
+       (nnslashdot-request-article): Ditto.
+
+1999-12-13 11:41:32  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnweb.el (nnweb-insert): Narrow to point.
+
+1999-12-13 10:59:42  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnweb.el (nnweb-insert): Follow refresh url.
+       * nnslashdot.el: Use it.
+
+1999-12-13 10:39:53  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnweb.el (nnweb-decode-entities): Decode numerical entities.
+       (nnweb-decode-entities-string): New function.
+
+       * nnwarchive.el (nnwarchive-decode-entities-string): Rename to
+       nnweb-* and move to nnweb.el.
+       * nnwarchive.el: Use nnweb-decode-entities, etc.
+       * webmail.el: Ditto.
+
+       * nnslashdot.el: Use nnweb-decode-entities-string.
+       (nnslashdot-decode-entities): Remove.
+
+1999-12-13 10:40:56  Eric Marsden  <emarsden@mail.dotcom.fr>
+
+       * nnslashdot.el: Decode entities.
+
+1999-12-12  Dave Love  <fx@gnu.org>
+
+       * gnus-agent.el (gnus-category-edit-groups)
+       (gnus-category-edit-score, gnus-category-edit-predicate): Replace
+       expansion of setf, fixed.
+
+1999-12-12 12:50:30  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el: Revoke last Dave Love's patch, because of
+       incompatibility of XEmacs.
+
+1999-12-12 12:27:03  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-uu.el: Change headers.
+       * rfc1843.el: Ditto.
+       * uudecode.el: Ditto.
+
+1999-12-07  Dave Love  <fx@gnu.org>
+
+       * gnus-agent.el (gnus-category-edit-predicate)
+       (gnus-category-edit-score, gnus-category-edit-score): Expand setf
+       inside backquote to avoid it at runtime.
+
+1999-12-07  Dave Love  <fx@gnu.org>
+
+       * binhex.el: Require cl when compiling.
+
+1999-12-04  Dave Love  <fx@gnu.org>
+
+       * gnus-cus.el (gnus-group-parameters): Allow nil for banner.
+
+1999-12-04  Dave Love  <fx@gnu.org>
+
+       * mm-util.el (mm-delete-duplicates): New function.
+       (mm-write-region): Use it.
+
+       * mml.el (mml-minibuffer-read-type): Use mm-delete-duplicates.
+
+       * mailcap.el (mailcap-mime-types): Require mm-util.  Use
+       mm-delete-duplicates.
+
+       * imap.el (imap-open, imap-debug): Avoid mapc.
+
+       * nnvirtual.el (nnvirtual-create-mapping): Likewise.
+
+       * gnus-sum.el (gnus-summary-exit-no-update): Avoid copy-list.
+       (gnus-multi-decode-encoded-word-string): Avoid mapc.
+
+       * gnus-start.el (gnus-site-init-file): Avoid ignore-errors at
+       runtime.
+
+       * gnus.el (gnus-select-method): Likewise.
+
+       * nnheader.el (nnheader-nov-read-integer): Likewise.
+
+       * mm-view.el (mm-inline-message): Require cl when compiling.
+       Avoid ignore-errors at runtime.
+       (mm-inline-text): Avoid mapc.
+
+1999-12-12 10:36:51  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-decode-charset): Widen is bad.
+
+1999-12-12 10:17:42  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-charset-after): `charset-after' may not be defined.
+
+1999-12-12  Florian Weimer  <fw@s.netic.de>
+
+       * rfc2047.el (rfc2047-encodable-p): New parameter header used to
+       indicate that only US-ASCII is permitted.
+       (rfc2047-encode-message-header): Use it.  Now, Gnus should never
+       use unencoded 8-bit characters in message headers.
+
+1999-12-12 03:08:15  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * ietf-drums.el (ietf-drums-narrow-to-header): Make it work with
+       CRLF.
+
+1999-12-11 14:42:26  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el: Require url-cookie.
+
+1999-12-11 14:21:23  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnwarchive.el (nnwarchive-make-caesar-translation-table): A
+       new function to make modified caesar table.
+       (nnwarchive-from-r13): Use it.
+       (nnwarchive-mail-archive-article): Improved.
+
+1999-12-11 12:30:20  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el (webmail-url): Use mm-with-unibyte-current-buffer.
+
+1999-12-10 16:22:24  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnweb.el (nnweb-request-article): Return cons.
+
+1999-12-10 16:06:04  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-setup-default-charset): Typo.
+
+1999-12-10 12:14:04  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-with-unibyte): New macro.
+       * nnweb.el (nnweb-init): Use it.
+
+1999-12-09 20:39:49  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-charset-after): New function.
+       (mm-find-mime-charset-region): Set charsets after
+       delete-duplicates and use find-coding-systems-region.
+       (mm-find-charset-region): Remove composition.
+
+       * mm-bodies.el (mm-encode-body): Use mm-charset-after.
+
+       * mml.el (mml-parse-singlepart-with-multiple-charsets): Ditto.
+
+1999-12-09 17:47:56  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-find-mime-charset-region): Revoke last change.
+       * mml.el (mml-confirmation-set): New variable.
+       (mml-parse-1): Ask user to confirm.
+
+1999-12-09  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-start.el (gnus-get-unread-articles): Make sure all methods
+       are scanned when we have directory mail-sources (the mail source
+       is modified in that case, so we must scan it for all
+       groups/methods).
+
+1999-12-09 12:05:28  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnml.el (nnml-request-move-article): Save nnml-current-directory
+       and nnml-article-file-alist.
+
+1999-12-09 10:20:07  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-get-new-news-this-group): Binding
+       nnmail-fetched-sources.
+
+1999-12-09 10:19:01  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-find-charset-region): Use the last charset.
+
+1999-12-08  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus.el (gnus-select-method): Made the option list prettier.
+
+1999-12-08  Florian Weimer  <fw@s.netic.de>
+
+       * gnus-msg.el (gnus-group-posting-charset-alist): Use iso-8859-1
+       for the `de' newsgroups hierarchy, as it is common practice there.
+
+
+1999-12-07 16:17:12  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnwarchive.el (nnwarchive-mail-archive-article): Fix
+       buffer-string arguments. Fix references.
+
+1999-12-07 15:04:18  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-confirmation-function): New variable.
+       (gnus-agent-batch-fetch): Use it.
+       (gnus-agent-fetch-session): Use it.
+
+1999-12-07 12:32:43  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-find-mime-charset-region): Delete nil.
+
+1999-12-07 11:45:10  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-find-charset-region): Don't capitalize.  Delete
+       nil.
+
+1999-12-07  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * nnslashdot.el (nnslashdot-request-list): There were two
+       top-level body-forms.  Put a `progn' around them.
+
+       * gnus.el (gnus-select-method): Use `condition-case'
+       instead of `ignore-errors', since cl may not be loaded when the
+       form is evaluated.
+
+1999-12-06 23:57:47  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnwarchive.el: Support www.mail-archive.com.
+
+1999-12-06 23:55:55  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnmail.el (nnmail-get-new-mail): Remove fetched sources before
+       do anything.
+
+1999-12-06  Simon Josefsson  <jas@pdc.kth.se>
+
+       * utf7.el: New file, written by Jon K Hellan.
+
+       * imap.el (imap-use-utf7): Renamed from `imap-utf7-p', change
+       default to t.
+
+1999-12-06 04:40:24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnslashdot.el (nnslashdot-request-delete-group): New function.
+
+       * gnus-sum.el (gnus-summary-refer-article): Work for lists with
+       current.
+       (gnus-refer-article-methods): New function.
+       (gnus-summary-refer-article): Use it.
+
+1999-11-13  Simon Josefsson  <jas@pdc.kth.se>
+
+       * nnimap.el (nnimap-retrieve-groups): Return active format.
+
+       * nnimap.el (nnimap-replace-in-string): Removed.
+       (nnimap-request-list):
+       (nnimap-retrieve-groups):
+       (nnimap-request-newgroups): Quote group instead of escaping SPC.
+
+1999-12-05  Simon Josefsson  <jas@pdc.kth.se>
+
+       * imap.el: Use format-spec for ssl program.
+       * imap.el (imap-ssl-arguments): Removed.
+       (imap-ssl-open-{1,2}): Removed.
+
+1999-12-04  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus-start.el (gnus-site-init-file): Use `condition-case'
+       instead of `ignore-errors', since cl may not be loaded when the
+       form is evaluated.
+
+1999-12-04 11:34:22  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-bodies.el (mm-8bit-char-regexps): Removed.
+       (mm-7bit-chars): New variable.
+       (mm-body-7-or-8): Use it in both cases.
+
+1999-12-04  Michael Welsh Duggan  <md5i@cs.cmu.edu>
+
+       * gnus-start.el (gnus-site-init-file): Don't use cl macros in
+       defcustom definitions.
+
+1999-12-04  Simon Josefsson  <jas@pdc.kth.se>
+
+       * mm-decode.el (mm-display-part): Let mm-display-external return
+       inline or external.
+       (mm-display-external): For copiousoutput methods, insert output in
+       buffer.
+
+1999-12-04 03:29:13  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nntp.el (nntp-retrieve-headers-with-xover): Goto the end of
+       buffer.
+
+1999-12-04 08:31:10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-audio.el: An M too far.
+
+       * gnus-msg.el (gnus-setup-message): One backtick too many.
+
+       * gnus-art.el (gnus-mime-view-part-as-type): mailcap-mime-types is
+       a function, not a variable.
+
+1999-12-04 08:14:08  Max Froumentin  <masmef@maths.bath.ac.uk>
+
+       * gnus-score.el (gnus-score-body): Widen before requesting.
+
+1999-12-04 08:06:13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-prepare-flat): Comment fix.
+
+1999-12-04 03:01:55  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mail-source.el (mail-source-fetch-webmail): Bind
+       mail-source-string.
+
+1999-12-04 07:18:23  Matt Swift  <swift@alum.mit.edu>
+
+       * gnus-uu.el (gnus-uu-mark-by-regexp): Doc fix.
+       (gnus-uu-unmark-by-regexp): Ditto.
+
+       * gnus-group.el (gnus-group-catchup-current): Would bug out on
+       dead groups.
+
+1999-12-04 01:34:31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-setup-message): Allow the charset setting to
+       do their real thing.
+
+       * nnmh.el (nnmh-be-safe): Doc fix.
+
+       * gnus-sum.el (gnus-summary-exit): Write cache active file.
+
+       * nntp.el (nntp-retrieve-headers-with-xover): Make sure the entire
+       status line has arrived before we count it.
+
+       * mailcap.el (mailcap-mime-data): Removed save-file from audio/*.
+
+       * gnus-sum.el (gnus-thread-header): Fixed after indent.
+       Whitespace problems.
+
+       * gnus-win.el (gnus-configure-windows): Error fix.
+
+       * gnus-demon.el (gnus-demon-add-nntp-close-connection): Add the
+       right function.
+
+       * gnus.el: Fixed all the doc strings to match the FSF convetions.
+       Indent all functions.  Fix all comments to match the comment
+       conventions.  Double-space after full stop.
+
+1999-12-04 01:14:55  YAMAMOTO Kouji  <kouji@pobox.com>
+
+       * nnmail.el (nnmail-split-it): I redefined nnmail-split-fancy's
+       value to divide received mails into my favorite groups and I met
+       an error.  It takes place if the length of a element "VALUE" in
+       nnmail-split-fancy is less than two.
+
+1999-10-10  Robert Bihlmeyer  <robbe@orcus.priv.at>
+
+       * mml.el (mml-insert-part): New function.
+
+1999-09-29 04:48:14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Add `sc-cite-regexp'.
+
+1999-12-02  Dave Love  <fx@gnu.org>
+
+       * mm-decode.el: Customize.
+
+1999-12-03  Dave Love  <fx@gnu.org>
+
+       * nnslashdot.el, nnultimate.el: Don't lose at compile time when
+       the W3 stuff isn't available.
+
+1999-12-03  Dave Love  <fx@gnu.org>
+
+       * imap.el, mailcap.el, nnvirtual.el, rfc2104.el: Don't require cl
+       at runtime.
+
+1999-12-04 00:47:35  Dan Christensen  <jdc@jhu.edu>
+
+       * gnus-score.el (gnus-score-headers): Fix orphan scoring.
+
+1999-12-01  Andrew Innes  <andrewi@gnu.org>
+
+       * nnmbox.el (nnmbox-read-mbox): Count messages correctly, and
+       don't be fooled by "From nobody" lines added by respooling.
+
+       * pop3.el (pop3-movemail): Write crashbox in binary.
+       (pop3-get-message-count): New function.
+
+       * mail-source.el (mail-source-primary-source): New variable.
+       (mail-source-report-new-mail-interval): New variable.
+       (mail-source-idle-time-delay): New variable.
+       (mail-source-new-mail-available): New internal variable.
+       (mail-source-fetch-pop): Clear new mail flag, when mail from
+       primary source has been fetched.
+       (mail-source-check-pop): New function.
+       (mail-source-new-mail-p): New function.
+       (mail-source-start-idle-timer): New function.
+       (mail-source-report-new-mail): New function.
+       (mail-source-report-new-mail): New internal variable.
+       (mail-source-report-new-mail-timer): New internal variable.
+       (mail-source-report-new-mail-idle-timer): New internal variables.
+
+1999-12-04 00:39:34  Andreas Schwab  <schwab@suse.de>
+
+       * gnus-cus.el (gnus-group-customize): Customize fix.
+
+1999-12-04 00:38:24  Andrea Arcangeli  <andrea@suse.de>
+
+       * message.el (message-send-mail-with-sendmail): Use
+       message-make-address.
+
+Fri Dec  3 20:34:11 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v5.8.2 is released.
+
+Fri Dec  3 20:09:41 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v5.8.1 is released.
+
+1999-11-11  Hrvoje Niksic  <hniksic@iskon.hr>
+
+       * mml.el (mml-insert-tag): Don't close the tag.
+       (mml-insert-empty-tag): New function.
+       (mml-attach-file): Use mml-insert-empty-tag instead of
+       mml-insert-tag.
+       (mml-attach-buffer): Ditto.
+       (mml-attach-external): Ditto.
+       (mml-insert-multipart): Ditto.
+
+1999-12-03 08:49:53  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnfolder.el (nnfolder-request-article): Return -1 if not find
+       the article number.
+
+1999-12-03 01:12:41  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el (gnus-find-method-for-group): The method of a new group
+       is not the native one.
+
+1999-12-03 01:26:55  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-button-embedded-url): Always call browse-url.
+
+1999-12-02 18:00:15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnultimate.el (nnultimate-retrieve-headers): Use
+       mm-with-unibyte-current-buffer.
+       (nnultimate-request-article): Ditto.
+
+1999-12-02 14:57:46  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nntp.el (nntp-retrieve-groups): Set to process buffer.
+
+1999-12-02 11:14:50  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-with-unibyte-current-buffer): New macro.
+       * nnweb.el (nnweb-retrieve-headers): Use it.
+       (nnweb-request-article): Use it.
+
+       * nnweb.el (nnweb-dejanews-create-mapping): Set a default date in
+       case matching failed.
+
+1999-12-02  John Wiegley  <jwiegley@inprise.com>
+
+       * mail-source.el (mail-source-keyword-map): Add backslash to
+       Delete-flag.
+
+1999-12-02 07:24:35  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-group-charset-alist): Default nnweb groups to
+       Latin-1.
+       (gnus-group-charset-alist): No, don't.
+
+       * nnweb.el (nnweb-init): Make the buffer unibyte.
+
+1999-12-01 23:02:48  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mail-source.el (mail-source-set-common-1): Fix to get the
+       default value.
+
+1999-12-02 00:27:46  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnslashdot.el (nnslashdot-read-groups): Unibyte.
+
+       * nnultimate.el (nnultimate-request-list): Use unibyte.
+
+       * gnus-uu.el (gnus-uu-grab-articles): Bind
+       gnus-display-mime-function to nil.
+
+       * message.el (message-send-mail-with-sendmail): Use the
+       user-mail-address variable.
+
+       * gnus-art.el (gnus-ignored-headers): More headers.
+
+       * message.el (message-shorten-1): Use list.
+
+1999-12-01 21:59:36  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-configure-posting-styles): Ignore nil
+       signatures.
+
+       * nnweb.el (nnweb-dejanews-create-mapping): Get the data.
+       (nnweb-dejanews-create-mapping): Do the properish date.
+
+1999-12-01 17:41:21  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mail-source.el (mail-source-common-keyword-map): New variable.
+       (mail-source-bind-common): New macro.
+       (mail-source-fetch): Support plugged mail source.
+       * gnus-int.el (gnus-request-scan): Use them.
+
+1999-12-01 21:59:36  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-view.el (mm-inline-message): Check whether charset is a
+       string.
+
+       * nnslashdot.el (nnslashdot-request-post): Insert <p>'s.
+
+       * message.el (message-mode-map): Changed keystroke for
+       message-yank-buffer.
+
+1999-11-26  Hrvoje Niksic  <hniksic@iskon.hr>
+
+       * message.el (message-shorten-references): Cut references to 31
+       elements, then either fold them or shorten them to 988 characters.
+       (message-shorten-1): New function.
+       (message-cater-to-broken-inn): New variable.
+
+1999-12-01 21:47:10  Eric Marsden  <emarsden@mail.dotcom.fr>
+
+       * nnslashdot.el (nnslashdot-lose): New function.
+
+1999-12-01 21:08:48  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-view.el (mm-inline-message): Not the right type of charset is
+       being fetched here.  Let the group charset rule.
+       (mm-inline-message): Ignore us-ascii.
+
+1999-11-24  Carsten Leonhardt  <leo@arioch.oche.de>
+
+       * mail-source.el (mail-source-fetch-maildir): work around the
+       ommitted "file-regular-p" in efs/ange-ftp.
+
+1999-12-01 19:59:25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml.el (mml-generate-mime-1): Don't insert extra empty line.
+       (mml-generate-mime-1): Use the encoding param.
+
+       * gnus-sum.el (gnus-summary-show-article): Don't bind gnus-visual.
+
+       * gnus-cache.el (gnus-cache-possibly-enter-article): Require
+       gnus-art before binding its variables.
+
+       * gnus-art.el (gnus-article-prepare-display): Run the prepare
+       after the MIME.
+
+1999-12-01 19:48:14  Rupa Schomaker  <rupa-list@rupa.com>
+
+       * message.el (message-clone-locals): Use it.
+
+       * gnus-msg.el (gnus-configure-posting-styles): Make
+       user-mail-address local.
+
+1999-11-20  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-start.el (gnus-get-unread-articles): Scan each method only
+       once.
+
+1999-12-01 17:37:18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-generate-new-buffer-clone-locals): Use varstr.
+       (message-clone-locals): Ditto.
+
+       * gnus-sum.el (gnus-summary-enter-digest-group): Have the digest
+       group inherit reply-to or from.
+
+1999-12-01 13:04:09  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-show-article): Support numbered ARG
+       for charset.
+       (gnus-summary-show-article-charset-alist): New variable.
+
+       * mm-bodies.el (mm-decode-string): Support gnus-all and
+       gnus-unknown.
+       (mm-decode-body): Ditto.
+       * rfc2047.el (rfc2047-decode): Ditto.
+
+1999-12-01 17:37:18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-delete-incoming): Change default to
+       t.
+
+Wed Dec  1 16:31:31 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.99 is released.
+
+1999-12-01 14:28:49  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * dgnushack.el (dgnushack-compile): No webmail under Emacs.
+
+       * gnus-sum.el (gnus-summary-refer-article): Wrong interactive
+       spec.
+
+       * gnus-msg.el (gnus-configure-posting-styles): Eval `eval'.
+       (gnus-configure-posting-styles): No, don't.
+       (gnus-configure-posting-styles): Allow overriding files.
+
+       * gnus-art.el (gnus-header-button-alist): Use browse-url
+       directly.
+
+       * mm-decode.el (mm-inline-media-tests): Check feature vcard.
+
+       * gnus-msg.el (gnus-summary-yank-message): New command and
+       keystroke.
+
+       * message.el (message-yank-buffer): New command.
+       (message-buffers): New function.
+
+       * gnus-sum.el (gnus-summary-catchup-and-goto-next-group): Select
+       next group in a more normal fasion.
+
+       * mml.el (mml-boundary-function): New variable.
+       (mml-compute-boundary): Use it.
+
+       * nnmh.el (nnmh-active-number): Skip past files that have buffers
+       that exist for them.
+
+       * gnus-async.el (gnus-async-prefetch-next): Cancel timers.
+       (gnus-async-timer): New variable.
+
+1999-11-30 02:07:18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnultimate.el (nnultimate-request-list): Be more lenient with
+       root addresses.
+
+1999-11-28 20:22:37  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-treatment-function-alist): Do
+       gnus-treat-capitalize-sentences.
+
+1999-11-30 09:07:53  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el (webmail-hotmail-article): Hotmail changes the
+       format.
+
+1999-11-29  Simon Josefsson  <jas@pdc.kth.se>
+
+       * mm-decode.el (mm-display-external): For `copiousoutput' methods,
+       switch to buffer after calling program.
+       (mm-display-external): Use `shell-command-switch' instead of "-c".
+
+1999-11-27 15:21:25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnultimate.el (nnultimate-possibly-change-server): Don't always
+       read groups file.
+
+       * nnslashdot.el (nnslashdot-request-article): Convert <br><br> to
+       <p>.
+
+1999-11-24 20:18:24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-mode): Doc fix.
+
+1999-11-24 09:25:00  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-emphasize): Check group variable.
+       * rfc1843.el (rfc1843-decode-article-body): Ditto.
+
+1999-11-24 00:11:27  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-save-part-to-file): Inhibit jka-compr for any
+       type.
+
+1999-11-23 17:21:05  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el: Support www.netaddress.com, i.e. usa.net.
+
+1999-11-23  Hrvoje Niksic  <hniksic@iskon.hr>
+
+       * mml.el (mml-quote-region): Insert ! after the hash.
+
+1999-11-23 05:08:23  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-warchive-address-history): Change to
+       nil.
+
+1999-11-23 02:33:13  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el: Support mail.yahoo.com.
+
+       * mail-source.el (mail-source-fetch-webmail): Add password check.
+       (mail-source-keyword-map): Use `subtype'.
+
+1999-11-22 04:35:43  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mail-source.el (mail-source-keyword-map): Add webmail.
+       (mail-source-fetcher-alist): Ditto.
+       (mail-source-fetch-webmail): New function.
+       * webmail.el: New file.
+
+1999-11-21 12:20:02  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnwarchive.el (nnwarchive-request-group): Print 0 if it is nil.
+
+1999-11-21 12:19:11  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mailcap.el (mailcap-parse-mailcap): Don't skip double semicolon.
+
+1999-11-20 12:54:25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnultimate.el (nnultimate-request-list): Add fetch-time slot.
+       (nnultimate-prune-days): New function.
+       (nnultimate-create-mapping): Use it.
+       (nnultimate-request-group): Only fetch the groups list if it has
+       not been done before.
+       (nnultimate-retrieve-headers): Don't write groups.
+       (nnultimate-create-mapping): Off-by-one error.
+
+1999-11-19 12:17:25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnslashdot.el (nnslashdot-sane-retrieve-headers): Fix to match
+       threaded subjects.
+
+1999-11-20 02:22:52  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnwarchive.el: Lots of changes make agent happy.
+
+1999-11-19 21:37:41  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-start.el (gnus-get-unread-articles): Assert group is in
+       hashtb.
+
+1999-11-19 19:53:08  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-display-external): Write region with binary
+       mode.
+
+1999-11-18 14:52:05  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnweb.el (nnweb-dejanews-create-mapping): Bind `text'.
+
+1999-11-18 14:35:01  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-uu.el (mm-uu-dissect): Use fake charset `gnus-decoded'.
+       (mm-uu-test): Now it is in restricted region.
+
+       * gnus-art.el (article-decode-charset): Don't mm-uu-test.
+
+       * mm-view.el (mm-view-message): Fix buffer leak.
+       (mm-inline-message): Support 'gnus-decoded.
+
+       * mm-bodies.el (mm-decode-body): Ditto.
+
+       * rfc2047.el (rfc2047-decode-region): Ditto.
+
+1999-11-18  Matthias Andree  <ma@dt.e-technik.uni-dortmund.de>
+
+       * imap.el (require): Added autoload for base64-encode-string.
+
+1999-11-17  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus.el (gnus-refer-article-method): Made list value
+       customizable.
+
+1999-11-17 13:09:37  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-recenter): set-window-start with
+       NOFORCE in Emacs case.
+
+1999-11-17 13:04:01  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-request-article-this-buffer): Set
+       gnus-newsgroup-name.
+
+1999-11-16 23:53:22  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-xmas.el (gnus-xmas-summary-recenter): set-window-start with
+       NOFORCE.
+
+1999-11-17  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-start.el (gnus-get-unread-articles): Check server before
+       scanning.
+
+1999-11-16 10:01:03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-valid-select-methods): nnslashdot is news.
+
+       * nnslashdot.el (nnslashdot-login-name): New variable.
+       (nnslashdot-password): Ditto.
+       (nnslashdot-request-post): New function.
+
+       * gnus-art.el (gnus-treat-buttonize): More testing.
+
+       * mm-encode.el: Another CVS test.
+
+       * gnus-art.el (gnus-treat-emphasize): Change default.
+       (gnus-treat-buttonize): Ditto.
+       (gnus-treat-buttonize): This is a test.
+
+       * gnus-sum.el (gnus-build-old-threads): Bind mail-parse-charset.
+       (gnus-build-sparse-threads): Ditto.
+       (gnus-build-all-threads): Ditto.
+
+       * nnheader.el (make-full-mail-header): Make into a subst.
+
+       * dgnushack.el (dgnushack-compile): Skip all w3-dependent files
+       unless w3 is supplied.
+
+       * gnus.el (gnus-refer-article-method): Doc fix.
+
+       * gnus-sum.el: Do not accept a prefix.
+       (gnus-summary-refer-article): Accept a list of select methods.
+
+1999-11-15 21:28:40  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * Makefile.in: Change `^  *' to `\t'.
+
+1999-11-11  Matt Pharr  <mmp@graphics.stanford.edu>
+
+       * message.el (message-forward): Pay attention to prefix argument
+       again and forward all headers when it is set, regardless of the
+       value of message-forward-ignored-headers.
+
+1999-11-15 20:44:50  William M. Perry  <wmperry@aventail.com>
+
+       * dgnushack.el (dgnushack-compile): Vpath file.
+
+       * Makefile.in (SHELL): VPATH support.
+
+1999-11-15 20:37:17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-ems.el: Check for cygwin32.
+
+1999-11-14 18:15:28  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-display-external): Use 'non-viewer.
+
+1999-11-14 15:21:06  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * base64.el (base64-encode-string): An alias for base64-encode for
+       compatibility.
+
+1999-11-14 01:58:18  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nntp.el (nntp-retrieve-groups): Erase nntp-sever-buffer before
+       nntp-inhibit-erase.
+
+1999-11-13  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-start.el (gnus-get-unread-articles): Use
+       nnfoo-retrieve-groups to find new news, if available.
+       (gnus-read-active-file-2): New function.
+       (gnus-get-unread-articles): Use it.
+       (gnus-read-active-file-1): Ditto.
+
+1999-11-13 17:59:18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-util.el (mm-find-mime-charset-region): Make sure
+       find-coding-systems-for-charsets is fbound.
+
+       * gnus-ems.el: Typo fix.
+
+1999-11-13  Florian Weimer  <fw@s.netic.de>
+
+       * mm-util.el (mm-find-mime-charset-region): Use UTF-8 if
+       it's available and makes sense.
+
+1999-11-12 19:56:23  Fabrice POPINEAU  <Fabrice.Popineau@supelec.fr>
+
+       * gnus-score.el (gnus-score-save): Translate score file.
+
+1999-11-13  Simon Josefsson  <jas@pdc.kth.se>
+
+       * mail-source.el (mail-source-keyword-map): For IMAP mail source,
+       added fetchflag and dontexpunge keywords.
+       (mail-source-fetch-imap): Use them.
+
+1999-11-12  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus-start.el (gnus-level-subscribed, gnus-level-unsubscribed,
+       gnus-level-zombie, gnus-level-killed): Changed from `defcustom' to
+       `defconst'.
+
+       * gnus-cus.el (gnus-group-parameters): Changed from `defcustom' to
+       `defconst'.
+       Mention that it is both for group and topic parameters.
+       (gnus-extra-topic-parameters): New constant, including `subscribe'
+       parameter.
+       (gnus-extra-group-parameters): New constant.
+       (gnus-group-customize): Use them.
+
+       * gnus.el (gnus-select-method): Added default value and tag.
+       (gnus-refer-article-method): Added `DejaNews' customization option.
+
+1999-11-12 05:04:43  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-int.el (gnus-server-opened): Ignore denied servers.
+
+       * gnus-ems.el (gnus-mule-max-width-function): New backquote
+       syntax.
+
+       * nndoc.el (nndoc-mime-digest-type-p): Reinstated.
+
+       * nnslashdot.el (nnslashdot-group-number): Changed default.
+
+       * nnweb.el (nnweb-dejanews-create-mapping): Work with new deja.
+       (nnweb-dejanews-wash-article): Removed.
+       (nnweb-type-definition): Fetch by id.
+
+       * gnus-msg.el (gnus-configure-posting-styles): Don't insert unless
+       we mean it.
+
+       * nnslashdot.el (nnslashdot-group-number): Doc fix.
+       (nnslashdot-request-list): Use Ultramode as well.
+       (nnslashdot-date-to-date): Be more lenient.
+       (nnslashdot-threaded): New function.
+
+1999-11-11 17:40:54  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-mime-internalize-part): Doc fix.
+
+1999-11-11 14:32:48  Steinar Bang  <sb@metis.no>
+
+       * nnweb.el (nnweb-type-definition): /=dnc .
+
+1999-11-11 10:58:38  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnultimate.el (nnultimate-retrieve-headers): Work with american
+       dates.
+       (nnultimate-retrieve-headers): Wrong ordering.
+
+1999-11-11 07:31:51  Matt Pharr  <mmp@graphics.stanford.edu>
+
+       * message.el (message-forward-as-mime): New variable.
+
+1999-11-11 05:24:13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-util.el (gnus-dd-mmm): Beware buggy dates.
+
+1999-11-10 16:50:01  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mail-source.el (mail-source-movemail-and-remove): New function.
+       (mail-source-keyword-map): Add `function' for `maildir'.
+       (mail-source-fetch-maildir): Use it.
+
+1999-11-10 13:48:10  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnwarchive.el: New file.
+       * gnus-group.el (gnus-group-make-warchive-group): New function.
+       * gnus.el (gnus-valid-select-methods): Add `nnwarchive'.
+
+1999-11-10 12:13:30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnultimate.el (nnultimate-retrieve-headers): Work for multi-page
+       subjects.
+
+1999-11-10 11:33:23  Rajappa Iyer  <rajappa@mindspring.com>
+
+       * gnus-salt.el (gnus-pick-article-or-thread): Don't move point.
+
+1999-11-10 05:22:56  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnultimate.el (nnultimate-open-server): Do address.
+       (nnultimate-forum-table-p): New function.
+
+       * nnweb.el (nnweb-insert-html): Renamed.
+       (nnweb-insert): New function.
+
+       * nnultimate.el (nnultimate-insert-html): New function.
+
+       * nnslashdot.el (nnslashdot-retrieve-headers): Don't do anything
+       if nov is evil.
+       (nnslashdot-retrieve-headers): use the sane version instead.
+
+1999-11-09 00:13:25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnslashdot.el (nnslashdot-request-article): Fold case.
+
+       * nnultimate.el: New file.
+
+       * nnslashdot.el (nnslashdot-retrieve-headers): Skip the article
+       unless wanted.
+
+       * gnus-start.el (gnus-active-to-gnus-format): Catch errors.
+       (gnus-read-active-file-1): Separated into own function.
+       (gnus-read-active-file): Catch quits.
+
+       * nnslashdot.el (nnslashdot-request-article): Search better on
+       first article.
+       (nnslashdot-request-list): Fold case.
+       (nnslashdot-retrieve-headers): Ditto.
+
+1999-11-08 05:33:15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el: Autoload gnus-subscribe-topics.
+
+1999-11-07 22:56:46  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-save-group-info): Remove backslash
+       before dot.
+       * gnus-util.el (gnus-write-active-file): Ditto.
+
+1999-11-07 22:31:10  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnheader.el (nnheader-replace-duplicate-chars-in-string): New
+       function.
+       * gnus-cache.el (gnus-cache-file-name): Use it.
+       * gnus-agent.el (gnus-agent-group-path): Use it.
+       * nnmail.el (nnmail-group-pathname): Use it.
+
+1999-11-07 21:07:55  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-start.el (gnus-active-to-gnus-format): Don't insert backslash
+       if cooked.
+       * gnus-util.el (gnus-write-active-file): Write cooked active file.
+       * gnus-agent.el (gnus-agent-save-group-info): Ditto.
+       * gnus.el (gnus-short-group-name): "..." proof.
+
+1999-11-07 20:03:16  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-srvr.el (gnus-browse-foreign-server): Keep using `read' to
+       support nnslashdot.
+
+1999-11-08 00:06:02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnslashdot.el (nnslashdot-retrieve-headers): Don't fetch too
+       many articles.
+       (nnslashdot-generate-active): New function.
+       (nnslashdot-request-newgroups): Use it.
+
+       * gnus-start.el (gnus-active-to-gnus-format): Intern strings group
+       names.
+
+       * nnslashdot.el (nnslashdot-request-newgroups): New function.
+       (nnslashdot-request-list): Not moderated.
+
+1999-11-07  Simon Josefsson  <jas@pdc.kth.se>
+
+       * nnimap.el (nnimap-open-server): Remove error signal if
+       nnimap-server-buffer is nil (the check should've been `boundp').
+
+       * imap.el (imap-log):
+       * nnimap.el (nnimap-debug): Disable debugging by default.
+
+1999-11-07 01:17:53  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-subscribe-newsgroup-method): Doc fix.
+
+       * gnus-topic.el (gnus-subscribe-topic): New function.
+
+       * nnslashdot.el (nnslashdot-request-list): Give out extended group
+       names.
+
+       * gnus-start.el (gnus-ignored-newsgroups): Disregard bogus chars
+       if starting with a quote.
+
+1999-11-07 13:06:11  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-srvr.el (gnus-browse-foreign-server): Support backslash in
+       group name.
+
+1999-11-07 01:17:53  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnslashdot.el: New file.
+
+       * nnheader.el (nnheader-insert-header): New function.
+
+       * gnus-art.el (gnus-mime-internalize-part): Bind
+       mm-inlined-types.
+
+       * nndraft.el (nndraft-request-expire-articles): Do all the backup
+       files.
+
+1999-10-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * smiley.el (gnus-smiley-display): Use `smiley-toggle-buffer'.
+       (smiley-toggle-buffer): New function.
+       (smiley-buffer): Don't quote the function.
+       (smiley-toggle-extents): Ditto.
+
+1999-11-07 01:00:32  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-topic.el (gnus-topic-goto-missing-topic): Work even in
+       empty buffers.
+
+1999-11-06 23:16:24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-mode-map): Use the summary article
+       edit.
+
+1999-11-06 22:56:49  Jens-Ulrik Petersen  <Jens-Ulrik.Petersen@nokia.com>
+
+       * gnus-group.el (gnus-group-read-ephemeral-group): Doc fix.
+
+1999-11-06 21:40:30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-uu.el (gnus-uu-mark-thread): Don't move point around.
+
+1999-10-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-treat-predicate): Examine whether the argument
+       is list or not before condition.
+
+1999-10-07  Yoshiki Hayashi  <t90553@mail.ecc.u-tokyo.ac.jp>
+
+       * gnus-art.el (gnus-treat-predicate): Work for (typep "something").
+
+1999-11-06 19:18:14  Kevin the Bandicoot  <user42@zip.com.au>
+
+       * gnus-art.el (gnus-emphasis-alist): New value.
+
+1999-11-06 13:57:13  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-srvr.el (gnus-browse-foreign-server): Use both `read' and
+       `buffer-substring'.
+
+1999-11-06 04:24:30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-date-ut): Keep the updated timer.
+       (gnus-emphasis-underline-italic): Doc fix.
+
+       * gnus-msg.el (gnus-post-method): Doc fix.
+       (gnus-post-method): Change default.
+
+1999-11-06 04:12:13  Francisco Solsona  <flsc@hp.fciencias.unam.mx>
+
+       * message.el (message-newline-and-reformat): Improvements.
+
+1999-11-06 03:51:24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-newline-and-reformat): Don't insert too many
+       newlines.
+       (message-newline-and-reformat): Work even if not sc.
+
+       * mm-view.el (mm-inline-message): Insert a delimiter at the end.
+
+       * mm-decode.el (mm-inline-media-tests): Only if diff mode.
+
+1999-11-06 03:48:02  Toby Speight  <Toby.Speight@streapadair.freeserve.co.uk>
+
+       * mm-view.el (mm-display-patch-inline): New function.
+
+1999-11-06 03:47:54  Robert Bihlmeyer  <robbe@orcus.priv.at>
+
+       * mm-view.el (mm-display-patch-inline): New function.
+
+1999-11-06 02:17:54  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-read-move-group-name): Subscribe to the
+       group.
+
+       * message.el (message-forward): Narrow to the right header.
+
+       * gnus-sum.el (gnus-summary-limit-to-age): Protect against bogus
+       dates.
+
+       * gnus-msg.el (gnus-configure-posting-styles): Use the
+       user-full-name function.
+
+       * mm-bodies.el (mm-body-encoding): Use the choosing function.
+       (mm-body-charset-encoding-alist): Default to nil.
+
+       * message.el (message-elide-ellipsis): Fix typo.
+       (message-elide-region): Ditto.
+       (message-elide-region): Don't insert a newline first.
+
+1999-11-05 20:28:27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-cut-thread): Also cut for numberp
+       gnus-fetch-old-headers.
+       (gnus-cut-threads): Ditto.
+       (gnus-summary-initial-limit): Ditto.
+       (gnus-summary-limit-children): Ditto.
+
+       * gnus-msg.el (gnus-configure-posting-styles): Allow `header'
+       matches.
+
+1999-11-06  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-art.el (article-decode-encoded-words):
+       (gnus-mime-display-single): Don't assume gnus-summary-buffer is
+       live.
+
+       * gnus.el (gnus-read-method): Add methods from
+       `gnus-opened-servers' to completion. Map entered method/address
+       into existing methods if possible.
+
+       * gnus-group.el (gnus-group-make-group): Simplify method.
+
+       * gnus-srvr.el (gnus-browse-unsubscribe-group): Simplify method.
+
+       * mml.el (mml-preview): Remove mail-header-separator before
+       encoding.
+
+1999-11-05 20:28:27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-read-from-minibuffer): New function.
+
+Fri Nov  5 19:10:02 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.98 is released.
+
+1999-11-05 01:27:49  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-expire): Remove bad line in NOV.
+
+1999-11-04 22:20:35  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-generate-mime-1): Read attached binary file in
+       binary mode.
+
+1999-11-03 16:08:56  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-toggle-header): Fix arg bug.
+
+1999-11-03 15:27:38  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mailcap.el (mailcap-viewer-lessp): Fix bug.
+
+1999-11-02 17:28:33  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-search-article): Fix loop search bug.
+
+1999-10-31 21:24:59  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-mime-match-handle-first): New function.
+       (gnus-article-mime-match-handle-function): New variable.
+       (gnus-article-view-part): Make `b' customizable.
+
+1999-10-29 14:30:07  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-article-get-xrefs): Test eobp.
+
+1999-09-27  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * mm-decode.el (mm-attachment-override-types): Exclude text/plain.
+
+1999-10-26 23:27:44  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-dissect-buffer): CTE may come without CTL.
+
+1999-10-26 21:44:05  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-srvr.el (gnus-browse-foreign-server): Use
+       `buffer-substring' instead of `read'.
+
+1999-10-23  Simon Josefsson  <jas@pdc.kth.se>
+
+       * nnimap.el, imap.el, rfc2104.el: New files.
+
+       * gnus.el (gnus-valid-select-methods): Add nnimap.
+
+       * gnus-group.el (gnus-group-group-map): Add
+       gnus-group-nnimap-edit-acl, gnus-group-nnimap-expunge.
+       (gnus-group-nnimap-expunge): New function.
+       (gnus-group-nnimap-edit-acl): New function.
+
+       * gnus-agent.el (gnus-agent-group-mode-map): Add
+       gnus-agent-synchronize.
+       (gnus-agent-synchronize): New function.
+       (gnus-agent-fetch-group-1): Check if server is open.
+
+       * nnagent.el (nnagent-request-set-mark): Save marks.
+
+       * mail-source.el (mail-source-keyword-map): New imap mail-source.
+       (mail-source-fetcher-alist): Map to imap fetcher function.
+       (mail-source-fetch-imap): New function.
+
+       * gnus-art.el (article-hide-pgp): Hide all headers, not just
+       Hash:.
+
+1999-10-22 11:03:00  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-topic.el (gnus-topic-sort-topics-1): New function.
+       (gnus-topic-sort-topics): New function.
+       (gnus-topic-make-menu-bar): Add sort-topics.
+       (gnus-topic-move): New function.
+       (gnus-topic-move-group): Move the topic if no group selected.
+
+1999-10-13 21:31:50  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-setup-buffer): Fix buffer leak.
+
+1999-10-13 12:52:18  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-view.el (mm-inline-message): Fix leaving group bug.
+
+1999-10-07 17:59:49  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-post-method): Use normal method if current is
+       not available.
+
+1999-10-07 17:09:34  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnmail.el (nnmail-insert-xref): Dealing with empty articles.
+       (nnmail-insert-lines): Ditto.
+
+1999-10-07  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnfolder.el (nnfolder-insert-newsgroup-line): Insert a blank
+       line.
+
+       * message.el (message-unsent-separator): One more separator.
+
+1999-10-06  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnfolder.el (nnfolder-request-move-article): For empty article,
+       search till (point-max).
+       (nnfolder-retrieve-headers): Ditto.
+       (nnfolder-request-accept-article): Ditto.
+       (nnfolder-save-mail): Ditto.
+       (nnfolder-insert-newsgroup-line): Ditto.
+
+1999-10-05  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * qp.el (quoted-printable-encode-region): Check eobp.
+
+1999-10-03  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nntp.el (nntp-retrieve-headers-with-xover): Fix hanging problem.
+
+1999-10-02  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nntp.el (nntp-send-xover-command): Wait for nothing if not
+       wait-for-reply.
+
+1999-09-29  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-uu.el (mm-uu-forward-begin-line): Change the regexp.
+       (mm-uu-forward-end-line): Ditto.
+
+1999-09-29  Didier Verna  <verna@inf.enst.fr>
+
+       * binhex.el (binhex-decode-region): don't consider the value of
+       `enable-multibyte-characters' in XEmacs.
+
+       * gnus-start.el (gnus-read-descriptions-file): ditto.
+
+       * mm-util.el (mm-multibyte-p): ditto.
+       (mm-with-unibyte-buffer): ditto.
+       (mm-find-charset-region): use `mm-multibyte-p'.
+
+       * mm-bodies.el (mm-decode-body): ditto.
+       (mm-decode-string): ditto.
+
+       * lpath.el ((string-match "XEmacs" emacs-version)): Don't define
+       `enable-multibyte-characters' in XEmacs.
+
+1999-09-29  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-binary-coding-system): Try binary first.
+
+1999-09-14  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc1843.el (rfc1843-decode-article-body): Don't decode twice.
+
+1999-09-10  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-make-date-line): Add time-zone in iso8601
+       format.
+       (article-date-ut): Find correct insert position.
+
+1999-09-03  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-uu.el (mm-uu-dissect): Do not dissect quoted-printable
+       forwarded message.
+
+1999-09-27 20:33:41  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-topic.el (gnus-topic-find-groups): Work for unactivated
+       groups.
+
+       * message.el (message-resend): Use message mode when prompting.
+
+       * gnus-art.el (article-hide-headers): Mark wash.
+       (article-emphasize): Ditto.
+
+1999-09-27 19:52:14  Vladimir Volovich  <vvv@vvv.vsu.ru>
+
+       * message.el (message-newline-and-reformat): Work for SC.
+
+1999-09-27 19:38:33  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-group-posting-charset-alist): 2047 in de.*.
+
+       * gnus-sum.el (gnus-newsgroup-ignored-charsets): Add x-unknown.
+
+1999-10-20  David S. Goldberg  <dsg@mitre.org>
+
+       * mm-decode.el (mm-inline-override-types): New variable.
+
+       * mm-decode.el (mm-inline-override-p): New function.
+
+       * mm-decode.el (mm-inlined-p): Use it.
+
+1999-10-20  David S. Goldberg  <dsg@mitre.org>
+
+       * mm-decode.el (mm-inline-override-types): New variable.
+
+       * mm-decode.el (mm-inline-override-p): New function.
+
+       * mm-decode.el (mm-inlined-p): Use it.
+
+Mon Sep 27 15:18:05 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.97 is released.
+
+1999-09-01  Brendan Kehoe  <brendan@zen.org>
+
+       * gnus-sum.el (gnus-summary-catchup-and-goto-next-group): Use
+       gnus-summary-next-group, not gnus-summary-next-article.  Only give
+       3 args.
+
+1999-09-25 08:07:57  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-agent.el (gnus-agent-fetch-group-1): Look in the group
+       buffer for params.
+
+       * gnus-xmas.el (gnus-xmas-summary-recenter): Display one more
+       line.
+
+       * message.el (message-forward-ignored-headers): New variable.
+
+       * gnus-art.el (gnus-article-prepare-display): Nix out
+       gnus-article-wash-types.
+
+       * gnus-agent.el (gnus-agent-create-buffer): New function.
+       (gnus-agent-fetch-group-1): Use it.
+       (gnus-agent-start-fetch): Ditto.
+
+       * gnus-sum.el (gnus-summary-exit): Don't use
+       `gnus-use-adaptive-scoring'.
+
+       * mail-source.el (mail-source-fetch-pop): Only store password when
+       successful.
+
+       * gnus-nocem.el (gnus-nocem-scan-groups): Message better.
+
+1999-09-24 18:43:23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-reply): Use it.
+       (message-dont-reply-to-names): New variable.
+
+       * nntp.el (nntp-open-telnet): Don't erase-buffer.
+
+       * mm-util.el (mm-preferred-coding-system): Typo fix.
+
+       * message.el (message-bounce): Work for non-MIME.
+
+       * gnus.el (gnus-short-group-name): Short the right parts of the
+       name.
+
+1999-09-24 18:17:48  Johan Kullstam  <kullstam@ne.mediaone.net>
+
+       * mm-encode.el (mm-qp-or-base64): New version.
+
+1999-09-10  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-make-date-line): Fix time-zone bug.
+
+1999-09-09  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-add-buttons): Don't delete markers out
+       of restricted region.
+       (gnus-mime-display-single): Set beg at correct point.
+
+1999-09-09  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnmail.el (nnmail-process-maildir-mail-format): Typo.
+
+1999-09-09  Jens-Ulrik Petersen  <jens-ulrik.petersen@nokia.com>
+
+       * gnus-msg.el (gnus-configure-posting-styles): Let
+       `gnus-posting-styles' have its say in posting-style: local
+       variable `styles' is already bound to `gnus-posting-styles' so
+       don't rebind it to nil.
+
+1999-09-24 18:10:56  Robert Bihlmeyer  <robbe@orcus.priv.at>
+
+       * gnus-score.el (gnus-summary-increase-score): Allow editing of
+       Message-ID.
+
+1999-09-08  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-encode.el (mm-encode-content-transfer-encoding): Fold
+       quoted-printable-encode-region.
+
+       * qp.el (quoted-printable-encode-region): Assume charset
+       encoded. Fold every line in the region.
+
+1999-09-02  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-srvr.el (gnus-browse-foreign-server): Read the first line
+       of active file.
+
+1999-09-01  Didier Verna  <verna@inf.enst.fr>
+
+       * message.el (message-mode): allows whitespaces between multiple
+       instances of the fill character ">".
+
+1999-09-24 18:02:50  Kim-Minh Kaplan  <kmkaplan@vocatex.fr>
+
+       * mm-encode.el (mm-qp-or-base64): Fix.
+
+1999-09-01 12:18:01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-send): Too much and.
+
+1999-09-24 17:58:07  Andreas Schwab  <schwab@suse.de>
+
+       * gnus-art.el (gnus-mime-view-part-as-type): Renamed.
+
+1999-08-28 12:44:20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-score.el (gnus-score-headers): Work for nil scores.
+
+1999-08-27 20:46:11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-cache.el (gnus-cache-write-active): Write full names.
+
+       * gnus-util.el (gnus-write-active-file): Accept full name.
+
+       * mm-decode.el (mm-inlinable-p): Use string-match on the types.
+       (mm-assoc-string-match): New function.
+       (mm-display-inline): Use it.
+
+       * gnus-group.el (gnus-group-set-info): Work for nil group params.
+
+       * gnus-msg.el (gnus-configure-posting-styles): Allow eval.
+
+1999-08-27 19:08:10  Florian Weimer  <fw@s.netic.de>
+
+       * mml.el (mml-generate-multipart-alist): New variable.
+
+1999-08-27 15:30:02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-treat-predicate): Work for (not 5).
+
+1999-08-27  Peter von der Ahe  <pahe@daimi.au.dk>
+
+       * message.el (message-send): More helpful error message if sending
+       fails.
+
+1999-09-06  Robert Bihlmeyer  <robbe@orcus.priv.at>
+
+       * gnus-score.el (gnus-summary-increase-score): "Lars" was broken
+       in newer emacsen, where ?r isn't equal 114.
+
+Fri Aug 27 13:17:48 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.96 is released.
+
+1999-08-17  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-start.el (gnus-groups-to-gnus-format): Only use agent
+       to get active info if method is covered by agent, otherwise
+       active info is lost.
+
+1999-08-17  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-sum.el (gnus-summary-move-article): Report backend errors.
+
+1999-08-09  Dave Love  <fx@gnu.org>
+
+       * mm-util.el: Use `defalias', not `fset' for dummy functions.
+
+1999-08-09  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-art.el (gnus-ignored-headers): Remove "X-Pgp-*"
+       (already matched by "^X-Pgp"), removed duplicate
+       X-Mailing-List, added several new junk headers.
+
+1999-08-01  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-art.el (article-decode-charset): Don't assume
+       gnus-summary-buffer is live.
+
+1999-08-27 15:07:43  Paul Flinders  <paul@dawa.demon.co.uk>
+
+       * smiley.el (smiley-deformed-regexp-alist): Fix % smileys.
+
+1999-08-27 15:02:58  Florian Weimer  <fw@s.netic.de>
+
+       * gnus-score.el (gnus-home-score-file): Work with absolute path
+       names.
+
+1999-07-17  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-articles-to-read): Return cached articles if
+       nothing else in the group.
+
+1999-07-16  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-bcklg.el (gnus-backlog-enter-article): Check the size of
+       the article.
+
+1999-07-15  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-uu.el (mm-uu-dissect): Fix for base64 message.
+
+1999-07-15  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-uu.el (mm-uu-forward-end-line): Support forwarded message
+       from mutt.
+
+1999-07-14  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding): Delete
+       whitespace.
+
+1999-07-14  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-text-coding-system-for-write): New variable.
+       (mm-append-to-file): New function.
+       (mm-write-region): New function.
+
+       * gnus-art.el (gnus-output-to-file): Use it.
+       * gnus-util.el (gnus-output-to-rmail): Ditto.
+       (gnus-output-to-mail): Ditto.
+       * gnus-uu.el (gnus-uu-binhex-article): Ditto.
+
+1999-07-14  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnmail.el (nnmail-find-file): Use mm-auto-mode-alist.
+
+       * nnheader.el (nnheader-insert-file-contents): Revert and use
+       mm-insert-file-contents.
+       (nnheader-find-file-noselect): Use mm-auto-mode-alist.
+       (nnheader-auto-mode-alist): Removed.
+
+       * mm-util.el (mm-inhibit-file-name-handlers): New variable.
+       (mm-insert-file-contents): Add a new parameter for inserting
+       compressed file literally.
+
+       * mml.el (mml-generate-mime-1): Insert non-text literally.
+
+       * gnus.el: Change most mm-insert-file-contents back to nnheader.
+
+1999-07-13  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * gnus-art.el (gnus-unbuttonized-mime-types): Fix docstring.
+
+1999-08-27 14:53:42  Oleg S. Tihonov  <ost@benetnash.ffke-campus.mipt.ru>
+
+       * gnus-sum.el (gnus-group-charset-alist): Default fido7 to
+       koi8-r.
+
+1999-07-11  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-insert-mime): Decode text.
+       (mml-to-mime): Narrow to headers-or-head.
+
+1999-07-11  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-view.el (mm-inline-text): Check
+       w3-meta-content-type-charset-regexp.
+
+1999-07-10  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-agent.el (gnus-agent-fetch-group-1): Search topics for
+       predicate.
+
+1999-07-10  Alexandre Oliva  <oliva@dcc.unicamp.br>
+
+       * gnus-mlspl.el: Documentation fixes.
+
+1999-08-27 14:42:14  Rui Zhu  <sprache@iname.com>
+
+       * gnus-sum.el (gnus-summary-limit-to-age): Prompt better.
+
+1999-08-27 14:40:52  Michael Cook  <cook@sightpath.com>
+
+       * gnus-art.el (gnus-article-setup-buffer): Kill all local
+       variables.
+
+1999-08-27 14:39:34  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * nnmail.el (nnmail-get-new-mail): "Done".
+
+1999-08-27 14:38:14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-kill-all-zombies): Only prompt when
+       interactive.
+
+1999-07-12  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-decode-charset): Fix broken CT.
+
+1999-07-12  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-fetch-group-1): Recreate agent
+       overview buffer if it is killed.
+
+1999-08-27 14:26:03  Eric Marsden  <emarsden@mail.dotcom.fr>
+
+       * gnus-art.el (article-babel): New version.
+
+1999-08-27 14:22:39  Jon Kv  <jonkv@ida.liu.se>
+
+       * nnfolder.el (nnfolder-request-list-newsgroups): Faster expiry.
+
+1999-07-11  Andreas Jaeger  <aj@arthur.rhein-neckar.de>
+
+       * gnus-uu.el (gnus-uu-digest-mail-forward): Delete file after
+       usage.
+
+1999-07-10  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-running-xemacs): Removed.
+       (mm-coding-system-p): New function.
+       (mm-binary-coding-system): Safe guess.
+       (mm-text-coding-system): Ditto.
+       (mm-auto-save-coding-system): Ditto.
+
+1999-07-11 11:02:03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-encode.el (mm-qp-or-base64): Also consider control chars.
+       (mm-qp-or-base64): Reversed logic.
+
+       * mm-decode.el (mm-save-part-to-file): Let coding system be
+       binary.
+
+1999-07-15  Mike McEwan  <mike@lotusland.demon.co.uk>
+
+       * gnus-agent.el (gnus-agent-fetch-group-1): Allow 'agent-score' to
+       be set in topic parameters.
+
+1999-07-10  Mike McEwan  <mike@lotusland.demon.co.uk>
+
+       * gnus-sum.el (gnus-sort-gathered-threads-function): New variable.
+       (gnus-sort-gathered-threads): Allow the user to specify the
+       function to use when sorting gathered threads.
+
+       * gnus-agent.el (gnus-agent-get-undownloaded-list): Don't
+       mark cached articles as `undownloaded'.
+
+Tue Jul 20 02:39:56 1999  Peter von der Ahe  <peter@ahe.dk>
+
+       * gnus-sum.el (gnus-summary-exit): Allow gnus-use-adaptive-scoring
+       to have buffer local values.
+
+1999-07-25  Matt Pharr  <mmp@graphics.stanford.edu>
+
+       * gnus-group.el (gnus-group-make-doc-group): Notice when user
+       types 'g' for 'guess group type.
+
+1999-07-30  Simon Josefsson  <jas@pdc.kth.se>
+
+       * nnmail.el (nnmail-remove-list-identifiers): Remove whitespace
+       after each regexp in nnmail-list-identifiers, not just after last
+       one.
+
+       * gnus-sum.el (gnus-list-identifiers): New variable.
+       (gnus-summary-remove-list-identifiers): New function.
+       (gnus-select-newsgroup): Use it.
+       (gnus-summary-wash-hide-map): Bind
+       `gnus-article-hide-list-identifiers' to W W l.
+       (gnus-summary-make-menu-bar): Add list-identifiers command.
+
+       * gnus-art.el (gnus-treat-strip-list-identifiers): New variable.
+       (gnus-treatment-function-alist): Add variable.
+       (article-hide-list-identifiers): New function.
+       (mapcar): Add function.
+       (gnus-article-hide): Use it.
+
+Fri Jul  9 22:21:16 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.95 is released.
+
+1999-07-09 21:46:05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-mailcap-command): New function.
+       (mm-display-external): Use it.
+
+       * gnus-art.el (article-make-date-line): Work for India.
+
+       * mm-encode.el (mm-qp-or-base64): Typo.
+
+       * gnus-topic.el (gnus-topic-goto-topic): Made into command.
+
+Fri Jul  9 19:28:29 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.94 is released.
+
+1999-07-09 21:19:23  Stainless Steel Rat  <ratinox@peorth.gweep.net>
+
+       * pop3.el: New version.
+
+1999-07-09 20:01:44  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-encode.el (mm-qp-or-base64): New function.
+       (mm-content-transfer-encoding): Use it.
+
+       * gnus-util.el (gnus-parse-netrc): Allow quoted names.
+
+1999-07-08  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-display-external): Fix typo and use 'non-viewer.
+
+       * mailcap.el (mailcap-mailcap-entry-passes-test): Add needsterminal.
+
+1999-07-09 18:52:22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-mime-view-part-as-media): New command and
+       keystroke.
+
+       * mailcap.el (mailcap-mime-types): New function.
+
+       * nnmh.el (nnmh-request-group): Update nnmh-group-alist.
+
+       * message.el (message-goto-eoh): Really go to the end.
+
+1999-07-09 18:40:23  Puneet Goel  <puneet@computer.org>
+
+       * message.el (message-make-date): Do the right thing in with
+       sub-hour time zones.
+
+1999-07-09 18:36:21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-make-menu-bar): Removed double bug
+       report.
+
+1999-07-08  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnfolder.el (nnfolder-request-rename-group): Create directory.
+
+1999-07-08  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mailcap.el (mailcap-parse-mailcap): Skip \;.
+       (mailcap-parse-mailcap-extras): Fix "nonterminal;" and empty name,
+       and use t as default value.
+
+Wed Jul  7 18:40:30 1999  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-get-newsgroup-headers): Don't assume
+       gnus-summary-buffer is live.
+
+1999-07-09 17:44:03  Robert Pluim  <rpluim@nortelnetworks.com>
+
+       * mm-util.el (mm-enable-multibyte): Check whether var bound.
+
+1999-07-09 17:31:39  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-bounce): Do MIME bounces MIMEy.
+
+       * gnus-sum.el (gnus-summary-read-group-1): Update mark positions.
+
+1999-07-08 08:41:10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mailcap.el (mailcap-mime-extensions): Changed patch to
+       text/x-patch.
+
+       * mm-decode.el (mm-display-external): Wrong placement of paren.
+
+Wed Jul  7 13:09:51 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.93 is released.
+
+1999-07-08  Alexandre Oliva  <oliva@dcc.unicamp.br>
+
+       * gnus-cus.el (gnus-group-parameters): New entries for
+       gnus-group-split.
+
+       * gnus-mlspl.el: Renamed functions and variables so as to
+       start with gnus-group-split.
+       * gnus.el: Adjust autoload entries.
+
+1999-07-07  Alexandre Oliva  <oliva@dcc.unicamp.br>
+
+       * gnus-mlspl.el: Removed trailing t from comment and provide.
+       Renamed functions and variables to start with gnus-mlsplit.
+       Added autoload comments.
+       * gnus.el: Added autoload entries.
+
+1999-07-06 05:37:46  Alexandre Oliva  <oliva@dcc.unicamp.br>
+
+       * nnmail.el (nnmail-split-it): Search the regexp multiple times,
+       so that matches excluded by RESTRICTs do not cause the whole split
+       to be ignored.  This also fixes a long-standing bug in which a
+       split with \N substitutions wouldn't cause cross-posting as
+       expected.
+
+       * nnmail.el (nnmail-split-fancy): Document RESTRICT clauses.
+       (nnmail-split-it): Implement them.
+
+       * nnmail.el (nnmail-split-fancy): Document ! splits.
+
+1999-07-07 10:41:11  Stainless Steel Rat  <ratinox@peorth.gweep.net>
+
+       * pop3.el: New version.
+
+1999-07-05  Simon Josefsson
+
+       * gnus-srvr.el (gnus-browse-foreign-server): Use read.
+
+1999-07-07 10:37:26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-mime-display-alternative): Do treatment.
+
+1999-07-06  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-util.el (gnus-write-active-file): Use real name.
+
+       * gnus-agent.el (gnus-agent-expire): Update active file
+       method by method.
+
+1999-07-06  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nndraft.el (nndraft-request-article): Use difference
+       coding-systems for queue and drafts.
+
+       * gnus-sum.el (gnus-summary-setup-default-charset): Special-case
+       nndraft:drafts.
+
+       * mm-util.el (mm-auto-save-coding-system): New coding system.
+
+       * message.el (message-draft-coding-system): Use it.
+
+1999-07-06  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-uu.el: More customizable and less aggressive.
+
+1999-07-07 07:53:23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-groups-to-gnus-format): Only gnus-active
+       when plugged.
+
+       * mml.el (mml-generate-mime-1): Don't insert nofile files.
+       (mml-insert-mml-markup): Accept a nofile.
+       (mml-insert-mime): Insert nofile.
+
+       * gnus-art.el (gnus-treat-strip-blank-lines): Removed.
+
+       * mm-decode.el (mm-handle-media-type): New function.
+       (mm-handle-media-supertype): New function.
+       (mm-handle-media-subtype): New function.
+       Use new functions throughout. "/"))
+
+1999-05-18 03:03:50  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-treat-predicate): Typo.
+
+1999-07-07 06:21:36  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-score.el (gnus-summary-score-entry): Made un-interactive.
+
+1999-07-06 17:57:16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-date-ut): UT!  Default it!
+
+Tue Jul  6 10:59:24 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.92 is released.
+
+1999-07-06 12:30:59  Johannes Weinert  <Johannes.Weinert@Informatik.Uni-Oldenburg.DE>
+
+       * gnus-sum.el (gnus-summary-catchup-and-exit): Doc fix.
+
+1999-07-06 07:41:07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nntp.el (nntp-retrieve-groups): Don't do anything when not
+       connected.
+
+       * gnus-start.el (gnus-active-to-gnus-format): Only save active
+       when plugged.
+
+       * mm-view.el (mm-inline-message): Ignore remove-spec.
+
+       * gnus-agent.el (gnus-agent-write-active): Check whether orig sym
+       is bound.
+
+       * gnus-msg.el (gnus-summary-mail-forward): Rename From_ lines.
+
+       * nndoc.el (nndoc-guess-type): Remove blank lines at the start.
+
+       * nnfolder.el (nnfolder-read-folder): Remove blank lines at the
+       start.
+
+       * message.el (message-fill-yanked-message): Remove `t' arg.
+
+       * gnus-group.el (gnus-group-kill-group): Message killing of
+       groups.
+
+       * mm-util.el (mm-preferred-coding-system): New function.
+       (mm-mime-charset): Use it.
+
+       * mml.el (mml-generate-mime-1): Charset-encode message parts.
+
+1999-07-06 07:03:31  Alexandre Oliva  <oliva@dcc.unicamp.br>
+
+       * gnus-mlsplt.el: New file.
+
+1999-07-06 05:47:57  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-inline-Media-tests): Changed from forms to
+       functions.
+       (mm-attachment-override-p): Take a handle instead of a type.
+       (mm-inlined-p): Ditto.
+       (mm-automatic-display-p): Ditto.
+       (mm-inlinable-p): Ditto.
+
+       * nndraft.el (nndraft-request-expire-articles): Delete backup
+       files.
+
+       * mailcap.el (mailcap-parse-mailcap): Regexp-quote stuff.
+
+       * gnus-sum.el (gnus-summary-limit-to-extra): Typo.
+
+1999-07-06 05:37:46  Alexandre Oliva  <oliva@dcc.unicamp.br>
+
+       * nnmail.el (nnmail-split-it): Allow .*.
+
+1999-07-05 05:04:57  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-inline-large-images-p): Renamed.
+
+       * gnus-art.el (article-date-ut): Always look in the current buffer
+       for the Date header.
+
+       * mml.el (mml-validate): New command.
+
+       * mailcap.el (mailcap-possible-viewers): Revert to string-match
+       since we are dealing with regexps.
+
+Sun Jul  4 06:31:01 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.91 is released.
+
+1999-07-04 04:35:28  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-agent.el (gnus-agent-save-active-1): New function.
+       (gnus-agent-save-active): use it.
+       (gnus-agent-save-groups): Ditto.
+
+       * gnus-cache.el (gnus-cache-write-active): Use it.
+
+       * gnus-agent.el (gnus-agent-write-active): Use it.
+
+       * gnus-util.el (gnus-write-active-file): New function.
+
+       * gnus-agent.el (gnus-agent-write-active): New function to keep
+       lower boundaries and canceled groups.
+       (gnus-agent-save-groups): Use it.
+       (gnus-agent-save-active): Use it.
+       (gnus-agent-save-group-info): Only write active files.
+       (gnus-agent-expire): Update active file.
+
+       * mm-decode.el (mm-inlinable-part-p): Removed.
+       (mm-user-display-methods): Default to nil.
+       (mm-user-display-methods): Removed.
+       (add-mime-display-method): Removed.
+       (mm-automatic-display): Renamed.
+       (mm-automatic-display-p): Use it.
+       (mm-inlined-types): New variable.
+       (mm-inlined-p): New function.
+
+       * message.el (message-reply): Bind message-this-is-mail.
+
+1999-07-03 13:16:31  Michael Klingbeil  <mklingbeil@knuut.de>
+
+       * smiley.el (smiley-buffer): Fix for NT.
+
+1999-07-03 11:26:47  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-encode.el (mm-encode-buffer): Check whether we have 7bit.
+
+       * message.el (message-check-news-header-syntax): Protect against
+       nil froms.
+
+       * mm-util.el (mm-auto-mode-alist): New.
+
+       * mml.el (mml-generate-mime-1): Ditto.
+
+       * gnus.el: Use mm-insert-file-contents throughout instead of
+       nnheader.
+
+       * mm-util.el (mm-insert-file-contents): New function.
+
+Sat Jul  3 07:35:35 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.90 is released.
+
+1999-07-03 09:31:10  Sven Fischer  <herpes@kawo2.rwth-aachen.de>
+
+       * mailcap.el (mailcap-possible-viewers): Use string=.
+
+1999-07-01  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-uu.el (mm-uu-forward-begin-line): New variable.
+       (mm-uu-forward-end-line): New variable.
+       (mm-uu-begin-line): Handle forwarded message.
+       (mm-uu-identifier-alist): Ditto.
+       (mm-uu-dissect): Ditto.
+
+1999-06-29  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * lpath.el: Two free variables.
+
+1999-07-02  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnheader.el (nnheader-file-coding-system): Use raw-text.
+       * gnus-agent.el (gnus-agent-file-coding-system): Ditto.
+       * gnus-cache.el (gnus-cache-coding-system): Ditto.
+
+       * nnfolder.el (nnfolder-file-coding-system): Use mm-text-coding-system.
+       (nnfolder-file-coding-system-for-write): New variable.
+       (nnfolder-active-file-coding-system): New variable.
+       (nnfolder-active-file-coding-system-for-write): New variable.
+       (nnfolder-save-active): New function.
+       (nnfolder-save-buffer): Use them.
+       (nnfolder-possibly-change-group): Ditto.
+       (nnfolder-request-list-newsgroups): Ditto.
+       (nnfolder-request-create-group): Ditto.
+       (nnfolder-request-expire-articles): Ditto.
+       (nnfolder-request-move-article): Ditto.
+       (nnfolder-request-accept-article): Ditto.
+       (nnfolder-request-delete-group): Ditto.
+       (nnfolder-request-rename-group): Ditto.
+       (nnfolder-possibly-change-folder): Ditto.
+       (nnfolder-read-folder): Ditto.
+       (nnfolder-request-list): Remove pathname-coding-system.
+       (nnfolder-possibly-change-group): Use nnmail-pathname-coding-system.
+
+       * nnmail.el (nnmail-file-coding-system): Use raw-text.
+       (nnmail-file-coding-system-1): Removed.
+       (nnmail-find-file): Use nnmail-pathname-coding-system.
+       (nnmail-write-region): Ditto.
+
+       * nnmbox.el (nnmbox-file-coding-system): New variable.
+       (nnmbox-file-coding-system-for-write): New variable.
+       (nnmbox-active-file-coding-system): New variable.
+       (nnmbox-active-file-coding-system-for-write): New variable.
+       (nnmbox-save-buffer): New function.
+       (nnmbox-save-active): New function.
+       (nnmbox-request-scan): Use them.
+       (nnmbox-request-expire-articles): Ditto.
+       (nnmbox-request-move-article): Ditto.
+       (nnmbox-request-accept-article): Ditto.
+       (nnmbox-request-replace-article): Ditto.
+       (nnmbox-request-delete-group): Ditto.
+       (nnmbox-request-rename-group): Ditto.
+       (nnmbox-request-create-group): Ditto.
+
+       * mm-util.el (mm-text-coding-system): raw-text or -dos.
+       (mm-running-ntemacs): Removed.
+
+       * nnml.el (nnml-file-coding-system): Use nnmail-file-coding-system.
+
+1999-07-02  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnfolder.el (nnfolder-read-folder): Use nnheader-file-coding-system.
+
+1999-07-01  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * qp.el (quoted-printable-encoding-characters): Support lower case.
+
+1999-07-01  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-encode): Fold before B-encoding.
+       (rfc2047-b-encode-region): Encode line by line.
+
+1999-07-03 09:20:16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-util.el (mm-find-mime-charset-region): Fix.
+
+1999-06-30  KOSEKI Yoshinori  <kose@yk.NetLaputa.ne.jp>
+
+       * mm-util.el (mm-mime-mule-charset-alist): Fix iso-2022-jp(-2) bug.
+       (mm-find-mime-charset-region): Ditto.
+
+1999-07-03 09:15:35  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-sum.el (gnus-summary-move-article): Fix something or
+       other.
+
+1999-06-29  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-newsgroup-ephemeral-charset): New variable.
+       (gnus-newsgroup-ephemeral-ignored-charsets): New variable.
+       (gnus-summary-enter-digest-group): Use them.
+       (gnus-summary-setup-default-charset): Ditto.
+
+1999-06-15  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * base64.el (base64-run-command-on-region): Use unibyte buffer.
+
+1999-06-15  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-configure-posting-styles): Fix bug when
+       gnus-newsgroup-name is nil.
+
+1999-06-15  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-encode): Chop the tail newline.
+
+1999-06-15  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-emphasize): Use correct
+       gnus-article-emphasis-alist.
+
+1999-06-15  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-view.el (mm-inline-text): Fix text/html bug.
+
+Mon Jun 28 17:54:01 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.89 is released.
+
+1999-06-24  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnmail.el (nnmail-file-coding-system-1): For NTEmacs in Windows.
+       * message.el (message-draft-coding-system): Ditto.
+       * mm-util.el (mm-running-ntemacs): Ditto.
+
+1999-06-23  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-xmas.el (gnus-xmas-summary-recenter): A blank line may
+       cause problem.
+
+1999-06-23  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-view.el (mm-inline-text): Ignore error in w3-region.
+
+1999-06-23  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el: require mm-decode.
+
+1999-06-23  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-display-mime): Treat as head only if necessary.
+
+1999-06-23  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-view.el (mm-inline-image): Fix image undisplayer.
+
+1999-06-22  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-insert-multipart): Error in compeling-read.
+       (mml-insert-tag): Match tags.
+
+1999-06-19  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-cache.el (gnus-cache-braid-nov): Fix coding-system bug.
+       (gnus-cache-braid-heads): Ditto.
+       (gnus-cache-retrieve-headers): Ditto.
+
+1999-06-16  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-draft.el (gnus-draft-send): Fix encoding bug.
+
+1999-06-16 10:17:29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-read-summary-keys): Convert key events
+       to string under XEmacs.
+
+1999-06-28 19:34:03  Petersen Jens-Ulrik  <jens-ulrik.petersen@nokia.com>
+
+       * gnus-start.el (gnus-find-new-newsgroups): Doc fix.
+
+1999-06-22  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-view.el (mm-inline-message): Fix message view bug.
+       * gnus-art.el (gnus-article-prepare): Ditto.
+
+1999-06-16  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-cache.el (gnus-cache-possibly-enter-article): Fetch headers.
+
+Tue Jun 15 04:13:01 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.88 is released.
+
+1999-06-15 04:13:45  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-save-parts): Destroy handles after
+       usage.
+
+       * nnmail.el (nnmail-get-new-mail): Save info.
+
+Mon Jun 14 01:15:59 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.87 is released.
+
+1999-06-14 02:46:05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-fetch-file): Use prescript-delay.
+       (mail-source-run-script): New function.
+       (mail-source-fetch-pop): Use it.
+
+1999-06-13 09:52:11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-setup-highlight-words): Moved here.
+
+Sun Jun 13 07:30:40 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.86 is released.
+
+1999-06-13 08:51:25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-treat-translate): New variable.
+       (gnus-treat-predicate): Accept a list of regexps.
+       (gnus-article-treat-custom): Allow a list of regexps.
+
+1999-06-09  Markus Rost  <markus.rost@mathematik.uni-regensburg.de>
+
+       * gnus-group.el (gnus-permanently-visible-groups): Fix custom type.
+
+1999-06-13 05:15:52  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-babel): Narrow a bit.
+
+       * gnus-agent.el (gnus-agent-get-undownloaded-list): Was too slow.
+
+1999-06-12  Simon Josefsson  <jas@pdc.kth.se>
+
+       (gnus-agent-get-undownloaded-list): Operate on all articles, not
+       only unread ones.
+       (gnus-agent-fetch-headers): Fetch headers from unread and marked
+       articles, not only unread ones.
+
+1999-06-13 03:01:35  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-limit-to-extra): New command and
+       keystroke.
+
+       * gnus-art.el (gnus-article-x-face-command): Ditto.
+
+       * gnus-uu.el (gnus-uu-default-view-rules): Default to "display".
+
+       * gnus.el (gnus-method-simplify): Accept server names.
+
+1999-06-13 02:36:15  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus-art.el (article-babel-prompt): New function.
+       (article-babel): New command.
+
+1999-06-13 01:01:52  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-part-wrapper): Go to part.
+
+       * mml.el (mml-generate-mime-1): Don't insert literally.
+
+       * gnus-util.el (gnus-parse-netrc): Skip lines with #'s.
+       (gnus-netrc-syntax-table): Removed.
+       (gnus-parse-netrc): Don't use syntax table; just use whitespace.
+
+Wed May  5 13:51:13 1999  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-view.el (mm-inline-text): Fix charset for text/html.
+
+Wed May  5 01:15:08 1999  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-draft-coding-system): Use emacs-mule-dos.
+
+1999-06-12 07:29:39  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnmail.el (nnmail-split-incoming): Return the number of split
+       mails.
+       (nnmail-process-babyl-mail-format): Ditto.
+       (nnmail-process-unix-mail-format): Ditto.
+       (nnmail-process-mmdf-mail-format): Ditto.
+       (nnmail-process-maildir-mail-format): Ditto.
+
+       * mail-source.el (mail-source-callback): Return the number from
+       the callback.
+
+       * message.el (message-send-mail): Generate Lines.
+
+       * mail-source.el (mail-source-call-script): New function.
+       (mail-source-call-script): New function.
+
+Sun May  2 02:00:27 1999  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-setup-highlight-words): New function.
+       (gnus-select-newsgroup): Use it.
+       (gnus-group-highlight-words-alist): New variable.
+       (gnus-newsgroup-emphasis-alist): New variable.
+       (gnus-summary-local-variables): Use it.
+       * lpath.el: Use it.
+       * gnus-art.el (article-emphasize): Use it.
+       (gnus-emphasis-highlight-words): New face.
+       * gnus-cus.el (gnus-group-parameters): New parameter.
+
+Sun May  2 01:00:02 1999  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-cache.el (gnus-cache-possibly-enter-article): Remove
+       parameter `headers'.
+       (gnus-cache-enter-article): Ditto.
+       (gnus-cache-update-article): Ditto.
+       * gnus-sum.el (gnus-summary-move-article): Ditto.
+       (gnus-summary-mark-article-as-unread): Ditto.
+       (gnus-summary-mark-article): Ditto.
+
+1999-06-12 03:59:56  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-message-insert-stylings): Removed.
+       (gnus-posting-style-alist): Removed.
+       (gnus-message-style-insertions): Ditto.
+       (gnus-configure-posting-styles): Reimplementation.
+
+       * mail-source.el (mail-source-fetch): Error the message.
+
+       * gnus-msg.el (gnus-inews-do-gcc): Do mml and encoding.
+
+Sat Jun 12 00:19:57 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.85 is released.
+
+1999-04-20  Michael Cook  <cook@sightpath.com>
+
+       * gnus-cite.el (gnus-cite-attribution-prefix): Tweak for MS
+       Outlook citation regex.
+
+1999-06-12 02:09:49  Lars Magne Ingebrigtsen  <pinard@iro.umontreal.ca>
+
+       * nndoc.el (nndoc-mime-parts-type-p): Accept space before
+       semicolon.
+
+1999-05-24  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-range.el (gnus-remove-from-range): Document range1
+       modification, protect range2.
+
+1999-05-24  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-sum.el (gnus-update-marks): Protect lists from
+       gnus-remove-from-range, don't sort twice.
+
+1999-05-21  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-start.el (gnus-read-descriptions-file): Protect if no
+       function in backend.
+
+1999-05-15  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-sum.el (gnus-valid-move-group-p): Check for a
+       request-accept-article function in the backend instead of using
+       the 'respool capability.
+
+1999-04-18  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding): Handle
+       spurious whitespace at eob.
+
+1999-06-12 02:02:06  Adrian Aichner  <aichner@ecf.teradyne.com>
+
+       * nnmail.el (nnmail-get-new-mail): Check right variable.
+
+1999-06-12 01:57:39  Karl Kleinpaste  <karl@justresearch.com>
+
+       * mailcap.el (mailcap-mime-data): Fix rfc822.
+
+1999-06-11 23:48:50  TOZAWA Akihiko  <miles@is.s.u-tokyo.ac.jp>
+
+       * nndoc.el (nndoc-nsmail-type-p): New function.
+       (nndoc-type-alist): Recognize nsmail.
+
+1999-05-12  Mike McEwan  <mike@lotusland.demon.co.uk>
+
+       * gnus-art.el (gnus-treatment-function-alist): Display `x-face'
+       *before* `article-hide-headers' deletes the information.
+
+1999-05-22 00:26:46  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-save-parts): New command and
+       keystroke.
+       (gnus-summary-save-parts-1): New function.
+       (gnus-summary-iterate): Buggy.
+
+       * mm-decode.el (mm-save-part-to-file): Made into own function.
+
+1999-05-11 05:53:16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-set-info): Resist nils.
+
+1999-05-04 19:26:08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mailcap.el (mailcap-mime-data): Ditto.
+
+       * gnus-uu.el (gnus-uu-default-view-rules): Ditto.
+
+       * gnus-art.el (gnus-article-x-face-command): Default to ee.
+
+1999-05-02  Gareth Jones  <gdj1@gdjones.demon.co.uk>
+
+       * gnus-art.el (article-make-date-line): Put X-Sent below Date if
+       gnus-article-date-lapsed-new-header is t.
+
+Sat May  1 20:27:43 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.84 is released.
+
+1999-05-01 22:23:21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-bug-message): Mime change.
+
+1999-04-22  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-sum.el (gnus-update-marks): Process null mark lists.
+
+1999-04-21  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding): Recognize
+       `x-uue'.
+
+1999-03-04  Aaron M. Ucko  <amu@mit.edu>
+
+       * mail-source.el (mail-source-fetch-pop): Only prompt for password
+       when authentication is 'password.
+
+1999-05-01 22:17:55  <pinard@iro.umontreal.ca>
+
+       * gnus-win.el (gnus-configure-windows): Accept a setting.
+
+1999-04-21 20:51:13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-util.el (mm-quote-arg): Moved here.
+
+       * mm-decode.el (mm-quote-arg): Quote more chars.
+
+1999-04-18 20:12:49  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnheader.el (nnheader-parse-head): Message-ID in In-Reply-To
+       with newlines would create buggy .nov files.
+
+       * gnus-art.el (gnus-article-date-lapsed-new-header): Default to nil.
+
+       * qp.el (quoted-printable-encode-region): Encode whitespace at the
+       end of lines.
+
+       * message.el (message-mode): Doc fix.
+
+       * gnus-art.el (article-hide-headers): Delete the hidden headers.
+
+       * gnus-msg.el (gnus-setup-posting-charset): Default group to "".
+
+       * gnus-art.el (article-date-ut): Rewrite.
+
+       * mm-decode.el (mm-preferred-alternative-precedence): Reverse the
+       order.
+
+       * gnus-msg.el (gnus-message-insert-stylings): Remove duplicate
+       headers.
+
+       * gnus-art.el (gnus-article-date-lapsed-new-header): Doc fix.
+
+1999-04-18  Didier Verna  <verna@inf.enst.fr>
+
+       * gnus-art.el (gnus-article-date-lapsed-new-header): new variable.
+       (article-date-ut): use it.
+
+1999-04-18 20:06:20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-fetch-pop): Call script
+       asynchronously.
+
+Sun Apr 18 12:40:04 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.83 is released.
+
+1999-04-18 10:55:57  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-draft.el (gnus-draft-mode): Use mml minor mode.
+
+       * gnus-cite.el (gnus-dissect-cited-text): Off-by-one error.
+
+       * gnus-uu.el (gnus-uu-mark-thread): Save hidden threads.
+
+       * gnus-art.el (gnus-mime-inline-part): Don't do a charset param.
+
+       * gnus-msg.el (gnus-bug): Use application/x-emacs-lisp.
+
+       * message.el (message-generate-headers): Accept continuation
+       headers.
+
+1999-04-18 10:48:57  Renaud Rioboo  <Renaud.Rioboo@lip6.fr>
+
+       * gnus-demon.el (gnus-demon-time-to-step): Not strings.
+
+1999-04-18 08:21:52  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-treatment-function-alist): use
+       maybe-hide-headers.
+
+       * message.el (message-inhibit-body-encoding): Typo.
+       (message-resend): Inhibit encoding.
+
+       * gnus-sum.el (gnus-summary-toggle-header): Decode rfc2047.
+
+       * gnus-art.el (article-remove-cr): Use re-search.
+
+       * rfc2231.el (rfc2231-parse-string): Allow broken elm MIME
+       headers.
+
+       * mm-decode.el (mm-quote-arg): Quote '.
+
+       * gnus-ems.el (gnus-x-splash): Would place splash wrongly.
+
+       * mm-decode.el (mm-insert-part): Use multibyte for text.
+
+       * gnus-start.el (gnus-read-newsrc-file): New variable.
+       (gnus-read-newsrc-file): Use it.
+
+1999-04-17 18:51:54  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnvirtual.el (nnvirtual-request-expire-articles): New function.
+
+       * gnus-group.el (gnus-group-expire-articles-1): Made into own
+       function.
+
+Sat Apr 17 16:41:30 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.82 is released.
+
+1999-04-15  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * gnus-sum.el (gnus-group-charset-alist): Include Croatian groups
+       for iso8859-2.
+
+1999-04-17 18:23:50  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-util.el (mm-charset-synonym-alist): Remove iso-2022-jp-2 from
+       synonym alist.
+
+1999-04-17 18:03:38  Adam P. Jenkins  <ajenkins@netway.com>
+
+       * gnus-sum.el (gnus-summary-local-variables): Mark as global.
+
+1999-04-17 18:02:05  Ettore Perazzoli  <ettore@comm2000.it>
+
+       * mail-source.el (mail-source-fetch): Ask before bugging out.
+
+1999-03-19  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * uudecode.el (uudecode-decode-region-external): Don't assume
+       uudecode-temporary-file-directory ends with a slash.
+
+1999-03-18  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-sum.el (gnus-update-marks):
+       (gnus-update-read-articles):
+       (gnus-summary-expire-articles): Check server.
+
+1999-03-16  Simon Josefsson  <jas@pdc.kth.se>
+
+       * mml.el (mml-preview): New function.
+
+1999-04-17 17:10:21  William M. Perry  <wmperry@aventail.com>
+
+       * mail-source.el (mail-source-fetch-file): Return the right
+       value.
+
+1999-04-17 07:52:17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml.el (mml-insert-parameter): New function.
+       (mml-insert-parameter-string): New function.
+
+       * nnmail.el (nnmail-get-new-mail): Say how many new articles.
+
+       * gnus-art.el (gnus-mime-multipart-functions): New variable.
+       (gnus-mime-display-part): Use it.
+
+       * mm-decode.el (mm-alternative-precedence): Removed.
+       (mm-discouraged-alternatives): New variable.
+       (mm-preferred-alternative-precedence): New function.
+
+       * nnmail.el (nnmail-get-new-mail): Use mail-sources.
+
+       * mail-source.el (mail-sources): New variable.
+
+       * gnus-art.el (article-remove-cr): Remove several trailing CRs.
+
+       * mm-decode.el (mm-valid-image-format-p): New function.
+       (mm-inline-media-tests): Use it.
+       (mm-valid-and-fit-image-p): New function.
+
+       * gnus-agent.el (gnus-agent-fetch-groups): Error when unplugged.
+       (gnus-agent-fetch-group): Ditto.
+
+1999-04-12  Didier Verna  <verna@inf.enst.fr>
+
+       * nnmail.el (nnmail-article-group): in case of a group name
+       containing "\\n" constructs, be sure to pass the expanded value to
+       nn*-save-mail.
+
+Sat Apr 17 05:40:45 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.81 is released.
+
+1999-04-16 15:54:02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-get-split-value): Reverse result.
+
+1999-04-03 00:17:24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-always-read-dribble-file): Doc fix.
+
+1999-04-02 15:33:43  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml.el (mml-insert-tag): Insert concluding part.
+
+       * message.el (message-send-mail): Encode later.
+       (message-send-news): Ditto.
+
+       * nnfolder.el: Don't use mail delim.
+
+1999-03-28 19:14:27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-cus.el (gnus-group-customize): Put point at min.
+
+       * mm-view.el (mm-inline-text): Allow toggling html.
+
+1999-03-28 17:11:15  William M. Perry  <wmperry@aventail.com>
+
+       * mail-source.el: Added prescript and postscript to file.
+
+1999-03-28 13:46:00  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnmail.el: Reverted.
+
+       * gnus-msg.el (gnus-setup-posting-charset): Didn't work.
+       (gnus-setup-posting-charset): Did work.
+
+1999-03-28 13:19:50  Jae-you Chung  <jay@pllab.kaist.ac.kr>
+
+       * gnus.el (gnus-short-group-name): Use
+       gnus-group-uncollapsed-levels.
+
+1999-03-28 13:11:43  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-cite.el (gnus-dissect-cited-text): Don't remove overlays.
+
+1999-03-26 13:18:45  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-treat-strip-headers-in-body): New variable.
+       (article-strip-headers-from-body): New command and keystroke.
+
+1999-03-14 16:09:10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-fetch-pop): Check for symbol first.
+
+       * nnheader.el (nnheader-insert-file-contents): Bind
+       enable-local-eval to nil.
+       (nnheader-find-file-noselect): Ditto.
+
+       * nnmail.el (nnmail-article-group): Don't remove long lines.
+       (nnmail-remove-long-lines): New function.
+       (nnmail-split-header-length-limit): Removed.
+
+       * mml.el (mml-generate-mime-1): Use unibyte buffers.
+
+       * gnus-group.el (gnus-group-kill-all-zombies): Query user.
+
+1999-03-06 07:20:05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-generic-mark): New function.
+
+       * nnmail.el (nnmail-split-header-length-limit): Increased.
+       (nnmail-article-group): Allow nil.
+
+       * gnus-cite.el (gnus-cite-parse-wrapper): Inhibit point-motion.
+
+       * nndoc.el (nndoc-generate-mime-parts-head): Insert real headers
+       first.
+
+       * mml.el (mml-minibuffer-read-type): Include types from
+       mailcap-mime-data.
+
+       * nndraft.el (nndraft-request-article): Would clobber Japanese.
+
+1999-03-05  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * mml.el (mml-insert-tag): New function.
+       (mml-read-file): Renamed to mml-minibuffer-read-file to avoid
+       confusion with functions like `mml-read-tag'.
+       (mml-read-type): Ditto with `mml-minibuffer-read-type'.
+       (mml-minibuffer-read-description): Ditto with
+       `mml-minibuffer-read-description'.
+       (mml-attach-buffer): New function.
+       (mml-mode-map): New entry for /.
+       (mml-minibuffer-read-type): Accept DEFAULT.
+
+       * mml.el (mml-quote-region): Narrow the region.
+
+       * message.el (message-mode-menu): message-mime-attach-file is now
+       mml-attach-file.
+
+1999-03-05 21:24:23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-treatment-function-alist): Do emphasis earlier.
+
+1999-03-05 21:08:10  Robert Bihlmeyer  <robbe@orcus.priv.at>
+
+       * mml.el (mml-attach-buffer): New command.
+
+1999-02-27  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-sum.el (gnus-update-marks): Call gnus-remove-from-range
+       with a proper range. Compress range.
+
+       * gnus-range.el (gnus-remove-from-range): Protect arguments.
+
+1999-03-05 20:59:54  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-get-image): Create a temporary file for xbms.
+
+1999-03-04 04:20:25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-picon.el (gnus-picons-x-face-file-name): Removed.
+       (gnus-picons-convert-x-face): Removed.
+       (gnus-picons-article-display-x-face): Removed.
+       (gnus-picons-x-face-sentinel): Ditto.
+       (gnus-picons-display-x-face): Ditto.
+
+Thu Mar  4 01:38:00 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.80 is released.
+
+1999-03-02 16:04:30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-mm-display-part): Narrow to the part itself.
+
+       * gnus-sum.el (gnus-with-article): Moved here.
+
+       * mail-source.el (mail-source-fetch-pop): Ask for password even
+       when program.
+
+1999-02-28 13:16:12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-bug): Add description.
+
+       * mml.el (mml-insert-mml-markup): Insert disposition.
+
+       * message.el (message-send-mail): Always encode mail headers.
+
+       * smiley.el (gnus-smiley-display): Goto body.
+
+1999-02-28 13:15:47  Petr Konecny  <pekon@informatics.muni.cz>
+
+       * smiley.el (gnus-smiley-display): Don't search to blank line.
+
+1999-02-28 00:38:40  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-treat-article): Only run the highlight stuff
+       when requested.
+
+       * nnmail.el (nnmail-current-spool): Removed.
+
+       * gnus-salt.el (gnus-tree-inhibit): New varible.
+
+       * gnus.el (mm-util): Required.
+
+1999-02-27 23:44:52  paul stevenson  <spaul@mail.phy.ornl.gov>
+
+       * gnus-sum.el (gnus-summary-toggle-header): Narrow to head first.
+
+1999-02-27 17:17:47  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-bind): Doc fix.
+
+1999-02-26 20:35:57  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-mode): Doc fix.
+
+       * mm-encode.el (mm-content-transfer-encoding-defaults): Use 8bit
+       encoding.
+
+       * gnus.el (gnus-methods-equal-p): Moved here.
+
+       * mail-source.el: pop at 110.
+
+       * pop3.el (pop3-movemail): Use write-region instead of
+       append-to-file to avoid excessive messaging.
+
+1999-02-27  lantz moore  <lmoore@contigo.com>
+
+       * nnmail.el (nnmail-get-new-mail): honor suffix for spool-files of
+       type directory.
+
+1999-03-04  Robert Bihlmeyer  <robbe@orcus.priv.at>
+
+       * gnus-art.el (article-hide-boring-headers): Field names must not
+       contain whitespace.
+
+Fri Feb 26 18:54:16 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.79 is released.
+
+1999-02-26 18:11:04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-cite.el (gnus-cite-toggle): Don't remove highlighting.
+
+       * mml.el (mml-mode): Don't use add-minor-mode.
+
+       * message.el (messgage-inhibit-body-encoding): New variable.
+       (message-encode-message-body): Use it.
+
+Fri Feb 26 17:00:25 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.78 is released.
+
+1999-02-26 07:45:30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-mode): Switch on MML mode.
+
+       * mml.el: Included commands and functions.
+       (mml-mode-map): New keymap.
+
+       * message.el: Removed the insertion commands and functions.
+
+       * gnus-ems.el (gnus-mule-cite-add-face): Removed.
+
+       * gnus-sum.el (gnus-summary-sort-by-chars): New command and
+       keystroke.
+
+       * gnus-art.el (gnus-narrow-to-page): Revert.
+
+       * gnus-cite.el (gnus-cite-delete-overlays): New function.
+       (gnus-cite-parse-maybe): Always reparse.
+
+       * message.el (message-encode-message-body): Don't insert
+       "multipart warning".
+
+       * gnus-art.el (gnus-article-treat-head-custom): New variable.
+
+1999-02-25  Miles Bader  <miles@ccs.mt.nec.co.jp>
+
+       * mail-source.el (mail-source-fetch-pop): Return 1 for success.
+
+       * nnmail.el: Require mm-util.
+
+1999-02-26 07:39:33  Justin Sheehy  <justin@linus.mitre.org>
+
+       * nnmail.el (nnmail-get-new-mail): Only get mail for the one
+       group.
+
+1999-02-26 07:38:08  SeokChan LEE  <chan@smoky-blue.com>
+
+       * mm-bodies.el (mm-body-charset-encoding-alist): Add euc-kr.
+
+1999-02-21  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-msg.el (gnus-extended-version): Better regexp.
+
+1999-02-25  Didier Verna  <verna@inf.enst.fr>
+
+       * nnmail.el (nnmail-split-it): new syntax: `(! FUNC SPLIT)'. FUNC
+       is called with the result of SPLIT and should return a new split.
+
+1999-02-23  Didier Verna  <verna@inf.enst.fr>
+
+       * gnus-picon.el (gnus-picons-display-bar-p): when picons are
+       displayed in the article buffer, output bars if
+       `gnus-picons-display-article-move-p'.
+
+1999-02-20  Aaron M. Ucko  <amu@mit.edu>
+
+       * mail-source.el (mail-source-fetch-pop): Typo.
+
+1999-02-26 07:15:12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-toggle-header): Save restriction.
+
+1999-02-23 03:07:58  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-cite.el (gnus-cite-parse-wrapper): Always parse.
+
+1999-02-21 11:11:39  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml.el (mml-insert-buffer): New function.
+
+       * message.el (message-forward): Insert the buffer in the buffer.
+
+Sun Feb 21 01:20:50 1999  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-view.el (mm-inline-message): Insert part in narrowed region.
+
+Sat Feb 20 23:09:40 1999  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-toggle-header): Save restriction.
+
+Sat Feb 20 21:34:28 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.77 is released.
+
+1999-02-20 17:32:17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-displaying-mime): New variable.
+       (article-narrow-to-head): New function.
+
+       * mail-source.el (mail-source-fetch-pop): Include pre/postscript.
+       Default to pop instead of pop3.
+
+1999-02-19 16:16:04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-hide-pgp): Goto body.
+
+       * gnus-uu.el (gnus-uu-digest-mail-forward): Don't kill buffer.
+
+       * gnus-cite.el: Don't use goto-line.
+
+       * gnus-art.el (gnus-article-treat-html): Removed.
+       (gnus-treat-article): Save restriction.
+
+1999-02-17  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * message.el (message-send-mail): Don't untabify.
+       (message-mode): Don't use tabs for indentation.
+
+1999-02-19 14:54:13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-send-mail): Don't untabify.
+
+       * nnml.el (nnml-save-mail): Typo fix.
+
+1999-02-19  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * message.el (message-cite-function): Add
+       `message-cite-original-without-signature' customization option.
+
+1999-02-18  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * nnmail.el (nnmail-fix-eudora-headers): Mark as option to
+       `nnmail-prepare-incoming-header-hook'.
+
+1999-02-19 14:41:43  Justin Sheehy  <justin@linus.mitre.org>
+
+       * gnus-util.el (gnus-make-sort-function-1): Typo fix.
+
+1999-02-19 14:40:37  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-get-new-news): Require nnmail.
+
+1999-02-18  Michael Cook  <cook@sightpath.com>
+
+       * Recognize Microsoft Outlook's cite attribution conventions.
+
+1999-02-19 14:33:11  James H. Cloos, Jr.  <cloos@jhcloos.com>
+
+       * gnus-sum.el: Bind M.
+
+1999-02-19 14:31:29  Neil Crellin  <neilc@wallaby.cc>
+
+       * mail-source.el (mail-source-fetch-pop): Bind pop3-port.
+
+1999-02-15  Didier Verna  <verna@inf.enst.fr>
+
+       * gnus-picon.el (gnus-group-display-picons): ensures that
+       `article-goto-body' really goes to the article body.
+
+1999-02-19 12:57:19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-view.el (mm-inline-text): Bind url-standalone-mode.
+
+       * gnus-msg.el (gnus-summary-mail-forward): Create unique names.
+
+       * mm-view.el (mm-view-message): Enable multibyte.
+
+1999-02-11 18:37:15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnmail.el (nnmail-get-new-mail): Message later.
+
+       * mm-util.el (mm-find-charset-region): Revert to checking
+       multibyte.
+
+1999-02-11  Matt Pharr  <mmp@graphics.stanford.edu>
+
+       * gnus-msg.el (gnus-bug): Encode environment info as a MIME
+       attachment.
+
+Thu Feb 11 04:58:51 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.76 is released.
+
+1999-02-06  Felix Lee  <flee@cygnus.com>
+
+       * gnus.el (gnus-group-change-level-function): Typo.
+
+1999-02-11 05:47:51  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-nov-skip-field): Removed.
+       (gnus-nov-field): Ditto.
+       (gnus-nov-parse-extra): Ditto.
+       (gnus-nov-read-integer): Ditto.
+
+1999-02-05 09:44:20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnheader.el (nnheader-nov-read-message-id): New macro.
+       (nnheader-parse-nov): Use it.
+
+       * gnus-sum.el (gnus-nov-read-message-id): New macro.
+       (gnus-nov-parse-line): Use it; use `(eobp)' instead of
+       `(eq (char-after) ?\n)'.
+
+1999-02-11 05:16:26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-other-frame): Always pop up a new frame.
+
+Wed Feb 10 01:03:43 1999  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-range.el (gnus-range-add): Rewrite.
+
+1999-02-02 18:12:00  Carsten Leonhardt  <leo@arioch.oche.de>
+
+       * nnmail.el (nnmail-split-incoming): Added detection of maildir
+       format.
+       (nnmail-process-maildir-mail-format): New function.
+
+       * mail-source.el (mail-source-fetch-maildir): New function.
+       (mail-source-keyword-map): Add default for maildir method.
+       (mail-source-fetcher-alist): Changed "qmail" to "maildir".
+
+1999-02-10 02:29:28  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-fetcher-alist): Remove apop.
+
+       * nndoc.el (nndoc-type-alist): Remove MIME-digest.
+       (nndoc-mime-digest-type-p): Removed.
+
+1999-02-09 15:25:52  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-read-summary-keys): Set the point
+       where it is supposed to be.
+       (gnus-treat-play-sounds): New variable.
+
+       * gnus-sum.el (gnus-newsgroup-ignored-charsets): New variable.
+
+       * gnus-art.el (article-display-x-face): Narrow to head.
+       (gnus-article-washed-types): New variable.
+       (article-hide-pgp): Is not a toggle.
+       (gnus-article-hide-text-type): Save types.
+       (article-decode-charset): Use it.
+
+       * nnmail.el (nnmail-get-new-mail): Ignore procmail.
+
+       * message.el (message-forward-start-separator): Removed.
+       (message-forward-end-separator): Removed.
+       (message-signature-before-forwarded-message): Removed.
+       (message-included-forward-headers): Removed.
+       (message-check-news-body-syntax): Don't check forward.
+       (message-forward): Use MIME.
+
+       * nnvirtual.el (nnvirtual-request-article): Bind
+       gnus-article-decode-hook to nil.
+
+1999-02-06 16:55:25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml.el (mml-parse-singlepart-with-multiple-charsets): Check for
+       us-ascii.
+
+1999-02-04 00:00:35  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * format-spec.el (format-spec): Be more robust.
+
+       * message.el (message-encode-message-body): Default
+       mail-parse-charset to mail-parse-charset.
+
+       * gnus-sum.el (gnus-summary-edit-article-done): Don't encode.
+       (gnus-summary-edit-article): Bind mail-parse-charset.
+
+       * mml.el (mml-read-tag): Ignore white space after end of tag.
+
+       * message.el (message-goto-body): Also work in separatorless
+       articles.
+
+       * mml.el (mml-translate-from-mime): New function.
+       (mml-insert-mime): Ditto.
+       (mml-to-mime): New function.
+       (mime-to-mml): New name.
+
+       * gnus-sum.el (gnus-summary-edit-article): Always select raw
+       article.
+
+       * gnus-group.el (gnus-group-catchup-current): Unmark groups.
+
+       * gnus-sum.el (gnus-summary-setup-default-charset): Don't
+       special-case nndraft groups.
+
+1999-02-03 16:44:19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-get-newsgroup-headers): Bind charset.
+       (gnus-get-newsgroup-headers): Already bound.
+
+       * message.el (message-encode-message-body): Use posting charset.
+
+       * mm-bodies.el (mm-encode-body): Use MIME charsets.
+       (mm-body-encoding): Do CTE.
+       (mm-body-7-or-8): New function.
+
+       * mm-util.el (mm-mime-charset): Always fall back on alist.
+       (mm-mime-mule-charset-alist): Include katakana-jisx0201.
+       (mm-mime-mule-charset-alist): Add arabic-*-column.
+       (mm-find-mime-charset-region): New function.
+
+       * format-spec.el (format-spec-make): New function.
+
+       * mail-source.el (format-spec): Required.
+       (mail-source-fetch-with-program): Removed.
+       (mail-source-fetch-with-program): New function.
+
+       * format-spec.el: New file.
+
+1999-02-03 16:00:41  Tatsuya Ichikawa  <ichikawa@hv.epson.co.jp>
+
+       * mail-source.el (mail-source-fetch-with-program): Take optional
+       parameter.
+
+1999-02-03 00:31:21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el: Ignore some groups.
+       (gnus-setup-news): Bind nnmail-fetched-sources.
+
+       * message.el (message-send-mail): Remove all tabs.
+
+       * mm-util.el (mm-find-charset-region): Just check whether
+       find-charset-region is defined.
+
+1999-02-02 23:35:20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-get-new-news): Use
+       nnmail-fetched-sources.
+
+       * nnmail.el (nnmail-fetched-sources): New variable.
+       (nnmail-get-new-mail): Use it.
+
+       * mail-source.el (mail-source-fetched-sources): New variable.
+       (mail-source-fetch): Use it.
+
+1999-02-02 23:20:20  Mark W. Eichin  <eichin@thok.org>
+
+       * gnus.el (gnus-getenv-nntpserver): if the file that
+       gnus-nntpserver-file names has a trailing newline, the
+       string-match will always match, and thus the file will never be
+       read.  (^ matches start of "line", \\` matches start of "buffer",
+       which is what was intended...)
+
+1999-02-02 23:17:40  Kim-Minh Kaplan  <kmkaplan@western.fr>
+
+       * gnus-picon.el (gnus-picons-parse-filenames): Quote group names.
+
+1999-01-28 04:15:46  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-start.el (gnus-read-active-file): Eliminate duplicated
+       select methods.
+
+1999-01-27  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-range.el (gnus-remove-from-range): Sort second argument.
+
+1999-02-02 10:55:23  Scott Hofmann  <shofmann@mindspring.com>
+
+       * nntp.el: Use mail-source-read-passwd instead of nnmail-read-passwd.
+
+Mon Feb  1 23:23:03 1999  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-cus.el (gnus-group-parameters): Charset as symbol, and fix
+       a typo.
+       * gnus-sum.el (gnus-summary-setup-default-charset): Set nndraft's
+       charset to nil.
+       * gnus-agent.el (gnus-agent-queue-setup): Remove charset setting.
+       * gnus-start.el (gnus-start-draft-setup): Ditto.
+
+1999-02-02 22:13:14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-fetch-directory): Use the predicate.
+       (mail-source-value): Don't do variables.
+
+       * nnmail.el (nnmail-get-new-mail): Set the predicate.
+
+       * gnus-sum.el (gnus-summary-toggle-header): Fix, and bound to t.
+
+1999-02-01  Michael Cook  <cook@sightpath.com>
+
+       * Defenestrate spurious ?a.
+
+1999-02-02 21:59:51  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-fetch-pop): Instead use
+       :authentication.
+
+1999-02-01  Tatsuya Ichikawa  <t-ichi@po.shiojiri.ne.jp>
+
+       * mail-source.el : Support APOP authentication scheme.
+
+1999-02-02 21:56:14  Tatsuya Ichikawa  <t-ichi@niagara.shiojiri.ne.jp>
+
+       * pop3.el (pop3-movemail): Return t.
+
+1999-02-02 21:48:46  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * rfc2047.el (rfc2047-fold-region): New function.
+       (rfc2047-encode-message-header): Use it.
+
+1999-02-02 21:07:27  Hallvard B. Furuseth  <h.b.furuseth@usit.uio.no>
+
+       * gnus-sum.el (gnus-group-charset-alist): Add more.
+
+Mon Feb  1 21:18:00 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.75 is released.
+
+1999-02-01 21:54:26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-display-x-face): Don't narrow to head.
+
+1999-02-01 21:48:39  Michael Cook  <cook@sightpath.com>
+
+       * gnus-cite.el (gnus-cited-lines-visible): Accept a cons.
+
+1999-02-01 20:59:38  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-fetch-directory): Ignore
+       directories.
+
+       * gnus-cus.el (gnus-group-parameters): Addition.
+
+       * gnus-art.el (article-strip-banner): Do symbolic banners.
+       (article-strip-banner): New keystroke.
+
+1999-02-01 20:54:32  Michael Cook  <cook@sightpath.com>
+
+       * gnus-art.el (article-strip-banner): New command.
+
+1999-02-01 20:53:45  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-treat-strip-banners): New variable.
+
+1999-01-28 05:34:56  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mail-source.el (mail-source-read-passwd): Use `read-passwd' if it
+       has been exist.
+
+Thu Jan 28 01:38:34 1999  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-draft-coding-system): Check coding-system.
+       * mm-util.el (mm-text-coding-system): Ditto.
+
+1999-01-28 12:11:31  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mail-source.el (mail-source-fetch-pop): Save excursion.
+
+1999-01-28 08:14:21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-movemail-args): Not constant.
+       (mail-source-movemail-args): Removed.
+       (mail-source-fetch-with-program): New function.
+       (mail-source-fetch-pop): Use program and function.
+       (mail-source-movemail-program): Removed.
+
+       * gnus-art.el (gnus-treat-date-iso8601): New variable.
+       (gnus-treat-date-user-defined): New variable.
+
+1999-01-28 08:07:12  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * nnmail.el (nnmail-fix-eudora-headers): New function.
+
+1999-01-28 08:05:19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-bodies.el (mm-encode-body): Use mail-parse-charset.
+
+1999-01-27 08:06:38  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * smiley.el (smiley-deformed-regexp-alist): Removed =>.
+       (smiley-nosey-regexp-alist): Ditto.
+
+       * gnus-art.el (gnus-treatment-function-alist): Do
+       gnus-article-add-buttons-to-head later.
+       (gnus-treat-capitalize-sentences): New variable.
+       (article-capitalize-sentences): New command and keystroke.
+
+       * gnus-group.el (gnus-group-catchup-current): Do group.
+
+       * message.el (message-default-charset): Add group.
+
+Wed Jan 27 05:24:53 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.74 is released.
+
+1999-01-27 05:56:29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-fill-long-lines): Renamed.
+       (article-fill-long-lines): New keystroke.
+
+1999-01-26 06:35:07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-setup-posting-charset): Check for group.
+
+       * gnus-group.el (gnus-group-catchup-current): Skip groups now
+       displayed.
+       (gnus-group-catchup-current): Be more robus.
+
+       * gnus-sum.el (gnus-summary-select-article): Reselect for showing
+       headers.
+
+1999-01-25  Dave Love  <fx@gnu.org>
+
+       * message.el (message-mode-menu): Add message-mime-attach-file.
+       (message-mode): Doc fix.
+
+1999-01-26 05:24:19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnmail.el (nnmail-check-duplication): Insert the mail source
+       string.
+
+       * mail-source.el (mail-source-fetch-pop): Bind mail-source-string.
+       (mail-source-fetch-directory): Ditto.
+       (mail-source-fetch-file): Ditto.
+       (mail-source-string): New variable.
+
+       * gnus-start.el (gnus-get-unread-articles): Nix out groups over
+       the level.
+
+       * rfc2047.el (rfc2047-encodable-p): Convert to MIME charsets
+       before handling.
+
+       * mm-util.el (mm-mime-charset): Use the parameters.
+       (mm-mime-charset): Removed region paremeters.
+
+       * nnmail.el (nnmail-get-new-mail): Don't message the entire
+       source.
+
+1999-01-25 12:05:16  Lloyd Zusman  <ljz@asfast.com>
+
+       * nnmail.el (nnmail-get-split-group): Quote right.
+
+1999-01-25 05:55:41  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-movemail): Would kill an arbitrary
+       buffer.
+
+1999-01-24 03:02:31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-clear-inboxes-moved): Removed.
+       (gnus-group-mode): Don't hook.
+
+       * mail-source.el (mail-source-bind): Doc fix.
+       (mail-source-bind): Take only one param.
+
+       * gnus-art.el (gnus-treat-highlight-signature): typep.
+
+       * mail-source.el (mail-source-movemail): Ignore empty file.
+       (mail-source-callback): Check before deleting.
+
+       * message.el (message-mime-attach-file): Include name.
+
+1999-01-23 17:01:12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-util.el (mm-read-charset): Return a symbol.
+
+       * mm-view.el (mm-inline-text): Insert signature separator.
+
+       * gnus-art.el (gnus-treat-predicate): New function.
+       (gnus-treat-article): Allow all types to be checked.
+
+       * gnus-util.el (gnus-or): New function.
+       (gnus-and): Ditto.
+
+       * gnus-art.el (gnus-mime-display-single): Use override.
+
+       * mm-decode.el (mm-attachment-override-types): New variable.
+       (mm-attachment-override-p): New function.
+
+       * gnus-picon.el (gnus-group-display-picons): Don't go backward.
+
+1999-01-23 16:45:06  Andrew J. Cosgriff  <ajc@bing.wattle.id.au>
+
+       * mm-view.el (mm-inline-text): Do vcards.
+
+Sat Jan 23 14:23:27 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.73 is released.
+
+1999-01-23 11:38:36  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnmail.el (nnmail-spool-file): Changed to use mail-source.
+       (nnmail-crash-box, nnmail-use-procmail, nnmail-procmail-directory,
+       nnmail-procmail-suffix, nnmail-resplit-incoming): Removed.
+       (nnmail-movemail-program): Removed.
+       (nnmail-movemail-args): Removed.
+       (nnmail-pop-password-required): Ditto.
+       (nnmail-tmp-directory): Ditto.
+       (nnmail-delete-incoming): Removed.
+       (nnmail-pop-password, nnmail-moved-inboxes,
+       nnmail-internal-password, nnmail-move-inbox): Removed.
+       (nnmail-read-passwd): Ditto.
+       (nnmail-get-spool-files): Removed.
+       (nnmail-resplit-incoming): Reinstated.
+
+       * mail-source.el: New file.
+
+1999-01-23 09:08:31  James H. Cloos, Jr.  <cloos@jhcloos.com>
+
+       * gnus-art.el (gnus-article-mode-map): Bind backspace.
+
+1999-01-23 09:05:04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-make-date-line): Fix iso8601 display.
+
+1999-01-20 02:53:52  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-treat-display-smileys): Check xpm.
+
+       * gnus-picon.el (gnus-group-display-picons): Goto body.
+
+       * gnus.el: Indented all functions; broke long lines; changed all
+       instances of illegal/legal to invalid/valid.  Yes, I'm bored.
+
+Wed Jan 20 00:50:53 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.72 is released.
+
+1999-01-20 01:39:48  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el: Cleaned up trailing whitespace.
+
+       * mm-util.el (mm-read-charset): Work.
+
+1999-01-17  Matt Armstrong  <mattdav+matt@best.com>
+
+       * gnus-score.el (gnus-score-find-bnews): Match regexp on the
+       nnheader-translate-file-chars'd group name.
+
+1999-01-20 01:30:30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-encode-message-body): Fold case.
+
+1999-01-20 01:28:16  Alexei V. Barantsev  <barancev@ispras.ru>
+
+       * gnus-xmas.el (gnus-xmas-modeline-glyph): Backquote.
+
+1999-01-20 00:46:15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mailcap.el (mailcap-add): New function.
+
+1999-01-18 09:40:37  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-goto-body-goes-to-point-min-p): New variable.
+       (article-goto-body): Use it.
+       (gnus-treat-article): Ditto.
+
+       * gnus-agent.el (gnus-agent-get-undownloaded-list): Remove the
+       downloaded articles from the downloadeble list.
+
+1999-01-16 17:31:08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-encode-message-body): Bind
+       mail-parse-charset.
+
+       * mm-util.el (mm-charset-synonym-alist): New variable.
+       (mm-charset-to-coding-system): Use it.
+       (mm-charset-coding-system-alist): Removed.
+       (mm-charset-to-coding-system): Don't use it.
+       (mm-find-charset-region): Use mail-parse-charset.
+
+       * gnus-art.el (gnus-treatment-function-alist): Use
+       gnus-article-display-picons.
+       (gnus-treat-display-xface): Only do if we have xface feature.
+       (gnus-part-display-hook): New function.
+       (gnus-treat-article): Use it.
+       (gnus-treat-article): Use gnus-visual.
+
+       * gnus-msg.el (gnus-setup-posting-charset): Check elem.
+
+       * gnus-art.el (gnus-mm-display-part): Fix the MIME button after
+       displaying.
+
+       * mm-decode.el (mm-insert-part): Use insert-buffer-substring.
+
+       * gnus-score.el (gnus-score-find-bnews): Protect against invalid
+       regexp file names.
+
+Sat Jan 16 03:15:57 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.71 is released.
+
+1999-01-16 00:13:31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-view.el (mm-inline-image): Don't add a dot.
+
+       * gnus-art.el (gnus-treat-article): New function.
+
+       * gnus.el (gnus-article-display-hook): Removed.
+
+       * gnus-art.el (gnus-article-treat-custom): New variable.
+
+       * gnus-start.el (gnus-ignored-newsgroups-has-to-p): Removed.
+
+       * gnus-msg.el (gnus-setup-posting-charset): Allow variables and
+       functions.
+
+       * message.el (message-posting-charset): New variable.
+       (message-send-mail): Use it.
+
+       * gnus-msg.el (gnus-group-posting-charset-alist): Moved here.
+       (gnus-setup-posting-charset): New function.
+       (gnus-setup-message): Use it.
+
+       * message.el (message-encode-message-body): Just look for
+       Content-Type before inserting a new one.
+
+1999-01-15 23:08:47  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * rfc2047.el (rfc2047-default-charset): Removed.
+
+       * mail-prsvr.el: New file.
+       (mail-parse-charset): New variable.
+
+       * gnus-sum.el (gnus-newsgroup-charset): Changed name.
+       Changed name.
+
+       * gnus.el (gnus-charset): New group.
+
+       * nnmail.el (nnmail-pathname-coding-system): Default to binary.
+
+       * gnus-sum.el (gnus-default-charset): Default to nil.
+       (gnus-newsgroup-iso-8859-1-forced-regexp): Removed.
+       (gnus-newsgroup-iso-8859-1-forced): Removed.
+
+       * mm-util.el (mm-known-charsets): Removed.
+       (mm-default-coding-system): Removed.
+       (mm-default-charset): Removed.
+       (mm-read-charset): New function.
+
+       * message.el (message-default-charset): Removed.
+
+       * rfc2047.el (rfc2047-default-charset): Default to nil.
+
+       * mm-util.el (mm-charset-iso-8859-1-forced): Removed.
+
+Fri Jan 15 20:50:38 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.70 is released.
+
+1999-01-15 00:06:04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-save-part): Use mm-get-part.
+       (mm-insert-part): New function.
+       (mm-get-part): Use it.
+       (mm-get-image): Ditto.
+       (mm-display-external): Ditto.
+
+       * mm-view.el (mm-inline-text): Ditto.
+
+       * gnus-move.el (gnus-move-group-to-server): Protect against nil
+       ranges.
+
+       * mm-decode.el (mm-display-external): Save the buffer.
+       (mm-remove-part): Kill it.
+
+       * qp.el (quoted-printable-decode-region): Do the right thing at eobp.
+
+       * nnagent.el (nnagent-request-set-mark): Defined stub.
+
+1999-01-14 23:05:31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-score.el (gnus-score-load-score-alist): Bind
+       coding-system-for-read.
+
+       * gnus-sum.el (gnus-summary-exit): Do adaptive scoring before
+       prepare-exit-hook.
+
+       * mm-view.el (mm-setup-w3): Require w3.
+
+1999-01-13  Kiyokazu SUTO  <suto@merry.xmath.ous.ac.jp>
+
+       * nnspool.el (nnspool-retrieve-headers): Protect against empty body.
+
+1999-01-14 21:17:35  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-encode.el: Ditto.
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding): Message the
+       error.
+
+       * mailcap.el (mailcap-mime-data): SAFER ps.
+
+       * message.el (message-encode-message-body): Always insert a
+       Content-Type header.
+
+       * mm-decode.el (mm-inline-media-tests): Default all text/* to be
+       shown inline.
+
+       * mm-view.el (mm-inline-text): Handle all sorts of text.
+
+       * mailcap.el (mailcap-mime-data): non-viewer for viewers that
+       don't view.
+
+       * mm-decode.el (mm-display-external): Use it.
+
+       * gnus-art.el (gnus-visible-headers): Added bcc, gcc, fcc.
+
+       * mm-decode.el (mm-save-part): Removed double code.
+
+1999-01-12  Dave Love  <fx@gnu.org>
+
+       * mm-decode.el (mm-save-part): Avoid doubly-compressed
+       application/octet-stream .gz & al files with jka-compr.
+
+1999-01-12  Dave Love  <fx@gnu.org>
+
+       * gnus-ems.el (gnus-down-mouse-3): New variable.
+       * gnus-art.el (gnus-mime-button-map): Use it.
+       (gnus-mime-button-menu): Set the clicked-on buffer initially.
+
+1999-01-13 19:41:57  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mailcap.el (mailcap-mime-data): Added ImageMagic and ee.
+
+1999-01-12 17:34:43  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-picon.el (gnus-picons-kill-buffer): Don't kill article
+       buffers.
+
+       * gnus-sum.el (gnus-summary-exit): Destroy all MIME.
+
+       * gnus-cache.el (gnus-cache-read-active): Reversed check.
+
+1999-01-12 17:18:25  Matt Armstrong  <matta@geoworks.com>
+
+       * mml.el (mml-parameter-string): Strip directory component.
+
+1999-01-12 17:02:58  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-use-demon): Removed.
+
+1999-01-12 05:53:23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnmail.el (nnmail-article-group): Don't infloop.
+
+1999-01-11  Colin Rafferty  <colin@xemacs.org>
+
+       * gnus-art.el (article-update-date-lapsed): Made it work with
+       picons, and make it update on all visible frames.
+       (article-date-ut): Get summary-buffer's current-headers.
+
+1999-01-12 07:20:31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-picon.el (gnus-picons-setup-buffer): Don't set major mode.
+       (gnus-picons-setup-p): New variable.
+
+1999-01-11 02:13:12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnmail.el (nnmail-split-header-length-limit): Lowered to 512.
+
+1999-01-04 12:58:13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-exit-no-update): Don't use run-hooks.
+       (gnus-summary-exit-no-update): Use mapcar.
+
+1999-01-02 14:36:32  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-agent.el (gnus-category-write): Make directory.
+
+1998-09-26 19:39:31  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-sum.el (gnus-update-read-articles):
+       (gnus-update-marks): Request backend update of mark.
+
+1999-01-03 15:29:52  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-bodies.el (mm-body-encoding): Use mm-find.
+
+1999-01-03 15:28:27  Kim-Minh Kaplan  <kmkaplan@western.fr>
+
+       * gnus-picon.el (gnus-article-display-picons): Fix.
+
+Sun Jan  3 13:32:02 1999  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.69 is released.
+
+1999-01-03 06:45:10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-picon.el (gnus-picons-setup-buffer): Run the hook.
+
+       * gnus-agent.el (gnus-agent-remove-group): New command and
+       keystroke.
+
+       * rfc2047.el (rfc2047-decode-region): Check for us-ascii.
+
+1999-01-02 14:12:41  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-agent.el (gnus-agent-write-servers): Make directory.
+
+1998-12-26 02:38:01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-view.el (mm-inline-text): Bind current id.
+
+       * mm-decode.el (mm-handle-id): New macro.
+       (mm-make-handle): Accept id.
+       (mm-dissect-singlepart): Use it.
+
+1998-12-23  Matt Pharr  <mmp@graphics.stanford.edu>
+
+       * message.el (message-cite-original-without-signature): Use
+       message-signature-separator when searching for signature in
+       message-cite-original-without-signature.
+
+1998-12-24 16:25:38  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus.el (gnus-server-to-method): Check named methods.
+
+1998-12-24 03:27:02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-view.el (mm-view-message): Goto point-min.
+
+       * nnmail.el (nnmail-article-group): Don't delete lines, only
+       shorten them.
+
+       * gnus-msg.el (gnus-configure-posting-styles): Also do nil
+       values.
+
+       * nnheader.el (nnheader-temp-directory): New variable.
+       (nnheader-temp-directory): Removed.
+
+1998-12-22  Jack Vinson  <jvinson@chevax.ecs.umass.edu>
+
+       * mailcap.el (mailcap-parse-mailcaps): Add "~/.mailcaps" to the
+       list of files to check for mailcap entries under windows-nt.
+
+1998-12-24 03:02:15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-maybe-hide-headers): Check whether the
+       summary buffer exists.
+
+1998-12-22  Aaron M. Ucko  <amu@mit.edu>
+
+       * nnsoup.el (nnsoup-store-reply): Remove code to deal with
+       irrelevant Sun sendmail bug.
+       (nnsoup-store-reply): Stop mucking with mail-header-separator.
+
+       * message.el (message-send-news): Bind mail-header-separator to
+       "" when asking backend to post.
+
+1998-12-22  Karl Kleinpaste  <karl@justresearch.com>
+
+       * mm-uu.el (mm-dissect-disposition): New variable.
+       (mm-uu-dissect): Use it.
+
+1998-12-21 21:34:22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-view.el (mm-inline-text): Bind url-current-object.
+
+1998-12-06 03:05:41  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-range.el (gnus-remove-from-range): Rewrite.
+
+1998-12-09  SL Baur  <steve@altair.xemacs.org>
+
+       * gnus-picon.el (annotations): Remove bogus require 'xpm.
+
+1998-12-18  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * message.el (message-encode-message-body): Insert `MIME-Version'
+       instead of `Mime-Version'.
+
+1998-12-04  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * message.el (message-insert-mime-part): Add the attachment
+       disposition.
+       (message-insert-mime-part): Make TYPE and DESCRIPTION optional.
+       (message-mime-query-type): New function.
+       (message-mime-query-description): Ditto.
+       (message-mime-query-file): Ditto.
+       (message-insert-mime-part): Use them.
+       (message-mime-insert-external): Use the new stuff.
+
+1998-12-19 23:02:26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnmail.el (nnmail-split-header-length-limit): New variable.
+
+       * mm-decode.el (mm-dissect-buffer): Check syntax.
+
+       * rfc2231.el (rfc2231-parse-string): Remove check for syntax.
+
+       * rfc2047.el (rfc2047-encodable-p): Use mm-find-charset-region.
+       (rfc2047-dissect-region): Ditto.
+
+1998-12-17 18:36:43  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-view.el (mm-view-message): Decode charset.
+
+1998-12-16 16:01:22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * rfc2231.el (rfc2231-parse-string): Ignore syntactically invalid
+       CT headers.
+
+Wed Dec 16 01:44:40 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding): Use
+       mm-uu-*-function.
+       * mm-uu.el (mm-uu-dissect): Use x-uuencode.
+
+1998-12-16 10:20:52  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-send-mail): Do MML first.
+       (message-send-news): Ditto.
+
+1998-12-15 20:57:18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-picon.el (gnus-picons-face): New face.
+       (gnus-picons-try-face): Use it.
+
+Tue Dec 15 19:17:43 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.68 is released.
+
+Tue Dec 15 18:28:24 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.67 is released.
+
+Tue Dec 15 17:31:44 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.66 is released.
+
+1998-12-13 11:00:43  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-insert-mime-button): Decode description.
+
+Sat Dec  5 16:50:49 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-decode-encoded-words): Rollback to 0.55.
+       (gnus-decode-header-methods): Ditto.
+       (gnus-decode-with-mail-decode-encoded-word-region): Ditto.
+
+1998-12-13 10:04:39  Lloyd Zusman  <ljz@asfast.com>
+
+       * gnus-xmas.el (gnus-xmas-summary-recenter): Allow numbers.
+
+1998-12-13 09:32:38  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml.el (mml-insert-mime-headers): Encode description.
+
+       * nnfolder.el (nnfolder-request-expire-articles): Go to the date
+       line.
+
+       * gnus-sum.el (gnus-default-charset): Doc fix.
+
+Wed Dec  9 15:18:39 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-display-part): Forward a line.
+
+Wed Dec  9 13:30:29 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-running-ntemacs): New variable.
+       (mm-text-coding-system): Ditto.
+       * nnmail.el (nnmail-incoming-coding-system): Ditto.
+       (nnmail-split-incoming): Use nnmail-incoming-coding-system.
+
+1998-12-13 08:52:45  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-picon.el (gnus-picons-network-display-internal): Don't set
+       buffer.
+
+       * message.el (message-insert-headers): New command and keystroke.
+
+1998-12-07 23:42:14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-inline-media-tests): Recognize x-xbitmap.
+       (mm-get-image): Ditto.
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding): Only for
+       base64, uudecode and binhex.
+
+Sun Dec  6 21:58:31 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding): Replace CRLF
+       in text/plain.
+       * mm-uu.el (mm-uu-dissect): Use inline.
+
+1998-12-07 23:19:14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-view.el (mm-view-message): New function.
+
+       * mm-encode.el (mm-content-transfer-encoding-defaults): Changed to
+       qp.
+
+1998-12-07  Karl Kleinpaste  <karl@justresearch.com>
+
+       * mm-encode.el (mm-content-transfer-encoding-defaults): Add an
+       entry for message/rfc822 as 8bit.
+
+1998-12-07 23:16:54  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mailcap.el (mailcap-mime-extensions): Add patch.
+
+1998-12-05  Dale Hagglund  <rdh@best.com>
+
+       * gnus-sum.el (gnus-summary-display-buttonized): Use prefix
+       argument to force all multipart/* to look like multipart/mixed.
+
+       * gnus-art.el (gnus-mime-display-multipart-as-mixed): New
+       variable.
+       (gnus-mime-display-part): Use it.
+
+1998-12-07 22:46:37  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-draft.el (gnus-draft-send): Only disable checks for
+       non-interactive use.
+       (gnus-draft-send-message): Use it.
+
+Sun Dec  6 19:36:53 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.65 is released.
+
+1998-12-06 20:11:02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-prepare-display): Don't init w3.
+
+       * mm-view.el (mm-inline-text): Bind url-standalone-mode here.
+
+Sat Dec  5 18:35:42 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.64 is released.
+
+1998-12-05 18:51:13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-view.el (mm-setup-w3): Don't load.
+
+       * gnus-msg.el (gnus-setup-message): Set group name.
+       (gnus-group-mail): Avoid leaking local vars.
+
+       * message.el (message-attach-file): Renamed.
+       (message-mime-attach-file): Renamed again.
+
+1998-12-05  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * gnus-art.el (article-decode-encoded-words): Bind
+       rfc2047-default-charset here.
+
+       * gnus-art.el (gnus-insert-mime-button): Nix slashes in file name.
+
+1998-12-05 18:33:27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-picon.el (gnus-picons-setup-buffer): Run picons hook.
+       (gnus-picons-setup-hook): New hook.
+
+1998-12-05  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * mailcap.el (mailcap-mime-data): Remove "*" from documentation
+       string.
+       (mailcap-mime-extensions): Ditto.  Made first sentense fit a
+       line.
+
+1998-12-05 17:11:04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-prepare-display): Setup w3.
+       (gnus-mime-view-part): Ditto.
+       (gnus-mime-inline-part): Dotii.
+       (gnus-mime-externalize-part): Daddo.
+       (gnus-mime-internalize-part): Tutti frutti.
+       (gnus-widget-press-button): Da da do.
+
+       * mm-view.el (mm-setup-w3): Require url-vars.
+
+Fri Dec  4 12:13:12 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-draft-coding-system): Fix for XEmacs-NT.
+       * mm-util.el (mm-find-charset-region): Ditto.
+
+1998-12-05 16:30:01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-send): Don't encode here.
+       (message-send-mail): But here.
+       (message-send-news): And here.
+
+1998-12-04 15:29:02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-message-insert-stylings): Don't insert twice.
+
+Fri Dec  4 04:09:15 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.63 is released.
+
+1998-12-04 04:59:20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml.el (mml-base-boundary): Shorten.
+
+       * message.el (message-insert-mime-part): Use default.
+
+       * gnus-art.el (gnus-insert-mime-button): Bind gnus-tmp-type-long.
+
+1998-12-03  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus-art.el (gnus-mime-display-alternative): Use (*) for radio
+       buttons, not [*].
+
+1998-12-04  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * gnus-art.el (gnus-insert-mime-button): Do proper help-echo.
+
+1998-12-04 04:48:37  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * gnus-art.el (gnus-insert-mime-button): Fix.
+
+1998-12-03  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * message.el (message-insert-mime-part): Nicify prompts.
+       (message-insert-mime-part): Really delete duplicates.
+       (message-insert-mime-part): Check against common errors.
+       (message-insert-mime-part): Fix docstring.
+
+1998-12-04 04:41:58  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-mime-internalize-part): Bugged out.
+
+1998-12-03  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * gnus-art.el (gnus-mime-button-line-format): Nicify.
+       (gnus-insert-mime-button): Modify accordingly.
+
+1998-12-04 01:50:53  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-display-mime): Set window point.
+
+       * mm-decode.el (mm-display-external): Only decode when not
+       saving.
+       (mm-alternative-precedence): Prefer multiparts.
+       (mm-inline-media-tests): Inline multiparts.
+
+       * gnus-picon.el (gnus-picons-next-job-internal): Do bar if asked.
+       Ignore errors when requiring url.
+
+       * mml.el (mml-quote-region): New command.
+
+       * message.el (message-cite-original): Use it.
+       (message-cite-original-without-signature): Ditto.
+
+Thu Dec  3 12:53:58 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.62 is released.
+
+1998-12-03 13:38:36  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-mime-view-all-parts): Work with multiparts.
+
+1998-12-03  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * mm-view.el (mm-inline-text): Use `point-min-marker' and
+       `point-max-marker'.
+
+1998-12-03 13:22:57  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mailcap.el (mailcap-mime-extensions): Use image/xpm for xpms.
+
+       * gnus-art.el (gnus-mime-display-single): Check for attachment
+       before other tests.
+
+1998-12-03  Didier Verna  <verna@inf.enst.fr>
+
+       * gnus-msg.el (gnus-configure-posting-styles): find a
+       posting-style entry in the group parameters, if any, and honor it
+       at the end.
+
+1998-12-03 13:03:37  Felix Lee  <flee@teleport.com>
+
+       * nntp.el (nntp-after-change-function): Fix.
+
+1998-12-03 12:44:30  Mike McEwan  <mike@lotusland.demon.co.uk>
+
+       * mml.el (mml-generate-mime-1): Insert literally.
+
+1998-12-03 00:23:17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml.el (mml-insert-mime-headers): Removed debug.
+
+1998-12-02 22:22:03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-show-article): Destroy parts when
+       prefixed.
+
+       * mm-encode.el (mm-content-transfer-encoding-defaults): Default
+       application/emacs-lisp to 8bit.
+
+1998-12-03  Dale Hagglund  <rdh@best.com>
+
+       * mm-decode.el (mm-quote-arg): Add quoting of '()', '<>', and '|'.
+
+Wed Dec  2 20:24:27 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.61 is released.
+
+1998-12-02 21:12:56  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml.el (mml-parse-1): Skipped parts.
+       (mml-insert-mime-headers): Nil is a list.
+       (mml-generate-mime-1): Don't insert literally.
+       (mml-read-tag): Drop text props.
+       (mml-read-part): Ditto.
+       (mml-parse-singlepart-with-multiple-charsets): Ditto.
+
+Wed Dec  2 20:07:16 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.60 is released.
+
+1998-12-02 20:11:28  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml.el (mml-parse-1): Don't throw contents away.
+
+1998-12-02  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * mml.el (mml-compute-boundary-1): Regexp-quote the boundary.
+
+1998-12-02 18:42:24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml.el (mml-parse-singlepart-with-multiple-charsets): New
+       function.
+       (mml-parse-1): Use it.
+
+Tue Dec  1 23:04:25 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-decode-with-mail-decode-encoded-word-region):
+       Use gnus-newsgroup-default-charset.
+       (article-decode-encoded-words): Remove charset codes.
+       * gnus-sum.el (gnus-newsgroup-default-charset): Use
+       gnus-default-charset.
+
+1998-12-02 03:14:20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-send-mail): Don't encode here.
+       (message-send-news): Nor here.
+       (message-send): ... but here instead.
+
+       * gnus-picon.el (gnus-picons-display-article-move-p): Changed
+       default to nil.
+       (gnus-article-display-picons): Replace From line.
+       (gnus-group-display-picons): Replace Newsgroups line.
+       (gnus-picons-display-glyph): Set baseline.
+       (gnus-group-display-picons): Piconize the entire Newsgroups line.
+       (gnus-picons-xbm-face): Revert to old, standard colors.
+
+       * message.el (message-fetch-field): Remove text props.
+
+       * gnus-art.el (gnus-article-normalized-header-length): New
+       variable.
+       (article-normalize-headers): New command and keystroke.
+
+       * gnus-picon.el (gnus-picons-xbm-face): Changed colors.
+
+Wed Dec  2 01:43:48 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.59 is released.
+
+1998-12-02 01:38:31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml.el (mml-insert-mime-headers): Beep at multiple charsets.
+
+       * gnus-art.el (gnus-mime-copy-part): Set buffer-file-name.
+
+1998-11-30  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * mml.el (mml-generate-mime-1): Handle unquoting end-tags.
+
+1998-12-02 00:15:30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-all-images-fit): New variable.
+       (mm-image-fit-p): Use it.
+
+       * gnus-art.el (gnus-mime-display-single): Use it.
+       (gnus-mime-internalize-part): New command and keystroke.
+
+       * mm-decode.el (mm-user-automatic-external-display): New
+       variable.
+       (mm-automatic-external-display-p): New function.
+
+       * gnus-picon.el (gnus-picons-xbm-face): Default to sensible
+       colors.
+
+1998-12-01 23:52:05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-repair-multipart): Reselect article.
+
+       * gnus-art.el (gnus-with-article): Work in the original article
+       buffer.
+       (gnus-with-article): Work in read-only groups.
+
+Tue Dec  1 00:15:36 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-bodies.el (mm-decode-string): Return original string if not
+       decode.
+
+Mon Nov 30 23:38:02 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-uu.el (mm-uu-dissect): Use mm-make-handle.
+
+1998-12-01 01:53:49  Francois Pinard  <pinard@iro.umontreal.ca>
+
+       * nndoc.el (nndoc-mime-parts-type-p): Do related.
+
+Tue Dec  1 00:46:20 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.58 is released.
+
+1998-11-30  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * mm-decode.el (mm-get-image): Return a glyph, not an image
+       specifier.
+
+1998-11-29  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * rfc2047.el (rfc2047-decode): Bind mm-default-charset.
+
+1998-12-01 01:23:35  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-parse.el (rfc2045): Required.
+
+1998-12-01 00:59:53  William M. Perry  <wmperry@aventail.com>
+
+       * mm-view.el (mm-inline-text): Remove props.
+
+1998-12-01 00:18:47  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-view.el (mm-setup-w3): Protect url-misc.
+
+       * message.el (message-ignored-resent-headers): Remove
+       Gnus-Warning.
+
+       * mml.el (mml-insert-mime-headers): Use encoding.
+       (mml-parameter-string): Ditto.
+
+       * rfc2045.el: New file.
+       (rfc2045-encode-string): New function.
+
+1998-11-30 23:11:22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-parse.el (mail-header-encode-parameter): New function.
+
+       * rfc2231.el (rfc2231-encode-string): New function.
+
+Mon Nov 30 13:52:50 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-bodies.el (mm-decode-string): New function.
+       * mm-view.el (mm-inline-text): Use mm-decode-string.
+
+Mon Nov 30 21:57:00 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.57 is released.
+
+1998-11-23  Felix Lee  <flee@cygnus.com>
+
+       * nntp.el (nntp-async-needs-kluge): new setting.
+       (nntp-async-timer): new var.
+       (nntp-async-process-list): new var.
+       (nntp-async-kluge): new function.
+       (nntp-async-timer-handler): new function.
+       (nntp-async-wait): new function.
+       (nntp-async-stop): new function.
+       (nntp-after-change-function): renamed, and split apart.
+       (nntp-async-trigger): new function.
+       (nntp-do-callback): new function.
+       (nntp-accept-process-output): add optional timeout arg.
+
+       * gnus-async.el (gnus-async-request-fetched-article): fixed.
+       (gnus-async-wait-for-article): new function.
+       (gnus-async-with-semaphore): s/asynch/async/.
+
+1998-11-30 16:54:56  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-with-article): Don't encode.
+       (gnus-insert-mime-button): Fall back on filename from C-D.
+       (gnus-mime-display-single): Have dots right on text/plain
+       attachments.
+
+       * mm-decode.el (mm-dissect-buffer): Respect Content-Disposition in
+       broken parts.
+
+       * gnus-art.el (gnus-with-article): Flush cache and backlog.
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding): Also do
+       binhex.
+
+       * gnus-sum.el (gnus-summary-reparent-thread): Use new macro.
+       (gnus-summary-repair-multipart): New command and keystroke.
+
+       * gnus-art.el (gnus-with-article-buffer): New macro.
+
+Sun Nov 29 23:51:57 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-inline-part): Do not get part when
+       undisplay the part.
+
+1998-11-30 03:38:35  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-util.el (gnus-make-sort-function-1): Allow lambdas.
+
+       * mml.el (mml-read-part): Partition right.
+
+       * mm-decode.el (mm-handle-set-cache): New macro.
+       (mm-handle-cache): Ditto.
+       (mm-make-handle): Ditto.
+       (mm-dissect-singlepart): Use it.
+       (mm-get-image): Use the cache.
+
+1998-11-29 23:44:44  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-mime-display-mixed): Rewrite.
+       (gnus-mime-display-single): Don't insert lines between parts.
+
+Sun Nov 29 04:55:40 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnmail.el (nnmail-file-coding-system-1): New variable.
+       * nnfolder.el (nnfolder-file-coding-system): Ditto.
+       (nnfolder-read-folder): Use nnfolder-file-coding-system.
+       * nnml.el (nnml-file-coding-system): New variable.
+       (nnml-request-article): Use nnml-file-coding-system.
+
+Sun Nov 29 15:12:52 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.56 is released.
+
+1998-11-29 00:52:53  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-mime-display-part): New function.
+       (gnus-mime-display-mixed): Use it.
+
+       * mm-view.el (mm-setup-w3): Don't register.
+
+       * message.el (message-cite-original): Cite parts.
+
+1998-11-28 23:51:25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml.el (mml-parameter-string): New function.
+       (mml-insert-mime-headers): Separated into new function.
+
+1998-11-28  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * mml.el (mml-make-boundary): Use `make-string'.
+
+1998-11-27  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * binhex.el (binhex-insert-char): Ditto.
+
+       * base64.el (base64-insert-char): Ditto.
+
+       * uudecode.el (uudecode-insert-char): Code correctly.
+
+1998-11-28 01:08:19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml.el (mml-generate-mime): Don't generate multiparts for
+       empties.
+
+       * gnus-art.el (gnus-display-mime): Save excursion.
+
+       * message.el (message-remove-first-header): New function.
+       (message-encode-message-body): Use it.
+
+Fri Nov 27 12:26:10 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.55 is released.
+
+1998-11-27 12:38:52  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-view.el (mm-setup-w3): New function.
+
+       * mm-decode.el (mm-content-id-get-contents): New function.
+       (mm-content-id-get-type): Ditto.
+       (mm-content-id-get-encoding): Ditto.
+       (mm-get-handle-by-content-id): Removed.
+
+1998-11-25  Colin Rafferty  <colin@xemacs.org>
+
+       * message.el (message-generate-new-buffers): Fix tag.
+
+1998-11-25 10:43:28  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-buffer-name): Check for unique first.
+
+       * gnus-art.el (gnus-unbuttonized-mime-type-p): use
+       gnus-inhibit-mime-unbuttonizing.
+
+       * gnus-sum.el (t): Bind M-t.
+       (gnus-inhibit-unbuttonizing): New variable.
+       (gnus-summary-toggle-display-buttonized): New command.
+
+       * gnus-art.el (gnus-display-mime): Select article window.
+       (article-strip-trailing-space): New command and keystroke.
+
+       * nneething.el (nneething-include-files): New variable.
+       (nneething-create-mapping): Use it.
+
+       * nntp.el (nntp-possibly-change-group): Use nntp-send-command.
+
+       * nnvirtual.el (nnvirtual-request-update-mark): Only yodate
+       ayto-expirable marks.
+
+1998-11-24 21:00:02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-mime-view-all-parts): Set buffer.
+
+       * gnus-sum.el (gnus-summary-display-buttonized): Don't pass on
+       ARG.
+
+       * gnus-art.el (gnus-article-mode-line-format): Doc fix.
+
+Tue Nov 24 14:57:41 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-binary-coding-system): New variable.
+       (mm-with-unibyte-buffer): Use mm-binary-coding-system.
+       * mm-decode.el (mm-display-external): Ditto.
+
+Tue Nov 24 10:43:06 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.54 is released.
+
+1998-11-24 11:21:32  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-newsgroup-default-charset-alist): Note fj.
+
+1998-11-24 11:14:54  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-save-part): Unquote.
+
+1998-11-24 11:14:39  Matt Armstrong  <matta@geoworks.com>
+
+       * mm-decode.el (mm-save-part): Bind coding system for write.
+
+1998-11-24 10:42:30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-mode-line-format): New default.
+       (gnus-article-mime-part-status): New function.
+
+       * message.el (message-send-news): Check the body syntax before
+       encoding.
+
+       * gnus-art.el (gnus-unbuttonized-mime-type): New function.
+       (gnus-mime-display-single): Use it.
+       (gnus-mime-display-alternative): Ditto.
+
+       * mm-decode.el: Check for whether we are running under a term.
+
+1998-11-22 08:12:25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-preferred-alternative): Default to first
+       alternative.
+       (mm-preferred-alternative): No, we dont.
+
+Tue Nov 24 03:01:48 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-display-external): Use binary instead of
+       no-conversion.
+       * gnus-agent.el (gnus-agent-file-coding-system): Ditto.
+       * nnheader.el (nnheader-file-coding-system): Ditto.
+       * mm-util.el (mm-with-unibyte-buffer): Use binary instead of nil.
+
+Mon Nov 23 01:51:57 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-newsgroup-setup-default-charset): Use group
+       name without method.
+
+Mon Nov 23 01:26:40 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-newsgroup-default-charset): Rename
+       coding-system -> default-charset.
+       (gnus-newsgroup-default-charset-alist): Ditto.
+       (gnus-summary-local-variables): Ditto.
+       (gnus-set-global-variables): Ditto.
+       (gnus-get-newsgroup-headers): Ditto.
+       (gnus-summary-from-or-to-or-newsgroups): Ditto.
+       (gnus-get-newsgroup-headers-xover): Ditto.
+       (gnus-newsgroup-setup-default-charset): Ditto.
+       (article-decode-mime-words): Ditto.
+       (article-decode-charset): Ditto.
+       (article-decode-encoded-words): Ditto.
+       (article-de-quoted-unreadable): Ditto.
+       (gnus-mime-view-all-parts): Ditto.
+       (gnus-mime-externalize-part): Ditto.
+       (gnus-mm-display-part): Ditto.
+       (gnus-mime-display-single): Ditto.
+       (gnus-mime-display-alternative): Ditto.
+       * lpath.el : Ditto.
+
+Mon Nov 23 00:54:33 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-decode-region): Do not decode nil charset.
+       * gnus-art.el (article-decode-charset): Overlay
+       rfc2047-default-charset.
+       * message.el (message-draft-coding-system): New variable.
+       (message-set-auto-save-file-name): Use message-draft-coding-system.
+       * nndraft.el (nndraft-request-article): Ditto.
+       * gnus-start.el (gnus-start-draft-setup): Set charset nil.
+       * gnus-agent.el (gnus-agent-queue-setup): Ditto.
+
+Sun Nov 22 04:42:22 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-uu.el (mm-uu-test): New function.
+       (mm-uu-dissect): Inherit charset and cte from head.
+       * gnus-art.el (article-decode-charset): Use mm-uu-test.
+
+Sat Nov 21 09:57:01 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.53 is released.
+
+1998-11-21 05:54:19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-get-image): New function.
+       (mm-image-fit-p): New function.
+
+       * gnus-xmas.el (gnus-xmas-annotation-in-region-p): Ditto.
+
+       * gnus-util.el (gnus-annotation-in-region-p): New definition.
+
+       * gnus-art.el (gnus-article-insert-newline): New function.
+       (article-goto-body): New function.
+
+1998-11-20 10:34:04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-mime-display-single): Insert blank line before
+       buttons.
+
+       * gnus-sum.el (gnus-summary-display-buttonized): New command and
+       keystroke.
+
+       * gnus-art.el (gnus-mime-display-single): Don't insert a blank
+       line between parts.
+
+       * message.el (message-remove-header): Go to end if wanted.
+
+1998-11-20  Karl Kleinpaste  <karl@justresearch.com>
+
+       * gnus-art.el (gnus-mime-display-alternative): Avoid window
+       movement with save-window-excursion.
+
+Fri Nov 20 03:50:30 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-inline-part): Use argument as charset.
+
+Fri Nov 20 03:37:53 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-bodies.el (mm-decode-body): Remove buffer-file-coding-system.
+
+Fri Nov 20 01:20:38 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-from-or-to-or-newsgroups): Use
+       gnus-newsgroup-coding-system.
+       (gnus-get-newsgroup-headers): Ditto.
+       (gnus-get-newsgroup-headers-xover): Ditto.
+       (gnus-set-global-variables): Ditto.
+       * gnus-art.el (article-decode-mime-words): Ditto.
+       (article-decode-charset): Ditto.
+       (article-decode-encoded-words): Ditto.
+       (article-de-quoted-unreadable): Ditto.
+       (gnus-mime-view-all-parts): Ditto.
+       (gnus-mime-externalize-part): Ditto.
+       (gnus-mm-display-part): Ditto.
+       (gnus-mime-display-alternative): Ditto.
+       (gnus-mime-display-single): Ditto.
+       * mm-view.el (mm-inline-text): Use default coding system.
+
+Fri Nov 20 00:54:37 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-newsgroup-coding-system-alist): New variable.
+       (gnus-newsgroup-iso-8859-1-forced-regexp): New variable.
+       (gnus-newsgroup-coding-system): New local variable.
+       (gnus-newsgroup-iso-8859-1-forced): New local variable.
+       (gnus-summary-local-variables): Add two new local variables.
+       (gnus-newsgroup-setup-coding-system): New function.
+       (gnus-select-newsgroup): Setup coding system.
+       * lpath.el: Add two new variables.
+       * mm-util.el (mm-charset-iso-8859-1-forced): New variable.
+       (mm-charset-to-coding-system): Use mm-charset-iso-8859-1-forced.
+       * gnus-cus.el (gnus-group-parameters): Customizable
+       iso-8859-1-forced.
+
+Fri Nov 20 05:30:26 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.52 is released.
+
+1998-11-20 04:32:23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * rfc2047.el (rfc2047-encode-message-header): Encode the default
+       encoding.
+
+       * gnus-art.el (gnus-mime-display-single): Insert buttons for
+       undisplayed text types.
+
+       * mm-decode.el (mm-automatic-display-p): Only prefer inlinable
+       types.
+
+1998-11-19  Felix Lee  <flee@cygnus.com>
+
+       * nntp.el (nntp-after-change-function-callback): recover from C-g.
+
+1998-11-19  Felix Lee  <flee@cygnus.com>
+
+       * gnus-async.el (gnus-asynch-obarray): rename to
+       gnus-async-hashtb, and don't buffer-local it.
+
+       (gnus-async-article-callback): new function.
+       (gnus-make-async-article-function): use it.
+
+       (gnus-async-current-prefetch-group): new var.
+       (gnus-async-current-prefetch-article): new var.
+       (gnus-async-request-fetched-article): are we fetching it already?
+
+       (gnus-async-delete-prefected-entry): s/prefected/prefetched/ .
+
+1998-11-20 02:49:21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-show-article): Require.
+
+       * message.el: Provide before hooks.
+       (message-send-news): Do MIME before headers.
+
+       * gnus-art.el (gnus-article-check-buffer): New function.
+       (gnus-article-read-summary-keys): Use it.
+
+       * mm-decode.el (mm-user-automatic-display): Display all inline
+       images.
+
+       * gnus-art.el (gnus-mime-display-single): Don't buttonize so
+       much.
+       (gnus-unbuttonized-mime-types): New variable.
+
+1998-11-19 06:29:03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-inhibit-user-auto-expire): Changed to t.
+
+       * mm-decode.el (mm-quote-arg): Quote semicolons.
+
+       * gnus-art.el (gnus-mime-display-single): Don't display
+       attachments.
+       (gnus-mime-externalize-part): New command and keystroke.
+
+       * mm-decode.el (mm-dissect-buffer): Pass on the description info.
+       (mm-alternative-precedence): Changed order.
+
+1998-11-07 17:41:47  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus.el (gnus-method-simplify): New function.
+       (gnus-native-method-p): New function.
+       (gnus-secondary-method-p): Use gnus-method-equal.
+
+       * gnus-start.el (gnus-group-change-level): Shorten select method.
+
+Thu Nov 19 04:48:42 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.51 is released.
+
+1998-11-19 04:02:34  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el: Applied patches from 5.6.45.
+
+       * gnus-score.el (gnus-score-find-trace): Print complete file
+       paths.
+       (gnus-score-find-trace): Truncate lines.
+
+       * gnus.el (gnus-message-archive-group): Allow function.
+
+       * message.el (message-encode-message-body): Remove Mime-Version
+       before inserting.
+
+       * gnus-cus.el (gnus-group-customize): Optional topic.
+
+       * gnus-sum.el (gnus-summary-customize-parameters): New command and
+       keystroke.
+
+Wed Nov 18 13:46:08 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-encode-message-body): Rewrite.
+
+1998-11-18 07:37:47  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml.el (mml-base-boundary): New variable.
+       (mml-make-boundary): New function.
+
+       * gnus-cache.el (gnus-cache-coding-system): New variable.
+       (gnus-cache-request-article): Use it.
+
+       * message.el (message-insert-mime-part): Delete duplicates.
+
+Wed Nov 18 11:52:19 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-display-alternative): Set end of
+       multipart and display even when nothing is preferred.
+
+Wed Nov 18 05:06:44 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.50 is released.
+
+1998-11-18 04:42:01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-inline-media-tests): Check that device-type is
+       fbound.
+
+       * gnus-sum.el (gnus-summary-sort): Didn't do reverse.
+
+1998-11-07 23:39:48  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus.el (gnus-similar-server-opened): Compare backend.
+
+1998-11-08 03:37:42  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-topic.el (gnus-topic-expire-articles): New function.
+       (gnus-topic-mode-map): Bind it.
+
+1998-11-10  Miles Bader  <miles@ccs.mt.nec.co.jp>
+
+       * gnus-sum.el
+       (gnus-auto-expirable-marks): New variable.
+       (gnus-inhibit-user-auto-expire): New variable.
+       (gnus-summary-mark-article-as-read, gnus-summary-mark-article):
+       When looking to see if we should expire instead, check
+       gnus-auto-expirable-marks instead of using a hard-wired list.
+       (gnus-summary-mark-as-read-forward,
+       gnus-summary-mark-as-read-backward):
+       Pass gnus-inhibit-user-auto-expire for the no-expire argument to
+       gnus-summary-mark-forward, instead of `t'.
+
+1998-11-18 03:30:26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml.el (mml-compute-boundary): New function.
+       (mml-compute-boundary-1): New function.
+       (mml-generate-mime-1): Use it.
+
+1998-11-18  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * mml.el (mml-generate-mime-1): Always precede closing boundary
+       with newline.
+
+1998-11-18 02:36:37  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml.el (mml-generate-mime-1): Do right boundaries when several
+       multiparts.
+
+       * mm-decode.el (mm-user-automatic-display): Default to inline
+       jpeg.
+
+       * mml.el (mml-generate-mime-1): Encode non-text parts.
+
+Wed Nov 18 02:22:23 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.49 is released.
+
+1998-11-18 00:37:43  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-view.el (mm-inline-text): Require w3-vars.
+
+       * gnus-setup.el (gnus-use-tm): Removed.
+
+       * gnus-art.el (gnus-article-goto-part): Don't beep.
+       (gnus-article-view-part): Check return value.
+       (gnus-mime-display-alternative): Don't display when there is
+       nothing to display.
+
+       * mml.el (mml-generate-mime-1): Don't use a unibyte buffer.
+       (mml-generate-mime-1): Use unibyte for binaries.
+
+       * gnus-art.el (gnus-display-mime): Call
+       gnus-article-mime-part-function.
+       (gnus-mime-part-function): New function.
+       (gnus-article-mime-part-function): New function.
+
+       * mml.el (mml-generate-mime-1): Don't insert so many newlines.
+
+1998-11-16 06:44:19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml.el (mml-generate-mime-1): Do it in unibyte buffers.
+
+       * message.el (message-font-lock-keywords): Highlight MML.
+       (message-mml-face): New font.
+
+Mon Nov 16 23:34:12 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-display-mime): Clean up even when no handles.
+       (gnus-mm-display-part): Do not select-window if the article window
+       is not found.
+
+Mon Nov 16 02:26:40 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-move-article): Use no-encode for B m.
+
+Mon Nov 16 02:00:05 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.48 is released.
+
+1998-11-15 23:18:56  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-bodies.el (mm-encode-body): Disbabled for nonmule.
+
+       * mm-util.el (mm-find-charset-region): Bogus change for non-Mule.
+
+       * message.el (message-cite-original-without-signature): Ditto.
+       (message-cite-original): Quote parts.
+
+Sun Nov 15 22:01:55 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.47 is released.
+
+1998-11-15 20:11:33  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-encode-message-body): Insert MIME warning.
+
+       * mml.el (mml-read-tag): Look for #tag.
+
+       * mm-util.el (mm-find-charset-region): Check whether
+       enable-multibyte-characters is bound.
+
+Sun Nov 15 02:01:31 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.46 is released.
+
+1998-11-15 01:54:40  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-encode-message-body): Insert headers at the
+       right spot.
+
+Sun Nov 15 01:13:41 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.45 is released.
+
+1998-11-15 00:28:49  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nndraft.el (nndraft-save-mime-part): Removed.
+       (nndraft-get-mime-part): Ditto.
+
+       * message.el (message-format-mime-old): Removed.
+       (message-encode-message-body): Removed.
+       (message-encode-message-body): Renamed.
+
+1998-11-14 18:27:19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-get-newsgroup-headers): Translate \r's.
+
+       * message.el (message-format-mime): Check message-mime-part.
+
+       * mm-encode.el (mm-mime-file-types): Removed.
+       (mm-default-file-encoding): New definition.
+
+Sat Nov 14 01:29:39 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-view.el (mm-inline-image): Use mm-insert-inline.
+       * gnus-art.el (gnus-mm-display-part): Go to correct position.
+
+Sat Nov 14 05:47:57 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.44 is released.
+
+1998-11-14 03:59:14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-format-mime): New function.
+
+       * nndraft.el (nndraft-save-mime-part): New function.
+       (nndraft-get-mime-part): New function.
+
+       * mm-encode.el (mm-default-file-encoding): New function.
+       (mm-content-transfer-encoding): New function.
+       (mm-encode-buffer): New function.
+
+       * message.el: New command.
+       (message-mime-part): New variable.
+       (message-insert-mime-part): New command.
+
+       * mm-encode.el (mm-encode-content-transfer-encoding): New
+       function.
+
+       * mm-util.el (mm-content-transfer-encoding-defaults): New
+       variable.
+       (mm-mime-file-types): Taken from TM.
+
+Sat Nov 14 01:51:06 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.43 is released.
+
+1998-11-07  Karl Kleinpaste  <karl@jprc.com>
+
+       * gnus-cus.el (gnus-score-customize): Add "Extra" element.
+       * gnus-score.el (gnus-score-default-header): Ditto.
+       (gnus-header-index): Ditto.
+       (gnus-summary-increase-score): Ditto, & process "extra" requests.
+       (gnus-summary-header): Handle extra headers.
+       (gnus-summary-score-entry): Ditto, & provide new score element.
+       (gnus-summary-score-effect): Ditto.
+       (gnus-score-string): Avoid "extra" string sort, & modify match in
+       "extra" case.
+       * gnus-sum.el (gnus-make-score-map): Add "extra" element.
+
+1998-11-13 20:30:40  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-resend): Bind message-required-mail-headers
+       to nil.
+
+       * mm-view.el (mm-inline-text): Bind w3-strict-width.
+
+       * nngateway.el (require): Require cl.
+
+       * gnus-art.el (gnus-button-alist): Exclude more chars from news:
+       things.
+
+Wed Nov 11 02:15:06 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-fetch-headers): Create directory even
+       when no articles.
+
+1998-11-13 19:25:10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-ignored-resent-headers): Remove X-Gnus.
+
+1998-11-10  Colin Rafferty  <colin@xemacs.org>
+
+       * gnus-sum.el (gnus-ignored-from-addresses): Only quote
+       user-mail-address if non-nil.
+
+1998-11-13 18:50:18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-util.el (gnus-make-sort-function): Do `reverse'.
+       (gnus-make-sort-function-1): Ditto.
+
+       * gnus-art.el (gnus-mm-display-part): Switch to mm in right
+       window.
+
+1998-11-12 22:31:58  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-util.el (mm-with-unibyte-buffer): Ditto.
+
+       * binhex.el (binhex-decode-region): Quote.
+
+1998-11-10 05:32:28  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-decode-charset): Don't downcase charset.
+
+       * gnus-sum.el (gnus-get-newsgroup-headers-xover): Translate CR's.
+
+Sun Nov  8 23:17:24 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.42 is released.
+
+Sun Nov  8 02:36:33 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-display-mime): Add id for alternative part.
+
+1998-11-08 02:24:47  Simon Josefsson  <jas@pdc.kth.se>
+
+       * nntp.el (nntp-send-mode-reader): Revert.
+
+Sun Nov  8 00:45:13 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-fetch-articles): Use with-temp-buffer.
+
+Sat Nov  7 23:07:24 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-make-date): Fix for negative time zones.
+
+Sun Nov  8 01:00:16 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.41 is released.
+
+1998-11-08 00:52:38  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * mm-decode.el (mm-dissect-multipart): Quote regexp.
+
+1998-10-29  Sudish Joseph  <sj@eng.mindspring.net>
+
+       * gnus.el (gnus-short-group-name): When shortening foreign select
+       methods, do not scan for plusses beyond the first colon.
+
+1998-11-07  Mike McEwan  <mike@lotusland.demon.co.uk>
+
+       * gnus-agent.el (gnus-agent-save-group-info): Cater for group info
+       lines where `group' is the last thing on the line.
+
+1998-11-08 00:35:09  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-view-part): Do alternative.
+       (gnus-mime-display-alternative): Insert marker.
+
+1998-11-07 14:33:46  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-dissect-multipart): Quote regexp.
+
+       * nnmail.el (nnmail-expired-article-p): Protect against bogus
+       dates.
+
+       * gnus-cus.el (gnus-topic): Required.
+
+       * nnheader.el (nnheader-parse-nov): Parse extra.
+       (nnheader-nov-parse-extra): New macro.
+
+1998-10-31 12:33:22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-view-part): Internal move.
+
+1998-10-28  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus-cus-new.el (gnus-custom-topic): New free variable.
+       (gnus-group-customize): Support editing topic parameters.
+
+1998-10-29 12:09:20  Karl Kleinpaste  <karl@jprc.com>
+
+       * gnus-sum.el (gnus-summary-from-or-to-or-newsgroups): Add
+       indicators.
+
+1998-10-29 11:31:11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-mm-display-part): Return.
+       (gnus-article-view-part): Only go if external.
+       (gnus-article-dumbquotes-map): Do 205.
+
+       * mm-decode.el (mm-display-part): Return what was done.
+
+       * message.el (message-buffer-naming-style): New variable.
+       (message-generate-new-buffers): Extended.
+       (message-buffer-naming-style): Removed.
+       (message-buffer-name): Use it.
+       (message-do-send-housekeeping): Rename new styling.
+
+       * gnus-sum.el (gnus-summary-recenter): Allow
+       gnus-auto-center-summary to be a number.
+
+Wed Nov  4 02:24:39 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * pop3.el (pop3-open-server): Use "binary" instead of
+       "no-conversion".
+
+Sun Nov  1 01:26:42 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-srvr.el (gnus-browse-foreign-server): Set
+       gnus-browse-current-method to the result of gnus-server-to-method.
+
+Thu Oct 29 01:47:44 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-util.el (gnus-pull): Another optional argument.
+       * nnweb.el (nnweb-request-delete-group): Delete from
+       nnweb-group-alist and update active file.
+
+Thu Oct 29 01:05:08 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-make-group): Accept group of new
+       method.
+
+Wed Oct 28 02:19:16 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-fetch-group-1): Update dribble.
+
+Tue Oct 27 11:59:31 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-view.el (mm-inline-text): Postion of html portion.
+
+1998-10-29 10:26:54  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nntp.el (nntp-list-active-group): Waited for short strings.
+       (nntp-send-mode-reader): Ditto.
+       (nntp-open-connection): Ditto.
+
+       * gnus-int.el (gnus-request-group-articles): New function.
+
+       * nntp.el (nntp-request-listgroup): New function.
+       (nntp-request-group-articles): Renamed.
+
+1998-10-27 10:37:52  Karl Kleinpaste  <karl@jprc.com>
+
+       * nnheader.el (nnheader-parse-nov): Supply extra.
+
+1998-10-26 23:03:48  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-button-push): Don't go to
+       gnus-article-buffer.
+
+       * mm-view.el (mm-inline-image): Add a newline.
+
+       * gnus-start.el (gnus-check-first-time-used): Check more.
+
+1998-10-26 23:03:29  Francois Felix Ingrand  <felix@laas.fr>
+
+       * gnus-start.el (gnus-check-first-time-used): Check current.
+
+1998-10-26 22:07:52  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-util.el (mm-find-charset-region): New function.
+
+       * ietf-drums.el (ietf-drums-narrow-to-header): Work when no header.
+
+       * gnus-art.el (gnus-mime-button-menu): Fix.
+
+1998-10-26 22:07:43  Michael Welsh Duggan  <md5i@cs.cmu.edu>
+
+       * gnus-art.el (gnus-mime-button-menu): New definition.
+
+1998-10-26 01:46:11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-decode-charset): Downcase charset.
+       (article-decode-charset): Pass on type.
+       (article-decode-charset): Check nil charsets.
+       (article-remove-cr): Translate CR to LF.
+       (gnus-ignored-mime-types): Default to nil.
+
+       * nnheader.el (nnheader-insert-nov): Work when not Xref.
+
+       * gnus-sum.el (gnus-ignored-from-addresses): Default to
+       user-mail-address.
+       (gnus-nov-parse-extra): Didn't return right thing.
+
+1998-10-25 23:25:27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-xmas.el: Use compiled-function-p.
+
+Mon Oct 26 14:37:19 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-copy-Yo-buffer): Make it works when no header.
+
+Sun Oct 25 23:11:44 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.40 is released.
+
+1998-10-25 21:41:05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-mark-forward): Show thread.
+
+       * gnus-start.el (gnus-check-first-time-used): Ignore dribble.
+
+       * gnus-agent.el (gnus-agent-fetch-group-1): Bind name.
+
+       * nnml.el (nnml-possibly-create-directory): Check before making.
+
+1998-10-25 19:43:08  Kai Grossjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * nnheader.el (nnheader-insert-nov): Don't infloop.
+
+1998-10-25 19:26:11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-set-mode-line): Check that the spec has been
+       set up.
+
+1998-10-25 19:22:03  Joerg Lenneis  <lenneis@statrix2.wu-wien.ac.at>
+
+       * nneething.el (nneething-file-name): New definition.
+
+1998-10-25 17:56:23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-treatment-function-alist): Fix.
+       (gnus-summary-save-in-rmail): Use gnus-output-to-rmail.
+
+       * nndoc.el (nndoc-dissect-mime-parts-sub): Recognize first part.
+
+Sun Oct 25 06:23:13 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.39 is released.
+
+1998-10-25 00:34:39  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-ignored-mime-types): New variable.
+       (gnus-mime-display-single): Use it.
+       (gnus-treatment-function-alist): New variable.
+
+       * gnus.el (gnus-mime): New group.
+
+       * gnus-art.el (gnus-mime-display-alternative): Don't destroy
+       things for other parts.
+       (gnus-mime-display-alternative): Place point.
+
+       * gnus.el: autoload gnus-uu-post-news.
+
+       * mailcap.el (mailcap-mailcap-entry-passes-test): Also check
+       needsterm/DISPLAY.
+
+       * mm-decode.el (mm-display-part): Default to inline text/.*
+       parts.
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding): Default to
+       8bit.
+
+       * gnus-art.el (gnus-mime-copy-part): Use normal-mode.
+       (gnus-mime-display-single): Inline all text parts.
+       (gnus-article-narrow-to-signature): Removed mime:: stubs.
+
+1998-10-24 21:38:37  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnml.el (nnml-possibly-create-directory): Rewrite.
+       (nnml-request-create-group): Change to right server.
+
+       * gnus-xmas.el (gnus-xmas-define): Use byte-code-function-p.
+
+       * gnus-sum.el (gnus-set-mode-line): Use truncate-string-to-width.
+
+       * gnus.el: rmail-output-to-rmail-file autoload.
+
+       * gnus-util.el (gnus-output-to-rmail): Didn't work if not in
+       Gnus.
+
+       * nnheader.el (nnheader-parse-head): Checked wrong variable.
+
+       * gnus-sum.el (gnus-summary-update-mark): Ignore nil'd marks.
+
+Tue Oct 20 23:37:43 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-display-mixed): Multipart in
+       mixed part.
+
+Tue Oct 20 23:36:43 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-exit): Use mm-destroy-parts.
+
+       * gnus-sum.el (gnus-summary-exit-no-update): Ditto.
+
+Tue Oct 20 16:22:51 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-uu.el (mm-uu-dissect): Create pseudo multipart head.
+
+1998-10-24 20:51:53  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-valid-move-group-p): Make sure group has a
+       value.
+
+       * gnus-art.el (gnus-article-hidden-text-p): Return nil when not
+       hidden.
+
+       * gnus-spec.el (gnus-update-format-specifications): Use the
+       article mode line spec.
+
+       * gnus-art.el (gnus-insert-mime-button): Put right type.
+       (gnus-insert-prev-page-button): Ditto.
+       (gnus-insert-next-page-button): Dutti.
+
+       * pop3.el: New version installed.
+
+Sat Oct 24 16:48:51 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-uu.el (mm-uu-dissect): Delete the begining spurious newline
+       and display last part.
+
+Sat Oct 24 20:31:55 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.38 is released.
+
+1998-10-24 07:54:58  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-mime-decode-quoted-printable-buffer):
+       Removed.
+       (article-de-quoted-unreadable): Narrow to default.
+
+       * qp.el (quoted-printable-encode-region): Encode before QP-ing.
+
+       * gnus-art.el (article-decode-charset): Decode even when broken
+       MIME.
+
+       * gnus-sum.el (gnus-summary-from-or-to-or-newsgroups): Return
+       name.
+
+       * gnus-msg.el (gnus-copy-article-buffer): Delete headers.
+
+       * gnus-cache.el (gnus-cache-possibly-enter-article): Use
+       nnheader.
+
+       * nnmail.el (nnmail-extra-headers): New variable.
+
+       * nnheader.el (nnheader-insert-nov): Insert extra.
+
+       * gnus.el (gnus-summary-line-format): Doc fix.
+
+       * gnus-sum.el (gnus-get-newsgroup-headers): Parse extra.
+       (gnus-nov-parse-line): Ditto.
+       (gnus-nov-parse-extra): New macro.
+       (gnus-header): New function.
+       (gnus-update-summary-mark-positions): Change.
+       (gnus-ignored-from-addresses): New variable.
+       (gnus-summary-insert-from-or-to): New function.
+
+       * gnus.el (gnus-extra-headers): New variable.
+
+       * nnheader.el (make-mail-header): Expand.
+       (mail-header-extra): New macro.
+       (mail-header-set-extra): Ditto.
+       (make-full-mail-header): Expand.
+
+Sat Oct 24 07:41:42 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.37 is released.
+
+1998-10-24 07:29:11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-bodies.el (mm-decode-body): Check for multibyticity.
+
+       * mm-util.el (mm-enable-multibyte): Don't always switch multibyte
+       on.
+
+1998-10-22  Didier Verna  <verna@inf.enst.fr>
+
+       * gnus-spec.el (gnus-balloon-face-function): new function
+       (gnus-parse-format): understand the %< %> specifiers.
+       (gnus-parse-complex-format): ditto.
+
+1998-10-24 06:31:33  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el: Changed following-char to char-after throughout.
+
+1998-10-22 04:05:55  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-display-external): Protect more and message.
+
+Wed Oct 21 03:26:30 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-xmas.el (gnus-xmas-article-push-button): Go to the
+       position.
+
+Tue Oct 20 23:37:43 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-display-mixed): Multipart in
+       mixed part.
+
+Tue Oct 20 23:36:43 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-exit): Use mm-destroy-parts.
+
+       * gnus-sum.el (gnus-summary-exit-no-update): Ditto.
+
+Tue Oct 20 16:22:51 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-uu.el (mm-uu-dissect): Create pseudo multipart head.
+
+1998-10-21  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * mailcap.el (mailcap-save-binary-file): Use unwind-protect.
+
+       * mm-decode.el (mm-display-external): Set undisplayer to mm
+       buffer, not the current buffer; use unwind-protect.
+
+1998-10-21 00:07:59  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-exit): Destroy parts.
+       (gnus-summary-exit-no-update): Ditto.
+
+1998-10-20 22:02:05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-inline-media-tests): Look for w3.
+
+       * mailcap.el (mailcap-mime-data): Inline html.
+
+Tue Oct 20 20:25:03 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.36 is released.
+
+1998-10-20 18:13:08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-translate-strings):
+       (gnus-article-dumbquotes-map): Don't dot.
+
+       * pop3.el (pop3-open-server): Set point right.
+
+       * mm-decode.el (mm-dissect-multipart): Dissect hierarchically.
+       (mm-dissect-buffer): Ditto.
+       (mm-destroy-part): Ignore non-handles.
+       (mm-remove-part): Ditto.
+       (mm-destroy-parts): New function.
+       (mm-remove-parts): Ditto.
+
+       * gnus-art.el (gnus-mm-display-part): Don't move point.
+
+Tue Oct 20 02:16:36 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-uu.el : New file.
+
+       * gnus-art.el (gnus-display-mime): Dissect uu stuffs.
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding): Encoding as
+       a function.
+
+1998-10-20 00:35:05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-display-external): Check before selecting.
+
+Sat Sep 26 02:03:00 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-multi-decode-encoded-word-string): Rewrite.
+
+       * gnus-sum.el (gnus-decode-encoded-word-methods): New variable.
+
+       * gnus-sum.el (gnus-decode-encoded-word-methods-cache): New
+       variable.
+
+       * gnus-sum.el (gnus-encoded-word-method-alist): Deleted.
+
+       * gnus-art.el (gnus-decode-header-methods): New variable.
+
+       * gnus-art.el (gnus-decode-header-methods-cache): New variable.
+
+       * gnus-art.el (gnus-multi-decode-header): New function.
+
+Tue Oct 20 00:24:16 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.35 is released.
+
+1998-10-20 00:00:36  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * uudecode.el (uudecode-decode-region-external): Insert
+       literally.
+
+       * gnus-xmas.el (gnus-xmas-mime-button-menu): Moved here.
+
+       * mm-bodies.el (mm-decode-body): Optional encoding.
+
+1998-10-19 23:57:57  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-ems.el (gnus-mouse-3): New variable.
+
+       * binhex.el (binhex-decode-region-external): Don't use -internally.
+
+1998-10-16 14:54:02  Simon Josefsson  <jas@pdc.kth.se>
+
+       * mailcap.el (mailcap-parse-mailcaps): Only open regular
+       files.
+
+1998-09-26 22:28:01  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-group.el (gnus-add-marked-articles): Request backend update
+       of flags.
+
+1998-09-26 19:39:31  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-sum.el (gnus-update-read-articles):
+       (gnus-update-marks): Request backend update of mark.
+
+1998-09-26 16:27:27  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-range.el (gnus-remove-from-range): Don't add stuff in
+       list to range.
+
+1998-10-19 23:45:13  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus-sum.el (gnus-summary-exit-no-update): Don't expire.
+
+1998-10-14  SL Baur  <steve@altair.xemacs.org>
+
+       * gnus-sum.el: Move gnus-save-hidden-threads above where it is
+       first used.
+
+1998-10-10  SL Baur  <steve@altair.xemacs.org>
+
+       * mm-view.el: Require mm-decode for macros.
+
+       * mm-decode.el (mm-handle-type): Move macro declarations above the
+       place where they are used.
+
+Sun Oct 18 13:59:07 1998  Kurt Swanson  <ksw@dna.lth.se>
+
+       * gnus-msg.el (gnus-summary-mail-forward): Erase old forward
+       buffer.
+
+1998-10-19 23:38:11  Katsumi Yamaoka  <yamaoka@ga.sony.co.jp>
+
+       * nnagent.el (nnagent-open-server): Error message.
+
+1998-10-19 23:35:08  Joerg Lenneis  <lenneis@statrix2.wu-wien.ac.at>
+
+       * nnheader.el (nnheader-article-p): Recognize lower-case headers.
+
+1998-10-19  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * score-mode.el (gnus-score-mode-map): Ditto.
+
+       * message.el (message-mode-map): Ditto.
+
+       * gnus-uu.el (gnus-uu-post-news): Ditto.
+
+       * gnus-kill.el (gnus-kill-file-mode-map): Ditto.
+
+       * gnus-eform.el (gnus-edit-form-mode-map): Ditto.
+
+       * gnus-art.el (gnus-article-edit-mode-map): Use
+       `set-keymap-parent' rather than `copy-keymap'.
+
+1998-10-18  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * gnus-art.el (gnus-mime-button-commands): New variable.
+       (gnus-mime-button-map): Initialize it from
+       `gnus-mime-button-commands'.
+       (gnus-mime-button-menu): New function.
+       (gnus-insert-mime-button): Use `gnus-mime-button-map'.
+
+1998-10-11  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * message.el (message-insert-to): Make `nobody' and `poster'
+       synonymous to `never' and `always' in Mail-Copies-To.
+       (message-reply): Ditto.
+       (message-followup): Ditto.
+
+1998-10-19 23:17:41  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mailcap.el (mailcap-mime-data): Save sound.
+
+1998-09-24  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * message.el (message-ignored-supersedes-headers): Include
+       `NNTP-Posting-Date'.
+
+1998-10-19 01:25:27  Jonas Steverud  <d4jonas@dtek.chalmers.se>
+
+       * gnus-art.el (gnus-article-dumbquotes-table): New variable.
+
+1998-10-19 00:50:22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding): Use
+       uudecode.
+
+1998-10-18 18:20:34  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-display-external): Don't switch on save.
+
+1998-10-18 18:14:06  Andy Piper  <andyp@parallax.co.uk>
+
+       * nnmail.el (nnmail-movemail-args): New variable.
+
+1998-10-18 00:17:02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-translate-strings):
+
+1998-10-17 22:51:31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-view-part): Use it.
+       (gnus-mm-display-part): New function.
+       (article-de-quoted-unreadable): Yse mm-default-coding-system.
+
+       * mm-decode.el (mm-handle-displayed-p): New function.
+
+       * gnus-art.el (gnus-mime-copy-part): Create better names.
+       (gnus-mime-button-line-format): Include dots spec.
+
+1998-10-15  Matt Pharr  <mmp@graphics.stanford.edu>
+
+       * gnus-msg.el (gnus-summary-mail-forward): Erase contents of old
+       forward buffer first.
+
+1998-10-17 21:16:46  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-util.el (gnus-set-window-start): New function.
+
+       * message.el (message-send): Don't check changed.
+
+1998-10-12 15:26:41  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-setup-buffer): Set params.
+
+       * mm-decode.el (mm-user-display-methods): Inline
+       "message/delivery-status".
+
+1998-10-11 07:06:38  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-auto-save-directory): Rename.
+       (message-mode): Dof fix.
+
+       * gnus-art.el (gnus-summary-save-in-pipe): Default to "cat".
+       (gnus-summary-save-in-pipe): No, check gnus-last-shell-command.
+
+       * nndoc.el (nndoc-mime-parts-type-p): Be a bit more forgiving.
+
+       * message.el (message-make-date): Avoid locale.
+
+       * gnus-art.el (gnus-article-edit-done): Allow update before doing
+       cache.
+
+       * mm-decode.el (mm-display-inline): Goto point-min.
+
+       * gnus-art.el (gnus-article-prepare-display): Not read-only.
+
+       * mm-decode.el (mm-display-external): Reverse before sorting.
+
+       * gnus-draft.el (gnus-draft-send): Allow mail.
+
+1998-10-10  SL Baur  <steve@altair.xemacs.org>
+
+       * message.el (message-check): Move message-check macro above where
+       it is first used.
+
+       * gnus-art.el (article-hide-pgp): Hide the PGP 5/GNUPG Hash: line.
+
+1998-10-11 06:45:37  Lloyd Zusman  <ljz@asfast.com>
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Fix.
+
+Sun Oct 11 02:28:40 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.34 is released.
+
+1998-10-11 02:15:41  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-inline-media-tests): delivery-status.
+
+       * mm-view.el (mm-inline-text): Provide default.
+
+1998-10-11 01:01:37  Lloyd Zusman  <ljz@asfast.com>
+
+       * mailcap.el (mailcap-possible-viewers): Fix nils.
+
+1998-10-11 00:03:37  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-edit-exit): Don't do updates.
+       (article-update-date-lapsed): Record the buffer.
+       (article-update-date-lapsed): Do all windows that display article
+       buffers.
+
+       * nnml.el (nnml-generate-nov-databases-1): Ditto.
+
+       * gnus-score.el (gnus-score-score-files-1): Ignore dotted files.
+
+       * gnus-art.el (gnus-insert-mime-button): Mark buttons as
+       annoations.
+
+       * gnus-msg.el (gnus-summary-mail-forward): Decode properly.
+
+1998-10-10 22:07:03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-agent.el (gnus-category-add): Change default category to
+       'false.
+
+       * nnvirtual.el (nnvirtual-update-read-and-marked): Don't nix out
+       scores.
+
+       * gnus-draft.el (gnus-draft-send): Check server more.
+
+       * gnus-art.el (gnus-article-view-part): New command and keystroke.
+       (gnus-article-goto-part): New function.
+
+       * mm-view.el (mm-inline-text): Insert richtext properly.
+
+       * gnus-art.el (gnus-insert-mime-button): Store handle in alist.
+
+1998-10-03 15:04:27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * parse-time.el (parse-time-rules): Accept dates far into the past
+       and the future, and parse single-digit numbers as years.
+
+1998-10-02 04:46:46  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-display-external): Chop off directories.
+
+1998-10-01 07:33:35  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * uudecode.el (uu-decode-region-external): Use
+       insert-file-contents-literally.
+
+       * gnus-cache.el (gnus-cache-generate-active): Translate _ to :.
+
+1998-10-01 07:02:11  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * uudecode.el: New file.
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding): Do
+       x-uuencode.
+
+1998-10-01 05:19:35  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-mime-display-alternative): Set faces.
+
+       * message.el (message-fetch-field): Unfold properly.
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding): Replace CRLF
+       in text/plain.
+
+1998-09-30 05:47:49  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-first-unread-subject): New command.
+       (gnus-auto-select-first): Removed.
+       (gnus-auto-select-first): Extended.
+       (gnus-summary-read-group-1): Use new value.
+
+1998-09-29 13:21:06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-fix-before-sending): Space.
+
+       * nnmail.el (nnmail-find-file): Don't erase.
+
+Wed Sep 30 23:49:03 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-fetch-headers): Do not decode headers.
+
+Wed Sep 30 23:46:29 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-soup.el (gnus-soup-add-article): Do not decode headers.
+
+Wed Sep 30 23:44:08 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-soup.el (gnus-soup-pack-packet): Pack only if necesary.
+
+Sat Sep 26 03:04:18 1998  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-with-unibyte-buffer): Make it work in XEmacs
+       20.4.
+
+1998-09-29 11:35:09  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-mime-view-all-parts): New command and
+       keystroke.
+
+       * mm-decode.el (mm-display-external): Translate slashes.
+
+       * nnmail.el (nnmail-find-file): Restrict auto-mode-alist.
+
+       * nndraft.el (nndraft-retrieve-headers): Don't copy so much.
+
+       * mm-decode.el (mm-quote-arg): Quote spaces.
+       (mm-display-external): Quote args.
+
+1998-09-24 22:27:55  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-inlinable-part-p): New function.
+
+1998-09-25 22:28:01  Simon Josefsson  <jas@pdc.kth.se>
+
+       * mm-util.el (mm-disable-multibyte): New function.
+
+Thu Sep 24 20:28:31 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.33 is released.
+
+1998-09-24 18:47:31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-insert-mime-button): Get buffer size.
+
+       * mm-decode.el (mm-display-external): Don't switch for externals.
+       (mm-dissect-multipart): Don't include end-sep.
+
+       * mm-util.el (mm-get-coding-system-list): New function.
+       (mm-coding-system-list): New variable.
+
+Thu Sep 24 02:08:10 1998  ZHU Shenghuo  <zsh@cs.rochester.edu>
+
+       * gnus-cus.el (gnus-group-parameters): Add charset as a parameter
+
+Thu Sep 24 02:05:48 1998  ZHU Shenghuo  <zsh@cs.rochester.edu>
+
+       * gnus-cus.el (gnus-group-customize): Use variable as cons not as
+       group
+
+Thu Sep 24 01:41:03 1998  ZHU Shenghuo  <zsh@cs.rochester.edu>
+
+       * base64.el (base64-run-command-on-region): External base64
+       decoder do not use coding system
+
+Thu Sep 24 01:39:44 1998  ZHU Shenghuo  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-interactively-view-part): Typo.
+
+Thu Sep 24 01:37:30 1998  ZHU Shenghuo  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-dissect-multipart): Display last part when the
+       article has no close-delimiter
+
+Thu Sep 24 01:28:54 1998  ZHU Shenghuo  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-dissect-buffer): Display parts which have no
+       content-type.
+
+Thu Sep 24 01:23:57 1998  ZHU Shenghuo  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-display-mime): Typo.
+
+Thu Sep 24 02:29:57 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.32 is released.
+
+1998-09-24 00:27:11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-kill.el (gnus-batch-score): Protect against errors.
+
+       * gnus-art.el: Protect against broken headers.
+
+       * mm-decode.el (mm-display-external): Respect needsterm.
+       (mm-display-external): Create buffer for external commands.
+
+1998-09-23 22:04:05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mailcap.el (mailcap-mime-info): Return the proper viewer.
+
+       * mm-decode.el (mm-display-external): Use file name.
+
+1998-09-22  Markus Rost  <markus.rost@mathematik.uni-regensburg.de>
+
+       * gnus-util.el (gnus-output-to-rmail): adjust to
+       `rmail-output-to-rmail-file'.
+
+1998-09-23 20:07:00  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-util.el (gnus-output-to-rmail): Reinstated function.
+
+       * gnus-sum.el (gnus-select-newsgroup): Set global variables before
+       headers.
+
+       * gnus-art.el (article-decode-charset): Fold case.
+
+1998-09-17 15:49:10  Simon Josefsson  <jas@pdc.kth.se>
+
+       * mailcap.el (mailcap-save-binary-file): Goto point-min.
+
+1998-09-23 19:48:52  Aaron M. Ucko  <amu@mit.edu>
+
+       * nnmail.el (nnmail-check-duplication): Enter into duplicate list
+       after being stored.
+
+Tue Sep 15 16:15:16 1998  Kurt Swanson  <ksw@dna.lth.se>
+
+       * gnus-salt.el (gnus-pick-setup-message): Return from whence ye
+       come.
+
+1998-09-23 19:42:03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-xmas.el (wid-edit): Required.
+
+       * gnus-ems.el (gnus-widget-button-keymap): New variable.
+
+Sun Sep 20 00:27:55 1998  ZHU Shenghuo  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-inline-part): remove part if necessary.
+
+1998-09-23 19:30:52  Matt Armstrong  <matta@geoworks.com>
+
+       * gnus-art.el (article-decode-charset): Narrow to the correct
+       region.
+
+       * mm-bodies.el: Fix autoload.
+
+1998-09-22 18:35:12  Lee Willis  <lee@gbdirect.co.uk>
+
+       * gnus-art.el (gnus-mime-button-line-format): Doc fix.
+
+1998-09-22 14:53:35  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * rfc2047.el (rfc2047-decode): Use rfc2047-default-charset.
+
+1998-09-19 13:58:35  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-insert-mime-button): Specify keymap.
+       (gnus-article-add-button): Ditto.
+
+       * gnus-sum.el (gnus-summary-insert-pseudos): Use mm.
+
+       * gnus-art.el (gnus-article-prepare-display): Make article mode.
+       (gnus-article-prepare-display): Bind url-standalone-mode.
+
+       * mm-decode.el (mm-remove-part): Also delete directory.
+       (mm-display-external): Create a private sub-dir.
+
+       * mailcap.el (mailcap-binary-suffixes): New variable.
+       (mailcap-command-p): Use it.
+
+1998-09-16 10:38:21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnmbox.el (nnmbox-request-group): Change server.
+       (nnmbox-possibly-change-newsgroup): Enable multibyte.
+
+       * message.el (message-encode-message-body): Don't stomp MIME
+       headers.
+
+       * gnus-sum.el (gnus-summary-edit-article-done): Don't encode
+       unless useful.
+       (gnus-summary-exit): Check for a live article buffer.
+       (gnus-summary-exit-no-update): Ditto.
+
+       * gnus-int.el (gnus-request-replace-article): Accept no-encode
+       param.
+
+       * gnus-sum.el (gnus-article-decoded-p): New variable.
+
+       * mm-decode.el (mm-display-external): Use no-conv.
+
+       * rfc2047.el (rfc2047-q-encode-region): Bound properly.
+       (rfc2047-charset-encoding-alist): Use B encoding for koi8-r.
+
+       * gnus-art.el (gnus-article-mode-map): Bind button2 to
+       mouse-click.
+
+1998-09-15 14:38:02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-agent.el (gnus-agent-expire): Protect against nil infos.
+
+Mon Sep 14 18:55:38 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.31 is released.
+
+1998-09-14 15:12:59  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-exit): Destroy MIME.
+
+       * mm-decode.el (mm-display-part): Accept no-default.
+
+       * gnus-art.el (gnus-insert-mime-button): buffer-size doesn't take
+       a parameter.
+
+       * gnus-sum.el (gnus-summary-insert-line): Don't exclude faces.
+       (gnus-summary-prepare-threads): Ditto.
+
+       * gnus.el (gnus-article-mode-map): Make sparse keymap.
+
+       * gnus-art.el (gnus-mime-button-line-format-alist): Allow a %d spec.
+       (gnus-mime-button-line-format): Doc fix.
+       (gnus-insert-mime-button): Use it.
+       (gnus-article-add-button): Use widget-convert-button.
+
+       * gnus.el ((featurep 'gnus-xmas)): Defalias gnus-decode-rfc1522 to
+       ignore.
+
+       * mm-decode.el (mm-alternative-precedence): Ditto.
+
+1998-09-14 15:12:49  Conrad Sauerwald  <conrad@stack.nl>
+
+       * mm-decode.el (mm-user-automatic-display): Use enriched.
+
+1998-09-14 15:09:12  Paul Fisher  <rao@gnu.org>
+
+       * mm-decode.el (mm-dissect-multipart): Have the part start on the
+       right place.
+
+1998-09-14 14:33:34  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-inews-add-send-actions): Mark silently.
+
+       * gnus-art.el (article-update-date-lapsed): Only update header if
+       buffer is dispalyed in frame.
+       (gnus-article-prepare-display): New function.
+       (gnus-article-prepare): Use it.
+
+1998-09-14 08:16:43  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-mime-inline-part): New command and keystroke.
+
+       * mm-view.el (mm-insert-inline): New function.
+
+       * mm-decode.el (mm-pipe-part): Bugged.
+
+       * gnus-agent.el (gnus-agent-send-mail): Don't encode.
+
+       * mm-bodies.el (mm-encode-body): Move over the body.
+
+       * nnmbox.el (nnmbox-read-mbox): Enable multibyte.
+
+       * rfc2047.el (rfc2047-q-encode-region): Would bug out.
+
+1998-09-13  Francois Pinard  <pinard@iro.umontreal.ca>
+
+       * nndoc.el: Make nndoc-dissection-alist simpler for MIME, adjust all
+       related functions.  Handle message/rfc822 parts.  Display subject on
+       multipart summary lines.  Display name on sub-parts when available.
+
+1998-09-14 07:36:38  Hallvard B. Furuseth  <h.b.furuseth@usit.uio.no>
+
+       * mailcap.el (mailcap-command-p): New version.
+
+1998-09-13  Mike McEwan  <mike@lotusland.demon.co.uk>
+
+       * gnus-agent.el (gnus-agent-expire): Stop expiry barfing on killed
+       groups.
+
+1998-09-13 18:34:06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-make-date): Remove weekday name.
+
+       * mm-decode.el (mm-dissect-buffer): Protect against broken
+       headers.
+
+       * mailcap.el (mailcap-command-in-path-p): New function.
+       (mailcap-command-p): Renamed.
+
+1998-09-13 17:58:47  Hallvard B. Furuseth  <h.b.furuseth@usit.uio.no>
+
+       * rfc2047.el (eval): Autoload.
+
+1998-09-13 12:22:40  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-decode-encoded-word-functions): New variable.
+       (gnus-multi-decode-encoded-word-string): New function.
+       (gnus-encoded-word-method-alist): New variable.
+       (gnus-decode-encoded-word-functions): Removed.
+
+1998-09-13  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-int.el (gnus-request-replace-article): Replace
+       message-narrow-to-headers with message-narrow-to-head.
+
+1998-09-13 12:05:41  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * drums.el (drums-quote-string): Reversed match.
+
+       * message.el (message-make-date): Use weekday name.
+
+Sun Sep 11 10:27:15 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.30 is released.
+
+1998-09-13 08:00:41  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-decode-encoded-words): Use it.
+       (gnus-decode-header-function): New variable.
+
+       * gnus-sum.el (gnus-nov-parse-line): Use it.
+       (gnus-decode-encoded-word-function): New variable.
+
+       * gnus-msg.el (gnus-copy-article-buffer): Decode the right
+       buffer.
+
+       * gnus-art.el (gnus-insert-mime-button): Use widget.
+       (gnus-widget-press-button): New function.
+       (gnus-article-prev-button): Removed.
+       (gnus-article-next-button): Ditto.
+       (gnus-article-add-button): Ditto.
+
+       * gnus.el (gnus-article-mode-map): Inherit from widget.
+       (gnus-article-mode-map): No, don't.
+
+       * mm-decode.el (mm-dissect-buffer): Store Content-ID things.
+       (mm-content-id-alist): New variable.
+       (mm-get-content-id): New function.
+
+       * gnus-art.el (gnus-request-article-this-buffer): Only decode
+       articles if we are fetching to the article buffer.
+
+1998-09-13 07:58:59  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-move-article): Don't decode accepting
+       articles.
+
+1998-09-13 07:23:28  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-util.el (mm-mime-charset): Try to use safe-charsets.
+       (mm-default-mime-charset): New variable.
+
+       * rfc2047.el (rfc2047-dissect-region): Dissect using tspecials.
+
+       * drums.el (drums-quote-string): Reversed test.
+
+1998-09-12 14:29:21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-util.el (mm-insert-rfc822-headers): Possibly not quote
+       string.
+
+       * drums.el (drums-quote-string): New function.
+
+       * rfc2047.el (rfc2047-encode-message-header): Goto point-min.
+       (rfc2047-b-encode-region): Chop lines.
+       (rfc2047-q-encode-region): Ditto.
+
+Sat Sep 12 13:27:15 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.29 is released.
+
+1998-09-12 12:46:30  Istvan Marko  <imarko@pacificnet.net>
+
+       * mm-decode.el (mm-save-part): Message right.
+
+1998-09-12 11:30:01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * drums.el (drums-parse-address): Returned a list instead of a
+       string.
+       (drums-remove-whitespace): Skip comments.
+       (drums-parse-addresses): Didn't work.
+
+Sat Sep 12 09:17:30 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.28 is released.
+
+1998-09-12 04:57:25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-mime-button-map): Use the article keymap as a
+       starting point.
+       (article-decode-encoded-words): Rename.
+
+       * message.el (message-narrow-to-headers-or-head): New function.
+
+       * gnus-int.el (gnus-request-accept-article): Narrow to the right
+       region.
+
+       * message.el (message-send-news): Encode body after checking
+       syntax.
+
+       * gnus-art.el (gnus-mime-button-line-format): Allow descriptions.
+
+       * mm-decode.el (mm-save-part): Use Content-Disposition filename.
+
+       * gnus-art.el (gnus-display-mime): Respect disposition.
+
+       * mm-decode.el (mm-preferred-alternative): Respect disposition.
+
+       * gnus-art.el (article-strip-multiple-blank-lines): Don't delete
+       text with annotations.
+
+       * message.el (message-make-date): Fix sign for negative time
+       zones.
+
+       * mm-view.el (mm-inline-image): Insert a space at the end of the
+       image.
+
+       * mail-parse.el: New file.
+
+       * rfc2231.el: New file.
+
+       * drums.el (drums-content-type-get): Removed.
+       (drums-parse-content-type): Ditto.
+
+       * mailcap.el (mailcap-mime-data): Use symbols instead of strings.
+
+Fri Sep 11 18:23:34 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.27 is released.
+
+1998-09-11 12:42:07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-alternative-precedence): New variable.
+       (mm-preferred-alternative): New function.
+
+       * gnus-art.el (gnus-mime-copy-part): New command.
+
+       * mm-decode.el (mm-get-part): New function.
+
+       * mm-view.el: New file.
+
+       * mm-decode.el (mm-dissect-buffer): Downcase cte.
+       (mm-display-part): Default to mailcap-save-binary-file.
+
+Fri Sep 11 12:32:50 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.26 is released.
+
+1998-09-11 08:25:33  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el (mm-interactively-view-part): New function.
+
+       * gnus-art.el (gnus-mime-view-part): New command.
+
+       * mm-decode.el (mm-last-shell-command): New variable.
+
+       * mailcap.el (mailcap-mime-info): Allow returning all matches.
+
+       * mm-decode.el (mm-save-part): New function.
+
+       * gnus-art.el (article-decode-charset): Protect against buggy
+       content-types.
+       (gnus-mime-pipe-part): New command.
+       (gnus-mime-save-part): New command.
+       (gnus-mime-button-map): New keymap.
+       (gnus-mime-button-line-format): New variable.
+       (gnus-insert-mime-button): New function.
+       (gnus-display-mime): Use it.
+
+       * gnus-util.el (gnus-dd-mmm): Removed length spec.
+
+       * mm-decode.el (mm-inline-text): Decode charsets.
+
+       * gnus-art.el (gnus-article-save): Comment fix.
+
+       * gnus-int.el (gnus-start-news-server): When in batch, don't
+       prompt.
+
+       * gnus-cache.el (gnus-cache-possibly-enter-article): Don't
+       decode.
+
+       * mm-decode.el (mm-inline-media-tests): Add audio.
+       (mm-inline-audio): New function.
+
+1998-09-11 08:19:22  Katsumi Yamaoka  <yamaoka@ga.sony.co.jp>
+
+       * gnus-art.el (article-make-date-line): Didn't work.
+
+       * parse-time.el (parse-time-string): One too many nils.
+
+Fri Sep 11 08:09:40 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.25 is released.
+
+1998-09-11 07:38:14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-remove-trailing-blank-lines): Don't remove
+       annotations.
+
+       * gnus.el ((featurep 'gnus-xmas)): New
+       'gnus-annotation-in-region-p alias.
+
+1998-09-10 06:20:52  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-util.el (mm-with-unibyte-buffer): New function.
+
+       * gnus-uu.el (gnus-quote-arg-for-sh-or-csh): Renamed.
+
+       * mm-decode.el (mm-inline-media-tests): New variable.
+
+       * gnus-sum.el (gnus-summary-exit): Destroy handles.
+
+       * gnus-art.el (gnus-article-mime-handles): New variable.
+
+       * drums.el (drums-narrow-to-header): New function.
+
+       * gnus-art.el (article-decode-charset): Use it.
+
+       * drums.el (drums-content-type-get): New function.
+
+       * mm-util.el (mm-content-type-charset): Removed.
+
+       * drums.el (drums-syntax-table): @ is word.
+       (drums-parse-content-type): New function.
+
+       * parse-time.el (parse-time-rules): Parse "Wed, 29 Apr 98 0:26:01
+       EDT" times.
+
+       * gnus-util.el (gnus-date-get-time): Use safe date.
+
+       * gnus-sum.el (gnus-show-mime): Removed.
+       (gnus-summary-toggle-mime): Removed.
+
+       * gnus-art.el (gnus-strict-mime): Removed.
+       (gnus-article-prepare): Don't do MIME.
+       (gnus-decode-encoded-word-method): Removed.
+       (gnus-show-mime-method): Removed.
+
+Thu Sep 10 04:03:29 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.24 is released.
+
+1998-09-10 01:58:24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-show-article): Don't decode chars if
+       PREFIX.
+
+       * parse-time.el (parse-time-rules): Accept times that look like
+       "h:mm".
+
+       * message.el (message-make-date): Use zone properly.
+
+       * gnus.el: Autoload gnus-batch.
+
+       * gnus-art.el (article-de-quoted-unreadable): Do not do
+       gnus-article-decode-rfc1522.
+
+       * gnus-msg.el (gnus-inews-do-gcc): Use it.
+
+       * gnus-int.el (gnus-request-accept-article): Accept a no-encode
+       param.
+
+       * message.el (message-encode-message-body): Check for us-ascii.
+
+       * gnus-msg.el (gnus-extended-version): Move Gnus version comments
+       to the left.
+
+1998-09-09 13:18:13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-decode-charset): Rename.
+
+Wed Sep  9 12:25:48 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.23 is released.
+
+1998-09-09 12:14:47  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-util.el (gnus-parent-id): Ditto.
+       (gnus-put-text-property-excluding-newlines): Ditto.
+
+       * gnus-sum.el (gnus-dependencies-add-header): Make into subst.
+
+1998-09-08  Karl Kleinpaste  <karl@jprc.com>
+
+       * message.el (message-generate-headers): Generate User-Agent
+       instead of X-Mailer & X-Newsreader.
+
+       * gnus-msg.el (gnus-extended-version): Reformat for USEFOR
+       User-Agent header format.
+
+Tue Sep  8 22:38:27 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.22 is released.
+
+1998-09-08 22:36:54  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-util.el (mm-multibyte-p): Typo.
+
+Tue Sep  8 22:25:53 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.21 is released.
+
+1998-09-08  Hrvoje Niksic  <hniksic@srce.hr>
+
+       * gnus-art.el (article-treat-dumbquotes): Handle \224 correctly.
+
+1998-09-08 22:18:03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-util.el (mm-multibyte-p): New function.
+
+Tue Sep  8 21:43:03 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.20 is released.
+
+1998-09-08 11:40:45  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * rfc2047.el (rfc2047-decode-region): Only decode when in
+       multibyte.
+
+       * nnheader.el (nnheader-pathname-coding-system): Changed to binary.
+
+       * gnus-int.el (gnus-request-replace-article): Encode.
+       (gnus-request-accept-article): Encode.
+
+       * gnus-art.el (gnus-request-article-this-buffer): Decode charsets
+       here.
+
+       * gnus.el (gnus-article-display-hook): Take the charset functions
+       out.
+
+       * time-date.el (safe-date-to-time): New function.
+
+       * gnus-util.el (gnus-dd-mmm): Protect against bogus dates.
+
+Tue Sep  8 07:09:28 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.19 is released.
+
+1998-09-08 04:51:39  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * base64.el (base64-encode-region): Accept no-line-break.
+
+       * mm-util.el (mm-mime-charset): New function.
+
+       * gnus-draft.el (gnus-draft-edit-message): Delete article.
+
+Tue Sep  8 04:29:23 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.18 is released.
+
+1998-09-08 02:21:36  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-send-and-exit): Return t on success.
+       (message-make-date): Make a proper time zone.
+
+       * gnus-draft.el (gnus-draft-send): Only remove article if the
+       sending is successful.
+
+       * drums.el (drums-get-comment): Return the last comment.
+       (drums-parse-address): Parse old-style From headers.
+
+1998-09-07  SL Baur  <steve@altair.xemacs.org>
+
+       * gnus-sum.el (gnus-data-compute-positions): Move below
+       `gnus-save-hidden-threads' so the former is correctly detected as
+       a macro.
+
+1998-09-06  Dave Love  <fx@gnu.org>
+
+       * nnweb.el (require): Wrap requirement of w3 and url in ignore-errors
+       too, eval'd when compile.  Require w3 stuff at load time for nicer
+       failure if it's not available.
+
+1998-09-08 00:38:39  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * time-date.el (time-to-seconds): Renamed.
+
+       * parse-time.el (parse-time-string): Downcase before handling.
+       (parse-time-rules): Times without seconds have 0 seconds.
+
+       * rfc2047.el (rfc2047-encode-region): New version.
+       (rfc2047-dissect-region): New function.
+
+1998-09-07 01:08:35  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-make-date): Use symbolic zone.
+
+1998-09-06 23:23:06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * time-date.el (parse-time): Always use parse-time.
+
+       * parse-time.el (parse-time-syntax): Use vectors.
+
+Sun Sep  6 21:19:26 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.17 is released.
+
+1998-09-06 05:45:17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * time-date.el: Renamed from "date".
+
+       * gnus.el: Removed all timezone dependencies.
+
+       * score-mode.el: Removed.
+       (gnus-score-edit-insert-date): Use date.
+
+       * date.el (float-to-time): New function.
+
+       * nnspool.el (nnspool-seconds-since-epoch): Removed.
+
+       * date.el (time-to-float): New function.
+
+       * message.el (message-make-date): Use format-time-string.
+       (message-make-expires): Use make-date.
+
+       * gnus-xmas.el (gnus-xmas-seconds-since-epoch): Removed.
+
+       * gnus-util.el (gnus-dd-mmm): Use date.
+       (gnus-sortable-date): Ditto.
+
+       * message.el (message-make-date): Take an optional time.
+
+       * gnus.el: Applied patches from 5.6.43.
+
+       * date.el (if): Use parse-time.
+
+       * gnus-score.el (gnus-summary-score-entry): Make into a command
+       again.
+
+       * gnus-group.el (gnus-group-get-new-news-this-group): Only call if
+       gnus-agent.
+
+       * gnus.el (gnus-agent-meta-information-header): Moved here.
+
+1998-09-05  Mike McEwan  <mike@lotusland.demon.co.uk>
+
+       * gnus-agent.el (gnus-agent-scoreable-headers): New variable.
+       (gnus-agent-fetch-group-1): Score article headers using normal
+       group score files if the download score rule of a category/group
+       is `file'.
+       (gnus-agent-fetch-group-1): Don't parse the entire .overview when
+       deciding what articles to download.
+       (gnus-agent-fetch-group-1): Don't push headers through scoring and
+       predicate processing if predicate is `true' or `false'.
+
+1998-09-06 01:56:02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-score.el (gnus-score-load-score-alist): Bind coding system.
+
+       * gnus-art.el (gnus-article-setup-buffer): Enable multibyte.
+
+       * score-mode.el (score-mode-coding-system): New variable.
+       (gnus-score-edit-exit): Use it.
+
+1998-09-04  Jason R Mastaler  <jason@4b.org>
+
+       * drums.el: Corrected typo.
+
+1998-09-05 23:24:43  Hallvard B. Furuseth  <h.b.furuseth@usit.uio.no>
+
+       * mm-bodies.el (mm-body-encoding): Faster version.
+
+1998-09-05 22:23:03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-decode-charset): Only decode text
+       things.
+
+       * message.el (message-output): Use rmail.
+
+       * rfc2047.el (rfc2047-encoded-word-regexp): Allow spaces in the
+       word part.
+
+       * mm-util.el (mm-charset-to-coding-system): Use
+       rfc2047-default-charset.
+       (mm-known-charsets): New variable.
+
+       * message.el (message-caesar-region): Bugged out.
+
+1998-09-06  Mike McEwan  <mike@lotusland.demon.co.uk>
+
+       * gnus-agent.el (gnus-agent-fetch-group-1): Allow lists when
+       specifying `agent-predicate' in a group's parameters.
+
+Sat Sep  5 21:55:01 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.16 is released.
+
+1998-09-05 17:30:11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnmail.el (nnmail-expired-article-p): Use predicate.
+
+       * date.el (time-less-p): Renamed.
+
+       * gnus-art.el (gnus-article-decode-charset): Really fetch headers
+       from the headers.
+
+       * rfc2047.el (rfc2047-decode-region): Use the mm decoding
+       functions.
+
+       * gnus-group.el (gnus-group-sort-selected-flat): Didn't work at
+       all.
+       (gnus-group-sort-selected-groups-by-alphabet): Changed interface
+       to all functions.
+
+Sat Sep  5 01:45:52 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.15 is released.
+
+1998-09-05 00:21:22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * date.el: New file.
+
+       * gnus-util.el (gnus-encode-date): Removed.
+       (gnus-time-less): Ditto.
+
+       * nnmail.el (nnmail-date-to-time): Removed.
+       (nnmail-time-less): Ditto.
+       (nnmail-days-to-time): Ditto.
+       (nnmail-time-since): Ditto.
+
+       * drums.el: New file.
+
+1998-09-04 00:25:52  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-encode-message-body): Encode headers with
+       body encoding.
+
+       * rfc2047.el (rfc2047-default-charset): Renamed.
+       (rfc2047-encodable-p): Use it.
+
+       * base64.el (mm-util): Required.
+
+1998-09-03 16:28:30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-post-method): Peel off real info from opened
+       servers.
+
+       * gnus-util.el (gnus-output-to-rmail): Removed.
+
+       * gnus-art.el (gnus-summary-save-in-rmail): Use
+       gnus-output-to-rmailrmail-output-to-rmail-file.
+
+       * rfc2047.el (rfc2047-decode-region): Fold case.
+       (rfc2047-decode): Use decode-string.
+
+       * mm-util.el: Provide mm-char-int.
+
+Thu Sep  3 15:23:22 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.14 is released.
+
+1998-09-03 15:08:30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-bodies.el (mm-body-encoding): Go through the buffer to make
+       sure we have 7bit.
+
+1998-09-02 14:38:18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-post-method): Use opened servers, and remove
+       ducplicates.
+       (gnus-inews-insert-mime-headers): Removed.
+
+       * message.el (message-caesar-region): Protect against MULE chars.
+
+1998-09-02 00:36:23  Hallvard B. Furuseth  <h.b.furuseth@usit.uio.no>
+
+       * mm-util.el (if): fset the right function.
+
+1998-09-02 00:31:53  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-decode-charset): Use real
+       read-coding-system.
+
+1998-09-01 17:58:40  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-bodies.el (mm-decode-body): Protect against malformed
+       base64.
+       (mm-decode-body): Check that buffer-file-coding-system is
+       non-nil.
+
+Tue Sep  1 10:29:33 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.13 is released.
+
+1998-09-01 09:14:33  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-util.el (gnus-strip-whitespace): Already defined.
+       Removed.
+
+       * gnus-art.el (gnus-article-decode-charset): Strip whitespace.
+
+       * gnus-util.el (gnus-strip-whitespace): New function.
+
+       * mm-util.el (mm-content-type-charset): Downcase.
+
+1998-08-31 23:04:29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-decode-charset): Accept a prefix.
+       (gnus-article-decode-charset): Don't fetch all headers.
+
+       * mm-util.el (mm-read-coding-system): New function.
+
+       * mm-bodies.el (mm-decode-body): Check the right charset.
+
+       * gnus-sum.el (gnus-summary-mode-line-format): Ditto.
+
+       * gnus-art.el (gnus-article-mode-line-format): Use short group
+       format.
+
+Mon Aug 31 23:03:13 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.12 is released.
+
+1998-08-31 22:39:36  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-bodies.el (mm-decode-body): Don't do charset unless MULE.
+
+       * gnus-art.el (gnus-article-decode-charset): Supply cte.
+       (gnus-article-decode-charset): Always run.
+
+       * mm-bodies.el (mm-decode-body): Decode cte.
+
+Mon Aug 31 22:14:50 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.11 is released.
+
+1998-08-31 14:27:25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-encode-message-body): Ditto.
+
+       * gnus-art.el (gnus-article-decode-mime-words): New command and
+       keystroke.
+       (gnus-article-decode-charset): Ditto.
+       (gnus-article-decode-charset): Only work under MULE.
+
+       * mm-util.el (mm-content-type-charset): New function.
+
+       * nnmail.el (nnmail-delete-incoming): Changed to nil.
+
+       * message.el (message-send-mail): Insert MIME headers.
+       (message-check-news-body-syntax): Don't warn for escape sequences.
+       (message-check-news-body-syntax): Insert MIME headers.
+
+       * mm-bodies.el (mm-body-encoding): New function.
+
+       * message.el (message-encode-message-body): New function.
+
+       * mm-bodies.el: New file.
+
+       * mm-util.el (mm-narrow-to-head): New function.
+
+       * rfc2047.el (rfc2047-encode): Use it.
+
+       * mm-util.el: Provide mm-encode-coding-region.
+
+       * gnus-sum.el (gnus-summary-mode): Enable multibyte.
+
+       * gnus-util.el (gnus-set-work-buffer): Enable multibyte.
+
+       * mm-util.el (mm-enable-multibyte): New function.
+
+       * message.el (message-set-work-buffer): Set multibyte.
+
+       * gnus.el (gnus-continuum-version): Be valid forever and ever.
+
+       * gnus-util.el (gnus-point-at-eol): Removed.
+       (gnus-point-at-bol): Ditto.
+
+       * base64.el (base64-decode-region): Commented out messaging.
+
+1998-08-31  Didier Verna  <verna@inf.enst.fr>
+
+       * gnus-msg.el (gnus-group-mail): make it behave like
+       gnus-group-post-news with regards to the prefix (this enables the
+       use of posting styles).
+
+1998-08-31 12:53:32  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-article-display-hook): Added
+       gnus-article-decode-rfc1522 to hook.
+
+Mon Aug 31 12:43:46 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.10 is released.
+
+1998-08-31 11:45:13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnfolder.el (nnfolder-delete-mail): Narrow to mail and allow
+       hook to be run.
+
+1998-08-30 17:59:07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * rfc2047.el (rfc2047-encodable-p): Use find-charset-region.
+
+       * mm-util.el (mm-charsets-in-region): Removed.
+
+       * rfc2047.el: Renamed file.
+
+       * gnus-msg.el (gnus-copy-article-buffer): Multibyte.
+
+       * message.el (message-mode): Set multibyte.
+
+       * mm-util.el (mm-charsets-in-region): Copied here.
+
+       * gnus-util.el: Removed gnus-truncate-string.
+
+       * gnus-art.el (gnus-article-decode-mime-words): Use 1522.
+
+       * rfc1522.el (rfc1522-unencoded-charsets): New variable.
+       (rfc1522-encodable-p): New function.
+       (rfc1522-encode-message-header): Use it.
+
+Sun Aug 30 17:46:01 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.9 is released.
+
+1998-08-30 16:13:08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-util.el: Shadow encode-coding-string.
+
+       * base64.el (base64-encode-region): Don't add newline.
+
+       * rfc1522.el (rfc1522-narrow-to-field): Copied here.
+
+       * mm-util.el: New file.
+
+       * mm-decode.el: Somewhat depleted.
+       * mm-encode.el: Ditto.
+
+       * rfc1522.el: New file.
+
+       * mm-util.el (mm-replace-chars-in-string): Copied here.
+
+       * mm-encode.el (mm-q-encode-region): New function.
+
+       * qp.el (quoted-printable-encode-region): Take an optional CLASS
+       param.
+
+       * mm-encode.el (mm-encode-word-region): Downcase.
+
+Sun Aug 30 15:28:01 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.8 is released.
+
+1998-08-30 12:23:03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-send-mail): Encode headers.
+
+       * qp.el (quoted-printable-encode-region): Encode 8-bit words.
+       (quoted-printable-encode-region): Upcase.
+
+       * message.el (message-default-charset): New variable.
+
+       * qp.el (quoted-printable-encode-region): Optional param FOLD.
+
+       * message.el (message-narrow-to-field): Changed name.
+
+       * mm-encode.el: New file.
+
+       * message.el (message-narrow-to-header): New function.
+
+       * gnus-art.el (gnus-article-decode-mime-words): Place point in the
+       right buffer.
+
+Sun Aug 30 12:15:54 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.7 is released.
+
+1998-08-30 01:26:12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el: Remove autoload for
+       gnus-article-mime-decode-quoted-printable.
+
+       * mm-decode.el (mm-charset-to-coding-system): Allow iso-8859-1 to
+       be decoded in non-MULE Emacsen.
+
+       * gnus-xmas.el (gnus-xmas-logo-color-alist): More brown.
+
+1998-08-29  SL Baur  <steve@altair.xemacs.org>
+
+       * gnus-xmas.el (gnus-xmas-logo-color-alist): Try shades of brown.
+
+1998-08-30 01:04:57  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-decode.el: Check for coding-system-list.
+
+Sun Aug 30 00:59:15 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.6 is released.
+
+1998-08-30 00:36:28  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnheader.el (fboundp): Protect code-coding-string.
+
+       * gnus-art.el (gnus-article-mode): Check that set-buffer-multibyte
+       is available.
+
+Sat Aug 29 23:24:31 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Pterodactyl Gnus v0.5 is released.
+
+1998-08-29 22:38:35  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-mode): Make article buffer multibyte.
+       (gnus-hack-decode-rfc1522): Removed.
+
+       * mm-decode.el (mm-charset-coding-system-alist): Check better.
+
+Sat Aug 29 22:20:39 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Gnus v0.4 is released.
+
+1998-08-29 20:53:29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-decode-mime-words): New command and
+       keystroke.
+
+       * qp.el (quoted-printable-decode-region): Don't use hexl.
+
+       * gnus-xmas.el (gnus-xmas-logo-color-style): Changed to dino.
+
+       * gnus-sum.el (gnus-parse-headers-hook): Default to nil.
+       (gnus-structured-field-decoder): Removed.
+       (gnus-unstructured-field-decoder): Ditto.
+
+       * mm-decode.el: New file.
+
+       * qp.el: New file.
+
+       * gnus-art.el (article-mime-decode-quoted-printable): Removed.
+
+       * gnus-ems.el (fboundp): Removed gnus-split-string.
+
+       * gnus.el (gnus-splash-face): Doc fix.
+
+       * gnus-ems.el (fboundp): Don't bind mail-file-babyl-p.
+
+       * gnus-art.el (article-mime-decode-quoted-printable): Don't use
+       hexl.
+
+       * nnheader.el (nnheader-temp-write): Removed.
+
+Sat Aug 29 20:34:17 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Gnus v0.3 is released.
+
+Sat Aug 29 19:32:06 1998  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Gnus v0.2 is released.
+
+  Copyright (C) 1998-2016 Free Software Foundation, Inc.
+  Copying and distribution of this file, with or without modification,
+  are permitted provided the copyright notice and this notice are preserved.
+
+;; Local Variables:
+;; coding: utf-8
+;; End:
diff --git a/xemacs-packages/gnus/lisp/ChangeLog.2 b/xemacs-packages/gnus/lisp/ChangeLog.2
new file mode 100644 (file)
index 0000000..a16014e
--- /dev/null
@@ -0,0 +1,18853 @@
+2004-01-04  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Gnus v5.10.6 is released.
+
+2004-01-04  Kai Grossjohann  <kai@emptydomain.de>
+
+       * gnus-sum.el (gnus-summary-print-article): Doc fix.
+
+2004-01-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Bump.
+
+2004-01-04  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Gnus v5.10.5 is released.
+
+2004-01-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-fun.el (gnus-face-from-file): Message 9.
+
+2004-01-03  Romain FRANCOISE  <romain@orebokech.com>
+
+       * gnus-fun.el (gnus-face-from-file): Use gnus-message.
+
+2004-01-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button-mid-or-mail-heuristic): Treat Gmane
+       addresses specially.  Fix returned value and messages.
+
+       * mm-decode.el (mm-enable-external): New variable.
+       (mm-display-part): Use it.
+       (mm-display-external): Fix message in case of nil handle.
+
+       * Update copyright for several files.
+
+       * spam-report.el (spam-report-gmane): Adjust verbosity.
+       Delete trailing whitespace.  Update copyright.
+
+       * spam.el: Fix many (but not all) checkdoc complaints.
+       Delete trailing whitespace.
+
+       * message.el (message-header-synonyms): Defcustom.
+       (message-get-reply-headers): Catch `Original-To'.
+       (message-carefully-insert-headers): Added comment.
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Improved "Washing" menu.
+
+2004-01-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-select-newsgroup): Use cat.
+
+       * gnus-agent.el (gnus-agent-cat-enable-undownloaded-faces): New
+       cat.
+
+       * gnus.el (gnus-user-agent): Moved here.
+
+       * gnus-msg.el (gnus-user-agent): Moved from here.
+
+       * gnus.el (gnus-version-number): Bump.
+
+2004-01-03  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Gnus v5.10.4 is released.
+
+2004-01-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.el (gnus-mode-line-buffer-identification): Show version in
+       help-echo.
+       (gnus-read-group): Allow most group names.  Changed warning.
+
+2004-01-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-dired.el (gnus-dired-mode-map): Change keymaps.
+
+2004-01-02  Arne Jørgensen  <arne@arnested.dk>
+
+       * smime.el (smime-crl-check): Doc fix.
+
+2004-01-02  Edwin Steiner  <edwin.steiner@gmx.net>  (tiny change)
+
+       * gnus-nocem.el (gnus-nocem-enter-article): Use the real group
+       hashtb.
+
+2004-01-02  Michael Albinus  <Michael.Albinus@alcatel.de>
+
+       * nnml.el (nnml-save-mail): Grok compressed articles.
+
+2004-01-02  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-ham-copy-or-move-routine): Use spam-list-articles.
+       (spam-list-articles): Rewritten to only check a mark once per
+       invocation.
+
+2004-01-01  Simon Josefsson  <jas@extundo.com>
+
+       * mml-sec.el (mml-default-encrypt-method)
+       (mml-default-sign-method): Defcustom.
+
+2003-12-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml.el (mml-generate-mime-1): Remove extra ).
+
+       * gnus-group.el (gnus-group-set-current-level): Signal errors on
+       topic lines.
+       (gnus-group-set-current-level): Fix fix.
+
+2003-12-31  Jeremy Maitin-Shepard  <jbms@attbi.com>
+
+       * mml.el (mml-generate-mime-1): Use mml-compute-boundary (tiny
+       change).
+
+2003-12-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-group.el: Removed `(when t ...)' around `gnus-define-keys'.
+       (gnus-group-group-map): Added `gnus-group-read-ephemeral-group'
+       (already in previous commit inadvertently).
+       (gnus-group-make-menu-bar): Added `gnus-group-read-ephemeral-group'.
+       (gnus-group-read-ephemeral-group): Made interactive.
+
+       * gnus-score.el (gnus-score-find-trace): Added comment on sync
+       with `gnus-score-edit-file-at-point'.
+
+       * gnus-logic.el (gnus-score-advanced): Ditto.
+
+       * gnus-score.el (gnus-score-edit-file-at-point): Fix for
+       advanced scoring.
+
+2003-12-30  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-score.el (gnus-score-edit-file-at-point): Use
+       gnus-point-at-*, for portability.
+
+2003-12-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-treat-body-boundary): Fix doc-string and
+       custom type.
+       (gnus-button-mid-or-mail-regexp): Don't be too restrictive.
+       Suggested by Felix Wiemann <Felix.Wiemann@gmx.net>.
+       (gnus-button-alist): Added "M-x ... RET" and "mid:" buttons.
+       Added comments about relevant RFCs.
+
+       * gnus-sum.el (gnus-summary-mode): Untabify doc-string.
+       (gnus-summary-goto-article): Allow `%40'.
+       (gnus-summary-refer-article): Convert `%40' to `@'.
+
+2003-12-30  Arne Jørgensen  <arne@arnested.dk>
+
+       * smime.el (smime-crl-check): New.
+       (smime-verify-region): Use it.
+
+2003-12-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       (gnus-score-find-trace): Use gnus-score-edit-file-at-point.  Added
+       `f' and `t' commands, added quick help.  With some suggestions
+       from Karl Pflästerer <sigurd@12move.de>.
+
+       * gnus-util.el (gnus-emacs-version): Added doc-string.
+
+       * mml.el (mml-minibuffer-read-disposition): New function.
+       (mml-attach-file): Use it.
+       (mml-preview): Added MIME preview to gnus-buffers.
+
+2003-12-30  Karl Pflästerer  <sigurd@12move.de>
+
+       * gnus-score.el (gnus-score-edit-file-at-point): Consider the
+       whole match element.
+
+2003-12-30  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Add ellipses.
+
+2003-12-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-get-unread-articles): Inline gnus-server-get-method.
+       (gnus-get-unread-articles): Cache methods.
+       (gnus-get-unread-articles-in-group): Indent.
+
+       * gnus.el (gnus-version-number): Bump.
+       (gnus-secondary-method-p): Extend servers to methods before comparing.
+       (gnus-secondary-method-p): Revert.
+
+2003-12-30  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Gnus v5.10.3 is released.
+
+2003-12-29  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-agent.el (gnus-agentize): Improve auto-agentizing logic.
+       Suggested by Steinar Bang <sb@dod.no>.
+       (gnus-agent-auto-agentize-methods): Customize.
+
+2003-12-29  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+       * gnus.el (gnus-server-to-method): Fixed bug in 2003-12-22
+       check-in.
+
+2003-12-28  Adrian Lanz  <lanz@fowi.ethz.ch>
+
+       * mail-source.el (mail-source-fetch-imap): Prevent storing of
+       identical entries for imap mail sources, when retrieving mail
+       messages from an imap server within the same Gnus session several
+       times (tiny change).
+
+2003-12-28  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-view.el (mm-text-html-washer-alist): Use
+       mm-inline-wash-with-stdin for w3m-standalone.
+
+       * mm-decode.el (mm-text-html-renderer): Add w3m-standalone.
+
+       * mml1991.el (mml1991-pgg-encrypt): Decode according to CTE before
+       encrypting.
+
+2003-12-28  Ivan Boldyrev  <boldyrev@uiggm.nsc.ru>  (tiny change)
+
+       * mml1991.el (mml1991-pgg-sign): Use unibyte when re-encoding.
+
+2003-12-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el: Add an advice to byte-optimize-form-code-walker to
+       avoid the warning ``...called for effect'' for the pop form when
+       running Emacs 21.3.
+
+2003-12-26  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-bodies.el (mm-body-encoding): Don't use 7bit if the body
+       contains "^From " and mm-use-ultra-safe-encoding is true.
+
+2003-12-25  Jesper Harder  <harder@ifa.au.dk>
+
+       * mml1991.el (mml1991-pgg-sign): Encode and decode according to
+       CTE header.  Don't insert gpg output as unibyte.
+
+2003-12-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Remove display-time-event-handler and open-ssl-stream;
+       add delete-extent for Emacs; rearrange bindings assuming w3 may
+       not be available and XEmacs without the file-coding feature may be
+       used.
+
+2003-12-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (dgnushack-compile): Increase the value for
+       max-specpdl-size when compiling Gnus with Emacs 20.
+
+2003-12-22  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-int.el (gnus-open-server): Fixed the server status such
+       that an agentized server, when opened offline, has a status of
+       offline.  Also fixes bug whereby the agent's backend was called
+       twice to open each server.
+
+       * gnus-start.el (gnus-get-unread-articles-in-group): Autoload
+       gnus-agent-possibly-alter-active rather than inline to resolve
+       compiler warnings.
+
+       * gnus.el (gnus-server-to-method): Added fallback of iterating
+       over gnus-newsrc-alist to resolve names of foreign servers.
+       Should fix recent agent bug.
+
+2003-12-22  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-score.el (gnus-summary-lower-score)
+       (gnus-summary-increase-score): Mention symbolic prefix in the
+       doc-string.  Suggested by Karl Pflästerer <sigurd@12move.de>.
+
+2003-12-21  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-agent.el (gnus-agent-read-agentview): Use
+       car-less-than-car.
+
+2003-12-20  Artem Chuprina  <ran@ran.pp.ru>  (tiny change)
+
+       * message.el (message-yank-buffer): Bind message-reply-buffer to
+       a buffer rather than a string.
+
+2003-12-19  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-msg.el (gnus-summary-followup): Correct documentation.
+
+2003-12-18  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-msg.el (gnus-inews-add-send-actions): `yanked' can be a
+       list of lists.  Reported by Dmitri Paduchikh <paduch@imm.uran.ru>.
+
+2003-12-18  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-url.el (mm-url-insert-file-contents-external)
+       (mm-url-insert-file-contents): Added doc-strings.  Autoload.
+
+2003-12-18  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-cus.el (defvar): Defvar
+       gnus-agent-cat-disable-undownloaded-faces.
+
+2003-12-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-forward-subject-name-subject): Use
+       gnus-extract-address-components instead of
+       mail-header-parse-address because it may be called with non-ascii
+       text.
+
+2003-12-16  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * nnmail.el (nnmail-split-fancy): The widget now supports
+       restrictions.
+
+2003-12-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnheader.el (nnheader-find-etc-directory): Find the newest one.
+
+2003-12-16  Simon Josefsson  <jas@extundo.com>
+
+       * sha1-el.el (autoload): Don't use ignore-errors.
+       (sha1-use-external): Use condition-case.  Suggested by Katsumi
+       Yamaoka <yamaoka@jpl.org>.
+
+2003-12-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnmail.el (nnmail-split-fancy): Make it customizable with Emacs
+       20 as well.
+
+2003-12-15  Simon Josefsson  <jas@extundo.com>
+
+       * sha1-el.el (autoload): Ignore errors for
+       executable-find.  (XEmacs ecrypto does not require sh-script where
+       executable.el is located.)
+       (sha1-use-external): Likewise.
+
+       * sha1-el.el (sha1): Add defgroup.
+       (sha1-maximum-internal-length, sha1-program, sha1-use-external)
+       (sha1-program): Use 'sha1sum' from GNU CoreUtils instead of OpenSSL.
+       (sha1): Autoload.
+
+       * nndraft.el (nndraft-request-move-article): Copy definition of
+       nnmh-request-move-article instead of calling it, because the nnmh
+       version uses nnmh-request-article which isn't the same as the
+       nndraft version.
+
+2003-12-13  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el: Added some gnus-registry autoloads.
+       (spam-split-symbolic-return): Makes spam-split return 'spam
+       instead of the value of spam-split-group when spam is detected.
+       (spam-split-symbolic-return-positive): Makes spam-split return
+       'ham instead of nil when ham is detected.
+       (spam-autodetect-recheck-messages): Tells spam.el whether it
+       should recheck all messages in a group, or only the unseen ones.
+       (spam-split-last-successful-check): spam-split will set this to
+       the last successful check; this was seen as a cleaner approach
+       than returning a cell like '(spam spam-use-bogofilter).
+       (spam-list-of-checks): Documentation appended.
+       (spam-split): Accommodate the spam-split-symbolic-return and
+       spam-split-symbolic-return-positive variables.
+       (spam-find-spam): New function called when the summary is built.
+       (spam-log-registered-p): Checks if a ham or spam registration has
+       already been done for an article.
+       (spam-check-regex-headers, spam-check-blackholes, spam-check-BBDB)
+       (spam-check-ifile, spam-check-stat, spam-check-whitelist)
+       (spam-check-blacklist, spam-check-bogofilter-headers)
+       (spam-check-spamoracle): Respect the spam-split-symbolic-return
+       and spam-split-symbolic-return-positive variables.
+       (spam-initialize): Add spam-find-spam to gnus-summary-prepare-hook.
+       (spam-unload-hook): Remove spam-find-spam from
+       gnus-summary-prepare-hook.
+
+       * gnus.el (spam-autodetect, spam-autodetect-methods): New
+       configuration items for spam autodetection.
+
+2003-12-12  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-draft.el (gnus-draft-mode-map): Bind `e' to
+       `gnus-draft-edit-message'.  We still have `B w' for
+       `gnus-summary-edit-article'.
+
+2003-12-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnheaderxm.el (nnheader-xmas-run-at-time): Use a simple function
+       definition if there is not a bug in start-itimer.
+
+       * pgg.el (pgg-run-at-time): Ditto.
+
+2003-12-11  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-possibly-alter-active): New Function.
+       (gnus-agent-regenerate-group): When necessary, alter the group's
+       active range to include articles newly recognized as being
+       downloaded.
+       (gnus-agent-regenerate): Removed code that updated the agent's
+       active file as the new gnus-agent-possibly-alter-active function
+       obsolesced it.
+
+       * gnus-cus.el (gnus-agent-customize-category): Added missing
+       agent-disable-undownloaded-faces parameter.
+
+       * gnus-start.el (gnus-activate-group): Backed out my 2003-11-29
+       patch as it was too late at adjusting the active range.
+       (gnus-get-unread-articles-in-group): Added call to new
+       gnus-agent-possibly-alter-active to adjust the active range.
+
+2003-12-10  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-get-reply-headers): Narrow to headers.
+
+2003-12-10  Lőrentey Károly  <lorentey@elte.hu>
+
+       * spam.el (spam-disable-spam-split-during-ham-respool): New
+       variable.
+       (spam-ham-copy-or-move-routine): Respect
+       spam-disable-spam-split-during-ham-respool.
+       (spam-split-disabled): New variable.
+       (spam-split): Respect spam-split-disabled.
+
+2003-12-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnheaderxm.el (nnheader-xmas-run-at-time): Make it work
+       correctly for the first argument.
+
+       * pgg.el (pgg-run-at-time): New function.
+       (pgg-add-passphrase-cache): Use it.
+
+2003-12-10  Simon Josefsson  <jas@extundo.com>
+
+       * pgg-parse.el (pgg-decode-packets): Rewrite to handle corrupt
+       input.
+       (pgg-decode-armor-region): Don't parse packet if decoding fail.
+
+2003-12-09  Lőrentey Károly  <lorentey@elte.hu>
+
+       * spam.el (spam-check-bogofilter): Run in the correct buffer.
+
+2003-12-09  Xavier Maillard  <zedek@gnu-rox.org>
+
+       * spam.el (spam-bogofilter-database-directory): Correct
+       customization group.
+
+2003-12-09  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * nnmail.el (nnmail-lazy, nnmail-split-fancy): New widgets.
+       (nnmail-split-fancy): Use it.
+
+2003-12-08  Joel Ray Holveck  <joelh@piquan.org>  (tiny change)
+
+       * gnus-sum.el (gnus-summary-save-parts-1): Consider the "name"
+       parameter of Content-Type.
+
+2003-12-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el: Revert 2003-12-03 change, instead, provide the
+       compiler macro for rmail-select-summary if rmail is not available,
+       and bind rmail-summary-displayed and rmail-maybe-display-summary
+       in order to silence the compiler even if tm is not available.
+
+2003-12-08  Simon Josefsson  <jas@extundo.com>
+
+       * flow-fill.el (fill-flowed-encode-tests, fill-flowed-test): Add.
+
+2003-12-08  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-msg.el (gnus-extended-version): Bind float-output-format to
+       nil.
+
+2003-12-08  Simon Josefsson  <jas@extundo.com>
+
+       * mml-smime.el (mml-smime-sign): Replace CRLF with LF in OpenSSL
+       output.  Reported by Arne Jørgensen <arne@arnested.dk>.
+
+2003-12-07  Lloyd Zusman  <ljz@asfast.com>  (tiny change)
+
+       * pgg-gpg.el (pgg-gpg-recipient-arg): Add.
+       (pgg-gpg-encrypt-region): Use it.
+
+2003-12-07  Simon Josefsson  <jas@extundo.com>
+
+       * pgg-gpg.el (pgg-gpg-recipient-argument): Doc fix.
+       Renamed from p-g-r-a.
+       (pgg-gpg-encrypt-region): Update.
+
+2003-12-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * spam.el (spam-check-spamoracle, spam-spamoracle-learn): Don't
+       use = or zerop to test the return value of call-process, because
+       it can be a string.
+
+       * mail-source.el (mail-source-fetch-with-program): Do.
+
+       * mailcap.el (mailcap-viewer-passes-test): Do.
+
+       * gnus-uu.el (gnus-uu-treat-archive, gnus-uu-post-encode-mime)
+       (gnus-uu-post-encode-file): Do.
+
+       * gnus-soup.el (gnus-soup-pack, gnus-soup-unpack-packet): Do.
+
+       * message.el (message-fix-before-sending): Fix detection of
+       non-printables.  Don't replace unencodable utf-8.
+
+2003-12-05  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-url.el (mm-url-predefined-programs): Add user-agent for wget.
+       (mm-url-insert-file-contents-external): Signal an error if program
+       fails.
+
+2003-12-04  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam-report.el (spam-report-gmane): Iterate over articles
+       instead of a single one; remove interactive usage.
+
+2003-12-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dns.el: Fix misplaced eval-when-compile.
+
+       * gnus-util.el: Require alist and provide tm-view when compiling
+       with XEmacs.
+
+2003-12-03  Jerry James  <james@xemacs.org>  (tiny change)
+
+       * gnus-xmas.el: Add autoloads for macros defined in gnus.el.
+
+       * gnus-util.el: Get rmail definitions when compiling.
+
+       * dns.el: Require gnus-xmas at compile time instead of trying to
+       autoload `gnus-xmas-open-network-stream' because it wasn't picking
+       up the macro.
+
+2003-12-01  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-consider-all-articles): Updated
+       docstring.
+       (gnus-predicate-implies-unread, gnus-predicate-implies-unread-1):
+       Fixed implementation such that the predicate `true' no longer
+       evaluates to t.
+
+2003-12-01  Adrian Lanz  <lanz@fowi.ethz.ch>  (tiny change)
+
+       * spam.el (spam-check-bogofilter): Check the bogofilter headers
+       AFTER the save-excursion scope is over.
+
+2003-12-01  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-fetch-field-message-id-fast): Doc fix.
+
+2003-12-01  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-agent.el (gnus-agent-expire-days): Doc fix.
+
+2003-11-30  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-agent.el (gnus-agent-expire-group-1): Bind message-log-max
+       when messaging "X % completed" to inhibit logging them to the
+       message buffer.
+       (gnus-agent-expire-group-1): Mention group name in messages.
+       (gnus-agent-expire-group-1): Only print a message for an article
+       when there actually was something done to it.
+
+       * gnus-agent.el (gnus-agent-expire-unagentized-dirs): Custom fix.
+
+2003-11-30  Kenichi Handa  <handa@m17n.org>
+
+       * mm-util.el (mm-enable-multibyte): Call set-buffer-multibyte with
+       'to argument.  Fixes something or other in Emacs 22, and is
+       backwards compatible.
+
+2003-11-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-agent.el (gnus-agent-covered-methods): Remove nil methods.
+
+2003-11-29  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+       * gnus-start.el (gnus-activate-group): The active range of the
+       group must include the articles known to the agent.
+
+       * gnus.el (gnus-agent-method-p): Accept a server name as the
+       method being tested.
+
+2003-11-29  Alexander Kreuzer  <alex@freesources.org>  (tiny change)
+
+       * nnrss.el (nnrss-check-group): Set xml when nnrss-use-local is t.
+
+2003-11-29  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-group.el (gnus-group-make-menu-bar): Add
+       gnus-group-make-rss-group.
+
+2003-11-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el: Added custom-manual links to all variables that have
+       an index entry in the message manual.
+       (message-generate-headers-first): Fixed doc-string.
+
+2003-11-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-summary-yank-message): Don't bind
+       gnus-display-mime-function to nil so that non-ascii text is
+       decoded and attachments are not shown.
+
+       * message.el (message-cite-original-without-signature): Replace
+       the value of message-reply-headers with the yanked article since
+       it may be a different article from the original.
+       (message-cite-original): Ditto.
+
+2003-11-25  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-blacklist-ignored-regexes): New variable, so
+       blacklisting can ignore certain regular expressions (e.g. the
+       user's e-mail address).
+       (spam-bogofilter-spam-strong-switch)
+       (spam-bogofilter-ham-strong-switch): Options used when articles are
+       already registered as the opposite classification.
+       (spam-old-ham-articles, spam-old-spam-articles): Lists of ham and
+       spam articles, generated when a summary buffer is entered, and
+       consulted when it's exited so we know what articles are changing
+       state from spam to ham or vice-versa.
+       (spam-xor): Everyone needs a little convenience.
+       (spam-list-of-processors): Lookup table for old-style spam/ham
+       exits processors.
+       (spam-group-processor-p): Support old-style and new-style spam/ham
+       exit processors.
+       (spam-group-processor-multiple-p): Handle new-style spam/ham exit
+       processors.
+       (spam-summary-prepare): Use spam-old-{ham,spam}-articles; change
+       logic to iterate over list of processors instead of manual
+       individual lookup, unregister any articles that change from ham to
+       spam or vice-versa in the course of the summary buffer usage; use
+       the new spam-register-routine.
+       (spam-ham-copy-routine, spam-ham-move-routine)
+       (spam-mark-spam-as-expired-and-move-routine): Check that the list
+       of groups is not nil, because apply doesn't like to apply a
+       function across nil.
+       (spam-registration-functions): Variable for looking up spam/ham
+       registration/unregistration functions based on a spam-use-* symbol.
+       (spam-classification-valid-p, spam-process-type-valid-p)
+       (spam-registration-check-valid-p)
+       (spam-unregistration-check-valid-p): Convenience functions.
+       (spam-registration-function, spam-unregistration-function): Look
+       up the registration/unregistration function based on a
+       classification and the check (spam-use-* symbol).
+       (spam-list-articles): Generate list of spam/ham articles from a
+       given list of articles.
+       (spam-register-routine): Do the heavy work of registering and
+       unregistering articles, using all the articles in the group or
+       specific ones as needed.
+       (spam-generic-register-routine): Removed, no longer used.
+       (spam-log-unregistration-needed-p, spam-log-undo-registration):
+       Handle article registration/unregistration with a given spam/ham
+       processor and group.
+       (BBDB, ifile, spam-stat, blacklists, whitelists, spam-report)
+       (bogofilter, spamoracle): Rewrite registration/unregistration
+       functions to take a list of articles and the unregister option.
+       Much hilarity ensues.
+       (spam-initialize): spam-stat-maybe-{save,load} already
+       respect spam-use-stat.
+       (spam-stat-register-ham-routine, spam-stat-register-spam-routine):
+       Don't load and save unnecessarily.
+
+       * spam-stat.el (spam-stat-dirty): New variable, set when the stats
+       database is modified.
+       (spam-stat-buffer-is-spam, spam-stat-buffer-is-non-spam)
+       (spam-stat-buffer-change-to-spam, spam-stat-to-hash-table)
+       (spam-stat-buffer-change-to-non-spam): Set spam-stat-dirty when
+       needed.
+       (spam-stat-save): Respect spam-stat-dirty, unless the force
+       parameter is specified.
+       (spam-stat-load): Clear spam-stat-dirty.
+
+       * gnus.el (gnus-install-group-spam-parameters): Marked the
+       old-style exit processors as obsolete in the docs, added the
+       new-style exit processors while the old ones are still allowed.
+
+2003-11-25  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (article-hide-boring-headers): Don't hide Reply-To
+       unless its list of addresses is identical to From.
+
+2003-11-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (mapc): Add the compiler macro for Emacs 20.
+
+2003-11-24  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-srvr.el (gnus-server-insert-server-line): The server names
+       used in gnus-agent are different (for example, the native server
+       uses the alias "native") from the names in gnus-srvr.
+       Compensating by adding a second text property storing the name
+       expected by gnus-agent.
+       (gnus-server-named-server): New function.
+       * gnus-agent.el (gnus-agent-remove-server, gnus-agent-add-server):
+       No longer expect an argument as it was ignored anyway.  Uses the
+       new gnus-server-named-server function to get gnus-agent compatible
+       names from the server buffer.
+
+2003-11-20  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus.el (gnus-agent-covered-methods): Documented use of
+       named servers, not methods, to identity agentized groups.
+       Users may now change their server configurations without having
+       the server become "unagentized".
+       (gnus-agent-covered-methods): Removed from gnus-variable-list to
+       avoid storing two copies of gnus-agent-covered-methods, one in
+       .newsrc.eld and the other in agent/lib/servers.
+       (gnus-server-to-method): Do not cache server for the nil method.
+       (gnus-method-to-server): New function.  Associate named server
+       with all, even foreign, methods.
+       (gnus-agent-method-p, gnus-agent-method-p-cache): Incorporated
+       simple last-response cache to offset performance lose of having to
+       always convert methods to named servers.
+       * gnus-agent.el (gnus-agent-expire-days): Removed obsolete
+       documentation.
+       (gnus-agentize, gnus-agent-add-server, gnus-agent-remove-server):
+       Modified to support new definition of gnus-agent-covered-method.
+       (gnus-agent-read-servers): Rewritten to convert old method data
+       into server names.
+       (gnus-agent-read-servers-validate)
+       (gnus-agent-read-servers-validate-native): New functions.
+       (gnus-agent-write-servers): No longer use gnus-method-simplify as
+       it failed to simplify foreign methods.
+       (gnus-agent-close-connections, gnus-agent-synchronize-flags)
+       (gnus-agent-possibly-synchronize-flags, gnus-agent-fetch-session)
+       (gnus-agent-regenerate): Uses new gnus-agent-covered-methods
+       function as gnus-agent-covered-methods variable no longer provides
+       methods.
+       (gnus-agent-covered-methods): New function.
+       (gnus-agent-expire-group, gnus-agent-expire): Final message will,
+       if gnus-verbose is greater than 4, report statistics of NOV
+       entries and files deleted as well as total bytes recovered.
+       (gnus-agent-expire-done-message): New function.
+       (gnus-agent-unread-articles): Bug fix.  No longer drops last
+       unread article onto read list.
+       (gnus-agent-regenerate-group): Changed prompt to use typical
+       style.
+       (gnus-agent-group-covered-p): Rewrote to internally use
+       gnus-agent-method-p.
+       * gnus-int.el (gnus-start-news-server): Partially convert old
+       gnus-agent-covered-methods to new format so that gnus-open-server
+       functions correctly.
+       * gnus-srvr.el (gnus-server-insert-server-line): Replaced
+       gnus-agent-covered-methods with gnus-agent-method-p.
+       * gnus-start.el (gnus-clear-system): Added
+       gnus-agent-covered-methods to compensate for removing it from
+       gnus-variable-list.
+       (gnus-setup-news): Complete conversion of old
+       gnus-agent-covered-methods to new format so that secondary and
+       foreign servers can be correctly opened.
+
+2003-11-20  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-ham-copy-or-move-routine): Add respooling
+       support, not working well yet.
+
+       * gnus.el (ham-process-destination): Make 'respool option the
+       only one, so it can't be chosen together with other groups.
+
+2003-11-19  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-track-extra): Make it a set of
+       choices instead of a boolean.
+       (gnus-registry-track-subject-p, gnus-registry-track-sender-p):
+       New convenience functions.
+       (gnus-registry-split-fancy-with-parent): Use convenience
+       functions, also don't return extra tracking info if sender or
+       subject is found in more than one groups.
+       (gnus-registry-add-group): Use new convenience functions to
+       decide if sender and subject should be tracked.
+
+       * gnus.el (ham-process-destination): Add 'respool option,
+       unused by spam.el yet.
+
+2003-11-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-score.el (gnus-decay-score): Return a surely smaller value
+       than the argument in XEmacs.
+
+2003-11-18  Sam Steingold  <sds@gnu.org>
+
+       * message.el (message-insert-to): Don't use `gnus-message'.
+       (message-header-synonyms): New variable.
+       (message-carefully-insert-headers): Use it (check for synonyms).
+       Added doc-string.
+
+2003-11-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * html2text.el (html2text-remove-tags): Remove the tag in a
+       simpler way to avoid inflooping.
+
+2003-11-17  Simon Josefsson  <jas@extundo.com>
+
+       * imap.el (imap-gssapi-auth-p): Don't check capability (some
+       servers remove AUTH=GSSAPI from capability response returned after
+       successful authentication).
+
+2003-11-16  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.el (gnus-getenv-nntpserver): Fix regexp and simplify.
+       Reported by Artem Chuprina <ran@ran.pp.ru>.
+
+2003-11-14  Simon Josefsson  <jas@extundo.com>
+
+       * mm-util.el (mm-charset-synonym-alist): Map BIG5-HKSCS to BIG5
+       when it isn't available.
+
+2003-11-13  Alex Schroeder  <alex@gnu.org>
+
+       * nnrss.el (nnrss-check-group): Use dc:contributor if neither
+       rss:author nor dc:creator is provided.
+
+2003-11-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-dissect-buffer): Save start="<id>" value
+       contained in Content-Type header of multipart/related messages.
+
+       * mm-view.el (mm-w3m-cid-retrieve-1): New function.
+       (mm-w3m-cid-retrieve): Use it.
+
+       * mml.el (mml-generate-mime-1): Add start="<id>" to Content-Type.
+       (mml-insert-mime-headers): Insert Content-ID header.
+       (mml-insert-mml-markup): Insert start="<id>" value.
+
+2003-11-12  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * nnml.el (nnml-request-accept-article): Pass sender to
+       nnmail-cache-insert.
+
+       * nnmh.el (nnmh-request-accept-article): Pass sender to
+       nnmail-cache-insert.
+
+       * nnmbox.el (nnmbox-request-accept-article): Pass sender to
+       nnmail-cache-insert.
+
+       * nnfolder.el (nnfolder-request-accept-article): Pass sender to
+       nnmail-cache-insert.
+
+       * nnbabyl.el (nnbabyl-request-accept-article): Pass sender to
+       nnmail-cache-insert.
+
+       * nnmail.el (nnmail-cache-insert): Accept sender parameter and
+       pass it to the nnmail-spool-hook.
+
+       * gnus-registry.el (gnus-registry-track-extra): Clarify doc.
+       (gnus-registry-action): Add sender lexical var and pass it to
+       gnus-registry-add-group.
+       (gnus-registry-spool-action): Take a sender parameter, pass to
+       gnus-registry-add-group.
+       (gnus-registry-split-fancy-with-parent): Trace by sender in
+       addition to subject.
+       (gnus-registry-fetch-sender-fast): New function.
+       (gnus-registry-add-group): Accept sender parameter.
+
+2003-11-11  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-ham-copy-routine, spam-ham-move-routine)
+       (spam-mark-spam-as-expired-and-move-routine): Allow for the
+       groups to be a list of a single item.
+
+       * gnus.el (gnus-install-group-spam-parameters):
+       ham-process-destination and spam-process-destination allow lists now.
+
+2003-11-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-mode-field-menu): Moved some entries, added
+       `message-insert-wide-reply'.
+       (message-change-subject): Fixed comment.
+
+2003-11-10  Sam Steingold  <sds@gnu.org>
+
+       * message.el (message-insert-to): Do error out when the user
+       requested no Cc.  Don't insert empty To.  Can be added to
+       `message-setup-hook' now.
+
+2003-11-10  Simon Josefsson  <jas@extundo.com>
+
+       * pgg-def.el (pgg-encrypt-for-me): Change default from nil to t.
+
+2003-11-09  Simon Josefsson  <jas@extundo.com>
+
+       * pgg-gpg.el (pgg-gpg-encrypt-region): Cache passphrase under hex
+       key id too (for decryption).
+       (pgg-gpg-sign-region): Likewise.
+
+2003-11-09  Satyaki Das  <satyakid@stanford.edu>
+
+       * pgg-gpg.el (pgg-gpg-all-secret-keys): New variable.
+       (pgg-gpg-lookup-all-secret-keys): New function.
+       (pgg-gpg-select-matching-key): Likewise.
+       (pgg-gpg-decrypt-region): Use new functions.
+
+2003-11-07  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * nnmail.el (nnmail-cache-insert): Make sure that the
+       nnmail-spool-hook is called with a valid newsgroup name (though
+       it may be wrong).
+
+       * gnus.el (gnus-group-real-prefix): Return nil if group is not a
+       string, instead of triggering an error.
+
+2003-11-06  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.el (gnus-group-guess-full-name-from-command-method):
+       New function.
+
+       * gnus-registry.el (gnus-registry-fetch-group): Use long names if
+       requested.
+       (gnus-registry-split-fancy-with-parent): When long names are in use,
+       strip the name if we're in the native server, or else return nothing.
+       (gnus-registry-spool-action, gnus-registry-action): Use
+       gnus-group-guess-full-name-from-command-method instead of
+       gnus-group-guess-full-name.
+
+       * spam.el (spam-mark-spam-as-expired-and-move-routine)
+       (spam-ham-copy-or-move-routine): Prevent article deletions or
+       moves unless the backend allows it.
+
+       * gnus.el (gnus-install-group-spam-parameters): Fixed parameters
+       to list spamoracle as well, suggested by Jean-Marc Lasgouttes
+       <Jean-Marc.Lasgouttes@inria.fr>.
+
+       * spam.el (spam-spamoracle): Doc change, suggested by Jean-Marc
+       Lasgouttes <Jean-Marc.Lasgouttes@inria.fr>.
+
+2003-11-04  Norbert Koch  <viteno@xemacs.org>  (tiny change)
+
+       * gnus-score.el (gnus-decay-score): Protect against arithmetic
+       errors.
+
+2003-10-31  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el
+       (spam-log-processing-to-registry): Improved message and comments.
+       (spam-log-unregistration-needed-p): New function.
+       (spam-ifile-register-spam-routine)
+       (spam-ifile-register-ham-routine, spam-stat-register-spam-routine)
+       (spam-stat-register-ham-routine)
+       (spam-blacklist-register-routine)
+       (spam-whitelist-register-routine)
+       (spam-bogofilter-register-spam-routine)
+       (spam-bogofilter-register-ham-routine)
+       (spam-spamoracle-learn-ham, spam-spamoracle-learn-spam): Change
+       spam-log-processing-to-registry invocations appropriately.
+
+2003-10-31  Derek Atkins  <warlord@MIT.EDU>  (tiny change)
+
+       * imap.el (imap-kerberos4-open): Ignore output from ATHENA imtest.
+
+2003-10-31  Simon Josefsson  <jas@extundo.com>
+
+       * imap.el (imap-process-connection-type): Improve docstring.
+       Suggested by Derek Atkins <warlord@MIT.EDU>.
+
+2003-10-31  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (autoload): Autoload the gnus-registry functions we'll need.
+       (spam-log-to-registry): New variable for interfacing with the
+       gnus-registry.
+       (spam-install-hooks): Variable had the wrong customization group.
+       (spam-fetch-field-message-id-fast): Convenience function for fetch
+       a message ID quickly.
+       (spam-log-processing-to-registry): New function.
+       (spam-ifile-register-spam-routine)
+       (spam-ifile-register-ham-routine, spam-stat-register-spam-routine)
+       (spam-stat-register-ham-routine)
+       (spam-blacklist-register-routine)
+       (spam-whitelist-register-routine)
+       (spam-bogofilter-register-spam-routine)
+       (spam-bogofilter-register-ham-routine)
+       (spam-spamoracle-learn-ham, spam-spamoracle-learn-spam): Add
+       spam-log-processing-to-registry invocations.
+
+       * gnus-registry.el: Fixed docs in the preface to mention
+       gnus-registry-initialize.
+       (gnus-registry-store-extra): Remove cached extra entry
+       information when new extra entry is stored.
+
+2003-10-29  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-forward-make-body-plain): Fix ARG=1 mode
+       after separating m-f-m-b.
+
+2003-10-29  Andre Srinivasan  <andre@e2open.com>  (tiny change)
+
+       * message.el (message-forward-make-body-plain): Remove ignored
+       headers.
+
+2003-10-29  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-forward-make-body-plain): Fix ARG=1.
+
+2003-10-28  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-forward-subject-name-subject)
+       (message-forward-subject-author-subject): Decode non-ASCII
+       newsgroup names.
+       (autoload): Autoload gnus-group-decoded-name.
+
+2003-10-27  Simon Josefsson  <jas@extundo.com>
+
+       * pgg-gpg.el (pgg-gpg-possibly-cache-passphrase): New optional
+       parameter key, overrides the key id used to store passphrase
+       under (uses true key id from gpg output if nil).
+       (pgg-gpg-encrypt-region): Search for passphrase using user supplied
+       string STR, instead of (pgg-lookup-key STR t).
+       (pgg-gpg-encrypt-region): Store passphrase under user supplied
+       string, instead of real key id taken from gpg output.
+       (pgg-gpg-decrypt-region): Likewise.
+       (pgg-gpg-sign-region): Likewise.
+       * pgg.el (pgg-decrypt-region): Don't set pgg-default-user-id.
+
+2003-10-27  Romain FRANCOISE  <romain@orebokech.com>
+
+       * gnus-art.el (gnus-article-goto-prev-page): Doc fix.
+
+2003-10-27  Simon Josefsson  <jas@extundo.com>
+
+       * mm-bodies.el (mm-body-encoding): Don't use QP when message body
+       only consists of short lines and ASCII, when
+       mm-use-ultra-safe-encoding.  Refer to 'About foo' thread in
+       gnus-bug, e.g. <ilullrg4k7p.fsf@extundo.com>, for more discussion.
+       This make it possible to pipe the raw RFC 822 message into 'gpg'
+       and have the signature work.  Potential problem: what if message
+       contain data that would be dash-escaped by OpenPGP
+       implementations? Then PGP 2.x might not be able to parse the raw
+       RFC 822 message correctly.  If that problem is worth fixing, it
+       should be fixed by detecting the situation, instead of applying QP
+       to everything.  Based on discussion with "John A. Martin"
+       <jam@jamux.com>.
+
+2003-10-27  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-mark-spam-as-expired-and-move-routine)
+       (spam-ham-copy-or-move-routine): Don't ask when deleting copied
+       articles, and use move instead of copy when possible.
+       (spam-split): Added the option of specifying a string as a
+       spam-split parameter; such a string will override
+       spam-split-group temporarily.
+
+       * nnmail.el (nnmail-cache-insert): Protect from nil message IDs,
+       but should we do something else?
+
+       * gnus-registry.el (gnus-registry-spool-action): Protect from nil
+       message IDs.
+
+2003-10-26  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-art.el (gnus-button-alist): Allow & in mailto URLs.
+       (gnus-header-button-alist): Likewise.
+       (gnus-url-mailto): Handle ?to parameters.  Replace \r\n with \n.
+       Reverse parameter list to use same order as in the URL.  Reported
+       by f95-msv@f.kth.se (Mårten Svantesson).
+
+2003-10-25  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-move-spam-nonspam-groups-only): Documentation fix
+       for the variable.
+
+2003-10-25  Steve Youngs  <sryoungs@bigpond.net.au>
+
+       * Makefile.in (clean-some): Remove auto-autoloads.* and
+       custom-load.* as well.
+       (distclean): Ditto.
+
+       * dgnushack.el (dgnushack-make-load): Add a local vars section to
+       the dummy gnus-load.el.
+
+2003-10-24  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-ham-copy-or-move-routine): Do not delete if copy
+       is t, also don't interpret the list of groups as a list of lists.
+       (spam-mark-spam-as-expired-and-move-routine)
+       (spam-ham-copy-or-move-routine): Delete articles only if 1 or
+       more groups were specified (and "copy" was not specified for
+       spam-ham-copy-or-move-routine) (fixed twice).
+
+2003-10-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nndoc.el (nndoc-guess-type): Reverse the sort order.  Suggested
+       by ARISAWA Akihiro <ari@mbf.ocn.ne.jp>.
+       (nndoc-dissect-buffer): Don't miss even-numbered articles.
+
+2003-10-24  Steve Youngs  <sryoungs@bigpond.net.au>
+
+       * dgnushack.el (dgnushack-gnus-load-file): Set to
+       "auto-autoloads.el" if building with XEmacs.
+       (dgnushack-cus-load-file): Set to "custom-load.el" if building
+       with XEmacs.
+       (dgnushack-make-cus-load): We don't delete the resulting file if
+       building with XEmacs so byte-compile it.
+       (dgnushack-make-load): When building with XEmacs do nothing except
+       byte-compile the autoload file and create a dummy gnus-load.el
+       file.
+
+2003-10-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-make-fqdn): Bind case-fold-search.
+       Suggested by Christopher Richards <richards@CS.Princeton.EDU>.
+
+2003-10-23  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.el (spam-process-destination, ham-process-destination):
+       Allow multiple groups as a choice.
+
+       * spam.el (spam-check-blackholes): Remove "[IP address]"
+       requirement, now just "IP address" is enough for detection for
+       blackhole checking.
+       (spam-check-blackholes): Oops, the dots were not escaped.
+       (spam-mark-spam-as-expired-and-move-routine): Added multiple group
+       support (multiple copies, then delete).
+       (spam-ham-copy-routine): New function.
+       (spam-ham-move-routine): New function.
+       (spam-ham-copy-or-move-routine): New function (used to be
+       spam-ham-move-routine), handle multiple groups.
+       (spam-summary-prepare-exit): Call the new functions.
+
+2003-10-23  Simon Josefsson  <jas@extundo.com>
+
+       * flow-fill.el (fill-flowed-encode, fill-flowed): Autoload.
+
+2003-10-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-emphasis-strikethru): Use the :strike-through
+       attribute in Emacs.
+
+2003-10-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-bounce): Don't erase except bounced header.
+
+2003-10-21  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-reverse-ip-string): New function to reverse an IP
+       address in a string.
+       (spam-check-blackholes): Use spam-reverse-ip-string.
+
+2003-10-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-narrow-to-page): Clear as well as set the
+       value for gnus-page-broken.
+
+       * gnus-sum.el (gnus-summary-beginning-of-article): Use
+       gnus-break-pages instead of gnus-page-broken.
+       (gnus-summary-end-of-article): Use gnus-break-pages instead of
+       gnus-page-broken; narrow to the end of a page beforehand.
+       (gnus-summary-toggle-header): Use gnus-break-pages instead of
+       gnus-page-broken; remove delimiter buttons unless gnus-break-pages
+       is non-nil.
+
+2003-10-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-picon.el (gnus-picon-transform-address): Protect against
+       errors.
+
+2003-10-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (nnspool-rejected-article-hook): Remove defvar.
+       (xemacs-codename): Move defvar to gnus-util.el.
+
+       * gnus-util.el (xemacs-codename): Defvar when compiling.
+
+2003-10-20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * spam-report.el (spam-report-url-ping-plain): Include a
+       User-Agent.
+
+       * gnus-msg.el (gnus-extended-version): Use it.
+
+       * gnus-util.el (gnus-emacs-version): Separated out into own
+       function.
+
+2003-10-19  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-mode-field-menu): Added
+       message-generate-unsubscribed-mail-followup-to.
+       (message-forward-subject-fwd): Avoid double "Fwd: ".
+       (message-change-subject): Added comment.
+
+2003-10-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-nov-parse-line): Remove condition-cases.
+
+       * mml.el (mml-insert-mime): Quote mml.
+
+2003-10-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-remove-odd-characters): Use
+       mm-subst-char-in-string instead of subst-char-in-string.
+       (gnus-summary-refer-article): Use gnus-replace-in-string instead
+       of replace-regexp-in-string.
+
+2003-10-19  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-uu.el (gnus-uu-uustrip-article): Really strip directory
+       from file name.
+
+2003-10-18  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-summary-save-parts-last-directory): Default
+       to mm-default-directory.
+       (gnus-summary-save-parts-1): Use mm-file-name-rewrite-functions.
+
+2003-10-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * pop3.el (pop3-read-response): Check whether the process is
+       alive.
+
+       * gnus-sum.el (gnus-summary-refer-article): Strip spaces.
+
+       * rfc2047.el (rfc2047-encode-region): Do error out on invalid
+       strings.
+
+       * nntp.el (nntp-retrieve-headers-with-xover): Get error messages
+       right.
+
+       * gnus-agent.el (gnus-agent-read-servers): Remove sit-for.
+
+       * gnus-art.el (article-treat-dumbquotes): Doc fix.
+
+       * message.el (message-field-value): New function.
+       (message-insert-disposition-notification-to): Use Reply-To, too.
+
+       * imap.el (imap-mailbox-status): Upcase STATUS commands.
+
+       * gnus-sum.el (gnus-remove-odd-characters): New function.
+       (gnus-nov-parse-line): Use it.
+
+2003-10-18  Matt Swift  <swift@alum.mit.edu>
+
+       * mm-decode.el (mm-inline-media-tests): Recognize pjpeg as jpeg.
+
+2003-10-18  Romain FRANCOISE  <romain@orebokech.com>
+
+       * message.el (message-forward-make-body): Does both
+       m-f-make-body-mml and m-f-make-body-plain, resulting in a strange
+       message buffer.
+
+2003-10-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-narrow-to-page): Only break page if it's
+       broken.
+
+       * nnrss.el (nnrss-find-rss-via-syndic8): Return nil if xml-rpc
+       isn't available.
+
+       * message.el (message-hidden-headers): Doc fix.
+
+2003-10-18  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-msg.el (gnus-summary-resend-message-edit): Avoid error when
+       fields aren't found.
+
+2003-10-18  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-forward-make-body-plain)
+       (message-forward-make-body-mime, message-forward-make-body-mml)
+       (message-forward-make-body-digest-plain)
+       (message-forward-make-body-digest-mime)
+       (message-forward-make-body-digest): New, derived from
+       message-forward-make-body.
+       (message-forward-make-body): Use them.
+       (message-forward-show-mml): New default 'best.
+       (message-forward-make-body): Support it.
+
+2003-10-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-mode): Set gnus-page-broken to nil.
+       (gnus-article-prepare): Don't set to t.
+       (gnus-narrow-to-page): Set to t if we break.
+
+2003-06-11  Daniel Néri  <dne@mayonnaise.net>
+
+       * message.el (message-resend): Generate Resent-Message-ID header.
+
+2003-10-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-next-page): Don't go to the next line
+       before checking end-of-buffer.
+       (gnus-mime-delete-part): Don't insert parts twice.
+
+2003-10-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-update-date-lapsed): Make sure point
+       doesn't move around (much).
+
+2003-07-28  Vasily Korytov  <deskpot@myrealbox.com>
+
+       * mail-source.el (mail-source-keyword-map): List "cur" before
+       "new" for maildirs.
+
+2003-10-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-enter-digest-group): ogroup, nor
+       group.
+
+       * gnus-msg.el (gnus-inews-insert-archive-gcc): Use the parent
+       name for gcc-self.
+       (gnus-inews-insert-archive-gcc): Paren mistake.
+
+       * gnus-sum.el (gnus-summary-enter-digest-group): Add
+       parent-group.
+
+       * gnus-art.el (gnus-ignored-headers): Add more headers.
+
+       * rfc2047.el (rfc2047-encode): See which encoding is shorter --
+       base64 or QP.
+
+       * nnmail.el (nnmail-article-group): Default to "bogus".
+
+       * mail-source.el (mail-source-delete-incoming): Change to nil.
+
+2003-10-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mail-source.el (mail-source-fetch-imap): Fix mismatched parens.
+
+2003-10-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (defvar): Add post/pre/scripts.
+       (mail-source-fetch-imap): Use them.
+
+       * nndraft.el (nndraft-request-move-article): Fix infinite
+       recursion.
+
+       * gnus-group.el (gnus-group-mark-regexp): Jump to groups.
+
+2003-10-16  Ed L. Cashin  <ecashin@uga.edu>
+
+       * imap.el (imap-interactive-login): Set imap-password to nil if
+       login fails.
+
+2003-10-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-inserted-headers): New variable.
+       (message-mode): Make local.
+       (message-mode): Set all the local action variables to nil.
+
+2003-10-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-inline-text-html-with-images): Doc fix.
+       (mm-w3m-safe-url-regexp): Doc fix.
+
+2003-10-12  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-summary-respool-query): Don't narrow to head,
+       it's done by nnmail-article-group.
+
+2003-10-12  Mark Hood  <markhood@speakeasy.net>  (tiny change)
+
+       * gnus-uu.el (gnus-uu-grab-articles): Fix misplaced parens.
+
+2003-10-10  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-decode.el (mm-file-name-delete-gotchas): Avoid infloop in
+       XEmacs.
+
+2003-10-10  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-initialize): New function, does the spam-face
+       update and all the hooks, replaces spam-install-hooks-function.
+
+       * gnus-registry.el (gnus-registry-initialize): New autoloaded
+       function to explicitly initialize the registry.
+
+2003-10-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-w3m-safe-url-regexp): Doc fix.
+
+       * mm-view.el (mm-w3m-mode-map): Doc fix.
+       (mm-inline-text-html-render-with-w3m): Add a comment.
+
+2003-10-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el: Remove superfluous eval-when-compiles.
+
+2003-10-10  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-group.el (gnus-group-suspend): Reset gnus-backlog-articles.
+
+2003-10-08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * dns.el (query-dns): Don't error out on malformed resolv files.
+
+2003-10-06  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.el (gnus-group-faq-directory): Update .tw entry.  From
+       Albert Chun-Chieh Huang <mr894348@cs.nthu.edu.tw>
+
+2003-10-03  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-check-blackholes): Exit the loop if matches are
+       found (idea from Adrian Lanz <lanz@fowi.ethz.ch>).
+       (spam-check-bogofilter-headers, spam-check-blackholes, spam-check-BBDB)
+       (spam-from-listed-p): Use nnmail-fetch-field instead of
+       message-fetch-field.
+
+2003-10-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-attachment-file-modes): Change the default
+       value into 384 from ?\600 which doesn't mean an integer in XEmacs.
+
+2003-10-03  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-decode.el (mm-file-name-delete-control)
+       (mm-file-name-delete-gotchas): New functions.
+       (mm-file-name-rewrite-functions): Use them.
+       (mm-attachment-file-modes): New option.
+       (mm-save-part-to-file): Use it.
+
+2003-10-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * spam.el (spam-install-hooks-function): Added Autoload cookie.
+
+2003-10-02  Michael Shields  <shields@msrl.com>
+
+       * pgg-def.el (pgg-default-keyserver-address): Change to
+       subkeys.pgp.net.
+
+2003-10-01  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-idna-to-ascii-rhs-1): RHS can be terminated
+       by ',', as in 'foo@example.org, bar@example.org'.
+
+2003-10-01  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-send): Fix reversed logic of supersedes
+       check.
+
+2003-09-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-article-view-part-as-charset): Doc fix,
+       suggested by Norbert Koch <viteno@xemacs.org>.
+
+2003-09-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-topic.el (gnus-topic-goto-missing-topic): Revert 2003-02-09
+       change in order to correct the position where an invisible topic
+       (because gnus-topic-display-empty-topics is nil) may be inserted.
+
+2003-09-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-ignored-supersedes-headers): Add X-Payment.
+
+2003-09-20  Jesper Harder  <harder@ifa.au.dk>
+
+       * rfc2047.el (rfc2047-encode): Limit line length to 76 characters.
+
+2003-09-20  Simon Josefsson  <jas@extundo.com>
+
+       * tls.el (tls-process-connection-type): Doc fix.
+
+       * imap.el (imap-starttls-open): Rewrite, should support both old
+       starttls.el and new starttls.el that uses GNUTLS.
+
+2003-09-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-treat-display-x-face): Use set-default instead
+       of custom-set-default which isn't available in old XEmacsen.
+
+2003-09-17  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-msg.el (gnus-summary-resend-message-edit): Don't convert
+       to MML.  MIME -> MML -> MIME does not work for PGP/MIME.
+
+       * message.el (message-bounce, message-forward-show-mml): Do.
+
+2003-09-13  Jesper Harder  <harder@ifa.au.dk>
+
+       * rfc2047.el (rfc2047-charset-encoding-alist): Add viscii.
+       (rfc2047-encode): Add factors for big5, gb2312 and euc-kr.
+
+       * nnweb.el (nnweb-google-parse-1): Fix parsing.
+
+2003-09-12  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-group.el (gnus-group-fetch-control): ISC changed
+       compression from .Z to .gz.
+
+       * rfc2047.el (rfc2047-header-encoding-alist): Add "Approved" to
+       address-mime.
+
+2003-09-11  Jesper Harder  <harder@ifa.au.dk>
+
+       * rfc2047.el (rfc2047-encode): Restrict encoded-words to 75
+       characters.
+
+2003-09-10  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.el (gnus-group-charter-alist): Update.
+
+2003-09-10  Eric Knauel  <knauel@informatik.uni-tuebingen.de>
+
+       * spam-report.el: Use mm-url.el functions for external URL loading
+       when the built-in HTTP GET is insufficient (e.g. proxies are in
+       the way).
+
+2003-09-10  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam-report.el (spam-report-url-ping-function): New option,
+       defaults to the built-in HTTP GET (spam-report-url-ping-plain).
+       (spam-report-url-ping): Call spam-report-url-ping-function.
+       (spam-report-url-ping-plain): New function, does what
+       spam-report-url-ping used to do.
+       (spam-report-url-ping-mm-url): Function that delegates to
+       mm-url.el (autoloaded).
+
+2003-09-08  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-delete-id): Function to
+       completely delete an ID, including all the cache hashtables.
+       (gnus-registry-delete-group): Use gnus-registry-delete-id.
+       (gnus-registry-simplify-subject): Only run if the argument is a
+       string, return nil otherwise.
+
+2003-09-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-msg.el (gnus-summary-resend-bounced-mail): Docstring fix.
+
+2003-09-05  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-split-fancy-with-parent): Yet
+       another error.  *sigh*
+
+       * gnus-registry.el (gnus-registry-fetch-extra-entry): Don't use
+       puthash unless gnus-registry-entry-caching is on.
+       (gnus-registry-split-fancy-with-parent): Misplaced parenthesis
+       made everything a part of the 'else'.
+       (gnus-registry-save): Used 'entry-caching' instead of 'caching'.
+
+2003-09-05  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-button-alist): Improve Info regexp.
+
+2003-09-04  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el: Added brief explanation of basics.
+       (gnus-registry-track-extra): New variable for tracking of message
+       subjects.
+       (gnus-registry-entry-caching): Caching parameter, used for extra
+       data.
+       (gnus-registry-minimum-subject-length): Minimum subject length
+       before it's considered when tracing subjects.
+       (gnus-registry-save): Accommodate extra data entry caching.
+       (gnus-registry-action): Change function name, add the subject and
+       pass it to gnus-registry-add-group.
+       (gnus-registry-spool-action): Change function name, add the
+       subject and pass it to gnus-registry-add-group.
+       (gnus-registry-split-fancy-with-parent): Add subject tracking.
+       (gnus-registry-register-message-ids): Pass subject to
+       gnus-registry-add-group.
+       (gnus-registry-simplify-subject)
+       (gnus-registry-fetch-simplified-message-subject-fast): New
+       functions.
+       (gnus-registry-fetch-extra, gnus-registry-fetch-extra-entry): Add
+       extra data entry caching.
+       (gnus-registry-add-group): Handle the extra subject parameter.
+       (gnus-registry-install-hooks, gnus-registry-unload-hook): Fix the
+       gnus-register-* function names.
+
+       * nnmail.el (nnmail-cache-insert): Add subject parameter, pass it
+       on to the nnmail-spool-hook.
+
+       * nnbabyl.el (nnbabyl-request-accept-article): Added subject to
+       nnmail-cache-insert call.
+
+       * nndiary.el (nndiary-request-accept-article): Added subject to
+       nnmail-cache-insert call.
+
+       * nnfolder.el (nnfolder-request-accept-article): Added subject to
+       nnmail-cache-insert call.
+
+       * nnimap.el (nnimap-split-articles): Added subject to
+       nnmail-cache-insert call.
+       (nnimap-request-accept-article): Added subject to
+       nnmail-cache-insert call.
+
+       * nnmbox.el (nnmbox-request-accept-article): Added subject to
+       nnmail-cache-insert call.
+
+       * nnmh.el (nnmh-request-accept-article): Added subject to
+       nnmail-cache-insert call.
+
+       * nnml.el (nnml-request-accept-article): Added subject to
+       nnmail-cache-insert call.
+
+2003-09-04  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-button-handle-info-url)
+       (gnus-button-handle-info-url-gnome)
+       (gnus-button-handle-info-url-kde, gnus-button-alist): Handle GNOME
+       and KDE style Info URLs.
+
+       * gnus-util.el (gnus-url-unhex-string): Don't replace "+" with " ".
+
+2003-09-02  Jesper Harder  <harder@ifa.au.dk>
+
+       * rfc2047.el (rfc2047-fold-region): Don't fold at the beginning
+       of the field.
+
+2003-09-01  Simon Josefsson  <jas@extundo.com>
+
+       * mml.el (mml-insert-mime-headers-always): New variable.
+       (mml-insert-mime-headers): Use it.  Based on (tiny) patch from
+       Lars Balker Rasmussen <lars@balker.org>.
+
+2003-08-30  Gaute B Strokkenes  <gs234@srcf.ucam.org>  (tiny change)
+
+       * mail-source.el (mail-source-fetch-imap): Pass correct buffer to
+       imap-open, reverts 2003-03-17 change.  Reverse remove before
+       calling gnus-compress-sequence.
+
+2003-08-29  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-group.el (gnus-group-delete-group): Doc fix.  Suggested by
+       Jochen Küpper <jochen@jochen-kuepper.de>.
+
+2003-08-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-display-x-face): Make it possible to set
+       the gnus-article-x-face-command variable to the lambda form.
+
+2003-08-27  Simon Josefsson  <jas@extundo.com>
+
+       * mm-decode.el (mm-remove-part): Try to kill external displayers
+       cleanly first (if it refuses, C-g aborts loop and kill process
+       unconditionally).  Also make sure process is dead before we remove
+       the files it may be using.  Reported by David Coe
+       <davidc@debian.org>.
+
+2003-08-27  Vagn Johansen  <v@johansen.mail.dk>  (tiny change)
+
+       * gnus-cache.el (gnus-cache-generate-active): Fix bug in
+       replacement.
+
+2003-08-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el: Don't use defvaralias.
+       (gnus-treat-display-x-face): Warn if the obsolete variable
+       `gnus-treat-display-xface' exists.
+
+2003-08-25  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-treat-display-face): Fix typo.
+       (gnus-treat-display-xface): Rename to gnus-treat-display-x-face
+       (reported by Jochen Küpper <jochen@jochen-kuepper.de>).
+
+2003-08-24  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-header-button-alist, gnus-button-alist): Fix
+       type.
+
+2003-08-22  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-make-forward-subject-function): Fix
+       customize mismatch.
+
+       * gnus.el (gnus-message-archive-method): Do.
+
+2003-08-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.el (gnus-read-group): Offer to continue only if the invalid
+       char is `/' and add more information for the user.
+
+       * gnus-art.el (gnus-button-alist): Add `+' (gnus-button-handle-man).
+       (gnus-header-button-alist): Added `In-Reply-To'.
+
+       * nnimap.el (nnimap-open-connection): Allow different user names
+       on the same server (and in the same authinfo file).
+
+2003-08-20  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sieve.el (gnus-sieve-crosspost): Fix type.
+
+       * message.el (message-make-forward-subject-function): Add
+       message-forward-subject-name-subject to choices.
+
+       * gnus-art.el (gnus-article-edit-done, gnus-article-edit-exit):
+       Redisplay article after editing.
+
+2003-08-20  Jari Aalto  <jari.aalto@poboxes.com>
+
+       * gnus.el (gnus-read-group): Added check to ask confirmation if
+       Group name contains invalid character.  You can use '/' in IMAP,
+       but not in filenames.  G m cannot know what the user is creating,
+       so let user decide.  See thread m2oeysiev3.fsf@naima.lensflare.org.
+
+2003-08-13  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-score.el (gnus-summary-score-effect): Fix interactive use.
+
+2003-08-10  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-draft.el (gnus-draft-send-all-messages): Ask if all drafts
+       should be sent unless gnus-expert-user is on.
+
+2003-08-09  Jesper Harder  <harder@ifa.au.dk>
+
+       * pgg-gpg.el (pgg-gpg-extra-args): Fix customization type.
+
+2003-08-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * pgg-gpg.el (pgg-gpg-process-region): Bind
+       default-enable-multibyte-characters to nil.
+
+2003-08-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * canlock.el (canlock-password): Fix customization type.
+       (canlock-password-for-verify): Ditto.
+       * deuglify.el (gnus-outlook-deuglify-unwrap-min): Ditto.
+       (gnus-outlook-deuglify-unwrap-max): Ditto.
+       (gnus-outlook-deuglify-unwrap-stop-chars): Ditto.
+       * gnus-sum.el (gnus-sum-thread-tree-root): Ditto.
+       (gnus-sum-thread-tree-false-root): Ditto.
+       (gnus-sum-thread-tree-single-indent): Ditto.
+       * message.el (message-archive-note): Ditto.
+       (message-subscribed-address-file): Ditto.
+       (message-user-fqdn): Ditto.
+       * spam-report.el (spam-report-gmane-regex): Ditto.
+       * spam.el (spam-blackhole-good-server-regex): Ditto.
+
+       * gnus-start.el (gnus-save-killed-list): Fix last change.
+       * message.el (message-courtesy-message): Ditto.
+
+2003-08-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-header-face-alist): Revert previous change.
+       (gnus-header-newsgroups-face): Explain that it's only used for
+       crossposts.
+
+2003-08-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-registry.el (gnus-registry-max-entries): Fix customization
+       type.
+       * gnus-score.el (gnus-adaptive-word-length-limit): Ditto.
+       * gnus.el (gnus-refer-article-method): Ditto.
+       * message.el (message-courtesy-message): Ditto.
+
+2003-08-06  Chunyu Wang  <spr@db.cs.hit.edu.cn>  (tiny change)
+
+       * gnus-art.el (gnus-header-face-alist): Fix "Newsgroups" entry.
+
+2003-08-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-start.el (gnus-save-killed-list): Fix customization type.
+       * gnus-sum.el (gnus-thread-hide-subtree): Ditto.
+       * gnus.el (gnus-use-long-file-name): Ditto.
+
+2003-08-04  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-group.el (gnus-group-rename-group): Don't allow renaming to
+       an existing name.
+
+       * gnus-sum.el (gnus-summary-highlight): Add uncached to docstring.
+
+       * nnmail.el (nnmail-large-newsgroup): Docstring fix.
+
+       * nntp.el (nntp-large-newsgroup): Do.
+
+       * nnspool.el (nnspool-large-newsgroup): Do.
+
+       * gnus-cus.el (gnus-group-parameters): Typo.
+
+2003-07-31  Simon Josefsson  <jas@extundo.com>
+
+       * mml-sec.el (mml-signencrypt-style-alist): Use separate S/MIME
+       method by default (revert partial 2003-07-10 patch).
+
+2003-07-28  Dave Love  <fx@gnu.org>
+
+       * pgg-gpg.el, pgg-pgp.el, pgg-pgp5.el: Require cl when compiling.
+
+2003-07-26  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-install): Add an initial
+       registry read to the loading when gnus-registry-install is set.
+
+2003-07-26  Mark Thomas  <swoon@bellatlantic.net>  (tiny change)
+
+       * flow-fill.el (fill-flowed): Empty lines separate paragraphs
+       even if the preceding line ends with a soft break.
+
+2003-07-25  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-use-regex-body, spam-regex-body-spam)
+       (spam-regex-body-ham): New variables, default to nil/empty/empty.
+       (spam-install-hooks): Added spam-use-regex-body to list or
+       pre-install conditions.
+       (spam-list-of-checks): Added spam-use-regex-body and
+       spam-check-regex-body to list of checks.
+       (spam-list-of-statistical-checks): Added spam-use-regex-body to
+       list of statistical checks.
+       (spam-check-regex-body): Invokes spam-check-regex-headers with
+       appropriate variable masking.
+       (spam-check-regex-headers): Changes to print "body" or "header"
+       where appropriate.
+
+2003-07-25  Jesper Harder  <harder@ifa.au.dk>
+
+       * smime.el (smime-ask-passphrase): Use read-passwd rather than
+       comint-read-noecho.  The former is more secure.
+
+2003-07-24  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-cache-whitespace): Make "adding
+       whitespace" message level 5 instead of 4.
+       (gnus-registry-clean-empty-function): New function to remove empty
+       registry entries.
+       (gnus-registry-clean-empty): New variable to enable cleaning the
+       registry when saving it by calling gnus-registry-clean-empty-function.
+
+       * spam.el (spam-summary-prepare-exit): Use
+       spam-process-ham-in-spam-groups.
+       (spam-process-ham-in-spam-groups): New variable.
+
+2003-07-24  Jesper Harder  <harder@ifa.au.dk>
+
+       * pgg-gpg.el (pgg-gpg-process-region): Add "--yes" to options.
+
+       * pgg-gpg.el, pgg-pgp.el, pgg-pgp5.el, pgg.el: Reapply changes
+       from 2003-04-03 to fix security problem.  See
+       http://www.debian.org/security/2003/dsa-339.
+
+2003-07-23  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.el (gnus-install-group-spam-parameters): Add the
+       gnus-ticked-mark to the possible choices of ham marks.
+
+       * spam.el (spam-process-ham-in-nonham-groups): New variable.
+       (spam-summary-prepare-exit): Use spam-process-ham-in-nonham-groups.
+
+2003-07-23  Jesper Harder  <harder@ifa.au.dk>
+
+       * rfc2047.el (rfc2047-header-encoding-alist): Add Mail-Followup-To
+       and Mail-Copies-To to address-mime.
+       (rfc2047-narrow-to-field): Use rfc2047-point-at-bol.
+
+2003-07-19  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-util.el (mm-coding-system-priorities): Docstring improvement.
+
+2003-07-17  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-thread-latest-date): Move condition-case to
+       the right place.
+
+2003-07-14  Simon Josefsson  <jas@extundo.com>
+
+       * mail-source.el (mail-source-fetch-imap): Don't assume
+       imap-error-text returns something.
+
+2003-07-12  Nevin Kapur  <kapur@mts.jhu.edu>
+
+       * nnimap.el (nnimap-request-newgroups): Use the pattern in
+       nnimap-list-pattern instead of "*".
+
+2003-07-10  Simon Josefsson  <jas@extundo.com>
+
+       * mml-sec.el (mml-signencrypt-style-alist): Use "combined" by
+       default.  Improve docstring.
+
+2003-07-10  Kai Großjohann  <kai.grossjohann@gmx.net>
+
+       * imap.el (imap-arrival-filter): Fix test for missing process
+       buffer.
+
+2003-07-09  Gaute B Strokkenes  <gs234@cam.ac.uk>  (tiny change)
+
+       * imap.el (imap-wait-for-tag): Clarify comment.  Use timeout zero
+       for second, after-process-has-died, accept-process-output.
+       (imap-arrival-filter): If PROC has no buffer, do nothing.
+
+2003-07-09  Jesper Harder  <harder@ifa.au.dk>
+
+       * flow-fill.el: Docstring and message fixes.
+
+       * deuglify.el: Do.
+
+       * gnus-int.el: Do.
+
+       * gnus-msg.el: Do.
+
+       * gnus-util.el: Do.
+
+       * gnus-draft.el: Do.
+
+       * gnus-start.el: Do.
+
+       * gnus.el: Do.
+
+       * gnus-group.el: Do.
+
+       * gnus-art.el: Do.
+
+       * gnus-sum.el: Do.
+
+       * mail-source.el (mail-source-movemail): Handle non-numerical
+       return values.
+
+2003-07-08  Jesper Harder  <harder@ifa.au.dk>
+
+       * mailcap.el (mailcap-parse-args-syntax-table)
+       (mailcap-viewer-passes-test): Docstring fix.
+
+       * mm-bodies.el (mm-long-lines-p): Docstring fix.
+
+       * mm-decode.el (mm-w3m-safe-url-regexp, mm-verify-option)
+       (mm-decrypt-option, mm-handle-set-external-undisplayer)
+       (mm-file-name-replace-whitespace): Docstring fix.
+
+       * mm-uu.el (mm-uu-emacs-sources-regexp): Docstring fix.
+       (mm-uu-pgp-signed-test): Fix message.
+
+       * mml.el (mml-tweak-sexp-alist): Docstring fix.
+       (mml-parse-1, mml-insert-mime-headers): Fix message.
+
+       * message.el (message-archive-header)
+       (message-subscribed-address-functions)
+       (message-subscribed-addresses, message-subscribed-regexps)
+       (message-canlock-generate)
+       (message-generate-new-buffer-clone-locals): Docstring fixes.
+
+2003-07-07  Gaute B Strokkenes  <gs234@cam.ac.uk>  (tiny change)
+
+       * imap.el (imap-wait-for-tag): After the process has died, look
+       for more output still pending.
+
+2003-07-07  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-bogofilter-score): Redisplay article normally
+       after spam-bogofilter-score is called.
+
+2003-07-06  Michael Piotrowski  <mxp@dynalabs.de>  (tiny change)
+
+       * gnus-sum.el (gnus-print-buffer): Apply emphasis.
+
+2003-07-06  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-send-mail-with-sendmail): Handle
+       non-numeric return values.
+
+       * gnus-start.el (gnus-clear-system): Revert change from
+       2003-06-19.
+
+2003-07-04  Dave Love  <fx@gnu.org>
+
+       * rfc2047.el (rfc2047-q-encode-region): Exclude especials from
+       characters not encoded, and make the list more legible.
+
+2003-07-04  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-make-from): Revert change from 2002-01-08.
+
+2003-06-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnheader.el (nnheader-init-server-buffer): Don't add
+       nntp-server-buffer to list of Gnus buffers.
+
+2003-06-25  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-parse-list): Prevent empty ("") strings.
+
+2003-06-24  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-parse-list): Use gnus-extract-address-components
+       instead of ietf-drums-parse-addresses.
+       (spam-from-listed-p): let* was unnecessary.
+
+2003-06-24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-ems.el (gnus-put-image): Mark the right text segment with
+       gnus-image-category.
+
+       * gnus-srvr.el (gnus-browse-unsubscribe-group): Strip prefix from
+       native groups.
+
+       * gnus-topic.el (gnus-group-prepare-topics): Update topic line
+       format specs.
+
+       * gnus-picon.el: Written by moi, moi, moi.
+
+       * gnus-group.el (gnus-group-kill-group): Clean up.
+
+2003-06-23  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-from-listed-p, spam-parse-list): Use
+       ietf-drums-parse-addresses to extract the address portion of the
+       whitelist/blacklist file if it looks like an address can be found.
+
+2003-06-23  Didier Verna  <didier@xemacs.org>
+
+       * gnus-ems.el (gnus-put-image): New argument CATEGORY.  Add it as a
+       text property.
+       (gnus-remove-image): New argument CATEGORY.  Only remove if
+       category matches.
+       * gnus-xmas.el (gnus-xmas-put-image):
+       (gnus-xmas-remove-image): Ditto, with extents.
+       * gnus-art.el (gnus-delete-images): Pass CATEGORY argument to
+       gnus-[xmas-]remove-image.
+       (article-display-face): Don't always act as a toggle.  Call
+       `gnus-put-image' with CATEGORY argument.
+       (article-display-x-face): Call `gnus-put-image' with CATEGORY
+       argument.
+       * smiley.el (smiley-region): Ditto.
+       * gnus-fun.el (gnus-display-x-face-in-from): Ditto.
+       * gnus-picon.el (gnus-picon-insert-glyph): Ditto.
+       (gnus-treat-mail-picon): Don't always act as a toggle.
+       * gnus-picon.el (gnus-treat-newsgroups-picon): Ditto.
+
+2003-06-23  Didier Verna  <didier@xemacs.org>
+
+       * gnus-art.el (article-display-face): Check for existence of the
+       original article buffer before switching to it.
+
+2003-06-20  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-util.el (mm-append-to-file): Say "Appended to".  Suggested by
+       Dan Jacobson <jidanni@jidanni.org>.
+
+       * mm-view.el (mm-inline-message): Bind
+       gnus-original-article-buffer to the buffer in the mml handle
+       holding the message.
+
+2003-06-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (sender, from): No need to bind them.
+
+2003-06-19  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-enter-list): search-forward specified wrong.
+
+2003-06-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el: Comment fix.
+
+2003-06-20  Jesper Harder  <harder@ifa.au.dk>
+
+       * spam.el (spam-spamoracle-learn): insert-string is obsolete.
+
+2003-06-20  Jan Rychter  <jan@rychter.com>
+
+       * gnus-msg.el (gnus-configure-posting-styles): Remove unused
+       variable.
+
+2003-06-19  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-enter-list): Do not enter duplicate addresses into
+       the whitelist/blacklist.
+
+2003-06-19  Jesper Harder  <harder@ifa.au.dk>
+
+       * nnheader.el (nnheader-init-server-buffer): Add
+       nntp-server-buffer to gnus-buffers.
+
+       * gnus-start.el (gnus-clear-system): Now we don't need to kill
+       nntp-server-buffer separately.
+
+2003-06-18  Didier Verna  <didier@xemacs.org>
+
+       * gnus-art.el (article-display-face): Correctly toggle between
+       display and hiding.  Handle multiple Face headers.
+
+2003-06-17  Dave Love  <fx@gnu.org>
+
+       * nnimap.el: Require cl when compiling.
+
+       * message.el (message-fix-before-sending): Reinstate nullifying
+       the invisible text property.
+       (sender, from): Defvar when compiling.
+       (message-is-yours-p): Remove autoload cookie.
+
+2003-06-17  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-util.el (gnus-extract-address-components): Added
+       doc-string.
+
+2003-06-16  Michael Albinus  <Michael.Albinus@alcatel.de>
+
+       * nnml.el (nnml-current-group-article-to-file-alist): Don't read
+       overview when using compressed files.
+
+2003-06-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-refer-parent-article): Extract
+       Message-ID from In-Reply-To header.
+
+2003-06-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-is-yours-p): Narrow to head; extract from
+       and sender by itself.
+       (message-cancel-news, message-supersede): Remove useless things.
+
+2003-06-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el (gnus-summary-force-verify-and-decrypt): Bind
+       `gnus-article-emulate-mime'.
+
+2003-06-15  Tommi Vainikainen  <thv+gnus@iki.fi>
+
+       * message.el (message-is-yours-p): New function.  Separated common
+       code from message-cancel-news and message-supersede.  Added
+       matching code which uses message-alternative-emails regexp as last
+       resort.
+       (message-cancel-news, message-supersede): Use message-is-yours-p.
+
+2003-06-13  Niklas Morberg  <niklas.morberg@axis.com>
+
+       * nnimap.el (nnimap-split-articles): Narrow the right buffer to
+       the headers.
+
+2003-06-12  Dave Love  <fx@gnu.org>
+
+       * nnheader.el (nnheader-functionp): Deleted.
+
+       * nnmail.el (nnmail-split-fancy-syntax-table): Define all in
+       defvar.
+       (nnmail-version): Deleted.
+       (nnmail-check-duplication, nnmail-expiry-target-group): Don't use
+       nnheader-functionp.
+
+2003-06-10  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-check-bogofilter-headers): Fix for when the score
+       is requested but the message is not spam.
+
+2003-06-09  Eric Knauel  <knauel@informatik.uni-tuebingen.de>
+
+       * spam.el (spam-use-spamoracle): New variable.
+       (spam-install-hooks): Add spamoracle to the list of conditions
+       for activation of spam-install-hooks.
+       (spam-spamoracle): New variable customization group.
+       (spam-spamoracle, spam-spamoracle): New variables.
+       (spam-group-spam-processor-spamoracle-p)
+       (spam-group-ham-processor-spamoracle-p): New functions.
+       (spam-summary-prepare-exit): Added spamoracle ham/spam exit processing.
+       (spam-list-of-checks, spam-list-of-statistical-checks): Add
+       spam-use-spamoracle.
+       (spam-check-spamoracle, spam-spamoracle-learn)
+       (spam-spamoracle-learn-ham, spam-spamoracle-learn-spam): New functions.
+
+       * gnus.el (gnus-group-spam-exit-processor-spamoracle)
+       (gnus-group-ham-exit-processor-spamoracle): New variables for SpamOracle.
+       (spam-process, ham-process): Added spamoracle spam/ham processors.
+
+2003-06-08  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-beginning-of-line): Docstring improvement.
+       Suggested by Michael R. Wolf <MichaelRunningWolf@att.net>
+
+2003-06-07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Removed ["Add buttons"
+       gnus-summary-display-buttonized t].
+
+2003-06-07  Kai Großjohann  <kai.grossjohann@gmx.net>
+
+       * nnmail.el (nnmail-split-fancy-match-partial-words): Doc string
+       fix.  Reported by Johan Bockgård <bojohan+news@dd.chalmers.se>.
+
+2003-06-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-beginning-of-line): Docstring improvement.
+
+2003-06-06  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-srvr.el (gnus-browse-foreign-server): Parse garbage NNTP
+       groups correctly.
+
+2003-06-06  Benjamin Rutt  <rutt+news@cis.ohio-state.edu>
+
+       * message.el (message-fetch-field): Augment documentation to state
+       the narrowed-to-headers restriction.
+       (message-change-subject, message-reduce-to-to-cc)
+       (message-generate-unsubscribed-mail-followup-to)
+       (message-insert-importance-high, message-insert-importance-low)
+       (message-insert-or-toggle-importance)
+       (message-insert-disposition-notification-to): Narrow to headers
+       before calling message-fetch-field or message-remove-header.
+
+2003-06-06  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-trim): Fix for when
+       gnus-registry-max-entries is nil.
+
+2003-06-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * qp.el (quoted-printable-decode-region): Don't error out on
+       malformed text.
+
+2003-06-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * rfc2047.el (rfc2047-encode-region): Don't error out on invalid
+       strings.
+
+2003-06-04  Ivan Boldyrev  <boldyrev+nospam@cgitftp.uiggm.nsc.ru>  (tiny change)
+
+       * mml1991.el (mml1991-pgg-sign): Insert pgg output as unibyte.
+
+2003-06-03  Dave Love  <fx@gnu.org>
+
+       * gnus-soup.el (gnus-soup-send-packet): Don't use
+       message-functionp.
+
+       * gnus.el (gnus-agent-cache): Doc fix.
+       (gnus-other-frame): Quote lambda used as hook.
+
+       * message.el: Doc fixes.
+       (message-functionp): Deleted.  Callers changed.
+       (message-fix-before-sending): Highlight with overlays.  Clarify
+       `illegible text' messages.
+       (rmail-enable-mime-composing, gnus-message-group-art): Defvar when
+       compiling.
+       (gnus-find-method-for-group, nnvirtual-find-group-art): Autoload.
+
+2003-06-03  Kai Großjohann  <kai.grossjohann@gmx.net>
+
+       * nnmail.el (nnmail-split-fancy-match-partial-words): New user
+       option.
+       (nnmail-split-it): Obey it.  Don't let-bind regexp twice.
+
+       * message.el (message-fetch-field): Mention narrow-to-headers
+       requirement.
+
+2003-06-03  Eric Eide  <eeide@cs.utah.edu>
+
+       * gnus-xmas.el (gnus-xmas-create-image): Use
+       insert-file-contents-literally.
+
+2003-06-02  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-fetch-group): Always return the
+       short name of the group.
+
+2003-06-02  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-cus.el (defvar): Silence byte-compiler warnings.
+
+       * gnus-sum.el (gnus-get-newsgroup-headers): Unfold headers.
+
+2003-05-31  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (article-unsplit-urls): Use gnus-treat-article
+       rather than gnus-display-mime-function.
+
+2003-05-30  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-use-long-group-names): New variable.
+       (gnus-registry-add-group): Use it.
+       (gnus-registry-trim-articles-without-groups): New variable.
+       (gnus-registry-delete-group): Use it.
+       (gnus-registry-unload-hook): Uninstall all the hooks.
+
+       * spam.el (spam-install-hooks-function, spam-unload-hook): New
+       functions so users that load spam.el for customization don't get
+       all the hooks installed.
+       (spam-install-hooks): New variable, set to t by default if user
+       has one of the spam-use-* variables set.
+
+       * spam-stat.el (spam-stat-install-hooks, spam-stat-unload-hook): New
+       functions so users that load spam-stat.el for customization don't get
+       all the hooks installed.
+
+2003-05-30  Dave Love  <fx@gnu.org>
+
+       * rfc2047.el (rfc2047-decode): Don't use
+       mm-with-unibyte-current-buffer.
+
+       * qp.el (quoted-printable-decode-string): Use
+       mm-with-unibyte-buffer.
+
+2003-05-29  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-save): Allow forced saving even
+       when registry is not dirty.  Use gnus-registry-trim to shorten the
+       gnus-registry-alist.
+       (gnus-registry-max-entries): New variable.
+       (gnus-registry-trim): New function, trim gnus-registry-alist to
+       size gnus-registry-max-entries, sorting by entry mtime so the
+       newest entries stick around.
+
+       * gnus-start.el (gnus-gnus-to-quick-newsrc-format): Instead of
+       just one specific variable, allow a list of specific variables.
+
+2003-05-28  Dave Love  <fx@gnu.org>
+
+       * rfc2047.el (rfc2047-encode-region): Skip ASCII at beginning and
+       end of region.
+
+2003-05-28  Jesper Harder  <harder@ifa.au.dk>
+
+       * lpath.el: Add put-char-table and get-char-table.
+
+2003-05-28  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-dirty): Flag for modified registry.
+       (gnus-registry-save, gnus-registry-read)
+       (gnus-registry-store-extra, gnus-registry-clear): Use it (note
+       that gnus-registry-store-extra is invoked for all modifications to
+       set the mtime, so gnus-registry-dirty only needs to be set there).
+
+2003-05-23  Simon Josefsson  <jas@extundo.com>
+
+       * mml1991.el (mml1991-pgg-sign): Use mml-sender instead of
+       message-sender.
+
+       * gnus-art.el (gnus-use-idna): Check if idna-program is installed.
+
+       * message.el (message-use-idna): Ditto.
+
+2003-05-20  Dave Love  <fx@gnu.org>
+
+       * rfc2047.el (rfc2047-q-encoding-alist): Deleted.
+       (rfc2047-q-encode-region): Don't use it.
+       (rfc2047-encode-message-header) <(eq method 'mime)>: Bind
+       rfc2047-encoding-type to `mime'.
+       (rfc2047-encode-string, rfc2047-encode): Doc fix.
+
+2003-05-20  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-send-mail): Don't insert a courtesy copy
+       notice in base64 encoded messages.
+
+2003-05-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-move-article): Don't copy expirable
+       marks if the destination group is not auto-expirable.
+
+2003-05-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (assq-delete-all): Removed the compiler macro.
+
+2003-05-14  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agentize): Updated documentation to match
+       usage.
+       (gnus-agent-expire-group-1): Do not skip over a group when the
+       force argument is set.
+       * gnus.el (gnus-agent): Updated documentation to reflect that
+       gnus-agent now defaults to t.
+
+2003-05-14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Bump.
+
+2003-05-14  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Gnus v5.10.2 is released.
+
+2003-05-14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-delete-incoming): Changed to t.
+
+       * rfc2047.el (rfc2047-syntax-table): Funcall.
+
+       * lpath.el ((featurep 'xemacs)): Added set-char-table-range.
+       ((featurep 'xemacs)): No, don't.
+
+       * rfc2047.el (rfc2047-encodable-p): Use the header charset.
+
+       * gnus-sum.el (gnus-summary-reselect-current-group): Supply
+       leave-hidden.
+
+2003-05-14  Jonathan I. Kamens  <jik@kamens.brookline.ma.us>
+
+       * gnus-sum.el (gnus-summary-exit): Added `leave-hidden'.  (Tiny
+       patch.)
+
+2003-05-13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-registry.el (gnus-registry-store-extra-entry): Use
+       gnus-assq-delete-all.
+
+       * gnus-xmas.el (gnus-xmas-assq-delete-all): New function.
+
+       * message.el (message-ignored-bounced-headers): Add Delivered-To.
+
+       * gnus-sum.el (gnus-summary-find-next): Indent.
+       (gnus-summary-find-prev): Ditto.
+       (gnus-summary-catchup): Doc fix.
+       (gnus-summary-mark-current-read-and-unread-as-read): New function.
+       (gnus-summary-catchup): Really mark after point.
+
+       * gnus-util.el (gnus-user-date): Use %d instead of %m.
+       (gnus-user-date): Use floating point time so that we don't get
+       overflows.
+
+       * gnus-sum.el (gnus-summary-local-variables): Clean up.
+
+       * gnus-fun.el (gnus-display-x-face-in-from): Don't use centering
+       since none of the other image things do.
+
+2003-05-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (assq-delete-all): New compiler macro for Emacs 20.
+
+2003-05-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind find-coding-system.
+
+       * dgnushack.el (dgnushack-make-load): Remove redundant format call
+       in message.  Suggested by Yoichi NAKAYAMA <yoichi@geiin.org>.
+       * pop3.el (pop3-movemail): Ditto.
+
+2003-05-12  Colin Marquardt  <c.marquardt@alcatel.de>  (tiny change)
+
+       * gnus.el (gnus-agent): Docstring fix.
+
+2003-05-12  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-install): New variable.
+       (gnus-registry-fetch-extra, gnus-registry-fetch-extra-entry)
+       (gnus-registry-store-extra-entry, gnus-registry-delete-group)
+       (gnus-registry-add-group): Add a modification timestamp to each entry.
+       (gnus-registry-install-hooks): New function.
+
+2003-05-12  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-cat-name): Eval macro while compiling.
+       (gnus-agent-cat-disable-undownloaded-faces): New function.
+       Accessor for new agent property
+       'agent-disable-undownloaded-faces'.
+       gnus-cus.el (gnus-agent-parameters): Added
+       agent-disable-undownloaded-faces and corrected documentation.
+       (gnus-agent-cat-prepare-category-field,
+       gnus-agent-customize-category): Changed to avoid creating free
+       references to each field's symbol.
+       gnus-sum.el (gnus-summary-use-undownloaded-faces): New local variable.
+       (gnus-select-newgroup): Initialize it.
+       (gnus-summary-highlight-line): Use it.
+
+2003-05-12  Dave Love  <fx@gnu.org>
+
+       * mm-util.el (mm-read-charset): Deleted.
+       (mm-coding-system-mime-charset): New.
+       (mm-read-coding-system, mm-mule-charset-to-mime-charset)
+       (mm-charset-to-coding-system, mm-mime-charset)
+       (mm-find-mime-charset-region): Use it.
+       (mm-default-multibyte-p): Fix non-mule case.
+
+       * rfc2047.el (rfc2047-point-at-bol, rfc2047-point-at-bol): Eval
+       and compile.
+       (rfc2047-syntax-table): Fix building table to work in Emacs 22.
+       (rfc2047-unfold-region): Delete unused var `leading'.
+
+2003-05-12  Ville Skyttä  <scop@xemacs.org>  (tiny change)
+
+       * pgg.el (pgg-temp-buffer-show-function): Reuse existing visible
+       output window if one is available.
+
+2003-05-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-agent.el (gnus-agent-expire-unagentized-dirs): Added
+       space.
+
+2003-05-11  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-summary-enter-digest-group): Don't do article
+       washing etc.
+       (gnus-handle-ephemeral-exit): Don't reload article after exiting.
+
+       * nndoc.el (nndoc-type-alist): `mime-digest' should be before
+       `mime-parts'.
+
+2003-05-10  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-cite.el (gnus-article-hide-citation-maybe): Make toggling
+       work.  Update mode-line.
+
+2003-05-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-logo-color-alist): Added no colors.
+
+2003-05-09  Dave Love  <fx@gnu.org>
+
+       * utf7.el (mm-util): Require.
+       (utf7-direct-encoding-chars, utf7-imap-direct-encoding-chars):
+       Defconst, not defvar.
+       (utf7-utf-16-coding-system): New.
+       (utf7-encode-internal): Hoist concat out of loop.
+       (utf7-fragment-encode): Use mm-with-unibyte-current-buffer.
+       (utf7-get-u16char-converter) [utf7-utf-16-coding-system]: New
+       case.
+       (utf7-latin1-u16-char-converter): Encode the region.
+       (utf7-u16-latin1-char-converter): Decode the region.
+       (utf7-encode, utf7-decode): Fix multibyteness.
+
+       * mm-bodies.el (mm-body-7-or-8): Don't special-case mule.
+       (mm-encode-body): Use mm-read-coding-system, not mm-read-charset.
+       (mm-uu-yenc-decode-function): Defvar when compiling.
+       (mm-encode-body, mm-decode-body): Doc fix.
+
+2003-05-09  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-unregistered-group-regex):
+       removed in favor of the group/topic/global variables.
+       (gnus-registry-register-message-ids): Fixed test to omit
+       gnus-registry-unregistered-group-regex.
+
+       * gnus.el (gnus-variable-list): Removed gnus-registry-alist and
+       gnus-registry-headers-alist from the list.
+       (gnus-registry-headers-alist): Removed.
+       (registry-ignore): New parameter, with accompanying
+       gnus-registry-ignored-groups global variable.
+
+       * gnus-start.el (gnus-clear-system): No need to clear the
+       registry, we can do it ourselves.
+       (gnus-gnus-to-quick-newsrc-format): Extra parameters so it can be
+       used by gnus-registry.el.
+
+       * gnus-registry.el (gnus-registry-cache-file): New file variable.
+       (gnus-registry-cache-read, gnus-registry-cache-save): New
+       functions.
+       (gnus-registry-save, gnus-registry-read): Use the new
+       gnus-registry-cache-{read|save} functions, and change the name
+       from gnus-registry-translate-{from|to}-alist.
+       (gnus-registry-clear): Fixed so it doesn't refer to old function name.
+
+2003-05-09  Dan Christensen  <jdc@chow.mat.jhu.edu>
+
+       * gnus-registry.el (gnus-registry-cache-whitespace): New function.
+
+2003-05-09  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-picon.el (gnus-picon-transform-address): Parse the encoded
+       address.
+
+2003-05-08  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-start.el (gnus-clear-system): Added gnus-registry-alist to
+       the list of cleared variables.
+
+       * gnus-registry.el (gnus-registry-split-fancy-with-parent):
+       nnmail-split-fancy-with-parent-ignore-groups can be a single regex
+       in addition to a list of regexes.
+
+2003-05-08  Niklas Morberg  <niklas.morberg@axis.com>
+
+       * spam.el (spam-use-regex-headers): Docstring fix.
+
+2003-05-08  Kai Großjohann  <kai.grossjohann@gmx.net>
+
+       * gnus-sum.el (gnus-summary-next-page): Mention
+       `gnus-article-skip-boring' in docstring.
+
+2003-05-08  Jesper Harder  <harder@ifa.au.dk>
+
+       * rfc2231.el (rfc2231-parse-string): "=" should have whitespace
+       syntax here.
+
+       * ietf-drums.el (ietf-drums-syntax-table): "=" should not have
+       whitespace syntax class when parsing email addresses.
+
+       * message.el (message-forward-subject-name-subject): Don't use
+       mail-decode-encoded-word-string before parsing from.
+
+2003-05-07  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-setup-1): Setup alternative email before
+       generate-headers.
+
+       (message-forward-subject-name-subject): Fix the case when the
+       field "from" doesn't exist.
+
+2003-05-07  Dave Love  <fx@gnu.org>
+
+       * rfc2047.el (rfc2047-encode-region): Skip \n as whitespace.
+
+       * mm-util.el (mm-find-mime-charset-region): Expurgate utf-16 from
+       possible values.
+
+2003-05-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-kill-to-signature): Fix.
+
+2003-05-06  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-auto-goto-ignores): Docstring fix.
+
+       * gnus-art.el (gnus-mime-display-multipart-as-mixed)
+       (gnus-mime-display-multipart-related-as-mixed)
+       (gnus-button-mid-or-mail-heuristic-alist): Do.
+
+2003-05-05  Dave Love  <fx@gnu.org>
+
+       * mm-util.el (mm-default-multibyte-p): New.
+       (mm-coding-system-p): Maybe use find-coding-systems.
+
+2003-05-04  Dave Love  <fx@gnu.org>
+
+       * rfc2047.el (with-syntax-table): Define if necessary.
+       (rfc2047-syntax-table): Fix last change for XEmacs.
+       (rfc2047-parse-and-decode): Revert last change.
+
+2003-05-03  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.el: Don't test for `mm-guess-mime-charset'.
+
+       * mm-util.el (mm-guess-mime-charset): Remove.  Not used any more.
+
+       * gnus.el (gnus-default-charset): Set default value to
+       `undecided'.
+
+       * gnus-art.el (article-decode-charset): Don't supply 4th arg to
+       mm-decode-body.
+
+       * mm-bodies.el (mm-decode-coding-region-safely): Remove.
+       (mm-decode-body): Don't use mm-decode-coding-region-safely.
+
+2003-05-03  Vasily Korytov  <deskpot@despammed.com>  (tiny change)
+
+       * gnus-util.el (gnus-multiple-choice): Add ", ?".
+
+2003-05-03  Dave Love  <fx@gnu.org>
+
+       * rfc2047.el (rfc2047-syntax-table): Don't call make-char-table
+       with 2 args.
+       (rfc2047-decode-string): Don't set the buffer multibyte before
+       calling buffer-string.
+
+       * mm-encode.el (mm-long-lines-p): Autoload.
+       (mm-encode-content-transfer-encoding): Doc fix.  Don't make buffer
+       unibyte.  Signal error on unknown encoding.
+       (mm-encode-buffer, mm-qp-or-base64): Doc fix.
+
+       * rfc2047.el (rfc2047-point-at-bol, rfc2047-point-at-eol): New.
+       Callers of gnus- versions changed to use them.
+       (rfc2047-header-encoding-alist): Add `address-mime' part.  Doc
+       fixes.
+       (rfc2047-encoding-type): New.
+       (rfc2047-encode-message-header): Use mm-charset-to-coding-system.
+       Don't include header name field in encoding.  Add `address-mime'
+       case and bind rfc2047-encoding-type for `mime' case.
+       (rfc2047-encodable-p): Deleted.
+       (rfc2047-syntax-table): New.
+       (rfc2047-encode-region, rfc2047-encode): Rewritten to take account
+       of rfc2047 rules with respect to rfc2822 tokens and to do encoding
+       in place rather than by passing strings.
+       (rfc2047-encode-string): Doc fix.
+       (rfc2047-q-encode-region): Don't use
+       mm-with-unibyte-current-buffer.
+       (rfc2047-encoded-word-regexp): eval-and-compile.
+       (rfc2047-decode-region): Avoid concatenation in loop.
+       (rfc2047-parse-and-decode): Remove useless disjunction.
+
+2003-05-02  Dave Love  <fx@gnu.org>
+
+       * rfc2047.el (rfc2047-q-encode-region, rfc2047-decode): Use
+       mm-with-unibyte-current-buffer.
+       (ietf-drums, gnus-util): Don't require.
+
+       * sieve.el (sieve-manage-mode-menu): Define before use.
+
+       * mml-smime.el (message-narrow-to-headers): Autoload.
+
+       * mm-util.el (mm-coding-system-p): Don't override nil from
+       coding-system-p.
+       (mm-mule4-p, mm-disable-multibyte-mule4)
+       (mm-with-unibyte-current-buffer-mule4): Deleted.
+       (mm-multibyte-p): Use defun, not defalias.
+       (mm-make-temp-file): Moved to group at top of file.
+       (mm-point-at-eol, mm-point-at-bol): New.
+
+       * gnus-cite.el (gnus-art): Require.
+
+       * gnus-ems.el (gnus-get-buffer-create)
+       (nnheader-find-etc-directory, message-text-with-property):
+       Autoload.
+       (gnus-tmp-unread, gnus-tmp-replied, gnus-tmp-score-char)
+       (gnus-tmp-indentation, gnus-tmp-opening-bracket, gnus-tmp-lines)
+       (gnus-tmp-name, gnus-tmp-closing-bracket, gnus-tmp-subject-or-nil)
+       (gnus-check-before-posting): Only defvar when compiling.
+
+       * gnus-int.el (gnus-agent-expire): Autoload, don't defun.
+
+       * gnus-util.el (rmail-default-rmail-file, mm-text-coding-system):
+       Defvar when compiling.
+       (gnus-output-to-rmail): Require mm-util.
+
+       * mail-source.el (mail-source-callback): Use mm-make-temp-file.
+       (mail-source-make-complex-temp-name): Deleted.
+
+       * message.el (message-use-idna): Use mm-coding-system-p.
+       (message-tokenize-header, message-make-organization)
+       (message-make-from): Use with-temp-buffer.
+       (message-set-work-buffer): Deleted.
+       (message-fill-paragraph): Use `if' not `and' for compiler warning.
+       (message-check-news-header-syntax): Remove useless lambda.
+       (message-forward-make-body): Use mm-disable-multibyte,
+       mm-with-unibyte-current-buffer, mm-enable-multibyte.
+       (message-replace-chars-in-string): Deleted.
+
+       * mm-extern.el (mm-extern-local-file): Use mm-disable-multibyte.
+       (mm-extern-url): Use mm-with-unibyte-current-buffer,
+       mm-disable-multibyte.
+       (mm-extern-anon-ftp): Use mm-disable-multibyte.
+
+       * mml1991.el (mml1991-mailcrypt-encrypt, mml1991-gpg-encrypt): Use
+       mm-with-unibyte-current-buffer.
+
+       * mml2015.el (mml): Require.
+       (mml2015-mailcrypt-encrypt, mml2015-gpg-encrypt): Use
+       mm-with-unibyte-current-buffer.
+
+       * nnheader.el (gnus-util): Require.
+
+       * nntp.el (format-spec, format-spec-make, open-tls-stream):
+       Autoload.
+
+       * rfc2231.el (mail-header-remove-comments, mm-encode-body)
+       (mail-header-remove-whitespace): Autoload.
+
+       * sieve-manage.el (starttls-negotiate): Autoload.
+
+2003-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnrss.el (nnrss-find-rss-via-syndic8): Indent.
+
+2003-05-01  Mark A. Hershberger  <mah@everybody.org>
+
+       * nnrss.el (nnrss-find-rss-via-syndic8): Don't error out.
+
+2003-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Bump.
+
+2003-05-01  Jon Ericson  <Jon.Ericson@jpl.nasa.gov>  (tiny change)
+
+       * spam-report.el (spam-report-gmane-regex): Docstring fix.
+
+       * gnus.el (gnus-install-group-spam-parameters): Docstring fix.
+
+2003-05-01  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-fetch-extra)
+       (gnus-registry-store-extra, gnus-registry-group-count): New functions.
+       (gnus-registry-fetch-group, gnus-registry-delete-group)
+       (gnus-registry-add-group): Changed to work with extra data element
+       if present.
+
+2003-05-01  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Gnus v5.10.1 is released.
+
+2003-05-01  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.24 is released.
+
+2003-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * dgnushack.el (when): Check whether defadvice is fbound.
+
+2003-05-01  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-unregistered-group-regex):
+       New variable.
+       (gnus-registry-register-message-ids): Use it.
+
+2003-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Bump.
+
+       * gnus.el: Update copyright for several files.
+
+2003-05-01  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.23 is released.
+
+2003-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * spam-stat.el (spam-stat-test-directory): Compare against zero.
+
+2003-05-01  Trey Jackson  <tjackson@ichips.intel.com>  (tiny change)
+
+       * spam-stat.el (spam-stat-test-directory): Skip 0 length files.
+
+2003-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-forward-subject-name-subject): Decode
+       string when forwarding.
+
+2003-05-01  Oystein Viggen  <oysteivi@tihlde.org>
+
+       * dgnushack.el (when): Add defadvice.
+
+2003-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Bump.
+
+2003-05-01  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.22 is released.
+
+2003-05-01  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.21 is released.
+
+2003-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Bump.
+
+2003-05-01  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.20 is released.
+
+2003-05-01  Vasily Korytov  <deskpot@despammed.com>
+
+       * gnus-dired.el (gnus-dired-mode-map): Move to C-c C-l.
+
+2003-04-30  Mark A. Hershberger  <mah@everybody.org>
+
+       * mm-url.el (mm-url-insert-file-contents): Set url-current-object
+       in the case where mm-url-use-external is set.
+
+       * nnrss.el (nnrss-request-article): Change the messages created to
+       multipart/alternative.  Hopefully fixes a problem interaction with
+       w3m.
+       (nnrss-find-rss-via-syndic8): Better handling if xml-rpc.el isn't
+       around.
+
+2003-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-check-news-header-syntax): Alter "posting"
+       message.
+
+       * nnrss.el (nnrss-node-text): Don't use char classes.
+
+2003-05-01  David Z. Maze  <dmaze@mit.edu>
+
+       * nnrss.el (nnrss-find-rss-via-syndic8): Have an `error' branch
+       in condition-case.
+
+2003-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-required-headers): Remove In-Reply-To.
+
+       * gnus-int.el (gnus-open-server): Revert changes.
+
+2003-04-30  Kai Großjohann  <kai.grossjohann@gmx.net>
+
+       * gnus-int.el (gnus-open-server): Try to open unagentized servers
+       even when unplugged.
+
+2003-04-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button-prefer-mid-or-mail): Fixed typo in
+       doc-string.
+
+2003-05-01  Steve Youngs  <youngs@xemacs.org>
+
+       * lpath.el: Add a section for non-Mule XEmacsen.
+       fbind `find-charset-string' and `coding-system-base' in that
+       section.
+
+       * gnus-util.el (gnus-completing-read-maybe-default): New.
+       (gnus-completing-read): Use it.
+
+       * mm-view.el (mm-view-pkcs7-decrypt): Ditto.
+
+       * gnus-art.el (gnus-read-string): New.
+       (gnus-summary-pipe-to-muttprint): Use it.
+
+       * gnus-xmas.el (gnus-xmas-open-network-stream): New.
+
+       * dns.el (dns-make-network-process): Use it.
+
+       Take care of some differences between XEmacs 21.1 and newer
+       versions of XEmacs.
+
+2003-04-30  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-split-fancy-with-parent): Added
+       diagnostic message.
+       (gnus-registry-grep-in-list): Don't run when word is nil.
+       (gnus-registry-fetch-message-id-fast): New function.
+       (gnus-registry-delete-group, gnus-registry-add-group): Make sure
+       the id and group are not nil.
+       (gnus-registry-register-message-ids): New function.
+       (gnus-register-action): Optimized logical flow.
+       (gnus-summary-prepare-hook): Added gnus-registry-register-message-ids.
+
+2003-04-30  Kai Großjohann  <kai.grossjohann@gmx.net>
+
+       * gnus-delay.el (gnus-delay-article): Call
+       `gnus-agent-queue-setup' to create the delay group.
+
+       * gnus-agent.el (gnus-agent-queue-setup): Support optional arg
+       for the (queue) group name.
+
+2003-04-30  Simon Josefsson  <jas@extundo.com>
+
+       * mm-util.el (mm-charset-to-coding-system): Use user specified
+       charset unless coding-system-get is fboundp.
+
+2003-04-30  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-cat-defaccessor, gnus-agent-cat-name):
+       Wrapped in eval-when-compile.
+       (gnus-agent-mode): Bind gnus-agent-go-online to nil as you
+       shouldn't be asked twice to go online with each server.
+       (gnus-agent-get-undownloaded-list, gnus-agent-fetch-articles,
+       gnus-agent-crosspost, gnus-agent-flush-cache,
+       gnus-agent-fetch-session, gnus-agent-unread-articles,
+       gnus-agent-uncached-articles, gnus-agent-regenerate-group,
+       gnus-agent-group-covered-p): Expanded pop macros used for
+       effect.  Avoids compilation warning in emacs 21.3.
+
+       * gnus-int.el (gnus-open-server): Restructured to only open
+       nnagent when gnus-plugged is nil.
+
+2003-04-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind string-to-multibyte.
+
+2003-04-30  Steve Youngs  <youngs@xemacs.org>
+
+       * dgnushack.el: Add some missing autoloads for XEmacs 21.1.
+
+2003-04-29  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-registry-fetch-group): Faster.
+       (gnus-registry-delete-group): New function.
+       (gnus-registry-add-group): New function.
+       (gnus-register-spool-action): Use it.
+       (gnus-register-action): Use it.
+       (gnus-registry-translate-from-alist)
+       (gnus-registry-translate-to-alist): Remove the headers registry
+       for now.
+
+2003-04-29  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button-alist): Fixed CTAN regexp.
+
+2003-04-29  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam-report.el (spam-report-gmane): gnus-summary-article-number
+       is not necessary, just use the function parameter.
+
+2003-04-29  Karl Pflästerer  <sigurd@12move.de>
+
+       * spam-stat.el (spam-stat-save): No longer font-locks the file
+       when saving.
+
+2003-04-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * canlock.el: Bind mail-header-separator when compiling (XEmacs
+       provides it in mail-lib/auto-autoloads.el).
+
+2003-04-29  Simon Josefsson  <jas@extundo.com>
+
+       * mml2015.el (mml2015-pgg-sign): Use mml-sender instead of
+       message-sender.
+
+       * mml.el (mml-generate-mime-1): Set mml-sender too.
+
+2003-04-29  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-summary-display-while-building): Docstring fix.
+
+       * mm-url.el (mm-url-use-external): Do.
+
+2003-04-29  Simon Josefsson  <jas@extundo.com>
+
+       * canlock.el (mail-fetch-field): Autoload it (fix xemacs compile
+       warnings).
+
+       * sieve-mode.el (c-mode): Ditto.
+
+       * pgg.el (run-at-time): Ditto.
+
+       * mm-url.el (require): Require timer when compiling for
+       with-timeout macro (fix xemacs compile warnings).
+
+2003-04-28  Dave Love  <fx@gnu.org>
+
+       * gnus-util.el (nnheader): Don't require.
+       (Nnheader-narrow-to-headers, nnheader-replace-chars-in-string):
+       Autoload.
+
+       * spam.el: Require cl when compiling.
+
+       * dns.el: Require cl when compiling.
+
+2003-04-28  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-article-goto-next-page)
+       (gnus-article-goto-prev-page): Revert 2003-02-12 change to make
+       gnus-pick-mode work.
+
+2003-04-28  Steve Youngs  <youngs@xemacs.org>
+
+       * Makefile.in (FLAGS): Use @FLAGS@.
+
+2003-04-27  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-mime-display-multipart-as-mixed)
+       (gnus-mime-display-multipart-alternative-as-mixed)
+       (gnus-mime-display-multipart-related-as-mixed): Added doc-strings,
+       allow customization.
+
+2003-04-27  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * dgnushack.el (dgnushack-compile-verbosely): New function.
+       Not currently called (See source for explanation).
+
+2003-04-27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-catchup): Don't mark ticked messages.
+       (gnus-summary-mark-read-and-unread-as-read): Take an optional
+       mark.
+
+       * gnus.el (gnus-version-number): Bump.
+
+2003-04-27 06:47:31  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.19 is released.
+
+2003-04-27  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-registry.el (gnus-register-spool-action): Replaced literal
+       carriage-return character with its escape sequence.
+
+2003-04-27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-catchup-from-here): Doc fix.
+
+       * nnrss.el (nnrss-node-text): Use only one
+       gnus-replace-in-string.
+
+       * gnus.el: Remove gnus-functionp throughout.
+
+       * gnus-util.el (gnus-functionp): Removed.
+
+       * gnus-msg.el (gnus-summary-wide-reply-with-original): Doc fix.
+
+       * message.el (message-required-headers): Add In-Reply-To.
+
+2003-04-27  Marshall T. Vandegrift  <vandem2@rpi.edu>
+
+       * gnus-fun.el (gnus-face-from-file): Bind coding-system-for-read
+       to binary.
+
+2003-04-27  Jesper Harder  <harder@ifa.au.dk>
+
+       * mml.el (mml-preview): Do.
+
+       * message.el (message-mode): Do.
+
+       * gnus-undo.el (gnus-undo-mode): Do.
+
+       * gnus-topic.el (gnus-topic-mode): Do.
+
+       * gnus-sum.el (gnus-summary-mode, gnus-summary-edit-article): Do.
+
+       * gnus-msg.el (gnus-setup-message)
+       (gnus-inews-add-send-actions, gnus-configure-posting-styles): Do.
+
+       * gnus-gl.el (gnus-grouplens-mode): Do.
+
+       * gnus-art.el (gnus-mime-save-part-and-strip)
+       (gnus-mime-delete-part): Use it.
+
+       * gnus-util.el (gnus-make-local-hook): New function.
+
+2003-04-25  Simon Josefsson  <jas@extundo.com>
+
+       * nnrss.el (nnrss-node-text): Don't use a star.
+       (nnrss-node-text): Use g-r-i-s, not g-r-r-i-s which doesn't exist.
+
+2003-04-24  Dave Love  <fx@gnu.org>
+
+       * mm-encode.el (mm-long-lines-p): Autoload.
+       (mm-encode-content-transfer-encoding): Don't try to make buffer
+       unibyte before decoding.  Don't ignore errors for base64 encoding.
+
+       * qp.el (quoted-printable-decode-region): Use mm-insert-byte.
+       Signal error on malformed text, as for base64.
+       (quoted-printable-encode-region): DTRT in Emacs 22.
+
+       * mm-util.el (mm-make-temp-file, mm-insert-byte): New.
+       (mm-auto-save-coding-system): Consider utf-8-emacs.
+       (mm-mime-mule-charset-alist, mm-mule-charset-to-mime-charset)
+       (mm-charset-to-coding-system, mm-mime-charset)
+       (mm-find-mime-charset-region): Check for :mime-charset coding
+       systems property.
+
+       * mml-sec.el (mml2015, mml1991): Don't require.
+       (mml2015-sign, mml2015-encrypt, mml1991-sign, mml1991-encrypt)
+       (message-goto-body, mml-insert-tag): Autoload.
+
+       * mm-decode.el (mm-tmp-directory): Re-write to help avoid warnings.
+
+       * gnus-start.el (message-make-date): Autoload rather than
+       requiring message.
+
+       * gnus-group.el (gnus-group-name-charset-group-alist): Use
+       mm-coding-system-p.
+       (gnus-cache-active-altered): Defvar when compiling.
+       (gnus-group-delete-group): Re-write to help avoid warnings.
+
+       * gnus-art.el (gnus-use-idna): Use mm-coding-system-p.
+
+       * pgg.el: Split eval-when-compile forms.
+
+2003-04-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-group.el (gnus-large-ephemeral-newsgroup)
+       (gnus-fetch-old-ephemeral-headers): News variables.
+       (gnus-group-read-ephemeral-group): Use them.
+
+2003-04-24  Simon Josefsson  <jas@extundo.com>
+
+       * sieve.el (sieve-upload): Don't use replace-regexp-in-string.
+
+       * nnrss.el (nnrss-node-text): Ditto.
+
+2003-04-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-inews-do-gcc): Make sure the obsolete variable
+       gnus-inews-mark-gcc-as-read exists.
+
+2003-04-23  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sieve.el (gnus-sieve-generate): Rewrite regexp search so it
+       doesn't exceed the regexp stack space.
+
+2003-04-23  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-msg.el (gnus-inews-mark-gcc-as-read): Don't defvar it.
+
+       * gnus-art.el (gnus-article-hide-pgp-hook): Do.
+
+2003-04-23  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mml.el (mml-preview): Bind `=', RET, and mouse-2.
+
+2003-04-23  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-bodies.el (mm-decode-body): Don't override supplied charset.
+
+2003-04-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (merge, copy-list): Remove compiler macros.
+       (butlast): Add a compiler macro.
+
+2003-04-22  Paul Jarc  <prj@po.cwru.edu>
+
+       * gnus-util.el (gnus-merge): Added "type" argument to match CL
+       merge and gnus-sum.el's expectations.
+
+2003-04-21  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button-url-regexp): Added nntp.
+
+       * message.el (message-generate-headers-first): Default to
+       '(references).
+
+       * gnus-art.el (gnus-mime-delete-part): Require confirmation.
+
+2003-04-21  Jesper Harder  <harder@ifa.au.dk>
+
+       * smime.el (smime-decrypt-region): Insert From header.
+
+2003-04-21  Gaute B Strokkenes  <gs234@cam.ac.uk>  (tiny change)
+
+       * gnus-fun.el (gnus-face-from-file, gnus-convert-png-to-face):
+       Max length of header is 726, not 740.
+
+2003-04-20  Jesper Harder  <harder@ifa.au.dk>
+
+       * nndb.el, mml1991.el: Fix license template.
+
+2003-04-20  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap-split-articles): Don't download body unless
+       required.
+
+       * imap.el (imap-gssapi-open, imap-ssl-open): Erase buffer before
+       starting process, like imap-kerberos4-open does.
+
+       * mml-smime.el, rfc1843.el, dig.el, smime.el, uudecode.el: Fix
+       license template.
+
+       * mml-sec.el: Fix license template.
+
+       * gnus-sieve.el, sieve.el, sieve-manage.el, sieve-mode.el: Fix
+       license template.
+
+       * pgg-def.el, pgg.el, pgg-gpg.el, pgg-parse.el, pgg-pgp5.el,
+       pgg-pgp.el: Fix license template.
+
+2003-04-19  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-summary-delete-article): Improve docstring.
+
+2003-04-19  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-move-spam-nonspam-groups-only): Dumb typo fix.
+
+2003-04-18  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-split): Allow a particular check as a parameter,
+       e.g. (: spam-split 'spam-use-bogofilter).
+       (spam-mark-only-unseen-as-spam): New parameter, see doc.
+       (spam-mark-junk-as-spam-routine): Use
+       spam-mark-only-unseen-as-spam, simplify routine to take advantage
+       of gnus-newsgroup-unread as well as gnus-newsgroup-unseen.
+
+2003-04-17  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.el (gnus-group-short-name, gnus-group-prefixed-p): New functions.
+       (gnus-group-guess-full-name): Don't prefix the group twice.
+
+       * nnmail.el (nnmail-split-fancy-with-parent): Docstring fix.
+
+       * gnus-registry.el (gnus-registry-clear)
+       (gnus-registry-fetch-group, gnus-registry-grep-in-list)
+       (gnus-registry-split-fancy-with-parent): New functions.
+       (gnus-register-spool-action, gnus-register-action): Simplified the
+       format.
+       (gnus-registry): New customization group.
+       (gnus-registry-unfollowed-groups): New variable.
+
+2003-04-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-button-alist): Add nntp: urls.
+       (gnus-header-button-alist): Ditto.
+
+2003-04-17  Dave Love  <fx@gnu.org>
+
+       * gnus-util.el (gnus-string-equal): Revert last change.
+
+2003-04-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-srvr.el (gnus-browse-make-menu-bar): Fix typo.
+
+2003-04-17  Mike Woolley  <mike@ariel.co.uk>
+
+       * gnus-sum.el (gnus-sum-thread-tree-false-root): New variable.
+
+2003-04-15  Michael Shields  <shields@msrl.com>
+
+       * gnus-art.el (article-hide-boring-headers): Hide Reply-To: if
+       the broken-reply-to group parameter is set.  Idea from Vasily
+       Korytov <deskpot@myrealbox.com>.
+
+2003-04-17  Steve Youngs  <youngs@xemacs.org>
+
+       * dgnushack.el: 'setenv' is in env.el for XEmacsen <= 21.4, but in
+       process.el in XEmacsen >= 21.5.
+
+2003-04-17  Steve Youngs  <youngs@xemacs.org>
+
+       * dgnushack.el: Add a whole swag of autoloads and defaliases to
+       satisfy the byte-compiler when building with XEmacs.
+
+       * lpath.el (maybe-bind): Add 'w3-meta-content-type-charset-regexp'
+       and 'w3-meta-charset-content-type-regexp' in XEmacs.  The upstream
+       W3 doesn't have these.
+
+       * mailcap.el: Maybe require 'lpr in XEmacs.
+
+2003-04-16  Simon Josefsson  <jas@extundo.com>
+
+       * mml2015.el (mml2015-pgg-sign): Bind pgg-default-user-id to MML
+       sender tag, if available.
+
+2003-04-16  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-registry.el (gnus-register-action)
+       (gnus-register-spool-action, hashtable-to-alist)
+       (gnus-registry-translate-from-alist, alist-to-hashtable)
+       (gnus-registry-translate-to-alist, gnus-registry-headers-hashtb):
+       new variables and function fixes.
+
+       * gnus.el (gnus-registry-headers-alist): New variable to hold
+       article header data.
+       (gnus-variable-list): Save gnus-registry-headers-alist.
+
+       * spam-report.el (Module): New module for spam reporting.
+
+       * gnus.el (spam-process): Added
+       gnus-group-spam-exit-processor-report-gmane to the list of choices.
+       (gnus-install-group-spam-parameters): Defined new spam exit processor.
+
+       * spam.el (autoload): Autoload spam-report-gmane when needed.
+       (spam-report-gmane-register-routine): Glue for spam-report.el.
+       (spam-group-spam-processor-report-gmane-p): Glue for the
+       gnus-group-spam-exit-processor-report-gmane spam processor.
+       (spam-summary-prepare-exit): Check the report-gmane spam processor
+       and run spam-report-gmane-register-routine if it's active.
+
+2003-04-16  John Wiegley  <johnw@gnu.org>
+
+       * spam.el (spam-bogofilter-score): Check bogofilter headers before
+       checking bogofilter itself.
+
+2003-04-16  Dave Love  <fx@gnu.org>
+
+       * gnus-agent.el: Wrap defsetf in eval-when-compile.
+       (gnus-agent-cat-defaccessor): Don't use gensym.
+
+       * mml1991.el: Require cl, mm-util when compiling.
+       (quoted-printable-decode-region, quoted-printable-encode-region):
+       Autoload.
+
+       * pgg.el: Require cl when compiling.
+
+       * nnmail.el (gnus): Require.
+
+       * gnus-util.el: Move provide to end.
+       (gnus-string-equal): Maybe use compare-strings.
+       (gnus-merge): New.
+
+       * gnus-sum.el (gnus-summary-prepare-threads): Don't use copy-list.
+       (gnus-summary-insert-articles): Use gnus-merge.
+
+       * gnus-fun.el: Require cl and mm-util when compiling.
+
+       * gnus-diary.el (gnus-diary-delay-format-french)
+       (gnus-diary-delay-format-english): Don't use setf with nthcdr.
+
+       * nndiary.el (nndiary-compute-reminders): Don't use setf with
+       nthcdr.
+
+2003-04-16  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-make-cat): Added optional parameter to
+       specify a predicate other than false.
+       (gnus-category-read): Use the new feature to create a 'default'
+       category with a 'short' predicate.
+
+2003-04-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-unique-id): Comment change.
+
+       * gnus-art.el (gnus-article-next-page-1): New function.
+       (gnus-article-next-page): Use it.
+
+2003-04-15  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-split): Added save-restriction to save-excursion.
+
+2003-04-15  Julien Avarre  <julien@avarre.com>
+
+       * gnus-fun.el: Fixed autoload cookie.
+
+2003-04-15  Remi Letot  <remi.letot@easynet.be>
+
+       * nnmaildir.el (nnmaildir-request-scan): Use gnus-remove-if
+       instead of remove-if.
+
+2003-04-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-summary-news-other-window): Use delq and
+       copy-sequence instead of remove which is a cl run-time function in
+       Emacs 20.
+
+2003-04-14  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-msg.el (gnus-summary-news-other-window): Make a buffer
+       local copy of gnus-discouraged-post-methods with the current
+       method removed.
+
+2003-04-14  Simon Josefsson  <jas@extundo.com>
+
+       * mailcap.el (mailcap-mime-data): Add application/pgp-keys.
+
+2003-04-13  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-util.el (mm-sort-coding-systems-predicate): Convert elements
+       of `mm-coding-system-priorities' to base coding system.
+
+       * gnus-sum.el: Added coding cookie ("middle dot" in
+       gnus-summary-morse-message).
+
+2003-04-13  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-art.el (article-fill-long-lines)
+       (article-verify-x-pgp-sig, article-decode-group-name)
+       (gnus-mime-button-menu): Split >80 character lines.
+
+2003-04-13  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-summary-local-variables): Use defvar since
+       we're let-binding it.
+
+       * nnmbox.el (nnmbox-mbox-buffer): It's not a constant.
+
+2003-04-13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-hide-headers): Don't do intangible.
+
+       * gnus.el (gnus-group-prefixed-name): Comment out the test for
+       colon.
+
+       * gnus-srvr.el (gnus-browse-read-group): Don't give the real name
+       to the ephemeral entry, but the prefixed name.
+
+       * gnus.el (gnus-group-prefixed-name): Clean up.
+
+2003-04-13  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-group-pathname): Bind
+       gnus-command-method so that gnus-agent-directory will always
+       return a valid directory.
+       * gnus-cache.el (gnus-cache-enter-article): Remove article from
+       gnus-newsgroup-undownloaded so that the summary will display the
+       article as downloaded.
+       (gnus-cache-remove-article): If the article isn't in the agent,
+       remove it from gnus-newsgroup-undownloaded so that the summary
+       will display the article as undownloaded.
+
+2003-04-13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Bump.
+
+2003-04-13 01:12:01  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.18 is released.
+
+2003-04-13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-draft.el (gnus-draft-send): Add message-hidden-headers.
+
+2003-04-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-next-page): Use
+       gnus-article-over-scroll.
+       (gnus-article-over-scroll): New variable.
+
+       * message.el (message-newline-and-reformat): Place a boundary
+       before filling.
+       (message-make-forward-subject-function): Changed default to
+       message-forward-subject-name-subject.
+       (message-forward-subject-name-subject): New function.
+
+       * nnimap.el (nnimap-split-fancy): Ditto.
+
+       * gnus-sum.el (gnus-summary-line-message-size): Ditto.
+
+       * gnus-cus.el (gnus-group-parameters): Removed "which see".
+
+       * mml.el (mml-minibuffer-read-file): Bind
+       completion-ignored-extensions to nil.
+
+       * message.el (message-fix-before-sending): Comment fix.
+       (message-fix-before-sending): Make hidden headers visible.
+       (message-hide-headers): Bind after-change-functions to nil.
+       (message-forbidden-properties): Put invisible and intangible
+       back.
+       (message-strip-forbidden-properties): Ignore message-hidden text.
+
+       * gnus-msg.el: Hide headers.
+
+       * message.el (message-hidden-headers): New variable.
+       (message-hide-headers): New function.
+       (message-hide-header-p): New function.
+       (message-hide-header-p): Change logic.
+       (message-forbidden-properties): Remove intangible nil invisible
+       nil.
+       (message-hide-headers): Narrow to headers.
+
+       * lpath.el (featurep): Bind Info-directory, Info-menu.
+
+2003-04-12  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-bodies.el (mm-body-charset-encoding-alist): UTF-16 *must* be
+       encoded.
+       (mm-encode-body): Don't corrupt UTF-16.
+       (mm-body-encoding): Pay attention to mm-body-charset-encoding-alist.
+
+2003-04-10  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-get-undownloaded-list): Articles in
+       the CACHE are now detected and handled the same as an article
+       downloaded into the agent.
+       (gnus-agent-group-path): Modified to match nnmail-group-pathname
+       so that the agent front-end and back-end (nnagent) always use the
+       same directory.
+       (gnus-agent-group-pathname): New function.  Wrapper for
+       nnmail-group-pathname.
+       (gnus-agent-expire-unagentized-dirs): New variable.  May be
+       customized to disable gnus-agent-expire-unagentized-dirs.
+       (gnus-agent-expire-unagentized-dirs): Expand gnus-agent-directory
+       as the directories in gnus-agent-expire-current-dirs were
+       expanded.
+
+2003-04-10  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Disable "Encrypt
+       body" entry in read only groups.
+
+2003-04-09  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Disable "Import file"
+       and "Create article" items in non-editable groups.
+
+2003-04-09  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-write-active): Added option of
+       replacing, rather than updating, the agent's active file.  Do NOT
+       use the fully qualified group name as gnus-active-to-gnus-format
+       blindly prefixes group names with server names.
+       (gnus-agent-save-group-info): Merge BOTH min/max of current active
+       range, was just merging min, with specified active range.
+       (gnus-agent-expire): Save agent's active ranges after
+       expiring all groups.
+       (gnus-agent-expire-group-1): Update min of agent's active range to
+       min article currently fetched.
+       (gnus-agent-expire-unagentized-dirs): Avoid asking to delete the
+       same ancestor multiple times.
+
+       * gnus-async.el (gnus-asynchronous): Moved defcustom of
+       gnus-asynchronous away from defgroup of gnus-asynchronous.  This
+       seems to fix an intermittant error in which loading gnus-async
+       fails to define gnus-asynchronous (the variable).
+
+       * gnus-sum.el: Concur with Steve Young, 5th argument to 'load' is
+       non-essential.  Removed on all platforms.
+       (gnus-select-newsgroup): When the agent is active, expand the
+       group's active range to include fetched articles that are no
+       longer in the server's active range.
+
+       * gnus-util.el (gnus-with-output-to-file): Removed all of the
+       print-* bindings as they should be handled by the function doing
+       the printing.
+
+2003-04-09  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-uu.el (mm-uu-copy-to-buffer): Buffer-file-coding-system
+       might be unbound in non-MULE XEmacsen.
+
+2003-04-08  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-uu.el (mm-uu-diff-groups-regexp, mm-uu-type-alist)
+       (mm-uu-diff-extract, mm-uu-diff-test): New functionality:
+       recognize diffs.
+
+       * mm-bodies.el (mm-decode-body): Use the supplied charset
+       unconditionally if `code-pages' hasn't been loaded.
+
+2003-04-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (article-verify-x-pgp-sig): Don't use
+       `insert-buffer', the docstring says "This function is meant for
+       the user to run interactively.  Don't call it from programs!"
+
+       * mm-extern.el (mm-extern-mail-server): Do.
+
+       * mml1991.el (mml1991-mailcrypt-sign, mml1991-mailcrypt-sign)
+       (mml1991-gpg-sign, mml1991-gpg-encrypt, mml1991-pgg-sign)
+       (mml1991-pgg-encrypt): Do.
+
+       * pgg.el (pgg-decrypt-region): Do.
+
+       * mm-view.el (mm-view-pkcs7-decrypt): Do.
+
+       * mml-smime.el (mml-smime-verify): Do.
+
+       * mml.el (mml-insert-mime, mml-preview): Do.
+
+       * mml2015.el (mml2015-gpg-decrypt-1, mml2015-gpg-sign)
+       (mml2015-gpg-encrypt, mml2015-pgg-clear-decrypt)
+       (mml2015-pgg-encrypt): Do.
+
+2003-04-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-bodies.el (mm-decode-body): Silence XEmacs when compiling.
+
+2003-04-06  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-uu.el (mm-uu-copy-to-buffer): Copy
+       `buffer-file-coding-system' to the new buffer.
+       (mm-uu-pgp-signed-extract-1): Don't copy
+       `buffer-file-coding-system' here.
+
+       * mm-bodies.el (mm-decode-body): last-coding-system-used doesn't
+       exist in XEmacs.
+       (mm-decode-body): Add missing quote.
+
+       * mm-uu.el (mm-uu-pgp-signed-extract-1): Set
+       buffer-file-coding-system.
+
+       * mm-bodies.el (mm-decode-body): Set buffer-file-coding-system to
+       last-coding-system-used.
+
+       * mml2015.el (mml2015-pgg-clear-verify): Encode the text
+       according to buffer-file-coding-system.
+
+       * pgg-gpg.el (pgg-gpg-process-region): Revert previous change.
+
+       * pgg-pgp.el (pgg-pgp-process-region, pgg-pgp-verify-region)
+       (pgg-pgp-snarf-keys-region): Do.
+
+       * pgg-pgp5.el (pgg-pgp5-verify-region)
+       (pgg-pgp5-snarf-keys-region, pgg-pgp5-process-region): Do.
+
+       * pgg.el (pgg-make-temp-file, pgg-temporary-file-directory): Do.
+
+2003-04-05  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-split): (save-excursion) around (widen).
+       (spam-ham-move-routine): Use spam-group-ham-mark-p, not
+       spam-group-spam-mark-p (from Michael Shields <shields@msrl.com>).
+
+2003-04-05  Steve Youngs  <youngs@xemacs.org>
+
+       * gnus-sum.el: XEmacs doesn't support the 5th arg to 'load', so
+       don't use it when loading gnus-sum.el if we're in XEmacs.
+
+2003-04-05  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-start.el (gnus-gnus-to-quick-newsrc-format): Bound
+       print-escape-nonascii to fix more characters in compiled format
+       specs.
+
+2003-04-05  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-audio.el (gnus-audio-au-player, gnus-audio-wav-player):
+       Fix customization type.
+
+2003-04-04  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-start.el (gnus-gnus-to-quick-newsrc-format): Bound
+       print-quoted, print-readably, print-escape-multibyte, and
+       print-level to match original behavior of gnus-prin1.  This should
+       repair the format of .newsrc.eld when using compiled format specs.
+
+2003-04-04  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-group.el (tool-bar-map): defvar it.
+
+       * gnus-art.el (tool-bar-map): Do.
+
+       * gnus-sum.el (tool-bar-map): Do.
+
+2003-04-03  Jesper Harder  <harder@ifa.au.dk>
+
+       * earcon.el (earcon-regexp-alist): catmeow is a wav file.
+
+2003-04-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button-ctan-directory-regexp): Changed meaning
+       and value.
+       (gnus-button-alist): Use it.
+
+2003-04-03  Jesper Harder  <harder@ifa.au.dk>
+
+       * pgg-gpg.el (pgg-gpg-process-region): Do.
+
+       * pgg-pgp.el (pgg-pgp-process-region, pgg-pgp-verify-region)
+       (pgg-pgp-snarf-keys-region): Do.
+
+       * pgg-pgp5.el (pgg-pgp5-verify-region)
+       (pgg-pgp5-snarf-keys-region, pgg-pgp5-process-region): Use it.
+
+       * pgg.el (pgg-make-temp-file): New function.  `make-temp-name' is
+       unsafe.
+       (pgg-temporary-file-directory): Remove.
+
+2003-04-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind Info-directory and Info-menu.
+
+2003-04-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-util.el (gnus-message): Added doc-string.
+
+       * gnus-score.el (gnus-score-find-trace): Changed behavior of `q'.
+       (gnus-score-edit-file-at-point): Goto first match when using `e'.
+
+2003-04-01  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button-ctan-directory-regexp): New variable.
+       (gnus-button-alist): Use it.  Changed CTAN and "setq" entries.
+
+2003-04-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nntp.el (nntp-via-rlogin-command-switches): Doc fix.
+       (nntp-open-via-rlogin-and-telnet): Disable the telnet linemode.
+
+2003-03-31  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-start.el (gnus-gnus-to-quick-newsrc-format): Bound
+       print-escape-newlines to print escape sequences rather than
+       literal newline characters.
+
+2003-03-31  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button-valid-fqdn-regexp): Use
+       `message-valid-fqdn-regexp' for initialization.
+       (gnus-button-handle-info-url): Renamed and extended version of
+       `gnus-button-handle-info'.
+       (gnus-button-message-level): Renamed from `gnus-button-mail-level'.
+       (gnus-button-handle-symbol, gnus-button-handle-library)
+       (gnus-button-handle-info-keystrokes): New functions.
+       (gnus-button-browse-level): New variable.
+       (gnus-button-alist): Use them.  Added levels.
+       (gnus-header-button-alist): Added levels.
+
+2003-03-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Bump.
+
+2003-03-31 20:08:19  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.17 is released.
+
+2003-03-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-unload): Removed.
+
+       * pop3.el (pop3-read-response): Use
+       nnheader-accept-process-output.
+       (pop3-retr): Ditto.
+
+       * mm-view.el (mm-text-html-renderer-alist): Add -nolist to Lynx.
+       (mm-text-html-washer-alist): Ditto.
+
+2003-03-31  Simon Josefsson  <jas@extundo.com>
+
+       * imap.el (imap-gssapi-program): Also try GNU SASL.
+       (imap-gssapi-open): Accept GNU SASL greeting.
+       (imap-read-timeout): New.
+       (imap-wait-for-tag): Use it.
+
+2003-03-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nntp.el (nntp-accept-process-output): Use new function.
+
+       * nnheader.el (nnheader-read-timeout): New variable.
+       (nnheader-accept-process-output): New function.
+
+       * nntp.el (nntp-read-timeout): Removed.
+
+       * gnus-sum.el (gnus-summary-prepare-threads): Add comment.
+
+2003-03-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-cache.el (gnus-cache-braid-nov): Revoke last change.
+
+2003-03-30  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-idna-inside-rhs-p): Narrow to header before
+       searching.
+
+       * gnus-art.el (article-decode-idna-rhs): More restrictive regexp.
+
+2003-03-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnmail.el (nnmail-process-mmdf-mail-format): Indent.
+
+2003-03-28  Vasily Korytov  <deskpot@myrealbox.com>
+
+       * message.el (message-make-in-reply-to): Use
+       mail-extract-address-components to determine sender's
+       name/address.
+
+2003-03-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nndoc.el (nndoc-type-alist): Move mime-parts further ahead.
+
+       * gnus-registry.el (gnus-registry-translate-to-alist): Make a
+       valid lambda.
+       (gnus-registry-translate-from-alist): Ditto.
+
+       * gnus-start.el (gnus-gnus-to-quick-newsrc-format): Bind
+       print-length to nil.
+
+       * gnus-sum.el (gnus-summary-highlight-line-0): Indent.
+
+       * gnus-fun.el (gnus-fun-ppm-change-string): New function.
+       (gnus-grab-cam-face): Use it.
+
+2003-03-28  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir-request-set-mark)
+       (nnmaildir-close-group): Allow each mark directory in a group to
+       have its own inode for mark files, to accommodate AFS.
+
+2003-03-28  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-start.el (gnus-read-newsrc-el-hook): New hook called by
+       gnus-read-newsrc-el-file.
+       (gnus-read-newsrc-el-file): Call the gnus-read-newsrc-el-hook.
+
+       * gnus-registry.el (gnus-registry-translate-to-alist)
+       (gnus-registry-translate-from-alist): New functions.
+       (gnus-register-spool-action): Add a spool item to the registry.
+
+       * gnus.el (gnus-variable-list): Added gnus-registry-alist to the
+       list of saved variables.
+       (gnus-registry-alist): New variable.
+
+2003-03-28  Andreas Fuchs  <asf@void.at>
+
+       * gnus-registry.el (alist-to-hashtable, hashtable-to-alist): New
+       functions.
+
+2003-03-27  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-art.el (article-decode-group-name): Be correct instead of
+       smart.
+
+2003-03-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Bind url-current-object for Emacs; bind
+       gnus-agent-expire-current-dirs for XEmacs; fbind open-ssl-stream
+       for both Emacsen.
+
+2003-03-27  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-article-loose-mime)
+       (gnus-article-emulate-mime): Move to gnus-article-mime customize
+       group.
+
+       * gnus-msg.el (gnus-mailing-list-groups): Fix customize type and
+       doc string.
+
+2003-03-26  Kevin Ryde  <user42@zip.com.au>
+
+       * gnus-sum.el (gnus-summary-find-for-reselect): Renamed from
+       gnus-summary-find-uncancelled, skip temporary articles inserted by
+       "refer" functions.
+
+2003-03-26  Vasily Korytov  <deskpot@myrealbox.com>
+
+       * smiley.el (smiley-buffer): New function.
+
+2003-03-26  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-fetch-selected-article): Replaced
+       gnus-summary-update-line (which updated the article's face) with
+       gnus-summary-update-download-mark (which updates the article's
+       face by calling gnus-summary-update-line AND updates the download
+       mark to show that the article was fetched).
+
+2003-03-23  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-expire-unagentized-dirs): Provides
+       option of deleting agent directories for groups/servers that are
+       not currently agentized.
+       (gnus-agent-expire): Use gnus-agent-expire-unagentized-dirs.
+
+       * gnus-int.el (gnus-open-server): Report backend errors in
+       condition handler.
+
+2003-03-23  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-idna-to-ascii-rhs-1): Don't continue outside
+       header.
+
+       * rfc2047.el (rfc2047-header-encoding-alist): Make Followup-To
+       same as Newsgroups.
+
+       * nntp.el (nntp-open-connection-function): Mention
+       nntp-open-tls-stream.
+       (nntp-open-tls-stream): New function.
+
+       * tls.el: New file.
+
+       * nnimap.el (nnimap-server-port, nnimap-stream): Say TLS/SSL
+       instead of SSL.
+       (nnimap-stream): Add other streams, link to imap variables.
+       (nnimap-authenticator): Add other authenticator, link to imap
+       variables.
+
+       * imap.el: Autoload open-tls-stream.
+       (imap-streams): Add tls in front of ssl.
+       (imap-stream-alist): Add tls.
+       (imap-default-tls-port): New variable.
+       (imap-tls-p, imap-tls-open): New functions.
+
+2003-03-22  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-url.el (mm-url-insert-file-contents): Parse url only if
+       results is a list.
+
+2003-03-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-fetch-imap): Revert.
+
+2003-03-22  Svend Tollak Munkejord  <stm@bacchus.pvv.org>
+
+       * deuglify.el (gnus-outlook-repair-attribution-outlook): Use a
+       less strict regexp.
+
+2003-03-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-fetch-imap): Use buffer name for
+       more imap function.
+
+2003-03-21  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-art.el (article-decode-group-name): Replace Newsgroups and
+       Followup-To data inline.
+
+2003-03-21  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-treat-display-xface): Don't enable if
+       icontopbm isn't available.
+
+2003-03-21  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-int.el (gnus-open-server): Catch errors in backend's
+       open-server method.  Returns nil rather than crashing startup.
+
+       * gnus-sum.el (eval-when-compile): Modified to resolve
+       compile-time warnings.
+
+       * gnus-uu.el (gnus-uu-mark-series): Added informative msg.
+       Reports length of series so that the user can compare N with a
+       subject that should, if the entire series is present, contain
+       '(.../N)'.
+       (gnus-uu-delete-work-dir): Avoid hanging when O/S forbids deletion
+       of temp file (Win-XP may leave the temp file locked when the
+       uudecode process fails).
+
+2003-03-20  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-split-line): Ignore error.
+
+       * lpath.el (split-line): Avoid split-line warning message.
+
+2003-03-20  Kim F. Storm  <storm@cua.dk>
+
+       * message.el (message-split-line): New function.
+       (message-mode-map): Remap split-line to message-split-line.
+
+2003-03-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-make-overlay): Defalias it to make-overlay.
+       (message-delete-overlay): Defalias it to delete-overlay.
+       (message-overlay-put): Defalias it to overlay-put.
+       (message-idna-to-ascii-rhs-1): Use them.
+
+       * messagexmas.el (message-xmas-redefine): Defalias some overlay
+       functions to extent functions.
+
+2003-03-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-check-news-header-syntax): Fixed regexp.
+
+2003-03-20  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2231.el (rfc2231-decode-encoded-string): Downcase charset.
+
+       * mm-url.el (mm-url-insert): Move url-current-object stuff into
+       mm-url-insert-file-contents.
+
+       * nnrss.el (nnrss-fetch): Fetch the local stuff.
+       (nnrss-check-group): Use it.
+
+2003-03-20  Mark A. Hershberger  <mah@everybody.org>
+
+       * nnrss.el: Primitive XML Name-space support.  This means that RSS
+       feeds like Kevin Burton's[1] can now be read in Gnus.
+
+       Implemented support for Mark Pilgrim's RSS Autodiscovery.[2] This
+       means that if you want to read the RSS feed for example.com, all
+       you have to do is hit "G R http://www.example.com/ RET" and
+       nnrss.el will find and the feed listed on the site or (if you have
+       loaded xml-rpc.el) look it up on syndic8.com.
+
+       Marked the message as HTML (by adding a Content-Type header) so
+       that Gnus will render it as html if the user wants that.
+
+       Implemented the ability to save nnrss-group-alist so that any new
+       feeds you subscribe to will be found the next time you start up.
+
+       Implemented support for RSS 2.0 elements (author, pubDate).
+
+       Prefer for <content:encoded> over <description> where both
+       elements exist.
+
+       * mm-url.el (mm-url-insert): Set url-current-object.
+
+       * gnus-group.el (gnus-group-make-rss-group): New function.
+
+2003-03-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-idna-to-ascii-rhs-1): Don't use replace-*
+       for highlight overlays.
+
+2003-03-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-cache.el (gnus-cache-braid-nov): Test if a line looks like
+       a NOV.
+
+2003-03-20  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-use-idna): Disable if UTF-8 unavailable.
+       (message-idna-to-ascii-rhs): Use it.
+
+       * gnus-art.el (gnus-use-idna): Disable if UTF-8 unavailable.
+
+2003-03-19  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-group-ham-mark-p, spam-group-spam-mark-p)
+       (spam-group-ham-marks, spam-group-spam-marks): New functions.
+       (spam-spam-marks, spam-ham-marks): Removed in favor of the
+       spam-marks and ham-marks parameters.
+       (spam-generic-register-routine, spam-ham-move-routine): Use the
+       new spam-group-{spam,ham}-mark-p functions.
+
+       * gnus.el (spam-marks, ham-marks): New group parameters with
+       default values same as the old spam-spam-marks and spam-ham-marks.
+
+2003-03-19  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-art.el (gnus-article-decode-hook): Add IDNA.
+       (gnus-use-idna): New variable.
+       (article-decode-idna-rhs): New function.
+
+       * message.el (message-use-idna): New variable.
+       (message-mode-field-menu): Add entry for IDNA.
+       (message-idna-inside-rhs-p, message-idna-to-ascii-rhs-1)
+       (message-idna-to-ascii-rhs): New function.
+       (message-generate-headers): Invoke IDNA code.
+
+2003-03-19  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir--system-name): New function.
+       (nnmaildir-request-accept-article): Use it.
+
+2003-03-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-byte-compile): Make it work silently as the
+       gnus-compile function does.
+
+       * gnus-sum.el (gnus-summary-highlight-line-0): Revoke the last
+       bogus change.
+
+2003-03-19  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-util.el (mm-mule-charset-to-mime-charset): Test if
+       sort-coding-systems is defined.
+
+2003-03-18  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir-open-server, nnmaildir-request-scan)
+       (nnmaildir-request-create-group, nnmaildir-request-delete-group):
+       Replace create-directory with target-prefix.
+
+2003-03-18  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-bodies.el (mm-decode-coding-region-safely): Don't use
+       find-charset-string which is slooow in XEmacs.
+
+2003-03-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-highlight-line-0): Silence the byte-
+       compiler under XEmacs.
+
+2003-03-18  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-treat-highlight-signature): Make the default
+       work for multipart/signed where the message text isn't `last'.
+
+2003-03-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-view.el (mm-setup-w3m): Set w3m-display-inline-images to
+       the value of mm-inline-text-html-with-images.
+       (mm-inline-text-html-render-with-w3m): Don't bind
+       w3m-display-inline-images.
+
+       * gnus-art.el (gnus-article-wash-html-with-w3m): Don't bind
+       w3m-display-inline-images.
+
+       * lpath.el: Bind w3m-display-inline-images; bind mm-w3m-mode-map
+       regardless of an Emacs flavor.
+
+2003-03-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Bump.
+
+2003-03-18 00:38:22  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.16 is released.
+
+2003-03-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * lpath.el (featurep): Bind mm-w3m-mode-map.
+
+2003-03-17  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmail.el (nnmail-cache-primary-mail-backend): Not all
+       'respool-able backends define a global nnchoke-get-new-mail
+       variable.
+
+2003-03-17  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-mime-delete-part): New function.
+       (gnus-mime-action-alist, gnus-mime-button-commands): Use it.
+
+2003-03-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-check-news-header-syntax): Don't push
+       groups twice onto list of unknown groups.
+
+       * nndoc.el (nndoc-type-alist): Move exim-bounce a bit further
+       back.
+
+       * nnheader.el (nnheader-find-etc-directory): Doc fix.
+
+       * gnus-msg.el (gnus-inews-add-send-actions): Don't restore window
+       config unless the summary buffer exists.
+
+       * gnus-sum.el (gnus-summary-next-group): Semi-exit group first to
+       that target group is computed correctly when articles are marked
+       as read by Xref handling.
+
+       * mail-source.el (mail-source-fetch-imap): Pass buffer-name to
+       imap-open.
+
+       * message.el (message-send-mail): Add courtesy string to Bcc's,
+       too.
+
+       * gnus-cite.el (gnus-cited-line-p): New function.
+
+2003-03-15  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-bodies.el (mm-decode-body): Add new optional parameter,
+       force, to use the supplied charset unconditionally.
+
+       * gnus-art.el (article-decode-charset): Use it.
+
+2003-03-14  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-bodies.el (mm-decode-coding-region-safely): New function.
+       (mm-decode-body): Use it.
+
+       * rfc2047.el (rfc2047-decode-region): Do.
+       (rfc2047-decode-string): Guess coding system if the default is
+       invalid.
+
+2003-03-12  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir-request-update-info): Pretend missing
+       articles are marked 'read, so we get correct article counts.
+
+2003-03-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-insert-mime-button): Exclude a newline from
+       the button.
+       (gnus-insert-prev-page-button): Ditto.
+       (gnus-insert-next-page-button): Ditto.
+       (gnus-insert-mime-security-button): Ditto.
+
+       * mm-view.el (mm-inline-image-emacs): Open the bottom of an image
+       one line.  Suggested by Greg Klanderman <gak@klanderman.net>.
+       (mm-inline-image-xemacs): Ditto.
+
+2003-03-12  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir--parse-filename, nnmaildir--sort-files,
+       nnmaildir--scan, nnmaildir-request-accept-article): Changes for
+       the recent filename uniqueness discussion.
+
+2003-03-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-view.el (mm-inline-image-emacs): Make it delete an excessive
+       newline next time.
+       (mm-inline-image-xemacs): Ditto.
+
+2003-03-10  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-agent.el (gnus-agent-synchronize-flags-server): Don't use
+       kill-line.
+
+2003-03-09  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-msg.el (gnus-inews-insert-archive-gcc): Don't use
+       kill-line.
+
+2003-03-09  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-fetched-hook): New variable.  Just
+       fixing the code to match the documentation.
+       (gnus-agent-fetch-selected-article): Replaced
+       gnus-summary-update-article-line with gnus-summary-update-line as
+       the former did not correctly recalculate the thread indentation.
+       (gnus-agent-find-parameter): The agent-predicate, if not found
+       anywhere else, defaults to the value of gnus-agent-predicate.
+       (gnus-agent-fetch-session): Fixed typo; now executes
+       gnus-agent-fetched-hook rather than the undocumented
+       gnus-agent-fetch-hook.
+       (gnus-agent-fetch-group-1): Removed part of 2003-03-06 fix.  The
+       default agent predicate is now provided by
+       gnus-agent-find-parameter.
+       (gnus-agent-message): New macro.  This macro avoids potentially
+       costly parameter evaluation when the message's level is too high
+       to display.
+       (gnus-agent-expire-group-1): Disabled undo tracking in temp
+       overview buffer.  Uses new gnus-agent-message macro to reduce
+       overhead of optional messages.  Reversed message levels to
+       emphasize percent completion messages.  Detailed messages of
+       little use except when debugging code.
+
+2003-03-08  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-ham-move-routine): Use
+       spam-mark-ham-unread-before-move-from-spam-group.
+       (spam-mark-ham-unread-before-move-from-spam-group): New variable.
+
+2003-03-07  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el: Load nnimap.el when compiling.
+       (spam-setup-widening): Use nnimap-split-download-body-default instead
+       of nnimap-split-download-body which is a user-customizable variable.
+
+2003-03-07  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap-split-download-body-default): New, holds
+       default for n-s-d-b.
+       (nnimap-split-download-body): Add new setting (symbol default),
+       which uses contents of n-s-d-b-d, and made it the default.
+
+2003-03-07  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-use-hashcash): New variable.
+       (spam-list-of-checks): Added spam-use-hashcash with associated
+       spam-check-hashcash.
+       (spam-check-hashcash): New function, installed iff hashcash.el is
+       loaded.
+       (spam-setup-widening): Don't use (return).
+
+2003-03-06  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-fetch-group-1): Added default
+       predicate of `false' to avoid an error when a group defines no
+       predicate.  Fixed typo that disabled agent scoring (i.e. the
+       low/high predicates should now work).
+
+2003-03-06  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el: Add spam-maybe-spam-stat-load to
+       gnus-get-top-new-news-hook, remove it from gnus-get-new-news-hook.
+       (spam-bogofilter-register-with-bogofilter): Use
+       spam-bogofilter-spam-switch and spam-bogofilter-ham-switch.
+       (spam-bogofilter-spam-switch, spam-bogofilter-ham-switch): New
+       custom variables to replace "-s" and "-n".
+
+       * gnus-group.el (gnus-group-get-new-news): Call the new
+       gnus-get-top-new-news-hook hook.
+
+       * gnus-start.el (gnus-get-top-new-news-hook): New hook, run ONLY
+       by gnus-get-new-news, NOT by gnus-group-get-new-news-this-group.
+
+2003-03-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-uu.el (mm-uu-pgp-encrypted-test): Fix message.
+
+2003-03-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-cus.el (gnus-group-customize): Don't use delete-if which is
+       a cl run-time function.
+
+2003-03-06  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-fetch-group-1): Added missing binding
+       on gnus-agent-short-article.
+       (gnus-category-read): Replaced CL function mapcar* with new macro:
+       gnus-mapcar.
+       * gnus-util.el (gnus-mapcar): New macro.  Generalizes mapcar to
+       support functions that accept multiple parameters.  A separate
+       sequence must be provided for each parameter in the function.
+       Iteration stops when the end of the shortest list is reached.
+
+2003-03-06  Jesper Harder  <harder@ifa.au.dk>
+
+       * nnimap.el (nnimap-request-accept-article): Use delete-region.
+
+       * html2text.el (html2text-clean-dtdd, html2text-delete-tags)
+       (html2text-delete-single-tag, html2text-clean-anchor)
+       (html2text-remove-tags): Use delete-region.
+       (html2text-fix-paragraphs): Simplify.
+
+       * mml1991.el (mml1991-mailcrypt-sign, mml1991-mailcrypt-encrypt)
+       (mml1991-gpg-sign, mml1991-gpg-encrypt, mml1991-pgg-sign)
+       (mml1991-pgg-encrypt, mml1991-pgg-encrypt): Use delete-region, not
+       kill-region.
+
+2003-03-04  John Paul Wallington  <jpw@gnu.org>
+
+       * gnus-agent.el (gnus-agent-enable-expiration)
+       (gnus-agent-article-alist, gnus-agent-article-alist)
+       (gnus-agent-cat-defaccessor): Doc fixes.
+
+2003-03-04  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus-agent.el (gnus-function-implies-unread-1): Grok
+       byte-compiled functions.
+
+2003-03-04  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-sum.el (gnus-auto-goto-ignores): New variable.  Provides
+       customization between new maneuvering (which permits selecting
+       undownloaded articles) and old maneuvering (which skipped over
+       undownloaded articles) behaviors.
+       (gnus-summary-find-next): Pass through the unread and subject
+       parameters when calling gnus-summary-find-prev.
+       (gnus-summary-find-next, gnus-summary-find-prev): Apply
+       gnus-auto-goto-ignores to filter out unacceptable articles.
+
+2003-03-04  Jesper Harder  <harder@ifa.au.dk>
+
+       * mail-source.el (mail-source-read-passwd): Remove.  `read-passwd'
+       exists in all supported Emacs versions, so we don't need this
+       compatibility function.
+       (mail-source-fetch-pop, mail-source-check-pop)
+       (mail-source-fetch-webmail): Use read-passwd.
+
+       * nntp.el (nntp-send-authinfo, nntp-send-nosy-authinfo)
+       (nntp-open-telnet, nntp-open-via-telnet-and-telnet): Use
+       read-passwd.
+
+       * nnwarchive.el (nnwarchive-open-server): Use read-passwd.
+
+       * imap.el (imap-read-passwd): Remove.
+       (imap-interactive-login): Use read-passwd.
+
+       * canlock.el (canlock-read-passwd): Remove.
+       (canlock-insert-header, canlock-verify): Use read-passwd.
+
+       * sieve-manage.el (sieve-manage-read-passwd): Remove.
+       (sieve-manage-interactive-login): Use read-passwd.
+
+       * pop3.el (pop3-read-passwd): Remove.
+       (pop3-movemail, pop3-get-message-count, pop3-apop): Use
+       read-passwd.
+
+       * pgg.el (pgg-read-passphrase): Simplify.
+
+2003-03-04  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-mode): Fixed the mode line reports
+       'plugged' when actually 'unplugged' bug.
+       (gnus-category-read): Ignore nil values when converting an
+       old-format category so that the new-format category will default
+       those attributes to the global variables.
+
+2003-03-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mail-source.el (mail-source-delete-old-incoming-confirm): Fixed
+       doc-string.
+
+2003-03-03  Jesper Harder  <harder@ifa.au.dk>
+
+       * nnrss.el (nnrss-decode-entities-unibyte-string): Use `buffer-string'.
+       * nndoc.el (nndoc-dissect-mime-parts-sub): Do.
+       * nndb.el (nndb-request-accept-article, nndb-status-message): Do.
+       * mm-url.el (mm-url-decode-entities-string): Do.
+       * mml1991.el (mml1991-mailcrypt-sign, mml1991-gpg-sign): Do.
+       * mm-decode.el (mm-find-raw-part-by-type): Do.
+       * message.el (message-send-mail-partially)
+       (message-send-mail-with-sendmail): Do.
+       * gnus-uu.el (gnus-uu-save-article, gnus-uu-reginize-string): Do.
+       * gnus-kill.el (gnus-pp-gnus-kill): Do.
+       * gnus-art.el (gnus-article-treat-unfold-headers)
+       (gnus-article-encrypt-body): Do.
+
+2003-02-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mail-source.el (mail-source-delete-incoming): Allow integer value.
+       (mail-source-delete-old-incoming-confirm): New variable.
+       (mail-source-delete-old-incoming): Use it.  New function.
+       (mail-source-callback): Call `mail-source-delete-old-incoming' if
+       `mail-source-delete-incoming' is a nonnegative integer.
+
+2003-03-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-msg.el (gnus-extended-version): Fix for 'emacs-gnus-config.
+       (gnus-user-agent): Fixed typo.
+
+2003-03-03  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-enable-expiration): Fixed documentation.
+       (gnus-agent-expire-group-1): Removed invalid (interactive) specifier.
+
+2003-03-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-agent.el (gnus-agent-fetch-articles): Fix nil message.
+       (gnus-agent-fetch-session): Allow debugging to take place.
+
+2003-03-03  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-highlight-selected-summary)
+       (gnus-article-get-xrefs, gnus-summary-show-thread): Use
+       `gnus-point-at-bol' and `gnus-point-at-eol' instead of
+       `(progn (beginning-of-line) (point))'.  It's shorter, faster,
+       and makes it clear that we don't need the side effect.
+       * gnus-util.el (gnus-delete-line): Do.
+       * gnus-xmas.el (gnus-group-add-icon): Do.
+       * nnmail.el (nnmail-article-group, nnmail-cache-fetch-group): Do.
+       * nntp.el (nntp-send-authinfo-from-file): Do.
+       * nnml.el (nnml-header-value): Do.
+       * nnheader.el (nnheader-insert-references): Do.
+       * gnus-cite.el (gnus-article-highlight-citation)
+       (gnus-cite-parse): Do.
+       * gnus-score.el (gnus-score-followup): Do.
+       * gnus-draft.el (gnus-draft-send): Do.
+       * gnus-group.el (gnus-group-highlight-line): Do.
+       * gnus-cache.el (gnus-cache-braid-nov): Do.
+       * nnfolder.el (nnfolder-retrieve-headers)
+       (nnfolder-request-article): Do.
+       * gnus-art.el (article-hide-boring-headers)
+       (gnus-article-hide-header): Do.
+
+       * nnheader.el (nnheader-find-nov-line): Use gnus-delete-line.
+       * nnml.el (nnml-request-replace-article): Do.
+       * nnmbox.el (nnmbox-request-move-article, nnmbox-delete-mail): Do.
+       * nnfolder.el (nnfolder-request-move-article): Do.
+       * gnus-cache.el (gnus-cache-possibly-remove-article): Do.
+       * gnus-art.el (gnus-mm-display-part): Do.
+
+       * gnus-art.el (gnus-article-goto-part): Use gnus-goto-char.
+
+2003-03-02  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * nntp.el (nntp-possibly-change-group): Avoid calling
+       process-buffer on nil (Which happened when you lost your
+       connection while fetching); instead signal a "Server Closed
+       Connection" error.
+
+2003-03-02  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-enable-expiration): New
+       variable.  Either ENABLE or DISABLE.  Sets default behavior for
+       selecting which groups are expired.
+       (gnus-agent-cat-set-property, gnus-agent-cat-defaccessor,
+       gnus-agent-set-cat-groups): Provides abstract interface for
+       accessing agent category.  Category now implemented by an alist.
+       (gnus-agent-add-group, gnus-agent-remove-group,
+       gnus-category-insert-line, gnus-category-edit-predicate,
+       gnus-category-edit-score, gnus-category-edit-groups,
+       gnus-category-copy, gnus-category-add, gnus-group-category): Use
+       new agent category abstraction.
+       (gnus-agent-find-parameter): New function.  Search for agent
+       configuration parameter first in the group's parameters, then its
+       topics (if any), and then the group's category.  If not found
+       anywhere, use the original defined constants.
+       (gnus-agent-fetch-headers, gnus-agent-fetch-group-1): Use new
+       gnus-agent-find-parameter.
+       (gnus-agent-fetch-headers, gnus-agent-uncached-articles): Clearing
+       gnus-agent-cache now blocks retrieving headers and articles from
+       the local cache.  Fetched content is still added to the cache
+       before being returned.
+       (gnus-agent-fetch-session): Use error-message-string to generate
+       displayed error message.
+       (gnus-agent-customize-category): New Command.  'e' in category
+       buffer opens category customization buffer.
+       (gnus-category-read): Reads either positional or alist format;
+       returns alist format.
+       (gnus-category-write): Writes category file compatible with
+       current, and previous, versions of gnus-agent.
+       (gnus-category-make-function, gnus-category-make-function-1):
+       Corrected documentation; parameter is predicate NOT category.
+       (gnus-predicate-implies-unread): Now works in more cases per the
+       todo comment.
+       (gnus-function-implies-unread-1): New function.  Supports
+       gnus-predicate-implies-unread.
+       (gnus-agent-expire-group): Command now provides default of group
+       under point.
+       (gnus-agent-expire-group-1): Obeys new agent-enable-expiration and
+       agent-days-until-old parameters.  No longer supports
+       gnus-agent-expire-days being set to an alist.
+       (gnus-agent-request-article): Now performs its own checks of
+       gnus-agent, gnus-agent-cache, and gnus-plugged rather than
+       assuming that the caller will do them correctly.
+       (): Added one-time hook to gnus-group-prepare-hook.  Detects when
+       gnus-agent-expire-days is set to an alist.  Converts said alist
+       into group parameter so that gnus-agent-expire-days will not be
+       needed.
+       * gnus-art.el (gnus-request-article-this-buffer): Conditional
+       checks surrounding gnus-agent-request-article removed; now
+       performed by gnus-agent-request-article.
+       * gnus-cus.el (gnus-agent-parameters): New variable.  List of
+       customizable group/topic parameters that regulate the agent.
+       (gnus-group-customize): Uses gnus-agent-parameters.  Replace
+       kill-buffer with gnus-kill-buffer to remove the killed buffer from
+       the list of gnus buffers.
+       (gnus-trim-whitespace): Removes leading and trailing whitespace
+       from multiline strings.
+       (gnus-agent-cat-prepare-category-field)
+       (gnus-agent-customize-category): Constructs a category
+       customization buffer.
+       * gnus-int.el (gnus-retrieve-headers)
+       (gnus-request-expire-articles): No longer checks gnus-agent-cache
+       as it is handled internally by the agent.
+       (gnus-request-head, gnus-request-body): Conditional checks
+       surrounding gnus-agent-request-article removed; now performed by
+       gnus-agent-request-article.
+
+       * gnus-start.el (): Add defvar statements to resolve compilation
+       warnings.
+       (gnus-long-file-names): New function.  Isolates platform dependent
+       msdos-long-file-names.
+       (gnus-save-startup-file-via-temp-buffer): New variable.  Provides
+       option of writing directly to file.  Avoids memory exhausted
+       errors when .newsrc.eld is huge.
+       (gnus-save-newsrc-file): Uses new
+       gnus-save-startup-file-via-temp-buffer.
+       (gnus-gnus-to-quick-newsrc-format): Rewrite to write to
+       standard-output.
+       (gnus-display-time-event-handler): Change to alias from a defun
+       to avoid a compile-time warning when display-time-event-handler is
+       not defined.
+       * gnus-util.el (gnus-with-output-to-file): New macro.
+       Binds standard-output such that prin1 and princ will write directly
+       to a file.
+
+       * gnus.el (gnus-agent-cache): Expand documentation.
+       (gnus-summary-high-undownloaded-face): Remove second bold keyword
+       so that this face is actually bold.
+
+       * nnkiboze.el (nnkiboze-request-article): Only use the cache when
+       gnus-use-cache has been set.
+
+2003-03-02  Jesper Harder  <harder@ifa.au.dk>
+
+       * nnvirtual.el (nnvirtual-update-xref-header): Simplify.
+
+2003-03-01  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-article-refer-article): Be more permissive.
+
+2003-03-01  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * spam.el: Fix typo.
+
+2003-03-01  Satyaki Das  <satyaki@theforce.stanford.edu>
+
+       * pgg-gpg.el (pgg-gpg-process-region): Insert process status into
+       errors-buffer.  This produces a nicer error message in case of
+       problems.
+
+2003-03-01  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-maybe-spam-stat-load, spam-maybe-spam-stat-load):
+       load stats iff spam-use-stat is on.
+
+       * spam.el: Add spam-maybe-spam-stat-load to gnus-startup hook,
+       also use spam-maybe-spam-stat-load and spam-maybe-spam-stat-save
+       instead of spam-stat-load and spam-stat-save in the
+       gnus-get-new-news-hook and gnus-save-newsrc-hook, respectively.
+
+2003-03-01  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-view.el (mm-inline-text): Ignore errors from enriched-decode.
+
+2003-03-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-make-fqdn): Protect against nil user-mail.
+
+2003-02-28  Vasily Korytov  <deskpot@myrealbox.com>
+
+       * gnus-art.el (gnus-boring-article-headers): New values:
+       'to-list and 'cc-list.
+
+2003-02-28  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-setup-widening): New function to set.
+       nnimap-split-download-body, we add it to gnus-get-new-news-hook.
+       (spam-list-of-statistical-checks): List of statistical splitter
+       checks.
+       (spam-split): Added a widen call when a statistical check is
+       enabled.
+
+2003-02-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-msg.el (gnus-user-agent): Changed default to
+       'emacs-gnus-type, renamed 'full.
+
+2003-02-28  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnfolder.el (nnfolder-request-accept-article): Don't use
+       mail-header-unfold-field.
+
+2003-02-27  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * imap.el (imap-ssl-open): Don't depend on ssl.el.
+       * nntp.el (nntp-open-ssl-stream): Don't depend on ssl.el.
+
+2003-02-26  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el: Add spam-stat-load to gnus-get-new-news-hook.
+       (spam-split): Remove spam-stat-load call.
+
+2003-02-26  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-summary-toggle-header): Run
+       gnus-article-decode-hook instead of calling a-decode-encoded-words
+       directly (the latter is run as part of the former).
+
+2003-02-26  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-expire-group): Remove debug.
+
+2003-02-25  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-sendmail-envelope-from): New option.
+       (message-sendmail-envelope-from): New function.
+       (message-send-mail-with-sendmail): Use it.
+
+2003-02-25  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button-mid-or-mail-heuristic-alist): Added
+       compensation for TDMA addresses.
+
+2003-02-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-msg.el (gnus-user-agent): New variable.
+       (gnus-version-expose-system): Removed.  Obsoleted by
+       `gnus-user-agent'.
+       (gnus-extended-version): Use `gnus-user-agent'.
+
+2003-02-24  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-stat-register-spam-routine)
+       (spam-stat-register-ham-routine): Remove spam-stat-save.
+       (spam-stat hook): Add spam-stat-save to the gnus-save-newsrc-hook.
+
+2003-02-24  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-group.el (gnus-topic-mode-p): Fixed free variable
+       reference.
+
+2003-02-24  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * nnheader.el (nnheader-find-nov-line): Changed midpoint
+       calculation to avoid integer overflow.
+
+2003-02-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-start.el (gnus-backup-startup-file): Fixed custom type.
+
+2003-02-24  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el: Disabled spam-get-article-as-filename.
+
+2003-02-24  Michael Shields  <shields@msrl.com>
+
+       * gnus-group.el (gnus-group-is-exiting-without-update-p): New.
+       * gnus-sum.el (gnus-summary-exit-no-update): Use it.
+       * gnus-sum.el (gnus-summary-expire-articles): Use it.
+       * spam.el (spam-summary-prepare-exit): Use it.
+       * gnus.el (gnus-install-group-spam-parameters): New.
+       * spam.el (spam-group-ham-processor-copy-p): New.
+       * spam.el (spam-summary-prepare-exit): Support for ham copying.
+       * spam.el (spam-mark-spam-as-expired-and-move-routine): Fix bug
+       that would cause the current message to be moved if the group had
+       no spam.
+       * spam.el (spam-ham-move-routine): New `copy' argument.
+
+2003-02-24  Martin Thornquist  <martint@ifi.uio.no>
+
+       * gnus-topic.el (gnus-topic-select-group): Select last group if
+       after last group.
+       * gnus-group.el (gnus-group-select-group): Ditto.
+
+2003-02-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (popup-menu): Compiler macro for Emacs 20.
+       (gnus-article-refer-article): Use gnus-point-at-(b|e)ol instead of
+       point-at-(b|e)ol which aren't available in Emacs 20.
+
+       * gnus-registry.el (puthash): Alias to cl-puthash for Emacs 20.
+
+2003-02-23  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-start.el (gnus-activate-group): Re-enabled the catch error
+       clause of the condition-case statement.  Errors connecting to a
+       server no longer terminate gnus.
+
+       * gnus-agent.el (gnus-agent-toggle-plugged): Renamed parameter to
+       make its use obvious.  Added no-nothing case to avoid
+       opening(closing) servers when already open(closed).
+       (gnus-agent-while-plugged): Added macro to facilitate internal use
+       of gnus-agent-toggle-plugged.
+       (gnus-agent-fetch-group): Use new gnus-agent-while-plugged to
+       temporarily open servers.
+       (gnus-agent-get-undownloaded-list): Sort list of article numbers
+       as sorting gnus-newsgroup-headers is wrong.
+       (gnus-agent-summary-fetch-group): Use new gnus-agent-while-plugged
+       to temporarily open servers.  Corrected logic to handle setting
+       gnus-agent-mark-unread-after-downloaded.
+       (gnus-agent-fetch-articles): Now handles headers with missing
+       article sizes and/or missing article lengths.  Now clears the
+       message buffer when finished.
+       (gnus-agent-fetch-group-1): Position point before calling
+       gnus-summary-set-agent-mark.
+       (gnus-get-predicate): Corrected description, parameter is
+       predicate not category.
+       (gnus-agent-expire-group): Adapted the gnus-agent-expire-* code to
+       provide a separate single group expiration function.
+       (gnus-agent-regenerate-group): Now clears the message buffer when
+       finished.
+
+2003-02-23  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus.el (gnus-agent-target-move-group-header): New variable.
+       * gnus-draft.el (gnus-draft-send): If special header
+       "X-Gnus-Agent-Target-Move-Group" is present, do like Gcc into
+       that group, instead of performing the regular sending functions.
+
+2003-02-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-xmas.el (gnus-xmas-mime-button-menu): Accept a prefix arg.
+
+2003-02-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-user-fqdn, message-valid-fqdn-regexp): New
+       variables.
+       (message-make-fqdn): Use it.  Improved validity check.
+
+2003-02-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-user-mail-address): Check whether
+       user-mail-address looks valid.
+
+       * gnus-msg.el (gnus-mailing-list-followup-to): New function.
+
+       * gnus-util.el (gnus-fetch-original-field): New function.
+
+2003-02-23  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * message.el (message-mode): \\(...\\) around additional
+       paragraph-separate alternative.
+
+2003-02-23  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-mime-button-commands): Add ellipsis.
+       (gnus-mime-button-menu): Define MIME popup menu with easy-menu to
+       display key bindings.
+       (gnus-mime-button-menu): Rewrite.
+
+2003-02-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-button-url-regexp): Removed `.
+
+2003-02-23  Max Froumentin  <mf@w3.org>
+
+       * gnus-art.el (gnus-button-url-regexp): Remove `, enter '.
+
+2003-02-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-mime-action-on-part): Require a match
+       interactively.
+
+       * gnus-start.el (gnus-save-newsrc-file): Use
+       gnus-backup-startup-file.
+       (gnus-backup-startup-file): New variable.
+
+2003-02-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-summary-buffer-name): Moved function here.
+
+       * gnus-draft.el (defun): Remove debug.
+
+2003-02-22  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-summary-refer-article): Skip method if we
+       can't open server.
+
+2003-02-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-draft.el (defun): Configure posting styles.
+
+       * gnus-start.el (gnus-get-unread-articles-in-group): Make sure
+       the entry for the group exists before we alter it.
+
+2003-02-22  David S. Goldberg  <david.goldberg6@verizon.net>  (tiny change)
+
+       * message.el (message-mode): MML tags separate paragraphs.
+
+2003-02-22  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus-agent.el (gnus-agent-get-undownloaded-list): Sort
+       `gnus-newsgroup-headers'.
+
+2003-02-22  Karl Pflästerer  <sigurd@12move.de>
+
+       * gnus-art.el (gnus-article-refer-article): Grok more message id
+       formats.
+
+2003-02-22  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-decode.el (mm-path-name-rewrite-functions): Doc fix: don't
+       use "path name".
+
+2003-02-21  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-sum.el (gnus-summary-move-article)
+       (gnus-summary-expire-articles): Send data header for article, not
+       just article ID.
+
+       * gnus-registry.el (gnus-registry-hashtb, gnus-register-action)
+       (gnus-register-spool-action): Added hashtable of message ID keys
+       with message motion data.
+
+2003-02-21  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button-mid-or-mail-heuristic-alist): New
+       variable, used in `gnus-button-mid-or-mail-heuristic'.
+       (gnus-button-mid-or-mail-heuristic): New function derived from
+       Florian Weimer's Perl script.
+       (gnus-button-handle-mid-or-mail): Allow a function instead of
+       'guess.
+       (gnus-button-guessed-mid-regexp): Removed.
+
+2003-02-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-resend): Bind message-setup-hook to nil;
+       remove X-Draft-From header.
+
+2003-02-20  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-simplify-subject-fully, gnus-subject-equal)
+       (gnus-newsgroup-undownloaded)
+       (gnus-summary-save-parts-default-mime, gnus-auto-select-next):
+       Doc fixes.
+
+2003-02-17  John Paul Wallington  <jpw@gnu.org>
+
+       * gnus.el (gnus-shell-command-separator, gnus-email-address)
+       (gnus-default-charset, gnus-other-frame-parameters): Doc fixes.
+
+2003-02-20  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-spec.el (gnus-xmas-format): Use insert instead of
+       insert-string which is obsolete in Emacs 22.1.
+
+       * message.el (message-cross-post-followup-to-header): Do.
+
+       * spam.el (spam-ifile-register-with-ifile)
+       (spam-stat-register-spam-routine)
+       (spam-stat-register-ham-routine)
+       (spam-bogofilter-register-with-bogofilter): Do.
+
+       * mailcap.el (mailcap-mime-data): Fix typo.
+
+       * gnus-topic.el (gnus-topic-make-menu-bar): Add ellipsis.
+
+2003-02-19  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-cite.el (gnus-cite-unsightly-citation-regexp)
+       (gnus-cite-parse): Renamed `gnus-unsightly-citation-regexp' to
+       `gnus-cite-unsightly-citation-regexp'.
+
+2003-02-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-copy-article-buffer): Copy an article header
+       even if there's just a header.
+
+2003-02-19  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-fix-before-sending): Fix highlighting of
+       illegible and invisible text.
+
+       * gnus-util.el (gnus-multiple-choice): Separate choices with
+       ", ".  Suggested by Dan Jacobson <jidanni@dman.ddts.net>.
+
+2003-02-18  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-summary-exit-no-update): Use gnus-kill-buffer.
+
+2003-02-18  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-ham-move-routine)
+       (spam-mark-spam-as-expired-and-move-routine): Use
+       gnus-summary-kill-process-mark and gnus-summary-yank-process-mark
+       around process-mark manipulation on the group.
+
+2003-02-17  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Add MIME/Multipart
+       submenu.
+
+2003-02-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-fetch): Reverse the return value of
+       the continuation question.
+
+2003-02-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nndraft.el (nndraft-request-move-article): Bind
+       nnmh-allow-delete-final to t.
+
+2003-02-14  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-uu.el (mm-uu-uu-filename): Fix use of character constant.
+
+2003-02-11  Stefan Monnier  <monnier@cs.yale.edu>
+
+       * nntp.el (nntp-accept-process-output): Don't use point-max to get
+       the buffer's size.
+
+2003-01-31  Joe Buehler  <jhpb@draco.hekimian.com>
+
+       * nnheader.el: Added cygwin to system-type comparisons.
+
+2003-01-27  Juanma Barranquero  <lektu@terra.es>
+
+       * imap.el (imap-mailbox-status): Fix typo.
+
+2003-02-14  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-prepare): Don't set agent mark if
+       online.
+
+2003-02-14  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus-agent.el (gnus-agent-group-make-menu-bar): Include all
+       commands.
+       * gnus-sum.el: Small change from Frank Weinberg
+       <frank@usenet-rundfahrt.de>:
+       (gnus-auto-center-group): New variable.
+       (gnus-summary-read-group-1): Use it.
+       (gnus-summary-next-group): Fix docstring.
+
+2003-02-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-faces-at): Simplify.
+
+2003-02-13  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-ham-move-routine)
+       (spam-mark-spam-as-expired-and-move-routine): Made the article
+       move conditional, so it's not called even if there's nothing to move.
+
+2003-02-13  Kurt B. Kaiser  <kbk@shore.net>
+
+       * message.el (message-unix-mail-delimiter): Accept any whitespace
+       after the email address and before the date; do not require the
+       space character.
+
+2003-02-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-only-boring-p): Make sure that the
+       gnus-article-boring-faces variable is bound; use gnus-faces-at.
+
+       * gnus-util.el (gnus-faces-at): New macro.
+
+2003-02-13  Michael Shields  <shields@msrl.com>
+
+       * gnus-cite.el
+       (gnus-cite-attribution-suffix, gnus-cite-parse):
+       Better handling for Microsoft citation styles.
+       (gnus-unsightly-citation-regexp): New.
+
+2003-02-12  Michael Shields  <shields@msrl.com>
+
+       * gnus-art.el (article-strip-banner): Strip both per-group and
+       per-user-address banners.
+       (article-really-strip-banner): New.
+
+2003-02-12  Michael Shields  <shields@msrl.com>
+
+       * gnus-sum.el (gnus-article-goto-next-page,
+       gnus-article-goto-prev-page): Call gnus-summary-*-page, instead of
+       relying on the summary bindings of `n' and `p'.
+
+2003-02-12  Michael Shields  <shields@msrl.com>
+
+       * gnus-art.el (gnus-article-only-boring-p): New.
+       (gnus-article-skip-boring): New.
+       * gnus-cite.el (gnus-article-boring-faces): New.
+       * gnus-sum.el (gnus-summary-next-page): Use
+       gnus-article-only-boring-p.
+
+2003-02-12  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-mark-spam-as-expired-and-move-routine)
+       (spam-ham-move-routine): Unmark all articles before marking those
+       of interest and calling gnus-summary-move-article.
+
+2003-02-12  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.el (gnus-kill-buffer): Move to gnus.el because it's
+       logically the complement of gnus-get-buffer-create and
+       gnus-add-buffer.
+
+       * gnus-util.el (gnus-kill-buffer): Do.
+
+       * nnmail.el: Autoload gnus-kill-buffer.
+
+2003-02-11  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-summary-set-agent-mark): Added call to
+       gnus-summary-goto-subject as gnus-summary-update-mark operates on
+       the current LINE.
+       (gnus-agent-summary-fetch-group): Minimized the number of times
+       that the article is updated in the buffer.
+
+2003-02-11  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-ham-move-routine): Use the process-mark instead of
+       gnus-current-article when moving articles.
+       (spam-mark-spam-as-expired-and-move-routine): Ditto,
+       use the process-mark.
+
+2003-02-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-topic.el (gnus-topic-expire-articles): Recursive.
+       (gnus-topic-catchup-articles): Ditto.
+       (gnus-topic-mark-topic): Reverse recursive logic.
+
+2003-02-11  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-summary-refer-thread): Handle case where
+       gnus-refer-thread-limit is t.
+
+2003-02-10  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-util.el (mm-mule-charset-to-mime-charset): Use
+       sort-coding-systems to prefer utf-8 over utf-16.
+
+2003-02-09  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-expire-days):
+       gnus-request-move-article depends on gnus-agent-expire to clean up
+       the cache after moving the article.  Therefore, g-a-e-d can NOT
+       default to nil or can gnus-agent-expire be disabled by doing so.
+       If you don't want to run gnus-agent-expire, don't call it.
+       (gnus-agent-expire): The broken test to disable gnus-agent-expire
+       when g-a-e-d was NOT nil was removed.
+       (gnus-agent-article-name): Removed unnecessary input test as
+       article IDs are always strings.
+       (gnus-agent-regenerate-group): Added check to protect against
+       servers that generate absurdly long article IDs.  Valid IDs are
+       less than 10 digits to avoid overflow errors.  Fixed logic error
+       when ensuring that the final article ID is present in the new
+       alist.
+
+2003-02-09  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-topic.el (gnus-topic-goto-missing-topic): Just move to the
+       next line after finding the parent.
+
+2003-02-08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Bumped.
+
+2003-02-08 23:23:27  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.15 is released.
+
+2003-02-08  Michael Welsh Duggan  <md5i@cs.cmu.edu>
+
+       * nnmail.el (nnmail-split-it): If a message ends up matching the
+       same mailbox more than once, it will cause duplicates to appear
+       in the mailbox.
+
+2003-02-08  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-summary-select-article): Remove blink removal
+       code that only worked under Emacs.
+
+2003-02-08  Satyaki Das  <satyaki@chicory.stanford.edu>
+
+       * pgg-gpg.el (pgg-gpg-process-region): Don't blink.
+
+2003-02-08  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-article-refer-article): Use
+       gnus-replace-in-string.
+
+       * gnus-util.el (gnus-map-function): Remove unneeded let-binding.
+       (gnus-remove-duplicates): Do.
+
+2003-02-07  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-int.el (gnus-internal-registry-spool-current-method):
+       New variable.
+       (gnus-request-scan): Set
+       gnus-internal-registry-spool-current-method to gnus-command-method
+       before a request-scan operation.
+
+       * gnus-registry.el (regtest-nnmail): Use
+       gnus-internal-registry-spool-current-method.
+
+2003-02-07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-fetch): Typo fix.
+
+2003-02-07  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * nnmail.el (nnmail-spool-hook): New hook.
+       (nnmail-cache-insert): Call nnmail-spool-hook.
+
+       * gnus-registry.el: New file with examples of using the hooks.
+
+       * gnus.el (gnus-registry): Added registry customization group.
+       (gnus-group-prefixed-name): Improve function to return full group
+       name optionally.
+       (gnus-group-guess-prefixed-name): Shortcut to
+       gnus-group-prefixed-name, using just the group name.
+       (gnus-group-full-name): Always get a group's full name.
+       (gnus-group-guess-full-name): Shortcut, using just the group name.
+
+       * gnus-sum.el (gnus-summary-article-move-hook)
+       (gnus-summary-article-delete-hook)
+       (gnus-summary-article-expire-hook): New hooks.
+       (gnus-summary-move-article, gnus-summary-expire-articles)
+       (gnus-summary-delete-article): Invoke the new hooks.
+
+2003-02-07  Frank Weinberg  <frank@usenet-rundfahrt.de>
+
+       * gnus-art.el (gnus-article-refer-article): Strip leading "news:"
+       from message-ID.
+
+2003-02-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-util.el (gnus-run-hooks): Use save-current-buffer.
+
+2003-02-07  John Paul Wallington  <jpw@gnu.org>
+
+       * mm-util.el (mm-delete-duplicates, mm-append-to-file)
+       (mm-write-region, mm-detect-coding-region): Doc fixes.
+
+2003-02-07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-source-fetch): Ignore errors.
+       (mail-source-ignore-errors): New variable.
+
+       * gnus-sum.el (gnus-summary-refer-thread): Don't re-fetch current
+       articles.
+
+       * gnus-msg.el (gnus-version-expose-system): Change default.
+
+2003-02-07  Vasily Korytov  <deskpot@myrealbox.com>
+
+       * gnus-msg.el (gnus-version-expose-system): New variable.
+
+2003-02-07  Simon Josefsson  <jas@extundo.com>
+
+       * mml-sec.el (mml-unsecure-message): Don't use kill-region.  Tiny
+       patch from deskpot@myrealbox.com (Vasily Korytov).
+
+2003-02-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-display-face): Get the Face header from
+       the current buffer.
+
+2003-02-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-mime-view-part-internally): Bind
+       buffer-read-only to nil.
+
+2003-02-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-agent.el (gnus-agent-expire-1,2): Pass the dir argument
+       from g-a-e-1 to g-a-e-2.
+
+2003-02-05  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-check-BBDB): No need to regexp-quote the argument
+       of bbdb-search-simple, use spam-use-BBDB-exclusive.
+       (spam-check-whitelist): Use spam-use-whitelist-exclusive.
+       (spam-use-whitelist-exclusive): New variable affecting
+       spam-use-whitelist.
+       (spam-use-BBDB-exclusive): New variable affecting spam-use-BBDB.
+
+2003-02-05  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-agent.el (gnus-agent-expire-days): Change default to nil.
+       (gnus-agent-expire): Don't expire if g-a-e-d is nil.
+       (gnus-agent-expire): Move most code into gnus-agent-expire-1.
+       (gnus-agent-expire-1): New.
+       (gnus-agent-expire-1): Move code into gnus-agent-expire-2.
+       (gnus-agent-expire-2): New.
+
+2003-02-05  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-util.el (gnus-delete-if): Rename to gnus-remove-if.
+       "delete-if" is misleading because it isn't actually destructive.
+
+       * gnus-topic.el (gnus-group-prepare-topics): Use new name.
+
+       * nnmail.el (nnmail-purge-split-history): Do.
+
+       * gnus-win.el (gnus-get-buffer-window): Do.
+
+       * gnus-sum.el (gnus-simplify-whitespace): Remove unnecessary
+       let-binding.
+       (gnus-simplify-all-whitespace): Do.
+
+2003-02-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-delay.el (gnus-delay-article): Fix binding of the
+       nndraft:delayed group.
+
+2003-02-04  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.el (spam group parameters): Change 'other to 'const in
+       the group parameter definitions to soothe XEmacs.
+
+2003-02-04  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus-delay.el (gnus-delay-article): Really create
+       nndraft:delayed group if it doesn't exist.
+
+2003-02-04  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-summary-search-article): Speed up by
+       disabling various visual features while searching.
+       (gnus-summary-recenter): Test gnus-auto-center-summary first.
+
+2003-02-03  Jesper Harder  <harder@ifa.au.dk>
+
+       * spam.el (spam-list-of-checks): Don't quote nil and t in
+       docstrings.  From the elisp manual:
+
+          When a documentation string refers to a Lisp symbol, write
+          it [..] with single-quotes around it.  [..] There are two
+          exceptions: write t and nil without single-quotes.
+
+       * messcompat.el (message-from-style): Do.
+
+       * message.el (message-send-mail): Do.
+
+       * gnus-util.el (gnus-use-byte-compile): Do.
+
+       * gnus-score.el (gnus-score-lower-thread): Do.
+
+       * gnus-int.el (gnus-server-unopen-status): Do.
+
+       * gnus.el (gnus-define-group-parameter, gnus-large-newsgroup)
+       (large-newsgroup-initial, gnus-install-group-spam-parameters): Do.
+
+       * gnus-cus.el (gnus-group-customize, gnus-score-parameters)
+       (gnus-group-parameters): Do.
+
+       * gnus-art.el (gnus-article-mime-match-handle-function): Do.
+
+       * mm-decode.el (mm-text-html-renderer): Do.
+
+2003-02-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nnheader.el (nnheader-directory-separator-character): Change the
+       way to compute the default value.
+
+2003-02-02  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-button-handle-describe-key): Implement it.
+       (gnus-button-alist): Fix regexp for describe-key.
+       (gnus-button-handle-describe-function)
+       (gnus-button-handle-describe-variable)
+       (gnus-button-handle-apropos, gnus-button-handle-apropos-command)
+       (gnus-button-handle-apropos-variable)
+       (gnus-button-handle-apropos-documentation): Docstring fix.
+
+       * gnus-util.el (gnus-kill-buffer): Use get-buffer.
+
+2003-02-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-draft.el (gnus-group-send-queue): Bind gnus-posting-styles
+       to nil.
+
+       * nnmail.el: Removed gnus-util autoload.
+
+       * gnus.el: Use gnus-prin1-to-string throughout.
+
+       * gnus-util.el (gnus-prin1-to-string): Bind print-length and
+       print-level.
+
+       * gnus-art.el (article-display-x-face): Removed gray x-face stuff.
+       (gnus-treat-display-grey-xface): Removed.
+
+       * gnus-fun.el (gnus-grab-cam-face): New.
+       (gnus-convert-image-to-gray-x-face): Removed.
+       (gnus-convert-gray-x-face-to-xpm): Removed.
+       (gnus-convert-gray-x-face-region): Removed.
+       (gnus-grab-gray-x-face): Removed.
+
+       * nnmail.el (nnmail-expiry-wait-function): Doc indent.
+
+2003-01-31  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-util.el (gnus-kill-buffer): Functions in gnus-util
+       shouldn't depend on the rest of Gnus, so test if gnus-buffers is
+       bound.
+
+       * nnmail.el (nnmail-cache-close): Use gnus-kill-buffer.
+
+2003-01-30  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-cite.el (gnus-cite-reply-regexp, gnus-cite-always-check):
+       Remove -- these are bogus options which are never used.
+
+2003-01-29  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-article-mode): Use summary tool bar.
+
+2003-01-27  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-check-blackholes)
+       (spam-blackhole-good-server-regex): New variable to skip some IPs
+       when checking blackholes; use it.
+       (spam-check-bogofilter-headers)
+       (spam-bogofilter-bogosity-positive-spam-header): New variable, in
+       case more X-Bogosity is used than just "Yes/No".
+       (spam-ham-move-routine): Semi-fixed, only first article is
+       properly moved now.
+
+2003-01-27  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-util.el (gnus-kill-buffer): Remove buffer from gnus-buffers
+       as well.
+
+       * gnus-sum.el (gnus-select-newsgroup): Use gnus-kill-buffer.
+
+       * gnus-score.el (gnus-score-headers, gnus-score-find-bnews): Do.
+
+       * gnus-start.el (gnus-save-newsrc-file, gnus-clear-system): Do.
+
+       * gnus-bcklg.el (gnus-backlog-shutdown): Do.
+
+       * gnus-srvr.el (gnus-server-exit, gnus-browse-exit): Do.
+
+2003-01-26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-fun.el (gnus-face-encode): New function.
+       (gnus-convert-png-to-face): Use it.
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Added M-& to marks.
+
+2003-01-26  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-decode.el (mm-dissection-list): Remove.
+       (mm-dissect-singlepart): Don't push to mm-dissection-list, it's
+       only used in mm-remove-all-parts.
+       (mm-remove-all-parts): Remove it, it's never called.
+
+2003-01-25  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-group.el (gnus-group-make-group): Report errors.
+
+       * nnimap.el (nnimap-request-create-group): Ditto.
+
+       * sieve-manage.el (sieve-manage-is-okno): Parse literal strings.
+
+       * sieve.el (sieve-upload): Fix error printing.
+
+       * mm-encode.el (mm-qp-or-base64): Always QP iff
+       mm-use-ultra-safe-encoding and cleartext PGP.
+
+       * gnus-sum.el (gnus-summary-select-article): Inhibit
+       redisplay (mainly for secured messages).
+
+       * nnmail.el (nnmail-article-group): Copy body too (but don't
+       process it).
+
+2003-01-25  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-article-setup-buffer): Reset
+       gnus-button-marker-list.
+
+2003-01-25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nntp.el (nntp-read-timeout): Default to using a second delay
+       under Microsoft Windows.
+
+2003-01-24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnheader.el (nnheader-directory-separator-character): New
+       variable.
+
+2003-01-24  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus-agent.el (gnus-agent-max-fetch-size)
+       (gnus-agent-article-alist, gnus-agent-get-undownloaded-list)
+       (gnus-agent-catchup, gnus-agent-summary-fetch-group)
+       (gnus-agent-fetch-articles, gnus-agent-backup-overview-buffer)
+       (gnus-agent-flush-cache, gnus-agent-fetch-headers)
+       (gnus-agent-braid-nov, gnus-agent-load-alist)
+       (gnus-agent-article-alist-save-format)
+       (gnus-agent-read-agentview, gnus-agent-save-alist)
+       (gnus-agent-fetch-group-1, gnus-agent-expire)
+       (gnus-agent-uncached-articles, gnus-agent-retrieve-headers)
+       (gnus-agent-regenerate-group): Reformat to keep under eighty
+       columns.  Reword docstrings so that first line is under eighty
+       chars and a complete sentence.  Still need to work on the rear
+       end of the file, in particular gnus-agent-expire.
+
+2003-01-24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-agent.el (gnus-agentize): Indent.
+
+       * gnus.el (gnus-version-number): Bumped.
+
+2003-01-24 20:32:44  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.14 is released.
+
+2003-01-24  Mark Thomas  <swoon@bellatlantic.net>  (tiny change)
+
+       * gnus-sum.el (gnus-summary-prepare-threads): Reset state for %B
+       before beginning.
+
+2003-01-24  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-check-blackholes, spam-split)
+       (spam-mark-junk-as-spam-routine, spam-summary-prepare-exit): Added
+       gnus-message calls to show to users what spam.el is doing.
+
+2003-01-24  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-msg.el (gnus-message-replysign)
+       (gnus-message-replyencrypt): Fix typo.
+
+2003-01-24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-mime-security-show-details): Toggle showing
+       details.
+
+2003-01-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-press-button): let* -> let.
+       (gnus-mime-security-show-details): Cleaned up.
+       (gnus-mime-security-press-button): Save excursion.
+       (gnus-insert-mime-security-button): Clean up.
+
+       * gnus-sum.el (gnus-summary-force-verify-and-decrypt): Doc fix.
+
+       * gnus-async.el (gnus-async-wait-for-article): Don't use a
+       timeout.
+
+       * nntp.el (nntp-accept-process-output): Removed timeout.
+       (nntp-read-timeout): New variable.
+       (nntp-accept-process-output): Use it.
+
+       * gnus-sum.el (gnus-data-find-list): Remove *.
+
+2003-01-23  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-sum.el (gnus-summary-first-subject): Fixed bug that I
+       introduced on 2002-01-22.
+       (gnus-summary-first-unseen-or-unread-subject): Ditto.
+
+2003-01-23  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-check-regex-headers, spam-list-of-checks)
+       (spam-regex-headers-spam, spam-regex-headers-ham): Added spam/ham
+       checks of incoming mail based on simple header regexp matching.
+
+2003-01-22  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-sum.el (gnus-spam-mark): Set to `$'.
+
+2003-01-22  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-get-undownloaded-list): Now computes
+       gnus-newsgroup-unfetched, the list of articles whose headers have
+       not been fetched from the server.
+
+       * gnus-sum.el (gnus-summary-find-next): Removed undownloaded
+       parameter as it never worked due to a bug.  Added check to prevent
+       selection of any article in the gnus-newsgroup-unfetched list.
+       (gnus-summary-find-prev): Added check to prevent selection of any
+       article in the gnus-newsgroup-unfetched list.
+       (gnus-summary-first-subject): Documented API.  Modified
+       implementation so that constraints are handled independently.
+       Added check to prevent selection of any article in the
+       gnus-newsgroup-unfetched list.
+       (gnus-summary-first-unseen-subject): Updated parameters in
+       gnus-summary-first-subject call to match new API.
+       (gnus-summary-first-unseen-or-unread-subject): Ditto.
+       (gnus-summary-catchup): Do not mark unfetched articles as read.
+
+2003-01-22  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-treat-strip-pgp, gnus-article-hide-pgp-hook):
+       make-obsolete-variable allows only two arguments in XEmacs and
+       Emacs 20.
+
+       * gnus-sum.el (gnus-summary-wash-hide-map): Remove
+       gnus-article-hide-pgp.
+       (gnus-summary-make-menu-bar): Do.
+
+       * gnus-art.el (gnus-treat-strip-pgp): Make obsolete.
+       (gnus-treatment-function-alist): Remove gnus-treat-strip-pgp and
+       gnus-article-hide-pgp.
+       (article-hide-pgp): Remove.
+       (gnus-article-hide): Remove gnus-article-hide-pgp.
+
+       * gnus.el: Remove gnus-article-hide-pgp.
+
+2003-01-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-required-headers): Doc fix.
+
+2003-01-21  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-group-ham-processor-bogofilter-p): Fixed bug.
+       (spam-ifile-register-ham-routine, spam-ifile-ham-category): New
+       option to make ifile a purely binary classifier.
+
+2003-01-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mml-sec.el (mml-secure-sign-pgpauto): Renamed.
+       (mml-secure-encrypt-pgpmime): Removed double.
+
+       * gnus-sum.el (gnus-summary-mark-article-as-replied): Added
+       debugging statements.
+
+2003-01-21  Andreas Fuchs  <asf@void.at>
+
+       * mml-sec.el (mml-sign-alist): Added pgpauto.
+
+2003-01-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Bumped version number.
+
+2003-01-21 07:15:41  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.13 is released.
+
+2003-01-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-button-url-regexp): Removed |.
+
+       * message.el (message-send-hook): Doc fix.
+
+       * gnus-win.el (gnus-buffer-configuration): Display article
+       instead of article-copy when `reply'.
+
+2003-01-21  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.el (gnus-format): Change customize group to gnus.
+       (gnus-cache): Add link.
+       (gnus-group-charter-alist): Fix docstring.
+
+2003-01-20  Jesper Harder  <harder@ifa.au.dk>
+
+       * mailcap.el (mailcap-print-command): lpr-command might be
+       unbound in XEmacs.
+
+2003-01-18  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-regenerate-group): Added interactive form.
+
+       * gnus-sum.el (gnus-summary-update-article-line): Fixed
+       calculation of net characters added for use in the gnus-data
+       structure.
+
+2003-01-18  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * nnmail.el (nnmail-process-unix-mail-format): Improve error
+       message.  Suggested by Jari Aalto.
+
+2003-01-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-followup-with-original): Clean up.
+       (gnus-article-reply-with-original): Ditto.
+
+       * gnus-sum.el (gnus-summary-catchup): Make sure downloadable,
+       read articles don't become unread.
+
+2003-01-17  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-fun.el (gnus-x-face-from-file):
+       (gnus-face-from-file): Suggest image format in minibuffer prompt.
+
+       * gnus-fun.el (gnus-convert-image-to-x-face-command)
+       (gnus-convert-image-to-face-command): Doc fix.
+
+2003-01-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-fun.el (gnus-convert-face-to-png): Protect against errors.
+
+2003-01-17  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-mime-print-part): Use mm-save-part-to-file to
+       avoid encoding problems.
+
+       * mailcap.el (mailcap-ps-command): New variable.
+       (mailcap-mime-data): Add print entry where applicable.  Use
+       pdftotext on a tty.
+
+2003-01-16  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-alter-header-function): Add type and group.
+
+2003-01-16  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-fun.el (gnus-convert-image-to-x-face-command)
+       (gnus-convert-image-to-face-command, gnus-x-face-from-file)
+       (gnus-face-from-file): Doc fix; don't mention image format.
+
+2003-01-16  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-get-article-as-filename): New function (unused for now).
+       (spam-get-article-as-buffer): New function.
+       (spam-get-article-as-string): Use spam-get-article-as-buffer.
+       (spam-summary-prepare-exit): Fixed bug, noticed by Malcolm Purvis.
+
+2003-01-15  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el: Don't use `path'.
+       From the GNU coding standards:
+
+           Please do not use the term ``pathname'' that is used in Unix
+           documentation; use ``file name'' (two words) instead.  We use
+           the term ``path'' only for search paths, which are lists of
+           directory names.
+
+       * nnsoup.el (nnsoup-file-name): Ditto.
+
+       * nnmail.el (nnmail-pathname-coding-system): Ditto.
+       (nnmail-group-pathname): Ditto.
+
+       * nnimap.el (nnimap-group-overview-filename): Ditto.
+
+       * nnheader.el (nnheader-pathname-coding-system): Ditto.
+       (nnheader-group-pathname): Ditto.
+
+       * nnfolder.el (nnfolder-group-pathname): Ditto.
+
+       * gnus.el (gnus-home-directory): Ditto.
+
+       * gnus-group.el (gnus-group-icon-list): Ditto.
+
+2003-01-16  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-mime-print-part): Use mm-handle-media-type.
+
+       * message.el (message-mode-menu): Use it.
+       (message-mode-menu): Deactivate "Yank Original" if there's no
+       reply buffer.
+
+       * messagexmas.el (message-xmas-redefine): Redefine in XEmacs.
+
+       * message.el (message-mark-active-p): New function.
+
+2003-01-15  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-use-bogofilter-headers, spam-bogofilter-header)
+       (spam-bogofilter-database-directory): New variables.
+       (spam-check-bogofilter-headers, spam-check-bogofilter)
+       (spam-bogofilter-register-with-bogofilter)
+       (spam-bogofilter-register-spam-routine)
+       (spam-bogofilter-register-ham-routine)
+       (spam-group-ham-processor-bogofilter-p): New functions for the new
+       Bogofilter interface.
+       (spam-summary-prepare-exit): Use the new Bogofilter functions.
+       (spam-list-of-checks): Added spam-use-bogofilter-headers.
+       (spam-bogofilter-score): Rewrote function.
+       (spam-check-bogofilter): Optional score parameter, uses
+       spam-check-bogofilter-headers better.
+       (spam-check-bogofilter-headers): Optional score parameter.
+
+       * gnus.el (gnus-install-group-spam-parameters): New variable, t by
+       default, in the gnus-start customization group.  Used to disable
+       the spam-*/ham-* parameters.
+       (gnus-group-ham-exit-processor-bogofilter): New ham processor.
+
+2003-01-15  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-xmas.el (gnus-xmas-redefine): Use region-exists-p in
+       XEmacs.
+
+       * gnus-ems.el (gnus-mark-active-p): Do.
+
+2003-01-15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-send): Don't warn about duplicates when
+       superseding.
+
+2003-01-15  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap-split-download-body): New variable.
+       (nnimap-split-articles): Use it.
+
+2003-01-14  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-check-overview-buffer): This data
+       integrity checker was incorrectly flagging, and removing, articles
+       whose article number was negative.
+       (gnus-agent-fetch-group-1): When executed in the group's summary
+       buffer, refresh each downloaded line to update the status flag and
+       font.  Preserve the value of gnus-newsgroup-headers so that
+       gnus-agent-fetch-articles can split the requests by size.
+       (gnus-agent-expire): Corrected day calculation for when
+       gnus-agent-expire-days contains a list.
+
+2003-01-14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-audio.el (gnus-audio-au-player): Use executable-find.
+
+2003-01-13  Jhair Tocancipa Triana  <jhair_tocancipa@gmx.net>
+
+       * gnus-audio.el (gnus-audio-au-player, gnus-audio-wav-player): Use
+       /usr/bin/play as default player.
+       (gnus-audio-play): Added ARG-DESCRIPTOR to prompt for a file to play.
+
+2003-01-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-inews-add-send-actions): Allow a list of
+       articles to be marked as well.
+
+2003-01-14  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-get-undownloaded-list): Include the
+       fictitious headers generated by nnagent (ie. Undownloaded Article
+       ####) in the list of articles that have not been downloaded.
+
+       * gnus-int.el (): Added require declarations to resolve
+       compile-time warnings.
+       (gnus-open-server): If the server status is set to offline,
+       recursively execute gnus-open-server to open the offline backend
+       (e.g. nnagent).
+
+2003-01-14  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (gnus-article-reply-with-original): Use
+       gnus-mark-active-p.
+       (gnus-article-followup-with-original): Do.
+
+2003-01-13  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-sum.el: Removed `(when t ...)' around `gnus-define-keys'.
+
+2003-01-13  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-score.el (gnus-score-edit-file-at-point): New function.
+       (gnus-score-find-trace): Bind it to `e' key.  Added `q' for quit.
+
+2003-01-13  Romain FRANCOISE  <romain@orebokech.com>
+
+       * gnus-fun.el (gnus-x-face-from-file): Quote file name.
+       (gnus-face-from-file): Ditto.
+
+2003-01-13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-articles-to-read): Don't just apply
+       gnus-alter-articles-to-read-function to the unread articles.
+
+2003-01-13  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * deuglify.el (gnus-article-outlook-unwrap-lines)
+       (gnus-article-outlook-repair-attribution)
+       (gnus-article-outlook-rearrange-citation): New function names,
+       renamed from "gnus-outlook-" to "gnus-article-outlook-".  Changed
+       doc-string.
+
+       * gnus-sum.el (gnus-summary-mode-map): Use new function names,
+       removed `W k' key binding (use `W Y f' instead).
+       (gnus-summary-make-menu-bar): Use new function names.
+
+2003-01-13  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-fun.el (gnus-random-x-face): Doc fix.
+       (gnus-insert-random-x-face-header): New function.
+
+2003-01-13  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Deactivate items if
+       mark is not active.
+
+       * gnus-msg.el (gnus-inews-do-gcc): Comment.
+
+       * gnus-ems.el (gnus-mark-active-p): New function.
+
+       * gnus-group.el (gnus-topic-mode-p): New function.
+       (gnus-group-make-menu-bar): Show more key bindings in topic mode.
+       Deactivate items if mark is not active.
+
+2003-01-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Bumped version.
+       (gnus-summary-line-format): Doc fix.
+
+2003-01-12 22:02:49  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.12 is released.
+
+2003-01-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mail-source.el (mail-sources): Removed autoload to make it
+       compile under XEmacs.
+
+2003-01-12  Raymond Scholz  <ray-2003@zonix.de>
+
+       * gnus-msg.el (gnus-confirm-mail-reply-to-news): May be a
+       regexp or a function too.
+       (gnus-confirm-treat-mail-like-news): New variable.  Ask for
+       confirmation even if the original article is mail.
+
+2003-01-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-inews-add-send-actions): Get the right
+       articles to be marked when not yanking.
+
+2003-01-12  François-David Collin  <Francois-David.Collin@curie.fr>
+
+       * mm-decode.el (mm-get-part): Use mm-with-unibyte-current-buffer.
+
+2003-01-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-fun.el (gnus-face-from-file): Autoload.
+
+       * gnus-cite.el (gnus-cite-delete-overlays): Protect against more
+       errors.
+
+2003-01-12  Simon Josefsson  <jas@extundo.com>
+
+       * sieve.el (sieve-upload-and-bury): New.  Suggested by
+       kai.grossjohann@uni-duisburg.de (Kai Großjohann).
+
+       * sieve-mode.el (sieve-mode-map): Bind s-u-a-b to C-c C-c.
+       Suggested by kai.grossjohann@uni-duisburg.de (Kai Großjohann).
+
+2003-01-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-ignored-headers): Don't include the ^ and :
+       in every string.
+
+       * gnus.el (gnus-version-number): Bumped version number.
+
+2003-01-12 13:46:20  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.11 is released.
+
+2003-01-12  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-fetch-reply-field): Narrow to headers.
+
+       * gnus-msg.el (gnus-inews-do-gcc): Don't try to mark GCC's as read
+       if Gnus isn't alive.
+
+2003-01-11  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-fetch-group-1): Remove downloadable
+       marks from articles that are already stored in the agent.
+       (gnus-agent-backup-overview-buffer): New debug tool.  Creates a
+       backup copy of an invalid .overview file for later analysis.
+
+2003-01-12  Gregorio Gervasio, Jr.  <gtgj@pacbell.net>
+
+       * gnus-sum.el (gnus-summary-exit): Reverse change to make group
+       exit work with two frames.
+
+2003-01-11  François-David Collin  <Francois-David.Collin@wanadoo.fr>
+
+       * message.el (message-forward-make-body): Use mule4.
+
+2003-01-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-mode-map): Move wide-reply command.
+
+2003-01-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * deuglify.el (gnus-outlook-deuglify-attrib-verb-regexp): Added
+       castellano.
+       (gnus-outlook-display-hook): New variable.
+       (gnus-outlook-display-article-buffer): New function.
+       (gnus-outlook-unwrap-lines, gnus-outlook-repair-attribution)
+       (gnus-outlook-deuglify-article): Made them interactive and added
+       optional arg.  Use `g-o-d-a-b'.
+       (gnus-article-outlook-deuglify-article): Use `g-o-d-a-b'.
+
+       * gnus-sum.el: Added autoloads.
+       (gnus-summary-mode-map): Added gnus-summary-wash-deuglify-map.
+       (gnus-summary-make-menu-bar): Added "(Outlook) Deuglify" menu.
+
+2003-01-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-display-mime): Use the mime emulation
+       variable.
+
+       * gnus-sum.el (gnus-article-emulate-mime): New variable.
+
+       * gnus-start.el (gnus-read-newsrc-el-file): Make sure that the
+       newsrc-alist is initialized properly.
+
+       * mail-source.el (mail-sources): Autoload.
+
+       * gnus-sum.el (gnus-summary-make-false-root-always): Default to
+       nil.
+
+       * gnus-msg.el (gnus-configure-posting-styles): Make sure we don't
+       insert two newlines.
+
+       * message.el (message-check-news-header-syntax): Compute the
+       header length correctly.
+
+2003-01-10  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-expire): Do not remove article from
+       alist when keeping fetched article file.
+       (gnus-agent-retrieve-headers): When parsing response for article
+       numbers, use the same algorithm as gnus-agent-braid-nov to protect
+       against garbage in the server's response.
+
+       * gnus-int.el (gnus-request-expire-articles,
+       gnus-request-move-article): Only expire when the group's server
+       has been agentized.
+
+2003-01-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-cite.el (gnus-cite-delete-overlays): Protect against
+       errors when deleting overlays.
+
+       * gnus-score.el (gnus-score-followup): Allow tracing.
+
+       * gnus-art.el (gnus-treat-display-face): New variable.
+       (article-display-face): New command.
+
+       * gnus-fun.el (gnus-face-from-file): New function.
+       (gnus-convert-face-to-png): Ditto.
+
+       * gnus-art.el (gnus-ignored-headers): Added Face.
+
+2003-01-10  Simon Josefsson  <jas@extundo.com>
+
+       * nndraft.el (nndraft-request-group): Avoid crash in
+       directory-files when draft directory doesn't exists.
+
+       * gnus-sum.el (gnus-select-article-hook): Add :option.
+
+2003-01-10  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-use-stat): New variable.
+       (spam-group-spam-processor-stat-p)
+       (spam-group-ham-processor-stat-p): New convenience functions.
+       (spam-summary-prepare-exit): Add spam/ham processors to sequence.
+       (spam-list-of-checks): Add spam-use-stat to list of checks.
+       (spam-split): Conditionally load the spam-stat tables.
+       (spam-stat-register-spam-routine, spam-stat-register-ham-routine)
+       (spam-check-ifile): New functions.
+
+       * spam-stat.el (spam-stat): Typo fix.
+       (spam-stat-install-hooks): New variable.
+       (spam-stat-split-fancy-spam-group): Added documentation clarification.
+       (spam-stat-split-fancy-spam-threshhold): New variable.
+       (spam-stat-install-hooks): Make hooks conditional.
+       (spam-stat-split-fancy): Use spam-stat-split-fancy-spam-threshhold.
+
+       * gnus.el (gnus-group-ham-exit-processor-stat, spam-process): Add
+       spam-stat ham/spam processor symbols.
+
+2003-01-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-read-newsrc-el-file): Make sure the .eld
+       file exists.
+
+2003-01-10  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-summary-read-group-1): Don't select first
+       undownloaded/downloadable only when unplugged.
+
+2003-01-10  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-srvr.el (gnus-browse-foreign-server): Optimize inner loop.
+
+2003-01-09  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-check-ifile): Fixed call-process-region to use the
+       db parameter only if it's set.
+       (spam-ifile-register-with-ifile): Ditto.
+
+2003-01-09  Alex Schroeder  <alex@emacswiki.org>
+
+       * spam-stat.el (spam-stat-save): Set spam-stat-ngood and
+       spam-stat-nbad before creating the hash table.
+       (spam-stat-reset): Set spam-stat-ngood and spam-stat-nbad to 0.
+       Changed copyright statement to FSF.
+
+2003-01-09  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-catchup): Do not mark cached nor
+       processable articles as read.
+       (gnus-agent-summary-fetch-series): Remove processable and
+       downloadable marks on all downloaded articles in the series.
+
+       * nntp.el (nntp-report): Throw error after reporting the problem.
+       (nntp-accept-process-output): Corrected error check to report an
+       error when the process is nil.
+
+2003-01-09  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-tool-bar-map): Add preview.
+
+2003-01-09  Jesper Harder  <harder@ifa.au.dk>
+
+       * mml.el (mml-preview): Get rid of MIME handles and buffers after
+       previewing.
+
+2003-01-08  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir--grp-add-art): Fix wrong-type-argument
+       bug when the (n+1)th article to be added to a group has a smaller
+       number than the n articles already added.
+
+2003-01-08  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-mode-field-menu): Use backquote.
+
+2003-01-08  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el: Fixed the BBDB autoloads again, using
+       bbdb-search-simple now (which is not a macro, thank god).
+
+       * lpath.el (bbdb-search): Removed function from maybe-fbind list.
+
+       * gnus.el (ham-process-destination): Added new parameter for
+       destination of ham articles found in spam groups at summary exit.
+
+       * spam.el (spam-get-ifile-database-parameter):
+       use spam-ifile-database-path.
+       (spam-check-ifile, spam-ifile-register-with-ifile):
+       use spam-get-ifile-database-parameter.
+       (spam-ifile-database-path): Added new parameter for ifile's database.
+       (spam-move-spam-nonspam-groups-only): New parameter to determine
+       if spam should be moved from all groups or only some.
+       (spam-summary-prepare-exit): Fixed logic to use
+       spam-move-spam-nonspam-groups-only when deciding to invoke
+       spam-mark-spam-as-expired-and-move-routine; always invoke that
+       routine after the spam has been expired-or-moved in case there's
+       some spam left over; use spam-ham-move-routine in spam groups.
+       (spam-ham-move-routine): New function to move ham articles to the
+       ham-process-destinations group parameter.
+
+2003-01-08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-spec.el (gnus-parse-complex-format): %~ => ~*.
+
+       * gnus-agent.el (gnus-agent-fetch-selected-article): Use
+       gnus-summary-update-article-line.
+
+2003-01-08  Simon Josefsson  <jas@extundo.com>
+
+       * nnmail.el (nnmail-expiry-target-group): Request group, create it
+       not successful.
+
+2003-01-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el (bbdb-records): Fbind it for both Emacs and XEmacs.
+
+2003-01-07  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-check-ifile): Fixed the spam-ifile-all-categories
+       logic, finally.
+
+2003-01-08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-spec.el (gnus-parse-format): %C is a complex format.
+       (gnus-parse-format): Change to %~.
+
+       * message.el (message-generate-headers): Don't generate optional
+       empty headers.
+
+2003-01-07  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-cross-post-default)
+       (message-cross-post-note-function, message-shoot-gnksa-feet)
+       (message-strip-subject-trailing-was, message-change-subject)
+       (message-mark-insert-file, message-cross-post-followup-to)
+       (message-cross-post-followup-to, message-mode-map)
+       (message-generate-unsubscribed-mail-followup-to)
+       (message-make-mail-followup-to): Minor changes to doc-strings and
+       error messages.  Updated copyright line.
+
+       * message.el (message-make-mail-followup-to,
+       message-generate-unsubscribed-mail-followup-to): New function
+       names.  Renamed functions: "-mft" -> "-mail-followup-to".
+       (message-make-mft, message-gen-unsubscribed-mft): Removed function
+       names.
+
+       * mml.el (mml-preview-insert-mail-followup-to): New function name.
+       (mml-preview-insert-mft): Removed function name.
+       (mml-preview): Use new function names.
+
+       * gnus-art.el (gnus-article-edit-mode-map): Use new function names.
+
+       * message.el (message-mode-field-menu): Moved header related
+       commands from "Message" to "Field" menu.
+
+2003-01-07  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-generate-headers-first): Added customization
+       if variable is a list.
+
+2003-01-07  Michael Shields  <shields@msrl.com>
+
+       * gnus-art.el (gnus-article-next-page): Correctly handle the case
+       where the last line of the article is the last line of the window.
+
+2003-01-08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-debug): Use ignore-errors.
+
+       * gnus-agent.el (gnus-agent-fetch-selected-article): Use
+       `gnus-summary-update-line'.
+
+2003-01-08  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-art.el (gnus-unbuttonized-mime-types)
+       (gnus-buttonized-mime-types): Doc fix.
+
+2003-01-08  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-decode.el (mm-inline-media-tests): .xpm is 'x-xpixmap'.
+
+2003-01-07  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnrss.el (nnrss-group-alist): Add and clear up.
+
+2003-01-07  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el: Removed unnecessary condition-case for loading bbdb-com.el.
+
+       * lpath.el (bbdb-search): Added BBDB functions for a better way to
+       fix missing functions.
+
+       * spam.el (spam-check-ifile): If should be an unless.
+
+       * spam.el: Define 'ignore alias for spam-BBDB-register-routine,
+       spam-enter-ham-BBDB, and bbdb-create-internal initially to
+       hush up warnings.
+       (spam-ifile-all-categories): Doc string fixed to be less than 80 chars.
+
+2003-01-07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Added
+       gnus-summary-refer-thread to thread menu.
+
+2003-01-07  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-fetch-group-1): When fetching within a
+       summary buffer, articles that cannot be fetched are marked as
+       canceled.
+
+       * nntp.el (nntp-with-open-group): The quit signal handler must
+       propagate the quit signal to the next outer handler so that the
+       caller knows that the request aborted abnormally.
+
+2003-01-07  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-check-ifile, spam-ifile-register-with-ifile)
+       (spam-ifile-register-spam-routine)
+       (spam-ifile-register-ham-routine): Added ifile functionality that
+       does not use ifile-gnus.el to classify and register articles.
+       (spam-get-article-as-string): Convenience function.
+       (spam-summary-prepare-exit): Added ifile spam and ham registration.
+       (spam-ifile-all-categories, spam-ifile-spam-category)
+       (spam-ifile-path, spam-ifile): Added customization options.
+
+       * gnus.el (gnus-group-ham-exit-processor-ifile): Added ifile ham
+       exit processor.
+       (spam-process): Added gnus-group-ham-exit-processor-ifile to the
+       list of choices.
+
+2003-01-07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-score.el (gnus-score-followup): Also score immediate
+       followups.
+
+2003-01-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnweb.el (nnweb-asynchronous-p): Changed to nil.
+
+2003-01-07  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-mode-menu): Fix receipt balloon help.
+
+2003-01-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-msg.el (gnus-group-post-news): Don't assume that "" will
+       always be interpreted as news.
+
+2003-01-07  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sieve.el (gnus-sieve-script): Use the crosspost argument to
+       gnus-sieve-script, instead of the global variable
+       gnus-sieve-crosspost.  One-line patch from Steinar Bang
+       <sb@dod.no>.
+
+2003-01-06  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus.el: Renamed gnus-summary-*-uncached-face as
+       gnus-summary-*-undownloaded-face to avoid confusing the agent with
+       the cache.
+
+       * gnus-sum.el: Ditto.
+
+2003-01-06  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-fetch-group): Modified to permit execution
+       in either the group or summary buffer.
+       New command "JS", in summary buffer, will fetch articles per the
+       group's category, predicate, and processable flags.
+       (gnus-agent-summary-fetch-series): Rewritten to call
+       gnus-agent-session-fetch-group once with all articles in the
+       series.
+       (gnus-agent-summary-fetch-group): Fixed bug and modified code to
+       return list of fetched articles.
+       (gnus-agent-fetch-articles): Split fetch list into sublists such
+       that the article buffer is only slightly larger than
+       gnus-agent-max-fetch-size.  Added unwind-protect to ensure that
+       the group's article alist is saved.
+       (gnus-agent-fetch-headers): The 'killed' and 'cached' marks no
+       longer result in the agent trying to fetch an article.
+       (gnus-agent-fetch-group-1): Can now be called in either the group
+       or summary buffer.  Removed the max-fetch-size code that I added
+       on 2002-12-13 as that capability is now part of
+       gnus-agent-fetch-articles.  Added code to update summary buffer.
+       When called in the group buffer, articles that can not be fetched
+       are AUTOMATICALLY MARKED AS READ.
+
+       * gnus-sum.el (): Modified eval-when-compile to minimize
+       misleading compilation warnings.
+       (gnus-update-summary-mark-positions): Changed code to use
+       gnus-undownloaded-mark rather than gnus-downloaded-mark.
+
+       * nnheader.el (nnheader-insert-nov-file): Do not try to insert an
+       empty file as the parser assumes that the file isn't empty.
+
+       * nntp.el (nntp-send-string): The process-send-string call can,
+       because it performs I/O on the process, change the process' state
+       from open to closed.  If this happens, call nntp-report
+       immediately to report the broken connection.
+       (nntp-report): Rewritten to avoid needing a global variable to
+       determine the appropriate course of action.  Instead, two function
+       implementations are provided and the nntp-report function value is
+       bound to the appropriate implementation.
+       (nntp-retrieve-data): Moved nntp-report call to end of implementation.
+       (nntp-with-open-group): Now binds nntp-report's function cell
+       rather than binding gnus-with-open-group-first-pass.  Added a
+       condition-case to detect a quit during a nntp command.  When the
+       quit occurs, the current connection is closed as a fetch articles
+       request could have several megabytes queued up for reading.
+       (nntp-retrieve-headers): Bind articles to itself.  If
+       nntp-with-open-group repeats this command, I must have access to
+       the original list of articles.
+       (nntp-retrieve-groups): Ditto for groups.
+       (nntp-retrieve-articles): Ditto for articles.
+       (*): Replaced nntp-possibly-change-group calls to
+       nntp-with-open-group forms in all, but one, occurrence.
+       (nntp-accept-process-output): Bug fix.  Detect when called with
+       null process.
+
+2003-01-06  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-util.el (mm-find-mime-charset-region): Don't do Latin-9 hack
+       if we don't need to.
+       (mm-iso-8859-x-to-15-region): Fix misplaced parenthesis.
+
+2003-01-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-make-web-group): Pass the select
+       method on to group-create.
+       (gnus-group-line-format-alist): %U is an integer.
+
+       * gnus-sum.el (gnus-summary-exit-no-update): Don't update
+       ephemeral groups.
+       (gnus-summary-read-group-1): Ditto.
+       (gnus-group-make-articles-read): Ditto.
+
+       * mm-url.el (mm-url-program): Doc fix.
+
+       * message.el (message-mode-map): Rebound
+       message-insert-wide-reply.
+
+2003-01-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-xmas.el (gnus-xmas-group-startup-message): Bind the oort
+       color as `gnus-group-startup-message' does.
+
+2003-01-05  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el: Fixed line lengths to 80 chars or less.
+
+       * gnus-sum.el (gnus-read-mark-p): Added the spam-mark as a
+       "not-read" mark.
+       (gnus-summary-mark-forward): Added the spam-mark to the list of
+       marks not to be marked as "read" when viewed.
+
+2003-01-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-inews-make-draft): Quote article-reply.
+
+       * gnus-group.el (gnus-number-of-unseen-articles-in-group):
+       Protect against unactive groups.
+
+       * message.el (message-check-news-header-syntax): Check long
+       header lines.
+       (message-check-news-header-syntax): Update `start'.
+
+       * gnus-group.el (gnus-group-expire-articles): Doc fix.
+       (gnus-group-line-format): %U.
+       (gnus-group-line-format-alist): ?U.
+       (gnus-number-of-unseen-articles-in-group): New function.
+
+       * nntp.el (nntp-accept-process-output): Use a 0.1 second timeout.
+
+       * gnus.el (gnus-version-number): Bump version number.
+
+2003-01-05 01:53:30  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.10 is released.
+
+2003-01-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Fix version number.
+
+2003-01-05 01:40:09  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.08 is released.
+
+2003-01-04  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-util.el: Add mm-string-make-unibyte.
+
+       * gnus-group.el (gnus-group-jump-to-group): Make it work for
+       UTF-8 groups.
+
+2003-01-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-variable-list): Write gnus-format-specs last.
+
+       * gnus-sum.el (gnus-summary-goto-subjects): Fix typo.
+
+2003-01-04  Kevin Ryde  <user42@zip.com.au>
+
+       * gnus-art.el (gnus-mime-jka-compr-maybe-uncompress): New
+       function.
+
+2003-01-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-exit): Bind gnus-group-is-exiting-p.
+       (gnus-summary-read-group-1): Update group line.
+       (gnus-summary-exit-no-update): Update group on exit.
+
+       * gnus-group.el (gnus-group-line-format): Add %*.
+       (gnus-group-line-format-alist): Ditto.
+       (gnus-group-insert-group-line): Set it.
+       (gnus-group-is-exiting-p): New variable.
+       (gnus-group-insert-group-line): Use it.
+
+2003-01-03  Teodor Zlatanov  <tzz@beld.net>
+
+       * spam.el (spam-enter-ham-BBDB, spam-BBDB-register-routine):
+       enable BBDB ham processing.
+       (spam-blacklist-register-routine): Enable blacklist spam processing.
+       (spam-whitelist-register-routine): Enable whitelist ham processing.
+       (spam-fetch-field-from-fast): Fast fetching of the "from" field
+       from (gnus-data-list).
+       (spam-summary-prepare-exit): Works completely now.
+       (spam-use-blacklist): Oops, should be nil by default.
+       (spam-summary-prepare-exit): spam-use-PROCESSOR is only for
+       split processing now; before it was for summary exit as
+       well but that's done with the spam-contents and spam-process
+       parameters now.
+
+2003-01-03  Jesper Harder  <harder@ifa.au.dk>
+
+       * mml.el (mml-insert-tag): Don't quote non-ASCII unibyte
+       characters.
+
+2003-01-02  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-group-spam-contents-p, spam-group-ham-contents-p)
+       (spam-group-processor-p, spam-group-processor-bogofilter-p)
+       (spam-group-processor-ifile-p, spam-group-processor-blacklist-p)
+       (spam-group-processor-whitelist-p, spam-group-processor-BBDB-p)
+       (spam-mark-spam-as-expired-and-move-routine)
+       (spam-generic-register-routine, spam-BBDB-register-routine)
+       (spam-ifile-register-routine, spam-blacklist-register-routine)
+       (spam-whitelist-register-routine): New functions.
+       (spam-summary-prepare-exit): Added summary exit processing (expire
+       or move) of spam-marked articles for spam groups; added slots for
+       all the spam-*-register-routine functions.
+
+2003-01-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * pop3.el (pop3-retr): Wait 500 msecs.
+       (pop3-read-response): Ditto.
+
+       * gnus-msg.el (gnus-setup-message): Get the evaliation order
+       right.
+       (gnus-inews-make-draft): New function.
+       (gnus-setup-message): Use it.
+
+       * message.el (message-required-headers): Add From.
+
+2003-01-02  Norbert Koch  <nk@viteno.net>  (tiny change)
+
+       * gnus-msg.el (gnus-gcc-externalize-attachments): Fix typo.
+
+2003-01-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-generate-headers): Let header formatters do
+       their work.
+
+2003-01-02  Raymond Scholz  <ray-2003@zonix.de>
+
+       * deuglify.el (gnus-article-outlook-deuglify-article):
+       Rehighlight, reapply treatments and call
+       `gnus-article-prepare-hook'.  Suggested by Niels Olof Bouvin.
+       (gnus-outlook-repair-attribution-block): Recognize cited
+       attributions.  Suggested by Niklas Morberg.
+
+2003-01-02  Pete Kazmier  <pete@kazmier.com>
+
+       * gnus-art.el (gnus-treat-predicate): Check condition first.
+
+2003-01-02  Jesper Harder  <harder@ifa.au.dk>
+
+       * lpath.el: Add url-http-file-exists-p.
+
+       * gnus-group.el (gnus-group-fetch-charter): Use
+       http://TLH.news-admin.org/charters/GROUPNAME as a fallback.
+
+2003-01-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-draft-headers): Also generate From to get a
+       nicer draft buffer summary.
+
+       * gnus-xmas.el (gnus-xmas-read-event-char): Take an optional
+       parameter.
+
+       * gnus-art.el (article-wash-html): Clean up.
+       (article-wash-html): Typo fix.
+
+       * gnus-msg.el (gnus-summary-mail-forward): Clean up.
+       (gnus-summary-mail-forward): To many lists of lists.
+
+       * gnus-art.el (article-wash-html): Clean up.
+
+2003-01-02  Pete Kazmier  <pete@kazmier.com>
+
+       * gnus-art.el (gnus-treat-wash-html): New variable.
+
+2003-01-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-check-news-header-syntax): Allow posting.
+       (message-check-news-header-syntax): Fix logic for sure, this
+       time.
+
+2003-01-02  Matthieu Moy  <Matthieu.Moy@imag.fr>
+
+       * message.el (message-check-news-header-syntax): Check syntax of
+       continuation headers.
+
+2003-01-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button-url-regexp)
+       (gnus-button-mid-or-mail-regexp, gnus-button-alist)
+       (gnus-header-button-alist): Regexps are case insensitive here.
+
+2003-01-02  Simon Josefsson  <jas@extundo.com>
+
+       * dig.el (query-dig): Doc fix.
+
+2003-01-02  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus-agent.el (gnus-agent-fetch-selected-article): Update whole
+       summary buffer line, not just the download mark.
+
+2003-01-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-goto-subjects): New function.
+       (gnus-summary-insert-dormant-articles): New command and
+       keystroke.
+
+       * gnus-cache.el (gnus-summary-insert-cached-articles): Use new
+       function for mass insertion of subjects.
+
+       * nndraft.el (nndraft-generate-headers): Don't move point.
+
+       * gnus.el (nnheader): Require nnheader.
+
+       * nndraft.el (nndraft-request-associate-buffer): Use
+       make-local-variable.
+
+2003-01-02  Michael Shields  <shields@msrl.com>
+
+       * nndraft.el (nndraft-request-associate-buffer): Make
+       write-contents-hooks buffer-local before setting it.
+
+2003-01-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-group-parameter-value): Take an extra param.
+       (gnus-group-fast-parameter): Let group param results be nil.
+
+       * gnus-art.el (gnus-article-forward-header): New function.
+       (article-date-ut): Use it to remove continuation date headers.
+
+       * gnus-sum.el (gnus-summary-walk-group-buffer): Supply prompt to
+       read-event.
+       (gnus-summary-remove-bookmark): Clean up.
+       (gnus-summary-set-bookmark): Clean up.
+
+       * gnus-util.el (gnus-read-event-char): Take an optional prompt.
+
+       * gnus.el (gnus-group-startup-message): Bind data-directory to
+       the Gnus etc directory.
+
+2003-01-01  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-summary-prepare-exit): Added slots for spam- and
+       ham-processing of articles; use the new
+       spam-group-(spam|ham)-contents-p functions.
+       (spam-group-spam-contents-p, spam-group-ham-contents-p): New
+       convenience functions.
+       (spam-mark-junk-as-spam-routine): Use the new
+       spam-group-spam-contents-p function.
+
+       * gnus.el (spam-process, spam-contents, spam-process-destination):
+       added new parameters with corresponding global variables.
+       (gnus-group-spam-exit-processor-ifile)
+       (gnus-group-spam-exit-processor-bogofilter)
+       (gnus-group-spam-exit-processor-blacklist)
+       (gnus-group-spam-exit-processor-whitelist)
+       (gnus-group-spam-exit-processor-BBDB)
+       (gnus-group-spam-classification-spam)
+       (gnus-group-spam-classification-ham): Added new symbols for the
+       spam-process and spam-contents parameters.
+
+       * spam.el (spam-ham-marks, spam-spam-marks): Changed list
+       customization and list itself to store mark symbol rather than
+       mark character.
+       (spam-bogofilter-register-routine): Added logic to generate mark
+       values list from spam-ham-marks and spam-spam-marks, so (member)
+       would work.
+
+2003-01-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-cross-post-followup-to): Fix comment.
+
+2003-01-01  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-ham-marks, spam-spam-marks): Changed list
+       customization and list itself to store mark symbol rather than
+       mark character.
+       (spam-bogofilter-register-routine): Added logic to generate mark
+       values list from spam-ham-marks and spam-spam-marks, so (member)
+       would work.
+
+2003-01-01  Raymond Scholz  <ray-2002@zonix.de>
+
+       * message.el (message-signature-insert-empty-line): New variable.
+
+2002-12-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el: Renamed functions and variables: "xpost" ->
+       "cross-post", "-fup2" -> "-followup-to".
+       (message-cross-post-old-target, message-cross-post-default,
+       message-cross-post-note, message-followup-to-note,
+       message-cross-post-note-function): New variables names.
+       (message-xpost-old-target, message-xpost-default,
+       message-xpost-note, message-fup2-note,
+       message-xpost-note-function): Removed variable names.
+       (message-cross-post-followup-to-header,
+       message-cross-post-insert-note, message-cross-post-followup-to):
+       New function names.
+       (message-xpost-fup2-header, message-xpost-insert-note,
+       message-xpost-fup2): Removed function names.
+
+2002-12-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-send-mail): Added message-cleanup-headers to
+       prevent newlines in headers.
+
+2003-01-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * dns.el (dns-make-network-process): Comment.
+
+       * gnus-sum.el (gnus-summary-display-while-building): Default to
+       nil.
+
+2003-01-01  Wes Hardaker  <wes@hardakers.net>
+
+       * gnus-sum.el (gnus-summary-display-while-building): New
+       variable.
+
+2003-01-01  Raymond Scholz  <ray-2003@zonix.de>
+
+       * deuglify.el (gnus-outlook-rearrange-article): Kill overlays
+       before rearranging the article.
+
+2003-01-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nndraft.el (nndraft-generate-headers): New function.
+       (nndraft-request-associate-buffer): Use it to write headers on
+       buffer save.
+
+       * message.el (message-generate-headers): Let the function be a
+       lambda form.
+       (message-draft-headers): New variable.
+
+       * gnus-msg.el (gnus-inews-make-draft-meta-information): New
+       function.
+       (gnus-setup-message): Use it.
+
+       * message.el (message-generate-headers-first): Doc fix.
+       (message-setup-1): Use new function for getting which headers to
+       generate.
+       (message-headers-to-generate): New function.
+
+2003-01-01  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-save-alist): Make directory.
+
+2002-12-31  Reiner Steib  <4uce.02.r.steib@gmx.net>
+
+       * gnus-sum.el (gnus-summary-limit-to-age): Make prompt string
+       mention negatives.
+
+2002-12-31  Raymond Scholz  <ray-2002@zonix.de>
+
+       * deuglify.el (gnus-outlook-rearrange-article): Use
+       `transpose-regions' instead of tempering the kill-ring.
+       (gnus-article-outlook-deuglify-article): Rehighlight article
+       instead of a complete redisplay.
+
+2002-12-31  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el: Most defvars are defcustoms now.
+
+       Patches from Michael Shields  <shields@msrl.com>
+
+       * spam.el (spam-bogofilter-articles): Select the article
+       body using gnus-summary-show-article t instead of
+       gnus-summary-select-article; this presents the raw text
+       without running any hooks.
+
+       * spam.el (spam-bogofilter-articles): Use message-remove-header
+       to remove headers; the old way incorrectly removed just the first
+       line of folded headers.
+
+2002-12-31  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-start.el (gnus-load): Replace `ding-file' with `file'.
+
+2002-12-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-load): New function.
+       (gnus-read-newsrc-el-file): Use it.
+
+2002-12-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button-valid-fqdn-regexp): New variable.
+       (gnus-button-handle-apropos-documentation): New function.
+       (gnus-button-handle-ctan): New function.
+       (gnus-button-alist): Use them.  Improve some regexps.
+       (gnus-button-prefer-mid-or-mail): Addition to doc-string.
+
+2002-12-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-subscribed-p): New function.
+       (message-send-mail): Use it.
+       * mml.el (mml-preview-insert-mft): New function.
+       (mml-preview): Use it.
+
+2002-12-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-thread-latest-date): Protect against errors
+       when sorting by date.
+
+       * gnus-art.el (gnus-article-edit-mode): New variable.
+       (gnus-article-setup-buffer): Warn user about discarding edits.
+
+       * gnus-sum.el (gnus-summary-pipe-output): Clean up.
+       (gnus-summary-pipe-output): Take a symbolic prefix to save all
+       headers.
+
+       * mm-uu.el (mm-uu-configure-list): Default to (shar . disabled).
+
+2002-12-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-completion-alist): Added "Mail-Followup-To"
+       and "Mail-Copies-To".
+
+2002-07-21  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-group.el: Add key bindings for
+       gnus-group-sort-groups-by-real-name and
+       gnus-group-sort-selected-groups-by-real-name.
+
+2002-12-30  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-use-dig): New variable for blackhole checking
+       through dig.el.
+       (spam-check-blackholes): Added dig.el checking functionality and
+       more verbose reporting; query-dig is autoloaded from dig.el.
+       (spam-use-blackholes): Disabled by default.
+       (spam-blackhole-servers): Removed rbl.maps.vix.com from the
+       blackhole servers list.
+
+2002-12-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-required-headers): New variable.
+
+2002-12-30  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * dig.el (query-dig): New function.
+
+2002-12-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * flow-fill.el (fill-flowed): Don't infloop on too long fill
+       prefixes.
+
+       * dns.el (query-dns): Protect against errors.
+
+       * gnus-msg.el (gnus-article-yanked-articles): New variable.
+       (gnus-inews-add-send-actions): Mark all answered messages as
+       answered.
+
+2002-08-10  Jari Aalto  <jari.aalto@poboxes.com>
+
+       * nnmail.el (nnmail-split-it): Added tracing to
+       `:' split rule.
+
+2002-08-13  Hrvoje Niksic  <hniksic@xemacs.org>
+
+       * mm-decode.el (mm-mailcap-command): Remove the quotes around '%s'
+       and "%s" so we don't overquote them.
+
+2002-08-13  Hrvoje Niksic  <hniksic@xemacs.org>
+
+       * (mm-display-external): Display the actual command that has been
+       executed in the echo area.
+
+2002-12-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-topic.el (gnus-topic-display-missing-topic): Bind entry.
+
+       * message.el (message-with-reply-buffer): New macro.
+       (message-fetch-reply-field): Use it.
+       (message-insert-wide-reply): New command and keystroke.
+       (message-carefully-insert-headers): New function.
+       (message-insert-to): Use new function.
+
+       * gnus-topic.el (gnus-topic-display-missing-topic): New function.
+       (gnus-topic-goto-missing-group): Use it.
+
+       * message.el (message-required-news-headers): Removed Lines.
+       (message-reply): Don't insert References first.
+       (message-followup): Ditto.
+       (message-make-references): New function.
+       (message-followup): Set message-reply-headers before generating
+       the buffer stuff.
+
+2002-12-29  Jesper Harder  <harder@ifa.au.dk>
+
+       * mml.el (mml-generate-mime-1): Reverse the order of
+       encoding/flowing.
+
+2002-12-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnmail.el (nnmail-expiry-target-group): Mark articles as read
+       after moving them.
+
+       * gnus-sum.el (gnus-summary-dummy-line-format): Update format to
+       fit with newer standard format.
+       (gnus-summary-make-false-root-always): New variable.
+       (gnus-gather-threads-by-subject): Use it.
+
+       * message.el (message-get-reply-headers): Take an address list
+       optional argument.
+
+2002-12-28  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-keep-backlog): Change default to 20.
+
+       * gnus-agent.el (gnus-agent-check-overview-buffer): Start from
+       start.
+       (gnus-agent-check-overview-buffer): Remove negative article
+       numbers.
+
+       * nnmail.el (nnmail-split-fancy-with-parent-ignore-groups): Doc fix.
+       (nnmail-cache-ignore-groups): Doc fix.
+
+       * nnimap.el (nnimap-debug): Made into a flag and defcustomed.
+       (nnimap-debug-buffer): New variable.
+       (nnimap-debug): Use it.
+
+2002-12-28  Lars Magne Ingebrigtsen  <kgreiner@xpediantsolutions.com>
+
+       * gnus.el (gnus-summary-high-uncached-face): New color scheme.
+
+2002-12-28  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-agent.el (gnus-agent-check-overview-buffer): Sort lines if
+       they aren't already sorted.
+
+2002-12-28  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-mode-menu): Add ellipses to menu items
+       expecting user interaction.
+       (message-mode-field-menu): Do.
+
+2002-12-26  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-summary-highlight-line): Don't bind `list' --
+       it isn't used any more.
+
+2002-12-22  Jesper Harder  <harder@ifa.au.dk>
+
+       * binhex.el (binhex-decoder-program): Fix docstring.
+
+2002-12-21  Laurent Martelli  <laurent@bearteam.org>
+
+       * mm-decode.el (mm-mailcap-command): Do not backslash-quote
+       special chars if the mailcap file uses single quotes around %s.
+
+2002-12-19  Paul Jarc  <prj@po.cwru.edu>
+
+       * gnus-int.el (gnus-request-update-info): nnchoke-r-u-i might not
+       return the info object.
+
+2002-12-18  Paul Jarc  <prj@po.cwru.edu>
+
+       * gnus-int.el (gnus-request-update-info): Artificially add
+       (1 . (1- min)) to the read range, in case the backend doesn't
+       store marks for nonexistent articles.
+
+2002-12-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * binhex.el (binhex-insert-char): Eval-and-compile.
+
+2002-12-17  Jesper Harder  <harder@ifa.au.dk>
+
+       * lpath.el: Add tool-bar-local-item-from-menu.
+
+       * message.el (message-tool-bar-local-item-from-menu): New function.
+       (message-tool-bar-map): Use it.
+
+2002-12-14  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-uu.el (gnus-uu-digest-headers): Mention nil value in docstring.
+
+       * gnus-art.el (gnus-article-header-rank): Last header in
+       gnus-sorted-header-list should have higher rank than non-members.
+
+2002-12-13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-agent.el (gnus-close-agent): Don't blank out the list of
+       covered methods.
+
+2002-12-12  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * nntp.el (nntp-with-open-group-first-pass): Do not wrap in
+       eval-when-compile.  Suggested by Kevin Greiner.
+
+2002-12-13  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-max-fetch-size): New, defcustom.
+       (gnus-agent-fetch-headers): Initialize gnus-agent-overview-buffer
+       even though no headers may have been fetched
+       (gnus-agent-fetch-group-1, and perhaps others, require this
+       behavior).
+       (gnus-agent-fetch-group-1): Fetch articles in chucks so that the
+       server buffer is constrained by gnus-agent-max-fetch-size.
+       Multiple chunks in the same group may perform arbitrarily large
+       updates.
+
+2002-12-12  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-fetch-selected-article): Added call to
+       gnus-summary-update-download-mark to update the article in the
+       summary.
+
+2002-12-11  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus.el (gnus-summary-high-uncached-face,
+       gnus-summary-normal-uncached-face, gnus-summary-low-uncached-face)
+       New faces.
+
+       * gnus-agent.el (gnus-agent-downloaded-article-face): REMOVED.  I
+       added this on 2002-11-23 but it just wasn't working out as
+       intended.  The idea isn't entirely dead, three new faces
+       gnus-summary-*-uncached-face are being added to gnus.el to provide
+       the basis for an improved implementation.
+       (gnus-agent-read-servers): Undo the change made on 2002-11-23.  The
+       proper file to open is lib/servers.
+       (gnus-summary-set-agent-mark): Expanded documentation.  Unmarking
+       (i.e. removing the article from gnus-newsgroup-downloadable) will
+       now restore the article's default mark rather than simply setting
+       no mark.
+       (gnus-agent-get-undownloaded-list): Corrected documentation.
+       Added code to set new summary local variable,
+       gnus-newsgroup-agentized.  Reworked impl so that it doesn't create
+       a temporary list.  No longer sets gnus-newsgroup-downloadable.
+       (gnus-agent-summary-fetch-group): Keep gnus-newsgroup-undownloaded
+       up to date.  Call new gnus-summary-update-download-mark to keep
+       summary buffer up-to-date.
+       (gnus-agent-fetch-selected-article): Keep
+       gnus-newsgroup-undownloaded up to date.
+       (gnus-agent-fetch-articles): Return list of articles that were
+       successfully fetched.
+       (gnus-agent-check-overview-buffer): No more thingatpt.
+       (gnus-agent-expire): No longer deletes NOV entries of unread
+       articles.
+       (gnus-agent-unread-articles): New function.
+       (gnus-agent-regenerate-group): The article number must be
+       terminated by a tab character.  Added more messages to report
+       repairs.  Inhibit quits while writing changes so it is now safe
+       have to quit regeneration.  Renamed gnus-tmp-downloaded back to
+       downloaded to 1) resolve the unbound references and 2) avoid
+       confusing this list with the gnus-tmp-downloaded in gnus-sum.el.
+
+       * gnus-art.el (gnus-article-prepare): The agent
+       downloaded/undownloaded mark is no longer stored as the article's
+       mark.
+
+       * gnus-salt.el (gnus-tree-highlight-node): Added uncached as
+       gnus-summary-highlight may use it.  Added downloaded as
+       gnus-summary-highlight was using it.
+
+       * gnus-sum.el (gnus-undownloaded-mark): Changed from ?@ to ?- as
+       the download mark now follows Kai's +/- convention.
+       (gnus-downloaded-mark): Added ?+ mark.
+       (gnus-summary-highlight): Added rules to select
+       gnus-summary-high-uncached-face,
+       gnus-summary-normal-uncached-face, and
+       gnus-summary-low-uncached-face.  Removed the
+       gnus-agent-downloaded-article-face.
+       (gnus-summary-line-format-alist): Implemented the download flag
+       format (?O) as named in the manual.  This implementation displays
+       either gnus-undownloaded-mark, gnus-downloaded-mark, or
+       gnus-no-mark.
+       (gnus-newsgroup-agentized): New local variable that identifies
+       which groups are agentized.  While the agent is now on by default,
+       you don't have to agentize every server that you use.
+       (gnus-update-summary-mark-positions): Completed support for the
+       download type of mark.
+       (gnus-summary-insert-line): Added undownloaded to the parameters.
+       (gnus-summary-prepare-threads): Set gnus-tmp-downloaded for
+       reference by the gnus-summary-line-format-spec.
+
+       * nntp.el (nntp-with-open-group): This macro handles dropped or
+       broken connections by opening a new connection and repeating the
+       failed command.
+       (nntp-retrieve-headers-with-xover): Some NNTP servers respond to
+       XOVER commands preceding the active articles with the nov entry
+       of the first available article.  When gnus connected to such a
+       server, the unexpected nov entry would result in duplicate lines
+       in the agent's overview file.  This patch fixes the duplicate
+       lines problem and improves performance by skipping over all
+       articles IDs that precede the first nov entry in the server's
+       reply.
+
+2002-12-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-tmp-downloaded): New internal variable.
+       (gnus-summary-highlight): Use it instead of `downloaded'.
+       (gnus-summary-highlight-line): Ditto.
+
+       * gnus-agent.el (gnus-agent-regenerate-group): Ditto.
+
+2002-12-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-variable-list): Add gnus-agent-covered-methods.
+
+       * gnus-agent.el (gnus-agent-check-overview-buffer): Remove debug
+       calls.
+
+       * gnus-sum.el (gnus-summary-highlight-line): Don't set the
+       downloaded variable if we're in an uncovered group.
+
+       * gnus-agent.el (gnus-agent-downloaded-article-face): Change the
+       font to something less noticeable.
+       (gnus-agent-group-covered-p): New function.
+
+2002-12-09  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-braid-nov): Remove corrupted lines.
+       Because of an unknown bug, the group buffer is saved in .overview
+       file.
+
+2002-12-09  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * nntp.el (nntp-send-command): Braino in last commit.  Replace
+       `and' with `or'.
+
+2002-12-08  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * nntp.el (nntp-send-command): Assume that echo does not happen
+       when nntp-open-connection-function is nntp-open-network-stream.
+       Suggested by Sebastian D.B. Krause <krause@my.gnus.org>.
+
+2002-12-07  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnslashdot.el (nnslashdot-retrieve-headers-1): Update the parser.
+
+2002-12-06  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir-request-group): Bugfix: don't erase
+       nntp-server-buffer if we aren't going to write to it.
+
+2002-12-04  Itai Zukerman  <zukerman@math-hat.com>  (tiny change)
+
+       * mm-decode.el (mm-w3m-safe-url-regexp): Fix parenthesis.
+
+2002-12-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-decode-region): Remove newlines between
+       decoded words.
+
+2002-12-03  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus.el (fboundp): After loading mm-util, make sure it was the
+       right one.
+
+2002-11-29  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus-art.el (gnus-inhibit-mime-unbuttonizing): Moved here from
+       gnus-sum.  Made into a user option.
+
+       * gnus-sum.el (gnus-simplify-ignored-prefixes)
+       (gnus-summary-mark-article-as-unread): ???
+
+2002-11-29  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * time-date.el (date-to-time): Typo.
+
+       * parse-time.el: Typo.
+
+       * nnsoup.el (nnsoup-retrieve-headers): Typo.
+
+       * nnmail.el (nnmail-split, nnmail-process-unix-mail-format): Typos.
+
+       * nnimap.el:
+       (nnimap-split-rule, nnimap-find-minmax-uid): Typos.
+
+       * mm-encode.el (mm-safer-encoding): Typo.
+
+       * messcompat.el: Typo.
+
+       * message.el (message-face-alist): Typo.
+
+       * imap.el (imap-interactive-login, imap-open): Typos.
+
+       * ietf-drums.el (ietf-drums-text-token, ietf-drums-qtext-token): Typos.
+
+       * gnus.el: Typo.
+
+       * gnus-win.el (gnus-configure-frame): Typo.
+
+       * gnus-util.el (gnus-atomic-progn-assign): Typo.
+
+       * gnus-topic.el (gnus-topic-sort-topics): Typo.
+
+       * gnus-sum.el (gnus-summary-article-number)
+       (gnus-summary-read-group-1, gnus-summary-mark-article)
+       (gnus-summary-fetch-faq, gnus-refer-article-methods): Typos.
+
+       * gnus-mule.el (gnus-mule-add-group): Typo.
+
+       * gnus-mlspl.el (gnus-group-split-fancy): Typo.
+
+       * gnus-group.el (gnus-group-fetch-faq): Typo.
+
+       * gnus-art.el (gnus-decode-header-methods): Typo.
+
+       * flow-fill.el: Typo.
+
+2002-11-19  Stefan Monnier  <monnier@cs.yale.edu>
+
+       * binhex.el (binhex-decode-region): Don't hardcode point-min == 1.
+
+2002-11-29  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus-sum.el (gnus-simplify-ignored-prefixes)
+       (gnus-summary-mark-article-as-unread)
+       (gnus-mark-article-as-unread, gnus-summary-highlight-line):
+       Reformatting to avoid long lines.
+       (gnus-inhibit-mime-unbuttonizing): Moved to gnus-art.
+
+2002-11-28  Daiki Ueno  <ueno@unixuser.org>
+
+       * gnus-agent.el (gnus-agent-fetch-group-1): Article numbers should
+       be accessed through `mail-header-number'.
+
+2002-11-27  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-sum.el (gnus-summary-insert-old-articles): No longer passes
+       compressed range to gnus-summary-insert-articles.
+
+2002-11-26  Kevin Ryde  <user42@zip.com.au>
+
+       * gnus-art.el (gnus-mime-copy-part): Look for filename
+       parameter under content-disposition, not content-type.
+
+       * gnus-sum.el (gnus-summary-find-uncancelled): New function.
+       (gnus-summary-reselect-current-group): Use it.
+
+2002-11-26  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-uncached-articles): If
+       gnus-agent-load-alist fails, return ARTICLES.
+
+       * nnrss.el (nnrss-group-alist): Update the link of Jabber.
+
+2002-11-26  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus-sum.el (gnus-summary-insert-old-articles): Remove
+       superfluous function call.
+       (gnus-summary-catchup-all, gnus-summary-catchup-all-and-exit):
+       Add warning to docstring.
+
+2002-11-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-agent.el: Autoload number-at-point instead.
+       (gnus-agent-check-overview-buffer): No warning for deactivate-mark.
+
+2002-11-26  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus-agent.el (gnus-agent-check-overview-buffer): Explicitly
+       require thingatpt (for number-at-point) and protect against
+       deactivate-mark being unbound (on XEmacs).
+
+2002-11-25  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus-agent.el (gnus-agent-check-overview-buffer): Make debugger
+       print message on entry.
+
+2002-11-25  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-range.el (gnus-range-difference): New function.
+       * gnus-sum.el (gnus-summary-insert-old-articles): Use it.
+
+2002-11-24  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus-sum.el (gnus-summary-insert-old-articles): Use
+       gnus-remove-from-range instead of gnus-range-difference which
+       doesn't exist.
+
+2002-11-23  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus-agent.el (gnus-agent-downloaded-article-face): New face,
+       used for showing which articles have been downloaded.
+       (gnus-agent-article-alist): Format change.  Add documentation.
+       (gnus-agent-summary-mode-map): New keybinding `J s' for fetching
+       process-marked articles.
+       (gnus-agent-summary-fetch-series): Command for `J s'.  Articles
+       in the series are individually fetched to minimize lose of
+       content due to an error/quit.
+       (gnus-agent-synchronize-flags-server, gnus-agent-add-server): Use
+       gnus-message instead of message.
+       (gnus-agent-read-servers): Use file lib/methods instead of
+       lib/servers.  TODO: Why?
+       (gnus-summary-set-agent-mark): Adapt to new agent-alist format.
+       (gnus-agent-get-undownloaded-list): Remove articles that appear to
+       come from the agent.  This means that they are not downloaded.
+       (gnus-agent-fetch-selected-article): Don't use history.
+       (gnus-agent-save-history, gnus-agent-enter-history)
+       (gnus-agent-article-in-history-p, gnus-agent-history-path):
+       Removed function; history is not used anymore.
+       (gnus-agent-fetch-articles): Fix handling of crossposted articles.
+       (gnus-agent-crosspost): Started rewrite then realized that a typo
+       in gnus-agent-fetch-articles ensures that this function is never
+       called.  This will need to be fixed later.
+       (gnus-agent-check-overview-buffer): Some sanity checks on the
+       agent overview buffer.  This is a safety net used during
+       development.
+       (gnus-agent-flush-cache): The gnus-agent-article-alist format has
+       changed, write a number to the file indicating this.
+       (gnus-agent-fetch-headers): Rewrite to respect
+       gnus-agent-consider-all-articles without relying on the
+       `.fetched' files.  Make it fast.
+       (gnus-agent-braid-nov): Change resulting from
+       gnus-agent-fetch-headers change.
+       (gnus-agent-load-alist, gnus-agent-save-alist): Don't use
+       `.fetched' files.
+       (gnus-agent-read-agentview): New function, used by
+       gnus-agent-load-alist.
+       (gnus-agent-load-fetched-headers): Remove.
+       (gnus-agent-save-alist): Rewrite to accommodate new format.
+       (gnus-agent-fetch-group-1): Make sure list of articles is in the
+       same order as in gnus-newsgroup-headers.
+       (gnus-agent-expire): Document and implement extra args ARTICLES,
+       GROUP, FORCE.  Do not restrict usage.
+       (gnus-agent-uncached-articles): New function.
+       (gnus-agent-retrieve-headers): Use it.
+       (gnus-agent-regenerate-group): No longer needs to be called from
+       gnus-agent-regenerate.  Individual groups may be regenerated.  The
+       regeneration code now fixes duplicate, and mis-ordered, NOV entries.
+       The article fetch dates are validated in the article alist.  The
+       article alist is pruned of entries that do not reference existing
+       NOV entries.  All changes are computed then applied with
+       inhibit-quit bound to t.  As a result, it is now safe to quit out of
+       regeneration.  The optional clean parameter has been replaced with
+       an optional reread parameter.  Clean is no longer necessary as
+       regeneration gets the appropriate setting from
+       gnus-agent-consider-all-articles.  The new reread parameter will
+       result in fetched, or all, articles being marked as unread.
+       (gnus-agent-regenerate): Removed code to regenerate the history
+       file as it is no longer used.
+
+       * gnus-start.el (gnus-make-ascending-articles-unread): New
+       function, for efficient mass-marking.
+
+       * gnus-sum.el (gnus-summary-highlight): Use new face for
+       downloaded articles.
+       (gnus-article-mark): Prefer to indicate read/unread status over
+       downloaded status.
+       (gnus-summary-highlight-line-0): New function, maybe rehighlights
+       line.
+       (gnus-summary-highlight-line): Use new face for downloaded
+       articles.
+       (gnus-summary-insert-old-articles): Improved performance by
+       replacing the initial LIST of older articles with a compressed
+       RANGE of older articles.  Some servers appear to lie about
+       their active range so the original list could contain millions
+       of article numbers.  The range is not expanded into a list
+       until the optional ALL parameter has been applied.
+
+2002-11-18  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus-agent.el (gnus-category-mode): Typo in doc string.
+
+2002-11-21  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el:
+       Added patch from Andreas Fuchs <asf@void.at> to prevent apply errors.
+
+       * spam.el: Added `M s t' and `M s x' key mappings.
+
+2002-11-20  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-summary-morse-message): Narrow to body.
+
+2002-11-19  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-summary-morse-message): Load
+       morse.el (unmorse-region not autoloaded in Emacs 20 nor XEmacs).
+       (unmorse-region): Autoload it instead.
+
+2002-11-18  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-summary-morse-message): New function.
+       (gnus-summary-wash-map): Bind to `W m'.
+       (gnus-summary-make-menu-bar): Add.
+
+       * nnimap.el (nnimap-request-expire-articles): Compress sequence
+       before storing \Deleted mark on expired articles.
+
+2002-11-17  Markus Rost  <rost@math.ohio-state.edu>  (tiny change)
+
+       * gnus-sum.el (gnus-summary-goto-unread): Doc fix - escape open
+       parens in column 0.
+
+2002-11-17  Juanma Barranquero  <lektu@terra.es>
+
+       * nnweb.el (nnweb-google-create-mapping): Fix typo.
+
+       * nnlistserv.el (nnlistserv-kk-create-mapping): Likewise.
+
+       * gnus-nocem.el (gnus-nocem-liberal-fetch): Likewise.
+
+2002-11-17  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-set-auto-save-file-name): Use
+       make-directory, to avoid the dependence on gnus-util.
+
+2002-11-16  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap-callback-callback-function):
+       (nnimap-callback-buffer): Removed, these cannot be global but must
+       be embedded into the callback.
+       (nnimap-make-callback): New.  Embedd article number, callback and
+       buffer in function.
+       (nnimap-callback, nnimap-request-article-part): Update.
+
+2002-11-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mml.el (mml-preview): Bind message-this-is-mail if it is mail.
+
+2002-11-13  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus.el (gnus-summary-line-format): Document %C.
+
+2002-11-11  Simon Josefsson  <jas@extundo.com>
+
+       * pgg.el (pgg-encrypt, pgg-decrypt, pgg-sign, pgg-verify): Display
+       output when called interactively.
+
+2002-11-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-edit-exit): Kill local variables.
+
+       * message.el (message-draft-coding-system): Improve comment; use
+       mm-auto-save-coding-system for the default value.
+
+       * nndraft.el (nndraft-request-article): Revert to the state before
+       2002-10-29; regexp-quote mail-header-separator.
+
+2002-11-06  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-draft.el (gnus-draft-setup): Set gnus-message-group-art to
+       allow editing of drafts from an nnvirtual group.
+
+2002-11-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nndraft.el (nndraft-request-article): Replace emacs-mule with
+       mm-auto-save-coding-system.
+
+       * message.el (message-draft-coding-system): Default to
+       iso-2022-7bit.
+
+       * mm-util.el (mm-auto-save-coding-system): Undo last change to
+       restore the default value to emacs-mule or escape-quoted.
+
+2002-11-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-encrypt-body): Inhibit encrypting of
+       a delayed or a queued article as well as a draft.
+
+       * gnus-sum.el (gnus-summary-edit-article): Inhibit editing of a
+       delayed or a queued article in the raw format; treat a delayed
+       article as a raw article as well as a draft.
+       (gnus-summary-setup-default-charset): Clear gnus-newsgroup-charset
+       for the delayed group.
+
+       * nndraft.el (nndraft-request-article): Ignore auto save files for
+       a delayed or a queued article; don't bother to decode a queued
+       article; don't bind nnmail-file-coding-system for a queued article.
+
+       * nnmail.el (nnmail-split-fancy-with-parent): Ignore the delayed
+       and the queue group.
+
+2002-11-04  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-group.el (gnus-group-delete-group):
+       gnus-cache-active-hashtb might be void.
+
+2002-11-02  Raymond Scholz  <ray-2002@zonix.de>
+
+       * pgg-gpg.el (pgg-gpg-encrypt-region): Makes PGG respect the
+       setting of the default user ID.
+
+2002-11-01  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-bodies.el (mm-body-encoding): Don't return 8bit for 7bit
+       charset.
+
+2002-10-31  Alex Schroeder  <alex@emacswiki.org>
+
+       * spam-stat.el (spam-stat-process-directory): Add dir to message.
+       (spam-stat-reduce-size): No longer remove words
+       with values close to 0.5, because the default value is 0.2.
+
+2002-10-31  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus-util.el (gnus-user-date-format-alist): Clarify and correct
+       documentation.
+
+2002-10-28  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus-agent.el (gnus-agent-fetched-headers)
+       (gnus-agent-load-fetched-headers)
+       (gnus-agent-save-fetched-headers): Remove variable and two
+       functions.  Kevin Greiner's version of gnus-agent-fetch-headers
+       works better.
+       (gnus-agent-fetch-headers): New implementation from Kevin
+       Greiner.  Uses gnus-agent-article-alist to store information
+       about fetched messages which aren't on the server anymore.  The
+       trick is to return a list of considered messages to the caller,
+       but to only fetch those which haven't been fetched yet.
+
+2002-10-30  Simon Josefsson  <jas@extundo.com>
+
+       * pgg-def.el (pgg-passphrase-cache-expiry): New, defcustom.
+
+       * pgg.el (pgg-passphrase-cache-expiry): Removed.
+
+2002-10-30  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * mm-view.el (mm-w3m-local-map-property): Make it work with older
+       versions of emacs-w3m than 1.3.3.
+
+       * lpath.el: Bind w3m-minor-mode-map.
+
+       * mm-view.el (mm-w3m-mode-command-alist)
+       (mm-w3m-mode-dont-bind-keys, mm-w3m-mode-ignored-keys): Removed.
+       (mm-w3m-mode-map): Undefined for Emacs21 and XEmacs.
+       (mm-setup-w3m): Simplified.
+       (mm-w3m-local-map-property): New function.
+       (mm-inline-text-html-render-with-w3m): Use it.
+
+       * gnus-art.el (gnus-article-wash-html-with-w3m): Use
+       mm-w3m-local-map-property.
+
+2002-10-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-auto-save-coding-system): Default to
+       iso-2022-7bit.
+
+       * nndraft.el (nndraft-request-article): Decode an article using
+       the coding-system emacs-mule if it seems to have been saved using
+       emacs-mule.
+       (nndraft-request-replace-article): Use message-draft-coding-system
+       instead of mm-auto-save-coding-system for the draft or delayed
+       group.
+
+2002-10-28  Josh Huber  <huber@alum.wpi.edu>
+
+       * mml.el (mml-mode-map): Fixed keybindings for mml-secure-*
+       functions.
+
+2002-10-28  Mark A. Hershberger  <mah@everybody.org>
+
+       * mm-url.el (mm-url-insert-file-contents): Make it return the same
+       type values ("url" size) regardless of the values of
+       mm-url-use-external.
+
+2002-10-26  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * nnimap.el (nnimap-request-article-part): Try harder to show
+       group name in debugging message.
+
+2002-10-25  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus-agent.el (gnus-agent-save-fetched-headers): Create
+       directory if it doesn't exist.
+       (gnus-agent-fetch-headers): Remove old cruft that tried to
+       abstain from downloading articles more than once if
+       gnus-agent-consider-all-articles was true.  This is now done
+       properly via the .fetched files.
+
+2002-10-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nndraft.el (nndraft-request-article): Treat delayed articles
+       like drafts.
+
+2002-10-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-agent.el (gnus-agent-load-alist): Fix parenthesis.
+
+2002-10-24  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus-agent.el (gnus-agent-save-alist, gnus-agent-load-alist):
+       Remove unused optional arg DIR and corresponding code.
+
+       * nnimap.el (nnimap-request-article-part): Include group name in
+       debugging output.
+
+2002-10-24  Paul Jarc  <prj@po.cwru.edu>
+
+       * gnus-agent.el (gnus-agent-fetch-headers): Add some comments.
+
+2002-10-23  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus-agent.el (gnus-agent-fetched-headers): New variable,
+       contains range of headers that have been fetched by the agent
+       already.  Compare gnus-agent-article-alist.
+       (gnus-agent-file-header-cache): Like
+       gnus-agent-file-loading-cache, but for gnus-agent-fetched-headers.
+       (gnus-agent-fetch-headers): Improve comment.  Revert to old
+       seen/recent logic.
+       Remember which headers have been fetched before and don't fetch
+       them again the next time round.
+       (gnus-agent-load-fetched-headers)
+       (gnus-agent-save-fetched-headers): New functions, for remembering
+       which headers have been fetched before.
+
+2002-10-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Remove useless bindings.
+
+2002-10-22  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-summary-execute-command): Disable visual
+       features while searching.
+
+2002-10-22  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * pgg.el (pgg-snarf-keys): Do not refer unbound local variables.
+
+2002-10-22  Simon Josefsson  <jas@extundo.com>
+
+       * pgg.el (pgg-encrypt, pgg-decrypt, pgg-sign, pgg-verify)
+       (pgg-snarf-keys): Add.
+
+2002-10-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind bbdb-records.
+
+       * spam.el: Don't autoload bbdb-records.
+
+2002-10-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * spam.el: Set autoload for bbdb-records after loading bbdb-com to
+       prevent inf-loop.
+
+2002-10-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnslashdot.el: Removed some test lines.
+       More test.
+
+2002-10-21  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-agent.el (gnus-agent-fetch-headers): Remove articles that
+       are known to be downloaded already.
+
+2002-10-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-view.el (mm-text-html-renderer-alist): Add w3m-standalone.
+       (mm-text-html-washer-alist): Ditto.
+
+2002-10-19  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * nnheader.el (nnheader-remove-body): Fix an error of detecting
+       boundary between headers and body.
+       * nnml.el (nnml-parse-head): Ditto.
+
+2002-10-20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnslashdot.el (nnslashdot-generate-active): Ignore any bogus
+       entries.
+
+       * gnus-group.el (gnus-fetch-group): Allow an optional
+       specification of the articles to select.
+
+       * gnus-srvr.el (gnus-server-prepare): Removed superfluous cdr.
+
+2002-10-20  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-agent.el (gnus-agent-fetch-group-1): After fetching
+       headers from the group, update variable `articles' to contain
+       only those numbers where headers exist.  (When fetching all
+       articles in a group, Gnus creates lots of numbers where there is
+       no articles.)
+
+2002-10-20  Steve Youngs  <youngs@xemacs.org>
+
+       * pgg-parse.el (pgg-parse-public-key-algorithm-alist): XEmacs
+       doesn't have the 'alist custom type, use cons cells instead.
+       (pgg-parse-symmetric-key-algorithm-alist): Ditto.
+       (pgg-parse-hash-algorithm-alist): Ditto.
+       (pgg-parse-compression-algorithm-alist): Ditto.
+       (pgg-parse-signature-type-alist): Ditto.
+
+       * pgg-gpg.el (pgg-gpg-extra-args): Fix custom mismatch.
+
+       * pgg-pgp5.el (pgg-pgp5-extra-args): Ditto.
+
+       * pgg-pgp.el (pgg-pgp-extra-args): Ditto.
+
+2002-10-19  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap-open-server): Check imap-state in IMAP server
+       buffer.
+
+2002-10-18  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-spec.el (gnus-make-format-preserve-properties)
+       (gnus-xmas-format, gnus-parse-simple-format): Preserve text
+       properties also on XEmacs.  `gnus-xmas-format' is like format but
+       preserves text properties on XEmacs (though it only understands
+       simple format specs).  The variable
+       `gnus-make-format-preserve-properties' controls whether the
+       function is used, and is checked in `gnus-parse-simple-format'.
+       Patch by Paul Moore <gustav@morpheus.demon.co.uk>.
+
+       * gnus-agent.el (gnus-agent-fetch-articles): More debugging
+       output.
+       (gnus-agent-consider-all-articles): New variable.
+       (gnus-agent-get-undownloaded-list): Comment that marks todo item.
+       (gnus-agent-fetch-headers): Depending on
+       gnus-agent-consider-all-articles, maybe get all articles.
+       (gnus-category-predicate-alist, gnus-agent-read-p): New predicate
+       `read'.
+       (gnus-predicate-imples-unread): New function.
+       (gnus-agent-fetch-headers): Optimize to call
+       gnus-list-of-unread-articles if that is sufficient.
+       Check unseen and recent instead of seen and recent.
+       (gnus-agent-fetch-headers): Abstain from calling
+       gnus-list-range-intersection if range (a . b) would have (> a b).
+
+2002-10-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-send-mail): Make it possible to perform
+       edebug-defun.
+
+2002-10-18  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-art.el (gnus-button-man-handler): Change default to
+       `manual-entry' (defined in both emacsen).
+       (gnus-button-man-handler): Remove emacsen difference and use
+       `manual-entry'.
+
+2002-10-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * spam.el: Wrap autoload settings for bbdb-records,
+       executable-find and ifile-spam-filter with eval-and-compile.
+       (spam-display-buffer-contents): Remove.
+       (spam-bogofilter-score): Merge spam-display-buffer-contents.
+
+2002-10-17  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-display-buffer-contents): New function.
+       (spam-bogofilter-score): Use spam-display-buffer-contents, patch
+       from Katsumi Yamaoka <yamaoka@jpl.org>.
+
+2002-10-17  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * nnheader.el (nnheader-parse-naked-head): New function.
+       (nnheader-parse-head): Use the above function, in order to handle
+       continuation lines properly.
+       (nnheader-remove-body): New function.
+       (nnheader-remove-cr-followed-by-lf): New function.
+       (nnheader-ms-strip-cr): Use the above function.
+
+       * gnus-agent.el (gnus-agent-regenerate-group): Call
+       `nnheader-remove-body'; use `nnheader-parse-naked-head' instead of
+       `nnheader-parse-head'.
+       * gnus-cache.el (gnus-cache-possibly-enter-article): Ditto.
+
+       * gnus-msg.el (gnus-inews-yank-articles): Do not unfold
+       continuation lines by itself; call `nnheader-parse-naked-head'
+       instead of `nnheader-parse-head'.
+       * nndiary.el (nndiary-parse-head): Ditto.
+       * nnfolder.el (nnfolder-parse-head): Ditto.
+       * nnimap.el (nnimap-retrieve-headers-progress): Ditto.
+       * nnmaildir.el (nnmaildir--update-nov): Ditto.
+       * nnml.el (nnml-parse-head): Ditto.
+
+2002-10-17  Steve Youngs  <youngs@xemacs.org>
+
+       * gnus-art.el (gnus-button-man-handler): Add 'manual-entry' for
+       XEmacs, default to it if featurep 'xemacs.
+
+2002-10-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * spam-stat.el: Check for the existence of hash functions instead
+       of the Emacs version to decide whether to load cl.  Suggested by
+       Kai Großjohann.
+
+2002-10-15  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-agent.el (gnus-agent-fetch-selected-article): Open history
+       if it isn't open yet.
+
+2002-10-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el: Require mm-url only when compiling.
+       (gnus-group-fetch-charter): Require mm-url.
+
+       * spam-stat.el: Require cl for the functions gethash,
+       hash-table-count, make-hash-table and mapc for Emacs 20.
+       (puthash): Alias to cl-puthash for Emacs 20.
+       (with-syntax-table): New macro for Emacs 20.
+
+2002-10-12  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-spec.el (gnus-pad-form): Use gnus-string-width-function.
+
+2002-10-11  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-check-ifile): Added ifile as a spam checking
+       backend, and spam-use-ifle as the variable to toggle that check.
+
+2002-10-12  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-beginning-of-line): New variable.
+       (message-beginning-of-line): Use it.
+
+2002-10-11  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el: More compilation fixes for BBDB.
+
+       * spam-stat.el: Added code from Alex Schroeder <alex@gnu.org>.
+       (spam-stat-reduce-size): Interactive.
+       (spam-stat-reset): New function.
+       (spam-stat-save): Interactive.
+
+2002-10-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el: Autoload gnus-delay-initialize.
+
+       * message.el: Autoload gnus-delay-article.
+
+2002-10-11  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-spec.el (gnus-balloon-face-function): Use the help-echo
+       text property in Emacs.
+
+2002-10-11  Simon Josefsson  <jas@extundo.com>
+
+       * mml2015.el (mml2015-pgg-decrypt, mml2015-pgg-clear-decrypt)
+       (mml2015-pgg-verify, mml2015-pgg-clear-verify): Remove CR.
+
+       * mml1991.el (mml1991-pgg-sign): Remove CR.
+
+2002-10-10  Simon Josefsson  <jas@extundo.com>
+
+       * mml2015.el (mml2015-pgg-decrypt): Set gnus details even when
+       decrypt failed.
+       (mml2015-trust-boundaries-alist): Removed.
+       (mml2015-gpg-extract-signature-details): Don't use it.
+       (mml2015-unabbrev-trust-alist): New.
+       (mml2015-gpg-extract-signature-details): Use it.
+
+2002-10-10  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el: Compilation fixes, spam-check-bbdb function is nil if no
+       BBDB installed.
+
+       * spam-stat.el: Added code from Alex Schroeder <alex@gnu.org> to do
+       statistical analysis of spam in Lisp only.
+
+2002-10-10  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap-open-server): Re-open server if it isn't in
+       auth, selected or examine state.
+
+       * pgg-gpg.el (pgg-gpg-verify-region): Filter out stuff into output
+       buffer and error buffer depending on type of information.
+
+       * mml2015.el (mml2015-gpg-extract-signature-details): Parse
+       --status-fd stuff even if gpg.el is not used (revert earlier
+       change).
+       (mml2015-pgg-{clear-,}verify): Store both output and errors as
+       gnus details.
+       (mml2015-pgg-{clear-,}verify): Extract signature info from errors
+       buffer.
+
+       * pgg.el (pgg-verify-region): Use it.
+
+       * pgg-def.el (pgg-query-keyserver): New variable.
+
+       * pgg.el (pgg-decrypt-region): Bind pgg-default-user-id to
+       key-identifier in packet.  Is this a good idea?
+
+       * mml.el (mml-mode-map): Add security commands that operates on
+       MIME parts.
+       (mml-menu): And menu items for them.
+
+       * mml1991.el (mml1991-pgg-encrypt): Remove headers.
+
+       * mml.el (mml-parse-1): Support sender in #secure tags.
+
+       * mml1991.el (mml1991-pgg-sign): Only use message-sender if it is
+       defined.
+
+       * mml-sec.el (mml-smime-encrypt-buffer): Warn about combined signing.
+       (mml-pgp-encrypt-buffer): Support combined signing.
+
+       * mml1991.el (mml1991-mailcrypt-encrypt): Support combined signing.
+       (mml1991-gpg-encrypt): Ditto.
+       (mml1991-pgg-encrypt): Ditto.
+       (mml1991-encrypt): Pass sign parameter.
+
+       * mml-sec.el (mml-signencrypt-style-alist): Defcustom.
+       (mml-signencrypt-style): Mention the variable.
+
+2002-10-09  Simon Josefsson  <jas@extundo.com>
+
+       * mml1991.el (mml1991-pgg-sign): Bind pgg-default-user-id, not
+       pgg-gpg-user-id.
+
+       * pgg.el (pgg-insert-url-with-w3): Ignore errors.
+       (pgg-fetch-key-function): Nil if w3 is not installed.
+
+2002-10-08  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-agent.el (gnus-agent-fetch-selected-article): Bind
+       gnus-agent-current-history.
+
+2002-10-06  Simon Josefsson  <jas@extundo.com>
+
+       * imap.el (imap-parse-status): Don't use read to read token.
+
+2002-10-05  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-agent.el (gnus-agent-fetch-selected-article): Do nothing
+       for methods not covered by the agent, and when unplugged.
+
+2002-10-05  Simon Josefsson  <jas@extundo.com>
+
+       * pgg-gpg.el (pgg-gpg-encrypt-region): Query passphrase when
+       signing.
+
+       * gnus-agent.el (gnus-agent-read-servers): If getting method from
+       a named server fails, ignore the server.
+
+       * mml1991.el (mml1991-pgg-sign): Do QP.
+
+       * pgg-gpg.el (pgg-gpg-encrypt-region): Make signencrypt really
+       work.
+
+2002-10-04  Simon Josefsson  <jas@extundo.com>
+
+       * pgg-gpg.el (pgg-gpg-encrypt-region): Make signencrypt work.
+
+       * pgg-pgp.el (pgg-pgp-verify-region): Inline
+       binary-write-decoded-region from MEL.
+
+       * pgg.el (pgg-encrypt-region): Support sign.
+
+       * pgg-gpg.el (pgg-gpg-encrypt-region): Ditto.
+
+       * mml2015.el (mml2015-pgg-encrypt): Ditto.
+
+       * pgg.el, pgg-def.el, pgg-parse.el, pgg-gpg.el, pgg-pgp5.el,
+       pgg-pgp6.el: Moved from ../pgg/.  Modifications compared to EMIKO
+       branch where PGG was taken from in the ChangeLog entries below.
+
+2002-10-01  Simon Josefsson  <jas@extundo.com>
+
+       * pgg-pgp.el: Don't require mel.  Don't use luna.
+       (pgg-scheme-pgp-instance, pgg-make-scheme-pgp): Remove.
+       (pgg-pgp-process-region): Use expand-file-name instead of concat.
+       (pgg-pgp-process-region): Don't use binary-funcall.
+
+       * pgg-pgp5.el (pgg-pgp5-process-region): Don't use binary-funcall.
+
+       * pgg-gpg.el (pgg-gpg-process-region): Use expand-file-name
+       instead of concat.
+
+       * pgg-pgp5.el (pgg-pgp5-process-region): Ditto.
+
+2002-09-29  Simon Josefsson  <jas@extundo.com>
+
+       * pgg-parse.el (pgg-char-int, pgg-string-as-unibyte): Prevent byte
+       compile warnings.
+
+       * pgg.el (pgg-decrypt-region): Don't parse packet.
+
+       * pgg.el, pgg-gpg.el, pgg-pgp5.el: Don't depend on luna.el.
+
+2002-09-29  Daiki Ueno  <ueno@unixuser.org>
+
+       * pgg.el: Remove dependency on calist.el.
+
+2002-09-28  Simon Josefsson  <jas@extundo.com>
+
+       * pgg.el (pgg-temporary-file-directory): New variable.
+       (pgg-verify-region): Don't assume set-buffer-multibyte exists.
+
+       * pgg-pgp5.el (pgg-pgp5-process-region, pgg-scheme-verify-region)
+       (pgg-scheme-snarf-keys-region): Use pgg-temporary-file-directory.
+
+       * pgg-parse.el (pgg-char-int): Defalias.
+       (pgg-format-key-identifier, pgg-byte-after, pgg-read-byte)
+       (pgg-read-bytes, pgg-read-body): Use it.
+       (pgg-decode-packets): Don't use MEL, use base64-*.
+       (pgg-parse-armor): Don't assume set-buffer-multibyte exists.
+       (pgg-string-as-unibyte): Defalias.
+       (pgg-parse-armor-region): Use it.
+
+       * pgg-gpg.el (pgg-gpg-process-region): Use
+       pgg-temporary-file-directory.
+
+       * luna.el: Don't def-edebug.
+
+       * pgg-pgp5.el (pgg-scheme-verify-region): Inline
+       binary-write-decoded-region from MEL.
+
+       * pgg-pgp5.el, pgg-gpg.el: Don't require mel.
+
+       * alist.el, calist.el: Don't require product/APEL.
+
+       * pgg-parse.el (top-level): Remove dependency on static.el,
+       pccl.el, mel.el.
+       (pgg-parse-crc24, pgg-parse-crc24-string): Only define if
+       `define-ccl-program' is boundp, instead of using broken.
+
+2002-10-01  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-required-mail-headers): Remove Lines:.
+
+2002-10-03  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-group.el (gnus-group-fetch-charter,
+       gnus-group-fetch-control): Prompt for group if given a prefix
+       argument.
+       * gnus-sum.el: Add gnus-group-fetch-charter and
+       gnus-group-fetch-control to summary key map and menu.
+
+2002-10-03  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir--group-maxnum-art): Fix maximum article
+       number when there are no articles.
+
+2002-10-03  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-agent.el (gnus-agent-summary-fetch-group): Optional prefix
+       arg ALL means to fetch all articles, not only downloadable ones.
+       (gnus-agent-fetch-selected-article): New function for
+       gnus-select-article-hook or gnus-mark-article-hook.
+
+2002-10-02  Peter von der Ahe  <nospam2159@daimi.au.dk>
+
+       * gnus-ems.el (gnus-x-splash): Set coding-system-for-read to
+       raw-text.
+
+2002-09-30  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el: Merged changes from pinard@iro.umontreal.ca (François
+       Pinard).
+       Major revamp of the code, documentation is in comments in the file
+       for now.
+
+2002-09-30  Simon Josefsson  <jas@extundo.com>
+
+       * mml2015.el (mml2015-pgg-clear-verify): Verifying in a unibyte
+       buffer seem to be needed?
+
+2002-09-29  Simon Josefsson  <jas@extundo.com>
+
+       * mml1991.el (pgg-output-buffer, pgg-errors-buffer): Prevent byte
+       compile warnings.
+
+       * mml1991.el (mml1991-function-alist): Add pgg.
+       (mml1991-pgg-sign, mml1991-pgg-encrypt): New functions.
+       (mml1991-pgg-encrypt): Fix recipients querying.
+
+2002-09-28  David Edmondson  <dme@dme.org>
+
+       * mml2015.el (autoload): Autoload correct files.
+
+2002-09-28  Simon Josefsson  <jas@extundo.com>
+
+       (mml2015-pgg-decrypt, mml2015-pgg-verify): Make sure either nil or
+       handle is returned.
+
+2002-09-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-start.el (gnus-fixup-nnimap-unread-after-getting-new-news):
+       Protect against non-existent of `nnimap-mailbox-info'.
+
+2002-09-27  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-start.el (gnus-fixup-nnimap-unread-after-getting-new-news): New.
+       (gnus-setup-news-hook): Use it.
+       (gnus-after-getting-new-news-hook): Ditto.
+
+       * nnimap.el (nnimap-fixup-unread-after-getting-new-news): Remove.
+
+2002-09-27  Mats Lidell  <matsl@contactor.se>
+
+       * gnus-art.el (gnus-article-mode-syntax-table): Replace "-" to " ".
+
+2002-09-27  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * gnus-sum.el (gnus-nov-parse-line): When an error is signaled in
+       the part to decode encoded words, use raw words instead of decoded
+       words.
+
+2002-09-26  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnimap.el (nnimap-update-unseen): Use gnus-gethash-safe.
+
+       * mm-view.el (mm-w3m-mode-ignored-keys): New variable.
+       (mm-setup-w3m): Use it.
+
+2002-09-27  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-art.el (gnus-article-mode-syntax-table): Make M-. work in
+       article buffers.
+
+       * nnimap.el (nnimap-fixup-unread-after-getting-new-news): Autoload
+       it just in case.
+       (nnimap-update-unseen): New function; update unseen count in
+       `n-m-info'.
+       (nnimap-close-group): Call it.
+
+       * gnus-start.el (gnus-setup-news-hook): Add n-f-u-a-g-n-n.
+       (gnus-after-getting-new-news-hook): Ditto.
+
+       * nnimap.el (nnimap-retrieve-groups): Move the quick mail check
+       message into verboselevel 9.  Change slow mail check message.
+       (nnimap-retrieve-groups): Use prefixed names in n-mailbox-info.
+       (nnimap-fixup-unread-after-getting-new-news): New function, to be
+       used as a hook after getting new mail.
+
+2002-09-26  Simon Josefsson  <jas@extundo.com>
+
+       * imap.el (imap-parse-resp-text-code): The UNSEEN value in
+       SELECT/EXAMINE is first unseen article, not number of unseen
+       articles.  Make them distinct by renaming the former to
+       `first-unseen' instead of `unseen'.
+
+       * nnimap.el (nnimap-retrieve-groups): Get uidvalidity and unseen
+       too.
+       (nnimap-retrieve-groups): Don't used cached data if uidvalidity
+       changed.
+       (nnimap-retrieve-groups): Store uidvalidity and unseen data too.
+
+       * gnus-int.el (gnus-server-unopen-status): Defcustom.
+
+       * mml-sec.el (mml-signencrypt-style): Docstring to font-lock
+       better.
+
+       * mml2015.el (mml2015-pgg-decrypt): Only add security information
+       if dissecting resulting buffer actually had any information.
+
+2002-09-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el (gnus-group-sort-by-method): Remove `symbol-name'
+       because the function `string<' allows symbols.
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Ditto.
+
+2002-09-25  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-forward-make-body): Revert an early change
+       because 8-bit utf-8 emails.
+
+2002-09-25  Björn Torkelsson  <torkel@acc.umu.se>
+
+       * gnus-agent.el (gnus-category-line-format): Doc fixes (mostly added
+       links to Info).
+       * gnus-art.el (gnus-treat-highlight-signature):
+       * gnus-art.el (gnus-treat-buttonize):
+       * gnus-art.el (gnus-treat-buttonize-head):
+       * gnus-art.el (gnus-treat-emphasize):
+       * gnus-art.el (gnus-treat-strip-cr):
+       * gnus-art.el (gnus-treat-unsplit-urls):
+       * gnus-art.el (gnus-treat-leading-whitespace):
+       * gnus-art.el (gnus-treat-hide-headers):
+       * gnus-art.el (gnus-treat-hide-boring-headers):
+       * gnus-art.el (gnus-treat-hide-signature):
+       * gnus-art.el (gnus-treat-fill-article):
+       * gnus-art.el (gnus-treat-hide-citation):
+       * gnus-art.el (gnus-treat-hide-citation-maybe):
+       * gnus-art.el (gnus-treat-strip-list-identifiers):
+       * gnus-art.el (gnus-treat-strip-pgp):
+       * gnus-art.el (gnus-treat-strip-pem):
+       * gnus-art.el (gnus-treat-strip-banner):
+       * gnus-art.el (gnus-treat-highlight-headers):
+       * gnus-art.el (gnus-treat-highlight-citation):
+       * gnus-art.el (gnus-treat-date-ut):
+       * gnus-art.el (gnus-treat-date-local):
+       * gnus-art.el (gnus-treat-date-english):
+       * gnus-art.el (gnus-treat-date-lapsed):
+       * gnus-art.el (gnus-treat-date-original):
+       * gnus-art.el (gnus-treat-date-iso8601):
+       * gnus-art.el (gnus-treat-date-user-defined):
+       * gnus-art.el (gnus-treat-strip-headers-in-body):
+       * gnus-art.el (gnus-treat-strip-trailing-blank-lines):
+       * gnus-art.el (gnus-treat-strip-leading-blank-lines):
+       * gnus-art.el (gnus-treat-strip-multiple-blank-lines):
+       * gnus-art.el (gnus-treat-unfold-headers):
+       * gnus-art.el (gnus-treat-fold-headers):
+       * gnus-art.el (gnus-treat-fold-newsgroups):
+       * gnus-art.el (gnus-treat-overstrike):
+       * gnus-art.el (gnus-treat-display-xface):
+       * gnus-art.el (gnus-treat-display-smileys):
+       * gnus-art.el (gnus-treat-from-picon):
+       * gnus-art.el (gnus-treat-mail-picon):
+       * gnus-art.el (gnus-treat-newsgroups-picon):
+       * gnus-art.el (gnus-treat-body-boundary):
+       * gnus-art.el (gnus-treat-capitalize-sentences):
+       * gnus-art.el (gnus-treat-fill-long-lines):
+       * gnus-art.el (gnus-treat-play-sounds):
+       * gnus-art.el (gnus-treat-translate):
+       * gnus-art.el (gnus-treat-x-pgp-sig):
+       * gnus-art.el (gnus-mime-button-line-format):
+       * gnus-art.el (gnus-button-man-level):
+       * gnus-art.el (gnus-button-emacs-level):
+       * gnus-cus.el (gnus-group-parameters):
+       * gnus-gl.el (bbb-build-mid-scores-alist):
+       * gnus-group.el (gnus-group-line-format):
+       * gnus-mlspl.el (gnus-group-split-setup):
+       * gnus-mlspl.el (gnus-group-split):
+       * gnus-msg.el (gnus-mailing-list-groups):
+       * gnus-msg.el (gnus-posting-styles):
+       * gnus-nocem.el (gnus-nocem-issuers):
+       * gnus-score.el (gnus-score-regexp-bad-p):
+       * gnus-srvr.el (gnus-server-line-format):
+       * gnus-topic.el (gnus-topic-line-format):
+       * gnus.el (gnus-summary-line-format):
+       * mail-source.el (mail-sources):
+       * message.el (message-subscribed-address-file):
+       * nnmail.el (nnmail-split-fancy): ???
+
+2002-09-24  Evgeny Roubinchtein  <zhenya@freeshell.org>
+
+       * mail-source.el (mail-source-run-script): Use `functionp' to test
+       whether the argument `script' is in fact a function.
+       (mail-sources): Adjust the defcustom to allow users to specify a
+       function or a string as the value of the `:prescript' and
+       `:postscript' arguments of the `file' and `pop3' mail sources.
+
+2002-09-25  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir--grp-add-art): Fix minimum article
+       number when article 1 does not exist.
+
+2002-09-25  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button-handle-apropos-variable): Fall back to
+       apropos if apropos-variable does not exist.
+       (gnus-button-guessed-mid-regexp)
+       (gnus-button-handle-describe-prefix, gnus-button-alist): Better
+       regexes.
+       (gnus-button-handle-describe-function)
+       (gnus-button-handle-describe-variable): Doc fix.
+       (gnus-button-handle-describe-key, gnus-button-handle-apropos)
+       (gnus-button-handle-apropos-command): Doc fix.
+
+2002-09-25  Mark A. Hershberger  <mah@everybody.org>  (tiny change)
+
+       * nnrss.el (nnrss-save-server-data): Save nnrss-group-alist in
+       the file.
+
+2002-09-24  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-start.el (gnus-1): Create nndraft:queue, nndraft:drafts.
+
+2002-09-24  Simon Josefsson  <jas@extundo.com>
+
+       * mml2015.el (top-level): Require mm-util for mm-make-temp-file.
+       (mml2015-use): Prefer PGG if installed.
+       (mml2015-function-alist): Add PGG wrappers.
+       (mml2015-gpg-extract-signature-details): Check mml2015-use too.
+       (mml2015-gpg-extract-signature-details): PGG strips "gpg: "
+       prefix, make regexp optionally skip it.
+       (mml2015-pgg-decrypt, mml2015-pgg-clear-decrypt)
+       (mml2015-pgg-verify, mml2015-pgg-clear-verify, mml2015-pgg-sign)
+       (mml2015-pgg-encrypt): New functions.
+       (defvar, autoload): Prevent byte-compile warnings.
+
+2002-09-24  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * gnus-art.el (article-strip-banner): Check for the existence of
+       from header.
+
+2002-09-23  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button-guessed-mid-regexp): Improved regexp.
+       (gnus-button-alist): Improved regexp for
+       gnus-button-handle-mid-or-mail (false positives), fixed
+       gnus-button-handle-man entries.
+
+2002-09-23  Josh Huber  <huber@alum.wpi.edu>
+
+       * nnmaildir.el (nnmaildir--update-nov): Fix wrong-type error when
+       nnmail-extra-headers is non-nil.
+
+2002-09-23  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el: Store article numbers persistently.  General
+       revision.
+       (nnmaildir-request-expire-articles): Handle 'immediate and 'never
+       for nnmail-expiry-wait; delete instead of moving if 'force is
+       given.
+
+2002-09-23  Simon Josefsson  <jas@extundo.com>
+       Trivial fix from beaker@iavmb.pl (Krzysztof Jędruczyk).
+
+       * smime.el (smime-sign-buffer): Get key and extra certs.
+       (smime-get-key-with-certs-by-email): Utility function.
+
+2002-09-21  ShengHuo ZHU  <zsh@cs.rochester.edu>
+       Trivial patch from Micha Wiedenmann <mw-u1@gmx.de>
+
+       * gnus-soup.el (gnus-soup-add-article): Mark as read only when the
+       article exists.
+
+2002-09-20  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-next-group): Switch to the summary buffer.
+
+2002-09-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-art.el (gnus-button-handle-custom)
+       (gnus-button-handle-mid-or-mail)
+       (gnus-button-handle-describe-{function,variable,key})
+       (gnus-button-handle-apropos{,command,variable}): New functions.
+       (gnus-button-prefer-mid-or-mail,gnus-button-guessed-mid-regexp)
+       (gnus-button-{man,emacs,mail}-level): New variables.
+       (gnus-button-alist): Use the above to buttonize emacs and mail
+       related links.
+
+2002-09-18  Juanma Barranquero  <lektu@terra.es>
+
+       * gnus-int.el (gnus-status-message): Fix spacing.
+
+       * imap.el (imap-continuation): Fix typos.
+
+2002-09-18  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-configure-posting-styles): Sort results.
+
+       * gnus-art.el (gnus-article-reply-with-original): Correct
+       with-current-buffer scope.
+
+       * message.el (message-completion-alist): Add Reply-To, From, etc.
+
+2002-09-18  Nevin Kapur  <nevin@jhu.edu>
+
+       * nnimap.el (nnimap-request-expire-articles): Make flag setting
+       conditional.
+
+2002-09-17  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap-expiry-target): Don't search for which
+       articles exists here.
+       (nnimap-request-expire-articles): Do it here instead.  Only expire
+       when articles are found.  Suggested by Nevin Kapur
+       <nevin@jhu.edu>.
+
+2002-09-17  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.el (message-strip-subject-trailing-was)
+       (message-change-subject, message-add-archive-header)
+       (message-xpost-fup2-header, message-xpost-insert-note)
+       (message-xpost-fup2, message-reduce-to-to-cc): New functions
+       adopted from message-utils.el.  Add functions to the keymap, mode
+       describtion and menu.
+       (message-change-subject, message-xpost-fup2): Signal error if
+       current header is empty.
+       (message-xpost-insert-note): Changed insert position.
+       (message-archive-note): Ensure to insert note in message body (not
+       in head).
+       (message-archive-header, message-archive-note)
+       (message-xpost-default, message-xpost-note, message-fup2-note)
+       (message-xpost-note-function): New variables adopted from
+       message-utils.el.  Changed some doc-strings.
+       (message-mark-insert-{begin,end}): Rename from
+       message-{begin,end}-inserted-text-mark (message-utils.el), changed
+       values.
+       (message-subject-trailing-was-query)
+       (message-subject-trailing-was-ask-regexp)
+       (message-subject-trailing-was-regexp): New variables.
+       (message-to-list-only): Added doc-string and menu entry.
+
+       * message-utils.el: Removed.  Functions are now in message.el.
+
+2002-09-16  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-reply-with-original,
+       gnus-article-followup-with-original): Switch to
+       gnus-summary-buffer before reply/followup.
+
+2002-09-15  John Paul Wallington  <jpw@shootybangbang.com>
+
+       * gnus-sum.el (gnus-summary-toggle-header): The article window may
+       not exist.  Toggle it anyway.
+
+2002-09-13  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-copy-article-buffer): Bind mail-header-separator.
+
+       * gnus-art.el (article-fill-long-lines): Fill-paragraph properly.
+       Trivial patch from Urban Engberg <ue@ccieurope.com>.
+
+       * rfc2047.el (message-posting-charset): Defvar it.
+       (rfc2047-charset-encoding-alist): Use B for iso-8859-7 and
+       iso-8859-8.  Fix doc.  Suggested by Dave Love <fx@gnu.org>.
+
+       * mail-source.el (mail-source-fetch): Hide password.
+
+       * gnus-sum.el (gnus-summary-next-group): Semi-exit only when needed.
+
+2002-09-12  John Paul Wallington  <jpw@shootybangbang.com>
+
+       * gnus.el (gnus-visual, gnus-meta): Fix typo.
+
+2002-09-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-address-banner-alist): Doc fix.
+
+2002-09-11  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap-expiry-target): Only expiry-target existing articles.
+       (nnimap-split-rule): Doc fix.
+       (nnimap-request-expire-articles): Cleanup code.
+
+2002-09-11  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * gnus-art.el (gnus-article-address-banner-alist): New option.
+       (article-strip-banner): Refer the above option to split banners of
+       free mail servers, when no group parameter is specified.
+
+2002-09-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nntp.el (nntp-wait-for-string): Check for a process in the
+       current buffer instead of `nntp-server-buffer'.
+
+2002-09-09  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-art.el (gnus-button-man-handler): New variable.
+       (gnus-button-alist): Use g-b-handle-man.
+       (gnus-button-handle-man): New, call g-b-man-handler.
+
+2002-09-08  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-art.el (gnus-button-alist): Buttonize man page links.
+
+2002-09-07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-dumbquotes-map): Add \230.
+
+2002-09-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-srvr.el (gnus-browse-make-menu-bar): Add "d".
+
+       * gnus-sum.el (gnus-summary-limit-to-unseen): New command and
+       keystroke.
+
+       * gnus-srvr.el (gnus-browse-describe-group): New command and
+       keystroke.
+
+2002-09-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-treat-body-boundary): Don't quote a
+       value for gnus-decoration property.
+
+2002-09-06  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * nnmail.el (nnmail-cache-fetch-group): Don't return "" (empty
+       string) as group name in case we have a CRLF in the file.
+
+2002-09-04  Jesper Harder  <harder@ifa.au.dk>
+
+       * rfc1843.el (rfc1843-decode-loosely): Move to mime customization
+       group.
+       (rfc1843-decode-hzp): Do.
+       (rfc1843-newsgroups-regexp): Do.
+
+2002-09-04  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-canlock-generate): Make sure sha1 doesn't
+       call external programs.
+
+2002-09-03  Simon Josefsson  <jas@extundo.com>
+
+       * nntp.el (nntp-wait-for-string): Don't infloop if process died.
+
+       * gnus-agent.el (gnus-agent-batch): Add doc.
+
+2002-09-03  Josh Huber  <huber@alum.wpi.edu>
+
+       * gnus-msg.el (gnus-summary-handle-replysign): Change the order we
+       check for signed and encrypted parts.
+       * mml.el (mml-parse-1): Correct small typo which preventing
+       setting recipients in a secure tag.
+
+2002-09-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-util.el (mm-coding-system-priorities): Default to a list of
+       iso-2022-jp and others for the Japanese environment.
+
+2002-09-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-util.el (gnus-frame-or-window-display-name): Exclude
+       invalid display names.
+
+2002-08-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-group.el (gnus-group-fetch-control): Fix typo in last
+       commit.
+
+2002-08-26  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.el (gnus-group-charter-alist): New option.
+       (gnus-group-fetch-control-use-browse-url): New option.
+
+       * gnus-group.el (gnus-group-fetch-charter): New function.
+       (gnus-group-fetch-control): New function.
+       Add them to the keymap and menu.  Require mm-url.
+
+2002-08-30  Alex Schroeder  <alex@emacswiki.org>
+
+       * gnus-mlspl.el (gnus-group-split-fancy): Doc fix.
+
+2002-08-29  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-group.el (gnus-group-make-menu-bar): Add ellipses to menu
+       items expecting user interaction.
+
+       * gnus-topic.el (gnus-topic-make-menu-bar): Do.
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Do.
+
+       * gnus-srvr.el (gnus-server-make-menu-bar): Do.
+
+       * mml.el (mml-menu): Do.
+
+2002-08-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mail-source.el (mail-source-touch-pop): New function.
+
+       * message.el (message-smtpmail-send-it): New function.
+       (message-send-mail-function): Add it for a candidate.
+
+2002-08-27  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-msg.el (posting-charset-alist): Use
+       gnus-define-group-parameter instead of defcustom.
+       (gnus-put-message): Handle SPC in GCC.
+       (gnus-inews-insert-gcc): Ditto.
+       (gnus-inews-insert-archive-gcc): Ditto.
+
+2002-08-26  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-agent.el (gnus-agent-auto-agentize-methods): New variable.
+       (gnus-agentize): Auto agentize all nntp and nnimap groups.
+       (gnus-agent-possibly-save-gcc): Autoload.
+       Suggested by (KOSEKI Yoshinori) <kose@meadowy.org>.
+
+2002-08-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (gnus-other-frame-function): New user option.
+       (gnus-other-frame): Use it; add a doc-string; make it work with
+       the gnuclient program.
+
+       * gnus-util.el (gnus-frame-or-window-display-name): New function.
+
+       * lpath.el: Fbind `frame-parameter', `make-frame-on-display',
+       `device-connection' and `dfw-device'.
+
+2002-08-22  Jochen Hein  <jochen@jochen.org>  (tiny change)
+
+       * gnus-art.el (gnus-emphasis-alist): Strikethru had a lot of false
+       positives, make it stricter.
+
+2002-08-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (gnus-other-frame): Trivial fix.
+
+2002-08-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (gnus-other-frame-parameters): New user option.
+       (gnus-other-frame-object): New variable.
+       (gnus-other-frame): Make it search for existing Gnus frame; don't
+       read new news; delete frame on exit.
+
+       * gnus-util.el (gnus-select-frame-set-input-focus): New function.
+
+       * lpath.el: Fbind w32-focus-frame and x-focus-frame.
+
+2002-08-20  小関 吉則 (KOSEKI Yoshinori)  <kose@meadowy.org>
+
+       * message.el (message-set-auto-save-file-name): Add support for
+       the Cygwin Emacs; the system-type is `cygwin'.
+       * nnheader.el (nnheader-file-name-translation-alist): Ditto.
+
+2002-08-20  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-button-url-regexp): Use POSIX regexp if possible.
+
+       * nnmh.el (nnmh-request-list-1): Use %.0f instead of %d to
+       avoid arithmetic errors.
+
+2002-08-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el: Don't fbind `gnus-article-replace-with-quoted-text'.
+
+2002-08-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-ignored-supersedes-headers): Add X-Hashcash.
+       (message-ignored-resent-headers): Add envelope From.
+
+2002-08-18  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.el (gnus-summary-line-format): Document %k specifier.
+
+2002-08-17  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-sum.el (gnus-summary-line-message-size): New function.
+       (gnus-summary-line-format-alist): Use it.
+
+2002-08-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-make-date-line): Refer to the value for
+       `gnus-article-time-format' in the summary buffer.
+
+       * message.el (message-cite-prefix-regexp): Exclude ":" and "»".
+
+2002-08-14  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-art.el (gnus-button-alist): Use ' not ` for default value
+       quoting.
+       (gnus-button-alist): Fix doc.
+       (gnus-header-button-alist): Use ' not ` for default value quoting.
+       (gnus-header-button-alist): Don't inline gnus-button-url-regexp,
+       rationale similar to 2002-05-01 change.
+       (gnus-article-add-buttons-to-head): Evaluate expression.
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Add MIME button option.
+
+2002-08-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-font-lock-keywords): Refer to the value for
+       `message-cite-prefix-regexp' dynamically.
+
+2002-08-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-decode-header-methods): Doc fix.
+
+2002-08-12  Simon Josefsson  <jas@extundo.com>
+
+       * imap.el (imap-shell-open): Allow non-list `imap-shell-program'.
+       (imap-shell-open): Skip initial junk before IMAP greeting.
+
+2002-08-11  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message-utils.el (message-xpost-default)
+       (message-xpost-fup2-header, message-xpost-fup2): Fixed Typos.
+
+2002-08-09  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-canlock-password): Set
+       canlock-password-for-verify to newly generated canlock-password.
+       When Emacs is restarted, Custom makes sure this is set, but during
+       the same session we must set it manually.
+
+2002-08-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * yenc.el: New file.
+
+       * mm-uu.el (mm-uu-yenc-decode-function): New variable.
+       (mm-uu-type-alist): Add yenc.
+       (mm-uu-yenc-filename): New function.
+       (mm-uu-yenc-extract): New function.
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding): Add yenc.
+
+2002-08-06  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * dgnushack.el (merge): Don't use coerce.
+
+2002-05-27  Jesper Harder  <harder@ifa.au.dk>
+
+       * mailcap.el (mailcap-mime-data): Test window-system rather than
+       mm-device-type.
+       (mailcap-mime-data): Call xdvi and gv with "-safer".
+
+       * mm-util.el: Don't define mm-device-type.
+
+2002-08-05  Simon Josefsson  <jas@extundo.com>
+
+       * mm-util.el (mm-coding-system-priorities): coding-system type not
+       supported everywhere.
+
+2002-08-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Bumped version number.
+
+2002-08-04 01:48:57  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.07 is released.
+
+2002-08-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-thread-sort-functions): Doc fix.
+       (gnus-article-sort-functions): Doc fix.
+       (t): New keystroke.
+       (gnus-article-sort-by-random): New function.
+       (gnus-thread-sort-by-random): New function.
+
+2002-08-02  Scott A Crosby  <scrosby@cs.rice.edu>
+
+       * gnus-logic.el (gnus-advanced-integer): Swap arguments in
+       funcall.
+
+2002-07-31  Danny Siu  <dsiu@adobe.com>
+
+       * nnimap.el (nnimap-split-articles): Do not call nnmail-fetch-field
+       when splitting malformed messages without message-id.
+
+2002-07-28  Niklas Morberg  <niklas.morberg@axis.com>
+
+       * nnweb.el (nnweb-type, nnweb-type-definition)
+       (nnweb-gmane-create-mapping, nnweb-gmane-wash-article)
+       (nnweb-gmane-search, nnweb-gmane-identity): Added gmane
+       functionality.
+       * nnweb.el: Removed old non-functioning search engines.
+
+2002-07-27  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-forward-make-body): Don't use
+       `message-forward-ignored-headers' when doing a "raw" followup (it
+       is important to preserve e.g. CTE).
+
+       * flow-fill.el (fill-flowed): Disable filladapt-mode.
+
+       * gnus-sieve.el (gnus-sieve-guess-rule-for-article): Don't
+       regexp-quote, Cyrus Sieve is fixed.
+
+       * sieve-manage.el (sieve-manage-deletescript): New function.
+
+       * sieve.el (sieve-manage-mode-map): Fix down-mouse-2 and down-mouse-3.
+       (sieve-manage-mode): Fix menubar.
+       (sieve-activate): Change some messages.
+       (sieve-deactivate-all): New function.
+       (sieve-deactivate): New alias.
+       (sieve-remove): New function.
+       (sieve-help): Fix help.
+       All suggested by Ned Ludd.
+
+2002-07-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-inline-text-html-with-images): Doc fix.
+       (mm-w3m-safe-url-regexp): New user option.
+
+       * mm-view.el (mm-inline-text-html-render-with-w3m): Use
+       `mm-w3m-safe-url-regexp' to bind `w3m-safe-url-regexp'.
+
+2002-07-23  Karl Kleinpaste  <karl@charcoal.com>
+
+       * gnus-sum.el (gnus-summary-delete-article): Force
+       nnmail-expiry-target to 'delete, so that absolute deletion
+       happens when absolute deletion is requested.
+
+2002-07-21  Nevin Kapur  <nevin@jhu.edu>
+
+       * nnmail.el (nnmail-fancy-expiry-target): Treat nonexistent
+       headers as empty headers.
+
+2002-07-21  Jochen Hein  <jochen@jochen.org>
+
+       * gnus-art.el (gnus-emphasis-alist): Add strikethrough and
+       correct typo.
+       (gnus-emphasis-strikethru): New face.
+
+2002-07-20  Jason Merrill  <jason@redhat.com>
+
+       * nnfolder.el (nnfolder-retrieve-headers): Avoid searching the
+       entire file for each of a sequence of missing articles.
+
+       * gnus-salt.el (gnus-binary-display-article): Respect an existing
+       value for gnus-view-pseudos.
+
+       * gnus-sum.el (gnus-summary-insert-new-articles): Count down to
+       avoid nreverse.
+
+2002-07-14  Teodor Zlatanov  <teodor.zlatanov@divine.com>
+
+       * gnus-sum.el (gnus-auto-expirable-marks): Remove `spam'.
+       (gnus-summary-mode-line-format-alist): Add %h for number of
+       spams.
+       (gnus-newsgroup-spam-marked): New variable.
+       (gnus-summary-local-variables): Add gnus-newsgroup-spam-marked.
+       (gnus-article-read-p, gnus-article-mark)
+       (gnus-set-global-variables, gnus-set-global-variables)
+       (gnus-article-marked-p, gnus-summary-mark-article-as-read)
+       (gnus-summary-mark-article-as-unread)
+       (gnus-summary-mark-article-as-unread, gnus-summary-mark-article)
+       (gnus-mark-article-as-read, gnus-mark-article-as-unread)
+       (gnus-mark-article-as-unread, gnus-summary-catchup): Grok spam.
+
+2002-07-10  KANEMATSU Daiji  <kdaiji@bea.com>
+
+       * nnimap.el (nnimap-split-to-groups): Allow group string to be a
+       function.
+
+2002-07-09  Nevin Kapur  <nevin@jhu.edu>
+
+       * gnus-sum.el (gnus-summary-delete-article): Respect group
+       parameters while expiring.
+
+2002-07-08  Henrik Enberg  <henrik@enberg.org>
+
+       * gnus-art.el (article-make-date-line): Fix string.
+
+2002-07-08  Niklas Morberg  <niklas.morberg@axis.com>
+
+       * gnus-art.el (article-unsplit-urls): Only display MIME when this
+       function is called interactively.
+
+2002-07-06  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-topic.el (gnus-topic-indent, gnus-topic-unindent): Change
+       cdaar to cdar and car.
+
+       * nnsoup.el (nnsoup-retrieve-headers, nnsoup-request-type)
+       (nnsoup-read-active-file, nnsoup-article-to-area): Ditto.
+
+2002-07-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-toggle-header): Show headers anyway;
+       don't break a narrowed article.
+
+       * nntp.el (nntp-via-rlogin-command-switches): Doc fix.
+       (nntp-open-via-rlogin-and-telnet): Ditto.
+
+2002-07-02  Didier Verna  <didier@xemacs.org>
+
+       * nnmail.el (nnmail-split-methods): Fix custom type.
+
+2002-07-02  Niklas Morberg  <niklas.morberg@axis.com>
+
+       * gnus-art.el (article-unsplit-urls): Keep URL buttonized after
+       unsplitting.
+
+2002-07-01  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-msg.el (gnus-summary-resend-default-address): New user option.
+       (gnus-summary-resend-message): Use it.
+
+2002-06-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nntp.el (nntp-via-rlogin-command-switches): New variable.
+       (nntp-open-via-rlogin-and-telnet): Re-revert; use the var above.
+
+2002-06-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-font-lock-keywords): Don't fontify
+       headers in the message body, only in the header.
+       (message-font-lock-make-header-matcher): New function, used by
+       message-font-lock-keywords.
+
+2002-06-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nntp.el (nntp-open-via-rlogin-and-telnet): Revert last change.
+
+2002-06-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nntp.el (nntp-open-via-rlogin-and-telnet): Hide commandline args.
+
+2002-06-26  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * message.el (message-font-lock-keywords): Revert 2002-06-22
+       change.
+
+2002-06-24  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * message.el (message-font-lock-keywords): Put colon in header
+       name match.
+
+2002-06-22  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * message.el (message-font-lock-keywords): Don't use header faces
+       in the body.  Thanks to Stefan Monnier for the hint on the
+       implementation.
+
+2002-05-09  Miles Bader  <miles@gnu.org>
+
+       * gnus-cite.el (gnus-cite-blank-line-after-header): New variable.
+       (gnus-article-hide-citation): Respect it.
+
+2002-04-12  Juanma Barranquero  <lektu@terra.es>
+
+       * pop3.el (pop3-open-server): Fix typo.
+
+2002-06-18  Josh Huber  <huber@alum.wpi.edu>
+
+       * gnus.el (gnus-find-subscribed-addresses): Use add-to-list
+       instead of push to ignore duplicate to-(list|address) values.
+       * nnmail.el (nnmail-cache-ignore-groups): New.
+       * nnmail.el (nnmail-cache-insert): Obey nnmail-cache-ignore-groups.
+
+2002-06-18  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-delay.el (gnus-delay-send-queue): Delete the delay header
+       before sending.  Suggested by Jan Rychter.
+
+2002-06-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (remove): New compiler macro.
+       (last, coerce, subseq): Remove compiler macros for those built-in
+       or unused functions.
+
+2002-06-17  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-start.el (gnus-clear-system, gnus-read-newsrc-file): Make
+       sure to write byte-compiled versions of gnus-*-format-alist to
+       .newsrc.eld.
+
+2002-06-16  Bjørn Mork  <bmork@dod.no>
+
+       * gnus-agent.el (gnus-agent-read-servers)
+       (gnus-agent-write-servers): Put server name (string like
+       "nnchoke:frumple") in the file instead of a server specification
+       (Lisp expression like (nnchoke "frumple" ...parameters...)).
+
+2002-06-16  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-cache.el (gnus-cache-remove-article): n is &optional.
+
+2002-06-15  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnheader.el (nnheader-file-name-translation-alist): Set the
+       default value for MS Windows systems.
+
+       * gnus-ems.el (nnheader-file-name-translation-alist): Removed.
+
+2002-06-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-beginning-of-line): Keep the region active
+       in XEmacs.  Suggested by TAKAHASHI Kaoru <kaoru@kaisei.org>.
+
+2002-06-13  Josh Huber  <huber@alum.wpi.edu>
+
+       * gnus-msg.el (gnus-summary-followup): Use g-s-handle-replysign.
+       * gnus-msg.el (gnus-summary-reply): Ditto.
+       * gnus-msg.el (gnus-summary-handle-replysign): New.
+
+2002-06-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-send-mail-with-sendmail): Kill errbuf even
+       if sending failed.
+
+2002-06-11  Josh Huber  <huber@alum.wpi.edu>
+
+       * gnus-start.el (gnus-dribble-enter): Don't call set-window-point
+       anymore.
+       * mml2015.el (mml2015-mailcrypt-encrypt): Accept optional argument
+       to sign while encrypting.
+
+2002-06-11  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-int.el (gnus-request-move-article): Agent expire article if
+       successfuly moved.
+
+2002-06-11  Niklas Morberg  <niklas.morberg@axis.com>
+
+       * nnweb.el (nnweb-google-create-mapping): Honors the value of
+       nnweb-max-hits.
+
+2002-06-10  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-int.el (gnus-request-expire-articles): Fix last change?
+
+2002-06-09  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-summary-delete-article): Don't agent expire here.
+
+       * gnus-int.el (gnus-request-expire-articles): Do it here instead.
+
+2002-06-08  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * flow-fill.el (fill-flowed): Ignore errors.
+
+2002-06-06  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-send-mail-with-sendmail): Improve error message.
+
+2002-06-06  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * message.el (message-interactive): Change default from nil to t.
+       Better to be safe than to be fast.
+
+2002-06-05  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * message.el (message-send-mail-with-sendmail): Check return value
+       from call-process-region.
+
+2002-06-04  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-msg.el (gnus-group-mail, gnus-group-news)
+       (gnus-group-post-news, gnus-summary-mail-other-window)
+       (gnus-summary-news-other-window, gnus-summary-post-news): Bind
+       gnus-article-copy to nil, thereby inhibiting the `header' posting
+       style match to use data from last viewed article.
+       Suggested by Hrvoje Niksic.
+
+2002-06-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * spam.el (spam-point-at-eol): New alias.
+       (spam-parse-whitelist): Use it.
+
+2002-06-03  Simon Josefsson  <jas@extundo.com>
+
+       * nnmail.el (nnmail-mail-splitting-decodes): New variable.
+       (nnmail-article-group): Use it.
+
+2002-05-30  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-msg.el (gnus-inews-yank-articles): Merge split header lines
+       so that code reading them won't be surprised.
+
+2002-05-29  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-summary-delete-article): Agent expire deleted
+       articles.
+
+       * gnus.el (gnus-agent-cache): Doc fix.
+       (gnus-agent): Change default to t.
+
+       * gnus-agent.el (gnus-agent-expire): Make it accept optional
+       ARTICLES, GROUP and FORCE parameters.
+
+2002-05-28  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-group.el (gnus-group-line-format): Doc fix.
+
+2002-05-28  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-msg.el (gnus-inews-yank-articles): Unfold headers of
+       original article before yanking.
+
+2002-05-26  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-summary-menu-split): New function.
+       (gnus-summary-make-menu-bar): Split charset submenu.
+       (gnus-summary-menu-maxlen): New variable.
+       (gnus-summary-menu-split): Use it.
+
+2002-05-25  Simon Josefsson  <jas@extundo.com>
+
+       * mml.el (mml-preview): Generate some headers.
+
+       * gnus.el (gnus-large-newsgroup): Fix :type.
+
+       * nnimap.el (nnimap-nov-is-evil): Change default to t (because the
+       Agent cache NOV's by default now).
+       (nnimap-nov-is-evil): Make it default to `gnus-agent' instead.
+
+2002-05-18  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-dependencies-add-header): Avoid one unnecessary
+       call to gnus-parent-id when we check for References loops.
+       (gnus-summary-prepare-threads): Avoid simplifying every Subject
+       twice by saving the simplified subject string in simp-subject.
+
+2002-05-23  Benjamin Rutt  <rutt+news@cis.ohio-state.edu>  (tiny change)
+
+       * gnus-msg.el (gnus-confirm-mail-reply-to-news): Typo.
+
+2002-05-23  Niklas Morberg  <niklas.morberg@axis.com>  (tiny change)
+
+       * nnweb.el (nnweb-type): Remove dejanewsold.
+
+2002-05-22  Simon Josefsson  <jas@extundo.com>
+
+       * sieve.el (sieve-change-region): Define it before it is used.
+
+2002-05-22  Benjamin Rutt  <rutt+news@cis.ohio-state.edu>
+
+       * gnus-msg.el (gnus-confirm-mail-reply-to-news)
+       (gnus-summary-reply): Ask for confirmation when replying to news.
+       Defaults to not ask.
+
+       * nnimap.el (nnimap-nov-is-evil): Improve doc.
+
+2002-05-21  Simon Josefsson  <jas@extundo.com>
+
+       * sieve-mode.el (sieve-manage): Fix autoloads.
+
+       * sieve-manage.el (sieve-manage-cram-md5-auth): Just send the SASL
+       name (makes it work with recent Cyrus timsieved).
+
+2002-05-20  Jason Baker  <jbaker@cs.utah.edu>  (tiny change)
+
+       * gnus-art.el (gnus-request-article-this-buffer): Try
+       reconnecting if you don't get the message.
+
+2002-05-20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-enter-digest-group): Only get
+       Reply-To headers from the headers.
+
+2002-05-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-url.el (mm-url-insert): Remove junk message.
+
+2002-05-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnslashdot.el (nnslashdot-request-list): Parse new html.
+       (nnslashdot-use-front-page): New variable.
+       (nnslashdot-request-list): Use it.
+
+       * mm-url.el (mm-url-timeout): New variable.
+       (mm-url-retries): Ditto.
+       (mm-url-insert): Use it.
+
+2002-05-16  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-simplify-all-whitespace): New function.
+       (gnus-simplify-subject-functions): Mention g-s-a-w.
+
+2002-05-15  Josh Huber  <huber@alum.wpi.edu>
+
+       * nnbabyl.el (nnbabyl-request-accept-article): Pass group to
+       nnmail-cache-insert.
+       * nndiary.el (nndiary-request-accept-article): Ditto.
+       * nnfolder.el (nnfolder-request-accept-article): Ditto.
+       * nnimap.el (nnimap-request-accept-article): Ditto.
+       * nnmail.el (nnmail-process-unix-mail-format): Ditto.
+       * nnmail.el (nnmail-check-duplication): Ditto.  (From gnus-art.)
+       * nnmbox.el (nnmbox-request-accept-article): Ditto.
+       * nnmh.el (nnmh-request-accept-article): Ditto.
+       * nnmail.el (nnmail-cache-insert): Change group to required,
+       removed code which tried to figure out the group.
+
+2002-05-13  Hans de Graaff  <hans@degraaff.org>
+
+       * mml.el (mml-generate-mime-1): Fix mml generation for signed only
+       messages.
+
+2002-05-13  Josh Huber  <huber@alum.wpi.edu>
+
+       * nnml.el (nnml-request-accept-article): Pass in the group name to
+       nnmail-cache-insert, since it's available.
+
+2002-05-10  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nndoc.el (nndoc-mime-digest-type-p): Set proper file-end.
+
+2002-05-08  Florian Weimer  <fw@deneb.enyo.de>
+
+       * gnus.el (subscribed): New group parameter.
+       (gnus-find-subscribed-addresses): Use it.
+
+2002-05-08  Josh Huber  <huber@alum.wpi.edu>
+
+       * mml-sec.el (mml-signencrypt-style-alist): Rename.  Also, changed
+       the default for pgpmime to support pgp v2.
+       * mml-sec.el (mml-signencrypt-style): New accessor function to
+       allow users to get/set the signencrypt style more easily without
+       frobbing the alist directly.
+       * mml.el (mml-generate-mime-1): Use accessor function.
+
+2002-05-08  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-art.el (gnus-article-mode-syntax-table): Specify matching
+       parenthesis for "<" and ">".  Suggested by Andreas Schwab
+       <schwab@suse.de>.
+
+2002-05-07  Josh Huber  <huber@alum.wpi.edu>
+
+       * nnmail.el (nnmail-cache-insert): Prefer group-art over group
+       when intuiting the group the message is written to.
+
+2002-05-06  Matt Armstrong  <matt@lickey.com>
+
+       * gnus-topic.el (gnus-group-topic-parameters): Work when group
+       buffer doesn't show group.
+
+2002-05-06  Josh Huber  <huber@alum.wpi.edu>
+
+       * mml2015.el (mml2015-gpg-encrypt): Changed name of optional
+       argument, and fixed compiler warning.  (Added autoload for
+       gpg-encrypt).
+
+2002-05-04  Simon Josefsson  <jas@extundo.com>
+
+       * mml1991.el (mml1991-function-alist): Doc fix.
+
+       * mml.el (mml-preview): Bind gnus-newsrc-hashtb temporarily if it
+       doesn't exist (for previewing messages without having Gnus
+       started).
+
+       * mm-util.el (mm-coding-system-priorities): Defcustom.
+
+       * mm-encode.el (mm-content-transfer-encoding-defaults): Defcustom.
+
+2002-05-01  Josh Huber  <huber@alum.wpi.edu>
+
+       * gnus-msg.el (gnus-message-replysignencrypted): Enabled by
+       default.
+       * mml-sec.el:
+       * mml-sec.el (mml-signencrypt-style): New.
+       * mml-sec.el (mml-pgpmime-encrypt-buffer): Accept optional
+       argument `sign'.
+       * mml-sec.el (mml-secure-message-encrypt-pgp): Changed default to
+       signencrypt.
+       * mml-sec.el (mml-secure-message-encrypt-pgpmime): Ditto.
+       * mml.el (mml-generate-mime-1): Changed logic so a part which is
+       both signed & encryped is processed in one operation (rather than
+       two separate ops: sign, then encrypt).
+       * mml2015.el (mml2015-gpg-extract-signature-details): Give some
+       indication if a message is signed by an expired key.
+       * mml2015.el (mml2015-gpg-encrypt): Accept optional argument which
+       enables combined sign & encrypt operation (this was always on
+       before).
+       * mml2015.el (mml2015-encrypt): Accept optional argument `sign'.
+
+2002-05-01  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap-retrieve-groups): Use separate data for each
+       server.
+       (nnimap-mailbox-info): defvar instead of defvoo.
+
+2002-05-01 20:09:21  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.06 is released.
+
+2002-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * lpath.el: Bind url-package-version.
+
+2002-05-01  Simon Josefsson  <jas@extundo.com>
+
+       * nnfolder.el (nnfolder-request-delete-group): Figure out nov/mrk
+       filename before deleting the group itself, because the presence of
+       a group filename decides if long filenames are used or not.
+
+       * gnus-art.el (gnus-button-alist): Don't inline
+       gnus-button-url-regexp.  This makes it possible to change g-b-u-r
+       without also modifying g-button-alist.
+       (gnus-button-alist): Fix type to allow variable as well as regexp.
+       (gnus-article-add-buttons): Evaluate regexp.  Strings evaluate to
+       themselves, variables to its contents.
+       (gnus-button-entry): Ditto.
+
+2002-05-01  Simon Josefsson  <jas@extundo.com>
+
+       * imap.el (imap-parse-resp-text-code, imap-parse-status): Treat
+       UIDNEXT as a string.
+
+       * nnimap.el (nnimap-string-lessp-numerical): New function.
+       (nnimap-retrieve-groups): Compare UIDNEXT as strings instead of
+       integers.
+
+2002-04-29  Simon Josefsson  <jas@extundo.com>
+
+       * nnmail.el (nnmail-cache-insert): Accept optional group
+       parameter.
+
+       * nnimap.el (nnimap-retrieve-groups): Don't send STATUS when
+       n-r-g-a is disabled.
+
+2002-04-29  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap-split-fancy): Fix doc.
+       (nnimap-split-fancy): Fix doc.
+
+       * nnimap.el (nnimap-retrieve-groups-asynchronous): New variable.
+       (nnimap-mailbox-info): New internal variable.
+       (nnimap-retrieve-groups): Implement faster new mail check.
+
+       * nnimap.el (nnimap-split-articles): Support
+       nnmail-cache-accepted-message-ids.
+       (nnimap-request-accept-article): Ditto.
+
+       * imap.el (imap-mailbox-status-asynch): New command.
+
+2002-04-29  Nevin Kapur  <nevin@jhu.edu>
+
+       * gnus.el (gnus-find-subscribed-addresses): Return nil when there
+       are no subscribed mail groups.
+       - Strip quoted names when comparing addresses.
+
+2002-04-28  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-decode.el (mm-text-html-renderer): Change customize type to
+       const.
+
+       * gnus-msg.el (gnus-discouraged-post-methods): Fix typo.
+       (gnus-debug-exclude-variables): Do.
+
+2002-04-27  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-article-mail): Use gnus-msg-mail instead.
+       Trivial change from Karl Pflästerer <sigurd@12move.de>.
+
+2002-04-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dns.el (dns-make-network-process): New macro.
+       (query-dns): Use it.
+
+2002-04-27  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-summary-reply): Remove unbound variable
+       article-buffer.
+
+       * mm-url.el (mm-url-package-name): New variable.
+       (mm-url-package-version): New variable.
+       (mm-url-insert-file-contents): Bind url-package-name and
+       url-package-version here.
+       * nnrss.el (nnrss-insert-w3): Move the bindings.
+
+       * nnrss.el (nnrss-insert-w3): Bind url-package-name and
+       url-package-version.  Trivial change from Andrew J Cosgriff
+       <ajc@polydistortion.net>.
+
+       * mm-decode.el (mm-save-part): Fill in file name when GUI saving
+       attachments.  Trivial change from Peter 'Luna' Runestig
+       <peter@runestig.com>.
+
+2002-04-19  Jesper Harder  <harder@ifa.au.dk>
+
+       * nnkiboze.el (nnkiboze-request-scan):
+       Call nnkiboze-possibly-change-group.
+       (nnkiboze-generate-group): Use mm-with-unibyte to avoid encoding
+       problems.
+       (nnkiboze-generate-group): Set newsrc to the *highest* article
+       number kibozed, not the lowest.
+
+2002-04-15  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-art.el (article-unsplit-urls): Allow trailing SPC.
+
+2002-04-24  Dan Christensen  <jdc+news@uwo.ca>
+
+       * nndoc.el (nndoc-type-alist, nndoc-lanl-gov-announce-type-p)
+       (nndoc-transform-lanl-gov-announce, nndoc-generate-lanl-gov-head):
+       Recognize math postings.  Extract Date (now ignores "(15kb)").
+       Extract email address using gnus-extract-address-components
+       instead of just taking the first word.  Create Date and From
+       headers for message which are missing these headers.  Get rid
+       of spurious \\ lines (purely cosmetic).  Extend body-end and
+       file-end regexps, to exclude more garbage from the message.
+       Make URL rephrasing regexp more flexible, to match current
+       format.
+
+2002-04-23  Simon Josefsson  <jas@extundo.com>
+
+       * netrc.el: New file, functions copied from gnus-util.el by Ted
+       Zlatanov <tzz@lifelogs.com>.
+
+       * gnus-util.el: Require netrc.
+       (gnus-netrc-get, gnus-netrc-machine, gnus-parse-netrc): Aliased to
+       new code in netrc.el.
+
+2002-04-23  Matthieu Moy  <Matthieu.Moy@imag.fr>
+
+       * gnus-msg.el (gnus-summary-resend-message-edit): Remove
+       message-ignored-resent-headers, too.
+
+2002-04-22  Björn Torkelsson  <torkel@acc.umu.se>
+
+       * gnus-srvr.el (gnus-server-browse-in-group-buffer): It is a
+       boolean not a string.
+       * gnus-group.el (gnus-group-line-format): Add description of %C.
+       * gnus-group.el (gnus-group-line-format-alist): Add gnus-tmp-comment
+       as %C.
+       * gnus-group.el (gnus-group-insert-group-line): Add gnus-tmp-comment.
+
+2002-04-22  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir-request-scan): Typo: set
+       nnmaildir-get-new-mail, not nnmaildir-new-mail.  Don't call
+       nnmail-get-new-mail for 'find-new-groups.
+
+2002-04-21  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir-request-update-info, nnmaildir-request-group)
+       (nnmaildir-retrieve-groups): Remove unnecessary calls to
+       nnmaildir-request-scan.
+
+2002-04-20  Josh Huber  <huber@alum.wpi.edu>
+
+       * gnus-msg.el (gnus-message-replysign, gnus-message-replyencrypt)
+       (gnus-message-replysignencrypted): New.
+       (gnus-summary-reply): Use the three new variables (above)
+       to automatically encrypt/sign to encrypted/signed messages.
+       * message.el (message-mode-map): Add keybinding for
+       `message-to-list-only'.
+       (message-mode): Add description for
+       `message-to-list-only'.
+       (message-to-list-only): New.
+       (message-make-mft): Changed to use the cl loop macro, and added
+       optional flag to return only the matched list (for use in new
+       message-to-list-only function).
+
+2002-04-20  Josh Huber  <huber@alum.wpi.edu>
+
+       * gnus-msg.el (gnus-message-replysign, gnus-replysign)
+       (gnus-replyencrypt, gnus-replysignencrypted, gnus-summary-reply): New.
+       * message.el (message-mode-map, message-mode, message-to-list-only)
+       (message-make-mft): New.
+
+2002-04-19  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-win.el (gnus-configure-windows-hook): Fix typo.
+
+2002-04-18  Josh Huber  <huber@alum.wpi.edu>
+
+       * message.el (message-gen-unsubscribed-mft): Accept a prefix
+       argument so CC can be included with C-u C-c C-f C-a.
+
+2002-04-17  Teodor Zlatanov  <teodor.zlatanov@divine.com>
+
+       * spam.el (spam-whitelist, spam-blacklist, spam-enter-whitelist):
+       Improve docstring.
+       (spam-enter-blacklist): New command.
+
+       * gnus-sum.el (gnus-spam-mark): New mark.
+       (gnus-auto-expirable-marks): Add gnus-spam-mark.
+       (gnus-summary-make-tool-bar): Correct conditional.
+       (gnus-summary-limit-to-unread): Add gnus-spam-mark.
+       (gnus-summary-mark-as-spam): New command.
+
+2002-04-13  Josh Huber  <huber@alum.wpi.edu>
+
+       * mml-sec.el (mml-secure-message): Changed to support arbritrary
+       modes.
+       * mml-sec.el (mml-secure-message-encrypt-(smime|pgp|pgpmime)):
+       changed to support "signencrypt" mode.
+       * mml.el (mml-parse-1): Changed to support different secure modes
+       more easily (for signencrypt).
+
+2002-04-11  Stefan Monnier  <monnier@cs.yale.edu>
+
+       * gnus-sum.el (gnus-update-summary-mark-positions)
+       (gnus-summary-toggle-header):
+       * gnus-uu.el (gnus-uu-binhex-article, gnus-uu-reginize-string)
+       (gnus-uu-expand-numbers, gnus-uu-post-make-mime)
+       (gnus-uu-post-encoded):
+       * nnfolder.el (nnfolder-possibly-change-group):
+       * nnimap.el (nnimap-retrieve-headers):
+       * nnmbox.el (nnmbox-create-mbox): Don't assume point-min == 1.
+
+2002-04-08  Stefan Monnier  <monnier@cs.yale.edu>
+
+       * nnml.el (nnml-save-nov, nnml-generate-nov-file):
+       * pop3.el (pop3-md5): Don't hardcode point-min == 1.
+
+2002-04-12  Daiki Ueno  <ueno@unixuser.org>
+
+       * gnus-srvr.el (gnus-server-set-info): Clear
+       `gnus-server-method-cache' when `gnus-server-alist' is changed.
+
+2002-04-11  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-summary-force-verify-and-decrypt): Force
+       viewing of security buttons.  Thanks to Nicolas Kowalski
+       <Nicolas.Kowalski@imag.fr>.
+
+       * smime.el (smime-CA-directory): Fix doc.  Thanks to Arne
+       Jørgensen <arne+usenet@daimi.au.dk>.
+       (smime-sign-buffer): Work in XEmacs.  Thanks to Nicolas Kowalski
+       <Nicolas.Kowalski@imag.fr>.
+       (smime-decrypt-buffer): Ditto.
+
+2002-04-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-prepare): Place point on the empty
+       header line.
+
+2002-04-11  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus.el (gnus-refer-article-method): Change `dejanews' to `google'.
+
+2002-04-08  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-delete-marked-with): Fix typo.
+
+2002-04-07  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-view.el (mm-inline-text-html-render-with-w3): Don't ignore
+       errors when debug.
+
+2002-04-07  Josh Huber  <huber@alum.wpi.edu>
+
+       * message.el (message-make-mft): Changed MFT code from using
+       message-recipients (which included Bcc) to use only the To and CC
+       headers.
+
+2002-04-05  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus-art.el (gnus-treat-from-picon): Add to gnus-picon group and
+       add link.
+       (gnus-treat-mail-picon): Ditto.
+       (gnus-treat-newsgroups-picon): Ditto.
+       (gnus-picon-databases): Fix custom type.
+       (gnus-picon-databases): Add link.
+       (gnus-article-x-face-command): Add to gnus-picon group.
+
+2002-04-01  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.el (message-buffer-naming-style): Remove.
+
+2002-04-02  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-make-tool-bar): Load tool-bar first.
+
+       * message.el (message-tool-bar-map): Ditto.
+
+       * gnus-sum.el (gnus-summary-make-tool-bar): Ditto.
+
+2002-04-01  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnwarchive.el (nnwarchive-mail-archive-article): Fix typo.
+
+2002-04-01  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el: Fixed some buggy invocations of nnmaildir--pgname.
+
+2002-03-31  Andrew Cohen  <cohen@andy.bu.edu>  (tiny change)
+
+       * dns.el: open-network-stream under XEmacs does udp.
+
+2002-03-31  Lars Magne Ingebrigtsen  <larsi@quimbies.gnus.org>
+
+       * spam.el (spam-enter-whitelist): New function.
+       (spam-parse-whitelist): Ditto.
+       (spam-refresh-list-cache): Ditto.
+       (spam-address-whitelisted-p): New function.
+
+       * dns.el (query-dns): Use TCP when make-network-process isn't
+       available.
+       (dns-servers): New variable.
+       (dns-parse-resolv-conf): New function.
+       (query-dns): Use it.
+
+       * spam.el: New file.
+
+       * dns.el (query-dns): Test.
+
+2002-03-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * lpath.el (featurep): Bind make-network-process.
+
+2002-03-31  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el: Use defstruct.  Use a single copy of
+       nnmail-extra-headers to save memory.  Store server's group name
+       prefix instead of each group's prefixed name.
+       * nnnil.el (nnnil-retrieve-headers, nnnil-request-list): Erase
+       nntp-server-buffer.
+
+2002-03-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * dns.el: New file.
+
+2002-03-28  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-summary-dummy-line-format):
+       * gnus.el (gnus-summary-line-format): Fixing links to Info.
+       Trivial change from Björn Torkelsson <torkel@pdc.kth.se>.
+
+2002-03-29  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-sum.el (gnus-summary-move-article)
+       (gnus-summary-copy-article): Mention `gnus-move-split-methods' in
+       the doc string.
+
+2002-03-28  Simon Josefsson  <jas@extundo.com>
+
+       * mml-sec.el (mml-secure-message): Search after
+       mail-header-separator from top of message.
+
+2002-03-28  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el: Cosmetic changes.
+       (nnmaildir--with-nntp-buffer, nnmaildir--with-work-buffer,
+       nnmaildir--with-nov-buffer, nnmaildir--with-move-buffer,
+       nnmaildir--group-ls): New macros/functions.  Use them.
+       (nnmaildir--unlink): Evaluate argument only once.
+
+2002-03-27  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-summary-highlight): Use `eq' when comparing
+       symbols.
+       (gnus-summary-highlight-line): Use `gnus-point-at-bol' and
+       `gnus-point-at-eol'.
+
+2002-03-27  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir--subdir, nnmaildir--nov-dir,
+       nnmaildir--marks-dir): New macros.  Use them.
+       Use inhibit-quit for atomicity instead of in-memory journaling.
+       (nnmaildir--edit-prep): New function.
+       (Local Variables): Use it.
+
+2002-03-26  Pavel Janík  <Pavel@Janik.cz>
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Fix typo.
+
+2002-03-25  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-mode): Fix doc.
+
+2002-03-25  Matthieu Moy  <Matthieu.Moy@imag.fr>
+
+       * message.el (message-subject-re-regexp): Skip Re[42]: junk.
+
+2002-03-24  Jesper Harder  <harder@ifa.au.dk>
+
+       * mml-sec.el (mml-unsecure-message): Add docstring.
+
+2002-03-23  Andre Srinivasan  <andre@slamdunknetworks.com>  (tiny change)
+
+       * nnmail.el (nnmail-large-newsgroup): Fix doc, allow non-numeric
+       value.
+
+2002-03-22  Josh Huber  <huber@alum.wpi.edu>
+
+       * mml.el (mml-mode-map): Added a keybinding for
+       `mml-unsecure-message'.  Also, added a menu entry for said
+       function in the Attachments menu.
+
+2002-03-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * canlock.el (canlock-version): Remove.
+       (canlock-sha1-with-openssl): Don't use `canlock-string-as-unibyte'
+       here; simplify \x insertions.
+       (canlock-sha1): New function, always return a unibyte string.
+       (canlock-make-cancel-key): Use `canlock-sha1'; simplify truncation
+       of a password.
+       (canlock-insert-header): Use `canlock-sha1'.
+       (canlock-verify): Ditto.
+
+2002-03-21  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-fix-before-sending): Add an option that
+       ignores illegible text.
+       Trivial change from Mark Milhollan <mlm@attglobal.net>
+
+       * message.el (message-font-lock-keywords): Support multi-line MML
+       tags.
+
+2002-03-21  Lőrentey Károly  <lorentey@elte.hu>
+
+       * gnus-sum.el (gnus-print-buffer): Remove gnus-decoration.
+
+2002-03-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Use intern'ed function
+       symbols for "View as different encoding" submenu.
+
+2002-03-19  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Add "View as different
+       encoding" submenu.
+
+2002-03-19  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-process-prefix): Make sure there is a mark.
+
+2002-03-19  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-sum.el (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): Make customizable.
+
+2002-03-16  Francis Litterio  <franl@world.std.com>
+
+       * gnus-util.el (gnus-extract-address-components): Don't break on
+       names such as James "Kibo" Parry.
+
+2002-03-13  Pavel Janík  <Pavel@Janik.cz>
+
+       * pop3.el (pop3-open-server): Revert multibyte change.
+
+       * message.el (message-send-mail-with-qmail): Make it work.
+
+2002-03-13  Josh Huber  <huber@alum.wpi.edu>
+
+       * message.el (message-make-mft): Set case-fold-search while
+       generating the MFT.  Also, a little cleanup in the MFT code.
+
+2002-03-12  Faried Nawaz  <fn@hungry.org>  (tiny change)
+
+       * message.el (message-qmail-inject-args): May be function.  Adjust
+       doc string and custom type.
+       (message-send-mail-with-qmail): Call function if m-q-i-a is a
+       function.
+
+2002-03-12  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-abbrevs-loaded): Remove.
+       (mailabbrev): Require it.
+
+       * nnslashdot.el (nnslashdot-request-article): Remove IFRAME.
+
+2002-03-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * pop3.el (pop3-open-server): Set process buffer unibyte.
+
+2002-03-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-fun.el (gnus-subscribe-to-mailing-list): New function.
+
+2002-03-10  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnslashdot.el (nnslashdot-request-article): Remove javascript
+       too.
+
+2002-03-09  Andre Srinivasan  <andre@slamdunknetworks.com>  (tiny change)
+
+       * gnus-sum.el (gnus-summary-save-parts-default-mime): Remove
+       duplication.
+       (gnus-summary-save-parts-type-history): Ditto.
+       (gnus-summary-save-parts-last-directory): Ditto.
+
+2002-03-09  Paul Jarc  <prj@po.cwru.edu>
+
+       * gnus-start.el (gnus-auto-subscribed-groups): Include nnmaildir.
+
+2002-03-06  Matthieu Moy  <Matthieu.Moy@imag.fr>
+
+       * gnus-msg.el (gnus-summary-resend-message-edit): New function.
+
+2002-03-06  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnslashdot.el (nnslashdot-request-article): Use "<!-- no ad 6
+       -->" as the end of the first article.
+
+       * message.el (message-add-action): Use add-to-list.
+       (message-delete-action): New function.
+
+       * nndoc.el (nndoc-mail-in-mail-type-p): Break a long regexp into
+       pieces.
+
+2002-03-05  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnnil.el: New file.
+       * gnus.el (gnus-valid-select-methods): Include nnnil.
+
+2002-03-05  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-syntax-checks): Because canlock is
+       supported, we disable sender syntax check.
+       (message-shoot-gnksa-feet): Add cancel-messages option doc.
+
+       * gnus-draft.el (gnus-draft-send): If interactive, use its default
+       value of message-syntax-checks.
+
+       * qp.el (quoted-printable-decode-region): Doc addition.
+       From: Eli Zaretskii <eliz@is.elta.co.il>
+
+       * mail-source.el (make-source-make-complex-temp-name): Use
+       make-temp-file.
+
+       * mm-util.el (mm-make-temp-file): New function.
+       * nneething.el (nneething-file-name): Use it.
+       * mml-smime.el (mml-smime-encrypt): Ditto.
+       * mm-view.el (mm-inline-wash-with-file): Ditto.
+       * mm-decode.el (mm-display-external, mm-create-image-xemacs): Ditto.
+       * gnus-uu.el (gnus-uu-decode-binhex, gnus-uu-decode-binhex-view)
+       (gnus-uu-digest-mail-forward, gnus-uu-initialize): Ditto.
+       * gnus-start.el (gnus-slave-save-newsrc): Ditto.
+       * gnus-fun.el (gnus-convert-image-to-gray-x-face): Ditto.
+       * gnus-art.el (gnus-mime-print-part): Ditto.
+
+2002-03-04  Paul Jarc  <prj@po.cwru.edu>
+
+       * message.el (nnmaildir-article-number-to-base-name): New
+       function.
+       (nnmaildir-base-name-to-article-number): New function.
+
+2002-03-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * smime.el (smime-make-temp-file): Don't quote
+       `temporary-file-directory'.
+
+2002-03-04  Simon Josefsson  <jas@extundo.com>
+
+       * smime.el (smime-sign-region): Rename argument keyfiles to
+       keyfile.  You only sign something with one key.
+       (smime-sign-buffer): Better completing-read prompt.
+       (smime-decrypt-buffer): Ditto.
+
+       * smime.el (smime-make-temp-file): Make it work under XEmacs.
+
+       * mm-view.el (mm-view-pkcs7-decrypt): Better prompt for
+       completing-read.
+       (mm-view-pkcs7-decrypt): CRLF->LF.
+
+2002-03-04  Teodor Zlatanov  <teodor.zlatanov@divine.com>
+
+       * message.el (message-hierarchical-addresses): New variable.
+       (message-get-reply-headers): Use it.
+
+2002-03-03  Geoff Greene  <ggreene@wpi.edu>  (tiny change)
+
+       * message.el (message-mode): If buffer-file-name, don't set auto
+       save file name.
+
+2002-03-02  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-util.el (gnus-multiple-choice): Use message.  XEmacs only
+       takes one argument in read-char.
+
+       * message.el (message-fix-before-sending): Forward a char.
+       Check mmu-multibyte-p, add control-1.
+
+2002-03-01  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-start.el (gnus-read-init-file): Ditto.
+
+       * gnus-agent.el (gnus-agent-fetch-session): Ditto.
+
+       * dgnushack.el (dgnushack-make-load): Ditto.
+
+       * mail-source.el (mail-source-fetch): Extract the right error
+       code.
+
+       * message.el (message-fix-before-sending): Check illegible text.
+
+       * gnus-util.el (gnus-multiple-choice): New function.
+
+       * gnus-kill.el (gnus-score-insert-help): Removed, because it is
+       also defined in gnus-score.el.
+
+2002-03-01  Paul Jarc  <prj@po.cwru.edu>
+
+       * message.el (message-get-reply-headers): Downcase email addresses
+       for comaparisons for duplicate removal.
+
+2002-03-01  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-view.el (mm-view-pkcs7-verify): New function.  A bogus
+       implementation of PKCS#7, which just allows users read the
+       message.
+       (mm-view-pkcs7): Use it.
+
+2002-02-27  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el (large-newsgroup-initial): New parameter.
+
+       * gnus-sum.el (gnus-articles-to-read): Use large-newsgroup-initial.
+       (gnus-summary-insert-old-articles): Ditto.
+
+2002-02-26  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * gnus-sum.el (gnus-articles-to-read): `gnus-large-newsgroup' is
+       used as the default answer of the question, "How many articles?".
+
+2002-02-26  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnagent.el (nnagent-retrieve-headers): Remove articles with
+       small numbers.
+
+2002-02-24  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * deuglify.el: Fix comments.
+
+2002-02-23  Andre Srinivasan  <andre@slamdunknetworks.com>  (tiny change)
+
+       * mml.el (mml-generate-mime-1): Add cdr.
+
+2002-02-23  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * html2text.el (html2text-clean-anchor): If there is no HREF,
+       insert nothing.
+
+       * mm-view.el (mm-text-html-renderer-alist): Add html2text.
+       (mm-text-html-washer-alist): Ditto.
+
+       * mm-decode.el (mm-text-html-renderer): Add html2text.
+
+       * html2text.el: Face lift.
+
+       * html2text.el: New file from Joakim Hove <hove@phys.ntnu.no>.
+
+2002-02-22  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el: Add gnus-article-outlook-deuglify-article.
+
+       * deuglify.el: Change copy right.  Add autoload.  Add coding-system.
+
+2002-02-22  Raymond Scholz  <rscholz@zonix.de>
+
+       * deuglify.el: New file.  The original file name is
+       gnus-outlook-deuglify.el.
+
+2002-02-22  Andre Srinivasan  <andre@slamdunknetworks.com>  (tiny change)
+
+       * mm-decode.el (mm-display-external): Use
+       mm-file-name-rewrite-functions.
+
+2002-02-22  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir-request-list): Report the highest
+       article number, not the total number of articles.
+
+2002-02-21  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el: Move uu key map here.
+       (gnus-summary-make-menu-bar): Add gnus-summary-save-parts.
+
+2002-02-21  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir-request-expire-articles): Use
+       nnmail-expiry-wait* if expire-age parameter is not set.
+
+2002-02-21  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-sort-groups-by-real-name): New
+       function.
+       (gnus-group-sort-selected-groups-by-real-name): New function.
+       (gnus-group-make-menu-bar): Add sort by real name.
+
+       * gnus-sum.el (gnus-dependencies-add-header): If replaced, don't
+       rebuild.
+       (gnus-summary-edit-article-done): Gnus-get-newsgroup-headers takes
+       nil as dependencies as well.
+
+2002-02-20  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nndoc.el (nndoc-dissect-mime-parts-sub): Fix MIME-Version header
+       for mime-parts.
+
+       * gnus-art.el (gnus-article-edit-done): Widen the buffer.
+
+       * message.el (message-send-mail): Be talkative.
+
+2002-02-20  TSUCHIYA Masatoshi  <tsuchiya@pine.kuee.kyoto-u.ac.jp>
+
+       * gnus-group.el (gnus-group-name-decode): Don't test
+       multibyte-string, because it breaks XEmacs.
+
+2002-02-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * mm-decode.el (mm-inlined-types): Add application/x-emacs-lisp.
+       (mm-automatic-display): Ditto.
+
+       * mailcap.el (mailcap-mime-data): Ditto.
+
+2002-02-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * Many files: Remove trailing whitespaces, replace spc+tab with
+       tab, replace leading whitespaces with tabs.
+
+2002-02-19  Paul Jarc  <prj@po.cwru.edu>
+
+       * gnus-sum.el (gnus-summary-toggle-header): Fix handling of
+       articles with no body and no blank line after the header.
+
+2002-02-19  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-dissect-multipart): Consider the case of empty
+       parts.
+
+       * ietf-drums.el (ietf-drums-syntax-table): Modify syntax of
+       non-ascii chars.
+
+       * rfc2231.el (rfc2231-parse-string): Support non-ascii chars.
+
+       * gnus-art.el (gnus-article-wash-html-with-w3): Remove
+       w3-delay-image-loads.
+       * mm-view.el (mm-inline-text-html-render-with-w3): Ditto.
+       (mm-w3-prepare-buffer): Ditto.
+
+       * mail-source.el (mail-source-fetch-directory): Run scripts.
+
+2002-02-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-fun.el (gnus-respond-to-confirmation): Do the right thing
+       for Majordomo confirmations.
+
+2002-02-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-fun.el (gnus-respond-to-confirmation): New command.
+
+2002-02-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnultimate.el (nnultimate-retrieve-headers): Clean up.
+
+2002-02-18  Mark Thomas  <mthomas@cmu.edu>
+
+       * gnus-util.el (gnus-parent-id): Ignore trailing whitespace in the
+       References header field.
+
+2002-02-18  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-view.el (mm-inline-render-with-file): With unibyte buffer.
+       (mm-inline-render-with-stdin): Ditto.
+       (mm-inline-render-with-function): Ditto.
+       (mm-inline-wash-with-file): Bind coding-system-for-write.
+       (mm-inline-wash-with-stdin): Ditto.
+
+2002-02-18  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       Suggested by Felix Natter <fnatter@gmx.net>
+
+       * gnus-art.el (gnus-mime-view-part-externally): Rename from
+       gnus-mime-externalize-view.
+       (gnus-mime-view-part-internally): Rename from
+       gnus-mime-internalize-view.
+       (gnus-article-view-part-externally): Rename from
+       gnus-article-externalize-part.
+       (gnus-mime-action-alist): Change correspondingly.
+       (gnus-mime-button-commands): Ditto.
+       (gnus-mime-action-alist): Remove duplication.
+
+       * gnus-sum.el (gnus-summary-mime-map): Change correspondingly.
+
+2002-02-18  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-dissect-buffer): Add loose-mime parameter.
+
+       * gnus-art.el (gnus-display-mime): Use it.
+
+       * mm-partial.el (mm-partial-find-parts): Use it.
+
+       * gnus-sum.el (gnus-article-loose-mime): Rename from
+       gnus-article-no-strict-mime.
+       (gnus-summary-save-parts): Use it.
+
+2002-02-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-fun.el (gnus-convert-gray-x-face-to-xpm): Remove unused
+       local variable.
+
+       * gnus-art.el (article-display-x-face): Don't sort multiple
+       X-Faces.
+
+2002-02-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-fun.el (gnus-convert-gray-x-face-to-xpm): Improved to speed
+       up.  Suggested by Yuuichi Teranishi <teranisi@gohome.org>.
+
+       * gnus-art.el (article-display-x-face): Sort gray X-Faces.
+
+2002-02-17  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       Some ideas is inspired by code from Hrvoje Niksic
+       <hniksic@arsdigita.com>
+
+       * gnus-art.el (gnus-article-wash-function): Set the default to
+       nil, so that we use mm-text-html-renderer instead.
+       (article-wash-html): Use mm-text-html-renderer.
+
+       * mm-decode.el (mm-inline-media-tests): Use mm-inline-text-*.
+       (mm-text-html-renderer): New variable.
+       (mm-inline-text-html-renderer): Set the default to nil, so that we
+       use mm-text-html-renderer instead.
+
+       * mm-view.el (mm-inline-text-html): New function.
+       (mm-text-html-renderer-alist): New variable.
+       (mm-inline-text-vcard): New function.
+       (mm-inline-text): Split.
+       (mm-links-remove-leading-blank): New function.
+       (mm-inline-render-with-file): New function.
+       (mm-inline-render-with-stdin): New function.
+       (mm-inline-render-with-function): New function.
+       (mm-text-html-washer-alist): New variable.
+       (mm-inline-wash-with-file): New function.
+       (mm-inline-wash-with-stdin): New function.
+
+2002-02-17  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message-utils.el: Fix installation doc.
+
+2002-02-16  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-discouraged-post-methods): New variable.
+       (gnus-post-method): Use it.
+       (gnus-summary-cancel-article): Find the correct post-method.
+
+       * gnus-soup.el (gnus-soup-send-packet): Via ... using ...
+       * message.el (message-send-news): Ditto.
+       Suggested by Lloyd Zusman <ljz@asfast.com> and IPmonger
+       <ipmonger@delamancha.org>
+
+       * gnus.el (gnus-select-method): Fix doc.
+       (gnus-server-string): Use 'using nntp'.
+
+       * gnus-agent.el (gnus-slave-unplugged): New command.
+       From: Felix Natter <fnatter@gmx.net>
+
+2002-02-15  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-edit-done): Kill-all-local-variables.
+       Call edit-done-function first, then change the window
+       configuration.
+       (gnus-article-edit-mode-map): Add message key bindings.  Add menu.
+       (gnus-article-edit-mode): mml-mode.
+
+       * gnus-util.el (gnus-byte-compile): Work around a bug in XEmacs
+       21.4.  Suggested by Russ Allbery <rra@stanford.edu>.
+
+       * message-utils.el: Adopt the file.
+
+2002-02-15  Holger Schauer  <Holger.Schauer@gmx.de>
+
+       * message-utils.el: New file.
+
+2002-02-14  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-move-article): Select-article only
+       when gnus-move-split-methods is non-nil.  And we don't render or
+       mark the article.
+
+       * gnus-fun.el (gnus-shell-command-to-string): New function.
+       (gnus-shell-command-on-region): New function.
+       (gnus-random-x-face): Use them.
+       (gnus-x-face-from-file): Ditto.
+       (gnus-convert-image-to-gray-x-face): Ditto.
+       (gnus-convert-gray-x-face-to-xpm): Ditto.
+       (gnus-convert-image-to-x-face-command): Don't use 2>/dev/null.
+
+2002-02-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-treat-display-xface): Don't use
+       `shell-command-to-string' when compiling.
+       (gnus-treat-display-grey-xface): Ditto.
+
+2002-02-13  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir--article-count): If the group is
+       completely empty, report minimum article number as 1 instead of 0.
+
+2002-02-13  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-get-predicate): Use nconc.
+
+       * gnus-sum.el (gnus-summary-display-make-predicate): Use
+       gnus-summary-display-cache as cache.
+
+       * nndoc.el (nndoc-type-alist): Add mail-in-mail type.
+       (nndoc-mail-in-mail-type-p): New function.
+       (nndoc-mail-in-mail-article-begin): New function.
+
+2002-02-12  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mailcap.el (mailcap-mime-data): Use enriched-decode.
+
+       * gnus-cite.el (gnus-article-fill-cited-article): Bind
+       use-hard-newlines to nil.
+
+       * gnus-xmas.el (gnus-xmas-image-type-available-p): Assume that
+       image is not available if window-system is not available.
+
+       * gnus-sum.el (gnus-summary-display-make-predicate): Add unread.
+
+2002-02-11  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el (gnus-article-unpropagated-mark-lists): Don't propagate
+       bookmark, because update-mark doesn't handle it correctly.
+
+2002-02-09  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-soup.el (gnus-soup-send-packet): Send news and mail
+       directly instead of calling message-send-mail.
+
+       * gnus-start.el (gnus-read-descriptions-file): Use
+       gnus-default-charset.
+
+       * mm-util.el (mm-guess-mime-charset): New function.
+
+       * gnus.el (gnus-default-charset): Use it.
+       (gnus-group-charset-alist): Remove .*, Let gnus-default-charset be
+       the default.
+
+2002-02-08  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-treat-display-grey-xface): New variable.
+       (article-display-x-face): Use it.  Disable gray xface, if
+       uncompface is not found.
+
+       * message.el (message-mode): Don't enable multibyte on an indirect
+       buffer.
+
+       * nnrss.el (nnrss-content-function): New variable.
+       (nnrss-request-article): Use it.
+
+2002-02-08  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el: Add article-unsplit-urls.
+       * gnus-sum.el: Ditto.
+       * gnus-art.el (gnus-treat-strip-cr): New variable.
+       (gnus-treatment-function-alist): Use it.
+       (article-unsplit-urls): New function.
+       (gnus-article-make-menu-bar): Use it.
+       From: Michael Cook <michael.cook@cisco.com>
+
+2002-02-08  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-braid-nov): Find the first article to
+       copy.
+
+2002-02-07  Paul Jarc  <prj@po.cwru.edu>
+
+       * gnus-util.el (gnus-split-references): Allow (broken) Message-IDs
+       with internal whitespace.
+       (gnus-parent-id): Ditto.
+
+2002-02-07  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-treat-body-boundary): Add
+       gnus-decoration property.
+       * gnus-msg.el (gnus-copy-article-buffer): Remove gnus-decoration.
+
+       * gnus-art.el (gnus-article-treat-unfold-headers): Don't remove
+       too many spaces.
+
+       * rfc2047.el (rfc2047-unfold-region): Ditto.
+       (rfc2047-decode-region): Don't unfold.  Let
+       gnus-article-treat-unfold-headers do it.
+
+2002-02-07  Matt Armstrong  <matt@lickey.com>
+
+       * message.el (message-mode): Set local-abbrev-table.
+
+2002-02-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-sum.el (gnus-dependencies-add-header): Fix typo.
+
+2002-02-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-posting-styles): Add x-face-file.
+       (gnus-configure-posting-styles): Use it.
+       (gnus-configure-posting-styles): Remove trailing newspaces.
+
+2002-02-06  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-articles-to-read): Fetch all if the predicate
+       is non-nil.
+
+       * mm-util.el (mm-use-find-coding-systems-region): Add doc.
+
+       * gnus.el (gnus-server-to-method): Switch position with
+       gnus-server-get-method.
+       (gnus-agent): Add doc.
+
+       * gnus-sum.el (gnus-article-no-strict-mime): New variable.
+       (gnus-summary-save-parts): Use it.
+
+       * gnus-art.el (gnus-display-mime): Use it.
+       * mm-partial.el (mm-partial-find-parts): Use it.
+
+       * nnweb.el (nnweb-google-parse-1): Use a correct format of date.
+
+       * nnagent.el (nnagent-request-expire-articles): Don't delete
+       files.
+
+2002-02-06  Stefan Reichör  <xsteve@riic.at>
+
+       * gnus-agent.el (gnus-agent-summary-make-menu-bar): Fix typo.
+
+2002-02-05  Sriram Karra  <karra@cs.utah.edu>
+
+       * message.el (message-gen-unsubscribed-mft): New function.
+
+2002-02-05  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el (gnus-article-unpropagated-mark-lists): Backslash the
+       open parenthesis.
+
+       * mm-view.el (mm-w3-prepare-buffer): Bind url-gateway-unplugged.
+       (mm-inline-text-html-render-with-w3): Ditto.
+       * gnus-art.el (gnus-article-wash-html-with-w3): Ditto.
+       Suggested by Dave Love  <d.love@dl.ac.uk>.
+
+       * mm-url.el (mm-url-load-url): Require w3-vars for old versions.
+
+       * nntp.el (nntp-send-command-and-decode): Check PROCESS.
+       * nntp.el (nntp-send-command): Ditto.
+       * nntp.el (nntp-send-command-nodelete): Ditto.
+
+2002-02-04  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-url.el (mm-url-load-url): New function.
+       (mm-url-insert-file-contents): Use it.
+
+       * gnus-msg.el (gnus-summary-mail-forward): Use gnus-article-charset.
+
+       * message.el (message-forward-make-body): Correctly copy
+       forward-buffer.
+
+       * rfc2047.el (rfc2047-decode-region): Don't decode us-ascii characters.
+
+2002-02-04  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-art.el (gnus-article-followup-with-original): Mark with
+       force, prevent errors when following up from article buffer.
+       (gnus-article-reply-with-original): Ditto.
+
+       * binhex.el (binhex-decoder-switches): Fix doc.  From
+       Pavel@Janik.cz (Pavel Janík).
+
+2002-02-04  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-treatment-function-alist): Move hide-citation,
+       highlight-citation after emphasize.
+
+2002-02-04  David Edmondson  <dme@sun.com>
+
+       * nnfolder.el (nnfolder-open-marks): Message when done.
+
+       * nnml.el (nnml-open-marks): Ditto.
+
+2002-02-03  Steinar Bang  <sb@dod.no>
+
+       * imap.el (imap-anonymous-auth): Fix typo.
+
+2002-02-03  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-cache.el (gnus-cache-braid-nov): Use set-buffer instead of
+       save-excursion.
+       (gnus-cache-braid-heads): Ditto.
+
+       * gnus-agent.el (gnus-agent-copy-nov-line): Move to the correct
+       line, because there are extra articles in the overview buffer.
+
+       * nntp.el (nntp-retrieve-groups): Check whether BUF is live.
+
+       * message.el (message-forward-rmail-make-body): Directly use
+       rmail-msg-restore-non-pruned-header to avoid calling
+       vertical-motion.
+
+2002-02-02  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-cache.el (gnus-summary-insert-cached-articles):
+       (gnus-summary-limit-include-cached): gnus-newsgroup-cached is sorted.
+
+       * gnus-group.el (gnus-group-mark-article-read): Nreverse
+       gnus-newsgroups-unselected.
+
+       * gnus-agent.el (gnus-summary-set-agent-mark): Use
+       gnus-add-to-sorted-list.
+
+       * gnus-sum.el (gnus-summary-update-info): gnus-newsgroup-unreads
+       gnus-newsgroup-unselected are sorted.  Use gnus-sorted-union.
+       (gnus-build-all-threads): Use gnus-add-to-sorted-list.
+       (gnus-update-read-articles): UNREAD is sorted.
+       (gnus-newsgroup-unreads, gnus-newsgroup-unselected)
+       (gnus-newsgroup-marked, gnus-newsgroup-cached)
+       (gnus-newsgroup-expirable, gnus-newsgroup-downloadable)
+       (gnus-newsgroup-dormant): Require sorted.
+
+       * gnus-dired.el (gnus-dired-find-file-mailcap): Correctly handle
+       directories.
+       (gnus-dired-print): New function.
+
+       * gnus-art.el (gnus-mime-print-part): Add argument filename.  Call
+       ps-despool.
+
+2002-02-02  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-dired.el (turn-on-gnus-dired-mode): Autoload.  Make defun.
+
+2002-02-02  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-start.el (gnus-1): Call gnus-agentize if gnus-agent is
+       t.  This makes gnus-agent customizable without putting
+       gnus-agentize into .gnus.
+
+       * gnus.el (gnus-agent): Make it customizable.
+
+       * gnus-cache.el (gnus-cache-articles-in-group): Remove from active
+       if no article.
+       (gnus-cache-possibly-remove-article): Ditto.
+       (gnus-cache-possibly-enter-article): Use gnus-add-to-sorted-list.
+
+2002-02-02  Benjamin Rutt  <brutt@bloomington.in.us>
+
+       * gnus-dired.el: New file.
+
+2002-02-01  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-int.el (gnus-request-accept-article): Use gnus-get-function.
+
+2002-02-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-view.el (mm-w3m-mode-dont-bind-keys): New variable.
+       (mm-setup-w3m): Don't bind keys listed in the above.
+
+2002-02-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-view.el (mm-inline-text-html-render-with-w3m): Bind
+       `w3m-safe-url-regexp' with nil if `mm-inline-text-html-with-images'
+       is non-nil; bind `w3m-force-redisplay' with nil.
+
+       * gnus-art.el (gnus-article-wash-html-with-w3m): Ditto.
+
+       * mm-decode.el (mm-inline-text-html-with-images): Supplement docs.
+
+2002-01-31  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnfolder.el (nnfolder-request-replace-article): Unfold.  Don't
+       use mail-header-unfold-field.
+
+       * gnus-cache.el (gnus-summary-insert-cached-articles): Use
+       gnus-summary-limit.
+
+       * gnus-range.el (gnus-add-to-sorted-list): New function.
+       * gnus-sum.el (gnus-mark-article-as-read): Use it.
+       (gnus-mark-article-as-unread): Ditto.
+       (gnus-summary-mark-article-as-unread): Ditto.
+       (gnus-build-get-header): Ditto.
+       (gnus-summary-prepare-threads): Ditto.
+       (gnus-summary-insert-pseudos): Ditto.
+       (gnus-articles-to-read): Use gnus-sorted-union and gnus-sorted-nunion.
+       (gnus-summary-insert-new-articles): Use gnus-sorted-nunion.
+       (gnus-summary-insert-old-articles): Ditto.
+
+       * gnus-msg.el (gnus-posting-styles): Add new format of header.
+       (gnus-configure-posting-styles): Support the new format.
+
+       * mail-source.el (mail-source-bind, mail-source-bind-common): Set
+       edebug-form-spec to (sexp body).
+       Suggested by Joe Wells <jbw@izanami.cee.hw.ac.uk>.
+
+       * message.el (message-reply-headers): Add doc.
+
+2002-01-30  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-delete-group): Nix the entry in
+       gnus-cache-active-hashtb.
+
+       * gnus-agent.el (gnus-agent-mark-unread-afer-downloaded): New variable.
+       (gnus-agent-summary-fetch-group): Use it.
+
+       * gnus-msg.el (gnus-debug-files): New variable.
+       (gnus-debug-exclude-variables): New variable.
+       (gnus-debug): Use them.
+
+       * gnus-range.el (gnus-range-length): Don't use gnus-uncompress-range.
+
+2002-01-30  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-cite-prefix-regexp): Use text-mode-syntax-table.
+       (message-mode-syntax-table): Move back the previous position.
+
+       * nnagent.el (nnagent-retrieve-headers): Use gnus-sorted-difference.
+
+       * gnus-agent.el (gnus-agent-retrieve-headers): Use
+       gnus-sorted-difference.
+
+       * nnsoup.el (nnsoup-request-expire-articles): Use
+       gnus-sorted-difference.
+
+       * nnheader.el: Autoload gnus-sorted-difference.
+
+       * nnfolder.el (nnfolder-request-expire-articles): Use
+       gnus-sorted-difference.
+
+       * gnus-cache.el (gnus-cache-retrieve-headers): Use
+       gnus-sorted-difference.
+
+       * gnus-range.el: Autoload cookies.
+       (gnus-sorted-difference): New function.
+       (gnus-sorted-ndifference): New function.
+       (gnus-sorted-nintersection): Rename from
+       gnus-set-sorted-intersection.
+       (gnus-sorted-nunion): Rename from gnus-set-sorted-union.
+       (gnus-list-range-difference): Rename from
+       gnus-inverse-list-range-intersection.
+       (gnus-inverse-list-range-intersection): Use defalias.
+
+       * gnus-sum.el (gnus-select-newsgroup): Use gnus-sorted-difference,
+       gnus-sorted-ndifference, and gnus-sorted-nintersection.
+       (gnus-articles-to-read): Use gnus-sorted-difference.
+       (gnus-summary-limit-mark-excluded-as-read): Use
+       gnus-sorted-intersection and gnus-sorted-ndifference.
+       (gnus-list-of-read-articles): Use gnus-list-range-difference.
+       (gnus-summary-insert-articles): Use gnus-sorted-difference.
+
+       * gnus-sum.el (gnus-summary-update-info): Use gnus-sorted-union.
+
+2002-01-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-wash-html-with-w3m): Add keymap
+       property to the buffer for using emacs-w3m command keys.
+
+       * mm-decode.el (mm-inline-text-html-with-w3m-keymap): New user
+       option.
+
+       * mm-view.el (mm-w3m-mode-map): New variable.
+       (mm-w3m-mode-command-alist): New variable.
+       (mm-w3m-minor-mode): Removed.
+       (mm-setup-w3m): Setup `mm-w3m-mode-map'; don't add minor mode.
+       (mm-inline-text-html-render-with-w3m): Add keymap property to the
+       buffer for using emacs-w3m command keys.
+
+2002-01-29  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-mode-syntax-table): Move forward.
+       (message-cite-prefix-regexp): Auto detect non word constituents.
+       (message-cite-prefix-regexp): Don't use with-syntax-table.
+
+       * gnus-sum.el (gnus-summary-update-info): Use
+       gnus-list-range-intersection.
+
+       * gnus-agent.el (gnus-agent-fetch-headers): Use
+       gnus-list-range-intersection.
+
+       * gnus-range.el (gnus-range-normalize): Use correct predicate.
+       (gnus-list-range-intersection): Use it.
+       (gnus-inverse-list-range-intersection): Ditto.
+       (gnus-sorted-intersection): Add doc.
+       (gnus-set-sorted-intersection): Add doc.
+       (gnus-sorted-union): New function.
+       (gnus-set-sorted-union): New function.
+
+       * gnus-range.el (gnus-list-range-intersection): Correct the logic.
+       (gnus-inverse-list-range-intersection): Ditto.
+
+2002-01-29  Karl Kleinpaste  <karl@charcoal.com>
+
+       * mm-uu.el (mm-uu-type-alist): Add optional leading `0'.
+
+       * gnus-uu.el (gnus-uu-shar-name-marker): Add optional leading `0'
+       and permit `:' and `\' in order to handle full Windows pathnames.
+       (gnus-uu-begin-string): Add optional leading `0'.  Leading `0' is
+       technically not correct per standard, but seems to have common use.
+
+2002-01-29  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-uu.el (gnus-uu-expand-numbers): Ignore errors when
+       replacing numbers.
+
+2002-01-28  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-followup-with-original): Use (mark).
+
+       * gnus-score.el (gnus-score-insert-help): Move to (point-min).
+       Don't split when the window is small, e.g. when a small *BBDB*
+       window is the lowest one.
+
+       * gnus-agent.el (gnus-agent-retrieve-headers): Use
+       nnheader-find-nov-line to speed up.  Use nreverse, because it is
+       sorted.  Use nnheader-insert-nov-file.
+
+2002-01-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-decode.el (mm-inline-text-html-with-images): New user option.
+
+       * mm-view.el (mm-inline-text-html-render-with-w3m): Bind the value
+       of `w3m-display-inline-images' with the value of
+       `mm-inline-text-html-with-images'.
+       From: TSUCHIYA Masatoshi <tsuchiya@namazu.org>.
+
+       * gnus-art.el (gnus-article-wash-html-with-w3m): Ditto.
+
+2002-01-27  Richard M. Stallman  <rms@gnu.org>
+
+       * time-date.el: Add autoload cookies.  Many doc fixes.
+       (time-add): New function.
+       (time-subtract): Renamed from subtract-time.
+       (subtract-time): New alias for time-subtract.
+
+2002-01-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-wash-html-with-w3m): Replace w3m to
+       emacs-w3m in doc-string.
+
+       * lpath.el: Bind `w3m-cid-retrieve-function-alist' and
+       `w3m-current-buffer'.
+
+2002-01-27  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * gnus-art.el (gnus-article-wash-html-with-w3m): Handle cid: URLs.
+
+       * mm-view.el (mm-setup-w3m): Add `mm-w3m-cid-retrieve' to
+       `w3m-cid-retrieve-function-alist' for `gnus-article-mode'.
+       (mm-w3m-cid-retrieve): New function.
+       (mm-inline-text-html-render-with-w3m): Handle cid: URLs.
+
+2002-01-27  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-fetch-articles): Don't save empty articles.
+
+2002-01-27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-util.el (gnus-cache-file-contents): Don't use equalp.
+
+2002-01-26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnheader.el (nnheader-insert-nov-file): Increased cutoff to
+       32K.
+
+       * gnus-sum.el (gnus-summary-expire-articles): Clean up.
+
+       * nnmail.el (nnmail-article-group): Decode headers before running
+       split rules over them.
+       (nnmail-mail-splitting-charset): New variable.
+
+       * smiley.el: Replaced with smiley-ems.el.
+
+2002-01-26  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-url.el (mm-url-predefined-programs): Add w3m.
+       (mm-url-program): Ditto.
+
+2002-01-26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnml.el (nnml-use-compressed-files): New variable.
+       (nnml-filenames-are-evil): Removed.
+       (nnml-current-group-article-to-file-alist): Don't use.
+       (nnml-update-file-alist): Inhibit.
+       (nnml-article-to-file): Use new var.
+
+2002-01-26  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-util.el (gnus-parse-without-error): Add edebug-form-spec.
+
+       * nnagent.el (nnagent-retrieve-headers): Loop until eobp.
+
+2002-01-26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-agent.el (gnus-agent-load-alist): Use new caching
+       function.
+
+       * gnus-util.el (gnus-cache-file-contents): New function.
+
+       * gnus-agent.el (gnus-agent-file-loading-cache): New variable.
+       (gnus-agent-load-alist): Use it.
+
+       * nnagent.el (nnagent-retrieve-headers): Use optimized function.
+
+       * nnheader.el (nnheader-insert-nov-file): New function.
+
+       * gnus-util.el (gnus-parse-without-error): Correct the loop.
+
+       * gnus-sum.el (gnus-dependencies-add-header): Use in-reply-to if
+       there are no references.
+       (gnus-extract-message-id-from-in-reply-to): New function.
+       (gnus-nov-parse-line): Use in-reply-to if there are no
+       references.
+
+2002-01-25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnagent.el (nnagent-retrieve-headers): Use new macro.
+
+       * gnus-util.el (gnus-parse-without-error): New macro.
+
+2002-01-25  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-wash-html-with-w3m): Call w3m-region.
+       (gnus-article-wash-function): Use locate-library to decide which
+       to use.
+
+2002-01-25  Simon Josefsson  <jas@extundo.com>
+
+       * pop3.el (pop3-munge-message-separator): Work if no date.
+       Trivial patch from Marius Vollmer <mvo@zagadka.ping.de>.
+
+2002-01-25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-agent.el (gnus-agent-save-alist): Fix.
+
+       * nnagent.el (nnagent-retrieve-headers): Must have cut too much by
+       mistake.  Reinstated lost code.
+
+2002-01-25  Josh Huber  <huber@alum.wpi.edu>
+
+       * mml2015.el (mml2015-mailcrypt-decrypt): Display a signature if
+       one exists in the case of an encrypted message with an internal
+       signature.
+
+2002-01-25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-agent.el (gnus-agent-save-alist): Optimized.
+
+2002-01-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el: Commented out the experimental code.
+
+2002-01-25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-range.el (gnus-inverse-list-range-intersection): Off-by-one
+       error.
+
+       * gnus.el (gnus-server-to-method): Made into subst.
+       (gnus-server-method-cache): New variable.
+       (gnus-server-to-method): Use it.
+       (gnus-group-method-cache): New variable.
+       (gnus-find-method-for-group-1): Renamed.
+       (gnus-find-method-for-group): New function.
+       (gnus-group-method-cache): Removed.
+
+       * gnus-sum.el (gnus-compute-unseen-list): Use new optimized
+       function.
+
+       * gnus-range.el (gnus-members-of-range): New function.
+       (gnus-list-range-intersection): Renamed.
+       (gnus-inverse-list-range-intersection): New function.
+
+       * gnus-sum.el (gnus-compute-unseen-list): Made into own function.
+
+       * nnagent.el (nnagent-retrieve-headers): New implementation.
+
+       * gnus-agent.el (gnus-agent-get-undownloaded-list): New, faster
+       implementation.
+
+2002-01-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind `w3m-charset-to-coding-system'; bind
+       `w3m-meta-content-type-charset-regexp'.
+
+       * mm-view.el (mm-inline-text-html-render-with-w3m): Decode
+       charset-encoded html contents.
+
+2002-01-24  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-request-article): Make sure it is not
+       an empty file.
+
+       * nnweb.el (url): Ignore errors when request url.
+
+       * nnrss.el: Clean up the comments.
+
+2002-01-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * lpath.el: Fbind `w3m-region'; bind `w3m-mode-map'.
+
+       * mm-decode.el (mm-inline-text-html-renderer): New user option.
+       (mm-inline-media-tests): Test whether the value of
+       `mm-inline-text-html-renderer' is a function for text/html.
+
+       * mm-view.el (mm-inline-text-html-render-with-w3): New function
+       separated from `mm-inline-text'.
+       (mm-w3m-minor-mode): New variable.
+       (mm-w3m-setup): New variable.
+       (mm-setup-w3m): New function.
+       (mm-inline-text-html-render-with-w3m): New function.
+       (mm-inline-text): Funcall `mm-inline-text-html-renderer' for
+       text/html.
+
+2002-01-23  Paul Jarc  <prj@po.cwru.edu>
+
+       * lpath.el: fbind make-symbolic-link and unix-sync for nnmaildir.
+
+2002-01-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-xmas.el (gnus-xmas-redefine): Quote `gnus-completing-read'
+       and `gnus-xmas-completing-read'.
+
+2002-01-19  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * nneething.el (nneething-message-id-number): Abolished.
+       (nneething-encode-file-name): Not encode numerical characters.
+       (nneething-make-head): `nneething-message-id-number' is not
+       used to generate message IDs.
+
+2002-01-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-emphasis-alist): Include !? as sentence-ending
+       characters.
+
+2002-01-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-xmas.el (gnus-xmas-completing-read): New function.
+       (gnus-xmas-redefine): Redefine conditionally.
+
+2002-01-22  Josh Huber  <huber@alum.wpi.edu>
+
+       * mml.el (mml-parse-1): Fixed usage of recipients in the secure
+       tag.
+
+2002-01-22  Josh Huber  <huber@alum.wpi.edu>
+
+       * message.el (message-font-lock-keywords): Added the secure tag.
+       * mml-sec.el: Added functions to generate/modify/remove the secure
+       tag while in message mode.
+       * mml-sec.el (mml-secure-message): New.
+       * mml-sec.el (mml-unsecure-message): New.
+       * mml-sec.el (mml-secure-message-sign-smime): New.
+       * mml-sec.el (mml-secure-message-sign-pgp): New.
+       * mml-sec.el (mml-secure-message-sign-pgpmime): New.
+       * mml-sec.el (mml-secure-message-encrypt-smime): New.
+       * mml-sec.el (mml-secure-message-encrypt-pgp): New.
+       * mml-sec.el (mml-secure-message-encrypt-pgpmime): New.
+       * mml.el (mml-parse-1): Added code to recognize the secure tag and
+       convert it to either a part or multipart depending on if there are
+       other parts in the message.
+       * mml.el (mml-mode-map): Changed default sign/encrypt keybindings
+       to use the secure tag, rather than the part tag.
+       * mml.el (mml-preview): Added a save-excursion to keep cursor
+       position after doing an MML preview.
+
+2002-01-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnheader.el (nnheader-parse-overview-file): New function.
+       (nnheader-write-overview-file): New function.
+
+2002-01-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-group-fast-parameter): Check better if expansion
+       in wanted.
+
+       * nnweb.el (nnweb-type-definition): Clean up.
+
+2002-01-21  Alastair Burt  <burt@dfki.de>  (tiny change)
+
+       * gnus-art.el (gnus-mm-display-part): Make sure that the summary
+       buffer exists before jumping to it.
+
+2002-01-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-wash-html-with-w3): Made into own
+       function.
+       (article-wash-html): Use it.
+       (gnus-article-wash-function): New variable.
+       (gnus-article-wash-html-with-w3m): New function.
+
+2002-01-20  Björn Torkelsson  <torkel@acc.umu.se>
+
+       * dgnushack.el (dgnushack-compile): Compile smiley-ems for
+       XEmacs.
+
+2002-01-20  John H. Palmieri  <palmieri@math.washington.edu>
+
+       * gnus-fun.el (gnus-convert-image-to-gray-x-face): More standard
+       command line.
+
+2002-01-21  Simon Josefsson  <jas@extundo.com>
+
+       * canlock.el (base64-encode-string): Autoload it from base64.
+       (canlock-make-cancel-key): Base64 encode unibyte string.
+
+2002-01-20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnfolder.el (nnfolder-request-accept-article): Unfold
+       x-from-line.
+       (nnfolder-request-replace-article): Ditto.
+
+2002-01-20  Nevin Kapur  <nevin@jhu.edu>
+
+       * gnus-group.el (gnus-group-best-unread-group): Use the right
+       positioning function.
+
+2002-01-20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * smiley-ems.el (smiley-region): Use new function.
+       (smiley-update-cache): Use general image functions.
+       (smiley-region): Use general functions.
+
+       * gnus-util.el (gnus-graphic-display-p): New function.
+
+       * nnmail.el (nnmail-article-group): Allow outputting traces of
+       non-strings.
+
+       * nndoc.el (nndoc-type-alist): Rules for exim bounces.
+       (nndoc-exim-bounce-type-p): New function.
+
+       * message.el (message-dont-send): Doc fix.
+
+       * gnus-util.el (gnus-completing-read): Remove
+       inherit-input-method.
+
+       * gnus-art.el (gnus-treat-smiley): Doc fix.
+
+       * gnus-agent.el (gnus-agent-fetch-headers): Ignore seen and recent
+       articles.
+
+2002-01-19  Simon Josefsson  <jas@extundo.com>
+
+       * imap.el (imap-gssapi-open): Don't wait for logout to complete.
+       (imap-kerberos4-open): Ditto.
+       (imap-open): Set port correctly, don't set auth.
+
+2002-01-20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-version-number): Bump version number.
+
+2002-01-20 05:33:30  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.05 is released.
+
+2002-01-20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnkiboze.el (nnkiboze-generate-group): Make sure the directory
+       exists.
+
+       * gnus-spec.el (gnus-string-width-function): New function.
+       (gnus-tilde-cut-form): Use it.
+       (gnus-tilde-max-form): Ditto.
+       (gnus-use-correct-string-widths): Default to (featurep 'xemacs).
+       (gnus-substring-function): Use it.
+       (gnus-tilde-cut-form): Ditto.
+       (gnus-substring-function): New function.
+
+       * message.el (message-check-news-header-syntax): New message.
+
+       * gnus.el (gnus-slave-no-server): Doc fix.
+
+       * gnus-spec.el (gnus-use-correct-string-widths): Default to t.
+
+2002-01-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-adjust-marked-articles): Fix the record for
+       `seen' if it looks like (seen NUM1 . NUM2).  It should be
+       (seen (NUM1 . NUM2)).
+
+2002-01-20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-topic.el (gnus-topic-catchup-articles): Update article
+       number in closed topics.
+
+2002-01-19  Daniel Pittman  <daniel@rimspace.net>
+
+       * gnus-sum.el (gnus-summary-first-unseen-or-unread-subject): New
+       functions.
+
+2002-01-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-group-find-parameter): Clean up.
+
+       * gnus-sum.el (gnus-summary-goto-subject): Error on non-numerical
+       articles.
+
+       * gnus-util.el (gnus-completing-read-with-default): Renamed.
+
+       * nnmail.el (nnmail-article-group): Clean up.
+
+2002-01-19  Paul Stodghill  <stodghil@cs.cornell.edu>
+
+       * gnus-agent.el (gnus-category-name): Intern the category name.
+
+2002-01-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-topic.el (gnus-topic-move-group): Use gnus-topic-history.
+
+       * gnus-util.el (gnus-completing-read): New function.
+
+2002-01-19  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-add-wash-type): Use add-to-list.
+
+       * smiley-ems.el (smiley-region): Register smiley.
+       (smiley-toggle-buffer): Rewrite the function.
+       (smiley-active): Removed.
+
+2002-01-19  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-util.el (gnus-parent-id): Optimize null n case.  From
+       Jesper Harder <harder@ifa.au.dk>.
+
+2002-01-18  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * gnus-art.el (gnus-request-article-this-buffer): Call
+       `nneething-get-file-name' to extract the file name from the
+       message id.
+
+       * nneething.el (nneething-encode-file-name): New function.
+       (nneething-decode-file-name): Ditto.
+       (nneething-get-file-name): Ditto.
+       (nneething-make-head): Encode the file name and encapsulate it
+       into the field of the message id.
+
+2002-01-18  Simon Josefsson  <jas@extundo.com>
+
+       * nnml.el (nnml-request-update-info): Don't erase flags that isn't
+       stored in .marks.
+
+       * nnfolder.el (nnfolder-request-update-info): Ditto.
+
+2002-01-18  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-url-parse-query-string): Allow new line in value.
+
+2002-01-18  Simon Josefsson  <jas@extundo.com>
+
+       * imap.el (imap-starttls-p): Don't check for binary.
+       (imap-gssapi-auth-p): Ditto.
+       (imap-kerberos4-auth-p): Ditto.
+       (imap-open): Change logic.  Iterate through all possible streams,
+       instead of bailing out after first failure.  Move authenticator
+       decision to `imap-authenticate'.
+       (imap-authenticate): Change logic, now finds the authenticator to
+       use, was previously in `imap-open'.
+       (imap-open): Return nil on failure.
+       (imap-open): Setup temp buffer correctly.
+       (imap-open): Return buffer only on success.
+       (imap-interactive-login, imap-interactive-login): Tell the user
+       which stream/authenticator is used for the queried
+       username/password.
+       (imap-open, imap-authenticate): Set variables.
+       (imap-gssapi-auth-p, imap-kerberos4-auth-p): Fix typo.
+       (imap-open): Don't assume how `with-temp-buffer' is implemented.
+
+2002-01-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-fun.el (gnus-grab-cam-x-face): New function.
+
+2002-01-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-emphasis-alist): Allow matching "*this*.)".
+
+2002-01-17  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-toggle-group-plugged): New function.
+       (gnus-agent-group-mode-map): Bind it to "Jo".
+       (gnus-agent-group-make-menu-bar): Add it into menu bar.
+
+2002-01-17  Karl Kleinpaste  <karl@charcoal.com>
+
+       * gnus-xmas.el (gnus-group-toolbar): Add .newsrc save button.
+       (gnus-summary-mail-toolbar): Add mail article deletion button.
+
+       * smiley.el (smiley-deformed-regexp-alist): Eliminate noseless
+       false positives for lines of "^^^^".
+
+       * gnus-picon.el (gnus-picon-find-face): Faces database is all
+       lowercase.
+
+2002-01-17  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-retrieve-headers): Use correct buffer.
+       (gnus-agent-braid-nov): Switch back to nntp-server-buffer.  Remove
+       duplications.
+       (gnus-agent-batch): Bind gnus-agent-confirmation-function.
+
+2002-01-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-initial-limit): Inline
+       gnus-summary-limit-children.
+       (gnus-summary-initial-limit): Don't limit if
+       gnus-newsgroup-display is nil.
+       (gnus-summary-initial-limit): No, don't.
+
+       * gnus-util.el
+       (gnus-put-text-property-excluding-characters-with-faces): Inline
+       gnus-put-text-property.
+
+       * gnus-spec.el (gnus-default-format-specs): New variable.
+
+       * gnus-start.el (gnus-read-newsrc-file): Don't clear
+       gnus-format-specs.
+       (gnus-read-newsrc-el-file): Default to gnus-default-format-specs.
+
+       * gnus-spec.el (gnus-update-format-specifications): Really check
+       the Gnus version of the .newsrc.eld file.
+       (gnus-format-specs): Save the new default summary format.
+
+       * gnus-util.el (gnus-parent-id): Check whether references is empty
+       before splitting.
+
+       * gnus-sum.el (gnus-summary-from-or-to-or-newsgroups): Inline some
+       functions.
+       (gnus-gather-threads-by-references): Inline
+       `gnus-split-references'.
+
+       * gnus-spec.el (gnus-summary-line-format-spec): New, optimized
+       default value of gnus-summary-line-format-spec.
+
+2002-01-15  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnslashdot.el (nnslashdot-retrieve-headers-1): A better error
+       message.
+       (nnslashdot-request-list): Ditto.
+       (nnslashdot-sid-strip): Removed.
+
+2002-01-15  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap-close-asynchronous): Enable.
+       (nnimap-close-group): Expunge.
+
+2002-01-15  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-util.el (gnus-user-date-format-alist): Typo.
+       From: Frank Schmitt <usereplyto@Frank-Schmitt.net>
+
+2002-01-15  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * nneething.el (nneething-request-article): Set
+       `nnmail-file-coding-system' to `binary' locally, in order to read
+       files without any conversion.
+
+2002-01-15  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-retrieve-headers): Use
+       nnheader-file-coding-system and nnmail-active-file-coding-system.
+       (gnus-agent-regenerate-group): Ditto.
+       (gnus-agent-regenerate): Ditto.
+       (gnus-agent-write-active): Ditto.
+       Suggested by Katsumi Yamaoka <yamaoka@jpl.org>
+
+2002-01-14  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-button-alist): Don't highlight <URL:.
+       Suggested by Ian Fitchet <ian.fitchet@lunanbay.com>
+
+2002-01-14  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el: We don't need gnus-article-show-all-headers.
+
+       * gnus-art.el (article-show-all, gnus-article-show-all-header):
+       Ditto.
+
+       * gnus-sum.el (gnus-summary-select-article): Don't call
+       show-all-headers, because hidden headers are not hidden text any
+       more.
+
+2002-01-13  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-newline-and-reformat): Use `newline' instead
+       of inserting \n, so that the newline is marked as hard.
+
+2002-01-13  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-spec.el (gnus-pad-form): Don't evaluate EL multiple times.
+
+2002-01-12  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * imap.el (imap-close): Keep going if quit.
+
+       * gnus-agent.el (gnus-agent-retrieve-headers): Erase
+       nntp-server-buffer.
+
+2002-01-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mm-view.el (mm-display-inline-fontify): Require font-lock to
+       avoid unbinding shadowed variables.
+
+       * gnus-art.el (gnus-picon-databases): Moved here.
+       (gnus-picons-installed-p): Moved here.
+       (gnus-article-reply-with-original): Use `mark'.
+
+       * gnus.el (gnus-picon): Moved here and renamed.
+
+       * gnus-art.el (gnus-treat-from-picon): Only be on if picons are
+       installed.
+       (gnus-treat-mail-picon): Ditto.
+       (gnus-treat-newsgroups-picon): Ditto.
+
+       * gnus-picon.el (gnus-picons-installed-p): New function.
+
+2002-01-12  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-go-online): Fix doc.
+
+2002-01-12  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap-need-unselect-to-notice-new-mail)
+       (nnimap-before-find-minmax-bugworkaround): Use it.
+       (nnimap-find-minmax-uid): Don't reselect current mailbox.
+       (nnimap-dont-close): New variable.
+       (nnimap-close-group): Use it.
+
+2002-01-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-reply-with-original): Use
+       `mark-active'.
+
+       * gnus-msg.el (gnus-summary-reply): Don't bug out on regions.
+
+       * gnus-logic.el (gnus-advanced-score-rule): Thinko fix.
+       (gnus-score-advanced): Clean up.
+       (gnus-score-advanced): Accept a multiple of the score.
+
+2002-01-12  Simon Josefsson  <jas@extundo.com>
+
+       * flow-fill.el (fill-flowed-display-column)
+       (fill-flowed-encode-columnq): New variables.  Suggested by
+       Kai.Grossjohann@CS.Uni-Dortmund.DE (Kai Großjohann).
+       (fill-flowed-encode, fill-flowed): Use them.
+
+       * message.el (message-send-news, message-send-mail): Use
+       m-b-s-n-p-e-h-n.
+
+       * mml.el (autoload): Autoload fill-flowed-encode.
+       (mml-buffer-substring-no-properties-except-hard-newlines): New
+       function.
+       (mml-read-part): Use it.
+       (mml-generate-mime-1): Encode format=flowed if appropriate.
+       (mml-insert-mime-headers): Insert format=flowed.
+
+       * flow-fill.el (fill-flowed-encode): New function.
+       (fill-flowed): Bind fill-column to window width.
+
+2002-01-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-buffer-name): Return the dead name if
+       it exists.
+       (gnus-summary-setup-buffer): Wake up dead summary buffers.
+       (gnus-summary-buffer-name): Don't return the dead name after all.
+       (gnus-summary-setup-buffer): Kill the dead buffer.
+
+       * gnus-art.el (gnus-article-followup-with-original): Store the
+       value of the mark before deactivating it.
+
+2002-01-11  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-fun.el (gnus-display-x-face-in-from): Fake it.
+       From: Karl Kleinpaste <karl@charcoal.com>
+
+       * gnus-art.el (article-display-x-face): Ditto.
+       (gnus-article-reply-with-original): Use gnus-region-active-p.
+       (gnus-article-followup-with-original): Ditto.
+
+       * gnus-sum.el (gnus-summary-read-group-1): Don't select
+       downloadable article either.
+
+2002-01-11  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-display-x-face): Insert From:.
+
+       * gnus-sum.el (gnus-summary-move-article): Don't draw the
+       article.  Bind gnus-display-mime-function and
+       gnus-article-prepare-hook.
+
+       * gnus-agent.el (gnus-agent-retrieve-headers): Load agentview.
+       (gnus-agent-toggle-plugged): Use gnus-agent-go-online.  Move
+       gnus-agent-possibly-synchronize-flags to the last.
+       (gnus-agent-go-online): New function.  New variable.
+
+2002-01-11  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-regenerate-group): Add clean option.
+       (gnus-agent-regenerate): Ditto.
+
+2002-01-11  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-ignored-news-headers)
+       (message-ignored-mail-headers): Add X-Gnus-Agent-Meta-Information:.
+       Suggested by ARISAWA Akihiro <ari@atesoft.advantest.co.jp>
+
+       * gnus.el (gnus-gethash-safe): New macro.
+
+       * gnus-agent.el (gnus-agent-regenerate-history): New function.
+       (gnus-agent-regenerate): Show messages.
+
+2002-01-11  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-regenerate-group): New function.
+       (gnus-agent-regenerate): New function.
+       (gnus-agent-save-alist): Sort.
+       (gnus-agent-copy-nov-line): Test eobp.
+       (gnus-agent-retrieve-headers): Erase buffer.
+
+2002-01-10  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-charset-to-coding-system): Change charset to cs.
+       From: Torsten Hilbrich <email@myrkr.in-berlin.de>
+
+       * gnus.el (gnus-agent-covered-methods): Move here.
+       (gnus-online): New function.
+       (gnus-agent-method-p): Move here.
+
+       * nnagent.el (nnagent-retrieve-headers): Check whether arts is
+       nil.  Remove articles-alist.
+
+       * gnus-start.el (gnus-get-unread-articles): Check online.
+       (gnus-groups-to-gnus-format): Ditto.
+       (gnus-active-to-gnus-format): Ditto.
+
+       * gnus-agent.el (gnus-agent-get-function): Use it.
+       (gnus-agent-get-undownloaded-list): Ditto.
+       (gnus-agent-fetch-session): Only fetch online methods.
+
+       * gnus-srvr.el (gnus-server-make-menu-bar): Add offline.
+       (gnus-server-mode-map): Ditto.
+       (gnus-server-offline-face): New face.
+       (gnus-server-offline-face): New variable.
+       (gnus-server-font-lock-keywords): Add offline.
+       (gnus-server-insert-server-line): Ditto.
+       (gnus-server-offline-server): New function.
+
+       * gnus-int.el (gnus-open-server): Turn to offline.
+       (gnus-server-unopen-status): New variable.
+
+2002-01-10  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnkiboze.el (nnkiboze-request-article): Use
+       gnus-agent-request-article.
+
+       * nnagent.el (nnagent-retrieve-headers): Don't use nnml
+       function.  Insert undownloaded NOV.
+
+       * gnus-agent.el (gnus-agent-retrieve-headers): New function.
+       (gnus-agent-request-article): New function.
+
+       * gnus.el (gnus-agent-cache): New variable.
+
+       * gnus-int.el (gnus-retrieve-headers): Use
+       gnus-agent-retrieve-headers.
+       (gnus-request-head): Use gnus-agent-request-article.
+       (gnus-request-body): Ditto.
+
+       * gnus-art.el (gnus-request-article-this-buffer): Use
+       gnus-agent-request-article.
+
+       * gnus-sum.el (gnus-summary-read-group-1): Don't show the first
+       article if it is undownloaded.
+
+2002-01-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-spec.el (gnus-spec-tab): Deal with wide characters.
+
+2002-01-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * canlock.el (canlock-string-as-unibyte): New macro.
+       (canlock-sha1-with-openssl): Return a unibyte string.
+       (canlock-make-cancel-key): Treat Message-ID as a unibyte string.
+
+2002-01-09  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el (gnus-expand-group-parameters): Match \N or \& only.
+
+2002-01-08  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-encode.el (mm-content-transfer-encoding-defaults): Add
+       application/x-emacs-lisp.
+
+       * gnus-msg.el (gnus-bug): Use application/emacs-lisp.
+
+       * nntp.el (nntp-request-article): Add group parameter.
+       (nntp-request-head): Ditto.
+       (nntp-find-group-and-number): Add parameter group.  Figure out
+       number if the status line doesn't give (e.g. quimby.gnus.org).
+
+2002-01-08  Simon Josefsson  <jas@extundo.com>
+
+       * mml.el (mml-generate-mime-1): Set recipient correctly.
+
+2002-01-08  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-read-from-minibuffer): Add parameter
+       initial-contents.
+       * gnus-msg.el (gnus-summary-resend-message): Use it.
+
+       * gnus-group.el (gnus-group-read-ephemeral-group): Restore the old
+       behavior of quit-config.
+
+2002-01-08  Bjørn Mork  <bmork@dod.no>  (tiny change)
+
+       * message.el (message-make-from): Don't quote fullname.
+
+2002-01-08  Andre Srinivasan  <andre@slamdunknetworks.com>  (tiny change)
+
+       * gnus-group.el (gnus-group-suspend): Don't kill message buffers.
+
+2002-01-07  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-mark-article-read): Typo.  Increase n.
+
+       * gnus-art.el (gnus-header-button-alist): Handle mailto.
+
+       * mml.el (mml-preview): Bind gnus-original-article-buffer because
+       article-decode-group-name uses it.  Bind gnus-article-prepare-hook
+       because bbdb may use it.
+
+2002-01-07  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * nneething.el (nneething-request-article): When a non-text file
+       is converted to an article, its data is encoded in base64.  Call
+       `nneething-make-head' with options to specify MIME types.
+       (nneething-make-head): Add optional arguments to specify MIME
+       types.
+
+2002-01-06  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-fun.el (gnus-display-x-face-in-from): Fake a "From: "
+       header if there is not.
+
+       * gnus-xmas.el (gnus-xmas-put-image): Insert " " if bobp.
+
+       * gnus-msg.el (gnus-gcc-mark-as-read): New variable.
+       (gnus-inews-mark-gcc-as-read): Obsolete variable.
+       (gnus-inews-do-gcc): Use them.
+
+       * gnus-group.el (gnus-group-mark-article-read): Put holes into
+       gnus-newsgroup-unselected.
+
+2002-01-06  Simon Josefsson  <jas@extundo.com>
+
+       * imap.el (imap-ssl-open, imap-ssl-open, imap-parse-fetch): Use
+       condition-case, not ignore-errors.
+
+2002-01-06  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-insert-old-articles): Bind
+       gnus-fetch-old-headers.
+
+       * gnus-art.el (article-display-x-face): Use the current buffer
+       unless `W f'.  Otherwise, X-Face may be shown in the header of a
+       forwarded part.
+       (gnus-treatment-function-alist): Treat xface before hiding
+       headers.
+
+2002-01-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-read-ephemeral-group): Fix
+       parameters.
+
+2002-01-06  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-multibyte-p): Define conditionally when load.
+       (mm-guess-charset): New function.
+       (mm-charset-after): Use it.
+       (mm-detect-coding-region): New function.
+       (mm-detect-mime-charset-region): New function.
+
+       * gnus-sum.el (gnus-summary-show-article): Use
+       mm-detect-coding-region.
+
+2002-01-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-make-fqdn): Be less violent.
+
+       * gnus.el (gnus-logo-color-style): Compute custom form
+       automatically.
+
+       * gnus-sum.el (gnus-summary-enter-digest-group): Feed the adaptive
+       score file of the parent to the document group.
+
+       * gnus-group.el (gnus-group-read-ephemeral-group): Add an optional
+       parameters parameter.
+
+       * gnus-score.el (gnus-score-load-file): Clean up.
+
+2002-01-06  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-thread-sort-by-most-recent-number): Fix typo.
+       From: Damien Wyart <damien.wyart@free.fr>
+
+       * gnus-util.el (gnus-local-map-property): In Emacs 21, use keymap.
+
+2002-01-05  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-select-group-hook): Typo.
+
+       * rfc2047.el (rfc2047-decode-string): Return immediately if there
+       is no quoted-printable-encoded STRING.
+       From: Jesper Harder <harder@ifa.au.dk>
+
+       (rfc2047-decode-string): Decode it.
+
+2002-01-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-logo-color-alist): Added more colors from Luis.
+
+2002-01-05  Keiichi Suzuki  <keiichi@nanap.org>  (tiny change)
+
+       * nntp.el (nntp-possibly-change-group): Erase contents of nntp
+       buffer to get rid of junk line.
+
+2002-01-05  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-mode-map): Bind message-goto-from to C-c C-f
+       C-o.
+       (message-mode-map): Bind message-insert-or-toggle-importance to
+       C-c C-u.
+       (message-mode-map): Bind message-disposition-notification-to to
+       C-c M-n.
+       (message-mode-menu): Add m-d-n-t.
+       (message-mode-field-menu): Add m-goto-from.
+       (message-mode): Doc fix.
+       (message-goto-from): New function.
+       (message-insert-disposition-notification-to): New function.
+       (message-tool-bar-map): Add receipt button.
+
+2002-01-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-thread-latest-date): New function.
+       (gnus-thread-sort-by-most-recent-number): Renamed.
+       (gnus-thread-sort-functions): Doc fix.
+       (gnus-select-group-hook): Don't use setq on a hook.
+       (gnus-thread-latest-date): Use date, not number.
+
+       * gnus-agent.el (gnus-agent-expire-days): Doc fix.
+       (gnus-agent-expire): Allow regexp of expire-days.
+
+       * gnus-art.el (gnus-article-reply-with-original): Deactivate
+       region.
+       (gnus-article-followup-with-original): Ditto.
+
+       * gnus-sum.el (gnus-thread-highest-number): Doc fix.
+
+       * gnus-art.el (gnus-mime-display-alternative): Use
+       gnus-local-map-property.
+       (gnus-mime-display-alternative): Ditto.
+       (gnus-insert-mime-security-button): Ditto.
+       (gnus-insert-next-page-button): Ditto.
+       (gnus-button-prev-page): Take optional args.
+       (gnus-insert-prev-page-button): widget-convert.
+
+       * gnus-util.el (gnus-local-map-property): New function.
+
+       * gnus-art.el (gnus-prev-page-map): Use parent map.
+       (gnus-next-page-map): Ditto.
+
+       * gnus-spec.el (gnus-parse-format): Clean up.
+       (gnus-parse-format): Do complex formatting for %=.
+
+       * gnus-fun.el (gnus-display-x-face-in-from): Add the string
+       "X-Face: " to the data in the built-in scenario.
+
+       * gnus-spec.el (gnus-parse-simple-format): Use gnus-pad-form.
+       (gnus-correct-pad-form): Renamed.
+       (gnus-tilde-max-form): Clean up.
+       (gnus-pad-form): Use gnus-use-correct-string-widths.
+
+       * gnus-fun.el (gnus-display-x-face-in-from): Use native xface
+       support if that is available.
+
+       * gnus-sum.el (gnus-thread-highest-number): New function.
+       (gnus-thread-sort-by-most-recent-thread): New function.
+       (gnus-thread-sort-functions): Doc fix.
+
+2002-01-04  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-select-article): Disable multibyte in
+       all cases.
+       (gnus-summary-mode): Enable it in all cases.
+       (gnus-summary-display-article): Ditto.
+       (gnus-summary-edit-article): Ditto.
+
+       * gnus-ems.el (gnus-put-image): Really return glyph.
+
+       * gnus-art.el (gnus-article-x-face-command): Fix :type.
+       (gnus-treat-smiley): Don't take "P" in the interactive form.
+
+2002-01-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * compface.el (uncompface): XEmacs and Emacs have differing
+       capabilities.
+
+       * gnus-fun.el (gnus-display-x-face-in-from): Use face.
+
+       * gnus-ems.el (gnus-article-xface-ring-internal): Removed.
+       (gnus-article-xface-ring-size): Removed.
+       (gnus-article-display-xface): Removed.
+       (gnus-remove-image): Cleaned up.
+
+       * gnus-xmas.el (gnus-xmas-create-image): Convert pbm to xbm.
+       (gnus-xmas-create-image): Take pbm files.
+       (gnus-x-face): Removed.
+       (gnus-xmas-article-display-xface): Removed.
+
+       * gnus-fun.el (gnus-display-x-face-in-from): Bind
+       default-enable-multibyte-characters.
+
+       * compface.el (uncompface): Doc fix.
+
+       * gnus-art.el (gnus-article-x-face-command): Use
+       gnus-display-x-face-in-from.
+
+       * gnus-xmas.el (gnus-xmas-put-image): Return the image.
+
+       * gnus-ems.el (gnus-put-image): Return the image.
+
+       * gnus-fun.el (gnus-display-x-face-in-from): New function.
+       (gnus-x-face): Moved here.
+
+2002-01-04  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-xmas.el (gnus-xmas-put-image): Don't insert SPC or make
+       invisible if string is nil.
+       (gnus-xmas-article-display-xface): Use it.
+
+       * gnus-ems.el (gnus-put-image): Explicitly use SPC, and add text
+       property when string is nil.
+       (gnus-article-display-xface): Use it.
+
+2002-01-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-display-x-face): Check whether valid grey
+       face was returned.
+       (article-display-x-face): Place image in the right spot.
+
+       * gnus-fun.el (gnus-convert-gray-x-face-to-xpm): Get rid of
+       stderr.
+       (gnus-convert-gray-x-face-to-xpm): Check whether output is valid.
+
+2002-01-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-xmas.el (gnus-xmas-create-image): Take optional
+       parameters.
+       (gnus-xmas-put-image): Allow non-strings to be passed.
+
+       * gnus-art.el (article-display-x-face): Use optional parameters.
+
+       * gnus-ems.el (gnus-create-image): Take optional parameters.
+
+       * gnus-fun.el (gnus-convert-gray-x-face-to-xpm): Use uncompface.
+
+       * compface.el (compface-xbm-p): Removed.
+
+       * gnus-ems.el (gnus-article-compface-xbm): Removed.
+       (gnus-article-display-xface): Use compface.
+
+       * compface.el: New file.
+
+       * gnus-fun.el (gnus-convert-pbm-to-x-face-command): Remove quotes.
+       (gnus-convert-image-to-x-face-command): Ditto.
+       (gnus-random-x-face): Quote argument.
+       (gnus-x-face-from-file): Ditto.
+
+2002-01-03  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir-request-expire-articles): Evaluate
+       the expire-group parameter once per article rather than once
+       per group; bind `nnmaildir-article-file-name' and `article'
+       for convenience.  Leave article alone when expire-group
+       specifies the current group.
+       (nnmaildir--update-nov): Be more concurrency-friendly with
+       temp file names.
+
+2002-01-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-read-init-file): Cleaned up.
+
+2002-01-03  Dave Love  <d.love@dl.ac.uk>
+
+       * gnus-start.el (gnus-startup-file-coding-system): Removed.
+       (gnus-read-init-file): Don't use it.
+
+2002-01-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-agent.el (gnus-agent-fetch-session): Run hook.
+
+2002-01-03  Dave Love  <fx@gnu.org>
+
+       * gnus-start.el (gnus-read-init-file): Don't force coding system
+       for ~/.gnus.
+
+2002-01-03  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nntp.el (nntp-send-buffer): Use mm-with-unibyte-current-buffer.
+       * nnspool.el (nnspool-request-post): Ditto.
+
+       * mm-util.el (mm-use-find-coding-systems-region): New variable.
+       (mm-find-mime-charset-region): Use it.
+
+2002-01-03  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus.el (gnus-summary-line-format): Added :link.
+       * gnus-topic.el (gnus-topic-line-format): Ditto.
+       * gnus-sum.el (gnus-summary-dummy-line-format): Ditto.
+       * gnus-srvr.el (gnus-server-line-format): Ditto.
+       * gnus-group.el (gnus-group-line-format): Ditto.
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Use correct syntax for
+       :keys, it works on both Emacsen.
+
+2002-01-03  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-charset-to-coding-system): Don't setq charset.
+
+2002-01-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-summary-send-map): Fix binding for very-wide.
+
+2002-01-03  Reiner Steib  <reiner.steib@gmx.de>
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Menu bar entries for
+       very wide reply.
+
+2002-01-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-picon.el (gnus-picon-transform-address): Cache stuff.
+       (gnus-picon-cache): New variable.
+       (gnus-picon-transform-newsgroups): Cache stuff.
+
+       * gnus-art.el (gnus-article-reply-with-original): New command.
+       (gnus-article-followup-with-original): New command.
+
+       * gnus-msg.el (gnus-copy-article-buffer): Take optional BEG and
+       END parameters.
+       (gnus-summary-followup): Take a list of list of articles.
+       (gnus-inews-yank-articles): Allow lists of article/regions.
+
+       * gnus-art.el (gnus-article-read-summary-keys): `R' and `F' are no
+       longer the usual commands.
+
+       * gnus-fun.el (gnus-convert-image-to-gray-x-face): Use pnmnoraw.
+       (gnus-convert-gray-x-face-to-xpm): Don't use six parameters to
+       shell-command-on-region.
+
+2002-01-02  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-picon.el (gnus-picon-transform-newsgroups): Fix for the case
+       "Newsgroups: rec.music.beatles.moderated, rec.music.beatles".
+
+2002-01-03  Steve Youngs  <youngs@xemacs.org>
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): XEmacs doesn't
+       understand ':keys', wrap it in an featurep 'xemacs.
+
+2002-01-02  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-ems.el (gnus-article-display-xface): Show xface in the
+       order of headers (Actually, it is called in a reversed order).
+       Add 'gnus-image-text-deletable property.
+       (gnus-remove-image): Remove text with such a property.
+
+       * gnus-xmas.el (gnus-xmas-article-display-xface): Don't use
+       gnus-put-image.
+
+       * gnus-art.el (gnus-article-treat-fold-newsgroups): Replace ", *"
+       with ", ".
+
+2002-01-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-fun.el (gnus-convert-gray-x-face-to-xpm): Renamed.
+
+       * gnus-art.el (gnus-ignored-headers): Hide all X-Faces.
+       (article-display-x-face): Display gray X-Faces.
+
+       * gnus-fun.el (gnus-convert-gray-x-face-region): New function.
+       (gnus-convert-gray-x-face-to-ppm): Ditto.
+       (gnus-convert-image-to-gray-x-face): Ditto.
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Add a :keys to
+       gnus-summary-show-raw-article.
+
+2002-01-02  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       Display picons in XEmacs without showing text.
+
+       * gnus-xmas.el (gnus-xmas-create-image): Don't use
+       mm-create-image-xemacs to create xbm glyph, because it deletes
+       temporary files.
+       (gnus-xmas-put-image): Use end-glyph.  Make text invisible.
+       (gnus-xmas-remove-image): Make text visible, remove glyph.
+
+       * gnus-picon.el (gnus-picon-transform-newsgroups)
+       (gnus-picon-transform-address): Insert spec backward, due to the
+       incompatibility of gnus-xmas-put-image.
+
+2002-01-02  Pavel Janík  <Pavel@Janik.cz>
+
+       * gnus-fun.el (gnus-convert-pbm-to-x-face-command): Doc fix.
+
+2002-01-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el: Doc fix.
+
+       * gnus-art.el: Doc fix.
+
+       * gnus-agent.el: Doc fix.
+
+2002-01-01  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-diary.el, gnus-delay.el: Fix copyright lines.
+
+2002-01-01  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir--update-nov): Automatically parse
+       NOV data out of the message again if nnmail-extra-headers has
+       changed.
+
+2002-01-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-fun.el: New file.
+       (gnus-convert-image-to-x-face-command): New variable.
+       (gnus-insert-x-face): New function.
+       (gnus-random-x-face): Renamed.
+       (gnus-x-face-from-file): Renamed.
+
+       * gnus-art.el (gnus-body-boundary-delimiter): Changed default to
+       "_".
+       (gnus-body-boundary-delimiter): Typo fix.
+
+2002-01-02  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-art.el (gnus-article-treat-body-boundary): Handle nil.
+       (gnus-body-boundary-delimiter): Fix type.
+
+2002-01-01  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-art.el (gnus-treat-buttonize, gnus-treat-buttonize-head)
+       (gnus-treat-emphasize, gnus-treat-strip-cr)
+       (gnus-treat-leading-whitespace, gnus-treat-hide-headers)
+       (gnus-treat-hide-boring-headers, gnus-treat-hide-signature)
+       (gnus-treat-fill-article, gnus-treat-hide-citation)
+       (gnus-treat-hide-citation-maybe)
+       (gnus-treat-strip-list-identifiers, gnus-treat-strip-pgp)
+       (gnus-treat-strip-pem, gnus-treat-strip-banner)
+       (gnus-treat-highlight-headers, gnus-treat-highlight-citation)
+       (gnus-treat-date-ut, gnus-treat-date-local)
+       (gnus-treat-date-english, gnus-treat-date-lapsed)
+       (gnus-treat-date-original, gnus-treat-date-iso8601)
+       (gnus-treat-date-user-defined, gnus-treat-strip-headers-in-body)
+       (gnus-treat-strip-trailing-blank-lines)
+       (gnus-treat-strip-leading-blank-lines)
+       (gnus-treat-strip-multiple-blank-lines)
+       (gnus-treat-unfold-headers, gnus-treat-fold-headers)
+       (gnus-treat-fold-newsgroups, gnus-treat-overstrike)
+       (gnus-treat-display-xface, gnus-treat-display-smileys)
+       (gnus-treat-from-picon, gnus-treat-mail-picon)
+       (gnus-treat-newsgroups-picon, gnus-treat-body-boundary)
+       (gnus-treat-capitalize-sentences, gnus-treat-fill-long-lines)
+       (gnus-treat-play-sounds, gnus-treat-translate)
+       (gnus-treat-x-pgp-sig): Doc fix, add link to manual.
+
+       * gnus-art.el (gnus-body-boundary-delimiter): New variable.
+       (gnus-article-treat-body-boundary): Use it.
+
+       * message.el (message-mode): Fix doc.
+       (message-mode-menu): Fix names.
+
+2002-01-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-first-subject): Really go to unseen
+       articles.
+
+       * gnus-picon.el (gnus-picon-find-face): Search MISC for all types.
+       (gnus-picon-transform-address): Search for unknown faces as well.
+       (gnus-picon-find-face): Don't search "news" for MISC.
+       (gnus-picon-user-directories): Changed default back to exclude
+       "unknown".
+
+       * gnus-sum.el (gnus-summary-hide-all-threads): Reversed logic.
+
+       * gnus-picon.el (gnus-picon-find-face): Search through all
+       databases.
+       (gnus-picon-find-face): New implementation.
+
+       * gnus-topic.el (gnus-topic-goto-previous-topic): New command and
+       keystroke.
+       (gnus-topic-goto-next-topic): Ditto.
+
+       * gnus.el (gnus-summary-line-format): Changed default.
+
+       * nnmail.el (nnmail-extra-headers): Change default.
+
+       * gnus-sum.el (gnus-extra-headers): Change default.
+
+       * message.el (message-news-other-window): Changed "news" to
+       "posting".
+       (message-news-other-frame): Ditto.
+       (message-do-send-housekeeping): Ditto.
+
+       * gnus-sum.el (gnus-summary-maybe-hide-threads): Use predicate
+       function.
+       (gnus-article-unread-p): New function.
+       (gnus-article-unseen-p): New function.
+       (gnus-dead-summary-mode-map): Typo.
+
+       * gnus-util.el (gnus-make-predicate): New function.
+       (gnus-make-predicate-1): New function.
+
+       * gnus-sum.el: New function.
+       (gnus-map-articles): New function.
+
+       * gnus-art.el (gnus-treat-fold-headers): New variable.
+       (gnus-article-treat-fold-headers): New command and keystroke.
+
+       * gnus-sum.el (gnus-dead-summary-mode-map): Clean up.
+       (gnus-dead-summary-mode-map): Bind q to bury-buffer.
+
+2002-01-01  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-fcc-externalize-attachments): New variable.
+       (message-do-fcc): Use it.
+
+       * gnus-msg.el (gnus-gcc-externalize-attachments): New variable.
+       (gnus-inews-do-gcc): Use it.
+
+       * mml.el (mml-tweak-sexp-alist): New variable.
+       (mml-externalize-attachments): New variable.
+       (mml-tweak-part): Use mml-tweak-sexp-alist.
+       (mml-tweak-externalize-attachments): New function.
+
+2002-01-01  Steve Youngs  <youngs@xemacs.org>
+
+       * gnus-xmas.el (gnus-xmas-article-display-xface): Uncomment
+       'set-glyph-face' so x-face back/foreground can be set.
+
+2001-12-31  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-fix-before-sending): Fix a typo.
+
+2002-01-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-treat-smiley): Renamed command.
+       (gnus-article-remove-images): New command and keystroke.
+
+       * gnus-sum.el (gnus-summary-toggle-smiley): Removed.
+
+       * smiley-ems.el (gnus-smiley-display): Removed.
+
+       * gnus.el (gnus-version-number): Update version.
+
+       * message.el (message-text-with-property): Renamed and moved
+       here.
+       (message-fix-before-sending): Highlight invisible text and place
+       point there.
+
+2002-01-01 02:32:53  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.04 is released.
+
+2002-01-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-delay.el (gnus-delay-send-queue): Renamed.
+
+       * gnus-art.el (gnus-ignored-headers): More headers.
+
+       * ietf-drums.el (ietf-drums-parse-addresses): Use `error' instead
+       of `scan-error', since XEmacs doesn't seem to support that.
+
+2001-12-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-best-unread-article): Take a prefix
+       arg.
+       (gnus-summary-best-unread-subject): Ditto.
+       (gnus-summary-best-unread-subject): No, don't.
+       (gnus-summary-better-unread-subject): New command.
+
+       * gnus-xmas.el (gnus-xmas-put-image): Insert the string itself.
+
+       * lpath.el ((featurep 'xemacs)): fbind url function.
+
+       * gnus-xmas.el (gnus-xmas-article-display-xface): Use data, not
+       buffer.
+       (gnus-xmas-remove-image): Implementation that does something.
+       (gnus-xmas-article-display-xface): Mark images properly.
+
+       * gnus-art.el (gnus-mime-print-part): Use mm-temp-directory.
+
+2001-12-31  Florian Weimer  <fw@deneb.enyo.de>
+
+       * gnus.el (gnus): Warn if trying to run Gnus un-byte-compiled.
+
+2001-12-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-line-format): Added %O to the default
+       value.
+
+       * gnus-util.el (gnus-text-with-property): The smallest point is
+       point-min.
+
+       * smiley-ems.el (smiley-region): Return images.
+       (gnus-smiley-display): Allow toggling.
+       (smiley-region): Use text properties, not overlays.
+
+       * gnus-xmas.el (gnus-xmas-remove-image): New function, not
+       implemented yet.
+
+       * smiley-ems.el (smiley-update-cache): Check for valid types.
+
+       * gnus-art.el (gnus-with-article-buffer): New macro.
+
+       * gnus-picon.el (gnus-picon-transform-newsgroups): Keep the
+       strings as well as the glyphs.
+       (gnus-picon-transform-address): Ditto.
+       (gnus-picon-insert-glyph): Ditto.
+       (gnus-picon-transform-newsgroups): Toggle.
+       (gnus-picon-transform-address): Toggle.
+
+       * gnus-ems.el (gnus-remove-image): New function.
+       (gnus-put-image): Take an optional string.
+
+       * gnus-util.el (gnus-text-with-property): New function.
+
+       * gnus-art.el (gnus-delete-images): New function.
+
+       * gnus-ems.el (gnus-article-display-xface): Mark and store image.
+
+       * gnus-art.el (gnus-article-wash-status-entry): Renamed.
+       (gnus-article-wash-status): Use it.
+       (gnus-signature-toggle): Clean up.
+       (gnus-add-wash-status): New function.
+       (gnus-delete-wash-status): New function.
+       (gnus-article-hide-text-type): Use them throughout.
+       (gnus-add-image): New function.
+
+       * gnus-ems.el (gnus-article-display-xface): Use new interface.
+
+       * gnus-xmas.el (gnus-xmas-article-display-xface): Use new
+       interface.
+
+       * gnus-art.el (article-display-x-face): Cleaned up.
+
+       * rfc2047.el (rfc2047-field-value): New function.
+
+       * mail-parse.el (mail-header-field-value): New alias.
+
+       * gnus-art.el (gnus-mime-print-part): Fix typos.
+
+       * smiley-ems.el (gnus-smiley-file-types): New variable.
+       (smiley-update-cache): Use it.
+       (smiley-regexp-alist): Suffix-less smiley names.
+       (smiley-regexp-alist): Added more smileys.
+
+       * gnus-sum.el (gnus-print-buffer): Made into own function.
+       (gnus-summary-print-article): Use it.
+
+       * mailcap.el (mailcap-mime-info): Actually return the bit that we
+       looked for when REQUEST is a string.
+
+       * gnus-art.el (gnus-mime-button-commands): Add printing
+       keystroke.
+       (gnus-mime-copy-part): Doc fix.
+       (gnus-mime-print-part): New command.
+
+2001-12-31  Simon Josefsson  <jas@extundo.com>
+
+       * imap.el (imap-parse-fetch): Notice empty flags responses.  From
+       Nic Ferrier <nferrier@tf1.tapsellferrier.co.uk>.
+
+2001-12-30  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-picon.el (gnus-treat-from-picon): Autoload.
+       (picon): Fix doc.
+
+       * gnus-win.el (gnus-window-to-buffer): gnus-picon-buffer-name no
+       longer exists.  Remove those codes.
+       * gnus.el (gnus-use-picons): Ditto.
+
+2001-12-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-treat-fold-newsgroups): Don't
+       infloop.
+
+       * gnus-sum.el (t): New `W D' map.
+
+       * gnus-art.el (gnus-treat-fold-newsgroups): New variable.
+       (gnus-article-treat-body-boundary): Clean up.
+       (gnus-body-boundary-face): Removed.
+       (gnus-article-goto-header): Moved here.
+       (gnus-article-goto-header): Allow better regexps.
+       (gnus-article-treat-fold-newsgroups): New command.
+
+       * gnus-sum.el (gnus-summary-move-article): We have to select an
+       article to give `gnus-read-move-group-name' an opportunity to
+       suggest an appropriate default.
+
+       * rfc2047.el (rfc2047-fold-line): New function.
+       (rfc2047-unfold-line): Ditto.
+       (rfc2047-fold-region): Don't fold just after the header name.
+
+       * mail-parse.el (mail-header-fold-line): New alias.
+       (mail-header-unfold-line): Ditto.
+
+       * gnus-art.el (gnus-body-boundary-face): Renamed.
+       (gnus-article-treat-body-boundary): Use it.
+       (gnus-article-treat-body-boundary): Use an invisible header and a
+       line of underline characters.
+
+2001-12-30  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * ietf-drums.el (ietf-drums-parse-addresses): Recover from errors.
+
+       * gnus-picon.el (gnus-picon-transform-address): Skip bad addresses.
+       (gnus-picon-split-address): New function.
+       (gnus-picon-find-face): Use it.
+       (gnus-picon-transform-address): Use it.  Set first to t for each
+       address.
+
+       * gnus-art.el (gnus-with-article-headers): Move to here.  Define
+       the macro then use it.
+       (gnus-treatment-function-alist): Treat picons earlier.
+
+2001-12-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-body-separator-face): New variable.
+       (gnus-article-treat-body-boundary): Use a blank, colored line.
+
+       * gnus-picon.el (gnus-picon-find-face): Look into misc/MISC as
+       well.
+
+       * gnus-art.el (gnus-treat-body-boundary): New variable.
+       (gnus-article-treat-unfold-headers): Use helper macro.
+       (gnus-article-treat-body-boundary): New command.
+
+       * gnus.el (gnus-logo-color-style): Change the default color.
+       (gnus-splash-face): Gray, gray.
+
+       * gnus-xmas.el (gnus-xmas-group-startup-message): Use general
+       colors.
+
+       * gnus.el (gnus-logo-color-alist): Moved here and renamed.
+       (gnus-logo-color-style): Ditto.
+       (gnus-logo-colors): Ditto.
+
+       * gnus-picon.el (gnus-picon-create-glyph): Cache glyphs.
+
+       * gnus-art.el (gnus-treat-newsgroups-picon): New variable.
+
+       * gnus-picon.el (gnus-treat-newsgroups-picon): New function.
+       (gnus-picon-transform-newsgroups): New function.
+
+       * ietf-drums.el (ietf-drums-parse-addresses): Accept a nil
+       string.
+
+       * gnus-picon.el (gnus-treat-mail-picon): Renamed.
+
+       * gnus-art.el (gnus-treat-cc-picon): New variable.
+       (gnus-treat-mail-picon): Renamed.
+
+       * gnus-picon.el: New implementation.
+       (gnus-picon-find-face): Renamed.
+       (gnus-treat-from-picon): Use it.
+       (gnus-picon-transform-address): Renamed.
+       (gnus-treat-from-picon): Use it.
+       (gnus-picon-create-glyph): Renamed.
+       (gnus-picon-transform-address): Use it.
+       (gnus-treat-cc-picon): New command.
+
+       * mm-decode.el (mm-create-image-xemacs): Separated out into
+       function.
+       (mm-get-image): Use it.
+
+       * gnus-art.el (gnus-treat-display-picons): Simplify.
+       (gnus-treat-from-picon): Renamed.
+
+       * gnus-ems.el (gnus-create-image): New function.
+       (gnus-put-image): New function.
+
+       * gnus-art.el (gnus-article-treat-unfold-headers): Doc fix.
+       (gnus-with-article-headers): New macro.
+       (gnus-article-goto-header): New function.
+
+       * gnus-xmas.el (gnus-image-type-available-p): New function.
+
+       * gnus-ems.el (gnus-image-type-available-p): New function.
+
+2001-12-30  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnrss.el (nnrss-check-group): Find the correct tag, because
+       xml.el is changed.
+
+2001-12-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-treat-unfold-headers): Only fold when
+       lines are shorter than the window width.
+       (gnus-ignored-headers): More headers.
+
+2001-12-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-treat-unfold-lines): New variable.
+       (gnus-treat-unfold-headers): Renamed.
+       (gnus-article-treat-unfold-headers): New command and keystroke.
+
+       * rfc2047.el (rfc2047-encode-message-header): Clean up.
+
+       * gnus-int.el (gnus-open-server): Mark quit-ed server as denied.
+
+2001-12-29  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * sha1-el.el (sha1-use-external): New variable.
+       (sha1-region): Use it.
+       (sha1-string): Ditto.
+
+       * dgnushack.el (dgnushack-compile): Compile gnus-picon for Emacs.
+       * gnus-picon.el: Less warnings when compile.
+
+2001-12-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-picon.el (gnus-picons-news-directories): Removed obsolete
+       alias.
+       (gnus-picons-database): Default to list.
+       (gnus-picons-lookup-internal): Use it.
+
+       * nnmail.el (nnmail-article-group): Default nnmail-split-methods
+       to "bogus".
+
+       * gnus-win.el (gnus-configure-windows-hook): New hook.
+
+2001-12-29  Sascha Lüdecke  <sascha@meta-x.de>
+
+       * gnus-win.el (gnus-configure-windows): Minimize tree buffer.
+
+2001-12-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-update-marks): Don't uncompress the seen
+       lists.
+       (gnus-select-newsgroup): Don't append; push.
+       (gnus-adjust-marked-articles): Remove obsolete ranges from
+       `seen'.
+       (gnus-update-marks): Clean up.
+       (gnus-select-newsgroup): Don't stomp gnus-newsgroup-seen.
+
+2001-12-29  Frank Schmitt  <usereplyto@Frank-Schmitt.net>
+
+       * gnus-sum.el (gnus-summary-limit-to-age): Allow negative days.
+
+2001-12-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-auto-select-subject): New variable.
+       (gnus-summary-best-unread-subject): New function.
+       (gnus-summary-best-unread-article): Use it.
+       (gnus-summary-first-unseen-subject): New function and command.
+
+       * gnus-art.el (gnus-treatment-function-alist): Emphasize after
+       other treatments.
+
+       * gnus-util.el (gnus-put-overlay-excluding-newlines): New
+       function.
+
+       * gnus-art.el (gnus-article-show-hidden-text): Remove the type
+       from the list of hidden types.
+
+       * mm-view.el (mm-inline-text): Ditto.
+       (mm-inline-text): Ditto.
+       (mm-w3-prepare-buffer): Ditto.
+
+       * gnus-art.el (article-wash-html): Inhibit more remote fetching.
+
+2001-12-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-ignored-headers): Added more headers.
+
+2001-12-29  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-srvr.el (gnus-browse-foreign-server): Compute the prefix
+       once.
+
+2001-12-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-srvr.el (gnus-server-browse-in-group-buffer): Doc fix.
+
+2001-12-28  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-srvr.el (gnus-browse-foreign-server): Fix typo.  From
+       Jesper Harder <harder@ifa.au.dk>.
+
+2001-12-27  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-select-newsgroup): Make
+       `gnus-newsgroup-unseen' sorted.  Make `gnus-newsgroup-unseen'
+       contain all articles (instead of none) when no seen marks have
+       been set for the group.
+       (gnus-update-marks): Use `gnus-range-add' on a uncompressed list
+       instead, it seems to result in shorter ranges.
+
+2001-12-26 11:00:00  Jesper Harder  <harder@ifa.au.dk>
+
+       * mm-util.el (mm-iso-8859-x-to-15-region): Use
+       insert-before-markers.
+
+2001-12-26  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el (nnmaildir-save-mail): Create the destination
+       groups if they do not exist.
+
+2001-12-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * canlock.el (canlock-sha1-with-openssl): Remove unused variable.
+
+2001-12-22 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-read-ephemeral-group): Call
+       gnus-group-real-name.
+
+       * gnus-sum.el (gnus-decode-encoded-word-methods): Backslash paren.
+       (gnus-newsgroup-variables): Ditto.
+
+       * gnus.el (gnus-group-prefixed-name): If group name is prefixed,
+       return it.
+
+2001-12-21  Paul Jarc  <prj@po.cwru.edu>
+
+       * gnus.el (gnus-valid-select-methods): Include nnmaildir.
+       * nnmaildir.el (top-level): Add commentary.
+       (nnmaildir-version): Indicate that nnmaildir is now a standard
+       part of Gnus, not separately released.
+
+2001-12-21 08:00:00  Pavel Janík  <Pavel@Janik.cz>
+
+       * 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.
+
+2001-12-20 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnmaildir.el: Copyright changes.  Require cl only at compile time.
+
+2001-12-20  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (top-level): Don't require cl.  Suggested by ShengHuo
+       ZHU <zsh@cs.rochester.edu>.
+       (nnimap-close-group): Don't quote KEYLIST items.  Suggested by
+       Brian P Templeton <bpt@tunes.org>.
+
+2001-12-19 17:00:00  Paul Jarc  <prj@po.cwru.edu>
+
+       * nnmaildir.el: New file.
+
+2001-12-19 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nndoc.el (nndoc-type-alist): Move forward to the end.
+
+2001-12-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (gnus-find-subscribed-addresses): Replace `mapc' with
+       `dolist'.
+
+2001-12-19 01:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-win.el (gnus-frames-on-display-list): New function.
+       (gnus-get-buffer-window): Use it.
+
+2001-12-19 00:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnwarchive.el (nnwarchive-mail-archive-xover): Fix the regexp.
+
+2001-12-18 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-win.el (gnus-get-buffer-window): Use gnus-delete-if.
+
+2001-12-18 11:00:00  Harald Meland  <Harald.Meland@usit.uio.no>
+
+       * gnus-win.el (gnus-get-buffer-window): New function.
+       (gnus-all-windows-visible-p): Use it.
+
+       * gnus-util.el (gnus-horizontal-recenter)
+       (gnus-horizontal-recenter, gnus-horizontal-recenter)
+       (gnus-horizontal-recenter, gnus-set-window-start): Use it.
+
+       * gnus-score.el (gnus-score-insert-help): Use it.
+
+       * gnus-salt.el (gnus-tree-recenter, gnus-generate-tree)
+       (gnus-generate-tree, gnus-highlight-selected-tree)
+       (gnus-highlight-selected-tree, gnus-tree-highlight-article): Use
+       it.
+
+       * gnus-art.el (gnus-article-set-window-start)
+       (gnus-mm-display-part, gnus-request-article-this-buffer)
+       (gnus-button-next-page, gnus-button-prev-page)
+       (gnus-article-button-next-page, gnus-article-button-prev-page):
+       Use it.
+
+2001-12-18  Josh Huber  <huber@alum.wpi.edu>
+
+       * ChangeLog, ChangeLog.1, nnwfm.el, smiley.el:
+       * gnus-cite.el, gnus-delay.el, gnus-spec.el, message.el:
+       * mml1991.el, nnultimate.el: Removed buffer-file-coding-system tag.
+
+2001-12-18 01:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * ChangeLog, ChangeLog.1, nnwfm.el, gnus-smiley.el:
+       * gnus-cite.el, gnus-delay.el, gnus-spec.el, message.el:
+       * mml1991.el, nnultimate.el: Add `coding'.
+
+2001-12-17  Josh Huber  <huber@alum.wpi.edu>
+
+       * ChangeLog: Changed coding to buffer-file-coding-system.
+       * ChangeLog.1: Same.
+       * nnwfm.el: Same.
+       * gnus-smiley.el: Same.
+       * gnus-cite.el: Moved -*- magic cookie -*- to Local Variables.
+       * gnus-delay.el: Same.
+       * gnus-spec.el: Same.
+       * message.el: Same.
+       * mml1991.el: Same.
+       * nnultimate.el: Same.
+
+2001-12-16  Simon Josefsson  <jas@extundo.com>
+
+       Inspired by code by Dirk Meyer <dischi@tzi.de>.
+       * gnus-sum.el (gnus-summary-muttprint-program): New variable.
+       (gnus-summary-save-map): Add muttprint.
+       (gnus-summary-make-menu-bar): Ditto.
+       (gnus-summary-muttprint): New function.
+
+       * gnus-art.el (gnus-summary-pipe-to-muttprint): New function.
+
+2001-12-14 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * uudecode.el (uudecode-decode-region-internal): Speedup by using
+       temporary list instead of buffer.
+
+       * mm-url.el (executable-find): Autoload.
+
+2001-12-12  Pavel Janík  <Pavel@Janik.cz>
+
+       * gnus-mlspl.el (gnus-group-split-fancy): Doc fix (add reference
+       to variable, follow doc-string conventions).
+
+2001-12-13  Josh Huber  <huber@alum.wpi.edu>
+
+       * gnus-cus.el (gnus-extra-topic-parameters): Added topic parameter
+       subscribe-level.
+       * gnus-topic.el (gnus-subscribe-topics): Use it.
+
+2001-12-13 22:00:00  Sean Neakums  <sneakums@zork.net>  (tiny change)
+
+       * gnus-msg.el (gnus-summary-mail-forward): Forward all marked
+       messages.
+
+       * gnus-uu.el (gnus-uu-grab-articles): Set gnus-current-article to
+       nil after shooting down the gnus-original-article-buffer.
+
+2001-12-13 20:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * uudecode.el (uudecode-use-external): New variable.
+       (uudecode-decode-region): Automatically detect external program.
+
+       * binhex.el (binhex-use-external): New variable.
+       (binhex-decode-region-internal): New function.
+       (binhex-decode-region): Automatically detect external program.
+
+       * mm-uu.el (mm-uu-decode-function, mm-uu-binhex-decode-function):
+       Use them.
+
+2001-12-12  Simon Josefsson  <jas@extundo.com>
+
+       * nnvirtual.el (nnvirtual-always-rescan)
+       (nnvirtual-component-regexp): Fix doc.
+
+       * nnoo.el (defvoo): Add doc to defvoo variables.
+
+       * nnml.el (nnml-directory, nnml-active-file)
+       (nnml-newsgroups-file, nnml-get-new-mail, nnml-nov-is-evil)
+       (nnml-marks-is-evil, nnml-filenames-are-evil)
+       (nnml-prepare-save-mail-hook, nnml-inhibit-expiry): Fix doc.
+
+       * nnmh.el (nnmh-directory, nnmh-get-new-mail)
+       (nnmh-prepare-save-mail-hook, nnmh-be-safe): Fix doc.
+       (nnmh-possibly-change-directory): Use `nnheader-report' instead of
+       `error'.
+
+       * nnmbox.el (nnmbox-mbox-file, nnmbox-active-file)
+       (nnmbox-get-new-mail, nnmbox-prepare-save-mail-hook): ???
+
+       * nnfolder.el (nnfolder-directory, nnfolder-active-file)
+       (nnfolder-newsgroups-file, nnfolder-get-new-mail)
+       (nnfolder-save-buffer-hook, nnfolder-inhibit-expiry)
+       (nnfolder-nov-is-evil, nnfolder-marks-is-evil): Fix doc.
+
+       * nnbabyl.el (nnbabyl-mbox-file, nnbabyl-active-file)
+       (nnbabyl-get-new-mail, nnbabyl-prepare-save-mail-hook): Fix doc.
+
+       * imap.el, nnimap.el: Fix indentation.
+
+       * gnus-sieve.el (gnus-sieve-article-add-rule): Autoload it.
+
+2001-12-12  Didier Verna  <didier@xemacs.org>
+
+       * gnus-msg.el (gnus-group-news): New function.
+       * gnus-group.el (gnus-group-mode-map): Bind it to `i'.
+       * gnus-group.el (gnus-group-make-menu-bar): Add a menu item for it.
+       * gnus-salt.el (gnus-carpal-group-buffer-buttons): Add a button
+       for it.
+       * gnus-msg.el (gnus-summary-news-other-window): New function.
+       * gnus-msg.el ((gnus-summary-send-map "S" gnus-summary-mode-map)):
+       bind it to `i'.
+       * gnus-sum.el (gnus-summary-mode-map): Bind it to `i'.
+       * gnus-sum.el (gnus-summary-make-menu-bar): Add a menu item for it.
+       * gnus-salt.el (gnus-carpal-summary-buffer-buttons): Add a button
+       for it (called with a prefix).
+       * gnus-msg.el (gnus-configure-posting-styles): Add an optional
+       group-name argument.
+       * gnus-msg.el (gnus-setup-message): Use it.
+
+2001-12-12 00:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-show-article): Fix doc.
+
+2001-12-10 17:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mime-to-mml): Remove Content-Disposition too.
+
+2001-12-09 08:00:00  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * gnus-sum.el (gnus-summary-buffer-name): Decode group name.
+       * gnus-group.el (gnus-group-name-decode): Decode unibyte
+       strings only.
+
+2001-12-08  Nevin Kapur  <nevin@jhu.edu>
+
+       * nnmail.el (nnmail-fancy-expiry-targets): New variable.
+       (nnmail-fancy-expiry-target): Use it.
+       Suggestions from Simon Josefsson <jas@extundo.com>.
+
+2001-12-07 14:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-show-article): Recount lines if not exist.
+
+2001-12-07 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnwfm.el (nnwfm-create-mapping): Use gnus-url-unhex-string.
+
+       * gnus-util.el (gnus-url-unhex-string): Move here.
+
+2001-12-07 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnrss.el (nnrss-decode-entities-unibyte-string): Use
+       mm-url-decode-entities-nbsp.
+
+       * nnlistserv.el, nnultimate.el, nnwarchive.el, nnweb.el:
+       * webmail.el, nnwfm.el: Use mm-url.
+
+       * mm-url.el (mm-url-fetch-form): Move from nnweb.
+       (mm-url-remove-markup): Move from nnweb.
+       (mm-url-fetch-simple): Move from webmail.
+
+       * nnslashdot.el (nnslashdot-request-post): Use mm-url-fetch-form.
+
+2001-12-07 01:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-print-truncate-and-quote): New function.
+       (gnus-summary-print-article): Use it.
+
+       * gnus-util.el (gnus-replace-in-string): Typo.
+
+2001-12-06 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnweb.el (nnweb-replace-in-string): Removed.
+
+       * gnus-util.el (gnus-replace-in-string): New function.
+       (gnus-mode-string-quote): Use it.
+
+       * nnrss.el (nnrss-format-string): Use gnus-replace-in-string.
+       * nnwfm.el (nnwfm-create-mapping): Ditto.
+
+2001-12-06 01:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * dgnushack.el (dgnushack-compile): nnrss.el and
+       nnslashdot.el don't depend on nnweb, url, w3.
+
+       * nnrss.el: Use mm-url.
+
+2001-12-06 00:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-url.el (mm-url-insert-file-contents): Support file:.
+
+2001-12-05 14:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-view.el: Lower case for the description line.  Sync from the
+       Emacs CVS.
+
+2001-12-05 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-find-new-groups): Fix doc.
+       From: Stefan Monnier <monnier@cs.yale.edu>
+
+2001-12-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * mm-view.el (mm-inline-text): Decode a charset-encoded rich text.
+
+2001-12-04 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-url.el: Require executable.
+       Suggested by Katsumi Yamaoka <yamaoka@jpl.org>.
+
+2001-12-03 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * pop3.el (pop3-munge-message-separator): Only use valid date.
+       Trivial patch from Michael Welsh Duggan <md5i@cs.cmu.edu>.
+
+       * Makefile.in: gnus-load.elc may not be generated.
+
+2001-12-03 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-url.el: New file.
+       * nnslashdot.el: Use it.
+       * mm-extern.el (mm-extern-url): Use it.
+
+2001-12-01 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-save-article): Nix
+       gnus-display-mime-function and gnus-article-prepare-hook.
+
+       * gnus-spec.el (gnus-parse-complex-format): Properly handle %C at
+       the beginning of lines.
+       (gnus-complex-form-to-spec): Ditto.
+
+2001-12-01 08:00:00  Paul Jarc  <prj@po.cwru.edu>
+
+       * message.el (message-make-mft): Fix the m-s-a-file regexp.
+
+2001-11-30 21:00:00  Paul Jarc  <prj@po.cwru.edu>
+
+       * message.el: New variable message-subscribed-address-file;
+       use it in message-make-mft.
+
+2001-11-30 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-tab-body-function): Set to nil.
+       (message-tab): Use text-mode-map or global-map.
+       Suggested by Kai Großjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>.
+
+2001-11-30  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-agent.el (gnus-agent-fetch-headers): Use gnus-range-add
+       instead of gnus-union, for speed.  Suggested by Christoph Conrad
+       <christoph.conrad@gmx.de>.
+       (gnus-agent-fetch-group-1): Add verbose message.
+
+2001-11-29 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-write-active): Make sure sym is a cons
+       of integers.
+
+2001-11-29  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * message.el (message-newgroups-header-regexp)
+       (message-completion-alist, message-tab-body-function): Use
+       defcustom rather than defvar.
+       (message-tab): Mention `message-tab-body-function' in doc.
+       Suggested by Karl Eichwalder.
+
+2001-11-28 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-uu.el (gnus-uu-save-article): Use #part instead of #mml.
+
+2001-11-28 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnheader.el (nnheader-find-nov-line): Don't use macro
+       gnus-delete-line.
+
+       * gnus-group.el (gnus-group-name-decode): Defun instead of defsubst.
+       (gnus-group-name-charset): Ditto.
+
+       * gnus-util.el (gnus-buffer-live-p): Ditto.
+
+2001-11-28 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * sieve-manage.el (sieve-manage-stream-alist): Backslash before
+       open parenthesis in doc.
+       (sieve-manage-authenticator-alist): Typo in doc.
+       * imap.el (imap-authenticator-alist): Typo in doc.
+       (imap-stream-alist): Backslash.
+
+       * gnus-sum.el (gnus-summary-limit-to-author): Missing arguments.
+       Thanks to david.goldberg6@verizon.net (David S. Goldberg).
+
+2001-11-27 14:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-topic.el (gnus-topic-mode): Add LOCAL for add-hook.
+
+       * message.el (message-mode): make-local-hook is harmless in Emacs 21.
+
+       * gnus-msg.el (gnus-configure-posting-styles): Use
+       make-local-hook.  Add LOCAL for add-hook.
+
+2001-11-27  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * message.el (message-mode): Use `make-local-hook' unless
+       obsolete.
+       Patch by Katsumi Yamaoka <yamaoka@jpl.org>.
+
+2001-11-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * canlock.el: Remove sha1.el and base64.el stuff.
+
+2001-11-26  Didier Verna  <didier@xemacs.org>
+
+       * nnmbox.el (nnmbox-create-mbox): Create the mbox file directory
+       if needed.
+
+2001-11-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-tamago-not-in-use-p): New function.
+       (message-strip-forbidden-properties): Use it.
+
+2001-11-26  Didier Verna  <didier@xemacs.org>
+
+       * gnus-start.el (gnus-check-first-time-used): Only check for
+       existence of .el[d] files.
+
+2001-11-25 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-coding-system-priorities): Add backslash in the doc.
+
+       * message.el (message-setup-1): Clean up mc-*.
+
+2001-11-25 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-util.el (gnus-directory-sep-char-regexp): New variable.
+       * gnus-score.el (gnus-score-find-bnews): Use it.
+
+       * gnus-sum.el (gnus-summary-limit-to-subject): An exclusion version.
+       (gnus-summary-limit-to-author): Ditto.
+       (gnus-summary-limit-to-extra): Ditto.
+       (gnus-summary-find-matching): Support not-matching argument.
+
+2001-11-25  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * message.el (message-wash-subject): Use `insert' rather than
+       `insert-string', which is deprecated.
+
+2001-11-24  Simon Josefsson  <jas@extundo.com>
+
+       * mm-encode.el (mm-encode-content-transfer-encoding): Fix error
+       message.  (Gnus does not "default" to using 8bit for the message,
+       it default to use 8bit encoding and the user-supplied CTE
+       value.  Calling this behavior "treating it as 8bit" is perhaps
+       better.)
+
+       * mm-bodies.el (mm-body-encoding): Intern encoding if needed
+       (compare mm-charset-to-coding-system).
+
+2001-11-23 02:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * canlock.el (canlock-sha1-with-openssl): Use unibyte
+       buffer.  Correctly decode hex.
+
+2001-11-21 01:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-category-insert-line): Convert category
+       names to strings.
+
+2001-11-20 21:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (sha1): eval-and-compile.
+
+2001-11-20  Paul Jarc  <prj@po.cwru.edu>
+
+       * message.el (message-allow-no-recipients): New variable.
+       (message-send): Use it, customize the prompting when posting to
+       Gcc/Fcc alone.
+
+2001-11-20 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-coding-system-priorities): New variable.
+       (mm-sort-coding-systems-predicate): New function.
+       (mm-find-mime-charset-region): Resort coding systems if needed.
+       Suggested by Katsumi Yamaoka <yamaoka@jpl.org>.
+
+2001-11-20  Didier Verna  <didier@xemacs.org>
+
+       * gnus-group.el (gnus-group-make-help-group): New optional
+       argument to control the error behavior.
+       * gnus-start.el (gnus-check-first-time-used): Use it to avoid
+       erroring.
+
+2001-11-19  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-mode-map): Use C-c C-f C-i for Importance:
+       instead of C-c C-u.  Suggested by Per Abrahamsen
+       <abraham@dina.kvl.dk>.
+
+2001-11-18 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnfolder.el (nnfolder-read-folder): Use group instead of
+       nnfolder-current-group.
+       Suggested by Károly Lőrentey <lorentey@elte.hu>.
+
+2001-11-17  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-send): Ask user if Fcc/Gcc should be
+       performed when no other sender was specified.
+       Suggested by prj@po.cwru.edu (Paul Jarc).
+
+2001-11-17  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-mode, message-mode-map): Use C-c C-u for
+       Importance: instead of C-c C-p (used by SC).
+
+2001-11-16  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-insert-importance-high)
+       (message-insert-importance-low): Save point.
+
+       * mail-source.el (mail-source-fetch-imap): Fix BODY.PEEK return
+       value.
+
+2001-11-16  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * message.el (message-strip-special-text-properties): New option.
+       (message-strip-forbidden-properties): Obey it.
+
+2001-11-14  Sam Steingold  <sds@gnu.org>
+
+       * gnus-score.el: Fixed some doc strings to properly quote symbols.
+
+2001-11-15  Simon Josefsson  <jas@extundo.com>
+
+       Support "Importance:" header in Message.
+
+       * message.el (message-mode-map): Bind C-c C-p to
+       `message-insert-or-toggle-importance'.
+       (message-mode-menu): Add message-insert-importance-{high,low}.
+       (message-insert-importance-high, message-insert-importance-low)
+       (message-insert-or-toggle-importance): New functions.
+       (message-tool-bar-map): Add {un,}important.
+       (message-mode): Doc fix.
+
+2001-11-15  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-tool-bar-map): Fix attach toolbar tooltip.
+
+       * mml.el (mml-menu): Fix toolbar tooltip.
+
+2001-11-15 14:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnfolder.el (nnfolder-save-marks): gnus-prin1 takes one argument.
+       * nnml.el (nnml-save-marks): Ditto.
+
+       * gnus-sum.el (gnus-newsgroup-variables): Fix doc.
+
+2001-11-15  Simon Josefsson  <jas@extundo.com>
+
+       * nnml.el (nnml-save-marks):
+       * nnfolder.el (nnfolder-save-marks): Use `gnus-prin1'.
+       Suggested by Istvan Marko <mi-gnus@imarko.dhs.org>.
+
+2001-11-15  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus-art.el (gnus-article-wash-status-strings): Use
+       `copy-sequence', not `copy-seq'.
+
+2001-11-15  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus-art.el (gnus-article-wash-status-strings): New constant.
+       (gnus-gnus-article-wash-status-entry): New function.
+       (gnus-article-wash-status): Use it.
+
+2001-11-13 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml1991.el: Add coding header.
+
+2001-11-12  Simon Josefsson  <jas@extundo.com>
+
+       * mml1991.el (mml1991-use, mml1991-function-alist): New variables.
+       (mml1991-gpg-sign, mml1991-gpg-encrypt): Renamed, from
+       `mml1991-sign' and `mml1991-encrypt'.
+       (mml1991-encrypt, mml1991-sign): New glue functions.
+       (mml1991-mailcrypt-sign, mml1991-mailcrypt-encrypt): New functions.
+
+       * mml.el (mml-mode-map): `C-c RET o' map for PGP.
+       (mml-menu): Add PGP to menu.
+
+       * mml-sec.el (top-level): Require mml1991.  Don't require smime.
+       (mml-sign-alist, mml-encrypt-alist): Add "pgp".
+       (mml-pgp-sign-buffer, mml-pgp-encrypt-buffer)
+       (mml-secure-sign-pgp, mml-secure-encrypt-pgp): New glue functions.
+
+       * mml2015.el: Mention RFC 3156.
+
+2001-11-12  Sascha Lüdecke  <sascha@meta-x.de>
+
+       * mml1991.el: New file.
+
+2001-11-12 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-start.el (gnus-auto-subscribed-groups): Use ^nnml.
+
+2001-11-12  Michael Cook  <Michael.Cook@cisco.com>
+
+       * gnus-sum.el (gnus-summary-move-article): Use number-to-string.
+
+2001-11-11  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (top-level): Autoload sha1.
+       (message-canlock-generate): Use sha1 instead of md5 (sha1 used by
+       canlock, no need to require two different hash algs).  Suggested
+       by Ferenc Wagner <wferi@bolyai1.elte.hu>.
+
+2001-11-09  Pavel Janík  <Pavel@Janik.cz>
+
+       * gnus.el (gnus-local-domain): Fix doc.
+
+2001-11-09  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * message.el (message-point-in-header-p): New function.
+       (message-do-auto-fill): Use it.
+       (message-beginning-of-line): New function.  Goes to beginning of
+       header value (i.e., end of header name), or to beginning of line
+       if already at beginning of value.  Behaves like
+       `beginning-of-line' when in message body.
+       (message-mode-map): Bind it.
+
+2001-11-08  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-msg.el (gnus-posting-styles): Add doc.
+
+2001-11-07  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sieve.el (gnus-sieve-generate): Don't invoke sieve-mode.
+
+       * sieve-mode.el (sieve-control-commands-face)
+       (sieve-control-commands-face, sieve-action-commands-face)
+       (sieve-test-commands-face, sieve-tagged-arguments-face): New
+       faces.
+       (sieve-font-lock-keywords): Use them.
+       (sieve-mode): Only set font-lock-defaults in emacs.
+
+       * gnus-art.el (gnus-default-article-saver): Add
+       gnus-summary-save-body-in-file.
+       (gnus-summary-write-to-file): Fix doc.
+
+2001-11-07  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-art.el (gnus-treat-highlight-signature): Add cross
+       reference to the correct chapter in the manual.
+
+       * mml.el (mml-mode): Add cross reference to Emacs MIME manual.
+       Suggested by "Golubev I. N." <gin@mo.msk.ru>.
+
+2001-11-07 06:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-preview): Bind mail-header-separator.
+
+2001-11-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el: Always require canlock.
+       (message-ignored-supersedes-headers): Include Cancel-Lock and
+       Cancel-Key.
+       (message-insert-canlock): Don't require canlock.
+       (message-cancel-news): Don't check whether canlock is available.
+       (message-supersede): Support cancel-locks.
+
+       * gnus-art.el: Don't autoload canlock.
+
+2001-11-06 18:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mail-source.el (mail-source-fetch-imap): ASYNC param.
+       From: <andre@slamdunknetworks.com>
+
+2001-11-06 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * Many files: Fix copyright lines.
+
+2001-11-05 07:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-generate-mime-1): Use mm-with-unibyte-current-buffer.
+       Suggested by Dave Love  <fx@gnu.org>.
+
+2001-11-04 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-kill-buffer): Remove auto-save file after
+       confirm.
+
+       * message.el (message-send-mail): Call message-generate-headers
+       once.  Suggested by Matt Armstrong <matt@lickey.com>.
+
+       * gnus-topic.el (gnus-topic-rename): Initial-input.
+       Suggested by Katsuhiro Hermit Endo <hermit@koka-in.org>.
+
+2001-11-03  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * message.el (message-forbidden-properties): New constant.
+       (message-strip-forbidden-properties): New function.
+       (message-mode): Activate it.
+
+2001-11-02 17:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-iso-8859-15-compatible): Fix doc.
+       (mm-hack-charsets): Fix doc.
+
+2001-11-02  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-int.el (gnus-check-server): Message "...done" when done.
+
+       * imap.el (imap-close): Don't message (imap-send-command-wait
+       returns if the connection is dropped).
+       (imap-wait-for-tag): Nix out message only when necessary.
+
+       * gnus-sieve.el (gnus-sieve-script): Use "stop" instead of "elsif"
+       for non-crossposting.
+       (gnus-sieve-crosspost): Default to t to be consistent with other
+       parts of Gnus.
+
+2001-11-01 18:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-iso-8859-15-compatible): Add inconvertible chars.
+       (mm-iso-8859-x-to-15-table): Ditto.
+       (mm-iso-8859-x-to-15-region): Ditto.
+       (mm-find-mime-charset-region): Ditto.
+
+2001-11-01  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap-close-asynchronous): New variable.
+       (nnimap-close-group): Use it.
+       (nnimap-expunge): Don't use it.
+
+       * imap.el (imap-callbacks): New variable.
+       (imap-remassoc): Copied from `gnus-remassoc'.
+       (imap-add-callback): New function.
+       (imap-mailbox-expunge, imap-mailbox-close): Support asynchronous
+       behavior.
+       (imap-parse-response): Call the callback.
+
+       * message.el (message-insert-canlock): New variable.
+       (message-canlock-generate, message-canlock-password)
+       (message-insert-canlock): New functions.
+       (message-send-news): Call `message-insert-canlock'.
+       (top-level): Require canlock when compiling.
+       (message-insert-canlock): Require canlock before we need it.
+
+2001-11-01 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-copy-article-buffer): Copy sequence.
+
+2001-11-01 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * dgnushack.el (dgnushack-make-load): A workaround for
+       custom-add-loads bug in some versions of XEmacs.
+
+2001-11-01 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-charset-synonym-alist): Revert (some).
+
+2001-11-01 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-iso-8859-x-to-15-region): New function.
+       (mm-hack-charsets): New variable.
+       (mm-iso-8859-15-compatible): New variable.
+       (mm-iso-8859-x-to-15-table): New variable.
+       (mm-find-mime-charset-region): Add parameter hack-charsets.
+
+       * mm-bodies.el (mm-encode-body): Use it.
+       * mml.el (mml-parse-1): Ditto.
+
+2001-11-01  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-group.el (gnus-group-make-menu-bar): Add Sieve.
+
+2001-11-01 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-charset-to-coding-system): Return nil, if charset
+       is nil.
+
+2001-11-01 07:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * smiley-ems.el (smiley-update-cache): Auto detect file type.
+
+       * message.el (message-forward-rmail-make-body): Use
+       save-window-excursion.
+       (message-encode-message-body): Search with noerror.
+       (message-setup-1): Convert compose-mail send-actions to
+       message-send-actions.
+
+2001-11-01  Simon Josefsson  <jas@extundo.com>
+
+       * sieve.el: Don't require easy-mmode.  Suggested by Katsumi Yamaoka
+       <yamaoka@jpl.org>.
+
+2001-10-31 20:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * sieve-manage.el (sieve-string-bytes): No complain.
+
+2001-11-01  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-group.el (gnus-group-mode-map): Bind "D u" to
+       `gnus-sieve-update' and "D g" to `gnus-sieve-generate'.  (Functions
+       has autoload cookies, so no `require' should be necessary.)
+
+       * sieve.el, sieve-mode.el, sieve-manage.el, gnus-sieve.el: New
+       files.
+
+2001-10-31  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-cus.el (gnus-group-parameters): Support integer `display'
+       parameter.
+
+       * gnus-sum.el (gnus-select-newsgroup): If group parameter
+       `display' is a number (and C-u wasn't used to enter group), only
+       fetch that number of articles.
+
+2001-10-31  Matt Armstrong  <matt@lickey.com>
+
+       * gnus.el (gnus-find-subscribed-addresses): Doc fix:
+       not-subscribed -> subscribed.
+
+2001-10-31 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+       From: Josh Huber <huber@alum.wpi.edu>
+
+       * message.el (message-subscribed-address-functions): New variable.
+       (message-subscribed-addresses): New variable.
+       (message-subscribed-regexps): New variable.
+       (message-goto-mail-followup-to): New function.
+       (message-send-mail): Add Mail-Followup-To.
+       (message-make-mft): New function.
+
+       * gnus.el (gnus-find-subscribed-addresses): New function.
+
+2001-10-31 07:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mail-source.el (mail-source-fetch): If debug, don't regain signals.
+       (mail-source-fetch-pop): Ditto.
+       (mail-source-check-pop): Ditto.
+
+       * gnus-start.el (gnus-read-init-file): Ditto.
+       (gnus-activate-group): Ditto.
+       (gnus-read-newsrc-el-file): Ditto.
+
+2001-10-30 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-get-reply-headers): Make sure there is ", ".
+
+       * mm-util.el (mm-mime-mule-charset-alist): Move down and call
+       mm-coding-system-p.  Don't correct it only in XEmacs.
+       (mm-charset-to-coding-system): Use mm-coding-system-p and
+       mm-get-coding-system-list.
+       (mm-emacs-mule, mm-mule4-p): New variables.
+       (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.
+
+2001-10-30  Dave Love  <fx@gnu.org>
+
+       * mm-util.el (mm-mime-mule-charset-alist): Make it correct by
+       construction.
+       (mm-charset-synonym-alist): Remove windows-125[02].  Make other
+       entries conditional on not having a coding system defined for
+       them.
+       (mm-mule-charset-to-mime-charset): Use
+       find-coding-systems-for-charsets if defined.
+       (mm-charset-to-coding-system): Don't use
+       mm-get-coding-system-list.  Look in mm-charset-synonym-alist
+       later.  Add last resort search of coding systems.
+       (mm-enable-multibyte-mule4, mm-disable-multibyte-mule4)
+       (mm-with-unibyte-current-buffer-mule4): Just treat Mule 5 like
+       Mule 4.
+       (mm-find-mime-charset-region): Re-write.
+       (mm-with-unibyte-current-buffer): Restore buffer as well as
+       multibyteness.
+
+2001-10-30 21:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * canlock.el, sha1-el.el, hex-util.el: Move from contrib
+       directory.  Thanks to Katsumi Yamaoka <yamaoka@jpl.org> and Shuhei
+       KOBAYASHI <shuhei@aqua.ocn.ne.jp>.
+
+2001-10-30 20:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-display-x-face): Nix buffer-read-only
+       again.
+
+       * mml2015.el (mml2015-gpg-verify): Convert <LF> to <CR><LF>.
+
+2001-10-30 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-spec.el (gnus-parse-simple-format): Use
+       buffer-substring-no-properties.
+
+2001-10-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-verify-cancel-lock): New function.
+
+       * nnheader.el (nntp-process-response): New variable.
+       (nnheader-init-server-buffer): Make `nntp-process-response'
+       buffer-local in `nntp-server-buffer'.
+
+       * nntp.el (nntp-prepare-post-hook): New hook.
+       (nntp-wait-for): Save a server's ID in `nntp-process-response'.
+       (nntp-async-trigger): Ditto.
+       (nntp-request-post): Insert a server's ID if there's no Message-ID
+       header; run `nntp-prepare-post-hook'.
+
+2001-10-30 04:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-decode-group-name): Use nnmail-fetch-field
+       instead.
+
+       * message.el (message-forward-subject-author-subject): Don't use
+       message-news-p, which widens the buffer.
+       (message-forward-make-body): New function.
+       (message-forward): Use it.
+       (message-insinuate-rmail): New function.
+       (message-forward-rmail-make-body): New function.
+
+2001-10-30 02:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-extern.el (mm-extern): Provide it.
+
+       * mm-partial.el (mm-partial): Provide it.
+
+2001-10-28 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-setup-message): Call post-command-hook.
+
+2001-10-29  Jesper Harder  <harder@myrealbox.com>
+
+       * mml.el (mml-preview): Bind message-this-is-news if it is
+       news.
+
+2001-10-28  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-group-make-articles-read): Inline group.
+
+2001-10-29  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * smiley-ems.el (smiley-regexp-alist): Add support for sad and
+       ironic smilies.
+
+2001-10-27  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-indent-citation): Don't add trailing
+       whitespace when citing text.
+
+2001-10-27  Jesper Harder  <harder@myrealbox.com>
+
+       * gnus.el (gnus-group-faq-directory): Fix.
+
+2001-10-26 14:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnweb.el (nnweb-possibly-change-server): Create nnweb-hashtb if
+       not available.
+       (nnweb-request-scan): Nix nnweb-hashtb if ephemeral.
+       (nnweb-type-definition): Add google as alias of dejanews.
+       (nnweb-google-parse-1): Forward 1 line.
+
+2001-10-26  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-msg.el (gnus-summary-mail-forward): Doc fix: add pointer to
+       variable `message-forward-ignored-headers'.
+
+2001-10-24  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus.el (gnus-expand-group-parameter): New function.
+       (gnus-expand-group-parameters): Call it.
+       (gnus-group-fast-parameter): New function.
+       (gnus-group-find-parameter): Call it.
+
+2001-10-23  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus.el (gnus-news-group-p): Rewrote.  Now accepts a header
+       vector (it didn't before because of a bug).
+       * gnus-msg.el (gnus-post-news): Use header vector directly, if
+       available.  Before it converted it to an article number.
+
+       This makes followup to news articles with negative numbers in
+       nnvirtual groups use news instead of mail.
+
+2001-10-23  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus.el (post-method): Use `native' instead of `nil'.
+
+       * gnus-msg.el (gnus-post-method): Ditto.
+
+2001-10-23  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus.el (gnus-define-group-parameter): Grammar fix.
+
+2001-10-22  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-msg.el (gnus-extended-version): Include
+       system-configuration.
+       Suggested by Kai.Grossjohann@CS.Uni-Dortmund.DE (Kai Großjohann).
+
+2001-10-22  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus.el (post-method): Customization fix: `native' is not a
+       valid value.
+       * gnus-msg.el (gnus-post-method): Doc and customization fix:
+       `native' is not a valid value.
+
+2001-10-21  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap): Defgroup.
+       (nnimap-strict-function, nnimap-strict-function-match): New
+       widget, from Per Abrahamsen <abraham@dina.kvl.dk>.
+       (nnimap-split-crosspost, nnimap-split-inbox)
+       (nnimap-split-rule, nnimap-split-predicate)
+       (nnimap-split-predicate): Defcustom.
+       (nnimap-split-inbox, nnimap-expunge-search-string)
+       (nnimap-importantize-dormant): Remove "*" from doc.
+
+2001-10-20  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-sum.el (gnus-summary-limit-to-score): Prompt for score if
+       not supplied via prefix arg.  From Lisp, make arg mandatory.
+       Suggested by Frank Schmitt.
+
+2001-10-20  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * message.el (message-do-auto-fill): Avoid calling
+       'rfc822-goto-eoh'.
+
+2001-10-20  Paul Jarc  <prj@po.cwru.edu>
+
+       * message.el (message-get-reply-headers): Restructure the logic
+       and add comments.
+
+2001-10-20  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-cancel-news): Support cancel-locks.
+       Suggested by Per Abrahamsson.
+
+       * nnfolder.el (nnfolder-marks-changed-p): Ditto.
+
+2001-10-20  David Z. Maze  <dmaze@MIT.EDU>
+
+       * nnml.el (nnml-marks-changed-p): Use `equal' when comparing
+       conses.
+
+2001-10-19  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * mm-decode.el (mm-default-directory): Fix customize type.
+
+       * message.el (message-setup-fill-variables): Kludge to use
+       normal-auto-fill-function even if auto fill is already activated.
+
+2001-10-19  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * message.el (message-do-auto-fill): New version that does not
+       rely on text properties, by Simon Josefsson <jas@extundo.com>.
+       (message-setup-1): Removed the `message-field' property.
+
+       * gnus-draft.el (gnus-draft-edit-message): Removed the
+       `message-field' property.
+
+2001-10-19  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus-draft.el (gnus-draft-edit-message): Change `field' to
+       `message-field'.  The `field' property has a special significance in
+       Emacs 21.
+
+       * message.el (message-send, message-setup-1): Ditto.
+
+2001-10-18  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-group-make-articles-read): Call g-r-set-mark
+       when undoing.
+
+2001-10-18  Frank Schmitt  <usereplyto@Frank-Schmitt.net>
+
+       * gnus-sum.el (gnus-summary-limit-to-display-predicate): Fix typo.
+       (gnus-summary-make-menu-bar): Ditto.
+
+2001-10-17  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap-expiry-target): Make sure it is back to the
+       server.  Suggested by ShengHuo ZHU <zsh@cs.rochester.edu>.
+
+2001-10-17 17:00:00  Frank Schmitt  <usenet@Frank-Schmitt.net>
+
+       * gnus-sum.el (gnus-summary-line-format-alist): user-date entry.
+       * gnus-util.el (gnus-user-date): New function.
+
+2001-10-17  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * message.el (message-check-news-header-syntax): Special case
+       nnvirtual groups.
+
+       * gnus-sum.el (gnus-summary-respool-default-method): Changed
+       customize type to `symbol'.
+
+2001-10-17 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-spec.el (gnus-parse-simple-format): Support extended spec
+       %&foo;.
+       (gnus-parse-simple-format): Support user extended spec too.
+       %u&foo; invokes gnus-user-format-function-foo.
+
+2001-10-17 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnml.el (nnml-request-expire-articles): Make sure it is back to
+       the server.
+       * nnmbox.el (nnmbox-request-expire-articles): Ditto.
+       * nnfolder.el (nnfolder-request-expire-articles): Ditto.
+       * nnbabyl.el (nnbabyl-request-expire-articles): Ditto.
+       * nndiary.el (nndiary-request-expire-articles): Ditto.
+       (nndiary-schedule): Defsubst it before use it.
+       (nndiary-error): eval-and-compile.
+
+2001-10-17  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus-msg.el (gnus-post-method): Changed two instances of
+       `active' to `current' and one `null' to `not'.
+
+2001-10-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-setup-fill-variables): Use
+       `normal-auto-fill-function' instead of `auto-fill-function'.
+
+2001-10-16  Simon Josefsson  <jas@extundo.com>
+
+       * mml2015.el (mml2015-fix-micalg): Fix for Mutt-bug.
+       (mml2015-gpg-decrypt-1): Decanonicalize decrypted MIME
+       body.  (Mailcrypt seem to do this, but gpg.el doesn't.)
+
+2001-10-16  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+       Patch by Oliver Scholz <oscholz@my.gnus.org>.
+
+       * gnus-draft.el (gnus-draft-edit-message): Add text property
+       `field' with value `header' to message headers.
+       * message.el (message-setup-1): Really add text property to all of
+       the header, not just part of it.
+
+2001-09-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-sort-by-server): Use it.
+
+       * gnus.el (gnus-method-to-full-server-name): New, bogus function.
+
+       * gnus-topic.el (gnus-topic-sort-groups-by-server): New command
+       and keystroke.
+
+2001-10-14  Simon Josefsson  <jas@extundo.com>
+
+       * dig.el: Doc fix.
+
+       * smime.el: Doc fix.
+
+       * gnus-msg.el (gnus-inews-do-gcc): Port header encoded-word
+       charset magic from message.el.
+
+2001-10-12  Simon Josefsson  <jas@extundo.com>
+
+       Suggested by david.goldberg6@verizon.net (David S. Goldberg).
+
+       * gnus-cite.el (gnus-article-toggle-cited-text): Don't remove
+       'cite from g-a-wash-types.
+       (gnus-cite-toggle): Ditto.  Add 'cite.  Set modeline.
+       (gnus-article-hide-citation): Fix.
+
+       * gnus-cite.el (gnus-article-hide-citation): Add `c' mode line
+       character.
+       (gnus-article-toggle-cited-text): Toggle `c' mode line character.
+
+       * gnus-art.el (gnus-treat-hide-citation-maybe): Remove duplicate
+       definition.
+       (gnus-signature-toggle): Toggle `s' mode line character.
+
+       * gnus-art.el (article-emphasize): Set `g-a-wash-types' after
+       doing stuff that clears it.
+
+2001-10-12  Eric Marsden  <emarsden@laas.fr>
+
+       * gnus-cache.el (gnus-summary-limit-include-cached): Rewrite.
+
+2001-10-12 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-do-auto-fill): Use gnus-point-at-bol.
+       (autoload): Add some autoloads.
+
+2001-10-12  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+       Suggested by Oliver Scholz <epameinondas@gmx.de>.
+
+       * message.el (message-do-auto-fill): New function.  Like
+       `do-auto-fill' but don't fill when in the message header.
+       (message-setup-1): Put a text property on the message header.
+       (message-setup-fill-variables): Use `message-do-auto-fill'.
+
+2001-10-10 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-send-mail-partially): Insert an empty line
+       first, because of the change of message-make-lines.
+
+2001-10-10  Florian Weimer  <fw@deneb.enyo.de>
+
+       * mm-util.el (mm-charset-synonym-alist): If Emacs doesn't support
+       iso-8859-15, make it an alias for iso-8859-1.
+
+2001-10-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-send-news): Don't modify the value of
+       `message-syntax-checks' if it is not a list (possibly it is
+       `dont-check-for-anything-just-trust-me').
+
+2001-10-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-group.el (gnus-group-name-charset-group-alist): Use
+       `find-coding-system' for XEmacs to check whether the coding-system
+       `utf-8' is available.
+
+2001-10-09 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * dgnushack.el (dgnushack-compile): Detect mh-e and xml.
+
+2001-10-09  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * message.el (message-send-news): Oops, missed case with no
+       "Followup-To" header...
+
+2001-10-09  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * message.el (message-send-news): Allow
+       `gnus-group-name-charset-group-alist' to affect encoding of the
+       "Newsgroups" and "Followup-To" headers.
+
+2001-10-07 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * Makefile.in (install-el): Depend on gnus-load.el.
+
+2001-10-07 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * Makefile.in (install-el): Use -f.
+       From: Amos Gouaux <amos+lists.ding@utdallas.edu>
+
+2001-10-07  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * message.el (message-send-news): Don't encode Followups-To when
+       `gnus-group-name-charset-group-alist is' ".*".  [Yuck]
+
+       * gnus-util.el (gnus-decode-newsgroups): No space in newsgroup
+       header.
+
+       * gnus-art.el (article-decode-group-name): Also decode
+       "Followup-To".
+
+       * rfc2047.el (rfc2047-encode-message-header): Encode without
+       asking for null methods.
+
+       * gnus-group.el (gnus-group-name-charset-group-alist): Make utf-8
+       default charset for newsgroup names in accordance with USEFOR.
+
+       * gnus-group.el (gnus-group-name-charset-method-alist,
+       gnus-group-name-charset-group-alist): Removed "*" from doc
+       strings, "*" should not be used for complex variables.
+
+2001-10-06  Simon Josefsson  <jas@extundo.com>
+
+       Support UTF-8 group names better.
+
+       * message.el (message-check-news-header-syntax): Encode group
+       names before comparison.
+
+       * gnus-msg.el (gnus-copy-article-buffer): Run all
+       `gnus-article-decode-hook's except `article-decode-charset'
+       instead of hardcoding call to one of them.
+
+       * gnus-art.el (gnus-article-decode-hook): Add
+       `article-decode-group-name'.
+       (article-decode-group-name): New function, use `g-d-n'.
+
+       * gnus-group.el (gnus-group-insert-group-line): Decode
+       gnus-tmp-group using `g-d-n'.
+
+       * gnus-util.el (gnus-decode-newsgroups): New function.
+
+2001-10-06  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus-srvr.el (gnus-browse-foreign-server): Fixed bug non-nil
+       `gnus-group-name-charset-group-alist'.
+
+2001-10-06 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * Makefile.in: Install el in install.  Add uninstall.
+
+2001-10-05  Simon Josefsson  <jas@extundo.com>
+
+       * nnheader.el (gnus-verbose-backends, gnus-nov-is-evil): Custom.
+
+       * gnus-sum.el (gnus-summary-move-article): Also activate new groups.
+
+       * nnfolder.el (nnfolder-normalize-buffer): Don't insert \n\n in
+       empty folders.
+
+       * gnus-sum.el (gnus-select-newsgroup): Don't enable `display'
+       limiting if read-all (C-u RET) was used.
+
+2001-10-04  Simon Josefsson  <jas@extundo.com>
+
+       * mail-source.el (mail-source-movemail-program): New variable.
+       (mail-source-movemail): Use it.  Suggested by Taylor Hutt
+       <thutt@thutt.vmware.com>.
+
+2001-10-03  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-summary-from-or-to-or-newsgroups): New param.
+       (gnus-summary-line-format-alist): Fix param.
+
+2001-10-02  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap-request-move-article): Use imap.el directly,
+       don't go through `nnimap-request-expire-articles' to delete the
+       article.  Thanks to prj@po.cwru.edu (Paul Jarc).
+
+2001-10-02 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-write-active): The min in the
+       agent/active may be larger than that in the server/active.
+
+2001-10-01  Simon Josefsson  <jas@extundo.com>
+
+       * mail-source.el (mail-source-fetch-imap): Use BODY.PEEK if server
+       is IMAP4rev1.
+
+       * nnml.el (gnus-article-unpropagatable-p): Autoload gnus-sum.
+
+       * nnfolder.el: Ditto.
+
+2001-09-30  Dan Christensen  <jdc@uwo.ca>
+
+       * gnus-sum.el (gnus-summary-extract-address-component): New function.
+       (gnus-summary-from-or-to-or-newsgroups): Optimize.
+
+2001-09-29  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * message.el (message-mode-map): Keybinding for `gnus-delay-article'.
+       (message-mode-menu): Menu item for same.
+
+       * gnus-group.el (gnus-group-make-menu-bar): Menu item for sending
+       delayed articles.
+
+       * gnus-delay.el (gnus-delay-send-drafts): Do nothing if
+       nndraft:delayed does not exist.
+       (gnus-delay-initialize): Don't set up keymap, that's done from
+       message.el now.
+       (gnus-delay, gnus-delay-group, gnus-delay-header)
+       (gnus-delay-default-delay, gnus-delay-default-hour): Customize.
+
+2001-09-29  Simon Josefsson  <jas@extundo.com>
+
+       * mm-util.el (mm-mime-mule-charset-alist): Encode mule-utf-8 as
+       utf-8, not eight-bit-control.
+
+       * imap.el (imap-shell-host, imap-default-user, imap-use-utf7)
+       (imap-log, imap-debug): Custom.
+       (imap-log-buffer, imap-debug-buffer): New constants.
+       (imap-kerberos4-open, imap-gssapi-open, imap-ssl-open)
+       (imap-network-open, imap-shell-open, imap-starttls-open)
+       (imap-send-command-1, imap-send-command, imap-arrival-filter)
+       (imap-debug): Use imap-*-buffer.
+
+       * nndoc.el (nndoc-article-type): Add mailman.
+       (nndoc-type-alist): Ditto.
+       (nndoc-mailman-type-p): New function.
+
+2001-09-28 07:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-xmas.el (gnus-article-x-face-command): Merge it into
+       gnus-art.el.
+
+2001-09-27  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-topic.el (gnus-topic-mode-map): Add catchup.
+       (gnus-topic-catchup-articles): New function.  Suggested by Robin
+       S. Socha <robin-dated-1001857693.185e29@socha.net>.
+
+2001-09-27 11:00:00  Gerd Möllmann  <gerd@gnu.org>
+
+       * gnus-ems.el (gnus-article-display-xface): Insert xface after
+       previous ones.
+
+2001-09-27 07:00:00  Daiki Ueno  <ueno@unixuser.org>
+
+       * gnus-sum.el (gnus-summary-show-article): The arglist of
+       detect-coding-region is incompatible.
+
+2001-09-26 18:00:00  Katsuhiro Hermit Endo  <hermit@koka-in.org>
+
+       * gnus-group.el (gnus-group-delete-group): Typo.
+
+2001-09-26  Simon Josefsson  <jas@extundo.com>
+
+       * nnmail.el (nnmail-expiry-target-group): Add doc warning.
+
+       * nnimap.el (nnimap-expiry-target): Use temp buffer.
+
+2001-09-26 07:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-cus.el (gnus-group-parameters): Display as sexp.
+
+2001-09-22  Simon Josefsson  <jas@extundo.com>
+
+       * nnml.el (nnml-open-marks): Remove unpropagatable marks.
+
+       * nnfolder.el (nnfolder-open-marks): Ditto.
+
+       * gnus-sum.el (gnus-article-unpropagatable-p): New function.
+       (gnus-update-marks): Use it.
+       (gnus-update-marks): Use `gnus-article-mark-to-type' instead of
+       hardcoded list.
+
+       * gnus.el (gnus-article-special-mark-lists): Add killed.
+       (gnus-article-unpropagated-mark-lists): New constant.
+
+2001-09-22  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-summary-mode-hook): Add gnus-pick-mode as
+       custom option.
+
+2001-09-23  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-draft.el (gnus-draft-setup): Add mark in backend as well.
+
+2001-09-23 02:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-button-mailto): Hack save-selected-window-window.
+
+2001-09-22  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus-group.el (gnus-group-sort-function): Fix customize type to
+       accept lists of functions.
+
+2001-09-20  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-group.el (gnus-group-catchup): Update expire marks in
+       backend.  Also, if ALL also set expire marks on tick/dormant.
+
+2001-09-20  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * message.el (message-tab-body-function): New variable.
+       * message.el (message-tab): Use it.
+
+2001-09-19  Sam Steingold  <sds@gnu.org>
+
+       * gnus-win.el (gnus-buffer-configuration): Respect
+       `gnus-bug-create-help-buffer'.
+
+2001-09-18  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-spec.el (gnus-correct-pad-form): Re-revert.
+       (gnus-parse-simple-format): Re-revert.
+
+2001-09-16  Katsuhiro Hermit Endo  <hermit@koka-in.org>  (tiny change)
+
+       * gnus-spec.el (gnus-parse-complex-format): Don't fold search
+       case.  (Thanks to Daiki Ueno <ueno@unixuser.org>.)
+
+2001-09-18  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-spec.el (gnus-correct-pad-form): Remove until papers are
+       signed.
+       (gnus-parse-simple-format): Don't use it.
+
+2001-09-17  Miles Bader  <miles@gnu.org>
+
+       * gnus-srvr.el (gnus-server-insert-server-line): Don't let an
+       error querying a backend abort the whole process.
+
+2001-09-17 08:00:00  Gerd Möllmann  <gerd@gnu.org>
+
+       * gnus-srvr.el (gnus-server-mode): Fix bogus fontification.
+
+2001-09-17  Didier Verna  <didier@xemacs.org>
+
+       * nndiary.el: Version 0.2-b14.
+       * gnus-diary.el (gnus-diary-check-message): Fix `read-string'
+       compatibility problem with XEmacs 21.1.
+
+2001-09-15  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-group.el (gnus-group-line-format): Document %c.
+
+       * nnml.el (nnml-parse-head): Handle CRLF files.
+       (nnml-generate-nov-file): Ditto.
+       (nnml-retrieve-headers): Ditto.
+
+2001-09-15  Michael Welsh Duggan  <md5i@cs.cmu.edu>
+
+       * gnus-spec.el (gnus-parse-format): Don't treat %c as %C.
+
+2001-09-13  Martin Kretzschmar  <Martin.Kretzschmar@inf.tu-dresden.de>
+
+       * gnus-spec.el (gnus-correct-substring): Still stopped one
+       character before we wanted (never included last character).
+       (gnus-tilde-max-form, gnus-tilde-cut-form) Made readable again,
+       add missing "," (once per function).
+
+2001-09-14  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-start.el (gnus-group-mode-hook): Moved from gnus-group
+       (otherwise e.g. gnus-agentize in .gnus overrides the customized
+       default before gnus-group is loaded and the variable set.)
+
+       * nnimap.el (nnimap-request-set-mark): Do not store bookmark,
+       killed or unsent marks.
+
+       * gnus-draft.el (gnus-draft-setup): Don't set mark when there
+       isn't an article to set it on (e.g. when you `a' in a group).
+
+2001-09-12  Pavel Janík  <Pavel@Janik.cz>
+
+       * mm-util.el (mm-charset-synonym-alist): Add windows-1250 so we
+       can read e-mails from Microsoft Outlook users not using ISO
+       8859-2 character set.
+
+2001-09-12 18:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-diary.el: Minor modifications to avoid warnings.
+       (gnus-summary-misc-menu): defvar.
+       (gnus-diary-check-message): Use gnus-point-at-eol.
+       (gnus-diary-kill-entire-line): eval-and-compile.
+
+2001-09-12  Didier Verna  <didier@xemacs.org>
+
+       * nndiary.el: New version (0.2-b13).
+       * nndiary.el (nndiary-mail-sources): Doc update.
+       * nndiary.el (nndiary-split-methods): Ditto.
+       * nndiary.el (nndiary-request-accept-article-hooks): New.
+       * nndiary.el (nndiary-request-accept-article): Use it, check
+       message validity.
+       * nndiary.el (nndiary-get-new-mail): Changed default to nil.
+       * nndiary.el (nndiary-schedule): Fix bug (misplaced
+       condition-case): it didn't return nil on error.
+       * gnus-diary.el: New version.
+       * gnus-diary.el (gnus-diary-summary-line-format): Removed %I.
+       * gnus-diary.el (gnus-diary-header-value-history): New.
+       * gnus-diary.el (gnus-diary-narrow-to-headers): New.
+       * gnus-diary.el (gnus-diary-add-header): New.
+       * gnus-diary.el (gnus-diary-check-message): New.
+       * gnus-diary.el (message-mode-map): Bind the above to `C-c D c'.
+       * gnus-diary.el (gnus-article-edit-mode-map): Ditto.
+
+2001-09-10  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * gnus-sum.el (gnus-select-newsgroup): Make
+       `gnus-current-select-method' buffer-local.
+
+       * gnus-art.el (gnus-request-article-this-buffer): Refer
+       `gnus-current-select-method' in the current summary buffer.
+
+2001-09-10  Daniel Pittman  <daniel@rimspace.net>
+
+       * gnus-spec.el (gnus-correct-pad-form): Fix.
+
+2001-09-09  Simon Josefsson  <jas@extundo.com>
+
+       * mm-decode.el (mm-inline-media-tests): Add
+       application/x-emacs-lisp.
+       (mm-attachment-override-types): Add
+       application/{x-,}pkcs7-signature.
+
+       * gnus-srvr.el (gnus-server-mode-hook, gnus-server-exit-hook)
+       (gnus-server-line-format, gnus-server-mode-line-format)
+       (gnus-server-browse-in-group-buffer): Customize.
+
+2001-09-08 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnml.el (nnml-marks-changed-p): Typo.
+       (nnml-save-marks, nnml-open-marks): Use gnus-sethash.
+       (nnml-marks-changed-p): Use gnus-gethash.
+       (nnml-marks-modtime): Use gnus-make-hashtable.
+
+       * nnfolder.el (nnfolder-marks-changed-p): Typo.
+       (nnfolder-request-expire-articles, nnfolder-save-marks)
+       (nnfolder-open-marks): Typo.
+       (nnfolder-save-marks, nnfolder-open-marks): Use gnus-sethash.
+       (nnfolder-marks-changed-p): Use gnus-gethash.
+       (nnfolder-marks-modtime): Use gnus-make-hashtable.
+
+2001-09-08  Simon Josefsson  <jas@extundo.com>
+
+       * nnfolder.el (nnfolder-marks-modtime): New variable.
+       (nnfolder-marks-changed-p): New function.
+       (nnfolder-save-marks, nnfolder-open-marks): Save modtime.
+       (nnfolder-request-update-info): Don't update if marks didn't change.
+
+       * nnml.el (nnml-marks-modtime): New variable.
+       (nnml-marks-changed-p): New function.
+       (nnml-save-marks, nnml-open-marks): Save modtime.
+       (nnml-request-update-info): Don't update if marks didn't change.
+
+       * gnus-agent.el (gnus-agent-any-covered-gcc)
+       (gnus-agent-add-server, gnus-agent-remove-server): Use
+       gnus-agent-method-p.
+
+       * gnus-art.el (gnus-buttonized-mime-types): New variable.
+       (gnus-unbuttonized-mime-type-p): Use it.
+
+       * gnus-agent.el (gnus-agent-fetch-group): If online, actually
+       fetch group.
+
+2001-09-08  Daniel Pittman  <daniel@rimspace.net>
+
+       * gnus-spec.el (gnus-correct-pad-form): New function.
+       (gnus-parse-simple-format): Use it.
+
+2001-09-07  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-group.el (gnus-group-sort-groups): Unmark all groups.
+       (gnus-group-sort-selected-groups): Ditto.  Suggested by Harry
+       Putnam <reader@newsguy.com>.
+       (gnus-group-sort-selected-groups): Touch dribble file.
+
+2001-09-07  Raja R Harinath  <harinath@cs.umn.edu>
+
+       * nnml.el (nnml-filenames-are-evil): New variable.
+       (nnml-article-to-file-alist): Rename to ...
+       (nnml-current-group-article-to-file-alist): ... this.
+       Respect `nnml-filenames-are-evil'.
+       (nnml-active-number): Update.
+       (nnml-update-file-alist): Update.
+       (nnml-request-article): Use nnheader-article-to-file-alist.
+       (nnml-request-rename-group): Likewise.
+
+2001-09-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-insert-line): Fix.
+
+2001-09-06  Björn Torkelsson  <torkel@acc.umu.se>
+
+       * gnus-sum.el: Bind g-s-t-s to "W g".
+       * gnus-sum.el (gnus-summary-make-menu-bar): Add g-s-t-s.
+       * gnus-sum.el (gnus-summary-toggle-smiley): New function.
+       Toggles display of graphical smilies.
+
+2001-09-07 02:00:00  Bill White  <billw@wolfram.com>
+
+       * gnus-start.el (gnus-setup-news): A typo.
+
+2001-09-06  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-summary-insert-line): Insert forwarded, recent
+       and unseen marks.
+
+2001-09-05  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * nnmail.el (nnmail-split-fancy): Document `junk'.
+
+2001-09-04  Simon Josefsson  <jas@extundo.com>
+
+       * imap.el (imap-search): Don't error if server is broken.
+
+2001-09-02  Benjamin Rutt  <brutt@bloomington.in.us>
+
+       * nnmbox.el (nnmbox-find-article): Fix infinite loop when
+       searching for an article that isn't in the mbox.
+
+2001-09-02 23:12:48  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnslashdot.el (nnslashdot-retrieve-headers-1): Get references
+       right, and get all the comments.
+
+2001-09-02  Simon Josefsson  <jas@extundo.com>
+       Suggested by Dan Christensen <jdc+news@uwo.ca>
+
+       * nnfolder.el (nnfolder-request-update-info): Fix message.
+
+       * nnml.el (nnml-request-update-info): Ditto.
+
+2001-09-01  Simon Josefsson  <jas@extundo.com>
+
+       * nnml.el (nnml-request-expire-articles): Also bind
+       `nnml-current-group' and `nnml-article-file-alist' when using
+       expiry-target.  (Otherwise nnml will be in a inconsistent internal
+       state causing all kind of problems.)
+       (nnml-request-expire-articles): If `nnml-article-to-file' or
+       `file-attributes' fail, return article as un-expirable instead
+       of treating it as expired.
+
+2001-08-31  Sam Steingold  <sds@gnu.org>
+
+       * imap.el (imap-mailbox-examine, imap-mailbox-examine-1): Fix a
+       typo: `exmine' --> `examine'.
+
+2001-08-30 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nndoc.el (nndoc-forward-type-p): It is not a digest.
+
+2001-08-30 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnml.el (nnml-check-directory-twice): Remove.
+       (nnml-retrieve-headers): Ditto.
+       (nnml-article-to-file): Use nnheader-directory-files-is-safe.
+
+2001-08-30  Andrew Innes  <andrewi@gnu.org>
+
+       * nnheader.el (nnheader-directory-files-is-safe): No need to read
+       directory twice on Windows, or on GNU Emacs-21.
+
+2001-08-30  Andrew Innes  <andrewi@gnu.org>
+
+       * nnml.el (nnml-request-article): Use nnml-article-to-file-alist.
+       (nnml-request-rename-group): Ditto.
+       (nnml-active-number): Ditto.
+       (nnml-request-create-group): Use nnml-directory-articles.
+       (nnml-request-expire-articles): Use nnml-directory-articles, which
+       gets list from nov database if available.
+       (nnml-get-nov-buffer): New function.
+       (nnml-open-nov): Use it.
+       (nnml-update-file-alist): Use nnml-article-to-file-alist, which
+       gets alist from nov database if available.
+       (nnml-directory-articles): New function.
+       (nnml-article-to-file-alist): New function.
+
+2001-08-30  Andrew Innes  <andrewi@gnu.org>
+
+       * mm-decode.el (mm-display-external): Use `name' as filename, if
+       `filename' attribute is not present.
+
+2001-08-30  Andrew Innes  <andrewi@gnu.org>
+
+       * mail-source.el (mail-source-flash): New defcustom.
+       (mail-source-new-mail-p): Ring visible bell if appropriate.
+       (mail-source-start-idle-timer): Use unwind-protect to ensure idle
+       timer is cleared even if mail check signals an error.
+
+2001-08-29 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-move-article): Only update marks of
+       type 'list.
+
+2001-08-29 00:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * flow-fill.el (fill-flowed): eol might be point-max.
+
+2001-08-27  Simon Josefsson  <jas@extundo.com>
+
+       * nnml.el (nnml-request-update-info): Fix message.
+       (nnml-open-marks): Ditto.
+
+       * nnfolder.el (nnfolder-request-update-info):
+       (nnfolder-open-marks): Fix message.
+
+2001-08-25  Simon Josefsson  <jas@extundo.com>
+
+       * nnfolder.el (nnfolder-save-marks): Don't create directory named
+       after group in ~/.
+
+2001-08-25  Andreas Jaeger  <aj@suse.de>
+
+       * nnfolder.el (nnfolder-open-marks): Fix typo.
+       * nnml.el (nnml-open-marks): Likewise.
+
+2001-08-25  Simon Josefsson  <jas@extundo.com>
+
+       Make nnfolder groups self-contained as far as marks are concerned.
+
+       * nnfolder.el (nnfolder-marks-directory, nnfolder-marks-is-evil)
+       (nnfolder-marks, nnfolder-marks-file-suffix): New variables.
+       (nnfolder-open-server): Make marks directory.
+       (nnfolder-request-delete-group): Delete marks file.
+       (nnfolder-request-delete-group): Check of nov/marks file exist
+       before deleting.
+       (nnfolder-request-rename-group): Rename marks file.
+       (nnfolder-request-rename-group): Only rename nov/mark if they exists.
+       (nnfolder-request-set-mark, nnfolder-request-update-info)
+       (nnfolder-group-marks-pathname, nnfolder-save-marks)
+       (nnfolder-open-marks): New functions.
+       (top-level): Require gnus.
+
+2001-08-25 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnweb.el (nnweb-type-definition): Use google raw file.
+       (nnweb-google-parse-1): Ditto.
+       (nnweb-google-identity): Ditto.
+       (nnweb-reference-wash-article): Move nnweb-decode-entities here.
+       (nnweb-altavista-wash-article): Ditto.
+       (nnweb-request-article): Remove nnweb-decode-entities.
+
+       * nnml.el: Require 'gnus.
+
+2001-08-25  Simon Josefsson  <jas@extundo.com>
+
+       * nnml.el (nnml-marks-is-evil): Add doc.
+
+2001-08-25  Simon Josefsson  <jas@extundo.com>
+
+       * nnml.el (nnml-save-marks): Wrap saving marks in a
+       condition-case, to allow user to start Gnus if saving marks failed
+       for some reason.
+
+2001-08-24 16:05:38  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-spec.el (gnus-compile): Don't compile gnus-version.
+
+       * gnus-group.el (gnus-update-group-mark-positions): Bind
+       gnus-group-update-hook to nil.
+
+2001-08-24 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-generate-mime-1): Force as multibyte string.
+
+2001-08-24 12:00:00  Martin Kretzschmar  <Martin.Kretzschmar@inf.tu-dresden.de>
+
+       * gnus-sum.el (gnus-summary-insert-line)
+       (gnus-summary-prepare-threads): gnus-tmp-lines should be a string.
+
+2001-08-24 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-spec.el (gnus-correct-substring): Take optional END.
+
+       * nnrss.el (nnrss-request-article): Remove \n.
+       (nnrss-retrieve-headers): Lines number is -1.
+
+2001-08-24  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-group.el (gnus-info-clear-data): Call
+       nnfoo-request-set-mark to propagate marks.  Fix bug:
+       `gnus-group-update-line' doesn't update read range unless we call
+       `gnus-get-unread-articles-in-group' first.
+
+       * nnimap.el (nnimap-request-set-mark): Don't propagate seen flags
+       to server.
+
+2001-08-23 21:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-util.el (gnus-create-info-command): Return an interactive
+       function.
+
+2001-08-23 19:00:00  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-spec.el (gnus-parse-complex-format): Use equal.
+
+2001-08-23 18:43:05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-select-newsgroup): Use it.
+
+       * gnus-util.el (gnus-not-ignore): New function.
+
+       * lpath.el (featurep): Don't fbind char-int.
+
+       * gnus-util.el (gnus-create-info-command): New function.
+
+       * gnus-group.el (gnus-group-edit-group): Make C-c C-i go to the
+       right node.
+
+       * gnus-sum.el (gnus-select-newsgroup): Clean up.
+       (gnus-summary-limit-children): Use 'identity instead of `all'.
+       (gnus-summary-limit-to-display-predicate): New command and
+       keystroke.
+
+2001-08-23 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnrss.el (nnrss-group-alist): Use fm-releases.rdf.
+
+       * gnus-spec.el (gnus-format-specs): Miss a right parenthesis.
+
+2001-08-23 18:43:05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-spec.el: Add the Gnus version.
+       (gnus-update-format-specifications): If the Gnus version changes,
+       nix out the format spec cache.
+
+       * gnus.el (gnus-continuum-version): Made into a command and
+       optionalize the VERSION.
+
+       * gnus-spec.el (gnus-parse-complex-format): Remove %C specs from
+       the start of the lines.
+
+2001-08-22 00:06:52  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-visual-p): Define function before use of
+       function.
+
+2001-08-21 23:28:02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-adjust-marked-articles): Use new variable.
+       (gnus-article-mark-to-type): New function.
+       (gnus-update-missing-marks): Only update marks of type 'list.
+
+       * gnus.el (gnus-article-special-mark-lists): New variable.
+
+2001-08-21 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-limit-children): Check 'all.
+       (gnus-select-newsgroup): Still use 'all.
+       (gnus-summary-initial-limit): Comparing with 'all.
+
+2001-08-20 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-start.el (gnus-activate-group): If dont-check, don't update
+       active.
+
+2001-08-20 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnslashdot.el (nnslashdot-retrieve-headers-1): Replace
+       nnslashdot-*-retrieve-headers.
+       (nnslashdot-request-article): Fix for slashcode 2.2.
+       (nnslashdot-make-tuple): New function.
+       (nnslashdot-read-groups): Use it.
+
+2001-08-20 01:34:03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-expand-group-parameters): Don't alter the variable
+       list.
+
+       * gnus-sum.el (gnus-summary-move-article): Don't select article.
+
+2001-08-20  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-msg.el (gnus-inews-do-gcc): If archive server can't be
+       opened, error instead of continuing (and exploding later).
+
+2001-08-20 01:34:03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.el (gnus-expand-group-parameters): Return the parameter
+       list.
+
+       * gnus-sum.el (gnus-summary-show-article): Doc fix.
+       (gnus-summary-show-article): Guess at charset if required.
+
+       * gnus-spec.el (gnus-correct-substring): Stopped one character
+       before we wanted.
+
+2001-08-19  Pavel Janík  <Pavel@Janik.cz>
+
+       * earcon.el (earcon-auto-play): Remove unused option.
+
+2001-08-19 16:14:41  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-score.el (gnus-score-headers): Move the "Scoring..."
+       message down in levels, since it happens very fast.
+
+       * smiley-ems.el (smiley-update-cache): Respect the symbol version
+       of smiley-regexp-alist.
+
+       * mm-view.el (mm-inline-text): Ignore vcard errors.
+
+       * gnus-art.el (gnus-ignored-headers): Added more junk headers.
+
+       * gnus-score.el (gnus-all-score-files): Use append instead of
+       nconc.
+
+       * gnus.el (gnus-splash-face): Doc fix.
+
+       * mm-decode.el (mm-mailcap-command): Use
+       mm-path-name-rewrite-functions.
+       (mm-path-name-rewrite-functions): New variable.
+
+       * gnus-spec.el (gnus-parse-complex-format): React to ?=.
+       (gnus-complex-form-to-spec): Insert tab.
+       (gnus-spec-tab): New function.
+
+       * gnus-sum.el (gnus-select-newsgroup): Set the marks before
+       entering the group.
+
+       * gnus-spec.el (gnus-complex-form-to-spec): Insert Lisp to match
+       the positional spec.
+       (gnus-parse-complex-format): React to %C.
+
+       * gnus-ems.el (gnus-char-width): Moved here.
+
+       * gnus-sum.el (gnus-select-newsgroup): Set
+       gnus-newsgroup-articles.
+       (gnus-unseen-mark): New variable.
+       (gnus-newsgroup-unseen): Ditto.
+       (gnus-newsgroup-seen): Ditto.
+       (gnus-adjust-marked-articles): Use them.
+       (gnus-update-marks): Use them.
+       (gnus-summary-update-secondary-mark): Display.
+       (gnus-summary-prepare-threads): Display.
+
+       * gnus-msg.el (gnus-inews-group-method): Use and return the
+       method, not the server.
+
+2001-08-19  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-srvr.el (gnus-server-agent-face): New.
+       (gnus-server-agent-face): New.
+       (gnus-server-mode): Turn on font-lock-mode.
+
+       * gnus.el (gnus-server-visual): Add defgroup.
+
+2001-08-19  Joe Casadonte  <jcasadonte@northbound-train.com>
+
+       * gnus-srvr.el (gnus-server-opened-face, gnus-server-closed-face,
+       gnus-server-denied-face): New.
+       (gnus-server-opened-face, gnus-server-closed-face,
+       gnus-server-denied-face): New.
+       (gnus-server-font-lock-keywords): Add.
+
+2001-08-19  Simon Josefsson  <jas@extundo.com>
+
+       * nnml.el (nnml-request-set-mark): Return nil.
+       (nnml-save-marks): Use nnml-possibly-create-directory.
+       (nnml-open-marks): Only work in temp buffer when inserting/reading
+       .marks file.
+
+2001-08-18 19:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el (gnus-expand-group-parameters): Fix.
+
+       * gnus-spec.el (gnus-char-width): New function.
+       (gnus-correct-substring, gnus-correct-length): Use it.
+
+       * message.el (message-required-mail-headers): Fix doc.
+
+2001-08-18 18:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-group-make-articles-read): gnus-request-set-mark.
+
+       * mm-decode.el (mm-save-part-to-file): Insert the handle.
+
+2001-08-18 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnslashdot.el (nnslashdot-threaded-retrieve-headers):
+       slashdot 2.2 (not fully fixed yet).
+       (nnslashdot-request-article): Ditto.
+
+2001-08-18  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-util.el (gnus-remassoc, gnus-update-alist-soft): Moved from
+       nnimap.
+
+       * nnimap.el (nnimap-remassoc, nnimap-update-alist-soft): Moved to
+       gnus-util.
+       (nnimap-request-update-info-internal): Use new functions.
+
+       * nnml.el (nnml-request-set-mark, nnml-request-update-info): Use
+       new functions.
+
+2001-08-18  Simon Josefsson  <jas@extundo.com>
+
+       Make nnml groups self-contained as far as marks are concerned.
+
+       * nnml.el (nnml-request-delete-group): Delete marks file.
+       (nnml-request-rename-group): Move marks file.
+       (nnml-marks-file-name, nnml-marks-is-evil, nnml-marks): New server
+       variables.
+       (nnml-request-set-mark, nnml-request-update-info): New server
+       functions.
+       (nnml-save-marks, nnml-open-marks): New functions.
+
+2001-08-18  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-sum.el (gnus-summary-move-article): Use `add' instead of
+       `set' when setting marks.
+
+2001-08-17 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el (gnus-info-find-node): Take an argument.
+
+       * gnus-art.el (gnus-button-handle-info): New function.
+       (gnus-url-unhex-string): Replace "+" with " ".
+
+2001-08-17 21:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-check-news-header-syntax): Check bad From.
+
+2001-08-18 00:14:45  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-spec.el (gnus-correct-length): New function.
+       (gnus-correct-substring): New function.
+       (gnus-tilde-max-form): Use it.
+
+2001-08-17  Nevin Kapur  <nevin@jhu.edu>
+
+       * nnmh.el: Docstring changes as below.
+
+       * nnml.el: Docstring changes as below.
+
+       * nnbabyl.el: Docstring changes as below.
+
+       * nnmbox.el: Docstring changes as below.
+
+       * nnfolder.el: Added docstrings identifying each virtual server
+       parameter.
+
+2001-08-18  Simon Josefsson  <jas@extundo.com>
+
+       * mml.el (mml-menu): Collapse Attach, Insert and Security submenu.
+
+2001-08-17  Björn Torkelsson  <torkel@acc.kth.se>
+
+       * message.el: Rename "Abort Message" to "Postpone Message".
+       Remove "Attach file as MIME" from Message menu, it's already in
+       the MIME menu.
+
+2001-08-17 14:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * smime.el (smime-point-at-eol): eval-and-compile.
+       (smime-make-temp-file): New function.
+       (smime-sign-region, smime-encrypt-region, smime-decrypt-region):
+       Use it.
+
+2001-08-17 10:41:14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-agent.el (gnus-agent-fetch-group): Go online if offline.
+       (gnus-agent-summary-fetch-group): New command and keystroke.
+
+       * gnus-art.el (gnus-insert-mime-button): Tiny clean-up.
+       (gnus-mime-display-security): Make it respect
+       gnus-unbuttonized-mime-type-p.
+
+       * gnus-sum.el (gnus-articles-to-read): Comments.
+       (gnus-article-marked-p): New function.
+       (gnus-summary-display-make-predicate): New function.
+       (gnus-select-newsgroup): Use them.
+
+       * mm-decode.el (mm-save-part-to-file): Made it not error.
+
+2001-08-17  Simon Josefsson  <jas@extundo.com>
+
+       * imap.el (imap-wait-for-tag): If process-status isn't open or
+       run, return nil instead of sit-for looping.
+
+2001-08-17 10:41:14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * lpath.el (featurep): fbind xml-parse-region.
+
+       * gnus.el (gnus-message-archive-method): Default to "archive".
+       (gnus-message-archive-method): Doc fix.
+       (gnus-parameters-get-parameter): Cleaned up.
+       (gnus-expand-group-parameter): New function.
+
+       * gnus-start.el (gnus-setup-news): Push the archive server only
+       the server list.
+
+       * mml.el (mml-menu): Changed name to "Attachments".
+
+       * mm-decode.el (mm-destroy-postponed-undisplay-list): Only message
+       when there is something to destroy.
+
+2001-05-21 17:11:46  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-srvr.el (gnus-server-browse-in-group-buffer): Default to
+       nil.
+
+2001-08-15  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-delay.el (gnus-delay-article): Allow "01:23" time spec,
+       which specifies a time today or tomorrow.
+
+2001-08-15  Pavel Janík  <Pavel@Janik.cz>
+
+       * gnus-agent.el (gnus-agent-make-mode-line-string)
+       (gnus-agent-toggle-plugged): Use new API.
+
+2001-08-14  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-delay.el (gnus-delay-send-drafts): Fix check whether
+       deadline has expired.
+
+2001-08-12  Simon Josefsson  <jas@extundo.com>
+
+       Suggested by Kai.Grossjohann@CS.Uni-Dortmund.DE.
+
+       Support `recent' mark indicating newly arrived messages (to
+       separate from old but unread messages).
+
+       * nnimap.el (nnimap-retrieve-groups): Push dummy article into
+       `nnmail-split-history' if recent is > 0.
+       (nnimap-request-update-info-internal): Update `recent' marks.
+       (nnimap-request-set-mark): Never set `recent' marks.
+       (nnimap-mark-to-predicate-alist, nnimap-mark-to-flag-alist): Add
+       recent.
+
+       * gnus-sum.el (gnus-recent-mark): New mark.
+       (gnus-newsgroup-recent): New variable.
+       (gnus-summary-local-variables): Add gnus-newsgroup-recent.
+       (gnus-summary-prepare-threads): Mark recent articles.
+       (gnus-summary-add-mark): Support recent.
+       (gnus-summary-update-secondary-mark): Support recent.
+
+       * gnus.el (gnus-article-mark-lists): Add recent.
+
+2001-08-12  Simon Josefsson  <jas@extundo.com>
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding): Returns
+       whether successful decoding took place.  Add doc.
+
+2001-08-12  Simon Josefsson  <jas@extundo.com>
+       Suggested by Per Abrahamsen <abraham@dina.kvl.dk>
+
+       * gnus.el (gnus-summary-line-format, gnus-parameters):
+       * gnus-gl.el (gnus-summary-grouplens-line-format):
+       * gnus-salt.el (gnus-summary-pick-line-format):
+       * gnus-spec.el (gnus-format-specs): %n is 23 chars.
+
+2001-08-11 09:40:00  Karl Kleinpaste  <karl@charcoal.com>
+
+       * gnus-score.el (gnus-score-string): Fix `match' regexp
+       for `extra' header case.
+
+2001-08-10 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnmbox.el (nnmbox-read-mbox): No warning.
+
+2001-08-10 21:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nndoc.el (nndoc-article-type): Fix doc.
+       (nndoc-generate-article-function): New variable.
+       (nndoc-dissection-function): New variable.
+       (nndoc-type-alist): Add oe-dbx.
+       (nndoc-oe-dbx-type-p): New function.
+       (nndoc-oe-dbx-dissection): New function.
+       (nndoc-oe-dbx-generate-article): New function.
+
+2001-08-11  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-delay.el (gnus-delay-send-drafts): Cleaner way to check
+       whether deadline has been reached.  Patch from Dan Nicolaescu
+       <dann@godzilla.ics.uci.edu>.
+
+2001-08-10 02:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-ml.el (turn-on-gnus-mailing-list-mode): Use
+       gnus-group-find-parameter.  Suggested by Janne Rinta-Manty
+       <rintaman@cs.Helsinki.FI>.
+
+       * mail-source.el (mail-source-movemail): The error buffer is
+       modified, but nothing in it.
+
+2001-08-10 01:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-bogus-system-names): New variable.
+       (message-make-fqdn): Use it.
+
+2001-08-09 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nndraft.el (nndraft-request-group): Use
+       nndraft-auto-save-file-name.
+
+2001-08-09  Simon Josefsson  <jas@extundo.com>
+
+       * mm-view.el (mm-view-pkcs7-decrypt): Operate in current buffer.
+       Don't ask whether to decrypt.  Just leave result in buffer (don't
+       call mm).
+
+       * mm-decode.el (mm-dissect-buffer): Possibly verify/decrypt single
+       parts as well.
+       (mm-inline-media-tests): Ignore application/{x-,}pkcs7-mime.
+       (mm-possibly-verify-or-decrypt): Support application/{x-,}pkcs7-mime.
+
+2001-08-09  Simon Josefsson  <jas@extundo.com>
+
+       * mm-decode.el (mm-insert-part): Return decoding success status.
+       (mm-save-part-to-file): Error if decoding failed.
+
+2001-08-09 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-tab): Use indent-relative.
+       (message-mode): Don't bind indent-line-function to indent-relative.
+
+2001-08-09  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-get-reply-headers): Fix string.  Suggested by
+       Christoph Conrad <cc@cli.de>.
+
+2001-08-08 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-tab): Use the current value of
+       indent-line-function.
+       (message-mode): Bind indent-line-function to indent-relative.
+
+2001-08-08  Simon Josefsson  <jas@extundo.com>
+
+       * imap.el (imap-gssapi-auth-p, imap-kerberos4-auth-p): Also check
+       whether `imtest' is installed.
+
+2001-08-04  Nuutti Kotivuori  <nuutti.kotivuori@smarttrust.com>
+
+       * 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  Gerd Möllmann  <gerd@gnu.org>
+
+       * mm-uu.el (mm-uu-dissect): Autoload.
+
+2001-08-07 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Misc -> Gnus.
+
+       * gnus-group.el (gnus-group-make-menu-bar): Ditto.
+
+       * gnus-art.el (gnus-output-to-file): Bind file-name-coding-system.
+
+       * gnus-util.el (gnus-output-to-rmail): Ditto.
+       (gnus-output-to-mail): Ditto.
+
+       * nnmail.el (nnmail-pathname-coding-system): Set default to nil.
+
+2001-08-06  Florian Weimer  <fw@deneb.enyo.de>
+
+       * message.el (message-indent-citation): Use
+       `message-yank-cited-prefix' for empty lines.
+
+2001-08-05  Florian Weimer  <fw@deneb.enyo.de>
+
+       * message.el (message-indent-citation): Quote only lines starting
+       with ">" using `message-yank-cited-prefix'.
+
+2001-08-05  Nuutti Kotivuori  <nuutti.kotivuori@smarttrust.com>  (tiny change)
+
+       * gnus-cache.el (gnus-cache-possibly-enter-article): Use
+       gnus-cache-fully-p.
+
+2001-08-04  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-cache.el (gnus-cache-possibly-update-active): Create active
+       file if it doesn't exist (by calling gnus-cache-read-active).
+
+2001-08-04  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-cache.el (gnus-cache-possibly-enter-article): Revert.
+       (gnus-cache-passively-or-fully-p): Removed.
+       (gnus-cache-fully-p): Fix it.
+
+       * mm-view.el (mm-pkcs7-signed-magic): Support more ASN.1 lengths.
+
+2001-08-04  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-cache.el (gnus-cache-fully-p)
+       (gnus-cache-passively-or-fully-p): New functions.
+       (gnus-cache-possibly-enter-article): Cosmetic change, use
+       `g-c-p-o-f-p'.
+       (gnus-cache-possibly-enter-article): Use `g-c-p-u-a'; last change
+       was bogus (`g-c-p-a-a' does not change active info, just change
+       the functions parameters).
+       (gnus-cache-possibly-remove-articles-1): Make sure articles are
+       not removed in groups that match `gnus-uncacheable-groups'.
+
+       Reported and modifications based on discussions with Nuutti
+       Kotivuori <nuutti.kotivuori@smarttrust.com>.
+
+2001-08-04  Simon Josefsson  <jas@extundo.com>
+       Trivial patch from Nuutti Kotivuori  <nuutti.kotivuori@smarttrust.com>
+
+       * gnus-cache.el (gnus-cache-possibly-update-active): New function;
+       calls `gnus-cache-update-active' if bounds has been extended.
+
+2001-08-04 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-security-verify-or-decrypt): Insert
+       before remove.
+       (gnus-mime-security-show-details): Ditto.
+
+2001-08-04  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * nnmail.el (nnmail-split-fancy-with-parent): Correct `mapconcat'
+       syntax.  Protect string-match against nil string and regexp.
+
+2001-08-03 19:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-find-charset-region): Remove control-1.
+
+2001-08-03 17:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-readable-p): Emacs 20 takes one argument.
+
+2001-08-04  Simon Josefsson  <jas@extundo.com>
+
+       * smime.el (smime-sign-region, smime-encrypt-region): Fix details
+       buffer.  Delete MIME-Version header.
+
+2001-08-03  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-cache.el (gnus-cache-possibly-enter-article): The article
+       that is entered does not necessarily have the highest article
+       number in the group, so use `gnus-cache-possibly-alter-active'
+       instead of `gnus-cache-update-active'.
+
+2001-08-03 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml2015.el (mml2015-gpg-extract-signature-details): Don't barf.
+
+2001-08-03  Simon Josefsson  <jas@extundo.com>
+
+       * mml.el (mml-menu): Rename from MML to Mime.  Collapse Security menu.
+
+2001-08-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (post-method): New group parameter.  It also provides
+       the user option `gnus-post-method-alist' and the internal function
+       `gnus-parameter-post-method'.
+
+       * gnus-msg.el (gnus-post-method): Bind the value of
+       `gnus-post-method' to the group parameter if it is defined.
+
+2001-08-02  Simon Josefsson  <jas@extundo.com>
+
+       * smime.el (smime-extra-arguments): Removed.
+       (smime-call-openssl-region): Don't use it.
+
+2001-08-02  Simon Josefsson  <jas@extundo.com>
+
+       * smime.el (smime-sign-region): Handle stderr.
+       (smime-encrypt-region): Ditto.
+
+       * mm-view.el (mm-pkcs7-signed-magic): Make it a regexp.  Don't
+       match the ASN.1 length bytes.
+       (mm-pkcs7-enveloped-magic): Ditto.
+       (mm-view-pkcs7-get-type): Don't regexp quote.
+
+2001-08-01 14:00:00  Andreas Fuchs  <asf@void.at>
+
+       * mml2015.el (mml2015-trust-boundaries-alist): Typo.
+
+2001-08-01 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-header-button-alist): References regexp.
+
+2001-08-01  Gerd Moellmann  <gerd@gnu.org>
+
+       * mm-view.el (autoload): Don't autoload `diff-mode' if it's
+       already fboundp.  Add INTERACTIVE arg to autoload form.
+
+2001-08-01 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnslashdot.el (nnslashdot-init): Add as gnus buffer.
+
+       * nnmail.el (nnmail-cache-open): Ditto.
+
+2001-07-31 21:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-button-fetch-group): Fix the regexp.
+
+2001-07-31  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-post-method): Refer to `gnus-parameters'.
+
+2001-07-31 17:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+       Originally from Pavel Janík <Pavel@Janik.cz>
+
+       * gnus-agent.el (gnus-agent-make-mode-line-string): New function.
+       (gnus-agent-toggle-plugged): Use it.
+
+2001-07-31  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-start.el (gnus-startup-file-coding-system): Revert to binary.
+       (gnus-ding-file-coding-system): New variable.
+       (gnus-read-newsrc-el-file, gnus-save-newsrc-file)
+       (gnus-slave-save-newsrc): Use it.
+
+2001-07-31  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-delay.el (gnus-delay-initialize): Use standard define-key
+       syntax.
+
+2001-07-30 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+       Originally from Andreas Fuchs <asf@void.at>
+
+       * mml2015.el (mml2015-trust-boundaries-alist): New variable.
+       (mml2015-gpg-pretty-print-fpr): New function.
+       (mml2015-gpg-extract-signature-details): More details, rename from
+       `m-g-e-from'.
+       (mml2015-gpg-verify): Use them.
+       (mml2015-gpg-clear-verify): Use them.
+
+2001-07-31  Simon Josefsson  <jas@extundo.com>
+
+       * mml-smime.el (mml-smime-sign, mml-smime-encrypt): Goto end of
+       buffer when done.
+
+2001-07-30  Simon Josefsson  <jas@extundo.com>
+
+       * smime.el (smime-call-openssl-region): Revert previous change,
+       just pass on buf to `call-process-region'.
+       (smime-verify-region): Doc fix.  Don't message stuff.  Use
+       `smime-new-details-buffer'.  Inserts error messages into buffer.
+       (smime-noverify-region): Ditto.
+       (smime-decrypt-region): Ditto.  Handles stderr separately.
+       (smime-verify-buffer, smime-noverify-buffer)
+       (smime-decrypt-buffer): Doc fix.
+       (smime-new-details-buffer): New function.
+       (smime-pkcs7-region, smime-pkcs7-certificates-region)
+       (smime-pkcs7-email-region): Use `smime-new-details-buffer'.
+       (smime-sign-region, smime-encrypt-region): Don't use
+       `insert-buffer'.
+
+       * mml-smime.el (mml-smime-verify): Fix security button strings.
+
+2001-07-30 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-save-part-and-strip): Save
+       gnus-article-mime-handles.
+
+2001-07-29  Simon Josefsson  <jas@extundo.com>
+
+       * mail-source.el (top-level): Require message for message-directory.
+       (mail-source-directory): Change default to message-directory.
+
+       * smime.el (smime-keys, smime-CA-directory, smime-CA-file)
+       (smime-certificate-directory, smime-openssl-program)
+       (smime-encrypt-cipher, smime-dns-server): Fix doc (leading "*").
+       (smime-extra-arguments): New variable.
+       (smime-dns-server): Fix customize group.
+       (smime-call-openssl-region): Use `smime-extra-arguments'.
+
+2001-07-29  Vladimir Volovich  <vvv@vsu.ru>
+
+       * smime.el (smime-call-openssl-region): Ignore stderr.
+
+2001-07-29  Christoph Conrad  <christoph.conrad@gmx.de>
+
+       * gnus-agent.el (gnus-agent-save-group-info): Don't destroy active
+       file.
+
+2001-07-29  Simon Josefsson  <jas@extundo.com>
+
+       * mm-view.el (mm-view-pkcs7-decrypt): Adhere to `mm-decrypt-option'.
+
+       Support S/MIME decryption.
+
+       * mm-decode.el (mm-inline-media-tests):
+       (mm-inlined-types):
+       (mm-automatic-display):
+       (mm-attachment-override-types): Add application/{x-,}pkcs7-mime.
+
+       * mm-view.el (mm-pkcs7-signed-magic):
+       (mm-pkcs7-enveloped-magic): New variables.
+       (mm-view-pkcs7-get-type): New function; identify PKCS#7 type.
+       (mm-view-pkcs7): New function; mm viewer for PKCS#7 blobs.
+       (mm-view-pkcs7-decrypt): New function; mm viewer for encrypted
+       PKCS#7 blobs.
+
+       * smime.el (smime-decrypt-region): Expand keyfile.
+
+2001-07-29  Simon Josefsson  <jas@extundo.com>
+
+       * nntp.el (nntp-open-ssl-stream): Don't mess with internal
+       `ssl.el' variables.
+
+       * gnus-agent.el (gnus-agent-save-group-info): Delete everything
+       but line instead of narrowing to it, because `nnmail-parse-active'
+       calls widen.  Thanks to Christoph Conrad
+       <christoph.conrad@gmx.de>.
+
+2001-07-29  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.el (gnus-summary-line-format): Mention `gnus-sum-thread-*'
+       for %B spec.
+
+       * gnus-sum.el (gnus-summary-prepare-threads): If
+       gnus-sum-thread-tree-root is nil, use subject instead.
+       (gnus-sum-thread-tree-root, gnus-sum-thread-tree-single-indent)
+       (gnus-sum-thread-tree-vertical, gnus-sum-thread-tree-indent)
+       (gnus-sum-thread-tree-leaf-with-other)
+       (gnus-sum-thread-tree-single-leaf): Documentation.
+       (gnus-sum-thread-tree-single-indent): Allow nil.
+
+2001-07-28 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-fill-paragraph): Do nothing if the user
+       wants filladapt-mode.
+
+2001-07-27 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-image-type-from-buffer): New function.
+       (mm-get-image): Use it.
+
+2001-07-27 18:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el (gnus-large-newsgroup): Add doc, "If it is nil, ...".
+
+       * gnus-art.el (gnus-mime-view-all-parts): buffer-read-only covers
+       mm-display-parts too.
+
+2001-07-27 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnfolder.el (nnfolder-request-accept-article): Bind
+       nntp-server-buffer.
+
+       * nnmail.el (nnmail-parse-active): Read from buffer instead of
+       nntp-server-buffer.
+
+2001-07-27 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-check-news-header-syntax): Use
+       message-post-method.
+       (message-send-news): Bind message-post-method.
+
+2001-07-27 07:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-tweak-type-alist): New variable.
+       (mml-tweak-function-alist): New variable.
+       (mml-tweak-part): New function.
+       (mml-generate-mime-1): Use it.
+
+2001-07-26 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnfolder.el (nnfolder-request-accept-article): Replace
+       nnfolder-request-list.
+
+2001-07-27  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap-open-server): Set nnimap-server-buffer if
+       nnoo-change-server failed to do it.
+
+2001-07-26 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el (gnus-parameters): Make it customizable.
+
+2001-07-26 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mm-display-part): Narrow to point if eobp.
+
+       * message.el (message-set-auto-save-file-name): More
+       poor-system-types.
+
+       * mailcap.el (mailcap-parse-mimetypes): poor-system-types.
+
+       * gnus-ems.el (nnheader-file-name-translation-alist): M$Windows-NT
+       supports +.
+
+2001-07-26 14:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-readable-p): New function.
+       (mm-inline-media-tests): Fix the default testers.
+
+2001-07-26  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap-version): Bump version number.
+
+2001-07-26 10:00:00  Steven E. Harris  <seh@speakeasy.org>
+
+       * nnheader.el (nnheader-translate-file-chars): cygwin32 is running
+       in M$Windows too.
+
+2001-07-26  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-delay.el (gnus-delay-send-drafts): Don't `error'.
+
+2001-07-25 21:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-bcklg.el (gnus-backlog-shutdown): Make interactive.
+
+       * mm-decode.el (mm-get-image): Guess then use the type.
+
+       * gnus-art.el (gnus-mime-view-part-as-type): Don't copy cache.
+
+2001-07-25 12:54:00  Danny Siu  <dsiu@adobe.com>
+
+       * gnus-sum.el (gnus-summary-prepare-threads): Shouldn't do tree
+       display (%B) for threads if threading is off.
+
+2001-07-25 14:00:00  Henrik Enberg  <henrik@enberg.org>
+
+       * gnus-msg.el: Customization patch.
+
+2001-07-25 22:22:22  Raymond Scholz  <rscholz@zonix.de>
+
+       * nnmail.el (nnmail-split-fancy-with-parent-ignore-groups): New
+       variable.
+       (nnmail-split-fancy-with-parent): Ignore certain groups.
+
+2001-07-25 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-util.el (gnus-byte-compile): New function.
+       (gnus-use-byte-compile): New variable.
+       (gnus-make-sort-function): Use it.
+
+       * nnmail.el (nnmail-get-new-mail): Use it.
+
+       * gnus-agent.el (gnus-category-make-function): Simple function or
+       compiled function.
+       (gnus-agent-fetch-group-1): Don't use (caaddr predicate).
+
+       * gnus-gl.el (bbb-build-rate-command): Remove quote before lambda.
+       * gnus-topic.el (gnus-topic-sort-topics-1): Ditto.
+       (gnus-topic-sort-topics-1): Use gnus-byte-compile.
+
+       * message.el (message-check-news-header-syntax): Remove quote.
+
+2001-07-24 19:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-use-mail-followup-to): `t' is not a
+       documented value.
+
+2001-07-24 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-display-arrow): Test fboundp.
+
+2001-07-24 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-encode.el (mm-encode-buffer): Don't use 7bit encoding if
+       there are long lines.
+
+2001-07-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (copy-list): New compiler macro.
+
+2001-07-24 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-bounce): If no Return-Path, the whole
+       content is considered as the original message.
+
+       * nnml.el (nnml-check-directory-twice): New variable.
+       (nnml-article-to-file): Use it.
+       (nnml-retrieve-headers): Hack it.
+
+2001-07-24 02:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-win.el (gnus-buffer-configuration): New configure.
+
+       * gnus-art.el (gnus-mm-display-part): Don't select-window if it is
+       not alive.
+
+       * mm-decode.el (mm-remove-part): Don't murder the current window (nil).
+       (mm-display-external): Use display-term configure.
+
+2001-07-24  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-delay.el (gnus-delay-default-hour): New variable.
+       (gnus-delay-article): Allow specific date in YYYY-MM-DD format.
+
+2001-07-23 22:00:00  Karl Kleinpaste  <karl@charcoal.com>
+
+       * gnus-sum.el (gnus-summary-line-format-alist): Add %B.
+       (gnus-summary-prepare-threads): Ditto.
+
+       * gnus.el (gnus-summary-line-format): Add %B.
+
+2001-07-23 19:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-articles-to-read): Use gnus-group-decoded-name.
+
+       * mm-util.el (mm-string-as-multibyte): New function.
+
+       * nnmh.el (nnmh-request-list-1): Encode, not decode!
+
+2001-07-23 18:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-universal-coding-system): New variable.
+
+       * gnus-start.el (gnus-startup-file-coding-system): Use it.
+
+       * score-mode.el (score-mode-coding-system): Use it.
+
+2001-07-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-start.el (gnus-setup-news): Call
+       `gnus-check-bogus-newsgroups' just after the native server is
+       opened.
+
+2001-07-23  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * nnmail.el (nnmail-do-request-post): Util function to be used by
+       `nnchoke-request-post' for all nnmail-derived backends.
+
+       * nnml.el (nnml-request-post): Use it.
+
+       * gnus.el (gnus-valid-select-methods): nnml is a post-mail
+       backend, for it groks nnml-request-post.
+
+       * gnus-group.el (gnus-group-highlight, gnus-group-highlight-line):
+       Treat `mail-post' backends like `mail' backends, not like `news'
+       backends.
+
+2001-07-22 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-setup-message): make-local-hook.
+
+2001-07-22  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-delay.el (gnus-delay-article): Fix `read-string' for
+       XEmacs.  Allow more units.  Submitted by Karl Kleinpaste
+       <karl@charcoal.com>, slightly changed by Kai.
+
+       * message.el (message-check-news-header-syntax): When checking
+       whether the groups exist, check the right server based on
+       `gnus-post-method'.
+
+2001-07-21  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-delay.el: New file.
+
+2001-07-21 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-read-coding-system): Take two arguments.
+
+       * gnus-sum.el (gnus-summary-show-article): Use
+       mm-read-coding-system.
+
+       * gnus-art.el (article-de-quoted-unreadable):
+       (article-de-base64-unreadable, article-wash-html):
+       (gnus-mime-inline-part, gnus-mime-view-part-as-charset): Ditto.
+
+2001-07-21  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * nnml.el (nnml-request-post): New function.  Can be used for
+       annotations in nnml groups.
+
+2001-07-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * nntp.el (nntp-request-newgroups): Use UTC date for NEWGROUPS
+       command.
+
+       * gnus-start.el (gnus-find-new-newsgroups): Use
+       `message-make-date' instead of `current-time-string'.
+       (gnus-ask-server-for-new-groups): Ditto.
+       (gnus-check-first-time-used): Ditto.
+
+2001-07-20 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-score.el (gnus-home-score-file): nnheader-translate-file-chars.
+
+2001-07-18  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * message.el (message-shorten-references): Change `maxcount' and
+       `cut' to obey USEFOR draft 5.
+
+2001-07-12  Colin Walters  <walters@cis.ohio-state.edu>
+
+       * gnus-sum.el (gnus-summary-display-arrow): New variable.
+       (gnus-summary-set-article-display-arrow): New function.
+       (gnus-summary-goto-subject): Use it.
+
+2001-07-18 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-import-article): Insert date if
+       doesn't exist.
+
+2001-07-18 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-content-type-parameters): New variable.
+       (mml-content-disposition-parameters): New variable.
+       (mml-insert-mime-headers): Use them.
+       (mml-parse-1): Accept charset.
+
+2001-07-17 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-select-group): Doc fix.
+
+       * gnus-eform.el (gnus-edit-form-done): Return nil if end-of-file.
+
+2001-07-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (dgnushack-make-auto-load): Advise `make-autoload'
+       to handle `define-derived-mode'.
+
+2001-07-16 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+       From Stefan Monnier <monnier@cs.yale.edu>.
+
+       * message.el (message-mode): Use define-derived-mode.
+       (message-tab): message-completion-alist.
+
+       * imap.el (imap-interactive-login): Use make-local-variable.
+       (imap-open): Ditto.
+       (imap-authenticate): Ditto.
+
+       * gnus-msg.el (gnus-setup-message): Change-major-mode-hook.
+
+       * gnus-art.el (gnus-article-edit-mode): Use define-derived-mode.
+
+2001-07-16  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * message.el (message-citation-line-function): Refer to
+       gnus-cite-attribution-suffix.
+
+2001-07-15  Pavel Janík  <Pavel@Janik.cz>
+
+       * gnus-art.el, ...: Error convention changes.
+
+2001-07-13 20:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-rebuild-thread): Count hidden lines too.
+
+2001-07-13 20:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnrss.el (nnrss-read-group-data): Nuke emacs-lisp-mode-hook.
+       (nnrss-read-server-data): Ditto.
+
+2001-07-13 12:00:00  Pavel Janík  <Pavel@Janik.cz>
+
+       * gnus-setup.el (gnus-use-installed-gnus): Typo.
+       * Cleanup files.
+
+2001-07-13 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el (gnus-summary-line-format): Add %o.
+
+       * gnus-sum.el (gnus-summary-pipe-output): Don't configure as pipe
+       unless shell outputs something.
+
+2001-07-13 07:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-boring-article-headers): Better doc.
+       (article-hide-headers): Better regexp.
+       Suggested by Matt Swift <swift@alum.mit.edu>.
+
+       * nnheader.el (nnheader-max-head-length): Better doc.
+       (nnheader-header-value): Skip spaces.
+       (nnheader-parse-head): Remove space.
+       Suggested by Matt Swift <swift@alum.mit.edu>.
+
+       * gnus-sum.el (gnus-summary-show-raw-article): New function.
+       (gnus-get-newsgroup-headers): Remove space.
+
+2001-07-12 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-msg-treat-broken-reply-to): Add force.
+       (gnus-summary-reply): Use it.
+       (gnus-summary-reply-broken-reply-to): New function.
+       (gnus-msg-force-broken-reply-to): New function.
+
+       * mm-view.el (mm-inline-text): Showing as text/plain when error.
+
+2001-07-12 21:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-draft.el (gnus-draft-setup): Restore gnus-newsgroup-name.
+
+2001-07-12 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-external-terminal-program): New variable.
+       (mm-display-external): Use it.  Use term to display when no
+       window-system.
+
+2001-07-12  Björn Torkelsson  <torkel@hpc2n.umu.se>
+
+       * gnus-srvr.el (gnus-browse-make-menu-bar): Changed one of the
+       Browse->Next entries to Browse->Prev.
+
+2001-07-11 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-inews-do-gcc): Don't test gnus-alive-p.
+
+2001-07-11 18:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-encode.el (mm-content-transfer-encoding-defaults): Use base64
+       for the default encoding.
+
+       * nnrss.el (nnrss-url-field): New field.
+       (nnrss-request-article): Add newsgroups.
+
+       * nnfolder.el (nnfolder-read-folder): Force to use a multibyte buffer.
+
+2001-07-11 04:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nndraft.el (nndraft-request-restore-buffer): Don't remove Date.
+
+       * gnus-draft.el (gnus-draft-edit-message): Remove Date here.
+       (gnus-draft-setup): Remove backlog.
+
+2001-07-10  Pavel Janík  <Pavel@Janik.cz>
+
+       * gnus-logic.el, gnus-srvr.el, gnus-vm.el, nnheaderxm.el, nnoo.el:
+       Cleanup.
+
+2001-07-09 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-bug): Erase buffer.
+
+       * nnfolder.el (nnfolder-possibly-change-group): Don't create group.
+
+2001-07-09 19:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-attachment-override-p): Fix typo.
+
+2001-03-19 05:28:00  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-kill.el (gnus-execute): Work with the extra headers.
+       * gnus-sum.el (gnus-summary-execute-command): Ditto.
+
+2001-07-09 17:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-view.el (mm-inline-text): w3-coding-system-for-mime-charset
+       may not defined.  From: Raja R Harinath <harinath@cs.umn.edu>.
+
+       * message.el (message-send-mail-real-function): New variable.
+       (message-send-mail-partially, message-send-mail): Use it.
+
+       * nngateway.el (nngateway-request-post): Use it.
+
+       * gnus-agent.el (gnus-agentize): Use it.
+
+       * nnsoup.el (nnsoup-old-functions, nnsoup-set-variables)
+       (nnsoup-revert-variables): Use it.
+
+2001-07-09  Colin Walters  <walters@cis.ohio-state.edu>
+
+       * mm-decode.el (mm-inline-media-tests): Default to displaying as
+       text/plain if the type doesn't match any other media types.
+       (mm-inlined-types): Doc fix.
+       (mm-display-inline): Revert previous change (now handled by a
+       default type in `mm-inline-media-tests'.
+       (mm-inlinable-p): Revive.
+       (mm-display-part): Call `mm-inlinable-p'.
+       (mm-attachment-override-p): Ditto.
+       (mm-inlined-p): Doc fix.
+
+       * gnus-art.el (gnus-mime-display-single): Call `mm-inlinable-p' as
+       well as `mm-inlined-p'.
+
+2001-07-09 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nntp.el (nntp-send-command, nntp-send-command-nodelete):
+       (nntp-send-command-and-decode): Use gnus-point-at-bol.
+
+2001-07-09 13:00:00  Paul Jarc  <prj@po.cwru.edu>
+
+       * message.el (message-use-mail-followup-to): New variable.
+       (message-get-reply-headers): Use it.
+
+2001-07-04  Gerd Moellmann  <gerd@gnu.org>
+
+       * nnheader.el (nnheader-init-server-buffer): Make sure the
+       *nntpd* buffer is made multibyte instead of a random buffer.
+
+2001-07-09 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-get-newsgroup-headers-xover): Get headers only
+       when it returns headers.
+
+2001-07-07  Simon Josefsson  <jas@extundo.com>
+
+       * rfc2047.el (rfc2047-encode-message-header): Skip header when
+       trying to fold.  Thanks to Colin Walters <walters@cis.ohio-state.edu>.
+
+2001-07-06  Simon Josefsson  <jas@extundo.com>
+
+       * imap.el (imap-parse-address-list, imap-parse-flag-list)
+       (imap-parse-body-extension, imap-parse-body-ext, imap-parse-body):
+       Add information in `assert's.
+
+       * nnimap.el (nnimap-possibly-change-group): Ignore uidvalidity
+       changes.  (From nnimaps' point of view, `nnimap-verify-uidvalidity'
+       and `nnimap-group-overview-filename', should handle all
+       change-of-uidvalidity related issues.  But there may be other
+       problems.)
+
+2001-07-05  Colin Walters  <walters@cis.ohio-state.edu>
+
+       * rfc2047.el (rfc2047-encode-message-header): Don't include the
+       header name when folding.
+
+2001-07-05  Colin Walters  <walters@cis.ohio-state.edu>
+
+       * mm-decode.el (mm-inlined-types): Document relationship with
+       `mm-inline-media-tests'.
+       (mm-display-inline): Default to displaying as plain text if no
+       inlining handler is available.
+       (mm-inlinable-p): Remove.
+       (mm-inlined-p): Don't call `mm-inlinable-p'.
+       (mm-automatic-display-p): Ditto.
+       (mm-attachment-override-p): Ditto.
+
+2001-07-04  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap-importantize-dormant): New variable.
+       (nnimap-request-update-info-internal): Use it.
+       (nnimap-request-set-mark): Ditto.
+
+2001-07-04  Didier Verna  <didier@lrde.epita.fr>
+
+       * nntp.el (nntp-send-command): Don't pass a buffer argument to
+       `point'.  Only XEmacs accepts this.
+       * nntp.el (nntp-send-command-nodelete): Ditto.
+       * nntp.el (nntp-send-command-and-decode): Ditto.
+
+2001-07-04  Didier Verna  <didier@lrde.epita.fr>
+
+       * nntp.el (nntp-open-connection-function): Doc update.
+       * nntp.el (nntp-pre-command): New.
+       * nntp.el (nntp-via-rlogin-command): New.
+       * nntp.el (nntp-via-telnet-command): New.
+       * nntp.el (nntp-via-telnet-switches): New.
+       * nntp.el (nntp-via-user-name): New.
+       * nntp.el (nntp-via-user-password): New.
+       * nntp.el (nntp-via-address): New.
+       * nntp.el (nntp-via-envuser): New.
+       * nntp.el (nntp-via-shell-prompt): New.
+       * nntp.el (nntp-open-telnet-stream): New.
+       * nntp.el (nntp-open-via-rlogin-and-telnet): New.
+       * nntp.el (nntp-open-via-telnet-and-telnet): New.
+       * nntp.el (nntp-wait-for): Check for possibly echo'ed commands.
+       * nntp.el (nntp-send-command): Ditto.
+       * nntp.el (nntp-send-command-nodelete): Ditto.
+       * nntp.el (nntp-send-command-and-decode): Ditto.
+
+2001-06-30  YAGI Tatsuya  <yagi@is.titech.ac.jp>  (tiny change)
+
+       * gnus-start.el (gnus-check-first-time-used): Use `if' instead of
+       `when'.
+
+2001-07-03  Nuutti Kotivuori  <nuutti.kotivuori@smarttrust.com>
+
+       * flow-fill.el (fill-flowed): Use (1+ (point-at-eol)) instead.
+
+2001-07-03  Simon Josefsson  <jas@extundo.com>
+
+       * flow-fill.el (fill-flowed): If `fill-region' inserts empty line,
+       remove it (workaround XEmacs `fill-region' bug).
+
+2001-07-01  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap-date-days-ago): Defeat locale.
+
+2001-06-28 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml2015.el (mml2015-format-error): New function.
+       (mml2015-mailcrypt-decrypt, mml2015-mailcrypt-clear-decrypt)
+       (mml2015-mailcrypt-verify, mml2015-gpg-clear-verify)
+       (mml2015-mailcrypt-clear-verify, mml2015-gpg-verify): Use it.
+
+2001-06-26 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnrss.el (nnrss-retrieve-headers): The description may not exist.
+       Suggested by Christoph Conrad <C.Conrad@cli.de>.
+
+       * gnus-sum.el (gnus-summary-set-local-parameters): Don't override
+       group variables.
+
+2001-06-25 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnslashdot.el (nnslashdot-write-groups): Use gnus-prin1.
+
+       * nnrss.el (nnrss-save-server-data): Bind print-level and print-length.
+       (nnrss-save-group-data): Ditto.
+
+       * gnus-agent.el (gnus-agent-save-alist): Ditto.
+
+2001-06-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-do-send-housekeeping): Narrow to headers.
+
+2001-06-24  Simon Josefsson  <jas@extundo.com>
+
+       * rfc2047.el (rfc2047-fold-region): The check to skip WSP
+       insertion when breaking lines looked for " \t" instead of "[ \t]".
+       (rfc2047-encode-message-header): Fold lines even if
+       no QP encoding is done.
+
+2001-06-23  Samuel Tardieu  <sam@inf.enst.fr>
+
+       * smime.el (smime-keys): Support additional certificates.
+       (smime-make-certfiles): New function.
+       (smime-sign-region): Use previous variables.
+       (smime-get-certfiles): New function.
+       (smime-sign-buffer): Use it.
+       (smime-verify-region): Support both CAfile and CApath.
+
+2001-06-23  Simon Josefsson  <jas@extundo.com>
+
+       * smime.el (smime-decrypt-region): Perhaps work.
+
+2001-06-22 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-copy-article-buffer): Typo.
+
+2001-04-06  Ralph Schleicher  <rs@nunatak.allgaeu.org>
+
+       * mm-decode.el (mm-save-part): Rewrite file name.
+       (mm-file-name-rewrite-functions): New variable.
+       (mm-file-name-delete-whitespace): New function.
+       (mm-file-name-trim-whitespace): New function.
+       (mm-file-name-collapse-whitespace): New function.
+       (mm-file-name-replace-whitespace): New variable and function.
+
+2001-06-22  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-make-date): Workaround locale for weekdays.
+
+2001-06-21 17:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-goto-body): Return nil if not found. (revert!)
+
+2001-06-21 10:00:00  John Fremlin  <chief@bandits.org>  (tiny change)
+
+       * message.el (message-goto-body): Some messages have no header.
+
+       * gnus-msg.el (gnus-copy-article-buffer): Use it.
+
+2001-06-21  Ralph Schleicher  <rs@nunatak.allgaeu.org>
+
+       * nnultimate.el (nnultimate-retrieve-headers): Date fix.
+
+2001-06-21 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-make-date): Add week day.
+       Suggested by Jason R. Mastaler <jason@mastaler.com>.
+
+2001-06-19  Simon Josefsson  <jas@extundo.com>
+
+       * message.el (message-yank-prefix): Doc fix.
+       (message-yank-cited-prefix): Ditto.
+       (message-delete-not-region): Keep citation prefix on first line,
+       if possible and appropriate.
+
+2001-06-19  Simon Josefsson  <jas@extundo.com>
+
+       * imap.el (imap-process-connection-type): New variable.
+       (imap-kerberos4-open, imap-gssapi-open): Use it.  This makes
+       recent `imtest's work completely (no line length issues), while
+       making making old `imtest's unusable.  Thanks to NAGY Andras
+       <nagya@inf.elte.hu> for his work.
+
+2000-12-30  NAGY Andras  <nagya@inf.elte.hu>
+
+       * imap.el (imap-ssl-program): Add -quiet to shut up
+       OpenSSL/SSLeay's internal debug talk.
+
+2001-06-19  Matt Armstrong  <matt@lickey.com>
+
+       * imap.el (imap-parse-flag-list): Workaround bug in Courier IMAP
+       server.
+
+2001-06-19 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnmail.el (nnmail-article-buffer): New variable.
+       (nnmail-split-incoming): Use it.
+
+2001-06-15  Eli Zaretskii  <eliz@is.elta.co.il>
+
+       * qp.el (quoted-printable-decode-region): If called interactively,
+       use coding-system-for-read.
+
+2001-06-16 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-check-news-header-syntax): Check Reply-To.
+
+2001-06-16 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-parse-1): Use message options.
+
+       * message.el (message-do-fcc): Don't do anything if there is no
+       FCC.
+
+2001-06-16  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (nnimap-split-articles): Support 'junk to-groups.
+       (nnimap-expunge-search-string): New variable.
+       (nnimap-request-expire-articles): Use it.
+
+2001-06-15 19:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-send-mail-with-qmail): Wrong exit status is
+       100 not 1.  Reported by Paul Jarc <prj@po.cwru.edu>.
+
+2001-06-15 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-strip-multiple-blank-lines): Use
+       delete-region instead of replace-match.
+
+2001-06-14 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnweb.el (nnweb-google-parse-1): Fix Google content regexp.
+       (nnweb-google-wash-article): Ditto.
+
+2001-06-14  Ferenc Wagner  <wferi@bolyai1.elte.hu>
+
+       * nnweb.el (nnweb-google-parse-1): Fix Google url regexp.
+
+2001-06-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (gnus-define-group-parameter): Don't quote the defcustom
+       specs.
+
+2001-06-13 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el (gnus-email-address): Move it here.
+
+       * gnus-art.el (article-de-quoted-unreadable): Read charset if
+       requested.
+       (article-de-base64-unreadable): Ditto.
+       (article-wash-html): Ditto.
+
+2001-06-12 14:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-options-set-recipient): Don't add ", "
+       unless necessary.  Suggested by Josh Huber <huber@alum.wpi.edu>.
+
+2001-06-12 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnrss.el (nnrss-group-alist): Use |fr| instead of [fr].
+
+2001-06-12 11:00:00  Marc Lefranc  <Marc.Lefranc@univ-lille1.fr>
+
+       * gnus-art.el (gnus-plain-save-name): Use file-relative-name.
+
+2001-06-12 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnrss.el (nnrss-node-text): Node might be nil.
+
+2001-06-11 10:00:00  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-uu.el (gnus-uu-save-article): Use mml tag instead of
+       part.
+
+2001-06-11 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnrss.el (nnrss-group-alist): More items.
+
+2001-06-09 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnrss.el (nnrss-node-text): Use cddr instead xml-node-children.
+
+2001-06-03  ShengHuo ZHU  <zsh@cs.rochester.edu>
+       Trivial patch from Dale Hagglund  <rdh@best.com>
+
+       * gnus-mlspl.el (gnus-group-split-fancy): Fix generation of split
+       restrict clauses.
+
+2001-06-07 16:00:00  Benjamin Rutt  <brutt+news@bloomington.in.us>
+
+       * message.el (message-wide-reply-confirm-recipients): New variable.
+
+2001-06-06  Mark Thomas  <mthomas@edrc.cmu.edu>  (tiny change)
+
+       * nnmail.el (nnmail-fix-eudora-headers): Change the In-Reply-To
+       fix so it works with XEmacs.
+
+2001-06-07 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnrss.el (nnrss-retrieve-headers): Support description as extra
+       headers.
+
+2001-06-07 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnrss.el: Fix a few bugs.
+
+2001-06-05  Alex Schroeder  <alex@gnu.org>
+
+       * mm-decode.el (mm-handle-set-external-undisplayer): Don't
+       generate compiler warnings.
+
+2001-06-04  Hrvoje Niksic  <hniksic@arsdigita.com>
+
+       * mm-decode.el (mm-pipe-part): Bind coding-system-for-write to
+       binary so that we don't transmit ISO 2022 garbage to the process.
+       This is needed under XEmacs.
+
+2001-06-03  Simon Josefsson  <simon@josefsson.org>
+
+       * imap.el (imap-ssl-open): Require ssl.  (Otherwise ssl.el is
+       autoloaded incorrectly below because ssl-program-* is bound.)
+       Thanks to Amos Gouaux for report.
+
+2001-06-02  Simon Josefsson  <simon@josefsson.org>
+
+       * imap.el (imap-kerberos4-open):
+       (imap-gssapi-open):
+       (imap-ssl-open):
+       (imap-network-open):
+       (imap-shell-open):
+       (imap-starttls-open): Set buffer to workaround spurious
+       `accept-process-output' buffer changes.  Thanks to Mats Lidell
+       <Mats.Lidell@contactor.se> for report and partial patch and Jake
+       Colman <colman@ppllc.com> for report.
+
+2001-05-31 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-catchup): New argument.
+       (gnus-summary-catchup-from-here): New function.
+
+2001-05-30  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * mm-view.el (mm-inline-image-xemacs): Insert newline, then move
+       back, then insert glyph.  (Before, the glyph was inserted first,
+       then the newline.)  This works around a behavior in XEmacs where
+       it is not possible to insert a character after a glyph which is at
+       the end of a buffer.  Patch by Lloyd Zusman <ljz@asfast.com>.
+
+2001-05-28  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  Raja R. Harinath  <harinath@cs.umn.edu>
+
+       * gnus-salt.el (gnus-tree-highlight-node): Bind `default-high' and
+       `default-low' when evaluating `gnus-summary-highlight'.
+
+2001-05-27  Simon Josefsson  <simon@josefsson.org>
+
+       * message.el (message-yank-cited-prefix): New variable.
+       (message-indent-citation): Use it.
+
+       * mml2015.el (mml2015-mailcrypt-verify): Store gpg stderr output
+       as details.
+       (mml2015-mailcrypt-clear-verify): Ditto.
+
+2001-05-24  Nevin Kapur  <nevin@jhu.edu>
+
+       * gnus-sum.el (gnus-summary-default-high-score,
+       gnus-summary-default-low-score): New variables.
+       (gnus-summary-highlight): Use them.
+
+2001-05-16  Didier Verna  <didier@lrde.epita.fr>
+
+       * message.el (message-mail): Pass the 'send-actions argument to
+       `message-setup'.
+
+2001-05-16  Raymond Scholz  <ray-2001@zonix.de>
+
+       * gnus-art.el (gnus-mime-view-part-as-charset):
+       (gnus-mime-internalize-part): Doc fixes.
+
+2001-05-11  Simon Josefsson  <simon@josefsson.org>
+
+       * gnus-start.el (gnus-ignored-newsgroups): Also ignore NNTP type
+       status lines without any text ("^215$").
+
+2001-05-06 21:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnrss.el (nnrss-check-group): Reverse.
+
+2001-05-07  Simon Josefsson  <simon@josefsson.org>
+
+       * message.el (message-get-reply-headers):
+       (message-followup): Fix typo, suggested by David Green
+       <dgreen@uab.edu>
+
+2001-05-05 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnslashdot.el (nnslashdot-request-expire-articles): Fix.
+
+       * nnrss.el (nnrss-open-server): Read server data when it is called.
+       (nnrss-request-expire-articles): Fix.
+
+2001-05-05 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-do-send-housekeeping): mail-abbrevs may
+       rename buffer behind Gnus.
+
+2001-05-04 14:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnrss.el (nnrss-check-group): Use nnheader-translate-file-chars.
+       (nnrss-group-alist): Add more resources.
+       (nnrss-check-group): Ignore errors.
+
+2001-05-04 00:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnrss.el (nnrss-request-expire-articles): Correct the return value.
+
+       * nnslashdot.el (nnslashdot-request-list): Add time.
+       (nnslashdot-request-expire-articles): New function.
+
+       * gnus-start.el (gnus-check-bogus-newsgroups): Remove bogus
+       secondary methods too.
+
+2001-05-03 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-use-followup-to): Set default value to t.
+
+2001-05-03  Florian Weimer  <fw@deneb.enyo.de>
+
+       * message.el (message-dont-reply-to-names): Fix documentation.
+       (message-get-reply-headers): Use Mail-Followup-To only for wide
+       replies.
+
+2001-05-03 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnrss.el (nnrss-request-expire-articles): Calculate # of days
+       correctly.
+       (nnrss-check-group): Use time.
+
+2001-05-01 19:21:19  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.03 is released.
+
+2001-05-01 19:06:21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnultimate.el (nnultimate-topic-article-to-article): Use the
+       group.
+
+2001-04-24 19:50:14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-srvr.el (gnus-server-insert-server-line): Add a space.
+
+2001-04-15 14:55:03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnultimate.el (nnultimate-retrieve-headers): Return all
+       available headers.
+
+       * gnus-sum.el (gnus-read-all-available-headers): New variable.
+       (gnus-get-newsgroup-headers-xover): Use it.
+
+2001-04-14 15:47:26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnultimate.el (nnultimate-retrieve-headers): Clean up.
+
+2001-04-30 17:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nntp.el (nntp-retrieve-groups): Use throw instead of error.
+
+2001-04-29 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnrss.el (nnrss-insert-w3): Use cache before I figure out how to
+       disable it.
+
+       * gnus.el (gnus-info-nodes): Remove a few The's.
+
+2001-04-29 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mail-source.el (mail-source-movemail): Call-process may return a
+       signal description string.
+
+       * gnus-start.el (gnus-read-newsrc-el-file):
+       gnus-newsrc-file-version may be nil.
+
+       * nnmail.el (nnmail-get-new-mail): Use the exact file only.
+       Suggested by Michael Sperber [Mr. Preprocessor]
+       <sperber@informatik.uni-tuebingen.de>.
+
+2001-04-25  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * mm-uu.el (mm-uu-configure-list): Fixed customize type.
+
+2001-04-24  Hrvoje Niksic  <hniksic@arsdigita.com>
+
+       * mm-view.el (mm-display-inline-fontify): Allow XEmacs to fully
+       fontify HANDLE.
+
+2001-04-18  Simon Josefsson  <simon@josefsson.org>
+
+       * smime.el (smime-ask-passphrase): Rework to return value.
+       (smime-sign-region): Rework to bind value and use it.
+       (smime-decrypt-region): Ditto.
+
+2001-04-18  Simon Josefsson  <simon@josefsson.org>
+       Trivial patch from Mathias Herberts  <Mathias.Herberts@iroise.net>
+
+       * smime.el (smime-ask-passphrase): New function.
+       (smime-sign-region): Use it.
+       (smime-encrypt-cipher): New variable.
+       (smime-decrypt-region): Ditto.
+
+2001-04-12  Jason Merrill  <jason_merrill@redhat.com>
+
+       * imap.el (imap-shell-open): Erase the buffer *after* copying it into
+       the log.
+
+2001-04-14 01:14:42  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.el: Oort Gnus v0.02 is released.
+
+2001-04-14 00:48:42  Lars Magne Ingebrigtsen  <larsi@quimby.gnus.org>
+
+       * gnus.el: Oort Gnus v0.01 is released.
+
+2001-04-13 22:01:46  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-highlight): Highlight read
+       undownloaded articles as read articles.
+
+       * gnus-agent.el (gnus-agent-get-undownloaded-list): Clean up.
+       (gnus-agent-get-undownloaded-list): Mark all undownloaded
+       articles, even read ones, as such.
+
+       * 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-thread): Include articles that have
+       matching subjects.
+       (gnus-offer-save-summaries): Clean up.
+
+2001-04-13  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * nnmail.el (nnmail-split-fancy-with-parent): Add docstring.
+
+2001-04-12 19:00:00  Jason Merrill  <jason_merrill@redhat.com>
+
+       * gnus-sum.el (gnus-summary-insert-new-articles): Reverse the articles.
+
+2001-04-10 08:01:15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-msg.el (gnus-post-news): Fill the Newsgroups header by the
+       newsgroup names when the original article is a news message.
+
+2001-04-12 19:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-cite-prefix-regexp): Use POSIX regexp if
+       supported.  Suggest by Jim Meyering <jim@meyering.net>.
+
+2001-04-02  Nevin Kapur  <nevin@jhu.edu>
+
+       * nnmail.el (nnmail-split-it): Added check for .* at the end of
+       regexp in nnmail-split-fancy.
+
+2001-04-10  Simon Josefsson  <simon@josefsson.org>
+
+       * message.el (message-options-set-recipient): Look at Cc and Bcc too.
+
+2001-04-10  Colin Marquardt  <colin@marquardt-home.de>
+
+       * message.el (message-send-mail): Improve the interaction with the
+       user.
+
+2001-04-10  Simon Josefsson  <simon@josefsson.org>
+
+       * imap.el (imap-message-copy): Work around buggy servers that
+       doesn't send TRYCREATE tags.
+
+2001-04-09 01:15:54  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-start.el (gnus-read-newsrc-el-file): Work with Semi-gnusae.
+
+2001-04-05 21:43:25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-update-summary-mark-positions): Use a valid
+       date.
+
+2001-04-04 16:13:17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-group.el (gnus-group-quit): Check that the dribble buffer
+       lives.
+
+2001-04-02 00:40:12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-parse-news-url): New function.
+       (gnus-button-handle-news): New function.
+       (gnus-button-alist): Point to new functions.
+
+       * 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.
+
+       * message.el (message-check-news-header-syntax): Question even
+       when Gnus doesn't know the group names.
+       (message-send-news): Clean up.
+
+       * gnus-start.el (gnus-dribble-read-file): Say whether Gnus was
+       exited on purpose without saving.
+
+       * gnus-group.el (gnus-group-quit): Mark the dribble file as `Q'.
+
+2001-04-01 00:37:14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-score.el (gnus-score-orphans): Clean up.
+
+       * gnus-win.el (gnus-remove-some-windows): Leave one Gnus window.
+
+       * gnus-sum.el (gnus-summary-exit): Kill the summary buffer a bit
+       later.
+
+       * gnus-start.el (gnus-close-all-servers): Find the right items to
+       close.
+
+       * qp.el (quoted-printable-decode-region): Just message
+       malformation; don't quit.
+
+2001-03-31 21:00:00  Gerd Moellmann  <gerd@gnu.org>
+
+       * gnus.el (gnus-interactive): A typo.
+
+2001-03-26  Juanma Barranquero  <lektu@uol.com.br>
+
+       * gnus-util.el (gnus-delete-alist): Declare it as an alias of
+       `assq-delete-all', if that function exists; otherwise use the old
+       definition.  Documentation changed to match the one in
+       `assq-delete-all'.
+
+2001-04-01 00:37:14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-start.el (gnus-close-all-servers): New function.
+
+       * gnus-srvr.el (gnus-server-close-all-servers): Clean up.
+       (gnus-server-remove-denials): Clean up.
+
+       * gnus-sum.el (gnus-summary-sort-by-original): New command and
+       keystroke.
+
+2001-03-31 02:56:55  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-send-news): Message where we are sending.
+       (message-send-mail): Ditto.
+
+       * gnus.el (gnus-server-string): New function.
+
+       * gnus-sum.el (gnus-summary-up-thread): Doc fix.
+
+       * mm-decode.el (mm-default-directory): Customized.
+       (mm-tmp-directory): Ditto.
+
+       * gnus-sum.el (gnus-summary-catchup-and-exit): Doc fix.
+       (gnus-get-newsgroup-headers): Return -1 for articles without Lines
+       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.
+       (gnus-summary-print-article): Unbalanced parentheses.
+
+       * gnus-msg.el (gnus-inews-do-gcc): Check group to allow it to find
+       out whether new stuff has arrived.
+
+2001-03-31 02:14:38  Alan Shutko  <ats@acm.org>
+
+       * gnus-sum.el: Let printing work on ttys on Emacs.
+
+2001-03-31 01:11:14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-post-news): Add an empty Newsgroups header
+       when forcing news.
+
+       * gnus-sum.el (gnus-summary-mark-article-as-replied): Make into a
+       command.
+
+2001-03-31 01:04:54  Francis Litterio  <franl@world.std.com>
+
+       * message.el (message-set-auto-save-file-name): Don't use
+       asterisks under nt.
+
+2001-03-31 00:03:42  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-inews-insert-draft-meta-information): Allow
+       lists of articles.
+
+       * gnus-uu.el (gnus-uu-digest-mail-forward): Mark as forwarded.
+
+       * 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-sum.el (gnus-summary-mark-article-as-replied): Take a list
+       of articles.
+       (gnus-summary-mark-article-as-forwarded): Ditto.
+
+       * gnus-msg.el (gnus-summary-resend-message): Mark article as
+       forwarded.
+       (gnus-summary-mail-forward): Clean up.
+
+       * gnus.el (gnus-article-mark-lists): Added forward.
+
+       * gnus-sum.el (gnus-forwarded-mark): New variable.
+       (gnus-summary-prepare-threads): Use it.
+       (gnus-summary-update-secondary-mark): Ditto.
+       (gnus-newsgroup-forwarded): New variable.
+
+2001-03-30 23:13:37  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-msg.el (gnus-summary-reply): Allow very wide replies.
+       (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-adaptive): Use it.
+
+       * gnus-start.el (gnus-get-unread-articles): Clean up.
+
+2001-03-21 20:00:43  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnultimate.el (nnultimate-retrieve-headers): Work for other
+       boards.
+
+2001-03-21  Didier Verna  <didier@lrde.epita.fr>
+
+       * gnus-start.el (gnus-subscribe-newsgroup-hooks): New.
+       * gnus-start.el (gnus-subscribe-newsgroup): Use it.
+
+2001-03-15 09:47:23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnultimate.el (nnultimate-retrieve-headers): Understand
+       long-form month names.
+
+2001-03-18 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-show-all-headers):
+       gnus-article-show-all-headers is broken.  Use
+       gnus-summary-toggle-header instead.
+
+       * mml2015.el (mml2015-gpg-extract-from): No error.
+
+2001-03-18 23:00:00  Bjørn Mork  <bmork@dod.no>
+
+       * mml2015.el (mml2015-gpg-extract-from): New function.
+       (mml2015-gpg-verify): Use it.
+       (mml2015-gpg-clear-verify): Use it.
+
+2001-03-17 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-setup-fill-variables): Use
+       fill-paragraph-function.
+       (message-fill-paragraph): Take an argument.
+       (message-newline-and-reformat): Take another argument.
+
+2001-03-16 20:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (rmail-output): It is in rmailout.el not rmail.el.
+
+2001-03-16 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-forward): local-variable-p takes an extra
+       argument in XEmacs.
+
+2001-03-16  Simon Josefsson  <simon@josefsson.org>
+
+       * nnimap.el (nnimap-dont-use-nov-p): Renamed from
+       `nnimap-use-nov-p' (it really tested the negative).
+       (nnimap-retrieve-headers): Use it.
+
+2001-03-11  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * message.el (message-generate-headers-first): Update doc.
+
+2001-03-10  Matthias Wiehl  <mwiehl@gmx.de>  (tiny change)
+
+       * gnus.el (gnus-summary-line-format): Typo.
+
+2001-03-11  Simon Josefsson  <simon@josefsson.org>
+
+       * mailcap.el (mailcap-mime-data): Add application/sieve.
+       (mailcap-mime-extensions): Add .siv, .xls.
+
+2001-03-14 20:00:00  Christoph Conrad  <christoph.conrad@gmx.de>
+
+       * gnus-score.el (gnus-summary-lower-thread): Typo.
+
+2001-03-14 19:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-forward-decoded-p): New variable.
+       (message-forward-subject-author-subject): Use it.
+       (message-make-forward-subject): Use it.
+       (message-forward): Use it.
+
+       * gnus-uu.el (gnus-uu-digest-mail-forward): Use it.
+
+       * mm-util.el, message.el, rfc2047.el, gnus-sum.el, gnus-score.el:
+       Sync with Emacs 21 (tag EMACS_PRETEST_21_0_100).
+
+;;Has been fixed -- zsh.
+;;2001-03-05  Dave Love  <fx@gnu.org>
+;;
+;;     * mm-util.el (mm-mime-mule-charset-alist): Fix utf-8 case.
+;;     Move it after definition of mm-coding-system-p.
+;;
+2001-03-01  Dave Love  <fx@gnu.org>
+
+       * mm-util.el (mm-inhibit-file-name-handlers): Add
+       image-file-handler.
+
+2001-02-11  Dave Love  <fx@gnu.org>
+
+       * message.el (message-signature-file): Fix doc, :type.
+
+2001-02-08  Dave Love  <fx@gnu.org>
+
+       * rfc2047.el (rfc2047-fold-region): Don't forward-char at EOB.
+       (message-posting-charset): Defvar when compiling again.
+       (rfc2047-encodable-p): Require message.
+
+       * gnus-sum.el (gnus-alter-articles-to-read-function):
+       * gnus-score.el (gnus-score-after-write-file-function): Fix :type.
+
+2001-03-08 20:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnrss.el: New file.
+
+2001-03-08 02:41:36  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * rfc2047.el (rfc2047-unfold-region): Fix arg of
+       `skip-chars-forward'.
+
+2001-03-07 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nndraft.el (nndraft-request-group): Restore auto save files if
+       the original files do not exist.
+
+2001-03-07 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-score.el (gnus-score-find-bnews): Print messages on illegal
+       SCORE paths.
+
+       * mm-decode.el (mm-dissect-buffer): Call
+       mail-extract-address-components only if necessary.
+
+2001-03-06 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-score.el (gnus-score-find-bnews): Maybe there is no
+       directory part.
+       (gnus-score-search-global-directories): Use file-directory-p.
+
+2001-03-06 13:00:00  Adrian Aichner  <adrian@xemacs.org>
+
+       * gnus-score.el (gnus-score-score-files-1): Use
+       gnus-kill-files-directory.
+
+2001-03-05 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el (charset): Move here from gnus-sum.el.
+
+2001-03-04 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-preview): Disable local map.
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Make
+       gnus-article-post-menu here.
+
+       * gnus-art.el (gnus-article-make-menu-bar): Make summary-menu bar
+       if it has not been made.
+
+2001-03-02 02:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-describe-key): Map key to event.
+       (gnus-article-describe-key-briefly): Ditto.
+
+2001-03-01 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-limit-include-expunged): Fix.
+
+2001-03-01 22:00:00  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * dgnushack.el (coerce, merge, subseq): defmacro.
+
+2001-03-01 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * lpath.el (nndraft-request-group): Move it here from nndraft.el.
+       A fake defalias in nndraft.el results a not-activated bug in
+       uncompiled versions.
+
+2001-02-26 11:27:27  Paul Jarc  <prj@po.cwru.edu>
+
+       * gnus-util.el (gnus-split-references): Handle malformed References:.
+
+2001-02-26 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-mime-part-status): 1 part.
+
+2001-02-25 10:00:00  NAGY Andras  <nagya@inf.elte.hu>
+
+       * gnus.el (gnus-parameters): Typo.
+
+2001-02-24 00:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el (gnus-read-method): Remove redundancy.
+
+2001-02-23 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnslashdot.el (nnslashdot-backslash-url): New variable.
+       (nnslashdot-request-list): Use it.
+
+2001-02-23 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnml.el (nnml-generate-active-info): Fix the case when there is
+       no file.
+
+       * gnus-sum.el (gnus-summary-import-article): Display it.  Enable edit.
+       (gnus-summary-create-article): New function.
+
+       * gnus-group.el (gnus-group-mark-article-read): New function.
+
+       * gnus-msg.el (gnus-inews-do-gcc): Use it.
+
+       * gnus-art.el (gnus-article-edit-article): Set modified-p nil.
+
+2001-02-23 17:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-edit-done): Don't use
+       gnus-article-edit-exit.
+       (gnus-article-edit-exit): Confirm and insert original-article-buffer.
+
+       * gnus.el (gnus-parameters): New variable.
+       Suggested by NAGY Andras <nagya@inf.elte.hu>.
+       (gnus-parameters-get-parameter): New function.
+       (gnus-group-find-parameter): Use it.
+
+2001-02-23  Simon Josefsson  <simon@josefsson.org>
+
+       * gnus-msg.el (gnus-post-method): Fix documentation to reflect
+       change of default value to `current'.
+
+2001-02-23 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nneething.el (nneething-get-head): Insert unreadable file too.
+
+2001-02-22 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-insert-articles): Remove fetched headers.
+
+       * webmail.el (webmail-type-definition): Deja is bought by google.
+
+2001-02-22 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-fetch-headers): New function.
+       (gnus-select-newsgroup): Use it.
+       (gnus-summary-insert-articles): New function.
+       (gnus-summary-insert-old-articles): New function.
+       (gnus-summary-insert-new-articles): New function.
+
+       * gnus-group.el (gnus-group-prepare-flat-list-dead): Use decoded-name.
+       (gnus-group-list-active): Ditto.
+       * gnus-sum.el (gnus-set-mode-line): Ditto.
+       (gnus-summary-read-group-1): Ditto.
+
+2001-02-21 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-topic.el (gnus-topic-get-new-news-this-topic): Redraw the
+       current topic.
+
+2001-02-21 01:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * smiley.el (gnus-smiley-display): Don't do widening.
+
+       * smiley-ems.el (gnus-smiley-display): Don't do widening.  Smiley
+       within body.
+
+       * gnus-msg.el (gnus-inews-do-gcc): Activate group anyway.
+
+       * gnus-art.el (gnus-mime-display-multipart-alternative-as-mixed):
+       New variable.
+       (gnus-mime-display-multipart-related-as-mixed): New variable.
+       (gnus-mime-display-part): Use them.
+
+2001-02-20 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-start.el (gnus-setup-news): Allow gnus-group-line-format to be
+       something special.
+
+2001-02-20 00:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnweb.el (nnweb-request-group): Set nnweb-group anyway.
+       (nnweb-request-article): Call reference if exists.
+       (nnweb-type-definition): Dejanews is bought by google.com.
+       Beta!
+
+2001-02-19 19:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-draft.el (gnus-draft-reminder): "Confirm to exit?".
+
+2001-02-19  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-sum.el (gnus-thread-sort-functions): Doc fix.  Refer to
+       gnus-article-sort-functions.
+       (gnus-article-sort-functions): Doc fix.  Refer to
+       gnus-thread-sort-functions.
+
+2001-02-18 20:00:00  Paul Jarc  <prj@po.cwru.edu>
+
+       * message.el (message-get-reply-headers): More fixes.
+
+2001-02-17  Paul Jarc  <prj@po.cwru.edu>
+
+       * message.el (message-get-reply-headers): Fix bug with
+       Mail-Followup-To/to-address interaction.
+
+2001-02-17 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-configure-posting-styles): Match header in
+       gnus-article-copy.
+
+2001-02-16 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-do-send-housekeeping): Rename to a better
+       name.
+
+2001-02-16 18:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-cancel-news): Check article first, then ask
+       yes or no.
+
+2001-02-16 14:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-uu.el (mm-uu-type-alist): Add emacs-sources.
+
+2001-02-16 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-range.el (gnus-range-normalize): New function.
+
+2001-02-15  NAGY Andras  <nagya@inf.elte.hu>
+
+       * imap.el (imap-gssapi-open): Set imap-c-l-s-first.
+
+2001-02-14 21:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-srvr.el (gnus-server-regenerate-server): Use gnus-get-function.
+
+       * nnagent.el (nnagent-request-regenerate): New function.
+
+       * nnfolder.el (nnfolder-request-regenerate): New deffoo.
+
+       * nnml.el (nnml-generate-nov-databases): Accept argument
+       server.  Don't open server if it is opened.
+       (nnml-request-regenerate): Use it.  Change to deffoo.
+
+2001-02-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (gnus-define-group-parameter): Fix.
+
+2001-02-14 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el (gnus-define-group-parameter): Improved.
+
+       * gnus-sum.el (charset): Define parameter.
+       (ignored-charsets): Ditto.
+       (gnus-summary-setup-default-charset): Use them.
+
+       * gnus-start.el (gnus-read-descriptions-file): Use them.
+
+       * gnus-cus.el (gnus-group-parameters): Remove them.
+
+2001-02-14 00:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-print-article): Redo highlight.
+
+2001-02-13 21:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-read-group-1): Remove
+       gnus-summary-set-local-parameters.
+       (gnus-summary-setup-buffer): Put it here.
+
+2001-02-13 20:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el (to-address): Define parameter.
+       (to-list): Ditto.
+       * gnus-art.el (article-hide-boring-headers): Use them.
+       * gnus-msg.el (gnus-post-news): Ditto.
+       * gnus-cus.el (gnus-group-parameters): Remove them.
+
+2001-02-13 19:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-draft.el (gnus-draft-reminder): New function.
+
+       * gnus-art.el (gnus-sender-save-name): New function.
+
+2001-02-13 18:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-mime-charset): Error message.
+
+2001-02-13 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-check-news-body-syntax): Don't check mml lines.
+
+2001-02-12 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-topic.el (gnus-subscribe-topics): Return nil if not
+       subscribe.
+
+       * gnus-start.el (gnus-call-subscribe-functions): New function.
+       (gnus-find-new-newsgroups): Use it.
+       (gnus-ask-server-for-new-groups): Use it.
+       (gnus-check-first-time-used): Use it.
+       (gnus-subscribe-newsgroup-method): Grok a list of functions.
+       (gnus-subscribe-options-newsgroup-method): Ditto.
+       (gnus-subscribe-hierarchically): Return gnus-subscribe-newsgroup's
+       return .
+
+2001-02-12  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-cus.el (gnus-score-customize): Doc fix.
+
+2001-02-11  Jesper Harder  <harder@ifa.au.dk>
+
+       * dgnushack.el (my-getenv): Typo.
+
+2001-02-11 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * dgnushack.el (dgnushack-make-load): Don't autoload smiley functions.
+
+2001-02-11 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-suspend): Offer save summaries.
+
+       * gnus-art.el (gnus-treat-leading-whitespace): New variable.
+       (gnus-treatment-function-alist): Use it.
+       (article-remove-leading-whitespace): New function.
+       (gnus-article-make-menu-bar): Use it.
+
+       * gnus-sum.el (gnus-summary-wash-empty-map): Add
+       remove-leading-whitespace.
+       (gnus-summary-wash-map): Bind strip-headers-in-body to `W a',
+       because of conflict.
+
+2001-02-09 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * Makefile.in: Hack generating gnus-load.el.
+       * dgnushack.el: Ditto.
+       * gnus-load.el: Remove it.
+
+2001-02-09 20:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * dgnushack.el : Add URLDIR.
+
+       * Makefile.in (EMACS_COMP): Ditto.
+
+2001-02-09 19:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-cus.el (gnus-score-customize): Error on no score file.
+
+2001-02-09 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-merge-handles): New function.
+
+       * mm-view.el (mm-inline-message): Use it.
+       (mm-view-message): Ditto.
+
+       * mm-partial.el (mm-inline-partial): Ditto.
+
+       * mm-extern.el (mm-inline-external-body): Ditto.
+
+       * gnus-art.el (gnus-mime-view-part): Ditto.
+       (gnus-mime-view-part-as-type): Ditto.
+       (gnus-mime-save-part-and-strip): Prevent users to strip in some
+       cases.
+
+2001-02-08 20:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-cancel-news): Allow to shoot foot.
+       (message-supersede): Ditto.
+
+2001-02-08  Tommi Vainikainen  <thv@iki.fi>  (tiny change)
+
+       * gnus-sum.el (gnus-simplify-subject-re): Use
+       message-subject-re-regexp.
+
+2001-02-08 18:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnmail.el (nnmail-expiry-target-group): Bind
+       nnmail-cache-accepted-message-ids to nil.
+
+       * gnus-xmas.el (gnus-xmas-article-display-xface): Use binary
+       coding system.
+
+2001-02-07 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * qp.el (quoted-printable-encode-region): Make sure characters are
+       between 00 and FF.  Don't check charset.
+
+       * mm-encode.el (mm-encode-content-transfer-encoding): Use unibyte
+       in Emacs 20.
+       * rfc2047.el (rfc2047-q-encode-region): Ditto.
+
+2001-02-07 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-make-forward-subject): Argument decoded.
+       (message-forward): Use it when digest.
+
+       * gnus-uu.el (gnus-uu-grab-articles): Shoot down original article
+       buffer.
+
+2001-02-07  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * message.el (message-generate-headers-first): Doc fix.
+
+2001-02-07 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-make-date-line): Error proof.
+
+2001-02-06 21:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-listing-limit): New variable.
+       (gnus-group-prepare-flat-list-dead): Use old trick to speed up.
+
+       * gnus-topic.el (gnus-group-prepare-topics): Use gnus-killed-hashtb.
+
+2001-02-06 18:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-newline-and-reformat): Special case for
+       breaking at BOL.
+
+2001-02-06  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus-uu.el (gnus-uu-save-article): Make the topics summary a
+       message/rfc822.
+
+2001-02-06 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-encode-message-body): Don't insert
+       Content-Type if it is inside a mail.
+
+2001-02-06 02:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-xmas.el (gnus-xmas-article-menu-add): Add
+       gnus-article-commands-menu.
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Don't share menu bar
+       in Emacs.
+
+       * gnus-start.el (gnus-read-descriptions-file): Use
+       gnus-group-name-charset and gnus-group-charset-alist.
+
+2001-02-04 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-mark-as-processable): Understand
+       active region.
+
+       * gnus-start.el (gnus-group-change-level): Remove from both
+       gnus-zombie-list and gnus-killed-list.
+
+2001-02-04 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-start.el (gnus-subscribe-options-newsgroup-method): Add
+       gnus-subscribe-topics.
+
+       * gnus-cus.el (gnus-extra-topic-parameters): Fix doc.
+
+2001-02-04 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-make-menu-bar): Make
+       gnus-article-post-menu.
+
+       * gnus-xmas.el (gnus-xmas-article-menu-add): Add post menu.
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Use t if XEmacs.
+
+       * gnus-group.el (gnus-group-make-menu-bar): Ditto.
+
+       * message.el (message-mode-menu): Ditto.
+
+       * gnus-art.el (defvar): eval-when-compile.
+
+2001-02-02 17:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agentize): Fix doc.
+
+2001-02-02  Karl Kleinpaste  <karl@charcoal.com>
+
+       * mml.el (mml-preview): Bind `q'.
+
+2001-02-02 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-mime-mule-charset-alist): Non-Mule case.
+
+2001-01-31  Dave Love  <fx@gnu.org>
+
+       * mm-util.el (mm-mime-mule-charset-alist)
+       (mm-find-mime-charset-region): Consider mule-utf-8.
+
+2001-01-31  Dave Love  <fx@gnu.org>
+
+       * gnus-art.el (gnus-article-x-face-command)
+       (gnus-treat-display-xface, gnus-treat-display-smileys): Add
+       :version.
+
+2001-01-26  Dave Love  <fx@gnu.org>
+
+       * mm-util.el (mm-multibyte-string-p): New.
+
+;;     * qp.el: Remove un-logged bogus changes from 2000-12-20.
+;;     (quoted-printable-encode-region): Doc fix.  Don't call
+;;     string-as-multibyte on class.  Clarify line-folding.
+       (quoted-printable-encode-string): Make temp buffer inherit
+       string's multibyteness.
+
+2001-01-23  Gerd Moellmann  <gerd@gnu.org>
+
+       * nnheader.el (toplevel): Don't require `gnus-util' at
+       compile-time; this creates a circular dependency, and prevents
+       a bootstrap.
+
+2001-01-22  Andreas Schwab  <schwab@suse.de>
+
+       * nnheader.el (gnus-delete-line): Autoload it as a macro.
+
+2001-01-31 18:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnmail.el (nnmail-remove-list-identifiers): Use consp.
+
+       * gnus-art.el (article-hide-list-identifiers): Ditto.
+
+       * gnus-sum.el (gnus-summary-remove-list-identifiers): Ditto.
+
+2001-01-31 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-remove-list-identifiers): Similar.
+
+       * gnus-art.el (article-hide-list-identifiers): Similar.
+
+2001-01-31  Karl Kleinpaste  <karl@charcoal.com>
+
+       * nnmail.el (nnmail-remove-list-identifiers): Improved.
+
+2001-01-31 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-score.el (gnus-summary-score-entry): Match may be an integer.
+
+2001-01-30 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-util.el (gnus-string-equal): New function.
+
+       * gnus-art.el (article-hide-boring-headers): Use it.
+
+2001-01-27  Karl Kleinpaste  <karl@charcoal.com>
+
+       * gnus-art.el (gnus-article-banner-alist): eGroups new banner.
+
+2001-01-27 00:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-msg-mail): Support switch-action.
+
+2001-01-26 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-summary-save-in-pipe): Prompt for saving
+       command if there is not last-saver.
+
+2001-01-24 19:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nntp.el (nntp-open-connection): 201 is possible.
+
+2001-01-24 18:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-encode): MIME charset is not coding system.
+       (rfc2047-charset-encoding-alist): Add big5.
+
+2001-01-24 17:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-add-server): Redraw the line.
+       (gnus-agent-remove-server): Ditto.
+       (autoload): gnus-server-update-server.
+
+       * gnus-srvr.el (gnus-server-line-format): Add %a.
+       (gnus-server-line-format-alist): Add gnus-tmp-agent.
+       (gnus-server-insert-server-line): Use it.
+
+2001-01-24 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-mime-mule-charset-alist): Preferred MIME names
+       GB2312 and Big5.
+
+2001-01-24  Simon Josefsson  <sj@extundo.com>
+
+       * mail-source.el (mail-sources): Add :program specifier to IMAP
+       mail source.
+       (mail-source-fetch-imap): Map :program to `imap-shell-program'.
+
+2001-01-24 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-score.el (gnus-score-lower-thread): Fix a doc typo.
+
+2001-01-24 12:22:47  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nntp.el (nntp-wait-for): Return the success code.
+       (nntp-open-connection): Use it.
+
+2001-01-11 11:49:02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-int.el (gnus-check-server): Allow breaking the opening.
+
+2001-01-23 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-print-article): Remove process mark.
+
+2001-01-22 17:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-print-article): Take one prefix
+       argument.  Allow to print several articles in one file.
+
+2001-01-21 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * webmail.el (webmail-type-definition): netaddress changes.
+
+2001-01-21 00:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el: Fix copyright.  Remove trailing spaces.
+
+       * message.el (message-forward): Use mule4.
+
+2001-01-20 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-string-as-unibyte): New function.
+
+       * message.el (message-forward): Use it.
+
+2001-01-19 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-cite-original-without-signature): Don't peel
+       off the blank line.
+       (message-get-reply-headers): Add Cc if it is not in follow-to.
+
+2001-01-20  Simon Josefsson  <sj@extundo.com>
+
+       * mm-decode.el (mm-handle-multipart-from): Add.
+       (mm-dissect-buffer): Save From: header value.
+       (mm-security-from): Remove.
+       (mm-possibly-verify-or-decrypt): Don't set mm-security-from.
+
+       * mml-smime.el (mml-smime-verify): Use `mm-handle-multipart-from'
+       instead of `mml-security-from'.  Protect null from value.
+
+2001-01-20  Simon Josefsson  <sj@extundo.com>
+
+       * mailcap.el (mailcap-mime-data): Run `gnumeric' on
+       application/vnd.ms-excel attachments.
+
+2001-01-19  Simon Josefsson  <sj@extundo.com>
+
+       * gnus-art.el (gnus-button-alist): Add `?=' to mailto URL regexp.
+
+2001-01-19 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-ignored-mail-headers): Ditto.
+
+2001-01-19  Simon Josefsson  <sj@extundo.com>
+
+       * message.el (message-ignored-news-headers): Only search beginning
+       of line.
+
+2001-01-19  ShengHuo Zhu  <zsh@cs.rochester.edu>
+       Trivial patch from Alberto Lusiani  <a.lusiani@noemail.org>
+
+       * message.el (message-send-mail): Content-Type may not be there.
+
+2001-01-18 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-ems.el (gnus-article-display-xface): Add BUFFER.
+       * gnus-xmas.el (gnus-xmas-article-display-xface): Ditto.
+
+       * gnus-art.el (article-display-x-face): Insert X-Face if there is
+       not.
+
+2001-01-18 19:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-read-group-1): Don't test dead
+       non-native groups.
+
+2001-01-18 18:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-yank-original): Understand
+       universal-argument.
+
+2001-01-18 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-boring-article-headers): Add to-address.
+       (article-hide-boring-headers): Ditto.
+
+       * mm-view.el (mm-inline-message): Insert a newline unless bolp.
+
+2001-01-18 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-fold-region): Don't insert LWSP if there is
+       one.
+
+2001-01-16  Simon Josefsson  <simon@josefsson.org>
+
+       * message.el (message-make-in-reply-to): Add comment to message-id
+       (old syntax, see 2000-08-02 change).
+
+2001-01-16 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-url-mailto): Use gnus-msg-mail.
+       (gnus-button-mailto): Setup message.  Moved to gnus-msg.el.
+       (gnus-button-reply): Ditto.
+
+2001-01-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-display-x-face): Fix.
+
+2001-01-15 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-display-x-face): Use
+       gnus-original-article-buffer.
+
+2001-01-15  Jack Twilley  <jmt@tbe.net>
+
+       * message.el (message-add-header): Move to point-max.
+
+2001-01-15  Simon Josefsson  <simon@josefsson.org>
+
+       * smime.el (smime-CA-directory, smime-CA-file): Change default to
+       nil, improve documentation.
+       (smime-certificate-directory): Comment out false hints (until it
+       is implemented).
+
+       * mml-smime.el (mml-smime-sign): Place user in customize buffer if
+       there aren't any keys.
+       (mml-smime-verify): If smime-CA-{file,directory} set, also try to
+       verify certificate.  Default is changed to only check integrity.
+       Improved security status texts.  If a certificate doesn't contain
+       a email address, don't fail.
+
+       * smime.el (smime-noverify-region):
+       (smime-noverify-buffer): New functions.  Verifies integrity only.
+
+2001-01-12 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-sort-by-score): Reverse order.
+
+2001-01-12 17:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-win.el (gnus-configure-windows): switch-to-buffer in XEmacs.
+       (gnus-remove-some-windows): Ditto.
+
+2001-01-12 14:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-make-date-line): 11th.
+
+2001-01-11 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml2015.el (mml2015-gpg-encrypt): Remove CR.
+       (mml2015-gpg-sign): Ditto.
+
+2001-01-10 14:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el: Sync with EMACS_PRETEST_21_0_95.
+       * gnus.el (gnus-default-posting-charset): Bogus.  Removed.
+
+2001-01-08  Dave Love  <fx@gnu.org>
+
+       * mm-encode.el (mm-qp-or-base64): Don't base64 for the sake of a
+       single character.
+
+       * mm-util.el (mm-mime-mule-charset-alist): Add Latin-{8,9}.
+
+       * message.el: Doc and message fixes.
+       (message-send-rename-function)
+       (message-make-forward-subject-function)
+       (message-send-mail-function, message-reply-to-function)
+       (message-wide-reply-to-function, message-followup-to-function)
+       (message-distribution-function, message-auto-save-directory): Fix
+       :type.
+
+       * mml.el (mml-parse-1): Frob mml-confirmation-set when
+       proceeding after warnings.  Amend multipart warning message.
+
+2001-01-04  Dave Love  <fx@gnu.org>
+
+       * gnus-util.el (nnmail-pathname-coding-system): Defvar when
+       compiling.
+       (gnus-make-directory): Require nnmail.
+
+       * mm-decode.el (mm-inline-media-tests): Add
+       image/x-portable-bitmap.
+       (mm-get-image): Grok pbm.
+
+2001-01-10  Paul Stevenson  <p.stevenson@surrey.ac.uk>
+
+       * nnvirtual.el (nnvirtual-request-expire-articles): delq nil.
+
+2001-01-09  Didier Verna  <didier@xemacs.org>
+
+       * dgnushack.el (dgnushack-compile): Give a dummy value to
+       `gnus-xmas-glyph-directory' for the time of compilation.
+       * gnus-agent.el: Moved some XEmacs specific hook add-ons from
+       `gnus-xmas-[re]define' to avoid loosing user custom settings.
+       * gnus-art.el: Ditto.
+       * gnus-group.el: Ditto.
+       * gnus-salt.el: Ditto.
+       * gnus-sum.el: Ditto.
+       * gnus-topic.el: Ditto.
+       * gnus-xmas.el (gnus-xmas-define): See above.
+       * gnus-xmas.el (gnus-xmas-redefine): See above.
+       * gnus-xmas.el (gnus-xmas-glyph-directory): Generate a
+       non-continuable error when the directory can't be found.
+
+2001-01-09 01:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-interactively-view-part): Don't copy-sequence
+       handle.
+       * gnus-art.el (gnus-mime-view-part): Copy it.
+       (gnus-mime-view-part-as-type): Add into gnus-article-mime-handles.
+
+2001-01-09  Michael Downes  <mjd@ams.org>
+
+       * gnus-sum.el (gnus-summary-read-group-1): More useful message.
+
+2001-01-08 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnmail.el (nnmail-get-new-mail): Find group only if file is not
+       orig-file.  Use ',source.
+
+2001-01-08 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-xmas.el (gnus-xmas-modeline-glyph):
+       (gnus-xmas-group-startup-message):
+       Detect gnus-xmas-glyph-directory when it is nil.
+
+2001-01-08 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * pop3.el (pop3-get-message-count): Andrew Innes
+       <andrewi@gnu.org>'s patch of 1999-12-01 was not fully committed.
+
+2001-01-05 06:49:37  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-agent.el (gnus-agent-fetch-session): Say what we quit.
+
+       * time-date.el (time-to-number-of-days): New function.
+
+2001-01-04 11:06:14  Gregory Chernov  <greg@visiontech-dml.com>  (tiny change)
+
+       * nnslashdot.el (nnslashdot-request-list): Always get the right
+       sid.
+
+2001-01-05 00:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-minibuffer-local-map): New keymap.
+       (message-read-from-minibuffer): Use it.
+       * gnus-msg.el (gnus-summary-resend-message): Use it.
+
+2001-01-04 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-start.el (gnus-display-time-event-handler): New function.
+       (gnus-after-getting-new-news-hook): Use it.
+
+2001-01-03 07:26:58  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-ignored-mail-headers): Add draft header.
+
+2001-01-02 06:28:28  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-expire-articles): Don't save
+       excursion.
+
+       * nnslashdot.el (nnslashdot-request-list): Get the right year.
+
+2001-01-01 00:52:44  Ed L. Cashin  <ecashin@coe.uga.edu>
+
+       * gnus-sum.el (gnus-summary-expire-articles): A revoked patch.
+       Save excursion.
+
+2000-12-31 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * qp.el (quoted-printable-decode-region): Don't backward-char.
+
+2000-12-31 03:57:31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-draft.el: Mark articles as replied.
+
+       * gnus-sum.el (gnus-summary-add-mark): New function.
+
+       * gnus-group.el (gnus-add-mark): New function.
+
+       * gnus-sum.el (gnus-summary-buffer-name): New function.
+       (gnus-summary-setup-buffer): Use it.
+
+       * gnus-draft.el: Set things up with the right post method and
+       stuff.
+
+       * message.el (message-ignored-news-headers): Remove X-Draft-From.
+
+       * gnus-msg.el (gnus-inews-insert-draft-meta-information): New function.
+
+       * gnus.el (gnus-draft-meta-information-header): New variable.
+
+2000-12-30 00:17:38  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-treatment-function-alist): Move the date
+       functions before the header sorting functions.
+
+       * mm-uu.el (mm-uu-pgp-signed-extract-1): Unquote "- " quotes.
+
+       * dgnushack.el (dgnushack-compile): Message whether there is w3.
+       Don't (push "/usr/share/emacs/site-lisp" load-path).
+
+       * gnus-cite.el (gnus-article-fill-cited-article): Don't add space
+       to empty fill prefixes.
+
+2000-12-30 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nntp.el (nntp-open-connection): Kill pbuffer if process is nil.
+       Suggested by Christoph Conrad <christoph.conrad@gmx.de>.
+
+2000-12-30 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnheader.el (autoload): Autoload gnus-sorted-intersection.
+
+       * nnml.el (autoload): Move to nnheader.el.
+
+       * nnfolder.el (nnfolder-existing-articles): Reversed, i.e. sorted.
+       (nnfolder-request-expire-articles): Use gnus-sorted-intersection.
+       (nnfolder-retrieve-headers): Use intersection.  Suggested by Jonas
+       Kvarnström <jonkv@ida.liu.se>.
+
+2000-12-30 00:17:38  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (article-make-date-line): Get the hours right.
+       (gnus-ignored-headers): More hiding.
+
+       * nnmail.el (nnmail-expiry-wait): Not an integer.
+
+       * message.el (message-goto-body): Only expand abbrev when called
+       interactively.
+       (message-make-lines): Use it.
+
+2000-12-29 20:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-inews-yank-articles): Reparse headers.
+
+2000-12-30 00:17:38  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-limit-include-expunged): Really
+       include the expunged articles.
+
+       * gnus-group.el (gnus-group-sort-by-server): New function.
+
+       * gnus.el (gnus-method-to-server-name): New function.
+       (gnus-group-prefixed-name): Use it.
+
+       * gnus-group.el (gnus-group-sort-function): Doc fix.
+       (gnus-group-sort-groups-by-server): New command.
+
+2000-12-29 13:25:10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-treat-date-english): New variable.
+       (article-date-english): New command.
+       (gnus-english-month-names): New variable.
+       (article-make-date-line): Do 'english.
+
+       * gnus-cite.el (gnus-article-fill-cited-article): Add a space
+       after the fill prefix.
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Removed "Enter
+       score...".
+
+       * gnus-art.el (gnus-ignored-headers): Hide more headers.
+
+       * message.el (message-mode-map): Bind comment-region.
+
+       * gnus-art.el (gnus-mime-display-part): Let w3 display
+       multipart/related.
+
+       * mm-bodies.el (mm-long-lines-p): New function.
+       (mm-body-encoding): Use it.
+       (mm-body-encoding): Encode articles with lines longer than 1000
+       characters.
+
+2000-12-29 01:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-enable-multibyte): Use
+       default-enable-multibyte-characters.
+       (mm-enable-multibyte-mule4): Ditto.
+       (mm-disable-multibyte): Test XEmacs.
+       (mm-disable-multibyte-mule4): Ditto.
+       (mm-with-unibyte-current-buffer): Simplified.
+       (mm-with-unibyte-current-buffer-mule4): Ditto.
+
+2000-12-28 19:44:56  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnheaderxm.el (nnheader-string-as-multibyte): New alias.
+
+       * nnheader.el (nnheader-string-as-multibyte): New alias.
+
+       * mm-view.el (mm-inline-text): Warn when bugging out in w3.
+
+       * gnus-uu.el (gnus-message-process-mark): New function.
+       (gnus-uu-mark-by-regexp): Use it.
+       (gnus-new-processable): New function.
+
+2000-12-28 19:21:57  Inge Frick  <inge@nada.kth.se>  (tiny change)
+
+       * gnus-sum.el (gnus-no-mark): New variable.
+
+2000-11-01 01:12:29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnwfm.el (nnwfm-create-mapping): Remove quote marks and
+       backslashes.
+
+2000-12-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-article-banner-alist): Remove duplicate
+       definition.
+
+2000-12-25 00:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * dgnushack.el (dgnushack-compile): elc is in the current directory.
+
+       * qp.el (quoted-printable-encode-region): Don't check multibyte in
+       XEmacs.
+
+2000-12-25  Lloyd Zusman  <ljz@asfast.com>  (tiny change)
+
+       * mml.el (mml-read-tag): Save tag location.
+
+2000-12-25  Simon Josefsson  <simon@josefsson.org>
+
+       * starttls.el: Sync with Emacs 21.
+
+2000-12-24 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-mail): Support yank-action.
+
+       * message.el (message-setup): Revoke the last change.
+
+2000-12-24 01:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-setup): Use cons.  Suggested by Johan Vromans
+       <jvromans@squirrel.nl>.
+
+2000-12-24  Simon Josefsson  <sj@extundo.com>
+
+       * mm-bodies.el (mm-decode-content-transfer-encoding): Preserve
+       mailing list junk at end of part.
+
+2000-12-23  Simon Josefsson  <sj@extundo.com>
+
+       * nnimap.el (nnimap-expiry-target): New function.
+       (nnimap-request-expire-articles): Use it.
+
+2000-12-22 21:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el (gnus-group-parameters-more): New variable.
+       * gnus-cus.el (gnus-group-customize): Use it.
+
+       * gnus.el (gnus-define-group-parameter): New macro.
+       (auto-expire): Use it.
+       (total-expire): Use it.
+       * gnus-art.el (banner): Use it.
+
+       * mml.el (mml-parse): save-excursion.  Suggested by Lloyd Zusman
+       <ljz@asfast.com>.
+
+2000-12-22 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-topic.el (gnus-topic-create-topic): Use list.
+
+       * gnus-vm.el (gnus-summary-save-article-vm): Require gnus-art
+       before binding gnus-default-article-saver.
+
+       * gnus-sum.el (gnus-summary-save-article):
+       (gnus-summary-pipe-output):
+       (gnus-summary-save-article-mail):
+       (gnus-summary-save-article-rmail):
+       (gnus-summary-save-article-file):
+       (gnus-summary-write-article-file):
+       (gnus-summary-save-article-body-file): Ditto.
+
+       * gnus-mh.el (gnus-summary-save-article-folder): Ditto.
+
+2000-12-22 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-security-button-map):
+       (gnus-mime-button-map): Add parent.
+
+2000-12-22 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * messagexmas.el (message-xmas-redefine): New function.
+
+       * message.el: Use it.
+
+       * gnus-art.el (gnus-article-check-hidden-text): Return t.
+
+       * gnus-util.el (gnus-remove-text-properties-when): Return t.
+
+2000-12-22 03:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-dissect-multipart): Avoid errors owing to
+       malformatted messages.
+
+2000-12-22 02:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-image-load-path): New function.
+
+       * gnus-group.el (gnus-group-make-tool-bar): Use it.
+
+       * gnus-sum.el (gnus-summary-make-tool-bar): Use it.
+
+       * message.el (message-tool-bar-map): Use it.
+
+       * Makefile.in (install-el): New rule.
+
+2000-12-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (article-treat-dumbquotes): Quote \.
+
+2000-12-21 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-treat-emphasize): Don't treat emphasis if
+       Emacs 20 runs on a terminal.
+
+2000-12-21 14:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-bug): Revert to save-excursion.
+
+       * mml.el (gnus-add-minor-mode): Autoload.
+
+       * message.el (message-forward): Save-restriction.
+
+2000-12-21  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-art.el (article-treat-dumbquotes): More doc, provided by
+       Paul Stevenson <p.stevenson@surrey.ac.uk>
+
+2000-12-21 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-ml.el (gnus-mailing-list-mode-map): Use C-c C-n prefix.
+
+       * mml.el (gnus-ems): Don't require.
+
+       * gnus.el (gnus-decode-rfc1522): Removed.
+       (gnus-set-text-properties): Define.
+
+2000-12-21 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-*): Handle may be nil.
+
+       * gnus-sum.el (gnus-summary-mode): Turn on gnus-mailing-list-mode.
+
+       * gnus.el (gnus-group-remove-excess-properties): Not defined
+       in gnus-xmas.
+
+2000-12-20 21:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-mail-user-agent): Add :version.
+
+2000-12-21  Miles Bader  <miles@gnu.org>
+
+       * message.el (message-mode): Set `comment-start' to the  yank prefix.
+
+2000-12-20 17:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-mail-user-agent): New variable.
+       (message-setup): Renamed to message-setup-1.  Support
+       mail-user-agent.
+       (message-mail-user-agent): New function.
+       (message-mail): Use it.
+       (message-reply): Use it.
+       (message-resend): Use it.
+       (message-mail-other-window): Use it.
+       (message-mail-other-frame): Use it.
+
+       * gnus-msg.el (gnus-bug): Support mail-user-agent.
+
+2000-12-20 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-tool-bar-map): Simplify.
+       (message-narrow-to-head-1): New function.
+       (message-narrow-to-head): Use it.
+       (message-reply): Ditto.
+       (message-cancel-news): Ditto.
+       (message-supersede): Ditto.
+       (message-make-forward-subject): Ditto.
+       (message-bounce): Ditto.
+
+2000-12-20 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * uudecode.el (uudecode-decode-region-external): make-temp-file
+       may not be defined.
+
+       * binhex.el (defalias): eval-and-compile.
+
+       * message.el (message-tool-bar-map): New function.
+       (message-mode): Use it.
+
+2000-12-20 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nntp.el (nntp-find-connection): Remove the entry.
+       (nntp-retrieve-groups): (gnus-buffer-live-p buf).
+
+2000-12-20 05:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-summary-mail-forward): Use original buffer.
+
+       * message.el (message-forward): Copy buffer in unibyte mode.
+
+2000-12-20 04:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-make-forward-subject): Don't widen.  Decode.
+       (message-forward): Don't decode subject.
+
+2000-12-20  Christoph Conrad  <C.Conrad@cli.de>
+
+       * qp.el (quoted-printable-encode-region): Upcase QP.
+
+2000-12-20 03:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-possibly-verify-or-decrypt): Use
+       mail-extract-a-c instead.  Don't depend on Gnus.
+
+       * mml.el (gnus-ems): Require it.
+
+       * gnus-msg.el (gnus-summary-mail-forward): ???
+
+       * message.el (message-forward): Move mime-to-mml here.
+
+2000-12-20 02:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el, gnus-sum.el, message.el: Add :help unless Emacs.
+       * gnus-art.el (gnus-insert-mime-button): Simplify.
+       (gnus-mime-display-alternative): Ditto.
+       (gnus-insert-mime-security-button): Ditto.
+
+2000-12-20 01:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-util.el (gnus-add-text-properties-when): In XEmacs,
+       text-property-not-all doesn't return nil when start=mark(end).
+       (gnus-remove-text-properties-when): Ditto.
+
+2000-12-20 00:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-start.el (gnus-group-change-level): Remove group from
+       gnus-active-hashtb if real killed.
+
+2000-12-19 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-insert-mime-button): Emacs20 needs local-map.
+       (gnus-mime-display-alternative): Ditto.
+       (gnus-insert-mime-security-button): Ditto.
+
+2000-12-19 21:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-start.el (gnus-group-change-level): Don't add it into
+       killed-list if it was killed.
+
+2000-12-19 19:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnmbox.el (nnmbox-file-coding-system): Use binary.
+       (nnmbox-active-file-coding-system): Ditto.
+
+       * gnus-cus.el (gnus-group-parameters): Add posting-style.
+
+2000-12-19 18:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el (gnus-version):
+       (gnus-version-number): Set to Oort Gnus 0.01.
+
+       * gnus-art.el (gnus-mime-security-button-map):
+       (gnus-insert-mime-security-button): Fix for Emacs21.
+
+2000-12-19 17:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el, gnus-sum.el, message.el: Comment out :help in
+       easymenu, because XEmacs doesn't understand :help.
+
+       * mm-uu.el: Require binhex.
+
+2000-12-19 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el: Merged.  Emacs21 CVS tag is zsh-merge-ognus-1.
+
+2000-12-19  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-charset-synonym-alist): Fix a typo.
+
+2000-12-18  Gerd Moellmann  <gerd@gnu.org>
+
+       * *.xpm, *.pbm: Convert icons icons to size 24x24.
+
+2000-12-18  Dave Love  <fx@gnu.org>
+
+       * gnus-msg.el (news-setup, news-reply-mode): Don't autoload
+       (unused).
+
+2000-12-13  Miles Bader  <miles@gnu.org>
+
+       * smiley-ems.el (smiley-region): Bind `inhibit-point-motion-hooks'
+       to t, so that we don't get stuck while trying to smilefy
+       intangible text.
+
+2000-12-12  Gerd Moellmann  <gerd@gnu.org>
+
+       * smiley-ems.el (smiley-regexp-alist): Make regexps match
+       at the end of the buffer.
+       (smiley-region): In the loop, move to the end of the submatch
+       matching the smiley instead of using the end of the match
+       of the whole regexp.
+
+2000-12-12  Eli Zaretskii  <eliz@is.elta.co.il>
+
+       * message.el (message-mode): Doc fix.
+
+2000-12-12  Gerd Moellmann  <gerd@gnu.org>
+
+       * smiley-ems.el (smiley-region): Doc fix.
+
+2000-12-11  Miles Bader  <miles@gnu.org>
+
+       * gnus-sum.el (gnus-summary-recenter): When trying to keep the
+       bottom line visible, check to see if it's partially obscured, and
+       if so, either scroll one more line to make it fully visible, or
+       revert to showing the second line from the top.
+
+2000-12-07  Dave Love  <fx@gnu.org>
+
+       * mailcap.el (mailcap-download-directory)
+       * gnus-audio.el (gnus-audio-directory)
+       * smiley-ems.el (smiley-data-directory): Fix :type.
+
+2000-11-30  Dave Love  <fx@gnu.org>
+
+       * message.el (message-auto-save-directory): Use
+       file-name-as-directory.
+       (message-set-auto-save-file-name): Create
+       message-auto-save-directory if necessary.
+       (message-replace-chars-in-string): Removed -- unused.
+       (message-mail-alias-type): Customize.
+       (message-headers): Remove duplicate defgroup.
+
+2000-11-29  Dave Love  <fx@gnu.org>
+
+       * qp.el (quoted-printable-decode-region): Use error, not message
+       to report malformed text (like base64).  Amend message.
+
+2000-11-29  Miles Bader  <miles@gnu.org>
+
+       * message.el (message-header-lines): Fontify tag.
+
+2000-11-27  Dave Love  <fx@gnu.org>
+
+       * nnlistserv.el: Ignore errors when requiring nnweb and avoid a
+       compiler warning.
+
+;2000-11-26  Dave Love  <fx@gnu.org>
+;
+;      * mm-uu.el (mm-uu-configure-list): Fix typo in :type.
+;
+2000-11-23  Dave Love  <fx@gnu.org>
+
+       * uu-post.pbm, uu-decode.pbm: New files from XPMs.
+
+       * mm-uu.el (uudecode): Require.
+       (uudecode-decode-region, uudecode-decode-region-external): Don't
+       autoload.
+       (mm-uu-copy-to-buffer): Doc fix.
+       (mm-uu-decode-function, mm-uu-binhex-decode-function): Doc, custom
+       type fix.
+
+       * mailcap.el: Doc fixes.
+       (mailcap-mime-data): Various adjustments.
+       (mailcap): New group.
+       (mailcap-download-directory): Customize.
+       (mailcap-generate-unique-filename, mailcap-binary-suffixes)
+       (mailcap-temporary-directory): Deleted (unused).
+       (mailcap-unescape-mime-test): Simplify slightly.
+       (mailcap-viewer-passes-test): Use functionp.
+       (mailcap-command-p): Aliased to executable-find.
+
+       * rfc2047.el (rfc2047-encode-message-header): Don't encode if
+       default-enable-multibyte-characters is nil.
+
+2000-11-22  Gerd Moellmann  <gerd@gnu.org>
+
+       * gnus-group.el (gnus-group-make-tool-bar): Fix a paren typo.
+
+2000-11-21  Dave Love  <fx@gnu.org>
+
+       * gnus-art.el (gnus-mime-button-map): Don't inherit from
+       gnus-article-mode-map.
+;      (gnus-mime-button-menu): Use mouse-set-point.
+       (gnus-insert-mime-button, gnus-mime-display-alternative)
+       (gnus-mime-display-alternative): Don't use local-map property.
+
+2000-11-17  Dave Love  <fx@gnu.org>
+
+       * uudecode.el (uudecode-insert-char): Fix bogus feature test.
+       (uudecode-decode-region-external): Doc fix.  Use with-temp-buffer
+       and make-temp-file.
+       (uudecode-decode-region): Doc fix.
+
+2000-11-14  Dave Love  <fx@gnu.org>
+
+       * cu-exit.pbm, exit-summ.pbm, followup.pbm, fuwo.pbm:
+       * mail-reply.pbm, next-ur.pbm, post.pbm, prev-ur.pbm:
+       * reply-wo.pbm, reply.pbm, rot13.pbm, save-aif.pbm, save-art.pbm:
+       New files, derived from the XPMs.
+
+2000-11-10  Dave Love  <fx@gnu.org>
+
+       * gnus-agent.el (gnus-agent-confirmation-function): Add :version.
+       (gnus-agent-lib-file, gnus-agent-load-alist)
+       (gnus-agent-save-alist, gnus-agent-article-name): Use
+       expand-file-name.
+
+       * gnus-group.el (gnus-group-name-charset-method-alist): Add
+       :version.
+       (nnkiboze-score-file): Defvar when compiling.
+
+       * gnus-start.el (gnus-read-newsrc-file): Add :version.
+
+       * gnus-art.el (gnus-article-banner-alist)
+       (gnus-emphasize-whitespace-regexp, gnus-ignored-mime-types)
+       (gnus-article-date-lapsed-new-header)
+       (gnus-article-mime-match-handle-function, gnus-mime-action-alist)
+       (gnus-treat-strip-list-identifiers, gnus-treat-date-iso8601)
+       (gnus-treat-strip-headers-in-body)
+       (gnus-treat-capitalize-sentences, gnus-treat-play-sounds)
+       (gnus-treat-translate): Add :version.
+       (gnus-article-mime-part-function): Fix defcustom.
+
+       * nnmail.el (nnmail-expiry-target)
+       (nnmail-scan-directory-mail-source-once, nnmail-extra-headers)
+       (nnmail-split-header-length-limit): Add :version.
+
+       * gnus-sum.el (gnus-auto-expirable-marks)
+       (gnus-inhibit-user-auto-expire, gnus-list-identifiers)
+       (gnus-extra-headers, gnus-ignored-from-addresses)
+       (gnus-newsgroup-ignored-charsets)
+       (gnus-group-highlight-words-alist)
+       (gnus-summary-show-article-charset-alist): Add :version.
+
+       * catchup.pbm, describe-group.pbm, exit-gnus.pbm, get-news.pbm:
+       gnntg.pbm, kill-group.pbm, subscribe.pbm, unsubscribe.pbm: New
+       files, converted from the XPMs.
+
+       * gnus-cache.el (gnus-cache-active-file): Don't use
+       file-name-as-directory on directory.
+       (gnus-cache-file-name): Use expand-file-name, not concat.  Don't
+       use file-name-as-directory on directory.
+
+       * time-date.el (timezone-make-date-arpa-standard): Autoload.
+       (date-to-time): Use it.
+
+;      * message.el (message-mode) <adaptive-fill-regexp>:
+;      <adaptive-fill-first-line-regexp>: Use [:alnum:] in regexp range.
+;      (message-newline-and-reformat): Likewise.
+       (message-forward-as-mime, message-forward-ignored-headers)
+       (message-buffer-naming-style, message-default-charset)
+       (message-dont-reply-to-names, message-send-mail-partially-limit):
+       Add :version.
+
+       * mm-util.el: Doc fixes.
+       (mm-mime-charset): Don't use the raw result of
+       mm-preferred-coding-system.
+       (mm-with-unibyte-buffer, mm-with-unibyte-current-buffer)
+       (mm-with-unibyte): Simplify.
+
+       * gnus-int.el (gnus-start-news-server): Use expand-file-name, not
+       concat.
+
+       * pop3.el (pop3-version): Deleted.
+       (pop3-make-date): New function, avoiding message-make-date.
+       (pop3-munge-message-separator): Use it.
+
+2000-11-09  Dave Love  <fx@gnu.org>
+
+       * gnus-group.el (gnus-group-make-directory-group)
+       (gnus-group-fetch-faq): Use expand-file-name.
+       (gnus-group-fetch-faq): Simplify completing-read form.
+
+       * mm-bodies.el (mm-encode-body): Use mm-multibyte-p, don't just
+       test for Mule.
+
+       * message.el (tool-bar-map): Defvar when compiling.
+
+       * gnus-setup.el (running-xemacs, gnus-use-installed-tm)
+       (gnus-tm-lisp-directory): Deleted.
+       (gnus-use-installed-mailcrypt, gnus-emacs-lisp-directory): Use
+       (featurep 'xemacs).
+       (gnus-gnus-lisp-directory, gnus-mailcrypt-lisp-directory)
+       (gnus-mailcrypt-lisp-directory, gnus-bbdb-lisp-directory): Remove
+       version numbers from file names.
+
+2000-11-08  Dave Love  <fx@gnu.org>
+
+       * mm-view.el: Use featurep for XEmacs test.
+       (mm-inline-message): Test for `remove-specifier'; don't use
+       condition-case.
+
+       * mm-bodies.el (mm-encode-body): Use mm-multibyte-p.
+
+       * gnus-score.el (gnus-score-load-file): Use expand-file-name.
+       (gnus-score-find-bnews): Don't concat "".
+
+       * cu-exit.xpm, prev-ur.xpm, next-ur.xpm, post.xpm, fuwo.xpm:
+       * followup.xpm, uu-post.xpm, uu-decode.xpm, mail-reply.xpm:
+       * reply.xpm, reply-wo.xpm, rot13.xpm, save-aif.xpm, save-art.xpm:
+       * exit-summ.xpm: New files, renamed from icons by Luis Fernandes.
+
+       * gnus-sum.el: Put some defvars in eval-when-compile.
+       (gnus-summary-mode-hook): Add :options.
+       (gnus-summary-make-menu-bar): Add some :help, used by tool bar.
+       (gnus-summary-tool-bar-map): New variable.
+       (gnus-summary-make-tool-bar): New function.
+       (gnus-summary-mode): Put kill-all-local-variables first.
+
+       * gnus-group.el (gnus-group-toolbar-map): New variable.
+       (gnus-group-make-tool-bar): Rewritten.
+       (gnus-group-mode): Put kill-all-local-variables first.
+
+       * rfc2047.el: Require gnus-util.
+
+       * nnml.el (gnus-sorted-intersection): Autoload.
+
+       * nnheader.el: Wrap subst-char-in-string def in eval-and-compile.
+       Put some defvars in eval-when-compile.
+       (gnus-intersection, gnus-sorted-complement): Autoload.
+
+       * imap.el (imap-point-at-eol): New, replacing gnus-point-at-eol.
+
+       * mm-encode.el (mm-body-7-or-8): Autoload.
+
+       * mm-decode.el (mm-insert-inline): Autoload.
+
+       * mml.el:
+       * message.el: Put some defvars in eval-when-compile.
+
+       * gnus-msg.el: Put some defvars in eval-when-compile.
+       (gnus-msg-mail): Move after gnus-setup-message.
+
+       * smiley-ems.el (smiley-data-directory, smiley-regexp-alist): Doc fix.
+
+2000-11-07  Dave Love  <fx@gnu.org>
+
+       * gnus-util.el (nnheader): Don't require message (recursive
+       autoload).
+
+       * uudecode.el: Avoid compiler warnings.
+
+       * rfc2047.el (rfc2047-fold-region): Use gnus-point-at-bol.
+       (rfc2047-charset-encoding-alist): Add iso-8859-1[45].
+
+2000-11-06  Dave Love  <fx@gnu.org>
+
+       * gnus-salt.el (gnus-binary-mode): Fix call to gnus-add-minor-mode.
+
+       * uudecode.el: Use (featurep 'xemacs).  Require cl when compiling.
+       (uudecode-char-int): New alias, replacing char-int.
+       (uudecode-decode-region): Don't call buffer-disable-undo.
+
+;      * mm-uu.el (mm-uu-configure): Unquote lambda.
+;      (mm-uu-configure-list): Doc fix.
+;
+;      * earcon.el (running-xemacs): Don't define.
+;
+;2000-11-03  Stefan Monnier  <monnier@cs.yale.edu>
+;
+;      * message.el (message-font-lock-keywords): Match a final newline
+;      to help font-lock's multiline support.
+;
+2000-11-03  Dave Love  <fx@gnu.org>
+
+       * gnus-nocem.el (gnus-nocem-check-article-limit): Default to 500.
+
+       * mm-partial.el (mm-inline-partial): Space-prefix temp buffer
+       name.
+
+       * gnus-cus.el (gnus-group-parameters) <gcc-self>: Fix custom type.
+       <banner>: Fix custom type, doc.
+
+       * mm-decode.el (mm-display-external): Space-prefix temp buffer
+       name.  Don't disable undo explicitly.
+
+;2000-11-02  Dave Love  <fx@gnu.org>
+;
+;      * message.el (message-font-lock-keywords): Use [:alpha:] for
+;      cite-prefix.
+
+2000-11-01  Dave Love  <fx@gnu.org>
+
+       * rfc2047.el (base64): Require unconditionally.
+       (message-posting-charset): Defvar when compiling.
+       (rfc2047-encode-message-header, rfc2047-encodable-p): Require
+       message.
+
+       * gnus-sum.el (nnoo): Require.
+       (mm-uu-dissect): Autoload.
+
+       * mml.el (mml-parse-1): Clarify message.
+       (mml-minibuffer-read-type): Use mailcap-mime-types.
+
+2000-11-01  Stefan Monnier  <monnier@cs.yale.edu>
+
+       * mml.el: Fix a typo in the requiring of CL.
+
+2000-11-01  Dave Love  <fx@gnu.org>
+
+       * utf7.el: Require cl when compiling.
+
+       * binhex.el: Use (featurep 'xemacs).
+       (binhex-char-int): New alias, replacing char-int.  Change callers.
+       (binhex-decode-region): Simplify work buffer code.
+       (binhex-decode-region-external): Use expand-file-name, not concat.
+
+2000-10-30  Dave Love  <fx@gnu.org>
+
+       * gnus-art.el: Fix 2000-10-27 change properly.
+
+2000-10-28  Miles Bader  <miles@gnu.org>
+
+       * gnus-art.el (gnus-read-save-file-name): Remove extraneous paren.
+
+2000-10-27  Dave Love  <fx@gnu.org>
+
+       * gnus-group.el (gnus-group-make-menu-bar): Add some :help
+       strings.
+       (gnus-group-make-tool-bar): New function.
+       (gnus-group-mode): Use it.
+
+       * message.el (message-mode-menu): Add some :help strings.
+       (message-mode) [message-tool-bar-map]: Define tool-bar-map.
+       (featurep): Use (featurep 'xemacs).  Install tool bar for Emacs.
+
+       * catchup.xpm, exit-gnus.xpm, gnntg.xpm, subscribe.xpm:
+       * describe-group.xpm, get-news.xpm, kill-group.xpm:
+       * unsubscribe.xpm: New files.  Renamed icons from Luis Fernandes.
+
+       * mm-decode.el (mm-valid-and-fit-image-p): Don't test
+       display-graphic-p here.
+
+2000-10-27  Miles Bader  <miles@lsi.nec.co.jp>
+
+       * gnus-ems.el (gnus-ems-redefine): Use (featurep 'xemacs) instead
+       of the `gnus-xemacs' variable, as the latter has been removed.
+       * gnus-start.el (gnus-1, gnus-read-descriptions-file): Likewise.
+       * gnus-art.el (gnus-treat-display-xface)
+       (gnus-treat-display-smileys, gnus-treat-display-picons)
+       (gnus-article-read-summary-keys): Likewise.
+
+2000-10-26  Dave Love  <fx@gnu.org>
+
+       (defvar): Use rmail-spool-directory unconditionally.
+
+2000-10-18  Dave Love  <fx@gnu.org>
+
+       * mm-bodies.el (mm-uu-decode-function)
+       (mm-uu-binhex-decode-function): Defvar when compiling.
+
+       * gnus-nocem.el (gnus-nocem-issuers): Update.
+       (gnus-nocem-check-from): New option.
+       (gnus-nocem-scan-groups): Use it.
+       (gnus-nocem-check-article): Bind gnus-newsgroup-name.
+       (gnus-nocem-check-article-limit): Add :version.
+
+2000-10-16  Stefan Monnier  <monnier@cs.yale.edu>
+
+       * ietf-drums.el (mm-util): Require CL when compiling.
+
+2000-10-15  Dave Love  <fx@gnu.org>
+
+       * qp.el: Require mm-util.
+
+2000-10-13  Dave Love  <fx@gnu.org>
+
+       * qp.el (quoted-printable-decode-region): Avoid invalid
+       coding-systems.
+
+2000-10-12  Gerd Moellmann  <gerd@gnu.org>
+
+       * mm-bodies.el: Don't require `mm-uu' at compile-time; it leads
+       to a recursive load.
+
+2000-10-12  Dave Love  <fx@gnu.org>
+
+       * mm-util.el (mm-charset-synonym-alist): Add windows-1252.
+
+       * gnus.el (gnus-group-startup-message): Check for PBM image.
+
+2000-10-09  Dave Love  <fx@gnu.org>
+
+       * mail-source.el (mail-source-fetch-imap): Bind
+       default-enable-multibyte-characters rather than using
+       mm-disable-multibyte.
+
+2000-10-05  Dave Love  <fx@gnu.org>
+
+       * qp.el (mm-decode-coding-region, mm-encode-coding-region):
+       Autoload.
+       (quoted-printable-decode-region): Rename arg which confused
+       charset with coding-system.  Don't use nonascii-insert-offset.
+       Coding-system encode the region initially.  Don't recognize `=='
+       as valid QP.  Coding-system decode the region finally.
+       (quoted-printable-decode-string): Rename arg which confused
+       charset with coding-system.
+
+       * mm-bodies.el: Require mm-uu, Don't require qp, uudecode.
+       (mm-encode-body): Apply mm-charset-to-coding-system to arg of
+       mm-encode-coding-region.
+       (mm-decode-body, mm-decode-string): Rename variables which
+       confused charset with coding-system.
+       (binhex-decode-region): Don't autoload.
+       (mm-body-encoding): Require message.
+       (mm-decode-content-transfer-encoding): Require mm-uu in relevant
+       cond branches.
+
+       * gnus-art.el (article-de-quoted-unreadable)
+       (article-de-base64-unreadable): Fold search case
+       rather than downcasing string.  Apply mm-charset-to-coding-system
+       to arg of quoted-printable-decode-region.
+
+2000-10-04  Dave Love  <fx@gnu.org>
+
+       * gnus-ems.el: Don't turn off compiler warnings in local vars.
+       Require ring when compiling.
+       (gnus-article-compface-xbm): New variable.
+
+2000-10-04  Dave Love  <fx@gnu.org>
+
+       * smiley-ems.el (smiley-regexp-alist, smiley-update-cache): Use
+       pbm images.
+
+       * frown.pbm, smile.pbm, wry.pbm: New files.
+
+       * frown.xbm, smile.xbm, wry.xbm: Deleted.
+
+2000-10-03  Dave Love  <fx@gnu.org>
+
+       * mail-source.el (mail-sources): Revert to nil.
+
+       * nnmail.el (nnmail-spool-file): Revert to `((file))'.
+
+       * qp.el: Don't require mm-util.
+       (quoted-printable-decode-region): Rewritten.
+       (quoted-printable-decode-string, quoted-printable-encode-region):
+       Doc fix.
+       (quoted-printable-encode-region): Barf on multibyte characters.
+       Maybe make the class multibyte.  Upcase chars, not formatted
+       strings.  Allow mm-use-ultra-safe-encoding to be unbound.
+       (quoted-printable-encode-string): Don't use
+       mm-with-unibyte-buffer.
+
+2000-09-29  Gerd Moellmann  <gerd@gnu.org>
+
+       * smiley-ems.el (smiley-update-cache): Use `:ascent center'.
+
+2000-09-21  Dave Love  <fx@gnu.org>
+
+       * smiley-ems.el (smiley-region): Test if display-graphic-p bound
+       (for Emacs 20).  Tidy somewhat.
+
+2000-09-21  Dave Love  <fx@gnu.org>
+
+       * gnus-ems.el (gnus-article-display-xface): Use unibyte for the
+       image processing.  Rationalize logic somewhat.
+
+2000-09-20  Dave Love  <fx@gnu.org>
+
+       * gnus-start.el (gnus-1) <gnus-simple-splash>: Don't test for X
+       specifically.
+
+       * gnus.el (gnus-version-number): Avoid some redundant
+       autoloads.
+
+2000-09-20  Gerd Moellmann  <gerd@gnu.org>
+
+       * gnus-ems.el (gnus-article-display-xface): Don't convert PBM
+       to XBM; we always have PBM support.
+
+2000-09-14  Dave Love  <fx@gnu.org>
+
+       * gnus.el (gnus-charset):
+       * mm-decode.el (mime-display):
+       * imap.el (imap) <defgroup>: Add :version.
+
+2000-09-13  Gerd Moellmann  <gerd@gnu.org>
+
+       * parse-time.el: Fix author's mail address.
+
+       * earcon.el, flow-fill.el, gnus-cite.el, gnus-gl.el, gnus-ml.el:
+       * gnus-mlspl.el, gnus-nocem.el, gnus-range.el, gnus-salt.el:
+       * gnus-setup.el, gnus-soup.el, gnus-undo.el, gnus-vm.el:
+       * messcompat.el, nnbabyl.el, nndir.el, nneething.el:
+       * nngateway.el, nnheaderxm.el, nnkiboze.el, nnlistserv.el:
+       * nnmbox.el, nnmh.el, nnoo.el, nnsoup.el, nnspool.el, rfc2045.el:
+       * rfc2231.el, uudecode.el: Fix copyright notice.
+
+       * nnweb.el (toplevel): To make the file bootstrap in Emacs,
+       require `w3' at load-time only if not running in batch mode.
+
+2000-12-19 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el: Before merge with Emacs21.
+
+2000-12-19  Raymond Scholz  <ray-2000@zonix.de>
+
+       * gnus-art.el (gnus-article-dumbquotes-map): Add EUR symbol.
+
+2000-12-19  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * mml.el (mml-mode-map): Change mml prefix from `M-m' to `C-c C-m'
+       to avoid conflict with the standard `back-to-indentation'
+       binding.
+
+2000-12-17 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-extern.el (mm-inline-external-body): g-a-m-h may be a handle.
+
+       * mm-util.el (mm-enable-multibyte-mule4): Test charsetp.
+       (mm-disable-multibyte-mule4): Ditto.
+       (mm-with-unibyte-current-buffer-mule4): Ditto.
+
+2000-12-15 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * pop3.el (pop3-movemail): Use binary.
+       (pop3-movemail-file-coding-system): Removed.
+
+2000-12-14 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-charset-synonym-alist): Add cn-gb.
+
+2000-12-13 21:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnspool.el (nnspool-lib-dir): Check whether /usr/lib/news/active
+       exists.
+
+2000-12-13 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-post-method): Use backend name when the
+       address is "".
+
+2000-12-08 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-verify-x-pgp-sig): Don't test
+       mm-verify-option.
+       (gnus-treat-x-pgp-sig): Default value.
+       (gnus-ignored-headers): Redundant.
+
+2000-12-04 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-win.el (gnus-configure-frame): Save selected window.
+
+2000-02-15  Andrew Innes  <andrewi@gnu.org>
+
+       * nnmbox.el: Require gnus-range.
+       (nnmbox-group-building-active-articles): New variable.
+       (nnmbox-group-active-articles): New variable; this is a cache of
+       all active articles by group and number.
+       (nnmbox-in-header-p): New function.
+       (nnmbox-find-article): New function.
+       (nnmbox-record-active-article): New function.
+       (nnmbox-record-deleted-article): New function.
+       (nnmbox-is-article-active-p): New function.
+       (nnmbox-retrieve-headers): Use nnmbox-find-article.
+       (nnmbox-request-article): Ditto.  Also supply extra arg to
+       nnmbox-article-group-number.
+       (nnmbox-request-expire-articles): Ditto.
+       (nnmbox-request-move-article): Ditto.
+       (nnmbox-request-replace-article): Ditto.
+       (nnmbox-request-rename-group): Rename group entry in active
+       article cache.
+       (nnmbox-delete-mail): Update active article cache, unless article
+       is being replaced.
+       (nnmbox-possibly-change-newsgroup): Call nnmbox-read-mbox, rather
+       than partially duplicating it.
+       (nnmbox-article-group-number): Add extra `this-line' arg, to
+       handle articles belonging to multiple groups.
+       (nnmbox-save-mail): Update active article cache.
+       (nnmbox-read-mbox): Build active article cache when loading mbox.
+       Also do some repair work, if we find articles that are missing the
+       appropriate X-Gnus-Newsgroup lines in the header.  We can usually
+       reconstruct these from Xref info.
+
+2000-12-04 18:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mail-source.el (mail-source-report-new-mail): Use
+       nnheader-run-at-time.
+
+2000-02-15  Andrew Innes  <andrewi@gnu.org>
+
+       * mail-source.el (mail-source-fetch-pop): Clear pop password when
+       an error is thrown, and then rethrow the error.
+       (mail-source-check-pop): Ditto.
+       (mail-source-start-idle-timer): Prevent multiple pop checks
+       running if the check takes a long time.
+
+2000-12-04 14:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-msg-mail): COMPOSEFUNC should return t if
+       succeed.
+
+2000-12-04 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-win.el (gnus-configure-windows): Make sure
+       nntp-server-buffer is live.
+       (gnus-remove-some-windows): switch-to-buffer -> set-buffer.
+
+2000-11-21  Stefan Monnier  <monnier@cs.yale.edu>
+
+       * gnus-win.el (gnus-configure-windows): switch-to-buffer -> set-buffer.
+
+2000-12-04  Andreas Jaeger  <aj@suse.de>
+
+       * gnus-msg.el (gnus-summary-mail-forward): Fix typos in description.
+
+2000-12-03 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml2015.el (mml2015-fix-micalg): Alg might be nil.
+
+2000-12-01  ShengHuo ZHU  <zsh@cs.rochester.edu>
+       Trivial patch from Christopher Splinter  <chris@splinter.inka.de>
+
+       * gnus-sum.el (gnus-summary-limit-to-age): Fix typo.
+
+2000-12-01  Simon Josefsson  <sj@extundo.com>
+
+       * mml-smime.el (mml-smime-verify): Fix address parsing.
+
+2000-12-01  Simon Josefsson  <sj@extundo.com>
+
+       * mml-smime.el (mml-smime-verify): Don't modify MM buffer.  Handle
+       more than one certificate inside PKCS#7 blob.  Better security
+       information (clamed / actual sender, openssl output, certificates
+       inside message).
+
+       * smime.el (smime-verify-region): Output to /dev/null.
+       (smime-buffer-as-string-region): Don't parse empty lines.
+
+2000-11-30 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-security-button-line-format-alist): Add
+       ?d and ?D.
+       (gnus-mime-security-show-details-inline): New variable.
+       (gnus-mime-security-show-details): Use them.
+       (gnus-insert-mime-security-button): Ditto.
+
+       * mml2015.el (mml2015-gpg-verify): Set details when succeed.
+       Suggest by Michael Duggan (md5i@cs.cmu.edu).
+       (mml2015-gpg-clear-verify): Ditto.
+       (mml2015-gpg-decrypt-1): Ditto.
+       (mml2015-use): Prefer 'gpg.
+
+2000-11-30 19:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-util.el (gnus-add-text-properties-when): New function.
+       (gnus-remove-text-properties-when): Ditto.
+
+       * gnus-cite.el (gnus-article-hide-citation): Use them.
+       (gnus-article-toggle-cited-text): Use them.
+
+       * gnus-art.el (gnus-signature-toggle): Use them.
+       (gnus-article-show-hidden-text): Ditto.
+       (gnus-article-hide-text): Ditto.
+
+2000-11-30 14:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-find-charset-region): Remove eight-bit-*.
+
+2000-11-30  Simon Josefsson  <sj@extundo.com>
+
+       * smime.el (smime-point-at-eol): New alias.
+       (smime-buffer-as-string-region): Use it.
+
+2000-11-29 21:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nndraft.el (nndraft-request-restore-buffer): Remove Date field.
+
+2000-11-29 20:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnfolder.el (nnfolder-request-expire-articles): expiry-target.
+
+       * nnbabyl.el (nnbabyl-request-expire-articles): Ditto.
+
+       * nnmbox.el (nnmbox-request-expire-articles): Ditto.
+
+2000-11-22  Jan Nieuwenhuizen  <janneke@gnu.org>
+
+       * nnmh.el (nnmh-request-expire-articles): Implemented
+       expiry-target for nnmh backend.
+
+2000-11-30  Simon Josefsson  <sj@extundo.com>
+
+       * mm-decode.el (mm-security-from): New variable.
+       (mm-possibly-verify-or-decrypt): Use it rather than `from'.
+
+       * mml-smime.el (mml-smime-verify): Use `mm-security-from' rather
+       than `from'.
+
+2000-11-30  Simon Josefsson  <sj@extundo.com>
+
+       * mml-smime.el (mml-smime-verify): Verify that certificate mail
+       address match sender address.
+
+       * mm-decode.el (mm-possibly-verify-or-decrypt): Bind sender address.
+
+       * smime.el (smime-verify-region): Don't copy buffer.
+       (smime-decrypt-buffer): Use expand-file-name on keyfile.
+       (smime-pkcs7-region): New function.
+       (smime-pkcs7-certificates-region): Ditto.
+       (smime-pkcs7-email-region): Ditto.
+       (smime-buffer-as-string-region): Ditto.
+
+       * gnus-art.el (gnus-mime-security-show-details): Goto beginning of
+       buffer.
+
+2000-11-23  Jens Krinke  <j.krinke@gmx.de>
+
+       * smime.el (smime-decrypt-region): Fix keyfile argument.
+
+2000-11-29 00:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnmail.el (nnmail-cache-accepted-message-ids): Add doc.
+
+2000-11-28 17:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-shoot-gnksa-feet): New variable.
+       (message-gnksa-enable-p): New function.
+       (message-send): Use it.
+       (message-check-news-body-syntax): Ditto.
+
+2000-11-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.el (message-make-message-id): Remove the redundancy.
+
+2000-11-22 17:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-setup): Discourage using mc-install-*-mode.
+
+       * gnus-setup.el (gnus-use-mailcrypt): Don't hook mail-crypt.
+
+2000-11-22 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-cite.el (gnus-cite-parse): Guess citation length.
+
+2000-11-22 14:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-ml.el (gnus-mailing-list-insinuate): New function.
+
+2000-11-22 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-ml.el (gnus-mailing-list-archive): Find the real url.
+
+2000-11-22 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-xmas.el (gnus-xmas-article-display-xface): Use
+       insert-buffer-substring.
+
+       * message.el (message-send-mail): Use buffer-substring-no-properties.
+       (message-send-news): Ditto.
+
+2000-11-22  David Edmondson  <dme@dme.org>
+
+       * imap.el (imap-wait-for-tag): Message read info.
+
+2000-11-21 20:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml2015.el (mml2015-mailcrypt-encrypt): Ensure the part is encrypted.
+       (mml2015-mailcrypt-encrypt): Use unibyte-buffer.
+       (mml2015-gpg-encrypt): Ditto.
+
+2000-11-21 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-verify-option): Default value.
+
+       * mml-sec.el (mml-secure-part): Error message.
+
+2000-11-20 18:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-ml.el (gnus-mailing-list-archive): Use browse-url.
+
+2000-11-20 17:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-make-menu-bar): Use easy-menu-add.
+
+2000-11-20 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-describe-key): Use prompt.
+       (gnus-article-describe-key-briefly): Ditto.
+
+2000-11-20 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-agent.el (gnus-agent-expire): Ignore corrupted history.
+
+2000-11-20 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-describe-key): New function.
+       (gnus-article-describe-key-briefly): New function.
+
+2000-11-19 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-decrypt-option): Doc typo.
+
+       * gnus-art.el (gnus-article-read-summary-keys): lookup-key may
+       return a number.
+
+2000-11-19 21:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-newline-and-reformat): Typo.
+
+2000-11-19 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (article-verify-x-pgp-sig): Check whether
+       original-article-buffer exists.
+
+       * rfc2047.el (rfc2047-q-encoding-alist): Match Resent-.
+       (rfc2047-header-encoding-alist): Addresses are different from text.
+       (rfc2047-encode-message-header): Ditto.
+       (rfc2047-dissect-region): Extra parameter.
+       (rfc2047-encode-region): Ditto.
+       (rfc2047-encode-string): Ditto.
+
+2000-11-19 00:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-uu.el (mm-uu-pgp-encrypted-extract-1): New function.
+       (mm-uu-pgp-encrypted-extract): Use it.
+       (mm-uu-pgp-signed-extract-1): New function.
+       (mm-uu-pgp-signed-extract): Use it.
+
+       * gnus-art.el (gnus-mime-display-security): New function.
+       (gnus-mime-display-part): Use it.
+       (gnus-mime-security-verify-or-decrypt): New function.
+       (gnus-mime-security-press-button): New function.
+       (gnus-insert-mime-security-button): Use it.
+
+       * mm-decode.el (mm-possibly-verify-or-decrypt): Use mm-h-m-c-p.
+       (mm-find-raw-part-by-type): Ditto.
+       (mm-verify-function-alist): Add x-gnus-pgp-signature handle.
+       (mm-decrypt-function-alist): Add x-gnus-pgp-encrypted handle.
+       (mm-destroy-parts): Kill nested multibyte buffer.
+
+       * mml2015.el (mml2015-mailcrypt-verify): Use mm-h-m-c-p.
+       (mml2015-gpg-verify): Ditto.
+
+2000-11-18  Simon Josefsson  <sj@extundo.com>
+
+       * mml2015.el (mml2015-mailcrypt-clear-verify): New function.
+       (mml2015-function-alist): Use it.
+
+       * mml-sec.el (mml-sign-alist): Update names.
+       (mml-encrypt-alist): Ditto.
+       (mml-secure-part-smime-sign): Moved to mml-smime.el
+       as `mml-smime-sign-query'.
+       (mml-secure-part-smime-encrypt-by-file): Moved to mml-smime.el as
+       `mml-smime-get-file-cert'.
+       (mml-secure-part-smime-encrypt-by-dns): Moved to mml-smime.el as
+       `mml-smime-get-dns-cert'.
+       (mml-secure-part-smime-encrypt): Moved to mml-smime.el as
+       `mml-smime-encrypt-query'.
+       (mml-smime-sign-buffer): Use mml-smime-sign.
+       (mml-smime-encrypt-buffer): Use mml-smime-encrypt.
+
+       * mml-smime.el (mml-smime-sign): New function.
+       (mml-smime-encrypt):
+       (mml-smime-sign-query):
+       (mml-smime-get-file-cert):
+       (mml-smime-get-dns-cert):
+       (mml-smime-encrypt-query): Moved from mml-sec.el.
+
+2000-11-16  Simon Josefsson  <sj@extundo.com>
+
+       * mml2015.el (mml2015-gpg-clear-verify): New function.
+       (mml2015-function-alist): Add it.
+
+2000-11-17 14:21  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-setup-fill-variables): Use
+       message-cite-prefix-regexp.
+       (message-newline-and-reformat): Check the end of citation, leading
+       WSP, break in the cite prefix.
+       (message-fill-paragraph): New function.
+
+2000-11-17 13:44  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * lpath.el: Shut up.
+
+2000-11-17  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus-msg.el (gnus-group-posting-charset-alist): No longer allow
+       raw 8-bit in headers in dk.* newsgroups.
+
+2000-11-17 08:02  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-newline-and-reformat): Match extra WSPs.
+
+2000-11-16 23:31  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-generate-mime-1): Ignore ascii.
+
+2000-11-16  Justin Sheehy  <justin@iago.org>
+
+       * gnus-sum.el (gnus-summary-make-menu-bar): Fix menu items.
+
+2000-11-16 17:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-cite-prefix-regexp): Prefix should not end
+       at space.
+
+2000-11-15 18:09  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-mode-syntax-table): Add - as a word
+       constituent as in articles.
+       (message-setup-fill-variables): Add -_. as supercite-style prefix.
+       * gnus-art.el (gnus-article-mode-syntax-table): Remove ?-.
+       * gnus-cite.el (gnus-cite-parse): Match from the beginning of line.
+
+2000-11-15 13:21  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-inews-do-gcc): Expire the article.
+
+2000-11-12  David Edmondson  <dme@dme.org>
+
+       * message.el (message-font-lock-keywords): Use
+       message-cite-prefix-regexp.
+
+2000-11-15  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-group.el (gnus-group-jump-to-group-prompt): New variable by
+       Stein Arild Strømme.
+       (gnus-group-jump-to-group): Use it.
+       (gnus-group-jump-to-group-prompt): Customize.
+
+2000-11-14 10:32:42  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mailcap.el (mailcap-possible-viewers): Match the entire string.
+
+2000-11-14 10:20:56  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml2015.el (mml2015-mailcrypt-verify): replace-match is
+       incompatible.
+       (mml2015-mailcrypt-sign): Ditto.
+
+2000-11-14 10:12:05  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-inews-do-gcc): Update summary data when the
+       group is open.
+
+2000-11-14 00:48:52  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-bcklg.el (gnus-backlog-enter-article): Don't enter
+       nnvirtual articles.
+       (gnus-backlog-request-article): Don't request nnvirtual articles.
+
+2000-11-13 22:08:09  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml2015.el (mml2015-mailcrypt-sign): Remove "-" escape.
+       * mml.el (mml-generate-mime-1): Save cont.  Skip multipart attributes.
+
+2000-11-13 20:43:37  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-get-part): Don't call mm-insert-part.
+       * mml.el (mml-generate-mime-1): Use charset attribute.
+       * mm-bodies.el (mm-encode-body): Add parameter charset.
+       * mm-util.el (mm-mime-charset): Show error when find 8-bit characters.
+
+2000-11-13 16:09:09  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml2015.el (mml2015-mailcrypt-decrypt): Handle quit.
+       (mml2015-mailcrypt-clear-decrypt): Ditto.
+       (mml2015-mailcrypt-verify): Ditto.
+       (mml2015-mailcrypt-clear-verify): Ditto.
+       (mml2015-gpg-verify): Ditto.
+
+2000-11-13 15:29:58  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * smime.el (smime-openssl-program): Test the existence of openssl.
+       * mml-smime.el: Require mm-decode.
+       (mml-smime-verify-test): New function.
+       * mm-decode.el (mm-verify-function-alist): Use it.
+
+2000-11-13 09:50:29  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-repair-multipart): Fix Mime-Version
+       anyway.
+
+2000-11-13  Simon Josefsson  <sj@extundo.com>
+
+       * mm-uu.el (mm-uu-pgp-signed-extract): Explain why clear
+       verification doesn't work.
+
+2000-11-12 23:36:45  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-inews-mark-gcc-as-read): New variable.
+       (gnus-inews-do-gcc): Use it.
+
+2000-11-12 21:35:04  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2231.el (rfc2231-encode-string): Insert semi-colon and
+       leading space.
+       * mm-extern.el (mm-inline-external-body): Report error when no
+       access-type.
+
+2000-11-12 19:48:30  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-select-newsgroup): Change the error message.
+
+2000-11-12 11:53:18  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-button-menu): Use select-window.
+
+2000-11-12 09:47:54  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-display-part): Display multipart/related
+       as multipart/mixed.
+
+2000-11-12  David Edmondson  <dme@dme.org>
+
+       * message.el (message-cite-prefix-regexp): Moved from gnus-cite.el
+       and replace `.' with `\w' to allow for different syntax tables
+       (from Vladimir Volovich).
+       * message.el (message-newline-and-reformat): Use
+       `message-cite-prefix-regexp'.
+       * gnus-cite.el (gnus-supercite-regexp): Use
+       `message-cite-prefix-regexp'.
+       * gnus-cite.el (gnus-cite-parse): Use
+       `message-cite-prefix-regexp'.
+
+2000-11-12 08:52:46  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml2015.el (mml2015-mailcrypt-verify): Replace armors with
+       PGP SIGNATURE.  Escape leading "-"'s.
+       (mml2015-mailcrypt-sign): Replace armors with PGP MESSAGE.
+
+2000-11-11 15:55:35  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-uu.el (mm-uu-type-alist): Stricter shar regexp.
+
+2000-11-11  Simon Josefsson  <sj@extundo.com>
+
+       * mml2015.el (mml2015-gpg-verify): Set "OK" security status.
+
+       * smime.el (smime-details-buffer): New variable.
+       (smime-sign-region):
+       (smime-encrypt-region):
+       (smime-verify-region):
+       (smime-decrypt-region): Copy OpenSSL output to the buffer.
+
+       * mml-smime.el (mml-smime-verify): Support security info.
+
+2000-11-10 17:11:22  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-verify-option): Set default to nil.
+       (mm-decrypt-option): Ditto.
+       * gnus-art.el (article-verify-x-pgp-sig): New function.
+
+2000-11-10 09:01:25  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-display-alternative): Show button if no
+       preferred part.
+
+2000-11-07  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus-sum.el (gnus-move-split-methods): Say that
+       `gnus-split-methods' uses file names, whereas this uses group
+       names.  (Report from Nevin Kapur.)
+
+2000-11-10 01:23:20  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-partial.el (mm-inline-partial): Insert MIME-Version.
+
+2000-11-09 17:02:50  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnheader.el (nnheader-directory-files-is-safe): New variable.
+       (nnheader-directory-articles): Use it.
+       (nnheader-article-to-file-alist): Ditto.
+
+2000-11-09 16:20:37  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-pad-base64): New function.
+       (rfc2047-decode): Use it.
+
+2000-11-09 08:53:04  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-srvr.el (gnus-browse-foreign-server): Bind the original
+       select method.
+
+2000-11-08 19:58:58  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml2015.el (mml2015-gpg-decrypt-1):
+       (mml2015-gpg-verify): buffer-string has no argument in Emacs.
+
+2000-11-08 16:37:02  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-cache.el (gnus-cache-generate-nov-databases): Reopen cache.
+
+2000-11-08 08:38:30  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * pop3.el (pop3-munge-message-separator): A message may have an
+       empty body.
+
+2000-11-07 18:02:26  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-uu.el (mm-uu-type-alist): Don't test pgp stuff.
+       (mm-uu-pgp-encrypted-extract): Clean mml2015 buffer.
+       (mm-uu-pgp-signed-extract): Use coding-system.
+
+2000-11-07 14:33:19  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-display-part): Show MIME security button.
+       (gnus-insert-mime-security-button): New function.
+       * mm-decode.el (mm-possibly-verify-or-decrypt): Add security info.
+       * mml2015.el: Add security info when verify or decrypt.
+       * mm-uu.el (mm-uu-pgp-signed-extract): Use multipart.
+       (mm-uu-pgp-encrypted-extract): Ditto.
+
+2000-11-07 08:49:36  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-display-parts): New function.
+       * gnus-art.el (gnus-mime-view-all-parts): Use it.  Remove parts first.
+
+2000-02-02  Alexandre Oliva  <oliva@lsd.ic.unicamp.br>
+
+       * gnus-mlspl.el: Documentation tweaks.
+
+2000-11-06 22:06:44  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-possibly-verify-or-decrypt): Fix.
+       * gnus-art.el (gnus-article-encrypt-body): Rename and support prefix
+       argument.
+
+2000-11-06 19:10:14  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2231.el (rfc2231-encode-string): Use us-ascii if charset is nil.
+
+2000-11-06 18:17:53  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-article-encrypt): New function.
+       (gnus-article-encrypt-protocol-alist): New variable.
+       (gnus-article-encrypt-protocol): New variable.
+       * mml2015.el (mml2015-self-encrypt): New function.
+       (mml2015-mailcrypt-encrypt): Set mc-pgp-always-sign.
+
+2000-11-06 16:02:52  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-uu.el (mm-uu-gpg-key-skip-to-last): New function.
+       (mm-uu-pgp-key-extract): Use application/pgp-keys, don't snarf,
+       let mailcap do it.
+       * mml2015.el: Remove snarf code.
+       * mm-decode.el: Remove snarf code.
+
+2000-11-06 14:03:10  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-insert-mml-markup): Ignore internal stuff.
+       (mml-insert-mime): Understand gnus-decoded.
+       (mime-to-mml): New parameter handles.
+       * gnus-art.el (gnus-mime-save-part-and-strip): Use it.
+       * gnus-sum.el (gnus-summary-edit-article): Add argument `3'.
+
+2000-11-06 13:51:37  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mime-security): New group.
+       (mm-verify-function-alist): Add test function.
+       (mm-decrypt-function-alist): Ditto.
+       (mm-snarf-option): Set default value as nil.
+       (mm-find-part-by-type): Recursive parameter.
+       (mm-possibly-verify-or-decrypt): Support draft-ietf-openpgp-multsig.
+       * mml2015.el: Support draft-ietf-openpgp-multsig.
+
+2000-11-06 13:01:27  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-view-part-as-charset): New function.
+       (gnus-article-view-part-as-charset): New function.
+
+2000-11-05 22:34:07  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-verify-option): Default value.
+       (mm-possibly-verify-or-decrypt): Dealing with broken messages.
+
+2000-11-05 15:06:05  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnvirtual.el (nnvirtual-request-expire-articles): Uncompress range.
+
+2000-11-05  Simon Josefsson  <sj@extundo.com>
+
+       * mml-smime.el (mml-smime-verify): Work in original multipart
+       buffert.
+
+       * mm-decode.el (mm-handle-multipart-original-buffer): New macro.
+       (mm-handle-multipart-ctl-parameter): Ditto.
+       (mm-alist-to-plist): New function.
+       (mm-dissect-buffer): Store CTL parameters and copy original buffer
+       for multiparts.
+       (mm-destroy-parts): Destroy multipart buffert.
+       (mm-remove-part): Ditto.
+
+       * mml-smime.el (mml-smime-sign): Not used.
+       (mml-smime-encrypt): Ditto.
+
+       * mm-decode.el (mml-smime-verify): Autoload mml-smime.
+
+       Verify S/MIME signature support.
+
+       * mm-decode.el (mm-inline-media-tests): Add
+       application/{x-,}pkcs7-signature.
+       (mm-inlined-types): Ditto.
+       (mm-automatic-display): Ditto.
+       (mm-verify-function-alist): Ditto.  Add name of method.
+       (mm-decrypt-function-alist): Add name of method.
+       (mm-find-part-by-type): Add documentation.
+       (mm-possibly-verify-or-decrypt): Use new format of
+       mm-{verify,decrypt}-function-alist.  Use method names.
+
+       * mml-smime.el (mml-smime-verify): New function.
+
+2000-11-04 20:38:50  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-view.el (mm-inline-text): Move point to the end of inserted text.
+
+2000-11-04 19:07:08  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml2015.el (mml2015-function-alist): Clear verify and decrypt.
+       * mm-uu.el: Reorganized.  Add gnatsweb, pgp-signed, pgp-encrypted.
+       * mm-decode.el (mm-snarf-option): New variable.
+
+2000-11-04 13:08:02  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-util.el (mm-subst-char-in-string): New function.
+       (mm-replace-chars-in-string): Use it.
+       * message.el (message-replace-chars-in-string): Use it.
+       * nnheader.el (nnheader-replace-chars-in-string): Use it.
+       * gnus-mh.el (mh-lib-progs): Shut up.
+
+2000-11-04  ShengHuo Zhu  <zsh@cs.rochester.edu>
+
+       * base64.el, md5.el: Moved to contrib directory.
+
+2000-11-04 11:13:56  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-search-article-forward): Don't move
+       the last article when search.
+
+2000-11-04 10:34:29  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnheader.el (nnheader-pathname-coding-system): Default iso-8859-1.
+       * nnmail.el (nnmail-pathname-coding-system): Ditto.
+
+2000-09-29  David Edmondson  <dme@thus.net>
+
+       * message.el (message-newline-and-reformat): Typo.
+
+2000-11-04 10:11:05  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2231.el (rfc2231-decode-encoded-string): Test mm-multibyte-p.
+
+2000-11-04 09:53:42  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nntp.el (nntp-decode-text): Delete bogus status lines.
+
+2000-11-03  Stefan Monnier  <monnier@cs.yale.edu>
+
+       * message.el (message-font-lock-keywords): Match a final newline
+       to help font-lock's multiline support.
+
+2000-11-04 09:11:44  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnoo.el (nnoo-set): New function.
+
+2000-11-04  ShengHuo Zhu  <zsh@cs.rochester.edu>
+
+       * gpg.el, gpg-ring.el: Moved to contrib directory.
+
+2000-11-04  Simon Josefsson  <sj@extundo.com>
+
+       * nnimap.el (nnimap-split-inbox): Typo.
+
+2000-11-03 10:46:44  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-msg.el (gnus-msg-mail): Move it backwards.
+
+2000-11-03  Simon Josefsson  <sj@extundo.com>
+
+       * rfc2231.el (rfc2231-parse-qp-string): New function.
+       (require): rfc2047.
+
+       * mail-parse.el (mail-header-parse-content-type):
+       (mail-header-parse-content-disposition): Support invalid QP
+       encoded strings, by using `rfc2231-parse-qp-string'.
+
+2000-11-03 08:58:08  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2231.el (rfc2231-parse-string): Decode when there is no number.
+       (rfc2231-decode-encoded-string): Typo "> X 1".
+       (rfc2231-encode-string): Insert the name of charset.
+       * mail-parse.el (mail-header-encode-parameter): Use RFC2231.
+
+2000-11-02 23:35:50  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-save-part): Return the filename.
+       * gnus-sum.el (gnus-summary-edit-article): Remove a hack.
+       * gnus-art.el (gnus-mime-save-part-and-strip): New function.
+       (gnus-mime-action-alist): Use it.
+       (gnus-mime-button-commands): Use it.
+       * mm-extern.el (mm-extern-local-file): Error when the file is gone.
+       (mm-inline-external-body): unwind-protect.
+
+2000-11-02 21:08:49  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-insert-mime-button): Show url.
+
+2000-11-02 19:51:19  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-generate-mime-1): Support external url.
+       * nnwarchive.el (nnwarchive-mail-archive-article): Use external url.
+
+2000-11-02 16:53:32  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-partial.el (mm-inline-partial): Buffer name with a leading space.
+       * mm-decode.el (mm-display-external): Ditto.
+       * mm-extern.el: New file.
+       * mm-decode.el (mm-inline-media-tests): Hook it up.
+       (mm-inlined-types): Inline message/external-body.
+
+2000-11-02  Simon Josefsson  <sj@extundo.com>
+
+       * gnus-art.el (gnus-visible-headers): Add Mail-Followup-To.
+
+       * message.el (message-get-reply-headers): Better handling when
+       Mail-Followup-To is very large.
+
+2000-11-02 13:27:56  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-uu.el (gnus-uu-post-news): Comment out the redundancy.
+       * gnus-art.el (gnus-article-edit-done):
+       * gnus-sum.el (gnus-summary-edit-article-done): Move line
+       counting code here.
+       * gnus-msg.el (gnus-setup-message): Remove a hack.
+
+2000-11-02 09:33:01  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-newsgroup-variables): New variable.
+       (gnus-summary-mode): Make them local variables.
+       (gnus-set-global-variables): Globalize them.
+       (gnus-summary-exit): Kill them.
+
+2000-11-02  Hrvoje Niksic  <hniksic@arsdigita.com>
+
+       * rfc2047.el (rfc2047-encoded-word-regexp): Allow empty encoded
+       word.
+
+2000-11-01 10:07:13  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-display-part): Add to signed or encrypted.
+       gnus-article-wash-types.
+       * gnus-art.el (gnus-article-wash-status): Use them.
+
+2000-11-01 08:54:11  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-read-tag): Remove spaces and LF.
+
+2000-11-01 08:01:03  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml2015.el (mml2015-mailcrypt-encrypt): Use from and sign parameters.
+       * mml.el (mml-generate-mime-1): Add sender and recipients attributes.
+
+2000-11-01 07:39:24  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-force-verify-and-decrypt): New function.
+
+2000-10-31 22:06:13  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-article-charset): New variable.
+       (gnus-summary-display-article): Set it.
+       * gnus-msg.el (gnus-copy-article-buffer): Use it.
+       * gnus-art.el (gnus-article-mode): Make it local variable.
+
+2000-11-01 01:12:29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnultimate.el (nnultimate-create-mapping): Use nreverse.
+
+2000-10-31 23:45:31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnwfm.el: New file.
+
+       * nnweb.el (nnweb-replace-in-string): New function.
+
+2000-10-31 17:32:02  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml2015.el: Wrap gpg.el.
+       * gpg.el (gpg-verify): The last argument of apply is a list.
+       (gpg-encrypt): Add passphrase as a parameter.
+
+2000-10-31 17:28:45  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gpg.el: New file.
+       * gpg-ring.el: New file.
+
+2000-10-31 11:44:29  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-sum.el (gnus-summary-show-article): Fix the summary line.
+
+2000-10-31  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-sum.el (gnus-summary-insert-line): Work with quoted
+       double-quote characters.
+       (gnus-summary-prepare-threads): Ditto.
+
+2000-10-31 08:36:03  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-art.el (gnus-mime-display-single): Forward line -1.
+       * mml.el (mml-read-tag): Don't skip the leading space.
+       * lpath.el (font-lock-set-defaults): Shut up.
+
+2000-10-31 00:04:35  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml2015.el: Fix doc.  Remove bogus mml2015-setup.
+
+2000-10-30 23:37:07  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * qp.el (quoted-printable-encode-region): Replace leading - when
+       ultra safe.
+       * mml.el (mml-generate-mime-postprocess-function): Removed.
+       (mml-postprocess-alist): Removed.
+       (mml-generate-mime-1): Use ultra-safe when sign.
+       * mml2015.el (mml2015-fix-micalg): Uppercase.
+       (mml2015-verify): Insert LF.
+       (mml2015-mailcrypt-sign): Downcase; search backward.
+
+2000-10-16 11:36:52  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * nnultimate.el (nnultimate-forum-table-p): Be a bit more
+       restrictive.
+       (nnultimate-table-regexp): New variable.
+       (nnultimate-forum-table-p): Use it.
+
+2000-10-30  Ed L Cashin  <ecashin@coe.uga.edu>  (tiny change)
+
+       * gnus-sum.el (gnus-summary-expire-articles): Save point.
+
+2000-10-30 08:52:50  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml-sec.el (mml-pgpmime-sign-buffer): Use mml2015-sign.
+       (mml-pgpmime-encrypt-buffer): Use mml2015-encrypt.
+
+2000-10-30 08:38:12  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml2015.el: Shut up.
+
+2000-10-30 08:17:46  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.el (gnus-server-browse-hashtb): Removed.
+       * gnus-group.el (gnus-group-prepare-flat-list-dead): Use gnus-active.
+       (gnus-group-insert-group-line-info): Use simplified method.
+       * gnus-srvr.el (gnus-browse-foreign-server): Use gnus-set-active.
+
+2000-10-30 01:52:40  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-util.el (gnus-union): Renamed from gnus-agent-union, and
+       moved here.
+       * gnus-agent.el (gnus-agent-fetch-headers): Use it.
+       * gnus-group.el (gnus-group-prepare-flat): Use it.
+       * gnus-topic.el (gnus-group-prepare-topics): Use it.
+
+2000-10-30 01:23:49  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-mode): Show menu in XEmacs.
+
+2000-10-30 00:49:33  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-srvr.el (gnus-server-browse-in-group-buffer): New variable.
+       (gnus-server-read-server-in-server-buffer): New function.
+       (gnus-browse-foreign-server): Browse in group buffer.
+       * gnus-group.el (gnus-group-prepare-flat): List group not in list.
+       (gnus-group-prepare-flat-list-dead): Use gnus-group-insert-group-line.
+       * gnus-topic.el (gnus-group-prepare-topics): Ditto.
+       * gnus.el (gnus-server-browse-hashtb): New variable.
+
+2000-10-29 22:31:40  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnfolder.el (nnfolder-open-nov): Use group.
+
+2000-10-29 17:23:15  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnfolder.el: Add NOV.  Set version to 2.0.
+       (nnfolder-nov-is-evil): If non-nil, nnfolder acts like 1.0.
+
+2000-10-29 10:35:08  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml2015.el (mml2015-mailcrypt-sign): Use mc-sign-generic.
+
+2000-10-29 09:42:05  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-srvr.el (gnus-browse-foreign-server): Show level mark.
+       (gnus-browse-unsubscribe-group): Unsubscribed is not killed.
+
+2000-10-29 08:28:58  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnfolder.el (nnfolder-read-folder): Don't goto point-min.
+
+2000-10-28 19:11:01  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-verify-function-alist): New variable.
+       (mm-verify-option): New variable.
+       (mm-decrypt-function-alist): Ditto.
+       (mm-decrypt-option): Ditto.
+       (mm-find-raw-part-by-type): New function.
+       (mm-possibly-verify-or-decrypt): New function.
+       (mm-dissect-multipart): Use it.
+       * mml2015.el (mml2015-fix-micalg): New function.
+       (mml2015-decrypt): Use new interface.
+       (mml2015-verify): Use new interface.
+       (mml2015-setup): Make it bogus.
+
+2000-10-28 16:54:45  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml.el (mml-generate-mime-postprocess-function): Set to
+       mml-postprocess.
+       (autoload): Autoload mml2015 and mml-smime.
+       (mml-postprocess-alist): Use mml2015-sign and mml2015-encrypt.
+       * mml2015.el (mml2015-encrypt): New function.
+       (mml2015-sign): New function.
+       (mml2015-encrypt-function): New variable.
+       (mml2015-sign-function): New variable.
+       (mml2015-mailcrypt-encrypt): Use message-recipients.
+       (mml2015-setup): Don't set mml-generate-mime-postprocess-function.
+       * mml-smime.el (mml-smime-setup): Ditto.
+
+2000-10-28  Simon Josefsson  <sj@extundo.com>
+
+       * imap.el (imap-parse-resp-text-code): Workaround bug in Stalker
+       Communigate Pro 3.3.1 server.
+
+       * mml-sec.el (mml-smime-encrypt-buffer): Support certfiles stored
+       in buffers.
+       (mml-secure-dns-server): Removed.
+       (mml-secure-part-smime-encrypt-by-dns): Use DIG interface.  Don't
+       write certificates to files.
+
+       * smime.el (smime-dns-server): New variable.
+       (smime-mail-to-domain):
+       (smime-cert-by-dns): New functions.
+
+       * dig.el: New file.
+
+2000-10-28 10:09:41  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.el (message-options): New variable.
+       (message-options-set-recipient): New function.
+       (message-send): Use them.
+       * gnus-int.el (gnus-request-replace-article): Use them.
+       (gnus-request-accept-article): Ditto.
+       * mml.el (mml-preview): Use them.
+       * gnus-sum.el (gnus-summary-edit-article): Use them.
+
+       * message.el (message-options-get): New function.
+       (message-options-get): New function.
+       * rfc2047.el (rfc2047-encode-message-header): Use them.
+       * mm-bodies.el (mm-encode-body): Use them.
+
+2000-10-28  Simon Josefsson  <sj@extundo.com>
+
+       * nnimap.el (nnimap-retrieve-which-headers):
+       (nnimap-request-article-part): Quote message-id.
+
+       * smime.el (smime-CA-directory): Rename from `smime-CAs'.
+       (smime-CA-file): New variable.
+       (smime-call-openssl-region): Don't error.
+       (smime-sign-region): Return result value.
+       (smime-encrypt-region): Ditto.
+       (smime-verify-region): New function.
+       (smime-decrypt-region): Ditto.
+       (smime-verify-buffer): Ditto.
+       (smime-decrypt-buffer): Ditto.
+
+       * mml.el: Require mml-sec.
+       (mml-generate-mime-1): Support "sign" and "encrypt" MML tags.
+       (mml-mode-map): Add "sign" and "encrypt" maps.
+       (mml-menu): Add security menu.
+       (mml-preview): Use generate-new-buffer.
+
+       * mml-sec.el: New file.
+
+2000-10-28 03:43:03  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mm-decode.el (mm-find-part-by-type): Move it here.
+       * mml.el (mml-postprocess): Move it here.
+       (mml-postprocess-alist): Move it here.  Merge them.
+
+2000-10-28 03:38:39  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * rfc2047.el (rfc2047-encode-message-header): Make sure no
+       unencoded stuff in the header.
+
+2000-10-28 02:40:46  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus-group.el (gnus-group-listed-groups): New variable.
+       (gnus-group-list-option): New variable.
+       (gnus-group-list-limit-map): New keymap.
+       (gnus-group-list-flush-map): New keymap.
+       (gnus-group-list-plus-map): New keymap.
+       (gnus-group-prepare-logic): New function.
+       (gnus-group-prepare-flat): Merge with
+       gnus-group-prepare-flat-predicate.  Use gnus-group-listed-groups.
+       (gnus-group-prepare-flat-list-dead): Ditto.
+       (gnus-group-list-matching): Use gnus-group-prepare-function.
+       (gnus-group-list-dormant): Ditto.
+       (gnus-group-list-cached): Ditto.
+       (gnus-group-listed-groups): New function.
+       (gnus-group-list-limit): New function.
+       (gnus-group-list-flush): New function.
+       (gnus-group-list-plus): New function.
+       * gnus-topic.el (gnus-group-prepare-topics): Accept predicate.
+       (gnus-topic-prepare-topic): Ditto.
+
+2000-10-27  Paul Jarc  <prj@po.cwru.edu>
+
+       * message.el (message-insert-to, message-get-reply-headers):
+       (message-reply, message-followup): Mail-{Followup,Reply}-To.
+
+2000-10-27 19:45:58  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * mml2015.el: New file.
+       * smime.el: New file.
+       * mml-smime.el: New file.
+
+2000-10-27 19:42:12  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * ChangeLog: Moved to ChangeLog.1.
+
+See ChangeLog.1 for earlier changes.
+
+  Copyright (C) 2000-2002, 2004-2016 Free Software Foundation, Inc.
+
+  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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;; Local Variables:
+;; coding: utf-8
+;; End:
diff --git a/xemacs-packages/gnus/lisp/Makefile.in b/xemacs-packages/gnus/lisp/Makefile.in
new file mode 100644 (file)
index 0000000..4dfe2f0
--- /dev/null
@@ -0,0 +1,133 @@
+prefix = @prefix@
+datarootdir = @datarootdir@
+datadir = @datadir@
+lispdir = @lispdir@
+srcdir = @srcdir@
+subdir = lisp
+top_srcdir = @top_srcdir@
+
+EMACS = @EMACS@
+FLAGS = @FLAGS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+SHELL = /bin/sh
+VPATH = @srcdir@
+EMACS_COMP = lispdir="$(lispdir)" srcdir=$(srcdir) $(EMACS) $(FLAGS)
+GZIP_PROG = @GZIP_PROG@
+COMPRESS_INSTALL = @COMPRESS_INSTALL@
+
+all total: clean-some
+       $(MAKE) gnus-load.el
+       $(EMACS_COMP) -f dgnushack-compile
+
+clean-some:
+       rm -f *.elc gnus-load.el auto-autoloads.* custom-load.*
+
+warn: clean-some
+       $(MAKE) 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"
+
+fail-on-warning: clean-some
+       $(MAKE) gnus-load.el
+       $(EMACS_COMP) -f dgnushack-compile-error-on-warn
+
+# The "clever" rule is unsafe, since redefined macros are loaded from
+# .elc files, and not the .el file.
+clever some l: gnus-load.el
+       $(EMACS_COMP) -f dgnushack-compile
+
+install: install-el-elc list-installed-shadows
+
+# Test rules
+check: test-registry test-nntp
+
+test-registry:
+       $(EMACS) $(FLAGS) -l ert -l gnus-registry.el -f ert-run-tests-batch-and-exit
+
+test-nntp:
+       $(EMACS) $(FLAGS) -l ert -l tests/gnustest-nntp.el -f ert-run-tests-batch-and-exit
+
+# This entry will never install .el files if there are no .elc files.
+install-el: gnus-load.el
+       $(SHELL) $(top_srcdir)/mkinstalldirs "$(DESTDIR)$(lispdir)"
+       $(INSTALL_DATA) gnus-load.el "$(DESTDIR)$(lispdir)/gnus-load.el"
+       @for p in *.elc; do \
+         p=`basename $$p c`; \
+         if [ -f "$(srcdir)/$$p" ]; then \
+           echo "$(INSTALL_DATA) $$p \"$(DESTDIR)$(lispdir)/$$p\""; \
+           $(INSTALL_DATA) $(srcdir)/$$p "$(DESTDIR)$(lispdir)/$$p"; \
+           if test $(COMPRESS_INSTALL) = yes -a -n "$(GZIP_PROG)"; then \
+             rm -f "$(DESTDIR)$(lispdir)/$$p.gz"; \
+             $(GZIP_PROG) -9n "$(DESTDIR)$(lispdir)/$$p"; \
+           fi; \
+         fi; \
+       done
+
+install-elc: clever
+       rm -f dgnushack.elc
+       $(SHELL) $(top_srcdir)/mkinstalldirs "$(DESTDIR)$(lispdir)"
+       @for p in *.elc; do \
+         echo "$(INSTALL_DATA) $$p \"$(DESTDIR)$(lispdir)/$$p\""; \
+         $(INSTALL_DATA) $$p "$(DESTDIR)$(lispdir)/$$p"; \
+       done
+
+install-el-elc: clever
+       rm -f dgnushack.elc
+       $(SHELL) $(top_srcdir)/mkinstalldirs "$(DESTDIR)$(lispdir)"
+       $(INSTALL_DATA) gnus-load.el "$(DESTDIR)$(lispdir)/gnus-load.el"
+       @for p in *.elc; do \
+         q=`basename $$p c`; \
+         if [ -f "$(srcdir)/$$q" ]; then \
+           echo "$(INSTALL_DATA) $$q \"$(DESTDIR)$(lispdir)/$$q\""; \
+           $(INSTALL_DATA) $(srcdir)/$$q "$(DESTDIR)$(lispdir)/$$q"; \
+           if test $(COMPRESS_INSTALL) = yes -a -n "$(GZIP_PROG)"; then \
+             rm -f "$(DESTDIR)$(lispdir)/$$q.gz"; \
+             $(GZIP_PROG) -9n "$(DESTDIR)$(lispdir)/$$q"; \
+           fi; \
+         fi; \
+         echo "$(INSTALL_DATA) $$p \"$(DESTDIR)$(lispdir)/$$p\""; \
+         $(INSTALL_DATA) $$p "$(DESTDIR)$(lispdir)/$$p"; \
+       done
+
+list-installed-shadows:
+       $(EMACS_COMP) -f dgnushack-find-lisp-shadows
+
+remove-installed-shadows:
+       $(EMACS_COMP) -f dgnushack-remove-lisp-shadows
+
+uninstall:
+       for p in *.elc; do \
+         rm -f "$(DESTDIR)$(lispdir)/$$p"; \
+       done
+       cd $(srcdir); \
+       for p in *.el; do \
+         rm -f "$(DESTDIR)$(lispdir)/$$p" "$(DESTDIR)$(lispdir)/$$p.gz"; \
+       done
+
+tags:
+       etags *.el
+
+separately:
+       rm -f *.elc ; for i in *.el; do $(EMACS) $(FLAGS) -f batch-byte-compile $$i; done
+
+pot:
+       xpot -drgnus -r`cat ./version` *.el > rgnus.pot
+
+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
+
+clean:
+       rm -f *.elc *.orig *.rej *~ auto-autoloads.* custom-load.* gnus-load.el
+
+distclean: clean
+       rm -f Makefile
+
+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/xemacs-packages/gnus/lisp/assistant.el b/xemacs-packages/gnus/lisp/assistant.el
new file mode 100644 (file)
index 0000000..93d7219
--- /dev/null
@@ -0,0 +1,482 @@
+;;; assistant.el --- guiding users through Emacs setup
+;; Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: util
+
+;; 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 3, 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.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile
+  (require 'cl))
+
+(require 'widget)
+(require 'wid-edit)
+
+(autoload 'gnus-error "gnus-util")
+(autoload 'netrc-get "netrc")
+(autoload 'netrc-machine "netrc")
+(autoload 'netrc-parse "netrc")
+
+(defvar assistant-readers
+  '(("variable" assistant-variable-reader)
+    ("validate" assistant-sexp-reader)
+    ("result" assistant-list-reader)
+    ("next" assistant-list-reader)
+    ("text" assistant-text-reader)))
+
+(defface assistant-field '((t (:bold t)))
+  "Face used for editable fields."
+  :group 'gnus-article-emphasis)
+;; backward-compatibility alias
+(put 'assistant-field-face 'face-alias 'assistant-field)
+
+;;; Internal variables
+
+(defvar assistant-data nil)
+(defvar assistant-current-node nil)
+(defvar assistant-previous-nodes nil)
+(defvar assistant-widgets nil)
+
+(defun assistant-parse-buffer ()
+  (let (results command value)
+    (goto-char (point-min))
+    (while (search-forward "@" nil t)
+      (if (not (looking-at "[^ \t\n]+"))
+         (error "Dangling @")
+       (setq command (downcase (match-string 0)))
+       (goto-char (match-end 0)))
+      (setq value
+           (if (looking-at "[ \t]*\n")
+               (let (start)
+                 (forward-line 1)
+                 (setq start (point))
+                 (unless (re-search-forward (concat "^@end " command) nil t)
+                   (error "No @end %s found" command))
+                 (beginning-of-line)
+                 (prog1
+                     (buffer-substring start (point))
+                   (forward-line 1)))
+             (skip-chars-forward " \t")
+             (prog1
+                 (buffer-substring (point) (point-at-eol))
+               (forward-line 1))))
+      (push (list command (assistant-reader command value))
+           results))
+    (assistant-segment (nreverse results))))
+
+(defun assistant-text-reader (text)
+  (with-temp-buffer
+    (insert text)
+    (goto-char (point-min))
+    (let ((start (point))
+         (sections nil))
+      (while (re-search-forward "@\\([^{]+\\){\\([^}]+\\)}" nil t)
+       (push (buffer-substring start (match-beginning 0))
+             sections)
+       (push (list (match-string 1) (match-string 2))
+             sections)
+       (setq start (point)))
+      (push (buffer-substring start (point-max))
+           sections)
+      (nreverse sections))))
+
+;; Segment the raw assistant data into a list of nodes.
+(defun assistant-segment (list)
+  (let ((ast nil)
+       (node nil)
+       (title (pop list)))
+    (dolist (elem list)
+      (when (and (equal (car elem) "node")
+                node)
+       (push (list "save" nil) node)
+       (push (nreverse node) ast)
+       (setq node nil))
+      (push elem node))
+    (when node
+      (push (list "save" nil) node)
+      (push (nreverse node) ast))
+    (cons title (nreverse ast))))
+
+(defun assistant-reader (command value)
+  (let ((formatter (cadr (assoc command assistant-readers))))
+    (if (not formatter)
+       value
+      (funcall formatter value))))
+
+(defun assistant-list-reader (value)
+  (car (read-from-string (concat "(" value ")"))))
+
+(defun assistant-variable-reader (value)
+  (let ((section (car (read-from-string (concat "(" value ")")))))
+    (append section (list 'default))))
+
+(defun assistant-sexp-reader (value)
+  (if (zerop (length value))
+      nil
+    (car (read-from-string value))))
+
+(defun assistant-buffer-name (title)
+  (format "*Assistant %s*" title))
+
+(defun assistant-get (ast command)
+  (cadr (assoc command ast)))
+
+(defun assistant-set (ast command value)
+  (let ((elem (assoc command ast)))
+    (when elem
+      (setcar (cdr elem) value))))
+
+(defun assistant-get-list (ast command)
+  (let ((result nil))
+    (dolist (elem ast)
+      (when (equal (car elem) command)
+       (push elem result)))
+    (nreverse result)))
+
+;;;###autoload
+(defun assistant (file)
+  "Assist setting up Emacs based on FILE."
+  (interactive "fAssistant file name: ")
+  (let ((ast
+        (with-temp-buffer
+          (insert-file-contents file)
+          (assistant-parse-buffer))))
+    (pop-to-buffer (assistant-buffer-name (assistant-get ast "title")))
+    (assistant-render ast)))
+
+(defun assistant-render (ast)
+  (let ((first-node (assistant-get (nth 1 ast) "node")))
+    (set (make-local-variable 'assistant-data) ast)
+    (set (make-local-variable 'assistant-current-node) nil)
+    (set (make-local-variable 'assistant-previous-nodes) nil)
+    (assistant-render-node first-node)))
+
+(defun assistant-find-node (node-name)
+  (let ((ast (cdr assistant-data)))
+    (while (and ast
+               (not (string= node-name (assistant-get (car ast) "node"))))
+      (pop ast))
+    (car ast)))
+
+(defun assistant-node-name (node)
+  (assistant-get node "node"))
+
+(defun assistant-previous-node-text (node)
+  (format "<< Go back to %s" node))
+
+(defun assistant-next-node-text (node)
+  (if (and node
+          (not (eq node 'finish)))
+      (format "Proceed to %s >>" node)
+    "Finish"))
+
+(defun assistant-set-defaults (node &optional forcep)
+  (dolist (variable (assistant-get-list node "variable"))
+    (setq variable (cadr variable))
+    (when (or (eq (nth 3 variable) 'default)
+             forcep)
+      (setcar (nthcdr 3 variable)
+             (assistant-eval (nth 2 variable))))))
+
+(defun assistant-get-variable (node variable &optional type raw)
+  (let ((variables (assistant-get-list node "variable"))
+       (result nil)
+       elem)
+    (while (and (setq elem (pop variables))
+               (not result))
+      (setq elem (cadr elem))
+      (when (eq (intern variable) (car elem))
+       (if type
+           (setq result (nth 1 elem))
+         (setq result (if raw (nth 3 elem)
+                        (format "%s" (nth 3 elem)))))))
+    result))
+
+(defun assistant-set-variable (node variable value)
+  (let ((variables (assistant-get-list node "variable"))
+       elem)
+    (while (setq elem (pop variables))
+      (setq elem (cadr elem))
+      (when (eq (intern variable) (car elem))
+       (setcar (nthcdr 3 elem) value)))))
+
+(defun assistant-render-text (text node)
+  (unless (and text node)
+    (gnus-error
+     5
+     "The assistant was asked to render invalid text or node data"))
+  (dolist (elem text)
+    (if (stringp elem)
+       ;; Ordinary text
+       (insert elem)
+      ;; A variable to be inserted as a widget.
+      (let* ((start (point))
+            (variable (cadr elem))
+            (type (assistant-get-variable node variable 'type)))
+       (cond
+        ((eq (car-safe type) :radio)
+         (push
+          (apply
+           #'widget-create
+           'radio-button-choice
+           :assistant-variable variable
+           :assistant-node node
+           :value (assistant-get-variable node variable)
+           :notify (lambda (widget &rest ignore)
+                     (assistant-set-variable
+                      (widget-get widget :assistant-node)
+                      (widget-get widget :assistant-variable)
+                      (widget-value widget))
+                     (assistant-render-node
+                      (assistant-get
+                       (widget-get widget :assistant-node)
+                       "node")))
+           (cadr type))
+          assistant-widgets))
+        ((eq (car-safe type) :set)
+         (push
+          (apply
+           #'widget-create
+           'set
+           :assistant-variable variable
+           :assistant-node node
+           :value (assistant-get-variable node variable nil t)
+           :notify (lambda (widget &rest ignore)
+                     (assistant-set-variable
+                      (widget-get widget :assistant-node)
+                      (widget-get widget :assistant-variable)
+                      (widget-value widget))
+                     (assistant-render-node
+                      (assistant-get
+                       (widget-get widget :assistant-node)
+                       "node")))
+           (cadr type))
+          assistant-widgets))
+        (t
+         (push
+          (widget-create
+           'editable-field
+           :value-face 'assistant-field
+           :assistant-variable variable
+           (assistant-get-variable node variable))
+          assistant-widgets)
+         (add-text-properties start (point)
+                              (list
+                               'bold t
+                               'face 'assistant-field
+                               'not-read-only t)))))))
+  (widget-setup))
+
+(defun assistant-render-node (node-name)
+  (let ((node (assistant-find-node node-name))
+       (inhibit-read-only t)
+       (previous assistant-current-node)
+       (buffer-read-only nil))
+    (unless node
+      (gnus-error 5 "The node for %s could not be found" node-name))
+    (set (make-local-variable 'assistant-widgets) nil)
+    (assistant-set-defaults node)
+    (if (equal (assistant-get node "type") "interstitial")
+       (assistant-render-node (nth 0 (assistant-find-next-nodes node-name)))
+      (setq assistant-current-node node-name)
+      (when previous
+       (push previous assistant-previous-nodes))
+      (erase-buffer)
+      (insert (cadar assistant-data) "\n\n")
+      (insert node-name "\n\n")
+      (assistant-render-text (assistant-get node "text") node)
+      (insert "\n\n")
+      (when assistant-previous-nodes
+       (assistant-node-button 'previous (car assistant-previous-nodes)))
+      (widget-create
+       'push-button
+       :assistant-node node-name
+       :notify (lambda (widget &rest ignore)
+                (let* ((node (widget-get widget :assistant-node)))
+                  (assistant-set-defaults (assistant-find-node node) 'force)
+                  (assistant-render-node node)))
+       "Reset")
+      (insert "\n")
+      (dolist (nnode (assistant-find-next-nodes))
+       (assistant-node-button 'next nnode)
+       (insert "\n"))
+
+      (goto-char (point-min))
+      (assistant-make-read-only))))
+
+(defun assistant-make-read-only ()
+  (let ((start (point-min))
+       end)
+    (while (setq end (text-property-any start (point-max) 'not-read-only t))
+      (put-text-property start end 'read-only t)
+      (put-text-property start end 'rear-nonsticky t)
+      (while (get-text-property end 'not-read-only)
+       (incf end))
+      (setq start end))
+    (put-text-property start (point-max) 'read-only t)))
+
+(defun assistant-node-button (type node)
+  (let ((text (if (eq type 'next)
+                 (assistant-next-node-text node)
+               (assistant-previous-node-text node))))
+    (widget-create
+     'push-button
+     :assistant-node node
+     :assistant-type type
+     :notify (lambda (widget &rest ignore)
+              (let* ((node (widget-get widget :assistant-node))
+                     (type (widget-get widget :assistant-type)))
+                (if (eq type 'previous)
+                    (progn
+                      (setq assistant-current-node nil)
+                      (pop assistant-previous-nodes))
+                  (assistant-get-widget-values)
+                  (assistant-validate))
+                (if (null node)
+                    (assistant-finish)
+                  (assistant-render-node node))))
+     text)
+    (use-local-map widget-keymap)))
+
+(defun assistant-validate-types (node)
+  (dolist (variable (assistant-get-list node "variable"))
+    (setq variable (cadr variable))
+    (let ((type (nth 1 variable))
+         (value (nth 3 variable)))
+      (when
+         (cond
+          ((eq type :number)
+           (string-match "[^0-9]" value))
+          (t
+           nil))
+       (error "%s is not of type %s: %s"
+              (car variable) type value)))))
+
+(defun assistant-get-widget-values ()
+  (let ((node (assistant-find-node assistant-current-node)))
+    (dolist (widget assistant-widgets)
+      (assistant-set-variable
+       node (widget-get widget :assistant-variable)
+       (widget-value widget)))))
+
+(defun assistant-validate ()
+  (let* ((node (assistant-find-node assistant-current-node))
+        (validation (assistant-get node "validate"))
+        result)
+    (assistant-validate-types node)
+    (when validation
+      (when (setq result (assistant-eval validation))
+       (unless (y-or-n-p (format "Error: %s.  Continue? " result))
+         (error "%s" result))))
+    (assistant-set node "save" t)))
+
+;; (defun assistant-find-next-node (&optional node)
+;;   (let* ((node (assistant-find-node (or node assistant-current-node)))
+;;      (node-name (assistant-node-name node))
+;;      (nexts (assistant-get-list node "next"))
+;;      next elem applicable)
+
+;;     (while (setq elem (pop nexts))
+;;       (when (assistant-eval (car (cadr elem)))
+;;     (setq applicable (cons elem applicable))))
+
+;;     ;; return the first thing we can
+;;     (cadr (cadr (pop applicable)))))
+
+(defun assistant-find-next-nodes (&optional node)
+  (let* ((node (assistant-find-node (or node assistant-current-node)))
+        (nexts (assistant-get-list node "next"))
+        next elem applicable return)
+
+    (while (setq elem (pop nexts))
+      (when (assistant-eval (car (cadr elem)))
+       (setq applicable (cons elem applicable))))
+
+    ;; return the first thing we can
+
+    (while (setq elem (pop applicable))
+      (push (cadr (cadr elem)) return))
+
+    return))
+
+(defun assistant-get-all-variables ()
+  (let ((variables nil))
+    (dolist (node (cdr assistant-data))
+      (setq variables
+           (append (assistant-get-list node "variable")
+                   variables)))
+    variables))
+
+(defun assistant-eval (form)
+  (let ((bindings nil))
+    (dolist (variable (assistant-get-all-variables))
+      (setq variable (cadr variable))
+      (push (list (car variable)
+                 (if (eq (nth 3 variable) 'default)
+                     nil
+                   (if (listp (nth 3 variable))
+                       `(list ,@(nth 3 variable))
+                     (nth 3 variable))))
+           bindings))
+    (eval
+     `(let ,bindings
+       ,form))))
+
+(defun assistant-finish ()
+  (let ((results nil)
+       result)
+    (dolist (node (cdr assistant-data))
+      (when (assistant-get node "save")
+       (setq result (assistant-get node "result"))
+       (push (list (car result)
+                   (assistant-eval (cadr result)))
+             results)))
+    (message "Results: %s"
+            (nreverse results))))
+
+;;; Validation functions.
+
+(defun assistant-validate-connect-to-server (server port)
+  (let* ((error nil)
+        (stream
+         (condition-case err
+             (open-network-stream "nntpd" nil server port)
+           (error (setq error err)))))
+    (if (and (processp stream)
+            (memq (process-status stream) '(open run)))
+       (progn
+         (delete-process stream)
+         nil)
+      error)))
+
+(defun assistant-authinfo-data (server port type)
+  (when (file-exists-p "~/.authinfo")
+    (netrc-get (netrc-machine (netrc-parse "~/.authinfo")
+                             server port)
+              (if (eq type 'user)
+                  "login"
+                "password"))))
+
+(defun assistant-password-required-p ()
+  nil)
+
+(provide 'assistant)
+
+;;; assistant.el ends here
diff --git a/xemacs-packages/gnus/lisp/auth-source.el b/xemacs-packages/gnus/lisp/auth-source.el
new file mode 100644 (file)
index 0000000..30b36c7
--- /dev/null
@@ -0,0 +1,2147 @@
+;;; auth-source.el --- authentication sources for Gnus and Emacs
+
+;; Copyright (C) 2008-2016 Free Software Foundation, Inc.
+
+;; Author: Ted Zlatanov <tzz@lifelogs.com>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This is the auth-source.el package.  It lets users tell Gnus how to
+;; authenticate in a single place.  Simplicity is the goal.  Instead
+;; of providing 5000 options, we'll stick to simple, easy to
+;; understand options.
+
+;; See the auth.info Info documentation for details.
+
+;; TODO:
+
+;; - never decode the backend file unless it's necessary
+;; - a more generic way to match backends and search backend contents
+;; - absorb netrc.el and simplify it
+;; - protect passwords better
+;; - allow creating and changing netrc lines (not files) e.g. change a password
+
+;;; Code:
+
+(require 'password-cache)
+(require 'mm-util)
+(require 'gnus-util)
+
+(eval-when-compile (require 'cl))
+(eval-and-compile
+  (or (ignore-errors (require 'eieio))
+      ;; gnus-fallback-lib/ from gnus/lisp/gnus-fallback-lib
+      (ignore-errors
+        (let ((load-path (cons (expand-file-name
+                                "gnus-fallback-lib/eieio"
+                                (file-name-directory (locate-library "gnus")))
+                               load-path)))
+          (require 'eieio)))
+      (error
+       "eieio not found in `load-path' or gnus-fallback-lib/ directory.")))
+
+(autoload 'secrets-create-item "secrets")
+(autoload 'secrets-delete-item "secrets")
+(autoload 'secrets-get-alias "secrets")
+(autoload 'secrets-get-attributes "secrets")
+(autoload 'secrets-get-secret "secrets")
+(autoload 'secrets-list-collections "secrets")
+(autoload 'secrets-search-items "secrets")
+
+(autoload 'rfc2104-hash "rfc2104")
+
+(autoload 'plstore-open "plstore")
+(autoload 'plstore-find "plstore")
+(autoload 'plstore-put "plstore")
+(autoload 'plstore-delete "plstore")
+(autoload 'plstore-save "plstore")
+(autoload 'plstore-get-file "plstore")
+
+(autoload 'epg-make-context "epg")
+(autoload 'epg-context-set-passphrase-callback "epg")
+(autoload 'epg-decrypt-string "epg")
+(autoload 'epg-encrypt-string "epg")
+(autoload 'epg-context-set-armor "epg")
+
+(autoload 'help-mode "help-mode" nil t)
+
+(defvar secrets-enabled)
+
+(defgroup auth-source nil
+  "Authentication sources."
+  :version "23.1" ;; No Gnus
+  :group 'gnus)
+
+;;;###autoload
+(defcustom auth-source-cache-expiry 7200
+  "How many seconds passwords are cached, or nil to disable
+expiring.  Overrides `password-cache-expiry' through a
+let-binding."
+  :version "24.1"
+  :group 'auth-source
+  :type '(choice (const :tag "Never" nil)
+                 (const :tag "All Day" 86400)
+                 (const :tag "2 Hours" 7200)
+                 (const :tag "30 Minutes" 1800)
+                 (integer :tag "Seconds")))
+
+;; The slots below correspond with the `auth-source-search' spec,
+;; so a backend with :host set, for instance, would match only
+;; searches for that host.  Normally they are nil.
+(defclass auth-source-backend ()
+  ((type :initarg :type
+         :initform 'netrc
+         :type symbol
+         :custom symbol
+         :documentation "The backend type.")
+   (source :initarg :source
+           :type string
+           :custom string
+           :documentation "The backend source.")
+   (host :initarg :host
+         :initform t
+         :type t
+         :custom string
+         :documentation "The backend host.")
+   (user :initarg :user
+         :initform t
+         :type t
+         :custom string
+         :documentation "The backend user.")
+   (port :initarg :port
+         :initform t
+         :type t
+         :custom string
+         :documentation "The backend protocol.")
+   (data :initarg :data
+         :initform nil
+         :documentation "Internal backend data.")
+   (create-function :initarg :create-function
+                    :initform ignore
+                    :type function
+                    :custom function
+                    :documentation "The create function.")
+   (search-function :initarg :search-function
+                    :initform ignore
+                    :type function
+                    :custom function
+                    :documentation "The search function.")))
+
+(defcustom auth-source-protocols '((imap "imap" "imaps" "143" "993")
+                                   (pop3 "pop3" "pop" "pop3s" "110" "995")
+                                   (ssh  "ssh" "22")
+                                   (sftp "sftp" "115")
+                                   (smtp "smtp" "25"))
+  "List of authentication protocols and their names"
+
+  :group 'auth-source
+  :version "23.2" ;; No Gnus
+  :type '(repeat :tag "Authentication Protocols"
+                 (cons :tag "Protocol Entry"
+                       (symbol :tag "Protocol")
+                       (repeat :tag "Names"
+                               (string :tag "Name")))))
+
+;; Generate all the protocols in a format Customize can use.
+;; TODO: generate on the fly from auth-source-protocols
+(defconst auth-source-protocols-customize
+  (mapcar (lambda (a)
+            (let ((p (car-safe a)))
+              (list 'const
+                    :tag (upcase (symbol-name p))
+                    p)))
+          auth-source-protocols))
+
+(defvar auth-source-creation-defaults nil
+  ;; FIXME: AFAICT this is not set (or let-bound) anywhere!
+  "Defaults for creating token values.  Usually let-bound.")
+
+(defvar auth-source-creation-prompts nil
+  "Default prompts for token values.  Usually let-bound.")
+
+(make-obsolete 'auth-source-hide-passwords nil "Emacs 24.1")
+
+(defcustom auth-source-save-behavior 'ask
+  "If set, auth-source will respect it for save behavior."
+  :group 'auth-source
+  :version "23.2" ;; No Gnus
+  :type `(choice
+          :tag "auth-source new token save behavior"
+          (const :tag "Always save" t)
+          (const :tag "Never save" nil)
+          (const :tag "Ask" ask)))
+
+;; TODO: make the default (setq auth-source-netrc-use-gpg-tokens `((,(if (boundp 'epa-file-auto-mode-alist-entry) (car epa-file-auto-mode-alist-entry) "\\.gpg\\'") never) (t gpg)))
+;; TODO: or maybe leave as (setq auth-source-netrc-use-gpg-tokens 'never)
+
+(defcustom auth-source-netrc-use-gpg-tokens 'never
+  "Set this to tell auth-source when to create GPG password
+tokens in netrc files.  It's either an alist or `never'.
+Note that if EPA/EPG is not available, this should NOT be used."
+  :group 'auth-source
+  :version "23.2" ;; No Gnus
+  :type `(choice
+          (const :tag "Always use GPG password tokens" (t gpg))
+          (const :tag "Never use GPG password tokens" never)
+          (repeat :tag "Use a lookup list"
+                  (list
+                   (choice :tag "Matcher"
+                           (const :tag "Match anything" t)
+                           (const :tag "The EPA encrypted file extensions"
+                                  ,(if (boundp 'epa-file-auto-mode-alist-entry)
+                                       (car epa-file-auto-mode-alist-entry)
+                                     "\\.gpg\\'"))
+                           (regexp :tag "Regular expression"))
+                   (choice :tag "What to do"
+                           (const :tag "Save GPG-encrypted password tokens" gpg)
+                           (const :tag "Don't encrypt tokens" never))))))
+
+(defvar auth-source-magic "auth-source-magic ")
+
+(defcustom auth-source-do-cache t
+  "Whether auth-source should cache information with `password-cache'."
+  :group 'auth-source
+  :version "23.2" ;; No Gnus
+  :type `boolean)
+
+(defcustom auth-source-debug nil
+  "Whether auth-source should log debug messages.
+
+If the value is nil, debug messages are not logged.
+
+If the value is t, debug messages are logged with `message'.  In
+that case, your authentication data will be in the clear (except
+for passwords).
+
+If the value is a function, debug messages are logged by calling
+ that function using the same arguments as `message'."
+  :group 'auth-source
+  :version "23.2" ;; No Gnus
+  :type `(choice
+          :tag "auth-source debugging mode"
+          (const :tag "Log using `message' to the *Messages* buffer" t)
+          (const :tag "Log all trivia with `message' to the *Messages* buffer"
+                 trivia)
+          (function :tag "Function that takes arguments like `message'")
+          (const :tag "Don't log anything" nil)))
+
+(defcustom auth-sources '("~/.authinfo" "~/.authinfo.gpg" "~/.netrc")
+  "List of authentication sources.
+Each entry is the authentication type with optional properties.
+Entries are tried in the order in which they appear.
+See Info node `(auth)Help for users' for details.
+
+If an entry names a file with the \".gpg\" extension and you have
+EPA/EPG set up, the file will be encrypted and decrypted
+automatically.  See Info node `(epa)Encrypting/decrypting gpg files'
+for details.
+
+It's best to customize this with `\\[customize-variable]' because the choices
+can get pretty complex."
+  :group 'auth-source
+  :version "24.1" ;; No Gnus
+  :type `(repeat :tag "Authentication Sources"
+                 (choice
+                  (string :tag "Just a file")
+                  (const :tag "Default Secrets API Collection" default)
+                  (const :tag "Login Secrets API Collection" "secrets:Login")
+                  (const :tag "Temp Secrets API Collection" "secrets:session")
+
+                  (const :tag "Default internet Mac OS Keychain"
+                         macos-keychain-internet)
+
+                  (const :tag "Default generic Mac OS Keychain"
+                         macos-keychain-generic)
+
+                  (list :tag "Source definition"
+                        (const :format "" :value :source)
+                        (choice :tag "Authentication backend choice"
+                                (string :tag "Authentication Source (file)")
+                                (list
+                                 :tag "Secret Service API/KWallet/GNOME Keyring"
+                                 (const :format "" :value :secrets)
+                                 (choice :tag "Collection to use"
+                                         (string :tag "Collection name")
+                                         (const :tag "Default" default)
+                                         (const :tag "Login" "Login")
+                                         (const
+                                          :tag "Temporary" "session")))
+                                (list
+                                 :tag "Mac OS internet Keychain"
+                                 (const :format ""
+                                        :value :macos-keychain-internet)
+                                 (choice :tag "Collection to use"
+                                         (string :tag "internet Keychain path")
+                                         (const :tag "default" default)))
+                                (list
+                                 :tag "Mac OS generic Keychain"
+                                 (const :format ""
+                                        :value :macos-keychain-generic)
+                                 (choice :tag "Collection to use"
+                                         (string :tag "generic Keychain path")
+                                         (const :tag "default" default))))
+                        (repeat :tag "Extra Parameters" :inline t
+                                (choice :tag "Extra parameter"
+                                        (list
+                                         :tag "Host"
+                                         (const :format "" :value :host)
+                                         (choice :tag "Host (machine) choice"
+                                                 (const :tag "Any" t)
+                                                 (regexp
+                                                  :tag "Regular expression")))
+                                        (list
+                                         :tag "Protocol"
+                                         (const :format "" :value :port)
+                                         (choice
+                                          :tag "Protocol"
+                                          (const :tag "Any" t)
+                                          ,@auth-source-protocols-customize))
+                                        (list :tag "User" :inline t
+                                              (const :format "" :value :user)
+                                              (choice
+                                               :tag "Personality/Username"
+                                               (const :tag "Any" t)
+                                               (string
+                                                :tag "Name")))))))))
+
+(defcustom auth-source-gpg-encrypt-to t
+  "List of recipient keys that `authinfo.gpg' encrypted to.
+If the value is not a list, symmetric encryption will be used."
+  :group 'auth-source
+  :version "24.1" ;; No Gnus
+  :type '(choice (const :tag "Symmetric encryption" t)
+                 (repeat :tag "Recipient public keys"
+                         (string :tag "Recipient public key"))))
+
+;; temp for debugging
+;; (unintern 'auth-source-protocols)
+;; (unintern 'auth-sources)
+;; (customize-variable 'auth-sources)
+;; (setq auth-sources nil)
+;; (format "%S" auth-sources)
+;; (customize-variable 'auth-source-protocols)
+;; (setq auth-source-protocols nil)
+;; (format "%S" auth-source-protocols)
+;; (auth-source-pick nil :host "a" :port 'imap)
+;; (auth-source-user-or-password "login" "imap.myhost.com" 'imap)
+;; (auth-source-user-or-password "password" "imap.myhost.com" 'imap)
+;; (auth-source-user-or-password-imap "login" "imap.myhost.com")
+;; (auth-source-user-or-password-imap "password" "imap.myhost.com")
+;; (auth-source-protocol-defaults 'imap)
+
+;; (let ((auth-source-debug 'debug)) (auth-source-do-debug "hello"))
+;; (let ((auth-source-debug t)) (auth-source-do-debug "hello"))
+;; (let ((auth-source-debug nil)) (auth-source-do-debug "hello"))
+(defun auth-source-do-debug (&rest msg)
+  (when auth-source-debug
+    (apply #'auth-source-do-warn msg)))
+
+(defun auth-source-do-trivia (&rest msg)
+  (when (or (eq auth-source-debug 'trivia)
+            (functionp auth-source-debug))
+    (apply #'auth-source-do-warn msg)))
+
+(defun auth-source-do-warn (&rest msg)
+  (apply
+   ;; set logger to either the function in auth-source-debug or 'message
+   ;; note that it will be 'message if auth-source-debug is nil
+   (if (functionp auth-source-debug)
+       auth-source-debug
+     'message)
+   msg))
+
+
+;; (auth-source-read-char-choice "enter choice? " '(?a ?b ?q))
+(defun auth-source-read-char-choice (prompt choices)
+  "Read one of CHOICES by `read-char-choice', or `read-char'.
+`dropdown-list' support is disabled because it doesn't work reliably.
+Only one of CHOICES will be returned.  The PROMPT is augmented
+with \"[a/b/c] \" if CHOICES is \(?a ?b ?c)."
+  (when choices
+    (let* ((prompt-choices
+            (apply #'concat (loop for c in choices
+                                 collect (format "%c/" c))))
+           (prompt-choices (concat "[" (substring prompt-choices 0 -1) "] "))
+           (full-prompt (concat prompt prompt-choices))
+           k)
+
+      (while (not (memq k choices))
+        (setq k (cond
+                 ((fboundp 'read-char-choice)
+                  (read-char-choice full-prompt choices))
+                 (t (message "%s" full-prompt)
+                    (setq k (read-char))))))
+      k)))
+
+;; (auth-source-pick nil :host "any" :port 'imap :user "joe")
+;; (auth-source-pick t :host "any" :port 'imap :user "joe")
+;; (setq auth-sources '((:source (:secrets default) :host t :port t :user "joe")
+;;                   (:source (:secrets "session") :host t :port t :user "joe")
+;;                   (:source (:secrets "Login") :host t :port t)
+;;                   (:source "~/.authinfo.gpg" :host t :port t)))
+
+;; (setq auth-sources '((:source (:secrets default) :host t :port t :user "joe")
+;;                   (:source (:secrets "session") :host t :port t :user "joe")
+;;                   (:source (:secrets "Login") :host t :port t)
+;;                   ))
+
+;; (setq auth-sources '((:source "~/.authinfo.gpg" :host t :port t)))
+
+;; (auth-source-backend-parse "myfile.gpg")
+;; (auth-source-backend-parse 'default)
+;; (auth-source-backend-parse "secrets:Login")
+;; (auth-source-backend-parse 'macos-keychain-internet)
+;; (auth-source-backend-parse 'macos-keychain-generic)
+;; (auth-source-backend-parse "macos-keychain-internet:/path/here.keychain")
+;; (auth-source-backend-parse "macos-keychain-generic:/path/here.keychain")
+
+(defun auth-source-backend-parse (entry)
+  "Creates an auth-source-backend from an ENTRY in `auth-sources'."
+  (auth-source-backend-parse-parameters
+   entry
+   (cond
+    ;; take 'default and recurse to get it as a Secrets API default collection
+    ;; matching any user, host, and protocol
+    ((eq entry 'default)
+     (auth-source-backend-parse '(:source (:secrets default))))
+    ;; take secrets:XYZ and recurse to get it as Secrets API collection "XYZ"
+    ;; matching any user, host, and protocol
+    ((and (stringp entry) (string-match "^secrets:\\(.+\\)" entry))
+     (auth-source-backend-parse `(:source (:secrets ,(match-string 1 entry)))))
+
+    ;; take 'macos-keychain-internet and recurse to get it as a Mac OS
+    ;; Keychain collection matching any user, host, and protocol
+    ((eq entry 'macos-keychain-internet)
+     (auth-source-backend-parse '(:source (:macos-keychain-internet default))))
+    ;; take 'macos-keychain-generic and recurse to get it as a Mac OS
+    ;; Keychain collection matching any user, host, and protocol
+    ((eq entry 'macos-keychain-generic)
+     (auth-source-backend-parse '(:source (:macos-keychain-generic default))))
+    ;; take macos-keychain-internet:XYZ and recurse to get it as MacOS
+    ;; Keychain "XYZ" matching any user, host, and protocol
+    ((and (stringp entry) (string-match "^macos-keychain-internet:\\(.+\\)"
+                                        entry))
+     (auth-source-backend-parse `(:source (:macos-keychain-internet
+                                           ,(match-string 1 entry)))))
+    ;; take macos-keychain-generic:XYZ and recurse to get it as MacOS
+    ;; Keychain "XYZ" matching any user, host, and protocol
+    ((and (stringp entry) (string-match "^macos-keychain-generic:\\(.+\\)"
+                                        entry))
+     (auth-source-backend-parse `(:source (:macos-keychain-generic
+                                           ,(match-string 1 entry)))))
+
+    ;; take just a file name and recurse to get it as a netrc file
+    ;; matching any user, host, and protocol
+    ((stringp entry)
+     (auth-source-backend-parse `(:source ,entry)))
+
+    ;; a file name with parameters
+    ((stringp (plist-get entry :source))
+     (if (equal (file-name-extension (plist-get entry :source)) "plist")
+         (auth-source-backend
+          (plist-get entry :source)
+          :source (plist-get entry :source)
+          :type 'plstore
+          :search-function #'auth-source-plstore-search
+          :create-function #'auth-source-plstore-create
+          :data (plstore-open (plist-get entry :source)))
+       (auth-source-backend
+        (plist-get entry :source)
+        :source (plist-get entry :source)
+        :type 'netrc
+        :search-function #'auth-source-netrc-search
+        :create-function #'auth-source-netrc-create)))
+
+    ;; the MacOS Keychain
+    ((and
+      (not (null (plist-get entry :source))) ; the source must not be nil
+      (listp (plist-get entry :source))      ; and it must be a list
+      (or
+       (plist-get (plist-get entry :source) :macos-keychain-generic)
+       (plist-get (plist-get entry :source) :macos-keychain-internet)))
+
+     (let* ((source-spec (plist-get entry :source))
+            (keychain-generic (plist-get source-spec :macos-keychain-generic))
+            (keychain-type (if keychain-generic
+                               'macos-keychain-generic
+                             'macos-keychain-internet))
+            (source (plist-get source-spec (if keychain-generic
+                                               :macos-keychain-generic
+                                             :macos-keychain-internet))))
+
+       (when (symbolp source)
+         (setq source (symbol-name source)))
+
+       (auth-source-backend
+        (format "Mac OS Keychain (%s)" source)
+        :source source
+        :type keychain-type
+        :search-function #'auth-source-macos-keychain-search
+        :create-function #'auth-source-macos-keychain-create)))
+
+    ;; the Secrets API.  We require the package, in order to have a
+    ;; defined value for `secrets-enabled'.
+    ((and
+      (not (null (plist-get entry :source))) ; the source must not be nil
+      (listp (plist-get entry :source))      ; and it must be a list
+      (require 'secrets nil t)               ; and we must load the Secrets API
+      secrets-enabled)                       ; and that API must be enabled
+
+     ;; the source is either the :secrets key in ENTRY or
+     ;; if that's missing or nil, it's "session"
+     (let ((source (or (plist-get (plist-get entry :source) :secrets)
+                       "session")))
+
+       ;; if the source is a symbol, we look for the alias named so,
+       ;; and if that alias is missing, we use "Login"
+       (when (symbolp source)
+         (setq source (or (secrets-get-alias (symbol-name source))
+                          "Login")))
+
+       (if (featurep 'secrets)
+           (auth-source-backend
+            (format "Secrets API (%s)" source)
+            :source source
+            :type 'secrets
+            :search-function #'auth-source-secrets-search
+            :create-function #'auth-source-secrets-create)
+         (auth-source-do-warn
+          "auth-source-backend-parse: no Secrets API, ignoring spec: %S" entry)
+         (auth-source-backend
+          (format "Ignored Secrets API (%s)" source)
+          :source ""
+          :type 'ignore))))
+
+    ;; none of them
+    (t
+     (auth-source-do-warn
+      "auth-source-backend-parse: invalid backend spec: %S" entry)
+     (make-instance 'auth-source-backend
+      :source ""
+      :type 'ignore)))))
+
+(defun auth-source-backend-parse-parameters (entry backend)
+  "Fills in the extra auth-source-backend parameters of ENTRY.
+Using the plist ENTRY, get the :host, :port, and :user search
+parameters."
+  (let ((entry (if (stringp entry)
+                   nil
+                 entry))
+        val)
+    (when (setq val (plist-get entry :host))
+      (oset backend host val))
+    (when (setq val (plist-get entry :user))
+      (oset backend user val))
+    (when (setq val (plist-get entry :port))
+      (oset backend port val)))
+  backend)
+
+;; (mapcar 'auth-source-backend-parse auth-sources)
+
+(defun* auth-source-search (&rest spec
+                                  &key max
+                                  require create delete
+                                  &allow-other-keys)
+  "Search or modify authentication backends according to SPEC.
+
+This function parses `auth-sources' for matches of the SPEC
+plist.  It can optionally create or update an authentication
+token if requested.  A token is just a standard Emacs property
+list with a :secret property that can be a function; all the
+other properties will always hold scalar values.
+
+Typically the :secret property, if present, contains a password.
+
+Common search keys are :max, :host, :port, and :user.  In
+addition, :create specifies if and how tokens will be created.
+Finally, :type can specify which backend types you want to check.
+
+A string value is always matched literally.  A symbol is matched
+as its string value, literally.  All the SPEC values can be
+single values (symbol or string) or lists thereof (in which case
+any of the search terms matches).
+
+:create t means to create a token if possible.
+
+A new token will be created if no matching tokens were found.
+The new token will have only the keys the backend requires.  For
+the netrc backend, for instance, that's the user, host, and
+port keys.
+
+Here's an example:
+
+\(let ((auth-source-creation-defaults \\='((user . \"defaultUser\")
+                                        (A    . \"default A\"))))
+  (auth-source-search :host \"mine\" :type \\='netrc :max 1
+                      :P \"pppp\" :Q \"qqqq\"
+                      :create t))
+
+which says:
+
+\"Search for any entry matching host `mine' in backends of type
+ `netrc', maximum one result.
+
+ Create a new entry if you found none.  The netrc backend will
+ automatically require host, user, and port.  The host will be
+ `mine'.  We prompt for the user with default `defaultUser' and
+ for the port without a default.  We will not prompt for A, Q,
+ or P.  The resulting token will only have keys user, host, and
+ port.\"
+
+:create \\='(A B C) also means to create a token if possible.
+
+The behavior is like :create t but if the list contains any
+parameter, that parameter will be required in the resulting
+token.  The value for that parameter will be obtained from the
+search parameters or from user input.  If any queries are needed,
+the alist `auth-source-creation-defaults' will be checked for the
+default value.  If the user, host, or port are missing, the alist
+`auth-source-creation-prompts' will be used to look up the
+prompts IN THAT ORDER (so the `user' prompt will be queried first,
+then `host', then `port', and finally `secret').  Each prompt string
+can use %u, %h, and %p to show the user, host, and port.
+
+Here's an example:
+
+\(let ((auth-source-creation-defaults \\='((user . \"defaultUser\")
+                                        (A    . \"default A\")))
+       (auth-source-creation-prompts
+        \\='((password . \"Enter IMAP password for %h:%p: \"))))
+  (auth-source-search :host \\='(\"nonesuch\" \"twosuch\") :type \\='netrc :max 1
+                      :P \"pppp\" :Q \"qqqq\"
+                      :create \\='(A B Q)))
+
+which says:
+
+\"Search for any entry matching host `nonesuch'
+ or `twosuch' in backends of type `netrc', maximum one result.
+
+ Create a new entry if you found none.  The netrc backend will
+ automatically require host, user, and port.  The host will be
+ `nonesuch' and Q will be `qqqq'.  We prompt for the password
+ with the shown prompt.  We will not prompt for Q.  The resulting
+ token will have keys user, host, port, A, B, and Q.  It will not
+ have P with any value, even though P is used in the search to
+ find only entries that have P set to `pppp'.\"
+
+When multiple values are specified in the search parameter, the
+user is prompted for which one.  So :host (X Y Z) would ask the
+user to choose between X, Y, and Z.
+
+This creation can fail if the search was not specific enough to
+create a new token (it's up to the backend to decide that).  You
+should `catch' the backend-specific error as usual.  Some
+backends (netrc, at least) will prompt the user rather than throw
+an error.
+
+:require (A B C) means that only results that contain those
+tokens will be returned.  Thus for instance requiring :secret
+will ensure that any results will actually have a :secret
+property.
+
+:delete t means to delete any found entries.  nil by default.
+Use `auth-source-delete' in ELisp code instead of calling
+`auth-source-search' directly with this parameter.
+
+:type (X Y Z) will check only those backend types.  `netrc' and
+`secrets' are the only ones supported right now.
+
+:max N means to try to return at most N items (defaults to 1).
+More than N items may be returned, depending on the search and
+the backend.
+
+When :max is 0 the function will return just t or nil to indicate
+if any matches were found.
+
+:host (X Y Z) means to match only hosts X, Y, or Z according to
+the match rules above.  Defaults to t.
+
+:user (X Y Z) means to match only users X, Y, or Z according to
+the match rules above.  Defaults to t.
+
+:port (P Q R) means to match only protocols P, Q, or R.
+Defaults to t.
+
+:K (V1 V2 V3) for any other key K will match values V1, V2, or
+V3 (note the match rules above).
+
+The return value is a list with at most :max tokens.  Each token
+is a plist with keys :backend :host :port :user, plus any other
+keys provided by the backend (notably :secret).  But note the
+exception for :max 0, which see above.
+
+The token can hold a :save-function key.  If you call that, the
+user will be prompted to save the data to the backend.  You can't
+request that this should happen right after creation, because
+`auth-source-search' has no way of knowing if the token is
+actually useful.  So the caller must arrange to call this function.
+
+The token's :secret key can hold a function.  In that case you
+must call it to obtain the actual value."
+  (let* ((backends (mapcar #'auth-source-backend-parse auth-sources))
+         (max (or max 1))
+         (ignored-keys '(:require :create :delete :max))
+         (keys (loop for i below (length spec) by 2
+                     unless (memq (nth i spec) ignored-keys)
+                     collect (nth i spec)))
+         (cached (auth-source-remembered-p spec))
+         ;; note that we may have cached results but found is still nil
+         ;; (there were no results from the search)
+         (found (auth-source-recall spec))
+         filtered-backends)
+
+    (if (and cached auth-source-do-cache)
+        (auth-source-do-debug
+         "auth-source-search: found %d CACHED results matching %S"
+         (length found) spec)
+
+      (assert
+       (or (eq t create) (listp create)) t
+       "Invalid auth-source :create parameter (must be t or a list): %s %s")
+
+      (assert
+       (listp require) t
+       "Invalid auth-source :require parameter (must be a list): %s")
+
+      (setq filtered-backends (copy-sequence backends))
+      (dolist (backend backends)
+        (dolist (key keys)
+          ;; ignore invalid slots
+          (condition-case nil
+              (unless (auth-source-search-collection
+                       (plist-get spec key)
+                       (slot-value backend key))
+                (setq filtered-backends (delq backend filtered-backends))
+                (return))
+            (invalid-slot-name nil))))
+
+      (auth-source-do-trivia
+       "auth-source-search: found %d backends matching %S"
+       (length filtered-backends) spec)
+
+      ;; (debug spec "filtered" filtered-backends)
+      ;; First go through all the backends without :create, so we can
+      ;; query them all.
+      (setq found (auth-source-search-backends filtered-backends
+                                               spec
+                                               ;; to exit early
+                                               max
+                                               ;; create is always nil here
+                                               nil delete
+                                               require))
+
+      (auth-source-do-debug
+       "auth-source-search: found %d results (max %d) matching %S"
+       (length found) max spec)
+
+      ;; If we didn't find anything, then we allow the backend(s) to
+      ;; create the entries.
+      (when (and create
+                 (not found))
+        (setq found (auth-source-search-backends filtered-backends
+                                                 spec
+                                                 ;; to exit early
+                                                 max
+                                                 create delete
+                                                 require))
+        (auth-source-do-debug
+         "auth-source-search: CREATED %d results (max %d) matching %S"
+         (length found) max spec))
+
+      ;; note we remember the lack of result too, if it's applicable
+      (when auth-source-do-cache
+        (auth-source-remember spec found)))
+
+    (if (zerop max)
+        (not (null found))
+      found)))
+
+(defun auth-source-search-backends (backends spec max create delete require)
+  (let ((max (if (zerop max) 1 max)) ; stop with 1 match if we're asked for zero
+        matches)
+    (dolist (backend backends)
+      (when (> max (length matches)) ; if we need more matches...
+        (let* ((bmatches (apply
+                          (slot-value backend 'search-function)
+                          :backend backend
+                          :type (slot-value backend 'type)
+                          ;; note we're overriding whatever the spec
+                          ;; has for :max, :require, :create, and :delete
+                          :max max
+                          :require require
+                          :create create
+                          :delete delete
+                          spec)))
+          (when bmatches
+            (auth-source-do-trivia
+             "auth-source-search-backend: got %d (max %d) in %s:%s matching %S"
+             (length bmatches) max
+             (slot-value backend 'type)
+             (slot-value backend 'source)
+             spec)
+            (setq matches (append matches bmatches))))))
+    matches))
+
+;; (auth-source-search :max 0)
+;; (auth-source-search :max 1)
+;; (funcall (plist-get (nth 0 (auth-source-search :max 1)) :secret))
+;; (auth-source-search :host "nonesuch" :type 'netrc :K 1)
+;; (auth-source-search :host "nonesuch" :type 'secrets)
+
+(defun auth-source-delete (&rest spec)
+  "Delete entries from the authentication backends according to SPEC.
+Calls `auth-source-search' with the :delete property in SPEC set to t.
+The backend may not actually delete the entries.
+
+Returns the deleted entries."
+  (auth-source-search (plist-put spec :delete t)))
+
+(defun auth-source-search-collection (collection value)
+  "Returns t is VALUE is t or COLLECTION is t or COLLECTION contains VALUE."
+  (when (and (atom collection) (not (eq t collection)))
+    (setq collection (list collection)))
+
+  ;; (debug :collection collection :value value)
+  (or (eq collection t)
+      (eq value t)
+      (equal collection value)
+      (member value collection)))
+
+(defvar auth-source-netrc-cache nil)
+
+(defun auth-source-forget-all-cached ()
+  "Forget all cached auth-source data."
+  (interactive)
+  (loop for sym being the symbols of password-data
+        ;; when the symbol name starts with auth-source-magic
+        when (string-match (concat "^" auth-source-magic)
+                           (symbol-name sym))
+        ;; remove that key
+        do (password-cache-remove (symbol-name sym)))
+  (setq auth-source-netrc-cache nil))
+
+(defun auth-source-format-cache-entry (spec)
+  "Format SPEC entry to put it in the password cache."
+  (concat auth-source-magic (format "%S" spec)))
+
+(defun auth-source-remember (spec found)
+  "Remember FOUND search results for SPEC."
+  (let ((password-cache-expiry auth-source-cache-expiry))
+    (password-cache-add
+     (auth-source-format-cache-entry spec) found)))
+
+(defun auth-source-recall (spec)
+  "Recall FOUND search results for SPEC."
+  (password-read-from-cache (auth-source-format-cache-entry spec)))
+
+(defun auth-source-remembered-p (spec)
+  "Check if SPEC is remembered."
+  (password-in-cache-p
+   (auth-source-format-cache-entry spec)))
+
+(defun auth-source-forget (spec)
+  "Forget any cached data matching SPEC exactly.
+
+This is the same SPEC you passed to `auth-source-search'.
+Returns t or nil for forgotten or not found."
+  (password-cache-remove (auth-source-format-cache-entry spec)))
+
+;; (loop for sym being the symbols of password-data when (string-match (concat "^" auth-source-magic) (symbol-name sym)) collect (symbol-name sym))
+
+;; (auth-source-remember '(:host "wedd") '(4 5 6))
+;; (auth-source-remembered-p '(:host "wedd"))
+;; (auth-source-remember '(:host "xedd") '(1 2 3))
+;; (auth-source-remembered-p '(:host "xedd"))
+;; (auth-source-remembered-p '(:host "zedd"))
+;; (auth-source-recall '(:host "xedd"))
+;; (auth-source-recall '(:host t))
+;; (auth-source-forget+ :host t)
+
+(defun auth-source-forget+ (&rest spec)
+  "Forget any cached data matching SPEC.  Returns forgotten count.
+
+This is not a full `auth-source-search' spec but works similarly.
+For instance, \(:host \"myhost\" \"yourhost\") would find all the
+cached data that was found with a search for those two hosts,
+while \(:host t) would find all host entries."
+  (let ((count 0)
+        sname)
+    (loop for sym being the symbols of password-data
+          ;; when the symbol name matches with auth-source-magic
+          when (and (setq sname (symbol-name sym))
+                    (string-match (concat "^" auth-source-magic "\\(.+\\)")
+                                  sname)
+                    ;; and the spec matches what was stored in the cache
+                    (auth-source-specmatchp spec (read (match-string 1 sname))))
+          ;; remove that key
+          do (progn
+               (password-cache-remove sname)
+               (incf count)))
+    count))
+
+(defun auth-source-specmatchp (spec stored)
+  (let ((keys (loop for i below (length spec) by 2
+                    collect (nth i spec))))
+    (not (eq
+          (dolist (key keys)
+            (unless (auth-source-search-collection (plist-get stored key)
+                                                   (plist-get spec key))
+              (return 'no)))
+          'no))))
+
+;; (auth-source-pick-first-password :host "z.lifelogs.com")
+;; (auth-source-pick-first-password :port "imap")
+(defun auth-source-pick-first-password (&rest spec)
+  "Pick the first secret found from applying SPEC to `auth-source-search'."
+  (let* ((result (nth 0 (apply #'auth-source-search (plist-put spec :max 1))))
+         (secret (plist-get result :secret)))
+
+    (if (functionp secret)
+        (funcall secret)
+      secret)))
+
+;; (auth-source-format-prompt "test %u %h %p" '((?u "user") (?h "host")))
+(defun auth-source-format-prompt (prompt alist)
+  "Format PROMPT using %x (for any character x) specifiers in ALIST."
+  (dolist (cell alist)
+    (let ((c (nth 0 cell))
+          (v (nth 1 cell)))
+      (when (and c v)
+        (setq prompt (replace-regexp-in-string (format "%%%c" c)
+                                               (format "%s" v)
+                                               prompt nil t)))))
+  prompt)
+
+(defun auth-source-ensure-strings (values)
+  (if (eq values t)
+      values
+    (unless (listp values)
+      (setq values (list values)))
+    (mapcar (lambda (value)
+             (if (numberp value)
+                 (format "%s" value)
+               value))
+           values)))
+
+;;; Backend specific parsing: netrc/authinfo backend
+
+(defun auth-source--aput-1 (alist key val)
+  (let ((seen ())
+        (rest alist))
+    (while (and (consp rest) (not (equal key (caar rest))))
+      (push (pop rest) seen))
+    (cons (cons key val)
+          (if (null rest) alist
+            (nconc (nreverse seen)
+                   (if (equal key (caar rest)) (cdr rest) rest))))))
+(defmacro auth-source--aput (var key val)
+  `(setq ,var (auth-source--aput-1 ,var ,key ,val)))
+
+(defun auth-source--aget (alist key)
+  (cdr (assoc key alist)))
+
+;; (auth-source-netrc-parse :file "~/.authinfo.gpg")
+(defun* auth-source-netrc-parse (&key file max host user port require
+                                 &allow-other-keys)
+  "Parse FILE and return a list of all entries in the file.
+Note that the MAX parameter is used so we can exit the parse early."
+  (if (listp file)
+      ;; We got already parsed contents; just return it.
+      file
+    (when (file-exists-p file)
+      (setq port (auth-source-ensure-strings port))
+      (with-temp-buffer
+        (let* ((max (or max 5000))       ; sanity check: default to stop at 5K
+               (modified 0)
+               (cached (cdr-safe (assoc file auth-source-netrc-cache)))
+               (cached-mtime (plist-get cached :mtime))
+               (cached-secrets (plist-get cached :secret))
+               (check (lambda(alist)
+                        (and alist
+                             (auth-source-search-collection
+                              host
+                              (or
+                               (auth-source--aget alist "machine")
+                               (auth-source--aget alist "host")
+                               t))
+                             (auth-source-search-collection
+                              user
+                              (or
+                               (auth-source--aget alist "login")
+                               (auth-source--aget alist "account")
+                               (auth-source--aget alist "user")
+                               t))
+                             (auth-source-search-collection
+                              port
+                              (or
+                               (auth-source--aget alist "port")
+                               (auth-source--aget alist "protocol")
+                               t))
+                             (or
+                              ;; the required list of keys is nil, or
+                              (null require)
+                              ;; every element of require is in n(ormalized)
+                              (let ((n (nth 0 (auth-source-netrc-normalize
+                                               (list alist) file))))
+                                (loop for req in require
+                                      always (plist-get n req)))))))
+               result)
+
+          (if (and (functionp cached-secrets)
+                   (equal cached-mtime
+                          (nth 5 (file-attributes file))))
+              (progn
+                (auth-source-do-trivia
+                 "auth-source-netrc-parse: using CACHED file data for %s"
+                 file)
+                (insert (funcall cached-secrets)))
+            (insert-file-contents file)
+            ;; cache all netrc files (used to be just .gpg files)
+            ;; Store the contents of the file heavily encrypted in memory.
+            ;; (note for the irony-impaired: they are just obfuscated)
+            (auth-source--aput
+             auth-source-netrc-cache file
+             (list :mtime (nth 5 (file-attributes file))
+                   :secret (lexical-let ((v (mapcar #'1+ (buffer-string))))
+                             (lambda () (apply #'string (mapcar #'1- v)))))))
+          (goto-char (point-min))
+          (let ((entries (auth-source-netrc-parse-entries check max))
+                alist)
+            (while (setq alist (pop entries))
+                (push (nreverse alist) result)))
+
+          (when (< 0 modified)
+            (when auth-source-gpg-encrypt-to
+              ;; (see bug#7487) making `epa-file-encrypt-to' local to
+              ;; this buffer lets epa-file skip the key selection query
+              ;; (see the `local-variable-p' check in
+              ;; `epa-file-write-region').
+              (unless (local-variable-p 'epa-file-encrypt-to (current-buffer))
+                (make-local-variable 'epa-file-encrypt-to))
+              (if (listp auth-source-gpg-encrypt-to)
+                  (setq epa-file-encrypt-to auth-source-gpg-encrypt-to)))
+
+            ;; ask AFTER we've successfully opened the file
+            (when (y-or-n-p (format "Save file %s? (%d deletions)"
+                                    file modified))
+              (write-region (point-min) (point-max) file nil 'silent)
+              (auth-source-do-debug
+               "auth-source-netrc-parse: modified %d lines in %s"
+               modified file)))
+
+          (nreverse result))))))
+
+(defun auth-source-netrc-parse-next-interesting ()
+  "Advance to the next interesting position in the current buffer."
+  ;; If we're looking at a comment or are at the end of the line, move forward
+  (while (or (looking-at "#")
+             (and (eolp)
+                  (not (eobp))))
+    (forward-line 1))
+  (skip-chars-forward "\t "))
+
+(defun auth-source-netrc-parse-one ()
+  "Read one thing from the current buffer."
+  (auth-source-netrc-parse-next-interesting)
+
+  (when (or (looking-at "'\\([^']*\\)'")
+            (looking-at "\"\\([^\"]*\\)\"")
+            (looking-at "\\([^ \t\n]+\\)"))
+    (forward-char (length (match-string 0)))
+    (auth-source-netrc-parse-next-interesting)
+    (match-string-no-properties 1)))
+
+;; with thanks to org-mode
+(defsubst auth-source-current-line (&optional pos)
+  (save-excursion
+    (and pos (goto-char pos))
+    ;; works also in narrowed buffer, because we start at 1, not point-min
+    (+ (if (bolp) 1 0) (count-lines 1 (point)))))
+
+(defun auth-source-netrc-parse-entries(check max)
+  "Parse up to MAX netrc entries, passed by CHECK, from the current buffer."
+  (let ((adder (lambda(check alist all)
+                 (when (and
+                        alist
+                        (> max (length all))
+                        (funcall check alist))
+                   (push alist all))
+                 all))
+        item item2 all alist default)
+    (while (setq item (auth-source-netrc-parse-one))
+      (setq default (equal item "default"))
+      ;; We're starting a new machine.  Save the old one.
+      (when (and alist
+                 (or default
+                     (equal item "machine")))
+        ;; (auth-source-do-trivia
+        ;;  "auth-source-netrc-parse-entries: got entry %S" alist)
+        (setq all (funcall adder check alist all)
+              alist nil))
+      ;; In default entries, we don't have a next token.
+      ;; We store them as ("machine" . t)
+      (if default
+          (push (cons "machine" t) alist)
+        ;; Not a default entry.  Grab the next item.
+        (when (setq item2 (auth-source-netrc-parse-one))
+          ;; Did we get a "machine" value?
+          (if (equal item2 "machine")
+              (progn
+                (gnus-error 1
+                 "%s: Unexpected `machine' token at line %d"
+                 "auth-source-netrc-parse-entries"
+                 (auth-source-current-line))
+                (forward-line 1))
+            (push (cons item item2) alist)))))
+
+    ;; Clean up: if there's an entry left over, use it.
+    (when alist
+      (setq all (funcall adder check alist all))
+      ;; (auth-source-do-trivia
+      ;;  "auth-source-netrc-parse-entries: got2 entry %S" alist)
+      )
+    (nreverse all)))
+
+(defvar auth-source-passphrase-alist nil)
+
+(defun auth-source-token-passphrase-callback-function (_context _key-id file)
+  (let* ((file (file-truename file))
+        (entry (assoc file auth-source-passphrase-alist))
+        passphrase)
+    ;; return the saved passphrase, calling a function if needed
+    (or (copy-sequence (if (functionp (cdr entry))
+                          (funcall (cdr entry))
+                        (cdr entry)))
+       (progn
+         (unless entry
+           (setq entry (list file))
+           (push entry auth-source-passphrase-alist))
+         (setq passphrase
+               (read-passwd
+                (format "Passphrase for %s tokens: " file)
+                t))
+         (setcdr entry (lexical-let ((p (copy-sequence passphrase)))
+                         (lambda () p)))
+         passphrase))))
+
+;; (auth-source-epa-extract-gpg-token "gpg:LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tClZlcnNpb246IEdudVBHIHYxLjQuMTEgKEdOVS9MaW51eCkKCmpBMEVBd01DT25qMjB1ak9rZnRneVI3K21iNm9aZWhuLzRad3cySkdlbnVaKzRpeEswWDY5di9icDI1U1dsQT0KPS9yc2wKLS0tLS1FTkQgUEdQIE1FU1NBR0UtLS0tLQo=" "~/.netrc")
+(defun auth-source-epa-extract-gpg-token (secret file)
+  "Pass either the decoded SECRET or the gpg:BASE64DATA version.
+FILE is the file from which we obtained this token."
+  (when (string-match "^gpg:\\(.+\\)" secret)
+    (setq secret (base64-decode-string (match-string 1 secret))))
+  (let ((context (epg-make-context 'OpenPGP)))
+    (epg-context-set-passphrase-callback
+     context
+     (cons #'auth-source-token-passphrase-callback-function
+           file))
+    (epg-decrypt-string context secret)))
+
+(defvar pp-escape-newlines)
+
+;; (insert (auth-source-epa-make-gpg-token "mysecret" "~/.netrc"))
+(defun auth-source-epa-make-gpg-token (secret file)
+  (let ((context (epg-make-context 'OpenPGP))
+        (pp-escape-newlines nil)
+        cipher)
+    (epg-context-set-armor context t)
+    (epg-context-set-passphrase-callback
+     context
+     (cons #'auth-source-token-passphrase-callback-function
+           file))
+    (setq cipher (epg-encrypt-string context secret nil))
+    (with-temp-buffer
+      (insert cipher)
+      (base64-encode-region (point-min) (point-max) t)
+      (concat "gpg:" (buffer-substring-no-properties
+                      (point-min)
+                      (point-max))))))
+
+(defun auto-source--symbol-keyword (symbol)
+  (intern (format ":%s" symbol)))
+
+(defun auth-source-netrc-normalize (alist filename)
+  (mapcar (lambda (entry)
+            (let (ret item)
+              (while (setq item (pop entry))
+                (let ((k (car item))
+                      (v (cdr item)))
+
+                  ;; apply key aliases
+                  (setq k (cond ((member k '("machine")) "host")
+                                ((member k '("login" "account")) "user")
+                                ((member k '("protocol")) "port")
+                                ((member k '("password")) "secret")
+                                (t k)))
+
+                  ;; send back the secret in a function (lexical binding)
+                  (when (equal k "secret")
+                    (setq v (lexical-let ((lexv v)
+                                          (token-decoder nil))
+                              (when (string-match "^gpg:" lexv)
+                                ;; it's a GPG token: create a token decoder
+                                ;; which unsets itself once
+                                (setq token-decoder
+                                      (lambda (val)
+                                        (prog1
+                                            (auth-source-epa-extract-gpg-token
+                                             val
+                                             filename)
+                                          (setq token-decoder nil)))))
+                              (lambda ()
+                                (when token-decoder
+                                  (setq lexv (funcall token-decoder lexv)))
+                                lexv))))
+                  (setq ret (plist-put ret
+                                       (auto-source--symbol-keyword k)
+                                       v))))
+              ret))
+          alist))
+
+;; (setq secret (plist-get (nth 0 (auth-source-search :host t :type 'netrc :K 1 :max 1)) :secret))
+;; (funcall secret)
+
+(defun* auth-source-netrc-search (&rest
+                                  spec
+                                  &key backend require create
+                                  type max host user port
+                                  &allow-other-keys)
+  "Given a property list SPEC, return search matches from the :backend.
+See `auth-source-search' for details on SPEC."
+  ;; just in case, check that the type is correct (null or same as the backend)
+  (assert (or (null type) (eq type (oref backend type)))
+          t "Invalid netrc search: %s %s")
+
+  (let ((results (auth-source-netrc-normalize
+                  (auth-source-netrc-parse
+                   :max max
+                   :require require
+                   :file (oref backend source)
+                   :host (or host t)
+                   :user (or user t)
+                   :port (or port t))
+                  (oref backend source))))
+
+    ;; if we need to create an entry AND none were found to match
+    (when (and create
+               (not results))
+
+      ;; create based on the spec and record the value
+      (setq results (or
+                     ;; if the user did not want to create the entry
+                     ;; in the file, it will be returned
+                     (apply (slot-value backend 'create-function) spec)
+                     ;; if not, we do the search again without :create
+                     ;; to get the updated data.
+
+                     ;; the result will be returned, even if the search fails
+                     (apply #'auth-source-netrc-search
+                            (plist-put spec :create nil)))))
+    results))
+
+(defun auth-source-netrc-element-or-first (v)
+  (if (listp v)
+      (nth 0 v)
+    v))
+
+;; (auth-source-search :host "nonesuch" :type 'netrc :max 1 :create t)
+;; (auth-source-search :host "nonesuch" :type 'netrc :max 1 :create t :create-extra-keys '((A "default A") (B)))
+
+(defun* auth-source-netrc-create (&rest spec
+                                        &key backend
+                                        host port create
+                                        &allow-other-keys)
+  (let* ((base-required '(host user port secret))
+         ;; we know (because of an assertion in auth-source-search) that the
+         ;; :create parameter is either t or a list (which includes nil)
+         (create-extra (if (eq t create) nil create))
+         (current-data (car (auth-source-search :max 1
+                                                :host host
+                                                :port port)))
+         (required (append base-required create-extra))
+         (file (oref backend source))
+         (add "")
+         ;; `valist' is an alist
+         valist
+         ;; `artificial' will be returned if no creation is needed
+         artificial)
+
+    ;; only for base required elements (defined as function parameters):
+    ;; fill in the valist with whatever data we may have from the search
+    ;; we complete the first value if it's a list and use the value otherwise
+    (dolist (br base-required)
+      (let ((val (plist-get spec (auto-source--symbol-keyword br))))
+        (when val
+          (let ((br-choice (cond
+                            ;; all-accepting choice (predicate is t)
+                            ((eq t val) nil)
+                            ;; just the value otherwise
+                            (t val))))
+            (when br-choice
+              (auth-source--aput valist br br-choice))))))
+
+    ;; for extra required elements, see if the spec includes a value for them
+    (dolist (er create-extra)
+      (let ((k (auto-source--symbol-keyword er))
+            (keys (loop for i below (length spec) by 2
+                        collect (nth i spec))))
+        (when (memq k keys)
+          (auth-source--aput valist er (plist-get spec k)))))
+
+    ;; for each required element
+    (dolist (r required)
+      (let* ((data (auth-source--aget valist r))
+             ;; take the first element if the data is a list
+             (data (or (auth-source-netrc-element-or-first data)
+                       (plist-get current-data
+                                  (auto-source--symbol-keyword r))))
+             ;; this is the default to be offered
+             (given-default (auth-source--aget
+                             auth-source-creation-defaults r))
+             ;; the default supplementals are simple:
+             ;; for the user, try `given-default' and then (user-login-name);
+             ;; otherwise take `given-default'
+             (default (cond
+                       ((and (not given-default) (eq r 'user))
+                        (user-login-name))
+                       (t given-default)))
+             (printable-defaults (list
+                                  (cons 'user
+                                        (or
+                                         (auth-source-netrc-element-or-first
+                                          (auth-source--aget valist 'user))
+                                         (plist-get artificial :user)
+                                         "[any user]"))
+                                  (cons 'host
+                                        (or
+                                         (auth-source-netrc-element-or-first
+                                          (auth-source--aget valist 'host))
+                                         (plist-get artificial :host)
+                                         "[any host]"))
+                                  (cons 'port
+                                        (or
+                                         (auth-source-netrc-element-or-first
+                                          (auth-source--aget valist 'port))
+                                         (plist-get artificial :port)
+                                         "[any port]"))))
+             (prompt (or (auth-source--aget auth-source-creation-prompts r)
+                         (case r
+                           (secret "%p password for %u@%h: ")
+                           (user "%p user name for %h: ")
+                           (host "%p host name for user %u: ")
+                           (port "%p port for %u@%h: "))
+                         (format "Enter %s (%%u@%%h:%%p): " r)))
+             (prompt (auth-source-format-prompt
+                      prompt
+                      `((?u ,(auth-source--aget printable-defaults 'user))
+                        (?h ,(auth-source--aget printable-defaults 'host))
+                        (?p ,(auth-source--aget printable-defaults 'port))))))
+
+        ;; Store the data, prompting for the password if needed.
+        (setq data (or data
+                       (if (eq r 'secret)
+                           ;; Special case prompt for passwords.
+                           ;; TODO: make the default (setq auth-source-netrc-use-gpg-tokens `((,(if (boundp 'epa-file-auto-mode-alist-entry) (car epa-file-auto-mode-alist-entry) "\\.gpg\\'") nil) (t gpg)))
+                           ;; TODO: or maybe leave as (setq auth-source-netrc-use-gpg-tokens 'never)
+                           (let* ((ep (format "Use GPG password tokens in %s?" file))
+                                  (gpg-encrypt
+                                   (cond
+                                    ((eq auth-source-netrc-use-gpg-tokens 'never)
+                                     'never)
+                                    ((listp auth-source-netrc-use-gpg-tokens)
+                                     (let ((check (copy-sequence
+                                                   auth-source-netrc-use-gpg-tokens))
+                                           item ret)
+                                       (while check
+                                         (setq item (pop check))
+                                         (when (or (eq (car item) t)
+                                                   (string-match (car item) file))
+                                           (setq ret (cdr item))
+                                           (setq check nil)))
+                                       ;; FIXME: `ret' unused.
+                                       ;; Should we return it here?
+                                       ))
+                                    (t 'never)))
+                                  (plain (or (eval default) (read-passwd prompt))))
+                             ;; ask if we don't know what to do (in which case
+                             ;; auth-source-netrc-use-gpg-tokens must be a list)
+                             (unless gpg-encrypt
+                               (setq gpg-encrypt (if (y-or-n-p ep) 'gpg 'never))
+                               ;; TODO: save the defcustom now? or ask?
+                               (setq auth-source-netrc-use-gpg-tokens
+                                     (cons `(,file ,gpg-encrypt)
+                                           auth-source-netrc-use-gpg-tokens)))
+                             (if (eq gpg-encrypt 'gpg)
+                                 (auth-source-epa-make-gpg-token plain file)
+                               plain))
+                         (if (stringp default)
+                             (read-string (if (string-match ": *\\'" prompt)
+                                              (concat (substring prompt 0 (match-beginning 0))
+                                                      " (default " default "): ")
+                                            (concat prompt "(default " default ") "))
+                                          nil nil default)
+                           (eval default)))))
+
+        (when data
+          (setq artificial (plist-put artificial
+                                      (auto-source--symbol-keyword r)
+                                      (if (eq r 'secret)
+                                          (lexical-let ((data data))
+                                            (lambda () data))
+                                        data))))
+
+        ;; When r is not an empty string...
+        (when (and (stringp data)
+                   (< 0 (length data)))
+          ;; this function is not strictly necessary but I think it
+          ;; makes the code clearer -tzz
+          (let ((printer (lambda ()
+                           ;; append the key (the symbol name of r)
+                           ;; and the value in r
+                           (format "%s%s %s"
+                                   ;; prepend a space
+                                   (if (zerop (length add)) "" " ")
+                                   ;; remap auth-source tokens to netrc
+                                   (case r
+                                     (user   "login")
+                                     (host   "machine")
+                                     (secret "password")
+                                     (port   "port") ; redundant but clearer
+                                     (t (symbol-name r)))
+                                   (if (string-match "[\"# ]" data)
+                                       (format "%S" data)
+                                     data)))))
+            (setq add (concat add (funcall printer)))))))
+
+    (plist-put
+     artificial
+     :save-function
+     (lexical-let ((file file)
+                   (add add))
+       (lambda () (auth-source-netrc-saver file add))))
+
+    (list artificial)))
+
+;;(funcall (plist-get (nth 0 (auth-source-search :host '("nonesuch2") :user "tzz" :port "imap" :create t :max 1)) :save-function))
+(defun auth-source-netrc-saver (file add)
+  "Save a line ADD in FILE, prompting along the way.
+Respects `auth-source-save-behavior'.  Uses
+`auth-source-netrc-cache' to avoid prompting more than once."
+  (let* ((key (format "%s %s" file (rfc2104-hash 'md5 64 16 file add)))
+         (cached (assoc key auth-source-netrc-cache)))
+
+    (if cached
+        (auth-source-do-trivia
+         "auth-source-netrc-saver: found previous run for key %s, returning"
+         key)
+      (with-temp-buffer
+        (when (file-exists-p file)
+          (insert-file-contents file))
+        (when auth-source-gpg-encrypt-to
+          ;; (see bug#7487) making `epa-file-encrypt-to' local to
+          ;; this buffer lets epa-file skip the key selection query
+          ;; (see the `local-variable-p' check in
+          ;; `epa-file-write-region').
+          (unless (local-variable-p 'epa-file-encrypt-to (current-buffer))
+            (make-local-variable 'epa-file-encrypt-to))
+          (if (listp auth-source-gpg-encrypt-to)
+              (setq epa-file-encrypt-to auth-source-gpg-encrypt-to)))
+        ;; we want the new data to be found first, so insert at beginning
+        (goto-char (point-min))
+
+        ;; Ask AFTER we've successfully opened the file.
+        (let ((prompt (format "Save auth info to file %s? " file))
+              (done (not (eq auth-source-save-behavior 'ask)))
+              (bufname "*auth-source Help*")
+              k)
+          (while (not done)
+            (setq k (auth-source-read-char-choice prompt '(?y ?n ?N ?e ??)))
+            (case k
+              (?y (setq done t))
+              (?? (save-excursion
+                    (with-output-to-temp-buffer bufname
+                      (princ
+                       (concat "(y)es, save\n"
+                               "(n)o but use the info\n"
+                               "(N)o and don't ask to save again\n"
+                               "(e)dit the line\n"
+                               "(?) for help as you can see.\n"))
+                      ;; Why?  Doesn't with-output-to-temp-buffer already do
+                      ;; the exact same thing anyway?  --Stef
+                      (set-buffer standard-output)
+                      (help-mode))))
+              (?n (setq add ""
+                        done t))
+              (?N
+               (setq add ""
+                     done t)
+               (customize-save-variable 'auth-source-save-behavior nil))
+              (?e (setq add (read-string "Line to add: " add)))
+              (t nil)))
+
+          (when (get-buffer-window bufname)
+            (delete-window (get-buffer-window bufname)))
+
+          ;; Make sure the info is not saved.
+          (when (null auth-source-save-behavior)
+            (setq add ""))
+
+          (when (< 0 (length add))
+            (progn
+              (unless (bolp)
+                (insert "\n"))
+              (insert add "\n")
+              (write-region (point-min) (point-max) file nil 'silent)
+             ;; Make the .authinfo file non-world-readable.
+             (set-file-modes file #o600)
+              (auth-source-do-debug
+               "auth-source-netrc-create: wrote 1 new line to %s"
+               file)
+              (message "Saved new authentication information to %s" file)
+              nil))))
+      (auth-source--aput auth-source-netrc-cache key "ran"))))
+
+;;; Backend specific parsing: Secrets API backend
+
+;; (let ((auth-sources '(default))) (auth-source-search :max 1 :create t))
+;; (let ((auth-sources '(default))) (auth-source-search :max 1 :delete t))
+;; (let ((auth-sources '(default))) (auth-source-search :max 1))
+;; (let ((auth-sources '(default))) (auth-source-search))
+;; (let ((auth-sources '("secrets:Login"))) (auth-source-search :max 1))
+;; (let ((auth-sources '("secrets:Login"))) (auth-source-search :max 1 :signon_realm "https://git.gnus.org/Git"))
+
+(defun auth-source-secrets-listify-pattern (pattern)
+  "Convert a pattern with lists to a list of string patterns.
+
+auth-source patterns can have values of the form :foo (\"bar\"
+\"qux\"), which means to match any secret with :foo equal to
+\"bar\" or :foo equal to \"qux\".  The secrets backend supports
+only string values for patterns, so this routine returns a list
+of patterns that is equivalent to the single original pattern
+when interpreted such that if a secret matches any pattern in the
+list, it matches the original pattern."
+  (if (null pattern)
+      '(nil)
+    (let* ((key (pop pattern))
+           (value (pop pattern))
+           (tails (auth-source-secrets-listify-pattern pattern))
+           (heads (if (stringp value)
+                      (list (list key value))
+                    (mapcar (lambda (v) (list key v)) value))))
+      (loop
+         for h in heads
+         nconc
+           (loop
+              for tl in tails
+              collect (append h tl))))))
+
+(defun* auth-source-secrets-search (&rest
+                                    spec
+                                    &key backend create delete label max
+                                    &allow-other-keys)
+  "Search the Secrets API; spec is like `auth-source'.
+
+The :label key specifies the item's label.  It is the only key
+that can specify a substring.  Any :label value besides a string
+will allow any label.
+
+All other search keys must match exactly.  If you need substring
+matching, do a wider search and narrow it down yourself.
+
+You'll get back all the properties of the token as a plist.
+
+Here's an example that looks for the first item in the `Login'
+Secrets collection:
+
+ (let ((auth-sources \\='(\"secrets:Login\")))
+    (auth-source-search :max 1)
+
+Here's another that looks for the first item in the `Login'
+Secrets collection whose label contains `gnus':
+
+ (let ((auth-sources \\='(\"secrets:Login\")))
+    (auth-source-search :max 1 :label \"gnus\")
+
+And this one looks for the first item in the `Login' Secrets
+collection that's a Google Chrome entry for the git.gnus.org site
+authentication tokens:
+
+ (let ((auth-sources \\='(\"secrets:Login\")))
+    (auth-source-search :max 1 :signon_realm \"https://git.gnus.org/Git\"))
+"
+
+  ;; TODO
+  (assert (not create) nil
+          "The Secrets API auth-source backend doesn't support creation yet")
+  ;; TODO
+  ;; (secrets-delete-item coll elt)
+  (assert (not delete) nil
+          "The Secrets API auth-source backend doesn't support deletion yet")
+
+  (let* ((coll (oref backend source))
+         (max (or max 5000))     ; sanity check: default to stop at 5K
+         (ignored-keys '(:create :delete :max :backend :label :require :type))
+         (search-keys (loop for i below (length spec) by 2
+                            unless (memq (nth i spec) ignored-keys)
+                            collect (nth i spec)))
+         ;; build a search spec without the ignored keys
+         ;; if a search key is nil or t (match anything), we skip it
+         (search-specs (auth-source-secrets-listify-pattern
+                        (apply #'append (mapcar
+                                      (lambda (k)
+                                        (if (or (null (plist-get spec k))
+                                                (eq t (plist-get spec k)))
+                                            nil
+                                          (list k (plist-get spec k))))
+                                      search-keys))))
+         ;; needed keys (always including host, login, port, and secret)
+         (returned-keys (mm-delete-duplicates (append
+                                               '(:host :login :port :secret)
+                                               search-keys)))
+         (items
+          (loop for search-spec in search-specs
+               nconc
+               (loop for item in (apply #'secrets-search-items coll search-spec)
+                  unless (and (stringp label)
+                              (not (string-match label item)))
+                  collect item)))
+         ;; TODO: respect max in `secrets-search-items', not after the fact
+         (items (butlast items (- (length items) max)))
+         ;; convert the item name to a full plist
+         (items (mapcar (lambda (item)
+                          (append
+                           ;; make an entry for the secret (password) element
+                           (list
+                            :secret
+                            (lexical-let ((v (secrets-get-secret coll item)))
+                              (lambda () v)))
+                           ;; rewrite the entry from ((k1 v1) (k2 v2)) to plist
+                           (apply #'append
+                                  (mapcar (lambda (entry)
+                                            (list (car entry) (cdr entry)))
+                                          (secrets-get-attributes coll item)))))
+                        items))
+         ;; ensure each item has each key in `returned-keys'
+         (items (mapcar (lambda (plist)
+                          (append
+                           (apply #'append
+                                  (mapcar (lambda (req)
+                                            (if (plist-get plist req)
+                                                nil
+                                              (list req nil)))
+                                          returned-keys))
+                           plist))
+                        items)))
+    items))
+
+(defun auth-source-secrets-create (&rest spec)
+  ;; TODO
+  ;; (apply 'secrets-create-item (auth-get-source entry) name passwd spec)
+  (debug spec))
+
+;;; Backend specific parsing: Mac OS Keychain (using /usr/bin/security) backend
+
+;; (let ((auth-sources '(macos-keychain-internet))) (auth-source-search :max 1 :create t))
+;; (let ((auth-sources '(macos-keychain-internet))) (auth-source-search :max 1 :delete t))
+;; (let ((auth-sources '(macos-keychain-internet))) (auth-source-search :max 1))
+;; (let ((auth-sources '(macos-keychain-internet))) (auth-source-search))
+
+;; (let ((auth-sources '(macos-keychain-generic))) (auth-source-search :max 1 :create t))
+;; (let ((auth-sources '(macos-keychain-generic))) (auth-source-search :max 1 :delete t))
+;; (let ((auth-sources '(macos-keychain-generic))) (auth-source-search :max 1))
+;; (let ((auth-sources '(macos-keychain-generic))) (auth-source-search))
+
+;; (let ((auth-sources '("macos-keychain-internet:/Users/tzz/Library/Keychains/login.keychain"))) (auth-source-search :max 1))
+;; (let ((auth-sources '("macos-keychain-generic:Login"))) (auth-source-search :max 1 :host "git.gnus.org"))
+;; (let ((auth-sources '("macos-keychain-generic:Login"))) (auth-source-search :max 1))
+
+(defun* auth-source-macos-keychain-search (&rest
+                                    spec
+                                    &key backend create delete
+                                    type max
+                                    &allow-other-keys)
+  "Search the MacOS Keychain; spec is like `auth-source'.
+
+All search keys must match exactly.  If you need substring
+matching, do a wider search and narrow it down yourself.
+
+You'll get back all the properties of the token as a plist.
+
+The :type key is either `macos-keychain-internet' or
+`macos-keychain-generic'.
+
+For the internet keychain type, the :label key searches the
+item's labels (\"-l LABEL\" passed to \"/usr/bin/security\").
+Similarly, :host maps to \"-s HOST\", :user maps to \"-a USER\",
+and :port maps to \"-P PORT\" or \"-r PROT\"
+\(note PROT has to be a 4-character string).
+
+For the generic keychain type, the :label key searches the item's
+labels (\"-l LABEL\" passed to \"/usr/bin/security\").
+Similarly, :host maps to \"-c HOST\" (the \"creator\" keychain
+field), :user maps to \"-a USER\", and :port maps to \"-s PORT\".
+
+Here's an example that looks for the first item in the default
+generic MacOS Keychain:
+
+ (let ((auth-sources \\='(macos-keychain-generic)))
+    (auth-source-search :max 1)
+
+Here's another that looks for the first item in the internet
+MacOS Keychain collection whose label is `gnus':
+
+ (let ((auth-sources \\='(macos-keychain-internet)))
+    (auth-source-search :max 1 :label \"gnus\")
+
+And this one looks for the first item in the internet keychain
+entries for git.gnus.org:
+
+ (let ((auth-sources \\='(macos-keychain-internet\")))
+    (auth-source-search :max 1 :host \"git.gnus.org\"))
+"
+  ;; TODO
+  (assert (not create) nil
+          "The MacOS Keychain auth-source backend doesn't support creation yet")
+  ;; TODO
+  ;; (macos-keychain-delete-item coll elt)
+  (assert (not delete) nil
+          "The MacOS Keychain auth-source backend doesn't support deletion yet")
+
+  (let* ((coll (oref backend source))
+         (max (or max 5000))     ; sanity check: default to stop at 5K
+         (ignored-keys '(:create :delete :max :backend :label))
+         (search-keys (loop for i below (length spec) by 2
+                            unless (memq (nth i spec) ignored-keys)
+                            collect (nth i spec)))
+         ;; build a search spec without the ignored keys
+         ;; if a search key is nil or t (match anything), we skip it
+         (search-spec (apply #'append (mapcar
+                                      (lambda (k)
+                                        (if (or (null (plist-get spec k))
+                                                (eq t (plist-get spec k)))
+                                            nil
+                                          (list k (plist-get spec k))))
+                                      search-keys)))
+         ;; needed keys (always including host, login, port, and secret)
+         (returned-keys (mm-delete-duplicates (append
+                                               '(:host :login :port :secret)
+                                               search-keys)))
+         (items (apply #'auth-source-macos-keychain-search-items
+                       coll
+                       type
+                       max
+                       search-spec))
+
+         ;; ensure each item has each key in `returned-keys'
+         (items (mapcar (lambda (plist)
+                          (append
+                           (apply #'append
+                                  (mapcar (lambda (req)
+                                            (if (plist-get plist req)
+                                                nil
+                                              (list req nil)))
+                                          returned-keys))
+                           plist))
+                        items)))
+    items))
+
+(defun* auth-source-macos-keychain-search-items (coll _type _max
+                                                      &key label type
+                                                      host user port
+                                                      &allow-other-keys)
+
+  (let* ((keychain-generic (eq type 'macos-keychain-generic))
+         (args `(,(if keychain-generic
+                      "find-generic-password"
+                    "find-internet-password")
+                 "-g"))
+         (ret (list :type type)))
+    (when label
+      (setq args (append args (list "-l" label))))
+    (when host
+      (setq args (append args (list (if keychain-generic "-c" "-s") host))))
+    (when user
+      (setq args (append args (list "-a" user))))
+
+    (when port
+      (if keychain-generic
+          (setq args (append args (list "-s" port)))
+        (setq args (append args (list
+                                 (if (string-match "[0-9]+" port) "-P" "-r")
+                                 port)))))
+
+      (unless (equal coll "default")
+        (setq args (append args (list coll))))
+
+      (with-temp-buffer
+        (apply #'call-process "/usr/bin/security" nil t nil args)
+        (goto-char (point-min))
+        (while (not (eobp))
+          (cond
+           ((looking-at "^password: \"\\(.+\\)\"$")
+            (setq ret (auth-source-macos-keychain-result-append
+                       ret
+                       keychain-generic
+                       "secret"
+                       (lexical-let ((v (match-string 1)))
+                         (lambda () v)))))
+           ;; TODO: check if this is really the label
+           ;; match 0x00000007 <blob>="AppleID"
+           ((looking-at "^[ ]+0x00000007 <blob>=\"\\(.+\\)\"")
+            (setq ret (auth-source-macos-keychain-result-append
+                       ret
+                       keychain-generic
+                       "label"
+                       (match-string 1))))
+           ;; match "crtr"<uint32>="aapl"
+           ;; match "svce"<blob>="AppleID"
+           ((looking-at "^[ ]+\"\\([a-z]+\\)\"[^=]+=\"\\(.+\\)\"")
+            (setq ret (auth-source-macos-keychain-result-append
+                       ret
+                       keychain-generic
+                       (match-string 1)
+                       (match-string 2)))))
+          (forward-line)))
+      ;; return `ret' iff it has the :secret key
+      (and (plist-get ret :secret) (list ret))))
+
+(defun auth-source-macos-keychain-result-append (result generic k v)
+  (push v result)
+  (push (auto-source--symbol-keyword
+         (cond
+          ((equal k "acct") "user")
+          ;; for generic keychains, creator is host, service is port
+          ((and generic (equal k "crtr")) "host")
+          ((and generic (equal k "svce")) "port")
+          ;; for internet keychains, protocol is port, server is host
+          ((and (not generic) (equal k "ptcl")) "port")
+          ((and (not generic) (equal k "srvr")) "host")
+          (t k)))
+        result))
+
+(defun auth-source-macos-keychain-create (&rest spec)
+  ;; TODO
+  (debug spec))
+
+;;; Backend specific parsing: PLSTORE backend
+
+(defun* auth-source-plstore-search (&rest
+                                    spec
+                                    &key backend create delete
+                                    max
+                                    &allow-other-keys)
+  "Search the PLSTORE; spec is like `auth-source'."
+  (let* ((store (oref backend data))
+         (max (or max 5000))     ; sanity check: default to stop at 5K
+         (ignored-keys '(:create :delete :max :backend :label :require :type))
+         (search-keys (loop for i below (length spec) by 2
+                            unless (memq (nth i spec) ignored-keys)
+                            collect (nth i spec)))
+         ;; build a search spec without the ignored keys
+         ;; if a search key is nil or t (match anything), we skip it
+         (search-spec (apply #'append (mapcar
+                                      (lambda (k)
+                                        (let ((v (plist-get spec k)))
+                                          (if (or (null v)
+                                                  (eq t v))
+                                              nil
+                                            (if (stringp v)
+                                                (setq v (list v)))
+                                            (list k v))))
+                                      search-keys)))
+         ;; needed keys (always including host, login, port, and secret)
+         (returned-keys (mm-delete-duplicates (append
+                                               '(:host :login :port :secret)
+                                               search-keys)))
+         (items (plstore-find store search-spec))
+         (item-names (mapcar #'car items))
+         (items (butlast items (- (length items) max)))
+         ;; convert the item to a full plist
+         (items (mapcar (lambda (item)
+                          (let* ((plist (copy-tree (cdr item)))
+                                 (secret (plist-member plist :secret)))
+                            (if secret
+                                (setcar
+                                 (cdr secret)
+                                 (lexical-let ((v (car (cdr secret))))
+                                   (lambda () v))))
+                            plist))
+                        items))
+         ;; ensure each item has each key in `returned-keys'
+         (items (mapcar (lambda (plist)
+                          (append
+                           (apply #'append
+                                  (mapcar (lambda (req)
+                                            (if (plist-get plist req)
+                                                nil
+                                              (list req nil)))
+                                          returned-keys))
+                           plist))
+                        items)))
+    (cond
+     ;; if we need to create an entry AND none were found to match
+     ((and create
+           (not items))
+
+      ;; create based on the spec and record the value
+      (setq items (or
+                   ;; if the user did not want to create the entry
+                   ;; in the file, it will be returned
+                   (apply (slot-value backend 'create-function) spec)
+                   ;; if not, we do the search again without :create
+                   ;; to get the updated data.
+
+                   ;; the result will be returned, even if the search fails
+                   (apply #'auth-source-plstore-search
+                          (plist-put spec :create nil)))))
+     ((and delete
+           item-names)
+      (dolist (item-name item-names)
+        (plstore-delete store item-name))
+      (plstore-save store)))
+    items))
+
+(defun* auth-source-plstore-create (&rest spec
+                                          &key backend
+                                          host port create
+                                          &allow-other-keys)
+  (let* ((base-required '(host user port secret))
+         (base-secret '(secret))
+         ;; we know (because of an assertion in auth-source-search) that the
+         ;; :create parameter is either t or a list (which includes nil)
+         (create-extra (if (eq t create) nil create))
+         (current-data (car (auth-source-search :max 1
+                                                :host host
+                                                :port port)))
+         (required (append base-required create-extra))
+         ;; `valist' is an alist
+         valist
+         ;; `artificial' will be returned if no creation is needed
+         artificial
+         secret-artificial)
+
+    ;; only for base required elements (defined as function parameters):
+    ;; fill in the valist with whatever data we may have from the search
+    ;; we complete the first value if it's a list and use the value otherwise
+    (dolist (br base-required)
+      (let ((val (plist-get spec (auto-source--symbol-keyword br))))
+        (when val
+          (let ((br-choice (cond
+                            ;; all-accepting choice (predicate is t)
+                            ((eq t val) nil)
+                            ;; just the value otherwise
+                            (t val))))
+            (when br-choice
+              (auth-source--aput valist br br-choice))))))
+
+    ;; for extra required elements, see if the spec includes a value for them
+    (dolist (er create-extra)
+      (let ((k (auto-source--symbol-keyword er))
+            (keys (loop for i below (length spec) by 2
+                        collect (nth i spec))))
+        (when (memq k keys)
+          (auth-source--aput valist er (plist-get spec k)))))
+
+    ;; for each required element
+    (dolist (r required)
+      (let* ((data (auth-source--aget valist r))
+             ;; take the first element if the data is a list
+             (data (or (auth-source-netrc-element-or-first data)
+                       (plist-get current-data
+                                  (auto-source--symbol-keyword r))))
+             ;; this is the default to be offered
+             (given-default (auth-source--aget
+                             auth-source-creation-defaults r))
+             ;; the default supplementals are simple:
+             ;; for the user, try `given-default' and then (user-login-name);
+             ;; otherwise take `given-default'
+             (default (cond
+                       ((and (not given-default) (eq r 'user))
+                        (user-login-name))
+                       (t given-default)))
+             (printable-defaults (list
+                                  (cons 'user
+                                        (or
+                                         (auth-source-netrc-element-or-first
+                                          (auth-source--aget valist 'user))
+                                         (plist-get artificial :user)
+                                         "[any user]"))
+                                  (cons 'host
+                                        (or
+                                         (auth-source-netrc-element-or-first
+                                          (auth-source--aget valist 'host))
+                                         (plist-get artificial :host)
+                                         "[any host]"))
+                                  (cons 'port
+                                        (or
+                                         (auth-source-netrc-element-or-first
+                                          (auth-source--aget valist 'port))
+                                         (plist-get artificial :port)
+                                         "[any port]"))))
+             (prompt (or (auth-source--aget auth-source-creation-prompts r)
+                         (case r
+                           (secret "%p password for %u@%h: ")
+                           (user "%p user name for %h: ")
+                           (host "%p host name for user %u: ")
+                           (port "%p port for %u@%h: "))
+                         (format "Enter %s (%%u@%%h:%%p): " r)))
+             (prompt (auth-source-format-prompt
+                      prompt
+                      `((?u ,(auth-source--aget printable-defaults 'user))
+                        (?h ,(auth-source--aget printable-defaults 'host))
+                        (?p ,(auth-source--aget printable-defaults 'port))))))
+
+        ;; Store the data, prompting for the password if needed.
+        (setq data (or data
+                       (if (eq r 'secret)
+                           (or (eval default) (read-passwd prompt))
+                         (if (stringp default)
+                             (read-string
+                              (if (string-match ": *\\'" prompt)
+                                  (concat (substring prompt 0 (match-beginning 0))
+                                          " (default " default "): ")
+                                (concat prompt "(default " default ") "))
+                              nil nil default)
+                           (eval default)))))
+
+        (when data
+          (if (member r base-secret)
+              (setq secret-artificial
+                    (plist-put secret-artificial
+                               (auto-source--symbol-keyword r)
+                               data))
+            (setq artificial (plist-put artificial
+                                        (auto-source--symbol-keyword r)
+                                        data))))))
+    (plstore-put (oref backend data)
+                 (sha1 (format "%s@%s:%s"
+                               (plist-get artificial :user)
+                               (plist-get artificial :host)
+                               (plist-get artificial :port)))
+                 artificial secret-artificial)
+    (if (y-or-n-p (format "Save auth info to file %s? "
+                          (plstore-get-file (oref backend data))))
+        (plstore-save (oref backend data)))))
+
+;;; older API
+
+;; (auth-source-user-or-password '("login" "password") "imap.myhost.com" t "tzz")
+
+;; deprecate the old interface
+(make-obsolete 'auth-source-user-or-password
+               'auth-source-search "Emacs 24.1")
+(make-obsolete 'auth-source-forget-user-or-password
+               'auth-source-forget "Emacs 24.1")
+
+(defun auth-source-user-or-password
+  (mode host port &optional username create-missing delete-existing)
+  "Find MODE (string or list of strings) matching HOST and PORT.
+
+DEPRECATED in favor of `auth-source-search'!
+
+USERNAME is optional and will be used as \"login\" in a search
+across the Secret Service API (see secrets.el) if the resulting
+items don't have a username.  This means that if you search for
+username \"joe\" and it matches an item but the item doesn't have
+a :user attribute, the username \"joe\" will be returned.
+
+A non nil DELETE-EXISTING means deleting any matching password
+entry in the respective sources.  This is useful only when
+CREATE-MISSING is non nil as well; the intended use case is to
+remove wrong password entries.
+
+If no matching entry is found, and CREATE-MISSING is non nil,
+the password will be retrieved interactively, and it will be
+stored in the password database which matches best (see
+`auth-sources').
+
+MODE can be \"login\" or \"password\"."
+  (auth-source-do-debug
+   "auth-source-user-or-password: DEPRECATED get %s for %s (%s) + user=%s"
+   mode host port username)
+
+  (let* ((listy (listp mode))
+         (mode (if listy mode (list mode)))
+         ;; (cname (if username
+         ;;            (format "%s %s:%s %s" mode host port username)
+         ;;          (format "%s %s:%s" mode host port)))
+         (search (list :host host :port port))
+         (search (if username (append search (list :user username)) search))
+         (search (if create-missing
+                     (append search (list :create t))
+                   search))
+         (search (if delete-existing
+                     (append search (list :delete t))
+                   search))
+         ;; (found (if (not delete-existing)
+         ;;            (gethash cname auth-source-cache)
+         ;;          (remhash cname auth-source-cache)
+         ;;          nil)))
+         (found nil))
+    (if found
+        (progn
+          (auth-source-do-debug
+           "auth-source-user-or-password: DEPRECATED cached %s=%s for %s (%s) + %s"
+           mode
+           ;; don't show the password
+           (if (and (member "password" mode) t)
+               "SECRET"
+             found)
+           host port username)
+          found)                        ; return the found data
+      ;; else, if not found, search with a max of 1
+      (let ((choice (nth 0 (apply #'auth-source-search
+                                  (append '(:max 1) search)))))
+        (when choice
+          (dolist (m mode)
+            (cond
+             ((equal "password" m)
+              (push (if (plist-get choice :secret)
+                        (funcall (plist-get choice :secret))
+                      nil) found))
+             ((equal "login" m)
+              (push (plist-get choice :user) found)))))
+        (setq found (nreverse found))
+        (setq found (if listy found (car-safe found)))))
+
+    found))
+
+(defun auth-source-user-and-password (host &optional user)
+  (let* ((auth-info (car
+                     (if user
+                         (auth-source-search
+                          :host host
+                          :user "yourusername"
+                          :max 1
+                          :require '(:user :secret)
+                          :create nil)
+                       (auth-source-search
+                        :host host
+                        :max 1
+                        :require '(:user :secret)
+                        :create nil))))
+         (user (plist-get auth-info :user))
+         (password (plist-get auth-info :secret)))
+    (when (functionp password)
+      (setq password (funcall password)))
+    (list user password auth-info)))
+
+(provide 'auth-source)
+
+;;; auth-source.el ends here
diff --git a/xemacs-packages/gnus/lisp/binhex.el b/xemacs-packages/gnus/lisp/binhex.el
new file mode 100644 (file)
index 0000000..a5f3982
--- /dev/null
@@ -0,0 +1,336 @@
+;;; binhex.el --- decode BinHex-encoded text
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Shenghuo Zhu <zsh@cs.rochester.edu>
+;; Keywords: binhex 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; BinHex is a binary-to-text encoding scheme similar to uuencode.
+;; The command `binhex-decode-region' decodes BinHex-encoded text, via
+;; the external program "hexbin" if that is available, or an Emacs
+;; Lisp implementation if not.
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(eval-and-compile
+  (defalias 'binhex-char-int
+    (if (fboundp 'char-int)
+       'char-int
+      'identity)))
+
+(defgroup binhex nil
+  "Decoding of BinHex (binary-to-hexadecimal) data."
+  :group 'mail
+  :group 'news)
+
+(defcustom binhex-decoder-program "hexbin"
+  "Non-nil value should be a string that names a binhex decoder.
+The program should expect to read binhex data on its standard
+input and write the converted data to its standard output."
+  :type 'string
+  :group 'binhex)
+
+(defcustom binhex-decoder-switches '("-d")
+  "List of command line flags passed to the command `binhex-decoder-program'."
+  :group 'binhex
+  :type '(repeat string))
+
+(defcustom binhex-use-external
+  (executable-find binhex-decoder-program)
+  "Use external binhex program."
+  :version "22.1"
+  :group 'binhex
+  :type 'boolean)
+
+(defconst binhex-alphabet-decoding-alist
+  '(( ?\! . 0) ( ?\" . 1) ( ?\# . 2) ( ?\$ . 3) ( ?\% . 4) ( ?\& . 5)
+    ( ?\' . 6) ( ?\( . 7) ( ?\) . 8) ( ?\* . 9) ( ?\+ . 10) ( ?\, . 11)
+    ( ?\- . 12) ( ?0 . 13) ( ?1 . 14) ( ?2 . 15) ( ?3 . 16) ( ?4 . 17)
+    ( ?5 . 18) ( ?6 . 19) ( ?8 . 20) ( ?9 . 21) ( ?@ . 22) ( ?A . 23)
+    ( ?B . 24) ( ?C . 25) ( ?D . 26) ( ?E . 27) ( ?F . 28) ( ?G . 29)
+    ( ?H . 30) ( ?I . 31) ( ?J . 32) ( ?K . 33) ( ?L . 34) ( ?M . 35)
+    ( ?N . 36) ( ?P . 37) ( ?Q . 38) ( ?R . 39) ( ?S . 40) ( ?T . 41)
+    ( ?U . 42) ( ?V . 43) ( ?X . 44) ( ?Y . 45) ( ?Z . 46) ( ?\[ . 47)
+    ( ?\` . 48) ( ?a . 49) ( ?b . 50) ( ?c . 51) ( ?d . 52) ( ?e . 53)
+    ( ?f . 54) ( ?h . 55) ( ?i . 56) ( ?j . 57) ( ?k . 58) ( ?l . 59)
+    ( ?m . 60) ( ?p . 61) ( ?q . 62) ( ?r . 63)))
+
+(defun binhex-char-map (char)
+  (cdr (assq char binhex-alphabet-decoding-alist)))
+
+;;;###autoload
+(defconst binhex-begin-line
+  "^:...............................................................$"
+  "Regular expression matching the start of a BinHex encoded region.")
+(defconst binhex-body-line
+  "^[^:]...............................................................$")
+(defconst binhex-end-line ":$")                ; unused
+
+(defvar binhex-temporary-file-directory
+  (cond ((fboundp 'temp-directory) (temp-directory))
+       ((boundp 'temporary-file-directory) temporary-file-directory)
+       ("/tmp/")))
+
+(eval-and-compile
+  (defalias 'binhex-insert-char
+    (if (featurep 'xemacs)
+       'insert-char
+      (lambda (char &optional count ignored buffer)
+       "Insert COUNT copies of CHARACTER into BUFFER."
+       (if (or (null buffer) (eq buffer (current-buffer)))
+           (insert-char char count)
+         (with-current-buffer buffer
+           (insert-char char count)))))))
+
+(defvar binhex-crc-table
+  [0  4129  8258  12387  16516  20645  24774  28903
+      33032  37161  41290  45419  49548  53677  57806  61935
+      4657  528  12915  8786  21173  17044  29431  25302
+      37689  33560  45947  41818  54205  50076  62463  58334
+      9314  13379  1056  5121  25830  29895  17572  21637
+      42346  46411  34088  38153  58862  62927  50604  54669
+      13907  9842  5649  1584  30423  26358  22165  18100
+      46939  42874  38681  34616  63455  59390  55197  51132
+      18628  22757  26758  30887  2112  6241  10242  14371
+      51660  55789  59790  63919  35144  39273  43274  47403
+      23285  19156  31415  27286  6769  2640  14899  10770
+      56317  52188  64447  60318  39801  35672  47931  43802
+      27814  31879  19684  23749  11298  15363  3168  7233
+      60846  64911  52716  56781  44330  48395  36200  40265
+      32407  28342  24277  20212  15891  11826  7761  3696
+      65439  61374  57309  53244  48923  44858  40793  36728
+      37256  33193  45514  41451  53516  49453  61774  57711
+      4224  161  12482  8419  20484  16421  28742  24679
+      33721  37784  41979  46042  49981  54044  58239  62302
+      689  4752  8947  13010  16949  21012  25207  29270
+      46570  42443  38312  34185  62830  58703  54572  50445
+      13538  9411  5280  1153  29798  25671  21540  17413
+      42971  47098  34713  38840  59231  63358  50973  55100
+      9939  14066  1681  5808  26199  30326  17941  22068
+      55628  51565  63758  59695  39368  35305  47498  43435
+      22596  18533  30726  26663  6336  2273  14466  10403
+      52093  56156  60223  64286  35833  39896  43963  48026
+      19061  23124  27191  31254  2801  6864  10931  14994
+      64814  60687  56684  52557  48554  44427  40424  36297
+      31782  27655  23652  19525  15522  11395  7392  3265
+      61215  65342  53085  57212  44955  49082  36825  40952
+      28183  32310  20053  24180  11923  16050  3793  7920])
+
+(defun binhex-update-crc (crc char &optional count)
+  (if (null count) (setq count 1))
+  (while (> count 0)
+    (setq crc (logxor (logand (lsh crc 8) 65280)
+                     (aref binhex-crc-table
+                           (logxor (logand (lsh crc -8) 255)
+                                   char)))
+         count (1- count)))
+  crc)
+
+(defun binhex-verify-crc (buffer start end)
+  (with-current-buffer buffer
+    (let ((pos start) (crc 0) (last (- end 2)))
+      (while (< pos last)
+       (setq crc (binhex-update-crc crc (char-after pos))
+             pos (1+ pos)))
+      (if (= crc (binhex-string-big-endian (buffer-substring last end)))
+         nil
+       (error "CRC error")))))
+
+(defun binhex-string-big-endian (string)
+  (let ((ret 0) (i 0) (len (length string)))
+    (while (< i len)
+      (setq ret (+ (lsh ret 8) (binhex-char-int (aref string i)))
+           i (1+ i)))
+    ret))
+
+(defun binhex-string-little-endian (string)
+  (let ((ret 0) (i 0) (shift 0) (len (length string)))
+    (while (< i len)
+      (setq ret (+ ret (lsh (binhex-char-int (aref string i)) shift))
+           i (1+ i)
+           shift (+ shift 8)))
+    ret))
+
+(defun binhex-header (buffer)
+  (with-current-buffer buffer
+    (let ((pos (point-min)) len)
+      (vector
+       (prog1
+          (setq len (binhex-char-int (char-after pos)))
+        (setq pos (1+ pos)))
+       (buffer-substring pos (setq pos (+ pos len)))
+       (prog1
+          (setq len (binhex-char-int (char-after pos)))
+        (setq pos (1+ pos)))
+       (buffer-substring pos (setq pos (+ pos 4)))
+       (buffer-substring pos (setq pos (+ pos 4)))
+       (binhex-string-big-endian
+       (buffer-substring pos (setq pos (+ pos 2))))
+       (binhex-string-big-endian
+       (buffer-substring pos (setq pos (+ pos 4))))
+       (binhex-string-big-endian
+       (buffer-substring pos (setq pos (+ pos 4))))))))
+
+(defvar binhex-last-char)
+(defvar binhex-repeat)
+
+(defun binhex-push-char (char &optional count ignored buffer)
+  (cond
+   (binhex-repeat
+    (if (eq char 0)
+       (binhex-insert-char (setq binhex-last-char 144) 1
+                           ignored buffer)
+      (binhex-insert-char binhex-last-char (- char 1)
+                         ignored buffer)
+      (setq binhex-last-char nil))
+    (setq binhex-repeat nil))
+   ((= char 144)
+    (setq binhex-repeat t))
+   (t
+    (binhex-insert-char (setq binhex-last-char char) 1 ignored buffer))))
+
+;;;###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)
+       (counter 0)
+       (bits 0) (tmp t)
+       (lim 0) inputpos
+       (non-data-chars " \t\n\r:")
+       file-name-length data-fork-start
+       header
+       binhex-last-char binhex-repeat)
+    (unwind-protect
+       (save-excursion
+         (goto-char start)
+         (when (re-search-forward binhex-begin-line end t)
+            (setq work-buffer (generate-new-buffer " *binhex-work*"))
+           (unless (featurep 'xemacs)
+             (with-current-buffer work-buffer (set-buffer-multibyte nil)))
+           (beginning-of-line)
+           (setq bits 0 counter 0)
+           (while tmp
+             (skip-chars-forward non-data-chars end)
+             (setq inputpos (point))
+             (end-of-line)
+             (setq lim (point))
+             (while (and (< inputpos lim)
+                         (setq tmp (binhex-char-map (char-after inputpos))))
+               (setq bits (+ bits tmp)
+                     counter (1+ counter)
+                     inputpos (1+ inputpos))
+               (cond ((= counter 4)
+                      (binhex-push-char (lsh bits -16) 1 nil work-buffer)
+                      (binhex-push-char (logand (lsh bits -8) 255) 1 nil
+                                        work-buffer)
+                      (binhex-push-char (logand bits 255) 1 nil
+                                        work-buffer)
+                      (setq bits 0 counter 0))
+                     (t (setq bits (lsh bits 6)))))
+             (if (null file-name-length)
+                 (with-current-buffer work-buffer
+                   (setq file-name-length (char-after (point-min))
+                         data-fork-start (+ (point-min)
+                                            file-name-length 22))))
+             (when (and (null header)
+                        (with-current-buffer work-buffer
+                          (>= (buffer-size) data-fork-start)))
+               (binhex-verify-crc work-buffer
+                                  (point-min) data-fork-start)
+               (setq header (binhex-header work-buffer))
+               (when header-only (setq tmp nil counter 0)))
+             (setq tmp (and tmp (not (eq inputpos end)))))
+           (cond
+            ((= counter 3)
+             (binhex-push-char (logand (lsh bits -16) 255) 1 nil
+                               work-buffer)
+             (binhex-push-char (logand (lsh bits -8) 255) 1 nil
+                               work-buffer))
+            ((= counter 2)
+             (binhex-push-char (logand (lsh bits -10) 255) 1 nil
+                               work-buffer))))
+         (if header-only nil
+           (binhex-verify-crc work-buffer
+                              data-fork-start
+                              (+ data-fork-start (aref header 6) 2))
+           (or (markerp end) (setq end (set-marker (make-marker) end)))
+           (goto-char start)
+           (insert-buffer-substring work-buffer
+                                    data-fork-start (+ data-fork-start
+                                                       (aref header 6)))
+           (delete-region (point) end)))
+      (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-internal start end t)
+                           ".data")
+                   binhex-temporary-file-directory)))
+    (save-excursion
+      (goto-char start)
+      (when (re-search-forward binhex-begin-line nil t)
+       (let ((cdir default-directory) default-process-coding-system)
+         (unwind-protect
+             (progn
+               (set-buffer (setq work-buffer
+                                 (generate-new-buffer " *binhex-work*")))
+               (buffer-disable-undo work-buffer)
+               (insert-buffer-substring cbuf firstline end)
+               (cd binhex-temporary-file-directory)
+               (apply 'call-process-region
+                      (point-min)
+                      (point-max)
+                      binhex-decoder-program
+                      nil
+                      nil
+                      nil
+                      binhex-decoder-switches))
+           (cd cdir) (set-buffer cbuf)))
+       (if (and file-name (file-exists-p file-name))
+           (progn
+             (goto-char start)
+             (delete-region start end)
+             (let (format-alist)
+               (insert-file-contents-literally file-name)))
+         (error "Can not binhex")))
+      (and work-buffer (kill-buffer work-buffer))
+      (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/xemacs-packages/gnus/lisp/canlock.el b/xemacs-packages/gnus/lisp/canlock.el
new file mode 100644 (file)
index 0000000..b73d863
--- /dev/null
@@ -0,0 +1,250 @@
+;;; canlock.el --- functions for Cancel-Lock feature
+
+;; Copyright (C) 1998-1999, 2001-2016 Free Software Foundation, Inc.
+
+;; Author: Katsumi Yamaoka <yamaoka@jpl.org>
+;; Keywords: news, cancel-lock, hmac, sha1, rfc2104
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; 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:
+
+(eval-when-compile
+  (require 'cl))
+
+(require 'sha1)
+
+(defvar mail-header-separator)
+
+(defgroup canlock nil
+  "The Cancel-Lock feature."
+  :group 'news)
+
+(defcustom canlock-password nil
+  "Password to use when signing a Cancel-Lock or a Cancel-Key header."
+  :type '(radio (const :format "Not specified " nil)
+               (string :tag "Password"))
+  :group 'canlock)
+
+(defcustom canlock-password-for-verify canlock-password
+  "Password to use when verifying a Cancel-Lock or a Cancel-Key header."
+  :type '(radio (const :format "Not specified " nil)
+               (string :tag "Password"))
+  :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)
+
+(eval-when-compile
+  (defmacro canlock-string-as-unibyte (string)
+    "Return a unibyte string with the same individual bytes as STRING."
+    (if (fboundp 'string-as-unibyte)
+       (list 'string-as-unibyte string)
+      string)))
+
+(defun canlock-sha1 (message)
+  "Make a SHA-1 digest of MESSAGE as a unibyte string of length 20 bytes."
+  (let (sha1-maximum-internal-length)
+    (sha1 message nil nil 'binary)))
+
+(defun canlock-make-cancel-key (message-id password)
+  "Make a Cancel-Key header."
+  (when (> (length password) 20)
+    (setq password (canlock-sha1 password)))
+  (setq password (concat password (make-string (- 64 (length password)) 0)))
+  (let ((ipad (mapconcat (lambda (byte)
+                          (char-to-string (logxor 54 byte)))
+                        password ""))
+       (opad (mapconcat (lambda (byte)
+                          (char-to-string (logxor 92 byte)))
+                        password "")))
+    (base64-encode-string
+     (canlock-sha1
+      (concat opad
+             (canlock-sha1
+              (concat ipad (canlock-string-as-unibyte 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
+                              (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 (canlock-sha1 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."
+  (interactive)
+  (let (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
+       (error "%s" errmsg)
+      (setq password (or canlock-password-for-verify
+                        (read-passwd "Password for Canlock: ")))
+      (if (or (not (stringp password)) (zerop (length password)))
+         (error "Password for Canlock is bad")
+       (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
+                  (canlock-sha1 (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/xemacs-packages/gnus/lisp/color.el b/xemacs-packages/gnus/lisp/color.el
new file mode 100644 (file)
index 0000000..a47fb4e
--- /dev/null
@@ -0,0 +1,399 @@
+;;; color.el --- Color manipulation library -*- coding: utf-8; -*-
+
+;; Copyright (C) 2010-2016 Free Software Foundation, Inc.
+
+;; Authors: Julien Danjou <julien@danjou.info>
+;;          Drew Adams <drew.adams@oracle.com>
+;; Keywords: lisp, faces, color, hex, rgb, hsv, hsl, cie-lab, background
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package provides functions for manipulating colors, including
+;; converting between color representations, computing color
+;; complements, and computing CIEDE2000 color distances.
+;;
+;; Supported color representations include RGB (red, green, blue), HSV
+;; (hue, saturation, value), HSL (hue, saturation, luminance), sRGB,
+;; CIE XYZ, and CIE L*a*b* color components.
+
+;;; Code:
+
+;; Emacs < 23.3
+(eval-and-compile
+  (unless (boundp 'float-pi)
+    (defconst float-pi (* 4 (atan 1)) "The value of Pi (3.1415926...).")))
+
+;;;###autoload
+(defun color-name-to-rgb (color &optional frame)
+  "Convert COLOR string to a list of normalized RGB components.
+COLOR should be a color name (e.g. \"white\") or an RGB triplet
+string (e.g. \"#ff12ec\").
+
+Normally the return value is a list of three floating-point
+numbers, (RED GREEN BLUE), each between 0.0 and 1.0 inclusive.
+
+Optional argument FRAME specifies the frame where the color is to be
+displayed.  If FRAME is omitted or nil, use the selected frame.
+If FRAME cannot display COLOR, return nil."
+  ;; `colors-values' maximum value is either 65535 or 65280 depending on the
+  ;; display system.  So we use a white conversion to get the max value.
+  (let ((valmax (float (car (color-values "#ffffff")))))
+    (mapcar (lambda (x) (/ x valmax)) (color-values color frame))))
+
+(defun color-rgb-to-hex  (red green blue)
+  "Return hexadecimal notation for the color RED GREEN BLUE.
+RED, GREEN, and BLUE should be numbers between 0.0 and 1.0, inclusive."
+  (format "#%02x%02x%02x"
+          (* red 255) (* green 255) (* blue 255)))
+
+(defun color-complement (color-name)
+  "Return the color that is the complement of COLOR-NAME.
+COLOR-NAME should be a string naming a color (e.g. \"white\"), or
+a string specifying a color's RGB components (e.g. \"#ff12ec\")."
+  (let ((color (color-name-to-rgb color-name)))
+    (list (- 1.0 (nth 0 color))
+          (- 1.0 (nth 1 color))
+          (- 1.0 (nth 2 color)))))
+
+(defun color-gradient (start stop step-number)
+  "Return a list with STEP-NUMBER colors from START to STOP.
+The color list builds a color gradient starting at color START to
+color STOP.  It does not include the START and STOP color in the
+resulting list."
+  (let* ((r (nth 0 start))
+        (g (nth 1 start))
+        (b (nth 2 start))
+        (r-step (/ (- (nth 0 stop) r) (1+ step-number)))
+        (g-step (/ (- (nth 1 stop) g) (1+ step-number)))
+        (b-step (/ (- (nth 2 stop) b) (1+ step-number)))
+        result)
+    (dotimes (n step-number)
+      (push (list (setq r (+ r r-step))
+                 (setq g (+ g g-step))
+                 (setq b (+ b b-step)))
+           result))
+    (nreverse result)))
+
+(defun color-hue-to-rgb (v1 v2 h)
+  "Compute hue from V1 and V2 H.
+Used internally by `color-hsl-to-rgb'."
+  (cond
+   ((< h (/ 1.0 6))   (+ v1 (* (- v2 v1) h 6.0)))
+   ((< h 0.5)         v2)
+   ((< h (/ 2.0 3))   (+ v1 (* (- v2 v1) (- (/ 2.0 3) h) 6.0)))
+   (t                 v1)))
+
+(defun color-hsl-to-rgb (H S L)
+  "Convert hue, saturation and luminance to their RGB representation.
+H, S, and L should each be numbers between 0.0 and 1.0, inclusive.
+Return a list (RED GREEN BLUE), where each element is between 0.0 and 1.0,
+inclusive."
+  (if (= S 0.0)
+      (list L L L)
+    (let* ((m2 (if (<= L 0.5)
+                  (* L (+ 1.0 S))
+                (- (+ L S) (* L S))))
+          (m1 (- (* 2.0 L) m2)))
+      (list
+       (color-hue-to-rgb m1 m2 (mod (+ H (/ 1.0 3)) 1))
+       (color-hue-to-rgb m1 m2 H)
+       (color-hue-to-rgb m1 m2 (mod (- H (/ 1.0 3)) 1))))))
+
+(defun color-complement-hex (color)
+  "Return the color that is the complement of COLOR, in hexadecimal format."
+  (apply 'color-rgb-to-hex (color-complement color)))
+
+(defun color-rgb-to-hsv (red green blue)
+  "Convert RGB color components to HSV.
+RED, GREEN, and BLUE should each be numbers between 0.0 and 1.0,
+inclusive.  Return a list (HUE SATURATION VALUE), where HUE is
+in radians and both SATURATION and VALUE are between 0.0 and 1.0,
+inclusive."
+  (let* ((r (float red))
+        (g (float green))
+        (b (float blue))
+        (max (max r g b))
+        (min (min r g b)))
+    (if (< (- max min) 1e-8)
+       (list 0.0 0.0 min)
+      (list
+       (/ (* 2 float-pi
+            (cond ((and (= r g) (= g b)) 0)
+                  ((and (= r max)
+                        (>= g b))
+                   (* 60 (/ (- g b) (- max min))))
+                  ((and (= r max)
+                        (< g b))
+                   (+ 360 (* 60 (/ (- g b) (- max min)))))
+                  ((= max g)
+                   (+ 120 (* 60 (/ (- b r) (- max min)))))
+                  ((= max b)
+                   (+ 240 (* 60 (/ (- r g) (- max min)))))))
+         360)
+       (if (= max 0) 0 (- 1 (/ min max)))
+       max))))
+
+(defun color-rgb-to-hsl (red green blue)
+  "Convert RGB colors to their HSL representation.
+RED, GREEN, and BLUE should each be numbers between 0.0 and 1.0,
+inclusive.  Return a list (HUE SATURATION LUMINANCE), where
+each element is between 0.0 and 1.0, inclusive."
+  (let* ((r red)
+         (g green)
+         (b blue)
+         (max (max r g b))
+         (min (min r g b))
+         (delta (- max min))
+         (l (/ (+ max min) 2.0)))
+    (if (= delta 0)
+       (list 0.0 0.0 l)
+      (let* ((s (if (<= l 0.5) (/ delta (+ max min))
+                 (/ delta (- 2.0 max min))))
+            (rc (/ (- max r) delta))
+            (gc (/ (- max g) delta))
+            (bc (/ (- max b) delta))
+            (h  (mod
+                 (/
+                  (cond
+                   ((= r max)      (- bc gc))
+                   ((= g max)      (+ 2.0 rc (- bc)))
+                   (t              (+ 4.0 gc (- rc))))
+                  6.0) 1.0)))
+       (list h s l)))))
+
+(defun color-srgb-to-xyz (red green blue)
+  "Convert RED GREEN BLUE colors from the sRGB color space to CIE XYZ.
+RED, GREEN and BLUE should be between 0.0 and 1.0, inclusive."
+  (let ((r (if (<= red 0.04045)
+               (/ red 12.95)
+             (expt (/ (+ red 0.055) 1.055) 2.4)))
+        (g (if (<= green 0.04045)
+               (/ green 12.95)
+             (expt (/ (+ green 0.055) 1.055) 2.4)))
+        (b (if (<= blue 0.04045)
+               (/ blue 12.95)
+             (expt (/ (+ blue 0.055) 1.055) 2.4))))
+    (list (+ (* 0.4124564 r) (* 0.3575761 g) (* 0.1804375 b))
+          (+ (* 0.21266729 r) (* 0.7151522 g) (* 0.0721750 b))
+          (+ (* 0.0193339 r) (* 0.1191920 g) (* 0.9503041 b)))))
+
+(defun color-xyz-to-srgb (X Y Z)
+  "Convert CIE X Y Z colors to sRGB color space."
+  (let ((r (+ (* 3.2404542 X) (* -1.5371385 Y) (* -0.4985314 Z)))
+        (g (+ (* -0.9692660 X) (* 1.8760108 Y) (* 0.0415560 Z)))
+        (b (+ (* 0.0556434 X) (* -0.2040259 Y) (* 1.0572252 Z))))
+    (list (if (<= r 0.0031308)
+              (* 12.92 r)
+            (- (* 1.055 (expt r (/ 1 2.4))) 0.055))
+          (if (<= g 0.0031308)
+              (* 12.92 g)
+            (- (* 1.055 (expt g (/ 1 2.4))) 0.055))
+          (if (<= b 0.0031308)
+              (* 12.92 b)
+            (- (* 1.055 (expt b (/ 1 2.4))) 0.055)))))
+
+(defconst color-d65-xyz '(0.950455 1.0 1.088753)
+  "D65 white point in CIE XYZ.")
+
+(defconst color-cie-ε (/ 216 24389.0))
+(defconst color-cie-κ (/ 24389 27.0))
+
+(defun color-xyz-to-lab (X Y Z &optional white-point)
+  "Convert CIE XYZ to CIE L*a*b*.
+WHITE-POINT specifies the (X Y Z) white point for the
+conversion.  If omitted or nil, use `color-d65-xyz'."
+  (destructuring-bind (Xr Yr Zr) (or white-point color-d65-xyz)
+      (let* ((xr (/ X Xr))
+             (yr (/ Y Yr))
+             (zr (/ Z Zr))
+             (fx (if (> xr color-cie-ε)
+                     (expt xr (/ 1 3.0))
+                   (/ (+ (* color-cie-κ xr) 16) 116.0)))
+             (fy (if (> yr color-cie-ε)
+                     (expt yr (/ 1 3.0))
+                   (/ (+ (* color-cie-κ yr) 16) 116.0)))
+             (fz (if (> zr color-cie-ε)
+                     (expt zr (/ 1 3.0))
+                   (/ (+ (* color-cie-κ zr) 16) 116.0))))
+        (list
+         (- (* 116 fy) 16)                  ; L
+         (* 500 (- fx fy))                  ; a
+         (* 200 (- fy fz))))))              ; b
+
+(defun color-lab-to-xyz (L a b &optional white-point)
+  "Convert CIE L*a*b* to CIE XYZ.
+WHITE-POINT specifies the (X Y Z) white point for the
+conversion.  If omitted or nil, use `color-d65-xyz'."
+  (destructuring-bind (Xr Yr Zr) (or white-point color-d65-xyz)
+      (let* ((fy (/ (+ L 16) 116.0))
+             (fz (- fy (/ b 200.0)))
+             (fx (+ (/ a 500.0) fy))
+             (xr (if (> (expt fx 3.0) color-cie-ε)
+                     (expt fx 3.0)
+               (/ (- (* fx 116) 16) color-cie-κ)))
+             (yr (if (> L (* color-cie-κ color-cie-ε))
+                     (expt (/ (+ L 16) 116.0) 3.0)
+                   (/ L color-cie-κ)))
+             (zr (if (> (expt fz 3) color-cie-ε)
+                     (expt fz 3.0)
+                   (/ (- (* 116 fz) 16) color-cie-κ))))
+        (list (* xr Xr)                 ; X
+              (* yr Yr)                 ; Y
+              (* zr Zr)))))             ; Z
+
+(defun color-srgb-to-lab (red green blue)
+  "Convert RGB to CIE L*a*b*."
+  (apply 'color-xyz-to-lab (color-srgb-to-xyz red green blue)))
+
+(defun color-lab-to-srgb (L a b)
+  "Convert CIE L*a*b* to RGB."
+  (apply 'color-xyz-to-srgb (color-lab-to-xyz L a b)))
+
+(defun color-cie-de2000 (color1 color2 &optional kL kC kH)
+  "Return the CIEDE2000 color distance between COLOR1 and COLOR2.
+Both COLOR1 and COLOR2 should be in CIE L*a*b* format, as
+returned by `color-srgb-to-lab' or `color-xyz-to-lab'."
+  (destructuring-bind (L₁ a₁ b₁) color1
+    (destructuring-bind (L₂ a₂ b₂) color2
+      (let* ((kL (or kL 1))
+             (kC (or kC 1))
+             (kH (or kH 1))
+             (C₁ (sqrt (+ (expt a₁ 2.0) (expt b₁ 2.0))))
+             (C₂ (sqrt (+ (expt a₂ 2.0) (expt b₂ 2.0))))
+             (C̄ (/ (+ C₁ C₂) 2.0))
+             (G (* 0.5 (- 1 (sqrt (/ (expt C̄ 7.0) (+ (expt C̄ 7.0) (expt 25 7.0)))))))
+             (a′₁ (* (+ 1 G) a₁))
+             (a′₂ (* (+ 1 G) a₂))
+             (C′₁ (sqrt (+ (expt a′₁ 2.0) (expt b₁ 2.0))))
+             (C′₂ (sqrt (+ (expt a′₂ 2.0) (expt b₂ 2.0))))
+             (h′₁ (if (and (= b₁ 0) (= a′₁ 0))
+                      0
+                    (let ((v (atan b₁ a′₁)))
+                      (if (< v 0)
+                          (+ v (* 2 float-pi))
+                        v))))
+             (h′₂ (if (and (= b₂ 0) (= a′₂ 0))
+                      0
+                    (let ((v (atan b₂ a′₂)))
+                      (if (< v 0)
+                          (+ v (* 2 float-pi))
+                        v))))
+             (ΔL′ (- L₂ L₁))
+             (ΔC′ (- C′₂ C′₁))
+             (Δh′ (cond ((= (* C′₁ C′₂) 0)
+                         0)
+                        ((<= (abs (- h′₂ h′₁)) float-pi)
+                         (- h′₂ h′₁))
+                        ((> (- h′₂ h′₁) float-pi)
+                         (- (- h′₂ h′₁) (* 2 float-pi)))
+                        ((< (- h′₂ h′₁) (- float-pi))
+                         (+ (- h′₂ h′₁) (* 2 float-pi)))))
+             (ΔH′ (* 2 (sqrt (* C′₁ C′₂)) (sin (/ Δh′ 2.0))))
+             (L̄′ (/ (+ L₁ L₂) 2.0))
+             (C̄′ (/ (+ C′₁ C′₂) 2.0))
+             (h̄′ (cond ((= (* C′₁ C′₂) 0)
+                        (+ h′₁ h′₂))
+                       ((<= (abs (- h′₁ h′₂)) float-pi)
+                        (/ (+ h′₁ h′₂) 2.0))
+                       ((< (+ h′₁ h′₂) (* 2 float-pi))
+                        (/ (+ h′₁ h′₂ (* 2 float-pi)) 2.0))
+                       ((>= (+ h′₁ h′₂) (* 2 float-pi))
+                        (/ (+ h′₁ h′₂ (* -2 float-pi)) 2.0))))
+             (T (+ 1
+                   (- (* 0.17 (cos (- h̄′ (degrees-to-radians 30)))))
+                   (* 0.24 (cos (* h̄′ 2)))
+                   (* 0.32 (cos (+ (* h̄′ 3) (degrees-to-radians 6))))
+                   (- (* 0.20 (cos (- (* h̄′ 4) (degrees-to-radians 63)))))))
+             (Δθ (* (degrees-to-radians 30) (exp (- (expt (/ (- h̄′ (degrees-to-radians 275)) (degrees-to-radians 25)) 2.0)))))
+             (Rc (* 2 (sqrt (/ (expt C̄′ 7.0) (+ (expt C̄′ 7.0) (expt 25.0 7.0))))))
+             (Sl (+ 1 (/ (* 0.015 (expt (- L̄′ 50) 2.0)) (sqrt (+ 20 (expt (- L̄′ 50) 2.0))))))
+             (Sc (+ 1 (* C̄′ 0.045)))
+             (Sh (+ 1 (* 0.015 C̄′ T)))
+             (Rt (- (* (sin (* Δθ 2)) Rc))))
+        (sqrt (+ (expt (/ ΔL′ (* Sl kL)) 2.0)
+                 (expt (/ ΔC′ (* Sc kC)) 2.0)
+                 (expt (/ ΔH′ (* Sh kH)) 2.0)
+                 (* Rt (/ ΔC′ (* Sc kC)) (/ ΔH′ (* Sh kH)))))))))
+
+(defun color-clamp (value)
+  "Make sure VALUE is a number between 0.0 and 1.0 inclusive."
+  (min 1.0 (max 0.0 value)))
+
+(defun color-saturate-hsl (H S L percent)
+  "Make a color more saturated by a specified amount.
+Given a color defined in terms of hue, saturation, and luminance
+\(arguments H, S, and L), return a color that is PERCENT more
+saturated.  Returns a list (HUE SATURATION LUMINANCE)."
+  (list H (color-clamp (+ S (/ percent 100.0))) L))
+
+(defun color-saturate-name (name percent)
+  "Make a color with a specified NAME more saturated by PERCENT.
+See `color-saturate-hsl'."
+  (apply 'color-rgb-to-hex
+        (apply 'color-hsl-to-rgb
+               (apply 'color-saturate-hsl
+                      (append
+                       (apply 'color-rgb-to-hsl
+                              (color-name-to-rgb name))
+                       (list percent))))))
+
+(defun color-desaturate-hsl (H S L percent)
+  "Make a color less saturated by a specified amount.
+Given a color defined in terms of hue, saturation, and luminance
+\(arguments H, S, and L), return a color that is PERCENT less
+saturated.  Returns a list (HUE SATURATION LUMINANCE)."
+  (color-saturate-hsl H S L (- percent)))
+
+(defun color-desaturate-name (name percent)
+  "Make a color with a specified NAME less saturated by PERCENT.
+See `color-desaturate-hsl'."
+  (color-saturate-name name (- percent)))
+
+(defun color-lighten-hsl (H S L percent)
+  "Make a color lighter by a specified amount.
+Given a color defined in terms of hue, saturation, and luminance
+\(arguments H, S, and L), return a color that is PERCENT lighter.
+Returns a list (HUE SATURATION LUMINANCE)."
+  (list H S (color-clamp (+ L (/ percent 100.0)))))
+
+(defun color-lighten-name (name percent)
+  "Make a color with a specified NAME lighter by PERCENT.
+See `color-lighten-hsl'."
+  (apply 'color-rgb-to-hex
+        (apply 'color-hsl-to-rgb
+               (apply 'color-lighten-hsl
+                      (append
+                       (apply 'color-rgb-to-hsl
+                              (color-name-to-rgb name))
+                       (list percent))))))
+
+(defun color-darken-hsl (H S L percent)
+    "Make a color darker by a specified amount.
+Given a color defined in terms of hue, saturation, and luminance
+\(arguments H, S, and L), return a color that is PERCENT darker.
+Returns a list (HUE SATURATION LUMINANCE)."
+  (color-lighten-hsl H S L (- percent)))
+
+(defun color-darken-name (name percent)
+  "Make a color with a specified NAME darker by PERCENT.
+See `color-darken-hsl'."
+  (color-lighten-name name (- percent)))
+
+(provide 'color)
+
+;;; color.el ends here
diff --git a/xemacs-packages/gnus/lisp/compface.el b/xemacs-packages/gnus/lisp/compface.el
new file mode 100644 (file)
index 0000000..cd70d6c
--- /dev/null
@@ -0,0 +1,62 @@
+;;; compface.el --- functions for converting X-Face headers
+
+;; Copyright (C) 2002-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+;;;###
+(defun uncompface (face)
+  "Convert FACE to pbm.
+Requires the external programs `uncompface', and `icontopbm'.  On a
+GNU/Linux system these might be in packages with names like `compface'
+or `faces-xface' and `netpbm' or `libgr-progs', for instance."
+  (with-temp-buffer
+    (unless (featurep 'xemacs) (set-buffer-multibyte nil))
+    (insert face)
+    (let ((coding-system-for-read 'raw-text)
+         ;; At least "icontopbm" doesn't work with Windows because
+         ;; the line-break code is converted into CRLF by default.
+         (coding-system-for-write 'binary))
+      (and (eq 0 (apply 'call-process-region (point-min) (point-max)
+                       "uncompface"
+                       'delete '(t nil) nil))
+          (progn
+            (goto-char (point-min))
+            (insert "/* Format_version=1, Width=48, Height=48, Depth=1,\
+ Valid_bits_per_item=16 */\n")
+            ;; I just can't get "icontopbm" to work correctly on its
+            ;; own in XEmacs.  And Emacs doesn't understand un-raw pbm
+            ;; files.
+            (if (not (featurep 'xemacs))
+                (eq 0 (call-process-region (point-min) (point-max)
+                                           "icontopbm"
+                                           'delete '(t nil)))
+              (shell-command-on-region (point-min) (point-max)
+                                       "icontopbm | pnmnoraw"
+                                       (current-buffer) t)
+              t))
+          (buffer-string)))))
+
+(provide 'compface)
+
+;;; compface.el ends here
diff --git a/xemacs-packages/gnus/lisp/deuglify.el b/xemacs-packages/gnus/lisp/deuglify.el
new file mode 100644 (file)
index 0000000..c74f69e
--- /dev/null
@@ -0,0 +1,478 @@
+;;; deuglify.el --- deuglify broken Outlook (Express) articles
+
+;; Copyright (C) 2001-2016 Free Software Foundation, Inc.
+
+;; Author: Raymond Scholz <rscholz@zonix.de>
+;;         Thomas Steffen
+;; (unwrapping algorithm, based on an idea of Stefan Monnier)
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This file enables Gnus to repair broken citations produced by
+;; common user agents like MS Outlook (Express).  It may repair
+;; articles of other user agents too.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;
+;; Outlook sometimes wraps cited lines before sending a message as
+;; seen in this example:
+;;
+;; Example #1
+;; ----------
+;;
+;; John Doe wrote:
+;;
+;; > This sentence no verb.  This sentence no verb.  This sentence
+;; no
+;; > verb.  This sentence no verb.  This sentence no verb.  This
+;; > sentence no verb.
+;;
+;; The function `gnus-article-outlook-unwrap-lines' tries to recognize those
+;; erroneously wrapped lines and will unwrap them.  I.e. putting the
+;; wrapped parts ("no" in this example) back where they belong (at the
+;; end of the cited line above).
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Note that some people not only use broken user agents but also
+;; practice a bad citation style by omitting blank lines between the
+;; cited text and their own text.
+;:
+;; Example #2
+;; ----------
+;;
+;; John Doe wrote:
+;;
+;; > This sentence no verb.  This sentence no verb.  This sentence no
+;; You forgot in all your sentences.
+;; > verb.  This sentence no verb.  This sentence no verb.  This
+;; > sentence no verb.
+;;
+;; Unwrapping "You forgot in all your sentences." would be invalid as
+;; this part wasn't intended to be cited text.
+;; `gnus-article-outlook-unwrap-lines' will only unwrap lines if the resulting
+;; citation line will be of a certain maximum length.  You can control
+;; this by adjusting `gnus-outlook-deuglify-unwrap-max'.  Also
+;; unwrapping will only be done if the line above the (possibly)
+;; wrapped line has a minimum length of `gnus-outlook-deuglify-unwrap-min'.
+;;
+;; Furthermore no unwrapping will be undertaken if the last character
+;; is one of the chars specified in
+;; `gnus-outlook-deuglify-unwrap-stop-chars'.  Setting this to ".?!"
+;; inhibits unwrapping if the cited line ends with a full stop,
+;; question mark or exclamation mark.  Note that this variable
+;; defaults to nil, triggering a few false positives but generally
+;; giving you better results.
+;;
+;; Unwrapping works on every level of citation.  Thus you will be able
+;; repair broken citations of broken user agents citing broken
+;; citations of broken user agents citing broken citations...
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Citations are commonly introduced with an attribution line
+;; indicating who wrote the cited text.  Outlook adds superfluous
+;; information that can be found in the header of the message to this
+;; line and often wraps it.
+;;
+;; If that weren't enough, lots of people write their own text above
+;; the cited text and cite the complete original article below.
+;;
+;; Example #3
+;; ----------
+;;
+;; Hey, John.  There's no in all your sentences!
+;;
+;; John Doe <john.doe@some.domain> wrote in message
+;; news:a87usw8$dklsssa$2@some.news.server...
+;; > This sentence no verb.  This sentence no verb.  This sentence
+;; no
+;; > verb.  This sentence no verb.  This sentence no verb.  This
+;; > sentence no verb.
+;; >
+;; > Bye, John
+;;
+;; Repairing the attribution line will be done by function
+;; `gnus-article-outlook-repair-attribution' which calls other function that
+;; try to recognize and repair broken attribution lines.  See variable
+;; `gnus-outlook-deuglify-attrib-cut-regexp' for stuff that should be
+;; cut off from the beginning of an attribution line and variable
+;; `gnus-outlook-deuglify-attrib-verb-regexp' for the verbs that are
+;; required to be found in an attribution line.  These function return
+;; the point where the repaired attribution line starts.
+;;
+;; Rearranging the article so that the cited text appears above the
+;; new text will be done by function
+;; `gnus-article-outlook-rearrange-citation'.  This function calls
+;; `gnus-article-outlook-repair-attribution' to find and repair an attribution
+;; line.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Well, and that's what the message will look like after applying
+;; deuglification:
+;;
+;; Example #3 (deuglified)
+;; -----------------------
+;;
+;; John Doe <john.doe@some.domain> wrote:
+;;
+;; > This sentence no verb.  This sentence no verb.  This sentence no
+;; > verb.  This sentence no verb.  This sentence no verb.  This
+;; > sentence no verb.
+;; >
+;; > Bye, John
+;;
+;; Hey, John.  There's no in all your sentences!
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Usage
+;; -----
+;;
+;; Press `W k' in the Summary Buffer.
+;;
+;; Non recommended usage :-)
+;; ---------------------
+;;
+;; To automatically invoke deuglification on every article you read,
+;; put something like that in your .gnus:
+;;
+;; (add-hook 'gnus-article-decode-hook 'gnus-article-outlook-unwrap-lines)
+;;
+;; or _one_ of the following lines:
+;;
+;; ;; repair broken attribution lines
+;; (add-hook 'gnus-article-decode-hook 'gnus-article-outlook-repair-attribution)
+;;
+;; ;; repair broken attribution lines and citations
+;; (add-hook 'gnus-article-decode-hook 'gnus-article-outlook-rearrange-citation)
+;;
+;; Note that there always may be some false positives, so I suggest
+;; using the manual invocation.  After deuglification you may want to
+;; refill the whole article using `W w'.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Limitations
+;; -----------
+;;
+;; As I said before there may (or will) be a few false positives on
+;; unwrapping cited lines with `gnus-article-outlook-unwrap-lines'.
+;;
+;; `gnus-article-outlook-repair-attribution' will only fix the first
+;; attribution line found in the article.  Furthermore it fixed to
+;; certain kinds of attributions.  And there may be horribly many
+;; false positives, vanishing lines and so on -- so don't trust your
+;; eyes.  Again I recommend manual invocation.
+;;
+;; `gnus-article-outlook-rearrange-citation' carries all the limitations of
+;; `gnus-article-outlook-repair-attribution'.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; See commit log for other changes.
+;;
+;; Revision 1.5  2002/01/27 14:39:17  rscholz
+;; * New variable `gnus-outlook-deuglify-no-wrap-chars' to inhibit
+;;   unwrapping if one these chars is first in the possibly wrapped line.
+;; * Improved rearranging of the article.
+;; * New function `gnus-outlook-repair-attribution-block' for repairing
+;;   those big "Original Message (following some headers)" attributions.
+;;
+;; Revision 1.4  2002/01/03 14:05:00  rscholz
+;; Renamed `gnus-outlook-deuglify-article' to
+;; `gnus-article-outlook-deuglify-article'.
+;; Made it easier to deuglify the article while being in Gnus' Article
+;; Edit Mode.  (suggested by Phil Nitschke)
+;;
+;;
+;; Revision 1.3  2002/01/02 23:35:54  rscholz
+;; Fix a bug that caused succeeding long attribution lines to be
+;; unwrapped.  Minor doc fixes and regular expression tuning.
+;;
+;; Revision 1.2  2001/12/30 20:14:34  rscholz
+;; Clean up source.
+;;
+;; Revision 1.1  2001/12/30 20:13:32  rscholz
+;; Initial revision
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;; Code:
+
+(require 'gnus-art)
+(require 'gnus-sum)
+
+(defconst gnus-outlook-deuglify-version "1.5 Gnus version"
+  "Version of gnus-outlook-deuglify.")
+
+;;; User Customizable Variables:
+
+(defgroup gnus-outlook-deuglify nil
+  "Deuglify articles generated by broken user agents like MS Outlook (Express)."
+  :version "22.1"
+  :group 'gnus)
+
+(defcustom gnus-outlook-deuglify-unwrap-min 45
+  "Minimum length of the cited line above the (possibly) wrapped line."
+  :version "22.1"
+  :type 'integer
+  :group 'gnus-outlook-deuglify)
+
+(defcustom gnus-outlook-deuglify-unwrap-max 95
+  "Maximum length of the cited line after unwrapping."
+  :version "22.1"
+  :type 'integer
+  :group 'gnus-outlook-deuglify)
+
+(defcustom gnus-outlook-deuglify-cite-marks ">|#%"
+  "Characters that indicate cited lines."
+  :version "22.1"
+  :type 'string
+  :group 'gnus-outlook-deuglify)
+
+(defcustom gnus-outlook-deuglify-unwrap-stop-chars nil ;; ".?!" or nil
+  "Characters that inhibit unwrapping if they are the last one on the cited line above the possible wrapped line."
+  :version "22.1"
+  :type '(radio (const :format "None  " nil)
+               (string :value ".?!"))
+  :group 'gnus-outlook-deuglify)
+
+(defcustom gnus-outlook-deuglify-no-wrap-chars "`"
+  "Characters that inhibit unwrapping if they are the first one in the possibly wrapped line."
+  :version "22.1"
+  :type 'string
+  :group 'gnus-outlook-deuglify)
+
+(defcustom  gnus-outlook-deuglify-attrib-cut-regexp
+  "\\(On \\|Am \\)?\\(Mon\\|Tue\\|Wed\\|Thu\\|Fri\\|Sat\\|Sun\\),[^,]+, "
+  "Regular expression matching the beginning of an attribution line that should be cut off."
+  :version "22.1"
+  :type 'string
+  :group 'gnus-outlook-deuglify)
+
+(defcustom gnus-outlook-deuglify-attrib-verb-regexp
+  "wrote\\|writes\\|says\\|schrieb\\|schreibt\\|meinte\\|skrev\\|a écrit\\|schreef\\|escribió"
+  "Regular expression matching the verb used in an attribution line."
+  :version "22.1"
+  :type 'string
+  :group 'gnus-outlook-deuglify)
+
+(defcustom  gnus-outlook-deuglify-attrib-end-regexp
+  ": *\\|\\.\\.\\."
+  "Regular expression matching the end of an attribution line."
+  :version "22.1"
+  :type 'string
+  :group 'gnus-outlook-deuglify)
+
+(defcustom gnus-outlook-display-hook nil
+  "A hook called after an deuglified article has been prepared.
+It is run after `gnus-article-prepare-hook'."
+  :version "22.1"
+  :type 'hook
+  :group 'gnus-outlook-deuglify)
+
+;; Functions
+
+(defun gnus-outlook-display-article-buffer ()
+  "Redisplay current buffer or article buffer."
+  (with-current-buffer (or gnus-article-buffer (current-buffer))
+    ;; "Emulate" `gnus-article-prepare-display' without calling
+    ;; it. Calling `gnus-article-prepare-display' on an already
+    ;; prepared article removes all MIME parts.  I'm unsure whether
+    ;; this is a bug or not.
+    (gnus-article-highlight t)
+    (gnus-treat-article nil)
+    (gnus-run-hooks 'gnus-article-prepare-hook
+                   'gnus-outlook-display-hook)))
+
+;;;###autoload
+(defun gnus-article-outlook-unwrap-lines (&optional nodisplay)
+  "Unwrap lines that appear to be wrapped citation lines.
+You can control what lines will be unwrapped by frobbing
+`gnus-outlook-deuglify-unwrap-min' and `gnus-outlook-deuglify-unwrap-max',
+indicating the minimum and maximum length of an unwrapped citation line.  If
+NODISPLAY is non-nil, don't redisplay the article buffer."
+  (interactive "P")
+  (let ((case-fold-search nil)
+       (inhibit-read-only t)
+       (cite-marks gnus-outlook-deuglify-cite-marks)
+       (no-wrap gnus-outlook-deuglify-no-wrap-chars)
+       (stop-chars gnus-outlook-deuglify-unwrap-stop-chars))
+    (gnus-with-article-buffer
+      (article-goto-body)
+      (while (re-search-forward
+             (concat
+              "^\\([ \t" cite-marks "]*\\)"
+              "\\([" cite-marks "].*[^\n " stop-chars "]\\)[ \t]?\n"
+              "\\1\\([^\n " cite-marks no-wrap "]+.*\\)$")
+              nil t)
+       (let ((len12 (- (match-end 2) (match-beginning 1)))
+             (len3 (- (match-end 3) (match-beginning 3))))
+         (when (and (> len12 gnus-outlook-deuglify-unwrap-min)
+                    (< (+ len12 len3) gnus-outlook-deuglify-unwrap-max))
+           (replace-match "\\1\\2 \\3")
+           (goto-char (match-beginning 0)))))))
+  (unless nodisplay (gnus-outlook-display-article-buffer)))
+
+(defun gnus-outlook-rearrange-article (attr-start)
+  "Put the text from ATTR-START to the end of buffer at the top of the article buffer."
+  ;; FIXME: 1.  (*) text/plain          ( ) text/html
+  (let ((inhibit-read-only t)
+       (cite-marks gnus-outlook-deuglify-cite-marks))
+    (gnus-with-article-buffer
+      (article-goto-body)
+      ;; article does not start with attribution
+      (unless (= (point) attr-start)
+       (gnus-kill-all-overlays)
+       (let ((cur (point))
+             ;; before signature or end of buffer
+             (to (if (gnus-article-search-signature)
+                     (point)
+                   (point-max))))
+         ;; handle the case where the full quote is below the
+         ;; signature
+         (when (< to attr-start)
+           (setq to (point-max)))
+         (save-excursion
+           (narrow-to-region attr-start to)
+           (goto-char attr-start)
+           (forward-line)
+           (unless (looking-at ">")
+             (message-indent-citation (point) (point-max) 'yank-only)
+             (goto-char (point-max))
+             (newline)
+             (setq to (point-max)))
+           (widen))
+         (transpose-regions cur attr-start attr-start to))))))
+
+;; John Doe <john.doe@some.domain> wrote in message
+;; news:a87usw8$dklsssa$2@some.news.server...
+
+(defun gnus-outlook-repair-attribution-outlook ()
+  "Repair a broken attribution line (Outlook)."
+  (let ((case-fold-search nil)
+       (inhibit-read-only t)
+       (cite-marks gnus-outlook-deuglify-cite-marks))
+    (gnus-with-article-buffer
+      (article-goto-body)
+      (when (re-search-forward
+            (concat "^\\([^" cite-marks "].+\\)"
+                    "\\(" gnus-outlook-deuglify-attrib-verb-regexp "\\)"
+                    "\\(.*\n?[^\n" cite-marks "].*\\)?"
+                    "\\(" gnus-outlook-deuglify-attrib-end-regexp "\\)$")
+            nil t)
+       (gnus-kill-all-overlays)
+       (replace-match "\\1\\2\\4")
+       (match-beginning 0)))))
+
+
+;; ----- Original Message -----
+;; From: "John Doe" <john.doe@some.domain>
+;; To: "Doe Foundation" <info@doefnd.org>
+;; Sent: Monday, November 19, 2001 12:13 PM
+;; Subject: More Doenuts
+
+(defun gnus-outlook-repair-attribution-block ()
+  "Repair a big broken attribution block."
+  (let ((case-fold-search nil)
+       (inhibit-read-only t)
+       (cite-marks gnus-outlook-deuglify-cite-marks))
+    (gnus-with-article-buffer
+      (article-goto-body)
+      (when (re-search-forward
+            (concat "^[" cite-marks " \t]*--* ?[^-]+ [^-]+ ?--*\\s *\n"
+                    "[^\n:]+:[ \t]*\\([^\n]+\\)\n"
+                    "\\([^\n:]+:[ \t]*[^\n]+\n\\)+")
+            nil t)
+       (gnus-kill-all-overlays)
+       (replace-match "\\1 wrote:\n")
+       (match-beginning 0)))))
+
+;; On Wed, 16 Jan 2002 23:23:30 +0100, John Doe <john.doe@some.domain> wrote:
+
+(defun gnus-outlook-repair-attribution-other ()
+  "Repair a broken attribution line (other user agents than Outlook)."
+  (let ((case-fold-search nil)
+       (inhibit-read-only t)
+       (cite-marks gnus-outlook-deuglify-cite-marks))
+    (gnus-with-article-buffer
+      (article-goto-body)
+      (when (re-search-forward
+            (concat "^\\("gnus-outlook-deuglify-attrib-cut-regexp"\\)?"
+                    "\\([^" cite-marks "].+\\)\n\\([^\n" cite-marks "].*\\)?"
+                    "\\(" gnus-outlook-deuglify-attrib-verb-regexp "\\).*"
+                    "\\(" gnus-outlook-deuglify-attrib-end-regexp "\\)$")
+            nil t)
+       (gnus-kill-all-overlays)
+       (replace-match "\\4 \\5\\6\\7")
+       (match-beginning 0)))))
+
+;;;###autoload
+(defun gnus-article-outlook-repair-attribution (&optional nodisplay)
+  "Repair a broken attribution line.
+If NODISPLAY is non-nil, don't redisplay the article buffer."
+  (interactive "P")
+  (let ((attrib-start
+        (or
+         (gnus-outlook-repair-attribution-other)
+         (gnus-outlook-repair-attribution-block)
+         (gnus-outlook-repair-attribution-outlook))))
+    (unless nodisplay (gnus-outlook-display-article-buffer))
+    attrib-start))
+
+(defun gnus-article-outlook-rearrange-citation (&optional nodisplay)
+  "Repair broken citations.
+If NODISPLAY is non-nil, don't redisplay the article buffer."
+  (interactive "P")
+  (let ((attrib-start (gnus-article-outlook-repair-attribution 'nodisplay)))
+    ;; rearrange citations if an attribution line has been recognized
+    (if attrib-start
+       (gnus-outlook-rearrange-article attrib-start)))
+  (unless nodisplay (gnus-outlook-display-article-buffer)))
+
+;;;###autoload
+(defun gnus-outlook-deuglify-article (&optional nodisplay)
+  "Full deuglify of broken Outlook (Express) articles.
+Treat dumbquotes, unwrap lines, repair attribution and rearrange citation.  If
+NODISPLAY is non-nil, don't redisplay the article buffer."
+  (interactive "P")
+  ;; apply treatment of dumb quotes
+  (gnus-article-treat-dumbquotes)
+  ;; repair wrapped cited lines
+  (gnus-article-outlook-unwrap-lines 'nodisplay)
+  ;; repair attribution line and rearrange citation.
+  (gnus-article-outlook-rearrange-citation 'nodisplay)
+  (unless nodisplay (gnus-outlook-display-article-buffer)))
+
+;;;###autoload
+(defun gnus-article-outlook-deuglify-article ()
+  "Deuglify broken Outlook (Express) articles and redisplay."
+  (interactive)
+  (gnus-outlook-deuglify-article nil))
+
+(provide 'deuglify)
+
+;; Local Variables:
+;; coding: utf-8
+;; End:
+
+;;; deuglify.el ends here
diff --git a/xemacs-packages/gnus/lisp/dgnushack.el b/xemacs-packages/gnus/lisp/dgnushack.el
new file mode 100644 (file)
index 0000000..b1203e3
--- /dev/null
@@ -0,0 +1,625 @@
+;;; dgnushack.el --- a hack to set the load path for byte-compiling
+;; Copyright (C) 1994-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Version: 4.19
+;; Keywords: news, path
+
+;; 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 3, 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.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(defvar dgnushack-default-load-path (copy-sequence load-path))
+
+(when (featurep 'xemacs)
+  (defmacro declare-function (fn file &optional arglist fileonly)
+    (unless (fboundp fn) (autoload fn file))
+    nil))
+
+(defalias 'facep 'ignore)
+
+(require 'cl)
+(require 'iswitchb)
+
+(condition-case nil
+    (require 'org-entities)
+  (error nil))
+
+(defvar srcdir (or (getenv "srcdir") "."))
+(defvar loaddir (and load-file-name (file-name-directory load-file-name)))
+
+(defun my-getenv (str)
+  (let ((val (getenv str)))
+    (if (equal val "no") nil val)))
+
+(if (my-getenv "lispdir")
+    (push (my-getenv "lispdir") load-path))
+
+;(push "/usr/share/emacs/site-lisp" load-path)
+
+;; If we are building Gnus in a different directory than the source
+;; directory, we must read *.el from source directory and write *.elc
+;; into the building directory.  For that, we define this function
+;; before loading bytecomp.  Bytecomp doesn't overwrite this function.
+(defun byte-compile-dest-file (filename)
+  "Convert an Emacs Lisp source file name to a compiled file name.
+ In addition, remove directory name part from FILENAME."
+  (setq filename (byte-compiler-base-file-name filename))
+  (setq filename (file-name-sans-versions filename))
+  (setq filename (file-name-nondirectory filename))
+  (if (eq system-type 'windows-nt)
+      (setq filename (downcase filename)))
+  (cond ((eq system-type 'vax-vms)
+        (concat (substring filename 0 (string-match ";" filename)) "c"))
+       ((string-match emacs-lisp-file-regexp filename)
+        (concat (substring filename 0 (match-beginning 0)) ".elc"))
+       (t (concat filename ".elc"))))
+
+(require 'bytecomp)
+;; To avoid having defsubsts and inlines happen.
+;(if (featurep 'xemacs)
+;    (require 'byte-optimize)
+;  (require 'byte-opt))
+;(defun byte-optimize-inline-handler (form)
+;  "byte-optimize-handler for the `inline' special-form."
+;  (cons 'progn (cdr form)))
+;(defalias 'byte-compile-file-form-defsubst 'byte-compile-file-form-defun)
+
+;; Work around for an incompatibility (XEmacs 21.4 vs. 21.5), see the
+;; following threads:
+;;
+;; http://thread.gmane.org/gmane.emacs.gnus.general/56414
+;; Subject: attachment problems found but not fixed
+;;
+;; http://thread.gmane.org/gmane.emacs.gnus.general/56459
+;; Subject: Splitting mail -- XEmacs 21.4 vs 21.5
+;;
+;; http://thread.gmane.org/gmane.emacs.xemacs.beta/20519
+;; Subject: XEmacs 21.5 and Gnus fancy splitting.
+;;
+;; Should be fixed in XEmacs (March 2007).
+;; http://thread.gmane.org/gmane.emacs.xemacs.patches/8124
+;; When should we remove this workaround?
+;;
+(when (and (featurep 'xemacs)
+          (let ((table (copy-syntax-table emacs-lisp-mode-syntax-table)))
+            (modify-syntax-entry ?= " " table)
+            (with-temp-buffer
+              (with-syntax-table table
+                (insert "foo=bar")
+                (goto-char (point-min))
+                (forward-sexp 1)
+                (eolp)))))
+  ;; The original `with-syntax-table' uses `copy-syntax-table' which
+  ;; doesn't seem to copy modified syntax entries in old XEmacs 21.5.
+  (defmacro with-syntax-table (syntab &rest body)
+    "Evaluate BODY with the SYNTAB as the current syntax table."
+    `(let ((stab (syntax-table)))
+       (unwind-protect
+          (progn
+            ;;(set-syntax-table (copy-syntax-table ,syntab))
+            (set-syntax-table ,syntab)
+            ,@body)
+        (set-syntax-table stab)))))
+
+(push srcdir load-path)
+(push loaddir load-path)
+(load (expand-file-name "lpath.el" loaddir) nil t)
+
+(defalias 'device-sound-enabled-p 'ignore)
+(defalias 'play-sound-file 'ignore)
+(defalias 'efs-re-read-dir 'ignore)
+(defalias 'ange-ftp-re-read-dir 'ignore)
+(defalias 'define-mail-user-agent 'ignore)
+(defalias 'debbugs-gnu-summary-mode 'ignore)
+(defvar debbugs-gnu-bug-number nil)
+
+(eval-and-compile
+  (unless (featurep 'xemacs)
+    (defalias 'get-popup-menu-response 'ignore)
+    (defalias 'event-object 'ignore)
+    (autoload 'iswitchb-read-buffer "iswitchb")
+    (autoload 'netrc-credentials "netrc")
+    (defalias 'x-defined-colors 'ignore)
+    (defalias 'read-color 'ignore)))
+
+(eval-and-compile
+  (when (featurep 'xemacs)
+    (defvar window-point-insertion-type nil)
+    (unless (fboundp 'defadvice)
+      (autoload 'defadvice "advice" nil nil 'macro))
+    (unless (boundp 'help-echo-owns-message)
+      (defvar help-echo-owns-message))
+    (unless (boundp 'gnus-registry-enabled)
+      (defvar gnus-registry-enabled nil))
+    (unless (boundp 'mail-dont-reply-to-names)
+      (defvar mail-dont-reply-to-names nil))
+    (unless (fboundp 'url-retrieve-synchronously)
+      (defalias 'url-retrieve-synchronously 'url-retrieve))
+    (unless (fboundp 'url-queue-retrieve)
+      (defun url-queue-retrieve (url callback &optional cbargs silent
+                                    inhibit-cookies)
+       (url-retrieve url callback cbargs)))
+    (unless (boundp 'w3-configuration-directory)
+      (setq w3-configuration-directory "~/.w3/"))
+    (autoload 'Info-directory "info" nil t)
+    (autoload 'Info-index "info" nil t)
+    (autoload 'Info-index-next "info" nil t)
+    (autoload 'Info-menu "info" nil t)
+    (autoload 'ad-add-advice "advice")
+    (unless (and (emacs-version>= 21 5)
+                (not (featurep 'sxemacs)))
+      ;; calendar/auto-autoloads.el provides it.
+      (autoload 'add-to-invisibility-spec "dummy"))
+    (autoload 'annotations-at "annotations")
+    (autoload 'apropos "apropos" nil t)
+    (autoload 'apropos-command "apropos" nil t)
+    (autoload 'bbdb-complete-name "bbdb-com" nil t)
+    (autoload 'browse-url "browse-url" nil t)
+    (autoload 'browse-url-of-file "browse-url" nil t)
+    (autoload 'c-mode "cc-mode" nil t)
+    (autoload 'customize-apropos "cus-edit" nil t)
+    (autoload 'customize-group "cus-edit" nil t)
+    (autoload 'customize-save-variable "cus-edit" nil t)
+    (autoload 'customize-set-variable "cus-edit" nil t)
+    (autoload 'customize-variable "cus-edit" nil t)
+    (autoload 'debug "debug" nil t)
+    (autoload 'sha1 "sha1")
+    (if (featurep 'mule)
+       (unless (locate-library "mule-ccl")
+         (autoload 'define-ccl-program "ccl" nil nil 'macro))
+      (defalias 'define-ccl-program 'ignore))
+    (autoload 'delete-annotation "annotations")
+    (autoload 'dolist "cl-macs" nil nil 'macro)
+    (autoload 'enriched-decode "enriched")
+    (autoload 'eudc-expand-inline "eudc" nil t)
+    (autoload 'executable-find "executable")
+    (autoload 'font-lock-fontify-buffer "font-lock" nil t)
+    (when (and (emacs-version>= 21 5)
+              (not (featurep 'sxemacs)))
+      (autoload 'get-display-table "disp-table")
+      (autoload 'put-display-table "disp-table"))
+    (autoload 'info "info" nil t)
+    (autoload 'mail-extract-address-components "mail-extr")
+    (autoload 'mail-fetch-field "mail-utils")
+    (autoload 'make-annotation "annotations")
+    (autoload 'make-display-table "disp-table")
+    (autoload 'pp "pp")
+    (autoload 'ps-despool "ps-print" nil t)
+    (autoload 'ps-spool-buffer "ps-print" nil t)
+    (autoload 'ps-spool-buffer-with-faces "ps-print" nil t)
+    (autoload 'read-passwd "passwd")
+    (autoload 'regexp-opt "regexp-opt")
+    (autoload 'reporter-submit-bug-report "reporter")
+    (if (condition-case nil
+           (progn
+             (require 'rot13)
+             (not (fboundp 'rot13-string)))
+         (error nil))
+       (defmacro rot13-string (string)
+         "Return ROT13 encryption of STRING."
+         `(let ((string ,string))
+            (with-temp-buffer
+              (insert string)
+              (translate-region (point-min) (point-max) ,rot13-display-table)
+              (buffer-string)))))
+    (if (and (emacs-version>= 21 5)
+            (not (featurep 'sxemacs)))
+       (autoload 'setenv "process" nil t)
+      (autoload 'setenv "env" nil t))
+    (autoload 'sgml-mode "psgml" nil t)
+    (autoload 'smtpmail-send-it "smtpmail")
+    (autoload 'sort-numeric-fields "sort" nil t)
+    (autoload 'sort-subr "sort")
+    (autoload 'thing-at-point "thingatpt")
+    (autoload 'toggle-truncate-lines "view-less" nil t)
+    (autoload 'trace-function-background "trace" nil t)
+    (autoload 'unmorse-region "morse" nil t)
+    (defalias 'frame-char-height 'frame-height)
+    (defalias 'frame-char-width 'frame-width)
+    (defalias 'frame-parameter 'frame-property)
+    (defalias 'replace-dehighlight 'ignore)
+    (defalias 'replace-highlight 'ignore)
+    (defalias 'gnutls-available-p 'ignore)
+    (defvar timer-list nil)
+    (defvar scroll-margin 0)
+    (dolist (fn '(copy-overlay
+                 delete-overlay make-overlay move-overlay next-overlay-change
+                 overlay-buffer overlay-end overlay-get overlay-lists
+                 overlay-properties overlay-put overlay-recenter overlay-start
+                 overlayp overlays-at overlays-in previous-overlay-change
+                 remove-overlays))
+      (autoload fn "overlay"))))
+
+(defun dgnushack-emacs-compile-defcustom-p ()
+  "Return non-nil if Emacs byte compiles `defcustom' forms.
+Those Emacsen will warn against undefined variables and functions used
+in `defcustom' forms."
+  (let ((outbuf (with-temp-buffer
+                 (insert "(defcustom foo (1+ (random)) \"\" :group 'emacs)\n")
+                 (byte-compile-from-buffer (current-buffer) "foo.el"))))
+    (when outbuf
+      (prog1
+         (with-current-buffer outbuf
+           (goto-char (point-min))
+           (search-forward " 'foo '(byte-code " nil t))
+       (kill-buffer outbuf)))))
+
+(when (and (featurep 'xemacs)
+          (dgnushack-emacs-compile-defcustom-p))
+  (maybe-fbind '(defined-colors face-attribute))
+  (maybe-bind '(idna-program installation-directory)))
+
+(when (featurep 'xemacs)
+  (defadvice byte-optimize-apply (before use-mapcan (form) activate)
+    "Replace (apply 'nconc (mapcar ...)) with (mapcan ...)."
+    (let ((last (nth (1- (length form)) form)))
+      (when (and (eq last (third form))
+                (consp last)
+                (eq 'mapcar (car last))
+                (member (nth 1 form) '('nconc #'nconc)))
+       (setq form (cons 'mapcan (cdr last)))))))
+
+(if (featurep 'emacs)
+    (defun dgnushack-compile-file (file)
+      "Byte-compile FILE after reporting that it's being compiled."
+      (message "Compiling %s..." (file-name-nondirectory file))
+      ;; The Emacs 25 version of it doesn't say much.
+      (byte-compile-file file))
+  (defalias 'dgnushack-compile-file 'byte-compile-file))
+
+(defun dgnushack-compile-verbosely ()
+  "Call dgnushack-compile with warnings ENABLED.  If you are compiling
+patches to gnus, you should consider modifying make.bat to call
+dgnushack-compile-verbosely.  All other users should continue to use
+dgnushack-compile."
+  (dgnushack-compile t))
+
+(defun dgnushack-compile-error-on-warn ()
+  "Call dgnushack-compile with minimal warnings, but with error-on-warn ENABLED.
+This means that every warning will be reported as an error."
+  (unless (dgnushack-compile nil t)
+    (error "Error during byte compilation (warnings were reported as errors!).")))
+
+(defun dgnushack-compile (&optional warn error-on-warn)
+  ;;(setq byte-compile-dynamic t)
+  (unless warn
+    (setq byte-compile-warnings
+         '(free-vars unresolved callargs redefine suspicious)))
+  (let ((files (directory-files srcdir nil "^[^=].*\\.el$"))
+       (compilesuccess t)
+       ;;(byte-compile-generate-call-tree t)
+       file elc)
+    ;; Avoid barfing (from gnus-xmas) because the etc directory is not yet
+    ;; installed.
+    (when (featurep 'xemacs)
+      (setq gnus-xmas-glyph-directory "dummy"))
+    (dolist (file '(".dir-locals.el" "dgnushack.el" "lpath.el"))
+      (setq files (delete file files)))
+    (when (featurep 'base64)
+      (setq files (delete "base64.el" files)))
+    (condition-case code
+       ;; Under XEmacs 21.4 this loads easy-mmode.elc that provides
+       ;; the Emacs functions `propertize' and `replace-regexp-in-string'.
+       (require 'mh-e)
+      (error
+       (message "No mh-e: %s %s" (cadr code) (or (locate-library "mh-e") ""))
+       (setq files (delete "gnus-mh.el" files))))
+    (condition-case code
+       (require 'xml)
+      (error
+       (message "No xml: %s %s" (cadr code) (or (locate-library "xml") ""))
+       (setq files (delete "nnrss.el" files))))
+    (dolist (file
+            (if (featurep 'xemacs)
+                '("md5.el")
+              '("gnus-xmas.el" "messagexmas.el" "nnheaderxm.el")))
+      (setq files (delete file files)))
+    (unless (and (fboundp 'libxml-parse-html-region)
+                ;; lpath.el binds it.
+                (not (eq (symbol-function 'libxml-parse-html-region)
+                         'ignore)))
+      (dolist (file '("color.el"))
+       (setq files (delete file files))))
+    (unless (locate-library "epg")
+      (setq files (delete "plstore.el" files)))
+    ;; Temporary code until we fix pcase and defmethod stuff.
+    (when (or (featurep 'xemacs)
+             (or (< emacs-major-version 24)
+                 (< emacs-minor-version 3)))
+      (setq files (delete "gnus-icalendar.el" files))
+      ;; Temporary during development.
+      (setq files (delete "gnus-cloud.el" files)))
+    ;; Prefer XEmacs mail-lib pkg if installed
+    (when (and (featurep 'xemacs)
+              (locate-library "mail-lib/_pkg"))
+      (dolist (file
+              '("rfc2104.el" "netrc.el" "pop3.el" "starttls.el" "tls.el"))
+       (setq files (delete file files))))
+    ;; Prefer XEmacs ecrypto pkg if installed
+    (when (and (featurep 'xemacs)
+              (locate-library "ecrypto/_pkg"))
+      (dolist (file '("md4.el" "sha1.el" "hex-util.el"))
+       (setq files (delete file files))))
+    ;; Prefer XEmacs net-utils pkg if installed
+    (when (and (featurep 'xemacs)
+              (locate-library "net-utils/_pkg"))
+      (dolist (file '("dig.el" "dns.el" "dns-mode.el"))
+       (setq files (delete file files))))
+    ;; Prefer XEmacs text-modes pkg if installed
+    (when (and (featurep 'xemacs)
+              (locate-library "text-modes/_pkg"))
+      (setq files (delete "format-spec.el" files)))
+    (dolist (file files)
+      (setq file (expand-file-name file srcdir))
+      (when (and (file-exists-p
+                 (setq elc (concat (file-name-nondirectory file) "c")))
+                (file-newer-than-file-p file elc))
+       (delete-file elc)))
+
+    (while (setq file (pop files))
+      (setq file (expand-file-name file srcdir))
+      (when (or (not (file-exists-p
+                     (setq elc (concat (file-name-nondirectory file) "c"))))
+               (file-newer-than-file-p file elc))
+       (if error-on-warn
+           (let ((byte-compile-error-on-warn t))
+             (unless (ignore-errors
+                       (dgnushack-compile-file file))
+               (setq compilesuccess nil)))
+         (ignore-errors
+           (dgnushack-compile-file file)))))
+    compilesuccess))
+
+(defun dgnushack-recompile ()
+  (require 'gnus)
+  (byte-recompile-directory "." 0))
+
+(defvar dgnushack-gnus-load-file
+  (if (featurep 'xemacs)
+      (expand-file-name "auto-autoloads.el")
+    (expand-file-name "gnus-load.el")))
+
+(defvar        dgnushack-cus-load-file
+  (if (featurep 'xemacs)
+      (expand-file-name "custom-load.el")
+    (expand-file-name "cus-load.el")))
+
+(defun dgnushack-make-cus-load ()
+  (load "cus-dep")
+  (let ((cusload-base-file dgnushack-cus-load-file))
+    (defadvice directory-files (after exclude-dir-locals activate)
+      "Exclude .dir-locals.el file."
+      (dolist (file ad-return-value)
+       (if (string-match "\\(?:\\`\\|/\\)\\.dir-locals\\.el\\'" file)
+           (setq ad-return-value (delete file ad-return-value)))))
+    (unwind-protect
+       (if (fboundp 'custom-make-dependencies)
+           (custom-make-dependencies)
+         (Custom-make-dependencies))
+      (ad-unadvise 'directory-files))
+    (when (featurep 'xemacs)
+      (message "Compiling %s..." dgnushack-cus-load-file)
+      (byte-compile-file dgnushack-cus-load-file))))
+
+(defun dgnushack-make-auto-load ()
+  (require 'autoload)
+  (let ((generated-autoload-file dgnushack-gnus-load-file)
+       (make-backup-files nil)
+       (autoload-package-name "gnus"))
+    (if (featurep 'xemacs)
+       (if (file-exists-p generated-autoload-file)
+           (delete-file generated-autoload-file))
+      (with-temp-file generated-autoload-file
+       (insert ?\014)))
+    (defadvice directory-files (after exclude-dir-locals activate)
+      "Exclude .dir-locals.el file."
+      (dolist (file ad-return-value)
+       (if (string-match "\\(?:\\`\\|/\\)\\.dir-locals\\.el\\'" file)
+           (setq ad-return-value (delete file ad-return-value)))))
+    (unwind-protect
+       (batch-update-autoloads)
+      (ad-unadvise 'directory-files))))
+
+(defun dgnushack-make-load ()
+  (unless (featurep 'xemacs)
+    (message "Generating %s..." dgnushack-gnus-load-file)
+    (with-temp-file dgnushack-gnus-load-file
+      (insert-file-contents dgnushack-cus-load-file)
+      (delete-file dgnushack-cus-load-file)
+      (goto-char (point-min))
+      (search-forward ";;; Code:")
+      (forward-line)
+      (delete-region (point-min) (point))
+      (insert "\
+;;; gnus-load.el --- automatically extracted custom dependencies and autoload
+;;
+;;; Code:
+")
+      (goto-char (point-max))
+      (if (search-backward "custom-versions-load-alist" nil t)
+         (forward-line -1)
+       (forward-line -1)
+       (while (eq (char-after) ?\;)
+         (forward-line -1))
+       (forward-line))
+      (delete-region (point) (point-max))
+      (insert "\n")
+      ;; smiley-* are duplicated. Remove them all.
+      (let ((point (point)))
+       (insert-file-contents dgnushack-gnus-load-file)
+       (goto-char point)
+       (while (search-forward "smiley-" nil t)
+         (beginning-of-line)
+         (if (looking-at "(autoload ")
+             (delete-region (point) (progn (forward-sexp) (point)))
+           (forward-line))))
+      ;;
+      (goto-char (point-max))
+      (when (search-backward "\n(provide " nil t)
+       (forward-line -1)
+       (delete-region (point) (point-max)))
+      (insert "\
+
+\(provide 'gnus-load)
+
+;;; Local Variables:
+;;; version-control: never
+;;; no-byte-compile: t
+;;; no-update-autoloads: t
+;;; End:
+;;; gnus-load.el ends here
+")
+      ))
+  (message "Compiling %s..." dgnushack-gnus-load-file)
+  (byte-compile-file dgnushack-gnus-load-file)
+  (when (featurep 'xemacs)
+    (message "Creating dummy gnus-load.el...")
+    (with-temp-file (expand-file-name "gnus-load.el")
+      (insert "\
+
+\(provide 'gnus-load)
+
+;;; Local Variables:
+;;; version-control: never
+;;; no-byte-compile: t
+;;; no-update-autoloads: t
+;;; End:
+;;; gnus-load.el ends here"))))
+
+(defun dgnushack-find-lisp-shadows (&optional lispdir)
+  "Return a list of directories in which other Gnus installations exist.
+This function looks for the other Gnus installations which will shadow
+the new Gnus Lisp modules which have been installed in LISPDIR, using
+the default `load-path'.  The return value will make sense only when
+LISPDIR is existent and is listed in the default `load-path'.  Assume
+LISPDIR will be prepended to `load-path' by a user if the default
+`load-path' does not contain it."
+  (unless lispdir
+    (setq lispdir (getenv "lispdir")))
+  (when (and lispdir (file-directory-p lispdir))
+    (setq lispdir (file-truename (directory-file-name lispdir)))
+    (let ((indices '("gnus.elc" "gnus.el" "gnus.el.bz2" "gnus.el.gz"
+                    "message.elc" "message.el" "message.el.bz2"
+                    "message.el.gz"))
+         (path (delq nil (mapcar
+                          (lambda (p)
+                            (condition-case nil
+                                (when (and p (file-directory-p p))
+                                  (file-truename (directory-file-name p)))
+                              (error nil)))
+                          dgnushack-default-load-path)))
+         rest elcs)
+      (while path
+       (setq rest (cons (car path) rest)
+             path (delete (car rest) (cdr path))))
+      (setq path (nreverse (cdr (member lispdir rest)))
+           rest nil)
+      (while path
+       (setq elcs indices)
+       (while elcs
+         (when (file-exists-p (expand-file-name (pop elcs) (car path)))
+           (setq rest (cons (car path) rest)
+                 elcs nil)))
+       (setq path (cdr path)))
+      (prog1
+         (setq path (nreverse rest))
+       (when path
+         (let (print-level print-length)
+           (princ (concat "\n\
+WARNING: The other Gnus installation" (if (cdr path) "s have" " has") "\
+ been detected in:\n\n  " (mapconcat 'identity path "\n  ") "\n\n\
+You will need to modify the run-time `load-path', remove them manually,
+or remove them using `make remove-installed-shadows'.\n\n"))))))))
+
+(defun dgnushack-remove-lisp-shadows (&optional lispdir)
+  "Remove the other Gnus installations which shadow the recent one."
+  (let ((path (with-temp-buffer
+               (let ((standard-output (current-buffer)))
+                 (dgnushack-find-lisp-shadows lispdir))))
+       elcs files shadows file)
+    (when path
+      (unless (setq elcs (directory-files srcdir nil "\\.elc\\'"))
+       (error "You should build .elc files first."))
+      (setq files
+           (apply
+            'append
+            (mapcar
+             (lambda (el)
+               (list (concat el "c") el (concat el ".bz2") (concat el ".gz")))
+             (append
+              (list (file-name-nondirectory dgnushack-gnus-load-file)
+                    (file-name-nondirectory dgnushack-cus-load-file))
+              (mapcar (lambda (elc) (substring elc 0 -1)) elcs)))))
+      (while path
+       (setq shadows files)
+       (while shadows
+         (setq file (expand-file-name (pop shadows) (car path)))
+         (when (file-exists-p file)
+           (princ (concat "  Removing " file "..."))
+           (condition-case nil
+               (progn
+                 (delete-file file)
+                 (princ "done\n"))
+             (error (princ "failed\n")))))
+       (setq path (cdr path))))))
+
+(unless (fboundp 'with-demoted-errors)
+  (defmacro with-demoted-errors (&rest body)
+    "Run BODY and demote any errors to simple messages.
+If `debug-on-error' is non-nil, run BODY without catching its errors.
+This is to be used around code which is not expected to signal an error
+but which should be robust in the unexpected case that an error is signaled."
+    (declare (debug t) (indent 0))
+    (let ((err (make-symbol "err")))
+      `(condition-case ,err
+          (progn ,@body)
+        (error (message "Error: %S" ,err) nil)))))
+
+;; `define-obsolete-function-alias' and `define-obsolete-variable-alias'
+;; take only two arguments in XEmacs:
+;; (define-obsolete-function-alias OLDFUN NEWFUN)
+;; (define-obsolete-variable-alias OLDVAR NEWVAR)
+(condition-case nil
+    (define-obsolete-function-alias
+      'dgnushack-obsolete-name 'dgnushack-current-name "0")
+  (wrong-number-of-arguments
+   (defadvice define-obsolete-function-alias (around ignore-rest-args
+                                                    (oldfun newfun &rest args)
+                                                    activate)
+     "Ignore arguments other than the 1st and the 2nd ones."
+     ad-do-it)
+   (put 'define-obsolete-function-alias 'byte-optimizer
+       (lambda (form)
+         (setcdr (nthcdr 2 form) nil)
+         form))))
+(condition-case nil
+    (define-obsolete-variable-alias
+      'dgnushack-obsolete-name 'dgnushack-current-name "0")
+  (wrong-number-of-arguments
+   (defadvice define-obsolete-variable-alias (around ignore-rest-args
+                                                    (oldvar newvar &rest args)
+                                                    activate)
+     "Ignore arguments other than the 1st and the 2nd ones."
+     ad-do-it)
+   (put 'define-obsolete-variable-alias 'byte-optimizer
+       (lambda (form)
+         (setcdr (nthcdr 2 form) nil)
+         form))))
+
+;;; dgnushack.el ends here
diff --git a/xemacs-packages/gnus/lisp/dig.el b/xemacs-packages/gnus/lisp/dig.el
new file mode 100644 (file)
index 0000000..02cb627
--- /dev/null
@@ -0,0 +1,185 @@
+;;; dig.el --- Domain Name System dig interface
+
+;; Copyright (C) 2000-2016 Free Software Foundation, Inc.
+
+;; Author: Simon Josefsson <simon@josefsson.org>
+;; Keywords: DNS BIND dig comm
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This provide an interface for "dig".
+;;
+;; For interactive use, try M-x dig and type a hostname.  Use `q' to quit
+;; dig buffer.
+;;
+;; 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))
+
+(defgroup dig nil
+  "Dig configuration."
+  :group 'comm)
+
+(defcustom dig-program "dig"
+  "Name of dig (domain information groper) binary."
+  :type 'file
+  :group 'dig)
+
+(defcustom dig-dns-server nil
+  "DNS server to query.
+If nil, use system defaults."
+  :type '(choice (const :tag "System defaults")
+                string)
+  :group 'dig)
+
+(defcustom dig-font-lock-keywords
+  '(("^;; [A-Z]+ SECTION:" 0 font-lock-keyword-face)
+    ("^;;.*" 0 font-lock-comment-face)
+    ("^; <<>>.*" 0 font-lock-type-face)
+    ("^;.*" 0 font-lock-function-name-face))
+  "Default expressions to highlight in dig mode."
+  :type 'sexp
+  :group 'dig)
+
+(defun dig-invoke (domain &optional
+                         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 with a DNS type.  QUERY-CLASS is an optional string with a DNS
+class.  QUERY-OPTION is an optional string with dig \"query options\".
+DIG-OPTION is an optional string with parameters for the dig program.
+SERVER is an optional string with a domain name server to query.
+
+Dig is an external program found in the BIND name server distribution,
+and is a commonly available debugging tool."
+  (let (buf cmdline)
+    (setq buf (generate-new-buffer "*dig output*"))
+    (if dig-option (push dig-option cmdline))
+    (if query-option (push query-option cmdline))
+    (if query-class (push query-class cmdline))
+    (if query-type (push query-type cmdline))
+    (push domain cmdline)
+    (if server (push (concat "@" server) cmdline)
+      (if dig-dns-server (push (concat "@" dig-dns-server) cmdline)))
+    (apply 'call-process dig-program nil buf nil cmdline)
+    buf))
+
+(defun dig-extract-rr (domain &optional type class)
+  "Extract resource records for DOMAIN, TYPE and CLASS from buffer.
+Buffer should contain output generated by `dig-invoke'."
+  (save-excursion
+    (goto-char (point-min))
+    (if (re-search-forward
+        (concat domain "\\.?[\t ]+[0-9wWdDhHmMsS]+[\t ]+"
+                (upcase (or class "IN")) "[\t ]+" (upcase (or type "A")))
+        nil t)
+       (let (b e)
+         (end-of-line)
+         (setq e (point))
+         (beginning-of-line)
+         (setq b (point))
+         (when (search-forward " (" e t)
+           (search-forward " )"))
+         (end-of-line)
+         (setq e (point))
+         (buffer-substring b e))
+      (and (re-search-forward (concat domain "\\.?[\t ]+[0-9wWdDhHmMsS]+[\t ]+"
+                                     (upcase (or class "IN"))
+                                     "[\t ]+CNAME[\t ]+\\(.*\\)$") nil t)
+          (dig-extract-rr (match-string 1) type class)))))
+
+(defun dig-rr-get-pkix-cert (rr)
+  (let (b e str)
+    (string-match "[^\t ]+[\t ]+[0-9wWdDhHmMsS]+[\t ]+IN[\t ]+CERT[\t ]+\\(1\\|PKIX\\)[\t ]+[0-9]+[\t ]+[0-9]+[\t ]+(?" rr)
+    (setq b (match-end 0))
+    (string-match ")" rr)
+    (setq e (match-beginning 0))
+    (setq str (substring rr b e))
+    (while (string-match "[\t \n\r]" str)
+      (setq str (replace-match "" nil nil str)))
+    str))
+
+;; XEmacs does it like this.  For Emacs, we have to set the
+;; `font-lock-defaults' buffer-local variable.
+(put 'dig-mode 'font-lock-defaults '(dig-font-lock-keywords t))
+
+(put 'dig-mode 'mode-class 'special)
+
+(defvar dig-mode-map
+  (let ((map (make-sparse-keymap)))
+    (suppress-keymap map)
+    (define-key map "q" 'dig-exit)
+    map))
+
+(define-derived-mode dig-mode nil "Dig"
+  "Major mode for displaying dig output."
+  (buffer-disable-undo)
+  (unless (featurep 'xemacs)
+    (set (make-local-variable 'font-lock-defaults)
+        '(dig-font-lock-keywords t)))
+  (when (featurep 'font-lock)
+    ;; FIXME: what is this for??  --Stef
+    (font-lock-set-defaults))
+  )
+
+(defun dig-exit ()
+  "Quit dig output buffer."
+  (interactive)
+  (kill-buffer (current-buffer)))
+
+;;;###autoload
+(defun dig (domain &optional
+                  query-type query-class query-option dig-option server)
+  "Query addresses of a DOMAIN using dig, by calling `dig-invoke'.
+Optional arguments are passed to `dig-invoke'."
+  (interactive "sHost: ")
+  (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)
+       (forward-line))
+  (dig-mode)
+  (setq buffer-read-only t)
+  (set-buffer-modified-p nil))
+
+;; named for consistency with query-dns in dns.el
+(defun query-dig (domain &optional
+                        query-type query-class query-option dig-option server)
+  "Query addresses of a DOMAIN using dig.
+It works by calling `dig-invoke' and `dig-extract-rr'.
+Optional arguments are passed to `dig-invoke' and `dig-extract-rr'.
+Returns nil for domain/class/type queries that result in no data."
+(let ((buffer (dig-invoke domain query-type query-class
+                         query-option dig-option server)))
+  (when buffer
+    (switch-to-buffer buffer)
+    (let ((digger (dig-extract-rr domain query-type query-class)))
+      (kill-buffer buffer)
+      digger))))
+
+(provide 'dig)
+
+;;; dig.el ends here
diff --git a/xemacs-packages/gnus/lisp/dns-mode.el b/xemacs-packages/gnus/lisp/dns-mode.el
new file mode 100644 (file)
index 0000000..521b1f3
--- /dev/null
@@ -0,0 +1,221 @@
+;;; dns-mode.el --- a mode for viewing/editing Domain Name System master files
+
+;; Copyright (C) 2000-2001, 2004-2016 Free Software Foundation, Inc.
+
+;; Author: Simon Josefsson <simon@josefsson.org>
+;; Keywords: DNS master zone file SOA comm
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Use M-x dns-mode RET to invoke in master files.
+;;
+;; C-c C-s  Increment SOA serial.
+;;          Understands YYYYMMDDNN, Unix time, and serial number formats,
+;;          and complains if it fail to find SOA serial.
+
+;;; References:
+
+;; RFC 1034, "DOMAIN NAMES - CONCEPTS AND FACILITIES", P. Mockapetris.
+;; RFC 1035, "DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION", P. Mockapetris.
+
+;;; Release history:
+
+;; 2004-09-11  Posted on gnu.emacs.sources.
+;; 2004-09-13  Ported to XEmacs.
+;; 2004-09-14  Installed in Emacs CVS.
+
+;;; Code:
+
+(defgroup dns-mode nil
+  "DNS master file mode configuration."
+  :group 'data)
+
+(defconst dns-mode-classes '("IN" "CS" "CH" "HS")
+  "List of strings with known DNS classes.")
+
+(defconst dns-mode-types '("A" "NS" "MD" "MF" "CNAME" "SOA" "MB" "MG" "MR"
+                          "NULL" "WKS" "PTR" "HINFO" "MINFO" "MX" "TXT"
+                          "RP" "AFSDB" "X25" "ISDN" "RT" "NSAP" "NSAP"
+                          "SIG" "KEY" "PX" "GPOS" "AAAA" "LOC" "NXT"
+                          "EID" "NIMLOC" "SRV" "ATMA" "NAPTR" "KX" "CERT"
+                          "A6" "DNAME" "SINK" "OPT" "APL" "DS" "SSHFP"
+                          "RRSIG" "NSEC" "DNSKEY" "UINFO" "UID" "GID"
+                          "UNSPEC" "TKEY" "TSIG" "IXFR" "AXFR" "MAILB"
+                          "MAILA")
+  "List of strings with known DNS types.")
+
+;; Font lock.
+
+(defvar dns-mode-control-entity-face 'font-lock-keyword-face
+  "Name of face used for control entities, e.g. $ORIGIN.")
+
+(defvar dns-mode-bad-control-entity-face 'font-lock-warning-face
+  "Name of face used for non-standard control entities, e.g. $FOO.")
+
+(defvar dns-mode-type-face 'font-lock-type-face
+  "Name of face used for DNS types, e.g., SOA.")
+
+(defvar dns-mode-class-face 'font-lock-constant-face
+  "Name of face used for DNS classes, e.g., IN.")
+
+(defcustom dns-mode-font-lock-keywords
+  `(("^$ORIGIN" 0 ,dns-mode-control-entity-face)
+    ("^$INCLUDE" 0 ,dns-mode-control-entity-face)
+    ("^$[a-z0-9A-Z]+" 0 ,dns-mode-bad-control-entity-face)
+    (,(regexp-opt dns-mode-classes) 0 ,dns-mode-class-face)
+    (,(regexp-opt dns-mode-types) 0 ,dns-mode-type-face))
+  "Font lock keywords used to highlight text in DNS master file mode."
+  :type 'sexp
+  :group 'dns-mode)
+
+(defcustom dns-mode-soa-auto-increment-serial t
+  "Whether to increment the SOA serial number automatically.
+
+If this variable is t, the serial number is incremented upon each save of
+the file.  If it is `ask', Emacs asks for confirmation whether it should
+increment the serial upon saving.  If nil, serials must be incremented
+manually with \\[dns-mode-soa-increment-serial]."
+  :type '(choice (const :tag "Always" t)
+                (const :tag "Ask" ask)
+                (const :tag "Never" nil))
+  :group 'dns-mode)
+
+;; Syntax table.
+
+(defvar dns-mode-syntax-table
+  (let ((table (make-syntax-table)))
+    (modify-syntax-entry ?\; "<   " table)
+    (modify-syntax-entry ?\n ">   " table)
+    table)
+  "Syntax table in use in DNS master file buffers.")
+
+;; Keymap.
+
+(defvar dns-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "\C-c\C-s" 'dns-mode-soa-increment-serial)
+    map)
+  "Keymap for DNS master file mode.")
+
+;; Menu.
+
+(defvar dns-mode-menu nil
+  "Menubar used in DNS master file mode.")
+
+(easy-menu-define dns-mode-menu dns-mode-map
+  "DNS Menu."
+  '("DNS"
+    ["Increment SOA serial" dns-mode-soa-increment-serial t]))
+
+;; Mode.
+
+;;;###autoload
+(define-derived-mode dns-mode text-mode "DNS"
+  "Major mode for viewing and editing DNS master files.
+This mode is inherited from text mode.  It add syntax
+highlighting, and some commands for handling DNS master files.
+Its keymap inherits from `text-mode' and it has the same
+variables for customizing indentation.  It has its own abbrev
+table and its own syntax table.
+
+Turning on DNS mode runs `dns-mode-hook'."
+  (set (make-local-variable 'comment-start) ";")
+  (set (make-local-variable 'comment-end) "")
+  (set (make-local-variable 'comment-start-skip) ";+ *")
+  (unless (featurep 'xemacs)
+    (set (make-local-variable 'font-lock-defaults)
+        '(dns-mode-font-lock-keywords nil nil ((?_ . "w")))))
+  (add-hook 'before-save-hook 'dns-mode-soa-maybe-increment-serial
+           nil t)
+  (easy-menu-add dns-mode-menu dns-mode-map))
+
+;;;###autoload (defalias 'zone-mode 'dns-mode)
+
+;; Tools.
+
+;;;###autoload
+(defun dns-mode-soa-increment-serial ()
+  "Locate SOA record and increment the serial field."
+  (interactive)
+  (save-excursion
+    (goto-char (point-min))
+    (unless (re-search-forward
+            (concat "^\\(\\(\\([^ \t]+[ \t]+\\)?[^ \t]+"
+                    "[ \t]+\\)?[^ \t]+[ \t]+\\)?SOA") nil t)
+      (error "Cannot locate SOA record"))
+    (if (re-search-forward (concat "\\<\\("
+                                  ;; year
+                                  "\\(198\\|199\\|20[0-9]\\)[0-9]"
+                                  ;; month
+                                  "\\(0[0-9]\\|10\\|11\\|12\\)"
+                                  ;; day
+                                  "\\([012][0-9]\\|30\\|31\\)"
+                                  ;; counter
+                                  "\\([0-9]\\{1,3\\}\\)"
+                                  "\\)\\>")
+                          nil t)
+       ;; YYYYMMDDIII format, one to three I's.
+       (let* ((serial (match-string 1))
+              (counterstr (match-string 5))
+              (counter (string-to-number counterstr))
+              (now (format-time-string "%Y%m%d"))
+              (nowandoldserial (concat now counterstr)))
+         (if (string< serial nowandoldserial)
+             (let ((new (format "%s00" now)))
+               (replace-match new nil nil nil 1)
+               (message "Replaced old serial %s with %s" serial new))
+           (if (string= serial nowandoldserial)
+               (let ((new (format (format "%%s%%0%dd" (length counterstr))
+                                  now (1+ counter))))
+                 (replace-match new nil nil nil 1)
+                 (message "Replaced old serial %s with %s" serial new))
+             (error "Current SOA serial is in the future"))))
+      (if (re-search-forward "\\<\\([0-9]\\{9,10\\}\\)\\>" nil t)
+         ;; Unix time
+         (let* ((serial (match-string 1))
+                (new (format-time-string "%s")))
+           (if (not (string< serial new))
+               (error "Current SOA serial is in the future")
+             (replace-match new nil nil nil 1)
+             (message "Replaced old serial %s with %s" serial new)))
+       (if (re-search-forward "\\<\\([0-9]+\\)\\>" nil t)
+           ;; Just any serial number.
+           (let* ((serial (match-string 1))
+                  (new (format "%d" (1+ (string-to-number serial)))))
+             (replace-match new nil nil nil 1)
+             (message "Replaced old serial %s with %s" serial new))
+         (error "Cannot locate serial number in SOA record"))))))
+
+(defun dns-mode-soa-maybe-increment-serial ()
+  "Increment SOA serial if needed.
+
+This function is run from `before-save-hook'."
+  (when (and (buffer-modified-p)
+            dns-mode-soa-auto-increment-serial
+            (or (eq dns-mode-soa-auto-increment-serial t)
+                (y-or-n-p "Increment SOA serial? ")))
+    ;; If `dns-mode-soa-increment-serial' signals an error saving will
+    ;; fail but that probably means that the serial should be fixed to
+    ;; comply with the RFC anyway! -rfr
+    (progn (dns-mode-soa-increment-serial)
+          ;; We return nil in case this is used in write-contents-functions.
+          nil)))
+
+(provide 'dns-mode)
+
+;;; dns-mode.el ends here
diff --git a/xemacs-packages/gnus/lisp/dns.el b/xemacs-packages/gnus/lisp/dns.el
new file mode 100644 (file)
index 0000000..487cfc9
--- /dev/null
@@ -0,0 +1,459 @@
+;;; dns.el --- Domain Name Service lookups
+
+;; Copyright (C) 2002-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: network comm
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(defvar dns-timeout 5
+  "How many seconds to wait when doing DNS queries.")
+
+(defvar dns-servers nil
+  "List of DNS servers to query.
+If nil, /etc/resolv.conf and nslookup will be consulted.")
+
+(defvar dns-servers-valid-for-interfaces nil
+  "The return value of `network-interface-list' when `dns-servers' was set.
+If the set of network interfaces and/or their IP addresses
+change, then presumably the list of DNS servers needs to be
+updated.  Set this variable to t to disable the check.")
+
+;;; Internal code:
+
+(defvar dns-query-types
+  '((A 1)
+    (NS 2)
+    (MD 3)
+    (MF 4)
+    (CNAME 5)
+    (SOA 6)
+    (MB 7)
+    (MG 8)
+    (MR 9)
+    (NULL 10)
+    (WKS 11)
+    (PTR 12)
+    (HINFO 13)
+    (MINFO 14)
+    (MX 15)
+    (TXT 16)
+    (AAAA 28) ; RFC3596
+    (SRV 33) ; RFC2782
+    (AXFR 252)
+    (MAILB 253)
+    (MAILA 254)
+    (* 255))
+  "Names of query types and their values.")
+
+(defvar dns-classes
+  '((IN 1)
+    (CS 2)
+    (CH 3)
+    (HS 4))
+  "Classes of queries.")
+
+(defun dns-write-bytes (value &optional length)
+  (let (bytes)
+    (dotimes (i (or length 1))
+      (push (% value 256) bytes)
+      (setq value (/ value 256)))
+    (dolist (byte bytes)
+      (insert byte))))
+
+(defun dns-read-bytes (length)
+  (let ((value 0))
+    (dotimes (i length)
+      (setq value (logior (* value 256) (following-char)))
+      (forward-char 1))
+    value))
+
+(defun dns-get (type spec)
+  (cadr (assq type spec)))
+
+(defun dns-inverse-get (value spec)
+  (let ((found nil))
+    (while (and (not found)
+               spec)
+      (if (eq value (cadr (car spec)))
+         (setq found (caar spec))
+       (pop spec)))
+    found))
+
+(defun dns-write-name (name)
+  (dolist (part (split-string name "\\."))
+    (dns-write-bytes (length part))
+    (insert part))
+  (dns-write-bytes 0))
+
+(defun dns-read-string-name (string buffer)
+  (with-temp-buffer
+    (unless (featurep 'xemacs) (set-buffer-multibyte nil))
+    (insert string)
+    (goto-char (point-min))
+    (dns-read-name buffer)))
+
+(defun dns-read-name (&optional buffer)
+  (let ((ended nil)
+       (name nil)
+       length)
+    (while (not ended)
+      (setq length (dns-read-bytes 1))
+      (if (= 192 (logand length (lsh 3 6)))
+         (let ((offset (+ (* (logand 63 length) 256)
+                          (dns-read-bytes 1))))
+           (save-excursion
+             (when buffer
+               (set-buffer buffer))
+             (goto-char (1+ offset))
+             (setq ended (dns-read-name buffer))))
+       (if (zerop length)
+           (setq ended t)
+         (push (buffer-substring (point)
+                                 (progn (forward-char length) (point)))
+               name))))
+    (if (stringp ended)
+       (if (null name)
+           ended
+         (concat (mapconcat 'identity (nreverse name) ".") "." ended))
+      (mapconcat 'identity (nreverse name) "."))))
+
+(defun dns-write (spec &optional tcp-p)
+  "Write a DNS packet according to SPEC.
+If TCP-P, the first two bytes of the package with be the length field."
+  (with-temp-buffer
+    (unless (featurep 'xemacs) (set-buffer-multibyte nil))
+    (dns-write-bytes (dns-get 'id spec) 2)
+    (dns-write-bytes
+     (logior
+      (lsh (if (dns-get 'response-p spec) 1 0) -7)
+      (lsh
+       (cond
+       ((eq (dns-get 'opcode spec) 'query) 0)
+       ((eq (dns-get 'opcode spec) 'inverse-query) 1)
+       ((eq (dns-get 'opcode spec) 'status) 2)
+       (t (error "No such opcode: %s" (dns-get 'opcode spec))))
+       -3)
+      (lsh (if (dns-get 'authoritative-p spec) 1 0) -2)
+      (lsh (if (dns-get 'truncated-p spec) 1 0) -1)
+      (lsh (if (dns-get 'recursion-desired-p spec) 1 0) 0)))
+    (dns-write-bytes
+     (cond
+      ((eq (dns-get 'response-code spec) 'no-error) 0)
+      ((eq (dns-get 'response-code spec) 'format-error) 1)
+      ((eq (dns-get 'response-code spec) 'server-failure) 2)
+      ((eq (dns-get 'response-code spec) 'name-error) 3)
+      ((eq (dns-get 'response-code spec) 'not-implemented) 4)
+      ((eq (dns-get 'response-code spec) 'refused) 5)
+      (t 0)))
+    (dns-write-bytes (length (dns-get 'queries spec)) 2)
+    (dns-write-bytes (length (dns-get 'answers spec)) 2)
+    (dns-write-bytes (length (dns-get 'authorities spec)) 2)
+    (dns-write-bytes (length (dns-get 'additionals spec)) 2)
+    (dolist (query (dns-get 'queries spec))
+      (dns-write-name (car query))
+      (dns-write-bytes (cadr (assq (or (dns-get 'type query) 'A)
+                                  dns-query-types)) 2)
+      (dns-write-bytes (cadr (assq (or (dns-get 'class query) 'IN)
+                                  dns-classes)) 2))
+    (dolist (slot '(answers authorities additionals))
+      (dolist (resource (dns-get slot spec))
+       (dns-write-name (car resource))
+      (dns-write-bytes (cadr (assq (dns-get 'type resource) dns-query-types))
+                      2)
+      (dns-write-bytes (cadr (assq (dns-get 'class resource) dns-classes))
+                      2)
+      (dns-write-bytes (dns-get 'ttl resource) 4)
+      (dns-write-bytes (length (dns-get 'data resource)) 2)
+      (insert (dns-get 'data resource))))
+    (when tcp-p
+      (goto-char (point-min))
+      (dns-write-bytes (buffer-size) 2))
+    (buffer-string)))
+
+(defun dns-read (packet)
+  (with-temp-buffer
+    (unless (featurep 'xemacs) (set-buffer-multibyte nil))
+    (let ((spec nil)
+          queries answers authorities additionals)
+      (insert packet)
+      (goto-char (point-min))
+      (push (list 'id (dns-read-bytes 2)) spec)
+      (let ((byte (dns-read-bytes 1)))
+        (push (list 'response-p (if (zerop (logand byte (lsh 1 7))) nil t))
+              spec)
+        (let ((opcode (logand byte (lsh 7 3))))
+          (push (list 'opcode
+                      (cond ((eq opcode 0) 'query)
+                            ((eq opcode 1) 'inverse-query)
+                            ((eq opcode 2) 'status)))
+                spec))
+        (push (list 'authoritative-p (if (zerop (logand byte (lsh 1 2)))
+                                         nil t)) spec)
+        (push (list 'truncated-p (if (zerop (logand byte (lsh 1 2))) nil t))
+              spec)
+        (push (list 'recursion-desired-p
+                    (if (zerop (logand byte (lsh 1 0))) nil t)) spec))
+      (let ((rc (logand (dns-read-bytes 1) 15)))
+        (push (list 'response-code
+                    (cond
+                     ((eq rc 0) 'no-error)
+                     ((eq rc 1) 'format-error)
+                     ((eq rc 2) 'server-failure)
+                     ((eq rc 3) 'name-error)
+                     ((eq rc 4) 'not-implemented)
+                     ((eq rc 5) 'refused)))
+              spec))
+      (setq queries (dns-read-bytes 2))
+      (setq answers (dns-read-bytes 2))
+      (setq authorities (dns-read-bytes 2))
+      (setq additionals (dns-read-bytes 2))
+      (let ((qs nil))
+        (dotimes (i queries)
+          (push (list (dns-read-name)
+                      (list 'type (dns-inverse-get (dns-read-bytes 2)
+                                                   dns-query-types))
+                      (list 'class (dns-inverse-get (dns-read-bytes 2)
+                                                    dns-classes)))
+                qs))
+        (push (list 'queries qs) spec))
+      (dolist (slot '(answers authorities additionals))
+        (let ((qs nil)
+              type)
+          (dotimes (i (symbol-value slot))
+            (push (list (dns-read-name)
+                        (list 'type
+                              (setq type (dns-inverse-get (dns-read-bytes 2)
+                                                          dns-query-types)))
+                        (list 'class (dns-inverse-get (dns-read-bytes 2)
+                                                      dns-classes))
+                        (list 'ttl (dns-read-bytes 4))
+                        (let ((length (dns-read-bytes 2)))
+                          (list 'data
+                                (dns-read-type
+                                 (buffer-substring
+                                  (point)
+                                  (progn (forward-char length) (point)))
+                                 type))))
+                  qs))
+          (push (list slot qs) spec)))
+      (nreverse spec))))
+
+(defun dns-read-int32 ()
+  ;; Full 32 bit Integers can't be handled by 32-bit Emacsen.  If we
+  ;; use floats, it works.
+  (format "%.0f" (+ (* (dns-read-bytes 1) 16777216.0)
+                   (dns-read-bytes 3))))
+
+(defun dns-read-type (string type)
+  (let ((buffer (current-buffer))
+       (point (point)))
+    (prog1
+        (with-temp-buffer
+         (unless (featurep 'xemacs) (set-buffer-multibyte nil))
+          (insert string)
+          (goto-char (point-min))
+          (cond
+           ((eq type 'A)
+            (let ((bytes nil))
+              (dotimes (i 4)
+                (push (dns-read-bytes 1) bytes))
+              (mapconcat 'number-to-string (nreverse bytes) ".")))
+           ((eq type 'AAAA)
+            (let (hextets)
+              (dotimes (i 8)
+                (push (dns-read-bytes 2) hextets))
+              (mapconcat (lambda (n) (format "%x" n))
+                         (nreverse hextets) ":")))
+           ((eq type 'SOA)
+            (list (list 'mname (dns-read-name buffer))
+                  (list 'rname (dns-read-name buffer))
+                  (list 'serial (dns-read-int32))
+                  (list 'refresh (dns-read-int32))
+                  (list 'retry (dns-read-int32))
+                  (list 'expire (dns-read-int32))
+                  (list 'minimum (dns-read-int32))))
+           ((eq type 'SRV)
+            (list (list 'priority (dns-read-bytes 2))
+                  (list 'weight (dns-read-bytes 2))
+                  (list 'port (dns-read-bytes 2))
+                  (list 'target (dns-read-name buffer))))
+           ((eq type 'MX)
+            (cons (dns-read-bytes 2) (dns-read-name buffer)))
+           ((or (eq type 'CNAME) (eq type 'NS) (eq type 'PTR))
+            (dns-read-string-name string buffer))
+           (t string)))
+      (goto-char point))))
+
+(declare-function network-interface-list "process.c")
+
+(defun dns-servers-up-to-date-p ()
+  "Return false if we need to recheck the list of DNS servers."
+  (and dns-servers
+       (or (eq dns-servers-valid-for-interfaces t)
+          ;; `network-interface-list' was introduced in Emacs 22.1.
+          (not (fboundp 'network-interface-list))
+          (equal dns-servers-valid-for-interfaces
+                 (network-interface-list)))))
+
+(defun dns-set-servers ()
+  "Set `dns-servers' to a list of DNS servers or nil if none are found.
+Parses \"/etc/resolv.conf\" or calls \"nslookup\"."
+  (or (when (file-exists-p "/etc/resolv.conf")
+       (setq dns-servers nil)
+       (with-temp-buffer
+         (insert-file-contents "/etc/resolv.conf")
+         (goto-char (point-min))
+         (while (re-search-forward "^nameserver[\t ]+\\([^ \t\n]+\\)" nil t)
+           (push (match-string 1) dns-servers))
+         (setq dns-servers (nreverse dns-servers))))
+      (when (executable-find "nslookup")
+       (with-temp-buffer
+         (call-process "nslookup" nil t nil "localhost")
+         (goto-char (point-min))
+         (re-search-forward
+          "^Address:[ \t]*\\([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\)" nil t)
+         (setq dns-servers (list (match-string 1))))))
+  (when (fboundp 'network-interface-list)
+    (setq dns-servers-valid-for-interfaces (network-interface-list))))
+
+(defun dns-read-txt (string)
+  (if (> (length string) 1)
+      (substring string 1)
+    string))
+
+(defun dns-get-txt-answer (answers)
+  (let ((result "")
+       (do-next nil))
+    (dolist (answer answers)
+      (dolist (elem answer)
+       (when (consp elem)
+         (cond
+          ((eq (car elem) 'type)
+           (setq do-next (eq (cadr elem) 'TXT)))
+          ((eq (car elem) 'data)
+           (when do-next
+             (setq result (concat result (dns-read-txt (cadr elem))))))))))
+    result))
+
+;;; Interface functions.
+(defmacro dns-make-network-process (server)
+  (if (featurep 'xemacs)
+      `(let ((coding-system-for-read 'binary)
+            (coding-system-for-write 'binary))
+        (open-network-stream "dns" (current-buffer)
+                             ,server "domain" 'udp))
+    `(let ((server ,server)
+          (coding-system-for-read 'binary)
+          (coding-system-for-write 'binary))
+       (if (fboundp 'make-network-process)
+          (make-network-process
+           :name "dns"
+           :coding 'binary
+           :buffer (current-buffer)
+           :host server
+           :service "domain"
+           :type 'datagram)
+        ;; Older versions of Emacs doesn't have
+        ;; `make-network-process', so we fall back on opening a TCP
+        ;; connection to the DNS server.
+        (open-network-stream "dns" (current-buffer) server "domain")))))
+
+(defvar dns-cache (make-vector 4096 0))
+
+(defun dns-query-cached (name &optional type fullp reversep)
+  (let* ((key (format "%s:%s:%s:%s" name type fullp reversep))
+        (sym (intern-soft key dns-cache)))
+    (if (and sym
+            (boundp sym))
+       (symbol-value sym)
+      (let ((result (dns-query name type fullp reversep)))
+       (set (intern key dns-cache) result)
+       result))))
+
+;; The old names `query-dns' and `query-dns-cached' weren't used in Emacs 23
+;; yet, so no alias are provided.  --rsteib
+
+(defun dns-query (name &optional type fullp reversep)
+  "Query a DNS server for NAME of TYPE.
+If FULLP, return the entire record returned.
+If REVERSEP, look up an IP address."
+  (setq type (or type 'A))
+  (unless (dns-servers-up-to-date-p)
+    (dns-set-servers))
+
+  (when reversep
+    (setq name (concat
+               (mapconcat 'identity (nreverse (split-string name "\\.")) ".")
+               ".in-addr.arpa")
+         type 'PTR))
+
+  (if (not dns-servers)
+      (message "No DNS server configuration found")
+    (with-temp-buffer
+      (unless (featurep 'xemacs) (set-buffer-multibyte nil))
+      (let ((process (condition-case ()
+                         (dns-make-network-process (car dns-servers))
+                       (error
+                        (message
+                         "dns: Got an error while trying to talk to %s"
+                         (car dns-servers))
+                        nil)))
+            (tcp-p (and (not (fboundp 'make-network-process))
+                        (not (featurep 'xemacs))))
+            (step 100)
+            (times (* dns-timeout 1000))
+            (id (random 65000)))
+        (when process
+          (process-send-string
+           process
+           (dns-write `((id ,id)
+                        (opcode query)
+                        (queries ((,name (type ,type))))
+                        (recursion-desired-p t))
+                      tcp-p))
+          (while (and (zerop (buffer-size))
+                      (> times 0))
+            (sit-for (/ step 1000.0))
+            (accept-process-output process 0 step)
+            (setq times (- times step)))
+          (condition-case nil
+              (delete-process process)
+            (error nil))
+          (when (and tcp-p
+                     (>= (buffer-size) 2))
+            (goto-char (point-min))
+            (delete-region (point) (+ (point) 2)))
+          (when (and (>= (buffer-size) 2)
+                     ;; We had a time-out.
+                     (> times 0))
+            (let ((result (dns-read (buffer-string))))
+              (if fullp
+                  result
+                (let ((answer (car (dns-get 'answers result))))
+                  (when (eq type (dns-get 'type answer))
+                    (if (eq type 'TXT)
+                        (dns-get-txt-answer (dns-get 'answers result))
+                      (dns-get 'data answer))))))))))))
+
+(provide 'dns)
+
+;;; dns.el ends here
diff --git a/xemacs-packages/gnus/lisp/ecomplete.el b/xemacs-packages/gnus/lisp/ecomplete.el
new file mode 100644 (file)
index 0000000..084895c
--- /dev/null
@@ -0,0 +1,167 @@
+;;; ecomplete.el --- electric completion of addresses and the like
+
+;; Copyright (C) 2006-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile
+  (require 'cl))
+
+(eval-when-compile
+  (when (featurep 'xemacs)
+    ;; The `kbd' macro requires that the `read-kbd-macro' macro is available.
+    (require 'edmacro)))
+
+(defgroup ecomplete nil
+  "Electric completion of email addresses and the like."
+  :group 'mail)
+
+(defcustom ecomplete-database-file "~/.ecompleterc"
+  "*The name of the file to store the ecomplete data."
+  :group 'ecomplete
+  :type 'file)
+
+(defcustom ecomplete-database-file-coding-system 'iso-2022-7bit
+  "Coding system used for writing the ecomplete database file."
+  :type '(symbol :tag "Coding system")
+  :group 'ecomplete)
+
+;;; Internal variables.
+
+(defvar ecomplete-database nil)
+
+;;;###autoload
+(defun ecomplete-setup ()
+  (when (file-exists-p ecomplete-database-file)
+    (with-temp-buffer
+      (let ((coding-system-for-read ecomplete-database-file-coding-system))
+       (insert-file-contents ecomplete-database-file)
+       (setq ecomplete-database (read (current-buffer)))))))
+
+(defun ecomplete-add-item (type key text)
+  (let ((elems (assq type ecomplete-database))
+       (now (string-to-number
+             (format "%.0f" (if (featurep 'emacs)
+                                (float-time)
+                              (require 'gnus-util)
+                              (gnus-float-time)))))
+       entry)
+    (unless elems
+      (push (setq elems (list type)) ecomplete-database))
+    (if (setq entry (assoc key (cdr elems)))
+       (setcdr entry (list (1+ (cadr entry)) now text))
+      (nconc elems (list (list key 1 now text))))))
+
+(defun ecomplete-get-item (type key)
+  (assoc key (cdr (assq type ecomplete-database))))
+
+(defun ecomplete-save ()
+  (with-temp-buffer
+    (let ((coding-system-for-write ecomplete-database-file-coding-system))
+      (insert "(")
+      (loop for (type . elems) in ecomplete-database
+           do
+           (insert (format "(%s\n" type))
+           (dolist (entry elems)
+             (prin1 entry (current-buffer))
+             (insert "\n"))
+           (insert ")\n"))
+      (insert ")")
+      (write-region (point-min) (point-max)
+                   ecomplete-database-file nil 'silent))))
+
+(defun ecomplete-get-matches (type match)
+  (let* ((elems (cdr (assq type ecomplete-database)))
+        (match (regexp-quote match))
+        (candidates
+         (sort
+          (loop for (key count time text) in elems
+                when (string-match match text)
+                collect (list count time text))
+          (lambda (l1 l2)
+            (> (car l1) (car l2))))))
+    (when (> (length candidates) 10)
+      (setcdr (nthcdr 10 candidates) nil))
+    (unless (zerop (length candidates))
+      (with-temp-buffer
+       (dolist (candidate candidates)
+         (insert (caddr candidate) "\n"))
+       (goto-char (point-min))
+       (put-text-property (point) (1+ (point)) 'ecomplete t)
+       (while (re-search-forward match nil t)
+         (put-text-property (match-beginning 0) (match-end 0)
+                            'face 'isearch))
+       (buffer-string)))))
+
+(defun ecomplete-display-matches (type word &optional choose)
+  (let* ((matches (ecomplete-get-matches type word))
+        (line 0)
+        (max-lines (when matches (- (length (split-string matches "\n")) 2)))
+        (message-log-max nil)
+        command highlight)
+    (if (not matches)
+       (progn
+         (message "No ecomplete matches")
+         nil)
+      (if (not choose)
+         (progn
+           (message "%s" matches)
+           nil)
+       (setq highlight (ecomplete-highlight-match-line matches line))
+       (let ((local-map (make-sparse-keymap))
+             selected)
+         (define-key local-map (kbd "RET")
+           (lambda () (setq selected (nth line (split-string matches "\n")))))
+         (define-key local-map (kbd "M-n")
+           (lambda () (setq line (min (1+ line) max-lines))))
+         (define-key local-map (kbd "M-p")
+           (lambda () (setq line (max (1- line) 0))))
+         (let ((overriding-local-map local-map))
+           (while (and (null selected)
+                       (setq command (read-key-sequence highlight))
+                       (lookup-key local-map command))
+             (apply (key-binding command) nil)
+             (setq highlight (ecomplete-highlight-match-line matches line))))
+         (if selected
+             (message selected)
+           (message "Abort"))
+         selected)))))
+
+(defun ecomplete-highlight-match-line (matches line)
+  (with-temp-buffer
+    (insert matches)
+    (goto-char (point-min))
+    (forward-line line)
+    (save-restriction
+      (narrow-to-region (point) (point-at-eol))
+      (while (not (eobp))
+       ;; Put the 'region face on any characters on this line that
+       ;; aren't already highlighted.
+       (unless (get-text-property (point) 'face)
+         (put-text-property (point) (1+ (point)) 'face 'highlight))
+       (forward-char 1)))
+    (buffer-string)))
+
+(provide 'ecomplete)
+
+;;; ecomplete.el ends here
diff --git a/xemacs-packages/gnus/lisp/flow-fill.el b/xemacs-packages/gnus/lisp/flow-fill.el
new file mode 100644 (file)
index 0000000..904f031
--- /dev/null
@@ -0,0 +1,241 @@
+;;; flow-fill.el --- interpret RFC2646 "flowed" text
+
+;; Copyright (C) 2000-2016 Free Software Foundation, Inc.
+
+;; Author: Simon Josefsson <jas@pdc.kth.se>
+;; Keywords: mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This implement decoding of RFC2646 formatted text, including the
+;; quoted-depth wins rules.
+
+;; Theory of operation: search for lines ending with SPC, save quote
+;; length of line, remove SPC and concatenate line with the following
+;; line if quote length of following line matches current line.
+
+;; When no further concatenations are possible, we've found a
+;; paragraph and we let `fill-region' fill the long line into several
+;; lines with the quote prefix as `fill-prefix'.
+
+;; Todo: implement basic `fill-region' (Emacs and XEmacs
+;;       implementations differ..)
+
+;;; History:
+
+;; 2000-02-17  posted on ding mailing list
+;; 2000-02-19  use `point-at-{b,e}ol' in XEmacs
+;; 2000-03-11  no compile warnings for point-at-bol stuff
+;; 2000-03-26  committed to gnus cvs
+;; 2000-10-23  don't flow "-- " lines, make "quote-depth wins" rule
+;;             work when first line is at level 0.
+;; 2002-01-12  probably incomplete encoding support
+;; 2003-12-08  started working on test harness.
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(defcustom fill-flowed-display-column 'fill-column
+  "Column beyond which format=flowed lines are wrapped, when displayed.
+This can be a Lisp expression or an integer."
+  :version "22.1"
+  :group 'mime-display
+  :type '(choice (const :tag "Standard `fill-column'" fill-column)
+                (const :tag "Fit Window" (- (window-width) 5))
+                (sexp)
+                (integer)))
+
+(defcustom fill-flowed-encode-column 66
+  "Column beyond which format=flowed lines are wrapped, in outgoing messages.
+This can be a Lisp expression or an integer.
+RFC 2646 suggests 66 characters for readability."
+  :version "22.1"
+  :group 'mime-display
+  :type '(choice (const :tag "Standard fill-column" fill-column)
+                (const :tag "RFC 2646 default (66)" 66)
+                (sexp)
+                (integer)))
+
+;;;###autoload
+(defun fill-flowed-encode (&optional buffer)
+  (with-current-buffer (or buffer (current-buffer))
+    ;; No point in doing this unless hard newlines is used.
+    (when use-hard-newlines
+      (let ((start (point-min)) end)
+       ;; Go through each paragraph, filling it and adding SPC
+       ;; as the last character on each line.
+       (while (setq end (text-property-any start (point-max) 'hard 't))
+         (save-restriction
+           (narrow-to-region start end)
+           (let ((fill-column (eval fill-flowed-encode-column)))
+             (fill-flowed-fill-buffer))
+           (goto-char (point-min))
+           (while (re-search-forward "\n" nil t)
+             (replace-match " \n" t t))
+           (goto-char (setq start (1+ (point-max)))))))
+      t)))
+
+(defun fill-flowed-fill-buffer ()
+  (let ((prefix nil)
+       (prev-prefix nil)
+       (start (point-min)))
+    (goto-char (point-min))
+    (while (not (eobp))
+      (setq prefix (and (looking-at "[> ]+")
+                       (match-string 0)))
+      (if (equal prefix prev-prefix)
+         (forward-line 1)
+       (save-restriction
+         (narrow-to-region start (point))
+         (let ((fill-prefix prev-prefix))
+           (fill-region (point-min) (point-max) t 'nosqueeze 'to-eop))
+         (goto-char (point-max)))
+       (setq prev-prefix prefix
+             start (point))))
+    (save-restriction
+      (narrow-to-region start (point))
+      (let ((fill-prefix prev-prefix))
+       (fill-region (point-min) (point-max) t 'nosqueeze 'to-eop)))))
+
+;;;###autoload
+(defun fill-flowed (&optional buffer delete-space)
+  (with-current-buffer (or (current-buffer) buffer)
+    (goto-char (point-min))
+    ;; Remove space stuffing.
+    (while (re-search-forward "^\\( \\|>+ $\\)" nil t)
+      (delete-char -1)
+      (forward-line 1))
+    (goto-char (point-min))
+    (while (re-search-forward " $" nil t)
+      (when (save-excursion
+             (beginning-of-line)
+             (looking-at "^\\(>*\\)\\( ?\\)"))
+       (let ((quote (match-string 1))
+             sig)
+         (if (string= quote "")
+             (setq quote nil))
+         (when (and quote (string= (match-string 2) ""))
+           (save-excursion
+             ;; insert SP after quote for pleasant reading of quoted lines
+             (beginning-of-line)
+             (when (> (skip-chars-forward ">") 0)
+               (insert " "))))
+         ;; XXX slightly buggy handling of "-- "
+         (while (and (save-excursion
+                       (ignore-errors (backward-char 3))
+                       (setq sig (looking-at "-- "))
+                       (looking-at "[^-][^-] "))
+                     (save-excursion
+                       (unless (eobp)
+                         (forward-char 1)
+                         (looking-at (format "^\\(%s\\)\\([^>\n\r]\\)"
+                                             (or quote " ?"))))))
+           (save-excursion
+             (replace-match (if (string= (match-string 2) " ")
+                                "" "\\2")))
+           (backward-delete-char -1)
+           (when delete-space
+             (delete-char -1))
+           (end-of-line))
+         (unless sig
+           (condition-case nil
+               (let ((fill-prefix (when quote (concat quote " ")))
+                     (fill-column (eval fill-flowed-display-column))
+                     filladapt-mode
+                     adaptive-fill-mode)
+                 (fill-region (point-at-bol)
+                              (min (1+ (point-at-eol))
+                                   (point-max))
+                              'left 'nosqueeze))
+             (error
+              (forward-line 1)
+              nil))))))))
+
+;; Test vectors.
+
+(defvar show-trailing-whitespace)
+
+(defvar fill-flowed-encode-tests
+  `(
+    ;; The syntax of each list element is:
+    ;; (INPUT . EXPECTED-OUTPUT)
+    (,(concat
+       "> Thou villainous ill-breeding spongy dizzy-eyed \n"
+       "> reeky elf-skinned pigeon-egg! \n"
+       ">> Thou artless swag-bellied milk-livered \n"
+       ">> dismal-dreaming idle-headed scut!\n"
+       ">>> Thou errant folly-fallen spleeny reeling-ripe \n"
+       ">>> unmuzzled ratsbane!\n"
+       ">>>> Henceforth, the coding style is to be strictly \n"
+       ">>>> enforced, including the use of only upper case.\n"
+       ">>>>> I've noticed a lack of adherence to the coding \n"
+       ">>>>> styles, of late.\n"
+       ">>>>>> Any complaints?")
+     .
+     ,(concat
+       "> Thou villainous ill-breeding spongy dizzy-eyed reeky elf-skinned\n"
+       "> pigeon-egg! \n"
+       ">> Thou artless swag-bellied milk-livered dismal-dreaming idle-headed\n"
+       ">> scut!\n"
+       ">>> Thou errant folly-fallen spleeny reeling-ripe unmuzzled ratsbane!\n"
+       ">>>> Henceforth, the coding style is to be strictly enforced,\n"
+       ">>>> including the use of only upper case.\n"
+       ">>>>> I've noticed a lack of adherence to the coding styles, of late.\n"
+       ">>>>>> Any complaints?\n"
+       ))
+    ;; (,(concat
+    ;;    "\n"
+    ;;    "> foo\n"
+    ;;    "> \n"
+    ;;    "> \n"
+    ;;    "> bar\n")
+    ;;  .
+    ;;  ,(concat
+    ;;    "\n"
+    ;;    "> foo bar\n"))
+    ))
+
+(defun fill-flowed-test ()
+  (interactive "")
+  (switch-to-buffer (get-buffer-create "*Format=Flowed test output*"))
+  (erase-buffer)
+  (setq show-trailing-whitespace t)
+  (dolist (test fill-flowed-encode-tests)
+    (let (start output)
+      (insert "***** BEGIN TEST INPUT *****\n")
+      (insert (car test))
+      (insert "***** END TEST INPUT *****\n\n")
+      (insert "***** BEGIN TEST OUTPUT *****\n")
+      (setq start (point))
+      (insert (car test))
+      (save-restriction
+       (narrow-to-region start (point))
+       (fill-flowed))
+      (setq output (buffer-substring start (point-max)))
+      (insert "***** END TEST OUTPUT *****\n")
+      (unless (string= output (cdr test))
+       (insert "\n***** BEGIN TEST EXPECTED OUTPUT *****\n")
+       (insert (cdr test))
+       (insert "***** END TEST EXPECTED OUTPUT *****\n"))
+      (insert "\n\n")))
+  (goto-char (point-max)))
+
+(provide 'flow-fill)
+
+;;; flow-fill.el ends here
diff --git a/xemacs-packages/gnus/lisp/format-spec.el b/xemacs-packages/gnus/lisp/format-spec.el
new file mode 100644 (file)
index 0000000..39ea271
--- /dev/null
@@ -0,0 +1,87 @@
+;;; format-spec.el --- functions for formatting arbitrary formatting strings
+
+;; Copyright (C) 1999-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: tools
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(defun format-spec (format specification)
+  "Return a string based on FORMAT and SPECIFICATION.
+FORMAT is a string containing `format'-like specs like \"bash %u %k\",
+while SPECIFICATION is an alist mapping from format spec characters
+to values.  Any text properties on a %-spec itself are propagated to
+the text that it generates."
+  (with-temp-buffer
+    (insert format)
+    (goto-char (point-min))
+    (while (search-forward "%" nil t)
+      (cond
+       ;; Quoted percent sign.
+       ((eq (char-after) ?%)
+       (delete-char 1))
+       ;; Valid format spec.
+       ((looking-at "\\([-0-9.]*\\)\\([a-zA-Z]\\)")
+       (let* ((num (match-string 1))
+              (spec (if (featurep 'xemacs)
+                        (char-to-int (string-to-char (match-string 2)))
+                      (string-to-char (match-string 2))))
+              (val (assq spec specification)))
+         (unless val
+           (error "Invalid format character: `%%%c'" spec))
+         (setq val (cdr val))
+         ;; Pad result to desired length.
+         (let ((text (format (concat "%" num "s") val)))
+           ;; Insert first, to preserve text properties.
+           (insert-and-inherit text)
+           ;; Delete the specifier body.
+            (delete-region (+ (match-beginning 0) (length text))
+                           (+ (match-end 0) (length text)))
+            ;; Delete the percent sign.
+            (delete-region (1- (match-beginning 0)) (match-beginning 0)))))
+       ;; Signal an error on bogus format strings.
+       (t
+       (error "Invalid format string"))))
+    (buffer-string)))
+
+(defun format-spec-make (&rest pairs)
+  "Return an alist suitable for use in `format-spec' based on PAIRS.
+PAIRS is a list where every other element is a character and a value,
+starting with a character."
+  (let (alist)
+    (while pairs
+      (unless (cdr pairs)
+       (error "Invalid list of pairs"))
+      (push (cons (if (featurep 'xemacs)
+                     (if (characterp (car pairs))
+                         (char-to-int (car pairs))
+                       (car pairs))
+                   (car pairs))
+                 (cadr pairs))
+           alist)
+      (setq pairs (cddr pairs)))
+    (nreverse alist)))
+
+(provide 'format-spec)
+
+;;; format-spec.el ends here
diff --git a/xemacs-packages/gnus/lisp/gmm-utils.el b/xemacs-packages/gnus/lisp/gmm-utils.el
new file mode 100644 (file)
index 0000000..fd9dcbd
--- /dev/null
@@ -0,0 +1,497 @@
+;;; gmm-utils.el --- Utility functions for Gnus, Message and MML
+
+;; Copyright (C) 2006-2016 Free Software Foundation, Inc.
+
+;; Author: Reiner Steib <reiner.steib@gmx.de>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This library provides self-contained utility functions.  The functions are
+;; used in Gnus, Message and MML, but within this library there are no
+;; dependencies on Gnus, Message, or MML.
+
+;;; Code:
+
+(defgroup gmm nil
+  "Utility functions for Gnus, Message and MML."
+  :prefix "gmm-"
+  :version "22.1" ;; Gnus 5.10.9
+  :group 'lisp)
+
+;; Helper functions from `gnus-utils.el': gmm-verbose, gmm-message, gmm-error
+
+(defcustom gmm-verbose 7
+  "Integer that says how verbose gmm should be.
+The higher the number, the more messages will flash to say what
+it did.  At zero, it will be totally mute; at five, it will
+display most important messages; and at ten, it will keep on
+jabbering all the time."
+  :type 'integer
+  :group 'gmm)
+
+;;;###autoload
+(defun gmm-regexp-concat (regexp)
+  "Potentially concat a list of regexps into a single one.
+The concatenation is done with logical ORs."
+  (cond ((null regexp)
+        nil)
+       ((stringp regexp)
+        regexp)
+       ((listp regexp)
+        (mapconcat (lambda (elt) (concat "\\(" elt "\\)"))
+                   regexp
+                   "\\|"))))
+
+;;;###autoload
+(defun gmm-message (level &rest args)
+  "If LEVEL is lower than `gmm-verbose' print ARGS using `message'.
+
+Guideline for numbers:
+1 - error messages
+3 - non-serious error messages
+5 - messages for things that take a long time
+7 - not very important messages on stuff
+9 - messages inside loops."
+  (if (<= level gmm-verbose)
+      (apply 'message args)
+    ;; We have to do this format thingy here even if the result isn't
+    ;; shown - the return value has to be the same as the return value
+    ;; from `message'.
+    (apply 'format args)))
+
+;;;###autoload
+(defun gmm-error (level &rest args)
+  "Beep an error if LEVEL is equal to or less than `gmm-verbose'.
+ARGS are passed to `message'."
+  (when (<= (floor level) gmm-verbose)
+    (apply 'message args)
+    (ding)
+    (let (duration)
+      (when (and (floatp level)
+                (not (zerop (setq duration (* 10 (- level (floor level)))))))
+       (sit-for duration))))
+  nil)
+
+;;;###autoload
+(defun gmm-widget-p (symbol)
+  "Non-nil if SYMBOL is a widget."
+  (get symbol 'widget-type))
+
+(autoload 'widget-create-child-value "wid-edit")
+(autoload 'widget-convert "wid-edit")
+(autoload 'widget-default-get "wid-edit")
+
+;; Copy of the `nnmail-lazy' code from `nnmail.el':
+(define-widget 'gmm-lazy 'default
+  "Base widget for recursive data structures.
+
+This is a copy of the `lazy' widget in Emacs 22.1 provided for compatibility."
+  :format "%{%t%}: %v"
+  :convert-widget 'widget-value-convert-widget
+  :value-create (lambda (widget)
+                  (let ((value (widget-get widget :value))
+                        (type (widget-get widget :type)))
+                    (widget-put widget :children
+                                (list (widget-create-child-value
+                                       widget (widget-convert type) value)))))
+  :value-delete 'widget-children-value-delete
+  :value-get (lambda (widget)
+               (widget-value (car (widget-get widget :children))))
+  :value-inline (lambda (widget)
+                  (widget-apply (car (widget-get widget :children))
+                                :value-inline))
+  :default-get (lambda (widget)
+                 (widget-default-get
+                  (widget-convert (widget-get widget :type))))
+  :match (lambda (widget value)
+           (widget-apply (widget-convert (widget-get widget :type))
+                         :match value))
+  :validate (lambda (widget)
+              (widget-apply (car (widget-get widget :children)) :validate)))
+
+;; Note: The format of `gmm-tool-bar-item' may change if some future Emacs
+;; version will provide customizable tool bar buttons using a different
+;; interface.
+
+;; TODO: Extend API so that the "Command" entry can be a function or a plist.
+;; In case of a list it should have the format...
+;;
+;;  (:none command-without-modifier
+;;   :shift command-with-shift-pressed
+;;   :control command-with-ctrl-pressed
+;;   :control-shift command-with-control-and-shift-pressed
+;;   ;; mouse-2 and mouse-3 can't be used in Emacs yet.
+;;   :mouse-2 command-on-mouse-2-press
+;;   :mouse-3 command-on-mouse-3-press) ;; typically a menu of related commands
+;;
+;; Combinations of mouse-[23] plus shift and/or control might be overkill.
+;;
+;; Then use (plist-get rs-command :none), (plist-get rs-command :shift)
+
+(define-widget 'gmm-tool-bar-item (if (gmm-widget-p 'lazy) 'lazy 'gmm-lazy)
+  "Tool bar list item."
+  :tag "Tool bar item"
+  :type '(choice
+         (list :tag "Command and Icon"
+               (function :tag "Command")
+               (string :tag "Icon file")
+               (choice
+                (const :tag "Default map" nil)
+                ;; Note: Usually we need non-nil attributes if map is t.
+                (const :tag "No menu" t)
+                (sexp :tag "Other map"))
+               (plist :inline t :tag "Properties"))
+         (list :tag "Separator"
+               (const :tag "No command" gmm-ignore)
+               (string :tag "Icon file")
+               (const :tag "No map")
+               (plist :inline t :tag "Properties"))))
+
+(define-widget 'gmm-tool-bar-zap-list (if (gmm-widget-p 'lazy) 'lazy 'gmm-lazy)
+  "Tool bar zap list."
+  :tag "Tool bar zap list"
+  :type '(choice (const :tag "Zap all" t)
+                (const :tag "Keep all" nil)
+                (list
+                 ;; :value
+                 ;; Work around (bug in customize?), see
+                 ;; <news:v9is48jrj1.fsf@marauder.physik.uni-ulm.de>
+                 ;; (new-file open-file dired kill-buffer write-file
+                 ;;        print-buffer customize help)
+                 (set :inline t
+                      (const new-file)
+                      (const open-file)
+                      (const dired)
+                      (const kill-buffer)
+                      (const save-buffer)
+                      (const write-file)
+                      (const undo)
+                      (const cut)
+                      (const copy)
+                      (const paste)
+                      (const search-forward)
+                      (const print-buffer)
+                      (const customize)
+                      (const help))
+                 (repeat :inline t
+                         :tag "Other"
+                         (symbol :tag "Icon item")))))
+
+;; (defun gmm-color-cells (&optional display)
+;;   "Return the number of color cells supported by DISPLAY.
+;; Compatibility function."
+;;   ;; `display-color-cells' doesn't return more than 256 even if color depth is
+;;   ;; > 8 in Emacs 21.
+;;   ;;
+;;   ;; Feel free to add proper XEmacs support.
+;;   (let* ((cells (and (fboundp 'display-color-cells)
+;;                  (display-color-cells display)))
+;;      (plane (and (fboundp 'x-display-planes)
+;;                  (ash 1 (x-display-planes))))
+;;      (none -1))
+;;     (max (if (integerp cells) cells none)
+;;      (if (integerp plane) plane none))))
+
+(defcustom gmm-tool-bar-style
+  (if (and (boundp 'tool-bar-mode)
+          tool-bar-mode
+          (and (fboundp 'display-visual-class)
+               (not (memq (display-visual-class)
+                          (list 'static-gray 'gray-scale
+                                'static-color 'pseudo-color)))))
+      'gnome
+    'retro)
+  "Preferred tool bar style."
+  :type '(choice (const :tag "GNOME style" gnome)
+                (const :tag "Retro look"  retro))
+  :group 'gmm)
+
+(defvar tool-bar-map)
+
+;;;###autoload
+(defun gmm-tool-bar-from-list (icon-list zap-list default-map)
+  "Make a tool bar from ICON-LIST.
+
+Within each entry of ICON-LIST, the first element is a menu
+command, the second element is an icon file name and the third
+element is a test function.  You can use \\[describe-key]
+<menu-entry> to find out the name of a menu command.  The fourth
+and all following elements are passed as the PROPS argument to the
+function `tool-bar-local-item'.
+
+If ZAP-LIST is a list, remove those item from the default
+`tool-bar-map'.  If it is t, start with a new sparse map.  You
+can use \\[describe-key] <icon> to find out the name of an icon
+item.  When \\[describe-key] <icon> shows \"<tool-bar> <new-file>
+runs the command find-file\", then use `new-file' in ZAP-LIST.
+
+DEFAULT-MAP specifies the default key map for ICON-LIST."
+  (let (;; For Emacs 21, we must let-bind `tool-bar-map'.  In Emacs 22, we
+       ;; could use some other local variable.
+       (tool-bar-map (if (eq zap-list t)
+                         (make-sparse-keymap)
+                       (copy-keymap tool-bar-map))))
+    (when (listp zap-list)
+      ;; Zap some items which aren't relevant for this mode and take up space.
+      (dolist (key zap-list)
+       (define-key tool-bar-map (vector key) nil)))
+    (mapc (lambda (el)
+           (let ((command (car el))
+                 (icon (nth 1 el))
+                 (fmap (or (nth 2 el) default-map))
+                 (props  (cdr (cdr (cdr el)))) )
+             ;; command may stem from different from-maps:
+             (cond ((eq command 'gmm-ignore)
+                    ;; The dummy `gmm-ignore', see `gmm-tool-bar-item'
+                    ;; widget.  Suppress tooltip by adding `:enable nil'.
+                    (if (fboundp 'tool-bar-local-item)
+                        (apply 'tool-bar-local-item icon nil nil
+                               tool-bar-map :enable nil props)
+                      ;; (tool-bar-local-item ICON DEF KEY MAP &rest PROPS)
+                      ;; (tool-bar-add-item ICON DEF KEY &rest PROPS)
+                      (apply 'tool-bar-add-item icon nil nil :enable nil props)))
+                   ((equal fmap t) ;; Not a menu command
+                    (apply 'tool-bar-local-item
+                           icon command
+                           (intern icon) ;; reuse icon or fmap here?
+                           tool-bar-map props))
+                   (t ;; A menu command
+                    (apply 'tool-bar-local-item-from-menu
+                           ;; (apply 'tool-bar-local-item icon def key
+                           ;; tool-bar-map props)
+                           command icon tool-bar-map (symbol-value fmap)
+                           props)))
+             t))
+         (if (symbolp icon-list)
+             (eval icon-list)
+           icon-list))
+    tool-bar-map))
+
+(defmacro defun-gmm (name function arg-list &rest body)
+  "Create function NAME.
+If FUNCTION exists, then NAME becomes an alias for FUNCTION.
+Otherwise, create function NAME with ARG-LIST and BODY."
+  (let ((defined-p (fboundp function)))
+    (if defined-p
+        `(defalias ',name ',function)
+      `(defun ,name ,arg-list ,@body))))
+
+(defun-gmm gmm-image-search-load-path
+  image-search-load-path (file &optional path)
+  "Emacs 21 and XEmacs don't have `image-search-load-path'.
+This function returns nil on those systems."
+  nil)
+
+;; Cf. `mh-image-load-path-for-library' in `mh-compat.el'.
+
+(defun-gmm gmm-image-load-path-for-library
+  image-load-path-for-library (library image &optional path no-error)
+  "Return a suitable search path for images used by LIBRARY.
+
+It searches for IMAGE in `image-load-path' (excluding
+\"`data-directory'/images\") and `load-path', followed by a path
+suitable for LIBRARY, which includes \"../../etc/images\" and
+\"../etc/images\" relative to the library file itself, and then
+in \"`data-directory'/images\".
+
+Then this function returns a list of directories which contains
+first the directory in which IMAGE was found, followed by the
+value of `load-path'.  If PATH is given, it is used instead of
+`load-path'.
+
+If NO-ERROR is non-nil and a suitable path can't be found, don't
+signal an error.  Instead, return a list of directories as before,
+except that nil appears in place of the image directory.
+
+Here is an example that uses a common idiom to provide
+compatibility with versions of Emacs that lack the variable
+`image-load-path':
+
+    ;; Shush compiler.
+    (defvar image-load-path)
+
+    (let* ((load-path (image-load-path-for-library \"mh-e\" \"mh-logo.xpm\"))
+           (image-load-path (cons (car load-path)
+                                  (when (boundp \\='image-load-path)
+                                    image-load-path))))
+      (mh-tool-bar-folder-buttons-init))"
+  (unless library (error "No library specified"))
+  (unless image   (error "No image specified"))
+  (let (image-directory image-directory-load-path)
+    ;; Check for images in image-load-path or load-path.
+    (let ((img image)
+          (dir (or
+                ;; Images in image-load-path.
+                (gmm-image-search-load-path image) ;; "gmm-" prefix!
+                ;; Images in load-path.
+                (locate-library image)))
+          parent)
+      ;; Since the image might be in a nested directory (for
+      ;; example, mail/attach.pbm), adjust `image-directory'
+      ;; accordingly.
+      (when dir
+        (setq dir (file-name-directory dir))
+        (while (setq parent (file-name-directory img))
+          (setq img (directory-file-name parent)
+                dir (expand-file-name "../" dir))))
+      (setq image-directory-load-path dir))
+
+    ;; If `image-directory-load-path' isn't Emacs's image directory,
+    ;; it's probably a user preference, so use it.  Then use a
+    ;; relative setting if possible; otherwise, use
+    ;; `image-directory-load-path'.
+    (cond
+     ;; User-modified image-load-path?
+     ((and image-directory-load-path
+           (not (equal image-directory-load-path
+                       (file-name-as-directory
+                        (expand-file-name "images" data-directory)))))
+      (setq image-directory image-directory-load-path))
+     ;; Try relative setting.
+     ((let (library-name d1ei d2ei)
+        ;; First, find library in the load-path.
+        (setq library-name (locate-library library))
+        (if (not library-name)
+            (error "Cannot find library %s in load-path" library))
+        ;; And then set image-directory relative to that.
+        (setq
+         ;; Go down 2 levels.
+         d2ei (file-name-as-directory
+               (expand-file-name
+                (concat (file-name-directory library-name) "../../etc/images")))
+         ;; Go down 1 level.
+         d1ei (file-name-as-directory
+               (expand-file-name
+                (concat (file-name-directory library-name) "../etc/images"))))
+        (setq image-directory
+              ;; Set it to nil if image is not found.
+              (cond ((file-exists-p (expand-file-name image d2ei)) d2ei)
+                    ((file-exists-p (expand-file-name image d1ei)) d1ei)))))
+     ;; Use Emacs's image directory.
+     (image-directory-load-path
+      (setq image-directory image-directory-load-path))
+     (no-error
+      (message "Could not find image %s for library %s" image library))
+     (t
+      (error "Could not find image %s for library %s" image library)))
+
+    ;; Return an augmented `path' or `load-path'.
+    (nconc (list image-directory)
+           (delete image-directory (copy-sequence (or path load-path))))))
+
+(defun gmm-customize-mode (&optional mode)
+  "Customize customization group for MODE.
+If mode is nil, use `major-mode' of the current buffer."
+  (interactive)
+  (customize-group
+   (or mode
+       (intern (let ((mode (symbol-name major-mode)))
+                (string-match "^\\(.+\\)-mode$" mode)
+                (match-string 1 mode))))))
+
+(defun gmm-write-region (start end filename &optional append visit
+                              lockname mustbenew)
+  "Compatibility function for `write-region'.
+
+In XEmacs, the seventh argument of `write-region' specifies the
+coding-system."
+  (if (and mustbenew (featurep 'xemacs))
+      (if (file-exists-p filename)
+         (signal 'file-already-exists (list "File exists" filename))
+       (write-region start end filename append visit lockname))
+    (write-region start end filename append visit lockname mustbenew)))
+
+;; `interactive-p' is obsolete since Emacs 23.2.
+(defmacro gmm-called-interactively-p (kind)
+  (condition-case nil
+      (progn
+       (eval '(called-interactively-p 'any))
+       ;; Emacs >=23.2
+       `(called-interactively-p ,kind))
+    ;; Emacs <23.2
+    (wrong-number-of-arguments '(called-interactively-p))
+    ;; XEmacs
+    (void-function '(interactive-p))))
+
+;; `flet' and `labels' are obsolete since Emacs 24.3.
+(defmacro gmm-flet (bindings &rest body)
+  "Make temporary overriding function definitions.
+This is an analogue of a dynamically scoped `let' that operates on
+the function cell of FUNCs rather than their value cell.
+
+\(fn ((FUNC ARGLIST BODY...) ...) FORM...)"
+  (require 'cl)
+  (if (fboundp 'cl-letf)
+      `(cl-letf ,(mapcar (lambda (binding)
+                          `((symbol-function ',(car binding))
+                            (lambda ,@(cdr binding))))
+                        bindings)
+        ,@body)
+    `(flet ,bindings ,@body)))
+(put 'gmm-flet 'lisp-indent-function 1)
+(put 'gmm-flet 'edebug-form-spec '((&rest (sexp sexp &rest form)) &rest form))
+
+(defmacro gmm-labels (bindings &rest body)
+  "Make temporary function bindings.
+The bindings can be recursive and the scoping is lexical, but capturing
+them in closures will only work if `lexical-binding' is in use.  But in
+Emacs 24.2 and older, the lexical scoping is handled via `lexical-let'
+rather than relying on `lexical-binding'.
+
+\(fn ((FUNC ARGLIST BODY...) ...) FORM...)"
+  `(,(progn (require 'cl) (if (fboundp 'cl-labels) 'cl-labels 'labels))
+    ,bindings ,@body))
+(put 'gmm-labels 'lisp-indent-function 1)
+(put 'gmm-labels 'edebug-form-spec '((&rest (sexp sexp &rest form)) &rest form))
+
+(defun gmm-format-time-string (format-string &optional time tz)
+  "Use FORMAT-STRING to format the time TIME, or now if omitted.
+The optional TZ specifies the time zone in a number of seconds; any
+other non-nil value will be treated as 0.  Note that both the format
+specifiers `%Z' and `%z' will be replaced with a numeric form. "
+;; FIXME: is there a smart way to replace %Z with a time zone name?
+  (if (and (numberp tz) (not (zerop tz)))
+      (let ((st 0)
+           (case-fold-search t)
+           ls nd rest)
+       (setq time (if time
+                      (copy-sequence time)
+                    (current-time)))
+       (if (>= (setq ls (- (cadr time) (car (current-time-zone)) (- tz))) 0)
+           (setcar (cdr time) ls)
+         (setcar (cdr time) (+ ls 65536))
+         (setcar time (1- (car time))))
+       (setq tz (format "%s%02d%02d"
+                        (if (>= tz 0) "+" "-")
+                        (/ (abs tz) 3600)
+                        (/ (% (abs tz) 3600) 60)))
+       (while (string-match "%+z" format-string st)
+         (if (zerop (% (- (setq nd (match-end 0)) (match-beginning 0)) 2))
+             (progn
+               (push (substring format-string st (- nd 2)) rest)
+               (push tz rest))
+           (push (substring format-string st nd) rest))
+         (setq st nd))
+       (push (substring format-string st) rest)
+       (format-time-string (apply 'concat (nreverse rest)) time))
+    (format-time-string format-string time tz)))
+
+(provide 'gmm-utils)
+
+;;; gmm-utils.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-agent.el b/xemacs-packages/gnus/lisp/gnus-agent.el
new file mode 100644 (file)
index 0000000..9219ce0
--- /dev/null
@@ -0,0 +1,4207 @@
+;;; gnus-agent.el --- unplugged support for Gnus
+
+;; Copyright (C) 1997-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'gnus)
+(require 'gnus-cache)
+(require 'nnmail)
+(require 'nnvirtual)
+(require 'gnus-sum)
+(require 'gnus-score)
+(require 'gnus-srvr)
+(require 'gnus-util)
+(eval-when-compile
+  (if (featurep 'xemacs)
+      (require 'itimer)
+    (require 'timer))
+  (require 'cl))
+
+(autoload 'gnus-server-update-server "gnus-srvr")
+(autoload 'gnus-agent-customize-category "gnus-cus")
+
+(defcustom gnus-agent-directory (nnheader-concat gnus-directory "agent/")
+  "Where the Gnus agent will store its files."
+  :group 'gnus-agent
+  :type 'directory)
+
+(defcustom gnus-agent-plugged-hook nil
+  "Hook run when plugging into the network."
+  :group 'gnus-agent
+  :type 'hook)
+
+(defcustom gnus-agent-unplugged-hook nil
+  "Hook run when unplugging from the network."
+  :group 'gnus-agent
+  :type 'hook)
+
+(defcustom gnus-agent-fetched-hook nil
+  "Hook run when finished fetching articles."
+  :version "22.1"
+  :group 'gnus-agent
+  :type 'hook)
+
+(defcustom gnus-agent-handle-level gnus-level-subscribed
+  "Groups on levels higher than this variable will be ignored by the Agent."
+  :group 'gnus-agent
+  :type 'integer)
+
+(defcustom gnus-agent-expire-days 7
+  "Read articles older than this will be expired.
+If you wish to disable Agent expiring, see `gnus-agent-enable-expiration'."
+  :group 'gnus-agent
+  :type '(number :tag "days"))
+
+(defcustom gnus-agent-expire-all nil
+  "If non-nil, also expire unread, ticked and dormant articles.
+If nil, only read articles will be expired."
+  :group 'gnus-agent
+  :type 'boolean)
+
+(defcustom gnus-agent-group-mode-hook nil
+  "Hook run in Agent group minor modes."
+  :group 'gnus-agent
+  :type 'hook)
+
+;; Extracted from gnus-xmas-redefine in order to preserve user settings
+(when (featurep 'xemacs)
+  (add-hook 'gnus-agent-group-mode-hook 'gnus-xmas-agent-group-menu-add))
+
+(defcustom gnus-agent-summary-mode-hook nil
+  "Hook run in Agent summary minor modes."
+  :group 'gnus-agent
+  :type 'hook)
+
+;; Extracted from gnus-xmas-redefine in order to preserve user settings
+(when (featurep 'xemacs)
+  (add-hook 'gnus-agent-summary-mode-hook 'gnus-xmas-agent-summary-menu-add))
+
+(defcustom gnus-agent-server-mode-hook nil
+  "Hook run in Agent summary minor modes."
+  :group 'gnus-agent
+  :type 'hook)
+
+;; Extracted from gnus-xmas-redefine in order to preserve user settings
+(when (featurep 'xemacs)
+  (add-hook 'gnus-agent-server-mode-hook 'gnus-xmas-agent-server-menu-add))
+
+(defcustom gnus-agent-confirmation-function 'y-or-n-p
+  "Function to confirm when error happens."
+  :version "21.1"
+  :group 'gnus-agent
+  :type 'function)
+
+(defcustom gnus-agent-synchronize-flags nil
+  "Indicate if flags are synchronized when you plug in.
+If this is `ask' the hook will query the user."
+  ;; If the default switches to something else than nil, then the function
+  ;; should be fixed not be exceedingly slow.  See 2005-09-20 ChangeLog entry.
+  :version "21.1"
+  :type '(choice (const :tag "Always" t)
+                (const :tag "Never" nil)
+                (const :tag "Ask" ask))
+  :group 'gnus-agent)
+
+(defcustom gnus-agent-go-online 'ask
+  "Indicate if offline servers go online when you plug in.
+If this is `ask' the hook will query the user."
+  :version "21.3"
+  :type '(choice (const :tag "Always" t)
+                (const :tag "Never" nil)
+                (const :tag "Ask" ask))
+  :group 'gnus-agent)
+
+(defcustom gnus-agent-mark-unread-after-downloaded t
+  "Indicate whether to mark articles unread after downloaded."
+  :version "21.1"
+  :type 'boolean
+  :group 'gnus-agent)
+
+(defcustom gnus-agent-download-marks '(download)
+  "Marks for downloading."
+  :version "21.1"
+  :type '(repeat (symbol :tag "Mark"))
+  :group 'gnus-agent)
+
+(defcustom gnus-agent-consider-all-articles nil
+  "When non-nil, the agent will let the agent predicate decide
+whether articles need to be downloaded or not, for all articles.  When
+nil, the default, the agent will only let the predicate decide
+whether unread articles are downloaded or not.  If you enable this,
+groups with large active ranges may open slower and you may also want
+to look into the agent expiry settings to block the expiration of
+read articles as they would just be downloaded again."
+  :version "22.1"
+  :type 'boolean
+  :group 'gnus-agent)
+
+(defcustom gnus-agent-max-fetch-size 10000000 ;; 10 Mb
+  "Chunk size for `gnus-agent-fetch-session'.
+The function will split its article fetches into chunks smaller than
+this limit."
+  :version "22.1"
+  :group 'gnus-agent
+  :type 'integer)
+
+(defcustom gnus-agent-enable-expiration 'ENABLE
+  "The default expiration state for each group.
+When set to ENABLE, the default, `gnus-agent-expire' will expire old
+contents from a group's local storage.  This value may be overridden
+to disable expiration in specific categories, topics, and groups.  Of
+course, you could change gnus-agent-enable-expiration to DISABLE then
+enable expiration per categories, topics, and groups."
+  :version "22.1"
+  :group 'gnus-agent
+  :type '(radio (const :format "Enable " ENABLE)
+                (const :format "Disable " DISABLE)))
+
+(defcustom gnus-agent-expire-unagentized-dirs t
+  "*Whether expiration should expire in unagentized directories.
+Have gnus-agent-expire scan the directories under
+\(gnus-agent-directory) for groups that are no longer agentized.
+When found, offer to remove them."
+  :version "22.1"
+  :type 'boolean
+  :group 'gnus-agent)
+
+(defcustom gnus-agent-auto-agentize-methods nil
+  "Initially, all servers from these methods are agentized.
+The user may remove or add servers using the Server buffer.
+See Info nodes `(gnus)Server Buffer', `(gnus)Agent Variables'."
+  :version "22.1"
+  :type '(repeat symbol)
+  :group 'gnus-agent)
+
+(defcustom gnus-agent-queue-mail t
+  "Whether and when outgoing mail should be queued by the agent.
+When `always', always queue outgoing mail.  When nil, never
+queue.  Otherwise, queue if and only if unplugged."
+  :version "22.1"
+  :group 'gnus-agent
+  :type '(radio (const :format "Always" always)
+               (const :format "Never" nil)
+               (const :format "When unplugged" t)))
+
+(defcustom gnus-agent-prompt-send-queue nil
+  "If non-nil, `gnus-group-send-queue' will prompt if called when unplugged."
+  :version "22.1"
+  :group 'gnus-agent
+  :type 'boolean)
+
+(defcustom gnus-agent-article-alist-save-format 1
+  "Indicates whether to use compression(2), versus no
+compression(1), when writing agentview files.  The compressed
+files do save space but load times are 6-7 times higher.  A group
+must be opened then closed for the agentview to be updated using
+the new format."
+  ;; Wouldn't symbols instead numbers be nicer?  --rsteib
+  :version "22.1"
+  :group 'gnus-agent
+  :type '(radio (const :format "Compressed" 2)
+               (const :format "Uncompressed" 1)))
+
+;;; Internal variables
+
+(defvar gnus-agent-history-buffers nil)
+(defvar gnus-agent-buffer-alist nil)
+(defvar gnus-agent-article-alist nil
+  "An assoc list identifying the articles whose headers have been fetched.
+If successfully fetched, these headers will be stored in the group's overview
+file.  The key of each assoc pair is the article ID, the value of each assoc
+pair is a flag indicating whether the identified article has been downloaded
+\(gnus-agent-fetch-articles sets the value to the day of the download).
+NOTES:
+1) The last element of this list can not be expired as some
+   routines (for example, get-agent-fetch-headers) use the last
+   value to track which articles have had their headers retrieved.
+2) The function `gnus-agent-regenerate' may destructively modify the value.")
+(defvar gnus-agent-group-alist nil)
+(defvar gnus-category-alist nil)
+(defvar gnus-agent-current-history nil)
+(defvar gnus-agent-overview-buffer nil)
+(defvar gnus-category-predicate-cache nil)
+(defvar gnus-category-group-cache nil)
+(defvar gnus-agent-spam-hashtb nil)
+(defvar gnus-agent-file-name nil)
+(defvar gnus-agent-file-coding-system 'raw-text)
+(defvar gnus-agent-file-loading-cache nil)
+(defvar gnus-agent-total-fetched-hashtb nil)
+(defvar gnus-agent-inhibit-update-total-fetched-for nil)
+(defvar gnus-agent-need-update-total-fetched-for nil)
+
+;; Dynamic variables
+(defvar gnus-headers)
+(defvar gnus-score)
+
+;; Added to support XEmacs
+(eval-and-compile
+  (unless (fboundp 'directory-files-and-attributes)
+    (defun directory-files-and-attributes (directory
+                                          &optional full match nosort)
+      (let (result)
+       (dolist (file (directory-files directory full match nosort))
+         (push (cons file (file-attributes file)) result))
+       (nreverse result)))))
+
+;;;
+;;; Setup
+;;;
+
+(defun gnus-open-agent ()
+  (setq gnus-agent t)
+  (gnus-agent-read-servers)
+  (gnus-category-read)
+  (gnus-agent-create-buffer)
+  (add-hook 'gnus-group-mode-hook 'gnus-agent-mode)
+  (add-hook 'gnus-summary-mode-hook 'gnus-agent-mode)
+  (add-hook 'gnus-server-mode-hook 'gnus-agent-mode))
+
+(defun gnus-agent-create-buffer ()
+  (if (gnus-buffer-live-p gnus-agent-overview-buffer)
+      t
+    (setq gnus-agent-overview-buffer
+         (gnus-get-buffer-create " *Gnus agent overview*"))
+    (with-current-buffer gnus-agent-overview-buffer
+      (mm-enable-multibyte))
+    nil))
+
+(gnus-add-shutdown 'gnus-close-agent 'gnus)
+
+(defun gnus-close-agent ()
+  (setq gnus-category-predicate-cache nil
+       gnus-category-group-cache nil
+       gnus-agent-spam-hashtb nil)
+  (gnus-kill-buffer gnus-agent-overview-buffer))
+
+;;;
+;;; Utility functions
+;;;
+
+(defmacro gnus-agent-with-refreshed-group (group &rest body)
+  "Performs the body then updates the group's line in the group
+buffer.  Automatically blocks multiple updates due to recursion."
+`(prog1 (let ((gnus-agent-inhibit-update-total-fetched-for t)) ,@body)
+     (when (and gnus-agent-need-update-total-fetched-for
+               (not gnus-agent-inhibit-update-total-fetched-for))
+       (with-current-buffer gnus-group-buffer
+         (setq gnus-agent-need-update-total-fetched-for nil)
+         (gnus-group-update-group ,group t)))))
+
+(defun gnus-agent-read-file (file)
+  "Load FILE and do a `read' there."
+  (with-temp-buffer
+    (ignore-errors
+      (nnheader-insert-file-contents file)
+      (goto-char (point-min))
+      (read (current-buffer)))))
+
+(defsubst gnus-agent-method ()
+  (concat (symbol-name (car gnus-command-method)) "/"
+         (if (equal (cadr gnus-command-method) "")
+             "unnamed"
+           (cadr gnus-command-method))))
+
+(defsubst gnus-agent-directory ()
+  "The name of the Gnus agent directory."
+  (nnheader-concat gnus-agent-directory
+                  (nnheader-translate-file-chars (gnus-agent-method)) "/"))
+
+(defun gnus-agent-lib-file (file)
+  "The full name of the Gnus agent library FILE."
+  (expand-file-name file
+                   (file-name-as-directory
+                    (expand-file-name "agent.lib" (gnus-agent-directory)))))
+
+(defun gnus-agent-cat-set-property (category property value)
+  (if value
+      (setcdr (or (assq property category)
+              (let ((cell (cons property nil)))
+                    (setcdr category (cons cell (cdr category)))
+                    cell)) value)
+    (let ((category category))
+      (while (cond ((eq property (caadr category))
+                    (setcdr category (cddr category))
+                    nil)
+                   (t
+                    (setq category (cdr category)))))))
+  category)
+
+(eval-when-compile
+  (defmacro gnus-agent-cat-defaccessor (name prop-name)
+    "Define accessor and setter methods for manipulating a list of the form
+\(NAME (PROPERTY1 VALUE1) ... (PROPERTY_N VALUE_N)).
+Given the call (gnus-agent-cat-defaccessor func PROPERTY1), the list may be
+manipulated as follows:
+  (func LIST): Returns VALUE1
+  (setf (func LIST) NEW_VALUE1): Replaces VALUE1 with NEW_VALUE1."
+    `(progn (defmacro ,name (category)
+              (list 'cdr (list 'assq '',prop-name category)))
+
+            (defsetf ,name (category) (value)
+              (list 'gnus-agent-cat-set-property
+                    category '',prop-name value))))
+  )
+
+(defmacro gnus-agent-cat-name (category)
+  `(car ,category))
+
+(gnus-agent-cat-defaccessor
+ gnus-agent-cat-days-until-old             agent-days-until-old)
+(gnus-agent-cat-defaccessor
+ gnus-agent-cat-enable-expiration          agent-enable-expiration)
+(gnus-agent-cat-defaccessor
+ gnus-agent-cat-groups                     agent-groups)
+(gnus-agent-cat-defaccessor
+ gnus-agent-cat-high-score                 agent-high-score)
+(gnus-agent-cat-defaccessor
+ gnus-agent-cat-length-when-long           agent-long-article)
+(gnus-agent-cat-defaccessor
+ gnus-agent-cat-length-when-short          agent-short-article)
+(gnus-agent-cat-defaccessor
+ gnus-agent-cat-low-score                  agent-low-score)
+(gnus-agent-cat-defaccessor
+ gnus-agent-cat-predicate                  agent-predicate)
+(gnus-agent-cat-defaccessor
+ gnus-agent-cat-score-file                 agent-score)
+(gnus-agent-cat-defaccessor
+ gnus-agent-cat-enable-undownloaded-faces  agent-enable-undownloaded-faces)
+
+
+;; This form may expand to code that uses CL functions at run-time,
+;; but that's OK since those functions will only ever be called from
+;; something like `setf', so only when CL is loaded anyway.
+(defsetf gnus-agent-cat-groups gnus-agent-set-cat-groups)
+
+(defun gnus-agent-set-cat-groups (category groups)
+  (unless (eq groups 'ignore)
+    (let ((new-g groups)
+          (old-g (gnus-agent-cat-groups category)))
+      (cond ((eq new-g old-g)
+             ;; gnus-agent-add-group is fiddling with the group
+             ;; list. Still, Im done.
+             nil
+             )
+            ((eq new-g (cdr old-g))
+             ;; gnus-agent-add-group is fiddling with the group list
+             (setcdr (or (assq 'agent-groups category)
+                         (let ((cell (cons 'agent-groups nil)))
+                           (setcdr category (cons cell (cdr category)))
+                           cell)) new-g))
+            (t
+             (let ((groups groups))
+               (while groups
+                 (let* ((group        (pop groups))
+                        (old-category (gnus-group-category group)))
+                   (if (eq category old-category)
+                       nil
+                     (setf (gnus-agent-cat-groups old-category)
+                           (delete group (gnus-agent-cat-groups
+                                          old-category))))))
+               ;; Purge cache as preceding loop invalidated it.
+               (setq gnus-category-group-cache nil))
+
+             (setcdr (or (assq 'agent-groups category)
+                         (let ((cell (cons 'agent-groups nil)))
+                           (setcdr category (cons cell (cdr category)))
+                           cell)) groups))))))
+
+(defsubst gnus-agent-cat-make (name &optional default-agent-predicate)
+  (list name `(agent-predicate . ,(or default-agent-predicate 'false))))
+
+(defun gnus-agent-read-group ()
+  "Read a group name in the minibuffer, with completion."
+  (let ((def (or (gnus-group-group-name) gnus-newsgroup-name)))
+    (when def
+      (setq def (gnus-group-decoded-name def)))
+    (gnus-group-completing-read nil nil t nil nil def)))
+
+;;; Fetching setup functions.
+
+(defun gnus-agent-start-fetch ()
+  "Initialize data structures for efficient fetching."
+  (gnus-agent-create-buffer))
+
+(defun gnus-agent-stop-fetch ()
+  "Save all data structures and clean up."
+  (setq gnus-agent-spam-hashtb nil)
+  (with-current-buffer nntp-server-buffer
+    (widen)))
+
+(defmacro gnus-agent-with-fetch (&rest forms)
+  "Do FORMS safely."
+  `(unwind-protect
+       (let ((gnus-agent-fetching t))
+        (gnus-agent-start-fetch)
+        ,@forms)
+     (gnus-agent-stop-fetch)))
+
+(put 'gnus-agent-with-fetch 'lisp-indent-function 0)
+(put 'gnus-agent-with-fetch 'edebug-form-spec '(body))
+
+(defmacro gnus-agent-append-to-list (tail value)
+  `(setq ,tail (setcdr ,tail (cons ,value nil))))
+
+(defmacro gnus-agent-message (level &rest args)
+  `(if (<= ,level gnus-verbose)
+       (message ,@args)))
+
+;;;
+;;; Mode infestation
+;;;
+
+(defvar gnus-agent-mode-hook nil
+  "Hook run when installing agent mode.")
+
+(defvar gnus-agent-mode nil)
+(defvar gnus-agent-mode-status '(gnus-agent-mode " Plugged"))
+
+(defun gnus-agent-mode ()
+  "Minor mode for providing a agent support in Gnus buffers."
+  (let* ((buffer (progn (string-match "^gnus-\\(.*\\)-mode$"
+                                     (symbol-name major-mode))
+                       (match-string 1 (symbol-name major-mode))))
+        (mode (intern (format "gnus-agent-%s-mode" buffer))))
+    (set (make-local-variable 'gnus-agent-mode) t)
+    (set mode nil)
+    (set (make-local-variable mode) t)
+    ;; Set up the menu.
+    (when (gnus-visual-p 'agent-menu 'menu)
+      (funcall (intern (format "gnus-agent-%s-make-menu-bar" buffer))))
+    (unless (assq mode minor-mode-alist)
+      (push (cons mode (cdr gnus-agent-mode-status)) minor-mode-alist))
+    (unless (assq mode minor-mode-map-alist)
+      (push (cons mode (symbol-value (intern (format "gnus-agent-%s-mode-map"
+                                                    buffer))))
+           minor-mode-map-alist))
+    (when (derived-mode-p 'gnus-group-mode)
+      (let ((init-plugged gnus-plugged)
+            (gnus-agent-go-online nil))
+        ;; g-a-t-p does nothing when gnus-plugged isn't changed.
+        ;; Therefore, make certain that the current value does not
+        ;; match the desired initial value.
+        (setq gnus-plugged :unknown)
+        (gnus-agent-toggle-plugged init-plugged)))
+    (gnus-run-hooks 'gnus-agent-mode-hook
+                   (intern (format "gnus-agent-%s-mode-hook" buffer)))))
+
+(defvar gnus-agent-group-mode-map (make-sparse-keymap))
+(gnus-define-keys gnus-agent-group-mode-map
+  "Ju" gnus-agent-fetch-groups
+  "Jc" gnus-enter-category-buffer
+  "Jj" gnus-agent-toggle-plugged
+  "Js" gnus-agent-fetch-session
+  "JY" gnus-agent-synchronize-flags
+  "JS" gnus-group-send-queue
+  "Ja" gnus-agent-add-group
+  "Jr" gnus-agent-remove-group
+  "Jo" gnus-agent-toggle-group-plugged)
+
+(defun gnus-agent-group-make-menu-bar ()
+  (unless (boundp 'gnus-agent-group-menu)
+    (easy-menu-define
+     gnus-agent-group-menu gnus-agent-group-mode-map ""
+     '("Agent"
+       ["Toggle plugged" gnus-agent-toggle-plugged t]
+       ["Toggle group plugged" gnus-agent-toggle-group-plugged t]
+       ["List categories" gnus-enter-category-buffer t]
+       ["Add (current) group to category" gnus-agent-add-group t]
+       ["Remove (current) group from category" gnus-agent-remove-group t]
+       ["Send queue" gnus-group-send-queue gnus-plugged]
+       ("Fetch"
+       ["All" gnus-agent-fetch-session gnus-plugged]
+       ["Group" gnus-agent-fetch-group gnus-plugged])
+       ["Synchronize flags" gnus-agent-synchronize-flags t]
+       ))))
+
+(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
+  "JS" gnus-agent-fetch-group
+  "Js" gnus-agent-summary-fetch-series
+  "J#" gnus-agent-mark-article
+  "J\M-#" gnus-agent-unmark-article
+  "@" gnus-agent-toggle-mark
+  "Jc" gnus-agent-catchup)
+
+(defun gnus-agent-summary-make-menu-bar ()
+  (unless (boundp 'gnus-agent-summary-menu)
+    (easy-menu-define
+     gnus-agent-summary-menu gnus-agent-summary-mode-map ""
+     '("Agent"
+       ["Toggle plugged" gnus-agent-toggle-plugged t]
+       ["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-agent-summary-fetch-group t]
+       ["Catchup undownloaded" gnus-agent-catchup t]))))
+
+(defvar gnus-agent-server-mode-map (make-sparse-keymap))
+(gnus-define-keys gnus-agent-server-mode-map
+  "Jj" gnus-agent-toggle-plugged
+  "Ja" gnus-agent-add-server
+  "Jr" gnus-agent-remove-server)
+
+(defun gnus-agent-server-make-menu-bar ()
+  (unless (boundp 'gnus-agent-server-menu)
+    (easy-menu-define
+     gnus-agent-server-menu gnus-agent-server-mode-map ""
+     '("Agent"
+       ["Toggle plugged" gnus-agent-toggle-plugged t]
+       ["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)
+                 'mouse-face
+                 (if (and (featurep 'xemacs)
+                          ;; XEmacs's `facep' only checks for a face
+                          ;; object, not for a face name, so it's useless
+                          ;; to check with `facep'.
+                          (find-face 'modeline))
+                     'modeline
+                   'mode-line-highlight))
+    string))
+
+(defun gnus-agent-toggle-plugged (set-to)
+  "Toggle whether Gnus is unplugged or not."
+  (interactive (list (not gnus-plugged)))
+  (cond ((eq set-to gnus-plugged)
+         nil)
+        (set-to
+         (setq gnus-plugged set-to)
+         (gnus-run-hooks 'gnus-agent-plugged-hook)
+         (setcar (cdr gnus-agent-mode-status)
+                 (gnus-agent-make-mode-line-string " Plugged"
+                                                   'mouse-2
+                                                   'gnus-agent-toggle-plugged))
+         (gnus-agent-go-online gnus-agent-go-online))
+        (t
+         (gnus-agent-close-connections)
+         (setq gnus-plugged set-to)
+         (gnus-run-hooks 'gnus-agent-unplugged-hook)
+         (setcar (cdr gnus-agent-mode-status)
+                 (gnus-agent-make-mode-line-string " Unplugged"
+                                                   'mouse-2
+                                                   'gnus-agent-toggle-plugged))))
+  (set-buffer-modified-p t))
+
+(defmacro gnus-agent-while-plugged (&rest body)
+  `(let ((original-gnus-plugged gnus-plugged))
+    (unwind-protect
+        (progn (gnus-agent-toggle-plugged t)
+               ,@body)
+      (gnus-agent-toggle-plugged original-gnus-plugged))))
+
+(put 'gnus-agent-while-plugged 'lisp-indent-function 0)
+(put 'gnus-agent-while-plugged 'edebug-form-spec '(body))
+
+(defun gnus-agent-close-connections ()
+  "Close all methods covered by the Gnus agent."
+  (let ((methods (gnus-agent-covered-methods)))
+    (while methods
+      (gnus-close-server (pop methods)))))
+
+;;;###autoload
+(defun gnus-unplugged ()
+  "Start Gnus unplugged."
+  (interactive)
+  (setq gnus-plugged nil)
+  (gnus))
+
+;;;###autoload
+(defun gnus-plugged ()
+  "Start Gnus plugged."
+  (interactive)
+  (setq gnus-plugged t)
+  (gnus))
+
+;;;###autoload
+(defun gnus-slave-unplugged (&optional arg)
+  "Read news as a slave unplugged."
+  (interactive "P")
+  (setq gnus-plugged nil)
+  (gnus arg nil 'slave))
+
+;;;###autoload
+(defun gnus-agentize ()
+  "Allow Gnus to be an offline newsreader.
+
+The gnus-agentize function is now called internally by gnus when
+gnus-agent is set.  If you wish to avoid calling gnus-agentize,
+customize gnus-agent to nil.
+
+This will modify the `gnus-setup-news-hook', and
+`message-send-mail-real-function' variables, and install the Gnus agent
+minor mode in all Gnus buffers."
+  (interactive)
+  (gnus-open-agent)
+  (setq message-send-mail-real-function 'gnus-agent-send-mail)
+
+  ;; If the servers file doesn't exist, auto-agentize some servers and
+  ;; save the servers file so this auto-agentizing isn't invoked
+  ;; again.
+  (when (and (not (file-exists-p (nnheader-concat
+                                 gnus-agent-directory "lib/servers")))
+            gnus-agent-auto-agentize-methods)
+    (gnus-message 3 "First time agent user, agentizing remote groups...")
+    (mapc
+     (lambda (server-or-method)
+       (let ((method (gnus-server-to-method server-or-method)))
+        (when (memq (car method)
+                    gnus-agent-auto-agentize-methods)
+          (push (gnus-method-to-server method)
+                gnus-agent-covered-methods)
+          (setq gnus-agent-method-p-cache nil))))
+     (cons gnus-select-method gnus-secondary-select-methods))
+    (gnus-agent-write-servers)))
+
+(defun gnus-agent-queue-setup (&optional group-name)
+  "Make sure the queue group exists.
+Optional arg GROUP-NAME allows to specify another group."
+  (unless (gnus-gethash (format "nndraft:%s" (or group-name "queue"))
+                       gnus-newsrc-hashtb)
+    (gnus-request-create-group (or group-name "queue") '(nndraft ""))
+    (let ((gnus-level-default-subscribed 1))
+      (gnus-subscribe-group (format "nndraft:%s" (or group-name "queue"))
+                           nil '(nndraft "")))
+    (gnus-group-set-parameter
+     (format "nndraft:%s" (or group-name "queue"))
+     'gnus-dummy '((gnus-draft-mode)))))
+
+(defun gnus-agent-send-mail ()
+  (if (or (not gnus-agent-queue-mail)
+         (and gnus-plugged (not (eq gnus-agent-queue-mail 'always))))
+      (message-multi-smtp-send-mail)
+    (goto-char (point-min))
+    (re-search-forward
+     (concat "^" (regexp-quote mail-header-separator) "\n"))
+    (replace-match "\n")
+    (gnus-agent-insert-meta-information 'mail)
+    (gnus-request-accept-article "nndraft:queue" nil t t)
+    (gnus-group-refresh-group "nndraft:queue")))
+
+(defun gnus-agent-insert-meta-information (type &optional method)
+  "Insert meta-information into the message that says how it's to be posted.
+TYPE can be either `mail' or `news'.  If the latter, then METHOD can
+be a select method."
+  (save-excursion
+    (message-remove-header gnus-agent-meta-information-header)
+    (goto-char (point-min))
+    (insert gnus-agent-meta-information-header ": "
+           (symbol-name type) " " (format "%S" method)
+           "\n")
+    (forward-char -1)
+    (while (search-backward "\n" nil t)
+      (replace-match "\\n" t t))))
+
+(defun gnus-agent-restore-gcc ()
+  "Restore GCC field from saved header."
+  (save-excursion
+    (goto-char (point-min))
+    (while (re-search-forward
+           (concat "^" (regexp-quote gnus-agent-gcc-header) ":") nil t)
+      (replace-match "Gcc:" 'fixedcase))))
+
+(defun gnus-agent-any-covered-gcc ()
+  (save-restriction
+    (message-narrow-to-headers)
+    (let* ((gcc (mail-fetch-field "gcc" nil t))
+          (methods (and gcc
+                        (mapcar 'gnus-inews-group-method
+                                (message-unquote-tokens
+                                 (message-tokenize-header
+                                  gcc " ,")))))
+          covered)
+      (while (and (not covered) methods)
+       (setq covered (gnus-agent-method-p (car methods))
+             methods (cdr methods)))
+      covered)))
+
+;;;###autoload
+(defun gnus-agent-possibly-save-gcc ()
+  "Save GCC if Gnus is unplugged."
+  (when (and (not gnus-plugged) (gnus-agent-any-covered-gcc))
+    (save-excursion
+      (goto-char (point-min))
+      (let ((case-fold-search t))
+       (while (re-search-forward "^gcc:" nil t)
+         (replace-match (concat gnus-agent-gcc-header ":") 'fixedcase))))))
+
+(defun gnus-agent-possibly-do-gcc ()
+  "Do GCC if Gnus is plugged."
+  (when (or gnus-plugged (not (gnus-agent-any-covered-gcc)))
+    (gnus-inews-do-gcc)))
+
+;;;
+;;; Group mode commands
+;;;
+
+(defun gnus-agent-fetch-groups (n)
+  "Put all new articles in the current groups into the Agent."
+  (interactive "P")
+  (unless gnus-plugged
+    (error "Groups can't be fetched when Gnus is unplugged"))
+  (gnus-group-iterate n 'gnus-agent-fetch-group))
+
+(defun gnus-agent-fetch-group (&optional group)
+  "Put all new articles in GROUP into the Agent."
+  (interactive (list (gnus-group-group-name)))
+  (setq group (or group gnus-newsgroup-name))
+  (unless group
+    (error "No group on the current line"))
+  (if (not (gnus-agent-group-covered-p group))
+      (message "%s isn't covered by the agent" group)
+    (gnus-agent-while-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))))))
+
+(defun gnus-agent-add-group (category arg)
+  "Add the current group to an agent category."
+  (interactive
+   (list
+    (intern
+     (gnus-completing-read
+      "Add to category"
+      (mapcar (lambda (cat) (symbol-name (car cat)))
+             gnus-category-alist)
+      t))
+    current-prefix-arg))
+  (let ((cat (assq category gnus-category-alist))
+       c groups)
+    (gnus-group-iterate arg
+      (lambda (group)
+       (when (gnus-agent-cat-groups (setq c (gnus-group-category group)))
+         (setf (gnus-agent-cat-groups c)
+                (delete group (gnus-agent-cat-groups c))))
+       (push group groups)))
+    (setf (gnus-agent-cat-groups cat)
+          (nconc (gnus-agent-cat-groups cat) groups))
+    (gnus-category-write)))
+
+(defun gnus-agent-remove-group (arg)
+  "Remove the current group from its agent category, if any."
+  (interactive "P")
+  (let (c)
+    (gnus-group-iterate arg
+      (lambda (group)
+       (when (gnus-agent-cat-groups (setq c (gnus-group-category group)))
+         (setf (gnus-agent-cat-groups c)
+                (delete group (gnus-agent-cat-groups c))))))
+    (gnus-category-write)))
+
+(defun gnus-agent-synchronize-flags ()
+  "Synchronize unplugged flags with servers."
+  (interactive)
+  (save-excursion
+    (dolist (gnus-command-method (gnus-agent-covered-methods))
+      (when (file-exists-p (gnus-agent-lib-file "flags"))
+       (gnus-agent-synchronize-flags-server gnus-command-method)))))
+
+(defun gnus-agent-possibly-synchronize-flags ()
+  "Synchronize flags according to `gnus-agent-synchronize-flags'."
+  (interactive)
+  (save-excursion
+    (dolist (gnus-command-method (gnus-agent-covered-methods))
+      (when (eq (gnus-server-status gnus-command-method) 'ok)
+       (gnus-agent-possibly-synchronize-flags-server gnus-command-method)))))
+
+(defun gnus-agent-synchronize-flags-server (method)
+  "Synchronize flags set when unplugged for server."
+  (let ((gnus-command-method method)
+       (gnus-agent nil))
+    (when (file-exists-p (gnus-agent-lib-file "flags"))
+      (set-buffer (get-buffer-create " *Gnus Agent flag synchronize*"))
+      (erase-buffer)
+      (nnheader-insert-file-contents (gnus-agent-lib-file "flags"))
+      (cond ((null gnus-plugged)
+            (gnus-message
+             1 "You must be plugged to synchronize flags with server %s"
+             (nth 1 gnus-command-method)))
+           ((null (gnus-check-server gnus-command-method))
+            (gnus-message
+             1 "Couldn't open server %s" (nth 1 gnus-command-method)))
+           (t
+            (condition-case err
+                (while t
+                  (let ((bgn (point)))
+                    (eval (read (current-buffer)))
+                    (delete-region bgn (point))))
+              (end-of-file
+               (delete-file (gnus-agent-lib-file "flags")))
+              (error
+               (let ((file (gnus-agent-lib-file "flags")))
+                 (write-region (point-min) (point-max)
+                               (gnus-agent-lib-file "flags") nil 'silent)
+                 (error "Couldn't set flags from file %s due to %s"
+                        file (error-message-string err)))))))
+      (kill-buffer nil))))
+
+(defun gnus-agent-possibly-synchronize-flags-server (method)
+  "Synchronize flags for server according to `gnus-agent-synchronize-flags'."
+  (when (and (file-exists-p (gnus-agent-lib-file "flags"))
+            (or (and gnus-agent-synchronize-flags
+                     (not (eq gnus-agent-synchronize-flags 'ask)))
+                (and (eq gnus-agent-synchronize-flags 'ask)
+                     (gnus-y-or-n-p
+                      (gnus-format-message
+                       "Synchronize flags on server `%s'? "
+                       (cadr method))))))
+    (gnus-agent-synchronize-flags-server method)))
+
+;;;###autoload
+(defun gnus-agent-rename-group (old-group new-group)
+  "Rename fully-qualified OLD-GROUP as NEW-GROUP.
+Always updates the agent, even when disabled, as the old agent
+files would corrupt gnus when the agent was next enabled.
+Depends upon the caller to determine whether group renaming is
+supported."
+  (let* ((old-command-method (gnus-find-method-for-group old-group))
+        (old-path           (directory-file-name
+                             (let ((gnus-command-method old-command-method))
+                               (gnus-agent-group-pathname old-group))))
+        (new-command-method (gnus-find-method-for-group new-group))
+        (new-path           (directory-file-name
+                             (let ((gnus-command-method new-command-method))
+                               (gnus-agent-group-pathname new-group))))
+        (file-name-coding-system nnmail-pathname-coding-system))
+    (gnus-rename-file old-path new-path t)
+
+    (let* ((old-real-group (gnus-group-real-name old-group))
+          (new-real-group (gnus-group-real-name new-group))
+          (old-active (gnus-agent-get-group-info old-command-method old-real-group)))
+      (gnus-agent-save-group-info old-command-method old-real-group nil)
+      (gnus-agent-save-group-info new-command-method new-real-group old-active)
+
+      (let ((old-local (gnus-agent-get-local old-group
+                                            old-real-group old-command-method)))
+       (gnus-agent-set-local old-group
+                             nil nil
+                             old-real-group old-command-method)
+       (gnus-agent-set-local new-group
+                             (car old-local) (cdr old-local)
+                             new-real-group new-command-method)))))
+
+;;;###autoload
+(defun gnus-agent-delete-group (group)
+  "Delete fully-qualified GROUP.
+Always updates the agent, even when disabled, as the old agent
+files would corrupt gnus when the agent was next enabled.
+Depends upon the caller to determine whether group deletion is
+supported."
+  (let* ((command-method (gnus-find-method-for-group group))
+        (path           (directory-file-name
+                         (let ((gnus-command-method command-method))
+                           (gnus-agent-group-pathname group))))
+        (file-name-coding-system nnmail-pathname-coding-system))
+    (gnus-delete-directory path)
+
+    (let* ((real-group (gnus-group-real-name group)))
+      (gnus-agent-save-group-info command-method real-group nil)
+      ;; FIXME: Does gnus-agent-get-local have any useful side-effect?
+      (gnus-agent-get-local group real-group command-method)
+      (gnus-agent-set-local group
+                            nil nil
+                            real-group command-method))))
+
+;;;
+;;; Server mode commands
+;;;
+
+(defun gnus-agent-add-server ()
+  "Enroll SERVER in the agent program."
+  (interactive)
+  (let* ((server       (gnus-server-server-name))
+         (named-server (gnus-server-named-server))
+         (method       (and server
+                            (gnus-server-get-method nil server))))
+    (unless server
+      (error "No server on the current line"))
+
+    (when (gnus-agent-method-p method)
+      (error "Server already in the agent program"))
+
+    (push named-server gnus-agent-covered-methods)
+
+    (setq gnus-agent-method-p-cache nil)
+    (gnus-server-update-server server)
+    (gnus-agent-write-servers)
+    (gnus-message 1 "Entered %s into the Agent" server)))
+
+(defun gnus-agent-remove-server ()
+  "Remove SERVER from the agent program."
+  (interactive)
+  (let* ((server       (gnus-server-server-name))
+         (named-server (gnus-server-named-server)))
+    (unless server
+      (error "No server on the current line"))
+
+    (unless (member named-server gnus-agent-covered-methods)
+      (error "Server not in the agent program"))
+
+    (setq gnus-agent-covered-methods
+          (delete named-server gnus-agent-covered-methods)
+          gnus-agent-method-p-cache nil)
+
+    (gnus-server-update-server server)
+    (gnus-agent-write-servers)
+    (gnus-message 1 "Removed %s from the agent" server)))
+
+(defun gnus-agent-read-servers ()
+  "Read the alist of covered servers."
+  (setq gnus-agent-covered-methods
+        (gnus-agent-read-file
+         (nnheader-concat gnus-agent-directory "lib/servers"))
+        gnus-agent-method-p-cache nil)
+
+  ;; I am called so early in start-up that I can not validate server
+  ;; names.  When that is the case, I skip the validation.  That is
+  ;; alright as the gnus startup code calls the validate methods
+  ;; directly.
+  (if gnus-server-alist
+      (gnus-agent-read-servers-validate)))
+
+(defun gnus-agent-read-servers-validate ()
+  (mapcar (lambda (server-or-method)
+            (let* ((server (if (stringp server-or-method)
+                               server-or-method
+                             (gnus-method-to-server server-or-method)))
+                   (method (gnus-server-to-method server)))
+              (if method
+                  (unless (member server gnus-agent-covered-methods)
+                    (push server gnus-agent-covered-methods)
+                    (setq gnus-agent-method-p-cache nil))
+                (gnus-message 8 "Ignoring disappeared server `%s'" server))))
+          (prog1 gnus-agent-covered-methods
+            (setq gnus-agent-covered-methods nil))))
+
+(defun gnus-agent-read-servers-validate-native (native-method)
+  (setq gnus-agent-covered-methods
+        (mapcar (lambda (method)
+                  (if (or (not method)
+                          (equal method native-method))
+                      "native"
+                    method)) gnus-agent-covered-methods)))
+
+(defun gnus-agent-write-servers ()
+  "Write the alist of covered servers."
+  (gnus-make-directory (nnheader-concat gnus-agent-directory "lib"))
+  (let ((coding-system-for-write nnheader-file-coding-system)
+       (file-name-coding-system nnmail-pathname-coding-system))
+    (with-temp-file (nnheader-concat gnus-agent-directory "lib/servers")
+      (prin1 gnus-agent-covered-methods
+            (current-buffer)))))
+
+;;;
+;;; Summary commands
+;;;
+
+(defun gnus-agent-mark-article (n &optional unmark)
+  "Mark the next N articles as downloadable.
+If N is negative, mark backward instead.  If UNMARK is non-nil, remove
+the mark instead.  The difference between N and the actual number of
+articles marked is returned."
+  (interactive "p")
+  (let ((backward (< n 0))
+       (n (abs n)))
+    (while (and
+           (> n 0)
+           (progn
+             (gnus-summary-set-agent-mark
+              (gnus-summary-article-number) unmark)
+             (zerop (gnus-summary-next-subject (if backward -1 1) nil t))))
+      (setq n (1- n)))
+    (when (/= 0 n)
+      (gnus-message 7 "No more articles"))
+    (gnus-summary-recenter)
+    (gnus-summary-position-point)
+    n))
+
+(defun gnus-agent-unmark-article (n)
+  "Remove the downloadable mark from the next N articles.
+If N is negative, unmark backward instead.  The difference between N and
+the actual number of articles unmarked is returned."
+  (interactive "p")
+  (gnus-agent-mark-article n t))
+
+(defun gnus-agent-toggle-mark (n)
+  "Toggle the downloadable mark from the next N articles.
+If N is negative, toggle backward instead.  The difference between N and
+the actual number of articles toggled is returned."
+  (interactive "p")
+  (gnus-agent-mark-article n 'toggle))
+
+(defun gnus-summary-set-agent-mark (article &optional unmark)
+  "Mark ARTICLE as downloadable.  If UNMARK is nil, article is marked.
+When UNMARK is t, the article is unmarked.  For any other value, the
+article's mark is toggled."
+  (let ((unmark (cond ((eq nil unmark)
+                      nil)
+                     ((eq t unmark)
+                      t)
+                     (t
+                      (memq article gnus-newsgroup-downloadable)))))
+    (when (gnus-summary-goto-subject article nil t)
+      (gnus-summary-update-mark
+       (if unmark
+           (progn
+             (setq gnus-newsgroup-downloadable
+                   (delq article gnus-newsgroup-downloadable))
+             (gnus-article-mark article))
+        (setq gnus-newsgroup-downloadable
+              (gnus-add-to-sorted-list gnus-newsgroup-downloadable article))
+        gnus-downloadable-mark)
+       'unread))))
+
+;;;###autoload
+(defun gnus-agent-get-undownloaded-list ()
+  "Construct list of articles that have not been downloaded."
+  (let ((gnus-command-method (gnus-find-method-for-group gnus-newsgroup-name)))
+    (when (set (make-local-variable 'gnus-newsgroup-agentized)
+               (gnus-agent-method-p gnus-command-method))
+      (let* ((alist (gnus-agent-load-alist gnus-newsgroup-name))
+             (headers (sort (mapcar (lambda (h)
+                                      (mail-header-number h))
+                                    gnus-newsgroup-headers) '<))
+             (cached (and gnus-use-cache gnus-newsgroup-cached))
+             (undownloaded (list nil))
+             (tail-undownloaded undownloaded)
+             (unfetched (list nil))
+             (tail-unfetched unfetched))
+       (while (and alist headers)
+         (let ((a (caar alist))
+               (h (car headers)))
+           (cond ((< a h)
+                  ;; Ignore IDs in the alist that are not being
+                  ;; displayed in the summary.
+                  (setq alist (cdr alist)))
+                 ((> a h)
+                   ;; Headers that are not in the alist should be
+                   ;; fictitious (see nnagent-retrieve-headers); they
+                   ;; imply that this article isn't in the agent.
+                  (gnus-agent-append-to-list tail-undownloaded h)
+                  (gnus-agent-append-to-list tail-unfetched    h)
+                   (setq headers (cdr headers)))
+                 ((cdar alist)
+                  (setq alist (cdr alist))
+                  (setq headers (cdr headers))
+                  nil                  ; ignore already downloaded
+                  )
+                 (t
+                  (setq alist (cdr alist))
+                  (setq headers (cdr headers))
+
+                   ;; This article isn't in the agent.  Check to see
+                   ;; if it is in the cache.  If it is, it's been
+                   ;; downloaded.
+                   (while (and cached (< (car cached) a))
+                     (setq cached (cdr cached)))
+                   (unless (equal a (car cached))
+                     (gnus-agent-append-to-list tail-undownloaded a))))))
+
+       (while headers
+          (let ((num (pop headers)))
+            (gnus-agent-append-to-list tail-undownloaded num)
+            (gnus-agent-append-to-list tail-unfetched    num)))
+
+       (setq gnus-newsgroup-undownloaded (cdr undownloaded)
+              gnus-newsgroup-unfetched    (cdr unfetched))))))
+
+(defun gnus-agent-catchup ()
+  "Mark as read all unhandled articles.
+An article is unhandled if it is neither cached, nor downloaded, nor
+downloadable."
+  (interactive)
+  (save-excursion
+    (let ((articles gnus-newsgroup-undownloaded))
+      (when (or gnus-newsgroup-downloadable
+                gnus-newsgroup-cached)
+        (setq articles (gnus-sorted-ndifference
+                       (gnus-sorted-ndifference
+                        (gnus-copy-sequence articles)
+                        gnus-newsgroup-downloadable)
+                       gnus-newsgroup-cached)))
+
+      (while articles
+        (gnus-summary-mark-article
+         (pop articles) gnus-catchup-mark)))
+    (gnus-summary-position-point)))
+
+(defun gnus-agent-summary-fetch-series ()
+  "Fetch the process-marked articles into the Agent."
+  (interactive)
+  (when gnus-newsgroup-processable
+    (setq gnus-newsgroup-downloadable
+          (let* ((dl gnus-newsgroup-downloadable)
+                (processable (sort (gnus-copy-sequence gnus-newsgroup-processable) '<))
+                 (gnus-newsgroup-downloadable processable))
+           (gnus-agent-summary-fetch-group)
+
+            ;; For each article that I processed that is no longer
+            ;; undownloaded, remove its processable mark.
+
+           (mapc #'gnus-summary-remove-process-mark
+                 (gnus-sorted-ndifference gnus-newsgroup-processable gnus-newsgroup-undownloaded))
+
+            ;; The preceding call to (gnus-agent-summary-fetch-group)
+            ;; updated the temporary gnus-newsgroup-downloadable to
+            ;; remove each article successfully fetched.  Now, I
+            ;; update the real gnus-newsgroup-downloadable to only
+            ;; include undownloaded articles.
+           (gnus-sorted-ndifference dl (gnus-sorted-ndifference processable gnus-newsgroup-undownloaded))))))
+
+(defun gnus-agent-summary-fetch-group (&optional all)
+  "Fetch the downloadable articles in the group.
+Optional arg ALL, if non-nil, means to fetch all articles."
+  (interactive "P")
+  (let ((articles
+        (if all gnus-newsgroup-articles
+          gnus-newsgroup-downloadable))
+       (gnus-command-method (gnus-find-method-for-group gnus-newsgroup-name))
+        fetched-articles)
+    (gnus-agent-while-plugged
+      (unless articles
+        (error "No articles to download"))
+      (gnus-agent-with-fetch
+        (setq gnus-newsgroup-undownloaded
+              (gnus-sorted-ndifference
+               gnus-newsgroup-undownloaded
+               (setq fetched-articles
+                     (gnus-agent-fetch-articles
+                      gnus-newsgroup-name articles)))))
+      (save-excursion
+        (dolist (article articles)
+          (let ((was-marked-downloadable
+                 (memq article gnus-newsgroup-downloadable)))
+            (cond (gnus-agent-mark-unread-after-downloaded
+                   (setq gnus-newsgroup-downloadable
+                         (delq article gnus-newsgroup-downloadable))
+                  (when (and (not (member article gnus-newsgroup-dormant))
+                             (not (member article gnus-newsgroup-marked)))
+                    (gnus-summary-mark-article article gnus-unread-mark)))
+                  (was-marked-downloadable
+                   (gnus-summary-set-agent-mark article t)))
+            (when (gnus-summary-goto-subject article nil t)
+              (gnus-summary-update-download-mark article))))))
+    fetched-articles))
+
+(defun gnus-agent-fetch-selected-article ()
+  "Fetch the current article as it is selected.
+This can be added to `gnus-select-article-hook' or
+`gnus-mark-article-hook'."
+  (let ((gnus-command-method gnus-current-select-method))
+    (when (and gnus-plugged (gnus-agent-method-p gnus-command-method))
+      (when (gnus-agent-fetch-articles
+             gnus-newsgroup-name
+            (list gnus-current-article))
+       (setq gnus-newsgroup-undownloaded
+             (delq gnus-current-article gnus-newsgroup-undownloaded))
+        (gnus-summary-update-download-mark gnus-current-article)))))
+
+;;;
+;;; Internal functions
+;;;
+
+(defun gnus-agent-synchronize-group-flags (group actions server)
+"Update a plugged group by performing the indicated actions."
+  (let* ((gnus-command-method (gnus-server-to-method server))
+        (info
+         ;; This initializer is required as gnus-request-set-mark
+         ;; calls gnus-group-real-name to strip off the host name
+         ;; before calling the backend.  Now that the backend is
+         ;; trying to call gnus-request-set-mark, I have to
+         ;; reconstruct the original group name.
+         (or (gnus-get-info group)
+             (gnus-get-info
+              (setq group (gnus-group-full-name
+                           group gnus-command-method))))))
+    (gnus-request-set-mark group actions)
+
+    (when info
+      (dolist (action actions)
+       (let ((range (nth 0 action))
+             (what  (nth 1 action))
+             (marks (nth 2 action)))
+         (dolist (mark marks)
+           (cond ((eq mark 'read)
+                  (gnus-info-set-read
+                   info
+                   (funcall (if (eq what 'add)
+                                'gnus-range-add
+                              'gnus-remove-from-range)
+                            (gnus-info-read info)
+                            range))
+                  (gnus-get-unread-articles-in-group
+                   info
+                   (gnus-active (gnus-info-group info))))
+                 ((memq mark '(tick))
+                  (let ((info-marks (assoc mark (gnus-info-marks info))))
+                    (unless info-marks
+                      (gnus-info-set-marks info (cons (setq info-marks (list mark)) (gnus-info-marks info))))
+                    (setcdr info-marks (funcall (if (eq what 'add)
+                                 'gnus-range-add
+                               'gnus-remove-from-range)
+                             (cdr info-marks)
+                             range))))))))
+
+      ;;Marks can be synchronized at any time by simply toggling from
+      ;;unplugged to plugged.  If that is what is happening right now, make
+      ;;sure that the group buffer is up to date.
+          (when (gnus-buffer-live-p gnus-group-buffer)
+            (gnus-group-update-group group t)))
+    nil))
+
+(defun gnus-agent-save-active (method &optional groups-p)
+  "Sync the agent's active file with the current buffer.
+Pass non-nil for GROUPS-P if the buffer starts out in groups format.
+Regardless, both the file and the buffer end up in active format
+if METHOD is agentized; otherwise the function is a no-op."
+  (when (gnus-agent-method-p method)
+    (let* ((gnus-command-method method)
+          (new (gnus-make-hashtable (count-lines (point-min) (point-max))))
+          (file (gnus-agent-lib-file "active")))
+      (if groups-p
+         (gnus-groups-to-gnus-format nil new)
+       (gnus-active-to-gnus-format nil new))
+      (gnus-agent-write-active file new)
+      (erase-buffer)
+      (let ((nnheader-file-coding-system gnus-agent-file-coding-system))
+       (nnheader-insert-file-contents file)))))
+
+(defun gnus-agent-write-active (file new)
+    (gnus-make-directory (file-name-directory file))
+    (let ((nnmail-active-file-coding-system gnus-agent-file-coding-system))
+      ;; The hashtable contains real names of groups.  However, do NOT
+      ;; add the foreign server prefix as gnus-active-to-gnus-format
+      ;; will add it while reading the file.
+      (gnus-write-active-file file new nil)))
+
+;;;###autoload
+(defun gnus-agent-possibly-alter-active (group active &optional info)
+  "Possibly expand a group's active range to include articles
+downloaded into the agent."
+  (let* ((gnus-command-method (or gnus-command-method
+                                  (gnus-find-method-for-group group))))
+    (when (gnus-agent-method-p gnus-command-method)
+      (let* ((local (gnus-agent-get-local group))
+             (active-min (or (car active) 0))
+             (active-max (or (cdr active) 0))
+             (agent-min (or (car local) active-min))
+             (agent-max (or (cdr local) active-max)))
+
+        (when (< agent-min active-min)
+          (setcar active agent-min))
+
+        (when (> agent-max active-max)
+          (setcdr active agent-max))
+
+        (when (and info (< agent-max (- active-min 100)))
+          ;; I'm expanding the active range by such a large amount
+          ;; that there is a gap of more than 100 articles between the
+          ;; last article known to the agent and the first article
+          ;; currently available on the server.  This gap contains
+          ;; articles that have been lost, mark them as read so that
+          ;; gnus doesn't waste resources trying to fetch them.
+
+          ;; NOTE: I don't do this for smaller gaps (< 100) as I don't
+          ;; want to modify the local file everytime someone restarts
+          ;; gnus.  The small gap will cause a tiny performance hit
+          ;; when gnus tries, and fails, to retrieve the articles.
+          ;; Still that should be smaller than opening a buffer,
+          ;; printing this list to the buffer, and then writing it to a
+          ;; file.
+
+          (let ((read (gnus-info-read info)))
+            (gnus-info-set-read
+             info
+             (gnus-range-add
+              read
+              (list (cons (1+ agent-max)
+                          (1- active-min))))))
+
+          ;; Lie about the agent's local range for this group to
+          ;; disable the set read each time this server is opened.
+          ;; NOTE: Opening this group will restore the valid local
+          ;; range but it will also expand the local range to
+          ;; encompass the new active range.
+          (gnus-agent-set-local group agent-min (1- active-min)))))))
+
+(defun gnus-agent-save-group-info (method group active)
+  "Update a single group's active range in the agent's copy of the server's active file."
+  (when (gnus-agent-method-p method)
+    (let* ((gnus-command-method (or method gnus-command-method))
+          (coding-system-for-write nnheader-file-coding-system)
+          (file-name-coding-system nnmail-pathname-coding-system)
+          (file (gnus-agent-lib-file "active"))
+          oactive-min oactive-max)
+      (gnus-make-directory (file-name-directory file))
+      (with-temp-file file
+       ;; Emacs got problem to match non-ASCII group in multibyte buffer.
+       (mm-disable-multibyte)
+       (when (file-exists-p file)
+         (nnheader-insert-file-contents file)
+
+          (goto-char (point-min))
+          (when (re-search-forward
+                 (concat "^" (regexp-quote group) " ") nil t)
+            (save-excursion
+              (setq oactive-max (read (current-buffer))        ;; max
+                    oactive-min (read (current-buffer)))) ;; min
+            (gnus-delete-line)))
+       (when active
+         (insert (format "%S %d %d y\n" (intern group)
+                         (max (or oactive-max (cdr active)) (cdr active))
+                         (min (or oactive-min (car active)) (car active))))
+         (goto-char (point-max))
+         (while (search-backward "\\." nil t)
+           (delete-char 1)))))))
+
+(defun gnus-agent-get-group-info (method group)
+  "Get a single group's active range in the agent's copy of the server's active file."
+  (when (gnus-agent-method-p method)
+    (let* ((gnus-command-method (or method gnus-command-method))
+          (coding-system-for-write nnheader-file-coding-system)
+          (file-name-coding-system nnmail-pathname-coding-system)
+          (file (gnus-agent-lib-file "active"))
+          oactive-min oactive-max)
+      (gnus-make-directory (file-name-directory file))
+      (with-temp-buffer
+       ;; Emacs got problem to match non-ASCII group in multibyte buffer.
+       (mm-disable-multibyte)
+       (when (file-exists-p file)
+         (nnheader-insert-file-contents file)
+
+          (goto-char (point-min))
+          (when (re-search-forward
+                 (concat "^" (regexp-quote group) " ") nil t)
+            (save-excursion
+              (setq oactive-max (read (current-buffer))        ;; max
+                    oactive-min (read (current-buffer))) ;; min
+             (cons oactive-min oactive-max))))))))
+
+(defvar gnus-agent-decoded-group-names nil
+  "Alist of non-ASCII group names and decoded ones.")
+
+(defun gnus-agent-decoded-group-name (group)
+  "Return a decoded group name of GROUP."
+  (or (cdr (assoc group gnus-agent-decoded-group-names))
+      (if (string-match "[^\000-\177]" group)
+         (let ((decoded (gnus-group-decoded-name group)))
+           (push (cons group decoded) gnus-agent-decoded-group-names)
+           decoded)
+       group)))
+
+(defun gnus-agent-group-path (group)
+  "Translate GROUP into a file name."
+
+  ;; NOTE: This is what nnmail-group-pathname does as of Apr 2003.
+  ;; The two methods must be kept synchronized, which is why
+  ;; gnus-agent-group-pathname was added.
+
+  (setq group
+        (nnheader-translate-file-chars
+         (nnheader-replace-duplicate-chars-in-string
+          (nnheader-replace-chars-in-string
+           (gnus-group-real-name (gnus-agent-decoded-group-name group))
+           ?/ ?_)
+          ?. ?_)))
+  (if (or nnmail-use-long-file-names
+          (file-directory-p (expand-file-name group (gnus-agent-directory))))
+      group
+    (nnheader-replace-chars-in-string group ?. ?/)))
+
+(defun gnus-agent-group-pathname (group)
+  "Translate GROUP into a file name."
+  ;; nnagent uses nnmail-group-pathname to read articles while
+  ;; unplugged.  The agent must, therefore, use the same directory
+  ;; while plugged.
+  (nnmail-group-pathname
+   (gnus-group-real-name (gnus-agent-decoded-group-name group))
+   (if gnus-command-method
+       (gnus-agent-directory)
+     (let ((gnus-command-method (gnus-find-method-for-group group)))
+       (gnus-agent-directory)))))
+
+(defun gnus-agent-get-function (method)
+  (if (gnus-online method)
+      (car method)
+    (require 'nnagent)
+    'nnagent))
+
+(defun gnus-agent-covered-methods ()
+  "Return the subset of methods that are covered by the agent."
+  (delq nil (mapcar #'gnus-server-to-method gnus-agent-covered-methods)))
+
+;;; History functions
+
+(defun gnus-agent-history-buffer ()
+  (cdr (assoc (gnus-agent-method) gnus-agent-history-buffers)))
+
+(defun gnus-agent-open-history ()
+  (save-excursion
+    (push (cons (gnus-agent-method)
+               (set-buffer (gnus-get-buffer-create
+                            (format " *Gnus agent %s history*"
+                                    (gnus-agent-method)))))
+         gnus-agent-history-buffers)
+    (mm-disable-multibyte) ;; everything is binary
+    (erase-buffer)
+    (insert "\n")
+    (let ((file (gnus-agent-lib-file "history")))
+      (when (file-exists-p file)
+       (nnheader-insert-file-contents file))
+      (set (make-local-variable 'gnus-agent-file-name) file))))
+
+(defun gnus-agent-close-history ()
+  (when (gnus-buffer-live-p gnus-agent-current-history)
+    (kill-buffer gnus-agent-current-history)
+    (setq gnus-agent-history-buffers
+         (delq (assoc (gnus-agent-method) gnus-agent-history-buffers)
+               gnus-agent-history-buffers))))
+
+;;;
+;;; Fetching
+;;;
+
+(defun gnus-agent-fetch-articles (group articles)
+  "Fetch ARTICLES from GROUP and put them into the Agent."
+  (when (and articles
+            (gnus-online (gnus-group-method group)))
+    (gnus-agent-load-alist group)
+    (let* ((alist gnus-agent-article-alist)
+           (headers (if (< (length articles) 2) nil gnus-newsgroup-headers))
+           (selected-sets (list nil))
+           (current-set-size 0)
+           article
+           header-number)
+      ;; Check each article
+      (while (setq article (pop articles))
+        ;; Skip alist entries preceding this article
+        (while (> article (or (caar alist) (1+ article)))
+          (setq alist (cdr alist)))
+
+        ;; Prune off articles that we have already fetched.
+        (unless (and (eq article (caar alist))
+                     (cdar alist))
+          ;; Skip headers preceding this article
+          (while (> article
+                    (setq header-number
+                          (let* ((header (car headers)))
+                            (if header
+                                (mail-header-number header)
+                              (1+ article)))))
+            (setq headers (cdr headers)))
+
+          ;; Add this article to the current set
+          (setcar selected-sets (cons article (car selected-sets)))
+
+          ;; Update the set size, when the set is too large start a
+          ;; new one.  I do this after adding the article as I want at
+          ;; least one article in each set.
+          (when (< gnus-agent-max-fetch-size
+                   (setq current-set-size
+                        (+ current-set-size
+                           (if (= header-number article)
+                                (let ((char-size (mail-header-chars
+                                                  (car headers))))
+                                  (if (<= char-size 0)
+                                      ;; The char size was missing/invalid,
+                                      ;; assume a worst-case situation of
+                                      ;; 65 char/line.  If the line count
+                                      ;; is missing, arbitrarily assume a
+                                      ;; size of 1000 characters.
+                                     (max (* 65 (mail-header-lines
+                                                 (car headers)))
+                                          1000)
+                                    char-size))
+                             0))))
+            (setcar selected-sets (nreverse (car selected-sets)))
+            (setq selected-sets (cons nil selected-sets)
+                  current-set-size 0))))
+
+      (when (or (cdr selected-sets) (car selected-sets))
+        (let* ((fetched-articles (list nil))
+               (tail-fetched-articles fetched-articles)
+               (dir (gnus-agent-group-pathname group))
+               (date (time-to-days (current-time)))
+               (case-fold-search t)
+               pos crosses
+              (file-name-coding-system nnmail-pathname-coding-system))
+
+          (setcar selected-sets (nreverse (car selected-sets)))
+          (setq selected-sets (nreverse selected-sets))
+
+          (gnus-make-directory dir)
+         (gnus-message 7 "Fetching articles for %s..."
+                       (gnus-agent-decoded-group-name group))
+
+          (unwind-protect
+              (while (setq articles (pop selected-sets))
+                ;; Fetch the articles from the backend.
+                (if (gnus-check-backend-function 'retrieve-articles group)
+                    (setq pos (gnus-retrieve-articles articles group))
+                  (with-temp-buffer
+                    (let (article)
+                      (while (setq article (pop articles))
+                        (gnus-message 10 "Fetching article %s for %s..."
+                                     article
+                                     (gnus-agent-decoded-group-name group))
+                        (when (or
+                               (gnus-backlog-request-article group article
+                                                             nntp-server-buffer)
+                               (gnus-request-article article group))
+                          (goto-char (point-max))
+                          (push (cons article (point)) pos)
+                          (insert-buffer-substring nntp-server-buffer)))
+                      (copy-to-buffer
+                      nntp-server-buffer (point-min) (point-max))
+                      (setq pos (nreverse pos)))))
+                ;; Then save these articles into the Agent.
+                (with-current-buffer nntp-server-buffer
+                  (while pos
+                    (narrow-to-region (cdar pos) (or (cdadr pos) (point-max)))
+                    (goto-char (point-min))
+                    (unless (eobp) ;; Don't save empty articles.
+                      (when (search-forward "\n\n" nil t)
+                        (when (search-backward "\nXrefs: " nil t)
+                          ;; Handle cross posting.
+                          (goto-char (match-end 0)) ; move to end of header name
+                          (skip-chars-forward "^ ") ; skip server name
+                          (skip-chars-forward " ")
+                          (setq crosses nil)
+                          (while (looking-at "\\([^: \n]+\\):\\([0-9]+\\) *")
+                            (push (cons (buffer-substring (match-beginning 1)
+                                                          (match-end 1))
+                                        (string-to-number
+                                        (buffer-substring (match-beginning 2)
+                                                          (match-end 2))))
+                                  crosses)
+                            (goto-char (match-end 0)))
+                          (gnus-agent-crosspost crosses (caar pos) date)))
+                      (goto-char (point-min))
+                      (let ((coding-system-for-write
+                             gnus-agent-file-coding-system))
+                        (write-region (point-min) (point-max)
+                                      (concat dir (number-to-string (caar pos)))
+                                      nil 'silent))
+
+                      (gnus-agent-append-to-list
+                      tail-fetched-articles (caar pos)))
+                    (widen)
+                    (setq pos (cdr pos)))))
+
+            (gnus-agent-save-alist group (cdr fetched-articles) date)
+           (gnus-agent-update-files-total-fetched-for group (cdr fetched-articles))
+
+            (gnus-message 7 ""))
+          (cdr fetched-articles))))))
+
+(defun gnus-agent-unfetch-articles (group articles)
+  "Delete ARTICLES that were fetched from GROUP into the agent."
+  (when articles
+    (gnus-agent-with-refreshed-group
+     group
+     (gnus-agent-load-alist group)
+     (let* ((alist (cons nil gnus-agent-article-alist))
+           (articles (sort articles #'<))
+           (next-possibility alist)
+           (delete-this (pop articles)))
+       (while (and (cdr next-possibility) delete-this)
+        (let ((have-this (caar (cdr next-possibility))))
+          (cond
+           ((< delete-this have-this)
+            (setq delete-this (pop articles)))
+           ((= delete-this have-this)
+            (let ((timestamp (cdar (cdr next-possibility))))
+              (when timestamp
+                (let* ((file-name (concat (gnus-agent-group-pathname group)
+                                          (number-to-string have-this)))
+                       (size-file
+                        (float (or (and gnus-agent-total-fetched-hashtb
+                                        (nth 7 (file-attributes file-name)))
+                                   0)))
+                       (file-name-coding-system
+                        nnmail-pathname-coding-system))
+                  (delete-file file-name)
+                  (gnus-agent-update-files-total-fetched-for
+                   group (- size-file)))))
+
+            (setcdr next-possibility (cddr next-possibility)))
+           (t
+            (setq next-possibility (cdr next-possibility))))))
+       (setq gnus-agent-article-alist (cdr alist))
+       (gnus-agent-save-alist group)))))
+
+(defun gnus-agent-crosspost (crosses article &optional date)
+  (setq date (or date t))
+
+  (let (gnus-agent-article-alist group alist beg end)
+    (with-current-buffer gnus-agent-overview-buffer
+      (when (nnheader-find-nov-line article)
+       (forward-word 1)
+       (setq beg (point))
+       (setq end (progn (forward-line 1) (point)))))
+    (while crosses
+      (setq group (caar crosses))
+      (unless (setq alist (assoc group gnus-agent-group-alist))
+       (push (setq alist (list group (gnus-agent-load-alist (caar crosses))))
+             gnus-agent-group-alist))
+      (setcdr alist (cons (cons (cdar crosses) date) (cdr alist)))
+      (with-current-buffer (gnus-get-buffer-create
+                           (format " *Gnus agent overview %s*"group))
+       (when (= (point-max) (point-min))
+         (push (cons group (current-buffer)) gnus-agent-buffer-alist)
+         (ignore-errors
+          (let ((file-name-coding-system nnmail-pathname-coding-system))
+            (nnheader-insert-file-contents
+             (gnus-agent-article-name ".overview" group)))))
+       (nnheader-find-nov-line (string-to-number (cdar crosses)))
+       (insert (string-to-number (cdar crosses)))
+       (insert-buffer-substring gnus-agent-overview-buffer beg end)
+        (gnus-agent-check-overview-buffer))
+      (setq crosses (cdr crosses)))))
+
+(defun gnus-agent-backup-overview-buffer ()
+  (when gnus-newsgroup-name
+    (let ((root (gnus-agent-article-name ".overview" gnus-newsgroup-name))
+          (cnt 0)
+          name
+         (file-name-coding-system nnmail-pathname-coding-system))
+      (while (file-exists-p
+             (setq name (concat root "~"
+                                (int-to-string (setq cnt (1+ cnt))) "~"))))
+      (write-region (point-min) (point-max) name nil 'no-msg)
+      (gnus-message 1 "Created backup copy of overview in %s." name)))
+  t)
+
+(defun gnus-agent-check-overview-buffer (&optional buffer)
+  "Check the overview file given for sanity.
+In particular, checks that the file is sorted by article number
+and that there are no duplicates."
+  (let ((prev-num -1)
+        (backed-up nil))
+    (save-excursion
+      (when buffer
+       (set-buffer buffer))
+      (save-restriction
+       (widen)
+       (goto-char (point-min))
+
+       (while (< (point) (point-max))
+         (let ((p (point))
+               (cur (condition-case nil
+                        (read (current-buffer))
+                      (error nil))))
+           (cond
+            ((or (not (integerp cur))
+                 (not (eq (char-after) ?\t)))
+              (or backed-up
+                  (setq backed-up (gnus-agent-backup-overview-buffer)))
+             (gnus-message 1
+                           "Overview buffer contains garbage `%s'."
+                           (buffer-substring
+                            p (point-at-eol))))
+            ((= cur prev-num)
+             (or backed-up
+                  (setq backed-up (gnus-agent-backup-overview-buffer)))
+              (gnus-message 1
+                           "Duplicate overview line for %d" cur)
+             (delete-region p (progn (forward-line 1) (point))))
+            ((< cur prev-num)
+             (or backed-up
+                  (setq backed-up (gnus-agent-backup-overview-buffer)))
+              (gnus-message 1 "Overview buffer not sorted!")
+             (sort-numeric-fields 1 (point-min) (point-max))
+             (goto-char (point-min))
+             (setq prev-num -1))
+            (t
+             (setq prev-num cur)))
+           (forward-line 1)))))))
+
+(defun gnus-agent-flush-server (&optional server-or-method)
+  "Flush all agent index files for every subscribed group within
+  the given SERVER-OR-METHOD.  When called with nil, the current
+  value of gnus-command-method identifies the server."
+  (let* ((gnus-command-method (if server-or-method
+                                 (gnus-server-to-method server-or-method)
+                               gnus-command-method))
+        (alist gnus-newsrc-alist))
+    (while alist
+      (let ((entry (pop alist)))
+       (when (gnus-methods-equal-p gnus-command-method (gnus-info-method entry))
+         (gnus-agent-flush-group (gnus-info-group entry)))))))
+
+(defun gnus-agent-flush-group (group)
+  "Flush the agent's index files such that the GROUP no longer
+appears to have any local content.  The actual content, the
+article files, may then be deleted using gnus-agent-expire-group.
+If flushing was a mistake, the gnus-agent-regenerate-group method
+provides an undo mechanism by reconstructing the index files from
+the article files."
+  (interactive (list (gnus-agent-read-group)))
+
+  (let* ((gnus-command-method (or gnus-command-method
+                                 (gnus-find-method-for-group group)))
+        (overview (gnus-agent-article-name ".overview" group))
+        (agentview (gnus-agent-article-name ".agentview" group))
+        (file-name-coding-system nnmail-pathname-coding-system))
+
+    (if (file-exists-p overview)
+       (delete-file overview))
+    (if (file-exists-p agentview)
+       (delete-file agentview))
+
+    (gnus-agent-update-view-total-fetched-for group nil gnus-command-method)
+    (gnus-agent-update-view-total-fetched-for group t   gnus-command-method)
+
+    ;(gnus-agent-set-local group nil nil)
+    ;(gnus-agent-save-local t)
+    (gnus-agent-save-group-info nil group nil)))
+
+(defun gnus-agent-flush-cache ()
+  "Flush the agent's index files such that the group no longer
+appears to have any local content.  The actual content, the
+article files, is then deleted using gnus-agent-expire-group. The
+gnus-agent-regenerate-group method provides an undo mechanism by
+reconstructing the index files from the article files."
+  (interactive)
+  (save-excursion
+    (let ((file-name-coding-system nnmail-pathname-coding-system))
+      (while gnus-agent-buffer-alist
+       (set-buffer (cdar gnus-agent-buffer-alist))
+       (let ((coding-system-for-write gnus-agent-file-coding-system))
+         (write-region (point-min) (point-max)
+                       (gnus-agent-article-name ".overview"
+                                                (caar gnus-agent-buffer-alist))
+                       nil 'silent))
+       (setq gnus-agent-buffer-alist (cdr gnus-agent-buffer-alist)))
+      (while gnus-agent-group-alist
+       (with-temp-file (gnus-agent-article-name
+                        ".agentview" (caar gnus-agent-group-alist))
+         (princ (cdar gnus-agent-group-alist))
+         (insert "\n")
+         (princ 1 (current-buffer))
+         (insert "\n"))
+       (setq gnus-agent-group-alist (cdr gnus-agent-group-alist))))))
+
+;;;###autoload
+(defun gnus-agent-find-parameter (group symbol)
+  "Search for GROUPs SYMBOL in the group's parameters, the group's
+topic parameters, the group's category, or the customizable
+variables.  Returns the first non-nil value found."
+  (or (gnus-group-find-parameter group symbol t)
+      (gnus-group-parameter-value (cdr (gnus-group-category group)) symbol t)
+      (symbol-value
+       (cdr
+        (assq symbol
+              '((agent-short-article . gnus-agent-short-article)
+                (agent-long-article . gnus-agent-long-article)
+                (agent-low-score . gnus-agent-low-score)
+                (agent-high-score . gnus-agent-high-score)
+                (agent-days-until-old . gnus-agent-expire-days)
+                (agent-enable-expiration
+                 . gnus-agent-enable-expiration)
+                (agent-predicate . gnus-agent-predicate)))))))
+
+(defun gnus-agent-fetch-headers (group)
+  "Fetch interesting headers into the agent.  The group's overview
+file will be updated to include the headers while a list of available
+article numbers will be returned."
+  (let* ((fetch-all (and gnus-agent-consider-all-articles
+                         ;; Do not fetch all headers if the predicate
+                         ;; implies that we only consider unread articles.
+                         (not (gnus-predicate-implies-unread
+                               (gnus-agent-find-parameter group
+                                                          'agent-predicate)))))
+         (articles (if fetch-all
+                      (if gnus-newsgroup-maximum-articles
+                          (let ((active (gnus-active group)))
+                            (gnus-uncompress-range
+                             (cons (max (car active)
+                                        (- (cdr active)
+                                           gnus-newsgroup-maximum-articles
+                                           -1))
+                                   (cdr active))))
+                        (gnus-uncompress-range (gnus-active group)))
+                     (gnus-list-of-unread-articles group)))
+         (gnus-decode-encoded-word-function 'identity)
+        (gnus-decode-encoded-address-function 'identity)
+         (file (gnus-agent-article-name ".overview" group))
+        (file-name-coding-system nnmail-pathname-coding-system))
+
+    (unless fetch-all
+      ;; Add articles with marks to the list of article headers we want to
+      ;; fetch.  Don't fetch articles solely on the basis of a recent or seen
+      ;; mark, but do fetch recent or seen articles if they have other, more
+      ;; interesting marks.  (We have to fetch articles with boring marks
+      ;; because otherwise the agent will remove their marks.)
+      (dolist (arts (gnus-info-marks (gnus-get-info group)))
+        (unless (memq (car arts) '(seen recent killed cache))
+          (setq articles (gnus-range-add articles (cdr arts)))))
+      (setq articles (sort (gnus-uncompress-sequence articles) '<)))
+
+    ;; At this point, I have the list of articles to consider for
+    ;; fetching.  This is the list that I'll return to my caller. Some
+    ;; of these articles may have already been fetched.  That's OK as
+    ;; the fetch article code will filter those out.  Internally, I'll
+    ;; filter this list to just those articles whose headers need to
+    ;; be fetched.
+    (let ((articles articles))
+      ;; Remove known articles.
+      (when (and (or gnus-agent-cache
+                     (not gnus-plugged))
+                 (gnus-agent-load-alist group))
+        ;; Remove articles marked as downloaded.
+        (if fetch-all
+            ;; I want to fetch all headers in the active range.
+            ;; Therefore, exclude only those headers that are in the
+            ;; article alist.
+            ;; NOTE: This is probably NOT what I want to do after
+            ;; agent expiration in this group.
+            (setq articles (gnus-agent-uncached-articles articles group))
+
+          ;; I want to only fetch those headers that have never been
+          ;; fetched.  Therefore, exclude all headers that are, or
+          ;; WERE, in the article alist.
+          (let ((low (1+ (caar (last gnus-agent-article-alist))))
+                (high (cdr (gnus-active group))))
+            ;; Low can be greater than High when the same group is
+            ;; fetched twice in the same session {The first fetch will
+            ;; fill the article alist such that (last
+            ;; gnus-agent-article-alist) equals (cdr (gnus-active
+            ;; group))}.  The addition of one(the 1+ above) then
+            ;; forces Low to be greater than High.  When this happens,
+            ;; gnus-list-range-intersection returns nil which
+            ;; indicates that no headers need to be fetched. -- Kevin
+            (setq articles (gnus-list-range-intersection
+                            articles (list (cons low high)))))))
+
+      (when articles
+       (gnus-message
+        10 "gnus-agent-fetch-headers: undownloaded articles are `%s'"
+        (gnus-compress-sequence articles t)))
+
+      (with-current-buffer nntp-server-buffer
+        (if articles
+            (progn
+             (gnus-message 8 "Fetching headers for %s..."
+                           (gnus-agent-decoded-group-name group))
+
+              ;; Fetch them.
+              (gnus-make-directory (nnheader-translate-file-chars
+                                    (file-name-directory file) t))
+
+              (unless (eq 'nov (gnus-retrieve-headers articles group))
+                (nnvirtual-convert-headers))
+              (gnus-agent-check-overview-buffer)
+              ;; Move these headers to the overview buffer so that
+              ;; gnus-agent-braid-nov can merge them with the contents
+              ;; of FILE.
+              (copy-to-buffer
+              gnus-agent-overview-buffer (point-min) (point-max))
+             ;; NOTE: Call g-a-brand-nov even when the file does not
+             ;; exist.  As a minimum, it will validate the article
+             ;; numbers already in the buffer.
+             (gnus-agent-braid-nov articles file)
+              (let ((coding-system-for-write
+                     gnus-agent-file-coding-system))
+                (gnus-agent-check-overview-buffer)
+                (write-region (point-min) (point-max) file nil 'silent))
+             (gnus-agent-update-view-total-fetched-for group t)
+              (gnus-agent-save-alist group articles nil)
+              articles)
+          (ignore-errors
+            (erase-buffer)
+            (nnheader-insert-file-contents file)))))
+    articles))
+
+(defsubst gnus-agent-read-article-number ()
+  "Reads the article number at point.  Returns nil when a valid article number can not be read."
+
+  ;; It is unfortunate but the read function quietly overflows
+  ;; integer.  As a result, I have to use string operations to test
+  ;; for overflow BEFORE calling read.
+  (when (looking-at "[0-9]+\t")
+    (let ((len (- (match-end 0) (match-beginning 0))))
+      (cond ((< len 9)
+            (read (current-buffer)))
+           ((= len 9)
+            ;; Many 9 digit base-10 numbers can be represented in a 27-bit int
+            ;; Back convert from int to string to ensure that this is one of them.
+            (let* ((str1 (buffer-substring (match-beginning 0) (1- (match-end 0))))
+                   (num (read (current-buffer)))
+                   (str2 (int-to-string num)))
+              (when (equal str1 str2)
+                num)))))))
+
+(defsubst gnus-agent-copy-nov-line (article)
+  "Copy the indicated ARTICLE from the overview buffer to the nntp server buffer."
+  (let (art b e)
+    (set-buffer gnus-agent-overview-buffer)
+    (while (and (not (eobp))
+               (or (not (setq art (gnus-agent-read-article-number)))
+                   (< art article)))
+      (forward-line 1))
+    (beginning-of-line)
+    (if (or (eobp)
+           (not (eq article art)))
+       (set-buffer nntp-server-buffer)
+      (setq b (point))
+      (setq e (progn (forward-line 1) (point)))
+      (set-buffer nntp-server-buffer)
+      (insert-buffer-substring gnus-agent-overview-buffer b e))))
+
+(defun gnus-agent-braid-nov (articles file)
+  "Merge agent overview data with given file.
+Takes unvalidated headers for ARTICLES from
+`gnus-agent-overview-buffer' and validated headers from the given
+FILE and places the combined valid headers into
+`nntp-server-buffer'.  This function can be used, when file
+doesn't exist, to valid the overview buffer."
+  (let (start last)
+    (set-buffer gnus-agent-overview-buffer)
+    (goto-char (point-min))
+    (set-buffer nntp-server-buffer)
+    (erase-buffer)
+    (when (file-exists-p file)
+      (nnheader-insert-file-contents file))
+    (goto-char (point-max))
+    (forward-line -1)
+
+    (unless (or (= (point-min) (point-max))
+               (< (setq last (read (current-buffer))) (car articles)))
+      ;; Old and new overlap -- We do it the hard way.
+      (when (nnheader-find-nov-line (car articles))
+        ;; Replacing existing NOV entry
+        (delete-region (point) (progn (forward-line 1) (point))))
+      (gnus-agent-copy-nov-line (pop articles))
+
+      (ignore-errors
+       (while articles
+         (while (let ((art (read (current-buffer))))
+                  (cond ((< art (car articles))
+                         (forward-line 1)
+                         t)
+                        ((= art (car articles))
+                         (beginning-of-line)
+                         (delete-region
+                          (point) (progn (forward-line 1) (point)))
+                         nil)
+                        (t
+                         (beginning-of-line)
+                         nil))))
+
+         (gnus-agent-copy-nov-line (pop articles)))))
+
+    (goto-char (point-max))
+
+    ;; Append the remaining lines
+    (when articles
+      (when last
+       (set-buffer gnus-agent-overview-buffer)
+       (setq start (point))
+       (set-buffer nntp-server-buffer))
+
+      (let ((p (point)))
+       (insert-buffer-substring gnus-agent-overview-buffer start)
+       (goto-char p))
+
+      (setq last (or last -134217728))
+      (while (catch 'problems
+              (let (sort art)
+                (while (not (eobp))
+                  (setq art (gnus-agent-read-article-number))
+                  (cond ((not art)
+                         ;; Bad art num - delete this line
+                         (beginning-of-line)
+                         (delete-region (point) (progn (forward-line 1) (point))))
+                        ((< art last)
+                         ;; Art num out of order - enable sort
+                         (setq sort t)
+                         (forward-line 1))
+                        ((= art last)
+                         ;; Bad repeat of art number - delete this line
+                         (beginning-of-line)
+                         (delete-region (point) (progn (forward-line 1) (point))))
+                        (t
+                         ;; Good art num
+                         (setq last art)
+                         (forward-line 1))))
+                (when sort
+                  ;; something is seriously wrong as we simply shouldn't see out-of-order data.
+                  ;; First, we'll fix the sort.
+                  (sort-numeric-fields 1 (point-min) (point-max))
+
+                  ;; but now we have to consider that we may have duplicate rows...
+                  ;; so reset to beginning of file
+                  (goto-char (point-min))
+                  (setq last -134217728)
+
+                  ;; and throw a code that restarts this scan
+                  (throw 'problems t))
+                nil))))))
+
+;; Keeps the compiler from warning about the free variable in
+;; gnus-agent-read-agentview.
+(defvar gnus-agent-read-agentview)
+
+(defun gnus-agent-load-alist (group)
+  "Load the article-state alist for GROUP."
+  ;; Bind free variable that's used in `gnus-agent-read-agentview'.
+  (let* ((gnus-agent-read-agentview group)
+        (file-name-coding-system nnmail-pathname-coding-system)
+        (agentview (gnus-agent-article-name ".agentview" group)))
+    (setq gnus-agent-article-alist
+         (and (file-exists-p agentview)
+              (gnus-cache-file-contents
+               agentview
+               'gnus-agent-file-loading-cache
+               'gnus-agent-read-agentview)))))
+
+(defun gnus-agent-read-agentview (file)
+  "Load FILE and do a `read' there."
+  (with-temp-buffer
+    (condition-case nil
+       (progn
+         (nnheader-insert-file-contents file)
+         (goto-char (point-min))
+         (let ((alist (read (current-buffer)))
+               (version (condition-case nil (read (current-buffer))
+                          (end-of-file 0)))
+               changed-version)
+
+           (cond
+            ((= version 0)
+             (let ((inhibit-quit t)
+                   entry)
+               (gnus-agent-open-history)
+               (set-buffer (gnus-agent-history-buffer))
+               (goto-char (point-min))
+               (while (not (eobp))
+                 (if (and (looking-at
+                           "[^\t\n]+\t\\([0-9]+\\)\t\\([^ \n]+\\) \\([0-9]+\\)")
+                          (string= (match-string 2)
+                                   gnus-agent-read-agentview)
+                          (setq entry (assoc (string-to-number (match-string 3)) alist)))
+                     (setcdr entry (string-to-number (match-string 1))))
+                 (forward-line 1))
+               (gnus-agent-close-history)
+               (setq changed-version t)))
+            ((= version 1)
+             (setq changed-version (not (= 1 gnus-agent-article-alist-save-format))))
+            ((= version 2)
+             (let (state sequence uncomp)
+               (while alist
+                 (setq state (caar alist)
+                       sequence (inline (gnus-uncompress-range (cdar alist)))
+                       alist (cdr alist))
+                 (while sequence
+                   (push (cons (pop sequence) state) uncomp)))
+               (setq alist (sort uncomp 'car-less-than-car)))
+             (setq changed-version (not (= 2 gnus-agent-article-alist-save-format)))))
+           (when changed-version
+             (let ((gnus-agent-article-alist alist))
+               (gnus-agent-save-alist gnus-agent-read-agentview)))
+           alist))
+      ((end-of-file file-error)
+       ;; The agentview file is missing.
+       (condition-case nil
+          ;; If the agent directory exists, attempt to perform a brute-force
+          ;; reconstruction of its contents.
+          (let* (alist
+                 (file-name-coding-system nnmail-pathname-coding-system)
+                 (file-attributes (directory-files-and-attributes
+                                   (gnus-agent-article-name ""
+                                                            gnus-agent-read-agentview) nil "^[0-9]+$" t)))
+            (while file-attributes
+              (let ((fa (pop file-attributes)))
+                (unless (nth 1 fa)
+                  (push (cons (string-to-number (nth 0 fa)) (time-to-days (nth 5 fa))) alist))))
+            alist)
+        (file-error nil))))))
+
+(defun gnus-agent-save-alist (group &optional articles state)
+  "Save the article-state alist for GROUP."
+  (let* ((file-name-coding-system nnmail-pathname-coding-system)
+        (prev (cons nil gnus-agent-article-alist))
+        (all prev)
+        print-level print-length article)
+    (while (setq article (pop articles))
+      (while (and (cdr prev)
+                  (< (caadr prev) article))
+       (setq prev (cdr prev)))
+      (cond
+       ((not (cdr prev))
+       (setcdr prev (list (cons article state))))
+       ((> (caadr prev) article)
+       (setcdr prev (cons (cons article state) (cdr prev))))
+       ((= (caadr prev) article)
+       (setcdr (cadr prev) state)))
+      (setq prev (cdr prev)))
+    (setq gnus-agent-article-alist (cdr all))
+
+    (gnus-agent-set-local group
+                          (caar gnus-agent-article-alist)
+                          (caar (last gnus-agent-article-alist)))
+
+    (gnus-make-directory (gnus-agent-article-name "" group))
+    (with-temp-file (gnus-agent-article-name ".agentview" group)
+      (cond ((eq gnus-agent-article-alist-save-format 1)
+             (princ gnus-agent-article-alist (current-buffer)))
+            ((eq gnus-agent-article-alist-save-format 2)
+             (let ((alist gnus-agent-article-alist)
+                  article-id day-of-download comp-list compressed)
+              (while alist
+                (setq article-id (caar alist)
+                      day-of-download (cdar alist)
+                      comp-list (assq day-of-download compressed)
+                      alist (cdr alist))
+                (if comp-list
+                    (setcdr comp-list (cons article-id (cdr comp-list)))
+                  (push (list day-of-download article-id) compressed)))
+              (setq alist compressed)
+              (while alist
+                (setq comp-list (pop alist))
+                (setcdr comp-list
+                        (gnus-compress-sequence (nreverse (cdr comp-list)))))
+               (princ compressed (current-buffer)))))
+      (insert "\n")
+      (princ gnus-agent-article-alist-save-format (current-buffer))
+      (insert "\n"))
+
+    (gnus-agent-update-view-total-fetched-for group nil)))
+
+(defvar gnus-agent-article-local nil)
+(defvar gnus-agent-article-local-times nil)
+(defvar gnus-agent-file-loading-local nil)
+
+(defun gnus-agent-load-local (&optional method)
+  "Load the METHOD'S local file.  The local file contains min/max
+article counts for each of the method's subscribed groups."
+  (let ((gnus-command-method (or method gnus-command-method)))
+    (when (or (null gnus-agent-article-local-times)
+             (zerop gnus-agent-article-local-times)
+             (not (gnus-methods-equal-p
+                   gnus-command-method
+                   (symbol-value (intern "+method" gnus-agent-article-local)))))
+      (setq gnus-agent-article-local
+           (gnus-cache-file-contents
+            (gnus-agent-lib-file "local")
+            'gnus-agent-file-loading-local
+            'gnus-agent-read-and-cache-local))
+      (when gnus-agent-article-local-times
+       (incf gnus-agent-article-local-times)))
+    gnus-agent-article-local))
+
+(defun gnus-agent-read-and-cache-local (file)
+  "Load and read FILE then bind its contents to
+gnus-agent-article-local.  If that variable had `dirty' (also known as
+modified) original contents, they are first saved to their own file."
+  (if (and gnus-agent-article-local
+           (symbol-value (intern "+dirty" gnus-agent-article-local)))
+      (gnus-agent-save-local))
+  (gnus-agent-read-local file))
+
+(defun gnus-agent-read-local (file)
+  "Load FILE and do a `read' there."
+  (let ((my-obarray (gnus-make-hashtable (count-lines (point-min)
+                                                      (point-max))))
+        (line 1))
+    (with-temp-buffer
+      (condition-case nil
+         (let ((nnheader-file-coding-system gnus-agent-file-coding-system))
+           (nnheader-insert-file-contents file))
+        (file-error))
+
+      (goto-char (point-min))
+      ;; Skip any comments at the beginning of the file (the only place where they may appear)
+      (while (= (following-char) ?\;)
+        (forward-line 1)
+        (setq line (1+ line)))
+
+      (while (not (eobp))
+        (condition-case err
+            (let (group
+                  min
+                  max
+                  (cur (current-buffer))
+                 (obarray my-obarray))
+              (setq group (read cur)
+                    min (read cur)
+                    max (read cur))
+
+              (when (stringp group)
+                (setq group (intern group my-obarray)))
+
+              ;; NOTE: The '+ 0' ensure that min and max are both numerics.
+              (set group (cons (+ 0 min) (+ 0 max))))
+          (error
+           (gnus-message 3 "Warning - invalid agent local: %s on line %d: %s"
+                         file line (error-message-string err))))
+        (forward-line 1)
+        (setq line (1+ line))))
+
+    (set (intern "+dirty" my-obarray) nil)
+    (set (intern "+method" my-obarray) gnus-command-method)
+    my-obarray))
+
+(defun gnus-agent-save-local (&optional force)
+  "Save gnus-agent-article-local under it method's agent.lib directory."
+  (let ((my-obarray gnus-agent-article-local))
+    (when (and my-obarray
+               (or force (symbol-value (intern "+dirty" my-obarray))))
+      (let* ((gnus-command-method (symbol-value (intern "+method" my-obarray)))
+             ;; NOTE: gnus-command-method is used within gnus-agent-lib-file.
+             (dest (gnus-agent-lib-file "local")))
+        (gnus-make-directory (gnus-agent-lib-file ""))
+
+       (let ((coding-system-for-write gnus-agent-file-coding-system)
+             (file-name-coding-system nnmail-pathname-coding-system))
+         (with-temp-file dest
+           (let ((gnus-command-method (symbol-value (intern "+method" my-obarray)))
+                 print-level print-length
+                 (standard-output (current-buffer)))
+             (mapatoms (lambda (symbol)
+                         (cond ((not (boundp symbol))
+                                nil)
+                               ((member (symbol-name symbol) '("+dirty" "+method"))
+                                nil)
+                               (t
+                                (let ((range (symbol-value symbol)))
+                                  (when range
+                                    (prin1 symbol)
+                                    (princ " ")
+                                    (princ (car range))
+                                    (princ " ")
+                                    (princ (cdr range))
+                                    (princ "\n"))))))
+                       my-obarray))))))))
+
+(defun gnus-agent-get-local (group &optional gmane method)
+  (let* ((gmane (or gmane (gnus-group-real-name group)))
+         (gnus-command-method (or method (gnus-find-method-for-group group)))
+         (local (gnus-agent-load-local))
+         (symb (intern gmane local))
+         (minmax (and (boundp symb) (symbol-value symb))))
+    (unless minmax
+      ;; Bind these so that gnus-agent-load-alist doesn't change the
+      ;; current alist (i.e. gnus-agent-article-alist)
+      (let* ((gnus-agent-article-alist gnus-agent-article-alist)
+             (gnus-agent-file-loading-cache gnus-agent-file-loading-cache)
+             (alist (gnus-agent-load-alist group)))
+        (when alist
+          (setq minmax
+                (cons (caar alist)
+                      (caar (last alist))))
+          (gnus-agent-set-local group (car minmax) (cdr minmax)
+                                gmane gnus-command-method local))))
+    minmax))
+
+(defun gnus-agent-set-local (group min max &optional gmane method local)
+  (let* ((gmane (or gmane (gnus-group-real-name group)))
+         (gnus-command-method (or method (gnus-find-method-for-group group)))
+         (local (or local (gnus-agent-load-local)))
+         (symb (intern gmane local))
+         (minmax (and (boundp symb) (symbol-value symb))))
+    (if (cond ((and minmax
+                    (or (not (eq min (car minmax)))
+                        (not (eq max (cdr minmax))))
+                   min
+                   max)
+               (setcar minmax min)
+               (setcdr minmax max)
+               t)
+              (minmax
+               nil)
+              ((and min max)
+               (set symb (cons min max))
+               t)
+             (t
+              (unintern symb local)))
+        (set (intern "+dirty" local) t))))
+
+(defun gnus-agent-article-name (article group)
+  (expand-file-name article
+                   (file-name-as-directory
+                     (gnus-agent-group-pathname group))))
+
+(defun gnus-agent-batch-confirmation (msg)
+  "Show error message and return t."
+  (gnus-message 1 "%s" msg)
+  t)
+
+;;;###autoload
+(defun gnus-agent-batch-fetch ()
+  "Start Gnus and fetch session."
+  (interactive)
+  (gnus)
+  (let ((gnus-agent-confirmation-function 'gnus-agent-batch-confirmation))
+    (gnus-agent-fetch-session))
+  (gnus-group-exit))
+
+(defun gnus-agent-fetch-session ()
+  "Fetch all articles and headers that are eligible for fetching."
+  (interactive)
+  (unless gnus-agent-covered-methods
+    (error "No servers are covered by the Gnus agent"))
+  (unless gnus-plugged
+    (error "Can't fetch articles while Gnus is unplugged"))
+  (let ((methods (gnus-agent-covered-methods))
+       groups group gnus-command-method)
+    (save-excursion
+      (while methods
+       (setq gnus-command-method (car methods))
+       (when (and (or (gnus-server-opened gnus-command-method)
+                      (gnus-open-server gnus-command-method))
+                  (gnus-online gnus-command-method))
+         (setq groups (gnus-groups-from-server (car methods)))
+         (gnus-agent-with-fetch
+           (while (setq group (pop groups))
+             (when (<= (gnus-group-level group)
+                       gnus-agent-handle-level)
+               (if (or debug-on-error debug-on-quit)
+                   (gnus-agent-fetch-group-1
+                    group gnus-command-method)
+                 (condition-case err
+                     (gnus-agent-fetch-group-1
+                      group gnus-command-method)
+                   (error
+                    (unless (funcall gnus-agent-confirmation-function
+                                     (format "Error %s while fetching session.  Should gnus continue? "
+                                             (error-message-string err)))
+                      (error "Cannot fetch articles into the Gnus agent")))
+                   (quit
+                    (gnus-agent-regenerate-group group)
+                    (unless (funcall gnus-agent-confirmation-function
+                                     (format
+                                      "%s while fetching session.  Should gnus continue? "
+                                      (error-message-string err)))
+                      (signal 'quit
+                              "Cannot fetch articles into the Gnus agent")))))))))
+       (setq methods (cdr methods)))
+      (gnus-run-hooks 'gnus-agent-fetched-hook)
+      (gnus-message 6 "Finished fetching articles into the Gnus agent"))))
+
+(defvar gnus-agent-short-article 500
+  "Articles that have fewer lines than this are short.")
+
+(defvar gnus-agent-long-article 1000
+  "Articles that have more lines than this are long.")
+
+(defvar gnus-agent-low-score 0
+  "Articles that have a score lower than this have a low score.")
+
+(defvar gnus-agent-high-score 0
+  "Articles that have a score higher than this have a high score.")
+
+(defun gnus-agent-fetch-group-1 (group method)
+  "Fetch GROUP."
+  (let ((gnus-command-method method)
+       (gnus-newsgroup-name group)
+       (gnus-newsgroup-dependencies gnus-newsgroup-dependencies)
+        (gnus-newsgroup-headers gnus-newsgroup-headers)
+       (gnus-newsgroup-scored gnus-newsgroup-scored)
+       (gnus-use-cache gnus-use-cache)
+       (gnus-summary-expunge-below gnus-summary-expunge-below)
+       (gnus-summary-mark-below gnus-summary-mark-below)
+       (gnus-orphan-score gnus-orphan-score)
+       ;; Maybe some other gnus-summary local variables should also
+       ;; be put here.
+
+        gnus-headers
+        gnus-score
+        articles
+        predicate info marks
+       )
+    (unless (gnus-check-group group)
+      (error "Can't open server for %s" group))
+
+    ;; Fetch headers.
+    (when (or gnus-newsgroup-active
+              (gnus-active group)
+              (gnus-activate-group group))
+      (let ((marked-articles gnus-newsgroup-downloadable))
+        ;; Identify the articles marked for download
+        (unless gnus-newsgroup-active
+         ;; The variable gnus-newsgroup-active was selected as I need
+         ;; a gnus-summary local variable that is NOT bound to any
+         ;; value (its global value should default to nil).
+          (dolist (mark gnus-agent-download-marks)
+            (let ((arts (cdr (assq mark (gnus-info-marks
+                                         (setq info (gnus-get-info group)))))))
+              (when arts
+                (setq marked-articles (nconc (gnus-uncompress-range arts)
+                                             marked-articles))
+                ))))
+        (setq marked-articles (sort marked-articles '<))
+
+        ;; Fetch any new articles from the server
+        (setq articles (gnus-agent-fetch-headers group))
+
+        ;; Merge new articles with marked
+        (setq articles (sort (append marked-articles articles) '<))
+
+        (when articles
+          ;; Parse them and see which articles we want to fetch.
+          (setq gnus-newsgroup-dependencies
+                (or gnus-newsgroup-dependencies
+                    (make-vector (length articles) 0)))
+          (setq gnus-newsgroup-headers
+                (or gnus-newsgroup-headers
+                    (gnus-get-newsgroup-headers-xover articles nil nil
+                                                      group)))
+          ;; `gnus-agent-overview-buffer' may be killed for
+          ;; timeout reason.  If so, recreate it.
+          (gnus-agent-create-buffer)
+
+          (setq predicate
+                (gnus-get-predicate
+                 (gnus-agent-find-parameter group 'agent-predicate)))
+
+          ;; If the selection predicate requires scoring, score each header
+          (unless (memq predicate '(gnus-agent-true gnus-agent-false))
+            (let ((score-param
+                   (gnus-agent-find-parameter group 'agent-score-file)))
+              ;; Translate score-param into real one
+              (cond
+               ((not score-param))
+               ((eq score-param 'file)
+                (setq score-param (gnus-all-score-files group)))
+               ((stringp (car score-param)))
+               (t
+                (setq score-param (list (list score-param)))))
+              (when score-param
+                (gnus-score-headers score-param))))
+
+          (unless (and (eq predicate 'gnus-agent-false)
+                       (not marked-articles))
+            (let ((arts (list nil)))
+              (let ((arts-tail arts)
+                    (alist (gnus-agent-load-alist group))
+                    (marked-articles marked-articles)
+                    (gnus-newsgroup-headers gnus-newsgroup-headers))
+                (while (setq gnus-headers (pop gnus-newsgroup-headers))
+                  (let ((num (mail-header-number gnus-headers)))
+                    ;; Determine if this article is already in the cache
+                    (while (and alist
+                                (> num (caar alist)))
+                      (setq alist (cdr alist)))
+
+                    (unless (and (eq num (caar alist))
+                                 (cdar alist))
+
+                      ;; Determine if this article was marked for download.
+                      (while (and marked-articles
+                                  (> num (car marked-articles)))
+                        (setq marked-articles
+                              (cdr marked-articles)))
+
+                      ;; When this article is marked, or selected by the
+                      ;; predicate, add it to the download list
+                      (when (or (eq num (car marked-articles))
+                                (let ((gnus-score
+                                       (or (cdr
+                                           (assq num gnus-newsgroup-scored))
+                                           gnus-summary-default-score))
+                                      (gnus-agent-long-article
+                                       (gnus-agent-find-parameter
+                                        group 'agent-long-article))
+                                      (gnus-agent-short-article
+                                       (gnus-agent-find-parameter
+                                        group 'agent-short-article))
+                                      (gnus-agent-low-score
+                                       (gnus-agent-find-parameter
+                                        group 'agent-low-score))
+                                      (gnus-agent-high-score
+                                       (gnus-agent-find-parameter
+                                        group 'agent-high-score))
+                                      (gnus-agent-expire-days
+                                       (gnus-agent-find-parameter
+                                        group 'agent-days-until-old)))
+                                  (funcall predicate)))
+                        (gnus-agent-append-to-list arts-tail num))))))
+
+              (let (fetched-articles)
+                ;; Fetch all selected articles
+                (setq gnus-newsgroup-undownloaded
+                      (gnus-sorted-ndifference
+                      gnus-newsgroup-undownloaded
+                      (setq fetched-articles
+                            (if (cdr arts)
+                                (gnus-agent-fetch-articles group (cdr arts))
+                              nil))))
+
+                (let ((unfetched-articles
+                      (gnus-sorted-ndifference (cdr arts) fetched-articles)))
+                  (if gnus-newsgroup-active
+                      ;; Update the summary buffer
+                      (progn
+                        (dolist (article marked-articles)
+                          (gnus-summary-set-agent-mark article t))
+                        (dolist (article fetched-articles)
+                          (when gnus-agent-mark-unread-after-downloaded
+                           (setq gnus-newsgroup-downloadable
+                                 (delq article gnus-newsgroup-downloadable))
+                           (gnus-summary-mark-article
+                            article gnus-unread-mark))
+                          (when (gnus-summary-goto-subject article nil t)
+                            (gnus-summary-update-download-mark article)))
+                        (dolist (article unfetched-articles)
+                          (gnus-summary-mark-article
+                          article gnus-canceled-mark)))
+
+                    ;; Update the group buffer.
+
+                    ;; When some, or all, of the marked articles came
+                    ;; from the download mark.  Remove that mark.  I
+                    ;; didn't do this earlier as I only want to remove
+                    ;; the marks after the fetch is completed.
+
+                    (dolist (mark gnus-agent-download-marks)
+                      (when (eq mark 'download)
+                        (let ((marked-arts
+                              (assq mark (gnus-info-marks
+                                          (setq info (gnus-get-info group))))))
+                          (when (cdr marked-arts)
+                            (setq marks
+                                 (delq marked-arts (gnus-info-marks info)))
+                            (gnus-info-set-marks info marks)))))
+                    (let ((read (gnus-info-read
+                                (or info (setq info (gnus-get-info group))))))
+                      (gnus-info-set-read
+                      info (gnus-add-to-range read unfetched-articles)))
+
+                    (gnus-group-update-group group t)
+                    (sit-for 0)
+
+                    (gnus-dribble-enter
+                     (concat "(gnus-group-set-info '"
+                             (gnus-prin1-to-string info)
+                             ")")
+                    (concat "^(gnus-group-set-info '(\""
+                            (regexp-quote group) "\""))))))))))))
+
+;;;
+;;; Agent Category Mode
+;;;
+
+(defvar gnus-category-mode-hook nil
+  "Hook run in `gnus-category-mode' buffers.")
+
+(defvar gnus-category-line-format "     %(%20c%): %g\n"
+  "Format of category lines.
+
+Valid specifiers include:
+%c  Topic name (string)
+%g  The number of groups in the topic (integer)
+
+General format specifiers can also be used.  See Info node
+`(gnus)Formatting Variables'.")
+
+(defvar gnus-category-mode-line-format "Gnus: %%b"
+  "The format specification for the category mode line.")
+
+(defvar gnus-agent-predicate 'false
+  "The selection predicate used when no other source is available.")
+
+
+;;; Internal variables.
+
+(defvar gnus-category-buffer "*Agent Category*")
+
+(defvar gnus-tmp-name)
+(defvar gnus-tmp-groups)
+
+(defvar gnus-category-line-format-alist
+  `((?c gnus-tmp-name ?s)
+    (?g gnus-tmp-groups ?d)))
+
+(defvar gnus-category-mode-line-format-alist
+  `((?u user-defined ?s)))
+
+(defvar gnus-category-line-format-spec nil)
+(defvar gnus-category-mode-line-format-spec nil)
+
+(defvar gnus-category-mode-map nil)
+(put 'gnus-category-mode 'mode-class 'special)
+
+(unless gnus-category-mode-map
+  (setq gnus-category-mode-map (make-sparse-keymap))
+  (suppress-keymap gnus-category-mode-map)
+
+  (gnus-define-keys gnus-category-mode-map
+    "q" gnus-category-exit
+    "k" gnus-category-kill
+    "c" gnus-category-copy
+    "a" gnus-category-add
+    "e" gnus-agent-customize-category
+    "p" gnus-category-edit-predicate
+    "g" gnus-category-edit-groups
+    "s" gnus-category-edit-score
+    "l" gnus-category-list
+
+    "\C-c\C-i" gnus-info-find-node
+    "\C-c\C-b" gnus-bug))
+
+(defvar gnus-category-menu-hook nil
+  "*Hook run after the creation of the menu.")
+
+(defun gnus-category-make-menu-bar ()
+  (gnus-turn-off-edit-menu 'category)
+  (unless (boundp 'gnus-category-menu)
+    (easy-menu-define
+     gnus-category-menu gnus-category-mode-map ""
+     '("Categories"
+       ["Add" gnus-category-add t]
+       ["Kill" gnus-category-kill t]
+       ["Copy" gnus-category-copy t]
+       ["Edit category" gnus-agent-customize-category t]
+       ["Edit predicate" gnus-category-edit-predicate t]
+       ["Edit score" gnus-category-edit-score t]
+       ["Edit groups" gnus-category-edit-groups t]
+       ["Exit" gnus-category-exit t]))
+
+    (gnus-run-hooks 'gnus-category-menu-hook)))
+
+(define-derived-mode gnus-category-mode fundamental-mode "Category"
+  "Major mode for listing and editing agent categories.
+
+All normal editing commands are switched off.
+\\<gnus-category-mode-map>
+For more in-depth information on this mode, read the manual
+\(`\\[gnus-info-find-node]').
+
+The following commands are available:
+
+\\{gnus-category-mode-map}"
+  (when (gnus-visual-p 'category-menu 'menu)
+    (gnus-category-make-menu-bar))
+  (gnus-simplify-mode-line)
+  (gnus-set-default-directory)
+  (setq mode-line-process nil)
+  (buffer-disable-undo)
+  (setq truncate-lines t)
+  (setq buffer-read-only t))
+
+(defalias 'gnus-category-position-point 'gnus-goto-colon)
+
+(defun gnus-category-insert-line (category)
+  (let* ((gnus-tmp-name (format "%s" (car category)))
+        (gnus-tmp-groups (length (gnus-agent-cat-groups category))))
+    (beginning-of-line)
+    (gnus-add-text-properties
+     (point)
+     (prog1 (1+ (point))
+       ;; Insert the text.
+       (eval gnus-category-line-format-spec))
+     (list 'gnus-category gnus-tmp-name))))
+
+(defun gnus-enter-category-buffer ()
+  "Go to the Category buffer."
+  (interactive)
+  (gnus-category-setup-buffer)
+  (gnus-configure-windows 'category)
+  (gnus-category-prepare))
+
+(defun gnus-category-setup-buffer ()
+  (unless (get-buffer gnus-category-buffer)
+    (with-current-buffer (gnus-get-buffer-create gnus-category-buffer)
+      (gnus-category-mode))))
+
+(defun gnus-category-prepare ()
+  (gnus-set-format 'category-mode)
+  (gnus-set-format 'category t)
+  (let ((alist gnus-category-alist)
+       (buffer-read-only nil))
+    (erase-buffer)
+    (while alist
+      (gnus-category-insert-line (pop alist)))
+    (goto-char (point-min))
+    (gnus-category-position-point)))
+
+(defun gnus-category-name ()
+  (or (intern (get-text-property (point-at-bol) 'gnus-category))
+      (error "No category on the current line")))
+
+(defun gnus-category-read ()
+  "Read the category alist."
+  (setq gnus-category-alist
+        (or
+         (with-temp-buffer
+           (ignore-errors
+            (nnheader-insert-file-contents (nnheader-concat gnus-agent-directory "lib/categories"))
+            (goto-char (point-min))
+            ;; This code isn't temp, it will be needed so long as
+            ;; anyone may be migrating from an older version.
+
+            ;; Once we're certain that people will not revert to an
+            ;; earlier version, we can take out the old-list code in
+            ;; gnus-category-write.
+            (let* ((old-list (read (current-buffer)))
+                   (new-list (ignore-errors (read (current-buffer)))))
+              (if new-list
+                  new-list
+                ;; Convert from a positional list to an alist.
+                (mapcar
+                 (lambda (c)
+                   (setcdr c
+                           (delq nil
+                                 (gnus-mapcar
+                                  (lambda (valu symb)
+                                    (if valu
+                                        (cons symb valu)))
+                                  (cdr c)
+                                  '(agent-predicate agent-score-file agent-groups))))
+                   c)
+                 old-list)))))
+         (list (gnus-agent-cat-make 'default 'short)))))
+
+(defun gnus-category-write ()
+  "Write the category alist."
+  (setq gnus-category-predicate-cache nil
+       gnus-category-group-cache nil)
+  (gnus-make-directory (nnheader-concat gnus-agent-directory "lib"))
+  (with-temp-file (nnheader-concat gnus-agent-directory "lib/categories")
+    ;; This prin1 is temporary.  It exists so that people can revert
+    ;; to an earlier version of gnus-agent.
+    (prin1 (mapcar (lambda (c)
+              (list (car c)
+                    (cdr (assoc 'agent-predicate c))
+                    (cdr (assoc 'agent-score-file c))
+                    (cdr (assoc 'agent-groups c))))
+                   gnus-category-alist)
+           (current-buffer))
+    (newline)
+    (prin1 gnus-category-alist (current-buffer))))
+
+(defun gnus-category-edit-predicate (category)
+  "Edit the predicate for CATEGORY."
+  (interactive (list (gnus-category-name)))
+  (let ((info (assq category gnus-category-alist)))
+    (gnus-edit-form
+     (gnus-agent-cat-predicate info)
+     (format "Editing the select predicate for category %s" category)
+     `(lambda (predicate)
+        ;; Avoid run-time execution of setf form
+        ;; (setf (gnus-agent-cat-predicate (assq ',category gnus-category-alist))
+        ;;       predicate)
+        ;; use its expansion instead:
+        (gnus-agent-cat-set-property (assq ',category gnus-category-alist)
+                                     'agent-predicate predicate)
+
+       (gnus-category-write)
+       (gnus-category-list)))))
+
+(defun gnus-category-edit-score (category)
+  "Edit the score expression for CATEGORY."
+  (interactive (list (gnus-category-name)))
+  (let ((info (assq category gnus-category-alist)))
+    (gnus-edit-form
+     (gnus-agent-cat-score-file info)
+     (format "Editing the score expression for category %s" category)
+     `(lambda (score-file)
+        ;; Avoid run-time execution of setf form
+        ;; (setf (gnus-agent-cat-score-file (assq ',category gnus-category-alist))
+        ;;       score-file)
+        ;; use its expansion instead:
+        (gnus-agent-cat-set-property (assq ',category gnus-category-alist)
+                                     'agent-score-file score-file)
+
+       (gnus-category-write)
+       (gnus-category-list)))))
+
+(defun gnus-category-edit-groups (category)
+  "Edit the group list for CATEGORY."
+  (interactive (list (gnus-category-name)))
+  (let ((info (assq category gnus-category-alist)))
+    (gnus-edit-form
+     (gnus-agent-cat-groups info)
+     (format "Editing the group list for category %s" category)
+     `(lambda (groups)
+        ;; Avoid run-time execution of setf form
+        ;; (setf (gnus-agent-cat-groups (assq ',category gnus-category-alist))
+        ;;       groups)
+        ;; use its expansion instead:
+        (gnus-agent-set-cat-groups (assq ',category gnus-category-alist)
+                                   groups)
+
+       (gnus-category-write)
+       (gnus-category-list)))))
+
+(defun gnus-category-kill (category)
+  "Kill the current category."
+  (interactive (list (gnus-category-name)))
+  (let ((info (assq category gnus-category-alist))
+       (buffer-read-only nil))
+    (gnus-delete-line)
+    (setq gnus-category-alist (delq info gnus-category-alist))
+    (gnus-category-write)))
+
+(defun gnus-category-copy (category to)
+  "Copy the current category."
+  (interactive (list (gnus-category-name) (intern (read-string "New name: "))))
+  (let ((info (assq category gnus-category-alist)))
+    (push (let ((newcat (gnus-copy-sequence info)))
+            (setf (gnus-agent-cat-name newcat) to)
+            (setf (gnus-agent-cat-groups newcat) nil)
+            newcat)
+         gnus-category-alist)
+    (gnus-category-write)
+    (gnus-category-list)))
+
+(defun gnus-category-add (category)
+  "Create a new category."
+  (interactive "SCategory name: ")
+  (when (assq category gnus-category-alist)
+    (error "Category %s already exists" category))
+  (push (gnus-agent-cat-make category)
+       gnus-category-alist)
+  (gnus-category-write)
+  (gnus-category-list))
+
+(defun gnus-category-list ()
+  "List all categories."
+  (interactive)
+  (gnus-category-prepare))
+
+(defun gnus-category-exit ()
+  "Return to the group buffer."
+  (interactive)
+  (kill-buffer (current-buffer))
+  (gnus-configure-windows 'group t))
+
+;; To avoid having 8-bit characters in the source file.
+(defvar gnus-category-not (list '! 'not (intern (format "%c" 172))))
+
+(defvar gnus-category-predicate-alist
+  '((spam . gnus-agent-spam-p)
+    (short . gnus-agent-short-p)
+    (long . gnus-agent-long-p)
+    (low . gnus-agent-low-scored-p)
+    (high . gnus-agent-high-scored-p)
+    (read . gnus-agent-read-p)
+    (true . gnus-agent-true)
+    (false . gnus-agent-false))
+  "Mapping from short score predicate symbols to predicate functions.")
+
+(defun gnus-agent-spam-p ()
+  "Say whether an article is spam or not."
+  (unless gnus-agent-spam-hashtb
+    (setq gnus-agent-spam-hashtb (gnus-make-hashtable 1000)))
+  (if (not (equal (mail-header-references gnus-headers) ""))
+      nil
+    (let ((string (gnus-simplify-subject (mail-header-subject gnus-headers))))
+      (prog1
+         (gnus-gethash string gnus-agent-spam-hashtb)
+       (gnus-sethash string t gnus-agent-spam-hashtb)))))
+
+(defun gnus-agent-short-p ()
+  "Say whether an article is short or not."
+  (< (mail-header-lines gnus-headers) gnus-agent-short-article))
+
+(defun gnus-agent-long-p ()
+  "Say whether an article is long or not."
+  (> (mail-header-lines gnus-headers) gnus-agent-long-article))
+
+(defun gnus-agent-low-scored-p ()
+  "Say whether an article has a low score or not."
+  (< gnus-score gnus-agent-low-score))
+
+(defun gnus-agent-high-scored-p ()
+  "Say whether an article has a high score or not."
+  (> gnus-score gnus-agent-high-score))
+
+(defun gnus-agent-read-p ()
+  "Say whether an article is read or not."
+  (gnus-member-of-range (mail-header-number gnus-headers)
+                       (gnus-info-read (gnus-get-info gnus-newsgroup-name))))
+
+(defun gnus-category-make-function (predicate)
+  "Make a function from PREDICATE."
+  (let ((func (gnus-category-make-function-1 predicate)))
+    (if (and (= (length func) 1)
+            (symbolp (car func)))
+       (car func)
+      (gnus-byte-compile `(lambda () ,func)))))
+
+(defun gnus-agent-true ()
+  "Return t."
+  t)
+
+(defun gnus-agent-false ()
+  "Return nil."
+  nil)
+
+(defun gnus-category-make-function-1 (predicate)
+  "Make a function from PREDICATE."
+  (cond
+   ;; Functions are just returned as is.
+   ((or (symbolp predicate)
+       (functionp predicate))
+    `(,(or (cdr (assq predicate gnus-category-predicate-alist))
+          predicate)))
+   ;; More complex predicate.
+   ((consp predicate)
+    `(,(cond
+       ((memq (car predicate) '(& and))
+        'and)
+       ((memq (car predicate) '(| or))
+        'or)
+       ((memq (car predicate) gnus-category-not)
+        'not))
+      ,@(mapcar 'gnus-category-make-function-1 (cdr predicate))))
+   (t
+    (error "Unknown predicate type: %s" predicate))))
+
+(defun gnus-get-predicate (predicate)
+  "Return the function implementing PREDICATE."
+  (or (cdr (assoc predicate gnus-category-predicate-cache))
+      (let ((func (gnus-category-make-function predicate)))
+       (push (cons predicate func) gnus-category-predicate-cache)
+       func)))
+
+(defun gnus-predicate-implies-unread (predicate)
+  "Say whether PREDICATE implies unread articles only.
+It is okay to miss some cases, but there must be no false positives.
+That is, if this predicate returns true, then indeed the predicate must
+return only unread articles."
+  (eq t (gnus-function-implies-unread-1
+         (gnus-category-make-function-1 predicate))))
+
+(defun gnus-function-implies-unread-1 (function)
+  "Recursively evaluate a predicate function to determine whether it can select
+any read articles.  Returns t if the function is known to never
+return read articles, nil when it is known to always return read
+articles, and t_nil when the function may return both read and unread
+articles."
+  (let ((func (car function))
+        (args (mapcar 'gnus-function-implies-unread-1 (cdr function))))
+    (cond ((eq func 'and)
+           (cond ((memq t args) ; if any argument returns only unread articles
+                  ;; then that argument constrains the result to only unread articles.
+                  t)
+                 ((memq 't_nil args) ; if any argument is indeterminate
+                  ;; then the result is indeterminate
+                  't_nil)))
+          ((eq func 'or)
+           (cond ((memq nil args) ; if any argument returns read articles
+                  ;; then that argument ensures that the results includes read articles.
+                  nil)
+                 ((memq 't_nil args) ; if any argument is indeterminate
+                  ;; then that argument ensures that the results are indeterminate
+                  't_nil)
+                 (t ; if all arguments return only unread articles
+                  ;; then the result returns only unread articles
+                  t)))
+          ((eq func 'not)
+           (cond ((eq (car args) 't_nil) ; if the argument is indeterminate
+                  ; then the result is indeterminate
+                  (car args))
+                 (t ; otherwise
+                  ; toggle the result to be the opposite of the argument
+                  (not (car args)))))
+          ((eq func 'gnus-agent-read-p)
+           nil) ; The read predicate NEVER returns unread articles
+          ((eq func 'gnus-agent-false)
+           t) ; The false predicate returns t as the empty set excludes all read articles
+          ((eq func 'gnus-agent-true)
+           nil) ; The true predicate ALWAYS returns read articles
+          ((catch 'found-match
+             (let ((alist gnus-category-predicate-alist))
+               (while alist
+                 (if (eq func (cdar alist))
+                     (throw 'found-match t)
+                   (setq alist (cdr alist))))))
+           't_nil) ; All other predicates return read and unread articles
+          (t
+           (error "Unknown predicate function: %s" function)))))
+
+(defun gnus-group-category (group)
+  "Return the category GROUP belongs to."
+  (unless gnus-category-group-cache
+    (setq gnus-category-group-cache (gnus-make-hashtable 1000))
+    (let ((cs gnus-category-alist)
+         groups cat)
+      (while (setq cat (pop cs))
+       (setq groups (gnus-agent-cat-groups cat))
+       (while groups
+         (gnus-sethash (pop groups) cat gnus-category-group-cache)))))
+  (or (gnus-gethash group gnus-category-group-cache)
+      (assq 'default gnus-category-alist)))
+
+(defvar gnus-agent-expire-current-dirs)
+(defvar gnus-agent-expire-stats)
+
+(defun gnus-agent-expire-group (group &optional articles force)
+  "Expire all old articles in GROUP.
+If you want to force expiring of certain articles, this function can
+take ARTICLES, and FORCE parameters as well.
+
+The articles on which the expiration process runs are selected as follows:
+  if ARTICLES is null, all read and unmarked articles.
+  if ARTICLES is t, all articles.
+  if ARTICLES is a list, just those articles.
+FORCE is equivalent to setting the expiration predicates to true."
+  (interactive (list (gnus-agent-read-group)))
+
+  (if (not group)
+      (gnus-agent-expire articles group force)
+    (let (;; Bind gnus-agent-expire-stats to enable tracking of
+         ;; expiration statistics of this single group
+          (gnus-agent-expire-stats (list 0 0 0.0)))
+      (if (or (not (eq articles t))
+              (yes-or-no-p
+               (concat "Are you sure that you want to "
+                       "expire all articles in " group "? ")))
+          (let ((gnus-command-method (gnus-find-method-for-group group))
+                (overview (gnus-get-buffer-create " *expire overview*"))
+                orig)
+            (unwind-protect
+                (let ((active-file (gnus-agent-lib-file "active")))
+                  (when (file-exists-p active-file)
+                    (with-temp-buffer
+                      (nnheader-insert-file-contents active-file)
+                      (gnus-active-to-gnus-format
+                       gnus-command-method
+                       (setq orig (gnus-make-hashtable
+                                   (count-lines (point-min) (point-max))))))
+                    (save-excursion
+                      (gnus-agent-expire-group-1
+                       group overview (gnus-gethash-safe group orig)
+                       articles force))))
+              (kill-buffer overview))))
+      (gnus-message 4 "%s" (gnus-agent-expire-done-message)))))
+
+(defun gnus-agent-expire-group-1 (group overview active articles force)
+  ;; Internal function - requires caller to have set
+  ;; gnus-command-method, initialized overview buffer, and to have
+  ;; provided a non-nil active
+
+  (let ((dir (gnus-agent-group-pathname group))
+       (file-name-coding-system nnmail-pathname-coding-system)
+       (decoded (gnus-agent-decoded-group-name group)))
+    (gnus-agent-with-refreshed-group
+     group
+     (when (boundp 'gnus-agent-expire-current-dirs)
+       (push dir gnus-agent-expire-current-dirs))
+
+     (if (and (not force)
+             (eq 'DISABLE (gnus-agent-find-parameter group
+                                                     'agent-enable-expiration)))
+        (gnus-message 5 "Expiry skipping over %s" decoded)
+       (gnus-message 5 "Expiring articles in %s" decoded)
+       (gnus-agent-load-alist group)
+       (let* ((bytes-freed 0)
+             (size-files-deleted 0.0)
+             (files-deleted 0)
+             (nov-entries-deleted 0)
+             (info (gnus-get-info group))
+             (alist gnus-agent-article-alist)
+             (day (- (time-to-days (current-time))
+                     (gnus-agent-find-parameter group 'agent-days-until-old)))
+             (specials (if (and alist
+                                (not force))
+                           ;; This could be a bit of a problem.  I need to
+                           ;; keep the last article to avoid refetching
+                           ;; headers when using nntp in the backend.  At
+                           ;; the same time, if someone uses a backend
+                           ;; that supports article moving then I may have
+                           ;; to remove the last article to complete the
+                           ;; move.  Right now, I'm going to assume that
+                           ;; FORCE overrides specials.
+                           (list (caar (last alist)))))
+             (unreads ;; Articles that are excluded from the
+              ;; expiration process
+              (cond (gnus-agent-expire-all
+                     ;; All articles are marked read by global decree
+                     nil)
+                    ((eq articles t)
+                     ;; All articles are marked read by function
+                     ;; parameter
+                     nil)
+                    ((not articles)
+                     ;; Unread articles are marked protected from
+                     ;; expiration Don't call
+                     ;; gnus-list-of-unread-articles as it returns
+                     ;; articles that have not been fetched into the
+                     ;; agent.
+                     (ignore-errors
+                       (gnus-agent-unread-articles group)))
+                    (t
+                     ;; All articles EXCEPT those named by the caller
+                     ;; are protected from expiration
+                     (gnus-sorted-difference
+                      (gnus-uncompress-range
+                       (cons (caar alist)
+                             (caar (last alist))))
+                      (sort articles '<)))))
+             (marked ;; More articles that are excluded from the
+              ;; expiration process
+              (cond (gnus-agent-expire-all
+                     ;; All articles are unmarked by global decree
+                     nil)
+                    ((eq articles t)
+                     ;; All articles are unmarked by function
+                     ;; parameter
+                     nil)
+                    (articles
+                     ;; All articles may as well be unmarked as the
+                     ;; unreads list already names the articles we are
+                     ;; going to keep
+                     nil)
+                    (t
+                     ;; Ticked and/or dormant articles are excluded
+                     ;; from expiration
+                     (nconc
+                      (gnus-uncompress-range
+                       (cdr (assq 'tick (gnus-info-marks info))))
+                      (gnus-uncompress-range
+                       (cdr (assq 'dormant
+                                  (gnus-info-marks info))))))))
+             (nov-file (concat dir ".overview"))
+             (cnt 0)
+             (completed -1)
+             dlist
+             type)
+
+        ;; The normal article alist contains elements that look like
+        ;; (article# .  fetch_date) I need to combine other
+        ;; information with this list.  For example, a flag indicating
+        ;; that a particular article MUST BE KEPT.  To do this, I'm
+        ;; going to transform the elements to look like (article#
+        ;; fetch_date keep_flag NOV_entry_position) Later, I'll reverse
+        ;; the process to generate the expired article alist.
+
+        ;; Convert the alist elements to (article# fetch_date nil
+        ;; nil).
+        (setq dlist (mapcar (lambda (e)
+                              (list (car e) (cdr e) nil nil)) alist))
+
+        ;; Convert the keep lists to elements that look like (article#
+        ;; nil keep_flag nil) then append it to the expanded dlist
+        ;; These statements are sorted by ascending precedence of the
+        ;; keep_flag.
+        (setq dlist (nconc dlist
+                           (mapcar (lambda (e)
+                                     (list e nil 'unread  nil))
+                                   unreads)))
+        (setq dlist (nconc dlist
+                           (mapcar (lambda (e)
+                                     (list e nil 'marked  nil))
+                                   marked)))
+        (setq dlist (nconc dlist
+                           (mapcar (lambda (e)
+                                     (list e nil 'special nil))
+                                   specials)))
+
+        (set-buffer overview)
+        (erase-buffer)
+        (buffer-disable-undo)
+        (when (file-exists-p nov-file)
+          (gnus-message 7 "gnus-agent-expire: Loading overview...")
+          (nnheader-insert-file-contents nov-file)
+          (goto-char (point-min))
+
+          (let (p)
+            (while (< (setq p (point)) (point-max))
+              (condition-case nil
+                  ;; If I successfully read an integer (the plus zero
+                  ;; ensures a numeric type), append the position
+                  ;; to the list
+                  (push (list (+ 0 (read (current-buffer))) nil nil
+                              p)
+                        dlist)
+                (error
+                 (gnus-message 1 "gnus-agent-expire: read error \
+occurred when reading expression at %s in %s.  Skipping to next \
+line." (point) nov-file)))
+              ;; Whether I succeeded, or failed, it doesn't matter.
+              ;; Move to the next line then try again.
+              (forward-line 1)))
+
+          (gnus-message
+           7 "gnus-agent-expire: Loading overview... Done"))
+        (set-buffer-modified-p nil)
+
+        ;; At this point, all of the information is in dlist.  The
+        ;; only problem is that much of it is spread across multiple
+        ;; entries.  Sort then MERGE!!
+        (gnus-message 7 "gnus-agent-expire: Sorting entries... ")
+         (setq dlist
+               (sort dlist
+                     (lambda (a b)
+                       (cond ((< (nth 0 a) (nth 0 b))
+                              t)
+                             ((> (nth 0 a) (nth 0 b))
+                              nil)
+                             (t
+                              ;; If two entries have the same article-number
+                              ;; then sort by ascending keep_flag.
+                              (let* ((kf-score '((special . 0)
+                                                 (marked . 1)
+                                                 (unread . 2)))
+                                     (a (or (cdr (assq (nth 2 a) kf-score))
+                                            3))
+                                     (b (or (cdr (assq (nth 2 b) kf-score))
+                                            3)))
+                                (<= a b)))))))
+        (gnus-message 7 "gnus-agent-expire: Sorting entries... Done")
+        (gnus-message 7 "gnus-agent-expire: Merging entries... ")
+        (let ((dlist dlist))
+          (while (cdr dlist)           ; I'm not at the end-of-list
+            (if (eq (caar dlist) (caadr dlist))
+                (let ((first (cdr (car dlist)))
+                      (secnd (cdr (cadr dlist))))
+                  (setcar first (or (car first)
+                                    (car secnd))) ; fetch_date
+                  (setq first (cdr first)
+                        secnd (cdr secnd))
+                  (setcar first (or (car first)
+                                    (car secnd))) ; Keep_flag
+                  (setq first (cdr first)
+                        secnd (cdr secnd))
+                  (setcar first (or (car first)
+                                    (car secnd))) ; NOV_entry_position
+
+                  (setcdr dlist (cddr dlist)))
+              (setq dlist (cdr dlist)))))
+
+        ;; Check the order of the entry positions.  They should be in
+        ;; ascending order.  If they aren't, the positions must be
+        ;; converted to markers.
+        (when (catch 'sort-results
+                (let ((dlist dlist)
+                      (prev-pos -1)
+                      pos)
+                  (while dlist
+                    (if (setq pos (nth 3 (pop dlist)))
+                        (if (< pos prev-pos)
+                            (throw 'sort-results 'unsorted)
+                          (setq prev-pos pos))))))
+          (gnus-message 7 "gnus-agent-expire: Unsorted overview; inserting markers to compensate.")
+          (mapc (lambda (entry)
+                    (let ((pos (nth 3 entry)))
+                      (if pos
+                          (setf (nth 3 entry)
+                                (set-marker (make-marker)
+                                            pos)))))
+                  dlist))
+
+        (gnus-message 7 "gnus-agent-expire: Merging entries... Done")
+
+        (let* ((len (float (length dlist)))
+               (alist (list nil))
+               (tail-alist alist)
+               (position-offset 0)
+               )
+
+          (while dlist
+            (let ((new-completed (truncate (* 100.0
+                                              (/ (setq cnt (1+ cnt))
+                                                 len))))
+                  message-log-max)
+              (when (> new-completed completed)
+                (setq completed new-completed)
+                (gnus-message 7 "%3d%% completed..."  completed)))
+            (let* ((entry          (car dlist))
+                   (article-number (nth 0 entry))
+                   (fetch-date     (nth 1 entry))
+                   (keep           (nth 2 entry))
+                   (marker         (nth 3 entry)))
+
+              (cond
+               ;; Kept articles are unread, marked, or special.
+               (keep
+                (gnus-agent-message 10
+                                    "gnus-agent-expire: %s:%d: Kept %s article%s."
+                                    decoded article-number keep (if fetch-date " and file" ""))
+                (when fetch-date
+                  (unless (file-exists-p
+                           (concat dir (number-to-string
+                                        article-number)))
+                    (setf (nth 1 entry) nil)
+                    (gnus-agent-message 3 "gnus-agent-expire cleared \
+download flag on %s:%d as the cached article file is missing."
+                                        decoded (caar dlist)))
+                  (unless marker
+                    (gnus-message 1 "gnus-agent-expire detected a \
+missing NOV entry.  Run gnus-agent-regenerate-group to restore it.")))
+                (gnus-agent-append-to-list
+                 tail-alist
+                 (cons article-number fetch-date)))
+
+               ;; The following articles are READ, UNMARKED, and
+               ;; ORDINARY.  See if they can be EXPIRED!!!
+               ((setq type
+                      (cond
+                       ((not (integerp fetch-date))
+                        'read) ;; never fetched article (may expire
+                       ;; right now)
+                       ((not (file-exists-p
+                              (concat dir (number-to-string
+                                           article-number))))
+                        (setf (nth 1 entry) nil)
+                        'externally-expired) ;; Can't find the cached
+                       ;; article.  Handle case
+                       ;; as though this article
+                       ;; was never fetched.
+
+                       ;; We now have the arrival day, so we see
+                       ;; whether it's old enough to be expired.
+                       ((< fetch-date day)
+                        'expired)
+                       (force
+                        'forced)))
+
+                ;; I found some reason to expire this entry.
+
+                (let ((actions nil))
+                  (when (memq type '(forced expired))
+                    (ignore-errors     ; Just being paranoid.
+                      (let* ((file-name (nnheader-concat dir (number-to-string
+                                                              article-number)))
+                             (size (float (nth 7 (file-attributes file-name)))))
+                        (incf bytes-freed size)
+                        (incf size-files-deleted size)
+                        (incf files-deleted)
+                        (delete-file file-name))
+                      (push "expired cached article" actions))
+                    (setf (nth 1 entry) nil)
+                    )
+
+                  (when marker
+                    (push "NOV entry removed" actions)
+
+                    (goto-char (if (markerp marker)
+                                   marker
+                                 (- marker position-offset)))
+
+                    (incf nov-entries-deleted)
+
+                    (let* ((from (point-at-bol))
+                           (to (progn (forward-line 1) (point)))
+                           (freed (- to from)))
+                      (incf bytes-freed freed)
+                      (incf position-offset freed)
+                      (delete-region from to)))
+
+                  ;; If considering all articles is set, I can only
+                  ;; expire article IDs that are no longer in the
+                  ;; active range (That is, articles that precede the
+                  ;; first article in the new alist).
+                  (if (and gnus-agent-consider-all-articles
+                           (>= article-number (car active)))
+                      ;; I have to keep this ID in the alist
+                      (gnus-agent-append-to-list
+                       tail-alist (cons article-number fetch-date))
+                    (push (format "Removed %s article number from \
+article alist" type) actions))
+
+                  (when actions
+                    (gnus-agent-message 8 "gnus-agent-expire: %s:%d: %s"
+                                        decoded article-number
+                                        (mapconcat 'identity actions ", ")))))
+               (t
+                (gnus-agent-message
+                 10 "gnus-agent-expire: %s:%d: Article kept as \
+expiration tests failed." decoded article-number)
+                (gnus-agent-append-to-list
+                 tail-alist (cons article-number fetch-date)))
+               )
+
+              ;; Remove markers as I intend to reuse this buffer again.
+              (when (and marker
+                         (markerp marker))
+                (set-marker marker nil))
+
+              (setq dlist (cdr dlist))))
+
+          (setq alist (cdr alist))
+
+          (let ((inhibit-quit t))
+            (unless (equal alist gnus-agent-article-alist)
+              (setq gnus-agent-article-alist alist)
+              (gnus-agent-save-alist group))
+
+            (when (buffer-modified-p)
+              (let ((coding-system-for-write
+                     gnus-agent-file-coding-system))
+                (gnus-make-directory dir)
+                (write-region (point-min) (point-max) nov-file nil
+                              'silent)
+                ;; clear the modified flag as that I'm not confused by
+                ;; its status on the next pass through this routine.
+                (set-buffer-modified-p nil)
+                (gnus-agent-update-view-total-fetched-for group t)))
+
+            (when (eq articles t)
+              (gnus-summary-update-info))))
+
+        (when (boundp 'gnus-agent-expire-stats)
+          (let ((stats gnus-agent-expire-stats))
+            (incf (nth 2 stats) bytes-freed)
+            (incf (nth 1 stats) files-deleted)
+            (incf (nth 0 stats) nov-entries-deleted)))
+
+        (gnus-agent-update-files-total-fetched-for group (- size-files-deleted)))))))
+
+(defun gnus-agent-expire (&optional articles group force)
+  "Expire all old articles.
+If you want to force expiring of certain articles, this function can
+take ARTICLES, GROUP and FORCE parameters as well.
+
+The articles on which the expiration process runs are selected as follows:
+  if ARTICLES is null, all read and unmarked articles.
+  if ARTICLES is t, all articles.
+  if ARTICLES is a list, just those articles.
+Setting GROUP will limit expiration to that group.
+FORCE is equivalent to setting the expiration predicates to true."
+  (interactive)
+
+  (if group
+      (gnus-agent-expire-group group articles force)
+    (if (or (not (eq articles t))
+            (yes-or-no-p "Are you sure that you want to expire all \
+articles in every agentized group? "))
+        (let ((methods (gnus-agent-covered-methods))
+              ;; Bind gnus-agent-expire-current-dirs to enable tracking
+              ;; of agent directories.
+              (gnus-agent-expire-current-dirs nil)
+              ;; Bind gnus-agent-expire-stats to enable tracking of
+              ;; expiration statistics across all groups
+              (gnus-agent-expire-stats (list 0 0 0.0))
+              gnus-command-method overview orig)
+          (setq overview (gnus-get-buffer-create " *expire overview*"))
+          (unwind-protect
+              (while (setq gnus-command-method (pop methods))
+                (let ((active-file (gnus-agent-lib-file "active")))
+                  (when (file-exists-p active-file)
+                    (with-temp-buffer
+                      (nnheader-insert-file-contents active-file)
+                      (gnus-active-to-gnus-format
+                       gnus-command-method
+                       (setq orig (gnus-make-hashtable
+                                   (count-lines (point-min) (point-max))))))
+                    (dolist (expiring-group (gnus-groups-from-server
+                                             gnus-command-method))
+                      (let* ((active
+                              (gnus-gethash-safe expiring-group orig)))
+
+                        (when active
+                          (save-excursion
+                            (gnus-agent-expire-group-1
+                             expiring-group overview active articles force))))))))
+            (kill-buffer overview))
+          (gnus-agent-expire-unagentized-dirs)
+          (gnus-message 4 "%s" (gnus-agent-expire-done-message))))))
+
+(defun gnus-agent-expire-done-message ()
+  (if (and (> gnus-verbose 4)
+           (boundp 'gnus-agent-expire-stats))
+      (let* ((stats gnus-agent-expire-stats)
+             (size (nth 2 stats))
+            (units '(B KB MB GB)))
+        (while (and (> size 1024.0)
+                    (cdr units))
+          (setq size (/ size 1024.0)
+                units (cdr units)))
+
+        (format "Expiry recovered %d NOV entries, deleted %d files,\
+ and freed %.f %s."
+                (nth 0 stats)
+                (nth 1 stats)
+                size (car units)))
+    "Expiry...done"))
+
+(defun gnus-agent-expire-unagentized-dirs ()
+  (when (and gnus-agent-expire-unagentized-dirs
+             (boundp 'gnus-agent-expire-current-dirs))
+    (let* ((keep (gnus-make-hashtable))
+          (file-name-coding-system nnmail-pathname-coding-system))
+
+      (gnus-sethash gnus-agent-directory t keep)
+      (dolist (dir gnus-agent-expire-current-dirs)
+       (when (and (stringp dir)
+                  (file-directory-p dir))
+         (while (not (gnus-gethash dir keep))
+           (gnus-sethash dir t keep)
+           (setq dir (file-name-directory (directory-file-name dir))))))
+
+      (let* (to-remove
+             checker
+             (checker
+              (function
+               (lambda (d)
+                 "Given a directory, check it and its subdirectories for
+              membership in the keep hash.  If it isn't found, add
+              it to to-remove."
+                 (let ((files (directory-files d))
+                       file)
+                   (while (setq file (pop files))
+                     (cond ((equal file ".") ; Ignore self
+                            nil)
+                           ((equal file "..") ; Ignore parent
+                            nil)
+                           ((equal file ".overview")
+                            ;; Directory must contain .overview to be
+                            ;; agent's cache of a group.
+                            (let ((d (file-name-as-directory d))
+                                  r)
+                              ;; Search ancestor's for last directory NOT
+                              ;; found in keep hash.
+                              (while (not (gnus-gethash
+                                           (setq d (file-name-directory d)) keep))
+                                (setq r d
+                                      d (directory-file-name d)))
+                              ;; if ANY ancestor was NOT in keep hash and
+                              ;; it's not already in to-remove, add it to
+                              ;; to-remove.
+                              (if (and r
+                                       (not (member r to-remove)))
+                                  (push r to-remove))))
+                           ((file-directory-p (setq file (nnheader-concat d file)))
+                            (funcall checker file)))))))))
+        (funcall checker (expand-file-name gnus-agent-directory))
+
+        (when (and to-remove
+                   (or gnus-expert-user
+                       (gnus-y-or-n-p
+                        "gnus-agent-expire has identified local directories that are\
+ not currently required by any agentized group.  Do you wish to consider\
+ deleting them?")))
+          (while to-remove
+            (let ((dir (pop to-remove)))
+              (if (or gnus-expert-user
+                     (gnus-y-or-n-p (format "Delete %s? " dir)))
+                  (let* (delete-recursive
+                        files f
+                         (delete-recursive
+                          (function
+                           (lambda (f-or-d)
+                             (ignore-errors
+                               (if (file-directory-p f-or-d)
+                                   (condition-case nil
+                                       (delete-directory f-or-d)
+                                     (file-error
+                                     (setq files (directory-files f-or-d))
+                                     (while files
+                                       (setq f (pop files))
+                                       (or (member f '("." ".."))
+                                           (funcall delete-recursive
+                                                    (nnheader-concat
+                                                     f-or-d f))))
+                                      (delete-directory f-or-d)))
+                                 (delete-file f-or-d)))))))
+                    (funcall delete-recursive dir))))))))))
+
+;;;###autoload
+(defun gnus-agent-batch ()
+  "Start Gnus, send queue and fetch session."
+  (interactive)
+  (let ((init-file-user "")
+       (gnus-always-read-dribble-file t))
+    (gnus))
+  (let ((gnus-agent-confirmation-function 'gnus-agent-batch-confirmation))
+    (gnus-group-send-queue)
+    (gnus-agent-fetch-session)))
+
+(defun gnus-agent-unread-articles (group)
+  (let* ((read (gnus-info-read (gnus-get-info group)))
+        (known (gnus-agent-load-alist group))
+        (unread (list nil))
+        (tail-unread unread))
+    (while (and known read)
+      (let ((candidate (car (pop known))))
+       (while (let* ((range (car read))
+                     (min   (if (numberp range) range (car range)))
+                     (max   (if (numberp range) range (cdr range))))
+                (cond ((or (not min)
+                           (< candidate min))
+                       (gnus-agent-append-to-list tail-unread candidate)
+                       nil)
+                      ((> candidate max)
+                       (setq read (cdr read))
+                        ;; return t so that I always loop one more
+                        ;; time.  If I just iterated off the end of
+                        ;; read, min will become nil and the current
+                        ;; candidate will be added to the unread list.
+                        t))))))
+    (while known
+      (gnus-agent-append-to-list tail-unread (car (pop known))))
+    (cdr unread)))
+
+(defun gnus-agent-uncached-articles (articles group &optional cached-header)
+  "Restrict ARTICLES to numbers already fetched.
+Returns a sublist of ARTICLES that excludes those article ids in GROUP
+that have already been fetched.
+If CACHED-HEADER is nil, articles are only excluded if the article itself
+has been fetched."
+
+  ;; Logically equivalent to: (gnus-sorted-difference articles (mapcar
+  ;; 'car gnus-agent-article-alist))
+
+  ;; Functionally, I don't need to construct a temp list using mapcar.
+
+  (if (and (or gnus-agent-cache (not gnus-plugged))
+           (gnus-agent-load-alist group))
+    (let* ((ref gnus-agent-article-alist)
+           (arts articles)
+           (uncached (list nil))
+           (tail-uncached uncached))
+      (while (and ref arts)
+        (let ((v1 (car arts))
+              (v2 (caar ref)))
+          (cond ((< v1 v2) ; v1 does not appear in the reference list
+                (gnus-agent-append-to-list tail-uncached v1)
+                 (setq arts (cdr arts)))
+                ((= v1 v2)
+                 (unless (or cached-header (cdar ref)) ; v1 is already cached
+                  (gnus-agent-append-to-list tail-uncached v1))
+                 (setq arts (cdr arts))
+                 (setq ref (cdr ref)))
+                (t ; reference article (v2) precedes the list being filtered
+                 (setq ref (cdr ref))))))
+      (while arts
+       (gnus-agent-append-to-list tail-uncached (pop arts)))
+      (cdr uncached))
+    ;; if gnus-agent-load-alist fails, no articles are cached.
+    articles))
+
+(defun gnus-agent-retrieve-headers (articles group &optional fetch-old)
+  (save-excursion
+    (gnus-agent-create-buffer)
+    (let ((gnus-decode-encoded-word-function 'identity)
+         (gnus-decode-encoded-address-function 'identity)
+         (file (gnus-agent-article-name ".overview" group))
+          uncached-articles
+         (file-name-coding-system nnmail-pathname-coding-system))
+      (gnus-make-directory (nnheader-translate-file-chars
+                           (file-name-directory file) t))
+
+      (when fetch-old
+       (setq articles (gnus-uncompress-range
+                       (cons (if (numberp fetch-old)
+                                 (max 1 (- (car articles) fetch-old))
+                               1)
+                             (car (last articles))))))
+
+      ;; Populate temp buffer with known headers
+      (when (file-exists-p file)
+       (with-current-buffer gnus-agent-overview-buffer
+         (erase-buffer)
+         (let ((nnheader-file-coding-system
+                gnus-agent-file-coding-system))
+           (nnheader-insert-nov-file file (car articles)))))
+
+      (if (setq uncached-articles (gnus-agent-uncached-articles articles group
+                                                                t))
+         (progn
+            ;; Populate nntp-server-buffer with uncached headers
+           (set-buffer nntp-server-buffer)
+           (erase-buffer)
+            (cond ((not (eq 'nov (let (gnus-agent) ; Turn off agent
+                                   (gnus-retrieve-headers
+                                    uncached-articles group))))
+                   (nnvirtual-convert-headers))
+                  ((eq 'nntp (car gnus-current-select-method))
+                   ;; The author of gnus-get-newsgroup-headers-xover
+                   ;; reports that the XOVER command is commonly
+                   ;; unreliable. The problem is that recently
+                   ;; posted articles may not be entered into the
+                   ;; NOV database in time to respond to my XOVER
+                   ;; query.
+                   ;;
+                   ;; I'm going to use his assumption that the NOV
+                   ;; database is updated in order of ascending
+                   ;; article ID.  Therefore, a response containing
+                   ;; article ID N implies that all articles from 1
+                   ;; to N-1 are up-to-date.  Therefore, missing
+                   ;; articles in that range have expired.
+
+                   (set-buffer nntp-server-buffer)
+                   (let* ((fetched-articles (list nil))
+                          (tail-fetched-articles fetched-articles)
+                          (min (car articles))
+                          (max (car (last articles))))
+
+                     ;; Get the list of articles that were fetched
+                     (goto-char (point-min))
+                     (let ((pm (point-max))
+                          art)
+                       (while (< (point) pm)
+                        (when (setq art (gnus-agent-read-article-number))
+                           (gnus-agent-append-to-list tail-fetched-articles art))
+                         (forward-line 1)))
+
+                     ;; Clip this list to the headers that will
+                     ;; actually be returned
+                     (setq fetched-articles (gnus-list-range-intersection
+                                             (cdr fetched-articles)
+                                             (cons min max)))
+
+                     ;; Clip the uncached articles list to exclude
+                     ;; IDs after the last FETCHED header.  The
+                     ;; excluded IDs may be fetchable using HEAD.
+                     (if (car tail-fetched-articles)
+                         (setq uncached-articles
+                               (gnus-list-range-intersection
+                                uncached-articles
+                                (cons (car uncached-articles)
+                                      (car tail-fetched-articles)))))
+
+                     ;; Create the list of articles that were
+                     ;; "successfully" fetched.  Success, in this
+                     ;; case, means that the ID should not be
+                     ;; fetched again.  In the case of an expired
+                     ;; article, the header will not be fetched.
+                     (setq uncached-articles
+                           (gnus-sorted-nunion fetched-articles
+                                               uncached-articles))
+                     )))
+
+            ;; Erase the temp buffer
+           (set-buffer gnus-agent-overview-buffer)
+           (erase-buffer)
+
+            ;; Copy the nntp-server-buffer to the temp buffer
+           (set-buffer nntp-server-buffer)
+           (copy-to-buffer gnus-agent-overview-buffer (point-min) (point-max))
+
+           ;; Merge the temp buffer with the known headers (found on
+           ;; disk in FILE) into the nntp-server-buffer
+           (when uncached-articles
+             (gnus-agent-braid-nov uncached-articles file))
+
+           ;; Save the new set of known headers to FILE
+           (set-buffer nntp-server-buffer)
+           (let ((coding-system-for-write
+                  gnus-agent-file-coding-system))
+             (gnus-agent-check-overview-buffer)
+             (write-region (point-min) (point-max) file nil 'silent))
+
+           (gnus-agent-update-view-total-fetched-for group t)
+
+            ;; Update the group's article alist to include the newly
+            ;; fetched articles.
+           (gnus-agent-load-alist group)
+           (gnus-agent-save-alist group uncached-articles nil)
+            )
+
+        ;; Copy the temp buffer to the nntp-server-buffer
+        (set-buffer nntp-server-buffer)
+       (erase-buffer)
+       (insert-buffer-substring gnus-agent-overview-buffer)))
+
+    (if (and fetch-old
+            (not (numberp fetch-old)))
+       t                               ; Don't remove anything.
+      (nnheader-nov-delete-outside-range
+       (car articles)
+       (car (last articles)))
+      t)
+
+    'nov))
+
+(defun gnus-agent-request-article (article group)
+  "Retrieve ARTICLE in GROUP from the agent cache."
+  (when (and gnus-agent
+             (or gnus-agent-cache
+                 (not gnus-plugged))
+             (numberp article))
+    (let* ((gnus-command-method (gnus-find-method-for-group group))
+           (file (gnus-agent-article-name (number-to-string article) group))
+           (buffer-read-only nil)
+          (file-name-coding-system nnmail-pathname-coding-system))
+      (when (and (file-exists-p file)
+                 (> (nth 7 (file-attributes file)) 0))
+        (erase-buffer)
+        (gnus-kill-all-overlays)
+        (let ((coding-system-for-read gnus-cache-coding-system))
+          (insert-file-contents file))
+        t))))
+
+(defun gnus-agent-store-article (article group)
+  (let* ((gnus-command-method (gnus-find-method-for-group group))
+        (file (gnus-agent-article-name (number-to-string article) group))
+        (file-name-coding-system nnmail-pathname-coding-system)
+        (coding-system-for-write gnus-cache-coding-system))
+    (when (not (file-exists-p file))
+      (gnus-make-directory (file-name-directory file))
+      (write-region (point-min) (point-max) file nil 'silent)
+      ;; Tell the Agent when the article was fetched, so that it can
+      ;; be expired later.
+      (gnus-agent-load-alist group)
+      (gnus-agent-save-alist group (list article)
+                            (time-to-days (current-time))))))
+
+(defun gnus-agent-regenerate-group (group &optional reread)
+  "Regenerate GROUP.
+If REREAD is t, all articles in the .overview are marked as unread.
+If REREAD is a list, the specified articles will be marked as unread.
+In addition, their NOV entries in .overview will be refreshed using
+the articles' current headers.
+If REREAD is not nil, downloaded articles are marked as unread."
+  (interactive
+   (list (gnus-agent-read-group)
+         (catch 'mark
+           (while (let (c
+                        (cursor-in-echo-area t)
+                        (echo-keystrokes 0))
+                    (message "Mark as unread: (n)one / (a)ll / all (d)ownloaded articles? (n) ")
+                    (setq c (read-char-exclusive))
+
+                    (cond ((or (eq c ?\r) (eq c ?n) (eq c ?N))
+                           (throw 'mark nil))
+                          ((or (eq c ?a) (eq c ?A))
+                           (throw 'mark t))
+                          ((or (eq c ?d) (eq c ?D))
+                           (throw 'mark 'some)))
+                    (gnus-message 3 "Ignoring unexpected input")
+                    (sit-for 1)
+                    t)))))
+  (when group
+    (gnus-message 5 "Regenerating in %s" (gnus-agent-decoded-group-name group))
+    (let* ((gnus-command-method (or gnus-command-method
+                                   (gnus-find-method-for-group group)))
+          (file (gnus-agent-article-name ".overview" group))
+          (dir (file-name-directory file))
+          (file-name-coding-system nnmail-pathname-coding-system)
+          (downloaded (if (file-exists-p dir)
+                          (sort (delq nil (mapcar (lambda (name)
+                                                    (and (not (file-directory-p (nnheader-concat dir name)))
+                                                         (string-to-number name)))
+                                                  (directory-files dir nil "^[0-9]+$" t)))
+                                '>)
+                        (progn (gnus-make-directory dir) nil)))
+           nov-arts
+          alist header
+          regenerated)
+
+      (mm-with-unibyte-buffer
+       (if (file-exists-p file)
+           (let ((nnheader-file-coding-system
+                  gnus-agent-file-coding-system))
+             (nnheader-insert-file-contents file)))
+       (set-buffer-modified-p nil)
+
+       ;; Load the article IDs found in the overview file.  As a
+       ;; side-effect, validate the file contents.
+       (let ((load t))
+         (while load
+           (setq load nil)
+           (goto-char (point-min))
+           (while (< (point) (point-max))
+             (cond ((and (looking-at "[0-9]+\t")
+                         (<= (- (match-end 0) (match-beginning 0)) 9))
+                    (push (read (current-buffer)) nov-arts)
+                    (forward-line 1)
+                    (let ((l1 (car nov-arts))
+                          (l2 (cadr nov-arts)))
+                      (cond ((and (listp reread) (memq l1 reread))
+                             (gnus-delete-line)
+                             (setq nov-arts (cdr nov-arts))
+                             (gnus-message 4 "gnus-agent-regenerate-group: NOV\
+ entry of article %s deleted." l1))
+                            ((not l2)
+                             nil)
+                            ((< l1 l2)
+                             (gnus-message 3 "gnus-agent-regenerate-group: NOV\
+ entries are NOT in ascending order.")
+                             ;; Don't sort now as I haven't verified
+                             ;; that every line begins with a number
+                             (setq load t))
+                            ((= l1 l2)
+                             (forward-line -1)
+                             (gnus-message 4 "gnus-agent-regenerate-group: NOV\
+ entries contained duplicate of article %s.     Duplicate deleted." l1)
+                             (gnus-delete-line)
+                             (setq nov-arts (cdr nov-arts))))))
+                   (t
+                    (gnus-message 1 "gnus-agent-regenerate-group: NOV\
+ entries contained line that did not begin with an article number.  Deleted\
+ line.")
+                    (gnus-delete-line))))
+           (when load
+             (gnus-message 5 "gnus-agent-regenerate-group: Sorting NOV\
+ entries into ascending order.")
+             (sort-numeric-fields 1 (point-min) (point-max))
+             (setq nov-arts nil))))
+       (gnus-agent-check-overview-buffer)
+
+       ;; Construct a new article alist whose nodes match every header
+       ;; in the .overview file.  As a side-effect, missing headers are
+       ;; reconstructed from the downloaded article file.
+       (while (or downloaded nov-arts)
+         (cond ((and downloaded
+                     (or (not nov-arts)
+                         (> (car downloaded) (car nov-arts))))
+                ;; This entry is missing from the overview file
+                (gnus-message 3 "Regenerating NOV %s %d..."
+                              (gnus-agent-decoded-group-name group)
+                              (car downloaded))
+                (let ((file (concat dir (number-to-string (car downloaded)))))
+                  (mm-with-unibyte-buffer
+                    (nnheader-insert-file-contents file)
+                    (nnheader-remove-body)
+                    (setq header (nnheader-parse-naked-head)))
+                  (mail-header-set-number header (car downloaded))
+                  (if nov-arts
+                      (let ((key (concat "^" (int-to-string (car nov-arts))
+                                         "\t")))
+                        (or (re-search-backward key nil t)
+                            (re-search-forward key))
+                        (forward-line 1))
+                    (goto-char (point-min)))
+                  (nnheader-insert-nov header))
+                (setq nov-arts (cons (car downloaded) nov-arts)))
+               ((eq (car downloaded) (car nov-arts))
+                ;; This entry in the overview has been downloaded
+                (push (cons (car downloaded)
+                            (time-to-days
+                             (nth 5 (file-attributes
+                                     (concat dir (number-to-string
+                                                  (car downloaded))))))) alist)
+                (setq downloaded (cdr downloaded))
+                (setq nov-arts (cdr nov-arts)))
+               (t
+                ;; This entry in the overview has not been downloaded
+                (push (cons (car nov-arts) nil) alist)
+                (setq nov-arts (cdr nov-arts)))))
+
+       ;; When gnus-agent-consider-all-articles is set,
+       ;; gnus-agent-regenerate-group should NOT remove article IDs from
+       ;; the alist.  Those IDs serve as markers to indicate that an
+       ;; attempt has been made to fetch that article's header.
+
+       ;; When gnus-agent-consider-all-articles is NOT set,
+       ;; gnus-agent-regenerate-group can remove the article ID of every
+       ;; article (with the exception of the last ID in the list - it's
+       ;; special) that no longer appears in the overview.  In this
+       ;; situation, the last article ID in the list implies that it,
+       ;; and every article ID preceding it, have been fetched from the
+       ;; server.
+
+       (if gnus-agent-consider-all-articles
+           ;; Restore all article IDs that were not found in the overview file.
+           (let* ((n (cons nil alist))
+                  (merged n)
+                  (o (gnus-agent-load-alist group)))
+             (while o
+               (let ((nID (caadr n))
+                     (oID (caar o)))
+                 (cond ((not nID)
+                        (setq n (setcdr n (list (list oID))))
+                        (setq o (cdr o)))
+                       ((< oID nID)
+                        (setcdr n (cons (list oID) (cdr n)))
+                        (setq o (cdr o)))
+                       ((= oID nID)
+                        (setq o (cdr o))
+                        (setq n (cdr n)))
+                       (t
+                        (setq n (cdr n))))))
+             (setq alist (cdr merged)))
+         ;; Restore the last article ID if it is not already in the new alist
+         (let ((n (last alist))
+               (o (last (gnus-agent-load-alist group))))
+           (cond ((not o)
+                  nil)
+                 ((not n)
+                  (push (cons (caar o) nil) alist))
+                 ((< (caar n) (caar o))
+                  (setcdr n (list (car o)))))))
+
+       (let ((inhibit-quit t))
+         (if (setq regenerated (buffer-modified-p))
+             (let ((coding-system-for-write gnus-agent-file-coding-system))
+               (write-region (point-min) (point-max) file nil 'silent)))
+
+         (setq regenerated (or regenerated
+                               (and reread gnus-agent-article-alist)
+                               (not (equal alist gnus-agent-article-alist))))
+
+         (setq gnus-agent-article-alist alist)
+
+         (when regenerated
+           (gnus-agent-save-alist group)
+
+           ;; I have to alter the group's active range NOW as
+           ;; gnus-make-ascending-articles-unread will use it to
+           ;; recalculate the number of unread articles in the group
+
+           (let ((group (gnus-group-real-name group))
+                 (group-active (or (gnus-active group)
+                                   (gnus-activate-group group))))
+             (gnus-agent-possibly-alter-active group group-active)))))
+
+      (when (and reread gnus-agent-article-alist)
+       (gnus-agent-synchronize-group-flags
+        group
+        (list (list
+               (if (listp reread)
+                   reread
+                 (delq nil (mapcar (function (lambda (c)
+                                               (cond ((eq reread t)
+                                                      (car c))
+                                                     ((cdr c)
+                                                      (car c)))))
+                                   gnus-agent-article-alist)))
+               'del '(read)))
+        gnus-command-method)
+
+       (when regenerated
+         (gnus-agent-update-files-total-fetched-for group nil)))
+
+      (gnus-message 5 "")
+      regenerated)))
+
+;;;###autoload
+(defun gnus-agent-regenerate (&optional _clean reread)
+  "Regenerate all agent covered files.
+CLEAN is obsolete and ignored."
+  (interactive)
+  (let (regenerated)
+    (gnus-message 4 "Regenerating Gnus agent files...")
+    (dolist (gnus-command-method (gnus-agent-covered-methods))
+      (dolist (group (gnus-groups-from-server gnus-command-method))
+        (setq regenerated (or (gnus-agent-regenerate-group group reread)
+                              regenerated))))
+    (gnus-message 4 "Regenerating Gnus agent files...done")
+
+    regenerated))
+
+(defun gnus-agent-go-online (&optional force)
+  "Switch servers into online status."
+  (interactive (list t))
+  (dolist (server gnus-opened-servers)
+    (when (eq (nth 1 server) 'offline)
+      (if (if (eq force 'ask)
+             (gnus-y-or-n-p
+              (format "Switch %s:%s into online status? "
+                      (caar server) (cadar server)))
+           force)
+         (setcar (nthcdr 1 server) 'close)))))
+
+(defun gnus-agent-toggle-group-plugged (group)
+  "Toggle the status of the server of the current group."
+  (interactive (list (gnus-group-group-name)))
+  (let* ((method (gnus-find-method-for-group group))
+        (status (cadr (assoc method gnus-opened-servers))))
+    (if (eq status 'offline)
+       (gnus-server-set-status method 'closed)
+      (gnus-close-server method)
+      (gnus-server-set-status method 'offline))
+    (message "Turn %s:%s from %s to %s." (car method) (cadr method)
+            (if (eq status 'offline) 'offline 'online)
+            (if (eq status 'offline) 'online 'offline))))
+
+(defun gnus-agent-group-covered-p (group)
+  (gnus-agent-method-p (gnus-group-method group)))
+
+(defun gnus-agent-update-files-total-fetched-for (group delta
+                                                       &optional method path)
+  "Update, or set, the total disk space used by the articles that the
+agent has fetched."
+  (when gnus-agent-total-fetched-hashtb
+    (gnus-agent-with-refreshed-group
+     group
+     ;; if null, gnus-agent-group-pathname will calc method.
+     (let* ((gnus-command-method method)
+           (path (or path (gnus-agent-group-pathname group)))
+           (entry (or (gnus-gethash path gnus-agent-total-fetched-hashtb)
+                      (gnus-sethash path (make-list 3 0)
+                                    gnus-agent-total-fetched-hashtb)))
+           (file-name-coding-system nnmail-pathname-coding-system))
+       (when (file-exists-p path)
+        (when (listp delta)
+          (if delta
+              (let ((sum 0.0)
+                    file)
+                (while (setq file (pop delta))
+                  (incf sum (float (or (nth 7 (file-attributes
+                                               (nnheader-concat
+                                                path
+                                                (if (numberp file)
+                                                    (number-to-string file)
+                                                  file)))) 0))))
+                (setq delta sum))
+            (let ((sum (- (nth 2 entry)))
+                  (info (directory-files-and-attributes
+                         path nil "^-?[0-9]+$" t))
+                  file)
+              (while (setq file (pop info))
+                (incf sum (float (or (nth 8 file) 0))))
+              (setq delta sum))))
+
+        (setq gnus-agent-need-update-total-fetched-for t)
+        (incf (nth 2 entry) delta))))))
+
+(defun gnus-agent-update-view-total-fetched-for
+  (group agent-over &optional method path)
+  "Update, or set, the total disk space used by the .agentview and
+.overview files.  These files are calculated separately as they can be
+modified."
+  (when gnus-agent-total-fetched-hashtb
+    (gnus-agent-with-refreshed-group
+     group
+     ;; if null, gnus-agent-group-pathname will calc method.
+     (let* ((gnus-command-method method)
+           (path (or path (gnus-agent-group-pathname group)))
+           (entry (or (gnus-gethash path gnus-agent-total-fetched-hashtb)
+                      (gnus-sethash path (make-list 3 0)
+                                    gnus-agent-total-fetched-hashtb)))
+           (file-name-coding-system nnmail-pathname-coding-system)
+           (size (or (nth 7 (file-attributes
+                             (nnheader-concat
+                              path (if agent-over
+                                       ".overview"
+                                     ".agentview"))))
+                     0)))
+       (setq gnus-agent-need-update-total-fetched-for t)
+       (setf (nth (if agent-over 1 0) entry) size)))))
+
+(defun gnus-agent-total-fetched-for (group &optional method no-inhibit)
+  "Get the total disk space used by the specified GROUP."
+  (unless (equal group "dummy.group")
+    (unless gnus-agent-total-fetched-hashtb
+      (setq gnus-agent-total-fetched-hashtb (gnus-make-hashtable 1024)))
+
+    ;; if null, gnus-agent-group-pathname will calc method.
+    (let* ((gnus-command-method method)
+          (path (gnus-agent-group-pathname group))
+          (entry (gnus-gethash path gnus-agent-total-fetched-hashtb)))
+      (if entry
+         (apply '+ entry)
+       (let ((gnus-agent-inhibit-update-total-fetched-for (not no-inhibit)))
+         (+
+          (gnus-agent-update-view-total-fetched-for  group nil method path)
+          (gnus-agent-update-view-total-fetched-for  group t   method path)
+          (gnus-agent-update-files-total-fetched-for group nil method path)))))))
+
+(provide 'gnus-agent)
+
+;;; gnus-agent.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-art.el b/xemacs-packages/gnus/lisp/gnus-art.el
new file mode 100644 (file)
index 0000000..4858fc7
--- /dev/null
@@ -0,0 +1,9024 @@
+;;; gnus-art.el --- article mode commands for Gnus
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile
+  (require 'cl))
+(defvar tool-bar-map)
+(defvar w3m-minor-mode-map)
+
+(require 'gnus)
+(require 'gnus-util)
+(require 'gnus-sum)
+(require 'gnus-spec)
+(require 'gnus-int)
+(require 'gnus-win)
+(require 'mm-bodies)
+(require 'mail-parse)
+(require 'mm-decode)
+(require 'mm-view)
+(require 'wid-edit)
+(require 'mm-uu)
+(require 'message)
+(require 'mouse)
+
+(autoload 'gnus-msg-mail "gnus-msg" nil t)
+(autoload 'gnus-button-mailto "gnus-msg")
+(autoload 'gnus-button-reply "gnus-msg" nil t)
+(autoload 'parse-time-string "parse-time" nil nil)
+(autoload 'ansi-color-apply-on-region "ansi-color")
+(autoload 'mm-url-insert-file-contents-external "mm-url")
+(autoload 'mm-extern-cache-contents "mm-extern")
+(autoload 'url-expand-file-name "url-expand")
+
+(defgroup gnus-article nil
+  "Article display."
+  :link '(custom-manual "(gnus)Article Buffer")
+  :group 'gnus)
+
+(defgroup gnus-article-treat nil
+  "Treating article parts."
+  :link '(custom-manual "(gnus)Article Hiding")
+  :group 'gnus-article)
+
+(defgroup gnus-article-hiding nil
+  "Hiding article parts."
+  :link '(custom-manual "(gnus)Article Hiding")
+  :group 'gnus-article)
+
+(defgroup gnus-article-highlight nil
+  "Article highlighting."
+  :link '(custom-manual "(gnus)Article Highlighting")
+  :group 'gnus-article
+  :group 'gnus-visual)
+
+(defgroup gnus-article-signature nil
+  "Article signatures."
+  :link '(custom-manual "(gnus)Article Signature")
+  :group 'gnus-article)
+
+(defgroup gnus-article-headers nil
+  "Article headers."
+  :link '(custom-manual "(gnus)Hiding Headers")
+  :group 'gnus-article)
+
+(defgroup gnus-article-washing nil
+  "Special commands on articles."
+  :link '(custom-manual "(gnus)Article Washing")
+  :group 'gnus-article)
+
+(defgroup gnus-article-emphasis nil
+  "Fontisizing articles."
+  :link '(custom-manual "(gnus)Article Fontisizing")
+  :group 'gnus-article)
+
+(defgroup gnus-article-saving nil
+  "Saving articles."
+  :link '(custom-manual "(gnus)Saving Articles")
+  :group 'gnus-article)
+
+(defgroup gnus-article-mime nil
+  "Worshiping the MIME wonder."
+  :link '(custom-manual "(gnus)Using MIME")
+  :group 'gnus-article)
+
+(defgroup gnus-article-buttons nil
+  "Pushable buttons in the article buffer."
+  :link '(custom-manual "(gnus)Article Buttons")
+  :group 'gnus-article)
+
+(defgroup gnus-article-various nil
+  "Other article options."
+  :link '(custom-manual "(gnus)Misc Article")
+  :group 'gnus-article)
+
+(defcustom gnus-ignored-headers
+  (mapcar
+   (lambda (header)
+     (concat "^" header ":"))
+   '("Path" "Expires" "Date-Received" "References" "Xref" "Lines"
+     "Relay-Version" "Message-ID" "Approved" "Sender" "Received"
+     "X-UIDL" "MIME-Version" "Return-Path" "In-Reply-To"
+     "Content-Type" "Content-Transfer-Encoding" "X-WebTV-Signature"
+     "X-MimeOLE" "X-MSMail-Priority" "X-Priority" "X-Loop"
+     "X-Authentication-Warning" "X-MIME-Autoconverted" "X-Face"
+     "X-Attribution" "X-Originating-IP" "Delivered-To"
+     "NNTP-[-A-Za-z]+" "Distribution" "X-no-archive" "X-Trace"
+     "X-Complaints-To" "X-NNTP-Posting-Host" "X-Orig.*"
+     "Abuse-Reports-To" "Cache-Post-Path" "X-Article-Creation-Date"
+     "X-Poster" "X-Mail2News-Path" "X-Server-Date" "X-Cache"
+     "Originator" "X-Problems-To" "X-Auth-User" "X-Post-Time"
+     "X-Admin" "X-UID" "Resent-[-A-Za-z]+" "X-Mailing-List"
+     "Precedence" "Original-[-A-Za-z]+" "X-filename" "X-Orcpt"
+     "Old-Received" "X-Pgp" "X-Auth" "X-From-Line"
+     "X-Gnus-Article-Number" "X-Majordomo" "X-Url" "X-Sender"
+     "MBOX-Line" "Priority" "X400-[-A-Za-z]+"
+     "Status" "X-Gnus-Mail-Source" "Cancel-Lock"
+     "X-FTN" "X-EXP32-SerialNo" "Encoding" "Importance"
+     "Autoforwarded" "Original-Encoded-Information-Types" "X-Ya-Pop3"
+     "X-Face-Version" "X-Vms-To" "X-ML-NAME" "X-ML-COUNT"
+     "Mailing-List" "X-finfo" "X-md5sum" "X-md5sum-Origin"
+     "X-Sun-Charset" "X-Accept-Language" "X-Envelope-Sender"
+     "List-[A-Za-z]+" "X-Listprocessor-Version"
+     "X-Received" "X-Distribute" "X-Sequence" "X-Juno-Line-Breaks"
+     "X-Notes-Item" "X-MS-TNEF-Correlator" "x-uunet-gateway"
+     "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-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"
+     "X-Received-Date" "X-Hashcash" "Face" "X-DMCA-Notifications"
+     "X-Abuse-and-DMCA-Info" "X-Postfilter" "X-Gpg-.*" "X-Disclaimer"
+     "Envelope-To" "X-Spam-Score" "System-Type" "X-Injected-Via-Gmane"
+     "X-Gmane-NNTP-Posting-Host" "Jabber-ID" "Archived-At"
+     "Envelope-Sender" "Envelope-Recipients"))
+  "*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."
+  :type '(choice regexp
+                (repeat regexp))
+  :group 'gnus-article-hiding)
+
+(defcustom gnus-visible-headers
+  "^From:\\|^Newsgroups:\\|^Subject:\\|^Date:\\|^Followup-To:\\|^Reply-To:\\|^Organization:\\|^Summary:\\|^Keywords:\\|^To:\\|^[BGF]?Cc:\\|^Posted-To:\\|^Mail-Copies-To:\\|^Mail-Followup-To:\\|^Apparently-To:\\|^Gnus-Warning:\\|^Resent-From:"
+  "*All headers that do not match this regexp will be hidden.
+This variable can also be a list of regexp of headers to remain visible.
+If this variable is non-nil, `gnus-ignored-headers' will be ignored."
+  :type '(choice
+         (repeat :value-to-internal (lambda (widget value)
+                                      (custom-split-regexp-maybe value))
+                 :match (lambda (widget value)
+                          (or (stringp value)
+                              (widget-editable-list-match widget value)))
+                 regexp)
+         (const :tag "Use gnus-ignored-headers" nil)
+         regexp)
+  :group 'gnus-article-hiding)
+
+(defcustom gnus-sorted-header-list
+  '("^From:" "^Subject:" "^Summary:" "^Keywords:" "^Newsgroups:"
+    "^Followup-To:" "^To:" "^Cc:" "^Date:" "^Organization:")
+  "*This variable is a list of regular expressions.
+If it is non-nil, headers that match the regular expressions will
+be placed first in the article buffer in the sequence specified by
+this list."
+  :type '(repeat regexp)
+  :group 'gnus-article-hiding)
+
+(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'       Headers with no content.
+  `newsgroups'  Newsgroup identical to Gnus group.
+  `to-address'  To identical to To-address.
+  `to-list'     To identical to To-list.
+  `cc-list'     CC identical to To-list.
+  `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 identical to Gnus group." newsgroups)
+             (const :tag "To identical to To-address." to-address)
+             (const :tag "To identical to To-list." to-list)
+             (const :tag "CC identical to To-list." cc-list)
+             (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 "To and/or Cc longer than 1024 characters." long-to)
+             (const :tag "Multiple To and/or Cc headers." many-to))
+  :group 'gnus-article-hiding)
+
+(defcustom gnus-article-skip-boring nil
+  "Skip over text that is not worth reading.
+By default, if you set this t, then Gnus will display citations and
+signatures, but will never scroll down to show you a page consisting
+only of boring text.  Boring text is controlled by
+`gnus-article-boring-faces'."
+  :version "22.1"
+  :type 'boolean
+  :group 'gnus-article-hiding)
+
+(defcustom gnus-signature-separator '("^-- $" "^-- *$")
+  "Regexp matching signature separator.
+This can also be a list of regexps.  In that case, it will be checked
+from head to tail looking for a separator.  Searches will be done from
+the end of the buffer."
+  :type '(choice :format "%{%t%}: %[Value Menu%]\n%v"
+                (regexp)
+                (repeat :tag "List of regexp" regexp))
+  :group 'gnus-article-signature)
+
+(defcustom gnus-signature-limit nil
+  "Provide a limit to what is considered a signature.
+If it is a number, no signature may not be longer (in characters) than
+that number.  If it is a floating point number, no signature may be
+longer (in lines) than that number.  If it is a function, the function
+will be called without any parameters, and if it returns nil, there is
+no signature in the buffer.  If it is a string, it will be used as a
+regexp.  If it matches, the text in question is not a signature.
+
+This can also be a list of the above values."
+  :type '(choice (const nil)
+                (integer :value 200)
+                (number :value 4.0)
+                function
+                (regexp :value ".*"))
+  :group 'gnus-article-signature)
+
+(defcustom gnus-hidden-properties
+  ;; We use to have `intangible' here as well, but Emacs's command loop moves
+  ;; point out of invisible text anyway, so `intangible' is clearly not
+  ;; needed there.  And XEmacs doesn't handle `intangible' anyway.
+  '(invisible t)
+  "Property list to use for hiding text."
+  :type 'sexp
+  :group 'gnus-article-hiding)
+
+;; Fixme: This isn't the right thing for mixed graphical and non-graphical
+;; frames in a session.
+(defcustom gnus-article-x-face-command
+  (if (featurep 'xemacs)
+      (if (or (gnus-image-type-available-p 'xface)
+             (gnus-image-type-available-p 'pbm))
+         'gnus-display-x-face-in-from
+       "{ echo \
+'/* Format_version=1, Width=48, Height=48, Depth=1, Valid_bits_per_item=16 */'\
+; uncompface; } | icontopbm | ee -")
+    (if (gnus-image-type-available-p 'pbm)
+       'gnus-display-x-face-in-from
+      "{ echo \
+'/* Format_version=1, Width=48, Height=48, Depth=1, Valid_bits_per_item=16 */'\
+; 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-display-x-face-in-from)
+                function)
+  :version "21.1"
+  :group 'gnus-picon
+  :group 'gnus-article-washing)
+
+(defcustom gnus-article-x-face-too-ugly nil
+  "Regexp matching posters whose face shouldn't be shown automatically."
+  :type '(choice regexp (const nil))
+  :group 'gnus-article-washing)
+
+(defcustom gnus-article-banner-alist nil
+  "Banner alist for stripping.
+For example,
+     ((egroups . \"^[ \\t\\n]*-------------------+\\\\( \\\\(e\\\\|Yahoo! \\\\)Groups Sponsor -+\\\\)?....\\n\\\\(.+\\n\\\\)+\"))"
+  :version "21.1"
+  :type '(repeat (cons symbol regexp))
+  :group 'gnus-article-washing)
+
+(gnus-define-group-parameter
+ banner
+ :variable-document
+ "Alist of regexps (to match group names) and banner."
+ :variable-group gnus-article-washing
+ :parameter-type
+ '(choice :tag "Banner"
+         :value nil
+         (const :tag "Remove signature" signature)
+         (symbol :tag "Item in `gnus-article-banner-alist'" none)
+         regexp
+         (const :tag "None" nil))
+ :parameter-document
+ "If non-nil, specify how to remove `banners' from articles.
+
+Symbol `signature' means to remove signatures delimited by
+`gnus-signature-separator'.  Any other symbol is used to look up a
+regular expression to match the banner in `gnus-article-banner-alist'.
+A string is used as a regular expression to match the banner
+directly.")
+
+(defcustom gnus-article-address-banner-alist nil
+  "Alist of mail addresses and banners.
+Each element has the form (ADDRESS . BANNER), where ADDRESS is a regexp
+to match a mail address in the From: header, BANNER is one of a symbol
+`signature', an item in `gnus-article-banner-alist', a regexp and nil.
+If ADDRESS matches author's mail address, it will remove things like
+advertisements.  For example:
+
+\((\"@yoo-hoo\\\\.co\\\\.jp\\\\\\='\" . \"\\n_+\\nDo You Yoo-hoo!\\\\?\\n.*\\n.*\\n\"))
+"
+  :type '(repeat
+         (cons
+          (regexp :tag "Address")
+          (choice :tag "Banner" :value nil
+                  (const :tag "Remove signature" signature)
+                  (symbol :tag "Item in `gnus-article-banner-alist'" none)
+                  regexp
+                  (const :tag "None" nil))))
+  :version "22.1"
+  :group 'gnus-article-washing)
+
+(defmacro gnus-emphasis-custom-with-format (&rest body)
+  `(let ((format "\
+\\(\\s-\\|^\\|\\=\\|[-\"]\\|\\s(\\)\\(%s\\(\\w+\\(\\s-+\\w+\\)*[.,]?\\)%s\\)\
+\\(\\([-,.;:!?\"]\\|\\s)\\)+\\s-\\|[?!.]\\s-\\|\\s)\\|\\s-\\)"))
+     ,@body))
+
+(defun gnus-emphasis-custom-value-to-external (value)
+  (gnus-emphasis-custom-with-format
+   (if (consp (car value))
+       (list (format format (car (car value)) (cdr (car value)))
+            2
+            (if (nth 1 value) 2 3)
+            (nth 2 value))
+     value)))
+
+(defun gnus-emphasis-custom-value-to-internal (value)
+  (gnus-emphasis-custom-with-format
+   (let ((regexp (concat "\\`"
+                        (format (regexp-quote format)
+                                "\\([^()]+\\)" "\\([^()]+\\)")
+                        "\\'"))
+        pattern)
+     (if (string-match regexp (setq pattern (car value)))
+        (list (cons (match-string 1 pattern) (match-string 2 pattern))
+              (= (nth 2 value) 2)
+              (nth 3 value))
+       value))))
+
+(defcustom gnus-emphasis-alist
+  (let ((types
+        '(("\\*" "\\*" bold nil 2)
+          ("_" "_" underline)
+          ("/" "/" italic)
+          ("_/" "/_" underline-italic)
+          ("_\\*" "\\*_" underline-bold)
+          ("\\*/" "/\\*" bold-italic)
+          ("_\\*/" "/\\*_" underline-bold-italic))))
+    (nconc
+     (gnus-emphasis-custom-with-format
+      (mapcar (lambda (spec)
+               (list (format format (car spec) (cadr spec))
+                     (or (nth 3 spec) 2)
+                     (or (nth 4 spec) 3)
+                     (intern (format "gnus-emphasis-%s" (nth 2 spec)))))
+             types))
+     '(;; I've never seen anyone use this strikethru convention whereas I've
+       ;; several times seen it triggered by normal text.  --Stef
+       ;; Miles suggests that this form is sometimes used but for italics,
+       ;; so maybe we should map it to `italic'.
+       ;; ("\\(\\s-\\|^\\)\\(-\\(\\(\\w\\|-[^-]\\)+\\)-\\)\\(\\s-\\|[?!.,;]\\)"
+       ;; 2 3 gnus-emphasis-strikethru)
+       ("\\(\\s-\\|^\\)\\(_\\(\\(\\w\\|_[^_]\\)+\\)_\\)\\(\\s-\\|[?!.,;]\\)"
+       2 3 gnus-emphasis-underline))))
+  "*Alist that says how to fontify certain phrases.
+Each item looks like this:
+
+  (\"_\\\\(\\\\w+\\\\)_\" 0 1 \\='underline)
+
+The first element is a regular expression to be matched.  The second
+is a number that says what regular expression grouping used to find
+the entire emphasized word.  The third is a number that says what
+regexp grouping should be displayed and highlighted.  The fourth
+is the face used for highlighting."
+  :type
+  '(repeat
+    (menu-choice
+     :format "%[Customizing Style%]\n%v"
+     :indent 2
+     (group :tag "Default"
+           :value ("" 0 0 default)
+           :value-create
+           (lambda (widget)
+             (let ((value (widget-get
+                           (cadr (widget-get (widget-get widget :parent)
+                                             :args))
+                           :value)))
+               (if (not (eq (nth 2 value) 'default))
+                   (widget-put
+                    widget
+                    :value
+                    (gnus-emphasis-custom-value-to-external value))))
+             (widget-group-value-create widget))
+           regexp
+           (integer :format "Match group: %v")
+           (integer :format "Emphasize group: %v")
+           face)
+     (group :tag "Simple"
+           :value (("_" . "_") nil default)
+           (cons :format "%v"
+                 (regexp :format "Start regexp: %v")
+                 (regexp :format "End regexp: %v"))
+           (boolean :format "Show start and end patterns: %[%v%]\n"
+                    :on " On " :off " Off ")
+           face)))
+  :get (lambda (symbol)
+        (mapcar 'gnus-emphasis-custom-value-to-internal
+                (default-value symbol)))
+  :set (lambda (symbol value)
+        (set-default symbol (mapcar 'gnus-emphasis-custom-value-to-external
+                                    value)))
+  :group 'gnus-article-emphasis)
+
+(defcustom gnus-emphasize-whitespace-regexp "^[ \t]+\\|[ \t]*\n"
+  "A regexp to describe whitespace which should not be emphasized.
+Typical values are \"^[ \\t]+\\\\|[ \\t]*\\n\" and \"[ \\t]+\\\\|[ \\t]*\\n\".
+The former avoids underlining of leading and trailing whitespace,
+and the latter avoids underlining any whitespace at all."
+  :version "21.1"
+  :group 'gnus-article-emphasis
+  :type 'regexp)
+
+(defface gnus-emphasis-bold '((t (:bold t)))
+  "Face used for displaying strong emphasized text (*word*)."
+  :group 'gnus-article-emphasis)
+
+(defface gnus-emphasis-italic '((t (:italic t)))
+  "Face used for displaying italic emphasized text (/word/)."
+  :group 'gnus-article-emphasis)
+
+(defface gnus-emphasis-underline '((t (:underline t)))
+  "Face used for displaying underlined emphasized text (_word_)."
+  :group 'gnus-article-emphasis)
+
+(defface gnus-emphasis-underline-bold '((t (:bold t :underline t)))
+  "Face used for displaying underlined bold emphasized text (_*word*_)."
+  :group 'gnus-article-emphasis)
+
+(defface gnus-emphasis-underline-italic '((t (:italic t :underline t)))
+  "Face used for displaying underlined italic emphasized text (_/word/_)."
+  :group 'gnus-article-emphasis)
+
+(defface gnus-emphasis-bold-italic '((t (:bold t :italic t)))
+  "Face used for displaying bold italic emphasized text (/*word*/)."
+  :group 'gnus-article-emphasis)
+
+(defface gnus-emphasis-underline-bold-italic
+  '((t (:bold t :italic t :underline t)))
+  "Face used for displaying underlined bold italic emphasized text.
+Example: (_/*word*/_)."
+  :group 'gnus-article-emphasis)
+
+(defface gnus-emphasis-strikethru (if (featurep 'xemacs)
+                                     '((t (:strikethru t)))
+                                   '((t (:strike-through t))))
+  "Face used for displaying strike-through text (-word-)."
+  :group 'gnus-article-emphasis)
+
+(defface gnus-emphasis-highlight-words
+  '((t (:background "black" :foreground "yellow")))
+  "Face used for displaying highlighted words."
+  :group 'gnus-article-emphasis)
+
+(defcustom gnus-article-time-format "%a, %d %b %Y %T %Z"
+  "Format for display of Date headers in article bodies.
+See `format-time-string' for the possible values.
+
+The variable can also be function, which should return a complete Date
+header.  The function is called with one argument, the time, which can
+be fed to `format-time-string'."
+  :type '(choice string function)
+  :link '(custom-manual "(gnus)Article Date")
+  :group 'gnus-article-washing)
+
+(defcustom gnus-save-all-headers t
+  "*If non-nil, don't remove any headers before saving.
+This will be overridden by the `:headers' property that the symbol of
+the saver function, which is specified by `gnus-default-article-saver',
+might have."
+  :group 'gnus-article-saving
+  :type 'boolean)
+
+(defcustom gnus-prompt-before-saving 'always
+  "*This variable says how much prompting is to be done when saving articles.
+If it is nil, no prompting will be done, and the articles will be
+saved to the default files.  If this variable is `always', each and
+every article that is saved will be preceded by a prompt, even when
+saving large batches of articles.  If this variable is neither nil not
+`always', there the user will be prompted once for a file name for
+each invocation of the saving commands."
+  :group 'gnus-article-saving
+  :type '(choice (item always)
+                (item :tag "never" nil)
+                (sexp :tag "once" :format "%t\n" :value t)))
+
+(defcustom gnus-saved-headers gnus-visible-headers
+  "Headers to keep if `gnus-save-all-headers' is nil.
+If `gnus-save-all-headers' is non-nil, this variable will be ignored.
+If that variable is nil, however, all headers that match this regexp
+will be kept while the rest will be deleted before saving.  This and
+`gnus-save-all-headers' will be overridden by the `:headers' property
+that the symbol of the saver function, which is specified by
+`gnus-default-article-saver', might have."
+  :group 'gnus-article-saving
+  :type 'regexp)
+
+;; Note that "Rmail format" is mbox since Emacs 23, but Babyl before.
+(defcustom gnus-default-article-saver 'gnus-summary-save-in-rmail
+  "A function to save articles in your favorite format.
+The function will be called by way of the `gnus-summary-save-article'
+command, and friends such as `gnus-summary-save-article-rmail'.
+
+Gnus provides the following functions:
+
+* gnus-summary-save-in-rmail (Rmail format)
+* 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)
+* gnus-summary-write-body-to-file (article body -- overwrite)
+* gnus-summary-save-in-pipe (article format)
+
+The symbol of each function may have the following properties:
+
+* :decode
+The value non-nil means save decoded articles.  This is meaningful
+only with `gnus-summary-save-in-file', `gnus-summary-save-body-in-file',
+`gnus-summary-write-to-file', `gnus-summary-write-body-to-file', and
+`gnus-summary-save-in-pipe'.
+
+* :function
+The value specifies an alternative function which appends, not
+overwrites, articles to a file.  This implies that when saving many
+articles at a time, `gnus-prompt-before-saving' is bound to t and all
+articles are saved in a single file.  This is meaningful only with
+`gnus-summary-write-to-file' and `gnus-summary-write-body-to-file'.
+
+* :headers
+The value specifies the symbol of a variable of which the value
+specifies headers to be saved.  If it is omitted,
+`gnus-save-all-headers' and `gnus-saved-headers' control what
+headers should be saved."
+  :group 'gnus-article-saving
+  :type '(radio (function-item gnus-summary-save-in-rmail)
+               (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)
+               (function-item gnus-summary-write-body-to-file)
+               (function-item gnus-summary-save-in-pipe)
+               (function)))
+
+(defcustom gnus-article-save-coding-system
+  (or (and (mm-coding-system-p 'utf-8) 'utf-8)
+      (and (mm-coding-system-p 'iso-2022-7bit) 'iso-2022-7bit)
+      (and (mm-coding-system-p 'emacs-mule) 'emacs-mule)
+      (and (mm-coding-system-p 'escape-quoted) 'escape-quoted))
+  "Coding system used to save decoded articles to a file.
+
+The recommended coding systems are `utf-8', `iso-2022-7bit' and so on,
+which can safely encode any characters in text.  This is used by the
+commands including:
+
+* gnus-summary-save-article-file
+* gnus-summary-save-article-body-file
+* gnus-summary-write-article-file
+* gnus-summary-write-article-body-file
+
+and the functions to which you may set `gnus-default-article-saver':
+
+* gnus-summary-save-in-file
+* gnus-summary-save-body-in-file
+* gnus-summary-write-to-file
+* gnus-summary-write-body-to-file
+
+Those commands and functions save just text displayed in the article
+buffer to a file if the value of this variable is non-nil.  Note that
+buttonized MIME parts will be lost in a saved file in that case.
+Otherwise, raw articles will be saved."
+  :group 'gnus-article-saving
+  :type `(choice
+         :format "%{%t%}:\n %[Value Menu%] %v"
+         (const :tag "Save raw articles" nil)
+         ,@(delq nil
+                 (mapcar
+                  (lambda (arg) (if (mm-coding-system-p (nth 3 arg)) arg))
+                  '((const :tag "UTF-8" utf-8)
+                    (const :tag "iso-2022-7bit" iso-2022-7bit)
+                    (const :tag "Emacs internal" emacs-mule)
+                    (const :tag "escape-quoted" escape-quoted))))
+         (symbol :tag "Coding system")))
+
+(defcustom gnus-rmail-save-name 'gnus-plain-save-name
+  "A function generating a file name to save articles in Rmail format.
+The function is called with NEWSGROUP, HEADERS, and optional LAST-FILE."
+  :group 'gnus-article-saving
+  :type 'function)
+
+(defcustom gnus-mail-save-name 'gnus-plain-save-name
+  "A function generating a file name to save articles in Unix mail format.
+The function is called with NEWSGROUP, HEADERS, and optional LAST-FILE."
+  :group 'gnus-article-saving
+  :type 'function)
+
+(defcustom gnus-folder-save-name 'gnus-folder-save-name
+  "A function generating a file name to save articles in MH folder.
+The function is called with NEWSGROUP, HEADERS, and optional LAST-FOLDER."
+  :group 'gnus-article-saving
+  :type 'function)
+
+(defcustom gnus-file-save-name 'gnus-numeric-save-name
+  "A function generating a file name to save articles in article format.
+The function is called with NEWSGROUP, HEADERS, and optional
+LAST-FILE."
+  :group 'gnus-article-saving
+  :type 'function)
+
+(defcustom gnus-split-methods
+  '((gnus-article-archive-name)
+    (gnus-article-nndoc-name))
+  "*Variable used to suggest where articles are to be saved.
+For instance, if you would like to save articles related to Gnus in
+the file \"gnus-stuff\", and articles related to VM in \"vm-stuff\",
+you could set this variable to something like:
+
+  ((\"^Subject:.*gnus\\|^Newsgroups:.*gnus\" \"gnus-stuff\")
+   (\"^Subject:.*vm\\|^Xref:.*vm\" \"vm-stuff\"))
+
+This variable is an alist where the key is the match and the
+value is a list of possible files to save in if the match is
+non-nil.
+
+If the match is a string, it is used as a regexp match on the
+article.  If the match is a symbol, that symbol will be funcalled
+from the buffer of the article to be saved with the newsgroup as the
+parameter.  If it is a list, it will be evalled in the same buffer.
+
+If this form or function returns a string, this string will be used as a
+possible file name; and if it returns a non-nil list, that list will be
+used as possible file names."
+  :group 'gnus-article-saving
+  :type '(repeat (choice (list :value (fun) function)
+                        (cons :value ("" "") regexp (repeat string))
+                        (sexp :value nil))))
+
+(defcustom gnus-page-delimiter "^\^L"
+  "*Regexp describing what to use as article page delimiters.
+The default value is \"^\^L\", which is a form linefeed at the
+beginning of a line."
+  :type 'regexp
+  :group 'gnus-article-various)
+
+(defcustom gnus-article-mode-line-format "Gnus: %g %S%m"
+  "*The format specification for the article mode line.
+See `gnus-summary-mode-line-format' for a closer description.
+
+The following additional specs are available:
+
+%w  The article washing status.
+%m  The number of MIME parts in the article."
+  :version "24.1"
+  :type 'string
+  :group 'gnus-article-various)
+
+(defcustom gnus-article-mode-hook nil
+  "*A hook for Gnus article mode."
+  :type 'hook
+  :group 'gnus-article-various)
+
+(when (featurep 'xemacs)
+  ;; Extracted from gnus-xmas-define in order to preserve user settings
+  (when (fboundp 'turn-off-scroll-in-place)
+    (add-hook 'gnus-article-mode-hook 'turn-off-scroll-in-place))
+  ;; Extracted from gnus-xmas-redefine in order to preserve user settings
+  (add-hook 'gnus-article-mode-hook 'gnus-xmas-article-menu-add))
+
+(defcustom gnus-article-menu-hook nil
+  "*Hook run after the creation of the article mode menu."
+  :type 'hook
+  :group 'gnus-article-various)
+
+(defcustom gnus-article-prepare-hook nil
+  "*A hook called after an article has been prepared in the article buffer."
+  :type 'hook
+  :group 'gnus-article-various)
+
+(defcustom gnus-copy-article-ignored-headers nil
+  "List of headers to be removed when copying an article.
+Each element is a regular expression."
+  :version "23.1" ;; No Gnus
+  :type '(repeat regexp)
+  :group 'gnus-article-various)
+
+(make-obsolete-variable 'gnus-article-hide-pgp-hook nil
+                       "Gnus 5.10 (Emacs 22.1)")
+
+(defface gnus-button
+  '((t (:weight bold)))
+  "Face used for highlighting a button in the article buffer."
+  :group 'gnus-article-buttons)
+
+(defcustom gnus-article-button-face 'gnus-button
+  "Face used for highlighting buttons in the article buffer.
+
+An article button is a piece of text that you can activate by pressing
+`RET' or `mouse-2' above it."
+  :type 'face
+  :group 'gnus-article-buttons)
+
+(defcustom gnus-article-mouse-face 'highlight
+  "Face used for mouse highlighting in the article buffer.
+
+Article buttons will be displayed in this face when the cursor is
+above them."
+  :type 'face
+  :group 'gnus-article-buttons)
+
+(defcustom gnus-signature-face 'gnus-signature
+  "Face used for highlighting a signature in the article buffer.
+Obsolete; use the face `gnus-signature' for customizations instead."
+  :type 'face
+  :group 'gnus-article-highlight
+  :group 'gnus-article-signature)
+
+(defface gnus-signature
+  '((t
+     (:italic t)))
+  "Face used for highlighting a signature in the article buffer."
+  :group 'gnus-article-highlight
+  :group 'gnus-article-signature)
+;; backward-compatibility alias
+(put 'gnus-signature-face 'face-alias 'gnus-signature)
+(put 'gnus-signature-face 'obsolete-face "22.1")
+
+(defface gnus-header-from
+  '((((class color)
+      (background dark))
+     (:foreground "PaleGreen1"))
+    (((class color)
+      (background light))
+     (:foreground "red3"))
+    (t
+     (:italic t)))
+  "Face used for displaying from headers."
+  :group 'gnus-article-headers
+  :group 'gnus-article-highlight)
+;; backward-compatibility alias
+(put 'gnus-header-from-face 'face-alias 'gnus-header-from)
+(put 'gnus-header-from-face 'obsolete-face "22.1")
+
+(defface gnus-header-subject
+  '((((class color)
+      (background dark))
+     (:foreground "SeaGreen1"))
+    (((class color)
+      (background light))
+     (:foreground "red4"))
+    (t
+     (:bold t :italic t)))
+  "Face used for displaying subject headers."
+  :group 'gnus-article-headers
+  :group 'gnus-article-highlight)
+;; backward-compatibility alias
+(put 'gnus-header-subject-face 'face-alias 'gnus-header-subject)
+(put 'gnus-header-subject-face 'obsolete-face "22.1")
+
+(defface gnus-header-newsgroups
+  '((((class color)
+      (background dark))
+     (:foreground "yellow" :italic t))
+    (((class color)
+      (background light))
+     (:foreground "MidnightBlue" :italic t))
+    (t
+     (:italic t)))
+  "Face used for displaying newsgroups headers.
+In the default setup this face is only used for crossposted
+articles."
+  :group 'gnus-article-headers
+  :group 'gnus-article-highlight)
+;; backward-compatibility alias
+(put 'gnus-header-newsgroups-face 'face-alias 'gnus-header-newsgroups)
+(put 'gnus-header-newsgroups-face 'obsolete-face "22.1")
+
+(defface gnus-header-name
+  '((((class color)
+      (background dark))
+     (:foreground "SpringGreen2"))
+    (((class color)
+      (background light))
+     (:foreground "maroon"))
+    (t
+     (:bold t)))
+  "Face used for displaying header names."
+  :group 'gnus-article-headers
+  :group 'gnus-article-highlight)
+;; backward-compatibility alias
+(put 'gnus-header-name-face 'face-alias 'gnus-header-name)
+(put 'gnus-header-name-face 'obsolete-face "22.1")
+
+(defface gnus-header-content
+  '((((class color)
+      (background dark))
+     (:foreground "SpringGreen1" :italic t))
+    (((class color)
+      (background light))
+     (:foreground "indianred4" :italic t))
+    (t
+     (:italic t)))  "Face used for displaying header content."
+  :group 'gnus-article-headers
+  :group 'gnus-article-highlight)
+;; backward-compatibility alias
+(put 'gnus-header-content-face 'face-alias 'gnus-header-content)
+(put 'gnus-header-content-face 'obsolete-face "22.1")
+
+(defcustom gnus-header-face-alist
+  '(("From" nil gnus-header-from)
+    ("Subject" nil gnus-header-subject)
+    ("Newsgroups:.*," nil gnus-header-newsgroups)
+    ("" gnus-header-name gnus-header-content))
+  "*Controls highlighting of article headers.
+
+An alist of the form (HEADER NAME CONTENT).
+
+HEADER is a regular expression which should match the name of a
+header and NAME and CONTENT are either face names or nil.
+
+The name of each header field will be displayed using the face
+specified by the first element in the list where HEADER matches
+the header name and NAME is non-nil.  Similarly, the content will
+be displayed by the first non-nil matching CONTENT face."
+  :group 'gnus-article-headers
+  :group 'gnus-article-highlight
+  :type '(repeat (list (regexp :tag "Header")
+                      (choice :tag "Name"
+                              (item :tag "skip" nil)
+                              (face :value default))
+                      (choice :tag "Content"
+                              (item :tag "skip" nil)
+                              (face :value default)))))
+
+(defcustom gnus-face-properties-alist (if (featurep 'xemacs)
+                                         '((xface . (:face gnus-x-face)))
+                                       '((pbm . (:face gnus-x-face))
+                                         (png . nil)))
+  "Alist of image types and properties applied to Face and X-Face images.
+Here are examples:
+
+;; Specify the altitude of Face images in the From header.
+\(setq gnus-face-properties-alist
+      \\='((pbm . (:face gnus-x-face :ascent 80))
+       (png . (:ascent 80))))
+
+;; Show Face images as pressed buttons.
+\(setq gnus-face-properties-alist
+      \\='((pbm . (:face gnus-x-face :relief -2))
+       (png . (:relief -2))))
+
+See the manual for the valid properties for various image types.
+Currently, `pbm' is used for X-Face images and `png' is used for Face
+images in Emacs.  Only the `:face' property is effective on the `xface'
+image type in XEmacs if it is built with the libcompface library."
+  :version "23.1" ;; No Gnus
+  :group 'gnus-article-headers
+  :type '(repeat (cons :format "%v" (symbol :tag "Image type") plist)))
+
+(defcustom gnus-article-decode-hook
+  '(article-decode-charset article-decode-encoded-words
+                          article-decode-group-name article-decode-idna-rhs)
+  "*Hook run to decode charsets in articles."
+  :group 'gnus-article-headers
+  :type 'hook)
+
+(defcustom gnus-display-mime-function 'gnus-display-mime
+  "Function to display MIME articles."
+  :group 'gnus-article-mime
+  :type 'function)
+
+(defvar gnus-decode-header-function 'mail-decode-encoded-word-region
+  "Function used to decode headers.")
+
+(defvar gnus-decode-address-function 'mail-decode-encoded-address-region
+  "Function used to decode addresses.")
+
+(defvar gnus-article-dumbquotes-map
+  '((?\200 "EUR")
+    (?\202 ",")
+    (?\203 "f")
+    (?\204 ",,")
+    (?\205 "...")
+    (?\213 "<")
+    (?\214 "OE")
+    (?\221 "`")
+    (?\222 "'")
+    (?\223 "``")
+    (?\224 "\"")
+    (?\225 "*")
+    (?\226 "-")
+    (?\227 "--")
+    (?\230 "~")
+    (?\231 "(TM)")
+    (?\233 ">")
+    (?\234 "oe")
+    (?\264 "'"))
+  "Table for MS-to-Latin1 translation.")
+
+(defcustom gnus-ignored-mime-types nil
+  "List of MIME types that should be ignored by Gnus."
+  :version "21.1"
+  :group 'gnus-article-mime
+  :type '(repeat regexp))
+
+(defcustom gnus-unbuttonized-mime-types '(".*/.*")
+  "List of MIME types that should not be given buttons when rendered inline.
+See also `gnus-buttonized-mime-types' which may override this variable.
+This variable is only used when `gnus-inhibit-mime-unbuttonizing' is nil."
+  :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\")'.  You could also add \"multipart/alternative\" to
+this list to display radio buttons that allow you to choose one of two
+media types those mails include.  See also `mm-discouraged-alternatives'.
+This variable is only used when `gnus-inhibit-mime-unbuttonizing' is nil."
+  :version "22.1"
+  :group 'gnus-article-mime
+  :type '(repeat regexp))
+
+(defcustom gnus-inhibit-mime-unbuttonizing nil
+  "If non-nil, all MIME parts get buttons.
+When nil (the default value), then some MIME parts do not get buttons,
+as described by the variables `gnus-buttonized-mime-types' and
+`gnus-unbuttonized-mime-types'."
+  :version "22.1"
+  :group 'gnus-article-mime
+  :type 'boolean)
+
+(defcustom gnus-body-boundary-delimiter "_"
+  "String used to delimit header and body.
+This variable is used by `gnus-article-treat-body-boundary' which can
+be controlled by `gnus-treat-body-boundary'."
+  :version "22.1"
+  :group 'gnus-article-various
+  :type '(choice (item :tag "None" :value nil)
+                string))
+
+(defcustom gnus-picon-databases '("/usr/lib/picon" "/usr/local/faces"
+                                 "/usr/share/picons")
+  "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"
+  :version "22.1"
+  :type '(repeat directory)
+  :link '(url-link :tag "download"
+                  "http://www.cs.indiana.edu/picons/ftp/index.html")
+  :link '(custom-manual "(gnus)Picons")
+  :group 'gnus-picon)
+
+(defun gnus-picons-installed-p ()
+  "Say whether picons are installed on your machine."
+  (let ((installed nil))
+    (dolist (database gnus-picon-databases)
+      (when (file-exists-p database)
+       (setq installed t)))
+    installed))
+
+(defcustom gnus-article-mime-part-function nil
+  "Function called with a MIME handle as the argument.
+This is meant for people who want to do something automatic based
+on parts -- for instance, adding Vcard info to a database."
+  :group 'gnus-article-mime
+  :type '(choice (const nil)
+                function))
+
+(defcustom gnus-mime-multipart-functions nil
+  "An alist of MIME types to functions to display them."
+  :version "21.1"
+  :group 'gnus-article-mime
+  :type '(repeat (cons :format "%v" (string :tag "MIME type") function)))
+
+(defcustom gnus-article-date-headers '(combined-lapsed)
+  "A list of Date header formats to display.
+Valid formats are `ut' (universal time), `local' (local time
+zone), `english' (readable English), `lapsed' (elapsed time),
+`combined-lapsed' (both the original date and the elapsed time),
+`original' (the original date header), `iso8601' (ISO8601
+format), and `user-defined' (a user-defined format defined by the
+`gnus-article-time-format' variable).
+
+You have as many date headers as you want in the article buffer.
+Some of these headers are updated automatically.  See
+`gnus-article-update-date-headers' for details."
+  :version "24.1"
+  :group 'gnus-article-headers
+  :type '(set
+         (const :tag "Universal time (UT)" ut)
+         (const :tag "Local time zone" local)
+         (const :tag "Readable English" english)
+         (const :tag "Elapsed time" lapsed)
+         (const :tag "Original and elapsed time" combined-lapsed)
+         (const :tag "Original date header" original)
+         (const :tag "ISO8601 format" iso8601)
+         (const :tag "User-defined" user-defined)))
+
+(defcustom gnus-article-update-date-headers nil
+  "A number that says how often to update the date header (in seconds).
+If nil, don't update it at all."
+  :version "24.1"
+  :group 'gnus-article-headers
+  :type '(choice
+         (item :tag "Don't update" :value nil)
+         integer))
+
+(defcustom gnus-article-mime-match-handle-function 'undisplayed-alternative
+  "Function called with a MIME handle as the argument.
+This is meant for people who want to view first matched part.
+For `undisplayed-alternative' (default), the first undisplayed
+part or alternative part is used.  For `undisplayed', the first
+undisplayed part is used.  For a function, the first part which
+the function return t is used.  For nil, the first part is
+used."
+  :version "21.1"
+  :group 'gnus-article-mime
+  :type '(choice
+         (item :tag "first" :value nil)
+         (item :tag "undisplayed" :value undisplayed)
+         (item :tag "undisplayed or alternative"
+               :value undisplayed-alternative)
+         (function)))
+
+(defcustom gnus-mime-action-alist
+  '(("save to file" . gnus-mime-save-part)
+    ("save and strip" . gnus-mime-save-part-and-strip)
+    ("replace with file" . gnus-mime-replace-part)
+    ("delete part" . gnus-mime-delete-part)
+    ("display as text" . gnus-mime-inline-part)
+    ("view the part" . gnus-mime-view-part)
+    ("pipe to command" . gnus-mime-pipe-part)
+    ("toggle display" . gnus-article-press-button)
+    ("toggle display" . gnus-article-view-part-as-charset)
+    ("view as type" . gnus-mime-view-part-as-type)
+    ("view internally" . gnus-mime-view-part-internally)
+    ("view externally" . gnus-mime-view-part-externally))
+  "An alist of actions that run on the MIME attachment."
+  :group 'gnus-article-mime
+  :type '(repeat (cons (string :tag "name")
+                      (function))))
+
+(defcustom gnus-auto-select-part 1
+  "Advance to next MIME part when deleting or stripping parts.
+
+When 0, point will be placed on the same part as before.  When
+positive (negative), move point forward (backwards) this many
+parts.  When nil, redisplay article."
+  :version "23.1" ;; No Gnus
+  :group 'gnus-article-mime
+  :type '(choice (const nil :tag "Redisplay article.")
+                (const 1 :tag "Next part.")
+                (const 0 :tag "Current part.")
+                integer))
+
+;;;
+;;; The treatment variables
+;;;
+
+(defvar gnus-part-display-hook nil
+  "Hook called on parts that are to receive treatment.")
+
+(defvar gnus-article-treat-custom
+  '(choice (const :tag "Off" nil)
+          (const :tag "On" t)
+          (const :tag "Header" head)
+          (const :tag "First" first)
+          (const :tag "Last" last)
+          (integer :tag "Less")
+          (repeat :tag "Groups" regexp)
+          (sexp :tag "Predicate")))
+
+(defvar gnus-article-treat-head-custom
+  '(choice (const :tag "Off" nil)
+          (const :tag "Header" head)))
+
+(defvar gnus-article-treat-types '("text/plain" "text/x-verbatim"
+                                  "text/x-patch" "text/html")
+  "Part types eligible for treatment.")
+
+(defvar gnus-inhibit-treatment nil
+  "Whether to inhibit treatment.")
+
+(defcustom gnus-treat-highlight-signature '(or t (typep "text/x-vcard"))
+  "Highlight the signature.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+(put 'gnus-treat-highlight-signature 'highlight t)
+
+(defcustom gnus-treat-buttonize '(and 100000 (typep "text/plain"))
+  "Add buttons.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+(put 'gnus-treat-buttonize 'highlight t)
+
+(defcustom gnus-treat-buttonize-head 'head
+  "Add buttons to the head.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-head-custom)
+(put 'gnus-treat-buttonize-head 'highlight t)
+
+(defcustom gnus-treat-date 'head
+  "Display dates according to the `gnus-article-date-headers' variable.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :version "24.1"
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-head-custom)
+
+(defcustom gnus-treat-emphasize 50000
+  "Emphasize text.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+(put 'gnus-treat-emphasize 'highlight t)
+
+(defcustom gnus-treat-strip-cr nil
+  "Remove carriage returns.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :version "22.1"
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-unsplit-urls nil
+  "Remove newlines from within URLs.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :version "22.1"
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-leading-whitespace nil
+  "Remove leading whitespace in headers.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :version "22.1"
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-hide-headers 'head
+  "Hide headers.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-head-custom)
+
+(defcustom gnus-treat-hide-boring-headers nil
+  "Hide boring headers.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-head-custom)
+
+(defcustom gnus-treat-hide-signature nil
+  "Hide the signature.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-fill-article nil
+  "Fill the article.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-hide-citation nil
+  "Hide cited text.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'.
+
+See `gnus-article-highlight-citation' for variables used to
+control what it hides."
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-hide-citation-maybe nil
+  "Hide cited text according to certain conditions.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'.
+
+See `gnus-cite-hide-percentage' and `gnus-cite-hide-absolute' for
+how to control what it hides."
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :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', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :version "21.1"
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
+(gnus-define-group-parameter
+ list-identifier
+ :variable-document
+ "Alist of regexps and correspondent identifiers."
+ :variable-group gnus-article-washing
+ :parameter-type
+ '(choice :tag "Identifier"
+         :value nil
+         (symbol :tag "Item in `gnus-list-identifiers'" none)
+         regexp
+         (const :tag "None" nil))
+ :parameter-document
+ "If non-nil, specify how to remove `identifiers' from articles' subject.
+
+Any symbol is used to look up a regular expression to match the
+banner in `gnus-list-identifiers'.  A string is used as a regular
+expression to match the identifier directly.")
+
+(make-obsolete-variable 'gnus-treat-strip-pgp nil
+                       "Gnus 5.10 (Emacs 22.1)")
+
+(defcustom gnus-treat-strip-pem nil
+  "Strip PEM signatures.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-strip-banner t
+  "Strip banners from articles.
+The banner to be stripped is specified in the `banner' group parameter.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-highlight-headers 'head
+  "Highlight the headers.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-head-custom)
+(put 'gnus-treat-highlight-headers 'highlight t)
+
+(defcustom gnus-treat-highlight-citation t
+  "Highlight cited text.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+(put 'gnus-treat-highlight-citation 'highlight t)
+
+(defcustom gnus-treat-strip-headers-in-body t
+  "Strip the X-No-Archive header line from the beginning of the body.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :version "21.1"
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-strip-trailing-blank-lines nil
+  "Strip trailing blank lines.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'.
+
+When set to t, it also strips trailing blanks in all MIME parts.
+Consider to use `last' instead."
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-strip-leading-blank-lines nil
+  "Strip leading blank lines.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'.
+
+When set to t, it also strips trailing blanks in all MIME parts."
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-strip-multiple-blank-lines nil
+  "Strip multiple blank lines.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-unfold-headers 'head
+  "Unfold folded header lines.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :version "22.1"
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-article-unfold-long-headers nil
+  "If non-nil, allow unfolding headers even if the header is long.
+If it is a regexp, only long headers matching this regexp are unfolded.
+If it is t, all long headers are unfolded.
+
+This variable has no effect if `gnus-treat-unfold-headers' is nil."
+  :version "23.1" ;; No Gnus
+  :group 'gnus-article-treat
+  :type '(choice (const nil)
+                (const :tag "all" t)
+                (regexp)))
+
+(defcustom gnus-treat-fold-headers nil
+  "Fold headers.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :version "22.1"
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-fold-newsgroups 'head
+  "Fold the Newsgroups and Followup-To headers.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :version "22.1"
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-overstrike t
+  "Treat overstrike highlighting.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+(put 'gnus-treat-overstrike 'highlight t)
+
+(defcustom gnus-treat-ansi-sequences (if (locate-library "ansi-color") t)
+  "Treat ANSI SGR control sequences.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
+(make-obsolete-variable 'gnus-treat-display-xface
+                       'gnus-treat-display-x-face "Emacs 22.1")
+
+(defcustom gnus-treat-display-x-face
+  (and (not noninteractive)
+       (gnus-image-type-available-p 'xbm)
+       (if (featurep 'xemacs)
+          (featurep 'xface)
+        (condition-case nil
+             (and (string-match "^0x" (shell-command-to-string "uncompface"))
+                  (executable-find "icontopbm"))
+           ;; shell-command-to-string may signal an error, e.g. if
+           ;; shell-file-name is not found.
+           (error nil)))
+       'head)
+  "Display X-Face headers.
+Valid values are nil and `head'.
+See Info node `(gnus)Customizing Articles' and Info node
+`(gnus)X-Face' for details."
+  :group 'gnus-article-treat
+  :version "21.1"
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :link '(custom-manual "(gnus)X-Face")
+  :type gnus-article-treat-head-custom
+  :set (lambda (symbol value)
+        (set-default
+         symbol
+         (cond ((or (boundp symbol) (get symbol 'saved-value))
+                value)
+               ((boundp 'gnus-treat-display-xface)
+                (message "\
+** gnus-treat-display-xface is an obsolete variable;\
+ use gnus-treat-display-x-face instead")
+                (default-value 'gnus-treat-display-xface))
+               ((get 'gnus-treat-display-xface 'saved-value)
+                (message "\
+** gnus-treat-display-xface is an obsolete variable;\
+ use gnus-treat-display-x-face instead")
+                (eval (car (get 'gnus-treat-display-xface 'saved-value))))
+               (t
+                value)))))
+(put 'gnus-treat-display-x-face 'highlight t)
+
+(defcustom gnus-treat-display-face
+  (and (not noninteractive)
+       (gnus-image-type-available-p 'png)
+       'head)
+  "Display Face headers.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles' and Info
+node `(gnus)Face' for details."
+  :group 'gnus-article-treat
+  :version "22.1"
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :link '(custom-manual "(gnus)X-Face")
+  :type gnus-article-treat-head-custom)
+(put 'gnus-treat-display-face 'highlight t)
+
+(defcustom gnus-treat-display-smileys (gnus-image-type-available-p 'xpm)
+  "Display smileys.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles' and Info
+node `(gnus)Smileys' for details."
+  :group 'gnus-article-treat
+  :version "21.1"
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :link '(custom-manual "(gnus)Smileys")
+  :type gnus-article-treat-custom)
+(put 'gnus-treat-display-smileys 'highlight t)
+
+(defcustom gnus-treat-from-picon
+  (if (and (gnus-image-type-available-p 'xpm)
+          (gnus-picons-installed-p))
+      'head nil)
+  "Display picons in the From header.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles' and Info
+node `(gnus)Picons' for details."
+  :version "22.1"
+  :group 'gnus-article-treat
+  :group 'gnus-picon
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :link '(custom-manual "(gnus)Picons")
+  :type gnus-article-treat-head-custom)
+(put 'gnus-treat-from-picon 'highlight t)
+
+(defcustom gnus-treat-mail-picon
+  (if (and (gnus-image-type-available-p 'xpm)
+          (gnus-picons-installed-p))
+      'head nil)
+  "Display picons in To and Cc headers.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles' and Info
+node `(gnus)Picons' for details."
+  :version "22.1"
+  :group 'gnus-article-treat
+  :group 'gnus-picon
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :link '(custom-manual "(gnus)Picons")
+  :type gnus-article-treat-head-custom)
+(put 'gnus-treat-mail-picon 'highlight t)
+
+(defcustom gnus-treat-newsgroups-picon
+  (if (and (gnus-image-type-available-p 'xpm)
+          (gnus-picons-installed-p))
+      'head nil)
+  "Display picons in the Newsgroups and Followup-To headers.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles' and Info
+node `(gnus)Picons' for details."
+  :version "22.1"
+  :group 'gnus-article-treat
+  :group 'gnus-picon
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :link '(custom-manual "(gnus)Picons")
+  :type gnus-article-treat-head-custom)
+(put 'gnus-treat-newsgroups-picon 'highlight t)
+
+(defcustom gnus-treat-from-gravatar nil
+  "Display gravatars in the From header.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles' and Info
+node `(gnus)Gravatars' for details."
+  :version "24.1"
+  :group 'gnus-article-treat
+  :group 'gnus-gravatar
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :link '(custom-manual "(gnus)Gravatars")
+  :type gnus-article-treat-head-custom)
+(put 'gnus-treat-from-gravatar 'highlight t)
+
+(defcustom gnus-treat-mail-gravatar nil
+  "Display gravatars in To and Cc headers.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles' and Info
+node `(gnus)Gravatars' for details."
+  :version "24.1"
+  :group 'gnus-article-treat
+  :group 'gnus-gravatar
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :link '(custom-manual "(gnus)Gravatars")
+  :type gnus-article-treat-head-custom)
+(put 'gnus-treat-mail-gravatar 'highlight t)
+
+(defcustom gnus-treat-body-boundary
+  (if (or gnus-treat-newsgroups-picon
+         gnus-treat-mail-picon
+         gnus-treat-from-picon
+          gnus-treat-from-gravatar
+          gnus-treat-mail-gravatar)
+      ;; If there's much decoration, the user might prefer a boundary.
+      'head
+    nil)
+  "Draw a boundary at the end of the headers.
+Valid values are nil and `head'.
+See Info node `(gnus)Customizing Articles' for details."
+  :version "22.1"
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-head-custom)
+
+(defcustom gnus-treat-capitalize-sentences nil
+  "Capitalize sentence-starting words.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :version "21.1"
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-wash-html nil
+  "Format as HTML.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :version "22.1"
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-fill-long-lines '(typep "text/plain")
+  "Fill long lines.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :version "24.1"
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-x-pgp-sig nil
+  "Verify X-PGP-Sig.
+To automatically treat X-PGP-Sig, set it to head.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :version "22.1"
+  :group 'gnus-article-treat
+  :group 'mime-security
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
+(defvar gnus-article-encrypt-protocol-alist
+  '(("PGP" . mml2015-self-encrypt)))
+
+;; Set to nil if more than one protocol added to
+;; gnus-article-encrypt-protocol-alist.
+(defcustom gnus-article-encrypt-protocol "PGP"
+  "The protocol used for encrypt articles.
+It is a string, such as \"PGP\". If nil, ask user."
+  :version "22.1"
+  :type 'string
+  :group 'mime-security)
+
+(defvar idna-program)
+
+(defcustom gnus-use-idna (and (mm-coding-system-p 'utf-8)
+                             (condition-case nil
+                                 (require 'idna)
+                               (file-error)
+                               (invalid-operation))
+                             idna-program
+                             (executable-find idna-program))
+  "Whether IDNA decoding of headers is used when viewing messages.
+This requires GNU Libidn, and by default only enabled if it is found."
+  :version "22.1"
+  :group 'gnus-article-headers
+  :type 'boolean)
+
+(defcustom gnus-article-over-scroll nil
+  "If non-nil, allow scrolling the article buffer even when there no more text."
+  :version "22.1"
+  :group 'gnus-article
+  :type 'boolean)
+
+(defcustom gnus-inhibit-images nil
+  "Non-nil means inhibit displaying of images inline in the article body."
+  :version "24.1"
+  :group 'gnus-article
+  :type 'boolean)
+
+(defcustom gnus-blocked-images 'gnus-block-private-groups
+  "Images that have URLs matching this regexp will be blocked.
+This can also be a function to be evaluated.  If so, it will be
+called with the group name as the parameter, and should return a
+regexp."
+  :version "24.1"
+  :group 'gnus-art
+  :type '(choice regexp function))
+
+;;; Internal variables
+
+(defvar gnus-english-month-names
+  '("January" "February" "March" "April" "May" "June" "July" "August"
+    "September" "October" "November" "December"))
+
+(defvar article-goto-body-goes-to-point-min-p nil)
+(defvar gnus-article-wash-types nil)
+(defvar gnus-article-emphasis-alist nil)
+(defvar gnus-article-image-alist nil)
+
+(defvar gnus-article-mime-handle-alist-1 nil)
+(defvar gnus-treatment-function-alist
+  '((gnus-treat-strip-cr gnus-article-remove-cr)
+    (gnus-treat-x-pgp-sig gnus-article-verify-x-pgp-sig)
+    (gnus-treat-strip-banner gnus-article-strip-banner)
+    (gnus-treat-strip-headers-in-body gnus-article-strip-headers-in-body)
+    (gnus-treat-highlight-signature gnus-article-highlight-signature)
+    (gnus-treat-buttonize gnus-article-add-buttons)
+    (gnus-treat-fill-article gnus-article-fill-cited-article)
+    (gnus-treat-fill-long-lines gnus-article-fill-cited-long-lines)
+    (gnus-treat-unsplit-urls gnus-article-unsplit-urls)
+    (gnus-treat-display-x-face gnus-article-display-x-face)
+    (gnus-treat-display-face gnus-article-display-face)
+    (gnus-treat-hide-headers gnus-article-maybe-hide-headers)
+    (gnus-treat-hide-boring-headers gnus-article-hide-boring-headers)
+    (gnus-treat-hide-signature gnus-article-hide-signature)
+    (gnus-treat-strip-list-identifiers gnus-article-hide-list-identifiers)
+    (gnus-treat-leading-whitespace gnus-article-remove-leading-whitespace)
+    (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-strip-pem gnus-article-hide-pem)
+    (gnus-treat-date gnus-article-treat-date)
+    (gnus-treat-from-gravatar gnus-treat-from-gravatar)
+    (gnus-treat-mail-gravatar gnus-treat-mail-gravatar)
+    (gnus-treat-highlight-headers gnus-article-highlight-headers)
+    (gnus-treat-highlight-signature gnus-article-highlight-signature)
+    (gnus-treat-strip-trailing-blank-lines
+     gnus-article-remove-trailing-blank-lines)
+    (gnus-treat-strip-leading-blank-lines
+     gnus-article-strip-leading-blank-lines)
+    (gnus-treat-strip-multiple-blank-lines
+     gnus-article-strip-multiple-blank-lines)
+    (gnus-treat-overstrike gnus-article-treat-overstrike)
+    (gnus-treat-ansi-sequences gnus-article-treat-ansi-sequences)
+    (gnus-treat-unfold-headers gnus-article-treat-unfold-headers)
+    (gnus-treat-fold-newsgroups gnus-article-treat-fold-newsgroups)
+    (gnus-treat-fold-headers gnus-article-treat-fold-headers)
+    (gnus-treat-buttonize-head gnus-article-add-buttons-to-head)
+    (gnus-treat-display-smileys gnus-treat-smiley)
+    (gnus-treat-capitalize-sentences gnus-article-capitalize-sentences)
+    (gnus-treat-wash-html gnus-article-wash-html)
+    (gnus-treat-emphasize gnus-article-emphasize)
+    (gnus-treat-hide-citation gnus-article-hide-citation)
+    (gnus-treat-hide-citation-maybe gnus-article-hide-citation-maybe)
+    (gnus-treat-highlight-citation gnus-article-highlight-citation)
+    (gnus-treat-body-boundary gnus-article-treat-body-boundary)))
+
+(defvar gnus-article-mime-handle-alist nil)
+(defvar article-lapsed-timer nil)
+(defvar gnus-article-current-summary nil)
+
+(defvar gnus-article-mode-syntax-table
+  (let ((table (copy-syntax-table text-mode-syntax-table)))
+    ;; This causes the citation match run O(2^n).
+    ;; (modify-syntax-entry ?- "w" table)
+    (modify-syntax-entry ?> ")<" table)
+    (modify-syntax-entry ?< "(>" table)
+    ;; make M-. in article buffers work for `foo' strings
+    (modify-syntax-entry ?' " " table)
+    (modify-syntax-entry ?` " " table)
+    table)
+  "Syntax table used in article mode buffers.
+Initialized from `text-mode-syntax-table'.")
+
+(defvar gnus-save-article-buffer nil)
+
+(defvar gnus-number-of-articles-to-be-saved nil)
+
+(defvar gnus-inhibit-hiding nil)
+
+(defvar gnus-article-edit-mode nil)
+
+;;; Macros for dealing with the article buffer.
+
+(defmacro gnus-with-article-headers (&rest forms)
+  `(with-current-buffer gnus-article-buffer
+     (save-restriction
+       (let ((inhibit-read-only t)
+            (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)
+  `(when (buffer-live-p (get-buffer gnus-article-buffer))
+     (with-current-buffer gnus-article-buffer
+       (let ((inhibit-read-only t))
+         ,@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."
+  (gnus-add-text-properties-when 'article-type nil b e props))
+
+(defsubst gnus-article-unhide-text (b e)
+  "Remove hidden text properties from region between B and E."
+  (remove-text-properties b e gnus-hidden-properties))
+
+(defun gnus-article-hide-text-type (b e type)
+  "Hide text of TYPE between B and E."
+  (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."
+  (gnus-delete-wash-type type)
+  (remove-text-properties
+   b e (cons 'article-type (cons type gnus-hidden-properties))))
+
+(defun gnus-article-delete-text-of-type (type)
+  "Delete text of TYPE in the current buffer."
+  (save-excursion
+    (let ((b (point-min)))
+      (if (eq type 'multipart)
+         ;; Remove MIME buttons associated with multipart/alternative parts.
+         (progn
+           (goto-char b)
+           (while (if (get-text-property (point) 'gnus-part)
+                      (setq b (point))
+                    (when (setq b (next-single-property-change (point)
+                                                               'gnus-part))
+                      (goto-char b)
+                      t))
+             (end-of-line)
+             (skip-chars-forward "\n")
+             (when (eq (get-text-property b 'article-type) 'multipart)
+               (delete-region b (point)))))
+       (while (setq b (text-property-any b (point-max) 'article-type type))
+         (delete-region
+          b (or (text-property-not-all b (point-max) 'article-type type)
+                (point-max))))))))
+
+(defun gnus-article-delete-invisible-text ()
+  "Delete all invisible text in the current buffer."
+  (save-excursion
+    (let ((b (point-min)))
+      (while (setq b (text-property-any b (point-max) 'invisible t))
+       (delete-region
+        b (or (text-property-not-all b (point-max) 'invisible t)
+              (point-max)))))))
+
+(defsubst gnus-article-header-rank ()
+  "Give the rank of the string HEADER as given by `gnus-sorted-header-list'."
+  (let ((list gnus-sorted-header-list)
+       (i 1))
+    (while list
+      (if (looking-at (car list))
+         (setq list nil)
+       (setq list (cdr list))
+       (incf i)))
+      i))
+
+(defun article-hide-headers (&optional _arg _delete)
+  "Hide unwanted headers and possibly sort them as well."
+  (interactive)
+  ;; This function might be inhibited.
+  (unless gnus-inhibit-hiding
+    (let ((inhibit-read-only t)
+         (case-fold-search t)
+         (max (1+ (length gnus-sorted-header-list)))
+         (inhibit-point-motion-hooks t)
+         (cur (current-buffer))
+         ignored visible beg)
+      (save-excursion
+       ;; `gnus-ignored-headers' and `gnus-visible-headers' may be
+       ;; group parameters, so we should go to the summary buffer.
+       (when (prog1
+                 (condition-case nil
+                     (progn (set-buffer gnus-summary-buffer) t)
+                   (error nil))
+               (setq ignored (when (not gnus-visible-headers)
+                               (cond ((stringp gnus-ignored-headers)
+                                      gnus-ignored-headers)
+                                     ((listp gnus-ignored-headers)
+                                      (mapconcat 'identity
+                                                 gnus-ignored-headers
+                                                 "\\|"))))
+                     visible (cond ((stringp gnus-visible-headers)
+                                    gnus-visible-headers)
+                                   ((and gnus-visible-headers
+                                         (listp gnus-visible-headers))
+                                    (mapconcat 'identity
+                                               gnus-visible-headers
+                                               "\\|")))))
+         (set-buffer cur))
+       (save-restriction
+         ;; First we narrow to just the headers.
+         (article-narrow-to-head)
+         ;; Hide any "From " lines at the beginning of (mail) articles.
+         (while (looking-at "From ")
+           (forward-line 1))
+         (unless (bobp)
+           (delete-region (point-min) (point)))
+         ;; Then treat the rest of the header lines.
+         ;; Then we use the two regular expressions
+         ;; `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)
+           (beginning-of-line)
+           ;; Mark the rank of the header.
+           (put-text-property
+            (point) (1+ (point)) 'message-rank
+            (if (or (and visible (looking-at visible))
+                    (and ignored
+                         (not (looking-at ignored))))
+                (gnus-article-header-rank)
+              (+ 2 max)))
+           (forward-line 1))
+         (message-sort-headers-1)
+         (when (setq beg (text-property-any
+                          (point-min) (point-max) 'message-rank (+ 2 max)))
+           ;; We delete the unwanted headers.
+           (gnus-add-wash-type 'headers)
+           (add-text-properties (point-min) (+ 5 (point-min))
+                                '(article-type headers dummy-invisible t))
+           (delete-region beg (point-max))))))))
+
+(defun article-hide-boring-headers (&optional arg)
+  "Toggle hiding of headers that aren't very interesting.
+If given a negative prefix, always show; if given a positive prefix,
+always hide."
+  (interactive (gnus-article-hidden-arg))
+  (when (and (not (gnus-article-check-hidden-text 'boring-headers arg))
+            (not gnus-show-all-headers))
+    (save-excursion
+      (save-restriction
+       (let ((inhibit-read-only t)
+             (inhibit-point-motion-hooks t))
+         (article-narrow-to-head)
+         (dolist (elem gnus-boring-article-headers)
+           (goto-char (point-min))
+           (cond
+            ;; Hide empty headers.
+            ((eq elem 'empty)
+             (while (re-search-forward "^[^: \t]+:[ \t]*\n[^ \t]" nil t)
+               (forward-line -1)
+               (gnus-article-hide-text-type
+                (point-at-bol)
+                (progn
+                  (end-of-line)
+                  (if (re-search-forward "^[^ \t]" nil t)
+                      (match-beginning 0)
+                    (point-max)))
+                'boring-headers)))
+            ;; Hide boring Newsgroups header.
+            ((eq elem 'newsgroups)
+             (when (gnus-string-equal
+                    (gnus-fetch-field "newsgroups")
+                    (gnus-group-real-name
+                     (if (boundp 'gnus-newsgroup-name)
+                         gnus-newsgroup-name
+                       "")))
+               (gnus-article-hide-header "newsgroups")))
+            ((eq elem 'to-address)
+             (let ((to (message-fetch-field "to"))
+                   (to-address
+                    (gnus-parameter-to-address
+                     (if (boundp 'gnus-newsgroup-name)
+                         gnus-newsgroup-name ""))))
+               (when (and to to-address
+                          (ignore-errors
+                            (gnus-string-equal
+                             ;; only one address in To
+                             (nth 1 (mail-extract-address-components to))
+                             to-address)))
+                 (gnus-article-hide-header "to"))))
+            ((eq elem 'to-list)
+             (let ((to (message-fetch-field "to"))
+                   (to-list
+                    (gnus-parameter-to-list
+                     (if (boundp 'gnus-newsgroup-name)
+                         gnus-newsgroup-name ""))))
+               (when (and to to-list
+                          (ignore-errors
+                            (gnus-string-equal
+                             ;; only one address in To
+                             (nth 1 (mail-extract-address-components to))
+                             to-list)))
+                 (gnus-article-hide-header "to"))))
+            ((eq elem 'cc-list)
+             (let ((cc (message-fetch-field "cc"))
+                   (to-list
+                    (gnus-parameter-to-list
+                     (if (boundp 'gnus-newsgroup-name)
+                         gnus-newsgroup-name ""))))
+               (when (and cc to-list
+                          (ignore-errors
+                            (gnus-string-equal
+                             ;; only one address in CC
+                             (nth 1 (mail-extract-address-components cc))
+                             to-list)))
+                 (gnus-article-hide-header "cc"))))
+            ((eq elem 'followup-to)
+             (when (gnus-string-equal
+                    (message-fetch-field "followup-to")
+                    (message-fetch-field "newsgroups"))
+               (gnus-article-hide-header "followup-to")))
+            ((eq elem 'reply-to)
+             (if (gnus-group-find-parameter
+                  gnus-newsgroup-name 'broken-reply-to)
+                 (gnus-article-hide-header "reply-to")
+               (let ((from (message-fetch-field "from"))
+                     (reply-to (message-fetch-field "reply-to")))
+                 (when
+                     (and
+                      from reply-to
+                      (ignore-errors
+                        (equal
+                         (sort (mapcar
+                                (lambda (x) (downcase (cadr x)))
+                                (mail-extract-address-components from t))
+                               'string<)
+                         (sort (mapcar
+                                (lambda (x) (downcase (cadr x)))
+                                (mail-extract-address-components reply-to t))
+                               'string<))))
+                   (gnus-article-hide-header "reply-to")))))
+            ((eq elem 'date)
+             (let ((date (with-current-buffer gnus-original-article-buffer
+                           ;; If date in `gnus-article-buffer' is localized
+                           ;; (`gnus-treat-date-user-defined'),
+                           ;; `days-between' might fail.
+                           (message-fetch-field "date"))))
+               (when (and date
+                          (< (days-between (current-time-string) date)
+                             4))
+                 (gnus-article-hide-header "date"))))
+            ((eq elem 'long-to)
+             (let ((to (message-fetch-field "to"))
+                   (cc (message-fetch-field "cc")))
+               (when (> (length to) 1024)
+                 (gnus-article-hide-header "to"))
+               (when (> (length cc) 1024)
+                 (gnus-article-hide-header "cc"))))
+            ((eq elem 'many-to)
+             (let ((to-count 0)
+                   (cc-count 0))
+               (goto-char (point-min))
+               (while (re-search-forward "^to:" nil t)
+                 (setq to-count (1+ to-count)))
+               (when (> to-count 1)
+                 (while (> to-count 0)
+                   (goto-char (point-min))
+                   (save-restriction
+                     (re-search-forward "^to:" nil nil to-count)
+                     (forward-line -1)
+                     (narrow-to-region (point) (point-max))
+                     (gnus-article-hide-header "to"))
+                   (setq to-count (1- to-count))))
+               (goto-char (point-min))
+               (while (re-search-forward "^cc:" nil t)
+                 (setq cc-count (1+ cc-count)))
+               (when (> cc-count 1)
+                 (while (> cc-count 0)
+                   (goto-char (point-min))
+                   (save-restriction
+                     (re-search-forward "^cc:" nil nil cc-count)
+                     (forward-line -1)
+                     (narrow-to-region (point) (point-max))
+                     (gnus-article-hide-header "cc"))
+                   (setq cc-count (1- cc-count)))))))))))))
+
+(defun gnus-article-hide-header (header)
+  (save-excursion
+    (goto-char (point-min))
+    (when (re-search-forward (concat "^" header ":") nil t)
+      (gnus-article-hide-text-type
+       (point-at-bol)
+       (progn
+        (end-of-line)
+        (if (re-search-forward "^[^ \t]" nil t)
+            (match-beginning 0)
+          (point-max)))
+       'boring-headers))))
+
+(defvar gnus-article-normalized-header-length 40
+  "Length of normalized headers.")
+
+(defun article-normalize-headers ()
+  "Make all header lines 40 characters long."
+  (interactive)
+  (let ((inhibit-read-only t)
+       column)
+    (save-excursion
+      (save-restriction
+       (article-narrow-to-head)
+       (while (not (eobp))
+         (cond
+          ((< (setq column (- (point-at-eol) (point)))
+              gnus-article-normalized-header-length)
+           (end-of-line)
+           (insert (make-string
+                    (- gnus-article-normalized-header-length column)
+                    ? )))
+          ((> column gnus-article-normalized-header-length)
+           (gnus-put-text-property
+            (progn
+              (forward-char gnus-article-normalized-header-length)
+              (point))
+            (point-at-eol)
+            'invisible t))
+          (t
+           ;; Do nothing.
+           ))
+         (forward-line 1))))))
+
+(defun article-treat-dumbquotes ()
+  "Translate M****s*** sm*rtq**t*s and other symbols into proper text.
+Note that this function guesses whether a character is a sm*rtq**t* or
+not, so it should only be used interactively.
+
+Sm*rtq**t*s are M****s***'s unilateral extension to the
+iso-8859-1 character map in an attempt to provide more quoting
+characters.  If you see something like \\222 or \\264 where
+you're expecting some kind of apostrophe or quotation mark, then
+try this wash."
+  (interactive)
+  (article-translate-strings gnus-article-dumbquotes-map))
+
+(defvar org-entities)
+
+(defun article-treat-non-ascii ()
+  "Translate many Unicode characters into their ASCII equivalents."
+  (interactive)
+  (require 'org-entities)
+  (let ((table (make-char-table (if (featurep 'xemacs) 'generic))))
+    (dolist (elem org-entities)
+      (when (and (listp elem)
+                (= (length (nth 6 elem)) 1))
+       (if (featurep 'xemacs)
+           (put-char-table (aref (nth 6 elem) 0) (nth 4 elem) table)
+         (set-char-table-range table (aref (nth 6 elem) 0) (nth 4 elem)))))
+    (save-excursion
+      (when (article-goto-body)
+       (let ((inhibit-read-only t)
+             replace props)
+         (while (not (eobp))
+           (if (not (setq replace (if (featurep 'xemacs)
+                                      (get-char-table (following-char) table)
+                                    (aref table (following-char)))))
+               (forward-char 1)
+             (if (prog1
+                     (setq props (text-properties-at (point)))
+                   (delete-char 1))
+                 (add-text-properties (point) (progn (insert replace) (point))
+                                      props)
+               (insert replace)))))))))
+
+(defun article-translate-strings (map)
+  "Translate all string in the body of the article according to MAP.
+MAP is an alist where the elements are on the form (\"from\" \"to\")."
+  (save-excursion
+    (when (article-goto-body)
+      (let ((inhibit-read-only t))
+       (dolist (elem map)
+         (let ((from (car elem))
+               (to (cadr elem)))
+           (save-excursion
+             (if (stringp from)
+                 (while (search-forward from nil t)
+                   (replace-match to))
+               (while (not (eobp))
+                 (if (eq (following-char) from)
+                     (progn
+                       (delete-char 1)
+                       (insert to))
+                   (forward-char 1)))))))))))
+
+(defun article-treat-overstrike ()
+  "Translate overstrikes into bold text."
+  (interactive)
+  (save-excursion
+    (when (article-goto-body)
+      (let ((inhibit-read-only t))
+       (while (search-forward "\b" nil t)
+         (let ((next (char-after))
+               (previous (char-after (- (point) 2))))
+           ;; We do the boldification/underlining by hiding the
+           ;; overstrikes and putting the proper text property
+           ;; on the letters.
+           (cond
+            ((eq next previous)
+             (gnus-article-hide-text-type (- (point) 2) (point) 'overstrike)
+             (put-text-property (point) (1+ (point)) 'face 'bold))
+            ((eq next ?_)
+             (gnus-article-hide-text-type
+              (1- (point)) (1+ (point)) 'overstrike)
+             (put-text-property
+              (- (point) 2) (1- (point)) 'face 'underline))
+            ((eq previous ?_)
+             (gnus-article-hide-text-type (- (point) 2) (point) 'overstrike)
+             (put-text-property
+              (point) (1+ (point)) 'face 'underline)))))))))
+
+(defun article-treat-ansi-sequences ()
+  "Translate ANSI SGR control sequences into overlays or extents."
+  (interactive)
+  (save-excursion
+    (when (article-goto-body)
+      (let ((inhibit-read-only t))
+       (ansi-color-apply-on-region (point) (point-max))))))
+
+(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-string))
+                (unfoldable
+                 (or (equal gnus-article-unfold-long-headers t)
+                     (and (stringp gnus-article-unfold-long-headers)
+                          (string-match gnus-article-unfold-long-headers
+                                        header)))))
+           (with-temp-buffer
+             (insert header)
+             (goto-char (point-min))
+             (while (re-search-forward "\n[\t ]" nil t)
+               (replace-match " " t t)))
+           (setq length (- (point-max) (point-min) 1))
+           (when (or unfoldable
+                     (< length (window-width)))
+             (while (re-search-forward "\n[\t ]" nil t)
+               (replace-match " " t t))))
+         (goto-char (point-max)))))))
+
+(defun gnus-article-treat-fold-headers ()
+  "Fold message headers."
+  (interactive)
+  (gnus-with-article-headers
+    (while (not (eobp))
+      (save-restriction
+       (mail-header-narrow-to-field)
+       (mail-header-fold-field)
+       (goto-char (point-max))))))
+
+(defun gnus-treat-smiley ()
+  "Toggle display of textual emoticons (\"smileys\") as small graphical icons."
+  (interactive)
+  (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)))))))
+
+(defun gnus-article-remove-images ()
+  "Remove all images from the article buffer."
+  (interactive)
+  (gnus-with-article-buffer
+    (save-restriction
+      (widen)
+      (dolist (elem gnus-article-image-alist)
+       (gnus-delete-images (car elem))))))
+
+(autoload 'w3m-toggle-inline-images "w3m")
+
+(defun gnus-article-show-images ()
+  "Show any images that are in the HTML-rendered article buffer.
+This only works if the article in question is HTML."
+  (interactive)
+  (gnus-with-article-buffer
+    (save-restriction
+      (widen)
+      (if (eq mm-text-html-renderer 'w3m)
+         (let ((mm-inline-text-html-with-images nil))
+           (w3m-toggle-inline-images))
+       (dolist (region (gnus-find-text-property-region (point-min) (point-max)
+                                                       'image-displayer))
+         (destructuring-bind (start end function) region
+           (funcall function (get-text-property start 'image-url)
+                    start end)))))))
+
+(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 (re-search-forward ", *" nil t)
+         (replace-match ", " t t))
+       (mail-header-fold-field)
+       (goto-char (point-max))))))
+
+(defcustom gnus-article-truncate-lines (default-value 'truncate-lines)
+  "Value of `truncate-lines' in Gnus Article buffer.
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :version "23.1" ;; No Gnus
+  :group 'gnus-article
+  ;; :link '(custom-manual "(gnus)Customizing Articles")
+  :type 'boolean)
+
+(defun gnus-article-toggle-truncate-lines (&optional arg)
+  "Toggle whether to fold or truncate long lines in article the buffer.
+If ARG is non-nil and not a number, toggle
+`gnus-article-truncate-lines' too.  If ARG is a number, truncate
+long lines if and only if arg is positive."
+  (interactive "P")
+  (cond
+   ((and (numberp arg) (> arg 0))
+    (setq gnus-article-truncate-lines t))
+   ((numberp arg)
+    (setq gnus-article-truncate-lines nil))
+   (arg
+    (setq gnus-article-truncate-lines
+         (not gnus-article-truncate-lines))))
+  (gnus-with-article-buffer
+    (cond
+     ((and (numberp arg) (> arg 0))
+      (setq truncate-lines nil))
+     ((numberp arg)
+      (setq truncate-lines t)))
+    ;; In versions of Emacs 22 (CVS) before 2006-05-26,
+    ;; `toggle-truncate-lines' needs an argument.
+    (toggle-truncate-lines)))
+
+(defun gnus-article-treat-body-boundary ()
+  "Place a boundary line at the end of the headers."
+  (interactive)
+  (when (and gnus-body-boundary-delimiter
+            (> (length gnus-body-boundary-delimiter) 0))
+    (gnus-with-article-headers
+      (goto-char (point-max))
+      (let ((start (point)))
+       (insert "X-Boundary: ")
+       (gnus-add-text-properties start (point) gnus-hidden-properties)
+       (insert (let (str (max (window-width)))
+                 (if (featurep 'xemacs)
+                     (setq max (1- max)))
+                 (while (>= max (length str))
+                   (setq str (concat str gnus-body-boundary-delimiter)))
+                 (substring str 0 max))
+               "\n")
+       (gnus-put-text-property start (point) 'gnus-decoration 'header)))))
+
+(defun article-fill-long-lines ()
+  "Fill lines that are wider than the window width."
+  (interactive)
+  (save-excursion
+    (let ((inhibit-read-only t)
+         (width (window-width (get-buffer-window (current-buffer)))))
+      (save-restriction
+       (article-goto-body)
+       (let ((adaptive-fill-mode nil)) ;Why?  -sm
+         (while (not (eobp))
+           (end-of-line)
+           (when (>= (current-column) (min fill-column width))
+             (narrow-to-region (min (1+ (point)) (point-max))
+                               (point-at-bol))
+              (let ((goback (point-marker)))
+                (fill-paragraph nil)
+                (goto-char (marker-position goback)))
+             (widen))
+           (forward-line 1)))))))
+
+(defun article-capitalize-sentences ()
+  "Capitalize the first word in each sentence."
+  (interactive)
+  (save-excursion
+    (let ((inhibit-read-only t)
+         (paragraph-start "^[\n\^L]"))
+      (article-goto-body)
+      (while (not (eobp))
+       (capitalize-word 1)
+       (forward-sentence)))))
+
+(defun article-remove-cr ()
+  "Remove trailing CRs and then translate remaining CRs into LFs."
+  (interactive)
+  (save-excursion
+    (let ((inhibit-read-only t))
+      (goto-char (point-min))
+      (while (re-search-forward "\r+$" nil t)
+       (replace-match "" t t))
+      (goto-char (point-min))
+      (while (search-forward "\r" nil t)
+       (replace-match "\n" t t)))))
+
+(defun article-remove-trailing-blank-lines ()
+  "Remove all trailing blank lines from the article."
+  (interactive)
+  (save-excursion
+    (let ((inhibit-read-only t))
+      (goto-char (point-max))
+      (delete-region
+       (point)
+       (progn
+        (while (and (not (bobp))
+                    (looking-at "^[ \t]*$")
+                    (not (gnus-annotation-in-region-p
+                          (point) (point-at-eol))))
+          (forward-line -1))
+        (forward-line 1)
+        (point))))))
+
+(defvar gnus-face-properties-alist)
+
+(defun article-display-face (&optional force)
+  "Display any Face headers in the header."
+  (interactive (list 'force))
+  (let ((wash-face-p buffer-read-only))
+    (gnus-with-article-headers
+      ;; When displaying parts, this function can be called several times on
+      ;; the same article, without any intended toggle semantic (as typing `W
+      ;; D d' would have). So face deletion must occur only when we come from
+      ;; an interactive command, that is when the *Article* buffer is
+      ;; read-only.
+      (if (and wash-face-p (memq 'face gnus-article-wash-types))
+         (gnus-delete-images 'face)
+       (let ((from (message-fetch-field "from"))
+             faces)
+         (save-current-buffer
+           (when (and wash-face-p
+                      (gnus-buffer-live-p gnus-original-article-buffer)
+                      (not (re-search-forward "^Face:[\t ]*" nil t)))
+             (set-buffer gnus-original-article-buffer))
+           (save-restriction
+             (mail-narrow-to-head)
+             (when (or force
+                       ;; Check whether this face is censored.
+                       (not (and gnus-article-x-face-too-ugly
+                                 (or from
+                                     (setq from (message-fetch-field "from")))
+                                 (string-match gnus-article-x-face-too-ugly
+                                               from))))
+               (while (gnus-article-goto-header "Face")
+                 (push (mail-header-field-value) faces)))))
+         (when faces
+           (goto-char (point-min))
+           (let (png image)
+             (unless (setq from (gnus-article-goto-header "from"))
+               (insert "From:")
+               (setq from (point))
+               (insert " [no 'from' set]\n"))
+             (while faces
+               (when (setq png (gnus-convert-face-to-png (pop faces)))
+                 (setq image
+                       (apply 'gnus-create-image png 'png t
+                              (cdr (assq 'png gnus-face-properties-alist))))
+                 (goto-char from)
+                 (when image
+                   (gnus-add-wash-type 'face)
+                   (gnus-add-image 'face image)
+                   (gnus-put-image image nil 'face)))))))))))
+
+(defun article-display-x-face (&optional force)
+  "Look for an X-Face header and display it if present."
+  (interactive (list 'force))
+  (let ((wash-face-p buffer-read-only))        ;; When type `W f'
+    (gnus-with-article-headers
+      ;; Delete the old process, if any.
+      (when (process-status "article-x-face")
+       (delete-process "article-x-face"))
+      ;; See the comment in `article-display-face'.
+      (if (and wash-face-p (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 ((from (message-fetch-field "from"))
+             x-faces)
+         (save-current-buffer
+           (when (and wash-face-p
+                      (gnus-buffer-live-p gnus-original-article-buffer)
+                      (not (re-search-forward "^X-Face:[\t ]*" nil t)))
+             ;; If type `W f', use gnus-original-article-buffer,
+             ;; otherwise use the current buffer because displaying
+             ;; RFC822 parts calls this function too.
+             (set-buffer gnus-original-article-buffer))
+           (save-restriction
+             (mail-narrow-to-head)
+             (and gnus-article-x-face-command
+                  (or force
+                      ;; Check whether this face is censored.
+                      (not (and gnus-article-x-face-too-ugly
+                                (or from
+                                    (setq from (message-fetch-field "from")))
+                                (string-match gnus-article-x-face-too-ugly
+                                              from))))
+                  (while (gnus-article-goto-header "X-Face")
+                    (push (mail-header-field-value) x-faces)))))
+         (when x-faces
+           ;; We display the face.
+           (cond ((functionp gnus-article-x-face-command)
+                  ;; The command is a lisp function, so we call it.
+                  (mapc gnus-article-x-face-command x-faces))
+                 ((stringp 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))
+                    (gnus-set-process-query-on-exit-flag
+                     (start-process
+                      "article-x-face" nil shell-file-name
+                      shell-command-switch gnus-article-x-face-command)
+                     nil)
+                    ;; Sending multiple EOFs to xv doesn't work,
+                    ;; so we only do a single external face.
+                    (with-temp-buffer
+                      (insert (car x-faces))
+                      (process-send-region "article-x-face"
+                                           (point-min) (point-max)))
+                    (process-send-eof "article-x-face")))
+                 (t
+                  (error "`%s' set to `%s' is not a function"
+                         gnus-article-x-face-command
+                         'gnus-article-x-face-command)))))))))
+
+(defun article-decode-mime-words ()
+  "Decode all MIME-encoded words in the article."
+  (interactive)
+  (gnus-with-article-buffer
+    (let ((inhibit-point-motion-hooks t)
+         (mail-parse-charset gnus-newsgroup-charset)
+         (mail-parse-ignored-charsets
+          (with-current-buffer gnus-summary-buffer
+            gnus-newsgroup-ignored-charsets)))
+      (mail-decode-encoded-word-region (point-min) (point-max)))))
+
+(defun article-decode-charset (&optional prompt)
+  "Decode charset-encoded text in the article.
+If PROMPT (the prefix), prompt for a coding system to use."
+  (interactive "P")
+  (let ((inhibit-point-motion-hooks t) (case-fold-search t)
+       (inhibit-read-only t)
+       (mail-parse-charset gnus-newsgroup-charset)
+       (mail-parse-ignored-charsets
+        (save-excursion (condition-case nil
+                            (set-buffer gnus-summary-buffer)
+                          (error))
+                        gnus-newsgroup-ignored-charsets))
+       ct cte ctl charset format)
+    (save-excursion
+      (save-restriction
+       (article-narrow-to-head)
+       (setq ct (message-fetch-field "Content-Type" t)
+             cte (message-fetch-field "Content-Transfer-Encoding" t)
+             ctl (and ct (mail-header-parse-content-type ct))
+             charset (cond
+                      (prompt
+                       (mm-read-coding-system "Charset to decode: "))
+                      (ctl
+                       (mail-content-type-get ctl 'charset)))
+             format (and ctl (mail-content-type-get ctl 'format)))
+       (when cte
+         (setq cte (mail-header-strip cte)))
+       (if (and ctl (not (string-match "/" (car ctl))))
+           (setq ctl nil))
+       (goto-char (point-max)))
+      (forward-line 1)
+      (save-restriction
+       (narrow-to-region (point) (point-max))
+       (when (and (eq mail-parse-charset 'gnus-decoded)
+                  (eq (mm-body-7-or-8) '8bit))
+         ;; The text code could have been decoded.
+         (setq charset mail-parse-charset))
+       (when (and (or (not ctl)
+                      (equal (car ctl) "text/plain"))
+                  (not format)) ;; article with format will decode later.
+         (mm-decode-body
+          charset (and cte (intern (downcase
+                                    (gnus-strip-whitespace cte))))
+          (car ctl)))))))
+
+(defun article-decode-encoded-words ()
+  "Remove encoded-word encoding from headers."
+  (let ((inhibit-point-motion-hooks t)
+       (mail-parse-charset gnus-newsgroup-charset)
+       (mail-parse-ignored-charsets
+        (save-excursion (condition-case nil
+                            (set-buffer gnus-summary-buffer)
+                          (error))
+                        gnus-newsgroup-ignored-charsets))
+       (inhibit-read-only t)
+       end start)
+    (goto-char (point-min))
+    (when (search-forward "\n\n" nil 'move)
+      (forward-line -1))
+    (setq end (point))
+    (while (not (bobp))
+      (while (progn
+              (forward-line -1)
+              (and (not (bobp))
+                   (memq (char-after) '(?\t ? )))))
+      (setq start (point))
+      (if (looking-at "\
+\\(?:Resent-\\)?\\(?:From\\|Cc\\|To\\|Bcc\\|\\(?:In-\\)?Reply-To\\|Sender\
+\\|Mail-Followup-To\\|Mail-Copies-To\\|Approved\\):")
+         (funcall gnus-decode-address-function start end)
+       (funcall gnus-decode-header-function start end))
+      (goto-char (setq end start)))))
+
+(defun article-decode-group-name ()
+  "Decode group names in Newsgroups, Followup-To and Xref headers."
+  (let ((inhibit-point-motion-hooks t)
+       (inhibit-read-only t)
+       (method (gnus-find-method-for-group gnus-newsgroup-name))
+       regexp)
+    (when (and (or gnus-group-name-charset-method-alist
+                  gnus-group-name-charset-group-alist)
+              (gnus-buffer-live-p gnus-original-article-buffer))
+      (save-restriction
+       (article-narrow-to-head)
+       (dolist (header '("Newsgroups" "Followup-To" "Xref"))
+         (with-current-buffer gnus-original-article-buffer
+           (goto-char (point-min)))
+         (setq regexp (concat "^" header
+                              ":\\([^\n]*\\(?:\n[\t ]+[^\n]+\\)*\\)\n"))
+         (while (re-search-forward regexp nil t)
+           (replace-match (save-match-data
+                            (gnus-decode-newsgroups
+                             ;; XXX how to use data in article buffer?
+                             (with-current-buffer gnus-original-article-buffer
+                               (re-search-forward regexp nil t)
+                               (match-string 1))
+                             gnus-newsgroup-name method))
+                          t t nil 1))
+         (goto-char (point-min)))))))
+
+(autoload 'idna-to-unicode "idna")
+
+(defun article-decode-idna-rhs ()
+  "Decode IDNA strings in RHS in various headers in current buffer.
+The following headers are decoded: From:, To:, Cc:, Reply-To:,
+Mail-Reply-To: and Mail-Followup-To:."
+  (when gnus-use-idna
+    (save-restriction
+      (let ((inhibit-point-motion-hooks t)
+           (inhibit-read-only t))
+       (article-narrow-to-head)
+       (goto-char (point-min))
+       (while (re-search-forward "@[^ \t\n\r,>]*\\(xn--[-A-Za-z0-9.]*\\)[ \t\n\r,>]" nil t)
+         (let (ace unicode)
+           (when (save-match-data
+                   (and (setq ace (match-string 1))
+                        (save-excursion
+                          (and (re-search-backward "^[^ \t]" nil t)
+                               (looking-at "From\\|To\\|Cc\\|Reply-To\\|Mail-Reply-To\\|Mail-Followup-To")))
+                        (setq unicode (idna-to-unicode ace))))
+             (unless (string= ace unicode)
+               (replace-match unicode nil nil nil 1)))))))))
+
+(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.
+If READ-CHARSET, ask for a coding system."
+  (interactive (list 'force current-prefix-arg))
+  (save-excursion
+    (let ((inhibit-read-only t) type charset)
+      (if (gnus-buffer-live-p gnus-original-article-buffer)
+         (with-current-buffer gnus-original-article-buffer
+           (setq type
+                 (gnus-fetch-field "content-transfer-encoding"))
+           (let* ((ct (gnus-fetch-field "content-type"))
+                  (ctl (and ct (mail-header-parse-content-type ct))))
+             (setq charset (and ctl
+                                (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
+               (and type (let ((case-fold-search t))
+                           (string-match "quoted-printable" type))))
+       (article-goto-body)
+       (quoted-printable-decode-region
+        (point) (point-max) (mm-charset-to-coding-system charset nil t))))))
+
+(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.
+If READ-CHARSET, ask for a coding system."
+  (interactive (list 'force current-prefix-arg))
+  (save-excursion
+    (let ((inhibit-read-only t) type charset)
+      (if (gnus-buffer-live-p gnus-original-article-buffer)
+         (with-current-buffer gnus-original-article-buffer
+           (setq type
+                 (gnus-fetch-field "content-transfer-encoding"))
+           (let* ((ct (gnus-fetch-field "content-type"))
+                  (ctl (and ct (mail-header-parse-content-type ct))))
+             (setq charset (and ctl
+                                (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
+               (and type (let ((case-fold-search t))
+                           (string-match "base64" type))))
+       (article-goto-body)
+       (save-restriction
+         (narrow-to-region (point) (point-max))
+         (base64-decode-region (point-min) (point-max))
+         (mm-decode-coding-region
+          (point-min) (point-max)
+          (mm-charset-to-coding-system charset nil t)))))))
+
+(eval-when-compile
+  (require 'rfc1843))
+
+(defun article-decode-HZ ()
+  "Translate a HZ-encoded article."
+  (interactive)
+  (require 'rfc1843)
+  (save-excursion
+    (let ((inhibit-read-only t))
+      (rfc1843-decode-region (point-min) (point-max)))))
+
+(defun article-unsplit-urls ()
+  "Remove the newlines that some other mailers insert into URLs."
+  (interactive)
+  (save-excursion
+    (let ((inhibit-read-only t))
+      (goto-char (point-min))
+      (while (re-search-forward
+             "\\(\\(https?\\|ftp\\)://\\S-+\\) *\n\\(\\S-+\\)" nil t)
+       (replace-match "\\1\\3" t)))
+    (when (gmm-called-interactively-p 'any)
+      (gnus-treat-article nil))))
+
+(defun article-wash-html ()
+  "Format an HTML article."
+  (interactive)
+  (let ((handles nil)
+       (buffer-read-only nil))
+    (when (gnus-buffer-live-p gnus-original-article-buffer)
+      (with-current-buffer gnus-original-article-buffer
+       (setq handles (mm-dissect-buffer t t))))
+    (article-goto-body)
+    (delete-region (point) (point-max))
+    (mm-enable-multibyte)
+    (mm-inline-text-html handles)))
+
+(defvar gnus-article-browse-html-temp-list nil
+  "List of temporary files created by `gnus-article-browse-html-parts'.
+Internal variable.")
+
+(defcustom gnus-article-browse-delete-temp 'ask
+  "What to do with temporary files from `gnus-article-browse-html-parts'.
+If nil, don't delete temporary files.  If it is t, delete them on
+exit from the summary buffer.  If it is the symbol `file', query
+on each file, if it is `ask' ask once when exiting from the
+summary buffer."
+  :group 'gnus-article
+  :version "23.1" ;; No Gnus
+  :type '(choice (const :tag "Don't delete" nil)
+                (const :tag "Don't ask" t)
+                (const :tag "Ask" ask)
+                (const :tag "Ask for each file" file)))
+
+;; Cf. mm-postponed-undisplay-list / mm-destroy-postponed-undisplay-list.
+
+(defun gnus-article-browse-delete-temp-files (&optional how)
+  "Delete temp-files created by `gnus-article-browse-html-parts'."
+  (when (and gnus-article-browse-html-temp-list
+            (progn
+              (or how (setq how gnus-article-browse-delete-temp))
+              (if (eq how 'ask)
+                  (let ((files (length gnus-article-browse-html-temp-list)))
+                    (or (gnus-y-or-n-p
+                         (if (= files 1)
+                             "Delete the temporary HTML file? "
+                           (format "Delete all %s temporary HTML files? "
+                                   files)))
+                        (setq gnus-article-browse-html-temp-list nil)))
+                how)))
+    (dolist (file gnus-article-browse-html-temp-list)
+      (cond ((file-directory-p file)
+            (when (or (not (eq how 'file))
+                      (gnus-y-or-n-p
+                       (gnus-format-message
+                        "Delete temporary HTML file(s) in directory `%s'? "
+                        (file-name-as-directory file))))
+              (gnus-delete-directory file)))
+           ((file-exists-p file)
+            (when (or (not (eq how 'file))
+                      (gnus-y-or-n-p
+                       (format "Delete temporary HTML file `%s'? " file)))
+              (delete-file file)))))
+    ;; Also remove file from the list when not deleted or if file doesn't
+    ;; exist anymore.
+    (setq gnus-article-browse-html-temp-list nil))
+  gnus-article-browse-html-temp-list)
+
+(defun gnus-article-browse-html-save-cid-content (cid handles directory)
+  "Find CID content in HANDLES and save it in a file in DIRECTORY.
+Return file name relative to the parent of DIRECTORY."
+  (save-match-data
+    (let (file afile)
+      (catch 'found
+       (dolist (handle handles)
+         (cond
+          ((not (listp handle)))
+          ;; Exclude broken handles that `gnus-summary-enter-digest-group'
+          ;; may create.
+          ((not (or (bufferp (car handle)) (stringp (car handle)))))
+          ((equal (mm-handle-media-supertype handle) "multipart")
+           (when (setq file (gnus-article-browse-html-save-cid-content
+                             cid handle directory))
+             (throw 'found file)))
+          ((equal (concat "<" cid ">") (mm-handle-id handle))
+           (setq file (or (mm-handle-filename handle)
+                          (concat
+                           (make-temp-name "cid")
+                           (car (rassoc (car (mm-handle-type handle))
+                                        mailcap-mime-extensions))))
+                 afile (expand-file-name file directory))
+           (mm-save-part-to-file handle afile)
+           (throw 'found (concat (file-name-nondirectory
+                                  (directory-file-name directory))
+                                 "/" file)))))))))
+
+(defun gnus-article-browse-html-parts (list &optional header)
+  "View all \"text/html\" parts from LIST.
+Recurse into multiparts.  The optional HEADER that should be a decoded
+message header will be added to the bodies of the \"text/html\" parts."
+  ;; Internal function used by `gnus-article-browse-html-article'.
+  (let (type file charset content cid-dir tmp-file showed)
+    ;; Find and show the html-parts.
+    (dolist (handle list)
+      ;; If HTML, show it:
+      (cond ((not (listp handle)))
+           ((or (equal (car (setq type (mm-handle-type handle))) "text/html")
+                (and (equal (car type) "message/external-body")
+                     (or header
+                         (setq file (mm-handle-filename handle)))
+                     (or (mm-handle-cache handle)
+                         (condition-case code
+                             (progn (mm-extern-cache-contents handle) t)
+                           (error
+                            (gnus-message 3 "%s" (error-message-string code))
+                            (when (>= gnus-verbose 3) (sit-for 2))
+                            nil)))
+                     (progn
+                       (setq handle (mm-handle-cache handle)
+                             type (mm-handle-type handle))
+                       (equal (car type) "text/html"))))
+            (setq charset (mail-content-type-get type 'charset)
+                  content (mm-get-part handle))
+            (with-temp-buffer
+              (if (eq charset 'gnus-decoded)
+                  (mm-enable-multibyte)
+                (mm-disable-multibyte))
+              (insert content)
+              ;; resolve cid contents
+              (let ((case-fold-search t)
+                    st base regexp cid-file)
+                (goto-char (point-min))
+                (when (and (re-search-forward "<head[\t\n >]" nil t)
+                           (progn
+                             (setq st (match-end 0))
+                             (re-search-forward "</head[\t\n >]" nil t))
+                           (re-search-backward "<base\
+\\(?:[\t\n ]+[^\t\n >]+\\)*[\t\n ]+href=\"\\([^\"]+\\)\"[^>]*>" st t))
+                  (setq base (match-string 1))
+                  (replace-match "<!--\\&-->")
+                  (setq st (point))
+                  (dolist (tag '(("a" . "href") ("form" . "action")
+                                 ("img" . "src")))
+                    (setq regexp (concat "<" (car tag)
+                                         "\\(?:[\t\n ]+[^\t\n >]+\\)*[\t\n ]+"
+                                         (cdr tag) "=\"\\([^\"]+\\)"))
+                    (while (re-search-forward regexp nil t)
+                      (insert (prog1
+                                  (condition-case nil
+                                      (save-match-data
+                                        (url-expand-file-name (match-string 1)
+                                                              base))
+                                    (error (match-string 1)))
+                                (delete-region (match-beginning 1)
+                                               (match-end 1)))))
+                    (goto-char st)))
+                (while (re-search-forward "\
+<img[\t\n ]+\\(?:[^\t\n >]+[\t\n ]+\\)*src=\"\\(cid:\\([^\"]+\\)\\)\""
+                                          nil t)
+                  (unless cid-dir
+                    (setq cid-dir (mm-make-temp-file "cid" t))
+                    (add-to-list 'gnus-article-browse-html-temp-list cid-dir))
+                  (setq file nil
+                        content nil)
+                  (when (setq cid-file
+                              (gnus-article-browse-html-save-cid-content
+                               (match-string 2)
+                               (with-current-buffer gnus-article-buffer
+                                 gnus-article-mime-handles)
+                               cid-dir))
+                    (replace-match cid-file nil nil nil 1))))
+              (unless content (setq content (buffer-string))))
+            (when (or charset header (not file))
+              (setq tmp-file (mm-make-temp-file
+                              ;; Do we need to care for 8.3 filenames?
+                              "mm-" nil ".html")))
+            ;; Add a meta html tag to specify charset and a header.
+            (cond
+             (header
+              (let (title eheader body hcharset coding)
+                (with-temp-buffer
+                  (mm-enable-multibyte)
+                  (setq case-fold-search t)
+                  (insert header "\n")
+                  (setq title (message-fetch-field "subject"))
+                  (goto-char (point-min))
+                  (while (re-search-forward "\\(<\\)\\|\\(>\\)\\|\\(&\\)\\|\n"
+                                            nil t)
+                    (replace-match (cond ((match-beginning 1) "&lt;")
+                                         ((match-beginning 2) "&gt;")
+                                         ((match-beginning 3) "&amp;")
+                                         (t "<br>\n"))))
+                  (goto-char (point-min))
+                  (while (re-search-forward "^[\t ]+" nil t)
+                    (dotimes (i (prog1
+                                    (current-column)
+                                  (delete-region (match-beginning 0)
+                                                 (match-end 0))))
+                      (insert "&nbsp;")))
+                  (goto-char (point-min))
+                  (insert "<div align=\"left\">\n")
+                  (goto-char (point-max))
+                  (insert "</div>\n<hr>\n")
+                  ;; We have to examine charset one by one since
+                  ;; charset specified in parts might be different.
+                  (if (eq charset 'gnus-decoded)
+                      (setq charset 'utf-8
+                            eheader (mm-encode-coding-string (buffer-string)
+                                                             charset)
+                            title (when title
+                                    (mm-encode-coding-string title charset))
+                            body (mm-encode-coding-string content charset))
+                    (setq hcharset (mm-find-mime-charset-region (point-min)
+                                                                (point-max)))
+                    (cond ((= (length hcharset) 1)
+                           (setq hcharset (car hcharset)
+                                 coding (mm-charset-to-coding-system
+                                         hcharset nil t)))
+                          ((> (length hcharset) 1)
+                           (setq hcharset 'utf-8
+                                 coding hcharset)))
+                    (if coding
+                        (if charset
+                            (progn
+                              (setq body
+                                    (mm-charset-to-coding-system charset
+                                                                 nil t))
+                              (if (eq coding body)
+                                  (setq eheader (mm-encode-coding-string
+                                                 (buffer-string) coding)
+                                        title (when title
+                                                (mm-encode-coding-string
+                                                 title coding))
+                                        body content)
+                                (setq charset 'utf-8
+                                      eheader (mm-encode-coding-string
+                                               (buffer-string) charset)
+                                      title (when title
+                                              (mm-encode-coding-string
+                                               title charset))
+                                      body (mm-encode-coding-string
+                                            (mm-decode-coding-string
+                                             content body)
+                                            charset))))
+                          (setq charset hcharset
+                                eheader (mm-encode-coding-string
+                                         (buffer-string) coding)
+                                title (when title
+                                        (mm-encode-coding-string
+                                         title coding))
+                                body content))
+                      (setq eheader (mm-string-as-unibyte (buffer-string))
+                            body content)))
+                  (erase-buffer)
+                  (mm-disable-multibyte)
+                  (insert body)
+                  (when charset
+                    (mm-add-meta-html-tag handle charset t))
+                  (when title
+                    (goto-char (point-min))
+                    (unless (search-forward "<title>" nil t)
+                      (re-search-forward "<head>\\s-*" nil t)
+                      (insert "<title>" title "</title>\n")))
+                  (goto-char (point-min))
+                  (or (re-search-forward
+                       "<body\\(?:\\s-+[^>]+\\|\\s-*\\)>\\s-*" nil t)
+                      (re-search-forward
+                       "</head\\(?:\\s-+[^>]+\\|\\s-*\\)>\\s-*" nil t))
+                  (insert eheader)
+                  (mm-write-region (point-min) (point-max)
+                                   tmp-file nil nil nil 'binary t))))
+             (charset
+              (mm-with-unibyte-buffer
+                (insert (if (eq charset 'gnus-decoded)
+                            (mm-encode-coding-string content
+                                                     (setq charset 'utf-8))
+                          content))
+                (if (or (mm-add-meta-html-tag handle charset)
+                        (not file))
+                    (mm-write-region (point-min) (point-max)
+                                     tmp-file nil nil nil 'binary t)
+                  (setq tmp-file nil))))
+             (tmp-file
+              (mm-save-part-to-file handle tmp-file)))
+            (when tmp-file
+              (add-to-list 'gnus-article-browse-html-temp-list tmp-file))
+            (add-hook 'gnus-summary-prepare-exit-hook
+                      'gnus-article-browse-delete-temp-files)
+            (add-hook 'gnus-exit-gnus-hook
+                      (lambda  ()
+                        (gnus-article-browse-delete-temp-files t)))
+            ;; FIXME: Warn if there's an <img> tag?
+            (browse-url-of-file (or tmp-file (expand-file-name file)))
+            (setq showed t))
+           ;; If multipart, recurse
+           ((equal (mm-handle-media-supertype handle) "multipart")
+            (when (gnus-article-browse-html-parts handle header)
+              (setq showed t)))
+           ((equal (mm-handle-media-type handle) "message/rfc822")
+            (mm-with-multibyte-buffer
+              (mm-insert-part handle)
+              (setq handle (mm-dissect-buffer t t))
+              (when (and (bufferp (car handle))
+                         (stringp (car (mm-handle-type handle))))
+                (setq handle (list handle)))
+              (when header
+                (article-decode-encoded-words)
+                (let ((gnus-visible-headers
+                       (or (get 'gnus-visible-headers 'standard-value)
+                           gnus-visible-headers)))
+                  (article-hide-headers))
+                (goto-char (point-min))
+                (search-forward "\n\n" nil 'move)
+                (skip-chars-backward "\t\n ")
+                (setq header (buffer-substring (point-min) (point)))))
+            (when (prog1
+                      (gnus-article-browse-html-parts handle header)
+                    (mm-destroy-parts handle))
+              (setq showed t)))))
+    showed))
+
+(defun gnus-article-browse-html-article (&optional arg)
+  "View \"text/html\" parts of the current article with a WWW browser.
+Inline images embedded in a message using the cid scheme, as they are
+generally considered to be safe, will be processed properly.
+The message header is added to the beginning of every html part unless
+the prefix argument ARG is given.
+
+Warning: Spammers use links to images (using the http scheme) in HTML
+articles to verify whether you have read the message.  As
+`gnus-article-browse-html-article' passes the HTML content to the
+browser without eliminating these \"web bugs\" you should only
+use it for mails from trusted senders.
+
+If you always want to display HTML parts in the browser, set
+`mm-text-html-renderer' to nil.
+
+This command creates temporary files to pass HTML contents including
+images if any to the browser, and deletes them when exiting the group
+\(if you want)."
+  ;; Cf. `mm-w3m-safe-url-regexp'
+  (interactive "P")
+  (if arg
+      (gnus-summary-show-article)
+    (let ((gnus-visible-headers (or (get 'gnus-visible-headers 'standard-value)
+                                   gnus-visible-headers))
+         ;; As we insert a <hr>, there's no need for the body boundary.
+         (gnus-treat-body-boundary nil))
+      (gnus-summary-show-article)))
+  (with-current-buffer gnus-article-buffer
+    (let ((header (unless arg
+                   (save-restriction
+                     (widen)
+                     (buffer-substring-no-properties
+                      (goto-char (point-min))
+                      (if (search-forward "\n\n" nil t)
+                          (match-beginning 0)
+                        (goto-char (point-max))
+                        (skip-chars-backward "\t\n ")
+                        (point))))))
+         parts)
+      (set-buffer gnus-original-article-buffer)
+      (setq parts (mm-dissect-buffer t t))
+      ;; If singlepart, enforce a list.
+      (when (and (bufferp (car parts))
+                (stringp (car (mm-handle-type parts))))
+       (setq parts (list parts)))
+      ;; Process the list
+      (unless (gnus-article-browse-html-parts parts header)
+       (gnus-error 3 "Mail doesn't contain a \"text/html\" part!"))
+      (mm-destroy-parts parts)
+      (unless arg
+       (gnus-summary-show-article)))))
+
+(defun article-hide-list-identifiers ()
+  "Remove list identifiers from the Subject header.
+The `gnus-list-identifiers' variable specifies what to do."
+  (interactive)
+  (let ((inhibit-point-motion-hooks t)
+        (regexp (gnus-group-get-list-identifiers gnus-newsgroup-name))
+        (inhibit-read-only t))
+    (when regexp
+      (save-excursion
+       (save-restriction
+         (article-narrow-to-head)
+         (goto-char (point-min))
+         (while (re-search-forward
+                 (concat "^Subject: +\\(R[Ee]: +\\)*\\(" regexp " *\\)")
+                 nil t)
+           (delete-region (match-beginning 2) (match-end 0))
+           (beginning-of-line))
+         (when (re-search-forward
+                "^Subject: +\\(\\(R[Ee]: +\\)+\\)R[Ee]: +" nil t)
+           (delete-region (match-beginning 1) (match-end 1))))))))
+
+(defun article-hide-pem (&optional arg)
+  "Toggle hiding of any PEM headers and signatures in the current article.
+If given a negative prefix, always show; if given a positive prefix,
+always hide."
+  (interactive (gnus-article-hidden-arg))
+  (unless (gnus-article-check-hidden-text 'pem arg)
+    (save-excursion
+      (let ((inhibit-read-only t) end)
+       (goto-char (point-min))
+       ;; Hide the horrendously ugly "header".
+       (when (and (search-forward
+                   "\n-----BEGIN PRIVACY-ENHANCED MESSAGE-----\n"
+                   nil t)
+                  (setq end (1+ (match-beginning 0))))
+         (gnus-add-wash-type 'pem)
+         (gnus-article-hide-text-type
+          end
+          (if (search-forward "\n\n" nil t)
+              (match-end 0)
+            (point-max))
+          'pem)
+         ;; Hide the trailer as well
+         (when (search-forward "\n-----END PRIVACY-ENHANCED MESSAGE-----\n"
+                               nil t)
+           (gnus-article-hide-text-type
+            (match-beginning 0) (match-end 0) 'pem)))))))
+
+(defun article-strip-banner ()
+  "Strip the banners specified by the `banner' group parameter and by
+`gnus-article-address-banner-alist'."
+  (interactive)
+  (save-excursion
+    (save-restriction
+      (let ((inhibit-point-motion-hooks t))
+       (when (gnus-parameter-banner gnus-newsgroup-name)
+         (article-really-strip-banner
+          (gnus-parameter-banner gnus-newsgroup-name)))
+       (when gnus-article-address-banner-alist
+         ;; Note that the From header is decoded here, so it is
+         ;; required that the *-extract-address-components function
+         ;; supports non-ASCII text.
+         (let ((from (save-restriction
+                       (widen)
+                       (article-narrow-to-head)
+                       (mail-fetch-field "from"))))
+           (when (and from
+                      (setq from
+                            (cadr (funcall gnus-extract-address-components
+                                           from))))
+             (catch 'found
+               (dolist (pair gnus-article-address-banner-alist)
+                 (when (string-match (car pair) from)
+                   (throw 'found
+                          (article-really-strip-banner (cdr pair)))))))))))))
+
+(defun article-really-strip-banner (banner)
+  "Strip the banner specified by the argument."
+  (save-excursion
+    (save-restriction
+      (let ((inhibit-point-motion-hooks t)
+           (gnus-signature-limit nil)
+           (inhibit-read-only t))
+       (article-goto-body)
+       (cond
+        ((eq banner 'signature)
+         (when (gnus-article-narrow-to-signature)
+           (widen)
+           (forward-line -1)
+           (delete-region (point) (point-max))))
+        ((symbolp banner)
+         (if (setq banner (cdr (assq banner gnus-article-banner-alist)))
+             (while (re-search-forward banner nil t)
+               (delete-region (match-beginning 0) (match-end 0)))))
+        ((stringp banner)
+         (while (re-search-forward banner nil t)
+           (delete-region (match-beginning 0) (match-end 0)))))))))
+
+(defun article-babel ()
+  "Translate article using an online translation service."
+  (interactive)
+  (require 'babel)
+  (gnus-with-article-buffer
+    (when (article-goto-body)
+      (let* ((start (point))
+            (end (point-max))
+            (orig (buffer-substring start end))
+            (trans (babel-as-string orig)))
+       (save-restriction
+         (narrow-to-region start end)
+         (delete-region start end)
+         (insert trans))))))
+
+(defun article-hide-signature (&optional arg)
+  "Hide the signature in the current article.
+If given a negative prefix, always show; if given a positive prefix,
+always hide."
+  (interactive (gnus-article-hidden-arg))
+  (unless (gnus-article-check-hidden-text 'signature arg)
+    (save-excursion
+      (save-restriction
+       (let ((inhibit-read-only t))
+         (when (gnus-article-narrow-to-signature)
+           (gnus-article-hide-text-type
+            (point-min) (point-max) 'signature))))))
+  (gnus-set-mode-line 'article))
+
+(defun article-strip-headers-in-body ()
+  "Strip offensive headers from bodies."
+  (interactive)
+  (save-excursion
+    (article-goto-body)
+    (let ((case-fold-search t))
+      (when (looking-at "x-no-archive:")
+       (gnus-delete-line)))))
+
+(defun article-strip-leading-blank-lines ()
+  "Remove all blank lines from the beginning of the article."
+  (interactive)
+  (save-excursion
+    (let ((inhibit-point-motion-hooks t)
+         (inhibit-read-only t))
+      (when (article-goto-body)
+       (while (and (not (eobp))
+                   (looking-at "[ \t]*$"))
+         (gnus-delete-line))))))
+
+(defun article-narrow-to-head ()
+  "Narrow the buffer to the head of the message.
+Point is left at the beginning of the narrowed-to region."
+  (narrow-to-region
+   (goto-char (point-min))
+   (cond
+    ;; Absolutely no headers displayed.
+    ((looking-at "\n")
+     (point))
+    ;; Normal headers.
+    ((search-forward "\n\n" nil 1)
+     (1- (point)))
+    ;; Nothing but headers.
+    (t
+     (point-max))))
+  (goto-char (point-min)))
+
+(defun article-goto-body ()
+  "Place point at the start of the body."
+  (goto-char (point-min))
+  (cond
+   ;; This variable is only bound when dealing with separate
+   ;; MIME body parts.
+   (article-goto-body-goes-to-point-min-p
+    t)
+   ((search-forward "\n\n" nil t)
+    t)
+   (t
+    (goto-char (point-max))
+    nil)))
+
+(defun article-strip-multiple-blank-lines ()
+  "Replace consecutive blank lines with one empty line."
+  (interactive)
+  (save-excursion
+    (let ((inhibit-point-motion-hooks t)
+         (inhibit-read-only t))
+      ;; First make all blank lines empty.
+      (article-goto-body)
+      (while (re-search-forward "^[ \t]+$" nil t)
+       (unless (gnus-annotation-in-region-p
+                (match-beginning 0) (match-end 0))
+         (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)
+       (unless (gnus-annotation-in-region-p
+                (match-beginning 0) (match-end 0))
+         (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."
+  (interactive)
+  (save-excursion
+    (let ((inhibit-point-motion-hooks t)
+         (inhibit-read-only t))
+      (article-goto-body)
+      (while (re-search-forward "^[ \t]+" nil t)
+       (replace-match "" t t)))))
+
+(defun article-strip-trailing-space ()
+  "Remove all white space from the end of the lines in the article."
+  (interactive)
+  (save-excursion
+    (let ((inhibit-point-motion-hooks t)
+         (inhibit-read-only t))
+      (article-goto-body)
+      (while (re-search-forward "[ \t]+$" nil t)
+       (replace-match "" t t)))))
+
+(defun article-strip-blank-lines ()
+  "Strip leading, trailing and multiple blank lines."
+  (interactive)
+  (article-strip-leading-blank-lines)
+  (article-remove-trailing-blank-lines)
+  (article-strip-multiple-blank-lines))
+
+(defun article-strip-all-blank-lines ()
+  "Strip all blank lines."
+  (interactive)
+  (save-excursion
+    (let ((inhibit-point-motion-hooks t)
+         (inhibit-read-only t))
+      (article-goto-body)
+      (while (re-search-forward "^[ \t]*\n" nil t)
+       (replace-match "" t t)))))
+
+(defun gnus-article-narrow-to-signature ()
+  "Narrow to the signature; return t if a signature is found, else nil."
+  (let ((inhibit-point-motion-hooks t))
+    (when (gnus-article-search-signature)
+      (forward-line 1)
+      ;; Check whether we have some limits to what we consider
+      ;; to be a signature.
+      (let ((limits (if (listp gnus-signature-limit) gnus-signature-limit
+                     (list gnus-signature-limit)))
+           limit limited)
+       (while (setq limit (pop limits))
+         (if (or (and (integerp limit)
+                      (< (- (point-max) (point)) limit))
+                 (and (floatp limit)
+                      (< (count-lines (point) (point-max)) limit))
+                 (and (functionp limit)
+                      (funcall limit))
+                 (and (stringp limit)
+                      (not (re-search-forward limit nil t))))
+             ()                        ; This limit did not succeed.
+           (setq limited t
+                 limits nil)))
+       (unless limited
+         (narrow-to-region (point) (point-max))
+         t)))))
+
+(defun gnus-article-search-signature ()
+  "Search the current buffer for the signature separator.
+Put point at the beginning of the signature separator."
+  (let ((cur (point)))
+    (goto-char (point-max))
+    (if (if (stringp gnus-signature-separator)
+           (re-search-backward gnus-signature-separator nil t)
+         (let ((seps gnus-signature-separator))
+           (while (and seps
+                       (not (re-search-backward (car seps) nil t)))
+             (pop seps))
+           seps))
+       t
+      (goto-char cur)
+      nil)))
+
+(defun gnus-article-hidden-arg ()
+  "Return the current prefix arg as a number, or 0 if no prefix."
+  (list (if current-prefix-arg
+           (prefix-numeric-value current-prefix-arg)
+         0)))
+
+(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
+means show, 0 means toggle."
+  (save-excursion
+    (save-restriction
+      (let ((hide (gnus-article-hidden-text-p type)))
+       (cond
+        ((or (null arg)
+             (> arg 0))
+         nil)
+        ((< arg 0)
+         (gnus-article-show-hidden-text type)
+         t)
+        (t
+         (if (eq hide 'hidden)
+             (progn
+               (gnus-article-show-hidden-text type)
+               t)
+           nil)))))))
+
+(defun gnus-article-hidden-text-p (type)
+  "Say whether the current buffer contains hidden text of type TYPE."
+  (let ((pos (text-property-any (point-min) (point-max) 'article-type type)))
+    (while (and pos
+               (not (get-text-property pos 'invisible))
+               (not (get-text-property pos 'dummy-invisible)))
+      (setq pos
+           (text-property-any (1+ pos) (point-max) 'article-type type)))
+    (if pos
+       'hidden
+      nil)))
+
+(defun gnus-article-show-hidden-text (type &optional _dummy)
+  "Show all hidden text of type TYPE.
+Originally it is hide instead of DUMMY."
+  (let ((inhibit-read-only t)
+       (inhibit-point-motion-hooks t))
+    (gnus-remove-text-properties-when
+     'article-type type
+     (point-min) (point-max)
+     (cons 'article-type (cons type
+                              gnus-hidden-properties)))
+    (gnus-delete-wash-type type)))
+
+(defconst article-time-units
+  `((year . ,(* 365.25 24 60 60))
+    (week . ,(* 7 24 60 60))
+    (day . ,(* 24 60 60))
+    (hour . ,(* 60 60))
+    (minute . 60)
+    (second . 1))
+  "Mapping from time units to seconds.")
+
+(defun gnus-article-forward-header ()
+  "Move point to the start of the next header.
+If the current header is a continuation header, this can be several
+lines forward."
+  (let ((ended nil))
+    (while (not ended)
+      (forward-line 1)
+      (if (looking-at "[ \t]+[^ \t]")
+         (forward-line 1)
+       (setq ended t)))))
+
+(defun article-treat-date ()
+  (article-date-ut (if (gnus-buffer-live-p gnus-summary-buffer)
+                      (with-current-buffer gnus-summary-buffer
+                        gnus-article-date-headers)
+                    gnus-article-date-headers)
+                  t))
+
+(defun article-date-ut (&optional type _highlight date-position)
+  "Convert DATE date to TYPE in the current article.
+The default type is `ut'.  See `gnus-article-date-headers' for
+possible values."
+  (interactive (list 'ut t))
+  (let* ((case-fold-search t)
+        (inhibit-read-only t)
+        (inhibit-point-motion-hooks t)
+        (visible-date (mail-fetch-field "Date"))
+        pos date bface eface)
+    (save-excursion
+      (if date-position
+         (progn
+           (goto-char date-position)
+           (setq date (get-text-property (point) 'original-date))
+           (when (looking-at "[^:]+:[\t ]*")
+             (setq bface (get-text-property (match-beginning 0) 'face)
+                   eface (get-text-property (match-end 0) 'face)))
+           (delete-region (point)
+                          (progn
+                            (gnus-article-forward-header)
+                            (point)))
+           (article-transform-date date type bface eface))
+       (save-restriction
+         (widen)
+         (goto-char (point-min))
+         (while (or (get-text-property (setq pos (point)) 'original-date)
+                    (and (setq pos (next-single-property-change
+                                    (point) 'original-date))
+                         (goto-char pos)))
+           (narrow-to-region pos (if (search-forward "\n\n" nil t)
+                                     (1+ (match-beginning 0))
+                                   (point-max)))
+           (while (setq pos (text-property-not-all pos (point-max)
+                                                   'gnus-date-type nil))
+             (setq date (get-text-property pos 'original-date))
+             (goto-char pos)
+             (when (looking-at "[^:]+:[\t ]*")
+               (setq bface (get-text-property (match-beginning 0) 'face)
+                     eface (get-text-property (match-end 0) 'face)))
+             (delete-region pos (or (text-property-any pos (point-max)
+                                                       'gnus-date-type nil)
+                                    (point-max))))
+           (unless date ;; the 1st time
+             (goto-char (point-min))
+             (while (re-search-forward "^Date:[\t ]*" nil t)
+               (setq date (get-text-property (match-beginning 0)
+                                             'original-date)
+                     bface (get-text-property (match-beginning 0) 'face)
+                     eface (get-text-property (match-end 0) 'face))
+               (delete-region (point-at-bol) (progn
+                                               (gnus-article-forward-header)
+                                               (point)))))
+           (when (and (not date)
+                      visible-date)
+             (setq date visible-date))
+           (when date
+             (article-transform-date date type bface eface))
+           (goto-char (point-max))
+           (widen)))))))
+
+(defun article-transform-date (date type bface eface)
+  (dolist (this-type (cond
+                     ((null type)
+                      (list 'ut))
+                     ((atom type)
+                      (list type))
+                     (t
+                      type)))
+    (goto-char
+     (prog1
+        (point)
+       (add-text-properties
+       (point)
+       (progn
+         (insert (article-make-date-line date (or this-type 'ut)) "\n")
+         (point))
+       (list 'original-date date 'gnus-date-type this-type))))
+    ;; Do highlighting.
+    (when (looking-at
+          "\\([^:]+:\\)[\t ]*\\(\\(?:[^\t\n ]+[\t ]+\\)*[^\t\n ]+\\)?")
+      (put-text-property (match-beginning 1) (match-end 1) 'face bface)
+      (when (match-beginning 2)
+       (put-text-property (match-beginning 2) (match-end 2) 'face eface))
+      (while (and (zerop (forward-line 1))
+                 (looking-at "[\t ]+\\(\\(?:[^\t\n ]+[\t ]+\\)*[^\t\n ]+\\)?"))
+       (when (match-beginning 1)
+         (put-text-property (match-beginning 1) (match-end 1) 'face eface))))))
+
+(defun article-make-date-line (date type)
+  "Return a DATE line of TYPE."
+  (unless (memq type '(local ut original user-defined iso8601 lapsed english
+                            combined-lapsed))
+    (error "Unknown conversion type: %s" type))
+  (condition-case ()
+      (let ((time (ignore-errors (date-to-time date))))
+       (cond
+        ;; Convert to the local timezone.
+        ((eq type 'local)
+         (concat "Date: " (message-make-date time)))
+        ;; Convert to Universal Time.
+        ((eq type 'ut)
+         (concat "Date: "
+                 (substring
+                  (message-make-date
+                   (let* ((e (parse-time-string date))
+                          (tm (apply 'encode-time e))
+                          (ms (car tm))
+                          (ls (- (cadr tm) (car (current-time-zone time)))))
+                     (cond ((< ls 0) (list (1- ms) (+ ls 65536)))
+                           ((> ls 65535) (list (1+ ms) (- ls 65536)))
+                           (t (list ms ls)))))
+                  0 -5)
+                 "UT"))
+        ;; Get the original date from the article.
+        ((eq type 'original)
+         (concat "Date: " (if (string-match "\n+$" date)
+                              (substring date 0 (match-beginning 0))
+                            date)))
+        ;; Let the user define the format.
+        ((eq type 'user-defined)
+         (let ((format (or (condition-case nil
+                               (with-current-buffer gnus-summary-buffer
+                                 gnus-article-time-format)
+                             (error nil))
+                           gnus-article-time-format)))
+           (if (functionp format)
+               (funcall format time)
+             (concat "Date: " (format-time-string format time)))))
+        ;; ISO 8601.
+        ((eq type 'iso8601)
+         (let ((tz (car (current-time-zone time))))
+           (concat
+            "Date: "
+            (format-time-string "%Y%m%dT%H%M%S" time)
+            (format "%s%02d%02d"
+                    (if (> tz 0) "+" "-") (/ (abs tz) 3600)
+                    (/ (% (abs tz) 3600) 60)))))
+        ;; Do a lapsed format.
+        ((eq type 'lapsed)
+         (concat "Date: " (article-lapsed-string time)))
+        ;; A combined date/lapsed format.
+        ((eq type 'combined-lapsed)
+         (let ((date-string (article-make-date-line date 'original))
+               (segments 3)
+               lapsed-string)
+           (while (and
+                    time
+                   (setq lapsed-string
+                         (concat " (" (article-lapsed-string time segments) ")"))
+                   (> (+ (length date-string)
+                         (length lapsed-string))
+                      (+ fill-column 6))
+                   (> segments 0))
+             (setq segments (1- segments)))
+           (if (> segments 0)
+               (concat date-string lapsed-string)
+             date-string)))
+        ;; Display the date in proper English
+        ((eq type 'english)
+         (let ((dtime (decode-time time)))
+           (concat
+            "Date: the "
+            (number-to-string (nth 3 dtime))
+            (let ((digit (% (nth 3 dtime) 10)))
+              (cond
+               ((memq (nth 3 dtime) '(11 12 13)) "th")
+               ((= digit 1) "st")
+               ((= digit 2) "nd")
+               ((= digit 3) "rd")
+               (t "th")))
+            " of "
+            (nth (1- (nth 4 dtime)) gnus-english-month-names)
+            " "
+            (number-to-string (nth 5 dtime))
+            " at "
+            (format "%02d" (nth 2 dtime))
+            ":"
+            (format "%02d" (nth 1 dtime)))))))
+    (foo
+     (format "Date: %s (from Gnus)" date))))
+
+(defun article-lapsed-string (time &optional max-segments)
+  ;; If the date is seriously mangled, the timezone functions are
+  ;; liable to bug out, so we ignore all errors.
+  (let* ((now (current-time))
+        (real-time (subtract-time now time))
+        (real-sec (and real-time
+                       (+ (* (float (car real-time)) 65536)
+                          (cadr real-time))))
+        (sec (and real-time (abs real-sec)))
+        (segments 0)
+        num prev)
+    (unless max-segments
+      (setq max-segments (length article-time-units)))
+    (cond
+     ((null real-time)
+      "Unknown")
+     ((zerop sec)
+      "Now")
+     (t
+      (concat
+       ;; 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.
+       (mapconcat
+       (lambda (unit)
+         (if (or (zerop (setq num (ffloor (/ sec (cdr unit)))))
+                 (>= segments max-segments))
+             ;; The (remaining) seconds are too few to
+             ;; be divided into this time unit.
+             ""
+           ;; It's big enough, so we output it.
+           (setq sec (- sec (* num (cdr unit))))
+           (prog1
+               (concat (if prev ", " "") (int-to-string
+                                          (floor num))
+                       " " (symbol-name (car unit))
+                       (if (> num 1) "s" ""))
+             (setq prev t
+                   segments (1+ segments)))))
+       article-time-units "")
+       ;; If dates are odd, then it might appear like the
+       ;; article was sent in the future.
+       (if (> real-sec 0)
+          " ago"
+        " in the future"))))))
+
+(defun article-date-local (&optional highlight)
+  "Convert the current article date to the local timezone."
+  (interactive (list t))
+  (article-date-ut 'local highlight))
+
+(defun article-date-english (&optional highlight)
+  "Convert the current article date to something that is proper English."
+  (interactive (list t))
+  (article-date-ut 'english highlight))
+
+(defun article-date-original (&optional highlight)
+  "Convert the current article date to what it was originally.
+This is only useful if you have used some other date conversion
+function and want to see what the date was before converting."
+  (interactive (list t))
+  (article-date-ut 'original highlight))
+
+(defun article-date-lapsed (&optional highlight)
+  "Convert the current article date to time lapsed since it was sent."
+  (interactive (list t))
+  (article-date-ut 'lapsed highlight))
+
+(defun article-date-combined-lapsed (&optional highlight)
+  "Convert the current article date to time lapsed since it was sent."
+  (interactive (list t))
+  (article-date-ut 'combined-lapsed highlight))
+
+(defun article-update-date-lapsed ()
+  "Function to be run from a timer to update the lapsed time line."
+  (save-match-data
+    (let ((buffer (current-buffer)))
+      (ignore-errors
+       (walk-windows
+        (lambda (w)
+          (set-buffer (window-buffer w))
+          (when (derived-mode-p 'gnus-article-mode)
+            (let ((old-line (count-lines (point-min) (point)))
+                  (old-column (- (point) (line-beginning-position)))
+                  (window-start (window-start w))
+                  (pos (point-min))
+                  type next end)
+              (while (setq pos (text-property-not-all pos (point-max)
+                                                      'gnus-date-type nil))
+                (setq next (or (next-single-property-change pos
+                                                            'gnus-date-type)
+                               (point-max)))
+                (setq type (get-text-property pos 'gnus-date-type))
+                (when (memq type '(lapsed combined-lapsed user-defined))
+                  (article-date-ut type t pos)
+                  (setq end (or (next-single-property-change pos
+                                                             'gnus-date-type)
+                                (point-max)))
+                  (when window-start
+                    (if (/= window-start next)
+                        (setq window-start nil)
+                      (set-window-start w end)))
+                  (setq next end))
+                (setq pos next))
+              (goto-char (point-min))
+              (when (> old-column 0)
+                (setq old-line (1- old-line)))
+              (forward-line old-line)
+              (end-of-line)
+              (when (> (current-column) old-column)
+                (beginning-of-line)
+                (forward-char old-column)))))
+        nil 'visible))
+      (set-buffer buffer))))
+
+(defun gnus-start-date-timer (&optional n)
+  "Start a timer to update the Date headers in the article buffers.
+The numerical prefix says how frequently (in seconds) the function
+is to run."
+  (interactive "p")
+  (unless n
+    (setq n 1))
+  (gnus-stop-date-timer)
+  (setq article-lapsed-timer
+       (run-at-time 1 n 'article-update-date-lapsed)))
+
+(defun gnus-stop-date-timer ()
+  "Stop the Date timer."
+  (interactive)
+  (when article-lapsed-timer
+    (nnheader-cancel-timer article-lapsed-timer)
+    (setq article-lapsed-timer nil)))
+
+(defun article-date-user (&optional highlight)
+  "Convert the current article date to the user-defined format.
+This format is defined by the `gnus-article-time-format' variable."
+  (interactive (list t))
+  (article-date-ut 'user highlight))
+
+(defun article-date-iso8601 (&optional highlight)
+  "Convert the current article date to ISO8601."
+  (interactive (list t))
+  (article-date-ut 'iso8601 highlight))
+
+(defmacro gnus-article-save-original-date (&rest forms)
+  "Save the original date as a text property and evaluate FORMS."
+  `(let* ((case-fold-search t)
+         (start (progn
+                  (goto-char (point-min))
+                  (when (and (re-search-forward "^date:[\t\n ]+" nil t)
+                             (not (bolp)))
+                    (match-end 0))))
+         (date (when (and start
+                          (re-search-forward "[\t ]*\n\\(?:[^\t ]\\|\\'\\)"
+                                             nil t))
+                 (buffer-substring-no-properties start
+                                                 (match-beginning 0)))))
+     (goto-char (point-max))
+     (skip-chars-backward "\n")
+     (put-text-property (point-min) (point) 'original-date date)
+     ,@forms
+     (goto-char (point-max))
+     (skip-chars-backward "\n")
+     (put-text-property (point-min) (point) 'original-date date)))
+
+;; (defun article-show-all ()
+;;   "Show all hidden text in the article buffer."
+;;   (interactive)
+;;   (save-excursion
+;;     (let ((inhibit-read-only t))
+;;       (gnus-article-unhide-text (point-min) (point-max)))))
+
+(defun article-remove-leading-whitespace ()
+  "Remove excessive whitespace from all headers."
+  (interactive)
+  (save-excursion
+    (save-restriction
+      (let ((inhibit-read-only t))
+       (article-narrow-to-head)
+       (goto-char (point-min))
+       (while (re-search-forward "^[^ :]+: \\([ \t]+\\)" nil t)
+         (delete-region (match-beginning 1) (match-end 1)))))))
+
+(defun article-emphasize (&optional arg)
+  "Emphasize text according to `gnus-emphasis-alist'."
+  (interactive (gnus-article-hidden-arg))
+  (unless (gnus-article-check-hidden-text 'emphasis arg)
+    (save-excursion
+      (let ((alist (or
+                   (condition-case nil
+                       (with-current-buffer gnus-summary-buffer
+                         gnus-article-emphasis-alist)
+                     (error))
+                   gnus-emphasis-alist))
+           (inhibit-read-only t)
+           (props (append '(article-type emphasis)
+                          gnus-hidden-properties))
+           regexp elem beg invisible visible face)
+       (article-goto-body)
+       (setq beg (point))
+       (while (setq elem (pop alist))
+         (goto-char beg)
+         (setq regexp (car elem)
+               invisible (nth 1 elem)
+               visible (nth 2 elem)
+               face (nth 3 elem))
+         (while (re-search-forward regexp nil t)
+           (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."
+  (unless gnus-article-emphasis-alist
+    (let ((name (and gnus-newsgroup-name
+                    (gnus-group-real-name gnus-newsgroup-name))))
+      (make-local-variable 'gnus-article-emphasis-alist)
+      (setq gnus-article-emphasis-alist
+           (nconc
+            (let ((alist gnus-group-highlight-words-alist) elem highlight)
+              (while (setq elem (pop alist))
+                (when (and name (string-match (car elem) name))
+                  (setq alist nil
+                        highlight (copy-sequence (cdr elem)))))
+              highlight)
+            (copy-sequence highlight-words)
+            (if gnus-newsgroup-name
+                (copy-sequence (gnus-group-find-parameter
+                                gnus-newsgroup-name 'highlight-words t)))
+            gnus-emphasis-alist)))))
+
+(defvar gnus-summary-article-menu)
+(defvar gnus-summary-post-menu)
+
+;;; Saving functions.
+
+(defun gnus-article-save (save-buffer file &optional num)
+  "Save the currently selected article."
+  (when (or (get gnus-default-article-saver :headers)
+           (not gnus-save-all-headers))
+    ;; Remove headers according to `gnus-saved-headers' or the value
+    ;; of the `:headers' property that the saver function might have.
+    (let ((gnus-visible-headers
+          (or (symbol-value (get gnus-default-article-saver :headers))
+              gnus-saved-headers gnus-visible-headers))
+         ;; Ignore group parameter.  See `article-hide-headers'.
+         (gnus-summary-buffer nil))
+      (with-current-buffer save-buffer
+       (article-hide-headers 1 t))))
+  (save-window-excursion
+    (if (not gnus-default-article-saver)
+       (error "No default saver is defined")
+      ;; !!! Magic!  The saving functions all save
+      ;; `gnus-save-article-buffer' (or so they think), but we
+      ;; bind that variable to our save-buffer.
+      (set-buffer gnus-article-buffer)
+      (let* ((gnus-save-article-buffer save-buffer)
+            (filename
+             (cond
+              ((not gnus-prompt-before-saving) 'default)
+              ((eq gnus-prompt-before-saving 'always) nil)
+              (t file)))
+            (gnus-number-of-articles-to-be-saved
+             (when (eq gnus-prompt-before-saving t)
+               num)))                  ; Magic
+       (set-buffer gnus-article-current-summary)
+       (funcall gnus-default-article-saver filename)))))
+
+(defun gnus-read-save-file-name (prompt &optional filename
+                                       function group headers variable
+                                       dir-var)
+  (let ((default-name
+         (funcall function group headers (symbol-value variable)))
+       result)
+    (setq result
+         (expand-file-name
+          (cond
+           ((eq filename 'default)
+            default-name)
+           ((eq filename t)
+            default-name)
+           (filename filename)
+           (t
+            (when (symbol-value dir-var)
+              (setq default-name (expand-file-name
+                                  (file-name-nondirectory default-name)
+                                  (symbol-value dir-var))))
+            (let* ((split-name (gnus-get-split-value gnus-split-methods))
+                   (prompt
+                    (format prompt
+                            (if (and gnus-number-of-articles-to-be-saved
+                                     (> gnus-number-of-articles-to-be-saved 1))
+                                (format "these %d articles"
+                                        gnus-number-of-articles-to-be-saved)
+                              "this article")))
+                   (file
+                    ;; Let the split methods have their say.
+                    (cond
+                     ;; No split name was found.
+                     ((null split-name)
+                      (read-file-name
+                       (concat prompt " (default "
+                               (file-name-nondirectory default-name) "): ")
+                       (file-name-directory default-name)
+                       default-name))
+                     ;; A single group name is returned.
+                     ((stringp split-name)
+                      (setq default-name
+                            (funcall function split-name headers
+                                     (symbol-value variable)))
+                      (read-file-name
+                       (concat prompt " (default "
+                               (file-name-nondirectory default-name) "): ")
+                       (file-name-directory default-name)
+                       default-name))
+                     ;; A single split name was found
+                     ((= 1 (length split-name))
+                      (let* ((name (expand-file-name
+                                    (car split-name)
+                                    gnus-article-save-directory))
+                             (dir (cond ((file-directory-p name)
+                                         (file-name-as-directory name))
+                                        ((file-exists-p name) name)
+                                        (t gnus-article-save-directory))))
+                        (read-file-name
+                         (concat prompt " (default " name "): ")
+                         dir name)))
+                     ;; A list of splits was found.
+                     (t
+                      (setq split-name (nreverse split-name))
+                      (let (result)
+                        (let ((file-name-history
+                               (nconc split-name file-name-history)))
+                          (setq result
+                                (expand-file-name
+                                 (read-file-name
+                                  (concat prompt " (`M-p' for defaults): ")
+                                  gnus-article-save-directory
+                                  (car split-name))
+                                 gnus-article-save-directory)))
+                        (car (push result file-name-history)))))))
+              ;; Create the directory.
+              (gnus-make-directory (file-name-directory file))
+              ;; If we have read a directory, we append the default file name.
+              (when (file-directory-p file)
+                (setq file (expand-file-name (file-name-nondirectory
+                                              default-name)
+                                             (file-name-as-directory file))))
+              ;; Possibly translate some characters.
+              (nnheader-translate-file-chars file))))))
+    (gnus-make-directory (file-name-directory result))
+    (when variable
+      (set variable result))
+    (when dir-var
+      (set dir-var (file-name-directory result)))
+    result))
+
+(defun gnus-article-archive-name (_group)
+  "Return the first instance of an \"Archive-name\" in the current buffer."
+  (let ((case-fold-search t))
+    (when (re-search-forward "archive-name: *\\([^ \n\t]+\\)[ \t]*$" nil t)
+      (nnheader-concat gnus-article-save-directory
+                      (match-string 1)))))
+
+(defun gnus-article-nndoc-name (group)
+  "If GROUP is an nndoc group, return the name of the parent group."
+  (when (eq (car (gnus-find-method-for-group group)) 'nndoc)
+    (gnus-group-get-parameter group 'save-article-group)))
+
+(defun gnus-summary-save-in-rmail (&optional filename)
+  "Append this article to Rmail file.
+Optional argument FILENAME specifies file name.
+Directory to save to is default to `gnus-article-save-directory'."
+  (setq filename (gnus-read-save-file-name
+                 "Save %s in rmail file" filename
+                 gnus-rmail-save-name gnus-newsgroup-name
+                 gnus-current-headers 'gnus-newsgroup-last-rmail))
+  (with-current-buffer gnus-save-article-buffer
+    (save-excursion
+      (save-restriction
+       (widen)
+       ;; Note that unlike gnus-summary-save-in-mail, there is no
+       ;; check to see if filename is Babyl.  Rmail in Emacs 23 does
+       ;; not use Babyl.
+       (gnus-output-to-rmail filename))))
+  filename)
+
+(defun gnus-summary-save-in-mail (&optional filename)
+  "Append this article to Unix mail file.
+Optional argument FILENAME specifies file name.
+Directory to save to is default to `gnus-article-save-directory'."
+  (setq filename (gnus-read-save-file-name
+                 "Save %s in Unix mail file" filename
+                 gnus-mail-save-name gnus-newsgroup-name
+                 gnus-current-headers 'gnus-newsgroup-last-mail))
+  (with-current-buffer gnus-save-article-buffer
+    (save-excursion
+      (save-restriction
+       (widen)
+       (if (and (file-readable-p filename)
+                (file-regular-p filename)
+                (mail-file-babyl-p filename))
+           (gnus-output-to-rmail filename)
+         (gnus-output-to-mail filename)))))
+  filename)
+
+(put 'gnus-summary-save-in-file :decode t)
+(put 'gnus-summary-save-in-file :headers 'gnus-saved-headers)
+(defun gnus-summary-save-in-file (&optional filename overwrite)
+  "Append this article to file.
+Optional argument FILENAME specifies file name.
+Directory to save to is default to `gnus-article-save-directory'."
+  (setq filename (gnus-read-save-file-name
+                 "Save %s in file" filename
+                 gnus-file-save-name gnus-newsgroup-name
+                 gnus-current-headers 'gnus-newsgroup-last-file))
+  (with-current-buffer gnus-save-article-buffer
+    (save-excursion
+      (save-restriction
+       (widen)
+       (when (and overwrite
+                  (file-exists-p filename))
+         (delete-file filename))
+       (gnus-output-to-file filename))))
+  filename)
+
+(put 'gnus-summary-write-to-file :decode t)
+(put 'gnus-summary-write-to-file :function 'gnus-summary-save-in-file)
+(put 'gnus-summary-write-to-file :headers 'gnus-saved-headers)
+(defun gnus-summary-write-to-file (&optional filename)
+  "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'."
+  (setq filename (gnus-read-save-file-name
+                 "Save %s in file" filename
+                 gnus-file-save-name gnus-newsgroup-name
+                 gnus-current-headers nil 'gnus-newsgroup-last-directory))
+  (gnus-summary-save-in-file filename t))
+
+(put 'gnus-summary-save-body-in-file :decode t)
+(defun gnus-summary-save-body-in-file (&optional filename overwrite)
+  "Append this article body to a file.
+Optional argument FILENAME specifies file name.
+The directory to save in defaults to `gnus-article-save-directory'."
+  (setq filename (gnus-read-save-file-name
+                 "Save %s body in file" filename
+                 gnus-file-save-name gnus-newsgroup-name
+                 gnus-current-headers 'gnus-newsgroup-last-file))
+  (with-current-buffer gnus-save-article-buffer
+    (save-excursion
+      (save-restriction
+       (widen)
+       (when (article-goto-body)
+         (narrow-to-region (point) (point-max)))
+       (when (and overwrite
+                  (file-exists-p filename))
+         (delete-file filename))
+       (gnus-output-to-file filename))))
+  filename)
+
+(put 'gnus-summary-write-body-to-file :decode t)
+(put 'gnus-summary-write-body-to-file
+     :function 'gnus-summary-save-body-in-file)
+(defun gnus-summary-write-body-to-file (&optional filename)
+  "Write this article body 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'."
+  (setq filename (gnus-read-save-file-name
+                 "Save %s body in file" filename
+                 gnus-file-save-name gnus-newsgroup-name
+                 gnus-current-headers nil 'gnus-newsgroup-last-directory))
+  (gnus-summary-save-body-in-file filename t))
+
+(put 'gnus-summary-save-in-pipe :decode t)
+(put 'gnus-summary-save-in-pipe :headers 'gnus-saved-headers)
+(defun gnus-summary-save-in-pipe (&optional command raw)
+  "Pipe this article to subprocess COMMAND.
+Valid values for COMMAND include:
+  a string
+    The executable command name and possibly arguments.
+  nil
+    You will be prompted for the command in the minibuffer.
+  the symbol `default'
+    It will be replaced with the command which the variable
+    `gnus-summary-pipe-output-default-command' holds or the command
+    last used for saving.
+Non-nil value for RAW overrides `:decode' and `:headers' properties
+and the raw article including all headers will be piped."
+  (let ((article (gnus-summary-article-number))
+       (decode (unless raw
+                 (get 'gnus-summary-save-in-pipe :decode)))
+       save-buffer default)
+    (if article
+       (if (vectorp (gnus-summary-article-header article))
+           (save-current-buffer
+             (gnus-summary-select-article decode decode nil article)
+             (insert-buffer-substring
+              (prog1
+                  (if decode
+                      gnus-article-buffer
+                    gnus-original-article-buffer)
+                (setq save-buffer
+                      (nnheader-set-temp-buffer " *Gnus Save*"))))
+             ;; Remove unwanted headers.
+             (when (and (not raw)
+                        (or (get 'gnus-summary-save-in-pipe :headers)
+                            (not gnus-save-all-headers)))
+               (let ((gnus-visible-headers
+                      (or (symbol-value (get 'gnus-summary-save-in-pipe
+                                             :headers))
+                          gnus-saved-headers gnus-visible-headers))
+                     (gnus-summary-buffer nil))
+                 (article-hide-headers 1 t))))
+         (error "%d is not a real article" article))
+      (error "No article to pipe"))
+    (setq default (or gnus-summary-pipe-output-default-command
+                     gnus-last-shell-command))
+    (unless (stringp command)
+      (setq command
+           (if (and (eq command 'default) default)
+               default
+             (gnus-read-shell-command "Shell command on this article: "
+                                      default))))
+    (when (string-equal command "")
+      (if default
+         (setq command default)
+       (error "A command is required")))
+    (with-current-buffer save-buffer
+      (save-restriction
+       (widen)
+       (shell-command-on-region (point-min) (point-max) command nil)))
+    (gnus-kill-buffer save-buffer))
+  (setq gnus-summary-pipe-output-default-command command))
+
+(defun gnus-summary-pipe-to-muttprint (&optional command)
+  "Pipe this article to muttprint."
+  (unless (stringp command)
+    (setq command (read-string
+                  "Print using command: " gnus-summary-muttprint-program
+                  nil gnus-summary-muttprint-program)))
+  (let ((gnus-summary-pipe-output-default-command
+        gnus-summary-pipe-output-default-command))
+    (gnus-summary-save-in-pipe command))
+  (setq gnus-summary-muttprint-program command))
+
+;;; Article file names when saving.
+
+(defun gnus-capitalize-newsgroup (newsgroup)
+  "Capitalize NEWSGROUP name."
+  (when (not (zerop (length newsgroup)))
+    (concat (char-to-string (upcase (aref newsgroup 0)))
+           (substring newsgroup 1))))
+
+(defun gnus-Numeric-save-name (newsgroup headers &optional last-file)
+  "Generate file name from NEWSGROUP, HEADERS, and optional LAST-FILE.
+If variable `gnus-use-long-file-name' is non-nil, it is ~/News/News.group/num.
+Otherwise, it is like ~/News/news/group/num."
+  (let ((default
+         (expand-file-name
+          (concat (if (gnus-use-long-file-name 'not-save)
+                      (gnus-capitalize-newsgroup newsgroup)
+                    (gnus-newsgroup-directory-form newsgroup))
+                  "/" (int-to-string (mail-header-number headers)))
+          gnus-article-save-directory)))
+    (if (and last-file
+            (string-equal (file-name-directory default)
+                          (file-name-directory last-file))
+            (string-match "^[0-9]+$" (file-name-nondirectory last-file)))
+       default
+      (or last-file default))))
+
+(defun gnus-numeric-save-name (newsgroup headers &optional last-file)
+  "Generate file name from NEWSGROUP, HEADERS, and optional LAST-FILE.
+If variable `gnus-use-long-file-name' is non-nil, it is
+~/News/news.group/num.  Otherwise, it is like ~/News/news/group/num."
+  (let ((default
+         (expand-file-name
+          (concat (if (gnus-use-long-file-name 'not-save)
+                      newsgroup
+                    (gnus-newsgroup-directory-form newsgroup))
+                  "/" (int-to-string (mail-header-number headers)))
+          gnus-article-save-directory)))
+    (if (and last-file
+            (string-equal (file-name-directory default)
+                          (file-name-directory last-file))
+            (string-match "^[0-9]+$" (file-name-nondirectory last-file)))
+       default
+      (or last-file default))))
+
+(defun gnus-plain-save-name (newsgroup _headers &optional last-file)
+  "Generate file name from NEWSGROUP, HEADERS, and optional LAST-FILE.
+If variable `gnus-use-long-file-name' is non-nil, it is
+~/News/news.group.  Otherwise, it is like ~/News/news/group/news."
+  (or last-file
+      (expand-file-name
+       (if (gnus-use-long-file-name 'not-save)
+          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)
+  "Generate file name from sender."
+  (let ((from (mail-header-from headers)))
+    (expand-file-name
+     (if (and from (string-match "\\([^ <]+\\)@" from))
+        (match-string 1 from)
+       "nobody")
+     gnus-article-save-directory)))
+
+(defun article-verify-x-pgp-sig ()
+  "Verify X-PGP-Sig."
+  ;; <ftp://ftp.isc.org/pub/pgpcontrol/FORMAT>
+  (interactive)
+  (if (gnus-buffer-live-p gnus-original-article-buffer)
+      (let ((sig (with-current-buffer gnus-original-article-buffer
+                  (gnus-fetch-field "X-PGP-Sig")))
+           items info headers)
+       (when (and sig
+                  mml2015-use
+                  (mml2015-clear-verify-function))
+         (with-temp-buffer
+           (insert-buffer-substring gnus-original-article-buffer)
+           (setq items (split-string sig))
+           (message-narrow-to-head)
+           (let ((inhibit-point-motion-hooks t)
+                 (case-fold-search t))
+             ;; Don't verify multiple headers.
+             (setq headers (mapconcat (lambda (header)
+                                        (concat header ": "
+                                                (mail-fetch-field header)
+                                                "\n"))
+                                      (split-string (nth 1 items) ",") "")))
+           (delete-region (point-min) (point-max))
+           (insert "-----BEGIN PGP SIGNED MESSAGE-----\n\n")
+           (insert "X-Signed-Headers: " (nth 1 items) "\n")
+           (insert headers)
+           (widen)
+           (forward-line)
+           (while (not (eobp))
+             (if (looking-at "^-")
+                 (insert "- "))
+             (forward-line))
+           (insert "\n-----BEGIN PGP SIGNATURE-----\n")
+           (insert "Version: " (car items) "\n\n")
+           (insert (mapconcat 'identity (cddr items) "\n"))
+           (insert "\n-----END PGP SIGNATURE-----\n")
+           (let ((mm-security-handle (list (format "multipart/signed"))))
+             (mml2015-clean-buffer)
+             (let ((coding-system-for-write (or gnus-newsgroup-charset
+                                                'iso-8859-1)))
+               (funcall (mml2015-clear-verify-function)))
+             (setq info
+                   (or (mm-handle-multipart-ctl-parameter
+                        mm-security-handle 'gnus-details)
+                       (mm-handle-multipart-ctl-parameter
+                        mm-security-handle 'gnus-info)))))
+         (when info
+           (let ((inhibit-read-only t) bface eface)
+             (save-restriction
+               (message-narrow-to-head)
+               (goto-char (point-max))
+               (forward-line -1)
+               (setq bface (get-text-property (point-at-bol) 'face)
+                     eface (get-text-property (1- (point-at-eol)) 'face))
+               (message-remove-header "X-Gnus-PGP-Verify")
+               (if (re-search-forward "^X-PGP-Sig:" nil t)
+                   (forward-line)
+                 (goto-char (point-max)))
+               (narrow-to-region (point) (point))
+               (insert "X-Gnus-PGP-Verify: " info "\n")
+               (goto-char (point-min))
+               (forward-line)
+               (while (not (eobp))
+                 (if (not (looking-at "^[ \t]"))
+                     (insert " "))
+                 (forward-line))
+               ;; Do highlighting.
+               (goto-char (point-min))
+               (when (looking-at "\\([^:]+\\): *")
+                 (put-text-property (match-beginning 1) (1+ (match-end 1))
+                                    'face bface)
+                 (put-text-property (match-end 0) (point-max)
+                                    'face eface)))))))))
+
+(autoload 'canlock-verify "canlock" nil t) ;; for XEmacs.
+
+(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
+  (mapc
+   (lambda (func)
+     (let (afunc gfunc)
+       (if (consp func)
+          (setq afunc (car func)
+                gfunc (cdr func))
+        (setq afunc func
+              gfunc (intern (format "gnus-%s" func))))
+       (defalias gfunc
+        (when (fboundp afunc)
+          `(lambda (&optional interactive &rest args)
+             ,(documentation afunc t)
+             (interactive (list t))
+             (with-current-buffer gnus-article-buffer
+               (if interactive
+                   (call-interactively ',afunc)
+                 (apply ',afunc args))))))))
+   '(article-hide-headers
+     article-verify-x-pgp-sig
+     article-verify-cancel-lock
+     article-hide-boring-headers
+     article-treat-overstrike
+     article-treat-ansi-sequences
+     article-fill-long-lines
+     article-capitalize-sentences
+     article-remove-cr
+     article-remove-leading-whitespace
+     article-display-x-face
+     article-display-face
+     article-de-quoted-unreadable
+     article-de-base64-unreadable
+     article-decode-HZ
+     article-wash-html
+     article-unsplit-urls
+     article-hide-list-identifiers
+     article-strip-banner
+     article-babel
+     article-hide-pem
+     article-hide-signature
+     article-strip-headers-in-body
+     article-remove-trailing-blank-lines
+     article-strip-leading-blank-lines
+     article-strip-multiple-blank-lines
+     article-strip-leading-space
+     article-strip-trailing-space
+     article-strip-blank-lines
+     article-strip-all-blank-lines
+     article-date-local
+     article-date-english
+     article-date-iso8601
+     article-date-original
+     article-treat-date
+     article-date-ut
+     article-decode-mime-words
+     article-decode-charset
+     article-decode-encoded-words
+     article-date-user
+     article-date-lapsed
+     article-date-combined-lapsed
+     article-emphasize
+     article-treat-dumbquotes
+     article-treat-non-ascii
+     article-normalize-headers
+     ;;(article-show-all . gnus-article-show-all-headers)
+     )))
+\f
+;;;
+;;; Gnus article mode
+;;;
+
+(put 'gnus-article-mode 'mode-class 'special)
+
+(set-keymap-parent gnus-article-mode-map widget-keymap)
+
+(gnus-define-keys gnus-article-mode-map
+  " " gnus-article-goto-next-page
+  [?\S-\ ] gnus-article-goto-prev-page
+  "\177" gnus-article-goto-prev-page
+  [delete] gnus-article-goto-prev-page
+  "\C-c^" gnus-article-refer-article
+  "h" gnus-article-show-summary
+  "s" gnus-article-show-summary
+  "\C-c\C-m" gnus-article-mail
+  "?" gnus-article-describe-briefly
+  "<" beginning-of-buffer
+  ">" end-of-buffer
+  "\C-c\C-i" gnus-info-find-node
+  "\C-c\C-b" gnus-bug
+  "R" gnus-article-reply-with-original
+  "F" gnus-article-followup-with-original
+  "\C-hk" gnus-article-describe-key
+  "\C-hc" gnus-article-describe-key-briefly
+  "\C-hb" gnus-article-describe-bindings
+
+  "e" gnus-article-read-summary-keys
+  "\C-d" gnus-article-read-summary-keys
+  "\M-*" gnus-article-read-summary-keys
+  "\M-#" gnus-article-read-summary-keys
+  "\M-^" gnus-article-read-summary-keys
+  "\M-g" gnus-article-read-summary-keys)
+
+(substitute-key-definition
+ 'undefined 'gnus-article-read-summary-keys gnus-article-mode-map)
+
+(defvar gnus-article-send-map)
+
+(gnus-define-keys (gnus-article-send-map "S" gnus-article-mode-map)
+  "W" gnus-article-wide-reply-with-original)
+(if (featurep 'xemacs)
+    (set-keymap-default-binding gnus-article-send-map
+                               'gnus-article-read-summary-send-keys)
+  (define-key gnus-article-send-map [t] 'gnus-article-read-summary-send-keys))
+
+(defun gnus-article-make-menu-bar ()
+  (unless (boundp 'gnus-article-commands-menu)
+    (gnus-summary-make-menu-bar))
+  (unless (boundp 'gnus-article-article-menu)
+    (easy-menu-define
+     gnus-article-article-menu gnus-article-mode-map ""
+     '("Article"
+       ["Scroll forwards" gnus-article-goto-next-page t]
+       ["Scroll backwards" gnus-article-goto-prev-page t]
+       ["Show summary" gnus-article-show-summary t]
+       ["Fetch Message-ID at point" gnus-article-refer-article t]
+       ["Mail to address at point" gnus-article-mail t]
+       ["Send a bug report" gnus-bug t]))
+
+    (easy-menu-define
+     gnus-article-treatment-menu gnus-article-mode-map ""
+     ;; Fixme: this should use :active (and maybe :visible).
+     '("Treatment"
+       ["Hide headers" gnus-article-hide-headers t]
+       ["Hide signature" gnus-article-hide-signature t]
+       ["Hide citation" gnus-article-hide-citation t]
+       ["Treat overstrike" gnus-article-treat-overstrike t]
+       ["Treat ANSI sequences" gnus-article-treat-ansi-sequences t]
+       ["Remove carriage return" gnus-article-remove-cr t]
+       ["Remove leading whitespace" gnus-article-remove-leading-whitespace t]
+       ["Remove quoted-unreadable" gnus-article-de-quoted-unreadable t]
+       ["Remove base64" gnus-article-de-base64-unreadable t]
+       ["Treat html" gnus-article-wash-html t]
+       ["Remove newlines from within URLs" gnus-article-unsplit-urls t]
+       ["Decode HZ" gnus-article-decode-HZ t]))
+
+    ;; 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)))
+
+(defvar bookmark-make-record-function)
+(defvar shr-put-image-function)
+
+(define-derived-mode gnus-article-mode fundamental-mode "Article"
+  "Major mode for displaying an article.
+
+All normal editing commands are switched off.
+
+The following commands are available in addition to all summary mode
+commands:
+\\<gnus-article-mode-map>
+\\[gnus-article-next-page]\t Scroll the article one page forwards
+\\[gnus-article-prev-page]\t Scroll the article one page backwards
+\\[gnus-article-refer-article]\t Go to the article referred to by an article id near point
+\\[gnus-article-show-summary]\t Display the summary buffer
+\\[gnus-article-mail]\t Send a reply to the address near point
+\\[gnus-article-describe-briefly]\t Describe the current mode briefly
+\\[gnus-info-find-node]\t Go to the Gnus info node"
+  (gnus-simplify-mode-line)
+  (make-local-variable 'minor-mode-alist)
+  (when (gnus-visual-p 'article-menu 'menu)
+    (gnus-article-make-menu-bar)
+    (when gnus-summary-tool-bar-map
+      (set (make-local-variable 'tool-bar-map) gnus-summary-tool-bar-map)))
+  (gnus-update-format-specifications nil 'article-mode)
+  (set (make-local-variable 'page-delimiter) gnus-page-delimiter)
+  (set (make-local-variable 'gnus-page-broken) nil)
+  (make-local-variable 'gnus-article-current-summary)
+  (make-local-variable 'gnus-article-mime-handles)
+  (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)
+  (set (make-local-variable 'bookmark-make-record-function)
+       'gnus-summary-bookmark-make-record)
+  ;; Prevent Emacs 22 from displaying non-break space with `nobreak-space'
+  ;; face.
+  (set (make-local-variable 'nobreak-char-display) nil)
+  ;; Enable `gnus-article-remove-images' to delete images shr.el renders.
+  (set (make-local-variable 'shr-put-image-function) 'gnus-shr-put-image)
+  (setq cursor-in-non-selected-windows nil)
+  (gnus-set-default-directory)
+  (buffer-disable-undo)
+  (setq buffer-read-only t
+       show-trailing-whitespace nil)
+  (mm-enable-multibyte))
+
+(defun gnus-article-setup-buffer ()
+  "Initialize the article buffer."
+  (let* ((name (if gnus-single-article-buffer "*Article*"
+                (concat "*Article "
+                        (gnus-group-decoded-name gnus-newsgroup-name)
+                        "*")))
+        (original
+         (progn (string-match "\\*Article" name)
+                (concat " *Original Article"
+                        (substring name (match-end 0))))))
+    (setq gnus-article-buffer name)
+    (setq gnus-original-article-buffer original)
+    (setq gnus-article-mime-handle-alist nil)
+    (with-current-buffer gnus-summary-buffer
+      ;; This might be a variable local to the summary buffer.
+      (unless gnus-single-article-buffer
+       (setq gnus-article-buffer name)
+       (setq gnus-original-article-buffer original)
+       (gnus-set-global-variables)))
+    (gnus-article-setup-highlight-words)
+    ;; Init original article buffer.
+    (with-current-buffer (gnus-get-buffer-create gnus-original-article-buffer)
+      (mm-enable-multibyte)
+      (setq major-mode 'gnus-original-article-mode)
+      (make-local-variable 'gnus-original-article))
+    (if (and (get-buffer name)
+            (with-current-buffer name
+              (if gnus-article-edit-mode
+                  (if (y-or-n-p "Article mode edit in progress; discard? ")
+                      (progn
+                        (set-buffer-modified-p nil)
+                        (gnus-kill-buffer name)
+                        (message "")
+                        nil)
+                    (error "Action aborted"))
+                t)))
+       (let ((summary gnus-summary-buffer))
+         (with-current-buffer name
+           (set (make-local-variable 'gnus-article-edit-mode) nil)
+           (gnus-article-stop-animations)
+           (when gnus-article-mime-handles
+             (mm-destroy-parts gnus-article-mime-handles)
+             (setq gnus-article-mime-handles nil))
+           ;; Set it to nil in article-buffer!
+           (setq gnus-article-mime-handle-alist nil)
+           (buffer-disable-undo)
+           (setq buffer-read-only t)
+           (unless (derived-mode-p 'gnus-article-mode)
+             (gnus-article-mode))
+           (set (make-local-variable 'gnus-summary-buffer) summary)
+           (setq truncate-lines gnus-article-truncate-lines)
+           (current-buffer)))
+      (let ((summary gnus-summary-buffer))
+       (with-current-buffer (gnus-get-buffer-create name)
+         (gnus-article-mode)
+         (setq truncate-lines gnus-article-truncate-lines)
+         (set (make-local-variable 'gnus-summary-buffer) summary)
+         (gnus-summary-set-local-parameters gnus-newsgroup-name)
+         (when article-lapsed-timer
+           (gnus-stop-date-timer))
+         (when gnus-article-update-date-headers
+           (gnus-start-date-timer gnus-article-update-date-headers))
+         (current-buffer))))))
+
+(defun gnus-article-stop-animations ()
+  (dolist (timer (and (boundp 'timer-list)
+                     timer-list))
+    (when (eq (gnus-timer--function timer) 'image-animate-timeout)
+      (cancel-timer timer))))
+
+(defun gnus-stop-downloads ()
+  (when (boundp 'url-queue)
+    (set (intern "url-queue" obarray) nil)))
+
+;; Set article window start at LINE, where LINE is the number of lines
+;; from the head of the article.
+(defun gnus-article-set-window-start (&optional line)
+  (let ((article-window (gnus-get-buffer-window gnus-article-buffer t)))
+    (when article-window
+      (set-window-start
+       article-window
+       (with-current-buffer gnus-article-buffer
+        (goto-char (point-min))
+        (if (not line)
+            (point-min)
+          (gnus-message 6 "Moved to bookmark")
+          (search-forward "\n\n" nil t)
+          (forward-line line)
+          (point)))))))
+
+(defvar gnus-tmp-internal-hook)
+
+(defun gnus-article-prepare (article &optional all-headers _header)
+  "Prepare ARTICLE in article mode buffer.
+ARTICLE should either be an article number or a Message-ID.
+If ARTICLE is an id, HEADER should be the article headers.
+If ALL-HEADERS is non-nil, no headers are hidden."
+  (save-excursion                ;FIXME: Shouldn't that be save-current-buffer?
+    ;; Make sure we start in a summary buffer.
+    (unless (derived-mode-p 'gnus-summary-mode)
+      (set-buffer gnus-summary-buffer))
+    (setq gnus-summary-buffer (current-buffer))
+    (let* ((summary-buffer (current-buffer))
+          (gnus-tmp-internal-hook gnus-article-internal-prepare-hook)
+          (group gnus-newsgroup-name)
+          result)
+      (save-excursion
+       (gnus-article-setup-buffer)
+       (set-buffer gnus-article-buffer)
+       ;; Deactivate active regions.
+       (when (and (boundp 'transient-mark-mode)
+                  transient-mark-mode)
+         (setq mark-active nil))
+       (if (not (setq result (let ((inhibit-read-only t))
+                               (gnus-request-article-this-buffer
+                                article group))))
+           ;; There is no such article.
+           (save-excursion
+             (when (and (numberp article)
+                        (not (memq article gnus-newsgroup-sparse)))
+               (setq gnus-article-current
+                     (cons gnus-newsgroup-name article))
+               (set-buffer gnus-summary-buffer)
+               (setq gnus-current-article article)
+               (if (and (memq article gnus-newsgroup-undownloaded)
+                        (not (gnus-online (gnus-find-method-for-group
+                                           gnus-newsgroup-name))))
+                   (progn
+                     (gnus-summary-set-agent-mark article)
+                     (message "Message marked for downloading"))
+                 (gnus-summary-mark-article article gnus-canceled-mark)
+                 (unless (memq article gnus-newsgroup-sparse)
+                   (gnus-error 1 "No such article (may have expired or been canceled)")))))
+         (if (or (eq result 'pseudo)
+                 (eq result 'nneething))
+             (progn
+               (with-current-buffer summary-buffer
+                 (push article gnus-newsgroup-history)
+                 (setq gnus-last-article gnus-current-article
+                       gnus-current-article 0
+                       gnus-current-headers nil
+                       gnus-article-current nil)
+                 (if (eq result 'nneething)
+                     (gnus-configure-windows 'summary)
+                   (gnus-configure-windows 'article))
+                 (gnus-set-global-variables))
+               (let ((gnus-article-mime-handle-alist-1
+                      gnus-article-mime-handle-alist))
+                 (gnus-set-mode-line 'article)))
+           ;; The result from the `request' was an actual article -
+           ;; or at least some text that is now displayed in the
+           ;; article buffer.
+           (when (and (numberp article)
+                      (not (eq article gnus-current-article)))
+             ;; Seems like a new article has been selected.
+             ;; `gnus-current-article' must be an article number.
+             (with-current-buffer summary-buffer
+               (push article gnus-newsgroup-history)
+               (setq gnus-last-article gnus-current-article
+                     gnus-current-article article
+                     gnus-current-headers
+                     (gnus-summary-article-header gnus-current-article)
+                     gnus-article-current
+                     (cons gnus-newsgroup-name gnus-current-article))
+               (unless (vectorp gnus-current-headers)
+                 (setq gnus-current-headers nil))
+               (gnus-summary-goto-subject gnus-current-article)
+               (when (gnus-summary-show-thread)
+                 ;; If the summary buffer really was folded, the
+                 ;; previous goto may not actually have gone to
+                 ;; the right article, but the thread root instead.
+                 ;; So we go again.
+                 (gnus-summary-goto-subject gnus-current-article))
+               (gnus-run-hooks 'gnus-mark-article-hook)
+               (gnus-set-mode-line 'summary)
+               (when (gnus-visual-p 'article-highlight 'highlight)
+                 (gnus-run-hooks 'gnus-visual-mark-article-hook))
+               ;; Set the global newsgroup variables here.
+               (gnus-set-global-variables)
+               (setq gnus-have-all-headers
+                     (or all-headers gnus-show-all-headers))))
+           (save-excursion
+             (gnus-configure-windows 'article))
+           (when (or (numberp article)
+                     (stringp article))
+             (gnus-article-prepare-display)
+             ;; Do page break.
+             (goto-char (point-min))
+             (when gnus-break-pages
+               (gnus-narrow-to-page)))
+           (let ((gnus-article-mime-handle-alist-1
+                  gnus-article-mime-handle-alist))
+             (gnus-set-mode-line 'article))
+           (article-goto-body)
+           (unless (bobp)
+             (forward-line -1))
+           (set-window-point (get-buffer-window (current-buffer)) (point))
+           (gnus-configure-windows 'article)
+           (gnus-run-hooks 'gnus-article-prepare-hook)
+           t))))))
+
+(defvar gnus-mime-display-attachment-buttons-in-header)
+
+;;;###autoload
+(defun gnus-article-prepare-display ()
+  "Make the current buffer look like a nice article."
+  ;; Hooks for getting information from the article.
+  ;; This hook must be called before being narrowed.
+  (let ((gnus-article-buffer (current-buffer))
+       buffer-read-only
+       (inhibit-read-only t))
+    (unless (derived-mode-p 'gnus-article-mode)
+      (gnus-article-mode))
+    (setq buffer-read-only 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))
+    ;; Add attachment buttons to the header.
+    (when gnus-mime-display-attachment-buttons-in-header
+      (gnus-mime-buttonize-attachments-in-header))))
+
+;;;
+;;; Gnus Sticky Article Mode
+;;;
+
+(define-derived-mode gnus-sticky-article-mode gnus-article-mode "StickyArticle"
+  "Mode for sticky articles."
+  ;; Release bindings that won't work.
+  (substitute-key-definition 'gnus-article-read-summary-keys 'undefined
+                            gnus-sticky-article-mode-map)
+  (substitute-key-definition 'gnus-article-refer-article 'undefined
+                            gnus-sticky-article-mode-map)
+  (dolist (k '("e" "h" "s" "F" "R"))
+    (define-key gnus-sticky-article-mode-map k nil))
+  (define-key gnus-sticky-article-mode-map "k" 'gnus-kill-sticky-article-buffer)
+  (define-key gnus-sticky-article-mode-map "q" 'bury-buffer)
+  (define-key gnus-sticky-article-mode-map "\C-hc" 'describe-key-briefly)
+  (define-key gnus-sticky-article-mode-map "\C-hk" 'describe-key))
+
+(defun gnus-sticky-article (arg)
+  "Make the current article sticky.
+If a prefix ARG is given, ask for a name for this sticky article buffer."
+  (interactive "P")
+  (gnus-summary-show-thread)
+  (gnus-summary-select-article nil nil 'pseudo)
+  (let (new-art-buf-name)
+    (gnus-eval-in-buffer-window gnus-article-buffer
+      (setq new-art-buf-name
+           (concat
+            "*Sticky Article: "
+            (if arg
+                (read-from-minibuffer "Sticky article buffer name: ")
+              (gnus-with-article-headers
+                (gnus-article-goto-header "subject")
+                (setq new-art-buf-name
+                      (buffer-substring-no-properties
+                       (line-beginning-position) (line-end-position)))
+                (goto-char (point-min))
+                (gnus-article-goto-header "from")
+                (setq new-art-buf-name
+                      (concat
+                       new-art-buf-name ", "
+                       (buffer-substring-no-properties
+                        (line-beginning-position) (line-end-position))))
+                (goto-char (point-min))
+                (gnus-article-goto-header "date")
+                (setq new-art-buf-name
+                      (concat
+                       new-art-buf-name ", "
+                       (buffer-substring-no-properties
+                        (line-beginning-position) (line-end-position))))))
+            "*"))
+      (if (and (gnus-buffer-live-p new-art-buf-name)
+              (with-current-buffer new-art-buf-name
+                (derived-mode-p 'gnus-sticky-article-mode)))
+         (switch-to-buffer new-art-buf-name)
+       (setq new-art-buf-name (rename-buffer new-art-buf-name t)))
+      (gnus-sticky-article-mode))
+    (setq gnus-article-buffer new-art-buf-name))
+  (gnus-summary-recenter)
+  (gnus-summary-position-point))
+
+(defun gnus-kill-sticky-article-buffer (&optional buffer)
+  "Kill the given sticky article BUFFER.
+If none is given, assume the current buffer and kill it if it has
+`gnus-sticky-article-mode'."
+  (interactive)
+  (unless buffer
+    (setq buffer (current-buffer)))
+  (with-current-buffer buffer
+    (when (derived-mode-p 'gnus-sticky-article-mode)
+      (gnus-kill-buffer buffer))))
+
+(defun gnus-kill-sticky-article-buffers (arg)
+  "Kill all sticky article buffers.
+If a prefix ARG is given, ask for confirmation."
+  (interactive "P")
+  (dolist (buf (gnus-buffers))
+    (with-current-buffer buf
+      (when (derived-mode-p 'gnus-sticky-article-mode)
+       (if (not arg)
+           (gnus-kill-buffer buf)
+         (when (yes-or-no-p (concat "Kill buffer " (buffer-name buf) "? "))
+           (gnus-kill-buffer buf)))))))
+
+;;;
+;;; Gnus MIME viewing functions
+;;;
+
+(defvar gnus-mime-button-line-format "%{%([%p. %d%T]%)%}%e\n"
+  "Format of the MIME buttons.
+
+Valid specifiers include:
+%t  The MIME type
+%T  MIME type, along with additional info
+%n  The `name' parameter
+%d  The description, if any
+%l  The length of the encoded part
+%p  The part identifier number
+%e  Dots if the part isn't displayed
+
+General format specifiers can also be used.  See Info node
+`(gnus)Formatting Variables'.")
+
+(defvar gnus-tmp-type)
+(defvar gnus-tmp-type-long)
+(defvar gnus-tmp-name)
+(defvar gnus-tmp-description)
+(defvar gnus-tmp-id)
+(defvar gnus-tmp-length)
+(defvar gnus-tmp-dots)
+(defvar gnus-tmp-info)
+(defvar gnus-tmp-pressed-details)
+
+(defvar gnus-mime-button-line-format-alist
+  '((?t gnus-tmp-type ?s)
+    (?T gnus-tmp-type-long ?s)
+    (?n gnus-tmp-name ?s)
+    (?d gnus-tmp-description ?s)
+    (?p gnus-tmp-id ?s)
+    (?l gnus-tmp-length ?d)
+    (?e gnus-tmp-dots ?s)))
+
+(defvar gnus-mime-button-commands
+  '((gnus-article-press-button "\r" "Toggle Display")
+    (gnus-mime-view-part "v" "View Interactively...")
+    (gnus-mime-view-part-as-type "t" "View As Type...")
+    (gnus-mime-view-part-as-charset "C" "View As charset...")
+    (gnus-mime-save-part "o" "Save...")
+    (gnus-mime-save-part-and-strip "\C-o" "Save and Strip")
+    (gnus-mime-replace-part "r" "Replace part")
+    (gnus-mime-delete-part "d" "Delete part")
+    (gnus-mime-copy-part "c" "View As Text, In Other Buffer")
+    (gnus-mime-inline-part "i" "View As Text, In This Buffer")
+    (gnus-mime-view-part-internally "E" "View Internally") ;; Why `E'?
+    (gnus-mime-view-part-externally "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...")))
+
+(defun gnus-article-mime-part-status ()
+  (if gnus-article-mime-handle-alist-1
+      (if (eq 1 (length gnus-article-mime-handle-alist-1))
+         " (1 part)"
+       (format " (%d parts)" (length gnus-article-mime-handle-alist-1)))
+    ""))
+
+(defvar gnus-mime-button-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map gnus-mouse-2 'gnus-article-push-button)
+    (define-key map gnus-down-mouse-3 'gnus-mime-button-menu)
+    (dolist (c gnus-mime-button-commands)
+      (define-key map (cadr c) (car c)))
+    map))
+
+(easy-menu-define
+  gnus-mime-button-menu gnus-mime-button-map "MIME button menu."
+  `("MIME Part"
+    ,@(mapcar (lambda (c)
+               (vector (caddr c) (car c) :active t))
+             gnus-mime-button-commands)))
+
+(defvar gnus-url-button-commands
+  '((gnus-article-copy-string "u" "Copy URL to kill ring")))
+
+(defvar gnus-url-button-map
+  (let ((map (make-sparse-keymap)))
+    (dolist (c gnus-url-button-commands)
+      (define-key map (cadr c) (car c)))
+    map))
+
+(easy-menu-define
+  gnus-url-button-menu gnus-url-button-map "URL button menu."
+  `("Url Button"
+    ,@(mapcar (lambda (c)
+               (vector (caddr c) (car c) :active t))
+             gnus-url-button-commands)))
+
+(defmacro gnus-bind-safe-url-regexp (&rest body)
+  "Bind `mm-w3m-safe-url-regexp' according to `gnus-safe-html-newsgroups'."
+  `(let ((mm-w3m-safe-url-regexp
+         (let ((group (if (and (derived-mode-p 'gnus-article-mode)
+                               (gnus-buffer-live-p
+                                gnus-article-current-summary))
+                          (with-current-buffer gnus-article-current-summary
+                            gnus-newsgroup-name)
+                        gnus-newsgroup-name)))
+           (if (cond ((not group)
+                      ;; Maybe we're in a mml-preview buffer
+                      ;; and no group is selected.
+                      t)
+                     ((stringp gnus-safe-html-newsgroups)
+                      (string-match gnus-safe-html-newsgroups group))
+                     ((consp gnus-safe-html-newsgroups)
+                      (member group gnus-safe-html-newsgroups)))
+               nil
+             mm-w3m-safe-url-regexp))))
+     ,@body))
+
+(defun gnus-mime-button-menu (event prefix)
+ "Construct a context-sensitive menu of MIME commands."
+ (interactive "e\nP")
+ (save-window-excursion
+   (let ((pos (event-start event)))
+     (select-window (posn-window pos))
+     (goto-char (posn-point pos))
+     (gnus-article-check-buffer)
+     (popup-menu gnus-mime-button-menu nil prefix))))
+
+(defun gnus-mime-view-all-parts (&optional handles)
+  "View all the MIME parts."
+  (interactive)
+  (with-current-buffer gnus-article-buffer
+    (let ((handles (or handles gnus-article-mime-handles))
+         (mail-parse-charset gnus-newsgroup-charset)
+         (mail-parse-ignored-charsets
+          (with-current-buffer gnus-summary-buffer
+            gnus-newsgroup-ignored-charsets)))
+      (when handles
+       (mm-remove-parts handles)
+       (goto-char (point-min))
+       (or (search-forward "\n\n") (goto-char (point-max)))
+       (let ((inhibit-read-only t))
+         (delete-region (point) (point-max))
+         (gnus-bind-safe-url-regexp (mm-display-parts handles)))))))
+
+(defun gnus-article-jump-to-part (n)
+  "Jump to MIME part N."
+  (interactive "P")
+  (let ((parts (with-current-buffer gnus-article-buffer
+                (length gnus-article-mime-handle-alist))))
+    (when (zerop parts)
+      (error "No such part"))
+    (pop-to-buffer gnus-article-buffer)
+    (or n
+       (setq n (if (= parts 1)
+                   1
+                 (read-number (format "Jump to part (1..%s): " parts)))))
+    (unless (and (integerp n) (<= n parts) (>= n 1))
+      (setq n
+           (progn
+             (gnus-message 7 "Invalid part `%s', using %s instead."
+                           n parts)
+             parts)))
+    (gnus-message 9 "Jumping to part %s." n)
+    (cond ((>= gnus-auto-select-part 1)
+          (while (and (<= n parts)
+                      (not (gnus-article-goto-part n)))
+            (setq n (1+ n))))
+         ((< gnus-auto-select-part 0)
+          (while (and (>= n 1)
+                      (not (gnus-article-goto-part n)))
+            (setq n (1- n))))
+         (t
+          (gnus-article-goto-part n)))))
+
+(defvar gnus-mime-buttonized-part-id nil
+  "ID of a mime part that should be buttonized.
+`gnus-mime-save-part-and-strip' and `gnus-mime-delete-part' bind it.")
+
+(eval-when-compile
+  (defsubst gnus-article-edit-part (handles &optional current-id)
+    "Edit an article in order to delete a mime part.
+This function is exclusively used by `gnus-mime-save-part-and-strip'
+and `gnus-mime-delete-part', and not provided at run-time normally."
+    (gnus-article-edit-article
+     `(lambda ()
+       (buffer-disable-undo)
+       (let ((mail-parse-charset (or gnus-article-charset
+                                     ',gnus-newsgroup-charset))
+             (mail-parse-ignored-charsets
+              (or gnus-article-ignored-charsets
+                  ',gnus-newsgroup-ignored-charsets))
+             (mbl mml-buffer-list))
+         (setq mml-buffer-list nil)
+         ;; A new text must be inserted before deleting existing ones
+         ;; at the end so as not to move existing markers of which
+         ;; the insertion type is t.
+         (delete-region
+          (point-min)
+          (prog1
+              (goto-char (point-max))
+            (insert-buffer-substring gnus-original-article-buffer)))
+         (mime-to-mml ',handles)
+         (setq gnus-article-mime-handles nil)
+         (let ((mbl1 mml-buffer-list))
+           (setq mml-buffer-list mbl)
+           (set (make-local-variable 'mml-buffer-list) mbl1))
+         (gnus-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
+                                     ',gnus-newsgroup-charset))
+             (message-options message-options)
+             (message-options-set-recipient)
+             (mail-parse-ignored-charsets
+              (or gnus-article-ignored-charsets
+                  ',gnus-newsgroup-ignored-charsets)))
+         (mml-to-mime)
+         (mml-destroy-buffers)
+         (remove-hook 'kill-buffer-hook
+                      'mml-destroy-buffers t)
+         (kill-local-variable 'mml-buffer-list))
+       (gnus-summary-edit-article-done
+        ,(or (mail-header-references gnus-current-headers) "")
+        ,(gnus-group-read-only-p)
+        ,gnus-summary-buffer no-highlight))
+     t)
+    ;; Force buttonizing this part.
+    (let ((gnus-mime-buttonized-part-id current-id))
+      (gnus-article-edit-done))
+    (gnus-configure-windows 'article)
+    (sit-for 0)
+    (when (and current-id (integerp gnus-auto-select-part))
+      (gnus-article-jump-to-part
+       (min (max (+ current-id gnus-auto-select-part) 1)
+           (with-current-buffer gnus-article-buffer
+             (length gnus-article-mime-handle-alist)))))))
+
+(defun gnus-mime-replace-part (file)
+  "Replace MIME part under point with an external body."
+  ;; Useful if file has already been saved to disk
+  (interactive
+   (list
+    (read-file-name "Replace MIME part with file: "
+                    (or mm-default-directory default-directory)
+                    nil nil)))
+  (gnus-mime-save-part-and-strip file))
+
+(defun gnus-mime-save-part-and-strip (&optional file)
+  "Save the MIME part under point then replace it with an external body.
+If FILE is given, use it for the external part."
+  (interactive)
+  (gnus-article-check-buffer)
+  (when (gnus-group-read-only-p)
+    (error "The current group does not support deleting of parts"))
+  (when (mm-complicated-handles gnus-article-mime-handles)
+    (error "\
+The current article has a complicated MIME structure, giving up..."))
+  (let* ((data (get-text-property (point) 'gnus-data))
+        (id (get-text-property (point) 'gnus-part))
+        (handles gnus-article-mime-handles))
+    (unless file
+      (setq file
+           (and data (mm-save-part data "Delete MIME part and save to: "))))
+    (when file
+      (with-current-buffer (mm-handle-buffer data)
+       (erase-buffer)
+       (insert "Content-Type: " (mm-handle-media-type data))
+       (mml-insert-parameter-string (cdr (mm-handle-type data))
+                                    '(charset))
+       ;; Add a filename for the sake of saving the part again.
+       (mml-insert-parameter
+        (mail-header-encode-parameter "name" (file-name-nondirectory file)))
+       (insert "\n")
+       (insert "Content-ID: " (message-make-message-id) "\n")
+       (insert "Content-Transfer-Encoding: binary\n")
+       (insert "\n"))
+      (setcdr data
+             (cdr (mm-make-handle nil
+                                  `("message/external-body"
+                                    (access-type . "LOCAL-FILE")
+                                    (name . ,file)))))
+      ;; (set-buffer gnus-summary-buffer)
+      (gnus-article-edit-part handles id))))
+
+;; A function like `gnus-summary-save-parts' (`X m', `<MIME> <Extract all
+;; parts...>') but with stripping would be nice.
+
+(defun gnus-mime-delete-part ()
+  "Delete the MIME part under point.
+Replace it with some information about the removed part."
+  (interactive)
+  (gnus-article-check-buffer)
+  (when (gnus-group-read-only-p)
+    (error "The current group does not support deleting of parts"))
+  (when (mm-complicated-handles gnus-article-mime-handles)
+    (error "\
+The current article has a complicated MIME structure, giving up..."))
+  (when (or gnus-expert-user
+           (gnus-yes-or-no-p "\
+Deleting parts may malfunction or destroy the article; continue? "))
+    (let* ((data (get-text-property (point) 'gnus-data))
+          (id (get-text-property (point) 'gnus-part))
+          (handles gnus-article-mime-handles)
+          (description
+           (let ((desc (mm-handle-description data)))
+             (when desc
+               (mail-decode-encoded-word-string desc))))
+          (filename (or (mm-handle-filename data) "(none)"))
+          (type (mm-handle-media-type data)))
+      (unless data
+       (error "No MIME part under point"))
+      (with-current-buffer (mm-handle-buffer data)
+       (let ((bsize (buffer-size)))
+         (erase-buffer)
+         (insert
+          (concat
+           ",----\n"
+           "| The following attachment has been deleted:\n"
+           "|\n"
+           "| Type:           " type "\n"
+           "| Filename:       " filename "\n"
+           "| Size (encoded): " (format "%s byte%s\n"
+                                        bsize (if (= bsize 1)
+                                                  ""
+                                                "s"))
+           (when description
+             (concat    "| Description:    " description "\n"))
+           "`----\n"))
+         (setcdr data
+                 (cdr (mm-make-handle
+                       nil `("text/plain" (charset . gnus-decoded)) nil nil
+                       (list "attachment")
+                       (format "Deleted attachment (%s bytes)" bsize))))))
+      ;; (set-buffer gnus-summary-buffer)
+      (gnus-article-edit-part handles id))))
+
+(defun gnus-mime-save-part ()
+  "Save the MIME part under point."
+  (interactive)
+  (gnus-article-check-buffer)
+  (let ((data (get-text-property (point) 'gnus-data)))
+    (when data
+      (mm-save-part data))))
+
+(defun gnus-mime-pipe-part (&optional cmd)
+  "Pipe the MIME part under point to a process.
+Use CMD as the process."
+  (interactive)
+  (gnus-article-check-buffer)
+  (let ((data (get-text-property (point) 'gnus-data)))
+    (when data
+      (mm-pipe-part data cmd))))
+
+(defun gnus-mime-view-part ()
+  "Interactively choose a viewing method for the MIME part under point."
+  (interactive)
+  (gnus-article-check-buffer)
+  (let ((data (get-text-property (point) 'gnus-data)))
+    (when data
+      (setq gnus-article-mime-handles
+           (mm-merge-handles
+            gnus-article-mime-handles (setq data (copy-sequence data))))
+      (mm-interactively-view-part data))))
+
+(defun gnus-mime-view-part-as-type-internal ()
+  (gnus-article-check-buffer)
+  (let* ((handle (get-text-property (point) 'gnus-data))
+        (name (or
+               ;; Content-Type: foo/bar; name=...
+               (mail-content-type-get (mm-handle-type handle) 'name)
+               ;; Content-Disposition: attachment; filename=...
+               (cdr (assq 'filename (cdr (mm-handle-disposition handle))))))
+        (def-type (and name (mm-default-file-encoding name))))
+    (or (and def-type (cons def-type 0))
+       (and handle
+            (equal (mm-handle-media-supertype handle) "text")
+            '("text/plain" . 0))
+       '("application/octet-stream" . 0))))
+
+(defun gnus-mime-view-part-as-type (&optional mime-type pred)
+  "Choose a MIME media type, and view the part as such.
+If non-nil, PRED is a predicate to use during completion to limit the
+available media-types."
+  (interactive)
+  (unless mime-type
+    (setq mime-type
+         (let ((default (gnus-mime-view-part-as-type-internal)))
+           (gnus-completing-read
+            "View as MIME type"
+            (if pred
+                (gnus-remove-if-not pred (mailcap-mime-types))
+              (mailcap-mime-types))
+            nil nil nil
+            (car default)))))
+  (gnus-article-check-buffer)
+  (let ((handle (get-text-property (point) 'gnus-data)))
+    (when handle
+      (when (equal (mm-handle-media-type handle) "message/external-body")
+       (unless (mm-handle-cache handle)
+         (mm-extern-cache-contents handle))
+       (setq handle (mm-handle-cache handle)))
+      (setq handle
+           (mm-make-handle (mm-handle-buffer handle)
+                           (cons mime-type (cdr (mm-handle-type handle)))
+                           (mm-handle-encoding handle)
+                           (mm-handle-undisplayer handle)
+                           (mm-handle-disposition handle)
+                           (mm-handle-description handle)
+                           nil
+                           (mm-handle-id handle)))
+      (setq gnus-article-mime-handles
+           (mm-merge-handles gnus-article-mime-handles handle))
+      (when (mm-handle-displayed-p handle)
+       (mm-remove-part handle))
+      (gnus-mm-display-part handle))))
+
+(defun gnus-mime-copy-part (&optional handle arg)
+  "Put the MIME part under point into a new buffer.
+If `auto-compression-mode' is enabled, compressed files like .gz and .bz2
+are decompressed."
+  (interactive (list nil current-prefix-arg))
+  (gnus-article-check-buffer)
+  (unless handle
+    (setq handle (get-text-property (point) 'gnus-data)))
+  (when handle
+    (let ((filename (mm-handle-filename handle))
+         contents dont-decode charset coding-system)
+      (mm-with-unibyte-buffer
+       (mm-insert-part handle)
+       (setq contents (or (condition-case nil
+                              (mm-decompress-buffer filename nil 'sig)
+                            (error
+                             (setq dont-decode t)
+                             nil))
+                          (buffer-string))))
+      (setq filename (cond (filename (file-name-nondirectory filename))
+                          (dont-decode "*raw data*")
+                          (t "*decoded*")))
+      (cond
+       (dont-decode)
+       ((not arg)
+       (unless (setq charset (mail-content-type-get
+                              (mm-handle-type handle) 'charset))
+         (unless (setq coding-system (mm-with-unibyte-buffer
+                                       (insert contents)
+                                       (mm-find-buffer-file-coding-system)))
+           (setq charset gnus-newsgroup-charset))))
+       ((numberp arg)
+       (setq charset (or (cdr (assq arg
+                                    gnus-summary-show-article-charset-alist))
+                         (mm-read-coding-system "Charset: ")))))
+      (switch-to-buffer (generate-new-buffer filename))
+      (if (or coding-system
+             (and charset
+                  (setq coding-system (mm-charset-to-coding-system
+                                       charset nil t))
+                  (not (eq coding-system 'ascii))))
+         (progn
+           (mm-enable-multibyte)
+           (insert (mm-decode-coding-string contents coding-system))
+           (setq buffer-file-coding-system
+                 (if (boundp 'last-coding-system-used)
+                     (symbol-value 'last-coding-system-used)
+                   coding-system)))
+       (mm-disable-multibyte)
+       (insert contents)
+       (setq buffer-file-coding-system mm-binary-coding-system))
+      ;; We do it this way to make `normal-mode' set the appropriate mode.
+      (unwind-protect
+         (progn
+           (setq buffer-file-name (expand-file-name filename))
+           (normal-mode))
+       (setq buffer-file-name nil))
+      (goto-char (point-min)))))
+
+(defun gnus-mime-print-part (&optional handle filename)
+  "Print the MIME part under point."
+  (interactive (list nil (ps-print-preprint current-prefix-arg)))
+  (gnus-article-check-buffer)
+  (let* ((handle (or handle (get-text-property (point) 'gnus-data)))
+        (contents (and handle (mm-get-part handle)))
+        (file (mm-make-temp-file (expand-file-name "mm." mm-tmp-directory)))
+        (printer (mailcap-mime-info (mm-handle-media-type handle) "print")))
+    (when contents
+       (if printer
+           (unwind-protect
+               (progn
+                 (mm-save-part-to-file handle file)
+                 (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))
+         (ps-despool filename)))))
+
+(defun gnus-mime-inline-part (&optional handle arg)
+  "Insert the MIME part under point into the current buffer.
+Compressed files like .gz and .bz2 are decompressed."
+  (interactive (list nil current-prefix-arg))
+  (gnus-article-check-buffer)
+  (let* ((inhibit-read-only t)
+        (b (point))
+        (btn ;; position where the MIME button exists
+         (if handle
+             (if (eq handle (get-text-property b 'gnus-data))
+                 b
+               (article-goto-body)
+               (or (text-property-any (point) (point-max) 'gnus-data handle)
+                   (text-property-any (point-min) (point) 'gnus-data handle)))
+           (setq handle (get-text-property b 'gnus-data))
+           b))
+        start)
+    (when handle
+      (when (= b (prog1
+                    btn
+                  (setq start (next-single-property-change btn 'gnus-data
+                                                           nil (point-max))
+                        btn (previous-single-property-change start
+                                                             'gnus-data))))
+       (setq b btn))
+      (if (and (not arg) (mm-handle-undisplayer handle))
+         (progn
+           (setq b (copy-marker b)
+                 btn (copy-marker btn))
+           (mm-remove-part handle))
+       (cond
+        ((not arg) nil)
+        ((numberp arg)
+         (if (mm-handle-undisplayer handle)
+             (mm-remove-part handle)))
+        ((mm-handle-undisplayer handle)
+         (mm-remove-part handle)))
+       (goto-char start)
+       (unless (bolp)
+         ;; This is a header button.
+         (forward-line 1))
+       (mm-display-inline handle))
+      ;; Toggle the button appearance between `[button]...' and `[button]'.
+      (when (markerp btn)
+       (setq btn (prog1 (marker-position btn)
+                   (set-marker btn nil))))
+      (goto-char btn)
+      (let ((displayed-p (mm-handle-displayed-p handle)))
+       (gnus-insert-mime-button handle (get-text-property btn 'gnus-part)
+                                (list displayed-p))
+       (if (featurep 'emacs)
+           (delete-region
+            (point)
+            (next-single-property-change (point) 'gnus-data nil (point-max)))
+         (let* ((end (next-single-property-change (point) 'gnus-data))
+                (annots (annotations-at (or end (point-max)))))
+           (delete-region (point)
+                          (if end
+                              (if annots (1+ end) end)
+                            (point-max)))
+           (dolist (annot annots)
+             (set-extent-endpoints annot (point) (point)))))
+       (setq start (point))
+       (if (search-backward "\n\n" nil t)
+           (progn
+             (goto-char start)
+             (unless (or displayed-p (eolp))
+               ;; Add extra newline.
+               (insert (propertize (buffer-substring (1- start) start)
+                                   'gnus-undeletable t))))
+         ;; We're in the article header.
+         (delete-char -1)
+         (dolist (ovl (overlays-in btn (point)))
+           (overlay-put ovl 'gnus-button-attachment-extra t)
+           (overlay-put ovl 'face nil))
+         (save-restriction
+           (message-narrow-to-field)
+           (let ((gnus-treatment-function-alist
+                  '((gnus-treat-highlight-headers
+                     gnus-article-highlight-headers))))
+             (gnus-treat-article 'head)))))
+      (when (markerp b)
+       (setq b (prog1 (marker-position b)
+                 (set-marker b nil))))
+      (goto-char b))))
+
+(defun gnus-mime-set-charset-parameters (handle charset)
+  "Set CHARSET to parameters in HANDLE.
+CHARSET may either be a string or a symbol."
+  (unless (stringp charset)
+    (setq charset (symbol-name charset)))
+  (if (stringp (car handle))
+      (dolist (h (cdr handle))
+       (gnus-mime-set-charset-parameters h charset))
+    (let* ((type (mm-handle-type (if (equal (mm-handle-media-type handle)
+                                           "message/external-body")
+                                    (progn
+                                      (unless (mm-handle-cache handle)
+                                        (mm-extern-cache-contents handle))
+                                      (mm-handle-cache handle))
+                                  handle)))
+          (param (assq 'charset (cdr type))))
+      (if param
+         (setcdr param charset)
+       (setcdr type (cons (cons 'charset charset) (cdr type)))))))
+
+(defun gnus-mime-view-part-as-charset (&optional handle arg)
+  "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)))
+       (fun (get-text-property (point) 'gnus-callback))
+       (gnus-newsgroup-ignored-charsets 'gnus-all)
+       charset form preferred parts)
+    (when handle
+      (when (prog1
+               (and fun
+                    (setq charset
+                          (or (cdr (assq
+                                    arg
+                                    gnus-summary-show-article-charset-alist))
+                              (mm-read-coding-system "Charset: "))))
+             (if (mm-handle-undisplayer handle)
+                 (mm-remove-part handle)))
+       (gnus-mime-set-charset-parameters handle charset)
+       (when (and (consp (setq form (cdr-safe fun)))
+                  (setq form (ignore-errors
+                               (assq 'gnus-mime-display-alternative form)))
+                  (setq preferred (caddr form))
+                  (progn
+                    (when (eq (car preferred) 'quote)
+                      (setq preferred (cadr preferred)))
+                    (not (equal preferred
+                                (get-text-property (point) 'gnus-data))))
+                  (setq parts (get-text-property (point) 'gnus-part))
+                  (setq parts (cdr (assq parts
+                                         gnus-article-mime-handle-alist)))
+                  (equal (mm-handle-media-type parts) "multipart/alternative")
+                  (setq parts (reverse (cdr parts))))
+         (setcar (cddr form)
+                 (list 'quote (or (cadr (member preferred parts))
+                                  (car parts)))))
+       (funcall fun handle)))))
+
+(defun gnus-mime-view-part-externally (&optional handle)
+  "View the MIME part under point with an external viewer."
+  (interactive)
+  (gnus-article-check-buffer)
+  (let* ((handle (or handle (get-text-property (point) 'gnus-data)))
+        (mm-inlined-types nil)
+        (mail-parse-charset gnus-newsgroup-charset)
+        (mail-parse-ignored-charsets
+          (with-current-buffer gnus-summary-buffer
+            gnus-newsgroup-ignored-charsets))
+         (type (mm-handle-media-type handle))
+         (method (mailcap-mime-info type))
+         (mm-enable-external t))
+    (if (not (stringp method))
+       (gnus-mime-view-part-as-type
+        nil (lambda (type) (stringp (mailcap-mime-info type))))
+      (when handle
+       (mm-display-part handle nil t)))))
+
+(defun gnus-mime-view-part-internally (&optional handle)
+  "View the MIME part under point with an internal 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)))
+        (mm-inlined-types '(".*"))
+        (mm-inline-large-images t)
+        (mail-parse-charset gnus-newsgroup-charset)
+        (mail-parse-ignored-charsets
+         (with-current-buffer gnus-summary-buffer
+           gnus-newsgroup-ignored-charsets))
+        (inhibit-read-only t))
+    (if (not (mm-inlinable-p handle))
+        (gnus-mime-view-part-as-type
+         nil (lambda (type) (mm-inlinable-p handle type)))
+      (when handle
+       (gnus-bind-safe-url-regexp
+        (mm-display-part handle nil t))))))
+
+(defun gnus-mime-action-on-part (&optional action)
+  "Do something with the MIME attachment at (point)."
+  (interactive
+   (list (gnus-completing-read "Action" (mapcar 'car gnus-mime-action-alist) t)))
+  (gnus-article-check-buffer)
+  (let ((action-pair (assoc action gnus-mime-action-alist)))
+    (if action-pair
+       (funcall (cdr action-pair)))))
+
+(defun gnus-article-part-wrapper (n function &optional no-handle interactive)
+  "Call FUNCTION on MIME part N.
+Unless NO-HANDLE, call FUNCTION with N-th MIME handle as its only argument.
+If INTERACTIVE, call FUNCTION interactively."
+  (let (window frame)
+    ;; Check whether the article is displayed.
+    (unless (and (gnus-buffer-live-p gnus-article-buffer)
+                (setq window (get-buffer-window gnus-article-buffer t))
+                (frame-visible-p (setq frame (window-frame window))))
+      (error "No article is displayed"))
+    (with-current-buffer gnus-article-buffer
+      ;; Check whether the article displays the right contents.
+      (unless (with-current-buffer gnus-summary-buffer
+               (eq gnus-current-article (gnus-summary-article-number)))
+       (error "You should select the right article first"))
+      (if n
+         (setq n (prefix-numeric-value n))
+       (let ((pt (point)))
+         (setq n (or (get-text-property pt 'gnus-part)
+                     (and (not (bobp))
+                          (get-text-property (1- pt) 'gnus-part))
+                     (get-text-property (prog2
+                                            (forward-line 1)
+                                            (point)
+                                          (goto-char pt))
+                                        'gnus-part)
+                     (get-text-property
+                      (or (and (setq pt (previous-single-property-change
+                                         pt 'gnus-part))
+                               (1- pt))
+                          (next-single-property-change (point) 'gnus-part)
+                          (point))
+                      'gnus-part)
+                     1))))
+      ;; Check whether the specified part exists.
+      (when (> n (length gnus-article-mime-handle-alist))
+       (error "No such part")))
+    (unless
+       (progn
+         ;; To select the window is needed so that the cursor
+         ;; might be visible on the MIME button.
+         (select-window (prog1
+                            window
+                          (setq window (selected-window))
+                          ;; Article may be displayed in the other frame.
+                          (gnus-select-frame-set-input-focus
+                           (prog1
+                               frame
+                             (setq frame (selected-frame))))))
+         (when (gnus-article-goto-part n)
+           ;; We point the cursor and the arrow at the MIME button
+           ;; when the `function' prompt the user for something.
+           (unless (and (pos-visible-in-window-p)
+                        (> (count-lines (point) (window-end))
+                           (/ (1- (window-height)) 3)))
+             (recenter (/ (1- (window-height)) 3)))
+           (let ((cursor-in-non-selected-windows t)
+                 (overlay-arrow-string "=>")
+                 (overlay-arrow-position (point-marker)))
+             (unwind-protect
+                 (cond
+                  ((and no-handle interactive)
+                   (call-interactively function))
+                  (no-handle
+                   (funcall function))
+                  (interactive
+                   (call-interactively
+                    function (get-text-property (point) 'gnus-data)))
+                  (t
+                   (funcall function
+                            (get-text-property (point) 'gnus-data))))
+               (set-marker overlay-arrow-position nil)
+               (unless gnus-auto-select-part
+                 (gnus-select-frame-set-input-focus frame)
+                 (select-window window))))
+           t))
+      (if gnus-inhibit-mime-unbuttonizing
+         ;; This is the default though the program shouldn't reach here.
+         (error "No such part")
+       ;; The part which doesn't have the MIME button is selected.
+       ;; So, we display all the buttons and redo it.
+       (let ((gnus-inhibit-mime-unbuttonizing t))
+         (gnus-summary-show-article)
+         (gnus-article-part-wrapper n function no-handle))))))
+
+(defun gnus-article-pipe-part (n)
+  "Pipe MIME part N, which is the numerical prefix."
+  (interactive "P")
+  (gnus-article-part-wrapper n 'mm-pipe-part))
+
+(defun gnus-article-save-part (n)
+  "Save MIME part N, which is the numerical prefix."
+  (interactive "P")
+  (gnus-article-part-wrapper n 'mm-save-part))
+
+(defun gnus-article-interactively-view-part (n)
+  "View MIME part N interactively, which is the numerical prefix."
+  (interactive "P")
+  (gnus-article-part-wrapper n 'mm-interactively-view-part))
+
+(defun gnus-article-copy-part (n)
+  "Copy MIME part N, which is the numerical prefix."
+  (interactive "P")
+  (gnus-article-part-wrapper n 'gnus-mime-copy-part))
+
+(defun gnus-article-view-part-as-charset (n)
+  "View MIME part N using a specified charset.
+N is the numerical prefix."
+  (interactive "P")
+  (gnus-article-part-wrapper n 'gnus-mime-view-part-as-charset))
+
+(defun gnus-article-view-part-externally (n)
+  "View MIME part N externally, which is the numerical prefix."
+  (interactive "P")
+  (gnus-article-part-wrapper n 'gnus-mime-view-part-externally))
+
+(defun gnus-article-inline-part (n)
+  "Inline MIME part N, which is the numerical prefix."
+  (interactive "P")
+  (gnus-article-part-wrapper n 'gnus-mime-inline-part))
+
+(defun gnus-article-save-part-and-strip (n)
+  "Save MIME part N and replace it with an external body.
+N is the numerical prefix."
+  (interactive "P")
+  (gnus-article-part-wrapper n 'gnus-mime-save-part-and-strip t))
+
+(defun gnus-article-replace-part (n)
+  "Replace MIME part N with an external body.
+N is the numerical prefix."
+  (interactive "P")
+  (gnus-article-part-wrapper n 'gnus-mime-replace-part t t))
+
+(defun gnus-article-delete-part (n)
+  "Delete MIME part N and add some information about the removed part.
+N is the numerical prefix."
+  (interactive "P")
+  (gnus-article-part-wrapper n 'gnus-mime-delete-part t))
+
+(defun gnus-article-view-part-as-type (n)
+  "Choose a MIME media type, and view part N as such.
+N is the numerical prefix."
+  (interactive "P")
+  (gnus-article-part-wrapper n 'gnus-mime-view-part-as-type t))
+
+(defun gnus-article-mime-match-handle-first (condition)
+  (if condition
+      (let (n)
+       (dolist (ihandle gnus-article-mime-handle-alist)
+         (if (and (cond
+                   ((functionp condition)
+                    (funcall condition (cdr ihandle)))
+                   ((eq condition 'undisplayed)
+                    (not (or (mm-handle-undisplayer (cdr ihandle))
+                             (equal (mm-handle-media-type (cdr ihandle))
+                                    "multipart/alternative"))))
+                   ((eq condition 'undisplayed-alternative)
+                    (not (mm-handle-undisplayer (cdr ihandle))))
+                   (t t))
+                  (gnus-article-goto-part (car ihandle))
+                  (or (not n) (< (car ihandle) n)))
+             (setq n (car ihandle))))
+       (or n 1))
+    1))
+
+(defun gnus-article-view-part (&optional n)
+  "View MIME part N, which is the numerical prefix.
+If the part is already shown, hide the part.  If N is nil, view
+all parts."
+  (interactive "P")
+  (with-current-buffer gnus-article-buffer
+    (or (numberp n) (setq n (gnus-article-mime-match-handle-first
+                            gnus-article-mime-match-handle-function)))
+    (when (> n (length gnus-article-mime-handle-alist))
+      (error "No such part"))
+    (let ((handle (cdr (assq n gnus-article-mime-handle-alist))))
+      (when (gnus-article-goto-part n)
+       (if (equal (car handle) "multipart/alternative")
+           (progn
+             (beginning-of-line) ;; Make it toggle subparts
+             (gnus-article-press-button))
+         (when (eq (gnus-mm-display-part handle) 'internal)
+           (gnus-set-window-start)))))))
+
+(defsubst gnus-article-mime-total-parts ()
+  (if (bufferp (car gnus-article-mime-handles))
+      1 ;; single part
+    (1- (length gnus-article-mime-handles))))
+
+(defun gnus-mm-display-part (handle)
+  "Display HANDLE and fix MIME button."
+  (let ((id (get-text-property (point) 'gnus-part))
+       (point (point))
+       (inhibit-read-only t)
+       (window (selected-window))
+       (mail-parse-charset gnus-newsgroup-charset)
+       (mail-parse-ignored-charsets
+        (if (gnus-buffer-live-p gnus-summary-buffer)
+            (with-current-buffer gnus-summary-buffer
+              gnus-newsgroup-ignored-charsets)
+          nil))
+       start retval)
+    (unwind-protect
+       (progn
+         (let ((win (gnus-get-buffer-window (current-buffer) t)))
+           (when win
+             (select-window win)
+             (goto-char point)))
+         (setq start (next-single-property-change point 'gnus-data
+                                                  nil (point-max))
+               point (previous-single-property-change start 'gnus-data))
+         (if (mm-handle-displayed-p handle)
+             ;; This will remove the part.
+             (setq point (copy-marker point)
+                   retval (mm-display-part handle))
+           (let ((part (or (and (mm-inlinable-p handle)
+                                (mm-inlined-p handle)
+                                t)
+                           (with-temp-buffer
+                             (gnus-bind-safe-url-regexp
+                              (setq retval (mm-display-part handle)))
+                             (unless (zerop (buffer-size))
+                               (buffer-string))))))
+             (goto-char start)
+             (unless (bolp)
+               ;; This is a header button.
+               (forward-line 1))
+             (cond ((stringp part)
+                    (save-restriction
+                      (narrow-to-region (point)
+                                        (progn
+                                          (insert part)
+                                          (unless (bolp) (insert "\n"))
+                                          (point)))
+                      (gnus-treat-article nil id
+                                          (gnus-article-mime-total-parts)
+                                          (mm-handle-media-type handle))
+                      (mm-handle-set-undisplayer
+                       handle
+                       `(lambda ()
+                          (let ((inhibit-read-only t))
+                            (delete-region ,(copy-marker (point-min) t)
+                                           ,(point-max-marker)))))))
+                   (part
+                    (mm-display-inline handle))))))
+      (when (markerp point)
+       (setq point (prog1 (marker-position point)
+                     (set-marker point nil))))
+      (goto-char point)
+      ;; Toggle the button appearance between `[button]...' and `[button]'.
+      (let ((displayed-p (mm-handle-displayed-p handle)))
+       (gnus-insert-mime-button handle id (list displayed-p))
+       (if (featurep 'emacs)
+           (delete-region
+            (point)
+            (next-single-property-change (point) 'gnus-data nil (point-max)))
+         (let* ((end (next-single-property-change (point) 'gnus-data))
+                (annots (annotations-at (or end (point-max)))))
+           (delete-region (point)
+                          (if end
+                              (if annots (1+ end) end)
+                            (point-max)))
+           (dolist (annot annots)
+             (set-extent-endpoints annot (point) (point)))))
+       (setq start (point))
+       (if (search-backward "\n\n" nil t)
+           (progn
+             (goto-char start)
+             (unless (or displayed-p (eolp))
+               ;; Add extra newline.
+               (insert (propertize (buffer-substring (1- start) start)
+                                   'gnus-undeletable t))))
+         ;; We're in the article header.
+         (delete-char -1)
+         (dolist (ovl (overlays-in point (point)))
+           (overlay-put ovl 'gnus-button-attachment-extra t)
+           (overlay-put ovl 'face nil))
+         (save-restriction
+           (message-narrow-to-field)
+           (let ((gnus-treatment-function-alist
+                  '((gnus-treat-highlight-headers
+                     gnus-article-highlight-headers))))
+             (gnus-treat-article 'head)))))
+      (goto-char point)
+      (if (window-live-p window)
+         (select-window window)))
+    retval))
+
+(defun gnus-article-goto-part (n)
+  "Go to MIME part N."
+  (when gnus-break-pages
+    (widen))
+  (article-goto-body)
+  (prog1
+      (let ((start (or (text-property-any (point) (point-max) 'gnus-part n)
+                      ;; There may be header buttons.
+                      (text-property-any (point-min) (point) 'gnus-part n)))
+           part handle end next handles)
+       (when start
+         (goto-char start)
+         (if (setq handle (get-text-property start 'gnus-data))
+             start
+           ;; Go to the displayed subpart, assuming this is
+           ;; multipart/alternative.
+           (setq part start
+                 end (point-at-eol))
+           (while (and (not handle)
+                       part
+                       (< part end)
+                       (setq next (text-property-not-all part end
+                                                         'gnus-data nil)))
+             (setq part next
+                   handle (get-text-property part 'gnus-data))
+             (push (cons handle part) handles)
+             (unless (mm-handle-displayed-p handle)
+               (setq handle nil
+                     part (text-property-any part end 'gnus-data nil))))
+           (unless handle
+             ;; No subpart is displayed, so we find preferred one.
+             (setq part
+                   (cdr (assq (mm-preferred-alternative
+                               (nreverse (mapcar 'car handles)))
+                              handles))))
+           (if part
+               (goto-char (1+ part))
+             start))))
+    (when gnus-break-pages
+      (gnus-narrow-to-page))))
+
+(defun gnus-insert-mime-button (handle id &optional displayed)
+  (let ((gnus-tmp-name
+        (or (mm-handle-filename handle)
+            (mail-content-type-get (mm-handle-type handle) 'url)
+            ""))
+        (gnus-tmp-id id)
+       (gnus-tmp-type (mm-handle-media-type handle))
+       (gnus-tmp-description (or (mm-handle-description handle) ""))
+       (gnus-tmp-dots
+        (if (if displayed (car displayed)
+              (mm-handle-displayed-p handle))
+            "" "..."))
+       (gnus-tmp-length (with-current-buffer (mm-handle-buffer handle)
+                          (buffer-size)))
+       gnus-tmp-type-long b e)
+    (when (string-match ".*/" gnus-tmp-name)
+      (setq gnus-tmp-name (replace-match "" t t gnus-tmp-name)))
+    (setq gnus-tmp-type-long (concat gnus-tmp-type
+                                    (and (not (equal gnus-tmp-name ""))
+                                         (concat "; " gnus-tmp-name))))
+    (unless (equal gnus-tmp-description "")
+      (setq gnus-tmp-type-long (concat " --- " gnus-tmp-type-long)))
+    (setq b (point))
+    (gnus-eval-format
+     gnus-mime-button-line-format gnus-mime-button-line-format-alist
+     `(keymap ,gnus-mime-button-map
+             gnus-callback gnus-mm-display-part
+             gnus-part ,gnus-tmp-id
+             article-type annotation
+             gnus-data ,handle
+             rear-nonsticky t))
+    (setq e (if (bolp)
+               ;; Exclude a newline.
+               (1- (point))
+             (point)))
+    (when gnus-article-button-face
+      (overlay-put (make-overlay b e nil t)
+                  'face gnus-article-button-face))
+    (widget-convert-button
+     'link b e
+     :mime-handle handle
+     :action 'gnus-widget-press-button
+     :button-keymap gnus-mime-button-map
+     :help-echo
+     (lambda (widget)
+       ;; Needed to properly clear the message due to a bug in
+       ;; wid-edit (XEmacs only).
+       (if (boundp 'help-echo-owns-message)
+          (setq help-echo-owns-message t))
+       (format
+       "%S: %s the MIME part; %S: more options"
+       (aref gnus-mouse-2 0)
+       (if (mm-handle-displayed-p (widget-get widget :mime-handle))
+           "hide" "show")
+       (aref gnus-down-mouse-3 0))))))
+
+(defun gnus-widget-press-button (elems _el)
+  (goto-char (widget-get elems :from))
+  (gnus-article-press-button))
+
+(defvar gnus-displaying-mime nil)
+
+(defun gnus-display-mime (&optional ihandles)
+  "Display the MIME parts."
+  (save-excursion
+    (save-selected-window
+      (let ((window (get-buffer-window gnus-article-buffer))
+           (point (point)))
+       (when window
+         (select-window window)
+         ;; We have to do this since selecting the window
+         ;; may change the point.  So we set the window point.
+         (set-window-point window point)))
+      (let ((handles ihandles)
+           (inhibit-read-only t))
+       (cond (handles)
+             ((setq handles (mm-dissect-buffer nil gnus-article-loose-mime))
+              (when gnus-article-emulate-mime
+                (mm-uu-dissect-text-parts handles)))
+             (gnus-article-emulate-mime
+              (setq handles (mm-uu-dissect))))
+       (when (and (not ihandles)
+                  (not gnus-displaying-mime))
+         ;; Top-level call; we clean up.
+         (when gnus-article-mime-handles
+           (mm-destroy-parts gnus-article-mime-handles)
+           (setq gnus-article-mime-handle-alist nil));; A trick.
+         (setq gnus-article-mime-handles handles)
+         ;; We allow users to glean info from the handles.
+         (when gnus-article-mime-part-function
+           (gnus-mime-part-function handles)))
+       (if (and handles
+                (or (not (stringp (car handles)))
+                    (cdr handles)))
+           (progn
+             (when (and (not ihandles)
+                        (not gnus-displaying-mime))
+               ;; Clean up for mime parts.
+               (article-goto-body)
+               (delete-region (point) (point-max)))
+             (let ((gnus-displaying-mime t))
+               (gnus-mime-display-part handles)))
+         (save-restriction
+           (article-goto-body)
+           (narrow-to-region (point) (point-max))
+           (gnus-treat-article nil 1 1 "text/plain")
+           (widen)))
+       (unless ihandles
+         ;; Highlight the headers.
+         (save-excursion
+           (save-restriction
+             (article-goto-body)
+             (narrow-to-region (point-min) (point))
+             (gnus-article-save-original-date
+              (gnus-treat-article 'head)))))))
+    ;; Cope with broken MIME messages.
+    (goto-char (point-max))
+    (unless (bolp)
+      (insert "\n"))))
+
+(defcustom gnus-mime-display-multipart-as-mixed nil
+  "Display \"multipart\" parts as  \"multipart/mixed\".
+
+If t, it overrides nil values of
+`gnus-mime-display-multipart-alternative-as-mixed' and
+`gnus-mime-display-multipart-related-as-mixed'."
+  :group 'gnus-article-mime
+  :type 'boolean)
+
+(defcustom gnus-mime-display-multipart-alternative-as-mixed nil
+  "Display \"multipart/alternative\" parts as  \"multipart/mixed\"."
+  :version "22.1"
+  :group 'gnus-article-mime
+  :type 'boolean)
+
+(defcustom gnus-mime-display-multipart-related-as-mixed nil
+  "Display \"multipart/related\" parts as  \"multipart/mixed\".
+
+If displaying \"text/html\" is discouraged \(see
+`mm-discouraged-alternatives') images or other material inside a
+\"multipart/related\" part might be overlooked when this variable is nil."
+  :version "22.1"
+  :group 'gnus-article-mime
+  :type 'boolean)
+
+(defcustom gnus-mime-display-attachment-buttons-in-header t
+  "Add attachment buttons in the end of the header of an article.
+Since MIME attachments tend to be put at the end of an article, we may
+overlook them if there is a huge body.  This option offers you a copy
+of all non-inlinable MIME parts as buttons shown in front of an article.
+If nil, don't show those extra buttons."
+  :version "25.1"
+  :group 'gnus-article-mime
+  :type 'boolean)
+
+(defun gnus-mime-display-part (handle)
+  (cond
+   ;; Maybe a broken MIME message.
+   ((null handle))
+   ;; Single part.
+   ((not (stringp (car handle)))
+    (gnus-mime-display-single handle))
+   ;; User-defined multipart
+   ((cdr (assoc (car handle) gnus-mime-multipart-functions))
+    (funcall (cdr (assoc (car handle) gnus-mime-multipart-functions))
+            handle))
+   ;; multipart/alternative
+   ((and (equal (car handle) "multipart/alternative")
+        (not (or gnus-mime-display-multipart-as-mixed
+                 gnus-mime-display-multipart-alternative-as-mixed)))
+    (let ((id (1+ (length gnus-article-mime-handle-alist))))
+      (push (cons id handle) gnus-article-mime-handle-alist)
+      (gnus-mime-display-alternative (cdr handle) nil nil id)))
+   ;; multipart/related
+   ((and (equal (car handle) "multipart/related")
+        (not (or gnus-mime-display-multipart-as-mixed
+                 gnus-mime-display-multipart-related-as-mixed)))
+    (gnus-mime-display-part (cadr handle)))
+   ((equal (car handle) "multipart/signed")
+    (gnus-add-wash-type 'signed)
+    (gnus-mime-display-security handle))
+   ((equal (car handle) "multipart/encrypted")
+    (gnus-add-wash-type 'encrypted)
+    (gnus-mime-display-security handle))
+   ;; Other multiparts are handled like multipart/mixed.
+   (t
+    (gnus-mime-display-mixed (cdr handle)))))
+
+(defun gnus-mime-part-function (handles)
+  (if (stringp (car handles))
+      (mapcar 'gnus-mime-part-function (cdr handles))
+    (funcall gnus-article-mime-part-function handles)))
+
+(defun gnus-mime-display-mixed (handles)
+  (mapcar 'gnus-mime-display-part handles))
+
+(defun gnus-mime-display-single (handle)
+  (let ((type (mm-handle-media-type handle))
+       (ignored gnus-ignored-mime-types)
+       (not-attachment t)
+       display text)
+    (catch 'ignored
+      (progn
+       (while ignored
+         (when (string-match (pop ignored) type)
+           (throw 'ignored nil)))
+       (if (and (not (and (if (gnus-buffer-live-p gnus-summary-buffer)
+                              (with-current-buffer gnus-summary-buffer
+                                gnus-inhibit-images)
+                            gnus-inhibit-images)
+                          (string-match "\\`image/" type)))
+                (setq not-attachment
+                      (and (not (mm-inline-override-p handle))
+                           (or (not (mm-handle-disposition handle))
+                               (equal (car (mm-handle-disposition handle))
+                                      "inline")
+                               (mm-attachment-override-p handle))))
+                (mm-automatic-display-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")
+           (setq text t)))
+       (let ((id (car (rassq handle gnus-article-mime-handle-alist)))
+             beg)
+         (unless id
+           (setq id (1+ (length gnus-article-mime-handle-alist)))
+           (push (cons id handle) gnus-article-mime-handle-alist))
+         (when (and display
+                    (equal (mm-handle-media-supertype handle) "message"))
+           (insert-char
+            ?\n
+            (cond ((not (bolp)) 2)
+                  ((or (bobp) (eq (char-before (1- (point))) ?\n)) 0)
+                  (t 1))))
+         (when (or (not display)
+                   (not (gnus-unbuttonized-mime-type-p type))
+                   (eq id gnus-mime-buttonized-part-id))
+           (gnus-insert-mime-button
+            handle id (list (or display (and not-attachment text)))))
+         (setq beg (point))
+         (cond
+          (display
+           (let ((mail-parse-charset gnus-newsgroup-charset)
+                 (mail-parse-ignored-charsets
+                  (save-excursion (condition-case ()
+                                      (set-buffer gnus-summary-buffer)
+                                    (error))
+                                  gnus-newsgroup-ignored-charsets)))
+             (gnus-bind-safe-url-regexp (mm-display-part handle t))))
+          ((and text not-attachment)
+           (mm-display-inline handle)))
+         (goto-char (point-max))
+         (if (string-match "\\`image/" type)
+             (gnus-article-insert-newline)
+           (if (prog1
+                   (= (skip-chars-backward "\n") -1)
+                 (unless (eobp) (forward-char 1)))
+               (gnus-article-insert-newline)
+             (put-text-property (point) (point-max) 'gnus-undeletable t))
+           (goto-char (point-max)))
+         ;; Do highlighting.
+         (save-excursion
+           (save-restriction
+             (narrow-to-region beg (point))
+             (if (eq handle gnus-article-mime-handles)
+                 ;; The format=flowed case.
+                 (gnus-treat-article nil 1 1 (mm-handle-media-type handle))
+               ;; Don't count signature parts that are never displayed.
+               ;; The part number should be re-calculated supposing this
+               ;; might be a message/rfc822 part.
+               (let (handles)
+                 (dolist (part gnus-article-mime-handles)
+                   (unless (or (stringp part)
+                               (equal (car (mm-handle-type part))
+                                      "application/pgp-signature"))
+                     (push part handles)))
+                 (gnus-treat-article
+                  nil (length (memq handle handles)) (length handles)
+                  (mm-handle-media-type handle)))))))))))
+
+(defun gnus-unbuttonized-mime-type-p (type)
+  "Say whether TYPE is to be unbuttonized."
+  (unless gnus-inhibit-mime-unbuttonizing
+    (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."
+  (gnus-put-text-property
+   (point) (progn (insert "\n") (point)) 'gnus-undeletable t))
+
+(defun gnus-mime-display-alternative (handles &optional preferred ibegend id)
+  (let* ((preferred (or preferred (mm-preferred-alternative handles)))
+        (ihandles handles)
+        (point (point))
+        handle (inhibit-read-only t) from begend not-pref)
+    (save-window-excursion
+      (save-restriction
+       (when ibegend
+         (narrow-to-region (car ibegend)
+                           (or (cdr ibegend)
+                               (progn
+                                 (goto-char (car ibegend))
+                                 (forward-line 2)
+                                 (point))))
+         (delete-region (point-min) (point-max))
+         (mm-remove-parts handles))
+       (setq begend (list (point-marker)))
+       ;; Do the toggle.
+       (unless (setq not-pref (cadr (member preferred ihandles)))
+         (setq not-pref (car ihandles)))
+       (when (or ibegend
+                 (not preferred)
+                 (not (gnus-unbuttonized-mime-type-p
+                       "multipart/alternative")))
+         (gnus-add-text-properties
+          (setq from (point))
+          (progn
+            (insert (format "%d.  " id))
+            (point))
+          `(gnus-callback
+            (lambda (handles)
+              (unless ,(not ibegend)
+                (setq gnus-article-mime-handle-alist
+                      ',gnus-article-mime-handle-alist))
+              (gnus-mime-display-alternative
+               ',ihandles ',not-pref ',begend ,id))
+            keymap ,gnus-mime-button-map
+            ,gnus-mouse-face-prop ,gnus-article-mouse-face
+            face ,gnus-article-button-face
+            gnus-part ,id
+            article-type multipart
+            rear-nonsticky t))
+         (widget-convert-button 'link from (point)
+                                :action 'gnus-widget-press-button
+                                :button-keymap gnus-widget-button-keymap)
+         ;; Do the handles
+         (while (setq handle (pop handles))
+           (gnus-add-text-properties
+            (setq from (point))
+            (progn
+              (insert (format "(%c) %-18s"
+                              (if (equal handle preferred) ?* ? )
+                              (mm-handle-media-type handle)))
+              (point))
+            `(gnus-callback
+              (lambda (handles)
+                (unless ,(not ibegend)
+                  (setq gnus-article-mime-handle-alist
+                        ',gnus-article-mime-handle-alist))
+                (gnus-mime-display-alternative
+                 ',ihandles ',handle ',begend ,id))
+              keymap ,gnus-mime-button-map
+              ,gnus-mouse-face-prop ,gnus-article-mouse-face
+              face ,gnus-article-button-face
+              gnus-part ,id
+              gnus-data ,handle
+              rear-nonsticky t))
+           (widget-convert-button 'link from (point)
+                                  :action 'gnus-widget-press-button
+                                  :button-keymap gnus-widget-button-keymap)
+           (insert "  "))
+         (insert "\n\n"))
+       (when preferred
+         (if (stringp (car preferred))
+             (gnus-display-mime preferred)
+           (let ((mail-parse-charset gnus-newsgroup-charset)
+                 (mail-parse-ignored-charsets
+                  (with-current-buffer gnus-summary-buffer
+                    gnus-newsgroup-ignored-charsets)))
+             (gnus-bind-safe-url-regexp (mm-display-part preferred))
+             ;; Do highlighting.
+             (save-excursion
+               (save-restriction
+                 (narrow-to-region (car begend) (point-max))
+                 (gnus-treat-article
+                  nil (length gnus-article-mime-handle-alist)
+                  (gnus-article-mime-total-parts)
+                  (mm-handle-media-type preferred))))))
+         (goto-char (point-max))
+         (setcdr begend (point-marker)))))
+    (when ibegend
+      (goto-char point)))
+  ;; Redraw attachment buttons in the header.
+  (when gnus-mime-display-attachment-buttons-in-header
+    (gnus-mime-buttonize-attachments-in-header)))
+
+(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."
+  (with-current-buffer gnus-article-buffer
+    (let ((cite (memq 'cite gnus-article-wash-types))
+         (headers (memq 'headers gnus-article-wash-types))
+         (boring (memq 'boring-headers gnus-article-wash-types))
+         (pgp (memq 'pgp gnus-article-wash-types))
+         (pem (memq 'pem gnus-article-wash-types))
+         (signed (memq 'signed gnus-article-wash-types))
+         (encrypted (memq 'encrypted gnus-article-wash-types))
+         (signature (memq 'signature gnus-article-wash-types))
+         (overstrike (memq 'overstrike gnus-article-wash-types))
+         (emphasis (memq 'emphasis gnus-article-wash-types)))
+      (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."
+  (add-to-list 'gnus-article-wash-types type))
+
+(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 category))
+    (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)
+
+(defun gnus-article-maybe-hide-headers ()
+  "Hide unwanted headers if `gnus-have-all-headers' is nil.
+Provided for backwards compatibility."
+  (when (and (or (not (gnus-buffer-live-p gnus-summary-buffer))
+                (not (with-current-buffer gnus-summary-buffer
+                       gnus-have-all-headers)))
+            (not gnus-inhibit-hiding))
+    (gnus-article-hide-headers)))
+
+(declare-function shr-put-image "shr" (data alt &optional flags))
+
+(defun gnus-shr-put-image (data alt &optional flags)
+  "Put image DATA with a string ALT.  Enable image to be deleted."
+  (let ((image (if flags
+                  (shr-put-image data (propertize (or alt "*")
+                                                  'gnus-image-category 'shr)
+                                 flags)
+                ;; Old `shr-put-image' doesn't take the optional `flags'
+                ;; argument.
+                (shr-put-image data (propertize (or alt "*")
+                                                'gnus-image-category 'shr)))))
+    (when image
+      (gnus-add-image 'shr image))))
+
+(defun gnus-article-mime-handles (&optional alist id all)
+  (if alist
+      (let ((i 1) newid flat)
+       (dolist (handle alist flat)
+         (setq newid (append id (list i))
+               i (1+ i))
+         (if (stringp (car handle))
+             (setq flat (nconc flat (gnus-article-mime-handles
+                                     (cdr handle) newid all)))
+           (delq (rassq handle all) all)
+           (setq flat (nconc flat (list (cons newid handle)))))))
+    (let ((flat (list nil)))
+      ;; Assume that elements of `gnus-article-mime-handle-alist'
+      ;; are in the decreasing order, but unnumbered subsidiaries
+      ;; in each element are in the increasing order.
+      (dolist (handle (reverse gnus-article-mime-handle-alist))
+       (if (stringp (cadr handle))
+           (setq flat (nconc flat (gnus-article-mime-handles
+                                   (cddr handle) (list (car handle)) flat)))
+         (delq (rassq (cdr handle) flat) flat)
+         (setq flat (nconc flat (list (cons (list (car handle))
+                                            (cdr handle)))))))
+      (setq flat (cdr flat))
+      (mapc (lambda (handle)
+             (if (cdar handle)
+                 ;; This is a hidden (i.e. unnumbered) handle.
+                 (progn
+                   (setcar handle
+                           (1+ (caar gnus-article-mime-handle-alist)))
+                   (push handle gnus-article-mime-handle-alist))
+               (setcar handle (caar handle))))
+           flat)
+      flat)))
+
+(defun gnus-mime-buttonize-attachments-in-header (&optional interactive)
+  "Show attachments as buttons in the end of the header of an article.
+This function toggles the display when called interactively.  Note that
+buttons to be added to the header are only the ones that aren't inlined
+in the body.  Use `gnus-header-face-alist' to highlight buttons."
+  (interactive (list t))
+  (gnus-with-article-buffer
+    (let ((case-fold-search t) buttons handle type st)
+      (save-excursion
+       (save-restriction
+         (widen)
+         (article-narrow-to-head)
+         ;; Header buttons exist?
+         (while (and (not buttons)
+                     (re-search-forward "^attachments?:[\n ]+" nil t))
+           (when (get-char-property (match-end 0)
+                                    'gnus-button-attachment-extra)
+             (setq buttons (match-beginning 0))))
+         (widen)
+         (when buttons
+           ;; Delete header buttons.
+           (delete-region buttons (if (re-search-forward "^[^ ]" nil t)
+                                      (match-beginning 0)
+                                    (point-max))))
+         (unless (and interactive buttons)
+           ;; Find buttons.
+           (setq buttons nil)
+           (dolist (button (gnus-article-mime-handles))
+             (setq handle (cdr button)
+                   type (mm-handle-media-type handle))
+             (when (or (and (if (gnus-buffer-live-p gnus-summary-buffer)
+                                (with-current-buffer gnus-summary-buffer
+                                  gnus-inhibit-images)
+                              gnus-inhibit-images)
+                            (string-match "\\`image/" type))
+                       (mm-inline-override-p handle)
+                       (and (mm-handle-disposition handle)
+                            (not (equal (car (mm-handle-disposition handle))
+                                        "inline"))
+                            (not (mm-attachment-override-p handle)))
+                       (not (mm-automatic-display-p handle))
+                       (not (or (and (mm-inlinable-p handle)
+                                     (mm-inlined-p handle))
+                                (mm-automatic-external-display-p type))))
+               (push button buttons)))
+           (when buttons
+             ;; Add header buttons.
+             (article-goto-body)
+             (forward-line -1)
+             (narrow-to-region (point) (point))
+             (insert "Attachment" (if (cdr buttons) "s" "") ":")
+             (dolist (button (nreverse buttons))
+               (setq st (point))
+               (insert " ")
+               (mm-handle-set-undisplayer (setq handle (cdr button)) nil)
+               (gnus-insert-mime-button handle (car button))
+               (skip-chars-backward "\t\n ")
+               (delete-region (point) (point-max))
+               (when (> (current-column) (window-width))
+                 (goto-char st)
+                 (insert "\n")
+                 (end-of-line)))
+             (insert "\n")
+             (dolist (ovl (overlays-in (point-min) (point)))
+               (overlay-put ovl 'gnus-button-attachment-extra t)
+               (overlay-put ovl 'face nil))
+             (let ((gnus-treatment-function-alist
+                    '((gnus-treat-highlight-headers
+                       gnus-article-highlight-headers))))
+               (gnus-treat-article 'head)))))))))
+
+;;; Article savers.
+
+(defun gnus-output-to-file (file-name)
+  "Append the current article to a file named FILE-NAME.
+If `gnus-article-save-coding-system' is non-nil, it is used to encode
+text and used as the value of the coding cookie which is added to the
+top of a file.  Otherwise, this function saves a raw article without
+the coding cookie."
+  (let* ((artbuf (current-buffer))
+        (file-name-coding-system nnmail-pathname-coding-system)
+        (coding gnus-article-save-coding-system)
+        (coding-system-for-read (if coding
+                                    nil ;; Rely on the coding cookie.
+                                  mm-text-coding-system))
+        (coding-system-for-write (or coding
+                                     mm-text-coding-system-for-write
+                                     mm-text-coding-system))
+        (exists (file-exists-p file-name)))
+    (with-temp-buffer
+      (when exists
+       (insert-file-contents file-name)
+       (goto-char (point-min))
+       ;; Remove the existing coding cookie.
+       (when (looking-at "X-Gnus-Coding-System: .+\n\n")
+         (delete-region (match-beginning 0) (match-end 0))))
+      (goto-char (point-max))
+      (insert-buffer-substring artbuf)
+      ;; Append newline at end of the buffer as separator, and then
+      ;; save it to file.
+      (goto-char (point-max))
+      (insert "\n")
+      (when coding
+       ;; If the coding system is not suitable to encode the text,
+       ;; ask a user for a proper one.
+       (when (fboundp 'select-safe-coding-system)
+         (setq coding (coding-system-base
+                       (save-window-excursion
+                         (select-safe-coding-system (point-min) (point-max)
+                                                    coding))))
+         (setq coding-system-for-write
+               (or (cdr (assq coding '((mule-utf-8 . utf-8))))
+                   coding)))
+       (goto-char (point-min))
+       ;; Add the coding cookie.
+       (insert (format "X-Gnus-Coding-System: -*- coding: %s; -*-\n\n"
+                       coding-system-for-write)))
+      (if exists
+         (progn
+           (write-region (point-min) (point-max) file-name nil 'no-message)
+           (message "Appended to %s" file-name))
+       (write-region (point-min) (point-max) file-name))))
+  t)
+
+(defun gnus-narrow-to-page (&optional arg)
+  "Narrow the article buffer to a page.
+If given a numerical ARG, move forward ARG pages."
+  (interactive "P")
+  (setq arg (if arg (prefix-numeric-value arg) 0))
+  (with-current-buffer gnus-article-buffer
+    (widen)
+    ;; Remove any old next/prev buttons.
+    (when (gnus-visual-p 'page-marker)
+      (let ((inhibit-read-only t))
+       (gnus-remove-text-with-property 'gnus-prev)
+       (gnus-remove-text-with-property 'gnus-next)))
+    (let (st nd pt)
+      (when (save-excursion
+             (cond ((< arg 0)
+                    (if (re-search-backward page-delimiter nil 'move (abs arg))
+                        (prog1
+                            (setq nd (match-beginning 0)
+                                  pt nd)
+                          (when (re-search-backward page-delimiter nil t)
+                            (setq st (match-end 0))))
+                      (when (re-search-forward page-delimiter nil t)
+                        (setq nd (match-beginning 0)
+                              pt (point-min)))))
+                   ((> arg 0)
+                    (if (re-search-forward page-delimiter nil 'move arg)
+                        (prog1
+                            (setq st (match-end 0)
+                                  pt st)
+                          (when (re-search-forward page-delimiter nil t)
+                            (setq nd (match-beginning 0))))
+                      (when (re-search-backward page-delimiter nil t)
+                        (setq st (match-end 0)
+                              pt (point-max)))))
+                   (t
+                    (when (re-search-backward page-delimiter nil t)
+                      (goto-char (setq st (match-end 0))))
+                    (when (re-search-forward page-delimiter nil t)
+                      (setq nd (match-beginning 0)))
+                    (or st nd))))
+       (setq gnus-page-broken t)
+       (when pt (goto-char pt))
+       (narrow-to-region (or st (point-min)) (or nd (point-max)))
+       (when (gnus-visual-p 'page-marker)
+         (save-excursion
+           (when nd
+             (goto-char nd)
+             (gnus-insert-next-page-button))
+           (when st
+             (goto-char st)
+             (gnus-insert-prev-page-button))))))))
+
+;; Article mode commands
+
+(defun gnus-article-goto-next-page ()
+  "Show the next page of the article."
+  (interactive)
+  (when (gnus-article-next-page)
+    (goto-char (point-min))
+    (gnus-article-read-summary-keys nil (gnus-character-to-event ?n))))
+
+
+(defun gnus-article-goto-prev-page ()
+  "Show the previous page of the article."
+  (interactive)
+  (if (save-restriction (widen) (bobp)) ;; Real beginning-of-buffer?
+      (gnus-article-read-summary-keys nil (gnus-character-to-event ?p))
+    (gnus-article-prev-page nil)))
+
+;; This is cleaner but currently breaks `gnus-pick-mode':
+;;
+;; (defun gnus-article-goto-next-page ()
+;;   "Show the next page of the article."
+;;   (interactive)
+;;   (gnus-eval-in-buffer-window gnus-summary-buffer
+;;     (gnus-summary-next-page)))
+;;
+;; (defun gnus-article-goto-prev-page ()
+;;   "Show the next page of the article."
+;;   (interactive)
+;;   (gnus-eval-in-buffer-window gnus-summary-buffer
+;;     (gnus-summary-prev-page)))
+
+(defun gnus-article-next-page (&optional lines)
+  "Show the next page of the current article.
+If end of article, return non-nil.  Otherwise return nil.
+Argument LINES specifies lines to be scrolled up."
+  (interactive "p")
+  (move-to-window-line (if (featurep 'xemacs) -1 (- -1 scroll-margin)))
+  (if (and (not (and gnus-article-over-scroll
+                    (> (count-lines (window-start) (point-max))
+                       (if (featurep 'xemacs)
+                           (or lines (1- (window-height)))
+                         (+ (or lines (1- (window-height))) scroll-margin)))))
+          (save-excursion
+            (end-of-line)
+            (and (pos-visible-in-window-p)     ;Not continuation line.
+                 (>= (point) (point-max)))))
+      ;; Nothing in this page.
+      (if (or (not gnus-page-broken)
+             (save-excursion
+               (save-restriction
+                 (widen)
+                 (forward-line)
+                 (eobp)))) ;Real end-of-buffer?
+         (progn
+           (when gnus-article-over-scroll
+             (gnus-article-next-page-1 lines))
+           t)                  ;Nothing more.
+       (gnus-narrow-to-page 1)         ;Go to next page.
+       nil)
+    ;; More in this page.
+    (gnus-article-next-page-1 lines)
+    nil))
+
+(defun gnus-article-beginning-of-window ()
+  "Move point to the beginning of the window.
+In Emacs, the point is placed at the line number which `scroll-margin'
+specifies."
+  (if (featurep 'xemacs)
+      (move-to-window-line 0)
+    ;; There is an obscure bug in Emacs that makes it impossible to
+    ;; scroll past big pictures in the article buffer.  Try to fix
+    ;; this by adding a sanity check by counting the lines visible.
+    (when (> (count-lines (window-start) (window-end)) 30)
+      (move-to-window-line
+       (min (max 0 scroll-margin)
+           (max 1 (- (window-height)
+                     (if mode-line-format 1 0)
+                     (if header-line-format 1 0)
+                     2)))))))
+
+(defvar scroll-in-place)
+
+(defun gnus-article-next-page-1 (lines)
+  (condition-case ()
+      (let ((scroll-in-place nil)
+           (auto-window-vscroll nil))
+       (scroll-up lines))
+    (end-of-buffer
+     ;; Long lines may cause an end-of-buffer error.
+     (goto-char (point-max))))
+  (gnus-article-beginning-of-window))
+
+(defun gnus-article-prev-page (&optional lines)
+  "Show previous page of current article.
+Argument LINES specifies lines to be scrolled down."
+  (interactive "p")
+  (move-to-window-line 0)
+  (if (and gnus-page-broken
+          (bobp)
+          (not (save-restriction (widen) (bobp)))) ;Real beginning-of-buffer?
+      (progn
+       (gnus-narrow-to-page -1)        ;Go to previous page.
+       (goto-char (point-max))
+       (recenter (if gnus-article-over-scroll
+                     (if lines
+                         (max (if (featurep 'xemacs)
+                                  lines
+                                (+ lines scroll-margin))
+                              3)
+                       (- (window-height) 2))
+                   -1)))
+    (prog1
+       (condition-case ()
+           (let ((scroll-in-place nil))
+             (scroll-down lines))
+         (beginning-of-buffer
+          (goto-char (point-min))))
+      (gnus-article-beginning-of-window))))
+
+(defun gnus-article-only-boring-p ()
+  "Decide whether there is only boring text remaining in the article.
+Something \"interesting\" is a word of at least two letters that does
+not have a face in `gnus-article-boring-faces'."
+  (when (and gnus-article-skip-boring
+            (boundp 'gnus-article-boring-faces)
+            (symbol-value 'gnus-article-boring-faces))
+    (save-excursion
+      (let ((inhibit-point-motion-hooks t))
+       (catch 'only-boring
+         (while (re-search-forward "\\b\\w\\w" nil t)
+           (forward-char -1)
+           (when (not (gnus-intersection
+                       (gnus-faces-at (point))
+                       (symbol-value 'gnus-article-boring-faces)))
+             (throw 'only-boring nil)))
+         (throw 'only-boring t))))))
+
+(defun gnus-article-refer-article ()
+  "Read article specified by message-id around point."
+  (interactive)
+  (save-excursion
+    (re-search-backward "[ \t]\\|^" (point-at-bol) t)
+    (re-search-forward "<?news:<?\\|<" (point-at-eol) t)
+    (if (re-search-forward "[^@ ]+@[^ \t>]+" (point-at-eol) t)
+       (let ((msg-id (concat "<" (match-string 0) ">")))
+         (set-buffer gnus-summary-buffer)
+         (gnus-summary-refer-article msg-id))
+      (error "No references around point"))))
+
+(defun gnus-article-show-summary ()
+  "Reconfigure windows to show summary buffer."
+  (interactive)
+  (if (not (gnus-buffer-live-p gnus-summary-buffer))
+      (error "There is no summary buffer for this article buffer")
+    (gnus-article-set-globals)
+    (gnus-configure-windows 'article)
+    (gnus-summary-goto-subject gnus-current-article)
+    (gnus-summary-position-point)))
+
+(defun gnus-article-describe-briefly ()
+  "Describe article mode commands briefly."
+  (interactive)
+  (gnus-message 6 "%s" (substitute-command-keys "\\<gnus-article-mode-map>\\[gnus-article-goto-next-page]:Next page     \\[gnus-article-goto-prev-page]:Prev page  \\[gnus-article-show-summary]:Show summary  \\[gnus-info-find-node]:Run Info  \\[gnus-article-describe-briefly]:This help")))
+
+(defun gnus-article-check-buffer ()
+  "Beep if not in an article buffer."
+  (unless (derived-mode-p 'gnus-article-mode)
+    (error "Command invoked outside of a Gnus article buffer")))
+
+(defvar gnus-pick-mode)
+
+(defun gnus-article-read-summary-keys (&optional _arg key not-restore-window)
+  "Read a summary buffer key sequence and execute it from the article buffer."
+  (interactive "P")
+  (gnus-article-check-buffer)
+  (let ((nosaves
+        '("q" "Q"  "c" "r" "\C-c\C-f" "m"  "a" "f"
+          "Zc" "ZC" "ZE" "ZQ" "ZZ" "Zn" "ZR" "ZG" "ZN" "ZP"
+          "=" "^" "\M-^" "|"))
+       (nosave-but-article
+        '("A " "A<" "A>" "AM" "AP" "AR" "AT" "A\C-?" "A\M-\r" "A\r" "Ab" "Ae"
+          "An" "Ap" [?A (meta return)] [?A delete]))
+       (nosave-in-article
+        '("AS" "\C-d"))
+       keys new-sum-point)
+    (with-current-buffer gnus-article-current-summary
+      (let (gnus-pick-mode)
+       (setq unread-command-events (nconc unread-command-events
+                                          (list (or key last-command-event)))
+             keys (if (featurep 'xemacs)
+                      (events-to-keys (read-key-sequence nil t))
+                    (read-key-sequence nil t)))))
+
+    (message "")
+
+    (cond
+     ((eq (aref keys (1- (length keys))) ?\C-h)
+      (gnus-article-describe-bindings (substring keys 0 -1)))
+     ((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)
+         ;; We disable the pick minor mode commands.
+         (let (gnus-pick-mode)
+           (setq func (key-binding keys t))))
+       (if (or (not func)
+               (numberp func))
+           (ding)
+         (unless (member keys nosave-in-article)
+           (set-buffer gnus-article-current-summary))
+         (when (and (symbolp func)
+                    (get func 'disabled))
+           (error "Function %s disabled" func))
+         (call-interactively func)
+         (setq new-sum-point (point)))
+       (when (member keys nosave-but-article)
+         (pop-to-buffer gnus-article-buffer))))
+     (t
+      ;; These commands should restore window configuration.
+      (let ((obuf (current-buffer))
+           (owin (current-window-configuration))
+           win func in-buffer selected new-sum-start new-sum-hscroll err)
+       (cond (not-restore-window
+              (pop-to-buffer gnus-article-current-summary)
+              (setq win (selected-window)))
+             ((setq win (get-buffer-window gnus-article-current-summary))
+              (select-window win))
+             (t
+              (let ((summary-buffer gnus-article-current-summary))
+                (gnus-configure-windows 'article)
+                (unless (setq win (get-buffer-window summary-buffer 'visible))
+                  (let ((gnus-buffer-configuration
+                         '((article ((vertical 1.0
+                                               (summary 0.25 point)
+                                               (article 1.0)))))))
+                    (gnus-configure-windows 'article))
+                  (setq win (get-buffer-window summary-buffer 'visible)))
+                (gnus-select-frame-set-input-focus (window-frame win))
+                (select-window win))))
+       (setq in-buffer (current-buffer))
+       ;; We disable the pick minor mode commands.
+       (setq func (let (gnus-pick-mode)
+                    (key-binding keys t)))
+       (when (get func 'disabled)
+         (error "Function %s disabled" func))
+       (if (and func
+                (functionp func)
+                (condition-case code
+                    (progn
+                      (call-interactively func)
+                      t)
+                  (error
+                   (setq err code)
+                   nil)))
+           (progn
+             (when (eq win (selected-window))
+               (setq new-sum-point (point)
+                     new-sum-start (window-start win)
+                     new-sum-hscroll (window-hscroll win)))
+             (when (or (eq in-buffer (current-buffer))
+                       (when (eq obuf (current-buffer))
+                         (set-buffer in-buffer)
+                         t))
+               (setq selected (ignore-errors (gnus-summary-select-article)))
+               (set-buffer obuf)
+               (unless not-restore-window
+                 (set-window-configuration owin))
+               (when (and (eq selected 'old)
+                          new-sum-point)
+                 (set-window-start (get-buffer-window (current-buffer))
+                                   1)
+                 (set-window-point (get-buffer-window (current-buffer))
+                                   (if (article-goto-body)
+                                       (1- (point))
+                                     (point))))
+               (when (and (not not-restore-window)
+                          new-sum-point
+                          (window-live-p win)
+                          (with-current-buffer (window-buffer win)
+                            (derived-mode-p 'gnus-summary-mode)))
+                 (set-window-point win new-sum-point)
+                 (set-window-start win new-sum-start)
+                 (set-window-hscroll win new-sum-hscroll))))
+         (set-window-configuration owin)
+         (if err
+             (signal (car err) (cdr err))
+           (ding))))))))
+
+(defun gnus-article-read-summary-send-keys ()
+  (interactive)
+  (let ((unread-command-events (list (gnus-character-to-event ?S))))
+    (gnus-article-read-summary-keys)))
+
+(defun gnus-article-describe-key (key)
+  "Display documentation of the function invoked by KEY.
+KEY is a string or a vector."
+  (interactive (list (let ((cursor-in-echo-area t)) ;; better for XEmacs.
+                      (read-key-sequence "Describe key: "))))
+  (gnus-article-check-buffer)
+  (if (memq (key-binding key t) '(gnus-article-read-summary-keys
+                                 gnus-article-read-summary-send-keys))
+      (with-current-buffer gnus-article-current-summary
+       (setq unread-command-events
+             (if (featurep 'xemacs)
+                 (append key unread-command-events)
+               (nconc
+                (mapcar (lambda (x) (if (and (integerp x) (>= x 128))
+                                        (list 'meta (- x 128))
+                                      x))
+                        key)
+                unread-command-events)))
+       (let ((cursor-in-echo-area t)
+             gnus-pick-mode)
+         (describe-key (read-key-sequence nil t))))
+    (describe-key key)))
+
+(defun gnus-article-describe-key-briefly (key &optional insert)
+  "Display documentation of the function invoked by KEY.
+KEY is a string or a vector."
+  (interactive (list (let ((cursor-in-echo-area t)) ;; better for XEmacs.
+                      (read-key-sequence "Describe key: "))
+                    current-prefix-arg))
+  (gnus-article-check-buffer)
+  (if (memq (key-binding key t) '(gnus-article-read-summary-keys
+                                 gnus-article-read-summary-send-keys))
+      (with-current-buffer gnus-article-current-summary
+       (setq unread-command-events
+             (if (featurep 'xemacs)
+                 (append key unread-command-events)
+               (nconc
+                (mapcar (lambda (x) (if (and (integerp x) (>= x 128))
+                                        (list 'meta (- x 128))
+                                      x))
+                        key)
+                unread-command-events)))
+       (let ((cursor-in-echo-area t)
+             gnus-pick-mode)
+         (describe-key-briefly (read-key-sequence nil t) insert)))
+    (describe-key-briefly key insert)))
+
+;;`gnus-agent-mode' in gnus-agent.el will define it.
+(defvar gnus-agent-summary-mode)
+(defvar gnus-draft-mode)
+(defvar help-xref-stack-item)
+(defvar help-xref-following)
+
+(defun gnus-article-describe-bindings (&optional prefix)
+  "Show a list of all defined keys, and their definitions.
+The optional argument PREFIX, if non-nil, should be a key sequence;
+then we display only bindings that start with that prefix."
+  (interactive)
+  (gnus-article-check-buffer)
+  (let ((keymap (copy-keymap gnus-article-mode-map))
+       (map (copy-keymap gnus-article-send-map))
+       (sumkeys (where-is-internal 'gnus-article-read-summary-keys))
+       parent agent draft)
+    (define-key keymap "S" map)
+    (define-key map [t] nil)
+    (with-current-buffer gnus-article-current-summary
+      (set-keymap-parent
+       keymap
+       (if (setq parent (keymap-parent gnus-article-mode-map))
+          (prog1
+              (setq parent (copy-keymap parent))
+            (set-keymap-parent parent (current-local-map)))
+        (current-local-map)))
+      (set-keymap-parent map (key-binding "S"))
+      (let (key def gnus-pick-mode)
+       (while sumkeys
+         (setq key (pop sumkeys))
+         (cond ((and (vectorp key) (= (length key) 1)
+                     (consp (setq def (aref key 0)))
+                     (numberp (car def)) (numberp (cdr def)))
+                (when (< (max (car def) (cdr def)) 128)
+                  (setq sumkeys
+                        (append (mapcar
+                                 #'vector
+                                 (nreverse (gnus-uncompress-range def)))
+                                sumkeys))))
+               ((setq def (key-binding key))
+                (unless (eq def 'undefined)
+                  (define-key keymap key def))))))
+      (when (boundp 'gnus-agent-summary-mode)
+       (setq agent gnus-agent-summary-mode))
+      (when (boundp 'gnus-draft-mode)
+       (setq draft gnus-draft-mode)))
+    (with-temp-buffer
+      (use-local-map keymap)
+      (set (make-local-variable 'gnus-agent-summary-mode) agent)
+      (set (make-local-variable 'gnus-draft-mode) draft)
+      (describe-bindings prefix))
+    (let ((item `((lambda (prefix)
+                   (with-current-buffer ,(current-buffer)
+                     (gnus-article-describe-bindings prefix)))
+                 ,prefix)))
+      ;; Loading `help-mode' here is necessary if `describe-bindings'
+      ;; is replaced with something, e.g. `helm-descbinds'.
+      (require 'help-mode)
+      (with-current-buffer (let (help-xref-following) (help-buffer))
+       (setq help-xref-stack-item item)))))
+
+(defun gnus-article-reply-with-original (&optional wide)
+  "Start composing a reply mail to the current message.
+The text in the region will be yanked.  If the region isn't active,
+the entire article will be yanked."
+  (interactive)
+  (let ((article (cdr gnus-article-current))
+       contents)
+    (if (not (gnus-region-active-p))
+       (with-current-buffer gnus-summary-buffer
+         (gnus-summary-reply (list (list article)) wide))
+      (setq contents (buffer-substring (point) (mark t)))
+      ;; Deactivate active regions.
+      (when (and (boundp 'transient-mark-mode)
+                transient-mark-mode)
+       (setq mark-active nil))
+      (with-current-buffer gnus-summary-buffer
+       (gnus-summary-reply
+        (list (list article contents)) wide)))))
+
+(defun gnus-article-wide-reply-with-original ()
+  "Start composing a wide reply mail to the current message.
+The text in the region will be yanked.  If the region isn't active,
+the entire article will be yanked."
+  (interactive)
+  (gnus-article-reply-with-original t))
+
+(defun gnus-article-followup-with-original ()
+  "Compose a followup to the current article.
+The text in the region will be yanked.  If the region isn't active,
+the entire article will be yanked."
+  (interactive)
+  (let ((article (cdr gnus-article-current))
+       contents)
+      (if (not (gnus-region-active-p))
+         (with-current-buffer gnus-summary-buffer
+           (gnus-summary-followup (list (list article))))
+       (setq contents (buffer-substring (point) (mark t)))
+       ;; Deactivate active regions.
+       (when (and (boundp 'transient-mark-mode)
+                  transient-mark-mode)
+         (setq mark-active nil))
+       (with-current-buffer gnus-summary-buffer
+         (gnus-summary-followup
+          (list (list article contents)))))))
+
+(defun gnus-article-hide (&optional arg force)
+  "Hide all the gruft in the current article.
+This means that signatures, cited text and (some) headers will be
+hidden.
+If given a prefix, show the hidden text instead."
+  (interactive (append (gnus-article-hidden-arg) (list 'force)))
+  (gnus-article-hide-headers arg)
+  (gnus-article-hide-list-identifiers arg)
+  (gnus-article-hide-citation-maybe arg force)
+  (gnus-article-hide-signature arg))
+
+(defun gnus-check-group-server ()
+  ;; Make sure the connection to the server is alive.
+  (unless (gnus-server-opened
+          (gnus-find-method-for-group gnus-newsgroup-name))
+    (gnus-check-server (gnus-find-method-for-group gnus-newsgroup-name))
+    (gnus-request-group gnus-newsgroup-name t)))
+
+(declare-function nneething-get-file-name "nneething" (id))
+
+(defun gnus-request-article-this-buffer (article group)
+  "Get an article and insert it into this buffer."
+  (let (do-update-line sparse-header)
+    (prog1
+       (save-excursion
+         (erase-buffer)
+         (gnus-kill-all-overlays)
+         (setq group (or group gnus-newsgroup-name))
+
+         ;; Using `gnus-request-article' directly will insert the article into
+         ;; `nntp-server-buffer' - so we'll save some time by not having to
+         ;; copy it from the server buffer into the article buffer.
+
+         ;; We only request an article by message-id when we do not have the
+         ;; headers for it, so we'll have to get those.
+         (when (stringp article)
+           (gnus-read-header article))
+
+         ;; If the article number is negative, that means that this article
+         ;; doesn't belong in this newsgroup (possibly), so we find its
+         ;; message-id and request it by id instead of number.
+         (when (and (numberp article)
+                    gnus-summary-buffer
+                    (get-buffer gnus-summary-buffer)
+                    (gnus-buffer-exists-p gnus-summary-buffer))
+           (with-current-buffer gnus-summary-buffer
+             (let ((header (gnus-summary-article-header article)))
+               (when (< article 0)
+                 (cond
+                  ((memq article gnus-newsgroup-sparse)
+                   ;; This is a sparse gap article.
+                   (setq do-update-line article)
+                   (setq article (mail-header-id header))
+                   (setq sparse-header (gnus-read-header article))
+                   (setq gnus-newsgroup-sparse
+                         (delq article gnus-newsgroup-sparse)))
+                  ((vectorp header)
+                   ;; It's a real article.
+                   (setq article (mail-header-id header)))
+                  (t
+                   ;; It is an extracted pseudo-article.
+                   (setq article 'pseudo)
+                   (gnus-request-pseudo-article header))))
+
+               (let ((method (gnus-find-method-for-group
+                              gnus-newsgroup-name)))
+                 (when (and (eq (car method) 'nneething)
+                            (vectorp header))
+                   (let ((dir (nneething-get-file-name
+                               (mail-header-id header))))
+                     (when (and (stringp dir)
+                                (file-directory-p dir))
+                       (setq article 'nneething)
+                       (gnus-group-enter-directory dir))))))))
+
+         (cond
+          ;; Refuse to select canceled articles.
+          ((and (numberp article)
+                gnus-summary-buffer
+                (get-buffer gnus-summary-buffer)
+                (gnus-buffer-exists-p gnus-summary-buffer)
+                (eq (cdr (with-current-buffer gnus-summary-buffer
+                           (assq article gnus-newsgroup-reads)))
+                    gnus-canceled-mark))
+           nil)
+          ;; We first check `gnus-original-article-buffer'.
+          ((and (get-buffer gnus-original-article-buffer)
+                (numberp article)
+                (with-current-buffer gnus-original-article-buffer
+                  (and (equal (car gnus-original-article) group)
+                       (eq (cdr gnus-original-article) article))))
+            ;; `insert-buffer-substring' would incorrectly use the
+            ;; equivalent of string-make-multibyte which amount to decoding
+            ;; with locale-coding-system, causing failure of
+            ;; subsequent decoding.
+            (insert (mm-string-to-multibyte
+                     (with-current-buffer gnus-original-article-buffer
+                       (buffer-substring (point-min) (point-max)))))
+           'article)
+          ;; Check the backlog.
+          ((and gnus-keep-backlog
+                (gnus-backlog-request-article group article (current-buffer)))
+           'article)
+          ;; Check asynchronous pre-fetch.
+          ((gnus-async-request-fetched-article group article (current-buffer))
+           (gnus-async-prefetch-next group article gnus-summary-buffer)
+           (when (and (numberp article) gnus-keep-backlog)
+             (gnus-backlog-enter-article group article (current-buffer)))
+           'article)
+          ;; Check the cache.
+          ((and gnus-use-cache
+                (numberp article)
+                (gnus-cache-request-article article group))
+           'article)
+          ;; Check the agent cache.
+          ((gnus-agent-request-article article group)
+           'article)
+          ;; Get the article and put into the article buffer.
+          ((or (stringp article)
+               (numberp article))
+           (let ((gnus-override-method gnus-override-method)
+                 (methods (and (stringp article)
+                               (with-current-buffer gnus-summary-buffer
+                                 (gnus-refer-article-methods))))
+                 (backend (car (gnus-find-method-for-group
+                                gnus-newsgroup-name)))
+                 result
+                 (inhibit-read-only t))
+             (when (and (null gnus-override-method)
+                        methods)
+               (setq gnus-override-method (pop methods)))
+             (while (not result)
+               (erase-buffer)
+               (gnus-kill-all-overlays)
+               (let ((gnus-newsgroup-name group))
+                 (gnus-check-group-server))
+               (cond
+                ((gnus-request-article article group (current-buffer))
+                 (when (numberp article)
+                   (gnus-async-prefetch-next group article
+                                             gnus-summary-buffer)
+                   (when gnus-keep-backlog
+                     (gnus-backlog-enter-article
+                      group article (current-buffer)))
+                   (when (and gnus-agent
+                              (gnus-agent-group-covered-p group))
+                     (gnus-agent-store-article article group)))
+                 (setq result 'article))
+                (methods
+                 (setq gnus-override-method (pop methods)))
+                ((not (string-match "^400 "
+                                    (nnheader-get-report backend)))
+                 ;; If we get 400 server disconnect, reconnect and
+                 ;; retry; otherwise, assume the article has expired.
+                 (setq result 'done))))
+             (and (eq result 'article) 'article)))
+          ;; It was a pseudo.
+          (t article)))
+
+      ;; Associate this article with the current summary buffer.
+      (setq gnus-article-current-summary gnus-summary-buffer)
+
+      ;; Take the article from the original article buffer
+      ;; and place it in the buffer it's supposed to be in.
+      (when (and (get-buffer gnus-article-buffer)
+                (equal (buffer-name (current-buffer))
+                       (buffer-name (get-buffer gnus-article-buffer))))
+       (save-excursion
+         (if (get-buffer gnus-original-article-buffer)
+             (set-buffer gnus-original-article-buffer)
+           (set-buffer (gnus-get-buffer-create gnus-original-article-buffer))
+           (buffer-disable-undo)
+           (setq major-mode 'gnus-original-article-mode)
+           (setq buffer-read-only t))
+         (let ((inhibit-read-only t))
+           (erase-buffer)
+           (insert-buffer-substring gnus-article-buffer))
+         (setq gnus-original-article (cons group article)))
+
+       ;; Decode charsets.
+       (run-hooks 'gnus-article-decode-hook)
+       ;; Mark article as decoded or not.
+       (setq gnus-article-decoded-p gnus-article-decode-hook))
+
+      ;; Update sparse articles.
+      (when (and do-update-line
+                (or (numberp article)
+                    (stringp article)))
+       (let ((buf (current-buffer)))
+         (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 (gnus-get-buffer-window (current-buffer) t)
+                           (point))
+         (set-buffer buf))))))
+
+(defun gnus-block-private-groups (group)
+  "Allows images in newsgroups to be shown, blocks images in all
+other groups."
+  (if (or (gnus-news-group-p group)
+         (gnus-member-of-valid 'global group))
+      ;; Block nothing in news groups.
+      nil
+    ;; Block everything anywhere else.
+    "."))
+
+(defun gnus-blocked-images ()
+  (if (functionp gnus-blocked-images)
+      (funcall gnus-blocked-images gnus-newsgroup-name)
+    gnus-blocked-images))
+
+;;;
+;;; Article editing
+;;;
+
+(defcustom gnus-article-edit-mode-hook nil
+  "Hook run in article edit mode buffers."
+  :group 'gnus-article-various
+  :type 'hook)
+
+(defvar gnus-article-edit-done-function nil)
+
+(defvar gnus-article-edit-mode-map nil)
+
+;; Should we be using derived.el for this?
+(unless gnus-article-edit-mode-map
+  (setq gnus-article-edit-mode-map (make-keymap))
+  (set-keymap-parent gnus-article-edit-mode-map text-mode-map)
+
+  (gnus-define-keys gnus-article-edit-mode-map
+    "\C-c?"    describe-mode
+    "\C-c\C-c" gnus-article-edit-done
+    "\C-c\C-k" gnus-article-edit-exit
+    "\C-c\C-f\C-t" message-goto-to
+    "\C-c\C-f\C-o" message-goto-from
+    "\C-c\C-f\C-b" message-goto-bcc
+    ;;"\C-c\C-f\C-w" message-goto-fcc
+    "\C-c\C-f\C-c" message-goto-cc
+    "\C-c\C-f\C-s" message-goto-subject
+    "\C-c\C-f\C-r" message-goto-reply-to
+    "\C-c\C-f\C-n" message-goto-newsgroups
+    "\C-c\C-f\C-d" message-goto-distribution
+    "\C-c\C-f\C-f" message-goto-followup-to
+    "\C-c\C-f\C-m" message-goto-mail-followup-to
+    "\C-c\C-f\C-k" message-goto-keywords
+    "\C-c\C-f\C-u" message-goto-summary
+    "\C-c\C-f\C-i" message-insert-or-toggle-importance
+    "\C-c\C-f\C-a" message-generate-unsubscribed-mail-followup-to
+    "\C-c\C-b" message-goto-body
+    "\C-c\C-i" message-goto-signature
+
+    "\C-c\C-t" message-insert-to
+    "\C-c\C-n" message-insert-newsgroups
+    "\C-c\C-o" message-sort-headers
+    "\C-c\C-e" message-elide-region
+    "\C-c\C-v" message-delete-not-region
+    "\C-c\C-z" message-kill-to-signature
+    "\M-\r" message-newline-and-reformat
+    "\C-c\C-a" mml-attach-file
+    "\C-a" message-beginning-of-line
+    "\t" message-tab
+    "\M-;" comment-region)
+
+  (gnus-define-keys (gnus-article-edit-wash-map
+                    "\C-c\C-w" gnus-article-edit-mode-map)
+    "f" gnus-article-edit-full-stops))
+
+(easy-menu-define
+  gnus-article-edit-mode-field-menu gnus-article-edit-mode-map ""
+  '("Field"
+    ["Fetch To" message-insert-to t]
+    ["Fetch Newsgroups" message-insert-newsgroups t]
+    "----"
+    ["To" message-goto-to t]
+    ["From" message-goto-from 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]))
+
+(define-derived-mode gnus-article-edit-mode message-mode "Article Edit"
+  "Major mode for editing articles.
+This is an extended text-mode.
+
+\\{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))
+  (set (make-local-variable 'mail-header-separator) "")
+  (set (make-local-variable 'gnus-article-edit-mode) t)
+  (easy-menu-add message-mode-field-menu message-mode-map)
+  (mml-mode)
+  (setq buffer-read-only nil)
+  (buffer-enable-undo)
+  (widen))
+
+(defun gnus-article-edit (&optional force)
+  "Edit the current article.
+This will have permanent effect only in mail groups.
+If FORCE is non-nil, allow editing of articles even in read-only
+groups."
+  (interactive "P")
+  (when (and (not force)
+            (gnus-group-read-only-p))
+    (error "The current newsgroup does not support article editing"))
+  (gnus-article-date-original)
+  (gnus-article-edit-article
+   'ignore
+   `(lambda (no-highlight)
+      'ignore
+      (gnus-summary-edit-article-done
+       ,(or (mail-header-references gnus-current-headers) "")
+       ,(gnus-group-read-only-p) ,gnus-summary-buffer no-highlight))))
+
+(defun gnus-article-edit-article (start-func exit-func &optional quiet)
+  "Start editing the contents of the current article buffer."
+  (let ((winconf (current-window-configuration)))
+    (set-buffer gnus-article-buffer)
+    (let ((message-auto-save-directory
+          ;; Don't associate the article buffer with a draft file.
+          nil))
+      (gnus-article-edit-mode))
+    (funcall start-func)
+    (set-buffer-modified-p nil)
+    (gnus-configure-windows 'edit-article)
+    (setq gnus-article-edit-done-function exit-func)
+    (setq gnus-prev-winconf winconf)
+    (unless quiet
+      (gnus-message 6 "C-c C-c to end edits"))))
+
+(defun gnus-article-edit-done (&optional arg)
+  "Update the article edits and exit."
+  (interactive "P")
+  (let ((func gnus-article-edit-done-function)
+       (buf (current-buffer))
+       (start (window-start))
+       (winconf gnus-prev-winconf))
+    (widen) ;; Widen it in case that users narrowed the buffer.
+    (funcall func arg)
+    (set-buffer buf)
+    ;; The cache and backlog have to be flushed somewhat.
+    (when gnus-keep-backlog
+      (gnus-backlog-remove-article
+       (car gnus-article-current) (cdr gnus-article-current)))
+    ;; Flush original article as well.
+    (gnus-flush-original-article-buffer)
+    (when gnus-use-cache
+      (gnus-cache-update-article
+       (car gnus-article-current) (cdr gnus-article-current)))
+    ;; We remove all text props from the article buffer.
+    (kill-all-local-variables)
+    (set-text-properties (point-min) (point-max) nil)
+    (gnus-article-mode)
+    (set-window-configuration winconf)
+    (set-buffer buf)
+    (set-window-start (get-buffer-window buf) start)
+    (set-window-point (get-buffer-window buf) (point)))
+  (gnus-summary-show-article))
+
+(defun gnus-flush-original-article-buffer ()
+  (when (get-buffer gnus-original-article-buffer)
+    (with-current-buffer gnus-original-article-buffer
+      (setq gnus-original-article nil))))
+
+(defun gnus-article-edit-exit ()
+  "Exit the article editing without updating."
+  (interactive)
+  (when (or (not (buffer-modified-p))
+           (yes-or-no-p "Article modified; kill anyway? "))
+    (let ((curbuf (current-buffer))
+         (p (point))
+         (window-start (window-start)))
+      (erase-buffer)
+      (if (gnus-buffer-live-p gnus-original-article-buffer)
+         (insert-buffer-substring gnus-original-article-buffer))
+      (let ((winconf gnus-prev-winconf))
+       (kill-all-local-variables)
+       (gnus-article-mode)
+       (set-window-configuration winconf)
+       ;; Tippy-toe some to make sure that point remains where it was.
+       (save-current-buffer
+         (set-buffer curbuf)
+         (set-window-start (get-buffer-window (current-buffer)) window-start)
+         (goto-char p))))
+    (gnus-summary-show-article)))
+
+(defun gnus-article-edit-full-stops ()
+  "Interactively repair spacing at end of sentences."
+  (interactive)
+  (save-excursion
+    (goto-char (point-min))
+    (search-forward-regexp "^$" nil t)
+    (let ((case-fold-search nil))
+      (query-replace-regexp "\\([.!?][])}]* \\)\\([[({A-Z]\\)" "\\1 \\2"))))
+
+;;;
+;;; Article highlights
+;;;
+
+;; Written by Per Abrahamsen <abraham@iesd.auc.dk>.
+
+;;; Internal Variables:
+
+(defcustom gnus-button-url-regexp
+  (concat
+   "\\b\\(\\(www\\.\\|\\(s?https?\\|ftp\\|file\\|gopher\\|"
+   "nntp\\|news\\|telnet\\|wais\\|mailto\\|info\\):\\)"
+   "\\(//[-a-z0-9_.]+:[0-9]*\\)?"
+   (if (string-match "[[:digit:]]" "1") ;; Support POSIX?
+       (let ((chars "-a-z0-9_=#$@~%&*+\\/[:word:]")
+            (punct "!?:;.,"))
+        (concat
+         "\\(?:"
+         ;; Match paired parentheses, e.g. in Wikipedia URLs:
+         ;; http://thread.gmane.org/47B4E3B2.3050402@gmail.com
+         "[" chars punct "]+" "(" "[" chars punct "]+" "[" chars "]*)"
+         "\\(?:" "[" chars punct "]+" "[" chars "]" "\\)?"
+         "\\|"
+         "[" chars punct "]+" "[" chars "]"
+         "\\)"))
+     (concat ;; XEmacs 21.4 doesn't support POSIX.
+      "\\([-a-z0-9_=!?#$@~%&*+\\/:;.,]\\|\\w\\)+"
+      "\\([-a-z0-9_=#$@~%&*+\\/]\\|\\w\\)"))
+   "\\)")
+  "Regular expression that matches URLs."
+  :version "24.4"
+  :group 'gnus-article-buttons
+  :type 'regexp)
+
+(defcustom gnus-button-valid-fqdn-regexp
+  message-valid-fqdn-regexp
+  "Regular expression that matches a valid FQDN."
+  :version "22.1"
+  :group 'gnus-article-buttons
+  :type 'regexp)
+
+;; Regexp suggested by Felix Wiemann in <87oeuomcz9.fsf@news2.ososo.de>
+(defcustom gnus-button-valid-localpart-regexp
+  "[a-z0-9$%(*-=?[_][^<>\")!;:,{}\n\t @]*"
+  "Regular expression that matches a localpart of mail addresses or MIDs."
+  :version "22.1"
+  :group 'gnus-article-buttons
+  :type 'regexp)
+
+(defcustom gnus-button-man-handler 'manual-entry
+  "Function to use for displaying man pages.
+The function must take at least one argument with a string naming the
+man page."
+  :version "22.1"
+  :type '(choice (function-item :tag "Man" manual-entry)
+                (function-item :tag "Woman" woman)
+                (function :tag "Other"))
+  :group 'gnus-article-buttons)
+
+(defcustom gnus-button-mid-or-mail-regexp
+  (concat "\\b\\(<?" gnus-button-valid-localpart-regexp "@"
+         gnus-button-valid-fqdn-regexp
+         ">?\\)\\b")
+  "Regular expression that matches a message ID or a mail address."
+  :version "22.1"
+  :group 'gnus-article-buttons
+  :type 'regexp)
+
+(defcustom gnus-button-prefer-mid-or-mail 'gnus-button-mid-or-mail-heuristic
+  "What to do when the button on a string as \"foo123@bar.invalid\" is pushed.
+Strings like this can be either a message ID or a mail address.  If it is one
+of the symbols `mid' or `mail', Gnus will always assume that the string is a
+message ID or a mail address, respectively.  If this variable is set to the
+symbol `ask', always query the user what do do.  If it is a function, this
+function will be called with the string as its only argument.  The function
+must return `mid', `mail', `invalid' or `ask'."
+  :version "22.1"
+  :group 'gnus-article-buttons
+  :type '(choice (function-item :tag "Heuristic function"
+                               gnus-button-mid-or-mail-heuristic)
+                (const ask)
+                (const mid)
+                (const mail)))
+
+(defcustom gnus-button-mid-or-mail-heuristic-alist
+  '((-10.0 . ".+\\$.+@")
+    (-10.0 . "#")
+    (-10.0 . "\\*")
+    (-5.0  . "\\+[^+]*\\+.*@") ;; # two plus signs
+    (-5.0  . "@[Nn][Ee][Ww][Ss]") ;; /\@news/i
+    (-5.0  . "@.*[Dd][Ii][Aa][Ll][Uu][Pp]") ;; /\@.*dialup/i;
+    (-1.0  . "^[^a-z]+@")
+    ;;
+    (-5.0  . "\\.[0-9][0-9]+.*@") ;; "\.[0-9]{2,}.*\@"
+    (-5.0  . "[a-z].*[A-Z].*[a-z].*[A-Z].*@") ;; "([a-z].*[A-Z].*){2,}\@"
+    (-3.0  . "[A-Z][A-Z][a-z][a-z].*@")
+    (-5.0  . "\\...?.?@") ;; (-5.0 . "\..{1,3}\@")
+    ;;
+    (-2.0  . "^[0-9]")
+    (-1.0  . "^[0-9][0-9]")
+    ;;
+    ;; -3.0 /^[0-9][0-9a-fA-F]{2,2}/;
+    (-3.0  . "^[0-9][0-9a-fA-F][0-9a-fA-F][^0-9a-fA-F]")
+    ;; -5.0 /^[0-9][0-9a-fA-F]{3,3}/;
+    (-5.0  . "^[0-9][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][^0-9a-fA-F]")
+    ;;
+    (-3.0  .  "[0-9][0-9][0-9][0-9][0-9][^0-9].*@") ;; "[0-9]{5,}.*\@"
+    (-3.0  .  "[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][^0-9].*@")
+    ;;       "[0-9]{8,}.*\@"
+    (-3.0
+     . "[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9].*@")
+    ;; "[0-9]{12,}.*\@"
+    ;; compensation for TDMA dated mail addresses:
+    (25.0  . "-dated-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]+.*@")
+    ;;
+    (-20.0 . "\\.fsf@")        ;; Gnus
+    (-20.0 . "^slrn")
+    (-20.0 . "^Pine")
+    (-20.0 . "^alpine\\.")
+    (-20.0 . "_-_") ;; Subject change in thread
+    ;;
+    (-20.0 . "\\.ln@") ;; leafnode
+    (-30.0 . "@ID-[0-9]+\\.[a-zA-Z]+\\.dfncis\\.de")
+    (-30.0 . "@4[Aa][Xx]\\.com") ;; Forte Agent
+    ;;
+    ;; (5.0 . "") ;; $local_part_len <= 7
+    (10.0  . "^[^0-9]+@")
+    (3.0   . "^[^0-9]+[0-9][0-9]?[0-9]?@")
+    ;;      ^[^0-9]+[0-9]{1,3}\@ digits only at end of local part
+    (3.0   . "@stud")
+    ;;
+    (2.0   . "[a-z][a-z][._-][A-Z][a-z].*@")
+    ;;
+    (0.5   . "^[A-Z][a-z]")
+    (0.5   . "^[A-Z][a-z][a-z]")
+    (1.5   . "^[A-Z][a-z][A-Z][a-z][^a-z]") ;; ^[A-Z][a-z]{3,3}
+    (2.0   . "^[A-Z][a-z][A-Z][a-z][a-z][^a-z]")) ;; ^[A-Z][a-z]{4,4}
+  "An alist of (RATE . REGEXP) pairs for `gnus-button-mid-or-mail-heuristic'.
+
+A negative RATE indicates a message IDs, whereas a positive indicates a mail
+address.  The REGEXP is processed with `case-fold-search' set to nil."
+  :version "22.1"
+  :group 'gnus-article-buttons
+  :type '(repeat (cons (number :tag "Rate")
+                      (regexp :tag "Regexp"))))
+
+(defun gnus-button-mid-or-mail-heuristic (mid-or-mail)
+  "Guess whether MID-OR-MAIL is a message ID or a mail address.
+Returns `mid' if MID-OR-MAIL is a message IDs, `mail' if it's a mail
+address, `ask' if unsure and `invalid' if the string is invalid."
+  (let ((case-fold-search nil)
+       (list gnus-button-mid-or-mail-heuristic-alist)
+       (result 0) rate regexp lpartlen elem)
+    (setq lpartlen
+         (length (gnus-replace-in-string mid-or-mail "^\\(.*\\)@.*$" "\\1")))
+    (gnus-message 8 "`%s', length of local part=`%s'." mid-or-mail lpartlen)
+    ;; Certain special cases...
+    (when (string-match
+          (concat
+           "^0[0-9]+-[0-9][0-9][0-9][0-9]@t-online\\.de$\\|"
+           "^[0-9]+\\.[0-9]+@compuserve\\|"
+           "@public\\.gmane\\.org")
+          mid-or-mail)
+      (gnus-message 8 "`%s' is a known mail address." mid-or-mail)
+      (setq result 'mail))
+    (when (string-match "@.*@\\| " mid-or-mail)
+      (gnus-message 8 "`%s' is invalid." mid-or-mail)
+      (setq result 'invalid))
+    ;; Nothing more to do, if result is not a number here...
+    (when (numberp result)
+      (while list
+       (setq elem (car list)
+             rate (car elem)
+             regexp (cdr elem)
+             list (cdr list))
+       (when (string-match regexp mid-or-mail)
+         (setq result (+ result rate))
+         (gnus-message
+          9 "`%s' matched `%s', rate `%s', result `%s'."
+          mid-or-mail regexp rate result)))
+      (when (<= lpartlen 7)
+       (setq result (+ result 5.0))
+       (gnus-message 9 "`%s' matched (<= lpartlen 7), result `%s'."
+                     mid-or-mail result))
+      (when (>= lpartlen 12)
+       (gnus-message 9 "`%s' matched (>= lpartlen 12)" mid-or-mail)
+       (cond
+        ((string-match "[0-9][^0-9]+[0-9].*@" mid-or-mail)
+         ;; Long local part should contain realname if e-mail address,
+         ;; too many digits: message-id.
+         ;; $score -= 5.0 + 0.1 * $local_part_len;
+         (setq rate (* -1.0 (+ 5.0 (* 0.1 lpartlen))))
+         (setq result (+ result rate))
+         (gnus-message
+          9 "Many digits in `%s', rate `%s', result `%s'."
+          mid-or-mail rate result))
+        ((string-match "[^aeiouy][^aeiouy][^aeiouy][^aeiouy]+.*@"
+                       mid-or-mail)
+         ;; Too few vowels [^aeiouy]{4,}.*@
+         (setq result (+ result -5.0))
+         (gnus-message
+          9 "Few vowels in `%s', rate `%s', result `%s'."
+          mid-or-mail -5.0 result))
+        (t
+         (setq result (+ result 5.0))
+         (gnus-message
+          9 "`%s', rate `%s', result `%s'." mid-or-mail 5.0 result)))))
+    (gnus-message 8 "`%s': Final rate is `%s'." mid-or-mail result)
+    ;; Maybe we should make this a customizable alist: (condition . 'result)
+    (cond
+     ((symbolp result) result)
+     ;; Now convert number into proper results:
+     ((< result -10.0) 'mid)
+     ((> result  10.0) 'mail)
+     (t 'ask))))
+
+(defun gnus-button-handle-mid-or-mail (mid-or-mail)
+  (let* ((pref gnus-button-prefer-mid-or-mail) guessed
+        (url-mid (concat "news" ":" mid-or-mail))
+        (url-mailto (concat "mailto" ":" mid-or-mail)))
+    (gnus-message 9 "mid-or-mail=%s" mid-or-mail)
+    (when (fboundp pref)
+      (setq guessed
+           ;; get rid of surrounding angles...
+           (funcall pref
+                    (gnus-replace-in-string mid-or-mail "^<\\|>$" "")))
+      (if (or (eq 'mid guessed) (eq 'mail guessed))
+         (setq pref guessed)
+       (setq pref 'ask)))
+    (if (eq pref 'ask)
+       (save-window-excursion
+         (if (y-or-n-p (concat "Is <" mid-or-mail "> a mail address? "))
+             (setq pref 'mail)
+           (setq pref 'mid))))
+    (cond ((eq pref 'mid)
+          (gnus-message 8 "calling `gnus-button-handle-news' %s" url-mid)
+          (gnus-button-handle-news url-mid))
+         ((eq pref 'mail)
+          (gnus-message 8 "calling `gnus-url-mailto'  %s" url-mailto)
+          (gnus-url-mailto url-mailto))
+         (t (gnus-message 3 "Invalid string.")))))
+
+(defun gnus-button-handle-custom (fun arg)
+  "Call function FUN on argument ARG.
+Both FUN and ARG are supposed to be strings.  ARG will be passed
+as a symbol to FUN."
+  (funcall (intern fun)
+          (if (string-match "^customize-apropos" fun)
+              arg
+            (intern arg))))
+
+(defvar gnus-button-handle-describe-prefix "^\\(C-h\\|<?[Ff]1>?\\)")
+
+(defun gnus-button-handle-describe-function (url)
+  "Call `describe-function' when pushing the corresponding URL button."
+  (describe-function
+   (intern
+    (gnus-replace-in-string url gnus-button-handle-describe-prefix ""))))
+
+(defun gnus-button-handle-describe-variable (url)
+  "Call `describe-variable' when pushing the corresponding URL button."
+  (describe-variable
+   (intern
+    (gnus-replace-in-string url gnus-button-handle-describe-prefix ""))))
+
+(defun gnus-button-handle-symbol (url)
+"Display help on variable or function.
+Calls `describe-variable' or `describe-function'."
+  (let ((sym (intern url)))
+    (cond
+     ((fboundp sym) (describe-function sym))
+     ((boundp sym) (describe-variable sym))
+     (t (gnus-message 3 "`%s' is not a known function of variable." url)))))
+
+(defun gnus-button-handle-describe-key (url)
+  "Call `describe-key' when pushing the corresponding URL button."
+  (let* ((key-string
+         (gnus-replace-in-string url gnus-button-handle-describe-prefix ""))
+        (keys (ignore-errors (eval `(kbd ,key-string)))))
+    (if keys
+       (describe-key keys)
+      (gnus-message 3 "Invalid key sequence in button: %s" key-string))))
+
+(defun gnus-button-handle-apropos (url)
+  "Call `apropos' when pushing the corresponding URL button."
+  (apropos (gnus-replace-in-string url gnus-button-handle-describe-prefix "")))
+
+(defun gnus-button-handle-apropos-command (url)
+  "Call `apropos' when pushing the corresponding URL button."
+  (apropos-command
+   (gnus-replace-in-string url gnus-button-handle-describe-prefix "")))
+
+(defun gnus-button-handle-apropos-variable (url)
+  "Call `apropos' when pushing the corresponding URL button."
+  (funcall
+   (if (fboundp 'apropos-variable) 'apropos-variable 'apropos)
+   (gnus-replace-in-string url gnus-button-handle-describe-prefix "")))
+
+(defun gnus-button-handle-apropos-documentation (url)
+  "Call `apropos' when pushing the corresponding URL button."
+  (funcall
+   (if (fboundp 'apropos-documentation) 'apropos-documentation 'apropos)
+   (gnus-replace-in-string url gnus-button-handle-describe-prefix "")))
+
+(defun gnus-button-handle-library (url)
+  "Call `locate-library' when pushing the corresponding URL button."
+  (gnus-message 9 "url=`%s'" url)
+  (let* ((lib (locate-library url))
+        (file (gnus-replace-in-string (or lib "") "\\.elc" ".el")))
+    (if (not lib)
+       (gnus-message 1 "Cannot locale library `%s'." url)
+      (find-file-read-only file))))
+
+(defcustom gnus-button-man-level 5
+  "*Integer that says how many man-related buttons Gnus will show.
+The higher the number, the more buttons will appear and the more false
+positives are possible.  Note that you can set this variable local to
+specific groups.  Setting it higher in Unix groups is probably a good idea.
+See Info node `(gnus)Group Parameters' and the variable `gnus-parameters' on
+how to set variables in specific groups."
+  :version "22.1"
+  :group 'gnus-article-buttons
+  :link '(custom-manual "(gnus)Group Parameters")
+  :type 'integer)
+
+(defcustom gnus-button-emacs-level 5
+  "*Integer that says how many emacs-related buttons Gnus will show.
+The higher the number, the more buttons will appear and the more false
+positives are possible.  Note that you can set this variable local to
+specific groups.  Setting it higher in Emacs or Gnus related groups is
+probably a good idea.  See Info node `(gnus)Group Parameters' and the variable
+`gnus-parameters' on how to set variables in specific groups."
+  :version "22.1"
+  :group 'gnus-article-buttons
+  :link '(custom-manual "(gnus)Group Parameters")
+  :type 'integer)
+
+(defcustom gnus-button-message-level 5
+  "*Integer that says how many buttons for news or mail messages will appear.
+The higher the number, the more buttons will appear and the more false
+positives are possible."
+  ;; mail addresses, MIDs, URLs for news, ...
+  :version "22.1"
+  :group 'gnus-article-buttons
+  :type 'integer)
+
+(defcustom gnus-button-browse-level 5
+  "*Integer that says how many buttons for browsing will appear.
+The higher the number, the more buttons will appear and the more false
+positives are possible."
+  ;; stuff handled by `browse-url' or `gnus-button-embedded-url'
+  :version "22.1"
+  :group 'gnus-article-buttons
+  :type 'integer)
+
+(defcustom gnus-button-alist
+  '(("<\\(url:[>\n\t ]*?\\)?\\(nntp\\|news\\):[>\n\t ]*\\([^>\n\t ]*@[^>\n\t ]*\\)>"
+     0 (>= gnus-button-message-level 0) gnus-button-handle-news 3)
+    ((concat "\\b\\(nntp\\|news\\):\\("
+            gnus-button-valid-localpart-regexp "@[a-z0-9.-]+[a-z]\\)")
+     0 t gnus-button-handle-news 2)
+    ("\\(\\b<\\(url:[>\n\t ]*\\)?\\(nntp\\|news\\):[>\n\t ]*\\(//\\)?\\([^>\n\t ]*\\)>\\)"
+     1 (>= gnus-button-message-level 0) gnus-button-fetch-group 5)
+    ("\\b\\(nntp\\|news\\):\\(//\\)?\\([^'\">\n\t ]+\\)"
+     0 (>= gnus-button-message-level 0) gnus-button-fetch-group 3)
+    ;; RFC 2392 (Don't allow `/' in domain part --> CID)
+    ("\\bmid:\\(//\\)?\\([^'\">\n\t ]+@[^'\">\n\t /]+\\)"
+     0 (>= gnus-button-message-level 0) gnus-button-message-id 2)
+    ("\\bin\\( +article\\| +message\\)? +\\(<\\([^\n @<>]+@[^\n @<>]+\\)>\\)"
+     2 (>= gnus-button-message-level 0) gnus-button-message-id 3)
+    ("\\b\\(mid\\|message-id\\):? +\\(<\\([^\n @<>]+@[^\n @<>]+\\)>\\)"
+     2 (>= gnus-button-message-level 0) gnus-button-message-id 3)
+    ("\\(<URL: *\\)mailto: *\\([^> \n\t]+\\)>"
+     0 (>= gnus-button-message-level 0) gnus-url-mailto 2)
+    ;; RFC 2368 (The mailto URL scheme)
+    ("\\bmailto:\\([-a-z.@_+0-9%=?&/]+\\)"
+     0 (>= gnus-button-message-level 0) gnus-url-mailto 1)
+    ("\\bmailto:\\([^ \n\t]+\\)"
+     0 (>= gnus-button-message-level 0) gnus-url-mailto 1)
+    ;; Info Konqueror style <info:/foo/bar baz>.
+    ;; Must come before " Gnus home-grown style".
+    ("\\binfo://?\\([^'\">\n\t]+\\)"
+     0 (>= gnus-button-emacs-level 1) gnus-button-handle-info-url 1)
+   ;; Info, Gnus home-grown style (deprecated) <info://foo/bar+baz>
+    ("\\binfo://\\([^'\">\n\t ]+\\)"
+     0 (>= gnus-button-emacs-level 1) gnus-button-handle-info-url 1)
+    ;; Info GNOME style <info:foo#bar_baz>
+    ("\\binfo:\\([^('\n\t\r \"><][^'\n\t\r \"><]*\\)"
+     0 (>= gnus-button-emacs-level 1) gnus-button-handle-info-url-gnome 1)
+    ;; Info KDE style <info:(foo)bar baz>
+    ("<\\(info:\\(([^)]+)[^>\n\r]*\\)\\)>"
+     1 (>= gnus-button-emacs-level 1) gnus-button-handle-info-url-kde 2)
+    ("\\((Info-goto-node\\|(info\\)[ \t\n]*\\(\"[^\"]*\"\\))" 0
+     (>= gnus-button-emacs-level 1) gnus-button-handle-info-url 2)
+    ("\\b\\(C-h\\|<?[Ff]1>?\\)[ \t\n]+i[ \t\n]+d?[ \t\n]?m[ \t\n]+[^ ]+ ?[^ ]+[ \t\n]+RET\\([ \t\n]+i[ \t\n]+[^ ]+ ?[^ ]+[ \t\n]+RET\\([ \t\n,]*\\)\\)?"
+     ;; Info links like `C-h i d m Gnus RET' or `C-h i d m Gnus RET i partial RET'
+     0 (>= gnus-button-emacs-level 1) gnus-button-handle-info-keystrokes 0)
+    ;; This is custom
+    ("M-x[ \t\n]\\(customize-[^ ]+\\)[ \t\n]RET[ \t\n]\\([^ ]+\\)[ \t\n]RET\\>" 0
+     (>= gnus-button-emacs-level 1) gnus-button-handle-custom 1 2)
+    ;; Emacs help commands
+    ("M-x[ \t\n]+apropos[ \t\n]+RET[ \t\n]+\\([^ \t\n]+\\)[ \t\n]+RET\\>"
+     ;; regexp doesn't match arguments containing ` '.
+     0 (>= gnus-button-emacs-level 1) gnus-button-handle-apropos 1)
+    ("M-x[ \t\n]+apropos-command[ \t\n]+RET[ \t\n]+\\([^ \t\n]+\\)[ \t\n]+RET\\>"
+     0 (>= gnus-button-emacs-level 1) gnus-button-handle-apropos-command 1)
+    ("M-x[ \t\n]+apropos-variable[ \t\n]+RET[ \t\n]+\\([^ \t\n]+\\)[ \t\n]+RET\\>"
+     0 (>= gnus-button-emacs-level 1) gnus-button-handle-apropos-variable 1)
+    ("M-x[ \t\n]+apropos-documentation[ \t\n]+RET[ \t\n]+\\([^ \t\n]+\\)[ \t\n]+RET\\>"
+     0 (>= gnus-button-emacs-level 1) gnus-button-handle-apropos-documentation 1)
+    ;; The following entries may lead to many false positives so don't enable
+    ;; them by default (use a high button level).
+    ("/\\([a-z][-a-z0-9]+\\.el\\)\\>[^.?]"
+     ;; Exclude [.?] for URLs in gmane.emacs.cvs
+     1 (>= gnus-button-emacs-level 8) gnus-button-handle-library 1)
+    ("['`‘]\\([a-z][-a-z0-9]+\\.el\\)['’]"
+     1 (>= gnus-button-emacs-level 8) gnus-button-handle-library 1)
+    ("['`‘]\\([a-z][a-z0-9]+-[a-z0-9]+-[-a-z0-9]*[a-z]\\|\\(gnus\\|message\\)-[-a-z]+\\)['’]"
+     0 (>= gnus-button-emacs-level 8) gnus-button-handle-symbol 1)
+    ("['`‘]\\([a-z][a-z0-9]+-[a-z]+\\)['’]"
+     0 (>= gnus-button-emacs-level 9) gnus-button-handle-symbol 1)
+    ("(setq[ \t\n]+\\([a-z][a-z0-9]+-[-a-z0-9]+\\)[ \t\n]+.+)"
+     1 (>= gnus-button-emacs-level 7) gnus-button-handle-describe-variable 1)
+    ("\\bM-x[ \t\n]+\\([^ \t\n]+\\)[ \t\n]+RET\\>"
+     1 (>= gnus-button-emacs-level 7) gnus-button-handle-describe-function 1)
+    ("\\b\\(C-h\\|<?[Ff]1>?\\)[ \t\n]+f[ \t\n]+\\([^ \t\n]+\\)[ \t\n]+RET\\>"
+     0 (>= gnus-button-emacs-level 1) gnus-button-handle-describe-function 2)
+    ("\\b\\(C-h\\|<?[Ff]1>?\\)[ \t\n]+v[ \t\n]+\\([^ \t\n]+\\)[ \t\n]+RET\\>"
+     0 (>= gnus-button-emacs-level 1) gnus-button-handle-describe-variable 2)
+    ("['`‘]\\(\\(C-h\\|<?[Ff]1>?\\)[ \t\n]+k[ \t\n]+\\([^'’]+\\)\\)['’]"
+     ;; Unlike the other regexps we really have to require quoting
+     ;; here to determine where it ends.
+     1 (>= gnus-button-emacs-level 1) gnus-button-handle-describe-key 3)
+    ;; This is how URLs _should_ be embedded in text (RFC 1738, RFC 2396)...
+    ("<URL: *\\([^\n<>]*\\)>"
+     1 (>= gnus-button-browse-level 0) gnus-button-embedded-url 1)
+    ;; RFC 2396 (2.4.3., delims) ...
+    ("\"URL: *\\([^\n\"]*\\)\""
+     1 (>= gnus-button-browse-level 0) gnus-button-embedded-url 1)
+    ;; Raw URLs.
+    (gnus-button-url-regexp
+     0 (>= gnus-button-browse-level 0) browse-url 0)
+    ;; man pages
+    ("\\b\\([a-z][a-z]+([1-9])\\)\\W"
+     0 (and (>= gnus-button-man-level 1) (< gnus-button-man-level 3))
+     gnus-button-handle-man 1)
+    ;; more man pages: resolv.conf(5), iso_8859-1(7), xterm(1x)
+    ("\\b\\([a-z][-_.a-z0-9]+([1-9])\\)\\W"
+     0 (and (>= gnus-button-man-level 3) (< gnus-button-man-level 5))
+     gnus-button-handle-man 1)
+    ;; even more: Apache::PerlRun(3pm), PDL::IO::FastRaw(3pm),
+    ;; SoWWWAnchor(3iv), XSelectInput(3X11), X(1), X(7)
+    ("\\b\\(\\(?:[a-z][-+_.:a-z0-9]+([1-9][X1a-z]*)\\)\\|\\b\\(?:X([1-9])\\)\\)\\W"
+     0 (>= gnus-button-man-level 5) gnus-button-handle-man 1)
+    ;; Recognizing patches to .el files.  This is somewhat obscure,
+    ;; but considering the percentage of Gnus users who hack Emacs
+    ;; Lisp files...
+    ("^--- \\([^ .]+\\.el\\).*\n.*\n@@ -?\\([0-9]+\\)" 1
+     (>= gnus-button-message-level 4) gnus-button-patch 1 2)
+    ("^\\*\\*\\* \\([^ .]+\\.el\\).*\n.*\n\\*+\n\\*\\*\\* \\([0-9]+\\)" 1
+     (>= gnus-button-message-level 4) gnus-button-patch 1 2)
+    ;; MID or mail: To avoid too many false positives we don't try to catch
+    ;; all kind of allowed MIDs or mail addresses.  Domain part must contain
+    ;; at least one dot.  TLD must contain two or three chars or be a know TLD
+    ;; (info|name|...).  Put this entry near the _end_ of `gnus-button-alist'
+    ;; so that non-ambiguous entries (see above) match first.
+    (gnus-button-mid-or-mail-regexp
+     0 (>= gnus-button-message-level 5) gnus-button-handle-mid-or-mail 1))
+  "*Alist of regexps matching buttons in article bodies.
+
+Each entry has the form (REGEXP BUTTON FORM CALLBACK PAR...), where
+REGEXP: is the string (case insensitive) matching text around the button (can
+also be Lisp expression evaluating to a string),
+BUTTON: is the number of the regexp grouping actually matching the button,
+FORM: is a Lisp expression which must eval to true for the button to
+be added,
+CALLBACK: is the function to call when the user push this button, and each
+PAR: is a number of a regexp grouping whose text will be passed to CALLBACK.
+
+CALLBACK can also be a variable, in that case the value of that
+variable it the real callback function."
+  :group 'gnus-article-buttons
+  :type '(repeat (list (choice regexp variable sexp)
+                      (integer :tag "Button")
+                      (sexp :tag "Form")
+                      (function :tag "Callback")
+                      (repeat :tag "Par"
+                              :inline t
+                              (integer :tag "Regexp group")))))
+(put 'gnus-button-alist 'risky-local-variable t)
+
+(defcustom gnus-header-button-alist
+  '(("^\\(References\\|Message-I[Dd]\\|^In-Reply-To\\):" "<[^<>]+>"
+     0 (>= gnus-button-message-level 0) gnus-button-message-id 0)
+    ("^\\(From\\|Reply-To\\):" ": *\\(.+\\)$"
+     1 (>= gnus-button-message-level 0) gnus-button-reply 1)
+    ("^\\(Cc\\|To\\):" "[^ \t\n<>,()\"]+@[^ \t\n<>,()\"]+"
+     0 (>= gnus-button-message-level 0) gnus-msg-mail 0)
+    ("^X-[Uu][Rr][Ll]:" gnus-button-url-regexp
+     0 (>= gnus-button-browse-level 0) browse-url 0)
+    ("^Subject:" gnus-button-url-regexp
+     0 (>= gnus-button-browse-level 0) browse-url 0)
+    ("^[^:]+:" gnus-button-url-regexp
+     0 (>= gnus-button-browse-level 0) browse-url 0)
+    ("^OpenPGP:.*url=" gnus-button-url-regexp
+     0 (>= gnus-button-browse-level 0) gnus-button-openpgp 0)
+    ("^[^:]+:" "\\bmailto:\\([-a-z.@_+0-9%=?&/]+\\)"
+     0 (>= gnus-button-message-level 0) gnus-url-mailto 1)
+    ("^[^:]+:" "\\(<\\(url: \\)?\\(nntp\\|news\\):\\([^>\n ]*\\)>\\)"
+     1 (>= gnus-button-message-level 0) gnus-button-message-id 4))
+  "*Alist of headers and regexps to match buttons in article heads.
+
+This alist is very similar to `gnus-button-alist', except that each
+alist has an additional HEADER element first in each entry:
+
+\(HEADER REGEXP BUTTON FORM CALLBACK PAR)
+
+HEADER is a regexp to match a header.  For a fuller explanation, see
+`gnus-button-alist'."
+  :group 'gnus-article-buttons
+  :group 'gnus-article-headers
+  :type '(repeat (list (regexp :tag "Header")
+                      (choice regexp variable)
+                      (integer :tag "Button")
+                      (sexp :tag "Form")
+                      (function :tag "Callback")
+                      (repeat :tag "Par"
+                              :inline t
+                              (integer :tag "Regexp group")))))
+(put 'gnus-header-button-alist 'risky-local-variable t)
+
+;;; Commands:
+
+(defun gnus-article-push-button (event)
+  "Check text under the mouse pointer for a callback function.
+If the text under the mouse pointer has a `gnus-callback' property,
+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))
+        (fun (get-text-property pos 'gnus-callback)))
+    (goto-char pos)
+    (when fun
+      (funcall fun data))))
+
+(defun gnus-article-press-button ()
+  "Check text at point for a callback function.
+If the text at point has a `gnus-callback' property,
+call it with the value of the `gnus-data' text property."
+  (interactive)
+  (let ((data (get-text-property (point) 'gnus-data))
+       (fun (get-text-property (point) 'gnus-callback)))
+    (when fun
+      (funcall fun data))))
+
+(defun gnus-article-highlight (&optional force)
+  "Highlight current article.
+This function calls `gnus-article-highlight-headers',
+`gnus-article-highlight-citation',
+`gnus-article-highlight-signature', and `gnus-article-add-buttons' to
+do the highlighting.  See the documentation for those functions."
+  (interactive (list 'force))
+  (gnus-article-highlight-headers)
+  (gnus-article-highlight-citation force)
+  (gnus-article-highlight-signature)
+  (gnus-article-add-buttons)
+  (gnus-article-add-buttons-to-head))
+
+(defun gnus-article-highlight-some (&optional _force)
+  "Highlight current article.
+This function calls `gnus-article-highlight-headers',
+`gnus-article-highlight-signature', and `gnus-article-add-buttons' to
+do the highlighting.  See the documentation for those functions."
+  (interactive (list 'force))
+  (gnus-article-highlight-headers)
+  (gnus-article-highlight-signature)
+  (gnus-article-add-buttons))
+
+(defun gnus-article-highlight-headers ()
+  "Highlight article headers as specified by `gnus-header-face-alist'."
+  (interactive)
+  (gnus-with-article-headers
+    (let (regexp header-face field-face from hpoints fpoints)
+      (dolist (entry gnus-header-face-alist)
+       (goto-char (point-min))
+       (setq regexp (concat "^\\("
+                            (if (string-equal "" (nth 0 entry))
+                                "[^\t ]"
+                              (nth 0 entry))
+                            "\\)")
+             header-face (nth 1 entry)
+             field-face (nth 2 entry))
+       (while (and (re-search-forward regexp nil t)
+                   (not (eobp)))
+         (beginning-of-line)
+         (setq from (point))
+         (unless (search-forward ":" nil t)
+           (forward-char 1))
+         (when (and header-face
+                    (not (memq (point) hpoints)))
+           (push (point) hpoints)
+           (gnus-put-text-property from (point) 'face header-face))
+         (when (and field-face
+                    (not (memq (setq from (point)) fpoints)))
+           (push from fpoints)
+           (if (re-search-forward "^[^ \t]" nil t)
+               (forward-char -2)
+             (goto-char (point-max)))
+           (gnus-put-text-property from (point) 'face field-face)))))))
+
+(defun gnus-article-highlight-signature ()
+  "Highlight the signature in an article.
+It does this by highlighting everything after
+`gnus-signature-separator' using the face `gnus-signature'."
+  (interactive)
+  (gnus-with-article-buffer
+    (let ((inhibit-point-motion-hooks t))
+      (save-restriction
+       (when (and gnus-signature-face
+                  (gnus-article-narrow-to-signature))
+         (overlay-put (make-overlay (point-min) (point-max) nil t)
+                      'face gnus-signature-face)
+         (widen)
+         (gnus-article-search-signature)
+         (let ((start (match-beginning 0))
+               (end (set-marker (make-marker) (1+ (match-end 0)))))
+           (gnus-article-add-button start (1- end) 'gnus-signature-toggle
+                                    end)))))))
+
+(defun gnus-button-in-region-p (b e prop)
+  "Say whether PROP exists in the region."
+  (text-property-not-all b e prop nil))
+
+(defun gnus-article-add-buttons ()
+  "Find external references in the article and make buttons of them.
+\"External references\" are things like Message-IDs and URLs, as
+specified by `gnus-button-alist'."
+  (interactive)
+  (gnus-with-article-buffer
+    (let ((inhibit-point-motion-hooks t)
+         (case-fold-search t)
+         (alist gnus-button-alist)
+         beg entry regexp)
+      ;; We skip the headers.
+      (article-goto-body)
+      (setq beg (point))
+      (while (setq entry (pop alist))
+       (setq regexp (eval (car entry)))
+       (goto-char beg)
+       (while (re-search-forward regexp nil t)
+         (let ((start (match-beginning (nth 1 entry)))
+               (end (match-end (nth 1 entry)))
+               (from (match-beginning 0)))
+           (when (and (eval (nth 2 entry))
+                      (not (gnus-button-in-region-p
+                            start end 'gnus-callback)))
+             ;; That optional form returned non-nil, so we add the
+             ;; button.
+             (setq from (set-marker (make-marker) from))
+             (unless (and (eq (car entry) 'gnus-button-url-regexp)
+                          (gnus-article-extend-url-button from start end))
+               (gnus-article-add-button start end
+                                        'gnus-button-push (list from entry))
+               (gnus-put-text-property
+                start end
+                'gnus-string (buffer-substring-no-properties
+                              start end))))))))))
+
+(defun gnus-article-extend-url-button (beg start end)
+  "Extend url button if url is folded into two or more lines.
+Return non-nil if button is extended.  BEG is a marker that points to
+the beginning position of a text containing url.  START and END are
+the endpoints of a url button before it is extended.  The concatenated
+url is put as the `gnus-button-url' overlay property on the button."
+  (let ((opoint (point))
+       (points (list start end))
+       url delim regexp)
+    (prog1
+       (when (and (progn
+                    (goto-char end)
+                    (not (looking-at "[\t ]*[\">]")))
+                  (progn
+                    (goto-char start)
+                    (string-match
+                     "\\(?:\"\\|\\(<\\)\\)[\t ]*\\(?:url[\t ]*:[\t ]*\\)?\\'"
+                     (buffer-substring (point-at-bol) start)))
+                  (progn
+                    (setq url (list (buffer-substring start end))
+                          delim (if (match-beginning 1) ">" "\""))
+                    (beginning-of-line)
+                    (setq regexp (concat
+                                  (when (and (looking-at
+                                              message-cite-prefix-regexp)
+                                             (< (match-end 0) start))
+                                    (regexp-quote (match-string 0)))
+                                  "\
+[\t ]*\\(?:\\([^\t\n \">]+\\)[\t ]*$\\|\\([^\t\n \">]*\\)[\t ]*"
+                                  delim "\\)"))
+                    (while (progn
+                             (forward-line 1)
+                             (and (looking-at regexp)
+                                  (prog1
+                                      (match-beginning 1)
+                                    (push (or (match-string 2)
+                                              (match-string 1))
+                                          url)
+                                    (push (setq end (or (match-end 2)
+                                                        (match-end 1)))
+                                          points)
+                                    (push (or (match-beginning 2)
+                                              (match-beginning 1))
+                                          points)))))
+                    (match-beginning 2)))
+         (let (gnus-article-mouse-face widget-mouse-face)
+           (while points
+             (gnus-article-add-button (pop points) (pop points)
+                                      'gnus-button-push
+                                      (list beg (assq 'gnus-button-url-regexp
+                                                      gnus-button-alist)))))
+         (let ((overlay (make-overlay start end)))
+           (overlay-put overlay 'evaporate t)
+           (overlay-put overlay 'gnus-button-url
+                        (list (mapconcat 'identity (nreverse url) "")))
+           (when gnus-article-mouse-face
+             (overlay-put overlay 'mouse-face gnus-article-mouse-face)))
+         t)
+      (goto-char opoint))))
+
+;; Add buttons to the head of an article.
+(defun gnus-article-add-buttons-to-head ()
+  "Add buttons to the head of the article."
+  (interactive)
+  (gnus-with-article-headers
+    (let (beg end)
+      (dolist (entry gnus-header-button-alist)
+       ;; Each alist entry.
+       (goto-char (point-min))
+       (while (re-search-forward (car entry) nil t)
+         ;; Each header matching the entry.
+         (setq beg (match-beginning 0))
+         (setq end (or (and (re-search-forward "^[^ \t]" nil t)
+                            (match-beginning 0))
+                       (point-max)))
+         (goto-char beg)
+         (while (re-search-forward (eval (nth 1 entry)) end t)
+           ;; Each match within a header.
+           (let* ((entry (cdr entry))
+                  (start (match-beginning (nth 1 entry)))
+                  (end (match-end (nth 1 entry)))
+                  (form (nth 2 entry)))
+             (goto-char (match-end 0))
+             (when (eval form)
+               (gnus-article-add-button
+                start end (nth 3 entry)
+                (buffer-substring (match-beginning (nth 4 entry))
+                                  (match-end (nth 4 entry)))))))
+         (goto-char end))))))
+
+;;; External functions:
+
+(defun gnus-article-add-button (from to fun &optional data text)
+  "Create a button between FROM and TO with callback FUN and data DATA."
+  (when gnus-article-button-face
+    (overlay-put (make-overlay from to nil t)
+                'face gnus-article-button-face))
+  (gnus-add-text-properties
+   from to
+   (nconc (and gnus-article-mouse-face
+              (list gnus-mouse-face-prop gnus-article-mouse-face))
+         (list 'gnus-callback fun)
+         (and data (list 'gnus-data data))))
+  (widget-convert-button 'link from to :action 'gnus-widget-press-button
+                        :help-echo (or text "Follow the link")
+                        :keymap gnus-url-button-map
+                        :button-keymap gnus-widget-button-keymap))
+
+(defun gnus-article-copy-string ()
+  "Copy the string in the button to the kill ring."
+  (interactive)
+  (gnus-article-check-buffer)
+  (let ((data (get-text-property (point) 'gnus-string)))
+    (when data
+      (with-temp-buffer
+       (insert data)
+       (copy-region-as-kill (point-min) (point-max))
+       (message "Copied %s" data)))))
+
+;;; Internal functions:
+
+(defun gnus-article-set-globals ()
+  (with-current-buffer gnus-summary-buffer
+    (gnus-set-global-variables)))
+
+(defun gnus-signature-toggle (end)
+  (gnus-with-article-buffer
+    (let ((inhibit-point-motion-hooks t))
+      (if (text-property-any end (point-max) 'article-type 'signature)
+         (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)))))
+    (let ((gnus-article-mime-handle-alist-1 gnus-article-mime-handle-alist))
+      (gnus-set-mode-line 'article))))
+
+(defun gnus-button-push (marker-and-entry)
+  ;; Push button starting at MARKER.
+  (save-excursion
+    (let* ((marker (car marker-and-entry))
+           (entry (cadr marker-and-entry))
+           (regexp (car entry))
+           (inhibit-point-motion-hooks t))
+      (goto-char marker)
+      ;; This is obviously true, or something bad is happening :)
+      ;; But we need it to have the match-data
+      (when (looking-at (or (if (symbolp regexp)
+                                (symbol-value regexp)
+                              regexp)))
+        (let ((fun (nth 3 entry))
+              (args (or (and (eq (car entry) 'gnus-button-url-regexp)
+                             (get-char-property marker 'gnus-button-url))
+                        (mapcar (lambda (group)
+                                  (let ((string (match-string group)))
+                                    (set-text-properties
+                                     0 (length string) nil string)
+                                    string))
+                                (nthcdr 4 entry)))))
+
+          (cond
+           ((fboundp fun)
+            (apply fun args))
+           ((and (boundp fun)
+                 (fboundp (symbol-value fun)))
+            (apply (symbol-value fun) args))
+           (t
+            (gnus-message 1 "You must define `%S' to use this button"
+                          (cons fun args)))))))))
+
+(defun gnus-parse-news-url (url)
+  (let (scheme server port group message-id articles)
+    (with-temp-buffer
+      (insert url)
+      (goto-char (point-min))
+      (when (looking-at "\\([A-Za-z]+\\):")
+       (setq scheme (match-string 1))
+       (goto-char (match-end 0)))
+      (when (looking-at "//\\([^:/]+\\)\\(:?\\)\\([0-9]+\\)?/")
+       (setq server (match-string 1))
+       (setq port (if (stringp (match-string 3))
+                      (string-to-number (match-string 3))
+                    (match-string 3)))
+       (goto-char (match-end 0)))
+
+      (cond
+       ((looking-at "\\(.*@.*\\)")
+       (setq message-id (match-string 1)))
+       ((looking-at "\\([^/]+\\)/\\([-0-9]+\\)")
+       (setq group (match-string 1)
+             articles (split-string (match-string 2) "-")))
+       ((looking-at "\\([^/]+\\)/?")
+       (setq group (match-string 1)))
+       (t
+       (error "Unknown news URL syntax"))))
+    (list scheme server port group message-id articles)))
+
+(defvar nntp-port-number)
+
+(defun gnus-button-handle-news (url)
+  "Fetch a news URL."
+  (destructuring-bind (_scheme server port group message-id _articles)
+      (gnus-parse-news-url url)
+    (cond
+     (message-id
+      (with-current-buffer gnus-summary-buffer
+       (if server
+           (let ((gnus-refer-article-method
+                  (nconc (list (list 'nntp server))
+                         gnus-refer-article-method))
+                 (nntp-port-number (or port "nntp")))
+             (gnus-message 7 "Fetching %s with %s"
+                           message-id gnus-refer-article-method)
+             (gnus-summary-refer-article message-id))
+         (gnus-summary-refer-article message-id))))
+     (group
+      (gnus-button-fetch-group url)))))
+
+(defun gnus-button-patch (library line)
+  "Visit an Emacs Lisp library LIBRARY on line LINE."
+  (interactive)
+  (let ((file (locate-library (file-name-nondirectory library))))
+    (unless file
+      (error "Couldn't find library %s" library))
+    (find-file file)
+    (goto-char (point-min))
+    (forward-line (1- (string-to-number line)))))
+
+(defun gnus-button-handle-man (url)
+  "Fetch a man page."
+  (gnus-message 9 "`%s' `%s'" gnus-button-man-handler url)
+  (when (eq gnus-button-man-handler 'woman)
+    (setq url (gnus-replace-in-string url "([1-9][X1a-z]*).*\\'" "")))
+  (gnus-message 9 "`%s' `%s'" gnus-button-man-handler url)
+  (funcall gnus-button-man-handler url))
+
+(defun gnus-button-handle-info-url (url)
+  "Fetch an info URL."
+  (setq url (mm-subst-char-in-string ?+ ?\  url))
+  (cond
+   ((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)))))
+   ((string-match "([^)\"]+)[^\"]+" url)
+    (setq url
+         (gnus-replace-in-string
+          (gnus-replace-in-string url "[\n\t ]+" " ") "\"" ""))
+    (gnus-info-find-node url))
+   (t (error "Can't parse %s" url))))
+
+(defun gnus-button-handle-info-url-gnome (url)
+  "Fetch GNOME style info URL."
+  (setq url (mm-subst-char-in-string ?_ ?\  url))
+  (if (string-match "\\([^#]+\\)#?\\(.*\\)" url)
+      (gnus-info-find-node
+       (concat "("
+              (gnus-url-unhex-string
+                (match-string 1 url))
+              ")"
+              (or (gnus-url-unhex-string
+                   (match-string 2 url))
+                  "Top")))
+    (error "Can't parse %s" url)))
+
+(defun gnus-button-handle-info-url-kde (url)
+  "Fetch KDE style info URL."
+  (gnus-info-find-node (gnus-url-unhex-string url)))
+
+;; (info) will autoload info.el
+(declare-function Info-menu "info" (menu-item &optional fork))
+(declare-function Info-index-next "info" (num))
+
+(defun gnus-button-handle-info-keystrokes (url)
+  "Call `info' when pushing the corresponding URL button."
+  ;; For links like `C-h i d m gnus RET part RET , ,', `C-h i d m CC Mode RET'.
+  (let (node indx comma)
+    (if (string-match
+        (concat "\\b\\(C-h\\|<?[Ff]1>?\\)[ \t\n]+i[ \t\n]+d?[ \t\n]?m[ \t\n]+"
+                "\\([^ ]+ ?[^ ]+\\)[ \t\n]+RET"
+                "\\([ \t\n]+i[ \t\n]+[^ ]+ ?[^ ]+[ \t\n]+RET\\>"
+                "\\(?:[ \t\n,]*\\)\\)?")
+        url)
+       (setq node (match-string 2 url)
+             indx (match-string 3 url))
+      (error "Can't parse %s" url))
+    (info)
+    (Info-directory)
+    (Info-menu node)
+    (when (> (length indx) 0)
+      (string-match (concat "[ \t\n]+i[ \t\n]+\\([^ ]+ ?[^ ]+\\)[ \t\n]+RET\\>"
+                           "\\([ \t\n,]*\\)")
+                   indx)
+      (setq comma (match-string 2 indx))
+      (setq indx  (match-string 1 indx))
+      (Info-index indx)
+      (when comma
+       (dotimes (i (with-temp-buffer
+                     (insert comma)
+                     ;; Note: the XEmacs version of `how-many' takes
+                     ;; no optional argument.
+                     (goto-char (point-min))
+                     (how-many ",")))
+         (Info-index-next 1)))
+      nil)))
+
+(autoload 'pgg-snarf-keys-region "pgg")
+;; Called after pgg-snarf-keys-region, which autoloads pgg.el.
+(declare-function pgg-display-output-buffer "pgg" (start end status))
+
+(defun gnus-button-openpgp (url)
+  "Retrieve and add an OpenPGP key given URL from an OpenPGP header."
+  (with-temp-buffer
+    (mm-url-insert-file-contents-external url)
+    (pgg-snarf-keys-region (point-min) (point-max))
+    (pgg-display-output-buffer nil nil nil)))
+
+(defun gnus-button-message-id (message-id)
+  "Fetch MESSAGE-ID."
+  (with-current-buffer gnus-summary-buffer
+    (gnus-summary-refer-article message-id)))
+
+(defun gnus-button-fetch-group (address &rest _ignore)
+  "Fetch GROUP specified by ADDRESS."
+  (when (string-match "\\`\\(nntp\\|news\\):\\(//\\)?\\(.*\\)\\'"
+                     address)
+    ;; Allow to use `gnus-button-fetch-group' in `browse-url-browser-function'
+    ;; for nntp:// and news://
+    (setq address (match-string 3 address)))
+  (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
+         "^\\([^:/]+\\)\\(:\\([^/]+\\)\\)?/\\([^/]+\\)\\(/\\([0-9]+\\)\\)?"
+         address))
+       (error "Can't parse %s" address)
+      (gnus-group-read-ephemeral-group
+       (match-string 4 address)
+       `(nntp ,(match-string 1 address)
+             (nntp-address ,(match-string 1 address))
+             (nntp-port-number ,(if (match-end 3)
+                                    (match-string 3 address)
+                                  "nntp")))
+       nil nil nil
+       (and (match-end 6) (list (string-to-number (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))
+      (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) t))
+       (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-mailto (url)
+  ;; Send mail to someone
+  (setq url (replace-regexp-in-string "\n" " " url))
+  (when (string-match "mailto:/*\\(.*\\)" url)
+    (setq url (substring url (match-beginning 1) nil)))
+  (let* ((args (gnus-url-parse-query-string
+               (if (string-match "^\\?" url)
+                   (substring url 1)
+                 (if (string-match "^\\([^?]+\\)\\?\\(.*\\)" url)
+                     (concat "to=" (match-string 1 url) "&"
+                             (match-string 2 url))
+                   (concat "to=" url)))))
+         (subject (cdr-safe (assoc "subject" args)))
+         func)
+    (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)))
+      (insert (gnus-replace-in-string
+              (mapconcat 'identity (reverse (cdar args)) ", ")
+              "\r\n" "\n" t))
+      (setq args (cdr args)))
+    (if subject
+       (message-goto-body)
+      (message-goto-subject))))
+
+(defun gnus-button-embedded-url (address)
+  "Activate ADDRESS with `browse-url'."
+  (browse-url (gnus-strip-whitespace address)))
+
+;;; Next/prev buttons in the article buffer.
+
+(defvar gnus-next-page-line-format "%{%(Next page...%)%}\n")
+(defvar gnus-prev-page-line-format "%{%(Previous page...%)%}\n")
+
+(defvar gnus-prev-page-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map gnus-mouse-2 'gnus-button-prev-page)
+    (define-key map "\r" 'gnus-button-prev-page)
+    map))
+
+(defvar gnus-next-page-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map gnus-mouse-2 'gnus-button-next-page)
+    (define-key map "\r" 'gnus-button-next-page)
+    map))
+
+(defun gnus-insert-prev-page-button ()
+  (let ((b (point)) e
+       (inhibit-read-only t))
+    (gnus-eval-format
+     gnus-prev-page-line-format nil
+     `(keymap ,gnus-prev-page-map
+             gnus-prev t
+             gnus-callback gnus-article-button-prev-page
+             article-type annotation))
+    (setq e (if (bolp)
+               ;; Exclude a newline.
+               (1- (point))
+             (point)))
+    (when gnus-article-button-face
+      (overlay-put (make-overlay b e nil t)
+                  'face gnus-article-button-face))
+    (widget-convert-button
+     'link b e
+     :action 'gnus-button-prev-page
+     :button-keymap gnus-prev-page-map)))
+
+(defun gnus-button-next-page (&optional _args _more-args)
+  "Go to the next page."
+  (interactive)
+  (let ((win (selected-window)))
+    (select-window (gnus-get-buffer-window gnus-article-buffer t))
+    (gnus-article-next-page)
+    (select-window win)))
+
+(defun gnus-button-prev-page (&optional _args _more-args)
+  "Go to the prev page."
+  (interactive)
+  (let ((win (selected-window)))
+    (select-window (gnus-get-buffer-window gnus-article-buffer t))
+    (gnus-article-prev-page)
+    (select-window win)))
+
+(defun gnus-insert-next-page-button ()
+  (let ((b (point)) e
+       (inhibit-read-only t))
+    (gnus-eval-format gnus-next-page-line-format nil
+                     `(keymap ,gnus-next-page-map
+                               gnus-next t
+                               gnus-callback gnus-article-button-next-page
+                               article-type annotation))
+    (setq e (if (bolp)
+               ;; Exclude a newline.
+               (1- (point))
+             (point)))
+    (when gnus-article-button-face
+      (overlay-put (make-overlay b e nil t)
+                  'face gnus-article-button-face))
+    (widget-convert-button
+     'link b e
+     :action 'gnus-button-next-page
+     :button-keymap gnus-next-page-map)))
+
+(defun gnus-article-button-next-page (_arg)
+  "Go to the next page."
+  (interactive "P")
+  (let ((win (selected-window)))
+    (select-window (gnus-get-buffer-window gnus-article-buffer t))
+    (gnus-article-next-page)
+    (select-window win)))
+
+(defun gnus-article-button-prev-page (_arg)
+  "Go to the prev page."
+  (interactive "P")
+  (let ((win (selected-window)))
+    (select-window (gnus-get-buffer-window gnus-article-buffer t))
+    (gnus-article-prev-page)
+    (select-window win)))
+
+(defvar gnus-decode-header-methods
+  '(mail-decode-encoded-word-region)
+  "List of methods used to decode headers.
+
+This variable is a list of FUNCTION or (REGEXP . FUNCTION).  If item
+is FUNCTION, FUNCTION will be applied to all newsgroups.  If item is a
+\(REGEXP . FUNCTION), FUNCTION will be only apply to the newsgroups
+whose names match REGEXP.
+
+For example:
+\((\"chinese\" . gnus-decode-encoded-word-region-by-guess)
+ mail-decode-encoded-word-region
+ (\"chinese\" . rfc1843-decode-region))
+")
+
+(defvar gnus-decode-header-methods-cache nil)
+
+(defun gnus-multi-decode-header (start end)
+  "Apply the functions from `gnus-encoded-word-methods' that match."
+  (unless (and gnus-decode-header-methods-cache
+              (eq gnus-newsgroup-name
+                  (car gnus-decode-header-methods-cache)))
+    (setq gnus-decode-header-methods-cache (list gnus-newsgroup-name))
+    (dolist (x gnus-decode-header-methods)
+      (if (symbolp x)
+         (nconc gnus-decode-header-methods-cache (list x))
+       (if (and gnus-newsgroup-name
+                (string-match (car x) gnus-newsgroup-name))
+           (nconc gnus-decode-header-methods-cache
+                  (list (cdr x)))))))
+  (let ((xlist gnus-decode-header-methods-cache))
+    (pop xlist)
+    (save-restriction
+      (narrow-to-region start end)
+      (while xlist
+       (funcall (pop xlist) (point-min) (point-max))))))
+
+;;;
+;;; Treatment top-level handling.
+;;;
+
+(defvar gnus-inhibit-article-treatments nil)
+
+;; Dynamic variables.
+(defvar part-number)                    ;FIXME: Lacks a "gnus-" prefix.
+(defvar total-parts)                    ;FIXME: Lacks a "gnus-" prefix.
+(defvar gnus-treat-type)
+(defvar gnus-treat-condition)
+(defvar gnus-treat-length)
+
+(defun gnus-treat-article (condition
+                          &optional part-num total type)
+  (let ((gnus-treat-condition condition)
+        (part-number part-num)
+        (total-parts total)
+        (gnus-treat-type type)
+        (gnus-treat-length (- (point-max) (point-min)))
+       (alist gnus-treatment-function-alist)
+       (article-goto-body-goes-to-point-min-p t)
+       (treated-type
+        (or (not type)
+            (catch 'found
+              (let ((list gnus-article-treat-types))
+                (while list
+                  (when (string-match (pop list) type)
+                    (throw 'found t)))))))
+       (highlightp (gnus-visual-p 'article-highlight 'highlight))
+       val)
+    (gnus-run-hooks 'gnus-part-display-hook)
+    (dolist (elem alist)
+      (setq val
+           (save-excursion
+             (when (gnus-buffer-live-p gnus-summary-buffer)
+               (set-buffer gnus-summary-buffer))
+             (symbol-value (car elem))))
+      (when (and (or (consp val)
+                    treated-type)
+                (or (not gnus-inhibit-article-treatments)
+                    (eq gnus-treat-condition 'head))
+                (gnus-treat-predicate val)
+                (or (not (get (car elem) 'highlight))
+                    highlightp))
+       (save-restriction
+         (funcall (cadr elem)))))))
+
+(defun gnus-treat-predicate (val)
+  (cond
+   ((null val)
+    nil)
+   (gnus-treat-condition
+    (eq gnus-treat-condition val))
+   ((and (listp val)
+        (stringp (car val)))
+    (apply 'gnus-or (mapcar `(lambda (s)
+                              (string-match s ,(or gnus-newsgroup-name "")))
+                           val)))
+   ((listp val)
+    (let ((pred (pop val)))
+      (cond
+       ((eq pred 'or)
+       (apply 'gnus-or (mapcar 'gnus-treat-predicate val)))
+       ((eq pred 'and)
+       (apply 'gnus-and (mapcar 'gnus-treat-predicate val)))
+       ((eq pred 'not)
+       (not (gnus-treat-predicate (car val))))
+       ((eq pred 'typep)
+       (equal (car val) gnus-treat-type))
+       ((functionp pred)
+       (funcall pred))
+       (t
+       (error "%S is not a valid predicate" pred)))))
+   ((eq val t)
+    t)
+   ((eq val 'head)
+    nil)
+   ((eq val 'first)
+    (eq part-number 1))
+   ((eq val 'last)
+    (eq part-number total-parts))
+   ((numberp val)
+    (< gnus-treat-length val))
+   (t
+    (error "%S is not a valid value" val))))
+
+(defun gnus-article-encrypt-body (protocol &optional n)
+  "Encrypt the article body."
+  (interactive
+   (list
+    (or gnus-article-encrypt-protocol
+       (gnus-completing-read "Encrypt protocol"
+                              (mapcar 'car gnus-article-encrypt-protocol-alist)
+                              t))
+    current-prefix-arg))
+  ;; User might hit `K E' instead of `K e', so prompt once.
+  (when (and gnus-article-encrypt-protocol
+            gnus-novice-user)
+    (unless (gnus-y-or-n-p "Really encrypt article(s)? ")
+      (error "Encrypt aborted")))
+  (let ((func (cdr (assoc protocol gnus-article-encrypt-protocol-alist))))
+    (unless func
+      (error "Can't find the encrypt protocol %s" protocol))
+    (if (member gnus-newsgroup-name '("nndraft:delayed"
+                                     "nndraft:drafts"
+                                     "nndraft:queue"))
+       (error "Can't encrypt the article in group %s"
+              gnus-newsgroup-name))
+    (gnus-summary-iterate n
+      (with-current-buffer gnus-summary-buffer
+       (let ((mail-parse-charset gnus-newsgroup-charset)
+             (mail-parse-ignored-charsets gnus-newsgroup-ignored-charsets)
+             (summary-buffer gnus-summary-buffer)
+             references point)
+         (gnus-set-global-variables)
+         (when (gnus-group-read-only-p)
+           (error "The current newsgroup does not support article encrypt"))
+         (gnus-summary-show-article t)
+         (setq references
+             (or (mail-header-references gnus-current-headers) ""))
+         (set-buffer gnus-article-buffer)
+         (let* ((inhibit-read-only t)
+                (headers
+                 (mapcar (lambda (field)
+                           (and (save-restriction
+                                  (message-narrow-to-head)
+                                  (goto-char (point-min))
+                                  (search-forward field nil t))
+                                (prog2
+                                    (message-narrow-to-field)
+                                    (buffer-string)
+                                  (delete-region (point-min) (point-max))
+                                  (widen))))
+                         '("Content-Type:" "Content-Transfer-Encoding:"
+                           "Content-Disposition:"))))
+           (message-narrow-to-head)
+           (message-remove-header "MIME-Version")
+           (goto-char (point-max))
+           (setq point (point))
+           (insert (apply 'concat headers))
+           (widen)
+           (narrow-to-region point (point-max))
+           (let ((message-options message-options))
+             (message-options-set 'message-sender user-mail-address)
+             (message-options-set 'message-recipients user-mail-address)
+             (message-options-set 'message-sign-encrypt 'not)
+             (funcall func))
+           (goto-char (point-min))
+           (insert "MIME-Version: 1.0\n")
+           (widen)
+           (gnus-summary-edit-article-done
+            references nil summary-buffer t))
+         (when gnus-keep-backlog
+           (gnus-backlog-remove-article
+            (car gnus-article-current) (cdr gnus-article-current)))
+         (gnus-flush-original-article-buffer)
+         (when gnus-use-cache
+           (gnus-cache-update-article
+            (car gnus-article-current) (cdr gnus-article-current))))))))
+
+(defvar gnus-mime-security-button-line-format "%{%([[%t:%i]%D]%)%}\n"
+  "The following specs can be used:
+%t  The security MIME type
+%i  Additional info
+%d  Details
+%D  Details if button is pressed")
+
+(defvar gnus-mime-security-button-end-line-format "%{%([[End of %t]%D]%)%}\n"
+  "The following specs can be used:
+%t  The security MIME type
+%i  Additional info
+%d  Details
+%D  Details if button is pressed")
+
+(defvar gnus-mime-security-button-line-format-alist
+  '((?t gnus-tmp-type ?s)
+    (?i gnus-tmp-info ?s)
+    (?d gnus-tmp-details ?s)
+    (?D gnus-tmp-pressed-details ?s)))
+
+(defvar gnus-mime-security-button-commands
+  '((gnus-article-press-button "\r" "Show Detail")
+    (undefined "v")
+    (undefined "t")
+    (undefined "C")
+    (gnus-mime-security-save-part "o" "Save...")
+    (undefined "\C-o")
+    (undefined "r")
+    (undefined "d")
+    (undefined "c")
+    (undefined "i")
+    (undefined "E")
+    (undefined "e")
+    (undefined "p")
+    (gnus-mime-security-pipe-part "|" "Pipe To Command...")
+    (undefined ".")))
+
+(defvar gnus-mime-security-button-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map gnus-mouse-2 'gnus-article-push-button)
+    (define-key map gnus-down-mouse-3 'gnus-mime-security-button-menu)
+    (dolist (c gnus-mime-security-button-commands)
+      (define-key map (cadr c) (car c)))
+    map))
+
+(easy-menu-define
+  gnus-mime-security-button-menu gnus-mime-security-button-map
+  "Security button menu."
+  `("Security Part"
+    ,@(delq nil
+           (mapcar (lambda (c)
+                     (unless (eq (car c) 'undefined)
+                       (vector (caddr c) (car c) :active t)))
+                   gnus-mime-security-button-commands))))
+
+(defun gnus-mime-security-button-menu (event prefix)
+  "Construct a context-sensitive menu of security commands."
+  (interactive "e\nP")
+  (save-window-excursion
+    (let ((pos (event-start event)))
+      (select-window (posn-window pos))
+      (goto-char (posn-point pos))
+      (gnus-article-check-buffer)
+      (popup-menu gnus-mime-security-button-menu nil prefix))))
+
+(defvar gnus-mime-security-details-buffer nil)
+
+(defvar gnus-mime-security-button-pressed nil)
+
+(defvar gnus-mime-security-show-details-inline t
+  "If non-nil, show details in the article buffer.")
+
+(defun gnus-mime-security-verify-or-decrypt (handle)
+  (mm-remove-parts (cdr handle))
+  (let ((region (mm-handle-multipart-ctl-parameter handle 'gnus-region))
+       point (inhibit-read-only t))
+    (if region
+       (goto-char (car region)))
+    (setq 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))))
+    (gnus-mime-display-security handle)
+    (when region
+      (delete-region (point) (cdr region))
+      (set-marker (car region) nil)
+      (set-marker (cdr region) nil))
+    (goto-char point)))
+
+(defun gnus-mime-security-show-details (handle)
+  (let ((details (mm-handle-multipart-ctl-parameter handle 'gnus-details)))
+    (if (not details)
+       (gnus-message 5 "No details.")
+      (if gnus-mime-security-show-details-inline
+         (let ((gnus-mime-security-button-pressed
+                (not (get-text-property (point) 'gnus-mime-details)))
+               (gnus-mime-security-button-line-format
+                (get-text-property (point) 'gnus-line-format))
+               (inhibit-read-only t))
+           (forward-char -1)
+           (while (eq (get-text-property (point) 'gnus-line-format)
+                      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))))
+       ;; Not inlined.
+       (if (gnus-buffer-live-p gnus-mime-security-details-buffer)
+           (with-current-buffer gnus-mime-security-details-buffer
+             (erase-buffer)
+             t)
+         (setq gnus-mime-security-details-buffer
+               (gnus-get-buffer-create "*MIME Security Details*")))
+       (with-current-buffer gnus-mime-security-details-buffer
+         (insert details)
+         (goto-char (point-min)))
+       (pop-to-buffer gnus-mime-security-details-buffer)))))
+
+(defun gnus-mime-security-press-button (handle)
+  (save-excursion
+    (if (mm-handle-multipart-ctl-parameter handle 'gnus-info)
+       (gnus-mime-security-show-details handle)
+      (gnus-mime-security-verify-or-decrypt handle))))
+
+(defun gnus-insert-mime-security-button (handle &optional _displayed)
+  (let* ((protocol (mm-handle-multipart-ctl-parameter handle 'protocol))
+        (gnus-tmp-type
+         (concat
+          (or (nth 2 (assoc protocol mm-verify-function-alist))
+              (nth 2 (assoc protocol mm-decrypt-function-alist))
+              "Unknown")
+          (if (equal (car handle) "multipart/signed")
+              " Signed" " Encrypted")
+          " Part"))
+        (gnus-tmp-info
+         (or (mm-handle-multipart-ctl-parameter handle 'gnus-info)
+             "Undecided"))
+        (gnus-tmp-details
+         (mm-handle-multipart-ctl-parameter handle 'gnus-details))
+        gnus-tmp-pressed-details
+        b e)
+    (setq gnus-tmp-details
+         (if gnus-tmp-details
+             (concat "\n" gnus-tmp-details)
+           ""))
+    (setq gnus-tmp-pressed-details
+         (if gnus-mime-security-button-pressed gnus-tmp-details ""))
+    (unless (bolp)
+      (insert "\n"))
+    (setq b (point))
+    (gnus-eval-format
+     gnus-mime-security-button-line-format
+     gnus-mime-security-button-line-format-alist
+     `(keymap ,gnus-mime-security-button-map
+        gnus-callback gnus-mime-security-press-button
+        gnus-line-format ,gnus-mime-security-button-line-format
+        gnus-mime-details ,gnus-mime-security-button-pressed
+        article-type annotation
+        gnus-data ,handle))
+    (setq e (if (bolp)
+               ;; Exclude a newline.
+               (1- (point))
+             (point)))
+    (when gnus-article-button-face
+      (overlay-put (make-overlay b e nil t)
+                  'face gnus-article-button-face))
+    (widget-convert-button
+     'link b e
+     :mime-handle handle
+     :action 'gnus-widget-press-button
+     :button-keymap gnus-mime-security-button-map
+     :help-echo
+     (lambda (_widget)
+       ;; Needed to properly clear the message due to a bug in
+       ;; wid-edit (XEmacs only).
+       (when (boundp 'help-echo-owns-message)
+        (setq help-echo-owns-message t))
+       (format
+       "%S: show detail; %S: more options"
+       (aref gnus-mouse-2 0)
+       (aref gnus-down-mouse-3 0))))))
+
+(defun gnus-mime-display-security (handle)
+  (save-restriction
+    (narrow-to-region (point) (point))
+    (unless (gnus-unbuttonized-mime-type-p (car handle))
+      (gnus-insert-mime-security-button handle))
+    (gnus-mime-display-part (cadr handle))
+    (unless (bolp)
+      (insert "\n"))
+    (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 (point-min-marker) (point-max-marker)))
+    (goto-char (point-max))))
+
+(defun gnus-mime-security-run-function (function)
+  "Run FUNCTION with the security part under point."
+  (gnus-article-check-buffer)
+  (let ((data (get-text-property (point) 'gnus-data))
+       buffer handle)
+    (when (and (stringp (car-safe data))
+              (setq buffer (mm-handle-multipart-original-buffer data))
+              (setq handle (cadr data)))
+      (if (bufferp (mm-handle-buffer handle))
+         (progn
+           (setq handle (cons buffer (copy-sequence (cdr handle))))
+           (mm-handle-set-undisplayer handle nil))
+       (setq handle (mm-make-handle
+                     buffer
+                     (mm-handle-multipart-ctl-parameter handle 'protocol)
+                     nil nil nil nil nil nil)))
+      (funcall function handle))))
+
+(defun gnus-mime-security-save-part ()
+  "Save the security part under point."
+  (interactive)
+  (gnus-mime-security-run-function 'mm-save-part))
+
+(defun gnus-mime-security-pipe-part ()
+  "Pipe the security part under point to a process."
+  (interactive)
+  (gnus-mime-security-run-function 'mm-pipe-part))
+
+(gnus-ems-redefine)
+
+(provide 'gnus-art)
+
+(run-hooks 'gnus-art-load-hook)
+
+;;; gnus-art.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-async.el b/xemacs-packages/gnus/lisp/gnus-async.el
new file mode 100644 (file)
index 0000000..a140825
--- /dev/null
@@ -0,0 +1,395 @@
+;;; gnus-async.el --- asynchronous support for Gnus
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'gnus)
+(require 'gnus-sum)
+(require 'nntp)
+
+(defgroup gnus-asynchronous nil
+  "Support for asynchronous operations."
+  :group 'gnus)
+
+(defcustom gnus-use-article-prefetch 30
+  "*If non-nil, prefetch articles in groups that allow this.
+If a number, prefetch only that many articles forward;
+if t, prefetch as many articles as possible."
+  :group 'gnus-asynchronous
+  :type '(choice (const :tag "off" nil)
+                (const :tag "all" t)
+                (integer :tag "some" 0)))
+
+(defcustom gnus-asynchronous nil
+  "*If nil, inhibit all Gnus asynchronicity.
+If non-nil, let the other asynch variables be heeded."
+  :group 'gnus-asynchronous
+  :type 'boolean)
+
+(defcustom gnus-prefetched-article-deletion-strategy '(read exit)
+  "List of symbols that say when to remove articles from the prefetch buffer.
+Possible values in this list are `read', which means that
+articles are removed as they are read, and `exit', which means
+that all articles belonging to a group are removed on exit
+from that group."
+  :group 'gnus-asynchronous
+  :type '(set (const read) (const exit)))
+
+(defcustom gnus-use-header-prefetch nil
+  "*If non-nil, prefetch the headers to the next group."
+  :group 'gnus-asynchronous
+  :type 'boolean)
+
+(defcustom gnus-async-prefetch-article-p 'gnus-async-unread-p
+  "Function called to say whether an article should be prefetched or not.
+The function is called with one parameter -- the article data.
+It should return non-nil if the article is to be prefetched."
+  :group 'gnus-asynchronous
+  :type 'function)
+
+(defcustom gnus-async-post-fetch-function nil
+  "Function called after an article has been prefetched.
+The function will be called narrowed to the region of the article
+that was fetched."
+  :version "24.1"
+  :group 'gnus-asynchronous
+  :type '(choice (const nil) function))
+
+;;; Internal variables.
+
+(defvar gnus-async-prefetch-article-buffer " *Async Prefetch Article*")
+(defvar gnus-async-article-alist nil)
+(defvar gnus-async-article-semaphore '(nil))
+(defvar gnus-async-fetch-list nil)
+(defvar gnus-async-hashtb nil)
+(defvar gnus-async-current-prefetch-group nil)
+(defvar gnus-async-current-prefetch-article nil)
+(defvar gnus-async-timer nil)
+
+(defvar gnus-async-prefetch-headers-buffer " *Async Prefetch Headers*")
+(defvar gnus-async-header-prefetched nil)
+
+;;; Utility functions.
+
+(defun gnus-group-asynchronous-p (group)
+  "Say whether GROUP is fetched from a server that supports asynchronicity."
+  (gnus-asynchronous-p (gnus-find-method-for-group group)))
+
+;;; Somewhat bogus semaphores.
+
+(defun gnus-async-get-semaphore (semaphore)
+  "Wait until SEMAPHORE is released."
+  (while (/= (length (nconc (symbol-value semaphore) (list nil))) 2)
+    (sleep-for 1)))
+
+(defun gnus-async-release-semaphore (semaphore)
+  "Release SEMAPHORE."
+  (setcdr (symbol-value semaphore) nil))
+
+(defmacro gnus-async-with-semaphore (&rest forms)
+  `(unwind-protect
+       (progn
+        (gnus-async-get-semaphore 'gnus-async-article-semaphore)
+        ,@forms)
+     (gnus-async-release-semaphore 'gnus-async-article-semaphore)))
+
+(put 'gnus-async-with-semaphore 'lisp-indent-function 0)
+(put 'gnus-async-with-semaphore 'edebug-form-spec '(body))
+
+;;;
+;;; Article prefetch
+;;;
+
+(gnus-add-shutdown 'gnus-async-close 'gnus)
+(defun gnus-async-close ()
+  (gnus-kill-buffer gnus-async-prefetch-article-buffer)
+  (gnus-kill-buffer gnus-async-prefetch-headers-buffer)
+  (setq gnus-async-hashtb nil
+       gnus-async-article-alist nil
+       gnus-async-header-prefetched nil))
+
+(defun gnus-async-set-buffer ()
+  (nnheader-set-temp-buffer gnus-async-prefetch-article-buffer t)
+  (unless gnus-async-hashtb
+    (setq gnus-async-hashtb (gnus-make-hashtable 1023))))
+
+(defun gnus-async-halt-prefetch ()
+  "Stop prefetching."
+  (setq gnus-async-fetch-list nil))
+
+(defun gnus-async-prefetch-next (group article summary)
+  "Possibly prefetch several articles starting with the article after ARTICLE."
+  (when (and (gnus-buffer-live-p summary)
+            gnus-asynchronous
+            (gnus-group-asynchronous-p group))
+    (with-current-buffer gnus-summary-buffer
+      (let ((next (caadr (gnus-data-find-list article))))
+       (when next
+         (if (not (fboundp 'run-with-idle-timer))
+             ;; This is either an older Emacs or XEmacs, so we
+             ;; do this, which leads to slightly slower article
+             ;; buffer display.
+             (gnus-async-prefetch-article group next summary)
+           (when gnus-async-timer
+             (ignore-errors
+               (nnheader-cancel-timer 'gnus-async-timer)))
+           (setq gnus-async-timer
+                 (run-with-idle-timer
+                  0.1 nil 'gnus-async-prefetch-article
+                  group next summary))))))))
+
+(defun gnus-async-prefetch-article (group article summary &optional next)
+  "Possibly prefetch several articles starting with ARTICLE."
+  (if (not (gnus-buffer-live-p summary))
+      (gnus-async-with-semaphore
+       (setq gnus-async-fetch-list nil))
+    (when (and gnus-asynchronous
+              (gnus-alive-p))
+      (when next
+       (gnus-async-with-semaphore
+         (pop gnus-async-fetch-list)))
+      (let ((do-fetch next)
+           (do-message t))             ;(eq major-mode 'gnus-summary-mode)))
+       (when (and (gnus-group-asynchronous-p group)
+                  (gnus-buffer-live-p summary)
+                  (or (not next)
+                      gnus-async-fetch-list))
+         (gnus-async-with-semaphore
+           (unless next
+             (setq do-fetch (not gnus-async-fetch-list))
+             ;; Nix out any outstanding requests.
+             (setq gnus-async-fetch-list nil)
+             ;; Fill in the new list.
+             (let ((n gnus-use-article-prefetch)
+                   (data (gnus-data-find-list article))
+                   d)
+               (while (and (setq d (pop data))
+                           (if (numberp n)
+                               (natnump (decf n))
+                             n))
+                 (unless (or (gnus-async-prefetched-article-entry
+                              group (setq article (gnus-data-number d)))
+                             (not (natnump article))
+                             (not (funcall gnus-async-prefetch-article-p d)))
+                   ;; Not already fetched -- so we add it to the list.
+                   (push article gnus-async-fetch-list)))
+               (setq gnus-async-fetch-list
+                     (nreverse gnus-async-fetch-list))))
+
+           (when do-fetch
+             (setq article (car gnus-async-fetch-list))))
+
+         (when (and do-fetch article)
+           ;; We want to fetch some more articles.
+           (with-current-buffer summary
+             (let (mark)
+               (gnus-async-set-buffer)
+               (goto-char (point-max))
+               (setq mark (point-marker))
+               (let ((nnheader-callback-function
+                      (gnus-make-async-article-function
+                       group article mark summary next))
+                     (nntp-server-buffer
+                      (get-buffer gnus-async-prefetch-article-buffer)))
+                 (when do-message
+                   (gnus-message 9 "Prefetching article %d in group %s"
+                                 article group))
+                 (setq gnus-async-current-prefetch-group group)
+                 (setq gnus-async-current-prefetch-article article)
+                 (gnus-request-article article group))))))))))
+
+(defun gnus-make-async-article-function (group article mark summary next)
+  "Return a callback function."
+  `(lambda (arg)
+     (gnus-async-article-callback arg ,group ,article ,mark ,summary ,next)))
+
+(defun gnus-async-article-callback (arg group article mark summary next)
+  "Function called when an async article is done being fetched."
+  (save-excursion
+    (setq gnus-async-current-prefetch-article nil)
+    (when arg
+      (gnus-async-set-buffer)
+      (save-excursion
+       (save-restriction
+         (narrow-to-region mark (point-max))
+         ;; Put the articles into the agent, if they aren't already.
+         (when (and gnus-agent
+                    (gnus-agent-group-covered-p group))
+           (save-restriction
+             (narrow-to-region mark (point-max))
+             (gnus-agent-store-article article group)))
+         ;; Prefetch images for the groups that want that.
+         (when (fboundp 'gnus-html-prefetch-images)
+           (gnus-html-prefetch-images summary))
+         (when gnus-async-post-fetch-function
+           (funcall gnus-async-post-fetch-function summary))))
+      (gnus-async-with-semaphore
+       (setq
+        gnus-async-article-alist
+        (cons (list (intern (format "%s-%d" group article)
+                            gnus-async-hashtb)
+                    mark (point-max-marker)
+                    group article)
+              gnus-async-article-alist))))
+    (if (not (gnus-buffer-live-p summary))
+       (gnus-async-with-semaphore
+         (setq gnus-async-fetch-list nil))
+      (gnus-async-prefetch-article group next summary t))))
+
+(defun gnus-async-unread-p (data)
+  "Return non-nil if DATA represents an unread article."
+  (gnus-data-unread-p data))
+
+(defun gnus-async-request-fetched-article (group article buffer)
+  "See whether we have ARTICLE from GROUP and put it in BUFFER."
+  (when (numberp article)
+    (when (and (equal group gnus-async-current-prefetch-group)
+              (eq article gnus-async-current-prefetch-article))
+      (gnus-async-wait-for-article article))
+    (let ((entry (gnus-async-prefetched-article-entry group article)))
+      (when entry
+       (save-excursion
+         (gnus-async-set-buffer)
+         (copy-to-buffer buffer (cadr entry) (caddr entry))
+         ;; Remove the read article from the prefetch buffer.
+         (when (memq 'read gnus-prefetched-article-deletion-strategy)
+           (gnus-async-delete-prefetched-entry entry))
+         t)))))
+
+(defun gnus-async-wait-for-article (article)
+  "Wait until ARTICLE is no longer the currently-being-fetched article."
+  (save-excursion
+    (gnus-async-set-buffer)
+    (let ((proc (nntp-find-connection (current-buffer)))
+         (nntp-server-buffer (current-buffer))
+         (nntp-have-messaged nil)
+         (tries 0))
+      (when proc
+       (condition-case nil
+           ;; FIXME: we could stop waiting after some
+           ;; timeout, but this is the wrong place to do it.
+           ;; rather than checking time-spent-waiting, we
+           ;; should check time-since-last-output, which
+           ;; needs to be done in nntp.el.
+           (while (eq article gnus-async-current-prefetch-article)
+             (incf tries)
+             (when (nntp-accept-process-output proc)
+               (setq tries 0))
+             (when (and (not nntp-have-messaged)
+                        (= tries 3))
+               (gnus-message 5 "Waiting for async article...")
+               (setq nntp-have-messaged t)))
+         (quit
+          ;; if the user interrupted on a slow/hung connection,
+          ;; do something friendly.
+          (when (> tries 3)
+            (setq gnus-async-current-prefetch-article nil))
+          (signal 'quit nil)))
+       (when nntp-have-messaged
+         (gnus-message 5 ""))))))
+
+(defun gnus-async-delete-prefetched-entry (entry)
+  "Delete ENTRY from buffer and alist."
+  (ignore-errors
+    (delete-region (cadr entry) (caddr entry))
+    (set-marker (cadr entry) nil)
+    (set-marker (caddr entry) nil))
+  (gnus-async-with-semaphore
+    (setq gnus-async-article-alist
+         (delq entry gnus-async-article-alist))
+    (unintern (car entry) gnus-async-hashtb)))
+
+(defun gnus-async-prefetch-remove-group (group)
+  "Remove all articles belonging to GROUP from the prefetch buffer."
+  (when (and (gnus-group-asynchronous-p group)
+            (memq 'exit gnus-prefetched-article-deletion-strategy))
+    (save-excursion
+      (gnus-async-set-buffer)
+      (dolist (entry gnus-async-article-alist)
+       (when (equal group (nth 3 entry))
+         (gnus-async-delete-prefetched-entry entry))))))
+
+(defun gnus-async-prefetched-article-entry (group article)
+  "Return the entry for ARTICLE in GROUP if it has been prefetched."
+  (let ((entry (save-excursion
+                (gnus-async-set-buffer)
+                (assq (intern-soft (format "%s-%d" group article)
+                                   gnus-async-hashtb)
+                      gnus-async-article-alist))))
+    ;; Perhaps something has emptied the buffer?
+    (if (and entry
+            (= (cadr entry) (caddr entry)))
+       (progn
+         (ignore-errors
+           (set-marker (cadr entry) nil)
+           (set-marker (caddr entry) nil))
+         (setq gnus-async-article-alist
+               (delq entry gnus-async-article-alist))
+         nil)
+      entry)))
+
+;;;
+;;; Header prefetch
+;;;
+
+(defun gnus-async-prefetch-headers (group)
+  "Prefetch the headers for group GROUP."
+  (save-excursion
+    (let (unread)
+      (when (and gnus-use-header-prefetch
+                gnus-asynchronous
+                (gnus-group-asynchronous-p group)
+                (listp gnus-async-header-prefetched)
+                (setq unread (gnus-list-of-unread-articles group)))
+       ;; Mark that a fetch is in progress.
+       (setq gnus-async-header-prefetched t)
+       (nnheader-set-temp-buffer gnus-async-prefetch-headers-buffer t)
+       (erase-buffer)
+       (let ((nntp-server-buffer (current-buffer))
+             (nnheader-callback-function
+              `(lambda (arg)
+                 (setq gnus-async-header-prefetched
+                       ,(cons group unread)))))
+         (gnus-retrieve-headers unread group gnus-fetch-old-headers))))))
+
+(defun gnus-async-retrieve-fetched-headers (articles group)
+  "See whether we have prefetched headers."
+  (when (and gnus-use-header-prefetch
+            (gnus-group-asynchronous-p group)
+            (listp gnus-async-header-prefetched)
+            (equal group (car gnus-async-header-prefetched))
+            (equal articles (cdr gnus-async-header-prefetched)))
+    (save-excursion
+      (nnheader-set-temp-buffer gnus-async-prefetch-headers-buffer t)
+      (nntp-decode-text)
+      (copy-to-buffer nntp-server-buffer (point-min) (point-max))
+      (erase-buffer)
+      (setq gnus-async-header-prefetched nil)
+      t)))
+
+(provide 'gnus-async)
+
+;;; gnus-async.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-bcklg.el b/xemacs-packages/gnus/lisp/gnus-bcklg.el
new file mode 100644 (file)
index 0000000..b7a6365
--- /dev/null
@@ -0,0 +1,155 @@
+;;; gnus-bcklg.el --- backlog functions for Gnus
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'gnus)
+
+;;;
+;;; Buffering of read articles.
+;;;
+
+(defvar gnus-backlog-buffer " *Gnus Backlog*")
+(defvar gnus-backlog-articles nil)
+(defvar gnus-backlog-hashtb nil)
+
+(defun gnus-backlog-buffer ()
+  "Return the backlog buffer."
+  (or (get-buffer gnus-backlog-buffer)
+      (with-current-buffer (gnus-get-buffer-create gnus-backlog-buffer)
+       (buffer-disable-undo)
+       (setq buffer-read-only t)
+       (get-buffer gnus-backlog-buffer))))
+
+(defun gnus-backlog-setup ()
+  "Initialize backlog variables."
+  (unless gnus-backlog-hashtb
+    (setq gnus-backlog-hashtb (gnus-make-hashtable 1024))))
+
+(gnus-add-shutdown 'gnus-backlog-shutdown 'gnus)
+
+(defun gnus-backlog-shutdown ()
+  "Clear all backlog variables and buffers."
+  (interactive)
+  (when (get-buffer gnus-backlog-buffer)
+    (gnus-kill-buffer gnus-backlog-buffer))
+  (setq gnus-backlog-hashtb nil
+       gnus-backlog-articles nil))
+
+(defun gnus-backlog-enter-article (group number buffer)
+  (when (and (numberp number)
+            (not (gnus-virtual-group-p group)))
+    (gnus-backlog-setup)
+    (let ((ident (intern (concat group ":" (int-to-string number))
+                        gnus-backlog-hashtb))
+         b)
+      (if (memq ident gnus-backlog-articles)
+         ()                            ; It's already kept.
+      ;; Remove the oldest article, if necessary.
+       (and (numberp gnus-keep-backlog)
+            (>= (length gnus-backlog-articles) gnus-keep-backlog)
+          (gnus-backlog-remove-oldest-article))
+       (push ident gnus-backlog-articles)
+       ;; Insert the new article.
+       (with-current-buffer (gnus-backlog-buffer)
+         (let (buffer-read-only)
+           (goto-char (point-max))
+           (unless (bolp)
+             (insert "\n"))
+           (setq b (point))
+           (insert-buffer-substring buffer)
+           ;; Tag the beginning of the article with the ident.
+           (if (> (point-max) b)
+             (gnus-put-text-property b (1+ b) 'gnus-backlog ident)
+             (gnus-error 3 "Article %d is blank" number))))))))
+
+(defun gnus-backlog-remove-oldest-article ()
+  (with-current-buffer (gnus-backlog-buffer)
+    (goto-char (point-min))
+    (if (zerop (buffer-size))
+       ()                              ; The buffer is empty.
+      (let ((ident (get-text-property (point) 'gnus-backlog))
+           buffer-read-only)
+       ;; Remove the ident from the list of articles.
+       (when ident
+         (setq gnus-backlog-articles (delq ident gnus-backlog-articles)))
+       ;; Delete the article itself.
+       (delete-region
+        (point) (next-single-property-change
+                 (1+ (point)) 'gnus-backlog nil (point-max)))))))
+
+(defun gnus-backlog-remove-article (group number)
+  "Remove article NUMBER in GROUP from the backlog."
+  (when (numberp number)
+    (gnus-backlog-setup)
+    (let ((ident (intern (concat group ":" (int-to-string number))
+                        gnus-backlog-hashtb))
+         beg end)
+      (when (memq ident gnus-backlog-articles)
+       ;; It was in the backlog.
+       (with-current-buffer (gnus-backlog-buffer)
+         (let (buffer-read-only)
+           (when (setq beg (text-property-any
+                            (point-min) (point-max) 'gnus-backlog
+                            ident))
+             ;; Find the end (i. e., the beginning of the next article).
+             (setq end
+                   (next-single-property-change
+                    (1+ beg) 'gnus-backlog (current-buffer) (point-max)))
+             (delete-region beg end)
+             ;; Return success.
+             t))
+         (setq gnus-backlog-articles (delq ident gnus-backlog-articles)))))))
+
+(defun gnus-backlog-request-article (group number &optional buffer)
+  (when (and (numberp number)
+            (not (gnus-virtual-group-p group)))
+    (gnus-backlog-setup)
+    (let ((ident (intern (concat group ":" (int-to-string number))
+                        gnus-backlog-hashtb))
+         beg end)
+      (when (memq ident gnus-backlog-articles)
+       ;; It was in the backlog.
+       (with-current-buffer (gnus-backlog-buffer)
+         (if (not (setq beg (text-property-any
+                             (point-min) (point-max) 'gnus-backlog
+                             ident)))
+             ;; It wasn't in the backlog after all.
+             (ignore
+              (setq gnus-backlog-articles (delq ident gnus-backlog-articles)))
+           ;; Find the end (i. e., the beginning of the next article).
+           (setq end
+                 (next-single-property-change
+                  (1+ beg) 'gnus-backlog (current-buffer) (point-max)))))
+       (with-current-buffer (or (current-buffer) buffer)
+         (let ((buffer-read-only nil))
+           (erase-buffer)
+           (insert-buffer-substring gnus-backlog-buffer beg end)))
+       t))))
+
+(provide 'gnus-bcklg)
+
+;;; gnus-bcklg.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-bookmark.el b/xemacs-packages/gnus/lisp/gnus-bookmark.el
new file mode 100644 (file)
index 0000000..1a082c2
--- /dev/null
@@ -0,0 +1,822 @@
+;;; gnus-bookmark.el --- Bookmarks in Gnus
+
+;; Copyright (C) 2006-2016 Free Software Foundation, Inc.
+
+;; Author: Bastien Guerry <bzg AT altern DOT org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This file implements real bookmarks for Gnus, closely following the way
+;; `bookmark.el' handles bookmarks.  Most of the code comes from
+;; `bookmark.el'.
+;;
+;; Set a Gnus bookmark:
+;; M-x `gnus-bookmark-set' from the summary buffer.
+;;
+;; Jump to a Gnus bookmark:
+;; M-x `gnus-bookmark-jump'.
+;;
+;; Display a list of bookmarks
+;; M-x `gnus-bookmark-bmenu-list'.
+;;
+
+;;; Todo:
+
+;; - add tags to bookmarks
+;; - don't write file each time a bookmark is created
+;; - better annotation interactive buffer
+;; - edit annotation in gnus-bookmark-bmenu
+;; - sort gnus-bookmark-buffer by author/subject/date/group/message-id
+;; - auto-bmk-name customizable format
+;; - renaming bookmarks in gnus-bookmark-bmenu-list
+;; - better (formatted string) display in bmenu-list
+
+;; - Integrate the `gnus-summary-*-bookmark' functionality
+;; - Initialize defcustoms from corresponding `bookmark.el' variables?
+
+;;; Code:
+
+(require 'gnus-sum)
+
+;; FIXME: should avoid using C-c (no?)
+;; (define-key gnus-summary-mode-map "\C-crm" 'gnus-bookmark-set)
+;; (define-key global-map "\C-crb" 'gnus-bookmark-jump)
+;; (define-key global-map "\C-crj" 'gnus-bookmark-jump)
+;; (define-key global-map "\C-crl" 'gnus-bookmark-bmenu-list)
+
+;; FIXME: Add keybindings, see
+;; http://thread.gmane.org/gmane.emacs.gnus.general/63101/focus=63379
+;; http://thread.gmane.org/v9fxx9fkm4.fsf@marauder.physik.uni-ulm.de
+
+;; FIXME: Check if `gnus-bookmark.el' should use
+;; `bookmark-make-cell-function'.
+;; Cf. http://article.gmane.org/gmane.emacs.gnus.general/66076
+
+(defgroup gnus-bookmark nil
+  "Setting, annotation and jumping to Gnus bookmarks."
+  :group 'gnus)
+
+(defcustom gnus-bookmark-default-file
+  (cond
+   ;; Backward compatibility with previous versions:
+   ((file-exists-p "~/.gnus.bmk") "~/.gnus.bmk")
+   (t (nnheader-concat gnus-directory "bookmarks.el")))
+  "The default Gnus bookmarks file."
+  :type 'string
+  :group 'gnus-bookmark)
+
+(defcustom gnus-bookmark-file-coding-system
+  (if (mm-coding-system-p 'iso-2022-7bit)
+      'iso-2022-7bit)
+  "Coding system used for writing Gnus bookmark files."
+  :type '(symbol :tag "Coding system")
+  :group 'gnus-bookmark)
+
+(defcustom gnus-bookmark-sort-flag t
+  "Non-nil means Gnus bookmarks are sorted by bookmark names.
+Otherwise they will be displayed in LIFO order (that is,
+most recently set ones come first, oldest ones come last)."
+  :type 'boolean
+  :group 'gnus-bookmark)
+
+(defcustom gnus-bookmark-bmenu-toggle-infos t
+  "Non-nil means show details when listing Gnus bookmarks.
+List of details is defined in `gnus-bookmark-bookmark-inline-details'.
+This may result in truncated bookmark names.  To disable this, put the
+following in your `.emacs' file:
+
+\(setq gnus-bookmark-bmenu-toggle-infos nil)"
+  :type 'boolean
+  :group 'gnus-bookmark)
+
+(defcustom gnus-bookmark-bmenu-file-column 30
+  "Column at which to display details in a buffer listing Gnus bookmarks.
+You can toggle whether details are shown with \\<gnus-bookmark-bmenu-mode-map>\\[gnus-bookmark-bmenu-toggle-infos]."
+  :type 'integer
+  :group 'gnus-bookmark)
+
+(defcustom gnus-bookmark-use-annotations nil
+  "If non-nil, ask for an annotation when setting a bookmark."
+  :type 'boolean
+  :group 'gnus-bookmark)
+
+(defcustom gnus-bookmark-bookmark-inline-details '(author)
+  "Details to be shown with `gnus-bookmark-bmenu-toggle-infos'.
+The default value is \(subject)."
+  :type '(list :tag "Gnus bookmark details"
+              (set :inline t
+                   (const :tag "Author" author)
+                   (const :tag "Subject" subject)
+                   (const :tag "Date" date)
+                   (const :tag "Group" group)
+                   (const :tag "Message-id" message-id)))
+  :group 'gnus-bookmark)
+
+(defcustom gnus-bookmark-bookmark-details
+  '(author subject date group annotation)
+  "Details to be shown with `gnus-bookmark-bmenu-show-details'.
+The default value is \(author subject date group annotation)."
+  :type '(list :tag "Gnus bookmark details"
+              (set :inline t
+                   (const :tag "Author" author)
+                   (const :tag "Subject" subject)
+                   (const :tag "Date" date)
+                   (const :tag "Group" group)
+                   (const :tag "Message-id" message-id)
+                   (const :tag "Annotation" annotation)))
+  :group 'gnus-bookmark)
+
+(defface gnus-bookmark-menu-heading
+  '((t (:inherit font-lock-type-face)))
+  "Face used to highlight the heading in Gnus bookmark menu buffers."
+  :version "23.1" ;; No Gnus
+  :group 'gnus-bookmark)
+
+(defconst gnus-bookmark-end-of-version-stamp-marker
+  "-*- End Of Bookmark File Format Version Stamp -*-\n"
+  "This string marks the end of the version stamp in a Gnus bookmark file.")
+
+(defconst gnus-bookmark-file-format-version 0
+  "The current version of the format used by bookmark files.
+You should never need to change this.")
+
+(defvar gnus-bookmark-alist ()
+  "Association list of Gnus bookmarks and their records.
+The format of the alist is
+
+     (BMK1 BMK2 ...)
+
+where each BMK is of the form
+
+\(NAME
+  (group . GROUP)
+  (message-id . MESSAGE-ID)
+  (author . AUTHOR)
+  (date . DATE)
+  (subject . SUBJECT)
+  (annotation . ANNOTATION))
+
+So the cdr of each bookmark is an alist too.")
+
+(defmacro gnus-bookmark-mouse-available-p ()
+  "Return non-nil if a mouse is available."
+  (if (featurep 'xemacs)
+      '(device-on-window-system-p)
+    '(display-mouse-p)))
+
+(defun gnus-bookmark-remove-properties (string)
+  "Remove all text properties from STRING."
+  (set-text-properties 0 (length string) nil string)
+  string)
+
+;;;###autoload
+(defun gnus-bookmark-set ()
+  "Set a bookmark for this article."
+  (interactive)
+  (gnus-bookmark-maybe-load-default-file)
+  (if (or (not (derived-mode-p 'gnus-summary-mode))
+         (not gnus-article-current))
+      (error "Please select an article in the Gnus summary buffer")
+    (let* ((group (car gnus-article-current))
+          (article (cdr gnus-article-current))
+          (header (gnus-summary-article-header article))
+          (author (mail-header-from header))
+          (message-id (mail-header-id header))
+          (date (mail-header-date header))
+          (subject (gnus-summary-subject-string))
+          (bmk-name (gnus-bookmark-set-bookmark-name group author subject))
+          ;; Maybe ask for annotation
+          (annotation
+           (if gnus-bookmark-use-annotations
+                (read-from-minibuffer
+                 (format "Annotation for %s: " bmk-name)) "")))
+      ;; Set the bookmark list
+      (setq gnus-bookmark-alist
+           (cons
+            (list (gnus-bookmark-remove-properties bmk-name)
+                  (gnus-bookmark-make-record
+                   group message-id author date subject annotation))
+            gnus-bookmark-alist))))
+  (gnus-bookmark-bmenu-surreptitiously-rebuild-list)
+  (gnus-bookmark-write-file))
+
+(defun gnus-bookmark-make-record
+  (group message-id author date subject annotation)
+  "Return the record part of a new bookmark, given GROUP MESSAGE-ID AUTHOR DATE SUBJECT and ANNOTATION."
+  (let ((the-record
+        `((group . ,(gnus-bookmark-remove-properties group))
+          (message-id . ,(gnus-bookmark-remove-properties message-id))
+          (author . ,(gnus-bookmark-remove-properties author))
+          (date . ,(gnus-bookmark-remove-properties date))
+          (subject . ,(gnus-bookmark-remove-properties subject))
+          (annotation . ,(gnus-bookmark-remove-properties annotation)))))
+    the-record))
+
+(defun gnus-bookmark-set-bookmark-name (group author subject)
+  "Set bookmark name from GROUP AUTHOR and SUBJECT."
+  (let* ((subject (split-string subject))
+        (default-name-0 ;; Should be merged with -1?
+          (concat (car (nreverse (delete "" (split-string group "[\\.:]"))))
+                  "-" (car (split-string author))
+                  "-" (car subject) "-" (cadr subject)))
+        (default-name-1
+          ;; Strip "[]" chars from the bookmark name:
+          (gnus-replace-in-string default-name-0 "[]_[]" ""))
+        (name (read-from-minibuffer
+               (format "Set bookmark (%s): " default-name-1)
+               nil nil nil nil
+               default-name-1)))
+    (if (string-equal name "")
+       default-name-1
+      name)))
+
+(defun gnus-bookmark-write-file ()
+  "Write currently defined Gnus bookmarks into `gnus-bookmark-default-file'."
+  (interactive)
+  (save-excursion
+    (save-window-excursion
+      ;; Avoid warnings?
+      ;; (message "Saving Gnus bookmarks to file %s..." gnus-bookmark-default-file)
+      (set-buffer (get-buffer-create  " *Gnus bookmarks*"))
+      (erase-buffer)
+      (gnus-bookmark-insert-file-format-version-stamp)
+      (pp gnus-bookmark-alist (current-buffer))
+      (condition-case nil
+         (let ((coding-system-for-write gnus-bookmark-file-coding-system))
+           (write-region (point-min) (point-max)
+                         gnus-bookmark-default-file))
+       (file-error (message "Can't write %s"
+                            gnus-bookmark-default-file)))
+      (kill-buffer (current-buffer))
+      (message
+       "Saving Gnus bookmarks to file %s...done"
+       gnus-bookmark-default-file))))
+
+(defun gnus-bookmark-insert-file-format-version-stamp ()
+  "Insert text indicating current version of Gnus bookmark file format."
+  (insert
+   (format ";;;; Gnus Bookmark Format Version %d %s;;;;\n"
+          gnus-bookmark-file-format-version
+          (if gnus-bookmark-file-coding-system
+              (concat "-*- coding: "
+                      (symbol-name gnus-bookmark-file-coding-system)
+                      "; -*- ")
+            "")))
+  (insert ";;; This format is meant to be slightly human-readable;\n"
+          ";;; nevertheless, you probably don't want to edit it.\n"
+          ";;; "
+          gnus-bookmark-end-of-version-stamp-marker))
+
+;;;###autoload
+(defun gnus-bookmark-jump (&optional bmk-name)
+  "Jump to a Gnus bookmark (BMK-NAME)."
+  (interactive)
+  (gnus-bookmark-maybe-load-default-file)
+  (let* ((bookmark (or bmk-name
+                       (gnus-completing-read "Jump to bookmarked article"
+                                             (mapcar 'car gnus-bookmark-alist))))
+        (bmk-record (cadr (assoc bookmark gnus-bookmark-alist)))
+        (group (cdr (assoc 'group bmk-record)))
+        (message-id (cdr (assoc 'message-id bmk-record))))
+    (when group
+      (unless (get-buffer gnus-group-buffer)
+       (gnus-no-server))
+      (gnus-activate-group group)
+      (gnus-group-quick-select-group 0 group))
+    (if message-id
+      (or (gnus-summary-goto-article message-id nil 'force)
+         (if (fboundp 'gnus-summary-insert-cached-articles)
+             (progn
+               (gnus-summary-insert-cached-articles)
+               (gnus-summary-goto-article message-id nil 'force))
+           (message "Message could not be found."))))))
+
+(defvar gnus-bookmark-already-loaded nil)
+
+(defun gnus-bookmark-alist-from-buffer ()
+  "Return a `gnus-bookmark-alist' from the current buffer.
+The buffer must of course contain Gnus bookmark format information.
+Does not care from where in the buffer it is called, and does not
+affect point."
+  (save-excursion
+    (goto-char (point-min))
+    (if (search-forward
+        gnus-bookmark-end-of-version-stamp-marker nil t)
+        (read (current-buffer))
+      ;; Else no hope of getting information here.
+      (error "Not Gnus bookmark format"))))
+
+(defun gnus-bookmark-load (file)
+  "Load Gnus bookmarks from FILE (which must be in bookmark format)."
+  (interactive
+   (list (read-file-name
+          (format "Load Gnus bookmarks from: (%s) "
+                  gnus-bookmark-default-file)
+          "~/" gnus-bookmark-default-file 'confirm)))
+  (setq file (expand-file-name file))
+  (if (file-readable-p file)
+      (save-excursion
+       (save-window-excursion
+         (set-buffer (let ((enable-local-variables nil))
+                        (find-file-noselect file)))
+          (goto-char (point-min))
+         (let ((blist (gnus-bookmark-alist-from-buffer)))
+           (if (listp blist)
+               (progn (setq gnus-bookmark-already-loaded t)
+                      (setq gnus-bookmark-alist blist))
+             (error "Not Gnus bookmark format")))))))
+
+(defun gnus-bookmark-maybe-load-default-file ()
+  "Maybe load Gnus bookmarks in `gnus-bookmark-alist'."
+  (and (not gnus-bookmark-already-loaded)
+       (null gnus-bookmark-alist)
+       (file-readable-p (expand-file-name gnus-bookmark-default-file))
+       (gnus-bookmark-load gnus-bookmark-default-file)))
+
+(defun gnus-bookmark-maybe-sort-alist ()
+  "Return the gnus-bookmark-alist for display.
+If the gnus-bookmark-sort-flag is non-nil, then return a sorted
+copy of the alist."
+  (when gnus-bookmark-sort-flag
+    (setq gnus-bookmark-alist
+         (sort (copy-alist gnus-bookmark-alist)
+               (function
+                (lambda (x y) (string-lessp (car x) (car y))))))))
+
+;;;###autoload
+(defun gnus-bookmark-bmenu-list ()
+  "Display a list of existing Gnus bookmarks.
+The list is displayed in a buffer named `*Gnus Bookmark List*'.
+The leftmost column displays a D if the bookmark is flagged for
+deletion, or > if it is flagged for displaying."
+  (interactive)
+  (gnus-bookmark-maybe-load-default-file)
+  (if (gmm-called-interactively-p 'any)
+      (switch-to-buffer (get-buffer-create "*Gnus Bookmark List*"))
+    (set-buffer (get-buffer-create "*Gnus Bookmark List*")))
+  (let ((inhibit-read-only t)
+       alist name start end)
+    (erase-buffer)
+    (insert "% Gnus Bookmark\n- --------\n")
+    (add-text-properties (point-min) (point)
+                        '(font-lock-face gnus-bookmark-menu-heading))
+    ;; sort before displaying
+    (gnus-bookmark-maybe-sort-alist)
+    ;; Display gnus bookmarks
+    (setq alist gnus-bookmark-alist)
+    (while alist
+      (setq name (gnus-bookmark-name-from-full-record (pop alist)))
+      ;; if a Gnus bookmark has an annotation, prepend a "*"
+      ;; in the list of bookmarks.
+      (insert (if (member (gnus-bookmark-get-annotation name) (list nil ""))
+                 "  "
+               " *"))
+      (if (gnus-bookmark-mouse-available-p)
+         (add-text-properties
+          (prog1
+              (point)
+            (insert name))
+          (let ((end (point)))
+            (prog2
+                (re-search-backward "[^ \t]")
+                (1+ (point))
+              (goto-char end)
+              (insert "\n")))
+          `(mouse-face highlight follow-link t
+                       help-echo ,(format "%s: go to this article"
+                                          (aref gnus-mouse-2 0))))
+       (insert name "\n")))
+    (goto-char (point-min))
+    (forward-line 2)
+    (gnus-bookmark-bmenu-mode)
+    (if gnus-bookmark-bmenu-toggle-infos
+       (gnus-bookmark-bmenu-toggle-infos t))))
+
+(defun gnus-bookmark-bmenu-surreptitiously-rebuild-list ()
+  "Rebuild the Bookmark List if it exists.
+Don't affect the buffer ring order."
+  (if (get-buffer "*Gnus Bookmark List*")
+      (save-excursion
+        (save-window-excursion
+          (gnus-bookmark-bmenu-list)))))
+
+(defun gnus-bookmark-get-annotation (bookmark)
+  "Return the annotation of Gnus BOOKMARK, or nil if none."
+  (cdr (assq 'annotation (gnus-bookmark-get-bookmark-record bookmark))))
+
+(defun gnus-bookmark-get-bookmark (bookmark)
+  "Return the full entry for Gnus BOOKMARK in `gnus-bookmark-alist'.
+If BOOKMARK is not a string, return nil."
+  (when (stringp bookmark)
+    (assoc bookmark gnus-bookmark-alist)))
+
+(defun gnus-bookmark-get-bookmark-record (bookmark)
+  "Return the guts of the entry for Gnus BOOKMARK in `gnus-bookmark-alist'.
+That is, all information but the name."
+  (car (cdr (gnus-bookmark-get-bookmark bookmark))))
+
+(defun gnus-bookmark-name-from-full-record (full-record)
+  "Return name of FULL-RECORD (an alist element instead of a string)."
+  (car full-record))
+
+(defvar gnus-bookmark-bmenu-bookmark-column nil)
+(defvar gnus-bookmark-bmenu-hidden-bookmarks ())
+(defvar gnus-bookmark-bmenu-mode-map nil)
+
+(if gnus-bookmark-bmenu-mode-map
+    nil
+  (setq gnus-bookmark-bmenu-mode-map (make-keymap))
+  (suppress-keymap gnus-bookmark-bmenu-mode-map t)
+  (define-key gnus-bookmark-bmenu-mode-map "q" (if (fboundp 'quit-window)
+                                                  'quit-window
+                                                'bury-buffer))
+  (define-key gnus-bookmark-bmenu-mode-map "\C-m" 'gnus-bookmark-bmenu-select)
+  (define-key gnus-bookmark-bmenu-mode-map "v" 'gnus-bookmark-bmenu-select)
+  (define-key gnus-bookmark-bmenu-mode-map "d" 'gnus-bookmark-bmenu-delete)
+  (define-key gnus-bookmark-bmenu-mode-map "k" 'gnus-bookmark-bmenu-delete)
+  (define-key gnus-bookmark-bmenu-mode-map "\C-d" 'gnus-bookmark-bmenu-delete-backwards)
+  (define-key gnus-bookmark-bmenu-mode-map "x" 'gnus-bookmark-bmenu-execute-deletions)
+  (define-key gnus-bookmark-bmenu-mode-map " " 'next-line)
+  (define-key gnus-bookmark-bmenu-mode-map "n" 'next-line)
+  (define-key gnus-bookmark-bmenu-mode-map "p" 'previous-line)
+  (define-key gnus-bookmark-bmenu-mode-map "\177" 'gnus-bookmark-bmenu-backup-unmark)
+  (define-key gnus-bookmark-bmenu-mode-map "?" 'describe-mode)
+  (define-key gnus-bookmark-bmenu-mode-map "u" 'gnus-bookmark-bmenu-unmark)
+  (define-key gnus-bookmark-bmenu-mode-map "m" 'gnus-bookmark-bmenu-mark)
+  (define-key gnus-bookmark-bmenu-mode-map "l" 'gnus-bookmark-bmenu-load)
+  (define-key gnus-bookmark-bmenu-mode-map "s" 'gnus-bookmark-bmenu-save)
+  (define-key gnus-bookmark-bmenu-mode-map "t" 'gnus-bookmark-bmenu-toggle-infos)
+  (define-key gnus-bookmark-bmenu-mode-map "a" 'gnus-bookmark-bmenu-show-details)
+  (define-key gnus-bookmark-bmenu-mode-map gnus-mouse-2
+    'gnus-bookmark-bmenu-select-by-mouse))
+
+;; Bookmark Buffer Menu mode is suitable only for specially formatted
+;; data.
+(put 'gnus-bookmark-bmenu-mode 'mode-class 'special)
+
+;; Been to lazy to use gnus-bookmark-save...
+(defalias 'gnus-bookmark-bmenu-save 'gnus-bookmark-write-file)
+
+(define-derived-mode gnus-bookmark-bmenu-mode fundamental-mode "Bookmark Menu"
+  "Major mode for editing a list of Gnus bookmarks.
+Each line describes one of the bookmarks in Gnus.
+Letters do not insert themselves; instead, they are commands.
+Gnus bookmarks names preceded by a \"*\" have annotations.
+\\<gnus-bookmark-bmenu-mode-map>
+\\[gnus-bookmark-bmenu-mark] -- mark bookmark to be displayed.
+\\[gnus-bookmark-bmenu-select] -- select bookmark of line point is on.
+  Also show bookmarks marked using m in other windows.
+\\[gnus-bookmark-bmenu-toggle-infos] -- toggle displaying of details (they may obscure long bookmark names).
+\\[gnus-bookmark-bmenu-locate] -- display (in minibuffer) location of this bookmark.
+\\[gnus-bookmark-bmenu-rename] -- rename this bookmark (prompts for new name).
+\\[gnus-bookmark-bmenu-delete] -- mark this bookmark to be deleted, and move down.
+\\[gnus-bookmark-bmenu-delete-backwards] -- mark this bookmark to be deleted, and move up.
+\\[gnus-bookmark-bmenu-execute-deletions] -- delete bookmarks marked with `\\[gnus-bookmark-bmenu-delete]'.
+\\[gnus-bookmark-bmenu-load] -- load in a file of bookmarks (prompts for file.)
+\\[gnus-bookmark-bmenu-save] -- load in a file of bookmarks (prompts for file.)
+\\[gnus-bookmark-bmenu-unmark] -- remove all kinds of marks from current line.
+  With prefix argument, also move up one line.
+\\[gnus-bookmark-bmenu-backup-unmark] -- back up a line and remove marks.
+\\[gnus-bookmark-bmenu-show-details] -- show the annotation, if it exists, for the current bookmark
+  in another buffer.
+\\[gnus-bookmark-bmenu-show-all-annotations] -- show the annotations of all bookmarks in another buffer.
+\\[gnus-bookmark-bmenu-edit-annotation] -- edit the annotation for the current bookmark."
+  (setq truncate-lines t)
+  (setq buffer-read-only t))
+
+;; avoid compilation warnings
+(defvar gnus-bookmark-bmenu-toggle-infos nil)
+
+(defun gnus-bookmark-bmenu-toggle-infos (&optional show)
+  "Toggle whether details are shown in the Gnus bookmark list.
+Optional argument SHOW means show them unconditionally."
+  (interactive)
+  (cond
+   (show
+    (setq gnus-bookmark-bmenu-toggle-infos nil)
+    (gnus-bookmark-bmenu-show-infos)
+    (setq gnus-bookmark-bmenu-toggle-infos t))
+   (gnus-bookmark-bmenu-toggle-infos
+    (gnus-bookmark-bmenu-hide-infos)
+    (setq gnus-bookmark-bmenu-toggle-infos nil))
+   (t
+    (gnus-bookmark-bmenu-show-infos)
+    (setq gnus-bookmark-bmenu-toggle-infos t))))
+
+(defun gnus-bookmark-bmenu-show-infos (&optional force)
+  "Show infos in bmenu, maybe FORCE display of infos."
+  (if (and (not force) gnus-bookmark-bmenu-toggle-infos)
+      nil ;already shown, so do nothing
+    (save-excursion
+      (save-window-excursion
+        (goto-char (point-min))
+        (forward-line 2)
+        (setq gnus-bookmark-bmenu-hidden-bookmarks ())
+        (let ((inhibit-read-only t))
+          (while (< (point) (point-max))
+            (let ((bmrk (gnus-bookmark-bmenu-bookmark)))
+              (setq gnus-bookmark-bmenu-hidden-bookmarks
+                    (cons bmrk gnus-bookmark-bmenu-hidden-bookmarks))
+             (let ((start (point-at-eol)))
+               (move-to-column gnus-bookmark-bmenu-file-column t)
+               ;; Strip off `mouse-face' from the white spaces region.
+               (if (gnus-bookmark-mouse-available-p)
+                   (remove-text-properties start (point)
+                                           '(mouse-face nil help-echo nil))))
+             (delete-region (point) (progn (end-of-line) (point)))
+              (insert "  ")
+              ;; Pass the NO-HISTORY arg:
+              (gnus-bookmark-insert-details bmrk)
+              (forward-line 1))))))))
+
+(defun gnus-bookmark-insert-details (bmk-name)
+  "Insert the details of the article associated with BMK-NAME."
+  (let ((start (point)))
+    (prog1
+       (insert (gnus-bookmark-get-details
+                bmk-name
+                gnus-bookmark-bookmark-inline-details))
+      (if (gnus-bookmark-mouse-available-p)
+         (add-text-properties
+          start
+          (save-excursion (re-search-backward
+                           "[^ \t]")
+                                              (1+ (point)))
+          `(mouse-face highlight
+            follow-link t
+            help-echo ,(format "%s: go to this article"
+                               (aref gnus-mouse-2 0))))))))
+
+(defun gnus-bookmark-kill-line (&optional newline-too)
+  "Kill from point to end of line.
+If optional arg NEWLINE-TOO is non-nil, delete the newline too.
+Does not affect the kill ring."
+  (delete-region (point) (point-at-eol))
+  (if (and newline-too (looking-at "\n"))
+      (delete-char 1)))
+
+(defun gnus-bookmark-get-details (bmk-name details-list)
+  "Get details for a Gnus BMK-NAME depending on DETAILS-LIST."
+  (let ((details (cadr (assoc bmk-name gnus-bookmark-alist))))
+    (mapconcat
+     (lambda (info)
+       (cdr (assoc info details)))
+     details-list " | ")))
+
+(defun gnus-bookmark-bmenu-hide-infos (&optional force)
+  "Hide infos in bmenu, maybe FORCE."
+  (if (and (not force) gnus-bookmark-bmenu-toggle-infos)
+      ;; nothing to hide if above is nil
+      (save-excursion
+        (save-window-excursion
+          (goto-char (point-min))
+          (forward-line 2)
+          (setq gnus-bookmark-bmenu-hidden-bookmarks
+                (nreverse gnus-bookmark-bmenu-hidden-bookmarks))
+          (save-excursion
+            (goto-char (point-min))
+            (search-forward "Gnus Bookmark")
+            (backward-word 2)
+            (setq gnus-bookmark-bmenu-bookmark-column (current-column)))
+          (save-excursion
+            (let ((inhibit-read-only t))
+              (while gnus-bookmark-bmenu-hidden-bookmarks
+                (move-to-column gnus-bookmark-bmenu-bookmark-column t)
+                (gnus-bookmark-kill-line)
+               (let ((start (point)))
+                 (insert (car gnus-bookmark-bmenu-hidden-bookmarks))
+                 (if (gnus-bookmark-mouse-available-p)
+                     (add-text-properties
+                      start
+                      (save-excursion (re-search-backward
+                                       "[^ \t]")
+                                      (1+ (point)))
+                      `(mouse-face highlight
+                        follow-link t
+                        help-echo
+                        ,(format "%s: go to this bookmark in other window"
+                                 (aref gnus-mouse-2 0))))))
+                (setq gnus-bookmark-bmenu-hidden-bookmarks
+                      (cdr gnus-bookmark-bmenu-hidden-bookmarks))
+                (forward-line 1))))))))
+
+(defun gnus-bookmark-bmenu-check-position ()
+  "Return non-nil if on a line with a bookmark.
+The actual value returned is gnus-bookmark-alist.  Else
+reposition and try again, else return nil."
+  (cond ((< (count-lines (point-min) (point)) 2)
+         (goto-char (point-min))
+         (forward-line 2)
+         gnus-bookmark-alist)
+        ((and (bolp) (eobp))
+         (beginning-of-line 0)
+         gnus-bookmark-alist)
+        (t
+         gnus-bookmark-alist)))
+
+(defun gnus-bookmark-bmenu-bookmark ()
+  "Return a string which is bookmark of this line."
+  (if (gnus-bookmark-bmenu-check-position)
+      (save-excursion
+        (save-window-excursion
+          (goto-char (point-min))
+          (search-forward "Gnus Bookmark")
+          (backward-word 2)
+          (setq gnus-bookmark-bmenu-bookmark-column (current-column)))))
+  (if gnus-bookmark-bmenu-toggle-infos
+      (gnus-bookmark-bmenu-hide-infos))
+  (save-excursion
+    (save-window-excursion
+      (beginning-of-line)
+      (forward-char gnus-bookmark-bmenu-bookmark-column)
+      (prog1
+          (buffer-substring-no-properties (point)
+                            (progn
+                              (end-of-line)
+                              (point)))
+        ;; well, this is certainly crystal-clear:
+        (if gnus-bookmark-bmenu-toggle-infos
+            (gnus-bookmark-bmenu-toggle-infos t))))))
+
+(defun gnus-bookmark-show-details (bookmark)
+  "Display the annotation for BOOKMARK in a buffer."
+  (let ((record (gnus-bookmark-get-bookmark-record bookmark))
+       (old-buf (current-buffer))
+       (details gnus-bookmark-bookmark-details)
+       detail)
+    (save-excursion
+      (pop-to-buffer (get-buffer-create "*Gnus Bookmark Annotation*") t)
+      (erase-buffer)
+      (while details
+       (setq detail (pop details))
+       (unless (equal (cdr (assoc detail record)) "")
+         (insert (symbol-name detail) ": " (cdr (assoc detail record)) "\n")))
+      (goto-char (point-min))
+      (pop-to-buffer old-buf))))
+
+(defun gnus-bookmark-bmenu-show-details ()
+  "Show the annotation for the current bookmark in another window."
+  (interactive)
+  (let ((bookmark (gnus-bookmark-bmenu-bookmark)))
+    (if (gnus-bookmark-bmenu-check-position)
+       (gnus-bookmark-show-details bookmark))))
+
+(defun gnus-bookmark-bmenu-mark ()
+  "Mark bookmark on this line to be displayed by \\<gnus-bookmark-bmenu-mode-map>\\[gnus-bookmark-bmenu-select]."
+  (interactive)
+  (beginning-of-line)
+  (if (gnus-bookmark-bmenu-check-position)
+      (let ((inhibit-read-only t))
+        (delete-char 1)
+        (insert ?>)
+        (forward-line 1)
+        (gnus-bookmark-bmenu-check-position))))
+
+(defun gnus-bookmark-bmenu-unmark (&optional backup)
+  "Cancel all requested operations on bookmark on this line and move down.
+Optional BACKUP means move up."
+  (interactive "P")
+  (beginning-of-line)
+  (if (gnus-bookmark-bmenu-check-position)
+      (progn
+        (let ((inhibit-read-only t))
+          (delete-char 1)
+          ;; any flags to reset according to circumstances?  How about a
+          ;; flag indicating whether this bookmark is being visited?
+          ;; well, we don't have this now, so maybe later.
+          (insert " "))
+        (forward-line (if backup -1 1))
+        (gnus-bookmark-bmenu-check-position))))
+
+(defun gnus-bookmark-bmenu-backup-unmark ()
+  "Move up and cancel all requested operations on bookmark on line above."
+  (interactive)
+  (forward-line -1)
+  (if (gnus-bookmark-bmenu-check-position)
+      (progn
+        (gnus-bookmark-bmenu-unmark)
+        (forward-line -1)
+        (gnus-bookmark-bmenu-check-position))))
+
+(defun gnus-bookmark-bmenu-delete ()
+  "Mark Gnus bookmark on this line to be deleted.
+To carry out the deletions that you've marked, use
+\\<gnus-bookmark-bmenu-mode-map>\\[gnus-bookmark-bmenu-execute-deletions]."
+  (interactive)
+  (beginning-of-line)
+  (if (gnus-bookmark-bmenu-check-position)
+      (let ((inhibit-read-only t))
+        (delete-char 1)
+        (insert ?D)
+        (forward-line 1)
+        (gnus-bookmark-bmenu-check-position))))
+
+(defun gnus-bookmark-bmenu-delete-backwards ()
+  "Mark bookmark on this line to be deleted, then move up one line.
+To carry out the deletions that you've marked, use
+\\<gnus-bookmark-bmenu-mode-map>\\[gnus-bookmark-bmenu-execute-deletions]."
+  (interactive)
+  (gnus-bookmark-bmenu-delete)
+  (forward-line -2)
+  (if (gnus-bookmark-bmenu-check-position)
+      (forward-line 1))
+  (gnus-bookmark-bmenu-check-position))
+
+(defun gnus-bookmark-bmenu-select ()
+  "Select this line's bookmark; also display bookmarks marked with `>'.
+You can mark bookmarks with the
+\\<gnus-bookmark-bmenu-mode-map>\\[gnus-bookmark-bmenu-mark]
+command."
+  (interactive)
+  (if (gnus-bookmark-bmenu-check-position)
+      (let ((bmrk (gnus-bookmark-bmenu-bookmark))
+            (menu (current-buffer)))
+        (goto-char (point-min))
+        (delete-other-windows)
+        (gnus-bookmark-jump bmrk)
+        (bury-buffer menu))))
+
+(defun gnus-bookmark-bmenu-select-by-mouse (event)
+  (interactive "e")
+  (mouse-set-point event)
+  (gnus-bookmark-bmenu-select))
+
+(defun gnus-bookmark-bmenu-load ()
+  "Load the Gnus bookmark file and rebuild the bookmark menu-buffer."
+  (interactive)
+  (if (gnus-bookmark-bmenu-check-position)
+      (save-excursion
+        (save-window-excursion
+          ;; This will call `gnus-bookmark-bmenu-list'
+          (call-interactively 'gnus-bookmark-load)))))
+
+(defun gnus-bookmark-bmenu-execute-deletions ()
+  "Delete Gnus bookmarks marked with \\<Buffer-menu-mode-map>\\[Buffer-menu-delete] commands."
+  (interactive)
+  (message "Deleting Gnus bookmarks...")
+  (let ((hide-em gnus-bookmark-bmenu-toggle-infos)
+        (o-point  (point))
+        (o-str    (save-excursion
+                    (beginning-of-line)
+                    (if (looking-at "^D")
+                        nil
+                      (buffer-substring
+                       (point)
+                       (progn (end-of-line) (point))))))
+        (o-col     (current-column)))
+    (if hide-em (gnus-bookmark-bmenu-hide-infos))
+    (setq gnus-bookmark-bmenu-toggle-infos nil)
+    (goto-char (point-min))
+    (forward-line 1)
+    (while (re-search-forward "^D" (point-max) t)
+      (gnus-bookmark-delete (gnus-bookmark-bmenu-bookmark) t)) ; pass BATCH arg
+    (gnus-bookmark-bmenu-list)
+    (setq gnus-bookmark-bmenu-toggle-infos hide-em)
+    (if gnus-bookmark-bmenu-toggle-infos
+        (gnus-bookmark-bmenu-toggle-infos t))
+    (if o-str
+        (progn
+          (goto-char (point-min))
+          (search-forward o-str)
+          (beginning-of-line)
+          (forward-char o-col))
+      (goto-char o-point))
+    (beginning-of-line)
+    (gnus-bookmark-write-file)
+    (message "Deleting bookmarks...done")))
+
+(defun gnus-bookmark-delete (bookmark &optional batch)
+  "Delete BOOKMARK from the bookmark list.
+Removes only the first instance of a bookmark with that name.  If
+there are one or more other bookmarks with the same name, they will
+not be deleted.  Defaults to the \"current\" bookmark \(that is, the
+one most recently used in this file, if any).
+Optional second arg BATCH means don't update the bookmark list buffer,
+probably because we were called from there."
+  (gnus-bookmark-maybe-load-default-file)
+  (let ((will-go (gnus-bookmark-get-bookmark bookmark)))
+    (setq gnus-bookmark-alist (delq will-go gnus-bookmark-alist)))
+  ;; Don't rebuild the list
+  (if batch
+      nil
+    (gnus-bookmark-bmenu-surreptitiously-rebuild-list)))
+
+(provide 'gnus-bookmark)
+
+;;; gnus-bookmark.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-cache.el b/xemacs-packages/gnus/lisp/gnus-cache.el
new file mode 100644 (file)
index 0000000..83ccc4f
--- /dev/null
@@ -0,0 +1,917 @@
+;;; gnus-cache.el --- cache interface for Gnus
+
+;; Copyright (C) 1995-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'gnus)
+(require 'gnus-sum)
+
+(eval-when-compile
+  (unless (fboundp 'gnus-agent-load-alist)
+    (defun gnus-agent-load-alist (group))))
+
+(defcustom gnus-cache-active-file
+  (expand-file-name "active" gnus-cache-directory)
+  "*The cache active file."
+  :group 'gnus-cache
+  :type 'file)
+
+(defcustom gnus-cache-enter-articles '(ticked dormant)
+  "Classes of articles to enter into the cache."
+  :group 'gnus-cache
+  :type '(set (const ticked) (const dormant) (const unread) (const read)))
+
+(defcustom gnus-cache-remove-articles '(read)
+  "Classes of articles to remove from the cache."
+  :group 'gnus-cache
+  :type '(set (const ticked) (const dormant) (const unread) (const read)))
+
+(defcustom gnus-cacheable-groups nil
+  "*Groups that match this regexp will be cached.
+
+If you only want to cache your nntp groups, you could set this
+variable to \"^nntp\".
+
+If a group matches both gnus-cacheable-groups and gnus-uncacheable-groups
+it's not cached."
+  :group 'gnus-cache
+  :type '(choice (const :tag "off" nil)
+                regexp))
+
+(defcustom gnus-uncacheable-groups nil
+  "*Groups that match this regexp will not be cached.
+
+If you want to avoid caching your nnml groups, you could set this
+variable to \"^nnml\".
+
+If a group matches both gnus-cacheable-groups and gnus-uncacheable-groups
+it's not cached."
+  :group 'gnus-cache
+  :type '(choice (const :tag "off" nil)
+                regexp))
+
+(defvar gnus-cache-overview-coding-system 'raw-text
+  "Coding system used on Gnus cache files.")
+
+(defvar gnus-cache-coding-system 'raw-text
+  "Coding system used on Gnus cache files.")
+
+\f
+
+;;; Internal variables.
+
+(defvar gnus-cache-removable-articles nil)
+(defvar gnus-cache-buffer nil)
+(defvar gnus-cache-active-hashtb nil)
+(defvar gnus-cache-active-altered nil)
+(defvar gnus-cache-total-fetched-hashtb nil)
+
+(declare-function nnvirtual-find-group-art "nnvirtual" (group article))
+
+(autoload 'nnml-generate-nov-databases-directory "nnml")
+(autoload 'nnvirtual-find-group-art "nnvirtual")
+
+\f
+
+;;; Functions called from Gnus.
+
+(defun gnus-cache-open ()
+  "Initialize the cache."
+  (when (or (file-exists-p gnus-cache-directory)
+           (and gnus-use-cache
+                (not (eq gnus-use-cache 'passive))))
+    (gnus-cache-read-active)))
+
+;; Complexities of byte-compiling make this kludge necessary.  Eeek.
+(ignore-errors
+  (gnus-add-shutdown 'gnus-cache-close 'gnus))
+
+(defun gnus-cache-close ()
+  "Shut down the cache."
+  (gnus-cache-write-active)
+  (gnus-cache-save-buffers)
+  (setq gnus-cache-active-hashtb nil))
+
+(defun gnus-cache-save-buffers ()
+  ;; save the overview buffer if it exists and has been modified
+  ;; delete empty cache subdirectories
+  (when gnus-cache-buffer
+    (let ((buffer (cdr gnus-cache-buffer))
+         (overview-file (gnus-cache-file-name
+                         (car gnus-cache-buffer) ".overview")))
+      ;; write the overview only if it was modified
+      (when (and (buffer-live-p buffer) (buffer-modified-p buffer))
+       (with-current-buffer buffer
+         (if (> (buffer-size) 0)
+             ;; Non-empty overview, write it to a file.
+             (let ((coding-system-for-write
+                    gnus-cache-overview-coding-system))
+               (gnus-write-buffer overview-file))
+           (let ((file-name-coding-system nnmail-pathname-coding-system))
+             ;; Empty overview file, remove it
+             (when (file-exists-p overview-file)
+               (delete-file overview-file))
+             ;; If possible, remove group's cache subdirectory.
+             (condition-case nil
+                 ;; FIXME: we can detect the error type and warn the user
+                 ;; of any inconsistencies (articles w/o nov entries?).
+                 ;; for now, just be conservative...delete only if safe -- sj
+                 (delete-directory (file-name-directory overview-file))
+               (error))))
+
+         (gnus-cache-update-overview-total-fetched-for
+          (car gnus-cache-buffer) overview-file)))
+      ;; Kill the buffer -- it's either unmodified or saved.
+      (gnus-kill-buffer buffer)
+      (setq gnus-cache-buffer nil))))
+
+(defun gnus-cache-possibly-enter-article
+  (group article ticked dormant unread &optional force)
+  (when (and (or force (not (eq gnus-use-cache 'passive)))
+            (numberp article)
+            (> article 0))             ; This might be a dummy article.
+    (let ((number article)
+         file headers lines-chars
+         (file-name-coding-system nnmail-pathname-coding-system))
+      ;; If this is a virtual group, we find the real group.
+      (when (gnus-virtual-group-p group)
+       (let ((result (nnvirtual-find-group-art
+                      (gnus-group-real-name group) article)))
+         (setq group (car result)
+               number (cdr result))))
+      (when (and number
+                (> number 0)           ; Reffed article.
+                (or force
+                    (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
+                                                group number)))))
+       ;; Possibly create the cache directory.
+       (gnus-make-directory (file-name-directory file))
+       ;; Save the article in the cache.
+       (if (file-exists-p file)
+           t                           ; The article already is saved.
+         (with-current-buffer nntp-server-buffer
+           (require 'gnus-art)
+           (let ((gnus-use-cache nil)
+                 (gnus-article-decode-hook nil))
+             (gnus-request-article-this-buffer number group))
+           (when (> (buffer-size) 0)
+             (let ((coding-system-for-write gnus-cache-coding-system))
+               (gnus-write-buffer file)
+               (gnus-cache-update-file-total-fetched-for group file))
+             (setq lines-chars (nnheader-get-lines-and-char))
+             (nnheader-remove-body)
+             (setq headers (nnheader-parse-naked-head))
+             (mail-header-set-number headers number)
+             (mail-header-set-lines headers (car lines-chars))
+             (mail-header-set-chars headers (cadr lines-chars))
+             (gnus-cache-change-buffer group)
+             (set-buffer (cdr gnus-cache-buffer))
+             (goto-char (point-max))
+             (forward-line -1)
+             (while (condition-case ()
+                        (when (not (bobp))
+                          (> (read (current-buffer)) number))
+                      (error
+                       ;; The line was malformed, so we just remove it!!
+                       (gnus-delete-line)
+                       t))
+               (forward-line -1))
+             (if (bobp)
+                 (if (not (eobp))
+                     (progn
+                       (beginning-of-line)
+                       (when (< (read (current-buffer)) number)
+                         (forward-line 1)))
+                   (beginning-of-line))
+               (forward-line 1))
+             (beginning-of-line)
+             (nnheader-insert-nov headers)
+             ;; Update the active info.
+             (set-buffer gnus-summary-buffer)
+             (gnus-cache-possibly-update-active group (cons number number))
+             (setq gnus-newsgroup-cached
+                   (gnus-add-to-sorted-list gnus-newsgroup-cached article))
+             (gnus-summary-update-secondary-mark article))
+           t))))))
+
+(defun gnus-cache-enter-remove-article (article)
+  "Mark ARTICLE for later possible removal."
+  (when article
+    (push article gnus-cache-removable-articles)))
+
+(defun gnus-cache-possibly-remove-articles ()
+  "Possibly remove some of the removable articles."
+  (if (not (gnus-virtual-group-p gnus-newsgroup-name))
+      (gnus-cache-possibly-remove-articles-1)
+    (let ((arts gnus-cache-removable-articles)
+         ga)
+      (while arts
+       (when (setq ga (nnvirtual-find-group-art
+                       (gnus-group-real-name gnus-newsgroup-name) (pop arts)))
+         (let ((gnus-cache-removable-articles (list (cdr ga)))
+               (gnus-newsgroup-name (car ga)))
+           (gnus-cache-possibly-remove-articles-1)))))
+    (setq gnus-cache-removable-articles nil)))
+
+(defun gnus-cache-possibly-remove-articles-1 ()
+  "Possibly remove some of the removable articles."
+  (when (gnus-cache-fully-p gnus-newsgroup-name)
+    (let ((cache-articles gnus-newsgroup-cached))
+      (gnus-cache-change-buffer gnus-newsgroup-name)
+      (dolist (article gnus-cache-removable-articles)
+       (when (memq article cache-articles)
+         ;; The article was in the cache, so we see whether we are
+         ;; supposed to remove it from the cache.
+         (gnus-cache-possibly-remove-article
+          article (memq article gnus-newsgroup-marked)
+          (memq article gnus-newsgroup-dormant)
+          (or (memq article gnus-newsgroup-unreads)
+              (memq article gnus-newsgroup-unselected))))))
+    ;; The overview file might have been modified, save it
+    ;; safe because we're only called at group exit anyway.
+    (gnus-cache-save-buffers)))
+
+(defun gnus-cache-request-article (article group)
+  "Retrieve ARTICLE in GROUP from the cache."
+  (let ((file (gnus-cache-file-name group article))
+       (buffer-read-only nil)
+       (file-name-coding-system nnmail-pathname-coding-system))
+    (when (file-exists-p file)
+      (erase-buffer)
+      (gnus-kill-all-overlays)
+      (let ((coding-system-for-read gnus-cache-coding-system))
+       (insert-file-contents file))
+      t)))
+
+(defun gnus-cache-possibly-alter-active (group active)
+  "Alter the ACTIVE info for GROUP to reflect the articles in the cache."
+  (when gnus-cache-active-hashtb
+    (let ((cache-active (gnus-gethash group gnus-cache-active-hashtb)))
+      (when cache-active
+       (when (< (car cache-active) (car active))
+         (setcar active (car cache-active)))
+       (when (> (cdr cache-active) (cdr active))
+         (setcdr active (cdr cache-active)))))))
+
+(defun gnus-cache-retrieve-headers (articles group &optional fetch-old)
+  "Retrieve the headers for ARTICLES in GROUP."
+  (let ((cached
+        (setq gnus-newsgroup-cached (gnus-cache-articles-in-group group))))
+    (if (not cached)
+       ;; No cached articles here, so we just retrieve them
+       ;; the normal way.
+       (let ((gnus-use-cache nil))
+         (gnus-retrieve-headers articles group fetch-old))
+      (let ((uncached-articles (gnus-sorted-difference articles cached))
+           (cache-file (gnus-cache-file-name group ".overview"))
+           type
+           (file-name-coding-system nnmail-pathname-coding-system))
+       ;; We first retrieve all the headers that we don't have in
+       ;; the cache.
+       (let ((gnus-use-cache nil))
+         (when uncached-articles
+           (setq type (and articles
+                           (gnus-retrieve-headers
+                            uncached-articles group fetch-old)))))
+       (gnus-cache-save-buffers)
+       ;; Then we insert the cached headers.
+       (save-excursion
+         (cond
+          ((not (file-exists-p cache-file))
+           ;; There are no cached headers.
+           type)
+          ((null type)
+           ;; There were no uncached headers (or retrieval was
+           ;; unsuccessful), so we use the cached headers exclusively.
+           (set-buffer nntp-server-buffer)
+           (erase-buffer)
+           (let ((coding-system-for-read
+                  gnus-cache-overview-coding-system))
+             (insert-file-contents cache-file))
+           'nov)
+          ((eq type 'nov)
+           ;; We have both cached and uncached NOV headers, so we
+           ;; braid them.
+           (gnus-cache-braid-nov group cached)
+           type)
+          (t
+           ;; We braid HEADs.
+           (gnus-cache-braid-heads group (gnus-sorted-intersection
+                                          cached articles))
+           type)))))))
+
+(defun gnus-cache-enter-article (&optional n)
+  "Enter the next N articles into the cache.
+If not given a prefix, use the process marked articles instead.
+Returns the list of articles entered."
+  (interactive "P")
+  (let (out)
+    (dolist (article (gnus-summary-work-articles n))
+      (gnus-summary-remove-process-mark article)
+      (if (natnump article)
+         (when (gnus-cache-possibly-enter-article
+                gnus-newsgroup-name article
+                nil nil nil t)
+            (setq gnus-newsgroup-undownloaded (delq article gnus-newsgroup-undownloaded))
+           (push article out))
+       (gnus-message 2 "Can't cache article %d" article))
+      (gnus-summary-update-download-mark article)
+      (gnus-summary-update-secondary-mark article))
+    (gnus-summary-next-subject 1)
+    (gnus-summary-position-point)
+    (nreverse out)))
+
+(defun gnus-cache-remove-article (&optional n)
+  "Remove the next N articles from the cache.
+If not given a prefix, use the process marked articles instead.
+Returns the list of articles removed."
+  (interactive "P")
+  (gnus-cache-change-buffer gnus-newsgroup-name)
+  (let (out)
+    (dolist (article (gnus-summary-work-articles n))
+      (gnus-summary-remove-process-mark article)
+      (when (gnus-cache-possibly-remove-article article nil nil nil t)
+        (when gnus-newsgroup-agentized
+          (let ((alist (gnus-agent-load-alist gnus-newsgroup-name)))
+            (unless (cdr (assoc article alist))
+              (setq gnus-newsgroup-undownloaded
+                    (gnus-add-to-sorted-list
+                     gnus-newsgroup-undownloaded article)))))
+       (push article out))
+      (gnus-summary-update-download-mark article)
+      (gnus-summary-update-secondary-mark article))
+    (gnus-summary-next-subject 1)
+    (gnus-summary-position-point)
+    (nreverse out)))
+
+(defun gnus-cached-article-p (article)
+  "Say whether ARTICLE is cached in the current group."
+  (memq article gnus-newsgroup-cached))
+
+(defun gnus-summary-insert-cached-articles ()
+  "Insert all the articles cached for this group into the current buffer."
+  (interactive)
+  (let ((gnus-verbose (max 6 gnus-verbose)))
+    (cond
+     ((not gnus-newsgroup-cached)
+      (gnus-message 3 "No cached articles for this group"))
+     ;; This is faster if there are few articles to insert.
+     ((< (length gnus-newsgroup-cached) 20)
+      (gnus-summary-goto-subjects gnus-newsgroup-cached))
+     (t
+      (gnus-summary-include-articles gnus-newsgroup-cached)))))
+
+(defun gnus-summary-limit-include-cached ()
+  "Limit the summary buffer to articles that are cached."
+  (interactive)
+  (let ((gnus-verbose (max 6 gnus-verbose)))
+    (if gnus-newsgroup-cached
+       (progn
+         (gnus-summary-limit gnus-newsgroup-cached)
+         (gnus-summary-position-point))
+      (gnus-message 3 "No cached articles for this group"))))
+
+;;; Internal functions.
+
+(defun gnus-cache-change-buffer (group)
+  (and gnus-cache-buffer
+       ;; See if the current group's overview cache has been loaded.
+       (or (string= group (car gnus-cache-buffer))
+          ;; Another overview cache is current, save it.
+          (gnus-cache-save-buffers)))
+  ;; if gnus-cache buffer is nil, create it
+  (unless gnus-cache-buffer
+    ;; Create cache buffer
+    (save-excursion
+      (setq gnus-cache-buffer
+           (cons group
+                 (set-buffer (gnus-get-buffer-create
+                              " *gnus-cache-overview*"))))
+      ;; Insert the contents of this group's cache overview.
+      (erase-buffer)
+      (let ((file (gnus-cache-file-name group ".overview"))
+           (file-name-coding-system nnmail-pathname-coding-system))
+       (when (file-exists-p file)
+         (nnheader-insert-file-contents file)))
+      ;; We have a fresh (empty/just loaded) buffer,
+      ;; mark it as unmodified to save a redundant write later.
+      (set-buffer-modified-p nil))))
+
+;; Return whether an article is a member of a class.
+(defun gnus-cache-member-of-class (class ticked dormant unread)
+  (or (and ticked (memq 'ticked class))
+      (and dormant (memq 'dormant class))
+      (and unread (memq 'unread class))
+      (and (not unread) (not ticked) (not dormant) (memq 'read class))))
+
+(defvar gnus-cache-decoded-group-names nil
+  "Alist of original group names and decoded group names.
+Decoding is done according to `gnus-group-name-charset-method-alist'
+or `gnus-group-name-charset-group-alist'.")
+
+(defvar gnus-cache-unified-group-names nil
+  "Alist of unified decoded group names and original group names.
+A group name is decoded according to
+`gnus-group-name-charset-method-alist' or
+`gnus-group-name-charset-group-alist' first, and is encoded and
+decoded again according to `nnmail-pathname-coding-system',
+`file-name-coding-system', or `default-file-name-coding-system'.
+
+It is used when asking for a original group name from a cache
+directory name, in which non-ASCII characters might have been unified
+into the ones of a certain charset particularly if the `utf-8' coding
+system for example was used.")
+
+(defun gnus-cache-decoded-group-name (group)
+  "Return a decoded group name of GROUP."
+  (or (cdr (assoc group gnus-cache-decoded-group-names))
+      (let ((decoded (gnus-group-decoded-name group))
+           (coding (or nnmail-pathname-coding-system
+                       (and (boundp 'file-name-coding-system)
+                            file-name-coding-system)
+                       (and (boundp 'default-file-name-coding-system)
+                            default-file-name-coding-system))))
+       (push (cons group decoded) gnus-cache-decoded-group-names)
+       (push (cons (mm-decode-coding-string
+                    (mm-encode-coding-string decoded coding)
+                    coding)
+                   group)
+             gnus-cache-unified-group-names)
+       decoded)))
+
+(defun gnus-cache-file-name (group article)
+  (setq group (gnus-cache-decoded-group-name group))
+  (expand-file-name
+   (if (stringp article) article (int-to-string article))
+   (file-name-as-directory
+    (expand-file-name
+     (nnheader-translate-file-chars
+      (if (gnus-use-long-file-name 'not-cache)
+         group
+       (let ((group (nnheader-replace-duplicate-chars-in-string
+                     (nnheader-replace-chars-in-string group ?/ ?_)
+                     ?. ?_)))
+         ;; Translate the first colon into a slash.
+         (when (string-match ":" group)
+                 (setq group (concat (substring group 0 (match-beginning 0))
+                                     "/" (substring group (match-end 0)))))
+         (nnheader-replace-chars-in-string group ?. ?/)))
+      t)
+     gnus-cache-directory))))
+
+(defun gnus-cache-update-article (group article)
+  "If ARTICLE is in the cache, remove it and re-enter it."
+  (gnus-cache-change-buffer group)
+  (when (gnus-cache-possibly-remove-article article nil nil nil t)
+    (let ((gnus-use-cache nil))
+      (gnus-cache-possibly-enter-article
+       gnus-newsgroup-name article
+       nil nil nil t))))
+
+(defun gnus-cache-possibly-remove-article (article ticked dormant unread
+                                                  &optional force)
+  "Possibly remove ARTICLE from the cache."
+  (let ((group gnus-newsgroup-name)
+       (number article)
+       file
+       (file-name-coding-system nnmail-pathname-coding-system))
+    ;; If this is a virtual group, we find the real group.
+    (when (gnus-virtual-group-p group)
+      (let ((result (nnvirtual-find-group-art
+                    (gnus-group-real-name group) article)))
+       (setq group (car result)
+             number (cdr result))))
+    (setq file (gnus-cache-file-name group number))
+    (when (and (file-exists-p file)
+              (or force
+                  (gnus-cache-member-of-class
+                   gnus-cache-remove-articles ticked dormant unread)))
+      (save-excursion
+       (gnus-cache-update-file-total-fetched-for group file t)
+       (delete-file file)
+
+       (set-buffer (cdr gnus-cache-buffer))
+       (goto-char (point-min))
+       (when (or (looking-at (concat (int-to-string number) "\t"))
+                 (search-forward (concat "\n" (int-to-string number) "\t")
+                                 (point-max) t))
+           (gnus-delete-line)))
+      (unless (setq gnus-newsgroup-cached
+                   (delq article gnus-newsgroup-cached))
+       (gnus-sethash gnus-newsgroup-name nil gnus-cache-active-hashtb)
+       (setq gnus-cache-active-altered t))
+      (gnus-summary-update-secondary-mark article)
+      t)))
+
+(defun gnus-cache-articles-in-group (group)
+  "Return a sorted list of cached articles in GROUP."
+  (let ((dir (file-name-directory (gnus-cache-file-name group 1)))
+       articles
+       (file-name-coding-system nnmail-pathname-coding-system))
+    (when (file-exists-p dir)
+      (setq articles
+           (sort (mapcar (lambda (name) (string-to-number name))
+                         (directory-files dir nil "^[0-9]+$" t))
+                 '<))
+      ;; Update the cache active file, just to synch more.
+      (if articles
+         (progn
+           (gnus-cache-update-active group (car articles) t)
+           (gnus-cache-update-active group (car (last articles))))
+       (when (gnus-gethash group gnus-cache-active-hashtb)
+         (gnus-sethash group nil gnus-cache-active-hashtb)
+         (setq gnus-cache-active-altered t)))
+      articles)))
+
+(defun gnus-cache-braid-nov (group cached &optional file)
+  (let ((cache-buf (gnus-get-buffer-create " *gnus-cache*"))
+       beg end)
+    (gnus-cache-save-buffers)
+    (with-current-buffer cache-buf
+      (erase-buffer)
+      (let ((coding-system-for-read gnus-cache-overview-coding-system)
+           (file-name-coding-system nnmail-pathname-coding-system))
+       (insert-file-contents
+        (or file (gnus-cache-file-name group ".overview"))))
+      (goto-char (point-min))
+      (insert "\n")
+      (goto-char (point-min)))
+    (set-buffer nntp-server-buffer)
+    (goto-char (point-min))
+    (while cached
+      (while (and (not (eobp))
+                 (< (read (current-buffer)) (car cached)))
+       (forward-line 1))
+      (beginning-of-line)
+      (set-buffer cache-buf)
+      (if (search-forward (concat "\n" (int-to-string (car cached)) "\t")
+                         nil t)
+         (setq beg (point-at-bol)
+               end (progn (end-of-line) (point)))
+       (setq beg nil))
+      (set-buffer nntp-server-buffer)
+      (when beg
+       (insert-buffer-substring cache-buf beg end)
+       (insert "\n"))
+      (setq cached (cdr cached)))
+    (kill-buffer cache-buf)))
+
+(defun gnus-cache-braid-heads (group cached)
+  (let ((cache-buf (gnus-get-buffer-create " *gnus-cache*")))
+    (with-current-buffer cache-buf
+      (erase-buffer))
+    (set-buffer nntp-server-buffer)
+    (goto-char (point-min))
+    (dolist (entry cached)
+      (while (and (not (eobp))
+                 (looking-at "2.. +\\([0-9]+\\) ")
+                 (< (progn (goto-char (match-beginning 1))
+                           (read (current-buffer)))
+                    entry))
+       (search-forward "\n.\n" nil 'move))
+      (beginning-of-line)
+      (set-buffer cache-buf)
+      (erase-buffer)
+      (let ((coding-system-for-read gnus-cache-coding-system)
+           (file-name-coding-system nnmail-pathname-coding-system))
+       (insert-file-contents (gnus-cache-file-name group entry)))
+      (goto-char (point-min))
+      (insert "220 ")
+      (princ (pop cached) (current-buffer))
+      (insert " Article retrieved.\n")
+      (search-forward "\n\n" nil 'move)
+      (delete-region (point) (point-max))
+      (forward-char -1)
+      (insert ".")
+      (set-buffer nntp-server-buffer)
+      (insert-buffer-substring cache-buf))
+    (kill-buffer cache-buf)))
+
+;;;###autoload
+(defun gnus-jog-cache ()
+  "Go through all groups and put the articles into the cache.
+
+Usage:
+$ emacs -batch -l ~/.emacs -l gnus -f gnus-jog-cache"
+  (interactive)
+  (let ((gnus-mark-article-hook nil)
+       (gnus-expert-user t)
+       (mail-sources nil)
+       (gnus-use-dribble-file nil)
+       (gnus-novice-user nil)
+       (gnus-large-newsgroup nil))
+    ;; Start Gnus.
+    (gnus)
+    ;; Go through all groups...
+    (gnus-group-mark-buffer)
+    (gnus-group-iterate nil
+      (lambda (group)
+       (let (gnus-auto-select-next)
+         (gnus-summary-read-group group nil t)
+         ;; ... and enter the articles into the cache.
+         (when (eq major-mode 'gnus-summary-mode)
+           (gnus-uu-mark-buffer)
+           (gnus-cache-enter-article)
+           (kill-buffer (current-buffer))))))))
+
+(defun gnus-cache-read-active (&optional force)
+  "Read the cache active file."
+  (gnus-make-directory gnus-cache-directory)
+  (if (or (not (file-exists-p gnus-cache-active-file))
+         (zerop (nth 7 (file-attributes gnus-cache-active-file)))
+         force)
+      ;; There is no active file, so we generate one.
+      (gnus-cache-generate-active)
+    ;; We simply read the active file.
+    (save-excursion
+      (gnus-set-work-buffer)
+      (nnheader-insert-file-contents gnus-cache-active-file)
+      (gnus-active-to-gnus-format
+       nil (setq gnus-cache-active-hashtb
+                (gnus-make-hashtable
+                 (count-lines (point-min) (point-max)))))
+      (setq gnus-cache-active-altered nil))))
+
+(defun gnus-cache-write-active (&optional force)
+  "Write the active hashtb to the active file."
+  (when (or force
+           (and gnus-cache-active-hashtb
+                gnus-cache-active-altered))
+    (gnus-write-active-file gnus-cache-active-file gnus-cache-active-hashtb t)
+    ;; 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."
+  (let ((active (gnus-gethash group gnus-cache-active-hashtb)))
+    (if (null active)
+       ;; We just create a new active entry for this group.
+       (gnus-sethash group (cons number number) gnus-cache-active-hashtb)
+      ;; Update the lower or upper bound.
+      (if low
+         (setcar active number)
+       (setcdr active number)))
+    ;; Mark the active hashtb as altered.
+    (setq gnus-cache-active-altered t)))
+
+;;;###autoload
+(defun gnus-cache-generate-active (&optional directory)
+  "Generate the cache active file."
+  (interactive)
+  (let* ((top (null directory))
+        (directory (expand-file-name (or directory gnus-cache-directory)))
+        (file-name-coding-system nnmail-pathname-coding-system)
+        (files (directory-files directory 'full))
+        (group
+         (if top
+             ""
+           (string-match
+            (concat "^" (regexp-quote
+                         (file-name-as-directory
+                          (expand-file-name gnus-cache-directory))))
+            (directory-file-name directory))
+           (nnheader-replace-chars-in-string
+            (substring (directory-file-name directory) (match-end 0))
+            ?/ ?.)))
+        nums alphs)
+    (when top
+      (gnus-message 5 "Generating the cache active file...")
+      (setq gnus-cache-active-hashtb (gnus-make-hashtable 123)))
+    (when (string-match "^\\(nn[^_]+\\)_" group)
+      (setq group (replace-match "\\1:" t nil group)))
+    ;; Separate articles from all other files and directories.
+    (while files
+      (if (string-match "^[0-9]+$" (file-name-nondirectory (car files)))
+         (push (string-to-number (file-name-nondirectory (pop files))) nums)
+       (push (pop files) alphs)))
+    ;; If we have nums, then this is probably a valid group.
+    (when (setq nums (sort nums '<))
+      ;; Use non-decoded group name.
+      ;; FIXME: this is kind of a workaround.  The active file should
+      ;; be updated at the time articles are cached.  It will make
+      ;; `gnus-cache-unified-group-names' needless.
+      (gnus-sethash (or (cdr (assoc group gnus-cache-unified-group-names))
+                       group)
+                   (cons (car nums) (gnus-last-element nums))
+                   gnus-cache-active-hashtb))
+    ;; Go through all the other files.
+    (dolist (file alphs)
+      (when (and (file-directory-p file)
+                (not (string-match "^\\."
+                                   (file-name-nondirectory file))))
+       ;; We descend directories.
+       (gnus-cache-generate-active file)))
+    ;; Write the new active file.
+    (when top
+      (gnus-cache-write-active t)
+      (gnus-message 5 "Generating the cache active file...done"))))
+
+;;;###autoload
+(defun gnus-cache-generate-nov-databases (dir)
+  "Generate NOV files recursively starting in DIR."
+  (interactive (list gnus-cache-directory))
+  (gnus-cache-close)
+  (let ((nnml-generate-active-function 'identity))
+    (nnml-generate-nov-databases-directory dir))
+
+  (setq gnus-cache-total-fetched-hashtb nil)
+
+  (gnus-cache-open))
+
+(defun gnus-cache-move-cache (dir)
+  "Move the cache tree to somewhere else."
+  (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)))))))
+
+;;;###autoload
+(defun gnus-cache-rename-group (old-group new-group)
+  "Rename OLD-GROUP as NEW-GROUP.
+Always updates the cache, even when disabled, as the old cache
+files would corrupt Gnus when the cache was next enabled.  It
+depends on the caller to determine whether group renaming is
+supported."
+  (let ((old-dir (gnus-cache-file-name old-group ""))
+       (new-dir (gnus-cache-file-name new-group ""))
+       (file-name-coding-system nnmail-pathname-coding-system))
+    (gnus-rename-file old-dir new-dir t))
+
+  (gnus-cache-rename-group-total-fetched-for old-group new-group)
+
+  (let ((no-save gnus-cache-active-hashtb))
+    (unless gnus-cache-active-hashtb
+      (gnus-cache-read-active))
+    (let* ((old-group-hash-value
+           (gnus-gethash old-group gnus-cache-active-hashtb))
+          (new-group-hash-value
+           (gnus-gethash new-group gnus-cache-active-hashtb))
+          (delta
+           (or old-group-hash-value new-group-hash-value)))
+      (gnus-sethash new-group old-group-hash-value gnus-cache-active-hashtb)
+      (gnus-sethash old-group nil gnus-cache-active-hashtb)
+
+      (if no-save
+         (setq gnus-cache-active-altered delta)
+       (gnus-cache-write-active delta)))))
+
+;;;###autoload
+(defun gnus-cache-delete-group (group)
+  "Delete GROUP from the cache.
+Always updates the cache, even when disabled, as the old cache
+files would corrupt gnus when the cache was next enabled.
+Depends upon the caller to determine whether group deletion is
+supported."
+  (let ((dir (gnus-cache-file-name group ""))
+       (file-name-coding-system nnmail-pathname-coding-system))
+    (gnus-delete-directory dir))
+
+  (gnus-cache-delete-group-total-fetched-for group)
+
+  (let ((no-save gnus-cache-active-hashtb))
+    (unless gnus-cache-active-hashtb
+      (gnus-cache-read-active))
+    (let* ((group-hash-value (gnus-gethash group gnus-cache-active-hashtb)))
+      (gnus-sethash group nil gnus-cache-active-hashtb)
+
+      (if no-save
+         (setq gnus-cache-active-altered group-hash-value)
+       (gnus-cache-write-active group-hash-value)))))
+
+(defvar gnus-cache-inhibit-update-total-fetched-for nil)
+(defvar gnus-cache-need-update-total-fetched-for nil)
+
+(defmacro gnus-cache-with-refreshed-group (group &rest body)
+  `(prog1 (let ((gnus-cache-inhibit-update-total-fetched-for t))
+           ,@body)
+     (when (and gnus-cache-need-update-total-fetched-for
+               (not gnus-cache-inhibit-update-total-fetched-for))
+       (with-current-buffer gnus-group-buffer
+         (setq gnus-cache-need-update-total-fetched-for nil)
+         (gnus-group-update-group ,group t)))))
+
+(defun gnus-cache-update-file-total-fetched-for (group file &optional subtract)
+  (when gnus-cache-total-fetched-hashtb
+    (gnus-cache-with-refreshed-group
+     group
+     (let* ((entry (or (gnus-gethash group gnus-cache-total-fetched-hashtb)
+                      (gnus-sethash group (make-vector 2 0)
+                                    gnus-cache-total-fetched-hashtb)))
+           size)
+
+       (if file
+          (setq size (or (nth 7 (file-attributes file)) 0))
+        (let* ((file-name-coding-system nnmail-pathname-coding-system)
+               (files (directory-files (gnus-cache-file-name group "")
+                                       t nil t))
+               file attrs)
+          (setq size 0.0)
+          (while (setq file (pop files))
+            (setq attrs (file-attributes file))
+            (unless (nth 0 attrs)
+              (incf size (float (nth 7 attrs)))))))
+
+       (setq gnus-cache-need-update-total-fetched-for t)
+
+       (incf (nth 1 entry) (if subtract (- size) size))))))
+
+(defun gnus-cache-update-overview-total-fetched-for (group file)
+  (when gnus-cache-total-fetched-hashtb
+    (gnus-cache-with-refreshed-group
+     group
+     (let* ((entry (or (gnus-gethash group gnus-cache-total-fetched-hashtb)
+                      (gnus-sethash group (make-list 2 0)
+                                    gnus-cache-total-fetched-hashtb)))
+           (file-name-coding-system nnmail-pathname-coding-system)
+           (size (or (nth 7 (file-attributes
+                             (or file
+                                 (gnus-cache-file-name group ".overview"))))
+                     0)))
+       (setq gnus-cache-need-update-total-fetched-for t)
+       (setf (nth 0 entry) size)))))
+
+(defun gnus-cache-rename-group-total-fetched-for (old-group new-group)
+  "Record of disk space used by OLD-GROUP now associated with NEW-GROUP."
+  (when gnus-cache-total-fetched-hashtb
+    (let ((entry (gnus-gethash old-group gnus-cache-total-fetched-hashtb)))
+      (gnus-sethash new-group entry gnus-cache-total-fetched-hashtb)
+      (gnus-sethash old-group nil gnus-cache-total-fetched-hashtb))))
+
+(defun gnus-cache-delete-group-total-fetched-for (group)
+  "Delete record of disk space used by GROUP being deleted."
+  (when gnus-cache-total-fetched-hashtb
+      (gnus-sethash group nil gnus-cache-total-fetched-hashtb)))
+
+(defun gnus-cache-total-fetched-for (group &optional no-inhibit)
+  "Get total disk space used by the cache for the specified GROUP."
+  (unless (equal group "dummy.group")
+    (unless gnus-cache-total-fetched-hashtb
+      (setq gnus-cache-total-fetched-hashtb (gnus-make-hashtable 1024)))
+
+    (let* ((entry (gnus-gethash group gnus-cache-total-fetched-hashtb)))
+      (if entry
+         (apply '+ entry)
+       (let ((gnus-cache-inhibit-update-total-fetched-for (not no-inhibit)))
+         (+
+          (gnus-cache-update-overview-total-fetched-for group nil)
+          (gnus-cache-update-file-total-fetched-for     group nil)))))))
+
+(provide 'gnus-cache)
+
+;;; gnus-cache.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-cite.el b/xemacs-packages/gnus/lisp/gnus-cite.el
new file mode 100644 (file)
index 0000000..502a3be
--- /dev/null
@@ -0,0 +1,1259 @@
+;;; gnus-cite.el --- parse citations in articles for Gnus
+
+;; Copyright (C) 1995-2016 Free Software Foundation, Inc.
+
+;; Author: Per Abhiddenware
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(eval-when-compile
+  (when (featurep 'xemacs)
+    (require 'easy-mmode))) ; for `define-minor-mode'
+
+(require 'gnus)
+(require 'gnus-range)
+(require 'gnus-art)
+(require 'message)     ; for message-cite-prefix-regexp
+
+;;; Customization:
+
+(defgroup gnus-cite nil
+  "Citation."
+  :prefix "gnus-cite-"
+  :link '(custom-manual "(gnus)Article Highlighting")
+  :group 'gnus-article)
+
+(defcustom gnus-cited-opened-text-button-line-format "%(%{[-]%}%)\n"
+  "Format of opened cited text buttons."
+  :group 'gnus-cite
+  :type 'string)
+
+(defcustom gnus-cited-closed-text-button-line-format "%(%{[+]%}%)\n"
+  "Format of closed cited text buttons."
+  :group 'gnus-cite
+  :type 'string)
+
+(defcustom gnus-cited-lines-visible nil
+  "The number of lines of hidden cited text to remain visible.
+Or a pair (cons) of numbers which are the number of lines at the top
+and bottom of the text, respectively, to remain visible."
+  :group 'gnus-cite
+  :type '(choice (const :tag "none" nil)
+                integer
+                (cons :tag "Top and Bottom" integer integer)))
+
+(defcustom gnus-cite-parse-max-size 25000
+  "Maximum article size (in bytes) where parsing citations is allowed.
+Set it to nil to parse all articles."
+  :group 'gnus-cite
+  :type '(choice (const :tag "all" nil)
+                integer))
+
+(defcustom gnus-cite-max-prefix 20
+  "Maximum possible length for a citation prefix."
+  :group 'gnus-cite
+  :type 'integer)
+
+(defcustom gnus-supercite-regexp
+  (concat "^\\(" message-cite-prefix-regexp "\\)? *"
+         ">>>>> +\"\\([^\"\n]+\\)\" +==")
+  "*Regexp matching normal Supercite attribution lines.
+The first grouping must match prefixes added by other packages."
+  :group 'gnus-cite
+  :type 'regexp)
+
+(defcustom gnus-supercite-secondary-regexp "^.*\"\\([^\"\n]+\\)\" +=="
+  "Regexp matching mangled Supercite attribution lines.
+The first regexp group should match the Supercite attribution."
+  :group 'gnus-cite
+  :type 'regexp)
+
+(defcustom gnus-cite-minimum-match-count 2
+  "Minimum number of identical prefixes before we believe it's a citation."
+  :group 'gnus-cite
+  :type 'integer)
+
+;; Some Microsoft products put in a citation that extends to the
+;; remainder of the message:
+;;
+;;     -----Original Message-----
+;;     From: ...
+;;     To: ...
+;;     Sent: ...   [date, in non-RFC-2822 format]
+;;     Subject: ...
+;;
+;;     Cited message, with no prefixes
+;;
+;; The four headers are always the same.  But note they are prone to
+;; folding without additional indentation.
+;;
+;; Others use "----- Original Message -----" instead, and properly quote
+;; the body using "> ".  This style is handled without special cases.
+
+(defcustom gnus-cite-attribution-prefix
+  "In article\\|in <\\|On \\(Mon\\|Tue\\|Wed\\|Thu\\|Fri\\|Sat\\|Sun\\),\\|----- ?Original Message ?-----"
+  "*Regexp matching the beginning of an attribution line."
+  :group 'gnus-cite
+  :type 'regexp)
+
+(defcustom gnus-cite-attribution-suffix
+  "\\(\\(wrote\\|writes\\|said\\|says\\|>\\)\\(:\\|\\.\\.\\.\\)\\|----- ?Original Message ?-----\\)[ \t]*$"
+  "*Regexp matching the end of an attribution line.
+The text matching the first grouping will be used as a button."
+  :group 'gnus-cite
+  :type 'regexp)
+
+(defcustom gnus-cite-unsightly-citation-regexp
+  "^-----Original Message-----\nFrom: \\(.+\n\\)+\n"
+  "Regexp matching Microsoft-type rest-of-message citations."
+  :version "22.1"
+  :group 'gnus-cite
+  :type 'regexp)
+
+(defcustom gnus-cite-ignore-quoted-from t
+  "Non-nil means don't regard lines beginning with \">From \" as cited text.
+Those lines may have been quoted by MTAs in order not to mix up with
+the envelope From line."
+  :version "22.1"
+  :group 'gnus-cite
+  :type 'boolean)
+
+(defface gnus-cite-attribution '((t (:italic t)))
+  "Face used for attribution lines."
+  :group 'gnus-cite)
+;; backward-compatibility alias
+(put 'gnus-cite-attribution-face 'face-alias 'gnus-cite-attribution)
+(put 'gnus-cite-attribution-face 'obsolete-face "22.1")
+
+(defcustom gnus-cite-attribution-face 'gnus-cite-attribution
+  "Face used for attribution lines.
+It is merged with the face for the cited text belonging to the attribution."
+  :version "22.1"
+  :group 'gnus-cite
+  :type 'face)
+
+(defface gnus-cite-1 '((((class color)
+                        (background dark))
+                       (:foreground "light blue"))
+                      (((class color)
+                        (background light))
+                       (:foreground "MidnightBlue"))
+                      (t
+                       (:italic t)))
+  "Citation face."
+  :group 'gnus-cite)
+;; backward-compatibility alias
+(put 'gnus-cite-face-1 'face-alias 'gnus-cite-1)
+(put 'gnus-cite-face-1 'obsolete-face "22.1")
+
+(defface gnus-cite-2 '((((class color)
+                        (background dark))
+                       (:foreground "light cyan"))
+                      (((class color)
+                        (background light))
+                       (:foreground "firebrick"))
+                      (t
+                       (:italic t)))
+  "Citation face."
+  :group 'gnus-cite)
+;; backward-compatibility alias
+(put 'gnus-cite-face-2 'face-alias 'gnus-cite-2)
+(put 'gnus-cite-face-2 'obsolete-face "22.1")
+
+(defface gnus-cite-3 '((((class color)
+                        (background dark))
+                       (:foreground "light yellow"))
+                      (((class color)
+                        (background light))
+                       (:foreground "dark green"))
+                      (t
+                       (:italic t)))
+  "Citation face."
+  :group 'gnus-cite)
+;; backward-compatibility alias
+(put 'gnus-cite-face-3 'face-alias 'gnus-cite-3)
+(put 'gnus-cite-face-3 'obsolete-face "22.1")
+
+(defface gnus-cite-4 '((((class color)
+                        (background dark))
+                       (:foreground "light pink"))
+                      (((class color)
+                        (background light))
+                       (:foreground "OrangeRed"))
+                      (t
+                       (:italic t)))
+  "Citation face."
+  :group 'gnus-cite)
+;; backward-compatibility alias
+(put 'gnus-cite-face-4 'face-alias 'gnus-cite-4)
+(put 'gnus-cite-face-4 'obsolete-face "22.1")
+
+(defface gnus-cite-5 '((((class color)
+                        (background dark))
+                       (:foreground "pale green"))
+                      (((class color)
+                        (background light))
+                       (:foreground "dark khaki"))
+                      (t
+                       (:italic t)))
+  "Citation face."
+  :group 'gnus-cite)
+;; backward-compatibility alias
+(put 'gnus-cite-face-5 'face-alias 'gnus-cite-5)
+(put 'gnus-cite-face-5 'obsolete-face "22.1")
+
+(defface gnus-cite-6 '((((class color)
+                        (background dark))
+                       (:foreground "beige"))
+                      (((class color)
+                        (background light))
+                       (:foreground "dark violet"))
+                      (t
+                       (:italic t)))
+  "Citation face."
+  :group 'gnus-cite)
+;; backward-compatibility alias
+(put 'gnus-cite-face-6 'face-alias 'gnus-cite-6)
+(put 'gnus-cite-face-6 'obsolete-face "22.1")
+
+(defface gnus-cite-7 '((((class color)
+                        (background dark))
+                       (:foreground "orange"))
+                      (((class color)
+                        (background light))
+                       (:foreground "SteelBlue4"))
+                      (t
+                       (:italic t)))
+  "Citation face."
+  :group 'gnus-cite)
+;; backward-compatibility alias
+(put 'gnus-cite-face-7 'face-alias 'gnus-cite-7)
+(put 'gnus-cite-face-7 'obsolete-face "22.1")
+
+(defface gnus-cite-8 '((((class color)
+                        (background dark))
+                       (:foreground "magenta"))
+                      (((class color)
+                        (background light))
+                       (:foreground "magenta"))
+                      (t
+                       (:italic t)))
+  "Citation face."
+  :group 'gnus-cite)
+;; backward-compatibility alias
+(put 'gnus-cite-face-8 'face-alias 'gnus-cite-8)
+(put 'gnus-cite-face-8 'obsolete-face "22.1")
+
+(defface gnus-cite-9 '((((class color)
+                        (background dark))
+                       (:foreground "violet"))
+                      (((class color)
+                        (background light))
+                       (:foreground "violet"))
+                      (t
+                       (:italic t)))
+  "Citation face."
+  :group 'gnus-cite)
+;; backward-compatibility alias
+(put 'gnus-cite-face-9 'face-alias 'gnus-cite-9)
+(put 'gnus-cite-face-9 'obsolete-face "22.1")
+
+(defface gnus-cite-10 '((((class color)
+                         (background dark))
+                        (:foreground "plum1"))
+                       (((class color)
+                         (background light))
+                        (:foreground "medium purple"))
+                       (t
+                        (:italic t)))
+  "Citation face."
+  :group 'gnus-cite)
+;; backward-compatibility alias
+(put 'gnus-cite-face-10 'face-alias 'gnus-cite-10)
+(put 'gnus-cite-face-10 'obsolete-face "22.1")
+
+(defface gnus-cite-11 '((((class color)
+                         (background dark))
+                        (:foreground "turquoise"))
+                       (((class color)
+                         (background light))
+                        (:foreground "turquoise"))
+                       (t
+                        (:italic t)))
+  "Citation face."
+  :group 'gnus-cite)
+;; backward-compatibility alias
+(put 'gnus-cite-face-11 'face-alias 'gnus-cite-11)
+(put 'gnus-cite-face-11 'obsolete-face "22.1")
+
+(defcustom gnus-cite-face-list
+  '(gnus-cite-1 gnus-cite-2 gnus-cite-3 gnus-cite-4 gnus-cite-5 gnus-cite-6
+               gnus-cite-7 gnus-cite-8 gnus-cite-9 gnus-cite-10 gnus-cite-11)
+  "*List of faces used for highlighting citations.
+
+When there are citations from multiple articles in the same message,
+Gnus will try to give each citation from each article its own face.
+This should make it easier to see who wrote what."
+  :group 'gnus-cite
+  :type '(repeat face)
+  :set (lambda (symbol value)
+        (prog1
+            (custom-set-default symbol value)
+          (if (boundp 'gnus-message-max-citation-depth)
+              (setq gnus-message-max-citation-depth (length value)))
+          (if (boundp 'gnus-message-citation-keywords)
+              (setq gnus-message-citation-keywords
+                    `((gnus-message-search-citation-line
+                       ,@(let ((list nil)
+                               (count 1))
+                           (dolist (face value (nreverse list))
+                             (push (list count (list 'quote face) 'prepend t)
+                                   list)
+                             (setq count (1+ count)))))))))))
+
+(defcustom gnus-cite-hide-percentage 50
+  "Only hide excess citation if above this percentage of the body."
+  :group 'gnus-cite
+  :type 'number)
+
+(defcustom gnus-cite-hide-absolute 10
+  "Only hide excess citation if above this number of lines in the body."
+  :group 'gnus-cite
+  :type 'integer)
+
+(defcustom gnus-cite-blank-line-after-header t
+  "If non-nil, put a blank line between the citation header and the button."
+  :group 'gnus-cite
+  :type 'boolean)
+
+;; This has to go here because its default value depends on
+;; gnus-cite-face-list.
+(defcustom gnus-article-boring-faces (cons 'gnus-signature gnus-cite-face-list)
+  "List of faces that are not worth reading.
+If an article has more pages below the one you are looking at, but
+nothing on those pages is a word of at least three letters that is not
+in a boring face, then the pages will be skipped."
+  :type '(repeat face)
+  :group 'gnus-article-hiding)
+
+;;; Internal Variables:
+
+(defvar gnus-cite-article nil)
+(defvar gnus-cite-overlay-list nil)
+
+(defvar gnus-cite-prefix-alist nil)
+;; Alist of citation prefixes.
+;; The cdr is a list of lines with that prefix.
+
+(defvar gnus-cite-attribution-alist nil)
+;; Alist of attribution lines.
+;; The car is a line number.
+;; The cdr is the prefix for the citation started by that line.
+
+(defvar gnus-cite-loose-prefix-alist nil)
+;; Alist of citation prefixes that have no matching attribution.
+;; The cdr is a list of lines with that prefix.
+
+(defvar gnus-cite-loose-attribution-alist nil)
+;; Alist of attribution lines that have no matching citation.
+;; Each member has the form (WROTE IN PREFIX TAG), where
+;; WROTE: is the attribution line number
+;; IN: is the line number of the previous line if part of the same attribution,
+;; PREFIX: Is the citation prefix of the attribution line(s), and
+;; TAG: Is a Supercite tag, if any.
+
+(defvar gnus-cited-opened-text-button-line-format-alist
+  `((?b (marker-position beg) ?d)
+    (?e (marker-position end) ?d)
+    (?n (count-lines beg end) ?d)
+    (?l (- end beg) ?d)))
+(defvar gnus-cited-opened-text-button-line-format-spec nil)
+(defvar gnus-cited-closed-text-button-line-format-alist
+  gnus-cited-opened-text-button-line-format-alist)
+(defvar gnus-cited-closed-text-button-line-format-spec nil)
+
+
+;;; Commands:
+
+(defun gnus-article-highlight-citation (&optional force same-buffer)
+  "Highlight cited text.
+Each citation in the article will be highlighted with a different face.
+The faces are taken from `gnus-cite-face-list'.
+Attribution lines are highlighted with the same face as the
+corresponding citation merged with the face `gnus-cite-attribution'.
+
+Text is considered cited if at least `gnus-cite-minimum-match-count'
+lines matches `message-cite-prefix-regexp' with the same prefix.
+
+Lines matching `gnus-cite-attribution-suffix' and perhaps
+`gnus-cite-attribution-prefix' are considered attribution lines."
+  (interactive (list 'force))
+  (with-current-buffer (if same-buffer (current-buffer) gnus-article-buffer)
+    (gnus-cite-parse-maybe force)
+    (let ((buffer-read-only nil)
+         (alist gnus-cite-prefix-alist)
+         (faces gnus-cite-face-list)
+         (inhibit-point-motion-hooks t)
+         face entry prefix skip numbers number face-alist)
+      ;; Loop through citation prefixes.
+      (while alist
+       (setq entry (car alist)
+             alist (cdr alist)
+             prefix (car entry)
+             numbers (cdr entry)
+             face (car faces)
+             faces (or (cdr faces) gnus-cite-face-list)
+             face-alist (cons (cons prefix face) face-alist))
+       (while numbers
+         (setq number (car numbers)
+               numbers (cdr numbers))
+         (and (not (assq number gnus-cite-attribution-alist))
+              (not (assq number gnus-cite-loose-attribution-alist))
+              (gnus-cite-add-face number prefix face))))
+      ;; Loop through attribution lines.
+      (setq alist gnus-cite-attribution-alist)
+      (while alist
+       (setq entry (car alist)
+             alist (cdr alist)
+             number (car entry)
+             prefix (cdr entry)
+             skip (gnus-cite-find-prefix number)
+             face (cdr (assoc prefix face-alist)))
+       ;; Add attribution button.
+       (goto-char (point-min))
+       (forward-line (1- number))
+       (when (re-search-forward gnus-cite-attribution-suffix
+                                (point-at-eol)
+                                t)
+         (gnus-article-add-button (match-beginning 1) (match-end 1)
+                                  'gnus-cite-toggle prefix))
+       ;; Highlight attribution line.
+       (gnus-cite-add-face number skip face)
+       (gnus-cite-add-face number skip gnus-cite-attribution-face))
+      ;; Loop through attribution lines.
+      (setq alist gnus-cite-loose-attribution-alist)
+      (while alist
+       (setq entry (car alist)
+             alist (cdr alist)
+             number (car entry)
+             skip (gnus-cite-find-prefix number))
+       (gnus-cite-add-face number skip gnus-cite-attribution-face)))))
+
+(defun gnus-dissect-cited-text ()
+  "Dissect the article buffer looking for cited text."
+  (with-current-buffer gnus-article-buffer
+    (gnus-cite-parse-maybe nil t)
+    (let ((alist gnus-cite-prefix-alist)
+         prefix numbers number marks m)
+      ;; Loop through citation prefixes.
+      (while alist
+       (setq numbers (pop alist)
+             prefix (pop numbers))
+       (while numbers
+         (setq number (pop numbers))
+         (goto-char (point-min))
+         (forward-line number)
+         (push (cons (point-marker) "") marks)
+         (while (and numbers
+                     (= (1- number) (car numbers)))
+           (setq number (pop numbers)))
+         (goto-char (point-min))
+         (forward-line (1- number))
+         (push (cons (point-marker) prefix) marks)))
+      ;; Skip to the beginning of the body.
+      (article-goto-body)
+      (push (cons (point-marker) "") marks)
+      ;; Find the end of the body.
+      (goto-char (point-max))
+      (gnus-article-search-signature)
+      (push (cons (point-marker) "") marks)
+      ;; Sort the marks.
+      (setq marks (sort marks 'car-less-than-car))
+      (let ((omarks marks))
+       (setq marks nil)
+       (while (cdr omarks)
+         (if (= (caar omarks) (caadr omarks))
+             (progn
+               (unless (equal (cdar omarks) "")
+                 (push (car omarks) marks))
+               (unless (equal (cdadr omarks) "")
+                 (push (cadr omarks) marks))
+               (unless (and (equal (cdar omarks) "")
+                            (equal (cdadr omarks) "")
+                            (not (cddr omarks)))
+                 (setq omarks (cdr omarks))))
+           (push (car omarks) marks))
+         (setq omarks (cdr omarks)))
+       (when (car omarks)
+         (push (car omarks) marks))
+       (setq marks (setq m (nreverse marks)))
+       (while (cddr m)
+         (if (and (equal (cdadr m) "")
+                  (equal (cdar m) (cdaddr m))
+                  (goto-char (caadr m))
+                  (looking-at "[ \t]*$")
+                  (forward-line 1)
+                  (= (point) (caaddr m)))
+             (setcdr m (cdddr m))
+           (setq m (cdr m))))
+       marks))))
+
+(defun gnus-article-fill-cited-long-lines ()
+  (gnus-article-fill-cited-article nil t))
+
+(defun gnus-article-fill-cited-article (&optional width long-lines)
+  "Do word wrapping in the current article.
+If WIDTH (the numerical prefix), use that text width when
+filling.  If LONG-LINES, only fill sections that have lines
+longer than the frame width."
+  (interactive "P")
+  (with-current-buffer gnus-article-buffer
+    (let ((buffer-read-only nil)
+         (inhibit-point-motion-hooks t)
+         (marks (gnus-dissect-cited-text))
+         (adaptive-fill-mode nil)
+         (filladapt-mode nil)
+         (fill-column (if width (prefix-numeric-value width) fill-column)))
+      (save-restriction
+       (while (cdr marks)
+         (narrow-to-region (caar marks) (caadr marks))
+         (let ((adaptive-fill-regexp
+                (concat "^" (regexp-quote (cdar marks)) " *"))
+               (fill-prefix
+                (if (string= (cdar marks) "") ""
+                  (concat (cdar marks) " ")))
+               (do-fill (not long-lines))
+               use-hard-newlines)
+           (unless do-fill
+             (setq do-fill (gnus-article-foldable-buffer (cdar marks))))
+           ;; Note: the XEmacs version of `fill-region' inserts a newline
+           ;; unless the region ends with a newline.
+           (when do-fill
+             (if (not long-lines)
+                 (fill-region (point-min) (point-max))
+               (goto-char (point-min))
+               (while (not (eobp))
+                 (end-of-line)
+                 (when (prog1
+                           (> (current-column) (window-width))
+                         (forward-line 1))
+                   (save-restriction
+                     (narrow-to-region (line-beginning-position 0) (point))
+                     (fill-region (point-min) (point-max))))))))
+         (set-marker (caar marks) nil)
+         (setq marks (cdr marks)))
+       (when marks
+         (set-marker (caar marks) nil))
+       ;; All this information is now incorrect.
+       (setq gnus-cite-prefix-alist nil
+             gnus-cite-attribution-alist nil
+             gnus-cite-loose-prefix-alist nil
+             gnus-cite-loose-attribution-alist nil
+             gnus-cite-article nil)))))
+
+(defun gnus-article-foldable-buffer (prefix)
+  (let ((do-fill nil)
+       columns)
+    (goto-char (point-min))
+    (while (not (eobp))
+      (unless (> (length prefix) (- (point-max) (point)))
+       (forward-char (length prefix)))
+      (skip-chars-forward " \t")
+      (unless (eolp)
+       (let ((elem (assq (current-column) columns)))
+         (unless elem
+           (setq elem (cons (current-column) 0))
+           (push elem columns))
+         (setcdr elem (1+ (cdr elem)))))
+      (end-of-line)
+      (when (> (current-column) (window-width))
+       (setq do-fill t))
+      (forward-line 1))
+    (and do-fill
+        ;; We know know that there are long lines here, but does this look
+        ;; like code?  Check for ragged edges on the left.
+        (< (length columns) 3))))
+
+(defun gnus-article-hide-citation (&optional arg force)
+  "Toggle hiding of all cited text except attribution lines.
+See the documentation for `gnus-article-highlight-citation'.
+If given a negative prefix, always show; if given a positive prefix,
+always hide."
+  (interactive (append (gnus-article-hidden-arg) (list 'force)))
+  (gnus-set-format 'cited-opened-text-button t)
+  (gnus-set-format 'cited-closed-text-button t)
+  (with-current-buffer gnus-article-buffer
+    (let ((buffer-read-only nil)
+          marks
+          (inhibit-point-motion-hooks t)
+          (props (nconc (list 'article-type 'cite)
+                        gnus-hidden-properties))
+          (point (point-min))
+          found beg end start)
+      (while (setq point
+                   (text-property-any point (point-max)
+                                      'gnus-callback
+                                      'gnus-article-toggle-cited-text))
+        (setq found t)
+        (goto-char point)
+        (gnus-article-toggle-cited-text
+         (get-text-property point 'gnus-data) arg)
+        (forward-line 1)
+        (setq point (point)))
+      (unless found
+        (setq marks (gnus-dissect-cited-text))
+        (while marks
+          (setq beg nil
+                end nil)
+          (while (and marks (string= (cdar marks) ""))
+            (setq marks (cdr marks)))
+          (when marks
+            (setq beg (caar marks)))
+          (while (and marks (not (string= (cdar marks) "")))
+            (setq marks (cdr marks)))
+          (when marks
+           (setq end (caar marks)))
+          ;; Skip past lines we want to leave visible.
+          (when (and beg end gnus-cited-lines-visible)
+            (goto-char beg)
+            (forward-line (if (consp gnus-cited-lines-visible)
+                              (car gnus-cited-lines-visible)
+                            gnus-cited-lines-visible))
+            (if (>= (point) end)
+                (setq beg nil)
+              (setq beg (point-marker))
+              (when (consp gnus-cited-lines-visible)
+                (goto-char end)
+                (forward-line (- (cdr gnus-cited-lines-visible)))
+                (if (<= (point) beg)
+                    (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)
+                  end (set-marker (make-marker) end))
+            (gnus-add-text-properties-when 'article-type nil beg end props)
+            (goto-char beg)
+            (when (and gnus-cite-blank-line-after-header
+                       (not (save-excursion (search-backward "\n\n" nil t))))
+              (insert "\n"))
+            (put-text-property
+             (setq start (point-marker))
+             (progn
+              (gnus-article-add-button
+               (point)
+               (progn (eval gnus-cited-closed-text-button-line-format-spec)
+                      (point))
+               `gnus-article-toggle-cited-text
+               (list (cons beg end) start))
+              (point))
+             'article-type 'annotation)
+            (set-marker beg (point))))))))
+
+(defun gnus-article-toggle-cited-text (args &optional arg)
+  "Toggle hiding the text in REGION.
+ARG can be nil or a number.  Positive means hide, negative
+means show, nil means toggle."
+  (let* ((region (car args))
+        (beg (car region))
+        (end (cdr region))
+        (start (cadr args))
+        (hidden
+         (text-property-any beg (1- end) 'article-type 'cite))
+        (inhibit-point-motion-hooks t)
+        buffer-read-only)
+    (when (or (null arg)
+             (zerop arg)
+             (and (> arg 0) (not hidden))
+             (and (< arg 0) hidden))
+      (if hidden
+         (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
+        (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)
+       (put-text-property
+        (point)
+        (progn
+          (gnus-article-add-button
+           (point)
+           (progn (eval
+                   (if hidden
+                       gnus-cited-opened-text-button-line-format-spec
+                     gnus-cited-closed-text-button-line-format-spec))
+                  (point))
+           `gnus-article-toggle-cited-text
+           args)
+          (point))
+        'article-type 'annotation)))))
+
+(defun gnus-article-hide-citation-maybe (&optional arg force)
+  "Toggle hiding of cited text that has an attribution line.
+If given a negative prefix, always show; if given a positive prefix,
+always hide.
+This will do nothing unless at least `gnus-cite-hide-percentage'
+percent and at least `gnus-cite-hide-absolute' lines of the body is
+cited text with attributions.  When called interactively, these two
+variables are ignored.
+See also the documentation for `gnus-article-highlight-citation'."
+  (interactive (append (gnus-article-hidden-arg) '(force)))
+  (with-current-buffer gnus-article-buffer
+    (gnus-delete-wash-type 'cite)
+    (unless (gnus-article-check-hidden-text 'cite arg)
+      (save-excursion
+       (gnus-cite-parse-maybe force)
+       (article-goto-body)
+       (let ((start (point))
+             (atts gnus-cite-attribution-alist)
+             (buffer-read-only nil)
+             (inhibit-point-motion-hooks t)
+             (hidden 0)
+             total)
+         (goto-char (point-max))
+         (gnus-article-search-signature)
+         (setq total (count-lines start (point)))
+         (while atts
+           (setq hidden (+ hidden (length
+                                   (cdr (assoc (cdar atts)
+                                               gnus-cite-prefix-alist))))
+                 atts (cdr atts)))
+         (when (or force
+                   (and (> (* 100 hidden) (* gnus-cite-hide-percentage total))
+                        (> hidden gnus-cite-hide-absolute)))
+           (gnus-article-hide-citation)))))))
+
+(defun gnus-article-hide-citation-in-followups ()
+  "Hide cited text in non-root articles."
+  (interactive)
+  (with-current-buffer gnus-article-buffer
+    (let ((article (cdr gnus-article-current)))
+      (unless (with-current-buffer gnus-summary-buffer
+               (gnus-article-displayed-root-p article))
+       (gnus-article-hide-citation)))))
+
+;;; Internal functions:
+
+(defun gnus-cite-parse-maybe (&optional force no-overlay)
+  "Always parse the buffer."
+  (gnus-cite-localize)
+  ;;Reset parser information.
+  (setq gnus-cite-prefix-alist nil
+       gnus-cite-attribution-alist nil
+       gnus-cite-loose-prefix-alist nil
+       gnus-cite-loose-attribution-alist nil)
+  (unless no-overlay
+    (gnus-cite-delete-overlays))
+  ;; Parse if not too large.
+  (if (and gnus-cite-parse-max-size
+          (> (buffer-size) gnus-cite-parse-max-size))
+      ()
+    (setq gnus-cite-article (cons (car gnus-article-current)
+                                 (cdr gnus-article-current)))
+    (gnus-cite-parse-wrapper)))
+
+(defun gnus-cite-delete-overlays ()
+  (dolist (overlay gnus-cite-overlay-list)
+    (ignore-errors
+      (when (or (not (overlay-end overlay))
+               (and (>= (overlay-end overlay) (point-min))
+                    (<= (overlay-end overlay) (point-max))))
+       (setq gnus-cite-overlay-list (delete overlay gnus-cite-overlay-list))
+       (ignore-errors
+         (delete-overlay overlay))))))
+
+(defun gnus-cite-parse-wrapper ()
+  ;; Wrap chopped gnus-cite-parse.
+  (article-goto-body)
+  (let ((inhibit-point-motion-hooks t))
+    (save-excursion
+      (gnus-cite-parse-attributions))
+    (save-excursion
+      (gnus-cite-parse))
+    (save-excursion
+      (gnus-cite-connect-attributions))))
+
+(defun gnus-cite-parse ()
+  ;; Parse and connect citation prefixes and attribution lines.
+
+  ;; Parse current buffer searching for citation prefixes.
+  (let ((line (1+ (count-lines (point-min) (point))))
+       (case-fold-search t)
+       (max (save-excursion
+              (goto-char (point-max))
+              (gnus-article-search-signature)
+              (point)))
+       (prefix-regexp (concat "^\\(" message-cite-prefix-regexp "\\)"))
+       alist entry start begin end numbers prefix guess-limit)
+    ;; Get all potential prefixes in `alist'.
+    (while (< (point) max)
+      ;; Each line.
+      (setq begin (point)
+           guess-limit (progn (skip-chars-forward "^> \t\r\n") (point))
+           end (point-at-bol 2)
+           start end)
+      (goto-char begin)
+      ;; Ignore standard Supercite attribution prefix.
+      (when (and (< guess-limit (+ begin gnus-cite-max-prefix))
+                (looking-at gnus-supercite-regexp))
+       (if (match-end 1)
+           (setq end (1+ (match-end 1)))
+         (setq end (1+ begin))))
+      ;; Ignore very long prefixes.
+      (when (> end (+ begin gnus-cite-max-prefix))
+       (setq end (+ begin gnus-cite-max-prefix)))
+      ;; Ignore quoted envelope From_.
+      (when (and gnus-cite-ignore-quoted-from
+                (prog2
+                    (setq case-fold-search nil)
+                    (looking-at ">From ")
+                  (setq case-fold-search t)))
+       (setq end (1+ begin)))
+      (while (re-search-forward prefix-regexp (1- end) t)
+       ;; Each prefix.
+       (setq end (match-end 0)
+             prefix (buffer-substring begin end))
+       (set-text-properties 0 (length prefix) nil prefix)
+       (setq entry (assoc prefix alist))
+       (if entry
+           (setcdr entry (cons line (cdr entry)))
+         (push (list prefix line) alist))
+       (goto-char begin))
+      (goto-char start)
+      (setq line (1+ line)))
+    ;; Horrible special case for some Microsoft mailers.
+    (goto-char (point-min))
+    (setq start t begin nil entry nil)
+    (while start
+      ;; Assume this search ends up at the beginning of a line.
+      (if (re-search-forward gnus-cite-unsightly-citation-regexp max t)
+         (progn
+           (when (number-or-marker-p start)
+             (setq begin (count-lines (point-min) start)
+                   end (count-lines (point-min) (match-beginning 0))))
+           (setq start (match-end 0)))
+       (when (number-or-marker-p start)
+         (setq begin (count-lines (point-min) start)
+               end (count-lines (point-min) max)))
+       (setq start nil))
+      (when begin
+       (while (< begin end)
+         ;; Need to do 1+ because we're in the bol.
+         (push (setq begin (1+ begin)) entry))))
+    (when entry
+      (push (cons "" entry) alist))
+    ;; We got all the potential prefixes.  Now create
+    ;; `gnus-cite-prefix-alist' containing the oldest prefix for each
+    ;; line that appears at least `gnus-cite-minimum-match-count'
+    ;; times.  First sort them by length.  Longer is older.
+    (setq alist (sort alist (lambda (a b)
+                             (> (length (car a)) (length (car b))))))
+    (while alist
+      (setq entry (car alist)
+           prefix (car entry)
+           numbers (cdr entry)
+           alist (cdr alist))
+      (cond ((null numbers)
+            ;; No lines with this prefix that wasn't also part of
+            ;; a longer prefix.
+            )
+           ((< (length numbers) gnus-cite-minimum-match-count)
+            ;; Too few lines with this prefix.  We keep it a bit
+            ;; longer in case it is an exact match for an attribution
+            ;; line, but we don't remove the line from other
+            ;; prefixes.
+            (push entry gnus-cite-prefix-alist))
+           (t
+            (push entry
+                  gnus-cite-prefix-alist)
+            ;; Remove articles from other prefixes.
+            (let ((loop alist)
+                  current)
+              (while loop
+                (setq current (car loop)
+                      loop (cdr loop))
+                (setcdr current
+                        (gnus-set-difference (cdr current) numbers)))))))))
+
+(defun gnus-cite-parse-attributions ()
+  (let (al-alist)
+    ;; Parse attributions
+    (while (re-search-forward gnus-cite-attribution-suffix (point-max) t)
+      (let* ((start (match-beginning 0))
+            (end (match-end 0))
+            (wrote (count-lines (point-min) end))
+            (prefix (gnus-cite-find-prefix wrote))
+            ;; Check previous line for an attribution leader.
+            (tag (progn
+                   (beginning-of-line 1)
+                   (when (looking-at gnus-supercite-secondary-regexp)
+                     (buffer-substring (match-beginning 1)
+                                       (match-end 1)))))
+            (in (progn
+                  (goto-char start)
+                  (and (re-search-backward gnus-cite-attribution-prefix
+                                           (save-excursion
+                                             (beginning-of-line 0)
+                                             (point))
+                                           t)
+                       (not (re-search-forward gnus-cite-attribution-suffix
+                                               start t))
+                       (count-lines (point-min) (1+ (point)))))))
+       (when (eq wrote in)
+         (setq in nil))
+       (goto-char end)
+       ;; don't add duplicates
+       (let ((al (buffer-substring (save-excursion (beginning-of-line 0)
+                                                   (1+ (point)))
+                                   end)))
+         (when (not (assoc al al-alist))
+           (push (list wrote in prefix tag)
+                 gnus-cite-loose-attribution-alist)
+           (push (cons al t) al-alist)))))))
+
+(defun gnus-cite-connect-attributions ()
+  ;; Connect attributions to citations
+
+  ;; No citations have been connected to attribution lines yet.
+  (setq gnus-cite-loose-prefix-alist (append gnus-cite-prefix-alist nil))
+
+  ;; Parse current buffer searching for attribution lines.
+  ;; Find exact supercite citations.
+  (gnus-cite-match-attributions 'small nil
+                               (lambda (prefix tag)
+                                 (when tag
+                                   (concat "\\`"
+                                           (regexp-quote prefix) "[ \t]*"
+                                           (regexp-quote tag) ">"))))
+  ;; Find loose supercite citations after attributions.
+  (gnus-cite-match-attributions 'small t
+                               (lambda (prefix tag)
+                                 (when tag
+                                   (concat "\\<"
+                                           (regexp-quote tag)
+                                           "\\>"))))
+  ;; Find loose supercite citations anywhere.
+  (gnus-cite-match-attributions 'small nil
+                               (lambda (prefix tag)
+                                 (when tag
+                                   (concat "\\<"
+                                           (regexp-quote tag)
+                                           "\\>"))))
+  ;; Find nested citations after attributions.
+  (gnus-cite-match-attributions 'small-if-unique t
+                               (lambda (prefix tag)
+                                 (concat "\\`" (regexp-quote prefix) ".+")))
+  ;; Find nested citations anywhere.
+  (gnus-cite-match-attributions 'small nil
+                               (lambda (prefix tag)
+                                 (concat "\\`" (regexp-quote prefix) ".+")))
+  ;; Remove loose prefixes with too few lines.
+  (let ((alist gnus-cite-loose-prefix-alist)
+       entry)
+    (while alist
+      (setq entry (car alist)
+           alist (cdr alist))
+      (when (< (length (cdr entry)) gnus-cite-minimum-match-count)
+       (setq gnus-cite-prefix-alist
+             (delq entry gnus-cite-prefix-alist)
+             gnus-cite-loose-prefix-alist
+             (delq entry gnus-cite-loose-prefix-alist)))))
+  ;; Find flat attributions.
+  (gnus-cite-match-attributions 'first t nil)
+  ;; Find any attributions (are we getting desperate yet?).
+  (gnus-cite-match-attributions 'first nil nil))
+
+(defun gnus-cite-match-attributions (sort after fun)
+  ;; Match all loose attributions and citations (SORT AFTER FUN) .
+  ;;
+  ;; If SORT is `small', the citation with the shortest prefix will be
+  ;; used, if it is `first' the first prefix will be used, if it is
+  ;; `small-if-unique' the shortest prefix will be used if the
+  ;; attribution line does not share its own prefix with other
+  ;; loose attribution lines, otherwise the first prefix will be used.
+  ;;
+  ;; If AFTER is non-nil, only citations after the attribution line
+  ;; will be considered.
+  ;;
+  ;; If FUN is non-nil, it will be called with the arguments (WROTE
+  ;; PREFIX TAG) and expected to return a regular expression.  Only
+  ;; citations whose prefix matches the regular expression will be
+  ;; considered.
+  ;;
+  ;; WROTE is the attribution line number.
+  ;; PREFIX is the attribution line prefix.
+  ;; TAG is the Supercite tag on the attribution line.
+  (let ((atts gnus-cite-loose-attribution-alist)
+       (case-fold-search t)
+       att wrote in prefix tag regexp limit smallest best size)
+    (while atts
+      (setq att (car atts)
+           atts (cdr atts)
+           wrote (nth 0 att)
+           in (nth 1 att)
+           prefix (nth 2 att)
+           tag (nth 3 att)
+           regexp (if fun (funcall fun prefix tag) "")
+           size (cond ((eq sort 'small) t)
+                      ((eq sort 'first) nil)
+                      (t (< (length (gnus-cite-find-loose prefix)) 2)))
+           limit (if after wrote -1)
+           smallest 1000000
+           best nil)
+      (let ((cites gnus-cite-loose-prefix-alist)
+           cite candidate numbers first compare)
+       (while cites
+         (setq cite (car cites)
+               cites (cdr cites)
+               candidate (car cite)
+               numbers (cdr cite)
+               first (apply 'min numbers)
+               compare (if size (length candidate) first))
+         (and (> first limit)
+              regexp
+              (string-match regexp candidate)
+              (< compare smallest)
+              (setq best cite
+                    smallest compare))))
+      (if (null best)
+         ()
+       (setq gnus-cite-loose-attribution-alist
+             (delq att gnus-cite-loose-attribution-alist))
+       (push (cons wrote (car best)) gnus-cite-attribution-alist)
+       (when in
+         (push (cons in (car best)) gnus-cite-attribution-alist))
+       (when (memq best gnus-cite-loose-prefix-alist)
+         (let ((loop gnus-cite-prefix-alist)
+               (numbers (cdr best))
+               current)
+           (setq gnus-cite-loose-prefix-alist
+                 (delq best gnus-cite-loose-prefix-alist))
+           (while loop
+             (setq current (car loop)
+                   loop (cdr loop))
+             (if (eq current best)
+                 ()
+               (setcdr current (gnus-set-difference (cdr current) numbers))
+               (when (null (cdr current))
+                 (setq gnus-cite-loose-prefix-alist
+                       (delq current gnus-cite-loose-prefix-alist)
+                       atts (delq current atts)))))))))))
+
+(defun gnus-cite-find-loose (prefix)
+  ;; Return a list of loose attribution lines prefixed by PREFIX.
+  (let* ((atts gnus-cite-loose-attribution-alist)
+        att line lines)
+    (while atts
+      (setq att (car atts)
+           line (car att)
+           atts (cdr atts))
+      (when (string-equal (gnus-cite-find-prefix line) prefix)
+       (push line lines)))
+    lines))
+
+(defun gnus-cite-add-face (number prefix face)
+  ;; At line NUMBER, ignore PREFIX and add FACE to the rest of the line.
+  (when face
+    (let ((inhibit-point-motion-hooks t)
+         from to overlay)
+      (goto-char (point-min))
+      (when (zerop (forward-line (1- number)))
+       (forward-char (length prefix))
+       (skip-chars-forward " \t")
+       (setq from (point))
+       (end-of-line 1)
+       (skip-chars-backward " \t")
+       (setq to (point))
+       (when (< from to)
+         (push (setq overlay (make-overlay from to nil t))
+               gnus-cite-overlay-list)
+         (overlay-put overlay 'evaporate t)
+         (overlay-put overlay 'face face))))))
+
+(defun gnus-cite-toggle (prefix)
+  (with-current-buffer gnus-article-buffer
+    (gnus-cite-parse-maybe nil t)
+    (let ((buffer-read-only nil)
+         (numbers (cdr (assoc prefix gnus-cite-prefix-alist)))
+         (inhibit-point-motion-hooks t)
+         number)
+      (while numbers
+       (setq number (car numbers)
+             numbers (cdr numbers))
+       (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))))
+       (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.
+  (let ((alist gnus-cite-prefix-alist)
+       (prefix "")
+       entry)
+    (while alist
+      (setq entry (car alist)
+           alist (cdr alist))
+      (when (memq line (cdr entry))
+       (setq prefix (car entry))))
+    prefix))
+
+(defun gnus-cite-localize ()
+  "Make the citation variables local to the article buffer."
+  (let ((vars '(gnus-cite-article
+               gnus-cite-overlay-list gnus-cite-prefix-alist
+               gnus-cite-attribution-alist gnus-cite-loose-prefix-alist
+               gnus-cite-loose-attribution-alist)))
+    (while vars
+      (make-local-variable (pop vars)))))
+
+;; Highlighting of different citation levels in message-mode.
+;; - message-cite-prefix will be overridden if this is enabled.
+
+(defvar gnus-message-max-citation-depth
+  (length gnus-cite-face-list)
+  "Maximum supported level of citation.")
+
+(defvar gnus-message-cite-prefix-regexp
+  (concat "^\\(?:" message-cite-prefix-regexp "\\)"))
+
+(defun gnus-message-search-citation-line (limit)
+  "Search for a cited line and set match data accordingly.
+Returns nil if there is no such line before LIMIT, t otherwise."
+  (when (re-search-forward gnus-message-cite-prefix-regexp limit t)
+    (let ((cdepth (min (length (apply 'concat
+                                     (split-string
+                                      (match-string-no-properties 0)
+                                      "[ \t [:alnum:]]+")))
+                      gnus-message-max-citation-depth))
+         (mlist (make-list (* (1+ gnus-message-max-citation-depth) 2) nil))
+         (start (point-at-bol))
+         (end (point-at-eol)))
+      (setcar mlist start)
+      (setcar (cdr mlist) end)
+      (setcar (nthcdr (* cdepth 2) mlist) start)
+      (setcar (nthcdr (1+ (* cdepth 2)) mlist) end)
+      (set-match-data mlist))
+    t))
+
+(defvar gnus-message-citation-keywords
+  ;; eval-when-compile ;; This breaks in XEmacs
+  `((gnus-message-search-citation-line
+     ,@(let ((list nil)
+            (count 1))
+        ;; (require 'gnus-cite)
+        (dolist (face gnus-cite-face-list (nreverse list))
+          (push (list count (list 'quote face) 'prepend t) list)
+          (setq count (1+ count)))))) ;;
+  "Keywords for highlighting different levels of message citations.")
+
+(defvar font-lock-defaults-computed)
+(defvar font-lock-keywords)
+(defvar font-lock-set-defaults)
+
+(eval-and-compile
+  (unless (featurep 'xemacs)
+    (autoload 'font-lock-set-defaults "font-lock")))
+
+(define-minor-mode gnus-message-citation-mode
+  "Minor mode providing more font-lock support for nested citations.
+When enabled, it automatically turns on `font-lock-mode'."
+  nil ;; init-value
+  "" ;; lighter
+  nil ;; keymap
+  (when (eq major-mode 'message-mode)   ;FIXME: Use derived-mode-p.
+    ;; FIXME: Use font-lock-add-keywords!
+    (let ((defaults (car (if (featurep 'xemacs)
+                            (get 'message-mode 'font-lock-defaults)
+                          font-lock-defaults)))
+         default keywords)
+      (while defaults
+       (setq default (if (consp defaults)
+                         (pop defaults)
+                       (prog1
+                           defaults
+                         (setq defaults nil))))
+       (if gnus-message-citation-mode
+           ;; `gnus-message-citation-keywords' should be the last
+           ;; elements of the keywords because the others are unlikely
+           ;; to have the OVERRIDE flags -- XEmacs applies a keyword
+           ;; having no OVERRIDE flag to matched text even if it has
+           ;; already other faces, while Emacs doesn't.
+           (set (make-local-variable default)
+                (append (default-value default)
+                        gnus-message-citation-keywords))
+         (kill-local-variable default))))
+    ;; Force `font-lock-set-defaults' to update `font-lock-keywords'.
+    (if (featurep 'xemacs)
+       (progn
+         (require 'font-lock)
+         (setq font-lock-defaults-computed nil
+               font-lock-keywords nil))
+      (setq font-lock-set-defaults nil))
+    (font-lock-set-defaults)
+    (cond (font-lock-mode
+           (if (fboundp 'font-lock-flush)
+               (font-lock-flush)
+             (font-lock-fontify-buffer)))
+         (gnus-message-citation-mode
+          (font-lock-mode 1)))))
+
+(defun turn-on-gnus-message-citation-mode ()
+  "Turn on `gnus-message-citation-mode'."
+  (gnus-message-citation-mode 1))
+(defun turn-off-gnus-message-citation-mode ()
+  "Turn off `gnus-message-citation-mode'."
+  (gnus-message-citation-mode -1))
+
+(gnus-ems-redefine)
+
+(provide 'gnus-cite)
+
+;; Local Variables:
+;; coding: utf-8
+;; End:
+
+;;; gnus-cite.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-cloud.el b/xemacs-packages/gnus/lisp/gnus-cloud.el
new file mode 100644 (file)
index 0000000..a6a0f64
--- /dev/null
@@ -0,0 +1,343 @@
+;;; gnus-cloud.el --- storing and retrieving data via IMAP
+
+;; Copyright (C) 2014-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(require 'parse-time)
+(require 'nnimap)
+
+(defgroup gnus-cloud nil
+  "Syncing Gnus data via IMAP."
+  :version "25.1"
+  :group 'gnus)
+
+(defcustom gnus-cloud-synced-files
+  '(;;"~/.authinfo"
+    "~/.authinfo.gpg"
+    "~/.gnus.el"
+    (:directory "~/News" :match ".*.SCORE\\'"))
+  "List of file regexps that should be kept up-to-date via the cloud."
+  :group 'gnus-cloud
+  ;; FIXME this type does not match the default.  Nor does the documentation.
+  :type '(repeat regexp))
+
+(defvar gnus-cloud-group-name "*Emacs Cloud*")
+(defvar gnus-cloud-covered-servers nil)
+
+(defvar gnus-cloud-version 1)
+(defvar gnus-cloud-sequence 1)
+
+(defvar gnus-cloud-method nil
+  "The IMAP select method used to store the cloud data.")
+
+(defun gnus-cloud-make-chunk (elems)
+  (with-temp-buffer
+    (insert (format "Version %s\n" gnus-cloud-version))
+    (insert (gnus-cloud-insert-data elems))
+    (buffer-string)))
+
+(defun gnus-cloud-insert-data (elems)
+  (mm-with-unibyte-buffer
+    (dolist (elem elems)
+      (cond
+       ((eq (plist-get elem :type) :file)
+       (let (length data)
+         (mm-with-unibyte-buffer
+           (insert-file-contents-literally (plist-get elem :file-name))
+           (setq length (buffer-size)
+                 data (buffer-string)))
+         (insert (format "(:type :file :file-name %S :timestamp %S :length %d)\n"
+                         (plist-get elem :file-name)
+                         (plist-get elem :timestamp)
+                         length))
+         (insert data)
+         (insert "\n")))
+       ((eq (plist-get elem :type) :data)
+       (insert (format "(:type :data :name %S :length %d)\n"
+                       (plist-get elem :name)
+                       (with-current-buffer (plist-get elem :buffer)
+                         (buffer-size))))
+       (insert-buffer-substring (plist-get elem :buffer))
+       (insert "\n"))
+       ((eq (plist-get elem :type) :delete)
+       (insert (format "(:type :delete :file-name %S)\n"
+                       (plist-get elem :file-name))))))
+    (gnus-cloud-encode-data)
+    (buffer-string)))
+
+(defun gnus-cloud-encode-data ()
+  (call-process-region (point-min) (point-max) "gzip"
+                      t (current-buffer) nil
+                      "-c")
+  (base64-encode-region (point-min) (point-max)))
+
+(defun gnus-cloud-decode-data ()
+  (base64-decode-region (point-min) (point-max))
+  (call-process-region (point-min) (point-max) "gunzip"
+                      t (current-buffer) nil
+                      "-c"))
+
+(defun gnus-cloud-parse-chunk ()
+  (save-excursion
+    (goto-char (point-min))
+    (unless (looking-at "Version \\([0-9]+\\)")
+      (error "Not a valid Cloud chunk in the current buffer"))
+    (forward-line 1)
+    (let ((version (string-to-number (match-string 1)))
+         (data (buffer-substring (point) (point-max))))
+      (mm-with-unibyte-buffer
+       (insert data)
+       (cond
+        ((= version 1)
+         (gnus-cloud-decode-data)
+         (goto-char (point-min))
+         (gnus-cloud-parse-version-1))
+        (t
+         (error "Unsupported Cloud chunk version %s" version)))))))
+
+(defun gnus-cloud-parse-version-1 ()
+  (let ((elems nil))
+    (while (not (eobp))
+      (while (and (not (eobp))
+                 (not (looking-at "(:type")))
+       (forward-line 1))
+      (unless (eobp)
+       (let ((spec (ignore-errors (read (current-buffer))))
+             length)
+         (when (and (consp spec)
+                    (memq (plist-get spec :type) '(:file :data :delete)))
+           (setq length (plist-get spec :length))
+           (push (append spec
+                         (list
+                          :contents (buffer-substring (1+ (point))
+                                                      (+ (point) 1 length))))
+                 elems)
+           (goto-char (+ (point) 1 length))))))
+    (nreverse elems)))
+
+(defun gnus-cloud-update-data (elems)
+  (dolist (elem elems)
+    (let ((type (plist-get elem :type)))
+      (cond
+       ((eq type :data)
+       )
+       ((eq type :delete)
+       (gnus-cloud-delete-file (plist-get elem :file-name))
+       )
+       ((eq type :file)
+       (gnus-cloud-update-file elem))
+       (t
+       (message "Unknown type %s; ignoring" type))))))
+
+(defun gnus-cloud-update-file (elem)
+  (let ((file-name (plist-get elem :file-name))
+       (date (plist-get elem :timestamp))
+       (contents (plist-get elem :contents)))
+    (unless (gnus-cloud-file-covered-p file-name)
+      (message "%s isn't covered by the cloud; ignoring" file-name))
+    (when (or (not (file-exists-p file-name))
+             (and (file-exists-p file-name)
+                  (mm-with-unibyte-buffer
+                    (insert-file-contents-literally file-name)
+                    (not (equal (buffer-string) contents)))))
+      (gnus-cloud-replace-file file-name date contents))))
+
+(defun gnus-cloud-replace-file (file-name date new-contents)
+  (mm-with-unibyte-buffer
+    (insert new-contents)
+    (when (file-exists-p file-name)
+      (rename-file file-name (car (find-backup-file-name file-name))))
+    (write-region (point-min) (point-max) file-name)
+    (set-file-times file-name (parse-iso8601-time-string date))))
+
+(defun gnus-cloud-delete-file (file-name)
+  (unless (gnus-cloud-file-covered-p file-name)
+    (message "%s isn't covered by the cloud; ignoring" file-name))
+  (when (file-exists-p file-name)
+    (rename-file file-name (car (find-backup-file-name file-name)))))
+
+(defun gnus-cloud-file-covered-p (file-name)
+  (let ((matched nil))
+    (dolist (elem gnus-cloud-synced-files)
+      (cond
+       ((stringp elem)
+       (when (equal elem file-name)
+         (setq matched t)))
+       ((consp elem)
+       (when (and (equal (directory-file-name (plist-get elem :directory))
+                         (directory-file-name (file-name-directory file-name)))
+                  (string-match (plist-get elem :match)
+                                (file-name-nondirectory file-name)))
+         (setq matched t)))))
+    matched))
+
+(defun gnus-cloud-all-files ()
+  (let ((files nil))
+    (dolist (elem gnus-cloud-synced-files)
+      (cond
+       ((stringp elem)
+       (push elem files))
+       ((consp elem)
+       (dolist (file (directory-files (plist-get elem :directory)
+                                      nil
+                                      (plist-get elem :match)))
+         (push (format "%s/%s"
+                       (directory-file-name (plist-get elem :directory))
+                       file)
+               files)))))
+    (nreverse files)))
+
+(defvar gnus-cloud-file-timestamps nil)
+
+(defun gnus-cloud-files-to-upload (&optional full)
+  (let ((files nil)
+       timestamp)
+    (dolist (file (gnus-cloud-all-files))
+      (if (file-exists-p file)
+         (when (setq timestamp (gnus-cloud-file-new-p file full))
+           (push `(:type :file :file-name ,file :timestamp ,timestamp) files))
+       (when (assoc file gnus-cloud-file-timestamps)
+         (push `(:type :delete :file-name ,file) files))))
+    (nreverse files)))
+
+(defun gnus-cloud-file-new-p (file full)
+  (let ((timestamp (format-time-string
+                   "%FT%T%z" (nth 5 (file-attributes file))))
+       (old (cadr (assoc file gnus-cloud-file-timestamps))))
+    (when (or full
+             (null old)
+             (string< old timestamp))
+      timestamp)))
+
+(declare-function gnus-activate-group "gnus-start"
+                 (group &optional scan dont-check method dont-sub-check))
+(declare-function gnus-subscribe-group "gnus-start"
+                 (group &optional previous method))
+
+(defun gnus-cloud-ensure-cloud-group ()
+  (let ((method (if (stringp gnus-cloud-method)
+                   (gnus-server-to-method gnus-cloud-method)
+                 gnus-cloud-method)))
+    (unless (or (gnus-active gnus-cloud-group-name)
+               (gnus-activate-group gnus-cloud-group-name nil nil
+                                    gnus-cloud-method))
+      (and (gnus-request-create-group gnus-cloud-group-name gnus-cloud-method)
+          (gnus-activate-group gnus-cloud-group-name nil nil gnus-cloud-method)
+          (gnus-subscribe-group gnus-cloud-group-name)))))
+
+(defun gnus-cloud-upload-data (&optional full)
+  (gnus-cloud-ensure-cloud-group)
+  (with-temp-buffer
+    (let ((elems (gnus-cloud-files-to-upload full)))
+      (insert (format "Subject: (sequence: %d type: %s)\n"
+                     gnus-cloud-sequence
+                     (if full :full :partial)))
+      (insert "From: nobody@invalid.com\n")
+      (insert "\n")
+      (insert (gnus-cloud-make-chunk elems))
+      (when (gnus-request-accept-article gnus-cloud-group-name gnus-cloud-method
+                                        t t)
+       (setq gnus-cloud-sequence (1+ gnus-cloud-sequence))
+       (gnus-cloud-add-timestamps elems)))))
+
+(defun gnus-cloud-add-timestamps (elems)
+  (dolist (elem elems)
+    (let* ((file-name (plist-get elem :file-name))
+          (old (assoc file-name gnus-cloud-file-timestamps)))
+      (when old
+       (setq gnus-cloud-file-timestamps
+             (delq old gnus-cloud-file-timestamps)))
+      (push (list file-name (plist-get elem :timestamp))
+           gnus-cloud-file-timestamps))))
+
+(defun gnus-cloud-available-chunks ()
+  (gnus-activate-group gnus-cloud-group-name nil nil gnus-cloud-method)
+  (let* ((group (gnus-group-full-name gnus-cloud-group-name gnus-cloud-method))
+        (active (gnus-active group))
+        headers head)
+    (when (gnus-retrieve-headers (gnus-uncompress-range active) group)
+      (with-current-buffer nntp-server-buffer
+       (goto-char (point-min))
+       (while (and (not (eobp))
+                   (setq head (nnheader-parse-head)))
+         (push head headers))))
+    (sort (nreverse headers)
+         (lambda (h1 h2)
+           (> (gnus-cloud-chunk-sequence (mail-header-subject h1))
+              (gnus-cloud-chunk-sequence (mail-header-subject h2)))))))
+
+(defun gnus-cloud-chunk-sequence (string)
+  (if (string-match "sequence: \\([0-9]+\\)" string)
+      (string-to-number (match-string 1 string))
+    0))
+
+(defun gnus-cloud-prune-old-chunks (headers)
+  (let ((headers (reverse headers))
+       (found nil))
+  (while (and headers
+             (not found))
+    (when (string-match "type: :full" (mail-header-subject (car headers)))
+      (setq found t))
+    (pop headers))
+  ;; All the chunks that are older than the newest :full chunk can be
+  ;; deleted.
+  (when headers
+    (gnus-request-expire-articles
+     (mapcar (lambda (h)
+              (mail-header-number h))
+            (nreverse headers))
+     (gnus-group-full-name gnus-cloud-group-name gnus-cloud-method)))))
+
+(defun gnus-cloud-download-data ()
+  (let ((articles nil)
+       chunks)
+    (dolist (header (gnus-cloud-available-chunks))
+      (when (> (gnus-cloud-chunk-sequence (mail-header-subject header))
+              gnus-cloud-sequence)
+       (push (mail-header-number header) articles)))
+    (when articles
+      (nnimap-request-articles (nreverse articles) gnus-cloud-group-name)
+      (with-current-buffer nntp-server-buffer
+       (goto-char (point-min))
+       (while (re-search-forward "^Version " nil t)
+         (beginning-of-line)
+         (push (gnus-cloud-parse-chunk) chunks)
+         (forward-line 1))))))
+
+(defun gnus-cloud-server-p (server)
+  (member server gnus-cloud-covered-servers))
+
+(defun gnus-cloud-collect-full-newsrc ()
+  (let ((infos nil))
+    (dolist (info (cdr gnus-newsrc-alist))
+      (when (gnus-cloud-server-p
+            (gnus-method-to-server
+             (gnus-find-method-for-group (gnus-info-group info))))
+       (push info infos)))
+    ))
+
+(provide 'gnus-cloud)
+
+;;; gnus-cloud.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-compat.el b/xemacs-packages/gnus/lisp/gnus-compat.el
new file mode 100644 (file)
index 0000000..c31baa7
--- /dev/null
@@ -0,0 +1,172 @@
+;;; gnus-compat.el --- Compatability functions for Gnus
+
+;; Copyright (C) 2012-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: compat
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package defines and redefines a bunch of functions for Gnus
+;; usage.  The basic (and somewhat unsound) idea is to make all
+;; Emacsen look like the current trunk of Emacs.  So it will define
+;; functions "missing" in other Emacs instances, and redefine other
+;; functions to work like the Emacs trunk versions.
+
+(eval-when-compile (require 'cl))
+
+(ignore-errors
+  (require 'help-fns))
+
+;; XEmacs doesn't have this function.
+(when (and (not (fboundp 'help-function-arglist))
+          (fboundp 'function-arglist))
+  (defun help-function-arglist (def &optional preserve-names)
+    "Return a formal argument list for the function DEF.
+PRESERVE-NAMES is ignored."
+    (cdr (car (read-from-string (downcase (function-arglist def)))))))
+
+;; Modify this function on Emacs 23.1 and earlier to always return the
+;; right answer.
+(when (and (fboundp 'help-function-arglist)
+          (eq (help-function-arglist 'car) t))
+  (defvar gnus-compat-original-help-function-arglist
+    (symbol-function 'help-function-arglist))
+  (defun help-function-arglist (def &optional preserve-names)
+    "Return a formal argument list for the function DEF.
+PRESERVE-NAMES is ignored."
+    (let ((orig (funcall gnus-compat-original-help-function-arglist def)))
+      (if (not (eq orig t))
+         orig
+       ;; Built-in subrs have the arglist hidden in the doc string.
+       (let ((doc (documentation def)))
+         (when (and doc
+                    (string-match "\n\n\\((fn\\( .*\\)?)\\)\\'" doc))
+           (cdr (car (read-from-string (downcase (match-string 1 doc)))))))))))
+
+(when (= (length (help-function-arglist 'delete-directory)) 1)
+  (defvar gnus-compat-original-delete-directory
+    (symbol-function 'delete-directory))
+  (defun delete-directory (directory &optional recursive trash)
+    "Delete the directory named DIRECTORY.  Does not follow symlinks.
+If RECURSIVE is non-nil, all files in DIRECTORY are deleted as well.
+TRASH is ignored."
+    (interactive "DDirectory: ")
+    (if (not recursive)
+       (funcall gnus-compat-original-delete-directory directory)
+      (dolist (file (directory-files directory t))
+       (unless (member (file-name-nondirectory file) '("." ".."))
+         (if (file-directory-p file)
+             (delete-directory file t)
+           (delete-file file))))
+      (delete-directory directory))))
+
+;; Emacs 24.0.93
+(require 'url)
+(when (= (length (help-function-arglist 'url-retrieve)) 5)
+  (defvar gnus-compat-original-url-retrieve
+    (symbol-function 'url-retrieve))
+  (defun url-retrieve (url callback &optional cbargs silent inhibit-cookies)
+    "Retrieve URL asynchronously and call CALLBACK with CBARGS when finished."
+    (funcall gnus-compat-original-url-retrieve
+            url callback cbargs silent)))
+
+;; XEmacs
+(when (and (not (fboundp 'timer-set-function))
+          (fboundp 'set-itimer-function))
+  (defun timer-set-function (timer function &optional args)
+    "Make TIMER call FUNCTION with optional ARGS when triggering."
+    (lexical-let ((function function)
+                 (args args))
+      (set-itimer-function timer
+                          (lambda (process status)
+                            (apply function process status args))))))
+
+;; XEmacs 21.4
+(unless (fboundp 'bound-and-true-p)
+  (defmacro bound-and-true-p (var)
+    "Return the value of symbol VAR if it is bound, else nil."
+    (and (boundp var)
+        (symbol-value var))))
+
+
+;; Emacs less than 24.3
+(unless (fboundp 'add-face)
+  (defun add-face (beg end face)
+    "Combine FACE BEG and END."
+    (let ((b beg))
+      (while (< b end)
+       (let ((oldval (get-text-property b 'face)))
+         (put-text-property
+          b (setq b (next-single-property-change b 'face nil end))
+          'face (cond ((null oldval)
+                       face)
+                      ((and (consp oldval)
+                            (not (keywordp (car oldval))))
+                       (cons face oldval))
+                      (t
+                       (list face oldval)))))))))
+
+(unless (fboundp 'move-beginning-of-line)
+  (defun move-beginning-of-line (arg)
+    (interactive "p")
+    (unless (= arg 1)
+      (forward-line arg))
+    (beginning-of-line)))
+
+(unless (fboundp 'delete-dups)
+  (defun delete-dups (list)
+    "Destructively remove `equal' duplicates from LIST.
+Store the result in LIST and return it.  LIST must be a proper list.
+Of several `equal' occurrences of an element in LIST, the first
+one is kept."
+    (let ((tail list))
+      (while tail
+       (setcdr tail (delete (car tail) (cdr tail)))
+       (setq tail (cdr tail))))
+    list))
+
+(unless (fboundp 'declare-function)
+  (defmacro declare-function (&rest r)))
+
+(unless (fboundp 'string-bytes)
+  (defun string-bytes (string)
+    (length (if (or (mm-coding-system-p 'utf-8)
+                   (ignore-errors
+                     (let (mucs-ignore-version-incompatibilities)
+                       (require 'un-define))))
+               (mm-encode-coding-string string 'utf-8)
+             string))))
+
+(unless (fboundp 'process-live-p)
+  (defun process-live-p (process)
+    "Returns non-nil if PROCESS is alive.
+A process is considered alive if its status is `run', `open',
+`listen', `connect' or `stop'.  Value is nil if PROCESS is not a
+process."
+    (and (processp process)
+        (memq (process-status process)
+              '(run open listen connect stop)))))
+
+;; XEmacs doesn't have auto-autoloads for overlay functions.
+(when (featurep 'xemacs)
+  (require 'overlay))
+
+(provide 'gnus-compat)
+
+;; gnus-compat.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-cus.el b/xemacs-packages/gnus/lisp/gnus-cus.el
new file mode 100644 (file)
index 0000000..de66e34
--- /dev/null
@@ -0,0 +1,1119 @@
+;;; gnus-cus.el --- customization commands for Gnus
+
+;; Copyright (C) 1996, 1999-2016 Free Software Foundation, Inc.
+
+;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'wid-edit)
+(require 'gnus)
+(require 'gnus-agent)
+(require 'gnus-score)
+(require 'gnus-topic)
+(require 'gnus-art)
+
+;;; Widgets:
+
+(define-derived-mode gnus-custom-mode fundamental-mode "Gnus Customize"
+  "Major mode for editing Gnus customization buffers.
+
+The following commands are available:
+
+\\[widget-forward]             Move to next button or editable field.
+\\[widget-backward]            Move to previous button or editable field.
+\\[widget-button-click]                Activate button under the mouse pointer.
+\\[widget-button-press]                Activate button under point.
+
+Entry to this mode calls the value of `gnus-custom-mode-hook'
+if that value is non-nil."
+  (use-local-map widget-keymap)
+  ;; Emacs stuff:
+  (when (and (facep 'custom-button-face)
+            (facep 'custom-button-pressed-face))
+    (set (make-local-variable 'widget-button-face)
+        'custom-button-face)
+    (set (make-local-variable 'widget-button-pressed-face)
+        'custom-button-pressed-face)
+    (set (make-local-variable 'widget-mouse-face)
+        'custom-button-pressed-face))
+  (when (and (boundp 'custom-raised-buttons)
+            (symbol-value 'custom-raised-buttons))
+    (set (make-local-variable 'widget-push-button-prefix) "")
+    (set (make-local-variable 'widget-push-button-suffix) "")
+    (set (make-local-variable 'widget-link-prefix) "")
+    (set (make-local-variable 'widget-link-suffix) "")))
+
+;;; Group Customization:
+
+(defconst gnus-group-parameters
+  '((extra-aliases (choice
+                   :tag "Extra Aliases"
+                   (list
+                    :tag "List"
+                    (editable-list
+                     :inline t
+                     (gnus-email-address :tag "Address")))
+                   (gnus-email-address :tag "Address")) "\
+Store messages posted from or to this address in this group.
+
+You must be using gnus-group-split for this to work.  The VALUE of the
+nnmail-split-fancy SPLIT generated for this group will match these
+addresses.")
+
+    (split-regexp (regexp :tag "gnus-group-split Regular Expression") "\
+Like gnus-group-split Address, but expects a regular expression.")
+
+    (split-exclude (list :tag "gnus-group-split Restricts"
+                        (editable-list
+                         :inline t (regexp :tag "Restrict"))) "\
+Regular expression that cancels gnus-group-split matches.
+
+Each entry is added to the nnmail-split-fancy SPLIT as a separate
+RESTRICT clause.")
+
+    (split-spec (choice :tag "gnus-group-split Overrider"
+                       (sexp :tag "Fancy Split")
+                       (const :tag "Catch All" catch-all)
+                       (const :tag "Ignore" nil)) "\
+Override all other gnus-group-split fields.
+
+In `Fancy Split', you can enter any nnmail-split-fancy SPLIT.  Note
+that the name of this group won't be automatically assumed, you have
+to add it to the SPLITs yourself.  This means you can use such splits
+to split messages to other groups too.
+
+If you select `Catch All', this group will get postings for any
+messages not matched in any other group.  It overrides the variable
+gnus-group-split-default-catch-all-group.
+
+Selecting `Ignore' forces no SPLIT to be generated for this group,
+disabling all other gnus-group-split fields.")
+
+    (broken-reply-to (const :tag "Broken Reply To" t) "\
+Ignore `Reply-To' headers in this group.
+
+That can be useful if you're reading a mailing list group where the
+listserv has inserted `Reply-To' headers that point back to the
+listserv itself.  This is broken behavior.  So there!")
+
+    (to-group (string :tag "To Group") "\
+All posts will be sent to the specified group.")
+
+    (gcc-self (choice :tag  "GCC"
+                     :value t
+                     (const :tag "To current group" t)
+                     (const none)
+                     (string :format "%v" :hide-front-space t)) "\
+Specify default value for GCC header.
+
+If this symbol is present in the group parameter list and set to t,
+new composed messages will be `Gcc''d to the current group.  If it is
+present and set to `none', no `Gcc:' header will be generated, if it
+is present and a string, this string will be inserted literally as a
+`gcc' header (this symbol takes precedence over any default `Gcc'
+rules as described later).")
+
+    (expiry-wait (choice :tag  "Expire Wait"
+                        :value never
+                        (const never)
+                        (const immediate)
+                        (number :hide-front-space t
+                                :format "%v")) "\
+When to expire.
+
+Overrides any `nnmail-expiry-wait' and `nnmail-expiry-wait-function'
+when expiring expirable messages.  The value can either be a number of
+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) "\
+Where expired messages end up.
+
+Overrides `nnmail-expiry-target'.")
+
+    (score-file (file :tag "Score File") "\
+Make the specified file into the current score file.
+This means that all score commands you issue will end up in this file.")
+
+    (adapt-file (file :tag "Adapt File") "\
+Make the specified file into the current adaptive file.
+All adaptive score entries will be put into this file.")
+
+    (admin-address (gnus-email-address :tag "Admin Address") "\
+Administration address for a mailing list.
+
+When unsubscribing to 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.")
+
+    (display (choice :tag "Display"
+                    :value default
+                    (const all)
+                    (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.
+
+`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.")
+
+    (visible (const :tag "Permanently visible" t) "\
+Always display this group, even when there are no unread articles in it.")
+
+    (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"
+                                  gnus-emphasis-highlight-words))))
+     "highlight regexps.
+See `gnus-emphasis-alist'.")
+
+    (posting-style
+     (choice :tag "Posting style"
+            :value nil
+            (repeat (list
+                     (choice :tag "Type"
+                             :value nil
+                             (const signature)
+                             (const signature-file)
+                             (const organization)
+                             (const address)
+                             (const x-face-file)
+                             (const name)
+                             (const body)
+                             (symbol)
+                             (string :tag "Header"))
+                     (string :format "%v"))))
+     "post style.
+See `gnus-posting-styles'."))
+  "Alist of valid group or topic parameters.
+
+Each entry has the form (NAME TYPE DOC), where NAME is the parameter
+itself (a symbol), TYPE is the parameters type (a sexp widget), and
+DOC is a documentation string for the parameter.")
+
+(defconst gnus-extra-topic-parameters
+  '((subscribe (regexp :tag "Subscribe") "\
+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")
+    (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
+itself (a symbol), TYPE is the parameters type (a sexp widget), and
+DOC is a documentation string for the parameter.")
+
+(defconst gnus-extra-group-parameters
+  '((uidvalidity (string :tag "IMAP uidvalidity") "\
+Server-assigned value attached to IMAP groups, used to maintain consistency."))
+  "Alist of group parameters that are not also topic parameters.
+
+Each entry has the form (NAME TYPE DOC), where NAME is the parameter
+itself (a symbol), TYPE is the parameters type (a sexp widget), and
+DOC is a documentation string for the parameter.")
+
+(eval-and-compile
+  (defconst gnus-agent-parameters
+    '((agent-predicate
+       (sexp :tag "Selection Predicate" :value false)
+       "Predicate used to automatically select articles for downloading."
+       gnus-agent-cat-predicate)
+      (agent-score
+       (choice :tag "Score File" :value nil
+               (const file :tag "Use group's score files")
+               (repeat (list (string :format "%v" :tag "File name"))))
+       "Which score files to use when using score to select articles to fetch.
+
+    nil
+         All articles will be scored to zero (0).
+
+    `file'
+         The group's score files will be used to score the articles.
+
+    `List'
+         A list of score file names."
+       gnus-agent-cat-score-file)
+      (agent-short-article
+       (integer :tag "Max Length of Short Article" :value "")
+       "The SHORT predicate will evaluate to true when the article is
+shorter than this length."  gnus-agent-cat-length-when-short)
+      (agent-long-article
+       (integer :tag "Min Length of Long Article" :value "")
+       "The LONG predicate will evaluate to true when the article is
+longer than this length."  gnus-agent-cat-length-when-long)
+      (agent-low-score
+       (integer :tag "Low Score Limit" :value "")
+       "The LOW predicate will evaluate to true when the article scores
+lower than this limit."  gnus-agent-cat-low-score)
+      (agent-high-score
+       (integer :tag "High Score Limit" :value "")
+       "The HIGH predicate will evaluate to true when the article scores
+higher than this limit."  gnus-agent-cat-high-score)
+      (agent-days-until-old
+       (integer :tag "Days Until Old" :value "")
+       "The OLD predicate will evaluate to true when the fetched article
+has been stored locally for at least this many days."
+       gnus-agent-cat-days-until-old)
+      (agent-enable-expiration
+       (radio :tag "Expire in this Group or Topic" :value nil
+              (const :format "Enable " ENABLE)
+              (const :format "Disable " DISABLE))
+       "\nEnable, or disable, agent expiration in this group or topic."
+       gnus-agent-cat-enable-expiration)
+      (agent-enable-undownloaded-faces
+       (boolean :tag "Enable Agent Faces")
+       "Have the summary buffer use the agent's undownloaded faces.
+These faces, when enabled, act as a warning that an article has not
+been fetched into either the agent nor the cache.  This is of most use
+to users who use the agent as a cache (i.e. they only operate on
+articles that have been downloaded).  Leave disabled to display normal
+article faces even when the article hasn't been downloaded."
+gnus-agent-cat-enable-undownloaded-faces))
+    "Alist of group parameters that are not also topic parameters.
+
+Each entry has the form (NAME TYPE DOC ACCESSOR), where NAME is the
+parameter itself (a symbol), TYPE is the parameters type (a sexp
+widget), DOC is a documentation string for the parameter, and ACCESSOR
+is a function (symbol) that extracts the current value from the
+category."))
+
+(defvar gnus-custom-params)
+(defvar gnus-custom-method)
+(defvar gnus-custom-group)
+(defvar gnus-custom-topic)
+
+(defun gnus-group-customize (group &optional topic)
+  "Edit the group or topic on the current line."
+  (interactive (list (gnus-group-group-name) (gnus-group-topic-name)))
+  (let (info
+       (types (mapcar (lambda (entry)
+                        `(cons :format "%v%h\n"
+                               :doc ,(nth 2 entry)
+                               (const :format "" ,(nth 0 entry))
+                               ,(nth 1 entry)))
+                      (append (reverse gnus-group-parameters-more)
+                              gnus-group-parameters
+                              (if group
+                                  gnus-extra-group-parameters
+                                gnus-extra-topic-parameters))))
+       (agent (mapcar (lambda (entry)
+                         (let ((type (nth 1 entry))
+                               vcons)
+                           (if (listp type)
+                               (setq type (copy-sequence type)))
+
+                           (setq vcons (cdr (memq :value type)))
+
+                           (if (symbolp (car vcons))
+                               (condition-case nil
+                                   (setcar vcons (symbol-value (car vcons)))
+                                 (error)))
+                           `(cons :format "%v%h\n"
+                                  :doc ,(nth 2 entry)
+                                  (const :format "" ,(nth 0 entry))
+                                  ,type)))
+                      (if gnus-agent
+                           gnus-agent-parameters))))
+    (unless (or group topic)
+      (error "No group on current line"))
+    (when (and group topic)
+      (error "Both a group an topic on current line"))
+    (unless (or topic (setq info (gnus-get-info group)))
+      (error "Killed group; can't be edited"))
+    ;; Ready.
+    (gnus-kill-buffer (gnus-get-buffer-create "*Gnus Customize*"))
+    (switch-to-buffer (gnus-get-buffer-create "*Gnus Customize*"))
+    (gnus-custom-mode)
+    (make-local-variable 'gnus-custom-group)
+    (setq gnus-custom-group group)
+    (make-local-variable 'gnus-custom-topic)
+    (setq gnus-custom-topic topic)
+    (buffer-disable-undo)
+    (widget-insert "Customize the ")
+    (if group
+       (widget-create 'info-link
+                      :help-echo "Push me to learn more."
+                      :tag "group parameters"
+                      "(gnus)Group Parameters")
+      (widget-create 'info-link
+                    :help-echo "Push me to learn more."
+                    :tag  "topic parameters"
+                    "(gnus)Topic Parameters"))
+    (widget-insert " for <")
+    (widget-insert (gnus-group-decoded-name (or group topic)))
+    (widget-insert "> and press ")
+    (widget-create 'push-button
+                  :tag "done"
+                  :help-echo "Push me when done customizing."
+                  :action 'gnus-group-customize-done)
+    (widget-insert ".\n\n")
+    (make-local-variable 'gnus-custom-params)
+
+    (let ((values (if group
+                     (gnus-info-params info)
+                   (gnus-topic-parameters topic))))
+
+      ;; The parameters in values may contain duplicates.  This is
+      ;; normally OK as assq returns the first. However, right here
+      ;; every duplicate ends up being displayed.  So, rather than
+      ;; display them, remove them from the list.
+
+      (let ((tmp (setq values (gnus-copy-sequence values)))
+           elem)
+       (while (cdr tmp)
+         (while (setq elem (assq (caar tmp) (cdr tmp)))
+           (delq elem tmp))
+         (setq tmp (cdr tmp))))
+
+      ;; Decode values posting-style holds.
+      (dolist (style (cdr (assq 'posting-style values)))
+       (when (stringp (cadr style))
+         (setcdr style (list (mm-decode-coding-string (cadr style) 'utf-8)))))
+
+      (setq gnus-custom-params
+            (apply 'widget-create 'group
+                   :value values
+                   (delq nil
+                         (list `(set :inline t
+                                     :greedy t
+                                     :tag "Parameters"
+                                     :format "%t:\n%h%v"
+                                     :doc "\
+These special parameters are recognized by Gnus.
+Check the [ ] for the parameters you want to apply to this group or
+to the groups in this topic, then edit the value to suit your taste."
+                                     ,@types)
+                               (when gnus-agent
+                                 `(set :inline t
+                                       :greedy t
+                                       :tag "Agent Parameters"
+                                       :format "%t:\n%h%v"
+                                       :doc "These agent parameters are
+recognized by Gnus.  They control article selection and expiration for
+use in the unplugged cache.  Check the [ ] for the parameters you want
+to apply to this group or to the groups in this topic, then edit the
+value to suit your taste.
+
+For those interested, group parameters override topic parameters while
+topic parameters override agent category parameters.  Underlying
+category parameters are the customizable variables."  ,@agent))
+                               '(repeat :inline t
+                                        :tag "Variables"
+                                        :format "%t:\n%h%v%i\n\n"
+                                        :doc "\
+Set variables local to the group you are entering.
+
+If you want to turn threading off in `news.answers', you could put
+`(gnus-show-threads nil)' in the group parameters of that group.
+`gnus-show-threads' will be made into a local variable in the summary
+buffer you enter, and the form nil will be `eval'ed there.
+
+This can also be used as a group-specific hook function, if you'd
+like.  If you want to hear a beep when you enter a group, you could
+put something like `(dummy-variable (ding))' in the parameters of that
+group.  `dummy-variable' will be set to the result of the `(ding)'
+form, but who cares?"
+                                        (list :format "%v" :value (nil nil)
+                                              (symbol :tag "Variable")
+                                              (sexp :tag
+                                                    "Value")))
+
+                               '(repeat :inline t
+                                        :tag "Unknown entries"
+                                        sexp))))))
+    (when group
+      (widget-insert "\n\nYou can also edit the ")
+      (widget-create 'info-link
+                    :tag "select method"
+                    :help-echo "Push me to learn more about select methods."
+                    "(gnus)Select Methods")
+      (widget-insert " for the group.\n")
+      (setq gnus-custom-method
+           (widget-create 'sexp
+                          :tag "Method"
+                          :value (gnus-info-method info))))
+    (use-local-map widget-keymap)
+    (widget-setup)
+    (buffer-enable-undo)
+    (goto-char (point-min))))
+
+(defun gnus-group-customize-done (&rest ignore)
+  "Apply changes and bury the buffer."
+  (interactive)
+  (let ((params (widget-value gnus-custom-params)))
+    ;; Encode values posting-style holds.
+    (dolist (style (cdr (assq 'posting-style params)))
+      (when (stringp (cadr style))
+       (setcdr style (list (mm-encode-coding-string (cadr style) 'utf-8)))))
+    (if gnus-custom-topic
+       (gnus-topic-set-parameters gnus-custom-topic params)
+      (gnus-group-edit-group-done 'params gnus-custom-group params)
+      (gnus-group-edit-group-done 'method gnus-custom-group
+                                 (widget-value gnus-custom-method)))
+    (bury-buffer)))
+
+;;; Score Customization:
+
+(defconst gnus-score-parameters
+  '((mark (number :tag "Mark") "\
+The value of this entry should be a number.
+Any articles with a score lower than this number will be marked as read.")
+
+    (expunge (number :tag "Expunge") "\
+The value of this entry should be a number.
+Any articles with a score lower than this number will be removed from
+the summary buffer.")
+
+    (mark-and-expunge (number :tag "Mark-and-expunge") "\
+The value of this entry should be a number.
+Any articles with a score lower than this number will be marked as
+read and removed from the summary buffer.")
+
+    (thread-mark-and-expunge (number :tag "Thread-mark-and-expunge") "\
+The value of this entry should be a number.
+All articles that belong to a thread that has a total score below this
+number will be marked as read and removed from the summary buffer.
+`gnus-thread-score-function' says how to compute the total score
+for a thread.")
+
+    (files (repeat :inline t :tag "Files" file) "\
+The value of this entry should be any number of file names.
+These files are assumed to be score files as well, and will be loaded
+the same way this one was.")
+
+    (exclude-files (repeat :inline t :tag "Exclude-files" file) "\
+The clue of this entry should be any number of files.
+These files will not be loaded, even though they would normally be so,
+for some reason or other.")
+
+    (eval (sexp :tag "Eval" :value nil) "\
+The value of this entry will be `eval'el.
+This element will be ignored when handling global score files.")
+
+    (read-only (boolean :tag "Read-only" :value t) "\
+Read-only score files will not be updated or saved.
+Global score files should feature this atom.")
+
+    (orphan (number :tag "Orphan") "\
+The value of this entry should be a number.
+Articles that do not have parents will get this number added to their
+scores.  Imagine you follow some high-volume newsgroup, like
+`comp.lang.c'.  Most likely you will only follow a few of the threads,
+also want to see any new threads.
+
+You can do this with the following two score file entries:
+
+     (orphan -500)
+     (mark-and-expunge -100)
+
+When you enter the group the first time, you will only see the new
+threads.  You then raise the score of the threads that you find
+interesting (with `I T' or `I S'), and ignore (`C y') the rest.
+Next time you enter the group, you will see new articles in the
+interesting threads, plus any new threads.
+
+I.e.---the orphan score atom is for high-volume groups where there
+exist a few interesting threads which can't be found automatically
+by ordinary scoring rules.")
+
+    (adapt (choice :tag "Adapt"
+                  (const t)
+                  (const ignore)
+                  (sexp :format "%v"
+                        :hide-front-space t)) "\
+This entry controls the adaptive scoring.
+If it is t, the default adaptive scoring rules will be used.  If it
+is `ignore', no adaptive scoring will be performed on this group.  If
+it is a list, this list will be used as the adaptive scoring rules.
+If it isn't present, or is something other than t or `ignore', the
+default adaptive scoring rules will be used.  If you want to use
+adaptive scoring on most groups, you'd set `gnus-use-adaptive-scoring'
+to t, and insert an `(adapt ignore)' in the groups where you do not
+want adaptive scoring.  If you only want adaptive scoring in a few
+groups, you'd set `gnus-use-adaptive-scoring' to nil, and insert
+`(adapt t)' in the score files of the groups where you want it.")
+
+    (adapt-file (file :tag "Adapt-file") "\
+All adaptive score entries will go to the file named by this entry.
+It will also be applied when entering the group.  This atom might
+be handy if you want to adapt on several groups at once, using the
+same adaptive file for a number of groups.")
+
+    (local (repeat :tag "Local"
+                  (group :value (nil nil)
+                         (symbol :tag "Variable")
+                         (sexp :tag "Value"))) "\
+The value of this entry should be a list of `(VAR VALUE)' pairs.
+Each VAR will be made buffer-local to the current summary buffer,
+and set to the value specified.  This is a convenient, if somewhat
+strange, way of setting variables in some groups if you don't like
+hooks much.")
+    (touched (sexp :format "Touched\n") "Internal variable."))
+  "Alist of valid symbolic score parameters.
+
+Each entry has the form (NAME TYPE DOC), where NAME is the parameter
+itself (a symbol), TYPE is the parameters type (a sexp widget), and DOC is a
+documentation string for the parameter.")
+
+(define-widget 'gnus-score-string 'group
+  "Edit score entries for string-valued headers."
+  :convert-widget 'gnus-score-string-convert)
+
+(defun gnus-score-string-convert (widget)
+  ;; Set args appropriately.
+  (let* ((tag (widget-get widget :tag))
+        (item `(const :format "" :value ,(downcase tag)))
+        (match '(string :tag "Match"))
+        (score '(choice :tag "Score"
+                        (const :tag "default" nil)
+                        (integer :format "%v"
+                                 :hide-front-space t)))
+        (expire '(choice :tag "Expire"
+                         (const :tag "off" nil)
+                         (integer :format "%v"
+                                  :hide-front-space t)))
+        (type '(choice :tag "Type"
+                       :value s
+                       ;; I should really create a forgiving :match
+                       ;; function for each type below, that only
+                       ;; looked at the first letter.
+                       (const :tag "Regexp" r)
+                       (const :tag "Regexp (fixed case)" R)
+                       (const :tag "Substring" s)
+                       (const :tag "Substring (fixed case)" S)
+                       (const :tag "Exact" e)
+                       (const :tag "Exact (fixed case)" E)
+                       (const :tag "Word" w)
+                       (const :tag "Word (fixed case)" W)
+                       (const :tag "default" nil)))
+        (group `(group ,match ,score ,expire ,type))
+        (doc (concat (or (widget-get widget :doc)
+                         (concat "Change score based on the " tag
+                                 " header.\n"))
+                     "
+You can have an arbitrary number of score entries for this header,
+each score entry has four elements:
+
+1. The \"match element\".  This should be the string to look for in the
+   header.
+
+2. The \"score element\".  This number should be an integer in the
+   neginf to posinf interval.  This number is added to the score
+   of the article if the match is successful.  If this element is
+   not present, the `gnus-score-interactive-default-score' number
+   will be used instead.  This is 1000 by default.
+
+3. The \"date element\".  This date says when the last time this score
+   entry matched, which provides a mechanism for expiring the
+   score entries.  It this element is not present, the score
+   entry is permanent.  The date is represented by the number of
+   days since December 31, 1 ce.
+
+4. The \"type element\".  This element specifies what function should
+   be used to see whether this score entry matches the article.
+
+   There are the regexp, as well as substring types, and exact match,
+   and word match types.  If this element is not present, Gnus will
+   assume that substring matching should be used.  There is case
+   sensitive variants of all match types.")))
+    (widget-put widget :args `(,item
+                              (repeat :inline t
+                                      :indent 0
+                                      :tag ,tag
+                                      :doc ,doc
+                                      :format "%t:\n%h%v%i\n\n"
+                                      (choice :format "%v"
+                                              :value ("" nil nil s)
+                                              ,group
+                                              sexp)))))
+  widget)
+
+(define-widget 'gnus-score-integer 'group
+  "Edit score entries for integer-valued headers."
+  :convert-widget 'gnus-score-integer-convert)
+
+(defun gnus-score-integer-convert (widget)
+  ;; Set args appropriately.
+  (let* ((tag (widget-get widget :tag))
+        (item `(const :format "" :value ,(downcase tag)))
+        (match '(integer :tag "Match"))
+        (score '(choice :tag "Score"
+                        (const :tag "default" nil)
+                        (integer :format "%v"
+                                 :hide-front-space t)))
+        (expire '(choice :tag "Expire"
+                         (const :tag "off" nil)
+                         (integer :format "%v"
+                                  :hide-front-space t)))
+        (type '(choice :tag "Type"
+                       :value <
+                       (const <)
+                       (const >)
+                       (const =)
+                       (const >=)
+                       (const <=)))
+        (group `(group ,match ,score ,expire ,type))
+        (doc (concat (or (widget-get widget :doc)
+                         (concat "Change score based on the " tag
+                                 " header.")))))
+    (widget-put widget :args `(,item
+                              (repeat :inline t
+                                      :indent 0
+                                      :tag ,tag
+                                      :doc ,doc
+                                      :format "%t:\n%h%v%i\n\n"
+                                      ,group))))
+  widget)
+
+(define-widget 'gnus-score-date 'group
+  "Edit score entries for date-valued headers."
+  :convert-widget 'gnus-score-date-convert)
+
+(defun gnus-score-date-convert (widget)
+  ;; Set args appropriately.
+  (let* ((tag (widget-get widget :tag))
+        (item `(const :format "" :value ,(downcase tag)))
+        (match '(string :tag "Match"))
+        (score '(choice :tag "Score"
+                        (const :tag "default" nil)
+                        (integer :format "%v"
+                                 :hide-front-space t)))
+        (expire '(choice :tag "Expire"
+                         (const :tag "off" nil)
+                         (integer :format "%v"
+                                  :hide-front-space t)))
+        (type '(choice :tag "Type"
+                       :value regexp
+                       (const regexp)
+                       (const before)
+                       (const at)
+                       (const after)))
+        (group `(group ,match ,score ,expire ,type))
+        (doc (concat (or (widget-get widget :doc)
+                         (concat "Change score based on the " tag
+                                 " header."))
+                     "
+For the Date header we have three kinda silly match types: `before',
+`at' and `after'.  I can't really imagine this ever being useful, but,
+like, it would feel kinda silly not to provide this function.  Just in
+case.  You never know.  Better safe than sorry.  Once burnt, twice
+shy.  Don't judge a book by its cover.  Never not have sex on a first
+date.  (I have been told that at least one person, and I quote,
+\"found this function indispensable\", however.)
+
+A more useful match type is `regexp'.  With it, you can match the date
+string using a regular expression.  The date is normalized to ISO8601
+compact format first---`YYYYMMDDTHHMMSS'.  If you want to match all
+articles that have been posted on April 1st in every year, you could
+use `....0401.........' as a match string, for instance.  (Note that
+the date is kept in its original time zone, so this will match
+articles that were posted when it was April 1st where the article was
+posted from.  Time zones are such wholesome fun for the whole family,
+eh?")))
+    (widget-put widget :args `(,item
+                              (repeat :inline t
+                                      :indent 0
+                                      :tag ,tag
+                                      :doc ,doc
+                                      :format "%t:\n%h%v%i\n\n"
+                                      ,group))))
+  widget)
+
+(define-widget 'gnus-score-extra 'group
+  "Edit score entries for extra headers."
+  :convert-widget 'gnus-score-extra-convert)
+
+(defun gnus-score-extra-convert (widget)
+  ;; Set args appropriately.
+  (let* ((tag (widget-get widget :tag))
+        (item `(const :format "" :value ,(downcase tag)))
+        (match '(string :tag "Match"))
+        (score '(choice :tag "Score"
+                        (const :tag "default" nil)
+                        (integer :format "%v"
+                                 :hide-front-space t)))
+        (expire '(choice :tag "Expire"
+                         (const :tag "off" nil)
+                         (integer :format "%v"
+                                  :hide-front-space t)))
+        (type '(choice :tag "Type"
+                       :value s
+                       ;; I should really create a forgiving :match
+                       ;; function for each type below, that only
+                       ;; looked at the first letter.
+                       (const :tag "Regexp" r)
+                       (const :tag "Regexp (fixed case)" R)
+                       (const :tag "Substring" s)
+                       (const :tag "Substring (fixed case)" S)
+                       (const :tag "Exact" e)
+                       (const :tag "Exact (fixed case)" E)
+                       (const :tag "Word" w)
+                       (const :tag "Word (fixed case)" W)
+                       (const :tag "default" nil)))
+        (header (if gnus-extra-headers
+                    (let (name)
+                      `(choice :tag "Header"
+                               ,@(mapcar (lambda (h)
+                                           (setq name (symbol-name h))
+                                           (list 'const :tag name name))
+                                         gnus-extra-headers)
+                               (string :tag "Other" :format "%v")))
+                  '(string :tag "Header")))
+        (group `(group ,match ,score ,expire ,type ,header))
+        (doc (concat (or (widget-get widget :doc)
+                         (concat "Change score based on the " tag
+                                 " header.\n")))))
+    (widget-put
+     widget :args
+     `(,item
+       (repeat :inline t
+              :indent 0
+              :tag ,tag
+              :doc ,doc
+              :format "%t:\n%h%v%i\n\n"
+              (choice :format "%v"
+                      :value ("" nil nil s
+                              ,(if gnus-extra-headers
+                                   (symbol-name (car gnus-extra-headers))
+                                 ""))
+                      ,group
+                      sexp)))))
+  widget)
+
+(defvar gnus-custom-scores)
+(defvar gnus-custom-score-alist)
+
+(defun gnus-score-customize (file)
+  "Customize score file FILE.
+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 "No score file for %s"
+           (gnus-group-decoded-name gnus-newsgroup-name)))
+  (let ((scores (gnus-score-load file))
+       (types (mapcar (lambda (entry)
+                        `(group :format "%v%h\n"
+                                :doc ,(nth 2 entry)
+                                (const :format "" ,(nth 0 entry))
+                                ,(nth 1 entry)))
+                      gnus-score-parameters)))
+    ;; Ready.
+    (kill-buffer (gnus-get-buffer-create "*Gnus Customize*"))
+    (switch-to-buffer (gnus-get-buffer-create "*Gnus Customize*"))
+    (gnus-custom-mode)
+    (make-local-variable 'gnus-custom-score-alist)
+    (setq gnus-custom-score-alist scores)
+    (widget-insert "Customize the ")
+    (widget-create 'info-link
+                  :help-echo "Push me to learn more."
+                  :tag "score entries"
+                  "(gnus)Score File Format")
+    (widget-insert " for\n\t")
+    (widget-insert file)
+    (widget-insert "\nand press ")
+    (widget-create 'push-button
+                  :tag "done"
+                  :help-echo "Push me when done customizing."
+                  :action 'gnus-score-customize-done)
+    (widget-insert ".\n
+Check the [ ] for the entries you want to apply to this score file, then
+edit the value to suit your taste.  Don't forget to mark the checkbox,
+if you do all your changes will be lost.  ")
+    (widget-insert "\n\n")
+    (make-local-variable 'gnus-custom-scores)
+    (setq gnus-custom-scores
+         (widget-create 'group
+                        :value scores
+                        `(checklist :inline t
+                                    :greedy t
+                                    (gnus-score-string :tag "From")
+                                    (gnus-score-string :tag "Subject")
+                                    (gnus-score-string :tag "References")
+                                    (gnus-score-string :tag "Xref")
+                                    (gnus-score-extra :tag "Extra")
+                                    (gnus-score-string :tag "Message-ID")
+                                    (gnus-score-integer :tag "Lines")
+                                    (gnus-score-integer :tag "Chars")
+                                    (gnus-score-date :tag "Date")
+                                    (gnus-score-string :tag "Head"
+                                                       :doc "\
+Match all headers in the article.
+
+Using one of `Head', `Body', `All' will slow down scoring considerable.
+")
+                                    (gnus-score-string :tag "Body"
+                                                       :doc "\
+Match the body sans header of the article.
+
+Using one of `Head', `Body', `All' will slow down scoring considerable.
+")
+                                    (gnus-score-string :tag "All"
+                                                       :doc "\
+Match the entire article, including both headers and body.
+
+Using one of `Head', `Body', `All' will slow down scoring
+considerable.
+")
+                                    (gnus-score-string :tag
+                                                       "Followup"
+                                                       :doc "\
+Score all followups to the specified authors.
+
+This entry is somewhat special, in that it will match the `From:'
+header, and affect the score of not only the matching articles, but
+also all followups to the matching articles.  This allows you
+e.g. increase the score of followups to your own articles, or decrease
+the score of followups to the articles of some known trouble-maker.
+")
+                                    (gnus-score-string :tag "Thread"
+                                                       :doc "\
+Add a score entry on all articles that are part of a thread.
+
+This match key works along the same lines as the `Followup' match key.
+If you say that you want to score on a (sub-)thread that is started by
+an article with a `Message-ID' X, then you add a `thread' match.  This
+will add a new `thread' match for each article that has X in its
+`References' header.  (These new `thread' matches will use the
+`Message-ID's of these matching articles.)  This will ensure that you
+can raise/lower the score of an entire thread, even though some
+articles in the thread may not have complete `References' headers.
+Note that using this may lead to nondeterministic scores of the
+articles in the thread.
+")
+                                    ,@types)
+                        '(repeat :inline t
+                                 :tag "Unknown entries"
+                                 sexp)))
+    (use-local-map widget-keymap)
+    (widget-setup)))
+
+(defun gnus-score-customize-done (&rest ignore)
+  "Reset the score alist with the present value."
+  (let ((alist gnus-custom-score-alist)
+       (value (widget-value gnus-custom-scores)))
+    (setcar alist (car value))
+    (setcdr alist (cdr value))
+    (gnus-score-set 'touched '(t) alist))
+  (bury-buffer))
+
+(defvar category-fields nil)
+(defvar gnus-agent-cat-name)
+(defvar gnus-agent-cat-score-file)
+(defvar gnus-agent-cat-length-when-short)
+(defvar gnus-agent-cat-length-when-long)
+(defvar gnus-agent-cat-low-score)
+(defvar gnus-agent-cat-high-score)
+(defvar gnus-agent-cat-enable-expiration)
+(defvar gnus-agent-cat-days-until-old)
+(defvar gnus-agent-cat-predicate)
+(defvar gnus-agent-cat-groups)
+(defvar gnus-agent-cat-enable-undownloaded-faces)
+
+(defun gnus-trim-whitespace (s)
+  (when (string-match "\\`[ \n\t]+" s)
+    (setq s (substring s (match-end 0))))
+  (when (string-match "[ \n\t]+\\'" s)
+    (setq s (substring s 0 (match-beginning 0))))
+  s)
+
+(defmacro gnus-agent-cat-prepare-category-field (parameter)
+  (let* ((entry (assq parameter gnus-agent-parameters))
+         (field (nth 3 entry)))
+    `(let* ((type (copy-sequence
+                   (nth 1 (assq ',parameter gnus-agent-parameters))))
+            (val (,field info))
+            (deflt (if (,field defaults)
+                       (concat " [" (gnus-trim-whitespace
+                                     (gnus-pp-to-string (,field defaults)))
+                               "]")))
+            symb)
+
+       (if (eq (car type) 'radio)
+           (let* ((rtype (nreverse type))
+                  (rt rtype))
+             (while (listp (or (cadr rt) 'not-list))
+               (setq rt (cdr rt)))
+
+             (setcdr rt (cons '(const :format "Inherit " nil) (cdr rt)))
+             (setq type (nreverse rtype))))
+
+       (if deflt
+           (let ((tag (cdr (memq :tag type))))
+             (when (string-match "\n" deflt)
+              (while (progn (setq deflt (replace-match "\n " t t
+                                                       deflt))
+                            (string-match "\n" deflt (match-end 0))))
+              (setq deflt (concat "\n" deflt)))
+
+             (setcar tag (concat (car tag) deflt))))
+
+       (widget-insert "\n")
+
+       (setq val (if val
+                     (widget-create type :value val)
+                   (widget-create type))
+             symb (set (make-local-variable ',field) val))
+
+       (widget-put symb :default val)
+       (widget-put symb :accessor ',field)
+       (push symb category-fields))))
+
+(defun gnus-agent-customize-category (category)
+  "Edit the CATEGORY."
+  (interactive (list (gnus-category-name)))
+  (let ((info (assq category gnus-category-alist))
+        (defaults (list nil '(agent-predicate . false)
+                        (cons 'agent-enable-expiration
+                              gnus-agent-enable-expiration)
+                        '(agent-days-until-old . 7)
+                        (cons 'agent-length-when-short
+                              gnus-agent-short-article)
+                        (cons 'agent-length-when-long gnus-agent-long-article)
+                        (cons 'agent-low-score gnus-agent-low-score)
+                        (cons 'agent-high-score gnus-agent-high-score))))
+
+    (let ((old (get-buffer "*Gnus Agent Category Customize*")))
+      (when old
+        (gnus-kill-buffer old)))
+    (switch-to-buffer (gnus-get-buffer-create
+                       "*Gnus Agent Category Customize*"))
+
+    (let ((inhibit-read-only t))
+      (gnus-custom-mode)
+      (buffer-disable-undo)
+
+      (let* ((name (gnus-agent-cat-name info)))
+        (widget-insert "Customize the Agent Category '")
+        (widget-insert (symbol-name name))
+        (widget-insert "' and press ")
+        (widget-create
+         'push-button
+         :notify
+         (lambda (&rest ignore)
+           (let* ((info (assq gnus-agent-cat-name gnus-category-alist))
+                  (widgets category-fields))
+             (while widgets
+               (let* ((widget (pop widgets))
+                      (value (condition-case nil (widget-value widget) (error))))
+                 (eval `(setf (,(widget-get widget :accessor) ',info)
+                              ',value)))))
+           (gnus-category-write)
+           (gnus-kill-buffer (current-buffer))
+           (when (get-buffer gnus-category-buffer)
+             (switch-to-buffer (get-buffer gnus-category-buffer))
+             (gnus-category-list)))
+                       "Done")
+        (widget-insert
+         "\n    Note: Empty fields default to the customizable global\
+ variables.\n\n")
+
+        (set (make-local-variable 'gnus-agent-cat-name)
+             name))
+
+      (set (make-local-variable 'category-fields) nil)
+      (gnus-agent-cat-prepare-category-field agent-predicate)
+
+      (gnus-agent-cat-prepare-category-field agent-score)
+      (gnus-agent-cat-prepare-category-field agent-short-article)
+      (gnus-agent-cat-prepare-category-field agent-long-article)
+      (gnus-agent-cat-prepare-category-field agent-low-score)
+      (gnus-agent-cat-prepare-category-field agent-high-score)
+
+      ;; The group list is NOT handled with
+      ;; gnus-agent-cat-prepare-category-field as I don't want the
+      ;; group list to appear when customizing a topic.
+      (widget-insert "\n")
+
+      (let ((symb
+             (set
+              (make-local-variable 'gnus-agent-cat-groups)
+              (widget-create
+               `(choice
+                 :format "%[Select Member Groups%]\n%v" :value ignore
+                 (const :menu-tag "do not change" :tag "" :value ignore)
+                 (checklist :entry-format "%b %v"
+                            :menu-tag "display group selectors"
+                            :greedy t
+                            :value
+                            ,(delq nil
+                                   (mapcar
+                                    (lambda (newsrc)
+                                      (car (member
+                                            (gnus-info-group newsrc)
+                                            (gnus-agent-cat-groups info))))
+                                    (cdr gnus-newsrc-alist)))
+                            ,@(mapcar (lambda (newsrc)
+                                        `(const ,(gnus-info-group newsrc)))
+                                      (cdr gnus-newsrc-alist))))))))
+
+      (widget-put symb :default (gnus-agent-cat-groups info))
+      (widget-put symb :accessor 'gnus-agent-cat-groups)
+      (push symb category-fields))
+
+      (widget-insert "\nExpiration Settings ")
+
+      (gnus-agent-cat-prepare-category-field agent-enable-expiration)
+      (gnus-agent-cat-prepare-category-field agent-days-until-old)
+
+      (widget-insert "\nVisual Settings ")
+
+      (gnus-agent-cat-prepare-category-field agent-enable-undownloaded-faces)
+
+      (use-local-map widget-keymap)
+      (widget-setup)
+      (buffer-enable-undo))))
+
+;;; The End:
+
+(provide 'gnus-cus)
+
+;;; gnus-cus.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-delay.el b/xemacs-packages/gnus/lisp/gnus-delay.el
new file mode 100644 (file)
index 0000000..93069e5
--- /dev/null
@@ -0,0 +1,194 @@
+;;; gnus-delay.el --- Delayed posting of articles
+
+;; Copyright (C) 2001-2016 Free Software Foundation, Inc.
+
+;; Author: Kai Großjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+;; Keywords: mail, news, extensions
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; 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 'parse-time-string "parse-time" nil nil)
+
+(defgroup gnus-delay nil
+  "Arrange for sending postings later."
+  :version "22.1"
+  :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."
+  :version "22.1"
+  :type 'integer
+  :group 'gnus-delay)
+
+;;;###autoload
+(defun gnus-delay-article (delay)
+  "Delay this article by some time.
+DELAY is a string, giving the length of the time.  Possible values are:
+
+* <digits><units> for <units> in minutes (`m'), hours (`h'), days (`d'),
+  weeks (`w'), months (`M'), or years (`Y');
+
+* YYYY-MM-DD for a specific date.  The time of day is given by the
+  variable `gnus-delay-default-hour', minute and second are zero.
+
+* hh:mm for a specific time.  Use 24h format.  If it is later than this
+  time, then the deadline is tomorrow, else today."
+  (interactive
+   (list (read-string
+         "Target date (YYYY-MM-DD), time (hh:mm), or length of delay (units in [mhdwMY]): "
+         gnus-delay-default-delay)))
+  ;; Allow spell checking etc.
+  (run-hooks 'message-send-hook)
+  (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)))
+          ;; ... for minute and hour.
+          (aset deadline 1 minute)
+          (aset deadline 2 hour)
+          ;; Convert to seconds.
+          (setq deadline (gnus-float-time (apply 'encode-time
+                                                 (append deadline nil))))
+          ;; If this time has passed already, add a day.
+          (when (< deadline (gnus-float-time))
+            (setq deadline (+ 86400 deadline))) ; 86400 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 (+ (gnus-float-time) delay)))))
+         (t (error "Malformed delay `%s'" delay)))
+    (message-add-header (format "%s: %s" gnus-delay-header deadline)))
+  (set-buffer-modified-p t)
+  ;; If group does not exist, create it.
+  (gnus-agent-queue-setup 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))
+          (message-send-hook (copy-sequence message-send-hook))
+          articles
+          article deadline)
+      (when (gnus-group-entry group)
+       (gnus-activate-group group)
+       (add-hook 'message-send-hook
+                 (lambda () (message-remove-header gnus-delay-header)) t)
+       (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: utf-8
+;; End:
+
+;;; gnus-delay.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-demon.el b/xemacs-packages/gnus/lisp/gnus-demon.el
new file mode 100644 (file)
index 0000000..eb7d0f8
--- /dev/null
@@ -0,0 +1,281 @@
+;;; gnus-demon.el --- daemonic Gnus behavior
+
+;; Copyright (C) 1995-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'gnus)
+(require 'gnus-int)
+(require 'nnheader)
+(require 'nntp)
+(require 'nnmail)
+
+(defgroup gnus-demon nil
+  "Demonic behavior."
+  :group 'gnus)
+
+(defcustom gnus-demon-handlers nil
+  "Alist of daemonic handlers to be run at intervals.
+Each handler is a list on the form
+
+\(FUNCTION TIME IDLE)
+
+FUNCTION is the function to be called.  TIME is the number of
+`gnus-demon-timestep's between each call.
+If nil, never call. If t, call each `gnus-demon-timestep'.
+
+If IDLE is t, only call each time Emacs has been idle for TIME.
+If IDLE is a number, only call when Emacs has been idle more than
+this number of `gnus-demon-timestep's.
+If IDLE is nil, don't care about idleness.
+If IDLE is a number and TIME is nil, then call once each time
+Emacs has been idle for IDLE `gnus-demon-timestep's."
+  :group 'gnus-demon
+  :type '(repeat (list function
+                      (choice :tag "Time"
+                              (const :tag "never" nil)
+                              (const :tag "one" t)
+                              (integer :tag "steps" 1))
+                      (choice :tag "Idle"
+                              (const :tag "don't care" nil)
+                              (const :tag "for a while" t)
+                              (integer :tag "steps" 1)))))
+
+(defcustom gnus-demon-timestep 60
+  "Number of seconds in each demon timestep."
+  :group 'gnus-demon
+  :type 'integer)
+
+;;; Internal variables.
+
+(defvar gnus-demon-timers nil
+  "Plist of idle timers which are running.")
+(defvar gnus-inhibit-demon nil
+  "If non-nil, no daemonic function will be run.")
+
+;;; Functions.
+
+(defun gnus-demon-add-handler (function time idle)
+  "Add the handler FUNCTION to be run at TIME and IDLE."
+  ;; First remove any old handlers that use this function.
+  (gnus-demon-remove-handler function)
+  ;; Then add the new one.
+  (push (list function time idle) gnus-demon-handlers)
+  (gnus-demon-init))
+
+(defun gnus-demon-remove-handler (function &optional no-init)
+  "Remove the handler FUNCTION from the list of handlers."
+  (gnus-alist-pull function gnus-demon-handlers)
+  (unless no-init
+    (gnus-demon-init)))
+
+(defun gnus-demon-idle-since ()
+  "Return the number of seconds since when Emacs is idle."
+  (if (featurep 'xemacs)
+      (itimer-time-difference (current-time) last-command-event-time)
+    (float-time (or (current-idle-time)
+                    '(0 0 0)))))
+
+(defun gnus-demon-run-callback (func &optional idle time special)
+  "Run FUNC if Emacs has been idle for longer than IDLE seconds.
+If not, and a TIME is given, restart a new idle timer, so FUNC
+can be called at the next opportunity. Such a special idle run is
+marked with SPECIAL."
+  (unless gnus-inhibit-demon
+    (block run-callback
+      (when (eq idle t)
+        (setq idle 0.001))
+      (cond (special
+             (setq gnus-demon-timers
+                   (plist-put gnus-demon-timers func
+                              (run-with-timer time time 'gnus-demon-run-callback
+                                              func idle time))))
+            ((and idle (> idle (gnus-demon-idle-since)))
+             (when time
+               (nnheader-cancel-timer (plist-get gnus-demon-timers func))
+               (setq gnus-demon-timers
+                     (plist-put gnus-demon-timers func
+                               (run-with-idle-timer idle nil
+                                                    'gnus-demon-run-callback
+                                                    func idle time t))))
+             (return-from run-callback)))
+      (with-local-quit
+        (ignore-errors
+          (funcall func))))))
+
+(defun gnus-demon-init ()
+  "Initialize the Gnus daemon."
+  (interactive)
+  (gnus-demon-cancel)
+  (dolist (handler gnus-demon-handlers)
+    ;; Set up the timer.
+    (let* ((func (nth 0 handler))
+           (time (nth 1 handler))
+           (idle (nth 2 handler))
+           ;; Compute time according with timestep.
+           ;; If t, replace by 1
+           (time (cond ((eq time t)
+                        gnus-demon-timestep)
+                       ((null time)
+                       nil)
+                      ((stringp time)
+                       (* (gnus-demon-time-to-step time) gnus-demon-timestep))
+                       (t
+                       (* time gnus-demon-timestep))))
+          (idle (cond ((numberp idle)
+                       (* idle gnus-demon-timestep))
+                      ((and (eq idle t) (numberp time))
+                       time)
+                      (t
+                       idle)))
+
+           (timer
+            (cond
+             ;; (func nil number)
+             ;; Only call when Emacs has been idle for `idle'
+             ((and (null time) (numberp idle))
+              (run-with-idle-timer idle t 'gnus-demon-run-callback func))
+             ;; (func number any)
+             ;; Call every `time'
+             ((integerp time)
+              (run-with-timer time time 'gnus-demon-run-callback
+                             func idle time))
+             ;; (func string any)
+             ((stringp time)
+              (run-with-timer time (* 24 60 60) 'gnus-demon-run-callback
+                             func idle)))))
+      (when timer
+        (setq gnus-demon-timers (plist-put gnus-demon-timers func timer))))))
+
+(defun gnus-demon-time-to-step (time)
+  "Find out how many steps to TIME, which is on the form \"17:43\"."
+  (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)))))
+    ;; return number of timesteps in the number of seconds
+    (round (/ diff gnus-demon-timestep))))
+
+(gnus-add-shutdown 'gnus-demon-cancel 'gnus)
+
+(defun gnus-demon-cancel ()
+  "Cancel any Gnus daemons."
+  (interactive)
+  (dotimes (i (/ (length gnus-demon-timers) 2))
+    (nnheader-cancel-timer (nth (1+ (* i 2)) gnus-demon-timers)))
+  (setq gnus-demon-timers nil))
+
+(defun gnus-demon-add-disconnection ()
+  "Add daemonic server disconnection to Gnus."
+  (gnus-demon-add-handler 'gnus-demon-close-connections nil 30))
+
+(defun gnus-demon-close-connections ()
+  (save-window-excursion
+    (gnus-close-backends)))
+
+(defun gnus-demon-add-nntp-close-connection ()
+  "Add daemonic nntp server disconnection to Gnus.
+If no commands have gone out via nntp during the last five
+minutes, the connection is closed."
+  (gnus-demon-add-handler 'gnus-demon-nntp-close-connection 5 nil))
+
+(defun gnus-demon-nntp-close-connection ()
+  (save-window-excursion
+    (when (time-less-p '(0 300) (time-since nntp-last-command-time))
+      (nntp-close-server))))
+
+(defun gnus-demon-add-scanmail ()
+  "Add daemonic scanning of mail from the mail backends."
+  (gnus-demon-add-handler 'gnus-demon-scan-mail 120 60))
+
+(defun gnus-demon-scan-mail ()
+  (save-window-excursion
+    (let ((servers gnus-opened-servers)
+         server
+         (nnmail-fetched-sources (list t)))
+      (while (setq server (car (pop servers)))
+       (and (gnus-check-backend-function 'request-scan (car server))
+            (or (gnus-server-opened server)
+                (gnus-open-server server))
+            (gnus-request-scan nil server))))))
+
+(defun gnus-demon-add-rescan ()
+  "Add daemonic scanning of new articles from all backends."
+  (gnus-demon-add-handler 'gnus-demon-scan-news 120 60))
+
+(defun gnus-demon-scan-news ()
+  (let ((win (current-window-configuration)))
+    (unwind-protect
+       (save-window-excursion
+         (when (gnus-alive-p)
+           (with-current-buffer gnus-group-buffer
+             (gnus-group-get-new-news))))
+      (set-window-configuration win))))
+
+(defun gnus-demon-add-scan-timestamps ()
+  "Add daemonic updating of timestamps in empty newgroups."
+  (gnus-demon-add-handler 'gnus-demon-scan-timestamps nil 30))
+
+(defun gnus-demon-scan-timestamps ()
+  "Set the timestamp on all newsgroups with no unread and no ticked articles."
+  (when (gnus-alive-p)
+    (let ((cur-time (current-time))
+         (newsrc (cdr gnus-newsrc-alist))
+         info group unread has-ticked)
+      (while (setq info (pop newsrc))
+       (setq group (gnus-info-group info)
+             unread (gnus-group-unread group)
+             has-ticked (cdr (assq 'tick (gnus-info-marks info))))
+       (when (and (numberp unread)
+                  (= unread 0)
+                  (not has-ticked))
+         (gnus-group-set-parameter group 'timestamp cur-time))))))
+
+(provide 'gnus-demon)
+
+;;; gnus-demon.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-diary.el b/xemacs-packages/gnus/lisp/gnus-diary.el
new file mode 100644 (file)
index 0000000..6f0bfe6
--- /dev/null
@@ -0,0 +1,403 @@
+;;; gnus-diary.el --- Wrapper around the NNDiary Gnus back end
+
+;; Copyright (C) 1999-2016 Free Software Foundation, Inc.
+
+;; Author:        Didier Verna <didier@xemacs.org>
+;; Maintainer:    Didier Verna <didier@xemacs.org>
+;; Created:       Tue Jul 20 10:42:55 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+
+;; Contents management by FCM version 0.1.
+
+;; Description:
+;; ===========
+
+;; gnus-diary is a utility toolkit used on top of the nndiary back end. It is
+;; now fully documented in the Gnus manual.
+
+
+;; Bugs / Todo:
+;; ===========
+
+
+;;; Code:
+
+(require 'nndiary)
+(require 'message)
+(require 'gnus-art)
+
+(defgroup gnus-diary nil
+  "Utilities on top of the nndiary back end for Gnus."
+  :version "22.1"
+  :group '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 appointments 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 back end 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) (setcdr (cdr 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) (setcdr (cdr 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) (car (cddr 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.
+;;;###autoload
+(defun gnus-user-format-function-d (header)
+  ;; Return an approximate delay string for the next occurrence 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.
+;;;###autoload
+(defun gnus-user-format-function-D (header)
+  ;; Returns a formatted time string for the next occurrence 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 appointments.
+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.
+
+  ;; Posting style:
+  (let ((posting-style (gnus-group-get-parameter group 'posting-style t))
+       (headers nndiary-headers)
+       header)
+    (while headers
+      (setq header (format "X-Diary-%s" (caar headers))
+           headers (cdr headers))
+      (unless (assoc header posting-style)
+       (setq posting-style (append posting-style (list (list header "*"))))))
+    (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 back end function.
+;; Thus, `nndiary-request-create-group-functions' 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-functions
+         'gnus-diary-update-group-parameters)
+;; Now that we have `gnus-subscribe-newsgroup-functions', this is not needed
+;; anymore. Maybe I should remove this completely.
+(add-hook 'nndiary-request-update-info-functions
+         'gnus-diary-update-group-parameters)
+(add-hook 'gnus-subscribe-newsgroup-functions
+         '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) (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))
+              (error
+               (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))
+                      (gnus-completing-read prompt (cons "*" (mapcar 'car (nth 1 head)))
+                                             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))
+            (error
+             (setq invalid t))))
+        (gnus-diary-add-header (concat header ": " value))
+        ))
+     nndiary-headers)
+    ))
+
+(add-hook 'nndiary-request-accept-article-functions
+         (lambda () (gnus-diary-check-message nil)))
+
+(define-key message-mode-map "\C-c\C-fd" 'gnus-diary-check-message)
+(define-key gnus-article-edit-mode-map "\C-c\C-fd" 'gnus-diary-check-message)
+
+
+;; The end ==================================================================
+
+(defun gnus-diary-version ()
+  "Current Diary back end version."
+  (interactive)
+  (message "NNDiary version %s" nndiary-version))
+
+(provide 'gnus-diary)
+
+;;; gnus-diary.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-dired.el b/xemacs-packages/gnus/lisp/gnus-dired.el
new file mode 100644 (file)
index 0000000..3bbd4de
--- /dev/null
@@ -0,0 +1,263 @@
+;;; gnus-dired.el --- utility functions where gnus and dired meet
+
+;; Copyright (C) 1996-1999, 2001-2016 Free Software Foundation, Inc.
+
+;; Authors: Benjamin Rutt <brutt@bloomington.in.us>,
+;;          Shenghuo Zhu <zsh@cs.rochester.edu>
+;; Keywords: mail, news, extensions
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package provides utility functions for intersections of gnus
+;; and dired.  To enable the gnus-dired-mode minor mode which will
+;; have the effect of installing keybindings in dired-mode, place the
+;; following in your ~/.gnus:
+
+;; (require 'gnus-dired) ;, isn't needed due to autoload cookies
+;; (add-hook 'dired-mode-hook 'turn-on-gnus-dired-mode)
+
+;; Note that if you visit dired buffers before your ~/.gnus file has
+;; been read, those dired buffers won't have the keybindings in
+;; effect.  To get around that problem, you may want to add the above
+;; statements to your ~/.emacs instead.
+
+;;; Code:
+
+(eval-when-compile
+  (when (featurep 'xemacs)
+    (require 'easy-mmode))) ; for `define-minor-mode'
+(require 'dired)
+(autoload 'mml-attach-file "mml")
+(autoload 'mm-default-file-encoding "mm-decode");; Shift this to `mailcap.el'?
+(autoload 'mailcap-extension-to-mime "mailcap")
+(autoload 'mailcap-mime-info "mailcap")
+
+;; Maybe shift this function to `mailcap.el'?
+(autoload 'mm-mailcap-command "mm-decode")
+
+(autoload 'ps-print-preprint "ps-print")
+
+;; Autoloads to avoid byte-compiler warnings.  These are used only if the user
+;; customizes `gnus-dired-mail-mode' to use Message and/or Gnus.
+(autoload 'message-buffers "message")
+(autoload 'gnus-print-buffer "gnus-sum")
+
+(defvar gnus-dired-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "\C-c\C-m\C-a" 'gnus-dired-attach)
+    (define-key map "\C-c\C-m\C-l" 'gnus-dired-find-file-mailcap)
+    (define-key map "\C-c\C-m\C-p" 'gnus-dired-print)
+    map))
+
+;; FIXME: Make it customizable, change the default to `mail-user-agent' when
+;; this file is renamed (e.g. to `dired-mime.el').
+
+(defcustom gnus-dired-mail-mode 'gnus-user-agent ;; mail-user-agent
+  "Your preference for a mail composition package.
+See `mail-user-agent' for more information."
+  :group 'mail ;; dired?
+  :version "23.1" ;; No Gnus
+  :type '(radio (function-item :tag "Default Emacs mail"
+                              :format "%t\n"
+                              sendmail-user-agent)
+               (function-item :tag "Emacs interface to MH"
+                              :format "%t\n"
+                              mh-e-user-agent)
+               (function-item :tag "Gnus Message package"
+                              :format "%t\n"
+                              message-user-agent)
+               (function-item :tag "Gnus Message with full Gnus features"
+                              :format "%t\n"
+                              gnus-user-agent)
+               (function :tag "Other")))
+
+(eval-when-compile
+  (when (featurep 'xemacs)
+    (defvar gnus-dired-mode-hook)
+    (defvar gnus-dired-mode-on-hook)
+    (defvar gnus-dired-mode-off-hook)))
+
+(define-minor-mode gnus-dired-mode
+  "Minor mode for intersections of gnus and dired.
+
+\\{gnus-dired-mode-map}"
+  :keymap gnus-dired-mode-map
+  (unless (derived-mode-p 'dired-mode)
+    (setq gnus-dired-mode nil)))
+
+;;;###autoload
+(defun turn-on-gnus-dired-mode ()
+  "Convenience method to turn on gnus-dired-mode."
+  (interactive)
+  (gnus-dired-mode 1))
+
+(defun gnus-dired-mail-buffers ()
+  "Return a list of active mail composition buffers."
+  (if (and (memq gnus-dired-mail-mode '(message-user-agent gnus-user-agent))
+          (require 'message)
+          (fboundp 'message-buffers))
+      (message-buffers)
+    ;; Cf. `message-buffers' in `message.el':
+    (let (buffers)
+      (save-excursion
+       (dolist (buffer (buffer-list t))
+         (set-buffer buffer)
+         (when (eq major-mode 'mail-mode)
+           (push (buffer-name buffer) buffers))))
+      (nreverse buffers))))
+
+(autoload 'gnus-completing-read "gnus-util")
+
+;; Method to attach files to a mail composition.
+(defun gnus-dired-attach (files-to-attach)
+  "Attach dired's marked files to a gnus message composition.
+If called non-interactively, FILES-TO-ATTACH should be a list of
+filenames."
+  (interactive
+   (list
+    (delq nil
+         (mapcar
+          ;; don't attach directories
+          (lambda (f) (if (file-directory-p f) nil f))
+          (nreverse
+           (let ((arg nil)) ;; Silence XEmacs 21.5 when compiling.
+             (dired-map-over-marks (dired-get-filename) arg)))))))
+  (let ((destination nil)
+       (files-str nil)
+       (bufs nil))
+    ;; warn if user tries to attach without any files marked
+    (if (null files-to-attach)
+       (error "No files to attach")
+      (setq files-str
+           (mapconcat
+            (lambda (f) (file-name-nondirectory f))
+            files-to-attach ", "))
+      (setq bufs (gnus-dired-mail-buffers))
+
+      ;; set up destination mail composition buffer
+      (if (and bufs
+              (y-or-n-p "Attach files to existing mail composition buffer? "))
+         (setq destination
+               (if (= (length bufs) 1)
+                   (get-buffer (car bufs))
+                 (gnus-completing-read "Attach to buffer"
+                                         bufs t nil nil (car bufs))))
+       ;; setup a new mail composition buffer
+       (let ((mail-user-agent gnus-dired-mail-mode)
+             ;; A workaround to prevent Gnus from displaying the Gnus
+             ;; logo when invoking this command without loading Gnus.
+             ;; Gnus demonstrates it when gnus.elc is being loaded if
+             ;; a command of which the name is prefixed with "gnus"
+             ;; causes that autoloading.  See the code in question,
+             ;; that is the one first found in gnus.el by performing
+             ;; `C-s this-command'.
+             (this-command (if (eq gnus-dired-mail-mode 'gnus-user-agent)
+                               'gnoose-dired-attach
+                             this-command)))
+         (compose-mail))
+       (setq destination (current-buffer)))
+
+      ;; set buffer to destination buffer, and attach files
+      (set-buffer destination)
+      (goto-char (point-max))          ;attach at end of buffer
+      (while files-to-attach
+       (mml-attach-file (car files-to-attach)
+                        (or (mm-default-file-encoding (car files-to-attach))
+                            "application/octet-stream") nil)
+       (setq files-to-attach (cdr files-to-attach)))
+      (message "Attached file(s) %s" files-str))))
+
+(autoload 'mailcap-parse-mailcaps "mailcap" "" t)
+
+(defun gnus-dired-find-file-mailcap (&optional file-name arg)
+  "In dired, visit FILE-NAME according to the mailcap file.
+If ARG is non-nil, open it in a new buffer."
+  (interactive (list
+               (file-name-sans-versions (dired-get-filename) t)
+               current-prefix-arg))
+  (mailcap-parse-mailcaps)
+  (if (file-exists-p file-name)
+      (let (mime-type method)
+       (if (and (not arg)
+                (not (file-directory-p file-name))
+                (string-match "\\.[^\\.]+$" file-name)
+                (setq mime-type
+                      (mailcap-extension-to-mime
+                       (match-string 0 file-name)))
+                (stringp
+                 (setq method
+                       (cdr (assoc 'viewer
+                                   (car (mailcap-mime-info mime-type
+                                                           'all
+                                                           'no-decode)))))))
+           (let ((view-command (mm-mailcap-command method file-name nil)))
+             (message "viewing via %s" view-command)
+             (start-process "*display*"
+                            nil
+                            shell-file-name
+                            shell-command-switch
+                            view-command))
+         (find-file file-name)))
+    (if (file-symlink-p file-name)
+       (error "File is a symlink to a nonexistent target")
+      (error "File no longer exists; type `g' to update Dired buffer"))))
+
+(defun gnus-dired-print (&optional file-name print-to)
+  "In dired, print FILE-NAME according to the mailcap file.
+
+If there is no print command, print in a PostScript image. If the
+optional argument PRINT-TO is nil, send the image to the printer. If
+PRINT-TO is a string, save the PostScript image in a file with that
+name.  If PRINT-TO is a number, prompt the user for the name of the
+file to save in."
+  (interactive (list
+               (file-name-sans-versions (dired-get-filename) t)
+               (ps-print-preprint current-prefix-arg)))
+  (mailcap-parse-mailcaps)
+  (cond
+   ((file-directory-p file-name)
+    (error "Can't print a directory"))
+   ((file-exists-p file-name)
+    (let (mime-type method)
+      (if (and (string-match "\\.[^\\.]+$" file-name)
+              (setq mime-type
+                    (mailcap-extension-to-mime
+                     (match-string 0 file-name)))
+              (stringp
+               (setq method (mailcap-mime-info mime-type "print"
+                                               'no-decode))))
+         (call-process shell-file-name nil
+                       (generate-new-buffer " *mm*")
+                       nil
+                       shell-command-switch
+                       (mm-mailcap-command method file-name mime-type))
+       (with-temp-buffer
+         (insert-file-contents file-name)
+         (if (eq gnus-dired-mail-mode 'gnus-user-agent)
+             (gnus-print-buffer)
+           ;; FIXME:
+           (error "MIME print only implemented via Gnus")))
+       (ps-despool print-to))))
+   ((file-symlink-p file-name)
+     (error "File is a symlink to a nonexistent target"))
+    (t
+     (error "File no longer exists; type `g' to update Dired buffer"))))
+
+(provide 'gnus-dired)
+
+;;; gnus-dired.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-draft.el b/xemacs-packages/gnus/lisp/gnus-draft.el
new file mode 100644 (file)
index 0000000..b5b17ba
--- /dev/null
@@ -0,0 +1,334 @@
+;;; gnus-draft.el --- draft message support for Gnus
+
+;; Copyright (C) 1997-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'gnus)
+(require 'gnus-sum)
+(require 'message)
+(require 'gnus-msg)
+(require 'nndraft)
+(require 'gnus-agent)
+(eval-when-compile (require 'cl))
+(eval-when-compile
+  (when (featurep 'xemacs)
+    (require 'easy-mmode))) ; for `define-minor-mode'
+
+;;; Draft minor mode
+
+(defvar gnus-draft-mode-map
+  (let ((map (make-sparse-keymap)))
+    (gnus-define-keys map
+     "Dt" gnus-draft-toggle-sending
+     "e"  gnus-draft-edit-message ;; Use `B w' for `gnus-summary-edit-article'
+     "De" gnus-draft-edit-message
+     "Ds" gnus-draft-send-message
+     "DS" gnus-draft-send-all-messages)
+    map))
+
+(defun gnus-draft-make-menu-bar ()
+  (unless (boundp 'gnus-draft-menu)
+    (easy-menu-define
+     gnus-draft-menu gnus-draft-mode-map ""
+     '("Drafts"
+       ["Toggle whether to send" gnus-draft-toggle-sending t]
+       ["Edit" gnus-draft-edit-message t]
+       ["Send selected message(s)" gnus-draft-send-message t]
+       ["Send all messages" gnus-draft-send-all-messages t]
+       ["Delete draft" gnus-summary-delete-article t]))))
+
+(define-minor-mode gnus-draft-mode
+  "Minor mode for providing a draft summary buffers.
+
+\\{gnus-draft-mode-map}"
+  :lighter " Draft" :keymap gnus-draft-mode-map
+  (cond
+   ((not (derived-mode-p 'gnus-summary-mode)) (setq gnus-draft-mode nil))
+   (gnus-draft-mode
+    ;; Set up the menu.
+    (when (gnus-visual-p 'draft-menu 'menu)
+      (gnus-draft-make-menu-bar))
+    (add-hook 'gnus-summary-prepare-exit-hook 'gnus-draft-clear-marks t t))))
+
+;;; Commands
+
+(defun gnus-draft-toggle-sending (article)
+  "Toggle whether to send an article or not."
+  (interactive (list (gnus-summary-article-number)))
+  (if (gnus-draft-article-sendable-p article)
+      (progn
+       (push article gnus-newsgroup-unsendable)
+       (gnus-summary-mark-article article gnus-unsendable-mark))
+    (setq gnus-newsgroup-unsendable
+         (delq article gnus-newsgroup-unsendable))
+    (gnus-summary-mark-article article gnus-unread-mark))
+  (gnus-summary-position-point))
+
+(defun gnus-draft-edit-message ()
+  "Enter a mail/post buffer to edit and send the draft."
+  (interactive)
+  (let ((article (gnus-summary-article-number))
+       (group gnus-newsgroup-name))
+    (gnus-draft-check-draft-articles (list article))
+    (gnus-summary-mark-as-read article gnus-canceled-mark)
+    (gnus-draft-setup article group t)
+    (set-buffer-modified-p t)
+    (save-excursion
+      (save-restriction
+       (message-narrow-to-headers)
+       (message-remove-header "date")))
+    (let ((message-draft-headers
+          (delq 'Date (copy-sequence message-draft-headers))))
+      (save-buffer))
+    (let ((gnus-verbose-backends nil))
+      (gnus-request-expire-articles (list article) group t))
+    (push
+     `((lambda ()
+        (when (gnus-buffer-exists-p ,gnus-summary-buffer)
+          (save-excursion
+            (set-buffer ,gnus-summary-buffer)
+            (gnus-cache-possibly-remove-article ,article nil nil nil t)))))
+     message-send-actions)))
+
+(defun gnus-draft-send-message (&optional n)
+  "Send the current draft(s).
+Obeys the standard process/prefix convention."
+  (interactive "P")
+  (let* ((articles (gnus-summary-work-articles n))
+        (total (length articles))
+        article)
+    (gnus-draft-check-draft-articles articles)
+    (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..."
+                      (- total (length articles)) total)))
+         (gnus-draft-send article gnus-newsgroup-name t))
+       (gnus-summary-mark-article article gnus-canceled-mark)))))
+
+(defun gnus-draft-send (article &optional group interactive)
+  "Send message ARTICLE."
+  (let* ((is-queue (or (not group)
+                       (equal group "nndraft:queue")))
+         (message-syntax-checks (if interactive message-syntax-checks
+                                  'dont-check-for-anything-just-trust-me))
+         (message-hidden-headers nil)
+         (message-inhibit-body-encoding (or is-queue
+                                            message-inhibit-body-encoding))
+         (message-send-hook (and (not is-queue)
+                                 message-send-hook))
+         (message-setup-hook (and (not is-queue)
+                                  message-setup-hook))
+        (gnus-message-setup-hook (and (not is-queue)
+                                      gnus-message-setup-hook))
+        (message-signature (and (not is-queue)
+                                message-signature))
+         (gnus-agent-queue-mail (and (not is-queue)
+                                     gnus-agent-queue-mail))
+        (rfc2047-encode-encoded-words nil)
+         type method move-to)
+    (gnus-draft-setup article (or group "nndraft:queue") nil 'dont-pop)
+    ;; We read the meta-information that says how and where
+    ;; this message is to be sent.
+    (save-restriction
+      (message-narrow-to-headers)
+      (when (re-search-forward
+            (concat "^" (regexp-quote gnus-agent-target-move-group-header)
+                    ":") nil t)
+       (skip-syntax-forward "-")
+       (setq move-to (buffer-substring (point) (point-at-eol)))
+       (message-remove-header gnus-agent-target-move-group-header))
+      (goto-char (point-min))
+      (when (re-search-forward
+            (concat "^" (regexp-quote gnus-agent-meta-information-header) ":")
+            nil t)
+       (setq type (ignore-errors (read (current-buffer)))
+             method (ignore-errors (read (current-buffer))))
+       (message-remove-header gnus-agent-meta-information-header)))
+    ;; Let Agent restore any GCC lines and have message.el perform them.
+    (gnus-agent-restore-gcc)
+    ;; Then we send it.  If we have no meta-information, we just send
+    ;; it and let Message figure out how.
+    (when (and (or (null method)
+                  (gnus-server-opened method)
+                  (gnus-open-server method))
+              (if type
+                  (let ((message-this-is-news (eq type 'news))
+                        (message-this-is-mail (eq type 'mail))
+                        (gnus-post-method method)
+                        (message-post-method method))
+                    (if move-to
+                        (gnus-inews-do-gcc move-to)
+                      (message-send-and-exit)))
+                (if move-to
+                    (gnus-inews-do-gcc move-to)
+                  (message-send-and-exit))))
+      (let ((gnus-verbose-backends nil))
+       (gnus-request-expire-articles
+        (list article) (or group "nndraft:queue") t)))))
+
+(defun gnus-draft-send-all-messages ()
+  "Send all the sendable drafts."
+  (interactive)
+  (when (or
+        gnus-expert-user
+        (gnus-y-or-n-p
+         "Send all drafts? "))
+    (gnus-uu-mark-buffer)
+    (gnus-draft-send-message)))
+
+(defun gnus-group-send-queue ()
+  "Send all sendable articles from the queue group."
+  (interactive)
+  (when (or gnus-plugged
+           (not gnus-agent-prompt-send-queue)
+           (gnus-y-or-n-p "Gnus is unplugged; really send queue? "))
+    (gnus-activate-group "nndraft:queue")
+    (save-excursion
+      (let* ((articles (nndraft-articles))
+            (unsendable (gnus-uncompress-range
+                         (cdr (assq 'unsend
+                                    (gnus-info-marks
+                                     (gnus-get-info "nndraft:queue"))))))
+            (gnus-posting-styles nil)
+            message-send-mail-partially-limit
+            (total (length articles))
+            article)
+       (while (setq article (pop articles))
+         (unless (memq article unsendable)
+           (let ((message-sending-message
+                  (format "Sending message %d of %d..."
+                          (- total (length articles)) total)))
+             (gnus-draft-send article))))))
+    (gnus-group-refresh-group "nndraft:queue")))
+
+;;;###autoload
+(defun gnus-draft-reminder ()
+  "Reminder user if there are unsent drafts."
+  (interactive)
+  (if (gnus-alive-p)
+      (let (active)
+       (catch 'continue
+         (dolist (group '("nndraft:drafts" "nndraft:queue"))
+           (setq active (gnus-activate-group group))
+           (if (and active (>= (cdr active) (car active)))
+               (if (y-or-n-p "There are unsent drafts.  Confirm to exit? ")
+                   (throw 'continue t)
+                 (error "Stop!"))))))))
+
+(defcustom gnus-draft-setup-hook nil
+  "Hook run after setting up a draft buffer."
+  :group 'gnus-message
+  :version "23.1" ;; No Gnus
+  :type 'hook)
+
+
+(defun gnus-draft-setup (narticle group &optional restore dont-pop)
+  "Setup a mail draft buffer.
+If DONT-POP is nil, display the buffer after setting it up."
+  (let (ga)
+    (gnus-setup-message 'forward
+      (let ((article narticle))
+        (message-mail nil nil nil nil
+                      (if dont-pop
+                          (lambda (buf) (set-buffer (get-buffer-create buf)))))
+        (let ((inhibit-read-only t))
+          (erase-buffer))
+        (if (not (gnus-request-restore-buffer article group))
+            (error "Couldn't restore the article")
+          (when (and restore
+                     (equal group "nndraft:queue"))
+            (mime-to-mml))
+          ;; Insert the separator.
+          (goto-char (point-min))
+          (search-forward "\n\n")
+          (forward-char -1)
+          (save-restriction
+            (narrow-to-region (point-min) (point))
+            (setq ga
+                  (message-fetch-field gnus-draft-meta-information-header)))
+          (insert mail-header-separator)
+          (forward-line 1)
+          (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)))
+      (gnus-configure-posting-styles)
+      (setq gnus-message-group-art (cons gnus-newsgroup-name (cadr ga)))
+      (setq message-post-method
+            `(lambda (arg)
+               (gnus-post-method arg ,(car ga))))
+      (unless (equal (cadr ga) "")
+        (dolist (article (cdr ga))
+          (message-add-action
+           `(progn
+              (gnus-add-mark ,(car ga) 'replied ,article)
+              (gnus-request-set-mark ,(car ga) (list (list (list ,article)
+                                                           'add '(reply)))))
+           'send))))
+    (run-hooks 'gnus-draft-setup-hook)))
+
+(defun gnus-draft-article-sendable-p (article)
+  "Say whether ARTICLE is sendable."
+  (not (memq article gnus-newsgroup-unsendable)))
+
+(defun gnus-draft-check-draft-articles (articles)
+  "Check whether the draft articles ARTICLES are under edit."
+  (when (equal gnus-newsgroup-name "nndraft:drafts")
+    (let ((buffers (buffer-list))
+         file buffs buff)
+      (save-current-buffer
+       (while (and articles
+                   (not buff))
+         (setq file (nndraft-article-filename (pop articles))
+               buffs buffers)
+         (while buffs
+           (set-buffer (setq buff (pop buffs)))
+           (if (and buffer-file-name
+                    (equal (file-remote-p file)
+                           (file-remote-p buffer-file-name))
+                    (string-equal (file-truename buffer-file-name)
+                                  (file-truename file))
+                    (buffer-modified-p))
+               (setq buffs nil)
+             (setq buff nil)))))
+      (when buff
+       (let* ((window (get-buffer-window buff t))
+              (frame (and window (window-frame window))))
+         (if frame
+             (gnus-select-frame-set-input-focus frame)
+           (pop-to-buffer buff t)))
+       (error "The draft %s is under edit" file)))))
+
+(defun gnus-draft-clear-marks ()
+  (setq gnus-newsgroup-reads nil
+       gnus-newsgroup-marked nil
+       gnus-newsgroup-unreads (nndraft-articles)))
+
+(provide 'gnus-draft)
+
+;;; gnus-draft.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-dup.el b/xemacs-packages/gnus/lisp/gnus-dup.el
new file mode 100644 (file)
index 0000000..bc11ba1
--- /dev/null
@@ -0,0 +1,161 @@
+;;; gnus-dup.el --- suppression of duplicate articles in Gnus
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package tries to mark articles as read the second time the
+;; user reads a copy.  This is useful if the server doesn't support
+;; Xref properly, or if the user reads the same group from several
+;; servers.
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'gnus)
+(require 'gnus-art)
+
+(defgroup gnus-duplicate nil
+  "Suppression of duplicate articles."
+  :group 'gnus)
+
+(defcustom gnus-save-duplicate-list nil
+  "*If non-nil, save the duplicate list when shutting down Gnus.
+If nil, duplicate suppression will only work on duplicates
+seen in the same session."
+  :group 'gnus-duplicate
+  :type 'boolean)
+
+(defcustom gnus-duplicate-list-length 10000
+  "*The number of Message-IDs to keep in the duplicate suppression list."
+  :group 'gnus-duplicate
+  :type 'integer)
+
+(defcustom gnus-duplicate-file (nnheader-concat gnus-directory "suppression")
+  "*The name of the file to store the duplicate suppression list."
+  :group 'gnus-duplicate
+  :type 'file)
+
+;;; Internal variables
+
+(defvar gnus-dup-list nil)
+(defvar gnus-dup-hashtb nil)
+
+(defvar gnus-dup-list-dirty nil)
+
+;;;
+;;; Starting and stopping
+;;;
+
+(gnus-add-shutdown 'gnus-dup-close 'gnus)
+
+(defun gnus-dup-close ()
+  "Possibly save the duplicate suppression list and shut down the subsystem."
+  (gnus-dup-save)
+  (setq gnus-dup-list nil
+       gnus-dup-hashtb nil
+       gnus-dup-list-dirty nil))
+
+(defun gnus-dup-open ()
+  "Possibly read the duplicate suppression list and start the subsystem."
+  (if gnus-save-duplicate-list
+      (gnus-dup-read)
+    (setq gnus-dup-list nil))
+  (setq gnus-dup-hashtb (gnus-make-hashtable gnus-duplicate-list-length))
+  ;; Enter all Message-IDs into the hash table.
+  (let ((obarray gnus-dup-hashtb))
+    (mapc 'intern gnus-dup-list)))
+
+(defun gnus-dup-read ()
+  "Read the duplicate suppression list."
+  (setq gnus-dup-list nil)
+  (when (file-exists-p gnus-duplicate-file)
+    (load gnus-duplicate-file t t t)))
+
+(defun gnus-dup-save ()
+  "Save the duplicate suppression list."
+  (when (and gnus-save-duplicate-list
+            gnus-dup-list-dirty)
+    (with-temp-file gnus-duplicate-file
+      (gnus-prin1 `(setq gnus-dup-list ',gnus-dup-list))))
+  (setq gnus-dup-list-dirty nil))
+
+;;;
+;;; Interface functions
+;;;
+
+(defun gnus-dup-enter-articles ()
+  "Enter articles from the current group for future duplicate suppression."
+  (unless gnus-dup-list
+    (gnus-dup-open))
+  (setq gnus-dup-list-dirty t)         ; mark list for saving
+  (let (msgid)
+    ;; Enter the Message-IDs of all read articles into the list
+    ;; and hash table.
+    (dolist (datum gnus-newsgroup-data)
+      (when (and (not (gnus-data-pseudo-p datum))
+                (> (gnus-data-number datum) 0)
+                (not (memq (gnus-data-number datum) gnus-newsgroup-unreads))
+                (not (= (gnus-data-mark datum) gnus-canceled-mark))
+                (setq msgid (mail-header-id (gnus-data-header datum)))
+                (not (nnheader-fake-message-id-p msgid))
+                (not (intern-soft msgid gnus-dup-hashtb)))
+       (push msgid gnus-dup-list)
+       (intern msgid gnus-dup-hashtb))))
+  ;; Chop off excess Message-IDs from the list.
+  (let ((end (nthcdr gnus-duplicate-list-length gnus-dup-list)))
+    (when end
+      (mapc (lambda (id) (unintern id gnus-dup-hashtb)) (cdr end))
+      (setcdr end nil))))
+
+(defun gnus-dup-suppress-articles ()
+  "Mark duplicate articles as read."
+  (unless gnus-dup-list
+    (gnus-dup-open))
+  (gnus-message 8 "Suppressing duplicates...")
+  (let ((auto (and gnus-newsgroup-auto-expire
+                  (memq gnus-duplicate-mark gnus-auto-expirable-marks)))
+       number)
+    (dolist (header gnus-newsgroup-headers)
+      (when (and (intern-soft (mail-header-id header) gnus-dup-hashtb)
+                (gnus-summary-article-unread-p (mail-header-number header)))
+       (setq gnus-newsgroup-unreads
+             (delq (setq number (mail-header-number header))
+                   gnus-newsgroup-unreads))
+       (if (not auto)
+           (push (cons number gnus-duplicate-mark) gnus-newsgroup-reads)
+         (push number gnus-newsgroup-expirable)
+         (push (cons number gnus-expirable-mark) gnus-newsgroup-reads)))))
+  (gnus-message 8 "Suppressing duplicates...done"))
+
+(defun gnus-dup-unsuppress-article (article)
+  "Stop suppression of ARTICLE."
+  (let* ((header (gnus-data-header (gnus-data-find article)))
+        (id     (when header (mail-header-id header))))
+    (when id
+      (setq gnus-dup-list-dirty t)
+      (setq gnus-dup-list (delete id gnus-dup-list))
+      (unintern id gnus-dup-hashtb))))
+
+(provide 'gnus-dup)
+
+;;; gnus-dup.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-eform.el b/xemacs-packages/gnus/lisp/gnus-eform.el
new file mode 100644 (file)
index 0000000..ab3992b
--- /dev/null
@@ -0,0 +1,127 @@
+;;; gnus-eform.el --- a mode for editing forms for Gnus
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'gnus)
+(require 'gnus-win)
+
+;;;
+;;; Editing forms
+;;;
+
+(defgroup gnus-edit-form nil
+  "A mode for editing forms."
+  :group 'gnus)
+
+(defcustom gnus-edit-form-mode-hook nil
+  "Hook run in `gnus-edit-form-mode' buffers."
+  :group 'gnus-edit-form
+  :type 'hook)
+
+(defcustom gnus-edit-form-menu-hook nil
+  "Hook run when creating menus in `gnus-edit-form-mode' buffers."
+  :group 'gnus-edit-form
+  :type 'hook)
+
+;;; Internal variables
+
+(defvar gnus-edit-form-buffer "*Gnus edit form*")
+(defvar gnus-edit-form-done-function nil)
+
+(defvar gnus-edit-form-mode-map nil)
+(unless gnus-edit-form-mode-map
+  (setq gnus-edit-form-mode-map (make-sparse-keymap))
+  (set-keymap-parent gnus-edit-form-mode-map emacs-lisp-mode-map)
+  (gnus-define-keys gnus-edit-form-mode-map
+    "\C-c\C-c" gnus-edit-form-done
+    "\C-c\C-k" gnus-edit-form-exit))
+
+(defun gnus-edit-form-make-menu-bar ()
+  (unless (boundp 'gnus-edit-form-menu)
+    (easy-menu-define
+     gnus-edit-form-menu gnus-edit-form-mode-map ""
+     '("Edit Form"
+       ["Exit and save changes" gnus-edit-form-done t]
+       ["Exit" gnus-edit-form-exit t]))
+    (gnus-run-hooks 'gnus-edit-form-menu-hook)))
+
+(define-derived-mode gnus-edit-form-mode fundamental-mode "Edit Form"
+  "Major mode for editing forms.
+It is a slightly enhanced emacs-lisp-mode.
+
+\\{gnus-edit-form-mode-map}"
+  (when (gnus-visual-p 'group-menu 'menu)
+    (gnus-edit-form-make-menu-bar))
+  (make-local-variable 'gnus-edit-form-done-function)
+  (make-local-variable 'gnus-prev-winconf))
+
+(defun gnus-edit-form (form documentation exit-func &optional layout)
+  "Edit FORM in a new buffer.
+Call EXIT-FUNC on exit.  Display DOCUMENTATION in the beginning
+of the buffer.
+The optional LAYOUT overrides the `edit-form' window layout."
+  (let ((winconf (current-window-configuration)))
+    (set-buffer (gnus-get-buffer-create gnus-edit-form-buffer))
+    (gnus-configure-windows (or layout 'edit-form))
+    (gnus-edit-form-mode)
+    (setq gnus-prev-winconf winconf)
+    (setq gnus-edit-form-done-function exit-func)
+    (erase-buffer)
+    (insert documentation)
+    (unless (bolp)
+      (insert "\n"))
+    (goto-char (point-min))
+    (while (not (eobp))
+      (insert ";;; ")
+      (forward-line 1))
+    (insert (substitute-command-keys
+            ";; Type `C-c C-c' after you've finished editing.\n"))
+    (insert "\n")
+    (let ((p (point)))
+      (gnus-pp form)
+      (insert "\n")
+      (goto-char p))))
+
+(defun gnus-edit-form-done ()
+  "Update changes and kill the current buffer."
+  (interactive)
+  (goto-char (point-min))
+  (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)))
+
+(defun gnus-edit-form-exit ()
+  "Kill the current buffer."
+  (interactive)
+  (let ((winconf gnus-prev-winconf))
+    (kill-buffer (current-buffer))
+    (set-window-configuration winconf)))
+
+(provide 'gnus-eform)
+
+;;; gnus-eform.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-ems.el b/xemacs-packages/gnus/lisp/gnus-ems.el
new file mode 100644 (file)
index 0000000..400ac4f
--- /dev/null
@@ -0,0 +1,266 @@
+;;; gnus-ems.el --- functions for making Gnus work under different Emacsen
+
+;; Copyright (C) 1995-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile
+  (require 'cl)
+  (require 'ring))
+
+;;; Function aliases later to be redefined for XEmacs usage.
+
+(defvar gnus-mouse-2 [mouse-2])
+(defvar gnus-down-mouse-3 [down-mouse-3])
+(defvar gnus-down-mouse-2 [down-mouse-2])
+(defvar gnus-widget-button-keymap nil)
+(defvar gnus-mode-line-modified
+  (if (featurep 'xemacs)
+      '("--**-" . "-----")
+    '("**" "--")))
+
+(eval-and-compile
+  (autoload 'gnus-xmas-define "gnus-xmas")
+  (autoload 'gnus-xmas-redefine "gnus-xmas"))
+
+(autoload 'gnus-get-buffer-create "gnus")
+(autoload 'nnheader-find-etc-directory "nnheader")
+(autoload 'smiley-region "smiley")
+
+(defun gnus-kill-all-overlays ()
+  "Delete all overlays in the current buffer."
+  (let* ((overlayss (overlay-lists))
+        (buffer-read-only nil)
+        (overlays (delq nil (nconc (car overlayss) (cdr overlayss)))))
+    (while overlays
+      (delete-overlay (pop overlays)))))
+
+;;; Mule functions.
+
+(defun gnus-mule-max-width-function (el max-width)
+  `(let* ((val (eval (, el)))
+         (valstr (if (numberp val)
+                     (int-to-string val) val)))
+     (if (> (length valstr) ,max-width)
+        (truncate-string-to-width valstr ,max-width)
+       valstr)))
+
+(eval-and-compile
+  (if (featurep 'xemacs)
+      (gnus-xmas-define)
+    (defvar gnus-mouse-face-prop 'mouse-face
+      "Property used for highlighting mouse regions.")))
+
+(defvar gnus-tmp-unread)
+(defvar gnus-tmp-replied)
+(defvar gnus-tmp-score-char)
+(defvar gnus-tmp-indentation)
+(defvar gnus-tmp-opening-bracket)
+(defvar gnus-tmp-lines)
+(defvar gnus-tmp-name)
+(defvar gnus-tmp-closing-bracket)
+(defvar gnus-tmp-subject-or-nil)
+(defvar gnus-check-before-posting)
+(defvar gnus-mouse-face)
+(defvar gnus-group-buffer)
+
+(defun gnus-ems-redefine ()
+  (cond
+   ((featurep 'xemacs)
+    (gnus-xmas-redefine))
+
+   ((featurep 'mule)
+    ;; Mule and new Emacs definitions
+
+    ;; [Note] Now there are three kinds of mule implementations,
+    ;; original MULE, XEmacs/mule and Emacs 20+ including
+    ;; MULE features.  Unfortunately these APIs are different.  In
+    ;; particular, Emacs (including original Mule) and XEmacs are
+    ;; quite different.  However, this version of Gnus doesn't support
+    ;; anything other than XEmacs 20+ and Emacs 20.3+.
+
+    ;; Predicates to check are following:
+    ;; (boundp 'MULE) is t only if Mule (original; anything older than
+    ;;                     Mule 2.3) is running.
+    ;; (featurep 'mule) is t when other mule variants are running.
+
+    ;; It is possible to detect XEmacs/mule by (featurep 'mule) and
+    ;; (featurep 'xemacs).  In this case, the implementation for
+    ;; XEmacs/mule may be shareable between XEmacs and XEmacs/mule.
+
+    (defvar gnus-summary-display-table nil
+      "Display table used in summary mode buffers.")
+    (defalias 'gnus-max-width-function 'gnus-mule-max-width-function)
+
+    (when (boundp 'gnus-check-before-posting)
+      (setq gnus-check-before-posting
+           (delq 'long-lines
+                 (delq 'control-chars gnus-check-before-posting))))
+
+    (defun gnus-summary-line-format-spec ()
+      (insert gnus-tmp-unread gnus-tmp-replied
+             gnus-tmp-score-char gnus-tmp-indentation)
+      (put-text-property
+       (point)
+       (progn
+        (insert
+         gnus-tmp-opening-bracket
+         (format "%4d: %-20s"
+                 gnus-tmp-lines
+                 (if (> (length gnus-tmp-name) 20)
+                     (truncate-string-to-width gnus-tmp-name 20)
+                   gnus-tmp-name))
+         gnus-tmp-closing-bracket)
+        (point))
+       gnus-mouse-face-prop gnus-mouse-face)
+      (insert " " gnus-tmp-subject-or-nil "\n")))))
+
+;; Clone of `appt-select-lowest-window' in appt.el.
+(defun gnus-select-lowest-window ()
+"Select the lowest window on the frame."
+  (let ((lowest-window (selected-window))
+       (bottom-edge (nth 3 (window-edges))))
+    (walk-windows (lambda (w)
+                   (let ((next-bottom-edge (nth 3 (window-edges w))))
+                     (when (< bottom-edge next-bottom-edge)
+                       (setq bottom-edge next-bottom-edge
+                             lowest-window w)))))
+    (select-window lowest-window)))
+
+(defun gnus-region-active-p ()
+  "Say whether the region is active."
+  (and (boundp 'transient-mark-mode)
+       transient-mark-mode
+       (boundp 'mark-active)
+       mark-active))
+
+(defun gnus-mark-active-p ()
+  "Non-nil means the mark and region are currently active in this buffer."
+  mark-active) ; aliased to region-exists-p in XEmacs.
+
+(autoload 'gnus-alive-p "gnus-util")
+(autoload 'mm-disable-multibyte "mm-util")
+
+;;; Image functions.
+
+(defun gnus-image-type-available-p (type)
+  (and (fboundp 'image-type-available-p)
+       (if (fboundp 'display-images-p)
+          (display-images-p)
+        t)
+       (image-type-available-p type)))
+
+(defun gnus-create-image (file &optional type data-p &rest props)
+  (let ((face (plist-get props :face)))
+    (when face
+      (setq props (plist-put props :foreground (face-foreground face)))
+      (setq props (plist-put props :background (face-background face))))
+    (ignore-errors
+      (apply 'create-image file type data-p props))))
+
+(defun gnus-put-image (glyph &optional string category)
+  (let ((point (point)))
+    (insert-image glyph (or string " "))
+    (put-text-property point (point) 'gnus-image-category category)
+    (unless string
+      (put-text-property (1- (point)) (point)
+                        'gnus-image-text-deletable t))
+    glyph))
+
+(defun gnus-remove-image (image &optional category)
+  "Remove the image matching IMAGE and CATEGORY found first."
+  (let ((start (point-min))
+       val end)
+    (while (and (not end)
+               (or (setq val (get-text-property start 'display))
+                   (and (setq start
+                              (next-single-property-change start 'display))
+                        (setq val (get-text-property start 'display)))))
+      (setq end (or (next-single-property-change start 'display)
+                   (point-max)))
+      (if (and (equal val image)
+              (equal (get-text-property start 'gnus-image-category)
+                     category))
+         (progn
+           (put-text-property start end 'display nil)
+           (when (get-text-property start 'gnus-image-text-deletable)
+             (delete-region start end)))
+       (unless (= end (point-max))
+         (setq start end
+               end nil))))))
+
+(defmacro gnus-string-mark-left-to-right (string)
+  (if (fboundp 'bidi-string-mark-left-to-right)
+      `(bidi-string-mark-left-to-right ,string)
+    string))
+
+(eval-and-compile
+  ;; XEmacs does not have window-inside-pixel-edges
+  (defalias 'gnus-window-inside-pixel-edges
+    (if (fboundp 'window-inside-pixel-edges)
+        'window-inside-pixel-edges
+      'window-pixel-edges))
+
+  (if (or (featurep 'emacs) (fboundp 'set-process-plist))
+      (progn                           ; these exist since Emacs 22.1
+       (defalias 'gnus-set-process-plist 'set-process-plist)
+       (defalias 'gnus-process-plist 'process-plist)
+       (defalias 'gnus-process-get 'process-get)
+       (defalias 'gnus-process-put 'process-put))
+    (defun gnus-set-process-plist (process plist)
+      "Replace the plist of PROCESS with PLIST.  Returns PLIST."
+      (put 'gnus-process-plist-internal process plist))
+
+    (defun gnus-process-plist (process)
+      "Return the plist of PROCESS."
+      ;; This form works but can't prevent the plist data from
+      ;; growing infinitely.
+      ;;(get 'gnus-process-plist-internal process)
+      (let* ((plist (symbol-plist 'gnus-process-plist-internal))
+            (tem (memq process plist)))
+       (prog1
+           (cadr tem)
+         ;; Remove it from the plist data.
+         (when tem
+           (if (eq plist tem)
+               (progn
+                 (setcar plist (caddr plist))
+                 (setcdr plist (or (cdddr plist) '(nil))))
+             (setcdr (nthcdr (- (length plist) (length tem) 1) plist)
+                     (cddr tem)))))))
+
+    (defun gnus-process-get (process propname)
+      "Return the value of PROCESS' PROPNAME property.
+This is the last value stored with `(gnus-process-put PROCESS PROPNAME VALUE)'."
+      (plist-get (gnus-process-plist process) propname))
+
+    (defun gnus-process-put (process propname value)
+      "Change PROCESS' PROPNAME property to VALUE.
+It can be retrieved with `(gnus-process-get PROCESS PROPNAME)'."
+      (gnus-set-process-plist process
+                             (plist-put (gnus-process-plist process)
+                                        propname value)))))
+
+(provide 'gnus-ems)
+
+;;; gnus-ems.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-fallback-lib/eieio/eieio-base.el b/xemacs-packages/gnus/lisp/gnus-fallback-lib/eieio/eieio-base.el
new file mode 100644 (file)
index 0000000..9df3fe9
--- /dev/null
@@ -0,0 +1,332 @@
+;;; eieio-base.el --- Base classes for EIEIO.
+
+;;; Copyright (C) 2000-2002, 2004-2005, 2007-2016
+;;; Free Software Foundation, Inc.
+
+;; Author: Eric M. Ludlam  <zappo@gnu.org>
+;; Version: 0.2
+;; Keywords: OO, lisp
+;; Package: eieio
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; Base classes for EIEIO.  These classes perform some basic tasks
+;; but are generally useless on their own.  To use any of these classes,
+;; inherit from one or more of them.
+
+;;; Code:
+
+(require 'eieio)
+
+;;; eieio-instance-inheritor
+;;
+;; Enable instance inheritance via the `clone' method.
+;; Works by using the `slot-unbound' method which usually throws an
+;; error if a slot is unbound.
+(defclass eieio-instance-inheritor ()
+  ((parent-instance :initarg :parent-instance
+                   :type eieio-instance-inheritor-child
+                   :documentation
+                   "The parent of this instance.
+If a slot of this class is referenced, and is unbound, then the parent
+is checked for a value.")
+   )
+  "This special class can enable instance inheritance.
+Use `clone' to make a new object that does instance inheritance from
+a parent instance.  When a slot in the child is referenced, and has
+not been set, use values from the parent."
+  :abstract t)
+
+(defmethod slot-unbound ((object eieio-instance-inheritor) class slot-name fn)
+  "If a slot OBJECT in this CLASS is unbound, try to inherit, or throw a signal.
+SLOT-NAME is the offending slot.  FN is the function signalling the error."
+  (if (slot-boundp object 'parent-instance)
+      ;; It may not look like it, but this line recurses back into this
+      ;; method if the parent instance's slot is unbound.
+      (eieio-oref (oref object parent-instance) slot-name)
+    ;; Throw the regular signal.
+    (call-next-method)))
+
+(defmethod clone ((obj eieio-instance-inheritor) &rest params)
+  "Clone OBJ, initializing `:parent' to OBJ.
+All slots are unbound, except those initialized with PARAMS."
+  (let ((nobj (make-vector (length obj) eieio-unbound))
+       (nm (aref obj object-name))
+       (passname (and params (stringp (car params))))
+       (num 1))
+    (aset nobj 0 'object)
+    (aset nobj object-class (aref obj object-class))
+    ;; The following was copied from the default clone.
+    (if (not passname)
+       (save-match-data
+         (if (string-match "-\\([0-9]+\\)" nm)
+             (setq num (1+ (string-to-number (match-string 1 nm)))
+                   nm (substring nm 0 (match-beginning 0))))
+         (aset nobj object-name (concat nm "-" (int-to-string num))))
+      (aset nobj object-name (car params)))
+    ;; Now initialize from params.
+    (if params (shared-initialize nobj (if passname (cdr params) params)))
+    (oset nobj parent-instance obj)
+    nobj))
+
+(defmethod eieio-instance-inheritor-slot-boundp ((object eieio-instance-inheritor)
+                                               slot)
+  "Return non-nil if the instance inheritor OBJECT's SLOT is bound.
+See `slot-boundp' for details on binding slots.
+The instance inheritor uses unbound slots as a way of cascading cloned
+slot values, so testing for a slot being bound requires extra steps
+for this kind of object."
+  (if (slot-boundp object slot)
+      ;; If it is regularly bound, return t.
+      t
+    (if (slot-boundp object 'parent-instance)
+       (eieio-instance-inheritor-slot-boundp (oref object parent-instance)
+                                             slot)
+      nil)))
+
+\f
+;;; eieio-instance-tracker
+;;
+;; Track all created instances of this class.
+;; The class must initialize the `tracking-symbol' slot, and that
+;; symbol is then used to contain these objects.
+(defclass eieio-instance-tracker ()
+  ((tracking-symbol :type symbol
+                   :allocation :class
+                   :documentation
+                   "The symbol used to maintain a list of our instances.
+The instance list is treated as a variable, with new instances added to it.")
+   )
+  "This special class enables instance tracking.
+Inheritors from this class must overload `tracking-symbol' which is
+a variable symbol used to store a list of all instances."
+  :abstract t)
+
+(defmethod initialize-instance :AFTER ((this eieio-instance-tracker)
+                                      &rest slots)
+  "Make sure THIS is in our master list of this class.
+Optional argument SLOTS are the initialization arguments."
+  ;; Theoretically, this is never called twice for a given instance.
+  (let ((sym (oref this tracking-symbol)))
+    (if (not (memq this (symbol-value sym)))
+       (set sym (append (symbol-value sym) (list this))))))
+
+(defmethod delete-instance ((this eieio-instance-tracker))
+  "Remove THIS from the master list of this class."
+  (set (oref this tracking-symbol)
+       (delq this (symbol-value (oref this tracking-symbol)))))
+
+;; In retrospect, this is a silly function.
+(defun eieio-instance-tracker-find (key slot list-symbol)
+  "Find KEY as an element of SLOT in the objects in LIST-SYMBOL.
+Returns the first match."
+  (object-assoc key slot (symbol-value list-symbol)))
+
+;;; eieio-singleton
+;;
+;; The singleton Design Pattern specifies that there is but one object
+;; of a given class ever created.  The EIEIO singleton base class defines
+;; a CLASS allocated slot which contains the instance used.  All calls to
+;; `make-instance' will either create a new instance and store it in this
+;; slot, or it will just return what is there.
+(defclass eieio-singleton ()
+  ((singleton :type eieio-singleton
+             :allocation :class
+             :documentation
+             "The only instance of this class that will be instantiated.
+Multiple calls to `make-instance' will return this object."))
+  "This special class causes subclasses to be singletons.
+A singleton is a class which will only ever have one instance."
+  :abstract t)
+
+(defmethod constructor :STATIC ((class eieio-singleton) name &rest slots)
+  "Constructor for singleton CLASS.
+NAME and SLOTS initialize the new object.
+This constructor guarantees that no matter how many you request,
+only one object ever exists."
+  ;; NOTE TO SELF: In next version, make `slot-boundp' support classes
+  ;; with class allocated slots or default values.
+  (let ((old (oref-default class singleton)))
+    (if (eq old eieio-unbound)
+       (oset-default class singleton (call-next-method))
+      old)))
+
+\f
+;;; eieio-persistent
+;;
+;; For objects which must save themselves to disk.  Provides an
+;; `object-write' method to save an object to disk, and a
+;; `eieio-persistent-read' function to call to read an object
+;; from disk.
+;;
+;; Also provide the method `eieio-persistent-path-relative' to
+;; calculate path names relative to a given instance.  This will
+;; make the saved object location independent by converting all file
+;; references to be relative to the directory the object is saved to.
+;; You must call `eieio-peristent-path-relative' on each file name
+;; saved in your object.
+(defclass eieio-persistent ()
+  ((file :initarg :file
+        :type string
+        :documentation
+        "The save file for this persistent object.
+This must be a string, and must be specified when the new object is
+instantiated.")
+   (extension :type string
+             :allocation :class
+             :initform ".eieio"
+             :documentation
+             "Extension of files saved by this object.
+Enables auto-choosing nice file names based on name.")
+   (file-header-line :type string
+                    :allocation :class
+                    :initform ";; EIEIO PERSISTENT OBJECT"
+                    :documentation
+                    "Header line for the save file.
+This is used with the `object-write' method.")
+   (do-backups :type boolean
+              :allocation :class
+              :initform t
+              :documentation
+              "Saving this object should make backup files.
+Setting to nil will mean no backups are made."))
+  "This special class enables persistence through save files
+Use the `object-save' method to write this object to disk.  The save
+format is Emacs Lisp code which calls the constructor for the saved
+object.  For this reason, only slots which do not have an `:initarg'
+specified will not be saved."
+  :abstract t)
+
+(defmethod eieio-persistent-save-interactive ((this eieio-persistent) prompt
+                                             &optional name)
+  "Prepare to save THIS.  Use in an `interactive' statement.
+Query user for file name with PROMPT if THIS does not yet specify
+a file.  Optional argument NAME specifies a default file name."
+  (unless (slot-boundp this 'file)
+      (oset this file
+           (read-file-name prompt nil
+                           (if   name
+                               (concat name (oref this extension))
+                             ))))
+  (oref this file))
+
+(defun eieio-persistent-read (filename)
+  "Read a persistent object from FILENAME, and return it."
+  (let ((ret nil)
+       (buffstr nil))
+    (unwind-protect
+       (progn
+         (with-current-buffer (get-buffer-create " *tmp eieio read*")
+           (insert-file-contents filename nil nil nil t)
+           (goto-char (point-min))
+           (setq buffstr (buffer-string)))
+         ;; Do the read in the buffer the read was initialized from
+         ;; so that any initialize-instance calls that depend on
+         ;; the current buffer will work.
+         (setq ret (read buffstr))
+         (if (not (child-of-class-p (car ret) 'eieio-persistent))
+             (error "Corrupt object on disk"))
+         (setq ret (eval ret))
+         (oset ret file filename))
+      (kill-buffer " *tmp eieio read*"))
+    ret))
+
+(defmethod object-write ((this eieio-persistent) &optional comment)
+  "Write persistent object THIS out to the current stream.
+Optional argument COMMENT is a header line comment."
+  (call-next-method this (or comment (oref this file-header-line))))
+
+(defmethod eieio-persistent-path-relative ((this eieio-persistent) file)
+  "For object THIS, make absolute file name FILE relative."
+  (file-relative-name (expand-file-name file)
+                     (file-name-directory (oref this file))))
+
+(defmethod eieio-persistent-save ((this eieio-persistent) &optional file)
+  "Save persistent object THIS to disk.
+Optional argument FILE overrides the file name specified in the object
+instance."
+  (save-excursion
+    (let ((b (set-buffer (get-buffer-create " *tmp object write*")))
+         (default-directory (file-name-directory (oref this file)))
+         (cfn (oref this file)))
+      (unwind-protect
+         (save-excursion
+           (erase-buffer)
+           (let ((standard-output (current-buffer)))
+             (oset this file
+                   (if file
+                       (eieio-persistent-path-relative this file)
+                     (file-name-nondirectory cfn)))
+             (object-write this (oref this file-header-line)))
+           (let ((backup-inhibited (not (oref this do-backups)))
+                 (cs (car (find-coding-systems-region
+                           (point-min) (point-max)))))
+             (unless (eq cs 'undecided)
+               (setq buffer-file-coding-system cs))
+             ;; Old way - write file.  Leaves message behind.
+             ;;(write-file cfn nil)
+
+             ;; New way - Avoid the vast quantities of error checking
+             ;; just so I can get at the special flags that disable
+             ;; displaying random messages.
+             (write-region (point-min) (point-max)
+                           cfn nil 1)
+             ))
+       ;; Restore :file, and kill the tmp buffer
+       (oset this file cfn)
+       (setq buffer-file-name nil)
+       (kill-buffer b)))))
+
+;; Notes on the persistent object:
+;; It should also set up some hooks to help it keep itself up to date.
+
+\f
+;;; Named object
+;;
+;; Named objects use the objects `name' as a slot, and that slot
+;; is accessed with the `object-name' symbol.
+
+(defclass eieio-named ()
+  ()
+  "Object with a name.
+Name storage already occurs in an object.  This object provides get/set
+access to it."
+  :abstract t)
+
+(defmethod slot-missing ((obj eieio-named)
+                        slot-name operation &optional new-value)
+  "Called when a non-existent slot is accessed.
+For variable `eieio-named', provide an imaginary `object-name' slot.
+Argument OBJ is the named object.
+Argument SLOT-NAME is the slot that was attempted to be accessed.
+OPERATION is the type of access, such as `oref' or `oset'.
+NEW-VALUE is the value that was being set into SLOT if OPERATION were
+a set type."
+  (if (or (eq slot-name 'object-name)
+         (eq slot-name :object-name))
+      (cond ((eq operation 'oset)
+            (if (not (stringp new-value))
+                (signal 'invalid-slot-type
+                        (list obj slot-name 'string new-value)))
+            (object-set-name-string obj new-value))
+           (t (object-name-string obj)))
+    (call-next-method)))
+
+(provide 'eieio-base)
+
+;;; eieio-base.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-fallback-lib/eieio/eieio-comp.el b/xemacs-packages/gnus/lisp/gnus-fallback-lib/eieio/eieio-comp.el
new file mode 100644 (file)
index 0000000..9ee91c4
--- /dev/null
@@ -0,0 +1,142 @@
+;;; eieio-comp.el -- eieio routines to help with byte compilation
+
+;; Copyright (C) 1995-1996, 1998-2002, 2005, 2008-2016
+;;   Free Software Foundation, Inc.
+
+;; Author: Eric M. Ludlam <zappo@gnu.org>
+;; Version: 0.2
+;; Keywords: lisp, tools
+;; Package: eieio
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Byte compiler functions for defmethod.  This will affect the new GNU
+;; byte compiler for Emacs 19 and better.  This function will be called by
+;; the byte compiler whenever a `defmethod' is encountered in a file.
+;; It will output a function call to `eieio--defmethod' with the byte
+;; compiled function as a parameter.
+
+;;; Code:
+
+(declare-function eieio-defgeneric-form "eieio" (method doc-string))
+
+;; Some compatibility stuff
+(eval-and-compile
+  (if (not (fboundp 'byte-compile-compiled-obj-to-list))
+      (defun byte-compile-compiled-obj-to-list (moose) nil))
+
+  (if (not (boundp 'byte-compile-outbuffer))
+      (defvar byte-compile-outbuffer nil))
+  )
+
+;; This teaches the byte compiler how to do this sort of thing.
+(put 'defmethod 'byte-hunk-handler 'byte-compile-file-form-defmethod)
+
+(defun byte-compile-file-form-defmethod (form)
+  "Mumble about the method we are compiling.
+This function is mostly ripped from `byte-compile-file-form-defun',
+but it's been modified to handle the special syntax of the `defmethod'
+command.  There should probably be one for `defgeneric' as well, but
+that is called but rarely.  Argument FORM is the body of the method."
+  (setq form (cdr form))
+  (let* ((meth (car form))
+        (key (progn (setq form (cdr form))
+                    (cond ((or (eq ':BEFORE (car form))
+                               (eq ':before (car form)))
+                           (setq form (cdr form))
+                           ":before ")
+                          ((or (eq ':AFTER (car form))
+                               (eq ':after (car form)))
+                           (setq form (cdr form))
+                           ":after ")
+                          ((or (eq ':PRIMARY (car form))
+                               (eq ':primary (car form)))
+                           (setq form (cdr form))
+                           ":primary ")
+                          ((or (eq ':STATIC (car form))
+                               (eq ':static (car form)))
+                           (setq form (cdr form))
+                           ":static ")
+                          (t ""))))
+        (params (car form))
+        (lamparams (byte-compile-defmethod-param-convert params))
+        (arg1 (car params))
+        (class (if (listp arg1) (nth 1 arg1) nil))
+        (my-outbuffer (if (eval-when-compile (featurep 'xemacs))
+                          byte-compile-outbuffer
+                        (cond ((boundp 'bytecomp-outbuffer)
+                               bytecomp-outbuffer) ; Emacs >= 23.2
+                              ((boundp 'outbuffer) outbuffer)
+                              (t (error "Unable to set outbuffer"))))))
+    (let ((name (format "%s::%s" (or class "#<generic>") meth)))
+      (if byte-compile-verbose
+         ;; #### filename used free
+         (message "Compiling %s... (%s)"
+                  (cond ((boundp 'bytecomp-filename) bytecomp-filename)
+                        ((boundp 'filename) filename)
+                        (t ""))
+                  name))
+      (setq byte-compile-current-form name) ; for warnings
+      )
+    ;; Flush any pending output
+    (byte-compile-flush-pending)
+    ;; Byte compile the body.  For the byte compiled forms, add the
+    ;; rest arguments, which will get ignored by the engine which will
+    ;; add them later (I hope)
+    (let* ((new-one (byte-compile-lambda
+                    (append (list 'lambda lamparams)
+                            (cdr form))))
+          (code (byte-compile-byte-code-maker new-one)))
+      (princ "\n(eieio--defmethod '" my-outbuffer)
+      (princ meth my-outbuffer)
+      (princ " '(" my-outbuffer)
+      (princ key my-outbuffer)
+      (prin1 params my-outbuffer)
+      (princ " " my-outbuffer)
+      (prin1 code my-outbuffer)
+      (princ "))" my-outbuffer)
+      )
+    ;; Now add this function to the list of known functions.
+    ;; Don't bother with a doc string.   Not relevant here.
+    (add-to-list 'byte-compile-function-environment
+                (cons meth
+                      (eieio-defgeneric-form meth "")))
+
+    ;; Remove it from the undefined list if it is there.
+    (let ((elt (assq meth byte-compile-unresolved-functions)))
+      (if elt (setq byte-compile-unresolved-functions
+                   (delq elt byte-compile-unresolved-functions))))
+
+    ;; nil prevents cruft from appearing in the output buffer.
+    nil))
+
+(defun byte-compile-defmethod-param-convert (paramlist)
+  "Convert method params into the params used by the `defmethod' thingy.
+Argument PARAMLIST is the parameter list to convert."
+  (let ((argfix nil))
+    (while paramlist
+      (setq argfix (cons (if (listp (car paramlist))
+                            (car (car paramlist))
+                          (car paramlist))
+                        argfix))
+      (setq paramlist (cdr paramlist)))
+    (nreverse argfix)))
+
+(provide 'eieio-comp)
+
+;;; eieio-comp.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-fallback-lib/eieio/eieio-custom.el b/xemacs-packages/gnus/lisp/gnus-fallback-lib/eieio/eieio-custom.el
new file mode 100644 (file)
index 0000000..4c243e6
--- /dev/null
@@ -0,0 +1,468 @@
+;;; eieio-custom.el -- eieio object customization
+
+;; Copyright (C) 1999-2001, 2005, 2007-2016 Free Software Foundation, Inc.
+
+;; Author: Eric M. Ludlam <zappo@gnu.org>
+;; Version: 0.2
+;; Keywords: OO, lisp
+;; Package: eieio
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;;   This contains support customization of eieio objects.  Enabling
+;; your object to be customizable requires use of the slot attribute
+;; `:custom'.
+
+(require 'eieio)
+(require 'widget)
+(require 'wid-edit)
+(require 'custom)
+
+;;; Compatibility
+
+;; (eval-and-compile
+;;   (if (featurep 'xemacs)
+;;       (defalias 'eieio-overlay-lists (lambda () (list (extent-list))))
+;;     (defalias 'eieio-overlay-lists 'overlay-lists)))
+
+;;; Code:
+(defclass eieio-widget-test-class nil
+  ((a-string :initarg :a-string
+            :initform "The moose is loose"
+            :custom string
+            :label "Amorphous String"
+            :group (default foo)
+            :documentation "A string for testing custom.
+This is the next line of documentation.")
+   (listostuff :initarg :listostuff
+              :initform ("1" "2" "3")
+              :type list
+              :custom (repeat (string :tag "Stuff"))
+              :label "List of Strings"
+              :group foo
+              :documentation "A list of stuff.")
+   (uninitialized :initarg :uninitialized
+                 :type string
+                 :custom string
+                 :documentation "This slot is not initialized.
+Used to make sure that custom doesn't barf when it encounters one
+of these.")
+   (a-number :initarg :a-number
+            :initform 2
+            :custom integer
+            :documentation "A number of thingies."))
+  "A class for testing the widget on.")
+
+(defcustom eieio-widget-test (eieio-widget-test-class "Foo")
+  "Test variable for editing an object."
+  :type 'object
+  :group 'eieio)
+
+(defface eieio-custom-slot-tag-face '((((class color)
+                                       (background dark))
+                                      (:foreground "light blue"))
+                                     (((class color)
+                                       (background light))
+                                      (:foreground "blue"))
+                                     (t (:italic t)))
+  "Face used for unpushable variable tags."
+  :group 'custom-faces)
+
+(defvar eieio-wo nil
+  "Buffer local variable in object customize buffers for the current widget.")
+(defvar eieio-co nil
+  "Buffer local variable in object customize buffers for the current obj.")
+(defvar eieio-cog nil
+  "Buffer local variable in object customize buffers for the current group.")
+
+ (defvar eieio-custom-ignore-eieio-co nil
+   "When true, all customizable slots of the current object are updated.
+Updates occur regardless of the current customization group.")
+
+(define-widget 'object-slot 'group
+  "Abstractly modify a single slot in an object."
+  :tag "Slot"
+  :format "%t %v%h\n"
+  :convert-widget 'widget-types-convert-widget
+  :value-create 'eieio-slot-value-create
+  :value-get 'eieio-slot-value-get
+  :value-delete 'widget-children-value-delete
+  :validate 'widget-children-validate
+  :match 'eieio-object-match ;; same
+  )
+
+(defun eieio-slot-value-create (widget)
+  "Create the value of WIDGET."
+  (let ((chil nil))
+    (setq chil (cons
+               (widget-create-child-and-convert
+                widget (widget-get widget :childtype)
+                :tag ""
+                :value (widget-get widget :value))
+               chil))
+    (widget-put widget :children chil)))
+
+(defun eieio-slot-value-get (widget)
+  "Get the value of WIDGET."
+  (widget-value (car (widget-get widget :children))))
+
+(defun eieio-custom-toggle-hide (widget)
+  "Toggle visibility of WIDGET."
+  (let ((vc (car (widget-get widget :children))))
+    (cond ((eq (widget-get vc :eieio-custom-state) 'hidden)
+          (widget-put vc :eieio-custom-state 'visible)
+          (widget-put vc :value-face (widget-get vc :orig-face)))
+         (t
+          (widget-put vc :eieio-custom-state 'hidden)
+          (widget-put vc :orig-face (widget-get vc :value-face))
+          (widget-put vc :value-face 'invisible)
+          ))
+    (widget-value-set vc (widget-value vc))))
+
+(defun eieio-custom-toggle-parent (widget &rest ignore)
+  "Toggle visibility of parent of WIDGET.
+Optional argument IGNORE is an extraneous parameter."
+  (eieio-custom-toggle-hide (widget-get widget :parent)))
+
+(define-widget 'object-edit 'group
+  "Abstractly modify a CLOS object."
+  :tag "Object"
+  :format "%v"
+  :convert-widget 'widget-types-convert-widget
+  :value-create 'eieio-object-value-create
+  :value-get 'eieio-object-value-get
+  :value-delete 'widget-children-value-delete
+  :validate 'widget-children-validate
+  :match 'eieio-object-match
+  :clone-object-children nil
+  )
+
+(defun eieio-object-match (widget value)
+  "Match info for WIDGET against VALUE."
+  ;; Write me
+  t)
+
+(defun eieio-filter-slot-type (widget slottype)
+  "Filter WIDGETs SLOTTYPE."
+  (if (widget-get widget :clone-object-children)
+      slottype
+    (cond ((eq slottype 'object)
+          'object-edit)
+         ((and (listp slottype)
+               (eq (car slottype) 'object))
+          (cons 'object-edit (cdr slottype)))
+         ((equal slottype '(repeat object))
+          '(repeat object-edit))
+         ((and (listp slottype)
+               (equal (car slottype) 'repeat)
+               (listp (car (cdr slottype)))
+               (equal (car (car (cdr slottype))) 'object))
+          (list 'repeat
+                (cons 'object-edit
+                      (cdr (car (cdr slottype))))))
+         (t slottype))))
+
+(defun eieio-object-value-create (widget)
+  "Create the value of WIDGET."
+  (if (not (widget-get widget :value))
+      (widget-put widget
+                 :value (cond ((widget-get widget :objecttype)
+                               (funcall (class-constructor
+                                         (widget-get widget :objecttype))
+                                        "Custom-new"))
+                              ((widget-get widget :objectcreatefcn)
+                               (funcall (widget-get widget :objectcreatefcn)))
+                              (t (error "No create method specified")))))
+  (let* ((chil nil)
+        (obj (widget-get widget :value))
+        (master-group (widget-get widget :eieio-group))
+        (cv (class-v (object-class-fast obj)))
+        (slots (aref cv class-public-a))
+        (flabel (aref cv class-public-custom-label))
+        (fgroup (aref cv class-public-custom-group))
+        (fdoc (aref cv class-public-doc))
+        (fcust (aref cv class-public-custom)))
+    ;; First line describes the object, but may not editable.
+    (if (widget-get widget :eieio-show-name)
+       (setq chil (cons (widget-create-child-and-convert
+                         widget 'string :tag "Object "
+                         :sample-face 'bold
+                         (object-name-string obj))
+                        chil)))
+    ;; Display information about the group being shown
+    (when master-group
+      (let ((groups (class-option (object-class-fast obj) :custom-groups)))
+       (widget-insert "Groups:")
+       (while groups
+         (widget-insert "  ")
+         (if (eq (car groups) master-group)
+             (widget-insert "*" (capitalize (symbol-name master-group)) "*")
+           (widget-create 'push-button
+                          :thing (cons obj (car groups))
+                          :notify (lambda (widget &rest stuff)
+                                    (eieio-customize-object
+                                     (car (widget-get widget :thing))
+                                     (cdr (widget-get widget :thing))))
+                          (capitalize (symbol-name (car groups)))))
+         (setq groups (cdr groups)))
+       (widget-insert "\n\n")))
+    ;; Loop over all the slots, creating child widgets.
+    (while slots
+      ;; Output this slot if it has a customize flag associated with it.
+      (when (and (car fcust)
+                (or (not master-group) (member master-group (car fgroup)))
+                (slot-boundp obj (car slots)))
+       ;; In this case, this slot has a custom type.  Create its
+       ;; children widgets.
+       (let ((type (eieio-filter-slot-type widget (car fcust)))
+             (stuff nil))
+         ;; This next bit is an evil hack to get some EDE functions
+         ;; working the way I like.
+         (if (and (listp type)
+                  (setq stuff (member :slotofchoices type)))
+             (let ((choices (eieio-oref obj (car (cdr stuff))))
+                   (newtype nil))
+               (while (not (eq (car type) :slotofchoices))
+                 (setq newtype (cons (car type) newtype)
+                       type (cdr type)))
+               (while choices
+                 (setq newtype (cons (list 'const (car choices))
+                                     newtype)
+                       choices (cdr choices)))
+               (setq type (nreverse newtype))))
+         (setq chil (cons (widget-create-child-and-convert
+                           widget 'object-slot
+                           :childtype type
+                           :sample-face 'eieio-custom-slot-tag-face
+                           :tag
+                           (concat
+                            (make-string
+                             (or (widget-get widget :indent) 0)
+                             ? )
+                            (if (car flabel)
+                                (car flabel)
+                              (let ((s (symbol-name
+                                        (or
+                                         (class-slot-initarg
+                                          (object-class-fast obj)
+                                          (car slots))
+                                         (car slots)))))
+                                (capitalize
+                                 (if (string-match "^:" s)
+                                     (substring s (match-end 0))
+                                   s)))))
+                           :value (slot-value obj (car slots))
+                           :doc  (if (car fdoc) (car fdoc)
+                                   "Slot not Documented.")
+                           :eieio-custom-visibility 'visible
+                           )
+                          chil))
+         )
+       )
+      (setq slots (cdr slots)
+           fdoc (cdr fdoc)
+           fcust (cdr fcust)
+           flabel (cdr flabel)
+           fgroup (cdr fgroup)))
+    (widget-put widget :children (nreverse chil))
+    ))
+
+(defun eieio-object-value-get (widget)
+  "Get the value of WIDGET."
+  (let* ((obj (widget-get widget :value))
+        (master-group eieio-cog)
+        (cv (class-v (object-class-fast obj)))
+        (fgroup (aref cv class-public-custom-group))
+        (wids (widget-get widget :children))
+        (name (if (widget-get widget :eieio-show-name)
+                  (car (widget-apply (car wids) :value-inline))
+                nil))
+        (chil (if (widget-get widget :eieio-show-name)
+                  (nthcdr 1 wids) wids))
+        (cv (class-v (object-class-fast obj)))
+        (slots (aref cv class-public-a))
+        (fcust (aref cv class-public-custom)))
+    ;; If there are any prefix widgets, clear them.
+    ;; -- None yet
+    ;; Create a batch of initargs for each slot.
+    (while (and slots chil)
+      (if (and (car fcust)
+              (or eieio-custom-ignore-eieio-co
+                  (not master-group) (member master-group (car fgroup)))
+              (slot-boundp obj (car slots)))
+         (progn
+           ;; Only customized slots have widgets
+           (let ((eieio-custom-ignore-eieio-co t))
+             (eieio-oset obj (car slots)
+                         (car (widget-apply (car chil) :value-inline))))
+           (setq chil (cdr chil))))
+      (setq slots (cdr slots)
+           fgroup (cdr fgroup)
+           fcust (cdr fcust)))
+    ;; Set any name updates on it.
+    (if name (aset obj object-name name))
+    ;; This is the same object we had before.
+    obj))
+
+(defmethod eieio-done-customizing ((obj eieio-default-superclass))
+  "When applying change to a widget, call this method.
+This method is called by the default widget-edit commands.
+User made commands should also call this method when applying changes.
+Argument OBJ is the object that has been customized."
+  nil)
+
+;;;###autoload
+(defun customize-object (obj &optional group)
+  "Customize OBJ in a custom buffer.
+Optional argument GROUP is the sub-group of slots to display."
+  (eieio-customize-object obj group))
+
+(defmethod eieio-customize-object ((obj eieio-default-superclass)
+                                  &optional group)
+  "Customize OBJ in a specialized custom buffer.
+To override call the `eieio-custom-widget-insert' to just insert the
+object widget.
+Optional argument GROUP specifies a subgroup of slots to edit as a symbol.
+These groups are specified with the `:group' slot flag."
+  ;; Insert check for multiple edits here.
+  (let* ((g (or group 'default)))
+    (switch-to-buffer (get-buffer-create
+                      (concat "*CUSTOMIZE "
+                              (object-name obj) " "
+                              (symbol-name g) "*")))
+    (toggle-read-only -1)
+    (kill-all-local-variables)
+    (erase-buffer)
+    (let ((all (overlay-lists)))
+      ;; Delete all the overlays.
+      (mapc 'delete-overlay (car all))
+      (mapc 'delete-overlay (cdr all)))
+    ;; Add an apply reset option at the top of the buffer.
+    (eieio-custom-object-apply-reset obj)
+    (widget-insert "\n\n")
+    (widget-insert "Edit object " (object-name obj) "\n\n")
+    ;; Create the widget editing the object.
+    (make-local-variable 'eieio-wo)
+    (setq eieio-wo (eieio-custom-widget-insert obj :eieio-group g))
+    ;;Now generate the apply buttons
+    (widget-insert "\n")
+    (eieio-custom-object-apply-reset obj)
+    ;; Now initialize the buffer
+    (use-local-map widget-keymap)
+    (widget-setup)
+    ;;(widget-minor-mode)
+    (goto-char (point-min))
+    (widget-forward 3)
+    (make-local-variable 'eieio-co)
+    (setq eieio-co obj)
+    (make-local-variable 'eieio-cog)
+    (setq eieio-cog group)))
+
+(defmethod eieio-custom-object-apply-reset ((obj eieio-default-superclass))
+  "Insert an Apply and Reset button into the object editor.
+Argument OBJ is the object being customized."
+  (widget-create 'push-button
+                :notify (lambda (&rest ignore)
+                          (widget-apply eieio-wo :value-get)
+                          (eieio-done-customizing eieio-co)
+                          (bury-buffer))
+                "Accept")
+  (widget-insert "   ")
+  (widget-create 'push-button
+                :notify (lambda (&rest ignore)
+                          ;; I think the act of getting it sets
+                          ;; its value through the get function.
+                          (message "Applying Changes...")
+                          (widget-apply eieio-wo :value-get)
+                          (eieio-done-customizing eieio-co)
+                          (message "Applying Changes...Done"))
+                "Apply")
+  (widget-insert "   ")
+  (widget-create 'push-button
+                :notify (lambda (&rest ignore)
+                          (message "Resetting")
+                          (eieio-customize-object eieio-co eieio-cog))
+                "Reset")
+  (widget-insert "   ")
+  (widget-create 'push-button
+                :notify (lambda (&rest ignore)
+                          (bury-buffer))
+                "Cancel"))
+
+(defmethod eieio-custom-widget-insert ((obj eieio-default-superclass)
+                                      &rest flags)
+  "Insert the widget used for editing object OBJ in the current buffer.
+Arguments FLAGS are widget compatible flags.
+Must return the created widget."
+  (apply 'widget-create 'object-edit :value obj flags))
+
+(define-widget 'object 'object-edit
+  "Instance of a CLOS class."
+  :format "%{%t%}:\n%v"
+  :value-to-internal 'eieio-object-value-to-abstract
+  :value-to-external 'eieio-object-abstract-to-value
+  :clone-object-children t
+  )
+
+(defun eieio-object-value-to-abstract (widget value)
+  "For WIDGET, convert VALUE to an abstract /safe/ representation."
+  (if (eieio-object-p value) value
+    (if (null value) value
+      nil)))
+
+(defun eieio-object-abstract-to-value (widget value)
+  "For WIDGET, convert VALUE from an abstract /safe/ representation."
+  value)
+
+\f
+;;; customization group functions
+;;
+;; These functions provide the ability to create dynamic menus to
+;; customize specific sections of an object.  They do not hook directly
+;; into a filter, but can be used to create easymenu vectors.
+(defmethod eieio-customize-object-group ((obj eieio-default-superclass))
+  "Create a list of vectors for customizing sections of OBJ."
+  (mapcar (lambda (group)
+           (vector (concat "Group " (symbol-name group))
+                   (list 'customize-object obj (list 'quote group))
+                   t))
+         (class-option (object-class-fast obj) :custom-groups)))
+
+(defvar eieio-read-custom-group-history nil
+  "History for the custom group reader.")
+
+(defmethod eieio-read-customization-group ((obj eieio-default-superclass))
+  "Do a completing read on the name of a customization group in OBJ.
+Return the symbol for the group, or nil"
+  (let ((g (class-option (object-class-fast obj) :custom-groups)))
+    (if (= (length g) 1)
+       (car g)
+      ;; Make the association list
+      (setq g (mapcar (lambda (g) (cons (symbol-name g) g)) g))
+      (cdr (assoc
+           (completing-read (concat (oref obj name)  " Custom Group: ")
+                            g nil t nil 'eieio-read-custom-group-history)
+           g)))))
+
+(provide 'eieio-custom)
+
+;; Local variables:
+;; generated-autoload-file: "eieio.el"
+;; End:
+
+;;; eieio-custom.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-fallback-lib/eieio/eieio-datadebug.el b/xemacs-packages/gnus/lisp/gnus-fallback-lib/eieio/eieio-datadebug.el
new file mode 100644 (file)
index 0000000..c313ec2
--- /dev/null
@@ -0,0 +1,148 @@
+;;; eieio-datadebug.el --- EIEIO extensions to the data debugger.
+
+;; Copyright (C) 2007-2016 Free Software Foundation, Inc.
+
+;; Author: Eric M. Ludlam <zappo@gnu.org>
+;; Keywords: OO, lisp
+;; Package: eieio
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; Extensions to data-debug for EIEIO objects.
+;;
+
+(require 'eieio)
+(require 'data-debug)
+
+;;; Code:
+
+(defun data-debug-insert-object-slots (object prefix)
+  "Insert all the slots of OBJECT.
+PREFIX specifies what to insert at the start of each line."
+  (let ((attrprefix (concat (make-string (length prefix) ? ) "] ")))
+    (data-debug/eieio-insert-slots object attrprefix)))
+
+(defun data-debug-insert-object-slots-from-point (point)
+  "Insert the object slots found at the object button at POINT."
+  (let ((object (get-text-property point 'ddebug))
+       (indent (get-text-property point 'ddebug-indent))
+       start)
+    (end-of-line)
+    (setq start (point))
+    (forward-char 1)
+    (data-debug-insert-object-slots object
+                                   (concat (make-string indent ? )
+                                           "~ "))
+    (goto-char start)))
+
+(defun data-debug-insert-object-button (object prefix prebuttontext)
+  "Insert a button representing OBJECT.
+PREFIX is the text that precedes the button.
+PREBUTTONTEXT is some text between PREFIX and the object button."
+  (let ((start (point))
+       (end nil)
+       (str (object-print object))
+       (tip (format "Object %s\nClass: %S\nParent(s): %S\n%d slots"
+                    (object-name-string object)
+                    (object-class object)
+                    (class-parents (object-class object))
+                    (length (object-slots object))
+                    ))
+       )
+    (insert prefix prebuttontext str)
+    (setq end (point))
+    (put-text-property (- end (length str)) end 'face 'font-lock-keyword-face)
+    (put-text-property start end 'ddebug object)
+    (put-text-property start end 'ddebug-indent(length prefix))
+    (put-text-property start end 'ddebug-prefix prefix)
+    (put-text-property start end 'help-echo tip)
+    (put-text-property start end 'ddebug-function
+                      'data-debug-insert-object-slots-from-point)
+    (insert "\n")))
+
+;;; METHODS
+;;
+;; Each object should have an opportunity to show stuff about itself.
+
+(defmethod data-debug/eieio-insert-slots ((obj eieio-default-superclass)
+                                               prefix)
+  "Insert the slots of OBJ into the current DDEBUG buffer."
+  (data-debug-insert-thing (object-name-string obj)
+                               prefix
+                               "Name: ")
+  (let* ((cl (object-class obj))
+        (cv (class-v cl)))
+    (data-debug-insert-thing (class-constructor cl)
+                                 prefix
+                                 "Class: ")
+    ;; Loop over all the public slots
+    (let ((publa (aref cv class-public-a))
+         (publd (aref cv class-public-d))
+         )
+      (while publa
+       (if (slot-boundp obj (car publa))
+           (let ((i (class-slot-initarg cl (car publa)))
+                 (v (eieio-oref obj (car publa))))
+             (data-debug-insert-thing
+              v prefix (concat
+                        (if i (symbol-name i)
+                          (symbol-name (car publa)))
+                        " ")))
+         ;; Unbound case
+         (let ((i (class-slot-initarg cl (car publa))))
+           (data-debug-insert-custom
+            "#unbound" prefix
+            (concat (if i (symbol-name i)
+                      (symbol-name (car publa)))
+                    " ")
+            'font-lock-keyword-face))
+         )
+       (setq publa (cdr publa) publd (cdr publd))))))
+
+;;; Augment the Data debug thing display list.
+(data-debug-add-specialized-thing (lambda (thing) (object-p thing))
+                                 #'data-debug-insert-object-button)
+
+;;; DEBUG METHODS
+;;
+;; A generic function to run DDEBUG on an object and popup a new buffer.
+;;
+(defmethod data-debug-show ((obj eieio-default-superclass))
+  "Run ddebug against any EIEIO object OBJ."
+  (data-debug-new-buffer (format "*%s DDEBUG*" (object-name obj)))
+  (data-debug-insert-object-slots obj "]"))
+
+;;; DEBUG FUNCTIONS
+;;
+(defun eieio-debug-methodinvoke (method class)
+  "Show the method invocation order for METHOD with CLASS object."
+  (interactive "aMethod: \nXClass Expression: ")
+  (let* ((eieio-pre-method-execution-hooks
+         (lambda (l) (throw 'moose l) ))
+        (data
+         (catch 'moose (eieio-generic-call
+                        method (list class))))
+        (buf (data-debug-new-buffer "*Method Invocation*"))
+        (data2 (mapcar (lambda (sym)
+                         (symbol-function (car sym)))
+                         data)))
+    (data-debug-insert-thing data2 ">" "")))
+
+(provide 'eieio-datadebug)
+
+;;; eieio-datadebug.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-fallback-lib/eieio/eieio-opt.el b/xemacs-packages/gnus/lisp/gnus-fallback-lib/eieio/eieio-opt.el
new file mode 100644 (file)
index 0000000..f26f017
--- /dev/null
@@ -0,0 +1,707 @@
+;;; eieio-opt.el -- eieio optional functions (debug, printing, speedbar)
+
+;; Copyright (C) 1996, 1998-2003, 2005, 2008-2016
+;;   Free Software Foundation, Inc.
+
+;; Author: Eric M. Ludlam <zappo@gnu.org>
+;; Version: 0.2
+;; Keywords: OO, lisp
+;; Package: eieio
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;;   This contains support functions to eieio.  These functions contain
+;; some small class browser and class printing functions.
+;;
+
+(require 'eieio)
+
+;;; Code:
+;;;###autoload
+(defun eieio-browse (&optional root-class)
+  "Create an object browser window to show all objects.
+If optional ROOT-CLASS, then start with that, otherwise start with
+variable `eieio-default-superclass'."
+  (interactive (if current-prefix-arg
+                  (list (read (completing-read "Class: "
+                                               (eieio-build-class-alist)
+                                               nil t)))
+                nil))
+  (if (not root-class) (setq root-class 'eieio-default-superclass))
+  (if (not (class-p root-class)) (signal 'wrong-type-argument (list 'class-p root-class)))
+  (display-buffer (get-buffer-create "*EIEIO OBJECT BROWSE*") t)
+  (with-current-buffer (get-buffer "*EIEIO OBJECT BROWSE*")
+    (erase-buffer)
+    (goto-char 0)
+    (eieio-browse-tree root-class "" "")
+    ))
+
+(defun eieio-browse-tree (this-root prefix ch-prefix)
+  "Recursively draw the children of the given class on the screen.
+Argument THIS-ROOT is the local root of the tree.
+Argument PREFIX is the character prefix to use.
+Argument CH-PREFIX is another character prefix to display."
+  (if (not (class-p (eval this-root))) (signal 'wrong-type-argument (list 'class-p this-root)))
+  (let ((myname (symbol-name this-root))
+       (chl (aref (class-v this-root) class-children))
+       (fprefix (concat ch-prefix "  +--"))
+       (mprefix (concat ch-prefix "  |  "))
+       (lprefix (concat ch-prefix "     ")))
+    (insert prefix myname "\n")
+    (while (cdr chl)
+      (eieio-browse-tree (car chl) fprefix mprefix)
+      (setq chl (cdr chl)))
+    (if chl
+       (eieio-browse-tree (car chl) fprefix lprefix))
+    ))
+
+;;; CLASS COMPLETION / DOCUMENTATION
+
+;;;###autoload
+(defalias 'describe-class 'eieio-describe-class)
+
+;;;###autoload
+(defun eieio-describe-class (class &optional headerfcn)
+  "Describe a CLASS defined by a string or symbol.
+If CLASS is actually an object, then also display current values of that object.
+Optional HEADERFCN should be called to insert a few bits of info first."
+  (interactive (list (eieio-read-class "Class: ")))
+  (with-output-to-temp-buffer (help-buffer) ;"*Help*"
+    (help-setup-xref (list #'eieio-describe-class class headerfcn)
+                    (called-interactively-p 'interactive))
+
+    (when headerfcn (funcall headerfcn))
+
+    (if (class-option class :abstract)
+       (princ "Abstract "))
+    (princ "Class ")
+    (prin1 class)
+    (terpri)
+    ;; Inheritence tree information
+    (let ((pl (class-parents class)))
+      (when pl
+       (princ " Inherits from ")
+       (while pl
+         (princ "`") (prin1 (car pl)) (princ "'")
+         (setq pl (cdr pl))
+         (if pl (princ ", ")))
+       (terpri)))
+    (let ((ch (class-children class)))
+      (when ch
+       (princ " Children ")
+       (while ch
+         (princ "`") (prin1 (car ch)) (princ "'")
+         (setq ch (cdr ch))
+         (if ch (princ ", ")))
+       (terpri)))
+    (terpri)
+    ;; System documentation
+    (let ((doc (documentation-property class 'variable-documentation)))
+      (when doc
+       (princ "Documentation:")
+       (terpri)
+       (princ doc)
+       (terpri)
+       (terpri)))
+    ;; Describe all the slots in this class
+    (eieio-describe-class-slots class)
+    ;; Describe all the methods specific to this class.
+    (let ((methods (eieio-all-generic-functions class))
+         (doc nil))
+      (if (not methods) nil
+       (princ "Specialized Methods:")
+       (terpri)
+       (terpri)
+       (while methods
+         (setq doc (eieio-method-documentation (car methods) class))
+         (princ "`")
+         (prin1 (car methods))
+         (princ "'")
+         (if (not doc)
+             (princ "  Undocumented")
+           (if (car doc)
+               (progn
+                 (princ "  :STATIC ")
+                 (prin1 (car (car doc)))
+                 (terpri)
+                 (princ (cdr (car doc)))))
+           (setq doc (cdr doc))
+           (if (car doc)
+               (progn
+                 (princ "  :BEFORE ")
+                 (prin1 (car (car doc)))
+                 (terpri)
+                 (princ (cdr (car doc)))))
+           (setq doc (cdr doc))
+           (if (car doc)
+               (progn
+                 (princ "  :PRIMARY ")
+                 (prin1 (car (car doc)))
+                 (terpri)
+                 (princ (cdr (car doc)))))
+           (setq doc (cdr doc))
+           (if (car doc)
+               (progn
+                 (princ "  :AFTER ")
+                 (prin1 (car (car doc)))
+                 (terpri)
+                 (princ (cdr (car doc)))))
+           (terpri)
+           (terpri))
+         (setq methods (cdr methods))))))
+  (with-current-buffer (help-buffer)
+    (buffer-string)))
+
+(defun eieio-describe-class-slots (class)
+  "Describe the slots in CLASS.
+Outputs to the standard output."
+  (let* ((cv (class-v class))
+        (docs   (aref cv class-public-doc))
+        (names  (aref cv class-public-a))
+        (deflt  (aref cv class-public-d))
+        (types  (aref cv class-public-type))
+        (publp (aref cv class-public-printer))
+        (i      0)
+        (prot   (aref cv class-protection))
+        )
+    (princ "Instance Allocated Slots:")
+    (terpri)
+    (terpri)
+    (while names
+      (if (car prot) (princ "Private "))
+      (princ "Slot: ")
+      (prin1 (car names))
+      (when (not (eq (aref types i) t))
+       (princ "    type = ")
+       (prin1 (aref types i)))
+      (unless (eq (car deflt) eieio-unbound)
+       (princ "    default = ")
+       (prin1 (car deflt)))
+      (when (car publp)
+       (princ "    printer = ")
+       (prin1 (car publp)))
+      (when (car docs)
+       (terpri)
+       (princ "  ")
+       (princ (car docs))
+       (terpri))
+      (terpri)
+      (setq names (cdr names)
+           docs (cdr docs)
+           deflt (cdr deflt)
+           publp (cdr publp)
+           prot (cdr prot)
+           i (1+ i)))
+    (setq docs  (aref cv class-class-allocation-doc)
+         names (aref cv class-class-allocation-a)
+         types (aref cv class-class-allocation-type)
+         i     0
+         prot  (aref cv class-class-allocation-protection))
+    (when names
+       (terpri)
+       (princ "Class Allocated Slots:"))
+       (terpri)
+       (terpri)
+    (while names
+      (when (car prot)
+       (princ "Private "))
+      (princ "Slot: ")
+      (prin1 (car names))
+      (unless (eq (aref types i) t)
+       (princ "    type = ")
+       (prin1 (aref types i)))
+      (condition-case nil
+         (let ((value (eieio-oref class (car names))))
+           (princ "   value = ")
+           (prin1 value))
+         (error nil))
+      (when (car docs)
+       (terpri)
+       (princ "  ")
+       (princ (car docs))
+       (terpri))
+      (terpri)
+      (setq names (cdr names)
+           docs (cdr docs)
+           prot (cdr prot)
+           i (1+ i)))))
+
+;;;###autoload
+(defun eieio-describe-constructor (fcn)
+  "Describe the constructor function FCN.
+Uses `eieio-describe-class' to describe the class being constructed."
+  (interactive
+   ;; Use eieio-read-class since all constructors have the same name as
+   ;; the class they create.
+   (list (eieio-read-class "Class: ")))
+  (eieio-describe-class
+   fcn (lambda ()
+        ;; Describe the constructor part.
+        (princ "Object Constructor Function: ")
+        (prin1 fcn)
+        (terpri)
+        (princ "Creates an object of class ")
+        (prin1 fcn)
+        (princ ".")
+        (terpri)
+        (terpri)
+        ))
+  )
+
+(defun eieio-build-class-alist (&optional class instantiable-only buildlist)
+  "Return an alist of all currently active classes for completion purposes.
+Optional argument CLASS is the class to start with.
+If INSTANTIABLE-ONLY is non nil, only allow names of classes which
+are not abstract, otherwise allow all classes.
+Optional argument BUILDLIST is more list to attach and is used internally."
+  (let* ((cc (or class eieio-default-superclass))
+        (sublst (aref (class-v cc) class-children)))
+    (if (or (not instantiable-only) (not (class-abstract-p cc)))
+       (setq buildlist (cons (cons (symbol-name cc) 1) buildlist)))
+    (while sublst
+      (setq buildlist (eieio-build-class-alist
+                      (car sublst) instantiable-only buildlist))
+      (setq sublst (cdr sublst)))
+    buildlist))
+
+(defvar eieio-read-class nil
+  "History of the function `eieio-read-class' prompt.")
+
+(defun eieio-read-class (prompt &optional histvar instantiable-only)
+  "Return a class chosen by the user using PROMPT.
+Optional argument HISTVAR is a variable to use as history.
+If INSTANTIABLE-ONLY is non nil, only allow names of classes which
+are not abstract."
+  (intern (completing-read prompt (eieio-build-class-alist nil instantiable-only)
+                          nil t nil
+                          (or histvar 'eieio-read-class))))
+
+(defun eieio-read-subclass (prompt class &optional histvar instantiable-only)
+  "Return a class chosen by the user using PROMPT.
+CLASS is the base class, and completion occurs across all subclasses.
+Optional argument HISTVAR is a variable to use as history.
+If INSTANTIABLE-ONLY is non nil, only allow names of classes which
+are not abstract."
+  (intern (completing-read prompt
+                          (eieio-build-class-alist class instantiable-only)
+                          nil t nil
+                          (or histvar 'eieio-read-class))))
+
+;;; METHOD COMPLETION / DOC
+
+(defalias 'describe-method 'eieio-describe-generic)
+;;;###autoload
+(defalias 'describe-generic 'eieio-describe-generic)
+(defalias 'eieio-describe-method 'eieio-describe-generic)
+
+;;;###autoload
+(defun eieio-describe-generic (generic)
+  "Describe the generic function GENERIC.
+Also extracts information about all methods specific to this generic."
+  (interactive (list (eieio-read-generic "Generic Method: ")))
+  (if (not (generic-p generic))
+      (signal 'wrong-type-argument '(generic-p generic)))
+  (with-output-to-temp-buffer (help-buffer) ; "*Help*"
+    (help-setup-xref (list #'eieio-describe-generic generic)
+                    (called-interactively-p 'interactive))
+
+    (prin1 generic)
+    (princ " is a generic function")
+    (when (generic-primary-only-p generic)
+      (princ " with only ")
+      (when (generic-primary-only-one-p generic)
+       (princ "one "))
+      (princ "primary method")
+      (when (not (generic-primary-only-one-p generic))
+       (princ "s"))
+      )
+    (princ ".")
+    (terpri)
+    (terpri)
+    (let ((d (documentation generic)))
+      (if (not d)
+         (princ "The generic is not documented.\n")
+       (princ "Documentation:")
+       (terpri)
+       (princ d)
+       (terpri)
+       (terpri)))
+    (princ "Implementations:")
+    (terpri)
+    (terpri)
+    (let ((i 3)
+         (prefix [ ":STATIC" ":BEFORE" ":PRIMARY" ":AFTER" ] ))
+      ;; Loop over fanciful generics
+      (while (< i 6)
+       (let ((gm (aref (get generic 'eieio-method-tree) i)))
+         (when gm
+           (princ "Generic ")
+           (princ (aref prefix (- i 3)))
+           (terpri)
+           (princ (or (nth 2 gm) "Undocumented"))
+           (terpri)
+           (terpri)))
+       (setq i (1+ i)))
+      (setq i 0)
+      ;; Loop over defined class-specific methods
+      (while (< i 3)
+       (let ((gm (reverse (aref (get generic 'eieio-method-tree) i))))
+         (while gm
+           (princ "`")
+           (prin1 (car (car gm)))
+           (princ "'")
+           ;; prefix type
+           (princ " ")
+           (princ (aref prefix i))
+           (princ " ")
+           ;; argument list
+           (let* ((func (cdr (car gm)))
+                  (arglst (eieio-lambda-arglist func)))
+             (prin1 arglst))
+           (terpri)
+           ;; 3 because of cdr
+           (princ (or (documentation (cdr (car gm)))
+                      "Undocumented"))
+           (setq gm (cdr gm))
+           (terpri)
+           (terpri)))
+       (setq i (1+ i)))))
+  (with-current-buffer (help-buffer)
+    (buffer-string)))
+
+(defun eieio-lambda-arglist (func)
+  "Return the argument list of FUNC, a function body."
+  (if (symbolp func) (setq func (symbol-function func)))
+  (if (byte-code-function-p func)
+      (eieio-compiled-function-arglist func)
+    (car (cdr func))))
+
+(defun eieio-all-generic-functions (&optional class)
+  "Return a list of all generic functions.
+Optional CLASS argument returns only those functions that contain
+methods for CLASS."
+  (let ((l nil) tree (cn (if class (symbol-name class) nil)))
+    (mapatoms
+     (lambda (symbol)
+       (setq tree (get symbol 'eieio-method-obarray))
+       (if tree
+          (progn
+            ;; A symbol might be interned for that class in one of
+            ;; these three slots in the method-obarray.
+            (if (or (not class)
+                    (fboundp (intern-soft cn (aref tree 0)))
+                    (fboundp (intern-soft cn (aref tree 1)))
+                    (fboundp (intern-soft cn (aref tree 2))))
+                (setq l (cons symbol l)))))))
+    l))
+
+(defun eieio-method-documentation (generic class)
+  "Return a list of the specific documentation of GENERIC for CLASS.
+If there is not an explicit method for CLASS in GENERIC, or if that
+function has no documentation, then return nil."
+  (let ((tree (get generic 'eieio-method-obarray))
+       (cn (symbol-name class))
+       before primary after)
+    (if (not tree)
+       nil
+      ;; A symbol might be interned for that class in one of
+      ;; these three slots in the method-obarray.
+      (setq before (intern-soft cn (aref tree 0))
+           primary (intern-soft cn (aref tree 1))
+           after (intern-soft cn (aref tree 2)))
+      (if (not (or (fboundp before)
+                  (fboundp primary)
+                  (fboundp after)))
+         nil
+       (list (if (fboundp before)
+                 (cons (eieio-lambda-arglist before)
+                       (documentation before))
+               nil)
+             (if (fboundp primary)
+                 (cons (eieio-lambda-arglist primary)
+                       (documentation primary))
+               nil)
+             (if (fboundp after)
+                 (cons (eieio-lambda-arglist after)
+                       (documentation after))
+               nil))))))
+
+(defvar eieio-read-generic nil
+  "History of the `eieio-read-generic' prompt.")
+
+(defun eieio-read-generic-p (fn)
+  "Function used in function `eieio-read-generic'.
+This is because `generic-p' is a macro.
+Argument FN is the function to test."
+  (generic-p fn))
+
+(defun eieio-read-generic (prompt &optional historyvar)
+  "Read a generic function from the minibuffer with PROMPT.
+Optional argument HISTORYVAR is the variable to use as history."
+  (intern (completing-read prompt obarray 'eieio-read-generic-p
+                          t nil (or historyvar 'eieio-read-generic))))
+
+;;; METHOD STATS
+;;
+;; Dump out statistics about all the active methods in a session.
+(defun eieio-display-method-list ()
+  "Display a list of all the methods and what features are used."
+  (interactive)
+  (let* ((meth1 (eieio-all-generic-functions))
+        (meth (sort meth1 (lambda (a b)
+                            (string< (symbol-name a)
+                                     (symbol-name b)))))
+        (buff (get-buffer-create "*EIEIO Method List*"))
+        (methidx 0)
+        (standard-output buff)
+        (slots '(method-static
+                 method-before
+                 method-primary
+                 method-after
+                 method-generic-before
+                 method-generic-primary
+                 method-generic-after))
+        (slotn '("static"
+                 "before"
+                 "primary"
+                 "after"
+                 "G bef"
+                 "G prim"
+                 "G aft"))
+        (idxarray (make-vector (length slots) 0))
+        (primaryonly 0)
+        (oneprimary 0)
+        )
+    (switch-to-buffer-other-window buff)
+    (erase-buffer)
+    (dolist (S slotn)
+      (princ S)
+      (princ "\t")
+      )
+    (princ "Method Name")
+    (terpri)
+    (princ "--------------------------------------------------------------------")
+    (terpri)
+    (dolist (M meth)
+      (let ((mtree (get M 'eieio-method-tree))
+           (P nil) (numP)
+           (!P nil))
+       (dolist (S slots)
+         (let ((num (length (aref mtree (symbol-value S)))))
+           (aset idxarray (symbol-value S)
+                 (+ num (aref idxarray (symbol-value S))))
+           (prin1 num)
+           (princ "\t")
+           (when (< 0 num)
+             (if (eq S 'method-primary)
+                 (setq P t numP num)
+               (setq !P t)))
+           ))
+       ;; Is this a primary-only impl method?
+       (when (and P (not !P))
+         (setq primaryonly (1+ primaryonly))
+         (when (= numP 1)
+           (setq oneprimary (1+ oneprimary))
+           (princ "*"))
+         (princ "* ")
+         )
+       (prin1 M)
+       (terpri)
+       (setq methidx (1+ methidx))
+       )
+      )
+    (princ "--------------------------------------------------------------------")
+    (terpri)
+    (dolist (S slots)
+      (prin1 (aref idxarray (symbol-value S)))
+      (princ "\t")
+      )
+    (prin1 methidx)
+    (princ " Total symbols")
+    (terpri)
+    (dolist (S slotn)
+      (princ S)
+      (princ "\t")
+      )
+    (terpri)
+    (terpri)
+    (princ "Methods Primary Only: ")
+    (prin1 primaryonly)
+    (princ "\t")
+    (princ (format "%d" (* (/ (float primaryonly) (float methidx)) 100)))
+    (princ "% of total methods")
+    (terpri)
+    (princ "Only One Primary Impl: ")
+    (prin1 oneprimary)
+    (princ "\t")
+    (princ (format "%d" (* (/ (float oneprimary) (float primaryonly)) 100)))
+    (princ "% of total primary methods")
+    (terpri)
+    ))
+
+;;; HELP AUGMENTATION
+;;
+;;;###autoload
+(defun eieio-help-mode-augmentation-maybee (&rest unused)
+  "For buffers thrown into help mode, augment for EIEIO.
+Arguments UNUSED are not used."
+  ;; Scan created buttons so far if we are in help mode.
+  (when (eq major-mode 'help-mode)
+    (save-excursion
+      (goto-char (point-min))
+      (let ((pos t) (inhibit-read-only t))
+       (while pos
+         (if (get-text-property (point) 'help-xref) ; move off reference
+             (goto-char
+              (or (next-single-property-change (point) 'help-xref)
+                  (point))))
+         (setq pos (next-single-property-change (point) 'help-xref))
+         (when pos
+           (goto-char pos)
+           (let* ((help-data (get-text-property (point) 'help-xref))
+                  ;(method (car help-data))
+                  (args (cdr help-data)))
+             (when (symbolp (car args))
+               (cond ((class-p (car args))
+                      (setcar help-data 'eieio-describe-class))
+                     ((generic-p (car args))
+                      (setcar help-data 'eieio-describe-generic))
+                     (t nil))
+               ))))
+       ;; start back at the beginning, and highlight some sections
+       (goto-char (point-min))
+       (while (re-search-forward "^\\(Documentation\\|Implementations\\):$" nil t)
+           (put-text-property (match-beginning 0) (match-end 0) 'face 'bold))
+       (goto-char (point-min))
+       (if (re-search-forward "^Specialized Methods:$" nil t)
+           (put-text-property (match-beginning 0) (match-end 0) 'face 'bold))
+       (goto-char (point-min))
+       (while (re-search-forward "^\\(Instance\\|Class\\) Allocated Slots:$" nil t)
+           (put-text-property (match-beginning 0) (match-end 0) 'face 'bold))
+       (goto-char (point-min))
+       (while (re-search-forward ":\\(STATIC\\|BEFORE\\|AFTER\\|PRIMARY\\)" nil t)
+           (put-text-property (match-beginning 0) (match-end 0) 'face 'bold))
+       (goto-char (point-min))
+       (while (re-search-forward "^\\(Private \\)?Slot:" nil t)
+           (put-text-property (match-beginning 0) (match-end 0) 'face 'bold))
+       ))))
+
+;;; SPEEDBAR SUPPORT
+;;
+(eval-when-compile
+  (condition-case nil
+      (require 'speedbar)
+    (error (message "Error loading speedbar... ignored"))))
+
+(defvar eieio-class-speedbar-key-map nil
+  "Keymap used when working with a project in speedbar.")
+
+(defun eieio-class-speedbar-make-map ()
+  "Make a keymap for EIEIO under speedbar."
+  (setq eieio-class-speedbar-key-map (speedbar-make-specialized-keymap))
+
+  ;; General viewing stuff
+  (define-key eieio-class-speedbar-key-map "\C-m" 'speedbar-edit-line)
+  (define-key eieio-class-speedbar-key-map "+" 'speedbar-expand-line)
+  (define-key eieio-class-speedbar-key-map "-" 'speedbar-contract-line)
+  )
+
+(if eieio-class-speedbar-key-map
+    nil
+  (if (not (featurep 'speedbar))
+      (add-hook 'speedbar-load-hook (lambda ()
+                                     (eieio-class-speedbar-make-map)
+                                     (speedbar-add-expansion-list
+                                      '("EIEIO"
+                                        eieio-class-speedbar-menu
+                                        eieio-class-speedbar-key-map
+                                        eieio-class-speedbar))))
+    (eieio-class-speedbar-make-map)
+    (speedbar-add-expansion-list '("EIEIO"
+                                  eieio-class-speedbar-menu
+                                  eieio-class-speedbar-key-map
+                                  eieio-class-speedbar))))
+
+(defvar eieio-class-speedbar-menu
+  ()
+  "Menu part in easymenu format used in speedbar while in `eieio' mode.")
+
+(defun eieio-class-speedbar (dir-or-object depth)
+  "Create buttons in speedbar that represents the current project.
+DIR-OR-OBJECT is the object to expand, or nil, and DEPTH is the
+current expansion depth."
+  (when (eq (point-min) (point-max))
+    ;; This function is only called once, to start the whole deal.
+    ;; Ceate, and expand the default object.
+    (eieio-class-button eieio-default-superclass 0)
+    (forward-line -1)
+    (speedbar-expand-line)))
+
+(defun eieio-class-button (class depth)
+  "Draw a speedbar button at the current point for CLASS at DEPTH."
+  (if (not (class-p class))
+      (signal 'wrong-type-argument (list 'class-p class)))
+  (let ((subclasses (aref (class-v class) class-children)))
+    (if subclasses
+       (speedbar-make-tag-line 'angle ?+
+                               'eieio-sb-expand
+                               class
+                               (symbol-name class)
+                               'eieio-describe-class-sb
+                               class
+                               'speedbar-directory-face
+                               depth)
+      (speedbar-make-tag-line 'angle ?  nil nil
+                             (symbol-name class)
+                             'eieio-describe-class-sb
+                             class
+                             'speedbar-directory-face
+                             depth))))
+
+(defun eieio-sb-expand (text class indent)
+  "For button TEXT, expand CLASS at the current location.
+Argument INDENT is the depth of indentation."
+  (cond ((string-match "+" text)       ;we have to expand this file
+        (speedbar-change-expand-button-char ?-)
+        (speedbar-with-writable
+          (save-excursion
+            (end-of-line) (forward-char 1)
+            (let ((subclasses (aref (class-v class) class-children)))
+              (while subclasses
+                (eieio-class-button (car subclasses) (1+ indent))
+                (setq subclasses (cdr subclasses)))))))
+       ((string-match "-" text)        ;we have to contract this node
+        (speedbar-change-expand-button-char ?+)
+        (speedbar-delete-subblock indent))
+       (t (error "Ooops...  not sure what to do")))
+  (speedbar-center-buffer-smartly))
+
+(defun eieio-describe-class-sb (text token indent)
+  "Describe the class TEXT in TOKEN.
+INDENT is the current indentation level."
+  (speedbar-with-attached-buffer
+   (eieio-describe-class token))
+  (speedbar-maybee-jump-to-attached-frame))
+
+(provide 'eieio-opt)
+
+;; Local variables:
+;; generated-autoload-file: "eieio.el"
+;; End:
+
+;;; eieio-opt.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-fallback-lib/eieio/eieio-speedbar.el b/xemacs-packages/gnus/lisp/gnus-fallback-lib/eieio/eieio-speedbar.el
new file mode 100644 (file)
index 0000000..51a1871
--- /dev/null
@@ -0,0 +1,424 @@
+;;; eieio-speedbar.el -- Classes for managing speedbar displays.
+
+;; Copyright (C) 1999-2002, 2005, 2007-2016 Free Software Foundation, Inc.
+
+;; Author: Eric M. Ludlam <zappo@gnu.org>
+;; Version: 0.2
+;; Keywords: OO, tools
+;; Package: eieio
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;;  This provides some classes that can be used as a parent which
+;; will automatically provide SPEEDBAR support for any list of objects
+;; of that type.
+;;
+;; This file requires speedbar version 0.10 or later.
+
+;;; Creating a new speedbar mode based on a pre-existing object hierarchy
+;;
+;; To create a new speedbar mode based on lists of objects is easier
+;; than creating a whole new speedbar mode from scratch.
+;;
+;; 1) Objects that will have lists of items that can be expanded
+;;    should also inherit from the classes:
+;;  * `eieio-speedbar'                  - specify your own button behavior
+;;  * `eieio-speedbar-directory-button' - objects that behave like directories
+;;  * `eieio-speedbar-file-button'      - objects that behave like files
+;;
+;; 2) Objects that have lists of children should implement the method
+;;    `eieio-speedbar-object-children' which returns a list of more
+;;    objects, or a list of strings.
+;;
+;; 3) Objects that return a list of strings should also implement these
+;;    methods:
+;;  * `eieio-speedbar-child-make-tag-lines' - make tag lines for a child.
+;;  * `eieio-speedbar-child-description' - describe non-object children
+;;
+;; 4) Objects which have expanded information should implement the method
+;;    `eieio-speedbar-description' to produce more information.
+;;
+;; 5) Objects that are associated with a directory should implement
+;;    the method `eieio-speedbar-derive-line-path' which returns a
+;;    path.
+;;
+;; 6) Objects that have a specialized behavior when clicked should
+;;    define the method `eieio-speedbar-handle-click'.
+;;
+;; To initialize a new eieio based speedbar display, do the following.
+;;
+;; 1) Create a keymap variable `foo-speedbar-key-map'.
+;;    This keymap variable should be initialized in a function.
+;;    If you have no special needs, use `eieio-speedbar-key-map'
+;;
+;; 2) Create a variable containing an easymenu definition compatible
+;;    with speedbar.  if you have no special needs, use
+;;    `eieio-speedbar-menu'.
+;;
+;; 3) Create a function which returns the top-level list of children
+;;    objects to be displayed in speedbar.
+;;
+;; 4) Call `eieio-speedbar-create' as specified in it's documentation
+;;    string.   This will automatically handle cases when speedbar is
+;;    not already loaded, and specifying all overload functions.
+;;
+;; 5) Create an initializer function which looks like this:
+;;
+;; (defun my-speedbar-mode-initialize ()
+;;   "documentation"
+;;   (interactive)
+;;   (speedbar-frame-mode 1)
+;;   (speedbar-change-initial-expansion-list mymodename)
+;;   (speedbar-get-focus))
+;;
+;; where `mymodename' is the same value as passed to `eieio-speedbar-create'
+;; as the MODENAME parameter.
+
+;; @todo - Can we make this ECB friendly?
+
+;;; Code:
+(require 'eieio)
+(require 'eieio-custom)
+(require 'speedbar)
+
+;;; Support a way of adding generic object based modes into speedbar.
+;;
+(defun eieio-speedbar-make-map ()
+  "Make the generic object based speedbar keymap."
+  (let ((map (speedbar-make-specialized-keymap)))
+
+    ;; General viewing things
+    (define-key map "\C-m" 'speedbar-edit-line)
+    (define-key map "+" 'speedbar-expand-line)
+    (define-key map "=" 'speedbar-expand-line)
+    (define-key map "-" 'speedbar-contract-line)
+
+    ;; Some object based things
+    (define-key map "C" 'eieio-speedbar-customize-line)
+    map))
+
+(defvar eieio-speedbar-key-map (eieio-speedbar-make-map)
+  "A generic object based speedbar display keymap.")
+
+(defvar eieio-speedbar-menu
+  '([ "Edit Object/Field" speedbar-edit-line t]
+    [ "Expand Object" speedbar-expand-line
+      (save-excursion (beginning-of-line)
+                     (looking-at "[0-9]+: *.\\+. "))]
+    [ "Contract Object" speedbar-contract-line
+      (save-excursion (beginning-of-line)
+                     (looking-at "[0-9]+: *.-. "))]
+    "---"
+    [ "Customize Object" eieio-speedbar-customize-line
+      (eieio-object-p (speedbar-line-token)) ]
+    )
+  "Menu part in easymenu format used in speedbar while browsing objects.")
+
+;; Note to self:  Fix this silly thing!
+(defalias 'eieio-speedbar-customize-line  'speedbar-edit-line)
+
+(defun eieio-speedbar-create (map-fn map-var menu-var modename fetcher)
+  "Create a speedbar mode for displaying an object hierarchy.
+MAP-FN is the keymap generator function used for extra keys.
+MAP-VAR is the keymap variable used.
+MENU-VAR is the symbol containing an easymenu compatible menu part to use.
+MODENAME is a string used to identify this browser mode.
+FETCHER is a generic function used to fetch the base object list used when
+creating the speedbar display."
+  (if (not (featurep 'speedbar))
+      (add-hook 'speedbar-load-hook
+               (list 'lambda nil
+                     (list 'eieio-speedbar-create-engine
+                           map-fn map-var menu-var modename fetcher)))
+    (eieio-speedbar-create-engine map-fn map-var menu-var modename fetcher)))
+
+(defun eieio-speedbar-create-engine (map-fn map-var menu-var modename fetcher)
+  "Create a speedbar mode for displaying an object hierarchy.
+Called from `eieio-speedbar-create', or the speedbar load-hook.
+MAP-FN, MAP-VAR, MENU-VAR, MODENAME, and FETCHER are the same as in
+`eieio-speedbar-create'."
+  ;; make sure the keymap exists
+  (funcall map-fn)
+  ;; Add to the expansion list.
+  (speedbar-add-expansion-list
+   (list modename
+        menu-var
+        map-var
+        (list 'lambda '(dir depth)
+              (list 'eieio-speedbar-buttons 'dir 'depth
+                    (list 'quote fetcher)))))
+  ;; Set the special functions.
+  (speedbar-add-mode-functions-list
+   (list modename
+        '(speedbar-item-info . eieio-speedbar-item-info)
+        '(speedbar-line-directory . eieio-speedbar-line-path))))
+
+(defun eieio-speedbar-buttons (dir-or-object depth fetcher)
+  "Create buttons for the speedbar display.
+Start in directory DIR-OR-OBJECT.  If it is an object, just display that
+object's subelements.
+Argument DEPTH specifies how far down we have already been displayed.
+If it is a directory, use FETCHER to fetch all objects associated with
+that path."
+  (let ((objlst (cond ((eieio-object-p dir-or-object)
+                      (list dir-or-object))
+                     ((stringp dir-or-object)
+                      (funcall fetcher dir-or-object))
+                     (t dir-or-object))))
+    (if (not objlst)
+       (speedbar-make-tag-line nil nil nil nil "Empty display" nil nil nil
+                               depth)
+      ;; Dump all objects into speedbar
+      (while objlst
+       (eieio-speedbar-make-tag-line (car objlst) depth)
+       (setq objlst (cdr objlst))))))
+
+\f
+;;; DEFAULT SUPERCLASS baseline methods
+;;
+;; First, define methods onto the superclass so all classes
+;; will have some minor support.
+
+(defmethod eieio-speedbar-description ((object eieio-default-superclass))
+  "Return a string describing OBJECT."
+  (object-name-string object))
+
+(defmethod eieio-speedbar-derive-line-path ((object eieio-default-superclass))
+  "Return the path which OBJECT has something to do with."
+  nil)
+
+(defmethod eieio-speedbar-object-buttonname ((object eieio-default-superclass))
+  "Return a string to use as a speedbar button for OBJECT."
+  (object-name-string object))
+
+(defmethod eieio-speedbar-make-tag-line ((object eieio-default-superclass)
+                                        depth)
+  "Insert a tag line into speedbar at point for OBJECT.
+By default, all objects appear as simple TAGS with no need to inherit from
+the special `eieio-speedbar' classes.  Child classes should redefine this
+method to create more accurate tag lines.
+Argument DEPTH is the depth at which the tag line is inserted."
+  (speedbar-make-tag-line nil nil nil nil
+                         (eieio-speedbar-object-buttonname object)
+                         'eieio-speedbar-object-click
+                         object
+                         'speedbar-tag-face
+                         depth))
+
+(defmethod eieio-speedbar-handle-click ((object eieio-default-superclass))
+  "Handle a click action on OBJECT in speedbar.
+Any object can be represented as a tag in SPEEDBAR without special
+attributes.  These default objects will be pulled up in a custom
+object edit buffer doing an in-place edit.
+
+If your object represents some other item, override this method
+and take the appropriate action."
+  (require 'eieio-custom)
+  (speedbar-with-attached-buffer
+   (eieio-customize-object object))
+  (speedbar-maybee-jump-to-attached-frame))
+
+\f
+;;; Class definitions
+;;
+;; Now define a special speedbar class with some
+;; variables with :allocation class which can be attached into
+;; object hierarchies.
+;;
+;; These more complex types are for objects which wish to display
+;; lists of children buttons.
+
+(defclass eieio-speedbar nil
+  ((buttontype :initform nil
+              :type symbol
+              :documentation
+              "The type of expansion button used for objects of this class.
+Possible values are those symbols supported by the `exp-button-type' argument
+to `speedbar-make-tag-line'."
+              :allocation :class)
+   (buttonface :initform speedbar-tag-face
+              :type (or symbol face)
+              :documentation
+              "The face used on the textual part of the button for this class.
+See `speedbar-make-tag-line' for details."
+              :allocation :class)
+   (expanded :initform nil
+            :type boolean
+            :documentation
+            "State of an object being expanded in speedbar.")
+   )
+  "Class which provides basic speedbar support for child classes.
+Add one of the child classes to this class to the parent list of a class."
+  :method-invocation-order :depth-first
+  :abstract t)
+
+(defclass eieio-speedbar-directory-button (eieio-speedbar)
+  ((buttontype :initform angle)
+   (buttonface :initform speedbar-directory-face))
+  "Class providing support for objects which behave like a directory."
+  :method-invocation-order :depth-first
+  :abstract t)
+
+(defclass eieio-speedbar-file-button (eieio-speedbar)
+  ((buttontype :initform bracket)
+   (buttonface :initform speedbar-file-face))
+  "Class providing support for objects which behave like a file."
+  :method-invocation-order :depth-first
+  :abstract t)
+
+\f
+;;; Methods to eieio-speedbar-* which do not need to be overriden
+;;
+(defmethod eieio-speedbar-make-tag-line ((object eieio-speedbar)
+                                        depth)
+  "Insert a tag line into speedbar at point for OBJECT.
+All objects a child of symbol `eieio-speedbar' can be created from
+this method.  Override this if you need non-traditional tag lines.
+Argument DEPTH is the depth at which the tag line is inserted."
+  (let ((children (eieio-speedbar-object-children object))
+       (exp (oref object expanded)))
+    (if (not children)
+       (if (eq (oref object buttontype) 'expandtag)
+           (speedbar-make-tag-line 'statictag
+                                   ?  nil nil
+                                   (eieio-speedbar-object-buttonname object)
+                                   'eieio-speedbar-object-click
+                                   object
+                                   (oref object buttonface)
+                                   depth)
+         (speedbar-make-tag-line (oref object buttontype)
+                                 ?  nil nil
+                                 (eieio-speedbar-object-buttonname object)
+                                 'eieio-speedbar-object-click
+                                 object
+                                 (oref object buttonface)
+                                 depth))
+      (speedbar-make-tag-line (oref object buttontype)
+                             (if exp ?- ?+)
+                             'eieio-speedbar-object-expand
+                             object
+                             (eieio-speedbar-object-buttonname object)
+                             'eieio-speedbar-object-click
+                             object
+                             (oref object buttonface)
+                             depth)
+      (if exp
+         (eieio-speedbar-expand object (1+ depth))))))
+
+(defmethod eieio-speedbar-child-make-tag-lines ((object eieio-speedbar) depth)
+  "Base method for creating tag lines for non-object children."
+  (error "You must implement `eieio-speedbar-child-make-tag-lines' for %s"
+        (object-name object)))
+
+(defmethod eieio-speedbar-expand ((object eieio-speedbar) depth)
+  "Expand OBJECT at indentation DEPTH.
+Inserts a list of new tag lines representing expanded elements within
+OBJECT."
+  (let ((children (eieio-speedbar-object-children object)))
+    (cond ((eieio-object-p (car children))
+          (mapcar (lambda (car)
+                    (eieio-speedbar-make-tag-line car depth))
+                  children))
+         (children (eieio-speedbar-child-make-tag-lines object depth)))))
+
+\f
+;;; Speedbar specific function callbacks.
+;;
+(defun eieio-speedbar-object-click (text token indent)
+  "Handle a user click on TEXT representing object TOKEN.
+The object is at indentation level INDENT."
+  (eieio-speedbar-handle-click token))
+
+(defun eieio-speedbar-object-expand (text token indent)
+  "Expand object represented by TEXT.
+TOKEN is the object.  INDENT is the current indentation level."
+  (cond ((string-match "+" text)       ;we have to expand this file
+        (speedbar-change-expand-button-char ?-)
+        (oset token expanded t)
+        (speedbar-with-writable
+          (save-excursion
+            (end-of-line) (forward-char 1)
+            (eieio-speedbar-expand token (1+ indent)))))
+       ((string-match "-" text)        ;we have to contract this node
+        (speedbar-change-expand-button-char ?+)
+        (oset token expanded nil)
+        (speedbar-delete-subblock indent))
+       (t (error "Ooops... not sure what to do")))
+  (speedbar-center-buffer-smartly))
+
+(defmethod eieio-speedbar-child-description ((obj eieio-speedbar))
+  "Return a description for a child of OBJ which is not an object."
+  (error "You must implement `eieio-speedbar-child-description' for %s"
+        (object-name obj)))
+
+(defun eieio-speedbar-item-info ()
+  "Display info for the current line when in EDE display mode."
+  ;; Switch across the types of the tokens.
+  (let ((tok (speedbar-line-token)))
+    (cond ((eieio-object-p tok)
+          (message (eieio-speedbar-description tok)))
+         (t
+          (let ((no (eieio-speedbar-find-nearest-object)))
+            (if no
+                (eieio-speedbar-child-description no)))))))
+
+(defun eieio-speedbar-find-nearest-object (&optional depth)
+  "Search backwards to the first line associated with an object.
+Optional argument DEPTH is the current depth of the search."
+  (save-excursion
+    (if (not depth)
+       (progn
+         (beginning-of-line)
+         (when (looking-at "^\\([0-9]+\\):")
+           (setq depth (string-to-number (match-string 1))))))
+    (when depth
+      (while (and (not (eieio-object-p (speedbar-line-token)))
+                 (> depth 0))
+       (setq depth (1- depth))
+       (re-search-backward (format "^%d:" depth) nil t))
+      (speedbar-line-token))))
+
+(defun eieio-speedbar-line-path (&optional depth)
+  "If applicable, return the path to the file the cursor is on.
+Optional DEPTH is the depth we start at."
+  (save-match-data
+    (if (not depth)
+       (progn
+         (beginning-of-line)
+         (looking-at "^\\([0-9]+\\):")
+         (setq depth (string-to-number (match-string 1)))))
+    ;; This whole function is presently bogus.  Make it better later.
+    (let ((tok (eieio-speedbar-find-nearest-object depth)))
+      (if (eieio-object-p tok)
+         (eieio-speedbar-derive-line-path tok)
+       default-directory))))
+
+\f
+;;; Methods to the eieio-speedbar-* classes which need to be overriden.
+;;
+(defmethod eieio-speedbar-object-children ((object eieio-speedbar))
+  "Return a list of children to be displayed in speedbar.
+If the return value is a list of OBJECTs, then those objects are
+queried for details.  If the return list is made of strings,
+then this object will be queried for the details needed
+to create a speedbar button."
+  nil)
+
+(provide 'eieio-speedbar)
+
+;;; eieio-speedbar.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-fallback-lib/eieio/eieio.el b/xemacs-packages/gnus/lisp/gnus-fallback-lib/eieio/eieio.el
new file mode 100644 (file)
index 0000000..0342e75
--- /dev/null
@@ -0,0 +1,2999 @@
+;;; eieio.el --- Enhanced Implementation of Emacs Interpreted Objects
+;;;              or maybe Eric's Implementation of Emacs Intrepreted Objects
+
+;; Copyright (C) 1995-1996, 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Eric M. Ludlam <zappo@gnu.org>
+;; Version: 1.3
+;; Keywords: OO, lisp
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; EIEIO is a series of Lisp routines which implements a subset of
+;; CLOS, the Common Lisp Object System.  In addition, EIEIO also adds
+;; a few new features which help it integrate more strongly with the
+;; Emacs running environment.
+;;
+;; See eieio.texi for complete documentation on using this package.
+;;
+;; Note: the implementation of the c3 algorithm is based on:
+;;   Kim Barrett et al.: A Monotonic Superclass Linearization for Dylan
+;;   Retrieved from:
+;;   http://192.220.96.201/dylan/linearization-oopsla96.html
+
+;; There is funny stuff going on with typep and deftype.  This
+;; is the only way I seem to be able to make this stuff load properly.
+
+;; @TODO - fix :initform to be a form, not a quoted value
+;; @TODO - Prefix non-clos functions with `eieio-'.
+
+;;; Code:
+
+(eval-when-compile
+  (require 'cl))
+
+(defvar eieio-version "1.3"
+  "Current version of EIEIO.")
+
+(defun eieio-version ()
+  "Display the current version of EIEIO."
+  (interactive)
+  (message eieio-version))
+
+(eval-and-compile
+;; About the above.  EIEIO must process its own code when it compiles
+;; itself, thus, by eval-and-compiling outselves, we solve the problem.
+
+;; Compatibility
+(if (fboundp 'compiled-function-arglist)
+
+    ;; XEmacs can only access a compiled functions arglist like this:
+    (defalias 'eieio-compiled-function-arglist 'compiled-function-arglist)
+
+  ;; Emacs doesn't have this function, but since FUNC is a vector, we can just
+  ;; grab the appropriate element.
+  (defun eieio-compiled-function-arglist (func)
+    "Return the argument list for the compiled function FUNC."
+    (aref func 0))
+
+  )
+
+\f
+;;;
+;; Variable declarations.
+;;
+
+(defvar eieio-hook nil
+  "*This hook is executed, then cleared each time `defclass' is called.")
+
+(defvar eieio-error-unsupported-class-tags nil
+  "Non-nil to throw an error if an encountered tag is unsupported.
+This may prevent classes from CLOS applications from being used with EIEIO
+since EIEIO does not support all CLOS tags.")
+
+(defvar eieio-skip-typecheck nil
+  "*If non-nil, skip all slot typechecking.
+Set this to t permanently if a program is functioning well to get a
+small speed increase.  This variable is also used internally to handle
+default setting for optimization purposes.")
+
+(defvar eieio-optimize-primary-methods-flag t
+  "Non-nil means to optimize the method dispatch on primary methods.")
+
+;; State Variables
+;; FIXME: These two constants below should have an `eieio-' prefix added!!
+(defvar this nil
+  "Inside a method, this variable is the object in question.
+DO NOT SET THIS YOURSELF unless you are trying to simulate friendly slots.
+
+Note: Embedded methods are no longer supported.  The variable THIS is
+still set for CLOS methods for the sake of routines like
+`call-next-method'.")
+
+(defvar scoped-class nil
+  "This is set to a class when a method is running.
+This is so we know we are allowed to check private parts or how to
+execute a `call-next-method'.  DO NOT SET THIS YOURSELF!")
+
+(defvar eieio-initializing-object  nil
+  "Set to non-nil while initializing an object.")
+
+(defconst eieio-unbound
+  (if (and (boundp 'eieio-unbound) (symbolp eieio-unbound))
+      eieio-unbound
+    (make-symbol "unbound"))
+  "Uninterned symbol representing an unbound slot in an object.")
+
+;; This is a bootstrap for eieio-default-superclass so it has a value
+;; while it is being built itself.
+(defvar eieio-default-superclass nil)
+
+;; FIXME: The constants below should have an `eieio-' prefix added!!
+(defconst class-symbol 1 "Class's symbol (self-referencing.).")
+(defconst class-parent 2 "Class parent slot.")
+(defconst class-children 3 "Class children class slot.")
+(defconst class-symbol-obarray 4 "Obarray permitting fast access to variable position indexes.")
+;; @todo
+;; the word "public" here is leftovers from the very first version.
+;; Get rid of it!
+(defconst class-public-a 5 "Class attribute index.")
+(defconst class-public-d 6 "Class attribute defaults index.")
+(defconst class-public-doc 7 "Class documentation strings for attributes.")
+(defconst class-public-type 8 "Class type for a slot.")
+(defconst class-public-custom 9 "Class custom type for a slot.")
+(defconst class-public-custom-label 10 "Class custom group for a slot.")
+(defconst class-public-custom-group 11 "Class custom group for a slot.")
+(defconst class-public-printer 12 "Printer for a slot.")
+(defconst class-protection 13 "Class protection for a slot.")
+(defconst class-initarg-tuples 14 "Class initarg tuples list.")
+(defconst class-class-allocation-a 15 "Class allocated attributes.")
+(defconst class-class-allocation-doc 16 "Class allocated documentation.")
+(defconst class-class-allocation-type 17 "Class allocated value type.")
+(defconst class-class-allocation-custom 18 "Class allocated custom descriptor.")
+(defconst class-class-allocation-custom-label 19 "Class allocated custom descriptor.")
+(defconst class-class-allocation-custom-group 20 "Class allocated custom group.")
+(defconst class-class-allocation-printer 21 "Class allocated printer for a slot.")
+(defconst class-class-allocation-protection 22 "Class allocated protection list.")
+(defconst class-class-allocation-values 23 "Class allocated value vector.")
+(defconst class-default-object-cache 24
+  "Cache index of what a newly created object would look like.
+This will speed up instantiation time as only a `copy-sequence' will
+be needed, instead of looping over all the values and setting them
+from the default.")
+(defconst class-options 25
+  "Storage location of tagged class options.
+Stored outright without modifications or stripping.")
+
+(defconst class-num-slots 26
+  "Number of slots in the class definition object.")
+
+(defconst object-class 1 "Index in an object vector where the class is stored.")
+(defconst object-name 2 "Index in an object where the name is stored.")
+
+(defconst method-static 0 "Index into :static tag on a method.")
+(defconst method-before 1 "Index into :before tag on a method.")
+(defconst method-primary 2 "Index into :primary tag on a method.")
+(defconst method-after 3 "Index into :after tag on a method.")
+(defconst method-num-lists 4 "Number of indexes into methods vector in which groups of functions are kept.")
+(defconst method-generic-before 4 "Index into generic :before tag on a method.")
+(defconst method-generic-primary 5 "Index into generic :primary tag on a method.")
+(defconst method-generic-after 6 "Index into generic :after tag on a method.")
+(defconst method-num-slots 7 "Number of indexes into a method's vector.")
+
+(defsubst eieio-specialized-key-to-generic-key (key)
+  "Convert a specialized KEY into a generic method key."
+  (cond ((eq key method-static) 0) ;; don't convert
+       ((< key method-num-lists) (+ key 3)) ;; The conversion
+       (t key) ;; already generic.. maybe.
+       ))
+
+\f
+;;; Important macros used in eieio.
+;;
+(defmacro class-v (class)
+  "Internal: Return the class vector from the CLASS symbol."
+  ;; No check: If eieio gets this far, it's probably been checked already.
+  `(get ,class 'eieio-class-definition))
+
+(defmacro class-p (class)
+  "Return t if CLASS is a valid class vector.
+CLASS is a symbol."
+  ;; this new method is faster since it doesn't waste time checking lots of
+  ;; things.
+  `(condition-case nil
+       (eq (aref (class-v ,class) 0) 'defclass)
+     (error nil)))
+
+(defmacro eieio-object-p (obj)
+  "Return non-nil if OBJ is an EIEIO object."
+  `(condition-case nil
+       (let ((tobj ,obj))
+        (and (eq (aref tobj 0) 'object)
+             (class-p (aref tobj object-class))))
+     (error nil)))
+(defalias 'object-p 'eieio-object-p)
+
+(defmacro class-constructor (class)
+  "Return the symbol representing the constructor of CLASS."
+  `(aref (class-v ,class) class-symbol))
+
+(defmacro generic-p (method)
+  "Return t if symbol METHOD is a generic function.
+Only methods have the symbol `eieio-method-obarray' as a property
+\(which contains a list of all bindings to that method type.)"
+  `(and (fboundp ,method) (get ,method 'eieio-method-obarray)))
+
+(defun generic-primary-only-p (method)
+  "Return t if symbol METHOD is a generic function with only primary methods.
+Only methods have the symbol `eieio-method-obarray' as a property (which
+contains a list of all bindings to that method type.)
+Methods with only primary implementations are executed in an optimized way."
+  (and (generic-p method)
+       (let ((M (get method 'eieio-method-tree)))
+        (and (< 0 (length (aref M method-primary)))
+             (not (aref M method-static))
+             (not (aref M method-before))
+             (not (aref M method-after))
+             (not (aref M method-generic-before))
+             (not (aref M method-generic-primary))
+             (not (aref M method-generic-after))))
+       ))
+
+(defun generic-primary-only-one-p (method)
+  "Return t if symbol METHOD is a generic function with only primary methods.
+Only methods have the symbol `eieio-method-obarray' as a property (which
+contains a list of all bindings to that method type.)
+Methods with only primary implementations are executed in an optimized way."
+  (and (generic-p method)
+       (let ((M (get method 'eieio-method-tree)))
+        (and (= 1 (length (aref M method-primary)))
+             (not (aref M method-static))
+             (not (aref M method-before))
+             (not (aref M method-after))
+             (not (aref M method-generic-before))
+             (not (aref M method-generic-primary))
+             (not (aref M method-generic-after))))
+       ))
+
+(defmacro class-option-assoc (list option)
+  "Return from LIST the found OPTION, or nil if it doesn't exist."
+  `(car-safe (cdr (memq ,option ,list))))
+
+(defmacro class-option (class option)
+  "Return the value stored for CLASS' OPTION.
+Return nil if that option doesn't exist."
+  `(class-option-assoc (aref (class-v ,class) class-options) ',option))
+
+(defmacro class-abstract-p (class)
+  "Return non-nil if CLASS is abstract.
+Abstract classes cannot be instantiated."
+  `(class-option ,class :abstract))
+
+(defmacro class-method-invocation-order (class)
+  "Return the invocation order of CLASS.
+Abstract classes cannot be instantiated."
+  `(or (class-option ,class :method-invocation-order)
+       :breadth-first))
+
+\f
+;;; Defining a new class
+;;
+(defmacro defclass (name superclass slots &rest options-and-doc)
+  "Define NAME as a new class derived from SUPERCLASS with SLOTS.
+OPTIONS-AND-DOC is used as the class' options and base documentation.
+SUPERCLASS is a list of superclasses to inherit from, with SLOTS
+being the slots residing in that class definition.  NOTE: Currently
+only one slot may exist in SUPERCLASS as multiple inheritance is not
+yet supported.  Supported tags are:
+
+  :initform   - Initializing form.
+  :initarg    - Tag used during initialization.
+  :accessor   - Tag used to create a function to access this slot.
+  :allocation - Specify where the value is stored.
+                Defaults to `:instance', but could also be `:class'.
+  :writer     - A function symbol which will `write' an object's slot.
+  :reader     - A function symbol which will `read' an object.
+  :type       - The type of data allowed in this slot (see `typep').
+  :documentation
+              - A string documenting use of this slot.
+
+The following are extensions on CLOS:
+  :protection - Specify protection for this slot.
+                Defaults to `:public'.  Also use `:protected', or `:private'.
+  :custom     - When customizing an object, the custom :type.  Public only.
+  :label      - A text string label used for a slot when customizing.
+  :group      - Name of a customization group this slot belongs in.
+  :printer    - A function to call to print the value of a slot.
+                See `eieio-override-prin1' as an example.
+
+A class can also have optional options.  These options happen in place
+of documentation (including a :documentation tag), in addition to
+documentation, or not at all.  Supported options are:
+
+  :documentation - The doc-string used for this class.
+
+Options added to EIEIO:
+
+  :allow-nil-initform - Non-nil to skip typechecking of null initforms.
+  :custom-groups      - List of custom group names.  Organizes slots into
+                        reasonable groups for customizations.
+  :abstract           - Non-nil to prevent instances of this class.
+                        If a string, use as an error string if someone does
+                        try to make an instance.
+  :method-invocation-order
+                      - Control the method invocation order if there is
+                        multiple inheritance.  Valid values are:
+                         :breadth-first - The default.
+                         :depth-first
+
+Options in CLOS not supported in EIEIO:
+
+  :metaclass - Class to use in place of `standard-class'
+  :default-initargs - Initargs to use when initializing new objects of
+                      this class.
+
+Due to the way class options are set up, you can add any tags you wish,
+and reference them using the function `class-option'."
+  ;; We must `eval-and-compile' this so that when we byte compile
+  ;; an eieio program, there is no need to load it ahead of time.
+  ;; It also provides lots of nice debugging errors at compile time.
+  `(eval-and-compile
+     (eieio-defclass ',name ',superclass ',slots ',options-and-doc)))
+
+(defvar eieio-defclass-autoload-map (make-vector 7 nil)
+  "Symbol map of superclasses we find in autoloads.")
+
+;; We autoload this because it's used in `make-autoload'.
+;;;###autoload
+(defun eieio-defclass-autoload (cname superclasses filename doc)
+  "Create autoload symbols for the EIEIO class CNAME.
+SUPERCLASSES are the superclasses that CNAME inherits from.
+DOC is the docstring for CNAME.
+This function creates a mock-class for CNAME and adds it into
+SUPERCLASSES as children.
+It creates an autoload function for CNAME's constructor."
+  ;; Assume we've already debugged inputs.
+
+  (let* ((oldc (when (class-p cname) (class-v cname)))
+        (newc (make-vector class-num-slots nil))
+        )
+    (if oldc
+       nil ;; Do nothing if we already have this class.
+
+      ;; Create the class in NEWC, but don't fill anything else in.
+      (aset newc 0 'defclass)
+      (aset newc class-symbol cname)
+
+      (let ((clear-parent nil))
+       ;; No parents?
+       (when (not superclasses)
+         (setq superclasses '(eieio-default-superclass)
+               clear-parent t)
+         )
+
+       ;; Hook our new class into the existing structures so we can
+       ;; autoload it later.
+       (dolist (SC superclasses)
+
+
+         ;; TODO - If we create an autoload that is in the map, that
+         ;;        map needs to be cleared!
+
+
+         ;; Does our parent exist?
+         (if (not (class-p SC))
+
+             ;; Create a symbol for this parent, and then store this
+             ;; parent on that symbol.
+             (let ((sym (intern (symbol-name SC) eieio-defclass-autoload-map)))
+               (if (not (boundp sym))
+                   (set sym (list cname))
+                 (add-to-list sym cname))
+               )
+
+           ;; We have a parent, save the child in there.
+           (when (not (member cname (aref (class-v SC) class-children)))
+             (aset (class-v SC) class-children
+                   (cons cname (aref (class-v SC) class-children)))))
+
+         ;; save parent in child
+         (aset newc class-parent (cons SC (aref newc class-parent)))
+         )
+
+       ;; turn this into a useable self-pointing symbol
+       (set cname cname)
+
+       ;; Store the new class vector definition into the symbol.  We need to
+       ;; do this first so that we can call defmethod for the accessor.
+       ;; The vector will be updated by the following while loop and will not
+       ;; need to be stored a second time.
+       (put cname 'eieio-class-definition newc)
+
+       ;; Clear the parent
+       (if clear-parent (aset newc class-parent nil))
+
+       ;; Create an autoload on top of our constructor function.
+       (autoload cname filename doc nil nil)
+       (autoload (intern (concat (symbol-name cname) "-p")) filename "" nil nil)
+       (autoload (intern (concat (symbol-name cname) "-child-p")) filename "" nil nil)
+
+       ))))
+
+(defsubst eieio-class-un-autoload (cname)
+  "If class CNAME is in an autoload state, load its file."
+  (when (eq (car-safe (symbol-function cname)) 'autoload)
+    (load-library (car (cdr (symbol-function cname))))))
+
+(defun eieio-defclass (cname superclasses slots options-and-doc)
+  ;; FIXME: Most of this should be moved to the `defclass' macro.
+  "Define CNAME as a new subclass of SUPERCLASSES.
+SLOTS are the slots residing in that class definition, and options or
+documentation OPTIONS-AND-DOC is the toplevel documentation for this class.
+See `defclass' for more information."
+  ;; Run our eieio-hook each time, and clear it when we are done.
+  ;; This way people can add hooks safely if they want to modify eieio
+  ;; or add definitions when eieio is loaded or something like that.
+  (run-hooks 'eieio-hook)
+  (setq eieio-hook nil)
+
+  (if (not (symbolp cname)) (signal 'wrong-type-argument '(symbolp cname)))
+  (if (not (listp superclasses)) (signal 'wrong-type-argument '(listp superclasses)))
+
+  (let* ((pname (if superclasses superclasses nil))
+        (newc (make-vector class-num-slots nil))
+        (oldc (when (class-p cname) (class-v cname)))
+        (groups nil) ;; list of groups id'd from slots
+        (options nil)
+        (clearparent nil))
+
+    (aset newc 0 'defclass)
+    (aset newc class-symbol cname)
+
+    ;; If this class already existed, and we are updating its structure,
+    ;; make sure we keep the old child list.  This can cause bugs, but
+    ;; if no new slots are created, it also saves time, and prevents
+    ;; method table breakage, particularly when the users is only
+    ;; byte compiling an EIEIO file.
+    (if oldc
+       (aset newc class-children (aref oldc class-children))
+      ;; If the old class did not exist, but did exist in the autoload map, then adopt those children.
+      ;; This is like the above, but deals with autoloads nicely.
+      (let ((sym (intern-soft (symbol-name cname) eieio-defclass-autoload-map)))
+       (when sym
+         (condition-case nil
+             (aset newc class-children (symbol-value sym))
+           (error nil))
+         (unintern (symbol-name cname) eieio-defclass-autoload-map)
+         ))
+      )
+
+    (cond ((and (stringp (car options-and-doc))
+               (/= 1 (% (length options-and-doc) 2)))
+          (error "Too many arguments to `defclass'"))
+         ((and (symbolp (car options-and-doc))
+               (/= 0 (% (length options-and-doc) 2)))
+          (error "Too many arguments to `defclass'"))
+         )
+
+    (setq options
+         (if (stringp (car options-and-doc))
+             (cons :documentation options-and-doc)
+           options-and-doc))
+
+    (if pname
+       (progn
+         (while pname
+           (if (and (car pname) (symbolp (car pname)))
+               (if (not (class-p (car pname)))
+                   ;; bad class
+                   (error "Given parent class %s is not a class" (car pname))
+                 ;; good parent class...
+                 ;; save new child in parent
+                 (when (not (member cname (aref (class-v (car pname)) class-children)))
+                   (aset (class-v (car pname)) class-children
+                         (cons cname (aref (class-v (car pname)) class-children))))
+                 ;; Get custom groups, and store them into our local copy.
+                 (mapc (lambda (g) (add-to-list 'groups g))
+                       (class-option (car pname) :custom-groups))
+                 ;; save parent in child
+                 (aset newc class-parent (cons (car pname) (aref newc class-parent))))
+             (error "Invalid parent class %s" pname))
+           (setq pname (cdr pname)))
+         ;; Reverse the list of our parents so that they are prioritized in
+         ;; the same order as specified in the code.
+         (aset newc class-parent (nreverse (aref newc class-parent))) )
+      ;; If there is nothing to loop over, then inherit from the
+      ;; default superclass.
+      (unless (eq cname 'eieio-default-superclass)
+       ;; adopt the default parent here, but clear it later...
+       (setq clearparent t)
+       ;; save new child in parent
+       (if (not (member cname (aref (class-v 'eieio-default-superclass) class-children)))
+           (aset (class-v 'eieio-default-superclass) class-children
+                 (cons cname (aref (class-v 'eieio-default-superclass) class-children))))
+       ;; save parent in child
+       (aset newc class-parent (list eieio-default-superclass))))
+
+    ;; turn this into a useable self-pointing symbol
+    (set cname cname)
+
+    ;; These two tests must be created right away so we can have self-
+    ;; referencing classes.  ei, a class whose slot can contain only
+    ;; pointers to itself.
+
+    ;; Create the test function
+    (let ((csym (intern (concat (symbol-name cname) "-p"))))
+      (fset csym
+           (list 'lambda (list 'obj)
+                 (format "Test OBJ to see if it an object of type %s" cname)
+                 (list 'and '(eieio-object-p obj)
+                       (list 'same-class-p 'obj cname)))))
+
+    ;; Make sure the method invocation order  is a valid value.
+    (let ((io (class-option-assoc options :method-invocation-order)))
+      (when (and io (not (member io '(:depth-first :breadth-first :c3))))
+       (error "Method invocation order %s is not allowed" io)
+       ))
+
+    ;; Create a handy child test too
+    (let ((csym (intern (concat (symbol-name cname) "-child-p"))))
+      (fset csym
+           `(lambda (obj)
+              ,(format
+                 "Test OBJ to see if it an object is a child of type %s"
+                 cname)
+              (and (eieio-object-p obj)
+                   (object-of-class-p obj ,cname))))
+
+      ;; When using typep, (typep OBJ 'myclass) returns t for objects which
+      ;; are subclasses of myclass.  For our predicates, however, it is
+      ;; important for EIEIO to be backwards compatible, where
+      ;; myobject-p, and myobject-child-p are different.
+      ;; "cl" uses this technique to specify symbols with specific typep
+      ;; test, so we can let typep have the CLOS documented behavior
+      ;; while keeping our above predicate clean.
+
+      ;; It would be cleaner to use `defsetf' here, but that requires cl
+      ;; at runtime.
+      (put cname 'cl-deftype-handler
+          (list 'lambda () `(list 'satisfies (quote ,csym)))))
+
+    ;; before adding new slots, lets add all the methods and classes
+    ;; in from the parent class
+    (eieio-copy-parents-into-subclass newc superclasses)
+
+    ;; Store the new class vector definition into the symbol.  We need to
+    ;; do this first so that we can call defmethod for the accessor.
+    ;; The vector will be updated by the following while loop and will not
+    ;; need to be stored a second time.
+    (put cname 'eieio-class-definition newc)
+
+    ;; Query each slot in the declaration list and mangle into the
+    ;; class structure I have defined.
+    (while slots
+      (let* ((slot1  (car slots))
+            (name    (car slot1))
+            (slot   (cdr slot1))
+            (acces   (plist-get slot ':accessor))
+            (init    (or (plist-get slot ':initform)
+                         (if (member ':initform slot) nil
+                           eieio-unbound)))
+            (initarg (plist-get slot ':initarg))
+            (docstr  (plist-get slot ':documentation))
+            (prot    (plist-get slot ':protection))
+            (reader  (plist-get slot ':reader))
+            (writer  (plist-get slot ':writer))
+            (alloc   (plist-get slot ':allocation))
+            (type    (plist-get slot ':type))
+            (custom  (plist-get slot ':custom))
+            (label   (plist-get slot ':label))
+            (customg (plist-get slot ':group))
+            (printer (plist-get slot ':printer))
+
+            (skip-nil (class-option-assoc options :allow-nil-initform))
+            )
+
+       (if eieio-error-unsupported-class-tags
+           (let ((tmp slot))
+             (while tmp
+               (if (not (member (car tmp) '(:accessor
+                                            :initform
+                                            :initarg
+                                            :documentation
+                                            :protection
+                                            :reader
+                                            :writer
+                                            :allocation
+                                            :type
+                                            :custom
+                                            :label
+                                            :group
+                                            :printer
+                                            :allow-nil-initform
+                                            :custom-groups)))
+                   (signal 'invalid-slot-type (list (car tmp))))
+               (setq tmp (cdr (cdr tmp))))))
+
+       ;; Clean up the meaning of protection.
+       (cond ((or (eq prot 'public) (eq prot :public)) (setq prot nil))
+             ((or (eq prot 'protected) (eq prot :protected)) (setq prot 'protected))
+             ((or (eq prot 'private) (eq prot :private)) (setq prot 'private))
+             ((eq prot nil) nil)
+             (t (signal 'invalid-slot-type (list ':protection prot))))
+
+       ;; Make sure the :allocation parameter has a valid value.
+       (if (not (or (not alloc) (eq alloc :class) (eq alloc :instance)))
+           (signal 'invalid-slot-type (list ':allocation alloc)))
+
+       ;; The default type specifier is supposed to be t, meaning anything.
+       (if (not type) (setq type t))
+
+       ;; Label is nil, or a string
+       (if (not (or (null label) (stringp label)))
+           (signal 'invalid-slot-type (list ':label label)))
+
+       ;; Is there an initarg, but allocation of class?
+       (if (and initarg (eq alloc :class))
+           (message "Class allocated slots do not need :initarg"))
+
+       ;; intern the symbol so we can use it blankly
+       (if initarg (set initarg initarg))
+
+       ;; The customgroup should be a list of symbols
+       (cond ((null customg)
+              (setq customg '(default)))
+             ((not (listp customg))
+              (setq customg (list customg))))
+       ;; The customgroup better be a symbol, or list of symbols.
+       (mapc (lambda (cg)
+               (if (not (symbolp cg))
+                   (signal 'invalid-slot-type (list ':group cg))))
+               customg)
+
+       ;; First up, add this slot into our new class.
+       (eieio-add-new-slot newc name init docstr type custom label customg printer
+                            prot initarg alloc 'defaultoverride skip-nil)
+
+       ;; We need to id the group, and store them in a group list attribute.
+       (mapc (lambda (cg) (add-to-list 'groups cg)) customg)
+
+       ;; anyone can have an accessor function.  This creates a function
+       ;; of the specified name, and also performs a `defsetf' if applicable
+       ;; so that users can `setf' the space returned by this function
+       (if acces
+           (progn
+             (eieio--defmethod
+               acces (if (eq alloc :class) :static :primary) cname
+               `(lambda (this)
+                  ,(format
+                      "Retrieves the slot `%s' from an object of class `%s'"
+                      name cname)
+                  (if (slot-boundp this ',name)
+                      (eieio-oref this ',name)
+                           ;; Else - Some error?  nil?
+                           nil)))
+
+             ;; Provide a setf method.  It would be cleaner to use
+             ;; defsetf, but that would require CL at runtime.
+             (put acces 'setf-method
+                  `(lambda (widget)
+                     (let* ((--widget-sym-- (make-symbol "--widget--"))
+                            (--store-sym-- (make-symbol "--store--")))
+                       (list
+                        (list --widget-sym--)
+                        (list widget)
+                        (list --store-sym--)
+                        (list 'eieio-oset --widget-sym-- '',name --store-sym--)
+                        (list 'getfoo --widget-sym--)))))))
+
+       ;; If a writer is defined, then create a generic method of that
+       ;; name whose purpose is to set the value of the slot.
+       (if writer
+            (eieio--defmethod
+             writer nil cname
+             `(lambda (this value)
+                ,(format "Set the slot `%s' of an object of class `%s'"
+                             name cname)
+                (setf (slot-value this ',name) value))))
+       ;; If a reader is defined, then create a generic method
+       ;; of that name whose purpose is to access this slot value.
+       (if reader
+            (eieio--defmethod
+             reader nil cname
+             `(lambda (this)
+                ,(format "Access the slot `%s' from object of class `%s'"
+                             name cname)
+                (slot-value this ',name))))
+       )
+      (setq slots (cdr slots)))
+
+    ;; Now that everything has been loaded up, all our lists are backwards!  Fix that up now.
+    (aset newc class-public-a (nreverse (aref newc class-public-a)))
+    (aset newc class-public-d (nreverse (aref newc class-public-d)))
+    (aset newc class-public-doc (nreverse (aref newc class-public-doc)))
+    (aset newc class-public-type
+         (apply 'vector (nreverse (aref newc class-public-type))))
+    (aset newc class-public-custom (nreverse (aref newc class-public-custom)))
+    (aset newc class-public-custom-label (nreverse (aref newc class-public-custom-label)))
+    (aset newc class-public-custom-group (nreverse (aref newc class-public-custom-group)))
+    (aset newc class-public-printer (nreverse (aref newc class-public-printer)))
+    (aset newc class-protection (nreverse (aref newc class-protection)))
+    (aset newc class-initarg-tuples (nreverse (aref newc class-initarg-tuples)))
+
+    ;; The storage for class-class-allocation-type needs to be turned into
+    ;; a vector now.
+    (aset newc class-class-allocation-type
+         (apply 'vector (aref newc class-class-allocation-type)))
+
+    ;; Also, take class allocated values, and vectorize them for speed.
+    (aset newc class-class-allocation-values
+         (apply 'vector (aref newc class-class-allocation-values)))
+
+    ;; Attach slot symbols into an obarray, and store the index of
+    ;; this slot as the variable slot in this new symbol.  We need to
+    ;; know about primes, because obarrays are best set in vectors of
+    ;; prime number length, and we also need to make our vector small
+    ;; to save space, and also optimal for the number of items we have.
+    (let* ((cnt 0)
+          (pubsyms (aref newc class-public-a))
+          (prots (aref newc class-protection))
+          (l (length pubsyms))
+          (vl (let ((primes '( 3 5 7 11 13 17 19 23 29 31 37 41 43 47
+                                 53 59 61 67 71 73 79 83 89 97 101 )))
+                (while (and primes (< (car primes) l))
+                  (setq primes (cdr primes)))
+                (car primes)))
+          (oa (make-vector vl 0))
+          (newsym))
+      (while pubsyms
+       (setq newsym (intern (symbol-name (car pubsyms)) oa))
+       (set newsym cnt)
+       (setq cnt (1+ cnt))
+       (if (car prots) (put newsym 'protection (car prots)))
+       (setq pubsyms (cdr pubsyms)
+             prots (cdr prots)))
+      (aset newc class-symbol-obarray oa)
+      )
+
+    ;; Create the constructor function
+    (if (class-option-assoc options :abstract)
+       ;; Abstract classes cannot be instantiated.  Say so.
+       (let ((abs (class-option-assoc options :abstract)))
+         (if (not (stringp abs))
+             (setq abs (format "Class %s is abstract" cname)))
+         (fset cname
+               `(lambda (&rest stuff)
+                  ,(format "You cannot create a new object of type %s" cname)
+                  (error ,abs))))
+
+      ;; Non-abstract classes need a constructor.
+      (fset cname
+           `(lambda (newname &rest slots)
+              ,(format "Create a new object with name NAME of class type %s" cname)
+              (apply 'constructor ,cname newname slots)))
+      )
+
+    ;; Set up a specialized doc string.
+    ;; Use stored value since it is calculated in a non-trivial way
+    (put cname 'variable-documentation
+        (class-option-assoc options :documentation))
+
+    ;; We have a list of custom groups.  Store them into the options.
+    (let ((g (class-option-assoc options :custom-groups)))
+      (mapc (lambda (cg) (add-to-list 'g cg)) groups)
+      (if (memq :custom-groups options)
+         (setcar (cdr (memq :custom-groups options)) g)
+       (setq options (cons :custom-groups (cons g options)))))
+
+    ;; Set up the options we have collected.
+    (aset newc class-options options)
+
+    ;; if this is a superclass, clear out parent (which was set to the
+    ;; default superclass eieio-default-superclass)
+    (if clearparent (aset newc class-parent nil))
+
+    ;; Create the cached default object.
+    (let ((cache (make-vector (+ (length (aref newc class-public-a))
+                                3) nil)))
+      (aset cache 0 'object)
+      (aset cache object-class cname)
+      (aset cache object-name 'default-cache-object)
+      (let ((eieio-skip-typecheck t))
+       ;; All type-checking has been done to our satisfaction
+       ;; before this call.  Don't waste our time in this call..
+       (eieio-set-defaults cache t))
+      (aset newc class-default-object-cache cache))
+
+    ;; Return our new class object
+    ;; newc
+    cname
+    ))
+
+(defun eieio-perform-slot-validation-for-default (slot spec value skipnil)
+  "For SLOT, signal if SPEC does not match VALUE.
+If SKIPNIL is non-nil, then if VALUE is nil return t instead."
+  (if (and (not (eieio-eval-default-p value))
+          (not eieio-skip-typecheck)
+          (not (and skipnil (null value)))
+          (not (eieio-perform-slot-validation spec value)))
+      (signal 'invalid-slot-type (list slot spec value))))
+
+(defun eieio-add-new-slot (newc a d doc type cust label custg print prot init alloc
+                                &optional defaultoverride skipnil)
+  "Add into NEWC attribute A.
+If A already exists in NEWC, then do nothing.  If it doesn't exist,
+then also add in D (default), DOC, TYPE, CUST, LABEL, CUSTG, PRINT, PROT, and INIT arg.
+Argument ALLOC specifies if the slot is allocated per instance, or per class.
+If optional DEFAULTOVERRIDE is non-nil, then if A exists in NEWC,
+we must override its value for a default.
+Optional argument SKIPNIL indicates if type checking should be skipped
+if default value is nil."
+  ;; Make sure we duplicate those items that are sequences.
+  (condition-case nil
+      (if (sequencep d) (setq d (copy-sequence d)))
+    ;; This copy can fail on a cons cell with a non-cons in the cdr.  Lets skip it if it doesn't work.
+    (error nil))
+  (if (sequencep type) (setq type (copy-sequence type)))
+  (if (sequencep cust) (setq cust (copy-sequence cust)))
+  (if (sequencep custg) (setq custg (copy-sequence custg)))
+
+  ;; To prevent override information w/out specification of storage,
+  ;; we need to do this little hack.
+  (if (member a (aref newc class-class-allocation-a)) (setq alloc ':class))
+
+  (if (or (not alloc) (and (symbolp alloc) (eq alloc ':instance)))
+      ;; In this case, we modify the INSTANCE version of a given slot.
+
+      (progn
+
+       ;; Only add this element if it is so-far unique
+       (if (not (member a (aref newc class-public-a)))
+           (progn
+             (eieio-perform-slot-validation-for-default a type d skipnil)
+             (aset newc class-public-a (cons a (aref newc class-public-a)))
+             (aset newc class-public-d (cons d (aref newc class-public-d)))
+             (aset newc class-public-doc (cons doc (aref newc class-public-doc)))
+             (aset newc class-public-type (cons type (aref newc class-public-type)))
+             (aset newc class-public-custom (cons cust (aref newc class-public-custom)))
+             (aset newc class-public-custom-label (cons label (aref newc class-public-custom-label)))
+             (aset newc class-public-custom-group (cons custg (aref newc class-public-custom-group)))
+             (aset newc class-public-printer (cons print (aref newc class-public-printer)))
+             (aset newc class-protection (cons prot (aref newc class-protection)))
+             (aset newc class-initarg-tuples (cons (cons init a) (aref newc class-initarg-tuples)))
+             )
+         ;; When defaultoverride is true, we are usually adding new local
+         ;; attributes which must override the default value of any slot
+         ;; passed in by one of the parent classes.
+         (when defaultoverride
+           ;; There is a match, and we must override the old value.
+           (let* ((ca (aref newc class-public-a))
+                  (np (member a ca))
+                  (num (- (length ca) (length np)))
+                  (dp (if np (nthcdr num (aref newc class-public-d))
+                        nil))
+                  (tp (if np (nth num (aref newc class-public-type))))
+                  )
+             (if (not np)
+                 (error "EIEIO internal error overriding default value for %s"
+                        a)
+               ;; If type is passed in, is it the same?
+               (if (not (eq type t))
+                   (if (not (equal type tp))
+                       (error
+                        "Child slot type `%s' does not match inherited type `%s' for `%s'"
+                        type tp a)))
+               ;; If we have a repeat, only update the initarg...
+               (unless (eq d eieio-unbound)
+                 (eieio-perform-slot-validation-for-default a tp d skipnil)
+                 (setcar dp d))
+               ;; If we have a new initarg, check for it.
+               (when init
+                 (let* ((inits (aref newc class-initarg-tuples))
+                        (inita (rassq a inits)))
+                   ;; Replace the CAR of the associate INITA.
+                   ;;(message "Initarg: %S replace %s" inita init)
+                   (setcar inita init)
+                   ))
+
+               ;; PLN Tue Jun 26 11:57:06 2007 : The protection is
+               ;; checked and SHOULD match the superclass
+               ;; protection. Otherwise an error is thrown. However
+               ;; I wonder if a more flexible schedule might be
+               ;; implemented.
+               ;;
+               ;; EML - We used to have (if prot... here,
+               ;;       but a prot of 'nil means public.
+               ;;
+               (let ((super-prot (nth num (aref newc class-protection)))
+                     )
+                 (if (not (eq prot super-prot))
+                     (error "Child slot protection `%s' does not match inherited protection `%s' for `%s'"
+                            prot super-prot a)))
+               ;; End original PLN
+
+               ;; PLN Tue Jun 26 11:57:06 2007 :
+               ;; Do a non redundant combination of ancient custom
+               ;; groups and new ones.
+               (when custg
+                 (let* ((groups
+                         (nthcdr num (aref newc class-public-custom-group)))
+                        (list1 (car groups))
+                        (list2 (if (listp custg) custg (list custg))))
+                   (if (< (length list1) (length list2))
+                       (setq list1 (prog1 list2 (setq list2 list1))))
+                   (dolist (elt list2)
+                     (unless (memq elt list1)
+                       (push elt list1)))
+                   (setcar groups list1)))
+               ;;  End PLN
+
+               ;;  PLN Mon Jun 25 22:44:34 2007 : If a new cust is
+               ;;  set, simply replaces the old one.
+               (when cust
+                 ;; (message "Custom type redefined to %s" cust)
+                 (setcar (nthcdr num (aref newc class-public-custom)) cust))
+
+               ;; If a new label is specified, it simply replaces
+               ;; the old one.
+               (when label
+                 ;; (message "Custom label redefined to %s" label)
+                 (setcar (nthcdr num (aref newc class-public-custom-label)) label))
+               ;;  End PLN
+
+               ;; PLN Sat Jun 30 17:24:42 2007 : when a new
+               ;; doc is specified, simply replaces the old one.
+               (when doc
+                 ;;(message "Documentation redefined to %s" doc)
+                 (setcar (nthcdr num (aref newc class-public-doc))
+                         doc))
+               ;; End PLN
+
+               ;; If a new printer is specified, it simply replaces
+               ;; the old one.
+               (when print
+                 ;; (message "printer redefined to %s" print)
+                 (setcar (nthcdr num (aref newc class-public-printer)) print))
+
+               )))
+         ))
+
+    ;; CLASS ALLOCATED SLOTS
+    (let ((value (eieio-default-eval-maybe d)))
+      (if (not (member a (aref newc class-class-allocation-a)))
+         (progn
+           (eieio-perform-slot-validation-for-default a type value skipnil)
+           ;; Here we have found a :class version of a slot.  This
+           ;; requires a very different aproach.
+           (aset newc class-class-allocation-a (cons a (aref newc class-class-allocation-a)))
+           (aset newc class-class-allocation-doc (cons doc (aref newc class-class-allocation-doc)))
+           (aset newc class-class-allocation-type (cons type (aref newc class-class-allocation-type)))
+           (aset newc class-class-allocation-custom (cons cust (aref newc class-class-allocation-custom)))
+           (aset newc class-class-allocation-custom-label (cons label (aref newc class-class-allocation-custom-label)))
+           (aset newc class-class-allocation-custom-group (cons custg (aref newc class-class-allocation-custom-group)))
+           (aset newc class-class-allocation-protection (cons prot (aref newc class-class-allocation-protection)))
+           ;; Default value is stored in the 'values section, since new objects
+           ;; can't initialize from this element.
+           (aset newc class-class-allocation-values (cons value (aref newc class-class-allocation-values))))
+       (when defaultoverride
+         ;; There is a match, and we must override the old value.
+         (let* ((ca (aref newc class-class-allocation-a))
+                (np (member a ca))
+                (num (- (length ca) (length np)))
+                (dp (if np
+                        (nthcdr num
+                                (aref newc class-class-allocation-values))
+                      nil))
+                (tp (if np (nth num (aref newc class-class-allocation-type))
+                      nil)))
+           (if (not np)
+               (error "EIEIO internal error overriding default value for %s"
+                      a)
+             ;; If type is passed in, is it the same?
+             (if (not (eq type t))
+                 (if (not (equal type tp))
+                     (error
+                      "Child slot type `%s' does not match inherited type `%s' for `%s'"
+                      type tp a)))
+             ;; EML - Note: the only reason to override a class bound slot
+             ;;       is to change the default, so allow unbound in.
+
+             ;; If we have a repeat, only update the vlaue...
+             (eieio-perform-slot-validation-for-default a tp value skipnil)
+             (setcar dp value))
+
+           ;; PLN Tue Jun 26 11:57:06 2007 : The protection is
+           ;; checked and SHOULD match the superclass
+           ;; protection. Otherwise an error is thrown. However
+           ;; I wonder if a more flexible schedule might be
+           ;; implemented.
+           (let ((super-prot
+                  (car (nthcdr num (aref newc class-class-allocation-protection)))))
+             (if (not (eq prot super-prot))
+                 (error "Child slot protection `%s' does not match inherited protection `%s' for `%s'"
+                        prot super-prot a)))
+           ;; Do a non redundant combination of ancient custom groups
+           ;; and new ones.
+           (when custg
+             (let* ((groups
+                     (nthcdr num (aref newc class-class-allocation-custom-group)))
+                    (list1 (car groups))
+                    (list2 (if (listp custg) custg (list custg))))
+               (if (< (length list1) (length list2))
+                   (setq list1 (prog1 list2 (setq list2 list1))))
+               (dolist (elt list2)
+                 (unless (memq elt list1)
+                   (push elt list1)))
+               (setcar groups list1)))
+
+           ;; PLN Sat Jun 30 17:24:42 2007 : when a new
+           ;; doc is specified, simply replaces the old one.
+           (when doc
+             ;;(message "Documentation redefined to %s" doc)
+             (setcar (nthcdr num (aref newc class-class-allocation-doc))
+                     doc))
+           ;; End PLN
+
+           ;; If a new printer is specified, it simply replaces
+           ;; the old one.
+           (when print
+             ;; (message "printer redefined to %s" print)
+             (setcar (nthcdr num (aref newc class-class-allocation-printer)) print))
+
+           ))
+       ))
+    ))
+
+(defun eieio-copy-parents-into-subclass (newc parents)
+  "Copy into NEWC the slots of PARENTS.
+Follow the rules of not overwriting early parents when applying to
+the new child class."
+  (let ((ps (aref newc class-parent))
+       (sn (class-option-assoc (aref newc class-options)
+                               ':allow-nil-initform)))
+    (while ps
+      ;; First, duplicate all the slots of the parent.
+      (let ((pcv (class-v (car ps))))
+       (let ((pa (aref pcv class-public-a))
+             (pd (aref pcv class-public-d))
+             (pdoc (aref pcv class-public-doc))
+             (ptype (aref pcv class-public-type))
+             (pcust (aref pcv class-public-custom))
+             (plabel (aref pcv class-public-custom-label))
+             (pcustg (aref pcv class-public-custom-group))
+             (printer (aref pcv class-public-printer))
+             (pprot (aref pcv class-protection))
+             (pinit (aref pcv class-initarg-tuples))
+             (i 0))
+         (while pa
+           (eieio-add-new-slot newc
+                                (car pa) (car pd) (car pdoc) (aref ptype i)
+                                (car pcust) (car plabel) (car pcustg)
+                                (car printer)
+                                (car pprot) (car-safe (car pinit)) nil nil sn)
+           ;; Increment each value.
+           (setq pa (cdr pa)
+                 pd (cdr pd)
+                 pdoc (cdr pdoc)
+                 i (1+ i)
+                 pcust (cdr pcust)
+                 plabel (cdr plabel)
+                 pcustg (cdr pcustg)
+                 printer (cdr printer)
+                 pprot (cdr pprot)
+                 pinit (cdr pinit))
+           )) ;; while/let
+       ;; Now duplicate all the class alloc slots.
+       (let ((pa (aref pcv class-class-allocation-a))
+             (pdoc (aref pcv class-class-allocation-doc))
+             (ptype (aref pcv class-class-allocation-type))
+             (pcust (aref pcv class-class-allocation-custom))
+             (plabel (aref pcv class-class-allocation-custom-label))
+             (pcustg (aref pcv class-class-allocation-custom-group))
+             (printer (aref pcv class-class-allocation-printer))
+             (pprot (aref pcv class-class-allocation-protection))
+             (pval (aref pcv class-class-allocation-values))
+             (i 0))
+         (while pa
+           (eieio-add-new-slot newc
+                                (car pa) (aref pval i) (car pdoc) (aref ptype i)
+                                (car pcust) (car plabel) (car pcustg)
+                                (car printer)
+                                (car pprot) nil ':class sn)
+           ;; Increment each value.
+           (setq pa (cdr pa)
+                 pdoc (cdr pdoc)
+                 pcust (cdr pcust)
+                 plabel (cdr plabel)
+                 pcustg (cdr pcustg)
+                 printer (cdr printer)
+                 pprot (cdr pprot)
+                 i (1+ i))
+           ))) ;; while/let
+      ;; Loop over each parent class
+      (setq ps (cdr ps)))
+    ))
+
+;;; CLOS style implementation of object creators.
+;;
+(defun make-instance (class &rest initargs)
+  "Make a new instance of CLASS based on INITARGS.
+CLASS is a class symbol.  For example:
+
+  (make-instance 'foo)
+
+  INITARGS is a property list with keywords based on the :initarg
+for each slot.  For example:
+
+  (make-instance 'foo :slot1 value1 :slotN valueN)
+
+Compatibility note:
+
+If the first element of INITARGS is a string, it is used as the
+name of the class.
+
+In EIEIO, the class' constructor requires a name for use when printing.
+`make-instance' in CLOS doesn't use names the way Emacs does, so the
+class is used as the name slot instead when INITARGS doesn't start with
+a string."
+  (if (and (car initargs) (stringp (car initargs)))
+      (apply (class-constructor class) initargs)
+    (apply  (class-constructor class)
+           (cond ((symbolp class) (symbol-name class))
+                 (t (format "%S" class)))
+           initargs)))
+
+\f
+;;; CLOS methods and generics
+;;
+
+(put 'eieio--defalias 'byte-hunk-handler
+     #'byte-compile-file-form-defalias) ;;(get 'defalias 'byte-hunk-handler)
+(defun eieio--defalias (name body)
+  "Like `defalias', but with less side-effects.
+More specifically, it has no side-effects at all when the new function
+definition is the same (`eq') as the old one."
+  (unless (and (fboundp name)
+               (eq (symbol-function name) body))
+    (defalias name body)))
+
+(defmacro defgeneric (method args &optional doc-string)
+  "Create a generic function METHOD.
+DOC-STRING is the base documentation for this class.  A generic
+function has no body, as its purpose is to decide which method body
+is appropriate to use.  Uses `defmethod' to create methods, and calls
+`defgeneric' for you.  With this implementation the ARGS are
+currently ignored.  You can use `defgeneric' to apply specialized
+top level documentation to a method."
+  `(eieio--defalias ',method
+                    (eieio--defgeneric-init-form ',method ,doc-string)))
+
+(defun eieio--defgeneric-init-form (method doc-string)
+  "Form to use for the initial definition of a generic."
+  (cond
+   ((or (not (fboundp method))
+        (eq 'autoload (car-safe (symbol-function method))))
+    ;; Make sure the method tables are installed.
+    (eieiomt-install method)
+    ;; Construct the actual body of this function.
+    (eieio-defgeneric-form method doc-string))
+   ((generic-p method) (symbol-function method))           ;Leave it as-is.
+   (t (error "You cannot create a generic/method over an existing symbol: %s"
+             method))))
+
+(defun eieio-defgeneric-form (method doc-string)
+  "The lambda form that would be used as the function defined on METHOD.
+All methods should call the same EIEIO function for dispatch.
+DOC-STRING is the documentation attached to METHOD."
+  `(lambda (&rest local-args)
+     ,doc-string
+     (eieio-generic-call (quote ,method) local-args)))
+
+(defsubst eieio-defgeneric-reset-generic-form (method)
+  "Setup METHOD to call the generic form."
+  (let ((doc-string (documentation method)))
+    (fset method (eieio-defgeneric-form method doc-string))))
+
+(defun eieio-defgeneric-form-primary-only (method doc-string)
+  "The lambda form that would be used as the function defined on METHOD.
+All methods should call the same EIEIO function for dispatch.
+DOC-STRING is the documentation attached to METHOD."
+  `(lambda (&rest local-args)
+     ,doc-string
+     (eieio-generic-call-primary-only (quote ,method) local-args)))
+
+(defsubst eieio-defgeneric-reset-generic-form-primary-only (method)
+  "Setup METHOD to call the generic form."
+  (let ((doc-string (documentation method)))
+    (fset method (eieio-defgeneric-form-primary-only method doc-string))))
+
+(defun eieio-defgeneric-form-primary-only-one (method doc-string
+                                                     class
+                                                     impl
+                                                     )
+  "The lambda form that would be used as the function defined on METHOD.
+All methods should call the same EIEIO function for dispatch.
+DOC-STRING is the documentation attached to METHOD.
+CLASS is the class symbol needed for private method access.
+IMPL is the symbol holding the method implementation."
+  ;; NOTE: I tried out byte compiling this little fcn.  Turns out it
+  ;; is faster to execute this for not byte-compiled.  ie, install this,
+  ;; then measure calls going through here.  I wonder why.
+  (require 'bytecomp)
+  (let ((byte-compile-warnings nil))
+    (byte-compile
+     `(lambda (&rest local-args)
+       ,doc-string
+       ;; This is a cool cheat.  Usually we need to look up in the
+       ;; method table to find out if there is a method or not.  We can
+       ;; instead make that determination at load time when there is
+       ;; only one method.  If the first arg is not a child of the class
+       ;; of that one implementation, then clearly, there is no method def.
+       (if (not (eieio-object-p (car local-args)))
+           ;; Not an object.  Just signal.
+           (signal 'no-method-definition
+                    (list ',method local-args))
+
+         ;; We do have an object.  Make sure it is the right type.
+         (if ,(if (eq class eieio-default-superclass)
+                  nil  ; default superclass means just an obj.  Already asked.
+                `(not (child-of-class-p (aref (car local-args) object-class)
+                                        ',class)))
+
+             ;; If not the right kind of object, call no applicable
+             (apply 'no-applicable-method (car local-args)
+                    ',method local-args)
+
+           ;; It is ok, do the call.
+           ;; Fill in inter-call variables then evaluate the method.
+           (let ((scoped-class ',class)
+                 (eieio-generic-call-next-method-list nil)
+                 (eieio-generic-call-key method-primary)
+                 (eieio-generic-call-methodname ',method)
+                 (eieio-generic-call-arglst local-args)
+                 )
+             (apply #',impl local-args)
+              ;;(,impl local-args)
+             )))))))
+
+(defsubst eieio-defgeneric-reset-generic-form-primary-only-one (method)
+  "Setup METHOD to call the generic form."
+  (let* ((doc-string (documentation method))
+        (M (get method 'eieio-method-tree))
+        (entry (car (aref M method-primary)))
+        )
+    (fset method (eieio-defgeneric-form-primary-only-one
+                 method doc-string
+                 (car entry)
+                 (cdr entry)
+                 ))))
+
+(defun eieio-unbind-method-implementations (method)
+  "Make the generic method METHOD have no implementations.
+It will leave the original generic function in place,
+but remove reference to all implementations of METHOD."
+  (put method 'eieio-method-tree nil)
+  (put method 'eieio-method-obarray nil))
+
+(defmacro defmethod (method &rest args)
+  "Create a new METHOD through `defgeneric' with ARGS.
+
+The optional second argument KEY is a specifier that
+modifies how the method is called, including:
+   :before  - Method will be called before the :primary
+   :primary - The default if not specified
+   :after   - Method will be called after the :primary
+   :static  - First arg could be an object or class
+The next argument is the ARGLIST.  The ARGLIST specifies the arguments
+to the method as with `defun'.  The first argument can have a type
+specifier, such as:
+  ((VARNAME CLASS) ARG2 ...)
+where VARNAME is the name of the local variable for the method being
+created.  The CLASS is a class symbol for a class made with `defclass'.
+A DOCSTRING comes after the ARGLIST, and is optional.
+All the rest of the args are the BODY of the method.  A method will
+return the value of the last form in the BODY.
+
+Summary:
+
+ (defmethod mymethod [:before | :primary | :after | :static]
+                     ((typearg class-name) arg2 &optional opt &rest rest)
+    \"doc-string\"
+     body)"
+  (let* ((key (if (keywordp (car args)) (pop args)))
+        (params (car args))
+        (arg1 (car params))
+         (fargs (if (consp arg1)
+                   (cons (car arg1) (cdr params))
+                 params))
+        (class (if (consp arg1) (nth 1 arg1)))
+         (code `(lambda ,fargs ,@(cdr args))))
+    `(progn
+       ;; Make sure there is a generic and the byte-compiler sees it.
+       (defgeneric ,method ,args
+         ,(or (documentation code)
+              (format "Generically created method `%s'." method)))
+       (eieio--defmethod ',method ',key ',class #',code))))
+
+(defun eieio--defmethod (method kind argclass code)
+  "Work part of the `defmethod' macro defining METHOD with ARGS."
+  (let ((key
+    ;; find optional keys
+         (cond ((or (eq ':BEFORE kind)
+                    (eq ':before kind))
+                method-before)
+               ((or (eq ':AFTER kind)
+                    (eq ':after kind))
+                method-after)
+               ((or (eq ':PRIMARY kind)
+                    (eq ':primary kind))
+                method-primary)
+               ((or (eq ':STATIC kind)
+                    (eq ':static kind))
+                method-static)
+               ;; Primary key
+               (t method-primary))))
+    ;; Make sure there is a generic (when called from defclass).
+    (eieio--defalias
+     method (eieio--defgeneric-init-form
+             method (or (documentation code)
+                        (format "Generically created method `%s'." method))))
+    ;; create symbol for property to bind to.  If the first arg is of
+    ;; the form (varname vartype) and `vartype' is a class, then
+    ;; that class will be the type symbol.  If not, then it will fall
+    ;; under the type `primary' which is a non-specific calling of the
+    ;; function.
+    (if argclass
+         (if (not (class-p argclass))
+             (error "Unknown class type %s in method parameters"
+                   argclass))
+      (if (= key -1)
+         (signal 'wrong-type-argument (list :static 'non-class-arg)))
+      ;; generics are higher
+      (setq key (eieio-specialized-key-to-generic-key key)))
+    ;; Put this lambda into the symbol so we can find it
+    (eieiomt-add method code key argclass)
+    )
+
+  (when eieio-optimize-primary-methods-flag
+    ;; Optimizing step:
+    ;;
+    ;; If this method, after this setup, only has primary methods, then
+    ;; we can setup the generic that way.
+    (if (generic-primary-only-p method)
+       ;; If there is only one primary method, then we can go one more
+       ;; optimization step.
+       (if (generic-primary-only-one-p method)
+           (eieio-defgeneric-reset-generic-form-primary-only-one method)
+         (eieio-defgeneric-reset-generic-form-primary-only method))
+      (eieio-defgeneric-reset-generic-form method)))
+
+  method)
+
+;;; Slot type validation
+
+;; This is a hideous hack for replacing `typep' from cl-macs, to avoid
+;; requiring the CL library at run-time.  It can be eliminated if/when
+;; `typep' is merged into Emacs core.
+(defun eieio--typep (val type)
+  (if (symbolp type)
+      (cond ((get type 'cl-deftype-handler)
+            (eieio--typep val (funcall (get type 'cl-deftype-handler))))
+           ((eq type t) t)
+           ((eq type 'null)   (null val))
+           ((eq type 'atom)   (atom val))
+           ((eq type 'float)  (and (numberp val) (not (integerp val))))
+           ((eq type 'real)   (numberp val))
+           ((eq type 'fixnum) (integerp val))
+           ((memq type '(character string-char)) (characterp val))
+           (t
+            (let* ((name (symbol-name type))
+                   (namep (intern (concat name "p"))))
+              (if (fboundp namep)
+                  (funcall `(lambda () (,namep val)))
+                (funcall `(lambda ()
+                            (,(intern (concat name "-p")) val)))))))
+    (cond ((get (car type) 'cl-deftype-handler)
+          (eieio--typep val (apply (get (car type) 'cl-deftype-handler)
+                                   (cdr type))))
+         ((memq (car type) '(integer float real number))
+          (and (eieio--typep val (car type))
+               (or (memq (cadr type) '(* nil))
+                   (if (consp (cadr type))
+                       (> val (car (cadr type)))
+                     (>= val (cadr type))))
+               (or (memq (caddr type) '(* nil))
+                   (if (consp (car (cddr type)))
+                       (< val (caar (cddr type)))
+                     (<= val (car (cddr type)))))))
+         ((memq (car type) '(and or not))
+          (eval (cons (car type)
+                      (mapcar (lambda (x)
+                                `(eieio--typep (quote ,val) (quote ,x)))
+                              (cdr type)))))
+         ((memq (car type) '(member member*))
+          (memql val (cdr type)))
+         ((eq (car type) 'satisfies)
+          (funcall `(lambda () (,(cadr type) val))))
+         (t (error "Bad type spec: %s" type)))))
+
+(defun eieio-perform-slot-validation (spec value)
+  "Return non-nil if SPEC does not match VALUE."
+  (or (eq spec t)                      ; t always passes
+      (eq value eieio-unbound)         ; unbound always passes
+      (eieio--typep value spec)))
+
+(defun eieio-validate-slot-value (class slot-idx value slot)
+  "Make sure that for CLASS referencing SLOT-IDX, VALUE is valid.
+Checks the :type specifier.
+SLOT is the slot that is being checked, and is only used when throwing
+an error."
+  (if eieio-skip-typecheck
+      nil
+    ;; Trim off object IDX junk added in for the object index.
+    (setq slot-idx (- slot-idx 3))
+    (let ((st (aref (aref (class-v class) class-public-type) slot-idx)))
+      (if (not (eieio-perform-slot-validation st value))
+         (signal 'invalid-slot-type (list class slot st value))))))
+
+(defun eieio-validate-class-slot-value (class slot-idx value slot)
+  "Make sure that for CLASS referencing SLOT-IDX, VALUE is valid.
+Checks the :type specifier.
+SLOT is the slot that is being checked, and is only used when throwing
+an error."
+  (if eieio-skip-typecheck
+      nil
+    (let ((st (aref (aref (class-v class) class-class-allocation-type)
+                   slot-idx)))
+      (if (not (eieio-perform-slot-validation st value))
+         (signal 'invalid-slot-type (list class slot st value))))))
+
+(defun eieio-barf-if-slot-unbound (value instance slotname fn)
+  "Throw a signal if VALUE is a representation of an UNBOUND slot.
+INSTANCE is the object being referenced.  SLOTNAME is the offending
+slot.  If the slot is ok, return VALUE.
+Argument FN is the function calling this verifier."
+  (if (and (eq value eieio-unbound) (not eieio-skip-typecheck))
+      (slot-unbound instance (object-class instance) slotname fn)
+    value))
+
+;;; Get/Set slots in an object.
+;;
+(defmacro oref (obj slot)
+  "Retrieve the value stored in OBJ in the slot named by SLOT.
+Slot is the name of the slot when created by `defclass' or the label
+created by the :initarg tag."
+  `(eieio-oref ,obj (quote ,slot)))
+
+(defun eieio-oref (obj slot)
+  "Return the value in OBJ at SLOT in the object vector."
+  (if (not (or (eieio-object-p obj) (class-p obj)))
+      (signal 'wrong-type-argument (list '(or eieio-object-p class-p) obj)))
+  (if (not (symbolp slot))
+      (signal 'wrong-type-argument (list 'symbolp slot)))
+  (if (class-p obj) (eieio-class-un-autoload obj))
+  (let* ((class (if (class-p obj) obj (aref obj object-class)))
+        (c (eieio-slot-name-index class obj slot)))
+    (if (not c)
+       ;; It might be missing because it is a :class allocated slot.
+       ;; Lets check that info out.
+       (if (setq c (eieio-class-slot-name-index class slot))
+           ;; Oref that slot.
+           (aref (aref (class-v class) class-class-allocation-values) c)
+         ;; The slot-missing method is a cool way of allowing an object author
+         ;; to intercept missing slot definitions.  Since it is also the LAST
+         ;; thing called in this fn, its return value would be retrieved.
+         (slot-missing obj slot 'oref)
+         ;;(signal 'invalid-slot-name (list (object-name obj) slot))
+         )
+      (if (not (eieio-object-p obj))
+         (signal 'wrong-type-argument (list 'eieio-object-p obj)))
+      (eieio-barf-if-slot-unbound (aref obj c) obj slot 'oref))))
+
+(defalias 'slot-value 'eieio-oref)
+(defalias 'set-slot-value 'eieio-oset)
+
+(defmacro oref-default (obj slot)
+  "Get the default value of OBJ (maybe a class) for SLOT.
+The default value is the value installed in a class with the :initform
+tag.  SLOT can be the slot name, or the tag specified by the :initarg
+tag in the `defclass' call."
+  `(eieio-oref-default ,obj (quote ,slot)))
+
+(defun eieio-oref-default (obj slot)
+  "Do the work for the macro `oref-default' with similar parameters.
+Fills in OBJ's SLOT with its default value."
+  (if (not (or (eieio-object-p obj) (class-p obj))) (signal 'wrong-type-argument (list 'eieio-object-p obj)))
+  (if (not (symbolp slot)) (signal 'wrong-type-argument (list 'symbolp slot)))
+  (let* ((cl (if (eieio-object-p obj) (aref obj object-class) obj))
+        (c (eieio-slot-name-index cl obj slot)))
+    (if (not c)
+       ;; It might be missing because it is a :class allocated slot.
+       ;; Lets check that info out.
+       (if (setq c
+                 (eieio-class-slot-name-index cl slot))
+           ;; Oref that slot.
+           (aref (aref (class-v cl) class-class-allocation-values)
+                 c)
+         (slot-missing obj slot 'oref-default)
+         ;;(signal 'invalid-slot-name (list (class-name cl) slot))
+         )
+      (eieio-barf-if-slot-unbound
+       (let ((val (nth (- c 3) (aref (class-v cl) class-public-d))))
+        (eieio-default-eval-maybe val))
+       obj cl 'oref-default))))
+
+(defsubst eieio-eval-default-p (val)
+  "Whether the default value VAL should be evaluated for use."
+  (and (consp val) (symbolp (car val)) (fboundp (car val))))
+
+(defun eieio-default-eval-maybe (val)
+  "Check VAL, and return what `oref-default' would provide."
+  (cond
+   ;; Is it a function call?  If so, evaluate it.
+   ((eieio-eval-default-p val)
+    (eval val))
+   ;;;; check for quoted things, and unquote them
+   ;;((and (consp val) (eq (car val) 'quote))
+   ;; (car (cdr val)))
+   ;; return it verbatim
+   (t val)))
+
+;;; Object Set macros
+;;
+(defmacro oset (obj slot value)
+  "Set the value in OBJ for slot SLOT to VALUE.
+SLOT is the slot name as specified in `defclass' or the tag created
+with in the :initarg slot.  VALUE can be any Lisp object."
+  `(eieio-oset ,obj (quote ,slot) ,value))
+
+(defun eieio-oset (obj slot value)
+  "Do the work for the macro `oset'.
+Fills in OBJ's SLOT with VALUE."
+  (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj)))
+  (if (not (symbolp slot)) (signal 'wrong-type-argument (list 'symbolp slot)))
+  (let ((c (eieio-slot-name-index (object-class-fast obj) obj slot)))
+    (if (not c)
+       ;; It might be missing because it is a :class allocated slot.
+       ;; Lets check that info out.
+       (if (setq c
+                 (eieio-class-slot-name-index (aref obj object-class) slot))
+           ;; Oset that slot.
+           (progn
+             (eieio-validate-class-slot-value (object-class-fast obj) c value slot)
+             (aset (aref (class-v (aref obj object-class))
+                         class-class-allocation-values)
+                   c value))
+         ;; See oref for comment on `slot-missing'
+         (slot-missing obj slot 'oset value)
+         ;;(signal 'invalid-slot-name (list (object-name obj) slot))
+         )
+      (eieio-validate-slot-value (object-class-fast obj) c value slot)
+      (aset obj c value))))
+
+(defmacro oset-default (class slot value)
+  "Set the default slot in CLASS for SLOT to VALUE.
+The default value is usually set with the :initform tag during class
+creation.  This allows users to change the default behavior of classes
+after they are created."
+  `(eieio-oset-default ,class (quote ,slot) ,value))
+
+(defun eieio-oset-default (class slot value)
+  "Do the work for the macro `oset-default'.
+Fills in the default value in CLASS' in SLOT with VALUE."
+  (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class)))
+  (if (not (symbolp slot)) (signal 'wrong-type-argument (list 'symbolp slot)))
+  (let* ((scoped-class class)
+        (c (eieio-slot-name-index class nil slot)))
+    (if (not c)
+       ;; It might be missing because it is a :class allocated slot.
+       ;; Lets check that info out.
+       (if (setq c (eieio-class-slot-name-index class slot))
+           (progn
+             ;; Oref that slot.
+             (eieio-validate-class-slot-value class c value slot)
+             (aset (aref (class-v class) class-class-allocation-values) c
+                   value))
+         (signal 'invalid-slot-name (list (class-name class) slot)))
+      (eieio-validate-slot-value class c value slot)
+      ;; Set this into the storage for defaults.
+      (setcar (nthcdr (- c 3) (aref (class-v class) class-public-d))
+             value)
+      ;; Take the value, and put it into our cache object.
+      (eieio-oset (aref (class-v class) class-default-object-cache)
+                 slot value)
+      )))
+
+;;; Handy CLOS macros
+;;
+(defmacro with-slots (spec-list object &rest body)
+  "Bind SPEC-LIST lexically to slot values in OBJECT, and execute BODY.
+This establishes a lexical environment for referring to the slots in
+the instance named by the given slot-names as though they were
+variables.  Within such a context the value of the slot can be
+specified by using its slot name, as if it were a lexically bound
+variable.  Both setf and setq can be used to set the value of the
+slot.
+
+SPEC-LIST is of a form similar to `let'.  For example:
+
+  ((VAR1 SLOT1)
+    SLOT2
+    SLOTN
+   (VARN+1 SLOTN+1))
+
+Where each VAR is the local variable given to the associated
+SLOT.  A slot specified without a variable name is given a
+variable name of the same name as the slot."
+  (declare (indent 2))
+  ;; Transform the spec-list into a symbol-macrolet spec-list.
+  (let ((mappings (mapcar (lambda (entry)
+                           (let ((var  (if (listp entry) (car entry) entry))
+                                 (slot (if (listp entry) (cadr entry) entry)))
+                             (list var `(slot-value ,object ',slot))))
+                         spec-list)))
+    (append (list 'symbol-macrolet mappings)
+           body)))
+\f
+;;; Simple generators, and query functions.  None of these would do
+;;  well embedded into an object.
+;;
+(defmacro object-class-fast (obj) "Return the class struct defining OBJ with no check."
+  `(aref ,obj object-class))
+
+(defun class-name (class) "Return a Lisp like symbol name for CLASS."
+  (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class)))
+  ;; I think this is supposed to return a symbol, but to me CLASS is a symbol,
+  ;; and I wanted a string.  Arg!
+  (format "#<class %s>" (symbol-name class)))
+
+(defun object-name (obj &optional extra)
+  "Return a Lisp like symbol string for object OBJ.
+If EXTRA, include that in the string returned to represent the symbol."
+  (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj)))
+  (format "#<%s %s%s>" (symbol-name (object-class-fast obj))
+         (aref obj object-name) (or extra "")))
+
+(defun object-name-string (obj) "Return a string which is OBJ's name."
+  (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj)))
+  (aref obj object-name))
+
+(defun object-set-name-string (obj name) "Set the string which is OBJ's NAME."
+  (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj)))
+  (if (not (stringp name)) (signal 'wrong-type-argument (list 'stringp name)))
+  (aset obj object-name name))
+
+(defun object-class (obj) "Return the class struct defining OBJ."
+  (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj)))
+  (object-class-fast obj))
+(defalias 'class-of 'object-class)
+
+(defun object-class-name (obj) "Return a Lisp like symbol name for OBJ's class."
+  (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj)))
+  (class-name (object-class-fast obj)))
+
+(defmacro class-parents-fast (class) "Return parent classes to CLASS with no check."
+  `(aref (class-v ,class) class-parent))
+
+(defun class-parents (class)
+  "Return parent classes to CLASS.  (overload of variable).
+
+The CLOS function `class-direct-superclasses' is aliased to this function."
+  (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class)))
+  (class-parents-fast class))
+
+(defmacro class-children-fast (class) "Return child classes to CLASS with no check."
+  `(aref (class-v ,class) class-children))
+
+(defun class-children (class)
+"Return child classes to CLASS.
+
+The CLOS function `class-direct-subclasses' is aliased to this function."
+  (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class)))
+  (class-children-fast class))
+
+(defun eieio-c3-candidate (class remaining-inputs)
+  "Returns CLASS if it can go in the result now, otherwise nil"
+  ;; Ensure CLASS is not in any position but the first in any of the
+  ;; element lists of REMAINING-INPUTS.
+  (and (not (let ((found nil))
+             (while (and remaining-inputs (not found))
+               (setq found (member class (cdr (car remaining-inputs)))
+                     remaining-inputs (cdr remaining-inputs)))
+             found))
+       class))
+
+(defun eieio-c3-merge-lists (reversed-partial-result remaining-inputs)
+  "Merge REVERSED-PARTIAL-RESULT REMAINING-INPUTS in a consistent order, if possible.
+If a consistent order does not exist, signal an error."
+  (if (let ((tail remaining-inputs)
+           (found nil))
+       (while (and tail (not found))
+         (setq found (car tail) tail (cdr tail)))
+       (not found))
+      ;; If all remaining inputs are empty lists, we are done.
+      (nreverse reversed-partial-result)
+    ;; Otherwise, we try to find the next element of the result. This
+    ;; is achieved by considering the first element of each
+    ;; (non-empty) input list and accepting a candidate if it is
+    ;; consistent with the rests of the input lists.
+    (let* ((found nil)
+          (tail remaining-inputs)
+          (next (progn
+                  (while (and tail (not found))
+                    (setq found (and (car tail)
+                                     (eieio-c3-candidate (caar tail)
+                                                         remaining-inputs))
+                          tail (cdr tail)))
+                  found)))
+      (if next
+         ;; The graph is consistent so far, add NEXT to result and
+         ;; merge input lists, dropping NEXT from their heads where
+         ;; applicable.
+         (eieio-c3-merge-lists
+          (cons next reversed-partial-result)
+          (mapcar (lambda (l) (if (eq (first l) next) (rest l) l))
+                  remaining-inputs))
+       ;; The graph is inconsistent, give up
+       (signal 'inconsistent-class-hierarchy (list remaining-inputs))))))
+
+(defun eieio-class-precedence-dfs (class)
+  "Return all parents of CLASS in depth-first order."
+  (let* ((parents (class-parents-fast class))
+        (classes (copy-sequence
+                  (apply #'append
+                         (list class)
+                         (or
+                          (mapcar
+                           (lambda (parent)
+                             (cons parent
+                                   (eieio-class-precedence-dfs parent)))
+                           parents)
+                          '((eieio-default-superclass))))))
+        (tail classes))
+    ;; Remove duplicates.
+    (while tail
+      (setcdr tail (delq (car tail) (cdr tail)))
+      (setq tail (cdr tail)))
+    classes))
+
+(defun eieio-class-precedence-bfs (class)
+  "Return all parents of CLASS in breadth-first order."
+  (let ((result)
+       (queue (or (class-parents-fast class)
+                  '(eieio-default-superclass))))
+    (while queue
+      (let ((head (pop queue)))
+       (unless (member head result)
+         (push head result)
+         (unless (eq head 'eieio-default-superclass)
+           (setq queue (append queue (or (class-parents-fast head)
+                                         '(eieio-default-superclass))))))))
+    (cons class (nreverse result)))
+  )
+
+(defun eieio-class-precedence-c3 (class)
+  "Return all parents of CLASS in c3 order."
+  (let ((parents (class-parents-fast class)))
+    (eieio-c3-merge-lists
+     (list class)
+     (append
+      (or
+       (mapcar
+       (lambda (x)
+         (eieio-class-precedence-c3 x))
+       parents)
+       '((eieio-default-superclass)))
+      (list parents))))
+  )
+
+(defun class-precedence-list (class)
+  "Return (transitively closed) list of parents of CLASS.
+The order, in which the parents are returned depends on the
+method invocation orders of the involved classes."
+  (if (or (null class) (eq class 'eieio-default-superclass))
+      nil
+    (case (class-method-invocation-order class)
+      (:depth-first
+       (eieio-class-precedence-dfs class))
+      (:breadth-first
+       (eieio-class-precedence-bfs class))
+      (:c3
+       (eieio-class-precedence-c3 class))))
+  )
+
+;; Official CLOS functions.
+(defalias 'class-direct-superclasses 'class-parents)
+(defalias 'class-direct-subclasses 'class-children)
+
+(defmacro class-parent-fast (class) "Return first parent class to CLASS with no check."
+  `(car (class-parents-fast ,class)))
+
+(defmacro class-parent (class) "Return first parent class to CLASS.  (overload of variable)."
+  `(car (class-parents ,class)))
+
+(defmacro same-class-fast-p (obj class) "Return t if OBJ is of class-type CLASS with no error checking."
+  `(eq (aref ,obj object-class) ,class))
+
+(defun same-class-p (obj class) "Return t if OBJ is of class-type CLASS."
+  (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class)))
+  (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj)))
+  (same-class-fast-p obj class))
+
+(defun object-of-class-p (obj class)
+  "Return non-nil if OBJ is an instance of CLASS or CLASS' subclasses."
+  (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj)))
+  ;; class will be checked one layer down
+  (child-of-class-p (aref obj object-class) class))
+;; Backwards compatibility
+(defalias 'obj-of-class-p 'object-of-class-p)
+
+(defun child-of-class-p (child class)
+  "Return non-nil if CHILD class is a subclass of CLASS."
+  (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class)))
+  (if (not (class-p child)) (signal 'wrong-type-argument (list 'class-p child)))
+  (let ((p nil))
+    (while (and child (not (eq child class)))
+      (setq p (append p (aref (class-v child) class-parent))
+           child (car p)
+           p (cdr p)))
+    (if child t)))
+
+(defun object-slots (obj)
+  "Return list of slots available in OBJ."
+  (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj)))
+  (aref (class-v (object-class-fast obj)) class-public-a))
+
+(defun class-slot-initarg (class slot) "Fetch from CLASS, SLOT's :initarg."
+  (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class)))
+  (let ((ia (aref (class-v class) class-initarg-tuples))
+       (f nil))
+    (while (and ia (not f))
+      (if (eq (cdr (car ia)) slot)
+         (setq f (car (car ia))))
+      (setq ia (cdr ia)))
+    f))
+
+;;; CLOS queries into classes and slots
+;;
+(defun slot-boundp (object slot)
+  "Return non-nil if OBJECT's SLOT is bound.
+Setting a slot's value makes it bound.  Calling `slot-makeunbound' will
+make a slot unbound.
+OBJECT can be an instance or a class."
+  ;; Skip typechecking while retrieving this value.
+  (let ((eieio-skip-typecheck t))
+    ;; Return nil if the magic symbol is in there.
+    (not (eq (cond
+             ((eieio-object-p object) (eieio-oref object slot))
+             ((class-p object)        (eieio-oref-default object slot))
+             (t (signal 'wrong-type-argument (list 'eieio-object-p object))))
+            eieio-unbound))))
+
+(defun slot-makeunbound (object slot)
+  "In OBJECT, make SLOT unbound."
+  (eieio-oset object slot eieio-unbound))
+
+(defun slot-exists-p (object-or-class slot)
+  "Return non-nil if OBJECT-OR-CLASS has SLOT."
+  (let ((cv (class-v (cond ((eieio-object-p object-or-class)
+                           (object-class object-or-class))
+                          ((class-p object-or-class)
+                           object-or-class))
+                    )))
+    (or (memq slot (aref cv class-public-a))
+       (memq slot (aref cv class-class-allocation-a)))
+    ))
+
+(defun find-class (symbol &optional errorp)
+  "Return the class that SYMBOL represents.
+If there is no class, nil is returned if ERRORP is nil.
+If ERRORP is non-nil, `wrong-argument-type' is signaled."
+  (if (not (class-p symbol))
+      (if errorp (signal 'wrong-type-argument (list 'class-p symbol))
+       nil)
+    (class-v symbol)))
+
+;;; Slightly more complex utility functions for objects
+;;
+(defun object-assoc (key slot list)
+  "Return an object if KEY is `equal' to SLOT's value of an object in LIST.
+LIST is a list of objects whose slots are searched.
+Objects in LIST do not need to have a slot named SLOT, nor does
+SLOT need to be bound.  If these errors occur, those objects will
+be ignored."
+  (if (not (listp list)) (signal 'wrong-type-argument (list 'listp list)))
+  (while (and list (not (condition-case nil
+                           ;; This prevents errors for missing slots.
+                           (equal key (eieio-oref (car list) slot))
+                         (error nil))))
+    (setq list (cdr list)))
+  (car list))
+
+(defun object-assoc-list (slot list)
+  "Return an association list with the contents of SLOT as the key element.
+LIST must be a list of objects with SLOT in it.
+This is useful when you need to do completing read on an object group."
+  (if (not (listp list)) (signal 'wrong-type-argument (list 'listp list)))
+  (let ((assoclist nil))
+    (while list
+      (setq assoclist (cons (cons (eieio-oref (car list) slot)
+                                 (car list))
+                           assoclist))
+      (setq list (cdr list)))
+    (nreverse assoclist)))
+
+(defun object-assoc-list-safe (slot list)
+  "Return an association list with the contents of SLOT as the key element.
+LIST must be a list of objects, but those objects do not need to have
+SLOT in it.  If it does not, then that element is left out of the association
+list."
+  (if (not (listp list)) (signal 'wrong-type-argument (list 'listp list)))
+  (let ((assoclist nil))
+    (while list
+      (if (slot-exists-p (car list) slot)
+         (setq assoclist (cons (cons (eieio-oref (car list) slot)
+                                     (car list))
+                               assoclist)))
+      (setq list (cdr list)))
+    (nreverse assoclist)))
+
+(defun object-add-to-list (object slot item &optional append)
+  "In OBJECT's SLOT, add ITEM to the list of elements.
+Optional argument APPEND indicates we need to append to the list.
+If ITEM already exists in the list in SLOT, then it is not added.
+Comparison is done with `equal' through the `member' function call.
+If SLOT is unbound, bind it to the list containing ITEM."
+  (let (ov)
+    ;; Find the originating list.
+    (if (not (slot-boundp object slot))
+       (setq ov (list item))
+      (setq ov (eieio-oref object slot))
+      ;; turn it into a list.
+      (unless (listp ov)
+       (setq ov (list ov)))
+      ;; Do the combination
+      (if (not (member item ov))
+         (setq ov
+               (if append
+                   (append ov (list item))
+                 (cons item ov)))))
+    ;; Set back into the slot.
+    (eieio-oset object slot ov)))
+
+(defun object-remove-from-list (object slot item)
+  "In OBJECT's SLOT, remove occurrences of ITEM.
+Deletion is done with `delete', which deletes by side effect,
+and comparisons are done with `equal'.
+If SLOT is unbound, do nothing."
+  (if (not (slot-boundp object slot))
+      nil
+    (eieio-oset object slot (delete item (eieio-oref object slot)))))
+\f
+;;; EIEIO internal search functions
+;;
+(defun eieio-slot-originating-class-p (start-class slot)
+  "Return non-nil if START-CLASS is the first class to define SLOT.
+This is for testing if `scoped-class' is the class that defines SLOT
+so that we can protect private slots."
+  (let ((par (class-parents start-class))
+       (ret t))
+    (if (not par)
+       t
+      (while (and par ret)
+       (if (intern-soft (symbol-name slot)
+                        (aref (class-v (car par))
+                              class-symbol-obarray))
+           (setq ret nil))
+       (setq par (cdr par)))
+      ret)))
+
+(defun eieio-slot-name-index (class obj slot)
+  "In CLASS for OBJ find the index of the named SLOT.
+The slot is a symbol which is installed in CLASS by the `defclass'
+call.  OBJ can be nil, but if it is an object, and the slot in question
+is protected, access will be allowed if OBJ is a child of the currently
+`scoped-class'.
+If SLOT is the value created with :initarg instead,
+reverse-lookup that name, and recurse with the associated slot value."
+  ;; Removed checks to outside this call
+  (let* ((fsym (intern-soft (symbol-name slot)
+                           (aref (class-v class)
+                                 class-symbol-obarray)))
+        (fsi (if (symbolp fsym) (symbol-value fsym) nil)))
+    (if (integerp fsi)
+       (cond
+        ((not (get fsym 'protection))
+         (+ 3 fsi))
+        ((and (eq (get fsym 'protection) 'protected)
+              scoped-class
+              (or (child-of-class-p class scoped-class)
+                  (and (eieio-object-p obj)
+                       (child-of-class-p class (object-class obj)))))
+         (+ 3 fsi))
+        ((and (eq (get fsym 'protection) 'private)
+              (or (and scoped-class
+                       (eieio-slot-originating-class-p scoped-class slot))
+                  eieio-initializing-object))
+         (+ 3 fsi))
+        (t nil))
+      (let ((fn (eieio-initarg-to-attribute class slot)))
+       (if fn (eieio-slot-name-index class obj fn) nil)))))
+
+(defun eieio-class-slot-name-index (class slot)
+  "In CLASS find the index of the named SLOT.
+The slot is a symbol which is installed in CLASS by the `defclass'
+call.  If SLOT is the value created with :initarg instead,
+reverse-lookup that name, and recurse with the associated slot value."
+  ;; This will happen less often, and with fewer slots.  Do this the
+  ;; storage cheap way.
+  (let* ((a (aref (class-v class) class-class-allocation-a))
+        (l1 (length a))
+        (af (memq slot a))
+        (l2 (length af)))
+    ;; Slot # is length of the total list, minus the remaining list of
+    ;; the found slot.
+    (if af (- l1 l2))))
+\f
+;;; CLOS generics internal function handling
+;;
+(defvar eieio-generic-call-methodname nil
+  "When using `call-next-method', provides a context on how to do it.")
+(defvar eieio-generic-call-arglst nil
+  "When using `call-next-method', provides a context for parameters.")
+(defvar eieio-generic-call-key nil
+  "When using `call-next-method', provides a context for the current key.
+Keys are a number representing :before, :primary, and :after methods.")
+(defvar eieio-generic-call-next-method-list nil
+  "When executing a PRIMARY or STATIC method, track the 'next-method'.
+During executions, the list is first generated, then as each next method
+is called, the next method is popped off the stack.")
+
+(defvar eieio-pre-method-execution-hooks nil
+  "*Hooks run just before a method is executed.
+The hook function must accept one argument, the list of forms
+about to be executed.")
+
+(defun eieio-generic-call (method args)
+  "Call METHOD with ARGS.
+ARGS provides the context on which implementation to use.
+This should only be called from a generic function."
+  ;; We must expand our arguments first as they are always
+  ;; passed in as quoted symbols
+  (let ((newargs nil) (mclass nil)  (lambdas nil) (tlambdas nil) (keys nil)
+       (eieio-generic-call-methodname method)
+       (eieio-generic-call-arglst args)
+       (firstarg nil)
+       (primarymethodlist nil))
+    ;; get a copy
+    (setq newargs args
+         firstarg (car newargs))
+    ;; Is the class passed in autoloaded?
+    ;; Since class names are also constructors, they can be autoloaded
+    ;; via the autoload command.  Check for this, and load them in.
+    ;; It's ok if it doesn't turn out to be a class.  Probably want that
+    ;; function loaded anyway.
+    (if (and (symbolp firstarg)
+            (fboundp firstarg)
+            (listp (symbol-function firstarg))
+            (eq 'autoload (car (symbol-function firstarg))))
+       (load (nth 1 (symbol-function firstarg))))
+    ;; Determine the class to use.
+    (cond ((eieio-object-p firstarg)
+          (setq mclass (object-class-fast firstarg)))
+         ((class-p firstarg)
+          (setq mclass firstarg))
+         )
+    ;; Make sure the class is a valid class
+    ;; mclass can be nil (meaning a generic for should be used.
+    ;; mclass cannot have a value that is not a class, however.
+    (when (and (not (null mclass)) (not (class-p mclass)))
+      (error "Cannot dispatch method %S on class %S"
+            method mclass)
+      )
+    ;; Now create a list in reverse order of all the calls we have
+    ;; make in order to successfully do this right.  Rules:
+    ;; 1) Only call generics if scoped-class is not defined
+    ;;    This prevents multiple calls in the case of recursion
+    ;; 2) Only call static if this is a static method.
+    ;; 3) Only call specifics if the definition allows for them.
+    ;; 4) Call in order based on :before, :primary, and :after
+    (when (eieio-object-p firstarg)
+      ;; Non-static calls do all this stuff.
+
+      ;; :after methods
+      (setq tlambdas
+           (if mclass
+               (eieiomt-method-list method method-after mclass)
+             (list (eieio-generic-form method method-after nil)))
+           ;;(or (and mclass (eieio-generic-form method method-after mclass))
+           ;;  (eieio-generic-form method method-after nil))
+           )
+      (setq lambdas (append tlambdas lambdas)
+           keys (append (make-list (length tlambdas) method-after) keys))
+
+      ;; :primary methods
+      (setq tlambdas
+           (or (and mclass (eieio-generic-form method method-primary mclass))
+               (eieio-generic-form method method-primary nil)))
+      (when tlambdas
+       (setq lambdas (cons tlambdas lambdas)
+             keys (cons method-primary keys)
+             primarymethodlist
+             (eieiomt-method-list method method-primary mclass)))
+
+      ;; :before methods
+      (setq tlambdas
+           (if mclass
+               (eieiomt-method-list method method-before mclass)
+             (list (eieio-generic-form method method-before nil)))
+           ;;(or (and mclass (eieio-generic-form method method-before mclass))
+           ;;  (eieio-generic-form method method-before nil))
+           )
+      (setq lambdas (append tlambdas lambdas)
+           keys (append (make-list (length tlambdas) method-before) keys))
+      )
+
+    (if mclass
+       ;; For the case of a class,
+       ;; if there were no methods found, then there could be :static methods.
+       (when (not lambdas)
+         (setq tlambdas
+               (eieio-generic-form method method-static mclass))
+         (setq lambdas (cons tlambdas lambdas)
+               keys (cons method-static keys)
+               primarymethodlist  ;; Re-use even with bad name here
+               (eieiomt-method-list method method-static mclass)))
+      ;; For the case of no class (ie - mclass == nil) then there may
+      ;; be a primary method.
+      (setq tlambdas
+           (eieio-generic-form method method-primary nil))
+      (when tlambdas
+       (setq lambdas (cons tlambdas lambdas)
+             keys (cons method-primary keys)
+             primarymethodlist
+             (eieiomt-method-list method method-primary nil)))
+      )
+
+    (run-hook-with-args 'eieio-pre-method-execution-hooks
+                       primarymethodlist)
+
+    ;; Now loop through all occurrences forms which we must execute
+    ;; (which are happily sorted now) and execute them all!
+    (let ((rval nil) (lastval nil) (rvalever nil) (found nil))
+      (while lambdas
+       (if (car lambdas)
+           (let* ((scoped-class (cdr (car lambdas)))
+                  (eieio-generic-call-key (car keys))
+                  (has-return-val
+                   (or (= eieio-generic-call-key method-primary)
+                       (= eieio-generic-call-key method-static)))
+                  (eieio-generic-call-next-method-list
+                   ;; Use the cdr, as the first element is the fcn
+                   ;; we are calling right now.
+                   (when has-return-val (cdr primarymethodlist)))
+                  )
+             (setq found t)
+             ;;(setq rval (apply (car (car lambdas)) newargs))
+             (setq lastval (apply (car (car lambdas)) newargs))
+             (when has-return-val
+               (setq rval lastval
+                     rvalever t))
+             ))
+       (setq lambdas (cdr lambdas)
+             keys (cdr keys)))
+      (if (not found)
+         (if (eieio-object-p (car args))
+             (setq rval (apply 'no-applicable-method (car args) method args)
+                   rvalever t)
+           (signal
+            'no-method-definition
+            (list method args))))
+      ;; Right Here... it could be that lastval is returned when
+      ;; rvalever is nil.  Is that right?
+      rval)))
+
+(defun eieio-generic-call-primary-only (method args)
+  "Call METHOD with ARGS for methods with only :PRIMARY implementations.
+ARGS provides the context on which implementation to use.
+This should only be called from a generic function.
+
+This method is like `eieio-generic-call', but only
+implementations in the :PRIMARY slot are queried.  After many
+years of use, it appears that over 90% of methods in use
+have :PRIMARY implementations only.  We can therefore optimize
+for this common case to improve performance."
+  ;; We must expand our arguments first as they are always
+  ;; passed in as quoted symbols
+  (let ((newargs nil) (mclass nil)  (lambdas nil)
+       (eieio-generic-call-methodname method)
+       (eieio-generic-call-arglst args)
+       (firstarg nil)
+       (primarymethodlist nil)
+       )
+    ;; get a copy
+    (setq newargs args
+         firstarg (car newargs))
+
+    ;; Determine the class to use.
+    (cond ((eieio-object-p firstarg)
+          (setq mclass (object-class-fast firstarg)))
+         ((not firstarg)
+          (error "Method %s called on nil" method))
+         ((not (eieio-object-p firstarg))
+          (error "Primary-only method %s called on something not an object" method))
+         (t
+          (error "EIEIO Error: Improperly classified method %s as primary only"
+                 method)
+         ))
+    ;; Make sure the class is a valid class
+    ;; mclass can be nil (meaning a generic for should be used.
+    ;; mclass cannot have a value that is not a class, however.
+    (when (null mclass)
+      (error "Cannot dispatch method %S on class %S" method mclass)
+      )
+
+    ;; :primary methods
+    (setq lambdas (eieio-generic-form method method-primary mclass))
+    (setq primarymethodlist  ;; Re-use even with bad name here
+         (eieiomt-method-list method method-primary mclass))
+
+    ;; Now loop through all occurrences forms which we must execute
+    ;; (which are happily sorted now) and execute them all!
+    (let* ((rval nil) (lastval nil) (rvalever nil)
+          (scoped-class (cdr lambdas))
+          (eieio-generic-call-key method-primary)
+          ;; Use the cdr, as the first element is the fcn
+          ;; we are calling right now.
+          (eieio-generic-call-next-method-list (cdr primarymethodlist))
+          )
+
+      (if (or (not lambdas) (not (car lambdas)))
+
+         ;; No methods found for this impl...
+         (if (eieio-object-p (car args))
+             (setq rval (apply 'no-applicable-method (car args) method args)
+                   rvalever t)
+           (signal
+            'no-method-definition
+            (list method args)))
+
+       ;; Do the regular implementation here.
+
+       (run-hook-with-args 'eieio-pre-method-execution-hooks
+                           lambdas)
+
+       (setq lastval (apply (car lambdas) newargs))
+       (setq rval lastval
+             rvalever t)
+       )
+
+      ;; Right Here... it could be that lastval is returned when
+      ;; rvalever is nil.  Is that right?
+      rval)))
+
+(defun eieiomt-method-list (method key class)
+  "Return an alist list of methods lambdas.
+METHOD is the method name.
+KEY represents either :before, or :after methods.
+CLASS is the starting class to search from in the method tree.
+If CLASS is nil, then an empty list of methods should be returned."
+  ;; Note: eieiomt - the MT means MethodTree.  See more comments below
+  ;; for the rest of the eieiomt methods.
+
+  ;; Collect lambda expressions stored for the class and its parent
+  ;; classes.
+  (let (lambdas)
+    (dolist (ancestor (class-precedence-list class))
+      ;; Lookup the form to use for the PRIMARY object for the next level
+      (let ((tmpl (eieio-generic-form method key ancestor)))
+       (when (and tmpl
+                  (or (not lambdas)
+                      ;; This prevents duplicates coming out of the
+                      ;; class method optimizer.  Perhaps we should
+                      ;; just not optimize before/afters?
+                      (not (member tmpl lambdas))))
+         (push tmpl lambdas))))
+
+    ;; Return collected lambda. For :after methods, return in current
+    ;; order (most general class last); Otherwise, reverse order.
+    (if (eq key method-after)
+       lambdas
+      (nreverse lambdas))))
+
+(defun next-method-p ()
+  "Return non-nil if there is a next method.
+Returns a list of lambda expressions which is the `next-method'
+order."
+  eieio-generic-call-next-method-list)
+
+(defun call-next-method (&rest replacement-args)
+  "Call the superclass method from a subclass method.
+The superclass method is specified in the current method list,
+and is called the next method.
+
+If REPLACEMENT-ARGS is non-nil, then use them instead of
+`eieio-generic-call-arglst'.  The generic arg list are the
+arguments passed in at the top level.
+
+Use `next-method-p' to find out if there is a next method to call."
+  (if (not scoped-class)
+      (error "`call-next-method' not called within a class specific method"))
+  (if (and (/= eieio-generic-call-key method-primary)
+          (/= eieio-generic-call-key method-static))
+      (error "Cannot `call-next-method' except in :primary or :static methods")
+    )
+  (let ((newargs (or replacement-args eieio-generic-call-arglst))
+       (next (car eieio-generic-call-next-method-list))
+       )
+    (if (or (not next) (not (car next)))
+       (apply 'no-next-method (car newargs) (cdr newargs))
+      (let* ((eieio-generic-call-next-method-list
+             (cdr eieio-generic-call-next-method-list))
+            (eieio-generic-call-arglst newargs)
+            (scoped-class (cdr next))
+            (fcn (car next))
+            )
+       (apply fcn newargs)
+       ))))
+\f
+;;;
+;; eieio-method-tree : eieiomt-
+;;
+;; Stored as eieio-method-tree in property list of a generic method
+;;
+;; (eieio-method-tree . [BEFORE PRIMARY AFTER
+;;                       genericBEFORE genericPRIMARY genericAFTER])
+;; and
+;; (eieio-method-obarray . [BEFORE PRIMARY AFTER
+;;                          genericBEFORE genericPRIMARY genericAFTER])
+;;    where the association is a vector.
+;;    (aref 0  -- all static methods.
+;;    (aref 1  -- all methods classified as :before
+;;    (aref 2  -- all methods classified as :primary
+;;    (aref 3  -- all methods classified as :after
+;;    (aref 4  -- a generic classified as :before
+;;    (aref 5  -- a generic classified as :primary
+;;    (aref 6  -- a generic classified as :after
+;;
+(defvar eieiomt-optimizing-obarray nil
+  "While mapping atoms, this contain the obarray being optimized.")
+
+(defun eieiomt-install (method-name)
+  "Install the method tree, and obarray onto METHOD-NAME.
+Do not do the work if they already exist."
+  (let ((emtv (get method-name 'eieio-method-tree))
+       (emto (get method-name 'eieio-method-obarray)))
+    (if (or (not emtv) (not emto))
+       (progn
+         (setq emtv (put method-name 'eieio-method-tree
+                         (make-vector method-num-slots nil))
+               emto (put method-name 'eieio-method-obarray
+                         (make-vector method-num-slots nil)))
+         (aset emto 0 (make-vector 11 0))
+         (aset emto 1 (make-vector 11 0))
+         (aset emto 2 (make-vector 41 0))
+         (aset emto 3 (make-vector 11 0))
+         ))))
+
+(defun eieiomt-add (method-name method key class)
+  "Add to METHOD-NAME the forms METHOD in a call position KEY for CLASS.
+METHOD-NAME is the name created by a call to `defgeneric'.
+METHOD are the forms for a given implementation.
+KEY is an integer (see comment in eieio.el near this function) which
+is associated with the :static :before :primary and :after tags.
+It also indicates if CLASS is defined or not.
+CLASS is the class this method is associated with."
+  (if (or (> key method-num-slots) (< key 0))
+      (error "eieiomt-add: method key error!"))
+  (let ((emtv (get method-name 'eieio-method-tree))
+       (emto (get method-name 'eieio-method-obarray)))
+    ;; Make sure the method tables are available.
+    (if (or (not emtv) (not emto))
+       (error "Programmer error: eieiomt-add"))
+    ;; only add new cells on if it doesn't already exist!
+    (if (assq class (aref emtv key))
+       (setcdr (assq class (aref emtv key)) method)
+      (aset emtv key (cons (cons class method) (aref emtv key))))
+    ;; Add function definition into newly created symbol, and store
+    ;; said symbol in the correct obarray, otherwise use the
+    ;; other array to keep this stuff
+    (if (< key method-num-lists)
+       (let ((nsym (intern (symbol-name class) (aref emto key))))
+         (fset nsym method)))
+    ;; Now optimize the entire obarray
+    (if (< key method-num-lists)
+       (let ((eieiomt-optimizing-obarray (aref emto key)))
+         ;; @todo - Is this overkill?  Should we just clear the symbol?
+         (mapatoms 'eieiomt-sym-optimize eieiomt-optimizing-obarray)))
+    ))
+
+(defun eieiomt-next (class)
+  "Return the next parent class for CLASS.
+If CLASS is a superclass, return variable `eieio-default-superclass'.
+If CLASS is variable `eieio-default-superclass' then return nil.
+This is different from function `class-parent' as class parent returns
+nil for superclasses.  This function performs no type checking!"
+  ;; No type-checking because all calls are made from functions which
+  ;; are safe and do checking for us.
+  (or (class-parents-fast class)
+      (if (eq class 'eieio-default-superclass)
+         nil
+       '(eieio-default-superclass))))
+
+(defun eieiomt-sym-optimize (s)
+  "Find the next class above S which has a function body for the optimizer."
+  ;; Set the value to nil in case there is no nearest cell.
+  (set s nil)
+  ;; Find the nearest cell that has a function body. If we find one,
+  ;; we replace the nil from above.
+  (let ((external-symbol (intern-soft (symbol-name s))))
+    (catch 'done
+      (dolist (ancestor (rest (class-precedence-list external-symbol)))
+       (let ((ov (intern-soft (symbol-name ancestor)
+                              eieiomt-optimizing-obarray)))
+         (when (fboundp ov)
+           (set s ov) ;; store ov as our next symbol
+           (throw 'done ancestor)))))))
+
+(defun eieio-generic-form (method key class)
+ "Return the lambda form belonging to METHOD using KEY based upon CLASS.
+If CLASS is not a class then use `generic' instead.  If class has
+no form, but has a parent class, then trace to that parent class.
+The first time a form is requested from a symbol, an optimized path
+is memorized for faster future use."
+ (let ((emto (aref (get method 'eieio-method-obarray)
+                  (if class key (eieio-specialized-key-to-generic-key key)))))
+   (if (class-p class)
+       ;; 1) find our symbol
+       (let ((cs (intern-soft (symbol-name class) emto)))
+        (if (not cs)
+            ;; 2) If there isn't one, then make one.
+            ;;    This can be slow since it only occurs once
+            (progn
+              (setq cs (intern (symbol-name class) emto))
+              ;; 2.1) Cache its nearest neighbor with a quick optimize
+              ;;      which should only occur once for this call ever
+              (let ((eieiomt-optimizing-obarray emto))
+                (eieiomt-sym-optimize cs))))
+        ;; 3) If it's bound return this one.
+        (if (fboundp  cs)
+            (cons cs (aref (class-v class) class-symbol))
+          ;; 4) If it's not bound then this variable knows something
+          (if (symbol-value cs)
+              (progn
+                ;; 4.1) This symbol holds the next class in its value
+                (setq class (symbol-value cs)
+                      cs (intern-soft (symbol-name class) emto))
+                ;; 4.2) The optimizer should always have chosen a
+                ;;      function-symbol
+                ;;(if (fboundp cs)
+                (cons cs (aref (class-v (intern (symbol-name class)))
+                               class-symbol))
+                  ;;(error "EIEIO optimizer: erratic data loss!"))
+                )
+              ;; There never will be a funcall...
+              nil)))
+     ;; for a generic call, what is a list, is the function body we want.
+     (let ((emtl (aref (get method 'eieio-method-tree)
+                      (if class key (eieio-specialized-key-to-generic-key key)))))
+       (if emtl
+          ;; The car of EMTL is supposed to be a class, which in this
+          ;; case is nil, so skip it.
+          (cons (cdr (car emtl)) nil)
+        nil)))))
+
+;;;
+;; Way to assign slots based on a list.  Used for constructors, or
+;; even resetting an object at run-time
+;;
+(defun eieio-set-defaults (obj &optional set-all)
+  "Take object OBJ, and reset all slots to their defaults.
+If SET-ALL is non-nil, then when a default is nil, that value is
+reset.  If SET-ALL is nil, the slots are only reset if the default is
+not nil."
+  (let ((scoped-class (aref obj object-class))
+       (eieio-initializing-object t)
+       (pub (aref (class-v (aref obj object-class)) class-public-a)))
+    (while pub
+      (let ((df (eieio-oref-default obj (car pub))))
+       (if (or df set-all)
+           (eieio-oset obj (car pub) df)))
+      (setq pub (cdr pub)))))
+
+(defun eieio-initarg-to-attribute (class initarg)
+  "For CLASS, convert INITARG to the actual attribute name.
+If there is no translation, pass it in directly (so we can cheat if
+need be... May remove that later...)"
+  (let ((tuple (assoc initarg (aref (class-v class) class-initarg-tuples))))
+    (if tuple
+       (cdr tuple)
+      nil)))
+
+(defun eieio-attribute-to-initarg (class attribute)
+  "In CLASS, convert the ATTRIBUTE into the corresponding init argument tag.
+This is usually a symbol that starts with `:'."
+  (let ((tuple (rassoc attribute (aref (class-v class) class-initarg-tuples))))
+    (if tuple
+       (car tuple)
+      nil)))
+
+\f
+;;; Here are some special types of errors
+;;
+(intern "no-method-definition")
+(put 'no-method-definition 'error-conditions '(no-method-definition error))
+(put 'no-method-definition 'error-message "No method definition")
+
+(intern "no-next-method")
+(put 'no-next-method 'error-conditions '(no-next-method error))
+(put 'no-next-method 'error-message "No next method")
+
+(intern "invalid-slot-name")
+(put 'invalid-slot-name 'error-conditions '(invalid-slot-name error))
+(put 'invalid-slot-name 'error-message "Invalid slot name")
+
+(intern "invalid-slot-type")
+(put 'invalid-slot-type 'error-conditions '(invalid-slot-type error nil))
+(put 'invalid-slot-type 'error-message "Invalid slot type")
+
+(intern "unbound-slot")
+(put 'unbound-slot 'error-conditions '(unbound-slot error nil))
+(put 'unbound-slot 'error-message "Unbound slot")
+
+(intern "inconsistent-class-hierarchy")
+(put 'inconsistent-class-hierarchy 'error-conditions
+     '(inconsistent-class-hierarchy error nil))
+(put 'inconsistent-class-hierarchy 'error-message "Inconsistent class hierarchy")
+
+;;; Here are some CLOS items that need the CL package
+;;
+
+(defsetf slot-value (obj slot) (store) (list 'eieio-oset obj slot store))
+(defsetf eieio-oref (obj slot) (store) (list 'eieio-oset obj slot store))
+
+;; The below setf method was written by Arnd Kohrs <kohrs@acm.org>
+(define-setf-method oref (obj slot)
+  (with-no-warnings
+    (require 'cl)
+    (let ((obj-temp (gensym))
+         (slot-temp (gensym))
+         (store-temp (gensym)))
+      (list (list obj-temp slot-temp)
+           (list obj `(quote ,slot))
+           (list store-temp)
+           (list 'set-slot-value obj-temp slot-temp
+                 store-temp)
+           (list 'slot-value obj-temp slot-temp)))))
+
+\f
+;;;
+;; We want all objects created by EIEIO to have some default set of
+;; behaviours so we can create object utilities, and allow various
+;; types of error checking.  To do this, create the default EIEIO
+;; class, and when no parent class is specified, use this as the
+;; default.  (But don't store it in the other classes as the default,
+;; allowing for transparent support.)
+;;
+
+(defclass eieio-default-superclass nil
+  nil
+  "Default parent class for classes with no specified parent class.
+Its slots are automatically adopted by classes with no specified parents.
+This class is not stored in the `parent' slot of a class vector."
+  :abstract t)
+
+(defalias 'standard-class 'eieio-default-superclass)
+
+(defgeneric constructor (class newname &rest slots)
+  "Default constructor for CLASS `eieio-default-superclass'.")
+
+(defmethod constructor :static
+  ((class eieio-default-superclass) newname &rest slots)
+  "Default constructor for CLASS `eieio-default-superclass'.
+NEWNAME is the name to be given to the constructed object.
+SLOTS are the initialization slots used by `shared-initialize'.
+This static method is called when an object is constructed.
+It allocates the vector used to represent an EIEIO object, and then
+calls `shared-initialize' on that object."
+  (let* ((new-object (copy-sequence (aref (class-v class)
+                                         class-default-object-cache))))
+    ;; Update the name for the newly created object.
+    (aset new-object object-name newname)
+    ;; Call the initialize method on the new object with the slots
+    ;; that were passed down to us.
+    (initialize-instance new-object slots)
+    ;; Return the created object.
+    new-object))
+
+(defgeneric shared-initialize (obj slots)
+  "Set slots of OBJ with SLOTS which is a list of name/value pairs.
+Called from the constructor routine.")
+
+(defmethod shared-initialize ((obj eieio-default-superclass) slots)
+  "Set slots of OBJ with SLOTS which is a list of name/value pairs.
+Called from the constructor routine."
+  (let ((scoped-class (aref obj object-class)))
+    (while slots
+      (let ((rn (eieio-initarg-to-attribute (object-class-fast obj)
+                                           (car slots))))
+       (if (not rn)
+           (slot-missing obj (car slots) 'oset (car (cdr slots)))
+         (eieio-oset obj rn (car (cdr slots)))))
+      (setq slots (cdr (cdr slots))))))
+
+(defgeneric initialize-instance (this &optional slots)
+  "Construct the new object THIS based on SLOTS.")
+
+(defmethod initialize-instance ((this eieio-default-superclass)
+                               &optional slots)
+  "Construct the new object THIS based on SLOTS.
+SLOTS is a tagged list where odd numbered elements are tags, and
+even numbered elements are the values to store in the tagged slot.
+If you overload the `initialize-instance', there you will need to
+call `shared-initialize' yourself, or you can call `call-next-method'
+to have this constructor called automatically.  If these steps are
+not taken, then new objects of your class will not have their values
+dynamically set from SLOTS."
+    ;; First, see if any of our defaults are `lambda', and
+    ;; re-evaluate them and apply the value to our slots.
+    (let* ((scoped-class (class-v (aref this object-class)))
+          (slot (aref scoped-class class-public-a))
+          (defaults (aref scoped-class class-public-d)))
+      (while slot
+       ;; For each slot, see if we need to evaluate it.
+       ;;
+       ;; Paul Landes said in an email:
+       ;; > CL evaluates it if it can, and otherwise, leaves it as
+       ;; > the quoted thing as you already have.  This is by the
+       ;; > Sonya E. Keene book and other things I've look at on the
+       ;; > web.
+       (let ((dflt (eieio-default-eval-maybe (car defaults))))
+         (when (not (eq dflt (car defaults)))
+           (eieio-oset this (car slot) dflt) ))
+       ;; Next.
+       (setq slot (cdr slot)
+             defaults (cdr defaults))))
+    ;; Shared initialize will parse our slots for us.
+    (shared-initialize this slots))
+
+(defgeneric slot-missing (object slot-name operation &optional new-value)
+  "Method invoked when an attempt to access a slot in OBJECT fails.")
+
+(defmethod slot-missing ((object eieio-default-superclass) slot-name
+                        operation &optional new-value)
+  "Method invoked when an attempt to access a slot in OBJECT fails.
+SLOT-NAME is the name of the failed slot, OPERATION is the type of access
+that was requested, and optional NEW-VALUE is the value that was desired
+to be set.
+
+This method is called from `oref', `oset', and other functions which
+directly reference slots in EIEIO objects."
+  (signal 'invalid-slot-name (list (object-name object)
+                                  slot-name)))
+
+(defgeneric slot-unbound (object class slot-name fn)
+  "Slot unbound is invoked during an attempt to reference an unbound slot.")
+
+(defmethod slot-unbound ((object eieio-default-superclass)
+                        class slot-name fn)
+  "Slot unbound is invoked during an attempt to reference an unbound slot.
+OBJECT is the instance of the object being reference.  CLASS is the
+class of OBJECT, and SLOT-NAME is the offending slot.  This function
+throws the signal `unbound-slot'.  You can overload this function and
+return the value to use in place of the unbound value.
+Argument FN is the function signaling this error.
+Use `slot-boundp' to determine if a slot is bound or not.
+
+In CLOS, the argument list is (CLASS OBJECT SLOT-NAME), but
+EIEIO can only dispatch on the first argument, so the first two are swapped."
+  (signal 'unbound-slot (list (class-name class) (object-name object)
+                             slot-name fn)))
+
+(defgeneric no-applicable-method (object method &rest args)
+  "Called if there are no implementations for OBJECT in METHOD.")
+
+(defmethod no-applicable-method ((object eieio-default-superclass)
+                                method &rest args)
+  "Called if there are no implementations for OBJECT in METHOD.
+OBJECT is the object which has no method implementation.
+ARGS are the arguments that were passed to METHOD.
+
+Implement this for a class to block this signal.  The return
+value becomes the return value of the original method call."
+  (signal 'no-method-definition (list method (object-name object)))
+  )
+
+(defgeneric no-next-method (object &rest args)
+"Called from `call-next-method' when no additional methods are available.")
+
+(defmethod no-next-method ((object eieio-default-superclass)
+                          &rest args)
+  "Called from `call-next-method' when no additional methods are available.
+OBJECT is othe object being called on `call-next-method'.
+ARGS are the arguments it is called by.
+This method signals `no-next-method' by default.  Override this
+method to not throw an error, and its return value becomes the
+return value of `call-next-method'."
+  (signal 'no-next-method (list (object-name object) args))
+)
+
+(defgeneric clone (obj &rest params)
+  "Make a copy of OBJ, and then supply PARAMS.
+PARAMS is a parameter list of the same form used by `initialize-instance'.
+
+When overloading `clone', be sure to call `call-next-method'
+first and modify the returned object.")
+
+(defmethod clone ((obj eieio-default-superclass) &rest params)
+  "Make a copy of OBJ, and then apply PARAMS."
+  (let ((nobj (copy-sequence obj))
+       (nm (aref obj object-name))
+       (passname (and params (stringp (car params))))
+       (num 1))
+    (if params (shared-initialize nobj (if passname (cdr params) params)))
+    (if (not passname)
+       (save-match-data
+         (if (string-match "-\\([0-9]+\\)" nm)
+             (setq num (1+ (string-to-number (match-string 1 nm)))
+                   nm (substring nm 0 (match-beginning 0))))
+         (aset nobj object-name (concat nm "-" (int-to-string num))))
+      (aset nobj object-name (car params)))
+    nobj))
+
+(defgeneric destructor (this &rest params)
+  "Destructor for cleaning up any dynamic links to our object.")
+
+(defmethod destructor ((this eieio-default-superclass) &rest params)
+  "Destructor for cleaning up any dynamic links to our object.
+Argument THIS is the object being destroyed.  PARAMS are additional
+ignored parameters."
+  ;; No cleanup... yet.
+  )
+
+(defgeneric object-print (this &rest strings)
+  "Pretty printer for object THIS.  Call function `object-name' with STRINGS.
+
+It is sometimes useful to put a summary of the object into the
+default #<notation> string when using EIEIO browsing tools.
+Implement this method to customize the summary.")
+
+(defmethod object-print ((this eieio-default-superclass) &rest strings)
+  "Pretty printer for object THIS.  Call function `object-name' with STRINGS.
+The default method for printing object THIS is to use the
+function `object-name'.
+
+It is sometimes useful to put a summary of the object into the
+default #<notation> string when using EIEIO browsing tools.
+
+Implement this function and specify STRINGS in a call to
+`call-next-method' to provide additional summary information.
+When passing in extra strings from child classes, always remember
+to prepend a space."
+  (object-name this (apply 'concat strings)))
+
+(defvar eieio-print-depth 0
+  "When printing, keep track of the current indentation depth.")
+
+(defgeneric object-write (this &optional comment)
+  "Write out object THIS to the current stream.
+Optional COMMENT will add comments to the beginning of the output.")
+
+(defmethod object-write ((this eieio-default-superclass) &optional comment)
+  "Write object THIS out to the current stream.
+This writes out the vector version of this object.  Complex and recursive
+object are discouraged from being written.
+  If optional COMMENT is non-nil, include comments when outputting
+this object."
+  (when comment
+    (princ ";; Object ")
+    (princ (object-name-string this))
+    (princ "\n")
+    (princ comment)
+    (princ "\n"))
+  (let* ((cl (object-class this))
+        (cv (class-v cl)))
+    ;; Now output readable lisp to recreate this object
+    ;; It should look like this:
+    ;; (<constructor> <name> <slot> <slot> ... )
+    ;; Each slot's slot is writen using its :writer.
+    (princ (make-string (* eieio-print-depth 2) ? ))
+    (princ "(")
+    (princ (symbol-name (class-constructor (object-class this))))
+    (princ " \"")
+    (princ (object-name-string this))
+    (princ "\"\n")
+    ;; Loop over all the public slots
+    (let ((publa (aref cv class-public-a))
+         (publd (aref cv class-public-d))
+         (publp (aref cv class-public-printer))
+         (eieio-print-depth (1+ eieio-print-depth)))
+      (while publa
+       (when (slot-boundp this (car publa))
+         (let ((i (class-slot-initarg cl (car publa)))
+               (v (eieio-oref this (car publa)))
+               )
+           (unless (or (not i) (equal v (car publd)))
+             (princ (make-string (* eieio-print-depth 2) ? ))
+             (princ (symbol-name i))
+             (princ " ")
+             (if (car publp)
+                 ;; Use our public printer
+                 (funcall (car publp) v)
+               ;; Use our generic override prin1 function.
+               (eieio-override-prin1 v))
+             (princ "\n"))))
+       (setq publa (cdr publa) publd (cdr publd)
+             publp (cdr publp)))
+      (princ (make-string (* eieio-print-depth 2) ? )))
+    (princ ")\n")))
+
+(defun eieio-override-prin1 (thing)
+  "Perform a `prin1' on THING taking advantage of object knowledge."
+  (cond ((eieio-object-p thing)
+        (object-write thing))
+       ((listp thing)
+        (eieio-list-prin1 thing))
+       ((class-p thing)
+        (princ (class-name thing)))
+       ((symbolp thing)
+        (princ (concat "'" (symbol-name thing))))
+       (t (prin1 thing))))
+
+(defun eieio-list-prin1 (list)
+  "Display LIST where list may contain objects."
+  (if (not (eieio-object-p (car list)))
+      (progn
+       (princ "'")
+       (prin1 list))
+    (princ "(list ")
+    (if (eieio-object-p (car list)) (princ "\n "))
+    (while list
+      (if (eieio-object-p (car list))
+         (object-write (car list))
+       (princ "'")
+       (prin1 (car list)))
+      (princ " ")
+      (setq list (cdr list)))
+    (princ (make-string (* eieio-print-depth 2) ? ))
+    (princ ")")))
+
+\f
+;;; Unimplemented functions from CLOS
+;;
+(defun change-class (obj class)
+  "Change the class of OBJ to type CLASS.
+This may create or delete slots, but does not affect the return value
+of `eq'."
+  (error "EIEIO: `change-class' is unimplemented"))
+
+)
+
+\f
+;;; Interfacing with edebug
+;;
+(defun eieio-edebug-prin1-to-string (object &optional noescape)
+  "Display EIEIO OBJECT in fancy format.
+Overrides the edebug default.
+Optional argument NOESCAPE is passed to `prin1-to-string' when appropriate."
+  (cond ((class-p object) (class-name object))
+       ((eieio-object-p object) (object-print object))
+       ((and (listp object) (or (class-p (car object))
+                                (eieio-object-p (car object))))
+        (concat "(" (mapconcat 'eieio-edebug-prin1-to-string object " ") ")"))
+       (t (prin1-to-string object noescape))))
+
+(add-hook 'edebug-setup-hook
+         (lambda ()
+           (def-edebug-spec defmethod
+             (&define                  ; this means we are defining something
+              [&or name ("setf" :name setf name)]
+              ;; ^^ This is the methods symbol
+              [ &optional symbolp ]    ; this is key :before etc
+              list              ; arguments
+              [ &optional stringp ]    ; documentation string
+              def-body                 ; part to be debugged
+              ))
+           ;; The rest of the macros
+           (def-edebug-spec oref (form quote))
+           (def-edebug-spec oref-default (form quote))
+           (def-edebug-spec oset (form quote form))
+           (def-edebug-spec oset-default (form quote form))
+           (def-edebug-spec class-v form)
+           (def-edebug-spec class-p form)
+           (def-edebug-spec eieio-object-p form)
+           (def-edebug-spec class-constructor form)
+           (def-edebug-spec generic-p form)
+           (def-edebug-spec with-slots (list list def-body))
+           ;; I suspect this isn't the best way to do this, but when
+           ;; cust-print was used on my system all my objects
+           ;; appeared as "#1 =" which was not useful.  This allows
+           ;; edebug to print my objects in the nice way they were
+           ;; meant to with `object-print' and `class-name'
+           ;; (defalias 'edebug-prin1-to-string 'eieio-edebug-prin1-to-string)
+           )
+         )
+
+;;; Interfacing with imenu in emacs lisp mode
+;;    (Only if the expression is defined)
+;;
+(if (eval-when-compile (boundp 'list-imenu-generic-expression))
+(progn
+
+(defun eieio-update-lisp-imenu-expression ()
+  "Examine `lisp-imenu-generic-expression' and modify it to find `defmethod'."
+  (let ((exp lisp-imenu-generic-expression))
+    (while exp
+      ;; it's of the form '( ( title expr indx ) ... )
+      (let* ((subcar (cdr (car exp)))
+            (substr (car subcar)))
+       (if (and (not (string-match "|method\\\\" substr))
+                (string-match "|advice\\\\" substr))
+           (setcar subcar
+                   (replace-match "|advice\\|method\\" t t substr 0))))
+      (setq exp (cdr exp)))))
+
+(eieio-update-lisp-imenu-expression)
+
+))
+
+;;; Autoloading some external symbols, and hooking into the help system
+;;
+
+\f
+;;; Start of automatically extracted autoloads.
+\f
+;;;### (autoloads (customize-object) "eieio-custom" "eieio-custom.el"
+;;;;;;  "cf1bd64c76a6e6406545e8c5a5530d43")
+;;; Generated autoloads from eieio-custom.el
+
+(autoload 'customize-object "eieio-custom" "\
+Customize OBJ in a custom buffer.
+Optional argument GROUP is the sub-group of slots to display.
+
+\(fn OBJ &optional GROUP)" nil nil)
+
+;;;***
+\f
+;;;### (autoloads (eieio-help-mode-augmentation-maybee eieio-describe-generic
+;;;;;;  eieio-describe-constructor eieio-describe-class eieio-browse)
+;;;;;;  "eieio-opt" "eieio-opt.el" "1bed0a56310f402683419139ebc18d7f")
+;;; Generated autoloads from eieio-opt.el
+
+(autoload 'eieio-browse "eieio-opt" "\
+Create an object browser window to show all objects.
+If optional ROOT-CLASS, then start with that, otherwise start with
+variable `eieio-default-superclass'.
+
+\(fn &optional ROOT-CLASS)" t nil)
+
+(defalias 'describe-class 'eieio-describe-class)
+
+(autoload 'eieio-describe-class "eieio-opt" "\
+Describe a CLASS defined by a string or symbol.
+If CLASS is actually an object, then also display current values of that object.
+Optional HEADERFCN should be called to insert a few bits of info first.
+
+\(fn CLASS &optional HEADERFCN)" t nil)
+
+(autoload 'eieio-describe-constructor "eieio-opt" "\
+Describe the constructor function FCN.
+Uses `eieio-describe-class' to describe the class being constructed.
+
+\(fn FCN)" t nil)
+
+(defalias 'describe-generic 'eieio-describe-generic)
+
+(autoload 'eieio-describe-generic "eieio-opt" "\
+Describe the generic function GENERIC.
+Also extracts information about all methods specific to this generic.
+
+\(fn GENERIC)" t nil)
+
+(autoload 'eieio-help-mode-augmentation-maybee "eieio-opt" "\
+For buffers thrown into help mode, augment for EIEIO.
+Arguments UNUSED are not used.
+
+\(fn &rest UNUSED)" nil nil)
+
+;;;***
+\f
+;;; End of automatically extracted autoloads.
+
+(provide 'eieio)
+
+;;; eieio ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-fallback-lib/json.el b/xemacs-packages/gnus/lisp/gnus-fallback-lib/json.el
new file mode 100644 (file)
index 0000000..c38a431
--- /dev/null
@@ -0,0 +1,534 @@
+;;; json.el --- JavaScript Object Notation parser / generator
+
+;; Copyright (C) 2006-2016 Free Software Foundation, Inc.
+
+;; Author: Edward O'Connor <ted@oconnor.cx>
+;; Version: 1.3
+;; Keywords: convenience
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This is a library for parsing and generating JSON (JavaScript Object
+;; Notation).
+
+;; Learn all about JSON here: <URL:http://json.org/>.
+
+;; The user-serviceable entry points for the parser are the functions
+;; `json-read' and `json-read-from-string'. The encoder has a single
+;; entry point, `json-encode'.
+
+;; Since there are several natural representations of key-value pair
+;; mappings in elisp (alist, plist, hash-table), `json-read' allows you
+;; to specify which you'd prefer (see `json-object-type' and
+;; `json-array-type').
+
+;; Similarly, since `false' and `null' are distinct in JSON, you can
+;; distinguish them by binding `json-false' and `json-null' as desired.
+
+;;; History:
+
+;; 2006-03-11 - Initial version.
+;; 2006-03-13 - Added JSON generation in addition to parsing. Various
+;;              other cleanups, bugfixes, and improvements.
+;; 2006-12-29 - XEmacs support, from Aidan Kehoe <kehoea@parhasard.net>.
+;; 2008-02-21 - Installed in GNU Emacs.
+;; 2011-10-17 - Patch `json-alist-p' and `json-plist-p' to avoid recursion -tzz
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+;; Compatibility code
+
+(defalias 'json-encode-char0 'encode-char)
+(defalias 'json-decode-char0 'decode-char)
+
+
+;; Parameters
+
+(defvar json-object-type 'alist
+  "Type to convert JSON objects to.
+Must be one of `alist', `plist', or `hash-table'.  Consider let-binding
+this around your call to `json-read' instead of `setq'ing it.")
+
+(defvar json-array-type 'vector
+  "Type to convert JSON arrays to.
+Must be one of `vector' or `list'.  Consider let-binding this around
+your call to `json-read' instead of `setq'ing it.")
+
+(defvar json-key-type nil
+  "Type to convert JSON keys to.
+Must be one of `string', `symbol', `keyword', or nil.
+
+If nil, `json-read' will guess the type based on the value of
+`json-object-type':
+
+    If `json-object-type' is:   nil will be interpreted as:
+      `hash-table'                `string'
+      `alist'                     `symbol'
+      `plist'                     `keyword'
+
+Note that values other than `string' might behave strangely for
+Sufficiently Weird keys.  Consider let-binding this around your call to
+`json-read' instead of `setq'ing it.")
+
+(defvar json-false :json-false
+  "Value to use when reading JSON `false'.
+If this has the same value as `json-null', you might not be able to tell
+the difference between `false' and `null'.  Consider let-binding this
+around your call to `json-read' instead of `setq'ing it.")
+
+(defvar json-null nil
+  "Value to use when reading JSON `null'.
+If this has the same value as `json-false', you might not be able to
+tell the difference between `false' and `null'.  Consider let-binding
+this around your call to `json-read' instead of `setq'ing it.")
+
+\f
+
+;;; Utilities
+
+(defun json-join (strings separator)
+  "Join STRINGS with SEPARATOR."
+  (mapconcat 'identity strings separator))
+
+(defun json-alist-p (list)
+  "Non-null if and only if LIST is an alist."
+  (while (consp list)
+    (setq list (if (consp (car list))
+                   (cdr list)
+                 'not-alist)))
+  (null list))
+
+(defun json-plist-p (list)
+  "Non-null if and only if LIST is a plist."
+  (while (consp list)
+    (setq list (if (and (keywordp (car list))
+                        (consp (cdr list)))
+                   (cddr list)
+                 'not-plist)))
+  (null list))
+
+;; Reader utilities
+
+(defsubst json-advance (&optional n)
+  "Skip past the following N characters."
+  (forward-char n))
+
+(defsubst json-peek ()
+  "Return the character at point."
+  (let ((char (char-after (point))))
+    (or char :json-eof)))
+
+(defsubst json-pop ()
+  "Advance past the character at point, returning it."
+  (let ((char (json-peek)))
+    (if (eq char :json-eof)
+        (signal 'end-of-file nil)
+      (json-advance)
+      char)))
+
+(defun json-skip-whitespace ()
+  "Skip past the whitespace at point."
+  (skip-chars-forward "\t\r\n\f\b "))
+
+\f
+
+;; Error conditions
+
+(put 'json-error 'error-message "Unknown JSON error")
+(put 'json-error 'error-conditions '(json-error error))
+
+(put 'json-readtable-error 'error-message "JSON readtable error")
+(put 'json-readtable-error 'error-conditions
+     '(json-readtable-error json-error error))
+
+(put 'json-unknown-keyword 'error-message "Unrecognized keyword")
+(put 'json-unknown-keyword 'error-conditions
+     '(json-unknown-keyword json-error error))
+
+(put 'json-number-format 'error-message "Invalid number format")
+(put 'json-number-format 'error-conditions
+     '(json-number-format json-error error))
+
+(put 'json-string-escape 'error-message "Bad unicode escape")
+(put 'json-string-escape 'error-conditions
+     '(json-string-escape json-error error))
+
+(put 'json-string-format 'error-message "Bad string format")
+(put 'json-string-format 'error-conditions
+     '(json-string-format json-error error))
+
+(put 'json-object-format 'error-message "Bad JSON object")
+(put 'json-object-format 'error-conditions
+     '(json-object-format json-error error))
+
+\f
+
+;;; Keywords
+
+(defvar json-keywords '("true" "false" "null")
+  "List of JSON keywords.")
+
+;; Keyword parsing
+
+(defun json-read-keyword (keyword)
+  "Read a JSON keyword at point.
+KEYWORD is the keyword expected."
+  (unless (member keyword json-keywords)
+    (signal 'json-unknown-keyword (list keyword)))
+  (mapc (lambda (char)
+          (unless (char-equal char (json-peek))
+            (signal 'json-unknown-keyword
+                    (list (save-excursion
+                            (backward-word 1)
+                            (thing-at-point 'word)))))
+          (json-advance))
+        keyword)
+  (unless (looking-at "\\(\\s-\\|[],}]\\|$\\)")
+    (signal 'json-unknown-keyword
+            (list (save-excursion
+                    (backward-word 1)
+                    (thing-at-point 'word)))))
+  (cond ((string-equal keyword "true") t)
+        ((string-equal keyword "false") json-false)
+        ((string-equal keyword "null") json-null)))
+
+;; Keyword encoding
+
+(defun json-encode-keyword (keyword)
+  "Encode KEYWORD as a JSON value."
+  (cond ((eq keyword t)          "true")
+        ((eq keyword json-false) "false")
+        ((eq keyword json-null)  "null")))
+
+;;; Numbers
+
+;; Number parsing
+
+(defun json-read-number (&optional sign)
+ "Read the JSON number following point.
+The optional SIGN argument is for internal use.
+
+N.B.: Only numbers which can fit in Emacs Lisp's native number
+representation will be parsed correctly."
+ ;; If SIGN is non-nil, the number is explicitly signed.
+ (let ((number-regexp
+        "\\([0-9]+\\)?\\(\\.[0-9]+\\)?\\([Ee][+-]?[0-9]+\\)?"))
+   (cond ((and (null sign) (char-equal (json-peek) ?-))
+          (json-advance)
+          (- (json-read-number t)))
+         ((and (null sign) (char-equal (json-peek) ?+))
+          (json-advance)
+          (json-read-number t))
+         ((and (looking-at number-regexp)
+               (or (match-beginning 1)
+                   (match-beginning 2)))
+          (goto-char (match-end 0))
+          (string-to-number (match-string 0)))
+         (t (signal 'json-number-format (list (point)))))))
+
+;; Number encoding
+
+(defun json-encode-number (number)
+  "Return a JSON representation of NUMBER."
+  (format "%s" number))
+
+;;; Strings
+
+(defvar json-special-chars
+  '((?\" . ?\")
+    (?\\ . ?\\)
+    (?/ . ?/)
+    (?b . ?\b)
+    (?f . ?\f)
+    (?n . ?\n)
+    (?r . ?\r)
+    (?t . ?\t))
+  "Characters which are escaped in JSON, with their elisp counterparts.")
+
+;; String parsing
+
+(defun json-read-escaped-char ()
+  "Read the JSON string escaped character at point."
+  ;; Skip over the '\'
+  (json-advance)
+  (let* ((char (json-pop))
+         (special (assq char json-special-chars)))
+    (cond
+     (special (cdr special))
+     ((not (eq char ?u)) char)
+     ((looking-at "[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]")
+      (let ((hex (match-string 0)))
+        (json-advance 4)
+        (json-decode-char0 'ucs (string-to-number hex 16))))
+     (t
+      (signal 'json-string-escape (list (point)))))))
+
+(defun json-read-string ()
+  "Read the JSON string at point."
+  (unless (char-equal (json-peek) ?\")
+    (signal 'json-string-format (list "doesn't start with '\"'!")))
+  ;; Skip over the '"'
+  (json-advance)
+  (let ((characters '())
+        (char (json-peek)))
+    (while (not (char-equal char ?\"))
+      (push (if (char-equal char ?\\)
+                (json-read-escaped-char)
+              (json-pop))
+            characters)
+      (setq char (json-peek)))
+    ;; Skip over the '"'
+    (json-advance)
+    (if characters
+        (apply 'string (nreverse characters))
+      "")))
+
+;; String encoding
+
+(defun json-encode-char (char)
+  "Encode CHAR as a JSON string."
+  (setq char (json-encode-char0 char 'ucs))
+  (let ((control-char (car (rassoc char json-special-chars))))
+    (cond
+     ;; Special JSON character (\n, \r, etc.)
+     (control-char
+      (format "\\%c" control-char))
+     ;; ASCIIish printable character
+     ((and (> char 31) (< char 161))
+      (format "%c" char))
+     ;; Fallback: UCS code point in \uNNNN form
+     (t
+      (format "\\u%04x" char)))))
+
+(defun json-encode-string (string)
+  "Return a JSON representation of STRING."
+  (format "\"%s\"" (mapconcat 'json-encode-char string "")))
+
+;;; JSON Objects
+
+(defun json-new-object ()
+  "Create a new Elisp object corresponding to a JSON object.
+Please see the documentation of `json-object-type'."
+  (cond ((eq json-object-type 'hash-table)
+         (make-hash-table :test 'equal))
+        (t
+         (list))))
+
+(defun json-add-to-object (object key value)
+  "Add a new KEY -> VALUE association to OBJECT.
+Returns the updated object, which you should save, e.g.:
+    (setq obj (json-add-to-object obj \"foo\" \"bar\"))
+Please see the documentation of `json-object-type' and `json-key-type'."
+  (let ((json-key-type
+         (if (eq json-key-type nil)
+             (cdr (assq json-object-type '((hash-table . string)
+                                           (alist . symbol)
+                                           (plist . keyword))))
+           json-key-type)))
+    (setq key
+          (cond ((eq json-key-type 'string)
+                 key)
+                ((eq json-key-type 'symbol)
+                 (intern key))
+                ((eq json-key-type 'keyword)
+                 (intern (concat ":" key)))))
+    (cond ((eq json-object-type 'hash-table)
+           (puthash key value object)
+           object)
+          ((eq json-object-type 'alist)
+           (cons (cons key value) object))
+          ((eq json-object-type 'plist)
+           (cons key (cons value object))))))
+
+;; JSON object parsing
+
+(defun json-read-object ()
+  "Read the JSON object at point."
+  ;; Skip over the "{"
+  (json-advance)
+  (json-skip-whitespace)
+  ;; read key/value pairs until "}"
+  (let ((elements (json-new-object))
+        key value)
+    (while (not (char-equal (json-peek) ?}))
+      (json-skip-whitespace)
+      (setq key (json-read-string))
+      (json-skip-whitespace)
+      (if (char-equal (json-peek) ?:)
+          (json-advance)
+        (signal 'json-object-format (list ":" (json-peek))))
+      (setq value (json-read))
+      (setq elements (json-add-to-object elements key value))
+      (json-skip-whitespace)
+      (unless (char-equal (json-peek) ?})
+        (if (char-equal (json-peek) ?,)
+            (json-advance)
+          (signal 'json-object-format (list "," (json-peek))))))
+    ;; Skip over the "}"
+    (json-advance)
+    elements))
+
+;; Hash table encoding
+
+(defun json-encode-hash-table (hash-table)
+  "Return a JSON representation of HASH-TABLE."
+  (format "{%s}"
+          (json-join
+           (let (r)
+             (maphash
+              (lambda (k v)
+                (push (format "%s:%s"
+                              (json-encode k)
+                              (json-encode v))
+                      r))
+              hash-table)
+             r)
+           ", ")))
+
+;; List encoding (including alists and plists)
+
+(defun json-encode-alist (alist)
+  "Return a JSON representation of ALIST."
+  (format "{%s}"
+          (json-join (mapcar (lambda (cons)
+                               (format "%s:%s"
+                                       (json-encode (car cons))
+                                       (json-encode (cdr cons))))
+                             alist)
+                     ", ")))
+
+(defun json-encode-plist (plist)
+  "Return a JSON representation of PLIST."
+  (let (result)
+    (while plist
+      (push (concat (json-encode (car plist))
+                    ":"
+                    (json-encode (cadr plist)))
+            result)
+      (setq plist (cddr plist)))
+    (concat "{" (json-join (nreverse result) ", ") "}")))
+
+(defun json-encode-list (list)
+  "Return a JSON representation of LIST.
+Tries to DWIM: simple lists become JSON arrays, while alists and plists
+become JSON objects."
+  (cond ((null list)         "null")
+        ((json-alist-p list) (json-encode-alist list))
+        ((json-plist-p list) (json-encode-plist list))
+        ((listp list)        (json-encode-array list))
+        (t
+         (signal 'json-error (list list)))))
+
+;;; Arrays
+
+;; Array parsing
+
+(defun json-read-array ()
+  "Read the JSON array at point."
+  ;; Skip over the "["
+  (json-advance)
+  (json-skip-whitespace)
+  ;; read values until "]"
+  (let (elements)
+    (while (not (char-equal (json-peek) ?\]))
+      (push (json-read) elements)
+      (json-skip-whitespace)
+      (unless (char-equal (json-peek) ?\])
+        (if (char-equal (json-peek) ?,)
+            (json-advance)
+          (signal 'json-error (list 'bleah)))))
+    ;; Skip over the "]"
+    (json-advance)
+    (apply json-array-type (nreverse elements))))
+
+;; Array encoding
+
+(defun json-encode-array (array)
+  "Return a JSON representation of ARRAY."
+  (concat "[" (mapconcat 'json-encode array ", ") "]"))
+
+\f
+
+;;; JSON reader.
+
+(defvar json-readtable
+  (let ((table
+         '((?t json-read-keyword "true")
+           (?f json-read-keyword "false")
+           (?n json-read-keyword "null")
+           (?{ json-read-object)
+           (?\[ json-read-array)
+           (?\" json-read-string))))
+    (mapc (lambda (char)
+            (push (list char 'json-read-number) table))
+          '(?- ?+ ?. ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9))
+    table)
+  "Readtable for JSON reader.")
+
+(defun json-read ()
+  "Parse and return the JSON object following point.
+Advances point just past JSON object."
+  (json-skip-whitespace)
+  (let ((char (json-peek)))
+    (if (not (eq char :json-eof))
+        (let ((record (cdr (assq char json-readtable))))
+          (if (functionp (car record))
+              (apply (car record) (cdr record))
+            (signal 'json-readtable-error record)))
+      (signal 'end-of-file nil))))
+
+;; Syntactic sugar for the reader
+
+(defun json-read-from-string (string)
+  "Read the JSON object contained in STRING and return it."
+  (with-temp-buffer
+    (insert string)
+    (goto-char (point-min))
+    (json-read)))
+
+(defun json-read-file (file)
+  "Read the first JSON object contained in FILE and return it."
+  (with-temp-buffer
+    (insert-file-contents file)
+    (goto-char (point-min))
+    (json-read)))
+
+\f
+
+;;; JSON encoder
+
+(defun json-encode (object)
+  "Return a JSON representation of OBJECT as a string."
+  (cond ((memq object (list t json-null json-false))
+         (json-encode-keyword object))
+        ((stringp object)      (json-encode-string object))
+        ((keywordp object)     (json-encode-string
+                                (substring (symbol-name object) 1)))
+        ((symbolp object)      (json-encode-string
+                                (symbol-name object)))
+        ((numberp object)      (json-encode-number object))
+        ((arrayp object)       (json-encode-array object))
+        ((hash-table-p object) (json-encode-hash-table object))
+        ((listp object)        (json-encode-list object))
+        (t                     (signal 'json-error (list object)))))
+
+(provide 'json)
+
+;;; json.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-fun.el b/xemacs-packages/gnus/lisp/gnus-fun.el
new file mode 100644 (file)
index 0000000..fa78b5c
--- /dev/null
@@ -0,0 +1,339 @@
+;;; gnus-fun.el --- various frivolous extension functions to Gnus
+
+;; Copyright (C) 2002-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile
+  (require 'cl))
+
+(require 'mm-util)
+(require 'gnus-ems)
+(require 'gnus-util)
+(require 'gnus)
+
+(defvar gnus-face-properties-alist)
+
+(defcustom gnus-x-face-directory (expand-file-name "x-faces" gnus-directory)
+  "*Directory where X-Face PBM files are stored."
+  :version "22.1"
+  :group 'gnus-fun
+  :type 'directory)
+
+(defcustom gnus-x-face-omit-files nil
+  "Regexp to match faces in `gnus-x-face-directory' to be omitted."
+  :version "25.1"
+  :group 'gnus-fun
+  :type 'string)
+
+(defcustom gnus-face-directory (expand-file-name "faces" gnus-directory)
+  "*Directory where Face PNG files are stored."
+  :version "25.1"
+  :group 'gnus-fun
+  :type 'directory)
+
+(defcustom gnus-face-omit-files nil
+  "Regexp to match faces in `gnus-face-directory' to be omitted."
+  :version "25.1"
+  :group 'gnus-fun
+  :type 'string)
+
+(defcustom gnus-convert-pbm-to-x-face-command "pbmtoxbm %s | compface"
+  "Command for converting a PBM to an X-Face."
+  :version "22.1"
+  :group 'gnus-fun
+  :type 'string)
+
+(defcustom gnus-convert-image-to-x-face-command
+  "convert -scale 48x48! %s xbm:- | xbm2xface.pl"
+  "Command for converting an image to an X-Face.
+The command must take a image filename (use \"%s\") as input.
+The output must be the X-Face header data on stdout."
+  :version "22.1"
+  :group 'gnus-fun
+  :type '(choice (const :tag "giftopnm, netpbm (GIF input only)"
+                       "giftopnm %s | ppmnorm | pnmscale -width 48 -height 48 | ppmtopgm | pgmtopbm | pbmtoxbm | compface")
+                (const :tag "convert"
+                       "convert -scale 48x48! %s xbm:- | xbm2xface.pl")
+                (string)))
+
+(defcustom gnus-convert-image-to-face-command
+  "convert -scale 48x48! %s -colors %d png:-"
+  "Command for converting an image to a Face.
+
+The command must take an image filename (first format argument
+\"%s\") and the number of colors (second format argument: \"%d\")
+as input.  The output must be the Face header data on stdout in
+PNG format."
+  :version "22.1"
+  :group 'gnus-fun
+  :type '(choice (const :tag "djpeg, netpbm (JPG input only)"
+                       "djpeg %s | ppmnorm | pnmscale -width 48 -height 48 | ppmquant %d | pnmtopng")
+                (const :tag "convert"
+                       "convert -scale 48x48! %s -colors %d png:-")
+                (string)))
+
+(defun gnus-shell-command-to-string (command)
+  "Like `shell-command-to-string' except not mingling ERROR."
+  (with-output-to-string
+    (call-process shell-file-name nil (list standard-output nil)
+                 nil shell-command-switch command)))
+
+;;;###autoload
+(defun gnus--random-face-with-type (dir ext omit fun)
+  "Return file from DIR with extension EXT, omitting matches of OMIT, processed by FUN."
+  (when (file-exists-p dir)
+    (let* ((files
+            (remove nil (mapcar
+                         (lambda (f) (unless (string-match (or omit "^$") f) f))
+                         (directory-files dir t ext))))
+           (file (nth (random (length files)) files)))
+      (when file
+        (funcall fun file)))))
+
+;;;###autoload
+(autoload 'message-goto-eoh "message" nil t)
+(autoload 'message-insert-header "message" nil t)
+
+(defun gnus--insert-random-face-with-type (fun type)
+  "Get a random face using FUN and insert it as a header TYPE.
+
+For instance, to insert an X-Face use `gnus-random-x-face' as FUN
+  and \"X-Face\" as TYPE."
+  (let ((data (funcall fun)))
+    (save-excursion
+      (if data
+          (progn (message-goto-eoh)
+                 (insert  type ": " data "\n"))
+       (message
+        "No face returned by the function %s." (symbol-name fun))))))
+
+
+
+;;;###autoload
+(defun gnus-random-x-face ()
+  "Return X-Face header data chosen randomly from `gnus-x-face-directory'.
+
+Files matching `gnus-x-face-omit-files' are not considered."
+  (interactive)
+  (gnus--random-face-with-type gnus-x-face-directory "\\.pbm$" gnus-x-face-omit-files
+                         (lambda (file)
+                           (gnus-shell-command-to-string
+                            (format gnus-convert-pbm-to-x-face-command
+                                    (shell-quote-argument file))))))
+
+;;;###autoload
+(defun gnus-insert-random-x-face-header ()
+  "Insert a random X-Face header from `gnus-x-face-directory'."
+  (interactive)
+  (gnus--insert-random-face-with-type 'gnus-random-x-face 'X-Face))
+
+;;;###autoload
+(defun gnus-x-face-from-file (file)
+  "Insert an X-Face header based on an image FILE.
+
+Depending on `gnus-convert-image-to-x-face-command' it may accept
+different input formats."
+  (interactive "fImage file name: ")
+  (when (file-exists-p file)
+    (gnus-shell-command-to-string
+     (format gnus-convert-image-to-x-face-command
+            (shell-quote-argument (expand-file-name file))))))
+
+;;;###autoload
+(defun gnus-face-from-file (file)
+  "Return a Face header based on an image FILE.
+
+Depending on `gnus-convert-image-to-face-command' it may accept
+different input formats."
+  (interactive "fImage file name: ")
+  (when (file-exists-p file)
+    (let ((done nil)
+         (attempt "")
+         (quant 16))
+      (while (and (not done)
+                 (> quant 1))
+       (setq attempt
+             (let ((coding-system-for-read 'binary))
+               (gnus-shell-command-to-string
+                (format gnus-convert-image-to-face-command
+                        (shell-quote-argument (expand-file-name file))
+                        quant))))
+       (if (> (length attempt) 726)
+           (progn
+             (setq quant (- quant (if (< quant 10) 1 2)))
+             (gnus-message 9 "Length %d; trying quant %d"
+                           (length attempt) quant))
+         (setq done t)))
+      (if done
+         (mm-with-unibyte-buffer
+           (insert attempt)
+           (gnus-face-encode))
+       nil))))
+
+(defun gnus-face-encode ()
+  (let ((step 72))
+    (base64-encode-region (point-min) (point-max))
+    (goto-char (point-min))
+    (while (search-forward "\n" nil t)
+      (replace-match ""))
+    (goto-char (point-min))
+    (while (> (- (point-max) (point))
+             step)
+      (forward-char step)
+      (insert "\n ")
+      (setq step 76))
+    (buffer-string)))
+
+;;;###autoload
+(defun gnus-convert-face-to-png (face)
+  "Convert FACE (which is base64-encoded) to a PNG.
+The PNG is returned as a string."
+  (mm-with-unibyte-buffer
+    (insert face)
+    (ignore-errors
+      (base64-decode-region (point-min) (point-max)))
+    (buffer-string)))
+
+;;;###autoload
+(defun gnus-convert-png-to-face (file)
+  "Convert FILE to a Face.
+FILE should be a PNG file that's 48x48 and smaller than or equal to
+726 bytes."
+  (mm-with-unibyte-buffer
+    (insert-file-contents file)
+    (when (> (buffer-size) 726)
+      (error "The file is %d bytes long, which is too long"
+            (buffer-size)))
+    (gnus-face-encode)))
+
+;;;###autoload
+(defun gnus-random-face ()
+  "Return randomly chosen Face from `gnus-face-directory'.
+
+Files matching `gnus-face-omit-files' are not considered."
+  (interactive)
+  (gnus--random-face-with-type gnus-face-directory "\\.png$"
+                         gnus-face-omit-files
+                         'gnus-convert-png-to-face))
+
+;;;###autoload
+(defun gnus-insert-random-face-header ()
+  "Insert a random Face header from `gnus-face-directory'."
+  (gnus--insert-random-face-with-type 'gnus-random-face 'Face))
+
+(defface gnus-x-face '((t (:foreground "black" :background "white")))
+  "Face to show X-Face.
+The colors from this face are used as the foreground and background
+colors of the displayed X-Faces."
+  :group 'gnus-article-headers)
+
+(declare-function article-narrow-to-head   "gnus-art" ())
+(declare-function gnus-article-goto-header "gnus-art" (header))
+(declare-function gnus-add-image           "gnus-art" (category image))
+(declare-function gnus-add-wash-type       "gnus-art" (type))
+
+(defun gnus-display-x-face-in-from (data)
+  "Display the X-Face DATA in the From header."
+  (require 'gnus-art)
+  (let (pbm)
+    (when (or (gnus-image-type-available-p 'xface)
+             (and (gnus-image-type-available-p 'pbm)
+                  (setq pbm (uncompface data))))
+      (save-excursion
+       (save-restriction
+         (article-narrow-to-head)
+         (gnus-article-goto-header "from")
+         (when (bobp)
+           (insert "From: [no 'from' set]\n")
+           (forward-char -17))
+         (gnus-add-image
+          'xface
+          (gnus-put-image
+           (if (gnus-image-type-available-p 'xface)
+               (apply 'gnus-create-image (concat "X-Face: " data) 'xface t
+                      (cdr (assq 'xface gnus-face-properties-alist)))
+             (apply 'gnus-create-image pbm 'pbm t
+                    (cdr (assq 'pbm gnus-face-properties-alist))))
+           nil 'xface))
+         (gnus-add-wash-type 'xface))))))
+
+(defun gnus-grab-cam-x-face ()
+  "Grab a picture off the camera and make it into an X-Face."
+  (interactive)
+  (shell-command "xawtv-remote snap ppm")
+  (let ((file nil))
+    (while (null (setq file (directory-files "/tftpboot/sparky/tmp"
+                                            t "snap.*ppm")))
+      (sleep-for 1))
+    (setq file (car file))
+    (with-temp-buffer
+      (shell-command
+       (format "pnmcut -left 110 -top 30 -width 144 -height 144 '%s' | ppmnorm 2>/dev/null | pnmscale -width 48 | ppmtopgm | pgmtopbm -threshold -value 0.92 | pbmtoxbm | compface"
+              file)
+       (current-buffer))
+      ;;(sleep-for 3)
+      (delete-file file)
+      (buffer-string))))
+
+(defun gnus-grab-cam-face ()
+  "Grab a picture off the camera and make it into an X-Face."
+  (interactive)
+  (shell-command "xawtv-remote snap ppm")
+  (let ((file nil)
+       (tempfile (make-temp-file "gnus-face-" nil ".ppm"))
+       result)
+    (while (null (setq file (directory-files "/tftpboot/sparky/tmp"
+                                            t "snap.*ppm")))
+      (sleep-for 1))
+    (setq file (car file))
+    (shell-command
+     (format "pnmcut -left 110 -top 30 -width 144 -height 144 '%s' | pnmscale -width 48 -height 48 | ppmtopgm >> %s"
+            file tempfile))
+    (let ((gnus-convert-image-to-face-command
+          (format "cat '%%s' | ppmquant %%d | ppmchange %s | pnmtopng"
+                  (gnus-fun-ppm-change-string))))
+      (setq result (gnus-face-from-file tempfile)))
+    (delete-file file)
+    ;;(delete-file tempfile)    ; FIXME why are we not deleting it?!
+    result))
+
+(defun gnus-fun-ppm-change-string ()
+  (let* ((possibilities '("%02x0000" "00%02x00" "0000%02x"
+                         "%02x%02x00" "00%02x%02x" "%02x00%02x"))
+        (format (concat "'#%02x%02x%02x' '#"
+                        (nth (random 6) possibilities)
+                        "'"))
+        (values nil))
+  (dotimes (i 255)
+    (push (format format i i i i i i)
+         values))
+  (mapconcat 'identity values " ")))
+
+(defun gnus-funcall-no-warning (function &rest args)
+  (when (fboundp function)
+    (apply function args)))
+
+(provide 'gnus-fun)
+
+;;; gnus-fun.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-gravatar.el b/xemacs-packages/gnus/lisp/gnus-gravatar.el
new file mode 100644 (file)
index 0000000..deb6e4b
--- /dev/null
@@ -0,0 +1,144 @@
+;;; gnus-gravatar.el --- Gnus Gravatar support
+
+;; Copyright (C) 2010-2016 Free Software Foundation, Inc.
+
+;; Author: Julien Danjou <julien@danjou.info>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'gravatar)
+(require 'gnus-art)
+(require 'mail-extr) ;; Because of binding `mail-extr-disable-voodoo'.
+
+(defgroup gnus-gravatar nil
+  "Gnus Gravatar."
+  :group 'gnus-visual)
+
+(defcustom gnus-gravatar-size nil
+  "How big should gravatars be displayed.
+If nil, default to `gravatar-size'."
+  :type '(choice (const nil) integer)
+  :version "24.1"
+  :group 'gnus-gravatar)
+
+(defcustom gnus-gravatar-properties '(:ascent center :relief 1)
+  "List of image properties applied to Gravatar images."
+  :type 'sexp
+  :version "24.1"
+  :group 'gnus-gravatar)
+
+(defcustom gnus-gravatar-too-ugly gnus-article-x-face-too-ugly
+  "Regexp matching posters whose avatar shouldn't be shown automatically."
+  :type '(choice regexp (const nil))
+  :version "24.1"
+  :group 'gnus-gravatar)
+
+(defun gnus-gravatar-transform-address (header category &optional force)
+  (gnus-with-article-headers
+    (let* ((mail-extr-disable-voodoo t)
+           (mail-extr-ignore-realname-equals-mailbox-name nil)
+          (addresses (mail-extract-address-components
+                      (or (mail-fetch-field header) "") t))
+          (gravatar-size (or gnus-gravatar-size gravatar-size))
+          name)
+      (dolist (address addresses)
+       (when (and (setq name (car address))
+                  (string-match "\\` +" name))
+         (setcar address (setq name (substring name (match-end 0)))))
+       (when (or force
+                 (not (and gnus-gravatar-too-ugly
+                           (or (string-match gnus-gravatar-too-ugly
+                                             (or (cadr address) ""))
+                               (and name
+                                    (string-match gnus-gravatar-too-ugly
+                                                  name))))))
+         (ignore-errors
+           (gravatar-retrieve
+            (cadr address)
+            'gnus-gravatar-insert
+            (list header address category))))))))
+
+(defun gnus-gravatar-insert (gravatar header address category)
+  "Insert GRAVATAR for ADDRESS in HEADER in current article buffer.
+Set image category to CATEGORY."
+  (unless (eq gravatar 'error)
+    (gnus-with-article-buffer
+      (let ((mark (point-marker))
+           (inhibit-point-motion-hooks t)
+           (case-fold-search t))
+       (save-restriction
+         (article-narrow-to-head)
+         ;; The buffer can be gone at this time
+         (when (buffer-live-p (current-buffer))
+           (gnus-article-goto-header header)
+           (mail-header-narrow-to-field)
+           (let ((real-name (car address))
+                 (mail-address (cadr address)))
+             (when (if real-name
+                       (re-search-forward
+                        (concat (gnus-replace-in-string
+                                 (regexp-quote real-name) "[\t ]+" "[\t\n ]+")
+                                "\\|"
+                                (regexp-quote mail-address))
+                        nil t)
+                     (search-forward mail-address nil t))
+               (goto-char (1- (match-beginning 0)))
+               ;; If we're on the " quoting the name, go backward
+               (when (looking-at "[\"<]")
+                 (goto-char (1- (point))))
+               ;; Do not do anything if there's already a gravatar. This can
+               ;; happens if the buffer has been regenerated in the mean time, for
+               ;; example we were fetching someaddress, and then we change to
+               ;; another mail with the same someaddress.
+               (unless (memq 'gnus-gravatar (text-properties-at (point)))
+                 (let ((point (point)))
+                   (unless (featurep 'xemacs)
+                     (setq gravatar (append gravatar gnus-gravatar-properties)))
+                   (gnus-put-image gravatar (buffer-substring (point) (1+ point)) category)
+                   (put-text-property point (point) 'gnus-gravatar address)
+                   (gnus-add-wash-type category)
+                   (gnus-add-image category gravatar)))))))
+       (goto-char (marker-position mark))))))
+
+;;;###autoload
+(defun gnus-treat-from-gravatar (&optional force)
+  "Display gravatar in the From header.
+If gravatar is already displayed, remove it."
+  (interactive (list t)) ;; When type `W D g'
+  (gnus-with-article-buffer
+    (if (memq 'from-gravatar gnus-article-wash-types)
+       (gnus-delete-images 'from-gravatar)
+      (gnus-gravatar-transform-address "from" 'from-gravatar force))))
+
+;;;###autoload
+(defun gnus-treat-mail-gravatar (&optional force)
+  "Display gravatars in the Cc and To headers.
+If gravatars are already displayed, remove them."
+  (interactive (list t)) ;; When type `W D h'
+    (gnus-with-article-buffer
+      (if (memq 'mail-gravatar gnus-article-wash-types)
+          (gnus-delete-images 'mail-gravatar)
+       (gnus-gravatar-transform-address "cc" 'mail-gravatar force)
+       (gnus-gravatar-transform-address "to" 'mail-gravatar force))))
+
+(provide 'gnus-gravatar)
+
+;;; gnus-gravatar.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-group.el b/xemacs-packages/gnus/lisp/gnus-group.el
new file mode 100644 (file)
index 0000000..1cd16a4
--- /dev/null
@@ -0,0 +1,4781 @@
+;;; gnus-group.el --- group mode commands for Gnus
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile
+  (require 'cl))
+(defvar tool-bar-mode)
+
+(require 'gnus)
+(require 'gnus-start)
+(require 'nnmail)
+(require 'gnus-spec)
+(require 'gnus-int)
+(require 'gnus-range)
+(require 'gnus-win)
+(require 'gnus-undo)
+(require 'gmm-utils)
+(require 'time-date)
+(require 'gnus-ems)
+
+(eval-when-compile
+  (require 'mm-url)
+  (let ((features (cons 'gnus-group features)))
+    (require 'gnus-sum))
+  (unless (boundp 'gnus-cache-active-hashtb)
+    (defvar gnus-cache-active-hashtb nil)))
+
+(autoload 'gnus-agent-total-fetched-for "gnus-agent")
+(autoload 'gnus-cache-total-fetched-for "gnus-cache")
+
+(autoload 'gnus-group-make-nnir-group "nnir")
+
+(defcustom gnus-no-groups-message "No news is good news"
+  "*Message displayed by Gnus when no groups are available."
+  :group 'gnus-start
+  :type 'string)
+
+(defcustom gnus-keep-same-level nil
+  "*Non-nil means that the next newsgroup after the current will be on the same level.
+When you type, for instance, `n' after reading the last article in the
+current newsgroup, you will go to the next newsgroup.  If this variable
+is nil, the next newsgroup will be the next from the group
+buffer.
+If this variable is non-nil, Gnus will either put you in the
+next newsgroup with the same level, or, if no such newsgroup is
+available, the next newsgroup with the lowest possible level higher
+than the current level.
+If this variable is `best', Gnus will make the next newsgroup the one
+with the best level."
+  :group 'gnus-group-levels
+  :type '(choice (const nil)
+                (const best)
+                (sexp :tag "other" t)))
+
+(defcustom gnus-group-goto-unread t
+  "*If non-nil, movement commands will go to the next unread and subscribed group."
+  :link '(custom-manual "(gnus)Group Maneuvering")
+  :group 'gnus-group-various
+  :type 'boolean)
+
+(defcustom gnus-goto-next-group-when-activating t
+  "*If non-nil, the \\<gnus-group-mode-map>\\[gnus-group-get-new-news-this-group] command will advance point to the next group."
+  :link '(custom-manual "(gnus)Scanning New Messages")
+  :group 'gnus-group-various
+  :type 'boolean)
+
+(defcustom gnus-permanently-visible-groups nil
+  "*Regexp to match groups that should always be listed in the group buffer.
+This means that they will still be listed even when there are no
+unread articles in the groups.
+
+If nil, no groups are permanently visible."
+  :group 'gnus-group-listing
+  :type '(choice regexp (const nil)))
+
+(defcustom gnus-safe-html-newsgroups "\\`nnrss[+:]"
+  "Groups in which links in html articles are considered all safe.
+The value may be a regexp matching those groups, a list of group names,
+or nil.  This overrides `mm-w3m-safe-url-regexp' (which see).  This is
+effective only when emacs-w3m renders html articles, i.e., in the case
+`mm-text-html-renderer' is set to `w3m'."
+  :version "23.2"
+  :group 'gnus-group-various
+  :type '(choice regexp
+                (repeat :tag "List of group names" (string :tag "Group"))
+                (const nil)))
+
+(defcustom gnus-list-groups-with-ticked-articles t
+  "*If non-nil, list groups that have only ticked articles.
+If nil, only list groups that have unread articles."
+  :group 'gnus-group-listing
+  :type 'boolean)
+
+(defcustom gnus-group-default-list-level gnus-level-subscribed
+  "Default listing level.
+Ignored if `gnus-group-use-permanent-levels' is non-nil."
+  :group 'gnus-group-listing
+  :type '(choice (integer :tag "Level")
+                 (function :tag "Function returning level")))
+
+(defcustom gnus-group-list-inactive-groups t
+  "*If non-nil, inactive groups will be listed."
+  :group 'gnus-group-listing
+  :group 'gnus-group-levels
+  :type 'boolean)
+
+(defcustom gnus-group-sort-function 'gnus-group-sort-by-alphabet
+  "*Function used for sorting the group buffer.
+This function will be called with group info entries as the arguments
+for the groups to be sorted.  Pre-made functions include
+`gnus-group-sort-by-alphabet', `gnus-group-sort-by-real-name',
+`gnus-group-sort-by-unread', `gnus-group-sort-by-level',
+`gnus-group-sort-by-score', `gnus-group-sort-by-method',
+`gnus-group-sort-by-server', and `gnus-group-sort-by-rank'.
+
+This variable can also be a list of sorting functions.  In that case,
+the most significant sort function should be the last function in the
+list."
+  :group 'gnus-group-listing
+  :link '(custom-manual "(gnus)Sorting Groups")
+  :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:%B%(%g%)\n"
+  "*Format of group lines.
+It works along the same lines as a normal formatting string,
+with some simple extensions.
+
+%M    Only marked articles (character, \"*\" or \" \")
+%S    Whether the group is subscribed (character, \"U\", \"K\", \"Z\" or \" \")
+%L    Level of subscribedness (integer)
+%N    Number of unread articles (integer)
+%I    Number of dormant articles (integer)
+%i    Number of ticked and dormant (integer)
+%T    Number of ticked articles (integer)
+%R    Number of read articles (integer)
+%U    Number of unseen articles (integer)
+%t    Estimated total number of articles (integer)
+%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'.
+%C    Group comment (string)
+%D    Group description (string)
+%s    Select method (string)
+%o    Moderated group (char, \"m\")
+%p    Process mark (char)
+%B    Whether a summary buffer for the group is open (char, \"*\")
+%O    Moderated group (string, \"(m)\" or \"\")
+%P    Topic indentation (string)
+%m    Whether there is new(ish) mail in the group (char, \"%\")
+%n    Select from where (string)
+%z    A string that look like `<%s:%n>' if a foreign select method is used
+%d    The date the group was last entered.
+%E    Icon as defined by `gnus-group-icon-list'.
+%F    The disk space used by the articles fetched by both the cache and agent.
+%u    User defined specifier.  The next character in the format string should
+      be a letter.  Gnus will call the function gnus-user-format-function-X,
+      where X is the letter following %u.  The function will be passed a
+      single dummy parameter as argument.  The function should return a
+      string, which will be inserted into the buffer just like information
+      from any other group specifier.
+
+Note that this format specification is not always respected.  For
+reasons of efficiency, when listing killed groups, this specification
+is ignored altogether.  If the spec is changed considerably, your
+output may end up looking strange when listing both alive and killed
+groups.
+
+If you use %o or %O, reading the active file will be slower and quite
+a bit of extra memory will be used.  %D and %F will also worsen
+performance.  Also note that if you change the format specification to
+include any of these specs, you must probably re-start Gnus to see
+them go into effect.
+
+General format specifiers can also be used.
+See Info node `(gnus)Formatting Variables'."
+  :link '(custom-manual "(gnus)Formatting Variables")
+  :group 'gnus-group-visual
+  :type 'string)
+
+(defcustom gnus-group-mode-line-format "Gnus: %%b {%M\ %:%S}"
+  "*The format specification for the group mode line.
+It works along the same lines as a normal formatting string,
+with some simple extensions:
+
+%S   The native news server.
+%M   The native select method.
+%:   \":\" if %S isn't \"\"."
+  :group 'gnus-group-visual
+  :type 'string)
+
+;; 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)
+  (add-hook 'gnus-group-mode-hook 'gnus-xmas-setup-group-toolbar))
+
+(defcustom gnus-group-menu-hook nil
+  "Hook run after the creation of the group mode menu."
+  :group 'gnus-group-various
+  :type 'hook)
+
+(defcustom gnus-group-catchup-group-hook nil
+  "Hook run when catching up a group from the group buffer."
+  :group 'gnus-group-various
+  :link '(custom-manual "(gnus)Group Data")
+  :type 'hook)
+
+(defcustom gnus-group-update-group-hook nil
+  "Hook called when updating group lines."
+  :group 'gnus-group-visual
+  :type 'hook)
+
+(defcustom gnus-group-prepare-function 'gnus-group-prepare-flat
+  "*A function that is called to generate the group buffer.
+The function is called with three arguments: The first is a number;
+all group with a level less or equal to that number should be listed,
+if the second is non-nil, empty groups should also be displayed.  If
+the third is non-nil, it is a number.  No groups with a level lower
+than this number should be displayed.
+
+The only current function implemented is `gnus-group-prepare-flat'."
+  :group 'gnus-group-listing
+  :type 'function)
+
+(defcustom gnus-group-prepare-hook nil
+  "Hook called after the group buffer has been generated.
+If you want to modify the group buffer, you can use this hook."
+  :group 'gnus-group-listing
+  :type 'hook)
+
+(defcustom gnus-suspend-gnus-hook nil
+  "Hook called when suspending (not exiting) Gnus."
+  :group 'gnus-exit
+  :type 'hook)
+
+(defcustom gnus-exit-gnus-hook nil
+  "Hook called when exiting Gnus."
+  :group 'gnus-exit
+  :type 'hook)
+
+(defcustom gnus-after-exiting-gnus-hook nil
+  "Hook called after exiting Gnus."
+  :group 'gnus-exit
+  :type 'hook)
+
+(defcustom gnus-group-update-hook nil
+  "Hook called when a group line is changed."
+  :group 'gnus-group-visual
+  :version "24.1"
+  :type 'hook)
+
+(defcustom gnus-useful-groups
+  '(("(ding) mailing list mirrored at gmane.org"
+     "gmane.emacs.gnus.general"
+     (nntp "Gmane"
+          (nntp-address "news.gmane.org")))
+    ("Gnus bug archive"
+     "gnus.gnus-bug"
+     (nntp "news.gnus.org"
+          (nntp-address "news.gnus.org")))
+    ("Local Gnus help group"
+     "gnus-help"
+     (nndoc "gnus-help"
+           (nndoc-article-type mbox)
+           (eval `(nndoc-address
+                   ,(let ((file (nnheader-find-etc-directory
+                                 "gnus-tut.txt" t)))
+                      (unless file
+                        (error "Couldn't find doc group"))
+                      file))))))
+  "*Alist of useful group-server pairs."
+  :group 'gnus-group-listing
+  :type '(repeat (list (string :tag "Description")
+                      (string :tag "Name")
+                      (sexp :tag "Method"))))
+
+(defcustom gnus-group-highlight
+  '(;; Mail.
+    ((and mailp (= unread 0) (eq level 1)) .
+     gnus-group-mail-1-empty)
+    ((and mailp (eq level 1)) .
+     gnus-group-mail-1)
+    ((and mailp (= unread 0) (eq level 2)) .
+     gnus-group-mail-2-empty)
+    ((and mailp (eq level 2)) .
+     gnus-group-mail-2)
+    ((and mailp (= unread 0) (eq level 3)) .
+     gnus-group-mail-3-empty)
+    ((and mailp (eq level 3)) .
+     gnus-group-mail-3)
+    ((and mailp (= unread 0)) .
+     gnus-group-mail-low-empty)
+    ((and mailp) .
+     gnus-group-mail-low)
+    ;; News.
+    ((and (= unread 0) (eq level 1)) .
+     gnus-group-news-1-empty)
+    ((and (eq level 1)) .
+     gnus-group-news-1)
+    ((and (= unread 0) (eq level 2)) .
+     gnus-group-news-2-empty)
+    ((and (eq level 2)) .
+     gnus-group-news-2)
+    ((and (= unread 0) (eq level 3)) .
+     gnus-group-news-3-empty)
+    ((and (eq level 3)) .
+     gnus-group-news-3)
+    ((and (= unread 0) (eq level 4)) .
+     gnus-group-news-4-empty)
+    ((and (eq level 4)) .
+     gnus-group-news-4)
+    ((and (= unread 0) (eq level 5)) .
+     gnus-group-news-5-empty)
+    ((and (eq level 5)) .
+     gnus-group-news-5)
+    ((and (= unread 0) (eq level 6)) .
+     gnus-group-news-6-empty)
+    ((and (eq level 6)) .
+     gnus-group-news-6)
+    ((and (= unread 0)) .
+     gnus-group-news-low-empty)
+    (t .
+     gnus-group-news-low))
+  "*Controls the highlighting of group buffer lines.
+
+Below is a list of `Form'/`Face' pairs.  When deciding how a
+particular group line should be displayed, each form is
+evaluated.  The content of the face field after the first true form is
+used.  You can change how those group lines are displayed by
+editing the face field.
+
+It is also possible to change and add form fields, but currently that
+requires an understanding of Lisp expressions.  Hopefully this will
+change in a future release.  For now, you can use the following
+variables in the Lisp expression:
+
+group: The name of the group.
+unread: The number of unread articles in the group.
+method: The select method used.
+mailp: Whether it's a mail group or not.
+level: The level of the group.
+score: The score of the group.
+ticked: The number of ticked articles."
+  :group 'gnus-group-visual
+  :type '(repeat (cons (sexp :tag "Form") face)))
+(put 'gnus-group-highlight 'risky-local-variable t)
+
+(defcustom gnus-new-mail-mark ?%
+  "Mark used for groups with new mail."
+  :group 'gnus-group-visual
+  :type 'character)
+
+(defgroup gnus-group-icons nil
+  "Add Icons to your group buffer."
+  :group 'gnus-group-visual)
+
+(defcustom gnus-group-icon-list
+  nil
+  "*Controls the insertion of icons into group buffer lines.
+
+Below is a list of `Form'/`File' pairs.  When deciding how a
+particular group line should be displayed, each form is evaluated.
+The icon from the file field after the first true form is used.  You
+can change how those group lines are displayed by editing the file
+field.  The File will either be found in the
+`gnus-group-glyph-directory' or by designating absolute name of the
+file.
+
+It is also possible to change and add form fields, but currently that
+requires an understanding of Lisp expressions.  Hopefully this will
+change in a future release.  For now, you can use the following
+variables in the Lisp expression:
+
+group: The name of the group.
+unread: The number of unread articles in the group.
+method: The select method used.
+mailp: Whether it's a mail group or not.
+level: The level of the group.
+score: The score of the group.
+ticked: The number of ticked articles."
+  :group 'gnus-group-icons
+  :type '(repeat (cons (sexp :tag "Form") file)))
+(put 'gnus-group-icon-list 'risky-local-variable t)
+
+(defcustom gnus-group-name-charset-method-alist nil
+  "Alist of method and the charset for group names.
+
+For example:
+    (((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
+  (if (or (and (fboundp 'find-coding-system) (find-coding-system 'utf-8))
+         (mm-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))"
+  :group 'gnus-charset
+  :type '(repeat (cons (regexp :tag "Group") (symbol :tag "Charset"))))
+
+(defcustom gnus-group-jump-to-group-prompt nil
+  "Default prompt for `gnus-group-jump-to-group'.
+
+If non-nil, the value should be a string or an alist.  If it is a string,
+e.g. \"nnml:\", in which case `gnus-group-jump-to-group' offers \"Group:
+nnml:\" in the minibuffer prompt.
+
+If it is an alist, it must consist of \(NUMBER .  PROMPT) pairs, for example:
+\((1 .  \"\") (2 .  \"nnfolder+archive:\")).  The element with number 0 is
+used when no prefix argument is given to `gnus-group-jump-to-group'."
+  :version "22.1"
+  :group 'gnus-group-various
+  :type '(choice (string :tag "Prompt string")
+                (const :tag "Empty" nil)
+                (repeat (cons (integer :tag "Argument")
+                              (string :tag "Prompt string")))))
+
+(defvar gnus-group-listing-limit 1000
+  "*A limit of the number of groups when listing.
+If the number of groups is larger than the limit, list them in a
+simple manner.")
+
+;;; Internal variables
+
+(defvar gnus-group-is-exiting-p nil)
+(defvar gnus-group-is-exiting-without-update-p nil)
+(defvar gnus-group-sort-alist-function 'gnus-group-sort-flat
+  "Function for sorting the group buffer.")
+
+(defvar gnus-group-sort-selected-function 'gnus-group-sort-selected-flat
+  "Function for sorting the selected groups in the group buffer.")
+
+(defvar gnus-group-indentation-function nil)
+(defvar gnus-goto-missing-group-function nil)
+(defvar gnus-group-update-group-function nil)
+(defvar gnus-group-goto-next-group-function nil
+  "Function to override finding the next group after listing groups.")
+
+(defvar gnus-group-edit-buffer nil)
+
+(defvar gnus-tmp-news-method)
+(defvar gnus-tmp-colon)
+(defvar gnus-tmp-news-server)
+(defvar gnus-tmp-decoded-group)
+(defvar gnus-tmp-header)
+(defvar gnus-tmp-process-marked)
+(defvar gnus-tmp-summary-live)
+(defvar gnus-tmp-news-method-string)
+(defvar gnus-tmp-group-icon)
+(defvar gnus-tmp-moderated-string)
+(defvar gnus-tmp-newsgroup-description)
+(defvar gnus-tmp-comment)
+(defvar gnus-tmp-qualified-group)
+(defvar gnus-tmp-subscribed)
+(defvar gnus-tmp-number-of-read)
+(defvar gnus-inhibit-demon)
+(defvar gnus-pick-mode)
+(defvar gnus-tmp-marked-mark)
+(defvar gnus-tmp-number-of-unread)
+
+(defvar gnus-group-line-format-alist
+  `((?M gnus-tmp-marked-mark ?c)
+    (?S gnus-tmp-subscribed ?c)
+    (?L gnus-tmp-level ?d)
+    (?N (cond ((eq number t) "*" )
+             ((numberp number)
+              (int-to-string
+               (+ number
+                  (gnus-range-length (cdr (assq 'dormant gnus-tmp-marked)))
+                  (gnus-range-length (cdr (assq 'tick gnus-tmp-marked))))))
+             (t number)) ?s)
+    (?R gnus-tmp-number-of-read ?s)
+    (?U (if (gnus-active gnus-tmp-group)
+           (gnus-number-of-unseen-articles-in-group gnus-tmp-group)
+         "*")
+       ?s)
+    (?t gnus-tmp-number-total ?d)
+    (?y gnus-tmp-number-of-unread ?s)
+    (?I (gnus-range-length (cdr (assq 'dormant gnus-tmp-marked))) ?d)
+    (?T (gnus-range-length (cdr (assq 'tick gnus-tmp-marked))) ?d)
+    (?i (+ (gnus-range-length (cdr (assq 'dormant gnus-tmp-marked)))
+          (gnus-range-length (cdr (assq 'tick gnus-tmp-marked)))) ?d)
+    (?g (if (boundp 'gnus-tmp-decoded-group)
+           gnus-tmp-decoded-group
+         gnus-tmp-group)
+       ?s)
+    (?G gnus-tmp-qualified-group ?s)
+    (?c (gnus-short-group-name (if (boundp 'gnus-tmp-decoded-group)
+                                  gnus-tmp-decoded-group
+                                gnus-tmp-group))
+       ?s)
+    (?C gnus-tmp-comment ?s)
+    (?D gnus-tmp-newsgroup-description ?s)
+    (?o gnus-tmp-moderated ?c)
+    (?O gnus-tmp-moderated-string ?s)
+    (?p gnus-tmp-process-marked ?c)
+    (?s gnus-tmp-news-server ?s)
+    (?n ,(if (featurep 'xemacs)
+            '(symbol-name gnus-tmp-news-method)
+          'gnus-tmp-news-method)
+       ?s)
+    (?P gnus-group-indentation ?s)
+    (?E gnus-tmp-group-icon ?s)
+    (?B gnus-tmp-summary-live ?c)
+    (?z gnus-tmp-news-method-string ?s)
+    (?m (gnus-group-new-mail gnus-tmp-group) ?c)
+    (?d (gnus-group-timestamp-string gnus-tmp-group) ?s)
+    (?u gnus-tmp-user-defined ?s)
+    (?F (gnus-total-fetched-for gnus-tmp-group) ?s)
+    ))
+
+(defvar gnus-group-mode-line-format-alist
+  `((?S gnus-tmp-news-server ?s)
+    (?M gnus-tmp-news-method ?s)
+    (?u gnus-tmp-user-defined ?s)
+    (?: gnus-tmp-colon ?s)))
+
+(defvar gnus-topic-topology nil
+  "The complete topic hierarchy.")
+
+(defvar gnus-topic-alist nil
+  "The complete topic-group alist.")
+
+(defvar gnus-group-marked nil)
+
+(defvar gnus-group-list-mode nil)
+
+
+(defvar gnus-group-listed-groups nil)
+(defvar gnus-group-list-option nil)
+
+;;;
+;;; Gnus group mode
+;;;
+
+(put 'gnus-group-mode 'mode-class 'special)
+
+(gnus-define-keys gnus-group-mode-map
+  " " gnus-group-read-group
+  "=" gnus-group-select-group
+  "\r" gnus-group-select-group
+  "\M-\r" gnus-group-quick-select-group
+  "\M- " gnus-group-visible-select-group
+  [(meta control return)] gnus-group-select-group-ephemerally
+  "j" gnus-group-jump-to-group
+  "n" gnus-group-next-unread-group
+  "p" gnus-group-prev-unread-group
+  "\177" gnus-group-prev-unread-group
+  [delete] gnus-group-prev-unread-group
+  "N" gnus-group-next-group
+  "P" gnus-group-prev-group
+  "\M-n" gnus-group-next-unread-group-same-level
+  "\M-p" gnus-group-prev-unread-group-same-level
+  "," gnus-group-best-unread-group
+  "." gnus-group-first-unread-group
+  "u" gnus-group-unsubscribe-current-group
+  "U" gnus-group-unsubscribe-group
+  "c" gnus-group-catchup-current
+  "C" gnus-group-catchup-current-all
+  "\M-c" gnus-group-clear-data
+  "l" gnus-group-list-groups
+  "L" gnus-group-list-all-groups
+  "m" gnus-group-mail
+  "i" gnus-group-news
+  "g" gnus-group-get-new-news
+  "\M-g" gnus-group-get-new-news-this-group
+  "R" gnus-group-restart
+  "r" gnus-group-read-init-file
+  "B" gnus-group-browse-foreign-server
+  "b" gnus-group-check-bogus-groups
+  "F" gnus-group-find-new-groups
+  "\C-c\C-d" gnus-group-describe-group
+  "\M-d" gnus-group-describe-all-groups
+  "\C-c\C-a" gnus-group-apropos
+  "\C-c\M-\C-a" gnus-group-description-apropos
+  "a" gnus-group-post-news
+  "\ek" gnus-group-edit-local-kill
+  "\eK" gnus-group-edit-global-kill
+  "\C-k" gnus-group-kill-group
+  "\C-y" gnus-group-yank-group
+  "\C-w" gnus-group-kill-region
+  "\C-x\C-t" gnus-group-transpose-groups
+  "\C-c\C-l" gnus-group-list-killed
+  "\C-c\C-x" gnus-group-expire-articles
+  "\C-c\M-\C-x" gnus-group-expire-all-groups
+  "V" gnus-version
+  "s" gnus-group-save-newsrc
+  "z" gnus-group-suspend
+  "q" gnus-group-exit
+  "Q" gnus-group-quit
+  "?" gnus-group-describe-briefly
+  "\C-c\C-i" gnus-info-find-node
+  "\M-e" gnus-group-edit-group-method
+  "^" gnus-group-enter-server-mode
+  gnus-mouse-2 gnus-mouse-pick-group
+  [follow-link] mouse-face
+  "<" beginning-of-buffer
+  ">" end-of-buffer
+  "\C-c\C-b" gnus-bug
+  "\C-c\C-s" gnus-group-sort-groups
+  "t" gnus-topic-mode
+  "\C-c\M-g" gnus-activate-all-groups
+  "\M-&" gnus-group-universal-argument
+  "#" gnus-group-mark-group
+  "\M-#" gnus-group-unmark-group)
+
+(gnus-define-keys (gnus-group-mark-map "M" gnus-group-mode-map)
+  "m" gnus-group-mark-group
+  "u" gnus-group-unmark-group
+  "w" gnus-group-mark-region
+  "b" gnus-group-mark-buffer
+  "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
+  "u" gnus-group-make-useful-group
+  "l" gnus-group-nnimap-edit-acl
+  "m" gnus-group-make-group
+  "E" gnus-group-edit-group
+  "e" gnus-group-edit-group-method
+  "p" gnus-group-edit-group-parameters
+  "v" gnus-group-add-to-virtual
+  "V" gnus-group-make-empty-virtual
+  "D" gnus-group-enter-directory
+  "f" gnus-group-make-doc-group
+  "w" gnus-group-make-web-group
+  "G" gnus-group-make-nnir-group
+  "M" gnus-group-read-ephemeral-group
+  "r" gnus-group-rename-group
+  "R" gnus-group-make-rss-group
+  "c" gnus-group-customize
+  "z" gnus-group-compact-group
+  "x" gnus-group-expunge-group
+  "\177" gnus-group-delete-group
+  [delete] gnus-group-delete-group)
+
+(gnus-define-keys (gnus-group-sort-map "S" gnus-group-group-map)
+  "s" gnus-group-sort-groups
+  "a" gnus-group-sort-groups-by-alphabet
+  "u" gnus-group-sort-groups-by-unread
+  "l" gnus-group-sort-groups-by-level
+  "v" gnus-group-sort-groups-by-score
+  "r" gnus-group-sort-groups-by-rank
+  "m" gnus-group-sort-groups-by-method
+  "n" gnus-group-sort-groups-by-real-name)
+
+(gnus-define-keys (gnus-group-sort-selected-map "P" gnus-group-group-map)
+  "s" gnus-group-sort-selected-groups
+  "a" gnus-group-sort-selected-groups-by-alphabet
+  "u" gnus-group-sort-selected-groups-by-unread
+  "l" gnus-group-sort-selected-groups-by-level
+  "v" gnus-group-sort-selected-groups-by-score
+  "r" gnus-group-sort-selected-groups-by-rank
+  "m" gnus-group-sort-selected-groups-by-method
+  "n" gnus-group-sort-selected-groups-by-real-name)
+
+(gnus-define-keys (gnus-group-list-map "A" gnus-group-mode-map)
+  "k" gnus-group-list-killed
+  "z" gnus-group-list-zombies
+  "s" gnus-group-list-groups
+  "u" gnus-group-list-all-groups
+  "A" gnus-group-list-active
+  "a" gnus-group-apropos
+  "d" gnus-group-description-apropos
+  "m" gnus-group-list-matching
+  "M" gnus-group-list-all-matching
+  "l" gnus-group-list-level
+  "c" gnus-group-list-cached
+  "?" gnus-group-list-dormant
+  "!" gnus-group-list-ticked)
+
+(gnus-define-keys (gnus-group-list-limit-map "/" gnus-group-list-map)
+  "k"  gnus-group-list-limit
+  "z"  gnus-group-list-limit
+  "s"  gnus-group-list-limit
+  "u"  gnus-group-list-limit
+  "A"  gnus-group-list-limit
+  "m"  gnus-group-list-limit
+  "M"  gnus-group-list-limit
+  "l"  gnus-group-list-limit
+  "c"  gnus-group-list-limit
+  "?"  gnus-group-list-limit
+  "!"  gnus-group-list-limit)
+
+(gnus-define-keys (gnus-group-list-flush-map "f" gnus-group-list-map)
+  "k"  gnus-group-list-flush
+  "z"  gnus-group-list-flush
+  "s"  gnus-group-list-flush
+  "u"  gnus-group-list-flush
+  "A"  gnus-group-list-flush
+  "m"  gnus-group-list-flush
+  "M"  gnus-group-list-flush
+  "l"  gnus-group-list-flush
+  "c"  gnus-group-list-flush
+  "?"  gnus-group-list-flush
+  "!"  gnus-group-list-flush)
+
+(gnus-define-keys (gnus-group-list-plus-map "p" gnus-group-list-map)
+  "k"  gnus-group-list-plus
+  "z"  gnus-group-list-plus
+  "s"  gnus-group-list-plus
+  "u"  gnus-group-list-plus
+  "A"  gnus-group-list-plus
+  "m"  gnus-group-list-plus
+  "M"  gnus-group-list-plus
+  "l"  gnus-group-list-plus
+  "c"  gnus-group-list-plus
+  "?"  gnus-group-list-plus
+  "!"  gnus-group-list-plus)
+
+(gnus-define-keys (gnus-group-score-map "W" gnus-group-mode-map)
+  "f" gnus-score-flush-cache
+  "e" gnus-score-edit-all-score)
+
+(gnus-define-keys (gnus-group-help-map "H" gnus-group-mode-map)
+  "d" gnus-group-describe-group
+  "v" gnus-version)
+
+(gnus-define-keys (gnus-group-sub-map "S" gnus-group-mode-map)
+  "l" gnus-group-set-current-level
+  "t" gnus-group-unsubscribe-current-group
+  "s" gnus-group-unsubscribe-group
+  "k" gnus-group-kill-group
+  "y" gnus-group-yank-group
+  "w" gnus-group-kill-region
+  "\C-k" gnus-group-kill-level
+  "z" gnus-group-kill-all-zombies)
+
+(defun gnus-topic-mode-p ()
+  "Return non-nil in `gnus-topic-mode'."
+  (and (boundp 'gnus-topic-mode)
+       (symbol-value 'gnus-topic-mode)))
+
+(defun gnus-group-make-menu-bar ()
+  (unless (boundp 'gnus-group-reading-menu)
+
+    (easy-menu-define
+     gnus-group-reading-menu gnus-group-mode-map ""
+     `("Group"
+       ["Read" gnus-group-read-group
+       :included (not (gnus-topic-mode-p))
+       :active (gnus-group-group-name)]
+       ["Read " gnus-topic-read-group
+       :included (gnus-topic-mode-p)]
+       ["Select" gnus-group-select-group
+       :included (not (gnus-topic-mode-p))
+       :active (gnus-group-group-name)]
+       ["Select " gnus-topic-select-group
+       :included (gnus-topic-mode-p)]
+       ["See old articles" (gnus-group-select-group 'all)
+       :keys "C-u SPC" :active (gnus-group-group-name)]
+       ["Catch up" gnus-group-catchup-current
+       :included (not (gnus-topic-mode-p))
+       :active (gnus-group-group-name)
+       ,@(if (featurep 'xemacs) nil
+           '(:help "Mark unread articles in the current group as read"))]
+       ["Catch up " gnus-topic-catchup-articles
+       :included (gnus-topic-mode-p)
+       ,@(if (featurep 'xemacs) nil
+           '(:help "Mark unread articles in the current group or topic as read"))]
+       ["Catch up all articles" gnus-group-catchup-current-all
+       (gnus-group-group-name)]
+       ["Check for new articles" gnus-group-get-new-news-this-group
+       :included (not (gnus-topic-mode-p))
+       :active (gnus-group-group-name)
+       ,@(if (featurep 'xemacs) nil
+           '(:help "Check for new messages in current group"))]
+       ["Check for new articles " gnus-topic-get-new-news-this-topic
+       :included (gnus-topic-mode-p)
+       ,@(if (featurep 'xemacs) nil
+           '(:help "Check for new messages in current group or topic"))]
+       ["Toggle subscription" gnus-group-unsubscribe-current-group
+       (gnus-group-group-name)]
+       ["Kill" gnus-group-kill-group :active (gnus-group-group-name)
+       ,@(if (featurep 'xemacs) nil
+             '(:help "Kill (remove) current group"))]
+       ["Yank" gnus-group-yank-group gnus-list-of-killed-groups]
+       ["Describe" gnus-group-describe-group :active (gnus-group-group-name)
+       ,@(if (featurep 'xemacs) nil
+           '(:help "Display description of the current group"))]
+       ;; Actually one should check, if any of the marked groups gives t for
+       ;; (gnus-check-backend-function 'request-expire-articles ...)
+       ["Expire articles" gnus-group-expire-articles
+       :included (not (gnus-topic-mode-p))
+       :active (or (and (gnus-group-group-name)
+                        (gnus-check-backend-function
+                         'request-expire-articles
+                         (gnus-group-group-name))) gnus-group-marked)]
+       ["Expire articles " gnus-topic-expire-articles
+       :included (gnus-topic-mode-p)]
+       ["Set group level..." gnus-group-set-current-level
+       (gnus-group-group-name)]
+       ["Select quick" gnus-group-quick-select-group (gnus-group-group-name)]
+       ["Customize" gnus-group-customize (gnus-group-group-name)]
+       ["Compact" gnus-group-compact-group
+       :active (gnus-group-group-name)]
+       ("Edit"
+       ["Parameters" gnus-group-edit-group-parameters
+        :included (not (gnus-topic-mode-p))
+        :active (gnus-group-group-name)]
+       ["Parameters " gnus-topic-edit-parameters
+        :included (gnus-topic-mode-p)]
+       ["Select method" gnus-group-edit-group-method
+        (gnus-group-group-name)]
+       ["Info" gnus-group-edit-group (gnus-group-group-name)]
+       ["Local kill file" gnus-group-edit-local-kill (gnus-group-group-name)]
+       ["Global kill file" gnus-group-edit-global-kill t])))
+
+    (easy-menu-define
+     gnus-group-group-menu gnus-group-mode-map ""
+     '("Groups"
+       ("Listing"
+       ["List unread subscribed groups" gnus-group-list-groups t]
+       ["List (un)subscribed groups" gnus-group-list-all-groups t]
+       ["List killed groups" gnus-group-list-killed gnus-killed-list]
+       ["List zombie groups" gnus-group-list-zombies gnus-zombie-list]
+       ["List level..." gnus-group-list-level t]
+       ["Describe all groups" gnus-group-describe-all-groups t]
+       ["Group apropos..." gnus-group-apropos t]
+       ["Group and description apropos..." gnus-group-description-apropos t]
+       ["List groups matching..." gnus-group-list-matching t]
+       ["List all groups matching..." gnus-group-list-all-matching t]
+       ["List active file" gnus-group-list-active t]
+       ["List groups with cached" gnus-group-list-cached t]
+       ["List groups with dormant" gnus-group-list-dormant t]
+       ["List groups with ticked" gnus-group-list-ticked t])
+       ("Sort"
+       ["Default sort" gnus-group-sort-groups t]
+       ["Sort by method" gnus-group-sort-groups-by-method t]
+       ["Sort by rank" gnus-group-sort-groups-by-rank t]
+       ["Sort by score" gnus-group-sort-groups-by-score t]
+       ["Sort by level" gnus-group-sort-groups-by-level t]
+       ["Sort by unread" gnus-group-sort-groups-by-unread t]
+       ["Sort by name" gnus-group-sort-groups-by-alphabet t]
+       ["Sort by real name" gnus-group-sort-groups-by-real-name t])
+       ("Sort process/prefixed"
+       ["Default sort" gnus-group-sort-selected-groups
+        (not (gnus-topic-mode-p))]
+       ["Sort by method" gnus-group-sort-selected-groups-by-method
+        (not (gnus-topic-mode-p))]
+       ["Sort by rank" gnus-group-sort-selected-groups-by-rank
+        (not (gnus-topic-mode-p))]
+       ["Sort by score" gnus-group-sort-selected-groups-by-score
+        (not (gnus-topic-mode-p))]
+       ["Sort by level" gnus-group-sort-selected-groups-by-level
+        (not (gnus-topic-mode-p))]
+       ["Sort by unread" gnus-group-sort-selected-groups-by-unread
+        (not (gnus-topic-mode-p))]
+       ["Sort by name" gnus-group-sort-selected-groups-by-alphabet
+        (not (gnus-topic-mode-p))]
+       ["Sort by real name" gnus-group-sort-selected-groups-by-real-name
+        (not (gnus-topic-mode-p))])
+       ("Mark"
+       ["Mark group" gnus-group-mark-group
+        (and (gnus-group-group-name)
+             (not (memq (gnus-group-group-name) gnus-group-marked)))]
+       ["Unmark group" gnus-group-unmark-group
+        (and (gnus-group-group-name)
+             (memq (gnus-group-group-name) gnus-group-marked))]
+       ["Unmark all" gnus-group-unmark-all-groups gnus-group-marked]
+       ["Mark regexp..." gnus-group-mark-regexp t]
+       ["Mark region" gnus-group-mark-region :active (gnus-mark-active-p)]
+       ["Mark buffer" gnus-group-mark-buffer t]
+       ["Execute command" gnus-group-universal-argument
+        (or gnus-group-marked (gnus-group-group-name))])
+       ("Subscribe"
+       ["Subscribe to a group..." gnus-group-unsubscribe-group t]
+       ["Kill all newsgroups in region" gnus-group-kill-region
+        :active (gnus-mark-active-p)]
+       ["Kill all zombie groups" gnus-group-kill-all-zombies
+        gnus-zombie-list]
+       ["Kill all groups on level..." gnus-group-kill-level t])
+       ("Foreign groups"
+       ["Make a foreign group..." gnus-group-make-group t]
+       ["Add a directory group..." gnus-group-make-directory-group t]
+       ["Add the help group" gnus-group-make-help-group t]
+       ["Make a doc group..." gnus-group-make-doc-group t]
+       ["Make a web group..." gnus-group-make-web-group t]
+       ["Make a search group..." gnus-group-make-nnir-group t]
+       ["Make a virtual group..." gnus-group-make-empty-virtual t]
+       ["Add a group to a virtual..." gnus-group-add-to-virtual t]
+       ["Make an ephemeral group..." gnus-group-read-ephemeral-group t]
+       ["Make an RSS group..." gnus-group-make-rss-group t]
+       ["Rename group..." gnus-group-rename-group
+        (gnus-check-backend-function
+         'request-rename-group (gnus-group-group-name))]
+       ["Delete group" gnus-group-delete-group
+        (gnus-check-backend-function
+         'request-delete-group (gnus-group-group-name))])
+       ("Move"
+       ["Next" gnus-group-next-group t]
+       ["Previous" gnus-group-prev-group t]
+       ["Next unread" gnus-group-next-unread-group t]
+       ["Previous unread" gnus-group-prev-unread-group t]
+       ["Next unread same level" gnus-group-next-unread-group-same-level t]
+       ["Previous unread same level"
+        gnus-group-prev-unread-group-same-level t]
+       ["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
+       (gnus-group-group-name)]
+       ["Read a directory as a group..." gnus-group-enter-directory t]))
+
+    (easy-menu-define
+     gnus-group-misc-menu gnus-group-mode-map ""
+     `("Gnus"
+       ["Send a mail" gnus-group-mail 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]
+       ["Browse foreign server..." gnus-group-browse-foreign-server t]
+       ["Enter server buffer" gnus-group-enter-server-mode t]
+       ["Expire all expirable articles" gnus-group-expire-all-groups t]
+       ["Gnus version" gnus-version t]
+       ["Save .newsrc files" gnus-group-save-newsrc t]
+       ["Suspend Gnus" gnus-group-suspend t]
+       ["Clear dribble buffer" gnus-group-clear-dribble t]
+       ["Read manual" gnus-info-find-node t]
+       ["Flush score cache" gnus-score-flush-cache t]
+       ["Toggle topics" gnus-topic-mode t]
+       ["Send a bug report" gnus-bug t]
+       ["Exit from Gnus" gnus-group-exit
+       ,@(if (featurep 'xemacs) '(t)
+           '(:help "Quit reading news"))]
+       ["Exit without saving" gnus-group-quit t]))
+
+    (gnus-run-hooks 'gnus-group-menu-hook)))
+
+
+(defvar gnus-group-tool-bar-map nil)
+
+(defun gnus-group-tool-bar-update (&optional symbol value)
+  "Update group buffer toolbar.
+Setter function for custom variables."
+  (when symbol
+    (set-default symbol value))
+  ;; (setq-default gnus-group-tool-bar-map nil)
+  ;; (use-local-map gnus-group-mode-map)
+  (when (gnus-alive-p)
+    (with-current-buffer gnus-group-buffer
+      (gnus-group-make-tool-bar t))))
+
+(defcustom gnus-group-tool-bar (if (eq gmm-tool-bar-style 'gnome)
+                                  'gnus-group-tool-bar-gnome
+                                'gnus-group-tool-bar-retro)
+  "Specifies the Gnus group tool bar.
+
+It can be either a list or a symbol referring to a list.  See
+`gmm-tool-bar-from-list' for the format of the list.  The
+default key map is `gnus-group-mode-map'.
+
+Pre-defined symbols include `gnus-group-tool-bar-gnome' and
+`gnus-group-tool-bar-retro'."
+  :type '(choice (const :tag "GNOME style" gnus-group-tool-bar-gnome)
+                (const :tag "Retro look" gnus-group-tool-bar-retro)
+                (repeat :tag "User defined list" gmm-tool-bar-item)
+                (symbol))
+  :version "23.1" ;; No Gnus
+  :initialize 'custom-initialize-default
+  :set 'gnus-group-tool-bar-update
+  :group 'gnus-group)
+
+(defcustom gnus-group-tool-bar-gnome
+  '((gnus-group-post-news "mail/compose")
+    ;; Some useful agent icons?  I don't use the agent so agent users should
+    ;; suggest useful commands:
+    (gnus-agent-toggle-plugged "unplugged" t
+                              :help "Gnus is currently unplugged.  Click to work online."
+                              :visible (and gnus-agent (not gnus-plugged)))
+    (gnus-agent-toggle-plugged "plugged" t
+                              :help "Gnus is currently plugged.  Click to work offline."
+                              :visible (and gnus-agent gnus-plugged))
+    ;; FIXME: gnus-agent-toggle-plugged (in gnus-agent-group-make-menu-bar)
+    ;; should have a better help text.
+    (gnus-group-send-queue "mail/outbox" t
+                          :visible (and gnus-agent gnus-plugged)
+                          :help "Send articles from the queue group")
+    (gnus-group-get-new-news "mail/inbox" nil
+                            :visible (or (not gnus-agent)
+                                         gnus-plugged))
+    ;; FIXME: gnus-*-read-group should have a better help text.
+    (gnus-topic-read-group "open" nil
+                          :visible (and (boundp 'gnus-topic-mode)
+                                        gnus-topic-mode))
+    (gnus-group-read-group "open" nil
+                          :visible (not (and (boundp 'gnus-topic-mode)
+                                             gnus-topic-mode)))
+    ;; (gnus-group-find-new-groups "???" nil)
+    (gnus-group-save-newsrc "save")
+    (gnus-group-describe-group "describe")
+    (gnus-group-unsubscribe-current-group "gnus/toggle-subscription")
+    (gnus-group-prev-unread-group "left-arrow")
+    (gnus-group-next-unread-group "right-arrow")
+    (gnus-group-exit "exit")
+    (gmm-customize-mode "preferences" t :help "Edit mode preferences")
+    (gnus-info-find-node "help"))
+  "List of functions for the group tool bar (GNOME style).
+
+See `gmm-tool-bar-from-list' for the format of the list."
+  :type '(repeat gmm-tool-bar-item)
+  :version "23.1" ;; No Gnus
+  :initialize 'custom-initialize-default
+  :set 'gnus-group-tool-bar-update
+  :group 'gnus-group)
+
+(defcustom gnus-group-tool-bar-retro
+  '((gnus-group-get-new-news "gnus/get-news")
+    (gnus-group-get-new-news-this-group "gnus/gnntg")
+    (gnus-group-catchup-current "gnus/catchup")
+    (gnus-group-describe-group "gnus/describe-group")
+    (gnus-group-subscribe "gnus/subscribe" t
+                         :help "Subscribe to the current group")
+    (gnus-group-unsubscribe "gnus/unsubscribe" t
+                           :help "Unsubscribe from the current group")
+    (gnus-group-exit "gnus/exit-gnus" gnus-group-mode-map))
+  "List of functions for the group tool bar (retro look).
+
+See `gmm-tool-bar-from-list' for the format of the list."
+  :type '(repeat gmm-tool-bar-item)
+  :version "23.1" ;; No Gnus
+  :initialize 'custom-initialize-default
+  :set 'gnus-group-tool-bar-update
+  :group 'gnus-group)
+
+(defcustom gnus-group-tool-bar-zap-list t
+  "List of icon items from the global tool bar.
+These items are not displayed in the Gnus group mode tool bar.
+
+See `gmm-tool-bar-from-list' for the format of the list."
+  :type 'gmm-tool-bar-zap-list
+  :version "23.1" ;; No Gnus
+  :initialize 'custom-initialize-default
+  :set 'gnus-group-tool-bar-update
+  :group 'gnus-group)
+
+(defvar image-load-path)
+(defvar tool-bar-map)
+
+(defun gnus-group-make-tool-bar (&optional force)
+  "Make a group mode tool bar from `gnus-group-tool-bar'.
+When FORCE, rebuild the tool bar."
+  (when (and (not (featurep 'xemacs))
+            (boundp 'tool-bar-mode)
+            tool-bar-mode
+             (display-graphic-p)
+            (or (not gnus-group-tool-bar-map) force))
+    (let* ((load-path
+           (gmm-image-load-path-for-library "gnus"
+                                            "gnus/toggle-subscription.xpm"
+                                            nil t))
+           (image-load-path (cons (car load-path)
+                                  (when (boundp 'image-load-path)
+                                    image-load-path)))
+          (map (gmm-tool-bar-from-list gnus-group-tool-bar
+                                       gnus-group-tool-bar-zap-list
+                                       'gnus-group-mode-map)))
+      (if map
+         (set (make-local-variable 'tool-bar-map) map))))
+  gnus-group-tool-bar-map)
+
+(define-derived-mode gnus-group-mode fundamental-mode "Group"
+  "Major mode for reading news.
+
+All normal editing commands are switched off.
+\\<gnus-group-mode-map>
+The group buffer lists (some of) the groups available.  For instance,
+`\\[gnus-group-list-groups]' will list all subscribed groups with unread articles, while `\\[gnus-group-list-zombies]'
+lists all zombie groups.
+
+Groups that are displayed can be entered with `\\[gnus-group-read-group]'.  To subscribe
+to a group not displayed, type `\\[gnus-group-unsubscribe-group]'.
+
+For more in-depth information on this mode, read the manual (`\\[gnus-info-find-node]').
+
+The following commands are available:
+
+\\{gnus-group-mode-map}"
+  (when (gnus-visual-p 'group-menu 'menu)
+    (gnus-group-make-menu-bar)
+    (gnus-group-make-tool-bar))
+  (gnus-simplify-mode-line)
+  (gnus-group-set-mode-line)
+  (setq mode-line-process nil)
+  (buffer-disable-undo)
+  (setq truncate-lines t)
+  (setq buffer-read-only t
+       show-trailing-whitespace nil)
+  (gnus-set-default-directory)
+  (gnus-update-format-specifications nil 'group 'group-mode)
+  (gnus-update-group-mark-positions)
+  (when gnus-use-undo
+    (gnus-undo-mode 1))
+  (when gnus-slave
+    (gnus-slave-mode)))
+
+(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)))
+      (gnus-set-active "dummy.group" '(0 . 0))
+      (gnus-set-work-buffer)
+      (gnus-group-insert-group-line "dummy.group" 0 nil 0 nil)
+      (goto-char (point-min))
+      (setq gnus-group-mark-positions
+           (list (cons 'process (and (search-forward
+                                      (mm-string-to-multibyte "\200") nil t)
+                                     (- (point) (point-min) 1))))))))
+
+(defun gnus-mouse-pick-group (e)
+  "Enter the group under the mouse pointer."
+  (interactive "e")
+  (mouse-set-point e)
+  (gnus-group-read-group nil))
+
+(defun gnus-group-default-list-level ()
+  "Return the real value for `gnus-group-default-list-level'."
+  (if (functionp gnus-group-default-list-level)
+      (funcall gnus-group-default-list-level)
+    gnus-group-default-list-level))
+
+;; Look at LEVEL and find out what the level is really supposed to be.
+;; If LEVEL is non-nil, LEVEL will be returned, if not, what happens
+;; will depend on whether `gnus-group-use-permanent-levels' is used.
+(defun gnus-group-default-level (&optional level number-or-nil)
+  (cond
+   (gnus-group-use-permanent-levels
+    (or (setq gnus-group-use-permanent-levels
+             (or level (if (numberp gnus-group-use-permanent-levels)
+                           gnus-group-use-permanent-levels
+                         (or (gnus-group-default-list-level)
+                             gnus-level-subscribed))))
+       (gnus-group-default-list-level) gnus-level-subscribed))
+   (number-or-nil
+    level)
+   (t
+    (or level (gnus-group-default-list-level) gnus-level-subscribed))))
+
+(defun gnus-group-setup-buffer ()
+  (set-buffer (gnus-get-buffer-create gnus-group-buffer))
+  (unless (derived-mode-p 'gnus-group-mode)
+    (gnus-group-mode)))
+
+(defun gnus-group-name-charset (method group)
+  (unless method
+    (setq method (gnus-find-method-for-group group)))
+  (when (stringp method)
+    (setq method (gnus-server-to-method method)))
+  (if (eq (car method) 'nnimap)
+      ;; IMAP groups should not be encoded, since they do the encoding
+      ;; in utf7 in the protocol.
+      'utf-8
+    (let ((item (or (assoc method gnus-group-name-charset-method-alist)
+                   (and (consp method)
+                        (assoc (list (car method) (cadr method))
+                               gnus-group-name-charset-method-alist))))
+         (alist gnus-group-name-charset-group-alist)
+         result)
+      (if item
+         (cdr item)
+       (while (setq item (pop alist))
+         (if (string-match (car item) group)
+             (setq alist nil
+                   result (cdr item))))
+       result))))
+
+(defun gnus-group-name-decode (string charset)
+  ;; Fixme: Don't decode in unibyte mode.
+  (if (and string charset (featurep 'mule))
+      (mm-decode-coding-string string charset)
+    string))
+
+(defun gnus-group-decoded-name (string)
+  (let ((charset (gnus-group-name-charset nil string)))
+    (gnus-group-name-decode string charset)))
+
+(defun gnus-group-list-groups (&optional level unread lowest)
+  "List newsgroups with level LEVEL or lower that have unread articles.
+Default is all subscribed groups.
+If argument UNREAD is non-nil, groups with no unread articles are also
+listed.
+
+Also see the `gnus-group-use-permanent-levels' variable."
+  (interactive
+   (list (if current-prefix-arg
+            (prefix-numeric-value current-prefix-arg)
+          (or
+           (gnus-group-default-level nil t)
+           (gnus-group-default-list-level)
+           gnus-level-subscribed))))
+  (unless level
+    (setq level (car gnus-group-list-mode)
+         unread (cdr gnus-group-list-mode)))
+  (setq level (gnus-group-default-level level))
+  (gnus-group-setup-buffer)
+  (gnus-update-format-specifications nil 'group 'group-mode)
+  (let ((case-fold-search nil)
+       (props (text-properties-at (point-at-bol)))
+       (empty (= (point-min) (point-max)))
+       (group (gnus-group-group-name))
+       number)
+    (set-buffer gnus-group-buffer)
+    (setq number (funcall gnus-group-prepare-function level unread lowest))
+    (when (or (and (numberp number)
+                  (zerop number))
+             (zerop (buffer-size)))
+      ;; No groups in the buffer.
+      (gnus-message 5 "%s" gnus-no-groups-message))
+    ;; We have some groups displayed.
+    (goto-char (point-max))
+    (when (or (not gnus-group-goto-next-group-function)
+             (not (funcall gnus-group-goto-next-group-function
+                           group props)))
+      (cond
+       (empty
+       (goto-char (point-min)))
+       ((not group)
+       ;; Go to the first group with unread articles.
+       (gnus-group-search-forward t))
+       (t
+       ;; Find the right group to put point on.  If the current group
+       ;; has disappeared in the new listing, try to find the next
+       ;; one.  If no next one can be found, just leave point at the
+       ;; first newsgroup in the buffer.
+       (when (not (gnus-goto-char
+                   (text-property-any
+                    (point-min) (point-max)
+                    'gnus-group (gnus-intern-safe
+                                 group gnus-active-hashtb))))
+         (let ((newsrc (cdddr (gnus-group-entry group))))
+           (while (and newsrc
+                       (not (gnus-goto-char
+                             (text-property-any
+                              (point-min) (point-max) 'gnus-group
+                              (gnus-intern-safe
+                               (caar newsrc) gnus-active-hashtb)))))
+             (setq newsrc (cdr newsrc)))
+           (unless newsrc
+             (goto-char (point-max))
+             (forward-line -1)))))))
+    ;; Adjust cursor point.
+    (gnus-group-position-point)))
+
+(defun gnus-group-list-level (level &optional all)
+  "List groups on LEVEL.
+If ALL (the prefix), also list groups that have no unread articles."
+  (interactive "nList groups on level: \nP")
+  (gnus-group-list-groups level all level))
+
+(defun gnus-group-prepare-logic (group test)
+  (or (and gnus-group-listed-groups
+          (null gnus-group-list-option)
+          (member group gnus-group-listed-groups))
+      (cond
+       ((null gnus-group-listed-groups) test)
+       ((null gnus-group-list-option) test)
+       (t (and (member group gnus-group-listed-groups)
+              (if (eq gnus-group-list-option 'flush)
+                  (not test)
+                test))))))
+
+(defun gnus-group-prepare-flat (level &optional predicate lowest regexp)
+  "List all newsgroups with unread articles of level LEVEL or lower.
+If PREDICATE is a function, list groups that the function returns non-nil;
+if it is t, list groups that have no unread articles.
+If LOWEST is non-nil, list all newsgroups of level LOWEST or higher.
+If REGEXP is a function, list dead groups that the function returns non-nil;
+if it is a string, only list groups matching REGEXP."
+  (set-buffer gnus-group-buffer)
+  (let ((buffer-read-only nil)
+       (newsrc (cdr gnus-newsrc-alist))
+       (lowest (or lowest 1))
+       (not-in-list (and gnus-group-listed-groups
+                         (copy-sequence gnus-group-listed-groups)))
+       info clevel unread group params)
+    (erase-buffer)
+    (when (or (< lowest gnus-level-zombie)
+             gnus-group-listed-groups)
+      ;; List living groups.
+      (while newsrc
+       (setq info (car newsrc)
+             group (gnus-info-group info)
+             params (gnus-info-params info)
+             newsrc (cdr newsrc)
+             unread (gnus-group-unread group))
+       (when not-in-list
+         (setq not-in-list (delete group not-in-list)))
+       (when (gnus-group-prepare-logic
+              group
+              (and (or unread          ; This group might be unchecked
+                       predicate)      ; Check if this group should be listed
+                   (or (not (stringp regexp))
+                       (string-match regexp group))
+                   (<= (setq clevel (gnus-info-level info)) level)
+                   (>= clevel lowest)
+                   (cond
+                    ((functionp predicate)
+                     (funcall predicate info))
+                    (predicate t)      ; We list all groups?
+                    (t
+                     (or
+                      (if (eq unread t) ; Inactive?
+                          gnus-group-list-inactive-groups
+                                       ; We list inactive
+                        (and (numberp unread) (> unread 0)))
+                                       ; We list groups with unread articles
+                      (and gnus-list-groups-with-ticked-articles
+                           (cdr (assq 'tick (gnus-info-marks info))))
+                                       ; And groups with ticked articles
+                      ;; Check for permanent visibility.
+                      (and gnus-permanently-visible-groups
+                           (string-match gnus-permanently-visible-groups
+                                         group))
+                      (memq 'visible params)
+                      (cdr (assq 'visible params)))))))
+         (gnus-group-insert-group-line
+          group (gnus-info-level info)
+          (gnus-info-marks info) unread (gnus-info-method info)))))
+
+    ;; List dead groups.
+    (when (or gnus-group-listed-groups
+             (and (>= level gnus-level-zombie)
+                  (<= lowest gnus-level-zombie)))
+      (gnus-group-prepare-flat-list-dead
+       (setq gnus-zombie-list (sort gnus-zombie-list 'string<))
+       gnus-level-zombie ?Z
+       regexp))
+    (when not-in-list
+      (dolist (group gnus-zombie-list)
+       (setq not-in-list (delete group not-in-list))))
+    (when (or gnus-group-listed-groups
+             (and (>= level gnus-level-killed) (<= lowest gnus-level-killed)))
+      (gnus-group-prepare-flat-list-dead
+       (gnus-union
+       not-in-list
+       (setq gnus-killed-list (sort gnus-killed-list 'string<))
+       :test 'equal)
+       gnus-level-killed ?K regexp))
+
+    (gnus-group-set-mode-line)
+    (setq gnus-group-list-mode (cons level predicate))
+    (gnus-run-hooks 'gnus-group-prepare-hook)
+    t))
+
+(defun gnus-group-prepare-flat-list-dead (groups level mark regexp)
+  ;; List zombies and killed lists somewhat faster, which was
+  ;; suggested by Jack Vinson <vinson@unagi.cis.upenn.edu>.  It does
+  ;; this by ignoring the group format specification altogether.
+  (let (group)
+    (if (> (length groups) gnus-group-listing-limit)
+       (while groups
+         (setq group (pop groups))
+         (when (gnus-group-prepare-logic
+                group
+                (or (not regexp)
+                    (and (stringp regexp) (string-match regexp group))
+                    (and (functionp regexp) (funcall regexp group))))
+           (gnus-add-text-properties
+            (point) (prog1 (1+ (point))
+                      (insert " " mark "     *: "
+                              (gnus-group-decoded-name group)
+                              "\n"))
+            (list 'gnus-group (gnus-intern-safe group gnus-active-hashtb)
+                  'gnus-unread t
+                  'gnus-level level))))
+      (while groups
+       (setq group (pop groups))
+       (when (gnus-group-prepare-logic
+              group
+              (or (not regexp)
+                  (and (stringp regexp) (string-match regexp group))
+                  (and (functionp regexp) (funcall regexp group))))
+         (gnus-group-insert-group-line
+          group level nil
+          (let ((active (gnus-active group)))
+            (if active
+                (if (zerop (cdr active))
+                    0
+                  (- (1+ (cdr active)) (car active)))
+              nil))
+          (gnus-method-simplify (gnus-find-method-for-group group))))))))
+
+(defun gnus-group-update-group-line ()
+  "Update the current line in the group buffer."
+  (let* ((buffer-read-only nil)
+        (group (gnus-group-group-name))
+        (entry (and group (gnus-group-entry group)))
+        gnus-group-indentation)
+    (when group
+      (and entry
+          (not (gnus-ephemeral-group-p group))
+          (gnus-dribble-enter
+           (concat "(gnus-group-set-info '"
+                   (gnus-prin1-to-string (nth 2 entry))
+                   ")")
+           (concat "^(gnus-group-set-info '(\"" (regexp-quote group) "\"")))
+      (setq gnus-group-indentation (gnus-group-group-indentation))
+      (gnus-delete-line)
+      (gnus-group-insert-group-line-info group)
+      (forward-line -1)
+      (gnus-group-position-point))))
+
+(defun gnus-group-insert-group-line-info (group)
+  "Insert GROUP on the current line."
+  (let ((entry (gnus-group-entry group))
+       (gnus-group-indentation (gnus-group-group-indentation))
+       active info)
+    (if entry
+       (progn
+         ;; (Un)subscribed group.
+         (setq info (nth 2 entry))
+         (gnus-group-insert-group-line
+          group (gnus-info-level info) (gnus-info-marks info)
+          (or (car entry) t) (gnus-info-method info)))
+      ;; This group is dead.
+      (gnus-group-insert-group-line
+       group
+       (if (member group gnus-zombie-list) gnus-level-zombie gnus-level-killed)
+       nil
+       (if (setq active (gnus-active group))
+          (if (zerop (cdr active))
+              0
+            (- (1+ (cdr active)) (car active)))
+        nil)
+       (gnus-method-simplify (gnus-find-method-for-group group))))))
+
+(defun gnus-number-of-unseen-articles-in-group (group)
+  (let* ((info (nth 2 (gnus-group-entry group)))
+        (marked (gnus-info-marks info))
+        (seen (cdr (assq 'seen marked)))
+        (active (gnus-active group)))
+    (if (not active)
+       0
+      (length (gnus-uncompress-range
+              (gnus-range-difference
+               (gnus-range-difference (list active) (gnus-info-read info))
+               seen))))))
+
+;; Moving through the Group buffer (in topic mode) e.g. with C-n doesn't
+;; update the state (enabled/disabled) of the icon `gnus-group-describe-group'
+;; automatically.  After `C-l' the state is correct.  See the following report
+;; on emacs-devel
+;; <http://thread.gmane.org/v9acdmrcse.fsf@marauder.physik.uni-ulm.de>:
+;; From: Reiner Steib
+;; Subject: tool bar icons not updated according to :active condition
+;; Newsgroups: gmane.emacs.devel
+;; Date: Mon, 23 Jan 2006 19:59:13 +0100
+;; Message-ID: <v9acdmrcse.fsf@marauder.physik.uni-ulm.de>
+
+(defcustom gnus-group-update-tool-bar
+  (and (not (featurep 'xemacs))
+       (boundp 'tool-bar-mode)
+       tool-bar-mode
+       ;; Using `redraw-frame' (see `gnus-tool-bar-update') in Emacs might
+       ;; be confusing, so maybe we shouldn't call it by default.
+       (fboundp 'force-window-update))
+  "Force updating the group buffer tool bar."
+  :group 'gnus-group
+  :version "22.1"
+  :initialize 'custom-initialize-default
+  :set (lambda (symbol value)
+        (set-default symbol value)
+        (when (gnus-alive-p)
+          (with-current-buffer gnus-group-buffer
+            ;; FIXME: Is there a better way to redraw the group buffer?
+            (gnus-group-get-new-news 0))))
+  :type 'boolean)
+
+(defun gnus-group-insert-group-line (gnus-tmp-group gnus-tmp-level
+                                                   gnus-tmp-marked number
+                                                   gnus-tmp-method)
+  "Insert a group line in the group buffer."
+  (let* ((gnus-tmp-method
+         (gnus-server-get-method gnus-tmp-group gnus-tmp-method))
+        (group-name-charset (gnus-group-name-charset gnus-tmp-method
+                                                     gnus-tmp-group))
+        (gnus-tmp-active (gnus-active gnus-tmp-group))
+        (gnus-tmp-number-total
+         (if gnus-tmp-active
+             (1+ (- (cdr gnus-tmp-active) (car gnus-tmp-active)))
+           0))
+        (gnus-tmp-number-of-unread
+         (if (numberp number) (int-to-string (max 0 number))
+           "*"))
+        (gnus-tmp-number-of-read
+         (if (numberp number)
+             (int-to-string (max 0 (- gnus-tmp-number-total number)))
+           "*"))
+        (gnus-tmp-subscribed
+         (cond ((<= gnus-tmp-level gnus-level-subscribed) ? )
+               ((<= gnus-tmp-level gnus-level-unsubscribed) ?U)
+               ((= gnus-tmp-level gnus-level-zombie) ?Z)
+               (t ?K)))
+        (gnus-tmp-qualified-group
+         (gnus-group-name-decode (gnus-group-real-name gnus-tmp-group)
+                                 group-name-charset))
+        (gnus-tmp-comment
+         (or (gnus-group-get-parameter gnus-tmp-group 'comment t)
+             gnus-tmp-group))
+        (gnus-tmp-newsgroup-description
+         (if gnus-description-hashtb
+             (or (gnus-group-name-decode
+                  (gnus-gethash gnus-tmp-group gnus-description-hashtb)
+                  group-name-charset) "")
+           ""))
+        (gnus-tmp-moderated
+         (if (and gnus-moderated-hashtb
+                  (gnus-gethash gnus-tmp-group gnus-moderated-hashtb))
+             ?m ? ))
+        (gnus-tmp-moderated-string
+         (if (eq gnus-tmp-moderated ?m) "(m)" ""))
+         (gnus-tmp-group-icon (gnus-group-get-icon gnus-tmp-group))
+        (gnus-tmp-news-server (or (cadr gnus-tmp-method) ""))
+        (gnus-tmp-news-method (or (car gnus-tmp-method) ""))
+        (gnus-tmp-news-method-string
+         (if gnus-tmp-method
+             (format "(%s:%s)" (car gnus-tmp-method)
+                     (cadr gnus-tmp-method)) ""))
+        (gnus-tmp-marked-mark
+         (if (and (numberp number)
+                  (zerop number)
+                  (cdr (assq 'tick gnus-tmp-marked)))
+             ?* ? ))
+        (gnus-tmp-summary-live
+         (if (and (not gnus-group-is-exiting-p)
+                  (gnus-buffer-live-p (gnus-summary-buffer-name
+                                       gnus-tmp-group)))
+             ?* ? ))
+        (gnus-tmp-process-marked
+         (if (member gnus-tmp-group gnus-group-marked)
+             gnus-process-mark ? ))
+        (buffer-read-only nil)
+        beg end
+         gnus-tmp-header)      ; passed as parameter to user-funcs.
+    (beginning-of-line)
+    (setq beg (point))
+    (gnus-add-text-properties
+     (point)
+     (prog1 (1+ (point))
+       ;; Insert the text.
+       (let ((gnus-tmp-decoded-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-number gnus-tmp-number-of-unread)
+                                t)
+                 gnus-marked ,gnus-tmp-marked-mark
+                 gnus-indentation ,gnus-group-indentation
+                 gnus-level ,gnus-tmp-level))
+    (setq end (point))
+    (gnus-group--setup-tool-bar-update beg end)
+    (forward-line -1)
+    (when (inline (gnus-visual-p 'group-highlight 'highlight))
+      (gnus-group-highlight-line gnus-tmp-group beg end))
+    (gnus-run-hooks 'gnus-group-update-hook)
+    (forward-line)))
+
+(defun gnus-group--setup-tool-bar-update (beg end)
+  (when gnus-group-update-tool-bar
+    (if (fboundp 'cursor-sensor-mode)
+        (progn
+          (unless (bound-and-true-p cursor-sensor-mode)
+            (cursor-sensor-mode 1))
+          (gnus-put-text-property beg end 'cursor-sensor-functions
+                                  '(gnus-tool-bar-update)))
+      (gnus-put-text-property beg end 'point-entered
+                              #'gnus-tool-bar-update)
+      (gnus-put-text-property beg end 'point-left
+                              #'gnus-tool-bar-update))))
+
+(defun gnus-group-update-eval-form (group list)
+  "Eval `car' of each element of LIST, and return the first that return t.
+Some value are bound so the form can use them."
+  (defvar group-age) (defvar ticked) (defvar score) (defvar level)
+  (defvar mailp) (defvar total) (defvar unread)
+  (when list
+    (let* ((entry (gnus-group-entry group))
+           (unread (if (numberp (car entry)) (car entry) 0))
+           (active (gnus-active group))
+           (total (if active (1+ (- (cdr active) (car active))) 0))
+           (info (nth 2 entry))
+           (method (inline (gnus-server-get-method group (gnus-info-method info))))
+           (marked (gnus-info-marks info))
+           (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))))
+           (group-age (gnus-group-timestamp-delta group)))
+      ;; FIXME: http://thread.gmane.org/gmane.emacs.gnus.general/65451/focus=65465
+      ;; ======================================================================
+      ;; From: Richard Stallman
+      ;; Subject: Re: Rewriting gnus-group-highlight-line (was: [...])
+      ;; Cc: ding@gnus.org
+      ;; Date: Sat, 27 Oct 2007 19:41:20 -0400
+      ;; Message-ID: <E1IlvHM-0006TS-7t@fencepost.gnu.org>
+      ;;
+      ;; [...]
+      ;; The kludge is that the alist elements contain expressions that refer
+      ;; to local variables with short names.  Perhaps write your own tiny
+      ;; evaluator that handles just `and', `or', and numeric comparisons
+      ;; and just a few specific variables.
+      ;; ======================================================================
+      ;;
+      ;; Similar for other evaluated variables.  Grep for risky-local-variable
+      ;; to find them!  -- rsteib
+      ;;
+      ;; Eval the cars of the lists until we find a match.
+      (while (and list
+                  (not (eval (caar list))))
+        (setq list (cdr list)))
+      list)))
+
+(defun gnus-group-highlight-line (group beg end)
+  "Highlight the current line according to `gnus-group-highlight'.
+GROUP is current group, and the line to highlight starts at BEG
+and ends at END."
+  (let ((face (cdar (gnus-group-update-eval-form
+                      group
+                      gnus-group-highlight))))
+    (unless (eq face (gnus-get-text-property-excluding-characters-with-faces beg 'face))
+      (let ((inhibit-read-only t))
+        (gnus-put-text-property-excluding-characters-with-faces
+         beg end 'face
+         (if (boundp face) (symbol-value face) face)))
+      (gnus-extent-start-open beg))))
+
+(defun gnus-group-get-icon (group)
+  "Return an icon for GROUP according to `gnus-group-icon-list'."
+  (if gnus-group-icon-list
+      (let ((image-path
+             (cdar (gnus-group-update-eval-form group gnus-group-icon-list))))
+        (if image-path
+            (propertize " "
+                        'display
+                        (append
+                         (gnus-create-image (expand-file-name image-path))
+                         '(:ascent center)))
+          " "))
+    " "))
+
+
+(defun gnus-group-refresh-group (group)
+  (gnus-activate-group group)
+  (gnus-get-unread-articles-in-group (gnus-get-info group)
+                                    (gnus-active group))
+  (gnus-group-update-group group))
+
+(defun gnus-group-update-group (group &optional visible-only
+                                     info-unchanged)
+  "Update all lines where GROUP appear.
+If VISIBLE-ONLY is non-nil, the group won't be displayed if it isn't
+already.  If INFO-UNCHANGED is non-nil, dribble buffer is not updated."
+  (with-current-buffer gnus-group-buffer
+    (save-excursion
+      ;; The buffer may be narrowed.
+      (save-restriction
+        (widen)
+        (let ((ident (gnus-intern-safe group gnus-active-hashtb))
+              (loc (point-min))
+              found buffer-read-only)
+         (unless info-unchanged
+           ;; Enter the current status into the dribble buffer.
+           (let ((entry (gnus-group-entry group)))
+             (when (and entry
+                        (not (gnus-ephemeral-group-p group)))
+               (gnus-dribble-enter
+                (concat "(gnus-group-set-info '"
+                        (gnus-prin1-to-string (nth 2 entry))
+                        ")")
+                (concat "^(gnus-group-set-info '(\""
+                        (regexp-quote group) "\"")))))
+          ;; Find all group instances.  If topics are in use, each group
+          ;; may be listed in more than once.
+          (while (setq loc (text-property-any
+                            loc (point-max) 'gnus-group ident))
+            (setq found t)
+            (goto-char loc)
+            (let ((gnus-group-indentation (gnus-group-group-indentation)))
+              (gnus-delete-line)
+              (gnus-group-insert-group-line-info group)
+              (save-excursion
+                (forward-line -1)
+                (gnus-run-hooks 'gnus-group-update-group-hook)))
+            (setq loc (1+ loc)))
+          (unless (or found visible-only)
+            ;; No such line in the buffer, find out where it's supposed to
+            ;; go, and insert it there (or at the end of the buffer).
+            (if gnus-goto-missing-group-function
+                (funcall gnus-goto-missing-group-function group)
+              (let ((entry (cddr (gnus-group-entry group))))
+                (while (and entry (car entry)
+                            (not
+                             (gnus-goto-char
+                              (text-property-any
+                               (point-min) (point-max)
+                               'gnus-group (gnus-intern-safe
+                                            (caar entry)
+                                            gnus-active-hashtb)))))
+                  (setq entry (cdr entry)))
+                (or entry (goto-char (point-max)))))
+            ;; Finally insert the line.
+            (let ((gnus-group-indentation (gnus-group-group-indentation)))
+              (gnus-group-insert-group-line-info group)
+              (save-excursion
+                (forward-line -1)
+                (gnus-run-hooks 'gnus-group-update-group-hook))))
+          (when gnus-group-update-group-function
+            (funcall gnus-group-update-group-function group))
+          (gnus-group-set-mode-line))))))
+
+(defun gnus-group-set-mode-line ()
+  "Update the mode line in the group buffer."
+  (when (memq 'group gnus-updated-mode-lines)
+    ;; Yes, we want to keep this mode line updated.
+    (with-current-buffer gnus-group-buffer
+      (let* ((gformat (or gnus-group-mode-line-format-spec
+                         (gnus-set-format 'group-mode)))
+            (gnus-tmp-news-server (cadr gnus-select-method))
+            (gnus-tmp-news-method (car gnus-select-method))
+            (gnus-tmp-colon (if (equal gnus-tmp-news-server "") "" ":"))
+            (max-len 60)
+            gnus-tmp-header            ;Dummy binding for user-defined formats
+            ;; Get the resulting string.
+            (modified
+             (and gnus-dribble-buffer
+                  (buffer-name gnus-dribble-buffer)
+                  (buffer-modified-p gnus-dribble-buffer)
+                  (with-current-buffer gnus-dribble-buffer
+                    (not (zerop (buffer-size))))))
+            (mode-string (eval gformat)))
+       ;; Say whether the dribble buffer has been modified.
+       (setq mode-line-modified
+             (if modified (car gnus-mode-line-modified)
+               (cdr gnus-mode-line-modified)))
+       ;; If the line is too long, we chop it off.
+       (when (> (length mode-string) max-len)
+         (setq mode-string (substring mode-string 0 (- max-len 4))))
+       (prog1
+           (setq mode-line-buffer-identification
+                 (gnus-mode-line-buffer-identification
+                  (list mode-string)))
+         (set-buffer-modified-p modified))))))
+
+(defun gnus-group-group-name ()
+  "Get the name of the newsgroup on the current line."
+  (let ((group (get-text-property (point-at-bol) 'gnus-group)))
+    (when group
+      (if (stringp group)
+         group
+       (symbol-name group)))))
+
+(defun gnus-group-group-level ()
+  "Get the level of the newsgroup on the current line."
+  (get-text-property (point-at-bol) 'gnus-level))
+
+(defun gnus-group-group-indentation ()
+  "Get the indentation of the newsgroup on the current line."
+  (or (get-text-property (point-at-bol) 'gnus-indentation)
+      (and gnus-group-indentation-function
+          (funcall gnus-group-indentation-function))
+      ""))
+
+(defun gnus-group-group-unread ()
+  "Get the number of unread articles of the newsgroup on the current line."
+  (get-text-property (point-at-bol) 'gnus-unread))
+
+(defun gnus-group-new-mail (group)
+  (if (nnmail-new-mail-p (gnus-group-real-name group))
+      gnus-new-mail-mark
+    ? ))
+
+(defun gnus-group-level (group)
+  "Return the estimated level of GROUP."
+  (or (gnus-info-level (gnus-get-info group))
+      (and (member group gnus-zombie-list) gnus-level-zombie)
+      gnus-level-killed))
+
+(defun gnus-group-search-forward (&optional backward all level first-too)
+  "Find the next newsgroup with unread articles.
+If BACKWARD is non-nil, find the previous newsgroup instead.
+If ALL is non-nil, just find any newsgroup.
+If LEVEL is non-nil, find group with level LEVEL, or higher if no such
+group exists.
+If FIRST-TOO, the current line is also eligible as a target."
+  (let ((way (if backward -1 1))
+       (low gnus-level-killed)
+       (beg (point))
+       pos found lev)
+    (if (and backward (progn (beginning-of-line)) (bobp))
+       nil
+      (unless first-too
+       (forward-line way))
+      (while (and
+             (not (eobp))
+             (not (setq
+                   found
+                   (and
+                    (get-text-property (point) 'gnus-group)
+                    (or all
+                        (and
+                         (let ((unread
+                                (get-text-property (point) 'gnus-unread)))
+                           (and (numberp unread) (> unread 0)))
+                         (setq lev (get-text-property (point)
+                                                      'gnus-level))
+                         (<= lev gnus-level-subscribed)))
+                    (or (not level)
+                        (and (setq lev (get-text-property (point)
+                                                          'gnus-level))
+                             (or (= lev level)
+                                 (and (< lev low)
+                                      (< level lev)
+                                      (progn
+                                        (setq low lev)
+                                        (setq pos (point))
+                                        nil))))))))
+             (zerop (forward-line way)))))
+    (if found
+       (progn (gnus-group-position-point) t)
+      (goto-char (or pos beg))
+      (and pos t))))
+
+(defun gnus-total-fetched-for (group)
+  (let* ((size-in-cache (or (gnus-cache-total-fetched-for group) 0))
+        (size-in-agent (or (gnus-agent-total-fetched-for group) 0))
+        (size (+ size-in-cache size-in-agent))
+        (suffix '("B" "K" "M" "G"))
+        (scale 1024.0)
+        (cutoff scale))
+    (while (> size cutoff)
+      (setq size (/ size scale)
+           suffix (cdr suffix)))
+    (format "%5.1f%s" size (car suffix))))
+
+;;; Gnus group mode commands
+
+;; Group marking.
+
+(defun gnus-group-mark-line-p ()
+  (save-excursion
+    (beginning-of-line)
+    (forward-char (or (cdr (assq 'process gnus-group-mark-positions)) 2))
+    (eq (char-after) gnus-process-mark)))
+
+(defun gnus-group-mark-group (n &optional unmark no-advance)
+  "Mark the current group."
+  (interactive "p")
+  (let ((buffer-read-only nil)
+       group)
+    (while (and (> n 0)
+               (not (eobp)))
+      (when (setq group (gnus-group-group-name))
+       ;; Go to the mark position.
+       (beginning-of-line)
+       (forward-char (or (cdr (assq 'process gnus-group-mark-positions)) 2))
+       (delete-char 1)
+       (if unmark
+           (progn
+             (setq gnus-group-marked (delete group gnus-group-marked))
+             (insert-char ? 1 t))
+          (setq gnus-group-marked
+                (cons group (delete group gnus-group-marked)))
+          (insert-char gnus-process-mark 1 t)))
+      (unless no-advance
+       (gnus-group-next-group 1))
+      (decf n))
+    (gnus-group-position-point)
+    n))
+
+(defun gnus-group-unmark-group (n)
+  "Remove the mark from the current group."
+  (interactive "p")
+  (gnus-group-mark-group n 'unmark)
+  (gnus-group-position-point))
+
+(defun gnus-group-unmark-all-groups ()
+  "Unmark all groups."
+  (interactive)
+  (save-excursion
+    (mapc 'gnus-group-remove-mark gnus-group-marked))
+  (gnus-group-position-point))
+
+(defun gnus-group-mark-region (unmark beg end)
+  "Mark all groups between point and mark.
+If UNMARK, remove the mark instead."
+  (interactive "P\nr")
+  (let ((num (count-lines beg end)))
+    (save-excursion
+      (goto-char beg)
+      (- num (gnus-group-mark-group num unmark)))))
+
+(defun gnus-group-mark-buffer (&optional unmark)
+  "Mark all groups in the buffer.
+If UNMARK, remove the mark instead."
+  (interactive "P")
+  (gnus-group-mark-region unmark (point-min) (point-max)))
+
+(defun gnus-group-mark-regexp (regexp)
+  "Mark all groups that match some regexp."
+  (interactive "sMark (regexp): ")
+  (let ((alist (cdr gnus-newsrc-alist))
+       group)
+    (save-excursion
+      (while alist
+       (when (string-match regexp (setq group (gnus-info-group (pop alist))))
+         (gnus-group-jump-to-group group)
+         (gnus-group-set-mark group)))))
+  (gnus-group-position-point))
+
+(defun gnus-group-remove-mark (group &optional test-marked)
+  "Remove the process mark from GROUP and move point there.
+Return nil if the group isn't displayed."
+  (if (gnus-group-goto-group group nil test-marked)
+      (save-excursion
+       (gnus-group-mark-group 1 'unmark t)
+       t)
+    (setq gnus-group-marked
+         (delete group gnus-group-marked))
+    nil))
+
+(defun gnus-group-set-mark (group)
+  "Set the process mark on GROUP."
+  (if (gnus-group-goto-group group)
+      (save-excursion
+       (gnus-group-mark-group 1 nil t))
+    (setq gnus-group-marked (cons group (delete group gnus-group-marked)))))
+
+(defun gnus-group-universal-argument (arg &optional groups func)
+  "Perform any command on all groups according to the process/prefix convention."
+  (interactive "P")
+  (if (eq (setq func (or func
+                        (key-binding
+                         (read-key-sequence
+                          (substitute-command-keys
+                           "\\<gnus-group-mode-map>\\[gnus-group-universal-argument]")))))
+         'undefined)
+      (gnus-error 1 "Undefined key")
+    (gnus-group-iterate arg
+      (lambda (group)
+       (command-execute func))))
+  (gnus-group-position-point))
+
+(defun gnus-group-process-prefix (n)
+  "Return a list of groups to work on.
+Take into consideration N (the prefix) and the list of marked groups."
+  (cond
+   (n
+    (setq n (prefix-numeric-value n))
+    ;; There is a prefix, so we return a list of the N next
+    ;; groups.
+    (let ((way (if (< n 0) -1 1))
+         (n (abs n))
+         group groups)
+      (save-excursion
+       (while (> n 0)
+         (if (setq group (gnus-group-group-name))
+             (push group groups))
+         (setq n (1- n))
+         (gnus-group-next-group way)))
+      (nreverse groups)))
+   ((and (gnus-region-active-p) (mark))
+    ;; Work on the region between point and mark.
+    (let ((max (max (point) (mark)))
+         groups)
+      (save-excursion
+       (goto-char (min (point) (mark)))
+       (while
+           (and
+            (push (gnus-group-group-name) groups)
+            (zerop (gnus-group-next-group 1))
+            (< (point) max)))
+       (nreverse groups))))
+   (gnus-group-marked
+    ;; No prefix, but a list of marked articles.
+    (reverse gnus-group-marked))
+   (t
+    ;; Neither marked articles or a prefix, so we return the
+    ;; current group.
+    (let ((group (gnus-group-group-name)))
+      (and group (list group))))))
+
+;;; !!!Surely gnus-group-iterate should be a macro instead?  I can't
+;;; imagine why I went through these contortions...
+(eval-and-compile
+  (let ((function (make-symbol "gnus-group-iterate-function"))
+       (window (make-symbol "gnus-group-iterate-window"))
+       (groups (make-symbol "gnus-group-iterate-groups"))
+       (group (make-symbol "gnus-group-iterate-group")))
+    (eval
+     `(defun gnus-group-iterate (arg ,function)
+       "Iterate FUNCTION over all process/prefixed groups.
+FUNCTION will be called with the group name as the parameter
+and with point over the group in question."
+       (let ((,groups (gnus-group-process-prefix arg))
+             (,window (selected-window))
+             ,group)
+         (while ,groups
+           (setq ,group (car ,groups)
+                 ,groups (cdr ,groups))
+           (select-window ,window)
+           (gnus-group-remove-mark ,group)
+           (save-selected-window
+             (save-excursion
+               (funcall ,function ,group)))))))))
+
+(put 'gnus-group-iterate 'lisp-indent-function 1)
+
+;; Selecting groups.
+
+(defun gnus-group-read-group (&optional all no-article group select-articles)
+  "Read news in this newsgroup.
+If the prefix argument ALL is non-nil, already read articles become
+readable.
+
+If ALL is a positive number, fetch this number of the latest
+articles in the group.  If ALL is a negative number, fetch this
+number of the earliest articles in the group.
+
+If the optional argument NO-ARTICLE is non-nil, no article will
+be auto-selected upon group entry.  If GROUP is non-nil, fetch
+that group."
+  (interactive "P")
+  (let ((no-display (eq all 0))
+       (group (or group (gnus-group-group-name)))
+       number active marked entry)
+    (when (eq all 0)
+      (setq all nil))
+    (unless group
+      (error "No group on current line"))
+    (setq marked (gnus-info-marks
+                 (nth 2 (setq entry (gnus-group-entry group)))))
+    ;; This group might be a dead group.  In that case we have to get
+    ;; the number of unread articles from `gnus-active-hashtb'.
+    (setq number
+         (cond ((numberp all) all)
+               (entry (car entry))
+               ((setq active (gnus-active group))
+                (- (1+ (cdr active)) (car active)))))
+    (gnus-summary-read-group
+     group (or all (and (numberp number)
+                       (zerop (+ number (gnus-range-length
+                                         (cdr (assq 'tick marked)))
+                                 (gnus-range-length
+                                  (cdr (assq 'dormant marked)))))))
+     no-article nil no-display nil select-articles)))
+
+(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 positive number, fetch this number of the latest
+articles in the group.
+If ALL is a negative number, fetch this number of the earliest
+articles in the group."
+  (interactive "P")
+  (when (and (eobp) (not (gnus-group-group-name)))
+    (forward-line -1))
+  (gnus-group-read-group all t))
+
+(defun gnus-group-quick-select-group (&optional all group)
+  "Select the GROUP \"quickly\".
+This means that no highlighting or scoring will be performed.  If
+ALL (the prefix argument) is 0, don't even generate the summary
+buffer.  If GROUP is nil, use current group.
+
+This might be useful if you want to toggle threading
+before entering the group."
+  (interactive "P")
+  (require 'gnus-score)
+  (let (gnus-visual
+       gnus-score-find-score-files-function
+       gnus-home-score-file
+       gnus-apply-kill-hook
+       gnus-summary-expunge-below)
+    (gnus-group-read-group all t group)))
+
+(defun gnus-group-visible-select-group (&optional all)
+  "Select the current group without hiding any articles."
+  (interactive "P")
+  (let ((gnus-inhibit-limiting t))
+    (gnus-group-read-group all t)))
+
+(defun gnus-group-select-group-ephemerally ()
+  "Select the current group without doing any processing whatsoever.
+You will actually be entered into a group that's a copy of
+the current group; no changes you make while in this group will
+be permanent."
+  (interactive)
+  (require 'gnus-score)
+  (let* (gnus-visual
+        gnus-score-find-score-files-function gnus-apply-kill-hook
+        gnus-summary-expunge-below gnus-show-threads gnus-suppress-duplicates
+        gnus-summary-mode-hook gnus-select-group-hook
+        (group (gnus-group-group-name))
+        (method (gnus-find-method-for-group group)))
+    (gnus-group-read-ephemeral-group
+     (gnus-group-prefixed-name group method) method)))
+
+(defun gnus-group-name-at-point ()
+  "Return a group name from around point if it exists, or nil."
+  (if (derived-mode-p 'gnus-group-mode)
+      (let ((group (gnus-group-group-name)))
+       (when group
+         (gnus-group-decoded-name group)))
+    (let ((regexp "[][\C-@-\t\v-*,/:-@\\^`{-\C-?]*\
+\\(nn[a-z]+\\(?:\\+[^][\C-@-*,/:-@\\^`{-\C-?]+\\)?:\
+[^][\C-@-*,./:-@\\^`{-\C-?]+\\(?:\\.[^][\C-@-*,./:-@\\^`{-\C-?]+\\)*\
+\\|[^][\C-@-*,./:-@\\^`{-\C-?]+\\(?:\\.[^][\C-@-*,./:-@\\^`{-\C-?]+\\)+\\)")
+         (start (point))
+         (case-fold-search nil))
+      (prog1
+         (if (or (and (not (or (eobp)
+                               (looking-at "[][\C-@-*,/;-@\\^`{-\C-?]")))
+                      (prog1 t
+                        (skip-chars-backward "^][\C-@-\t\v-*,/;-@\\^`{-\C-?"
+                                             (point-at-bol))))
+                 (and (looking-at "[][\C-@-\t\v-*,/;-@\\^`{-\C-?]*$")
+                      (prog1 t
+                        (skip-chars-backward "][\C-@-\t\v-*,/;-@\\^`{-\C-?")
+                        (skip-chars-backward "^][\C-@-\t\v-*,/;-@\\^`{-\C-?"
+                                             (point-at-bol))))
+                 (string-match "\\`[][\C-@-\t\v-*,/;-@\\^`{-\C-?]*\\'"
+                               (buffer-substring (point-at-bol) (point))))
+             (when (looking-at regexp)
+               (match-string 1))
+           (let (group distance)
+             (when (looking-at regexp)
+               (setq group (match-string 1)
+                     distance (- (match-beginning 1) (match-beginning 0))))
+             (skip-chars-backward "][\C-@-\t\v-*,/;-@\\^`{-\C-?")
+             (skip-chars-backward "^][\C-@-\t\v-*,/;-@\\^`{-\C-?"
+                                  (point-at-bol))
+             (if (looking-at regexp)
+                 (if (and group (<= distance (- start (match-end 0))))
+                     group
+                   (match-string 1))
+               group)))
+       (goto-char start)))))
+
+(defun gnus-group-completing-read (&optional prompt collection
+                                            require-match initial-input hist
+                                            def)
+  "Read a group name with completion.  Non-ASCII group names are allowed.
+The arguments are the same as `completing-read' except that COLLECTION
+and HIST default to `gnus-active-hashtb' and `gnus-group-history'
+respectively if they are omitted.  Regards COLLECTION as a hash table
+if it is not a list."
+  (or collection (setq collection gnus-active-hashtb))
+  (let (choices group)
+    (if (listp collection)
+       (dolist (symbol collection)
+         (setq group (symbol-name symbol))
+         (push (if (string-match "[^\000-\177]" group)
+                   (gnus-group-decoded-name group)
+                 group)
+               choices))
+      (mapatoms (lambda (symbol)
+                 (setq group (symbol-name symbol))
+                 (push (if (string-match "[^\000-\177]" group)
+                           (gnus-group-decoded-name group)
+                         group)
+                       choices))
+               collection))
+    (setq group (gnus-completing-read (or prompt "Group") (nreverse choices)
+                                     require-match initial-input
+                                     (or hist 'gnus-group-history)
+                                     def))
+    (unless (if (listp collection)
+               (member group (mapcar 'symbol-name collection))
+             (symbol-value (intern-soft group collection)))
+      (setq group
+           (mm-encode-coding-string
+            group (gnus-group-name-charset nil group))))
+    (gnus-replace-in-string group "\n" "")))
+
+;;;###autoload
+(defun gnus-fetch-group (group &optional articles)
+  "Start Gnus if necessary and enter GROUP.
+If ARTICLES, display those articles.
+Returns whether the fetching was successful or not."
+  (interactive (list (gnus-group-completing-read nil
+                                                nil nil
+                                                (gnus-group-name-at-point))))
+  (unless (gnus-alive-p)
+    (gnus-no-server))
+  (gnus-group-read-group (if articles nil t) nil group articles))
+
+;;;###autoload
+(defun gnus-fetch-group-other-frame (group)
+  "Pop up a frame and enter GROUP."
+  (interactive "P")
+  (let ((window (get-buffer-window gnus-group-buffer)))
+    (cond (window
+          (select-frame (window-frame window)))
+         ((= (length (frame-list)) 1)
+          (select-frame (make-frame)))
+         (t
+          (other-frame 1))))
+  (gnus-fetch-group group))
+
+(defcustom gnus-large-ephemeral-newsgroup 200
+  "The number of articles which indicates a large ephemeral newsgroup.
+Same as `gnus-large-newsgroup', but only used for ephemeral newsgroups.
+
+If the number of articles in a newsgroup is greater than this value,
+confirmation is required for selecting the newsgroup.  If it is nil, no
+confirmation is required."
+  :version "22.1"
+  :group 'gnus-group-select
+  :type '(choice (const :tag "No limit" nil)
+                integer))
+
+(defcustom gnus-fetch-old-ephemeral-headers nil
+  "Same as `gnus-fetch-old-headers', but only used for ephemeral newsgroups."
+  :version "22.1"
+  :group 'gnus-thread
+  :type '(choice (const :tag "off" nil)
+                (const some)
+                number
+                (sexp :menu-tag "other" t)))
+
+;; Enter a group that is not in the group buffer.  Non-nil is returned
+;; if selection was successful.
+(defun gnus-group-read-ephemeral-group (group method &optional activate
+                                             quit-config request-only
+                                             select-articles
+                                             parameters
+                                             number)
+  "Read GROUP from METHOD as an ephemeral group.
+If ACTIVATE, request the group first.
+If QUIT-CONFIG, use that Gnus window configuration name when
+exiting from the ephemeral group.
+If REQUEST-ONLY, don't actually read the group; just request it.
+If SELECT-ARTICLES, only select those articles.
+If PARAMETERS, use those as the group parameters.
+If NUMBER, fetch this number of articles.
+
+Return the name of the group if selection was successful."
+  (interactive
+   (list
+    ;; (gnus-read-group "Group name: ")
+    (gnus-group-completing-read)
+    (gnus-read-method "From method")))
+  (unless (gnus-alive-p)
+    (nnheader-init-server-buffer)
+    ;; Necessary because of funky inlining.
+    (require 'gnus-cache)
+    (setq gnus-newsrc-hashtb (gnus-make-hashtable)))
+  ;; Transform the select method into a unique server.
+  (when (stringp method)
+    (setq method (gnus-server-to-method method)))
+  (let ((address-slot
+        (intern (format "%s-address" (car method)))))
+    (setq method
+         (if (assq address-slot (cddr method))
+             `(,(car method) ,(concat (cadr method) "-ephemeral")
+               ,@(cddr method))
+           `(,(car method) ,(concat (cadr method) "-ephemeral")
+             (,address-slot ,(cadr method))
+             ,@(cddr method)))))
+  (let ((group (if (gnus-group-foreign-p group) group
+                (gnus-group-prefixed-name (gnus-group-real-name group)
+                                          method))))
+    (gnus-set-active group nil)
+    (gnus-sethash
+     group
+     `(-1 nil (,group
+              ,gnus-level-default-subscribed nil nil ,method
+              ,(cons
+                (cons 'quit-config
+                      (cond
+                       (quit-config
+                        quit-config)
+                       ((assq gnus-current-window-configuration
+                              gnus-buffer-configuration)
+                        (cons gnus-summary-buffer
+                              gnus-current-window-configuration))
+                       (t
+                        (cons (current-buffer)
+                              (current-window-configuration)))))
+                parameters)))
+     gnus-newsrc-hashtb)
+    (push method gnus-ephemeral-servers)
+    (when (gnus-buffer-live-p gnus-group-buffer)
+      (set-buffer gnus-group-buffer))
+    (unless (gnus-check-server method)
+      (error "Unable to contact server: %s" (gnus-status-message method)))
+    (when activate
+      (gnus-activate-group group 'scan)
+      (unless (gnus-request-group group)
+       (error "Couldn't request group: %s"
+              (nnheader-get-report (car method)))))
+    (if request-only
+       group
+      (condition-case ()
+         (when (let ((gnus-large-newsgroup gnus-large-ephemeral-newsgroup)
+                     (gnus-fetch-old-headers
+                      gnus-fetch-old-ephemeral-headers))
+                 (gnus-group-read-group (or number t) t group select-articles))
+           group)
+       (quit
+        (if debug-on-quit
+            (debug "Quit")
+          (message "Quit reading the ephemeral group"))
+        nil)))))
+
+(defcustom gnus-gmane-group-download-format
+  "http://download.gmane.org/%s/%s/%s"
+  "URL for downloading mbox files.
+It must contain three \"%s\".  They correspond to the group, the
+minimal and maximal article numbers, respectively."
+  :group 'gnus-group-foreign
+  :version "23.1" ;; No Gnus
+  :type 'string)
+
+(autoload 'url-insert-file-contents "url-handlers")
+;; FIXME:
+;; - Add documentation, menu, key bindings, ...
+
+(defun gnus-read-ephemeral-gmane-group (group start &optional range)
+  "Read articles from Gmane group GROUP as an ephemeral group.
+START is the first article.  RANGE specifies how many articles
+are fetched.  The articles are downloaded via HTTP using the URL
+specified by `gnus-gmane-group-download-format'."
+  ;; See <http://gmane.org/export.php> for more information.
+  (interactive
+   (list
+    (gnus-group-completing-read "Gmane group")
+    (read-number "Start article number: ")
+    (read-number "How many articles: ")))
+  (unless range (setq range 500))
+  (when (< range 1)
+    (error "Invalid range: %s" range))
+  (let ((tmpfile (mm-make-temp-file
+                 (format "%s.start-%s.range-%s." group start range)))
+       (gnus-thread-sort-functions '(gnus-thread-sort-by-number)))
+    (with-temp-file tmpfile
+      (url-insert-file-contents
+       (format gnus-gmane-group-download-format
+              group start (+ start range)))
+      (write-region (point-min) (point-max) tmpfile)
+      (gnus-group-read-ephemeral-group
+       (format "nndoc+ephemeral:%s.start-%s.range-%s" group start range)
+       `(nndoc ,tmpfile
+              (nndoc-article-type mbox))))
+    (delete-file tmpfile)))
+
+(defun gnus-read-ephemeral-gmane-group-url (url)
+  "Create an ephemeral Gmane group from URL.
+
+Valid input formats include:
+\"http://thread.gmane.org/gmane.foo.bar/12300/focus=12399\",
+\"http://thread.gmane.org/gmane.foo.bar/12345/\",
+\"http://article.gmane.org/gmane.foo.bar/12345/\",
+\"http://news.gmane.org/group/gmane.foo.bar/thread=12345\""
+  ;; - Feel free to add other useful Gmane URLs here!  Maybe the URLs should
+  ;;   be customizable?
+  ;; - The URLs should be added to `gnus-button-alist'.  Probably we should
+  ;;   prompt the user to decide: "View via `browse-url' or in Gnus? "
+  ;;   (`gnus-read-ephemeral-gmane-group-url')
+  (interactive
+   (list (gnus-group-completing-read "Gmane URL")))
+  (let (group start range)
+    (cond
+     ;; URLs providing `group', `start' and `range':
+     ((string-match
+       ;; http://thread.gmane.org/gmane.emacs.devel/86326/focus=86525
+       "^http://thread\\.gmane\\.org/\\([^/]+\\)/\\([0-9]+\\)/focus=\\([0-9]+\\)$"
+       url)
+      (setq group (match-string 1 url)
+           start (string-to-number (match-string 2 url))
+           ;; Ensure that `range' is large enough to ensure focus article is
+           ;; included.
+           range (- (string-to-number (match-string 3 url))
+                    start -1)))
+     ;; URLs providing `group' and `start':
+     ((or (string-match
+          ;; http://article.gmane.org/gmane.comp.gnu.make.bugs/3584
+          "^http://\\(?:thread\\|article\\|permalink\\)\\.gmane\\.org/\\([^/]+\\)/\\([0-9]+\\)"
+          url)
+         (string-match
+          ;; Don't advertise these in the doc string yet:
+          "^\\(?:nntp\\|news\\)://news\\.gmane\\.org/\\([^/]+\\)/\\([0-9]+\\)"
+          url)
+         (string-match
+          ;; http://news.gmane.org/group/gmane.emacs.gnus.general/thread=65099/force_load=t
+          "^http://news\\.gmane\\.org/group/\\([^/]+\\)/thread=\\([0-9]+\\)"
+          url))
+      (setq group (match-string 1 url)
+           start (string-to-number (match-string 2 url))))
+     (t
+      (error "Can't parse URL %s" url)))
+    (gnus-read-ephemeral-gmane-group group start range)))
+
+(defcustom gnus-bug-group-download-format-alist
+  '((emacs . "http://debbugs.gnu.org/cgi/bugreport.cgi?bug=%s;mboxmaint=yes;mboxstat=yes")
+    (debian
+     . "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%s&mbox=yes;mboxmaint=yes"))
+  "Alist of symbols for bug trackers and the corresponding URL format string.
+The URL format string must contain a single \"%s\", specifying
+the bug number, and browsing the URL must return mbox output."
+  :group 'gnus-group-foreign
+  ;; Added mboxmaint=yes.  This gets the version with the messages as
+  ;; they went out, not as they came in.
+  ;; Eg bug-gnu-emacs is replaced by ###@debbugs.
+  :version "24.1"
+  :type '(repeat (cons (symbol) (string :tag "URL format string"))))
+
+(defun gnus-read-ephemeral-bug-group (ids mbox-url &optional window-conf)
+  "Browse bug NUMBER as ephemeral group."
+  (interactive (list (read-string "Enter bug number: "
+                                 (thing-at-point 'word) nil)
+                    ;; FIXME: Add completing-read from
+                    ;; `gnus-emacs-bug-group-download-format' ...
+                    (cdr (assoc 'emacs gnus-bug-group-download-format-alist))))
+  (when (stringp ids)
+    (setq ids (string-to-number ids)))
+  (unless (listp ids)
+    (setq ids (list ids)))
+  (let ((tmpfile (mm-make-temp-file "gnus-temp-group-")))
+    (let ((coding-system-for-write 'binary)
+         (coding-system-for-read 'binary))
+      (with-temp-file tmpfile
+       (mm-disable-multibyte)
+       (dolist (id ids)
+         (url-insert-file-contents (format mbox-url id)))
+       (goto-char (point-min))
+       ;; Add the debbugs address so that we can respond to reports easily.
+       (while (re-search-forward "^To: " nil t)
+         (end-of-line)
+         (insert (format ", %s@%s" (car ids)
+                         (gnus-replace-in-string
+                          (gnus-replace-in-string mbox-url "^http://" "")
+                          "/.*$" ""))))))
+    (gnus-group-read-ephemeral-group
+     (format "nndoc+ephemeral:bug#%s"
+            (mapconcat 'number-to-string ids ","))
+     `(nndoc ,tmpfile
+            (nndoc-article-type mbox))
+     nil window-conf)
+    (delete-file tmpfile)))
+
+(defun gnus-read-ephemeral-debian-bug-group (number)
+  "Browse Debian bug NUMBER as ephemeral group."
+  (interactive (list (read-string "Enter bug number: "
+                                 (thing-at-point 'word) nil)))
+  (gnus-read-ephemeral-bug-group
+   number
+   (cdr (assoc 'debian gnus-bug-group-download-format-alist))))
+
+(defvar debbugs-gnu-bug-number)                ; debbugs-gnu
+
+(defun gnus-read-ephemeral-emacs-bug-group (ids &optional window-conf)
+  "Browse Emacs bugs IDS as an ephemeral group."
+  (interactive (list (string-to-number
+                     (read-string "Enter bug number: "
+                                  (thing-at-point 'word) nil))))
+  (unless (listp ids)
+    (setq ids (list ids)))
+  (gnus-read-ephemeral-bug-group
+   ids
+   (cdr (assoc 'emacs gnus-bug-group-download-format-alist))
+   window-conf)
+  (when (fboundp 'debbugs-gnu-summary-mode)
+    (with-current-buffer (window-buffer (selected-window))
+      (debbugs-gnu-summary-mode 1)
+      (set (make-local-variable 'debbugs-gnu-bug-number) (car ids)))))
+
+(defun gnus-group-jump-to-group (group &optional prompt)
+  "Jump to newsgroup GROUP.
+
+If PROMPT (the prefix) is a number, use the prompt specified in
+`gnus-group-jump-to-group-prompt'."
+  (interactive
+   (list (gnus-group-completing-read
+          nil nil nil
+          (if current-prefix-arg
+              (cdr (assq current-prefix-arg gnus-group-jump-to-group-prompt))
+            (or (and (stringp gnus-group-jump-to-group-prompt)
+                     gnus-group-jump-to-group-prompt)
+                (let ((p (cdr (assq 0 gnus-group-jump-to-group-prompt))))
+                  (and (stringp p) p)))))))
+
+  (when (equal group "")
+    (error "Empty group name"))
+
+  (unless (gnus-ephemeral-group-p group)
+    ;; Either go to the line in the group buffer...
+    (unless (gnus-group-goto-group group)
+      ;; ... or insert the line.
+      (gnus-group-update-group group)
+      (gnus-group-goto-group group)))
+  ;; Adjust cursor point.
+  (gnus-group-position-point))
+
+(defun gnus-group-goto-group (group &optional far test-marked)
+  "Goto to newsgroup GROUP.
+If FAR, it is likely that the group is not on the current line.
+If TEST-MARKED, the line must be marked."
+  (when group
+    (beginning-of-line)
+    (cond
+     ;; It's quite likely that we are on the right line, so
+     ;; we check the current line first.
+     ((and (not far)
+          (eq (get-text-property (point) 'gnus-group)
+              (gnus-intern-safe group gnus-active-hashtb))
+          (or (not test-marked) (gnus-group-mark-line-p)))
+      (point))
+     ;; Previous and next line are also likely, so we check them as well.
+     ((and (not far)
+          (save-excursion
+            (forward-line -1)
+            (and (eq (get-text-property (point) 'gnus-group)
+                     (gnus-intern-safe group gnus-active-hashtb))
+                 (or (not test-marked) (gnus-group-mark-line-p)))))
+      (forward-line -1)
+      (point))
+     ((and (not far)
+          (save-excursion
+            (forward-line 1)
+            (and (eq (get-text-property (point) 'gnus-group)
+                     (gnus-intern-safe group gnus-active-hashtb))
+                 (or (not test-marked) (gnus-group-mark-line-p)))))
+      (forward-line 1)
+      (point))
+     (test-marked
+      (goto-char (point-min))
+      (let (found)
+       (while (and (not found)
+                   (gnus-goto-char
+                    (text-property-any
+                     (point) (point-max)
+                     'gnus-group
+                     (gnus-intern-safe group gnus-active-hashtb))))
+         (if (gnus-group-mark-line-p)
+             (setq found t)
+           (forward-line 1)))
+       found))
+     (t
+      ;; Search through the entire buffer.
+      (gnus-goto-char
+       (text-property-any
+       (point-min) (point-max)
+       'gnus-group (gnus-intern-safe group gnus-active-hashtb)))))))
+
+(defun gnus-group-next-group (n &optional silent)
+  "Go to next N'th newsgroup.
+If N is negative, search backward instead.
+Returns the difference between N and the number of skips actually
+done."
+  (interactive "p")
+  (gnus-group-next-unread-group n t nil silent))
+
+(defun gnus-group-next-unread-group (n &optional all level silent)
+  "Go to next N'th unread newsgroup.
+If N is negative, search backward instead.
+If ALL is non-nil, choose any newsgroup, unread or not.
+If LEVEL is non-nil, choose the next group with level LEVEL, or, if no
+such group can be found, the next group with a level higher than
+LEVEL.
+Returns the difference between N and the number of skips actually
+made."
+  (interactive "p")
+  (let ((backward (< n 0))
+       (n (abs n)))
+    (while (and (> n 0)
+               (gnus-group-search-forward
+                backward (or (not gnus-group-goto-unread) all) level))
+      (setq n (1- n)))
+    (when (and (/= 0 n)
+              (not silent))
+      (gnus-message 7 "No more%s newsgroups%s" (if all "" " unread")
+                   (if level " on this level or higher" "")))
+    n))
+
+(defun gnus-group-prev-group (n)
+  "Go to previous N'th newsgroup.
+Returns the difference between N and the number of skips actually
+done."
+  (interactive "p")
+  (gnus-group-next-unread-group (- n) t))
+
+(defun gnus-group-prev-unread-group (n)
+  "Go to previous N'th unread newsgroup.
+Returns the difference between N and the number of skips actually
+done."
+  (interactive "p")
+  (gnus-group-next-unread-group (- n)))
+
+(defun gnus-group-next-unread-group-same-level (n)
+  "Go to next N'th unread newsgroup on the same level.
+If N is negative, search backward instead.
+Returns the difference between N and the number of skips actually
+done."
+  (interactive "p")
+  (gnus-group-next-unread-group n t (gnus-group-group-level))
+  (gnus-group-position-point))
+
+(defun gnus-group-prev-unread-group-same-level (n)
+  "Go to next N'th unread newsgroup on the same level.
+Returns the difference between N and the number of skips actually
+done."
+  (interactive "p")
+  (gnus-group-next-unread-group (- n) t (gnus-group-group-level))
+  (gnus-group-position-point))
+
+(defun gnus-group-best-unread-group (&optional exclude-group)
+  "Go to the group with the highest level.
+If EXCLUDE-GROUP, do not go to that group."
+  (interactive)
+  (goto-char (point-min))
+  (let ((best 100000)
+       unread best-point)
+    (while (not (eobp))
+      (setq unread (get-text-property (point) 'gnus-unread))
+      (when (and (numberp unread) (> unread 0))
+       (when (and (get-text-property (point) 'gnus-level)
+                  (< (get-text-property (point) 'gnus-level) best)
+                  (or (not exclude-group)
+                      (not (equal exclude-group (gnus-group-group-name)))))
+         (setq best (get-text-property (point) 'gnus-level))
+         (setq best-point (point))))
+      (forward-line 1))
+    (when best-point
+      (goto-char best-point))
+    (gnus-group-position-point)
+    (and best-point (gnus-group-group-name))))
+
+;; Is there something like an after-point-motion-hook?
+;; (inhibit-point-motion-hooks?).  Is there a tool-bar-update function?
+
+;; (defun gnus-group-menu-bar-update ()
+;;   (let* ((buf (list (with-current-buffer gnus-group-buffer
+;;                   (current-buffer))))
+;;      (name (buffer-name (car buf))))
+;;     (setcdr buf
+;;         (if (> (length name) 27)
+;;             (concat (substring name 0 12)
+;;                     "..."
+;;                     (substring name -12))
+;;           name))
+;;     (menu-bar-update-buffers-1 buf)))
+
+;; (defun gnus-group-position-point ()
+;;   (gnus-goto-colon)
+;;   (gnus-group-menu-bar-update))
+
+(defun gnus-group-first-unread-group ()
+  "Go to the first group with unread articles."
+  (interactive)
+  (prog1
+      (let ((opoint (point))
+           unread)
+       (goto-char (point-min))
+       (if (or (eq (setq unread (gnus-group-group-unread)) t) ; Not active.
+               (and (numberp unread)   ; Not a topic.
+                    (not (zerop unread))) ; Has unread articles.
+               (zerop (gnus-group-next-unread-group 1))) ; Next unread group.
+           (point)                     ; Success.
+         (goto-char opoint)
+         nil))                         ; Not success.
+    (gnus-group-position-point)))
+
+(defun gnus-group-enter-server-mode ()
+  "Jump to the server buffer."
+  (interactive)
+  (gnus-enter-server-buffer))
+
+(defun gnus-group-make-group-simple (&optional group)
+  "Add a new newsgroup.
+The user will be prompted for GROUP."
+  (interactive (list (gnus-group-completing-read)))
+  (gnus-group-make-group (gnus-group-real-name group)
+                        (gnus-group-server group)
+                        nil nil t))
+
+(defun gnus-group-make-group (name &optional method address args encoded)
+  "Add a new newsgroup.
+The user will be prompted for a NAME, for a select METHOD, and an
+ADDRESS.  NAME should be a human-readable string (i.e., not be encoded
+even if it contains non-ASCII characters) unless ENCODED is non-nil.
+
+If the backend supports it, the group will also be created on the
+server."
+  (interactive
+   (list
+    (gnus-read-group "Group name: ")
+    (gnus-read-method "Select method for new group (use tab for completion)")))
+
+  (when (stringp method)
+    (setq method (or (gnus-server-to-method method) method)))
+  (unless encoded
+    (setq name (mm-encode-coding-string
+               name
+               (gnus-group-name-charset method name))))
+  (let* ((meth (gnus-method-simplify
+               (when (and method
+                          (not (gnus-server-equal method gnus-select-method)))
+                 (if address (list (intern method) address)
+                   method))))
+        (nname (if method (gnus-group-prefixed-name name meth) name))
+        backend info)
+    (when (gnus-group-entry nname)
+      (error "Group %s already exists" (gnus-group-decoded-name nname)))
+    ;; Subscribe to the new group.
+    (gnus-group-change-level
+     (setq info (list t nname gnus-level-default-subscribed nil nil meth))
+     gnus-level-default-subscribed gnus-level-killed
+     (and (gnus-group-group-name)
+         (gnus-group-entry (gnus-group-group-name)))
+     t)
+    ;; Make it active.
+    (gnus-set-active nname (cons 1 0))
+    (unless (gnus-ephemeral-group-p name)
+      (gnus-dribble-enter
+       (concat "(gnus-group-set-info '"
+              (gnus-prin1-to-string (cdr info)) ")")
+       (concat "^(gnus-group-set-info '(\"" (regexp-quote name) "\"")))
+    ;; Insert the line.
+    (gnus-group-insert-group-line-info nname)
+    (forward-line -1)
+    (gnus-group-position-point)
+
+    ;; Load the back end and try to make the back end create
+    ;; the group as well.
+    (when (assoc (symbol-name (setq backend (car (gnus-server-get-method
+                                                 nil meth))))
+                gnus-valid-select-methods)
+      (require backend))
+    (gnus-check-server meth)
+    (when (gnus-check-backend-function 'request-create-group nname)
+      (unless (gnus-request-create-group nname nil args)
+       (error "Could not create group on server: %s"
+              (nnheader-get-report backend))))
+    t))
+
+(defun gnus-group-delete-groups (&optional arg)
+  "Delete the current group.  Only meaningful with editable groups."
+  (interactive "P")
+  (let ((n (length (gnus-group-process-prefix arg))))
+    (when (gnus-yes-or-no-p
+          (if (= n 1)
+              "Delete this 1 group? "
+            (format "Delete these %d groups? " n)))
+      (gnus-group-iterate arg
+       (lambda (group)
+         (gnus-group-delete-group group nil t))))))
+
+(defun gnus-group-delete-articles (group &optional oldp)
+  "Delete all articles in the current group.
+If OLDP (the prefix), only delete articles that are \"old\",
+according to the expiry settings.  Note that this will delete old
+not-expirable articles, too."
+  (interactive (list (gnus-group-group-name)
+                    current-prefix-arg))
+  (let ((articles (gnus-uncompress-range (gnus-active group))))
+    (when (gnus-yes-or-no-p
+          (format "Do you really want to delete these %d articles forever? "
+                  (length articles)))
+      (gnus-request-expire-articles articles group
+                                   (if current-prefix-arg
+                                       nil
+                                     'force)))))
+
+(defun gnus-group-delete-group (group &optional force no-prompt)
+  "Delete the current group.  Only meaningful with editable groups.
+If FORCE (the prefix) is non-nil, all the articles in the group will
+be deleted.  This is \"deleted\" as in \"removed forever from the face
+of the Earth\".  There is no undo.  The user will be prompted before
+doing the deletion.
+Note that you also have to specify FORCE if you want the group to
+be removed from the server, even when it's empty."
+  (interactive
+   (list (gnus-group-group-name)
+        current-prefix-arg))
+  (unless group
+    (error "No group to delete"))
+  (unless (gnus-check-backend-function 'request-delete-group group)
+    (error "This back end does not support group deletion"))
+  (prog1
+      (let ((group-decoded (gnus-group-decoded-name group)))
+       (if (and (not no-prompt)
+                (not (gnus-yes-or-no-p
+                      (format
+                       "Do you really want to delete %s%s? "
+                       group-decoded (if force " and all its contents" "")))))
+           ()                          ; Whew!
+         (gnus-message 6 "Deleting group %s..." group-decoded)
+         (if (not (gnus-request-delete-group group force))
+             (gnus-error 3 "Couldn't delete group %s" group-decoded)
+           (gnus-message 6 "Deleting group %s...done" group-decoded)
+           (gnus-group-goto-group group)
+           (gnus-group-kill-group 1 t)
+           (gnus-set-active group nil)
+           t)))
+    (gnus-group-position-point)))
+
+(defun gnus-group-rename-group (group new-name)
+  "Rename group from GROUP to NEW-NAME.
+When used interactively, GROUP is the group under point
+and NEW-NAME will be prompted for."
+  (interactive
+   (let ((group (gnus-group-group-name))
+        method new-name)
+     (unless (gnus-check-backend-function 'request-rename-group group)
+       (error "This back end does not support renaming groups"))
+     (setq new-name (gnus-read-group
+                    "Rename group to: "
+                    (gnus-group-real-name (gnus-group-decoded-name group)))
+          method (gnus-info-method (gnus-get-info group)))
+     (list group (mm-encode-coding-string
+                 new-name
+                 (gnus-group-name-charset
+                  method
+                  (gnus-group-prefixed-name new-name method))))))
+
+  (unless (gnus-check-backend-function 'request-rename-group group)
+    (error "This back end does not support renaming groups"))
+  (unless group
+    (error "No group to rename"))
+  (when (equal (gnus-group-real-name group) new-name)
+    (error "Can't rename to the same name"))
+
+  ;; We find the proper prefixed name.
+  (setq new-name
+       (if (gnus-group-native-p group)
+           ;; Native group.
+           new-name
+         ;; Foreign group.
+         (gnus-group-prefixed-name
+          (gnus-group-real-name new-name)
+          (gnus-info-method (gnus-get-info group)))))
+
+  (let ((decoded-group (gnus-group-decoded-name group))
+       (decoded-new-name (gnus-group-decoded-name new-name)))
+    (when (gnus-active new-name)
+      (error "The group %s already exists" decoded-new-name))
+
+    (gnus-message 6 "Renaming group %s to %s..."
+                 decoded-group decoded-new-name)
+    (prog1
+       (if (progn
+             (gnus-group-goto-group group)
+             (not (when (< (gnus-group-group-level) gnus-level-zombie)
+                    (gnus-request-rename-group group new-name))))
+           (gnus-error 3 "Couldn't rename group %s to %s"
+                       decoded-group decoded-new-name)
+         ;; We rename the group internally by killing it...
+         (gnus-group-kill-group)
+         ;; ... changing its name ...
+         (setcar (cdar gnus-list-of-killed-groups) new-name)
+         ;; ... and then yanking it.  Magic!
+         (gnus-group-yank-group)
+         (gnus-set-active new-name (gnus-active group))
+         (gnus-message 6 "Renaming group %s to %s...done"
+                       decoded-group decoded-new-name)
+         new-name)
+      (setq gnus-killed-list (delete group gnus-killed-list))
+      (gnus-set-active group nil)
+      (gnus-dribble-touch)
+      (gnus-group-position-point))))
+
+(defun gnus-group-edit-group (group &optional part)
+  "Edit the group on the current line."
+  (interactive (list (gnus-group-group-name)))
+  (let ((part (or part 'info))
+       info)
+    (unless group
+      (error "No group on current line"))
+    (unless (setq info (gnus-get-info group))
+      (error "Killed group; can't be edited"))
+    (ignore-errors
+      (gnus-close-group group))
+    (gnus-edit-form
+     ;; Find the proper form to edit.
+     (cond ((eq part 'method)
+           (or (gnus-info-method info) "native"))
+          ((eq part 'params)
+           (gnus-info-params info))
+          (t info))
+     ;; The proper documentation.
+     (gnus-format-message
+      "Editing the %s for `%s'."
+      (cond
+       ((eq part 'method) "select method")
+       ((eq part 'params) "group parameters")
+       (t "group info"))
+      (gnus-group-decoded-name group))
+     `(lambda (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."
+  (interactive (list (gnus-group-group-name)))
+  (gnus-group-edit-group group 'method))
+
+(defun gnus-group-edit-group-parameters (group)
+  "Edit the group parameters of GROUP."
+  (interactive (list (gnus-group-group-name)))
+  (gnus-group-edit-group group 'params))
+
+(defun gnus-group-edit-group-done (part group form)
+  "Update variables."
+  (let* ((method (cond ((eq part 'info) (nth 4 form))
+                      ((eq part 'method) form)
+                      (t nil)))
+        (info (cond ((eq part 'info) form)
+                    ((eq part 'method) (gnus-get-info group))
+                    (t nil)))
+        (new-group (if info
+                       (if (or (not method)
+                               (gnus-server-equal
+                                gnus-select-method method))
+                           (gnus-group-real-name (car info))
+                         (gnus-group-prefixed-name
+                          (gnus-group-real-name (car info)) method))
+                     nil)))
+    (when (and new-group
+              (not (equal new-group group)))
+      (when (gnus-group-goto-group group)
+       (gnus-group-kill-group 1))
+      (gnus-activate-group new-group))
+    ;; Set the info.
+    (if (not (and info new-group))
+       (gnus-group-set-info form (or new-group group) part)
+      (setq info (gnus-copy-sequence info))
+      (setcar info new-group)
+      (unless (gnus-server-equal method "native")
+       (unless (nthcdr 3 info)
+         (nconc info (list nil nil)))
+       (unless (nthcdr 4 info)
+         (nconc info (list nil)))
+       (gnus-info-set-method info method))
+      (gnus-group-set-info info))
+    (gnus-group-update-group (or new-group group))
+    (gnus-group-position-point)))
+
+(defun gnus-group-make-useful-group (group method)
+  "Create one of the groups described in `gnus-useful-groups'."
+  (interactive
+   (let ((entry (assoc (gnus-completing-read "Create group"
+                                             (mapcar 'car gnus-useful-groups)
+                                             t)
+                      gnus-useful-groups)))
+     (list (cadr entry)
+          ;; Don't use `caddr' here since macros within the `interactive'
+          ;; form won't be expanded.
+          (car (cddr entry)))))
+  (setq method (gnus-copy-sequence method))
+  (let (entry)
+    (while (setq entry (memq (assq 'eval method) method))
+      (setcar entry (eval (cadar entry)))))
+  (gnus-group-make-group group method))
+
+(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)))
+    (if (gnus-group-entry name)
+       (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)
+  "Create a group that uses a single file as the source.
+
+If called with a prefix argument, ask for the file type."
+  (interactive
+   (list (read-file-name "File name: ")
+        (and current-prefix-arg 'ask)))
+  (when (eq type 'ask)
+    (let ((err "")
+         char found)
+      (while (not found)
+       (message
+        "%sFile type (mbox, babyl, digest, forward, mmdf, guess) [m, b, d, f, a, g]: "
+        err)
+       (setq found (cond ((= (setq char (read-char)) ?m) 'mbox)
+                         ((= char ?b) 'babyl)
+                         ((= char ?d) 'digest)
+                         ((= char ?f) 'forward)
+                         ((= char ?a) 'mmfd)
+                         ((= char ?g) 'guess)
+                         (t (setq err (format "%c unknown. " char))
+                            nil))))
+      (setq type found)))
+  (setq file (expand-file-name file))
+  (let* ((name (gnus-generate-new-group-name
+               (gnus-group-prefixed-name
+                (file-name-nondirectory file) '(nndoc ""))))
+        (method (list 'nndoc file
+                      (list 'nndoc-address file)
+                      (list 'nndoc-article-type (or type 'guess))))
+        (coding (gnus-group-name-charset method name)))
+    (setcar (cdr method) (mm-encode-coding-string file coding))
+    (gnus-group-make-group
+     (mm-encode-coding-string (gnus-group-real-name name) coding)
+     method nil nil t)))
+
+(defvar nnweb-type-definition)
+(defvar gnus-group-web-type-history nil)
+(defvar gnus-group-web-search-history nil)
+(defun gnus-group-make-web-group (&optional solid)
+  "Create an ephemeral nnweb group.
+If SOLID (the prefix), create a solid group."
+  (interactive "P")
+  (require 'nnweb)
+  (let* ((group
+         (if solid (gnus-read-group "Group name: ")
+           (message-unique-id)))
+        (default-type (or (car gnus-group-web-type-history)
+                          (symbol-name (caar nnweb-type-definition))))
+        (type
+         (gnus-string-or
+          (gnus-completing-read
+           "Search engine type"
+           (mapcar (lambda (elem) (symbol-name (car elem)))
+                   nnweb-type-definition)
+           t nil 'gnus-group-web-type-history)
+          default-type))
+        (search
+         (read-string
+          "Search string: "
+          (cons (or (car gnus-group-web-search-history) "") 0)
+          'gnus-group-web-search-history))
+        (method
+         `(nnweb ,group (nnweb-search ,search)
+                 (nnweb-type ,(intern type))
+                 (nnweb-ephemeral-p t))))
+    (if solid
+       (progn
+         (gnus-alist-pull 'nnweb-ephemeral-p method)
+         (gnus-group-make-group group method))
+      (gnus-group-read-ephemeral-group
+       group method t
+       (cons (current-buffer)
+            (if (derived-mode-p 'gnus-summary-mode) 'summary 'group))))))
+
+(defvar nnrss-group-alist)
+(eval-when-compile
+  (defun nnrss-discover-feed (_arg))
+  (defun nnrss-save-server-data (_arg)))
+(defun gnus-group-make-rss-group (&optional url)
+  "Given a URL, discover if there is an RSS feed.
+If there is, use Gnus to create an nnrss group"
+  (interactive)
+  (require 'nnrss)
+  (if (not url)
+      (setq url (read-from-minibuffer "URL to Search for RSS: ")))
+  (let ((feedinfo (nnrss-discover-feed url)))
+    (if feedinfo
+       (let* ((title (gnus-newsgroup-savable-name
+                      (read-from-minibuffer "Title: "
+                                            (gnus-newsgroup-savable-name
+                                             (mapconcat
+                                              'identity
+                                              (split-string
+                                               (or (cdr (assoc 'title
+                                                               feedinfo))
+                                                   ""))
+                                              " ")))))
+              (desc  (read-from-minibuffer "Description: "
+                                           (mapconcat
+                                            'identity
+                                            (split-string
+                                             (or (cdr (assoc 'description
+                                                             feedinfo))
+                                                 ""))
+                                            " ")))
+              (href (cdr (assoc 'href feedinfo)))
+              (coding (gnus-group-name-charset '(nnrss "") title)))
+         (when coding
+           ;; Unify non-ASCII text.
+           (setq title (mm-decode-coding-string
+                        (mm-encode-coding-string title coding)
+                        coding)))
+         (gnus-group-make-group title '(nnrss ""))
+         (push (list title href desc) nnrss-group-alist)
+         (nnrss-save-server-data nil))
+      (error "No feeds found for %s" url))))
+
+(defun gnus-group-make-directory-group (dir)
+  "Create an nndir group.
+The user will be prompted for a directory.  The contents of this
+directory will be used as a newsgroup.  The directory should contain
+mail messages or news articles in files that have numeric names."
+  (interactive
+   (list (read-directory-name "Create group from directory: ")))
+  (unless (file-exists-p dir)
+    (error "No such directory"))
+  (unless (file-directory-p dir)
+    (error "Not a directory"))
+  (let ((ext "")
+       (i 0)
+       group)
+    (while (or (not group) (gnus-group-entry group))
+      (setq group
+           (gnus-group-prefixed-name
+            (expand-file-name ext dir)
+            '(nndir "")))
+      (setq ext (format "<%d>" (setq i (1+ i)))))
+    (gnus-group-make-group
+     (gnus-group-real-name group)
+     (list 'nndir (gnus-group-real-name group) (list 'nndir-directory dir)))))
+
+(defun gnus-group-add-to-virtual (n vgroup)
+  "Add the current group to a virtual group."
+  (interactive
+   (list current-prefix-arg
+        (gnus-group-completing-read "Add to virtual group"
+                                     nil t "nnvirtual:")))
+  (unless (eq (car (gnus-find-method-for-group vgroup)) 'nnvirtual)
+    (error "%s is not an nnvirtual group" vgroup))
+  (gnus-close-group vgroup)
+  (let* ((groups (gnus-group-process-prefix n))
+        (method (gnus-info-method (gnus-get-info vgroup))))
+    (setcar (cdr method)
+           (concat
+            (nth 1 method) "\\|"
+            (mapconcat
+             (lambda (s)
+               (gnus-group-remove-mark s)
+               (concat "\\(^" (regexp-quote s) "$\\)"))
+             groups "\\|"))))
+  (gnus-group-position-point))
+
+(defun gnus-group-make-empty-virtual (group)
+  "Create a new, fresh, empty virtual group."
+  (interactive "sCreate new, empty virtual group: ")
+  (let* ((method (list 'nnvirtual "^$"))
+        (pgroup (gnus-group-prefixed-name group method)))
+    ;; Check whether it exists already.
+    (when (gnus-group-entry pgroup)
+      (error "Group %s already exists" pgroup))
+    ;; Subscribe the new group after the group on the current line.
+    (gnus-subscribe-group pgroup (gnus-group-group-name) method)
+    (gnus-group-update-group pgroup)
+    (forward-line -1)
+    (gnus-group-position-point)))
+
+(defun gnus-group-enter-directory (dir)
+  "Enter an ephemeral nneething group."
+  (interactive "DDirectory to read: ")
+  (let* ((method (list 'nneething dir '(nneething-read-only t)))
+        (leaf (gnus-group-prefixed-name
+               (file-name-nondirectory (directory-file-name dir))
+               method))
+        (name (gnus-generate-new-group-name leaf)))
+    (unless (gnus-group-read-ephemeral-group
+            name method t
+            (cons (current-buffer)
+                  (if (derived-mode-p 'gnus-summary-mode)
+                      'summary 'group)))
+      (error "Couldn't enter %s" dir))))
+
+(defun gnus-group-expunge-group (group)
+  "Expunge deleted articles in current nnimap GROUP."
+  (interactive (list (gnus-group-group-name)))
+  (let ((method (gnus-find-method-for-group group)))
+    (if (not (gnus-check-backend-function
+             'request-expunge-group (car method)))
+       (error "%s does not support expunging" (car method))
+      (gnus-request-expunge-group group method))))
+
+(autoload 'nnimap-acl-get "nnimap")
+(autoload 'nnimap-acl-edit "nnimap")
+
+(defun gnus-group-nnimap-edit-acl (group)
+  "Edit the Access Control List of current nnimap GROUP."
+  (interactive (list (gnus-group-group-name)))
+  (let ((mailbox (gnus-group-real-name group)) method acl)
+    (unless group
+      (error "No group on current line"))
+    (unless (gnus-get-info group)
+      (error "Killed group; can't be edited"))
+    (unless (eq (car (setq method (gnus-find-method-for-group group))) 'nnimap)
+      (error "%s is not an nnimap group" group))
+    (unless (setq acl (nnimap-acl-get mailbox (cadr method)))
+      (error "Server does not support ACL's"))
+    (gnus-edit-form acl (gnus-format-message "\
+Editing the access control list for `%s'.
+
+   An access control list is a list of (identifier . rights) elements.
+
+   The identifier string specifies the corresponding user.  The
+   identifier \"anyone\" is reserved to refer to the universal identity.
+
+   Rights is a string listing a (possibly empty) set of alphanumeric
+   characters, each character listing a set of operations which is being
+   controlled.  Letters are reserved for \"standard\" rights, listed
+   below.  Digits are reserved for implementation or site defined rights.
+
+   l - lookup (mailbox is visible to LIST/LSUB commands)
+   r - read (SELECT the mailbox, perform CHECK, FETCH, PARTIAL,
+       SEARCH, COPY from mailbox)
+   s - keep seen/unseen information across sessions (STORE \\SEEN flag)
+   w - write (STORE flags other than \\SEEN and \\DELETED)
+   i - insert (perform APPEND, COPY into mailbox)
+   p - post (send mail to submission address for mailbox,
+       not enforced by IMAP4 itself)
+   c - create and delete mailbox (CREATE new sub-mailboxes in any
+       implementation-defined hierarchy, RENAME or DELETE mailbox)
+   d - delete messages (STORE \\DELETED flag, perform EXPUNGE)
+   a - administer (perform SETACL)" group)
+                   `(lambda (form)
+                      (nnimap-acl-edit
+                       ,mailbox ',method ',acl form)))))
+
+;; Group sorting commands
+;; Suggested by Joe Hildebrand <hildjj@idaho.fuentez.com>.
+
+(defun gnus-group-sort-groups (func &optional reverse)
+  "Sort the group buffer according to FUNC.
+When used interactively, the sorting function used will be
+determined by the `gnus-group-sort-function' variable.
+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))
+
+(defun gnus-group-sort-flat (func reverse)
+  ;; We peel off the dummy group from the alist.
+  (when func
+    (when (equal (gnus-info-group (car gnus-newsrc-alist)) "dummy.group")
+      (pop gnus-newsrc-alist))
+    ;; Do the sorting.
+    (setq gnus-newsrc-alist
+         (sort gnus-newsrc-alist func))
+    (when reverse
+      (setq gnus-newsrc-alist (nreverse gnus-newsrc-alist)))
+    ;; Regenerate the hash table.
+    (gnus-make-hashtable-from-newsrc-alist)))
+
+(defun gnus-group-sort-groups-by-alphabet (&optional reverse)
+  "Sort the group buffer alphabetically by group name.
+If REVERSE, sort in reverse order."
+  (interactive "P")
+  (gnus-group-sort-groups 'gnus-group-sort-by-alphabet reverse))
+
+(defun gnus-group-sort-groups-by-real-name (&optional reverse)
+  "Sort the group buffer alphabetically by real (unprefixed) group name.
+If REVERSE, sort in reverse order."
+  (interactive "P")
+  (gnus-group-sort-groups 'gnus-group-sort-by-real-name reverse))
+
+(defun gnus-group-sort-groups-by-unread (&optional reverse)
+  "Sort the group buffer by number of unread articles.
+If REVERSE, sort in reverse order."
+  (interactive "P")
+  (gnus-group-sort-groups 'gnus-group-sort-by-unread reverse))
+
+(defun gnus-group-sort-groups-by-level (&optional reverse)
+  "Sort the group buffer by group level.
+If REVERSE, sort in reverse order."
+  (interactive "P")
+  (gnus-group-sort-groups 'gnus-group-sort-by-level reverse))
+
+(defun gnus-group-sort-groups-by-score (&optional reverse)
+  "Sort the group buffer by group score.
+If REVERSE, sort in reverse order."
+  (interactive "P")
+  (gnus-group-sort-groups 'gnus-group-sort-by-score reverse))
+
+(defun gnus-group-sort-groups-by-rank (&optional reverse)
+  "Sort the group buffer by group rank.
+If REVERSE, sort in reverse order."
+  (interactive "P")
+  (gnus-group-sort-groups 'gnus-group-sort-by-rank reverse))
+
+(defun gnus-group-sort-groups-by-method (&optional reverse)
+  "Sort the group buffer alphabetically by back end name.
+If REVERSE, sort in reverse order."
+  (interactive "P")
+  (gnus-group-sort-groups 'gnus-group-sort-by-method reverse))
+
+(defun gnus-group-sort-groups-by-server (&optional reverse)
+  "Sort the group buffer alphabetically by server name.
+If REVERSE, sort in reverse order."
+  (interactive "P")
+  (gnus-group-sort-groups 'gnus-group-sort-by-server reverse))
+
+;;; Selected group sorting.
+
+(defun gnus-group-sort-selected-groups (n func &optional reverse)
+  "Sort the process/prefixed groups."
+  (interactive (list current-prefix-arg gnus-group-sort-function))
+  (let ((groups (gnus-group-process-prefix n)))
+    (funcall gnus-group-sort-selected-function
+            groups (gnus-make-sort-function func) reverse)
+    (gnus-group-unmark-all-groups)
+    (gnus-group-list-groups)
+    (gnus-dribble-touch)))
+
+(defun gnus-group-sort-selected-flat (groups func reverse)
+  (let (entries infos)
+    ;; First find all the group entries for these groups.
+    (while groups
+      (push (nthcdr 2 (gnus-group-entry (pop groups)))
+           entries))
+    ;; Then sort the infos.
+    (setq infos
+         (sort
+          (mapcar
+           (lambda (entry) (car entry))
+           (setq entries (nreverse entries)))
+          func))
+    (when reverse
+      (setq infos (nreverse infos)))
+    ;; Go through all the infos and replace the old entries
+    ;; with the new infos.
+    (while infos
+      (setcar (car entries) (pop infos))
+      (pop entries))
+    ;; Update the hashtable.
+    (gnus-make-hashtable-from-newsrc-alist)))
+
+(defun gnus-group-sort-selected-groups-by-alphabet (&optional n reverse)
+  "Sort the group buffer alphabetically by group name.
+Obeys the process/prefix convention.  If REVERSE (the symbolic prefix),
+sort in reverse order."
+  (interactive (gnus-interactive "P\ny"))
+  (gnus-group-sort-selected-groups n 'gnus-group-sort-by-alphabet reverse))
+
+(defun gnus-group-sort-selected-groups-by-real-name (&optional n reverse)
+  "Sort the group buffer alphabetically by real group name.
+Obeys the process/prefix convention.  If REVERSE (the symbolic prefix),
+sort in reverse order."
+  (interactive (gnus-interactive "P\ny"))
+  (gnus-group-sort-selected-groups n 'gnus-group-sort-by-real-name reverse))
+
+(defun gnus-group-sort-selected-groups-by-unread (&optional n reverse)
+  "Sort the group buffer by number of unread articles.
+Obeys the process/prefix convention.  If REVERSE (the symbolic prefix),
+sort in reverse order."
+  (interactive (gnus-interactive "P\ny"))
+  (gnus-group-sort-selected-groups n 'gnus-group-sort-by-unread reverse))
+
+(defun gnus-group-sort-selected-groups-by-level (&optional n reverse)
+  "Sort the group buffer by group level.
+Obeys the process/prefix convention.  If REVERSE (the symbolic prefix),
+sort in reverse order."
+  (interactive (gnus-interactive "P\ny"))
+  (gnus-group-sort-selected-groups n 'gnus-group-sort-by-level reverse))
+
+(defun gnus-group-sort-selected-groups-by-score (&optional n reverse)
+  "Sort the group buffer by group score.
+Obeys the process/prefix convention.  If REVERSE (the symbolic prefix),
+sort in reverse order."
+  (interactive (gnus-interactive "P\ny"))
+  (gnus-group-sort-selected-groups n 'gnus-group-sort-by-score reverse))
+
+(defun gnus-group-sort-selected-groups-by-rank (&optional n reverse)
+  "Sort the group buffer by group rank.
+Obeys the process/prefix convention.  If REVERSE (the symbolic prefix),
+sort in reverse order."
+  (interactive (gnus-interactive "P\ny"))
+  (gnus-group-sort-selected-groups n 'gnus-group-sort-by-rank reverse))
+
+(defun gnus-group-sort-selected-groups-by-method (&optional n reverse)
+  "Sort the group buffer alphabetically by back end name.
+Obeys the process/prefix convention.  If REVERSE (the symbolic prefix),
+sort in reverse order."
+  (interactive (gnus-interactive "P\ny"))
+  (gnus-group-sort-selected-groups n 'gnus-group-sort-by-method reverse))
+
+;;; Sorting predicates.
+
+(defun gnus-group-sort-by-alphabet (info1 info2)
+  "Sort alphabetically."
+  (string< (gnus-info-group info1) (gnus-info-group info2)))
+
+(defun gnus-group-sort-by-real-name (info1 info2)
+  "Sort alphabetically on real (unprefixed) names."
+  (string< (gnus-group-real-name (gnus-info-group info1))
+          (gnus-group-real-name (gnus-info-group info2))))
+
+(defun gnus-group-sort-by-unread (info1 info2)
+  "Sort by number of unread articles."
+  (let ((n1 (gnus-group-unread (gnus-info-group info1)))
+       (n2 (gnus-group-unread (gnus-info-group info2))))
+    (< (or (and (numberp n1) n1) 0)
+       (or (and (numberp n2) n2) 0))))
+
+(defun gnus-group-sort-by-level (info1 info2)
+  "Sort by level."
+  (< (gnus-info-level info1) (gnus-info-level info2)))
+
+(defun gnus-group-sort-by-method (info1 info2)
+  "Sort alphabetically by back end name."
+  (string< (car (gnus-find-method-for-group
+                (gnus-info-group info1) info1))
+          (car (gnus-find-method-for-group
+                (gnus-info-group info2) info2))))
+
+(defun gnus-group-sort-by-server (info1 info2)
+  "Sort alphabetically by server name."
+  (string< (gnus-method-to-full-server-name
+           (gnus-find-method-for-group
+            (gnus-info-group info1) info1))
+          (gnus-method-to-full-server-name
+           (gnus-find-method-for-group
+            (gnus-info-group info2) info2))))
+
+(defun gnus-group-sort-by-score (info1 info2)
+  "Sort by group score."
+  (> (gnus-info-score info1) (gnus-info-score info2)))
+
+(defun gnus-group-sort-by-rank (info1 info2)
+  "Sort by level and score."
+  (let ((level1 (gnus-info-level info1))
+       (level2 (gnus-info-level info2)))
+    (or (< level1 level2)
+       (and (= level1 level2)
+            (> (gnus-info-score info1) (gnus-info-score info2))))))
+
+;;; Clearing data
+
+(defun gnus-group-clear-data (&optional arg)
+  "Clear all marks and read ranges from the current group.
+Obeys the process/prefix convention."
+  (interactive "P")
+  (when (gnus-y-or-n-p "Really clear data? ")
+    (gnus-group-iterate arg
+      (lambda (group)
+       (let (info)
+         (gnus-info-clear-data (setq info (gnus-get-info group)))
+         (gnus-get-unread-articles-in-group info (gnus-active group) t)
+         (when (gnus-group-goto-group group)
+           (gnus-group-update-group-line)))))))
+
+(defun gnus-group-clear-data-on-native-groups ()
+  "Clear all marks and read ranges from all native groups."
+  (interactive)
+  (when (gnus-yes-or-no-p "Really clear all data from almost all groups? ")
+    (let ((alist (cdr gnus-newsrc-alist))
+         info)
+      (while (setq info (pop alist))
+       (when (gnus-group-native-p (gnus-info-group info))
+         (gnus-info-clear-data info)))
+      (gnus-get-unread-articles)
+      (gnus-dribble-touch)
+      (when (gnus-y-or-n-p
+            "Move the cache away to avoid problems in the future? ")
+       (call-interactively 'gnus-cache-move-cache)))))
+
+(defun gnus-info-clear-data (info)
+  "Clear all marks and read ranges from 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))))
+
+;; Group catching up.
+
+(defun gnus-group-catchup-current (&optional n all)
+  "Mark all unread articles in the current newsgroup as read.
+If prefix argument N is numeric, the next N newsgroups will be
+caught up.  If ALL is non-nil, marked articles will also be marked as
+read.  Cross references (Xref: header) of articles are ignored.
+The number of newsgroups that this function was unable to catch
+up is returned."
+  (interactive "P")
+  (let ((groups (gnus-group-process-prefix n))
+       (ret 0)
+       group)
+    (unless groups (error "No groups selected"))
+    (if (not
+        (or (not gnus-interactive-catchup) ;Without confirmation?
+            gnus-expert-user
+            (gnus-y-or-n-p
+             (format
+              (if all
+                  "Do you really want to mark all articles in %s as read? "
+                "Mark all unread articles in %s as read? ")
+              (if (= (length groups) 1)
+                  (gnus-group-decoded-name (car groups))
+                (format "these %d groups" (length groups)))))))
+       n
+      (while (setq group (pop groups))
+       (gnus-group-remove-mark group)
+       ;; Virtual groups have to be given special treatment.
+       (let ((method (gnus-find-method-for-group group)))
+         (when (eq 'nnvirtual (car method))
+           (nnvirtual-catchup-group
+            (gnus-group-real-name group) (nth 1 method) all)))
+       (cond
+        ((>= (gnus-group-level group) gnus-level-zombie)
+         (gnus-message 2 "Dead groups can't be caught up"))
+        ((prog1
+             (gnus-group-goto-group group)
+           (gnus-group-catchup group all))
+         (gnus-group-update-group-line))
+        (t
+         (setq ret (1+ ret)))))
+      (gnus-group-next-unread-group 1)
+      ret)))
+
+(defun gnus-group-catchup-current-all (&optional n)
+  "Mark all articles in current newsgroup as read.
+Cross references (Xref: header) of articles are ignored."
+  (interactive "P")
+  (gnus-group-catchup-current n 'all))
+
+(declare-function gnus-sequence-of-unread-articles "gnus-sum" (group))
+
+(defun gnus-group-catchup (group &optional all)
+  "Mark all articles in GROUP as read.
+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-group-entry group))
+        (num (car entry))
+        (marks (gnus-info-marks (nth 2 entry)))
+        (unread (gnus-sequence-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-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 (and (gnus-group-auto-expirable-p group)
+                (not (gnus-group-read-only-p group)))
+        (gnus-range-map
+        (lambda (article)
+          (gnus-add-marked-articles group 'expire (list article))
+          (gnus-request-set-mark group (list (list (list article)
+                                                   'add '(expire)))))
+        unread))
+      (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.
+Uses the process/prefix convention."
+  (interactive "P")
+  (let ((groups (gnus-group-process-prefix n))
+       group)
+    (unless groups
+      (error "No groups to expire"))
+    (while (setq group (pop groups))
+      (gnus-group-remove-mark group)
+      (gnus-group-expire-articles-1 group)
+      (gnus-dribble-touch)
+      (gnus-group-position-point))))
+
+(defun gnus-group-expire-articles-1 (group)
+  (when (gnus-check-backend-function 'request-expire-articles group)
+    (gnus-message 6 "Expiring articles in %s..."
+                 (gnus-group-decoded-name group))
+    (let* ((info (gnus-get-info group))
+          (expirable (if (gnus-group-total-expirable-p group)
+                         (cons nil (gnus-list-of-read-articles group))
+                       (assq 'expire (gnus-info-marks info))))
+          (articles-to-expire
+           (gnus-list-range-difference
+            (gnus-uncompress-sequence (cdr expirable))
+            (cdr (assq 'unexist (gnus-info-marks info)))))
+          (expiry-wait (gnus-group-find-parameter group 'expiry-wait))
+          (nnmail-expiry-target
+           (or (gnus-group-find-parameter group 'expiry-target)
+               nnmail-expiry-target)))
+      (when expirable
+       (gnus-check-group group)
+       (setcdr
+        expirable
+        (gnus-compress-sequence
+         (if expiry-wait
+             ;; We set the expiry variables to the group
+             ;; parameter.
+             (let ((nnmail-expiry-wait-function nil)
+                   (nnmail-expiry-wait expiry-wait))
+               (gnus-request-expire-articles articles-to-expire group))
+           ;; Just expire using the normal expiry values.
+           (gnus-request-expire-articles articles-to-expire group))))
+       (gnus-close-group group))
+      (gnus-message 6 "Expiring articles in %s...done"
+                   (gnus-group-decoded-name group))
+      ;; Return the list of un-expired articles.
+      (cdr expirable))))
+
+(defun gnus-group-expire-all-groups ()
+  "Expire all expirable articles in all newsgroups."
+  (interactive)
+  (save-excursion
+    (gnus-message 5 "Expiring...")
+    (let ((gnus-group-marked (mapcar (lambda (info) (gnus-info-group info))
+                                    (cdr gnus-newsrc-alist))))
+      (gnus-group-expire-articles nil)))
+  (gnus-group-position-point)
+  (gnus-message 5 "Expiring...done"))
+
+(defun gnus-group-set-current-level (n level)
+  "Set the level of the next N groups to LEVEL."
+  (interactive
+   (list
+    current-prefix-arg
+    (progn
+      (unless (gnus-group-process-prefix current-prefix-arg)
+       (error "No group on the current line"))
+      (string-to-number
+       (let ((s (read-string
+                (format "Level (default %s): "
+                        (or (gnus-group-group-level)
+                            gnus-level-default-subscribed)))))
+        (if (string-match "^\\s-*$" s)
+            (int-to-string (or (gnus-group-group-level)
+                               gnus-level-default-subscribed))
+          s))))))
+  (unless (and (>= level 1) (<= level gnus-level-killed))
+    (error "Invalid level: %d" level))
+  (dolist (group (gnus-group-process-prefix n))
+    (gnus-group-remove-mark group)
+    (gnus-message 6 "Changed level of %s from %d to %d"
+                 (gnus-group-decoded-name group)
+                 (or (gnus-group-group-level) gnus-level-killed)
+                 level)
+    (gnus-group-change-level
+     group level (or (gnus-group-group-level) gnus-level-killed))
+    (gnus-group-update-group-line))
+  (gnus-group-position-point))
+
+(defun gnus-group-unsubscribe (&optional n)
+  "Unsubscribe the current group."
+  (interactive "P")
+  (gnus-group-unsubscribe-current-group n 'unsubscribe))
+
+(defun gnus-group-subscribe (&optional n)
+  "Subscribe the current group."
+  (interactive "P")
+  (gnus-group-unsubscribe-current-group n 'subscribe))
+
+(defun gnus-group-unsubscribe-current-group (&optional n do-sub)
+  "Toggle subscription of the current group.
+If given numerical prefix, toggle the N next groups."
+  (interactive "P")
+  (dolist (group (gnus-group-process-prefix n))
+    (gnus-group-remove-mark group)
+    (gnus-group-unsubscribe-group
+     group
+     (cond
+      ((eq do-sub 'unsubscribe)
+       gnus-level-default-unsubscribed)
+      ((eq do-sub 'subscribe)
+       gnus-level-default-subscribed)
+      ((<= (gnus-group-group-level) gnus-level-subscribed)
+       gnus-level-default-unsubscribed)
+      (t
+       gnus-level-default-subscribed))
+     t)
+    (gnus-group-update-group-line))
+  (gnus-group-next-group 1))
+
+(defun gnus-group-unsubscribe-group (group &optional level silent)
+  "Toggle subscription to GROUP.
+Killed newsgroups are subscribed.  If SILENT, don't try to update the
+group line."
+  (interactive (list (gnus-group-completing-read
+                     nil nil (gnus-read-active-file-p))))
+  (let ((newsrc (gnus-group-entry group)))
+    (cond
+     ((string-match "\\`[ \t]*\\'" group)
+      (error "Empty group name"))
+     (newsrc
+      ;; Toggle subscription flag.
+      (gnus-group-change-level
+       newsrc (if level level (if (<= (gnus-info-level (nth 2 newsrc))
+                                     gnus-level-subscribed)
+                                 (1+ gnus-level-subscribed)
+                               gnus-level-default-subscribed)))
+      (unless silent
+       (gnus-group-update-group group)))
+     ((and (stringp group)
+          (or (not (gnus-read-active-file-p))
+              (gnus-active group)))
+      ;; Add new newsgroup.
+      (gnus-group-change-level
+       group
+       (if level level gnus-level-default-subscribed)
+       (or (and (member group gnus-zombie-list)
+               gnus-level-zombie)
+          gnus-level-killed)
+       (when (gnus-group-group-name)
+        (gnus-group-entry (gnus-group-group-name))))
+      (unless silent
+       (gnus-group-update-group group)))
+     (t (error "No such newsgroup: %s" group)))
+    (gnus-group-position-point)))
+
+(defun gnus-group-transpose-groups (n)
+  "Move the current newsgroup up N places.
+If given a negative prefix, move down instead.  The difference between
+N and the number of steps taken is returned."
+  (interactive "p")
+  (unless (gnus-group-group-name)
+    (error "No group on current line"))
+  (gnus-group-kill-group 1)
+  (prog1
+      (forward-line (- n))
+    (gnus-group-yank-group)
+    (gnus-group-position-point)))
+
+(defun gnus-group-kill-all-zombies (&optional dummy)
+  "Kill all zombie newsgroups.
+The optional DUMMY should always be nil."
+  (interactive (list (not (gnus-yes-or-no-p "Really kill all zombies? "))))
+  (unless dummy
+    (setq gnus-killed-list (nconc gnus-zombie-list gnus-killed-list))
+    (setq gnus-zombie-list nil)
+    (gnus-dribble-touch)
+    (gnus-group-list-groups)))
+
+(defun gnus-group-kill-region (begin end)
+  "Kill newsgroups in current region (excluding current point).
+The killed newsgroups can be yanked by using \\[gnus-group-yank-group]."
+  (interactive "r")
+  (let ((lines
+        ;; Count lines.
+        (save-excursion
+          (count-lines
+           (progn
+             (goto-char begin)
+             (point-at-bol))
+           (progn
+             (goto-char end)
+             (point-at-bol))))))
+    (goto-char begin)
+    (beginning-of-line)                        ;Important when LINES < 1
+    (gnus-group-kill-group lines)))
+
+(defun gnus-group-kill-group (&optional n discard)
+  "Kill the next N groups.
+The killed newsgroups can be yanked by using \\[gnus-group-yank-group].
+However, only groups that were alive can be yanked; already killed
+groups or zombie groups can't be yanked.
+The return value is the name of the group that was killed, or a list
+of groups killed."
+  (interactive "P")
+  (let ((buffer-read-only nil)
+       (groups (gnus-group-process-prefix n))
+       group entry level out)
+    (if (< (length groups) 10)
+       ;; This is faster when there are few groups.
+       (while groups
+         (push (setq group (pop groups)) out)
+         (gnus-group-remove-mark group)
+         (setq level (gnus-group-group-level))
+         (gnus-delete-line)
+         (when (and (not discard)
+                    (setq entry (gnus-group-entry group)))
+           (gnus-undo-register
+             `(progn
+                (gnus-group-goto-group ,(gnus-group-group-name))
+                (gnus-group-yank-group)))
+           (push (cons (car entry) (nth 2 entry))
+                 gnus-list-of-killed-groups))
+         (gnus-group-change-level
+          (if entry entry group) gnus-level-killed (if entry nil level))
+         (when (numberp (gnus-group-unread group))
+           (gnus-request-update-group-status group 'unsubscribe))
+         (message "Killed group %s" (gnus-group-decoded-name group)))
+      ;; If there are lots and lots of groups to be killed, we use
+      ;; this thing instead.
+      (dolist (group (nreverse groups))
+       (gnus-group-remove-mark group)
+       (gnus-delete-line)
+       (push group gnus-killed-list)
+       (setq gnus-newsrc-alist
+             (delq (assoc group gnus-newsrc-alist)
+                   gnus-newsrc-alist))
+       (when gnus-group-change-level-function
+         (funcall gnus-group-change-level-function
+                  group gnus-level-killed 3))
+       (cond
+        ((setq entry (gnus-group-entry group))
+         (push (cons (car entry) (nth 2 entry))
+               gnus-list-of-killed-groups)
+         (setcdr (cdr entry) (cdddr entry)))
+        ((member group gnus-zombie-list)
+         (setq gnus-zombie-list (delete group gnus-zombie-list))))
+       ;; There may be more than one instance displayed.
+       (while (gnus-group-goto-group group)
+         (gnus-delete-line))
+       (when (numberp (gnus-group-unread group))
+         (gnus-request-update-group-status group 'unsubscribe)))
+      (gnus-make-hashtable-from-newsrc-alist))
+
+    (gnus-group-position-point)
+    (if (< (length out) 2) (car out) (nreverse out))))
+
+(defun gnus-group-yank-group (&optional arg)
+  "Yank the last newsgroups killed with \\[gnus-group-kill-group], inserting it before the current newsgroup.
+The numeric ARG specifies how many newsgroups are to be yanked.  The
+name of the newsgroup yanked is returned, or (if several groups are
+yanked) a list of yanked groups is returned."
+  (interactive "p")
+  (setq arg (or arg 1))
+  (let (info group prev out)
+    (while (>= (decf arg) 0)
+      (when (not (setq info (pop gnus-list-of-killed-groups)))
+       (error "No more newsgroups to yank"))
+      (push (setq group (nth 1 info)) out)
+      ;; Find which newsgroup to insert this one before - search
+      ;; backward until something suitable is found.  If there are no
+      ;; other newsgroups in this buffer, just make this newsgroup the
+      ;; first newsgroup.
+      (setq prev (gnus-group-group-name))
+      (gnus-group-change-level
+       info (gnus-info-level (cdr info)) gnus-level-killed
+       (and prev (gnus-group-entry prev))
+       t)
+      (gnus-group-insert-group-line-info group)
+      (gnus-request-update-group-status group 'subscribe)
+      (gnus-undo-register
+       `(when (gnus-group-goto-group ,group)
+          (gnus-group-kill-group 1))))
+    (forward-line -1)
+    (gnus-group-position-point)
+    (if (< (length out) 2) (car out) (nreverse out))))
+
+(defun gnus-group-kill-level (level)
+  "Kill all groups that is on a certain LEVEL."
+  (interactive "nKill all groups on level: ")
+  (cond
+   ((= level gnus-level-zombie)
+    (setq gnus-killed-list
+         (nconc gnus-zombie-list gnus-killed-list))
+    (setq gnus-zombie-list nil))
+   ((and (< level gnus-level-zombie)
+        (> level 0)
+        (or gnus-expert-user
+            (gnus-yes-or-no-p
+             (format
+              "Do you really want to kill all groups on level %d? "
+              level))))
+    (let* ((prev gnus-newsrc-alist)
+          (alist (cdr prev)))
+      (while alist
+       (if (= (gnus-info-level (car alist)) level)
+           (progn
+             (push (gnus-info-group (car alist)) gnus-killed-list)
+             (setcdr prev (cdr alist)))
+         (setq prev alist))
+       (setq alist (cdr alist)))
+      (gnus-make-hashtable-from-newsrc-alist)
+      (gnus-group-list-groups)))
+   (t
+    (error "Can't kill; invalid level: %d" level))))
+
+(defun gnus-group-list-all-groups (&optional arg)
+  "List all newsgroups with level ARG or lower.
+Default is `gnus-level-unsubscribed', which lists all subscribed and most
+unsubscribed groups."
+  (interactive "P")
+  (gnus-group-list-groups (or arg gnus-level-unsubscribed) t))
+
+;; Redefine this to list ALL killed groups if prefix arg used.
+;; Rewritten by engstrom@src.honeywell.com (Eric Engstrom).
+(defun gnus-group-list-killed (&optional arg)
+  "List all killed newsgroups in the group buffer.
+If ARG is non-nil, list ALL killed groups known to Gnus.  This may
+entail asking the server for the groups."
+  (interactive "P")
+  ;; Find all possible killed newsgroups if arg.
+  (when arg
+    (gnus-get-killed-groups))
+  (if (not gnus-killed-list)
+      (gnus-message 6 "No killed groups")
+    (let (gnus-group-list-mode)
+      (funcall gnus-group-prepare-function
+              gnus-level-killed t gnus-level-killed))
+    (goto-char (point-min)))
+  (gnus-group-position-point))
+
+(defun gnus-group-list-zombies ()
+  "List all zombie newsgroups in the group buffer."
+  (interactive)
+  (if (not gnus-zombie-list)
+      (gnus-message 6 "No zombie groups")
+    (let (gnus-group-list-mode)
+      (funcall gnus-group-prepare-function
+              gnus-level-zombie t gnus-level-zombie))
+    (goto-char (point-min)))
+  (gnus-group-position-point))
+
+(defun gnus-group-list-active ()
+  "List all groups that are available from the server(s)."
+  (interactive)
+  ;; First we make sure that we have really read the active file.
+  (unless (gnus-read-active-file-p)
+    (let ((gnus-read-active-file t)
+         (gnus-agent gnus-plugged)); If we're actually plugged, store the active file in the agent.
+      (gnus-read-active-file)))
+  ;; Find all groups and sort them.
+  (let ((groups
+        (sort
+         (let (list)
+           (mapatoms
+            (lambda (sym)
+              (and (boundp sym)
+                   (symbol-value sym)
+                   (push (symbol-name sym) list)))
+            gnus-active-hashtb)
+           list)
+         'string<))
+       (buffer-read-only nil)
+       group)
+    (erase-buffer)
+    (while groups
+      (setq group (pop groups))
+      (gnus-add-text-properties
+       (point) (prog1 (1+ (point))
+                (insert "       *: "
+                        (gnus-group-decoded-name group)
+                        "\n"))
+       (list 'gnus-group (gnus-intern-safe group gnus-active-hashtb)
+            'gnus-unread t
+            'gnus-level (inline (gnus-group-level group)))))
+    (goto-char (point-min))))
+
+(defun gnus-activate-all-groups (level)
+  "Activate absolutely all groups."
+  (interactive (list gnus-level-unsubscribed))
+  (let ((gnus-activate-level level)
+       (gnus-activate-foreign-newsgroups level))
+    (gnus-group-get-new-news)))
+
+(defun gnus-group-get-new-news (&optional arg one-level)
+  "Get newly arrived articles.
+If ARG is a number, it specifies which levels you are interested in
+re-scanning.  If ARG is non-nil and not a number, this will force
+\"hard\" re-reading of the active files from all servers.
+If ONE-LEVEL is not nil, then re-scan only the specified level,
+otherwise all levels below ARG will be scanned too."
+  (interactive "P")
+  (require 'nnmail)
+  (let ((gnus-inhibit-demon t)
+       ;; Binding this variable will inhibit multiple fetchings
+       ;; of the same mail source.
+       (nnmail-fetched-sources (list t)))
+    (gnus-run-hooks 'gnus-get-top-new-news-hook)
+    (gnus-run-hooks 'gnus-get-new-news-hook)
+
+    ;; Read any slave files.
+    (unless gnus-slave
+      (gnus-master-read-slave-newsrc))
+
+    (gnus-get-unread-articles (gnus-group-default-level arg t)
+                             nil one-level)
+
+    ;; If the user wants it, we scan for new groups.
+    (when (eq gnus-check-new-newsgroups 'always)
+      (gnus-find-new-newsgroups))
+
+    (gnus-check-reasonable-setup)
+    (gnus-run-hooks 'gnus-after-getting-new-news-hook)
+    (gnus-group-list-groups (and (numberp arg)
+                                (max (car gnus-group-list-mode) arg)))))
+
+(defun gnus-group-get-new-news-this-group (&optional n dont-scan)
+  "Check for newly arrived news in the current group (and the N-1 next groups).
+The difference between N and the number of newsgroup checked is returned.
+If N is negative, this group and the N-1 previous groups will be checked.
+If DONT-SCAN is non-nil, scan non-activated groups as well."
+  (interactive "P")
+  (let* ((groups (gnus-group-process-prefix n))
+        (ret (if (numberp n) (- n (length groups)) 0))
+        (beg (unless n
+               (point-marker)))
+        group method
+        (gnus-inhibit-demon t)
+        ;; Binding this variable will inhibit multiple fetchings
+        ;; of the same mail source.
+        (nnmail-fetched-sources (list t)))
+    (gnus-run-hooks 'gnus-get-new-news-hook)
+    (while (setq group (pop groups))
+      (gnus-group-remove-mark group)
+      ;; Bypass any previous denials from the server.
+      (gnus-remove-denial (setq method (gnus-find-method-for-group group)))
+      (if (or (and (not dont-scan)
+                  (gnus-request-group-scan group (gnus-get-info group)))
+             (gnus-activate-group group (if dont-scan nil 'scan) nil method))
+         (let ((info (gnus-get-info group))
+               (active (gnus-active group)))
+           (when info
+             (gnus-request-update-info info method))
+           (gnus-get-unread-articles-in-group info active)
+           (unless (gnus-virtual-group-p group)
+             (gnus-close-group group))
+           (when gnus-agent
+             (gnus-agent-save-group-info
+              method (gnus-group-real-name group) active))
+           (gnus-group-update-group group nil t))
+       (gnus-error 3 "%s error: %s" group (gnus-status-message group))))
+    (when beg
+      (goto-char beg))
+    (when gnus-goto-next-group-when-activating
+      (gnus-group-next-unread-group 1 t))
+    (gnus-group-position-point)
+    ret))
+
+(defun gnus-group-describe-group (force &optional group)
+  "Display a description of the current newsgroup."
+  (interactive (list current-prefix-arg (gnus-group-group-name)))
+  (let* ((method (gnus-find-method-for-group group))
+        (mname (gnus-group-prefixed-name "" method))
+        desc)
+    (when (and force
+              gnus-description-hashtb)
+      (gnus-sethash mname nil gnus-description-hashtb))
+    (unless group
+      (error "No group name given"))
+    (when (or (and gnus-description-hashtb
+                  ;; We check whether this group's method has been
+                  ;; queried for a description file.
+                  (gnus-gethash mname gnus-description-hashtb))
+             (setq desc (gnus-group-get-description group))
+             (gnus-read-descriptions-file method))
+      (gnus-message 1 "%s"
+                   (or desc (gnus-gethash group gnus-description-hashtb)
+                       "No description available")))))
+
+;; Suggested by Per Abrahamsen <amanda@iesd.auc.dk>.
+(defun gnus-group-describe-all-groups (&optional force)
+  "Pop up a buffer with descriptions of all newsgroups."
+  (interactive "P")
+  (when force
+    (setq gnus-description-hashtb nil))
+  (when (not (or gnus-description-hashtb
+                (gnus-read-all-descriptions-files)))
+    (error "Couldn't request descriptions file"))
+  (let ((buffer-read-only nil)
+       b)
+    (erase-buffer)
+    (mapatoms
+     (lambda (group)
+       (setq b (point))
+       (let ((charset (gnus-group-name-charset nil (symbol-name group))))
+        (insert (format "      *: %-20s %s\n"
+                        (gnus-group-name-decode
+                         (symbol-name group) charset)
+                        (gnus-group-name-decode
+                         (symbol-value group) charset))))
+       (gnus-add-text-properties
+       b (1+ b) (list 'gnus-group group
+                      'gnus-unread t 'gnus-marked nil
+                      'gnus-level (1+ gnus-level-subscribed))))
+     gnus-description-hashtb)
+    (goto-char (point-min))
+    (gnus-group-position-point)))
+
+;; Suggested by Daniel Quinlan <quinlan@best.com>.
+(defun gnus-group-apropos (regexp &optional search-description)
+  "List all newsgroups that have names that match a regexp."
+  (interactive "sGnus apropos (regexp): ")
+  (let ((prev "")
+       (obuf (current-buffer))
+       groups des)
+    ;; Go through all newsgroups that are known to Gnus.
+    (mapatoms
+     (lambda (group)
+       (and (symbol-name group)
+           (string-match regexp (symbol-name group))
+           (symbol-value group)
+           (push (symbol-name group) groups)))
+     gnus-active-hashtb)
+    ;; Also go through all descriptions that are known to Gnus.
+    (when search-description
+      (mapatoms
+       (lambda (group)
+        (and (string-match regexp (symbol-value group))
+             (push (symbol-name group) groups)))
+       gnus-description-hashtb))
+    (if (not groups)
+       (gnus-message 3 "No groups matched \"%s\"." regexp)
+      ;; Print out all the groups.
+      (save-excursion
+       (pop-to-buffer "*Gnus Help*")
+       (buffer-disable-undo)
+       (erase-buffer)
+       (setq groups (sort groups 'string<))
+       (while groups
+         ;; Groups may be entered twice into the list of groups.
+         (when (not (string= (car groups) prev))
+           (setq prev (car groups))
+           (let ((charset (gnus-group-name-charset nil prev)))
+             (insert (gnus-group-name-decode prev charset) "\n")
+             (when (and gnus-description-hashtb
+                        (setq des (gnus-gethash (car groups)
+                                                gnus-description-hashtb)))
+               (insert "  " (gnus-group-name-decode des charset) "\n"))))
+         (setq groups (cdr groups)))
+       (goto-char (point-min))))
+    (pop-to-buffer obuf)))
+
+(defun gnus-group-description-apropos (regexp)
+  "List all newsgroups that have names or descriptions that match REGEXP."
+  (interactive "sGnus description apropos (regexp): ")
+  (when (not (or gnus-description-hashtb
+                (gnus-read-all-descriptions-files)))
+    (error "Couldn't request descriptions file"))
+  (gnus-group-apropos regexp t))
+
+;; Suggested by Per Abrahamsen <amanda@iesd.auc.dk>.
+(defun gnus-group-list-matching (level regexp &optional all lowest)
+  "List all groups with unread articles that match REGEXP.
+If the prefix LEVEL is non-nil, it should be a number that says which
+level to cut off listing groups.
+If ALL, also list groups with no unread articles.
+If LOWEST, don't list groups with level lower than LOWEST.
+
+This command may read the active file."
+  (interactive "P\nsList newsgroups matching: ")
+  ;; First make sure active file has been read.
+  (when (and level
+            (> (prefix-numeric-value level) gnus-level-killed))
+    (gnus-get-killed-groups))
+  (funcall gnus-group-prepare-function
+   (or level gnus-level-subscribed) (and all t) (or lowest 1) regexp)
+  (goto-char (point-min))
+  (gnus-group-position-point))
+
+(defun gnus-group-list-all-matching (level regexp &optional lowest)
+  "List all groups that match REGEXP.
+If the prefix LEVEL is non-nil, it should be a number that says which
+level to cut off listing groups.
+If LOWEST, don't list groups with level lower than LOWEST."
+  (interactive "P\nsList newsgroups matching: ")
+  (when level
+    (setq level (prefix-numeric-value level)))
+  (gnus-group-list-matching (or level gnus-level-killed) regexp t lowest))
+
+;; Suggested by Jack Vinson <vinson@unagi.cis.upenn.edu>.
+(defun gnus-group-save-newsrc (&optional force)
+  "Save the Gnus startup files.
+If FORCE, force saving whether it is necessary or not."
+  (interactive "P")
+  (gnus-save-newsrc-file force))
+
+(defun gnus-group-restart (&optional arg)
+  "Force Gnus to read the .newsrc file."
+  (interactive "P")
+  (when (gnus-yes-or-no-p
+        (format "Are you sure you want to restart Gnus? "))
+    (gnus-save-newsrc-file)
+    (gnus-clear-system)
+    (gnus)))
+
+(defun gnus-group-read-init-file ()
+  "Read the Gnus elisp init file."
+  (interactive)
+  (gnus-read-init-file)
+  (gnus-message 5 "Read %s" gnus-init-file))
+
+(defun gnus-group-check-bogus-groups (&optional silent)
+  "Check bogus newsgroups.
+If given a prefix, don't ask for confirmation before removing a bogus
+group."
+  (interactive "P")
+  (gnus-check-bogus-newsgroups (and (not silent) (not gnus-expert-user)))
+  (gnus-group-list-groups))
+
+(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'.
+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
+for new groups, and subscribe the new groups as zombies."
+  (interactive "p")
+  (let ((new-groups (gnus-find-new-newsgroups (or arg 1)))
+       current-group)
+    (gnus-group-list-groups)
+    (setq current-group (gnus-group-group-name))
+    (dolist (group new-groups)
+      (gnus-group-jump-to-group group))
+    (when current-group
+      (gnus-group-jump-to-group current-group))))
+
+(defun gnus-group-edit-global-kill (&optional article group)
+  "Edit the global kill file.
+If GROUP, edit that local kill file instead."
+  (interactive "P")
+  (setq gnus-current-kill-article article)
+  (gnus-kill-file-edit-file group)
+  (gnus-message 6 "Editing a %s kill file (Type %s to exit)"
+               (if group "local" "global")
+               (substitute-command-keys "\\[gnus-kill-file-exit]")))
+
+(defun gnus-group-edit-local-kill (article group)
+  "Edit a local kill file."
+  (interactive (list nil (gnus-group-group-name)))
+  (gnus-group-edit-global-kill article group))
+
+(defun gnus-group-force-update ()
+  "Update `.newsrc' file."
+  (interactive)
+  (gnus-save-newsrc-file))
+
+(defvar gnus-backlog-articles)
+
+(defun gnus-group-suspend ()
+  "Suspend the current Gnus session.
+In fact, cleanup buffers except for group mode buffer.
+The hook `gnus-suspend-gnus-hook' is called before actually suspending."
+  (interactive)
+  (gnus-run-hooks 'gnus-suspend-gnus-hook)
+  (gnus-offer-save-summaries)
+  ;; Kill Gnus buffers except for group mode buffer.
+  (let ((group-buf (get-buffer gnus-group-buffer)))
+    (dolist (buf (gnus-buffers))
+      (unless (or (eq buf group-buf)
+                 (eq buf gnus-dribble-buffer)
+                 (with-current-buffer buf
+                   (derived-mode-p 'message-mode)))
+       (gnus-kill-buffer buf)))
+    (setq gnus-backlog-articles nil)
+    (gnus-kill-gnus-frames)
+    ;; Closing all the backends is useful (for instance) when when the
+    ;; IP addresses have changed and you need to reconnect.
+    (dolist (elem gnus-opened-servers)
+      (gnus-close-server (car elem))
+      (setcar (cdr elem) 'closed))
+    (when group-buf
+      (bury-buffer group-buf)
+      (delete-windows-on group-buf t))))
+
+(defun gnus-group-clear-dribble ()
+  "Clear all information from the dribble buffer."
+  (interactive)
+  (gnus-dribble-clear)
+  (gnus-message 7 "Cleared dribble buffer"))
+
+(defun gnus-group-exit ()
+  "Quit reading news after updating .newsrc.eld and .newsrc.
+The hook `gnus-exit-gnus-hook' is called before actually exiting."
+  (interactive)
+  (when
+      (or noninteractive               ;For gnus-batch-kill
+         (not gnus-interactive-exit)   ;Without confirmation
+         gnus-expert-user
+         (gnus-y-or-n-p "Are you sure you want to quit reading news? "))
+    (gnus-run-hooks 'gnus-exit-gnus-hook)
+    ;; Offer to save data from non-quitted summary buffers.
+    (gnus-offer-save-summaries)
+    ;; Save the newsrc file(s).
+    (gnus-save-newsrc-file)
+    ;; Kill-em-all.
+    (gnus-close-backends)
+    ;; Reset everything.
+    (gnus-clear-system)
+    ;; Allow the user to do things after cleaning up.
+    (gnus-run-hooks 'gnus-after-exiting-gnus-hook)))
+
+(defun gnus-group-quit ()
+  "Quit reading news without updating .newsrc.eld or .newsrc.
+The hook `gnus-exit-gnus-hook' is called before actually exiting."
+  (interactive)
+  (when (or noninteractive             ;For gnus-batch-kill
+           (zerop (buffer-size))
+           (not (gnus-server-opened gnus-select-method))
+           gnus-expert-user
+           (not gnus-current-startup-file)
+           (gnus-yes-or-no-p
+            (format "Quit reading news without saving %s? "
+                    (file-name-nondirectory gnus-current-startup-file))))
+    (gnus-run-hooks 'gnus-exit-gnus-hook)
+    (gnus-configure-windows 'group t)
+    (when (and (gnus-buffer-live-p gnus-dribble-buffer)
+              (not (zerop (with-current-buffer gnus-dribble-buffer
+                           (buffer-size)))))
+      (gnus-dribble-enter
+       ";;; Gnus was exited on purpose without saving the .newsrc files."))
+    (gnus-dribble-save)
+    (gnus-close-backends)
+    (gnus-clear-system)
+    (gnus-kill-buffer gnus-group-buffer)
+    ;; Allow the user to do things after cleaning up.
+    (gnus-run-hooks 'gnus-after-exiting-gnus-hook)))
+
+(defun gnus-group-describe-briefly ()
+  "Give a one line description of the group mode commands."
+  (interactive)
+  (gnus-message 7 "%s" (substitute-command-keys "\\<gnus-group-mode-map>\\[gnus-group-read-group]:Select  \\[gnus-group-next-unread-group]:Forward  \\[gnus-group-prev-unread-group]:Backward  \\[gnus-group-exit]:Exit  \\[gnus-info-find-node]:Run Info  \\[gnus-group-describe-briefly]:This help")))
+
+(defun gnus-group-browse-foreign-server (method)
+  "Browse a foreign news server.
+If called interactively, this function will ask for a select method
+ (nntp, nnspool, etc.) and a server address (e.g., nntp.some.where).
+If not, METHOD should be a list where the first element is the method
+and the second element is the address."
+  (interactive
+   (list (let ((how (gnus-completing-read
+                    "Which back end"
+                    (mapcar 'car (append gnus-valid-select-methods
+                                         gnus-server-alist))
+                    t (cons "nntp" 0) 'gnus-method-history)))
+          ;; We either got a back end name or a virtual server name.
+          ;; If the first, we also need an address.
+          (if (assoc how gnus-valid-select-methods)
+              (list (intern how)
+                    ;; Suggested by mapjph@bath.ac.uk.
+                    (gnus-completing-read
+                     "Address"
+                     ;; FIXME? gnus-secondary-servers is obsolete,
+                     ;; and it is not obvious that there is anything
+                     ;; sensible to use instead in this particular case.
+                     (if (boundp 'gnus-secondary-servers)
+                         gnus-secondary-servers
+                       (cdr gnus-select-method))))
+            ;; We got a server name.
+            how))))
+  (gnus-browse-foreign-server method))
+
+(defun gnus-group-set-info (info &optional method-only-group part)
+  (when (or info part)
+    (let* ((entry (gnus-group-entry
+                  (or method-only-group (gnus-info-group info))))
+          (part-info info)
+          (info (if method-only-group (nth 2 entry) info))
+          method)
+      (when method-only-group
+       (unless entry
+         (error "Trying to change non-existent group %s" method-only-group))
+       ;; We have received parts of the actual group info - either the
+       ;; select method or the group parameters.  We first check
+       ;; whether we have to extend the info, and if so, do that.
+       (let ((len (length info))
+             (total (if (eq part 'method) 5 6)))
+         (when (< len total)
+           (setcdr (nthcdr (1- len) info)
+                   (make-list (- total len) nil)))
+         ;; Then we enter the new info.
+         (setcar (nthcdr (1- total) info) part-info)))
+      (unless entry
+       ;; This is a new group, so we just create it.
+       (with-current-buffer gnus-group-buffer
+         (setq method (gnus-info-method info))
+         (when (gnus-server-equal method "native")
+           (setq method nil))
+         (with-current-buffer gnus-group-buffer
+           (if method
+               ;; It's a foreign group...
+               (gnus-group-make-group
+                (gnus-group-real-name (gnus-info-group info))
+                (if (stringp method) method
+                  (prin1-to-string (car method)))
+                (and (consp method)
+                     (nth 1 (gnus-info-method info)))
+                nil t)
+             ;; It's a native group.
+             (gnus-group-make-group (gnus-info-group info) nil nil nil t)))
+         (gnus-message 6 "Note: New group created")
+         (setq entry
+               (gnus-group-entry (gnus-group-prefixed-name
+                                  (gnus-group-real-name (gnus-info-group info))
+                                  (or (gnus-info-method info) gnus-select-method))))))
+      ;; Whether it was a new group or not, we now have the entry, so we
+      ;; can do the update.
+      (if entry
+         (progn
+           (setcar (nthcdr 2 entry) info)
+           (when (and (not (eq (car entry) t))
+                      (gnus-active (gnus-info-group info)))
+             (setcar entry (length
+                            (gnus-list-of-unread-articles (car info))))))
+       (error "No such group: %s" (gnus-info-group info))))))
+
+;; Ad-hoc function for inserting data from a different newsrc.eld
+;; file.  Use with caution, if at all.
+(defun gnus-import-other-newsrc-file (file)
+  (with-temp-buffer
+    (insert-file-contents file)
+    (let (form)
+      (while (ignore-errors
+              (setq form (read (current-buffer))))
+       (when (and (consp form)
+                  (eq (cadr form) 'gnus-newsrc-alist))
+         (let ((infos (cadr (nth 2 form))))
+           (dolist (info infos)
+             (when (gnus-get-info (car info))
+               (gnus-set-info (car info) info)))))))))
+
+(defun gnus-add-marked-articles (group type articles &optional info force)
+  ;; Add ARTICLES of TYPE to the info of GROUP.
+  ;; If INFO is non-nil, use that info.  If FORCE is non-nil, don't
+  ;; add, but replace marked articles of TYPE with ARTICLES.
+  (let ((info (or info (gnus-get-info group)))
+       marked m)
+    (or (not info)
+       (and (not (setq marked (nthcdr 3 info)))
+            (or (null articles)
+                (setcdr (nthcdr 2 info)
+                        (list (list (cons type (gnus-compress-sequence
+                                                articles t)))))))
+       (and (not (setq m (assq type (car marked))))
+            (or (null articles)
+                (setcar marked
+                        (cons (cons type (gnus-compress-sequence articles t) )
+                              (car marked)))))
+       (if force
+           (if (null articles)
+               (setcar (nthcdr 3 info)
+                       (gnus-delete-alist type (car marked)))
+             (setcdr m (gnus-compress-sequence articles t)))
+         (setcdr m (gnus-compress-sequence
+                    (sort (nconc (gnus-uncompress-range (cdr m))
+                                 (copy-sequence articles)) '<) t))))))
+
+(declare-function gnus-summary-add-mark "gnus-sum" (article type))
+
+(defun gnus-add-mark (group mark article)
+  "Mark ARTICLE in GROUP with MARK, whether the group is displayed or not."
+  (let ((buffer (gnus-summary-buffer-name group)))
+    (if (gnus-buffer-live-p buffer)
+       (with-current-buffer (get-buffer buffer)
+         (gnus-summary-add-mark article mark))
+      (gnus-add-marked-articles group (cdr (assq mark gnus-article-mark-lists))
+                               (list article)))))
+
+;;;
+;;; Group timestamps
+;;;
+
+(defun gnus-group-set-timestamp ()
+  "Change the timestamp of the current group to the current time.
+This function can be used in hooks like `gnus-select-group-hook'
+or `gnus-group-catchup-group-hook'."
+  (when gnus-newsgroup-name
+    (let ((time (current-time)))
+      (setcdr (cdr time) nil)
+      (gnus-group-set-parameter gnus-newsgroup-name 'timestamp time))))
+
+(defsubst gnus-group-timestamp (group)
+  "Return the timestamp for GROUP."
+  (gnus-group-get-parameter group 'timestamp t))
+
+(defun gnus-group-timestamp-delta (group)
+  "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)))
+    (+ (* (nth 0 delta) 65536.0)
+       (nth 1 delta))))
+
+(defun gnus-group-timestamp-string (group)
+  "Return a string of the timestamp for GROUP."
+  (let ((time (gnus-group-timestamp group)))
+    (if (not time)
+       ""
+      (gnus-time-iso8601 time))))
+
+(defun gnus-group-list-cached (level &optional lowest)
+  "List all groups with cached articles.
+If the prefix LEVEL is non-nil, it should be a number that says which
+level to cut off listing groups.
+If LOWEST, don't list groups with level lower than LOWEST.
+
+This command may read the active file."
+  (interactive "P")
+  (when level
+    (setq level (prefix-numeric-value level)))
+  (when (or (not level) (>= level gnus-level-zombie))
+    (gnus-cache-open))
+  (funcall gnus-group-prepare-function
+          (or level gnus-level-subscribed)
+          #'(lambda (info)
+              (let ((marks (gnus-info-marks info)))
+                (assq 'cache marks)))
+          lowest
+          #'(lambda (group)
+              (or (gnus-gethash group
+                                gnus-cache-active-hashtb)
+                  ;; Cache active file might use "."
+                  ;; instead of ":".
+                  (gnus-gethash
+                   (mapconcat 'identity
+                              (split-string group ":")
+                              ".")
+                   gnus-cache-active-hashtb))))
+  (goto-char (point-min))
+  (gnus-group-position-point))
+
+(defun gnus-group-list-dormant (level &optional lowest)
+  "List all groups with dormant articles.
+If the prefix LEVEL is non-nil, it should be a number that says which
+level to cut off listing groups.
+If LOWEST, don't list groups with level lower than LOWEST.
+
+This command may read the active file."
+  (interactive "P")
+  (when level
+    (setq level (prefix-numeric-value level)))
+  (when (or (not level) (>= level gnus-level-zombie))
+    (gnus-cache-open))
+  (funcall gnus-group-prepare-function
+          (or level gnus-level-subscribed)
+          #'(lambda (info)
+              (let ((marks (gnus-info-marks info)))
+                (assq 'dormant marks)))
+          lowest
+          'ignore)
+  (goto-char (point-min))
+  (gnus-group-position-point))
+
+(defun gnus-group-list-ticked (level &optional lowest)
+  "List all groups with ticked articles.
+If the prefix LEVEL is non-nil, it should be a number that says which
+level to cut off listing groups.
+If LOWEST, don't list groups with level lower than LOWEST.
+
+This command may read the active file."
+  (interactive "P")
+  (when level
+    (setq level (prefix-numeric-value level)))
+  (when (or (not level) (>= level gnus-level-zombie))
+    (gnus-cache-open))
+  (funcall gnus-group-prepare-function
+          (or level gnus-level-subscribed)
+          #'(lambda (info)
+              (let ((marks (gnus-info-marks info)))
+                (assq 'tick marks)))
+          lowest
+          'ignore)
+  (goto-char (point-min))
+  (gnus-group-position-point))
+
+(defun gnus-group-listed-groups ()
+  "Return a list of listed groups."
+  (let (point groups)
+    (goto-char (point-min))
+    (while (setq point (text-property-not-all (point) (point-max)
+                                             'gnus-group nil))
+      (goto-char point)
+      (push (symbol-name (get-text-property point 'gnus-group)) groups)
+      (forward-char 1))
+    groups))
+
+(defun gnus-group-list-plus (&optional args)
+  "List groups plus the current selection."
+  (interactive "P")
+  (let ((gnus-group-listed-groups (gnus-group-listed-groups))
+       (gnus-group-list-mode gnus-group-list-mode) ;; Save it.
+       func)
+    (push last-command-event unread-command-events)
+    (if (featurep 'xemacs)
+       (push (make-event 'key-press '(key ?A)) unread-command-events)
+      (push ?A unread-command-events))
+    (let (gnus-pick-mode keys)
+      (setq keys (if (featurep 'xemacs)
+                    (events-to-keys (read-key-sequence nil))
+                  (read-key-sequence nil)))
+      (setq func (lookup-key (current-local-map) keys)))
+    (if (or (not func)
+           (numberp func))
+       (ding)
+      (call-interactively func))))
+
+(defun gnus-group-list-flush (&optional args)
+  "Flush groups from the current selection."
+  (interactive "P")
+  (let ((gnus-group-list-option 'flush))
+    (gnus-group-list-plus args)))
+
+(defun gnus-group-list-limit (&optional args)
+  "List groups limited within the current selection.
+If you've limited the groups, you can further limit the selection
+with this command.  If you've first limited to groups with
+dormant articles with `A ?', you can then further limit with
+`A / c', which will then limit to groups with cached articles, giving
+you the groups that have both dormant articles and cached articles."
+  (interactive "P")
+  (let ((gnus-group-list-option 'limit))
+    (gnus-group-list-plus args)))
+
+(declare-function gnus-mark-article-as-read "gnus-sum" (article &optional mark))
+(declare-function gnus-group-make-articles-read "gnus-sum" (group articles))
+
+(defun gnus-group-mark-article-read (group article)
+  "Mark ARTICLE read."
+  (let ((buffer (gnus-summary-buffer-name group))
+       (mark gnus-read-mark)
+       active n)
+    (if (get-buffer buffer)
+       (with-current-buffer buffer
+         (setq active gnus-newsgroup-active)
+         (gnus-activate-group group)
+         (when gnus-newsgroup-prepared
+           (when (and gnus-newsgroup-auto-expire
+                      (memq mark gnus-auto-expirable-marks))
+             (setq mark gnus-expirable-mark))
+           (setq mark (gnus-request-update-mark
+                       group article mark))
+           (gnus-request-set-mark
+            group (list (list (list article) 'add '(read))))
+           (gnus-mark-article-as-read article mark)
+           (setq gnus-newsgroup-active (gnus-active group))
+           (when active
+             (setq n (1+ (cdr active)))
+             (while (<= n (cdr gnus-newsgroup-active))
+               (unless (eq n article)
+                 (push n gnus-newsgroup-unselected))
+               (setq n (1+ n)))
+             (setq gnus-newsgroup-unselected
+                   (sort gnus-newsgroup-unselected '<)))))
+      (gnus-activate-group group)
+      (gnus-group-make-articles-read group (list article))
+      (when (and (gnus-group-auto-expirable-p group)
+                (not (gnus-group-read-only-p group)))
+       (gnus-add-marked-articles
+        group 'expire (list article))))))
+
+
+;;;
+;;; Group compaction. -- dvl
+;;;
+
+(defun gnus-group-compact-group (group)
+  "Compact the current group.
+Compaction means removing gaps between article numbers.  Hence, this
+operation is only meaningful for back ends using one file per article
+\(e.g. nnml).
+
+Note: currently only implemented in nnml."
+  (interactive (list (gnus-group-group-name)))
+  (unless group
+    (error "No group to compact"))
+  (unless (gnus-check-backend-function 'request-compact-group group)
+    (error "This back end does not support group compaction"))
+  (let ((group-decoded (gnus-group-decoded-name group)))
+    (gnus-message 6 "\
+Compacting group %s... (this may take a long time)"
+                 group-decoded)
+    (prog1
+       (if (not (gnus-request-compact-group group))
+           (gnus-error 3 "Couldn't compact group %s" group-decoded)
+         (gnus-message 6 "Compacting group %s...done" group-decoded)
+         t)
+      ;; Invalidate the "original article" buffer which might be out of date.
+      ;; #### NOTE: Yes, this might be a bit rude, but since compaction
+      ;; #### will not happen very often, I think this is acceptable.
+      (let ((original (get-buffer gnus-original-article-buffer)))
+       (and original (gnus-kill-buffer original)))
+      ;; Update the group line to reflect new information (art number etc).
+      (gnus-group-update-group-line))))
+
+(provide 'gnus-group)
+
+;;; gnus-group.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-html.el b/xemacs-packages/gnus/lisp/gnus-html.el
new file mode 100644 (file)
index 0000000..884b40e
--- /dev/null
@@ -0,0 +1,543 @@
+;;; gnus-html.el --- Render HTML in a buffer.
+
+;; Copyright (C) 2010-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: html, web
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; The idea is to provide a simple, fast and pretty minimal way to
+;; render HTML (including links and images) in a buffer, based on an
+;; external HTML renderer (i.e., w3m).
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'gnus-art)
+(eval-when-compile (require 'mm-decode))
+
+(require 'mm-url)
+(require 'url)
+(require 'url-cache)
+(require 'xml)
+(require 'browse-url)
+(require 'mm-util)
+(eval-and-compile (unless (featurep 'xemacs) (require 'help-fns)))
+
+(defcustom gnus-html-image-cache-ttl (days-to-time 7)
+  "Time used to determine if we should use images from the cache."
+  :version "24.1"
+  :group 'gnus-art
+  ;; FIXME hardly the friendliest type.  The allowed value is actually
+  ;; any time value, but we are assuming no-one cares about USEC and
+  ;; PSEC here.  It would be better to eg make it a number of minutes.
+  :type '(list integer integer))
+
+(defcustom gnus-html-image-automatic-caching t
+  "Whether automatically cache retrieve images."
+  :version "24.1"
+  :group 'gnus-art
+  :type 'boolean)
+
+(defcustom gnus-html-frame-width 70
+  "What width to use when rendering HTML."
+  :version "24.1"
+  :group 'gnus-art
+  :type 'integer)
+
+(defcustom gnus-max-image-proportion 0.9
+  "How big pictures displayed are in relation to the window they're in.
+A value of 0.7 means that they are allowed to take up 70% of the
+width and height of the window.  If they are larger than this,
+and Emacs supports it, then the images will be rescaled down to
+fit these criteria."
+  :version "24.1"
+  :group 'gnus-art
+  :type 'float)
+
+(defvar gnus-html-image-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "u" 'gnus-article-copy-string)
+    (define-key map "i" 'gnus-html-insert-image)
+    (define-key map "v" 'gnus-html-browse-url)
+    map))
+
+(defvar gnus-html-displayed-image-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "a" 'gnus-html-show-alt-text)
+    (define-key map "i" 'gnus-html-browse-image)
+    (define-key map "\r" 'gnus-html-browse-url)
+    (define-key map "u" 'gnus-article-copy-string)
+    (define-key map [tab] 'widget-forward)
+    map))
+
+(eval-and-compile
+  (defalias 'gnus-html-encode-url-chars
+    (if (fboundp 'browse-url-url-encode-chars)
+       'browse-url-url-encode-chars
+      (lambda (text chars)
+       "URL-encode the chars in TEXT that match CHARS.
+CHARS is a regexp-like character alternative (e.g., \"[)$]\")."
+       (let ((encoded-text (copy-sequence text))
+             (s 0))
+         (while (setq s (string-match chars encoded-text s))
+           (setq encoded-text
+                 (replace-match (format "%%%x"
+                                        (string-to-char
+                                         (match-string 0 encoded-text)))
+                                t t encoded-text)
+                 s (1+ s)))
+         encoded-text)))))
+
+(defun gnus-html-encode-url (url)
+  "Encode URL."
+  (gnus-html-encode-url-chars url "[)$ ]"))
+
+(defun gnus-html-cache-expired (url ttl)
+  "Check if URL is cached for more than TTL."
+  (cond (url-standalone-mode
+         (not (file-exists-p (url-cache-create-filename url))))
+        (t (let ((cache-time (url-is-cached url)))
+             (if cache-time
+                 (time-less-p
+                  (time-add
+                   cache-time
+                   ttl)
+                  (current-time))
+               t)))))
+
+;;;###autoload
+(defun gnus-article-html (&optional handle)
+  (let ((article-buffer (current-buffer)))
+    (unless handle
+      (setq handle (mm-dissect-buffer t)))
+    (save-restriction
+      (narrow-to-region (point) (point))
+      (save-excursion
+       (mm-with-part handle
+         (let* ((coding-system-for-read 'utf-8)
+                (coding-system-for-write 'utf-8)
+                (default-process-coding-system
+                  (cons coding-system-for-read coding-system-for-write))
+                (charset (mail-content-type-get (mm-handle-type handle)
+                                                'charset)))
+           (when (and charset
+                      (setq charset (mm-charset-to-coding-system
+                                     charset nil t))
+                      (not (eq charset 'ascii)))
+             (insert (prog1
+                         (mm-decode-coding-string (buffer-string) charset)
+                       (erase-buffer)
+                       (mm-enable-multibyte))))
+           (call-process-region (point-min) (point-max)
+                                "w3m"
+                                nil article-buffer nil
+                                "-halfdump"
+                                "-no-cookie"
+                                "-I" "UTF-8"
+                                "-O" "UTF-8"
+                                "-o" "ext_halfdump=1"
+                                 "-o" "display_ins_del=2"
+                                "-o" "pre_conv=1"
+                                "-t" (format "%s" tab-width)
+                                "-cols" (format "%s" gnus-html-frame-width)
+                                "-o" "display_image=on"
+                                "-T" "text/html"))))
+      (gnus-html-wash-tags))))
+
+(defvar gnus-article-mouse-face)
+
+(defun gnus-html-pre-wash ()
+  (goto-char (point-min))
+  (while (re-search-forward " *<pre_int> *</pre_int> *\n" nil t)
+    (replace-match "" t t))
+  (goto-char (point-min))
+  (while (re-search-forward "<a name[^\n>]+>" nil t)
+    (replace-match "" t t)))
+
+(defun gnus-html-wash-images ()
+  "Run through current buffer and replace img tags by images."
+  (let (tag parameters string start end images url alt-text
+           inhibit-images blocked-images)
+    (if (buffer-live-p gnus-summary-buffer)
+       (with-current-buffer gnus-summary-buffer
+         (setq inhibit-images gnus-inhibit-images
+               blocked-images (gnus-blocked-images)))
+      (setq inhibit-images gnus-inhibit-images
+           blocked-images (gnus-blocked-images)))
+    (goto-char (point-min))
+    ;; Search for all the images first.
+    (while (re-search-forward "<img_alt \\([^>]*\\)>" nil t)
+      (setq parameters (match-string 1)
+           start (match-beginning 0))
+      (delete-region start (point))
+      (when (search-forward "</img_alt>" (line-end-position) t)
+       (delete-region (match-beginning 0) (match-end 0)))
+      (setq end (point))
+      (when (string-match "src=\"\\([^\"]+\\)" parameters)
+       (gnus-message 8 "gnus-html-wash-tags: fetching image URL %s" url)
+       (setq url (gnus-html-encode-url (match-string 1 parameters))
+             alt-text (when (string-match "\\(alt\\|title\\)=\"\\([^\"]+\\)"
+                                          parameters)
+                        (xml-substitute-special (match-string 2 parameters))))
+       (gnus-add-text-properties
+        start end
+        (list 'image-url url
+              'image-displayer `(lambda (url start end)
+                                  (gnus-html-display-image url start end
+                                                           ,alt-text))
+              'gnus-image (list url start end alt-text)))
+       (widget-convert-button
+        'url-link start (point)
+        :help-echo alt-text
+        :keymap gnus-html-image-map
+        url)
+       (if (string-match "\\`cid:" url)
+           ;; URLs with cid: have their content stashed in other
+           ;; parts of the MIME structure, so just insert them
+           ;; immediately.
+           (let* ((handle (mm-get-content-id (substring url (match-end 0))))
+                  (image (when (and handle
+                                    (not inhibit-images))
+                           (gnus-create-image
+                            (mm-with-part handle (buffer-string))
+                            nil t))))
+             (if image
+                 (gnus-add-image
+                  'cid
+                  (gnus-put-image
+                   (gnus-rescale-image
+                    image (gnus-html-maximum-image-size))
+                   (gnus-string-or (prog1
+                                       (buffer-substring start end)
+                                     (delete-region start end))
+                                   "*")
+                   'cid))
+               (widget-convert-button
+                'link start end
+                :action 'gnus-html-insert-image
+                :help-echo url
+                :keymap gnus-html-image-map
+                :button-keymap gnus-html-image-map)))
+         ;; Normal, external URL.
+         (if (or inhibit-images
+                 (gnus-html-image-url-blocked-p url blocked-images))
+             (widget-convert-button
+              'link start end
+              :action 'gnus-html-insert-image
+              :help-echo url
+              :keymap gnus-html-image-map
+              :button-keymap gnus-html-image-map)
+           ;; Non-blocked url
+           (let ((width
+                  (when (string-match "width=\"?\\([0-9]+\\)" parameters)
+                    (string-to-number (match-string 1 parameters))))
+                 (height
+                  (when (string-match "height=\"?\\([0-9]+\\)" parameters)
+                    (string-to-number (match-string 1 parameters)))))
+             ;; Don't fetch images that are really small.  They're
+             ;; probably tracking pictures.
+             (when (and (or (null height)
+                            (> height 4))
+                        (or (null width)
+                            (> width 4)))
+               (gnus-html-display-image url start end alt-text)))))))))
+
+(defun gnus-html-display-image (url start end &optional alt-text)
+  "Display image at URL on text from START to END.
+Use ALT-TEXT for the image string."
+  (or alt-text (setq alt-text "*"))
+  (if (string-match "\\`cid:" url)
+      (let ((handle (mm-get-content-id (substring url (match-end 0)))))
+       (when handle
+         (gnus-html-put-image (mm-with-part handle (buffer-string))
+                              url alt-text)))
+    (if (gnus-html-cache-expired url gnus-html-image-cache-ttl)
+       ;; We don't have it, so schedule it for fetching
+       ;; asynchronously.
+       (gnus-html-schedule-image-fetching
+        (current-buffer)
+        (list url alt-text))
+      ;; It's already cached, so just insert it.
+      (gnus-html-put-image (gnus-html-get-image-data url) url alt-text))))
+
+(defun gnus-html-wash-tags ()
+  (let (tag parameters string start end images url)
+    (gnus-html-pre-wash)
+    (gnus-html-wash-images)
+
+    (goto-char (point-min))
+    ;; Then do the other tags.
+    (while (re-search-forward "<\\([^ />]+\\)\\([^>]*\\)>" nil t)
+      (setq tag (match-string 1)
+           parameters (match-string 2)
+           start (match-beginning 0))
+      (when (> (length parameters) 0)
+       (set-text-properties 0 (1- (length parameters)) nil parameters))
+      (delete-region start (point))
+      (when (search-forward (concat "</" tag ">") nil t)
+       (delete-region (match-beginning 0) (match-end 0)))
+      (setq end (point))
+      (cond
+       ;; Fetch and insert a picture.
+       ((equal tag "img_alt"))
+       ;; Add a link.
+       ((or (equal tag "a")
+           (equal tag "A"))
+       (when (string-match "href=\"\\([^\"]+\\)" parameters)
+         (setq url (match-string 1 parameters))
+          (gnus-message 8 "gnus-html-wash-tags: fetching link URL %s" url)
+         (gnus-article-add-button start end
+                                  'browse-url (mm-url-decode-entities-string url)
+                                  url)
+         (let ((overlay (make-overlay start end)))
+           (overlay-put overlay 'evaporate t)
+           (overlay-put overlay 'gnus-button-url url)
+           (gnus-put-text-property start end 'gnus-string url)
+           (when gnus-article-mouse-face
+             (overlay-put overlay 'mouse-face gnus-article-mouse-face)))))
+       ;; The upper-case IMG_ALT is apparently just an artifact that
+       ;; should be deleted.
+       ((equal tag "IMG_ALT")
+       (delete-region start end))
+       ;; w3m does not normalize the case
+       ((or (equal tag "b")
+            (equal tag "B"))
+        (overlay-put (make-overlay start end) 'face 'gnus-emphasis-bold))
+       ((or (equal tag "u")
+            (equal tag "U"))
+        (overlay-put (make-overlay start end) 'face 'gnus-emphasis-underline))
+       ((or (equal tag "i")
+            (equal tag "I"))
+        (overlay-put (make-overlay start end) 'face 'gnus-emphasis-italic))
+       ((or (equal tag "s")
+            (equal tag "S"))
+        (overlay-put (make-overlay start end) 'face 'gnus-emphasis-strikethru))
+       ((or (equal tag "ins")
+            (equal tag "INS"))
+        (overlay-put (make-overlay start end) 'face 'gnus-emphasis-underline))
+       ;; Handle different UL types
+       ((equal tag "_SYMBOL")
+        (when (string-match "TYPE=\\(.+\\)" parameters)
+          (let ((type (string-to-number (match-string 1 parameters))))
+            (delete-region start end)
+            (cond ((= type 33) (insert " "))
+                  ((= type 34) (insert " "))
+                  ((= type 35) (insert " "))
+                  ((= type 36) (insert " "))
+                  ((= type 37) (insert " "))
+                  ((= type 38) (insert " "))
+                  ((= type 39) (insert " "))
+                  ((= type 40) (insert " "))
+                  ((= type 42) (insert " "))
+                  ((= type 43) (insert " "))
+                  (t (insert " "))))))
+       ;; Whatever.  Just ignore the tag.
+       (t
+       ))
+      (goto-char start))
+    (goto-char (point-min))
+    ;; The output from -halfdump isn't totally regular, so strip
+    ;; off any </pre_int>s that were left over.
+    (while (re-search-forward "</pre_int>\\|</internal>" nil t)
+      (replace-match "" t t))
+    (mm-url-decode-entities)))
+
+(defun gnus-html-insert-image (&rest args)
+  "Fetch and insert the image under point."
+  (interactive)
+  (apply 'gnus-html-display-image (get-text-property (point) 'gnus-image)))
+
+(defun gnus-html-show-alt-text ()
+  "Show the ALT text of the image under point."
+  (interactive)
+  (message "%s" (get-text-property (point) 'gnus-alt-text)))
+
+(defun gnus-html-browse-image ()
+  "Browse the image under point."
+  (interactive)
+  (browse-url (get-text-property (point) 'image-url)))
+
+(defun gnus-html-browse-url ()
+  "Browse the image under point."
+  (interactive)
+  (let ((url (get-text-property (point) 'gnus-string)))
+    (cond
+     ((not url)
+      (message "No link under point"))
+     ((string-match "^mailto:" url)
+      (gnus-url-mailto url))
+     (t
+      (browse-url url)))))
+
+(defun gnus-html-schedule-image-fetching (buffer image)
+  "Retrieve IMAGE, and place it into BUFFER on arrival."
+  (gnus-message 8 "gnus-html-schedule-image-fetching: buffer %s, image %s"
+                buffer image)
+  (if (fboundp 'url-queue-retrieve)
+      (url-queue-retrieve (car image)
+                         'gnus-html-image-fetched
+                         (list buffer image) t t)
+    (ignore-errors
+      (url-retrieve (car image)
+                   'gnus-html-image-fetched
+                   (list buffer image)))))
+
+(defun gnus-html-image-fetched (status buffer image)
+  "Callback function called when image has been fetched."
+  (unless (plist-get status :error)
+    (when (and (or (search-forward "\n\n" nil t)
+                   (search-forward "\r\n\r\n" nil t))
+              (not (eobp)))
+      (when gnus-html-image-automatic-caching
+       (url-store-in-cache (current-buffer)))
+      (when (buffer-live-p buffer)
+       (let ((data (buffer-substring (point) (point-max))))
+         (with-current-buffer buffer
+           (let ((inhibit-read-only t))
+             (gnus-html-put-image data (car image) (cadr image))))))))
+  (kill-buffer (current-buffer)))
+
+(defun gnus-html-get-image-data (url)
+  "Get image data for URL.
+Return a string with image data."
+  (with-temp-buffer
+    (mm-disable-multibyte)
+    (url-cache-extract (url-cache-create-filename url))
+    (when (or (search-forward "\n\n" nil t)
+              (search-forward "\r\n\r\n" nil t))
+      (buffer-substring (point) (point-max)))))
+
+(defun gnus-html-maximum-image-size ()
+  "Return the maximum size of an image according to `gnus-max-image-proportion'."
+  (let ((edges (gnus-window-inside-pixel-edges
+                (get-buffer-window (current-buffer)))))
+    ;; (width . height)
+    (cons
+     ;; Aimed width
+     (truncate
+      (* gnus-max-image-proportion
+         (- (nth 2 edges) (nth 0 edges))))
+     ;; Aimed height
+     (truncate (* gnus-max-image-proportion
+                  (- (nth 3 edges) (nth 1 edges)))))))
+
+;; Behind display-graphic-p test.
+(declare-function image-size "image.c" (spec &optional pixels frame))
+
+(defun gnus-html-put-image (data url &optional alt-text)
+  "Put an image with DATA from URL and optional ALT-TEXT."
+  (when (gnus-graphic-display-p)
+    (let* ((start (text-property-any (point-min) (point-max)
+                                    'image-url url))
+           (end (when start
+                  (next-single-property-change start 'image-url))))
+      ;; Image found?
+      (when start
+        (let* ((image
+                (ignore-errors
+                  (gnus-create-image data nil t)))
+               (size (and image
+                          (if (featurep 'xemacs)
+                              (cons (glyph-width image) (glyph-height image))
+                            (image-size image t)))))
+          (save-excursion
+            (goto-char start)
+            (let ((alt-text (or alt-text
+                               (buffer-substring-no-properties start end)))
+                 (inhibit-read-only t))
+              (if (and image
+                       ;; Kludge to avoid displaying 30x30 gif images, which
+                       ;; seems to be a signal of a broken image.
+                       (not (and (if (featurep 'xemacs)
+                                     (glyphp image)
+                                   (listp image))
+                                 (eq (if (featurep 'xemacs)
+                                         (let ((d (cdadar
+                                                  (specifier-spec-list
+                                                   (glyph-image image)))))
+                                           (and (vectorp d)
+                                                (aref d 0)))
+                                       (plist-get (cdr image) :type))
+                                     'gif)
+                                 (= (car size) 30)
+                                 (= (cdr size) 30))))
+                  ;; Good image, add it!
+                  (let ((image (gnus-rescale-image image (gnus-html-maximum-image-size))))
+                    (delete-region start end)
+                    (gnus-put-image image alt-text 'external)
+                   (widget-convert-button
+                    'url-link start (point)
+                    :help-echo alt-text
+                    :keymap gnus-html-displayed-image-map
+                    url)
+                    (gnus-put-text-property start (point)
+                                           'gnus-alt-text alt-text)
+                    (when url
+                     (gnus-add-text-properties
+                      start (point)
+                      `(image-url
+                        ,url
+                        image-displayer
+                        (lambda (url start end)
+                          (gnus-html-display-image url start end
+                                                   ,alt-text)))))
+                    (gnus-add-image 'external image)
+                    t)
+                ;; Bad image, try to show something else
+                (when (fboundp 'find-image)
+                  (delete-region start end)
+                  (setq image (find-image
+                              '((:type xpm :file "lock-broken.xpm"))))
+                  (gnus-put-image image alt-text 'internal)
+                  (gnus-add-image 'internal image))
+                nil))))))))
+
+(defun gnus-html-image-url-blocked-p (url blocked-images)
+  "Find out if URL is blocked by BLOCKED-IMAGES."
+  (let ((ret (and blocked-images
+                  (string-match blocked-images url))))
+    (if ret
+        (gnus-message 8 "gnus-html-image-url-blocked-p: %s blocked by regex %s"
+                      url blocked-images)
+      (gnus-message 9 "gnus-html-image-url-blocked-p: %s passes regex %s"
+                    url blocked-images))
+    ret))
+
+;;;###autoload
+(defun gnus-html-prefetch-images (summary)
+  (when (buffer-live-p summary)
+    (let (inhibit-images blocked-images)
+      (with-current-buffer summary
+       (setq inhibit-images gnus-inhibit-images
+             blocked-images (gnus-blocked-images)))
+      (save-match-data
+       (while (re-search-forward "<img[^>]+src=[\"']\\(http[^\"']+\\)" nil t)
+         (let ((url (gnus-html-encode-url
+                     (mm-url-decode-entities-string (match-string 1)))))
+           (unless (or inhibit-images
+                       (gnus-html-image-url-blocked-p url blocked-images))
+              (when (gnus-html-cache-expired url gnus-html-image-cache-ttl)
+                (gnus-html-schedule-image-fetching nil
+                                                   (list url))))))))))
+
+(provide 'gnus-html)
+
+;;; gnus-html.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-icalendar.el b/xemacs-packages/gnus/lisp/gnus-icalendar.el
new file mode 100644 (file)
index 0000000..4faef06
--- /dev/null
@@ -0,0 +1,973 @@
+;;; gnus-icalendar.el --- reply to iCalendar meeting requests
+
+;; Copyright (C) 2013-2016 Free Software Foundation, Inc.
+
+;; Author: Jan Tatarik <Jan.Tatarik@gmail.com>
+;; Keywords: mail, icalendar, org
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; To install:
+;; (require 'gnus-icalendar)
+;; (gnus-icalendar-setup)
+
+;; to enable optional iCalendar->Org sync functionality
+;; NOTE: both the capture file and the headline(s) inside must already exist
+;; (setq gnus-icalendar-org-capture-file "~/org/notes.org")
+;; (setq gnus-icalendar-org-capture-headline '("Calendar"))
+;; (gnus-icalendar-org-setup)
+
+
+;;; Code:
+
+(require 'icalendar)
+(require 'eieio)
+(require 'gmm-utils)
+(require 'mm-decode)
+(require 'gnus-sum)
+(require 'gnus-art)
+
+(eval-when-compile (require 'cl))
+
+(defun gnus-icalendar-find-if (pred seq)
+  (catch 'found
+    (while seq
+      (when (funcall pred (car seq))
+        (throw 'found (car seq)))
+      (pop seq))))
+
+;;;
+;;; ical-event
+;;;
+
+(defclass gnus-icalendar-event ()
+  ((organizer :initarg :organizer
+              :accessor gnus-icalendar-event:organizer
+              :initform ""
+              :type (or null string))
+   (summary :initarg :summary
+            :accessor gnus-icalendar-event:summary
+            :initform ""
+            :type (or null string))
+   (description :initarg :description
+                :accessor gnus-icalendar-event:description
+                :initform ""
+                :type (or null string))
+   (location :initarg :location
+             :accessor gnus-icalendar-event:location
+             :initform ""
+             :type (or null string))
+   (start-time :initarg :start-time
+          :accessor gnus-icalendar-event:start-time
+          :initform ""
+          :type (or null t))
+   (end-time :initarg :end-time
+        :accessor gnus-icalendar-event:end-time
+        :initform ""
+        :type (or null t))
+   (recur :initarg :recur
+          :accessor gnus-icalendar-event:recur
+          :initform ""
+          :type (or null string))
+   (uid :initarg :uid
+        :accessor gnus-icalendar-event:uid
+        :type string)
+   (method :initarg :method
+           :accessor gnus-icalendar-event:method
+           :initform "PUBLISH"
+           :type (or null string))
+   (rsvp :initarg :rsvp
+         :accessor gnus-icalendar-event:rsvp
+         :initform nil
+         :type (or null boolean))
+   (participation-type :initarg :participation-type
+         :accessor gnus-icalendar-event:participation-type
+         :initform 'non-participant
+         :type (or null t))
+   (req-participants :initarg :req-participants
+         :accessor gnus-icalendar-event:req-participants
+         :initform nil
+         :type (or null t))
+   (opt-participants :initarg :opt-participants
+         :accessor gnus-icalendar-event:opt-participants
+         :initform nil
+         :type (or null t)))
+  "generic iCalendar Event class")
+
+(defclass gnus-icalendar-event-request (gnus-icalendar-event)
+  nil
+  "iCalendar class for REQUEST events")
+
+(defclass gnus-icalendar-event-cancel (gnus-icalendar-event)
+  nil
+  "iCalendar class for CANCEL events")
+
+(defclass gnus-icalendar-event-reply (gnus-icalendar-event)
+  nil
+  "iCalendar class for REPLY events")
+
+(defmethod gnus-icalendar-event:recurring-p ((event gnus-icalendar-event))
+  "Return t if EVENT is recurring."
+  (not (null (gnus-icalendar-event:recur event))))
+
+(defmethod gnus-icalendar-event:recurring-freq ((event gnus-icalendar-event))
+  "Return recurring frequency of EVENT."
+  (let ((rrule (gnus-icalendar-event:recur event)))
+    (string-match "FREQ=\\([[:alpha:]]+\\)" rrule)
+    (match-string 1 rrule)))
+
+(defmethod gnus-icalendar-event:recurring-interval ((event gnus-icalendar-event))
+  "Return recurring interval of EVENT."
+  (let ((rrule (gnus-icalendar-event:recur event))
+        (default-interval 1))
+
+    (string-match "INTERVAL=\\([[:digit:]]+\\)" rrule)
+    (or (match-string 1 rrule)
+        default-interval)))
+
+(defmethod gnus-icalendar-event:start ((event gnus-icalendar-event))
+  (format-time-string "%Y-%m-%d %H:%M" (gnus-icalendar-event:start-time event)))
+
+(defun gnus-icalendar-event--decode-datefield (event field zone-map)
+  (let* ((dtdate (icalendar--get-event-property event field))
+         (dtdate-zone (icalendar--find-time-zone
+                       (icalendar--get-event-property-attributes
+                        event field) zone-map))
+         (dtdate-dec (icalendar--decode-isodatetime dtdate nil dtdate-zone)))
+    (apply 'encode-time dtdate-dec)))
+
+(defun gnus-icalendar-event--find-attendee (ical name-or-email)
+  (let* ((event (car (icalendar--all-events ical)))
+         (event-props (caddr event)))
+    (gmm-labels ((attendee-name (att) (plist-get (cadr att) 'CN))
+                 (attendee-email (att)
+                   (replace-regexp-in-string "^.*MAILTO:" "" (caddr att)))
+                 (attendee-prop-matches-p (prop)
+                   (and (eq (car prop) 'ATTENDEE)
+                        (or (member (attendee-name prop) name-or-email)
+                            (let ((att-email (attendee-email prop)))
+                              (gnus-icalendar-find-if (lambda (email)
+                                                        (string-match email att-email))
+                                                      name-or-email))))))
+
+      (gnus-icalendar-find-if #'attendee-prop-matches-p event-props))))
+
+(defun gnus-icalendar-event--get-attendee-names (ical)
+  (let* ((event (car (icalendar--all-events ical)))
+         (attendee-props (gnus-remove-if-not
+                          (lambda (p) (eq (car p) 'ATTENDEE))
+                          (caddr event))))
+
+    (gmm-labels ((attendee-role (prop) (plist-get (cadr prop) 'ROLE))
+                 (attendee-name (prop)
+                                (or (plist-get (cadr prop) 'CN)
+                                    (replace-regexp-in-string "^.*MAILTO:" "" (caddr prop))))
+                 (attendees-by-type (type)
+                   (gnus-remove-if-not
+                    (lambda (p) (string= (attendee-role p) type))
+                    attendee-props))
+                 (attendee-names-by-type (type)
+                    (mapcar #'attendee-name (attendees-by-type type))))
+
+      (list
+       (attendee-names-by-type "REQ-PARTICIPANT")
+       (attendee-names-by-type "OPT-PARTICIPANT")))))
+
+(defun gnus-icalendar-event-from-ical (ical &optional attendee-name-or-email)
+  (let* ((event (car (icalendar--all-events ical)))
+         (organizer (replace-regexp-in-string
+                     "^.*MAILTO:" ""
+                     (or (icalendar--get-event-property event 'ORGANIZER) "")))
+         (prop-map '((summary . SUMMARY)
+                     (description . DESCRIPTION)
+                     (location . LOCATION)
+                     (recur . RRULE)
+                     (uid . UID)))
+         (method (caddr (assoc 'METHOD (caddr (car (nreverse ical))))))
+         (attendee (when attendee-name-or-email
+                     (gnus-icalendar-event--find-attendee ical attendee-name-or-email)))
+         (attendee-names (gnus-icalendar-event--get-attendee-names ical))
+         (role (plist-get (cadr attendee) 'ROLE))
+         (participation-type (pcase role
+                              ("REQ-PARTICIPANT" 'required)
+                              ("OPT-PARTICIPANT" 'optional)
+                              (_                 'non-participant)))
+         (zone-map (icalendar--convert-all-timezones ical))
+         (args (list :method method
+                     :organizer organizer
+                     :start-time (gnus-icalendar-event--decode-datefield event 'DTSTART zone-map)
+                     :end-time (gnus-icalendar-event--decode-datefield event 'DTEND zone-map)
+                     :rsvp (string= (plist-get (cadr attendee) 'RSVP) "TRUE")
+                     :participation-type participation-type
+                     :req-participants (car attendee-names)
+                     :opt-participants (cadr attendee-names)))
+         (event-class (cond
+                       ((string= method "REQUEST") 'gnus-icalendar-event-request)
+                       ((string= method "CANCEL") 'gnus-icalendar-event-cancel)
+                       ((string= method "REPLY") 'gnus-icalendar-event-reply)
+                       (t 'gnus-icalendar-event))))
+
+    (gmm-labels ((map-property (prop)
+                   (let ((value (icalendar--get-event-property event prop)))
+                     (when value
+                       ;; ugly, but cannot get
+                       ;;replace-regexp-in-string work with "\\" as
+                       ;;REP, plus we should also handle "\\;"
+                       (replace-regexp-in-string
+                        "\\\\," ","
+                        (replace-regexp-in-string
+                         "\\\\n" "\n" (substring-no-properties value))))))
+                 (accumulate-args (mapping)
+                   (destructuring-bind (slot . ical-property) mapping
+                     (setq args (append (list
+                                         (intern (concat ":" (symbol-name slot)))
+                                         (map-property ical-property))
+                                        args)))))
+
+      (mapc #'accumulate-args prop-map)
+      (apply 'make-instance event-class args))))
+
+(defun gnus-icalendar-event-from-buffer (buf &optional attendee-name-or-email)
+  "Parse RFC5545 iCalendar in buffer BUF and return an event object.
+
+Return a gnus-icalendar-event object representing the first event
+contained in the invitation. Return nil for calendars without an event entry.
+
+ATTENDEE-NAME-OR-EMAIL is a list of strings that will be matched
+against the event's attendee names and emails. Invitation rsvp
+status will be retrieved from the first matching attendee record."
+  (let ((ical (with-current-buffer (icalendar--get-unfolded-buffer (get-buffer buf))
+                (goto-char (point-min))
+                (icalendar--read-element nil nil))))
+
+    (when ical
+      (gnus-icalendar-event-from-ical ical attendee-name-or-email))))
+
+;;;
+;;; gnus-icalendar-event-reply
+;;;
+
+(defun gnus-icalendar-event--build-reply-event-body (ical-request status identities)
+  (let ((summary-status (capitalize (symbol-name status)))
+        (attendee-status (upcase (symbol-name status)))
+        reply-event-lines)
+    (gmm-labels ((update-summary (line)
+                   (if (string-match "^[^:]+:" line)
+                       (replace-match (format "\\&%s: " summary-status) t nil line)
+                     line))
+                 (update-dtstamp ()
+                   (format-time-string "DTSTAMP:%Y%m%dT%H%M%SZ" nil t))
+                 (attendee-matches-identity (line)
+                   (gnus-icalendar-find-if (lambda (name) (string-match-p name line))
+                                           identities))
+                 (update-attendee-status (line)
+                   (when (and (attendee-matches-identity line)
+                              (string-match "\\(PARTSTAT=\\)[^;]+" line))
+                     (replace-match (format "\\1%s" attendee-status) t nil line)))
+                 (process-event-line (line)
+                   (when (string-match "^\\([^;:]+\\)" line)
+                     (let* ((key (match-string 0 line))
+                            ;; NOTE: not all of the below fields are mandatory,
+                            ;; but they are often present in other clients'
+                            ;; replies. Can be helpful for debugging, too.
+                            (new-line
+                             (cond
+                              ((string= key "ATTENDEE") (update-attendee-status line))
+                              ((string= key "SUMMARY") (update-summary line))
+                              ((string= key "DTSTAMP") (update-dtstamp))
+                              ((member key '("ORGANIZER" "DTSTART" "DTEND"
+                                             "LOCATION" "DURATION" "SEQUENCE"
+                                             "RECURRENCE-ID" "UID")) line)
+                              (t nil))))
+                       (when new-line
+                         (push new-line reply-event-lines))))))
+
+      (mapc #'process-event-line (split-string ical-request "\n"))
+
+      (unless (gnus-icalendar-find-if (lambda (x) (string-match "^ATTENDEE" x))
+                          reply-event-lines)
+        (error "Could not find an event attendee matching given identity"))
+
+      (mapconcat #'identity `("BEGIN:VEVENT"
+                              ,@(nreverse reply-event-lines)
+                              "END:VEVENT")
+                 "\n"))))
+
+(defun gnus-icalendar-event-reply-from-buffer (buf status identities)
+  "Build a calendar event reply for request contained in BUF.
+The reply will have STATUS (`accepted', `tentative' or  `declined').
+The reply will be composed for attendees matching any entry
+on the IDENTITIES list."
+  (gmm-labels ((extract-block (blockname)
+               (save-excursion
+                 (let ((block-start-re (format "^BEGIN:%s" blockname))
+                       (block-end-re (format "^END:%s" blockname))
+                       start)
+                   (when (re-search-forward block-start-re nil t)
+                     (setq start (line-beginning-position))
+                     (re-search-forward block-end-re)
+                     (buffer-substring-no-properties start (line-end-position)))))))
+
+    (let (zone event)
+      (with-current-buffer (icalendar--get-unfolded-buffer (get-buffer buf))
+        (goto-char (point-min))
+        (setq zone (extract-block "VTIMEZONE")
+              event (extract-block "VEVENT")))
+
+      (when event
+        (let ((contents (list "BEGIN:VCALENDAR"
+                              "METHOD:REPLY"
+                              "PRODID:Gnus"
+                              "VERSION:2.0"
+                              zone
+                              (gnus-icalendar-event--build-reply-event-body event status identities)
+                              "END:VCALENDAR")))
+
+          (mapconcat #'identity (delq nil contents) "\n"))))))
+
+;;;
+;;; gnus-icalendar-org
+;;;
+;;; TODO: this is an optional feature, and it's only available with org-mode
+;;; 7+, so will need to properly handle emacsen with no/outdated org-mode
+
+(require 'org)
+(require 'org-capture)
+
+(defgroup gnus-icalendar-org nil
+  "Settings for Calendar Event gnus/org integration."
+  :version "24.4"
+  :group 'gnus-icalendar
+  :prefix "gnus-icalendar-org-")
+
+(defcustom gnus-icalendar-org-capture-file nil
+  "Target Org file for storing captured calendar events."
+  :type '(choice (const nil) file)
+  :group 'gnus-icalendar-org)
+
+(defcustom gnus-icalendar-org-capture-headline nil
+  "Target outline in `gnus-icalendar-org-capture-file' for storing captured events."
+  :type '(repeat string)
+  :group 'gnus-icalendar-org)
+
+(defcustom gnus-icalendar-org-template-name "used by gnus-icalendar-org"
+  "Org-mode template name."
+  :type '(string)
+  :group 'gnus-icalendar-org)
+
+(defcustom gnus-icalendar-org-template-key "#"
+  "Org-mode template hotkey."
+  :type '(string)
+  :group 'gnus-icalendar-org)
+
+(defvar gnus-icalendar-org-enabled-p nil)
+
+
+(defmethod gnus-icalendar-event:org-repeat ((event gnus-icalendar-event))
+  "Return `org-mode' timestamp repeater string for recurring EVENT.
+Return nil for non-recurring EVENT."
+  (when (gnus-icalendar-event:recurring-p event)
+    (let* ((freq-map '(("HOURLY" . "h")
+                       ("DAILY" . "d")
+                       ("WEEKLY" . "w")
+                       ("MONTHLY" . "m")
+                       ("YEARLY" . "y")))
+           (org-freq (cdr (assoc (gnus-icalendar-event:recurring-freq event) freq-map))))
+
+      (when org-freq
+        (format "+%s%s" (gnus-icalendar-event:recurring-interval event) org-freq)))))
+
+(defmethod gnus-icalendar-event:org-timestamp ((event gnus-icalendar-event))
+  "Build `org-mode' timestamp from EVENT start/end dates and recurrence info."
+  (let* ((start (gnus-icalendar-event:start-time event))
+         (end (gnus-icalendar-event:end-time event))
+         (start-date (format-time-string "%Y-%m-%d %a" start))
+         (start-time (format-time-string "%H:%M" start))
+         (start-at-midnight (string= start-time "00:00"))
+         (end-date (format-time-string "%Y-%m-%d %a" end))
+         (end-time (format-time-string "%H:%M" end))
+         (end-at-midnight (string= end-time "00:00"))
+         (start-end-date-diff (/ (float-time (time-subtract
+                                        (date-to-time end-date)
+                                        (date-to-time start-date)))
+                                 86400))
+         (org-repeat (gnus-icalendar-event:org-repeat event))
+         (repeat (if org-repeat (concat " " org-repeat) ""))
+         (time-1-day '(0 86400)))
+
+    ;; NOTE: special care is needed with appointments ending at midnight
+    ;; (typically all-day events): the end time has to be changed to 23:59 to
+    ;; prevent org agenda showing the event on one additional day
+    (cond
+     ;; start/end midnight
+     ;; A 0:0 - A+1 0:0 -> A
+     ;; A 0:0 - A+n 0:0 -> A - A+n-1
+     ((and start-at-midnight end-at-midnight) (if (> start-end-date-diff 1)
+                                                  (let ((end-ts (format-time-string "%Y-%m-%d %a" (time-subtract end time-1-day))))
+                                                    (format "<%s>--<%s>" start-date end-ts))
+                                                (format "<%s%s>" start-date repeat)))
+     ;; end midnight
+     ;; A .:. - A+1 0:0 -> A .:.-23:59
+     ;; A .:. - A+n 0:0 -> A .:. - A_n-1
+     (end-at-midnight (if (= start-end-date-diff 1)
+                          (format "<%s %s-23:59%s>" start-date start-time repeat)
+                        (let ((end-ts (format-time-string "%Y-%m-%d %a" (time-subtract end time-1-day))))
+                          (format "<%s %s>--<%s>" start-date start-time end-ts))))
+     ;; start midnight
+     ;; A 0:0 - A .:. -> A 0:0-.:. (default 1)
+     ;; A 0:0 - A+n .:. -> A - A+n .:.
+     ((and start-at-midnight
+           (plusp start-end-date-diff)) (format "<%s>--<%s %s>" start-date end-date end-time))
+     ;; default
+     ;; A .:. - A .:. -> A .:.-.:.
+     ;; A .:. - B .:.
+     ((zerop start-end-date-diff) (format "<%s %s-%s%s>" start-date start-time end-time repeat))
+     (t (format "<%s %s>--<%s %s>" start-date start-time end-date end-time)))))
+
+(defun gnus-icalendar--format-summary-line (summary &optional location)
+  (if location
+      (format "%s (%s)" summary location)
+    (format "%s" summary)))
+
+
+(defun gnus-icalendar--format-participant-list (participants)
+  (mapconcat #'identity participants ", "))
+
+;; TODO: make the template customizable
+(defmethod gnus-icalendar-event->org-entry ((event gnus-icalendar-event) reply-status)
+  "Return string with new `org-mode' entry describing EVENT."
+  (with-temp-buffer
+    (org-mode)
+    (with-slots (organizer summary description location
+                           recur uid) event
+      (let* ((reply (if reply-status (capitalize (symbol-name reply-status))
+                      "Not replied yet"))
+             (props `(("ICAL_EVENT" . "t")
+                      ("ID" . ,uid)
+                      ("ORGANIZER" . ,(gnus-icalendar-event:organizer event))
+                      ("LOCATION" . ,(gnus-icalendar-event:location event))
+                      ("PARTICIPATION_TYPE" . ,(symbol-name (gnus-icalendar-event:participation-type event)))
+                      ("REQ_PARTICIPANTS" . ,(gnus-icalendar--format-participant-list (gnus-icalendar-event:req-participants event)))
+                      ("OPT_PARTICIPANTS" . ,(gnus-icalendar--format-participant-list (gnus-icalendar-event:opt-participants event)))
+                      ("RRULE" . ,(gnus-icalendar-event:recur event))
+                      ("REPLY" . ,reply))))
+
+        (insert (format "* %s\n\n"
+                        (gnus-icalendar--format-summary-line summary location)))
+        (mapc (lambda (prop)
+                (org-entry-put (point) (car prop) (cdr prop)))
+              props))
+
+      (when description
+        (save-restriction
+          (narrow-to-region (point) (point))
+          (insert (gnus-icalendar-event:org-timestamp event)
+                  "\n\n"
+                  description)
+          (indent-region (point-min) (point-max) 2)
+          (fill-region (point-min) (point-max))))
+
+      (buffer-string))))
+
+(defun gnus-icalendar--deactivate-org-timestamp (ts)
+  (replace-regexp-in-string "[<>]"
+                            (lambda (m) (cond ((string= m "<") "[")
+                                              ((string= m ">") "]")))
+                            ts))
+
+(defun gnus-icalendar-find-org-event-file (event &optional org-file)
+  "Return the name of the file containing EVENT org entry.
+Return nil when not found.
+
+All org agenda files are searched for the EVENT entry.  When
+the optional ORG-FILE argument is specified, only that one file
+is searched."
+  (let ((uid (gnus-icalendar-event:uid event))
+        (files (or org-file (org-agenda-files t 'ifmode))))
+    (gmm-labels
+        ((find-event-in (file)
+           (org-check-agenda-file file)
+           (with-current-buffer (find-file-noselect file)
+             (let ((event-pos (org-find-entry-with-id uid)))
+               (when (and event-pos
+                          (string= (cdr (assoc "ICAL_EVENT" (org-entry-properties event-pos)))
+                                   "t"))
+                 (throw 'found file))))))
+
+      (gnus-icalendar-find-if #'find-event-in files))))
+
+
+(defun gnus-icalendar--show-org-event (event &optional org-file)
+  (let ((file (gnus-icalendar-find-org-event-file event org-file)))
+    (when file
+      (switch-to-buffer (find-file file))
+      (goto-char (org-find-entry-with-id (gnus-icalendar-event:uid event)))
+      (org-show-entry))))
+
+
+(defun gnus-icalendar--update-org-event (event reply-status &optional org-file)
+  (let ((file (gnus-icalendar-find-org-event-file event org-file)))
+    (when file
+      (with-current-buffer (find-file-noselect file)
+        (with-slots (uid summary description organizer location recur
+                         participation-type req-participants opt-participants) event
+          (let ((event-pos (org-find-entry-with-id uid)))
+            (when event-pos
+              (goto-char event-pos)
+
+              ;; update the headline, keep todo, priority and tags, if any
+              (save-excursion
+                (let* ((priority (org-entry-get (point) "PRIORITY"))
+                       (headline (delq nil (list
+                                            (org-entry-get (point) "TODO")
+                                            (when priority (format "[#%s]" priority))
+                                            (gnus-icalendar--format-summary-line summary location)
+                                            (org-entry-get (point) "TAGS")))))
+
+                  (re-search-forward "^\\*+ " (line-end-position))
+                  (delete-region (point) (line-end-position))
+                  (insert (mapconcat #'identity headline " "))))
+
+              ;; update props and description
+              (let ((entry-end (org-entry-end-position))
+                    (entry-outline-level (org-outline-level)))
+
+                ;; delete body of the entry, leave org drawers intact
+                (save-restriction
+                  (org-narrow-to-element)
+                  (goto-char entry-end)
+                  (re-search-backward "^[\t ]*:END:")
+                  (forward-line)
+                  (delete-region (point) entry-end))
+
+                ;; put new event description in the entry body
+                (when description
+                  (save-restriction
+                    (narrow-to-region (point) (point))
+                    (insert "\n"
+                            (gnus-icalendar-event:org-timestamp event)
+                            "\n\n"
+                            (replace-regexp-in-string "[\n]+$" "\n" description)
+                            "\n")
+                    (indent-region (point-min) (point-max) (1+ entry-outline-level))
+                    (fill-region (point-min) (point-max))))
+
+                ;; update entry properties
+                (gmm-labels
+                    ((update-org-entry (position property value)
+                                       (if (or (null value)
+                                               (string= value ""))
+                                           (org-entry-delete position property)
+                                         (org-entry-put position property value))))
+
+                  (update-org-entry event-pos "ORGANIZER" organizer)
+                  (update-org-entry event-pos "LOCATION" location)
+                  (update-org-entry event-pos "PARTICIPATION_TYPE" (symbol-name participation-type))
+                  (update-org-entry event-pos "REQ_PARTICIPANTS" (gnus-icalendar--format-participant-list req-participants))
+                  (update-org-entry event-pos "OPT_PARTICIPANTS" (gnus-icalendar--format-participant-list opt-participants))
+                  (update-org-entry event-pos "RRULE" recur)
+                  (update-org-entry event-pos "REPLY"
+                                    (if reply-status (capitalize (symbol-name reply-status))
+                                      "Not replied yet")))
+                (save-buffer)))))))))
+
+
+(defun gnus-icalendar--cancel-org-event (event &optional org-file)
+  (let ((file (gnus-icalendar-find-org-event-file event org-file)))
+    (when file
+      (with-current-buffer (find-file-noselect file)
+        (let ((event-pos (org-find-entry-with-id (gnus-icalendar-event:uid event))))
+          (when event-pos
+            (let ((ts (org-entry-get event-pos "DT")))
+              (when ts
+                (org-entry-put event-pos "DT" (gnus-icalendar--deactivate-org-timestamp ts))
+                (save-buffer)))))))))
+
+
+(defun gnus-icalendar--get-org-event-reply-status (event &optional org-file)
+  (let ((file (gnus-icalendar-find-org-event-file event org-file)))
+    (when file
+      (save-excursion
+        (with-current-buffer (find-file-noselect file)
+          (let ((event-pos (org-find-entry-with-id (gnus-icalendar-event:uid event))))
+            (org-entry-get event-pos "REPLY")))))))
+
+
+(defun gnus-icalendar-insinuate-org-templates ()
+  (unless (gnus-icalendar-find-if (lambda (x) (string= (cadr x) gnus-icalendar-org-template-name))
+                      org-capture-templates)
+    (setq org-capture-templates
+          (append `((,gnus-icalendar-org-template-key
+                     ,gnus-icalendar-org-template-name
+                     entry
+                     (file+olp ,gnus-icalendar-org-capture-file ,@gnus-icalendar-org-capture-headline)
+                     "%i"
+                     :immediate-finish t))
+                  org-capture-templates))
+
+    ;; hide the template from interactive template selection list
+    ;; (org-capture)
+    ;; NOTE: doesn't work when capturing from string
+    ;; (when (boundp 'org-capture-templates-contexts)
+    ;;   (push `(,gnus-icalendar-org-template-key "" ((in-mode . "gnus-article-mode")))
+    ;;         org-capture-templates-contexts))
+    ))
+
+(defun gnus-icalendar:org-event-save (event reply-status)
+  (with-temp-buffer
+    (org-capture-string (gnus-icalendar-event->org-entry event reply-status)
+                        gnus-icalendar-org-template-key)))
+
+(defun gnus-icalendar-show-org-agenda (event)
+  (let* ((time-delta (time-subtract (gnus-icalendar-event:end-time event)
+                                    (gnus-icalendar-event:start-time event)))
+         (duration-days (1+ (/ (+ (* (car time-delta) (expt 2 16))
+                                  (cadr time-delta))
+                               86400))))
+
+    (org-agenda-list nil (gnus-icalendar-event:start event) duration-days)))
+
+(defmethod gnus-icalendar-event:sync-to-org ((event gnus-icalendar-event-request) reply-status)
+  (if (gnus-icalendar-find-org-event-file event)
+      (gnus-icalendar--update-org-event event reply-status)
+    (gnus-icalendar:org-event-save event reply-status)))
+
+(defmethod gnus-icalendar-event:sync-to-org ((event gnus-icalendar-event-cancel) reply-status)
+  (when (gnus-icalendar-find-org-event-file event)
+    (gnus-icalendar--cancel-org-event event)))
+
+(defun gnus-icalendar-org-setup ()
+  (if (and gnus-icalendar-org-capture-file gnus-icalendar-org-capture-headline)
+      (progn
+        (gnus-icalendar-insinuate-org-templates)
+        (setq gnus-icalendar-org-enabled-p t))
+    (message "Cannot enable Calendar->Org: missing capture file, headline")))
+
+;;;
+;;; gnus-icalendar
+;;;
+
+(defgroup gnus-icalendar nil
+  "Settings for inline display of iCalendar invitations."
+  :version "24.4"
+  :group 'gnus-article
+  :prefix "gnus-icalendar-")
+
+(defcustom gnus-icalendar-reply-bufname "*CAL*"
+  "Buffer used for building iCalendar invitation reply."
+  :type '(string)
+  :group 'gnus-icalendar)
+
+(defcustom gnus-icalendar-additional-identities nil
+  "We need to know your identity to make replies to calendar requests work.
+
+Gnus will only offer you the Accept/Tentative/Decline buttons for
+calendar events if any of your identities matches at least one
+RSVP participant.
+
+Your identity is guessed automatically from the variables
+`user-full-name', `user-mail-address',
+`gnus-ignored-from-addresses' and `message-alternative-emails'.
+
+If you need even more aliases you can define them here.  It really
+only makes sense to define names or email addresses."
+
+  :type '(repeat string)
+  :group 'gnus-icalendar)
+
+(make-variable-buffer-local
+ (defvar gnus-icalendar-reply-status nil))
+
+(make-variable-buffer-local
+ (defvar gnus-icalendar-event nil))
+
+(make-variable-buffer-local
+ (defvar gnus-icalendar-handle nil))
+
+(defun gnus-icalendar-identities ()
+  "Return list of regexp-quoted names and email addresses belonging to the user.
+
+These will be used to retrieve the RSVP information from ical events."
+  (apply #'append
+         (mapcar (lambda (x) (if (listp x) x (list x)))
+                 (list user-full-name (regexp-quote user-mail-address)
+                       ; NOTE: these can be lists
+                       gnus-ignored-from-addresses ; already regexp-quoted
+                       message-alternative-emails  ;
+                       (mapcar #'regexp-quote gnus-icalendar-additional-identities)))))
+
+;; TODO: make the template customizable
+(defmethod gnus-icalendar-event->gnus-calendar ((event gnus-icalendar-event) &optional reply-status)
+  "Format an overview of EVENT details."
+  (gmm-labels ((format-header (x)
+            (format "%-12s%s"
+                    (propertize (concat (car x) ":") 'face 'bold)
+                    (cadr x))))
+
+    (with-slots (organizer summary description location recur uid
+                           method rsvp participation-type) event
+      (let ((headers `(("Summary" ,summary)
+                      ("Location" ,(or location ""))
+                      ("Time" ,(gnus-icalendar-event:org-timestamp event))
+                      ("Organizer" ,organizer)
+                      ("Attendance" ,(if (eq participation-type 'non-participant)
+                                         "You are not listed as an attendee"
+                                       (capitalize (symbol-name participation-type))))
+                      ("Method" ,method))))
+
+       (when (and (not (gnus-icalendar-event-reply-p event)) rsvp)
+         (setq headers (append headers
+                               `(("Status" ,(or reply-status "Not replied yet"))))))
+
+       (concat
+        (mapconcat #'format-header headers "\n")
+        "\n\n"
+        description)))))
+
+(defmacro gnus-icalendar-with-decoded-handle (handle &rest body)
+  "Execute BODY in buffer containing the decoded contents of HANDLE."
+  (let ((charset (make-symbol "charset")))
+    `(let ((,charset (cdr (assoc 'charset (mm-handle-type ,handle)))))
+       (with-temp-buffer
+         (mm-insert-part ,handle)
+         (when (string= ,charset "utf-8")
+           (mm-decode-coding-region (point-min) (point-max) 'utf-8))
+
+         ,@body))))
+
+
+(defun gnus-icalendar-event-from-handle (handle &optional attendee-name-or-email)
+  (gnus-icalendar-with-decoded-handle handle
+                       (gnus-icalendar-event-from-buffer (current-buffer) attendee-name-or-email)))
+
+(defun gnus-icalendar-insert-button (text callback data)
+  ;; FIXME: the gnus-mime-button-map keymap does not make sense for this kind
+  ;; of button.
+  (let ((start (point)))
+    (gnus-add-text-properties
+     start
+     (progn
+       (insert "[ " text " ]")
+       (point))
+     `(gnus-callback
+       ,callback
+       keymap ,gnus-mime-button-map
+       face ,gnus-article-button-face
+       gnus-data ,data))
+    (widget-convert-button 'link start (point)
+                           :action 'gnus-widget-press-button
+                           :button-keymap gnus-widget-button-keymap)))
+
+(defun gnus-icalendar-send-buffer-by-mail (buffer-name subject)
+  (let ((message-signature nil))
+    (with-current-buffer gnus-summary-buffer
+      (gnus-summary-reply)
+      (message-goto-body)
+      (mml-insert-multipart "alternative")
+      (mml-insert-empty-tag 'part 'type "text/plain")
+      (mml-attach-buffer buffer-name "text/calendar; method=REPLY; charset=UTF-8")
+      (message-goto-subject)
+      (delete-region (line-beginning-position) (line-end-position))
+      (insert "Subject: " subject)
+      (message-send-and-exit))))
+
+(defun gnus-icalendar-reply (data)
+  (let* ((handle (car data))
+         (status (cadr data))
+         (event (caddr data))
+         (reply (gnus-icalendar-with-decoded-handle handle
+                  (gnus-icalendar-event-reply-from-buffer
+                   (current-buffer) status (gnus-icalendar-identities)))))
+
+    (when reply
+      (gmm-labels ((fold-icalendar-buffer ()
+               (goto-char (point-min))
+               (while (re-search-forward "^\\(.\\{72\\}\\)\\(.+\\)$" nil t)
+                 (replace-match "\\1\n \\2")
+                 (goto-char (line-beginning-position)))))
+        (let ((subject (concat (capitalize (symbol-name status))
+                               ": " (gnus-icalendar-event:summary event))))
+
+          (with-current-buffer (get-buffer-create gnus-icalendar-reply-bufname)
+            (delete-region (point-min) (point-max))
+            (insert reply)
+            (fold-icalendar-buffer)
+            (gnus-icalendar-send-buffer-by-mail (buffer-name) subject))
+
+          ;; Back in article buffer
+          (setq-local gnus-icalendar-reply-status status)
+          (when gnus-icalendar-org-enabled-p
+            (gnus-icalendar--update-org-event event status)
+            ;; refresh article buffer to update the reply status
+            (with-current-buffer gnus-summary-buffer
+              (gnus-summary-show-article))))))))
+
+(defun gnus-icalendar-sync-event-to-org (event)
+  (gnus-icalendar-event:sync-to-org event gnus-icalendar-reply-status))
+
+(defmethod gnus-icalendar-event:inline-reply-buttons ((event gnus-icalendar-event) handle)
+  (when (gnus-icalendar-event:rsvp event)
+    `(("Accept" gnus-icalendar-reply (,handle accepted ,event))
+      ("Tentative" gnus-icalendar-reply (,handle tentative ,event))
+      ("Decline" gnus-icalendar-reply (,handle declined ,event)))))
+
+(defmethod gnus-icalendar-event:inline-reply-buttons ((event gnus-icalendar-event-reply) handle)
+  "No buttons for REPLY events."
+  nil)
+
+(defmethod gnus-icalendar-event:inline-reply-status ((event gnus-icalendar-event))
+  (or (when gnus-icalendar-org-enabled-p
+        (gnus-icalendar--get-org-event-reply-status event))
+      "Not replied yet"))
+
+(defmethod gnus-icalendar-event:inline-reply-status ((event gnus-icalendar-event-reply))
+  "No reply status for REPLY events."
+  nil)
+
+
+(defmethod gnus-icalendar-event:inline-org-buttons ((event gnus-icalendar-event))
+  (let* ((org-entry-exists-p (gnus-icalendar-find-org-event-file event))
+         (export-button-text (if org-entry-exists-p "Update Org Entry" "Export to Org")))
+
+    (delq nil (list
+               `("Show Agenda" gnus-icalendar-show-org-agenda ,event)
+               (when (gnus-icalendar-event-request-p event)
+                 `(,export-button-text gnus-icalendar-sync-event-to-org ,event))
+               (when org-entry-exists-p
+                 `("Show Org Entry" gnus-icalendar--show-org-event ,event))))))
+
+
+(defmethod gnus-icalendar-event:inline-org-buttons ((event gnus-icalendar-event-cancel))
+  (let ((org-entry-exists-p (gnus-icalendar-find-org-event-file event)))
+
+    (delq nil (list
+               `("Show Agenda" gnus-icalendar-show-org-agenda ,event)
+               (when org-entry-exists-p
+                 `("Update Org Entry" gnus-icalendar-sync-event-to-org ,event))
+               (when org-entry-exists-p
+                 `("Show Org Entry" gnus-icalendar--show-org-event ,event))))))
+
+
+(defun gnus-icalendar-mm-inline (handle)
+  (let ((event (gnus-icalendar-event-from-handle handle (gnus-icalendar-identities))))
+
+    (setq gnus-icalendar-reply-status nil)
+
+    (when event
+      (gmm-labels ((insert-button-group (buttons)
+                (when buttons
+                  (mapc (lambda (x)
+                          (apply 'gnus-icalendar-insert-button x)
+                          (insert "    "))
+                        buttons)
+                  (insert "\n\n"))))
+
+        (insert-button-group
+        (gnus-icalendar-event:inline-reply-buttons event handle))
+
+        (when gnus-icalendar-org-enabled-p
+          (insert-button-group (gnus-icalendar-event:inline-org-buttons event)))
+
+        (setq gnus-icalendar-event event
+              gnus-icalendar-handle handle)
+
+        (insert (gnus-icalendar-event->gnus-calendar
+                 event
+                 (gnus-icalendar-event:inline-reply-status event)))))))
+
+(defun gnus-icalendar-save-part (handle)
+  (let (event)
+    (when (and (equal (car (mm-handle-type handle)) "text/calendar")
+               (setq event (gnus-icalendar-event-from-handle handle (gnus-icalendar-identities))))
+
+      (gnus-icalendar-event:sync-to-org event))))
+
+
+(defun gnus-icalendar-save-event ()
+  "Save the Calendar event in the text/calendar part under point."
+  (interactive)
+  (gnus-article-check-buffer)
+  (let ((data (get-text-property (point) 'gnus-data)))
+    (when data
+      (gnus-icalendar-save-part data))))
+
+(defun gnus-icalendar-reply-accept ()
+  "Accept invitation in the current article."
+  (interactive)
+  (with-current-buffer gnus-article-buffer
+    (gnus-icalendar-reply (list gnus-icalendar-handle 'accepted gnus-icalendar-event))
+    (setq-local gnus-icalendar-reply-status 'accepted)))
+
+(defun gnus-icalendar-reply-tentative ()
+  "Send tentative response to invitation in the current article."
+  (interactive)
+  (with-current-buffer gnus-article-buffer
+    (gnus-icalendar-reply (list gnus-icalendar-handle 'tentative gnus-icalendar-event))
+    (setq-local gnus-icalendar-reply-status 'tentative)))
+
+(defun gnus-icalendar-reply-decline ()
+  "Decline invitation in the current article."
+  (interactive)
+  (with-current-buffer gnus-article-buffer
+    (gnus-icalendar-reply (list gnus-icalendar-handle 'declined gnus-icalendar-event))
+    (setq-local gnus-icalendar-reply-status 'declined)))
+
+(defun gnus-icalendar-event-export ()
+  "Export calendar event to `org-mode', or update existing agenda entry."
+  (interactive)
+  (with-current-buffer gnus-article-buffer
+    (gnus-icalendar-sync-event-to-org gnus-icalendar-event))
+  ;; refresh article buffer in case the reply had been sent before initial org
+  ;; export
+  (with-current-buffer gnus-summary-buffer
+    (gnus-summary-show-article)))
+
+(defun gnus-icalendar-event-show ()
+  "Display `org-mode' agenda entry related to the calendar event."
+  (interactive)
+  (gnus-icalendar--show-org-event
+   (with-current-buffer gnus-article-buffer
+     gnus-icalendar-event)))
+
+(defun gnus-icalendar-event-check-agenda ()
+  "Display `org-mode' agenda for days between event start and end dates."
+  (interactive)
+  (gnus-icalendar-show-org-agenda
+   (with-current-buffer gnus-article-buffer gnus-icalendar-event)))
+
+(defvar gnus-mime-action-alist)         ; gnus-art
+
+(defun gnus-icalendar-setup ()
+  (add-to-list 'mm-inlined-types "text/calendar")
+  (add-to-list 'mm-automatic-display "text/calendar")
+  (add-to-list 'mm-inline-media-tests '("text/calendar" gnus-icalendar-mm-inline identity))
+
+  (gnus-define-keys (gnus-summary-calendar-map "i" gnus-summary-mode-map)
+    "a" gnus-icalendar-reply-accept
+    "t" gnus-icalendar-reply-tentative
+    "d" gnus-icalendar-reply-decline
+    "c" gnus-icalendar-event-check-agenda
+    "e" gnus-icalendar-event-export
+    "s" gnus-icalendar-event-show)
+
+  (require 'gnus-art)
+  (add-to-list 'gnus-mime-action-alist
+               (cons "save calendar event" 'gnus-icalendar-save-event)
+               t))
+
+(provide 'gnus-icalendar)
+
+;;; gnus-icalendar.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-int.el b/xemacs-packages/gnus/lisp/gnus-int.el
new file mode 100644 (file)
index 0000000..d0798d3
--- /dev/null
@@ -0,0 +1,877 @@
+;;; gnus-int.el --- backend interface functions for Gnus
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'gnus)
+(require 'message)
+(require 'gnus-range)
+
+(autoload 'gnus-run-hook-with-args "gnus-util")
+(autoload 'gnus-agent-expire "gnus-agent")
+(autoload 'gnus-agent-regenerate-group "gnus-agent")
+(autoload 'gnus-agent-read-servers-validate-native "gnus-agent")
+(autoload 'gnus-agent-possibly-synchronize-flags-server "gnus-agent")
+
+(defcustom gnus-open-server-hook nil
+  "Hook called just before opening connection to the news server."
+  :group 'gnus-start
+  :type 'hook)
+
+(defcustom gnus-after-set-mark-hook nil
+  "Hook called just after marks are set in a group."
+  :version "24.1"
+  :group 'gnus-start
+  :type 'hook)
+
+(defcustom gnus-before-update-mark-hook nil
+  "Hook called just before marks are updated in a group."
+  :version "24.1"
+  :group 'gnus-start
+  :type 'hook)
+
+(defcustom gnus-server-unopen-status nil
+  "The default status if the server is not able to open.
+If the server is covered by Gnus agent, the possible values are
+`denied', set the server denied; `offline', set the server offline;
+nil, ask user.  If the server is not covered by Gnus agent, set the
+server denied."
+  :version "22.1"
+  :group 'gnus-start
+  :type '(choice (const :tag "Ask" nil)
+                (const :tag "Deny server" denied)
+                (const :tag "Unplug Agent" offline)))
+
+(defcustom gnus-nntp-server nil
+  "The name of the host running the NNTP server."
+  :group 'gnus-server
+  :type '(choice (const :tag "disable" nil)
+                string))
+(make-obsolete-variable 'gnus-nntp-server 'gnus-select-method "24.1")
+
+(defvar gnus-internal-registry-spool-current-method nil
+  "The current method, for the registry.")
+
+
+(defun gnus-server-opened (gnus-command-method)
+  "Check whether a connection to GNUS-COMMAND-METHOD has been opened."
+  (unless (eq (gnus-server-status gnus-command-method)
+             'denied)
+    (when (stringp gnus-command-method)
+      (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
+    (funcall (inline (gnus-get-function gnus-command-method 'server-opened))
+            (nth 1 gnus-command-method))))
+
+(defun gnus-status-message (gnus-command-method)
+  "Return the status message from GNUS-COMMAND-METHOD.
+If GNUS-COMMAND-METHOD is a string, it is interpreted as a group
+name.  The method this group uses will be queried."
+  (let ((gnus-command-method
+        (if (stringp gnus-command-method)
+            (gnus-find-method-for-group gnus-command-method)
+          gnus-command-method)))
+    (funcall (gnus-get-function gnus-command-method 'status-message)
+            (nth 1 gnus-command-method))))
+
+;;;
+;;; Server Communication
+;;;
+
+(defun gnus-start-news-server (&optional confirm)
+  "Open a method for getting news.
+If CONFIRM is non-nil, the user will be asked for an NNTP server."
+  (let (how)
+    (if gnus-current-select-method
+       ;; Stream is already opened.
+       nil
+      ;; Open NNTP server.
+      (when confirm
+       ;; Read server name with completion.
+       (setq gnus-nntp-server
+             (gnus-completing-read "NNTP server"
+                                    (cons gnus-nntp-server
+                                         (if (boundp 'gnus-secondary-servers)
+                                             gnus-secondary-servers))
+                                    nil gnus-nntp-server)))
+
+      (when (and gnus-nntp-server
+                (stringp gnus-nntp-server)
+                (not (string= gnus-nntp-server "")))
+       (setq gnus-select-method
+             (cond ((or (string= gnus-nntp-server "")
+                        (string= gnus-nntp-server "::"))
+                    (list 'nnspool (system-name)))
+                   ((string-match "^:" gnus-nntp-server)
+                    (list 'nnmh gnus-nntp-server
+                          (list 'nnmh-directory
+                                (file-name-as-directory
+                                 (expand-file-name
+                                  (substring gnus-nntp-server 1) "~/")))
+                          (list 'nnmh-get-new-mail nil)))
+                   (t
+                    (list 'nntp gnus-nntp-server)))))
+
+      (setq how (car gnus-select-method))
+      (cond
+       ((eq how 'nnspool)
+       (require 'nnspool)
+       (gnus-message 5 "Looking up local news spool..."))
+       ((eq how 'nnmh)
+       (require 'nnmh)
+       (gnus-message 5 "Looking up mh spool..."))
+       (t
+       (require 'nntp)))
+      (setq gnus-current-select-method gnus-select-method)
+      (gnus-run-hooks 'gnus-open-server-hook)
+
+      ;; Partially validate agent covered methods now that the
+      ;; gnus-select-method is known.
+
+      (if gnus-agent
+          ;; NOTE: This is here for one purpose only.  By validating
+          ;; the current select method, it converts the old 5.10.3,
+          ;; and earlier, format to the current format.  That enables
+          ;; the agent code within gnus-open-server to function
+          ;; correctly.
+          (gnus-agent-read-servers-validate-native gnus-select-method))
+
+      (or
+       ;; gnus-open-server-hook might have opened it
+       (gnus-server-opened gnus-select-method)
+       (gnus-open-server gnus-select-method)
+       gnus-batch-mode
+       (gnus-y-or-n-p
+       (gnus-format-message
+        "%s (%s) open error: `%s'.  Continue? "
+        (car gnus-select-method) (cadr gnus-select-method)
+        (gnus-status-message gnus-select-method)))
+       (gnus-error 1 "Couldn't open server on %s"
+                  (nth 1 gnus-select-method))))))
+
+(defun gnus-check-group (group)
+  "Try to make sure that the server where GROUP exists is alive."
+  (let ((method (gnus-find-method-for-group group)))
+    (or (gnus-server-opened method)
+       (gnus-open-server method))))
+
+(defun gnus-check-server (&optional method silent)
+  "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))
+       result)
+    ;; Transform virtual server names into select methods.
+    (when (stringp method)
+      (setq method (gnus-server-to-method method)))
+    (if (gnus-server-opened method)
+       ;; The stream is already opened.
+       t
+      ;; Open the server.
+      (unless silent
+       (gnus-message 5 "Opening %s server%s..." (car method)
+                     (if (equal (nth 1 method) "") ""
+                       (format " on %s" (nth 1 method)))))
+      (gnus-run-hooks 'gnus-open-server-hook)
+      (prog1
+         (setq result (gnus-open-server method))
+       (unless silent
+         (gnus-message
+          (if result 5 3)
+          "Opening %s server%s...%s" (car method)
+          (if (equal (nth 1 method) "") ""
+            (format " on %s" (nth 1 method)))
+          (if result
+              "done"
+            (format "failed: %s"
+                    (nnheader-get-report-string (car method))))))))))
+
+(defun gnus-get-function (method function &optional noerror)
+  "Return a function symbol based on METHOD and FUNCTION."
+  ;; Translate server names into methods.
+  (unless method
+    (error "Attempted use of a nil select method"))
+  (when (stringp method)
+    (setq method (gnus-server-to-method method)))
+  ;; Check cache of constructed names.
+  (let* ((method-sym (if gnus-agent
+                        (inline (gnus-agent-get-function method))
+                      (car method)))
+        (method-fns (get method-sym 'gnus-method-functions))
+        (func (let ((method-fnlist-elt (assq function method-fns)))
+                (unless method-fnlist-elt
+                  (setq method-fnlist-elt
+                        (cons function
+                              (intern (format "%s-%s" method-sym function))))
+                  (put method-sym 'gnus-method-functions
+                       (cons method-fnlist-elt method-fns)))
+                (cdr method-fnlist-elt))))
+    ;; Maybe complain if there is no function.
+    (unless (fboundp func)
+      (unless (car method)
+       (error "Trying to require a method that doesn't exist"))
+      (require (car method))
+      (when (not (fboundp func))
+       (if noerror
+           (setq func nil)
+         (error "No such function: %s" func))))
+    func))
+
+\f
+;;;
+;;; Interface functions to the backends.
+;;;
+
+(defun gnus-method-denied-p (method)
+  (eq (nth 1 (assoc method gnus-opened-servers))
+      'denied))
+
+(defvar gnus-backend-trace nil)
+(defvar gnus-backend-trace-elapsed nil)
+
+(defun gnus-backend-trace (type form)
+  (when gnus-backend-trace
+    (with-current-buffer (get-buffer-create "*gnus trace*")
+      (buffer-disable-undo)
+      (goto-char (point-max))
+      (insert (format-time-string "%H:%M:%S")
+             (format " %.2fs %s %S\n"
+                     (if (numberp gnus-backend-trace-elapsed)
+                         (- (float-time) gnus-backend-trace-elapsed)
+                       0)
+                     type form))
+      (setq gnus-backend-trace-elapsed (float-time)))))
+
+(defun gnus-open-server (gnus-command-method)
+  "Open a connection to GNUS-COMMAND-METHOD."
+  (when (stringp gnus-command-method)
+    (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
+  (gnus-backend-trace :opening gnus-command-method)
+  (let ((elem (assoc gnus-command-method gnus-opened-servers))
+       (server (gnus-method-to-server-name gnus-command-method)))
+    ;; If this method was previously denied, we just return nil.
+    (if (eq (nth 1 elem) 'denied)
+       (progn
+         (gnus-message
+          1 "Server %s previously determined to be down; not retrying" server)
+         nil)
+      ;; Open the server.
+      (let* ((open-server-function
+             (gnus-get-function gnus-command-method 'open-server))
+             (result
+             (condition-case err
+                 (funcall open-server-function
+                          (nth 1 gnus-command-method)
+                          (nthcdr 2 gnus-command-method))
+               (error
+                (gnus-message 1 "Unable to open server %s due to: %s"
+                              server (error-message-string err))
+                nil)
+               (quit
+                (if debug-on-quit
+                    (debug "Quit")
+                  (gnus-message 1 "Quit trying to open server %s" server))
+                nil)))
+            open-offline)
+       ;; If this hasn't been opened before, we add it to the list.
+       (unless elem
+         (setq elem (list gnus-command-method nil)
+               gnus-opened-servers (cons elem gnus-opened-servers)))
+       ;; Set the status of this server.
+        (setcar
+        (cdr elem)
+        (cond (result
+               (if (eq open-server-function 'nnagent-open-server)
+                   ;; The agent's backend has a "special" status
+                   'offline
+                 'ok))
+              ((and gnus-agent
+                    (gnus-agent-method-p gnus-command-method))
+               (cond
+                (gnus-server-unopen-status
+                 ;; Set the server's status to the unopen
+                 ;; status.  If that status is offline,
+                 ;; recurse to open the agent's backend.
+                 (setq open-offline (eq gnus-server-unopen-status 'offline))
+                 gnus-server-unopen-status)
+                ((not gnus-batch-mode)
+                 (setq open-offline t)
+                 'offline)
+                (t
+                 ;; This agentized server was still denied
+                 'denied)))
+              (t
+               ;; This unagentized server must be denied
+               'denied)))
+
+        ;; NOTE: I MUST set the server's status to offline before this
+        ;; recursive call as this status will drive the
+        ;; gnus-get-function (called above) to return the agent's
+        ;; backend.
+        (if open-offline
+            ;; Recursively open this offline server to perform the
+            ;; open-server function of the agent's backend.
+            (let ((gnus-server-unopen-status 'denied))
+              ;; Bind gnus-server-unopen-status to avoid recursively
+              ;; prompting with "go offline?".  This is only a concern
+              ;; when the agent's backend fails to open the server.
+              (gnus-open-server gnus-command-method))
+         (when (and (eq (cadr elem) 'ok) gnus-agent
+                    (gnus-agent-method-p gnus-command-method))
+           (save-excursion
+             (gnus-agent-possibly-synchronize-flags-server
+              gnus-command-method)))
+         (gnus-backend-trace :opened gnus-command-method)
+          result)))))
+
+(defun gnus-close-server (gnus-command-method)
+  "Close the connection to GNUS-COMMAND-METHOD."
+  (when (stringp gnus-command-method)
+    (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
+  (funcall (gnus-get-function gnus-command-method 'close-server)
+          (nth 1 gnus-command-method)))
+
+(defun gnus-request-list (gnus-command-method)
+  "Request the active file from GNUS-COMMAND-METHOD."
+  (when (stringp gnus-command-method)
+    (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
+  (funcall (gnus-get-function gnus-command-method 'request-list)
+          (nth 1 gnus-command-method)))
+
+(defun gnus-finish-retrieve-group-infos (gnus-command-method infos data)
+  "Read and update infos from GNUS-COMMAND-METHOD."
+  (when (stringp gnus-command-method)
+    (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
+  (gnus-backend-trace :finishing gnus-command-method)
+  (prog1
+      (funcall (gnus-get-function gnus-command-method
+                                 'finish-retrieve-group-infos)
+              (nth 1 gnus-command-method)
+              infos data)
+    (gnus-backend-trace :finished gnus-command-method)))
+
+(defun gnus-retrieve-group-data-early (gnus-command-method infos)
+  "Start early async retrieval of data from GNUS-COMMAND-METHOD."
+  (when (stringp gnus-command-method)
+    (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
+  (funcall (gnus-get-function gnus-command-method 'retrieve-group-data-early)
+          (nth 1 gnus-command-method)
+          infos))
+
+(defun gnus-request-list-newsgroups (gnus-command-method)
+  "Request the newsgroups file from GNUS-COMMAND-METHOD."
+  (when (stringp gnus-command-method)
+    (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
+  (funcall (gnus-get-function gnus-command-method 'request-list-newsgroups)
+          (nth 1 gnus-command-method)))
+
+(defun gnus-request-newgroups (date gnus-command-method)
+  "Request all new groups since DATE from GNUS-COMMAND-METHOD."
+  (when (stringp gnus-command-method)
+    (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
+  (let ((func (gnus-get-function gnus-command-method 'request-newgroups t)))
+    (when func
+      (funcall func date (nth 1 gnus-command-method)))))
+
+(defun gnus-request-regenerate (gnus-command-method)
+  "Request a data generation from GNUS-COMMAND-METHOD."
+  (when (stringp gnus-command-method)
+    (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
+  (funcall (gnus-get-function gnus-command-method 'request-regenerate)
+          (nth 1 gnus-command-method)))
+
+(defun gnus-request-compact-group (group)
+  (let* ((method (gnus-find-method-for-group group))
+        (gnus-command-method method)
+        (result
+         (funcall (gnus-get-function gnus-command-method
+                                     'request-compact-group)
+                  (gnus-group-real-name group)
+                  (nth 1 gnus-command-method) t)))
+    result))
+
+(defun gnus-request-compact (gnus-command-method)
+  "Request groups compaction from GNUS-COMMAND-METHOD."
+  (when (stringp gnus-command-method)
+    (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
+  (funcall (gnus-get-function gnus-command-method 'request-compact)
+          (nth 1 gnus-command-method)))
+
+(defun gnus-request-group (group &optional dont-check gnus-command-method info)
+  "Request GROUP.  If DONT-CHECK, no information is required."
+  (let ((gnus-command-method
+        (or gnus-command-method (inline (gnus-find-method-for-group group)))))
+    (when (stringp gnus-command-method)
+      (setq gnus-command-method
+           (inline (gnus-server-to-method gnus-command-method))))
+    (funcall (inline (gnus-get-function gnus-command-method 'request-group))
+            (gnus-group-real-name group) (nth 1 gnus-command-method)
+            dont-check
+            info)))
+
+(defun gnus-request-group-description (group)
+  "Request a description of GROUP."
+  (let ((gnus-command-method (gnus-find-method-for-group group))
+       (func 'request-group-description))
+    (when (gnus-check-backend-function func group)
+      (funcall (gnus-get-function gnus-command-method func)
+              (gnus-group-real-name group) (nth 1 gnus-command-method)))))
+
+(defun gnus-request-group-scan (group info)
+  "Request that GROUP get a complete rescan."
+  (let ((gnus-command-method (gnus-find-method-for-group group))
+       (func 'request-group-scan))
+    (when (gnus-check-backend-function func group)
+      (funcall (gnus-get-function gnus-command-method func)
+              (gnus-group-real-name group) (nth 1 gnus-command-method) info))))
+
+(defun gnus-close-group (group)
+  "Request the GROUP be closed."
+  (let ((gnus-command-method (inline (gnus-find-method-for-group group))))
+    (funcall (gnus-get-function gnus-command-method 'close-group)
+            (gnus-group-real-name group) (nth 1 gnus-command-method))))
+
+(defun gnus-retrieve-headers (articles group &optional fetch-old)
+  "Request headers for ARTICLES in GROUP.
+If FETCH-OLD, retrieve all headers (or some subset thereof) in the group."
+  (let ((gnus-command-method (gnus-find-method-for-group group)))
+    (cond
+     ((and gnus-use-cache (numberp (car articles)))
+      (gnus-cache-retrieve-headers articles group fetch-old))
+     ((and gnus-agent (gnus-online gnus-command-method)
+          (gnus-agent-method-p gnus-command-method))
+      (gnus-agent-retrieve-headers articles group fetch-old))
+     (t
+      (funcall (gnus-get-function gnus-command-method 'retrieve-headers)
+              articles (gnus-group-real-name group)
+              (nth 1 gnus-command-method) fetch-old)))))
+
+(defun gnus-retrieve-articles (articles group)
+  "Request ARTICLES in GROUP."
+  (let ((gnus-command-method (gnus-find-method-for-group group)))
+    (funcall (gnus-get-function gnus-command-method 'retrieve-articles)
+            articles (gnus-group-real-name group)
+            (nth 1 gnus-command-method))))
+
+(defun gnus-retrieve-groups (groups gnus-command-method)
+  "Request active information on GROUPS from GNUS-COMMAND-METHOD."
+  (when (stringp gnus-command-method)
+    (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
+  (funcall (gnus-get-function gnus-command-method 'retrieve-groups)
+          groups (nth 1 gnus-command-method)))
+
+(defun gnus-request-type (group &optional article)
+  "Return the type (`post' or `mail') of GROUP (and ARTICLE)."
+  (let ((gnus-command-method (gnus-find-method-for-group group)))
+    (if (not (gnus-check-backend-function
+             'request-type (car gnus-command-method)))
+       'unknown
+      (funcall (gnus-get-function gnus-command-method 'request-type)
+              (gnus-group-real-name group) article))))
+
+(defun gnus-request-update-group-status (group status)
+  "Change the status of a group.
+Valid statuses include `subscribe' and `unsubscribe'."
+  (let ((gnus-command-method (gnus-find-method-for-group group)))
+    (if (not (gnus-check-backend-function
+             'request-update-group-status (car gnus-command-method)))
+       nil
+      (funcall
+       (gnus-get-function gnus-command-method 'request-update-group-status)
+       (gnus-group-real-name group) status
+       (nth 1 gnus-command-method)))))
+
+(defun gnus-request-set-mark (group action)
+  "Set marks on articles in the back end."
+  (let ((gnus-command-method (gnus-find-method-for-group group)))
+    (if (not (gnus-check-backend-function
+             'request-set-mark (car gnus-command-method)))
+       action
+      (funcall (gnus-get-function gnus-command-method 'request-set-mark)
+              (gnus-group-real-name group) action
+              (nth 1 gnus-command-method))
+      (gnus-run-hook-with-args gnus-after-set-mark-hook group action))))
+
+(defun gnus-request-update-mark (group article mark)
+  "Allow the back end to change the mark the user tries to put on an article."
+  (let ((gnus-command-method (gnus-find-method-for-group group)))
+    (if (not (gnus-check-backend-function
+             'request-update-mark (car gnus-command-method)))
+       mark
+      (gnus-run-hook-with-args gnus-before-update-mark-hook group article mark)
+      (funcall (gnus-get-function gnus-command-method 'request-update-mark)
+              (gnus-group-real-name group) article mark))))
+
+(defun gnus-request-article (article group &optional buffer)
+  "Request the ARTICLE in GROUP.
+ARTICLE can either be an article number or an article Message-ID.
+If BUFFER, insert the article in that group."
+  (let ((gnus-command-method (gnus-find-method-for-group group)))
+    (funcall (gnus-get-function gnus-command-method 'request-article)
+            article (gnus-group-real-name group)
+            (nth 1 gnus-command-method) buffer)))
+
+(defun gnus-request-thread (header group)
+  "Request the headers in the thread containing the article specified by HEADER."
+  (let ((gnus-command-method (gnus-find-method-for-group group)))
+    (funcall (gnus-get-function gnus-command-method 'request-thread)
+            header
+            (gnus-group-real-name group))))
+
+(defun gnus-select-group-with-message-id (group message-id)
+  "Activate and select GROUP with the given MESSAGE-ID selected.
+Returns the article number of the message.
+
+If GROUP is not already selected, the message will be the only one in
+the group's summary.
+"
+  ;; TODO: is there a way to know at this point whether the group will
+  ;; be newly-selected?  If so we could clean up the logic at the end
+  ;;
+  ;; save the new group's display parameter, if any, so we
+  ;; can replace it temporarily with zero.
+  (let ((saved-display
+         (gnus-group-get-parameter group 'display :allow-list)))
+
+    ;; Tell gnus we really don't want any articles
+    (gnus-group-set-parameter group 'display 0)
+
+    (unwind-protect
+        (gnus-summary-read-group-1
+         group (not :show-all) :no-article (not :kill-buffer)
+         ;; The combination of no-display and this dummy list of
+         ;; articles to select somehow makes it possible to open a
+         ;; group with no articles in it.  Black magic.
+         :no-display '(-1); select-articles
+         )
+      ;; Restore the new group's display parameter
+      (gnus-group-set-parameter group 'display saved-display)))
+
+  ;; The summary buffer was suppressed by :no-display above.
+  ;; Create it now and insert the message
+  (let ((group-is-new (gnus-summary-setup-buffer group)))
+    (condition-case err
+        (let ((article-number
+               (gnus-summary-insert-subject message-id)))
+          (unless article-number
+            (signal 'error "message-id not in group"))
+          (gnus-summary-select-article nil nil nil article-number)
+          article-number)
+      ;; Clean up the new summary and propagate the error
+      (error (when group-is-new (gnus-summary-exit))
+             (apply 'signal err)))))
+
+(defun gnus-simplify-group-name (group)
+  "Return the simplest representation of the name of GROUP.
+This is the string that Gnus uses to identify the group."
+  (gnus-group-prefixed-name
+   (gnus-group-real-name group)
+   (gnus-group-method group)))
+
+(defun gnus-warp-to-article ()
+  "Look up the current article in the group where it originated.
+This command only makes sense for groups shows articles gathered
+from other groups -- for instance, search results and the like."
+  (interactive)
+  (let ((gnus-command-method
+         (gnus-find-method-for-group gnus-newsgroup-name)))
+    (or
+     (when (gnus-check-backend-function
+            'warp-to-article (car gnus-command-method))
+       (funcall (gnus-get-function gnus-command-method 'warp-to-article)))
+     (and (bound-and-true-p gnus-registry-enabled)
+          (gnus-try-warping-via-registry)))))
+
+(defun gnus-request-head (article group)
+  "Request the head of ARTICLE in GROUP."
+  (let* ((gnus-command-method (gnus-find-method-for-group group))
+        (head (gnus-get-function gnus-command-method 'request-head t))
+        res clean-up)
+    (cond
+     ;; Check the cache.
+     ((and gnus-use-cache
+          (numberp article)
+          (gnus-cache-request-article article group))
+      (setq res (cons group article)
+           clean-up t))
+     ;; Check the agent cache.
+     ((gnus-agent-request-article article group)
+      (setq res (cons group article)
+           clean-up t))
+     ;; Use `head' function.
+     ((fboundp head)
+      (setq res (funcall head article
+                         (and (not gnus-override-method) (gnus-group-real-name group))
+                        (nth 1 gnus-command-method))))
+     ;; Use `article' function.
+     (t
+      (setq res (gnus-request-article article group)
+           clean-up t)))
+    (when clean-up
+      (with-current-buffer nntp-server-buffer
+       (goto-char (point-min))
+       (when (search-forward "\n\n" nil t)
+         (delete-region (1- (point)) (point-max)))
+       (nnheader-fold-continuation-lines)))
+    res))
+
+(defun gnus-request-body (article group)
+  "Request the body of ARTICLE in GROUP."
+  (let* ((gnus-command-method (gnus-find-method-for-group group))
+        (head (gnus-get-function gnus-command-method 'request-body t))
+        res clean-up)
+    (cond
+     ;; Check the cache.
+     ((and gnus-use-cache
+          (numberp article)
+          (gnus-cache-request-article article group))
+      (setq res (cons group article)
+           clean-up t))
+     ;; Check the agent cache.
+     ((gnus-agent-request-article article group)
+      (setq res (cons group article)
+           clean-up t))
+     ;; Use `head' function.
+     ((fboundp head)
+      (setq res (funcall head article (gnus-group-real-name group)
+                        (nth 1 gnus-command-method))))
+     ;; Use `article' function.
+     (t
+      (setq res (gnus-request-article article group)
+           clean-up t)))
+    (when clean-up
+      (with-current-buffer nntp-server-buffer
+       (goto-char (point-min))
+       (when (search-forward "\n\n" nil t)
+         (delete-region (point-min) (1- (point))))))
+    res))
+
+(defun gnus-request-post (gnus-command-method)
+  "Post the current buffer using GNUS-COMMAND-METHOD."
+  (when (stringp gnus-command-method)
+    (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
+  (funcall (gnus-get-function gnus-command-method 'request-post)
+          (nth 1 gnus-command-method)))
+
+(defun gnus-request-expunge-group (group gnus-command-method)
+  "Expunge GROUP, which is removing articles that have been marked as deleted."
+  (when (stringp gnus-command-method)
+    (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
+  (funcall (gnus-get-function gnus-command-method 'request-expunge-group)
+          (gnus-group-real-name group)
+          (nth 1 gnus-command-method)))
+
+(defun gnus-request-scan (group gnus-command-method)
+  "Request a SCAN being performed in GROUP from GNUS-COMMAND-METHOD.
+If GROUP is nil, all groups on GNUS-COMMAND-METHOD are scanned."
+  (let ((gnus-command-method
+        (if group (gnus-find-method-for-group group) gnus-command-method))
+       (gnus-inhibit-demon t)
+       (mail-source-plugged gnus-plugged))
+    (when (or gnus-plugged
+             (not (gnus-agent-method-p gnus-command-method)))
+      (setq gnus-internal-registry-spool-current-method gnus-command-method)
+      (funcall (gnus-get-function gnus-command-method 'request-scan)
+              (and group (gnus-group-real-name group))
+              (nth 1 gnus-command-method)))))
+
+(defun gnus-request-update-info (info gnus-command-method)
+  (when (gnus-check-backend-function
+        'request-update-info (car gnus-command-method))
+    (when (stringp gnus-command-method)
+      (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
+    (funcall (gnus-get-function gnus-command-method 'request-update-info)
+            (gnus-group-real-name (gnus-info-group info)) info
+            (nth 1 gnus-command-method))))
+
+(defsubst gnus-request-marks (info gnus-command-method)
+  "Request that GNUS-COMMAND-METHOD update INFO."
+  (when (stringp gnus-command-method)
+    (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
+  (when (gnus-check-backend-function
+        'request-marks (car gnus-command-method))
+    (let ((group (gnus-info-group info)))
+      (and (funcall (gnus-get-function gnus-command-method 'request-marks)
+                   (gnus-group-real-name group)
+                   info (nth 1 gnus-command-method))
+          ;; If the minimum article number is greater than 1, then all
+          ;; smaller article numbers are known not to exist; we'll
+          ;; artificially add those to the 'read range.
+          (let* ((active (gnus-active group))
+                 (min (car active)))
+            (when (> min 1)
+              (let* ((range (if (= min 2) 1 (cons 1 (1- min))))
+                     (read (gnus-info-read info))
+                     (new-read (gnus-range-add read (list range))))
+                (gnus-info-set-read info new-read)))
+            info)))))
+
+(defun gnus-request-expire-articles (articles group &optional force)
+  (let* ((gnus-command-method (gnus-find-method-for-group group))
+         ;; Filter out any negative article numbers; they can't be
+         ;; expired here.
+         (articles
+          (delq nil (mapcar (lambda (n) (and (>= n 0) n)) articles)))
+        (gnus-inhibit-demon t)
+        (not-deleted
+         (funcall
+          (gnus-get-function gnus-command-method 'request-expire-articles)
+          articles (gnus-group-real-name group) (nth 1 gnus-command-method)
+          force)))
+    (when (and gnus-agent
+              (gnus-agent-method-p gnus-command-method))
+      (let ((expired-articles (gnus-sorted-difference articles not-deleted)))
+        (when expired-articles
+          (gnus-agent-expire expired-articles group 'force))))
+    not-deleted))
+
+(defun gnus-request-move-article (article group server accept-function
+                                         &optional last move-is-internal)
+  (let* ((gnus-command-method (gnus-find-method-for-group group))
+        (result (funcall (gnus-get-function gnus-command-method
+                                            'request-move-article)
+                         article (gnus-group-real-name group)
+                         (nth 1 gnus-command-method) accept-function
+                         last move-is-internal)))
+    (when (and result gnus-agent
+              (gnus-agent-method-p gnus-command-method))
+      (gnus-agent-unfetch-articles group (list article)))
+    result))
+
+(defun gnus-request-accept-article (group &optional gnus-command-method last
+                                         no-encode)
+  (when (stringp gnus-command-method)
+    (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
+  (when (and (not gnus-command-method)
+            (stringp group))
+    (setq gnus-command-method (or (gnus-find-method-for-group group)
+                                  (gnus-group-name-to-method group))))
+  (goto-char (point-max))
+  ;; Make sure there's a newline at the end of the article.
+  (unless (bolp)
+    (insert "\n"))
+  (unless no-encode
+    (let ((message-options message-options))
+      (message-options-set-recipient)
+      (save-restriction
+       (message-narrow-to-head)
+       (let ((mail-parse-charset message-default-charset))
+         (mail-encode-encoded-word-buffer)))
+      (message-encode-message-body)))
+  (let ((gnus-command-method (or gnus-command-method
+                                (gnus-find-method-for-group group)))
+       (result
+        (funcall
+         (gnus-get-function gnus-command-method 'request-accept-article)
+         (if (stringp group) (gnus-group-real-name group) group)
+         (cadr gnus-command-method)
+         last)))
+    (when (and gnus-agent
+              (gnus-agent-method-p gnus-command-method)
+              (cdr result))
+      (gnus-agent-regenerate-group group (list (cdr result))))
+    result))
+
+(defun gnus-request-replace-article (article group buffer &optional no-encode)
+  (unless no-encode
+    (let ((message-options message-options))
+      (message-options-set-recipient)
+      (save-restriction
+       (message-narrow-to-head)
+       (let ((mail-parse-charset message-default-charset))
+         (mail-encode-encoded-word-buffer)))
+      (message-encode-message-body)))
+  (let* ((func (car (gnus-group-name-to-method group)))
+         (result (funcall (intern (format "%s-request-replace-article" func))
+                         article (gnus-group-real-name group) buffer)))
+    (when (and gnus-agent (gnus-agent-method-p gnus-command-method))
+      (gnus-agent-regenerate-group group (list article)))
+    result))
+
+(defun gnus-request-restore-buffer (article group)
+  "Request a new buffer restored to the state of ARTICLE."
+  (let ((gnus-command-method (gnus-find-method-for-group group)))
+    (funcall (gnus-get-function gnus-command-method 'request-restore-buffer)
+            article (gnus-group-real-name group)
+            (nth 1 gnus-command-method))))
+
+(defun gnus-request-create-group (group &optional gnus-command-method args)
+  (when (stringp gnus-command-method)
+    (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
+  (let ((gnus-command-method
+        (or gnus-command-method (gnus-find-method-for-group group))))
+    (funcall (gnus-get-function gnus-command-method 'request-create-group)
+            (gnus-group-real-name group) (nth 1 gnus-command-method) args)))
+
+(defun gnus-request-delete-group (group &optional force)
+  (let* ((gnus-command-method (gnus-find-method-for-group group))
+        (result
+         (funcall (gnus-get-function gnus-command-method 'request-delete-group)
+                  (gnus-group-real-name group) force (nth 1 gnus-command-method))))
+    (when result
+      (gnus-cache-delete-group group)
+      (gnus-agent-delete-group group))
+    result))
+
+(defun gnus-request-rename-group (group new-name)
+  (let* ((gnus-command-method (gnus-find-method-for-group group))
+        (result
+         (funcall (gnus-get-function gnus-command-method 'request-rename-group)
+                  (gnus-group-real-name group)
+                  (gnus-group-real-name new-name) (nth 1 gnus-command-method))))
+    (when result
+      (gnus-cache-rename-group group new-name)
+      (gnus-agent-rename-group group new-name))
+    result))
+
+(defun gnus-close-backends ()
+  ;; Send a close request to all backends that support such a request.
+  (let ((methods gnus-valid-select-methods)
+       (gnus-inhibit-demon t)
+       func gnus-command-method)
+    (while (setq gnus-command-method (pop methods))
+      (when (fboundp (setq func (intern
+                                (concat (car gnus-command-method)
+                                        "-request-close"))))
+       (funcall func)))))
+
+(defun gnus-asynchronous-p (gnus-command-method)
+  (let ((func (gnus-get-function gnus-command-method 'asynchronous-p t)))
+    (when (fboundp func)
+      (funcall func))))
+
+(defun gnus-remove-denial (gnus-command-method)
+  (when (stringp gnus-command-method)
+    (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
+  (let* ((elem (assoc gnus-command-method gnus-opened-servers))
+        (status (cadr elem)))
+    ;; If this hasn't been opened before, we add it to the list.
+    (when (eq status 'denied)
+      ;; Set the status of this server.
+      (setcar (cdr elem) 'closed))))
+
+(provide 'gnus-int)
+
+;;; gnus-int.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-kill.el b/xemacs-packages/gnus/lisp/gnus-kill.el
new file mode 100644 (file)
index 0000000..9c06d4b
--- /dev/null
@@ -0,0 +1,687 @@
+;;; gnus-kill.el --- kill commands for Gnus
+
+;; Copyright (C) 1995-2016 Free Software Foundation, Inc.
+
+;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
+;;     Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'gnus)
+(require 'gnus-art)
+(require 'gnus-range)
+
+(defcustom gnus-kill-file-mode-hook nil
+  "Hook for Gnus kill file mode."
+  :group 'gnus-score-kill
+  :type 'hook)
+
+(defcustom gnus-kill-expiry-days 7
+  "*Number of days before expiring unused kill file entries."
+  :group 'gnus-score-kill
+  :group 'gnus-score-expire
+  :type 'integer)
+
+(defcustom gnus-kill-save-kill-file nil
+  "*If non-nil, will save kill files after processing them."
+  :group 'gnus-score-kill
+  :type 'boolean)
+
+(defcustom gnus-winconf-kill-file nil
+  "What does this do, Lars?
+I don't know, Per."
+  :group 'gnus-score-kill
+  :type 'sexp)
+
+(defcustom gnus-kill-killed t
+  "*If non-nil, Gnus will apply kill files to already killed articles.
+If it is nil, Gnus will never apply kill files to articles that have
+already been through the scoring process, which might very well save lots
+of time."
+  :group 'gnus-score-kill
+  :type 'boolean)
+
+\f
+
+(defmacro gnus-raise (field expression level)
+  `(gnus-kill ,field ,expression
+             (function (gnus-summary-raise-score ,level)) t))
+
+(defmacro gnus-lower (field expression level)
+  `(gnus-kill ,field ,expression
+             (function (gnus-summary-raise-score (- ,level))) t))
+
+;;;
+;;; Gnus Kill File Mode
+;;;
+
+(defvar gnus-kill-file-mode-map
+  (let ((map (make-sparse-keymap)))
+    (set-keymap-parent map emacs-lisp-mode-map)
+    (gnus-define-keymap map
+      "\C-c\C-k\C-s" gnus-kill-file-kill-by-subject
+      "\C-c\C-k\C-a" gnus-kill-file-kill-by-author
+      "\C-c\C-k\C-t" gnus-kill-file-kill-by-thread
+      "\C-c\C-k\C-x" gnus-kill-file-kill-by-xref
+      "\C-c\C-a" gnus-kill-file-apply-buffer
+      "\C-c\C-e" gnus-kill-file-apply-last-sexp
+      "\C-c\C-c" gnus-kill-file-exit)
+    map))
+
+(define-derived-mode gnus-kill-file-mode emacs-lisp-mode "Kill"
+  "Major mode for editing kill files.
+
+If you are using this mode - you probably shouldn't.  Kill files
+perform badly and paint with a pretty broad brush.  Score files, on
+the other hand, are vastly faster (40x speedup) and give you more
+control over what to do.
+
+In addition to Emacs-Lisp Mode, the following commands are available:
+
+\\{gnus-kill-file-mode-map}
+
+  A kill file contains Lisp expressions to be applied to a selected
+newsgroup.  The purpose is to mark articles as read on the basis of
+some set of regexps.  A global kill file is applied to every newsgroup,
+and a local kill file is applied to a specified newsgroup.  Since a
+global kill file is applied to every newsgroup, for better performance
+use a local one.
+
+  A kill file can contain any kind of Emacs Lisp expressions expected
+to be evaluated in the Summary buffer.  Writing Lisp programs for this
+purpose is not so easy because the internal working of Gnus must be
+well-known.  For this reason, Gnus provides a general function which
+does this easily for non-Lisp programmers.
+
+  The `gnus-kill' function executes commands available in Summary Mode
+by their key sequences.  `gnus-kill' should be called with FIELD,
+REGEXP and optional COMMAND and ALL.  FIELD is a string representing
+the header field or an empty string.  If FIELD is an empty string, the
+entire article body is searched for.  REGEXP is a string which is
+compared with FIELD value.  COMMAND is a string representing a valid
+key sequence in Summary mode or Lisp expression.  COMMAND defaults to
+'(gnus-summary-mark-as-read nil \"X\").  Make sure that COMMAND is
+executed in the Summary buffer.  If the second optional argument ALL
+is non-nil, the COMMAND is applied to articles which are already
+marked as read or unread.  Articles which are marked are skipped over
+by default.
+
+  For example, if you want to mark articles of which subjects contain
+the string `AI' as read, a possible kill file may look like:
+
+       (gnus-kill \"Subject\" \"AI\")
+
+  If you want to mark articles with `D' instead of `X', you can use
+the following expression:
+
+       (gnus-kill \"Subject\" \"AI\" \"d\")
+
+In this example it is assumed that the command
+`gnus-summary-mark-as-read-forward' is assigned to `d' in Summary Mode.
+
+  It is possible to delete unnecessary headers which are marked with
+`X' in a kill file as follows:
+
+       (gnus-expunge \"X\")
+
+  If the Summary buffer is empty after applying kill files, Gnus will
+exit the selected newsgroup normally.  If headers which are marked
+with `D' are deleted in a kill file, it is impossible to read articles
+which are marked as read in the previous Gnus sessions.  Marks other
+than `D' should be used for articles which should really be deleted.
+
+Entry to this mode calls emacs-lisp-mode-hook and
+gnus-kill-file-mode-hook with no arguments, if that value is non-nil.")
+
+(defun gnus-kill-file-edit-file (newsgroup)
+  "Begin editing a kill file for NEWSGROUP.
+If NEWSGROUP is nil, the global kill file is selected."
+  (interactive "sNewsgroup: ")
+  (let ((file (gnus-newsgroup-kill-file newsgroup)))
+    (gnus-make-directory (file-name-directory file))
+    ;; Save current window configuration if this is first invocation.
+    (or (and (get-file-buffer file)
+            (get-buffer-window (get-file-buffer file)))
+       (setq gnus-winconf-kill-file (current-window-configuration)))
+    ;; Hack windows.
+    (let ((buffer (find-file-noselect file)))
+      (cond ((get-buffer-window buffer)
+            (pop-to-buffer buffer))
+           ((derived-mode-p 'gnus-group-mode)
+            (gnus-configure-windows 'group) ;Take all windows.
+            (pop-to-buffer buffer))
+           ((derived-mode-p 'gnus-summary-mode)
+            (gnus-configure-windows 'article)
+            (pop-to-buffer gnus-article-buffer)
+            (bury-buffer gnus-article-buffer)
+            (switch-to-buffer buffer))
+           (t                          ;No good rules.
+            (find-file-other-window file))))
+    (gnus-kill-file-mode)))
+
+;; Fix by Sudish Joseph <joseph@cis.ohio-state.edu>.
+(defun gnus-kill-set-kill-buffer ()
+  (let* ((file (gnus-newsgroup-kill-file gnus-newsgroup-name))
+        (buffer (find-file-noselect file)))
+    (set-buffer buffer)
+    (gnus-kill-file-mode)
+    (bury-buffer buffer)))
+
+(defun gnus-kill-file-enter-kill (field regexp &optional dont-move)
+  ;; Enter kill file entry.
+  ;; FIELD: String containing the name of the header field to kill.
+  ;; REGEXP: The string to kill.
+  (save-excursion
+    (let (string)
+      (unless (derived-mode-p 'gnus-kill-file-mode)
+       (gnus-kill-set-kill-buffer))
+      (unless dont-move
+       (goto-char (point-max)))
+      (insert (setq string (format "(gnus-kill %S %S)\n" field regexp)))
+      (gnus-kill-file-apply-string string))))
+
+(defun gnus-kill-file-kill-by-subject ()
+  "Kill by subject."
+  (interactive)
+  (gnus-kill-file-enter-kill
+   "Subject"
+   (if (vectorp gnus-current-headers)
+       (regexp-quote
+       (gnus-simplify-subject (mail-header-subject gnus-current-headers)))
+     "")
+   t))
+
+(defun gnus-kill-file-kill-by-author ()
+  "Kill by author."
+  (interactive)
+  (gnus-kill-file-enter-kill
+   "From"
+   (if (vectorp gnus-current-headers)
+       (regexp-quote (mail-header-from gnus-current-headers))
+     "") t))
+
+(defun gnus-kill-file-kill-by-thread ()
+  "Kill by author."
+  (interactive)
+  (gnus-kill-file-enter-kill
+   "References"
+   (if (vectorp gnus-current-headers)
+       (regexp-quote (mail-header-id gnus-current-headers))
+     "")))
+
+(defun gnus-kill-file-kill-by-xref ()
+  "Kill by Xref."
+  (interactive)
+  (let ((xref (and (vectorp gnus-current-headers)
+                  (mail-header-xref gnus-current-headers)))
+       (start 0)
+       group)
+    (if xref
+       (while (string-match " \\([^ \t]+\\):" xref start)
+         (setq start (match-end 0))
+         (when (not (string=
+                     (setq group
+                           (substring xref (match-beginning 1) (match-end 1)))
+                     gnus-newsgroup-name))
+           (gnus-kill-file-enter-kill
+            "Xref" (concat " " (regexp-quote group) ":") t)))
+      (gnus-kill-file-enter-kill "Xref" "" t))))
+
+(defun gnus-kill-file-raise-followups-to-author (level)
+  "Raise score for all followups to the current author."
+  (interactive "p")
+  (let ((name (mail-header-from gnus-current-headers))
+       string)
+    (save-excursion
+      (gnus-kill-set-kill-buffer)
+      (goto-char (point-min))
+      (setq name (read-string (concat "Add " level
+                                     " to followup articles to: ")
+                             (regexp-quote name)))
+      (setq
+       string
+       (format
+       "(gnus-kill %S %S '(gnus-summary-temporarily-raise-by-thread %S))\n"
+       "From" name level))
+      (insert string)
+      (gnus-kill-file-apply-string string))
+    (gnus-message
+     6 "Added temporary score file entry for followups to %s." name)))
+
+(defun gnus-kill-file-apply-buffer ()
+  "Apply current buffer to current newsgroup."
+  (interactive)
+  (if (and gnus-current-kill-article
+          (get-buffer gnus-summary-buffer))
+      ;; Assume newsgroup is selected.
+      (gnus-kill-file-apply-string (buffer-string))
+    (ding) (gnus-message 2 "No newsgroup is selected.")))
+
+(defun gnus-kill-file-apply-string (string)
+  "Apply STRING to current newsgroup."
+  (interactive)
+  (let ((string (concat "(progn \n" string "\n)")))
+    (save-excursion
+      (save-window-excursion
+       (pop-to-buffer gnus-summary-buffer)
+       (eval (car (read-from-string string)))))))
+
+(defun gnus-kill-file-apply-last-sexp ()
+  "Apply sexp before point in current buffer to current newsgroup."
+  (interactive)
+  (if (and gnus-current-kill-article
+          (get-buffer gnus-summary-buffer))
+      ;; Assume newsgroup is selected.
+      (let ((string
+            (buffer-substring
+             (save-excursion (forward-sexp -1) (point)) (point))))
+       (save-excursion
+         (save-window-excursion
+           (pop-to-buffer gnus-summary-buffer)
+           (eval (car (read-from-string string))))))
+    (ding) (gnus-message 2 "No newsgroup is selected.")))
+
+(defun gnus-kill-file-exit ()
+  "Save a kill file, then return to the previous buffer."
+  (interactive)
+  (save-buffer)
+  (let ((killbuf (current-buffer)))
+    ;; We don't want to return to article buffer.
+    (when (get-buffer gnus-article-buffer)
+      (bury-buffer gnus-article-buffer))
+    ;; Delete the KILL file windows.
+    (delete-windows-on killbuf)
+    ;; Restore last window configuration if available.
+    (when gnus-winconf-kill-file
+      (set-window-configuration gnus-winconf-kill-file))
+    (setq gnus-winconf-kill-file nil)
+    ;; Kill the KILL file buffer.  Suggested by tale@pawl.rpi.edu.
+    (kill-buffer killbuf)))
+
+;; For kill files
+
+(defun gnus-expunge (marks)
+  "Remove lines marked with MARKS."
+  (with-current-buffer gnus-summary-buffer
+    (gnus-summary-limit-to-marks marks 'reverse)))
+
+(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))
+          (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)))
+
+(defun gnus-apply-kill-file-internal ()
+  "Apply a kill file to the current newsgroup.
+Returns the number of articles marked as read."
+  (let* ((kill-files (list (gnus-newsgroup-kill-file nil)
+                          (gnus-newsgroup-kill-file gnus-newsgroup-name)))
+        (unreads (length gnus-newsgroup-unreads))
+        (gnus-summary-inhibit-highlight t)
+        beg)
+    (setq gnus-newsgroup-kill-headers nil)
+    ;; If there are any previously scored articles, we remove these
+    ;; from the `gnus-newsgroup-headers' list that the score functions
+    ;; will see.  This is probably pretty wasteful when it comes to
+    ;; conses, but is, I think, faster than having to assq in every
+    ;; single score function.
+    (let ((files kill-files))
+      (while files
+       (if (file-exists-p (car files))
+           (let ((headers gnus-newsgroup-headers))
+             (if gnus-kill-killed
+                 (setq gnus-newsgroup-kill-headers
+                       (mapcar (lambda (header) (mail-header-number header))
+                               headers))
+               (while headers
+                 (unless (gnus-member-of-range
+                          (mail-header-number (car headers))
+                          gnus-newsgroup-killed)
+                   (push (mail-header-number (car headers))
+                         gnus-newsgroup-kill-headers))
+                 (setq headers (cdr headers))))
+             (setq files nil))
+         (setq files (cdr files)))))
+    (if (not gnus-newsgroup-kill-headers)
+       ()
+      (save-window-excursion
+       (save-excursion
+         (while kill-files
+           (if (not (file-exists-p (car kill-files)))
+               ()
+             (gnus-message 6 "Processing kill file %s..." (car kill-files))
+             (find-file (car kill-files))
+             (goto-char (point-min))
+
+             (if (consp (ignore-errors (read (current-buffer))))
+                 (gnus-kill-parse-gnus-kill-file)
+               (gnus-kill-parse-rn-kill-file))
+
+             (gnus-message
+              6 "Processing kill file %s...done" (car kill-files)))
+           (setq kill-files (cdr kill-files)))))
+
+      (gnus-set-mode-line 'summary)
+
+      (if beg
+         (let ((nunreads (- unreads (length gnus-newsgroup-unreads))))
+           (or (eq nunreads 0)
+               (gnus-message 6 "Marked %d articles as read" nunreads))
+           nunreads)
+       0))))
+
+;; Parse a Gnus killfile.
+(defun gnus-kill-parse-gnus-kill-file ()
+  (goto-char (point-min))
+  (gnus-kill-file-mode)
+  (let (beg form)
+    (while (progn
+            (setq beg (point))
+            (setq form (ignore-errors (read (current-buffer)))))
+      (unless (listp form)
+       (error "Invalid kill entry (possibly rn kill file?): %s" form))
+      (if (or (eq (car form) 'gnus-kill)
+             (eq (car form) 'gnus-raise)
+             (eq (car form) 'gnus-lower))
+         (progn
+           (delete-region beg (point))
+           (insert (or (eval form) "")))
+       (with-current-buffer gnus-summary-buffer
+         (ignore-errors (eval form)))))
+    (and (buffer-modified-p)
+        gnus-kill-save-kill-file
+        (save-buffer))
+    (set-buffer-modified-p nil)))
+
+;; Parse an rn killfile.
+(defun gnus-kill-parse-rn-kill-file ()
+  (goto-char (point-min))
+  (gnus-kill-file-mode)
+  (let ((mod-to-header
+        '((?a . "")
+          (?h . "")
+          (?f . "from")
+          (?: . "subject")))
+       ;;(com-to-com
+       ;; '((?m . " ")
+       ;;   (?j . "X")))
+       pattern modifier commands)
+    (while (not (eobp))
+      (if (not (looking-at "[ \t]*/\\([^/]*\\)/\\([ahfcH]\\)?:\\([a-z=:]*\\)"))
+         ()
+       (setq pattern (buffer-substring (match-beginning 1) (match-end 1)))
+       (setq modifier (if (match-beginning 2) (char-after (match-beginning 2))
+                        ?s))
+       (setq commands (buffer-substring (match-beginning 3) (match-end 3)))
+
+       ;; The "f:+" command marks everything *but* the matches as read,
+       ;; so we simply first match everything as read, and then unmark
+       ;; PATTERN later.
+       (when (string-match "\\+" commands)
+         (gnus-kill "from" ".")
+         (setq commands "m"))
+
+       (gnus-kill
+        (or (cdr (assq modifier mod-to-header)) "subject")
+        pattern
+        (if (string-match "m" commands)
+            '(gnus-summary-tick-article nil " ")
+          '(gnus-summary-mark-as-read nil "X"))
+        nil t))
+      (forward-line 1))))
+
+;; Kill changes and new format by suggested by JWZ and Sudish Joseph
+;; <joseph@cis.ohio-state.edu>.
+(defun gnus-kill (field regexp &optional exe-command all silent)
+  "If FIELD of an article matches REGEXP, execute COMMAND.
+Optional 1st argument COMMAND is default to
+       (gnus-summary-mark-as-read nil \"X\").
+If optional 2nd argument ALL is non-nil, articles marked are also applied to.
+If FIELD is an empty string (or nil), entire article body is searched for.
+COMMAND must be a Lisp expression or a string representing a key sequence."
+  ;; We don't want to change current point nor window configuration.
+  (let ((old-buffer (current-buffer)))
+    (save-excursion
+      (save-window-excursion
+       ;; Selected window must be summary buffer to execute keyboard
+       ;; macros correctly.  See command_loop_1.
+       (switch-to-buffer gnus-summary-buffer 'norecord)
+       (goto-char (point-min))         ;From the beginning.
+       (let ((kill-list regexp)
+             (date (current-time-string))
+             (command (or exe-command '(gnus-summary-mark-as-read
+                                        nil gnus-kill-file-mark)))
+             kill kdate prev)
+         (if (listp kill-list)
+             ;; It is a list.
+             (if (not (consp (cdr kill-list)))
+                 ;; It's of the form (regexp . date).
+                 (if (zerop (gnus-execute field (car kill-list)
+                                          command nil (not all)))
+                     (when (> (days-between date (cdr kill-list))
+                              gnus-kill-expiry-days)
+                       (setq regexp nil))
+                   (setcdr kill-list date))
+               (while (setq kill (car kill-list))
+                 (if (consp kill)
+                     ;; It's a temporary kill.
+                     (progn
+                       (setq kdate (cdr kill))
+                       (if (zerop (gnus-execute
+                                   field (car kill) command nil (not all)))
+                           (when (> (days-between date kdate)
+                                    gnus-kill-expiry-days)
+                             ;; Time limit has been exceeded, so we
+                             ;; remove the match.
+                             (if prev
+                                 (setcdr prev (cdr kill-list))
+                               (setq regexp (cdr regexp))))
+                         ;; Successful kill.  Set the date to today.
+                         (setcdr kill date)))
+                   ;; It's a permanent kill.
+                   (gnus-execute field kill command nil (not all)))
+                 (setq prev kill-list)
+                 (setq kill-list (cdr kill-list))))
+           (gnus-execute field kill-list command nil (not all))))))
+    (switch-to-buffer old-buffer)
+    (when (and (derived-mode-p 'gnus-kill-file-mode) regexp (not silent))
+      (gnus-pp-gnus-kill
+       (nconc (list 'gnus-kill field
+                   (if (consp regexp) (list 'quote regexp) regexp))
+             (when (or exe-command all)
+               (list (list 'quote exe-command)))
+             (if all (list t) nil))))))
+
+(defun gnus-pp-gnus-kill (object)
+  (if (or (not (consp (nth 2 object)))
+         (not (consp (cdr (nth 2 object))))
+         (and (eq 'quote (car (nth 2 object)))
+              (not (consp (cdadr (nth 2 object))))))
+      (concat "\n" (gnus-prin1-to-string object))
+    (with-current-buffer (gnus-get-buffer-create "*Gnus PP*")
+      (buffer-disable-undo)
+      (erase-buffer)
+      (insert (format "\n(%S %S\n  '(" (nth 0 object) (nth 1 object)))
+      (let ((klist (cadr (nth 2 object)))
+           (first t))
+       (while klist
+         (insert (if first (progn (setq first nil) "")  "\n    ")
+                 (gnus-prin1-to-string (car klist)))
+         (setq klist (cdr klist))))
+      (insert ")")
+      (and (nth 3 object)
+          (insert "\n  "
+                  (if (and (consp (nth 3 object))
+                           (not (eq 'quote (car (nth 3 object)))))
+                      "'" "")
+                  (gnus-prin1-to-string (nth 3 object))))
+      (when (nth 4 object)
+       (insert "\n  t"))
+      (insert ")")
+      (prog1
+         (buffer-string)
+       (kill-buffer (current-buffer))))))
+
+(defun gnus-execute-1 (function regexp form header)
+  (save-excursion
+    (let (did-kill)
+      (if (null header)
+         nil                           ;Nothing to do.
+       (if function
+           ;; Compare with header field.
+           (let (value)
+             (and header
+                  (progn
+                    (setq value (funcall function header))
+                    ;; Number (Lines:) or symbol must be converted to string.
+                    (unless (stringp value)
+                      (setq value (gnus-prin1-to-string value)))
+                    (setq did-kill (string-match regexp value)))
+                  (cond ((stringp form) ;Keyboard macro.
+                         (execute-kbd-macro form))
+                        ((functionp form)
+                         (funcall form))
+                        (t
+                         (eval form)))))
+         ;; Search article body.
+         (let ((gnus-current-article nil) ;Save article pointer.
+               (gnus-last-article nil)
+               (gnus-break-pages nil)  ;No need to break pages.
+               (gnus-mark-article-hook nil)) ;Inhibit marking as read.
+           (gnus-message
+            6 "Searching for article: %d..." (mail-header-number header))
+           (gnus-article-setup-buffer)
+           (gnus-article-prepare (mail-header-number header) t)
+           (when (with-current-buffer gnus-article-buffer
+                   (goto-char (point-min))
+                   (setq did-kill (re-search-forward regexp nil t)))
+             (cond ((stringp form)     ;Keyboard macro.
+                    (execute-kbd-macro form))
+                   ((functionp form)
+                    (funcall form))
+                   (t
+                    (eval form)))))))
+      did-kill)))
+
+(defun gnus-execute (field regexp form &optional backward unread)
+  "If FIELD of article header matches REGEXP, execute Lisp FORM (or a string).
+If FIELD is an empty string (or nil), entire article body is searched for.
+If optional 1st argument BACKWARD is non-nil, do backward instead.
+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 extras)
+      (cond
+       ;; Search body.
+       ((or (null field)
+           (string-equal field ""))
+       (setq function nil))
+       ;; Get access function of header field.
+       ((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)))
+      ;; Starting from the current article.
+      (while (or
+             ;; First article.
+             (and (not article)
+                  (setq article (gnus-summary-article-number)))
+             ;; Find later articles.
+             (setq article
+                   (gnus-summary-search-forward unread nil backward)))
+       (and (or (null gnus-newsgroup-kill-headers)
+                (memq article gnus-newsgroup-kill-headers))
+            (vectorp (setq header (gnus-summary-article-header article)))
+            (gnus-execute-1 function regexp form header)
+            (setq killed-no (1+ killed-no))))
+      ;; Return the number of killed articles.
+      killed-no)))
+
+;;;###autoload
+(defalias 'gnus-batch-kill 'gnus-batch-score)
+;;;###autoload
+(defun gnus-batch-score ()
+  "Run batched scoring.
+Usage: emacs -batch -l ~/.emacs -l gnus -f gnus-batch-score"
+  (interactive)
+  (let* ((gnus-newsrc-options-n
+         (gnus-newsrc-parse-options
+          (concat "options -n "
+                  (mapconcat 'identity command-line-args-left " "))))
+        (gnus-expert-user t)
+        (mail-sources nil)
+        (gnus-use-dribble-file nil)
+        (gnus-batch-mode t)
+        info group newsrc unread
+        ;; Disable verbose message.
+        gnus-novice-user gnus-large-newsgroup
+        gnus-options-subscribe gnus-auto-subscribed-groups
+        gnus-options-not-subscribe)
+    ;; Eat all arguments.
+    (setq command-line-args-left nil)
+    (gnus-slave)
+    ;; Apply kills to specified newsgroups in command line arguments.
+    (setq newsrc (cdr gnus-newsrc-alist))
+    (while (setq info (pop newsrc))
+      (setq group (gnus-info-group info)
+           unread (gnus-group-unread group))
+      (when (and (<= (gnus-info-level info) gnus-level-subscribed)
+                (and unread
+                     (or (eq unread t)
+                         (not (zerop unread)))))
+       (ignore-errors
+         (gnus-summary-read-group group nil t nil t))
+       (when (eq (current-buffer) (get-buffer gnus-summary-buffer))
+         (gnus-summary-exit))))
+    ;; Exit Emacs.
+    (switch-to-buffer gnus-group-buffer)
+    (gnus-group-save-newsrc)))
+
+(provide 'gnus-kill)
+
+;;; gnus-kill.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-logic.el b/xemacs-packages/gnus/lisp/gnus-logic.el
new file mode 100644 (file)
index 0000000..2065d0b
--- /dev/null
@@ -0,0 +1,232 @@
+;;; gnus-logic.el --- advanced scoring code for Gnus
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'gnus)
+(require 'gnus-score)
+(require 'gnus-util)
+
+;;; Internal variables.
+
+(defvar gnus-advanced-headers nil)
+
+;; To avoid having 8-bit characters in the source file.
+(defvar gnus-advanced-not (intern (format "%c" 172)))
+
+(defconst gnus-advanced-index
+  ;; Name to index alist.
+  '(("number" 0 gnus-advanced-integer)
+    ("subject" 1 gnus-advanced-string)
+    ("from" 2 gnus-advanced-string)
+    ("date" 3 gnus-advanced-date)
+    ("message-id" 4 gnus-advanced-string)
+    ("references" 5 gnus-advanced-string)
+    ("chars" 6 gnus-advanced-integer)
+    ("lines" 7 gnus-advanced-integer)
+    ("xref" 8 gnus-advanced-string)
+    ("head" nil gnus-advanced-body)
+    ("body" nil gnus-advanced-body)
+    ("all" nil gnus-advanced-body)))
+
+(autoload 'parse-time-string "parse-time")
+
+(defun gnus-score-advanced (rule &optional trace)
+  "Apply advanced scoring RULE to all the articles in the current group."
+  (let (new-score score multiple)
+    (dolist (gnus-advanced-headers gnus-newsgroup-headers)
+      (when (setq multiple (gnus-advanced-score-rule (car rule)))
+       (setq new-score (or (nth 1 rule)
+                           gnus-score-interactive-default-score))
+       (when (numberp multiple)
+         (setq new-score (* multiple new-score)))
+       ;; This rule was successful, so we add the score to this
+       ;; article.
+       (if (setq score (assq (mail-header-number gnus-advanced-headers)
+                             gnus-newsgroup-scored))
+           (setcdr score
+                   (+ (cdr score) new-score))
+         (push (cons (mail-header-number gnus-advanced-headers)
+                     new-score)
+               gnus-newsgroup-scored)
+         (when trace
+           (push (cons "A file" rule)
+                 ;; Must be synced with `gnus-score-edit-file-at-point'.
+                 gnus-score-trace)))))))
+
+(defun gnus-advanced-score-rule (rule)
+  "Apply RULE to `gnus-advanced-headers'."
+  (let ((type (car rule)))
+    (cond
+     ;; "And" rule.
+     ((or (eq type '&) (eq type 'and))
+      (pop rule)
+      (if (not rule)
+         t                             ; Empty rule is true.
+       (while (and rule
+                   (gnus-advanced-score-rule (car rule)))
+         (pop rule))
+       ;; If all the rules were true, then `rule' should be nil.
+       (not rule)))
+     ;; "Or" rule.
+     ((or (eq type '|) (eq type 'or))
+      (pop rule)
+      (if (not rule)
+         nil
+       (while (and rule
+                   (not (gnus-advanced-score-rule (car rule))))
+         (pop rule))
+       ;; If one of the rules returned true, then `rule' should be non-nil.
+       rule))
+     ;; "Not" rule.
+     ((or (eq type '!) (eq type 'not) (eq type gnus-advanced-not))
+      (not (gnus-advanced-score-rule (nth 1 rule))))
+     ;; This is a `1-'-type redirection rule.
+     ((and (symbolp type)
+          (string-match "^[0-9]+-$\\|^\\^+$" (symbol-name type)))
+      (let ((gnus-advanced-headers
+            (gnus-parent-headers
+             gnus-advanced-headers
+             (if (string-match "^\\([0-9]+\\)-$" (symbol-name type))
+                 ;; 1- type redirection.
+                 (string-to-number
+                  (substring (symbol-name type)
+                             (match-beginning 1) (match-end 1)))
+               ;; ^^^ type redirection.
+               (length (symbol-name type))))))
+       (when gnus-advanced-headers
+         (gnus-advanced-score-rule (nth 1 rule)))))
+     ;; Plain scoring rule.
+     ((stringp type)
+      (gnus-advanced-score-article rule))
+     ;; Bug-out time!
+     (t
+      (error "Unknown advanced score type: %s" rule)))))
+
+(defun gnus-advanced-score-article (rule)
+  ;; `rule' is a semi-normal score rule, so we find out what function
+  ;; that's supposed to do the actual processing.
+  (let* ((header (car rule))
+        (func (assoc (downcase header) gnus-advanced-index)))
+    (if (not func)
+       (error "No such header: %s" rule)
+      ;; Call the score function.
+      (funcall (caddr func) (or (cadr func) header)
+              (cadr rule) (caddr rule)))))
+
+(defun gnus-advanced-string (index match type)
+  "See whether string MATCH of TYPE matches `gnus-advanced-headers' in INDEX."
+  (let* ((type (or type 's))
+        (case-fold-search (not (eq (downcase (symbol-name type))
+                                   (symbol-name type))))
+        (header (or (aref gnus-advanced-headers index) "")))
+    (cond
+     ((memq type '(r R regexp Regexp))
+      (string-match match header))
+     ((memq type '(s S string String))
+      (string-match (regexp-quote match) header))
+     ((memq type '(e E exact Exact))
+      (string= match header))
+     ((memq type '(f F fuzzy Fuzzy))
+      (string-match (regexp-quote (gnus-simplify-subject-fuzzy match))
+                   header))
+     (t
+      (error "No such string match type: %s" type)))))
+
+(defun gnus-advanced-integer (index match type)
+  (if (not (memq type '(< > <= >= =)))
+      (error "No such integer score type: %s" type)
+    (funcall type (or (aref gnus-advanced-headers index) 0) match)))
+
+(defun gnus-advanced-date (index match type)
+  (let ((date (apply 'encode-time (parse-time-string
+                                  (aref gnus-advanced-headers index))))
+       (match (apply 'encode-time (parse-time-string match))))
+    (cond
+     ((eq type 'at)
+      (equal date match))
+     ((eq type 'before)
+      (time-less-p match date))
+     ((eq type 'after)
+      (time-less-p date match))
+     (t
+      (error "No such date score type: %s" type)))))
+
+(defun gnus-advanced-body (header match type)
+  (when (string= header "all")
+    (setq header "article"))
+  (with-current-buffer nntp-server-buffer
+    (let* ((request-func (cond ((string= "head" header)
+                                'gnus-request-head)
+                               ((string= "body" header)
+                                'gnus-request-body)
+                               (t 'gnus-request-article)))
+           ofunc article handles)
+      ;; Not all backends support partial fetching.  In that case, we
+      ;; just fetch the entire article.
+      ;; When scoring by body, we need to peek at the headers to detect the
+      ;; content encoding
+      (unless (or (gnus-check-backend-function
+                   (intern (concat "request-" header))
+                   gnus-newsgroup-name)
+                  (string= "body" header))
+        (setq ofunc request-func)
+        (setq request-func 'gnus-request-article))
+      (setq article (mail-header-number gnus-advanced-headers))
+      (gnus-message 7 "Scoring article %s..." article)
+      (when (funcall request-func article gnus-newsgroup-name)
+        (when (string= "body" header)
+          (setq handles (gnus-score-decode-text-parts)))
+        (goto-char (point-min))
+        ;; If just parts of the article is to be searched and the
+        ;; backend didn't support partial fetching, we just narrow to
+        ;; the relevant parts.
+        (when ofunc
+          (if (eq ofunc 'gnus-request-head)
+              (narrow-to-region
+               (point)
+               (or (search-forward "\n\n" nil t) (point-max)))
+            (narrow-to-region
+             (or (search-forward "\n\n" nil t) (point))
+             (point-max))))
+        (let* ((case-fold-search (not (eq (downcase (symbol-name type))
+                                          (symbol-name type))))
+               (search-func
+                (cond ((memq type '(r R regexp Regexp))
+                       're-search-forward)
+                      ((memq type '(s S string String))
+                       'search-forward)
+                      (t
+                       (error "Invalid match type: %s" type)))))
+          (goto-char (point-min))
+          (prog1
+              (funcall search-func match nil t)
+            (widen)))
+        (when handles (mm-destroy-parts handles))))))
+
+(provide 'gnus-logic)
+
+;;; gnus-logic.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-mh.el b/xemacs-packages/gnus/lisp/gnus-mh.el
new file mode 100644 (file)
index 0000000..f01811b
--- /dev/null
@@ -0,0 +1,111 @@
+;;; gnus-mh.el --- mh-e interface for Gnus
+
+;; Copyright (C) 1994-2016 Free Software Foundation, Inc.
+
+;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
+;;     Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Send mail using mh-e.
+
+;; The following mh-e interface is all cooperative works of
+;; tanaka@flab.fujitsu.CO.JP (TANAKA Hiroshi), kawabe@sra.CO.JP
+;; (Yoshikatsu Kawabe), and shingu@casund.cpr.canon.co.jp (Toshiaki
+;; SHINGU).
+
+;;; Code:
+
+(require 'gnus)
+(require 'mh-e)
+(require 'mh-comp)
+(require 'gnus-msg)
+(require 'gnus-sum)
+
+(defvar mh-lib-progs)
+
+(defun gnus-summary-save-article-folder (&optional arg)
+  "Append the current article to an mh folder.
+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-save-in-folder))
+    (gnus-summary-save-article arg)))
+
+(defun gnus-summary-save-in-folder (&optional folder)
+  "Save this article to MH folder (using `rcvstore' in MH library).
+Optional argument FOLDER specifies folder name."
+  ;; Thanks to yuki@flab.Fujitsu.JUNET and ohm@kaba.junet.
+  (mh-find-path)
+  (let ((folder
+        (cond ((and (eq folder 'default)
+                    gnus-newsgroup-last-folder)
+               gnus-newsgroup-last-folder)
+              (folder folder)
+              (t (mh-prompt-for-folder
+                  "Save article in"
+                  (funcall gnus-folder-save-name gnus-newsgroup-name
+                           gnus-current-headers gnus-newsgroup-last-folder)
+                  t))))
+       (errbuf (gnus-get-buffer-create " *Gnus rcvstore*"))
+       ;; Find the rcvstore program.
+       (exec-path (cond
+                   ((and (boundp 'mh-lib-progs) mh-lib-progs)
+                    (cons mh-lib-progs exec-path))
+                   (mh-lib (cons mh-lib exec-path))
+                   (t exec-path))))
+    (with-current-buffer gnus-original-article-buffer
+      (save-restriction
+       (widen)
+       (unwind-protect
+           (call-process-region
+            (point-min) (point-max) "rcvstore" nil errbuf nil folder)
+         (set-buffer errbuf)
+         (if (zerop (buffer-size))
+             (message "Article saved in folder: %s" folder)
+           (message "%s" (buffer-string)))
+         (kill-buffer errbuf))))
+    (setq gnus-newsgroup-last-folder folder)))
+
+(defun gnus-Folder-save-name (newsgroup headers &optional last-folder)
+  "Generate folder name from NEWSGROUP, HEADERS, and optional LAST-FOLDER.
+If variable `gnus-use-long-file-name' is nil, it is +News.group.
+Otherwise, it is like +news/group."
+  (or last-folder
+      (concat "+"
+             (if gnus-use-long-file-name
+                 (gnus-capitalize-newsgroup newsgroup)
+               (gnus-newsgroup-directory-form newsgroup)))))
+
+(defun gnus-folder-save-name (newsgroup headers &optional last-folder)
+  "Generate folder name from NEWSGROUP, HEADERS, and optional LAST-FOLDER.
+If variable `gnus-use-long-file-name' is nil, it is +news.group.
+Otherwise, it is like +news/group."
+  (or last-folder
+      (concat "+"
+             (if gnus-use-long-file-name
+                 newsgroup
+               (gnus-newsgroup-directory-form newsgroup)))))
+
+(provide 'gnus-mh)
+
+;;; gnus-mh.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-ml.el b/xemacs-packages/gnus/lisp/gnus-ml.el
new file mode 100644 (file)
index 0000000..8ff3616
--- /dev/null
@@ -0,0 +1,182 @@
+;;; gnus-ml.el --- Mailing list minor mode for Gnus
+
+;; Copyright (C) 2000-2016 Free Software Foundation, Inc.
+
+;; Author: Julien Gilles  <jgilles@free.fr>
+;; Keywords: news, mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; implement (small subset of) RFC 2369
+
+;;; Code:
+
+(require 'gnus)
+(require 'gnus-msg)
+(eval-when-compile (require 'cl))
+(eval-when-compile
+  (when (featurep 'xemacs)
+    (require 'easy-mmode))) ; for `define-minor-mode'
+
+;;; Mailing list minor mode
+
+(defvar gnus-mailing-list-mode-map
+  (let ((map (make-sparse-keymap)))
+    (gnus-define-keys map
+      "\C-c\C-nh" gnus-mailing-list-help
+      "\C-c\C-ns" gnus-mailing-list-subscribe
+      "\C-c\C-nu" gnus-mailing-list-unsubscribe
+      "\C-c\C-np" gnus-mailing-list-post
+      "\C-c\C-no" gnus-mailing-list-owner
+      "\C-c\C-na" gnus-mailing-list-archive)
+    map))
+
+(defvar gnus-mailing-list-menu)
+
+(defun gnus-mailing-list-make-menu-bar ()
+  (unless (boundp 'gnus-mailing-list-menu)
+    (easy-menu-define
+     gnus-mailing-list-menu gnus-mailing-list-mode-map ""
+     '("Mailing-Lists"
+       ["Get help" gnus-mailing-list-help t]
+       ["Subscribe" gnus-mailing-list-subscribe t]
+       ["Unsubscribe" gnus-mailing-list-unsubscribe t]
+       ["Post a message" gnus-mailing-list-post t]
+       ["Mail to owner" gnus-mailing-list-owner t]
+       ["Browse archive" gnus-mailing-list-archive t]))))
+
+;;;###autoload
+(defun turn-on-gnus-mailing-list-mode ()
+  (when (gnus-group-find-parameter gnus-newsgroup-name 'to-list)
+    (gnus-mailing-list-mode 1)))
+
+;;;###autoload
+(defun gnus-mailing-list-insinuate (&optional force)
+  "Setup group parameters from List-Post header.
+If FORCE is non-nil, replace the old ones."
+  (interactive "P")
+  (let ((list-post
+        (with-current-buffer gnus-original-article-buffer
+          (gnus-fetch-field "list-post"))))
+    (if list-post
+       (if (and (not force)
+                (gnus-group-get-parameter gnus-newsgroup-name 'to-list))
+           (gnus-message 1 "to-list is non-nil.")
+         (if (string-match "<mailto:\\([^>]*\\)>" list-post)
+             (setq list-post (match-string 1 list-post)))
+         (gnus-group-add-parameter gnus-newsgroup-name
+                                   (cons 'to-list list-post))
+         (gnus-mailing-list-mode 1))
+      (gnus-message 1 "no list-post in this message."))))
+
+(eval-when-compile
+  (when (featurep 'xemacs)
+    (defvar gnus-mailing-list-mode-hook)
+    (defvar gnus-mailing-list-mode-on-hook)
+    (defvar gnus-mailing-list-mode-off-hook)))
+
+;;;###autoload
+(define-minor-mode gnus-mailing-list-mode
+  "Minor mode for providing mailing-list commands.
+
+\\{gnus-mailing-list-mode-map}"
+  :lighter " Mailing-List"
+  :keymap gnus-mailing-list-mode-map
+  (cond
+   ((not (derived-mode-p 'gnus-summary-mode))
+    (setq gnus-mailing-list-mode nil))
+   (gnus-mailing-list-mode
+    ;; Set up the menu.
+    (when (gnus-visual-p 'mailing-list-menu 'menu)
+      (gnus-mailing-list-make-menu-bar)))))
+
+;;; Commands
+
+(defun gnus-mailing-list-help ()
+  "Get help from mailing list server."
+  (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))
+         (t (gnus-message 1 "no list-help in this group")))))
+
+(defun gnus-mailing-list-subscribe ()
+  "Subscribe to mailing list."
+  (interactive)
+  (let ((list-subscribe
+        (with-current-buffer gnus-original-article-buffer
+          (gnus-fetch-field "list-subscribe"))))
+    (cond (list-subscribe (gnus-mailing-list-message list-subscribe))
+         (t (gnus-message 1 "no list-subscribe in this group")))))
+
+(defun gnus-mailing-list-unsubscribe ()
+  "Unsubscribe from mailing list."
+  (interactive)
+  (let ((list-unsubscribe
+        (with-current-buffer gnus-original-article-buffer
+          (gnus-fetch-field "list-unsubscribe"))))
+    (cond (list-unsubscribe (gnus-mailing-list-message list-unsubscribe))
+         (t (gnus-message 1 "no list-unsubscribe in this group")))))
+
+(defun gnus-mailing-list-post ()
+  "Post message (really useful ?)"
+  (interactive)
+  (let ((list-post
+        (with-current-buffer gnus-original-article-buffer
+          (gnus-fetch-field "list-post"))))
+    (cond (list-post (gnus-mailing-list-message list-post))
+         (t (gnus-message 1 "no list-post in this group")))))
+
+(defun gnus-mailing-list-owner ()
+  "Mail to the mailing list owner."
+  (interactive)
+  (let ((list-owner
+        (with-current-buffer gnus-original-article-buffer
+          (gnus-fetch-field "list-owner"))))
+    (cond (list-owner (gnus-mailing-list-message list-owner))
+         (t (gnus-message 1 "no list-owner in this group")))))
+
+(defun gnus-mailing-list-archive ()
+  "Browse archive."
+  (interactive)
+  (require 'browse-url)
+  (let ((list-archive
+        (with-current-buffer gnus-original-article-buffer
+          (gnus-fetch-field "list-archive"))))
+    (cond (list-archive
+          (if (string-match "<\\(http:[^>]*\\)>" list-archive)
+              (browse-url (match-string 1 list-archive))
+            (browse-url list-archive)))
+         (t (gnus-message 1 "no list-archive in this group")))))
+
+;;; Utility functions
+
+(defun gnus-mailing-list-message (address)
+  "Send message to ADDRESS.
+ADDRESS is specified by a \"mailto:\" URL."
+  (cond
+   ((string-match "<\\(mailto:[^>]*\\)>" address)
+    (require 'gnus-art)
+    (gnus-url-mailto (match-string 1 address)))
+   ;; other case <http://...> to be done.
+   (t nil)))
+
+(provide 'gnus-ml)
+
+;;; gnus-ml.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-mlspl.el b/xemacs-packages/gnus/lisp/gnus-mlspl.el
new file mode 100644 (file)
index 0000000..4560002
--- /dev/null
@@ -0,0 +1,236 @@
+;;; gnus-mlspl.el --- a group params-based mail splitting mechanism
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Alexandre Oliva <oliva@lsd.ic.unicamp.br>
+;; Keywords: news, mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(require 'gnus)
+(require 'gnus-sum)
+(require 'gnus-group)
+(require 'nnmail)
+
+(defvar gnus-group-split-updated-hook nil
+  "Hook called just after `nnmail-split-fancy' is updated by
+`gnus-group-split-update'.")
+
+(defvar gnus-group-split-default-catch-all-group "mail.misc"
+  "Group name (or arbitrary fancy split) with default splitting rules.
+Used by `gnus-group-split' and `gnus-group-split-update' as a fallback
+split, in case none of the group-based splits matches.")
+
+;;;###autoload
+(defun gnus-group-split-setup (&optional auto-update catch-all)
+  "Set up the split for `nnmail-split-fancy'.
+Sets things up so that nnmail-split-fancy is used for mail
+splitting, and defines the variable nnmail-split-fancy according with
+group parameters.
+
+If AUTO-UPDATE is non-nil (prefix argument accepted, if called
+interactively), it makes sure nnmail-split-fancy is re-computed before
+getting new mail, by adding `gnus-group-split-update' to
+`nnmail-pre-get-new-mail-hook'.
+
+A non-nil CATCH-ALL replaces the current value of
+`gnus-group-split-default-catch-all-group'.  This variable is only used
+by gnus-group-split-update, and only when its CATCH-ALL argument is
+nil.  This argument may contain any fancy split, that will be added as
+the last split in a `|' split produced by `gnus-group-split-fancy',
+unless overridden by any group marked as a catch-all group.  Typical
+uses are as simple as the name of a default mail group, but more
+elaborate fancy splits may also be useful to split mail that doesn't
+match any of the group-specified splitting rules.  See
+`gnus-group-split-fancy' for details."
+  (interactive "P")
+  (setq nnmail-split-methods 'nnmail-split-fancy)
+  (when catch-all
+    (setq gnus-group-split-default-catch-all-group catch-all))
+  (gnus-group-split-update)
+  (when auto-update
+    (add-hook 'nnmail-pre-get-new-mail-hook 'gnus-group-split-update)))
+
+;;;###autoload
+(defun gnus-group-split-update (&optional catch-all)
+  "Computes nnmail-split-fancy from group params and CATCH-ALL.
+It does this by calling by calling (gnus-group-split-fancy nil
+nil CATCH-ALL).
+
+If CATCH-ALL is nil, `gnus-group-split-default-catch-all-group' is used
+instead.  This variable is set by `gnus-group-split-setup'."
+  (interactive)
+  (setq nnmail-split-fancy
+       (gnus-group-split-fancy
+        nil (null nnmail-crosspost)
+        (or catch-all gnus-group-split-default-catch-all-group)))
+  (run-hooks 'gnus-group-split-updated-hook))
+
+;;;###autoload
+(defun gnus-group-split ()
+  "Use information from group parameters in order to split mail.
+See `gnus-group-split-fancy' for more information.
+
+`gnus-group-split' is a valid value for `nnmail-split-methods'."
+  (let (nnmail-split-fancy)
+    (gnus-group-split-update)
+    (nnmail-split-fancy)))
+
+;;;###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
+
+\(: gnus-group-split-fancy GROUPS NO-CROSSPOST CATCH-ALL)
+
+GROUPS may be a regular expression or a list of group names, that will
+be used to select candidate groups.  If it is omitted or nil, all
+existing groups are considered.
+
+if NO-CROSSPOST is omitted or nil, a & split will be returned,
+otherwise, a | split, that does not allow crossposting, will be
+returned.
+
+For each selected group, a SPLIT is composed like this: if SPLIT-SPEC
+is specified, this split is returned as-is (unless it is nil: in this
+case, the group is ignored).  Otherwise, if TO-ADDRESS, TO-LIST and/or
+EXTRA-ALIASES are specified, a regexp that matches any of them is
+constructed (extra-aliases may be a list).  Additionally, if
+SPLIT-REGEXP is specified, the regexp will be extended so that it
+matches this regexp too, and if SPLIT-EXCLUDE is specified, RESTRICT
+clauses will be generated.
+
+If CATCH-ALL is nil, no catch-all handling is performed, regardless of
+catch-all marks in group parameters.  Otherwise, if there is no
+selected group whose SPLIT-REGEXP matches the empty string, nor is
+there a selected group whose SPLIT-SPEC is `catch-all', this fancy
+split (say, a group name) will be appended to the returned SPLIT list,
+as the last element of a `|' SPLIT.
+
+For example, given the following group parameters:
+
+nnml:mail.bar:
+\((to-address . \"bar@femail.com\")
+ (split-regexp . \".*@femail\\\\.com\"))
+nnml:mail.foo:
+\((to-list . \"foo@nowhere.gov\")
+ (extra-aliases \"foo@localhost\" \"foo-redist@home\")
+ (split-exclude \"bugs-foo\" \"rambling-foo\")
+ (admin-address . \"foo-request@nowhere.gov\"))
+nnml:mail.others:
+\((split-spec . catch-all))
+
+Calling (gnus-group-split-fancy nil nil \"mail.others\") returns:
+
+\(| (& (any \"\\\\(bar@femail\\\\.com\\\\|.*@femail\\\\.com\\\\)\"
+          \"mail.bar\")
+      (any \"\\\\(foo@nowhere\\\\.gov\\\\|foo@localhost\\\\|foo-redist@home\\\\)\"
+          - \"bugs-foo\" - \"rambling-foo\" \"mail.foo\"))
+   \"mail.others\")"
+  (let ((group-names (if (and (listp groups)
+                             (not (null groups)))
+                        groups
+                      (delete-dups
+                       (delq nil
+                             (mapcar
+                              (lambda (info)
+                                (let ((group (gnus-info-group info)))
+                                  (if (or (not groups)
+                                          (and (stringp groups)
+                                               (string-match groups group)))
+                                      group)))
+                              (append gnus-newsrc-alist gnus-parameters))))))
+       split)
+    (dolist (group group-names)
+      (let ((params (gnus-group-find-parameter group)))
+       ;; Skip groups without param (or nonexistent)
+       (when (not (null params))
+         (let ((split-spec (assoc 'split-spec params)) group-clean)
+           ;; Remove backend from group name
+           (setq group-clean (string-match ":" group))
+           (setq group-clean
+                 (if group-clean
+                     (substring group (1+ group-clean))
+                   group))
+           (if split-spec
+               (when (setq split-spec (cdr split-spec))
+                 (if (eq split-spec 'catch-all)
+                     ;; Emit catch-all only when requested
+                     (when catch-all
+                       (setq catch-all group-clean))
+                   ;; Append split-spec to the main split
+                   (push split-spec split)))
+             ;; Let's deduce split-spec from other params
+             (let ((to-address (cdr (assoc 'to-address params)))
+                   (to-list (cdr (assoc 'to-list params)))
+                   (extra-aliases (cdr (assoc 'extra-aliases params)))
+                   (split-regexp (cdr (assoc 'split-regexp params)))
+                   (split-exclude (cdr (assoc 'split-exclude params))))
+               (when (or to-address to-list extra-aliases split-regexp)
+                 ;; regexp-quote to-address, to-list and extra-aliases
+                 ;; and add them all to split-regexp
+                 (setq split-regexp
+                       (concat
+                        "\\("
+                        (mapconcat
+                         'identity
+                         (append
+                          (and to-address (list (regexp-quote to-address)))
+                          (and to-list (list (regexp-quote to-list)))
+                          (and extra-aliases
+                               (if (listp extra-aliases)
+                                   (mapcar 'regexp-quote extra-aliases)
+                                 (list extra-aliases)))
+                          (and split-regexp (list split-regexp)))
+                         "\\|")
+                        "\\)"))
+                 ;; Now create the new SPLIT
+                 (push (append
+                        (list 'any split-regexp)
+                        ;; Generate RESTRICTs for SPLIT-EXCLUDEs.
+                        (if (listp split-exclude)
+                            (apply #'append
+                                   (mapcar (lambda (arg) (list '- arg))
+                                           split-exclude))
+                          (list '- split-exclude))
+                        (list group-clean))
+                       split)
+                 ;; If it matches the empty string, it is a catch-all
+                 (when (string-match split-regexp "")
+                   (setq catch-all nil)))))))))
+    ;; Add catch-all if not crossposting
+    (if (and catch-all no-crosspost)
+       (push catch-all split))
+    ;; Move it to the tail, while arranging that SPLITs appear in the
+    ;; same order as groups.
+    (setq split (reverse split))
+    ;; Decide whether to accept cross-postings or not.
+    (push (if no-crosspost '| '&) split)
+    ;; Even if we can cross-post, catch-all should not get
+    ;; cross-posts.
+    (if (and catch-all (not no-crosspost))
+       (setq split (list '| split catch-all)))
+    split))
+
+(provide 'gnus-mlspl)
+
+;;; gnus-mlspl.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-msg.el b/xemacs-packages/gnus/lisp/gnus-msg.el
new file mode 100644 (file)
index 0000000..b95bec2
--- /dev/null
@@ -0,0 +1,2015 @@
+;;; gnus-msg.el --- mail and post interface for Gnus
+
+;; Copyright (C) 1995-2016 Free Software Foundation, Inc.
+
+;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
+;;     Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'gnus)
+(require 'gnus-ems)
+(require 'message)
+(require 'gnus-art)
+(require 'gnus-util)
+
+(defcustom gnus-post-method 'current
+  "*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 `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 `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
+  :link '(custom-manual "(gnus)Posting Server")
+  :type `(choice (const native)
+                (const current)
+                (sexp :tag "Methods" ,gnus-select-method)))
+
+(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
+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)."
+  :group 'gnus-message
+  :type '(choice (const nil)
+                (function)
+                (string :tag "Group")
+                (repeat :tag "List of groups" (string :tag "Group"))))
+
+(make-obsolete-variable 'gnus-outgoing-message-group 'gnus-message-archive-group "24.1")
+
+(defcustom gnus-mailing-list-groups nil
+  "*If non-nil a 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."
+  :group 'gnus-message
+  :type '(choice (regexp)
+                (const nil)))
+
+(defcustom gnus-add-to-list nil
+  "*If non-nil, add a `to-list' parameter automatically."
+  :group 'gnus-message
+  :type 'boolean)
+
+(defcustom gnus-crosspost-complaint
+  "Hi,
+
+You posted the article below with the following Newsgroups header:
+
+Newsgroups: %s
+
+The %s group, at least, was an inappropriate recipient
+of this message.  Please trim your Newsgroups header to exclude this
+group before posting in the future.
+
+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."
+  :group 'gnus-message
+  :type 'string)
+
+(defcustom gnus-message-setup-hook nil
+  "Hook run after setting up a message buffer."
+  :group 'gnus-message
+  :options '(message-remove-blank-cited-lines)
+  :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
+  :link '(custom-manual "(gnus)Posting Styles")
+  :type '(repeat (cons (choice (regexp)
+                              (variable)
+                              (list (const header)
+                                    (string :tag "Header")
+                                    (regexp :tag "Regexp"))
+                              (function)
+                              (sexp))
+                      (repeat (list
+                               (choice (const signature)
+                                       (const signature-file)
+                                       (const organization)
+                                       (const address)
+                                       (const x-face-file)
+                                       (const name)
+                                       (const body)
+                                       (symbol)
+                                       (string :tag "Header"))
+                               (choice (string)
+                                       (function)
+                                       (variable)
+                                       (sexp)))))))
+
+(defcustom gnus-gcc-mark-as-read nil
+  "If non-nil, automatically mark Gcc articles as read."
+  :version "22.1"
+  :group 'gnus-message
+  :type 'boolean)
+
+(make-obsolete-variable 'gnus-inews-mark-gcc-as-read
+                       'gnus-gcc-mark-as-read "Emacs 22.1")
+
+(defcustom gnus-gcc-externalize-attachments nil
+  "Should local-file attachments be included as external parts in Gcc copies?
+If it is `all', attach files as external parts;
+if a regexp and matches the Gcc group name, attach files as external parts;
+if nil, attach files as normal parts."
+  :version "22.1"
+  :group 'gnus-message
+  :type '(choice (const nil :tag "None")
+                (const all :tag "Any")
+                (string :tag "Regexp")))
+
+(defcustom gnus-gcc-self-resent-messages 'no-gcc-self
+  "Like `gcc-self' group parameter, only for unmodified resent messages.
+Applied to messages sent by `gnus-summary-resend-message'.  Non-nil
+value of this variable takes precedence over any existing Gcc header.
+
+If this is `none', no Gcc copy will be made.  If this is t, messages
+resent will be Gcc'd to the current group.  If this is a string, it
+specifies a group to which resent messages will be Gcc'd.  If this is
+nil, Gcc will be done according to existing Gcc header(s), if any.
+If this is `no-gcc-self', resent messages will be Gcc'd to groups that
+existing Gcc header specifies, except for the current group."
+  :version "24.3"
+  :group 'gnus-message
+  :type '(choice (const none) (const t) string (const nil)
+                (const no-gcc-self)))
+
+(gnus-define-group-parameter
+ posting-charset-alist
+ :type list
+ :function-document
+ "Return the permitted unencoded charsets for posting of GROUP."
+ :variable gnus-group-posting-charset-alist
+ :variable-default
+  '(("^\\(no\\|fr\\)\\.[^,]*\\(,[ \t\n]*\\(no\\|fr\\)\\.[^,]*\\)*$" iso-8859-1 (iso-8859-1))
+    ("^\\(fido7\\|relcom\\)\\.[^,]*\\(,[ \t\n]*\\(fido7\\|relcom\\)\\.[^,]*\\)*$" koi8-r (koi8-r))
+    (message-this-is-mail nil nil)
+    (message-this-is-news nil t))
+ :variable-document
+  "Alist of regexps and permitted unencoded charsets for posting.
+Each element of the alist has the form (TEST HEADER BODY-LIST), where
+TEST is either a regular expression matching the newsgroup header or a
+variable to query,
+HEADER is the charset which may be left unencoded in the header (nil
+means encode all charsets),
+BODY-LIST is a list of charsets which may be encoded using 8bit
+content-transfer encoding in the body, or one of the special values
+nil (always encode using quoted-printable) or t (always use 8bit).
+
+Note that any value other than nil for HEADER infringes some RFCs, so
+use this option with care."
+ :variable-group gnus-charset
+ :variable-type
+ '(repeat (list :tag "Permitted unencoded charsets"
+               (choice :tag "Where"
+                       (regexp :tag "Group")
+                       (const :tag "Mail message" :value message-this-is-mail)
+                       (const :tag "News article" :value message-this-is-news))
+               (choice :tag "Header"
+                       (const :tag "None" nil)
+                       (symbol :tag "Charset"))
+               (choice :tag "Body"
+                       (const :tag "Any" :value t)
+                       (const :tag "None" :value nil)
+                       (repeat :tag "Charsets"
+                               (symbol :tag "Charset")))))
+ :parameter-type '(choice :tag "Permitted unencoded charsets"
+                         :value nil
+                         (repeat (symbol)))
+ :parameter-document       "\
+List of charsets that are permitted to be unencoded.")
+
+(defcustom gnus-debug-files
+  '("gnus.el" "gnus-sum.el" "gnus-group.el"
+    "gnus-art.el" "gnus-start.el" "gnus-async.el"
+    "gnus-msg.el" "gnus-score.el" "gnus-win.el" "gnus-topic.el"
+    "gnus-agent.el" "gnus-cache.el" "gnus-srvr.el"
+    "mm-util.el" "mm-decode.el" "nnmail.el" "message.el")
+  "Files whose variables will be reported in `gnus-bug'."
+  :version "22.1"
+  :group 'gnus-message
+  :type '(repeat (string :tag "File")))
+
+(defcustom gnus-debug-exclude-variables
+  '(mm-mime-mule-charset-alist
+    nnmail-split-fancy message-minibuffer-local-map)
+  "Variables that should not be reported in `gnus-bug'."
+  :version "22.1"
+  :group 'gnus-message
+  :type '(repeat (symbol :tag "Variable")))
+
+(defcustom gnus-discouraged-post-methods
+  '(nndraft nnml nnimap nnmaildir nnmh nnfolder nndir)
+  "A list of back ends that are not used in \"real\" newsgroups.
+This variable is used only when `gnus-post-method' is `current'."
+  :version "22.1"
+  :group 'gnus-group-foreign
+  :type '(repeat (symbol :tag "Back end")))
+
+(defcustom gnus-message-replysign
+  nil
+  "Automatically sign replies to signed messages.
+See also the `mml-default-sign-method' variable."
+  :group 'gnus-message
+  :type 'boolean)
+
+(defcustom gnus-message-replyencrypt t
+  "Automatically encrypt replies to encrypted messages.
+See also the `mml-default-encrypt-method' variable."
+  :version "24.1"
+  :group 'gnus-message
+  :type 'boolean)
+
+(defcustom gnus-message-replysignencrypted
+  t
+  "Setting this causes automatically encrypted messages to also be signed."
+  :group 'gnus-message
+  :type 'boolean)
+
+(defcustom gnus-confirm-mail-reply-to-news (and gnus-novice-user
+                                               (not gnus-expert-user))
+  "If non-nil, Gnus requests confirmation when replying to news.
+This is done because new users often reply by mistake when reading
+news.
+This can also be a function receiving the group name as the only
+parameter, which should return non-nil if a confirmation is needed; or
+a regexp, in which case a confirmation is asked for if the group name
+matches the regexp."
+  :version "23.1" ;; No Gnus (default changed)
+  :group 'gnus-message
+  :type '(choice (const :tag "No" nil)
+                (const :tag "Yes" t)
+                (regexp :tag "If group matches regexp")
+                (function :tag "If function evaluates to non-nil")))
+
+(defcustom gnus-confirm-treat-mail-like-news
+  nil
+  "If non-nil, Gnus will treat mail like news with regard to confirmation
+when replying by mail.  See the `gnus-confirm-mail-reply-to-news' variable
+for fine-tuning this.
+If nil, Gnus will never ask for confirmation if replying to mail."
+  :version "22.1"
+  :group 'gnus-message
+  :type 'boolean)
+
+(defcustom gnus-summary-resend-default-address t
+  "If non-nil, Gnus tries to suggest a default address to resend to.
+If nil, the address field will always be empty after invoking
+`gnus-summary-resend-message'."
+  :version "22.1"
+  :group 'gnus-message
+  :type 'boolean)
+
+(defcustom gnus-message-highlight-citation
+  t ;; gnus-treat-highlight-citation ;; gnus-cite dependency
+  "Enable highlighting of different citation levels in message-mode."
+  :version "23.1" ;; No Gnus
+  :group 'gnus-cite
+  :group 'gnus-message
+  :type 'boolean)
+
+(defcustom gnus-gcc-pre-body-encode-hook nil
+  "A hook called before encoding the body of the Gcc copy of a message.
+The current buffer (when the hook is run) contains the message
+including the message header.  Changes made to the message will
+only affect the Gcc copy, but not the original message."
+  :group 'gnus-message
+  :version "24.3"
+  :type 'hook)
+
+(defcustom gnus-gcc-post-body-encode-hook nil
+    "A hook called after encoding the body of the Gcc copy of a message.
+The current buffer (when the hook is run) contains the message
+including the message header.  Changes made to the message will
+only affect the Gcc copy, but not the original message."
+  :group 'gnus-message
+  :version "24.3"
+  :type 'hook)
+
+(autoload 'gnus-message-citation-mode "gnus-cite" nil t)
+
+;;; Internal variables.
+
+(defvar gnus-inhibit-posting-styles nil
+  "Inhibit the use of posting styles.")
+
+(defvar gnus-article-yanked-articles nil)
+(defvar gnus-message-buffer "*Mail Gnus*")
+(defvar gnus-article-copy nil)
+(defvar gnus-check-before-posting nil)
+(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.
+========================================
+
+The buffer below is a mail buffer.  When you press `C-c C-c', it will
+be sent to the Gnus Bug Exterminators.
+
+The thing near the bottom of the buffer is how the environment
+settings will be included in the mail.  Please do not delete that.
+They will tell the Bug People what your environment is, so that it
+will be easier to locate the bugs.
+
+If you have found a bug that makes Emacs go \"beep\", set
+debug-on-error to t (`M-x set-variable RET debug-on-error RET t RET')
+and include the backtrace in your bug report.
+
+Please describe the bug in annoying, painstaking detail.
+
+Thank you for your help in stamping out bugs.
+")
+
+(autoload 'gnus-uu-post-news "gnus-uu" nil t)
+
+\f
+;;;
+;;; Gnus Posting Functions
+;;;
+
+(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
+  "s" gnus-summary-supersede-article
+  "r" gnus-summary-reply
+  "y" gnus-summary-yank-message
+  "R" gnus-summary-reply-with-original
+  "L" gnus-summary-reply-to-list-with-original
+  "w" gnus-summary-wide-reply
+  "W" gnus-summary-wide-reply-with-original
+  "v" gnus-summary-very-wide-reply
+  "V" gnus-summary-very-wide-reply-with-original
+  "n" gnus-summary-followup-to-mail
+  "N" gnus-summary-followup-to-mail-with-original
+  "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
+  "Op" gnus-uu-digest-post-forward)
+
+(gnus-define-keys (gnus-send-bounce-map "D" gnus-summary-send-map)
+  "b" gnus-summary-resend-bounced-mail
+  ;; "c" gnus-summary-send-draft
+  "r" gnus-summary-resend-message
+  "e" gnus-summary-resend-message-edit)
+
+;;; Internal functions.
+
+(defun gnus-inews-make-draft (articles)
+  `(lambda ()
+     (gnus-inews-make-draft-meta-information
+      ,(gnus-group-decoded-name gnus-newsgroup-name) ',articles)))
+
+(autoload 'nnir-article-number "nnir" nil nil 'macro)
+(autoload 'nnir-article-group "nnir" nil nil 'macro)
+(autoload 'gnus-nnir-group-p "nnir")
+
+
+(defvar gnus-article-reply nil)
+(defmacro gnus-setup-message (config &rest forms)
+  (let ((winconf (make-symbol "gnus-setup-message-winconf"))
+       (winconf-name (make-symbol "gnus-setup-message-winconf-name"))
+       (buffer (make-symbol "gnus-setup-message-buffer"))
+       (article (make-symbol "gnus-setup-message-article"))
+       (yanked (make-symbol "gnus-setup-yanked-articles"))
+       (group (make-symbol "gnus-setup-message-group")))
+    `(let ((,winconf (current-window-configuration))
+          (,winconf-name gnus-current-window-configuration)
+          (,buffer (buffer-name (current-buffer)))
+          (,article (if (and (gnus-nnir-group-p gnus-newsgroup-name)
+                             gnus-article-reply)
+                        (nnir-article-number (or (car-safe gnus-article-reply)
+                                                 gnus-article-reply))
+                      gnus-article-reply))
+          (,yanked gnus-article-yanked-articles)
+          (,group (if (and (gnus-nnir-group-p gnus-newsgroup-name)
+                           gnus-article-reply)
+                      (nnir-article-group (or (car-safe gnus-article-reply)
+                                              gnus-article-reply))
+                    gnus-newsgroup-name))
+          (message-header-setup-hook
+           (copy-sequence message-header-setup-hook))
+          (mbl mml-buffer-list)
+          (message-mode-hook (copy-sequence message-mode-hook)))
+       (setq mml-buffer-list nil)
+       (add-hook 'message-header-setup-hook (lambda ()
+                                             (gnus-inews-insert-gcc ,group)))
+       ;; message-newsreader and message-mailer were formerly set in
+       ;; gnus-inews-add-send-actions, but this is too late when
+       ;; message-generate-headers-first is used. --ansel
+       (add-hook 'message-mode-hook
+                (lambda nil
+                  (setq message-newsreader
+                        (setq message-mailer (gnus-extended-version)))))
+       ;; #### 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
+                (if (memq ,config '(reply-yank reply))
+                    (lambda ()
+                      (gnus-configure-posting-styles ,group))
+                  (lambda ()
+                    ;; There may be an old " *gnus article copy*" buffer.
+                    (let (gnus-article-copy)
+                      (gnus-configure-posting-styles ,group)))))
+       (gnus-alist-pull ',(intern gnus-draft-meta-information-header)
+                 message-required-headers)
+       (when (and ,group
+                 (not (string= ,group "")))
+        (push (cons
+               (intern gnus-draft-meta-information-header)
+               (gnus-inews-make-draft (or ,yanked ,article)))
+              message-required-headers))
+       (unwind-protect
+          (progn
+            ,@forms)
+        (gnus-inews-add-send-actions ,winconf ,buffer ,article ,config
+                                     ,yanked ,winconf-name)
+        (setq gnus-message-buffer (current-buffer))
+        (set (make-local-variable 'gnus-message-group-art)
+             (cons ,group ,article))
+        (set (make-local-variable 'gnus-newsgroup-name) ,group)
+        ;; Enable highlighting of different citation levels
+        (when gnus-message-highlight-citation
+          (gnus-message-citation-mode 1))
+        (gnus-run-hooks 'gnus-message-setup-hook)
+        (if (eq major-mode 'message-mode)
+            (let ((mbl1 mml-buffer-list))
+              (setq mml-buffer-list mbl)  ;; Global value
+              (set (make-local-variable 'mml-buffer-list) mbl1);; Local value
+              (gnus-make-local-hook 'kill-buffer-hook)
+              (gnus-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)))
+       (message-hide-headers)
+       (gnus-add-buffer)
+       (gnus-configure-windows ,config t)
+       (run-hooks 'post-command-hook)
+       (set-buffer-modified-p nil))))
+
+(defun gnus-inews-make-draft-meta-information (group articles)
+  (when (numberp articles)
+    (setq articles (list articles)))
+  (concat "(\"" group "\""
+         (if articles
+             (concat " "
+                     (mapconcat
+                      (lambda (elem)
+                        (number-to-string
+                         (if (consp elem)
+                             (car elem)
+                           elem)))
+                      articles " "))
+           "")
+         ")"))
+
+;;;###autoload
+(defun gnus-msg-mail (&optional to subject other-headers continue
+                               switch-action yank-action send-actions
+                               return-action)
+  "Start editing a mail message to be sent.
+Like `message-mail', but with Gnus paraphernalia, particularly the
+Gcc: header for archiving purposes.
+If Gnus isn't running, a plain `message-mail' setup is used
+instead."
+  (interactive)
+  (if (not (gnus-alive-p))
+      (progn
+       (message "Gnus not running; using plain Message mode")
+       (message-mail to subject other-headers continue
+                     nil yank-action send-actions return-action))
+    (let ((buf (current-buffer))
+         ;; Don't use posting styles corresponding to any existing group.
+         (group-name gnus-newsgroup-name)
+         mail-buf)
+      (unwind-protect
+         (progn
+           (setq gnus-newsgroup-name "")
+           (gnus-setup-message 'message
+             (message-mail to subject other-headers continue
+                           nil yank-action send-actions return-action)))
+       (setq gnus-newsgroup-name group-name))
+      (when switch-action
+       (setq mail-buf (current-buffer))
+       (switch-to-buffer buf)
+       (apply switch-action mail-buf nil))
+      ;; COMPOSEFUNC should return t if succeed.  Undocumented ???
+      t)))
+
+;;;###autoload
+(defun gnus-button-mailto (address)
+  "Mail to ADDRESS."
+  (set-buffer (gnus-copy-article-buffer))
+  (gnus-setup-message 'message
+    (message-reply address)))
+
+;;;###autoload
+(defun gnus-button-reply (&optional to-address wide)
+  "Like `message-reply'."
+  (interactive)
+  (gnus-setup-message 'message
+    (message-reply to-address wide)))
+
+;;;###autoload
+(define-mail-user-agent 'gnus-user-agent
+  'gnus-msg-mail 'message-send-and-exit
+  'message-kill-buffer 'message-send-hook)
+
+(defun gnus-setup-posting-charset (group)
+  (let ((alist gnus-group-posting-charset-alist)
+       (group (or group ""))
+       elem)
+    (when group
+      (catch 'found
+       (while (setq elem (pop alist))
+         (when (or (and (stringp (car elem))
+                        (string-match (car elem) group))
+                   (and (functionp (car elem))
+                        (funcall (car elem) group))
+                   (and (symbolp (car elem))
+                        (symbol-value (car elem))))
+           (throw 'found (cons (cadr elem) (caddr elem)))))))))
+
+(defun gnus-inews-add-send-actions (winconf buffer article
+                                           &optional config yanked
+                                           winconf-name)
+  (gnus-make-local-hook 'message-sent-hook)
+  (add-hook 'message-sent-hook (if gnus-agent 'gnus-agent-possibly-do-gcc
+                                'gnus-inews-do-gcc) nil t)
+  (when gnus-agent
+    (gnus-make-local-hook 'message-header-hook)
+    (add-hook 'message-header-hook 'gnus-agent-possibly-save-gcc nil t))
+  (setq message-post-method
+       `(lambda (&optional arg)
+          (gnus-post-method arg ,gnus-newsgroup-name)))
+  (message-add-action
+   `(progn
+      (setq gnus-current-window-configuration ',winconf-name)
+      (when (gnus-buffer-exists-p ,buffer)
+       (set-window-configuration ,winconf)))
+   'exit 'postpone 'kill)
+  (let ((to-be-marked (cond
+                      (yanked
+                       (mapcar
+                        (lambda (x) (if (listp x) (car x) x)) yanked))
+                      (article (if (listp article) article (list article)))
+                      (t nil))))
+    (message-add-action
+     `(when (gnus-buffer-exists-p ,buffer)
+       (with-current-buffer ,buffer
+         ,(when to-be-marked
+            (if (eq config 'forward)
+                `(gnus-summary-mark-article-as-forwarded ',to-be-marked)
+              `(gnus-summary-mark-article-as-replied ',to-be-marked)))))
+     'send)))
+
+(put 'gnus-setup-message 'lisp-indent-function 1)
+(put 'gnus-setup-message 'edebug-form-spec '(form body))
+
+;;; Post news commands of Gnus group mode and summary mode
+
+(defun gnus-group-mail (&optional arg)
+  "Start composing a mail.
+If ARG, use the group under the point to find a posting style.
+If ARG is 1, prompt for a 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)
+       ;; make sure last viewed article doesn't affect posting styles:
+       (gnus-article-copy)
+       (buffer (current-buffer)))
+    (unwind-protect
+       (progn
+         (setq gnus-newsgroup-name
+               (if arg
+                   (if (= 1 (prefix-numeric-value arg))
+                       (gnus-group-completing-read
+                        "Use posting style of group"
+                        nil (gnus-read-active-file-p))
+                     (gnus-group-group-name))
+                 ""))
+         ;; #### see comment in gnus-setup-message -- drv
+         (gnus-setup-message 'message (message-mail)))
+      (with-current-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 back end 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)
+       ;; make sure last viewed article doesn't affect posting styles:
+       (gnus-article-copy)
+       (buffer (current-buffer)))
+    (unwind-protect
+       (progn
+         (setq gnus-newsgroup-name
+               (if arg
+                   (if (= 1 (prefix-numeric-value arg))
+                       (gnus-group-completing-read "Use group"
+                                                   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))))
+      (with-current-buffer buffer
+       (setq gnus-newsgroup-name group)))))
+
+(defun gnus-group-post-news (&optional arg)
+  "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
+        (if arg
+            (if (= 1 (prefix-numeric-value arg))
+                (gnus-group-completing-read "Newsgroup" nil
+                                            (gnus-read-active-file-p))
+              (or (gnus-group-group-name) ""))
+          ""))
+       ;; make sure last viewed article doesn't affect posting styles:
+       (gnus-article-copy))
+    (gnus-post-news 'post gnus-newsgroup-name nil nil nil nil
+                   (string= 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)
+       ;; make sure last viewed article doesn't affect posting styles:
+       (gnus-article-copy)
+       (buffer (current-buffer)))
+    (unwind-protect
+       (progn
+         (setq gnus-newsgroup-name
+               (if arg
+                   (if (= 1 (prefix-numeric-value arg))
+                       (gnus-group-completing-read "Use group"
+                                                   nil
+                                                   (gnus-read-active-file-p))
+                     "")
+                 gnus-newsgroup-name))
+         ;; #### see comment in gnus-setup-message -- drv
+         (gnus-setup-message 'message (message-mail)))
+      (with-current-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 back end 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)
+       ;; make sure last viewed article doesn't affect posting styles:
+       (gnus-article-copy)
+       (buffer (current-buffer)))
+    (unwind-protect
+       (progn
+         (setq gnus-newsgroup-name
+               (if arg
+                   (if (= 1 (prefix-numeric-value arg))
+                       (gnus-group-completing-read "Use group"
+                                                   nil
+                                                   (gnus-read-active-file-p))
+                     "")
+                 gnus-newsgroup-name))
+         ;; #### see comment in gnus-setup-message -- drv
+         (gnus-setup-message 'message
+           (progn
+             (message-news (gnus-group-real-name gnus-newsgroup-name))
+             (set (make-local-variable 'gnus-discouraged-post-methods)
+                  (remove
+                   (car (gnus-find-method-for-group gnus-newsgroup-name))
+                   gnus-discouraged-post-methods)))))
+      (with-current-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))
+                (gnus-group-completing-read "Newsgroup" nil
+                                            (gnus-read-active-file-p))
+              "")
+          gnus-newsgroup-name))
+       ;; make sure last viewed article doesn't affect posting styles:
+       (gnus-article-copy))
+    (gnus-post-news 'post gnus-newsgroup-name)))
+
+
+(defun gnus-summary-followup (yank &optional force-news)
+  "Compose a followup to an article.
+If prefix argument YANK is non-nil, the original article is yanked
+automatically.
+YANK is a list of elements, where the car of each element is the
+article number, and the cdr is the string to be yanked."
+  (interactive
+   (list (and current-prefix-arg
+             (gnus-summary-work-articles 1))))
+  (when yank
+    (gnus-summary-goto-subject
+     (if (listp (car yank))
+        (caar yank)
+       (car yank))))
+  (save-window-excursion
+    (gnus-summary-select-article))
+  (let ((headers (gnus-summary-article-header (gnus-summary-article-number)))
+       (gnus-newsgroup-name gnus-newsgroup-name))
+    ;; Send a followup.
+    (gnus-post-news nil gnus-newsgroup-name
+                   headers gnus-article-buffer
+                   yank nil force-news)
+    (gnus-summary-handle-replysign)))
+
+(defun gnus-summary-followup-with-original (n &optional force-news)
+  "Compose a followup to an article and include the original article.
+The text in the region will be yanked.  If the region isn't
+active, the entire article will be yanked."
+  (interactive "P")
+  (gnus-summary-followup (gnus-summary-work-articles n) force-news))
+
+(defun gnus-summary-followup-to-mail (&optional arg)
+  "Followup to the current mail message via news."
+  (interactive
+   (list (and current-prefix-arg
+             (gnus-summary-work-articles 1))))
+  (gnus-summary-followup arg t))
+
+(defun gnus-summary-followup-to-mail-with-original (&optional arg)
+  "Followup to the current mail message via news."
+  (interactive "P")
+  (gnus-summary-followup (gnus-summary-work-articles arg) t))
+
+(defun gnus-inews-yank-articles (articles)
+  (let (beg article yank-string)
+    (message-goto-body)
+    (while (setq article (pop articles))
+      (when (listp article)
+       (setq yank-string (nth 1 article)
+             article (nth 0 article)))
+      (save-window-excursion
+       (set-buffer gnus-summary-buffer)
+       (gnus-summary-select-article nil nil nil article)
+       (gnus-summary-remove-process-mark article))
+      (gnus-copy-article-buffer nil yank-string)
+      (let ((message-reply-buffer gnus-article-copy)
+           (message-reply-headers
+            ;; The headers are decoded.
+            (with-current-buffer gnus-article-copy
+              (save-restriction
+                (nnheader-narrow-to-headers)
+                (nnheader-parse-naked-head)))))
+       (message-yank-original)
+       (message-exchange-point-and-mark)
+       (setq beg (or beg (mark t))))
+      (when articles
+       (insert "\n")))
+    (push-mark)
+    (goto-char beg)))
+
+(defun gnus-summary-cancel-article (&optional n symp)
+  "Cancel an article you posted.
+Uses the process-prefix convention.  If given the symbolic
+prefix `a', cancel using the standard posting method; if not
+post using the current select method."
+  (interactive (gnus-interactive "P\ny"))
+  (let ((message-post-method
+        `(lambda (arg)
+           (gnus-post-method (eq ',symp 'a) ,gnus-newsgroup-name)))
+       (custom-address user-mail-address))
+    (dolist (article (gnus-summary-work-articles n))
+      (when (gnus-summary-select-article t nil nil article)
+       ;; Pretend that we're doing a followup so that we can see what
+       ;; the From header would have ended up being.
+       (save-window-excursion
+         (save-excursion
+           (gnus-summary-followup nil)
+           (let ((from (message-fetch-field "from")))
+             (when from
+               (setq custom-address
+                     (car (mail-header-parse-address from)))))
+           (kill-buffer (current-buffer))))
+       ;; Now cancel the article using the From header we got.
+       (when (gnus-eval-in-buffer-window gnus-original-article-buffer
+               (let ((user-mail-address (or custom-address user-mail-address)))
+                 (message-cancel-news)))
+         (gnus-summary-mark-as-read article gnus-canceled-mark)
+         (gnus-cache-remove-article 1))
+       (gnus-article-hide-headers-if-wanted))
+      (gnus-summary-remove-process-mark article))))
+
+(defun gnus-summary-supersede-article ()
+  "Compose an article that will supersede a previous article.
+This is done simply by taking the old article and adding a Supersedes
+header line with the old Message-ID."
+  (interactive)
+  (let ((article (gnus-summary-article-number))
+       (mail-parse-charset gnus-newsgroup-charset))
+    (gnus-setup-message 'reply-yank
+      (gnus-summary-select-article t)
+      (set-buffer gnus-original-article-buffer)
+      (message-supersede)
+      (push
+       `((lambda ()
+          (when (gnus-buffer-exists-p ,gnus-summary-buffer)
+            (with-current-buffer ,gnus-summary-buffer
+              (gnus-cache-possibly-remove-article ,article nil nil nil t)
+              (gnus-summary-mark-as-read ,article gnus-canceled-mark)))))
+       message-send-actions)
+      ;; Add Gcc header.
+      (gnus-inews-insert-gcc))))
+
+\f
+
+(defun gnus-copy-article-buffer (&optional article-buffer yank-string)
+  ;; make a copy of the article buffer with all text properties removed
+  ;; this copy is in the buffer gnus-article-copy.
+  ;; if ARTICLE-BUFFER is nil, gnus-article-buffer is used
+  ;; this buffer should be passed to all mail/news reply/post routines.
+  (setq gnus-article-copy (gnus-get-buffer-create " *gnus article copy*"))
+  (with-current-buffer gnus-article-copy
+    (mm-enable-multibyte))
+  (let ((article-buffer (or article-buffer gnus-article-buffer))
+       end beg)
+    (if (not (and (get-buffer article-buffer)
+                 (gnus-buffer-exists-p article-buffer)))
+       (error "Can't find any article buffer")
+      (with-current-buffer article-buffer
+       (let ((gnus-newsgroup-charset (or gnus-article-charset
+                                         gnus-newsgroup-charset))
+             (inhibit-read-only t)
+             (gnus-newsgroup-ignored-charsets
+              (or gnus-article-ignored-charsets
+                  gnus-newsgroup-ignored-charsets)))
+         (save-restriction
+           ;; Copy over the (displayed) article buffer, delete
+           ;; hidden text and remove text properties.
+           (widen)
+           (copy-to-buffer gnus-article-copy (point-min) (point-max))
+           (set-buffer gnus-article-copy)
+           (when yank-string
+             (message-goto-body)
+             (delete-region (point) (point-max))
+             (insert yank-string))
+           (gnus-article-delete-text-of-type 'annotation)
+           (gnus-article-delete-text-of-type 'multipart)
+           (gnus-remove-text-with-property 'gnus-prev)
+           (gnus-remove-text-with-property 'gnus-next)
+           (gnus-remove-text-with-property 'gnus-decoration)
+           (insert
+            (prog1
+                (buffer-substring-no-properties (point-min) (point-max))
+              (erase-buffer)))
+           ;; Find the original headers.
+           (set-buffer gnus-original-article-buffer)
+           (goto-char (point-min))
+           (while (looking-at message-unix-mail-delimiter)
+             (forward-line 1))
+           (let ((mail-header-separator ""))
+             (setq beg (point)
+                   end (or (message-goto-body)
+                           ;; There may be just a header.
+                           (point-max))))
+           ;; Delete the headers from the displayed articles.
+           (set-buffer gnus-article-copy)
+           (let ((mail-header-separator ""))
+             (delete-region (goto-char (point-min))
+                            (or (message-goto-body) (point-max))))
+           ;; Insert the original article headers.
+           (insert-buffer-substring gnus-original-article-buffer beg end)
+           ;; Decode charsets.
+           (let ((gnus-article-decode-hook
+                  (delq 'article-decode-charset
+                        (copy-sequence gnus-article-decode-hook)))
+                 (rfc2047-quote-decoded-words-containing-tspecials t))
+             (run-hooks 'gnus-article-decode-hook)))))
+      gnus-article-copy)))
+
+(defun gnus-post-news (post &optional group header article-buffer yank subject
+                           force-news)
+  (when article-buffer
+    (gnus-copy-article-buffer))
+  (let ((gnus-article-reply (and article-buffer (gnus-summary-article-number)))
+       (gnus-article-yanked-articles yank)
+       (add-to-list gnus-add-to-list))
+    (gnus-setup-message (cond (yank 'reply-yank)
+                             (article-buffer 'reply)
+                             (t 'message))
+      (let* ((group (or group gnus-newsgroup-name))
+            (charset (gnus-group-name-charset nil group))
+            (pgroup group)
+            to-address to-group mailing-list to-list
+            newsgroup-p)
+       (when group
+         (setq to-address (gnus-parameter-to-address group)
+               to-group (gnus-group-find-parameter group 'to-group)
+               to-list (gnus-parameter-to-list group)
+               newsgroup-p (gnus-group-find-parameter group 'newsgroup)
+               mailing-list (when gnus-mailing-list-groups
+                              (string-match gnus-mailing-list-groups group))
+               group (gnus-group-name-decode (gnus-group-real-name group)
+                                             charset)))
+       (if (or (and to-group
+                    (gnus-news-group-p to-group))
+               newsgroup-p
+               force-news
+               (and (gnus-news-group-p
+                     (or pgroup gnus-newsgroup-name)
+                     (or header gnus-current-article))
+                    (not mailing-list)
+                    (not to-list)
+                    (not to-address)))
+           ;; This is news.
+           (if post
+               (message-news
+                (or to-group
+                    (and (not (gnus-virtual-group-p pgroup)) group)))
+             (set-buffer gnus-article-copy)
+             (gnus-msg-treat-broken-reply-to)
+             (message-followup (if (or newsgroup-p force-news)
+                                   (if (save-restriction
+                                         (article-narrow-to-head)
+                                         (message-fetch-field "newsgroups"))
+                                       nil
+                                     "")
+                                 to-group)))
+         ;; The is mail.
+         (if post
+             (progn
+               (message-mail (or to-address to-list))
+               ;; Arrange for mail groups that have no `to-address' to
+               ;; get that when the user sends off the mail.
+               (when (and (not to-list)
+                          (not to-address)
+                          add-to-list)
+                 (push (list 'gnus-inews-add-to-address pgroup)
+                       message-send-actions)))
+           (set-buffer gnus-article-copy)
+           (gnus-msg-treat-broken-reply-to)
+           (message-wide-reply to-address)))
+       (when yank
+         (gnus-inews-yank-articles yank))))))
+
+(defun gnus-msg-treat-broken-reply-to (&optional force)
+  "Remove the Reply-to header if broken-reply-to."
+  (when (or force
+           (gnus-group-find-parameter
+            gnus-newsgroup-name 'broken-reply-to))
+    (save-restriction
+      (message-narrow-to-head)
+      (message-remove-header "reply-to"))))
+
+(defun gnus-post-method (arg group &optional silent)
+  "Return the posting method based on GROUP and ARG.
+If SILENT, don't prompt the user."
+  (let ((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 (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 'current)
+         gnus-select-method
+       group-method))
+     ;; We query the user for a post method.
+     ((or arg
+         (and (listp gnus-post-method)
+              (listp (car gnus-post-method))))
+      (let* ((methods
+             ;; Collect all methods we know about.
+             (append
+              (when (listp gnus-post-method)
+                (if (listp (car gnus-post-method))
+                    gnus-post-method
+                  (list gnus-post-method)))
+              gnus-secondary-select-methods
+              (mapcar 'cdr gnus-server-alist)
+              (mapcar 'car gnus-opened-servers)
+              (list gnus-select-method)
+              (list group-method)))
+            method-alist post-methods method)
+       ;; Weed out all mail methods.
+       (while methods
+         (setq method (gnus-server-get-method "" (pop methods)))
+         (when (and (or (gnus-method-option-p method 'post)
+                        (gnus-method-option-p method 'post-mail))
+                    (not (member method post-methods)))
+           (push method post-methods)))
+       ;; Create a name-method alist.
+       (setq method-alist
+             (mapcar
+              (lambda (m)
+                (if (equal (cadr m) "")
+                    (list (symbol-name (car m)) m)
+                  (list (concat (cadr m) " (" (symbol-name (car m)) ")") m)))
+              post-methods))
+       ;; Query the user.
+       (cadr
+        (assoc
+         (setq gnus-last-posting-server
+               (if (and silent
+                        gnus-last-posting-server)
+                   ;; Just use the last value.
+                   gnus-last-posting-server
+                 (gnus-completing-read
+                  "Posting method" (mapcar 'car method-alist) t
+                  (cons (or gnus-last-posting-server "") 0))))
+         method-alist))))
+     ;; Override normal method.
+     ((and (eq gnus-post-method 'current)
+          (not (memq (car group-method) gnus-discouraged-post-methods))
+          (gnus-get-function group-method 'request-post t))
+      (assert (not arg))
+      group-method)
+     ;; 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 (nil or native).
+     (t gnus-select-method))))
+
+\f
+
+(defun gnus-extended-version ()
+  "Stringified Gnus version and Emacs version.
+See the variable `gnus-user-agent'."
+  (interactive)
+  (if (stringp gnus-user-agent)
+      gnus-user-agent
+    ;; `gnus-user-agent' is a list:
+    (let* ((float-output-format nil)
+          (gnus-v
+           (when (memq 'gnus gnus-user-agent)
+             (concat "Gnus/"
+                     (gnus-replace-in-string
+                      (format "%1.8f" (gnus-continuum-version gnus-version))
+                      "0+\\'" "")
+                     " (" gnus-version ")")))
+          (emacs-v (gnus-emacs-version)))
+      (concat gnus-v (when (and gnus-v emacs-v) " ")
+             emacs-v))))
+
+\f
+;;;
+;;; Gnus Mail Functions
+;;;
+
+;;; Mail reply commands of Gnus summary mode
+
+(defun gnus-summary-reply (&optional yank wide very-wide)
+  "Start composing a mail reply to the current message.
+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))))
+  ;; Allow user to require confirmation before replying by mail to the
+  ;; author of a news article (or mail message).
+  (when (or (not (or (gnus-news-group-p gnus-newsgroup-name)
+                    gnus-confirm-treat-mail-like-news))
+           (not (cond ((stringp gnus-confirm-mail-reply-to-news)
+                       (string-match gnus-confirm-mail-reply-to-news
+                                     gnus-newsgroup-name))
+                      ((functionp gnus-confirm-mail-reply-to-news)
+                       (funcall gnus-confirm-mail-reply-to-news
+                                gnus-newsgroup-name))
+                      (t gnus-confirm-mail-reply-to-news)))
+           (if (or wide very-wide)
+               t ;; Ignore gnus-confirm-mail-reply-to-news for wide and very
+                 ;; wide replies.
+             (y-or-n-p "Really reply by mail to article author? ")))
+    (let* ((article
+           (if (listp (car yank))
+               (caar yank)
+             (car yank)))
+          (gnus-article-reply (or article (gnus-summary-article-number)))
+          (gnus-article-yanked-articles yank)
+          (headers ""))
+      ;; Stripping headers should be specified with mail-yank-ignored-headers.
+      (when yank
+       (gnus-summary-goto-subject article))
+      (gnus-setup-message (if yank 'reply-yank 'reply)
+       (if (not very-wide)
+           (gnus-summary-select-article)
+         (dolist (article very-wide)
+           (gnus-summary-select-article nil nil nil article)
+           (with-current-buffer (gnus-copy-article-buffer)
+             (gnus-msg-treat-broken-reply-to)
+             (save-restriction
+               (message-narrow-to-head)
+               (setq headers (concat headers (buffer-string)))))))
+       (set-buffer (gnus-copy-article-buffer))
+       (gnus-msg-treat-broken-reply-to gnus-msg-force-broken-reply-to)
+       (save-restriction
+         (message-narrow-to-head)
+         (when very-wide
+           (erase-buffer)
+           (insert headers))
+         (goto-char (point-max)))
+       (mml-quote-region (point) (point-max))
+       (message-reply nil wide)
+       (when yank
+         (gnus-inews-yank-articles yank))
+       (gnus-summary-handle-replysign)))))
+
+(defun gnus-summary-handle-replysign ()
+  "Check the various replysign variables and take action accordingly."
+  (when (or gnus-message-replysign gnus-message-replyencrypt)
+    (let (signed encrypted)
+      (with-current-buffer gnus-article-buffer
+       (setq signed (memq 'signed gnus-article-wash-types))
+       (setq encrypted (memq 'encrypted gnus-article-wash-types)))
+      (cond ((and gnus-message-replyencrypt encrypted)
+            (mml-secure-message mml-default-encrypt-method
+                                (if gnus-message-replysignencrypted
+                                    'signencrypt
+                                  'encrypt)))
+           ((and gnus-message-replysign signed)
+            (mml-secure-message mml-default-sign-method 'sign))))))
+
+(defun gnus-summary-reply-with-original (n &optional wide)
+  "Start composing a reply mail to the current message.
+The original article will be yanked."
+  (interactive "P")
+  (gnus-summary-reply (gnus-summary-work-articles n) wide))
+
+(defun gnus-summary-reply-to-list-with-original (n &optional wide)
+  "Start composing a reply mail to the current message.
+The reply goes only to the mailing list.
+The original article will be yanked."
+  (interactive "P")
+  (let ((message-reply-to-function
+        (lambda nil
+          `((To . ,(gnus-mailing-list-followup-to))))))
+    (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
+automatically."
+  (interactive
+   (list (and current-prefix-arg
+             (gnus-summary-work-articles 1))))
+  (gnus-summary-reply yank t))
+
+(defun gnus-summary-wide-reply-with-original (n)
+  "Start composing a wide reply mail to the current message.
+The original article will be yanked.
+Uses the process/prefix convention."
+  (interactive "P")
+  (gnus-summary-reply-with-original n t))
+
+(defun gnus-summary-very-wide-reply (&optional yank)
+  "Start composing a very wide reply mail to the current message.
+If prefix argument YANK is non-nil, the original article is yanked
+automatically."
+  (interactive
+   (list (and current-prefix-arg
+             (gnus-summary-work-articles 1))))
+  (gnus-summary-reply yank t (gnus-summary-work-articles yank)))
+
+(defun gnus-summary-very-wide-reply-with-original (n)
+  "Start composing a very wide reply mail to the current message.
+The original article will be yanked."
+  (interactive "P")
+  (gnus-summary-reply
+   (gnus-summary-work-articles n) t (gnus-summary-work-articles n)))
+
+(defun gnus-summary-mail-forward (&optional arg post)
+  "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.
+For the \"inline\" alternatives, also see the variable
+`message-forward-ignored-headers'."
+  (interactive "P")
+  (if (cdr (gnus-summary-work-articles nil))
+      ;; Process marks are given.
+      (gnus-uu-digest-mail-forward nil post)
+    ;; No process marks.
+    (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-article-yanked-articles (list gnus-article-reply)))
+       (gnus-setup-message 'forward
+         (gnus-summary-select-article)
+         (let ((mail-parse-charset
+                (or (and (gnus-buffer-live-p gnus-article-buffer)
+                         (with-current-buffer gnus-article-buffer
+                           gnus-article-charset))
+                    gnus-newsgroup-charset))
+               (mail-parse-ignored-charsets
+                gnus-newsgroup-ignored-charsets))
+           (set-buffer gnus-original-article-buffer)
+           (message-forward post)))))))
+
+(defun gnus-summary-resend-message-insert-gcc ()
+  "Insert Gcc header according to `gnus-gcc-self-resent-messages'."
+  (gnus-inews-insert-gcc)
+  (let ((gcc (mapcar
+             (lambda (group)
+               (mm-encode-coding-string
+                group
+                (gnus-group-name-charset (gnus-inews-group-method group)
+                                         group)))
+             (message-unquote-tokens
+              (message-tokenize-header (mail-fetch-field "gcc" nil t)
+                                       " ,"))))
+       (self (with-current-buffer gnus-summary-buffer
+               gnus-gcc-self-resent-messages)))
+    (message-remove-header "gcc")
+    (when gcc
+      (goto-char (point-max))
+      (cond ((eq self 'none))
+           ((eq self t)
+            (insert "Gcc: \"" gnus-newsgroup-name "\"\n"))
+           ((stringp self)
+            (insert "Gcc: "
+                    (mm-encode-coding-string
+                     (if (string-match " " self)
+                         (concat "\"" self "\"")
+                       self)
+                     (gnus-group-name-charset (gnus-inews-group-method self)
+                                              self))
+                    "\n"))
+           ((null self)
+            (insert "Gcc: " (mapconcat 'identity gcc ", ") "\n"))
+           ((eq self 'no-gcc-self)
+            (when (setq gcc (delete
+                             gnus-newsgroup-name
+                             (delete (concat "\"" gnus-newsgroup-name "\"")
+                                     gcc)))
+              (insert "Gcc: " (mapconcat 'identity gcc ", ") "\n")))))))
+
+(defun gnus-summary-resend-message (address n)
+  "Resend the current article to ADDRESS."
+  (interactive
+   (list (message-read-from-minibuffer
+         "Resend message(s) to: "
+         (when (and gnus-summary-resend-default-address
+                    (gnus-buffer-live-p gnus-original-article-buffer))
+           ;; If some other article is currently selected, the
+           ;; initial-contents is wrong. Whatever, it is just the
+           ;; initial-contents.
+           (with-current-buffer gnus-original-article-buffer
+             (nnmail-fetch-field "to"))))
+        current-prefix-arg))
+  (let ((message-header-setup-hook (copy-sequence message-header-setup-hook))
+       (message-sent-hook (copy-sequence message-sent-hook))
+       ;; Honor posting-style for `name' and `address' in Resent-From header.
+       (styles (gnus-group-find-parameter gnus-newsgroup-name
+                                          'posting-style t))
+       (user-full-name user-full-name)
+       (user-mail-address user-mail-address)
+       tem)
+    (dolist (style styles)
+      (when (stringp (cadr style))
+       (setcdr style (list (mm-decode-coding-string (cadr style) 'utf-8)))))
+    (dolist (style (if styles
+                      (append gnus-posting-styles (list (cons ".*" styles)))
+                    gnus-posting-styles))
+      (when (and (stringp (car style))
+                (string-match (pop style) gnus-newsgroup-name))
+       (when (setq tem (cadr (assq 'name style)))
+         (setq user-full-name tem))
+       (when (setq tem (cadr (assq 'address style)))
+         (setq user-mail-address tem))))
+    ;; `gnus-summary-resend-message-insert-gcc' must run last.
+    (add-hook 'message-header-setup-hook
+             'gnus-summary-resend-message-insert-gcc t)
+    (add-hook 'message-sent-hook
+             `(lambda ()
+                (let ((rfc2047-encode-encoded-words nil))
+                  ,(if gnus-agent
+                       '(gnus-agent-possibly-do-gcc)
+                     '(gnus-inews-do-gcc)))))
+    (dolist (article (gnus-summary-work-articles n))
+      (gnus-summary-select-article nil nil nil article)
+      (with-current-buffer gnus-original-article-buffer
+       (let ((gnus-gcc-externalize-attachments nil)
+             (message-inhibit-body-encoding t))
+         (message-resend address)))
+      (gnus-summary-mark-article-as-forwarded article))))
+
+;; From: Matthieu Moy <Matthieu.Moy@imag.fr>
+(defun gnus-summary-resend-message-edit ()
+  "Resend an article that has already been sent.
+A new buffer will be created to allow the user to modify body and
+contents of the message, and then, everything will happen as when
+composing a new message."
+  (interactive)
+  (let ((mail-parse-charset gnus-newsgroup-charset))
+    (gnus-setup-message 'reply-yank
+      (gnus-summary-select-article t)
+      (set-buffer gnus-original-article-buffer)
+      (let ((cur (current-buffer))
+           (to (message-fetch-field "to")))
+       ;; Get a normal message buffer.
+       (message-pop-to-buffer (message-buffer-name "Resend" to))
+       (insert-buffer-substring cur)
+       (mime-to-mml)
+       (message-narrow-to-head-1)
+       ;; Gnus will generate a new one when sending.
+       (message-remove-header "Message-ID")
+       ;; Remove unwanted headers.
+       (message-remove-header message-ignored-resent-headers t)
+       (goto-char (point-max))
+       (insert mail-header-separator)
+       ;; Add Gcc header.
+       (gnus-inews-insert-gcc)
+       (goto-char (point-min))
+       (when (re-search-forward "^To:\\|^Newsgroups:" nil 'move)
+         (forward-char 1))
+       (widen)))))
+
+(defun gnus-summary-post-forward (&optional arg)
+  "Forward the current article to a newsgroup.
+See `gnus-summary-mail-forward' for ARG."
+  (interactive "P")
+  (gnus-summary-mail-forward arg t))
+
+(defun gnus-summary-mail-crosspost-complaint (n)
+  "Send a complaint about crossposting to the current article(s)."
+  (interactive "P")
+  (dolist (article (gnus-summary-work-articles n))
+    (set-buffer gnus-summary-buffer)
+    (gnus-summary-goto-subject article)
+    (let ((group (gnus-group-real-name gnus-newsgroup-name))
+         newsgroups followup-to)
+      (gnus-summary-select-article)
+      (set-buffer gnus-original-article-buffer)
+      (if (and (<= (length (message-tokenize-header
+                           (setq newsgroups
+                                 (mail-fetch-field "newsgroups"))
+                           ", "))
+                  1)
+              (or (not (setq followup-to (mail-fetch-field "followup-to")))
+                  (not (member group (message-tokenize-header
+                                      followup-to ", ")))))
+         (if followup-to
+             (gnus-message 1 "Followup-to restricted")
+           (gnus-message 1 "Not a crossposted article"))
+       (set-buffer gnus-summary-buffer)
+       (gnus-summary-reply-with-original 1)
+       (set-buffer gnus-message-buffer)
+       (message-goto-body)
+       (insert (format gnus-crosspost-complaint newsgroups group))
+       (message-goto-subject)
+       (re-search-forward " *$")
+       (replace-match " (crosspost notification)" t t)
+       (gnus-deactivate-mark)
+       (when (gnus-y-or-n-p "Send this complaint? ")
+         (message-send-and-exit))))))
+
+(defun gnus-inews-add-to-address (group)
+  (let ((to-address (mail-fetch-field "to")))
+    (when (and to-address
+              (gnus-alive-p))
+      ;; This mail group doesn't have a `to-list', so we add one
+      ;; here.  Magic!
+      (when (gnus-y-or-n-p
+            (format "Do you want to add this as `to-list': %s? " to-address))
+       (gnus-group-add-parameter group (cons 'to-list to-address))))))
+
+(defun gnus-article-mail (yank)
+  "Send a reply to the address near point.
+If YANK is non-nil, include the original article."
+  (interactive "P")
+  (let ((address
+        (buffer-substring
+         (save-excursion (re-search-backward "[ \t\n]" nil t) (1+ (point)))
+         (save-excursion (re-search-forward "[ \t\n]" nil t) (1- (point))))))
+    (when address
+      (gnus-msg-mail address)
+      (when yank
+       (gnus-inews-yank-articles (list (cdr gnus-article-current)))))))
+
+(defvar nntp-server-type)
+(defun gnus-bug ()
+  "Send a bug report to the Gnus maintainers."
+  (interactive)
+  (unless (gnus-alive-p)
+    (error "Gnus has been shut down"))
+  (gnus-setup-message (if (message-mail-user-agent) 'message 'bug)
+    (unless (message-mail-user-agent)
+      (when gnus-bug-create-help-buffer
+       (switch-to-buffer "*Gnus Help Bug*")
+       (erase-buffer)
+       (insert gnus-bug-message)
+       (goto-char (point-min)))
+      (message-pop-to-buffer "*Gnus Bug*"))
+    (let ((message-this-is-mail t))
+      (message-setup `((To . ,gnus-maintainer)
+                       (Subject . "")
+                       (X-Debbugs-Package
+                        . ,(format "%s" gnus-bug-package))
+                       (X-Debbugs-Version
+                        . ,(format "%s" (gnus-continuum-version))))))
+    (when gnus-bug-create-help-buffer
+      (push `(gnus-bug-kill-buffer) message-send-actions))
+    (goto-char (point-min))
+    (message-goto-body)
+    (insert "\n\n\n\n\n")
+    (insert (gnus-version) "\n"
+           (emacs-version) "\n")
+    (when (and (boundp 'nntp-server-type)
+              (stringp nntp-server-type))
+      (insert nntp-server-type))
+    (goto-char (point-min))
+    (search-forward "Subject: " nil t)
+    (message "")))
+
+(defun gnus-bug-kill-buffer ()
+  (when (get-buffer "*Gnus Help Bug*")
+    (kill-buffer "*Gnus Help Bug*")))
+
+(defun gnus-summary-yank-message (buffer n)
+  "Yank the current article into a composed message."
+  (interactive
+   (list (gnus-completing-read "Buffer" (message-buffers) t)
+        current-prefix-arg))
+  (gnus-summary-iterate n
+    (let ((gnus-inhibit-treatment t))
+      (gnus-summary-select-article))
+    (with-current-buffer buffer
+      (message-yank-buffer gnus-article-buffer))))
+
+;;; Treatment of rejected articles.
+;;; Bounced mail.
+
+(defun gnus-summary-resend-bounced-mail (&optional fetch)
+  "Re-mail the current message.
+This only makes sense if the current message is a bounce message that
+contains some mail you have written which has been bounced back to
+you.
+If FETCH, try to fetch the article that this is a reply to, if indeed
+this is a reply."
+  (interactive "P")
+  (gnus-summary-select-article t)
+  (let (summary-buffer parent)
+    (if fetch
+       (progn
+         (setq summary-buffer (current-buffer))
+         (set-buffer gnus-original-article-buffer)
+         (article-goto-body)
+         (when (re-search-forward "^References:\n?" nil t)
+           (while (memq (char-after) '(?\t ? ))
+             (forward-line 1))
+           (skip-chars-backward "\t\n ")
+           (setq parent
+                 (gnus-parent-id (buffer-substring (match-end 0) (point))))))
+      (set-buffer gnus-original-article-buffer))
+    (gnus-setup-message 'compose-bounce
+      (message-bounce)
+      ;; Add Gcc header.
+      (gnus-inews-insert-gcc)
+      ;; If there are references, we fetch the article we answered to.
+      (when parent
+       (with-current-buffer summary-buffer
+         (gnus-summary-refer-article parent)
+         (gnus-summary-show-all-headers))))))
+
+;;; Gcc handling.
+
+(defun gnus-inews-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)
+  (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 options
+           mml-externalize-attachments)
+       (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))
+           (setq method (gnus-inews-group-method group)
+                 group (mm-encode-coding-string
+                        group
+                        (gnus-group-name-charset method group)))
+           (unless (gnus-check-server method)
+             (error "Can't open server %s" (if (stringp method) method
+                                             (car method))))
+           (unless (gnus-request-group group t method)
+             (gnus-request-create-group group method))
+           (setq mml-externalize-attachments
+                 (if (stringp gnus-gcc-externalize-attachments)
+                     (string-match gnus-gcc-externalize-attachments group)
+                   gnus-gcc-externalize-attachments))
+           (save-excursion
+             (nnheader-set-temp-buffer " *acc*")
+             (setq message-options (with-current-buffer cur message-options))
+             (insert-buffer-substring cur)
+             (run-hooks 'gnus-gcc-pre-body-encode-hook)
+             (message-encode-message-body)
+             (run-hooks 'gnus-gcc-post-body-encode-hook)
+             (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
+                      ;; names with incompatible character sets.
+                      ;; -- Per Abrahamsen <abraham@dina.kvl.dk> 2001-10-08.
+                      (group-field-charset
+                       (gnus-group-name-charset
+                        method (or newsgroups-field "")))
+                      (followup-field-charset
+                       (gnus-group-name-charset
+                        method (or followup-field "")))
+                      (rfc2047-header-encoding-alist
+                       (append
+                        (when group-field-charset
+                          (list (cons "Newsgroups" group-field-charset)))
+                        (when followup-field-charset
+                          (list (cons "Followup-To" followup-field-charset)))
+                        rfc2047-header-encoding-alist)))
+                 (mail-encode-encoded-word-buffer)))
+             (goto-char (point-min))
+             (when (re-search-forward
+                    (concat "^" (regexp-quote mail-header-separator) "$")
+                    nil t)
+               (replace-match "" t t ))
+             (when (or (not (gnus-check-backend-function
+                             'request-accept-article group))
+                       (not (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)))
+             (when (stringp method)
+               (setq method (gnus-server-to-method method)))
+             (when (and (listp method)
+                        (gnus-native-method-p method))
+               (setq group (gnus-group-short-name group)))
+             (when (and group-art
+                        ;; FIXME: Should gcc-mark-as-read work when
+                        ;; Gnus is not running?
+                        (gnus-alive-p))
+               (if (or gnus-gcc-mark-as-read
+                       (and (boundp 'gnus-inews-mark-gcc-as-read)
+                            (symbol-value 'gnus-inews-mark-gcc-as-read)))
+                   (gnus-group-mark-article-read group (cdr group-art))
+                 (with-current-buffer gnus-group-buffer
+                   (let ((gnus-group-marked (list group))
+                         (gnus-get-new-news-hook nil)
+                         (inhibit-read-only t))
+                     (gnus-group-get-new-news-this-group nil t)))))
+             (setq options message-options)
+             (with-current-buffer cur (setq message-options options))
+             (kill-buffer (current-buffer)))))))))
+
+(defun gnus-inews-insert-gcc (&optional group)
+  "Insert the Gcc to say where the article is to be archived."
+  (let* ((group (or group gnus-newsgroup-name))
+         (group (when group (gnus-group-decoded-name group)))
+         (var (or gnus-outgoing-message-group gnus-message-archive-group))
+        (gcc-self-val
+         (and group (not (gnus-virtual-group-p group))
+              (gnus-group-find-parameter group 'gcc-self t)))
+        (gcc-self-get (lambda (gcc-self-val group)
+                        (if (stringp gcc-self-val)
+                            (if (string-match " " gcc-self-val)
+                                (concat "\"" gcc-self-val "\"")
+                              gcc-self-val)
+                          ;; In nndoc groups, we use the parent group name
+                          ;; instead of the current group.
+                          (let ((group (or (gnus-group-find-parameter
+                                            gnus-newsgroup-name 'parent-group)
+                                           group)))
+                            (if (string-match " " group)
+                                (concat "\"" group "\"")
+                              group)))))
+        result
+        (groups
+         (cond
+          ((null gnus-message-archive-method)
+           ;; Ignore.
+           nil)
+          ((stringp var)
+           ;; Just a single group.
+           (list var))
+          ((null var)
+           ;; We don't want this.
+           nil)
+          ((and (listp var) (stringp (car var)))
+           ;; A list of groups.
+           var)
+          ((functionp var)
+           ;; A function.
+           (funcall var group))
+          (group
+           ;; An alist of regexps/functions/forms.
+           (while (and var
+                       (not
+                        (setq result
+                              (cond
+                               ((and group
+                                     (stringp (caar var)))
+                                ;; Regexp.
+                                (when (string-match (caar var) group)
+                                  (cdar var)))
+                               ((and group
+                                     (functionp (car var)))
+                                ;; Function.
+                                (funcall (car var) group))
+                               (t
+                                (eval (car var)))))))
+             (setq var (cdr var)))
+           result)))
+        name)
+    (when (and (or groups gcc-self-val)
+              (gnus-alive-p))
+      (when (stringp groups)
+       (setq groups (list groups)))
+      (save-excursion
+       (save-restriction
+         (message-narrow-to-headers)
+         (goto-char (point-max))
+         (insert "Gcc: ")
+         (if gcc-self-val
+             ;; Use the `gcc-self' param value instead.
+             (progn
+               (insert (if (listp gcc-self-val)
+                           (mapconcat (lambda (val)
+                                        (funcall gcc-self-get val group))
+                                      gcc-self-val ", ")
+                           (funcall gcc-self-get gcc-self-val group)))
+               (if (not (eq gcc-self-val 'none))
+                   (insert "\n")
+                 (gnus-delete-line)))
+           ;; Use the list of groups.
+           (while (setq name (pop groups))
+             (let ((str (if (string-match ":" name)
+                            name
+                          (gnus-group-prefixed-name
+                           name gnus-message-archive-method))))
+               (insert (if (string-match " " str)
+                           (concat "\"" str "\"")
+                         str)))
+             (when groups
+               (insert " ")))
+           (insert "\n")))))))
+
+(defun gnus-mailing-list-followup-to ()
+  "Look at the headers in the current buffer and return a Mail-Followup-To address."
+  (let ((x-been-there (gnus-fetch-original-field "x-beenthere"))
+       (list-post (gnus-fetch-original-field "list-post")))
+    (when (and list-post
+              (string-match "mailto:\\([^>]+\\)" list-post))
+      (setq list-post (match-string 1 list-post)))
+    (or list-post
+       x-been-there)))
+
+;;; 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 group-name gnus-newsgroup-name ""))
+         (styles (if (gnus-buffer-live-p gnus-summary-buffer)
+                     (with-current-buffer gnus-summary-buffer
+                       gnus-posting-styles)
+                   gnus-posting-styles))
+         style match attribute value v results matched-string
+         filep name address element)
+      ;; If the group has a posting-style parameter, add it at the end with a
+      ;; regexp matching everything, to be sure it takes precedence over all
+      ;; the others.
+      (when gnus-newsgroup-name
+       (let ((tmp-style (gnus-group-find-parameter group 'posting-style t)))
+         (when tmp-style
+           (dolist (style tmp-style)
+             (when (stringp (cadr style))
+               (setcdr style (list (mm-decode-coding-string (cadr style)
+                                                            'utf-8)))))
+           (setq styles (append styles (list (cons ".*" tmp-style)))))))
+      ;; Go through all styles and look for matches.
+      (dolist (style styles)
+       (setq match (pop style))
+       (goto-char (point-min))
+       (when (cond
+              ((stringp match)
+               ;; Regexp string match on the group name.
+               (when (string-match match group)
+                  (setq matched-string group)
+                  t))
+              ((eq match 'header)
+               ;; Obsolete format of header match.
+               (and (gnus-buffer-live-p gnus-article-copy)
+                    (with-current-buffer gnus-article-copy
+                      (save-restriction
+                        (nnheader-narrow-to-headers)
+                        (let ((header (message-fetch-field (pop style))))
+                          (and header
+                               (string-match (pop style) header)))))))
+              ((or (symbolp match)
+                   (functionp match))
+               (cond
+                ((functionp match)
+                 ;; Function to be called.
+                 (funcall match))
+                ((boundp match)
+                 ;; Variable to be checked.
+                 (symbol-value match))))
+              ((listp match)
+               (cond
+                ((eq (car match) 'header)
+                 ;; New format of header match.
+                 (and (gnus-buffer-live-p gnus-article-copy)
+                      (with-current-buffer gnus-article-copy
+                        (save-restriction
+                          (nnheader-narrow-to-headers)
+                          (let ((header (message-fetch-field (nth 1 match))))
+                            (and header
+                                 (string-match (nth 2 match) header)
+                                 (setq matched-string header)))))))
+                (t
+                 ;; This is a form to be evalled.
+                 (eval match)))))
+         ;; We have a match, so we set the variables.
+         (dolist (attribute style)
+           (setq element (pop attribute)
+                 filep nil)
+           (setq value
+                 (cond
+                  ((eq (car attribute) :file)
+                   (setq filep t)
+                   (cadr attribute))
+                  ((eq (car attribute) :value)
+                   (cadr attribute))
+                  (t
+                   (car attribute))))
+           ;; We get the value.
+           (setq v
+                 (cond
+                  ((stringp value)
+                   (if (and matched-string
+                            (gnus-string-match-p "\\\\[&[:digit:]]" value)
+                            (match-beginning 1))
+                       (gnus-match-substitute-replacement value nil nil
+                                                          matched-string)
+                     value))
+                  ((or (symbolp value)
+                       (functionp value))
+                   (cond ((functionp value)
+                          (funcall value))
+                         ((boundp value)
+                          (symbol-value value))))
+                  ((listp value)
+                   (eval value))))
+           ;; Translate obsolescent value.
+           (cond
+            ((eq element 'signature-file)
+             (setq element 'signature
+                   filep t))
+            ((eq element 'x-face-file)
+             (setq element 'x-face
+                   filep t)))
+           ;; Post-processing for the signature posting-style:
+           (and (eq element 'signature) filep
+                message-signature-directory
+                ;; don't actually use the signature directory
+                ;; if message-signature-file contains a path.
+                (not (file-name-directory v))
+                (setq v (nnheader-concat message-signature-directory v)))
+           ;; Get the contents of file elems.
+           (when (and filep v)
+             (setq v (with-temp-buffer
+                       (insert-file-contents v)
+                       (buffer-substring
+                        (point-min)
+                        (progn
+                          (goto-char (point-max))
+                          (if (zerop (skip-chars-backward "\n"))
+                              (point)
+                            (1+ (point))))))))
+           (setq results (delq (assoc element results) results))
+           (push (cons element v) results))))
+      ;; Now we have all the styles, so we insert them.
+      (setq name (assq 'name results)
+           address (assq 'address results))
+      (setq results (delq name (delq address results)))
+      (gnus-make-local-hook 'message-setup-hook)
+      (setq results (sort results (lambda (x y)
+                                   (string-lessp (car x) (car y)))))
+      (dolist (result results)
+       (add-hook 'message-setup-hook
+                 (cond
+                  ((eq 'eval (car result))
+                   'ignore)
+                  ((eq 'body (car result))
+                   `(lambda ()
+                      (save-excursion
+                        (message-goto-body)
+                        (insert ,(cdr result)))))
+                  ((eq 'signature (car result))
+                   (set (make-local-variable 'message-signature) nil)
+                   (set (make-local-variable 'message-signature-file) nil)
+                   (if (not (cdr result))
+                       'ignore
+                     `(lambda ()
+                        (save-excursion
+                          (let ((message-signature ,(cdr result)))
+                            (when message-signature
+                              (message-insert-signature)))))))
+                  (t
+                   (let ((header
+                          (if (symbolp (car result))
+                              (capitalize (symbol-name (car result)))
+                            (car result))))
+                     `(lambda ()
+                        (save-excursion
+                          (message-remove-header ,header)
+                          (let ((value ,(cdr result)))
+                            (when value
+                              (message-goto-eoh)
+                              (insert ,header ": " value)
+                              (unless (bolp)
+                                (insert "\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))
+                    (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"))))
+                 nil 'local)))))
+
+;;; Allow redefinition of functions.
+
+(gnus-ems-redefine)
+
+(provide 'gnus-msg)
+
+;;; gnus-msg.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-notifications.el b/xemacs-packages/gnus/lisp/gnus-notifications.el
new file mode 100644 (file)
index 0000000..54a75b6
--- /dev/null
@@ -0,0 +1,201 @@
+;; gnus-notifications.el -- Send notification on new message in Gnus
+
+;; Copyright (C) 2012-2016 Free Software Foundation, Inc.
+
+;; Author: Julien Danjou <julien@danjou.info>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This implements notifications using `notifications-notify' on new
+;; messages received.
+;; Use (add-hook 'gnus-after-getting-new-news-hook 'gnus-notifications)
+;; to get notifications just after getting the new news.
+
+;;; Code:
+
+(ignore-errors
+  (require 'notifications))
+(require 'gnus-sum)
+(require 'gnus-group)
+(require 'gnus-int)
+(require 'gnus-art)
+(require 'gnus-util)
+(ignore-errors
+  (require 'google-contacts))        ; Optional
+(require 'gnus-fun)
+
+(defgroup gnus-notifications nil
+  "Send notifications on new message in Gnus."
+  :version "24.3"
+  :group 'gnus)
+
+(defcustom gnus-notifications-use-google-contacts t
+  "Use Google Contacts to retrieve photo."
+  :type 'boolean
+  :group 'gnus-notifications)
+
+(defcustom gnus-notifications-use-gravatar t
+  "Use Gravatar to retrieve photo."
+  :type 'boolean
+  :group 'gnus-notifications)
+
+(defcustom gnus-notifications-minimum-level 1
+  "Minimum group level the message should have to be notified.
+Any message in a group that has a greater value than this will
+not get notifications."
+  :type 'integer
+  :group 'gnus-notifications)
+
+(defcustom gnus-notifications-timeout nil
+  "Timeout used for notifications sent via `notifications-notify'."
+  :type '(choice (const :tag "Server default" nil)
+                 (integer :tag "Milliseconds"))
+  :group 'gnus-notifications)
+
+(defvar gnus-notifications-sent nil
+  "Notifications already sent.")
+
+(defvar gnus-notifications-id-to-msg nil
+  "Map notifications ids to messages.")
+
+(defun gnus-notifications-action (id key)
+  (let ((group-article (assoc id gnus-notifications-id-to-msg)))
+    (when group-article
+      (let ((group (cadr group-article))
+            (article (nth 2 group-article)))
+        (cond ((string= key "read")
+               (gnus-fetch-group group (list article))
+               (gnus-select-frame-set-input-focus (selected-frame)))
+              ((string= key "mark-read")
+               (gnus-update-read-articles
+                group
+                (delq article (gnus-list-of-unread-articles group)))
+               ;; gnus-group-refresh-group
+               (gnus-group-update-group group)))))))
+
+(defun gnus-notifications-notify (from subject photo-file)
+  "Send a notification about a new mail.
+Return a notification id if any, or t on success."
+  (if (fboundp 'notifications-notify)
+      (gnus-funcall-no-warning
+       'notifications-notify
+       :title from
+       :body subject
+       :actions '("read" "Read" "mark-read" "Mark As Read")
+       :on-action 'gnus-notifications-action
+       :app-icon (gnus-funcall-no-warning
+                  'image-search-load-path "gnus/gnus.png")
+       :image-path photo-file
+       :app-name "Gnus"
+       :category "email.arrived"
+       :timeout gnus-notifications-timeout)
+    (message "New message from %s: %s" from subject)
+    ;; Don't return an id
+    t))
+
+(declare-function gravatar-retrieve-synchronously "gravatar.el"
+                 (mail-address))
+
+(defun gnus-notifications-get-photo (mail-address)
+  "Get photo for mail address."
+  (let ((google-photo (when (and gnus-notifications-use-google-contacts
+                                 (fboundp 'google-contacts-get-photo))
+                        (ignore-errors
+                          (gnus-funcall-no-warning
+                          'google-contacts-get-photo mail-address)))))
+    (if google-photo
+        google-photo
+      (when gnus-notifications-use-gravatar
+        (let ((gravatar (ignore-errors
+                          (gravatar-retrieve-synchronously mail-address))))
+          (if (eq gravatar 'error)
+              nil
+            (plist-get (cdr gravatar) :data)))))))
+
+(defun gnus-notifications-get-photo-file (mail-address)
+  "Get a temporary file with an image for MAIL-ADDRESS.
+You have to delete the temporary image yourself using
+`delete-image'.
+
+Returns nil if no image found."
+  (let ((photo (gnus-notifications-get-photo mail-address)))
+    (when photo
+      (let ((photo-file (make-temp-file "gnus-notifications-photo-"))
+            (coding-system-for-write 'binary))
+        (with-temp-file photo-file
+          (insert photo))
+        photo-file))))
+
+;;;###autoload
+(defun gnus-notifications ()
+  "Send a notification on new message.
+This check for new messages that are in group with a level lower
+or equal to `gnus-notifications-minimum-level' and send a
+notification using `notifications-notify' for it.
+
+This is typically a function to add in
+`gnus-after-getting-new-news-hook'"
+  (dolist (entry gnus-newsrc-alist)
+    (let ((group (car entry)))
+      ;; Check that the group level is less than
+      ;; `gnus-notifications-minimum-level' and the the group has unread
+      ;; messages.
+      (when (and (<= (gnus-group-level group) gnus-notifications-minimum-level)
+                 (let ((unread (gnus-group-unread group)))
+                   (and (numberp unread)
+                        (> unread 0))))
+        ;; Each group should have an entry in the `gnus-notifications-sent'
+        ;; alist. If not, we add one at this time.
+        (let ((group-notifications (or (assoc group gnus-notifications-sent)
+                                       ;; Nothing, add one and return it.
+                                       (assoc group
+                                              (add-to-list
+                                               'gnus-notifications-sent
+                                               (cons group nil))))))
+          (dolist (article (gnus-list-of-unread-articles group))
+            ;; Check if the article already has been notified
+            (unless (memq article (cdr group-notifications))
+              (with-current-buffer nntp-server-buffer
+                (gnus-request-head article group)
+                (article-decode-encoded-words) ; to decode mail addresses, subjects, etc
+                (let* ((address-components (mail-extract-address-components
+                                            (or (mail-fetch-field "From") "")))
+                       (address (cadr address-components)))
+                  ;; Ignore mails from ourselves
+                  (unless (and gnus-ignored-from-addresses
+                               address
+                               (gnus-string-match-p gnus-ignored-from-addresses
+                                                    address))
+                    (let* ((photo-file (gnus-notifications-get-photo-file address))
+                           (notification-id (gnus-notifications-notify
+                                             (or (car address-components) address)
+                                             (mail-fetch-field "Subject")
+                                             photo-file)))
+                      (when notification-id
+                        ;; Register that we did notify this message
+                        (setcdr group-notifications (cons article (cdr group-notifications)))
+                        (unless (eq notification-id t)
+                          ;; Register the notification id for later actions
+                          (add-to-list 'gnus-notifications-id-to-msg (list notification-id group article))))
+                      (when photo-file
+                        (delete-file photo-file)))))))))))))
+
+(provide 'gnus-notifications)
+
+;;; gnus-notifications.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-picon.el b/xemacs-packages/gnus/lisp/gnus-picon.el
new file mode 100644 (file)
index 0000000..6365e8e
--- /dev/null
@@ -0,0 +1,319 @@
+;;; gnus-picon.el --- displaying pretty icons in Gnus
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: news xpm annotation glyph faces
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; 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
+;;
+;; Original implementation by Wes Hardaker <hardaker@ece.ucdavis.edu>.
+;;
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'gnus)
+(require 'gnus-art)
+
+;;; User variables:
+
+(defcustom gnus-picon-news-directories '("news")
+  "*List of directories to search for newsgroups faces."
+  :type '(repeat string)
+  :group 'gnus-picon)
+
+(defcustom gnus-picon-user-directories '("users" "usenix" "local" "misc")
+  "*List of directories to search for user faces."
+  :type '(repeat string)
+  :group 'gnus-picon)
+
+(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 'gnus-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 'gnus-picon)
+
+(defcustom gnus-picon-properties '(:color-symbols (("None" . "white")))
+  "List of image properties applied to picons."
+  :type 'sexp
+  :version "24.3"
+  :group 'gnus-picon)
+
+(defcustom gnus-picon-style 'inline
+  "How should picons be displayed.
+If `inline', the textual representation is replaced.  If `right', picons are
+added right to the textual representation."
+  ;; FIXME: `right' needs improvement for XEmacs.
+  :type '(choice (const inline)
+                (const right))
+  :group 'gnus-picon)
+
+(defcustom gnus-picon-inhibit-top-level-domains t
+  "If non-nil, don't piconify top-level domains.
+These are often not very interesting."
+  :version "24.1"
+  :type 'boolean
+  :group 'gnus-picon)
+
+;;; Internal variables:
+
+(defvar gnus-picon-glyph-alist nil
+  "Picon glyphs cache.
+List of pairs (KEY . GLYPH) where KEY is either a filename or an URL.")
+(defvar gnus-picon-cache nil)
+
+;;; Functions:
+
+(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* ((address (gnus-picon-split-address address))
+        (user (pop address))
+        (faddress address)
+        database directory result instance base)
+    (catch 'found
+      (dolist (database gnus-picon-databases)
+       (dolist (directory directories)
+         (setq address faddress
+               base (expand-file-name directory database))
+         (while address
+           (when (setq result (gnus-picon-find-image
+                               (concat base "/" (mapconcat 'downcase
+                                                           (reverse address)
+                                                           "/")
+                                       "/" (downcase user) "/")))
+             (throw 'found result))
+           (if exact
+               (setq address nil)
+             (pop address)))
+         ;; Kludge to search MISC as well.  But not in "news".
+         (unless (string= directory "news")
+           (when (setq result (gnus-picon-find-image
+                               (concat base "/MISC/" user "/")))
+             (throw 'found result))))))))
+
+(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 &optional nostring)
+  "Insert GLYPH into the buffer.
+GLYPH can be either a glyph or a string.  When NOSTRING, no textual
+replacement is added."
+  ;; Using NOSTRING prevents wrong BBDB entries with `gnus-picon-style' set to
+  ;; 'right.
+  (if (stringp glyph)
+      (insert glyph)
+    (gnus-add-wash-type category)
+    (gnus-add-image category (car glyph))
+    (gnus-put-image (car glyph) (unless nostring (cdr glyph)) category)))
+
+(defun gnus-picon-create-glyph (file)
+  (or (cdr (assoc file gnus-picon-glyph-alist))
+      (cdar (push (cons file (apply 'gnus-create-image
+                                   file nil nil
+                                   gnus-picon-properties))
+                 gnus-picon-glyph-alist))))
+
+;;; Functions that does picon transformations:
+
+(declare-function image-size "image.c" (spec &optional pixels frame))
+
+(defun gnus-picon-transform-address (header category)
+  (gnus-with-article-headers
+   (let ((addresses
+         (mail-header-parse-addresses
+          ;; mail-header-parse-addresses does not work (reliably) on
+          ;; decoded headers.
+          (or
+           (ignore-errors
+            (mail-encode-encoded-word-string
+             (or (mail-fetch-field header) "")))
+           (mail-fetch-field header))))
+        spec file point cache len)
+     (dolist (address addresses)
+       (setq address (car address))
+       (when (and (stringp address)
+                 (setq spec (gnus-picon-split-address address)))
+        (if (setq cache (cdr (assoc address gnus-picon-cache)))
+            (setq spec cache)
+          (when (setq file (or (gnus-picon-find-face
+                                address gnus-picon-user-directories)
+                               (gnus-picon-find-face
+                                (concat "unknown@"
+                                        (mapconcat
+                                         'identity (cdr spec) "."))
+                                gnus-picon-user-directories)))
+            (setcar spec (cons (gnus-picon-create-glyph file)
+                               (car spec))))
+
+          (dotimes (i (- (length spec)
+                         (if gnus-picon-inhibit-top-level-domains
+                             2 1)))
+            (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)))))
+          (setq spec (nreverse spec))
+          (push (cons address spec) gnus-picon-cache))
+
+        (gnus-article-goto-header header)
+        (mail-header-narrow-to-field)
+        (case gnus-picon-style
+              (right
+               (when (= (length addresses) 1)
+                 (setq len (apply '+ (mapcar (lambda (x)
+                                               (condition-case nil
+                                                   (car (image-size (car x)))
+                                                 (error 0))) spec)))
+                 (when (> len 0)
+                   (goto-char (point-at-eol))
+                   (insert (propertize
+                            " " 'display
+                            (cons 'space
+                                  (list :align-to (- (window-width) 1 len))))))
+                 (goto-char (point-at-eol))
+                 (setq point (point-at-eol))
+                 (dolist (image spec)
+                   (unless (stringp image)
+                     (goto-char point)
+                     (gnus-picon-insert-glyph image category 'nostring)))))
+              (inline
+                (when (search-forward address nil t)
+                  (delete-region (match-beginning 0) (match-end 0))
+                  (setq point (point))
+                  (while spec
+                    (goto-char point)
+                    (if (> (length spec) 2)
+                        (insert ".")
+                      (if (= (length spec) 2)
+                          (insert "@")))
+                    (gnus-picon-insert-glyph (pop spec) category))))))))))
+
+(defun gnus-picon-transform-newsgroups (header)
+  (interactive)
+  (gnus-with-article-headers
+   (gnus-article-goto-header header)
+   (mail-header-narrow-to-field)
+   (let ((groups (message-tokenize-header (mail-fetch-field header)))
+        spec file point)
+     (dolist (group groups)
+       (unless (setq spec (cdr (assoc group gnus-picon-cache)))
+        (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)))))
+        (push (cons group spec) gnus-picon-cache))
+       (when (search-forward group nil t)
+        (delete-region (match-beginning 0) (match-end 0))
+        (save-restriction
+          (narrow-to-region (point) (point))
+          (while spec
+            (goto-char (point-min))
+            (if (> (length spec) 1)
+                (insert "."))
+            (gnus-picon-insert-glyph (pop spec) 'newsgroups-picon))
+          (goto-char (point-max))))))))
+
+;;; Commands:
+
+;; #### NOTE: the test for buffer-read-only is the same as in
+;; article-display-[x-]face. See the comment up there.
+
+;;;###autoload
+(defun gnus-treat-from-picon ()
+  "Display picons in the From header.
+If picons are already displayed, remove them."
+  (interactive)
+  (let ((wash-picon-p buffer-read-only))
+    (gnus-with-article-buffer
+     (if (and wash-picon-p (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)
+  (let ((wash-picon-p buffer-read-only))
+    (gnus-with-article-buffer
+     (if (and wash-picon-p (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)
+  (let ((wash-picon-p buffer-read-only))
+    (gnus-with-article-buffer
+     (if (and wash-picon-p (memq 'newsgroups-picon gnus-article-wash-types))
+        (gnus-delete-images 'newsgroups-picon)
+       (gnus-picon-transform-newsgroups "newsgroups")
+       (gnus-picon-transform-newsgroups "followup-to")))))
+
+(provide 'gnus-picon)
+
+;;; gnus-picon.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-range.el b/xemacs-packages/gnus/lisp/gnus-range.el
new file mode 100644 (file)
index 0000000..5cc8367
--- /dev/null
@@ -0,0 +1,679 @@
+;;; gnus-range.el --- range and sequence functions for Gnus
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+;;; List and range functions
+
+(defsubst gnus-range-normalize (range)
+  "Normalize RANGE.
+If RANGE is a single range, return (RANGE). Otherwise, return RANGE."
+  (if (listp (cdr-safe range)) range (list range)))
+
+(defun gnus-last-element (list)
+  "Return last element of LIST."
+  (while (cdr list)
+    (setq list (cdr list)))
+  (car list))
+
+(defun gnus-copy-sequence (list)
+  "Do a complete, total copy of a list."
+  (let (out)
+    (while (consp list)
+      (if (consp (car list))
+         (push (gnus-copy-sequence (pop list)) out)
+       (push (pop list) out)))
+    (if list
+       (nconc (nreverse out) list)
+      (nreverse out))))
+
+(defun gnus-set-difference (list1 list2)
+  "Return a list of elements of LIST1 that do not appear in LIST2."
+  (let ((hash2 (make-hash-table :test 'eq))
+        (result nil))
+    (dolist (elt list2) (puthash elt t hash2))
+    (dolist (elt list1)
+      (unless (gethash elt hash2)
+        (setq result (cons elt result))))
+    (nreverse result)))
+
+(defun gnus-range-nconcat (&rest ranges)
+  "Return a range comprising all the RANGES, which are pre-sorted.
+RANGES will be destructively altered."
+  (setq ranges (delete nil ranges))
+  (let* ((result (gnus-range-normalize (pop ranges)))
+        (last (last result)))
+    (dolist (range ranges)
+      (setq range (gnus-range-normalize range))
+      ;; Normalize the single-number case, so that we don't need to
+      ;; special-case that so much.
+      (when (numberp (car last))
+       (setcar last (cons (car last) (car last))))
+      (when (numberp (car range))
+       (setcar range (cons (car range) (car range))))
+      (if (= (1+ (cdar last)) (caar range))
+         (progn
+           (setcdr (car last) (cdar range))
+           (setcdr last (cdr range)))
+       (setcdr last range)
+       ;; Denormalize back, since we couldn't join the ranges up.
+       (when (= (caar range) (cdar range))
+         (setcar range (caar range)))
+       (when (= (caar last) (cdar last))
+         (setcar last (caar last))))
+      (setq last (last last)))
+    (if (and (consp (car result))
+            (= (length result) 1))
+       (car result)
+      result)))
+
+(defun gnus-range-difference (range1 range2)
+  "Return the range of elements in RANGE1 that do not appear in RANGE2.
+Both ranges must be in ascending order."
+  (setq range1 (gnus-range-normalize range1))
+  (setq range2 (gnus-range-normalize range2))
+  (let* ((new-range (cons nil (copy-sequence range1)))
+         (r new-range)
+         (safe t))
+    (while (cdr r)
+      (let* ((r1 (cadr r))
+             (r2 (car range2))
+             (min1 (if (numberp r1) r1 (car r1)))
+             (max1 (if (numberp r1) r1 (cdr r1)))
+             (min2 (if (numberp r2) r2 (car r2)))
+             (max2 (if (numberp r2) r2 (cdr r2))))
+
+        (cond ((> min1 max1)
+               ;; Invalid range: may result from overlap condition (below)
+               ;; remove Invalid range
+               (setcdr r (cddr r)))
+              ((and (= min1 max1)
+                    (listp r1))
+               ;; Inefficient representation: may result from overlap condition (below)
+               (setcar (cdr r) min1))
+              ((not min2)
+               ;; All done with range2
+               (setq r nil))
+              ((< max1 min2)
+               ;; No overlap: range1 precedes range2
+               (pop r))
+              ((< max2 min1)
+               ;; No overlap: range2 precedes range1
+               (pop range2))
+              ((and (<= min2 min1) (<= max1 max2))
+               ;; Complete overlap: range1 removed
+               (setcdr r (cddr r)))
+              (t
+               (setcdr r (nconc (list (cons min1 (1- min2)) (cons (1+ max2) max1)) (cddr r)))))))
+    (cdr new-range)))
+
+
+
+;;;###autoload
+(defun gnus-sorted-difference (list1 list2)
+  "Return a list of elements of LIST1 that do not appear in LIST2.
+Both lists have to be sorted over <.
+The tail of LIST1 is not copied."
+  (let (out)
+    (while (and list1 list2)
+      (cond ((= (car list1) (car list2))
+            (setq list1 (cdr list1)
+                  list2 (cdr list2)))
+           ((< (car list1) (car list2))
+            (setq out (cons (car list1) out))
+            (setq list1 (cdr list1)))
+           (t
+            (setq list2 (cdr list2)))))
+    (nconc (nreverse out) list1)))
+
+;;;###autoload
+(defun gnus-sorted-ndifference (list1 list2)
+  "Return a list of elements of LIST1 that do not appear in LIST2.
+Both lists have to be sorted over <.
+LIST1 is modified."
+  (let* ((top (cons nil list1))
+        (prev top))
+    (while (and list1 list2)
+      (cond ((= (car list1) (car list2))
+            (setcdr prev (cdr list1))
+            (setq list1 (cdr list1)
+                  list2 (cdr list2)))
+           ((< (car list1) (car list2))
+            (setq prev list1
+                  list1 (cdr list1)))
+           (t
+            (setq list2 (cdr list2)))))
+    (cdr top)))
+
+;;;###autoload
+(defun gnus-sorted-complement (list1 list2)
+  "Return a list of elements that are in LIST1 or LIST2 but not both.
+Both lists have to be sorted over <."
+  (let (out)
+    (if (or (null list1) (null list2))
+       (or list1 list2)
+      (while (and list1 list2)
+       (cond ((= (car list1) (car list2))
+              (setq list1 (cdr list1)
+                    list2 (cdr list2)))
+             ((< (car list1) (car list2))
+              (setq out (cons (car list1) out))
+              (setq list1 (cdr list1)))
+             (t
+              (setq out (cons (car list2) out))
+              (setq list2 (cdr list2)))))
+      (nconc (nreverse out) (or list1 list2)))))
+
+;;;###autoload
+(defun gnus-intersection (list1 list2)
+  (let ((result nil))
+    (while list2
+      (when (memq (car list2) list1)
+       (setq result (cons (car list2) result)))
+      (setq list2 (cdr list2)))
+    result))
+
+;;;###autoload
+(defun gnus-sorted-intersection (list1 list2)
+  "Return intersection of LIST1 and LIST2.
+LIST1 and LIST2 have to be sorted over <."
+  (let (out)
+    (while (and list1 list2)
+      (cond ((= (car list1) (car list2))
+            (setq out (cons (car list1) out)
+                  list1 (cdr list1)
+                  list2 (cdr list2)))
+           ((< (car list1) (car list2))
+            (setq list1 (cdr list1)))
+           (t
+            (setq list2 (cdr list2)))))
+    (nreverse out)))
+
+;;;###autoload
+(defun gnus-sorted-range-intersection (range1 range2)
+  "Return intersection of RANGE1 and RANGE2.
+RANGE1 and RANGE2 have to be sorted over <."
+  (let* (out
+         (min1 (car range1))
+         (max1 (if (numberp min1)
+                   (if (numberp (cdr range1))
+                       (prog1 (cdr range1)
+                         (setq range1 nil)) min1)
+                 (prog1 (cdr min1)
+                   (setq min1 (car min1)))))
+         (min2 (car range2))
+         (max2 (if (numberp min2)
+                   (if (numberp (cdr range2))
+                       (prog1 (cdr range2)
+                         (setq range2 nil)) min2)
+                 (prog1 (cdr min2)
+                   (setq min2 (car min2))))))
+    (setq range1 (cdr range1)
+          range2 (cdr range2))
+    (while (and min1 min2)
+      (cond ((< max1 min2)              ; range1 precedes range2
+             (setq range1 (cdr range1)
+                   min1 nil))
+            ((< max2 min1)              ; range2 precedes range1
+             (setq range2 (cdr range2)
+                   min2 nil))
+            (t                     ; some sort of overlap is occurring
+             (let ((min (max min1 min2))
+                   (max (min max1 max2)))
+               (setq out (if (= min max)
+                             (cons min out)
+                           (cons (cons min max) out))))
+             (if (< max1 max2)          ; range1 ends before range2
+                 (setq min1 nil)        ; incr range1
+               (setq min2 nil))))       ; incr range2
+      (unless min1
+        (setq min1 (car range1)
+              max1 (if (numberp min1) min1 (prog1 (cdr min1) (setq min1 (car min1))))
+              range1 (cdr range1)))
+      (unless min2
+        (setq min2 (car range2)
+              max2 (if (numberp min2) min2 (prog1 (cdr min2) (setq min2 (car min2))))
+              range2 (cdr range2))))
+    (cond ((cdr out)
+        (nreverse out))
+          ((numberp (car out))
+           out)
+          (t
+           (car out)))))
+
+;;;###autoload
+(defalias 'gnus-set-sorted-intersection 'gnus-sorted-nintersection)
+
+;;;###autoload
+(defun gnus-sorted-nintersection (list1 list2)
+  "Return intersection of LIST1 and LIST2 by modifying cdr pointers of LIST1.
+LIST1 and LIST2 have to be sorted over <."
+  (let* ((top (cons nil list1))
+        (prev top))
+    (while (and list1 list2)
+      (cond ((= (car list1) (car list2))
+            (setq prev list1
+                  list1 (cdr list1)
+                  list2 (cdr list2)))
+           ((< (car list1) (car list2))
+            (setcdr prev (cdr list1))
+            (setq list1 (cdr list1)))
+           (t
+            (setq list2 (cdr list2)))))
+    (setcdr prev nil)
+    (cdr top)))
+
+;;;###autoload
+(defun gnus-sorted-union (list1 list2)
+  "Return union of LIST1 and LIST2.
+LIST1 and LIST2 have to be sorted over <."
+  (let (out)
+    (while (and list1 list2)
+      (cond ((= (car list1) (car list2))
+            (setq out (cons (car list1) out)
+                  list1 (cdr list1)
+                  list2 (cdr list2)))
+           ((< (car list1) (car list2))
+            (setq out (cons (car list1) out)
+                  list1 (cdr list1)))
+           (t
+            (setq out (cons (car list2) out)
+                  list2 (cdr list2)))))
+    (while list1
+      (setq out (cons (car list1) out)
+           list1 (cdr list1)))
+    (while list2
+      (setq out (cons (car list2) out)
+           list2 (cdr list2)))
+    (nreverse out)))
+
+;;;###autoload
+(defun gnus-sorted-nunion (list1 list2)
+  "Return union of LIST1 and LIST2 by modifying cdr pointers of LIST1.
+LIST1 and LIST2 have to be sorted over <."
+  (let* ((top (cons nil list1))
+        (prev top))
+    (while (and list1 list2)
+      (cond ((= (car list1) (car list2))
+            (setq prev list1
+                  list1 (cdr list1)
+                  list2 (cdr list2)))
+           ((< (car list1) (car list2))
+            (setq prev list1
+                  list1 (cdr list1)))
+           (t
+            (setcdr prev (list (car list2)))
+            (setq prev (cdr prev)
+                  list2 (cdr list2))
+            (setcdr prev list1))))
+    (while list2
+      (setcdr prev (list (car list2)))
+      (setq prev (cdr prev)
+           list2 (cdr list2)))
+    (cdr top)))
+
+(defun gnus-compress-sequence (numbers &optional always-list)
+  "Convert sorted list of numbers to a list of ranges or a single range.
+If ALWAYS-LIST is non-nil, this function will always release a list of
+ranges."
+  (let* ((first (car numbers))
+        (last (car numbers))
+        result)
+    (if (null numbers)
+       nil
+      (if (not (listp (cdr numbers)))
+         numbers
+       (while numbers
+         (cond ((= last (car numbers)) nil) ;Omit duplicated number
+               ((= (1+ last) (car numbers)) ;Still in sequence
+                (setq last (car numbers)))
+               (t                      ;End of one sequence
+                (setq result
+                      (cons (if (= first last) first
+                              (cons first last))
+                            result))
+                (setq first (car numbers))
+                (setq last  (car numbers))))
+         (setq numbers (cdr numbers)))
+       (if (and (not always-list) (null result))
+           (if (= first last) (list first) (cons first last))
+         (nreverse (cons (if (= first last) first (cons first last))
+                         result)))))))
+
+(defalias 'gnus-uncompress-sequence 'gnus-uncompress-range)
+(defun gnus-uncompress-range (ranges)
+  "Expand a list of ranges into a list of numbers.
+RANGES is either a single range on the form `(num . num)' or a list of
+these ranges."
+  (let (first last result)
+    (cond
+     ((null ranges)
+      nil)
+     ((not (listp (cdr ranges)))
+      (setq first (car ranges))
+      (setq last (cdr ranges))
+      (while (<= first last)
+       (setq result (cons first result))
+       (setq first (1+ first)))
+      (nreverse result))
+     (t
+      (while ranges
+       (if (atom (car ranges))
+           (when (numberp (car ranges))
+             (setq result (cons (car ranges) result)))
+         (setq first (caar ranges))
+         (setq last  (cdar ranges))
+         (while (<= first last)
+           (setq result (cons first result))
+           (setq first (1+ first))))
+       (setq ranges (cdr ranges)))
+      (nreverse result)))))
+
+(defun gnus-add-to-range (ranges list)
+  "Return a list of ranges that has all articles from both RANGES and LIST.
+Note: LIST has to be sorted over `<'."
+  (if (not ranges)
+      (gnus-compress-sequence list t)
+    (setq list (copy-sequence list))
+    (unless (listp (cdr ranges))
+      (setq ranges (list ranges)))
+    (let ((out ranges)
+         ilist lowest highest temp)
+      (while (and ranges list)
+       (setq ilist list)
+       (setq lowest (or (and (atom (car ranges)) (car ranges))
+                        (caar ranges)))
+       (while (and list (cdr list) (< (cadr list) lowest))
+         (setq list (cdr list)))
+       (when (< (car ilist) lowest)
+         (setq temp list)
+         (setq list (cdr list))
+         (setcdr temp nil)
+         (setq out (nconc (gnus-compress-sequence ilist t) out)))
+       (setq highest (or (and (atom (car ranges)) (car ranges))
+                         (cdar ranges)))
+       (while (and list (<= (car list) highest))
+         (setq list (cdr list)))
+       (setq ranges (cdr ranges)))
+      (when list
+       (setq out (nconc (gnus-compress-sequence list t) out)))
+      (setq out (sort out (lambda (r1 r2)
+                           (< (or (and (atom r1) r1) (car r1))
+                              (or (and (atom r2) r2) (car r2))))))
+      (setq ranges out)
+      (while ranges
+       (if (atom (car ranges))
+           (when (cdr ranges)
+             (if (atom (cadr ranges))
+                 (when (= (1+ (car ranges)) (cadr ranges))
+                   (setcar ranges (cons (car ranges)
+                                        (cadr ranges)))
+                   (setcdr ranges (cddr ranges)))
+               (when (= (1+ (car ranges)) (caadr ranges))
+                 (setcar (cadr ranges) (car ranges))
+                 (setcar ranges (cadr ranges))
+                 (setcdr ranges (cddr ranges)))))
+         (when (cdr ranges)
+           (if (atom (cadr ranges))
+               (when (= (1+ (cdar ranges)) (cadr ranges))
+                 (setcdr (car ranges) (cadr ranges))
+                 (setcdr ranges (cddr ranges)))
+             (when (= (1+ (cdar ranges)) (caadr ranges))
+               (setcdr (car ranges) (cdadr ranges))
+               (setcdr ranges (cddr ranges))))))
+       (setq ranges (cdr ranges)))
+      out)))
+
+(defun gnus-remove-from-range (range1 range2)
+  "Return a range that has all articles from RANGE2 removed from RANGE1.
+The returned range is always a list.  RANGE2 can also be a unsorted
+list of articles.  RANGE1 is modified by side effects, RANGE2 is not
+modified."
+  (if (or (null range1) (null range2))
+      range1
+    (let (out r1 r2 r1_min r1_max r2_min r2_max
+             (range2 (gnus-copy-sequence range2)))
+      (setq range1 (if (listp (cdr range1)) range1 (list range1))
+           range2 (sort (if (listp (cdr range2)) range2 (list range2))
+                        (lambda (e1 e2)
+                          (< (if (consp e1) (car e1) e1)
+                             (if (consp e2) (car e2) e2))))
+           r1 (car range1)
+           r2 (car range2)
+           r1_min (if (consp r1) (car r1) r1)
+           r1_max (if (consp r1) (cdr r1) r1)
+           r2_min (if (consp r2) (car r2) r2)
+           r2_max (if (consp r2) (cdr r2) r2))
+      (while (and range1 range2)
+       (cond ((< r2_max r1_min)        ; r2 < r1
+              (pop range2)
+              (setq r2 (car range2)
+                    r2_min (if (consp r2) (car r2) r2)
+                    r2_max (if (consp r2) (cdr r2) r2)))
+             ((and (<= r2_min r1_min) (<= r1_max r2_max)) ; r2 overlap r1
+              (pop range1)
+              (setq r1 (car range1)
+                    r1_min (if (consp r1) (car r1) r1)
+                    r1_max (if (consp r1) (cdr r1) r1)))
+             ((and (<= r2_min r1_min) (<= r2_max r1_max)) ; r2 overlap min r1
+              (pop range2)
+              (setq r1_min (1+ r2_max)
+                    r2 (car range2)
+                    r2_min (if (consp r2) (car r2) r2)
+                    r2_max (if (consp r2) (cdr r2) r2)))
+             ((and (<= r1_min r2_min) (<= r2_max r1_max)) ; r2 contained in r1
+              (if (eq r1_min (1- r2_min))
+                  (push r1_min out)
+                (push (cons r1_min (1- r2_min)) out))
+              (pop range2)
+              (if (< r2_max r1_max)    ; finished with r1?
+                  (setq r1_min (1+ r2_max))
+                (pop range1)
+                (setq r1 (car range1)
+                      r1_min (if (consp r1) (car r1) r1)
+                      r1_max (if (consp r1) (cdr r1) r1)))
+              (setq r2 (car range2)
+                    r2_min (if (consp r2) (car r2) r2)
+                    r2_max (if (consp r2) (cdr r2) r2)))
+             ((and (<= r2_min r1_max) (<= r1_max r2_max)) ; r2 overlap max r1
+              (if (eq r1_min (1- r2_min))
+                  (push r1_min out)
+                (push (cons r1_min (1- r2_min)) out))
+              (pop range1)
+              (setq r1 (car range1)
+                    r1_min (if (consp r1) (car r1) r1)
+                    r1_max (if (consp r1) (cdr r1) r1)))
+             ((< r1_max r2_min)        ; r2 > r1
+              (pop range1)
+              (if (eq r1_min r1_max)
+                  (push r1_min out)
+                (push (cons r1_min r1_max) out))
+              (setq r1 (car range1)
+                    r1_min (if (consp r1) (car r1) r1)
+                    r1_max (if (consp r1) (cdr r1) r1)))))
+      (when r1
+       (if (eq r1_min r1_max)
+           (push r1_min out)
+         (push (cons r1_min r1_max) out))
+       (pop range1))
+      (while range1
+       (push (pop range1) out))
+      (nreverse out))))
+
+(defun gnus-member-of-range (number ranges)
+  (if (not (listp (cdr ranges)))
+      (and (>= number (car ranges))
+          (<= number (cdr ranges)))
+    (let ((not-stop t))
+      (while (and ranges
+                 (if (numberp (car ranges))
+                     (>= number (car ranges))
+                   (>= number (caar ranges)))
+                 not-stop)
+       (when (if (numberp (car ranges))
+                 (= number (car ranges))
+               (and (>= number (caar ranges))
+                    (<= number (cdar ranges))))
+         (setq not-stop nil))
+       (setq ranges (cdr ranges)))
+      (not not-stop))))
+
+(defun gnus-list-range-intersection (list ranges)
+  "Return a list of numbers in LIST that are members of RANGES.
+LIST is a sorted list."
+  (setq ranges (gnus-range-normalize ranges))
+  (let (number result)
+    (while (setq number (pop list))
+      (while (and ranges
+                 (if (numberp (car ranges))
+                     (< (car ranges) number)
+                   (< (cdar ranges) number)))
+       (setq ranges (cdr ranges)))
+      (when (and ranges
+                (if (numberp (car ranges))
+                     (= (car ranges) number)
+                  ;; (caar ranges) <= number <= (cdar ranges)
+                  (>= number (caar ranges))))
+       (push number result)))
+    (nreverse result)))
+
+(defalias 'gnus-inverse-list-range-intersection 'gnus-list-range-difference)
+
+(defun gnus-list-range-difference (list ranges)
+  "Return a list of numbers in LIST that are not members of RANGES.
+LIST is a sorted list."
+  (setq ranges (gnus-range-normalize ranges))
+  (let (number result)
+    (while (setq number (pop list))
+      (while (and ranges
+                 (if (numberp (car ranges))
+                     (< (car ranges) number)
+                   (< (cdar ranges) number)))
+       (setq ranges (cdr ranges)))
+      (when (or (not ranges)
+               (if (numberp (car ranges))
+                   (not (= (car ranges) number))
+                 ;; not ((caar ranges) <= number <= (cdar ranges))
+                 (< number (caar ranges))))
+       (push number result)))
+    (nreverse result)))
+
+(defun gnus-range-length (range)
+  "Return the length RANGE would have if uncompressed."
+  (cond
+   ((null range)
+    0)
+   ((not (listp (cdr range)))
+    (- (cdr range) (car range) -1))
+   (t
+    (let ((sum 0))
+      (dolist (x range sum)
+       (setq sum
+             (+ sum (if (consp x) (- (cdr x) (car x) -1) 1))))))))
+
+(defun gnus-range-add (range1 range2)
+  "Add RANGE2 to RANGE1 (nondestructively)."
+  (unless (listp (cdr range1))
+    (setq range1 (list range1)))
+  (unless (listp (cdr range2))
+    (setq range2 (list range2)))
+  (let ((item1 (pop range1))
+       (item2 (pop range2))
+       range item selector)
+    (while (or item1 item2)
+      (setq selector
+           (cond
+            ((null item1) nil)
+            ((null item2) t)
+            ((and (numberp item1) (numberp item2)) (< item1 item2))
+            ((numberp item1) (< item1 (car item2)))
+            ((numberp item2) (< (car item1) item2))
+            (t (< (car item1) (car item2)))))
+      (setq item
+           (or
+            (let ((tmp1 item) (tmp2 (if selector item1 item2)))
+              (cond
+               ((null tmp1) tmp2)
+               ((null tmp2) tmp1)
+               ((and (numberp tmp1) (numberp tmp2))
+                (cond
+                 ((eq tmp1 tmp2) tmp1)
+                 ((eq (1+ tmp1) tmp2) (cons tmp1 tmp2))
+                 ((eq (1+ tmp2) tmp1) (cons tmp2 tmp1))
+                 (t nil)))
+               ((numberp tmp1)
+                (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
+                 ((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))
+                        (max (cdr tmp1) (cdr tmp2))))))
+            (progn
+              (if item (push item range))
+              (if selector item1 item2))))
+      (if selector
+         (setq item1 (pop range1))
+       (setq item2 (pop range2))))
+    (if item (push item range))
+    (reverse range)))
+
+;;;###autoload
+(defun gnus-add-to-sorted-list (list num)
+  "Add NUM into sorted LIST by side effect."
+  (let* ((top (cons nil list))
+        (prev top))
+    (while (and list (< (car list) num))
+      (setq prev list
+           list (cdr list)))
+    (unless (eq (car list) num)
+      (setcdr prev (cons num list)))
+    (cdr top)))
+
+(defun gnus-range-map (func range)
+  "Apply FUNC to each value contained by RANGE."
+  (setq range (gnus-range-normalize range))
+  (while range
+    (let ((span (pop range)))
+      (if (numberp span)
+          (funcall func span)
+        (let ((first (car span))
+              (last (cdr span)))
+          (while (<= first last)
+            (funcall func first)
+            (setq first (1+ first))))))))
+
+(provide 'gnus-range)
+
+;;; gnus-range.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-registry.el b/xemacs-packages/gnus/lisp/gnus-registry.el
new file mode 100644 (file)
index 0000000..74e2b82
--- /dev/null
@@ -0,0 +1,1258 @@
+;;; gnus-registry.el --- article registry for Gnus
+
+;; Copyright (C) 2002-2016 Free Software Foundation, Inc.
+
+;; Author: Ted Zlatanov <tzz@lifelogs.com>
+;; Keywords: news registry
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This is the gnus-registry.el package, which works with all
+;; Gnus backends, not just nnmail.  The major issue is that it
+;; doesn't go across backends, so for instance if an article is in
+;; nnml:sys and you see a reference to it in nnimap splitting, the
+;; article will end up in nnimap:sys
+
+;; gnus-registry.el intercepts article respooling, moving, deleting,
+;; and copying for all backends.  If it doesn't work correctly for
+;; you, submit a bug report and I'll be glad to fix it.  It needs
+;; better documentation in the manual (also on my to-do list).
+
+;; If you want to track recipients (and you should to make the
+;; gnus-registry splitting work better), you need the To and Cc
+;; headers collected by Gnus.  Note that in more recent Gnus versions
+;; this is already the case: look at `gnus-extra-headers' to be sure.
+
+;; ;;; you may also want Gcc Newsgroups Keywords X-Face
+;; (add-to-list 'gnus-extra-headers 'To)
+;; (add-to-list 'gnus-extra-headers 'Cc)
+;; (setq nnmail-extra-headers gnus-extra-headers)
+
+;; Put this in your startup file (~/.gnus.el for instance) or use Customize:
+
+;; (setq gnus-registry-max-entries 2500
+;;       gnus-registry-track-extra '(sender subject recipient))
+
+;; (gnus-registry-initialize)
+
+;; Then use this in your fancy-split:
+
+;; (: gnus-registry-split-fancy-with-parent)
+
+;; You should also consider using the nnregistry backend to look up
+;; articles.  See the Gnus manual for more information.
+
+;; Finally, you can put %uM in your summary line format to show the
+;; registry marks if you do this:
+
+;; show the marks as single characters (see the :char property in
+;; `gnus-registry-marks'):
+;; (defalias 'gnus-user-format-function-M 'gnus-registry-article-marks-to-chars)
+
+;; show the marks by name (see `gnus-registry-marks'):
+;; (defalias 'gnus-user-format-function-M 'gnus-registry-article-marks-to-names)
+
+;; TODO:
+
+;; - get the correct group on spool actions
+
+;; - articles that are spooled to a different backend should be moved
+;;   after splitting
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'gnus)
+(require 'gnus-int)
+(require 'gnus-sum)
+(require 'gnus-art)
+(require 'gnus-util)
+(require 'nnmail)
+(require 'easymenu)
+(require 'registry)
+
+;; Silence XEmacs byte compiler, which will otherwise complain about
+;; call to `eieio-persistent-read'.
+(when (featurep 'xemacs)
+   (byte-compiler-options
+     (warnings (- callargs))))
+
+(defvar gnus-adaptive-word-syntax-table)
+
+(defvar gnus-registry-dirty t
+ "Boolean set to t when the registry is modified.")
+
+(defgroup gnus-registry nil
+  "The Gnus registry."
+  :version "22.1"
+  :group 'gnus)
+
+(defvar gnus-registry-marks
+  '((Important
+     :char ?i
+     :image "summary_important")
+    (Work
+     :char ?w
+     :image "summary_work")
+    (Personal
+     :char ?p
+     :image "summary_personal")
+    (To-Do
+     :char ?t
+     :image "summary_todo")
+    (Later
+     :char ?l
+     :image "summary_later"))
+
+  "List of registry marks and their options.
+
+`gnus-registry-mark-article' will offer symbols from this list
+for completion.
+
+Each entry must have a character to be useful for summary mode
+line display and for keyboard shortcuts.
+
+Each entry must have an image string to be useful for visual
+display.")
+
+(defcustom gnus-registry-default-mark 'To-Do
+  "The default mark.  Should be a valid key for `gnus-registry-marks'."
+  :group 'gnus-registry
+  :type 'symbol)
+
+(defcustom gnus-registry-unfollowed-addresses
+  (list (regexp-quote user-mail-address))
+  "List of addresses that gnus-registry-split-fancy-with-parent won't trace.
+The addresses are matched, they don't have to be fully qualified.
+In the messages, these addresses can be the sender or the
+recipients."
+  :version "24.1"
+  :group 'gnus-registry
+  :type '(repeat regexp))
+
+(defcustom gnus-registry-unfollowed-groups
+  '("delayed$" "drafts$" "queue$" "INBOX$" "^nnmairix:" "archive")
+  "List of groups that gnus-registry-split-fancy-with-parent won't return.
+The group names are matched, they don't have to be fully
+qualified.  This parameter tells the Gnus registry 'never split a
+message into a group that matches one of these, regardless of
+references.'
+
+nnmairix groups are specifically excluded because they are ephemeral."
+  :group 'gnus-registry
+  :type '(repeat regexp))
+
+(defcustom gnus-registry-install 'ask
+  "Whether the registry should be installed."
+  :group 'gnus-registry
+  :type '(choice (const :tag "Never Install" nil)
+                 (const :tag "Always Install" t)
+                 (const :tag "Ask Me" ask)))
+
+(defvar gnus-registry-enabled nil)
+
+(defvar gnus-summary-misc-menu) ;; Avoid byte compiler warning.
+
+(defvar gnus-registry-misc-menus nil)   ; ugly way to keep the menus
+
+(make-obsolete-variable 'gnus-registry-clean-empty nil "23.4")
+(make-obsolete-variable 'gnus-registry-use-long-group-names nil "23.4")
+(make-obsolete-variable 'gnus-registry-max-track-groups nil "23.4")
+(make-obsolete-variable 'gnus-registry-entry-caching nil "23.4")
+(make-obsolete-variable 'gnus-registry-trim-articles-without-groups nil "23.4")
+;; FIXME it was simply deleted.
+(make-obsolete-variable 'gnus-registry-max-pruned-entries nil "25.1")
+
+(defcustom gnus-registry-track-extra '(subject sender recipient)
+  "Whether the registry should track extra data about a message.
+The subject, recipients (To: and Cc:), and Sender (From:) headers
+are tracked this way by default."
+  :group 'gnus-registry
+  :type
+  '(set :tag "Tracking choices"
+    (const :tag "Track by subject (Subject: header)" subject)
+    (const :tag "Track by recipient (To: and Cc: headers)" recipient)
+    (const :tag "Track by sender (From: header)"  sender)))
+
+(defcustom gnus-registry-split-strategy nil
+  "The splitting strategy applied to the keys in `gnus-registry-track-extra'.
+
+Given a set of unique found groups G and counts for each element
+of G, and a key K (typically `sender' or `subject'):
+
+When nil, if G has only one element, use it.  Otherwise give up.
+This is the fastest but also least useful strategy.
+
+When `majority', use the majority by count.  So if there is a
+group with the most articles counted by K, use that.  Ties are
+resolved in no particular order, simply the first one found wins.
+This is the slowest strategy but also the most accurate one.
+
+When `first', the first element of G wins.  This is fast and
+should be OK if your senders and subjects don't \"bleed\" across
+groups."
+  :group 'gnus-registry
+  :type
+  '(choice :tag "Splitting strategy"
+           (const :tag "Only use single choices, discard multiple matches" nil)
+           (const :tag "Majority of matches wins" majority)
+           (const :tag "First found wins"  first)))
+
+(defcustom gnus-registry-minimum-subject-length 5
+  "The minimum length of a subject before it's considered trackable."
+  :group 'gnus-registry
+  :type 'integer)
+
+(defcustom gnus-registry-extra-entries-precious '(mark)
+  "What extra keys are precious, meaning entries with them won't get pruned.
+By default, 'mark is included, so articles with marks are
+considered precious.
+
+Before you save the Gnus registry, it's pruned.  Any entries with
+keys in this list will not be pruned.  All other entries go to
+the Bit Bucket."
+  :group 'gnus-registry
+  :type '(repeat symbol))
+
+(defcustom gnus-registry-cache-file
+  (nnheader-concat
+   (or gnus-dribble-directory gnus-home-directory "~/")
+   ".gnus.registry.eieio")
+  "File where the Gnus registry will be stored."
+  :group 'gnus-registry
+  :type 'file)
+
+(defcustom gnus-registry-max-entries nil
+  "Maximum number of entries in the registry, nil for unlimited."
+  :group 'gnus-registry
+  :type '(radio (const :format "Unlimited " nil)
+                (integer :format "Maximum number: %v")))
+
+(defcustom gnus-registry-prune-factor 0.1
+  "When pruning, try to prune back to this factor less than the maximum size.
+
+In order to prevent constant pruning, we prune back to a number
+somewhat less than the maximum size.  This option controls
+exactly how much less.  For example, given a maximum size of
+50000 and a prune factor of 0.1, the pruning process will try to
+cut the registry back to \(- 50000 \(* 50000 0.1)) -> 45000
+entries.  The pruning process is constrained by the presence of
+\"precious\" entries."
+  :version "25.1"
+  :group 'gnus-registry
+  :type 'float)
+
+(defcustom gnus-registry-default-sort-function
+  #'gnus-registry-sort-by-creation-time
+  "Sort function to use when pruning the registry.
+Entries that sort to the front of the list are pruned first.
+This can slow pruning down.  Set to nil to perform no sorting."
+  :version "25.1"
+  :group 'gnus-registry
+  :type '(choice (const :tag "No sorting" nil) function))
+
+(defun gnus-registry-sort-by-creation-time (l r)
+  "Sort older entries to front of list."
+  ;; Pruning starts from the front of the list.
+  (time-less-p
+   (cadr (assq 'creation-time r))
+   (cadr (assq 'creation-time l))))
+
+(defun gnus-registry-fixup-registry (db)
+  (when db
+    (let ((old (oref db tracked)))
+      (setf (oref db precious)
+            (append gnus-registry-extra-entries-precious
+                    '()))
+      (setf (oref db max-size)
+            (or gnus-registry-max-entries
+                most-positive-fixnum))
+      (setf (oref db prune-factor)
+            (or gnus-registry-prune-factor
+               0.1))
+      (setf (oref db tracked)
+            (append gnus-registry-track-extra
+                    '(mark group keyword)))
+      (when (not (equal old (oref db tracked)))
+        (gnus-message 9 "Reindexing the Gnus registry (tracked change)")
+        (registry-reindex db))))
+  db)
+
+(defun gnus-registry-make-db (&optional file)
+  (interactive "fGnus registry persistence file: \n")
+  (gnus-registry-fixup-registry
+   (make-instance 'registry-db
+                  :file (or file gnus-registry-cache-file)
+                  ;; these parameters are set in `gnus-registry-fixup-registry'
+                  :max-size most-positive-fixnum
+                  :version registry-db-version
+                  :precious nil
+                  :tracked nil)))
+
+(defvar gnus-registry-db (gnus-registry-make-db)
+  "The article registry by Message ID.  See `registry-db'.")
+
+;; top-level registry data management
+(defun gnus-registry-remake-db (&optional forsure)
+  "Remake the registry database after customization.
+This is not required after changing `gnus-registry-cache-file'."
+  (interactive (list (y-or-n-p "Remake and CLEAR the Gnus registry? ")))
+  (when forsure
+    (gnus-message 4 "Remaking the Gnus registry")
+    (setq gnus-registry-db (gnus-registry-make-db))))
+
+(defun gnus-registry-load ()
+  "Load the registry from the cache file."
+  (interactive)
+  (let ((file gnus-registry-cache-file))
+    (condition-case nil
+        (gnus-registry-read file)
+      (file-error
+       ;; Fix previous mis-naming of the registry file.
+       (let ((old-file-name
+             (concat (file-name-sans-extension
+                     gnus-registry-cache-file)
+                    ".eioio")))
+        (if (and (file-exists-p old-file-name)
+                 (yes-or-no-p
+                  (format "Rename registry file from %s to %s? "
+                          old-file-name file)))
+            (progn
+              (gnus-registry-read old-file-name)
+              (setf (oref gnus-registry-db file) file)
+              (gnus-message 1 "Registry filename changed to %s" file))
+          (gnus-registry-remake-db t))))
+      (error
+       (gnus-message
+        1
+        "The Gnus registry could not be loaded from %s, creating a new one"
+        file)
+       (gnus-registry-remake-db t)))))
+
+(defun gnus-registry-read (file)
+  "Do the actual reading of the registry persistence file."
+  (gnus-message 5 "Reading Gnus registry from %s..." file)
+  (setq gnus-registry-db
+       (gnus-registry-fixup-registry
+        (condition-case nil
+            (with-no-warnings
+              (eieio-persistent-read file 'registry-db))
+          ;; Older EIEIO versions do not check the class name.
+          ('wrong-number-of-arguments
+           (eieio-persistent-read file)))))
+  (gnus-message 5 "Reading Gnus registry from %s...done" file))
+
+(defun gnus-registry-save (&optional file db)
+  "Save the registry cache file."
+  (interactive)
+  (let ((file (or file gnus-registry-cache-file))
+        (db (or db gnus-registry-db)))
+    (gnus-message 5 "Saving Gnus registry (%d entries) to %s..."
+                  (registry-size db) file)
+    (registry-prune
+     db gnus-registry-default-sort-function)
+    ;; TODO: call (gnus-string-remove-all-properties v) on all elements?
+    (eieio-persistent-save db file)
+    (gnus-message 5 "Saving Gnus registry (size %d) to %s...done"
+                  (registry-size db) file)))
+
+(defun gnus-registry-remove-ignored ()
+  (interactive)
+  (let* ((db gnus-registry-db)
+         (grouphashtb (registry-lookup-secondary db 'group))
+         (old-size (registry-size db)))
+    (registry-reindex db)
+    (loop for k being the hash-keys of grouphashtb
+          using (hash-values v)
+          when (gnus-registry-ignore-group-p k)
+          do (registry-delete db v nil))
+    (registry-reindex db)
+    (gnus-message 4 "Removed %d ignored entries from the Gnus registry"
+                  (- old-size (registry-size db)))))
+
+;; article move/copy/spool/delete actions
+(defun gnus-registry-action (action data-header from &optional to method)
+  (let* ((id (mail-header-id data-header))
+         (subject (mail-header-subject data-header))
+         (extra (mail-header-extra data-header))
+         (recipients (gnus-registry-sort-addresses
+                      (or (cdr-safe (assq 'Cc extra)) "")
+                      (or (cdr-safe (assq 'To extra)) "")))
+         (sender (nth 0 (gnus-registry-extract-addresses
+                         (mail-header-from data-header))))
+         (from (gnus-group-guess-full-name-from-command-method from))
+         (to (if to (gnus-group-guess-full-name-from-command-method to) nil)))
+    (gnus-message 7 "Gnus registry: article %s %s from %s to %s"
+                  id (if method "respooling" "going") from to)
+
+    (gnus-registry-handle-action
+     id
+     ;; unless copying, remove the old "from" group
+     (if (not (equal 'copy action)) from nil)
+     to subject sender recipients)))
+
+(defun gnus-registry-spool-action (id group &optional subject sender recipients)
+  (let ((to (gnus-group-guess-full-name-from-command-method group))
+        (recipients (or recipients
+                        (gnus-registry-sort-addresses
+                         (or (message-fetch-field "cc") "")
+                         (or (message-fetch-field "to") ""))))
+        (subject (or subject (message-fetch-field "subject")))
+        (sender (or sender (message-fetch-field "from"))))
+    (when (and (stringp id) (string-match "\r$" id))
+      (setq id (substring id 0 -1)))
+    (gnus-message 7 "Gnus registry: article %s spooled to %s"
+                  id
+                  to)
+    (gnus-registry-handle-action id nil to subject sender recipients)))
+
+(defun gnus-registry-handle-action (id from to subject sender
+                                       &optional recipients)
+  (gnus-message
+   10
+   "gnus-registry-handle-action %S" (list id from to subject sender recipients))
+  (let ((db gnus-registry-db)
+        ;; if the group is ignored, set the destination to nil (same as delete)
+        (to (if (gnus-registry-ignore-group-p to) nil to))
+        ;; safe if not found
+        (entry (gnus-registry-get-or-make-entry id))
+        (subject (gnus-string-remove-all-properties
+                  (gnus-registry-simplify-subject subject)))
+        (sender (gnus-string-remove-all-properties sender)))
+
+    ;; this could be done by calling `gnus-registry-set-id-key'
+    ;; several times but it's better to bunch the transactions
+    ;; together
+
+    (registry-delete db (list id) nil)
+    (when from
+      (setq entry (cons (delete from (assoc 'group entry))
+                        (assq-delete-all 'group entry))))
+
+    (dolist (kv `((group ,to)
+                  (sender ,sender)
+                  (recipient ,@recipients)
+                  (subject ,subject)))
+      (when (second kv)
+        (let ((new (or (assq (first kv) entry)
+                       (list (first kv)))))
+          (dolist (toadd (cdr kv))
+            (unless (member toadd new)
+              (setq new (append new (list toadd)))))
+          (setq entry (cons new
+                            (assq-delete-all (first kv) entry))))))
+    (gnus-message 10 "Gnus registry: new entry for %s is %S"
+                  id
+                  entry)
+    (gnus-registry-insert db id entry)))
+
+;; Function for nn{mail|imap}-split-fancy: look up all references in
+;; the cache and if a match is found, return that group.
+(defun gnus-registry-split-fancy-with-parent ()
+  "Split this message into the same group as its parent.
+The parent is obtained from the registry.  This function can be used as an
+entry in `nnmail-split-fancy' or `nnimap-split-fancy', for example like
+this: (: gnus-registry-split-fancy-with-parent)
+
+This function tracks ALL backends, unlike
+`nnmail-split-fancy-with-parent' which tracks only nnmail
+messages.
+
+For a message to be split, it looks for the parent message in the
+References or In-Reply-To header and then looks in the registry
+to see which group that message was put in.  This group is
+returned, unless `gnus-registry-follow-group-p' return nil for
+that group.
+
+See the Info node `(gnus)Fancy Mail Splitting' for more details."
+  (let* ((refstr (or (message-fetch-field "references") "")) ; guaranteed
+         (reply-to (message-fetch-field "in-reply-to"))      ; may be nil
+         ;; now, if reply-to is valid, append it to the References
+         (refstr (if reply-to
+                     (concat refstr " " reply-to)
+                   refstr))
+         (references (and refstr (gnus-extract-references refstr)))
+         ;; these may not be used, but the code is cleaner having them up here
+         (sender (gnus-string-remove-all-properties
+                  (message-fetch-field "from")))
+         (recipients (gnus-registry-sort-addresses
+                      (or (message-fetch-field "cc") "")
+                      (or (message-fetch-field "to") "")))
+         (subject (gnus-string-remove-all-properties
+                   (gnus-registry-simplify-subject
+                    (message-fetch-field "subject"))))
+
+         (nnmail-split-fancy-with-parent-ignore-groups
+          (if (listp nnmail-split-fancy-with-parent-ignore-groups)
+              nnmail-split-fancy-with-parent-ignore-groups
+            (list nnmail-split-fancy-with-parent-ignore-groups))))
+    (gnus-registry--split-fancy-with-parent-internal
+     :references references
+     :refstr refstr
+     :sender sender
+     :recipients recipients
+     :subject subject
+     :log-agent "Gnus registry fancy splitting with parent")))
+
+(defun* gnus-registry--split-fancy-with-parent-internal
+    (&rest spec
+           &key references refstr sender subject recipients log-agent
+           &allow-other-keys)
+  (gnus-message
+   10
+   "gnus-registry--split-fancy-with-parent-internal %S" spec)
+  (let ((db gnus-registry-db)
+        found)
+    ;; this is a big chain of statements.  it uses
+    ;; gnus-registry-post-process-groups to filter the results after
+    ;; every step.
+    ;; the references string must be valid and parse to valid references
+    (when references
+      (gnus-message
+       9
+       "%s is tracing references %s"
+       log-agent refstr)
+      (dolist (reference (nreverse references))
+        (gnus-message 9 "%s is looking up %s" log-agent reference)
+        (loop for group in (gnus-registry-get-id-key reference 'group)
+              when (gnus-registry-follow-group-p group)
+              do
+              (progn
+                (gnus-message 7 "%s traced %s to %s" log-agent reference group)
+                (push group found))))
+      ;; filter the found groups and return them
+      ;; the found groups are the full groups
+      (setq found (gnus-registry-post-process-groups
+                   "references" refstr found)))
+
+     ;; else: there were no matches, now try the extra tracking by subject
+     (when (and (null found)
+                (memq 'subject gnus-registry-track-extra)
+                subject
+                (< gnus-registry-minimum-subject-length (length subject)))
+       (let ((groups (apply
+                      'append
+                      (mapcar
+                       (lambda (reference)
+                         (gnus-registry-get-id-key reference 'group))
+                       (registry-lookup-secondary-value db 'subject subject)))))
+         (setq found
+               (loop for group in groups
+                     when (gnus-registry-follow-group-p group)
+                     do (gnus-message
+                         ;; warn more if gnus-registry-track-extra
+                         (if gnus-registry-track-extra 7 9)
+                         "%s (extra tracking) traced subject `%s' to %s"
+                         log-agent subject group)
+                    and collect group))
+         ;; filter the found groups and return them
+         ;; the found groups are NOT the full groups
+         (setq found (gnus-registry-post-process-groups
+                      "subject" subject found))))
+
+     ;; else: there were no matches, try the extra tracking by sender
+     (when (and (null found)
+                (memq 'sender gnus-registry-track-extra)
+                sender
+                (not (gnus-grep-in-list
+                      sender
+                      gnus-registry-unfollowed-addresses)))
+       (let ((groups (apply
+                      'append
+                      (mapcar
+                       (lambda (reference)
+                         (gnus-registry-get-id-key reference 'group))
+                       (registry-lookup-secondary-value db 'sender sender)))))
+         (setq found
+               (loop for group in groups
+                     when (gnus-registry-follow-group-p group)
+                     do (gnus-message
+                         ;; warn more if gnus-registry-track-extra
+                         (if gnus-registry-track-extra 7 9)
+                         "%s (extra tracking) traced sender `%s' to %s"
+                         log-agent sender group)
+                     and collect group)))
+
+       ;; filter the found groups and return them
+       ;; the found groups are NOT the full groups
+       (setq found (gnus-registry-post-process-groups
+                    "sender" sender found)))
+
+     ;; else: there were no matches, try the extra tracking by recipient
+     (when (and (null found)
+                (memq 'recipient gnus-registry-track-extra)
+                recipients)
+       (dolist (recp recipients)
+         (when (and (null found)
+                    (not (gnus-grep-in-list
+                          recp
+                          gnus-registry-unfollowed-addresses)))
+           (let ((groups (apply 'append
+                                (mapcar
+                                 (lambda (reference)
+                                   (gnus-registry-get-id-key reference 'group))
+                                 (registry-lookup-secondary-value
+                                  db 'recipient recp)))))
+             (setq found
+                   (loop for group in groups
+                         when (gnus-registry-follow-group-p group)
+                         do (gnus-message
+                             ;; warn more if gnus-registry-track-extra
+                             (if gnus-registry-track-extra 7 9)
+                             "%s (extra tracking) traced recipient `%s' to %s"
+                             log-agent recp group)
+                        and collect group)))))
+
+       ;; filter the found groups and return them
+       ;; the found groups are NOT the full groups
+       (setq found (gnus-registry-post-process-groups
+                    "recipients" (mapconcat 'identity recipients ", ") found)))
+
+     ;; after the (cond) we extract the actual value safely
+     (car-safe found)))
+
+(defun gnus-registry-post-process-groups (mode key groups)
+  "Inspects GROUPS found by MODE for KEY to determine which ones to follow.
+
+MODE can be `subject' or `sender' for example.  The KEY is the
+value by which MODE was searched.
+
+Transforms each group name to the equivalent short name.
+
+Checks if the current Gnus method (from `gnus-command-method' or
+from `gnus-newsgroup-name') is the same as the group's method.
+Foreign methods are not supported so they are rejected.
+
+Reduces the list to a single group, or complains if that's not
+possible.  Uses `gnus-registry-split-strategy'."
+  (let ((log-agent "gnus-registry-post-process-group")
+        (desc (format "%d groups" (length groups)))
+        out chosen)
+    ;; the strategy can be nil, in which case chosen is nil
+    (setq chosen
+          (case gnus-registry-split-strategy
+            ;; default, take only one-element lists into chosen
+            ((nil)
+             (and (= (length groups) 1)
+                  (car-safe groups)))
+
+            ((first)
+             (car-safe groups))
+
+            ((majority)
+             (let ((freq (make-hash-table
+                          :size 256
+                          :test 'equal)))
+               (mapc (lambda (x) (let ((x (gnus-group-short-name x)))
+                              (puthash x (1+ (gethash x freq 0)) freq)))
+                     groups)
+               (setq desc (format "%d groups, %d unique"
+                                  (length groups)
+                                  (hash-table-count freq)))
+               (car-safe
+                (sort groups
+                      (lambda (a b)
+                        (> (gethash (gnus-group-short-name a) freq 0)
+                           (gethash (gnus-group-short-name b) freq 0)))))))))
+
+    (if chosen
+        (gnus-message
+         9
+         "%s: strategy %s on %s produced %s"
+         log-agent gnus-registry-split-strategy desc chosen)
+      (gnus-message
+       9
+       "%s: strategy %s on %s did not produce an answer"
+       log-agent
+       (or gnus-registry-split-strategy "default")
+       desc))
+
+    (setq groups (and chosen (list chosen)))
+
+    (dolist (group groups)
+      (let ((m1 (gnus-find-method-for-group group))
+            (m2 (or gnus-command-method
+                    (gnus-find-method-for-group gnus-newsgroup-name)))
+            (short-name (gnus-group-short-name group)))
+        (if (gnus-methods-equal-p m1 m2)
+            (progn
+              ;; this is REALLY just for debugging
+              (when (not (equal group short-name))
+                (gnus-message
+                 10
+                 "%s: stripped group %s to %s"
+                 log-agent group short-name))
+              (pushnew short-name out :test #'equal))
+          ;; else...
+          (gnus-message
+           7
+           "%s: ignored foreign group %s"
+           log-agent group))))
+
+    (setq out (delq nil out))
+
+    (cond
+     ((= (length out) 1) out)
+     ((null out)
+      (gnus-message
+       5
+       "%s: no matches for %s `%s'."
+       log-agent mode key)
+      nil)
+     (t (gnus-message
+         5
+         "%s: too many extra matches (%s) for %s `%s'.  Returning none."
+         log-agent out mode key)
+        nil))))
+
+(defun gnus-registry-follow-group-p (group)
+  "Determines if a group name should be followed.
+Consults `gnus-registry-unfollowed-groups' and
+`nnmail-split-fancy-with-parent-ignore-groups'."
+  (and group
+       (not (or (gnus-grep-in-list
+                 group
+                 gnus-registry-unfollowed-groups)
+                (gnus-grep-in-list
+                 group
+                 nnmail-split-fancy-with-parent-ignore-groups)))))
+
+;; note that gnus-registry-ignored-groups is defined in gnus.el as a
+;; group/topic parameter and an associated variable!
+
+;; we do special logic for ignoring to accept regular expressions and
+;; nnmail-split-fancy-with-parent-ignore-groups as well
+(defun gnus-registry-ignore-group-p (group)
+  "Determines if a group name should be ignored.
+Consults `gnus-registry-ignored-groups' and
+`nnmail-split-fancy-with-parent-ignore-groups'."
+  (and group
+       (or (gnus-grep-in-list
+            group
+            (delq nil (mapcar (lambda (g)
+                                (cond
+                                 ((stringp g) g)
+                                 ((and (listp g) (nth 1 g))
+                                  (nth 0 g))
+                                 (t nil))) gnus-registry-ignored-groups)))
+           ;; only use `gnus-parameter-registry-ignore' if
+           ;; `gnus-registry-ignored-groups' is a list of lists
+           ;; (it can be a list of regexes)
+           (and (listp (nth 0 gnus-registry-ignored-groups))
+                (get-buffer "*Group*")  ; in automatic tests this is false
+                (gnus-parameter-registry-ignore group))
+           (gnus-grep-in-list
+            group
+            nnmail-split-fancy-with-parent-ignore-groups))))
+
+(defun gnus-registry-wash-for-keywords (&optional force)
+  "Get the keywords of the current article.
+Overrides existing keywords with FORCE set non-nil."
+  (interactive)
+  (let ((id (gnus-registry-fetch-message-id-fast gnus-current-article))
+        word words)
+    (if (or (not (gnus-registry-get-id-key id 'keyword))
+            force)
+        (with-current-buffer gnus-article-buffer
+          (article-goto-body)
+          (save-window-excursion
+            (save-restriction
+              (narrow-to-region (point) (point-max))
+              (with-syntax-table gnus-adaptive-word-syntax-table
+                (while (re-search-forward "\\b\\w+\\b" nil t)
+                  (setq word (gnus-string-remove-all-properties
+                              (downcase (buffer-substring
+                                         (match-beginning 0) (match-end 0)))))
+                  (if (> (length word) 2)
+                      (push word words))))))
+          (gnus-registry-set-id-key id 'keyword words)))))
+
+(defun gnus-registry-keywords ()
+  (let ((table (registry-lookup-secondary gnus-registry-db 'keyword))
+        (ks ()))
+    (when table (maphash (lambda (k _v) (push k ks)) table) ks)))
+
+(defun gnus-registry-find-keywords (keyword)
+  (interactive (list
+                (completing-read "Keyword: " (gnus-registry-keywords) nil t)))
+  (registry-lookup-secondary-value gnus-registry-db 'keyword keyword))
+
+(defun gnus-registry-register-message-ids ()
+  "Register the Message-ID of every article in the group."
+  (unless (gnus-parameter-registry-ignore gnus-newsgroup-name)
+    (dolist (article gnus-newsgroup-articles)
+      (let* ((id (gnus-registry-fetch-message-id-fast article))
+             (groups (gnus-registry-get-id-key id 'group)))
+        (unless (member gnus-newsgroup-name groups)
+          (gnus-message 9 "Registry: Registering article %d with group %s"
+                        article gnus-newsgroup-name)
+          (gnus-registry-handle-action id nil gnus-newsgroup-name
+           (gnus-registry-fetch-simplified-message-subject-fast article)
+           (gnus-registry-fetch-sender-fast article)
+           (gnus-registry-fetch-recipients-fast article)))))))
+
+;; message field fetchers
+(defun gnus-registry-fetch-message-id-fast (article)
+  "Fetch the Message-ID quickly, using the internal gnus-data-list function."
+  (if (and (numberp article)
+           (assoc article (gnus-data-list nil)))
+      (mail-header-id (gnus-data-header (assoc article (gnus-data-list nil))))
+    nil))
+
+(defun gnus-registry-extract-addresses (text)
+  "Extract all the addresses in a normalized way from TEXT.
+Returns an unsorted list of strings in the name <address> format.
+Addresses without a name will say \"noname\"."
+  (mapcar (lambda (add)
+            (gnus-string-remove-all-properties
+             (let* ((name (or (nth 0 add) "noname"))
+                    (addr (nth 1 add))
+                    (addr (if (bufferp addr)
+                              (with-current-buffer addr
+                                (buffer-string))
+                            addr)))
+               (format "%s <%s>" name addr))))
+          (mail-extract-address-components text t)))
+
+(defun gnus-registry-sort-addresses (&rest addresses)
+  "Return a normalized and sorted list of ADDRESSES."
+  (sort (apply 'nconc (mapcar 'gnus-registry-extract-addresses addresses))
+        'string-lessp))
+
+(defun gnus-registry-simplify-subject (subject)
+  (if (stringp subject)
+      (gnus-simplify-subject subject)
+    nil))
+
+(defun gnus-registry-fetch-simplified-message-subject-fast (article)
+  "Fetch the Subject quickly, using the internal gnus-data-list function."
+  (if (and (numberp article)
+           (assoc article (gnus-data-list nil)))
+      (gnus-string-remove-all-properties
+       (gnus-registry-simplify-subject
+        (mail-header-subject (gnus-data-header
+                              (assoc article (gnus-data-list nil))))))
+    nil))
+
+(defun gnus-registry-fetch-sender-fast (article)
+  (gnus-registry-fetch-header-fast "from" article))
+
+(defun gnus-registry-fetch-recipients-fast (article)
+  (gnus-registry-sort-addresses
+   (or (ignore-errors (gnus-registry-fetch-header-fast "Cc" article)) "")
+   (or (ignore-errors (gnus-registry-fetch-header-fast "To" article)) "")))
+
+(defun gnus-registry-fetch-header-fast (article header)
+  "Fetch the HEADER quickly, using the internal gnus-data-list function."
+  (if (and (numberp article)
+           (assoc article (gnus-data-list nil)))
+      (gnus-string-remove-all-properties
+       (cdr (assq header (gnus-data-header
+                          (assoc article (gnus-data-list nil))))))
+    nil))
+
+;; registry marks glue
+(defun gnus-registry-do-marks (type function)
+  "For each known mark, call FUNCTION for each cell of type TYPE.
+
+FUNCTION should take two parameters, a mark symbol and the cell value."
+  (dolist (mark-info gnus-registry-marks)
+    (let* ((mark (car-safe mark-info))
+           (data (cdr-safe mark-info))
+           (cell-data (plist-get data type)))
+      (when cell-data
+        (funcall function mark cell-data)))))
+
+;; FIXME: Why not merge gnus-registry--set/remove-mark and
+;; gnus-registry-set-article-mark-internal?
+(defun gnus-registry--set/remove-mark (mark remove articles)
+  "Set/remove the MARK over process-marked ARTICLES."
+  ;; If this is called and the user doesn't want the
+  ;; registry enabled, we'll ask anyhow.
+  (unless gnus-registry-install
+    (let ((gnus-registry-install 'ask))
+      (gnus-registry-install-p)))
+
+  ;; Now the user is asked if gnus-registry-install is `ask'.
+  (when (gnus-registry-install-p)
+    (gnus-registry-set-article-mark-internal
+     ;; All this just to get the mark, I must be doing it wrong.
+     mark articles remove t)
+    ;; FIXME: Why do we do the above only here and not directly inside
+    ;; gnus-registry-set-article-mark-internal?  I.e. we wouldn't we want to do
+    ;; the things below when gnus-registry-set-article-mark-internal is called
+    ;; from gnus-registry-set-article-mark or
+    ;; gnus-registry-remove-article-mark?
+    (gnus-message 9 "Applying mark %s to %d articles"
+                  mark (length articles))
+    (dolist (article articles)
+      (gnus-summary-update-article
+       article
+       (assoc article (gnus-data-list nil))))))
+
+;; This is ugly code, but I don't know how to do it better.
+(defun gnus-registry-install-shortcuts ()
+  "Install the keyboard shortcuts and menus for the registry.
+Uses `gnus-registry-marks' to find what shortcuts to install."
+  (let (keys-plist)
+    (setq gnus-registry-misc-menus nil)
+    (gnus-registry-do-marks
+     :char
+     (lambda (mark data)
+       (let ((function-format
+              (format "gnus-registry-%%s-article-%s-mark" mark)))
+
+;;;  The following generates these functions:
+;;;  (defun gnus-registry-set-article-Important-mark (&rest articles)
+;;;    "Apply the Important mark to process-marked ARTICLES."
+;;;    (interactive (gnus-summary-work-articles current-prefix-arg))
+;;;    (gnus-registry-set-article-mark-internal 'Important articles nil t))
+;;;  (defun gnus-registry-remove-article-Important-mark (&rest articles)
+;;;    "Apply the Important mark to process-marked ARTICLES."
+;;;    (interactive (gnus-summary-work-articles current-prefix-arg))
+;;;    (gnus-registry-set-article-mark-internal 'Important articles t t))
+
+         (dolist (remove '(t nil))
+           (let* ((variant-name (if remove "remove" "set"))
+                  (function-name
+                   (intern (format function-format variant-name)))
+                  (shortcut (format "%c" (if remove (upcase data) data))))
+             (defalias function-name
+               ;; If it weren't for the function's docstring, we could
+               ;; use a closure, with lexical-let :-(
+               `(lambda (&rest articles)
+                  ,(format
+                    "%s the %s mark over process-marked ARTICLES."
+                    (upcase-initials variant-name)
+                    mark)
+                  (interactive
+                   (gnus-summary-work-articles current-prefix-arg))
+                  (gnus-registry--set/remove-mark ',mark ',remove articles)))
+             (push function-name keys-plist)
+             (push shortcut keys-plist)
+             (push (vector (format "%s %s"
+                                   (upcase-initials variant-name)
+                                   (symbol-name mark))
+                           function-name t)
+                   gnus-registry-misc-menus)
+             (gnus-message 9 "Defined mark handling function %s"
+                           function-name))))))
+    (gnus-define-keys-1
+     '(gnus-registry-mark-map "M" gnus-summary-mark-map)
+     keys-plist)
+    (add-hook 'gnus-summary-menu-hook
+              (lambda ()
+                (easy-menu-add-item
+                 gnus-summary-misc-menu
+                 nil
+                 (cons "Registry Marks" gnus-registry-misc-menus))))))
+
+(make-obsolete 'gnus-registry-user-format-function-M
+               'gnus-registry-article-marks-to-chars "24.1") ?
+
+(defalias 'gnus-registry-user-format-function-M
+  'gnus-registry-article-marks-to-chars)
+
+;; use like this:
+;; (defalias 'gnus-user-format-function-M 'gnus-registry-article-marks-to-chars)
+(defun gnus-registry-article-marks-to-chars (headers)
+  "Show the marks for an article by the :char property."
+  (let* ((id (mail-header-message-id headers))
+         (marks (when id (gnus-registry-get-id-key id 'mark))))
+    (mapconcat (lambda (mark)
+                 (plist-get
+                  (cdr-safe
+                   (assoc mark gnus-registry-marks))
+                  :char))
+               marks "")))
+
+;; use like this:
+;; (defalias 'gnus-user-format-function-M 'gnus-registry-article-marks-to-names)
+(defun gnus-registry-article-marks-to-names (headers)
+  "Show the marks for an article by name."
+  (let* ((id (mail-header-message-id headers))
+         (marks (when id (gnus-registry-get-id-key id 'mark))))
+    (mapconcat (lambda (mark) (symbol-name mark)) marks ",")))
+
+(defun gnus-registry-read-mark ()
+  "Read a mark name from the user with completion."
+  (let ((mark (gnus-completing-read
+               "Label"
+               (mapcar 'symbol-name (mapcar 'car gnus-registry-marks))
+               nil nil nil
+               (symbol-name gnus-registry-default-mark))))
+    (when (stringp mark)
+      (intern mark))))
+
+(defun gnus-registry-set-article-mark (&rest articles)
+  "Apply a mark to process-marked ARTICLES."
+  (interactive (gnus-summary-work-articles current-prefix-arg))
+  (gnus-registry-set-article-mark-internal (gnus-registry-read-mark)
+                                           articles nil t))
+
+(defun gnus-registry-remove-article-mark (&rest articles)
+  "Remove a mark from process-marked ARTICLES."
+  (interactive (gnus-summary-work-articles current-prefix-arg))
+  (gnus-registry-set-article-mark-internal (gnus-registry-read-mark)
+                                           articles t t))
+
+(defun gnus-registry-set-article-mark-internal (mark
+                                                articles
+                                                &optional remove
+                                                show-message)
+  "Apply or remove MARK across a list of ARTICLES."
+  (let ((article-id-list
+         (mapcar 'gnus-registry-fetch-message-id-fast articles)))
+    (dolist (id article-id-list)
+      (let* ((marks (delq mark (gnus-registry-get-id-key id 'mark)))
+             (marks (if remove marks (cons mark marks))))
+        (when show-message
+          (gnus-message 1 "%s mark %s with message ID %s, resulting in %S"
+                        (if remove "Removing" "Adding")
+                        mark id marks))
+        (gnus-registry-set-id-key id 'mark marks)))))
+
+(defun gnus-registry-get-article-marks (&rest articles)
+  "Get the Gnus registry marks for ARTICLES and show them if interactive.
+Uses process/prefix conventions.  For multiple articles,
+only the last one's marks are returned."
+  (interactive (gnus-summary-work-articles 1))
+  (let* ((article (last articles))
+         (id (gnus-registry-fetch-message-id-fast article))
+         (marks (when id (gnus-registry-get-id-key id 'mark))))
+    (when (gmm-called-interactively-p 'any)
+      (gnus-message 1 "Marks are %S" marks))
+    marks))
+
+(defun gnus-registry-group-count (id)
+  "Get the number of groups of a message, based on the message ID."
+  (length (gnus-registry-get-id-key id 'group)))
+
+(defun gnus-registry-get-or-make-entry (id)
+  (let* ((db gnus-registry-db)
+         ;; safe if not found
+         (entries (registry-lookup db (list id))))
+
+    (when (null entries)
+      (gnus-registry-insert db id (list (list 'creation-time (current-time))
+                                        '(group) '(sender) '(subject)))
+      (setq entries (registry-lookup db (list id))))
+
+    (nth 1 (assoc id entries))))
+
+(defun gnus-registry-delete-entries (idlist)
+  (registry-delete gnus-registry-db idlist nil))
+
+(defun gnus-registry-get-id-key (id key)
+  (cdr-safe (assq key (gnus-registry-get-or-make-entry id))))
+
+(defun gnus-registry-set-id-key (id key vals)
+  (let* ((db gnus-registry-db)
+         (entry (gnus-registry-get-or-make-entry id)))
+    (registry-delete db (list id) nil)
+    (setq entry (cons (cons key vals) (assq-delete-all key entry)))
+    (gnus-registry-insert db id entry)
+    entry))
+
+(defun gnus-registry-insert (db id entry)
+  "Just like `registry-insert' but tries to prune on error."
+  (when (registry-full db)
+    (message "Trying to prune the registry because it's full")
+    (registry-prune
+     db gnus-registry-default-sort-function))
+  (registry-insert db id entry)
+  entry)
+
+(defun gnus-registry-import-eld (file)
+  (interactive "fOld registry file to import? ")
+  ;; example content:
+  ;;   (setq gnus-registry-alist '(
+  ;; ("<messageID>" ((marks nil)
+  ;;                 (mtime 19365 1776 440496)
+  ;;                 (sender . "root (Cron Daemon)")
+  ;;                 (subject . "Cron"))
+  ;;  "cron" "nnml+private:cron")
+  (load file t)
+  (when (boundp 'gnus-registry-alist)
+    (let* ((old (symbol-value 'gnus-registry-alist))
+           (count 0)
+           (expected (length old))
+           entry)
+      (while (car-safe old)
+        (incf count)
+        ;; don't use progress reporters for backwards compatibility
+        (when (and (< 0 expected)
+                   (= 0 (mod count 100)))
+          (message "importing: %d of %d (%.2f%%)"
+                   count expected (/ (* 100.0 count) expected)))
+        (setq entry (car-safe old)
+              old (cdr-safe old))
+        (let* ((id (car-safe entry))
+               (rest (cdr-safe entry))
+               (groups (loop for p in rest
+                             when (stringp p)
+                             collect p))
+               extra-cell key val)
+          ;; remove all the strings from the entry
+          (dolist (elem rest)
+            (if (stringp elem) (setq rest (delq elem rest))))
+          (gnus-registry-set-id-key id 'group groups)
+          ;; just use the first extra element
+          (setq rest (car-safe rest))
+          (while (car-safe rest)
+            (setq extra-cell (car-safe rest)
+                  key (car-safe extra-cell)
+                  val (cdr-safe extra-cell)
+                  rest (cdr-safe rest))
+            (when (and val (atom val))
+              (setq val (list val)))
+            (gnus-registry-set-id-key id key val))))
+      (message "Import done, collected %d entries" count))))
+
+;;;###autoload
+(defun gnus-registry-initialize ()
+  "Initialize the Gnus registry."
+  (interactive)
+  (gnus-message 5 "Initializing the registry")
+  (gnus-registry-install-hooks)
+  (gnus-registry-install-shortcuts)
+  (gnus-registry-load))
+
+;; FIXME: Why autoload this function?
+;;;###autoload
+(defun gnus-registry-install-hooks ()
+  "Install the registry hooks."
+  (interactive)
+  (setq gnus-registry-enabled t)
+  (add-hook 'gnus-summary-article-move-hook 'gnus-registry-action)
+  (add-hook 'gnus-summary-article-delete-hook 'gnus-registry-action)
+  (add-hook 'gnus-summary-article-expire-hook 'gnus-registry-action)
+  (add-hook 'nnmail-spool-hook 'gnus-registry-spool-action)
+
+  (add-hook 'gnus-save-newsrc-hook 'gnus-registry-save)
+  (add-hook 'gnus-read-newsrc-el-hook 'gnus-registry-load)
+
+  (add-hook 'gnus-summary-prepare-hook 'gnus-registry-register-message-ids))
+
+(defun gnus-registry-unload-hook ()
+  "Uninstall the registry hooks."
+  (interactive)
+  (remove-hook 'gnus-summary-article-move-hook 'gnus-registry-action)
+  (remove-hook 'gnus-summary-article-delete-hook 'gnus-registry-action)
+  (remove-hook 'gnus-summary-article-expire-hook 'gnus-registry-action)
+  (remove-hook 'nnmail-spool-hook 'gnus-registry-spool-action)
+
+  (remove-hook 'gnus-save-newsrc-hook 'gnus-registry-save)
+  (remove-hook 'gnus-read-newsrc-el-hook 'gnus-registry-load)
+
+  (remove-hook 'gnus-summary-prepare-hook 'gnus-registry-register-message-ids)
+  (setq gnus-registry-enabled nil))
+
+(add-hook 'gnus-registry-unload-hook 'gnus-registry-unload-hook)
+
+(defun gnus-registry-install-p ()
+  "Return non-nil if the registry is enabled (and maybe enable it first).
+If the registry is not already enabled, then if `gnus-registry-install'
+is `ask', ask the user; or if `gnus-registry-install' is non-nil, enable it."
+  (interactive)
+  (unless gnus-registry-enabled
+    (when (if (eq gnus-registry-install 'ask)
+              (gnus-y-or-n-p
+               (concat "Enable the Gnus registry?  "
+                       "See the variable `gnus-registry-install' "
+                       "to get rid of this query permanently. "))
+            gnus-registry-install)
+      (gnus-registry-initialize)))
+  gnus-registry-enabled)
+
+;; largely based on nnir-warp-to-article
+(defun gnus-try-warping-via-registry ()
+  "Try to warp via the registry.
+This will be done via the current article's source group based on
+data stored in the registry."
+  (interactive)
+  (when (gnus-summary-article-header)
+    (let* ((message-id (mail-header-id (gnus-summary-article-header)))
+           ;; Retrieve the message's group(s) from the registry
+           (groups (gnus-registry-get-id-key message-id 'group))
+           ;; If starting from an ephemeral group, this describes
+           ;; how to restore the window configuration
+           (quit-config
+            (gnus-ephemeral-group-p gnus-newsgroup-name))
+           (seen-groups (list (gnus-group-group-name))))
+
+      (catch 'found
+        (dolist (group (mapcar 'gnus-simplify-group-name groups))
+
+          ;; skip over any groups we really don't want to warp to.
+          (unless (or (member group seen-groups)
+                      (gnus-ephemeral-group-p group) ;; any ephemeral group
+                      (memq (car (gnus-find-method-for-group group))
+                           ;; Specific methods; this list may need to expand.
+                            '(nnir)))
+
+            ;; remember that we've seen this group already
+            (push group seen-groups)
+
+            ;; first exit from any ephemeral summary buffer.
+            (when quit-config
+              (gnus-summary-exit)
+              ;; and if the ephemeral summary buffer in turn came from
+              ;; another summary buffer we have to clean that summary
+              ;; up too.
+              (when (eq (cdr quit-config) 'summary)
+                (gnus-summary-exit))
+              ;; remember that we've already done this part
+              (setq quit-config nil))
+
+            ;; Try to activate the group.  If that fails, just move
+            ;; along.  We may have more groups to work with
+            (when
+                (ignore-errors
+                  (gnus-select-group-with-message-id group message-id) t)
+              (throw 'found t))))))))
+
+(defun gnus-registry-remove-extra-data (extra)
+  "Remove tracked EXTRA data from the gnus registry.
+EXTRA is a list of symbols.  Valid symbols are those contained in
+the docs of `gnus-registry-track-extra'.  This command is useful
+when you stop tracking some extra data and now want to purge it
+from your existing entries."
+  (interactive (list (mapcar 'intern
+                            (completing-read-multiple
+                             "Extra data: "
+                             '("subject" "sender" "recipient")))))
+  (when extra
+    (let ((db gnus-registry-db))
+      (registry-reindex db)
+      (loop for k being the hash-keys of (oref db data)
+           using (hash-value v)
+           do (let ((newv (delq nil (mapcar #'(lambda (entry)
+                                                (unless (member (car entry) extra)
+                                                  entry))
+                                            v))))
+                (registry-delete db (list k) nil)
+                (gnus-registry-insert db k newv)))
+      (registry-reindex db))))
+
+;; TODO: a few things
+
+(provide 'gnus-registry)
+
+;;; gnus-registry.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-salt.el b/xemacs-packages/gnus/lisp/gnus-salt.el
new file mode 100644 (file)
index 0000000..e4a8dbe
--- /dev/null
@@ -0,0 +1,897 @@
+;;; gnus-salt.el --- alternate summary mode interfaces for Gnus
+
+;; Copyright (C) 1996-1999, 2001-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(eval-when-compile
+  (when (featurep 'xemacs)
+    (require 'easy-mmode))) ; for `define-minor-mode'
+
+(require 'gnus)
+(require 'gnus-sum)
+(require 'gnus-win)
+
+;;;
+;;; gnus-pick-mode
+;;;
+
+(defcustom gnus-pick-display-summary nil
+  "*Display summary while reading."
+  :type 'boolean
+  :group 'gnus-summary-pick)
+
+(defcustom gnus-pick-mode-hook nil
+  "Hook run in summary pick mode buffers."
+  :type 'hook
+  :group 'gnus-summary-pick)
+
+(when (featurep 'xemacs)
+  (add-hook 'gnus-pick-mode-hook 'gnus-xmas-pick-menu-add))
+
+(defcustom gnus-mark-unpicked-articles-as-read nil
+  "*If non-nil, mark all unpicked articles as read."
+  :type 'boolean
+  :group 'gnus-summary-pick)
+
+(defcustom gnus-pick-elegant-flow t
+  "If non-nil, `gnus-pick-start-reading' runs
+ `gnus-summary-next-group' when no articles have been picked."
+  :type 'boolean
+  :group 'gnus-summary-pick)
+
+(defcustom gnus-summary-pick-line-format
+  "%-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
+  :group 'gnus-summary-pick)
+
+;;; Internal variables.
+
+(defvar gnus-pick-mode-map
+  (let ((map (make-sparse-keymap)))
+    (gnus-define-keys map
+      " " gnus-pick-next-page
+      "u" gnus-pick-unmark-article-or-thread
+      "." gnus-pick-article-or-thread
+      gnus-down-mouse-2 gnus-pick-mouse-pick-region
+      "\r" gnus-pick-start-reading)
+    map))
+
+(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]))))
+
+(eval-when-compile
+  (when (featurep 'xemacs)
+    (defvar gnus-pick-mode-on-hook)
+    (defvar gnus-pick-mode-off-hook)))
+
+(define-minor-mode gnus-pick-mode
+  "Minor mode for providing a pick-and-read interface in Gnus summary buffers.
+
+\\{gnus-pick-mode-map}"
+  :lighter " Pick" :keymap gnus-pick-mode-map
+  (cond
+   ((not (derived-mode-p 'gnus-summary-mode)) (setq gnus-pick-mode nil))
+   ((not gnus-pick-mode)
+    ;; FIXME: a buffer-local minor mode removing globally from a hook??
+    (remove-hook 'gnus-message-setup-hook 'gnus-pick-setup-message))
+   (t
+    ;; Make sure that we don't select any articles upon group entry.
+    (set (make-local-variable 'gnus-auto-select-first) nil)
+    ;; Change line format.
+    (setq gnus-summary-line-format gnus-summary-pick-line-format)
+    (setq gnus-summary-line-format-spec nil)
+    (gnus-update-format-specifications nil 'summary)
+    (gnus-update-summary-mark-positions)
+    ;; FIXME: a buffer-local minor mode adding globally to a hook??
+    (add-hook 'gnus-message-setup-hook 'gnus-pick-setup-message)
+    (set (make-local-variable 'gnus-summary-goto-unread) 'never)
+    ;; Set up the menu.
+    (when (gnus-visual-p 'pick-menu 'menu)
+      (gnus-pick-make-menu-bar)))))
+
+(defun gnus-pick-setup-message ()
+  "Make Message do the right thing on exit."
+  (when (and (gnus-buffer-live-p gnus-summary-buffer)
+            (with-current-buffer gnus-summary-buffer
+              gnus-pick-mode))
+    (message-add-action
+     `(gnus-configure-windows ,gnus-current-window-configuration t)
+     'send 'exit 'postpone 'kill)))
+
+(defvar gnus-pick-line-number 1)
+(defun gnus-pick-line-number ()
+  "Return the current line number."
+  (if (bobp)
+      (setq gnus-pick-line-number 1)
+    (incf gnus-pick-line-number)))
+
+(defun gnus-pick-start-reading (&optional catch-up)
+  "Start reading the picked articles.
+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-mark-excluded-as-read))
+       (gnus-summary-first-article)
+       (gnus-configure-windows
+        (if gnus-pick-display-summary 'article 'pick) t))
+    (if gnus-pick-elegant-flow
+       (progn
+         (when (or catch-up gnus-mark-unpicked-articles-as-read)
+           (gnus-summary-catchup nil t))
+         (if (gnus-group-quit-config gnus-newsgroup-name)
+             (gnus-summary-exit)
+           (gnus-summary-next-group)))
+      (error "No articles have been picked"))))
+
+(defun gnus-pick-goto-article (arg)
+  "Go to the article number indicated by ARG.
+If ARG is an invalid article number, then stay on current line."
+  (let (pos)
+    (save-excursion
+      (goto-char (point-min))
+      (when (zerop (forward-line (1- (prefix-numeric-value arg))))
+       (setq pos (point))))
+    (if (not pos)
+       (gnus-error 2 "No such line: %s" arg)
+      (goto-char pos))))
+
+(defun gnus-pick-article (&optional arg)
+  "Pick the article on the current line.
+If ARG, pick the article on that line instead."
+  (interactive "P")
+  (when arg
+    (gnus-pick-goto-article arg))
+  (gnus-summary-mark-as-processable 1))
+
+(defun gnus-pick-article-or-thread (&optional arg)
+  "If `gnus-thread-hide-subtree' is t, then pick the thread on the current line.
+Otherwise pick the article on the current line.
+If ARG, pick the article/thread on that line instead."
+  (interactive "P")
+  (when arg
+    (gnus-pick-goto-article arg))
+  (if gnus-thread-hide-subtree
+      (progn
+       (save-excursion
+         (gnus-uu-mark-thread))
+       (forward-line 1))
+    (gnus-summary-mark-as-processable 1)))
+
+(defun gnus-pick-unmark-article-or-thread (&optional arg)
+  "If `gnus-thread-hide-subtree' is t, then unmark the thread on current line.
+Otherwise unmark the article on current line.
+If ARG, unmark thread/article on that line instead."
+  (interactive "P")
+  (when arg
+    (gnus-pick-goto-article arg))
+  (if gnus-thread-hide-subtree
+      (save-excursion
+       (gnus-uu-unmark-thread))
+    (gnus-summary-unmark-as-processable 1)))
+
+(defun gnus-pick-mouse-pick (e)
+  (interactive "e")
+  (mouse-set-point e)
+  (save-excursion
+    (gnus-summary-mark-as-processable 1)))
+
+(defun gnus-pick-mouse-pick-region (start-event)
+  "Pick articles that the mouse is dragged over.
+This must be bound to a button-down mouse event."
+  (interactive "e")
+  (mouse-minibuffer-check start-event)
+  (let* ((echo-keystrokes 0)
+        (start-posn (event-start start-event))
+        (start-point (posn-point start-posn))
+         (start-line (1+ (count-lines (point-min) start-point)))
+        (start-window (posn-window start-posn))
+        (bounds (gnus-window-edges start-window))
+        (top (nth 1 bounds))
+        (bottom (if (window-minibuffer-p start-window)
+                    (nth 3 bounds)
+                  ;; Don't count the mode line.
+                  (1- (nth 3 bounds))))
+        (click-count (1- (event-click-count start-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,
+    ;; use the end of that text, and put it in START-POINT.
+    (when (< (point) start-point)
+      (goto-char start-point))
+    (gnus-pick-article)
+    (setq start-point (point))
+    ;; end-of-range is used only in the single-click case.
+    ;; It is the place where the drag has reached so far
+    ;; (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 (point-min) end-point)))
+                    (min-line (min this-line start-line))
+                    (max-line (max this-line start-line)))
+               (while (< min-line max-line)
+                 (goto-char (point-min))
+                 (forward-line (1- 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,
+         ;; 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.
+           (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.
+             (push event unread-command-events))))))))
+
+(defvar scroll-in-place)
+
+(defun gnus-pick-next-page ()
+  "Go to the next page.  If at the end of the buffer, start reading articles."
+  (interactive)
+  (let ((scroll-in-place nil))
+    (condition-case nil
+       (scroll-up)
+      (end-of-buffer (gnus-pick-start-reading)))))
+
+;;;
+;;; gnus-binary-mode
+;;;
+
+(defvar gnus-binary-mode-hook nil
+  "Hook run in summary binary mode buffers.")
+
+(defvar gnus-binary-mode-map
+  (let ((map (make-sparse-keymap)))
+    (gnus-define-keys map
+      "g" gnus-binary-show-article)
+    map))
+
+(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]))))
+
+(eval-when-compile
+  (when (featurep 'xemacs)
+    (defvar gnus-binary-mode-on-hook)
+    (defvar gnus-binary-mode-off-hook)))
+
+(define-minor-mode gnus-binary-mode
+  "Minor mode for providing a binary group interface in Gnus summary buffers."
+  :lighter " Binary" :keymap gnus-binary-mode-map
+  (cond
+   ((not (derived-mode-p 'gnus-summary-mode)) (setq gnus-binary-mode nil))
+   (gnus-binary-mode
+    ;; Make sure that we don't select any articles upon group entry.
+    (make-local-variable 'gnus-auto-select-first)
+    (setq gnus-auto-select-first nil)
+    (make-local-variable 'gnus-summary-display-article-function)
+    (setq gnus-summary-display-article-function 'gnus-binary-display-article)
+    ;; Set up the menu.
+    (when (gnus-visual-p 'binary-menu 'menu)
+      (gnus-binary-make-menu-bar)))))
+
+(defun gnus-binary-display-article (article &optional _all-header)
+  "Run ARTICLE through the binary decode functions."
+  (when (gnus-summary-goto-subject article)
+    (let ((gnus-view-pseudos (or gnus-view-pseudos 'automatic)))
+      (gnus-uu-decode-uu))))
+
+(defun gnus-binary-show-article (&optional arg)
+  "Bypass the binary functions and show the article."
+  (interactive "P")
+  (let (gnus-summary-display-article-function)
+    (gnus-summary-show-article arg)))
+
+;;;
+;;; gnus-tree-mode
+;;;
+
+(defcustom gnus-tree-line-format "%(%[%3,3n%]%)"
+  "Format of tree elements."
+  :type 'string
+  :group 'gnus-summary-tree)
+
+(defcustom gnus-tree-minimize-window t
+  "If non-nil, minimize the tree buffer window.
+If a number, never let the tree buffer grow taller than that number of
+lines."
+  :type '(choice boolean
+                integer)
+  :group 'gnus-summary-tree)
+
+(defcustom gnus-selected-tree-face 'mode-line
+  "*Face used for highlighting selected articles in the thread tree."
+  :type 'face
+  :group 'gnus-summary-tree)
+
+(defvar gnus-tree-brackets '((?\[ . ?\]) (?\( . ?\))
+                            (?\{ . ?\}) (?< . ?>))
+  "Brackets used in tree nodes.")
+
+(defvar gnus-tree-parent-child-edges '(?- ?\\ ?|)
+  "Characters used to connect parents with children.")
+
+(defcustom gnus-tree-mode-line-format "Gnus: %%b %S %Z"
+  "*The format specification for the tree mode line."
+  :type 'string
+  :group 'gnus-summary-tree)
+
+(defcustom gnus-generate-tree-function 'gnus-generate-vertical-tree
+  "*Function for generating a thread tree.
+Two predefined functions are available:
+`gnus-generate-horizontal-tree' and `gnus-generate-vertical-tree'."
+  :type '(radio (function-item gnus-generate-vertical-tree)
+               (function-item gnus-generate-horizontal-tree)
+               (function :tag "Other" nil))
+  :group 'gnus-summary-tree)
+
+(defcustom gnus-tree-mode-hook nil
+  "*Hook run in tree mode buffers."
+  :type 'hook
+  :group 'gnus-summary-tree)
+
+(when (featurep 'xemacs)
+  (add-hook 'gnus-tree-mode-hook 'gnus-xmas-tree-menu-add)
+  (add-hook 'gnus-tree-mode-hook 'gnus-xmas-switch-horizontal-scrollbar-off))
+
+
+;;; Internal variables.
+
+(defvar gnus-tmp-name)
+(defvar gnus-tmp-from)
+(defvar gnus-tmp-number)
+(defvar gnus-tmp-open-bracket)
+(defvar gnus-tmp-close-bracket)
+(defvar gnus-tmp-subject)
+
+(defvar gnus-tree-line-format-alist
+  `((?n gnus-tmp-name ?s)
+    (?f gnus-tmp-from ?s)
+    (?N gnus-tmp-number ?d)
+    (?\[ gnus-tmp-open-bracket ?c)
+    (?\] gnus-tmp-close-bracket ?c)
+    (?s gnus-tmp-subject ?s)))
+
+(defvar gnus-tree-mode-line-format-alist gnus-summary-mode-line-format-alist)
+
+(defvar gnus-tree-mode-line-format-spec nil)
+(defvar gnus-tree-line-format-spec nil)
+
+(defvar gnus-tree-node-length nil)
+(defvar gnus-selected-tree-overlay nil)
+
+(defvar gnus-tree-displayed-thread nil)
+(defvar gnus-tree-inhibit nil)
+
+(defvar gnus-tree-mode-map
+  (let ((map (make-keymap)))
+    (suppress-keymap map)
+    (gnus-define-keys
+        map
+      "\r" gnus-tree-select-article
+      gnus-mouse-2 gnus-tree-pick-article
+      "\C-?" gnus-tree-read-summary-keys
+      "h" gnus-tree-show-summary
+
+      "\C-c\C-i" gnus-info-find-node)
+
+    (substitute-key-definition
+     'undefined 'gnus-tree-read-summary-keys map)
+    map))
+
+(put 'gnus-tree-mode 'mode-class 'special)
+
+(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]))))
+
+(define-derived-mode gnus-tree-mode fundamental-mode "Tree"
+  "Major mode for displaying thread trees."
+  (gnus-set-format 'tree-mode)
+  (gnus-set-format 'tree t)
+  (when (gnus-visual-p 'tree-menu 'menu)
+    (gnus-tree-make-menu-bar))
+  (gnus-simplify-mode-line)
+  (buffer-disable-undo)
+  (setq buffer-read-only t)
+  (setq truncate-lines t)
+  (save-current-buffer
+    (gnus-set-work-buffer)
+    (gnus-tree-node-insert (make-mail-header "") nil)
+    (setq gnus-tree-node-length (1- (point)))))
+
+(defun gnus-tree-read-summary-keys (&optional arg)
+  "Read a summary buffer key sequence and execute it."
+  (interactive "P")
+  (unless gnus-tree-inhibit
+    (let ((buf (current-buffer))
+         (gnus-tree-inhibit t)
+         win)
+      (set-buffer gnus-article-buffer)
+      (gnus-article-read-summary-keys arg nil t)
+      (when (setq win (get-buffer-window buf))
+       (select-window win)
+       (when gnus-selected-tree-overlay
+         (goto-char (or (overlay-end gnus-selected-tree-overlay) 1)))
+       (gnus-tree-minimize)))))
+
+(defun gnus-tree-show-summary ()
+  "Reconfigure windows to show summary buffer."
+  (interactive)
+  (if (not (gnus-buffer-live-p gnus-summary-buffer))
+      (error "There is no summary buffer for this tree buffer")
+    (gnus-configure-windows 'article)
+    (gnus-summary-goto-subject gnus-current-article)))
+
+(defun gnus-tree-select-article (article)
+  "Select the article under point, if any."
+  (interactive (list (gnus-tree-article-number)))
+  (let ((buf (current-buffer)))
+    (when article
+      (with-current-buffer gnus-summary-buffer
+       (gnus-summary-goto-article article))
+      (select-window (get-buffer-window buf)))))
+
+(defun gnus-tree-pick-article (e)
+  "Select the article under the mouse pointer."
+  (interactive "e")
+  (mouse-set-point e)
+  (gnus-tree-select-article (gnus-tree-article-number)))
+
+(defun gnus-tree-article-number ()
+  (get-text-property (point) 'gnus-number))
+
+(defun gnus-tree-article-region (article)
+  "Return a cons with BEG and END of the article region."
+  (let ((pos (text-property-any
+             (point-min) (point-max) 'gnus-number article)))
+    (when pos
+      (cons pos (next-single-property-change pos 'gnus-number)))))
+
+(defun gnus-tree-recenter ()
+  "Center point in the tree window."
+  (let ((selected (selected-window))
+       (tree-window (gnus-get-buffer-window gnus-tree-buffer t)))
+    (when tree-window
+      (select-window tree-window)
+      (when gnus-selected-tree-overlay
+       (goto-char (or (overlay-end gnus-selected-tree-overlay) 1)))
+      (let* ((top (cond ((< (window-height) 4) 0)
+                       ((< (window-height) 7) 1)
+                       (t 2)))
+            (height (1- (window-height)))
+            (bottom (save-excursion (goto-char (point-max))
+                                    (forward-line (- height))
+                                    (point))))
+      ;; 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
+        tree-window (min bottom (save-excursion
+                                  (forward-line (- top)) (point)))))
+      (select-window selected))))
+
+(defun gnus-get-tree-buffer ()
+  "Return the tree buffer properly initialized."
+  (with-current-buffer (gnus-get-buffer-create gnus-tree-buffer)
+    (unless (derived-mode-p 'gnus-tree-mode)
+      (gnus-tree-mode))
+    (current-buffer)))
+
+(defun gnus-tree-minimize ()
+  (when (and gnus-tree-minimize-window
+            (not (one-window-p)))
+    (let ((windows 0)
+         tot-win-height)
+      (walk-windows (lambda (_window) (incf windows)))
+      (setq tot-win-height
+           (- (frame-height)
+              (* window-min-height (1- windows))
+              2))
+      (let* ((window-min-height 2)
+            (height (count-lines (point-min) (point-max)))
+            (min (max (1- window-min-height) height))
+            (tot (if (numberp gnus-tree-minimize-window)
+                     (min gnus-tree-minimize-window min)
+                   min))
+            (win (get-buffer-window (current-buffer)))
+            (wh (and win (1- (window-height win)))))
+       (setq tot (min tot tot-win-height))
+       (when (and win
+                  (not (eq tot wh)))
+         (let ((selected (selected-window)))
+           (when (ignore-errors (select-window win))
+             (enlarge-window (- tot wh))
+             (select-window selected))))))))
+
+;;; Generating the tree.
+
+(defun gnus-tree-node-insert (header sparse &optional adopted)
+  (let* ((dummy (stringp header))
+        (header (if (vectorp header) header
+                  (progn
+                    (setq header (make-mail-header "*****"))
+                    (mail-header-set-number header 0)
+                    (mail-header-set-lines header 0)
+                    (mail-header-set-chars header 0)
+                    header)))
+        (gnus-tmp-from (mail-header-from header))
+        (gnus-tmp-subject (mail-header-subject header))
+        (gnus-tmp-number (mail-header-number header))
+        (gnus-tmp-name
+         (cond
+          ((string-match "(.+)" gnus-tmp-from)
+           (substring gnus-tmp-from
+                      (1+ (match-beginning 0)) (1- (match-end 0))))
+          ((string-match "<[^>]+> *$" gnus-tmp-from)
+           (let ((beg (match-beginning 0)))
+             (or (and (string-match "^\"[^\"]*\"" gnus-tmp-from)
+                      (substring gnus-tmp-from (1+ (match-beginning 0))
+                                 (1- (match-end 0))))
+                 (substring gnus-tmp-from 0 beg))))
+          ((memq gnus-tmp-number sparse)
+           "***")
+          (t gnus-tmp-from)))
+        (gnus-tmp-open-bracket
+         (cond ((memq gnus-tmp-number sparse)
+                (caadr gnus-tree-brackets))
+               (dummy (caaddr gnus-tree-brackets))
+               (adopted (car (nth 3 gnus-tree-brackets)))
+               (t (caar gnus-tree-brackets))))
+        (gnus-tmp-close-bracket
+         (cond ((memq gnus-tmp-number sparse)
+                (cdadr gnus-tree-brackets))
+               (adopted (cdr (nth 3 gnus-tree-brackets)))
+               (dummy
+                (cdaddr gnus-tree-brackets))
+               (t (cdar gnus-tree-brackets))))
+        (buffer-read-only nil)
+        beg end)
+    (gnus-add-text-properties
+     (setq beg (point))
+     (setq end (progn (eval gnus-tree-line-format-spec) (point)))
+     (list 'gnus-number gnus-tmp-number))
+    (when (or t (gnus-visual-p 'tree-highlight 'highlight))
+      (gnus-tree-highlight-node gnus-tmp-number beg end))))
+
+(defmacro gnus--let-eval (bindings evalsym &rest body)
+  "Build an environment in which to evaluate expressions.
+BINDINGS is a `let'-style list of bindings to use for the environment.
+EVALSYM is then bound in BODY to a function that takes a sexp and evaluates
+it in the environment specified by BINDINGS."
+  (declare (indent 2) (debug ((&rest (sym form)) sym body)))
+  (if (eval '(ignore-errors (let ((x 3)) (eq (eval '(- x 1) '((x . 4))) x))))
+      ;; Use lexical vars if possible.
+      `(let* ((env (list ,@(mapcar (lambda (binding)
+                                     `(cons ',(car binding) ,(cadr binding)))
+                                   bindings)))
+             (,evalsym (lambda (exp) (eval exp env))))
+         ,@body)
+    `(let (,@bindings (,evalsym #'eval)) ,@body)))
+
+(defun gnus-tree-highlight-node (article beg end)
+  "Highlight current line according to `gnus-summary-highlight'."
+  (let ((list gnus-summary-highlight)
+       face)
+    (with-current-buffer gnus-summary-buffer
+      (let ((uncached (memq article gnus-newsgroup-undownloaded)))
+        (gnus--let-eval
+            ((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)
+             (uncached uncached)
+             (downloaded (not uncached))
+            (mark (or (gnus-summary-article-mark article) gnus-unread-mark)))
+            evalfun
+          ;; Eval the cars of the lists until we find a match.
+          (while (and list
+                      (not (funcall evalfun (caar list))))
+            (setq list (cdr list))))))
+    (unless (eq (setq face (cdar list)) (gnus-get-text-property-excluding-characters-with-faces beg 'face))
+      (gnus-put-text-property-excluding-characters-with-faces
+       beg end 'face
+       (if (boundp face) (symbol-value face) face)))))
+
+(defun gnus-tree-indent (level)
+  (insert (make-string (1- (* (1+ gnus-tree-node-length) level)) ? )))
+
+(defvar gnus-tmp-limit)
+(defvar gnus-tmp-sparse)
+(defvar gnus-tmp-indent)
+
+(defun gnus-generate-tree (thread)
+  "Generate a thread tree for THREAD."
+  (with-current-buffer (gnus-get-tree-buffer)
+    (let ((buffer-read-only nil)
+         (gnus-tmp-indent 0))
+      (erase-buffer)
+      (funcall gnus-generate-tree-function thread 0)
+      (gnus-set-mode-line 'tree)
+      (goto-char (point-min))
+      (gnus-tree-minimize)
+      (gnus-tree-recenter)
+      (let ((selected (selected-window)))
+       (when (gnus-get-buffer-window (set-buffer gnus-tree-buffer) t)
+         (select-window (gnus-get-buffer-window (set-buffer gnus-tree-buffer) t))
+         (gnus-horizontal-recenter)
+         (select-window selected))))))
+
+(defun gnus-generate-horizontal-tree (thread level &optional dummyp adopted)
+  "Generate a horizontal tree."
+  (let* ((dummy (stringp (car thread)))
+        (do (or dummy
+                (and (car thread)
+                     (memq (mail-header-number (car thread))
+                           gnus-tmp-limit))))
+        col beg)
+    (if (not do)
+       ;; We don't want this article.
+       (setq thread (cdr thread))
+      (if (not (bolp))
+         ;; Not the first article on the line, so we insert a "-".
+         (insert (car gnus-tree-parent-child-edges))
+       ;; If the level isn't zero, then we insert some indentation.
+       (unless (zerop level)
+         (gnus-tree-indent level)
+         (insert (cadr gnus-tree-parent-child-edges))
+         (setq col (- (setq beg (point)) (point-at-bol) 1))
+         ;; Draw "|" lines upwards.
+         (while (progn
+                  (forward-line -1)
+                  (forward-char col)
+                  (eq (char-after) ? ))
+           (delete-char 1)
+           (insert (caddr gnus-tree-parent-child-edges)))
+         (goto-char beg)))
+      (setq dummyp nil)
+      ;; Insert the article node.
+      (gnus-tree-node-insert (pop thread) gnus-tmp-sparse adopted))
+    (if (null thread)
+       ;; End of the thread, so we go to the next line.
+       (unless (bolp)
+         (insert "\n"))
+      ;; Recurse downwards in all children of this article.
+      (while thread
+       (gnus-generate-horizontal-tree
+        (pop thread) (if do (1+ level) level)
+        (or dummyp dummy) dummy)))))
+
+(defsubst gnus-tree-indent-vertical ()
+  (let ((len (- (* (1+ gnus-tree-node-length) gnus-tmp-indent)
+               (- (point) (point-at-bol)))))
+    (when (> len 0)
+      (insert (make-string len ? )))))
+
+(defsubst gnus-tree-forward-line (n)
+  (while (>= (decf n) 0)
+    (unless (zerop (forward-line 1))
+      (end-of-line)
+      (insert "\n")))
+  (end-of-line))
+
+(defun gnus-generate-vertical-tree (thread level &optional dummyp adopted)
+  "Generate a vertical tree."
+  (let* ((dummy (stringp (car thread)))
+        (do (or dummy
+                (and (car thread)
+                     (memq (mail-header-number (car thread))
+                           gnus-tmp-limit))))
+        beg)
+    (if (not do)
+       ;; We don't want this article.
+       (setq thread (cdr thread))
+      (if (not (save-excursion (beginning-of-line) (bobp)))
+         ;; Not the first article on the line, so we insert a "-".
+         (progn
+           (gnus-tree-indent-vertical)
+           (insert (make-string (/ gnus-tree-node-length 2) ? ))
+           (insert (caddr gnus-tree-parent-child-edges))
+           (gnus-tree-forward-line 1))
+       ;; If the level isn't zero, then we insert some indentation.
+       (unless (zerop gnus-tmp-indent)
+         (gnus-tree-forward-line (1- (* 2 level)))
+         (gnus-tree-indent-vertical)
+         (delete-char -1)
+         (insert (cadr gnus-tree-parent-child-edges))
+         (setq beg (point))
+         (forward-char -1)
+         ;; Draw "-" lines leftwards.
+         (while (and (not (bobp))
+                     (eq (char-after (1- (point))) ? ))
+           (delete-char -1)
+           (insert (car gnus-tree-parent-child-edges))
+           (forward-char -1))
+         (goto-char beg)
+         (gnus-tree-forward-line 1)))
+      (setq dummyp nil)
+      ;; Insert the article node.
+      (gnus-tree-indent-vertical)
+      (gnus-tree-node-insert (pop thread) gnus-tmp-sparse adopted)
+      (gnus-tree-forward-line 1))
+    (if (null thread)
+       ;; End of the thread, so we go to the next line.
+       (progn
+         (goto-char (point-min))
+         (end-of-line)
+         (incf gnus-tmp-indent))
+      ;; Recurse downwards in all children of this article.
+      (while thread
+       (gnus-generate-vertical-tree
+        (pop thread) (if do (1+ level) level)
+        (or dummyp dummy) dummy)))))
+
+;;; Interface functions.
+
+(defun gnus-possibly-generate-tree (article &optional force)
+  "Generate the thread tree for ARTICLE if it isn't displayed already."
+  (when (with-current-buffer gnus-summary-buffer
+         (and gnus-use-trees
+              gnus-show-threads
+              (vectorp (gnus-summary-article-header article))))
+    (save-excursion
+      (let ((top (with-current-buffer gnus-summary-buffer
+                  (gnus-cut-thread
+                   (gnus-remove-thread
+                    (mail-header-id
+                     (gnus-summary-article-header article))
+                    t))))
+           (gnus-tmp-limit gnus-newsgroup-limit)
+           (gnus-tmp-sparse gnus-newsgroup-sparse))
+       (when (or force
+                 (not (eq top gnus-tree-displayed-thread)))
+         (gnus-generate-tree top)
+         (setq gnus-tree-displayed-thread top))))))
+
+(defun gnus-tree-open ()
+  (gnus-get-tree-buffer))
+
+(defun gnus-tree-close ()
+  (gnus-kill-buffer gnus-tree-buffer))
+
+(defun gnus-tree-perhaps-minimize ()
+  (when (and gnus-tree-minimize-window
+            (get-buffer gnus-tree-buffer))
+    (with-current-buffer gnus-tree-buffer
+      (gnus-tree-minimize))))
+
+(defun gnus-highlight-selected-tree (article)
+  "Highlight the selected article in the tree."
+  (when (buffer-live-p gnus-tree-buffer)
+    (let ((buf (current-buffer))
+         region)
+      (set-buffer gnus-tree-buffer)
+      (when (setq region (gnus-tree-article-region article))
+       (when (or (not gnus-selected-tree-overlay)
+                 (gnus-extent-detached-p gnus-selected-tree-overlay))
+         ;; Create a new overlay.
+         (overlay-put
+          (setq gnus-selected-tree-overlay
+                (make-overlay (point-min) (1+ (point-min))))
+          'face gnus-selected-tree-face))
+       ;; Move the overlay to the article.
+       (move-overlay
+        gnus-selected-tree-overlay (goto-char (car region)) (cdr region))
+       (gnus-tree-minimize)
+       (gnus-tree-recenter)
+       (let ((selected (selected-window)))
+         (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?!?
+      (with-current-buffer gnus-tree-buffer
+       (gnus-set-mode-line 'tree))
+      (set-buffer buf))))
+
+(defun gnus-tree-highlight-article (article face)
+  ;; The save-excursion here is apparently necessary because
+  ;; `set-window-point' somehow manages to alter the buffer position.
+  (save-excursion
+    (with-current-buffer (gnus-get-tree-buffer)
+      (let (region)
+       (when (setq region (gnus-tree-article-region article))
+         (gnus-put-text-property (car region) (cdr region) 'face face)
+         (set-window-point
+          (gnus-get-buffer-window (current-buffer) t) (cdr region)))))))
+
+;;; Allow redefinition of functions.
+(gnus-ems-redefine)
+
+(provide 'gnus-salt)
+
+;;; gnus-salt.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-score.el b/xemacs-packages/gnus/lisp/gnus-score.el
new file mode 100644 (file)
index 0000000..d3a1139
--- /dev/null
@@ -0,0 +1,3088 @@
+;;; gnus-score.el --- scoring code for Gnus
+
+;; Copyright (C) 1995-2016 Free Software Foundation, Inc.
+
+;; Author: Per Abrahamsen <amanda@iesd.auc.dk>
+;;     Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'gnus)
+(require 'gnus-sum)
+(require 'gnus-range)
+(require 'gnus-win)
+(require 'message)
+(require 'score-mode)
+(require 'gmm-utils)
+
+(defcustom gnus-global-score-files nil
+  "List of global score files and directories.
+Set this variable if you want to use people's score files.  One entry
+for each score file or each score file directory.  Gnus will decide
+by itself what score files are applicable to which group.
+
+Say you want to use the single score file
+\"/ftp.gnus.org@ftp:/pub/larsi/ding/score/soc.motss.SCORE\" and all
+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\"))"
+  :group 'gnus-score-files
+  :type '(repeat file))
+
+(defcustom gnus-score-file-single-match-alist nil
+  "Alist mapping regexps to lists of score files.
+Each element of this alist should be of the form
+       (\"REGEXP\" [ \"SCORE-FILE-1\" ] [ \"SCORE-FILE-2\" ] ... )
+
+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').
+
+These score files are loaded in addition to any files returned by
+`gnus-score-find-score-files-function'."
+  :group 'gnus-score-files
+  :type '(repeat (cons regexp (repeat file))))
+
+(defcustom gnus-score-file-multiple-match-alist nil
+  "Alist mapping regexps to lists of score files.
+Each element of this alist should be of the form
+       (\"REGEXP\" [ \"SCORE-FILE-1\" ] [ \"SCORE-FILE-2\" ] ... )
+
+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').
+
+These score files are loaded in addition to any files returned by
+`gnus-score-find-score-files-function'."
+  :group 'gnus-score-files
+  :type '(repeat (cons regexp (repeat file))))
+
+(defcustom gnus-score-file-suffix "SCORE"
+  "Suffix of the score files."
+  :group 'gnus-score-files
+  :type 'string)
+
+(defcustom gnus-adaptive-file-suffix "ADAPT"
+  "Suffix of the adaptive score files."
+  :group 'gnus-score-files
+  :group 'gnus-score-adapt
+  :type 'string)
+
+(defcustom gnus-score-find-score-files-function 'gnus-score-find-bnews
+  "Function used to find score files.
+The function will be called with the group name as the argument, and
+should return a list of score files to apply to that group.  The score
+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.
+
+See the documentation to these functions for more information.
+
+This variable can also be a list of functions to be called.  Each
+function is given the group name as argument and should either return
+a list of score files, or a list of score alists.
+
+If functions other than these pre-defined functions are used,
+the `a' symbolic prefix to the score commands will always use
+\"all.SCORE\"."
+  :group 'gnus-score-files
+  :type '(radio (function-item gnus-score-find-single)
+               (function-item gnus-score-find-hierarchical)
+               (function-item gnus-score-find-bnews)
+               (repeat :tag "List of functions"
+                       (choice (function :tag "Other" :value 'ignore)
+                               (function-item gnus-score-find-single)
+                               (function-item gnus-score-find-hierarchical)
+                               (function-item gnus-score-find-bnews)))
+               (function :tag "Other" :value 'ignore)))
+
+(defcustom gnus-score-interactive-default-score 1000
+  "*Scoring commands will raise/lower the score with this number as the default."
+  :group 'gnus-score-default
+  :type 'integer)
+
+(defcustom gnus-score-expiry-days 7
+  "*Number of days before unused score file entries are expired.
+If this variable is nil, no score file entries will be expired."
+  :group 'gnus-score-expire
+  :type '(choice (const :tag "never" nil)
+                number))
+
+(defcustom gnus-update-score-entry-dates t
+  "*If non-nil, update matching score entry dates.
+If this variable is nil, then score entries that provide matches
+will be expired along with non-matching score entries."
+  :group 'gnus-score-expire
+  :type 'boolean)
+
+(defcustom gnus-decay-scores nil
+  "*If non-nil, decay non-permanent scores.
+
+If it is a regexp, only decay score files matching regexp."
+  :group 'gnus-score-decay
+  :type `(choice (const :tag "never" nil)
+                (const :tag "always" t)
+                (const :tag "adaptive score files"
+                       ,(concat "\\." gnus-adaptive-file-suffix "\\'"))
+                (regexp)))
+
+(defcustom gnus-decay-score-function 'gnus-decay-score
+  "*Function called to decay a score.
+It is called with one parameter -- the score to be decayed."
+  :group 'gnus-score-decay
+  :type '(radio (function-item gnus-decay-score)
+               (function :tag "Other")))
+
+(defcustom gnus-score-decay-constant 3
+  "*Decay all \"small\" scores with this amount."
+  :group 'gnus-score-decay
+  :type 'integer)
+
+(defcustom gnus-score-decay-scale .05
+  "*Decay all \"big\" scores with this factor."
+  :group 'gnus-score-decay
+  :type 'number)
+
+(defcustom gnus-home-score-file nil
+  "Variable to control where interactive score entries are to go.
+It can be:
+
+ * A string
+   This file will be used as the home score file.
+
+ * A function
+   The result of this function will be used as the home score file.
+   The function will be passed the name of the group as its
+   parameter.
+
+ * A list
+   The elements in this list can be:
+
+   * `(regexp file-name ...)'
+     If the `regexp' matches the group name, the first `file-name'
+     will be used as the home score file.  (Multiple filenames are
+     allowed so that one may use gnus-score-file-single-match-alist to
+     set this variable.)
+
+   * A function.
+     If the function returns non-nil, the result will be used
+     as the home score file.  The function will be passed the
+     name of the group as its parameter.
+
+   * A string.  Use the string as the home score file.
+
+   The list will be traversed from the beginning towards the end looking
+   for matches."
+  :group 'gnus-score-files
+  :type '(choice string
+                (repeat (choice string
+                                (cons regexp (repeat file))
+                                function))
+                (function-item gnus-hierarchial-home-score-file)
+                (function-item gnus-current-home-score-file)
+                function))
+
+(defcustom gnus-home-adapt-file nil
+  "Variable to control where new adaptive score entries are to go.
+This variable allows the same syntax as `gnus-home-score-file'."
+  :group 'gnus-score-adapt
+  :group 'gnus-score-files
+  :type '(choice string
+                (repeat (choice string
+                                (cons regexp (repeat file))
+                                function))
+                function))
+
+(defcustom gnus-default-adaptive-score-alist
+  `((gnus-kill-file-mark)
+    (gnus-unread-mark)
+    (gnus-read-mark
+     (from , (+ 2 gnus-score-decay-constant))
+     (subject , (+ 27 gnus-score-decay-constant)))
+    (gnus-catchup-mark
+     (subject , (+ -7 (* -1 gnus-score-decay-constant))))
+    (gnus-killed-mark
+     (from , (- -1 gnus-score-decay-constant))
+     (subject , (+ -17 (* -1 gnus-score-decay-constant))))
+    (gnus-del-mark
+     (from , (- -1 gnus-score-decay-constant))
+     (subject , (+ -12 (* -1 gnus-score-decay-constant)))))
+  "Alist of marks and scores.
+If you use score decays, you might want to set values higher than
+`gnus-score-decay-constant'."
+  :group 'gnus-score-adapt
+  :type '(repeat (cons (symbol :tag "Mark")
+                      (repeat (list (choice :tag "Header"
+                                            (const from)
+                                            (const subject)
+                                            (symbol :tag "other"))
+                                    (integer :tag "Score"))))))
+
+(defcustom gnus-adaptive-word-length-limit nil
+  "*Words of a length lesser than this limit will be ignored when doing adaptive scoring."
+  :version "22.1"
+  :group 'gnus-score-adapt
+  :type '(radio (const :format "Unlimited " nil)
+               (integer :format "Maximum length: %v")))
+
+(defcustom gnus-ignored-adaptive-words nil
+  "List of words to be ignored when doing adaptive word scoring."
+  :group 'gnus-score-adapt
+  :type '(repeat string))
+
+(defcustom gnus-default-ignored-adaptive-words
+  '("a" "i" "the" "to" "of" "and" "in" "is" "it" "for" "that" "if" "you"
+    "this" "be" "on" "with" "not" "have" "are" "or" "as" "from" "can"
+    "but" "by" "at" "an" "will" "no" "all" "was" "do" "there" "my" "one"
+    "so" "we" "they" "what" "would" "any" "which" "about" "get" "your"
+    "use" "some" "me" "then" "name" "like" "out" "when" "up" "time"
+    "other" "more" "only" "just" "end" "also" "know" "how" "new" "should"
+    "been" "than" "them" "he" "who" "make" "may" "people" "these" "now"
+    "their" "here" "into" "first" "could" "way" "had" "see" "work" "well"
+    "were" "two" "very" "where" "while" "us" "because" "good" "same"
+    "even" "much" "most" "many" "such" "long" "his" "over" "last" "since"
+    "right" "before" "our" "without" "too" "those" "why" "must" "part"
+    "being" "current" "back" "still" "go" "point" "value" "each" "did"
+    "both" "true" "off" "say" "another" "state" "might" "under" "start"
+    "try" "re")
+  "*Default list of words to be ignored when doing adaptive word scoring."
+  :group 'gnus-score-adapt
+  :type '(repeat string))
+
+(defcustom gnus-default-adaptive-word-score-alist
+  `((,gnus-read-mark . 30)
+    (,gnus-catchup-mark . -10)
+    (,gnus-killed-mark . -20)
+    (,gnus-del-mark . -15))
+  "*Alist of marks and scores."
+  :group 'gnus-score-adapt
+  :type '(repeat (cons (character :tag "Mark")
+                      (integer :tag "Score"))))
+
+(defcustom gnus-adaptive-word-minimum nil
+  "If a number, this is the minimum score value that can be assigned to a word."
+  :group 'gnus-score-adapt
+  :type '(choice (const nil) integer))
+
+(defcustom gnus-adaptive-word-no-group-words nil
+  "If t, don't adaptively score words included in the group name."
+  :group 'gnus-score-adapt
+  :type 'boolean)
+
+(defcustom gnus-score-mimic-keymap nil
+  "*Have the score entry functions pretend that they are a keymap."
+  :group 'gnus-score-default
+  :type 'boolean)
+
+(defcustom gnus-score-exact-adapt-limit 10
+  "*Number that says how long a match has to be before using substring matching.
+When doing adaptive scoring, one normally uses fuzzy or substring
+matching.  However, if the header one matches is short, the possibility
+for false positives is great, so if the length of the match is less
+than this variable, exact matching will be used.
+
+If this variable is nil, exact matching will always be used."
+  :group 'gnus-score-adapt
+  :type '(choice (const nil) integer))
+
+(defcustom gnus-score-uncacheable-files "ADAPT$"
+  "All score files that match this regexp will not be cached."
+  :group 'gnus-score-adapt
+  :group 'gnus-score-files
+  :type 'regexp)
+
+(defcustom gnus-adaptive-pretty-print nil
+  "If non-nil, adaptive score files fill are pretty printed."
+  :group 'gnus-score-files
+  :group 'gnus-score-adapt
+  :version "23.1" ;; No Gnus
+  :type 'boolean)
+
+(defcustom gnus-score-default-header nil
+  "Default header when entering new scores.
+
+Should be one of the following symbols.
+
+ a: from
+ s: subject
+ b: body
+ h: head
+ i: message-id
+ t: references
+ x: xref
+ e: `extra' (non-standard overview)
+ l: lines
+ d: date
+ f: followup
+
+If nil, the user will be asked for a header."
+  :group 'gnus-score-default
+  :type '(choice (const :tag "from" a)
+                (const :tag "subject" s)
+                (const :tag "body" b)
+                (const :tag "head" h)
+                (const :tag "message-id" i)
+                (const :tag "references" t)
+                (const :tag "xref" x)
+                (const :tag "extra" e)
+                (const :tag "lines" l)
+                (const :tag "date" d)
+                (const :tag "followup" f)
+                (const :tag "ask" nil)))
+
+(defcustom gnus-score-default-type nil
+  "Default match type when entering new scores.
+
+Should be one of the following symbols.
+
+ s: substring
+ e: exact string
+ f: fuzzy string
+ r: regexp string
+ b: before date
+ a: after date
+ n: this date
+ <: less than number
+ >: greater than number
+ =: equal to number
+
+If nil, the user will be asked for a match type."
+  :group 'gnus-score-default
+  :type '(choice (const :tag "substring" s)
+                (const :tag "exact string" e)
+                (const :tag "fuzzy string" f)
+                (const :tag "regexp string" r)
+                (const :tag "before date" b)
+                (const :tag "after date" a)
+                (const :tag "this date" n)
+                (const :tag "less than number" <)
+                (const :tag "greater than number" >)
+                (const :tag "equal than number" =)
+                (const :tag "ask" nil)))
+
+(defcustom gnus-score-default-fold nil
+  "Non-nil means use case folding for new score file entries."
+  :group 'gnus-score-default
+  :type 'boolean)
+
+(defcustom gnus-score-default-duration nil
+  "Default duration of effect when entering new scores.
+
+Should be one of the following symbols.
+
+ t: temporary
+ p: permanent
+ i: immediate
+
+If nil, the user will be asked for a duration."
+  :group 'gnus-score-default
+  :type '(choice (const :tag "temporary" t)
+                (const :tag "permanent" p)
+                (const :tag "immediate" i)
+                (const :tag "ask" nil)))
+
+(defcustom gnus-score-after-write-file-function nil
+  "Function called with the name of the score file just written to disk."
+  :group 'gnus-score-files
+  :type '(choice (const nil) function))
+
+(defcustom gnus-score-thread-simplify nil
+  "If non-nil, subjects will simplified as in threading."
+  :group 'gnus-score-various
+  :type 'boolean)
+
+(defcustom gnus-inhibit-slow-scoring nil
+  "Inhibit slow scoring, e.g. scoring on headers or body.
+
+If a regexp, scoring on headers or body is inhibited if the group
+matches the regexp.  If it is t, scoring on headers or body is
+inhibited for all groups."
+  :group 'gnus-score-various
+  :version "23.1" ;; No Gnus
+  :type '(choice (const :tag "All" nil)
+                (const :tag "None" t)
+                regexp))
+
+\f
+
+;; Internal variables.
+
+(defvar gnus-score-use-all-scores t
+  "If nil, only `gnus-score-find-score-files-function' is used.")
+
+(defvar gnus-adaptive-word-syntax-table
+  (let ((table (copy-syntax-table (standard-syntax-table)))
+       (numbers '(?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9)))
+    (while numbers
+      (modify-syntax-entry (pop numbers) " " table))
+    (modify-syntax-entry ?' "w" table)
+    table)
+  "Syntax table used when doing adaptive word scoring.")
+
+(defvar gnus-scores-exclude-files nil)
+(defvar gnus-internal-global-score-files nil)
+(defvar gnus-score-file-list nil)
+
+(defvar gnus-short-name-score-file-cache nil)
+
+(defvar gnus-score-help-winconf nil)
+(defvar gnus-adaptive-score-alist gnus-default-adaptive-score-alist)
+(defvar gnus-adaptive-word-score-alist gnus-default-adaptive-word-score-alist)
+(defvar gnus-score-trace nil)
+(defvar gnus-score-edit-buffer nil)
+
+(defvar gnus-score-alist nil
+  "Alist containing score information.
+The keys can be symbols or strings.  The following symbols are defined.
+
+touched: If this alist has been modified.
+mark:    Automatically mark articles below this.
+expunge: Automatically expunge articles below this.
+files:   List of other score files to load when loading this one.
+eval:    Sexp to be evaluated when the score file is loaded.
+
+String entries have the form (HEADER (MATCH TYPE SCORE DATE) ...)
+where HEADER is the header being scored, MATCH is the string we are
+looking for, TYPE is a flag indicating whether it should use regexp or
+substring matching, SCORE is the score to add and DATE is the date
+of the last successful match.")
+
+(defvar gnus-score-cache nil)
+(defvar gnus-scores-articles nil)
+(defvar gnus-score-index nil)
+
+
+(defconst gnus-header-index
+  ;; Name to index alist.
+  '(("number" 0 gnus-score-integer)
+    ("subject" 1 gnus-score-string)
+    ("from" 2 gnus-score-string)
+    ("date" 3 gnus-score-date)
+    ("message-id" 4 gnus-score-string)
+    ("references" 5 gnus-score-string)
+    ("chars" 6 gnus-score-integer)
+    ("lines" 7 gnus-score-integer)
+    ("xref" 8 gnus-score-string)
+    ("extra" 9 gnus-score-string)
+    ("head" -1 gnus-score-body)
+    ("body" -1 gnus-score-body)
+    ("all" -1 gnus-score-body)
+    ("followup" 2 gnus-score-followup)
+    ("thread" 5 gnus-score-thread)))
+
+;;; Summary mode score maps.
+
+(gnus-define-keys (gnus-summary-score-map "V" gnus-summary-mode-map)
+  "s" gnus-summary-set-score
+  "S" gnus-summary-current-score
+  "c" gnus-score-change-score-file
+  "C" gnus-score-customize
+  "m" gnus-score-set-mark-below
+  "x" gnus-score-set-expunge-below
+  "R" gnus-summary-rescore
+  "e" gnus-score-edit-current-scores
+  "f" gnus-score-edit-file
+  "F" gnus-score-flush-cache
+  "t" gnus-score-find-trace
+  "w" gnus-score-find-favourite-words)
+
+;; Summary score file commands
+
+;; Much modification of the kill (ahem, score) code and lots of the
+;; functions are written by Per Abrahamsen <amanda@iesd.auc.dk>.
+
+(defun gnus-summary-lower-score (&optional score symp)
+  "Make a score entry based on the current article.
+The user will be prompted for header to score on, match type,
+permanence, and the string to be used.  The numerical prefix will
+be used as SCORE.  A symbolic prefix of `a' (the SYMP parameter)
+says to use the `all.SCORE' file for the command instead of the
+current score file."
+  (interactive (gnus-interactive "P\ny"))
+  (gnus-summary-increase-score (- (gnus-score-delta-default score)) symp))
+
+(defun gnus-score-kill-help-buffer ()
+  (when (get-buffer "*Score Help*")
+    (kill-buffer "*Score Help*")
+    (when gnus-score-help-winconf
+      (set-window-configuration gnus-score-help-winconf))))
+
+(defun gnus-summary-increase-score (&optional score symp)
+  "Make a score entry based on the current article.
+The user will be prompted for header to score on, match type,
+permanence, and the string to be used.  The numerical prefix will
+be used as SCORE.  A symbolic prefix of `a' (the SYMP parameter)
+says to use the `all.SCORE' file for the command instead of the
+current score file."
+  (interactive (gnus-interactive "P\ny"))
+  (let* ((nscore (gnus-score-delta-default score))
+        (prefix (if (< nscore 0) ?L ?I))
+        (increase (> nscore 0))
+        (char-to-header
+         '((?a "from" nil nil string)
+           (?s "subject" nil nil string)
+           (?b "body" "" nil body-string)
+           (?h "head" "" nil body-string)
+           (?i "message-id" nil nil string)
+           (?r "references" "message-id" nil string)
+           (?x "xref" nil nil string)
+           (?e "extra" nil nil string)
+           (?l "lines" nil nil number)
+           (?d "date" nil nil date)
+           (?f "followup" nil nil string)
+           (?t "thread" "message-id" nil string)))
+        (char-to-type
+         '((?s s "substring" string)
+           (?e e "exact string" string)
+           (?f f "fuzzy string" string)
+           (?r r "regexp string" string)
+           (?z s "substring" body-string)
+           (?p r "regexp string" body-string)
+           (?b before "before date" date)
+           (?a after "after date" date)
+           (?n at "this date" date)
+           (?< < "less than number" number)
+           (?> > "greater than number" number)
+           (?= = "equal to number" number)))
+        (current-score-file gnus-current-score-file)
+        (char-to-perm
+         (list (list ?t (current-time-string) "temporary")
+               '(?p perm "permanent") '(?i now "immediate")))
+        (mimic gnus-score-mimic-keymap)
+        (hchar (and gnus-score-default-header
+                    (aref (symbol-name gnus-score-default-header) 0)))
+        (tchar (and gnus-score-default-type
+                    (aref (symbol-name gnus-score-default-type) 0)))
+        (pchar (and gnus-score-default-duration
+                    (aref (symbol-name gnus-score-default-duration) 0)))
+        entry temporary type match extra)
+
+    (unwind-protect
+       (progn
+
+         ;; First we read the header to score.
+         (while (not hchar)
+           (if mimic
+               (progn
+                 (sit-for 1)
+                 (message "%c-" prefix))
+             (message "%s header (%s?): " (if increase "Increase" "Lower")
+                      (mapconcat (lambda (s) (char-to-string (car s)))
+                                 char-to-header "")))
+           (setq hchar (read-char))
+           (when (or (= hchar ??) (= hchar ?\C-h))
+             (setq hchar nil)
+             (gnus-score-insert-help "Match on header" char-to-header 1)))
+
+         (gnus-score-kill-help-buffer)
+         (unless (setq entry (assq (downcase hchar) char-to-header))
+           (if mimic (error "%c %c" prefix hchar)
+             (error "Invalid header type")))
+
+         (when (/= (downcase hchar) hchar)
+           ;; This was a majuscule, so we end reading and set the defaults.
+           (if mimic (message "%c %c" prefix hchar) (message ""))
+           (setq tchar (or tchar ?s)
+                 pchar (or pchar ?t)))
+
+         (let ((legal-types
+                (delq nil
+                      (mapcar (lambda (s)
+                                (if (eq (nth 4 entry)
+                                        (nth 3 s))
+                                    s nil))
+                              char-to-type))))
+           ;; We continue reading - the type.
+           (while (not tchar)
+             (if mimic
+                 (progn
+                   (sit-for 1) (message "%c %c-" prefix hchar))
+               (message "%s header `%s' with match type (%s?): "
+                        (if increase "Increase" "Lower")
+                        (nth 1 entry)
+                        (mapconcat (lambda (s) (char-to-string (car s)))
+                                   legal-types "")))
+             (setq tchar (read-char))
+             (when (or (= tchar ??) (= tchar ?\C-h))
+               (setq tchar nil)
+               (gnus-score-insert-help "Match type" legal-types 2)))
+
+           (gnus-score-kill-help-buffer)
+           (unless (setq type (nth 1 (assq (downcase tchar) legal-types)))
+             (if mimic (error "%c %c" prefix hchar)
+               (error "Invalid match type"))))
+
+         (when (/= (downcase tchar) tchar)
+           ;; It was a majuscule, so we end reading and use the default.
+           (if mimic (message "%c %c %c" prefix hchar tchar)
+             (message ""))
+           (setq pchar (or pchar ?t)))
+
+         ;; We continue reading.
+         (while (not pchar)
+           (if mimic
+               (progn
+                 (sit-for 1) (message "%c %c %c-" prefix hchar tchar))
+             (message "%s permanence (%s?): " (if increase "Increase" "Lower")
+                      (mapconcat (lambda (s) (char-to-string (car s)))
+                                 char-to-perm "")))
+           (setq pchar (read-char))
+           (when (or (= pchar ??) (= pchar ?\C-h))
+             (setq pchar nil)
+             (gnus-score-insert-help "Match permanence" char-to-perm 2)))
+
+         (gnus-score-kill-help-buffer)
+         (if mimic (message "%c %c %c %c" prefix hchar tchar pchar)
+           (message ""))
+         (unless (setq temporary (cadr (assq pchar char-to-perm)))
+           ;; Deal with der(r)ided superannuated paradigms.
+           (when (and (eq (1+ prefix) 77)
+                      (eq (+ hchar 12) 109)
+                      (eq (1- tchar) 113)
+                      (eq (- pchar 4) 111))
+             (error "You rang?"))
+           (if mimic
+               (error "%c %c %c %c" prefix hchar tchar pchar)
+             (error "Invalid match duration"))))
+      ;; Always kill the score help buffer.
+      (gnus-score-kill-help-buffer))
+
+    ;; If scoring an extra (non-standard overview) header,
+    ;; we must find out which header is in question.
+    (setq extra
+         (and gnus-extra-headers
+              (equal (nth 1 entry) "extra")
+              (intern                  ; need symbol
+                (let ((collection (mapcar 'symbol-name gnus-extra-headers)))
+                  (gnus-completing-read
+                   "Score extra header"  ; prompt
+                   collection            ; completion list
+                   t                     ; require match
+                   nil                   ; no history
+                   nil                   ; no initial-input
+                   (car collection)))))) ; default value
+    ;; extra is now nil or a symbol.
+
+    ;; We have all the data, so we enter this score.
+    (setq match (if (string= (nth 2 entry) "") ""
+                 (gnus-summary-header (or (nth 2 entry) (nth 1 entry))
+                                      nil extra)))
+
+    ;; Modify the match, perhaps.
+    (cond
+     ((equal (nth 1 entry) "xref")
+      (when (string-match "^Xref: *" match)
+       (setq match (substring match (match-end 0))))
+      (when (string-match "^[^:]* +" match)
+       (setq match (substring match (match-end 0))))))
+
+    (when (memq type '(r R regexp Regexp))
+      (setq match (regexp-quote match)))
+
+    ;; Change score file to the "all.SCORE" file.
+    (when (eq symp 'a)
+      (with-current-buffer gnus-summary-buffer
+       (gnus-score-load-file
+        ;; This is a kludge; yes...
+        (cond
+         ((eq gnus-score-find-score-files-function
+              'gnus-score-find-hierarchical)
+          (gnus-score-file-name ""))
+         ((eq gnus-score-find-score-files-function 'gnus-score-find-single)
+          current-score-file)
+         (t
+          (gnus-score-file-name "all"))))))
+
+    (gnus-summary-score-entry
+     (nth 1 entry)                     ; Header
+     match                             ; Match
+     type                              ; Type
+     (if (eq score 's) nil score)      ; Score
+     (if (eq temporary 'perm)          ; Temp
+        nil
+       temporary)
+     (not (nth 3 entry))               ; Prompt
+     nil                               ; not silent
+     extra)                            ; non-standard overview.
+
+    (when (eq symp 'a)
+      ;; We change the score file back to the previous one.
+      (with-current-buffer gnus-summary-buffer
+       (gnus-score-load-file current-score-file)))))
+
+(defun gnus-score-insert-help (string alist idx)
+  (setq gnus-score-help-winconf (current-window-configuration))
+  (with-current-buffer (gnus-get-buffer-create "*Score Help*")
+    (buffer-disable-undo)
+    (delete-windows-on (current-buffer))
+    (erase-buffer)
+    (insert string ":\n\n")
+    (let ((max -1)
+         (list alist)
+         (i 0)
+         n width pad format)
+      ;; find the longest string to display
+      (while list
+       (setq n (length (nth idx (car list))))
+       (unless (> max n)
+         (setq max n))
+       (setq list (cdr list)))
+      (setq max (+ max 4))             ; %c, `:', SPACE, a SPACE at end
+      (setq n (/ (1- (window-width)) max)) ; items per line
+      (setq width (/ (1- (window-width)) n)) ; width of each item
+      ;; insert `n' items, each in a field of width `width'
+      (while alist
+       (if (< i n)
+           ()
+         (setq i 0)
+         (delete-char -1)              ; the `\n' takes a char
+         (insert "\n"))
+       (setq pad (- width 3))
+       (setq format (concat "%c: %-" (int-to-string pad) "s"))
+       (insert (format format (caar alist) (nth idx (car alist))))
+       (setq alist (cdr alist))
+       (setq i (1+ i))))
+    (goto-char (point-min))
+    ;; display ourselves in a small window at the bottom
+    (gnus-select-lowest-window)
+    (if (< (/ (window-height) 2) window-min-height)
+       (switch-to-buffer "*Score Help*")
+      (split-window)
+      (pop-to-buffer "*Score Help*"))
+    (let ((window-min-height 1))
+      (shrink-window-if-larger-than-buffer))
+    (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.
+  (let ((article (gnus-summary-article-number))
+       headers)
+    (if article
+       (if (and (setq headers (gnus-summary-article-header article))
+                (vectorp headers))
+           (if extra                   ; `header' must be "extra"
+               (or (cdr (assq extra (mail-header-extra headers))) "")
+             (aref headers (nth 1 (assoc header gnus-header-index))))
+         (if no-err
+             nil
+           (error "Pseudo-articles can't be scored")))
+      (if no-err
+         (error "No article on current line")
+       nil))))
+
+(defun gnus-newsgroup-score-alist ()
+  (or
+   (let ((param-file (gnus-group-find-parameter
+                     gnus-newsgroup-name 'score-file)))
+     (when param-file
+       (gnus-score-load param-file)))
+   (gnus-score-load
+    (gnus-score-file-name gnus-newsgroup-name)))
+  gnus-score-alist)
+
+(defsubst gnus-score-get (symbol &optional alist)
+  ;; Get SYMBOL's definition in ALIST.
+  (cdr (assoc symbol
+             (or alist
+                 gnus-score-alist
+                 (gnus-newsgroup-score-alist)))))
+
+(defun gnus-summary-score-entry (header match type score date
+                                       &optional prompt silent extra)
+  "Enter score file entry.
+HEADER is the header being scored.
+MATCH is the string we are looking for.
+TYPE is the match type: substring, regexp, exact, fuzzy.
+SCORE is the score to add.
+DATE is the expire date, or nil for no expire, or 'now for immediate expire.
+If optional argument `PROMPT' is non-nil, allow user to edit match.
+If optional argument `SILENT' is nil, show effect of score entry.
+If optional argument `EXTRA' is non-nil, it's a non-standard overview header."
+  ;; Regexp is the default type.
+  (when (eq type t)
+    (setq type 'r))
+  ;; Simplify matches...
+  (cond ((or (eq type 'r) (eq type 's) (eq type nil))
+        (setq match (if match (gnus-simplify-subject-re match) "")))
+       ((eq type 'f)
+        (setq match (gnus-simplify-subject-fuzzy match))))
+  (let ((score (gnus-score-delta-default score))
+       (header (downcase header))
+       new)
+    (set-text-properties 0 (length header) nil header)
+    (when prompt
+      (setq match (read-string
+                  (format "Match %s on %s, %s: "
+                          (cond ((eq date 'now)
+                                 "now")
+                                ((stringp date)
+                                 "temp")
+                                (t "permanent"))
+                          header
+                          (if (< score 0) "lower" "raise"))
+                  (if (numberp match)
+                      (int-to-string match)
+                    match))))
+
+    ;; If this is an integer comparison, we transform from string to int.
+    (if (eq (nth 2 (assoc header gnus-header-index)) 'gnus-score-integer)
+       (if (stringp match)
+           (setq match (string-to-number match)))
+      (set-text-properties 0 (length match) nil match))
+
+    (unless (eq date 'now)
+      ;; Add the score entry to the score file.
+      (when (= score gnus-score-interactive-default-score)
+       (setq score nil))
+      (let ((old (gnus-score-get header))
+           elem)
+       (setq new
+             (cond
+              (extra
+               (list match score
+                     (and date (if (numberp date) date
+                                 (date-to-day date)))
+                     type (symbol-name extra)))
+              (type
+               (list match score
+                     (and date (if (numberp date) date
+                                 (date-to-day date)))
+                     type))
+              (date (list match score (date-to-day date)))
+              (score (list match score))
+              (t (list match))))
+       ;; We see whether we can collapse some score entries.
+       ;; This isn't quite correct, because there may be more elements
+       ;; later on with the same key that have matching elems...  Hm.
+       (if (and old
+                (setq elem (assoc match old))
+                (eq (nth 3 elem) (nth 3 new))
+                (or (and (numberp (nth 2 elem)) (numberp (nth 2 new)))
+                    (and (not (nth 2 elem)) (not (nth 2 new)))))
+           ;; Yup, we just add this new score to the old elem.
+           (setcar (cdr elem) (+ (or (nth 1 elem)
+                                     gnus-score-interactive-default-score)
+                                 (or (nth 1 new)
+                                     gnus-score-interactive-default-score)))
+         ;; Nope, we have to add a new elem.
+         (gnus-score-set header (if old (cons new old) (list new)) nil t))
+       (gnus-score-set 'touched '(t))))
+
+    ;; Score the current buffer.
+    (unless silent
+      (if (and (>= (nth 1 (assoc header gnus-header-index)) 0)
+              (eq (nth 2 (assoc header gnus-header-index))
+                  'gnus-score-string))
+         (gnus-summary-score-effect header match type score extra)
+       (gnus-summary-rescore)))
+
+    ;; Return the new scoring rule.
+    new))
+
+(defun gnus-summary-score-effect (header match type score &optional extra)
+  "Simulate the effect of a score file entry.
+HEADER is the header being scored.
+MATCH is the string we are looking for.
+TYPE is the score type.
+SCORE is the score to add.
+EXTRA is the possible non-standard header."
+  (interactive (list (gnus-completing-read "Header"
+                                           (mapcar
+                                            'car
+                                            (gnus-remove-if-not
+                                             (lambda (x) (fboundp (nth 2 x)))
+                                             gnus-header-index))
+                                           t)
+                    (read-string "Match: ")
+                    (if (y-or-n-p "Use regexp match? ") 'r 's)
+                    (string-to-number (read-string "Score: "))))
+  (save-excursion
+    (unless (and (stringp match) (> (length match) 0))
+      (error "No match"))
+    (goto-char (point-min))
+    (let ((regexp (cond ((eq type 'f)
+                        (gnus-simplify-subject-fuzzy match))
+                       ((eq type 'r)
+                        match)
+                       ((eq type 'e)
+                        (concat "\\`" (regexp-quote match) "\\'"))
+                       (t
+                        (regexp-quote match)))))
+      (while (not (eobp))
+       (let ((content (gnus-summary-header header 'noerr extra))
+             (case-fold-search t))
+         (and content
+              (when (if (eq type 'f)
+                        (string-equal (gnus-simplify-subject-fuzzy content)
+                                      regexp)
+                      (string-match regexp content))
+                (gnus-summary-raise-score score))))
+       (beginning-of-line 2))))
+  (gnus-set-mode-line 'summary))
+\f
+;;;
+;;; Gnus Score Files
+;;;
+
+;; All score code written by Per Abrahamsen <abraham@iesd.auc.dk>.
+
+(defun gnus-score-set-mark-below (score)
+  "Automatically mark articles with score below SCORE as read."
+  (interactive
+   (list (or (and current-prefix-arg (prefix-numeric-value current-prefix-arg))
+            (string-to-number (read-string "Mark below: ")))))
+  (setq score (or score gnus-summary-default-score 0))
+  (gnus-score-set 'mark (list score))
+  (gnus-score-set 'touched '(t))
+  (setq gnus-summary-mark-below score)
+  (gnus-score-update-lines))
+
+(defun gnus-score-update-lines ()
+  "Update all lines in the summary buffer."
+  (save-excursion
+    (goto-char (point-min))
+    (while (not (eobp))
+      (gnus-summary-update-line)
+      (forward-line 1))))
+
+(defun gnus-score-update-all-lines ()
+  "Update all lines in the summary buffer, even the hidden ones."
+  (save-excursion
+    (goto-char (point-min))
+    (let (hidden)
+      (while (not (eobp))
+       (when (gnus-summary-show-thread)
+         (push (point) hidden))
+       (gnus-summary-update-line)
+       (forward-line 1))
+      ;; Re-hide the hidden threads.
+      (while hidden
+       (goto-char (pop hidden))
+       (gnus-summary-hide-thread)))))
+
+(defun gnus-score-set-expunge-below (score)
+  "Automatically expunge articles with score below SCORE."
+  (interactive
+   (list (or (and current-prefix-arg (prefix-numeric-value current-prefix-arg))
+            (string-to-number (read-string "Set expunge below: ")))))
+  (setq score (or score gnus-summary-default-score 0))
+  (gnus-score-set 'expunge (list score))
+  (gnus-score-set 'touched '(t)))
+
+(defun gnus-score-followup-article (&optional score)
+  "Add SCORE to all followups to the article in the current buffer."
+  (interactive "P")
+  (setq score (gnus-score-delta-default score))
+  (when (gnus-buffer-live-p gnus-summary-buffer)
+    (save-excursion
+      (save-restriction
+       (message-narrow-to-headers)
+       (let ((id (mail-fetch-field "message-id")))
+         (when id
+           (set-buffer gnus-summary-buffer)
+           (gnus-summary-score-entry
+            "references" (concat id "[ \t]*$") 'r
+            score (current-time-string) nil t)))))))
+
+(defun gnus-score-followup-thread (&optional score)
+  "Add SCORE to all later articles in the thread the current buffer is part of."
+  (interactive "P")
+  (setq score (gnus-score-delta-default score))
+  (when (gnus-buffer-live-p gnus-summary-buffer)
+    (save-excursion
+      (save-restriction
+       (goto-char (point-min))
+       (let ((id (mail-fetch-field "message-id")))
+         (when id
+           (set-buffer gnus-summary-buffer)
+           (gnus-summary-score-entry
+            "references" id 's
+            score (current-time-string))))))))
+
+(defun gnus-score-set (symbol value &optional alist warn)
+  ;; Set SYMBOL to VALUE in ALIST.
+  (let* ((alist
+         (or alist
+             gnus-score-alist
+             (gnus-newsgroup-score-alist)))
+        (entry (assoc symbol alist)))
+    (cond ((gnus-score-get 'read-only alist)
+          ;; This is a read-only score file, so we do nothing.
+          (when warn
+            (gnus-message 4 "Note: read-only score file; entry discarded")))
+         (entry
+          (setcdr entry value))
+         ((null alist)
+          (error "Empty alist"))
+         (t
+          (setcdr alist
+                  (cons (cons symbol value) (cdr alist)))))))
+
+(defun gnus-summary-raise-score (n)
+  "Raise the score of the current article by N."
+  (interactive "p")
+  (gnus-summary-set-score (+ (gnus-summary-article-score)
+                            (or n gnus-score-interactive-default-score ))))
+
+(defun gnus-summary-set-score (n)
+  "Set the score of the current article to N."
+  (interactive "p")
+  (save-excursion
+    (gnus-summary-show-thread)
+    (let ((buffer-read-only nil))
+      ;; Set score.
+      (gnus-summary-update-mark
+       (if (= n (or gnus-summary-default-score 0)) ?  ;Whitespace
+        (if (< n (or gnus-summary-default-score 0))
+            gnus-score-below-mark gnus-score-over-mark))
+       'score))
+    (let* ((article (gnus-summary-article-number))
+          (score (assq article gnus-newsgroup-scored)))
+      (if score (setcdr score n)
+       (push (cons article n) gnus-newsgroup-scored)))
+    (gnus-summary-update-line)))
+
+(defun gnus-summary-current-score (arg)
+  "Return the score of the current article.
+  With prefix ARG, return the total score of the current (sub)thread."
+  (interactive "P")
+  (gnus-message 1 "%s" (if arg
+                          (gnus-thread-total-score
+                           (gnus-id-to-thread
+                            (mail-header-id (gnus-summary-article-header))))
+                          (gnus-summary-article-score))))
+
+(defun gnus-score-change-score-file (file)
+  "Change current score alist."
+  (interactive
+   (list (read-file-name "Change to score file: " gnus-kill-files-directory)))
+  (gnus-score-load-file file)
+  (gnus-set-mode-line 'summary))
+
+(defvar gnus-score-edit-exit-function)
+(defun gnus-score-edit-current-scores (file)
+  "Edit the current score alist."
+  (interactive (list gnus-current-score-file))
+  (if (not gnus-current-score-file)
+      (error "No current score file")
+    (let ((winconf (current-window-configuration)))
+      (when (buffer-name gnus-summary-buffer)
+       (gnus-score-save))
+      (gnus-make-directory (file-name-directory file))
+      (setq gnus-score-edit-buffer (find-file-noselect file))
+      (gnus-configure-windows 'edit-score)
+      (gnus-score-mode)
+      (setq gnus-score-edit-exit-function 'gnus-score-edit-done)
+      (make-local-variable 'gnus-prev-winconf)
+      (setq gnus-prev-winconf winconf))
+    (gnus-message
+     4 "%s" (substitute-command-keys
+            "\\<gnus-score-mode-map>\\[gnus-score-edit-exit] to save edits"))))
+
+(defun gnus-score-edit-all-score ()
+  "Edit the all.SCORE file."
+  (interactive)
+  (find-file (gnus-score-file-name "all"))
+  (gnus-score-mode)
+  (setq gnus-score-edit-exit-function 'gnus-score-edit-done)
+  (gnus-message
+   4 (substitute-command-keys
+      "\\<gnus-score-mode-map>\\[gnus-score-edit-exit] to save edits")))
+
+(defun gnus-score-edit-file (file)
+  "Edit a score file."
+  (interactive
+   (list (read-file-name "Edit score file: " gnus-kill-files-directory)))
+  (gnus-make-directory (file-name-directory file))
+  (when (buffer-name gnus-summary-buffer)
+    (gnus-score-save))
+  (let ((winconf (current-window-configuration)))
+    (setq gnus-score-edit-buffer (find-file-noselect file))
+    (gnus-configure-windows 'edit-score)
+    (gnus-score-mode)
+    (setq gnus-score-edit-exit-function 'gnus-score-edit-done)
+    (make-local-variable 'gnus-prev-winconf)
+    (setq gnus-prev-winconf winconf))
+  (gnus-message
+   4 "%s" (substitute-command-keys
+          "\\<gnus-score-mode-map>\\[gnus-score-edit-exit] to save edits")))
+
+(defun gnus-score-edit-file-at-point (&optional format)
+  "Edit score file at point in Score Trace buffers.
+If FORMAT, also format the current score file."
+  (let* ((rule (save-excursion
+                (beginning-of-line)
+                (read (current-buffer))))
+        (sep "[ \n\r\t]*")
+        ;; Must be synced with `gnus-score-find-trace':
+        (reg " -> +")
+        (file (save-excursion
+                (end-of-line)
+                (if (and (re-search-backward reg (point-at-bol) t)
+                         (re-search-forward  reg (point-at-eol) t))
+                    (buffer-substring (point) (point-at-eol))
+                  nil))))
+    (if (or (not file)
+           (string-match "\\<\\(non-file rule\\|A file\\)\\>" file)
+           ;; (see `gnus-score-find-trace' and `gnus-score-advanced')
+           (string= "" file))
+       (gnus-error 3 "Can't find a score file in current line.")
+      (gnus-score-edit-file file)
+      (when format
+       (gnus-score-pretty-print))
+      (when (consp rule) ;; the rule exists
+       (setq rule (mapconcat #'(lambda (obj)
+                                 (regexp-quote (format "%S" obj)))
+                             rule
+                             sep))
+       (goto-char (point-min))
+       (re-search-forward rule nil t)
+       ;; make it easy to use `kill-sexp':
+       (goto-char (1- (match-beginning 0)))))))
+
+(defun gnus-score-load-file (file)
+  ;; Load score file FILE.  Returns a list a retrieved score-alists.
+  (let* ((file (expand-file-name
+               (or (and (string-match
+                         (concat "^" (regexp-quote
+                                      (expand-file-name
+                                       gnus-kill-files-directory)))
+                         (expand-file-name file))
+                        file)
+                   (expand-file-name file gnus-kill-files-directory))))
+        (cached (assoc file gnus-score-cache))
+        (global (member file gnus-internal-global-score-files))
+        lists alist)
+    (if cached
+       ;; The score file was already loaded.
+       (setq alist (cdr cached))
+      ;; We load the score file.
+      (setq gnus-score-alist nil)
+      (setq alist (gnus-score-load-score-alist file))
+      ;; We add '(touched) to the alist to signify that it hasn't been
+      ;; touched (yet).
+      (unless (assq 'touched alist)
+       (push (list 'touched nil) alist))
+      ;; If it is a global score file, we make it read-only.
+      (and global
+          (not (assq 'read-only alist))
+          (push (list 'read-only t) alist))
+      (push (cons file alist) gnus-score-cache))
+    (let ((a alist)
+         found)
+      (while a
+       ;; Downcase all header names.
+       (cond
+        ((stringp (caar a))
+         (setcar (car a) (downcase (caar a)))
+         (setq found t))
+        ;; Advanced scoring.
+        ((consp (caar a))
+         (setq found t)))
+       (pop a))
+      ;; If there are actual scores in the alist, we add it to the
+      ;; return value of this function.
+      (when found
+       (setq lists (list alist))))
+    ;; Treat the other possible atoms in the score alist.
+    (let ((mark (car (gnus-score-get 'mark alist)))
+         (expunge (car (gnus-score-get 'expunge alist)))
+         (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)))
+         (adapt (gnus-score-get 'adapt alist))
+         (thread-mark-and-expunge
+          (car (gnus-score-get 'thread-mark-and-expunge alist)))
+         (adapt-file (car (gnus-score-get 'adapt-file alist)))
+         (local (gnus-score-get 'local alist))
+         (decay (car (gnus-score-get 'decay alist)))
+         (eval (car (gnus-score-get 'eval alist))))
+      ;; Perform possible decays.
+      (when (and (if (stringp gnus-decay-scores)
+                    (string-match gnus-decay-scores file)
+                  gnus-decay-scores)
+                (or cached (file-exists-p file))
+                (or (not decay)
+                    (gnus-decay-scores alist decay)))
+       (gnus-score-set 'touched '(t) alist)
+       (gnus-score-set 'decay (list (time-to-days (current-time))) alist))
+      ;; We do not respect eval and files atoms from global score
+      ;; files.
+      (when (and files (not global))
+       (setq lists (apply 'append lists
+                          (mapcar 'gnus-score-load-file
+                                  (if adapt-file (cons adapt-file files)
+                                    files)))))
+      (when (and eval (not global))
+       (eval eval))
+      ;; We then expand any exclude-file directives.
+      (setq gnus-scores-exclude-files
+           (nconc
+            (apply
+             'nconc
+             (mapcar
+              (lambda (sfile)
+                (list
+                 (expand-file-name sfile (file-name-directory file))
+                 (expand-file-name sfile gnus-kill-files-directory)))
+              exclude-files))
+            gnus-scores-exclude-files))
+      (when local
+       (with-current-buffer gnus-summary-buffer
+         (while local
+           (and (consp (car local))
+                (symbolp (caar local))
+                (progn
+                  (make-local-variable (caar local))
+                  (set (caar local) (nth 1 (car local)))))
+           (setq local (cdr local)))))
+      (when orphan
+       (setq gnus-orphan-score orphan))
+      (setq gnus-adaptive-score-alist
+           (cond ((equal adapt '(t))
+                  (setq gnus-newsgroup-adaptive t)
+                  gnus-default-adaptive-score-alist)
+                 ((equal adapt '(ignore))
+                  (setq gnus-newsgroup-adaptive nil))
+                 ((consp adapt)
+                  (setq gnus-newsgroup-adaptive t)
+                  adapt)
+                 (t
+                  gnus-default-adaptive-score-alist)))
+      (setq gnus-thread-expunge-below
+           (or thread-mark-and-expunge gnus-thread-expunge-below))
+      (setq gnus-summary-mark-below
+           (or mark mark-and-expunge gnus-summary-mark-below))
+      (setq gnus-summary-expunge-below
+           (or expunge mark-and-expunge gnus-summary-expunge-below))
+      (setq gnus-newsgroup-adaptive-score-file
+           (or adapt-file gnus-newsgroup-adaptive-score-file)))
+    (setq gnus-current-score-file file)
+    (setq gnus-score-alist alist)
+    lists))
+
+(defun gnus-score-load (file)
+  ;; Load score FILE.
+  (let ((cache (assoc file gnus-score-cache)))
+    (if cache
+       (setq gnus-score-alist (cdr cache))
+      (setq gnus-score-alist nil)
+      (gnus-score-load-score-alist file)
+      (unless gnus-score-alist
+       (setq gnus-score-alist (copy-alist '((touched nil)))))
+      (push (cons file gnus-score-alist) gnus-score-cache))))
+
+(defun gnus-score-remove-from-cache (file)
+  (setq gnus-score-cache
+       (delq (assoc file gnus-score-cache) gnus-score-cache)))
+
+(defun gnus-score-load-score-alist (file)
+  "Read score FILE."
+  (let (alist)
+    (if (not (file-readable-p file))
+       ;; Couldn't read file.
+       (setq gnus-score-alist nil)
+      ;; Read file.
+      (with-temp-buffer
+       (let ((coding-system-for-read score-mode-coding-system))
+         (insert-file-contents file))
+       (goto-char (point-min))
+       ;; Only do the loading if the score file isn't empty.
+       (when (save-excursion (re-search-forward "[()0-9a-zA-Z]" nil t))
+         (setq alist
+               (condition-case ()
+                   (read (current-buffer))
+                 (error
+                  (gnus-error 3.2 "Problem with score file %s" file))))))
+      (cond
+       ((and alist
+            (atom alist))
+       ;; Bogus score file.
+       (error "Invalid syntax with score file %s" file))
+       ((eq (car alist) 'setq)
+       ;; This is an old-style score file.
+       (setq gnus-score-alist (gnus-score-transform-old-to-new alist)))
+       (t
+       (setq gnus-score-alist alist)))
+      ;; Check the syntax of the score file.
+      (setq gnus-score-alist
+           (gnus-score-check-syntax gnus-score-alist file)))))
+
+(defun gnus-score-check-syntax (alist file)
+  "Check the syntax of the score ALIST."
+  (cond
+   ((null alist)
+    nil)
+   ((not (consp alist))
+    (gnus-message 1 "Score file is not a list: %s" file)
+    (ding)
+    nil)
+   (t
+    (let ((a alist)
+         sr err s type)
+      (while (and a (not err))
+       (setq
+        err
+        (cond
+         ((not (listp (car a)))
+          (format "Invalid score element %s in %s" (car a) file))
+         ((stringp (caar a))
+          (cond
+           ((not (listp (setq sr (cdar a))))
+            (format "Invalid header match %s in %s" (nth 1 (car a)) file))
+           (t
+            (setq type (caar a))
+            (while (and sr (not err))
+              (setq s (pop sr))
+              (setq
+               err
+               (cond
+                ((if (member (downcase type) '("lines" "chars"))
+                     (not (numberp (car s)))
+                   (not (stringp (car s))))
+                 (format "Invalid match %s in %s" (car s) file))
+                ((and (cadr s) (not (integerp (cadr s))))
+                 (format "Non-integer score %s in %s" (cadr s) file))
+                ((and (caddr s) (not (integerp (caddr s))))
+                 (format "Non-integer date %s in %s" (caddr s) file))
+                ((and (cadddr s) (not (symbolp (cadddr s))))
+                 (format "Non-symbol match type %s in %s" (cadddr s) file)))))
+            err)))))
+       (setq a (cdr a)))
+      (if err
+         (progn
+           (ding)
+           (gnus-message 3 "%s" err)
+           (sit-for 2)
+           nil)
+       alist)))))
+
+(defun gnus-score-transform-old-to-new (alist)
+  (let* ((alist (nth 2 alist))
+        out entry)
+    (when (eq (car alist) 'quote)
+      (setq alist (nth 1 alist)))
+    (while alist
+      (setq entry (car alist))
+      (if (stringp (car entry))
+         (let ((scor (cdr entry)))
+           (push entry out)
+           (while scor
+             (setcar scor
+                     (list (caar scor) (nth 2 (car scor))
+                           (and (nth 3 (car scor))
+                                (date-to-day (nth 3 (car scor))))
+                           (if (nth 1 (car scor)) 'r 's)))
+             (setq scor (cdr scor))))
+       (push (if (not (listp (cdr entry)))
+                 (list (car entry) (cdr entry))
+               entry)
+             out))
+      (setq alist (cdr alist)))
+    (cons (list 'touched t) (nreverse out))))
+
+(defun gnus-score-save ()
+  ;; Save all score information.
+  (let ((cache gnus-score-cache)
+       entry score file)
+    (save-excursion
+      (setq gnus-score-alist nil)
+      (nnheader-set-temp-buffer " *Gnus Scores*")
+      (while cache
+       (current-buffer)
+       (setq entry (pop cache)
+             file (nnheader-translate-file-chars (car entry) t)
+             score (cdr entry))
+       (if (or (not (equal (gnus-score-get 'touched score) '(t)))
+               (gnus-score-get 'read-only score)
+               (and (file-exists-p file)
+                    (not (file-writable-p file))))
+           ()
+         (setq score (setcdr entry (gnus-delete-alist 'touched score)))
+         (erase-buffer)
+         (let (emacs-lisp-mode-hook)
+           (if (and (not gnus-adaptive-pretty-print)
+                    (string-match
+                     (concat (regexp-quote gnus-adaptive-file-suffix) "$")
+                     file))
+               ;; This is an adaptive score file, so we do not run it through
+               ;; `pp' unless requested.  These files can get huge, and are
+               ;; not meant to be edited by human hands.
+               (gnus-prin1 score)
+             ;; This is a normal score file, so we print it very
+             ;; prettily.
+             (let ((lisp-mode-syntax-table score-mode-syntax-table))
+               (gnus-pp score))))
+         (gnus-make-directory (file-name-directory file))
+         ;; If the score file is empty, we delete it.
+         (if (zerop (buffer-size))
+             (delete-file file)
+           ;; There are scores, so we write the file.
+           (when (file-writable-p file)
+             (let ((coding-system-for-write score-mode-coding-system))
+               (gnus-write-buffer file))
+             (when gnus-score-after-write-file-function
+               (funcall gnus-score-after-write-file-function file)))))
+       (and gnus-score-uncacheable-files
+            (string-match gnus-score-uncacheable-files file)
+            (gnus-score-remove-from-cache file)))
+      (kill-buffer (current-buffer)))))
+
+(defun gnus-score-load-files (score-files)
+  "Load all score files in SCORE-FILES."
+  ;; Load the score files.
+  (let (scores)
+    (while score-files
+      (if (stringp (car score-files))
+         ;; It is a string, which means that it's a score file name,
+         ;; so we load the score file and add the score alist to
+         ;; the list of alists.
+         (setq scores (nconc (gnus-score-load-file (car score-files)) scores))
+       ;; It is an alist, so we just add it to the list directly.
+       (setq scores (nconc (car score-files) scores)))
+      (setq score-files (cdr score-files)))
+    ;; Prune the score files that are to be excluded, if any.
+    (when gnus-scores-exclude-files
+      (let ((s scores)
+           c)
+       (while s
+         (and (setq c (rassq (car s) gnus-score-cache))
+              (member (car c) gnus-scores-exclude-files)
+              (setq scores (delq (car s) scores)))
+         (setq s (cdr s)))))
+    scores))
+
+(defun gnus-score-headers (score-files &optional trace)
+  ;; Score `gnus-newsgroup-headers'.
+  (let (scores news)
+    ;; PLM: probably this is not the best place to clear orphan-score
+    (setq gnus-orphan-score nil
+         gnus-scores-articles nil
+         gnus-scores-exclude-files nil
+         scores (gnus-score-load-files score-files))
+    (setq news scores)
+    ;; Do the scoring.
+    (while news
+      (setq scores news
+           news nil)
+      (when (and gnus-summary-default-score
+                scores)
+       (let* ((entries gnus-header-index)
+              (now (date-to-day (current-time-string)))
+              (expire (and gnus-score-expiry-days
+                           (- now gnus-score-expiry-days)))
+              (headers gnus-newsgroup-headers)
+              (current-score-file gnus-current-score-file)
+              entry header new)
+         (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
+           ;; be written as O(N+S), where N is (length gnus-newsgroup-headers)
+           ;; and S is (length gnus-newsgroup-scored).
+           (unless (assq (mail-header-number header) gnus-newsgroup-scored)
+             (setq gnus-scores-articles ;Total of 2 * N cons-cells used.
+                   (cons (cons header (or gnus-summary-default-score 0))
+                         gnus-scores-articles))))
+
+         (with-current-buffer (gnus-get-buffer-create "*Headers*")
+           (buffer-disable-undo)
+           (when (gnus-buffer-live-p gnus-summary-buffer)
+             (message-clone-locals gnus-summary-buffer))
+
+           ;; Set the global variant of this variable.
+           (setq gnus-current-score-file current-score-file)
+           ;; score orphans
+           (when gnus-orphan-score
+             (setq gnus-score-index
+                   (nth 1 (assoc "references" gnus-header-index)))
+             (gnus-score-orphans gnus-orphan-score))
+           ;; Run each header through the score process.
+           (while entries
+             (setq entry (pop entries)
+                   header (nth 0 entry)
+                   gnus-score-index (nth 1 (assoc header gnus-header-index)))
+             (when (< 0 (apply 'max (mapcar
+                                     (lambda (score)
+                                       (length (gnus-score-get header score)))
+                                     scores)))
+               (when (if (and gnus-inhibit-slow-scoring
+                              (or (eq gnus-inhibit-slow-scoring t)
+                                  (and (stringp gnus-inhibit-slow-scoring)
+                                       ;; Always true here?
+                                       ;; (stringp gnus-newsgroup-name)
+                                       (string-match
+                                        gnus-inhibit-slow-scoring
+                                        gnus-newsgroup-name)))
+                              (> 0 (nth 1 (assoc header gnus-header-index))))
+                         (progn
+                           (gnus-message
+                            7 "Scoring on headers or body skipped.")
+                           nil)
+                       ;; Call the scoring function for this type of "header".
+                       (setq new (funcall (nth 2 entry) scores header
+                                          now expire trace)))
+                 (push new news))))
+           (when (gnus-buffer-live-p gnus-summary-buffer)
+             (let ((scored gnus-newsgroup-scored))
+               (with-current-buffer gnus-summary-buffer
+                 (setq gnus-newsgroup-scored scored))))
+           ;; Remove the buffer.
+           (gnus-kill-buffer (current-buffer)))
+
+         ;; Add articles to `gnus-newsgroup-scored'.
+         (while gnus-scores-articles
+           (when (or (/= gnus-summary-default-score
+                         (cdar gnus-scores-articles))
+                     gnus-save-score)
+             (push (cons (mail-header-number (caar gnus-scores-articles))
+                         (cdar gnus-scores-articles))
+                   gnus-newsgroup-scored))
+           (setq gnus-scores-articles (cdr gnus-scores-articles)))
+
+         (let (score)
+           (while (setq score (pop scores))
+             (while score
+               (when (consp (caar score))
+                 (gnus-score-advanced (car score) trace))
+               (pop score))))
+
+         (gnus-message 7 "Scoring...done"))))))
+
+(defun gnus-score-lower-thread (thread score-adjust)
+  "Lower the score on THREAD with SCORE-ADJUST.
+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."
+  (while thread
+    (let ((head (car thread)))
+      (if (listp head)
+         ;; handle a child and its descendants
+         (gnus-score-lower-thread head score-adjust)
+       ;; handle the parent
+       (let* ((article (mail-header-number head))
+              (score (assq article gnus-newsgroup-scored)))
+         (if score (setcdr score (+ (cdr score) score-adjust))
+           (push (cons article score-adjust) gnus-newsgroup-scored)))))
+    (setq thread (cdr thread))))
+
+(defun gnus-score-orphans (score)
+  "Score orphans.
+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."
+  ;; 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
+  ;; is threaded.  It would be nice to somehow save this info and use
+  ;; it later.
+  (dolist (thread (gnus-make-threads))
+    (let ((id (aref (car thread) gnus-score-index)))
+      ;; If the parent of the thread is not a root, lower the score of
+      ;; it and its descendants.  Note that some roots seem to satisfy
+      ;; (eq id nil) and some (eq id "");  not sure why.
+      (when (and id
+                (not (string= id "")))
+       (gnus-score-lower-thread thread score)))))
+
+(defun gnus-score-integer (scores header now expire &optional trace)
+  (let ((gnus-score-index (nth 1 (assoc header gnus-header-index)))
+       entries alist)
+    ;; Find matches.
+    (while scores
+      (setq alist (car scores)
+           scores (cdr scores)
+           entries (assoc header alist))
+      (while (cdr entries)             ;First entry is the header index.
+       (let* ((rest (cdr entries))
+              (kill (car rest))
+              (match (nth 0 kill))
+              (type (or (nth 3 kill) '>))
+              (score (or (nth 1 kill) gnus-score-interactive-default-score))
+              (date (nth 2 kill))
+              (found nil)
+              (match-func (if (or (eq type '>) (eq type '<) (eq type '<=)
+                                  (eq type '>=) (eq type '=))
+                              type
+                            (error "Invalid match type: %s" type)))
+              (articles gnus-scores-articles))
+         ;; Instead of doing all the clever stuff that
+         ;; `gnus-score-string' does to minimize searches and stuff,
+         ;; I will assume that people generally will put so few
+         ;; matches on numbers that any cleverness will take more
+         ;; time than one would gain.
+         (while articles
+           (when (funcall match-func
+                          (or (aref (caar articles) gnus-score-index) 0)
+                          match)
+             (when trace
+               (push (cons (car-safe (rassq alist gnus-score-cache)) kill)
+                     gnus-score-trace))
+             (setq found t)
+             (setcdr (car articles) (+ score (cdar articles))))
+           (setq articles (cdr articles)))
+         ;; Update expire date
+         (cond ((null date))           ;Permanent entry.
+               ((and found gnus-update-score-entry-dates) ;Match, update date.
+                (gnus-score-set 'touched '(t) alist)
+                (setcar (nthcdr 2 kill) now))
+               ((and expire (< date expire)) ;Old entry, remove.
+                (gnus-score-set 'touched '(t) alist)
+                (setcdr entries (cdr rest))
+                (setq rest entries)))
+         (setq entries rest)))))
+  nil)
+
+(defun gnus-score-date (scores header now expire &optional trace)
+  (let ((gnus-score-index (nth 1 (assoc header gnus-header-index)))
+       entries alist match match-func article)
+    ;; Find matches.
+    (while scores
+      (setq alist (car scores)
+           scores (cdr scores)
+           entries (assoc header alist))
+      (while (cdr entries)             ;First entry is the header index.
+       (let* ((rest (cdr entries))
+              (kill (car rest))
+              (type (or (nth 3 kill) 'before))
+              (score (or (nth 1 kill) gnus-score-interactive-default-score))
+              (date (nth 2 kill))
+              (found nil)
+              (articles gnus-scores-articles)
+              l)
+         (cond
+          ((eq type 'after)
+           (setq match-func 'string<
+                 match (gnus-date-iso8601 (nth 0 kill))))
+          ((eq type 'before)
+           (setq match-func 'gnus-string>
+                 match (gnus-date-iso8601 (nth 0 kill))))
+          ((eq type 'at)
+           (setq match-func 'string=
+                 match (gnus-date-iso8601 (nth 0 kill))))
+          ((eq type 'regexp)
+           (setq match-func 'string-match
+                 match (nth 0 kill)))
+          (t (error "Invalid match type: %s" type)))
+         ;; Instead of doing all the clever stuff that
+         ;; `gnus-score-string' does to minimize searches and stuff,
+         ;; I will assume that people generally will put so few
+         ;; matches on numbers that any cleverness will take more
+         ;; time than one would gain.
+         (while (setq article (pop articles))
+           (when (and
+                  (setq l (aref (car article) gnus-score-index))
+                  (funcall match-func match (gnus-date-iso8601 l)))
+             (when trace
+               (push (cons (car-safe (rassq alist gnus-score-cache)) kill)
+                     gnus-score-trace))
+             (setq found t)
+             (setcdr article (+ score (cdr article)))))
+         ;; Update expire date
+         (cond ((null date))           ;Permanent entry.
+               ((and found gnus-update-score-entry-dates) ;Match, update date.
+                (gnus-score-set 'touched '(t) alist)
+                (setcar (nthcdr 2 kill) now))
+               ((and expire (< date expire)) ;Old entry, remove.
+                (gnus-score-set 'touched '(t) alist)
+                (setcdr entries (cdr rest))
+                (setq rest entries)))
+         (setq entries rest)))))
+  nil)
+
+(defun gnus-score-decode-text-parts ()
+  (gmm-labels
+      ((mm-text-parts
+       (handle)
+       (cond ((stringp (car handle))
+              (let ((parts (apply #'append
+                                  (mapcar #'mm-text-parts (cdr handle)))))
+                (if (equal "multipart/alternative" (car handle))
+                    ;; pick the first supported alternative
+                    (list (car parts))
+                  parts)))
+
+             ((bufferp (car handle))
+              (when (string-match "^text/" (mm-handle-media-type handle))
+                (list handle)))
+
+             (t (apply #'append (mapcar #'mm-text-parts handle)))))
+       (my-mm-display-part
+       (handle)
+       (when handle
+         (save-restriction
+           (narrow-to-region (point) (point))
+           (mm-display-inline handle)
+           (goto-char (point-max))))))
+
+    (let (;(mm-text-html-renderer 'w3m-standalone)
+         (handles (mm-dissect-buffer t)))
+      (save-excursion
+       (article-goto-body)
+       (delete-region (point) (point-max))
+       (mapc #'my-mm-display-part (mm-text-parts handles))
+       handles))))
+
+(defun gnus-score-body (scores header now expire &optional trace)
+    (if gnus-agent-fetching
+       nil
+     (save-excursion
+       (setq gnus-scores-articles
+             (sort gnus-scores-articles
+                   (lambda (a1 a2)
+                     (< (mail-header-number (car a1))
+                        (mail-header-number (car a2))))))
+       (set-buffer nntp-server-buffer)
+       (save-restriction
+         (let* ((buffer-read-only nil)
+                (articles gnus-scores-articles)
+                (all-scores scores)
+                (request-func (cond ((string= "head" header)
+                                     'gnus-request-head)
+                                    ((string= "body" header)
+                                     'gnus-request-body)
+                                    (t 'gnus-request-article)))
+                entries alist ofunc article last)
+           (when articles
+             (setq last (mail-header-number (caar (last articles))))
+             ;; Not all backends support partial fetching.  In that case,
+             ;; we just fetch the entire article.
+             ;; When scoring by body, we need to peek at the headers to detect
+             ;; the content encoding
+             (unless (or (gnus-check-backend-function
+                          (and (string-match "^gnus-" (symbol-name request-func))
+                               (intern (substring (symbol-name request-func)
+                                                  (match-end 0))))
+                          gnus-newsgroup-name)
+                         (string= "body" header))
+               (setq ofunc request-func)
+               (setq request-func 'gnus-request-article))
+             (while articles
+               (setq article (mail-header-number (caar articles)))
+               (gnus-message 7 "Scoring article %s of %s..." article last)
+               (widen)
+               (let (handles)
+                 (when (funcall request-func article gnus-newsgroup-name)
+                  (when (string= "body" header)
+                    (setq handles (gnus-score-decode-text-parts)))
+                  (goto-char (point-min))
+                  ;; If just parts of the article is to be searched, but the
+                  ;; backend didn't support partial fetching, we just narrow
+                  ;; to the relevant parts.
+                  (when ofunc
+                    (if (eq ofunc 'gnus-request-head)
+                        (narrow-to-region
+                         (point)
+                         (or (search-forward "\n\n" nil t) (point-max)))
+                      (narrow-to-region
+                       (or (search-forward "\n\n" nil t) (point))
+                       (point-max))))
+                  (setq scores all-scores)
+                  ;; Find matches.
+                  (while scores
+                    (setq alist (pop scores)
+                          entries (assoc header alist))
+                    (while (cdr entries) ;First entry is the header index.
+                      (let* ((rest (cdr entries))
+                             (kill (car rest))
+                             (match (nth 0 kill))
+                             (type (or (nth 3 kill) 's))
+                             (score (or (nth 1 kill)
+                                        gnus-score-interactive-default-score))
+                             (date (nth 2 kill))
+                             (found nil)
+                             (case-fold-search
+                              (not (or (eq type 'R) (eq type 'S)
+                                       (eq type 'Regexp) (eq type 'String))))
+                             (search-func
+                              (cond ((or (eq type 'r) (eq type 'R)
+                                         (eq type 'regexp) (eq type 'Regexp))
+                                     're-search-forward)
+                                    ((or (eq type 's) (eq type 'S)
+                                         (eq type 'string) (eq type 'String))
+                                     'search-forward)
+                                    (t
+                                     (error "Invalid match type: %s" type)))))
+                        (goto-char (point-min))
+                        (when (funcall search-func match nil t)
+                          ;; Found a match, update scores.
+                          (setcdr (car articles) (+ score (cdar articles)))
+                          (setq found t)
+                          (when trace
+                            (push
+                             (cons (car-safe (rassq alist gnus-score-cache))
+                                   kill)
+                             gnus-score-trace)))
+                        ;; Update expire date
+                        (unless trace
+                          (cond
+                           ((null date)) ;Permanent entry.
+                           ((and found gnus-update-score-entry-dates)
+                            ;; Match, update date.
+                            (gnus-score-set 'touched '(t) alist)
+                            (setcar (nthcdr 2 kill) now))
+                           ((and expire (< date expire)) ;Old entry, remove.
+                            (gnus-score-set 'touched '(t) alist)
+                            (setcdr entries (cdr rest))
+                            (setq rest entries))))
+                        (setq entries rest))))
+                  (when handles (mm-destroy-parts handles))))
+               (setq articles (cdr articles)))))))
+     nil))
+
+(defun gnus-score-thread (scores header now expire &optional trace)
+  (gnus-score-followup scores header now expire trace t))
+
+(defun gnus-score-followup (scores header now expire &optional trace thread)
+  (if gnus-agent-fetching
+      ;; FIXME: It seems doable in fetching mode.
+      nil
+    ;; Insert the unique article headers in the buffer.
+    (let ((gnus-score-index (nth 1 (assoc header gnus-header-index)))
+         (current-score-file gnus-current-score-file)
+         (all-scores scores)
+         ;; gnus-score-index is used as a free variable.
+         alike last this art entries alist articles
+         new news)
+
+      ;; Change score file to the adaptive score file.  All entries that
+      ;; this function makes will be put into this file.
+      (with-current-buffer gnus-summary-buffer
+       (gnus-score-load-file
+        (or gnus-newsgroup-adaptive-score-file
+            (gnus-score-file-name
+             gnus-newsgroup-name gnus-adaptive-file-suffix))))
+
+      (setq gnus-scores-articles (sort gnus-scores-articles
+                                      'gnus-score-string<)
+           articles gnus-scores-articles)
+
+      (erase-buffer)
+      (while articles
+       (setq art (car articles)
+             this (aref (car art) gnus-score-index)
+             articles (cdr articles))
+       (if (equal last this)
+           (push art alike)
+         (when last
+           (insert last ?\n)
+           (put-text-property (1- (point)) (point) 'articles alike))
+         (setq alike (list art)
+               last this)))
+      (when last                       ; Bwadr, duplicate code.
+       (insert last ?\n)
+       (put-text-property (1- (point)) (point) 'articles alike))
+
+      ;; Find matches.
+      (while scores
+       (setq alist (car scores)
+             scores (cdr scores)
+             entries (assoc header alist))
+       (while (cdr entries)            ;First entry is the header index.
+         (let* ((rest (cdr entries))
+                (kill (car rest))
+                (match (nth 0 kill))
+                (type (or (nth 3 kill) 's))
+                (score (or (nth 1 kill) gnus-score-interactive-default-score))
+                (date (nth 2 kill))
+                (found nil)
+                (mt (aref (symbol-name type) 0))
+                (case-fold-search
+                 (not (or (= mt ?R) (= mt ?S) (= mt ?E) (= mt ?F))))
+                (dmt (downcase mt))
+                (search-func
+                 (cond ((= dmt ?r) 're-search-forward)
+                       ((or (= dmt ?e) (= dmt ?s) (= dmt ?f)) 'search-forward)
+                       (t (error "Invalid match type: %s" type))))
+                arts art)
+           (goto-char (point-min))
+           (if (= dmt ?e)
+               (while (funcall search-func match nil t)
+                 (and (= (point-at-bol)
+                         (match-beginning 0))
+                      (= (progn (end-of-line) (point))
+                         (match-end 0))
+                      (progn
+                        (setq found (setq arts (get-text-property
+                                                (point) 'articles)))
+                        ;; Found a match, update scores.
+                        (while arts
+                          (setq art (car arts)
+                                arts (cdr arts))
+                          (gnus-score-add-followups
+                           (car art) score all-scores thread))))
+                 (end-of-line))
+             (while (funcall search-func match nil t)
+               (end-of-line)
+               (setq found (setq arts (get-text-property (point) 'articles)))
+               ;; Found a match, update scores.
+               (while (setq art (pop arts))
+                 (setcdr art (+ score (cdr art)))
+                 (when trace
+                   (push (cons
+                          (car-safe (rassq alist gnus-score-cache))
+                          kill)
+                         gnus-score-trace))
+                 (when (setq new (gnus-score-add-followups
+                                  (car art) score all-scores thread))
+                   (push new news)))))
+           ;; Update expire date
+           (cond ((null date))         ;Permanent entry.
+                 ((and found gnus-update-score-entry-dates)
+                                       ;Match, update date.
+                  (gnus-score-set 'touched '(t) alist)
+                  (setcar (nthcdr 2 kill) now))
+                 ((and expire (< date expire)) ;Old entry, remove.
+                  (gnus-score-set 'touched '(t) alist)
+                  (setcdr entries (cdr rest))
+                  (setq rest entries)))
+           (setq entries rest))))
+      ;; We change the score file back to the previous one.
+      (with-current-buffer gnus-summary-buffer
+       (gnus-score-load-file current-score-file))
+      (list (cons "references" news)))))
+
+(defun gnus-score-add-followups (header score scores &optional thread)
+  "Add a score entry to the adapt file."
+  (with-current-buffer gnus-summary-buffer
+    (let* ((id (mail-header-id header))
+          (scores (car scores))
+          entry dont)
+      ;; Don't enter a score if there already is one.
+      (while (setq entry (pop scores))
+       (and (equal "references" (car entry))
+            (or (null (nth 3 (cadr entry)))
+                (eq 's (nth 3 (cadr entry))))
+            (assoc id entry)
+            (setq dont t)))
+      (unless dont
+       (gnus-summary-score-entry
+        (if thread "thread" "references")
+        id 's score (current-time-string) nil t)))))
+
+(defun gnus-score-string (score-list header now expire &optional trace)
+  ;; Score ARTICLES according to HEADER in SCORE-LIST.
+  ;; Update matching entries to NOW and remove unmatched entries older
+  ;; than EXPIRE.
+
+  ;; 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)))
+       alike last this art entries alist articles
+       fuzzies arts words kill)
+
+    ;; Sorting the articles costs os O(N*log N) but will allow us to
+    ;; only match with each unique header.  Thus the actual matching
+    ;; will be O(M*U) where M is the number of strings to match with,
+    ;; and U is the number of unique headers.  It is assumed (but
+    ;; untested) this will be a net win because of the large constant
+    ;; factor involved with string matching.
+    (setq gnus-scores-articles
+         ;; We cannot string-sort the extra headers list.  *sigh*
+         (if (= gnus-score-index 9)
+             gnus-scores-articles
+           (sort gnus-scores-articles 'gnus-score-string<))
+         articles gnus-scores-articles)
+
+    (erase-buffer)
+    (while (setq art (pop articles))
+      (setq this (aref (car art) gnus-score-index))
+
+      ;; If we're working with non-standard headers, we are stuck
+      ;; with working on them as a group.  What a hassle.
+      ;; Just wait 'til you see what horrors we commit against `match'...
+      (if (= gnus-score-index 9)
+         (setq this (gnus-prin1-to-string this))) ; ick.
+
+      (if simplify
+         (setq this (gnus-map-function gnus-simplify-subject-functions this)))
+      (if (equal last this)
+         ;; O(N*H) cons-cells used here, where H is the number of
+         ;; headers.
+         (push art alike)
+       (when last
+         ;; Insert the line, with a text property on the
+         ;; terminating newline referring to the articles with
+         ;; this line.
+         (insert last ?\n)
+         (put-text-property (1- (point)) (point) 'articles alike))
+       (setq alike (list art)
+             last this)))
+    (when last                         ; Bwadr, duplicate code.
+      (insert last ?\n)
+      (put-text-property (1- (point)) (point) 'articles alike))
+
+    ;; Go through all the score alists and pick out the entries
+    ;; for this header.
+    (while score-list
+      (setq alist (pop score-list)
+           ;; There's only one instance of this header for
+           ;; each score alist.
+           entries (assoc header alist))
+      (while (cdr entries)             ;First entry is the header index.
+       (let* ((kill (cadr entries))
+              (type (or (nth 3 kill) 's))
+              (score (or (nth 1 kill) gnus-score-interactive-default-score))
+              (date (nth 2 kill))
+              (extra (nth 4 kill))     ; non-standard header; string.
+              (found nil)
+              (mt (aref (symbol-name type) 0))
+              (case-fold-search (not (memq mt '(?R ?S ?E ?F))))
+              (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)))
+              (search-func
+               (cond ((= dmt ?r) 're-search-forward)
+                     ((or (= dmt ?e) (= dmt ?s) (= dmt ?f)) 'search-forward)
+                     ((= dmt ?w) nil)
+                     (t (error "Invalid match type: %s" type)))))
+
+         ;; Evil hackery to make match usable in non-standard headers.
+         (when extra
+           (setq match (concat "[ (](" extra " \\. \"\\([^\"]*\\\\\"\\)*[^\"]*"
+                               (if (eq search-func 're-search-forward)
+                                   match
+                                 (regexp-quote match))
+                               "\\([^\"]*\\\\\"\\)*[^\"]*\")[ )]")
+                 search-func 're-search-forward)) ; XXX danger?!?
+
+         (cond
+          ;; Fuzzy matches.  We save these for later.
+          ((= dmt ?f)
+           (push (cons entries alist) fuzzies)
+           (setq entries (cdr entries)))
+          ;; Word matches.  Save these for even later.
+          ((= dmt ?w)
+           (push (cons entries alist) words)
+           (setq entries (cdr entries)))
+          ;; Exact matches.
+          ((= dmt ?e)
+           ;; Do exact matching.
+           (goto-char (point-min))
+           (while (and (not (eobp))
+                       (funcall search-func match nil t))
+             ;; Is it really exact?
+             (and (eolp)
+                  (= (point-at-bol) (match-beginning 0))
+                  ;; Yup.
+                  (progn
+                    (setq found (setq arts (get-text-property
+                                            (point) 'articles)))
+                    ;; Found a match, update scores.
+                    (if trace
+                        (while (setq art (pop arts))
+                          (setcdr art (+ score (cdr art)))
+                          (push
+                           (cons
+                            (car-safe (rassq alist gnus-score-cache))
+                            kill)
+                           gnus-score-trace))
+                      (while (setq art (pop arts))
+                        (setcdr art (+ score (cdr art)))))))
+             (forward-line 1))
+           ;; Update expiry date
+           (if trace
+               (setq entries (cdr entries))
+             (cond
+              ;; Permanent entry.
+              ((null date)
+               (setq entries (cdr entries)))
+              ;; We have a match, so we update the date.
+              ((and found gnus-update-score-entry-dates)
+               (gnus-score-set 'touched '(t) alist)
+               (setcar (nthcdr 2 kill) now)
+               (setq entries (cdr entries)))
+              ;; This entry has expired, so we remove it.
+              ((and expire (< date expire))
+               (gnus-score-set 'touched '(t) alist)
+               (setcdr entries (cddr entries)))
+              ;; No match; go to next entry.
+              (t
+               (setq entries (cdr entries))))))
+          ;; Regexp and substring matching.
+          (t
+           (goto-char (point-min))
+           (when (string= match "")
+             (setq match "\n"))
+           (while (and (not (eobp))
+                       (funcall search-func match nil t))
+             (goto-char (match-beginning 0))
+             (end-of-line)
+             (setq found (setq arts (get-text-property (point) 'articles)))
+             ;; Found a match, update scores.
+             (if trace
+                 (while (setq art (pop arts))
+                   (setcdr art (+ score (cdr art)))
+                   (push (cons (car-safe (rassq alist gnus-score-cache)) kill)
+                         gnus-score-trace))
+               (while (setq art (pop arts))
+                 (setcdr art (+ score (cdr art)))))
+             (forward-line 1))
+           ;; Update expiry date
+           (if trace
+               (setq entries (cdr entries))
+             (cond
+              ;; Permanent entry.
+              ((null date)
+               (setq entries (cdr entries)))
+              ;; We have a match, so we update the date.
+              ((and found gnus-update-score-entry-dates)
+               (gnus-score-set 'touched '(t) alist)
+               (setcar (nthcdr 2 kill) now)
+               (setq entries (cdr entries)))
+              ;; This entry has expired, so we remove it.
+              ((and expire (< date expire))
+               (gnus-score-set 'touched '(t) alist)
+               (setcdr entries (cddr entries)))
+              ;; No match; go to next entry.
+              (t
+               (setq entries (cdr entries))))))))))
+
+    ;; Find fuzzy matches.
+    (when fuzzies
+      ;; Simplify the entire buffer for easy matching.
+      (gnus-simplify-buffer-fuzzy gnus-simplify-subject-fuzzy-regexp)
+      (while (setq kill (cadaar fuzzies))
+       (let* ((match (nth 0 kill))
+              (type (nth 3 kill))
+              (score (or (nth 1 kill) gnus-score-interactive-default-score))
+              (date (nth 2 kill))
+              (mt (aref (symbol-name type) 0))
+              (case-fold-search (not (= mt ?F)))
+              found)
+         (goto-char (point-min))
+         (while (and (not (eobp))
+                     (search-forward match nil t))
+           (when (and (= (point-at-bol) (match-beginning 0))
+                      (eolp))
+             (setq found (setq arts (get-text-property (point) 'articles)))
+             (if trace
+                 (while (setq art (pop arts))
+                   (setcdr art (+ score (cdr art)))
+                   (push (cons
+                          (car-safe (rassq (cdar fuzzies) gnus-score-cache))
+                          kill)
+                         gnus-score-trace))
+               ;; Found a match, update scores.
+               (while (setq art (pop arts))
+                 (setcdr art (+ score (cdr art))))))
+           (forward-line 1))
+         ;; Update expiry date
+         (if (not trace)
+             (cond
+              ;; Permanent.
+              ((null date)
+               ;; Do nothing.
+               )
+              ;; Match, update date.
+              ((and found gnus-update-score-entry-dates)
+               (gnus-score-set 'touched '(t) (cdar fuzzies))
+               (setcar (nthcdr 2 kill) now))
+              ;; Old entry, remove.
+              ((and expire (< date expire))
+               (gnus-score-set 'touched '(t) (cdar fuzzies))
+               (setcdr (caar fuzzies) (cddaar fuzzies)))))
+         (setq fuzzies (cdr fuzzies)))))
+
+    (when words
+      ;; Enter all words into the hashtb.
+      (let ((hashtb (gnus-make-hashtable
+                    (* 10 (count-lines (point-min) (point-max))))))
+       (gnus-enter-score-words-into-hashtb hashtb)
+       (while (setq kill (cadaar words))
+         (let* ((score (or (nth 1 kill) gnus-score-interactive-default-score))
+                (date (nth 2 kill))
+                found)
+           (when (setq arts (intern-soft (nth 0 kill) hashtb))
+             (setq arts (symbol-value arts))
+             (setq found t)
+             (if trace
+                 (while (setq art (pop arts))
+                   (setcdr art (+ score (cdr art)))
+                   (push (cons
+                          (car-safe (rassq (cdar words) gnus-score-cache))
+                          kill)
+                         gnus-score-trace))
+               ;; Found a match, update scores.
+               (while (setq art (pop arts))
+                 (setcdr art (+ score (cdr art))))))
+           ;; Update expiry date
+           (if (not trace)
+               (cond
+                ;; Permanent.
+                ((null date)
+                 ;; Do nothing.
+                 )
+                ;; Match, update date.
+                ((and found gnus-update-score-entry-dates)
+                 (gnus-score-set 'touched '(t) (cdar words))
+                 (setcar (nthcdr 2 kill) now))
+                ;; Old entry, remove.
+                ((and expire (< date expire))
+                 (gnus-score-set 'touched '(t) (cdar words))
+                 (setcdr (caar words) (cddaar words)))))
+           (setq words (cdr words))))))
+    nil))
+
+(defun gnus-enter-score-words-into-hashtb (hashtb)
+  ;; Find all the words in the buffer and enter them into
+  ;; the hashtable.
+  (let (word val)
+    (goto-char (point-min))
+    (with-syntax-table gnus-adaptive-word-syntax-table
+      (while (re-search-forward "\\b\\w+\\b" nil t)
+       (setq val
+             (gnus-gethash
+              (setq word (downcase (buffer-substring
+                                    (match-beginning 0) (match-end 0))))
+              hashtb))
+       (gnus-sethash
+        word
+        (append (get-text-property (point-at-eol) 'articles) val)
+        hashtb)))
+    ;; Make all the ignorable words ignored.
+    (let ((ignored (append gnus-ignored-adaptive-words
+                          (if gnus-adaptive-word-no-group-words
+                              (message-tokenize-header
+                               (gnus-group-real-name gnus-newsgroup-name)
+                               "."))
+                          gnus-default-ignored-adaptive-words)))
+      (while ignored
+       (gnus-sethash (pop ignored) nil hashtb)))))
+
+(defun gnus-score-string< (a1 a2)
+  ;; Compare headers in articles A2 and A2.
+  ;; The header index used is the free variable `gnus-score-index'.
+  (string-lessp (aref (car a1) gnus-score-index)
+               (aref (car a2) gnus-score-index)))
+
+(defun gnus-current-score-file-nondirectory (&optional score-file)
+  (let ((score-file (or score-file gnus-current-score-file)))
+    (if score-file
+       (gnus-short-group-name (file-name-nondirectory score-file))
+      "none")))
+
+(defun gnus-score-adaptive ()
+  "Create adaptive score rules for this newsgroup."
+  (when gnus-newsgroup-adaptive
+    ;; We change the score file to the adaptive score file.
+    (with-current-buffer gnus-summary-buffer
+      (gnus-score-load-file
+       (or gnus-newsgroup-adaptive-score-file
+          (gnus-home-score-file gnus-newsgroup-name t)
+          (gnus-score-file-name
+           gnus-newsgroup-name gnus-adaptive-file-suffix))))
+    ;; Perform ordinary line scoring.
+    (when (or (not (listp gnus-newsgroup-adaptive))
+             (memq 'line gnus-newsgroup-adaptive))
+      (save-excursion
+       (let* ((malist (gnus-copy-sequence gnus-adaptive-score-alist))
+              (alist malist)
+              (date (current-time-string))
+              (data gnus-newsgroup-data)
+              elem headers match func)
+         ;; First we transform the adaptive rule alist into something
+         ;; that's faster to process.
+         (while malist
+           (setq elem (car malist))
+           (when (symbolp (car elem))
+             (setcar elem (symbol-value (car elem))))
+           (setq elem (cdr elem))
+           (while elem
+             (when (fboundp
+                    (setq func
+                          (intern
+                           (concat "mail-header-"
+                                   (if (eq (caar elem) 'followup)
+                                       "message-id"
+                                     (downcase (symbol-name (caar elem))))))))
+               (setcdr (car elem)
+                       (cons (if (eq (caar elem) 'followup)
+                                 "references"
+                               (symbol-name (caar elem)))
+                             (cdar elem)))
+               (setcar (car elem)
+                       `(lambda (h)
+                          (,func h))))
+             (setq elem (cdr elem)))
+           (setq malist (cdr malist)))
+         ;; Then we score away.
+         (while data
+           (setq elem (cdr (assq (gnus-data-mark (car data)) alist)))
+           (if (or (not elem)
+                   (gnus-data-pseudo-p (car data)))
+               ()
+             (when (setq headers (gnus-data-header (car data)))
+               (while elem
+                 (setq match (funcall (caar elem) headers))
+                 (gnus-summary-score-entry
+                  (nth 1 (car elem)) match
+                  (cond
+                   ((numberp match)
+                    '=)
+                   ((equal (nth 1 (car elem)) "date")
+                    'a)
+                   (t
+                    ;; Whether we use substring or exact matches is
+                    ;; controlled here.
+                    (if (or (not gnus-score-exact-adapt-limit)
+                            (< (length match) gnus-score-exact-adapt-limit))
+                        'e
+                      (if (equal (nth 1 (car elem)) "subject")
+                          'f 's))))
+                  (nth 2 (car elem)) date nil t)
+                 (setq elem (cdr elem)))))
+           (setq data (cdr data))))))
+
+    ;; Perform adaptive word scoring.
+    (when (and (listp gnus-newsgroup-adaptive)
+              (memq 'word gnus-newsgroup-adaptive))
+      (with-temp-buffer
+       (let* ((hashtb (gnus-make-hashtable 1000))
+              (date (date-to-day (current-time-string)))
+              (data gnus-newsgroup-data)
+              word d score val)
+         (with-syntax-table gnus-adaptive-word-syntax-table
+           ;; Go through all articles.
+           (while (setq d (pop data))
+             (when (and
+                    (not (gnus-data-pseudo-p d))
+                    (setq score
+                          (cdr (assq
+                                (gnus-data-mark d)
+                                gnus-adaptive-word-score-alist))))
+               ;; This article has a mark that should lead to
+               ;; adaptive word rules, so we insert the subject
+               ;; and find all words in that string.
+               (insert (mail-header-subject (gnus-data-header d)))
+               (downcase-region (point-min) (point-max))
+               (goto-char (point-min))
+               (while (re-search-forward "\\b\\w+\\b" nil t)
+                 ;; Put the word and score into the hashtb.
+                 (setq val (gnus-gethash (setq word (match-string 0))
+                                         hashtb))
+                 (when (or (not gnus-adaptive-word-length-limit)
+                           (> (length word)
+                              gnus-adaptive-word-length-limit))
+                   (setq val (+ score (or val 0)))
+                   (if (and gnus-adaptive-word-minimum
+                            (< val gnus-adaptive-word-minimum))
+                       (setq val gnus-adaptive-word-minimum))
+                   (gnus-sethash word val hashtb)))
+               (erase-buffer))))
+         ;; Make all the ignorable words ignored.
+         (let ((ignored (append gnus-ignored-adaptive-words
+                                (if gnus-adaptive-word-no-group-words
+                                    (message-tokenize-header
+                                     (gnus-group-real-name
+                                      gnus-newsgroup-name)
+                                     "."))
+                                gnus-default-ignored-adaptive-words)))
+           (while ignored
+             (gnus-sethash (pop ignored) nil hashtb)))
+         ;; Now we have all the words and scores, so we
+         ;; add these rules to the ADAPT file.
+         (set-buffer gnus-summary-buffer)
+         (mapatoms
+          (lambda (word)
+            (when (symbol-value word)
+              (gnus-summary-score-entry
+               "subject" (symbol-name word) 'w (symbol-value word)
+               date nil t)))
+          hashtb))))))
+
+(defun gnus-score-edit-done ()
+  (let ((bufnam (buffer-file-name (current-buffer)))
+       (winconf gnus-prev-winconf))
+    (when winconf
+      (set-window-configuration winconf))
+    (gnus-score-remove-from-cache bufnam)
+    (gnus-score-load-file bufnam)
+    (run-hooks 'gnus-score-edit-done-hook)))
+
+(defun gnus-score-find-trace ()
+  "Find all score rules that applies to the current article."
+  (interactive)
+  (let ((old-scored gnus-newsgroup-scored))
+    (let ((gnus-newsgroup-headers
+          (list (gnus-summary-article-header)))
+         (gnus-newsgroup-scored nil)
+         ;; Must be synced with `gnus-score-edit-file-at-point':
+         (frmt "%S [%s] -> %s\n")
+         trace
+         file)
+      (save-excursion
+       (nnheader-set-temp-buffer "*Score Trace*"))
+      (setq gnus-score-trace nil)
+      (gnus-possibly-score-headers 'trace)
+      (if (not (setq trace gnus-score-trace))
+         (gnus-error
+          1 "No score rules apply to the current article (default score %d)."
+          gnus-summary-default-score)
+       (set-buffer "*Score Trace*")
+       ;; Use a keymap instead?
+       (local-set-key "q"
+                      (lambda ()
+                        (interactive)
+                        (bury-buffer nil)
+                        (gnus-summary-expand-window)))
+       (local-set-key "k"
+                      (lambda ()
+                        (interactive)
+                        (kill-buffer (current-buffer))
+                        (gnus-summary-expand-window)))
+       (local-set-key "e" (lambda ()
+                            "Run `gnus-score-edit-file-at-point'."
+                            (interactive)
+                            (gnus-score-edit-file-at-point)))
+       (local-set-key "f" (lambda ()
+                            "Run `gnus-score-edit-file-at-point'."
+                            (interactive)
+                            (gnus-score-edit-file-at-point 'format)))
+       (local-set-key "t" 'toggle-truncate-lines)
+       (setq truncate-lines t)
+       (dolist (entry trace)
+         (setq file (or (car entry)
+                        ;; Must be synced with
+                        ;; `gnus-score-edit-file-at-point':
+                        "(non-file rule)"))
+         (insert
+          (format frmt
+                  (cdr entry)
+                  ;; Don't use `file-name-sans-extension' to see .SCORE and
+                  ;; .ADAPT directly:
+                  (file-name-nondirectory file)
+                  (abbreviate-file-name file))))
+       (insert
+        (format "\nTotal score: %d"
+                (apply '+ (mapcar
+                           (lambda (s)
+                             (or (caddr s)
+                                 gnus-score-interactive-default-score))
+                           trace))))
+       (insert
+        "\n\nQuick help:
+
+Type `e' to edit score file corresponding to the score rule on current line,
+`f' to format (pretty print) the score file and edit it,
+`t' toggle to truncate long lines in this buffer,
+`q' to quit, `k' to kill score trace buffer.
+
+The first sexp on each line is the score rule, followed by the file name of
+the score file and its full name, including the directory.")
+       (goto-char (point-min))
+       (gnus-configure-windows 'score-trace)))
+    (set-buffer gnus-summary-buffer)
+    (setq gnus-newsgroup-scored old-scored)))
+
+(defun gnus-score-find-favourite-words ()
+  "List words used in scoring."
+  (interactive)
+  (let ((alists (gnus-score-load-files (gnus-all-score-files)))
+       alist rule rules kill)
+    ;; Go through all the score alists for this group
+    ;; and find all `w' rules.
+    (while (setq alist (pop alists))
+      (while (setq rule (pop alist))
+       (when (and (stringp (car rule))
+                  (equal "subject" (downcase (pop rule))))
+         (while (setq kill (pop rule))
+           (when (memq (nth 3 kill) '(w W word Word))
+             (push (cons (or (nth 1 kill)
+                             gnus-score-interactive-default-score)
+                         (car kill))
+                   rules))))))
+    (setq rules (sort rules (lambda (r1 r2)
+                             (string-lessp (cdr r1) (cdr r2)))))
+    ;; Add up words that have appeared several times.
+    (let ((r rules))
+      (while (cdr r)
+       (if (equal (cdar r) (cdadr r))
+           (progn
+             (setcar (car r) (+ (caar r) (caadr r)))
+             (setcdr r (cddr r)))
+         (pop r))))
+    ;; Insert the words.
+    (nnheader-set-temp-buffer "*Score Words*")
+    (if (not (setq rules (sort rules (lambda (r1 r2) (> (car r1) (car r2))))))
+       (gnus-error 3 "No word score rules")
+      (while rules
+       (insert (format "%-5d: %s\n" (caar rules) (cdar rules)))
+       (pop rules))
+      (goto-char (point-min))
+      (gnus-configure-windows 'score-words))))
+
+(defun gnus-summary-rescore ()
+  "Redo the entire scoring process in the current summary."
+  (interactive)
+  (gnus-score-save)
+  (setq gnus-score-cache nil)
+  (setq gnus-newsgroup-scored nil)
+  (gnus-possibly-score-headers)
+  (gnus-score-update-all-lines))
+
+(defun gnus-score-flush-cache ()
+  "Flush the cache of score files."
+  (interactive)
+  (gnus-score-save)
+  (setq gnus-score-cache nil
+       gnus-score-alist nil
+       gnus-short-name-score-file-cache nil)
+  (gnus-message 6 "The score cache is now flushed"))
+
+(gnus-add-shutdown 'gnus-score-close 'gnus)
+
+(defvar gnus-score-file-alist-cache nil)
+
+(defun gnus-score-close ()
+  "Clear all internal score variables."
+  (setq gnus-score-cache nil
+       gnus-internal-global-score-files nil
+       gnus-score-file-list nil
+       gnus-score-file-alist-cache nil))
+
+;; Summary score marking commands.
+
+(defun gnus-summary-raise-same-subject-and-select (score)
+  "Raise articles which has the same subject with SCORE and select the next."
+  (interactive "p")
+  (let ((subject (gnus-summary-article-subject)))
+    (gnus-summary-raise-score score)
+    (while (gnus-summary-find-subject subject)
+      (gnus-summary-raise-score score))
+    (gnus-summary-next-article t)))
+
+(defun gnus-summary-raise-same-subject (score)
+  "Raise articles which has the same subject with SCORE."
+  (interactive "p")
+  (let ((subject (gnus-summary-article-subject)))
+    (gnus-summary-raise-score score)
+    (while (gnus-summary-find-subject subject)
+      (gnus-summary-raise-score score))
+    (gnus-summary-next-subject 1 t)))
+
+(defun gnus-score-delta-default (level)
+  (if level (prefix-numeric-value level)
+    gnus-score-interactive-default-score))
+
+(defun gnus-summary-raise-thread (&optional score)
+  "Raise the score of the articles in the current thread with SCORE."
+  (interactive "P")
+  (setq score (gnus-score-delta-default score))
+  (let (e)
+    (save-excursion
+      (let ((articles (gnus-summary-articles-in-thread)))
+       (while articles
+         (gnus-summary-goto-subject (car articles))
+         (gnus-summary-raise-score score)
+         (setq articles (cdr articles))))
+      (setq e (point)))
+    (let ((gnus-summary-check-current t))
+      (unless (zerop (gnus-summary-next-subject 1 t))
+       (goto-char e))))
+  (gnus-summary-recenter)
+  (gnus-summary-position-point)
+  (gnus-set-mode-line 'summary))
+
+(defun gnus-summary-lower-same-subject-and-select (score)
+  "Raise articles which has the same subject with SCORE and select the next."
+  (interactive "p")
+  (gnus-summary-raise-same-subject-and-select (- score)))
+
+(defun gnus-summary-lower-same-subject (score)
+  "Raise articles which has the same subject with SCORE."
+  (interactive "p")
+  (gnus-summary-raise-same-subject (- score)))
+
+(defun gnus-summary-lower-thread (&optional score)
+  "Lower score of articles in the current thread with SCORE."
+  (interactive "P")
+  (gnus-summary-raise-thread (- (gnus-score-delta-default score))))
+
+;;; Finding score files.
+
+(defun gnus-score-score-files (group)
+  "Return a list of all possible score files."
+  ;; Search and set any global score files.
+  (when gnus-global-score-files
+    (unless gnus-internal-global-score-files
+      (gnus-score-search-global-directories gnus-global-score-files)))
+  ;; Fix the kill-file dir variable.
+  (setq gnus-kill-files-directory
+       (file-name-as-directory gnus-kill-files-directory))
+  ;; If we can't read it, there are no score files.
+  (if (not (file-exists-p (expand-file-name gnus-kill-files-directory)))
+      (setq gnus-score-file-list nil)
+    (if (not (gnus-use-long-file-name 'not-score))
+       ;; We do not use long file names, so we have to do some
+       ;; directory traversing.
+       (setq gnus-score-file-list
+             (cons nil
+                   (or gnus-short-name-score-file-cache
+                       (prog2
+                           (gnus-message 6 "Finding all score files...")
+                           (setq gnus-short-name-score-file-cache
+                                 (gnus-score-score-files-1
+                                  gnus-kill-files-directory))
+                         (gnus-message 6 "Finding all score files...done")))))
+      ;; We want long file names.
+      (when (or (not gnus-score-file-list)
+               (not (car gnus-score-file-list))
+               (gnus-file-newer-than gnus-kill-files-directory
+                                     (car gnus-score-file-list)))
+       (setq gnus-score-file-list
+             (cons (nth 5 (file-attributes gnus-kill-files-directory))
+                   (nreverse
+                    (directory-files
+                     gnus-kill-files-directory t
+                     (gnus-score-file-regexp)))))))
+    (cdr gnus-score-file-list)))
+
+(defun gnus-score-score-files-1 (dir)
+  "Return all possible score files under DIR."
+  (let ((files (list (expand-file-name dir)))
+       (regexp (gnus-score-file-regexp))
+       (case-fold-search nil)
+       seen out file)
+    (while (setq file (pop files))
+      (cond
+       ;; Ignore files that start with a dot.
+       ((string-match "^\\." (file-name-nondirectory file))
+       nil)
+       ;; Add subtrees of directory to also be searched.
+       ((and (file-directory-p file)
+            (not (member (file-truename file) seen)))
+       (push (file-truename file) seen)
+       (setq files (nconc (directory-files file t nil t) files)))
+       ;; Add files to the list of score files.
+       ((string-match regexp file)
+       (push file out))))
+    (or out
+       ;; Return a dummy value.
+       (list (expand-file-name "this.file.does.not.exist.SCORE"
+                               gnus-kill-files-directory)))))
+
+(defun gnus-score-file-regexp ()
+  "Return a regexp that match all score files."
+  (concat "\\(" (regexp-quote gnus-score-file-suffix )
+         "\\|" (regexp-quote gnus-adaptive-file-suffix) "\\)\\'"))
+
+(defun gnus-score-find-bnews (group)
+  "Return a list of score files for GROUP.
+The score files are those files in the ~/News/ directory which matches
+GROUP using BNews sys file syntax."
+  (let* ((sfiles (append (gnus-score-score-files group)
+                        gnus-internal-global-score-files))
+        (kill-dir (file-name-as-directory
+                   (expand-file-name gnus-kill-files-directory)))
+        (klen (length kill-dir))
+        (score-regexp (gnus-score-file-regexp))
+        (trans (cdr (assq ?: nnheader-file-name-translation-alist)))
+        (group-trans (nnheader-translate-file-chars group t))
+        ofiles not-match regexp)
+    (with-current-buffer (gnus-get-buffer-create "*gnus score files*")
+      (buffer-disable-undo)
+      ;; Go through all score file names and create regexp with them
+      ;; as the source.
+      (while sfiles
+       (erase-buffer)
+       (insert (car sfiles))
+       (goto-char (point-min))
+       ;; First remove the suffix itself.
+       (when (re-search-forward (concat "." score-regexp) nil t)
+         (replace-match "" t t)
+         (goto-char (point-min))
+         (if (looking-at (regexp-quote kill-dir))
+             ;; If the file name was just "SCORE", `klen' is one character
+             ;; too much.
+             (delete-char (min (1- (point-max)) klen))
+           (goto-char (point-max))
+           (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))))
+         ;; If short file names were used, we have to translate slashes.
+         (goto-char (point-min))
+         (let ((regexp (concat
+                        "[/:" (if trans (char-to-string trans)) "]")))
+           (while (re-search-forward regexp nil t)
+             (replace-match "." t t)))
+         ;; Kludge to get rid of "nntp+" problems.
+         (goto-char (point-min))
+         (when (looking-at "nn[a-z]+\\+")
+           (search-forward "+")
+           (forward-char -1)
+           (insert "\\")
+           (forward-char 1))
+         ;; Kludge to deal with "++".
+         (while (search-forward "+" nil t)
+           (replace-match "\\+" t t))
+         ;; Translate "all" to ".*".
+         (goto-char (point-min))
+         (while (search-forward "all" nil t)
+           (replace-match ".*" t t))
+         (goto-char (point-min))
+         ;; Deal with "not."s.
+         (if (looking-at "not.")
+             (progn
+               (setq not-match t)
+               (setq regexp
+                     (concat "^" (buffer-substring 5 (point-max)) "$")))
+           (setq regexp (concat "^" (buffer-substring 1 (point-max)) "$"))
+           (setq not-match nil))
+         ;; Finally - if this resulting regexp matches the group name,
+         ;; we add this score file to the list of score files
+         ;; applicable to this group.
+         (when (or (and not-match
+                        (ignore-errors
+                          (not (string-match regexp group-trans))))
+                   (and (not not-match)
+                        (ignore-errors (string-match regexp group-trans))))
+           (push (car sfiles) ofiles)))
+       (setq sfiles (cdr sfiles)))
+      (gnus-kill-buffer (current-buffer))
+      ;; Slight kludge here - the last score file returned should be
+      ;; the local score file, whether it exists or not.  This is so
+      ;; that any score commands the user enters will go to the right
+      ;; file, and not end up in some global score file.
+      (let ((localscore (gnus-score-file-name group)))
+       (setq ofiles (cons localscore (delete localscore ofiles))))
+      (gnus-sort-score-files (nreverse ofiles)))))
+
+(defun gnus-score-find-single (group)
+  "Return list containing the score file for GROUP."
+  (list (or gnus-newsgroup-adaptive-score-file
+           (gnus-score-file-name group gnus-adaptive-file-suffix))
+       (gnus-score-file-name group)))
+
+(defun gnus-score-find-hierarchical (group)
+  "Return list of score files for GROUP.
+This includes the score file for the group and all its parents."
+  (let* ((prefix (gnus-group-real-prefix group))
+        (all (list nil))
+        (group (gnus-group-real-name group))
+        (start 0))
+    (while (string-match "\\." group (1+ start))
+      (setq start (match-beginning 0))
+      (push (substring group 0 start) all))
+    (push group all)
+    (setq all
+         (nconc
+          (mapcar (lambda (group)
+                    (gnus-score-file-name group gnus-adaptive-file-suffix))
+                  (setq all (nreverse all)))
+          (mapcar 'gnus-score-file-name all)))
+    (if (equal prefix "")
+       all
+      (mapcar
+       (lambda (file)
+        (nnheader-translate-file-chars
+         (concat (file-name-directory file) prefix
+                 (file-name-nondirectory file))))
+       all))))
+
+(defun gnus-score-file-rank (file)
+  "Return a number that says how specific score FILE is.
+Destroys the current buffer."
+  (if (member file gnus-internal-global-score-files)
+      0
+    (when (string-match
+          (concat "^" (regexp-quote
+                       (expand-file-name
+                        (file-name-as-directory gnus-kill-files-directory))))
+          file)
+      (setq file (substring file (match-end 0))))
+    (insert file)
+    (goto-char (point-min))
+    (let ((beg (point))
+         elems)
+      (while (re-search-forward "[./]" nil t)
+       (push (buffer-substring beg (1- (point)))
+             elems))
+      (erase-buffer)
+      (setq elems (delete "all" elems))
+      (length elems))))
+
+(defun gnus-sort-score-files (files)
+  "Sort FILES so that the most general files come first."
+  (with-temp-buffer
+    (let ((alist
+          (mapcar
+           (lambda (file)
+             (cons (inline (gnus-score-file-rank file)) file))
+           files)))
+      (mapcar 'cdr (sort alist 'car-less-than-car)))))
+
+(defun gnus-score-find-alist (group)
+  "Return list of score files for GROUP.
+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
+    (if (setq score-files (assoc group gnus-score-file-alist-cache))
+       (cdr score-files)               ;ensures caching groups with no matches
+      ;; handle the multiple match alist
+      (while alist
+       (when (string-match (caar alist) group)
+         (setq score-files (append (cdar alist) score-files)))
+       (setq alist (cdr alist)))
+      (setq alist gnus-score-file-single-match-alist)
+      ;; handle the single match alist
+      (while alist
+       (when (string-match (caar alist) group)
+         ;; progn used just in case ("regexp") has no files
+         ;; and score-files is still nil.  -sj
+         ;; this can be construed as a "stop searching here" feature :>
+         ;; and used to simplify regexps in the single-alist
+         (setq score-files (append (cdar alist) score-files))
+         (setq alist nil))
+       (setq alist (cdr alist)))
+      ;; cache the score files
+      (push (cons group score-files) gnus-score-file-alist-cache)
+      score-files)))
+
+(defun gnus-all-score-files (&optional group)
+  "Return a list of all score files for the current group."
+  (let ((funcs gnus-score-find-score-files-function)
+       (group (or group gnus-newsgroup-name))
+       score-files)
+    (when group
+      ;; Make sure funcs is a list.
+      (and funcs
+          (not (listp funcs))
+          (setq funcs (list funcs)))
+      (when gnus-score-use-all-scores
+       ;; Get the initial score files for this group.
+       (when funcs
+         (setq score-files (copy-sequence (gnus-score-find-alist group))))
+       ;; Add any home adapt files.
+       (let ((home (gnus-home-score-file group t)))
+         (when home
+           (push home score-files)
+           (setq gnus-newsgroup-adaptive-score-file home)))
+       ;; Check whether there is a `adapt-file' group parameter.
+       (let ((param-file (gnus-group-find-parameter group 'adapt-file)))
+         (when param-file
+           (push param-file score-files)
+           (setq gnus-newsgroup-adaptive-score-file param-file))))
+      ;; Go through all the functions for finding score files (or actual
+      ;; scores) and add them to a list.
+      (while funcs
+       (when (functionp (car funcs))
+         (setq score-files
+               (append score-files
+                       (nreverse (funcall (car funcs) group)))))
+       (setq funcs (cdr funcs)))
+      (when gnus-score-use-all-scores
+       ;; Add any home score files.
+       (let ((home (gnus-home-score-file group)))
+         (when home
+           (push home score-files)))
+       ;; Check whether there is a `score-file' group parameter.
+       (let ((param-file (gnus-group-find-parameter group 'score-file)))
+         (when param-file
+           (push param-file score-files))))
+      ;; Expand all files names.
+      (let ((files score-files))
+       (while files
+         (when (stringp (car files))
+           (setcar files (expand-file-name
+                          (car files) gnus-kill-files-directory)))
+         (pop files)))
+      (setq score-files (nreverse score-files))
+      ;; Remove any duplicate score files.
+      (while (and score-files
+                 (member (car score-files) (cdr score-files)))
+       (pop score-files))
+      (let ((files score-files))
+       (while (cdr files)
+         (if (member (cadr files) (cddr files))
+             (setcdr files (cddr files))
+           (pop files))))
+      ;; Do the scoring if there are any score files for this group.
+      score-files)))
+
+(defun gnus-possibly-score-headers (&optional trace)
+  "Do scoring if scoring is required."
+  (let ((score-files (gnus-all-score-files)))
+    (when score-files
+      (gnus-score-headers score-files trace))))
+
+(defun gnus-score-file-name (newsgroup &optional suffix)
+  "Return the name of a score file for NEWSGROUP."
+  (let ((suffix (or suffix gnus-score-file-suffix)))
+    (nnheader-translate-file-chars
+     (cond
+      ((or (null newsgroup)
+          (string-equal newsgroup ""))
+       ;; The global score file is placed at top of the directory.
+       (expand-file-name suffix gnus-kill-files-directory))
+      ((gnus-use-long-file-name 'not-score)
+       ;; Append ".SCORE" to newsgroup name.
+       (expand-file-name (concat (gnus-newsgroup-savable-name newsgroup)
+                                "." suffix)
+                        gnus-kill-files-directory))
+      (t
+       ;; Place "SCORE" under the hierarchical directory.
+       (expand-file-name (concat (gnus-newsgroup-directory-form newsgroup)
+                                "/" suffix)
+                        gnus-kill-files-directory))))))
+
+(defun gnus-score-search-global-directories (files)
+  "Scan all global score directories for score files."
+  ;; Set the variable `gnus-internal-global-score-files' to all
+  ;; available global score files.
+  (interactive (list gnus-global-score-files))
+  (let (out)
+    (while files
+      ;; #### /$ Unix-specific?
+      (if (file-directory-p (car files))
+         (setq out (nconc (directory-files
+                           (car files) t
+                           (concat (gnus-score-file-regexp) "$"))))
+       (push (car files) out))
+      (setq files (cdr files)))
+    (setq gnus-internal-global-score-files out)))
+
+(defun gnus-score-default-fold-toggle ()
+  "Toggle folding for new score file entries."
+  (interactive)
+  (setq gnus-score-default-fold (not gnus-score-default-fold))
+  (if gnus-score-default-fold
+      (gnus-message 1 "New score file entries will be case insensitive.")
+    (gnus-message 1 "New score file entries will be case sensitive.")))
+
+;;; Home score file.
+
+(defun gnus-home-score-file (group &optional adapt)
+  "Return the home score file for GROUP.
+If ADAPT, return the home adaptive file instead."
+  (let ((list (if adapt gnus-home-adapt-file gnus-home-score-file))
+       elem found)
+    ;; Make sure we have a list.
+    (unless (listp list)
+      (setq list (list list)))
+    ;; Go through the list and look for matches.
+    (while (and (not found)
+               (setq elem (pop list)))
+      (setq found
+           (cond
+            ;; Simple string.
+            ((stringp elem)
+             elem)
+            ;; Function.
+            ((functionp elem)
+             (funcall elem group))
+            ;; Regexp-file cons.
+            ((consp elem)
+             (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)))))
+
+(defun gnus-hierarchial-home-score-file (group)
+  "Return the score file of the top-level hierarchy of GROUP."
+  (if (string-match "^[^.]+\\." group)
+      (concat (match-string 0 group) gnus-score-file-suffix)
+    ;; Group name without any dots.
+    (concat group (if (gnus-use-long-file-name 'not-score) "." "/")
+           gnus-score-file-suffix)))
+
+(defun gnus-hierarchial-home-adapt-file (group)
+  "Return the adapt file of the top-level hierarchy of GROUP."
+  (if (string-match "^[^.]+\\." group)
+      (concat (match-string 0 group) gnus-adaptive-file-suffix)
+    ;; Group name without any dots.
+    (concat group (if (gnus-use-long-file-name 'not-score) "." "/")
+           gnus-adaptive-file-suffix)))
+
+(defun gnus-current-home-score-file (group)
+  "Return the \"current\" regular score file."
+  (car (gnus-score-find-alist group)))
+
+;;;
+;;; Score decays
+;;;
+
+(defun gnus-decay-score (score)
+  "Decay SCORE according to `gnus-score-decay-constant' and `gnus-score-decay-scale'."
+  (let ((n (- score
+             (* (if (< score 0) -1 1)
+                (min (abs score)
+                     (max gnus-score-decay-constant
+                          (* (abs score)
+                             gnus-score-decay-scale)))))))
+    (if (and (featurep 'xemacs)
+            ;; XEmacs's floor can handle only the floating point
+            ;; number below the half of the maximum integer.
+            (> (abs n) (lsh -1 -2)))
+       (string-to-number
+        (car (split-string (number-to-string n) "\\.")))
+      (floor n))))
+
+(defun gnus-decay-scores (alist day)
+  "Decay non-permanent scores in ALIST."
+  (let ((times (- (time-to-days (current-time)) day))
+       kill entry updated score n)
+    (unless (zerop times)              ;Done decays today already?
+      (while (setq entry (pop alist))
+       (when (stringp (car entry))
+         (setq entry (cdr entry))
+         (while (setq kill (pop entry))
+           (when (nth 2 kill)
+             (setq updated t)
+             (setq score (or (nth 1 kill)
+                             gnus-score-interactive-default-score)
+                   n times)
+             (while (natnump (decf n))
+               (setq score (funcall gnus-decay-score-function score)))
+             (setcdr kill (cons score
+                                (cdr (cdr kill)))))))))
+    ;; Return whether this score file needs to be saved.  By Je-haysuss!
+    updated))
+
+(provide 'gnus-score)
+
+;;; gnus-score.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-sieve.el b/xemacs-packages/gnus/lisp/gnus-sieve.el
new file mode 100644 (file)
index 0000000..cabcef2
--- /dev/null
@@ -0,0 +1,237 @@
+;;; gnus-sieve.el --- Utilities to manage sieve scripts for Gnus
+
+;; Copyright (C) 2001-2016 Free Software Foundation, Inc.
+
+;; Author: NAGY Andras <nagya@inf.elte.hu>,
+;;     Simon Josefsson <simon@josefsson.org>
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; 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\""
+  ;; FIXME? gnus-select-method?
+  :type '(choice (const nil) string)
+  :group 'gnus-sieve)
+
+(defcustom gnus-sieve-crosspost t
+  "Whether the generated Sieve script should do crossposting."
+  :type 'boolean
+  :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 (regexp-quote gnus-sieve-region-start) nil t)
+      (delete-region (match-beginning 0)
+                    (or (re-search-forward (regexp-quote
+                                            gnus-sieve-region-end) nil t)
+                        (point)))
+    (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" ,(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 crosspost
+                             ""
+                           "\tstop;\n")
+                         "}")
+                 script)))))
+    (mapconcat 'identity script "\n")))
+
+(provide 'gnus-sieve)
+
+;;; gnus-sieve.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-spec.el b/xemacs-packages/gnus/lisp/gnus-spec.el
new file mode 100644 (file)
index 0000000..2176e3f
--- /dev/null
@@ -0,0 +1,736 @@
+;;; gnus-spec.el --- format spec functions for Gnus
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(defvar gnus-newsrc-file-version)
+
+(require 'gnus)
+
+(defcustom gnus-use-correct-string-widths (featurep 'xemacs)
+  "*If non-nil, use correct functions for dealing with wide characters."
+  :version "22.1"
+  :group 'gnus-format
+  :type 'boolean)
+
+(defcustom gnus-make-format-preserve-properties (featurep 'xemacs)
+  "*If non-nil, use a replacement `format' function which preserves
+text properties. This is only needed on XEmacs, as Emacs does this anyway."
+  :version "22.1"
+  :group 'gnus-format
+  :type 'boolean)
+
+;;; Internal variables.
+
+(defvar gnus-summary-mark-positions nil)
+(defvar gnus-group-mark-positions nil)
+(defvar gnus-group-indentation "")
+
+;; Format specs.  The chunks below are the machine-generated forms
+;; that are to be evalled as the result of the default format strings.
+;; We write them in here to get them byte-compiled.  That way the
+;; default actions will be quite fast, while still retaining the full
+;; flexibility of the user-defined format specs.
+
+;; First we have lots of dummy defvars to let the compiler know these
+;; are really dynamic variables.
+
+(defvar gnus-tmp-unread)
+(defvar gnus-tmp-replied)
+(defvar gnus-tmp-score-char)
+(defvar gnus-tmp-indentation)
+(defvar gnus-tmp-opening-bracket)
+(defvar gnus-tmp-lines)
+(defvar gnus-tmp-name)
+(defvar gnus-tmp-closing-bracket)
+(defvar gnus-tmp-subject-or-nil)
+(defvar gnus-tmp-subject)
+(defvar gnus-tmp-marked)
+(defvar gnus-tmp-marked-mark)
+(defvar gnus-tmp-subscribed)
+(defvar gnus-tmp-process-marked)
+(defvar gnus-tmp-number-of-unread)
+(defvar gnus-tmp-group-name)
+(defvar gnus-tmp-group)
+(defvar gnus-tmp-article-number)
+(defvar gnus-tmp-unread-and-unselected)
+(defvar gnus-tmp-news-method)
+(defvar gnus-tmp-news-server)
+(defvar gnus-mouse-face)
+(defvar gnus-mouse-face-prop)
+(defvar gnus-tmp-header)
+(defvar gnus-tmp-from)
+
+(declare-function gnus-summary-from-or-to-or-newsgroups "gnus-sum"
+                  (header gnus-tmp-from))
+
+(defmacro gnus-lrm-string-p (string)
+  (if (fboundp 'bidi-string-mark-left-to-right)
+      ;; LRM, RLM, PDF characters as integers to avoid breaking Emacs
+      ;; 23.
+      `(memq (aref ,string (1- (length ,string))) '(8206 8207 8236))
+    nil))
+
+(defvar gnus-lrm-string (if (ignore-errors (string 8206))
+                           (propertize (string 8206) 'invisible t)
+                         ""))
+
+(defvar gnus-summary-line-format-spec nil)
+(defvar gnus-summary-dummy-line-format-spec nil)
+(defvar gnus-group-line-format-spec nil)
+
+(defvar gnus-format-specs
+  `((version . ,emacs-version)
+    (gnus-version . ,(gnus-continuum-version)))
+  "Alist of format specs.")
+
+(defvar gnus-default-format-specs gnus-format-specs)
+
+(defvar gnus-article-mode-line-format-spec nil)
+(defvar gnus-summary-mode-line-format-spec nil)
+(defvar gnus-group-mode-line-format-spec nil)
+
+;;; Phew.  All that gruft is over with, fortunately.
+
+;;;###autoload
+(defun gnus-update-format (var)
+  "Update the format specification near point."
+  (interactive
+   (list
+    (save-excursion
+      (eval-defun nil)
+      ;; Find the end of the current word.
+      (re-search-forward "[ \t\n]" nil t)
+      ;; Search backward.
+      (when (re-search-backward "\\(gnus-[-a-z]+-line-format\\)" nil t)
+       (match-string 1)))))
+  (let* ((type (intern (progn (string-match "gnus-\\([-a-z]+\\)-line" var)
+                             (match-string 1 var))))
+        (entry (assq type gnus-format-specs))
+        value spec)
+    (when entry
+      (setq gnus-format-specs (delq entry gnus-format-specs)))
+    (set
+     (intern (format "%s-spec" var))
+     (gnus-parse-format (setq value (symbol-value (intern var)))
+                       (symbol-value (intern (format "%s-alist" var)))
+                       (not (string-match "mode" var))))
+    (setq spec (symbol-value (intern (format "%s-spec" var))))
+    (push (list type value spec) gnus-format-specs)
+
+    (pop-to-buffer "*Gnus Format*")
+    (erase-buffer)
+    (lisp-interaction-mode)
+    (insert (gnus-pp-to-string spec))))
+
+(defun gnus-update-format-specifications (&optional force &rest types)
+  "Update all (necessary) format specifications.
+Return a list of updated types."
+  ;; Make the indentation array.
+  ;; See whether all the stored info needs to be flushed.
+  (when (or force
+           (not gnus-newsrc-file-version)
+           (not (equal (gnus-continuum-version)
+                       (gnus-continuum-version gnus-newsrc-file-version)))
+           (not (equal emacs-version
+                       (cdr (assq 'version gnus-format-specs)))))
+    (setq gnus-format-specs nil))
+  ;; Go through all the formats and see whether they need updating.
+  (let (new-format entry type val updated)
+    (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.)
+      (save-excursion
+       (let ((buffer (intern (format "gnus-%s-buffer" type))))
+         (when (and (boundp buffer)
+                    (setq val (symbol-value buffer))
+                    (gnus-buffer-exists-p val))
+           (set-buffer val))
+         (setq new-format (symbol-value
+                           (intern (format "gnus-%s-line-format" type)))))
+       (setq entry (cdr (assq type gnus-format-specs)))
+       (if (and (car entry)
+                (equal (car entry) new-format))
+           ;; Use the old format.
+           (set (intern (format "gnus-%s-line-format-spec" type))
+                (cadr entry))
+         ;; This is a new format.
+         (setq val
+               (if (not (stringp new-format))
+                   ;; This is a function call or something.
+                   new-format
+                 ;; This is a "real" format.
+                 (gnus-parse-format
+                  new-format
+                  (symbol-value
+                   (intern (format "gnus-%s-line-format-alist" type)))
+                  (not (string-match "mode$" (symbol-name type))))))
+         ;; Enter the new format spec into the list.
+         (if entry
+             (progn
+               (setcar (cdr entry) val)
+               (setcar entry new-format))
+           (push (list type new-format val) gnus-format-specs))
+         (set (intern (format "gnus-%s-line-format-spec" type)) val)
+         (push type updated))))
+
+    (unless (assq 'version gnus-format-specs)
+      (push (cons 'version emacs-version) gnus-format-specs))
+    updated))
+
+(defcustom gnus-mouse-face-0 'highlight
+  "The \"%(hello%)\" face."
+  :group 'gnus-format
+  :type 'face)
+
+(defcustom gnus-mouse-face-1 'highlight
+  "The \"%1(hello%)\" face."
+  :group 'gnus-format
+  :type 'face)
+
+(defcustom gnus-mouse-face-2 'highlight
+  "The \"%2(hello%)\" face."
+  :group 'gnus-format
+  :type 'face)
+
+(defcustom gnus-mouse-face-3 'highlight
+  "The \"%3(hello%)\" face."
+  :group 'gnus-format
+  :type 'face)
+
+(defcustom gnus-mouse-face-4 'highlight
+  "The \"%4(hello%)\" face."
+  :group 'gnus-format
+  :type 'face)
+
+(defun gnus-mouse-face-function (form type)
+  `(gnus-put-text-property
+    (point) (progn ,@form (point))
+    gnus-mouse-face-prop
+    ,(if (equal type 0)
+        'gnus-mouse-face
+       `(quote ,(symbol-value (intern (format "gnus-mouse-face-%d" type)))))))
+
+(defcustom gnus-face-0 'bold
+  "The \"%{hello%}\" face."
+  :group 'gnus-format
+  :type 'face)
+
+(defcustom gnus-face-1 'italic
+  "The \"%1{hello%}\" face."
+  :group 'gnus-format
+  :type 'face)
+
+(defcustom gnus-face-2 'bold-italic
+  "The \"%2{hello%}\" face."
+  :group 'gnus-format
+  :type 'face)
+
+(defcustom gnus-face-3 'bold
+  "The \"%3{hello%}\" face."
+  :group 'gnus-format
+  :type 'face)
+
+(defcustom gnus-face-4 'bold
+  "The \"%4{hello%}\" face."
+  :group 'gnus-format
+  :type 'face)
+
+(defun gnus-face-face-function (form type)
+  `(gnus-add-text-properties
+    (point) (progn ,@form (point))
+    (cons 'face
+         (cons
+          ;; Delay consing the value of the `face' property until
+          ;; `gnus-add-text-properties' runs, since it will be modified
+          ;; by `gnus-put-text-property-excluding-characters-with-faces'.
+          (list ',(symbol-value (intern (format "gnus-face-%d" type))) 'default)
+          ;; Redundant now, but still convenient.
+          '(gnus-face t)))))
+
+(defun gnus-balloon-face-function (form type)
+  `(gnus-put-text-property
+    (point) (progn ,@form (point))
+    ,(if (fboundp 'balloon-help-mode)
+        ''balloon-help
+       ''help-echo)
+    ,(intern (format "gnus-balloon-face-%d" type))))
+
+(defun gnus-spec-tab (column)
+  (if (> column 0)
+      `(insert-char ?  (max (- ,column (current-column)) 0))
+    (let ((column (abs column)))
+      `(if (> (current-column) ,column)
+          (let ((end (point)))
+            (if (= (move-to-column ,column) ,column)
+                (delete-region (point) end)
+              (delete-region (1- (point)) end)
+              (insert " ")))
+        (insert-char ?  (max (- ,column (current-column)) 0))))))
+
+(defun gnus-correct-length (string)
+  "Return the correct width of STRING."
+  (apply #'+ (mapcar #'char-width string)))
+
+(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 (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 (char-width (aref string seek)))
+      (incf seek))
+    (setq wend seek)
+    (substring string wstart (1- wend))))
+
+(defun gnus-string-width-function ()
+  (cond
+   (gnus-use-correct-string-widths
+    'gnus-correct-length)
+   ((fboundp 'string-width)
+    'string-width)
+   (t
+    'length)))
+
+(defun gnus-substring-function ()
+  (cond
+   (gnus-use-correct-string-widths
+    'gnus-correct-substring)
+   ((fboundp 'string-width)
+    'gnus-correct-substring)
+   (t
+    'substring)))
+
+(defun gnus-tilde-max-form (el max-width)
+  "Return a form that limits EL to MAX-WIDTH."
+  (let ((max (abs max-width))
+       (length-fun (gnus-string-width-function))
+       (substring-fun (gnus-substring-function)))
+    (if (symbolp el)
+       `(if (> (,length-fun ,el) ,max)
+            ,(if (< max-width 0)
+                 `(,substring-fun ,el (- (,length-fun ,el) ,max))
+               `(if (gnus-lrm-string-p ,el)
+                    (concat (,substring-fun ,el 0 ,max) ,gnus-lrm-string)
+                  (,substring-fun ,el 0 ,max)))
+          ,el)
+      `(let ((val (eval ,el)))
+        (if (> (,length-fun val) ,max)
+            ,(if (< max-width 0)
+                 `(,substring-fun val (- (,length-fun val) ,max))
+               `(if (gnus-lrm-string-p val)
+                    (concat (,substring-fun val 0 ,max) ,gnus-lrm-string)
+                  (,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))
+       (length-fun (gnus-string-width-function))
+       (substring-fun (gnus-substring-function)))
+    (if (symbolp el)
+       `(if (> (,length-fun ,el) ,cut)
+            ,(if (< cut-width 0)
+                 `(,substring-fun ,el 0 (- (,length-fun ,el) ,cut))
+               `(,substring-fun ,el ,cut))
+          ,el)
+      `(let ((val (eval ,el)))
+        (if (> (,length-fun val) ,cut)
+            ,(if (< cut-width 0)
+                 `(,substring-fun val 0 (- (,length-fun val) ,cut))
+               `(,substring-fun val ,cut))
+          val)))))
+
+(defun gnus-tilde-ignore-form (el ignore-value)
+  "Return a form that is blank when EL is IGNORE-VALUE."
+  (if (symbolp el)
+      `(if (equal ,el ,ignore-value)
+          "" ,el)
+    `(let ((val (eval ,el)))
+       (if (equal val ,ignore-value)
+          "" val))))
+
+(defun gnus-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))
+       (length-fun (gnus-string-width-function)))
+    (if (symbolp el)
+       `(let ((need (- ,pad (,length-fun ,el))))
+          (if (> need 0)
+              (concat ,(when side '(make-string need ?\ ))
+                      ,el
+                      ,(when (not side) '(make-string need ?\ )))
+            ,el))
+      `(let* ((val (eval ,el))
+             (need (- ,pad (,length-fun val))))
+        (if (> need 0)
+            (concat ,(when side '(make-string need ?\ ))
+                    val
+                    ,(when (not side) '(make-string need ?\ )))
+          val)))))
+
+(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
+  ;; string.  If the FORMAT string contains the specifiers %( and %)
+  ;; 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.
+  (let ((case-fold-search nil))
+    (if (string-match
+        "\\`\\(.*\\)%[0-9]?[{(«]\\(.*\\)%[0-9]?[»})]\\(.*\n?\\)\\'\\|%[-0-9]*=\\|%[-0-9]*\\*"
+        format)
+       (gnus-parse-complex-format format spec-alist)
+      ;; This is a simple format.
+      (gnus-parse-simple-format format spec-alist insert))))
+
+(defun gnus-parse-complex-format (format spec-alist)
+  (let ((cursor-spec nil))
+    (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 171)) ; «
+             (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]+\\)?\\*" nil t)
+         (replace-match "\"(point)\"" t t)
+         (setq cursor-spec 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 cursor-spec
+           `(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)
+          (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)))))
+        form)))
+
+
+(defun gnus-xmas-format (fstring &rest args)
+  "A version of `format' which preserves text properties.
+
+Required for XEmacs, where the built in `format' function strips all text
+properties from both the format string and any inserted strings.
+
+Only supports the format sequence %s, and %% for inserting
+literal % characters. A pad width and an optional - (to right pad)
+are supported for %s."
+  (let ((re "%%\\|%\\(-\\)?\\([1-9][0-9]*\\)?s")
+       (n (length args)))
+    (with-temp-buffer
+      (insert fstring)
+      (goto-char (point-min))
+      (while (re-search-forward re nil t)
+       (goto-char (match-end 0))
+       (cond
+        ((string= (match-string 0) "%%")
+         (delete-char -1))
+        (t
+         (if (null args)
+             (signal 'wrong-number-of-arguments
+                     (list #'gnus-xmas-format n fstring)))
+         (let* ((minlen (string-to-number (or (match-string 2) "")))
+                (arg (car args))
+                (str (if (stringp arg) arg (format "%s" arg)))
+                (lpad (null (match-string 1)))
+                (padlen (max 0 (- minlen (length str)))))
+           (replace-match "")
+           (if lpad (insert-char ?\  padlen))
+           (insert str)
+           (unless lpad (insert-char ?\  padlen))
+           (setq args (cdr args))))))
+      (buffer-string))))
+
+(defun gnus-parse-simple-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 a
+  ;; string.
+  (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 extended-spec)
+    (save-excursion
+      (gnus-set-work-buffer)
+      (insert format)
+      (goto-char (point-min))
+      (while (re-search-forward "%" nil t)
+       (setq user-defined nil
+             spec-beg nil
+             pad-width nil
+             max-width nil
+             cut-width nil
+             ignore-value nil
+             tilde-form nil
+             extended-spec nil)
+       (setq spec-beg (1- (point)))
+
+       ;; Parse this spec fully.
+       (while
+           (cond
+            ((looking-at "\\([-.0-9]+\\)\\(,[-0-9]+\\)?")
+             (setq pad-width (string-to-number (match-string 1)))
+             (when (match-beginning 2)
+               (setq max-width (string-to-number (buffer-substring
+                                                  (1+ (match-beginning 2))
+                                                  (match-end 2)))))
+             (goto-char (match-end 0)))
+            ((looking-at "~")
+             (forward-char 1)
+             (setq tilde (read (current-buffer))
+                   type (car tilde)
+                   value (cadr tilde))
+             (cond
+              ((memq type '(pad pad-left))
+               (setq pad-width value))
+              ((eq type 'pad-right)
+               (setq pad-width (- value)))
+              ((memq type '(max-right max))
+               (setq max-width value))
+              ((eq type 'max-left)
+               (setq max-width (- value)))
+              ((memq type '(cut cut-left))
+               (setq cut-width value))
+              ((eq type 'cut-right)
+               (setq cut-width (- value)))
+              ((eq type 'ignore)
+               (setq ignore-value
+                     (if (stringp value) value (format "%s" value))))
+              ((eq type 'form)
+               (setq tilde-form value))
+              (t
+               (error "Unknown tilde type: %s" tilde)))
+             t)
+            (t
+             nil)))
+       (cond
+        ;; User-defined spec -- find the spec name.
+        ((eq (setq spec (char-after)) ?u)
+         (forward-char 1)
+         (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))
+
+       ;; Now we have all the relevant data on this spec, so
+       ;; we start doing stuff.
+       (insert "%")
+       (if (eq spec ?%)
+           ;; "%%" just results in a "%".
+           (insert "%")
+         (cond
+          ;; Do tilde forms.
+          ((eq spec ?@)
+           (setq elem (list tilde-form ?s)))
+          ;; Treat user defined format specifiers specially.
+          (user-defined
+           (setq elem
+                 (list
+                  (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 (or extended-spec spec) spec-alist))))
+          ;; We used to use "%l" for displaying the grouplens score.
+          ((eq spec ?l)
+           (setq elem '("" ?s)))
+          (t
+           (setq elem '("*" ?s))))
+         (setq elem-type (cadr elem))
+         ;; Insert the new format elements.
+         (when (and pad-width
+                    (not (and (featurep 'xemacs)
+                              gnus-use-correct-string-widths)))
+           (insert (number-to-string pad-width)))
+         ;; Create the form to be evalled.
+         (if (or max-width cut-width ignore-value
+                 (and (featurep 'xemacs)
+                      gnus-use-correct-string-widths))
+             (progn
+               (insert ?s)
+               (let ((el (car elem)))
+                 (cond ((= (cadr elem) ?c)
+                        (setq el (list 'char-to-string el)))
+                       ((= (cadr elem) ?d)
+                        (setq el (list 'int-to-string el))))
+                 (when ignore-value
+                   (setq el (gnus-tilde-ignore-form el ignore-value)))
+                 (when cut-width
+                   (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-pad-form el pad-width)))
+                 (push el flist)))
+           (insert elem-type)
+           (push (car elem) flist))))
+      (setq fstring (buffer-substring-no-properties (point-min) (point-max))))
+
+    ;; Do some postprocessing to increase efficiency.
+    (setq
+     result
+     (cond
+      ;; Emptiness.
+      ((string= fstring "")
+       nil)
+      ;; Not a format string.
+      ((not (string-match "%" fstring))
+       (list fstring))
+      ;; A format string with just a single string spec.
+      ((string= fstring "%s")
+       (list (car flist)))
+      ;; A single character.
+      ((string= fstring "%c")
+       (list (car flist)))
+      ;; A single number.
+      ((string= fstring "%d")
+       (setq dontinsert t)
+       (if insert
+          `(insert (int-to-string ,(car flist)))
+        (list `(int-to-string ,(car flist)))))
+      ;; Just lots of chars and strings.
+      ((string-match "\\`\\(%[cs]\\)+\\'" fstring)
+       (nreverse flist))
+      ;; A single string spec at the beginning of the spec.
+      ((string-match "\\`%[sc][^%]+\\'" fstring)
+       (list (car flist) (substring fstring 2)))
+      ;; A single string spec in the middle of the spec.
+      ((string-match "\\`\\([^%]+\\)%[sc]\\([^%]+\\)\\'" fstring)
+       (list (match-string 1 fstring) (car flist) (match-string 2 fstring)))
+      ;; A single string spec in the end of the spec.
+      ((string-match "\\`\\([^%]+\\)%[sc]\\'" fstring)
+       (list (match-string 1 fstring) (car flist)))
+      ;; Only string (and %) specs (XEmacs only!)
+      ((and (featurep 'xemacs)
+           gnus-make-format-preserve-properties
+           (string-match
+            "\\`\\([^%]*\\(%%\\|%-?\\([1-9][0-9]*\\)?s\\)\\)*[^%]*\\'"
+            fstring))
+       (list (cons 'gnus-xmas-format (cons fstring (nreverse flist)))))
+      ;; A more complex spec.
+      (t
+       (list (cons 'format (cons fstring (nreverse flist)))))))
+
+    (if insert
+       (when result
+         (if dontinsert
+             result
+           (cons 'insert result)))
+      (cond ((stringp result)
+            result)
+           ((consp result)
+            (cons 'concat result))
+           (t "")))))
+
+(defun gnus-eval-format (format &optional alist props)
+  "Eval the format variable FORMAT, using ALIST.
+If PROPS, insert the result."
+  (let ((form (gnus-parse-format format alist props)))
+    (if props
+       (gnus-add-text-properties (point) (progn (eval form) (point)) props)
+      (eval form))))
+
+(defun gnus-set-format (type &optional insertable)
+  (set (intern (format "gnus-%s-line-format-spec" type))
+       (gnus-parse-format
+       (symbol-value (intern (format "gnus-%s-line-format" type)))
+       (symbol-value (intern (format "gnus-%s-line-format-alist" type)))
+       insertable)))
+
+(provide 'gnus-spec)
+
+;; Local Variables:
+;; coding: utf-8
+;; End:
+
+;;; gnus-spec.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-srvr.el b/xemacs-packages/gnus/lisp/gnus-srvr.el
new file mode 100644 (file)
index 0000000..7afd053
--- /dev/null
@@ -0,0 +1,1136 @@
+;;; gnus-srvr.el --- virtual server support for Gnus
+
+;; Copyright (C) 1995-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'gnus)
+(require 'gnus-start)
+(require 'gnus-spec)
+(require 'gnus-group)
+(require 'gnus-int)
+(require 'gnus-range)
+
+(autoload 'gnus-group-make-nnir-group "nnir")
+
+(defcustom gnus-server-mode-hook nil
+  "Hook run in `gnus-server-mode' buffers."
+  :group 'gnus-server
+  :type 'hook)
+
+(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%c\n"
+  "Format of server lines.
+It works along the same lines as a normal formatting string,
+with some simple extensions.
+
+The following specs are understood:
+
+%h back end
+%n name
+%w address
+%s status
+%a agent covered
+
+General format specifiers can also be used.
+See Info node `(gnus)Formatting Variables'."
+  :link '(custom-manual "(gnus)Formatting Variables")
+  :group 'gnus-server-visual
+  :type 'string)
+
+(defcustom gnus-server-mode-line-format "Gnus: %%b"
+  "The format specification for the server mode line."
+  :group 'gnus-server-visual
+  :type 'string)
+
+(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."
+  :version "22.1"
+  :group 'gnus-server-visual
+  :type 'boolean)
+
+;;; Internal variables.
+
+(defvar gnus-tmp-how)
+(defvar gnus-tmp-name)
+(defvar gnus-tmp-where)
+(defvar gnus-tmp-status)
+(defvar gnus-tmp-agent)
+(defvar gnus-tmp-cloud)
+(defvar gnus-tmp-news-server)
+(defvar gnus-tmp-news-method)
+(defvar gnus-tmp-user-defined)
+
+(defvar gnus-inserted-opened-servers nil)
+
+(defvar gnus-server-line-format-alist
+  `((?h gnus-tmp-how ?s)
+    (?n gnus-tmp-name ?s)
+    (?w gnus-tmp-where ?s)
+    (?s gnus-tmp-status ?s)
+    (?a gnus-tmp-agent ?s)
+    (?c gnus-tmp-cloud ?s)))
+
+(defvar gnus-server-mode-line-format-alist
+  `((?S gnus-tmp-news-server ?s)
+    (?M gnus-tmp-news-method ?s)
+    (?u gnus-tmp-user-defined ?s)))
+
+(defvar gnus-server-line-format-spec nil)
+(defvar gnus-server-mode-line-format-spec nil)
+(defvar gnus-server-killed-servers nil)
+
+(defvar gnus-server-mode-map)
+
+(defvar gnus-server-menu-hook nil
+  "*Hook run after the creation of the server mode menu.")
+
+(defun gnus-server-make-menu-bar ()
+  (gnus-turn-off-edit-menu 'server)
+  (unless (boundp 'gnus-server-server-menu)
+    (easy-menu-define
+     gnus-server-server-menu gnus-server-mode-map ""
+     '("Server"
+       ["Add..." gnus-server-add-server t]
+       ["Browse" gnus-server-read-server t]
+       ["Scan" gnus-server-scan-server t]
+       ["List" gnus-server-list-servers t]
+       ["Kill" gnus-server-kill-server t]
+       ["Yank" gnus-server-yank-server t]
+       ["Copy" gnus-server-copy-server t]
+       ["Show" gnus-server-show-server t]
+       ["Edit" gnus-server-edit-server t]
+       ["Regenerate" gnus-server-regenerate-server t]
+       ["Compact" gnus-server-compact-server t]
+       ["Exit" gnus-server-exit t]))
+
+    (easy-menu-define
+     gnus-server-connections-menu gnus-server-mode-map ""
+     '("Connections"
+       ["Open" gnus-server-open-server t]
+       ["Close" gnus-server-close-server t]
+       ["Offline" gnus-server-offline-server t]
+       ["Deny" gnus-server-deny-server t]
+       ["Toggle Cloud" gnus-server-toggle-cloud-server t]
+       "---"
+       ["Open All" gnus-server-open-all-servers t]
+       ["Close All" gnus-server-close-all-servers t]
+       ["Reset All" gnus-server-remove-denials t]))
+
+    (gnus-run-hooks 'gnus-server-menu-hook)))
+
+(defvar gnus-server-mode-map nil)
+(put 'gnus-server-mode 'mode-class 'special)
+
+(unless gnus-server-mode-map
+  (setq gnus-server-mode-map (make-sparse-keymap))
+  (suppress-keymap gnus-server-mode-map)
+
+  (gnus-define-keys gnus-server-mode-map
+    " " gnus-server-read-server-in-server-buffer
+    "\r" gnus-server-read-server
+    gnus-mouse-2 gnus-server-pick-server
+    "q" gnus-server-exit
+    "l" gnus-server-list-servers
+    "k" gnus-server-kill-server
+    "y" gnus-server-yank-server
+    "c" gnus-server-copy-server
+    "a" gnus-server-add-server
+    "e" gnus-server-edit-server
+    "S" gnus-server-show-server
+    "s" gnus-server-scan-server
+
+    "O" gnus-server-open-server
+    "\M-o" gnus-server-open-all-servers
+    "C" gnus-server-close-server
+    "\M-c" gnus-server-close-all-servers
+    "D" gnus-server-deny-server
+    "L" gnus-server-offline-server
+    "R" gnus-server-remove-denials
+
+    "n" next-line
+    "p" previous-line
+
+    "g" gnus-server-regenerate-server
+
+    "G" gnus-group-make-nnir-group
+
+    "z" gnus-server-compact-server
+
+    "i" gnus-server-toggle-cloud-server
+
+    "\C-c\C-i" gnus-info-find-node
+    "\C-c\C-b" gnus-bug))
+
+(defface gnus-server-agent
+  '((((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)
+;; backward-compatibility alias
+(put 'gnus-server-agent-face 'face-alias 'gnus-server-agent)
+(put 'gnus-server-agent-face 'obsolete-face "22.1")
+
+(defface gnus-server-cloud
+  '((((class color) (background light)) (:foreground "ForestGreen" :bold t))
+    (((class color) (background dark)) (:foreground "PaleGreen" :bold t))
+    (t (:bold t)))
+  "Face used for displaying AGENTIZED servers"
+  :group 'gnus-server-visual)
+
+(defface gnus-server-opened
+  '((((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)
+;; backward-compatibility alias
+(put 'gnus-server-opened-face 'face-alias 'gnus-server-opened)
+(put 'gnus-server-opened-face 'obsolete-face "22.1")
+
+(defface gnus-server-closed
+  '((((class color) (background light)) (:foreground "Steel Blue" :italic t))
+    (((class color) (background dark))
+     (:foreground "LightBlue" :italic t))
+    (t (:italic t)))
+  "Face used for displaying CLOSED servers"
+  :group 'gnus-server-visual)
+;; backward-compatibility alias
+(put 'gnus-server-closed-face 'face-alias 'gnus-server-closed)
+(put 'gnus-server-closed-face 'obsolete-face "22.1")
+
+(defface gnus-server-denied
+  '((((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)
+;; backward-compatibility alias
+(put 'gnus-server-denied-face 'face-alias 'gnus-server-denied)
+(put 'gnus-server-denied-face 'obsolete-face "22.1")
+
+(defface gnus-server-offline
+  '((((class color) (background light)) (:foreground "Orange" :bold t))
+    (((class color) (background dark)) (:foreground "Yellow" :bold t))
+    (t (:inverse-video t :bold t)))
+  "Face used for displaying OFFLINE servers"
+  :group 'gnus-server-visual)
+;; backward-compatibility alias
+(put 'gnus-server-offline-face 'face-alias 'gnus-server-offline)
+(put 'gnus-server-offline-face 'obsolete-face "22.1")
+
+(defvar gnus-server-font-lock-keywords
+  '(("(\\(agent\\))" 1 'gnus-server-agent)
+    ("(\\(cloud\\))" 1 'gnus-server-cloud)
+    ("(\\(opened\\))" 1 'gnus-server-opened)
+    ("(\\(closed\\))" 1 'gnus-server-closed)
+    ("(\\(offline\\))" 1 'gnus-server-offline)
+    ("(\\(denied\\))" 1 'gnus-server-denied)))
+
+(defun gnus-server-mode ()
+  "Major mode for listing and editing servers.
+
+All normal editing commands are switched off.
+\\<gnus-server-mode-map>
+For more in-depth information on this mode, read the manual
+\(`\\[gnus-info-find-node]').
+
+The following commands are available:
+
+\\{gnus-server-mode-map}"
+  ;; FIXME: Use define-derived-mode.
+  (interactive)
+  (when (gnus-visual-p 'server-menu 'menu)
+    (gnus-server-make-menu-bar))
+  (kill-all-local-variables)
+  (gnus-simplify-mode-line)
+  (setq major-mode 'gnus-server-mode)
+  (setq mode-name "Server")
+  (gnus-set-default-directory)
+  (setq mode-line-process nil)
+  (use-local-map gnus-server-mode-map)
+  (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-mode-hooks 'gnus-server-mode-hook))
+
+(defun gnus-server-insert-server-line (name method)
+  (let* ((gnus-tmp-name name)
+         (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)")
+          ((eq (nth 1 elem) 'offline) "(offline)")
+          (t
+           (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
+                                 (gnus-agent-method-p method))
+                            " (agent)"
+                          ""))
+        (gnus-tmp-cloud (if (gnus-cloud-server-p gnus-tmp-name)
+                            " (cloud)"
+                          "")))
+    (beginning-of-line)
+    (gnus-add-text-properties
+     (point)
+     (prog1 (1+ (point))
+       ;; Insert the text.
+       (eval gnus-server-line-format-spec))
+     (list 'gnus-server (intern gnus-tmp-name)
+           'gnus-named-server (intern (gnus-method-to-server method t))))))
+
+(defun gnus-enter-server-buffer ()
+  "Set up the server buffer."
+  (gnus-server-setup-buffer)
+  (gnus-configure-windows 'server)
+  ;; Usually `gnus-configure-windows' will finish with the
+  ;; `gnus-server-buffer' selected as the current buffer, but not always (I
+  ;; bumped into it when starting from a dedicated *Group* frame, and
+  ;; gnus-configure-windows opened *Server* into its own dedicated frame).
+  (with-current-buffer (get-buffer gnus-server-buffer)
+    (gnus-server-prepare)))
+
+(defun gnus-server-setup-buffer ()
+  "Initialize the server buffer."
+  (unless (get-buffer gnus-server-buffer)
+    (with-current-buffer (gnus-get-buffer-create gnus-server-buffer)
+      (gnus-server-mode))))
+
+(defun gnus-server-prepare ()
+  (gnus-set-format 'server-mode)
+  (gnus-set-format 'server t)
+  (let ((alist gnus-server-alist)
+       (buffer-read-only nil)
+       done server op-ser)
+    (erase-buffer)
+    (setq gnus-inserted-opened-servers nil)
+    ;; First we do the real list of servers.
+    (while alist
+      (unless (member (cdar alist) done)
+       (push (cdar alist) done)
+       (setq server (pop alist))
+       (when (and server (car server) (cdr server))
+         (gnus-server-insert-server-line (car server) (cdr server))))
+      (when (member (cdar alist) done)
+       (pop alist)))
+    ;; Then we insert the list of servers that have been opened in
+    ;; this session.
+    (dolist (open gnus-opened-servers)
+      (when (and (not (member (car open) done))
+                ;; Just ignore ephemeral servers.
+                (not (gnus-method-ephemeral-p (car open))))
+       (push (car open) done)
+       (gnus-server-insert-server-line
+        (setq op-ser (format "%s:%s" (caar open) (nth 1 (car open))))
+        (car open))
+       (push (list op-ser (car open)) gnus-inserted-opened-servers))))
+  (goto-char (point-min))
+  (gnus-server-position-point))
+
+(defun gnus-server-server-name ()
+  (let ((server (get-text-property (point-at-bol) 'gnus-server)))
+    (and server (symbol-name server))))
+
+(defun gnus-server-named-server ()
+  "Return a server name that matches one of the names returned by
+`gnus-method-to-server'."
+  (let ((server (get-text-property (point-at-bol) 'gnus-named-server)))
+    (and server (symbol-name server))))
+
+(defalias 'gnus-server-position-point 'gnus-goto-colon)
+
+(defconst gnus-server-edit-buffer "*Gnus edit server*")
+
+(defun gnus-server-update-server (server)
+  (with-current-buffer gnus-server-buffer
+    (let* ((buffer-read-only nil)
+          (entry (assoc server gnus-server-alist))
+          (oentry (assoc (gnus-server-to-method server)
+                         gnus-opened-servers)))
+      (when entry
+       (gnus-dribble-enter
+        (concat "(gnus-server-set-info \"" server "\" '"
+                (gnus-prin1-to-string (cdr entry)) ")\n")
+        (concat "^(gnus-server-set-info \"" (regexp-quote server) "\"")))
+      (when (or entry oentry)
+       ;; Buffer may be narrowed.
+       (save-restriction
+         (widen)
+         (when (gnus-server-goto-server server)
+           (gnus-delete-line))
+         (if entry
+             (gnus-server-insert-server-line (car entry) (cdr entry))
+           (gnus-server-insert-server-line
+            (format "%s:%s" (caar oentry) (nth 1 (car oentry)))
+            (car oentry)))
+         (gnus-server-position-point))))))
+
+(defun gnus-server-set-info (server info)
+  ;; Enter a select method into the virtual server alist.
+  (when (and server info)
+    (gnus-dribble-enter
+     (concat "(gnus-server-set-info \"" server "\" '"
+            (gnus-prin1-to-string info) ")")
+     (concat "^(gnus-server-set-info \"" (regexp-quote server) "\""))
+    (let* ((server (nth 1 info))
+          (entry (assoc server gnus-server-alist))
+          (cached (assoc server gnus-server-method-cache)))
+      (if cached
+         (setq gnus-server-method-cache
+               (delq cached gnus-server-method-cache)))
+      (if entry
+         (progn
+           ;; Remove the server from `gnus-opened-servers' since
+           ;; it has never been opened with the new `info' yet.
+           (gnus-opened-servers-remove (cdr entry))
+           ;; Don't make a new Lisp object.
+           (setcar (cdr entry) (car info))
+           (setcdr (cdr entry) (cdr info)))
+       (setq gnus-server-alist
+             (nconc gnus-server-alist (list (cons server info))))))))
+
+;;; Interactive server functions.
+
+(defun gnus-server-kill-server (server)
+  "Kill the server on the current line."
+  (interactive (list (gnus-server-server-name)))
+  (unless (gnus-server-goto-server server)
+    (if server (error "No such server: %s" server)
+      (error "No server on the current line")))
+  (unless (assoc server gnus-server-alist)
+    (error "Read-only server %s" server))
+  (gnus-dribble-touch)
+  (let ((buffer-read-only nil))
+    (gnus-delete-line))
+  (push (assoc server gnus-server-alist) gnus-server-killed-servers)
+  (setq gnus-server-alist (delq (car gnus-server-killed-servers)
+                               gnus-server-alist))
+  (let ((groups (gnus-groups-from-server server)))
+    (when (and groups
+              (gnus-yes-or-no-p
+               (format "Kill all %s groups from this server? "
+                       (length groups))))
+      (dolist (group groups)
+       (setq gnus-newsrc-alist
+             (delq (assoc group gnus-newsrc-alist)
+                   gnus-newsrc-alist))
+       (when gnus-group-change-level-function
+         (funcall gnus-group-change-level-function
+                  group gnus-level-killed 3)))))
+  (gnus-server-position-point))
+
+(defun gnus-server-yank-server ()
+  "Yank the previously killed server."
+  (interactive)
+  (unless gnus-server-killed-servers
+    (error "No killed servers to be yanked"))
+  (let ((alist gnus-server-alist)
+       (server (gnus-server-server-name))
+       (killed (car gnus-server-killed-servers)))
+    (if (not server)
+       (setq gnus-server-alist (nconc gnus-server-alist (list killed)))
+      (if (string= server (caar gnus-server-alist))
+         (push killed gnus-server-alist)
+       (while (and (cdr alist)
+                   (not (string= server (caadr alist))))
+         (setq alist (cdr alist)))
+       (if alist
+           (setcdr alist (cons killed (cdr alist)))
+         (setq gnus-server-alist (list killed)))))
+    (gnus-server-update-server (car killed))
+    (setq gnus-server-killed-servers (cdr gnus-server-killed-servers))
+    (gnus-server-position-point)))
+
+(defun gnus-server-exit ()
+  "Return to the group buffer."
+  (interactive)
+  (gnus-run-hooks 'gnus-server-exit-hook)
+  (gnus-kill-buffer (current-buffer))
+  (gnus-configure-windows 'group t))
+
+(defun gnus-server-list-servers ()
+  "List all available servers."
+  (interactive)
+  (let ((cur (gnus-server-server-name)))
+    (gnus-server-prepare)
+    (if cur (gnus-server-goto-server cur)
+      (goto-char (point-max))
+      (forward-line -1))
+    (gnus-server-position-point)))
+
+(defun gnus-server-set-status (method status)
+  "Make METHOD have STATUS."
+  (let ((entry (assoc method gnus-opened-servers)))
+    (if entry
+       (setcar (cdr entry) status)
+      (push (list method status) gnus-opened-servers))))
+
+(defun gnus-opened-servers-remove (method)
+  "Remove METHOD from the list of opened servers."
+  (setq gnus-opened-servers (delq (assoc method gnus-opened-servers)
+                                 gnus-opened-servers)))
+
+(defun gnus-server-open-server (server)
+  "Force an open of SERVER."
+  (interactive (list (gnus-server-server-name)))
+  (let ((method (gnus-server-to-method server)))
+    (unless method
+      (error "No such server: %s" server))
+    (gnus-server-set-status method 'ok)
+    (prog1
+       (gnus-open-server method)
+      (gnus-server-update-server server)
+      (gnus-server-position-point))))
+
+(defun gnus-server-open-all-servers ()
+  "Open all servers."
+  (interactive)
+  (dolist (server gnus-inserted-opened-servers)
+    (gnus-server-open-server (car server))))
+
+(defun gnus-server-close-server (server)
+  "Close SERVER."
+  (interactive (list (gnus-server-server-name)))
+  (let ((method (gnus-server-to-method server)))
+    (unless method
+      (error "No such server: %s" server))
+    (gnus-server-set-status method 'closed)
+    (prog1
+       (gnus-close-server method)
+      (gnus-server-update-server server)
+      (gnus-server-position-point))))
+
+(defun gnus-server-offline-server (server)
+  "Set SERVER to offline."
+  (interactive (list (gnus-server-server-name)))
+  (let ((method (gnus-server-to-method server)))
+    (unless method
+      (error "No such server: %s" server))
+    (prog1
+       (gnus-close-server method)
+      (gnus-server-set-status method 'offline)
+      (gnus-server-update-server server)
+      (gnus-server-position-point))))
+
+(defun gnus-server-close-all-servers ()
+  "Close all servers."
+  (interactive)
+  (dolist (server gnus-inserted-opened-servers)
+    (gnus-server-close-server (car server)))
+  (dolist (server gnus-server-alist)
+    (gnus-server-close-server (car server))))
+
+(defun gnus-server-deny-server (server)
+  "Make sure SERVER will never be attempted opened."
+  (interactive (list (gnus-server-server-name)))
+  (let ((method (gnus-server-to-method server)))
+    (unless method
+      (error "No such server: %s" server))
+    (gnus-server-set-status method 'denied))
+  (gnus-server-update-server server)
+  (gnus-server-position-point)
+  t)
+
+(defun gnus-server-remove-denials ()
+  "Make all denied servers into closed servers."
+  (interactive)
+  (dolist (server gnus-opened-servers)
+    (when (eq (nth 1 server) 'denied)
+      (setcar (nthcdr 1 server) 'closed)))
+  (gnus-server-list-servers))
+
+(defun gnus-server-copy-server (from to)
+  "Copy a server definition to a new name."
+  (interactive
+   (list
+    (or (gnus-server-server-name)
+       (error "No server on the current line"))
+    (read-string "Copy to: ")))
+  (unless from
+    (error "No server on current line"))
+  (unless (and to (not (string= to "")))
+    (error "No name to copy to"))
+  (when (assoc to gnus-server-alist)
+    (error "%s already exists" to))
+  (unless (gnus-server-to-method from)
+    (error "%s: no such server" from))
+  (let ((to-entry (cons from (gnus-copy-sequence
+                             (gnus-server-to-method from)))))
+    (setcar to-entry to)
+    (setcar (nthcdr 2 to-entry) to)
+    (push to-entry gnus-server-killed-servers)
+    (gnus-server-yank-server)))
+
+(defun gnus-server-add-server (how where)
+  (interactive
+   (list (intern (gnus-completing-read "Server method"
+                                       (mapcar 'car gnus-valid-select-methods)
+                                       t))
+        (read-string "Server name: ")))
+  (when (assq where gnus-server-alist)
+    (error "Server with that name already defined"))
+  (push (list where how where) gnus-server-killed-servers)
+  (gnus-server-yank-server))
+
+(defun gnus-server-goto-server (server)
+  "Jump to a server line."
+  (interactive
+   (list (gnus-completing-read "Goto server" (mapcar 'car gnus-server-alist) t)))
+  (let ((to (text-property-any (point-min) (point-max)
+                              'gnus-server (intern server))))
+    (when to
+      (goto-char to)
+      (gnus-server-position-point))))
+
+(defun gnus-server-edit-server (server)
+  "Edit the server on the current line."
+  (interactive (list (gnus-server-server-name)))
+  (unless server
+    (error "No server on current line"))
+  (unless (assoc server gnus-server-alist)
+    (error "This server can't be edited"))
+  (let ((info (cdr (assoc server gnus-server-alist))))
+    (gnus-close-server info)
+    (gnus-edit-form
+     info "Editing the server."
+     `(lambda (form)
+       (gnus-server-set-info ,server form)
+       (gnus-server-list-servers)
+       (gnus-server-position-point))
+     'edit-server)))
+
+(defun gnus-server-show-server (server)
+  "Show the definition of the server on the current line."
+  (interactive (list (gnus-server-server-name)))
+  (unless server
+    (error "No server on current line"))
+  (let ((info (gnus-server-to-method server)))
+    (gnus-edit-form
+     info "Showing the server."
+     `(lambda (form)
+       (gnus-server-position-point))
+     'edit-server)))
+
+(defun gnus-server-scan-server (server)
+  "Request a scan from the current server."
+  (interactive (list (gnus-server-server-name)))
+  (let ((method (gnus-server-to-method server)))
+    (if (not (gnus-get-function method 'request-scan))
+       (error "Server %s can't scan" (car method))
+      (gnus-message 3 "Scanning %s..." server)
+      (gnus-request-scan nil method)
+      (gnus-message 3 "Scanning %s...done" server))))
+
+(defun gnus-server-read-server-in-server-buffer (server)
+  "Browse a server in server buffer."
+  (interactive (list (gnus-server-server-name)))
+  (let (gnus-server-browse-in-group-buffer)
+    (gnus-server-read-server server)))
+
+(defun gnus-server-read-server (server)
+  "Browse a server."
+  (interactive (list (gnus-server-server-name)))
+  (let ((buf (current-buffer)))
+    (prog1
+       (gnus-browse-foreign-server server buf)
+      (with-current-buffer buf
+       (gnus-server-update-server (gnus-server-server-name))
+       (gnus-server-position-point)))))
+
+(defun gnus-server-pick-server (e)
+  (interactive "e")
+  (mouse-set-point e)
+  (gnus-server-read-server (gnus-server-server-name)))
+
+\f
+;;;
+;;; Browse Server Mode
+;;;
+
+(defvar gnus-browse-menu-hook nil
+  "*Hook run after the creation of the browse mode menu.")
+
+(defcustom gnus-browse-subscribe-newsgroup-method
+  'gnus-subscribe-alphabetically
+  "Function(s) called when subscribing groups in the Browse Server Buffer
+A few pre-made functions are supplied: `gnus-subscribe-randomly'
+inserts new groups at the beginning of the list of groups;
+`gnus-subscribe-alphabetically' inserts new groups in strict
+alphabetic order; `gnus-subscribe-hierarchically' inserts new groups
+in hierarchical newsgroup order; `gnus-subscribe-interactively' asks
+for your decision; `gnus-subscribe-killed' kills all new groups;
+`gnus-subscribe-zombies' will make all new groups into zombies;
+`gnus-subscribe-topics' will enter groups into the topics that
+claim them."
+  :version "24.1"
+  :group 'gnus-server
+  :type '(radio (function-item gnus-subscribe-randomly)
+               (function-item gnus-subscribe-alphabetically)
+               (function-item gnus-subscribe-hierarchically)
+               (function-item gnus-subscribe-interactively)
+               (function-item gnus-subscribe-killed)
+               (function-item gnus-subscribe-zombies)
+               (function-item gnus-subscribe-topics)
+               function
+               (repeat function)))
+
+(defvar gnus-browse-mode-hook nil)
+(defvar gnus-browse-mode-map nil)
+(put 'gnus-browse-mode 'mode-class 'special)
+
+(unless gnus-browse-mode-map
+  (setq gnus-browse-mode-map (make-keymap))
+  (suppress-keymap gnus-browse-mode-map)
+
+  (gnus-define-keys
+      gnus-browse-mode-map
+    " " gnus-browse-read-group
+    "=" gnus-browse-select-group
+    "n" gnus-browse-next-group
+    "p" gnus-browse-prev-group
+    "\177" gnus-browse-prev-group
+    [delete] gnus-browse-prev-group
+    "N" gnus-browse-next-group
+    "P" gnus-browse-prev-group
+    "\M-n" gnus-browse-next-group
+    "\M-p" gnus-browse-prev-group
+    "\r" gnus-browse-select-group
+    "u" gnus-browse-unsubscribe-current-group
+    "l" gnus-browse-exit
+    "L" gnus-browse-exit
+    "q" gnus-browse-exit
+    "Q" gnus-browse-exit
+    "d" gnus-browse-describe-group
+    [delete] gnus-browse-delete-group
+    "\C-c\C-c" gnus-browse-exit
+    "?" gnus-browse-describe-briefly
+
+    "\C-c\C-i" gnus-info-find-node
+    "\C-c\C-b" gnus-bug))
+
+(defun gnus-browse-make-menu-bar ()
+  (gnus-turn-off-edit-menu 'browse)
+  (unless (boundp 'gnus-browse-menu)
+    (easy-menu-define
+     gnus-browse-menu gnus-browse-mode-map ""
+     '("Browse"
+       ["Subscribe" gnus-browse-unsubscribe-current-group t]
+       ["Read" gnus-browse-read-group t]
+       ["Select" gnus-browse-select-group t]
+       ["Describe" gnus-browse-describe-group t]
+       ["Next" gnus-browse-next-group t]
+       ["Prev" gnus-browse-prev-group t]
+       ["Exit" gnus-browse-exit t]))
+    (gnus-run-hooks 'gnus-browse-menu-hook)))
+
+(defvar gnus-browse-current-method nil)
+(defvar gnus-browse-return-buffer nil)
+
+(defvar gnus-browse-buffer "*Gnus Browse Server*")
+
+(defun gnus-browse-foreign-server (server &optional return-buffer)
+  "Browse the server SERVER."
+  (setq gnus-browse-current-method (gnus-server-to-method server))
+  (setq gnus-browse-return-buffer return-buffer)
+  (let* ((method gnus-browse-current-method)
+        (orig-select-method gnus-select-method)
+        (gnus-select-method method)
+        groups group)
+    (gnus-message 5 "Connecting to %s..." (nth 1 method))
+    (cond
+     ((not (gnus-check-server method))
+      (gnus-message
+       1 "Unable to contact server %s: %s" (nth 1 method)
+       (gnus-status-message method))
+      nil)
+     ((not
+       (prog2
+          (gnus-message 6 "Reading active file...")
+          (gnus-request-list method)
+        (gnus-message 6 "Reading active file...done")))
+      (gnus-message
+       1 "Couldn't request list: %s" (gnus-status-message method))
+      nil)
+     (t
+      (with-current-buffer nntp-server-buffer
+       (let ((cur (current-buffer)))
+         (goto-char (point-min))
+         (unless (or (null gnus-ignored-newsgroups)
+                     (string= gnus-ignored-newsgroups ""))
+           (delete-matching-lines gnus-ignored-newsgroups))
+         ;; We treat NNTP as a special case to avoid problems with
+         ;; garbage group names like `"foo' that appear in some badly
+         ;; managed active files. -jh.
+         (if (eq (car method) 'nntp)
+             (while (not (eobp))
+               (ignore-errors
+                 (push (cons
+                        (mm-string-as-unibyte
+                         (buffer-substring
+                          (point)
+                          (progn
+                            (skip-chars-forward "^ \t")
+                            (point))))
+                        (let ((last (read cur)))
+                          (cons (read cur) last)))
+                       groups))
+               (forward-line))
+           (while (not (eobp))
+             (ignore-errors
+               (push (cons
+                      (mm-string-as-unibyte
+                       (if (eq (char-after) ?\")
+                           (read cur)
+                         (let ((p (point)) (name ""))
+                           (skip-chars-forward "^ \t\\\\")
+                           (setq name (buffer-substring p (point)))
+                           (while (eq (char-after) ?\\)
+                             (setq p (1+ (point)))
+                             (forward-char 2)
+                             (skip-chars-forward "^ \t\\\\")
+                             (setq name (concat name (buffer-substring
+                                                      p (point)))))
+                           name)))
+                      (let ((last (read cur)))
+                        (cons (read cur) last)))
+                     groups))
+             (forward-line)))))
+      (setq groups (sort groups
+                        (lambda (l1 l2)
+                          (string< (car l1) (car l2)))))
+      (if gnus-server-browse-in-group-buffer
+         (let* ((gnus-select-method orig-select-method)
+                (gnus-group-listed-groups
+                 (mapcar (lambda (group)
+                           (let ((name
+                                  (gnus-group-prefixed-name
+                                   (car group) method)))
+                             (gnus-set-active name (cdr group))
+                             name))
+                         groups)))
+           (gnus-configure-windows 'group)
+           (funcall gnus-group-prepare-function
+                    gnus-level-killed 'ignore 1 'ignore))
+       (gnus-get-buffer-create gnus-browse-buffer)
+       (gnus-configure-windows 'browse)
+       (buffer-disable-undo)
+       (let ((buffer-read-only nil))
+         (erase-buffer))
+       (gnus-browse-mode)
+       (setq mode-line-buffer-identification
+             (list
+              (format
+               "Gnus: %%b {%s:%s}" (car method) (cadr method))))
+       (let ((buffer-read-only nil)
+             name
+             (prefix (let ((gnus-select-method orig-select-method))
+                       (gnus-group-prefixed-name "" method))))
+         (while (setq group (pop groups))
+           (gnus-add-text-properties
+            (point)
+            (prog1 (1+ (point))
+              (insert
+               (format "%c%7d: %s\n"
+                       (let ((level
+                              (if (string= prefix "")
+                                  (gnus-group-level (setq name (car group)))
+                                (gnus-group-level
+                                 (concat prefix (setq name (car group)))))))
+                         (cond
+                          ((<= level gnus-level-subscribed) ? )
+                          ((<= level gnus-level-unsubscribed) ?U)
+                          ((= level gnus-level-zombie) ?Z)
+                          (t ?K)))
+                       (max 0 (- (1+ (cddr group)) (cadr group)))
+                       ;; Don't decode if name is ASCII
+                       (if (and (fboundp 'detect-coding-string)
+                                (eq (detect-coding-string name t) 'undecided))
+                           name
+                         (mm-decode-coding-string
+                          name
+                          (inline (gnus-group-name-charset method name)))))))
+            (list 'gnus-group name)
+            )))
+       (switch-to-buffer (current-buffer)))
+      (goto-char (point-min))
+      (gnus-group-position-point)
+      (gnus-message 5 "Connecting to %s...done" (nth 1 method))
+      t))))
+
+(define-derived-mode gnus-browse-mode fundamental-mode "Browse Server"
+  "Major mode for browsing a foreign server.
+
+All normal editing commands are switched off.
+
+\\<gnus-browse-mode-map>
+The only things you can do in this buffer is
+
+1) `\\[gnus-browse-unsubscribe-current-group]' to subscribe to a group.
+The group will be inserted into the group buffer upon exit from this
+buffer.
+
+2) `\\[gnus-browse-read-group]' to read a group ephemerally.
+
+3) `\\[gnus-browse-exit]' to return to the group buffer."
+  (when (gnus-visual-p 'browse-menu 'menu)
+    (gnus-browse-make-menu-bar))
+  (gnus-simplify-mode-line)
+  (setq mode-line-process nil)
+  (buffer-disable-undo)
+  (setq truncate-lines t)
+  (gnus-set-default-directory)
+  (setq buffer-read-only t))
+
+(defun gnus-browse-read-group (&optional no-article number)
+  "Enter the group at the current line.
+If NUMBER, fetch this number of articles."
+  (interactive "P")
+  (let ((group (gnus-browse-group-name)))
+    (if (or (not (gnus-get-info group))
+           (gnus-ephemeral-group-p group))
+       (unless (gnus-group-read-ephemeral-group
+                group gnus-browse-current-method nil
+                (cons (current-buffer) 'browse)
+                nil nil nil number)
+         (error "Couldn't enter %s" group))
+      (unless (gnus-group-read-group nil no-article group)
+       (error "Couldn't enter %s" group)))))
+
+(defun gnus-browse-select-group (&optional number)
+  "Select the current group.
+If NUMBER, fetch this number of articles."
+  (interactive "P")
+  (gnus-browse-read-group 'no number))
+
+(defun gnus-browse-next-group (n)
+  "Go to the next group."
+  (interactive "p")
+  (prog1
+      (forward-line n)
+    (gnus-group-position-point)))
+
+(defun gnus-browse-prev-group (n)
+  "Go to the next group."
+  (interactive "p")
+  (gnus-browse-next-group (- n)))
+
+(defun gnus-browse-unsubscribe-current-group (arg)
+  "(Un)subscribe to the next ARG groups.
+The variable `gnus-browse-subscribe-newsgroup-method' determines
+how new groups will be entered into the group buffer."
+  (interactive "p")
+  (when (eobp)
+    (error "No group at current line"))
+  (let ((ward (if (< arg 0) -1 1))
+       (arg (abs arg)))
+    (while (and (> arg 0)
+               (not (eobp))
+               (gnus-browse-unsubscribe-group)
+               (zerop (gnus-browse-next-group ward)))
+      (decf arg))
+    (gnus-group-position-point)
+    (when (/= 0 arg)
+      (gnus-message 7 "No more newsgroups"))
+    arg))
+
+(defun gnus-browse-group-name ()
+  (save-excursion
+    (beginning-of-line)
+    (let ((name (get-text-property (point) 'gnus-group)))
+      (when (re-search-forward ": \\(.*\\)$" (point-at-eol) t)
+       (concat (gnus-method-to-server-name gnus-browse-current-method) ":"
+               (or name
+                   (match-string-no-properties 1)))))))
+
+(defun gnus-browse-describe-group (group)
+  "Describe the current group."
+  (interactive (list (gnus-browse-group-name)))
+  (gnus-group-describe-group nil group))
+
+(defun gnus-browse-delete-group (group force)
+  "Delete the current group.  Only meaningful with editable groups.
+If FORCE (the prefix) is non-nil, all the articles in the group will
+be deleted.  This is \"deleted\" as in \"removed forever from the face
+of the Earth\".  There is no undo.  The user will be prompted before
+doing the deletion."
+  (interactive (list (gnus-browse-group-name)
+                    current-prefix-arg))
+  (gnus-group-delete-group group force))
+
+(defun gnus-browse-unsubscribe-group ()
+  "Toggle subscription of the current group in the browse buffer."
+  (let ((sub nil)
+       (buffer-read-only nil)
+       group)
+    (save-excursion
+      (beginning-of-line)
+      ;; If this group it killed, then we want to subscribe it.
+      (unless (eq (char-after) ? )
+       (setq sub t))
+      (setq group (gnus-browse-group-name))
+      (when (gnus-server-equal gnus-browse-current-method "native")
+       (setq group (gnus-group-real-name group)))
+      (if sub
+         (progn
+           ;; Make sure the group has been properly removed before we
+           ;; subscribe to it.
+           (if (gnus-ephemeral-group-p group)
+               (gnus-kill-ephemeral-group group))
+           (let ((entry (gnus-group-entry group)))
+             (if entry
+                 ;; Just change the subscription level if it is an
+                 ;; unsubscribed group.
+                 (gnus-group-change-level entry
+                                          gnus-level-default-subscribed)
+               ;; If it is a killed group or a zombie, feed it to the
+               ;; mechanism for new group subscription.
+               (gnus-call-subscribe-functions
+                gnus-browse-subscribe-newsgroup-method
+                group)
+               (gnus-request-update-group-status group 'subscribe)))
+           (delete-char 1)
+           (insert (let ((lvl (gnus-group-level group)))
+                     (cond
+                      ((< lvl gnus-level-unsubscribed) ? )
+                      ((< lvl gnus-level-zombie) ?U)
+                      ((< lvl gnus-level-killed) ?Z)
+                      (t ?K)))))
+       (gnus-group-change-level
+        group gnus-level-unsubscribed gnus-level-default-subscribed)
+       (delete-char 1)
+       (insert ?U)))
+    t))
+
+(defun gnus-browse-exit ()
+  "Quit browsing and return to the group buffer."
+  (interactive)
+  (when (derived-mode-p 'gnus-browse-mode)
+    (gnus-kill-buffer (current-buffer)))
+  ;; Insert the newly subscribed groups in the group buffer.
+  (with-current-buffer gnus-group-buffer
+    (gnus-group-list-groups nil))
+  (if gnus-browse-return-buffer
+      (gnus-configure-windows 'server 'force)
+    (gnus-configure-windows 'group 'force)))
+
+(defun gnus-browse-describe-briefly ()
+  "Give a one line description of the group mode commands."
+  (interactive)
+  (gnus-message 6 "%s"
+               (substitute-command-keys "\\<gnus-browse-mode-map>\\[gnus-group-next-group]:Forward  \\[gnus-group-prev-group]:Backward  \\[gnus-browse-exit]:Exit  \\[gnus-info-find-node]:Run Info  \\[gnus-browse-describe-briefly]:This help")))
+
+(defun gnus-server-regenerate-server ()
+  "Issue a command to the server to regenerate all its data structures."
+  (interactive)
+  (let ((server (gnus-server-server-name)))
+    (unless server
+      (error "No server on the current line"))
+    (condition-case ()
+       (gnus-get-function (gnus-server-to-method server)
+                          'request-regenerate)
+      (error
+       (error "This back end doesn't support regeneration")))
+    (gnus-message 5 "Requesting regeneration of %s..." server)
+    (unless (gnus-open-server server)
+      (error "Couldn't open server"))
+    (if (gnus-request-regenerate server)
+       (gnus-message 5 "Requesting regeneration of %s...done" server)
+      (gnus-message 5 "Couldn't regenerate %s" server))))
+
+
+;;;
+;;; Server compaction. -- dvl
+;;;
+
+;; #### FIXME: this function currently fails to update the Group buffer's
+;; #### appearance.
+(defun gnus-server-compact-server ()
+  "Issue a command to the server to compact all its groups.
+
+Note: currently only implemented in nnml."
+  (interactive)
+  (let ((server (gnus-server-server-name)))
+    (unless server
+      (error "No server on the current line"))
+    (condition-case ()
+       (gnus-get-function (gnus-server-to-method server)
+                          'request-compact)
+      (error
+       (error "This back end doesn't support compaction")))
+    (gnus-message 5 "\
+Requesting compaction of %s... (this may take a long time)"
+                 server)
+    (unless (gnus-open-server server)
+      (error "Couldn't open server"))
+    (if (not (gnus-request-compact server))
+       (gnus-message 5 "Couldn't compact %s" server)
+      (gnus-message 5 "Requesting compaction of %s...done" server)
+      ;; Invalidate the original article buffer which might be out of date.
+      ;; #### NOTE: Yes, this might be a bit rude, but since compaction
+      ;; #### will not happen very often, I think this is acceptable.
+      (let ((original (get-buffer gnus-original-article-buffer)))
+       (and original (gnus-kill-buffer original))))))
+
+(defun gnus-server-toggle-cloud-server ()
+  "Make the server under point be replicated in the Emacs Cloud."
+  (interactive)
+  (let ((server (gnus-server-server-name)))
+    (unless server
+      (error "No server on the current line"))
+
+    (unless (gnus-method-option-p server 'cloud)
+      (error "The server under point doesn't support cloudiness"))
+
+    (if (gnus-cloud-server-p server)
+       (setq gnus-cloud-covered-servers
+             (delete server gnus-cloud-covered-servers))
+      (push server gnus-cloud-covered-servers))
+
+    (gnus-server-update-server server)
+    (gnus-message 1 (if (gnus-cloud-server-p server)
+                       "Replication of %s in the cloud will start"
+                     "Replication of %s in the cloud will stop")
+                 server)))
+
+(provide 'gnus-srvr)
+
+;;; gnus-srvr.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-start.el b/xemacs-packages/gnus/lisp/gnus-start.el
new file mode 100644 (file)
index 0000000..52a53a7
--- /dev/null
@@ -0,0 +1,3239 @@
+;;; gnus-start.el --- startup functions for Gnus
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'gnus)
+(require 'gnus-win)
+(require 'gnus-int)
+(require 'gnus-spec)
+(require 'gnus-range)
+(require 'gnus-util)
+(ignore-errors (require 'gnus-cloud))
+(autoload 'message-make-date "message")
+(autoload 'gnus-agent-read-servers-validate "gnus-agent")
+(autoload 'gnus-agent-save-local "gnus-agent")
+(autoload 'gnus-agent-possibly-alter-active "gnus-agent")
+
+(eval-when-compile
+  (require 'cl))
+
+(defvar gnus-agent-covered-methods)
+(defvar gnus-agent-file-loading-local)
+(defvar gnus-agent-file-loading-cache)
+
+(defcustom gnus-startup-file (nnheader-concat gnus-home-directory ".newsrc")
+  "Your `.newsrc' file.
+`.newsrc-SERVER' will be used instead if that exists."
+  :group 'gnus-start
+  :type 'file)
+
+(defcustom gnus-backup-startup-file 'never
+  "Control use of version numbers for backups of `gnus-startup-file'.
+This variable takes the same values as the `version-control'
+variable."
+  :version "22.1"
+  :group 'gnus-start
+  :type '(choice (const :tag "Never" never)
+                (const :tag "If existing" nil)
+                (other :tag "Always" t)))
+
+(defcustom gnus-save-startup-file-via-temp-buffer t
+  "Whether to write the startup file contents to a buffer then save
+the buffer or write directly to the file.  The buffer is faster
+because all of the contents are written at once.  The direct write
+uses considerably less memory."
+  :version "22.1"
+  :group 'gnus-start
+  :type '(choice (const :tag "Write via buffer" t)
+                 (const :tag "Write directly to file" nil)))
+
+(defcustom gnus-init-file (nnheader-concat gnus-home-directory ".gnus")
+  "Your Gnus Emacs-Lisp startup file name.
+If a file with the `.el' or `.elc' suffixes exists, it will be read instead."
+  :group 'gnus-start
+  :type 'file)
+
+(defcustom gnus-site-init-file
+  (condition-case nil
+      (concat (file-name-directory
+              (directory-file-name installation-directory))
+             "site-lisp/gnus-init")
+    (error nil))
+  "The site-wide Gnus Emacs-Lisp startup file name, or nil if none.
+If a file with the `.el' or `.elc' suffixes exists, it will be read instead."
+  :group 'gnus-start
+  :type '(choice file (const nil)))
+
+(defcustom gnus-use-dribble-file t
+  "*Non-nil means that Gnus will use a dribble file to store user updates.
+If Emacs should crash without saving the .newsrc files, complete
+information can be restored from the dribble file."
+  :group 'gnus-dribble-file
+  :type 'boolean)
+
+(defcustom gnus-dribble-directory nil
+  "*The directory where dribble files will be saved.
+If this variable is nil, the directory where the .newsrc files are
+saved will be used."
+  :group 'gnus-dribble-file
+  :type '(choice directory (const nil)))
+
+(defcustom gnus-check-new-newsgroups 'ask-server
+  "*Non-nil means that Gnus will run `gnus-find-new-newsgroups' at startup.
+This normally finds new newsgroups by comparing the active groups the
+servers have already reported with those Gnus already knows, either alive
+or killed.
+
+When any of the following are true, `gnus-find-new-newsgroups' will instead
+ask the servers (primary, secondary, and archive servers) to list new
+groups since the last time it checked:
+  1. This variable is `ask-server'.
+  2. This variable is a list of select methods (see below).
+  3. Option `gnus-read-active-file' is nil or `some'.
+  4. A prefix argument is given to `gnus-find-new-newsgroups' interactively.
+
+Thus, if this variable is `ask-server' or a list of select methods or
+`gnus-read-active-file' is nil or `some', then the killed list is no
+longer necessary, so you could safely set `gnus-save-killed-list' to nil.
+
+This variable can be a list of select methods which Gnus will query with
+the `ask-server' method in addition to the primary, secondary, and archive
+servers.
+
+E.g.:
+  (setq gnus-check-new-newsgroups
+       \\='((nntp \"some.server\") (nntp \"other.server\")))
+
+If this variable is nil, then you have to tell Gnus explicitly to
+check for new newsgroups with \\<gnus-group-mode-map>\\[gnus-find-new-newsgroups]."
+  :group 'gnus-start
+  :type '(choice (const :tag "no" nil)
+                (const :tag "by brute force" t)
+                (const :tag "ask servers" ask-server)
+                (repeat :menu-tag "ask additional servers"
+                        :tag "ask additional servers"
+                        :value ((nntp ""))
+                        (sexp :format "%v"))))
+
+(defcustom gnus-check-bogus-newsgroups nil
+  "*Non-nil means that Gnus will check and remove bogus newsgroup at startup.
+If this variable is nil, then you have to tell Gnus explicitly to
+check for bogus newsgroups with \\<gnus-group-mode-map>\\[gnus-group-check-bogus-groups]."
+  :group 'gnus-start-server
+  :type 'boolean)
+
+(defcustom gnus-read-active-file 'some
+  "*Non-nil means that Gnus will read the entire active file at startup.
+If this variable is nil, Gnus will only know about the groups in your
+`.newsrc' file.
+
+If this variable is `some', Gnus will try to only read the relevant
+parts of the active file from the server.  Not all servers support
+this, and it might be quite slow with other servers, but this should
+generally be faster than both the t and nil value.
+
+If you set this variable to nil or `some', you probably still want to
+be told about new newsgroups that arrive.  To do that, set
+`gnus-check-new-newsgroups' to `ask-server'.  This may not work
+properly with all servers."
+  :group 'gnus-start-server
+  :type '(choice (const nil)
+                (const some)
+                (const t)))
+
+(defconst gnus-level-subscribed 5
+  "Groups with levels less than or equal to this variable are subscribed.")
+
+(defconst gnus-level-unsubscribed 7
+  "Groups with levels less than or equal to this variable are unsubscribed.
+
+Groups with levels less than `gnus-level-subscribed', which
+should be less than this variable, are subscribed.  Groups with
+levels from `gnus-level-subscribed' (exclusive) upto this
+variable (inclusive) are unsubscribed.  See also
+`gnus-level-zombie', `gnus-level-killed' and the Info node `(gnus)Group
+Levels' for details.")
+
+(defconst gnus-level-zombie 8
+  "Groups with this level are zombie groups.")
+
+(defconst gnus-level-killed 9
+  "Groups with this level are killed.")
+
+(defcustom gnus-level-default-subscribed 3
+  "*New subscribed groups will be subscribed at this level."
+  :group 'gnus-group-levels
+  :type 'integer)
+
+(defcustom gnus-level-default-unsubscribed 6
+  "*New unsubscribed groups will be unsubscribed at this level."
+  :group 'gnus-group-levels
+  :type 'integer)
+
+(defcustom gnus-activate-level (1+ gnus-level-subscribed)
+  "*Groups higher than this level won't be activated on startup.
+Setting this variable to something low might save lots of time when
+you have many groups that you aren't interested in."
+  :group 'gnus-group-levels
+  :type 'integer)
+
+(defcustom gnus-activate-foreign-newsgroups 4
+  "*If nil, Gnus will not check foreign newsgroups at startup.
+If it is non-nil, it should be a number between one and nine.  Foreign
+newsgroups that have a level lower or equal to this number will be
+activated on startup.  For instance, if you want to active all
+subscribed newsgroups, but not the rest, you'd set this variable to
+`gnus-level-subscribed'.
+
+If you subscribe to lots of newsgroups from different servers, startup
+might take a while.  By setting this variable to nil, you'll save time,
+but you won't be told how many unread articles there are in the
+groups."
+  :group 'gnus-group-levels
+  :type '(choice integer
+                (const :tag "none" nil)))
+
+(defcustom gnus-read-newsrc-file t
+  "*Non-nil means that Gnus will read the `.newsrc' file.
+Gnus always reads its own startup file, which is called
+\".newsrc.eld\".  The file called \".newsrc\" is in a format that can
+be readily understood by other newsreaders.  If you don't plan on
+using other newsreaders, set this variable to nil to save some time on
+entry."
+  :version "21.1"
+  :group 'gnus-newsrc
+  :type 'boolean)
+
+(defcustom gnus-save-newsrc-file t
+  "*Non-nil means that Gnus will save the `.newsrc' file.
+Gnus always saves its own startup file, which is called
+\".newsrc.eld\".  The file called \".newsrc\" is in a format that can
+be readily understood by other newsreaders.  If you don't plan on
+using other newsreaders, set this variable to nil to save some time on
+exit."
+  :group 'gnus-newsrc
+  :type 'boolean)
+
+(defcustom gnus-save-killed-list t
+  "*If non-nil, save the list of killed groups to the startup file.
+If you set this variable to nil, you'll save both time (when starting
+and quitting) and space (both memory and disk), but it will also mean
+that Gnus has no record of which groups are new and which are old, so
+the automatic new newsgroups subscription methods become meaningless.
+
+You should always set `gnus-check-new-newsgroups' to `ask-server' or
+nil if you set this variable to nil.
+
+This variable can also be a regexp.  In that case, all groups that do
+not match this regexp will be removed before saving the list."
+  :group 'gnus-newsrc
+  :type '(radio (sexp :format "Non-nil\n"
+                     :match (lambda (widget value)
+                              (and value (not (stringp value))))
+                     :value t)
+               (const nil)
+               regexp))
+
+(defcustom gnus-ignored-newsgroups
+  (mapconcat 'identity
+            '("^to\\."                 ; not "real" groups
+              "^[0-9. \t]+\\( \\|$\\)" ; all digits in name
+              "^[\"][\"#'()]"  ; bogus characters
+              )
+            "\\|")
+  "*A regexp to match uninteresting newsgroups in the active file.
+Any lines in the active file matching this regular expression are
+removed from the newsgroup list before anything else is done to it,
+thus making them effectively non-existent."
+  :group 'gnus-group-new
+  :type 'regexp)
+
+(defcustom gnus-subscribe-newsgroup-method 'gnus-subscribe-zombies
+  "*Function(s) called with a group name when new group is detected.
+A few pre-made functions are supplied: `gnus-subscribe-randomly'
+inserts new groups at the beginning of the list of groups;
+`gnus-subscribe-alphabetically' inserts new groups in strict
+alphabetic order; `gnus-subscribe-hierarchically' inserts new groups
+in hierarchical newsgroup order; `gnus-subscribe-interactively' asks
+for your decision; `gnus-subscribe-killed' kills all new groups;
+`gnus-subscribe-zombies' will make all new groups into zombies;
+`gnus-subscribe-topics' will enter groups into the topics that
+claim them."
+  :group 'gnus-group-new
+  :type '(radio (function-item gnus-subscribe-randomly)
+               (function-item gnus-subscribe-alphabetically)
+               (function-item gnus-subscribe-hierarchically)
+               (function-item gnus-subscribe-interactively)
+               (function-item gnus-subscribe-killed)
+               (function-item gnus-subscribe-zombies)
+               (function-item gnus-subscribe-topics)
+               function
+               (repeat function)))
+
+(define-obsolete-variable-alias 'gnus-subscribe-newsgroup-hooks
+  'gnus-subscribe-newsgroup-functions "24.3")
+(defcustom gnus-subscribe-newsgroup-functions nil
+  "*Hooks run after you subscribe to a new group.
+The hooks will be called with new group's name as argument."
+  :version "22.1"
+  :group 'gnus-group-new
+  :type 'hook)
+
+(defcustom gnus-subscribe-options-newsgroup-method
+  'gnus-subscribe-alphabetically
+  "*Function(s) called to subscribe newsgroups mentioned on \"options -n\" lines.
+If, for instance, you want to subscribe to all newsgroups in the
+\"no\" and \"alt\" hierarchies, you'd put the following in your
+.newsrc file:
+
+options -n no.all alt.all
+
+Gnus will then subscribe all new newsgroups in these hierarchies
+with the subscription method in this variable."
+  :group 'gnus-group-new
+  :type '(radio (function-item gnus-subscribe-randomly)
+               (function-item gnus-subscribe-alphabetically)
+               (function-item gnus-subscribe-hierarchically)
+               (function-item gnus-subscribe-interactively)
+               (function-item gnus-subscribe-killed)
+               (function-item gnus-subscribe-zombies)
+               (function-item gnus-subscribe-topics)
+               function
+               (repeat function)))
+
+(defcustom gnus-subscribe-hierarchical-interactive nil
+  "*If non-nil, Gnus will offer to subscribe hierarchically.
+When a new hierarchy appears, Gnus will ask the user:
+
+'alt.binaries': Do you want to subscribe to this hierarchy? ([d]ys):
+
+If the user pressed `d', Gnus will descend the hierarchy, `y' will
+subscribe to all newsgroups in the hierarchy and `s' will skip this
+hierarchy in its entirety."
+  :group 'gnus-group-new
+  :type 'boolean)
+
+(defcustom gnus-auto-subscribed-categories '(mail post-mail)
+  "*New groups from methods of these categories will be subscribed automatically.
+Note that this variable only deals with new groups.  It has no
+effect whatsoever on old groups.  The default is to automatically
+subscribe all groups from mail-like backends."
+  :version "24.1"
+  :group 'gnus-group-new
+  :type '(repeat symbol))
+
+(defcustom gnus-auto-subscribed-groups
+  "^nnml\\|^nnfolder\\|^nnmbox\\|^nnmh\\|^nnbabyl\\|^nnmaildir\\|^nnimap"
+  "*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.
+
+New groups that match this regexp will not be handled by
+`gnus-subscribe-newsgroup-method'.  Instead, they will
+be subscribed using `gnus-subscribe-options-newsgroup-method'."
+  :group 'gnus-group-new
+  :type 'regexp)
+
+(defcustom gnus-options-subscribe nil
+  "*All new groups matching this regexp will be subscribed unconditionally.
+Note that this variable deals only with new newsgroups.  This variable
+does not affect old newsgroups.
+
+New groups that match this regexp will not be handled by
+`gnus-subscribe-newsgroup-method'.  Instead, they will
+be subscribed using `gnus-subscribe-options-newsgroup-method'."
+  :group 'gnus-group-new
+  :type '(choice regexp
+                (const :tag "none" nil)))
+
+(defcustom gnus-options-not-subscribe nil
+  "*All new groups matching this regexp will be ignored.
+Note that this variable deals only with new newsgroups.  This variable
+does not affect old (already subscribed) newsgroups."
+  :group 'gnus-group-new
+  :type '(choice regexp
+                (const :tag "none" nil)))
+
+(defcustom gnus-modtime-botch nil
+  "*Non-nil means .newsrc should be deleted prior to save.
+Its use is due to the bogus appearance that .newsrc was modified on
+disc."
+  :group 'gnus-newsrc
+  :type 'boolean)
+
+(defcustom gnus-check-bogus-groups-hook nil
+  "A hook run after removing bogus groups."
+  :group 'gnus-start-server
+  :type 'hook)
+
+(defcustom gnus-startup-hook nil
+  "A hook called at startup.
+This hook is called after Gnus is connected to the NNTP server."
+  :group 'gnus-start
+  :type 'hook)
+
+(defcustom gnus-before-startup-hook nil
+  "A hook called before startup.
+This hook is called as the first thing when Gnus is started.
+See also `gnus-before-resume-hook'."
+  :group 'gnus-start
+  :type 'hook)
+
+(defcustom gnus-before-resume-hook nil
+  "A hook called before resuming Gnus after suspend.
+This hook is called as the first thing when Gnus is resumed after a suspend.
+See also `gnus-before-startup-hook'."
+  :version "24.4"
+  :group 'gnus-start
+  :type 'hook)
+
+(defcustom gnus-started-hook nil
+  "A hook called as the last thing after startup."
+  :group 'gnus-start
+  :type 'hook)
+
+(defcustom gnus-setup-news-hook nil
+  "A hook after reading the .newsrc file, but before generating the buffer."
+  :group 'gnus-start
+  :type 'hook)
+
+(defcustom gnus-get-top-new-news-hook nil
+  "A hook run just before Gnus checks for new news globally."
+  :version "22.1"
+  :group 'gnus-group-new
+  :type 'hook)
+
+(defcustom gnus-get-new-news-hook nil
+  "A hook run just before Gnus checks for new news."
+  :group 'gnus-group-new
+  :type 'hook)
+
+(defcustom gnus-after-getting-new-news-hook
+  '(gnus-display-time-event-handler)
+  "*A hook run after Gnus checks for new news when Gnus is already running."
+  :version "24.1"
+  :group 'gnus-group-new
+  :type 'hook)
+
+(defcustom gnus-read-newsrc-el-hook nil
+  "A hook called after reading the newsrc.eld? file."
+  :group 'gnus-newsrc
+  :type 'hook)
+
+(defcustom gnus-save-newsrc-hook nil
+  "A hook called before saving any of the newsrc files."
+  :group 'gnus-newsrc
+  :type 'hook)
+
+(defcustom gnus-save-quick-newsrc-hook nil
+  "A hook called just before saving the quick newsrc file.
+Can be used to turn version control on or off."
+  :group 'gnus-newsrc
+  :type 'hook)
+
+(defcustom gnus-save-standard-newsrc-hook nil
+  "A hook called just before saving the standard newsrc file.
+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
+
+;; Fixme: deal with old emacs-mule when mm-universal-coding-system is
+;; utf-8-emacs.
+(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)
+(defvar gnus-dribble-buffer nil)
+(defvar gnus-newsrc-options nil
+  "Options line in the .newsrc file.")
+
+(defvar gnus-newsrc-options-n nil
+  "List of regexps representing groups to be subscribed/ignored unconditionally.")
+
+(defvar gnus-newsrc-last-checked-date nil
+  "Date Gnus last asked server for new newsgroups.")
+
+(defvar gnus-current-startup-file nil
+  "Startup file for the current host.")
+
+;; Byte-compiler warning.
+(defvar gnus-group-line-format)
+
+;; Suggested by Brian Edmonds <edmonds@cs.ubc.ca>.
+(defvar gnus-init-inhibit nil)
+(defun gnus-read-init-file (&optional inhibit-next)
+  ;; Don't load .gnus if the -q option was used.
+  (when init-file-user
+    (if gnus-init-inhibit
+       (setq gnus-init-inhibit nil)
+      (setq gnus-init-inhibit inhibit-next)
+      (dolist (file (list gnus-site-init-file gnus-init-file))
+       (when (and file
+                  (locate-library file))
+         (if (or debug-on-error debug-on-quit)
+             (load file nil t)
+           (condition-case var
+               (load file nil t)
+             (error
+              (error "Error in %s: %s" file (cadr var))))))))))
+
+;; For subscribing new newsgroup
+
+(defun gnus-subscribe-hierarchical-interactive (groups)
+  (let ((groups (sort groups 'string<))
+       prefixes prefix start ans group starts real-group)
+    (while groups
+      (setq prefixes (list "^"))
+      (while (and groups prefixes)
+       (while (not (string-match (car prefixes)
+                                 (gnus-group-real-name (car groups))))
+         (setq prefixes (cdr prefixes)))
+       (setq prefix (car prefixes))
+       (setq start (1- (length prefix)))
+       (if (and (string-match "[^\\.]\\." (gnus-group-real-name (car groups))
+                              start)
+                (cdr groups)
+                (setq prefix
+                      (concat "^" (substring
+                                   (gnus-group-real-name (car groups))
+                                   0 (match-end 0))))
+                (string-match prefix (gnus-group-real-name (cadr groups))))
+           (progn
+             (push prefix prefixes)
+             (message "Descend hierarchy %s? ([y]nsq): "
+                      (substring prefix 1 (1- (length prefix))))
+             (while (not (memq (setq ans (read-char-exclusive))
+                               '(?y ?\n ?\r ?n ?s ?q)))
+               (ding)
+               (message "Descend hierarchy %s? ([y]nsq): "
+                        (substring prefix 1 (1- (length prefix)))))
+             (cond ((= ans ?n)
+                    (while (and groups
+                                (setq group (car groups)
+                                      real-group (gnus-group-real-name group))
+                                (string-match prefix real-group))
+                      (push group gnus-killed-list)
+                      (gnus-sethash group group gnus-killed-hashtb)
+                      (setq groups (cdr groups)))
+                    (setq starts (cdr starts)))
+                   ((= ans ?s)
+                    (while (and groups
+                                (setq group (car groups)
+                                      real-group (gnus-group-real-name group))
+                                (string-match prefix real-group))
+                      (gnus-sethash group group gnus-killed-hashtb)
+                      (gnus-subscribe-alphabetically (car groups))
+                      (setq groups (cdr groups)))
+                    (setq starts (cdr starts)))
+                   ((= ans ?q)
+                    (while groups
+                      (setq group (car groups))
+                      (push group gnus-killed-list)
+                      (gnus-sethash group group gnus-killed-hashtb)
+                      (setq groups (cdr groups))))
+                   (t nil)))
+         (message "Subscribe %s? ([n]yq)" (car groups))
+         (while (not (memq (setq ans (read-char-exclusive))
+                           '(?y ?\n ?\r ?q ?n)))
+           (ding)
+           (message "Subscribe %s? ([n]yq)" (car groups)))
+         (setq group (car groups))
+         (cond ((= ans ?y)
+                (gnus-subscribe-alphabetically (car groups))
+                (gnus-sethash group group gnus-killed-hashtb))
+               ((= ans ?q)
+                (while groups
+                  (setq group (car groups))
+                  (push group gnus-killed-list)
+                  (gnus-sethash group group gnus-killed-hashtb)
+                  (setq groups (cdr groups))))
+               (t
+                (push group gnus-killed-list)
+                (gnus-sethash group group gnus-killed-hashtb)))
+         (setq groups (cdr groups)))))))
+
+(defun gnus-subscribe-randomly (newsgroup)
+  "Subscribe new NEWSGROUP by making it the first newsgroup."
+  (gnus-subscribe-newsgroup newsgroup))
+
+(defun gnus-subscribe-alphabetically (newgroup)
+  "Subscribe new NEWGROUP and insert it in alphabetical order."
+  (let ((groups (cdr gnus-newsrc-alist))
+       before)
+    (while (and (not before) groups)
+      (if (string< newgroup (caar groups))
+         (setq before (caar groups))
+       (setq groups (cdr groups))))
+    (gnus-subscribe-newsgroup newgroup before)))
+
+(defun gnus-subscribe-hierarchically (newgroup)
+  "Subscribe new NEWGROUP and insert it in hierarchical newsgroup order."
+  ;; Basic ideas by mike-w@cs.aukuni.ac.nz (Mike Williams)
+  (with-current-buffer (nnheader-find-file-noselect gnus-current-startup-file)
+    (prog1
+       (let ((groupkey newgroup) before)
+         (while (and (not before) groupkey)
+           (goto-char (point-min))
+           (let ((groupkey-re
+                  (concat "^\\(" (regexp-quote groupkey) ".*\\)[!:]")))
+             (while (and (re-search-forward groupkey-re nil t)
+                         (progn
+                           (setq before (match-string 1))
+                           (string< before newgroup)))))
+           ;; Remove tail of newsgroup name (eg. a.b.c -> a.b)
+           (setq groupkey
+                 (when (string-match "^\\(.*\\)\\.[^.]+$" groupkey)
+                   (substring groupkey (match-beginning 1) (match-end 1)))))
+         (gnus-subscribe-newsgroup newgroup before))
+      (kill-buffer (current-buffer)))))
+
+(defun gnus-subscribe-interactively (group)
+  "Subscribe the new GROUP interactively.
+It is inserted in hierarchical newsgroup order if subscribed.  If not,
+it is killed."
+  (if (gnus-y-or-n-p (format "Subscribe new newsgroup %s? " group))
+      (gnus-subscribe-hierarchically group)
+    (push group gnus-killed-list)))
+
+(defun gnus-subscribe-zombies (group)
+  "Make the new GROUP into a zombie group."
+  (push group gnus-zombie-list))
+
+(defun gnus-subscribe-killed (group)
+  "Make the new GROUP a killed group."
+  (push group gnus-killed-list))
+
+(defun gnus-subscribe-newsgroup (newsgroup &optional next)
+  "Subscribe new NEWSGROUP.
+If NEXT is non-nil, it is inserted before NEXT.  Otherwise it is made
+the first newsgroup."
+  (save-excursion
+    (goto-char (point-min))
+    ;; We subscribe the group by changing its level to `subscribed'.
+    (gnus-group-change-level
+     newsgroup gnus-level-default-subscribed
+     gnus-level-killed (gnus-group-entry (or next "dummy.group")))
+    (gnus-request-update-group-status newsgroup 'subscribe)
+    (gnus-message 5 "Subscribe newsgroup: %s" newsgroup)
+    (run-hook-with-args 'gnus-subscribe-newsgroup-functions newsgroup)
+    t))
+
+(defun gnus-read-active-file-p ()
+  "Say whether the active file has been read from `gnus-select-method'."
+  (memq gnus-select-method gnus-have-read-active-file))
+
+;;; General various misc type functions.
+
+;; Silence byte-compiler.
+(defvar gnus-current-headers)
+(defvar gnus-thread-indent-array)
+(defvar gnus-newsgroup-name)
+(defvar gnus-newsgroup-headers)
+(defvar gnus-group-list-mode)
+(defvar gnus-group-mark-positions)
+(defvar gnus-newsgroup-data)
+(defvar gnus-newsgroup-unreads)
+(defvar nnoo-state-alist)
+(defvar gnus-current-select-method)
+(defvar mail-sources)
+(defvar nnmail-scan-directory-mail-source-once)
+(defvar nnmail-split-history)
+(defvar nnmail-spool-file)
+
+(defun gnus-close-all-servers ()
+  "Close all servers."
+  (interactive)
+  (dolist (server gnus-opened-servers)
+    (gnus-close-server (car server))))
+
+(defun gnus-clear-system ()
+  "Clear all variables and buffers."
+  ;; Clear Gnus variables.
+  (let ((variables (remove 'gnus-format-specs gnus-variable-list)))
+    (while variables
+      (set (car variables) nil)
+      (setq variables (cdr variables))))
+  ;; Clear other internal variables.
+  (setq gnus-list-of-killed-groups nil
+       gnus-have-read-active-file nil
+        gnus-agent-covered-methods nil
+        gnus-agent-file-loading-local nil
+        gnus-agent-file-loading-cache nil
+        gnus-server-method-cache nil
+       gnus-newsrc-alist nil
+       gnus-newsrc-hashtb nil
+       gnus-killed-list nil
+       gnus-zombie-list nil
+       gnus-killed-hashtb nil
+       gnus-active-hashtb nil
+       gnus-moderated-hashtb nil
+       gnus-description-hashtb nil
+       gnus-current-headers nil
+       gnus-thread-indent-array nil
+       gnus-newsgroup-headers nil
+       gnus-newsgroup-name nil
+       gnus-server-alist nil
+       gnus-group-list-mode nil
+       gnus-opened-servers nil
+       gnus-group-mark-positions nil
+       gnus-newsgroup-data nil
+       gnus-newsgroup-unreads nil
+       nnoo-state-alist nil
+       gnus-current-select-method nil
+       nnmail-split-history nil
+       gnus-extended-servers nil
+       gnus-ephemeral-servers nil)
+  (gnus-shutdown 'gnus)
+  ;; Kill the startup file.
+  (and gnus-current-startup-file
+       (get-file-buffer gnus-current-startup-file)
+       (kill-buffer (get-file-buffer gnus-current-startup-file)))
+  ;; Clear the dribble buffer.
+  (gnus-dribble-clear)
+  ;; Kill global KILL file buffer.
+  (when (get-file-buffer (gnus-newsgroup-kill-file nil))
+    (kill-buffer (get-file-buffer (gnus-newsgroup-kill-file nil))))
+  (gnus-kill-buffer nntp-server-buffer)
+  ;; Kill Gnus buffers.
+  (dolist (buffer (gnus-buffers))
+    (gnus-kill-buffer buffer))
+  ;; Remove Gnus frames.
+  (gnus-kill-gnus-frames))
+
+(defun gnus-no-server-1 (&optional arg slave)
+  "Read network news.
+If ARG is a positive number, Gnus will use that as the startup
+level.  If ARG is nil, Gnus will be started at level 2
+\(`gnus-level-default-subscribed' minus one).  If ARG is non-nil
+and not a positive number, Gnus will prompt the user for the name
+of an NNTP server to use.  As opposed to \\[gnus], this command
+will not connect to the local server."
+  (interactive "P")
+  (let ((val (or arg (1- gnus-level-default-subscribed))))
+    (gnus val t slave)
+    (make-local-variable 'gnus-group-use-permanent-levels)
+    (setq gnus-group-use-permanent-levels val)))
+
+(defun gnus-1 (&optional arg dont-connect slave)
+  "Read network news.
+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")
+
+  (if (gnus-alive-p)
+      (progn
+       (gnus-run-hooks 'gnus-before-resume-hook)
+       (switch-to-buffer gnus-group-buffer)
+       (gnus-group-get-new-news
+        (and (numberp arg)
+             (> arg 0)
+             (max (car gnus-group-list-mode) arg))))
+
+    (gnus-clear-system)
+    (gnus-splash)
+    (gnus-run-hooks 'gnus-before-startup-hook)
+    (nnheader-init-server-buffer)
+    (setq gnus-slave slave)
+    (gnus-read-init-file)
+
+    ;; Add "native" to gnus-predefined-server-alist just to have a
+    ;; name for the native select method.
+    (when gnus-select-method
+      (add-to-list 'gnus-predefined-server-alist
+                  (cons "native" gnus-select-method)))
+
+    (if gnus-agent
+       (gnus-agentize))
+
+    (let ((level (and (numberp arg) (> arg 0) arg))
+         did-connect)
+      (unwind-protect
+         (progn
+           (unless dont-connect
+             (setq did-connect
+                   (gnus-start-news-server (and arg (not level))))))
+       (if (and (not dont-connect)
+                (not did-connect))
+           ;; Couldn't connect to the server, so bail out.
+           (gnus-group-quit)
+         (gnus-run-hooks 'gnus-startup-hook)
+         ;; Find the current startup file name.
+         (setq gnus-current-startup-file
+               (gnus-make-newsrc-file gnus-startup-file))
+
+         ;; Read the dribble file.
+         (when (or gnus-slave gnus-use-dribble-file)
+           (gnus-dribble-read-file))
+
+         ;; Do the actual startup.
+         (gnus-setup-news nil level dont-connect)
+         (gnus-run-hooks 'gnus-setup-news-hook)
+         (when gnus-agent
+           (gnus-request-create-group "queue" '(nndraft "")))
+         (gnus-start-draft-setup)
+         ;; Generate the group buffer.
+         (gnus-group-list-groups level)
+         (gnus-group-first-unread-group)
+         (gnus-configure-windows 'group)
+         (gnus-group-set-mode-line)
+         (gnus-run-hooks 'gnus-started-hook))))))
+
+(defun gnus-start-draft-setup ()
+  "Make sure the draft group exists."
+  (interactive)
+  (gnus-request-create-group "drafts" '(nndraft ""))
+  (unless (gnus-group-entry "nndraft:drafts")
+    (let ((gnus-level-default-subscribed 1))
+      (gnus-subscribe-group "nndraft:drafts" nil '(nndraft "")))
+    (setcar (gnus-group-entry "nndraft:drafts") 0))
+  (unless (equal (gnus-group-get-parameter "nndraft:drafts" 'gnus-dummy t)
+                '((gnus-draft-mode)))
+    (gnus-group-set-parameter
+     "nndraft:drafts" 'gnus-dummy '((gnus-draft-mode)))))
+
+\f
+;;;
+;;; Dribble file
+;;;
+
+(defvar gnus-dribble-ignore nil)
+(defvar gnus-dribble-eval-file nil)
+
+(defun gnus-dribble-file-name ()
+  "Return the dribble file for the current .newsrc."
+  (concat
+   (if gnus-dribble-directory
+       (concat (file-name-as-directory gnus-dribble-directory)
+              (file-name-nondirectory gnus-current-startup-file))
+     gnus-current-startup-file)
+   "-dribble"))
+
+(defun gnus-dribble-enter (string &optional regexp)
+  "Enter STRING into the dribble buffer.
+If REGEXP is given, lines that match it will be deleted."
+  (when (and (not gnus-dribble-ignore)
+            gnus-dribble-buffer
+            (buffer-name gnus-dribble-buffer))
+    (let ((obuf (current-buffer)))
+      (set-buffer gnus-dribble-buffer)
+      (when regexp
+       (goto-char (point-min))
+       (let (end)
+         (while (re-search-forward regexp nil t)
+           (unless (bolp) (forward-line 1))
+           (setq end (point))
+           (goto-char (match-beginning 0))
+           (delete-region (point-at-bol) end))))
+      (goto-char (point-max))
+      (insert string "\n")
+      ;; This has been commented by Josh Huber <huber@alum.wpi.edu>
+      ;; It causes problems with both XEmacs and Emacs 21, and doesn't
+      ;; seem to be of much value. (FIXME: remove this after we make sure
+      ;; it's not needed).
+      ;; (set-window-point (get-buffer-window (current-buffer)) (point-max))
+      (bury-buffer gnus-dribble-buffer)
+      (with-current-buffer gnus-group-buffer
+       (gnus-group-set-mode-line))
+      (set-buffer obuf))))
+
+(defun gnus-dribble-touch ()
+  "Touch the dribble buffer."
+  (gnus-dribble-enter ""))
+
+(defun gnus-dribble-read-file ()
+  "Read the dribble file from disk."
+  (let ((dribble-file (gnus-dribble-file-name)))
+    (unless (file-exists-p (file-name-directory dribble-file))
+      (make-directory (file-name-directory dribble-file) t))
+    (with-current-buffer (setq gnus-dribble-buffer
+                              (gnus-get-buffer-create
+                               (file-name-nondirectory dribble-file)))
+      (set (make-local-variable 'file-precious-flag) t)
+      (setq buffer-save-without-query t)
+      (erase-buffer)
+      (setq buffer-file-name dribble-file)
+      ;; The buffer may be shrunk a lot when deleting old entries.
+      ;; It caused the auto-saving to stop.
+      (if (featurep 'emacs)
+         (set (make-local-variable 'auto-save-include-big-deletions) t)
+       (set (make-local-variable 'disable-auto-save-when-buffer-shrinks) nil))
+      (auto-save-mode t)
+      (buffer-disable-undo)
+      (bury-buffer (current-buffer))
+      (set-buffer-modified-p nil)
+      (let ((auto (make-auto-save-file-name))
+           (gnus-dribble-ignore t)
+           (purpose nil)
+           modes)
+       (when (or (file-exists-p auto) (file-exists-p dribble-file))
+         ;; Load whichever file is newest -- the auto save file
+         ;; or the "real" file.
+         (if (file-newer-than-file-p auto dribble-file)
+             (nnheader-insert-file-contents auto)
+           (nnheader-insert-file-contents dribble-file))
+         (unless (zerop (buffer-size))
+           (set-buffer-modified-p t))
+         ;; Set the file modes to reflect the .newsrc file modes.
+         (save-buffer)
+         (when (and (file-exists-p gnus-current-startup-file)
+                    (file-exists-p dribble-file)
+                    (setq modes (file-modes gnus-current-startup-file)))
+           (gnus-set-file-modes dribble-file modes))
+         (goto-char (point-min))
+         (when (search-forward "Gnus was exited on purpose" nil t)
+           (setq purpose t))
+         ;; Possibly eval the file later.
+         (when (or gnus-always-read-dribble-file
+                   (gnus-y-or-n-p
+                    (if purpose
+                        "Gnus exited on purpose without saving; read auto-save file anyway? "
+                    "Gnus auto-save file exists.  Do you want to read it? ")))
+           (setq gnus-dribble-eval-file t)))))))
+
+(defun gnus-dribble-eval-file ()
+  (when gnus-dribble-eval-file
+    (setq gnus-dribble-eval-file nil)
+    (save-excursion
+      (let ((gnus-dribble-ignore t))
+       (set-buffer gnus-dribble-buffer)
+       (eval-buffer (current-buffer))))))
+
+(defun gnus-dribble-delete-file ()
+  (when (file-exists-p (gnus-dribble-file-name))
+    (delete-file (gnus-dribble-file-name)))
+  (when gnus-dribble-buffer
+    (with-current-buffer gnus-dribble-buffer
+      (let ((auto (make-auto-save-file-name)))
+       (when (file-exists-p auto)
+         (delete-file auto))
+       (erase-buffer)
+       (set-buffer-modified-p nil)))))
+
+(defun gnus-dribble-save ()
+  (when (and gnus-dribble-buffer
+            (buffer-name gnus-dribble-buffer))
+    (with-current-buffer gnus-dribble-buffer
+      (when (> (buffer-size) 0)
+       (save-buffer)))))
+
+(defun gnus-dribble-clear ()
+  (when (gnus-buffer-exists-p gnus-dribble-buffer)
+    (with-current-buffer gnus-dribble-buffer
+      (erase-buffer)
+      (set-buffer-modified-p nil)
+      (setq buffer-saved-size (buffer-size)))))
+
+\f
+;;;
+;;; Active & Newsrc File Handling
+;;;
+
+(defun gnus-setup-news (&optional rawfile level dont-connect)
+  "Setup news information.
+If RAWFILE is non-nil, the .newsrc file will also be read.
+If LEVEL is non-nil, the news will be set up at level LEVEL."
+  (require 'nnmail)
+  (let ((init (not (and gnus-newsrc-alist gnus-active-hashtb (not rawfile))))
+       ;; Binding this variable will inhibit multiple fetchings
+       ;; of the same mail source.
+       (nnmail-fetched-sources (list t)))
+
+    (when init
+      ;; Clear some variables to re-initialize news information.
+      (setq gnus-newsrc-alist nil
+           gnus-active-hashtb nil)
+      ;; Read the newsrc file and create `gnus-newsrc-hashtb'.
+      (gnus-read-newsrc-file rawfile))
+
+    ;; Make sure the archive server is available to all and sundry.
+    (let ((method (or (and (stringp gnus-message-archive-method)
+                          (gnus-server-to-method
+                           gnus-message-archive-method))
+                     gnus-message-archive-method)))
+      ;; Check whether the archive method is writable.
+      (unless (or (not method)
+                 (stringp method)
+                 (memq 'respool (assoc (format "%s" (car method))
+                                       gnus-valid-select-methods)))
+       (setq method "archive")) ;; The default.
+      (when (stringp method)
+       (setq method `(nnfolder
+                      ,method
+                      (nnfolder-directory
+                       ,(nnheader-concat message-directory method))
+                      (nnfolder-active-file
+                       ,(nnheader-concat message-directory
+                                         (concat method "/active")))
+                      (nnfolder-get-new-mail nil)
+                      (nnfolder-inhibit-expiry t))))
+      (if (assoc "archive" gnus-server-alist)
+         (when gnus-update-message-archive-method
+           (if method
+               (setcdr (assoc "archive" gnus-server-alist) method)
+             (setq gnus-server-alist (delq (assoc "archive" gnus-server-alist)
+                                           gnus-server-alist))))
+       (when method
+         (push (cons "archive" method) gnus-server-alist))))
+
+    ;; If we don't read the complete active file, we fill in the
+    ;; hashtb here.
+    (when (or (null gnus-read-active-file)
+             (eq gnus-read-active-file 'some))
+      (gnus-update-active-hashtb-from-killed))
+    (unless gnus-active-hashtb
+      (setq gnus-active-hashtb (gnus-make-hashtable 4096)))
+    ;; Initialize the cache.
+    (when gnus-use-cache
+      (gnus-cache-open))
+
+    ;; Possibly eval the dribble file.
+    (and init
+        (or gnus-use-dribble-file gnus-slave)
+        (gnus-dribble-eval-file))
+
+    ;; Slave Gnusii should then clear the dribble buffer.
+    (when (and init gnus-slave)
+      (gnus-dribble-clear))
+
+    (gnus-update-format-specifications)
+
+    ;; See whether we need to read the description file.
+    (when (and (boundp 'gnus-group-line-format)
+              (stringp gnus-group-line-format)
+              (let ((case-fold-search nil))
+                (string-match "%[-,0-9]*D" gnus-group-line-format))
+              (not gnus-description-hashtb)
+              (not dont-connect)
+              gnus-read-active-file)
+      (gnus-read-all-descriptions-files))
+
+    ;; Find new newsgroups and treat them.
+    (when (and init gnus-check-new-newsgroups (not level)
+              (gnus-check-server gnus-select-method)
+              (not gnus-slave)
+              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))
+
+    ;; Read any slave files.
+    (gnus-master-read-slave-newsrc)
+
+    ;; 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 dont-connect))))
+
+(defun gnus-call-subscribe-functions (method group)
+  "Call METHOD to subscribe GROUP.
+If no function returns `non-nil', call `gnus-subscribe-zombies'."
+  (unless (cond
+          ((functionp method)
+           (funcall method group))
+          ((listp method)
+           (catch 'found
+             (dolist (func method)
+               (if (funcall func group)
+                   (throw 'found t)))
+             nil))
+          (t nil))
+    (gnus-subscribe-zombies group)))
+
+(defun gnus-find-new-newsgroups (&optional arg)
+  "Search for new newsgroups and add them.
+Each new newsgroup will be treated with `gnus-subscribe-newsgroup-method'.
+The `-n' option line from .newsrc is respected.
+
+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
+for new groups, and subscribe the new groups as zombies."
+  (interactive "p")
+  (let* ((gnus-subscribe-newsgroup-method
+         gnus-subscribe-newsgroup-method)
+        (check (cond
+                ((or (and (= (or arg 1) 4)
+                          (not (listp gnus-check-new-newsgroups)))
+                     (null gnus-read-active-file)
+                     (eq gnus-read-active-file 'some))
+                 'ask-server)
+                ((= (or arg 1) 16)
+                 (setq gnus-subscribe-newsgroup-method
+                       'gnus-subscribe-zombies)
+                 t)
+                (t gnus-check-new-newsgroups))))
+    (if (or (consp check)
+            (eq check 'ask-server))
+        ;; Ask the server for new groups.
+        (gnus-ask-server-for-new-groups)
+      ;; Go through the active hashtb and look for new groups.
+      (let ((groups 0)
+            group new-newsgroups)
+        (gnus-message 5 "Looking for new newsgroups...")
+        (unless gnus-have-read-active-file
+          (gnus-read-active-file))
+        (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
+        ;; with `gnus-newsrc-hashtb' and `gnus-killed-hashtb'.
+        (mapatoms
+         (lambda (sym)
+           (if (or (null (setq group (symbol-name sym)))
+                   (not (boundp sym))
+                   (null (symbol-value sym))
+                   (gnus-gethash group gnus-killed-hashtb)
+                   (gnus-gethash group gnus-newsrc-hashtb))
+               ()
+             (let ((do-sub (gnus-matches-options-n group)))
+               (cond
+                ((eq do-sub 'subscribe)
+                 (setq groups (1+ groups))
+                 (gnus-sethash group group gnus-killed-hashtb)
+                 (gnus-call-subscribe-functions
+                  gnus-subscribe-options-newsgroup-method group))
+                ((eq do-sub 'ignore)
+                 nil)
+                (t
+                 (setq groups (1+ groups))
+                 (gnus-sethash group group gnus-killed-hashtb)
+                 (if gnus-subscribe-hierarchical-interactive
+                     (push group new-newsgroups)
+                   (gnus-call-subscribe-functions
+                    gnus-subscribe-newsgroup-method group)))))))
+         gnus-active-hashtb)
+        (when new-newsgroups
+          (gnus-subscribe-hierarchical-interactive new-newsgroups))
+        (if (> groups 0)
+            (gnus-message 5 "%d new newsgroup%s arrived."
+                          groups (if (> groups 1) "s have" " has"))
+          (gnus-message 5 "No new newsgroups."))
+       groups))))
+
+(defun gnus-matches-options-n (group)
+  ;; Returns `subscribe' if the group is to be unconditionally
+  ;; subscribed, `ignore' if it is to be ignored, and nil if there is
+  ;; no match for the group.
+
+  ;; First we check the two user variables.
+  (cond
+   ((and gnus-options-subscribe
+        (string-match gnus-options-subscribe group))
+    'subscribe)
+   ((let ((do-subscribe nil))
+      (dolist (category gnus-auto-subscribed-categories)
+       (when (gnus-member-of-valid category group)
+         (setq do-subscribe t)))
+      do-subscribe)
+    'subscribe)
+   ((and gnus-auto-subscribed-groups
+        (string-match gnus-auto-subscribed-groups group))
+    'subscribe)
+   ((and gnus-options-not-subscribe
+        (string-match gnus-options-not-subscribe group))
+    'ignore)
+   ;; Then we go through the list that was retrieved from the .newsrc
+   ;; file.  This list has elements on the form
+   ;; `(REGEXP . {ignore,subscribe})'.  The first match found (the list
+   ;; is in the reverse order of the options line) is returned.
+   (t
+    (let ((regs gnus-newsrc-options-n))
+      (while (and regs
+                 (not (string-match (caar regs) group)))
+       (setq regs (cdr regs)))
+      (and regs (cdar regs))))))
+
+(defun gnus-ask-server-for-new-groups ()
+  (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)
+                          (list "archive"))
+                        (append
+                         (and (consp gnus-check-new-newsgroups)
+                              gnus-check-new-newsgroups)
+                         gnus-secondary-select-methods))))
+        (groups 0)
+        group new-newsgroups got-new method hashtb
+        gnus-override-subscribe-method)
+    (unless gnus-killed-hashtb
+      (gnus-make-hashtable-from-killed))
+    ;; Go through both primary and secondary select methods and
+    ;; request new newsgroups.
+    (while (setq method (gnus-server-get-method nil (pop methods)))
+      (setq new-newsgroups nil
+           gnus-override-subscribe-method method)
+      (when (and (gnus-check-server method)
+                (gnus-request-newgroups date method))
+       (save-excursion
+         (setq got-new t
+               hashtb (gnus-make-hashtable 100))
+         (set-buffer nntp-server-buffer)
+         ;; Enter all the new groups into a hashtable.
+         (gnus-active-to-gnus-format method hashtb 'ignore))
+       ;; Now all new groups from `method' are in `hashtb'.
+       (mapatoms
+        (lambda (group-sym)
+          (if (or (null (setq group (symbol-name group-sym)))
+                  (not (boundp group-sym))
+                  (null (symbol-value group-sym))
+                  (gnus-gethash group gnus-newsrc-hashtb)
+                  (member group gnus-zombie-list)
+                  (member group gnus-killed-list))
+              ;; The group is already known.
+              ()
+            ;; Make this group active.
+            (when (symbol-value group-sym)
+              (gnus-set-active group (symbol-value group-sym)))
+            ;; Check whether we want it or not.
+            (let ((do-sub (gnus-matches-options-n group)))
+              (cond
+               ((eq do-sub 'subscribe)
+                (incf groups)
+                (gnus-sethash group group gnus-killed-hashtb)
+                (gnus-call-subscribe-functions
+                 gnus-subscribe-options-newsgroup-method group))
+               ((eq do-sub 'ignore)
+                nil)
+               (t
+                (incf groups)
+                (gnus-sethash group group gnus-killed-hashtb)
+                (if gnus-subscribe-hierarchical-interactive
+                    (push group new-newsgroups)
+                  (gnus-call-subscribe-functions
+                   gnus-subscribe-newsgroup-method group)))))))
+        hashtb))
+      (when new-newsgroups
+       (gnus-subscribe-hierarchical-interactive new-newsgroups)))
+    (if (> groups 0)
+       (gnus-message 5 "%d new newsgroup%s arrived"
+                     groups (if (> groups 1) "s have" " has"))
+      (gnus-message 5 "No new newsgroups"))
+    (when got-new
+      (setq gnus-newsrc-last-checked-date new-date))
+    new-newsgroups))
+
+(defun gnus-subscribe-group (group &optional previous method)
+  "Subscribe GROUP and put it after PREVIOUS."
+  (gnus-group-change-level
+   (if method
+       (list t group gnus-level-default-subscribed nil nil method)
+     group)
+   gnus-level-default-subscribed gnus-level-killed previous t)
+  t)
+
+;; `gnus-group-change-level' is the fundamental function for changing
+;; subscription levels of newsgroups.  This might mean just changing
+;; from level 1 to 2, which is pretty trivial, from 2 to 6 or back
+;; again, which subscribes/unsubscribes a group, which is equally
+;; trivial.  Changing from 1-7 to 8-9 means that you kill a group, and
+;; from 8-9 to 1-7 means that you remove the group from the list of
+;; killed (or zombie) groups and add them to the (kinda) subscribed
+;; groups.  And last but not least, moving from 8 to 9 and 9 to 8,
+;; which is trivial.
+;; ENTRY can either be a string (newsgroup name) or a list (if
+;; FROMKILLED is t, it's a list on the format (NUM INFO-LIST),
+;; otherwise it's a list in the format of the `gnus-newsrc-hashtb'
+;; entries.
+;; LEVEL is the new level of the group, OLDLEVEL is the old level and
+;; PREVIOUS is the group (in hashtb entry format) to insert this group
+;; after.
+(defun gnus-group-change-level (entry level &optional oldlevel
+                                     previous fromkilled)
+  (let (group info active num)
+    ;; Glean what info we can from the arguments
+    (if (consp entry)
+       (if fromkilled (setq group (nth 1 entry))
+         (setq group (car (nth 2 entry))))
+      (setq group entry))
+    (when (and (stringp entry)
+              oldlevel
+              (< oldlevel gnus-level-zombie))
+      (setq entry (gnus-group-entry entry)))
+    (if (and (not oldlevel)
+            (consp entry))
+       (setq oldlevel (gnus-info-level (nth 2 entry)))
+      (setq oldlevel (or oldlevel gnus-level-killed)))
+    (when (stringp previous)
+      (setq previous (gnus-group-entry previous)))
+
+    (if (and (>= oldlevel gnus-level-zombie)
+            (gnus-group-entry group))
+       ;; We are trying to subscribe a group that is already
+       ;; subscribed.
+       ()                              ; Do nothing.
+
+      (unless (gnus-ephemeral-group-p group)
+       (gnus-dribble-enter
+        (format "(gnus-group-change-level %S %S %S %S %S)"
+                group level oldlevel (car (nth 2 previous)) fromkilled)))
+
+      ;; Then we remove the newgroup from any old structures, if needed.
+      ;; If the group was killed, we remove it from the killed or zombie
+      ;; list.  If not, and it is in fact going to be killed, we remove
+      ;; it from the newsrc hash table and assoc.
+      (cond
+       ((>= oldlevel gnus-level-zombie)
+       ;; oldlevel could be wrong.
+       (setq gnus-zombie-list (delete group gnus-zombie-list))
+       (setq gnus-killed-list (delete group gnus-killed-list)))
+       (t
+       (when (and (>= level gnus-level-zombie)
+                  entry)
+         (gnus-sethash (car (nth 2 entry)) nil gnus-newsrc-hashtb)
+         (when (nth 3 entry)
+           (setcdr (gnus-group-entry (car (nth 3 entry)))
+                   (cdr entry)))
+         (setcdr (cdr entry) (cdddr entry)))))
+
+      ;; Finally we enter (if needed) the list where it is supposed to
+      ;; go, and change the subscription level.  If it is to be killed,
+      ;; we enter it into the killed or zombie list.
+      (cond
+       ((>= level gnus-level-zombie)
+       ;; Remove from the hash table.
+       (gnus-sethash group nil gnus-newsrc-hashtb)
+       (if (= level gnus-level-zombie)
+           (push group gnus-zombie-list)
+         (if (= oldlevel gnus-level-killed)
+             ;; Remove from active hashtb.
+             (unintern group gnus-active-hashtb)
+           ;; Don't add it into killed-list if it was killed.
+           (push group gnus-killed-list))))
+       (t
+       ;; If the list is to be entered into the newsrc assoc, and
+       ;; it was killed, we have to create an entry in the newsrc
+       ;; hashtb format and fix the pointers in the newsrc assoc.
+       (if (< oldlevel gnus-level-zombie)
+           ;; It was alive, and it is going to stay alive, so we
+           ;; just change the level and don't change any pointers or
+           ;; hash table entries.
+           (setcar (cdaddr entry) level)
+         (if (listp entry)
+             (setq info (cdr entry)
+                   num (car entry))
+           (setq active (gnus-active group))
+           (setq num
+                 (if active (- (1+ (cdr active)) (car active)) t))
+           ;; Shorten the select method if possible, if we need to
+           ;; store it at all (native groups).
+           (let ((method (gnus-method-simplify
+                          (or gnus-override-subscribe-method
+                              (gnus-group-method group)))))
+             (if method
+                 (setq info (list group level nil nil method))
+               (setq info (list group level nil)))))
+         (unless previous
+           (setq previous
+                 (let ((p gnus-newsrc-alist))
+                   (while (cddr p)
+                     (setq p (cdr p)))
+                   p)))
+         (setq entry (cons info (cddr previous)))
+         (if (cdr previous)
+             (progn
+               (setcdr (cdr previous) entry)
+               (gnus-sethash group (cons num (cdr previous))
+                             gnus-newsrc-hashtb))
+           (setcdr previous entry)
+           (gnus-sethash group (cons num previous)
+                         gnus-newsrc-hashtb))
+         (when (cdr entry)
+           (setcdr (gnus-group-entry (caadr entry)) entry))
+         (gnus-dribble-enter
+          (format "(gnus-group-set-info '%S)" info)
+          (concat "^(gnus-group-set-info '(\"" (regexp-quote group) "\"")))))
+      (when gnus-group-change-level-function
+       (funcall gnus-group-change-level-function
+                group level oldlevel previous)))))
+
+(defun gnus-check-bogus-newsgroups (&optional confirm)
+  "Remove bogus newsgroups.
+If CONFIRM is non-nil, the user has to confirm the deletion of every
+newsgroup."
+  (let ((newsrc (cdr gnus-newsrc-alist))
+       bogus group entry info)
+    (gnus-message 5 "Checking bogus newsgroups...")
+    (unless (gnus-read-active-file-p)
+      (gnus-read-active-file t))
+    (when (gnus-read-active-file-p)
+      ;; Find all bogus newsgroup that are subscribed.
+      (while newsrc
+       (setq info (pop newsrc)
+             group (gnus-info-group info))
+       (unless (or (gnus-active group) ; Active
+                   (and (gnus-info-method info)
+                        (not (gnus-secondary-method-p
+                              (gnus-info-method info))))) ; Foreign
+         ;; Found a bogus newsgroup.
+         (push group bogus)))
+      (if confirm
+         (map-y-or-n-p
+          (format "Remove bogus group %%s (of %d groups)? " (length bogus))
+          (lambda (group)
+            ;; Remove all bogus subscribed groups by first killing them, and
+            ;; then removing them from the list of killed groups.
+            (when (setq entry (gnus-group-entry group))
+              (gnus-group-change-level entry gnus-level-killed)
+              (setq gnus-killed-list (delete group gnus-killed-list))))
+          bogus '("group" "groups" "remove"))
+       (while (setq group (pop bogus))
+         ;; Remove all bogus subscribed groups by first killing them, and
+         ;; then removing them from the list of killed groups.
+         (when (setq entry (gnus-group-entry group))
+           (gnus-group-change-level entry gnus-level-killed)
+           (setq gnus-killed-list (delete group gnus-killed-list)))))
+      ;; Then we remove all bogus groups from the list of killed and
+      ;; zombie groups.  They are removed without confirmation.
+      (let ((dead-lists '(gnus-killed-list gnus-zombie-list))
+           killed)
+       (while dead-lists
+         (setq killed (symbol-value (car dead-lists)))
+         (while killed
+           (unless (gnus-active (setq group (pop killed)))
+             ;; The group is bogus.
+             ;; !!!Slow as hell.
+             (set (car dead-lists)
+                  (delete group (symbol-value (car dead-lists))))))
+         (setq dead-lists (cdr dead-lists))))
+      (gnus-run-hooks 'gnus-check-bogus-groups-hook)
+      (gnus-message 5 "Checking bogus newsgroups...done"))))
+
+(defun gnus-check-duplicate-killed-groups ()
+  "Remove duplicates from the list of killed groups."
+  (interactive)
+  (let ((killed gnus-killed-list))
+    (while killed
+      (gnus-message 9 "%d" (length killed))
+      (setcdr killed (delete (car killed) (cdr killed)))
+      (setq killed (cdr killed)))))
+
+;; We want to inline a function from gnus-cache, so we cheat here:
+(defvar gnus-cache-active-hashtb)
+(eval-when-compile
+  (defun gnus-cache-possibly-alter-active (group active)
+    "Alter the ACTIVE info for GROUP to reflect the articles in the cache."
+    (when gnus-cache-active-hashtb
+      (let ((cache-active (gnus-gethash group gnus-cache-active-hashtb)))
+       (when cache-active
+         (when (< (car cache-active) (car active))
+           (setcar active (car cache-active)))
+         (when (> (cdr cache-active) (cdr active))
+           (setcdr active (cdr cache-active))))))))
+
+(defun gnus-activate-group (group &optional scan dont-check method
+                                 dont-sub-check)
+  "Check whether a group has been activated or not.
+If SCAN, request a scan of that group as well.  If METHOD, use
+that select method instead of determining the method based on the
+group name.  If DONT-CHECK, don't check whether the group
+actually exists.  If DONT-SUB-CHECK or DONT-CHECK, don't let the
+backend check whether the group actually exists."
+  (let ((method (or method (inline (gnus-find-method-for-group group))))
+       active)
+    (and (inline (gnus-check-server method))
+        ;; We escape all bugs and quit here to make it possible to
+        ;; continue if a group is so out-there that it reports bugs
+        ;; and stuff.
+        (progn
+          (and scan
+               (gnus-check-backend-function 'request-scan (car method))
+               (gnus-request-scan group method))
+          t)
+        (if (or debug-on-error debug-on-quit)
+            (inline (gnus-request-group group (or dont-sub-check dont-check)
+                                        method
+                                        (gnus-get-info group)))
+          (condition-case nil
+              (inline (gnus-request-group group (or dont-sub-check dont-check)
+                                          method
+                                          (gnus-get-info group)))
+            (quit
+             (if debug-on-quit
+                 (debug "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 (or (car active) 0))
+                   (zerop (or (cdr active) 0))
+                   (gnus-active group))
+              (gnus-active group)
+
+             ;; If a cache is present, we may have to alter the active info.
+             (when gnus-use-cache
+               (inline (gnus-cache-possibly-alter-active
+                        group active)))
+
+             ;; If the agent is enabled, we may have to alter the active info.
+             (when gnus-agent
+               (gnus-agent-possibly-alter-active group active))
+
+            (gnus-set-active group active)
+            ;; Return the new active info.
+            active)))))
+
+(defun gnus-get-unread-articles-in-group (info active &optional update)
+  (when (and info active)
+    ;; Allow the backend to update the info in the group.
+    (when (and update
+              (gnus-request-update-info
+               info (inline (gnus-find-method-for-group
+                             (gnus-info-group info)))))
+      (gnus-activate-group (gnus-info-group info) nil t))
+
+    (let* ((range (gnus-info-read info))
+          (num 0))
+
+      ;; These checks are present in gnus-activate-group but skipped
+      ;; due to setting dont-check in the preceding call.
+
+      ;; If a cache is present, we may have to alter the active info.
+      (when (and gnus-use-cache info)
+       (inline (gnus-cache-possibly-alter-active
+                (gnus-info-group info) active)))
+
+      ;; If the agent is enabled, we may have to alter the active info.
+      (when (and gnus-agent info)
+       (gnus-agent-possibly-alter-active (gnus-info-group info) active info))
+
+      ;; Modify the list of read articles according to what articles
+      ;; are available; then tally the unread articles and add the
+      ;; number to the group hash table entry.
+      (cond
+       ((zerop (cdr active))
+       (setq num 0))
+       ((not range)
+       (setq num (- (1+ (cdr active)) (car active))))
+       ((not (listp (cdr range)))
+       ;; Fix a single (num . num) range according to the
+       ;; active hash table.
+       ;; Fix by Carsten Bormann <cabo@Informatik.Uni-Bremen.DE>.
+       (and (< (cdr range) (car active)) (setcdr range (1- (car active))))
+       (and (> (cdr range) (cdr active)) (setcdr range (cdr active)))
+       ;; Compute number of unread articles.
+       (setq num (max 0 (- (cdr active) (- (1+ (cdr range)) (car range))))))
+       (t
+       ;; The read list is a list of ranges.  Fix them according to
+       ;; the active hash table.
+       ;; First peel off any elements that are below the lower
+       ;; active limit.
+       (while (and (cdr range)
+                   (>= (car active)
+                       (or (and (atom (cadr range)) (cadr range))
+                           (caadr range))))
+         (if (numberp (car range))
+             (setcar range
+                     (cons (car range)
+                           (or (and (numberp (cadr range))
+                                    (cadr range))
+                               (cdadr range))))
+           (setcdr (car range)
+                   (or (and (numberp (nth 1 range)) (nth 1 range))
+                       (cdadr range))))
+         (setcdr range (cddr range)))
+       ;; Adjust the first element to be the same as the lower limit.
+       (when (and (not (atom (car range)))
+                  (< (cdar range) (car active)))
+         (setcdr (car range) (1- (car active))))
+       ;; Then we want to peel off any elements that are higher
+       ;; than the upper active limit.
+       (let ((srange range))
+         ;; Go past all valid elements.
+         (while (and (cdr srange)
+                     (<= (or (and (atom (cadr srange))
+                                  (cadr srange))
+                             (caadr srange))
+                         (cdr active)))
+           (setq srange (cdr srange)))
+         (when (cdr srange)
+           ;; Nuke all remaining invalid elements.
+           (setcdr srange nil))
+
+         ;; Adjust the final element.
+         (when (and (not (atom (car srange)))
+                    (> (cdar srange) (cdr active)))
+           (setcdr (car srange) (cdr active))))
+       ;; Compute the number of unread articles.
+       (while range
+         (setq num (+ num (- (1+ (or (and (atom (car range)) (car range))
+                                     (cdar range)))
+                             (or (and (atom (car range)) (car range))
+                                 (caar range)))))
+         (setq range (cdr range)))
+       (setq num (max 0 (- (cdr active) num)))))
+      ;; Set the number of unread articles.
+      (when (and info
+                (gnus-group-entry (gnus-info-group info)))
+       (setcar (gnus-group-entry (gnus-info-group info)) num))
+      num)))
+
+;; Go though `gnus-newsrc-alist' and compare with `gnus-active-hashtb'
+;; and compute how many unread articles there are in each group.
+(defun gnus-get-unread-articles (&optional level dont-connect one-level)
+  (setq gnus-server-method-cache nil)
+  (require 'gnus-agent)
+  (let* ((newsrc (cdr gnus-newsrc-alist))
+        (alevel (or level gnus-activate-level (1+ gnus-level-subscribed)))
+        (foreign-level
+         (or
+          level
+          (min
+           (cond ((and gnus-activate-foreign-newsgroups
+                       (not (numberp gnus-activate-foreign-newsgroups)))
+                  (1+ gnus-level-subscribed))
+                 ((numberp gnus-activate-foreign-newsgroups)
+                  gnus-activate-foreign-newsgroups)
+                 (t 0))
+           alevel)))
+        (methods-cache nil)
+        (type-cache nil)
+        (gnus-agent-article-local-times 0)
+        (archive-method (gnus-server-to-method "archive"))
+        infos info group active method cmethod
+        method-type method-group-list entry)
+    (gnus-message 6 "Checking new news...")
+
+    (while newsrc
+      (setq active (gnus-active (setq group (gnus-info-group
+                                            (setq info (pop newsrc))))))
+      ;; First go through all the groups, see what select methods they
+      ;; belong to, and then collect them into lists per unique select
+      ;; method.
+      (if (not (setq method (gnus-info-method info)))
+         (setq method gnus-select-method)
+       ;; There may be several similar methods.  Possibly extend the
+       ;; method.
+       (if (setq cmethod (assoc method methods-cache))
+           (setq method (cdr cmethod))
+         (setq cmethod (if (stringp method)
+                           (gnus-server-to-method method)
+                         (inline (gnus-find-method-for-group
+                                  (gnus-info-group info) info))))
+         (push (cons method cmethod) methods-cache)
+         (setq method cmethod)))
+      (setq method-group-list (assoc method type-cache))
+      (unless method-group-list
+       (setq method-type
+             (cond
+              ((or (gnus-secondary-method-p method)
+                   (and (gnus-archive-server-wanted-p)
+                        (gnus-methods-equal-p archive-method method)))
+               'secondary)
+              ((inline (gnus-server-equal gnus-select-method method))
+               'primary)
+              (t
+               'foreign)))
+       (push (setq method-group-list (list method method-type nil nil))
+             type-cache))
+      ;; Only add groups that need updating.
+      (if (funcall (if one-level #'= #'<=) (gnus-info-level info)
+             (if (eq (cadr method-group-list) 'foreign)
+                 foreign-level
+               alevel))
+         (setcar (nthcdr 2 method-group-list)
+                 (cons info (nth 2 method-group-list)))
+       ;; The group is inactive, so we nix out the number of unread articles.
+       ;; It leads `(gnus-group-unread group)' to return t.  See also
+       ;; `gnus-group-prepare-flat'.
+       (unless active
+         (when (setq entry (gnus-group-entry group))
+           (setcar entry t)))))
+
+    ;; Sort the methods based so that the primary and secondary
+    ;; methods come first.  This is done for legacy reasons to try to
+    ;; ensure that side-effect behavior doesn't change from previous
+    ;; Gnus versions.
+    (setq type-cache
+         (sort (nreverse type-cache)
+               (lambda (c1 c2)
+                 (< (gnus-method-rank (cadr c1) (car c1))
+                    (gnus-method-rank (cadr c2) (car c2))))))
+    ;; Go through the list of servers and possibly extend methods that
+    ;; aren't equal (and that need extension; i.e., they are async).
+    (let ((methods nil))
+      (dolist (elem type-cache)
+       (destructuring-bind (method method-type infos dummy) elem
+         (let ((gnus-opened-servers methods))
+           (when (and (gnus-similar-server-opened method)
+                      (gnus-check-backend-function
+                       'retrieve-group-data-early (car method)))
+             (setq method (gnus-server-extend-method
+                           (gnus-info-group (car infos))
+                           method))
+             (setcar elem method))
+           (push (list method 'ok) methods)))))
+
+    ;; If we have primary/secondary select methods, but no groups from
+    ;; them, we still want to issue a retrieval request from them.
+    (unless dont-connect
+      (dolist (method (cons gnus-select-method
+                           gnus-secondary-select-methods))
+       (when (and (not (assoc method type-cache))
+                  (gnus-check-backend-function 'request-list (car method)))
+         (with-current-buffer nntp-server-buffer
+           (gnus-read-active-file-1 method nil)))))
+
+    ;; Clear out all the early methods.
+    (dolist (elem type-cache)
+      (destructuring-bind (method method-type infos dummy) elem
+       (when (and method
+                  infos
+                  (gnus-check-backend-function
+                   'retrieve-group-data-early (car method))
+                  (not (gnus-method-denied-p method)))
+         (when (ignore-errors (gnus-get-function method 'open-server))
+           (unless (gnus-server-opened method)
+             (gnus-open-server method))
+           (when (gnus-server-opened method)
+             ;; Just mark this server as "cleared".
+             (gnus-retrieve-group-data-early method nil))))))
+
+    ;; Start early async retrieval of data.
+    (let ((done-methods nil)
+         sanity-spec)
+      (dolist (elem type-cache)
+       (destructuring-bind (method method-type infos dummy) elem
+         (setq sanity-spec (list (car method) (cadr method)))
+         (when (and method infos
+                    (not (gnus-method-denied-p method)))
+           ;; If the open-server method doesn't exist, then the method
+           ;; itself doesn't exist, so we ignore it.
+           (if (not (ignore-errors (gnus-get-function method 'open-server)))
+               (setq type-cache (delq elem type-cache))
+             (unless (gnus-server-opened method)
+               (gnus-open-server method))
+             (when (and
+                    ;; This is a sanity check, so that we never
+                    ;; attempt to start two async requests to the
+                    ;; same server, because that will fail.  This
+                    ;; should never happen, since the methods should
+                    ;; be unique at this point, but apparently it
+                    ;; does happen in the wild with some setups.
+                    (not (member sanity-spec done-methods))
+                    (gnus-server-opened method)
+                    (gnus-check-backend-function
+                     'retrieve-group-data-early (car method)))
+               (push sanity-spec done-methods)
+               (when (gnus-check-backend-function 'request-scan (car method))
+                 (gnus-request-scan nil method))
+               ;; Store the token we get back from -early so that we
+               ;; can pass it to -finish later.
+               (setcar (nthcdr 3 elem)
+                       (gnus-retrieve-group-data-early method infos))))))))
+
+    ;; Do the rest of the retrieval.
+    (dolist (elem type-cache)
+      (destructuring-bind (method method-type infos early-data) elem
+       (when (and method infos
+                  (not (gnus-method-denied-p method)))
+         (let ((updatep (gnus-check-backend-function
+                         'request-update-info (car method))))
+           ;; See if any of the groups from this method require updating.
+           (gnus-read-active-for-groups method infos early-data)
+           (dolist (info infos)
+             (inline (gnus-get-unread-articles-in-group
+                      info (gnus-active (gnus-info-group info))
+                      updatep)))))))
+    (gnus-message 6 "Checking new news...done")))
+
+(defun gnus-method-rank (type method)
+  (cond
+   ;; Get info for virtual groups last.
+   ((eq (car method) 'nnvirtual)
+    200)
+   ((eq type 'primary)
+    1)
+   ;; Compute the rank of the secondary methods based on where they
+   ;; are in the secondary select list.
+   ((eq type 'secondary)
+    (let ((i 2))
+      (block nil
+       (dolist (smethod gnus-secondary-select-methods)
+         (when (equal method smethod)
+           (return i))
+         (incf i))
+       i)))
+   ;; Just say that all foreign groups have the same rank.
+   (t
+    100)))
+
+(defun gnus-read-active-for-groups (method infos early-data)
+  (with-current-buffer nntp-server-buffer
+    (cond
+     ;; Finish up getting the data from the methods that have -early
+     ;; methods.
+     ((and
+       early-data
+       (gnus-check-backend-function 'finish-retrieve-group-infos (car method))
+       (or (not (gnus-agent-method-p method))
+          (gnus-online method)))
+      (gnus-finish-retrieve-group-infos method infos early-data)
+      ;; We may have altered the data now, so mark the dribble buffer
+      ;; as dirty so that it gets saved.
+      (gnus-dribble-touch)
+      (gnus-agent-save-active method))
+     ;; Most backends have -retrieve-groups.
+     ((gnus-check-backend-function 'retrieve-groups (car method))
+      (when (gnus-check-backend-function 'request-scan (car method))
+       (gnus-request-scan nil method))
+      (let (groups)
+       (gnus-read-active-file-2
+        (dolist (info infos (nreverse groups))
+          (push (gnus-group-real-name (gnus-info-group info)) groups))
+        method)))
+     ;; Virtually all backends have -request-list.
+     ((gnus-check-backend-function 'request-list (car method))
+      (gnus-read-active-file-1 method nil))
+     ;; Except nnvirtual and friends, where we request each group, one
+     ;; by one.
+     (t
+      (dolist (info infos)
+       (gnus-activate-group (gnus-info-group info) nil nil method t))))))
+
+;; Create a hash table out of the newsrc alist.  The `car's of the
+;; alist elements are used as keys.
+(defun gnus-make-hashtable-from-newsrc-alist ()
+  (let ((alist gnus-newsrc-alist)
+       (ohashtb gnus-newsrc-hashtb)
+       prev info method rest methods)
+    (setq gnus-newsrc-hashtb (gnus-make-hashtable (length alist)))
+    (setq alist
+         (setq prev (setq gnus-newsrc-alist
+                          (if (equal (caar gnus-newsrc-alist)
+                                     "dummy.group")
+                              gnus-newsrc-alist
+                            (cons (list "dummy.group" 0 nil) alist)))))
+    (while alist
+      (setq info (car alist))
+      ;; Make the same select-methods identical Lisp objects.
+      (when (setq method (gnus-info-method info))
+       (if (setq rest (member method methods))
+           (gnus-info-set-method info (car rest))
+         (push method methods)))
+      ;; Check for duplicates.
+      (if (gnus-gethash (car info) gnus-newsrc-hashtb)
+         ;; Remove this entry from the alist.
+         (setcdr prev (cddr prev))
+       (gnus-sethash
+        (car info)
+        ;; Preserve number of unread articles in groups.
+        (cons (and ohashtb (car (gnus-gethash (car info) ohashtb)))
+              prev)
+        gnus-newsrc-hashtb)
+       (setq prev alist))
+      (setq alist (cdr alist)))
+    ;; Make the same select-methods in `gnus-server-alist' identical
+    ;; as well.
+    (while methods
+      (setq method (pop methods))
+      (when (setq rest (rassoc method gnus-server-alist))
+       (setcdr rest method)))))
+
+(defun gnus-make-hashtable-from-killed ()
+  "Create a hash table from the killed and zombie lists."
+  (let ((lists '(gnus-killed-list gnus-zombie-list))
+       list)
+    (setq gnus-killed-hashtb
+         (gnus-make-hashtable
+          (+ (length gnus-killed-list) (length gnus-zombie-list))))
+    (while lists
+      (setq list (symbol-value (pop lists)))
+      (while list
+       (gnus-sethash (car list) (pop list) gnus-killed-hashtb)))))
+
+(defun gnus-parse-active ()
+  "Parse active info in the nntp server buffer."
+  (with-current-buffer nntp-server-buffer
+    (goto-char (point-min))
+    ;; Parse the result we got from `gnus-request-group'.
+    (when (looking-at "[0-9]+ [0-9]+ \\([0-9]+\\) [0-9]+")
+      (goto-char (match-beginning 1))
+      (cons (read (current-buffer))
+           (read (current-buffer))))))
+
+(defun gnus-make-articles-unread (group articles)
+  "Mark ARTICLES in GROUP as unread."
+  (let* ((info (nth 2 (or (gnus-group-entry group)
+                         (gnus-group-entry
+                          (gnus-group-real-name group)))))
+        (ranges (gnus-info-read info))
+        news article)
+    (while articles
+      (when (gnus-member-of-range
+            (setq article (pop articles)) ranges)
+       (push article news)))
+    (when news
+      ;; Enter this list into the group info.
+      (gnus-info-set-read
+       info (gnus-remove-from-range (gnus-info-read info) (nreverse news)))
+
+      ;; Set the number of unread articles in gnus-newsrc-hashtb.
+      (gnus-get-unread-articles-in-group info (gnus-active group))
+
+      ;; Insert the change into the group buffer and the dribble file.
+      (gnus-group-update-group group t))))
+
+(defun gnus-make-ascending-articles-unread (group articles)
+  "Mark ascending ARTICLES in GROUP as unread."
+  (let* ((entry (or (gnus-group-entry group)
+                    (gnus-group-entry (gnus-group-real-name group))))
+         (info (nth 2 entry))
+        (ranges (gnus-info-read info))
+         (r ranges)
+        modified)
+
+    (while articles
+      (let ((article (pop articles))) ; get the next article to remove from ranges
+        (while (let ((range (car ranges))) ; note the current range
+                 (if (atom range)       ; single value range
+                     (cond ((not range)
+                            ;; the articles extend past the end of the ranges
+                            ;; OK - I'm done
+                            (setq articles nil))
+                           ((< range article)
+                            ;; this range precedes the article. Leave the range unmodified.
+                            (pop ranges)
+                            ranges)
+                           ((= range article)
+                            ;; this range exactly matches the article; REMOVE THE RANGE.
+                            ;; NOTE: When the range being removed is the last range, the list is corrupted by inserting null at its end.
+                            (setcar ranges (cadr ranges))
+                            (setcdr ranges (cddr ranges))
+                            (setq modified (if (car ranges) t 'remove-null))
+                            nil))
+                   (let ((min (car range))
+                         (max (cdr range)))
+                     ;; I have a min/max range to consider
+                     (cond ((> min max) ; invalid range introduced by splitter
+                            (setcar ranges (cadr ranges))
+                            (setcdr ranges (cddr ranges))
+                            (setq modified (if (car ranges) t 'remove-null))
+                            ranges)
+                           ((= min max)
+                            ;; replace min/max range with a single-value range
+                            (setcar ranges min)
+                            ranges)
+                           ((< max article)
+                            ;; this range precedes the article. Leave the range unmodified.
+                            (pop ranges)
+                            ranges)
+                           ((< article min)
+                            ;; this article precedes the range.  Return null to move to the
+                            ;; next article
+                            nil)
+                           (t
+                            ;; this article splits the range into two parts
+                            (setcdr ranges (cons (cons (1+ article) max) (cdr ranges)))
+                            (setcdr range (1- article))
+                            (setq modified t)
+                            ranges))))))))
+
+    (when modified
+      (when (eq modified 'remove-null)
+        (setq r (delq nil r)))
+      ;; Enter this list into the group info.
+      (gnus-info-set-read info r)
+
+      ;; Set the number of unread articles in gnus-newsrc-hashtb.
+      (gnus-get-unread-articles-in-group info (gnus-active group))
+
+      ;; Insert the change into the group buffer and the dribble file.
+      (gnus-group-update-group group t))))
+
+;; Enter all dead groups into the hashtb.
+(defun gnus-update-active-hashtb-from-killed ()
+  (let ((hashtb (setq gnus-active-hashtb (gnus-make-hashtable 4096)))
+       (lists (list gnus-killed-list gnus-zombie-list))
+       killed)
+    (while lists
+      (setq killed (car lists))
+      (while killed
+       (gnus-sethash (mm-string-as-unibyte (car killed)) nil hashtb)
+       (setq killed (cdr killed)))
+      (setq lists (cdr lists)))))
+
+(defun gnus-get-killed-groups ()
+  "Go through the active hashtb and mark all unknown groups as killed."
+  ;; First make sure active file has been read.
+  (unless (gnus-read-active-file-p)
+    (let ((gnus-read-active-file t))
+      (gnus-read-active-file)))
+  (unless gnus-killed-hashtb
+    (gnus-make-hashtable-from-killed))
+  ;; Go through all newsgroups that are known to Gnus - enlarge kill list.
+  (mapatoms
+   (lambda (sym)
+     (let ((groups 0)
+          (group (symbol-name sym)))
+       (if (or (null group)
+              (gnus-gethash group gnus-killed-hashtb)
+              (gnus-gethash group gnus-newsrc-hashtb))
+          ()
+        (let ((do-sub (gnus-matches-options-n group)))
+          (if (or (eq do-sub 'subscribe) (eq do-sub 'ignore))
+              ()
+            (setq groups (1+ groups))
+            (push group gnus-killed-list)
+            (gnus-sethash group group gnus-killed-hashtb))))))
+   gnus-active-hashtb)
+  (gnus-dribble-touch))
+
+;; Get the active file(s) from the backend(s).
+(defun gnus-read-active-file (&optional force not-native)
+  (gnus-group-set-mode-line)
+  (let ((methods
+        (mapcar
+         (lambda (m) (if (stringp m) (gnus-server-get-method nil m) m))
+         (append
+          (if (and (not not-native)
+                   (gnus-check-server gnus-select-method))
+              ;; The native server is available.
+              (cons gnus-select-method gnus-secondary-select-methods)
+            ;; The native server is down, so we just do the
+            ;; secondary ones.
+            gnus-secondary-select-methods)
+          ;; Also read from the archive server.
+          (when (gnus-archive-server-wanted-p)
+            (list "archive")))))
+       method)
+    (setq gnus-have-read-active-file nil)
+    (with-current-buffer nntp-server-buffer
+      (while (setq method (pop methods))
+       ;; Only do each method once, in case the methods appear more
+       ;; than once in this list.
+       (when (and (not (member method methods))
+                  ;; Check whether the backend exists.
+                  (ignore-errors (gnus-get-function method 'open-server)))
+         (if (or debug-on-error debug-on-quit)
+             (gnus-read-active-file-1 method force)
+           (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
+              (if debug-on-quit
+                  (debug "Quit")
+                (message "Quit reading the active file"))
+              nil))))))))
+
+(defun gnus-read-active-file-1 (method force)
+  (let (where mesg)
+    (setq where (nth 1 method)
+         mesg (format "Reading active file%s via %s..."
+                      (if (and where (not (zerop (length where))))
+                          (concat " from " where) "")
+                      (car method)))
+    (gnus-message 5 "%s" mesg)
+    (when (gnus-check-server method)
+      ;; Request that the backend scan its incoming messages.
+      (when (and (or (and gnus-agent
+                         (gnus-online method))
+                    (not gnus-agent))
+                (gnus-check-backend-function 'request-scan (car method)))
+       (gnus-request-scan nil method))
+      (cond
+       ((and (eq gnus-read-active-file 'some)
+            (gnus-check-backend-function 'retrieve-groups (car method))
+            (not force))
+       (let ((newsrc (cdr gnus-newsrc-alist))
+             (gmethod (gnus-server-get-method nil method))
+             groups info)
+         (while (setq info (pop newsrc))
+           (when (inline
+                   (gnus-server-equal
+                         (inline
+                           (gnus-find-method-for-group
+                                 (gnus-info-group info) info))
+                         gmethod))
+             (push (gnus-group-real-name (gnus-info-group info))
+                   groups)))
+         (gnus-read-active-file-2 groups method)))
+       ((null method)
+       t)
+       (t
+       (if (not (gnus-request-list method))
+           (unless (equal method gnus-message-archive-method)
+             (gnus-error 1 "Cannot read active file from %s server"
+                         (car method)))
+         (gnus-message 5 "%s" mesg)
+         (gnus-active-to-gnus-format method gnus-active-hashtb nil t)
+         ;; We mark this active file as read.
+         (add-to-list 'gnus-have-read-active-file method)
+         (gnus-message 5 "%sdone" mesg)))))))
+
+(defun gnus-read-active-file-2 (groups method)
+  "Read an active file for GROUPS in METHOD using `gnus-retrieve-groups'."
+  (when groups
+    (with-current-buffer nntp-server-buffer
+      (gnus-check-server method)
+      (let ((list-type (gnus-retrieve-groups groups method)))
+       (cond ((not list-type)
+              (gnus-error
+               1.2 "Cannot read partial active file from %s server."
+               (car method)))
+             ((eq list-type 'active)
+              (gnus-active-to-gnus-format method gnus-active-hashtb nil t))
+             (t
+              (gnus-groups-to-gnus-format method gnus-active-hashtb t)))))))
+
+;; Read an active file and place the results in `gnus-active-hashtb'.
+(defun gnus-active-to-gnus-format (&optional method hashtb ignore-errors
+                                            real-active)
+  (unless method
+    (setq method gnus-select-method))
+  (let ((cur (current-buffer))
+       (hashtb (or hashtb
+                   (if (and gnus-active-hashtb
+                            (not (equal method gnus-select-method)))
+                       gnus-active-hashtb
+                     (setq gnus-active-hashtb
+                           (if (equal method gnus-select-method)
+                               (gnus-make-hashtable
+                                (count-lines (point-min) (point-max)))
+                             (gnus-make-hashtable 4096))))))
+       group max min)
+    ;; Delete unnecessary lines.
+    (goto-char (point-min))
+    (cond
+     ((string= gnus-ignored-newsgroups "")
+      (delete-matching-lines "^to\\."))
+     (t
+      (delete-matching-lines (concat "^to\\.\\|" gnus-ignored-newsgroups))))
+
+    (goto-char (point-min))
+    (unless (re-search-forward "[\\\"]" nil t)
+      ;; Make the group names readable as a lisp expression even if they
+      ;; contain special characters.
+      (goto-char (point-max))
+      (while (re-search-backward "[][';?()#]" nil t)
+       (insert ?\\)))
+
+    ;; Let the Gnus agent save the active file.
+    (when (and gnus-agent real-active (gnus-online method))
+      (gnus-agent-save-active method))
+
+    ;; If these are groups from a foreign select method, we insert the
+    ;; group prefix in front of the group names.
+    (when (not (gnus-server-equal
+               (gnus-server-get-method nil method)
+               (gnus-server-get-method nil gnus-select-method)))
+      (let ((prefix (gnus-group-prefixed-name "" method)))
+       (goto-char (point-min))
+       (while (and (not (eobp))
+                   (progn
+                     (when (= (following-char) ?\")
+                       (forward-char 1))
+                     (insert prefix)
+                     (zerop (forward-line 1)))))))
+    ;; Store the active file in a hash table.
+    ;; Use a unibyte buffer in order to make `read' read non-ASCII
+    ;; group names (which have been encoded) as unibyte strings.
+    (mm-with-unibyte-buffer
+      (insert-buffer-substring cur)
+      (setq cur (current-buffer))
+      (goto-char (point-min))
+      (while (not (eobp))
+       (condition-case ()
+           (progn
+             (narrow-to-region (point) (point-at-eol))
+             ;; group gets set to a symbol interned in the hash table
+             ;; (what a hack!!) - jwz
+             (setq group (let ((obarray hashtb)) (read cur)))
+             ;; ### The extended group name scheme makes
+             ;; the previous optimization strategy sort of pointless...
+             (when (stringp group)
+               (setq group (intern group hashtb)))
+             (if (and (numberp (setq max (read cur)))
+                      (numberp (setq min (read cur)))
+                      (progn
+                        (skip-chars-forward " \t")
+                        (not
+                         (or (eq (char-after) ?=)
+                             (eq (char-after) ?x)
+                             (eq (char-after) ?j)))))
+                 (progn
+                   (set group (cons min max))
+                   ;; if group is moderated, stick in moderation table
+                   (when (eq (char-after) ?m)
+                     (unless gnus-moderated-hashtb
+                       (setq gnus-moderated-hashtb (gnus-make-hashtable)))
+                     (gnus-sethash (symbol-name group) t
+                                   gnus-moderated-hashtb)))
+               (set group nil)))
+         (error
+          (and group
+               (symbolp group)
+               (set group nil))
+          (unless ignore-errors
+            (gnus-message 3 "Warning - invalid active: %s"
+                          (buffer-substring
+                           (point-at-bol) (point-at-eol))))))
+       (widen)
+       (forward-line 1)))))
+
+(defun gnus-groups-to-gnus-format (method &optional hashtb real-active)
+  ;; Parse a "groups" active file.
+  (let ((cur (current-buffer))
+       (hashtb (or hashtb
+                   (if (and method gnus-active-hashtb)
+                       gnus-active-hashtb
+                     (setq gnus-active-hashtb
+                           (gnus-make-hashtable
+                            (count-lines (point-min) (point-max)))))))
+       (prefix (and method
+                    (not (gnus-server-equal
+                          (gnus-server-get-method nil method)
+                          (gnus-server-get-method nil gnus-select-method)))
+                    (gnus-group-prefixed-name "" method))))
+
+    ;; Let the Gnus agent save the active file.
+    (if (and gnus-agent
+            real-active
+            (gnus-online method)
+            (gnus-agent-method-p method))
+       (progn
+         (gnus-agent-save-active method t)
+         (gnus-active-to-gnus-format method hashtb nil real-active))
+
+      (goto-char (point-min))
+      ;; We split this into to separate loops, one with the prefix
+      ;; and one without to speed the reading up somewhat.
+      (if prefix
+         (let (min max opoint group)
+           (while (not (eobp))
+             (condition-case ()
+                 (progn
+                   (read cur) (read cur)
+                   (setq min (read cur)
+                         max (read cur)
+                         opoint (point))
+                   (skip-chars-forward " \t")
+                   (insert prefix)
+                   (goto-char opoint)
+                   (set (let ((obarray hashtb)) (read cur))
+                        (cons min max)))
+               (error (and group (symbolp group) (set group nil))))
+             (forward-line 1)))
+       (let (min max group)
+         (while (not (eobp))
+           (condition-case ()
+               (when (eq (char-after) ?2)
+                 (read cur) (read cur)
+                 (setq min (read cur)
+                       max (read cur))
+                 (set (setq group (let ((obarray hashtb)) (read cur)))
+                      (cons min max)))
+             (error (and group (symbolp group) (set group nil))))
+           (forward-line 1)))))))
+
+(defun gnus-read-newsrc-file (&optional force)
+  "Read startup file.
+If FORCE is non-nil, the .newsrc file is read."
+  ;; Reset variables that might be defined in the .newsrc.eld file.
+  (let ((variables (remove 'gnus-format-specs gnus-variable-list)))
+    (while variables
+      (set (car variables) nil)
+      (setq variables (cdr variables))))
+  (let* ((newsrc-file gnus-current-startup-file)
+        (quick-file (concat newsrc-file ".el")))
+    (save-excursion
+      ;; We always load the .newsrc.eld file.  If always contains
+      ;; much information that can not be gotten from the .newsrc
+      ;; file (ticked articles, killed groups, foreign methods, etc.)
+      (gnus-read-newsrc-el-file quick-file)
+
+      (when (and gnus-read-newsrc-file
+                (file-exists-p gnus-current-startup-file)
+                (or force
+                    (and (file-newer-than-file-p newsrc-file quick-file)
+                         (file-newer-than-file-p newsrc-file
+                                                 (concat quick-file "d")))
+                    (not gnus-newsrc-alist)))
+       ;; We read the .newsrc file.  Note that if there if a
+       ;; .newsrc.eld file exists, it has already been read, and
+       ;; the `gnus-newsrc-hashtb' has been created.  While reading
+       ;; the .newsrc file, Gnus will only use the information it
+       ;; can find there for changing the data already read -
+       ;; i. e., reading the .newsrc file will not trash the data
+       ;; already read (except for read articles).
+       (save-excursion
+         (gnus-message 5 "Reading %s..." newsrc-file)
+         (set-buffer (nnheader-find-file-noselect newsrc-file))
+         (buffer-disable-undo)
+         (gnus-newsrc-to-gnus-format)
+         (kill-buffer (current-buffer))
+         (gnus-message 5 "Reading %s...done" newsrc-file)))
+
+      ;; Convert old to new.
+      (gnus-convert-old-newsrc)
+      (gnus-clean-old-newsrc))))
+
+(defun gnus-clean-old-newsrc (&optional force)
+  ;; Currently no cleanups.
+  )
+
+(defun gnus-convert-old-newsrc ()
+  "Convert old newsrc formats into the current format, if needed."
+  (let ((fcv (and gnus-newsrc-file-version
+                 (gnus-continuum-version gnus-newsrc-file-version)))
+       (gcv (gnus-continuum-version)))
+    (when fcv
+      ;; A newsrc file was loaded.
+      (let (prompt-displayed
+            (converters
+             (sort
+              (mapcar (lambda (date-func)
+                        (cons (gnus-continuum-version (car date-func))
+                              date-func))
+                      ;; This is a list of converters that must be run
+                      ;; to bring the newsrc file up to the current
+                      ;; version.  If you create an incompatibility
+                      ;; with older versions, you should create an
+                      ;; entry here.  The entry should consist of the
+                      ;; current gnus version (hardcoded so that it
+                      ;; doesn't change with each release) and the
+                      ;; function that must be applied to convert the
+                      ;; previous version into the current version.
+                      '(("September Gnus v0.1" nil
+                         gnus-convert-old-ticks)
+                        ("Oort Gnus v0.08"     "legacy-gnus-agent"
+                         gnus-agent-convert-to-compressed-agentview)
+                        ("Gnus v5.10.7"        "legacy-gnus-agent"
+                         gnus-agent-unlist-expire-days)
+                        ("Gnus v5.10.7"        "legacy-gnus-agent"
+                         gnus-agent-unhook-expire-days)))
+              #'car-less-than-car)))
+        ;; Skip converters older than the file version
+        (while (and converters (>= fcv (caar converters)))
+          (pop converters))
+
+        ;; Perform converters to bring older version up to date.
+       (when (and converters (< fcv (caar converters)))
+         (while (and converters (< fcv (caar converters))
+                     (<= (caar converters) gcv))
+            (let* ((converter-spec  (pop converters))
+                   (convert-to      (nth 1 converter-spec))
+                   (load-from       (nth 2 converter-spec))
+                   (func            (nth 3 converter-spec)))
+              (when (and load-from
+                         (not (fboundp func)))
+                (load load-from t))
+              (or prompt-displayed
+                  (not (gnus-convert-converter-needs-prompt func))
+                  (while (let (c
+                               (cursor-in-echo-area t)
+                               (echo-keystrokes 0))
+                           (message "Convert gnus from version `%s' to `%s'? (n/y/?)"
+                                    gnus-newsrc-file-version gnus-version)
+                           (setq c (read-char-exclusive))
+
+                           (cond ((or (eq c ?n) (eq c ?N))
+                                  (error "Can not start gnus without converting"))
+                                 ((or (eq c ?y) (eq c ?Y))
+                                  (setq prompt-displayed t)
+                                  nil)
+                                 ((eq c ?\?)
+                                  (message "This conversion is irreversible. \
+ To be safe, you should backup your files before proceeding.")
+                                  (sit-for 5)
+                                  t)
+                                 (t
+                                  (gnus-message 3 "Ignoring unexpected input")
+                                  (sit-for 3)
+                                  t)))))
+
+              (funcall func convert-to)))
+          (gnus-dribble-enter
+           (gnus-format-message ";Converted gnus from version `%s' to `%s'."
+                               gnus-newsrc-file-version gnus-version)))))))
+
+(defun gnus-convert-mark-converter-prompt (converter no-prompt)
+  "Indicate whether CONVERTER requires gnus-convert-old-newsrc to
+  display the conversion prompt.  NO-PROMPT may be nil (prompt),
+  t (no prompt), or any form that can be called as a function.
+  The form should return either t or nil."
+  (put converter 'gnus-convert-no-prompt no-prompt))
+
+(defun gnus-convert-converter-needs-prompt (converter)
+  (let ((no-prompt (get converter 'gnus-convert-no-prompt)))
+    (not (if (memq no-prompt '(t nil))
+            no-prompt
+          (funcall no-prompt)))))
+
+(defun gnus-convert-old-ticks (converting-to)
+  (let ((newsrc (cdr gnus-newsrc-alist))
+       marks info dormant ticked)
+    (while (setq info (pop newsrc))
+      (when (setq marks (gnus-info-marks info))
+       (setq dormant (cdr (assq 'dormant marks))
+             ticked (cdr (assq 'tick marks)))
+       (when (or dormant ticked)
+         (gnus-info-set-read
+          info
+          (gnus-add-to-range
+           (gnus-info-read info)
+           (nconc (gnus-uncompress-range dormant)
+                  (gnus-uncompress-range ticked)))))))))
+
+(defun gnus-load (file)
+  "Load FILE, but in such a way that read errors can be reported."
+  (with-temp-buffer
+    (insert-file-contents file)
+    (while (not (eobp))
+      (condition-case type
+         (let ((form (read (current-buffer))))
+           (eval form))
+       (error
+        (unless (eq (car type) 'end-of-file)
+          (let ((errmsg (format "Error in %s line %d" file
+                                (count-lines (point-min) (point)))))
+            (ding)
+            (unless (gnus-yes-or-no-p (concat errmsg "; continue? "))
+              (error "%s" errmsg)))))))))
+
+(defun gnus-read-newsrc-el-file (file)
+  (let ((ding-file (concat file "d")))
+    (when (file-exists-p ding-file)
+      ;; We always, always read the .eld file.
+      (gnus-message 5 "Reading %s..." ding-file)
+      (let (gnus-newsrc-assoc)
+       (gnus-load ding-file)
+       ;; Older versions of `gnus-format-specs' are no longer valid
+       ;; in Oort Gnus 0.01.
+       (let ((version
+              (and gnus-newsrc-file-version
+                   (gnus-continuum-version gnus-newsrc-file-version))))
+         (when (or (not version)
+                   (< version 5.090009))
+           (setq gnus-format-specs gnus-default-format-specs)))
+       (when gnus-newsrc-assoc
+         (setq gnus-newsrc-alist gnus-newsrc-assoc))))
+    (dolist (elem gnus-newsrc-alist)
+      ;; Protect against broken .newsrc.el files.
+      (when (car elem)
+       (setcar elem (mm-string-as-unibyte (car elem)))))
+    (gnus-make-hashtable-from-newsrc-alist)
+    (when (file-newer-than-file-p file ding-file)
+      ;; Old format quick file
+      (gnus-message 5 "Reading %s..." file)
+      ;; The .el file is newer than the .eld file, so we read that one
+      ;; as well.
+      (gnus-read-old-newsrc-el-file file)))
+  (gnus-run-hooks 'gnus-read-newsrc-el-hook))
+
+;; Parse the old-style quick startup file
+(defun gnus-read-old-newsrc-el-file (file)
+  (let (newsrc killed marked group m info)
+    (prog1
+       (let ((gnus-killed-assoc nil)
+             gnus-marked-assoc gnus-newsrc-alist gnus-newsrc-assoc)
+         (prog1
+             (ignore-errors
+               (load file t t t))
+           (setq newsrc gnus-newsrc-assoc
+                 killed gnus-killed-assoc
+                 marked gnus-marked-assoc)))
+      (setq gnus-newsrc-alist nil)
+      (while (setq group (pop newsrc))
+       (if (setq info (gnus-get-info (car group)))
+           (progn
+             (gnus-info-set-read info (cddr group))
+             (gnus-info-set-level
+              info (if (nth 1 group) gnus-level-default-subscribed
+                     gnus-level-default-unsubscribed))
+             (push info gnus-newsrc-alist))
+         (push (setq info
+                     (list (car group)
+                           (if (nth 1 group) gnus-level-default-subscribed
+                             gnus-level-default-unsubscribed)
+                           (cddr group)))
+               gnus-newsrc-alist))
+       ;; Copy marks into info.
+       (when (setq m (assoc (car group) marked))
+         (unless (nthcdr 3 info)
+           (nconc info (list nil)))
+         (gnus-info-set-marks
+          info (list (cons 'tick (gnus-compress-sequence
+                                  (sort (cdr m) '<) t))))))
+      (setq newsrc killed)
+      (while newsrc
+       (setcar newsrc (caar newsrc))
+       (setq newsrc (cdr newsrc)))
+      (setq gnus-killed-list killed))
+    ;; The .el file version of this variable does not begin with
+    ;; "options", while the .eld version does, so we just add it if it
+    ;; isn't there.
+    (when
+       gnus-newsrc-options
+      (when (not (string-match "^ *options" gnus-newsrc-options))
+       (setq gnus-newsrc-options (concat "options " gnus-newsrc-options)))
+      (when (not (string-match "\n$" gnus-newsrc-options))
+       (setq gnus-newsrc-options (concat gnus-newsrc-options "\n")))
+      ;; Finally, if we read some options lines, we parse them.
+      (unless (string= gnus-newsrc-options "")
+       (gnus-newsrc-parse-options gnus-newsrc-options)))
+
+    (setq gnus-newsrc-alist (nreverse gnus-newsrc-alist))
+    (gnus-make-hashtable-from-newsrc-alist)))
+
+(defun gnus-make-newsrc-file (file)
+  "Make server dependent file name by catenating FILE and server host name."
+  (let* ((file (expand-file-name file nil))
+        (real-file (concat file "-" (nth 1 gnus-select-method))))
+    (if (or (file-exists-p real-file)
+           (file-exists-p (concat real-file ".el"))
+           (file-exists-p (concat real-file ".eld")))
+       real-file
+      file)))
+
+(defun gnus-newsrc-to-gnus-format ()
+  (setq gnus-newsrc-options "")
+  (setq gnus-newsrc-options-n nil)
+
+  (unless gnus-active-hashtb
+    (setq gnus-active-hashtb (gnus-make-hashtable 4096)))
+  (let ((buf (current-buffer))
+       (already-read (> (length gnus-newsrc-alist) 1))
+       group subscribed options-symbol newsrc Options-symbol
+       symbol reads num1)
+    (goto-char (point-min))
+    ;; We intern the symbol `options' in the active hashtb so that we
+    ;; can `eq' against it later.
+    (set (setq options-symbol (intern "options" gnus-active-hashtb)) nil)
+    (set (setq Options-symbol (intern "Options" gnus-active-hashtb)) nil)
+
+    (while (not (eobp))
+      ;; We first read the first word on the line by narrowing and
+      ;; then reading into `gnus-active-hashtb'.  Most groups will
+      ;; already exist in that hashtb, so this will save some string
+      ;; space.
+      (narrow-to-region
+       (point)
+       (progn (skip-chars-forward "^ \t!:\n") (point)))
+      (goto-char (point-min))
+      (setq symbol
+           (and (/= (point-min) (point-max))
+                (let ((obarray gnus-active-hashtb)) (read buf))))
+      (widen)
+      ;; Now, the symbol we have read is either `options' or a group
+      ;; name.  If it is an options line, we just add it to a string.
+      (cond
+       ((or (eq symbol options-symbol)
+           (eq symbol Options-symbol))
+       (setq gnus-newsrc-options
+             ;; This concatting is quite inefficient, but since our
+             ;; thorough studies show that approx 99.37% of all
+             ;; .newsrc files only contain a single options line, we
+             ;; don't give a damn, frankly, my dear.
+             (concat gnus-newsrc-options
+                     (buffer-substring
+                      (point-at-bol)
+                      ;; Options may continue on the next line.
+                      (or (and (re-search-forward "^[^ \t]" nil 'move)
+                               (point-at-bol))
+                          (point)))))
+       (forward-line -1))
+       (symbol
+       ;; Group names can be just numbers.
+       (when (numberp symbol)
+         (setq symbol (intern (int-to-string symbol) gnus-active-hashtb)))
+       (unless (boundp symbol)
+         (set symbol nil))
+       ;; It was a group name.
+       (setq subscribed (eq (char-after) ?:)
+             group (symbol-name symbol)
+             reads nil)
+       (if (eolp)
+           ;; If the line ends here, this is clearly a buggy line, so
+           ;; we put point a the beginning of line and let the cond
+           ;; below do the error handling.
+           (beginning-of-line)
+         ;; We skip to the beginning of the ranges.
+         (skip-chars-forward "!: \t"))
+       ;; We are now at the beginning of the list of read articles.
+       ;; We read them range by range.
+       (while
+           (cond
+            ((looking-at "[0-9]+")
+             ;; We narrow and read a number instead of buffer-substring/
+             ;; string-to-number because it's faster.  narrow/widen is
+             ;; faster than save-restriction/narrow, and save-restriction
+             ;; produces a garbage object.
+             (setq num1 (progn
+                          (narrow-to-region (match-beginning 0) (match-end 0))
+                          (read buf)))
+             (widen)
+             ;; If the next character is a dash, then this is a range.
+             (if (eq (char-after) ?-)
+                 (progn
+                   ;; We read the upper bound of the range.
+                   (forward-char 1)
+                   (if (not (looking-at "[0-9]+"))
+                       ;; This is a buggy line, by we pretend that
+                       ;; it's kinda OK.  Perhaps the user should be
+                       ;; dinged?
+                       (push num1 reads)
+                     (push
+                      (cons num1
+                            (progn
+                              (narrow-to-region (match-beginning 0)
+                                                (match-end 0))
+                              (read buf)))
+                      reads)
+                     (widen)))
+               ;; It was just a simple number, so we add it to the
+               ;; list of ranges.
+               (push num1 reads))
+             ;; If the next char in ?\n, then we have reached the end
+             ;; of the line and return nil.
+             (not (eq (char-after) ?\n)))
+            ((eq (char-after) ?\n)
+             ;; End of line, so we end.
+             nil)
+            (t
+             ;; Not numbers and not eol, so this might be a buggy
+             ;; line...
+             (unless (eobp)
+               ;; If it was eob instead of ?\n, we allow it.
+               ;; The line was buggy.
+               (setq group nil)
+               (gnus-error 3.1 "Mangled line: %s"
+                           (buffer-substring (point-at-bol)
+                                             (point-at-eol))))
+             nil))
+         ;; Skip past ", ".  Spaces are invalid in these ranges, but
+         ;; we allow them, because it's a common mistake to put a
+         ;; space after the comma.
+         (skip-chars-forward ", "))
+
+       ;; We have already read .newsrc.eld, so we gently update the
+       ;; data in the hash table with the information we have just
+       ;; read.
+       (when group
+         (let ((info (gnus-get-info group))
+               level)
+           (if info
+               ;; There is an entry for this file in the alist.
+               (progn
+                 (gnus-info-set-read info (nreverse reads))
+                 ;; We update the level very gently.  In fact, we
+                 ;; only change it if there's been a status change
+                 ;; from subscribed to unsubscribed, or vice versa.
+                 (setq level (gnus-info-level info))
+                 (cond ((and (<= level gnus-level-subscribed)
+                             (not subscribed))
+                        (setq level (if reads
+                                        gnus-level-default-unsubscribed
+                                      (1+ gnus-level-default-unsubscribed))))
+                       ((and (> level gnus-level-subscribed) subscribed)
+                        (setq level gnus-level-default-subscribed)))
+                 (gnus-info-set-level info level))
+             ;; This is a new group.
+             (setq info (list group
+                              (if subscribed
+                                  gnus-level-default-subscribed
+                                (if reads
+                                    (1+ gnus-level-subscribed)
+                                  gnus-level-default-unsubscribed))
+                              (nreverse reads))))
+           (push info newsrc)))))
+      (forward-line 1))
+
+    (setq newsrc (nreverse newsrc))
+
+    (if (not already-read)
+       ()
+      ;; We now have two newsrc lists - `newsrc', which is what we
+      ;; have read from .newsrc, and `gnus-newsrc-alist', which is
+      ;; what we've read from .newsrc.eld.  We have to merge these
+      ;; lists.  We do this by "attaching" any (foreign) groups in the
+      ;; gnus-newsrc-alist to the (native) group that precedes them.
+      (let ((rc (cdr gnus-newsrc-alist))
+           (prev gnus-newsrc-alist)
+           entry mentry)
+       (while rc
+         (or (null (nth 4 (car rc)))   ; It's a native group.
+             (assoc (caar rc) newsrc)  ; It's already in the alist.
+             (if (setq entry (assoc (caar prev) newsrc))
+                 (setcdr (setq mentry (memq entry newsrc))
+                         (cons (car rc) (cdr mentry)))
+               (push (car rc) newsrc)))
+         (setq prev rc
+               rc (cdr rc)))))
+
+    (setq gnus-newsrc-alist newsrc)
+    ;; We make the newsrc hashtb.
+    (gnus-make-hashtable-from-newsrc-alist)
+
+    ;; Finally, if we read some options lines, we parse them.
+    (unless (string= gnus-newsrc-options "")
+      (gnus-newsrc-parse-options gnus-newsrc-options))))
+
+;; Parse options lines to find "options -n !all rec.all" and stuff.
+;; The return value will be a list on the form
+;; ((regexp1 . ignore)
+;;  (regexp2 . subscribe)...)
+;; When handling new newsgroups, groups that match a `ignore' regexp
+;; will be ignored, and groups that match a `subscribe' regexp will be
+;; subscribed.  A line like
+;; options -n !all rec.all
+;; will lead to a list that looks like
+;; (("^rec\\..+" . subscribe)
+;;  ("^.+" . ignore))
+;; So all "rec.*" groups will be subscribed, while all the other
+;; groups will be ignored.  Note that "options -n !all rec.all" is very
+;; different from "options -n rec.all !all".
+(defun gnus-newsrc-parse-options (options)
+  (let (out eol)
+    (save-excursion
+      (gnus-set-work-buffer)
+      (insert (regexp-quote options))
+      ;; First we treat all continuation lines.
+      (goto-char (point-min))
+      (while (re-search-forward "\n[ \t]+" nil t)
+       (replace-match " " t t))
+      ;; Then we transform all "all"s into ".+"s.
+      (goto-char (point-min))
+      (while (re-search-forward "\\ball\\b" nil t)
+       (replace-match ".+" t t))
+      (goto-char (point-min))
+      ;; We remove all other options than the "-n" ones.
+      (while (re-search-forward "[ \t]-[^n][^-]*" nil t)
+       (replace-match " ")
+       (forward-char -1))
+      (goto-char (point-min))
+
+      ;; We are only interested in "options -n" lines - we
+      ;; ignore the other option lines.
+      (while (re-search-forward "[ \t]-n" nil t)
+       (setq eol
+             (or (save-excursion
+                   (and (re-search-forward "[ \t]-n" (point-at-eol) t)
+                        (- (point) 2)))
+                 (point-at-eol)))
+       ;; Search for all "words"...
+       (while (re-search-forward "[^ \t,\n]+" eol t)
+         (if (eq (char-after (match-beginning 0)) ?!)
+             ;; If the word begins with a bang (!), this is a "not"
+             ;; spec.  We put this spec (minus the bang) and the
+             ;; symbol `ignore' into the list.
+             (push (cons (concat
+                          "^" (buffer-substring
+                               (1+ (match-beginning 0))
+                               (match-end 0))
+                          "\\($\\|\\.\\)")
+                         'ignore)
+                   out)
+           ;; There was no bang, so this is a "yes" spec.
+           (push (cons (concat "^" (match-string 0) "\\($\\|\\.\\)")
+                       'subscribe)
+                 out))))
+
+      (setq gnus-newsrc-options-n out))))
+
+(eval-and-compile
+  (defalias 'gnus-long-file-names
+    (if (fboundp 'msdos-long-file-names)
+      'msdos-long-file-names
+      (lambda () t))))
+
+(defvar gnus-save-newsrc-file-last-timestamp nil)
+(defun gnus-save-newsrc-file (&optional force)
+  "Save .newsrc file."
+  ;; Note: We cannot save .newsrc file if all newsgroups are removed
+  ;; from the variable gnus-newsrc-alist.
+  (when (and (or gnus-newsrc-alist gnus-killed-list)
+            gnus-current-startup-file)
+    ;; Save agent range limits for the currently active method.
+    (when gnus-agent
+      (gnus-agent-save-local force))
+
+    (save-excursion
+      (if (and (or gnus-use-dribble-file gnus-slave)
+              (not force)
+              (or (not gnus-dribble-buffer)
+                  (not (buffer-name gnus-dribble-buffer))
+                  (zerop (with-current-buffer gnus-dribble-buffer
+                           (buffer-size)))))
+         (gnus-message 4 "(No changes need to be saved)")
+       (gnus-run-hooks 'gnus-save-newsrc-hook)
+       (if gnus-slave
+           (gnus-slave-save-newsrc)
+         ;; Save .newsrc.
+         (when gnus-save-newsrc-file
+           (gnus-message 8 "Saving %s..." gnus-current-startup-file)
+           (gnus-gnus-to-newsrc-format)
+           (gnus-message 8 "Saving %s...done" gnus-current-startup-file))
+
+         ;; Save .newsrc.eld.
+         (set-buffer (gnus-get-buffer-create " *Gnus-newsrc*"))
+         (make-local-variable 'version-control)
+         (setq version-control gnus-backup-startup-file)
+         (setq buffer-file-name
+               (concat gnus-current-startup-file ".eld"))
+         (setq default-directory (file-name-directory buffer-file-name))
+         (buffer-disable-undo)
+         (erase-buffer)
+          (gnus-message 5 "Saving %s.eld..." gnus-current-startup-file)
+
+          ;; check timestamp of `gnus-current-startup-file'.eld against
+          ;; `gnus-save-newsrc-file-last-timestamp'
+          (let* ((checkfile (concat gnus-current-startup-file ".eld"))
+                 (mtime (nth 5 (file-attributes checkfile))))
+            (when (and gnus-save-newsrc-file-last-timestamp
+                       (time-less-p gnus-save-newsrc-file-last-timestamp
+                                    mtime))
+              (unless (y-or-n-p
+                       (format "%s was updated externally after %s, save?"
+                               checkfile
+                               (format-time-string
+                                "%c"
+                                gnus-save-newsrc-file-last-timestamp)))
+                (error "Couldn't save %s: updated externally" checkfile))))
+
+          (if gnus-save-startup-file-via-temp-buffer
+              (let ((coding-system-for-write gnus-ding-file-coding-system)
+                    (standard-output (current-buffer)))
+                (gnus-gnus-to-quick-newsrc-format)
+                (gnus-run-hooks 'gnus-save-quick-newsrc-hook)
+                (save-buffer)
+                (setq gnus-save-newsrc-file-last-timestamp
+                            (nth 5 (file-attributes buffer-file-name))))
+            (let ((coding-system-for-write gnus-ding-file-coding-system)
+                  (version-control gnus-backup-startup-file)
+                  (startup-file (concat gnus-current-startup-file ".eld"))
+                  (working-dir (file-name-directory gnus-current-startup-file))
+                  working-file
+                  (i -1))
+              ;; Generate the name of a non-existent file.
+              (while (progn (setq working-file
+                                  (format
+                                   (if (and (eq system-type 'ms-dos)
+                                            (not (gnus-long-file-names)))
+                                       "%s#%d.tm#" ; MSDOS limits files to 8+3
+                                    "%s#tmp#%d")
+                                   working-dir (setq i (1+ i))))
+                            (file-exists-p working-file)))
+
+              (unwind-protect
+                  (progn
+                    (gnus-with-output-to-file working-file
+                     (gnus-gnus-to-quick-newsrc-format)
+                     (gnus-run-hooks 'gnus-save-quick-newsrc-hook))
+
+                    ;; These bindings will mislead the current buffer
+                    ;; into thinking that it is visiting the startup
+                    ;; file.
+                    (let ((buffer-backed-up nil)
+                          (buffer-file-name startup-file)
+                          (file-precious-flag t)
+                          (setmodes (file-modes startup-file)))
+                      ;; Backup the current version of the startup file.
+                      (backup-buffer)
+
+                      ;; Replace the existing startup file with the temp file.
+                      (rename-file working-file startup-file t)
+                      (gnus-set-file-modes startup-file setmodes)
+                      (setq gnus-save-newsrc-file-last-timestamp
+                            (nth 5 (file-attributes startup-file)))))
+                (condition-case nil
+                    (delete-file working-file)
+                  (file-error nil)))))
+
+         (gnus-kill-buffer (current-buffer))
+         (gnus-message
+          5 "Saving %s.eld...done" gnus-current-startup-file))
+       (gnus-dribble-delete-file)
+       (gnus-group-set-mode-line)))))
+
+(defun gnus-gnus-to-quick-newsrc-format (&optional minimal name &rest specific-variables)
+  "Print Gnus variables such as `gnus-newsrc-alist' in Lisp format."
+    (princ (format ";; -*- mode:emacs-lisp; coding: %s; -*-\n"
+                  gnus-ding-file-coding-system))
+    (if name
+       (princ (format ";; %s\n" name))
+      (princ ";; Gnus startup file.\n"))
+
+    (unless minimal
+      (princ "\
+;; Never delete this file -- if you want to force Gnus to read the
+;; .newsrc file (if you have one), touch .newsrc instead.\n")
+      (princ "(setq gnus-newsrc-file-version ")
+      (princ (gnus-prin1-to-string gnus-version))
+      (princ ")\n"))
+
+    (let* ((print-quoted t)
+           (print-readably t)
+           (print-escape-multibyte nil)
+           (print-escape-nonascii t)
+           (print-length nil)
+           (print-level nil)
+          (print-circle nil)
+           (print-escape-newlines t)
+          (gnus-killed-list
+           (if (and gnus-save-killed-list
+                    (stringp gnus-save-killed-list))
+               (gnus-strip-killed-list)
+             gnus-killed-list))
+          (variables
+           (or specific-variables
+               (if gnus-save-killed-list gnus-variable-list
+                 ;; Remove the `gnus-killed-list' from the list of variables
+                 ;; to be saved, if required.
+                 (delq 'gnus-killed-list (copy-sequence gnus-variable-list)))))
+          ;; Peel off the "dummy" group.
+          (gnus-newsrc-alist (cdr gnus-newsrc-alist))
+          variable)
+      ;; Insert the variables into the file.
+      (while variables
+       (when (and (boundp (setq variable (pop variables)))
+                  (symbol-value variable))
+         (princ "\n(setq ")
+          (princ (symbol-name variable))
+          (princ " '")
+         (prin1 (symbol-value variable))
+         (princ ")\n")))))
+
+(defun gnus-strip-killed-list ()
+  "Return the killed list minus the groups that match `gnus-save-killed-list'."
+  (let ((list gnus-killed-list)
+       olist)
+    (while list
+      (when (string-match gnus-save-killed-list (car list))
+       (push (car list) olist))
+      (pop list))
+    (nreverse olist)))
+
+(defun gnus-gnus-to-newsrc-format (&optional foreign-ok)
+  (interactive (list (gnus-y-or-n-p "write foreign groups too? ")))
+  ;; Generate and save the .newsrc file.
+  (with-current-buffer (create-file-buffer gnus-current-startup-file)
+    (let ((newsrc (cdr gnus-newsrc-alist))
+         (standard-output (current-buffer))
+         info ranges range method)
+      (setq buffer-file-name gnus-current-startup-file)
+      (setq default-directory (file-name-directory buffer-file-name))
+      (buffer-disable-undo)
+      (erase-buffer)
+      ;; Use a unibyte buffer since group names are unibyte strings;
+      ;; in particular, non-ASCII group names are the ones encoded by
+      ;; a certain coding system.
+      (mm-disable-multibyte)
+      ;; Write options.
+      (when gnus-newsrc-options
+       (insert gnus-newsrc-options))
+      ;; Write subscribed and unsubscribed.
+      (while (setq info (pop newsrc))
+       ;; Don't write foreign groups to .newsrc.
+       (when (or (null (setq method (gnus-info-method info)))
+                 (equal method "native")
+                 (inline (gnus-server-equal method gnus-select-method))
+                  foreign-ok)
+         (insert (gnus-info-group info)
+                 (if (> (gnus-info-level info) gnus-level-subscribed)
+                     "!" ":"))
+         (when (setq ranges (gnus-info-read info))
+           (insert " ")
+           (if (not (listp (cdr ranges)))
+               (if (= (car ranges) (cdr ranges))
+                   (princ (car ranges))
+                 (princ (car ranges))
+                 (insert "-")
+                 (princ (cdr ranges)))
+             (while (setq range (pop ranges))
+               (if (or (atom range) (= (car range) (cdr range)))
+                   (princ (or (and (atom range) range) (car range)))
+                 (princ (car range))
+                 (insert "-")
+                 (princ (cdr range)))
+               (when ranges
+                 (insert ",")))))
+         (insert "\n")))
+      (make-local-variable 'version-control)
+      (setq version-control 'never)
+      ;; It has been reported that sometime the modtime on the .newsrc
+      ;; file seems to be off.  We really do want to overwrite it, so
+      ;; we clear the modtime here before saving.  It's a bit odd,
+      ;; though...
+      ;; sometimes the modtime clear isn't sufficient.  most brute force:
+      ;; delete the silly thing entirely first.  but this fails to provide
+      ;; such niceties as .newsrc~ creation.
+      (if gnus-modtime-botch
+         (delete-file gnus-startup-file)
+       (clear-visited-file-modtime))
+      (gnus-run-hooks 'gnus-save-standard-newsrc-hook)
+      (let ((coding-system-for-write 'raw-text))
+       (save-buffer))
+      (kill-buffer (current-buffer)))))
+
+\f
+;;;
+;;; Slave functions.
+;;;
+
+(defvar gnus-slave-mode nil)
+
+(defun gnus-slave-mode ()
+  "Minor mode for slave Gnusae."
+  ;; FIXME: gnus-slave-mode appears to never be set (i.e. it'll always be nil):
+  ;; Remove, or fix and use define-minor-mode.
+  (add-minor-mode 'gnus-slave-mode " Slave" (make-sparse-keymap))
+  (gnus-run-hooks 'gnus-slave-mode-hook))
+
+(defun gnus-slave-save-newsrc ()
+  (with-current-buffer gnus-dribble-buffer
+    (let ((slave-name
+          (mm-make-temp-file (concat gnus-current-startup-file "-slave-")))
+         (modes (ignore-errors
+                  (file-modes (concat gnus-current-startup-file ".eld")))))
+      (let ((coding-system-for-write gnus-ding-file-coding-system))
+       (gnus-write-buffer slave-name))
+      (when modes
+       (gnus-set-file-modes slave-name modes)))))
+
+(defun gnus-master-read-slave-newsrc ()
+  (let ((slave-files
+        (directory-files
+         (file-name-directory gnus-current-startup-file)
+         t (concat
+            "^" (regexp-quote
+                 (concat
+                  (file-name-nondirectory gnus-current-startup-file)
+                  "-slave-")))
+         t))
+       file)
+    (if (not slave-files)
+       ()                              ; There are no slave files to read.
+      (gnus-message 7 "Reading slave newsrcs...")
+      (with-current-buffer (gnus-get-buffer-create " *gnus slave*")
+       (setq slave-files
+             (sort (mapcar (lambda (file)
+                             (list (nth 5 (file-attributes file)) file))
+                           slave-files)
+                   (lambda (f1 f2)
+                     (or (< (caar f1) (caar f2))
+                         (< (nth 1 (car f1)) (nth 1 (car f2)))))))
+       (while slave-files
+         (erase-buffer)
+         (setq file (nth 1 (car slave-files)))
+         (nnheader-insert-file-contents file)
+         (when (condition-case ()
+                   (progn
+                     (eval-buffer (current-buffer))
+                     t)
+                 (error
+                  (gnus-error 3.2 "Possible error in %s" file)
+                  nil))
+           (unless gnus-slave          ; Slaves shouldn't delete these files.
+             (ignore-errors
+               (delete-file file))))
+         (setq slave-files (cdr slave-files))))
+      (gnus-dribble-touch)
+      (gnus-message 7 "Reading slave newsrcs...done"))))
+
+\f
+;;;
+;;; Group description.
+;;;
+
+(defun gnus-read-all-descriptions-files ()
+  (let ((methods (cons gnus-select-method
+                      (nconc
+                       (when (gnus-archive-server-wanted-p)
+                         (list "archive"))
+                       gnus-secondary-select-methods))))
+    (while methods
+      (gnus-read-descriptions-file (car methods))
+      (setq methods (cdr methods)))
+    t))
+
+(defun gnus-read-descriptions-file (&optional method)
+  (let ((method (or method gnus-select-method))
+       group)
+    (when (stringp method)
+      (setq method (gnus-server-to-method method)))
+    ;; We create the hashtable whether we manage to read the desc file
+    ;; to avoid trying to re-read after a failed read.
+    (unless gnus-description-hashtb
+      (setq gnus-description-hashtb
+           (gnus-make-hashtable (length gnus-active-hashtb))))
+    ;; Mark this method's desc file as read.
+    (gnus-sethash (gnus-group-prefixed-name "" method) "Has read"
+                 gnus-description-hashtb)
+
+    (gnus-message 5 "Reading descriptions file via %s..." (car method))
+    (cond
+     ((null (gnus-get-function method 'request-list-newsgroups t))
+      t)
+     ((not (gnus-check-server method))
+      (gnus-message 1 "Couldn't open server")
+      nil)
+     ((not (gnus-request-list-newsgroups method))
+      (gnus-message 1 "Couldn't read newsgroups descriptions")
+      nil)
+     (t
+      (save-excursion
+        ;; FIXME: Shouldn't save-restriction be done after set-buffer?
+       (save-restriction
+         (set-buffer nntp-server-buffer)
+         (goto-char (point-min))
+         (when (or (search-forward "\n.\n" nil t)
+                   (goto-char (point-max)))
+           (beginning-of-line)
+           (narrow-to-region (point-min) (point)))
+         ;; If these are groups from a foreign select method, we insert the
+         ;; group prefix in front of the group names.
+         (and method (not (inline
+                            (gnus-server-equal
+                             (gnus-server-get-method nil method)
+                             (gnus-server-get-method
+                              nil gnus-select-method))))
+              (let ((prefix (gnus-group-prefixed-name "" method)))
+                (goto-char (point-min))
+                (while (and (not (eobp))
+                            (progn (insert prefix)
+                                   (zerop (forward-line 1)))))))
+         (goto-char (point-min))
+         (while (not (eobp))
+           ;; If we get an error, we set group to 0, which is not a
+           ;; symbol...
+           (setq group
+                 (condition-case ()
+                     (let ((obarray gnus-description-hashtb))
+                       ;; Group is set to a symbol interned in this
+                       ;; hash table.
+                       (read nntp-server-buffer))
+                   (error 0)))
+           (skip-chars-forward " \t")
+           ;; ...  which leads to this line being effectively ignored.
+           (when (symbolp group)
+             (let* ((str (buffer-substring
+                          (point) (progn (end-of-line) (point))))
+                    (name (symbol-name group))
+                    (charset
+                     (or (gnus-group-name-charset method name)
+                         (gnus-parameter-charset name)
+                         gnus-default-charset)))
+               ;; Fixme: Don't decode in unibyte mode.
+               (when (and str charset (featurep 'mule))
+                 (setq str (mm-decode-coding-string str charset)))
+               (set group str)))
+           (forward-line 1))))
+      (gnus-message 5 "Reading descriptions file...done")
+      t))))
+
+(defun gnus-group-get-description (group)
+  "Get the description of a group by sending XGTITLE to the server."
+  (when (gnus-request-group-description group)
+    (with-current-buffer nntp-server-buffer
+      (goto-char (point-min))
+      (when (looking-at "[^ \t]+[ \t]+\\(.*\\)")
+       (match-string 1)))))
+
+;;;###autoload
+(defun gnus-declare-backend (name &rest abilities)
+  "Declare back end NAME with ABILITIES as a Gnus back end."
+  (setq gnus-valid-select-methods
+       (nconc gnus-valid-select-methods
+              (list (apply 'list name abilities))))
+  (gnus-redefine-select-method-widget))
+
+(defun gnus-set-default-directory ()
+  "Set the default directory in the current buffer to `gnus-default-directory'.
+If this variable is nil, don't do anything."
+  (setq default-directory
+       (if (and gnus-default-directory
+                (file-exists-p gnus-default-directory))
+           (file-name-as-directory (expand-file-name gnus-default-directory))
+         default-directory)))
+
+(defun gnus-display-time-event-handler ()
+  (if (and (fboundp 'display-time-event-handler)
+          (gnus-boundp 'display-time-timer))
+      (display-time-event-handler)))
+
+(defun gnus-check-reasonable-setup ()
+  ;; Check whether nnml and nnfolder share a directory.
+  (let ((display-warn
+        (if (fboundp 'display-warning)
+            'display-warning
+          (lambda (type message)
+            (if noninteractive
+                (message "Warning (%s): %s" type message)
+              (let (window)
+                (with-current-buffer (get-buffer-create "*Warnings*")
+                  (goto-char (point-max))
+                  (unless (bolp)
+                    (insert "\n"))
+                  (insert (format "Warning (%s): %s\n" type message))
+                  (setq window (display-buffer (current-buffer)))
+                  (set-window-start
+                   window
+                   (prog2
+                       (forward-line (- 1 (window-height window)))
+                       (point)
+                     (goto-char (point-max))))))))))
+       method active actives match)
+    (dolist (server gnus-server-alist)
+      (setq method (gnus-server-to-method server)
+           active (intern (format "%s-active-file" (car method))))
+      (when (and (member (car method) '(nnml nnfolder))
+                (gnus-server-opened method)
+                (boundp active))
+       (when (setq match (assoc (symbol-value active) actives))
+         (funcall display-warn 'gnus-server
+                  (format "%s and %s share the same active file %s"
+                          (car method)
+                          (cadr match)
+                          (car match))))
+       (push (list (symbol-value active) method) actives)))))
+
+(provide 'gnus-start)
+
+;;; gnus-start.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-sum.el b/xemacs-packages/gnus/lisp/gnus-sum.el
new file mode 100644 (file)
index 0000000..3dbcc21
--- /dev/null
@@ -0,0 +1,13127 @@
+;;; gnus-sum.el --- summary mode commands for Gnus
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile
+  (require 'cl))
+(eval-when-compile
+  (when (featurep 'xemacs)
+    (require 'easy-mmode))) ; for `define-minor-mode'
+
+(defvar tool-bar-mode)
+(defvar gnus-tmp-header)
+
+(require 'gnus)
+(require 'gnus-group)
+(require 'gnus-spec)
+(require 'gnus-range)
+(require 'gnus-int)
+(require 'gnus-undo)
+(require 'gnus-util)
+(require 'gmm-utils)
+(require 'mm-decode)
+(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)
+(autoload 'turn-on-gnus-mailing-list-mode "gnus-ml" nil t)
+(autoload 'gnus-pick-line-number "gnus-salt" nil t)
+(autoload 'mm-uu-dissect "mm-uu")
+(autoload 'gnus-article-outlook-deuglify-article "deuglify"
+  "Deuglify broken Outlook (Express) articles and redisplay."
+  t)
+(autoload 'gnus-article-outlook-unwrap-lines "deuglify" nil t)
+(autoload 'gnus-article-outlook-repair-attribution "deuglify" nil t)
+(autoload 'gnus-article-outlook-rearrange-citation "deuglify" nil t)
+(autoload 'nnir-article-rsv "nnir" nil nil 'macro)
+(autoload 'nnir-article-group "nnir" nil nil 'macro)
+
+(defcustom gnus-kill-summary-on-exit t
+  "*If non-nil, kill the summary buffer when you exit from it.
+If nil, the summary will become a \"*Dead Summary*\" buffer, and
+it will be killed sometime later."
+  :group 'gnus-summary-exit
+  :type 'boolean)
+
+(defcustom gnus-summary-next-group-on-exit t
+  "If non-nil, go to the next unread newsgroup on summary exit.
+See `gnus-group-goto-unread'."
+  :link '(custom-manual "(gnus)Group Maneuvering")
+  :group 'gnus-summary-exit
+  :version "23.1" ;; No Gnus
+  :type 'boolean)
+
+(defcustom gnus-summary-stop-at-end-of-message nil
+  "If non-nil, don't select the next message when using `SPC'."
+  :link '(custom-manual "(gnus)Group Maneuvering")
+  :group 'gnus-summary-maneuvering
+  :version "24.1"
+  :type 'boolean)
+
+(defcustom gnus-fetch-old-headers nil
+  "*Non-nil means that Gnus will try to build threads by grabbing old headers.
+If an unread article in the group refers to an older, already
+read (or just marked as read) article, the old article will not
+normally be displayed in the Summary buffer.  If this variable is
+t, Gnus will attempt to grab the headers to the old articles, and
+thereby build complete threads.  If it has the value `some', all
+old headers will be fetched but only enough headers to connect
+otherwise loose threads will be displayed.  This variable can
+also be a number.  In that case, no more than that number of old
+headers will be fetched.  If it has the value `invisible', all
+old headers will be fetched, but none will be displayed.
+
+The server has to support NOV for any of this to work.
+
+This feature can seriously impact performance it ignores all
+locally cached header entries.  Setting it to t for groups for a
+server that doesn't expire articles (such as news.gmane.org),
+leads to very slow summary generation."
+  :group 'gnus-thread
+  :type '(choice (const :tag "off" nil)
+                (const :tag "on" t)
+                (const some)
+                (const invisible)
+                number
+                (sexp :menu-tag "other" t)))
+
+(defcustom gnus-refer-thread-limit 500
+  "*The number of old headers to fetch when doing \\<gnus-summary-mode-map>\\[gnus-summary-refer-thread].
+If t, fetch all the available old headers."
+  :group 'gnus-thread
+  :type '(choice number
+                (sexp :menu-tag "other" t)))
+
+(defcustom gnus-refer-thread-use-nnir nil
+  "*Use nnir to search an entire server when referring threads. A
+nil value will only search for thread-related articles in the
+current group."
+  :version "24.1"
+  :group 'gnus-thread
+  :type 'boolean)
+
+(defcustom gnus-summary-make-false-root 'adopt
+  "*nil means that Gnus won't gather loose threads.
+If the root of a thread has expired or been read in a previous
+session, the information necessary to build a complete thread has been
+lost.  Instead of having many small sub-threads from this original thread
+scattered all over the summary buffer, Gnus can gather them.
+
+If non-nil, Gnus will try to gather all loose sub-threads from an
+original thread into one large thread.
+
+If this variable is non-nil, it should be one of `none', `adopt',
+`dummy' or `empty'.
+
+If this variable is `none', Gnus will not make a false root, but just
+present the sub-threads after another.
+If this variable is `dummy', Gnus will create a dummy root that will
+have all the sub-threads as children.
+If this variable is `adopt', Gnus will make one of the \"children\"
+the parent and mark all the step-children as such.
+If this variable is `empty', the \"children\" are printed with empty
+subject fields.  (Or rather, they will be printed with a string
+given by the `gnus-summary-same-subject' variable.)"
+  :group 'gnus-thread
+  :type '(choice (const :tag "off" nil)
+                (const none)
+                (const dummy)
+                (const adopt)
+                (const empty)))
+
+(defcustom gnus-summary-make-false-root-always nil
+  "Always make a false dummy root."
+  :version "22.1"
+  :group 'gnus-thread
+  :type 'boolean)
+
+(defcustom gnus-summary-gather-exclude-subject "^ *$\\|^(none)$"
+  "*A regexp to match subjects to be excluded from loose thread gathering.
+As loose thread gathering is done on subjects only, that means that
+there can be many false gatherings performed.  By rooting out certain
+common subjects, gathering might become saner."
+  :group 'gnus-thread
+  :type 'regexp)
+
+(defcustom gnus-summary-gather-subject-limit nil
+  "*Maximum length of subject comparisons when gathering loose threads.
+Use nil to compare full subjects.  Setting this variable to a low
+number will help gather threads that have been corrupted by
+newsreaders chopping off subject lines, but it might also mean that
+unrelated articles that have subject that happen to begin with the
+same few characters will be incorrectly gathered.
+
+If this variable is `fuzzy', Gnus will use a fuzzy algorithm when
+comparing subjects."
+  :group 'gnus-thread
+  :type '(choice (const :tag "off" nil)
+                (const fuzzy)
+                (sexp :menu-tag "on" t)))
+
+(defcustom gnus-simplify-subject-functions nil
+  "List of functions taking a string argument that simplify subjects.
+The functions are applied recursively.
+
+Useful functions to put in this list include:
+`gnus-simplify-subject-re', `gnus-simplify-subject-fuzzy',
+`gnus-simplify-whitespace', and `gnus-simplify-all-whitespace'."
+  :group 'gnus-thread
+  :type '(repeat function))
+
+(defcustom gnus-simplify-ignored-prefixes nil
+  "*Remove matches for this regexp from subject lines when simplifying fuzzily."
+  :group 'gnus-thread
+  :type '(choice (const :tag "off" nil)
+                regexp))
+
+(defcustom gnus-build-sparse-threads nil
+  "*If non-nil, fill in the gaps in threads.
+If `some', only fill in the gaps that are needed to tie loose threads
+together.  If `more', fill in all leaf nodes that Gnus can find.  If
+non-nil and non-`some', fill in all gaps that Gnus manages to guess."
+  :group 'gnus-thread
+  :type '(choice (const :tag "off" nil)
+                (const some)
+                (const more)
+                (sexp :menu-tag "all" t)))
+
+(defcustom gnus-summary-thread-gathering-function
+  'gnus-gather-threads-by-subject
+  "*Function used for gathering loose threads.
+There are two pre-defined functions: `gnus-gather-threads-by-subject',
+which only takes Subjects into consideration; and
+`gnus-gather-threads-by-references', which compared the References
+headers of the articles to find matches."
+  :group 'gnus-thread
+  :type '(radio (function-item gnus-gather-threads-by-subject)
+               (function-item gnus-gather-threads-by-references)
+               (function :tag "other")))
+
+(defcustom gnus-summary-same-subject ""
+  "*String indicating that the current article has the same subject as the previous.
+This variable will only be used if the value of
+`gnus-summary-make-false-root' is `empty'."
+  :group 'gnus-summary-format
+  :type 'string)
+
+(defcustom gnus-summary-goto-unread nil
+  "*If t, many commands will go to the next unread article.
+This applies to marking commands as well as other commands that
+\"naturally\" select the next article, like, for instance, `SPC' at
+the end of an article.
+
+If nil, the marking commands do NOT go to the next unread article
+\(they go to the next article instead).  If `never', commands that
+usually go to the next unread article, will go to the next article,
+whether it is read or not."
+  :version "24.1"
+  :group 'gnus-summary-marks
+  :link '(custom-manual "(gnus)Setting Marks")
+  :type '(choice (const :tag "off" nil)
+                (const never)
+                (sexp :menu-tag "on" t)))
+
+(defcustom gnus-summary-default-score 0
+  "*Default article score level.
+All scores generated by the score files will be added to this score.
+If this variable is nil, scoring will be disabled."
+  :group 'gnus-score-default
+  :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."
+  :version "22.1"
+  :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."
+  :version "22.1"
+  :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'
+will not be marked."
+  :group 'gnus-summary-format
+  :type 'integer)
+
+(defcustom gnus-simplify-subject-fuzzy-regexp nil
+  "*Strings to be removed when doing fuzzy matches.
+This can either be a regular expression or list of regular expressions
+that will be removed from subject strings if fuzzy subject
+simplification is selected."
+  :group 'gnus-thread
+  :type '(repeat regexp))
+
+(defcustom gnus-show-threads t
+  "*If non-nil, display threads in summary mode."
+  :group 'gnus-thread
+  :type 'boolean)
+
+(defcustom gnus-thread-hide-subtree nil
+  "*If non-nil, hide all threads initially.
+This can be a predicate specifier which says which threads to hide.
+If threads are hidden, you have to run the command
+`gnus-summary-show-thread' by hand or select an article."
+  :group 'gnus-thread
+  :type '(radio (sexp :format "Non-nil\n"
+                     :match (lambda (widget value)
+                              (not (or (consp value) (functionp value))))
+                     :value t)
+               (const nil)
+               (sexp :tag "Predicate specifier")))
+
+(defcustom gnus-thread-hide-killed t
+  "*If non-nil, hide killed threads automatically."
+  :group 'gnus-thread
+  :type 'boolean)
+
+(defcustom gnus-thread-ignore-subject t
+  "*If non-nil, which is the default, ignore subjects and do all threading based on the Reference header.
+If nil, articles that have different subjects from their parents will
+start separate threads."
+  :group 'gnus-thread
+  :type 'boolean)
+
+(defcustom gnus-thread-operation-ignore-subject t
+  "*If non-nil, subjects will be ignored when doing thread commands.
+This affects commands like `gnus-summary-kill-thread' and
+`gnus-summary-lower-thread'.
+
+If this variable is nil, articles in the same thread with different
+subjects will not be included in the operation in question.  If this
+variable is `fuzzy', only articles that have subjects that are fuzzily
+equal will be included."
+  :group 'gnus-thread
+  :type '(choice (const :tag "off" nil)
+                (const fuzzy)
+                (sexp :tag "on" t)))
+
+(defcustom gnus-thread-indent-level 4
+  "*Number that says how much each sub-thread should be indented."
+  :group 'gnus-thread
+  :type 'integer)
+
+(defcustom gnus-auto-extend-newsgroup t
+  "*If non-nil, extend newsgroup forward and backward when requested."
+  :group 'gnus-summary-choose
+  :type 'boolean)
+
+(defcustom gnus-auto-select-first t
+  "If non-nil, select an article on group entry.
+An article is selected automatically when entering a group
+e.g. with \\<gnus-group-mode-map>\\[gnus-group-read-group], or via `gnus-summary-next-page' or
+`gnus-summary-catchup-and-goto-next-group'.
+
+Which article is selected is controlled by the variable
+`gnus-auto-select-subject'.
+
+If you want to prevent automatic selection of articles in some
+newsgroups, set the variable to nil in `gnus-select-group-hook'."
+  ;; Commands include...
+  ;; \\<gnus-group-mode-map>\\[gnus-group-read-group]
+  ;; \\<gnus-summary-mode-map>\\[gnus-summary-next-page]
+  ;; \\<gnus-summary-mode-map>\\[gnus-summary-catchup-and-goto-next-group]
+  :group 'gnus-group-select
+  :type '(choice (const :tag "none" nil)
+                (sexp :menu-tag "first" t)))
+
+(defcustom gnus-auto-select-subject 'unseen-or-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
+highest-scored article), `unseen' (place point on the subject line of
+the first unseen article), `unseen-or-unread' (place point on the subject
+line of the first unseen article or, if all articles have been seen, on the
+subject line of the first unread article), or a function to be called to
+place point on some subject line."
+  :version "24.1"
+  :group 'gnus-group-select
+  :type '(choice (const best)
+                (const unread)
+                (const first)
+                (const unseen)
+                (const unseen-or-unread)
+                (function :tag "Function to call")))
+
+(defcustom gnus-auto-select-next t
+  "*If non-nil, offer to go to the next group from the end of the previous.
+If the value is t and the next newsgroup is empty, Gnus will exit
+summary mode and go back to group mode.  If the value is neither nil
+nor t, Gnus will select the following unread newsgroup.  In
+particular, if the value is the symbol `quietly', the next unread
+newsgroup will be selected without any confirmation, and if it is
+`almost-quietly', the next group will be selected without any
+confirmation if you are located on the last article in the group.
+Finally, if this variable is `slightly-quietly', the `\\<gnus-summary-mode-map>\\[gnus-summary-catchup-and-goto-next-group]' command
+will go to the next group without confirmation."
+  :group 'gnus-summary-maneuvering
+  :type '(choice (const :tag "off" nil)
+                (const quietly)
+                (const almost-quietly)
+                (const slightly-quietly)
+                (sexp :menu-tag "on" t)))
+
+(defcustom gnus-auto-select-same nil
+  "*If non-nil, select the next article with the same subject.
+If there are no more articles with the same subject, go to
+the first unread article."
+  :group 'gnus-summary-maneuvering
+  :type 'boolean)
+
+(defcustom gnus-auto-select-on-ephemeral-exit 'next-noselect
+  "What article should be selected after exiting an ephemeral group.
+Valid values include:
+
+`next'
+  Select the next article.
+`next-unread'
+  Select the next unread article.
+`next-noselect'
+  Move the cursor to the next article.  This is the default.
+`next-unread-noselect'
+  Move the cursor to the next unread article.
+
+If it has any other value or there is no next (unread) article, the
+article selected before entering to the ephemeral group will appear."
+  :version "23.1" ;; No Gnus
+  :group 'gnus-summary-maneuvering
+  :type '(choice :format "%{%t%}:\n %[Value Menu%] %v"
+                (const next) (const next-unread)
+                (const next-noselect) (const next-unread-noselect)
+                (sexp :tag "other" :value nil)))
+
+(defcustom gnus-auto-goto-ignores 'unfetched
+  "*Says how to handle unfetched articles when maneuvering.
+
+This variable can either be the symbols nil (maneuver to any
+article), `undownloaded' (maneuvering while unplugged ignores articles
+that have not been fetched), `always-undownloaded' (maneuvering always
+ignores articles that have not been fetched), `unfetched' (maneuvering
+ignores articles whose headers have not been fetched).
+
+NOTE: The list of unfetched articles will always be nil when plugged
+and, when unplugged, a subset of the undownloaded article list."
+  :version "22.1"
+  :group 'gnus-summary-maneuvering
+  :type '(choice (const :tag "None" nil)
+                 (const :tag "Undownloaded when unplugged" undownloaded)
+                 (const :tag "Undownloaded" always-undownloaded)
+                 (const :tag "Unfetched" unfetched)))
+
+(defcustom gnus-summary-check-current nil
+  "*If non-nil, consider the current article when moving.
+The \"unread\" movement commands will stay on the same line if the
+current article is unread."
+  :group 'gnus-summary-maneuvering
+  :type 'boolean)
+
+(defcustom gnus-auto-center-summary
+  (max (or (bound-and-true-p scroll-margin) 0) 2)
+  "*If non-nil, always center the current summary buffer.
+In particular, if `vertical' do only vertical recentering.  If non-nil
+and non-`vertical', do both horizontal and vertical recentering."
+  :group 'gnus-summary-maneuvering
+  :type '(choice (const :tag "none" nil)
+                (const vertical)
+                (integer :tag "height")
+                (sexp :menu-tag "both" t)))
+
+(defcustom gnus-auto-center-group t
+  "If non-nil, always center the group buffer."
+  :group 'gnus-summary-maneuvering
+  :type 'boolean)
+
+(defcustom gnus-show-all-headers nil
+  "*If non-nil, don't hide any headers."
+  :group 'gnus-article-hiding
+  :group 'gnus-article-headers
+  :type 'boolean)
+
+(defcustom gnus-summary-ignore-duplicates nil
+  "*If non-nil, ignore articles with identical Message-ID headers."
+  :group 'gnus-summary
+  :type 'boolean)
+
+(defcustom gnus-single-article-buffer nil
+  "*If non-nil, display all articles in the same buffer.
+If nil, each group will get its own article buffer."
+  :version "24.1"
+  :group 'gnus-article-various
+  :type 'boolean)
+
+(defcustom gnus-widen-article-window nil
+  "If non-nil, selecting the article buffer will display only the article buffer."
+  :version "24.1"
+  :group 'gnus-article-various
+  :type 'boolean)
+
+(defcustom gnus-break-pages t
+  "*If non-nil, do page breaking on articles.
+The page delimiter is specified by the `gnus-page-delimiter'
+variable."
+  :group 'gnus-article-various
+  :type 'boolean)
+
+(defcustom gnus-move-split-methods nil
+  "*Variable used to suggest where articles are to be moved to.
+It uses the same syntax as the `gnus-split-methods' variable.
+However, whereas `gnus-split-methods' specifies file names as targets,
+this variable specifies group names."
+  :group 'gnus-summary-mail
+  :type '(repeat (choice (list :value (fun) function)
+                        (cons :value ("" "") regexp (repeat string))
+                        (sexp :value nil))))
+
+(defcustom gnus-move-group-prefix-function 'gnus-group-real-prefix
+  "Function used to compute default prefix for article move/copy/etc prompts.
+The function should take one argument, a group name, and return a
+string with the suggested prefix."
+  :group 'gnus-summary-mail
+  :type 'function)
+
+;; FIXME: Although the custom type is `character' for the following variables,
+;; using multibyte characters (Latin-1, UTF-8) doesn't work.  -- rs
+
+(defcustom gnus-unread-mark ?           ;Whitespace
+  "*Mark used for unread articles."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-ticked-mark ?!
+  "*Mark used for ticked articles."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-dormant-mark ??
+  "*Mark used for dormant articles."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-del-mark ?r
+  "*Mark used for del'd articles."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-read-mark ?R
+  "*Mark used for read articles."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-expirable-mark ?E
+  "*Mark used for expirable articles."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-killed-mark ?K
+  "*Mark used for killed articles."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-spam-mark ?$
+  "*Mark used for spam articles."
+  :version "22.1"
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-kill-file-mark ?X
+  "*Mark used for articles killed by kill files."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-low-score-mark ?Y
+  "*Mark used for articles with a low score."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-catchup-mark ?C
+  "*Mark used for articles that are caught up."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-replied-mark ?A
+  "*Mark used for articles that have been replied to."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-forwarded-mark ?F
+  "*Mark used for articles that have been forwarded."
+  :version "22.1"
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-recent-mark ?N
+  "*Mark used for articles that are recent."
+  :version "22.1"
+  :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."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-unseen-mark ?.
+  "*Mark used for articles that haven't been seen."
+  :version "22.1"
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-no-mark ?               ;Whitespace
+  "*Mark used for articles that have no other secondary mark."
+  :version "22.1"
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-ancient-mark ?O
+  "*Mark used for ancient articles."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-sparse-mark ?Q
+  "*Mark used for sparsely reffed articles."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-canceled-mark ?G
+  "*Mark used for canceled articles."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-duplicate-mark ?M
+  "*Mark used for duplicate articles."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-undownloaded-mark ?-
+  "*Mark used for articles that weren't downloaded."
+  :version "22.1"
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-downloaded-mark ?+
+  "*Mark used for articles that were downloaded."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-downloadable-mark ?%
+  "*Mark used for articles that are to be downloaded."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-unsendable-mark ?=
+  "*Mark used for articles that won't be sent."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-score-over-mark ?+
+  "*Score mark used for articles with high scores."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-score-below-mark ?-
+  "*Score mark used for articles with low scores."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-empty-thread-mark ?     ;Whitespace
+  "*There is no thread under the article."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-not-empty-thread-mark ?=
+  "*There is a thread under the article."
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(defcustom gnus-view-pseudo-asynchronously nil
+  "*If non-nil, Gnus will view pseudo-articles asynchronously."
+  :group 'gnus-extract-view
+  :type 'boolean)
+
+(defcustom gnus-auto-expirable-marks
+  (list gnus-killed-mark gnus-del-mark gnus-catchup-mark
+       gnus-low-score-mark gnus-ancient-mark gnus-read-mark
+       gnus-duplicate-mark)
+  "*The list of marks converted into expiration if a group is auto-expirable."
+  :version "24.1"
+  :group 'gnus-summary
+  :type '(repeat character))
+
+(defcustom gnus-inhibit-user-auto-expire t
+  "*If non-nil, user marking commands will not mark an article as expirable, even if the group has auto-expire turned on."
+  :version "21.1"
+  :group 'gnus-summary
+  :type 'boolean)
+
+(defcustom gnus-mark-copied-or-moved-articles-as-expirable nil
+  "If non-nil, mark articles copied or moved to auto-expire group as expirable.
+If nil, the expirable marks will be unchanged except that the marks
+will be removed when copying or moving articles to a group that has
+not turned auto-expire on.  If non-nil, articles that have been read
+will be marked as expirable when being copied or moved to a group in
+which auto-expire is turned on."
+  :version "23.2"
+  :type 'boolean
+  :group 'gnus-summary-marks)
+
+(defcustom gnus-view-pseudos nil
+  "*If `automatic', pseudo-articles will be viewed automatically.
+If `not-confirm', pseudos will be viewed automatically, and the user
+will not be asked to confirm the command."
+  :group 'gnus-extract-view
+  :type '(choice (const :tag "off" nil)
+                (const automatic)
+                (const not-confirm)))
+
+(defcustom gnus-view-pseudos-separately t
+  "*If non-nil, one pseudo-article will be created for each file to be viewed.
+If nil, all files that use the same viewing command will be given as a
+list of parameters to that command."
+  :group 'gnus-extract-view
+  :type 'boolean)
+
+(defcustom gnus-insert-pseudo-articles t
+  "*If non-nil, insert pseudo-articles when decoding articles."
+  :group 'gnus-extract-view
+  :type 'boolean)
+
+(defcustom gnus-summary-dummy-line-format
+  "   %(:                             :%) %S\n"
+  "*The format specification for the dummy roots in the summary buffer.
+It works along the same lines as a normal formatting string,
+with some simple extensions.
+
+%S  The subject
+
+General format specifiers can also be used.
+See `(gnus)Formatting Variables'."
+  :link '(custom-manual "(gnus)Formatting Variables")
+  :group 'gnus-threading
+  :type 'string)
+
+(defcustom gnus-summary-mode-line-format "Gnus: %g [%A] %Z"
+  "*The format specification for the summary mode line.
+It works along the same lines as a normal formatting string,
+with some simple extensions:
+
+%G  Group name
+%p  Unprefixed group name
+%A  Current article number
+%z  Current article score
+%V  Gnus version
+%U  Number of unread articles in the group
+%e  Number of unselected articles in the group
+%Z  A string with unread/unselected article counts
+%g  Shortish group name
+%S  Subject of the current article
+%u  User-defined spec
+%s  Current score file name
+%d  Number of dormant articles
+%r  Number of articles that have been marked as read in this session
+%E  Number of articles expunged by the score files"
+  :group 'gnus-summary-format
+  :type 'string)
+
+(defcustom gnus-list-identifiers nil
+  "Regexp that matches list identifiers to be removed from subject.
+This can also be a list of regexps."
+  :version "21.1"
+  :group 'gnus-summary-format
+  :group 'gnus-article-hiding
+  :type '(choice (const :tag "none" nil)
+                (regexp :value ".*")
+                (repeat :value (".*") regexp)))
+
+(defcustom gnus-summary-mark-below 0
+  "*Mark all articles with a score below this variable as read.
+This variable is local to each summary buffer and usually set by the
+score file."
+  :group 'gnus-score-default
+  :type 'integer)
+
+(defun gnus-widget-reversible-match (widget value)
+  "Ignoring WIDGET, convert VALUE to internal form.
+VALUE should have the form `FOO' or `(not FOO)', where FOO is an symbol."
+  ;; (debug value)
+  (or (symbolp value)
+      (and (listp value)
+           (eq (length value) 2)
+           (eq (nth 0 value) 'not)
+           (symbolp (nth 1 value)))))
+
+(defun gnus-widget-reversible-to-internal (widget value)
+  "Ignoring WIDGET, convert VALUE to internal form.
+VALUE should have the form `FOO' or `(not FOO)', where FOO is an atom.
+FOO is converted to (FOO nil) and (not FOO) is converted to (FOO t)."
+  ;; (debug value)
+  (if (atom value)
+      (list value nil)
+    (list (nth 1 value) t)))
+
+(defun gnus-widget-reversible-to-external (widget value)
+  "Ignoring WIDGET, convert VALUE to external form.
+VALUE should have the form `(FOO nil)' or `(FOO t)', where FOO is an atom.
+\(FOO  nil) is converted to FOO and (FOO t) is converted to (not FOO)."
+  ;; (debug value)
+  (if (nth 1 value)
+      (list 'not (nth 0 value))
+    (nth 0 value)))
+
+(define-widget 'gnus-widget-reversible 'group
+  "A `group' that convert values."
+  :match 'gnus-widget-reversible-match
+  :value-to-internal 'gnus-widget-reversible-to-internal
+  :value-to-external 'gnus-widget-reversible-to-external)
+
+(defcustom gnus-article-sort-functions '(gnus-article-sort-by-number)
+  "*List of functions used for sorting articles in the summary buffer.
+
+Each function takes two articles and returns non-nil if the first
+article should be sorted before the other.  If you use more than one
+function, the primary sort function should be the last.  You should
+probably always include `gnus-article-sort-by-number' in the list of
+sorting functions -- preferably first.  Also note that sorting by date
+is often much slower than sorting by number, and the sorting order is
+very similar.  (Sorting by date means sorting by the time the message
+was sent, sorting by number means sorting by arrival time.)
+
+Each item can also be a list `(not F)' where F is a function;
+this reverses the sort order.
+
+Ready-made functions include `gnus-article-sort-by-number',
+`gnus-article-sort-by-author', `gnus-article-sort-by-subject',
+`gnus-article-sort-by-date', `gnus-article-sort-by-random'
+and `gnus-article-sort-by-score'.
+
+When threading is turned on, the variable `gnus-thread-sort-functions'
+controls how articles are sorted."
+  :group 'gnus-summary-sort
+  :type '(repeat (gnus-widget-reversible
+                  (choice (function-item gnus-article-sort-by-number)
+                          (function-item gnus-article-sort-by-author)
+                          (function-item gnus-article-sort-by-subject)
+                          (function-item gnus-article-sort-by-date)
+                          (function-item gnus-article-sort-by-score)
+                          (function-item gnus-article-sort-by-random)
+                          (function :tag "other"))
+                  (boolean :tag "Reverse order"))))
+
+(defcustom gnus-thread-sort-functions '(gnus-thread-sort-by-number)
+  "*List of functions used for sorting threads in the summary buffer.
+By default, threads are sorted by article number.
+
+Each function takes two threads and returns non-nil if the first
+thread should be sorted before the other.  If you use more than one
+function, the primary sort function should be the last.  You should
+probably always include `gnus-thread-sort-by-number' in the list of
+sorting functions -- preferably first.  Also note that sorting by date
+is often much slower than sorting by number, and the sorting order is
+very similar.  (Sorting by date means sorting by the time the message
+was sent, sorting by number means sorting by arrival time.)
+
+Each list item can also be a list `(not F)' where F is a
+function; this specifies reversed sort order.
+
+Ready-made functions include `gnus-thread-sort-by-number',
+`gnus-thread-sort-by-author', `gnus-thread-sort-by-recipient'
+`gnus-thread-sort-by-subject', `gnus-thread-sort-by-date',
+`gnus-thread-sort-by-score', `gnus-thread-sort-by-most-recent-number',
+`gnus-thread-sort-by-most-recent-date', `gnus-thread-sort-by-random',
+and `gnus-thread-sort-by-total-score' (see
+`gnus-thread-score-function').
+
+When threading is turned off, the variable
+`gnus-article-sort-functions' controls how articles are sorted.
+
+By default, threads and their subthreads are sorted according to
+the value of this variable.  To use a different sorting order for
+subthreads, customize `gnus-subthread-sort-functions'."
+  :group 'gnus-summary-sort
+  :type '(repeat
+          (gnus-widget-reversible
+           (choice (function-item gnus-thread-sort-by-number)
+                   (function-item gnus-thread-sort-by-author)
+                   (function-item gnus-thread-sort-by-recipient)
+                   (function-item gnus-thread-sort-by-subject)
+                   (function-item gnus-thread-sort-by-date)
+                   (function-item gnus-thread-sort-by-score)
+                   (function-item gnus-thread-sort-by-most-recent-number)
+                   (function-item gnus-thread-sort-by-most-recent-date)
+                   (function-item gnus-thread-sort-by-random)
+                   (function-item gnus-thread-sort-by-total-score)
+                   (function :tag "other"))
+           (boolean :tag "Reverse order"))))
+
+(defcustom gnus-subthread-sort-functions 'gnus-thread-sort-functions
+  "*List of functions used for sorting subthreads in the summary buffer.
+By default, subthreads are sorted the same as threads, i.e.,
+according to the value of `gnus-thread-sort-functions'."
+  :version "24.4"
+  :group 'gnus-summary-sort
+  :type '(choice
+         (const :tag "Sort subthreads like threads" gnus-thread-sort-functions)
+         (repeat
+          (gnus-widget-reversible
+           (choice (function-item gnus-thread-sort-by-number)
+                   (function-item gnus-thread-sort-by-author)
+                   (function-item gnus-thread-sort-by-recipient)
+                   (function-item gnus-thread-sort-by-subject)
+                   (function-item gnus-thread-sort-by-date)
+                   (function-item gnus-thread-sort-by-score)
+                   (function-item gnus-thread-sort-by-most-recent-number)
+                   (function-item gnus-thread-sort-by-most-recent-date)
+                   (function-item gnus-thread-sort-by-random)
+                   (function-item gnus-thread-sort-by-total-score)
+                   (function :tag "other"))
+           (boolean :tag "Reverse order")))))
+
+(defcustom gnus-thread-score-function '+
+  "*Function used for calculating the total score of a thread.
+
+The function is called with the scores of the article and each
+subthread and should then return the score of the thread.
+
+Some functions you can use are `+', `max', or `min'."
+  :group 'gnus-summary-sort
+  :type 'function)
+
+(defcustom gnus-summary-expunge-below nil
+  "All articles that have a score less than this variable will be expunged.
+This variable is local to the summary buffers."
+  :group 'gnus-score-default
+  :type '(choice (const :tag "off" nil)
+                integer))
+
+(defcustom gnus-thread-expunge-below nil
+  "All threads that have a total score less than this variable will be expunged.
+See `gnus-thread-score-function' for en explanation of what a
+\"thread score\" is.
+
+This variable is local to the summary buffers."
+  :group 'gnus-threading
+  :group 'gnus-score-default
+  :type '(choice (const :tag "off" nil)
+                integer))
+
+(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 gnus-pick-mode)
+  :group 'gnus-summary-various
+  :type 'hook)
+
+;; Extracted from gnus-xmas-redefine in order to preserve user settings
+(when (featurep 'xemacs)
+  (add-hook 'gnus-summary-mode-hook 'gnus-xmas-summary-menu-add)
+  (add-hook 'gnus-summary-mode-hook 'gnus-xmas-setup-summary-toolbar)
+  (add-hook 'gnus-summary-mode-hook
+           'gnus-xmas-switch-horizontal-scrollbar-off))
+
+(defcustom gnus-summary-menu-hook nil
+  "*Hook run after the creation of the summary mode menu."
+  :group 'gnus-summary-visual
+  :type 'hook)
+
+(defcustom gnus-summary-exit-hook nil
+  "*A hook called on exit from the summary buffer.
+It will be called with point in the group buffer."
+  :group 'gnus-summary-exit
+  :type 'hook)
+
+(defcustom gnus-summary-prepare-hook nil
+  "*A hook called after the summary buffer has been generated.
+If you want to modify the summary buffer, you can use this hook."
+  :group 'gnus-summary-various
+  :type 'hook)
+
+(defcustom gnus-summary-prepared-hook nil
+  "*A hook called as the last thing after the summary buffer has been generated."
+  :group 'gnus-summary-various
+  :type 'hook)
+
+(defcustom gnus-summary-generate-hook nil
+  "*A hook run just before generating the summary buffer.
+This hook is commonly used to customize threading variables and the
+like."
+  :group 'gnus-summary-various
+  :type 'hook)
+
+(defcustom gnus-select-group-hook nil
+  "*A hook called when a newsgroup is selected.
+
+If you'd like to simplify subjects like the
+`gnus-summary-next-same-subject' command does, you can use the
+following hook:
+
+ (add-hook gnus-select-group-hook
+          (lambda ()
+            (mapcar (lambda (header)
+                      (mail-header-set-subject
+                       header
+                       (gnus-simplify-subject
+                        (mail-header-subject header) \\='re-only)))
+                    gnus-newsgroup-headers)))"
+  :group 'gnus-group-select
+  :type 'hook)
+
+(defcustom gnus-select-article-hook nil
+  "*A hook called when an article is selected."
+  :group 'gnus-summary-choose
+  :options '(gnus-agent-fetch-selected-article)
+  :type 'hook)
+
+(defcustom gnus-visual-mark-article-hook
+  (list 'gnus-highlight-selected-summary)
+  "*Hook run after selecting an article in the summary buffer.
+It is meant to be used for highlighting the article in some way.  It
+is not run if `gnus-visual' is nil."
+  :group 'gnus-summary-visual
+  :type 'hook)
+
+(defcustom gnus-parse-headers-hook nil
+  "*A hook called before parsing the headers."
+  :group 'gnus-various
+  :type 'hook)
+
+(defcustom gnus-exit-group-hook nil
+  "*A hook called when exiting summary mode.
+This hook is not called from the non-updating exit commands like `Q'."
+  :group 'gnus-various
+  :type 'hook)
+
+(defcustom gnus-summary-update-hook nil
+  "*A hook called when a summary line is changed.
+The hook will not be called if `gnus-visual' is nil.
+
+The default function `gnus-summary-highlight-line' will
+highlight the line according to the `gnus-summary-highlight'
+variable."
+  :group 'gnus-summary-visual
+  :type 'hook)
+
+(defcustom gnus-mark-article-hook '(gnus-summary-mark-read-and-unread-as-read)
+  "*A hook called when an article is selected for the first time.
+The hook is intended to mark an article as read (or unread)
+automatically when it is selected."
+  :group 'gnus-summary-choose
+  :type 'hook)
+
+(defcustom gnus-group-no-more-groups-hook nil
+  "*A hook run when returning to group mode having no more (unread) groups."
+  :group 'gnus-group-select
+  :type 'hook)
+
+(defcustom gnus-ps-print-hook nil
+  "*A hook run before ps-printing something from Gnus."
+  :group 'gnus-summary
+  :type 'hook)
+
+(defcustom gnus-summary-article-move-hook nil
+  "*A hook called after an article is moved, copied, respooled, or crossposted."
+  :version "22.1"
+  :group 'gnus-summary
+  :type 'hook)
+
+(defcustom gnus-summary-article-delete-hook nil
+  "*A hook called after an article is deleted."
+  :version "22.1"
+  :group 'gnus-summary
+  :type 'hook)
+
+(defcustom gnus-summary-article-expire-hook nil
+  "*A hook called after an article is expired."
+  :version "22.1"
+  :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 "22.1"
+  :group 'gnus-summary
+  :type 'boolean)
+
+(defcustom gnus-summary-selected-face 'gnus-summary-selected
+  "Face used for highlighting the current article in the summary buffer."
+  :group 'gnus-summary-visual
+  :type 'face)
+
+(defvar gnus-tmp-downloaded nil)
+
+(defcustom gnus-summary-highlight
+  '(((eq mark gnus-canceled-mark)
+     . gnus-summary-cancelled)
+    ((and uncached (> score default-high))
+     . gnus-summary-high-undownloaded)
+    ((and uncached (< score default-low))
+     . gnus-summary-low-undownloaded)
+    (uncached
+     . gnus-summary-normal-undownloaded)
+    ((and (> score default-high)
+         (or (eq mark gnus-dormant-mark)
+             (eq mark gnus-ticked-mark)))
+     . gnus-summary-high-ticked)
+    ((and (< score default-low)
+         (or (eq mark gnus-dormant-mark)
+             (eq mark gnus-ticked-mark)))
+     . gnus-summary-low-ticked)
+    ((or (eq mark gnus-dormant-mark)
+        (eq mark gnus-ticked-mark))
+     . gnus-summary-normal-ticked)
+    ((and (> score default-high) (eq mark gnus-ancient-mark))
+     . gnus-summary-high-ancient)
+    ((and (< score default-low) (eq mark gnus-ancient-mark))
+     . gnus-summary-low-ancient)
+    ((eq mark gnus-ancient-mark)
+     . gnus-summary-normal-ancient)
+    ((and (> score default-high) (eq mark gnus-unread-mark))
+     . gnus-summary-high-unread)
+    ((and (< score default-low) (eq mark gnus-unread-mark))
+     . gnus-summary-low-unread)
+    ((eq mark gnus-unread-mark)
+     . gnus-summary-normal-unread)
+    ((> score default-high)
+     . gnus-summary-high-read)
+    ((< score default-low)
+     . gnus-summary-low-read)
+    (t
+     . gnus-summary-normal-read))
+  "*Controls the highlighting of summary buffer lines.
+
+A list of (FORM . FACE) pairs.  When deciding how a particular
+summary line should be displayed, each form is evaluated.  The content
+of the face field after the first true form is used.  You can change
+how those summary lines are displayed, by editing the face field.
+
+You can use the following variables in the FORM field.
+
+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.
+mark:         The article's mark.
+uncached:     Non-nil if the article is uncached."
+  :group 'gnus-summary-visual
+  :type '(repeat (cons (sexp :tag "Form" nil)
+                      face)))
+(put 'gnus-summary-highlight 'risky-local-variable t)
+
+(defcustom gnus-alter-header-function nil
+  "Function called to allow alteration of article header structures.
+The function is called with one parameter, the article header vector,
+which it may alter in any way."
+  :type '(choice (const :tag "None" nil)
+                function)
+  :group 'gnus-summary)
+
+(defvar gnus-decode-encoded-word-function 'mail-decode-encoded-word-string
+  "Function used to decode a string with encoded words.")
+
+(defvar gnus-decode-encoded-address-function
+  'mail-decode-encoded-address-string
+  "Function used to decode addresses with encoded words.")
+
+(defcustom gnus-extra-headers '(To Cc Keywords Gcc Newsgroups X-GM-LABELS)
+  "*Extra headers to parse."
+  :version "25.1"
+  :group 'gnus-summary
+  :type '(repeat symbol))
+
+(defcustom gnus-ignored-from-addresses
+  (and user-mail-address
+       (not (string= user-mail-address ""))
+       (regexp-quote user-mail-address))
+  "*From headers that may be suppressed in favor of To headers.
+This can be a regexp or a list of regexps."
+  :version "21.1"
+  :group 'gnus-summary
+  :type '(choice regexp
+                (repeat :tag "Regexp List" regexp)))
+
+(defsubst gnus-ignored-from-addresses ()
+  (gmm-regexp-concat gnus-ignored-from-addresses))
+
+(defcustom gnus-summary-to-prefix "-> "
+  "*String prefixed to the To field in the summary line when
+using `gnus-ignored-from-addresses'."
+  :version "22.1"
+  :group 'gnus-summary
+  :type 'string)
+
+(defcustom gnus-summary-newsgroup-prefix "=> "
+  "*String prefixed to the Newsgroup field in the summary
+line when using the option `gnus-ignored-from-addresses'."
+  :version "22.1"
+  :group 'gnus-summary
+  :type 'string)
+
+(defcustom gnus-newsgroup-ignored-charsets '(unknown-8bit x-unknown)
+  "List of charsets that should be ignored.
+When these charsets are used in the \"charset\" parameter, the
+default charset will be used instead."
+  :version "21.1"
+  :type '(repeat symbol)
+  :group 'gnus-charset)
+
+(defcustom gnus-newsgroup-maximum-articles nil
+  "The maximum number of articles a newsgroup.
+If this is a number, old articles in a newsgroup exceeding this number
+are silently ignored.  If it is nil, no article is ignored.  Note that
+setting this variable to a number might prevent you from reading very
+old articles."
+  :group 'gnus-group-select
+  :version "22.2"
+  :type '(choice (const :tag "No limit" nil)
+                integer))
+
+(gnus-define-group-parameter
+ ignored-charsets
+ :type list
+ :function-document
+ "Return the ignored charsets of GROUP."
+ :variable gnus-group-ignored-charsets-alist
+ :variable-default
+ '(("alt\\.chinese\\.text" iso-8859-1))
+ :variable-document
+ "Alist of regexps (to match group names) and charsets that should be ignored.
+When these charsets are used in the \"charset\" parameter, the
+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"
+                         :value nil
+                         (repeat (symbol)))
+ :parameter-document       "\
+List of charsets that should be ignored.
+
+When these charsets are used in the \"charset\" parameter, the
+default charset will be used instead.")
+
+(defcustom gnus-group-highlight-words-alist nil
+  "Alist of group regexps and highlight regexps.
+This variable uses the same syntax as `gnus-emphasis-alist'."
+  :version "21.1"
+  :type '(repeat (cons (regexp :tag "Group")
+                      (repeat (list (regexp :tag "Highlight regexp")
+                                    (number :tag "Group for entire word" 0)
+                                    (number :tag "Group for displayed part" 0)
+                                    (symbol :tag "Face"
+                                            gnus-emphasis-highlight-words)))))
+  :group 'gnus-summary-visual)
+
+(defcustom gnus-summary-show-article-charset-alist
+  nil
+  "Alist of number and charset.
+The article will be shown with the charset corresponding to the
+numbered argument.
+For example: ((1 . cn-gb-2312) (2 . big5))."
+  :version "21.1"
+  :type '(repeat (cons (number :tag "Argument" 1)
+                      (symbol :tag "Charset")))
+  :group 'gnus-charset)
+
+(defcustom gnus-preserve-marks t
+  "Whether marks are preserved when moving, copying and respooling messages."
+  :version "21.1"
+  :type 'boolean
+  :group 'gnus-summary-marks)
+
+(defcustom gnus-alter-articles-to-read-function nil
+  "Function to be called to alter the list of articles to be selected."
+  :type '(choice (const nil) function)
+  :group 'gnus-summary)
+
+(defcustom gnus-orphan-score nil
+  "*All orphans get this score added.  Set in the score file."
+  :group 'gnus-score-default
+  :type '(choice (const nil)
+                integer))
+
+(defcustom gnus-summary-save-parts-default-mime "image/.*"
+  "*A regexp to match MIME parts when saving multiple parts of a
+message with `gnus-summary-save-parts' (\\<gnus-summary-mode-map>\\[gnus-summary-save-parts]).
+This regexp will be used by default when prompting the user for which
+type of files to save."
+  :group 'gnus-summary
+  :type 'regexp)
+
+(defcustom gnus-read-all-available-headers nil
+  "Whether Gnus should parse all headers made available to it.
+This is mostly relevant for slow back ends where the user may
+wish to widen the summary buffer to include all headers
+that were fetched."
+  :version "22.1"
+  :group 'gnus-summary
+  :type '(choice boolean regexp))
+
+(defcustom gnus-summary-pipe-output-default-command nil
+  "Command (and optional arguments) used to pipe article to subprocess.
+This will be used as the default command if it is non-nil.  The value
+will be updated if you modify it when executing the command
+`gnus-summary-pipe-output' or the function `gnus-summary-save-in-pipe'."
+  :version "23.1" ;; No Gnus
+  :group 'gnus-summary
+  :type '(radio (const :tag "None" nil) (string :tag "Command")))
+
+(defcustom gnus-summary-muttprint-program "muttprint"
+  "Command (and optional arguments) used to run Muttprint.
+The value will be updated if you modify it when executing the command
+`gnus-summary-muttprint'."
+  :version "22.1"
+  :group 'gnus-summary
+  :type 'string)
+
+(defcustom gnus-article-loose-mime t
+  "If non-nil, don't require MIME-Version header.
+Some brain-damaged MUA/MTA, e.g. Lotus Domino 5.0.6 clients, does not
+supply the MIME-Version header or deliberately strip it from the mail.
+If non-nil (the default), Gnus will treat some articles as MIME
+even if the MIME-Version header is missing."
+  :version "22.1"
+  :type 'boolean
+  :group 'gnus-article-mime)
+
+(defcustom gnus-article-emulate-mime t
+  "If non-nil, use MIME emulation for uuencode and the like.
+This means that Gnus will search message bodies for text that look
+like uuencoded bits, yEncoded bits, and so on, and present that using
+the normal Gnus MIME machinery."
+  :version "22.1"
+  :type 'boolean
+  :group 'gnus-article-mime)
+
+;;; Internal variables
+
+(defvar gnus-summary-display-cache nil)
+(defvar gnus-article-mime-handles nil)
+(defvar gnus-article-decoded-p nil)
+(defvar gnus-article-charset nil)
+(defvar gnus-article-ignored-charsets nil)
+(defvar gnus-scores-exclude-files nil)
+(defvar gnus-page-broken nil)
+
+(defvar gnus-original-article nil)
+(defvar gnus-article-internal-prepare-hook nil)
+(defvar gnus-newsgroup-process-stack nil)
+
+(defvar gnus-thread-indent-array nil)
+(defvar gnus-thread-indent-array-level gnus-thread-indent-level)
+(defvar gnus-sort-gathered-threads-function 'gnus-thread-sort-by-number
+  "Function called to sort the articles within a thread after it has been gathered together.")
+
+(defvar gnus-summary-save-parts-type-history nil)
+(defvar gnus-summary-save-parts-last-directory mm-default-directory)
+
+;; Avoid highlighting in kill files.
+(defvar gnus-summary-inhibit-highlight nil)
+(defvar gnus-newsgroup-selected-overlay nil)
+(defvar gnus-inhibit-limiting nil)
+(defvar gnus-newsgroup-adaptive-score-file nil)
+(defvar gnus-current-score-file nil)
+(defvar gnus-current-move-group nil)
+(defvar gnus-current-copy-group nil)
+(defvar gnus-current-crosspost-group nil)
+(defvar gnus-newsgroup-display nil)
+
+(defvar gnus-newsgroup-dependencies nil)
+(defvar gnus-newsgroup-adaptive nil)
+(defvar gnus-summary-display-article-function nil)
+(defvar gnus-summary-highlight-line-function nil
+  "Function called after highlighting a summary line.")
+
+(defvar gnus-summary-line-format-alist
+  `((?N ,(macroexpand '(mail-header-number gnus-tmp-header)) ?d)
+    (?S ,(macroexpand '(mail-header-subject gnus-tmp-header)) ?s)
+    (?s gnus-tmp-subject-or-nil ?s)
+    (?n gnus-tmp-name ?s)
+    (?A (car (cdr (funcall gnus-extract-address-components gnus-tmp-from)))
+       ?s)
+    (?a (or (car (funcall gnus-extract-address-components gnus-tmp-from))
+           gnus-tmp-from) ?s)
+    (?F gnus-tmp-from ?s)
+    (?x ,(macroexpand '(mail-header-xref gnus-tmp-header)) ?s)
+    (?D ,(macroexpand '(mail-header-date gnus-tmp-header)) ?s)
+    (?d (gnus-dd-mmm (mail-header-date gnus-tmp-header)) ?s)
+    (?o (gnus-date-iso8601 (mail-header-date gnus-tmp-header)) ?s)
+    (?M ,(macroexpand '(mail-header-id gnus-tmp-header)) ?s)
+    (?r ,(macroexpand '(mail-header-references gnus-tmp-header)) ?s)
+    (?c (or (mail-header-chars gnus-tmp-header) 0) ?d)
+    (?k (gnus-summary-line-message-size gnus-tmp-header) ?s)
+    (?L gnus-tmp-lines ?s)
+    (?Z (or (nnir-article-rsv (mail-header-number gnus-tmp-header))
+           0) ?d)
+    (?G (or (nnir-article-group (mail-header-number gnus-tmp-header))
+           "") ?s)
+    (?g (or (gnus-group-short-name
+            (nnir-article-group (mail-header-number gnus-tmp-header)))
+           "") ?s)
+    (?O gnus-tmp-downloaded ?c)
+    (?I gnus-tmp-indentation ?s)
+    (?T (if (= gnus-tmp-level 0) "" (make-string (frame-width) ? )) ?s)
+    (?R gnus-tmp-replied ?c)
+    (?\[ gnus-tmp-opening-bracket ?c)
+    (?\] gnus-tmp-closing-bracket ?c)
+    (?\> (make-string gnus-tmp-level ? ) ?s)
+    (?\< (make-string (max 0 (- 20 gnus-tmp-level)) ? ) ?s)
+    (?i gnus-tmp-score ?d)
+    (?z gnus-tmp-score-char ?c)
+    (?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 gnus-tmp-from)
+       ?s)
+    (?t (gnus-summary-number-of-articles-in-thread
+        (and (boundp 'thread) (car thread)) gnus-tmp-level)
+       ?d)
+    (?e (gnus-summary-number-of-articles-in-thread
+        (and (boundp 'thread) (car thread)) gnus-tmp-level t)
+       ?c)
+    (?u gnus-tmp-user-defined ?s)
+    (?P (gnus-pick-line-number) ?d)
+    (?B gnus-tmp-thread-tree-header-string ?s)
+    (user-date (gnus-user-date
+               ,(macroexpand '(mail-header-date gnus-tmp-header))) ?s))
+  "An alist of format specifications that can appear in summary lines.
+These are paired with what variables they correspond with, along with
+the type of the variable (string, integer, character, etc).")
+
+(defvar gnus-summary-dummy-line-format-alist
+  `((?S gnus-tmp-subject ?s)
+    (?N gnus-tmp-number ?d)
+    (?u gnus-tmp-user-defined ?s)))
+
+(defvar gnus-summary-mode-line-format-alist
+  `((?G gnus-tmp-group-name ?s)
+    (?g (gnus-short-group-name gnus-tmp-group-name) ?s)
+    (?p (gnus-group-real-name gnus-tmp-group-name) ?s)
+    (?A gnus-tmp-article-number ?d)
+    (?Z gnus-tmp-unread-and-unselected ?s)
+    (?V gnus-version ?s)
+    (?U gnus-tmp-unread-and-unticked ?d)
+    (?S gnus-tmp-subject ?s)
+    (?e gnus-tmp-unselected ?d)
+    (?u gnus-tmp-user-defined ?s)
+    (?d (length gnus-newsgroup-dormant) ?d)
+    (?t (length gnus-newsgroup-marked) ?d)
+    (?h (length gnus-newsgroup-spam-marked) ?d)
+    (?r (length gnus-newsgroup-reads) ?d)
+    (?z (gnus-summary-article-score gnus-tmp-article-number) ?d)
+    (?E gnus-newsgroup-expunged-tally ?d)
+    (?s (gnus-current-score-file-nondirectory) ?s)))
+
+;; This is here rather than in gnus-art for compilation reasons.
+(defvar gnus-article-mode-line-format-alist
+  (nconc '((?w (gnus-article-wash-status) ?s)
+          (?m (gnus-article-mime-part-status) ?s))
+        gnus-summary-mode-line-format-alist))
+
+(defvar gnus-last-search-regexp nil
+  "Default regexp for article search command.")
+
+(defvar gnus-last-shell-command nil
+  "Default shell command on article.")
+
+(defvar gnus-newsgroup-agentized nil
+  "Locally bound in each summary buffer to indicate whether the server has been agentized.")
+(defvar gnus-newsgroup-begin nil)
+(defvar gnus-newsgroup-end nil)
+(defvar gnus-newsgroup-last-rmail nil)
+(defvar gnus-newsgroup-last-mail nil)
+(defvar gnus-newsgroup-last-folder nil)
+(defvar gnus-newsgroup-last-file nil)
+(defvar gnus-newsgroup-last-directory nil)
+(defvar gnus-newsgroup-auto-expire nil)
+(defvar gnus-newsgroup-active nil)
+(defvar gnus-newsgroup-highest nil)
+
+(defvar gnus-newsgroup-data nil)
+(defvar gnus-newsgroup-data-reverse nil)
+(defvar gnus-newsgroup-limit nil)
+(defvar gnus-newsgroup-limits nil)
+(defvar gnus-summary-use-undownloaded-faces nil)
+
+(defvar gnus-newsgroup-unreads nil
+  "Sorted list of unread articles in the current newsgroup.")
+
+(defvar gnus-newsgroup-unselected nil
+  "Sorted list of unselected unread articles in the current newsgroup.")
+
+(defvar gnus-newsgroup-reads nil
+  "Alist of read articles and article marks in the current newsgroup.")
+
+(defvar gnus-newsgroup-expunged-tally nil)
+
+(defvar gnus-newsgroup-marked nil
+  "Sorted list of ticked articles in the current newsgroup (a subset of unread art).")
+
+(defvar gnus-newsgroup-spam-marked nil
+  "List of ranges of articles that have been marked as spam.")
+
+(defvar gnus-newsgroup-killed nil
+  "List of ranges of articles that have been through the scoring process.")
+
+(defvar gnus-newsgroup-cached nil
+  "Sorted list of articles that come from the article cache.")
+
+(defvar gnus-newsgroup-saved nil
+  "List of articles that have been saved.")
+
+(defvar gnus-newsgroup-kill-headers nil)
+
+(defvar gnus-newsgroup-replied nil
+  "List of articles that have been replied to in the current newsgroup.")
+
+(defvar gnus-newsgroup-forwarded nil
+  "List of articles that have been forwarded in the current newsgroup.")
+
+(defvar gnus-newsgroup-expirable nil
+  "Sorted list of articles in the current newsgroup that can be expired.")
+
+(defvar gnus-newsgroup-processable nil
+  "List of articles in the current newsgroup that can be processed.")
+
+(defvar gnus-newsgroup-downloadable nil
+  "Sorted list of articles in the current newsgroup that can be processed.")
+
+(defvar gnus-newsgroup-unfetched nil
+  "Sorted list of articles in the current newsgroup whose headers have
+not been fetched into the agent.
+
+This list will always be a subset of gnus-newsgroup-undownloaded.")
+
+(defvar gnus-newsgroup-undownloaded nil
+  "List of articles in the current newsgroup that haven't been downloaded.")
+
+(defvar gnus-newsgroup-unsendable nil
+  "List of articles in the current newsgroup that won't be sent.")
+
+(defvar gnus-newsgroup-bookmarks nil
+  "List of articles in the current newsgroup that have bookmarks.")
+
+(defvar gnus-newsgroup-dormant nil
+  "Sorted 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-unexist nil
+  "Range of unexisting 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.")
+
+(defvar gnus-newsgroup-headers nil
+  "List of article headers in the current newsgroup.")
+
+(defvar gnus-newsgroup-threads nil)
+
+(defvar gnus-newsgroup-prepared nil
+  "Whether the current group has been prepared properly.")
+
+(defvar gnus-newsgroup-ancient nil
+  "List of `gnus-fetch-old-headers' articles in the current newsgroup.")
+
+(defvar gnus-newsgroup-sparse nil)
+
+(defvar gnus-current-article nil)
+(defvar gnus-article-current nil)
+(defvar gnus-current-headers nil)
+(defvar gnus-have-all-headers nil)
+(defvar gnus-last-article nil)
+(defvar gnus-newsgroup-history nil)
+(defvar gnus-newsgroup-charset nil)
+(defvar gnus-newsgroup-ephemeral-charset nil)
+(defvar gnus-newsgroup-ephemeral-ignored-charsets nil)
+
+(defvar gnus-article-before-search nil)
+
+(defvar gnus-summary-local-variables
+  '(gnus-newsgroup-name
+
+    ;; Marks lists
+    gnus-newsgroup-unreads
+    gnus-newsgroup-unselected
+    gnus-newsgroup-marked
+    gnus-newsgroup-spam-marked
+    gnus-newsgroup-reads
+    gnus-newsgroup-saved
+    gnus-newsgroup-replied
+    gnus-newsgroup-forwarded
+    gnus-newsgroup-expirable
+    gnus-newsgroup-killed
+    gnus-newsgroup-unseen
+    gnus-newsgroup-seen
+    gnus-newsgroup-unexist
+    gnus-newsgroup-cached
+    gnus-newsgroup-downloadable
+    gnus-newsgroup-undownloaded
+    gnus-newsgroup-unsendable
+
+    gnus-newsgroup-begin gnus-newsgroup-end
+    gnus-newsgroup-last-rmail gnus-newsgroup-last-mail
+    gnus-newsgroup-last-folder gnus-newsgroup-last-file
+    gnus-newsgroup-last-directory
+    gnus-newsgroup-auto-expire
+    gnus-newsgroup-processable
+    gnus-newsgroup-unfetched
+    gnus-newsgroup-articles
+    gnus-newsgroup-bookmarks gnus-newsgroup-dormant
+    gnus-newsgroup-headers gnus-newsgroup-threads
+    gnus-newsgroup-prepared gnus-summary-highlight-line-function
+    gnus-current-article gnus-current-headers gnus-have-all-headers
+    gnus-last-article gnus-article-internal-prepare-hook
+    (gnus-summary-article-delete-hook . global)
+    (gnus-summary-article-move-hook . global)
+    gnus-newsgroup-dependencies gnus-newsgroup-selected-overlay
+    gnus-newsgroup-scored gnus-newsgroup-kill-headers
+    gnus-thread-expunge-below
+    gnus-score-alist gnus-current-score-file
+    (gnus-summary-expunge-below . global)
+    (gnus-summary-mark-below . global)
+    (gnus-orphan-score . global)
+    gnus-newsgroup-active gnus-scores-exclude-files
+    gnus-newsgroup-highest
+    gnus-newsgroup-history gnus-newsgroup-ancient
+    gnus-newsgroup-sparse gnus-newsgroup-process-stack
+    (gnus-newsgroup-adaptive . gnus-use-adaptive-scoring)
+    gnus-newsgroup-adaptive-score-file (gnus-reffed-article-number . -1)
+    (gnus-newsgroup-expunged-tally . 0)
+    gnus-cache-removable-articles
+    gnus-newsgroup-data gnus-newsgroup-data-reverse
+    gnus-newsgroup-limit gnus-newsgroup-limits
+    gnus-newsgroup-charset gnus-newsgroup-display
+    gnus-summary-use-undownloaded-faces)
+  "Variables that are buffer-local to the summary buffers.")
+
+(defvar gnus-newsgroup-variables nil
+  "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 expressions to be evalled (when the default
+values are not nil), that should be made global while the summary buffer
+is active.
+
+Note: The default expressions will be evaluated (using function `eval')
+before assignment to the local variable rather than just assigned to it.
+If the default expression is the symbol `global', that symbol will not
+be evaluated but the global value of the local variable will be used
+instead.
+
+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:\")))
+")
+
+(eval-when-compile
+  ;; Bind features so that require will believe that gnus-sum has
+  ;; already been loaded (avoids infinite recursion)
+  (let ((features (cons 'gnus-sum features)))
+    (require 'gnus-art)))
+
+;; MIME stuff.
+
+(defvar gnus-decode-encoded-word-methods
+  '(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 applied only to the newsgroups
+whose names match REGEXP.
+
+For example:
+\((\"chinese\" . gnus-decode-encoded-word-string-by-guess)
+ mail-decode-encoded-word-string
+ (\"chinese\" . rfc1843-decode-string))")
+
+(defvar gnus-decode-encoded-word-methods-cache nil)
+
+(defun gnus-multi-decode-encoded-word-string (string)
+  "Apply the functions from `gnus-encoded-word-methods' that match."
+  (unless (and gnus-decode-encoded-word-methods-cache
+              (eq gnus-newsgroup-name
+                  (car gnus-decode-encoded-word-methods-cache)))
+    (setq gnus-decode-encoded-word-methods-cache (list gnus-newsgroup-name))
+    (dolist (method gnus-decode-encoded-word-methods)
+      (if (symbolp method)
+         (nconc gnus-decode-encoded-word-methods-cache (list method))
+       (if (and gnus-newsgroup-name
+                (string-match (car method) gnus-newsgroup-name))
+           (nconc gnus-decode-encoded-word-methods-cache
+                  (list (cdr method)))))))
+  (dolist (method (cdr gnus-decode-encoded-word-methods-cache) string)
+    (setq string (funcall method string))))
+
+;; Subject simplification.
+
+(defun gnus-simplify-whitespace (str)
+  "Remove excessive whitespace from STR."
+  ;; Multiple spaces.
+  (while (string-match "[ \t][ \t]+" str)
+    (setq str (concat (substring str 0 (match-beginning 0))
+                       " "
+                       (substring str (match-end 0)))))
+  ;; Leading spaces.
+  (when (string-match "^[ \t]+" str)
+    (setq str (substring str (match-end 0))))
+  ;; Trailing spaces.
+  (when (string-match "[ \t]+$" str)
+    (setq str (substring str 0 (match-beginning 0))))
+  str)
+
+(defun gnus-simplify-all-whitespace (str)
+  "Remove all whitespace from STR."
+  (while (string-match "[ \t\n]+" str)
+    (setq str (replace-match "" nil nil str)))
+  str)
+
+(defsubst gnus-simplify-subject-re (subject)
+  "Remove \"Re:\" from subject lines."
+  (if (string-match message-subject-re-regexp subject)
+      (substring subject (match-end 0))
+    subject))
+
+(defun gnus-simplify-subject (subject &optional re-only)
+  "Remove `Re:' and words in parentheses.
+If RE-ONLY is non-nil, strip leading `Re:'s only."
+  (let ((case-fold-search t))          ;Ignore case.
+    ;; Remove `Re:', `Re^N:', `Re(n)', and `Re[n]:'.
+    (when (string-match "\\`\\(re\\([[(^][0-9]+[])]?\\)?:[ \t]*\\)+" subject)
+      (setq subject (substring subject (match-end 0))))
+    ;; Remove uninteresting prefixes.
+    (when (and (not re-only)
+              gnus-simplify-ignored-prefixes
+              (string-match gnus-simplify-ignored-prefixes subject))
+      (setq subject (substring subject (match-end 0))))
+    ;; Remove words in parentheses from end.
+    (unless re-only
+      (while (string-match "[ \t\n]*([^()]*)[ \t\n]*\\'" subject)
+       (setq subject (substring subject 0 (match-beginning 0)))))
+    ;; Return subject string.
+    subject))
+
+;; Remove any leading "re:"s, any trailing paren phrases, and simplify
+;; all whitespace.
+(defsubst gnus-simplify-buffer-fuzzy-step (regexp &optional newtext)
+  (goto-char (point-min))
+  (while (re-search-forward regexp nil t)
+    (replace-match (or newtext ""))))
+
+(defun gnus-simplify-buffer-fuzzy (regexp)
+  "Simplify string in the buffer fuzzily.
+The string in the accessible portion of the current buffer is simplified.
+It is assumed to be a single-line subject.
+Whitespace is generally cleaned up, and miscellaneous leading/trailing
+matter is removed.  Additional things can be deleted by setting
+`gnus-simplify-subject-fuzzy-regexp'."
+  (let ((case-fold-search t)
+       (modified-tick))
+    (gnus-simplify-buffer-fuzzy-step "\t" " ")
+
+    (while (not (eq modified-tick (buffer-modified-tick)))
+      (setq modified-tick (buffer-modified-tick))
+      (cond
+       ((listp regexp)
+       (mapc 'gnus-simplify-buffer-fuzzy-step regexp))
+       (regexp
+       (gnus-simplify-buffer-fuzzy-step regexp)))
+      (gnus-simplify-buffer-fuzzy-step "^ *\\[[-+?*!][-+?*!]\\] *")
+      (gnus-simplify-buffer-fuzzy-step
+       "^ *\\(re\\|fw\\|fwd\\)[[{(^0-9]*[])}]?[:;] *")
+      (gnus-simplify-buffer-fuzzy-step "^[[].*:\\( .*\\)[]]$" "\\1"))
+
+    (gnus-simplify-buffer-fuzzy-step " *[[{(][^()\n]*[]})] *$")
+    (gnus-simplify-buffer-fuzzy-step "  +" " ")
+    (gnus-simplify-buffer-fuzzy-step " $")
+    (gnus-simplify-buffer-fuzzy-step "^ +")))
+
+(defun gnus-simplify-subject-fuzzy (subject)
+  "Simplify a subject string fuzzily.
+See `gnus-simplify-buffer-fuzzy' for details."
+  (save-excursion
+    (let ((regexp gnus-simplify-subject-fuzzy-regexp))
+      (gnus-set-work-buffer)
+      (let ((case-fold-search t))
+       ;; Remove uninteresting prefixes.
+       (when (and gnus-simplify-ignored-prefixes
+                  (string-match gnus-simplify-ignored-prefixes subject))
+         (setq subject (substring subject (match-end 0))))
+       (insert subject)
+       (inline (gnus-simplify-buffer-fuzzy regexp))
+       (buffer-string)))))
+
+(defsubst gnus-simplify-subject-fully (subject)
+  "Simplify a subject string according to `gnus-summary-gather-subject-limit'."
+  (cond
+   (gnus-simplify-subject-functions
+    (gnus-map-function gnus-simplify-subject-functions subject))
+   ((null gnus-summary-gather-subject-limit)
+    (gnus-simplify-subject-re subject))
+   ((eq gnus-summary-gather-subject-limit 'fuzzy)
+    (gnus-simplify-subject-fuzzy subject))
+   ((numberp gnus-summary-gather-subject-limit)
+    (truncate-string-to-width (gnus-simplify-subject-re subject)
+                             gnus-summary-gather-subject-limit))
+   (t
+    subject)))
+
+(defsubst gnus-subject-equal (s1 s2 &optional simple-first)
+  "Check whether two subjects are equal.
+If optional argument SIMPLE-FIRST is t, first argument is already
+simplified."
+  (cond
+   ((null simple-first)
+    (equal (gnus-simplify-subject-fully s1)
+          (gnus-simplify-subject-fully s2)))
+   (t
+    (equal s1
+          (gnus-simplify-subject-fully s2)))))
+
+(defun gnus-summary-bubble-group ()
+  "Increase the score of the current group.
+This is a handy function to add to `gnus-summary-exit-hook' to
+increase the score of each group you read."
+  (gnus-group-add-score gnus-newsgroup-name))
+
+\f
+;;;
+;;; Gnus summary mode
+;;;
+
+(put 'gnus-summary-mode 'mode-class 'special)
+
+(defvar gnus-article-commands-menu)
+
+;; Non-orthogonal keys
+
+(gnus-define-keys gnus-summary-mode-map
+  " " gnus-summary-next-page
+  [?\S-\ ] gnus-summary-prev-page
+  "\177" gnus-summary-prev-page
+  [delete] gnus-summary-prev-page
+  "\r" gnus-summary-scroll-up
+  "\M-\r" gnus-summary-scroll-down
+  "n" gnus-summary-next-unread-article
+  "p" gnus-summary-prev-unread-article
+  "N" gnus-summary-next-article
+  "P" gnus-summary-prev-article
+  "\M-\C-n" gnus-summary-next-same-subject
+  "\M-\C-p" gnus-summary-prev-same-subject
+  "\M-n" gnus-summary-next-unread-subject
+  "\M-p" gnus-summary-prev-unread-subject
+  "." gnus-summary-first-unread-article
+  "," gnus-summary-best-unread-article
+  "\M-s" gnus-summary-search-article-forward
+  "\M-r" gnus-summary-search-article-backward
+  "\M-S" gnus-summary-repeat-search-article-forward
+  "\M-R" gnus-summary-repeat-search-article-backward
+  "<" gnus-summary-beginning-of-article
+  ">" gnus-summary-end-of-article
+  "j" gnus-summary-goto-article
+  "^" gnus-summary-refer-parent-article
+  "\M-^" gnus-summary-refer-article
+  "u" gnus-summary-tick-article-forward
+  "!" gnus-summary-tick-article-forward
+  "U" gnus-summary-tick-article-backward
+  "d" gnus-summary-mark-as-read-forward
+  "D" gnus-summary-mark-as-read-backward
+  "E" gnus-summary-mark-as-expirable
+  "\M-u" gnus-summary-clear-mark-forward
+  "\M-U" gnus-summary-clear-mark-backward
+  "k" gnus-summary-kill-same-subject-and-select
+  "\C-k" gnus-summary-kill-same-subject
+  "\M-\C-k" gnus-summary-kill-thread
+  "\M-\C-l" gnus-summary-lower-thread
+  "e" gnus-summary-edit-article
+  "#" gnus-summary-mark-as-processable
+  "\M-#" gnus-summary-unmark-as-processable
+  "\M-\C-t" gnus-summary-toggle-threads
+  "\M-\C-s" gnus-summary-show-thread
+  "\M-\C-h" gnus-summary-hide-thread
+  "\M-\C-f" gnus-summary-next-thread
+  "\M-\C-b" gnus-summary-prev-thread
+  [(meta down)] gnus-summary-next-thread
+  [(meta up)] gnus-summary-prev-thread
+  "\M-\C-u" gnus-summary-up-thread
+  "\M-\C-d" gnus-summary-down-thread
+  "&" gnus-summary-execute-command
+  "c" gnus-summary-catchup-and-exit
+  "\C-w" gnus-summary-mark-region-as-read
+  "\C-t" gnus-summary-toggle-truncation
+  "?" gnus-summary-mark-as-dormant
+  "\C-c\M-\C-s" gnus-summary-limit-include-expunged
+  "\C-c\C-s\C-n" gnus-summary-sort-by-number
+  "\C-c\C-s\C-m\C-n" gnus-summary-sort-by-most-recent-number
+  "\C-c\C-s\C-l" gnus-summary-sort-by-lines
+  "\C-c\C-s\C-c" gnus-summary-sort-by-chars
+  "\C-c\C-s\C-a" gnus-summary-sort-by-author
+  "\C-c\C-s\C-t" gnus-summary-sort-by-recipient
+  "\C-c\C-s\C-s" gnus-summary-sort-by-subject
+  "\C-c\C-s\C-d" gnus-summary-sort-by-date
+  "\C-c\C-s\C-m\C-d" gnus-summary-sort-by-most-recent-date
+  "\C-c\C-s\C-i" gnus-summary-sort-by-score
+  "\C-c\C-s\C-o" gnus-summary-sort-by-original
+  "\C-c\C-s\C-r" gnus-summary-sort-by-random
+  "=" gnus-summary-expand-window
+  "\C-x\C-s" gnus-summary-reselect-current-group
+  "\M-g" gnus-summary-rescan-group
+  "\C-c\C-r" gnus-summary-caesar-message
+  "f" gnus-summary-followup
+  "F" gnus-summary-followup-with-original
+  "C" gnus-summary-cancel-article
+  "r" gnus-summary-reply
+  "R" gnus-summary-reply-with-original
+  "\C-c\C-f" gnus-summary-mail-forward
+  "o" gnus-summary-save-article
+  "\C-o" gnus-summary-save-article-mail
+  "|" gnus-summary-pipe-output
+  "\M-k" gnus-summary-edit-local-kill
+  "\M-K" gnus-summary-edit-global-kill
+  ;; "V" gnus-version
+  "\C-c\C-d" gnus-summary-describe-group
+  "q" gnus-summary-exit
+  "Q" gnus-summary-exit-no-update
+  "\C-c\C-i" gnus-info-find-node
+  gnus-mouse-2 gnus-mouse-pick-article
+  [follow-link] mouse-face
+  "m" gnus-summary-mail-other-window
+  "a" gnus-summary-post-news
+  "x" gnus-summary-limit-to-unread
+  "s" gnus-summary-isearch-article
+  "\t" gnus-summary-widget-forward
+  [backtab] gnus-summary-widget-backward
+  "t" gnus-summary-toggle-header
+  "g" gnus-summary-show-article
+  "l" gnus-summary-goto-last-article
+  "\C-c\C-v\C-v" gnus-uu-decode-uu-view
+  "\C-d" gnus-summary-enter-digest-group
+  "\M-\C-d" gnus-summary-read-document
+  "\M-\C-e" gnus-summary-edit-parameters
+  "\M-\C-a" gnus-summary-customize-parameters
+  "\C-c\C-b" gnus-bug
+  "*" gnus-cache-enter-article
+  "\M-*" gnus-cache-remove-article
+  "\M-&" gnus-summary-universal-argument
+  "\C-l" gnus-recenter
+  "I" gnus-summary-increase-score
+  "L" gnus-summary-lower-score
+  "\M-i" gnus-symbolic-argument
+  "h" gnus-summary-select-article-buffer
+
+  "b" gnus-article-view-part
+  "\M-t" gnus-summary-toggle-display-buttonized
+
+  "V" gnus-summary-score-map
+  "X" gnus-uu-extract-map
+  "S" gnus-summary-send-map)
+
+;; Sort of orthogonal keymap
+(gnus-define-keys (gnus-summary-mark-map "M" gnus-summary-mode-map)
+  "t" gnus-summary-tick-article-forward
+  "!" gnus-summary-tick-article-forward
+  "d" gnus-summary-mark-as-read-forward
+  "r" gnus-summary-mark-as-read-forward
+  "c" gnus-summary-clear-mark-forward
+  " " gnus-summary-clear-mark-forward
+  "e" gnus-summary-mark-as-expirable
+  "x" gnus-summary-mark-as-expirable
+  "?" gnus-summary-mark-as-dormant
+  "b" gnus-summary-set-bookmark
+  "B" gnus-summary-remove-bookmark
+  "#" gnus-summary-mark-as-processable
+  "\M-#" gnus-summary-unmark-as-processable
+  "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
+  "P" gnus-uu-mark-map)
+
+(gnus-define-keys (gnus-summary-mscore-map "V" gnus-summary-mark-map)
+  "c" gnus-summary-clear-above
+  "u" gnus-summary-tick-above
+  "m" gnus-summary-mark-above
+  "k" gnus-summary-kill-below)
+
+(gnus-define-keys (gnus-summary-limit-map "/" gnus-summary-mode-map)
+  "/" gnus-summary-limit-to-subject
+  "n" gnus-summary-limit-to-articles
+  "b" gnus-summary-limit-to-bodies
+  "h" gnus-summary-limit-to-headers
+  "w" gnus-summary-pop-limit
+  "s" gnus-summary-limit-to-subject
+  "a" gnus-summary-limit-to-author
+  "u" gnus-summary-limit-to-unread
+  "m" gnus-summary-limit-to-marks
+  "M" gnus-summary-limit-exclude-marks
+  "v" gnus-summary-limit-to-score
+  "*" gnus-summary-limit-include-cached
+  "D" gnus-summary-limit-include-dormant
+  "T" gnus-summary-limit-include-thread
+  "d" gnus-summary-limit-exclude-dormant
+  "t" gnus-summary-limit-to-age
+  "." gnus-summary-limit-to-unseen
+  "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
+  "o" gnus-summary-insert-old-articles
+  "N" gnus-summary-insert-new-articles
+  "S" gnus-summary-limit-to-singletons
+  "r" gnus-summary-limit-to-replied
+  "R" gnus-summary-limit-to-recipient
+  "A" gnus-summary-limit-to-address)
+
+(gnus-define-keys (gnus-summary-goto-map "G" gnus-summary-mode-map)
+  "n" gnus-summary-next-unread-article
+  "p" gnus-summary-prev-unread-article
+  "N" gnus-summary-next-article
+  "P" gnus-summary-prev-article
+  "\C-n" gnus-summary-next-same-subject
+  "\C-p" gnus-summary-prev-same-subject
+  "\M-n" gnus-summary-next-unread-subject
+  "\M-p" gnus-summary-prev-unread-subject
+  "f" gnus-summary-first-unread-article
+  "b" gnus-summary-best-unread-article
+  "j" gnus-summary-goto-article
+  "g" gnus-summary-goto-subject
+  "l" gnus-summary-goto-last-article
+  "o" gnus-summary-pop-article)
+
+(gnus-define-keys (gnus-summary-thread-map "T" gnus-summary-mode-map)
+  "k" gnus-summary-kill-thread
+  "E" gnus-summary-expire-thread
+  "l" gnus-summary-lower-thread
+  "i" gnus-summary-raise-thread
+  "T" gnus-summary-toggle-threads
+  "t" gnus-summary-rethread-current
+  "^" gnus-summary-reparent-thread
+  "\M-^" gnus-summary-reparent-children
+  "s" gnus-summary-show-thread
+  "S" gnus-summary-show-all-threads
+  "h" gnus-summary-hide-thread
+  "H" gnus-summary-hide-all-threads
+  "n" gnus-summary-next-thread
+  "p" gnus-summary-prev-thread
+  "u" gnus-summary-up-thread
+  "o" gnus-summary-top-thread
+  "d" gnus-summary-down-thread
+  "#" gnus-uu-mark-thread
+  "\M-#" gnus-uu-unmark-thread)
+
+(gnus-define-keys (gnus-summary-buffer-map "Y" gnus-summary-mode-map)
+  "g" gnus-summary-prepare
+  "c" gnus-summary-insert-cached-articles
+  "d" gnus-summary-insert-dormant-articles
+  "t" gnus-summary-insert-ticked-articles)
+
+(gnus-define-keys (gnus-summary-exit-map "Z" gnus-summary-mode-map)
+  "c" gnus-summary-catchup-and-exit
+  "C" gnus-summary-catchup-all-and-exit
+  "E" gnus-summary-exit-no-update
+  "Q" gnus-summary-exit
+  "Z" gnus-summary-exit
+  "n" gnus-summary-catchup-and-goto-next-group
+  "p" gnus-summary-catchup-and-goto-prev-group
+  "R" gnus-summary-reselect-current-group
+  "G" gnus-summary-rescan-group
+  "N" gnus-summary-next-group
+  "s" gnus-summary-save-newsrc
+  "P" gnus-summary-prev-group)
+
+(gnus-define-keys (gnus-summary-article-map "A" gnus-summary-mode-map)
+  " " gnus-summary-next-page
+  "n" gnus-summary-next-page
+  [?\S-\ ] gnus-summary-prev-page
+  "\177" gnus-summary-prev-page
+  [delete] gnus-summary-prev-page
+  "p" gnus-summary-prev-page
+  "\r" gnus-summary-scroll-up
+  "\M-\r" gnus-summary-scroll-down
+  "<" gnus-summary-beginning-of-article
+  ">" gnus-summary-end-of-article
+  "b" gnus-summary-beginning-of-article
+  "e" gnus-summary-end-of-article
+  "^" gnus-summary-refer-parent-article
+  "r" gnus-summary-refer-parent-article
+  "C" gnus-summary-show-complete-article
+  "D" gnus-summary-enter-digest-group
+  "R" gnus-summary-refer-references
+  "T" gnus-summary-refer-thread
+  "W" gnus-warp-to-article
+  "g" gnus-summary-show-article
+  "s" gnus-summary-isearch-article
+  "\t" gnus-summary-widget-forward
+  [backtab] gnus-summary-widget-backward
+  "P" gnus-summary-print-article
+  "S" gnus-sticky-article
+  "M" gnus-mailing-list-insinuate
+  "t" gnus-article-babel)
+
+(gnus-define-keys (gnus-summary-wash-map "W" gnus-summary-mode-map)
+  "b" gnus-article-add-buttons
+  "B" gnus-article-add-buttons-to-head
+  "o" gnus-article-treat-overstrike
+  "e" gnus-article-emphasize
+  "w" gnus-article-fill-cited-article
+  "Q" gnus-article-fill-long-lines
+  "L" gnus-article-toggle-truncate-lines
+  "C" gnus-article-capitalize-sentences
+  "c" gnus-article-remove-cr
+  "q" gnus-article-de-quoted-unreadable
+  "6" gnus-article-de-base64-unreadable
+  "Z" gnus-article-decode-HZ
+  "A" gnus-article-treat-ansi-sequences
+  "h" gnus-article-wash-html
+  "u" gnus-article-unsplit-urls
+  "s" gnus-summary-force-verify-and-decrypt
+  "f" gnus-article-display-x-face
+  "l" gnus-summary-stop-page-breaking
+  "r" gnus-summary-caesar-message
+  "m" gnus-summary-morse-message
+  "t" gnus-summary-toggle-header
+  "g" gnus-treat-smiley
+  "v" gnus-summary-verbose-headers
+  "a" gnus-article-strip-headers-in-body ;; mnemonic: wash archive
+  "p" gnus-article-verify-x-pgp-sig
+  "d" gnus-article-treat-dumbquotes
+  "U" gnus-article-treat-non-ascii
+  "i" gnus-summary-idna-message)
+
+(gnus-define-keys (gnus-summary-wash-deuglify-map "Y" gnus-summary-wash-map)
+  ;; mnemonic: deuglif*Y*
+  "u" gnus-article-outlook-unwrap-lines
+  "a" gnus-article-outlook-repair-attribution
+  "c" gnus-article-outlook-rearrange-citation
+  "f" gnus-article-outlook-deuglify-article) ;; mnemonic: full deuglify
+
+(gnus-define-keys (gnus-summary-wash-hide-map "W" gnus-summary-wash-map)
+  "a" gnus-article-hide
+  "h" gnus-article-hide-headers
+  "b" gnus-article-hide-boring-headers
+  "s" gnus-article-hide-signature
+  "c" gnus-article-hide-citation
+  "C" gnus-article-hide-citation-in-followups
+  "l" gnus-article-hide-list-identifiers
+  "B" gnus-article-strip-banner
+  "P" gnus-article-hide-pem
+  "\C-c" gnus-article-hide-citation-maybe)
+
+(gnus-define-keys (gnus-summary-wash-highlight-map "H" gnus-summary-wash-map)
+  "a" gnus-article-highlight
+  "h" gnus-article-highlight-headers
+  "c" gnus-article-highlight-citation
+  "s" gnus-article-highlight-signature)
+
+(gnus-define-keys (gnus-summary-wash-header-map "G" gnus-summary-wash-map)
+  "f" gnus-article-treat-fold-headers
+  "u" gnus-article-treat-unfold-headers
+  "n" gnus-article-treat-fold-newsgroups)
+
+(gnus-define-keys (gnus-summary-wash-display-map "D" gnus-summary-wash-map)
+  "x" gnus-article-display-x-face
+  "d" gnus-article-display-face
+  "s" gnus-treat-smiley
+  "D" gnus-article-remove-images
+  "W" gnus-article-show-images
+  "f" gnus-treat-from-picon
+  "m" gnus-treat-mail-picon
+  "n" gnus-treat-newsgroups-picon
+  "g" gnus-treat-from-gravatar
+  "h" gnus-treat-mail-gravatar)
+
+(gnus-define-keys (gnus-summary-wash-mime-map "M" gnus-summary-wash-map)
+  "w" gnus-article-decode-mime-words
+  "c" gnus-article-decode-charset
+  "h" gnus-mime-buttonize-attachments-in-header
+  "v" gnus-mime-view-all-parts
+  "b" gnus-article-view-part)
+
+(gnus-define-keys (gnus-summary-wash-time-map "T" gnus-summary-wash-map)
+  "z" gnus-article-date-ut
+  "u" gnus-article-date-ut
+  "l" gnus-article-date-local
+  "p" gnus-article-date-english
+  "e" gnus-article-date-lapsed
+  "o" gnus-article-date-original
+  "i" gnus-article-date-iso8601
+  "s" gnus-article-date-user)
+
+(gnus-define-keys (gnus-summary-wash-empty-map "E" gnus-summary-wash-map)
+  "t" gnus-article-remove-trailing-blank-lines
+  "l" gnus-article-strip-leading-blank-lines
+  "m" gnus-article-strip-multiple-blank-lines
+  "a" gnus-article-strip-blank-lines
+  "A" gnus-article-strip-all-blank-lines
+  "s" gnus-article-strip-leading-space
+  "e" gnus-article-strip-trailing-space
+  "w" gnus-article-remove-leading-whitespace)
+
+(gnus-define-keys (gnus-summary-help-map "H" gnus-summary-mode-map)
+  "v" gnus-version
+  "d" gnus-summary-describe-group
+  "h" gnus-summary-describe-briefly
+  "i" gnus-info-find-node)
+
+(gnus-define-keys (gnus-summary-backend-map "B" gnus-summary-mode-map)
+  "e" gnus-summary-expire-articles
+  "\M-\C-e" gnus-summary-expire-articles-now
+  "\177" gnus-summary-delete-article
+  [delete] gnus-summary-delete-article
+  [backspace] gnus-summary-delete-article
+  "m" gnus-summary-move-article
+  "r" gnus-summary-respool-article
+  "w" gnus-summary-edit-article
+  "c" gnus-summary-copy-article
+  "B" gnus-summary-crosspost-article
+  "q" gnus-summary-respool-query
+  "t" gnus-summary-respool-trace
+  "i" gnus-summary-import-article
+  "I" gnus-summary-create-article
+  "p" gnus-summary-article-posted-p)
+
+(gnus-define-keys (gnus-summary-save-map "O" gnus-summary-mode-map)
+  "o" gnus-summary-save-article
+  "m" gnus-summary-save-article-mail
+  "F" gnus-summary-write-article-file
+  "r" gnus-summary-save-article-rmail
+  "f" gnus-summary-save-article-file
+  "b" gnus-summary-save-article-body-file
+  "B" gnus-summary-write-article-body-file
+  "h" gnus-summary-save-article-folder
+  "v" gnus-summary-save-article-vm
+  "p" gnus-summary-pipe-output
+  "P" gnus-summary-muttprint)
+
+(gnus-define-keys (gnus-summary-mime-map "K" gnus-summary-mode-map)
+  "b" gnus-summary-display-buttonized
+  "m" gnus-summary-repair-multipart
+  "v" gnus-article-view-part
+  "o" gnus-article-save-part
+  "O" gnus-article-save-part-and-strip
+  "r" gnus-article-replace-part
+  "d" gnus-article-delete-part
+  "t" gnus-article-view-part-as-type
+  "j" gnus-article-jump-to-part
+  "c" gnus-article-copy-part
+  "C" gnus-article-view-part-as-charset
+  "e" gnus-article-view-part-externally
+  "H" gnus-article-browse-html-article
+  "E" gnus-article-encrypt-body
+  "i" gnus-article-inline-part
+  "|" gnus-article-pipe-part)
+
+(gnus-define-keys (gnus-uu-mark-map "P" gnus-summary-mark-map)
+  "p" gnus-summary-mark-as-processable
+  "u" gnus-summary-unmark-as-processable
+  "U" gnus-summary-unmark-all-processable
+  "v" gnus-uu-mark-over
+  "s" gnus-uu-mark-series
+  "r" gnus-uu-mark-region
+  "g" gnus-uu-unmark-region
+  "R" gnus-uu-mark-by-regexp
+  "G" gnus-uu-unmark-by-regexp
+  "t" gnus-uu-mark-thread
+  "T" gnus-uu-unmark-thread
+  "a" gnus-uu-mark-all
+  "b" gnus-uu-mark-buffer
+  "S" gnus-uu-mark-sparse
+  "k" gnus-summary-kill-process-mark
+  "y" gnus-summary-yank-process-mark
+  "w" gnus-summary-save-process-mark
+  "i" gnus-uu-invert-processable)
+
+(gnus-define-keys (gnus-uu-extract-map "X" gnus-summary-mode-map)
+  ;;"x" gnus-uu-extract-any
+  "m" gnus-summary-save-parts
+  "u" gnus-uu-decode-uu
+  "U" gnus-uu-decode-uu-and-save
+  "s" gnus-uu-decode-unshar
+  "S" gnus-uu-decode-unshar-and-save
+  "o" gnus-uu-decode-save
+  "O" gnus-uu-decode-save
+  "b" gnus-uu-decode-binhex
+  "B" gnus-uu-decode-binhex
+  "Y" gnus-uu-decode-yenc
+  "p" gnus-uu-decode-postscript
+  "P" gnus-uu-decode-postscript-and-save)
+
+(gnus-define-keys
+    (gnus-uu-extract-view-map "v" gnus-uu-extract-map)
+  "u" gnus-uu-decode-uu-view
+  "U" gnus-uu-decode-uu-and-save-view
+  "s" gnus-uu-decode-unshar-view
+  "S" gnus-uu-decode-unshar-and-save-view
+  "o" gnus-uu-decode-save-view
+  "O" gnus-uu-decode-save-view
+  "b" gnus-uu-decode-binhex-view
+  "B" gnus-uu-decode-binhex-view
+  "p" gnus-uu-decode-postscript-view
+  "P" gnus-uu-decode-postscript-and-save-view)
+
+(defvar gnus-article-post-menu nil)
+
+(defconst gnus-summary-menu-maxlen 20)
+
+(defun gnus-summary-menu-split (menu)
+  ;; If we have lots of elements, divide them into groups of 20
+  ;; and make a pane (or submenu) for each one.
+  (if (> (length menu) (/ (* gnus-summary-menu-maxlen 3) 2))
+      (let ((menu menu) sublists next
+           (i 1))
+       (while menu
+         ;; Pull off the next gnus-summary-menu-maxlen elements
+         ;; and make them the next element of sublist.
+         (setq next (nthcdr gnus-summary-menu-maxlen menu))
+         (if next
+             (setcdr (nthcdr (1- gnus-summary-menu-maxlen) menu)
+                     nil))
+         (setq sublists (cons (cons (format "%s ... %s" (aref (car menu) 0)
+                                            (aref (car (last menu)) 0)) menu)
+                              sublists))
+         (setq i (1+ i))
+         (setq menu next))
+       (nreverse sublists))
+    ;; Few elements--put them all in one pane.
+    menu))
+
+(defun gnus-summary-make-menu-bar ()
+  (gnus-turn-off-edit-menu 'summary)
+
+  (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 article score" gnus-summary-current-score t]
+         ["Current thread score" (gnus-summary-current-score 'total) 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]
+             ["List identifiers" gnus-article-hide-list-identifiers 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])
+            ("MIME"
+             ["Words" gnus-article-decode-mime-words t]
+             ["Charset" gnus-article-decode-charset t]
+             ["QP" gnus-article-de-quoted-unreadable t]
+             ["Base64" gnus-article-de-base64-unreadable t]
+             ["View MIME buttons" gnus-summary-display-buttonized t]
+             ["View MIME buttons in header"
+              gnus-mime-buttonize-attachments-in-header t]
+             ["View all" gnus-mime-view-all-parts t]
+             ["Verify and Decrypt" gnus-summary-force-verify-and-decrypt t]
+             ["Encrypt body" gnus-article-encrypt-body
+              :active (not (gnus-group-read-only-p))
+              ,@(if (featurep 'xemacs) nil
+                  '(:help "Encrypt the message body on disk"))]
+             ["Extract all parts..." gnus-summary-save-parts t]
+             ("Multipart"
+              ["Repair multipart" gnus-summary-repair-multipart t]
+              ["Pipe part..." gnus-article-pipe-part t]
+              ["Inline part" gnus-article-inline-part t]
+              ["View part as type..." gnus-article-view-part-as-type t]
+              ["Encrypt body" gnus-article-encrypt-body
+               :active (not (gnus-group-read-only-p))
+              ,@(if (featurep 'xemacs) nil
+                  '(:help "Encrypt the message body on disk"))]
+              ["View part externally" gnus-article-view-part-externally t]
+              ["View HTML parts in browser" gnus-article-browse-html-article t]
+              ["View part with charset..." gnus-article-view-part-as-charset t]
+              ["Copy part" gnus-article-copy-part t]
+              ["Save part..." gnus-article-save-part t]
+              ["View part" gnus-article-view-part 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"
+             ["Display HTML images" gnus-article-show-images t]
+             ["Remove images" gnus-article-remove-images t]
+             ["Toggle smiley" gnus-treat-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]
+              ["Show Gravatars in From" gnus-treat-from-gravatar t]
+             ["Show Gravatars in mail headers" gnus-treat-mail-gravatar t]
+             ("View as different encoding"
+              ,@(gnus-summary-menu-split
+                 (mapcar
+                  (lambda (cs)
+                    ;; Since easymenu under Emacs doesn't allow
+                    ;; lambda forms for menu commands, we should
+                    ;; provide intern'ed function symbols.
+                    (let ((command (intern (format "\
+gnus-summary-show-article-from-menu-as-charset-%s" cs))))
+                      (fset command
+                            `(lambda ()
+                               (interactive)
+                               (let ((gnus-summary-show-article-charset-alist
+                                      '((1 . ,cs))))
+                                 (gnus-summary-show-article 1))))
+                      `[,(symbol-name cs) ,command t]))
+                  (sort (if (fboundp 'coding-system-list)
+                            (coding-system-list)
+                          (mapcar 'car mm-mime-mule-charset-alist))
+                        'string<)))))
+            ("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"
+               gnus-article-remove-leading-whitespace t])
+             ["Overstrike" gnus-article-treat-overstrike t]
+             ["Dumb quotes" gnus-article-treat-dumbquotes t]
+             ["Non-ASCII" gnus-article-treat-non-ascii t]
+             ["Emphasis" gnus-article-emphasize t]
+             ["Word wrap" gnus-article-fill-cited-article t]
+             ["Fill long lines" gnus-article-fill-long-lines t]
+             ["Toggle truncate long lines" gnus-article-toggle-truncate-lines t]
+             ["Capitalize sentences" gnus-article-capitalize-sentences t]
+             ["Remove 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"))]
+             ["De-IDNA" gnus-summary-idna-message t]
+             ["Morse decode" gnus-summary-morse-message 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]
+             ["Unsplit URLs" gnus-article-unsplit-urls t]
+             ["Verify X-PGP-Sig" gnus-article-verify-x-pgp-sig t]
+             ["Decode HZ" gnus-article-decode-HZ t]
+             ["ANSI sequences" gnus-article-treat-ansi-sequences t]
+             ("(Outlook) Deuglify"
+              ["Unwrap lines" gnus-article-outlook-unwrap-lines t]
+              ["Repair attribution" gnus-article-outlook-repair-attribution t]
+              ["Rearrange citation" gnus-article-outlook-rearrange-citation t]
+              ["Full (Outlook) deuglify"
+               gnus-article-outlook-deuglify-article t])
+             )
+            ("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
+              ,@(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]
+             ["Print with Muttprint..." gnus-summary-muttprint t]
+             ["Print" gnus-summary-print-article
+              ,@(if (featurep 'xemacs) '(t)
+                  '(:help "Generate and print a PostScript image"))])
+            ("Copy, move,... (Backend)"
+             ,@(if (featurep 'xemacs) nil
+                 '(:help "Copying, moving, expiring articles..."))
+             ["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
+              (gnus-check-backend-function
+               'request-accept-article gnus-newsgroup-name)]
+             ["Create article..." gnus-summary-create-article
+              (gnus-check-backend-function
+               'request-accept-article gnus-newsgroup-name)]
+             ["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
+              ,@(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]
+             ["All MIME parts" gnus-summary-save-parts 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]
+            ["Make article buffer sticky" gnus-sticky-article 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 :keys "C-u g"])))
+      (easy-menu-define
+       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
+             (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"
+       ["Find all messages in thread" gnus-summary-refer-thread t]
+       ["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]
+       ["Mark thread as expired" gnus-summary-expire-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"
+       ["Send a message (mail or news)" gnus-summary-post-news
+        ,@(if (featurep 'xemacs) '(t)
+            '(:help "Compose a new message (mail or news)"))]
+       ["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"))]
+       ["Very wide reply" gnus-summary-very-wide-reply t]
+       ["Very wide reply and yank" gnus-summary-very-wide-reply-with-original
+        ,@(if (featurep 'xemacs) '(t)
+            '(:help "Mail a very wide 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]
+       ["Resend message edit" gnus-summary-resend-message-edit 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]
+       ["Strip signature on reply"
+        (lambda ()
+          (interactive)
+          (if (not (memq message-cite-function
+                         '(message-cite-original-without-signature
+                           message-cite-original)))
+              ;; Stupid workaround for XEmacs not honoring :visible.
+              (message "Can't toggle this value of `message-cite-function'")
+            (setq message-cite-function
+                  (if (eq message-cite-function
+                          'message-cite-original-without-signature)
+                      'message-cite-original
+                    'message-cite-original-without-signature))))
+        ;; XEmacs barfs on :visible.
+        ,@(if (featurep 'xemacs) nil
+            '(:visible (memq message-cite-function
+                             '(message-cite-original-without-signature
+                               message-cite-original))))
+        :style toggle
+        :selected (eq message-cite-function
+                      'message-cite-original-without-signature)
+        ,@(if (featurep 'xemacs) nil
+            '(:help "Strip signature from cited article when replying."))]
+       ;;("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)
+      ;; Don't share post menu.
+      (setq gnus-article-post-menu
+           (copy-keymap gnus-summary-post-menu))))
+    (define-key gnus-article-mode-map [menu-bar post]
+      (cons "Post" gnus-article-post-menu))
+
+    (easy-menu-define
+      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
+         (gnus-mark-active-p)]
+        ["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]
+        ["Recipient..." gnus-summary-limit-to-recipient t]
+        ["Address..." gnus-summary-limit-to-address 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]
+        ["Unseen" gnus-summary-limit-to-unseen t]
+        ["Singletons" gnus-summary-limit-to-singletons t]
+        ["Replied" gnus-summary-limit-to-replied t]
+        ["Non-dormant" gnus-summary-limit-exclude-dormant t]
+        ["Next or process marked 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]
+        ["Invert marks" gnus-uu-invert-processable t]
+        ["Mark above" gnus-uu-mark-over t]
+        ["Mark series" gnus-uu-mark-series t]
+        ["Mark region" gnus-uu-mark-region (gnus-mark-active-p)]
+        ["Unmark region" gnus-uu-unmark-region (gnus-mark-active-p)]
+        ["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]
+         ["Run command on marked..." gnus-summary-universal-argument t]))
+       ("Registry Marks")
+       ("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 most recent number" gnus-summary-sort-by-most-recent-number t]
+        ["Sort by author" gnus-summary-sort-by-author t]
+        ["Sort by recipient" gnus-summary-sort-by-recipient t]
+        ["Sort by subject" gnus-summary-sort-by-subject t]
+        ["Sort by date" gnus-summary-sort-by-date t]
+        ["Sort by most recent date" gnus-summary-sort-by-most-recent-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]
+        ["Randomize" gnus-summary-sort-by-random t]
+        ["Original sort" gnus-summary-sort-by-original t])
+       ("Help"
+        ["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]
+        ["Insert dormant articles" gnus-summary-insert-dormant-articles t]
+        ["Insert ticked articles" gnus-summary-insert-ticked-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 articles..." 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]
+        ["Catchup and goto prev" gnus-summary-catchup-and-goto-prev-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)))
+
+(defvar gnus-summary-tool-bar-map nil)
+
+;; Note: The :set function in the `gnus-summary-tool-bar*' variables will only
+;; affect _new_ message buffers.  We might add a function that walks thru all
+;; summary-mode buffers and force the update.
+(defun gnus-summary-tool-bar-update (&optional symbol value)
+  "Update summary mode toolbar.
+Setter function for custom variables."
+  (setq-default gnus-summary-tool-bar-map nil)
+  (when symbol
+    ;; When used as ":set" function:
+    (set-default symbol value))
+  (when (gnus-buffer-live-p gnus-summary-buffer)
+    (with-current-buffer gnus-summary-buffer
+      (gnus-summary-make-tool-bar))))
+
+(defcustom gnus-summary-tool-bar (if (eq gmm-tool-bar-style 'gnome)
+                                    'gnus-summary-tool-bar-gnome
+                                  'gnus-summary-tool-bar-retro)
+  "Specifies the Gnus summary tool bar.
+
+It can be either a list or a symbol referring to a list.  See
+`gmm-tool-bar-from-list' for the format of the list.  The
+default key map is `gnus-summary-mode-map'.
+
+Pre-defined symbols include `gnus-summary-tool-bar-gnome' and
+`gnus-summary-tool-bar-retro'."
+  :type '(choice (const :tag "GNOME style" gnus-summary-tool-bar-gnome)
+                (const :tag "Retro look"  gnus-summary-tool-bar-retro)
+                (repeat :tag "User defined list" gmm-tool-bar-item)
+                (symbol))
+  :version "23.1" ;; No Gnus
+  :initialize 'custom-initialize-default
+  :set 'gnus-summary-tool-bar-update
+  :group 'gnus-summary)
+
+(defcustom gnus-summary-tool-bar-gnome
+  '((gnus-summary-post-news "mail/compose" nil)
+    (gnus-summary-insert-new-articles "mail/inbox" nil
+                                     :visible (or (not gnus-agent)
+                                                  gnus-plugged))
+    (gnus-summary-reply-with-original "mail/reply")
+    (gnus-summary-reply "mail/reply" nil :visible nil)
+    (gnus-summary-followup-with-original "mail/reply-all")
+    (gnus-summary-followup "mail/reply-all" nil :visible nil)
+    (gnus-summary-mail-forward "mail/forward")
+    (gnus-summary-save-article "mail/save")
+    (gnus-summary-search-article-forward "search" nil :visible nil)
+    (gnus-summary-print-article "print")
+    (gnus-summary-tick-article-forward "flag-followup" nil :visible nil)
+    ;; Some new commands that may need more suitable icons:
+    (gnus-summary-save-newsrc "save" nil :visible nil)
+    ;; (gnus-summary-show-article "stock_message-display" nil :visible nil)
+    (gnus-summary-prev-article "left-arrow")
+    (gnus-summary-next-article "right-arrow")
+    (gnus-summary-next-page "next-page")
+    ;; (gnus-summary-enter-digest-group "right_arrow" nil :visible nil)
+    ;;
+    ;; Maybe some sort-by-... could be added:
+    ;; (gnus-summary-sort-by-author "sort-a-z" nil :visible nil)
+    ;; (gnus-summary-sort-by-date "sort-1-9" nil :visible nil)
+    (gnus-summary-mark-as-expirable
+     "delete" nil
+     :visible (gnus-check-backend-function 'request-expire-articles
+                                          gnus-newsgroup-name))
+    (gnus-summary-mark-as-spam
+     "mail/spam" t
+     :visible (and (fboundp 'spam-group-ham-contents-p)
+                  (spam-group-ham-contents-p gnus-newsgroup-name))
+     :help "Mark as spam")
+    (gnus-summary-mark-as-read-forward
+     "mail/not-spam" nil
+     :visible (and (fboundp 'spam-group-spam-contents-p)
+                  (spam-group-spam-contents-p gnus-newsgroup-name)))
+    ;;
+    (gnus-summary-exit "exit")
+    (gmm-customize-mode "preferences" t :help "Edit mode preferences")
+    (gnus-info-find-node "help"))
+  "List of functions for the summary tool bar (GNOME style).
+
+See `gmm-tool-bar-from-list' for the format of the list."
+  :type '(repeat gmm-tool-bar-item)
+  :version "23.1" ;; No Gnus
+  :initialize 'custom-initialize-default
+  :set 'gnus-summary-tool-bar-update
+  :group 'gnus-summary)
+
+(defcustom gnus-summary-tool-bar-retro
+  '((gnus-summary-prev-unread-article "gnus/prev-ur")
+    (gnus-summary-next-unread-article "gnus/next-ur")
+    (gnus-summary-post-news "gnus/post")
+    (gnus-summary-followup-with-original "gnus/fuwo")
+    (gnus-summary-followup "gnus/followup")
+    (gnus-summary-reply-with-original "gnus/reply-wo")
+    (gnus-summary-reply "gnus/reply")
+    (gnus-summary-caesar-message "gnus/rot13")
+    (gnus-uu-decode-uu "gnus/uu-decode")
+    (gnus-summary-save-article-file "gnus/save-aif")
+    (gnus-summary-save-article "gnus/save-art")
+    (gnus-uu-post-news "gnus/uu-post")
+    (gnus-summary-catchup "gnus/catchup")
+    (gnus-summary-catchup-and-exit "gnus/cu-exit")
+    (gnus-summary-exit "gnus/exit-summ")
+    ;; Some new command that may need more suitable icons:
+    (gnus-summary-print-article "gnus/print" nil :visible nil)
+    (gnus-summary-mark-as-expirable "gnus/close" nil :visible nil)
+    (gnus-summary-save-newsrc "gnus/save" nil :visible nil)
+    ;; (gnus-summary-enter-digest-group "gnus/right_arrow" nil :visible nil)
+    (gnus-summary-search-article-forward "gnus/search" nil :visible nil)
+    ;; (gnus-summary-insert-new-articles "gnus/paste" nil :visible nil)
+    ;; (gnus-summary-toggle-threads "gnus/open" nil :visible nil)
+    ;;
+    (gnus-info-find-node "gnus/help" nil :visible nil))
+  "List of functions for the summary tool bar (retro look).
+
+See `gmm-tool-bar-from-list' for the format of the list."
+  :type '(repeat gmm-tool-bar-item)
+  :version "23.1" ;; No Gnus
+  :initialize 'custom-initialize-default
+  :set 'gnus-summary-tool-bar-update
+  :group 'gnus-summary)
+
+(defcustom gnus-summary-tool-bar-zap-list t
+  "List of icon items from the global tool bar.
+These items are not displayed in the Gnus summary mode tool bar.
+
+See `gmm-tool-bar-from-list' for the format of the list."
+  :type 'gmm-tool-bar-zap-list
+  :version "23.1" ;; No Gnus
+  :initialize 'custom-initialize-default
+  :set 'gnus-summary-tool-bar-update
+  :group 'gnus-summary)
+
+(defvar image-load-path)
+(defvar tool-bar-map)
+
+(defun gnus-summary-make-tool-bar (&optional force)
+  "Make a summary mode tool bar from `gnus-summary-tool-bar'.
+When FORCE, rebuild the tool bar."
+  (when (and (not (featurep 'xemacs))
+            (boundp 'tool-bar-mode)
+            tool-bar-mode
+            (or (not gnus-summary-tool-bar-map) force))
+    (let* ((load-path
+           (gmm-image-load-path-for-library "gnus"
+                                            "mail/save.xpm"
+                                            nil t))
+           (image-load-path (cons (car load-path)
+                                  (when (boundp 'image-load-path)
+                                    image-load-path)))
+          (map (gmm-tool-bar-from-list gnus-summary-tool-bar
+                                       gnus-summary-tool-bar-zap-list
+                                       'gnus-summary-mode-map)))
+      (when map
+       ;; Need to set `gnus-summary-tool-bar-map' because `gnus-article-mode'
+       ;; uses its value.
+       (setq gnus-summary-tool-bar-map map))))
+  (set (make-local-variable 'tool-bar-map) gnus-summary-tool-bar-map))
+
+(defun gnus-make-score-map (type)
+  "Make a summary score map of type TYPE."
+  (if t
+      nil
+    (let ((headers '(("author" "from" string)
+                    ("subject" "subject" string)
+                    ("article body" "body" string)
+                    ("article head" "head" string)
+                    ("xref" "xref" string)
+                    ("extra header" "extra" string)
+                    ("lines" "lines" number)
+                    ("followups to author" "followup" string)))
+         (types '((number ("less than" <)
+                          ("greater than" >)
+                          ("equal" =))
+                  (string ("substring" s)
+                          ("exact string" e)
+                          ("fuzzy string" f)
+                          ("regexp" r))))
+         (perms '(("temporary" (current-time-string))
+                  ("permanent" nil)
+                  ("immediate" now)))
+         header)
+      (list
+       (apply
+       'nconc
+       (list
+        (if (eq type 'lower)
+            "Lower score"
+          "Increase score"))
+       (let (outh)
+         (while headers
+           (setq header (car headers))
+           (setq outh
+                 (cons
+                  (apply
+                   'nconc
+                   (list (car header))
+                   (let ((ts (cdr (assoc (nth 2 header) types)))
+                         outt)
+                     (while ts
+                       (setq outt
+                             (cons
+                              (apply
+                               'nconc
+                               (list (caar ts))
+                               (let ((ps perms)
+                                     outp)
+                                 (while ps
+                                   (setq outp
+                                         (cons
+                                          (vector
+                                           (caar ps)
+                                           (list
+                                            'gnus-summary-score-entry
+                                            (nth 1 header)
+                                            (if (or (string= (nth 1 header)
+                                                             "head")
+                                                    (string= (nth 1 header)
+                                                             "body"))
+                                                ""
+                                              (list 'gnus-summary-header
+                                                    (nth 1 header)))
+                                            (list 'quote (nth 1 (car ts)))
+                                            (list 'gnus-score-delta-default
+                                                  nil)
+                                            (nth 1 (car ps))
+                                            t)
+                                           t)
+                                          outp))
+                                   (setq ps (cdr ps)))
+                                 (list (nreverse outp))))
+                              outt))
+                       (setq ts (cdr ts)))
+                     (list (nreverse outt))))
+                  outh))
+           (setq headers (cdr headers)))
+         (list (nreverse outh))))))))
+
+
+(declare-function turn-on-gnus-mailing-list-mode "gnus-ml" ())
+(defvar bookmark-make-record-function)
+\f
+(defvar bidi-paragraph-direction)
+
+(defun gnus-summary-mode (&optional group)
+  "Major mode for reading articles.
+
+All normal editing commands are switched off.
+\\<gnus-summary-mode-map>
+Each line in this buffer represents one article.  To read an
+article, you can, for instance, type `\\[gnus-summary-next-page]'.  To move forwards
+and backwards while displaying articles, type `\\[gnus-summary-next-unread-article]' and `\\[gnus-summary-prev-unread-article]',
+respectively.
+
+You can also post articles and send mail from this buffer.  To
+follow up an article, type `\\[gnus-summary-followup]'.  To mail a reply to the author
+of an article, type `\\[gnus-summary-reply]'.
+
+There are approx. one gazillion commands you can execute in this
+buffer; read the info pages for more information (`\\[gnus-info-find-node]').
+
+The following commands are available:
+
+\\{gnus-summary-mode-map}"
+  ;; FIXME: Use define-derived-mode.
+  (interactive)
+  (kill-all-local-variables)
+  (let ((gnus-summary-local-variables gnus-newsgroup-variables))
+    (gnus-summary-make-local-variables))
+  (gnus-summary-make-local-variables)
+  (setq gnus-newsgroup-name group)
+  (when (gnus-visual-p 'summary-menu 'menu)
+    (gnus-summary-make-menu-bar)
+    (gnus-summary-make-tool-bar))
+  (gnus-make-thread-indent-array)
+  (gnus-simplify-mode-line)
+  (setq major-mode 'gnus-summary-mode)
+  (setq mode-name "Summary")
+  (use-local-map gnus-summary-mode-map)
+  (buffer-disable-undo)
+  (setq buffer-read-only t             ;Disable modification
+       show-trailing-whitespace nil)
+  (setq truncate-lines t)
+  ;; Force paragraph direction to be left-to-right.  Don't make it
+  ;; bound globally in old Emacsen and XEmacsen.
+  (set (make-local-variable 'bidi-paragraph-direction) 'left-to-right)
+  (add-to-invisibility-spec '(gnus-sum . t))
+  (gnus-summary-set-display-table)
+  (gnus-set-default-directory)
+  (make-local-variable 'gnus-summary-line-format)
+  (make-local-variable 'gnus-summary-line-format-spec)
+  (make-local-variable 'gnus-summary-dummy-line-format)
+  (make-local-variable 'gnus-summary-dummy-line-format-spec)
+  (make-local-variable 'gnus-summary-mark-positions)
+  (gnus-make-local-hook 'pre-command-hook)
+  (add-hook 'pre-command-hook 'gnus-set-global-variables nil t)
+  (gnus-run-mode-hooks 'gnus-summary-mode-hook)
+  (turn-on-gnus-mailing-list-mode)
+  (mm-enable-multibyte)
+  (set (make-local-variable 'bookmark-make-record-function)
+       'gnus-summary-bookmark-make-record)
+  (gnus-update-format-specifications nil 'summary 'summary-mode 'summary-dummy)
+  (gnus-update-summary-mark-positions))
+
+(defun gnus-summary-make-local-variables ()
+  "Make all the local summary buffer variables."
+  (let (global)
+    (dolist (local gnus-summary-local-variables)
+      (if (consp local)
+         (progn
+           (if (eq (cdr local) 'global)
+               ;; Copy the global value of the variable.
+               (setq global (symbol-value (car local)))
+             ;; Use the value from the list.
+             (setq global (eval (cdr local))))
+           (set (make-local-variable (car local)) global))
+       ;; Simple nil-valued local variable.
+       (set (make-local-variable local) nil)))))
+
+;; Summary data functions.
+
+(defmacro gnus-data-number (data)
+  `(car ,data))
+
+(defmacro gnus-data-set-number (data number)
+  `(setcar ,data ,number))
+
+(defmacro gnus-data-mark (data)
+  `(nth 1 ,data))
+
+(defmacro gnus-data-set-mark (data mark)
+  `(setcar (nthcdr 1 ,data) ,mark))
+
+(defmacro gnus-data-pos (data)
+  `(nth 2 ,data))
+
+(defmacro gnus-data-set-pos (data pos)
+  `(setcar (nthcdr 2 ,data) ,pos))
+
+(defmacro gnus-data-header (data)
+  `(nth 3 ,data))
+
+(defmacro gnus-data-set-header (data header)
+  `(setf (nth 3 ,data) ,header))
+
+(defmacro gnus-data-level (data)
+  `(nth 4 ,data))
+
+(defmacro gnus-data-unread-p (data)
+  `(= (nth 1 ,data) gnus-unread-mark))
+
+(defmacro gnus-data-read-p (data)
+  `(/= (nth 1 ,data) gnus-unread-mark))
+
+(defmacro gnus-data-pseudo-p (data)
+  `(consp (nth 3 ,data)))
+
+(defmacro gnus-data-find (number)
+  `(assq ,number gnus-newsgroup-data))
+
+(defmacro gnus-data-find-list (number &optional data)
+  `(let ((bdata ,(or data 'gnus-newsgroup-data)))
+     (memq (assq ,number bdata)
+          bdata)))
+
+(defmacro gnus-data-make (number mark pos header level)
+  `(list ,number ,mark ,pos ,header ,level))
+
+(defun gnus-data-enter (after-article number mark pos header level offset)
+  (let ((data (gnus-data-find-list after-article)))
+    (unless data
+      (error "No such article: %d" after-article))
+    (setcdr data (cons (gnus-data-make number mark pos header level)
+                      (cdr data)))
+    (setq gnus-newsgroup-data-reverse nil)
+    (gnus-data-update-list (cddr data) offset)))
+
+(defun gnus-data-enter-list (after-article list &optional offset)
+  (when list
+    (let ((data (and after-article (gnus-data-find-list after-article)))
+         (ilist list))
+      (if (not (or data
+                  after-article))
+         (let ((odata gnus-newsgroup-data))
+           (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
+       ;; list.
+       (setq list (last list))
+       (if (not data)
+           (progn
+             (setcdr list gnus-newsgroup-data)
+             (setq gnus-newsgroup-data ilist)
+             (when offset
+               (gnus-data-update-list (cdr list) offset)))
+         (setcdr list (cdr data))
+         (setcdr data ilist)
+         (when offset
+           (gnus-data-update-list (cdr list) offset))))
+      (setq gnus-newsgroup-data-reverse nil))))
+
+(defun gnus-data-remove (article &optional offset)
+  (let ((data gnus-newsgroup-data))
+    (if (= (gnus-data-number (car data)) article)
+       (progn
+         (setq gnus-newsgroup-data (cdr gnus-newsgroup-data)
+               gnus-newsgroup-data-reverse nil)
+         (when offset
+           (gnus-data-update-list gnus-newsgroup-data offset)))
+      (while (cdr data)
+       (when (= (gnus-data-number (cadr data)) article)
+         (setcdr data (cddr data))
+         (when offset
+           (gnus-data-update-list (cdr data) offset))
+         (setq data nil
+               gnus-newsgroup-data-reverse nil))
+       (setq data (cdr data))))))
+
+(defmacro gnus-data-list (backward)
+  `(if ,backward
+       (or gnus-newsgroup-data-reverse
+          (setq gnus-newsgroup-data-reverse
+                (reverse gnus-newsgroup-data)))
+     gnus-newsgroup-data))
+
+(defun gnus-data-update-list (data offset)
+  "Add OFFSET to the POS of all data entries in DATA."
+  (setq gnus-newsgroup-data-reverse nil)
+  (while data
+    (setcar (nthcdr 2 (car data)) (+ offset (nth 2 (car data))))
+    (setq data (cdr data))))
+
+(defun gnus-summary-article-pseudo-p (article)
+  "Say whether this article is a pseudo article or not."
+  (not (vectorp (gnus-data-header (gnus-data-find article)))))
+
+(defmacro gnus-summary-article-sparse-p (article)
+  "Say whether this article is a sparse article or not."
+  `(memq ,article gnus-newsgroup-sparse))
+
+(defmacro gnus-summary-article-ancient-p (article)
+  "Say whether this article is a sparse article or not."
+  `(memq ,article gnus-newsgroup-ancient))
+
+(defun gnus-article-children (number)
+  "Return a list of all children to NUMBER."
+  (let* ((data (gnus-data-find-list number))
+        (level (gnus-data-level (car data)))
+        children)
+    (setq data (cdr data))
+    (while (and data
+               (= (gnus-data-level (car data)) (1+ level)))
+      (push (gnus-data-number (car data)) children)
+      (setq data (cdr data)))
+    children))
+
+(defmacro gnus-summary-skip-intangible ()
+  "If the current article is intangible, then jump to a different article."
+  '(let ((to (get-text-property (point) 'gnus-intangible)))
+     (and to (gnus-summary-goto-subject to))))
+
+(defmacro gnus-summary-article-intangible-p ()
+  "Say whether this article is intangible or not."
+  '(get-text-property (point) 'gnus-intangible))
+
+;; Some summary mode macros.
+
+(defmacro gnus-summary-article-number ()
+  "The article number of the article on the current line.
+If there isn't an article number here, then we return the current
+article number."
+  '(progn
+     (gnus-summary-skip-intangible)
+     (or (get-text-property (point) 'gnus-number)
+        (gnus-summary-last-subject))))
+
+(defmacro gnus-summary-article-header (&optional number)
+  "Return the header of article NUMBER."
+  `(gnus-data-header (gnus-data-find
+                     ,(or number '(gnus-summary-article-number)))))
+
+(defmacro gnus-summary-thread-level (&optional number)
+  "Return the level of thread that starts with article NUMBER."
+  `(if (and (eq gnus-summary-make-false-root 'dummy)
+           (get-text-property (point) 'gnus-intangible))
+       0
+     (gnus-data-level (gnus-data-find
+                      ,(or number '(gnus-summary-article-number))))))
+
+(defmacro gnus-summary-article-mark (&optional number)
+  "Return the mark of article NUMBER."
+  `(gnus-data-mark (gnus-data-find
+                   ,(or number '(gnus-summary-article-number)))))
+
+(defmacro gnus-summary-article-pos (&optional number)
+  "Return the position of the line of article NUMBER."
+  `(gnus-data-pos (gnus-data-find
+                  ,(or number '(gnus-summary-article-number)))))
+
+(defalias 'gnus-summary-subject-string 'gnus-summary-article-subject)
+(defmacro gnus-summary-article-subject (&optional number)
+  "Return current subject string or nil if nothing."
+  `(let ((headers
+         ,(if number
+              `(gnus-data-header (assq ,number gnus-newsgroup-data))
+            '(gnus-data-header (assq (gnus-summary-article-number)
+                                     gnus-newsgroup-data)))))
+     (and headers
+         (vectorp headers)
+         (mail-header-subject headers))))
+
+(defmacro gnus-summary-article-score (&optional number)
+  "Return current article score."
+  `(or (cdr (assq ,(or number '(gnus-summary-article-number))
+                 gnus-newsgroup-scored))
+       gnus-summary-default-score 0))
+
+(defun gnus-summary-article-children (&optional number)
+  "Return a list of article numbers that are children of article NUMBER."
+  (let* ((data (gnus-data-find-list (or number (gnus-summary-article-number))))
+        (level (gnus-data-level (car data)))
+        l children)
+    (while (and (setq data (cdr data))
+               (> (setq l (gnus-data-level (car data))) level))
+      (and (= (1+ level) l)
+          (push (gnus-data-number (car data))
+                children)))
+    (nreverse children)))
+
+(defun gnus-summary-article-parent (&optional number)
+  "Return the article number of the parent of article NUMBER."
+  (let* ((data (gnus-data-find-list (or number (gnus-summary-article-number))
+                                   (gnus-data-list t)))
+        (level (gnus-data-level (car data))))
+    (if (zerop level)
+       ()                              ; This is a root.
+      ;; We search until we find an article with a level less than
+      ;; this one.  That function has to be the parent.
+      (while (and (setq data (cdr data))
+                 (not (< (gnus-data-level (car data)) level))))
+      (and data (gnus-data-number (car data))))))
+
+(defun gnus-unread-mark-p (mark)
+  "Say whether MARK is the unread mark."
+  (= mark gnus-unread-mark))
+
+(defun gnus-read-mark-p (mark)
+  "Say whether MARK is one of the marks that mark as read.
+This is all marks except unread, ticked, dormant, and expirable."
+  (not (or (= mark gnus-unread-mark)
+          (= mark gnus-ticked-mark)
+          (= mark gnus-spam-mark)
+          (= mark gnus-dormant-mark)
+          (= mark gnus-expirable-mark))))
+
+(defmacro gnus-article-mark (number)
+  "Return the MARK of article NUMBER.
+This macro should only be used when computing the mark the \"first\"
+time; i.e., when generating the summary lines.  After that,
+`gnus-summary-article-mark' should be used to examine the
+marks of articles."
+  `(cond
+    ((memq ,number gnus-newsgroup-unsendable) gnus-unsendable-mark)
+    ((memq ,number gnus-newsgroup-downloadable) gnus-downloadable-mark)
+    ((memq ,number gnus-newsgroup-unreads) gnus-unread-mark)
+    ((memq ,number gnus-newsgroup-marked) gnus-ticked-mark)
+    ((memq ,number gnus-newsgroup-spam-marked) gnus-spam-mark)
+    ((memq ,number gnus-newsgroup-dormant) gnus-dormant-mark)
+    ((memq ,number gnus-newsgroup-expirable) gnus-expirable-mark)
+    (t (or (cdr (assq ,number gnus-newsgroup-reads))
+          gnus-ancient-mark))))
+
+;; Saving hidden threads.
+
+(defmacro gnus-save-hidden-threads (&rest forms)
+  "Save hidden threads, eval FORMS, and restore the hidden threads."
+  (let ((config (make-symbol "config")))
+    `(let ((,config (gnus-hidden-threads-configuration)))
+       (unwind-protect
+          (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."
+  (setq gnus-newsgroup-data-reverse nil)
+  (let ((data gnus-newsgroup-data))
+    (save-excursion
+      (gnus-save-hidden-threads
+       (gnus-summary-show-all-threads)
+       (goto-char (point-min))
+       (while data
+         (while (get-text-property (point) 'gnus-intangible)
+           (forward-line 1))
+         (gnus-data-set-pos (car data) (+ (point) 3))
+         (setq data (cdr data))
+         (forward-line 1))))))
+
+(defun gnus-hidden-threads-configuration ()
+  "Return the current hidden threads configuration."
+  (save-excursion
+    (let (config)
+      (goto-char (point-min))
+      (while (not (eobp))
+        (when (eq (get-char-property (point-at-eol) 'invisible) 'gnus-sum)
+          (push (save-excursion (forward-line 0) (point)) config))
+        (forward-line 1))
+      config)))
+
+(defun gnus-restore-hidden-threads-configuration (config)
+  "Restore hidden threads configuration from CONFIG."
+  (save-excursion
+    (let (point (inhibit-read-only t))
+      (while (setq point (pop config))
+        (goto-char point)
+        (gnus-summary-hide-thread)))))
+
+;; Various summary mode internalish functions.
+
+(defun gnus-mouse-pick-article (e)
+  (interactive "e")
+  (mouse-set-point e)
+  (gnus-summary-next-page nil t))
+
+(defun gnus-summary-set-display-table ()
+  "Change the display table.
+Odd characters have a tendency to mess
+up nicely formatted displays - we make all possible glyphs
+display only a single character."
+
+  ;; We start from the standard display table, if any.
+  (let ((table (or (copy-sequence standard-display-table)
+                  (make-display-table)))
+       (i 32))
+    ;; Nix out all the control chars...
+    (while (>= (setq i (1- i)) 0)
+      (gnus-put-display-table i [??] table))
+   ;; ... but not newline and cr, of course.  (cr is necessary for the
+    ;; selective display).
+    (gnus-put-display-table ?\n nil table)
+    (gnus-put-display-table ?\r nil table)
+    ;; We keep TAB as well.
+    (gnus-put-display-table ?\t nil table)
+    ;; We nix out any glyphs 127 through 255, or 127 through 159 in
+    ;; Emacs 23 (unicode), that are not set already.
+    (let ((i (if (ignore-errors (= (make-char 'latin-iso8859-1 160) 160))
+                160
+              256)))
+      (while (>= (setq i (1- i)) 127)
+       ;; Only modify if the entry is nil.
+       (unless (gnus-get-display-table i table)
+         (gnus-put-display-table i [??] table))))
+    (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 gnus-summary-display-arrow
+    (make-local-variable 'overlay-arrow-position)
+    (make-local-variable '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-setup-buffer (group)
+  "Initialize summary buffer.
+If the setup was successful, non-nil is returned."
+  (let ((buffer (gnus-summary-buffer-name group))
+       (dead-name (concat "*Dead Summary "
+                          (gnus-group-decoded-name group) "*")))
+    ;; If a dead summary buffer exists, we kill it.
+    (when (gnus-buffer-live-p dead-name)
+      (gnus-kill-buffer dead-name))
+    (if (get-buffer buffer)
+       (progn
+         (set-buffer buffer)
+         (setq gnus-summary-buffer (current-buffer))
+         (not gnus-newsgroup-prepared))
+      (set-buffer (gnus-get-buffer-create buffer))
+      (setq gnus-summary-buffer (current-buffer))
+      (gnus-summary-mode group)
+      (when (gnus-group-quit-config group)
+       (set (make-local-variable 'gnus-single-article-buffer) nil))
+      (make-local-variable 'gnus-article-buffer)
+      (make-local-variable 'gnus-article-current)
+      (make-local-variable 'gnus-original-article-buffer)
+      (setq gnus-newsgroup-name group)
+      ;; Set any local variables in the group parameters.
+      (gnus-summary-set-local-parameters gnus-newsgroup-name)
+      t)))
+
+(defun gnus-set-global-variables ()
+  "Set the global equivalents of the buffer-local variables.
+They are set to the latest values they had.  These reflect the summary
+buffer that was in action when the last article was fetched."
+  (when (derived-mode-p 'gnus-summary-mode)
+    (setq gnus-summary-buffer (current-buffer))
+    (let ((name gnus-newsgroup-name)
+         (marked gnus-newsgroup-marked)
+         (spam gnus-newsgroup-spam-marked)
+         (unread gnus-newsgroup-unreads)
+         (headers gnus-current-headers)
+         (data gnus-newsgroup-data)
+         (summary gnus-summary-buffer)
+         (article-buffer gnus-article-buffer)
+         (original gnus-original-article-buffer)
+         (gac gnus-article-current)
+         (reffed gnus-reffed-article-number)
+         (score-file gnus-current-score-file)
+         (default-charset gnus-newsgroup-charset)
+         vlist)
+      (let ((locals gnus-newsgroup-variables))
+       (while locals
+         (if (consp (car locals))
+             (push (eval (caar locals)) vlist)
+           (push (eval (car locals)) vlist))
+         (setq locals (cdr locals)))
+       (setq vlist (nreverse vlist)))
+      (with-temp-buffer
+       (setq gnus-newsgroup-name name
+             gnus-newsgroup-marked marked
+             gnus-newsgroup-spam-marked spam
+             gnus-newsgroup-unreads unread
+             gnus-current-headers headers
+             gnus-newsgroup-data data
+             gnus-article-current gac
+             gnus-summary-buffer summary
+             gnus-article-buffer article-buffer
+             gnus-original-article-buffer original
+             gnus-reffed-article-number reffed
+             gnus-current-score-file score-file
+             gnus-newsgroup-charset default-charset)
+       (let ((locals gnus-newsgroup-variables))
+         (while locals
+           (if (consp (car locals))
+               (set (caar locals) (pop vlist))
+             (set (car locals) (pop vlist)))
+           (setq locals (cdr locals))))))))
+
+(defun gnus-summary-article-unread-p (article)
+  "Say whether ARTICLE is unread or not."
+  (memq article gnus-newsgroup-unreads))
+
+(defun gnus-summary-first-article-p (&optional article)
+  "Return whether ARTICLE is the first article in the buffer."
+  (if (not (setq article (or article (gnus-summary-article-number))))
+      nil
+    (eq article (caar gnus-newsgroup-data))))
+
+(defun gnus-summary-last-article-p (&optional article)
+  "Return whether ARTICLE is the last article in the buffer."
+  (if (not (setq article (or article (gnus-summary-article-number))))
+      ;; All non-existent numbers are the last article.  :-)
+      t
+    (not (cdr (gnus-data-find-list article)))))
+
+(defun gnus-make-thread-indent-array (&optional n)
+  (when (or n
+           (progn (setq n 200) nil)
+           (null gnus-thread-indent-array)
+           (/= gnus-thread-indent-level gnus-thread-indent-array-level))
+    (setq gnus-thread-indent-array (make-vector (1+ n) "")
+         gnus-thread-indent-array-level gnus-thread-indent-level)
+    (while (>= n 0)
+      (aset gnus-thread-indent-array n
+           (make-string (* n gnus-thread-indent-level) ? ))
+      (setq n (1- n)))))
+
+(defun gnus-update-summary-mark-positions ()
+  "Compute where the summary marks are to go."
+  (save-excursion
+    (when (gnus-buffer-exists-p gnus-summary-buffer)
+      (set-buffer gnus-summary-buffer))
+    (let ((spec gnus-summary-line-format-spec)
+         pos)
+      (save-excursion
+       (gnus-set-work-buffer)
+       (let ((gnus-tmp-unread ?Z)
+             (gnus-replied-mark ?Z)
+             (gnus-score-below-mark ?Z)
+             (gnus-score-over-mark ?Z)
+             (gnus-undownloaded-mark ?Z)
+             (gnus-summary-line-format-spec spec)
+             (gnus-newsgroup-downloadable '(0))
+             (header [0 "" "" "05 Apr 2001 23:33:09 +0400" "" "" 0 0 "" nil])
+             case-fold-search ignores)
+         ;; Here, all marks are bound to Z.
+         (gnus-summary-insert-line header
+                                   0 nil t gnus-tmp-unread t nil "" nil 1)
+         (goto-char (point-min))
+         ;; Memorize the positions of the same characters as dummy marks.
+         (while (re-search-forward "[A-D]" nil t)
+           (push (point) ignores))
+         (erase-buffer)
+         ;; We use A-D as dummy marks in order to know column positions
+         ;; where marks should be inserted.
+         (setq gnus-tmp-unread ?A
+               gnus-replied-mark ?B
+               gnus-score-below-mark ?C
+               gnus-score-over-mark ?C
+               gnus-undownloaded-mark ?D)
+         (gnus-summary-insert-line header
+                                   0 nil t gnus-tmp-unread t nil "" nil 1)
+         ;; Ignore characters which aren't dummy marks.
+         (dolist (p ignores)
+           (delete-region (goto-char (1- p)) p)
+           (insert ?Z))
+         (goto-char (point-min))
+         (setq pos (list (cons 'unread
+                               (and (search-forward "A" nil t)
+                                    (- (point) (point-min) 1)))))
+         (goto-char (point-min))
+         (push (cons 'replied (and (search-forward "B" nil t)
+                                   (- (point) (point-min) 1)))
+               pos)
+         (goto-char (point-min))
+         (push (cons 'score (and (search-forward "C" nil t)
+                                 (- (point) (point-min) 1)))
+               pos)
+         (goto-char (point-min))
+         (push (cons 'download (and (search-forward "D" nil t)
+                                    (- (point) (point-min) 1)))
+               pos)))
+      (setq gnus-summary-mark-positions pos))))
+
+(defun gnus-summary-insert-dummy-line (gnus-tmp-subject gnus-tmp-number)
+  "Insert a dummy root in the summary buffer."
+  (beginning-of-line)
+  (gnus-add-text-properties
+   (point) (progn (eval gnus-summary-dummy-line-format-spec) (point))
+   (list 'gnus-number gnus-tmp-number 'gnus-intangible gnus-tmp-number)))
+
+(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)
+       (ignored-from-addresses (gnus-ignored-from-addresses))
+       ;; 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
+        (with-current-buffer gnus-summary-buffer
+          gnus-newsgroup-ignored-charsets)))
+    (or
+     (and ignored-from-addresses
+         (string-match 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-to-prefix
+                     (inline
+                       (gnus-summary-extract-address-component
+                        (funcall gnus-decode-encoded-address-function to)))))
+            ((setq newsgroups
+                   (or
+                    (cdr (assq 'Newsgroups extra-headers))
+                    (and
+                     (memq 'Newsgroups gnus-extra-headers)
+                     (eq (car (gnus-find-method-for-group
+                               gnus-newsgroup-name)) 'nntp)
+                     (gnus-group-real-name gnus-newsgroup-name))))
+             (concat gnus-summary-newsgroup-prefix newsgroups)))))
+     (gnus-string-mark-left-to-right
+      (inline
+       (gnus-summary-extract-address-component gnus-tmp-from))))))
+
+(defun gnus-summary-insert-line (gnus-tmp-header
+                                gnus-tmp-level gnus-tmp-current
+                                undownloaded gnus-tmp-unread gnus-tmp-replied
+                                gnus-tmp-expirable gnus-tmp-subject-or-nil
+                                &optional gnus-tmp-dummy gnus-tmp-score
+                                gnus-tmp-process)
+  (if (>= gnus-tmp-level (length gnus-thread-indent-array))
+      (gnus-make-thread-indent-array (max (* 2 (length gnus-thread-indent-array))
+                                         gnus-tmp-level)))
+  (let* ((gnus-tmp-indentation (aref gnus-thread-indent-array gnus-tmp-level))
+        (gnus-tmp-lines (mail-header-lines gnus-tmp-header))
+        (gnus-tmp-score (or gnus-tmp-score gnus-summary-default-score 0))
+        (gnus-tmp-score-char
+         (if (or (null gnus-summary-default-score)
+                 (<= (abs (- gnus-tmp-score gnus-summary-default-score))
+                     gnus-summary-zcore-fuzz))
+             ?                         ;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-unseen)
+                gnus-unseen-mark)
+               (t gnus-no-mark)))
+        (gnus-tmp-downloaded
+         (cond (undownloaded
+                 gnus-undownloaded-mark)
+                (gnus-newsgroup-agentized
+                 gnus-downloaded-mark)
+                (t
+                 gnus-no-mark)))
+        (gnus-tmp-from (mail-header-from gnus-tmp-header))
+        (gnus-tmp-name
+         (cond
+          ((string-match "<[^>]+> *$" gnus-tmp-from)
+           (let ((beg (match-beginning 0)))
+             (or (and (string-match "^\".+\"" gnus-tmp-from)
+                      (substring gnus-tmp-from 1 (1- (match-end 0))))
+                 (substring gnus-tmp-from 0 beg))))
+          ((string-match "(.+)" gnus-tmp-from)
+           (substring gnus-tmp-from
+                      (1+ (match-beginning 0)) (1- (match-end 0))))
+          (t gnus-tmp-from)))
+        (gnus-tmp-subject (mail-header-subject gnus-tmp-header))
+        (gnus-tmp-opening-bracket (if gnus-tmp-dummy ?\< ?\[))
+        (gnus-tmp-closing-bracket (if gnus-tmp-dummy ?\> ?\]))
+        (inhibit-read-only t))
+    (when (string= gnus-tmp-name "")
+      (setq gnus-tmp-name gnus-tmp-from))
+    (unless (numberp gnus-tmp-lines)
+      (setq gnus-tmp-lines -1))
+    (if (= gnus-tmp-lines -1)
+       (setq gnus-tmp-lines "?")
+      (setq gnus-tmp-lines (number-to-string gnus-tmp-lines)))
+    (condition-case ()
+       (gnus-put-text-property
+        (point)
+        (progn (eval gnus-summary-line-format-spec) (point))
+        'gnus-number gnus-tmp-number)
+      (error (gnus-message 5 "Error updating the summary line")))
+    (when (gnus-visual-p 'summary-highlight 'highlight)
+      (forward-line -1)
+      (gnus-summary-highlight-line)
+      (gnus-run-hooks 'gnus-summary-update-hook)
+      (forward-line 1))))
+
+(defun gnus-summary-update-line (&optional dont-update)
+  "Update summary line after change."
+  (when (and gnus-summary-default-score
+            (not gnus-summary-inhibit-highlight))
+    (let* ((gnus-summary-inhibit-highlight t) ; Prevent recursion.
+          (article (gnus-summary-article-number))
+          (score (gnus-summary-article-score article)))
+      (unless dont-update
+       (if (and gnus-summary-mark-below
+                (< (gnus-summary-article-score)
+                   gnus-summary-mark-below))
+           ;; This article has a low score, so we mark it as read.
+           (when (memq article gnus-newsgroup-unreads)
+             (gnus-summary-mark-article-as-read gnus-low-score-mark))
+         (when (eq (gnus-summary-article-mark) gnus-low-score-mark)
+           ;; This article was previously marked as read on account
+           ;; of a low score, but now it has risen, so we mark it as
+           ;; unread.
+           (gnus-summary-mark-article-as-unread gnus-unread-mark)))
+       (gnus-summary-update-mark
+        (if (or (null gnus-summary-default-score)
+                (<= (abs (- score gnus-summary-default-score))
+                    gnus-summary-zcore-fuzz))
+            ?                          ;Whitespace
+          (if (< score gnus-summary-default-score)
+              gnus-score-below-mark gnus-score-over-mark))
+        'score))
+      ;; Do visual highlighting.
+      (when (gnus-visual-p 'summary-highlight 'highlight)
+       (gnus-summary-highlight-line)
+       (gnus-run-hooks 'gnus-summary-update-hook)))))
+
+(defvar gnus-tmp-new-adopts nil)
+
+(defun gnus-summary-number-of-articles-in-thread (thread &optional level char)
+  "Return the number of articles in THREAD.
+This may be 0 in some cases -- if none of the articles in
+the thread are to be displayed."
+  (let* ((number
+        ;; Fix by Luc Van Eycken <Luc.VanEycken@esat.kuleuven.ac.be>.
+         (cond
+          ((not (listp thread))
+           1)
+          ((and (consp thread) (cdr thread))
+           (apply
+            '+ 1 (mapcar
+                  'gnus-summary-number-of-articles-in-thread (cdr thread))))
+          ((null thread)
+           1)
+          ((memq (mail-header-number (car thread)) gnus-newsgroup-limit)
+           1)
+          (t 0))))
+    (when (and level (zerop level) gnus-tmp-new-adopts)
+      (incf number
+           (apply '+ (mapcar
+                      'gnus-summary-number-of-articles-in-thread
+                      gnus-tmp-new-adopts))))
+    (if char
+       (if (> number 1) gnus-not-empty-thread-mark
+         gnus-empty-thread-mark)
+      number)))
+
+(defsubst gnus-summary-line-message-size (head)
+  "Return pretty-printed version of message size.
+This function is intended to be used in
+`gnus-summary-line-format-alist'."
+  (let ((c (or (mail-header-chars head) -1)))
+    (cond ((< c 0) "n/a")              ; chars not available
+         ((< c (* 1000 10)) (format "%1.1fk" (/ c 1024.0)))
+         ((< c (* 1000 100)) (format "%dk" (/ c 1024.0)))
+         ((< c (* 1000 10000)) (format "%1.1fM" (/ c (* 1024.0 1024))))
+         (t (format "%dM" (/ c (* 1024.0 1024)))))))
+
+(defcustom gnus-user-date-format-alist
+  '(((gnus-seconds-today) . "Today, %H:%M")
+    ((+ 86400 (gnus-seconds-today)) . "Yesterday, %H:%M")
+    (604800 . "%A %H:%M")               ; That's one week
+    ((gnus-seconds-month) . "%A %d")
+    ((gnus-seconds-year) . "%B %d")
+    (t . "%b %d %Y"))                   ; This one is used when no other
+                                        ; does match
+  "Specifies date format depending on age of article.
+This is an alist of items (AGE . FORMAT).  AGE can be a number (of
+seconds) or a Lisp expression evaluating to a number.  When the age of
+the article is less than this number, then use `format-time-string'
+with the corresponding FORMAT for displaying the date of the article.
+If AGE is not a number or a Lisp expression evaluating to a
+non-number, then the corresponding FORMAT is used as a default value.
+
+Note that the list is processed from the beginning, so it should be
+sorted by ascending AGE.  Also note that items following the first
+non-number AGE will be ignored.
+
+You can use the functions `gnus-seconds-today', `gnus-seconds-month'
+and `gnus-seconds-year' in the AGE spec.  They return the number of
+seconds passed since the start of today, of this month, of this year,
+respectively."
+  :version "24.1"
+  :group 'gnus-summary-format
+  :type '(alist :key-type sexp :value-type string))
+
+(defun gnus-user-date (messy-date)
+  "Format the messy-date according to `gnus-user-date-format-alist'.
+Returns \"  ?  \" if there's bad input or if another error occurs.
+Input should look like this: \"Sun, 14 Oct 2001 13:34:39 +0200\"."
+  (condition-case ()
+      (let* ((messy-date (gnus-float-time (gnus-date-get-time messy-date)))
+            (now (gnus-float-time))
+            ;;If we don't find something suitable we'll use this one
+            (my-format "%b %d '%y"))
+       (let* ((difference (- now 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) (seconds-to-time messy-date)))
+    (error "  ?   ")))
+
+(defun gnus-summary-set-local-parameters (group)
+  "Go through the local params of GROUP and set all variable specs in that list."
+  (let ((vars '(quit-config active)))  ; Ignore things that aren't
+                                       ; really variables.
+    (dolist (elem (gnus-group-find-parameter group))
+      (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) vars))
+          (ignore-errors
+            (push (car elem) vars)
+            ;; Variables like `gnus-show-threads' that are globally
+            ;; bound, if used as group parameters, need to get to be
+            ;; buffer-local, whereas just parameters like `gcc-self',
+            ;; `timestamp', etc. should not be bound as variables.
+            (if (boundp (car elem))
+                (set (make-local-variable (car elem)) (eval (nth 1 elem)))
+              (eval (nth 1 elem))))))))
+
+(defun gnus-summary-read-group (group &optional show-all no-article
+                                     kill-buffer no-display backward
+                                     select-articles)
+  "Start reading news in newsgroup GROUP.
+If SHOW-ALL is non-nil, already read articles are also listed.
+If NO-ARTICLE is non-nil, no article is selected initially.
+If NO-DISPLAY, don't generate the summary buffer contents.
+If KILL-BUFFER, it should be a buffer that's killed once the new
+summary buffer has been generated.
+If BACKWARD, move point to the previous group in the group buffer
+If SELECT-ARTICLES, only select those articles from GROUP."
+  (let (result)
+    (while (and group
+               (null (setq result
+                           (let ((gnus-auto-select-next nil))
+                             (or (gnus-summary-read-group-1
+                                  group show-all no-article
+                                  kill-buffer no-display
+                                  select-articles)
+                                 (setq show-all nil
+                                       select-articles nil)))))
+               (eq gnus-auto-select-next 'quietly))
+      (set-buffer gnus-group-buffer)
+      ;; The entry function called above goes to the next
+      ;; group automatically, so we go two groups back
+      ;; if we are searching for the previous group.
+      (when backward
+       (gnus-group-prev-unread-group 2))
+      (if (not (equal group (gnus-group-group-name)))
+         (setq group (gnus-group-group-name))
+       (setq group nil)))
+    result))
+
+(defun gnus-summary-read-group-1 (group show-all no-article
+                                       kill-buffer no-display
+                                       &optional select-articles)
+  ;; Killed foreign groups can't be entered.
+  ;;  (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 7 "Retrieving newsgroup: %s..."
+               (gnus-group-decoded-name group))
+  (let* ((new-group (gnus-summary-setup-buffer group))
+        (quit-config (gnus-group-quit-config group))
+        (did-select (and new-group (gnus-select-newsgroup
+                                    group show-all select-articles))))
+    (cond
+     ;; This summary buffer exists already, so we just select it.
+     ((not new-group)
+      (gnus-set-global-variables)
+      (when kill-buffer
+       (gnus-kill-or-deaden-summary kill-buffer))
+      (gnus-configure-windows 'summary 'force)
+      (gnus-set-mode-line 'summary)
+      (gnus-summary-position-point)
+      (message "")
+      t)
+     ;; We couldn't select this group.
+     ((null did-select)
+      (when (and (derived-mode-p 'gnus-summary-mode)
+                (not (equal (current-buffer) kill-buffer)))
+       (kill-buffer (current-buffer))
+       (if (not quit-config)
+           (progn
+             ;; Update the info -- marks might need to be removed,
+             ;; for instance.
+             (gnus-summary-update-info)
+             (set-buffer gnus-group-buffer)
+             (gnus-group-jump-to-group group)
+             (gnus-group-next-unread-group 1))
+         (gnus-handle-ephemeral-exit quit-config)))
+      (if (null (gnus-list-of-unread-articles group))
+         (gnus-message 3 "Group %s contains no messages" 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.
+     ((eq did-select 'quit)
+      (and (derived-mode-p 'gnus-summary-mode)
+          (not (equal (current-buffer) kill-buffer))
+          (kill-buffer (current-buffer)))
+      (when kill-buffer
+       (gnus-kill-or-deaden-summary kill-buffer))
+      (if (not quit-config)
+         (progn
+           (set-buffer gnus-group-buffer)
+           (gnus-group-jump-to-group group)
+           (gnus-configure-windows 'group 'force))
+       (gnus-handle-ephemeral-exit quit-config))
+      ;; Finally signal the quit.
+      (signal 'quit nil))
+     ;; The group was successfully selected.
+     (t
+      (gnus-set-global-variables)
+      (when (boundp 'spam-install-hooks)
+       (spam-initialize))
+      ;; Save the active value in effect when the group was entered.
+      (setq gnus-newsgroup-active
+           (gnus-copy-sequence
+            (gnus-active gnus-newsgroup-name)))
+      (setq gnus-newsgroup-highest (cdr gnus-newsgroup-active))
+      ;; You can change the summary buffer in some way with this hook.
+      (gnus-run-hooks 'gnus-select-group-hook)
+      (when (memq 'summary (gnus-update-format-specifications
+                           nil 'summary 'summary-mode 'summary-dummy))
+       ;; The format specification for the summary line was updated,
+       ;; so we need to update the mark positions as well.
+       (gnus-update-summary-mark-positions))
+      ;; Do score processing.
+      (when gnus-use-scoring
+       (gnus-possibly-score-headers))
+      ;; Check whether to fill in the gaps in the threads.
+      (when gnus-build-sparse-threads
+       (gnus-build-sparse-threads))
+      ;; Find the initial limit.
+      (if show-all
+         (let ((gnus-newsgroup-dormant nil))
+           (gnus-summary-initial-limit show-all))
+       (gnus-summary-initial-limit show-all))
+      ;; Generate the summary buffer.
+      (unless no-display
+       (gnus-summary-prepare))
+      (when gnus-use-trees
+       (gnus-tree-open)
+       (setq gnus-summary-highlight-line-function
+             'gnus-tree-highlight-article))
+      ;; If the summary buffer is empty, but there are some low-scored
+      ;; articles or some excluded dormants, we include these in the
+      ;; buffer.
+      (when (and (zerop (buffer-size))
+                (not no-display))
+       (cond (gnus-newsgroup-dormant
+              (gnus-summary-limit-include-dormant))
+             ((and gnus-newsgroup-scored show-all)
+              (gnus-summary-limit-include-expunged t))))
+      ;; Function `gnus-apply-kill-file' must be called in this hook.
+      (gnus-run-hooks 'gnus-apply-kill-hook)
+      (if (and (zerop (buffer-size))
+              (not no-display))
+         (progn
+           ;; This newsgroup is empty.
+           (gnus-summary-catchup-and-exit nil t)
+           (gnus-message 6 "No unread news")
+           (when kill-buffer
+             (gnus-kill-or-deaden-summary kill-buffer))
+           ;; Return nil from this function.
+           nil)
+       ;; Hide conversation thread subtrees.  We cannot do this in
+       ;; gnus-summary-prepare-hook since kill processing may not
+       ;; work with hidden articles.
+       (gnus-summary-maybe-hide-threads)
+       (gnus-configure-windows 'summary)
+       (when kill-buffer
+         (gnus-kill-or-deaden-summary kill-buffer))
+       (gnus-summary-auto-select-subject)
+       ;; Show first unread article if requested.
+       (if (and (not no-article)
+                (not no-display)
+                gnus-newsgroup-unreads
+                gnus-auto-select-first)
+           (progn
+             (let ((art (gnus-summary-article-number)))
+               (when (and art
+                          gnus-plugged
+                          (not (memq art gnus-newsgroup-undownloaded))
+                          (not (memq art gnus-newsgroup-downloadable)))
+                 (gnus-summary-goto-article art))))
+         ;; Don't select any articles.
+         (gnus-summary-position-point)
+         (gnus-configure-windows 'summary 'force)
+         (gnus-set-mode-line 'summary))
+       (when (and gnus-auto-center-group
+                  (get-buffer-window gnus-group-buffer t))
+         ;; Gotta use windows, because recenter does weird stuff if
+         ;; the current buffer ain't the displayed window.
+         (let ((owin (selected-window)))
+           (select-window (get-buffer-window gnus-group-buffer t))
+           (when (gnus-group-goto-group group)
+             (recenter))
+           (select-window owin)))
+       ;; Mark this buffer as "prepared".
+       (setq gnus-newsgroup-prepared t)
+       (gnus-run-hooks 'gnus-summary-prepared-hook)
+       (unless (gnus-ephemeral-group-p group)
+         (gnus-group-update-group group nil t))
+       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 'unseen-or-unread)
+    (gnus-summary-first-unseen-or-unread-subject))
+   ((eq gnus-auto-select-subject 'first)
+    ;; Do nothing.
+    )
+   ((functionp gnus-auto-select-subject)
+    (funcall gnus-auto-select-subject))))
+
+(defun gnus-summary-prepare ()
+  "Generate the summary buffer."
+  (interactive)
+  (let ((inhibit-read-only t))
+    (erase-buffer)
+    (setq gnus-newsgroup-data nil
+         gnus-newsgroup-data-reverse nil)
+    (gnus-run-hooks 'gnus-summary-generate-hook)
+    ;; Generate the buffer, either with threads or without.
+    (when gnus-newsgroup-headers
+      (gnus-summary-prepare-threads
+       (if gnus-show-threads
+          (gnus-sort-gathered-threads
+           (funcall gnus-summary-thread-gathering-function
+                    (gnus-sort-threads
+                     (gnus-cut-threads (gnus-make-threads)))))
+        ;; Unthreaded display.
+        (gnus-sort-articles gnus-newsgroup-headers))))
+    (setq gnus-newsgroup-data (nreverse gnus-newsgroup-data))
+    ;; Call hooks for modifying summary buffer.
+    (goto-char (point-min))
+    (gnus-run-hooks 'gnus-summary-prepare-hook)))
+
+(defsubst gnus-general-simplify-subject (subject)
+  "Simplify subject by the same rules as `gnus-gather-threads-by-subject'."
+  (setq subject
+       (cond
+        ;; Truncate the subject.
+        (gnus-simplify-subject-functions
+         (gnus-map-function gnus-simplify-subject-functions subject))
+        ((numberp gnus-summary-gather-subject-limit)
+         (setq subject (gnus-simplify-subject-re subject))
+         (if (> (length subject) gnus-summary-gather-subject-limit)
+             (substring subject 0 gnus-summary-gather-subject-limit)
+           subject))
+        ;; Fuzzily simplify it.
+        ((eq 'fuzzy gnus-summary-gather-subject-limit)
+         (gnus-simplify-subject-fuzzy subject))
+        ;; Just remove the leading "Re:".
+        (t
+         (gnus-simplify-subject-re subject))))
+
+  (if (and gnus-summary-gather-exclude-subject
+          (string-match gnus-summary-gather-exclude-subject subject))
+      nil                         ; This article shouldn't be gathered
+    subject))
+
+(defun gnus-summary-simplify-subject-query ()
+  "Query where the respool algorithm would put this article."
+  (interactive)
+  (gnus-summary-select-article)
+  (message "%s" (gnus-general-simplify-subject (gnus-summary-article-subject))))
+
+(defun gnus-gather-threads-by-subject (threads)
+  "Gather threads by looking at Subject headers."
+  (if (not gnus-summary-make-false-root)
+      threads
+    (let ((hashtb (gnus-make-hashtable 1024))
+         (prev threads)
+         (result threads)
+         subject hthread whole-subject)
+      (while threads
+       (setq subject (gnus-general-simplify-subject
+                      (setq whole-subject (mail-header-subject
+                                           (caar threads)))))
+       (when subject
+         (if (setq hthread (gnus-gethash subject hashtb))
+             (progn
+               ;; We enter a dummy root into the thread, if we
+               ;; haven't done that already.
+               (unless (stringp (caar hthread))
+                 (setcar hthread (list whole-subject (car hthread))))
+               ;; We add this new gathered thread to this gathered
+               ;; thread.
+               (setcdr (car hthread)
+                       (nconc (cdar hthread) (list (car threads))))
+               ;; Remove it from the list of threads.
+               (setcdr prev (cdr threads))
+               (setq threads prev))
+           ;; Enter this thread into the hash table.
+           (gnus-sethash subject
+                         (if gnus-summary-make-false-root-always
+                             (progn
+                               ;; If you want a dummy root above all
+                               ;; threads...
+                               (setcar threads (list whole-subject
+                                                     (car threads)))
+                               threads)
+                           threads)
+                         hashtb)))
+       (setq prev threads)
+       (setq threads (cdr threads)))
+      result)))
+
+(defun gnus-gather-threads-by-references (threads)
+  "Gather threads by looking at References headers."
+  (let ((idhashtb (gnus-make-hashtable 1024))
+       (thhashtb (gnus-make-hashtable 1024))
+       (prev threads)
+       (result threads)
+       ids references id gthread gid entered ref)
+    (while threads
+      (when (setq references (mail-header-references (caar threads)))
+       (setq id (mail-header-id (caar threads))
+             ids (inline (gnus-split-references references))
+             entered nil)
+       (while (setq ref (pop ids))
+         (setq ids (delete ref ids))
+         (if (not (setq gid (gnus-gethash ref idhashtb)))
+             (progn
+               (gnus-sethash ref id idhashtb)
+               (gnus-sethash id threads thhashtb))
+           (setq gthread (gnus-gethash gid thhashtb))
+           (unless entered
+             ;; We enter a dummy root into the thread, if we
+             ;; haven't done that already.
+             (unless (stringp (caar gthread))
+               (setcar gthread (list (mail-header-subject (caar gthread))
+                                     (car gthread))))
+             ;; We add this new gathered thread to this gathered
+             ;; thread.
+             (setcdr (car gthread)
+                     (nconc (cdar gthread) (list (car threads)))))
+           ;; Add it into the thread hash table.
+           (gnus-sethash id gthread thhashtb)
+           (setq entered t)
+           ;; Remove it from the list of threads.
+           (setcdr prev (cdr threads))
+           (setq threads prev))))
+      (setq prev threads)
+      (setq threads (cdr threads)))
+    result))
+
+(defun gnus-sort-gathered-threads (threads)
+  "Sort subthreads inside each gathered thread by `gnus-sort-gathered-threads-function'."
+  (let ((result threads))
+    (while threads
+      (when (stringp (caar threads))
+       (setcdr (car threads)
+               (sort (cdar threads) gnus-sort-gathered-threads-function)))
+      (setq threads (cdr threads)))
+    result))
+
+(defun gnus-thread-loop-p (root thread)
+  "Say whether ROOT is in THREAD."
+  (let ((stack (list thread))
+       (infloop 0)
+       th)
+    (while (setq thread (pop stack))
+      (setq th (cdr thread))
+      (while (and th
+                 (not (eq (caar th) root)))
+       (pop th))
+      (if th
+         ;; We have found a loop.
+         (let (ref-dep)
+           (setcdr thread (delq (car th) (cdr thread)))
+           (if (boundp (setq ref-dep (intern "none"
+                                             gnus-newsgroup-dependencies)))
+               (setcdr (symbol-value ref-dep)
+                       (nconc (cdr (symbol-value ref-dep))
+                              (list (car th))))
+             (set ref-dep (list nil (car th))))
+           (setq infloop 1
+                 stack nil))
+       ;; Push all the subthreads onto the stack.
+       (push (cdr thread) stack)))
+    infloop))
+
+(defun gnus-make-threads ()
+  "Go through the dependency hashtb and find the roots.  Return all threads."
+  (let (threads)
+    (while (catch 'infloop
+            (mapatoms
+             (lambda (refs)
+               ;; Deal with self-referencing References loops.
+               (when (and (car (symbol-value refs))
+                          (not (zerop
+                                (apply
+                                 '+
+                                 (mapcar
+                                  (lambda (thread)
+                                    (gnus-thread-loop-p
+                                     (car (symbol-value refs)) thread))
+                                  (cdr (symbol-value refs)))))))
+                 (setq threads nil)
+                 (throw 'infloop t))
+               (unless (car (symbol-value refs))
+                 ;; 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)))
+    threads))
+
+;; Build the thread tree.
+(defsubst gnus-dependencies-add-header (header dependencies force-new)
+  "Enter HEADER into the DEPENDENCIES table if it is not already there.
+
+If FORCE-NEW is not nil, enter HEADER into the DEPENDENCIES table even
+if it was already present.
+
+If `gnus-summary-ignore-duplicates' is nil then duplicate Message-IDs
+will not be entered in the DEPENDENCIES table.  Otherwise duplicate
+Message-IDs will be renamed to a unique Message-ID before being
+entered.
+
+Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
+  (let* ((id (mail-header-id header))
+        (id-dep (and id (intern id dependencies)))
+        parent-id ref ref-dep ref-header replaced)
+    ;; Enter this `header' in the `dependencies' table.
+    (cond
+     ((not id-dep)
+      (setq header nil))
+     ;; The first two cases do the normal part: enter a new `header'
+     ;; in the `dependencies' table.
+     ((not (boundp id-dep))
+      (set id-dep (list header)))
+     ((null (car (symbol-value id-dep)))
+      (setcar (symbol-value id-dep) header))
+
+     ;; From here the `header' was already present in the
+     ;; `dependencies' table.
+     (force-new
+      ;; Overrides an existing entry;
+      ;; just set the header part of the entry.
+      (setcar (symbol-value id-dep) header)
+      (setq replaced t))
+
+     ;; Renames the existing `header' to a unique Message-ID.
+     ((not gnus-summary-ignore-duplicates)
+      ;; An article with this Message-ID has already been seen.
+      ;; We rename the Message-ID.
+      (set (setq id-dep (intern (setq id (nnmail-message-id)) dependencies))
+          (list header))
+      (mail-header-set-id header id))
+
+     ;; The last case ignores an existing entry, except it adds any
+     ;; additional Xrefs (in case the two articles came from different
+     ;; servers.
+     ;; Also sets `header' to nil meaning that the `dependencies'
+     ;; table was *not* modified.
+     (t
+      (mail-header-set-xref
+       (car (symbol-value id-dep))
+       (concat (or (mail-header-xref (car (symbol-value id-dep)))
+                  "")
+              (or (mail-header-xref header) "")))
+      (setq header nil)))
+
+    (when (and header (not replaced))
+      ;; First check that we are not creating a References loop.
+      (setq parent-id (gnus-parent-id (mail-header-references header)))
+      (setq ref parent-id)
+      (while (and ref
+                 (setq ref-dep (intern-soft ref dependencies))
+                 (boundp ref-dep)
+                 (setq ref-header (car (symbol-value ref-dep))))
+       (if (string= id ref)
+           ;; Yuk!  This is a reference loop.  Make the article be a
+           ;; root article.
+           (progn
+             (mail-header-set-references (car (symbol-value id-dep)) "none")
+             (setq ref nil)
+             (setq parent-id nil))
+         (setq ref (gnus-parent-id (mail-header-references ref-header)))))
+      (setq ref-dep (intern (or parent-id "none") dependencies))
+      (if (boundp ref-dep)
+         (setcdr (symbol-value ref-dep)
+                 (nconc (cdr (symbol-value ref-dep))
+                        (list (symbol-value id-dep))))
+       (set ref-dep (list nil (symbol-value id-dep)))))
+    header))
+
+(defun gnus-extract-message-id-from-in-reply-to (string)
+  (if (string-match "<[^>]+>" string)
+      (substring string (match-beginning 0) (match-end 0))
+    nil))
+
+(defun gnus-build-sparse-threads ()
+  (let ((headers gnus-newsgroup-headers)
+       (mail-parse-charset gnus-newsgroup-charset)
+       (gnus-summary-ignore-duplicates t)
+       header references generation relations
+       subject child end new-child date)
+    ;; First we create an alist of generations/relations, where
+    ;; generations is how much we trust the relation, and the relation
+    ;; is parent/child.
+    (gnus-message 7 "Making sparse threads...")
+    (save-excursion
+      (nnheader-set-temp-buffer " *gnus sparse threads*")
+      (while (setq header (pop headers))
+       (when (and (setq references (mail-header-references header))
+                  (not (string= references "")))
+         (insert references)
+         (setq child (mail-header-id header)
+               subject (mail-header-subject header)
+               date (mail-header-date header)
+               generation 0)
+         (while (search-backward ">" nil t)
+           (setq end (1+ (point)))
+           (when (search-backward "<" nil t)
+             (setq new-child (buffer-substring (point) end))
+             (push (list (incf generation)
+                         child (setq child new-child)
+                         subject date)
+                   relations)))
+         (when child
+           (push (list (1+ generation) child nil subject) relations))
+         (erase-buffer)))
+      (kill-buffer (current-buffer)))
+    ;; Sort over trustworthiness.
+    (dolist (relation (sort relations 'car-less-than-car))
+      (when (gnus-dependencies-add-header
+            (make-full-mail-header
+             gnus-reffed-article-number
+             (nth 3 relation) "" (or (nth 4 relation) "")
+             (nth 1 relation)
+             (or (nth 2 relation) "") 0 0 "")
+            gnus-newsgroup-dependencies nil)
+       (push gnus-reffed-article-number gnus-newsgroup-limit)
+       (push gnus-reffed-article-number gnus-newsgroup-sparse)
+       (push (cons gnus-reffed-article-number gnus-sparse-mark)
+             gnus-newsgroup-reads)
+       (decf gnus-reffed-article-number)))
+    (gnus-message 7 "Making sparse threads...done")))
+
+(defun gnus-build-old-threads ()
+  ;; Look at all the articles that refer back to old articles, and
+  ;; fetch the headers for the articles that aren't there.  This will
+  ;; build complete threads - if the roots haven't been expired by the
+  ;; server, that is.
+  (let ((mail-parse-charset gnus-newsgroup-charset)
+       id heads)
+    (mapatoms
+     (lambda (refs)
+       (when (not (car (symbol-value refs)))
+        (setq heads (cdr (symbol-value refs)))
+        (while heads
+          (if (memq (mail-header-number (caar heads))
+                    gnus-newsgroup-dormant)
+              (setq heads (cdr heads))
+            (setq id (symbol-name refs))
+            (while (and (setq id (gnus-build-get-header id))
+                        (not (car (gnus-id-to-thread id)))))
+            (setq heads nil)))))
+     gnus-newsgroup-dependencies)))
+
+(defsubst gnus-remove-odd-characters (string)
+  "Translate STRING into something that doesn't contain weird characters."
+  (mm-subst-char-in-string
+   ?\r ?\-
+   (mm-subst-char-in-string ?\n ?\- string t) t))
+
+;; This function has to be called with point after the article number
+;; on the beginning of the line.
+(defsubst gnus-nov-parse-line (number dependencies &optional force-new)
+  (let ((eol (point-at-eol))
+       (buffer (current-buffer))
+       header references in-reply-to)
+
+    ;; overview: [num subject from date id refs chars lines misc]
+    (unwind-protect
+       (let (x)
+         (narrow-to-region (point) eol)
+         (unless (eobp)
+           (forward-char))
+
+         (setq header
+               (make-full-mail-header
+                number                 ; number
+                (condition-case ()     ; subject
+                    (gnus-remove-odd-characters
+                     (funcall gnus-decode-encoded-word-function
+                              (setq x (nnheader-nov-field))))
+                  (error x))
+                (condition-case ()     ; from
+                    (gnus-remove-odd-characters
+                     (funcall gnus-decode-encoded-address-function
+                              (setq x (nnheader-nov-field))))
+                  (error x))
+                (nnheader-nov-field)   ; date
+                (nnheader-nov-read-message-id number)  ; id
+                (setq references (nnheader-nov-field)) ; refs
+                (nnheader-nov-read-integer) ; chars
+                (nnheader-nov-read-integer) ; lines
+                (unless (eobp)
+                  (if (looking-at "Xref: ")
+                      (goto-char (match-end 0)))
+                  (nnheader-nov-field)) ; Xref
+                (nnheader-nov-parse-extra)))) ; extra
+
+      (widen))
+
+    (when (and (string= references "")
+              (setq in-reply-to (mail-header-extra header))
+              (setq in-reply-to (cdr (assq 'In-Reply-To in-reply-to))))
+      (mail-header-set-references
+       header (gnus-extract-message-id-from-in-reply-to in-reply-to)))
+
+    (when gnus-alter-header-function
+      (funcall gnus-alter-header-function header))
+    (gnus-dependencies-add-header header dependencies force-new)))
+
+(defun gnus-build-get-header (id)
+  "Look through the buffer of NOV lines and find the header to ID.
+Enter this line into the dependencies hash table, and return
+the id of the parent article (if any)."
+  (let ((deps gnus-newsgroup-dependencies)
+       found header)
+    (prog1
+       (with-current-buffer nntp-server-buffer
+         (let ((case-fold-search nil))
+           (goto-char (point-min))
+           (while (and (not found)
+                       (search-forward id nil t))
+             (beginning-of-line)
+             (setq found (looking-at
+                          (format "^[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t%s"
+                                  (regexp-quote id))))
+             (or found (beginning-of-line 2)))
+           (when found
+             (beginning-of-line)
+             (and
+              (setq header (gnus-nov-parse-line
+                            (read (current-buffer)) deps))
+              (gnus-parent-id (mail-header-references header))))))
+      (when header
+       (let ((number (mail-header-number header)))
+         (push number gnus-newsgroup-limit)
+         (push header gnus-newsgroup-headers)
+         (if (memq number gnus-newsgroup-unselected)
+             (progn
+               (setq gnus-newsgroup-unreads
+                     (gnus-add-to-sorted-list gnus-newsgroup-unreads
+                                              number))
+               (setq gnus-newsgroup-unselected
+                     (delq number gnus-newsgroup-unselected)))
+           (push number gnus-newsgroup-ancient)))))))
+
+(defun gnus-build-all-threads ()
+  "Read all the headers."
+  (let ((gnus-summary-ignore-duplicates t)
+       (mail-parse-charset gnus-newsgroup-charset)
+       (dependencies gnus-newsgroup-dependencies)
+       header article)
+    (with-current-buffer nntp-server-buffer
+      (let ((case-fold-search nil))
+       (goto-char (point-min))
+       (while (not (eobp))
+         (ignore-errors
+           (setq article (read (current-buffer))
+                 header (gnus-nov-parse-line article dependencies t)))
+         (when header
+           (with-current-buffer gnus-summary-buffer
+             (push header gnus-newsgroup-headers)
+             (if (memq (setq article (mail-header-number header))
+                       gnus-newsgroup-unselected)
+                 (progn
+                   (setq gnus-newsgroup-unreads
+                         (gnus-add-to-sorted-list
+                          gnus-newsgroup-unreads article))
+                   (setq gnus-newsgroup-unselected
+                         (delq article gnus-newsgroup-unselected)))
+               (push article gnus-newsgroup-ancient)))
+           (forward-line 1)))))))
+
+(defun gnus-summary-update-article-line (article header)
+  "Update the line for ARTICLE using HEADER."
+  (let* ((id (mail-header-id header))
+        (thread (gnus-id-to-thread id)))
+    (unless thread
+      (error "Article in no thread"))
+    ;; Update the thread.
+    (setcar thread header)
+    (gnus-summary-goto-subject article)
+    (let* ((datal (gnus-data-find-list article))
+          (data (car datal))
+          (inhibit-read-only t)
+          (level (gnus-summary-thread-level)))
+      (gnus-delete-line)
+      (let ((inserted (- (point)
+                         (progn
+                           (gnus-summary-insert-line
+                            header level nil
+                            (memq article gnus-newsgroup-undownloaded)
+                            (gnus-article-mark article)
+                            (memq article gnus-newsgroup-replied)
+                            (memq article gnus-newsgroup-expirable)
+                            ;; Only insert the Subject string when it's different
+                            ;; from the previous Subject string.
+                            (if (and
+                                 gnus-show-threads
+                                 (gnus-subject-equal
+                                  (condition-case ()
+                                      (mail-header-subject
+                                       (gnus-data-header
+                                        (cadr
+                                         (gnus-data-find-list
+                                          article
+                                          (gnus-data-list t)))))
+                                    ;; Error on the side of excessive subjects.
+                                    (error ""))
+                                  (mail-header-subject header)))
+                                ""
+                              (mail-header-subject header))
+                            nil (cdr (assq article gnus-newsgroup-scored))
+                            (memq article gnus-newsgroup-processable))
+                           (point)))))
+        (when (cdr datal)
+          (gnus-data-update-list
+           (cdr datal)
+           (- (gnus-data-pos data) (gnus-data-pos (cadr datal)) inserted)))))))
+
+(defun gnus-summary-update-article (article &optional iheader)
+  "Update ARTICLE in the summary buffer."
+  (set-buffer gnus-summary-buffer)
+  (let* ((header (gnus-summary-article-header article))
+        (id (mail-header-id header))
+        (data (gnus-data-find article))
+        (thread (gnus-id-to-thread id))
+        (references (mail-header-references header))
+        (parent
+         (gnus-id-to-thread
+          (or (gnus-parent-id
+               (when (and references
+                          (not (equal "" references)))
+                 references))
+              "none")))
+        (inhibit-read-only t)
+        (old (car thread)))
+    (when thread
+      (unless iheader
+       (setcar thread nil)
+       (when parent
+         (delq thread parent)))
+      (if (gnus-summary-insert-subject id header)
+         ;; Set the (possibly) new article number in the data structure.
+         (gnus-data-set-number data (gnus-id-to-article id))
+       (setcar thread old)
+       nil))))
+
+(defun gnus-rebuild-thread (id &optional line)
+  "Rebuild the thread containing ID.
+If LINE, insert the rebuilt thread starting on line LINE."
+  (let ((inhibit-read-only t)
+       old-pos current thread data)
+    (if (not gnus-show-threads)
+       (setq thread (list (car (gnus-id-to-thread id))))
+      ;; Get the thread this article is part of.
+      (setq thread (gnus-remove-thread id)))
+    (setq old-pos (point-at-bol))
+    (setq current (save-excursion
+                   (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))
+      (let ((subject (car thread))
+           roots thr)
+       (setq thread (cdr thread))
+       (while thread
+         (unless (memq (setq thr (gnus-id-to-thread
+                                  (gnus-root-id
+                                   (mail-header-id (caar thread)))))
+                       roots)
+           (push thr roots))
+         (setq thread (cdr thread)))
+       ;; We now have all (unique) roots.
+       (if (= (length roots) 1)
+           ;; All the loose roots are now one solid root.
+           (setq thread (car roots))
+         (setq thread (cons subject (gnus-sort-threads roots))))))
+    (let (threads)
+      ;; We then insert this thread into the summary buffer.
+      (when line
+       (goto-char (point-min))
+       (forward-line (1- line)))
+      (let (gnus-newsgroup-data gnus-newsgroup-threads)
+       (if gnus-show-threads
+           (gnus-summary-prepare-threads (gnus-cut-threads (list thread)))
+         (gnus-summary-prepare-unthreaded thread))
+       (setq data (nreverse gnus-newsgroup-data))
+       (setq threads gnus-newsgroup-threads))
+      ;; We splice the new data into the data structure.
+      ;;!!! This is kinda bogus.  We assume that in LINE is non-nil,
+      ;;!!! then we want to insert at the beginning of the buffer.
+      ;;!!! That happens to be true with Gnus now, but that may
+      ;;!!! change in the future.  Perhaps.
+      (gnus-data-enter-list
+       (if line nil current) data (- (point) old-pos))
+      (setq gnus-newsgroup-threads
+           (nconc threads gnus-newsgroup-threads))
+      (gnus-data-compute-positions))))
+
+(defun gnus-number-to-header (number)
+  "Return the header for article NUMBER."
+  (let ((headers gnus-newsgroup-headers))
+    (while (and headers
+               (not (= number (mail-header-number (car headers)))))
+      (pop headers))
+    (when headers
+      (car headers))))
+
+(defun gnus-parent-headers (in-headers &optional generation)
+  "Return the headers of the GENERATIONth parent of HEADERS."
+  (unless generation
+    (setq generation 1))
+  (let ((parent t)
+       (headers in-headers)
+       references)
+    (while (and parent
+               (not (zerop generation))
+               (setq references (mail-header-references headers)))
+      (setq headers (if (and references
+                            (setq parent (gnus-parent-id references)))
+                       (car (gnus-id-to-thread parent))
+                     nil))
+      (decf generation))
+    (and (not (eq headers in-headers))
+        headers)))
+
+(defun gnus-id-to-thread (id)
+  "Return the (sub-)thread where ID appears."
+  (gnus-gethash id gnus-newsgroup-dependencies))
+
+(defun gnus-id-to-article (id)
+  "Return the article number of ID."
+  (let ((thread (gnus-id-to-thread id)))
+    (when (and thread
+              (car thread))
+      (mail-header-number (car thread)))))
+
+(defun gnus-id-to-header (id)
+  "Return the article headers of ID."
+  (car (gnus-id-to-thread id)))
+
+(defun gnus-article-displayed-root-p (article)
+  "Say whether ARTICLE is a root(ish) article."
+  (let ((level (gnus-summary-thread-level article))
+       (refs (mail-header-references  (gnus-summary-article-header article)))
+       particle)
+    (cond
+     ((null level) nil)
+     ((zerop level) t)
+     ((null refs) t)
+     ((null (gnus-parent-id refs)) t)
+     ((and (= 1 level)
+          (null (setq particle (gnus-id-to-article
+                                (gnus-parent-id refs))))
+          (null (gnus-summary-thread-level particle)))))))
+
+(defun gnus-root-id (id)
+  "Return the id of the root of the thread where ID appears."
+  (let (last-id prev)
+    (while (and id (setq prev (car (gnus-id-to-thread id))))
+      (setq last-id id
+           id (gnus-parent-id (mail-header-references prev))))
+    last-id))
+
+(defun gnus-articles-in-thread (thread)
+  "Return the list of articles in THREAD."
+  (cons (mail-header-number (car thread))
+       (apply 'nconc (mapcar 'gnus-articles-in-thread (cdr thread)))))
+
+(defun gnus-remove-thread (id &optional dont-remove)
+  "Remove the thread that has ID in it."
+  (let (headers thread last-id)
+    ;; First go up in this thread until we find the root.
+    (setq last-id (gnus-root-id id)
+         headers (message-flatten-list (gnus-id-to-thread last-id)))
+    ;; We have now found the real root of this thread.  It might have
+    ;; been gathered into some loose thread, so we have to search
+    ;; through the threads to find the thread we wanted.
+    (let ((threads gnus-newsgroup-threads)
+         sub)
+      (while threads
+       (setq sub (car threads))
+       (if (stringp (car sub))
+           ;; This is a gathered thread, so we look at the roots
+           ;; below it to find whether this article is in this
+           ;; gathered root.
+           (progn
+             (setq sub (cdr sub))
+             (while sub
+               (when (member (caar sub) headers)
+                 (setq thread (car threads)
+                       threads nil
+                       sub nil))
+               (setq sub (cdr sub))))
+         ;; It's an ordinary thread, so we check it.
+         (when (eq (car sub) (car headers))
+           (setq thread sub
+                 threads nil)))
+       (setq threads (cdr threads)))
+      ;; If this article is in no thread, then it's a root.
+      (if thread
+         (unless dont-remove
+           (setq gnus-newsgroup-threads (delq thread gnus-newsgroup-threads)))
+       (setq thread (gnus-id-to-thread last-id)))
+      (when thread
+       (prog1
+           thread                      ; We return this thread.
+         (unless dont-remove
+           (if (stringp (car thread))
+               (progn
+                 ;; If we use dummy roots, then we have to remove the
+                 ;; dummy root as well.
+                 (when (eq gnus-summary-make-false-root 'dummy)
+                   ;; We go to the dummy root by going to
+                   ;; the first sub-"thread", and then one line up.
+                   (gnus-summary-goto-article
+                    (mail-header-number (caadr thread)))
+                   (forward-line -1)
+                   (gnus-delete-line)
+                   (gnus-data-compute-positions))
+                 (setq thread (cdr thread))
+                 (while thread
+                   (gnus-remove-thread-1 (car thread))
+                   (setq thread (cdr thread))))
+             (gnus-remove-thread-1 thread))))))))
+
+(defun gnus-remove-thread-1 (thread)
+  "Remove the thread THREAD recursively."
+  (let ((number (mail-header-number (pop thread)))
+       d)
+    (setq thread (reverse thread))
+    (while thread
+      (gnus-remove-thread-1 (pop thread)))
+    (when (setq d (gnus-data-find number))
+      (goto-char (gnus-data-pos d))
+      (gnus-summary-show-thread)
+      (gnus-data-remove
+       number
+       (- (point-at-bol)
+         (prog1
+             (1+ (point-at-eol))
+           (gnus-delete-line)))))))
+
+(defun gnus-sort-threads-recursive (threads func)
+  ;; Responsible for sorting the root articles of threads.
+  (let ((subthread-sort-func (if (eq gnus-subthread-sort-functions
+                                    'gnus-thread-sort-functions)
+                                func
+                              (gnus-make-sort-function
+                               gnus-subthread-sort-functions))))
+    (sort (mapcar (lambda (thread)
+                   (cons (car thread)
+                         (and (cdr thread)
+                              (gnus-sort-subthreads-recursive
+                               (cdr thread) subthread-sort-func))))
+                 threads) func)))
+
+(defun gnus-sort-subthreads-recursive (threads func)
+  ;; Responsible for sorting subthreads.
+  (sort (mapcar (lambda (thread)
+                 (cons (car thread)
+                       (and (cdr thread)
+                            (gnus-sort-subthreads-recursive (cdr thread) func))))
+               threads) func))
+
+(defun gnus-sort-threads-loop (threads func)
+  (let* ((superthread (cons nil threads))
+        (stack (list (cons superthread threads)))
+        remaining-threads thread)
+    (while stack
+      (setq remaining-threads (cdr (car stack)))
+      (if remaining-threads
+         (progn (setq thread (car remaining-threads))
+                (setcdr (car stack) (cdr remaining-threads))
+                (if (cdr thread)
+                    (push (cons thread (cdr thread)) stack)))
+       (setq thread (caar stack))
+       (setcdr thread (sort (cdr thread) func))
+       (pop stack)))
+    (cdr superthread)))
+
+(defun gnus-sort-threads (threads)
+  "Sort THREADS."
+  (if (not gnus-thread-sort-functions)
+      threads
+    (gnus-message 8 "Sorting threads...")
+    (prog1
+       (condition-case nil
+           (let ((max-lisp-eval-depth (max max-lisp-eval-depth 5000))
+                 (sort-func (gnus-make-sort-function gnus-thread-sort-functions)))
+             (gnus-sort-threads-recursive threads sort-func))
+         ;; Even after binding max-lisp-eval-depth, the recursive
+         ;; sorter might fail for very long threads.  In that case,
+         ;; try using a (less well-tested) non-recursive sorter.
+         (error (gnus-message 9 "Sorting threads with loop...")
+                (gnus-sort-threads-loop
+                 threads (gnus-make-sort-function
+                          gnus-thread-sort-functions))))
+      (gnus-message 8 "Sorting threads...done"))))
+
+(defun gnus-sort-articles (articles)
+  "Sort ARTICLES."
+  (when gnus-article-sort-functions
+    (gnus-message 7 "Sorting articles...")
+    (prog1
+       (setq gnus-newsgroup-headers
+             (sort articles (gnus-make-sort-function
+                             gnus-article-sort-functions)))
+      (gnus-message 7 "Sorting articles...done"))))
+
+;; Written by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>.
+(defmacro gnus-thread-header (thread)
+  "Return header of first article in THREAD.
+Note that THREAD must never, ever be anything else than a variable -
+using some other form will lead to serious barfage."
+  (or (symbolp thread) (signal 'wrong-type-argument '(symbolp thread)))
+  ;; (8% speedup to gnus-summary-prepare, just for fun :-)
+  (list 'byte-code "\10\211:\203\17\0\211@;\203\16\0A@@\207"
+       (vector thread) 2))
+
+(defsubst gnus-article-sort-by-number (h1 h2)
+  "Sort articles by article number."
+  (< (mail-header-number h1)
+     (mail-header-number h2)))
+
+(defun gnus-thread-sort-by-number (h1 h2)
+  "Sort threads by root article number."
+  (gnus-article-sort-by-number
+   (gnus-thread-header h1) (gnus-thread-header h2)))
+
+(defsubst gnus-article-sort-by-random (h1 h2)
+  "Sort articles randomly."
+  (zerop (random 2)))
+
+(defun gnus-thread-sort-by-random (h1 h2)
+  "Sort threads randomly."
+  (gnus-article-sort-by-random
+   (gnus-thread-header h1) (gnus-thread-header h2)))
+
+(defsubst gnus-article-sort-by-lines (h1 h2)
+  "Sort articles by article Lines header."
+  (< (mail-header-lines h1)
+     (mail-header-lines h2)))
+
+(defun gnus-thread-sort-by-lines (h1 h2)
+  "Sort threads by root article Lines header."
+  (gnus-article-sort-by-lines
+   (gnus-thread-header h1) (gnus-thread-header h2)))
+
+(defsubst gnus-article-sort-by-chars (h1 h2)
+  "Sort articles by octet length."
+  (< (mail-header-chars h1)
+     (mail-header-chars h2)))
+
+(defun gnus-thread-sort-by-chars (h1 h2)
+  "Sort threads by root article octet length."
+  (gnus-article-sort-by-chars
+   (gnus-thread-header h1) (gnus-thread-header h2)))
+
+(defsubst gnus-article-sort-by-author (h1 h2)
+  "Sort articles by root author."
+  (gnus-string<
+   (let ((extract (funcall
+                  gnus-extract-address-components
+                  (mail-header-from h1))))
+     (or (car extract) (cadr extract) ""))
+   (let ((extract (funcall
+                  gnus-extract-address-components
+                  (mail-header-from h2))))
+     (or (car extract) (cadr extract) ""))))
+
+(defun gnus-thread-sort-by-author (h1 h2)
+  "Sort threads by root author."
+  (gnus-article-sort-by-author
+   (gnus-thread-header h1)  (gnus-thread-header h2)))
+
+(defsubst gnus-article-sort-by-recipient (h1 h2)
+  "Sort articles by recipient."
+  (gnus-string<
+   (let ((extract (funcall
+                  gnus-extract-address-components
+                  (or (cdr (assq 'To (mail-header-extra h1))) ""))))
+     (or (car extract) (cadr extract)))
+   (let ((extract (funcall
+                  gnus-extract-address-components
+                  (or (cdr (assq 'To (mail-header-extra h2))) ""))))
+     (or (car extract) (cadr extract)))))
+
+(defun gnus-thread-sort-by-recipient (h1 h2)
+  "Sort threads by root recipient."
+  (gnus-article-sort-by-recipient
+   (gnus-thread-header h1) (gnus-thread-header h2)))
+
+(defsubst gnus-article-sort-by-subject (h1 h2)
+  "Sort articles by root subject."
+  (gnus-string<
+   (downcase (gnus-simplify-subject-re (mail-header-subject h1)))
+   (downcase (gnus-simplify-subject-re (mail-header-subject h2)))))
+
+(defun gnus-thread-sort-by-subject (h1 h2)
+  "Sort threads by root subject."
+  (gnus-article-sort-by-subject
+   (gnus-thread-header h1) (gnus-thread-header h2)))
+
+(defsubst gnus-article-sort-by-date (h1 h2)
+  "Sort articles by root article date."
+  (time-less-p
+   (gnus-date-get-time (mail-header-date h1))
+   (gnus-date-get-time (mail-header-date h2))))
+
+(defun gnus-thread-sort-by-date (h1 h2)
+  "Sort threads by root article date."
+  (gnus-article-sort-by-date
+   (gnus-thread-header h1) (gnus-thread-header h2)))
+
+(defsubst gnus-article-sort-by-score (h1 h2)
+  "Sort articles by root article score.
+Unscored articles will be counted as having a score of zero."
+  (> (or (cdr (assq (mail-header-number h1)
+                   gnus-newsgroup-scored))
+        gnus-summary-default-score 0)
+     (or (cdr (assq (mail-header-number h2)
+                   gnus-newsgroup-scored))
+        gnus-summary-default-score 0)))
+
+(defun gnus-thread-sort-by-score (h1 h2)
+  "Sort threads by root article score."
+  (gnus-article-sort-by-score
+   (gnus-thread-header h1) (gnus-thread-header h2)))
+
+(defun gnus-thread-sort-by-total-score (h1 h2)
+  "Sort threads by the sum of all scores in the thread.
+Unscored articles will be counted as having a score of zero."
+  (> (gnus-thread-total-score h1) (gnus-thread-total-score h2)))
+
+(defun gnus-thread-total-score (thread)
+  ;; This function find the total score of THREAD.
+  (cond
+   ((null thread)
+    0)
+   ((consp thread)
+    (if (stringp (car thread))
+       (apply gnus-thread-score-function 0
+              (mapcar 'gnus-thread-total-score-1 (cdr thread)))
+      (gnus-thread-total-score-1 thread)))
+   (t
+    (gnus-thread-total-score-1 (list thread)))))
+
+(defun gnus-article-sort-by-most-recent-number (h1 h2)
+  "Sort articles by number."
+  (gnus-article-sort-by-number h1 h2))
+
+(defun gnus-thread-sort-by-most-recent-number (h1 h2)
+  "Sort threads such that the thread with the most recently arrived article comes first."
+  (> (gnus-thread-highest-number h1) (gnus-thread-highest-number h2)))
+
+(defun gnus-thread-highest-number (thread)
+  "Return the highest article number in THREAD."
+  (apply 'max (mapcar (lambda (header)
+                       (mail-header-number header))
+                     (message-flatten-list thread))))
+
+(defun gnus-article-sort-by-most-recent-date (h1 h2)
+  "Sort articles by number."
+  (gnus-article-sort-by-date h1 h2))
+
+(defun gnus-thread-sort-by-most-recent-date (h1 h2)
+  "Sort threads such that the thread with the most recently dated article comes first."
+  (> (gnus-thread-latest-date h1) (gnus-thread-latest-date h2)))
+
+; Since this is called not only to sort the top-level threads, but
+; also in recursive sorts to order the articles within a thread, each
+; article will be processed many times.  Thus it speeds things up
+; quite a bit to use gnus-date-get-time, which caches the time value.
+(defun gnus-thread-latest-date (thread)
+  "Return the highest article date in THREAD."
+  (apply 'max
+        (mapcar (lambda (header) (gnus-float-time
+                                  (gnus-date-get-time
+                                   (mail-header-date header))))
+                (message-flatten-list thread))))
+
+(defun gnus-thread-total-score-1 (root)
+  ;; This function find the total score of the thread below ROOT.
+  (setq root (car root))
+  (apply gnus-thread-score-function
+        (or (append
+             (mapcar 'gnus-thread-total-score
+                     (cdr (gnus-id-to-thread (mail-header-id root))))
+             (when (> (mail-header-number root) 0)
+               (list (or (cdr (assq (mail-header-number root)
+                                    gnus-newsgroup-scored))
+                         gnus-summary-default-score 0))))
+            (list gnus-summary-default-score)
+            '(0))))
+
+;; Added by Per Abrahamsen <amanda@iesd.auc.dk>.
+(defvar gnus-tmp-prev-subject nil)
+(defvar gnus-tmp-false-parent nil)
+(defvar gnus-tmp-root-expunged nil)
+(defvar gnus-tmp-dummy-line nil)
+
+(defun gnus-extra-header (type &optional header)
+  "Return the extra header of TYPE."
+  (or (cdr (assq type (mail-header-extra (or header gnus-tmp-header))))
+      ""))
+
+(defvar gnus-tmp-thread-tree-header-string "")
+
+(defcustom gnus-sum-thread-tree-root "> "
+  "With %B spec, used for the root of a thread.
+If nil, use subject instead."
+  :version "22.1"
+  :type '(radio (const :format "%v  " nil) string)
+  :group 'gnus-thread)
+
+(defcustom gnus-sum-thread-tree-false-root "> "
+  "With %B spec, used for a false root of a thread.
+If nil, use subject instead."
+  :version "22.1"
+  :type '(radio (const :format "%v  " nil) string)
+  :group 'gnus-thread)
+
+(defcustom gnus-sum-thread-tree-single-indent ""
+  "With %B spec, used for a thread with just one message.
+If nil, use subject instead."
+  :version "22.1"
+  :type '(radio (const :format "%v  " nil) string)
+  :group 'gnus-thread)
+
+(defcustom gnus-sum-thread-tree-vertical "| "
+  "With %B spec, used for drawing a vertical line."
+  :version "22.1"
+  :type 'string
+  :group 'gnus-thread)
+
+(defcustom gnus-sum-thread-tree-indent "  "
+  "With %B spec, used for indenting."
+  :version "22.1"
+  :type 'string
+  :group 'gnus-thread)
+
+(defcustom gnus-sum-thread-tree-leaf-with-other "+-> "
+  "With %B spec, used for a leaf with brothers."
+  :version "22.1"
+  :type 'string
+  :group 'gnus-thread)
+
+(defcustom gnus-sum-thread-tree-single-leaf "\\-> "
+  "With %B spec, used for a leaf without brothers."
+  :version "22.1"
+  :type 'string
+  :group 'gnus-thread)
+
+(defcustom gnus-summary-display-while-building nil
+  "If non-nil, show and update the summary buffer as it's being built.
+If the value is t, update the buffer after every line is inserted.  If
+the value is an integer (N), update the display every N lines."
+  :version "22.1"
+  :group 'gnus-thread
+  :type '(choice (const :tag "off" nil)
+                number
+                (const :tag "frequently" t)))
+
+(defun gnus-summary-prepare-threads (threads)
+  "Prepare summary buffer from THREADS and indentation LEVEL.
+THREADS is either a list of `(PARENT [(CHILD1 [(GRANDCHILD ...]...) ...])'
+or a straight list of headers."
+  (gnus-message 7 "Generating summary...")
+
+  (setq gnus-newsgroup-threads threads)
+  (beginning-of-line)
+
+  (let ((gnus-tmp-level 0)
+       (default-score (or gnus-summary-default-score 0))
+       (gnus-visual-p (gnus-visual-p 'summary-highlight 'highlight))
+       (building-line-count gnus-summary-display-while-building)
+       (building-count (integerp gnus-summary-display-while-building))
+       thread number subject stack state gnus-tmp-gathered beg-match
+       new-roots gnus-tmp-new-adopts thread-end simp-subject
+       gnus-tmp-header gnus-tmp-unread gnus-tmp-downloaded
+       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
+       tree-stack)
+
+    (setq gnus-tmp-prev-subject nil
+          gnus-tmp-thread-tree-header-string "")
+
+    (if (vectorp (car threads))
+       ;; If this is a straight (sic) list of headers, then a
+       ;; threaded summary display isn't required, so we just create
+       ;; an unthreaded one.
+       (gnus-summary-prepare-unthreaded threads)
+
+      ;; Do the threaded display.
+
+      (if gnus-summary-display-while-building
+         (switch-to-buffer (buffer-name)))
+      (while (or threads stack gnus-tmp-new-adopts new-roots)
+
+       (if (and (= gnus-tmp-level 0)
+                (or (not stack)
+                    (= (caar stack) 0))
+                (not gnus-tmp-false-parent)
+                (or gnus-tmp-new-adopts new-roots))
+           (if gnus-tmp-new-adopts
+               (setq gnus-tmp-level (if gnus-tmp-root-expunged 0 1)
+                     thread (list (car gnus-tmp-new-adopts))
+                     gnus-tmp-header (caar thread)
+                     gnus-tmp-new-adopts (cdr gnus-tmp-new-adopts))
+             (when new-roots
+               (setq thread (list (car new-roots))
+                     gnus-tmp-header (caar thread)
+                     new-roots (cdr new-roots))))
+
+         (if threads
+             ;; If there are some threads, we do them before the
+             ;; threads on the stack.
+             (setq thread threads
+                   gnus-tmp-header (caar thread))
+           ;; There were no current threads, so we pop something off
+           ;; the stack.
+           (setq state (car stack)
+                 gnus-tmp-level (car state)
+                 tree-stack (cadr state)
+                 thread (caddr state)
+                 stack (cdr stack)
+                 gnus-tmp-header (caar thread))))
+
+       (setq gnus-tmp-false-parent nil)
+       (setq gnus-tmp-root-expunged nil)
+       (setq thread-end nil)
+
+       (if (stringp gnus-tmp-header)
+           ;; The header is a dummy root.
+           (cond
+            ((eq gnus-summary-make-false-root 'adopt)
+             ;; We let the first article adopt the rest.
+             (setq gnus-tmp-new-adopts (nconc gnus-tmp-new-adopts
+                                              (cddar thread)))
+             (setq gnus-tmp-gathered
+                   (nconc (mapcar
+                           (lambda (h) (mail-header-number (car h)))
+                           (cddar thread))
+                          gnus-tmp-gathered))
+             (setq thread (cons (list (caar thread)
+                                      (cadar thread))
+                                (cdr thread)))
+             (setq gnus-tmp-level -1
+                   gnus-tmp-false-parent t))
+            ((eq gnus-summary-make-false-root 'empty)
+             ;; We print adopted articles with empty subject fields.
+             (setq gnus-tmp-gathered
+                   (nconc (mapcar
+                           (lambda (h) (mail-header-number (car h)))
+                           (cddar thread))
+                          gnus-tmp-gathered))
+             (setq gnus-tmp-level -1))
+            ((eq gnus-summary-make-false-root 'dummy)
+             ;; We remember that we probably want to output a dummy
+             ;; root.
+             (setq gnus-tmp-dummy-line gnus-tmp-header)
+             (setq gnus-tmp-prev-subject gnus-tmp-header))
+            (t
+             ;; We do not make a root for the gathered
+             ;; sub-threads at all.
+             (setq gnus-tmp-level -1)))
+
+         (setq number (mail-header-number gnus-tmp-header)
+               subject (mail-header-subject gnus-tmp-header)
+               simp-subject (gnus-simplify-subject-fully subject))
+
+         (cond
+          ;; If the thread has changed subject, we might want to make
+          ;; this subthread into a root.
+          ((and (null gnus-thread-ignore-subject)
+                (not (zerop gnus-tmp-level))
+                gnus-tmp-prev-subject
+                (not (string= gnus-tmp-prev-subject simp-subject)))
+           (setq new-roots (nconc new-roots (list (car thread)))
+                 thread-end t
+                 gnus-tmp-header nil))
+          ;; If the article lies outside the current limit,
+          ;; then we do not display it.
+          ((not (memq number gnus-newsgroup-limit))
+           (setq gnus-tmp-gathered
+                 (nconc (mapcar
+                         (lambda (h) (mail-header-number (car h)))
+                         (cdar thread))
+                        gnus-tmp-gathered))
+           (setq gnus-tmp-new-adopts (if (cdar thread)
+                                         (append gnus-tmp-new-adopts
+                                                 (cdar thread))
+                                       gnus-tmp-new-adopts)
+                 thread-end t
+                 gnus-tmp-header nil)
+           (when (zerop gnus-tmp-level)
+             (setq gnus-tmp-root-expunged t)))
+          ;; Perhaps this article is to be marked as read?
+          ((and gnus-summary-mark-below
+                (< (or (cdr (assq number gnus-newsgroup-scored))
+                       default-score)
+                   gnus-summary-mark-below)
+                ;; Don't touch sparse articles.
+                (not (gnus-summary-article-sparse-p number))
+                (not (gnus-summary-article-ancient-p number)))
+           (setq gnus-newsgroup-unreads
+                 (delq number gnus-newsgroup-unreads))
+           (if gnus-newsgroup-auto-expire
+               (setq gnus-newsgroup-expirable
+                     (gnus-add-to-sorted-list
+                      gnus-newsgroup-expirable number))
+             (push (cons number gnus-low-score-mark)
+                   gnus-newsgroup-reads))))
+
+         (when gnus-tmp-header
+           ;; We may have an old dummy line to output before this
+           ;; article.
+           (when (and gnus-tmp-dummy-line
+                      (gnus-subject-equal
+                       gnus-tmp-dummy-line
+                       (mail-header-subject gnus-tmp-header)))
+             (gnus-summary-insert-dummy-line
+              gnus-tmp-dummy-line (mail-header-number gnus-tmp-header))
+             (setq gnus-tmp-dummy-line nil))
+
+           ;; Compute the mark.
+           (setq gnus-tmp-unread (gnus-article-mark number))
+
+           (push (gnus-data-make number gnus-tmp-unread (1+ (point))
+                                 gnus-tmp-header gnus-tmp-level)
+                 gnus-newsgroup-data)
+
+           ;; Actually insert the line.
+           (setq
+            gnus-tmp-subject-or-nil
+            (cond
+             ((and gnus-thread-ignore-subject
+                   gnus-tmp-prev-subject
+                   (not (string= gnus-tmp-prev-subject simp-subject)))
+              subject)
+             ((zerop gnus-tmp-level)
+              (if (and (eq gnus-summary-make-false-root 'empty)
+                       (memq number gnus-tmp-gathered)
+                       gnus-tmp-prev-subject
+                       (string= gnus-tmp-prev-subject simp-subject))
+                  gnus-summary-same-subject
+                subject))
+             (t gnus-summary-same-subject)))
+           (if (and (eq gnus-summary-make-false-root 'adopt)
+                    (= gnus-tmp-level 1)
+                    (memq number gnus-tmp-gathered))
+               (setq gnus-tmp-opening-bracket ?\<
+                     gnus-tmp-closing-bracket ?\>)
+             (setq gnus-tmp-opening-bracket ?\[
+                   gnus-tmp-closing-bracket ?\]))
+           (if (>= gnus-tmp-level (length gnus-thread-indent-array))
+               (gnus-make-thread-indent-array
+                (max (* 2 (length gnus-thread-indent-array))
+                     gnus-tmp-level)))
+           (setq
+            gnus-tmp-indentation
+            (aref gnus-thread-indent-array gnus-tmp-level)
+            gnus-tmp-lines (mail-header-lines gnus-tmp-header)
+            gnus-tmp-score (or (cdr (assq number gnus-newsgroup-scored))
+                               gnus-summary-default-score 0)
+            gnus-tmp-score-char
+            (if (or (null gnus-summary-default-score)
+                    (<= (abs (- gnus-tmp-score gnus-summary-default-score))
+                        gnus-summary-zcore-fuzz))
+                ?                      ;Whitespace
+              (if (< gnus-tmp-score gnus-summary-default-score)
+                  gnus-score-below-mark gnus-score-over-mark))
+            gnus-tmp-replied
+            (cond ((memq number gnus-newsgroup-processable)
+                   gnus-process-mark)
+                  ((memq number gnus-newsgroup-cached)
+                   gnus-cached-mark)
+                  ((memq number gnus-newsgroup-replied)
+                   gnus-replied-mark)
+                  ((memq number gnus-newsgroup-forwarded)
+                   gnus-forwarded-mark)
+                  ((memq number gnus-newsgroup-saved)
+                   gnus-saved-mark)
+                  ((memq number gnus-newsgroup-unseen)
+                   gnus-unseen-mark)
+                  (t gnus-no-mark))
+            gnus-tmp-downloaded
+             (cond ((memq number gnus-newsgroup-undownloaded)
+                    gnus-undownloaded-mark)
+                   (gnus-newsgroup-agentized
+                    gnus-downloaded-mark)
+                   (t
+                    gnus-no-mark))
+            gnus-tmp-from (mail-header-from gnus-tmp-header)
+            gnus-tmp-name
+            (cond
+             ((string-match "<[^>]+> *$" gnus-tmp-from)
+              (setq beg-match (match-beginning 0))
+              (or (and (string-match "^\".+\"" gnus-tmp-from)
+                       (substring gnus-tmp-from 1 (1- (match-end 0))))
+                  (substring gnus-tmp-from 0 beg-match)))
+             ((string-match "(.+)" gnus-tmp-from)
+              (substring gnus-tmp-from
+                         (1+ (match-beginning 0)) (1- (match-end 0))))
+             (t gnus-tmp-from))
+
+            ;; Do the %B string
+            gnus-tmp-thread-tree-header-string
+            (cond
+             ((not gnus-show-threads) "")
+             ((zerop gnus-tmp-level)
+              (cond ((cdar thread)
+                     (or gnus-sum-thread-tree-root subject))
+                    (gnus-tmp-new-adopts
+                     (or gnus-sum-thread-tree-false-root subject))
+                    (t
+                     (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))
+           (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))
+            'gnus-number number)
+           (when gnus-visual-p
+             (forward-line -1)
+             (gnus-summary-highlight-line)
+             (when gnus-summary-update-hook
+               (gnus-run-hooks 'gnus-summary-update-hook))
+             (forward-line 1))
+
+           (setq gnus-tmp-prev-subject simp-subject)))
+
+       (when (nth 1 thread)
+         (push (list (max 0 gnus-tmp-level)
+                     (copy-sequence 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)))
+       (if gnus-summary-display-while-building
+           (if building-count
+               (progn
+                 ;; use a set frequency
+                 (setq building-line-count (1- building-line-count))
+                 (when (= building-line-count 0)
+                   (sit-for 0)
+                   (setq building-line-count
+                         gnus-summary-display-while-building)))
+             ;; always
+             (sit-for 0)))
+       (unless threads
+         (setq gnus-tmp-level 0)))))
+  (gnus-message 7 "Generating summary...done"))
+
+(defun gnus-summary-prepare-unthreaded (headers)
+  "Generate an unthreaded summary buffer based on HEADERS."
+  (let (header number mark)
+
+    (beginning-of-line)
+
+    (while headers
+      ;; We may have to root out some bad articles...
+      (when (memq (setq number (mail-header-number
+                               (setq header (pop headers))))
+                 gnus-newsgroup-limit)
+       ;; Mark article as read when it has a low score.
+       (when (and gnus-summary-mark-below
+                  (< (or (cdr (assq number gnus-newsgroup-scored))
+                         gnus-summary-default-score 0)
+                     gnus-summary-mark-below)
+                  (not (gnus-summary-article-ancient-p number)))
+         (setq gnus-newsgroup-unreads
+               (delq number gnus-newsgroup-unreads))
+         (if gnus-newsgroup-auto-expire
+             (push number gnus-newsgroup-expirable)
+           (push (cons number gnus-low-score-mark)
+                 gnus-newsgroup-reads)))
+
+       (setq mark (gnus-article-mark number))
+       (push (gnus-data-make number mark (1+ (point)) header 0)
+             gnus-newsgroup-data)
+       (gnus-summary-insert-line
+        header 0 number
+        (memq number gnus-newsgroup-undownloaded)
+        mark (memq number gnus-newsgroup-replied)
+        (memq number gnus-newsgroup-expirable)
+        (mail-header-subject header) nil
+        (cdr (assq number gnus-newsgroup-scored))
+        (memq number gnus-newsgroup-processable))))))
+
+(declare-function gnus-parameter-list-identifier "gnus-art" (name) t)
+
+(defun gnus-group-get-list-identifiers (group)
+  "Get list identifier regexp for GROUP."
+  (or (gnus-parameter-list-identifier group)
+      (if (consp gnus-list-identifiers)
+          (mapconcat 'identity gnus-list-identifiers " *\\|")
+        gnus-list-identifiers)))
+
+(defun gnus-summary-remove-list-identifiers ()
+  "Remove list identifiers in `gnus-list-identifiers' from articles in the current group."
+  (let ((regexp (gnus-group-get-list-identifiers gnus-newsgroup-name))
+        changed subject)
+    (when regexp
+      (setq regexp (concat "^\\(?:R[Ee]: +\\)*\\(" regexp " *\\)"))
+      (dolist (header gnus-newsgroup-headers)
+       (setq subject (mail-header-subject header)
+             changed nil)
+       (while (string-match regexp subject)
+         (setq subject
+               (concat (substring subject 0 (match-beginning 1))
+                       (substring subject (match-end 0)))
+               changed t))
+       (when changed
+         (when (string-match "^\\(\\(?:R[Ee]: +\\)+\\)R[Ee]: +" subject)
+           (setq subject
+                 (concat (substring subject 0 (match-beginning 1))
+                         (substring subject (match-end 1)))))
+         (mail-header-set-subject header subject))))))
+
+(defun gnus-fetch-headers (articles &optional limit force-new dependencies)
+  "Fetch headers of ARTICLES."
+  (let ((name (gnus-group-decoded-name gnus-newsgroup-name)))
+    (gnus-message 7 "Fetching headers for %s..." name)
+    (prog1
+       (if (eq 'nov
+               (setq gnus-headers-retrieved-by
+                     (gnus-retrieve-headers
+                      articles gnus-newsgroup-name
+                      (or limit
+                          ;; We might want to fetch old headers, but
+                          ;; not if there is only 1 article.
+                          (and (or (and
+                                    (not (eq gnus-fetch-old-headers 'some))
+                                    (not (numberp gnus-fetch-old-headers)))
+                                   (> (length articles) 1))
+                               gnus-fetch-old-headers)))))
+           (gnus-get-newsgroup-headers-xover
+            articles force-new dependencies gnus-newsgroup-name t)
+         (gnus-get-newsgroup-headers dependencies force-new))
+      (gnus-message 7 "Fetching headers for %s...done" name))))
+
+(defun gnus-select-newsgroup (group &optional read-all select-articles)
+  "Select newsgroup GROUP.
+If READ-ALL is non-nil, all articles in the group are selected.
+If SELECT-ARTICLES, only select those articles from GROUP."
+  (let* ((entry (gnus-group-entry group))
+        ;;!!! Dirty hack; should be removed.
+        (gnus-summary-ignore-duplicates
+         (if (eq (car (gnus-find-method-for-group group)) 'nnvirtual)
+             t
+           gnus-summary-ignore-duplicates))
+        (info (nth 2 entry))
+        charset articles fetched-articles cached)
+
+    (unless (gnus-check-server
+            (set (make-local-variable 'gnus-current-select-method)
+                 (gnus-find-method-for-group group)))
+      (error "Couldn't open server"))
+    (setq charset (gnus-group-name-charset gnus-current-select-method group))
+
+    (or (and entry (not (eq (car entry) t))) ; Either it's active...
+       (gnus-activate-group group)     ; Or we can activate it...
+       (progn                          ; Or we bug out.
+         (when (derived-mode-p 'gnus-summary-mode)
+           (gnus-kill-buffer (current-buffer)))
+         (error
+          "Couldn't activate group %s: %s"
+          (mm-decode-coding-string group charset)
+          (mm-decode-coding-string (gnus-status-message group) charset))))
+
+    (unless (gnus-request-group group t nil (gnus-get-info group))
+      (when (derived-mode-p 'gnus-summary-mode)
+       (gnus-kill-buffer (current-buffer)))
+      (error "Couldn't request group %s: %s"
+            (mm-decode-coding-string group charset)
+            (mm-decode-coding-string (gnus-status-message group) charset)))
+
+    (when (and gnus-agent
+              (gnus-active group))
+      (gnus-agent-possibly-alter-active group (gnus-active group) info)
+
+      (setq gnus-summary-use-undownloaded-faces
+           (gnus-agent-find-parameter
+            group
+            'agent-enable-undownloaded-faces)))
+
+    (setq gnus-newsgroup-name group
+         gnus-newsgroup-unselected nil
+         gnus-newsgroup-unreads (gnus-list-of-unread-articles group))
+
+    (let ((display (gnus-group-find-parameter group 'display)))
+      (setq gnus-newsgroup-display
+           (cond
+            ((not (zerop (or (car-safe read-all) 0)))
+             ;; The user entered the group with C-u SPC/RET, let's show
+             ;; all articles.
+             'gnus-not-ignore)
+            ((eq display 'all)
+             'gnus-not-ignore)
+            ((arrayp display)
+             (gnus-summary-display-make-predicate (mapcar 'identity display)))
+            ((numberp display)
+             ;; The following is probably the "correct" solution, but
+             ;; it makes Gnus fetch all headers and then limit the
+             ;; articles (which is slow), so instead we hack the
+             ;; select-articles parameter instead. -- Simon Josefsson
+             ;; <jas@kth.se>
+             ;;
+             ;; (gnus-byte-compile
+             ;;  `(lambda () (> number ,(- (cdr (gnus-active group))
+             ;;                         display)))))
+             (setq select-articles
+                   (gnus-uncompress-range
+                    (cons (let ((tmp (- (cdr (gnus-active group)) display)))
+                            (if (> tmp 0)
+                                tmp
+                              1))
+                          (cdr (gnus-active group)))))
+             nil)
+            (t
+             nil))))
+
+    (gnus-summary-setup-default-charset)
+
+    ;; Kludge to avoid having cached articles nixed out in virtual groups.
+    (when (gnus-virtual-group-p group)
+      (setq cached gnus-newsgroup-cached))
+
+    (setq gnus-newsgroup-unreads
+         (gnus-sorted-ndifference
+          (gnus-sorted-ndifference gnus-newsgroup-unreads
+                                   gnus-newsgroup-marked)
+          gnus-newsgroup-dormant))
+
+    (setq gnus-newsgroup-processable nil)
+
+    (gnus-update-read-articles group gnus-newsgroup-unreads t)
+
+    ;; 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-difference gnus-newsgroup-unreads articles))
+      (setq articles (gnus-articles-to-read group read-all)))
+
+    (cond
+     ((null articles)
+      ;;(gnus-message 3 "Couldn't select newsgroup -- no articles to display")
+      'quit)
+     ((eq articles 0) nil)
+     (t
+      ;; Init the dependencies hash table.
+      (setq gnus-newsgroup-dependencies
+           (gnus-make-hashtable (length articles)))
+      (if (gnus-buffer-live-p gnus-group-buffer)
+         (gnus-set-global-variables)
+       (set-default 'gnus-newsgroup-name gnus-newsgroup-name))
+      ;; Retrieve the headers and read them in.
+
+      (setq gnus-newsgroup-headers (gnus-fetch-headers articles))
+
+      ;; Kludge to avoid having cached articles nixed out in virtual groups.
+      (when cached
+       (setq gnus-newsgroup-cached cached))
+
+      ;; Suppress duplicates?
+      (when gnus-suppress-duplicates
+       (gnus-dup-suppress-articles))
+
+      ;; 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-sorted-nintersection
+            gnus-newsgroup-unreads fetched-articles))
+      (gnus-compute-unseen-list)
+
+      ;; Removed marked articles that do not exist.
+      (gnus-update-missing-marks
+       (gnus-sorted-difference articles fetched-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-old-threads)))
+      ;; Let the Gnus agent mark articles as read.
+      (when gnus-agent
+       (gnus-agent-get-undownloaded-list))
+      ;; Remove list identifiers from subject
+      (gnus-summary-remove-list-identifiers)
+      ;; Check whether auto-expire is to be done in this group.
+      (setq gnus-newsgroup-auto-expire
+           (and (gnus-group-auto-expirable-p group)
+                (not (gnus-group-read-only-p group))))
+      ;; Set up the article buffer now, if necessary.
+      (unless (and gnus-single-article-buffer
+                  (equal gnus-article-buffer "*Article*"))
+       (gnus-article-setup-buffer))
+      ;; First and last article in this newsgroup.
+      (when gnus-newsgroup-headers
+       (setq gnus-newsgroup-begin
+             (mail-header-number (car gnus-newsgroup-headers))
+             gnus-newsgroup-end
+             (mail-header-number
+              (gnus-last-element gnus-newsgroup-headers))))
+      ;; GROUP is successfully selected.
+      (or gnus-newsgroup-headers t)))))
+
+(defun gnus-compute-unseen-list ()
+  ;; The `seen' marks are treated specially.
+  (if (not gnus-newsgroup-seen)
+      (setq gnus-newsgroup-unseen gnus-newsgroup-articles)
+    (setq gnus-newsgroup-unseen
+         (gnus-inverse-list-range-intersection
+          gnus-newsgroup-articles gnus-newsgroup-seen))))
+
+(declare-function gnus-get-predicate "gnus-agent" (predicate))
+
+(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 '((unread . unread)
+                           (read . read)
+                           (unseen . unseen))
+                         gnus-article-mark-lists))
+      (push (cons (cdr elem)
+                 (gnus-byte-compile    ;Why bother?
+                  `(lambda () (gnus-article-marked-p ',(cdr elem)))))
+           gnus-summary-display-cache)))
+  (let ((gnus-category-predicate-alist gnus-summary-display-cache)
+       (gnus-category-predicate-cache gnus-summary-display-cache))
+    (gnus-get-predicate display)))
+
+;; Uses the dynamically bound `gnus-number' variable.
+(defvar gnus-number)
+(defun gnus-article-marked-p (type &optional article)
+  (let ((article (or article gnus-number)))
+    (cond
+     ((eq type 'tick)
+      (memq article gnus-newsgroup-marked))
+     ((eq type 'spam)
+      (memq article gnus-newsgroup-spam-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)))
+     (t t))))
+
+(defun gnus-articles-to-read (group &optional read-all)
+  "Find out what articles the user wants to read."
+  (let* ((only-read-p t)
+        (articles
+         (gnus-list-range-difference
+         ;; Select all articles if `read-all' is non-nil, or if there
+         ;; are no unread articles.
+         (if (or read-all
+                 (and (zerop (length gnus-newsgroup-marked))
+                      (zerop (length gnus-newsgroup-unreads)))
+                 ;; Fetch all if the predicate is non-nil.
+                 gnus-newsgroup-display)
+             ;; 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
+              (if gnus-newsgroup-maximum-articles
+                  (let ((active (gnus-active group)))
+                    (gnus-uncompress-range
+                     (cons (max (car active)
+                                (- (cdr active)
+                                   gnus-newsgroup-maximum-articles
+                                   -1))
+                           (cdr active))))
+                (gnus-uncompress-range (gnus-active group)))
+              (gnus-cache-articles-in-group group))
+           ;; Select only the "normal" subset of articles.
+           (setq only-read-p nil)
+           (gnus-sorted-nunion
+            (gnus-sorted-union gnus-newsgroup-dormant gnus-newsgroup-marked)
+            gnus-newsgroup-unreads))
+         (cdr (assq 'unexist (gnus-info-marks (gnus-get-info group))))))
+        (scored-list (gnus-killed-articles gnus-newsgroup-killed articles))
+        (scored (length scored-list))
+        (number (length articles))
+        (marked (+ (length gnus-newsgroup-marked)
+                   (length gnus-newsgroup-dormant)))
+        (select
+         (cond
+          ((numberp read-all)
+           read-all)
+          ((numberp gnus-newsgroup-display)
+           gnus-newsgroup-display)
+          (t
+           (condition-case ()
+               (cond
+                ((and (or (<= scored marked) (= scored number))
+                      (numberp gnus-large-newsgroup)
+                      (> number gnus-large-newsgroup))
+                 (let* ((cursor-in-echo-area nil)
+                        (initial (gnus-parameter-large-newsgroup-initial
+                                  gnus-newsgroup-name))
+                        (default (if only-read-p
+                                     (or initial gnus-large-newsgroup)
+                                   number))
+                        (input
+                         (read-string
+                          (if only-read-p
+                              (format
+                               "How many articles from %s (available %d, default %d): "
+                               (gnus-group-decoded-name
+                                (gnus-group-real-name gnus-newsgroup-name))
+                               number default)
+                            (format
+                             "How many articles from %s (%d default): "
+                             (gnus-group-decoded-name
+                              (gnus-group-real-name gnus-newsgroup-name))
+                             default))
+                          nil
+                          nil
+                          (number-to-string default))))
+                   (if (string-match "^[ \t]*$" input) number input)))
+                ((and (> scored marked) (< scored number)
+                      (> (- scored number) 20))
+                 (let ((input
+                        (read-string
+                         (format "%s %s (%d scored, %d total): "
+                                 "How many articles from"
+                                 (gnus-group-decoded-name
+                                  (gnus-group-real-name gnus-newsgroup-name))
+                                 scored number))))
+                   (if (string-match "^[ \t]*$" input)
+                       number input)))
+                (t number))
+             (quit
+              (message "Quit getting the articles to read")
+              nil))))))
+    (setq select (if (stringp select) (string-to-number select) select))
+    (if (or (null select) (zerop select))
+       select
+      (if (and (not (zerop scored)) (<= (abs select) scored))
+         (progn
+           (setq articles (sort scored-list '<))
+           (setq number (length articles)))
+       (setq articles (copy-sequence articles)))
+
+      (when (< (abs select) number)
+       (if (< select 0)
+           ;; Select the N oldest articles.
+           (setcdr (nthcdr (1- (abs select)) articles) nil)
+         ;; Select the N most recent articles.
+         (setq articles (nthcdr (- number select) articles))))
+      (setq gnus-newsgroup-unselected
+           (gnus-sorted-difference gnus-newsgroup-unreads articles))
+      (when gnus-alter-articles-to-read-function
+       (setq articles
+             (sort
+              (funcall gnus-alter-articles-to-read-function
+                       gnus-newsgroup-name articles)
+              '<)))
+      articles)))
+
+(defun gnus-killed-articles (killed articles)
+  (let (out)
+    (while articles
+      (when (inline (gnus-member-of-range (car articles) killed))
+       (push (car articles) out))
+      (setq articles (cdr articles)))
+    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 back end."
+  (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))
+        (active (gnus-active (gnus-info-group info)))
+        (min (car active))
+        (max (cdr active))
+        (types gnus-article-mark-lists)
+        marks var articles article mark mark-type
+         bgn end)
+    ;; Hack to avoid adjusting marks for imap.
+    (when (eq (car (gnus-find-method-for-group (gnus-info-group info)))
+             'nnimap)
+      (setq min 1))
+
+    (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)))))
+      ;; 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 - compressed yet unsorted
+       ((eq mark-type 'list)
+        ;; Simultaneously uncompress and clip to active range
+        ;; See gnus-uncompress-range for a description of possible marks
+        (let (l lh)
+          (if (not (cadr marks))
+              (set var nil)
+            (setq articles (if (numberp (cddr marks))
+                               (list (cdr marks))
+                             (cdr marks))
+                  lh (cons nil nil)
+                  l lh)
+
+            (while (setq article (pop articles))
+              (cond ((consp article)
+                     (setq bgn (max (car article) min)
+                           end (min (cdr article) max))
+                     (while (<= bgn end)
+                       (setq l (setcdr l (cons bgn nil))
+                             bgn (1+ bgn))))
+                    ((and (<= min article)
+                          (>= max article))
+                     (setq l (setcdr l (cons article nil))))))
+            (set var (cdr lh)))))
+       ;; Adjust assocs.
+       ((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)))
+         (setq articles (list articles)))
+       (while articles
+         (when (or (not (consp (setq article (pop articles))))
+                   (< (car article) min)
+                   (> (car article) max))
+           (set var (delq article (symbol-value var))))))
+       ;; Adjust ranges (sloppily).
+       ((eq mark-type 'range)
+       (cond
+        ((eq mark 'seen)
+         ;; Fix the record for `seen' if it looks like (seen NUM1 . NUM2).
+         ;; It should be (seen (NUM1 . NUM2)).
+         (when (numberp (cddr marks))
+           (setcdr marks (list (cdr marks))))
+         (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))
+        ((eq mark 'unexist)
+         (set var (cdr marks)))))))))
+
+(defun gnus-update-missing-marks (missing)
+  "Go through the list of MISSING articles and remove them from the mark lists."
+  (when missing
+    (let (var m)
+      ;; Go through all types.
+      (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))
+       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))))))
+
+       (when list
+         ;; Get rid of the entries of the articles that have the
+         ;; default score.
+         (when (and (eq (cdr type) 'score)
+                    gnus-save-score
+                    list)
+           (let* ((arts list)
+                  (prev (cons nil list))
+                  (all prev))
+             (while arts
+               (if (or (not (consp (car arts)))
+                       (= (cdar arts) gnus-summary-default-score))
+                   (setcdr prev (cdr arts))
+                 (setq prev arts))
+               (setq arts (cdr arts)))
+             (setq list (cdr all)))))
+
+       (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 (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))))
+                ;; Don't do anything about marks for articles we
+                ;; didn't actually get any headers for.
+                (del
+                 (gnus-list-range-intersection
+                  gnus-newsgroup-articles
+                  (gnus-remove-from-range (gnus-copy-sequence old) list)))
+                (add
+                 (gnus-list-range-intersection
+                  gnus-newsgroup-articles
+                  (gnus-remove-from-range
+                   (gnus-copy-sequence list) old))))
+           (when add
+             (push (list add 'add (list (cdr type))) delta-marks))
+           (when del
+             ;; Don't delete marks from outside the active range.
+             ;; This shouldn't happen, but is a sanity check.
+             (setq del (gnus-sorted-range-intersection
+                        (gnus-active gnus-newsgroup-name) del))
+             (push (list del 'del (list (cdr type))) delta-marks))))
+
+       (when (or list
+                 (eq (cdr type) 'unexist))
+         (push (cons (cdr type) list) newmarked)))
+
+      (when delta-marks
+       (unless (gnus-check-group gnus-newsgroup-name)
+         (error "Can't open server for %s" gnus-newsgroup-name))
+       (gnus-request-set-mark gnus-newsgroup-name delta-marks))
+
+      ;; Enter these new marks into the info of the group.
+      (if (nthcdr 3 info)
+         (setcar (nthcdr 3 info) newmarked)
+       ;; Add the marks lists to the end of the info.
+       (when newmarked
+         (setcdr (nthcdr 2 info) (list newmarked))))
+
+      ;; Cut off the end of the info if there's nothing else there.
+      (let ((i 5))
+       (while (and (> i 2)
+                   (not (nth i info)))
+         (when (nthcdr (decf i) info)
+           (setcdr (nthcdr i info) nil)))))))
+
+(defun gnus-set-mode-line (where)
+  "Set the mode line of the article or summary buffers.
+If WHERE is `summary', the summary mode line format will be used."
+  ;; Is this mode line one we keep updated?
+  (when (and (memq where gnus-updated-mode-lines)
+            (symbol-value
+             (intern (format "gnus-%s-mode-line-format-spec" where))))
+    (let (mode-string)
+      ;; We evaluate this in the summary buffer since these
+      ;; variables are buffer-local to that buffer.
+      (with-current-buffer gnus-summary-buffer
+        ;; 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-mode-string-quote
+                                    (gnus-group-decoded-name
+                                     gnus-newsgroup-name)))
+              (gnus-tmp-article-number (or gnus-current-article 0))
+              (gnus-tmp-unread gnus-newsgroup-unreads)
+              (gnus-tmp-unread-and-unticked (length gnus-newsgroup-unreads))
+              (gnus-tmp-unselected (length gnus-newsgroup-unselected))
+              (gnus-tmp-unread-and-unselected
+               (cond ((and (zerop gnus-tmp-unread-and-unticked)
+                           (zerop gnus-tmp-unselected))
+                      "")
+                     ((zerop gnus-tmp-unselected)
+                      (format "{%d more}" gnus-tmp-unread-and-unticked))
+                     (t (format "{%d(+%d) more}"
+                                gnus-tmp-unread-and-unticked
+                                gnus-tmp-unselected))))
+              (gnus-tmp-subject
+               (if (and gnus-current-headers
+                        (vectorp gnus-current-headers))
+                   (gnus-mode-string-quote
+                    (mail-header-subject gnus-current-headers))
+                 ""))
+              bufname-length max-len
+              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
+                                      (buffer-name
+                                       (if (eq where 'summary)
+                                           nil
+                                         (get-buffer gnus-article-buffer))))
+                                     2)
+                                0))
+         (setq max-len (max 4 (if gnus-mode-non-string-length
+                                  (- (window-width)
+                                     gnus-mode-non-string-length
+                                     bufname-length)
+                                (length mode-string))))
+         ;; We might have to chop a bit of the string off...
+         (when (> (length mode-string) max-len)
+           (setq mode-string
+                 (concat (truncate-string-to-width mode-string (- max-len 3))
+                         "...")))))
+      ;; Update the mode line.
+      (setq mode-line-buffer-identification
+           (gnus-mode-line-buffer-identification (list mode-string)))
+      (set-buffer-modified-p t))))
+
+(defun gnus-create-xref-hashtb (from-newsgroup headers unreads)
+  "Go through the HEADERS list and add all Xrefs to a hash table.
+The resulting hash table is returned, or nil if no Xrefs were found."
+  (let* ((virtual (gnus-virtual-group-p from-newsgroup))
+        (prefix (if virtual "" (gnus-group-real-prefix from-newsgroup)))
+        (xref-hashtb (gnus-make-hashtable))
+        start group entry number xrefs header)
+    (while headers
+      (setq header (pop headers))
+      (when (and (setq xrefs (mail-header-xref header))
+                (not (memq (setq number (mail-header-number header))
+                           unreads)))
+       (setq start 0)
+       (while (string-match "\\([^ ]+\\)[:/]\\([0-9]+\\)" xrefs start)
+         (setq start (match-end 0))
+         (setq group (if prefix
+                         (concat prefix (substring xrefs (match-beginning 1)
+                                                   (match-end 1)))
+                       (substring xrefs (match-beginning 1) (match-end 1))))
+         (setq number
+               (string-to-number (substring xrefs (match-beginning 2)
+                                         (match-end 2))))
+         (if (setq entry (gnus-gethash group xref-hashtb))
+             (setcdr entry (cons number (cdr entry)))
+           (gnus-sethash group (cons number nil) xref-hashtb)))))
+    (and start xref-hashtb)))
+
+(defun gnus-mark-xrefs-as-read (from-newsgroup headers unreads)
+  "Look through all the headers and mark the Xrefs as read."
+  (let ((virtual (gnus-virtual-group-p from-newsgroup))
+       name info xref-hashtb idlist method nth4)
+    (with-current-buffer gnus-group-buffer
+      (when (setq xref-hashtb
+                 (gnus-create-xref-hashtb from-newsgroup headers unreads))
+       (mapatoms
+        (lambda (group)
+          (unless (string= from-newsgroup (setq name (symbol-name group)))
+            (setq idlist (symbol-value group))
+            ;; Dead groups are not updated.
+            (and (prog1
+                     (setq info (gnus-get-info name))
+                   (when (stringp (setq nth4 (gnus-info-method info)))
+                     (setq nth4 (gnus-server-to-method nth4))))
+                 ;; Only do the xrefs if the group has the same
+                 ;; select method as the group we have just read.
+                 (or (gnus-methods-equal-p
+                      nth4 (gnus-find-method-for-group from-newsgroup))
+                     virtual
+                     (equal nth4 (setq method (gnus-find-method-for-group
+                                               from-newsgroup)))
+                     (and (equal (car nth4) (car method))
+                          (equal (nth 1 nth4) (nth 1 method))))
+                 gnus-use-cross-reference
+                 (or (not (eq gnus-use-cross-reference t))
+                     virtual
+                     ;; Only do cross-references on subscribed
+                     ;; groups, if that is what is wanted.
+                     (<= (gnus-info-level info) gnus-level-subscribed))
+                 (gnus-group-make-articles-read name idlist))))
+        xref-hashtb)))))
+
+(defun gnus-compute-read-articles (group articles)
+  (let* ((entry (gnus-group-entry group))
+        (info (nth 2 entry))
+        (active (gnus-active group))
+        ninfo)
+    (when entry
+      ;; First peel off all invalid article numbers.
+      (when active
+       (let ((ids articles)
+             id first)
+         (while (setq id (pop ids))
+           (when (and first (> id (cdr active)))
+             ;; We'll end up in this situation in one particular
+             ;; obscure situation.  If you re-scan a group and get
+             ;; a new article that is cross-posted to a different
+             ;; group that has not been re-scanned, you might get
+             ;; crossposted article that has a higher number than
+             ;; Gnus believes possible.  So we re-activate this
+             ;; group as well.  This might mean doing the
+             ;; crossposting thingy will *increase* the number
+             ;; of articles in some groups.  Tsk, tsk.
+             (setq active (or (gnus-activate-group group) active)))
+           (when (or (> id (cdr active))
+                     (< id (car active)))
+             (setq articles (delq id articles))))))
+      ;; If the read list is nil, we init it.
+      (if (and active
+              (null (gnus-info-read info))
+              (> (car active) 1))
+         (setq ninfo (cons 1 (1- (car active))))
+       (setq ninfo (gnus-info-read info)))
+      ;; Then we add the read articles to the range.
+      (gnus-add-to-range
+       ninfo (setq articles (sort articles '<))))))
+
+(defun gnus-group-make-articles-read (group articles)
+  "Update the info of GROUP to say that ARTICLES are read."
+  (let* ((num 0)
+        (entry (gnus-group-entry group))
+        (info (nth 2 entry))
+        (active (gnus-active group))
+        (set-marks
+         (gnus-method-option-p
+          (gnus-find-method-for-group group)
+          'server-marks))
+        range)
+    (if (not entry)
+       ;; Group that Gnus doesn't know exists, but still allow the
+       ;; backend to set marks.
+       (when set-marks
+         (gnus-request-set-mark
+          group (list (list (gnus-compress-sequence (sort articles #'<))
+                            'add '(read)))))
+      ;; Normal, subscribed groups.
+      (setq range (gnus-compute-read-articles group articles))
+      (with-current-buffer gnus-group-buffer
+       (gnus-undo-register
+         `(progn
+            (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))
+            (when ,set-marks
+              (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)
+      (when set-marks
+       (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
+       (cond
+        ((not range)
+         (setq num (- (1+ (cdr active)) (car active))))
+        ((not (listp (cdr range)))
+         (setq num (- (cdr active) (- (1+ (cdr range))
+                                      (car range)))))
+        (t
+         (while range
+           (if (numberp (car range))
+               (setq num (1+ num))
+             (setq num (+ num (- (1+ (cdar range)) (caar range)))))
+           (setq range (cdr range)))
+         (setq num (- (cdr active) num))))
+       ;; Update the number of unread articles.
+       (setcar entry num)
+       ;; Update the group buffer.
+       (unless (gnus-ephemeral-group-p group)
+         (gnus-group-update-group group t))))))
+
+(defun gnus-get-newsgroup-headers (&optional dependencies force-new)
+  (let ((cur nntp-server-buffer)
+       (dependencies
+        (or dependencies
+            (with-current-buffer gnus-summary-buffer
+              gnus-newsgroup-dependencies)))
+       headers id end ref number
+       (mail-parse-charset gnus-newsgroup-charset)
+       (mail-parse-ignored-charsets
+        (save-current-buffer (condition-case nil
+                                  (set-buffer gnus-summary-buffer)
+                                (error))
+                              gnus-newsgroup-ignored-charsets)))
+    (with-current-buffer nntp-server-buffer
+      ;; Translate all TAB characters into SPACE characters.
+      (subst-char-in-region (point-min) (point-max) ?\t ?  t)
+      (subst-char-in-region (point-min) (point-max) ?\r ?  t)
+      (ietf-drums-unfold-fws)
+      (gnus-run-hooks 'gnus-parse-headers-hook)
+      (let ((case-fold-search t)
+           in-reply-to header p lines chars)
+       (goto-char (point-min))
+       ;; Search to the beginning of the next header.  Error messages
+       ;; do not begin with 2 or 3.
+       (while (re-search-forward "^[23][0-9]+ " nil t)
+         (setq id nil
+               ref nil)
+         ;; This implementation of this function, with nine
+         ;; search-forwards instead of the one re-search-forward and
+         ;; a case (which basically was the old function) is actually
+         ;; about twice as fast, even though it looks messier.  You
+         ;; can't have everything, I guess.  Speed and elegance
+         ;; doesn't always go hand in hand.
+         (setq
+          header
+          (vector
+           ;; Number.
+           (prog1
+               (setq number (read cur))
+             (end-of-line)
+             (setq p (point))
+             (narrow-to-region (point)
+                               (or (and (search-forward "\n.\n" nil t)
+                                        (- (point) 2))
+                                   (point))))
+           ;; Subject.
+           (progn
+             (goto-char p)
+             (if (search-forward "\nsubject:" nil t)
+                 (funcall gnus-decode-encoded-word-function
+                          (nnheader-header-value))
+               "(none)"))
+           ;; From.
+           (progn
+             (goto-char p)
+             (if (search-forward "\nfrom:" nil t)
+                 (funcall gnus-decode-encoded-address-function
+                          (nnheader-header-value))
+               "(nobody)"))
+           ;; Date.
+           (progn
+             (goto-char p)
+             (if (search-forward "\ndate:" nil t)
+                 (nnheader-header-value) ""))
+           ;; Message-ID.
+           (progn
+             (goto-char p)
+             (setq id (if (re-search-forward
+                           "^message-id: *\\(<[^\n\t> ]+>\\)" nil t)
+                          ;; We do it this way to make sure the Message-ID
+                          ;; is (somewhat) syntactically valid.
+                          (buffer-substring (match-beginning 1)
+                                            (match-end 1))
+                        ;; If there was no message-id, we just fake one
+                        ;; to make subsequent routines simpler.
+                        (nnheader-generate-fake-message-id number))))
+           ;; References.
+           (progn
+             (goto-char p)
+             (if (search-forward "\nreferences:" nil t)
+                 (progn
+                   (setq end (point))
+                   (prog1
+                       (nnheader-header-value)
+                     (setq ref
+                           (buffer-substring
+                            (progn
+                              (end-of-line)
+                              (search-backward ">" end t)
+                              (1+ (point)))
+                            (progn
+                              (search-backward "<" end t)
+                              (point))))))
+               ;; 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)
+                        (setq in-reply-to (nnheader-header-value))
+                        (string-match "<[^>]+>" in-reply-to))
+                   (let (ref2)
+                     (setq ref (substring in-reply-to (match-beginning 0)
+                                          (match-end 0)))
+                     (while (string-match "<[^>]+>" in-reply-to (match-end 0))
+                       (setq ref2 (substring in-reply-to (match-beginning 0)
+                                             (match-end 0)))
+                       (when (> (length ref2) (length ref))
+                         (setq ref ref2)))
+                     ref)
+                 (setq ref nil))))
+           ;; Chars.
+           (progn
+             (goto-char p)
+             (if (search-forward "\nchars: " nil t)
+                 (if (numberp (setq chars (ignore-errors (read cur))))
+                     chars -1)
+               -1))
+           ;; Lines.
+           (progn
+             (goto-char p)
+             (if (search-forward "\nlines: " nil t)
+                 (if (numberp (setq lines (ignore-errors (read cur))))
+                     lines -1)
+               -1))
+           ;; Xref.
+           (progn
+             (goto-char p)
+             (and (search-forward "\nxref:" nil t)
+                  (nnheader-header-value)))
+           ;; Extra.
+           (when gnus-extra-headers
+             (let ((extra gnus-extra-headers)
+                   out)
+               (while extra
+                 (goto-char p)
+                 (when (search-forward
+                        (concat "\n" (symbol-name (car extra)) ":") nil t)
+                   (push (cons (car extra) (nnheader-header-value))
+                         out))
+                 (pop extra))
+               out))))
+         (when (equal id ref)
+           (setq ref nil))
+
+         (when gnus-alter-header-function
+           (funcall gnus-alter-header-function header)
+           (setq id (mail-header-id header)
+                 ref (gnus-parent-id (mail-header-references header))))
+
+         (when (setq header
+                     (gnus-dependencies-add-header
+                      header dependencies force-new))
+           (push header headers))
+         (goto-char (point-max))
+         (widen))
+       (nreverse headers)))))
+
+;; Goes through the xover lines and returns a list of vectors
+(defun gnus-get-newsgroup-headers-xover (sequence &optional
+                                                 force-new dependencies
+                                                 group also-fetch-heads)
+  "Parse the news overview data in the server buffer.
+Return a list of headers that match SEQUENCE (see
+`nntp-retrieve-headers')."
+  ;; Get the Xref when the users reads the articles since most/some
+  ;; NNTP servers do not include Xrefs when using XOVER.
+  (setq gnus-article-internal-prepare-hook '(gnus-article-get-xrefs))
+  (let ((mail-parse-charset gnus-newsgroup-charset)
+       (mail-parse-ignored-charsets gnus-newsgroup-ignored-charsets)
+       (cur nntp-server-buffer)
+       (dependencies (or dependencies gnus-newsgroup-dependencies))
+       (allp (cond
+              ((eq gnus-read-all-available-headers t)
+               t)
+              ((and (stringp gnus-read-all-available-headers)
+                    group)
+               (string-match gnus-read-all-available-headers group))
+              (t
+               nil)))
+       number headers header)
+    (with-current-buffer nntp-server-buffer
+      (subst-char-in-region (point-min) (point-max) ?\r ?  t)
+      ;; Allow the user to mangle the headers before parsing them.
+      (gnus-run-hooks 'gnus-parse-headers-hook)
+      (goto-char (point-min))
+      (gnus-parse-without-error
+       (while (and (or sequence allp)
+                   (not (eobp)))
+         (setq number (read cur))
+         (when (not allp)
+           (while (and sequence
+                       (< (car sequence) number))
+             (setq sequence (cdr sequence))))
+         (when (and (or allp
+                        (and sequence
+                             (eq number (car sequence))))
+                    (progn
+                      (setq sequence (cdr sequence))
+                      (setq header (inline
+                                     (gnus-nov-parse-line
+                                      number dependencies force-new)))))
+           (push header headers))
+         (forward-line 1)))
+      ;; A common bug in inn is that if you have posted an article and
+      ;; then retrieves the active file, it will answer correctly --
+      ;; the new article is included.  However, a NOV entry for the
+      ;; article may not have been generated yet, so this may fail.
+      ;; We work around this problem by retrieving the last few
+      ;; headers using HEAD.
+      (if (or (not also-fetch-heads)
+             (not sequence))
+         ;; We (probably) got all the headers.
+         (nreverse headers)
+       (let ((gnus-nov-is-evil t))
+         (nconc
+          (nreverse headers)
+          (when (eq (gnus-retrieve-headers sequence group) 'headers)
+            (gnus-get-newsgroup-headers))))))))
+
+(defun gnus-article-get-xrefs ()
+  "Fill in the Xref value in `gnus-current-headers', if necessary.
+This is meant to be called in `gnus-article-internal-prepare-hook'."
+  (let ((headers (with-current-buffer gnus-summary-buffer
+                  gnus-current-headers)))
+    (or (not gnus-use-cross-reference)
+       (not headers)
+       (and (mail-header-xref headers)
+            (not (string= (mail-header-xref headers) "")))
+       (let ((case-fold-search t)
+             xref)
+         (save-restriction
+           (nnheader-narrow-to-headers)
+           (goto-char (point-min))
+           (when (or (and (not (eobp))
+                          (eq (downcase (char-after)) ?x)
+                          (looking-at "Xref:"))
+                     (search-forward "\nXref:" nil t))
+             (goto-char (1+ (match-end 0)))
+             (setq xref (buffer-substring (point) (point-at-eol)))
+             (mail-header-set-xref headers xref)))))))
+
+(defun gnus-summary-insert-subject (id &optional old-header use-old-header)
+  "Find article ID and insert the summary line for that article.
+OLD-HEADER can either be a header or a line number to insert
+the subject line on.
+If USE-OLD-HEADER is non-nil, then OLD-HEADER should be a header,
+and OLD-HEADER will be used when the summary line is inserted,
+too, instead of trying to fetch new headers."
+  (let* ((line (and (numberp old-header) old-header))
+        (old-header (and (vectorp old-header) old-header))
+        (header (cond ((and old-header use-old-header)
+                       old-header)
+                      ((and (numberp id)
+                            (gnus-number-to-header id))
+                       (gnus-number-to-header id))
+                      (t
+                       (gnus-read-header id))))
+        (number (and (numberp id) id))
+        d)
+    (when header
+      ;; Rebuild the thread that this article is part of and go to the
+      ;; article we have fetched.
+      (when (and (not gnus-show-threads)
+                old-header)
+       (when (and number
+                  (setq d (gnus-data-find (mail-header-number old-header))))
+         (goto-char (gnus-data-pos d))
+         (gnus-data-remove
+          number
+          (- (point-at-bol)
+             (prog1
+                 (1+ (point-at-eol))
+               (gnus-delete-line))))))
+      ;; Remove list identifiers from subject.
+      (let ((gnus-newsgroup-headers (list header)))
+        (gnus-summary-remove-list-identifiers))
+      (when old-header
+       (mail-header-set-number header (mail-header-number old-header)))
+      (setq gnus-newsgroup-sparse
+           (delq (setq number (mail-header-number header))
+                 gnus-newsgroup-sparse))
+      (setq gnus-newsgroup-ancient (delq number gnus-newsgroup-ancient))
+      (push number gnus-newsgroup-limit)
+      (gnus-rebuild-thread (mail-header-id header) line)
+      (gnus-summary-goto-subject number nil t))
+    (when (and (numberp number)
+              (> number 0))
+      ;; We have to update the boundaries even if we can't fetch the
+      ;; article if ID is a number -- so that the next `P' or `N'
+      ;; command will fetch the previous (or next) article even
+      ;; if the one we tried to fetch this time has been canceled.
+      (unless (and gnus-newsgroup-end (< number gnus-newsgroup-end))
+       (setq gnus-newsgroup-end number))
+      (unless (and gnus-newsgroup-begin (> number gnus-newsgroup-begin))
+       (setq gnus-newsgroup-begin number))
+      (setq gnus-newsgroup-unselected
+           (delq number gnus-newsgroup-unselected)))
+    ;; Report back a success?
+    (and header (mail-header-number header))))
+
+;;; Process/prefix in the summary buffer
+
+(defun gnus-summary-work-articles (n)
+  "Return a list of articles to be worked upon.
+The prefix argument, the list of process marked articles, and the
+current article will be taken into consideration."
+  (with-current-buffer gnus-summary-buffer
+    (cond
+     (n
+      ;; A numerical prefix has been given.
+      (setq n (prefix-numeric-value n))
+      (let ((backward (< n 0))
+           (n (abs (prefix-numeric-value n)))
+           articles article)
+       (save-excursion
+         (while
+             (and (> n 0)
+                  (push (setq article (gnus-summary-article-number))
+                        articles)
+                  (if backward
+                      (gnus-summary-find-prev nil article)
+                    (gnus-summary-find-next nil article)))
+           (decf n)))
+       (nreverse articles)))
+     ((and (gnus-region-active-p) (mark))
+      (message "region active")
+      ;; Work on the region between point and mark.
+      (let ((max (max (point) (mark)))
+           articles article)
+       (save-excursion
+         (goto-char (min (point) (mark)))
+         (while
+             (and
+              (push (setq article (gnus-summary-article-number)) articles)
+              (gnus-summary-find-next nil article)
+              (< (point) max)))
+         (nreverse articles))))
+     (gnus-newsgroup-processable
+      ;; There are process-marked articles present.
+      ;; Save current state.
+      (gnus-summary-save-process-mark)
+      ;; Return the list.
+      (reverse gnus-newsgroup-processable))
+     (t
+      ;; Just return the current article.
+      (list (gnus-summary-article-number))))))
+
+(defmacro gnus-summary-iterate (arg &rest forms)
+  "Iterate over the process/prefixed articles and do FORMS.
+ARG is the interactive prefix given to the command.  FORMS will be
+executed with point over the summary line of the articles."
+  (let ((articles (make-symbol "gnus-summary-iterate-articles")))
+    `(let ((,articles (gnus-summary-work-articles ,arg)))
+       (while ,articles
+        (gnus-summary-goto-subject (car ,articles))
+        ,@forms
+        (pop ,articles)))))
+
+(put 'gnus-summary-iterate 'lisp-indent-function 1)
+(put 'gnus-summary-iterate 'edebug-form-spec '(form body))
+
+(defun gnus-summary-save-process-mark ()
+  "Push the current set of process marked articles on the stack."
+  (interactive)
+  (push (copy-sequence gnus-newsgroup-processable)
+       gnus-newsgroup-process-stack))
+
+(defun gnus-summary-kill-process-mark ()
+  "Push the current set of process marked articles on the stack and unmark."
+  (interactive)
+  (gnus-summary-save-process-mark)
+  (gnus-summary-unmark-all-processable))
+
+(defun gnus-summary-yank-process-mark ()
+  "Pop the last process mark state off the stack and restore it."
+  (interactive)
+  (unless gnus-newsgroup-process-stack
+    (error "Empty mark stack"))
+  (gnus-summary-process-mark-set (pop gnus-newsgroup-process-stack)))
+
+(defun gnus-summary-process-mark-set (set)
+  "Make SET into the current process marked articles."
+  (gnus-summary-unmark-all-processable)
+  (mapc 'gnus-summary-set-process-mark set))
+
+;;; Searching and stuff
+
+(defun gnus-summary-search-group (&optional backward use-level)
+  "Search for next unread newsgroup.
+If optional argument BACKWARD is non-nil, search backward instead."
+  (with-current-buffer gnus-group-buffer
+    (when (gnus-group-search-forward
+          backward nil (if use-level (gnus-group-group-level) nil))
+      (gnus-group-group-name))))
+
+(defun gnus-summary-best-group (&optional exclude-group)
+  "Find the name of the best unread group.
+If EXCLUDE-GROUP, do not go to this group."
+  (with-current-buffer gnus-group-buffer
+    (save-excursion
+      (gnus-group-best-unread-group exclude-group))))
+
+(defun gnus-summary-find-next (&optional unread article backward)
+  (if backward
+      (gnus-summary-find-prev unread article)
+    (let* ((dummy (gnus-summary-article-intangible-p))
+          (article (or article (gnus-summary-article-number)))
+          (data (gnus-data-find-list article))
+          result)
+      (when (and (not dummy)
+                (or (not gnus-summary-check-current)
+                    (not unread)
+                    (not (gnus-data-unread-p (car data)))))
+       (setq data (cdr data)))
+      (when (setq result
+                 (if unread
+                     (progn
+                       (while data
+                          (unless (memq (gnus-data-number (car data))
+                                        (cond
+                                        ((eq gnus-auto-goto-ignores
+                                             'always-undownloaded)
+                                         gnus-newsgroup-undownloaded)
+                                        (gnus-plugged
+                                         nil)
+                                        ((eq gnus-auto-goto-ignores
+                                             'unfetched)
+                                         gnus-newsgroup-unfetched)
+                                        ((eq gnus-auto-goto-ignores
+                                             'undownloaded)
+                                         gnus-newsgroup-undownloaded)))
+                            (when (gnus-data-unread-p (car data))
+                              (setq result (car data)
+                                    data nil)))
+                         (setq data (cdr data)))
+                       result)
+                   (car data)))
+       (goto-char (gnus-data-pos result))
+       (gnus-data-number result)))))
+
+(defun gnus-summary-find-prev (&optional unread article)
+  (let* ((eobp (eobp))
+        (article (or article (gnus-summary-article-number)))
+        (data (gnus-data-find-list article (gnus-data-list 'rev)))
+        result)
+    (when (and (not eobp)
+              (or (not gnus-summary-check-current)
+                  (not unread)
+                  (not (gnus-data-unread-p (car data)))))
+      (setq data (cdr data)))
+    (when (setq result
+               (if unread
+                   (progn
+                     (while data
+                        (unless (memq (gnus-data-number (car data))
+                                      (cond
+                                      ((eq gnus-auto-goto-ignores
+                                           'always-undownloaded)
+                                       gnus-newsgroup-undownloaded)
+                                      (gnus-plugged
+                                       nil)
+                                      ((eq gnus-auto-goto-ignores
+                                           'unfetched)
+                                       gnus-newsgroup-unfetched)
+                                      ((eq gnus-auto-goto-ignores
+                                           'undownloaded)
+                                       gnus-newsgroup-undownloaded)))
+                          (when (gnus-data-unread-p (car data))
+                            (setq result (car data)
+                                  data nil)))
+                       (setq data (cdr data)))
+                     result)
+                 (car data)))
+      (goto-char (gnus-data-pos result))
+      (gnus-data-number result))))
+
+(defun gnus-summary-find-subject (subject &optional unread backward article)
+  (let* ((simp-subject (gnus-simplify-subject-fully subject))
+        (article (or article (gnus-summary-article-number)))
+        (articles (gnus-data-list backward))
+        (arts (gnus-data-find-list article articles))
+        result)
+    (when (or (not gnus-summary-check-current)
+             (not unread)
+             (not (gnus-data-unread-p (car arts))))
+      (setq arts (cdr arts)))
+    (while arts
+      (and (or (not unread)
+              (gnus-data-unread-p (car arts)))
+          (vectorp (gnus-data-header (car arts)))
+          (gnus-subject-equal
+           simp-subject (mail-header-subject (gnus-data-header (car arts))) t)
+          (setq result (car arts)
+                arts nil))
+      (setq arts (cdr arts)))
+    (and result
+        (goto-char (gnus-data-pos result))
+        (gnus-data-number result))))
+
+(defun gnus-summary-search-forward (&optional unread subject backward)
+  "Search forward for an article.
+If UNREAD, look for unread articles.  If SUBJECT, look for
+articles with that subject.  If BACKWARD, search backward instead."
+  (cond (subject (gnus-summary-find-subject subject unread backward))
+       (backward (gnus-summary-find-prev unread))
+       (t (gnus-summary-find-next unread))))
+
+(defun gnus-recenter (&optional n)
+  "Center point in window and redisplay frame.
+Also do horizontal recentering."
+  (interactive "P")
+  (when (and gnus-auto-center-summary
+            (not (eq gnus-auto-center-summary 'vertical)))
+    (gnus-horizontal-recenter))
+  (if (fboundp 'recenter-top-bottom)
+      (recenter-top-bottom n)
+    (recenter n)))
+
+(put 'gnus-recenter 'isearch-scroll t)
+
+(defun gnus-forward-line-ignore-invisible (n)
+  "Move N lines forward (backward if N is negative).
+Like forward-line, but skip over (and don't count) invisible lines."
+  (let (done)
+    (while (and (> n 0) (not done))
+      ;; If the following character is currently invisible,
+      ;; skip all characters with that same `invisible' property value.
+      (while (gnus-invisible-p (point))
+       (goto-char (gnus-next-char-property-change (point))))
+      (forward-line 1)
+      (if (eobp)
+         (setq done t)
+       (setq n (1- n))))
+    (while (and (< n 0) (not done))
+      (forward-line -1)
+      (if (bobp) (setq done t)
+       (setq n (1+ n))
+       (while (and (not (bobp)) (gnus-invisible-p (1- (point))))
+         (goto-char (gnus-previous-char-property-change (point))))))))
+
+(defun gnus-summary-recenter ()
+  "Center point in the summary window.
+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.
+  (interactive)
+  ;; The user has to want it.
+  (when gnus-auto-center-summary
+    (let* ((top (cond ((< (window-height) 4) 0)
+                     ((< (window-height) 7) 1)
+                     (t (if (numberp gnus-auto-center-summary)
+                            gnus-auto-center-summary
+                           (/ (1- (window-height)) 2)))))
+          (height (1- (window-height)))
+          (bottom (save-excursion
+                    (goto-char (point-max))
+                    (gnus-forward-line-ignore-invisible (- height))
+                    (point)))
+          (window (get-buffer-window (current-buffer))))
+      (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
+       ;; possible valid number, or the second line from the top,
+       ;; whichever is the least.
+       (let ((top-pos (save-excursion
+                        (gnus-forward-line-ignore-invisible (- top))
+                        (point))))
+         (if (> bottom top-pos)
+             ;; Keep the second line from the top visible
+             (set-window-start window top-pos)
+           ;; Try to keep the bottom line visible; if it's partially
+           ;; obscured, either scroll one more line to make it fully
+           ;; visible, or revert to using TOP-POS.
+           (save-excursion
+             (goto-char (point-max))
+             (gnus-forward-line-ignore-invisible -1)
+             (let ((last-line-start (point)))
+               (goto-char bottom)
+               (set-window-start window (point) t)
+               (when (not (pos-visible-in-window-p last-line-start window))
+                 (gnus-forward-line-ignore-invisible 1)
+                 (set-window-start window (min (point) top-pos) t)))))))
+      ;; Do horizontal recentering while we're at it.
+      (when (and (get-buffer-window (current-buffer) t)
+                (not (eq gnus-auto-center-summary 'vertical)))
+       (let ((selected (selected-window)))
+         (select-window (get-buffer-window (current-buffer) t))
+         (gnus-summary-position-point)
+         (gnus-horizontal-recenter)
+         (select-window selected))))))
+
+(defun gnus-summary-jump-to-group (newsgroup)
+  "Move point to NEWSGROUP in group mode buffer."
+  ;; Keep update point of group mode buffer if visible.
+  (if (eq (current-buffer) (get-buffer gnus-group-buffer))
+      (save-window-excursion
+       ;; Take care of tree window mode.
+       (when (get-buffer-window gnus-group-buffer)
+         (pop-to-buffer gnus-group-buffer))
+       (gnus-group-jump-to-group newsgroup))
+    (save-excursion
+      ;; Take care of tree window mode.
+      (if (get-buffer-window gnus-group-buffer 0)
+         (pop-to-buffer gnus-group-buffer)
+       (set-buffer gnus-group-buffer))
+      (gnus-group-jump-to-group newsgroup))))
+
+;; This function returns a list of article numbers based on the
+;; difference between the ranges of read articles in this group and
+;; the range of active articles.
+(defun gnus-list-of-unread-articles (group)
+  (let* ((read (gnus-info-read (gnus-get-info group)))
+        (active (or (gnus-active group) (gnus-activate-group group)))
+        (last (or (cdr active)
+                  (error "Group %s couldn't be activated " group)))
+        (bottom (if gnus-newsgroup-maximum-articles
+                    (max (car active)
+                         (- last gnus-newsgroup-maximum-articles -1))
+                  (car active)))
+        first nlast unread)
+    ;; If none are read, then all are unread.
+    (if (not read)
+       (setq first bottom)
+      ;; If the range of read articles is a single range, then the
+      ;; first unread article is the article after the last read
+      ;; article.  Sounds logical, doesn't it?
+      (if (and (not (listp (cdr read)))
+              (or (< (car read) bottom)
+                  (progn (setq read (list read))
+                         nil)))
+         (setq first (max bottom (1+ (cdr read))))
+       ;; `read' is a list of ranges.
+       (when (/= (setq nlast (or (and (numberp (car read)) (car read))
+                                 (caar read)))
+                 1)
+         (setq first bottom))
+       (while read
+         (when first
+           (while (< first nlast)
+             (setq unread (cons first unread)
+                    first (1+ first))))
+         (setq first (1+ (if (atom (car read)) (car read) (cdar read))))
+         (setq nlast (if (atom (cadr read)) (cadr read) (caadr read)))
+         (setq read (cdr read)))))
+    ;; And add the last unread articles.
+    (while (<= first last)
+      (setq unread (cons first unread)
+            first (1+ first)))
+    ;; Return the list of unread articles.
+    (delq 0 (nreverse unread))))
+
+(defun gnus-list-of-read-articles (group)
+  "Return a list of unread, unticked and non-dormant articles."
+  (let* ((info (gnus-get-info group))
+        (marked (gnus-info-marks info))
+        (active (gnus-active group)))
+    (and info active
+        (gnus-list-range-difference
+         (gnus-list-range-difference
+          (gnus-sorted-complement
+           (gnus-uncompress-range
+            (if gnus-newsgroup-maximum-articles
+                (cons (max (car active)
+                           (- (cdr active)
+                              gnus-newsgroup-maximum-articles
+                              -1))
+                      (cdr active))
+              active))
+           (gnus-list-of-unread-articles group))
+          (cdr (assq 'dormant marked)))
+         (cdr (assq 'tick marked))))))
+
+;; This function returns a sequence of article numbers based on the
+;; difference between the ranges of read articles in this group and
+;; the range of active articles.
+(defun gnus-sequence-of-unread-articles (group)
+  (let* ((read (gnus-info-read (gnus-get-info group)))
+        (active (or (gnus-active group) (gnus-activate-group group)))
+        (last (cdr active))
+        (bottom (if gnus-newsgroup-maximum-articles
+                    (max (car active)
+                         (- last gnus-newsgroup-maximum-articles -1))
+                  (car active)))
+        first nlast unread)
+    ;; If none are read, then all are unread.
+    (if (not read)
+       (setq first bottom)
+      ;; If the range of read articles is a single range, then the
+      ;; first unread article is the article after the last read
+      ;; article.  Sounds logical, doesn't it?
+      (if (and (not (listp (cdr read)))
+              (or (< (car read) bottom)
+                  (progn (setq read (list read))
+                         nil)))
+         (setq first (max bottom (1+ (cdr read))))
+       ;; `read' is a list of ranges.
+       (when (/= (setq nlast (or (and (numberp (car read)) (car read))
+                                 (caar read)))
+                 1)
+         (setq first bottom))
+       (while read
+         (when first
+            (push (cons first nlast) unread))
+         (setq first (1+ (if (atom (car read)) (car read) (cdar read))))
+         (setq nlast (if (atom (cadr read)) (cadr read) (caadr read)))
+         (setq read (cdr read)))))
+    ;; And add the last unread articles.
+    (cond ((not (and first last))
+          nil)
+         ((< first last)
+          (push (cons first last) unread))
+         ((= first last)
+          (push first unread)))
+    ;; Return the sequence of unread articles.
+    (delq 0 (nreverse unread))))
+
+;; Various summary commands
+
+(defun gnus-summary-select-article-buffer ()
+  "Reconfigure windows to show the article buffer.
+If `gnus-widen-article-window' is set, show only the article
+buffer."
+  (interactive)
+  (if (not (gnus-buffer-live-p gnus-article-buffer))
+      (error "There is no article buffer for this summary buffer")
+    (unless (get-buffer-window gnus-article-buffer)
+      (gnus-summary-show-article))
+    (gnus-configure-windows
+     (if gnus-widen-article-window
+        'only-article
+       'article)
+     t)
+    (select-window (get-buffer-window gnus-article-buffer))))
+
+(defun gnus-summary-universal-argument (arg)
+  "Perform any operation on all articles that are process/prefixed."
+  (interactive "P")
+  (let ((articles (gnus-summary-work-articles arg))
+       func article)
+    (if (eq
+        (setq
+         func
+         (key-binding
+          (read-key-sequence
+           (substitute-command-keys
+            "\\<gnus-summary-mode-map>\\[gnus-summary-universal-argument]"))))
+        'undefined)
+       (gnus-error 1 "Undefined key")
+      (save-excursion
+       (while articles
+         (gnus-summary-goto-subject (setq article (pop articles)))
+         (let (gnus-newsgroup-processable)
+           (command-execute func))
+         (gnus-summary-remove-process-mark article)))))
+  (gnus-summary-position-point))
+
+(defun gnus-summary-toggle-truncation (&optional arg)
+  "Toggle truncation of summary lines.
+With ARG, turn line truncation on if ARG is positive."
+  (interactive "P")
+  (setq truncate-lines
+       (if (null arg) (not truncate-lines)
+         (> (prefix-numeric-value arg) 0)))
+  (redraw-display))
+
+(defun gnus-summary-find-for-reselect ()
+  "Return the number of an article to stay on across a reselect.
+The current article is considered, then following articles, then previous
+articles.  An article is sought which is not canceled and isn't a temporary
+insertion from another group.  If there's no such then return a dummy 0."
+  (let (found)
+    (dolist (rev '(nil t))
+      (unless found      ; don't demand the reverse list if we don't need it
+        (let ((data (gnus-data-find-list
+                     (gnus-summary-article-number) (gnus-data-list rev))))
+          (while (and data (not found))
+            (if (and (< 0 (gnus-data-number (car data)))
+                     (not (eq gnus-canceled-mark (gnus-data-mark (car data)))))
+                (setq found (gnus-data-number (car data))))
+            (setq data (cdr data))))))
+    (or found 0)))
+
+(defun gnus-summary-reselect-current-group (&optional all rescan)
+  "Exit and then reselect the current newsgroup.
+The prefix argument ALL means to select all articles."
+  (interactive "P")
+  (when (gnus-ephemeral-group-p gnus-newsgroup-name)
+    (error "Ephemeral groups can't be reselected"))
+  (let ((current-subject (gnus-summary-find-for-reselect))
+       (group gnus-newsgroup-name))
+    (setq gnus-newsgroup-begin nil)
+    (gnus-summary-exit nil 'leave-hidden)
+    ;; We have to adjust the point of group mode buffer because
+    ;; point was moved to the next unread newsgroup by exiting.
+    (gnus-summary-jump-to-group group)
+    (when rescan
+      (save-excursion
+       (gnus-group-get-new-news-this-group 1)))
+    (gnus-group-read-group all t)
+    (gnus-summary-goto-subject current-subject nil t)))
+
+(defun gnus-summary-rescan-group (&optional all)
+  "Exit the newsgroup, ask for new articles, and select the newsgroup."
+  (interactive "P")
+  (let ((config gnus-current-window-configuration))
+    (gnus-summary-reselect-current-group all t)
+    (gnus-configure-windows config)
+    (when (eq config 'article)
+      (gnus-summary-select-article))))
+
+(defun gnus-summary-update-info (&optional non-destructive)
+  (save-excursion
+    (let ((group gnus-newsgroup-name))
+      (when group
+       (when gnus-newsgroup-kill-headers
+         (setq gnus-newsgroup-killed
+               (gnus-compress-sequence
+                (gnus-sorted-union
+                 (gnus-list-range-intersection
+                  gnus-newsgroup-unselected gnus-newsgroup-killed)
+                 gnus-newsgroup-unreads)
+                t)))
+       (unless (listp (cdr gnus-newsgroup-killed))
+         (setq gnus-newsgroup-killed (list gnus-newsgroup-killed)))
+       (let ((headers gnus-newsgroup-headers)
+             (ephemeral-p (gnus-ephemeral-group-p group))
+             info)
+         (unless ephemeral-p
+           (setq info (copy-sequence (gnus-get-info group))
+                 info (delq (gnus-info-params info) info)))
+         ;; Set the new ranges of read articles.
+         (with-current-buffer gnus-group-buffer
+           (gnus-undo-force-boundary))
+         (gnus-update-read-articles
+          group (gnus-sorted-union
+                 gnus-newsgroup-unreads gnus-newsgroup-unselected))
+         ;; Set the current article marks.
+         (let ((gnus-newsgroup-scored
+                (if (and (not gnus-save-score)
+                         (not non-destructive))
+                    nil
+                  gnus-newsgroup-scored)))
+           (save-excursion
+             (gnus-update-marks)))
+         ;; Do the cross-ref thing.
+         (when gnus-use-cross-reference
+           (gnus-mark-xrefs-as-read group headers gnus-newsgroup-unreads))
+         ;; Do not switch windows but change the buffer to work.
+         (set-buffer gnus-group-buffer)
+         (unless ephemeral-p
+           (gnus-group-update-group
+            group nil
+            (equal info
+                   (setq info (copy-sequence (gnus-get-info group))
+                         info (delq (gnus-info-params info) info))))))))))
+
+(defun gnus-summary-save-newsrc (&optional force)
+  "Save the current number of read/marked articles in the dribble buffer.
+The dribble buffer will then be saved.
+If FORCE (the prefix), also save the .newsrc file(s)."
+  (interactive "P")
+  (gnus-summary-update-info t)
+  (if force
+      (gnus-save-newsrc-file)
+    (gnus-dribble-save)))
+
+(declare-function gnus-cache-write-active "gnus-cache" (&optional force))
+(declare-function gnus-article-stop-animations "gnus-art" ())
+
+(defun gnus-summary-exit (&optional temporary leave-hidden)
+  "Exit reading current newsgroup, and then return to group selection mode.
+`gnus-exit-group-hook' is called with no arguments if that value is non-nil."
+  (interactive)
+  (gnus-set-global-variables)
+  (when (gnus-buffer-live-p gnus-article-buffer)
+    (with-current-buffer gnus-article-buffer
+      (mm-destroy-parts gnus-article-mime-handles)
+      ;; Set it to nil for safety reason.
+      (setq gnus-article-mime-handle-alist nil)
+      (setq gnus-article-mime-handles nil)))
+  (gnus-kill-save-kill-buffer)
+  (gnus-async-halt-prefetch)
+  (let* ((group gnus-newsgroup-name)
+        (quit-config (gnus-group-quit-config gnus-newsgroup-name))
+        (gnus-group-is-exiting-p t)
+        (article-buffer gnus-article-buffer)
+        (original-article-buffer gnus-original-article-buffer)
+        (mode major-mode)
+        (group-point nil)
+        (buf (current-buffer))
+        ;; `gnus-single-article-buffer' is nil buffer-locally in
+        ;; ephemeral group of which summary buffer will be killed,
+        ;; but the global value may be non-nil.
+        (single-article-buffer gnus-single-article-buffer))
+    (unless quit-config
+      ;; Do adaptive scoring, and possibly save score files.
+      (when gnus-newsgroup-adaptive
+       (gnus-score-adaptive))
+      (when gnus-use-scoring
+       (gnus-score-save)))
+    (gnus-run-hooks 'gnus-summary-prepare-exit-hook)
+    (when gnus-use-cache
+      (gnus-cache-possibly-remove-articles)
+      (gnus-cache-save-buffers))
+    (gnus-async-prefetch-remove-group group)
+    (when gnus-suppress-duplicates
+      (gnus-dup-enter-articles))
+    (when gnus-use-trees
+      (gnus-tree-close))
+    (when gnus-use-cache
+      (gnus-cache-write-active))
+    ;; Remove entries for this group.
+    (nnmail-purge-split-history (gnus-group-real-name group))
+    ;; Make all changes in this group permanent.
+    (unless quit-config
+      (gnus-run-hooks 'gnus-exit-group-hook)
+      (gnus-summary-update-info))
+    (gnus-close-group group)
+    ;; Make sure where we were, and go to next newsgroup.
+    (when (buffer-live-p (get-buffer gnus-group-buffer))
+      (set-buffer gnus-group-buffer))
+    (unless quit-config
+      (gnus-group-jump-to-group group))
+    (gnus-run-hooks 'gnus-summary-exit-hook)
+    (unless (or quit-config
+               (not gnus-summary-next-group-on-exit)
+               ;; If this group has disappeared from the summary
+               ;; buffer, don't skip forwards.
+               (not (string= group (gnus-group-group-name))))
+      (gnus-group-next-unread-group 1))
+    (setq group-point (point))
+    (gnus-article-stop-animations)
+    (if temporary
+       nil                             ;Nothing to do.
+      (set-buffer buf)
+      (if (not gnus-kill-summary-on-exit)
+         (progn
+           (gnus-deaden-summary)
+           (setq mode nil))
+       (when (get-buffer gnus-article-buffer)
+         (bury-buffer gnus-article-buffer))
+       ;; Return to group mode buffer.
+       (when (eq mode 'gnus-summary-mode)
+         (gnus-kill-buffer buf)))
+
+      (setq gnus-current-select-method gnus-select-method)
+      (when (gnus-buffer-live-p gnus-group-buffer)
+       (set-buffer gnus-group-buffer))
+      (if quit-config
+         (gnus-handle-ephemeral-exit quit-config)
+       (goto-char group-point)
+       ;; If gnus-group-buffer is already displayed, make sure we also move
+       ;; the cursor in the window that displays it.
+       (let ((win (get-buffer-window (current-buffer) 0)))
+         (if win (set-window-point win (point))))
+       (unless leave-hidden
+         (gnus-configure-windows 'group 'force)))
+
+      ;; If we have several article buffers, we kill them at exit.
+      (unless single-article-buffer
+       (when (gnus-buffer-live-p article-buffer)
+         (with-current-buffer article-buffer
+           ;; Don't kill sticky article buffers
+           (unless (eq major-mode 'gnus-sticky-article-mode)
+             (gnus-kill-buffer article-buffer)
+             (setq gnus-article-current nil))))
+       (gnus-kill-buffer original-article-buffer))
+
+      ;; Clear the current group name.
+      (unless quit-config
+       (setq gnus-newsgroup-name nil)))))
+
+(declare-function gnus-stop-downloads "gnus-art" ())
+
+(defalias 'gnus-summary-quit 'gnus-summary-exit-no-update)
+(defun gnus-summary-exit-no-update (&optional no-questions)
+  "Quit reading current newsgroup without updating read article info."
+  (interactive)
+  (let* ((group gnus-newsgroup-name)
+        (gnus-group-is-exiting-p t)
+        (gnus-group-is-exiting-without-update-p t)
+        (quit-config (gnus-group-quit-config group)))
+    (when (or no-questions
+             (gnus-ephemeral-group-p group)
+             gnus-expert-user
+             (gnus-y-or-n-p "Discard changes to this group and exit? "))
+      (gnus-async-halt-prefetch)
+      (run-hooks 'gnus-summary-prepare-exit-hook)
+      (when (gnus-buffer-live-p gnus-article-buffer)
+       (with-current-buffer gnus-article-buffer
+         (gnus-article-stop-animations)
+         (gnus-stop-downloads)
+         (mm-destroy-parts gnus-article-mime-handles)
+         ;; Set it to nil for safety reason.
+         (setq gnus-article-mime-handle-alist nil)
+         (setq gnus-article-mime-handles nil)))
+      ;; If we have several article buffers, we kill them at exit.
+      (unless gnus-single-article-buffer
+       (gnus-kill-buffer gnus-article-buffer)
+       (gnus-kill-buffer gnus-original-article-buffer)
+       (setq gnus-article-current nil))
+      ;; Return to the group buffer.
+      (if (not gnus-kill-summary-on-exit)
+         (progn
+           (gnus-deaden-summary)
+           (gnus-configure-windows 'group 'force))
+       (gnus-configure-windows 'group 'force)
+       (gnus-close-group group)
+       (gnus-kill-buffer gnus-summary-buffer))
+      (unless gnus-single-article-buffer
+       (setq gnus-article-current nil))
+      (when gnus-use-trees
+       (gnus-tree-close))
+      (gnus-async-prefetch-remove-group group)
+      (when (get-buffer gnus-article-buffer)
+       (bury-buffer gnus-article-buffer))
+      ;; Clear the current group name.
+      (setq gnus-newsgroup-name nil)
+      (unless (gnus-ephemeral-group-p group)
+       (gnus-group-update-group group nil t))
+      (when (equal (gnus-group-group-name) group)
+       (gnus-group-next-unread-group 1))
+      (gnus-article-stop-animations)
+      (when quit-config
+       (gnus-handle-ephemeral-exit quit-config)))))
+
+(defun gnus-handle-ephemeral-exit (quit-config)
+  "Handle movement when leaving an ephemeral group.
+The state which existed when entering the ephemeral is reset."
+  (if (not (buffer-live-p (car quit-config)))
+      (when (gnus-buffer-live-p gnus-group-buffer)
+       (gnus-configure-windows 'group 'force))
+    (set-buffer (car quit-config))
+    (unless (eq (cdr quit-config) 'group)
+      (setq gnus-current-select-method
+           (gnus-find-method-for-group gnus-newsgroup-name)))
+    (cond ((derived-mode-p 'gnus-summary-mode)
+          (gnus-set-global-variables))
+         ((derived-mode-p 'gnus-article-mode)
+          (save-current-buffer
+            ;; 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))
+       (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 (derived-mode-p 'gnus-summary-mode)
+      (if (memq gnus-auto-select-on-ephemeral-exit '(next-noselect
+                                                    next-unread-noselect))
+         (when (zerop (cond ((eq gnus-auto-select-on-ephemeral-exit
+                                 'next-noselect)
+                             (gnus-summary-next-subject 1 nil t))
+                            ((eq gnus-auto-select-on-ephemeral-exit
+                                 'next-unread-noselect)
+                             (gnus-summary-next-subject 1 t t))))
+           ;; Hide the article buffer which displays the article different
+           ;; from the one that the cursor points to in the summary buffer.
+           (gnus-configure-windows 'summary 'force))
+       (cond ((eq gnus-auto-select-on-ephemeral-exit 'next)
+              (gnus-summary-next-subject 1))
+             ((eq gnus-auto-select-on-ephemeral-exit 'next-unread)
+              (gnus-summary-next-subject 1 t))))
+      (gnus-summary-recenter)
+      (gnus-summary-position-point))))
+
+;;; Dead summaries.
+
+(defvar gnus-dead-summary-mode-map
+  (let ((map (make-keymap)))
+    (suppress-keymap map)
+    (substitute-key-definition 'undefined 'gnus-summary-wake-up-the-dead map)
+    (dolist (key '("\C-d" "\r" "\177" [delete]))
+      (define-key map key 'gnus-summary-wake-up-the-dead))
+    (dolist (key '("q" "Q"))
+      (define-key map key 'bury-buffer))
+    map))
+
+(define-minor-mode gnus-dead-summary-mode
+  "Minor mode for Gnus summary buffers."
+  :lighter " Dead" :keymap gnus-dead-summary-mode-map
+  (unless (derived-mode-p 'gnus-summary-mode)
+    (setq gnus-dead-summary-mode nil)))
+
+(defun gnus-deaden-summary ()
+  "Make the current summary buffer into a dead summary buffer."
+  ;; Kill any previous dead summary buffer.
+  (when (and gnus-dead-summary
+            (buffer-name gnus-dead-summary))
+    (with-current-buffer gnus-dead-summary
+      (when gnus-dead-summary-mode
+       (kill-buffer (current-buffer)))))
+  ;; Make this the current dead summary.
+  (setq gnus-dead-summary (current-buffer))
+  (gnus-dead-summary-mode 1)
+  (let ((name (buffer-name)))
+    (when (string-match "Summary" name)
+      (rename-buffer
+       (concat (substring name 0 (match-beginning 0)) "Dead "
+              (substring name (match-beginning 0)))
+       t)
+      (bury-buffer))))
+
+(defun gnus-kill-or-deaden-summary (buffer)
+  "Kill or deaden the summary BUFFER."
+  (save-excursion
+    (when (and (buffer-name buffer)
+              (not gnus-single-article-buffer))
+      (with-current-buffer buffer
+       (gnus-kill-buffer gnus-article-buffer)
+       (gnus-kill-buffer gnus-original-article-buffer)))
+    (cond
+     ;; Kill the buffer.
+     (gnus-kill-summary-on-exit
+      (when (and gnus-use-trees
+                (gnus-buffer-exists-p buffer))
+       (with-current-buffer buffer
+         (gnus-tree-close)))
+      (gnus-kill-buffer buffer))
+     ;; Deaden the buffer.
+     ((gnus-buffer-exists-p buffer)
+      (with-current-buffer buffer
+       (gnus-deaden-summary))))))
+
+(defun gnus-summary-wake-up-the-dead (&rest args)
+  "Wake up the dead summary buffer."
+  (interactive)
+  (gnus-dead-summary-mode -1)
+  (let ((name (buffer-name)))
+    (when (string-match "Dead " name)
+      (rename-buffer
+       (concat (substring name 0 (match-beginning 0))
+              (substring name (match-end 0)))
+       t)))
+  (gnus-message 3 "This dead summary is now alive again"))
+
+;; Suggested by Per Abrahamsen <amanda@iesd.auc.dk>.
+(defun gnus-summary-describe-group (&optional force)
+  "Describe the current newsgroup."
+  (interactive "P")
+  (gnus-group-describe-group force gnus-newsgroup-name))
+
+(defun gnus-summary-describe-briefly ()
+  "Describe summary mode commands briefly."
+  (interactive)
+  (gnus-message 6 "%s" (substitute-command-keys "\\<gnus-summary-mode-map>\\[gnus-summary-next-page]:Select  \\[gnus-summary-next-unread-article]:Forward  \\[gnus-summary-prev-unread-article]:Backward  \\[gnus-summary-exit]:Exit  \\[gnus-info-find-node]:Run Info  \\[gnus-summary-describe-briefly]:This help")))
+
+;; Walking around group mode buffer from summary mode.
+
+(defun gnus-summary-next-group (&optional no-article target-group backward)
+  "Exit current newsgroup and then select next unread newsgroup.
+If prefix argument NO-ARTICLE is non-nil, no article is selected
+initially.  If TARGET-GROUP, go to this group.  If BACKWARD, go to
+previous group instead."
+  (interactive "P")
+  ;; Stop pre-fetching.
+  (gnus-async-halt-prefetch)
+  (let ((current-group gnus-newsgroup-name)
+       (current-buffer (current-buffer))
+       entered)
+    ;; 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...
+    (gnus-summary-exit t)
+    (while (not entered)
+      ;; Then we find what group we are supposed to enter.
+      (set-buffer gnus-group-buffer)
+      (gnus-group-jump-to-group current-group)
+      (setq target-group
+           (or target-group
+               (if (eq gnus-keep-same-level 'best)
+                   (gnus-summary-best-group gnus-newsgroup-name)
+                 (gnus-summary-search-group backward gnus-keep-same-level))))
+      (if (not target-group)
+         ;; There are no further groups, so we return to the group
+         ;; buffer.
+         (progn
+           (gnus-message 5 "Returning to the group buffer")
+           (setq entered t)
+           (when (gnus-buffer-live-p current-buffer)
+             (set-buffer current-buffer)
+             (gnus-summary-exit))
+           (gnus-run-hooks 'gnus-group-no-more-groups-hook))
+       ;; We try to enter the target group.
+       (gnus-group-jump-to-group target-group)
+       (let ((unreads (gnus-group-group-unread)))
+         (if (and (or (eq t unreads)
+                      (and unreads (not (zerop unreads))))
+                  (gnus-summary-read-group
+                   target-group nil no-article
+                   (and (buffer-name current-buffer) current-buffer)
+                   nil backward))
+             (setq entered t)
+           (setq current-group target-group
+                 target-group nil)))))))
+
+(defun gnus-summary-prev-group (&optional no-article)
+  "Exit current newsgroup and then select previous unread newsgroup.
+If prefix argument NO-ARTICLE is non-nil, no article is selected initially."
+  (interactive "P")
+  (gnus-summary-next-group no-article nil t))
+
+;; Walking around summary lines.
+
+(defun gnus-summary-first-subject (&optional unread undownloaded unseen)
+  "Go to the first subject satisfying any non-nil constraint.
+If UNREAD is non-nil, the article should be unread.
+If UNDOWNLOADED is non-nil, the article should be undownloaded.
+If UNSEEN is non-nil, the article should be unseen as well as unread.
+Returns the article selected or nil if there are no matching articles."
+  (interactive "P")
+  (cond
+   ;; Empty summary.
+   ((null gnus-newsgroup-data)
+    (gnus-message 3 "No articles in the group")
+    nil)
+   ;; Pick the first article.
+   ((not (or unread undownloaded unseen))
+    (goto-char (gnus-data-pos (car gnus-newsgroup-data)))
+    (gnus-data-number (car gnus-newsgroup-data)))
+   ;; Find the first unread article.
+   (t
+    (let ((data gnus-newsgroup-data))
+      (while (and data
+                  (let ((num (gnus-data-number (car data))))
+                    (or (memq num gnus-newsgroup-unfetched)
+                        (not (or (and unread
+                                      (memq num gnus-newsgroup-unreads))
+                                 (and undownloaded
+                                      (memq num gnus-newsgroup-undownloaded))
+                                 (and unseen
+                                      (memq num gnus-newsgroup-unseen)
+                                     (memq num gnus-newsgroup-unreads)))))))
+        (setq data (cdr data)))
+      (prog1
+          (if data
+              (progn
+                (goto-char (gnus-data-pos (car data)))
+                (gnus-data-number (car data)))
+            (gnus-message 3 "No more%s articles"
+                          (let* ((r (when unread " unread"))
+                                 (d (when undownloaded " undownloaded"))
+                                 (s (when unseen " unseen"))
+                                 (l (delq nil (list r d s))))
+                            (cond ((= 3 (length l))
+                                   (concat r "," d ", or" s))
+                                  ((= 2 (length l))
+                                   (concat (car l) ", or" (cadr l)))
+                                  ((= 1 (length l))
+                                   (car l))
+                                  (t
+                                   ""))))
+            nil
+            )
+        (gnus-summary-position-point))))))
+
+(defun gnus-summary-next-subject (n &optional unread dont-display)
+  "Go to next N'th summary line.
+If N is negative, go to the previous N'th subject line.
+If UNREAD is non-nil, only unread articles are selected.
+The difference between N and the actual number of steps taken is
+returned."
+  (interactive "p")
+  (let ((backward (< n 0))
+       (n (abs n)))
+    (while (and (> n 0)
+               (if backward
+                   (gnus-summary-find-prev unread)
+                 (gnus-summary-find-next unread)))
+      (unless (zerop (setq n (1- n)))
+       (gnus-summary-show-thread)))
+    (when (/= 0 n)
+      (gnus-message 7 "No more%s articles"
+                   (if unread " unread" "")))
+    (unless dont-display
+      (gnus-summary-recenter)
+      (gnus-summary-position-point))
+    n))
+
+(defun gnus-summary-next-unread-subject (n)
+  "Go to next N'th unread summary line."
+  (interactive "p")
+  (gnus-summary-next-subject n t))
+
+(defun gnus-summary-prev-subject (n &optional unread)
+  "Go to previous N'th summary line.
+If optional argument UNREAD is non-nil, only unread article is selected."
+  (interactive "p")
+  (gnus-summary-next-subject (- n) unread))
+
+(defun gnus-summary-prev-unread-subject (n)
+  "Go to previous N'th unread summary line."
+  (interactive "p")
+  (gnus-summary-next-subject (- n) t))
+
+(defun gnus-summary-goto-subjects (articles)
+  "Insert the subject header for ARTICLES in the current buffer."
+  (save-excursion
+    (dolist (article articles)
+      (gnus-summary-goto-subject article t)))
+  (gnus-summary-limit (append articles gnus-newsgroup-limit))
+  (gnus-summary-position-point))
+
+(defun gnus-summary-goto-subject (article &optional force silent)
+  "Go to the subject line of ARTICLE.
+If FORCE, also allow jumping to articles not currently shown."
+  (interactive "nArticle number: ")
+  (unless (numberp article)
+    (error "Article %s is not a number" article))
+  (let ((b (point))
+       (data (gnus-data-find article)))
+    ;; We read in the article if we have to.
+    (and (not data)
+        force
+        (gnus-summary-insert-subject
+         article
+         (if (or (numberp force) (vectorp force)) force)
+         t)
+        (setq data (gnus-data-find article)))
+    (goto-char b)
+    (if (not data)
+       (progn
+         (unless silent
+           (gnus-message 3 "Can't find article %d" article))
+         nil)
+      (let ((pt (gnus-data-pos data)))
+       (goto-char pt)
+       (gnus-summary-set-article-display-arrow pt))
+      (gnus-summary-position-point)
+      article)))
+
+;; Walking around summary lines with displaying articles.
+
+(defun gnus-summary-expand-window (&optional arg)
+  "Make the summary buffer take up the entire Emacs frame.
+Given a prefix, will force an `article' buffer configuration."
+  (interactive "P")
+  (if arg
+      (gnus-configure-windows 'article 'force)
+    (gnus-configure-windows 'summary 'force)))
+
+(defun gnus-summary-display-article (article &optional all-header)
+  "Display ARTICLE in article buffer."
+  (unless (and (gnus-buffer-live-p gnus-article-buffer)
+              (with-current-buffer gnus-article-buffer
+                (derived-mode-p 'gnus-article-mode)))
+    (gnus-article-setup-buffer))
+  (gnus-set-global-variables)
+  (with-current-buffer gnus-article-buffer
+    (setq gnus-article-charset gnus-newsgroup-charset)
+    (setq gnus-article-ignored-charsets gnus-newsgroup-ignored-charsets)
+    (mm-enable-multibyte))
+  (if (null article)
+      nil
+    (prog1
+       (if gnus-summary-display-article-function
+           (funcall gnus-summary-display-article-function article all-header)
+         (gnus-article-prepare article all-header))
+      (gnus-run-hooks 'gnus-select-article-hook)
+      (when (and gnus-current-article
+                (not (zerop gnus-current-article)))
+       (gnus-summary-goto-subject gnus-current-article))
+      (gnus-summary-recenter)
+      (when (and gnus-use-trees gnus-show-threads)
+       (gnus-possibly-generate-tree article)
+       (gnus-highlight-selected-tree article))
+      ;; Successfully display article.
+      (gnus-article-set-window-start
+       (cdr (assq article gnus-newsgroup-bookmarks))))))
+
+(defun gnus-summary-select-article (&optional all-headers force pseudo article)
+  "Select the current article.
+If ALL-HEADERS is non-nil, show all header fields.  If FORCE is
+non-nil, the article will be re-fetched even if it already present in
+the article buffer.  If PSEUDO is non-nil, pseudo-articles will also
+be displayed."
+  ;; Make sure we are in the summary buffer to work around bbdb bug.
+  (unless (derived-mode-p '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.
+       gnus-summary-display-article-function)
+    (and (not pseudo)
+        (gnus-summary-article-pseudo-p article)
+        (error "This is a pseudo-article"))
+    (with-current-buffer gnus-summary-buffer
+      (if (or (and gnus-single-article-buffer
+                  (or (null gnus-current-article)
+                      (null gnus-article-current)
+                      (null (get-buffer gnus-article-buffer))
+                      (not (eq article (cdr gnus-article-current)))
+                      (not (equal (car gnus-article-current)
+                                  gnus-newsgroup-name))
+                      (not (get-buffer gnus-original-article-buffer))))
+             (and (not gnus-single-article-buffer)
+                  (or (null gnus-current-article)
+                      (not (get-buffer gnus-original-article-buffer))
+                      (not (eq gnus-current-article article))))
+             force)
+         ;; 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
+               (if (not gnus-article-decoded-p) ;; a local variable
+                   (mm-disable-multibyte))))
+           (gnus-article-set-window-start
+            (cdr (assq article gnus-newsgroup-bookmarks)))
+           article)
+       'old))))
+
+(defun gnus-summary-force-verify-and-decrypt ()
+  "Display buttons for signed/encrypted parts and verify/decrypt them."
+  (interactive)
+  (let ((mm-verify-option 'known)
+       (mm-decrypt-option 'known)
+       (gnus-article-emulate-mime t)
+       (gnus-buttonized-mime-types (append (list "multipart/signed"
+                                                 "multipart/encrypted")
+                                           gnus-buttonized-mime-types)))
+    (gnus-summary-select-article nil 'force)))
+
+(defun gnus-summary-next-article (&optional unread subject backward push)
+  "Select the next article.
+If UNREAD, only unread articles are selected.
+If SUBJECT, only articles with SUBJECT are selected.
+If BACKWARD, the previous article is selected instead of the next."
+  (interactive "P")
+  ;; Make sure we are in the summary buffer.
+  (unless (derived-mode-p 'gnus-summary-mode)
+    (set-buffer gnus-summary-buffer))
+  (cond
+   ;; Is there such an article?
+   ((and (gnus-summary-search-forward unread subject backward)
+        (or (gnus-summary-display-article (gnus-summary-article-number))
+            (eq (gnus-summary-article-mark) gnus-canceled-mark)))
+    (gnus-summary-position-point))
+   ;; If not, we try the first unread, if that is wanted.
+   ((and subject
+        gnus-auto-select-same
+        (gnus-summary-first-unread-article))
+    (gnus-summary-position-point)
+    (gnus-message 6 "Wrapped"))
+   ;; Try to get next/previous article not displayed in this group.
+   ((and gnus-auto-extend-newsgroup
+        (not unread) (not subject))
+    (gnus-summary-goto-article
+     (if backward (1- gnus-newsgroup-begin) (1+ gnus-newsgroup-end))
+     nil (count-lines (point-min) (point))))
+   ;; Go to next/previous group.
+   (t
+    (unless (gnus-ephemeral-group-p gnus-newsgroup-name)
+      (gnus-summary-jump-to-group gnus-newsgroup-name))
+    (let ((cmd (if (featurep 'xemacs)
+                  last-command-char
+                last-command-event))
+         (point
+          (with-current-buffer gnus-group-buffer
+            (point)))
+         (current-summary (current-buffer))
+         (group
+          (if (eq gnus-keep-same-level 'best)
+              (gnus-summary-best-group gnus-newsgroup-name)
+            (gnus-summary-search-group backward gnus-keep-same-level))))
+      ;; Select next unread newsgroup automagically.
+      (cond
+       ((or (not gnus-auto-select-next)
+           (not cmd))
+       (gnus-message 7 "No more%s articles" (if unread " unread" "")))
+       ((or (eq gnus-auto-select-next 'quietly)
+           (and (eq gnus-auto-select-next 'slightly-quietly)
+                push)
+           (and (eq gnus-auto-select-next 'almost-quietly)
+                (gnus-summary-last-article-p)))
+       ;; Select quietly.
+       (if (gnus-ephemeral-group-p gnus-newsgroup-name)
+           (gnus-summary-exit)
+         (gnus-message 7 "No more%s articles (%s)..."
+                       (if unread " unread" "")
+                       (if group (concat "selecting " group)
+                         "exiting"))
+         (gnus-summary-next-group nil group backward)))
+       (t
+       (when (gnus-key-press-event-p last-input-event)
+         ;; Somehow or other, we may now have selected a different
+         ;; window.  Make point go back to the summary buffer.
+         (when (eq current-summary (current-buffer))
+            ;; FIXME: This burps when get-buffer-window returns nil.
+           (select-window (get-buffer-window current-summary 0)))
+         (gnus-summary-walk-group-buffer
+          gnus-newsgroup-name cmd unread backward point))))))))
+
+(defun gnus-summary-walk-group-buffer (from-group cmd unread backward start)
+  (let ((keystrokes '((?\C-n (gnus-group-next-unread-group 1))
+                     (?\C-p (gnus-group-prev-unread-group 1))))
+       (cursor-in-echo-area t)
+       keve key group ended prompt)
+    (with-current-buffer gnus-group-buffer
+      (goto-char start)
+      (setq group
+           (if (eq gnus-keep-same-level 'best)
+               (gnus-summary-best-group gnus-newsgroup-name)
+             (gnus-summary-search-group backward gnus-keep-same-level))))
+    (while (not ended)
+      (setq prompt
+           (format
+            "No more%s articles%s " (if unread " unread" "")
+            (if (and group
+                     (not (gnus-ephemeral-group-p gnus-newsgroup-name)))
+                (format " (Type %s for %s [%s])"
+                        (single-key-description cmd)
+                        (gnus-group-decoded-name group)
+                        (gnus-group-unread group))
+              (format " (Type %s to exit %s)"
+                      (single-key-description cmd)
+                      (gnus-group-decoded-name gnus-newsgroup-name)))))
+      ;; Confirm auto selection.
+      (setq key (car (setq keve (gnus-read-event-char prompt)))
+           ended t)
+      (cond
+       ((assq key keystrokes)
+       (let ((obuf (current-buffer)))
+         (switch-to-buffer gnus-group-buffer)
+         (when group
+           (gnus-group-jump-to-group group))
+         (eval (cadr (assq key keystrokes)))
+         (setq group (gnus-group-group-name))
+         (switch-to-buffer obuf))
+       (setq ended nil))
+       ((equal key cmd)
+       (if (or (not group)
+               (gnus-ephemeral-group-p gnus-newsgroup-name))
+           (gnus-summary-exit)
+         (gnus-summary-next-group nil group backward)))
+       (t
+       (push (cdr keve) unread-command-events))))))
+
+(defun gnus-summary-next-unread-article ()
+  "Select unread article after current one."
+  (interactive)
+  (gnus-summary-next-article
+   (or (not (eq gnus-summary-goto-unread 'never))
+       (gnus-summary-last-article-p (gnus-summary-article-number)))
+   (and gnus-auto-select-same
+       (gnus-summary-article-subject))))
+
+(defun gnus-summary-prev-article (&optional unread subject)
+  "Select the article before the current one.
+If UNREAD is non-nil, only unread articles are selected."
+  (interactive "P")
+  (gnus-summary-next-article unread subject t))
+
+(defun gnus-summary-prev-unread-article ()
+  "Select unread article before current one."
+  (interactive)
+  (gnus-summary-prev-article
+   (or (not (eq gnus-summary-goto-unread 'never))
+       (gnus-summary-first-article-p (gnus-summary-article-number)))
+   (and gnus-auto-select-same
+       (gnus-summary-article-subject))))
+
+(declare-function gnus-article-only-boring-p "gnus-art" ())
+
+(defun gnus-summary-next-page (&optional lines circular stop)
+  "Show next page of the selected article.
+If at the end of the current article, select the next article.
+LINES says how many lines should be scrolled up.
+
+If CIRCULAR is non-nil, go to the start of the article instead of
+selecting the next article when reaching the end of the current
+article.
+
+If STOP is non-nil, just stop when reaching the end of the message.
+
+Also see the variable `gnus-article-skip-boring'."
+  (interactive "P")
+  (gnus-set-global-variables)
+  (let ((article (gnus-summary-article-number))
+       (article-window (get-buffer-window gnus-article-buffer t))
+       endp)
+    ;; If the buffer is empty, we have no article.
+    (unless article
+      (error "No article to select"))
+    (gnus-configure-windows 'article)
+    (if (eq (cdr (assq article gnus-newsgroup-reads)) gnus-canceled-mark)
+       (if (and (eq gnus-summary-goto-unread 'never)
+                (not (gnus-summary-last-article-p article)))
+           (gnus-summary-next-article)
+         (gnus-summary-next-unread-article))
+      (if (or (null gnus-current-article)
+             (null gnus-article-current)
+             (/= article (cdr gnus-article-current))
+             (not (equal (car gnus-article-current) gnus-newsgroup-name)))
+         ;; Selected subject is different from current article's.
+         (gnus-summary-display-article article)
+       (when article-window
+         (gnus-eval-in-buffer-window gnus-article-buffer
+           (setq endp (or (gnus-article-next-page lines)
+                          (gnus-article-only-boring-p))))
+         (when endp
+           (cond ((or stop gnus-summary-stop-at-end-of-message)
+                  (gnus-message 3 "End of message"))
+                 (circular
+                  (gnus-summary-beginning-of-article))
+                 (lines
+                  (gnus-message 3 "End of message"))
+                 ((null lines)
+                  (if (and (eq gnus-summary-goto-unread 'never)
+                           (not (gnus-summary-last-article-p article)))
+                      (gnus-summary-next-article)
+                    (gnus-summary-next-unread-article))))))))
+    (gnus-summary-recenter)
+    (gnus-summary-position-point)))
+
+(defun gnus-summary-prev-page (&optional lines move)
+  "Show previous page of selected article.
+Argument LINES specifies lines to be scrolled down.
+If MOVE, move to the previous unread article if point is at
+the beginning of the buffer."
+  (interactive "P")
+  (let ((article (gnus-summary-article-number))
+       (article-window (get-buffer-window gnus-article-buffer t))
+       endp)
+    (gnus-configure-windows 'article)
+    (if (or (null gnus-current-article)
+           (null gnus-article-current)
+           (/= article (cdr gnus-article-current))
+           (not (equal (car gnus-article-current) gnus-newsgroup-name)))
+       ;; Selected subject is different from current article's.
+       (gnus-summary-display-article article)
+      (gnus-summary-recenter)
+      (when article-window
+       (gnus-eval-in-buffer-window gnus-article-buffer
+         (setq endp (gnus-article-prev-page lines)))
+       (when (and move endp)
+         (cond (lines
+                (gnus-message 3 "Beginning of message"))
+               ((null lines)
+                (if (and (eq gnus-summary-goto-unread 'never)
+                         (not (gnus-summary-first-article-p article)))
+                    (gnus-summary-prev-article)
+                  (gnus-summary-prev-unread-article))))))))
+  (gnus-summary-position-point))
+
+(defun gnus-summary-prev-page-or-article (&optional lines)
+  "Show previous page of selected article.
+Argument LINES specifies lines to be scrolled down.
+If at the beginning of the article, go to the next article."
+  (interactive "P")
+  (gnus-summary-prev-page lines t))
+
+(defun gnus-summary-scroll-up (lines)
+  "Scroll up (or down) one line current article.
+Argument LINES specifies lines to be scrolled up (or down if negative).
+If no article is selected, then the current article will be selected first."
+  (interactive "p")
+  (gnus-configure-windows 'article)
+  (gnus-summary-show-thread)
+  (when (eq (gnus-summary-select-article nil nil 'pseudo) 'old)
+    (gnus-eval-in-buffer-window gnus-article-buffer
+      (cond ((> lines 0)
+            (when (gnus-article-next-page lines)
+              (gnus-message 3 "End of message")))
+           ((< lines 0)
+            (gnus-article-prev-page (- lines))))))
+  (gnus-summary-recenter)
+  (gnus-summary-position-point))
+
+(defun gnus-summary-scroll-down (lines)
+  "Scroll down (or up) one line current article.
+Argument LINES specifies lines to be scrolled down (or up if negative).
+If no article is selected, then the current article will be selected first."
+  (interactive "p")
+  (gnus-summary-scroll-up (- lines)))
+
+(defun gnus-summary-next-same-subject ()
+  "Select next article which has the same subject as current one."
+  (interactive)
+  (gnus-summary-next-article nil (gnus-summary-article-subject)))
+
+(defun gnus-summary-prev-same-subject ()
+  "Select previous article which has the same subject as current one."
+  (interactive)
+  (gnus-summary-prev-article nil (gnus-summary-article-subject)))
+
+(defun gnus-summary-next-unread-same-subject ()
+  "Select next unread article which has the same subject as current one."
+  (interactive)
+  (gnus-summary-next-article t (gnus-summary-article-subject)))
+
+(defun gnus-summary-prev-unread-same-subject ()
+  "Select previous unread article which has the same subject as current one."
+  (interactive)
+  (gnus-summary-prev-article t (gnus-summary-article-subject)))
+
+(defun gnus-summary-first-unread-article ()
+  "Select the first unread article.
+Return nil if there are no unread articles."
+  (interactive)
+  (prog1
+      (when (gnus-summary-first-subject t)
+       (gnus-summary-show-thread)
+       (gnus-summary-first-subject t)
+       (gnus-summary-display-article (gnus-summary-article-number)))
+    (gnus-summary-position-point)))
+
+(defun gnus-summary-first-unread-subject ()
+  "Place the point on the subject line of the first unread article.
+Return nil if there are no unread articles."
+  (interactive)
+  (prog1
+      (when (gnus-summary-first-subject t)
+       (gnus-summary-show-thread)
+       (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 nil nil t)
+       (gnus-summary-show-thread)
+       (gnus-summary-first-subject nil nil t))
+    (gnus-summary-position-point)))
+
+(defun gnus-summary-first-unseen-or-unread-subject ()
+  "Place the point on the subject line of the first unseen and unread article.
+If all article have been seen, on the subject line of the first unread
+article."
+  (interactive)
+  (prog1
+      (unless (when (gnus-summary-first-subject nil nil t)
+               (gnus-summary-show-thread)
+               (gnus-summary-first-subject nil nil t))
+       (when (gnus-summary-first-subject t)
+         (gnus-summary-show-thread)
+         (gnus-summary-first-subject t)))
+    (gnus-summary-position-point)))
+
+(defun gnus-summary-first-article ()
+  "Select the first article.
+Return nil if there are no articles."
+  (interactive)
+  (prog1
+      (when (gnus-summary-first-subject)
+       (gnus-summary-show-thread)
+       (gnus-summary-first-subject)
+       (gnus-summary-display-article (gnus-summary-article-number)))
+    (gnus-summary-position-point)))
+
+(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)
+       article score)
+    (while data
+      (and (gnus-data-unread-p (car data))
+          (> (setq score
+                   (gnus-summary-article-score (gnus-data-number (car data))))
+             best)
+          (setq best score
+                article (gnus-data-number (car data))))
+      (setq data (cdr data)))
+    (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."
+  (let ((article (gnus-data-number (car (gnus-data-list t)))))
+    (when article
+      (gnus-summary-goto-subject article))))
+
+(defun gnus-summary-goto-article (article &optional all-headers force)
+  "Fetch ARTICLE (article number or Message-ID) and display it if it exists.
+If ALL-HEADERS is non-nil, no header lines are hidden.
+If FORCE, go to the article even if it isn't displayed.  If FORCE
+is a number, it is the line the article is to be displayed on."
+  (interactive
+   (list
+    (gnus-completing-read
+     "Article number or Message-ID"
+     (mapcar 'int-to-string gnus-newsgroup-limit))
+    current-prefix-arg
+    t))
+  (prog1
+      (if (and (stringp article)
+              (string-match "@\\|%40" article))
+         (gnus-summary-refer-article article)
+       (when (stringp article)
+         (setq article (string-to-number article)))
+       (if (gnus-summary-goto-subject article force)
+           (gnus-summary-display-article article all-headers)
+         (gnus-message 4 "Couldn't go to article %s" article) nil))
+    (gnus-summary-position-point)))
+
+(defun gnus-summary-goto-last-article ()
+  "Go to the previously read article."
+  (interactive)
+  (prog1
+      (when gnus-last-article
+       (gnus-summary-goto-article gnus-last-article nil t))
+    (gnus-summary-position-point)))
+
+(defun gnus-summary-pop-article (number)
+  "Pop one article off the history and go to the previous.
+NUMBER articles will be popped off."
+  (interactive "p")
+  (let (to)
+    (setq gnus-newsgroup-history
+         (cdr (setq to (nthcdr number gnus-newsgroup-history))))
+    (if to
+       (gnus-summary-goto-article (car to) nil t)
+      (error "Article history empty")))
+  (gnus-summary-position-point))
+
+;; Summary commands and functions for limiting the summary buffer.
+
+(defun gnus-summary-limit-to-articles (n)
+  "Limit the summary buffer to the next N articles.
+If not given a prefix, use the process marked articles instead."
+  (interactive "P")
+  (prog1
+      (let ((articles (gnus-summary-work-articles n)))
+       (setq gnus-newsgroup-processable nil)
+       (gnus-summary-limit articles))
+    (gnus-summary-position-point)))
+
+(defun gnus-summary-pop-limit (&optional total)
+  "Restore the previous limit.
+If given a prefix, remove all limits."
+  (interactive "P")
+  (when total
+    (setq gnus-newsgroup-limits
+         (list (mapcar (lambda (h) (mail-header-number h))
+                       gnus-newsgroup-headers))))
+  (unless gnus-newsgroup-limits
+    (error "No limit to pop"))
+  (prog1
+      (gnus-summary-limit nil 'pop)
+    (gnus-summary-position-point)))
+
+(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 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 &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 (let* ((header (gnus-summary-article-header))
+               (default (and header (car (mail-header-parse-address
+                                          (mail-header-from header))))))
+          (read-string (concat (if current-prefix-arg
+                                   "Exclude author (regexp"
+                                 "Limit to author (regexp")
+                               (if default
+                                   (concat ", default \"" default "\"): ")
+                                 "): "))
+                       nil nil
+                       default))
+        current-prefix-arg))
+  (gnus-summary-limit-to-subject from "from" not-matching))
+
+(defun gnus-summary-limit-to-recipient (recipient &optional not-matching)
+  "Limit the summary buffer to articles with the given RECIPIENT.
+
+If NOT-MATCHING, exclude RECIPIENT.
+
+To and Cc headers are checked.  You need to include them in
+`nnmail-extra-headers'."
+  ;; Unlike `rmail-summary-by-recipients', doesn't include From.
+  (interactive
+   (list (read-string (format "%s recipient (regexp): "
+                             (if current-prefix-arg "Exclude" "Limit to")))
+        current-prefix-arg))
+  (when (not (equal "" recipient))
+    (prog1 (let* ((to
+                  (if (memq 'To nnmail-extra-headers)
+                      (gnus-summary-find-matching
+                       (cons 'extra 'To) recipient 'all nil nil
+                       not-matching)
+                    (gnus-message
+                     1 "`To' isn't present in `nnmail-extra-headers'")
+                    (sit-for 1)
+                    nil))
+                 (cc
+                  (if (memq 'Cc nnmail-extra-headers)
+                      (gnus-summary-find-matching
+                       (cons 'extra 'Cc) recipient 'all nil nil
+                       not-matching)
+                    (gnus-message
+                     1 "`Cc' isn't present in `nnmail-extra-headers'")
+                    (sit-for 1)
+                    nil))
+                 (articles
+                  (if not-matching
+                      ;; We need the numbers that are in both lists:
+                      (mapcar (lambda (a)
+                                (and (memq a to) a))
+                              cc)
+                    (nconc to cc))))
+            (unless articles
+              (error "Found no matches for \"%s\"" recipient))
+            (gnus-summary-limit articles))
+      (gnus-summary-position-point))))
+
+(defun gnus-summary-limit-to-address (address &optional not-matching)
+  "Limit the summary buffer to articles with the given ADDRESS.
+
+If NOT-MATCHING, exclude ADDRESS.
+
+To, Cc and From headers are checked.  You need to include `To' and `Cc'
+in `nnmail-extra-headers'."
+  (interactive
+   (list (read-string (format "%s address (regexp): "
+                             (if current-prefix-arg "Exclude" "Limit to")))
+        current-prefix-arg))
+  (when (not (equal "" address))
+    (prog1 (let* ((to
+                  (if (memq 'To nnmail-extra-headers)
+                      (gnus-summary-find-matching
+                       (cons 'extra 'To) address 'all nil nil
+                       not-matching)
+                    (gnus-message
+                     1 "`To' isn't present in `nnmail-extra-headers'")
+                    (sit-for 1)
+                    t))
+                 (cc
+                  (if (memq 'Cc nnmail-extra-headers)
+                      (gnus-summary-find-matching
+                       (cons 'extra 'Cc) address 'all nil nil
+                       not-matching)
+                    (gnus-message
+                     1 "`Cc' isn't present in `nnmail-extra-headers'")
+                    (sit-for 1)
+                    t))
+                 (from
+                  (gnus-summary-find-matching "from" address
+                                              'all nil nil not-matching))
+                 (articles
+                  (if not-matching
+                      ;; We need the numbers that are in all lists:
+                      (if (eq cc t)
+                          (if (eq to t)
+                              from
+                            (mapcar (lambda (a) (car (memq a from))) to))
+                        (if (eq to t)
+                            (mapcar (lambda (a) (car (memq a from))) cc)
+                          (mapcar (lambda (a) (car (memq a from)))
+                                  (mapcar (lambda (a) (car (memq a to)))
+                                          cc))))
+                    (nconc (if (eq to t) nil to)
+                           (if (eq cc t) nil cc)
+                           from))))
+            (unless articles
+              (error "Found no matches for \"%s\"" address))
+            (gnus-summary-limit articles))
+      (gnus-summary-position-point))))
+
+(defun gnus-summary-limit-strange-charsets-predicate (header)
+  (when (fboundp 'char-charset)
+    (let ((string (concat (mail-header-subject header)
+                         (mail-header-from header)))
+         charset found)
+      (dotimes (i (1- (length string)))
+       (setq charset (format "%s" (char-charset (aref string (1+ i)))))
+       (when (string-match "unicode\\|big\\|japanese" charset)
+         (setq found t)))
+      found)))
+
+(defun gnus-summary-limit-to-predicate (predicate)
+  "Limit to articles where PREDICATE returns non-nil.
+PREDICATE will be called with the header structures of the
+articles."
+  (let ((articles nil)
+       (case-fold-search t))
+    (dolist (header gnus-newsgroup-headers)
+      (when (funcall predicate header)
+       (push (mail-header-number header) articles)))
+    (gnus-summary-limit (nreverse articles))))
+
+(defun gnus-summary-limit-to-age (age &optional younger-p)
+  "Limit the summary buffer to articles that are older than (or equal) AGE days.
+If YOUNGER-P (the prefix) is non-nil, limit the summary buffer to
+articles that are younger than AGE days."
+  (interactive
+   (let ((younger current-prefix-arg)
+        (days-got nil)
+        days)
+     (while (not days-got)
+       (setq days (if younger
+                     (read-string "Limit to articles younger than (in days, older when negative): ")
+                   (read-string
+                    "Limit to articles older than (in days, younger when negative): ")))
+       (when (> (length days) 0)
+        (setq days (read days)))
+       (if (numberp days)
+          (progn
+            (setq days-got t)
+            (when (< days 0)
+              (setq younger (not younger))
+              (setq days (* days -1))))
+        (message "Please enter a number.")
+        (sleep-for 1)))
+     (list days younger)))
+  (prog1
+      (let ((data gnus-newsgroup-data)
+           (cutoff (days-to-time age))
+           articles d date is-younger)
+       (while (setq d (pop data))
+         (when (and (vectorp (gnus-data-header d))
+                    (setq date (mail-header-date (gnus-data-header d))))
+           (setq is-younger (time-less-p
+                             (time-since (gnus-date-get-time date))
+                             cutoff))
+           (when (if younger-p
+                     is-younger
+                   (not is-younger))
+             (push (gnus-data-number d) articles))))
+       (gnus-summary-limit (nreverse articles)))
+    (gnus-summary-position-point)))
+
+(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
+           (if current-prefix-arg
+               "Exclude extra header"
+             "Limit extra header")
+           (mapcar 'symbol-name gnus-extra-headers)
+           t nil nil
+            (symbol-name (car gnus-extra-headers))))))
+     (list 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 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 (gnus-number gnus-newsgroup-articles)
+      (when (funcall gnus-newsgroup-display)
+       (push gnus-number articles)))
+    (gnus-summary-limit articles))
+  (gnus-summary-position-point))
+
+(defun gnus-summary-limit-to-unread (&optional all)
+  "Limit the summary buffer to articles that are not marked as read.
+If ALL is non-nil, limit strictly to unread articles."
+  (interactive "P")
+  (if all
+      (gnus-summary-limit-to-marks (char-to-string gnus-unread-mark))
+    (gnus-summary-limit-to-marks
+     ;; Concat all the marks that say that an article is read and have
+     ;; those removed.
+     (list gnus-del-mark gnus-read-mark gnus-ancient-mark
+          gnus-killed-mark gnus-spam-mark gnus-kill-file-mark
+          gnus-low-score-mark gnus-expirable-mark
+          gnus-canceled-mark gnus-catchup-mark gnus-sparse-mark
+          gnus-duplicate-mark)
+     'reverse)))
+
+(defun gnus-summary-limit-to-headers (match &optional reverse)
+  "Limit the summary buffer to articles that have headers that match MATCH.
+If REVERSE (the prefix), limit to articles that don't match."
+  (interactive "sMatch headers (regexp): \nP")
+  (gnus-summary-limit-to-bodies match reverse t))
+
+(declare-function article-goto-body "gnus-art" ())
+
+(defun gnus-summary-limit-to-bodies (match &optional reverse headersp)
+  "Limit the summary buffer to articles that have bodies that match MATCH.
+If REVERSE (the prefix), limit to articles that don't match."
+  (interactive "sMatch body (regexp): \nP")
+  (let ((articles nil)
+       (gnus-select-article-hook nil)  ;Disable hook.
+       (gnus-article-prepare-hook nil)
+       (gnus-use-article-prefetch nil)
+       (gnus-keep-backlog nil)
+       (gnus-break-pages nil)
+       (gnus-summary-display-arrow nil)
+       (gnus-updated-mode-lines nil)
+       (gnus-auto-center-summary nil)
+       (gnus-display-mime-function nil))
+    (dolist (data gnus-newsgroup-data)
+      (let (gnus-mark-article-hook)
+       (gnus-summary-select-article t t nil (gnus-data-number data)))
+      (with-current-buffer gnus-article-buffer
+       (article-goto-body)
+       (let* ((case-fold-search t)
+              (found (if headersp
+                         (re-search-backward match nil t)
+                       (re-search-forward match nil t))))
+         (when (or (and found
+                        (not reverse))
+                   (and (not found)
+                        reverse))
+           (push (gnus-data-number data) articles)))))
+    (if (not articles)
+       (message "No messages matched")
+      (gnus-summary-limit articles)))
+  (gnus-summary-position-point))
+
+(defun gnus-summary-limit-to-singletons (&optional threadsp)
+  "Limit the summary buffer to articles that aren't part on any thread.
+If THREADSP (the prefix), limit to articles that are in threads."
+  (interactive "P")
+  (let ((articles nil)
+       thread-articles
+       threads)
+    (dolist (thread gnus-newsgroup-threads)
+      (if (stringp (car thread))
+         (dolist (thread (cdr thread))
+           (push thread threads))
+       (push thread threads)))
+    (dolist (thread threads)
+      (setq thread-articles (gnus-articles-in-thread thread))
+      (when (or (and threadsp
+                    (> (length thread-articles) 1))
+               (and (not threadsp)
+                    (= (length thread-articles) 1)))
+       (setq articles (nconc thread-articles articles))))
+    (if (not articles)
+       (message "No messages matched")
+      (gnus-summary-limit articles))
+    (gnus-summary-position-point)))
+
+(defun gnus-summary-limit-to-replied (&optional unreplied)
+  "Limit the summary buffer to replied articles.
+If UNREPLIED (the prefix), limit to unreplied articles."
+  (interactive "P")
+  (if unreplied
+      (gnus-summary-limit
+       (gnus-set-difference gnus-newsgroup-articles
+       gnus-newsgroup-replied))
+    (gnus-summary-limit gnus-newsgroup-replied))
+  (gnus-summary-position-point))
+
+(defun gnus-summary-limit-exclude-marks (marks &optional reverse)
+  "Exclude articles that are marked with MARKS (e.g. \"DK\").
+If REVERSE, limit the summary buffer to articles that are marked
+with MARKS.  MARKS can either be a string of marks or a list of marks.
+Returns how many articles were removed."
+  (interactive "sMarks: ")
+  (gnus-summary-limit-to-marks marks t))
+
+(defun gnus-summary-limit-to-marks (marks &optional reverse)
+  "Limit the summary buffer to articles that are marked with MARKS (e.g. \"DK\").
+If REVERSE (the prefix), limit the summary buffer to articles that are
+not marked with MARKS.  MARKS can either be a string of marks or a
+list of marks.
+Returns how many articles were removed."
+  (interactive "sMarks: \nP")
+  (prog1
+      (let ((data gnus-newsgroup-data)
+           (marks (if (listp marks) marks
+                    (append marks nil))) ; Transform to list.
+           articles)
+       (while data
+         (when (if reverse (not (memq (gnus-data-mark (car data)) marks))
+                 (memq (gnus-data-mark (car data)) marks))
+           (push (gnus-data-number (car data)) articles))
+         (setq data (cdr data)))
+       (gnus-summary-limit articles))
+    (gnus-summary-position-point)))
+
+(defun gnus-summary-limit-to-score (score)
+  "Limit to articles with score at or above SCORE."
+  (interactive "NLimit to articles with score of at least: ")
+  (let ((data gnus-newsgroup-data)
+       articles)
+    (while data
+      (when (>= (gnus-summary-article-score (gnus-data-number (car data)))
+               score)
+       (push (gnus-data-number (car data)) articles))
+      (setq data (cdr data)))
+    (prog1
+       (gnus-summary-limit articles)
+      (gnus-summary-position-point))))
+
+(defun gnus-summary-limit-to-unseen ()
+  "Limit to unseen articles."
+  (interactive)
+  (prog1
+      (gnus-summary-limit gnus-newsgroup-unseen)
+    (gnus-summary-position-point)))
+
+(defun gnus-summary-limit-include-thread (id)
+  "Display all the hidden articles that is in the thread with ID in it.
+When called interactively, ID is the Message-ID of the current
+article."
+  (interactive (list (mail-header-id (gnus-summary-article-header))))
+  (let ((articles (gnus-articles-in-thread
+                  (gnus-id-to-thread (gnus-root-id id))))
+       ;;we REALLY want the whole thread---this prevents cut-threads
+       ;;from removing the thread we want to include.
+       (gnus-fetch-old-headers nil)
+       (gnus-build-sparse-threads nil))
+    (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-position-point))))
+
+(defun gnus-summary-limit-include-matching-articles (header regexp)
+  "Display all the hidden articles that have HEADERs that match REGEXP."
+  (interactive (list (read-string "Match on header: ")
+                    (read-string "Regexp: ")))
+  (let ((articles (gnus-find-matching-articles header regexp)))
+    (prog1
+       (gnus-summary-limit (nconc articles gnus-newsgroup-limit))
+      (gnus-summary-position-point))))
+
+(defun gnus-summary-insert-dormant-articles ()
+  "Insert all the dormant articles for this group into the current buffer."
+  (interactive)
+  (let ((gnus-verbose (max 6 gnus-verbose)))
+    (if (not gnus-newsgroup-dormant)
+       (gnus-message 3 "No dormant articles for this group")
+      (gnus-summary-goto-subjects gnus-newsgroup-dormant))))
+
+(defun gnus-summary-insert-ticked-articles ()
+  "Insert ticked articles for this group into the current buffer."
+  (interactive)
+  (let ((gnus-verbose (max 6 gnus-verbose)))
+    (if (not gnus-newsgroup-marked)
+       (gnus-message 3 "No ticked articles for this group")
+      (gnus-summary-goto-subjects gnus-newsgroup-marked))))
+
+(defun gnus-summary-limit-include-dormant ()
+  "Display all the hidden articles that are marked as dormant.
+Note that this command only works on a subset of the articles currently
+fetched for this group."
+  (interactive)
+  (unless gnus-newsgroup-dormant
+    (error "There are no dormant articles in this group"))
+  (prog1
+      (gnus-summary-limit (append gnus-newsgroup-dormant gnus-newsgroup-limit))
+    (gnus-summary-position-point)))
+
+(defun gnus-summary-include-articles (articles)
+  "Fetch the headers for ARTICLES and then display the summary lines."
+  (let ((gnus-inhibit-demon t)
+       (gnus-agent nil)
+       (gnus-read-all-available-headers t))
+    (setq gnus-newsgroup-headers
+         (gnus-merge
+          'list gnus-newsgroup-headers
+          (gnus-fetch-headers articles nil t)
+          'gnus-article-sort-by-number))
+    (setq gnus-newsgroup-articles
+         (gnus-sorted-nunion gnus-newsgroup-articles articles))
+    (gnus-summary-limit (append articles gnus-newsgroup-limit))))
+
+(defun gnus-summary-limit-exclude-dormant ()
+  "Hide all dormant articles."
+  (interactive)
+  (prog1
+      (gnus-summary-limit-to-marks (list gnus-dormant-mark) 'reverse)
+    (gnus-summary-position-point)))
+
+(defun gnus-summary-limit-exclude-childless-dormant ()
+  "Hide all dormant articles that have no children."
+  (interactive)
+  (let ((data (gnus-data-list t))
+       articles d children)
+    ;; Find all articles that are either not dormant or have
+    ;; children.
+    (while (setq d (pop data))
+      (when (or (not (= (gnus-data-mark d) gnus-dormant-mark))
+               (and (setq children
+                          (gnus-article-children (gnus-data-number d)))
+                    (let (found)
+                      (while children
+                        (when (memq (car children) articles)
+                          (setq children nil
+                                found t))
+                        (pop children))
+                      found)))
+       (push (gnus-data-number d) articles)))
+    ;; Do the limiting.
+    (prog1
+       (gnus-summary-limit articles)
+      (gnus-summary-position-point))))
+
+(defun gnus-summary-limit-mark-excluded-as-read (&optional all)
+  "Mark all unread excluded articles as read.
+If ALL, mark even excluded ticked and dormants as read."
+  (interactive "P")
+  (setq gnus-newsgroup-limit (sort gnus-newsgroup-limit '<))
+  (let ((articles (gnus-sorted-ndifference
+                  (sort
+                   (mapcar (lambda (h) (mail-header-number h))
+                           gnus-newsgroup-headers)
+                   '<)
+                  gnus-newsgroup-limit))
+       article)
+    (setq gnus-newsgroup-unreads
+         (gnus-sorted-intersection gnus-newsgroup-unreads
+                                   gnus-newsgroup-limit))
+    (if all
+       (setq gnus-newsgroup-dormant nil
+             gnus-newsgroup-marked nil
+             gnus-newsgroup-reads
+             (nconc
+              (mapcar (lambda (n) (cons n gnus-catchup-mark)) articles)
+              gnus-newsgroup-reads))
+      (while (setq article (pop articles))
+       (unless (or (memq article gnus-newsgroup-dormant)
+                   (memq article gnus-newsgroup-marked))
+         (push (cons article gnus-catchup-mark) gnus-newsgroup-reads))))))
+
+(defun gnus-summary-limit (articles &optional pop)
+  (if pop
+      ;; We pop the previous limit off the stack and use that.
+      (setq articles (car gnus-newsgroup-limits)
+           gnus-newsgroup-limits (cdr gnus-newsgroup-limits))
+    ;; We use the new limit, so we push the old limit on the stack.
+    (push gnus-newsgroup-limit gnus-newsgroup-limits))
+  ;; Set the limit.
+  (setq gnus-newsgroup-limit articles)
+  (let ((total (length gnus-newsgroup-data))
+       (data (gnus-data-find-list (gnus-summary-article-number)))
+       (gnus-summary-mark-below nil)   ; Inhibit this.
+       found)
+    ;; This will do all the work of generating the new summary buffer
+    ;; according to the new limit.
+    (gnus-summary-prepare)
+    ;; Hide any threads, possibly.
+    (gnus-summary-maybe-hide-threads)
+    ;; Try to return to the article you were at, or one in the
+    ;; neighborhood.
+    (when data
+      ;; We try to find some article after the current one.
+      (while data
+       (when (gnus-summary-goto-subject (gnus-data-number (car data)) nil t)
+         (setq data nil
+               found t))
+       (setq data (cdr data))))
+    (unless found
+      ;; If there is no data, that means that we were after the last
+      ;; article.  The same goes when we can't find any articles
+      ;; after the current one.
+      (goto-char (point-max))
+      (gnus-summary-find-prev))
+    (gnus-set-mode-line 'summary)
+    ;; We return how many articles were removed from the summary
+    ;; buffer as a result of the new limit.
+    (- total (length gnus-newsgroup-data))))
+
+(defsubst gnus-invisible-cut-children (threads)
+  (let ((num 0))
+    (while threads
+      (when (memq (mail-header-number (caar threads)) gnus-newsgroup-limit)
+       (incf num))
+      (pop threads))
+    (< num 2)))
+
+(defsubst gnus-cut-thread (thread)
+  "Go forwards in the thread until we find an article that we want to display."
+  (when (or (eq gnus-fetch-old-headers 'some)
+           (eq gnus-fetch-old-headers 'invisible)
+           (numberp gnus-fetch-old-headers)
+           (eq gnus-build-sparse-threads 'some)
+           (eq gnus-build-sparse-threads 'more))
+    ;; Deal with old-fetched headers and sparse threads.
+    (while (and
+           thread
+           (or
+            (gnus-summary-article-sparse-p (mail-header-number (car thread)))
+            (gnus-summary-article-ancient-p
+             (mail-header-number (car thread))))
+           (if (or (<= (length (cdr thread)) 1)
+                   (eq gnus-fetch-old-headers 'invisible))
+               (setq gnus-newsgroup-limit
+                     (delq (mail-header-number (car thread))
+                           gnus-newsgroup-limit)
+                     thread (cadr thread))
+             (when (gnus-invisible-cut-children (cdr thread))
+               (let ((th (cdr thread)))
+                 (while th
+                   (if (memq (mail-header-number (caar th))
+                             gnus-newsgroup-limit)
+                       (setq thread (car th)
+                             th nil)
+                     (setq th (cdr th))))))))))
+  thread)
+
+(defun gnus-cut-threads (threads)
+  "Cut off all uninteresting articles from the beginning of THREADS."
+  (when (or (eq gnus-fetch-old-headers 'some)
+           (eq gnus-fetch-old-headers 'invisible)
+           (numberp gnus-fetch-old-headers)
+           (eq gnus-build-sparse-threads 'some)
+           (eq gnus-build-sparse-threads 'more))
+    (let ((th threads))
+      (while th
+       (setcar th (gnus-cut-thread (car th)))
+       (setq th (cdr th)))))
+  ;; Remove nixed out threads.
+  (delq nil threads))
+
+(defun gnus-summary-initial-limit (&optional show-if-empty)
+  "Figure out what the initial limit is supposed to be on group entry.
+This entails weeding out unwanted dormants, low-scored articles,
+fetch-old-headers verbiage, and so on."
+  ;; Most groups have nothing to remove.
+  (unless (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))
+                  (null gnus-summary-expunge-below)
+                  (not (eq gnus-build-sparse-threads 'some))
+                  (not (eq gnus-build-sparse-threads 'more))
+                  (null gnus-thread-expunge-below)))
+    (push gnus-newsgroup-limit gnus-newsgroup-limits)
+    (setq gnus-newsgroup-limit nil)
+    (mapatoms
+     (lambda (node)
+       (unless (car (symbol-value node))
+        ;; These threads have no parents -- they are roots.
+        (let ((nodes (cdr (symbol-value node)))
+              thread)
+          (while nodes
+            (if (and gnus-thread-expunge-below
+                     (< (gnus-thread-total-score (car nodes))
+                        gnus-thread-expunge-below))
+                (gnus-expunge-thread (pop nodes))
+              (setq thread (pop nodes))
+              (gnus-summary-limit-children thread))))))
+     gnus-newsgroup-dependencies)
+    ;; If this limitation resulted in an empty group, we might
+    ;; pop the previous limit and use it instead.
+    (when (and (not gnus-newsgroup-limit)
+              show-if-empty)
+      (setq gnus-newsgroup-limit (pop gnus-newsgroup-limits)))
+    gnus-newsgroup-limit))
+
+(defun gnus-summary-limit-children (thread)
+  "Return 1 if this subthread is visible and 0 if it is not."
+  ;; First we get the number of visible children to this thread.  This
+  ;; is done by recursing down the thread using this function, so this
+  ;; will really go down to a leaf article first, before slowly
+  ;; working its way up towards the root.
+  (when thread
+    (let* ((max-lisp-eval-depth (max 5000 max-lisp-eval-depth))
+          (children
+          (if (cdr thread)
+              (apply '+ (mapcar 'gnus-summary-limit-children
+                                (cdr thread)))
+            0))
+          (number (mail-header-number (car thread)))
+          score)
+      (if (and
+          (not (memq number gnus-newsgroup-marked))
+          (or
+           ;; If this article is dormant and has absolutely no visible
+           ;; children, then this article isn't visible.
+           (and (memq number gnus-newsgroup-dormant)
+                (zerop children))
+           ;; If this is "fetch-old-headered" and there is no
+           ;; visible children, then we don't want this article.
+           (and (or (eq gnus-fetch-old-headers 'some)
+                    (numberp gnus-fetch-old-headers))
+                (gnus-summary-article-ancient-p number)
+                (zerop children))
+           ;; If this is "fetch-old-headered" and `invisible', then
+           ;; we don't want this article.
+           (and (eq gnus-fetch-old-headers 'invisible)
+                (gnus-summary-article-ancient-p number))
+           ;; If this is a sparsely inserted article with no children,
+           ;; we don't want it.
+           (and (eq gnus-build-sparse-threads 'some)
+                (gnus-summary-article-sparse-p number)
+                (zerop children))
+           ;; If we use expunging, and this article is really
+           ;; low-scored, then we don't want this article.
+           (when (and gnus-summary-expunge-below
+                      (< (setq score
+                               (or (cdr (assq number gnus-newsgroup-scored))
+                                   gnus-summary-default-score))
+                         gnus-summary-expunge-below))
+             ;; We increase the expunge-tally here, but that has
+             ;; nothing to do with the limits, really.
+             (incf gnus-newsgroup-expunged-tally)
+             ;; We also mark as read here, if that's wanted.
+             (when (and gnus-summary-mark-below
+                        (< score gnus-summary-mark-below))
+               (setq gnus-newsgroup-unreads
+                     (delq number gnus-newsgroup-unreads))
+               (if gnus-newsgroup-auto-expire
+                   (push number gnus-newsgroup-expirable)
+                 (push (cons number gnus-low-score-mark)
+                       gnus-newsgroup-reads)))
+             t)
+           ;; Do the `display' group parameter.
+           (and gnus-newsgroup-display
+                (let ((gnus-number number))
+                  (not (funcall gnus-newsgroup-display))))))
+         ;; Nope, invisible article.
+         0
+       ;; Ok, this article is to be visible, so we add it to the limit
+       ;; and return 1.
+       (push number gnus-newsgroup-limit)
+       1))))
+
+(defun gnus-expunge-thread (thread)
+  "Mark all articles in THREAD as read."
+  (let* ((number (mail-header-number (car thread))))
+    (incf gnus-newsgroup-expunged-tally)
+    ;; We also mark as read here, if that's wanted.
+    (setq gnus-newsgroup-unreads
+         (delq number gnus-newsgroup-unreads))
+    (if gnus-newsgroup-auto-expire
+       (push number gnus-newsgroup-expirable)
+      (push (cons number gnus-low-score-mark)
+           gnus-newsgroup-reads)))
+  ;; Go recursively through all subthreads.
+  (mapcar 'gnus-expunge-thread (cdr thread)))
+
+;; Summary article oriented commands
+
+(defun gnus-summary-refer-parent-article (n)
+  "Refer parent article N times.
+If N is negative, go to ancestor -N instead.
+The difference between N and the number of articles fetched is returned."
+  (interactive "p")
+  (let ((skip 1)
+       error header ref)
+    (when (not (natnump n))
+      (setq skip (abs n)
+           n 1))
+    (while (and (> n 0)
+               (not error))
+      (setq header (gnus-summary-article-header))
+      (if (and (eq (mail-header-number header)
+                  (cdr gnus-article-current))
+              (equal gnus-newsgroup-name
+                     (car gnus-article-current)))
+         ;; If we try to find the parent of the currently
+         ;; displayed article, then we take a look at the actual
+         ;; References header, since this is slightly more
+         ;; reliable than the References field we got from the
+         ;; server.
+         (with-current-buffer gnus-original-article-buffer
+           (nnheader-narrow-to-headers)
+           (unless (setq ref (message-fetch-field "references"))
+             (when (setq ref (message-fetch-field "in-reply-to"))
+               (setq ref (gnus-extract-message-id-from-in-reply-to ref))))
+           (widen))
+       (setq ref
+             ;; It's not the current article, so we take a bet on
+             ;; the value we got from the server.
+             (mail-header-references header)))
+      (if (and ref
+              (not (equal ref "")))
+         (unless (gnus-summary-refer-article (gnus-parent-id ref skip))
+           (gnus-message 1 "Couldn't find parent"))
+       (gnus-message 1 "No references in article %d"
+                     (gnus-summary-article-number))
+       (setq error t))
+      (decf n))
+    (gnus-summary-position-point)
+    n))
+
+(defun gnus-summary-refer-references ()
+  "Fetch all articles mentioned in the References header.
+Return the number of articles fetched."
+  (interactive)
+  (let ((ref (mail-header-references (gnus-summary-article-header)))
+       (current (gnus-summary-article-number))
+       (n 0))
+    (if (or (not ref)
+           (equal ref ""))
+       (error "No References in the current article")
+      ;; For each Message-ID in the References header...
+      (while (string-match "<[^>]*>" ref)
+       (incf n)
+       ;; ... fetch that article.
+       (gnus-summary-refer-article
+        (prog1 (match-string 0 ref)
+          (setq ref (substring ref (match-end 0))))))
+      (gnus-summary-goto-subject current)
+      (gnus-summary-position-point)
+      n)))
+
+(defun gnus-delete-duplicate-headers (headers)
+  ;; First remove leading duplicates.
+  (while (and (> (length headers) 1)
+             (= (mail-header-number (car headers))
+                (mail-header-number (cadr headers))))
+    (pop headers))
+  ;; Then the rest.
+  (let ((result headers))
+    (while (> (length headers) 1)
+      (if (= (mail-header-number (car headers))
+            (mail-header-number (cadr headers)))
+         (setcdr headers (cddr headers))
+       (pop headers)))
+    result))
+
+(defun gnus-summary-refer-thread (&optional limit)
+  "Fetch all articles in the current thread. For backends that
+know how to search for threads (currently only 'nnimap) a
+non-numeric prefix arg will use nnir to search the entire
+server; without a prefix arg only the current group is
+searched. If the variable `gnus-refer-thread-use-nnir' is
+non-nil the prefix arg has the reverse meaning. If no
+backend-specific 'request-thread function is available fetch
+LIMIT (the numerical prefix) old headers. If LIMIT is
+non-numeric or nil fetch the number specified by the
+`gnus-refer-thread-limit' variable."
+  (interactive "P")
+  (gnus-warp-to-article)
+  (let* ((header (gnus-summary-article-header))
+        (id (mail-header-id header))
+        (gnus-inhibit-demon t)
+        (gnus-summary-ignore-duplicates t)
+        (gnus-read-all-available-headers t)
+        (gnus-refer-thread-use-nnir
+         (if (and (not (null limit)) (listp limit))
+             (not gnus-refer-thread-use-nnir) gnus-refer-thread-use-nnir))
+        (new-headers
+         (if (gnus-check-backend-function
+              'request-thread gnus-newsgroup-name)
+             (gnus-request-thread header gnus-newsgroup-name)
+           (let* ((limit (if (numberp limit) (prefix-numeric-value limit)
+                           gnus-refer-thread-limit))
+                  (last (if (numberp limit)
+                            (min (+ (mail-header-number header)
+                                    limit)
+                                 gnus-newsgroup-highest)
+                          gnus-newsgroup-highest))
+                  (subject (gnus-simplify-subject
+                            (mail-header-subject header)))
+                  (refs (split-string (or (mail-header-references header)
+                                          "")))
+                  (gnus-parse-headers-hook
+                   `(lambda () (goto-char (point-min))
+                     (keep-lines
+                      (regexp-opt ',(append refs (list id subject)))))))
+             (gnus-fetch-headers (list last) (if (numberp limit)
+                                                 (* 2 limit) limit) t))))
+        article-ids new-unreads)
+    (when (listp new-headers)
+      (dolist (header new-headers)
+       (push (mail-header-number header) article-ids))
+      (setq article-ids (nreverse article-ids))
+      (setq new-unreads
+           (gnus-sorted-intersection gnus-newsgroup-unselected article-ids))
+      (setq gnus-newsgroup-unselected
+           (gnus-sorted-ndifference gnus-newsgroup-unselected new-unreads))
+      (setq gnus-newsgroup-unreads
+           (gnus-sorted-nunion gnus-newsgroup-unreads new-unreads))
+      (setq gnus-newsgroup-headers
+            (gnus-delete-duplicate-headers
+             (gnus-merge
+              'list gnus-newsgroup-headers new-headers
+              'gnus-article-sort-by-number)))
+      (setq gnus-newsgroup-articles
+           (gnus-sorted-nunion gnus-newsgroup-articles article-ids))
+      (gnus-summary-limit-include-thread id)))
+  (gnus-summary-show-thread))
+
+(defun gnus-summary-open-group-with-article (message-id)
+  "Open a group containing the article with the given MESSAGE-ID."
+  (interactive "sMessage-ID: ")
+  (require 'nndoc)
+  (with-temp-buffer
+    ;; Prepare a dummy article
+    (erase-buffer)
+    (insert "From nobody Tue Sep 13 22:05:34 2011\n\n")
+
+    ;; Prepare pretty modelines for summary and article buffers
+    (let ((gnus-summary-mode-line-format "Found %G")
+          (gnus-article-mode-line-format
+           ;; Group names just get in the way here, especially the
+           ;; abbreviated ones
+           (if (string-match "%[gG]" gnus-article-mode-line-format)
+              (concat (substring gnus-article-mode-line-format
+                                 0 (match-beginning 0))
+                      (substring gnus-article-mode-line-format (match-end 0)))
+            gnus-article-mode-line-format)))
+
+      ;; Build an ephemeral group containing the dummy article (hidden)
+      (gnus-group-read-ephemeral-group
+       message-id
+       `(nndoc ,message-id
+              (nndoc-address ,(current-buffer))
+              (nndoc-article-type mbox))
+       :activate
+       (cons (current-buffer) gnus-current-window-configuration)
+       (not :request-only)
+       '(-1)                           ; :select-articles
+       (not :parameters)
+       0))                             ; :number
+    ;; Fetch the desired article
+    (gnus-summary-refer-article message-id)))
+
+(defun gnus-summary-refer-article (message-id)
+  "Fetch an article specified by MESSAGE-ID."
+  (interactive "sMessage-ID: ")
+  (gnus-warp-to-article)
+  (when (and (stringp message-id)
+            (not (zerop (length message-id))))
+    (setq message-id (gnus-replace-in-string message-id " " ""))
+    ;; Construct the correct Message-ID if necessary.
+    ;; Suggested by tale@pawl.rpi.edu.
+    (unless (string-match "^<" message-id)
+      (setq message-id (concat "<" message-id)))
+    (unless (string-match ">$" message-id)
+      (setq message-id (concat message-id ">")))
+    ;; People often post MIDs from URLs, so unhex it:
+    (unless (string-match "@" message-id)
+      (setq message-id (gnus-url-unhex-string message-id)))
+    (let* ((header (gnus-id-to-header message-id))
+          (sparse (and header
+                       (gnus-summary-article-sparse-p
+                        (mail-header-number header))
+                       (memq (mail-header-number header)
+                             gnus-newsgroup-limit)))
+          number)
+      (cond
+       ;; If the article is present in the buffer we just go to it.
+       ((and header
+            (or (not (gnus-summary-article-sparse-p
+                      (mail-header-number header)))
+                sparse))
+       (prog1
+           (gnus-summary-goto-article
+            (mail-header-number header) nil t)
+         (when sparse
+           (gnus-summary-update-article (mail-header-number header)))))
+       (t
+       ;; We fetch the article.
+       (catch 'found
+         (dolist (gnus-override-method (gnus-refer-article-methods))
+           (when (and (gnus-check-server gnus-override-method)
+                      ;; Fetch the header,
+                      (setq number (gnus-summary-insert-subject message-id)))
+             ;; and display the article.
+             (gnus-summary-select-article nil nil nil number)
+             (throw 'found t)))
+         (gnus-message 3 "Couldn't fetch article %s" message-id)))))))
+
+(defun gnus-refer-article-methods ()
+  "Return a list of referable methods."
+  (cond
+   ;; No method, so we default to current and native.
+   ((null gnus-refer-article-method)
+    (list gnus-current-select-method gnus-select-method))
+   ;; Current.
+   ((eq 'current gnus-refer-article-method)
+    (list gnus-current-select-method))
+   ;; List of select methods.
+   ((not (and (symbolp (car gnus-refer-article-method))
+             (assq (car gnus-refer-article-method) nnoo-definition-alist)))
+    (let (out)
+      (dolist (method gnus-refer-article-method)
+       (push (if (eq 'current method)
+                 gnus-current-select-method
+               (if (eq 'nnir (car method))
+                   (list
+                    'nnir
+                    (or (cadr method)
+                        (gnus-method-to-server gnus-current-select-method)))
+                 method))
+             out))
+      (nreverse out)))
+   ;; One single select method.
+   (t
+    (list gnus-refer-article-method))))
+
+(defun gnus-summary-edit-parameters ()
+  "Edit the group parameters of the current group."
+  (interactive)
+  (gnus-group-edit-group gnus-newsgroup-name 'params))
+
+(defun gnus-summary-customize-parameters ()
+  "Customize the group parameters of the current group."
+  (interactive)
+  (gnus-group-customize gnus-newsgroup-name))
+
+(defun gnus-summary-enter-digest-group (&optional force)
+  "Enter an nndoc group based on the current article.
+If FORCE, force a digest interpretation.  If not, try to guess
+what the document format is.
+
+To control what happens when you exit the group, see the
+`gnus-auto-select-on-ephemeral-exit' variable."
+  (interactive "P")
+  (let ((conf gnus-current-window-configuration))
+    (save-window-excursion
+      (save-excursion
+       (let (gnus-article-prepare-hook
+             gnus-display-mime-function
+             gnus-break-pages)
+         (gnus-summary-select-article))))
+    (setq gnus-current-window-configuration conf)
+    (let* ((name (format "%s-%d"
+                        (gnus-group-prefixed-name
+                         gnus-newsgroup-name (list 'nndoc ""))
+                        (with-current-buffer gnus-summary-buffer
+                          gnus-current-article)))
+          (ogroup gnus-newsgroup-name)
+          (params (append (gnus-info-params (gnus-get-info ogroup))
+                          (list (cons 'to-group ogroup))
+                          (list (cons 'parent-group ogroup))
+                          (list (cons 'save-article-group ogroup))))
+          (case-fold-search t)
+          (buf (current-buffer))
+          dig to-address charset)
+      (with-current-buffer gnus-original-article-buffer
+       ;; Have the digest group inherit the main mail address of
+       ;; the parent article.
+       (when (setq to-address (or (gnus-fetch-field "reply-to")
+                                  (gnus-fetch-field "from")))
+         (setq params
+               (append
+                params
+                (list (cons 'to-address
+                            (funcall gnus-decode-encoded-address-function
+                                     to-address))))))
+       (setq dig (nnheader-set-temp-buffer " *gnus digest buffer*"))
+       (insert-buffer-substring gnus-original-article-buffer)
+       (narrow-to-region
+        (goto-char (point-min))
+        (or (search-forward "\n\n" nil t) (point)))
+       ;; Remove lines that may lead nndoc to misinterpret the
+       ;; document type.
+       (goto-char (point-min))
+       (delete-matching-lines "^Path:\\|^From ")
+       ;; Parse charset, and decode content transfer encoding.
+       (setq charset (mail-content-type-get
+                      (mail-header-parse-content-type
+                       (or (gnus-fetch-field "content-type") ""))
+                      'charset))
+       (let ((encoding (gnus-fetch-field "content-transfer-encoding")))
+         (when encoding
+           (message-remove-header "content-transfer-encoding")
+           (goto-char (point-max))
+           (widen)
+           (narrow-to-region (point) (point-max))
+           (mm-decode-content-transfer-encoding
+            (intern (downcase (mail-header-strip encoding))))))
+       (widen))
+      (unwind-protect
+         (if (let ((gnus-newsgroup-ephemeral-charset
+                    (if charset
+                        (intern (downcase (gnus-strip-whitespace 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 nil nil nil
+                `((adapt-file . ,(gnus-score-file-name gnus-newsgroup-name
+                                                       "ADAPT")))))
+             ;; 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)
+  "Open a new group based on the current article(s).
+This will allow you to read digests and other similar
+documents as newsgroups.
+Obeys the standard process/prefix convention."
+  (interactive "P")
+  (let* ((ogroup gnus-newsgroup-name)
+        (params (append (gnus-info-params (gnus-get-info ogroup))
+                        (list (cons 'to-group ogroup))))
+        group egroup groups vgroup)
+    (dolist (article (gnus-summary-work-articles n))
+      (setq group (format "%s-%d" gnus-newsgroup-name article))
+      (gnus-summary-remove-process-mark article)
+      (when (gnus-summary-display-article article)
+       (save-excursion ;;What for?
+         (with-temp-buffer
+           (insert-buffer-substring gnus-original-article-buffer)
+           ;; Remove some headers that may lead nndoc to make
+           ;; the wrong guess.
+           (message-narrow-to-head)
+           (goto-char (point-min))
+           (delete-matching-lines "^Path:\\|^From ")
+           (widen)
+           (if (setq egroup
+                     (gnus-group-read-ephemeral-group
+                      group `(nndoc ,group (nndoc-address ,(current-buffer))
+                                    (nndoc-article-type guess))
+                      t nil t))
+               (progn
+                  ;; Make all postings to this group go to the parent group.
+                 (nconc (gnus-info-params (gnus-get-info egroup))
+                        params)
+                 (push egroup groups))
+             ;; Couldn't select this doc group.
+             (gnus-error 3 "Article couldn't be entered"))))))
+    ;; Now we have selected all the documents.
+    (cond
+     ((not groups)
+      (error "None of the articles could be interpreted as documents"))
+     ((gnus-group-read-ephemeral-group
+       (setq vgroup (format
+                    "nnvirtual:%s-%s" gnus-newsgroup-name
+                    (format-time-string "%Y%m%dT%H%M%S")))
+       `(nnvirtual ,vgroup (nnvirtual-component-groups ,groups))
+       t
+       (cons (current-buffer) 'summary)))
+     (t
+      (error "Couldn't select virtual nndoc group")))))
+
+(defun gnus-summary-widget-forward (arg)
+  "Move point to the next field or button in the article.
+With optional ARG, move across that many fields."
+  (interactive "p")
+  (gnus-summary-select-article)
+  (gnus-configure-windows 'article)
+  (select-window (gnus-get-buffer-window gnus-article-buffer))
+  (widget-forward arg))
+
+(defun gnus-summary-widget-backward (arg)
+  "Move point to the previous field or button in the article.
+With optional ARG, move across that many fields."
+  (interactive "p")
+  (gnus-summary-select-article)
+  (gnus-configure-windows 'article)
+  (select-window (gnus-get-buffer-window gnus-article-buffer))
+  (unless (widget-at (point))
+    (goto-char (point-max)))
+  (widget-backward arg))
+
+(defun gnus-summary-isearch-article (&optional regexp-p)
+  "Do incremental search forward on the current article.
+If REGEXP-P (the prefix) is non-nil, do regexp isearch."
+  (interactive "P")
+  (gnus-summary-select-article)
+  (gnus-configure-windows 'article)
+  (gnus-eval-in-buffer-window gnus-article-buffer
+    (save-restriction
+      (widen)
+      (isearch-forward regexp-p))))
+
+(defun gnus-summary-repeat-search-article-forward ()
+  "Repeat the previous search forwards."
+  (interactive)
+  (unless gnus-last-search-regexp
+    (error "No previous search"))
+  (gnus-summary-search-article-forward gnus-last-search-regexp))
+
+(defun gnus-summary-repeat-search-article-backward ()
+  "Repeat the previous search backwards."
+  (interactive)
+  (unless gnus-last-search-regexp
+    (error "No previous search"))
+  (gnus-summary-search-article-forward gnus-last-search-regexp t))
+
+(defun gnus-summary-search-article-forward (regexp &optional backward)
+  "Search for an article containing REGEXP forward.
+If BACKWARD, search backward instead."
+  (interactive
+   (list (read-string
+         (format "Search article %s (regexp%s): "
+                 (if current-prefix-arg "backward" "forward")
+                 (if gnus-last-search-regexp
+                     (concat ", default " gnus-last-search-regexp)
+                   "")))
+        current-prefix-arg))
+  (if (string-equal regexp "")
+      (setq regexp (or gnus-last-search-regexp ""))
+    (setq gnus-last-search-regexp regexp)
+    (setq gnus-article-before-search gnus-current-article))
+  ;; Intentionally set gnus-last-article.
+  (setq gnus-last-article gnus-article-before-search)
+  (let ((gnus-last-article gnus-last-article))
+    (if (gnus-summary-search-article regexp backward)
+       (gnus-summary-show-thread)
+      (signal 'search-failed (list regexp)))))
+
+(defun gnus-summary-search-article-backward (regexp)
+  "Search for an article containing REGEXP backward."
+  (interactive
+   (list (read-string
+         (format "Search article backward (regexp%s): "
+                 (if gnus-last-search-regexp
+                     (concat ", default " gnus-last-search-regexp)
+                   "")))))
+  (gnus-summary-search-article-forward regexp 'backward))
+
+(defun gnus-summary-search-article (regexp &optional backward)
+  "Search for an article containing REGEXP.
+Optional argument BACKWARD means do search for backward.
+`gnus-select-article-hook' is not called during the search."
+  ;; We have to require this here to make sure that the following
+  ;; dynamic binding isn't shadowed by autoloading.
+  (require 'gnus-async)
+  (require 'gnus-art)
+  (let ((gnus-select-article-hook nil) ;Disable hook.
+       (gnus-article-prepare-hook nil)
+       (gnus-mark-article-hook nil)    ;Inhibit marking as read.
+       (gnus-use-article-prefetch nil)
+       (gnus-xmas-force-redisplay nil) ;Inhibit XEmacs redisplay.
+       (gnus-use-trees nil)            ;Inhibit updating tree buffer.
+       (gnus-visual nil)
+       (gnus-keep-backlog nil)
+       (gnus-break-pages nil)
+       (gnus-summary-display-arrow nil)
+       (gnus-updated-mode-lines nil)
+       (gnus-auto-center-summary nil)
+       (sum (current-buffer))
+       (gnus-display-mime-function nil)
+       (found nil)
+       point)
+    (gnus-save-hidden-threads
+      (gnus-summary-select-article)
+      (set-buffer gnus-article-buffer)
+      (goto-char (window-point (get-buffer-window (current-buffer))))
+      (when backward
+       (forward-line -1))
+      (while (not found)
+       (gnus-message 7 "Searching article: %d..." (cdr gnus-article-current))
+       (if (if backward
+               (re-search-backward regexp nil t)
+             (re-search-forward regexp nil t))
+           ;; We found the regexp.
+           (progn
+             (setq found 'found)
+             (beginning-of-line)
+             (set-window-start
+              (get-buffer-window (current-buffer))
+              (point))
+             (forward-line 1)
+             (set-window-point
+              (get-buffer-window (current-buffer))
+              (point))
+             (set-buffer sum)
+             (setq point (point)))
+         ;; We didn't find it, so we go to the next article.
+         (set-buffer sum)
+         (setq found 'not)
+         (while (eq found 'not)
+           (if (not (if backward (gnus-summary-find-prev)
+                      (gnus-summary-find-next)))
+               ;; No more articles.
+               (setq found t)
+             ;; Select the next article and adjust point.
+             (unless (gnus-summary-article-sparse-p
+                      (gnus-summary-article-number))
+               (setq found nil)
+               (gnus-summary-select-article)
+               (set-buffer gnus-article-buffer)
+               (widen)
+               (goto-char (if backward (point-max) (point-min))))))))
+      (gnus-message 7 ""))
+    ;; Return whether we found the regexp.
+    (when (eq found 'found)
+      (goto-char point)
+      (sit-for 0) ;; Ensure that the point is visible in the summary window.
+      (gnus-summary-show-thread)
+      (gnus-summary-goto-subject gnus-current-article)
+      (gnus-summary-position-point)
+      t)))
+
+(defun gnus-find-matching-articles (header regexp)
+  "Return a list of all articles that match REGEXP on HEADER.
+This search includes all articles in the current group that Gnus has
+fetched headers for, whether they are displayed or not."
+  (let ((articles nil)
+       ;; Can't eta-reduce because it's a macro.
+       (func `(lambda (h) (,(intern (concat "mail-header-" header)) h)))
+       (case-fold-search t))
+    (dolist (header gnus-newsgroup-headers)
+      (when (string-match regexp (funcall func header))
+       (push (mail-header-number header) articles)))
+    (nreverse articles)))
+
+(defun gnus-summary-find-matching (header regexp &optional backward unread
+                                         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. 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)
+       (if (eq (car header) 'extra)
+           (setq func
+                 `(lambda (h)
+                    (or (cdr (assq ',(cdr header) (mail-header-extra h)))
+                        "")))
+         (error "%s is an invalid header" header))
+      (unless (fboundp (intern (concat "mail-header-" header)))
+       (error "%s is not a valid header" header))
+      (setq func `(lambda (h) (,(intern (concat "mail-header-" header)) h))))
+    (dolist (d (if (eq backward 'all)
+                  gnus-newsgroup-data
+                (gnus-data-find-list
+                 (gnus-summary-article-number)
+                 (gnus-data-list backward))))
+      (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.
+                (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)))
+
+(defun gnus-summary-execute-command (header regexp command &optional backward)
+  "Search forward for an article whose HEADER matches REGEXP and execute COMMAND.
+If HEADER is an empty string (or nil), the match is done on the entire
+article.  If BACKWARD (the prefix) is non-nil, search backward instead."
+  (interactive
+   (list (let ((completion-ignore-case t))
+          (gnus-completing-read
+           "Header name"
+           (mapcar 'symbol-name
+                   (append
+                    '(Number Subject From Lines Date
+                      Message-ID Xref References Body)
+                    gnus-extra-headers))
+           'require-match))
+        (read-string "Regexp: ")
+        (read-key-sequence "Command: ")
+        current-prefix-arg))
+  (when (equal header "Body")
+    (setq header ""))
+  ;; Hidden thread subtrees must be searched as well.
+  (gnus-summary-show-all-threads)
+  ;; We don't want to change current point nor window configuration.
+  (save-excursion
+    (save-window-excursion
+      (let (gnus-visual
+           gnus-treat-strip-trailing-blank-lines
+           gnus-treat-strip-leading-blank-lines
+           gnus-treat-strip-multiple-blank-lines
+           gnus-treat-hide-boring-headers
+           gnus-treat-fold-newsgroups
+           gnus-article-prepare-hook)
+       (gnus-message 6 "Executing %s..." (key-description command))
+       ;; We'd like to execute COMMAND interactively so as to give arguments.
+       (gnus-execute header regexp
+                     `(call-interactively ',(key-binding command))
+                     backward)
+       (gnus-message 6 "Executing %s...done" (key-description command))))))
+
+(defun gnus-summary-beginning-of-article ()
+  "Scroll the article back to the beginning."
+  (interactive)
+  (gnus-summary-select-article)
+  (gnus-configure-windows 'article)
+  (gnus-eval-in-buffer-window gnus-article-buffer
+    (widen)
+    (goto-char (point-min))
+    (when gnus-break-pages
+      (gnus-narrow-to-page))))
+
+(defun gnus-summary-end-of-article ()
+  "Scroll to the end of the article."
+  (interactive)
+  (gnus-summary-select-article)
+  (gnus-configure-windows 'article)
+  (gnus-eval-in-buffer-window gnus-article-buffer
+    (widen)
+    (goto-char (point-max))
+    (recenter -3)
+    (when gnus-break-pages
+      (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 process-marked (mail) articles.
+
+If used interactively, print the current article if none are
+process-marked.  With prefix arg, prompt the user for the name of the
+file to save in.
+
+When used from Lisp, accept two optional args FILENAME and N.  N means
+to print the next N articles.  If N is negative, print the N previous
+articles.  If N is nil and articles have been marked with the process
+mark, print these instead.
+
+If the optional first argument FILENAME is nil, send the image to the
+printer.  If FILENAME is a string, save the PostScript image in a file with
+that name.  If FILENAME is a number, prompt the user for the name of the file
+to save in."
+  (interactive (list (ps-print-preprint current-prefix-arg)))
+  (dolist (article (gnus-summary-work-articles n))
+    (gnus-summary-select-article nil nil 'pseudo article)
+    (gnus-eval-in-buffer-window gnus-article-buffer
+      (gnus-print-buffer))
+    (gnus-summary-remove-process-mark article))
+  (ps-despool filename))
+
+(defun gnus-print-buffer ()
+  (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 ps-print-color-p
+         (ps-spool-buffer-with-faces)
+       (ps-spool-buffer)))))
+
+(declare-function gnus-flush-original-article-buffer "gnus-art" ())
+
+(defun gnus-summary-show-complete-article ()
+  "Show a complete version of the current article.
+This is only useful if you're looking at a partial version of the
+article currently."
+  (interactive)
+  (let ((gnus-keep-backlog nil)
+       (gnus-use-cache nil)
+       (gnus-agent nil)
+       (variable (intern
+                  (format "%s-fetch-partial-articles"
+                          (car (gnus-find-method-for-group
+                                gnus-newsgroup-name)))
+                  obarray))
+       old-val)
+    (unwind-protect
+       (progn
+         (setq old-val (symbol-value variable))
+         (set variable nil)
+         (gnus-flush-original-article-buffer)
+         (gnus-summary-show-article))
+      (set variable old-val))))
+
+(defun gnus-summary-show-article (&optional arg)
+  "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
+input.
+If ARG (the prefix) is non-nil and not a number, show the article,
+but without running any of the article treatment functions
+article.  Normally, the keystroke is `C-u g'.  When using `C-u
+C-u g', show the raw article."
+  (interactive "P")
+  (cond
+   ((numberp arg)
+    (gnus-summary-show-article t)
+    (let ((gnus-newsgroup-charset
+          (or (cdr (assq arg gnus-summary-show-article-charset-alist))
+              (mm-read-coding-system
+               "View as charset: " ;; actually it is coding system.
+               (with-current-buffer gnus-article-buffer
+                 (mm-detect-coding-region (point) (point-max))))))
+         (gnus-newsgroup-ignored-charsets 'gnus-all))
+      (gnus-summary-select-article nil 'force)
+      (let ((deps gnus-newsgroup-dependencies)
+           head header lines)
+       (with-current-buffer gnus-original-article-buffer
+         (save-restriction
+           (message-narrow-to-head)
+           (setq head (buffer-string))
+           (goto-char (point-min))
+           (unless (re-search-forward "^lines:[ \t]\\([0-9]+\\)" nil t)
+             (goto-char (point-max))
+             (widen)
+             (setq lines (1- (count-lines (point) (point-max))))))
+         (with-temp-buffer
+           (insert (format "211 %d Article retrieved.\n"
+                           (cdr gnus-article-current)))
+           (insert head)
+           (if lines (insert (format "Lines: %d\n" lines)))
+           (insert ".\n")
+           (let ((nntp-server-buffer (current-buffer)))
+             (setq header (car (gnus-get-newsgroup-headers deps t))))))
+       (gnus-data-set-header
+        (gnus-data-find (cdr gnus-article-current))
+        header)
+       (gnus-summary-update-article-line
+        (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.
+    (if (eq mm-text-html-renderer 'shr)
+       (progn
+         (require 'shr)
+         (let ((shr-ignore-cache t))
+           (gnus-summary-select-article nil 'force)))
+      (gnus-summary-select-article nil 'force)))
+   ((equal arg '(16))
+    ;; C-u C-u g
+    (let ((gnus-inhibit-article-treatments t))
+      (gnus-summary-select-article nil 'force)))
+   (t
+    ;; We have to require this here to make sure that the following
+    ;; dynamic binding isn't shadowed by autoloading.
+    (require 'gnus-async)
+    (require 'gnus-art)
+    ;; Bind the article treatment functions to nil.
+    (let ((gnus-have-all-headers t)
+         gnus-article-prepare-hook
+         gnus-article-decode-hook
+         gnus-display-mime-function
+         gnus-break-pages)
+      ;; Destroy any MIME parts.
+      (when (gnus-buffer-live-p gnus-article-buffer)
+       (with-current-buffer gnus-article-buffer
+         (gnus-article-stop-animations)
+         (gnus-stop-downloads)
+         (mm-destroy-parts gnus-article-mime-handles)
+         ;; Set it to nil for safety reason.
+         (setq gnus-article-mime-handle-alist nil)
+         (setq gnus-article-mime-handles nil)))
+      (gnus-summary-select-article nil 'force))))
+  (gnus-summary-goto-subject gnus-current-article)
+  (gnus-summary-position-point))
+
+(defun gnus-summary-show-raw-article ()
+  "Show the raw article without any article massaging functions being run."
+  (interactive)
+  (gnus-summary-show-article t))
+
+(defun gnus-summary-verbose-headers (&optional arg)
+  "Toggle permanent full header display.
+If ARG is a positive number, turn header display on.
+If ARG is a negative number, turn header display off."
+  (interactive "P")
+  (setq gnus-show-all-headers
+       (cond ((or (not (numberp arg))
+                  (zerop arg))
+              (not gnus-show-all-headers))
+             ((natnump arg)
+              t)))
+  (gnus-summary-show-article))
+
+(declare-function article-narrow-to-head "gnus-art" ())
+(declare-function gnus-article-hidden-text-p "gnus-art" (type))
+(declare-function gnus-delete-wash-type "gnus-art" (type))
+(declare-function gnus-mime-buttonize-attachments-in-header
+                 "gnus-art" (&optional interactive))
+
+(defun gnus-summary-toggle-header (&optional arg)
+  "Show the headers if they are hidden, or hide them if they are shown.
+If ARG is a positive number, show the entire header.
+If ARG is a negative number, hide the unwanted header lines."
+  (interactive "P")
+  (let ((window (and (gnus-buffer-live-p gnus-article-buffer)
+                    (get-buffer-window gnus-article-buffer t))))
+    (with-current-buffer gnus-article-buffer
+      (widen)
+      (article-narrow-to-head)
+      (let* ((inhibit-read-only t)
+            (inhibit-point-motion-hooks t)
+            (hidden (if (numberp arg)
+                        (>= arg 0)
+                      (or (not (looking-at "[^ \t\n]+:"))
+                          (gnus-article-hidden-text-p 'headers))))
+            s e)
+       (delete-region (point-min) (point-max))
+       (with-current-buffer gnus-original-article-buffer
+         (goto-char (setq s (point-min)))
+         (setq e (if (search-forward "\n\n" nil t)
+                     (1- (point))
+                   (point-max))))
+       (insert-buffer-substring gnus-original-article-buffer s e)
+       (run-hooks 'gnus-article-decode-hook)
+       (if hidden
+           (let ((gnus-treat-hide-headers nil)
+                 (gnus-treat-hide-boring-headers nil))
+             (gnus-delete-wash-type 'headers)
+             (gnus-treat-article 'head))
+         (gnus-treat-article 'head)
+         ;; Add attachment buttons to the header.
+         (when gnus-mime-display-attachment-buttons-in-header
+           (gnus-mime-buttonize-attachments-in-header)))
+       (widen)
+       (if window
+           (set-window-start window (goto-char (point-min))))
+       (if gnus-break-pages
+           (gnus-narrow-to-page)
+         (when (gnus-visual-p 'page-marker)
+           (let ((inhibit-read-only t))
+             (gnus-remove-text-with-property 'gnus-prev)
+             (gnus-remove-text-with-property 'gnus-next))))
+       (gnus-set-mode-line 'article)))))
+
+(defun gnus-summary-show-all-headers ()
+  "Make all header lines visible."
+  (interactive)
+  (gnus-summary-toggle-header 1))
+
+(defun gnus-summary-caesar-message (&optional arg)
+  "Caesar rotate the current article by 13.
+With a non-numerical prefix, also rotate headers.  A numerical
+prefix specifies how many places to rotate each letter forward."
+  (interactive "P")
+  (gnus-summary-select-article)
+  (let ((mail-header-separator ""))
+    (gnus-eval-in-buffer-window gnus-article-buffer
+      (save-restriction
+       (widen)
+       (let ((start (window-start))
+             (inhibit-read-only t))
+         (if (equal arg '(4))
+             (message-caesar-buffer-body nil t)
+           (message-caesar-buffer-body arg))
+         (set-window-start (get-buffer-window (current-buffer)) start)))))
+  ;; Create buttons and stuff...
+  (gnus-treat-article nil))
+
+(declare-function idna-to-unicode "ext:idna" (str))
+
+(defun gnus-summary-idna-message (&optional arg)
+  "Decode IDNA encoded domain names in the current articles.
+IDNA encoded domain names looks like `xn--bar'.  If a string
+remain unencoded after running this function, it is likely an
+invalid IDNA string (`xn--bar' is invalid).
+
+You must have GNU Libidn (URL `http://www.gnu.org/software/libidn/')
+installed for this command to work."
+  (interactive "P")
+  (if (not (and (mm-coding-system-p 'utf-8)
+               (condition-case nil
+                   (require 'idna)
+                 (file-error)
+                 (invalid-operation))
+               (symbol-value 'idna-program)
+               (executable-find (symbol-value 'idna-program))))
+      (gnus-message
+       5 "GNU Libidn not installed properly (`idn' or `idna.el' missing)")
+    (gnus-summary-select-article)
+    (let ((mail-header-separator ""))
+      (gnus-eval-in-buffer-window gnus-article-buffer
+       (save-restriction
+         (widen)
+         (let ((start (window-start))
+               buffer-read-only)
+           (while (re-search-forward "\\(xn--[-0-9a-z]+\\)" nil t)
+             (replace-match (idna-to-unicode (match-string 1))))
+           (set-window-start (get-buffer-window (current-buffer)) start)))))))
+
+(defun gnus-summary-morse-message (&optional arg)
+  "Morse decode the current article."
+  (interactive "P")
+  (gnus-summary-select-article)
+  (let ((mail-header-separator ""))
+    (gnus-eval-in-buffer-window gnus-article-buffer
+      (save-excursion
+       (save-restriction
+         (widen)
+         (let ((pos (window-start))
+               (inhibit-read-only t))
+           (goto-char (point-min))
+           (when (message-goto-body)
+             (gnus-narrow-to-body))
+           (goto-char (point-min))
+           (while (search-forward "·" (point-max) t)
+             (replace-match "."))
+           (unmorse-region (point-min) (point-max))
+           (widen)
+           (set-window-start (get-buffer-window (current-buffer)) pos)))))))
+
+(defun gnus-summary-stop-page-breaking ()
+  "Stop page breaking in the current article."
+  (interactive)
+  (gnus-summary-select-article)
+  (gnus-eval-in-buffer-window gnus-article-buffer
+    (widen)
+    (when (gnus-visual-p 'page-marker)
+      (let ((inhibit-read-only t))
+       (gnus-remove-text-with-property 'gnus-prev)
+       (gnus-remove-text-with-property 'gnus-next))
+      (setq gnus-page-broken nil))))
+
+(defun gnus-summary-move-article (&optional n to-newsgroup
+                                           select-method action)
+  "Move the current article to a different newsgroup.
+If N is a positive number, move the N next articles.
+If N is a negative number, move the N previous articles.
+If N is nil and any articles have been marked with the process mark,
+move those articles instead.
+If TO-NEWSGROUP is string, do not prompt for a newsgroup to move to.
+If SELECT-METHOD is non-nil, do not move to a specific newsgroup, but
+re-spool using this method.
+
+When called interactively with TO-NEWSGROUP being nil, the value of
+the variable `gnus-move-split-methods' is used for finding a default
+for the target newsgroup.
+
+For this function to work, both the current newsgroup and the
+newsgroup that you want to move to have to support the `request-move'
+and `request-accept' functions.
+
+ACTION can be either `move' (the default), `crosspost' or `copy'."
+  (interactive "P")
+  (unless action
+    (setq action 'move))
+  ;; Check whether the source group supports the required functions.
+  (cond ((and (eq action 'move)
+             (not (gnus-check-backend-function
+                   'request-move-article gnus-newsgroup-name)))
+        (error "The current group does not support article moving"))
+       ((and (eq action 'crosspost)
+             (not (gnus-check-backend-function
+                   'request-replace-article gnus-newsgroup-name)))
+        (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)
+                   (funcall gnus-move-group-prefix-function
+                            gnus-newsgroup-name)
+                 ""))
+       (names '((move "Move" "Moving")
+                (copy "Copy" "Copying")
+                (crosspost "Crosspost" "Crossposting")))
+       (copy-buf (save-excursion
+                   (nnheader-set-temp-buffer " *copy article*")))
+       art-group to-method new-xref article to-groups
+       articles-to-update-marks encoded)
+    (unless (assq action names)
+      (error "Unknown action %s" action))
+    ;; Read the newsgroup name.
+    (when (and (not to-newsgroup)
+              (not select-method))
+      (if (and gnus-move-split-methods
+              (not
+               (and (memq gnus-current-article articles)
+                    (gnus-buffer-live-p gnus-original-article-buffer))))
+         ;; When `gnus-move-split-methods' is non-nil, we have to
+         ;; select an article to give `gnus-read-move-group-name' an
+         ;; opportunity to suggest an appropriate default.  However,
+         ;; we needn't render or mark the article.
+         (let ((gnus-display-mime-function nil)
+               (gnus-article-prepare-hook nil)
+               (gnus-mark-article-hook nil))
+           (gnus-summary-select-article nil nil nil (car articles))))
+      (setq to-newsgroup (gnus-read-move-group-name
+                         (cadr (assq action names))
+                         (symbol-value
+                          (intern (format "gnus-current-%s-group" action)))
+                         articles prefix)
+           encoded to-newsgroup
+           to-method (gnus-server-to-method (gnus-group-method to-newsgroup)))
+      (set (intern (format "gnus-current-%s-group" action))
+          (mm-decode-coding-string
+           to-newsgroup
+           (gnus-group-name-charset to-method to-newsgroup))))
+    (unless to-method
+      (setq to-method (or select-method
+                         (gnus-server-to-method
+                          (gnus-group-method to-newsgroup)))))
+    (setq to-newsgroup
+         (or encoded
+             (and to-newsgroup
+                  (mm-encode-coding-string
+                   to-newsgroup
+                   (gnus-group-name-charset to-method to-newsgroup)))))
+    ;; Check the method we are to move this article to...
+    (unless (gnus-check-backend-function
+            'request-accept-article (car to-method))
+      (error "%s does not support article copying" (car to-method)))
+    (unless (gnus-check-server to-method)
+      (error "Can't open server %s" (car to-method)))
+    (gnus-message 6 "%s to %s: %s..."
+                 (caddr (assq action names))
+                 (or (car select-method)
+                     (gnus-group-decoded-name to-newsgroup))
+                 articles)
+    (while articles
+      (setq article (pop articles))
+      ;; Set any marks that may have changed in the summary buffer.
+      (when gnus-preserve-marks
+       (gnus-summary-push-marks-to-backend article))
+      (setq
+       art-group
+       (cond
+       ;; Move the article.
+       ((eq action 'move)
+        ;; Remove this article from future suppression.
+        (gnus-dup-unsuppress-article article)
+        (let* ((from-method (gnus-find-method-for-group
+                             gnus-newsgroup-name))
+               (to-method (or select-method
+                              (gnus-find-method-for-group to-newsgroup)))
+               (move-is-internal (gnus-server-equal from-method to-method)))
+          (gnus-request-move-article
+           article                     ; Article to move
+           gnus-newsgroup-name         ; From newsgroup
+           (nth 1 (gnus-find-method-for-group
+                   gnus-newsgroup-name)) ; Server
+           (list 'gnus-request-accept-article
+                 to-newsgroup (list 'quote select-method)
+                 (not articles) t)     ; Accept form
+           (not articles)              ; Only save nov last time
+           (and move-is-internal
+                to-newsgroup           ; Not respooling
+                                       ; Is this move internal?
+                (gnus-group-real-name to-newsgroup)))))
+       ;; Copy the article.
+       ((eq action 'copy)
+        (with-current-buffer copy-buf
+          (when (gnus-request-article-this-buffer article
+                                                  gnus-newsgroup-name)
+            (save-restriction
+              (nnheader-narrow-to-headers)
+              (dolist (hdr gnus-copy-article-ignored-headers)
+                (message-remove-header hdr t)))
+            (gnus-request-accept-article
+             to-newsgroup select-method (not articles) t))))
+       ;; Crosspost the article.
+       ((eq action 'crosspost)
+        (let ((xref (message-tokenize-header
+                     (mail-header-xref (gnus-summary-article-header
+                                        article))
+                     " ")))
+          (setq new-xref (concat (gnus-group-real-name gnus-newsgroup-name)
+                                 ":" (number-to-string article)))
+          (unless xref
+            (setq xref (list (system-name))))
+          (setq new-xref
+                (concat
+                 (mapconcat 'identity
+                            (delete "Xref:" (delete new-xref xref))
+                            " ")
+                 " " new-xref))
+          (with-current-buffer copy-buf
+            ;; First put the article in the destination group.
+            (gnus-request-article-this-buffer article gnus-newsgroup-name)
+            (when (consp (setq art-group
+                               (gnus-request-accept-article
+                                to-newsgroup select-method (not articles)
+                                t)))
+              (setq new-xref (concat new-xref " " (car 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)
+              (gnus-request-replace-article
+               (cdr art-group) to-newsgroup (current-buffer) t)
+              art-group))))))
+      (cond
+       ((not art-group)
+       (gnus-message 1 "Couldn't %s article %s: %s"
+                     (cadr (assq action names)) article
+                     (nnheader-get-report (car to-method))))
+       ((eq art-group 'junk)
+       (when (eq action 'move)
+         (gnus-summary-mark-article article gnus-canceled-mark)
+         (gnus-message 4 "Deleted article %s" article)
+         ;; run the delete hook
+         (run-hook-with-args 'gnus-summary-article-delete-hook
+                             action
+                             (gnus-data-header
+                              (assoc article (gnus-data-list nil)))
+                             gnus-newsgroup-name nil
+                             select-method)))
+       (t
+       (let* ((pto-group (gnus-group-prefixed-name
+                          (car art-group) to-method))
+              (info (gnus-get-info pto-group))
+              (to-group (gnus-info-group info))
+              to-marks)
+         ;; Update the group that has been moved to.
+         (when (and info
+                    (memq action '(move copy)))
+           (unless (member to-group to-groups)
+             (push to-group to-groups))
+
+           (when (and (not (memq article gnus-newsgroup-unreads))
+                      (cdr art-group))
+             (push 'read to-marks)
+             (gnus-info-set-read
+              info (gnus-add-to-range (gnus-info-read info)
+                                      (list (cdr art-group)))))
+
+           ;; See whether the article is to be put in the cache.
+           (let* ((expirable (gnus-group-auto-expirable-p to-group))
+                  (marks (if expirable
+                             gnus-article-mark-lists
+                           (delete '(expirable . expire)
+                                   (copy-sequence
+                                    gnus-article-mark-lists))))
+                  (to-article (cdr art-group)))
+
+             ;; Enter the article into the cache in the new group,
+             ;; if that is required.
+             (when (and to-article
+                        gnus-use-cache)
+               (gnus-cache-possibly-enter-article
+                to-group to-article
+                (memq article gnus-newsgroup-marked)
+                (memq article gnus-newsgroup-dormant)
+                (memq article gnus-newsgroup-unreads)))
+
+             (when (and gnus-preserve-marks
+                        to-article)
+               ;; Copy any marks over to the new group.
+               (when (and (equal to-group gnus-newsgroup-name)
+                          (not (memq article gnus-newsgroup-unreads)))
+                 ;; Mark this article as read in this group.
+                 (push (cons to-article gnus-read-mark)
+                       gnus-newsgroup-reads)
+                 ;; Increase the active status of this group.
+                 (setcdr (gnus-active to-group) to-article)
+                 (setcdr gnus-newsgroup-active to-article))
+
+               (while marks
+                 (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)))
+
+               (when (and expirable
+                          gnus-mark-copied-or-moved-articles-as-expirable
+                          (not (memq 'expire to-marks)))
+                 ;; Mark this article as expirable.
+                 (push 'expire to-marks)
+                 (when (equal to-group gnus-newsgroup-name)
+                   (push to-article gnus-newsgroup-expirable))
+                 ;; Copy the expirable mark to other group.
+                 (gnus-add-marked-articles
+                  to-group 'expire (list to-article) info))
+
+               (when (and to-marks
+                          (gnus-method-option-p
+                           (gnus-find-method-for-group to-group)
+                           'server-marks))
+                 (gnus-request-set-mark
+                  to-group (list (list (list to-article) 'add to-marks)))))
+
+             (gnus-dribble-enter
+              (concat "(gnus-group-set-info '"
+                      (gnus-prin1-to-string (gnus-get-info to-group))
+                      ")")
+              (concat "^(gnus-group-set-info '(\""
+                      (regexp-quote to-group) "\""))))
+
+         ;; Update the Xref header in this article to point to
+         ;; the new crossposted article we have just created.
+         (when (eq action 'crosspost)
+           (with-current-buffer copy-buf
+             (gnus-request-article-this-buffer article gnus-newsgroup-name)
+             (nnheader-replace-header "Xref" new-xref)
+             (gnus-request-replace-article
+              article gnus-newsgroup-name (current-buffer) t)))
+
+         ;; run the move/copy/crosspost/respool hook
+         (run-hook-with-args 'gnus-summary-article-move-hook
+                             action
+                             (gnus-data-header
+                              (assoc article (gnus-data-list nil)))
+                             gnus-newsgroup-name
+                             to-newsgroup
+                             select-method))
+
+        ;;;!!!Why is this necessary?
+       (set-buffer gnus-summary-buffer)
+
+       (when (eq action 'move)
+         (save-excursion
+           (gnus-summary-goto-subject article)
+           (gnus-summary-mark-article article gnus-canceled-mark)))))
+      (push article articles-to-update-marks))
+
+    (save-excursion
+      (apply 'gnus-summary-remove-process-mark articles-to-update-marks))
+    ;; Re-activate all groups that have been moved to.
+    (with-current-buffer gnus-group-buffer
+      (let ((gnus-group-marked to-groups))
+       (gnus-group-get-new-news-this-group nil t)))
+
+    (gnus-kill-buffer copy-buf)
+    (gnus-summary-position-point)
+    (gnus-set-mode-line 'summary)))
+
+(defun gnus-summary-push-marks-to-backend (article)
+  (let ((set nil)
+       (del nil)
+       (marks gnus-article-mark-lists))
+    (unless (memq article gnus-newsgroup-unreads)
+      (push 'read set))
+    (while marks
+      (if (and (eq (gnus-article-mark-to-type (cdar marks)) 'list)
+              (memq article (symbol-value
+                             (intern (format "gnus-newsgroup-%s"
+                                             (caar marks))))))
+         (push (cdar marks) set)
+       (push (cdar marks) del))
+      (pop marks))
+    (gnus-request-set-mark gnus-newsgroup-name `(((,article) set ,set)
+                                                ((,article) del ,del)))))
+
+(defun gnus-summary-copy-article (&optional n to-newsgroup select-method)
+  "Copy the current article to some other group.
+If TO-NEWSGROUP is string, do not prompt for a newsgroup to copy to.
+When called interactively, if TO-NEWSGROUP is nil, use the value of
+the variable `gnus-move-split-methods' for finding a default target
+newsgroup.
+If SELECT-METHOD is non-nil, do not move to a specific newsgroup, but
+re-spool using this method."
+  (interactive "P")
+  (gnus-summary-move-article n to-newsgroup select-method 'copy))
+
+(defun gnus-summary-crosspost-article (&optional n)
+  "Crosspost the current article to some other group."
+  (interactive "P")
+  (gnus-summary-move-article n nil nil 'crosspost))
+
+(defcustom gnus-summary-respool-default-method nil
+  "Default method type for respooling an article.
+If nil, use to the current newsgroup method."
+  :type 'symbol
+  :group 'gnus-summary-mail)
+
+(defun gnus-summary-respool-article (&optional n method)
+  "Respool the current article.
+The article will be squeezed through the mail spooling process again,
+which means that it will be put in some mail newsgroup or other
+depending on `nnmail-split-methods'.
+If N is a positive number, respool the N next articles.
+If N is a negative number, respool the N previous articles.
+If N is nil and any articles have been marked with the process mark,
+respool those articles instead.
+
+Respooling can be done both from mail groups and \"real\" newsgroups.
+In the former case, the articles in question will be moved from the
+current group into whatever groups they are destined to.  In the
+latter case, they will be copied into the relevant groups."
+  (interactive
+   (list current-prefix-arg
+        (let* ((methods (mapcar #'car (gnus-methods-using 'respool)))
+               (methname
+                (symbol-name (or gnus-summary-respool-default-method
+                                 (car (gnus-find-method-for-group
+                                       gnus-newsgroup-name)))))
+               (method
+                (gnus-completing-read
+                 "Backend to use when respooling"
+                 methods t nil 'gnus-mail-method-history methname))
+               ms)
+          (cond
+           ((zerop (length (setq ms (gnus-servers-using-backend
+                                     (intern method)))))
+            (list (intern method) ""))
+           ((= 1 (length ms))
+            (car ms))
+           (t
+            (let ((ms-alist (mapcar (lambda (m) (cons (cadr m) m)) ms)))
+              (cdr (assoc (gnus-completing-read "Server name" ms-alist t)
+                          ms-alist))))))))
+  (unless method
+    (error "No method given for respooling"))
+  (if (assoc (symbol-name
+             (car (gnus-find-method-for-group gnus-newsgroup-name)))
+            (gnus-methods-using 'respool))
+      (gnus-summary-move-article n nil method)
+    (gnus-summary-copy-article n nil method)))
+
+(defun gnus-summary-import-article (file &optional edit)
+  "Import an arbitrary file into a mail newsgroup."
+  (interactive "fImport file: \nP")
+  (let ((group gnus-newsgroup-name)
+       (now (current-time))
+       atts lines group-art)
+    (unless (gnus-check-backend-function 'request-accept-article group)
+      (error "%s does not support article importing" group))
+    (or (file-readable-p file)
+       (not (file-regular-p file))
+       (error "Can't read %s" file))
+    (with-current-buffer (gnus-get-buffer-create " *import file*")
+      (erase-buffer)
+      (nnheader-insert-file-contents file)
+      (goto-char (point-min))
+      (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"
+               "Subject: " (read-string "Subject: ") "\n"
+               "Date: " (message-make-date (nth 5 atts)) "\n"
+               "Message-ID: " (message-make-message-id) "\n"
+               "Lines: " (int-to-string lines) "\n"
+               "Chars: " (int-to-string (nth 7 atts)) "\n\n"))
+      (setq group-art (gnus-request-accept-article group nil t))
+      (kill-buffer (current-buffer)))
+    (setq gnus-newsgroup-active (gnus-activate-group group))
+    (forward-line 1)
+    (gnus-summary-goto-article (cdr group-art) nil t)
+    (when edit
+      (gnus-summary-edit-article))))
+
+(defun gnus-summary-create-article ()
+  "Create an article in a mail newsgroup."
+  (interactive)
+  (let ((group gnus-newsgroup-name)
+       (now (current-time))
+       group-art)
+    (unless (gnus-check-backend-function 'request-accept-article group)
+      (error "%s does not support article importing" group))
+    (with-current-buffer (gnus-get-buffer-create " *import file*")
+      (erase-buffer)
+      (goto-char (point-min))
+      ;; This doesn't look like an article, so we fudge some headers.
+      (insert "From: " (read-string "From: ") "\n"
+             "Subject: " (read-string "Subject: ") "\n"
+             "Date: " (message-make-date now) "\n"
+             "Message-ID: " (message-make-message-id) "\n")
+      (setq group-art (gnus-request-accept-article group nil t))
+      (kill-buffer (current-buffer)))
+    (setq gnus-newsgroup-active (gnus-activate-group group))
+    (forward-line 1)
+    (gnus-summary-goto-article (cdr group-art) nil t)
+    (gnus-summary-edit-article)))
+
+(defun gnus-summary-article-posted-p ()
+  "Say whether the current (mail) article is available from news as well.
+This will be the case if the article has both been mailed and posted."
+  (interactive)
+  (let ((id (mail-header-references (gnus-summary-article-header)))
+       (gnus-override-method (car (gnus-refer-article-methods))))
+    (if (gnus-request-head id "")
+       (gnus-message 2 "The current message was found on %s"
+                     gnus-override-method)
+      (gnus-message 2 "The current message couldn't be found on %s"
+                   gnus-override-method)
+      nil)))
+
+(defun gnus-summary-expire-articles (&optional now)
+  "Expire all articles that are marked as expirable in the current group."
+  (interactive)
+  (when (and (not gnus-group-is-exiting-without-update-p)
+            (gnus-check-backend-function
+             'request-expire-articles gnus-newsgroup-name))
+    ;; This backend supports expiry.
+    (let* ((total (gnus-group-total-expirable-p gnus-newsgroup-name))
+          (expirable
+           (gnus-list-range-difference
+            (if total
+                (progn
+                  ;; We need to update the info for
+                  ;; this group for `gnus-list-of-read-articles'
+                  ;; to give us the right answer.
+                  (gnus-run-hooks 'gnus-exit-group-hook)
+                  (gnus-summary-update-info)
+                  (gnus-list-of-read-articles gnus-newsgroup-name))
+              (setq gnus-newsgroup-expirable
+                    (sort gnus-newsgroup-expirable '<)))
+            gnus-newsgroup-unexist))
+          (expiry-wait (if now 'immediate
+                         (gnus-group-find-parameter
+                          gnus-newsgroup-name 'expiry-wait)))
+          (nnmail-expiry-target
+           (or (gnus-group-find-parameter gnus-newsgroup-name 'expiry-target)
+               nnmail-expiry-target))
+          es)
+      (when expirable
+       ;; There are expirable articles in this group, so we run them
+       ;; through the expiry process.
+       (gnus-message 6 "Expiring articles...")
+       (when (gnus-check-group gnus-newsgroup-name)
+         ;; The list of articles that weren't expired is returned.
+         (save-excursion
+           (if expiry-wait
+               (let ((nnmail-expiry-wait-function nil)
+                     (nnmail-expiry-wait expiry-wait))
+                 (setq es (gnus-request-expire-articles
+                           expirable gnus-newsgroup-name)))
+             (setq es (gnus-request-expire-articles
+                       expirable gnus-newsgroup-name)))
+           (unless total
+             (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.
+             (let ((gnus-use-cache nil))
+               (dolist (article expirable)
+                 (when (and (not (memq article es))
+                            (gnus-data-find article))
+                   (gnus-summary-mark-article article gnus-canceled-mark)
+                   (run-hook-with-args
+                    'gnus-summary-article-expire-hook
+                    'delete
+                    (gnus-data-header (assoc article (gnus-data-list nil)))
+                    gnus-newsgroup-name
+                    (cond
+                     ((stringp nnmail-expiry-target) nnmail-expiry-target)
+                     ((eq nnmail-expiry-target 'delete) nil)
+                     (t
+                      (let ((rescall (funcall nnmail-expiry-target
+                                              gnus-newsgroup-name)))
+                        (if (stringp rescall) rescall nil))))
+                    nil)))))))
+       (gnus-message 6 "Expiring articles...done")))))
+
+(defun gnus-summary-expire-articles-now ()
+  "Expunge all expirable articles in the current group.
+This means that *all* articles that are marked as expirable will be
+deleted forever, right now."
+  (interactive)
+  (or gnus-expert-user
+      (gnus-yes-or-no-p
+       "Are you really, really sure you want to delete all expirable messages? ")
+      (error "Phew!"))
+  (gnus-summary-expire-articles t))
+
+;; Suggested by Jack Vinson <vinson@unagi.cis.upenn.edu>.
+(defun gnus-summary-delete-article (&optional n)
+  "Delete the N next (mail) articles.
+This command actually deletes articles.  This is not a marking
+command.  The article will disappear forever from your life, never to
+return.
+
+If N is negative, delete backwards.
+If N is nil and articles have been marked with the process mark,
+delete these instead.
+
+If `gnus-novice-user' is non-nil you will be asked for
+confirmation before the articles are deleted."
+  (interactive "P")
+  (unless (gnus-check-backend-function 'request-expire-articles
+                                      gnus-newsgroup-name)
+    (error "The current newsgroup does not support article deletion"))
+  (unless (gnus-check-server (gnus-find-method-for-group gnus-newsgroup-name))
+    (error "Couldn't open server"))
+  ;; Compute the list of articles to delete.
+  (let ((articles (sort (copy-sequence (gnus-summary-work-articles n)) '<))
+       (nnmail-expiry-target 'delete)
+       not-deleted)
+    (if (and gnus-novice-user
+            (not (gnus-yes-or-no-p
+                  (format "Do you really want to delete %s forever? "
+                          (if (> (length articles) 1)
+                              (format "these %s articles" (length articles))
+                            "this article")))))
+       ()
+      ;; Delete the articles.
+      (setq not-deleted (gnus-request-expire-articles
+                        articles gnus-newsgroup-name 'force))
+      (save-excursion
+       (while articles
+         (gnus-summary-remove-process-mark (car articles))
+         ;; The backend might not have been able to delete the article
+         ;; after all.
+         (unless (memq (car articles) not-deleted)
+           (gnus-summary-mark-article (car articles) gnus-canceled-mark)
+           (let* ((article (car articles))
+                  (ghead  (gnus-data-header
+                           (assoc article (gnus-data-list nil)))))
+             (run-hook-with-args 'gnus-summary-article-delete-hook
+                                 'delete ghead gnus-newsgroup-name nil
+                                 nil)))
+         (setq articles (cdr articles))))
+      (when not-deleted
+       (gnus-message 4 "Couldn't delete articles %s" not-deleted)))
+    (gnus-summary-position-point)
+    (gnus-set-mode-line 'summary)
+    not-deleted))
+
+(defun gnus-summary-edit-article (&optional arg)
+  "Edit the current article.
+This will have permanent effect only in mail groups.
+If ARG is nil, edit the decoded articles.
+If ARG is 1, edit the raw articles.
+If ARG is 2, edit the raw articles even in read-only groups.
+If ARG is 3, edit the articles with the current handles.
+Otherwise, allow editing of articles even in read-only
+groups."
+  (interactive "P")
+  (let (force raw current-handles)
+    (cond
+     ((null arg))
+     ((eq arg 1)
+      (setq raw t))
+     ((eq arg 2)
+      (setq raw t
+           force t))
+     ((eq arg 3)
+      (setq current-handles
+           (and (gnus-buffer-live-p gnus-article-buffer)
+                (with-current-buffer gnus-article-buffer
+                  (prog1
+                      gnus-article-mime-handles
+                    (setq gnus-article-mime-handles nil))))))
+     (t
+      (setq force t)))
+    (when (and raw (not force)
+              (member gnus-newsgroup-name '("nndraft:delayed"
+                                            "nndraft:drafts"
+                                            "nndraft:queue")))
+      (error "Can't edit the raw article in group %s"
+            gnus-newsgroup-name))
+    (with-current-buffer gnus-summary-buffer
+      (let ((mail-parse-charset gnus-newsgroup-charset)
+           (mail-parse-ignored-charsets gnus-newsgroup-ignored-charsets))
+       (gnus-set-global-variables)
+       (when (and (not force)
+                  (gnus-group-read-only-p))
+         (error "The current newsgroup does not support article editing"))
+       (gnus-summary-show-article t)
+       (when (and (not raw) (gnus-buffer-live-p gnus-article-buffer))
+         (with-current-buffer gnus-article-buffer
+           (mm-enable-multibyte)))
+       (if (member gnus-newsgroup-name '("nndraft:delayed" "nndraft:drafts"))
+           (setq raw t))
+       (gnus-article-edit-article
+        (if raw 'ignore
+          `(lambda ()
+             (let ((mbl mml-buffer-list))
+               (setq mml-buffer-list nil)
+               (let ((rfc2047-quote-decoded-words-containing-tspecials t))
+                 (mime-to-mml ,'current-handles))
+               (let ((mbl1 mml-buffer-list))
+                 (setq mml-buffer-list mbl)
+                 (set (make-local-variable 'mml-buffer-list) mbl1))
+               (gnus-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)
+                 (message-options message-options)
+                 (message-options-set-recipient)
+                 (mail-parse-ignored-charsets
+                  ',gnus-newsgroup-ignored-charsets)
+                 (rfc2047-header-encoding-alist
+                  ',(let ((charset (gnus-group-name-charset
+                                    (gnus-find-method-for-group
+                                     gnus-newsgroup-name)
+                                    gnus-newsgroup-name)))
+                      (append (list (cons "Newsgroups" charset)
+                                    (cons "Followup-To" charset)
+                                    (cons "Xref" charset))
+                              rfc2047-header-encoding-alist))))
+             ,(if (not raw) '(progn
+                               (mml-to-mime)
+                               (mml-destroy-buffers)
+                               (remove-hook 'kill-buffer-hook
+                                            'mml-destroy-buffers t)
+                               (kill-local-variable 'mml-buffer-list)))
+             (gnus-summary-edit-article-done
+              ,(or (mail-header-references gnus-current-headers) "")
+              ,(gnus-group-read-only-p)
+              ,gnus-summary-buffer no-highlight))))))))
+
+(defalias 'gnus-summary-edit-article-postpone 'gnus-article-edit-exit)
+
+(defun gnus-summary-edit-article-done (&optional references read-only buffer
+                                                no-highlight)
+  "Make edits to the current article permanent."
+  (interactive)
+  (save-excursion
+    ;; 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)))
+           (case-fold-search t)
+           (body (point-marker)))
+       (goto-char (point-min))
+       (when (re-search-forward "^content-length:[ \t]\\([0-9]+\\)" body t)
+         (delete-region (match-beginning 1) (match-end 1))
+         (insert (number-to-string length)))
+       (goto-char (point-min))
+       (when (re-search-forward
+              "^x-content-length:[ \t]\\([0-9]+\\)" body t)
+         (delete-region (match-beginning 1) (match-end 1))
+         (insert (number-to-string length)))
+       (goto-char (point-min))
+       (when (re-search-forward "^lines:[ \t]\\([0-9]+\\)" body t)
+         (delete-region (match-beginning 1) (match-end 1))
+         (insert (number-to-string lines))))))
+  ;; Replace the article.
+  (let ((buf (current-buffer))
+       (article (cdr gnus-article-current))
+       replace-result)
+    (with-temp-buffer
+      (insert-buffer-substring buf)
+      (if (and (not read-only)
+              (not (setq replace-result
+                         (gnus-request-replace-article
+                          article (car gnus-article-current)
+                          (current-buffer) t))))
+         (error "Couldn't replace article")
+       ;; If we got a number back, then that's the new article number
+       ;; for this article.  Otherwise, the article number didn't change.
+       (when (numberp replace-result)
+         (with-current-buffer gnus-summary-buffer
+           (setq gnus-newsgroup-limit (delq article gnus-newsgroup-limit))
+           (gnus-summary-limit gnus-newsgroup-limit)
+           (setq article replace-result)
+           (gnus-summary-goto-subject article t)))
+       ;; Update the summary buffer.
+       (if (and references
+                (equal (message-tokenize-header references " ")
+                       (message-tokenize-header
+                        (or (message-fetch-field "references") "") " ")))
+           ;; We only have to update this line.
+           (save-excursion
+             (save-restriction
+               (message-narrow-to-head)
+               (let ((head (buffer-substring-no-properties
+                            (point-min) (point-max)))
+                     header)
+                 (with-temp-buffer
+                   (insert (format "211 %d Article retrieved.\n" article))
+                   (insert head)
+                   (insert ".\n")
+                   (let ((nntp-server-buffer (current-buffer)))
+                     (setq header (car (gnus-get-newsgroup-headers nil t))))
+                   (with-current-buffer gnus-summary-buffer
+                     (gnus-data-set-header (gnus-data-find article) header)
+                     (gnus-summary-update-article-line article header)
+                     (if (gnus-summary-goto-subject article nil t)
+                         (gnus-summary-update-secondary-mark article)))))))
+         ;; Update threads.
+         (set-buffer (or buffer gnus-summary-buffer))
+         (gnus-summary-update-article article)
+         (if (gnus-summary-goto-subject article nil t)
+             (gnus-summary-update-secondary-mark article)))
+       ;; Prettify the article buffer again.
+       (unless no-highlight
+         (with-current-buffer gnus-article-buffer
+           ;;!!! Fix this -- article should be rehighlighted.
+           ;;(gnus-run-hooks 'gnus-article-display-hook)
+           (set-buffer gnus-original-article-buffer)
+           (gnus-request-article
+            article (car gnus-article-current) (current-buffer))))
+       ;; Prettify the summary buffer line.
+       (when (gnus-visual-p 'summary-highlight 'highlight)
+         (gnus-run-hooks 'gnus-visual-mark-article-hook))))))
+
+(defun gnus-summary-edit-wash (key)
+  "Perform editing command KEY in the article buffer."
+  (interactive
+   (list
+    (progn
+      (message "%s" (concat (this-command-keys) "- "))
+      (read-char))))
+  (message "")
+  (gnus-summary-edit-article)
+  (execute-kbd-macro (concat (this-command-keys) key))
+  (gnus-article-edit-done))
+
+;;; Respooling
+
+(defvar nnimap-split-fancy)
+(defvar nnimap-split-methods)
+
+(defun gnus-summary-respool-query (&optional silent trace)
+  "Query where the respool algorithm would put this article."
+  (interactive)
+  (let (gnus-mark-article-hook)
+    (gnus-summary-select-article)
+    (with-current-buffer gnus-original-article-buffer
+      (let ((groups
+            (if (eq (car (gnus-find-method-for-group gnus-newsgroup-name))
+                    'nnimap)
+                ;; nnimap has its own splitting variables.
+                (let ((nnmail-split-methods
+                       (cond
+                        ((eq nnimap-split-methods 'default)
+                         nnmail-split-methods)
+                        (nnimap-split-methods
+                         nnimap-split-methods)
+                        (nnimap-split-fancy
+                         'nnmail-split-fancy)))
+                      (nnmail-split-fancy (or nnimap-split-fancy
+                                              nnmail-split-fancy)))
+                  (nnmail-article-group 'identity trace))
+              (nnmail-article-group 'identity trace))))
+       (unless silent
+         (if groups
+             (message "This message would go to %s"
+                      (mapconcat 'car groups ", "))
+           (message "This message would go to no groups"))
+         groups)))))
+
+(defun gnus-summary-respool-trace ()
+  "Trace where the respool algorithm would put this article.
+Display a buffer showing all fancy splitting patterns which matched."
+  (interactive)
+  (gnus-summary-respool-query nil t))
+
+;; Summary marking commands.
+
+(defun gnus-summary-kill-same-subject-and-select (&optional unmark)
+  "Mark articles which has the same subject as read, and then select the next.
+If UNMARK is positive, remove any kind of mark.
+If UNMARK is negative, tick articles."
+  (interactive "P")
+  (when unmark
+    (setq unmark (prefix-numeric-value unmark)))
+  (let ((count
+        (gnus-summary-mark-same-subject
+         (gnus-summary-article-subject) unmark)))
+    ;; Select next unread article.  If auto-select-same mode, should
+    ;; select the first unread article.
+    (gnus-summary-next-article t (and gnus-auto-select-same
+                                     (gnus-summary-article-subject)))
+    (gnus-message 7 "%d article%s marked as %s"
+                 count (if (= count 1) " is" "s are")
+                 (if unmark "unread" "read"))))
+
+(defun gnus-summary-kill-same-subject (&optional unmark)
+  "Mark articles which has the same subject as read.
+If UNMARK is positive, remove any kind of mark.
+If UNMARK is negative, tick articles."
+  (interactive "P")
+  (when unmark
+    (setq unmark (prefix-numeric-value unmark)))
+  (let ((count
+        (gnus-summary-mark-same-subject
+         (gnus-summary-article-subject) unmark)))
+    ;; If marked as read, go to next unread subject.
+    (when (null unmark)
+      ;; Go to next unread subject.
+      (gnus-summary-next-subject 1 t))
+    (gnus-message 7 "%d articles are marked as %s"
+                 count (if unmark "unread" "read"))))
+
+(defun gnus-summary-mark-same-subject (subject &optional unmark)
+  "Mark articles with same SUBJECT as read, and return marked number.
+If optional argument UNMARK is positive, remove any kinds of marks.
+If optional argument UNMARK is negative, mark articles as unread instead."
+  (let ((count 1))
+    (save-excursion
+      (cond
+       ((null unmark)                  ; Mark as read.
+       (while (and
+               (progn
+                 (gnus-summary-mark-article-as-read gnus-killed-mark)
+                 (gnus-summary-show-thread) t)
+               (gnus-summary-find-subject subject))
+         (setq count (1+ count))))
+       ((> unmark 0)                   ; Tick.
+       (while (and
+               (progn
+                 (gnus-summary-mark-article-as-unread gnus-ticked-mark)
+                 (gnus-summary-show-thread) t)
+               (gnus-summary-find-subject subject))
+         (setq count (1+ count))))
+       (t                              ; Mark as unread.
+       (while (and
+               (progn
+                 (gnus-summary-mark-article-as-unread gnus-unread-mark)
+                 (gnus-summary-show-thread) t)
+               (gnus-summary-find-subject subject))
+         (setq count (1+ count)))))
+      (gnus-set-mode-line 'summary)
+      ;; Return the number of marked articles.
+      count)))
+
+(defun gnus-summary-mark-as-processable (n &optional unmark)
+  "Set the process mark on the next N articles.
+If N is negative, mark backward instead.  If UNMARK is non-nil, remove
+the process mark instead.  The difference between N and the actual
+number of articles marked is returned."
+  (interactive "P")
+  (if (and (null n) (gnus-region-active-p))
+      (gnus-uu-mark-region (region-beginning) (region-end) unmark)
+    (setq n (prefix-numeric-value n))
+    (let ((backward (< n 0))
+         (n (abs n)))
+      (while (and
+             (> n 0)
+             (if unmark
+                 (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)))
+      (when (/= 0 n)
+       (gnus-message 7 "No more articles"))
+      (gnus-summary-recenter)
+      (gnus-summary-position-point)
+      n)))
+
+(defun gnus-summary-unmark-as-processable (n)
+  "Remove the process mark from the next N articles.
+If N is negative, unmark backward instead.  The difference between N and
+the actual number of articles unmarked is returned."
+  (interactive "P")
+  (gnus-summary-mark-as-processable n t))
+
+(defun gnus-summary-unmark-all-processable ()
+  "Remove the process mark from all articles."
+  (interactive)
+  (save-excursion
+    (while gnus-newsgroup-processable
+      (gnus-summary-remove-process-mark (car gnus-newsgroup-processable))))
+  (gnus-summary-position-point))
+
+(defun gnus-summary-add-mark (article type)
+  "Mark ARTICLE with a mark of TYPE."
+  (let ((vtype (car (assq type gnus-article-mark-lists)))
+       var)
+    (if (not vtype)
+       (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 recent saved))
+         (gnus-summary-update-secondary-mark article)
+       ;;; !!! This is bogus.  We should find out what primary
+       ;;; !!! mark we want to set.
+       (gnus-summary-update-mark gnus-del-mark 'unread)))))
+
+(defun gnus-summary-mark-as-expirable (n)
+  "Mark N articles forward as expirable.
+If N is negative, mark backward instead.  The difference between N and
+the actual number of articles marked is returned."
+  (interactive "p")
+  (gnus-summary-mark-forward n gnus-expirable-mark))
+
+(defun gnus-summary-mark-as-spam (n)
+  "Mark N articles forward as spam.
+If N is negative, mark backward instead.  The difference between N and
+the actual number of articles marked is returned."
+  (interactive "p")
+  (gnus-summary-mark-forward n gnus-spam-mark))
+
+(defun gnus-summary-mark-article-as-replied (article)
+  "Mark ARTICLE as replied to and update the summary line.
+ARTICLE can also be a list of articles."
+  (interactive (list (gnus-summary-article-number)))
+  (let ((articles (if (listp article) article (list article))))
+    (dolist (article articles)
+      (unless (numberp article)
+       (error "%s is not a number" article))
+      (push article gnus-newsgroup-replied)
+      (let ((inhibit-read-only t))
+       (when (gnus-summary-goto-subject article nil t)
+         (gnus-summary-update-secondary-mark article))))))
+
+(defun gnus-summary-mark-article-as-forwarded (article)
+  "Mark ARTICLE as forwarded and update the summary line.
+ARTICLE can also be a list of articles."
+  (let ((articles (if (listp article) article (list article))))
+    (dolist (article articles)
+      (push article gnus-newsgroup-forwarded)
+      (let ((inhibit-read-only t))
+       (when (gnus-summary-goto-subject article nil t)
+         (gnus-summary-update-secondary-mark article))))))
+
+(defun gnus-summary-set-bookmark (article)
+  "Set a bookmark in current article."
+  (interactive (list (gnus-summary-article-number)))
+  (when (or (not (get-buffer gnus-article-buffer))
+           (not gnus-current-article)
+           (not gnus-article-current)
+           (not (equal gnus-newsgroup-name (car gnus-article-current))))
+    (error "No current article selected"))
+  ;; Remove old bookmark, if one exists.
+  (gnus-alist-pull article gnus-newsgroup-bookmarks)
+  ;; Set the new bookmark, which is on the form
+  ;; (article-number . line-number-in-body).
+  (push
+   (cons article
+        (with-current-buffer gnus-article-buffer
+          (count-lines
+           (min (point)
+                (save-excursion
+                  (article-goto-body)
+                  (point)))
+           (point))))
+   gnus-newsgroup-bookmarks)
+  (gnus-message 6 "A bookmark has been added to the current article."))
+
+(defun gnus-summary-remove-bookmark (article)
+  "Remove the bookmark from the current article."
+  (interactive (list (gnus-summary-article-number)))
+  ;; Remove old bookmark, if one exists.
+  (if (not (assq article gnus-newsgroup-bookmarks))
+      (gnus-message 6 "No bookmark in current article.")
+    (gnus-alist-pull article gnus-newsgroup-bookmarks)
+    (gnus-message 6 "Removed bookmark.")))
+
+;; Suggested by Daniel Quinlan <quinlan@best.com>.
+(defun gnus-summary-mark-as-dormant (n)
+  "Mark N articles forward as dormant.
+If N is negative, mark backward instead.  The difference between N and
+the actual number of articles marked is returned."
+  (interactive "p")
+  (gnus-summary-mark-forward n gnus-dormant-mark))
+
+(defun gnus-summary-set-process-mark (article)
+  "Set the process mark on ARTICLE and update the summary line."
+  (setq gnus-newsgroup-processable
+       (cons article
+             (delq article gnus-newsgroup-processable)))
+  (when (gnus-summary-goto-subject article)
+    (gnus-summary-show-thread)
+    (gnus-summary-goto-subject article)
+    (gnus-summary-update-secondary-mark article)))
+
+(defun gnus-summary-remove-process-mark (&rest articles)
+  "Remove the process mark from ARTICLES and update the summary line."
+  (dolist (article articles)
+    (setq gnus-newsgroup-processable (delq article gnus-newsgroup-processable))
+    (when (gnus-summary-goto-subject article)
+      (gnus-summary-show-thread)
+      (gnus-summary-goto-subject article)
+      (gnus-summary-update-secondary-mark article)))
+  t)
+
+(defun gnus-summary-set-saved-mark (article)
+  "Set the process mark on ARTICLE and update the summary line."
+  (push article gnus-newsgroup-saved)
+  (when (gnus-summary-goto-subject article)
+    (gnus-summary-update-secondary-mark article)))
+
+(defun gnus-summary-mark-forward (n &optional mark no-expire)
+  "Mark N articles as read forwards.
+If N is negative, mark backwards instead.  Mark with MARK, ?r by default.
+The difference between N and the actual number of articles marked is
+returned.
+If NO-EXPIRE, auto-expiry will be inhibited."
+  (interactive "p")
+  (gnus-summary-show-thread)
+  (let ((backward (< n 0))
+       (gnus-summary-goto-unread
+        (and gnus-summary-goto-unread
+             (not (eq gnus-summary-goto-unread 'never))
+             (not (memq mark (list gnus-unread-mark gnus-spam-mark
+                                   gnus-ticked-mark gnus-dormant-mark)))))
+       (n (abs n))
+       (mark (or mark gnus-del-mark)))
+    (while (and (> n 0)
+               (gnus-summary-mark-article nil mark no-expire)
+               (zerop (gnus-summary-next-subject
+                       (if backward -1 1)
+                       (and gnus-summary-goto-unread
+                            (not (eq gnus-summary-goto-unread 'never)))
+                       t)))
+      (setq n (1- n)))
+    (when (/= 0 n)
+      (gnus-message 7 "No more %sarticles" (if mark "" "unread ")))
+    (gnus-summary-recenter)
+    (gnus-summary-position-point)
+    (gnus-set-mode-line 'summary)
+    n))
+
+(defun gnus-summary-mark-article-as-read (mark)
+  "Mark the current article quickly as read with MARK."
+  (let ((article (gnus-summary-article-number)))
+    (setq gnus-newsgroup-unreads (delq article gnus-newsgroup-unreads))
+    (setq gnus-newsgroup-marked (delq article gnus-newsgroup-marked))
+    (setq gnus-newsgroup-spam-marked (delq article gnus-newsgroup-spam-marked))
+    (setq gnus-newsgroup-dormant (delq article gnus-newsgroup-dormant))
+    (push (cons article mark) gnus-newsgroup-reads)
+    ;; Possibly remove from cache, if that is used.
+    (when gnus-use-cache
+      (gnus-cache-enter-remove-article article))
+    ;; Allow the backend to change the mark.
+    (setq mark (gnus-request-update-mark gnus-newsgroup-name article mark))
+    ;; Check for auto-expiry.
+    (when (and gnus-newsgroup-auto-expire
+              (memq mark gnus-auto-expirable-marks))
+      (setq mark gnus-expirable-mark)
+      ;; Let the backend know about the mark change.
+      (setq mark (gnus-request-update-mark gnus-newsgroup-name article mark))
+      (push article gnus-newsgroup-expirable))
+    ;; Set the mark in the buffer.
+    (gnus-summary-update-mark mark 'unread)
+    t))
+
+(defun gnus-summary-mark-article-as-unread (mark)
+  "Mark the current article quickly as unread with MARK."
+  (let* ((article (gnus-summary-article-number))
+        (old-mark (gnus-summary-article-mark article)))
+    ;; Allow the backend to change the mark.
+    (setq mark (gnus-request-update-mark gnus-newsgroup-name article mark))
+    (if (eq mark old-mark)
+       t
+      (if (<= article 0)
+         (progn
+           (gnus-error 1 "Can't mark negative article numbers")
+           nil)
+       (setq gnus-newsgroup-marked (delq article gnus-newsgroup-marked))
+       (setq gnus-newsgroup-spam-marked
+             (delq article gnus-newsgroup-spam-marked))
+       (setq gnus-newsgroup-dormant (delq article gnus-newsgroup-dormant))
+       (setq gnus-newsgroup-expirable (delq article gnus-newsgroup-expirable))
+       (setq gnus-newsgroup-reads (delq article gnus-newsgroup-reads))
+       (setq gnus-newsgroup-unreads (delq article gnus-newsgroup-unreads))
+       (cond ((= mark gnus-ticked-mark)
+              (setq gnus-newsgroup-marked
+                    (gnus-add-to-sorted-list gnus-newsgroup-marked
+                                             article)))
+             ((= mark gnus-spam-mark)
+              (setq gnus-newsgroup-spam-marked
+                    (gnus-add-to-sorted-list gnus-newsgroup-spam-marked
+                                             article)))
+             ((= mark gnus-dormant-mark)
+              (setq gnus-newsgroup-dormant
+                    (gnus-add-to-sorted-list gnus-newsgroup-dormant
+                                             article)))
+             (t
+              (setq gnus-newsgroup-unreads
+                    (gnus-add-to-sorted-list gnus-newsgroup-unreads
+                                             article))))
+       (gnus-alist-pull article gnus-newsgroup-reads)
+
+       ;; See whether the article is to be put in the cache.
+       (and gnus-use-cache
+            (vectorp (gnus-summary-article-header article))
+            (save-excursion
+              (gnus-cache-possibly-enter-article
+               gnus-newsgroup-name article
+               (= mark gnus-ticked-mark)
+               (= mark gnus-dormant-mark) (= mark gnus-unread-mark))))
+
+       ;; Fix the mark.
+       (gnus-summary-update-mark mark 'unread)
+       t))))
+
+(defun gnus-summary-mark-article (&optional article mark no-expire)
+  "Mark ARTICLE with MARK.  MARK can be any character.
+Four MARK strings are reserved: `? ' (unread), `?!' (ticked),
+`??' (dormant) and `?E' (expirable).
+If MARK is nil, then the default character `?r' is used.
+If ARTICLE is nil, then the article on the current line will be
+marked.
+If NO-EXPIRE, auto-expiry will be inhibited."
+  ;; The mark might be a string.
+  (when (stringp mark)
+    (setq mark (aref mark 0)))
+  ;; If no mark is given, then we check auto-expiring.
+  (when (null mark)
+    (setq mark gnus-del-mark))
+  (when (and (not no-expire)
+            gnus-newsgroup-auto-expire
+            (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)))
+    ;; Allow the backend to change the mark.
+    (setq mark (gnus-request-update-mark gnus-newsgroup-name article mark))
+    (if (eq mark old-mark)
+       t
+      (unless article
+       (error "No article on current line"))
+      (if (not (if (or (= mark gnus-unread-mark)
+                      (= mark gnus-ticked-mark)
+                      (= mark gnus-spam-mark)
+                      (= mark gnus-dormant-mark))
+                  (gnus-mark-article-as-unread article mark)
+                (gnus-mark-article-as-read article mark)))
+         t
+       ;; See whether the article is to be put in the cache.
+       (and gnus-use-cache
+            (not (= mark gnus-canceled-mark))
+            (vectorp (gnus-summary-article-header article))
+            (save-excursion
+              (gnus-cache-possibly-enter-article
+               gnus-newsgroup-name article
+               (= mark gnus-ticked-mark)
+               (= mark gnus-dormant-mark) (= mark gnus-unread-mark))))
+
+       (when (gnus-summary-goto-subject article nil t)
+         (let ((inhibit-read-only t))
+           (gnus-summary-show-thread)
+           ;; Fix the mark.
+           (gnus-summary-update-mark mark 'unread)
+           t))))))
+
+(defun gnus-summary-update-secondary-mark (article)
+  "Update the secondary (read, process, cache) mark."
+  (gnus-summary-update-mark
+   (cond ((memq article gnus-newsgroup-processable)
+         gnus-process-mark)
+        ((memq article gnus-newsgroup-cached)
+         gnus-cached-mark)
+        ((memq article gnus-newsgroup-replied)
+         gnus-replied-mark)
+        ((memq article gnus-newsgroup-forwarded)
+         gnus-forwarded-mark)
+        ((memq article gnus-newsgroup-saved)
+         gnus-saved-mark)
+        ((memq article gnus-newsgroup-unseen)
+         gnus-unseen-mark)
+        (t gnus-no-mark))
+   'replied)
+  (when (gnus-visual-p 'summary-highlight 'highlight)
+    (gnus-summary-highlight-line)
+    (gnus-run-hooks 'gnus-summary-update-hook))
+  t)
+
+(defun gnus-summary-update-download-mark (article)
+  "Update the download mark."
+  (gnus-summary-update-mark
+   (cond ((memq article gnus-newsgroup-undownloaded)
+          gnus-undownloaded-mark)
+         (gnus-newsgroup-agentized
+          gnus-downloaded-mark)
+         (t
+          gnus-no-mark))
+   'download)
+  (gnus-summary-update-line t)
+  t)
+
+(defun gnus-summary-update-mark (mark type)
+  (let ((forward (cdr (assq type gnus-summary-mark-positions)))
+       (inhibit-read-only t))
+    (re-search-backward "[\n\r]" (point-at-bol) 'move-to-limit)
+    (when forward
+      (when (looking-at "\r")
+       (incf forward))
+      (when (<= (+ forward (point)) (point-max))
+       ;; Go to the right position on the line.
+       (goto-char (+ forward (point)))
+       ;; Replace the old mark with the new mark.
+        (let ((to-insert
+               (mm-subst-char-in-string
+               (char-after) mark
+               (buffer-substring (point) (1+ (point))))))
+          (delete-region (point) (1+ (point)))
+          (insert to-insert))
+       ;; Optionally update the marks by some user rule.
+       (when (eq type 'unread)
+         (gnus-data-set-mark
+          (gnus-data-find (gnus-summary-article-number)) mark)
+         (gnus-summary-update-line (eq mark gnus-unread-mark)))))))
+
+(defun gnus-mark-article-as-read (article &optional mark)
+  "Enter ARTICLE in the pertinent lists and remove it from others."
+  ;; Make the article expirable.
+  (let ((mark (or mark gnus-del-mark)))
+    (setq gnus-newsgroup-expirable
+         (if (= mark gnus-expirable-mark)
+             (gnus-add-to-sorted-list gnus-newsgroup-expirable article)
+           (delq article gnus-newsgroup-expirable)))
+    ;; Remove from unread and marked lists.
+    (setq gnus-newsgroup-unreads (delq article gnus-newsgroup-unreads))
+    (setq gnus-newsgroup-marked (delq article gnus-newsgroup-marked))
+    (setq gnus-newsgroup-spam-marked (delq article gnus-newsgroup-spam-marked))
+    (setq gnus-newsgroup-dormant (delq article gnus-newsgroup-dormant))
+    (push (cons article mark) gnus-newsgroup-reads)
+    ;; Possibly remove from cache, if that is used.
+    (when gnus-use-cache
+      (gnus-cache-enter-remove-article article))
+    t))
+
+(defun gnus-mark-article-as-unread (article &optional mark)
+  "Enter ARTICLE in the pertinent lists and remove it from others."
+  (let ((mark (or mark gnus-ticked-mark)))
+    (if (<= article 0)
+       (progn
+         (gnus-error 1 "Can't mark negative article numbers")
+         nil)
+      (setq gnus-newsgroup-marked (delq article gnus-newsgroup-marked)
+           gnus-newsgroup-spam-marked (delq article gnus-newsgroup-spam-marked)
+           gnus-newsgroup-dormant (delq article gnus-newsgroup-dormant)
+           gnus-newsgroup-expirable (delq article gnus-newsgroup-expirable)
+           gnus-newsgroup-unreads (delq article gnus-newsgroup-unreads))
+
+      ;; Unsuppress duplicates?
+      (when gnus-suppress-duplicates
+       (gnus-dup-unsuppress-article article))
+
+      (cond ((= mark gnus-ticked-mark)
+            (setq gnus-newsgroup-marked
+                  (gnus-add-to-sorted-list gnus-newsgroup-marked article)))
+           ((= mark gnus-spam-mark)
+            (setq gnus-newsgroup-spam-marked
+                  (gnus-add-to-sorted-list gnus-newsgroup-spam-marked
+                                           article)))
+           ((= mark gnus-dormant-mark)
+            (setq gnus-newsgroup-dormant
+                  (gnus-add-to-sorted-list gnus-newsgroup-dormant article)))
+           (t
+            (setq gnus-newsgroup-unreads
+                  (gnus-add-to-sorted-list gnus-newsgroup-unreads article))))
+      (gnus-alist-pull article gnus-newsgroup-reads)
+      t)))
+
+(defun gnus-summary-tick-article-forward (n)
+  "Tick N articles forwards.
+If N is negative, tick backwards instead.
+The difference between N and the number of articles ticked is returned."
+  (interactive "p")
+  (gnus-summary-mark-forward n gnus-ticked-mark))
+
+(defun gnus-summary-tick-article-backward (n)
+  "Tick N articles backwards.
+The difference between N and the number of articles ticked is returned."
+  (interactive "p")
+  (gnus-summary-mark-forward (- n) gnus-ticked-mark))
+
+(defun gnus-summary-tick-article (&optional article clear-mark)
+  "Mark current article as unread.
+Optional 1st argument ARTICLE specifies article number to be marked as unread.
+Optional 2nd argument CLEAR-MARK remove any kinds of mark."
+  (interactive)
+  (gnus-summary-mark-article article (if clear-mark gnus-unread-mark
+                                      gnus-ticked-mark)))
+
+(defun gnus-summary-mark-as-read-forward (n)
+  "Mark N articles as read forwards.
+If N is negative, mark backwards instead.
+The difference between N and the actual number of articles marked is
+returned."
+  (interactive "p")
+  (gnus-summary-mark-forward n gnus-del-mark gnus-inhibit-user-auto-expire))
+
+(defun gnus-summary-mark-as-read-backward (n)
+  "Mark the N articles as read backwards.
+The difference between N and the actual number of articles marked is
+returned."
+  (interactive "p")
+  (gnus-summary-mark-forward
+   (- n) gnus-del-mark gnus-inhibit-user-auto-expire))
+
+(defun gnus-summary-mark-as-read (&optional article mark)
+  "Mark current article as read.
+ARTICLE specifies the article to be marked as read.
+MARK specifies a string to be inserted at the beginning of the line."
+  (gnus-summary-mark-article article mark))
+
+(defun gnus-summary-clear-mark-forward (n)
+  "Clear marks from N articles forward.
+If N is negative, clear backward instead.
+The difference between N and the number of marks cleared is returned."
+  (interactive "p")
+  (gnus-summary-mark-forward n gnus-unread-mark))
+
+(defun gnus-summary-clear-mark-backward (n)
+  "Clear marks from N articles backward.
+The difference between N and the number of marks cleared is returned."
+  (interactive "p")
+  (gnus-summary-mark-forward (- n) gnus-unread-mark))
+
+(defun gnus-summary-mark-unread-as-read ()
+  "Intended to be used by `gnus-mark-article-hook'."
+  (when (memq gnus-current-article gnus-newsgroup-unreads)
+    (gnus-summary-mark-article gnus-current-article gnus-read-mark)))
+
+(defun gnus-summary-mark-read-and-unread-as-read (&optional new-mark)
+  "Intended to be used by `gnus-mark-article-hook'."
+  (let ((mark (gnus-summary-article-mark)))
+    (when (or (gnus-unread-mark-p mark)
+             (gnus-read-mark-p mark))
+      (gnus-summary-mark-article gnus-current-article
+                                (or new-mark gnus-read-mark)))))
+
+(defun gnus-summary-mark-current-read-and-unread-as-read (&optional new-mark)
+  "Intended to be used by `gnus-mark-article-hook'."
+  (let ((mark (gnus-summary-article-mark)))
+    (when (or (gnus-unread-mark-p mark)
+             (gnus-read-mark-p mark))
+      (gnus-summary-mark-article (gnus-summary-article-number)
+                                (or new-mark gnus-read-mark)))))
+
+(defun gnus-summary-mark-unread-as-ticked ()
+  "Intended to be used by `gnus-mark-article-hook'."
+  (when (memq gnus-current-article gnus-newsgroup-unreads)
+    (gnus-summary-mark-article gnus-current-article gnus-ticked-mark)))
+
+(defun gnus-summary-mark-region-as-read (point mark all)
+  "Mark all unread articles between point and mark as read.
+If given a prefix, mark all articles between point and mark as read,
+even ticked and dormant ones."
+  (interactive "r\nP")
+  (save-excursion
+    (let (article)
+      (goto-char point)
+      (beginning-of-line)
+      (while (and
+             (< (point) mark)
+             (progn
+               (when (or all
+                         (memq (setq article (gnus-summary-article-number))
+                               gnus-newsgroup-unreads))
+                 (gnus-summary-mark-article article gnus-del-mark))
+               t)
+             (gnus-summary-find-next))))))
+
+(defun gnus-summary-mark-below (score mark)
+  "Mark articles with score less than SCORE with MARK."
+  (interactive "P\ncMark: ")
+  (setq score (if score
+                 (prefix-numeric-value score)
+               (or gnus-summary-default-score 0)))
+  (with-current-buffer gnus-summary-buffer
+    (goto-char (point-min))
+    (while
+       (progn
+         (and (< (gnus-summary-article-score) score)
+              (gnus-summary-mark-article nil mark))
+         (gnus-summary-find-next)))))
+
+(defun gnus-summary-kill-below (&optional score)
+  "Mark articles with score below SCORE as read."
+  (interactive "P")
+  (gnus-summary-mark-below score gnus-killed-mark))
+
+(defun gnus-summary-clear-above (&optional score)
+  "Clear all marks from articles with score above SCORE."
+  (interactive "P")
+  (gnus-summary-mark-above score gnus-unread-mark))
+
+(defun gnus-summary-tick-above (&optional score)
+  "Tick all articles with score above SCORE."
+  (interactive "P")
+  (gnus-summary-mark-above score gnus-ticked-mark))
+
+(defun gnus-summary-mark-above (score mark)
+  "Mark articles with score over SCORE with MARK."
+  (interactive "P\ncMark: ")
+  (setq score (if score
+                 (prefix-numeric-value score)
+               (or gnus-summary-default-score 0)))
+  (with-current-buffer gnus-summary-buffer
+    (goto-char (point-min))
+    (while (and (progn
+                 (when (> (gnus-summary-article-score) score)
+                   (gnus-summary-mark-article nil mark))
+                 t)
+               (gnus-summary-find-next)))))
+
+;; Suggested by Daniel Quinlan <quinlan@best.com>.
+(defalias 'gnus-summary-show-all-expunged 'gnus-summary-limit-include-expunged)
+(defun gnus-summary-limit-include-expunged (&optional no-error)
+  "Display all the hidden articles that were expunged for low scores."
+  (interactive)
+  (let ((inhibit-read-only t))
+    (let ((scored gnus-newsgroup-scored)
+         headers h)
+      (while scored
+       (unless (gnus-summary-article-header (caar scored))
+         (and (setq h (gnus-number-to-header (caar scored)))
+              (< (cdar scored) gnus-summary-expunge-below)
+              (push h headers)))
+       (setq scored (cdr scored)))
+      (if (not headers)
+         (when (not no-error)
+           (error "No expunged articles hidden"))
+       (goto-char (point-min))
+       (push gnus-newsgroup-limit gnus-newsgroup-limits)
+       (setq gnus-newsgroup-limit (copy-sequence gnus-newsgroup-limit))
+       (dolist (x headers)
+         (push (mail-header-number x) gnus-newsgroup-limit))
+       (gnus-summary-prepare-unthreaded (nreverse headers))
+       (goto-char (point-min))
+       (gnus-summary-position-point)
+       t))))
+
+(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 (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."
+  (interactive "P")
+  (prog1
+      (save-excursion
+       (when (or quietly
+                 (not gnus-interactive-catchup) ;Without confirmation?
+                 gnus-expert-user
+                 (gnus-y-or-n-p
+                  (if all
+                      "Mark absolutely all articles as read? "
+                    "Mark all unread articles as read? ")))
+         (if (and not-mark
+                  (not gnus-newsgroup-adaptive)
+                  (not gnus-newsgroup-auto-expire)
+                  (not gnus-suppress-duplicates)
+                  (or (not gnus-use-cache)
+                      (eq gnus-use-cache 'passive)))
+             (progn
+               (when all
+                 (setq gnus-newsgroup-marked nil
+                       gnus-newsgroup-spam-marked nil
+                       gnus-newsgroup-dormant nil))
+               (setq gnus-newsgroup-unreads
+                     (gnus-sorted-nunion
+                       (gnus-sorted-intersection gnus-newsgroup-unreads
+                                                gnus-newsgroup-downloadable)
+                      (gnus-sorted-difference gnus-newsgroup-unfetched
+                                              gnus-newsgroup-cached))))
+           ;; We actually mark all articles as canceled, which we
+           ;; have to do when using auto-expiry or adaptive scoring.
+           (gnus-summary-show-all-threads)
+           (if (and to-here reverse)
+               (progn
+                 (goto-char to-here)
+                 (gnus-summary-mark-current-read-and-unread-as-read
+                  gnus-catchup-mark)
+                 (while (gnus-summary-find-next (not all))
+                   (gnus-summary-mark-article-as-read gnus-catchup-mark)))
+             (when (gnus-summary-first-subject (not all))
+               (while (and
+                       (if to-here (< (point) to-here) t)
+                       (gnus-summary-mark-article-as-read gnus-catchup-mark)
+                       (gnus-summary-find-next (not all))))))
+           (gnus-set-mode-line 'summary))
+         t))
+    (gnus-summary-position-point)))
+
+(defun gnus-summary-catchup-to-here (&optional all)
+  "Mark all unticked articles before 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-prev))
+         (gnus-summary-catchup all t beg)))))
+  (gnus-summary-position-point))
+
+(defun gnus-summary-catchup-from-here (&optional all)
+  "Mark all unticked articles after (and including) 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.
+This command is dangerous.  Normally, you want \\[gnus-summary-catchup]
+instead, which marks only unread articles as read."
+  (interactive "P")
+  (gnus-summary-catchup t quietly))
+
+(defun gnus-summary-catchup-and-exit (&optional all quietly)
+  "Mark all unread articles in this group as read, then exit.
+If prefix argument ALL is non-nil, all articles are marked as read.
+If QUIETLY is non-nil, no questions will be asked."
+  (interactive "P")
+  (when (gnus-summary-catchup all quietly nil 'fast)
+    ;; Select next newsgroup or exit.
+    (if (and (not (gnus-group-quit-config gnus-newsgroup-name))
+            (eq gnus-auto-select-next 'quietly))
+       (gnus-summary-next-group nil)
+      (gnus-summary-exit))))
+
+(defun gnus-summary-catchup-all-and-exit (&optional quietly)
+  "Mark all articles in this newsgroup as read, and then exit.
+This command is dangerous.  Normally, you want \\[gnus-summary-catchup-and-exit]
+instead, which marks only unread articles as read."
+  (interactive "P")
+  (gnus-summary-catchup-and-exit t quietly))
+
+(defun gnus-summary-catchup-and-goto-next-group (&optional all)
+  "Mark all articles in this group as read and select the next group.
+If given a prefix, mark all articles, unread as well as ticked, as
+read."
+  (interactive "P")
+  (save-excursion
+    (gnus-summary-catchup all))
+  (gnus-summary-next-group))
+
+(defun gnus-summary-catchup-and-goto-prev-group (&optional all)
+  "Mark all articles in this group as read and select the previous group.
+If given a prefix, mark all articles, unread as well as ticked, as
+read."
+  (interactive "P")
+  (save-excursion
+    (gnus-summary-catchup all))
+  (gnus-summary-next-group nil nil t))
+
+;;;
+;;; with article
+;;;
+
+(defmacro gnus-with-article (article &rest forms)
+  "Select ARTICLE and perform FORMS in the original article buffer.
+Then replace the article with the result."
+  `(progn
+     ;; We don't want the article to be marked as read.
+     (let (gnus-mark-article-hook)
+       (gnus-summary-select-article t t nil ,article))
+     (set-buffer gnus-original-article-buffer)
+     ,@forms
+     (if (not (gnus-check-backend-function
+              'request-replace-article (car gnus-article-current)))
+        (gnus-message 5 "Read-only group; not replacing")
+       (unless (gnus-request-replace-article
+               ,article (car gnus-article-current)
+               (current-buffer) t)
+        (error "Couldn't replace article")))
+     ;; The cache and backlog have to be flushed somewhat.
+     (when gnus-keep-backlog
+       (gnus-backlog-remove-article
+       (car gnus-article-current) (cdr gnus-article-current)))
+     (when gnus-use-cache
+       (gnus-cache-update-article
+       (car gnus-article-current) (cdr gnus-article-current)))))
+
+(put 'gnus-with-article 'lisp-indent-function 1)
+(put 'gnus-with-article 'edebug-form-spec '(form body))
+
+;; Thread-based commands.
+
+(defun gnus-summary-articles-in-thread (&optional article)
+  "Return a list of all articles in the current thread.
+If ARTICLE is non-nil, return all articles in the thread that starts
+with that article."
+  (let* ((article (or article (gnus-summary-article-number)))
+        (data (gnus-data-find-list article))
+        (top-level (gnus-data-level (car data)))
+        (top-subject
+         (cond ((null gnus-thread-operation-ignore-subject)
+                (gnus-simplify-subject-re
+                 (mail-header-subject (gnus-data-header (car data)))))
+               ((eq gnus-thread-operation-ignore-subject 'fuzzy)
+                (gnus-simplify-subject-fuzzy
+                 (mail-header-subject (gnus-data-header (car data)))))
+               (t nil)))
+        (end-point (save-excursion
+                     (goto-char (gnus-data-pos (car data)))
+                     (if (gnus-summary-go-to-next-thread)
+                         (point) (point-max))))
+        articles)
+    (while (and data
+               (< (gnus-data-pos (car data)) end-point))
+      (when (or (not top-subject)
+               (string= top-subject
+                        (if (eq gnus-thread-operation-ignore-subject 'fuzzy)
+                            (gnus-simplify-subject-fuzzy
+                             (mail-header-subject
+                              (gnus-data-header (car data))))
+                          (gnus-simplify-subject-re
+                           (mail-header-subject
+                            (gnus-data-header (car data)))))))
+       (push (gnus-data-number (car data)) articles))
+      (unless (and (setq data (cdr data))
+                  (> (gnus-data-level (car data)) top-level))
+       (setq data nil)))
+    ;; Return the list of articles.
+    (nreverse articles)))
+
+(defun gnus-summary-rethread-current ()
+  "Rethread the thread the current article is part of."
+  (interactive)
+  (let* ((gnus-show-threads t)
+        (article (gnus-summary-article-number))
+        (id (mail-header-id (gnus-summary-article-header)))
+        (gnus-newsgroup-threads (list (gnus-id-to-thread (gnus-root-id id)))))
+    (unless id
+      (error "No article on the current line"))
+    (gnus-rebuild-thread id)
+    (gnus-summary-goto-subject article)))
+
+(defun gnus-summary-reparent-thread ()
+  "Make the current article child of the marked (or previous) article.
+
+Note that the re-threading will only work if `gnus-thread-ignore-subject'
+is non-nil or the Subject: of both articles are the same."
+  (interactive)
+  (unless (not (gnus-group-read-only-p))
+    (error "The current newsgroup does not support article editing"))
+  (unless (<= (length gnus-newsgroup-processable) 1)
+    (error "No more than one article may be marked"))
+  (let ((child (gnus-summary-article-number))
+       ;; First grab the marked article, otherwise one line up.
+       (parent (if (not (null gnus-newsgroup-processable))
+                   (car gnus-newsgroup-processable)
+                 (save-excursion
+                   (if (eq (forward-line -1) 0)
+                       (gnus-summary-article-number)
+                     (error "Beginning of summary buffer"))))))
+    (gnus-summary-reparent-children parent (list child))))
+
+(defun gnus-summary-reparent-children (parent children)
+  "Make PARENT the parent of CHILDREN.
+When called interactively, PARENT is the current article and CHILDREN
+are the process-marked articles."
+  (interactive
+   (list (gnus-summary-article-number)
+        (gnus-summary-work-articles nil)))
+  (dolist (child children)
+    (save-window-excursion
+      (let ((gnus-article-buffer " *reparent*"))
+       (unless (not (eq parent child))
+         (error "An article may not be self-referential"))
+       (let ((message-id (mail-header-id
+                          (gnus-summary-article-header parent))))
+         (unless (and message-id (not (equal message-id "")))
+           (error "No message-id in desired parent"))
+         (gnus-with-article child
+           (save-restriction
+             (goto-char (point-min))
+             (message-narrow-to-head)
+             (if (re-search-forward "^References: " nil t)
+                 (progn
+                   (re-search-forward "^[^ \t]" nil t)
+                   (forward-line -1)
+                   (end-of-line)
+                   (insert " " message-id))
+               (insert "References: " message-id "\n"))))
+         (set-buffer gnus-summary-buffer)
+         (gnus-summary-unmark-all-processable)
+         (gnus-summary-update-article child)
+         (when (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"
+                       child parent))))))
+
+(defun gnus-summary-toggle-threads (&optional arg)
+  "Toggle showing conversation threads.
+If ARG is positive number, turn showing conversation threads on."
+  (interactive "P")
+  (let ((current (or (gnus-summary-article-number) gnus-newsgroup-end)))
+    (setq gnus-show-threads
+         (if (null arg) (not gnus-show-threads)
+           (> (prefix-numeric-value arg) 0)))
+    (gnus-summary-prepare)
+    (gnus-summary-goto-subject current)
+    (gnus-message 6 "Threading is now %s" (if gnus-show-threads "on" "off"))
+    (gnus-summary-position-point)))
+
+(defun gnus-summary-show-all-threads ()
+  "Show all threads."
+  (interactive)
+  (remove-overlays (point-min) (point-max) 'invisible 'gnus-sum)
+  (gnus-summary-position-point))
+
+(defsubst gnus-summary--inv (p)
+  (and (eq (get-char-property p 'invisible) 'gnus-sum) p))
+
+(defun gnus-summary-show-thread ()
+  "Show thread subtrees.
+Returns nil if no thread was there to be shown."
+  (interactive)
+  (let* ((orig (point))
+        (end (point-at-eol))
+         (end (or (gnus-summary--inv end) (gnus-summary--inv (1- end))))
+        ;; Leave point at bol
+        (beg (progn (beginning-of-line) (if (bobp) (point) (1- (point)))))
+        (eoi (when end
+               (if (fboundp 'next-single-char-property-change)
+                   ;; Note: XEmacs version of n-s-c-p-c may return nil
+                   (or (next-single-char-property-change end 'invisible)
+                       (point-max))
+                 (while (progn
+                          (end-of-line 2)
+                          (and (not (eobp))
+                               (eq (get-char-property (point) 'invisible)
+                                   'gnus-sum))))
+                 (point)))))
+    (when eoi
+      (remove-overlays beg eoi 'invisible 'gnus-sum)
+      (goto-char orig)
+      (gnus-summary-position-point)
+      eoi)))
+
+(defun gnus-summary-maybe-hide-threads ()
+  "If requested, hide the threads that should be hidden."
+  (when (and gnus-show-threads
+            gnus-thread-hide-subtree)
+    (gnus-summary-hide-all-threads
+     (if (or (consp gnus-thread-hide-subtree)
+            (functionp gnus-thread-hide-subtree))
+        (gnus-make-predicate gnus-thread-hide-subtree)
+       nil))))
+
+;;; Hiding predicates.
+
+(defun gnus-article-unread-p (header)
+  (memq (mail-header-number header) gnus-newsgroup-unreads))
+
+(defun gnus-article-unseen-p (header)
+  (memq (mail-header-number header) gnus-newsgroup-unseen))
+
+(defun gnus-map-articles (predicate articles)
+  "Map PREDICATE over ARTICLES and return non-nil if any predicate is non-nil."
+  (apply 'gnus-or (mapcar predicate
+                         (mapcar (lambda (number)
+                                   (gnus-summary-article-header number))
+                                 articles))))
+
+(defun gnus-summary-hide-all-threads (&optional predicate)
+  "Hide all thread subtrees.
+If PREDICATE is supplied, threads that satisfy this predicate
+will not be hidden."
+  (interactive)
+  (save-excursion
+    (goto-char (point-min))
+    (let ((end nil)
+          (count 0))
+      (while (not end)
+        (incf count)
+        (when (zerop (mod count 1000))
+          (message "Hiding all threads... %d" count))
+       (when (or (not predicate)
+                 (gnus-map-articles
+                  predicate (gnus-summary-article-children)))
+           (gnus-summary-hide-thread))
+       (setq end (not (zerop (gnus-summary-next-thread 1 t)))))))
+  (gnus-summary-position-point))
+
+(defun gnus-summary-hide-thread ()
+  "Hide thread subtrees.
+If PREDICATE is supplied, threads that satisfy this predicate
+will not be hidden.
+Returns nil if no threads were there to be hidden."
+  (interactive)
+  (beginning-of-line)
+  (let ((start (point))
+       (starteol (line-end-position))
+       (article (gnus-summary-article-number)))
+    ;; Go forward until either the buffer ends or the subthread ends.
+    (when (and (not (eobp))
+              (or (zerop (gnus-summary-next-thread 1 t))
+                  (goto-char (point-max))))
+      (if (and (> (point) start)
+              ;; FIXME: this should actually search for a non-invisible \n.
+              (search-backward "\n" start t))
+         (progn
+           (when (> (point) starteol)
+             (remove-overlays starteol (point) 'invisible 'gnus-sum)
+             (let ((ol (make-overlay starteol (point) nil t nil)))
+               (overlay-put ol 'invisible 'gnus-sum)
+               (overlay-put ol 'evaporate t)))
+           (gnus-summary-goto-subject article)
+            (when (> start (point))
+              (message "Hiding the thread moved us backwards, aborting!")
+              (goto-char (point-max))))
+       (goto-char start)
+       nil))))
+
+(defun gnus-summary-go-to-next-thread (&optional previous)
+  "Go to the same level (or less) next thread.
+If PREVIOUS is non-nil, go to previous thread instead.
+Return the article number moved to, or nil if moving was impossible."
+  (let ((level (gnus-summary-thread-level))
+       (way (if previous -1 1))
+       (beg (point)))
+    (forward-line way)
+    (while (and (not (eobp))
+               (< level (gnus-summary-thread-level)))
+      (forward-line way))
+    (if (eobp)
+       (progn
+         (goto-char beg)
+         nil)
+      (setq beg (point))
+      (prog1
+         (gnus-summary-article-number)
+       (goto-char beg)))))
+
+(defun gnus-summary-next-thread (n &optional silent)
+  "Go to the same level next N'th thread.
+If N is negative, search backward instead.
+Returns the difference between N and the number of skips actually
+done.
+
+If SILENT, don't output messages."
+  (interactive "p")
+  (let ((backward (< n 0))
+       (n (abs n)))
+    (while (and (> n 0)
+               (gnus-summary-go-to-next-thread backward))
+      (decf n))
+    (unless silent
+      (gnus-summary-position-point))
+    (when (and (not silent) (/= 0 n))
+      (gnus-message 7 "No more threads"))
+    n))
+
+(defun gnus-summary-prev-thread (n)
+  "Go to the same level previous N'th thread.
+Returns the difference between N and the number of skips actually
+done."
+  (interactive "p")
+  (gnus-summary-next-thread (- n)))
+
+(defun gnus-summary-go-down-thread ()
+  "Go down one level in the current thread."
+  (let ((children (gnus-summary-article-children)))
+    (when children
+      (gnus-summary-goto-subject (car children)))))
+
+(defun gnus-summary-go-up-thread ()
+  "Go up one level in the current thread."
+  (let ((parent (gnus-summary-article-parent)))
+    (when parent
+      (gnus-summary-goto-subject parent))))
+
+(defun gnus-summary-down-thread (n)
+  "Go down thread N steps.
+If N is negative, go up instead.
+Returns the difference between N and how many steps down that were
+taken."
+  (interactive "p")
+  (let ((up (< n 0))
+       (n (abs n)))
+    (while (and (> n 0)
+               (if up (gnus-summary-go-up-thread)
+                 (gnus-summary-go-down-thread)))
+      (setq n (1- n)))
+    (gnus-summary-position-point)
+    (when (/= 0 n)
+      (gnus-message 7 "Can't go further"))
+    n))
+
+(defun gnus-summary-up-thread (n)
+  "Go up thread N steps.
+If N is negative, go down instead.
+Returns the difference between N and how many steps down that were
+taken."
+  (interactive "p")
+  (gnus-summary-down-thread (- n)))
+
+(defun gnus-summary-top-thread ()
+  "Go to the top of the thread."
+  (interactive)
+  (while (gnus-summary-go-up-thread))
+  (gnus-summary-article-number))
+
+(defun gnus-summary-expire-thread ()
+  "Mark articles under current thread as expired."
+  (interactive)
+  (gnus-summary-kill-thread 0))
+
+(defun gnus-summary-kill-thread (&optional unmark)
+  "Mark articles under current thread as read.
+If the prefix argument is positive, remove any kinds of marks.
+If the prefix argument is zero, mark thread as expired.
+If the prefix argument is negative, tick articles instead."
+  (interactive "P")
+  (when unmark
+    (setq unmark (prefix-numeric-value unmark)))
+  (let ((articles (gnus-summary-articles-in-thread))
+       (hide (or (null unmark) (= unmark 0))))
+    (save-excursion
+      ;; Expand the thread.
+      (gnus-summary-show-thread)
+      ;; Mark all the articles.
+      (while articles
+       (gnus-summary-goto-subject (car articles))
+       (cond ((null unmark)
+              (gnus-summary-mark-article-as-read gnus-killed-mark))
+             ((> unmark 0)
+              (gnus-summary-mark-article-as-unread gnus-unread-mark))
+             ((= unmark 0)
+              (gnus-summary-mark-article nil gnus-expirable-mark))
+             (t
+              (gnus-summary-mark-article-as-unread gnus-ticked-mark)))
+       (setq articles (cdr articles))))
+    ;; Hide killed subtrees when hide is true.
+    (and hide
+        gnus-thread-hide-killed
+        (gnus-summary-hide-thread))
+    ;; If hide is t, go to next unread subject.
+    (when hide
+      ;; Go to next unread subject.
+      (gnus-summary-next-subject 1 t)))
+  (gnus-set-mode-line 'summary))
+
+;; Summary sorting commands
+
+(defun gnus-summary-sort-by-number (&optional reverse)
+  "Sort the summary buffer by article number.
+Argument REVERSE means reverse order."
+  (interactive "P")
+  (gnus-summary-sort 'number reverse))
+
+(defun gnus-summary-sort-by-most-recent-number (&optional reverse)
+  "Sort the summary buffer by most recent article number.
+Argument REVERSE means reverse order."
+  (interactive "P")
+  (gnus-summary-sort 'most-recent-number reverse))
+
+(defun gnus-summary-sort-by-random (&optional reverse)
+  "Randomize the order in the summary buffer.
+Argument REVERSE means to randomize in reverse order."
+  (interactive "P")
+  (gnus-summary-sort 'random reverse))
+
+(defun gnus-summary-sort-by-author (&optional reverse)
+  "Sort the summary buffer by author name alphabetically.
+If `case-fold-search' is non-nil, case of letters is ignored.
+Argument REVERSE means reverse order."
+  (interactive "P")
+  (gnus-summary-sort 'author reverse))
+
+(defun gnus-summary-sort-by-recipient (&optional reverse)
+  "Sort the summary buffer by recipient name alphabetically.
+If `case-fold-search' is non-nil, case of letters is ignored.
+Argument REVERSE means reverse order."
+  (interactive "P")
+  (gnus-summary-sort 'recipient reverse))
+
+(defun gnus-summary-sort-by-subject (&optional reverse)
+  "Sort the summary buffer by subject alphabetically.  `Re:'s are ignored.
+If `case-fold-search' is non-nil, case of letters is ignored.
+Argument REVERSE means reverse order."
+  (interactive "P")
+  (gnus-summary-sort 'subject reverse))
+
+(defun gnus-summary-sort-by-date (&optional reverse)
+  "Sort the summary buffer by date.
+Argument REVERSE means reverse order."
+  (interactive "P")
+  (gnus-summary-sort 'date reverse))
+
+(defun gnus-summary-sort-by-most-recent-date (&optional reverse)
+  "Sort the summary buffer by most recent date.
+Argument REVERSE means reverse order."
+  (interactive "P")
+  (gnus-summary-sort 'most-recent-date reverse))
+
+(defun gnus-summary-sort-by-score (&optional reverse)
+  "Sort the summary buffer by score.
+Argument REVERSE means reverse order."
+  (interactive "P")
+  (gnus-summary-sort 'score reverse))
+
+(defun gnus-summary-sort-by-lines (&optional reverse)
+  "Sort the summary buffer by the number of lines.
+Argument REVERSE means reverse order."
+  (interactive "P")
+  (gnus-summary-sort 'lines reverse))
+
+(defun gnus-summary-sort-by-chars (&optional reverse)
+  "Sort the summary buffer by article length.
+Argument REVERSE means reverse order."
+  (interactive "P")
+  (gnus-summary-sort 'chars reverse))
+
+(defun gnus-summary-sort-by-original (&optional reverse)
+  "Sort the summary buffer using the default sorting method.
+Argument REVERSE means reverse order."
+  (interactive "P")
+  (let* ((inhibit-read-only t)
+        (gnus-summary-prepare-hook nil))
+    ;; We do the sorting by regenerating the threads.
+    (gnus-summary-prepare)
+    ;; Hide subthreads if needed.
+    (gnus-summary-maybe-hide-threads)))
+
+(defun gnus-summary-sort (predicate reverse)
+  "Sort summary buffer by PREDICATE.  REVERSE means reverse order."
+  (let* ((thread (intern (format "gnus-thread-sort-by-%s" predicate)))
+        (article (intern (format "gnus-article-sort-by-%s" predicate)))
+        (gnus-thread-sort-functions
+         (if (not reverse)
+             thread
+           `(lambda (t1 t2)
+              (,thread t2 t1))))
+        (gnus-sort-gathered-threads-function
+         gnus-thread-sort-functions)
+        (gnus-article-sort-functions
+         (if (not reverse)
+             article
+           `(lambda (t1 t2)
+              (,article t2 t1))))
+        (inhibit-read-only t)
+        (gnus-summary-prepare-hook nil))
+    ;; We do the sorting by regenerating the threads.
+    (gnus-summary-prepare)
+    ;; Hide subthreads if needed.
+    (gnus-summary-maybe-hide-threads)))
+
+;; Summary saving commands.
+
+(defun gnus-summary-save-article (&optional n not-saved)
+  "Save the current article using the default saver function.
+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.
+The variable `gnus-default-article-saver' specifies the saver function.
+
+If the optional second argument NOT-SAVED is non-nil, articles saved
+will not be marked as saved."
+  (interactive "P")
+  (require 'gnus-art)
+  (let* ((articles (gnus-summary-work-articles n))
+        (save-buffer (save-excursion
+                       (nnheader-set-temp-buffer " *Gnus Save*")))
+        (num (length articles))
+        ;; Whether to save decoded articles or raw articles.
+        (decode (when gnus-article-save-coding-system
+                  (get gnus-default-article-saver :decode)))
+        ;; When saving many articles in a single file, use the other
+        ;; function to save articles other than the first one.
+        (saver2 (get gnus-default-article-saver :function))
+        (gnus-prompt-before-saving (if saver2
+                                       t
+                                     gnus-prompt-before-saving))
+        (gnus-default-article-saver gnus-default-article-saver)
+        header file)
+    (dolist (article articles)
+      (setq header (gnus-summary-article-header article))
+      (if (not (vectorp header))
+         ;; This is a pseudo-article.
+         (if (assq 'name header)
+             (gnus-copy-file (cdr (assq 'name header)))
+           (gnus-message 1 "Article %d is unsavable" article))
+       ;; This is a real article.
+       (save-window-excursion
+         (gnus-summary-select-article decode decode nil article)
+         (gnus-summary-goto-subject article))
+       (with-current-buffer save-buffer
+         (erase-buffer)
+         (insert-buffer-substring (if decode
+                                      gnus-article-buffer
+                                    gnus-original-article-buffer)))
+       (setq file (gnus-article-save save-buffer file num))
+       (gnus-summary-remove-process-mark article)
+       (unless not-saved
+         (gnus-summary-set-saved-mark article)))
+      (when saver2
+       (setq gnus-default-article-saver saver2
+             saver2 nil)))
+    (gnus-kill-buffer save-buffer)
+    (gnus-summary-position-point)
+    (gnus-set-mode-line 'summary)
+    n))
+
+(declare-function gnus-summary-save-in-pipe "gnus-art" (&optional command raw))
+
+(defun gnus-summary-pipe-output (&optional n sym)
+  "Pipe the current article to a subprocess.
+If N is a positive number, pipe the N next articles.
+If N is a negative number, pipe the N previous articles.
+If N is nil and any articles have been marked with the process mark,
+pipe those articles instead.
+The default command to which articles are piped is specified by the
+variable `gnus-summary-pipe-output-default-command'; if it is nil, you
+will be prompted for the command.
+
+The properties `:decode' and `:headers' that are put to the function
+symbol `gnus-summary-save-in-pipe' control whether this function
+decodes articles and what headers to keep (see the doc string for the
+`gnus-default-article-saver' variable).  If SYM (the symbolic prefix)
+is neither omitted nor the symbol `r', force including all headers
+regardless of the `:headers' property.  If it is the symbol `r',
+articles that are not decoded and include all headers will be piped
+no matter what the properties `:decode' and `:headers' are."
+  (interactive (gnus-interactive "P\ny"))
+  (require 'gnus-art)
+  (let* ((articles (gnus-summary-work-articles n))
+        (result-buffer "*Shell Command Output*")
+        (all-headers (not (memq sym '(nil r))))
+        (gnus-save-all-headers (or all-headers gnus-save-all-headers))
+        (raw (eq sym 'r))
+        (headers (get 'gnus-summary-save-in-pipe :headers))
+        command result)
+    (unless (numberp (car articles))
+      (error "No article to pipe"))
+    (setq command (gnus-read-shell-command
+                  (concat "Shell command on "
+                          (if (cdr articles)
+                              (format "these %d articles" (length articles))
+                            "this article")
+                          ": ")
+                  gnus-summary-pipe-output-default-command))
+    (when (string-equal command "")
+      (error "A command is required"))
+    (when all-headers
+      (put 'gnus-summary-save-in-pipe :headers nil))
+    (unwind-protect
+       (while articles
+         (gnus-summary-goto-subject (pop articles))
+         (save-window-excursion (gnus-summary-save-in-pipe command raw))
+         (when (and (get-buffer result-buffer)
+                    (not (zerop (buffer-size (get-buffer result-buffer)))))
+           (setq result (concat result (with-current-buffer result-buffer
+                                         (buffer-string))))))
+      (put 'gnus-summary-save-in-pipe :headers headers))
+    (unless (zerop (length result))
+      (if (with-current-buffer (get-buffer-create result-buffer)
+           (erase-buffer)
+           (insert result)
+           (prog1
+               (and (= (count-lines (point-min) (point)) 1)
+                    (progn
+                      (end-of-line 0)
+                      (<= (current-column)
+                          (window-width (minibuffer-window)))))
+             (goto-char (point-min))))
+         (message "%s" (substring result 0 -1))
+       (message nil)
+       (gnus-configure-windows 'pipe)))))
+
+(defun gnus-summary-save-article-mail (&optional arg)
+  "Append the current article to a Unix mail box file.
+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-save-in-mail))
+    (gnus-summary-save-article arg)))
+
+(defun gnus-summary-save-article-rmail (&optional arg)
+  "Append the current article to an rmail file.
+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-save-in-rmail))
+    (gnus-summary-save-article arg)))
+
+(defun gnus-summary-save-article-file (&optional arg)
+  "Append the current article to a file.
+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-save-in-file))
+    (gnus-summary-save-article arg)))
+
+(defun gnus-summary-write-article-file (&optional arg)
+  "Write the current article to a file, deleting the previous file.
+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-write-to-file))
+    (gnus-summary-save-article arg)))
+
+(defun gnus-summary-save-article-body-file (&optional arg)
+  "Append the current article body to a file.
+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-save-body-in-file))
+    (gnus-summary-save-article arg)))
+
+(defun gnus-summary-write-article-body-file (&optional arg)
+  "Write the current article body to a file, deleting the previous file.
+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-write-body-to-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: ")
+  (gnus-summary-select-article)
+  (let ((mail-header-separator ""))
+    (gnus-eval-in-buffer-window gnus-article-buffer
+      (save-restriction
+       (widen)
+       (let ((start (window-start))
+             (inhibit-read-only t))
+         (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."
+  (let (split-name method result match)
+    (when methods
+      (with-current-buffer gnus-original-article-buffer
+       (save-restriction
+         (nnheader-narrow-to-headers)
+         (while (and methods (not split-name))
+           (goto-char (point-min))
+           (setq method (pop methods))
+           (setq match (car method))
+           (when (cond
+                  ((stringp match)
+                   ;; Regular expression.
+                   (ignore-errors
+                     (re-search-forward match nil t)))
+                  ((functionp match)
+                   ;; Function.
+                   (save-restriction
+                     (widen)
+                     (setq result (funcall match gnus-newsgroup-name))))
+                  ((consp match)
+                   ;; Form.
+                   (save-restriction
+                     (widen)
+                     (setq result (eval match)))))
+             (setq split-name (cdr method))
+             (cond ((stringp result)
+                    (push (expand-file-name
+                           result gnus-article-save-directory)
+                          split-name))
+                   ((consp result)
+                    (setq split-name (append result split-name)))))))))
+    (nreverse split-name)))
+
+(defun gnus-valid-move-group-p (group)
+  (and (symbolp group)
+       (boundp group)
+       (symbol-name group)
+       (symbol-value group)
+       (gnus-get-function (gnus-find-method-for-group
+                          (symbol-name group)) 'request-accept-article t)))
+
+(defun gnus-read-move-group-name (prompt default articles prefix)
+  "Read a group name."
+  (let* ((split-name (gnus-get-split-value gnus-move-split-methods))
+        (minibuffer-confirm-incomplete nil) ; XEmacs
+        (prom
+         (format "%s %s to"
+                 prompt
+                 (if (> (length articles) 1)
+                     (format "these %d articles" (length articles))
+                   "this article")))
+        (to-newsgroup
+          (cond
+           ((null split-name)
+            (gnus-group-completing-read
+             prom
+             (gnus-remove-if-not 'gnus-valid-move-group-p gnus-active-hashtb t)
+             nil prefix nil default))
+           ((= 1 (length split-name))
+            (gnus-group-completing-read
+             prom
+            (gnus-remove-if-not 'gnus-valid-move-group-p gnus-active-hashtb t)
+             nil prefix 'gnus-group-history (car split-name)))
+           (t
+            (gnus-completing-read
+             prom (nreverse split-name) nil nil 'gnus-group-history))))
+         (to-method (gnus-server-to-method (gnus-group-method to-newsgroup)))
+        encoded)
+    (when to-newsgroup
+      (if (or (string= to-newsgroup "")
+             (string= to-newsgroup prefix))
+         (setq to-newsgroup default))
+      (unless to-newsgroup
+       (error "No group name entered"))
+      (setq encoded (mm-encode-coding-string
+                    to-newsgroup
+                    (gnus-group-name-charset to-method to-newsgroup)))
+      (or (gnus-active encoded)
+         (gnus-activate-group encoded nil nil to-method)
+         (if (gnus-y-or-n-p (format "No such group: %s.  Create it? "
+                                    to-newsgroup))
+             (or (and (gnus-request-create-group encoded to-method)
+                      (gnus-activate-group encoded nil nil to-method)
+                      (gnus-subscribe-group encoded))
+                 (error "Couldn't create group %s" to-newsgroup)))
+         (error "No such group: %s" to-newsgroup))
+      encoded)))
+
+(defvar gnus-summary-save-parts-counter)
+(declare-function mm-uu-dissect "mm-uu" (&optional noheader mime-type))
+
+(defun gnus-summary-save-parts (type dir n &optional reverse)
+  "Save parts matching TYPE to DIR.
+If REVERSE, save parts that do not match TYPE."
+  (interactive
+   (list (read-string "Save parts of type: "
+                     (or (car gnus-summary-save-parts-type-history)
+                         gnus-summary-save-parts-default-mime)
+                     'gnus-summary-save-parts-type-history)
+        (setq gnus-summary-save-parts-last-directory
+              (read-directory-name "Save to directory: "
+                                    gnus-summary-save-parts-last-directory
+                                    nil t))
+        current-prefix-arg))
+  (gnus-summary-iterate n
+    (let ((gnus-display-mime-function nil)
+         gnus-article-prepare-hook
+         gnus-article-decode-hook
+         gnus-display-mime-function
+         gnus-break-pages
+         (gnus-inhibit-treatment t))
+      (gnus-summary-select-article))
+    (with-current-buffer gnus-article-buffer
+      (let ((handles (or gnus-article-mime-handles
+                        (mm-dissect-buffer nil gnus-article-loose-mime)
+                        (and gnus-article-emulate-mime
+                             (mm-uu-dissect))))
+           (gnus-summary-save-parts-counter 1))
+       (when handles
+         (gnus-summary-save-parts-1 type dir handles reverse)
+         (unless gnus-article-mime-handles ;; Don't destroy this case.
+           (mm-destroy-parts handles)))))))
+
+(defun gnus-summary-save-parts-1 (type dir handle reverse)
+  (if (stringp (car handle))
+      (mapcar (lambda (h) (gnus-summary-save-parts-1 type dir h reverse))
+             (cdr handle))
+    (when (if reverse
+             (not (string-match type (mm-handle-media-type handle)))
+           (string-match type (mm-handle-media-type handle)))
+      (let ((file (expand-file-name
+                  (gnus-map-function
+                   mm-file-name-rewrite-functions
+                   (file-name-nondirectory
+                    (or
+                      (mm-handle-filename handle)
+                     (format "%s.%d.%d" gnus-newsgroup-name
+                             (cdr gnus-article-current)
+                             gnus-summary-save-parts-counter))))
+                  dir)))
+       (incf gnus-summary-save-parts-counter)
+       (unless (file-exists-p file)
+         (mm-save-part-to-file handle file))))))
+
+;; Summary extract commands
+
+(defun gnus-summary-insert-pseudos (pslist &optional not-view)
+  (let ((inhibit-read-only t)
+       (article (gnus-summary-article-number))
+       after-article b e)
+    (unless (gnus-summary-goto-subject article)
+      (error "No such article: %d" article))
+    (gnus-summary-position-point)
+    ;; If all commands are to be bunched up on one line, we collect
+    ;; them here.
+    (unless gnus-view-pseudos-separately
+      (let ((ps (setq pslist (sort pslist 'gnus-pseudos<)))
+           files action)
+       (while ps
+         (setq action (cdr (assq 'action (car ps))))
+         (setq files (list (cdr (assq 'name (car ps)))))
+         (while (and ps (cdr ps)
+                     (string= (or action "1")
+                              (or (cdr (assq 'action (cadr ps))) "2")))
+           (push (cdr (assq 'name (cadr ps))) files)
+           (setcdr ps (cddr ps)))
+         (when files
+           (when (not (string-match "%s" action))
+             (push " " files))
+           (push " " files)
+           (when (assq 'execute (car ps))
+             (setcdr (assq 'execute (car ps))
+                     (funcall (if (string-match "%s" action)
+                                  'format 'concat)
+                              action
+                              (mapconcat
+                               (lambda (f)
+                                 (if (equal f " ")
+                                     f
+                                   (shell-quote-argument f)))
+                               files " ")))))
+         (setq ps (cdr ps)))))
+    (if (and gnus-view-pseudos (not not-view))
+       (while pslist
+         (when (assq 'execute (car pslist))
+           (gnus-execute-command (cdr (assq 'execute (car pslist)))
+                                 (eq gnus-view-pseudos 'not-confirm)))
+         (setq pslist (cdr pslist)))
+      (save-excursion
+       (while pslist
+         (setq after-article (or (cdr (assq 'article (car pslist)))
+                                 (gnus-summary-article-number)))
+         (gnus-summary-goto-subject after-article)
+         (forward-line 1)
+         (setq b (point))
+         (insert "    " (file-name-nondirectory
+                         (cdr (assq 'name (car pslist))))
+                 ": " (or (cdr (assq 'execute (car pslist))) "") "\n")
+         (setq e (point))
+         (forward-line -1)             ; back to `b'
+         (gnus-add-text-properties
+          b (1- e) (list 'gnus-number gnus-reffed-article-number
+                         gnus-mouse-face-prop gnus-mouse-face))
+         (gnus-data-enter
+          after-article gnus-reffed-article-number
+          gnus-unread-mark b (car pslist) 0 (- e b))
+         (setq gnus-newsgroup-unreads
+               (gnus-add-to-sorted-list gnus-newsgroup-unreads
+                                        gnus-reffed-article-number))
+         (setq gnus-reffed-article-number (1- gnus-reffed-article-number))
+         (setq pslist (cdr pslist)))))))
+
+(defun gnus-pseudos< (p1 p2)
+  (let ((c1 (cdr (assq 'action p1)))
+       (c2 (cdr (assq 'action p2))))
+    (and c1 c2 (string< c1 c2))))
+
+(defun gnus-request-pseudo-article (props)
+  (cond ((assq 'execute props)
+        (gnus-execute-command (cdr (assq 'execute props)))))
+  (let ((gnus-current-article (gnus-summary-article-number)))
+    (gnus-run-hooks 'gnus-mark-article-hook)))
+
+(defun gnus-execute-command (command &optional automatic)
+  (save-excursion
+    (gnus-article-setup-buffer)
+    (set-buffer gnus-article-buffer)
+    (setq buffer-read-only nil)
+    (let ((command (if automatic command
+                    (read-string "Command: " (cons command 0)))))
+      (erase-buffer)
+      (insert "$ " command "\n\n")
+      (if gnus-view-pseudo-asynchronously
+         (start-process "gnus-execute" (current-buffer) shell-file-name
+                        shell-command-switch command)
+       (call-process shell-file-name nil t nil
+                     shell-command-switch command)))))
+
+;; Summary kill commands.
+
+(defun gnus-summary-edit-global-kill (article)
+  "Edit the \"global\" kill file."
+  (interactive (list (gnus-summary-article-number)))
+  (gnus-group-edit-global-kill article))
+
+(defun gnus-summary-edit-local-kill ()
+  "Edit a local kill file applied to the current newsgroup."
+  (interactive)
+  (setq gnus-current-headers (gnus-summary-article-header))
+  (gnus-group-edit-local-kill
+   (gnus-summary-article-number) gnus-newsgroup-name))
+
+;;; Header reading.
+
+(defun gnus-read-header (id &optional header)
+  "Read the headers of article ID and enter them into the Gnus system."
+  (let ((group gnus-newsgroup-name)
+       (gnus-override-method
+        (or
+         gnus-override-method
+         (and (gnus-news-group-p gnus-newsgroup-name)
+              (car (gnus-refer-article-methods)))))
+       where)
+    ;; First we check to see whether the header in question is already
+    ;; fetched.
+    (if (stringp id)
+       ;; This is a Message-ID.
+       (setq header (or header (gnus-id-to-header id)))
+      ;; This is an article number.
+      (setq header (or header (gnus-summary-article-header id))))
+    (if (and header
+            (not (gnus-summary-article-sparse-p (mail-header-number header))))
+       ;; We have found the header.
+       header
+      ;; We have to really fetch the header to this article.
+      (with-current-buffer nntp-server-buffer
+       (when (setq where (gnus-request-head id group))
+         (nnheader-fold-continuation-lines)
+         (goto-char (point-max))
+         (insert ".\n")
+         (goto-char (point-min))
+         (insert "211 ")
+         (princ (cond
+                 ((numberp id) id)
+                 ((cdr where) (cdr where))
+                 (header (mail-header-number header))
+                 (t gnus-reffed-article-number))
+                (current-buffer))
+         (insert " Article retrieved.\n"))
+       (if (or (not where)
+               (not (setq header (car (gnus-get-newsgroup-headers nil t)))))
+           ()                          ; Malformed head.
+         (unless (gnus-summary-article-sparse-p (mail-header-number header))
+            (when (and (bound-and-true-p gnus-registry-enabled)
+                       (not (gnus-ephemeral-group-p (car where))))
+              (gnus-registry-handle-action
+               (mail-header-id header) nil
+               (gnus-group-prefixed-name
+               (car where)
+               (or gnus-override-method (gnus-find-method-for-group group)))
+               (mail-header-subject header)
+               (mail-header-from header)))
+           (when (and (stringp id)
+                      (or
+                       (not (string= (gnus-group-real-name group)
+                                     (car where)))
+                       (not (gnus-server-equal gnus-override-method
+                                               (gnus-group-method group)))))
+             ;; If we fetched by Message-ID and the article came from
+             ;; a different group (or server), we fudge some bogus
+             ;; article numbers for this article.
+             (mail-header-set-number header gnus-reffed-article-number))
+           (with-current-buffer gnus-summary-buffer
+             (decf gnus-reffed-article-number)
+             (gnus-remove-header (mail-header-number header))
+             (push header gnus-newsgroup-headers)
+             (setq gnus-current-headers header)
+             (push (mail-header-number header) gnus-newsgroup-limit)))
+         header)))))
+
+(defun gnus-remove-header (number)
+  "Remove header NUMBER from `gnus-newsgroup-headers'."
+  (if (and gnus-newsgroup-headers
+          (= number (mail-header-number (car gnus-newsgroup-headers))))
+      (pop gnus-newsgroup-headers)
+    (let ((headers gnus-newsgroup-headers))
+      (while (and (cdr headers)
+                 (not (= number (mail-header-number (cadr headers)))))
+       (pop headers))
+      (when (cdr headers)
+       (setcdr headers (cddr headers))))))
+
+;;;
+;;; summary highlights
+;;;
+
+(defun gnus-highlight-selected-summary ()
+  "Highlight selected article in summary buffer."
+  ;; Added by Per Abrahamsen <amanda@iesd.auc.dk>.
+  (when gnus-summary-selected-face
+    (save-excursion
+      (let* ((beg (point-at-bol))
+            (end (point-at-eol))
+            ;; Fix by Mike Dugan <dugan@bucrf16.bu.edu>.
+            (from (if (get-text-property beg gnus-mouse-face-prop)
+                      beg
+                    (or (next-single-property-change
+                         beg gnus-mouse-face-prop nil end)
+                        beg)))
+            (to
+             (if (= from end)
+                 (- from 2)
+               (or (next-single-property-change
+                    from gnus-mouse-face-prop nil end)
+                   end))))
+       ;; If no mouse-face prop on line we will have to = from = end,
+       ;; so we highlight the entire line instead.
+       (when (= (+ to 2) from)
+         (setq from beg)
+         (setq to end))
+       (if gnus-newsgroup-selected-overlay
+           ;; Move old overlay.
+           (move-overlay
+            gnus-newsgroup-selected-overlay from to (current-buffer))
+         ;; Create new overlay.
+         (overlay-put
+          (setq gnus-newsgroup-selected-overlay (make-overlay from to))
+          'face gnus-summary-selected-face))))))
+
+(defvar gnus-summary-highlight-line-cached nil)
+(defvar gnus-summary-highlight-line-trigger nil)
+
+(defun gnus-summary-highlight-line-0 ()
+  (if (and (eq gnus-summary-highlight-line-trigger
+               gnus-summary-highlight)
+           gnus-summary-highlight-line-cached)
+      gnus-summary-highlight-line-cached
+    (setq gnus-summary-highlight-line-trigger gnus-summary-highlight
+          gnus-summary-highlight-line-cached
+          (let* ((cond (list 'cond))
+                 (c cond)
+                 (list gnus-summary-highlight))
+            (while list
+              (setcdr c (cons (list (caar list) (list 'quote (cdar list)))
+                             nil))
+              (setq c (cdr c)
+                    list (cdr list)))
+            (gnus-byte-compile (list 'lambda nil cond))))))
+
+(defun gnus-summary-highlight-line ()
+  "Highlight current line according to `gnus-summary-highlight'."
+  (let* ((beg (point-at-bol))
+        (article (or (gnus-summary-article-number) gnus-current-article))
+        (score (or (cdr (assq article
+                              gnus-newsgroup-scored))
+                   gnus-summary-default-score 0))
+        (mark (or (gnus-summary-article-mark) gnus-unread-mark))
+        (inhibit-read-only t)
+        (default gnus-summary-default-score)
+        (default-high gnus-summary-default-high-score)
+        (default-low gnus-summary-default-low-score)
+        (uncached (and gnus-summary-use-undownloaded-faces
+                        (memq article gnus-newsgroup-undownloaded)
+                        (not (memq article gnus-newsgroup-cached)))))
+    (let ((face (funcall (gnus-summary-highlight-line-0))))
+      (unless (eq face (gnus-get-text-property-excluding-characters-with-faces beg 'face))
+       (gnus-put-text-property-excluding-characters-with-faces
+        beg (point-at-eol) 'face
+        (setq face (if (boundp face) (symbol-value face) face)))
+       (when gnus-summary-highlight-line-function
+         (funcall gnus-summary-highlight-line-function article face))))))
+
+(defun gnus-update-read-articles (group unread &optional compute)
+  "Update the list of read articles in GROUP.
+UNREAD is a sorted list."
+  (let ((active (or gnus-newsgroup-active (gnus-active group)))
+       (info (gnus-get-info group))
+       (prev 1)
+       read)
+    (if (or (not info) (not active))
+       ;; There is no info on this group if it was, in fact,
+       ;; killed.  Gnus stores no information on killed groups, so
+       ;; there's nothing to be done.
+       ;; One could store the information somewhere temporarily,
+       ;; perhaps...  Hmmm...
+       ()
+      ;; Remove any negative articles numbers.
+      (while (and unread (< (car unread) 0))
+       (setq unread (cdr unread)))
+      ;; Remove any expired article numbers
+      (while (and unread (< (car unread) (car active)))
+       (setq unread (cdr unread)))
+      ;; Compute the ranges of read articles by looking at the list of
+      ;; unread articles.
+      (while unread
+       (when (/= (car unread) prev)
+         (push (if (= prev (1- (car unread))) prev
+                 (cons prev (1- (car unread))))
+               read))
+       (setq prev (1+ (car unread)))
+       (setq unread (cdr unread)))
+      (when (<= prev (cdr active))
+       (push (cons prev (cdr active)) read))
+      (setq read (if (> (length read) 1) (nreverse read) read))
+      (if compute
+         read
+       (save-excursion
+         (let (setmarkundo)
+           ;; Propagate the read marks to the backend.
+           (when (and (gnus-method-option-p
+                       (gnus-find-method-for-group group)
+                       'server-marks)
+                      (gnus-check-backend-function 'request-set-mark group))
+             (let ((del (gnus-remove-from-range (gnus-info-read info) read))
+                   (add (gnus-remove-from-range read (gnus-info-read info))))
+               (when (or add del)
+                 (unless (gnus-check-group group)
+                   (error "Can't open server for %s" group))
+                 (gnus-request-set-mark
+                  group (delq nil (list (if add (list add 'add '(read)))
+                                        (if del (list del 'del '(read))))))
+                 (setq setmarkundo
+                       `(gnus-request-set-mark
+                         ,group
+                         ',(delq nil (list
+                                      (if del (list del 'add '(read)))
+                                      (if add (list add 'del '(read))))))))))
+           (set-buffer gnus-group-buffer)
+           (gnus-undo-register
+             `(progn
+                (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-group-update-group ,group t)
+                ,setmarkundo))))
+       ;; Enter this list into the group info.
+       (gnus-info-set-read info read)
+       ;; Set the number of unread articles in gnus-newsrc-hashtb.
+       (gnus-get-unread-articles-in-group info (gnus-active group))
+       t))))
+
+(defun gnus-offer-save-summaries ()
+  "Offer to save all active summary buffers."
+  (let (buffers)
+    ;; Go through all buffers and find all summaries.
+    (dolist (buffer (buffer-list))
+      (when (and (setq buffer (buffer-name buffer))
+                (string-match "Summary" buffer)
+                (with-current-buffer buffer
+                  ;; We check that this is, indeed, a summary buffer.
+                  (and (derived-mode-p 'gnus-summary-mode)
+                       ;; Also make sure this isn't bogus.
+                       gnus-newsgroup-prepared
+                       ;; Also make sure that this isn't a
+                       ;; dead summary buffer.
+                       (not gnus-dead-summary-mode))))
+       (push buffer buffers)))
+    ;; Go through all these summary buffers and offer to save them.
+    (when buffers
+      (save-excursion
+       (if (eq gnus-interactive-exit 'quiet)
+           (dolist (buffer buffers)
+             (switch-to-buffer buffer)
+             (gnus-summary-exit))
+         (map-y-or-n-p
+          "Update summary buffer %s? "
+          (lambda (buf)
+            (switch-to-buffer buf)
+            (gnus-summary-exit))
+          buffers))))))
+
+(defun gnus-summary-setup-default-charset ()
+  "Setup newsgroup default charset."
+  (if (member gnus-newsgroup-name '("nndraft:delayed" "nndraft:drafts"))
+      (setq gnus-newsgroup-charset nil)
+    (let* ((ignored-charsets
+           (or gnus-newsgroup-ephemeral-ignored-charsets
+               (append
+                (and gnus-newsgroup-name
+                     (gnus-parameter-ignored-charsets gnus-newsgroup-name))
+                gnus-newsgroup-ignored-charsets))))
+      (setq gnus-newsgroup-charset
+           (or gnus-newsgroup-ephemeral-charset
+               (and gnus-newsgroup-name
+                    (gnus-parameter-charset gnus-newsgroup-name))
+               gnus-default-charset))
+      (set (make-local-variable 'gnus-newsgroup-ignored-charsets)
+          ignored-charsets))))
+
+;;;
+;;; Mime Commands
+;;;
+
+(defun gnus-summary-display-buttonized (&optional show-all-parts)
+  "Display the current article buffer fully MIME-buttonized.
+If SHOW-ALL-PARTS (the prefix) is non-nil, all multipart/* parts are
+treated as multipart/mixed."
+  (interactive "P")
+  (require 'gnus-art)
+  (let ((gnus-unbuttonized-mime-types nil)
+       (gnus-mime-display-multipart-as-mixed show-all-parts))
+    (gnus-summary-show-article)))
+
+(defun gnus-summary-repair-multipart (article)
+  "Add a Content-Type header to a multipart article without one."
+  (interactive (list (gnus-summary-article-number)))
+  (gnus-with-article article
+    (message-narrow-to-head)
+    (message-remove-header "Mime-Version")
+    (goto-char (point-max))
+    (insert "Mime-Version: 1.0\n")
+    (widen)
+    (when (search-forward "\n--" nil t)
+      (let ((separator (buffer-substring (point) (point-at-eol))))
+       (message-narrow-to-head)
+       (message-remove-header "Content-Type")
+       (goto-char (point-max))
+       (insert (format "Content-Type: multipart/mixed; boundary=\"%s\"\n"
+                       separator))
+       (widen))))
+  (let (gnus-mark-article-hook)
+    (gnus-summary-select-article t t nil article)))
+
+(defun gnus-summary-toggle-display-buttonized ()
+  "Toggle the buttonizing of the article buffer."
+  (interactive)
+  (require 'gnus-art)
+  (if (setq gnus-inhibit-mime-unbuttonizing
+           (not gnus-inhibit-mime-unbuttonizing))
+      (let ((gnus-unbuttonized-mime-types nil))
+       (gnus-summary-show-article))
+    (gnus-summary-show-article)))
+
+;;;
+;;; Generic summary marking commands
+;;;
+
+(defvar gnus-summary-marking-alist
+  '((read gnus-del-mark "d")
+    (unread gnus-unread-mark "u")
+    (ticked gnus-ticked-mark "!")
+    (dormant gnus-dormant-mark "?")
+    (expirable gnus-expirable-mark "e"))
+  "An alist of names/marks/keystrokes.")
+
+(defvar gnus-summary-generic-mark-map (make-sparse-keymap))
+(defvar gnus-summary-mark-map)
+
+(defun gnus-summary-make-all-marking-commands ()
+  (define-key gnus-summary-mark-map "M" gnus-summary-generic-mark-map)
+  (dolist (elem gnus-summary-marking-alist)
+    (apply 'gnus-summary-make-marking-command elem)))
+
+(defun gnus-summary-make-marking-command (name mark keystroke)
+  (let ((map (make-sparse-keymap)))
+    (define-key gnus-summary-generic-mark-map keystroke map)
+    (dolist (lway `((next "next" next nil "n")
+                   (next-unread "next unread" next t "N")
+                   (prev "previous" prev nil "p")
+                   (prev-unread "previous unread" prev t "P")
+                   (nomove "" nil nil ,keystroke)))
+      (let ((func (gnus-summary-make-marking-command-1
+                  mark (car lway) lway name)))
+       (setq func (eval func))
+       (define-key map (nth 4 lway) func)))))
+
+(defun gnus-summary-make-marking-command-1 (mark way lway name)
+  `(defun ,(intern
+           (format "gnus-summary-put-mark-as-%s%s"
+                   name (if (eq way 'nomove)
+                            ""
+                          (concat "-" (symbol-name way)))))
+     (n)
+     ,(format
+       "Mark the current article as %s%s.
+If N, the prefix, then repeat N times.
+If N is negative, move in reverse order.
+The difference between N and the actual number of articles marked is
+returned."
+       name (cadr lway))
+     (interactive "p")
+     (gnus-summary-generic-mark n ,mark ',(nth 2 lway) ,(nth 3 lway))))
+
+(defun gnus-summary-generic-mark (n mark move unread)
+  "Mark N articles with MARK."
+  (unless (derived-mode-p 'gnus-summary-mode)
+    (error "This command can only be used in the summary buffer"))
+  (gnus-summary-show-thread)
+  (let ((nummove
+        (cond
+         ((eq move 'next) 1)
+         ((eq move 'prev) -1)
+         (t 0))))
+    (if (zerop nummove)
+       (setq n 1)
+      (when (< n 0)
+       (setq n (abs n)
+             nummove (* -1 nummove))))
+    (while (and (> n 0)
+               (gnus-summary-mark-article nil mark)
+               (zerop (gnus-summary-next-subject nummove unread t)))
+      (setq n (1- n)))
+    (when (/= 0 n)
+      (gnus-message 7 "No more %sarticles" (if mark "" "unread ")))
+    (gnus-summary-recenter)
+    (gnus-summary-position-point)
+    (gnus-set-mode-line 'summary)
+    n))
+
+(defun gnus-summary-insert-articles (articles)
+  (when (setq articles
+             (gnus-sorted-difference articles
+                                     (mapcar (lambda (h)
+                                               (mail-header-number h))
+                                             gnus-newsgroup-headers)))
+    (setq gnus-newsgroup-headers
+         (gnus-merge 'list
+                     gnus-newsgroup-headers
+                     (gnus-fetch-headers articles nil t)
+                     'gnus-article-sort-by-number))
+    (setq gnus-newsgroup-articles
+         (gnus-sorted-nunion gnus-newsgroup-articles articles))
+    ;; Suppress duplicates?
+    (when gnus-suppress-duplicates
+      (gnus-dup-suppress-articles))
+
+    (if (and gnus-fetch-old-headers
+            (eq gnus-headers-retrieved-by 'nov))
+       ;; We might want to build some more threads first.
+       (if (eq gnus-fetch-old-headers 'invisible)
+           (gnus-build-all-threads)
+         (gnus-build-old-threads))
+      ;; Mark the inserted articles that are unread as unread.
+      (setq gnus-newsgroup-unreads
+           (gnus-sorted-nunion
+            gnus-newsgroup-unreads
+            (gnus-sorted-nintersection
+             (gnus-list-of-unread-articles gnus-newsgroup-name)
+             articles)))
+      ;; Mark the inserted articles as selected so that the information
+      ;; of the marks having been changed by a user may be updated when
+      ;; exiting this group.  See `gnus-summary-update-info'.
+      (dolist (art articles)
+       (setq gnus-newsgroup-unselected (delq art gnus-newsgroup-unselected))))
+    ;; Let the Gnus agent mark articles as read.
+    (when gnus-agent
+      (gnus-agent-get-undownloaded-list))
+    ;; Remove list identifiers from subject
+    (gnus-summary-remove-list-identifiers)
+    ;; First and last article in this newsgroup.
+    (when gnus-newsgroup-headers
+      (setq gnus-newsgroup-begin
+           (mail-header-number (car gnus-newsgroup-headers))
+           gnus-newsgroup-end
+           (mail-header-number
+            (gnus-last-element gnus-newsgroup-headers))))
+    (when gnus-use-scoring
+      (gnus-possibly-score-headers))))
+
+(defun gnus-summary-insert-old-articles (&optional all)
+  "Insert all old articles in this group.
+If ALL is non-nil, already read articles become readable.
+If ALL is a number, fetch this number of articles."
+  (interactive "P")
+  (prog1
+      (let ((old (sort (mapcar 'car gnus-newsgroup-data) '<))
+           older len)
+       (setq older
+             ;; Some nntp servers lie about their active range.  When
+             ;; this happens, the active range can be in the millions.
+             ;; Use a compressed range to avoid creating a huge list.
+             (gnus-range-difference
+              (gnus-range-difference (list gnus-newsgroup-active) old)
+              gnus-newsgroup-unexist))
+       (setq len (gnus-range-length older))
+       (cond
+        ((null older) nil)
+        ((numberp all)
+         (if (< all len)
+             (let ((older-range (nreverse older)))
+               (setq older nil)
+
+               (while (> all 0)
+                 (let* ((r (pop older-range))
+                        (min (if (numberp r) r (car r)))
+                        (max (if (numberp r) r (cdr r))))
+                   (while (and (<= min max)
+                               (> all 0))
+                     (push max older)
+                     (setq all (1- all)
+                           max (1- max))))))
+           (setq older (gnus-uncompress-range older))))
+        (all
+         (setq older (gnus-uncompress-range older)))
+        (t
+         (when (and (numberp gnus-large-newsgroup)
+                  (> len gnus-large-newsgroup))
+             (let* ((cursor-in-echo-area nil)
+                    (initial (gnus-parameter-large-newsgroup-initial
+                              gnus-newsgroup-name))
+                    (input
+                     (read-string
+                      (format
+                       "How many articles from %s (%s %d): "
+                       (gnus-group-decoded-name gnus-newsgroup-name)
+                       (if initial "max" "default")
+                       len)
+                      nil nil
+                      (and initial
+                           (number-to-string initial)))))
+               (unless (string-match "^[ \t]*$" input)
+                 (setq all (string-to-number input))
+                 (if (< all len)
+                     (let ((older-range (nreverse older)))
+                       (setq older nil)
+
+                       (while (> all 0)
+                         (let* ((r (pop older-range))
+                                (min (if (numberp r) r (car r)))
+                                (max (if (numberp r) r (cdr r))))
+                           (while (and (<= min max)
+                                       (> all 0))
+                             (push max older)
+                             (setq all (1- all)
+                                   max (1- max))))))))))
+         (setq older (gnus-uncompress-range older))))
+       (if (not older)
+           (message "No old news.")
+         (gnus-summary-insert-articles older)
+         (gnus-summary-limit (gnus-sorted-nunion old older))))
+    (gnus-summary-position-point)))
+
+(defun gnus-summary-insert-new-articles ()
+  "Insert all new articles in this group."
+  (interactive)
+  (let ((old (sort (mapcar 'car gnus-newsgroup-data) '<))
+       (old-high gnus-newsgroup-highest)
+       (nnmail-fetched-sources (list t))
+       (new-active (gnus-activate-group gnus-newsgroup-name 'scan))
+       i new)
+    (unless new-active
+      (error "Couldn't fetch new data"))
+    (setq gnus-newsgroup-active (gnus-copy-sequence new-active))
+    (setq i (cdr gnus-newsgroup-active)
+         gnus-newsgroup-highest i)
+    (while (> i old-high)
+      (push i new)
+      (decf i))
+    (if (not new)
+       (message "No gnus is bad news")
+      (gnus-summary-insert-articles new)
+      (setq gnus-newsgroup-unreads
+           (gnus-sorted-nunion gnus-newsgroup-unreads new))
+      (gnus-summary-limit (gnus-sorted-nunion old new))))
+  (gnus-summary-position-point))
+
+;;; Bookmark support for Gnus.
+(declare-function gnus-article-show-summary "gnus-art" ())
+(declare-function bookmark-make-record-default
+                  "bookmark" (&optional no-file no-context posn))
+(declare-function bookmark-prop-get "bookmark" (bookmark prop))
+(declare-function bookmark-default-handler "bookmark" (bmk))
+(declare-function bookmark-get-bookmark-record "bookmark" (bmk))
+(defvar bookmark-yank-point)
+(defvar bookmark-current-buffer)
+
+(defun gnus-summary-bookmark-make-record ()
+  "Make a bookmark entry for a Gnus summary buffer."
+  (let (pos buf)
+    (unless (and (derived-mode-p 'gnus-summary-mode) gnus-article-current)
+      (save-restriction              ; FIXME is it necessary to widen?
+        (widen) (setq pos (point))) ; Set position in gnus-article buffer.
+      (setq buf "art") ; We are recording bookmark from article buffer.
+      (setq bookmark-yank-point (point))
+      (setq bookmark-current-buffer (current-buffer))
+      (gnus-article-show-summary))      ; Go back in summary buffer.
+    ;; We are now recording bookmark from summary buffer.
+    (unless buf (setq buf "sum"))
+    (let* ((subject (elt (gnus-summary-article-header) 1))
+           (grp     (car gnus-article-current))
+           (art     (cdr gnus-article-current))
+           (head    (gnus-summary-article-header art))
+           (id      (mail-header-id head)))
+      `(,subject
+       ,@(condition-case nil
+             (bookmark-make-record-default 'no-file 'no-context pos)
+           (wrong-number-of-arguments
+            (bookmark-make-record-default 'point-only)))
+        (location . ,(format "Gnus-%s %s:%d:%s" buf grp art id))
+        (group . ,grp) (article . ,art)
+        (message-id . ,id) (handler . gnus-summary-bookmark-jump)))))
+
+;;;###autoload
+(defun gnus-summary-bookmark-jump (bookmark)
+  "Handler function for record returned by `gnus-summary-bookmark-make-record'.
+BOOKMARK is a bookmark name or a bookmark record."
+  (let ((group    (bookmark-prop-get bookmark 'group))
+        (article  (bookmark-prop-get bookmark 'article))
+        (id       (bookmark-prop-get bookmark 'message-id))
+        (buf      (car (split-string (bookmark-prop-get bookmark 'location)))))
+    (gnus-fetch-group group (list article))
+    (gnus-summary-insert-cached-articles)
+    (gnus-summary-goto-article id nil 'force)
+    ;; FIXME we have to wait article buffer is ready (only large buffer)
+    ;; Is there a better solution to know that?
+    ;; If we don't wait `bookmark-default-handler' will have no chance
+    ;; to set position. However there is no error, just wrong pos.
+    (sit-for 1)
+    (when (string= buf "Gnus-art")
+      (other-window 1))
+    (bookmark-default-handler
+     `(""
+       (buffer . ,(current-buffer))
+       . ,(bookmark-get-bookmark-record bookmark)))))
+
+(gnus-summary-make-all-marking-commands)
+
+(gnus-ems-redefine)
+
+(provide 'gnus-sum)
+
+(run-hooks 'gnus-sum-load-hook)
+
+;; Local Variables:
+;; coding: utf-8
+;; End:
+
+;;; gnus-sum.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-sync.el b/xemacs-packages/gnus/lisp/gnus-sync.el
new file mode 100644 (file)
index 0000000..1faa954
--- /dev/null
@@ -0,0 +1,930 @@
+;;; gnus-sync.el --- synchronization facility for Gnus
+
+;; Copyright (C) 2010-2016 Free Software Foundation, Inc.
+
+;; Author: Ted Zlatanov <tzz@lifelogs.com>
+;; Keywords: news synchronization nntp nnrss
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This is the gnus-sync.el package.
+
+;; Put this in your startup file (~/.gnus.el for instance)
+
+;; possibilities for gnus-sync-backend:
+;; Tramp over SSH: /ssh:user@host:/path/to/filename
+;; ...or any other file Tramp and Emacs can handle...
+
+;; (setq gnus-sync-backend "/remote:/path.gpg" ; will use Tramp+EPA if loaded
+;;       gnus-sync-global-vars '(gnus-newsrc-last-checked-date)
+;;       gnus-sync-newsrc-groups '("nntp" "nnrss"))
+;;       gnus-sync-newsrc-offsets '(2 3))
+;; against a LeSync server (beware the vampire LeSync, who knows your newsrc)
+
+;; (setq gnus-sync-backend '(lesync "http://lesync.info:5984/tzz")
+;;       gnus-sync-newsrc-groups '("nntp" "nnrss"))
+
+;; What's a LeSync server?
+
+;; 1. install CouchDB, set up a real server admin user, and create a
+;; database, e.g. "tzz" and save the URL,
+;; e.g. http://lesync.info:5984/tzz
+
+;; 2. run `M-: (gnus-sync-lesync-setup "http://lesync.info:5984/tzz" "tzzadmin" "mypassword" "mysalt" t t)'
+
+;;    (If you run it more than once, you have to remove the entry from
+;;    _users yourself.  This is intentional.  This sets up a database
+;;    admin for the "tzz" database, distinct from the server admin
+;;    user in (1) above.)
+
+;; That's it, you can start using http://lesync.info:5984/tzz in your
+;; gnus-sync-backend as a LeSync backend.  Fan fiction about the
+;; vampire LeSync is welcome.
+
+;; You may not want to expose a CouchDB install to the Big Bad
+;; Internet, especially if your love of all things furry would be thus
+;; revealed.  Make sure it's not accessible by unauthorized users and
+;; guests, at least.
+
+;; If you want to try it out, I will create a test DB for you under
+;; http://lesync.info:5984/yourfavoritedbname
+
+;; TODO:
+
+;; - after gnus-sync-read, the message counts look wrong until you do
+;;   `g'.  So it's not run automatically, you have to call it with M-x
+;;   gnus-sync-read
+
+;; - use gnus-after-set-mark-hook and gnus-before-update-mark-hook to
+;;   catch the mark updates
+
+;; - repositioning of groups within topic after a LeSync sync is a
+;;   weird sort of bubble sort ("buttle" sort: the old entry ends up
+;;   at the rear of the list); you will eventually end up with the
+;;   right order after calling `gnus-sync-read' a bunch of times.
+
+;; - installing topics and groups is inefficient and annoying, lots of
+;;   prompts could be avoided
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(eval-and-compile
+  (or (ignore-errors (progn
+                       (require 'json)))
+      ;; gnus-fallback-lib/ from gnus/lisp/gnus-fallback-lib
+      (ignore-errors
+        (let ((load-path (cons (expand-file-name
+                                "gnus-fallback-lib"
+                                (file-name-directory (locate-library "gnus")))
+                               load-path)))
+          (require 'json)))
+      (error
+       "json not found in `load-path' or gnus-fallback-lib/ directory.")))
+(require 'gnus)
+(require 'gnus-start)
+(require 'gnus-util)
+(require 'gmm-utils)
+
+(defvar gnus-topic-alist) ;; gnus-group.el
+(autoload 'gnus-group-topic "gnus-topic")
+
+(defgroup gnus-sync nil
+  "The Gnus synchronization facility."
+  :version "24.1"
+  :group 'gnus)
+
+(defcustom gnus-sync-newsrc-groups '("nntp" "nnrss")
+  "List of groups to be synchronized in the gnus-newsrc-alist.
+The group names are matched, they don't have to be fully
+qualified.  Typically you would choose all of these.  That's the
+default because there is no active sync backend by default, so
+this setting is harmless until the user chooses a sync backend."
+  :group 'gnus-sync
+  :type '(repeat regexp))
+
+(defcustom gnus-sync-newsrc-offsets '(2 3)
+  "List of per-group data to be synchronized."
+  :group 'gnus-sync
+  :version "24.4"
+  :type '(set (const :tag "Read ranges" 2)
+             (const :tag "Marks" 3)))
+
+(defcustom gnus-sync-global-vars nil
+  "List of global variables to be synchronized.
+You may want to sync `gnus-newsrc-last-checked-date' but pretty
+much any symbol is fair game.  You could additionally sync
+`gnus-newsrc-alist', `gnus-server-alist', `gnus-topic-topology',
+and `gnus-topic-alist'.  Also see `gnus-variable-list'."
+  :group 'gnus-sync
+  :type '(repeat (choice (variable :tag "A known variable")
+                         (symbol :tag "Any symbol"))))
+
+(defcustom gnus-sync-backend nil
+  "The synchronization backend."
+  :group 'gnus-sync
+  :type '(radio (const :format "None" nil)
+                (list :tag "Sync server"
+                      (const :format "LeSync Server API" lesync)
+                      (string :tag "URL of a CouchDB database for API access"))
+                (string :tag "Sync to a file")))
+
+(defvar gnus-sync-newsrc-loader nil
+  "Carrier for newsrc data")
+
+(defcustom gnus-sync-file-encrypt-to nil
+  "If non-nil, set `epa-file-encrypt-to' from this for encrypting the Sync file."
+  :version "24.4"
+  :type '(choice string (repeat string))
+  :group 'gnus-sync)
+
+(defcustom gnus-sync-lesync-name (system-name)
+  "The LeSync name for this machine."
+  :group 'gnus-sync
+  :version "24.3"
+  :type 'string)
+
+(defcustom gnus-sync-lesync-install-topics 'ask
+  "Should LeSync install the recorded topics?"
+  :group 'gnus-sync
+  :version "24.3"
+  :type '(choice (const :tag "Never Install" nil)
+                 (const :tag "Always Install" t)
+                 (const :tag "Ask Me Once" ask)))
+
+(defvar gnus-sync-lesync-props-hash (make-hash-table :test 'equal)
+  "LeSync props, keyed by group name")
+
+(defvar gnus-sync-lesync-design-prefix "/_design/lesync"
+  "The LeSync design prefix for CouchDB")
+
+(defvar gnus-sync-lesync-security-object "/_security"
+  "The LeSync security object for CouchDB")
+
+(defun gnus-sync-lesync-parse ()
+  "Parse the result of a LeSync request."
+  (goto-char (point-min))
+  (condition-case nil
+      (when (search-forward-regexp "^$" nil t)
+        (json-read))
+    (error
+     (gnus-message
+      1
+      "gnus-sync-lesync-parse: Could not read the LeSync response!")
+     nil)))
+
+(defun gnus-sync-lesync-call (url method headers &optional kvdata)
+  "Make an access request to URL using KVDATA and METHOD.
+KVDATA must be an alist."
+  (gmm-flet ((json-alist-p (list) (gnus-sync-json-alist-p list))) ; temp patch
+    (let ((url-request-method method)
+          (url-request-extra-headers headers)
+          (url-request-data (if kvdata (json-encode kvdata) nil)))
+      (with-current-buffer (url-retrieve-synchronously url)
+        (let ((data (gnus-sync-lesync-parse)))
+          (gnus-message 12 "gnus-sync-lesync-call: %s URL %s sent %S got %S"
+                        method url `((headers . ,headers) (data ,kvdata)) data)
+          (kill-buffer (current-buffer))
+          data)))))
+
+(defun gnus-sync-lesync-PUT (url headers &optional data)
+  (gnus-sync-lesync-call url "PUT" headers data))
+
+(defun gnus-sync-lesync-POST (url headers &optional data)
+  (gnus-sync-lesync-call url "POST" headers data))
+
+(defun gnus-sync-lesync-GET (url headers &optional data)
+  (gnus-sync-lesync-call url "GET" headers data))
+
+(defun gnus-sync-lesync-DELETE (url headers &optional data)
+  (gnus-sync-lesync-call url "DELETE" headers data))
+
+;; this is not necessary with newer versions of json.el but 1.2 or older
+;; (which are in Emacs 24.1 and earlier) need it
+(defun gnus-sync-json-alist-p (list)
+  "Non-null if and only if LIST is an alist."
+  (while (consp list)
+    (setq list (if (consp (car list))
+                   (cdr list)
+                 'not-alist)))
+  (null list))
+
+;; this is not necessary with newer versions of json.el but 1.2 or older
+;; (which are in Emacs 24.1 and earlier) need it
+(defun gnus-sync-json-plist-p (list)
+  "Non-null if and only if LIST is a plist."
+  (while (consp list)
+    (setq list (if (and (keywordp (car list))
+                        (consp (cdr list)))
+                   (cddr list)
+                 'not-plist)))
+  (null list))
+
+; (gnus-sync-lesync-setup "http://lesync.info:5984/tzz" "tzzadmin" "mypassword" "mysalt" t t)
+; (gnus-sync-lesync-setup "http://lesync.info:5984/tzz")
+
+(defun gnus-sync-lesync-setup (url &optional user password salt reader admin)
+  (interactive "sEnter URL to set up: ")
+  "Set up the LeSync database at URL.
+Install USER as a READER and/or an ADMIN in the security object
+under \"_security\", and in the CouchDB \"_users\" table using
+PASSWORD and SALT.  Only one USER is thus supported for now.
+When SALT is nil, a random one will be generated using `random'."
+  (let* ((design-url (concat url gnus-sync-lesync-design-prefix))
+         (security-object (concat url "/_security"))
+         (user-record `((names . [,user]) (roles . [])))
+         (couch-user-name (format "org.couchdb.user:%s" user))
+         (salt (or salt (sha1 (format "%s" (random)))))
+         (couch-user-record
+          `((_id . ,couch-user-name)
+            (type . user)
+            (name . ,(format "%s" user))
+            (roles . [])
+            (salt . ,salt)
+            (password_sha . ,(when password
+                               (sha1
+                                (format "%s%s" password salt))))))
+         (rev (progn
+                (gnus-sync-lesync-find-prop 'rev design-url design-url)
+                (gnus-sync-lesync-get-prop 'rev design-url)))
+         (latest-func "function(head,req)
+{
+  var tosend = [];
+  var row;
+  var ftime = (req.query['ftime'] || 0);
+  while (row = getRow())
+  {
+    if (row.value['float-time'] > ftime)
+    {
+      var s = row.value['_id'];
+      if (s) tosend.push('\"'+s.replace('\"', '\\\"')+'\"');
+    }
+  }
+  send('['+tosend.join(',') + ']');
+}")
+;; <key>read</key>
+;; <dict>
+;;   <key>de.alt.fan.ipod</key>
+;;   <array>
+;;       <integer>1</integer>
+;;       <integer>2</integer>
+;;       <dict>
+;;           <key>start</key>
+;;           <integer>100</integer>
+;;           <key>length</key>
+;;           <integer>100</integer>
+;;       </dict>
+;;   </array>
+;; </dict>
+         (xmlplistread-func "function(head, req) {
+  var row;
+  start({ 'headers': { 'Content-Type': 'text/xml' } });
+
+  send('<dict>');
+  send('<key>read</key>');
+  send('<dict>');
+  while(row = getRow())
+  {
+    var read = row.value.read;
+    if (read && read[0] && read[0] == 'invlist')
+    {
+      send('<key>'+row.key+'</key>');
+      //send('<invlist>'+read+'</invlist>');
+      send('<array>');
+
+      var from = 0;
+      var flip = false;
+
+      for (var i = 1; i < read.length && read[i]; i++)
+      {
+        var cur = read[i];
+        if (flip)
+        {
+          if (from == cur-1)
+          {
+            send('<integer>'+read[i]+'</integer>');
+          }
+          else
+          {
+            send('<dict>');
+            send('<key>start</key>');
+            send('<integer>'+from+'</integer>');
+            send('<key>end</key>');
+            send('<integer>'+(cur-1)+'</integer>');
+            send('</dict>');
+          }
+
+        }
+        flip = ! flip;
+        from = cur;
+      }
+      send('</array>');
+    }
+  }
+
+  send('</dict>');
+  send('</dict>');
+}
+")
+         (subs-func "function(doc){emit([doc._id, doc.source], doc._rev);}")
+         (revs-func "function(doc){emit(doc._id, doc._rev);}")
+         (bytimesubs-func "function(doc)
+{emit([(doc['float-time']||0), doc._id], doc._rev);}")
+         (bytime-func "function(doc)
+{emit([(doc['float-time']||0), doc._id], doc);}")
+         (groups-func "function(doc){emit(doc._id, doc);}"))
+    (and (if user
+             (and (assq 'ok (gnus-sync-lesync-PUT
+                             security-object
+                             nil
+                             (append (and reader
+                                          (list `(readers . ,user-record)))
+                                     (and admin
+                                          (list `(admins . ,user-record))))))
+                  (assq 'ok (gnus-sync-lesync-PUT
+                             (concat (file-name-directory url)
+                                     "_users/"
+                                     couch-user-name)
+                             nil
+                             couch-user-record)))
+           t)
+         (assq 'ok (gnus-sync-lesync-PUT
+                    design-url
+                    nil
+                    `(,@(when rev (list (cons '_rev rev)))
+                      (lists . ((latest . ,latest-func)
+                                (xmlplistread . ,xmlplistread-func)))
+                      (views . ((subs . ((map . ,subs-func)))
+                                (revs . ((map . ,revs-func)))
+                                (bytimesubs . ((map . ,bytimesubs-func)))
+                                (bytime . ((map . ,bytime-func)))
+                                (groups . ((map . ,groups-func)))))))))))
+
+(defun gnus-sync-lesync-find-prop (prop url key)
+  "Retrieve a PROPerty of a document KEY at URL.
+Calls `gnus-sync-lesync-set-prop'.
+For the 'rev PROP, uses '_rev against the document."
+  (gnus-sync-lesync-set-prop
+   prop key (cdr (assq (if (eq prop 'rev) '_rev prop)
+                       (gnus-sync-lesync-GET url nil)))))
+
+(defun gnus-sync-lesync-set-prop (prop key val)
+  "Update the PROPerty of document KEY at URL to VAL.
+Updates `gnus-sync-lesync-props-hash'."
+    (puthash (format "%s.%s" key prop) val gnus-sync-lesync-props-hash))
+
+(defun gnus-sync-lesync-get-prop (prop key)
+  "Get the PROPerty of KEY from `gnus-sync-lesync-props-hash'."
+    (gethash (format "%s.%s" key prop) gnus-sync-lesync-props-hash))
+
+(defun gnus-sync-deep-print (data)
+  (let* ((print-quoted t)
+         (print-readably t)
+         (print-escape-multibyte nil)
+         (print-escape-nonascii t)
+         (print-length nil)
+         (print-level nil)
+         (print-circle nil)
+         (print-escape-newlines t))
+    (format "%S" data)))
+
+(defun gnus-sync-newsrc-loader-builder (&optional only-modified)
+  (let* ((entries (cdr gnus-newsrc-alist))
+         entry name ret)
+    (while entries
+      (setq entry (pop entries)
+            name (car entry))
+      (when (gnus-grep-in-list name gnus-sync-newsrc-groups)
+        (if only-modified
+            (when (not (equal (gnus-sync-deep-print entry)
+                              (gnus-sync-lesync-get-prop 'checksum name)))
+              (gnus-message 9 "%s: add %s, it's modified"
+                            "gnus-sync-newsrc-loader-builder" name)
+              (push entry ret))
+          (push entry ret))))
+    ret))
+
+; (json-encode (gnus-sync-range2invlist '((1 . 47137) (47139 . 47714) 48129 48211 49231 49281 49342 49473 49475 49502)))
+(defun gnus-sync-range2invlist (ranges)
+  (append '(invlist)
+          (let ((ranges (delq nil ranges))
+                ret range from to)
+            (while ranges
+              (setq range (pop ranges))
+              (if (atom range)
+                  (setq from range
+                        to range)
+                (setq from (car range)
+                      to (cdr range)))
+              (push from ret)
+              (push (1+ to) ret))
+            (reverse ret))))
+
+; (let* ((d '((1 . 47137) (47139 . 47714) 48129 48211 49231 49281 49342 49473 49475 49502)) (j (format "%S" (gnus-sync-invlist2range (gnus-sync-range2invlist d))))) (or (equal (format "%S" d) j) j))
+(defun gnus-sync-invlist2range (inv)
+  (setq inv (append inv nil))
+  (if (equal (format "%s" (car inv)) "invlist")
+      (let ((i (cdr inv))
+            (start 0)
+            ret cur top flip)
+        (while i
+          (setq cur (pop i))
+          (when flip
+            (setq top (1- cur))
+            (if (= start top)
+                (push start ret)
+              (push (cons start top) ret)))
+          (setq flip (not flip))
+          (setq start cur))
+        (reverse ret))
+    inv))
+
+(defun gnus-sync-position (search list &optional test)
+  "Find the position of SEARCH in LIST using TEST, defaulting to `eq'."
+  (let ((pos 0)
+        (test (or test 'eq)))
+    (while (and list (not (funcall test (car list) search)))
+      (pop list)
+      (incf pos))
+    (if (funcall test (car list) search) pos nil)))
+
+(defun gnus-sync-topic-group-position (group topic-name)
+  (gnus-sync-position
+   group (cdr (assoc topic-name gnus-topic-alist)) 'equal))
+
+(defun gnus-sync-fix-topic-group-position (group topic-name position)
+  (unless (equal position (gnus-sync-topic-group-position group topic-name))
+    (let* ((loc "gnus-sync-fix-topic-group-position")
+           (groups (delete group (cdr (assoc topic-name gnus-topic-alist))))
+           (position (min position (1- (length groups))))
+           (old (nth position groups)))
+      (when (and old (not (equal old group)))
+        (setf (nth position groups) group)
+        (setcdr (assoc topic-name gnus-topic-alist)
+                (append groups (list old)))
+        (gnus-message 9 "%s: %s moved to %d, swap with %s"
+                      loc group position old)))))
+
+(defun gnus-sync-lesync-pre-save-group-entry (url nentry &rest passed-props)
+  (let* ((loc "gnus-sync-lesync-save-group-entry")
+         (k (car nentry))
+         (revision (gnus-sync-lesync-get-prop 'rev k))
+         (sname gnus-sync-lesync-name)
+         (topic (gnus-group-topic k))
+         (topic-offset (gnus-sync-topic-group-position k topic))
+         (sources (gnus-sync-lesync-get-prop 'source k)))
+    ;; set the revision so we don't have a conflict
+    `(,@(when revision
+          (list (cons '_rev revision)))
+      (_id . ,k)
+      ;; the time we saved
+      ,@passed-props
+      ;; add our name to the sources list for this key
+      (source ,@(if (member gnus-sync-lesync-name sources)
+                    sources
+                  (cons gnus-sync-lesync-name sources)))
+      ,(cons 'level (nth 1 nentry))
+      ,@(if topic (list (cons 'topic topic)) nil)
+      ,@(if topic-offset (list (cons 'topic-offset topic-offset)) nil)
+      ;; the read marks
+      ,(cons 'read (gnus-sync-range2invlist (nth 2 nentry)))
+      ;; the other marks
+      ,@(delq nil (mapcar (lambda (mark-entry)
+                            (gnus-message 12 "%s: prep param %s in %s"
+                                          loc
+                                          (car mark-entry)
+                                          (nth 3 nentry))
+                            (if (listp (cdr mark-entry))
+                                (cons (car mark-entry)
+                                      (gnus-sync-range2invlist
+                                       (cdr mark-entry)))
+                              (progn    ; else this is not a list
+                                (gnus-message 9 "%s: non-list param %s in %s"
+                                              loc
+                                              (car mark-entry)
+                                              (nth 3 nentry))
+                                nil)))
+                          (nth 3 nentry))))))
+
+(defun gnus-sync-lesync-post-save-group-entry (url entry)
+  (let* ((loc "gnus-sync-lesync-post-save-group-entry")
+         (k (cdr (assq 'id entry))))
+    (cond
+     ;; success!
+     ((and (assq 'rev entry) (assq 'id entry))
+      (progn
+        (gnus-sync-lesync-set-prop 'rev k (cdr (assq 'rev entry)))
+        (gnus-sync-lesync-set-prop 'checksum
+                                   k
+                                   (gnus-sync-deep-print
+                                    (assoc k gnus-newsrc-alist)))
+        (gnus-message 9 "%s: successfully synced %s to %s"
+                      loc k url)))
+     ;; specifically check for document conflicts
+     ((equal "conflict" (format "%s" (cdr-safe (assq 'error entry))))
+      (gnus-error
+       1
+       "%s: use `%s' to resolve the conflict synchronizing %s to %s: %s"
+       loc "gnus-sync-read" k url (cdr (assq 'reason entry))))
+     ;; generic errors
+     ((assq 'error entry)
+      (gnus-error 1 "%s: got error while synchronizing %s to %s: %s"
+                  loc k url (cdr (assq 'reason entry))))
+
+     (t
+      (gnus-message 2 "%s: unknown sync status after %s to %s: %S"
+                    loc k url entry)))
+    (assoc 'error entry)))
+
+(defun gnus-sync-lesync-groups-builder (url)
+  (let ((u (concat url gnus-sync-lesync-design-prefix "/_view/groups")))
+    (cdr (assq 'rows (gnus-sync-lesync-GET u nil)))))
+
+(defun gnus-sync-subscribe-group (name)
+  "Subscribe to group NAME.  Returns NAME on success, nil otherwise."
+  (gnus-subscribe-newsgroup name))
+
+(defun gnus-sync-lesync-read-group-entry (url name entry &rest passed-props)
+  "Read ENTRY information for NAME.  Returns NAME if successful.
+Skips entries whose sources don't contain
+`gnus-sync-lesync-name'.  When the alist PASSED-PROPS has a
+`subscribe-all' element that evaluates to true, we attempt to
+subscribe to unknown groups.  The user is also allowed to delete
+unwanted groups via the LeSync URL."
+  (let* ((loc "gnus-sync-lesync-read-group-entry")
+         (entry (gnus-sync-lesync-normalize-group-entry entry passed-props))
+         (subscribe-all (cdr (assq 'subscribe-all passed-props)))
+         (sources (cdr (assq 'source entry)))
+         (rev (cdr (assq 'rev entry)))
+         (in-sources (member gnus-sync-lesync-name sources))
+         (known (assoc name gnus-newsrc-alist))
+         cell)
+    (unless known
+      (if (and subscribe-all
+               (y-or-n-p (format "Subscribe to group %s?" name)))
+          (setq known (gnus-sync-subscribe-group name)
+                in-sources t)
+        ;; else...
+        (when (y-or-n-p (format "Delete group %s from server?" name))
+          (if (equal name (gnus-sync-lesync-delete-group url name))
+              (gnus-message 1 "%s: removed group %s from server %s"
+                            loc name url)
+            (gnus-error 1 "%s: could not remove group %s from server %s"
+                        loc name url)))))
+    (when known
+      (unless in-sources
+        (setq in-sources
+              (y-or-n-p
+               (format "Read group %s even though %s is not in sources %S?"
+                       name gnus-sync-lesync-name (or sources ""))))))
+    (when rev
+      (gnus-sync-lesync-set-prop 'rev name rev))
+
+    ;; if the source matches AND we have this group
+    (if (and known in-sources)
+        (progn
+          (gnus-message 10 "%s: reading LeSync entry %s, sources %S"
+                        loc name sources)
+          (while entry
+            (setq cell (pop entry))
+            (let ((k (car cell))
+                  (val (cdr cell)))
+              (gnus-sync-lesync-set-prop k name val)))
+          name)
+      ;; else...
+      (unless known
+        (gnus-message 5 "%s: ignoring entry %s, it wasn't subscribed.  %s"
+                        loc name "Call `gnus-sync-read' with C-u to force it."))
+      (unless in-sources
+        (gnus-message 5 "%s: ignoring entry %s, %s not in sources %S"
+                      loc name gnus-sync-lesync-name (or sources "")))
+      nil)))
+
+(declare-function gnus-topic-create-topic "gnus-topic"
+                  (topic parent &optional previous full-topic))
+(declare-function gnus-topic-enter-dribble "gnus-topic" ())
+
+(defun gnus-sync-lesync-install-group-entry (name)
+  (let* ((master (assoc name gnus-newsrc-alist))
+         (old-topic-name (gnus-group-topic name))
+         (old-topic (assoc old-topic-name gnus-topic-alist))
+         (target-topic-name (gnus-sync-lesync-get-prop 'topic name))
+         (target-topic-offset (gnus-sync-lesync-get-prop 'topic-offset name))
+         (target-topic (assoc target-topic-name gnus-topic-alist))
+         (loc "gnus-sync-lesync-install-group-entry"))
+    (if master
+        (progn
+          (when (eq 'ask gnus-sync-lesync-install-topics)
+            (setq gnus-sync-lesync-install-topics
+                  (y-or-n-p "Install topics from LeSync?")))
+          (when (and (eq t gnus-sync-lesync-install-topics)
+                     target-topic-name)
+            (if (equal old-topic-name target-topic-name)
+                (gnus-message 12 "%s: %s is already in topic %s"
+                              loc name target-topic-name)
+              ;; see `gnus-topic-move-group'
+              (when (and old-topic target-topic)
+                (setcdr old-topic (gnus-delete-first name (cdr old-topic)))
+                (gnus-message 5 "%s: removing %s from topic %s"
+                              loc name old-topic-name))
+              (unless target-topic
+                (when (y-or-n-p (format "Create missing topic %s?"
+                                        target-topic-name))
+                  (gnus-topic-create-topic target-topic-name nil)
+                  (setq target-topic (assoc target-topic-name
+                                            gnus-topic-alist))))
+              (if target-topic
+                  (prog1
+                      (nconc target-topic (list name))
+                    (gnus-message 5 "%s: adding %s to topic %s"
+                                  loc name (car target-topic))
+                    (gnus-topic-enter-dribble))
+                (gnus-error 2 "%s: LeSync group %s can't go in missing topic %s"
+                            loc name target-topic-name)))
+            (when (and target-topic-offset target-topic)
+              (gnus-sync-fix-topic-group-position
+               name target-topic-name target-topic-offset)))
+          ;; install the subscription level
+          (when (gnus-sync-lesync-get-prop 'level name)
+            (setf (nth 1 master) (gnus-sync-lesync-get-prop 'level name)))
+          ;; install the read and other marks
+          (setf (nth 2 master) (gnus-sync-lesync-get-prop 'read name))
+          (setf (nth 3 master) (gnus-sync-lesync-get-prop 'marks name))
+          (gnus-sync-lesync-set-prop 'checksum
+                                     name
+                                     (gnus-sync-deep-print master))
+          nil)
+      (gnus-error 1 "%s: invalid LeSync group %s" loc name)
+      'invalid-name)))
+
+; (gnus-sync-lesync-delete-group (cdr gnus-sync-backend) "nntp+Gmane:gwene.org.slashdot")
+
+(defun gnus-sync-lesync-delete-group (url name)
+  "Returns NAME if successful deleting it from URL, an error otherwise."
+  (interactive "sEnter URL to set up: \rsEnter group name: ")
+  (let* ((u (concat (cadr gnus-sync-backend) "/" (url-hexify-string name)))
+         (del (gnus-sync-lesync-DELETE
+               u
+               `(,@(when (gnus-sync-lesync-get-prop 'rev name)
+                     (list (cons "If-Match"
+                                 (gnus-sync-lesync-get-prop 'rev name))))))))
+    (or (cdr (assq 'id del)) del)))
+
+;;; (gnus-sync-lesync-normalize-group-entry '((subscribe . ["invlist"]) (read . ["invlist"]) (topic-offset . 20) (topic . "news") (level . 6) (source . ["a" "b"]) (float-time . 1319671237.099285) (_rev . "10-edf5107f41e5e6f7f6629d1c0ee172f7") (_id . "nntp+news.net:alt.movies")) '((read-time 1319672156.486414) (subscribe-all nil)))
+
+(defun gnus-sync-lesync-normalize-group-entry (entry &optional passed-props)
+  (let (ret
+        marks
+        cell)
+    (setq entry (append passed-props entry))
+    (while (setq cell (pop entry))
+      (let ((k (car cell))
+            (val (cdr cell)))
+        (cond
+         ((eq k 'read)
+          (push (cons k (gnus-sync-invlist2range val)) ret))
+         ;; we ignore these parameters
+         ((member k '(_id subscribe-all _deleted_conflicts))
+          nil)
+         ((eq k '_rev)
+          (push (cons 'rev val) ret))
+         ((eq k 'source)
+          (push (cons 'source (append val nil)) ret))
+         ((or (eq k 'float-time)
+              (eq k 'level)
+              (eq k 'topic)
+              (eq k 'topic-offset)
+              (eq k 'read-time))
+          (push (cons k val) ret))
+;;; "How often have I said to you that when you have eliminated the
+;;; impossible, whatever remains, however improbable, must be the
+;;; truth?" --Sherlock Holmes
+          ;; everything remaining must be a mark
+          (t (push (cons k (gnus-sync-invlist2range val)) marks)))))
+    (cons (cons 'marks marks) ret)))
+
+(defun gnus-sync-save (&optional force)
+"Save the Gnus sync data to the backend.
+With a prefix, FORCE is set and all groups will be saved."
+  (interactive "P")
+  (cond
+   ((and (listp gnus-sync-backend)
+         (eq (nth 0 gnus-sync-backend) 'lesync)
+         (stringp (nth 1 gnus-sync-backend)))
+
+    ;; refresh the revisions if we're forcing the save
+    (when force
+      (mapc (lambda (entry)
+              (when (and (assq 'key entry)
+                         (assq 'value entry))
+                (gnus-sync-lesync-set-prop
+                 'rev
+                 (cdr (assq 'key entry))
+                 (cdr (assq 'value entry)))))
+            ;; the revs view is key = name, value = rev
+            (cdr (assq 'rows (gnus-sync-lesync-GET
+                              (concat (nth 1 gnus-sync-backend)
+                                      gnus-sync-lesync-design-prefix
+                                      "/_view/revs")
+                              nil)))))
+
+    (let* ((ftime (float-time))
+           (url (nth 1 gnus-sync-backend))
+           (entries
+            (mapcar (lambda (entry)
+                      (gnus-sync-lesync-pre-save-group-entry
+                       (cadr gnus-sync-backend)
+                       entry
+                       (cons 'float-time ftime)))
+                    (gnus-sync-newsrc-loader-builder (not force))))
+           ;; when there are no entries, there's nothing to save
+           (sync (if entries
+                     (gnus-sync-lesync-POST
+                      (concat url "/_bulk_docs")
+                      '(("Content-Type" . "application/json"))
+                      `((docs . ,(vconcat entries nil))))
+                   (gnus-message
+                    2 "gnus-sync-save: nothing to save to the LeSync backend")
+                   nil)))
+      (mapcar (lambda (e) (gnus-sync-lesync-post-save-group-entry url e))
+              sync)))
+   ((stringp gnus-sync-backend)
+    (gnus-message 7 "gnus-sync-save: saving to backend %s" gnus-sync-backend)
+    ;; populate gnus-sync-newsrc-loader from all but the first dummy
+    ;; entry in gnus-newsrc-alist whose group matches any of the
+    ;; gnus-sync-newsrc-groups
+    ;; TODO: keep the old contents for groups we don't have!
+    (let ((gnus-sync-newsrc-loader
+          (loop for entry in (cdr gnus-newsrc-alist)
+                when (gnus-grep-in-list
+                      (car entry)     ;the group name
+                      gnus-sync-newsrc-groups)
+                collect (cons (car entry)
+                              (mapcar (lambda (offset)
+                                        (cons offset (nth offset entry)))
+                                      gnus-sync-newsrc-offsets)))))
+      (with-temp-file gnus-sync-backend
+        (progn
+          (let ((coding-system-for-write gnus-ding-file-coding-system)
+                (standard-output (current-buffer)))
+            (when gnus-sync-file-encrypt-to
+              (set (make-local-variable 'epa-file-encrypt-to)
+                   gnus-sync-file-encrypt-to))
+            (princ (format ";; -*- mode:emacs-lisp; coding: %s; -*-\n"
+                           gnus-ding-file-coding-system))
+            (princ ";; Gnus sync data v. 0.0.1\n")
+            ;; TODO: replace with `gnus-sync-deep-print'
+            (let* ((print-quoted t)
+                   (print-readably t)
+                   (print-escape-multibyte nil)
+                   (print-escape-nonascii t)
+                   (print-length nil)
+                   (print-level nil)
+                   (print-circle nil)
+                   (print-escape-newlines t)
+                   (variables (cons 'gnus-sync-newsrc-loader
+                                    gnus-sync-global-vars))
+                   variable)
+              (while variables
+                (if (and (boundp (setq variable (pop variables)))
+                           (symbol-value variable))
+                    (progn
+                      (princ "\n(setq ")
+                      (princ (symbol-name variable))
+                      (princ " '")
+                      (prin1 (symbol-value variable))
+                      (princ ")\n"))
+                  (princ "\n;;; skipping empty variable ")
+                  (princ (symbol-name variable)))))
+            (gnus-message
+             7
+             "gnus-sync-save: stored variables %s and %d groups in %s"
+             gnus-sync-global-vars
+             (length gnus-sync-newsrc-loader)
+             gnus-sync-backend)
+
+            ;; Idea from Dan Christensen <jdc@chow.mat.jhu.edu>
+            ;; Save the .eld file with extra line breaks.
+            (gnus-message 8 "gnus-sync-save: adding whitespace to %s"
+                          gnus-sync-backend)
+            (save-excursion
+              (goto-char (point-min))
+              (while (re-search-forward "^(\\|(\\\"" nil t)
+                (replace-match "\n\\&" t))
+              (goto-char (point-min))
+              (while (re-search-forward " $" nil t)
+                (replace-match "" t t))))))))
+    ;; the pass-through case: gnus-sync-backend is not a known choice
+    (nil)))
+
+(defun gnus-sync-read (&optional subscribe-all)
+  "Load the Gnus sync data from the backend.
+With a prefix, SUBSCRIBE-ALL is set and unknown groups will be subscribed."
+  (interactive "P")
+  (when gnus-sync-backend
+    (gnus-message 7 "gnus-sync-read: loading from backend %s" gnus-sync-backend)
+    (cond
+     ((and (listp gnus-sync-backend)
+           (eq (nth 0 gnus-sync-backend) 'lesync)
+           (stringp (nth 1 gnus-sync-backend)))
+      (let ((errored nil)
+            name ftime)
+        (mapc (lambda (entry)
+               (setq name (cdr (assq 'id entry)))
+               ;; set ftime the FIRST time through this loop, that
+               ;; way it reflects the time we FINISHED reading
+               (unless ftime (setq ftime (float-time)))
+
+               (unless errored
+                 (setq errored
+                       (when (equal name
+                                    (gnus-sync-lesync-read-group-entry
+                                     (nth 1 gnus-sync-backend)
+                                     name
+                                     (cdr (assq 'value entry))
+                                     `(read-time ,ftime)
+                                     `(subscribe-all ,subscribe-all)))
+                         (gnus-sync-lesync-install-group-entry
+                          (cdr (assq 'id entry)))))))
+             (gnus-sync-lesync-groups-builder (nth 1 gnus-sync-backend)))))
+
+     ((stringp gnus-sync-backend)
+      ;; read data here...
+      (if (or debug-on-error debug-on-quit)
+          (load gnus-sync-backend nil t)
+        (condition-case var
+            (load gnus-sync-backend nil t)
+          (error
+           (error "Error in %s: %s" gnus-sync-backend (cadr var)))))
+      (let ((valid-count 0)
+            invalid-groups)
+        (dolist (node gnus-sync-newsrc-loader)
+          (if (gnus-gethash (car node) gnus-newsrc-hashtb)
+              (progn
+                (incf valid-count)
+                (loop for store in (cdr node)
+                      do (setf (nth (car store)
+                                    (assoc (car node) gnus-newsrc-alist))
+                               (cdr store))))
+            (push (car node) invalid-groups)))
+        (gnus-message
+         7
+         "gnus-sync-read: loaded %d groups (out of %d) from %s"
+         valid-count (length gnus-sync-newsrc-loader)
+         gnus-sync-backend)
+        (when invalid-groups
+          (gnus-message
+           7
+           "gnus-sync-read: skipped %d groups (out of %d) from %s"
+           (length invalid-groups)
+           (length gnus-sync-newsrc-loader)
+           gnus-sync-backend)
+          (gnus-message 9 "gnus-sync-read: skipped groups: %s"
+                        (mapconcat 'identity invalid-groups ", ")))))
+     (nil))
+
+    (gnus-message 9 "gnus-sync-read: remaking the newsrc hashtable")
+    (gnus-make-hashtable-from-newsrc-alist)))
+
+;;;###autoload
+(defun gnus-sync-initialize ()
+"Initialize the Gnus sync facility."
+  (interactive)
+  (gnus-message 5 "Initializing the sync facility")
+  (gnus-sync-install-hooks))
+
+;;;###autoload
+(defun gnus-sync-install-hooks ()
+  "Install the sync hooks."
+  (interactive)
+  ;; (add-hook 'gnus-get-new-news-hook 'gnus-sync-read)
+  ;; (add-hook 'gnus-read-newsrc-el-hook 'gnus-sync-read)
+  (add-hook 'gnus-save-newsrc-hook 'gnus-sync-save))
+
+(defun gnus-sync-unload-hook ()
+  "Uninstall the sync hooks."
+  (interactive)
+  (remove-hook 'gnus-save-newsrc-hook 'gnus-sync-save))
+
+(add-hook 'gnus-sync-unload-hook 'gnus-sync-unload-hook)
+
+(when gnus-sync-backend (gnus-sync-initialize))
+
+(provide 'gnus-sync)
+
+;;; gnus-sync.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-topic.el b/xemacs-packages/gnus/lisp/gnus-topic.el
new file mode 100644 (file)
index 0000000..24ae4cf
--- /dev/null
@@ -0,0 +1,1773 @@
+;;; gnus-topic.el --- a folding minor mode for Gnus group buffers
+
+;; Copyright (C) 1995-2016 Free Software Foundation, Inc.
+
+;; Author: Ilja Weis <kult@uni-paderborn.de>
+;;     Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'gnus)
+(require 'gnus-group)
+(require 'gnus-start)
+(require 'gnus-util)
+
+(defgroup gnus-topic nil
+  "Group topics."
+  :group 'gnus-group)
+
+(defvar gnus-topic-mode nil
+  "Minor mode for Gnus group buffers.")
+
+(defcustom gnus-topic-mode-hook nil
+  "Hook run in topic mode buffers."
+  :type 'hook
+  :group 'gnus-topic)
+
+(when (featurep 'xemacs)
+  (add-hook 'gnus-topic-mode-hook 'gnus-xmas-topic-menu-add))
+
+(defcustom gnus-topic-line-format "%i[ %(%{%n%}%) -- %A ]%v\n"
+  "Format of topic lines.
+It works along the same lines as a normal formatting string,
+with some simple extensions.
+
+%i  Indentation based on topic level.
+%n  Topic name.
+%v  Nothing if the topic is visible, \"...\" otherwise.
+%g  Number of groups in the topic.
+%a  Number of unread articles in the groups in the topic.
+%A  Number of unread articles in the groups in the topic and its subtopics.
+
+General format specifiers can also be used.
+See Info node `(gnus)Formatting Variables'."
+  :link '(custom-manual "(gnus)Formatting Variables")
+  :type 'string
+  :group 'gnus-topic)
+
+(defcustom gnus-topic-indent-level 2
+  "*How much each subtopic should be indented."
+  :type 'integer
+  :group 'gnus-topic)
+
+(defcustom gnus-topic-display-empty-topics t
+  "*If non-nil, display the topic lines even of topics that have no unread articles."
+  :type 'boolean
+  :group 'gnus-topic)
+
+;; Internal variables.
+
+(defvar gnus-topic-active-topology nil)
+(defvar gnus-topic-active-alist nil)
+(defvar gnus-topic-unreads nil)
+
+(defvar gnus-topology-checked-p nil
+  "Whether the topology has been checked in this session.")
+
+(defvar gnus-topic-killed-topics nil)
+(defvar gnus-topic-inhibit-change-level nil)
+
+(defconst gnus-topic-line-format-alist
+  `((?n name ?s)
+    (?v visible ?s)
+    (?i indentation ?s)
+    (?g number-of-groups ?d)
+    (?a (gnus-topic-articles-in-topic entries) ?d)
+    (?A total-number-of-articles ?d)
+    (?l level ?d)))
+
+(defvar gnus-topic-line-format-spec nil)
+
+;;; Utility functions
+
+(defun gnus-group-topic-name ()
+  "The name of the topic on the current line."
+  (let ((topic (get-text-property (point-at-bol) 'gnus-topic)))
+    (and topic (symbol-name topic))))
+
+(defun gnus-group-topic-level ()
+  "The level of the topic on the current line."
+  (get-text-property (point-at-bol) 'gnus-topic-level))
+
+(defun gnus-group-topic-unread ()
+  "The number of unread articles in topic on the current line."
+  (get-text-property (point-at-bol) 'gnus-topic-unread))
+
+(defun gnus-topic-unread (topic)
+  "Return the number of unread articles in TOPIC."
+  (or (cdr (assoc topic gnus-topic-unreads))
+      0))
+
+(defun gnus-group-topic-p ()
+  "Return non-nil if the current line is a topic."
+  (gnus-group-topic-name))
+
+(defun gnus-topic-visible-p ()
+  "Return non-nil if the current topic is visible."
+  (get-text-property (point-at-bol) 'gnus-topic-visible))
+
+(defun gnus-topic-articles-in-topic (entries)
+  (let ((total 0)
+       number)
+    (while entries
+      (when (numberp (setq number (car (pop entries))))
+       (incf total number)))
+    total))
+
+(defun gnus-group-topic (group)
+  "Return the topic GROUP is a member of."
+  (let ((alist gnus-topic-alist)
+       out)
+    (while alist
+      (when (member group (cdar alist))
+       (setq out (caar alist)
+             alist nil))
+      (setq alist (cdr alist)))
+    out))
+
+(defun gnus-topic-goto-topic (topic)
+  (when topic
+    (gnus-goto-char (text-property-any (point-min) (point-max)
+                                      'gnus-topic (intern topic)))))
+
+(defun gnus-topic-jump-to-topic (topic)
+  "Go to TOPIC."
+  (interactive
+   (list (gnus-completing-read "Go to topic" (gnus-topic-list) t)))
+  (let ((inhibit-read-only t))
+    (dolist (topic (gnus-current-topics topic))
+      (unless (gnus-topic-goto-topic topic)
+       (gnus-topic-goto-missing-topic topic)
+       (gnus-topic-display-missing-topic topic))))
+  (gnus-topic-goto-topic topic))
+
+(defun gnus-current-topic ()
+  "Return the name of the current topic."
+  (let ((result
+        (or (get-text-property (point) 'gnus-topic)
+            (save-excursion
+              (and (gnus-goto-char (previous-single-property-change
+                                    (point) 'gnus-topic))
+                   (get-text-property (max (1- (point)) (point-min))
+                                      'gnus-topic))))))
+    (when result
+      (symbol-name result))))
+
+(defun gnus-current-topics (&optional topic)
+  "Return a list of all current topics, lowest in hierarchy first.
+If TOPIC, start with that topic."
+  (let ((topic (or topic (gnus-current-topic)))
+       topics)
+    (while topic
+      (push topic topics)
+      (setq topic (gnus-topic-parent-topic topic)))
+    (nreverse topics)))
+
+(defun gnus-group-active-topic-p ()
+  "Say whether the current topic comes from the active topics."
+  (get-text-property (point-at-bol) 'gnus-active))
+
+(defun gnus-topic-find-groups (topic &optional level all lowest recursive)
+  "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)
+    (setq lowest (or lowest 1))
+    (setq level (or level gnus-level-unsubscribed))
+    ;; We go through the newsrc to look for matches.
+    (while groups
+      (when (setq group (pop groups))
+       (setq entry (gnus-group-entry group)
+             info (nth 2 entry)
+             params (gnus-info-params info)
+             active (gnus-active group)
+             unread (or (car entry)
+                        (and (not (equal group "dummy.group"))
+                             active
+                             (- (1+ (cdr active)) (car active))))
+             clevel (or (gnus-info-level info)
+                        (if (member group gnus-zombie-list)
+                            gnus-level-zombie gnus-level-killed))))
+      (and
+       info                            ; nil means that the group is dead.
+       (<= clevel level)
+       (>= clevel lowest)              ; Is inside the level we want.
+       (or all
+          (if (or (eq unread t)
+                  (eq unread nil))
+              gnus-group-list-inactive-groups
+            (> unread 0))
+          (and gnus-list-groups-with-ticked-articles
+               (cdr (assq 'tick (gnus-info-marks info))))
+          ;; Has right readedness.
+          ;; Check for permanent visibility.
+          (and gnus-permanently-visible-groups
+               (string-match gnus-permanently-visible-groups group))
+          (memq 'visible params)
+          (cdr (assq 'visible params)))
+       ;; Add this group to the list of visible groups.
+       (push (or entry group) visible-groups)))
+    (setq visible-groups (nreverse visible-groups))
+    (when recursive
+      (if (eq recursive t)
+         (setq recursive (cdr (gnus-topic-find-topology topic))))
+      (dolist (topic-topology (cdr recursive))
+       (setq visible-groups
+             (nconc visible-groups
+                    (gnus-topic-find-groups
+                     (caar topic-topology)
+                     level all lowest topic-topology)))))
+    visible-groups))
+
+(defun gnus-topic-goto-previous-topic (n)
+  "Go to the N'th previous topic."
+  (interactive "p")
+  (gnus-topic-goto-next-topic (- n)))
+
+(defun gnus-topic-goto-next-topic (n)
+  "Go to the N'th next topic."
+  (interactive "p")
+  (let ((backward (< n 0))
+       (n (abs n))
+       (topic (gnus-current-topic)))
+    (while (and (> n 0)
+               (setq topic
+                     (if backward
+                         (gnus-topic-previous-topic topic)
+                       (gnus-topic-next-topic topic))))
+      (gnus-topic-goto-topic topic)
+      (setq n (1- n)))
+    (when (/= 0 n)
+      (gnus-message 7 "No more topics"))
+    n))
+
+(defun gnus-topic-previous-topic (topic)
+  "Return the previous topic on the same level as TOPIC."
+  (let ((top (cddr (gnus-topic-find-topology
+                   (gnus-topic-parent-topic topic)))))
+    (unless (equal topic (caaar top))
+      (while (and top (not (equal (caaadr top) topic)))
+       (setq top (cdr top)))
+      (caaar top))))
+
+(defun gnus-topic-parent-topic (topic &optional topology)
+  "Return the parent of TOPIC."
+  (unless topology
+    (setq topology gnus-topic-topology))
+  (let ((parent (car (pop topology)))
+       result found)
+    (while (and topology
+               (not (setq found (equal (caaar topology) topic)))
+               (not (setq result (gnus-topic-parent-topic
+                                  topic (car topology)))))
+      (setq topology (cdr topology)))
+    (or result (and found parent))))
+
+(defun gnus-topic-next-topic (topic &optional previous)
+  "Return the next sibling of TOPIC."
+  (let ((parentt (cddr (gnus-topic-find-topology
+                       (gnus-topic-parent-topic topic))))
+       prev)
+    (while (and parentt
+               (not (equal (caaar parentt) topic)))
+      (setq prev (caaar parentt)
+           parentt (cdr parentt)))
+    (if previous
+       prev
+      (caaadr parentt))))
+
+(defun gnus-topic-forward-topic (num)
+  "Go to the next topic on the same level as the current one."
+  (let* ((topic (gnus-current-topic))
+        (way (if (< num 0) 'gnus-topic-previous-topic
+               'gnus-topic-next-topic))
+        (num (abs num)))
+    (while (and (not (zerop num))
+               (setq topic (funcall way topic)))
+      (when (gnus-topic-goto-topic topic)
+       (decf num)))
+    (unless (zerop num)
+      (goto-char (point-max)))
+    num))
+
+(defun gnus-topic-find-topology (topic &optional topology level remove)
+  "Return the topology of TOPIC."
+  (unless topology
+    (setq topology gnus-topic-topology)
+    (setq level 0))
+  (let ((top topology)
+       result)
+    (if (equal (caar topology) topic)
+       (progn
+         (when remove
+           (delq topology remove))
+         (cons level topology))
+      (setq topology (cdr topology))
+      (while (and topology
+                 (not (setq result (gnus-topic-find-topology
+                                    topic (car topology) (1+ level)
+                                    (and remove top)))))
+       (setq topology (cdr topology)))
+      result)))
+
+(defvar gnus-tmp-topics nil)
+(defun gnus-topic-list (&optional topology)
+  "Return a list of all topics in the topology."
+  (unless topology
+    (setq topology gnus-topic-topology
+         gnus-tmp-topics nil))
+  (push (caar topology) gnus-tmp-topics)
+  (mapc 'gnus-topic-list (cdr topology))
+  gnus-tmp-topics)
+
+;;; Topic parameter jazz
+
+(defun gnus-topic-parameters (topic)
+  "Return the parameters for TOPIC."
+  (let ((top (gnus-topic-find-topology topic)))
+    (when top
+      (nth 3 (cadr top)))))
+
+(defun gnus-topic-set-parameters (topic parameters)
+  "Set the topic parameters of TOPIC to PARAMETERS."
+  (let ((top (gnus-topic-find-topology topic)))
+    (unless top
+      (error "No such topic: %s" topic))
+    ;; We may have to extend if there is no parameters here
+    ;; to begin with.
+    (unless (nthcdr 2 (cadr top))
+      (nconc (cadr top) (list nil)))
+    (unless (nthcdr 3 (cadr top))
+      (nconc (cadr top) (list nil)))
+    (setcar (nthcdr 3 (cadr top)) parameters)
+    (gnus-dribble-enter
+     (format "(gnus-topic-set-parameters %S '%S)" topic parameters))))
+
+(defun gnus-group-topic-parameters (group)
+  "Compute the group parameters for GROUP in topic mode.
+Possibly inherit parameters from topics above GROUP."
+  (let ((params-list (copy-sequence (gnus-group-get-parameter group))))
+    (save-excursion
+      (gnus-topic-hierarchical-parameters
+       ;; First we try to go to the group within the group buffer and find the
+       ;; topic for the group that way. This hopefully copes well with groups
+       ;; that are in more than one topic. Failing that (i.e. when the group
+       ;; isn't visible in the group buffer) we find a topic for the group via
+       ;; gnus-group-topic.
+       (or (and (gnus-group-goto-group group)
+               (gnus-current-topic))
+          (gnus-group-topic group))
+       params-list))))
+
+(defun gnus-topic-hierarchical-parameters (topic &optional group-params-list)
+  "Compute the topic parameters for TOPIC.
+Possibly inherit parameters from topics above TOPIC.
+If optional argument GROUP-PARAMS-LIST is non-nil, use it as the basis for
+inheritance."
+  (let ((params-list
+        ;; We probably have lots of nil elements here, so we remove them.
+        ;; Probably faster than doing this "properly".
+        (delq nil (cons group-params-list
+                        (mapcar 'gnus-topic-parameters
+                                (gnus-current-topics topic)))))
+       param out params)
+    ;; Now we have all the parameters, so we go through them
+    ;; and do inheritance in the obvious way.
+    (let (posting-style)
+      (while (setq params (pop params-list))
+       (while (setq param (pop params))
+         (when (atom param)
+           (setq param (cons param t)))
+         (cond ((eq (car param) 'posting-style)
+                (let ((param (cdr param))
+                      elt)
+                  (while (setq elt (pop param))
+                    (unless (assoc (car elt) posting-style)
+                      (push elt posting-style)))))
+               (t
+                (unless (assq (car param) out)
+                  (push param out))))))
+      (and posting-style (push (cons 'posting-style posting-style) out)))
+    ;; Return the resulting parameter list.
+    out))
+
+;;; General utility functions
+
+(defun gnus-topic-enter-dribble ()
+  (gnus-dribble-enter
+   (format "(setq gnus-topic-topology '%S)" gnus-topic-topology)))
+
+;;; Generating group buffers
+
+(defun gnus-group-prepare-topics (level &optional predicate lowest
+                                       regexp list-topic topic-level)
+  "List all newsgroups with unread articles of level LEVEL or lower.
+Use the `gnus-group-topics' to sort the groups.
+If PREDICATE is a function, list groups that the function returns non-nil;
+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 ((inhibit-read-only t)
+       (lowest (or lowest 1))
+       (not-in-list
+        (and gnus-group-listed-groups
+             (copy-sequence gnus-group-listed-groups))))
+
+    (gnus-update-format-specifications nil 'topic)
+
+    (when (or (not gnus-topic-alist)
+             (not gnus-topology-checked-p))
+      (gnus-topic-check-topology))
+
+    (unless list-topic
+      (erase-buffer))
+
+    ;; List dead groups?
+    (when (or gnus-group-listed-groups
+             (and (>= level gnus-level-zombie)
+                  (<= lowest gnus-level-zombie)))
+      (gnus-group-prepare-flat-list-dead
+       (setq gnus-zombie-list (sort gnus-zombie-list 'string<))
+       gnus-level-zombie ?Z
+       regexp))
+
+    (when (or gnus-group-listed-groups
+              (and (>= level gnus-level-killed)
+                   (<= lowest gnus-level-killed)))
+      (gnus-group-prepare-flat-list-dead
+       (setq gnus-killed-list (sort gnus-killed-list 'string<))
+       gnus-level-killed ?K regexp)
+      (when not-in-list
+       (unless gnus-killed-hashtb
+         (gnus-make-hashtable-from-killed))
+       (gnus-group-prepare-flat-list-dead
+        (gnus-remove-if (lambda (group)
+                          (or (gnus-group-entry group)
+                              (gnus-gethash group gnus-killed-hashtb)))
+                        not-in-list)
+        gnus-level-killed ?K regexp)))
+
+    ;; Use topics.
+    (prog1
+       (when (or (< lowest gnus-level-zombie)
+                 gnus-group-listed-groups)
+         (if list-topic
+             (let ((top (gnus-topic-find-topology list-topic)))
+               (gnus-topic-prepare-topic (cdr top) (car top)
+                                         (or topic-level level) predicate
+                                         nil lowest regexp))
+           (gnus-topic-prepare-topic gnus-topic-topology 0
+                                     (or topic-level level) predicate
+                                     nil lowest regexp)))
+      (gnus-group-set-mode-line)
+      (setq gnus-group-list-mode (cons level predicate))
+      (gnus-run-hooks 'gnus-group-prepare-hook))))
+
+(defun gnus-topic-prepare-topic (topicl level &optional list-level
+                                       predicate silent
+                                       lowest regexp)
+  "Insert TOPIC into the group buffer.
+If SILENT, don't insert anything.  Return the number of unread
+articles in the topic and its subtopics."
+  (let* ((type (pop topicl))
+        (entries (gnus-topic-find-groups
+                  (car type)
+                  (if gnus-group-listed-groups
+                      gnus-level-killed
+                    list-level)
+                  (or predicate gnus-group-listed-groups
+                      (cdr (assq 'visible
+                                 (gnus-topic-hierarchical-parameters
+                                  (car type)))))
+                  (if gnus-group-listed-groups 0 lowest)))
+        (visiblep (and (eq (nth 1 type) 'visible) (not silent)))
+        (gnus-group-indentation
+         (make-string (* gnus-topic-indent-level level) ? ))
+        (beg (progn (beginning-of-line) (point)))
+        (topicl (reverse topicl))
+        (all-entries entries)
+        (point-max (point-max))
+        (unread 0)
+        info entry end active tick)
+    ;; Insert any sub-topics.
+    (while topicl
+      (incf unread
+           (gnus-topic-prepare-topic
+            (pop topicl) (1+ level) list-level predicate
+            (not visiblep) lowest regexp)))
+    (setq end (point))
+    (goto-char beg)
+    ;; Insert all the groups that belong in this topic.
+    (while (setq entry (pop entries))
+      (when (if (stringp entry)
+               (gnus-group-prepare-logic
+                entry
+                (and
+                 (or (not gnus-group-listed-groups)
+                     (if (< list-level gnus-level-zombie) nil
+                       (let ((entry-level
+                              (if (member entry gnus-zombie-list)
+                                  gnus-level-zombie gnus-level-killed)))
+                         (and (<= entry-level list-level)
+                              (>= entry-level lowest)))))
+                 (cond
+                  ((stringp regexp)
+                   (string-match regexp entry))
+                  ((functionp regexp)
+                   (funcall regexp entry))
+                  ((null regexp) t)
+                  (t nil))))
+             (setq info (nth 2 entry))
+             (gnus-group-prepare-logic
+              (gnus-info-group info)
+              (and (or (not gnus-group-listed-groups)
+                       (let ((entry-level (gnus-info-level info)))
+                         (and (<= entry-level list-level)
+                              (>= entry-level lowest))))
+                   (or (not (functionp predicate))
+                       (funcall predicate info))
+                   (or (not (stringp regexp))
+                       (string-match regexp (gnus-info-group info))))))
+       (when visiblep
+         (if (stringp entry)
+             ;; Dead groups.
+             (gnus-group-insert-group-line
+              entry (if (member entry gnus-zombie-list)
+                        gnus-level-zombie gnus-level-killed)
+              nil (- (1+ (cdr (setq active (gnus-active entry))))
+                     (car active))
+              nil)
+           ;; Living groups.
+           (when (setq info (nth 2 entry))
+             (gnus-group-insert-group-line
+              (gnus-info-group info)
+              (gnus-info-level info) (gnus-info-marks info)
+              (car entry) (gnus-info-method info)))))
+       (when (and (listp entry)
+                  (numberp (car entry)))
+         (incf unread (car entry)))
+       (when (listp entry)
+         (setq tick t))))
+    (goto-char beg)
+    ;; Insert the topic line.
+    (when (and (not silent)
+              (or gnus-topic-display-empty-topics ;We want empty topics
+                  (not (zerop unread)) ;Non-empty
+                  tick                 ;Ticked articles
+                  (/= point-max (point-max)))) ;Inactive groups
+      (gnus-extent-start-open (point))
+      (gnus-topic-insert-topic-line
+       (car type) visiblep
+       (not (eq (nth 2 type) 'hidden))
+       level all-entries unread))
+    (gnus-topic-update-unreads (car type) unread)
+    (gnus-group--setup-tool-bar-update beg end)
+    (goto-char end)
+    unread))
+
+(defun gnus-topic-remove-topic (&optional insert total-remove _hide in-level)
+  "Remove the current topic."
+  (let ((topic (gnus-group-topic-name))
+       (level (gnus-group-topic-level))
+       (beg (progn (beginning-of-line) (point)))
+       buffer-read-only)
+    (when topic
+      (while (and (zerop (forward-line 1))
+                 (> (or (gnus-group-topic-level) (1+ level)) level)))
+      (delete-region beg (point))
+      ;; Do the change in this rather odd manner because it has been
+      ;; reported that some topics share parts of some lists, for some
+      ;; reason.  I have been unable to determine why this is the
+      ;; case, but this hack seems to take care of things.
+      (let ((data (cadr (gnus-topic-find-topology topic))))
+       (setcdr data
+               (list (if insert 'visible 'invisible)
+                     (caddr data)
+                     (cadddr data))))
+      (if total-remove
+         (setq gnus-topic-alist
+               (delq (assoc topic gnus-topic-alist) gnus-topic-alist))
+       (gnus-topic-insert-topic topic in-level)))))
+
+(defun gnus-topic-insert-topic (topic &optional level)
+  "Insert TOPIC."
+  (gnus-group-prepare-topics
+   (car gnus-group-list-mode) (cdr gnus-group-list-mode)
+   nil nil topic level))
+
+(defun gnus-topic-fold (&optional insert topic)
+  "Remove/insert the current topic."
+  (let ((topic (or topic (gnus-group-topic-name))))
+    (when topic
+      (save-excursion
+       (if (not (gnus-group-active-topic-p))
+           (gnus-topic-remove-topic
+            (or insert (not (gnus-topic-visible-p))))
+         (let ((gnus-topic-topology gnus-topic-active-topology)
+               (gnus-topic-alist gnus-topic-active-alist)
+               (gnus-group-list-mode (cons 5 t)))
+           (gnus-topic-remove-topic
+            (or insert (not (gnus-topic-visible-p))) nil nil 9)
+           (gnus-topic-enter-dribble)))))))
+
+(defvar gnus-tmp-header)
+
+(defun gnus-topic-insert-topic-line (name visiblep shownp level entries
+                                         &optional unread)
+  (let* ((visible (if visiblep "" "..."))
+        (indentation (make-string (* gnus-topic-indent-level level) ? ))
+        (total-number-of-articles unread)
+        (number-of-groups (length entries))
+        (active-topic (eq gnus-topic-alist gnus-topic-active-alist))
+        gnus-tmp-header)
+    (gnus-topic-update-unreads name unread)
+    (beginning-of-line)
+    ;; Insert the text.
+    (if shownp
+       (gnus-add-text-properties
+        (point)
+        (prog1 (1+ (point))
+          (eval gnus-topic-line-format-spec))
+        (list 'gnus-topic (intern name)
+              'gnus-topic-level level
+              'gnus-topic-unread unread
+              'gnus-active active-topic
+              'gnus-topic-visible visiblep)))))
+
+(defun gnus-topic-update-unreads (topic unreads)
+  (setq gnus-topic-unreads (delq (assoc topic gnus-topic-unreads)
+                                gnus-topic-unreads))
+  (push (cons topic unreads) gnus-topic-unreads))
+
+(defun gnus-topic-update-topics-containing-group (group)
+  "Update all topics that have GROUP as a member."
+  (when (and (eq major-mode 'gnus-group-mode)
+            gnus-topic-mode)
+    (save-excursion
+      (let ((alist gnus-topic-alist))
+       ;; This is probably not entirely correct.  If a topic
+       ;; isn't shown, then it's not updated.  But the updating
+       ;; should be performed in any case, since the topic's
+       ;; parent should be updated.  Pfft.
+       (while alist
+         (when (and (member group (cdar alist))
+                    (gnus-topic-goto-topic (caar alist)))
+           (gnus-topic-update-topic-line (caar alist)))
+         (pop alist))))))
+
+(defun gnus-topic-update-topic ()
+  "Update all parent topics to the current group."
+  (when (and (eq major-mode 'gnus-group-mode)
+            gnus-topic-mode)
+    (let ((group (gnus-group-group-name))
+         (m (point-marker))
+         (inhibit-read-only t))
+      (when (and group
+                (gnus-get-info group)
+                (gnus-topic-goto-topic (gnus-current-topic)))
+       (gnus-topic-update-topic-line (gnus-group-topic-name))
+       (goto-char m)
+       (set-marker m nil)
+       (gnus-group-position-point)))))
+
+(defun gnus-topic-goto-missing-group (group)
+  "Place point where GROUP is supposed to be inserted."
+  (let* ((topic (gnus-group-topic group))
+        (groups (cdr (assoc topic gnus-topic-alist)))
+        (g (cdr (member group groups)))
+        (unfound t))
+    ;; Try to jump to a visible group.
+    (while (and g
+               (not (gnus-group-goto-group (car g) t)))
+      (pop g))
+    ;; It wasn't visible, so we try to see where to insert it.
+    (when (not g)
+      (setq g (cdr (member group (reverse groups))))
+      (while (and g unfound)
+       (when (gnus-group-goto-group (pop g) t)
+         (forward-line 1)
+         (setq unfound nil)))
+      (when (and unfound
+                topic
+                (not (gnus-topic-goto-missing-topic topic)))
+       (gnus-topic-display-missing-topic topic)))))
+
+(defun gnus-topic-display-missing-topic (topic)
+  "Insert topic lines recursively for missing topics."
+  (let ((parent (gnus-topic-find-topology
+                (gnus-topic-parent-topic topic))))
+    (when (and parent
+              (not (gnus-topic-goto-missing-topic (caadr parent))))
+      (gnus-topic-display-missing-topic (caadr parent))))
+  (gnus-topic-goto-missing-topic topic)
+  ;; Skip past all groups in the topic we're in.
+  (while (gnus-group-group-name)
+    (forward-line 1))
+  (let* ((top (gnus-topic-find-topology topic))
+        (children (cddr top))
+        (type (cadr top))
+        (unread 0)
+        (entries (gnus-topic-find-groups
+                  (car type) (car gnus-group-list-mode)
+                  (cdr gnus-group-list-mode)))
+       entry)
+    (while children
+      (incf unread (gnus-topic-unread (caar (pop children)))))
+    (while (setq entry (pop entries))
+      (when (numberp (car entry))
+       (incf unread (car entry))))
+    (gnus-topic-insert-topic-line
+     topic t t (car (gnus-topic-find-topology topic)) nil unread)))
+
+(defun gnus-topic-goto-missing-topic (topic)
+  (if (gnus-topic-goto-topic topic)
+      (forward-line 1)
+    ;; Topic not displayed.
+    (let* ((top (gnus-topic-find-topology
+                (gnus-topic-parent-topic topic)))
+          (tp (reverse (cddr top))))
+      (if (not top)
+         (gnus-topic-insert-topic-line
+          topic t t (car (gnus-topic-find-topology topic)) nil 0)
+       (while (not (equal (caaar tp) topic))
+         (setq tp (cdr tp)))
+       (pop tp)
+       (while (and tp
+                   (not (gnus-topic-goto-topic (caaar tp))))
+         (pop tp))
+       (if tp
+           (gnus-topic-forward-topic 1)
+         (gnus-topic-goto-missing-topic (caadr top)))))
+    nil))
+
+(defun gnus-topic-update-topic-line (topic-name &optional reads)
+  (let* ((top (gnus-topic-find-topology topic-name))
+        (type (cadr top))
+        (children (cddr top))
+        (entries (gnus-topic-find-groups
+                  (car type) (car gnus-group-list-mode)
+                  (cdr gnus-group-list-mode)))
+        (parent (gnus-topic-parent-topic topic-name))
+        (all-entries entries)
+        (unread 0)
+        old-unread entry new-unread)
+    (when (gnus-topic-goto-topic (car type))
+      ;; Tally all the groups that belong in this topic.
+      (if reads
+         (setq unread (- (gnus-group-topic-unread) reads))
+       (while children
+         (incf unread (gnus-topic-unread (caar (pop children)))))
+       (while (setq entry (pop entries))
+         (when (numberp (car entry))
+           (incf unread (car entry)))))
+      (setq old-unread (gnus-group-topic-unread))
+      ;; Insert the topic line.
+      (gnus-topic-insert-topic-line
+       (car type) (gnus-topic-visible-p)
+       (not (eq (nth 2 type) 'hidden))
+       (gnus-group-topic-level) all-entries unread)
+      (gnus-delete-line)
+      (forward-line -1)
+      (setq new-unread (gnus-group-topic-unread)))
+    (when parent
+      (forward-line -1)
+      (gnus-topic-update-topic-line
+       parent
+       (- (or old-unread 0) (or new-unread 0))))
+    unread))
+
+(defun gnus-topic-group-indentation ()
+  (make-string
+   (* gnus-topic-indent-level
+      (or (save-excursion
+           (forward-line -1)
+           (gnus-topic-goto-topic (gnus-current-topic))
+           (gnus-group-topic-level))
+         0))
+   ? ))
+
+;;; Initialization
+
+(gnus-add-shutdown 'gnus-topic-close 'gnus)
+
+(defun gnus-topic-close ()
+  (setq gnus-topic-active-topology nil
+       gnus-topic-active-alist nil
+       gnus-topic-killed-topics nil
+       gnus-topology-checked-p nil))
+
+(defun gnus-topic-check-topology ()
+  ;; The first time we set the topology to whatever we have
+  ;; gotten here, which can be rather random.
+  (unless gnus-topic-alist
+    (gnus-topic-init-alist))
+
+  (setq gnus-topology-checked-p t)
+  ;; Go through the topic alist and make sure that all topics
+  ;; are in the topic topology.
+  (let ((topics (gnus-topic-list))
+       (alist gnus-topic-alist)
+       changed)
+    (while alist
+      (unless (member (caar alist) topics)
+       (nconc gnus-topic-topology
+              (list (list (list (caar alist) 'visible))))
+       (setq changed t))
+      (setq alist (cdr alist)))
+    (when changed
+      (gnus-topic-enter-dribble))
+    ;; Conversely, go through the topology and make sure that all
+    ;; topologies have alists.
+    (while topics
+      (unless (assoc (car topics) gnus-topic-alist)
+       (push (list (car topics)) gnus-topic-alist))
+      (pop topics)))
+  ;; Go through all living groups and make sure that
+  ;; they belong to some topic.
+  (let* ((tgroups (apply 'append (mapcar 'cdr gnus-topic-alist)))
+        (entry (last (assoc (caar gnus-topic-topology) gnus-topic-alist)))
+        (newsrc (cdr gnus-newsrc-alist))
+        group)
+    (while newsrc
+      (unless (member (setq group (gnus-info-group (pop newsrc))) tgroups)
+       (setcdr entry (list group))
+       (setq entry (cdr entry)))))
+  ;; Go through all topics and make sure they contain only living groups.
+  (let ((alist gnus-topic-alist)
+       topic)
+    (while (setq topic (pop alist))
+      (while (cdr topic)
+       (if (and (cadr topic)
+                (gnus-group-entry (cadr topic)))
+           (setq topic (cdr topic))
+         (setcdr topic (cddr topic)))))))
+
+(defun gnus-topic-init-alist ()
+  "Initialize the topic structures."
+  (setq gnus-topic-topology
+       (cons (list "Gnus" 'visible)
+             (mapcar (lambda (topic)
+                       (list (list (car topic) 'visible)))
+                     '(("misc")))))
+  (setq gnus-topic-alist
+       (list (cons "misc"
+                   (mapcar (lambda (info) (gnus-info-group info))
+                           (cdr gnus-newsrc-alist)))
+             (list "Gnus")))
+  (gnus-topic-enter-dribble))
+
+;;; Maintenance
+
+(defun gnus-topic-clean-alist ()
+  "Remove bogus groups from the topic alist."
+  (let ((topic-alist gnus-topic-alist)
+       result topic)
+    (unless gnus-killed-hashtb
+      (gnus-make-hashtable-from-killed))
+    (while (setq topic (pop topic-alist))
+      (let ((topic-name (pop topic))
+           group filtered-topic)
+       (while (setq group (pop topic))
+         (when (and (or (gnus-active group)
+                        (gnus-info-method (gnus-get-info group)))
+                    (not (gnus-gethash group gnus-killed-hashtb)))
+           (push group filtered-topic)))
+       (push (cons topic-name (nreverse filtered-topic)) result)))
+    (setq gnus-topic-alist (nreverse result))))
+
+(defun gnus-topic-change-level (group level oldlevel &optional previous)
+  "Run when changing levels to enter/remove groups from topics."
+  (with-current-buffer gnus-group-buffer
+    (let ((inhibit-read-only t))
+      (unless gnus-topic-inhibit-change-level
+       (gnus-group-goto-group (or (car (nth 2 previous)) group))
+       (when (and gnus-topic-mode
+                  gnus-topic-alist
+                  (not gnus-topic-inhibit-change-level))
+         ;; Remove the group from the topics.
+         (if (and (< oldlevel gnus-level-zombie)
+                  (>= level gnus-level-zombie))
+             (let ((alist gnus-topic-alist))
+               (while (gnus-group-goto-group group)
+                 (gnus-delete-line))
+               (while alist
+                 (when (member group (car alist))
+                   (setcdr (car alist) (delete group (cdar alist))))
+                 (pop alist)))
+           ;; If the group is subscribed we enter it into the topics.
+           (when (and (< level gnus-level-zombie)
+                      (>= oldlevel gnus-level-zombie))
+             (let* ((prev (gnus-group-group-name))
+                    (gnus-topic-inhibit-change-level t)
+                    (gnus-group-indentation
+                     (make-string
+                      (* gnus-topic-indent-level
+                         (or (save-excursion
+                               (gnus-topic-goto-topic (gnus-current-topic))
+                               (gnus-group-topic-level))
+                             0))
+                      ? ))
+                    (yanked (list group))
+                    alist talist end)
+               ;; Then we enter the yanked groups into the topics
+               ;; they belong to.
+               (when (setq alist (assoc (save-excursion
+                                          (forward-line -1)
+                                          (or
+                                           (gnus-current-topic)
+                                           (caar gnus-topic-topology)))
+                                        gnus-topic-alist))
+                 (setq talist alist)
+                 (when (stringp yanked)
+                   (setq yanked (list yanked)))
+                 (if (not prev)
+                     (nconc alist yanked)
+                   (if (not (cdr alist))
+                       (setcdr alist (nconc yanked (cdr alist)))
+                     (while (and (not end) (cdr alist))
+                       (when (equal (cadr alist) prev)
+                         (setcdr alist (nconc yanked (cdr alist)))
+                         (setq end t))
+                       (setq alist (cdr alist)))
+                     (unless end
+                       (nconc talist yanked))))))
+             (gnus-topic-update-topic))))))))
+
+(defun gnus-topic-goto-next-group (group props)
+  "Go to group or the next group after group."
+  (if (not group)
+      (if (not (memq 'gnus-topic props))
+         (goto-char (point-max))
+       (let ((topic (symbol-name (cadr (memq 'gnus-topic props)))))
+         (or (gnus-topic-goto-topic topic)
+             (gnus-topic-goto-topic (gnus-topic-next-topic topic)))))
+    (if (gnus-group-goto-group group)
+       t
+      ;; The group is no longer visible.
+      (let* ((list (assoc (gnus-group-topic group) gnus-topic-alist))
+            (topic-visible (save-excursion (gnus-topic-goto-topic (car list))))
+            (after (and topic-visible (cdr (member group (cdr list))))))
+       ;; First try to put point on a group after the current one.
+       (while (and after
+                   (not (gnus-group-goto-group (car after))))
+         (setq after (cdr after)))
+       ;; Then try to put point on a group before point.
+       (unless after
+         (setq after (cdr (member group (reverse (cdr list)))))
+         (while (and after
+                     (not (gnus-group-goto-group (car after))))
+           (setq after (cdr after))))
+       ;; Finally, just put point on the topic.
+       (if (not (car list))
+           (goto-char (point-min))
+         (unless after
+           (if topic-visible
+               (gnus-goto-char topic-visible)
+             (gnus-topic-goto-topic (gnus-topic-next-topic (car list))))
+           (setq after nil)))
+       t))))
+
+;;; Topic-active functions
+
+(defun gnus-topic-grok-active (&optional force)
+  "Parse all active groups and create topic structures for them."
+  ;; First we make sure that we have really read the active file.
+  (when (or force
+           (not gnus-topic-active-alist))
+    (let (groups)
+      ;; Get a list of all groups available.
+      (mapatoms (lambda (g) (when (symbol-value g)
+                             (push (symbol-name g) groups)))
+               gnus-active-hashtb)
+      (setq groups (sort groups 'string<))
+      ;; Init the variables.
+      (setq gnus-topic-active-topology (list (list "" 'visible)))
+      (setq gnus-topic-active-alist nil)
+      ;; Descend the top-level hierarchy.
+      (gnus-topic-grok-active-1 gnus-topic-active-topology groups)
+      ;; Set the top-level topic names to something nice.
+      (setcar (car gnus-topic-active-topology) "Gnus active")
+      (setcar (car gnus-topic-active-alist) "Gnus active"))))
+
+(defun gnus-topic-grok-active-1 (topology groups)
+  (let* ((name (caar topology))
+        (prefix (concat "^" (regexp-quote name)))
+        tgroups ntopology group)
+    (while (and groups
+               (string-match prefix (setq group (car groups))))
+      (if (not (string-match "\\." group (match-end 0)))
+         ;; There are no further hierarchies here, so we just
+         ;; enter this group into the list belonging to this
+         ;; topic.
+         (push (pop groups) tgroups)
+       ;; New sub-hierarchy, so we add it to the topology.
+       (nconc topology (list (setq ntopology
+                                   (list (list (substring
+                                                group 0 (match-end 0))
+                                               'invisible)))))
+       ;; Descend the hierarchy.
+       (setq groups (gnus-topic-grok-active-1 ntopology groups))))
+    ;; We remove the trailing "." from the topic name.
+    (setq name
+         (if (string-match "\\.$" name)
+             (substring name 0 (match-beginning 0))
+           name))
+    ;; Add this topic and its groups to the topic alist.
+    (push (cons name (nreverse tgroups)) gnus-topic-active-alist)
+    (setcar (car topology) name)
+    ;; We return the rest of the groups that didn't belong
+    ;; to this topic.
+    groups))
+
+;;; Topic mode, commands and keymap.
+
+(defvar gnus-topic-mode-map nil)
+(defvar gnus-group-topic-map nil)
+
+(unless gnus-topic-mode-map
+  (setq gnus-topic-mode-map (make-sparse-keymap))
+
+  ;; Override certain group mode keys.
+  (gnus-define-keys gnus-topic-mode-map
+    "=" gnus-topic-select-group
+    "\r" gnus-topic-select-group
+    " " gnus-topic-read-group
+    "\C-c\C-x" gnus-topic-expire-articles
+    "c" gnus-topic-catchup-articles
+    "\C-k" gnus-topic-kill-group
+    "\C-y" gnus-topic-yank-group
+    "\M-g" gnus-topic-get-new-news-this-topic
+    "AT" gnus-topic-list-active
+    "Gp" gnus-topic-edit-parameters
+    "#" gnus-topic-mark-topic
+    "\M-#" gnus-topic-unmark-topic
+    [tab] gnus-topic-indent
+    [(meta tab)] gnus-topic-unindent
+    "\C-i" gnus-topic-indent
+    "\M-\C-i" gnus-topic-unindent
+    gnus-mouse-2 gnus-mouse-pick-topic)
+
+  ;; Define a new submap.
+  (gnus-define-keys (gnus-group-topic-map "T" gnus-group-mode-map)
+    "#" gnus-topic-mark-topic
+    "\M-#" gnus-topic-unmark-topic
+    "n" gnus-topic-create-topic
+    "m" gnus-topic-move-group
+    "D" gnus-topic-remove-group
+    "c" gnus-topic-copy-group
+    "h" gnus-topic-hide-topic
+    "s" gnus-topic-show-topic
+    "j" gnus-topic-jump-to-topic
+    "M" gnus-topic-move-matching
+    "C" gnus-topic-copy-matching
+    "\M-p" gnus-topic-goto-previous-topic
+    "\M-n" gnus-topic-goto-next-topic
+    "\C-i" gnus-topic-indent
+    [tab] gnus-topic-indent
+    "r" gnus-topic-rename
+    "\177" gnus-topic-delete
+    [delete] gnus-topic-delete
+    "H" gnus-topic-toggle-display-empty-topics)
+
+  (gnus-define-keys (gnus-topic-sort-map "S" gnus-group-topic-map)
+    "s" gnus-topic-sort-groups
+    "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))
+
+(defun gnus-topic-make-menu-bar ()
+  (unless (boundp 'gnus-topic-menu)
+    (easy-menu-define
+     gnus-topic-menu gnus-topic-mode-map ""
+     '("Topics"
+       ["Toggle topics" gnus-topic-mode t]
+       ("Groups"
+       ["Copy..." gnus-topic-copy-group t]
+       ["Move..." gnus-topic-move-group t]
+       ["Remove" gnus-topic-remove-group t]
+       ["Copy matching..." gnus-topic-copy-matching t]
+       ["Move matching..." gnus-topic-move-matching t])
+       ("Topics"
+       ["Goto..." gnus-topic-jump-to-topic t]
+       ["Show" gnus-topic-show-topic t]
+       ["Hide" gnus-topic-hide-topic t]
+       ["Delete" gnus-topic-delete t]
+       ["Rename..." gnus-topic-rename t]
+       ["Create..." gnus-topic-create-topic t]
+       ["Mark" gnus-topic-mark-topic t]
+       ["Indent" gnus-topic-indent t]
+       ["Sort" gnus-topic-sort-topics t]
+       ["Previous topic" gnus-topic-goto-previous-topic t]
+       ["Next topic" gnus-topic-goto-next-topic t]
+       ["Toggle hide empty" gnus-topic-toggle-display-empty-topics t]
+       ["Edit parameters" gnus-topic-edit-parameters t])
+       ["List active" gnus-topic-list-active t]))))
+
+(define-minor-mode gnus-topic-mode
+  "Minor mode for topicsifying Gnus group buffers."
+  :lighter " Topic" :keymap gnus-topic-mode-map
+  (if (not (derived-mode-p 'gnus-group-mode))
+      (setq gnus-topic-mode nil)
+    ;; Infest Gnus with topics.
+    (if (not gnus-topic-mode)
+       (setq gnus-goto-missing-group-function nil)
+      (when (gnus-visual-p 'topic-menu 'menu)
+       (gnus-topic-make-menu-bar))
+      (gnus-set-format 'topic t)
+      (add-hook 'gnus-group-catchup-group-hook 'gnus-topic-update-topic)
+      (set (make-local-variable 'gnus-group-prepare-function)
+          'gnus-group-prepare-topics)
+      (set (make-local-variable 'gnus-group-get-parameter-function)
+          'gnus-group-topic-parameters)
+      (set (make-local-variable 'gnus-group-goto-next-group-function)
+          'gnus-topic-goto-next-group)
+      (set (make-local-variable 'gnus-group-indentation-function)
+          'gnus-topic-group-indentation)
+      (set (make-local-variable 'gnus-group-update-group-function)
+          'gnus-topic-update-topics-containing-group)
+      (set (make-local-variable 'gnus-group-sort-alist-function)
+          'gnus-group-sort-topic)
+      (setq gnus-group-change-level-function 'gnus-topic-change-level)
+      (setq gnus-goto-missing-group-function 'gnus-topic-goto-missing-group)
+      (gnus-make-local-hook 'gnus-check-bogus-groups-hook)
+      (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
+       (gnus-topic-check-topology)))
+    ;; Remove topic infestation.
+    (unless gnus-topic-mode
+      (remove-hook 'gnus-summary-exit-hook 'gnus-topic-update-topic)
+      (setq gnus-group-change-level-function nil)
+      (remove-hook 'gnus-check-bogus-groups-hook 'gnus-topic-clean-alist)
+      (setq gnus-group-prepare-function 'gnus-group-prepare-flat)
+      (setq gnus-group-sort-alist-function 'gnus-group-sort-flat))
+    (when (gmm-called-interactively-p 'any)
+      (gnus-group-list-groups))))
+
+(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 positive number, fetch this number of the latest
+articles in the group.  If ALL is a negative number, fetch this
+number of the earliest articles in the group.
+
+If performed over a topic line, toggle folding the topic."
+  (interactive "P")
+  (when (and (eobp) (not (gnus-group-group-name)))
+    (forward-line -1))
+  (if (gnus-group-topic-p)
+      (let ((gnus-group-list-mode
+            (if all (cons (if (numberp all) all 7) t) gnus-group-list-mode)))
+       (gnus-topic-fold all)
+       (gnus-dribble-touch))
+    (gnus-group-select-group all)))
+
+(defun gnus-mouse-pick-topic (e)
+  "Select the group or topic under the mouse pointer."
+  (interactive "e")
+  (mouse-set-point e)
+  (gnus-topic-read-group nil))
+
+(defun gnus-topic-expire-articles (topic)
+  "Expire articles in this topic or group."
+  (interactive (list (gnus-group-topic-name)))
+  (if (not topic)
+      (call-interactively 'gnus-group-expire-articles)
+    (save-excursion
+      (gnus-message 5 "Expiring groups in %s..." topic)
+      (let ((gnus-group-marked
+            (mapcar (lambda (entry) (car (nth 2 entry)))
+                    (gnus-topic-find-groups topic gnus-level-killed t
+                                            nil t))))
+       (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* ((groups
+              (mapcar (lambda (entry) (car (nth 2 entry)))
+                      (gnus-topic-find-groups topic gnus-level-killed t
+                                              nil t)))
+            (inhibit-read-only t)
+            (gnus-group-marked groups))
+       (gnus-group-catchup-current)
+       (mapcar 'gnus-topic-update-topics-containing-group groups)))))
+
+(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
+readable.
+
+If ALL is a positive number, fetch this number of the latest
+articles in the group.  If ALL is a negative number, fetch this
+number of the earliest articles in the group.
+
+If the optional argument NO-ARTICLE is non-nil, no article will
+be auto-selected upon group entry.  If GROUP is non-nil, fetch
+that group.
+
+If performed over a topic line, toggle folding the topic."
+  (interactive "P")
+  (when (and (eobp) (not (gnus-group-group-name)))
+    (forward-line -1))
+  (if (gnus-group-topic-p)
+      (let ((gnus-group-list-mode
+            (if all (cons (if (numberp all) all 7) t) gnus-group-list-mode)))
+       (gnus-topic-fold all))
+    (gnus-group-read-group all no-article group)))
+
+(defun gnus-topic-create-topic (topic parent &optional previous full-topic)
+  "Create a new TOPIC under PARENT.
+When used interactively, PARENT will be the topic under point."
+  (interactive
+   (list
+    (read-string "New topic: ")
+    (gnus-current-topic)))
+  ;; Check whether this topic already exists.
+  (when (gnus-topic-find-topology topic)
+    (error "Topic already exists"))
+  (unless parent
+    (setq parent (caar gnus-topic-topology)))
+  (let ((top (cdr (gnus-topic-find-topology parent)))
+       (full-topic (or full-topic (list (list topic 'visible nil nil)))))
+    (unless top
+      (error "No such parent topic: %s" parent))
+    (if previous
+       (progn
+         (while (and (cdr top)
+                     (not (equal (caaadr top) previous)))
+           (setq top (cdr top)))
+         (setcdr top (cons full-topic (cdr top))))
+      (nconc top (list full-topic)))
+    (unless (assoc topic gnus-topic-alist)
+      (push (list topic) gnus-topic-alist)))
+  (gnus-topic-enter-dribble)
+  (gnus-group-list-groups)
+  (gnus-topic-goto-topic topic))
+
+;; FIXME:
+;;  1. When the marked groups are overlapped with the process
+;;     region, the behavior of move or remove is not right.
+;;  2. Can't process on several marked groups with a same name,
+;;     because gnus-group-marked only keeps one copy.
+
+(defvar gnus-topic-history nil)
+
+(defun gnus-topic-move-group (n topic &optional copyp)
+  "Move the next N groups to TOPIC.
+If COPYP, copy the groups instead."
+  (interactive
+   (list current-prefix-arg
+        (gnus-completing-read "Move to topic" (mapcar 'car gnus-topic-alist) t
+                              nil 'gnus-topic-history)))
+  (let ((use-marked (and (not n) (not (gnus-region-active-p))
+                        gnus-group-marked t))
+       (groups (gnus-group-process-prefix n))
+       (topicl (assoc topic gnus-topic-alist))
+       (start-topic (gnus-group-topic-name))
+       (start-group (progn (forward-line 1) (gnus-group-group-name)))
+       entry)
+    (if (and (not groups) (not copyp) start-topic)
+       (gnus-topic-move start-topic topic)
+      (dolist (g groups)
+       (gnus-group-remove-mark g use-marked)
+       (when (and
+              (setq entry (assoc (gnus-current-topic) gnus-topic-alist))
+              (not copyp))
+         (setcdr entry (gnus-delete-first g (cdr entry))))
+       (nconc topicl (list g)))
+      (gnus-topic-enter-dribble)
+      (if start-group
+         (gnus-group-goto-group start-group)
+       (gnus-topic-goto-topic start-topic))
+      (gnus-group-list-groups))))
+
+(defun gnus-topic-remove-group (&optional n)
+  "Remove the current group from the topic."
+  (interactive "P")
+  (let ((use-marked (and (not n) (not (gnus-region-active-p))
+                        gnus-group-marked t))
+       (groups (gnus-group-process-prefix n)))
+    (mapc
+     (lambda (group)
+       (gnus-group-remove-mark group use-marked)
+       (let ((topicl (assoc (gnus-current-topic) gnus-topic-alist))
+            (inhibit-read-only t))
+        (when (and topicl group)
+          (gnus-delete-line)
+          (gnus-delete-first group topicl))
+        (gnus-topic-update-topic)))
+     groups)
+    (gnus-topic-enter-dribble)
+    (gnus-group-position-point)))
+
+(defun gnus-topic-copy-group (n topic)
+  "Copy the current group to a topic."
+  (interactive
+   (list current-prefix-arg
+        (gnus-completing-read
+         "Copy to topic" (mapcar 'car gnus-topic-alist) t)))
+  (gnus-topic-move-group n topic t))
+
+(defun gnus-topic-kill-group (&optional n discard)
+  "Kill the next N groups."
+  (interactive "P")
+  (if (gnus-group-topic-p)
+      (let ((topic (gnus-group-topic-name)))
+       (push (cons
+              (gnus-topic-find-topology topic)
+              (assoc topic gnus-topic-alist))
+             gnus-topic-killed-topics)
+       (gnus-topic-remove-topic nil t)
+       (gnus-topic-find-topology topic nil nil gnus-topic-topology)
+       (gnus-topic-enter-dribble))
+    (gnus-group-kill-group n discard)
+    (if (not (gnus-group-topic-p))
+       (gnus-topic-update-topic)
+      ;; Move up one line so that we update the right topic.
+      (forward-line -1)
+      (gnus-topic-update-topic)
+      (forward-line 1))))
+
+(defun gnus-topic-yank-group (&optional arg)
+  "Yank the last topic."
+  (interactive "p")
+  (if gnus-topic-killed-topics
+      (let* ((previous
+             (or (gnus-group-topic-name)
+                 (gnus-topic-next-topic (gnus-current-topic))))
+            (data (pop gnus-topic-killed-topics))
+            (alist (cdr data))
+            (item (cdar data)))
+       (push alist gnus-topic-alist)
+       (gnus-topic-create-topic
+        (caar item) (gnus-topic-parent-topic previous) previous
+        item)
+       (gnus-topic-enter-dribble)
+       (gnus-topic-goto-topic (caar item)))
+    (let* ((prev (gnus-group-group-name))
+          (gnus-topic-inhibit-change-level t)
+          (gnus-group-indentation
+           (make-string
+            (* gnus-topic-indent-level
+               (or (save-excursion
+                     (gnus-topic-goto-topic (gnus-current-topic))
+                     (gnus-group-topic-level))
+                   0))
+            ? ))
+          yanked alist)
+      ;; We first yank the groups the normal way...
+      (setq yanked (gnus-group-yank-group arg))
+      ;; Then we enter the yanked groups into the topics they belong
+      ;; to.
+      (setq alist (assoc (save-excursion
+                          (forward-line -1)
+                          (gnus-current-topic))
+                        gnus-topic-alist))
+      (when (stringp yanked)
+       (setq yanked (list yanked)))
+      (if (not prev)
+         (nconc alist yanked)
+       (if (not (cdr alist))
+           (setcdr alist (nconc yanked (cdr alist)))
+         (while (cdr alist)
+           (when (equal (cadr alist) prev)
+             (setcdr alist (nconc yanked (cdr alist)))
+             (setq alist nil))
+           (setq alist (cdr alist))))))
+    (gnus-topic-update-topic)))
+
+(defun gnus-topic-hide-topic (&optional permanent)
+  "Hide the current topic.
+If PERMANENT, make it stay hidden in subsequent sessions as well."
+  (interactive "P")
+  (when (gnus-current-topic)
+    (gnus-topic-goto-topic (gnus-current-topic))
+    (if permanent
+       (setcar (cddr
+                (cadr
+                 (gnus-topic-find-topology (gnus-current-topic))))
+               'hidden))
+    (gnus-topic-remove-topic nil nil)))
+
+(defun gnus-topic-show-topic (&optional permanent)
+  "Show the hidden topic.
+If PERMANENT, make it stay shown in subsequent sessions as well."
+  (interactive "P")
+  (when (gnus-group-topic-p)
+    (if (not permanent)
+       (gnus-topic-remove-topic t nil)
+      (let ((topic
+            (gnus-topic-find-topology
+             (gnus-completing-read "Show topic"
+                                    (mapcar 'car gnus-topic-alist) t))))
+       (setcar (cddr (cadr topic)) nil)
+       (setcar (cdr (cadr topic)) 'visible)
+       (gnus-group-list-groups)))))
+
+(defun gnus-topic-mark-topic (topic &optional unmark non-recursive)
+  "Mark all groups in the TOPIC with the process mark.
+If NON-RECURSIVE (which is the prefix) is t, don't mark its subtopics."
+  (interactive (list (gnus-group-topic-name)
+                    nil
+                    (and current-prefix-arg t)))
+  (if (not topic)
+      (call-interactively 'gnus-group-mark-group)
+    (save-excursion
+      (let ((groups (gnus-topic-find-groups topic gnus-level-killed t nil
+                                           (not non-recursive))))
+       (while groups
+         (funcall (if unmark 'gnus-group-remove-mark 'gnus-group-set-mark)
+                  (gnus-info-group (nth 2 (pop groups)))))))))
+
+(defun gnus-topic-unmark-topic (topic &optional _dummy non-recursive)
+  "Remove the process mark from all groups in the TOPIC.
+If NON-RECURSIVE (which is the prefix) is t, don't unmark its subtopics."
+  (interactive (list (gnus-group-topic-name)
+                    nil
+                    (and current-prefix-arg t)))
+  (if (not topic)
+      (call-interactively 'gnus-group-unmark-group)
+    (gnus-topic-mark-topic topic t non-recursive)))
+
+(defun gnus-topic-get-new-news-this-topic (&optional n)
+  "Check for new news in the current topic."
+  (interactive "P")
+  (if (not (gnus-group-topic-p))
+      (gnus-group-get-new-news-this-group n)
+    (let* ((topic (gnus-group-topic-name))
+          (data (cadr (gnus-topic-find-topology topic))))
+      (save-excursion
+       (gnus-topic-mark-topic topic nil (and n t))
+       (gnus-group-get-new-news-this-group))
+      (gnus-topic-remove-topic (eq 'visible (cadr data))))))
+
+(defun gnus-topic-move-matching (regexp topic &optional copyp)
+  "Move all groups that match REGEXP to some topic."
+  (interactive
+   (let (topic)
+     (nreverse
+      (list
+       (setq topic (gnus-completing-read "Move to topic"
+                                         (mapcar 'car gnus-topic-alist) t))
+       (read-string (format "Move to %s (regexp): " topic))))))
+  (gnus-group-mark-regexp regexp)
+  (gnus-topic-move-group nil topic copyp))
+
+(defun gnus-topic-copy-matching (regexp topic &optional _copyp)
+  "Copy all groups that match REGEXP to some topic."
+  (interactive
+   (let ((topic (gnus-completing-read "Copy to topic"
+                                      (mapcar #'car gnus-topic-alist) t)))
+     (nreverse
+      (list topic
+            (read-string (format "Copy to %s (regexp): " topic))))))
+  (gnus-topic-move-matching regexp topic t))
+
+(defun gnus-topic-delete (topic)
+  "Delete a topic."
+  (interactive (list (gnus-group-topic-name)))
+  (unless topic
+    (error "No topic to be deleted"))
+  (let ((entry (assoc topic gnus-topic-alist))
+       (inhibit-read-only t))
+    (when (cdr entry)
+      (error "Topic not empty"))
+    ;; Delete if visible.
+    (when (gnus-topic-goto-topic topic)
+      (gnus-delete-line))
+    ;; Remove from alist.
+    (setq gnus-topic-alist (delq entry gnus-topic-alist))
+    ;; Remove from topology.
+    (gnus-topic-find-topology topic nil nil 'delete)
+    (gnus-dribble-touch)))
+
+(defun gnus-topic-rename (old-name new-name)
+  "Rename a topic."
+  (interactive
+   (let ((topic (gnus-current-topic)))
+     (list 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))
+  ;; "nil" is an invalid name, for reasons I'd rather not go
+  ;; into here.  Trust me.
+  (when (equal new-name "nil")
+    (error "Invalid name: %s" nil))
+  ;; Do the renaming.
+  (let ((top (gnus-topic-find-topology old-name))
+       (entry (assoc old-name gnus-topic-alist)))
+    (when top
+      (setcar (cadr top) new-name))
+    (when entry
+      (setcar entry new-name))
+    (forward-line -1)
+    (gnus-dribble-touch)
+    (gnus-group-list-groups)
+    (forward-line 1)))
+
+(defun gnus-topic-indent (&optional unindent)
+  "Indent a topic -- make it a sub-topic of the previous topic.
+If UNINDENT, remove an indentation."
+  (interactive "P")
+  (if unindent
+      (gnus-topic-unindent)
+    (let* ((topic (gnus-current-topic))
+          (parent (gnus-topic-previous-topic topic))
+          (inhibit-read-only t))
+      (unless parent
+       (error "Nothing to indent %s into" topic))
+      (when topic
+       (gnus-topic-goto-topic topic)
+       (gnus-topic-kill-group)
+       (push (cdar gnus-topic-killed-topics) gnus-topic-alist)
+       (gnus-topic-create-topic
+        topic parent nil (cdar (car gnus-topic-killed-topics)))
+       (pop gnus-topic-killed-topics)
+       (or (gnus-topic-goto-topic topic)
+           (gnus-topic-goto-topic parent))))))
+
+(defun gnus-topic-unindent ()
+  "Unindent a topic."
+  (interactive)
+  (let* ((topic (gnus-current-topic))
+        (parent (gnus-topic-parent-topic topic))
+        (grandparent (gnus-topic-parent-topic parent)))
+    (unless grandparent
+      (error "Nothing to indent %s into" topic))
+    (when topic
+      (gnus-topic-goto-topic topic)
+      (gnus-topic-kill-group)
+      (push (cdar gnus-topic-killed-topics) gnus-topic-alist)
+      (gnus-topic-create-topic
+       topic grandparent (gnus-topic-next-topic parent)
+       (cdar (car gnus-topic-killed-topics)))
+      (pop gnus-topic-killed-topics)
+      (gnus-topic-goto-topic topic))))
+
+(defun gnus-topic-list-active (&optional force)
+  "List all groups that Gnus knows about in a topicsified fashion.
+If FORCE, always re-read the active file."
+  (interactive "P")
+  (when force
+    (gnus-get-killed-groups))
+  (gnus-topic-grok-active force)
+  (let ((gnus-topic-topology gnus-topic-active-topology)
+       (gnus-topic-alist gnus-topic-active-alist)
+       gnus-killed-list gnus-zombie-list)
+    (gnus-group-list-groups gnus-level-killed nil 1)))
+
+(defun gnus-topic-toggle-display-empty-topics ()
+  "Show/hide topics that have no unread articles."
+  (interactive)
+  (setq gnus-topic-display-empty-topics
+       (not gnus-topic-display-empty-topics))
+  (gnus-group-list-groups)
+  (message "%s empty topics"
+          (if gnus-topic-display-empty-topics
+              "Showing" "Hiding")))
+
+;;; Topic sorting functions
+
+(defun gnus-topic-edit-parameters (group)
+  "Edit the group parameters of GROUP.
+If performed on a topic, edit the topic parameters instead."
+  (interactive (list (gnus-group-group-name)))
+  (if group
+      (gnus-group-edit-group-parameters group)
+    (if (not (gnus-group-topic-p))
+       (error "Nothing to edit on the current line")
+      (let ((topic (gnus-group-topic-name)))
+       (gnus-edit-form
+        (gnus-topic-parameters topic)
+        (gnus-format-message "Editing the topic parameters for `%s'."
+                             (or group topic))
+        `(lambda (form)
+           (gnus-topic-set-parameters ,topic form)))))))
+
+(defun gnus-group-sort-topic (func reverse)
+  "Sort groups in the topics according to FUNC and REVERSE."
+  (let ((alist gnus-topic-alist))
+    (while alist
+      ;; !!!Sometimes nil elements sneak into the alist,
+      ;; for some reason or other.
+      (setcar alist (delq nil (car alist)))
+      (setcar alist (delete "dummy.group" (car alist)))
+      (gnus-topic-sort-topic (pop alist) func reverse))))
+
+(defun gnus-topic-sort-topic (topic func reverse)
+  ;; Each topic only lists the name of the group, while
+  ;; the sort predicates expect group infos as inputs.
+  ;; So we first transform the group names into infos,
+  ;; then sort, and then transform back into group names.
+  (setcdr
+   topic
+   (mapcar
+    (lambda (info) (gnus-info-group info))
+    (sort
+     (mapcar
+      (lambda (group) (gnus-get-info group))
+      (cdr topic))
+     func)))
+  ;; Do the reversal, if necessary.
+  (when reverse
+    (setcdr topic (nreverse (cdr topic)))))
+
+(defun gnus-topic-sort-groups (func &optional reverse)
+  "Sort the current topic according to FUNC.
+If REVERSE, reverse the sorting order."
+  (interactive (list gnus-group-sort-function current-prefix-arg))
+  (let ((topic (assoc (gnus-current-topic) gnus-topic-alist)))
+    (gnus-topic-sort-topic
+     topic (gnus-make-sort-function func) reverse)
+    (gnus-group-list-groups)))
+
+(defun gnus-topic-sort-groups-by-alphabet (&optional reverse)
+  "Sort the current topic alphabetically by group name.
+If REVERSE, sort in reverse order."
+  (interactive "P")
+  (gnus-topic-sort-groups 'gnus-group-sort-by-alphabet reverse))
+
+(defun gnus-topic-sort-groups-by-unread (&optional reverse)
+  "Sort the current topic by number of unread articles.
+If REVERSE, sort in reverse order."
+  (interactive "P")
+  (gnus-topic-sort-groups 'gnus-group-sort-by-unread reverse))
+
+(defun gnus-topic-sort-groups-by-level (&optional reverse)
+  "Sort the current topic by group level.
+If REVERSE, sort in reverse order."
+  (interactive "P")
+  (gnus-topic-sort-groups 'gnus-group-sort-by-level reverse))
+
+(defun gnus-topic-sort-groups-by-score (&optional reverse)
+  "Sort the current topic by group score.
+If REVERSE, sort in reverse order."
+  (interactive "P")
+  (gnus-topic-sort-groups 'gnus-group-sort-by-score reverse))
+
+(defun gnus-topic-sort-groups-by-rank (&optional reverse)
+  "Sort the current topic by group rank.
+If REVERSE, sort in reverse order."
+  (interactive "P")
+  (gnus-topic-sort-groups 'gnus-group-sort-by-rank reverse))
+
+(defun gnus-topic-sort-groups-by-method (&optional reverse)
+  "Sort the current topic alphabetically by backend name.
+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 (gnus-byte-compile
+                     `(lambda (top)
+                        (gnus-topic-sort-topics-1 top ,reverse)))
+                    (sort (cdr top)
+                          (lambda (t1 t2)
+                            (string-lessp (caar t1) (caar t2)))))))
+       (setcdr top (if reverse (reverse subtop) subtop))))
+  top)
+
+(defun gnus-topic-sort-topics (&optional topic reverse)
+  "Sort topics in TOPIC alphabetically by topic name.
+If REVERSE, reverse the sorting order."
+  (interactive
+   (list (gnus-completing-read "Sort topics in"
+                               (mapcar 'car gnus-topic-alist) t
+                               (gnus-current-topic))
+        current-prefix-arg))
+  (let ((topic-topology (or (and topic (cdr (gnus-topic-find-topology topic)))
+                           gnus-topic-topology)))
+    (gnus-topic-sort-topics-1 topic-topology reverse)
+    (gnus-topic-enter-dribble)
+    (gnus-group-list-groups)
+    (gnus-topic-goto-topic topic)))
+
+(defun gnus-topic-move (current to)
+  "Move the CURRENT topic to TO."
+  (interactive
+   (list
+    (gnus-group-topic-name)
+    (gnus-completing-read "Move to topic" (mapcar 'car gnus-topic-alist) t)))
+  (unless (and current to)
+    (error "Can't find topic"))
+  (let ((current-top (cdr (gnus-topic-find-topology current)))
+       (to-top (cdr (gnus-topic-find-topology to))))
+    (unless current-top
+      (error "Can't find topic `%s'" current))
+    (unless to-top
+      (error "Can't find topic `%s'" to))
+    (if (gnus-topic-find-topology to current-top 0);; Don't care the level
+       (error "Can't move `%s' to its sub-level" current))
+    (gnus-topic-find-topology current nil nil 'delete)
+    (setcdr (last to-top) (list current-top))
+    (gnus-topic-enter-dribble)
+    (gnus-group-list-groups)
+    (gnus-topic-goto-topic current)))
+
+(defun gnus-subscribe-topics (newsgroup)
+  (catch 'end
+    (let (match gnus-group-change-level-function)
+      (dolist (topic (gnus-topic-list))
+       (when (and (setq match (cdr (assq 'subscribe
+                                         (gnus-topic-parameters topic))))
+                  (string-match match newsgroup))
+         ;; Just subscribe the group.
+         (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)))
+
+(provide 'gnus-topic)
+
+;;; gnus-topic.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-undo.el b/xemacs-packages/gnus/lisp/gnus-undo.el
new file mode 100644 (file)
index 0000000..b3afcd7
--- /dev/null
@@ -0,0 +1,190 @@
+;;; gnus-undo.el --- minor mode for undoing in Gnus
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package allows arbitrary undoing in Gnus buffers.  As all the
+;; Gnus buffers aren't very text-oriented (what is in the buffers is
+;; just some arbitrary representation of the actual data), normal Emacs
+;; undoing doesn't work at all for Gnus.
+;;
+;; This package works by letting Gnus register functions for reversing
+;; actions, and then calling these functions when the user pushes the
+;; `undo' key.  As with normal `undo', there it is possible to set
+;; undo boundaries and so on.
+;;
+;; Internally, the undo sequence is represented by the
+;; `gnus-undo-actions' list, where each element is a list of functions
+;; to be called, in sequence, to undo some action.  (An "action" is a
+;; collection of functions.)
+;;
+;; For instance, a function for killing a group will call
+;; `gnus-undo-register' with a function that un-kills the group.  This
+;; package will put that function into an action.
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(eval-when-compile
+  (when (featurep 'xemacs)
+    (require 'easy-mmode))) ; for `define-minor-mode'
+
+(require 'gnus-util)
+(require 'gnus)
+
+(defgroup gnus-undo nil
+  "Undoing in Gnus buffers."
+  :group 'gnus)
+
+(defcustom gnus-undo-limit 2000
+  "The number of undoable actions recorded."
+  :type 'integer
+  :group 'gnus-undo)
+
+(defcustom gnus-undo-mode nil
+  ;; FIXME: This is a buffer-local minor mode which requires running
+  ;; code upon activation/deactivation, so defining it as a defcustom
+  ;; doesn't seem very useful: setting it to non-nil via Customize
+  ;; probably won't do the right thing.
+  "Minor mode for undoing in Gnus buffers."
+  :type 'boolean
+  :group 'gnus-undo)
+
+(defcustom gnus-undo-mode-hook nil
+  "Hook called in all `gnus-undo-mode' buffers."
+  :type 'hook
+  :group 'gnus-undo)
+
+;;; Internal variables.
+
+(defvar gnus-undo-actions nil)
+(defvar gnus-undo-boundary t)
+(defvar gnus-undo-last nil)
+(defvar gnus-undo-boundary-inhibit nil)
+
+;;; Minor mode definition.
+
+(defvar gnus-undo-mode-map
+  (let ((map (make-sparse-keymap)))
+    (gnus-define-keys map
+      "\M-\C-_"     gnus-undo
+      "\C-_"        gnus-undo
+      "\C-xu"       gnus-undo
+      ;; many people are used to type `C-/' on X terminals and get `C-_'.
+      [(control /)] gnus-undo)
+    map))
+
+(defun gnus-undo-make-menu-bar ()
+  ;; This is disabled for the time being.
+  (when nil
+    (define-key-after (current-local-map) [menu-bar file gnus-undo]
+      (cons "Undo" 'gnus-undo-actions)
+      [menu-bar file whatever])))
+
+(define-minor-mode gnus-undo-mode
+  "Minor mode for providing `undo' in Gnus buffers.
+
+\\{gnus-undo-mode-map}"
+  :keymap gnus-undo-mode-map
+  (set (make-local-variable 'gnus-undo-actions) nil)
+  (set (make-local-variable 'gnus-undo-boundary) t)
+  (when gnus-undo-mode
+    ;; Set up the menu.
+    (when (gnus-visual-p 'undo-menu 'menu)
+      (gnus-undo-make-menu-bar))
+    (gnus-make-local-hook 'post-command-hook)
+    (add-hook 'post-command-hook 'gnus-undo-boundary nil t)))
+
+;;; Interface functions.
+
+(defun gnus-disable-undo (&optional buffer)
+  "Disable undoing in the current buffer."
+  (interactive)
+  (save-excursion
+    (when buffer
+      (set-buffer buffer))
+    (gnus-undo-mode -1)))
+
+(defun gnus-undo-boundary ()
+  "Set Gnus undo boundary."
+  (if gnus-undo-boundary-inhibit
+      (setq gnus-undo-boundary-inhibit nil)
+    (setq gnus-undo-boundary t)))
+
+(defun gnus-undo-force-boundary ()
+  "Set Gnus undo boundary."
+  (setq gnus-undo-boundary-inhibit nil
+       gnus-undo-boundary t))
+
+(defun gnus-undo-register (form)
+  "Register FORMS as something to be performed to undo a change.
+FORMS may use backtick quote syntax."
+  (when gnus-undo-mode
+    (gnus-undo-register-1
+     `(lambda ()
+       ,form))))
+
+(put 'gnus-undo-register 'lisp-indent-function 0)
+(put 'gnus-undo-register 'edebug-form-spec '(body))
+
+(defun gnus-undo-register-1 (function)
+  "Register FUNCTION as something to be performed to undo a change."
+  (when gnus-undo-mode
+    (cond
+     ;; We are on a boundary, so we create a new action.
+     (gnus-undo-boundary
+      (push (list function) gnus-undo-actions)
+      (setq gnus-undo-boundary nil))
+     ;; Prepend the function to an old action.
+     (gnus-undo-actions
+      (setcar gnus-undo-actions (cons function (car gnus-undo-actions))))
+     ;; Initialize list.
+     (t
+      (setq gnus-undo-actions (list (list function)))))
+    ;; Limit the length of the undo list.
+    (let ((next (nthcdr gnus-undo-limit gnus-undo-actions)))
+      (when next
+       (setcdr next nil)))
+    ;; We are not at a boundary...
+    (setq gnus-undo-boundary-inhibit t)))
+
+(defun gnus-undo (n)
+  "Undo some previous changes in Gnus buffers.
+Repeat this command to undo more changes.
+A numeric argument serves as a repeat count."
+  (interactive "p")
+  (unless gnus-undo-mode
+    (error "Undoing is not enabled in this buffer"))
+  (message "%s" last-command)
+  (when (or (not (eq last-command 'gnus-undo))
+           (not gnus-undo-last))
+    (setq gnus-undo-last gnus-undo-actions))
+  (let ((action (pop gnus-undo-last)))
+    (unless action
+      (error "Nothing further to undo"))
+    (setq gnus-undo-actions (delq action gnus-undo-actions))
+    (setq gnus-undo-boundary t)
+    (mapc 'funcall action)))
+
+(provide 'gnus-undo)
+
+;;; gnus-undo.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-util.el b/xemacs-packages/gnus/lisp/gnus-util.el
new file mode 100644 (file)
index 0000000..31645fc
--- /dev/null
@@ -0,0 +1,2026 @@
+;;; gnus-util.el --- utility functions for Gnus
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Nothing in this file depends on any other parts of Gnus -- all
+;; functions and macros in this file are utility functions that are
+;; used by Gnus and may be used by any other package without loading
+;; Gnus first.
+
+;; [Unfortunately, it does depend on other parts of Gnus, e.g. the
+;; autoloads and defvars below...]
+
+;;; Code:
+
+(eval-when-compile
+  (require 'cl))
+
+(require 'time-date)
+
+(defcustom gnus-completing-read-function 'gnus-emacs-completing-read
+  "Function use to do completing read."
+  :version "24.1"
+  :group 'gnus-meta
+  :type `(radio (function-item
+                 :doc "Use Emacs standard `completing-read' function."
+                 gnus-emacs-completing-read)
+               ;; iswitchb.el is very old and ido.el is unavailable
+               ;; in XEmacs, so we exclude those function items.
+               ,@(unless (featurep 'xemacs)
+                   '((function-item
+                      :doc "Use `ido-completing-read' function."
+                      gnus-ido-completing-read)
+                     (function-item
+                      :doc "Use iswitchb based completing-read function."
+                      gnus-iswitchb-completing-read)))))
+
+(defcustom gnus-completion-styles
+  (if (and (boundp 'completion-styles-alist)
+           (boundp 'completion-styles))
+      (append (when (and (assq 'substring completion-styles-alist)
+                         (not (memq 'substring completion-styles)))
+                (list 'substring))
+              completion-styles)
+    nil)
+  "Value of `completion-styles' to use when completing."
+  :version "24.1"
+  :group 'gnus-meta
+  :type '(repeat symbol))
+
+;; Fixme: this should be a gnus variable, not nnmail-.
+(defvar nnmail-pathname-coding-system)
+(defvar nnmail-active-file-coding-system)
+
+;; Inappropriate references to other parts of Gnus.
+(defvar gnus-emphasize-whitespace-regexp)
+(defvar gnus-original-article-buffer)
+(defvar gnus-user-agent)
+
+(autoload 'gnus-get-buffer-window "gnus-win")
+(autoload 'nnheader-narrow-to-headers "nnheader")
+(autoload 'nnheader-replace-chars-in-string "nnheader")
+(autoload 'mail-header-remove-comments "mail-parse")
+
+(eval-and-compile
+  (cond
+   ;; Prefer `replace-regexp-in-string' (present in Emacs, XEmacs 21.5,
+   ;; SXEmacs 22.1.4) over `replace-in-string'.  The latter leads to inf-loops
+   ;; on empty matches:
+   ;;   (replace-in-string "foo" "/*$" "/")
+   ;;   (replace-in-string "xe" "\\(x\\)?" "")
+   ((fboundp 'replace-regexp-in-string)
+    (defun gnus-replace-in-string  (string regexp newtext &optional literal)
+      "Replace all matches for REGEXP with NEWTEXT in STRING.
+If LITERAL is non-nil, insert NEWTEXT literally.  Return a new
+string containing the replacements.
+
+This is a compatibility function for different Emacsen."
+      (replace-regexp-in-string regexp newtext string nil literal)))
+   ((fboundp 'replace-in-string)
+    (defalias 'gnus-replace-in-string 'replace-in-string))))
+
+(defun gnus-boundp (variable)
+  "Return non-nil if VARIABLE is bound and non-nil."
+  (and (boundp variable)
+       (symbol-value variable)))
+
+(defmacro gnus-eval-in-buffer-window (buffer &rest forms)
+  "Pop to BUFFER, evaluate FORMS, and then return to the original window."
+  (let ((tempvar (make-symbol "GnusStartBufferWindow"))
+       (w (make-symbol "w"))
+       (buf (make-symbol "buf")))
+    `(let* ((,tempvar (selected-window))
+           (,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)))))
+
+(put 'gnus-eval-in-buffer-window 'lisp-indent-function 1)
+(put 'gnus-eval-in-buffer-window 'edebug-form-spec '(form body))
+
+(defmacro gnus-intern-safe (string hashtable)
+  "Get hash value.  Arguments are STRING and HASHTABLE."
+  `(let ((symbol (intern ,string ,hashtable)))
+     (or (boundp symbol)
+        (set symbol nil))
+     symbol))
+
+(defsubst gnus-goto-char (point)
+  (and point (goto-char point)))
+
+(defmacro gnus-buffer-exists-p (buffer)
+  `(let ((buffer ,buffer))
+     (when buffer
+       (funcall (if (stringp buffer) 'get-buffer 'buffer-name)
+               buffer))))
+
+;; The LOCAL arg to `add-hook' is interpreted differently in Emacs and
+;; XEmacs.  In Emacs we don't need to call `make-local-hook' first.
+;; It's harmless, though, so the main purpose of this alias is to shut
+;; up the byte compiler.
+(defalias 'gnus-make-local-hook (if (featurep 'xemacs)
+                                    'make-local-hook
+                                  'ignore))
+
+(defun gnus-delete-first (elt list)
+  "Delete by side effect the first occurrence of ELT as a member of LIST."
+  (if (equal (car list) elt)
+      (cdr list)
+    (let ((total list))
+      (while (and (cdr list)
+                 (not (equal (cadr list) elt)))
+       (setq list (cdr list)))
+      (when (cdr list)
+       (setcdr list (cddr list)))
+      total)))
+
+;; Delete the current line (and the next N lines).
+(defmacro gnus-delete-line (&optional n)
+  `(delete-region (point-at-bol)
+                 (progn (forward-line ,(or n 1)) (point))))
+
+(defun gnus-extract-address-components (from)
+  "Extract address components from a From header.
+Given an RFC-822 address FROM, extract full name and canonical address.
+Returns a list of the form (FULL-NAME CANONICAL-ADDRESS).  Much more simple
+solution than `mail-extract-address-components', which works much better, but
+is slower."
+  (let (name address)
+    ;; First find the address - the thing with the @ in it.  This may
+    ;; not be accurate in mail addresses, but does the trick most of
+    ;; the time in news messages.
+    (cond (;; Check ``<foo@bar>'' first in order to handle the quite common
+          ;; form ``"abc@xyz" <foo@bar>'' (i.e. ``@'' as part of a comment)
+          ;; correctly.
+          (string-match "<\\([^@ \t<>]+[!@][^@ \t<>]+\\)>" from)
+          (setq address (substring from (match-beginning 1) (match-end 1))))
+         ((string-match "\\b[^@ \t<>]+[!@][^@ \t<>]+\\b" from)
+          (setq address (substring from (match-beginning 0) (match-end 0)))))
+    ;; Then we check whether the "name <address>" format is used.
+    (and address
+        ;; Linear white space is not required.
+        (string-match (concat "[ \t]*<" (regexp-quote address) ">") from)
+        (and (setq name (substring from 0 (match-beginning 0)))
+             ;; Strip any quotes from the name.
+             (string-match "^\".*\"$" name)
+             (setq name (substring name 1 (1- (match-end 0))))))
+    ;; If not, then "address (name)" is used.
+    (or name
+       (and (string-match "(.+)" from)
+            (setq name (substring from (1+ (match-beginning 0))
+                                  (1- (match-end 0)))))
+       (and (string-match "()" from)
+            (setq name address))
+       ;; XOVER might not support folded From headers.
+       (and (string-match "(.*" from)
+            (setq name (substring from (1+ (match-beginning 0))
+                                  (match-end 0)))))
+    (list (if (string= name "") nil name) (or address from))))
+
+(declare-function message-fetch-field "message" (header &optional not-all))
+
+(defun gnus-fetch-field (field)
+  "Return the value of the header FIELD of current article."
+  (require 'message)
+  (save-excursion
+    (save-restriction
+      (let ((inhibit-point-motion-hooks t))
+       (nnheader-narrow-to-headers)
+       (message-fetch-field field)))))
+
+(defun gnus-fetch-original-field (field)
+  "Fetch FIELD from the original version of the current article."
+  (with-current-buffer gnus-original-article-buffer
+    (gnus-fetch-field field)))
+
+
+(defun gnus-goto-colon ()
+  (move-beginning-of-line 1)
+  (let ((eol (point-at-eol)))
+    (goto-char (or (text-property-any (point) eol 'gnus-position t)
+                  (search-forward ":" eol t)
+                  (point)))))
+
+(declare-function gnus-find-method-for-group "gnus" (group &optional info))
+(declare-function gnus-group-name-decode "gnus-group" (string charset))
+(declare-function gnus-group-name-charset "gnus-group" (method group))
+;; gnus-group requires gnus-int which requires message.
+(declare-function message-tokenize-header "message"
+                  (header &optional separator))
+
+(defun gnus-decode-newsgroups (newsgroups group &optional method)
+  (require 'gnus-group)
+  (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."
+  (let ((start (point-min))
+       end)
+    (unless (get-text-property start prop)
+      (setq start (next-single-property-change start prop)))
+    (while start
+      (setq end (text-property-any start (point-max) prop nil))
+      (delete-region start (or end (point-max)))
+      (setq start (when end
+                   (next-single-property-change start prop))))))
+
+(defun gnus-find-text-property-region (start end prop)
+  "Return a list of text property regions that has property PROP."
+  (let (regions value)
+    (unless (get-text-property start prop)
+      (setq start (next-single-property-change start prop)))
+    (while start
+      (setq value (get-text-property start prop)
+           end (text-property-not-all start (point-max) prop value))
+      (if (not end)
+         (setq start nil)
+       (when value
+         (push (list (set-marker (make-marker) start)
+                     (set-marker (make-marker) end)
+                     value)
+               regions))
+       (setq start (next-single-property-change start prop))))
+    (nreverse regions)))
+
+(defun gnus-newsgroup-directory-form (newsgroup)
+  "Make hierarchical directory name from NEWSGROUP name."
+  (let* ((newsgroup (gnus-newsgroup-savable-name newsgroup))
+        (idx (string-match ":" newsgroup)))
+    (concat
+     (if idx (substring newsgroup 0 idx))
+     (if idx "/")
+     (nnheader-replace-chars-in-string
+      (if idx (substring newsgroup (1+ idx)) newsgroup)
+      ?. ?/))))
+
+(defun gnus-newsgroup-savable-name (group)
+  ;; Replace any slashes in a group name (eg. an ange-ftp nndoc group)
+  ;; with dots.
+  (nnheader-replace-chars-in-string group ?/ ?.))
+
+(defun gnus-string> (s1 s2)
+  (not (or (string< s1 s2)
+          (string= s1 s2))))
+
+(defun gnus-string< (s1 s2)
+  "Return t if first arg string is less than second in lexicographic order.
+Case is significant if and only if `case-fold-search' is nil.
+Symbols are also allowed; their print names are used instead."
+  (if case-fold-search
+      (string-lessp (downcase (if (symbolp s1) (symbol-name s1) s1))
+                   (downcase (if (symbolp s2) (symbol-name s2) s2)))
+    (string-lessp s1 s2)))
+
+;;; Time functions.
+
+(defun gnus-file-newer-than (file date)
+  (let ((fdate (nth 5 (file-attributes file))))
+    (or (> (car fdate) (car date))
+       (and (= (car fdate) (car date))
+            (> (nth 1 fdate) (nth 1 date))))))
+
+;; Every version of Emacs Gnus supports has built-in float-time.
+;; The featurep test silences an irritating compiler warning.
+(defalias 'gnus-float-time
+  (if (or (featurep 'emacs)
+         (fboundp 'float-time))
+      'float-time 'time-to-seconds))
+
+;;; Keymap macros.
+
+(defmacro gnus-local-set-keys (&rest plist)
+  "Set the keys in PLIST in the current keymap."
+  `(gnus-define-keys-1 (current-local-map) ',plist))
+
+(defmacro gnus-define-keys (keymap &rest plist)
+  "Define all keys in PLIST in KEYMAP."
+  ;; Convert the key [?\S-\ ] to [(shift space)] for XEmacs.
+  (when (featurep 'xemacs)
+    (let ((bindings plist))
+      (while bindings
+       (when (equal (car bindings) [?\S-\ ])
+         (setcar bindings [(shift space)]))
+       (setq bindings (cddr bindings)))))
+  `(gnus-define-keys-1 (quote ,keymap) (quote ,plist)))
+
+(defmacro gnus-define-keys-safe (keymap &rest plist)
+  "Define all keys in PLIST in KEYMAP without overwriting previous definitions."
+  `(gnus-define-keys-1 (quote ,keymap) (quote ,plist) t))
+
+(put 'gnus-define-keys 'lisp-indent-function 1)
+(put 'gnus-define-keys-safe 'lisp-indent-function 1)
+(put 'gnus-local-set-keys 'lisp-indent-function 1)
+
+(defmacro gnus-define-keymap (keymap &rest plist)
+  "Define all keys in PLIST in KEYMAP."
+  `(gnus-define-keys-1 ,keymap (quote ,plist)))
+
+(put 'gnus-define-keymap 'lisp-indent-function 1)
+
+(defun gnus-define-keys-1 (keymap plist &optional safe)
+  (when (null keymap)
+    (error "Can't set keys in a null keymap"))
+  (cond ((symbolp keymap)
+        (setq keymap (symbol-value keymap)))
+       ((keymapp keymap))
+       ((listp keymap)
+        (set (car keymap) nil)
+        (define-prefix-command (car keymap))
+        (define-key (symbol-value (caddr keymap)) (cadr keymap) (car keymap))
+        (setq keymap (symbol-value (car keymap)))))
+  (let (key)
+    (while plist
+      (when (symbolp (setq key (pop plist)))
+       (setq key (symbol-value key)))
+      (if (or (not safe)
+             (eq (lookup-key keymap key) 'undefined))
+         (define-key keymap key (pop plist))
+       (pop plist)))))
+
+(defun gnus-y-or-n-p (prompt)
+  (prog1
+      (y-or-n-p prompt)
+    (message "")))
+(defun gnus-yes-or-no-p (prompt)
+  (prog1
+      (yes-or-no-p prompt)
+    (message "")))
+
+;; By Frank Schmitt <ich@Frank-Schmitt.net>. Allows to have
+;; age-depending date representations. (e.g. just the time if it's
+;; from today, the day of the week if it's within the last 7 days and
+;; the full date if it's older)
+
+(defun gnus-seconds-today ()
+  "Return the number of seconds passed today."
+  (let ((now (decode-time)))
+    (+ (car now) (* (car (cdr now)) 60) (* (car (nthcdr 2 now)) 3600))))
+
+(defun gnus-seconds-month ()
+  "Return the number of seconds passed this month."
+  (let ((now (decode-time)))
+    (+ (car now) (* (car (cdr now)) 60) (* (car (nthcdr 2 now)) 3600)
+       (* (- (car (nthcdr 3 now)) 1) 3600 24))))
+
+(defun gnus-seconds-year ()
+  "Return the number of seconds passed this year."
+  (let* ((current (current-time))
+        (now (decode-time current))
+        (days (format-time-string "%j" current)))
+    (+ (car now) (* (car (cdr now)) 60) (* (car (nthcdr 2 now)) 3600)
+       (* (- (string-to-number days) 1) 3600 24))))
+
+(defmacro gnus-date-get-time (date)
+  "Convert DATE string to Emacs time.
+Cache the result as a text property stored in DATE."
+  ;; Either return the cached value...
+  `(let ((d ,date))
+     (if (equal "" d)
+        '(0 0)
+       (or (get-text-property 0 'gnus-time d)
+          ;; or compute the value...
+          (let ((time (safe-date-to-time d)))
+            ;; and store it back in the string.
+            (put-text-property 0 1 'gnus-time time d)
+            time)))))
+
+(defun gnus-dd-mmm (messy-date)
+  "Return a string like DD-MMM from a big messy string."
+  (condition-case ()
+      (format-time-string "%d-%b" (gnus-date-get-time messy-date))
+    (error "  -   ")))
+
+(defsubst gnus-time-iso8601 (time)
+  "Return a string of TIME in YYYYMMDDTHHMMSS format."
+  (format-time-string "%Y%m%dT%H%M%S" time))
+
+(defun gnus-date-iso8601 (date)
+  "Convert the DATE to YYYYMMDDTHHMMSS."
+  (condition-case ()
+      (gnus-time-iso8601 (gnus-date-get-time date))
+    (error "")))
+
+(defun gnus-mode-string-quote (string)
+  "Quote all \"%\"'s in STRING."
+  (gnus-replace-in-string string "%" "%%"))
+
+;; Make a hash table (default and minimum size is 256).
+;; Optional argument HASHSIZE specifies the table size.
+(defun gnus-make-hashtable (&optional hashsize)
+  (make-vector (if hashsize (max (gnus-create-hash-size hashsize) 256) 256) 0))
+
+;; Make a number that is suitable for hashing; bigger than MIN and
+;; equal to some 2^x.  Many machines (such as sparcs) do not have a
+;; hardware modulo operation, so they implement it in software.  On
+;; many sparcs over 50% of the time to intern is spent in the modulo.
+;; Yes, it's slower than actually computing the hash from the string!
+;; So we use powers of 2 so people can optimize the modulo to a mask.
+(defun gnus-create-hash-size (min)
+  (let ((i 1))
+    (while (< i min)
+      (setq i (* 2 i)))
+    i))
+
+(defcustom gnus-verbose 6
+  "*Integer that says how verbose Gnus should be.
+The higher the number, the more messages Gnus will flash to say what
+it's doing.  At zero, Gnus will be totally mute; at five, Gnus will
+display most important messages; and at ten, Gnus will keep on
+jabbering all the time."
+  :version "24.1"
+  :group 'gnus-start
+  :type 'integer)
+
+(defcustom gnus-add-timestamp-to-message nil
+  "Non-nil means add timestamps to messages that Gnus issues.
+If it is `log', add timestamps to only the messages that go into the
+\"*Messages*\" buffer (in XEmacs, it is the \" *Message-Log*\" buffer).
+If it is neither nil nor `log', add timestamps not only to log messages
+but also to the ones displayed in the echo area."
+  :version "23.1" ;; No Gnus
+  :group  'gnus-various
+  :type '(choice :format "%{%t%}:\n %[Value Menu%] %v"
+                (const :tag "Logged messages only" log)
+                (sexp :tag "All messages"
+                      :match (lambda (widget value) value)
+                      :value t)
+                (const :tag "No timestamp" nil)))
+
+(eval-when-compile
+  (defmacro gnus-message-with-timestamp-1 (format-string args)
+    (let ((timestamp '(format-time-string "%Y%m%dT%H%M%S.%3N> " time)))
+      (if (featurep 'xemacs)
+         `(let (str time)
+            (if (or (and (null ,format-string) (null ,args))
+                    (progn
+                      (setq str (apply 'format ,format-string ,args))
+                      (zerop (length str))))
+                (prog1
+                    (and ,format-string str)
+                  (clear-message nil))
+              (cond ((eq gnus-add-timestamp-to-message 'log)
+                     (setq time (current-time))
+                     (display-message 'no-log str)
+                     (log-message 'message (concat ,timestamp str)))
+                    (gnus-add-timestamp-to-message
+                     (setq time (current-time))
+                     (display-message 'message (concat ,timestamp str)))
+                    (t
+                     (display-message 'message str))))
+            str)
+       `(let (str time)
+          (cond ((eq gnus-add-timestamp-to-message 'log)
+                 (setq str (let (message-log-max)
+                             (apply 'message ,format-string ,args)))
+                 (when (and message-log-max
+                            (> message-log-max 0)
+                            (/= (length str) 0))
+                   (setq time (current-time))
+                   (with-current-buffer (if (fboundp 'messages-buffer)
+                                            (messages-buffer)
+                                          (get-buffer-create "*Messages*"))
+                     (goto-char (point-max))
+                     (let ((inhibit-read-only t))
+                       (insert ,timestamp str "\n")
+                       (forward-line (- message-log-max))
+                       (delete-region (point-min) (point)))
+                     (goto-char (point-max))))
+                 str)
+                (gnus-add-timestamp-to-message
+                 (if (or (and (null ,format-string) (null ,args))
+                         (progn
+                           (setq str (apply 'format ,format-string ,args))
+                           (zerop (length str))))
+                     (prog1
+                         (and ,format-string str)
+                       (message nil))
+                   (setq time (current-time))
+                   (message "%s" (concat ,timestamp str))
+                   str))
+                (t
+                 (apply 'message ,format-string ,args))))))))
+
+(defvar gnus-action-message-log nil)
+
+(defun gnus-message-with-timestamp (format-string &rest args)
+  "Display message with timestamp.  Arguments are the same as `message'.
+The `gnus-add-timestamp-to-message' variable controls how to add
+timestamp to message."
+  (gnus-message-with-timestamp-1 format-string args))
+
+(defun gnus-message (level &rest args)
+  "If LEVEL is lower than `gnus-verbose' print ARGS using `message'.
+
+Guideline for numbers:
+1 - error messages, 3 - non-serious error messages, 5 - messages for things
+that take a long time, 7 - not very important messages on stuff, 9 - messages
+inside loops."
+  (if (<= level gnus-verbose)
+      (let ((message
+            (if gnus-add-timestamp-to-message
+                (apply 'gnus-message-with-timestamp args)
+              (apply 'message args))))
+       (when (and (consp gnus-action-message-log)
+                  (<= level 3))
+         (push message gnus-action-message-log))
+       message)
+    ;; We have to do this format thingy here even if the result isn't
+    ;; shown - the return value has to be the same as the return value
+    ;; from `message'.
+    (apply 'format args)))
+
+(defun gnus-final-warning ()
+  (when (and (consp gnus-action-message-log)
+            (setq gnus-action-message-log
+                  (delete nil gnus-action-message-log)))
+    (message "Warning: %s"
+            (mapconcat #'identity gnus-action-message-log "; "))))
+
+(defun gnus-error (level &rest args)
+  "Beep an error if LEVEL is equal to or less than `gnus-verbose'.
+ARGS are passed to `message'."
+  (when (<= (floor level) gnus-verbose)
+    (apply 'message args)
+    (ding)
+    (let (duration)
+      (when (and (floatp level)
+                (not (zerop (setq duration (* 10 (- level (floor level)))))))
+       (sit-for duration))))
+  nil)
+
+(defun gnus-split-references (references)
+  "Return a list of Message-IDs in REFERENCES."
+  (let ((beg 0)
+       (references (mail-header-remove-comments (or references "")))
+       ids)
+    (while (string-match "<[^<]+[^< \t]" references beg)
+      (push (substring references (match-beginning 0) (setq beg (match-end 0)))
+           ids))
+    (nreverse ids)))
+
+(defun gnus-extract-references (references)
+  "Return a list of Message-IDs in REFERENCES (in In-Reply-To
+  format), trimmed to only contain the Message-IDs."
+  (let ((ids (gnus-split-references references))
+       refs)
+    (dolist (id ids)
+      (when (string-match "<[^<>]+>" id)
+       (push (match-string 0 id) refs)))
+    refs))
+
+(defsubst gnus-parent-id (references &optional n)
+  "Return the last Message-ID in REFERENCES.
+If N, return the Nth ancestor instead."
+  (when (and references
+            (not (zerop (length references))))
+    (if n
+       (let ((ids (inline (gnus-split-references references))))
+         (while (nthcdr n ids)
+           (setq ids (cdr ids)))
+         (car ids))
+      (let ((references (mail-header-remove-comments references)))
+       (when (string-match "\\(<[^<]+>\\)[ \t]*\\'" references)
+         (match-string 1 references))))))
+
+(defsubst gnus-buffer-live-p (buffer)
+  "Say whether BUFFER is alive or not."
+  (and buffer (buffer-live-p (get-buffer buffer))))
+
+(defun gnus-horizontal-recenter ()
+  "Recenter the current buffer horizontally."
+  (if (< (current-column) (/ (window-width) 2))
+      (set-window-hscroll (gnus-get-buffer-window (current-buffer) t) 0)
+    (let* ((orig (point))
+          (end (window-end (gnus-get-buffer-window (current-buffer) t)))
+          (max 0))
+      (when end
+       ;; Find the longest line currently displayed in the window.
+       (goto-char (window-start))
+       (while (and (not (eobp))
+                   (< (point) end))
+         (end-of-line)
+         (setq max (max max (current-column)))
+         (forward-line 1))
+       (goto-char orig)
+       ;; Scroll horizontally to center (sort of) the point.
+       (if (> max (window-width))
+           (set-window-hscroll
+            (gnus-get-buffer-window (current-buffer) t)
+            (min (- (current-column) (/ (window-width) 3))
+                 (+ 2 (- max (window-width)))))
+         (set-window-hscroll (gnus-get-buffer-window (current-buffer) t) 0))
+       max))))
+
+(defun gnus-read-event-char (&optional prompt)
+  "Get the next event."
+  (let ((event (read-event prompt)))
+    ;; should be gnus-characterp, but this can't be called in XEmacs anyway
+    (cons (and (numberp event) event) event)))
+
+(defun gnus-copy-file (file &optional to)
+  "Copy FILE to TO."
+  (interactive
+   (list (read-file-name "Copy file: " default-directory)
+        (read-file-name "Copy file to: " default-directory)))
+  (unless to
+    (setq to (read-file-name "Copy file to: " default-directory)))
+  (when (file-directory-p to)
+    (setq to (concat (file-name-as-directory to)
+                    (file-name-nondirectory file))))
+  (copy-file file to))
+
+(defvar gnus-work-buffer " *gnus work*")
+
+(declare-function gnus-get-buffer-create "gnus" (name))
+;; gnus.el requires mm-util.
+(declare-function mm-enable-multibyte "mm-util")
+
+(defun gnus-set-work-buffer ()
+  "Put point in the empty Gnus work buffer."
+  (if (get-buffer gnus-work-buffer)
+      (progn
+       (set-buffer gnus-work-buffer)
+       (erase-buffer))
+    (set-buffer (gnus-get-buffer-create gnus-work-buffer))
+    (kill-all-local-variables)
+    (mm-enable-multibyte)))
+
+(defmacro gnus-group-real-name (group)
+  "Find the real name of a foreign newsgroup."
+  `(let ((gname ,group))
+     (if (string-match "^[^:]+:" gname)
+        (substring gname (match-end 0))
+       gname)))
+
+(defmacro gnus-group-server (group)
+  "Find the server name of a foreign newsgroup.
+For example, (gnus-group-server \"nnimap+yxa:INBOX.foo\") would
+yield \"nnimap:yxa\"."
+  `(let ((gname ,group))
+     (if (string-match "^\\([^:+]+\\)\\(?:\\+\\([^:]*\\)\\)?:" gname)
+        (format "%s:%s" (match-string 1 gname) (or
+                                                (match-string 2 gname)
+                                                ""))
+       (format "%s:%s" (car gnus-select-method) (cadr gnus-select-method)))))
+
+(defun gnus-make-sort-function (funs)
+  "Return a composite sort condition based on the functions in FUNS."
+  (cond
+   ;; Just a simple function.
+   ((functionp funs) funs)
+   ;; No functions at all.
+   ((null funs) funs)
+   ;; A list of functions.
+   ((or (cdr funs)
+       (listp (car funs)))
+    (gnus-byte-compile
+     `(lambda (t1 t2)
+       ,(gnus-make-sort-function-1 (reverse funs)))))
+   ;; A list containing just one function.
+   (t
+    (car funs))))
+
+(defun gnus-make-sort-function-1 (funs)
+  "Return a composite sort condition based on the functions in FUNS."
+  (let ((function (car funs))
+       (first 't1)
+       (last 't2))
+    (when (consp function)
+      (cond
+       ;; Reversed spec.
+       ((eq (car function) 'not)
+       (setq function (cadr function)
+             first 't2
+             last 't1))
+       ((functionp function)
+       ;; Do nothing.
+       )
+       (t
+       (error "Invalid sort spec: %s" function))))
+    (if (cdr funs)
+       `(or (,function ,first ,last)
+            (and (not (,function ,last ,first))
+                 ,(gnus-make-sort-function-1 (cdr funs))))
+      `(,function ,first ,last))))
+
+(defun gnus-turn-off-edit-menu (type)
+  "Turn off edit menu in `gnus-TYPE-mode-map'."
+  (define-key (symbol-value (intern (format "gnus-%s-mode-map" type)))
+    [menu-bar edit] 'undefined))
+
+(defmacro gnus-bind-print-variables (&rest forms)
+  "Bind print-* variables and evaluate FORMS.
+This macro is used with `prin1', `pp', etc. in order to ensure printed
+Lisp objects are loadable.  Bind `print-quoted' and `print-readably'
+to t, and `print-escape-multibyte', `print-escape-newlines',
+`print-escape-nonascii', `print-length', `print-level' and
+`print-string-length' to nil."
+  `(let ((print-quoted t)
+        (print-readably t)
+        ;;print-circle
+        ;;print-continuous-numbering
+        print-escape-multibyte
+        print-escape-newlines
+        print-escape-nonascii
+        ;;print-gensym
+        print-length
+        print-level
+        print-string-length)
+     ,@forms))
+
+(defun gnus-prin1 (form)
+  "Use `prin1' on FORM in the current buffer.
+Bind `print-quoted' and `print-readably' to t, and `print-length' and
+`print-level' to nil.  See also `gnus-bind-print-variables'."
+  (gnus-bind-print-variables (prin1 form (current-buffer))))
+
+(defun gnus-prin1-to-string (form)
+  "The same as `prin1'.
+Bind `print-quoted' and `print-readably' to t, and `print-length' and
+`print-level' to nil.  See also `gnus-bind-print-variables'."
+  (gnus-bind-print-variables (prin1-to-string form)))
+
+(defun gnus-pp (form &optional stream)
+  "Use `pp' on FORM in the current buffer.
+Bind `print-quoted' and `print-readably' to t, and `print-length' and
+`print-level' to nil.  See also `gnus-bind-print-variables'."
+  (gnus-bind-print-variables (pp form (or stream (current-buffer)))))
+
+(defun gnus-pp-to-string (form)
+  "The same as `pp-to-string'.
+Bind `print-quoted' and `print-readably' to t, and `print-length' and
+`print-level' to nil.  See also `gnus-bind-print-variables'."
+  (gnus-bind-print-variables (pp-to-string form)))
+
+(defun gnus-make-directory (directory)
+  "Make DIRECTORY (and all its parents) if it doesn't exist."
+  (require 'nnmail)
+  (let ((file-name-coding-system nnmail-pathname-coding-system))
+    (when (and directory
+              (not (file-exists-p directory)))
+      (make-directory directory t)))
+  t)
+
+(defun gnus-write-buffer (file)
+  "Write the current buffer's contents to FILE."
+  (require 'nnmail)
+  (let ((file-name-coding-system nnmail-pathname-coding-system))
+    ;; Make sure the directory exists.
+    (gnus-make-directory (file-name-directory file))
+    ;; Write the buffer.
+    (write-region (point-min) (point-max) file nil 'quietly)))
+
+(defun gnus-delete-file (file)
+  "Delete FILE if it exists."
+  (when (file-exists-p file)
+    (delete-file file)))
+
+(defun gnus-delete-duplicates (list)
+  "Remove duplicate entries from LIST."
+  (let ((result nil))
+    (while list
+      (unless (member (car list) result)
+       (push (car list) result))
+      (pop list))
+    (nreverse result)))
+
+(defun gnus-delete-directory (directory)
+  "Delete files in DIRECTORY.  Subdirectories remain.
+If there's no subdirectory, delete DIRECTORY as well."
+  (when (file-directory-p directory)
+    (let ((files (directory-files
+                 directory t "^\\([^.]\\|\\.\\([^.]\\|\\..\\)\\).*"))
+         file dir)
+      (while files
+       (setq file (pop files))
+       (if (eq t (car (file-attributes file)))
+           ;; `file' is a subdirectory.
+           (setq dir t)
+         ;; `file' is a file or a symlink.
+         (delete-file file)))
+      (unless dir
+       (delete-directory directory)))))
+
+(defun gnus-strip-whitespace (string)
+  "Return STRING stripped of all whitespace."
+  (while (string-match "[\r\n\t ]+" string)
+    (setq string (replace-match "" t t string)))
+  string)
+
+(declare-function gnus-put-text-property "gnus"
+                  (start end property value &optional object))
+
+(defsubst gnus-put-text-property-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-put-text-property beg (match-beginning 0) prop val)
+         (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)
+         (overlay-put (make-overlay beg (match-beginning 0)) prop val)
+         (setq beg (point)))
+       (overlay-put (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', except where `gnus-face' is set.
+If so, and PROP is `face', set the second element of its value to VAL.
+Otherwise, do nothing."
+  (while (< beg end)
+    ;; Property values are compared with `eq'.
+    (let ((stop (next-single-property-change beg 'face nil end)))
+      (if (get-text-property beg 'gnus-face)
+         (when (eq prop 'face)
+           (setcar (cdr (get-text-property beg 'face)) (or val 'default)))
+       (inline
+         (gnus-put-text-property beg stop prop val)))
+      (setq beg stop))))
+
+(defun gnus-get-text-property-excluding-characters-with-faces (pos prop)
+  "The same as `get-text-property', except where `gnus-face' is set.
+If so, and PROP is `face', return the second element of its value.
+Otherwise, return the value."
+  (let ((val (get-text-property pos prop)))
+    (if (and (get-text-property pos 'gnus-face)
+            (eq prop 'face))
+       (cadr val)
+      (get-text-property pos prop))))
+
+(defmacro gnus-faces-at (position)
+  "Return a list of faces at POSITION."
+  (if (featurep 'xemacs)
+      `(let ((pos ,position))
+        (mapcar-extents 'extent-face
+                        nil (current-buffer) pos pos nil 'face))
+    `(let ((pos ,position))
+       (delq nil (cons (get-text-property pos 'face)
+                      (mapcar
+                       (lambda (overlay)
+                         (overlay-get overlay 'face))
+                       (overlays-at pos)))))))
+
+(if (fboundp 'invisible-p)
+    (defalias 'gnus-invisible-p 'invisible-p)
+  ;; for Emacs < 22.2, and XEmacs.
+  (defun gnus-invisible-p (pos)
+    "Return non-nil if the character after POS is currently invisible."
+    (let ((prop (get-char-property pos 'invisible)))
+      (if (eq buffer-invisibility-spec t)
+         prop
+       (or (memq prop buffer-invisibility-spec)
+           (assq prop buffer-invisibility-spec))))))
+
+;; Note: the optional 2nd argument has a different meaning between
+;; Emacs and XEmacs.
+;; (next-char-property-change POSITION &optional LIMIT)
+;; (next-extent-change        POS      &optional OBJECT)
+(defalias 'gnus-next-char-property-change
+  (if (fboundp 'next-extent-change)
+      'next-extent-change 'next-char-property-change))
+
+(defalias 'gnus-previous-char-property-change
+  (if (fboundp 'previous-extent-change)
+      'previous-extent-change 'previous-char-property-change))
+
+;;; Protected and atomic operations.  dmoore@ucsd.edu 21.11.1996
+;; The primary idea here is to try to protect internal data structures
+;; from becoming corrupted when the user hits C-g, or if a hook or
+;; similar blows up.  Often in Gnus multiple tables/lists need to be
+;; updated at the same time, or information can be lost.
+
+(defvar gnus-atomic-be-safe t
+  "If t, certain operations will be protected from interruption by C-g.")
+
+(defmacro gnus-atomic-progn (&rest forms)
+  "Evaluate FORMS atomically, which means to protect the evaluation
+from being interrupted by the user.  An error from the forms themselves
+will return without finishing the operation.  Since interrupts from
+the user are disabled, it is recommended that only the most minimal
+operations are performed by FORMS.  If you wish to assign many
+complicated values atomically, compute the results into temporary
+variables and then do only the assignment atomically."
+  `(let ((inhibit-quit gnus-atomic-be-safe))
+     ,@forms))
+
+(put 'gnus-atomic-progn 'lisp-indent-function 0)
+
+(defmacro gnus-atomic-progn-assign (protect &rest forms)
+  "Evaluate FORMS, but ensure that the variables listed in PROTECT
+are not changed if anything in FORMS signals an error or otherwise
+non-locally exits.  The variables listed in PROTECT are updated atomically.
+It is safe to use gnus-atomic-progn-assign with long computations.
+
+Note that if any of the symbols in PROTECT were unbound, they will be
+set to nil on a successful assignment.  In case of an error or other
+non-local exit, it will still be unbound."
+  (let* ((temp-sym-map (mapcar (lambda (x) (list (make-symbol
+                                                 (concat (symbol-name x)
+                                                         "-tmp"))
+                                                x))
+                              protect))
+        (sym-temp-map (mapcar (lambda (x) (list (cadr x) (car x)))
+                              temp-sym-map))
+        (temp-sym-let (mapcar (lambda (x) (list (car x)
+                                                `(and (boundp ',(cadr x))
+                                                      ,(cadr x))))
+                              temp-sym-map))
+        (sym-temp-let sym-temp-map)
+        (temp-sym-assign (apply 'append temp-sym-map))
+        (sym-temp-assign (apply 'append sym-temp-map))
+        (result (make-symbol "result-tmp")))
+    `(let (,@temp-sym-let
+          ,result)
+       (let ,sym-temp-let
+        (setq ,result (progn ,@forms))
+        (setq ,@temp-sym-assign))
+       (let ((inhibit-quit gnus-atomic-be-safe))
+        (setq ,@sym-temp-assign))
+       ,result)))
+
+(put 'gnus-atomic-progn-assign 'lisp-indent-function 1)
+;(put 'gnus-atomic-progn-assign 'edebug-form-spec '(sexp body))
+
+(defmacro gnus-atomic-setq (&rest pairs)
+  "Similar to setq, except that the real symbols are only assigned when
+there are no errors.  And when the real symbols are assigned, they are
+done so atomically.  If other variables might be changed via side-effect,
+see gnus-atomic-progn-assign.  It is safe to use gnus-atomic-setq
+with potentially long computations."
+  (let ((tpairs pairs)
+       syms)
+    (while tpairs
+      (push (car tpairs) syms)
+      (setq tpairs (cddr tpairs)))
+    `(gnus-atomic-progn-assign ,syms
+       (setq ,@pairs))))
+
+;(put 'gnus-atomic-setq 'edebug-form-spec '(body))
+
+
+;;; Functions for saving to babyl/mail files.
+
+(eval-when-compile
+  (if (featurep 'xemacs)
+      ;; Don't load tm and apel XEmacs packages that provide some
+      ;; Emacs emulating functions and variables.
+      (let ((features features))
+       (provide 'tm-view)
+       (unless (fboundp 'set-alist) (defalias 'set-alist 'ignore))
+       (require 'rmail)) ;; It requires tm-view that loads apel.
+    (require 'rmail))
+  (autoload 'rmail-update-summary "rmailsum"))
+
+(defvar mm-text-coding-system)
+
+(declare-function mm-append-to-file "mm-util"
+                  (start end filename &optional codesys inhibit))
+(declare-function rmail-swap-buffers-maybe "rmail" ())
+(declare-function rmail-maybe-set-message-counters "rmail" ())
+(declare-function rmail-count-new-messages "rmail" (&optional nomsg))
+(declare-function rmail-summary-exists "rmail" ())
+(declare-function rmail-show-message "rmail" (&optional n no-summary))
+;; Macroexpansion of rmail-select-summary:
+(declare-function rmail-summary-displayed "rmail" ())
+(declare-function rmail-pop-to-buffer "rmail" (&rest args))
+(declare-function rmail-maybe-display-summary "rmail" ())
+
+(defun gnus-output-to-rmail (filename &optional ask)
+  "Append the current article to an Rmail file named FILENAME.
+In Emacs 22 this writes Babyl format; in Emacs 23 it writes mbox unless
+FILENAME exists and is Babyl format."
+  (require 'rmail)
+  (require 'mm-util)
+  (require 'nnmail)
+  ;; Some of this codes is borrowed from rmailout.el.
+  (setq filename (expand-file-name filename))
+  ;; FIXME should we really be messing with this defcustom?
+  ;; It is not needed for the operation of this function.
+  (if (boundp 'rmail-default-rmail-file)
+      (setq rmail-default-rmail-file filename) ; 22
+    (setq rmail-default-file filename))        ; 23
+  (let ((artbuf (current-buffer))
+       (tmpbuf (get-buffer-create " *Gnus-output*"))
+        ;; Babyl rmail.el defines this, mbox does not.
+        (babyl (fboundp 'rmail-insert-rmail-file-header)))
+    (save-excursion
+      ;; Note that we ignore the possibility of visiting a Babyl
+      ;; format buffer in Emacs 23, since Rmail no longer supports that.
+     (or (get-file-buffer filename)
+         (progn
+           ;; In case someone wants to write to a Babyl file from Emacs 23.
+           (when (file-exists-p filename)
+             (setq babyl (mail-file-babyl-p filename))
+             t))
+         (if (or (not ask)
+                 (gnus-yes-or-no-p
+                  (concat "\"" filename "\" does not exist, create it? ")))
+             (let ((file-buffer (create-file-buffer filename)))
+               (with-current-buffer file-buffer
+                  (if (fboundp 'rmail-insert-rmail-file-header)
+                      (rmail-insert-rmail-file-header))
+                 (let ((require-final-newline nil)
+                       (coding-system-for-write mm-text-coding-system))
+                   (gnus-write-buffer filename)))
+               (kill-buffer file-buffer))
+           (error "Output file does not exist")))
+      (set-buffer tmpbuf)
+      (erase-buffer)
+      (insert-buffer-substring artbuf)
+      (if babyl
+          (gnus-convert-article-to-rmail)
+        ;; Non-Babyl case copied from gnus-output-to-mail.
+        (goto-char (point-min))
+        (if (looking-at "From ")
+            (forward-line 1)
+          (insert "From nobody " (current-time-string) "\n"))
+        (let (case-fold-search)
+          (while (re-search-forward "^From " nil t)
+            (beginning-of-line)
+            (insert ">"))))
+      ;; Decide whether to append to a file or to an Emacs buffer.
+      (let ((outbuf (get-file-buffer filename)))
+       (if (not outbuf)
+            (progn
+              (unless babyl             ; from gnus-output-to-mail
+                (let ((buffer-read-only nil))
+                  (goto-char (point-max))
+                  (forward-char -2)
+                  (unless (looking-at "\n\n")
+                    (goto-char (point-max))
+                    (unless (bolp)
+                      (insert "\n"))
+                    (insert "\n"))))
+              (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)
+               (msg (and (boundp 'rmail-current-message)
+                         (symbol-value 'rmail-current-message))))
+           ;; If MSG is non-nil, buffer is in RMAIL mode.
+            ;; Compare this with rmail-output-to-rmail-buffer in Emacs 23.
+           (when msg
+              (unless babyl
+                (rmail-swap-buffers-maybe)
+                (rmail-maybe-set-message-counters))
+              (widen)
+              (narrow-to-region (point-max) (point-max)))
+           (insert-buffer-substring tmpbuf)
+           (when msg
+              (when babyl
+                (goto-char (point-min))
+                (widen)
+                (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-show-message msg))
+           (save-buffer)))))
+    (kill-buffer tmpbuf)))
+
+(defun gnus-output-to-mail (filename &optional ask)
+  "Append the current article to a mail file named FILENAME."
+  (require 'nnmail)
+  (setq filename (expand-file-name filename))
+  (let ((artbuf (current-buffer))
+       (tmpbuf (get-buffer-create " *Gnus-output*")))
+    (save-excursion
+      ;; Create the file, if it doesn't exist.
+      (when (and (not (get-file-buffer filename))
+                (not (file-exists-p filename)))
+       (if (or (not ask)
+               (gnus-y-or-n-p
+                (concat "\"" filename "\" does not exist, create it? ")))
+           (let ((file-buffer (create-file-buffer filename)))
+             (with-current-buffer file-buffer
+               (let ((require-final-newline nil)
+                     (coding-system-for-write mm-text-coding-system))
+                 (gnus-write-buffer filename)))
+             (kill-buffer file-buffer))
+         (error "Output file does not exist")))
+      (set-buffer tmpbuf)
+      (erase-buffer)
+      (insert-buffer-substring artbuf)
+      (goto-char (point-min))
+      (if (looking-at "From ")
+         (forward-line 1)
+       (insert "From nobody " (current-time-string) "\n"))
+      (let (case-fold-search)
+       (while (re-search-forward "^From " nil t)
+         (beginning-of-line)
+         (insert ">")))
+      ;; Decide whether to append to a file or to an Emacs buffer.
+      (let ((outbuf (get-file-buffer filename)))
+       (if (not outbuf)
+           (let ((buffer-read-only nil))
+             (save-excursion
+               (goto-char (point-max))
+               (forward-char -2)
+               (unless (looking-at "\n\n")
+                 (goto-char (point-max))
+                 (unless (bolp)
+                   (insert "\n"))
+                 (insert "\n"))
+               (goto-char (point-max))
+               (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))
+           (goto-char (point-max))
+           (unless (eobp)
+             (insert "\n"))
+           (insert "\n")
+           (insert-buffer-substring tmpbuf)))))
+    (kill-buffer tmpbuf)))
+
+(defun gnus-convert-article-to-rmail ()
+  "Convert article in current buffer to Rmail message format."
+  (let ((buffer-read-only nil))
+    ;; Convert article directly into Babyl format.
+    (goto-char (point-min))
+    (insert "\^L\n0, unseen,,\n*** EOOH ***\n")
+    (while (search-forward "\n\^_" nil t) ;single char
+      (replace-match "\n^_" t t))      ;2 chars: "^" and "_"
+    (goto-char (point-max))
+    (insert "\^_")))
+
+(defun gnus-map-function (funs arg)
+  "Apply the result of the first function in FUNS to the second, and so on.
+ARG is passed to the first function."
+  (while funs
+    (setq arg (funcall (pop funs) arg)))
+  arg)
+
+(defun gnus-run-hooks (&rest funcs)
+  "Does the same as `run-hooks', but saves the current buffer."
+  (save-current-buffer
+    (apply 'run-hooks funcs)))
+
+(defun gnus-run-hook-with-args (hook &rest args)
+  "Does the same as `run-hook-with-args', but saves the current buffer."
+  (save-current-buffer
+    (apply 'run-hook-with-args hook args)))
+
+(defun gnus-run-mode-hooks (&rest funcs)
+  "Run `run-mode-hooks' if it is available, otherwise `run-hooks'.
+This function saves the current buffer."
+  (if (fboundp 'run-mode-hooks)
+      (save-current-buffer (apply 'run-mode-hooks funcs))
+    (save-current-buffer (apply 'run-hooks funcs))))
+
+;;; Various
+
+(defvar gnus-group-buffer)             ; Compiler directive
+(defun gnus-alive-p ()
+  "Say whether Gnus is running or not."
+  (and (boundp 'gnus-group-buffer)
+       (get-buffer gnus-group-buffer)
+       (with-current-buffer gnus-group-buffer
+        (eq major-mode 'gnus-group-mode))))
+
+(defun gnus-remove-if (predicate sequence &optional hash-table-p)
+  "Return a copy of SEQUENCE with all items satisfying PREDICATE removed.
+SEQUENCE should be a list, a vector, or a string.  Returns always a list.
+If HASH-TABLE-P is non-nil, regards SEQUENCE as a hash table."
+  (let (out)
+    (if hash-table-p
+       (mapatoms (lambda (symbol)
+                   (unless (funcall predicate symbol)
+                     (push symbol out)))
+                 sequence)
+      (unless (listp sequence)
+       (setq sequence (append sequence nil)))
+      (while sequence
+       (unless (funcall predicate (car sequence))
+         (push (car sequence) out))
+       (setq sequence (cdr sequence))))
+    (nreverse out)))
+
+(defun gnus-remove-if-not (predicate sequence &optional hash-table-p)
+  "Return a copy of SEQUENCE with all items not satisfying PREDICATE removed.
+SEQUENCE should be a list, a vector, or a string.  Returns always a list.
+If HASH-TABLE-P is non-nil, regards SEQUENCE as a hash table."
+  (let (out)
+    (if hash-table-p
+       (mapatoms (lambda (symbol)
+                   (when (funcall predicate symbol)
+                     (push symbol out)))
+                 sequence)
+      (unless (listp sequence)
+       (setq sequence (append sequence nil)))
+      (while sequence
+       (when (funcall predicate (car sequence))
+         (push (car sequence) out))
+       (setq sequence (cdr sequence))))
+    (nreverse out)))
+
+(if (fboundp 'assq-delete-all)
+    (defalias 'gnus-delete-alist 'assq-delete-all)
+  (defun gnus-delete-alist (key alist)
+    "Delete from ALIST all elements whose car is KEY.
+Return the modified alist."
+    (let (entry)
+      (while (setq entry (assq key alist))
+       (setq alist (delq entry alist)))
+      alist)))
+
+(defun gnus-grep-in-list (word list)
+  "Find if a WORD matches any regular expression in the given LIST."
+  (when (and word list)
+    (catch 'found
+      (dolist (r list)
+       (when (string-match r word)
+         (throw 'found r))))))
+
+(defmacro gnus-alist-pull (key alist &optional assoc-p)
+  "Modify ALIST to be without KEY."
+  (unless (symbolp alist)
+    (error "Not a symbol: %s" alist))
+  (let ((fun (if assoc-p 'assoc 'assq)))
+    `(setq ,alist (delq (,fun ,key ,alist) ,alist))))
+
+(defun gnus-globalify-regexp (re)
+  "Return a regexp that matches a whole line, if RE matches a part of it."
+  (concat (unless (string-match "^\\^" re) "^.*")
+         re
+         (unless (string-match "\\$$" re) ".*$")))
+
+(defun gnus-set-window-start (&optional point)
+  "Set the window start to POINT, or (point) if nil."
+  (let ((win (gnus-get-buffer-window (current-buffer) t)))
+    (when win
+      (set-window-start win (or point (point))))))
+
+(defun gnus-annotation-in-region-p (b e)
+  (if (= b e)
+      (eq (cadr (memq 'gnus-undeletable (text-properties-at b))) t)
+    (text-property-any b e 'gnus-undeletable t)))
+
+(defun gnus-or (&rest elems)
+  "Return non-nil if any of the elements are non-nil."
+  (catch 'found
+    (while elems
+      (when (pop elems)
+       (throw 'found t)))))
+
+(defun gnus-and (&rest elems)
+  "Return non-nil if all of the elements are non-nil."
+  (catch 'found
+    (while elems
+      (unless (pop elems)
+       (throw 'found nil)))
+    t))
+
+;; gnus.el requires mm-util.
+(declare-function mm-disable-multibyte "mm-util")
+
+(defun gnus-write-active-file (file hashtb &optional full-names)
+  ;; `coding-system-for-write' should be `raw-text' or equivalent.
+  (let ((coding-system-for-write nnmail-active-file-coding-system))
+    (with-temp-file file
+      ;; The buffer should be in the unibyte mode because group names
+      ;; are ASCII text or encoded non-ASCII text (i.e., unibyte).
+      (mm-disable-multibyte)
+      (mapatoms
+       (lambda (sym)
+        (when (and sym
+                   (boundp sym)
+                   (symbol-value sym))
+          (insert (format "%S %d %d y\n"
+                          (if full-names
+                              sym
+                            (intern (gnus-group-real-name (symbol-name sym))))
+                          (or (cdr (symbol-value sym))
+                              (car (symbol-value sym)))
+                          (car (symbol-value sym))))))
+       hashtb)
+      (goto-char (point-max))
+      (while (search-backward "\\." nil t)
+       (delete-char 1)))))
+
+;; Fixme: Why not use `with-output-to-temp-buffer'?
+(defmacro gnus-with-output-to-file (file &rest body)
+  (let ((buffer (make-symbol "output-buffer"))
+        (size (make-symbol "output-buffer-size"))
+        (leng (make-symbol "output-buffer-length"))
+        (append (make-symbol "output-buffer-append")))
+    `(let* ((,size 131072)
+            (,buffer (make-string ,size 0))
+            (,leng 0)
+            (,append nil)
+            (standard-output
+            (lambda (c)
+               (aset ,buffer ,leng c)
+
+              (if (= ,size (setq ,leng (1+ ,leng)))
+                  (progn (write-region ,buffer nil ,file ,append 'no-msg)
+                         (setq ,leng 0
+                               ,append t))))))
+       ,@body
+       (when (> ,leng 0)
+         (let ((coding-system-for-write 'no-conversion))
+        (write-region (substring ,buffer 0 ,leng) nil ,file
+                      ,append 'no-msg))))))
+
+(put 'gnus-with-output-to-file 'lisp-indent-function 1)
+(put 'gnus-with-output-to-file 'edebug-form-spec '(form body))
+
+(if (fboundp 'union)
+    (defalias 'gnus-union 'union)
+  (defun gnus-union (l1 l2 &rest keys)
+    "Set union of lists L1 and L2.
+If KEYS contains the `:test' and `equal' pair, use `equal' to compare
+items in lists, otherwise use `eq'."
+    (cond ((null l1) l2)
+         ((null l2) l1)
+         ((equal l1 l2) l1)
+         (t
+          (or (>= (length l1) (length l2))
+              (setq l1 (prog1 l2 (setq l2 l1))))
+          (if (eq 'equal (plist-get keys :test))
+              (while l2
+                (or (member (car l2) l1)
+                    (push (car l2) l1))
+                (pop l2))
+            (while l2
+              (or (memq (car l2) l1)
+                  (push (car l2) l1))
+              (pop l2)))
+          l1))))
+
+(declare-function gnus-add-text-properties "gnus"
+                  (start end properties &optional object))
+
+(defun gnus-add-text-properties-when
+  (property value start end properties &optional object)
+  "Like `gnus-add-text-properties', only applied on where PROPERTY is VALUE."
+  (let (point)
+    (while (and start
+               (< start end) ;; XEmacs will loop for every when start=end.
+               (setq point (text-property-not-all start end property value)))
+      (gnus-add-text-properties start point properties object)
+      (setq start (text-property-any point end property value)))
+    (if start
+       (gnus-add-text-properties start end properties object))))
+
+(defun gnus-remove-text-properties-when
+  (property value start end properties &optional object)
+  "Like `remove-text-properties', only applied on where PROPERTY is VALUE."
+  (let (point)
+    (while (and start
+               (< start end)
+               (setq point (text-property-not-all start end property value)))
+      (remove-text-properties start point properties object)
+      (setq start (text-property-any point end property value)))
+    (if start
+       (remove-text-properties start end properties object))
+    t))
+
+(defun gnus-string-remove-all-properties (string)
+  (condition-case ()
+      (let ((s string))
+       (set-text-properties 0 (length string) nil string)
+       s)
+    (error string)))
+
+;; This might use `compare-strings' to reduce consing in the
+;; case-insensitive case, but it has to cope with null args.
+;; (`string-equal' uses symbol print names.)
+(defun gnus-string-equal (x y)
+  "Like `string-equal', except it compares case-insensitively."
+  (and (= (length x) (length y))
+       (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 code.
+Setting it to nil has no effect after the first time `gnus-byte-compile'
+is run."
+  :type 'boolean
+  :version "22.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
+       (condition-case nil
+           ;; Work around a bug in XEmacs 21.4
+           (require 'byte-optimize)
+         (error))
+       (require 'bytecomp)
+       (defalias 'gnus-byte-compile
+         (lambda (form)
+           (let ((byte-compile-warnings '(unresolved callargs redefine)))
+             (byte-compile form))))
+       (gnus-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 (gnus-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)))
+
+;; Fixme: Do it like QP.
+(defun gnus-url-unhex-string (str &optional allow-newlines)
+  "Remove %XX, 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."
+  (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-make-predicate (spec)
+  "Transform SPEC into a function that can be called.
+SPEC is a predicate specifier that contains stuff like `or', `and',
+`not', lists and functions.  The functions all take one parameter."
+  `(lambda (elem) ,(gnus-make-predicate-1 spec)))
+
+(defun gnus-make-predicate-1 (spec)
+  (cond
+   ((symbolp spec)
+    `(,spec elem))
+   ((listp spec)
+    (if (memq (car spec) '(or and not))
+       `(,(car spec) ,@(mapcar 'gnus-make-predicate-1 (cdr spec)))
+      (error "Invalid predicate specifier: %s" spec)))))
+
+(defun gnus-completing-read (prompt collection &optional require-match
+                                    initial-input history def)
+  "Call `gnus-completing-read-function'."
+  (funcall gnus-completing-read-function
+           (concat prompt (when def
+                            (concat " (default " def ")"))
+                   ": ")
+           collection require-match initial-input history def))
+
+(defun gnus-emacs-completing-read (prompt collection &optional require-match
+                                          initial-input history def)
+  "Call standard `completing-read-function'."
+  (let ((completion-styles gnus-completion-styles))
+    (completing-read prompt
+                    (if (featurep 'xemacs)
+                        ;; Old XEmacs (at least 21.4) expect an alist,
+                        ;; in which the car of each element is a string,
+                        ;; for collection.
+                        (mapcar
+                         (lambda (elem)
+                           (list (format "%s" (or (car-safe elem) elem))))
+                         collection)
+                      collection)
+                     nil require-match initial-input history def)))
+
+(autoload 'ido-completing-read "ido")
+(defun gnus-ido-completing-read (prompt collection &optional require-match
+                                        initial-input history def)
+  "Call `ido-completing-read-function'."
+  (ido-completing-read prompt collection nil require-match
+                      initial-input history def))
+
+
+(declare-function iswitchb-read-buffer "iswitchb"
+                 (prompt &optional default require-match
+                         _predicate start matches-set))
+(defvar iswitchb-temp-buflist)
+(defvar iswitchb-mode)
+
+(defun gnus-iswitchb-completing-read (prompt collection &optional require-match
+                                            initial-input history def)
+  "`iswitchb' based completing-read function."
+  ;; Make sure iswitchb is loaded before we let-bind its variables.
+  ;; If it is loaded inside the let, variables can become unbound afterwards.
+  (require 'iswitchb)
+  (let ((iswitchb-make-buflist-hook
+         (lambda ()
+           (setq iswitchb-temp-buflist
+                 (let ((choices (append
+                                 (when initial-input (list initial-input))
+                                 (symbol-value history) collection))
+                       filtered-choices)
+                   (dolist (x choices)
+                     (setq filtered-choices (adjoin x filtered-choices)))
+                   (nreverse filtered-choices))))))
+    (unwind-protect
+        (progn
+          (or iswitchb-mode
+             (add-hook 'minibuffer-setup-hook 'iswitchb-minibuffer-setup))
+          (iswitchb-read-buffer prompt def require-match))
+      (or iswitchb-mode
+         (remove-hook 'minibuffer-setup-hook 'iswitchb-minibuffer-setup)))))
+
+(defun gnus-graphic-display-p ()
+  (if (featurep 'xemacs)
+      (device-on-window-system-p)
+    (display-graphic-p)))
+
+(put 'gnus-parse-without-error 'lisp-indent-function 0)
+(put 'gnus-parse-without-error 'edebug-form-spec '(body))
+
+(defmacro gnus-parse-without-error (&rest body)
+  "Allow continuing onto the next line even if an error occurs."
+  `(while (not (eobp))
+     (condition-case ()
+        (progn
+          ,@body
+          (goto-char (point-max)))
+       (error
+       (gnus-error 4 "Invalid data on line %d"
+                   (count-lines (point-min) (point)))
+       (forward-line 1)))))
+
+(defun gnus-cache-file-contents (file variable function)
+  "Cache the contents of FILE in VARIABLE.  The contents come from FUNCTION."
+  (let ((time (nth 5 (file-attributes file)))
+       contents value)
+    (if (or (null (setq value (symbol-value variable)))
+           (not (equal (car value) file))
+           (not (equal (nth 1 value) time)))
+       (progn
+         (setq contents (funcall function file))
+         (set variable (list file time contents))
+         contents)
+      (nth 2 value))))
+
+(defun gnus-multiple-choice (prompt choice &optional idx)
+  "Ask user a multiple choice question.
+CHOICE is a list of the choice char and help message at IDX."
+  (let (tchar buf)
+    (save-window-excursion
+      (save-excursion
+       (while (not tchar)
+         (message "%s (%s): "
+                  prompt
+                  (concat
+                   (mapconcat (lambda (s) (char-to-string (car s)))
+                              choice ", ") ", ?"))
+         (setq tchar (read-char))
+         (when (not (assq tchar choice))
+           (setq tchar nil)
+           (setq buf (get-buffer-create "*Gnus Help*"))
+           (pop-to-buffer buf)
+           (fundamental-mode)          ; for Emacs 20.4+
+           (buffer-disable-undo)
+           (erase-buffer)
+           (insert prompt ":\n\n")
+           (let ((max -1)
+                 (list choice)
+                 (alist choice)
+                 (idx (or idx 1))
+                 (i 0)
+                 n width pad format)
+             ;; find the longest string to display
+             (while list
+               (setq n (length (nth idx (car list))))
+               (unless (> max n)
+                 (setq max n))
+               (setq list (cdr list)))
+             (setq max (+ max 4))      ; %c, `:', SPACE, a SPACE at end
+             (setq n (/ (1- (window-width)) max)) ; items per line
+             (setq width (/ (1- (window-width)) n)) ; width of each item
+             ;; insert `n' items, each in a field of width `width'
+             (while alist
+               (if (< i n)
+                   ()
+                 (setq i 0)
+                 (delete-char -1)              ; the `\n' takes a char
+                 (insert "\n"))
+               (setq pad (- width 3))
+               (setq format (concat "%c: %-" (int-to-string pad) "s"))
+               (insert (format format (caar alist) (nth idx (car alist))))
+               (setq alist (cdr alist))
+               (setq i (1+ i))))))))
+    (if (buffer-live-p buf)
+       (kill-buffer buf))
+    tchar))
+
+(if (featurep 'emacs)
+    (defalias 'gnus-select-frame-set-input-focus 'select-frame-set-input-focus)
+  (if (fboundp 'select-frame-set-input-focus)
+      (defalias 'gnus-select-frame-set-input-focus 'select-frame-set-input-focus)
+    ;; XEmacs 21.4, SXEmacs
+    (defun gnus-select-frame-set-input-focus (frame)
+      "Select FRAME, raise it, and set input focus, if possible."
+      (raise-frame frame)
+      (select-frame frame)
+      (focus-frame frame))))
+
+(defun gnus-frame-or-window-display-name (object)
+  "Given a frame or window, return the associated display name.
+Return nil otherwise."
+  (if (featurep 'xemacs)
+      (device-connection (dfw-device object))
+    (if (or (framep object)
+           (and (windowp object)
+                (setq object (window-frame object))))
+       (let ((display (frame-parameter object 'display)))
+         (if (and (stringp display)
+                  ;; Exclude invalid display names.
+                  (string-match "\\`[^:]*:[0-9]+\\(\\.[0-9]+\\)?\\'"
+                                display))
+             display)))))
+
+(defvar tool-bar-mode)
+
+(defun gnus-tool-bar-update (&rest ignore)
+  "Update the tool bar."
+  (when (and (boundp 'tool-bar-mode)
+            tool-bar-mode)
+    (let* ((args nil)
+          (func (cond ((featurep 'xemacs)
+                       'ignore)
+                      ((fboundp 'tool-bar-update)
+                       'tool-bar-update)
+                      ((fboundp 'force-window-update)
+                       'force-window-update)
+                      ((fboundp 'redraw-frame)
+                       (setq args (list (selected-frame)))
+                       'redraw-frame)
+                      (t 'ignore))))
+      (apply func args))))
+
+;; Fixme: This has only one use (in gnus-agent), which isn't worthwhile.
+(defmacro gnus-mapcar (function seq1 &rest seqs2_n)
+  "Apply FUNCTION to each element of the sequences, and make a list of the results.
+If there are several sequences, FUNCTION is called with that many arguments,
+and mapping stops as soon as the shortest sequence runs out.  With just one
+sequence, this is like `mapcar'.  With several, it is like the Common Lisp
+`mapcar' function extended to arbitrary sequence types."
+
+  (if seqs2_n
+      (let* ((seqs (cons seq1 seqs2_n))
+            (cnt 0)
+            (heads (mapcar (lambda (seq)
+                             (make-symbol (concat "head"
+                                                  (int-to-string
+                                                   (setq cnt (1+ cnt))))))
+                           seqs))
+            (result (make-symbol "result"))
+            (result-tail (make-symbol "result-tail")))
+       `(let* ,(let* ((bindings (cons nil nil))
+                      (heads heads))
+                 (nconc bindings (list (list result '(cons nil nil))))
+                 (nconc bindings (list (list result-tail result)))
+                 (while heads
+                   (nconc bindings (list (list (pop heads) (pop seqs)))))
+                 (cdr bindings))
+          (while (and ,@heads)
+            (setcdr ,result-tail (cons (funcall ,function
+                                                ,@(mapcar (lambda (h) (list 'car h))
+                                                          heads))
+                                       nil))
+            (setq ,result-tail (cdr ,result-tail)
+                  ,@(apply 'nconc (mapcar (lambda (h) (list h (list 'cdr h))) heads))))
+          (cdr ,result)))
+    `(mapcar ,function ,seq1)))
+
+(if (fboundp 'merge)
+    (defalias 'gnus-merge 'merge)
+  ;; Adapted from cl-seq.el
+  (defun gnus-merge (type list1 list2 pred)
+    "Destructively merge lists LIST1 and LIST2 to produce a new list.
+Argument TYPE is for compatibility and ignored.
+Ordering of the elements is preserved according to PRED, a `less-than'
+predicate on the elements."
+    (let ((res nil))
+      (while (and list1 list2)
+       (if (funcall pred (car list2) (car list1))
+           (push (pop list2) res)
+         (push (pop list1) res)))
+      (nconc (nreverse res) list1 list2))))
+
+(defvar xemacs-codename)
+(defvar sxemacs-codename)
+(defvar emacs-program-version)
+
+(defun gnus-emacs-version ()
+  "Stringified Emacs version."
+  (let* ((lst (if (listp gnus-user-agent)
+                 gnus-user-agent
+               '(gnus emacs type)))
+        (system-v (cond ((memq 'config lst)
+                         system-configuration)
+                        ((memq 'type lst)
+                         (symbol-name system-type))
+                        (t nil)))
+        codename emacsname)
+    (cond ((featurep 'sxemacs)
+          (setq emacsname "SXEmacs"
+                codename sxemacs-codename))
+         ((featurep 'xemacs)
+          (setq emacsname "XEmacs"
+                codename xemacs-codename))
+         (t
+          (setq emacsname "Emacs")))
+    (cond
+     ((not (memq 'emacs lst))
+      nil)
+     ((string-match "^\\(\\([.0-9]+\\)*\\)\\.[0-9]+$" emacs-version)
+      ;; Emacs:
+      (concat "Emacs/" (match-string 1 emacs-version)
+             (if system-v
+                 (concat " (" system-v ")")
+               "")))
+     ((or (featurep 'sxemacs) (featurep 'xemacs))
+      ;; XEmacs or SXEmacs:
+      (concat emacsname "/" emacs-program-version
+             (let (plst)
+               (when (memq 'codename lst)
+                 (push codename plst))
+               (when system-v
+                 (push system-v plst))
+               (unless (featurep 'mule)
+                 (push "no MULE" plst))
+               (when (> (length plst) 0)
+                 (concat
+                  " (" (mapconcat 'identity (reverse plst) ", ") ")")))))
+     (t emacs-version))))
+
+(defun gnus-rename-file (old-path new-path &optional trim)
+  "Rename OLD-PATH as NEW-PATH.  If TRIM, recursively delete
+empty directories from OLD-PATH."
+  (when (file-exists-p old-path)
+    (let* ((old-dir (file-name-directory old-path))
+          (old-name (file-name-nondirectory old-path))
+          (new-dir (file-name-directory new-path))
+          (new-name (file-name-nondirectory new-path))
+          temp)
+      (gnus-make-directory new-dir)
+      (rename-file old-path new-path t)
+      (when trim
+       (while (progn (setq temp (directory-files old-dir))
+                     (while (member (car temp) '("." ".."))
+                       (setq temp (cdr temp)))
+                     (= (length temp) 0))
+         (delete-directory old-dir)
+         (setq old-dir (file-name-as-directory
+                        (file-truename
+                         (concat old-dir "..")))))))))
+
+(defun gnus-set-file-modes (filename mode)
+  "Wrapper for set-file-modes."
+  (ignore-errors
+    (set-file-modes filename mode)))
+
+(if (fboundp 'set-process-query-on-exit-flag)
+    (defalias 'gnus-set-process-query-on-exit-flag
+      'set-process-query-on-exit-flag)
+  (defalias 'gnus-set-process-query-on-exit-flag
+    'process-kill-without-query))
+
+(defalias 'gnus-read-shell-command
+  (if (fboundp 'read-shell-command) 'read-shell-command 'read-string))
+
+(defmacro gnus-put-display-table (range value display-table)
+  "Set the value for char RANGE to VALUE in DISPLAY-TABLE.  "
+  (if (featurep 'xemacs)
+      (progn
+        `(if (fboundp 'put-display-table)
+          (put-display-table ,range ,value ,display-table)
+          (if (sequencep ,display-table)
+              (aset ,display-table ,range ,value)
+            (put-char-table ,range ,value ,display-table))))
+    `(aset ,display-table ,range ,value)))
+
+(defmacro gnus-get-display-table (character display-table)
+  "Find value for CHARACTER in DISPLAY-TABLE.  "
+  (if (featurep 'xemacs)
+      `(if (fboundp 'get-display-table)
+          (get-display-table ,character ,display-table)
+          (if (sequencep ,display-table)
+              (aref ,display-table ,character)
+            (get-char-table ,character ,display-table)))
+    `(aref ,display-table ,character)))
+
+(declare-function image-size "image.c" (spec &optional pixels frame))
+
+(defun gnus-rescale-image (image size)
+  "Rescale IMAGE to SIZE if possible.
+SIZE is in format (WIDTH . HEIGHT). Return a new image.
+Sizes are in pixels."
+  (if (or (not (fboundp 'imagemagick-types))
+         (not (get-buffer-window (current-buffer))))
+      image
+    (let ((new-width (car size))
+          (new-height (cdr size)))
+      (when (> (cdr (image-size image t)) new-height)
+        (setq image (or (create-image (plist-get (cdr image) :data) 'imagemagick t
+                                      :height new-height)
+                        image)))
+      (when (> (car (image-size image t)) new-width)
+        (setq image (or
+                   (create-image (plist-get (cdr image) :data) 'imagemagick t
+                                 :width new-width)
+                   image)))
+      image)))
+
+(eval-when-compile (require 'gmm-utils))
+(defun gnus-recursive-directory-files (dir)
+  "Return all regular files below DIR.
+The first found will be returned if a file has hard or symbolic links."
+  (let (files attr attrs)
+    (gmm-labels
+       ((fn (directory)
+            (dolist (file (directory-files directory t))
+              (setq attr (file-attributes (file-truename file)))
+              (when (and (not (member attr attrs))
+                         (not (member (file-name-nondirectory file)
+                                      '("." "..")))
+                         (file-readable-p file))
+                (push attr attrs)
+                (cond ((file-regular-p file)
+                       (push file files))
+                      ((file-directory-p file)
+                       (fn file)))))))
+      (fn dir))
+    files))
+
+(defun gnus-list-memq-of-list (elements list)
+  "Return non-nil if any of the members of ELEMENTS are in LIST."
+  (let ((found nil))
+    (dolist (elem elements)
+      (setq found (or found
+                     (memq elem list))))
+    found))
+
+(eval-and-compile
+  (cond
+   ((fboundp 'match-substitute-replacement)
+    (defalias 'gnus-match-substitute-replacement 'match-substitute-replacement))
+   (t
+    (defun gnus-match-substitute-replacement (replacement &optional fixedcase literal string subexp)
+      "Return REPLACEMENT as it will be inserted by `replace-match'.
+In other words, all back-references in the form `\\&' and `\\N'
+are substituted with actual strings matched by the last search.
+Optional FIXEDCASE, LITERAL, STRING and SUBEXP have the same
+meaning as for `replace-match'.
+
+This is the definition of match-substitute-replacement in subr.el from GNU Emacs."
+      (let ((match (match-string 0 string)))
+       (save-match-data
+         (set-match-data (mapcar (lambda (x)
+                                   (if (numberp x)
+                                       (- x (match-beginning 0))
+                                     x))
+                                 (match-data t)))
+         (replace-match replacement fixedcase literal match subexp)))))))
+
+(if (fboundp 'string-match-p)
+    (defalias 'gnus-string-match-p 'string-match-p)
+  (defsubst gnus-string-match-p (regexp string &optional start)
+    "\
+Same as `string-match' except this function does not change the match data."
+    (save-match-data
+      (string-match regexp string start))))
+
+(if (fboundp 'string-prefix-p)
+    (defalias 'gnus-string-prefix-p 'string-prefix-p)
+  (defun gnus-string-prefix-p (str1 str2 &optional ignore-case)
+    "Return non-nil if STR1 is a prefix of STR2.
+If IGNORE-CASE is non-nil, the comparison is done without paying attention
+to case differences."
+    (and (<= (length str1) (length str2))
+        (let ((prefix (substring str2 0 (length str1))))
+          (if ignore-case
+              (string-equal (downcase str1) (downcase prefix))
+            (string-equal str1 prefix))))))
+
+(defalias 'gnus-format-message
+  (if (fboundp 'format-message) 'format-message
+    ;; for Emacs < 25, and XEmacs, don't worry about quote translation.
+    'format))
+
+;; Simple check: can be a macro but this way, although slow, it's really clear.
+;; We don't use `bound-and-true-p' because it's not in XEmacs.
+(defun gnus-bound-and-true-p (sym)
+  (and (boundp sym) (symbol-value sym)))
+
+(if (fboundp 'timer--function)
+    (defalias 'gnus-timer--function 'timer--function)
+  (defun gnus-timer--function (timer)
+    (elt timer 5)))
+
+(defun gnus-test-list (list predicate)
+  "To each element of LIST apply PREDICATE.
+Return nil if LIST is no list or is empty or some test returns nil;
+otherwise, return t."
+  (when (and list (listp list))
+    (let ((result (mapcar predicate list)))
+      (not (memq nil result)))))
+
+(defun gnus-subsetp (list1 list2)
+  "Return t if LIST1 is a subset of LIST2.
+Similar to `subsetp' but use member for element test so that this works for
+lists of strings."
+  (when (and (listp list1) (listp list2))
+    (if list1
+       (and (member (car list1) list2)
+            (gnus-subsetp (cdr list1) list2))
+      t)))
+
+(defun gnus-setdiff (list1 list2)
+  "Return member-based set difference of LIST1 and LIST2."
+  (when (and list1 (listp list1) (listp list2))
+    (if (member (car list1) list2)
+       (gnus-setdiff (cdr list1) list2)
+      (cons (car list1) (gnus-setdiff (cdr list1) list2)))))
+
+(provide 'gnus-util)
+
+;;; gnus-util.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-uu.el b/xemacs-packages/gnus/lisp/gnus-uu.el
new file mode 100644 (file)
index 0000000..83f817f
--- /dev/null
@@ -0,0 +1,2144 @@
+;;; gnus-uu.el --- extract (uu)encoded files in Gnus
+
+;; Copyright (C) 1985-1987, 1993-1998, 2000-2016 Free Software
+;; Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Created: 2 Oct 1993
+;; Keyword: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'gnus)
+(require 'gnus-art)
+(require 'message)
+(require 'gnus-msg)
+(require 'mm-decode)
+(require 'yenc)
+
+(defgroup gnus-extract nil
+  "Extracting encoded files."
+  :prefix "gnus-uu-"
+  :group 'gnus)
+
+(defgroup gnus-extract-view nil
+  "Viewing extracted files."
+  :group 'gnus-extract)
+
+(defgroup gnus-extract-archive nil
+  "Extracting encoded archives."
+  :group 'gnus-extract)
+
+(defgroup gnus-extract-post nil
+  "Extracting encoded archives."
+  :prefix "gnus-uu-post"
+  :group 'gnus-extract)
+
+;; Default viewing action rules
+
+(defcustom gnus-uu-default-view-rules
+  '(("\\.te?xt$\\|\\.doc$\\|read.*me\\|\\.c?$\\|\\.h$\\|\\.bat$\\|\\.asm$\\|makefile" "cat %s | sed 's/\r$//'")
+    ("\\.pas$" "cat %s | sed 's/\r$//'")
+    ("\\.[1-9]$" "groff -mandoc -Tascii %s | sed s/\b.//g")
+    ("\\.\\(jpe?g\\|gif\\|tiff?\\|p[pgb]m\\|xwd\\|xbm\\|pcx\\)$" "display")
+    ("\\.tga$" "tgatoppm %s | ee -")
+    ("\\.\\(wav\\|aiff\\|hcom\\|u[blw]\\|s[bfw]\\|voc\\|smp\\)$"
+     "sox -v .5 %s -t .au -u - > /dev/audio")
+    ("\\.au$" "cat %s > /dev/audio")
+    ("\\.midi?$" "playmidi -f")
+    ("\\.mod$" "str32")
+    ("\\.ps$" "ghostview")
+    ("\\.dvi$" "xdvi")
+    ("\\.html$" "xmosaic")
+    ("\\.mpe?g$" "mpeg_play")
+    ("\\.\\(flc\\|fli\\|rle\\|iff\\|pfx\\|avi\\|sme\\|rpza\\|dl\\|qt\\|rsrc\\|mov\\)$" "xanim")
+    ("\\.\\(tar\\|arj\\|zip\\|zoo\\|arc\\|gz\\|Z\\|lzh\\|ar\\|lha\\)$"
+     "gnus-uu-archive"))
+  "*Default actions to be taken when the user asks to view a file.
+To change the behavior, you can either edit this variable or set
+`gnus-uu-user-view-rules' to something useful.
+
+For example:
+
+To make gnus-uu use `xli' to display JPEG and GIF files, put the
+following in your .emacs file:
+
+  (setq gnus-uu-user-view-rules \\='((\"jpg$\\\\|gif$\" \"xli\")))
+
+Both these variables are lists of lists with two string elements.  The
+first string is a regular expression.  If the file name matches this
+regular expression, the command in the second string is executed with
+the file as an argument.
+
+If the command string contains \"%s\", the file name will be inserted
+at that point in the command string.  If there's no \"%s\" in the
+command string, the file name will be appended to the command string
+before executing.
+
+There are several user variables to tailor the behavior of gnus-uu to
+your needs.  First we have `gnus-uu-user-view-rules', which is the
+variable gnus-uu first consults when trying to decide how to view a
+file.  If this variable contains no matches, gnus-uu examines the
+default rule variable provided in this package.  If gnus-uu finds no
+match here, it uses `gnus-uu-user-view-rules-end' to try to make a
+match."
+  :group 'gnus-extract-view
+  :type '(repeat (group regexp (string :tag "Command"))))
+
+(defcustom gnus-uu-user-view-rules nil
+  "What actions are to be taken to view a file.
+See the documentation on the `gnus-uu-default-view-rules' variable for
+details."
+  :group 'gnus-extract-view
+  :type '(repeat (group regexp (string :tag "Command"))))
+
+(defcustom gnus-uu-user-view-rules-end
+  '(("" "file"))
+  "*What actions are to be taken if no rule matched the file name.
+See the documentation on the `gnus-uu-default-view-rules' variable for
+details."
+  :group 'gnus-extract-view
+  :type '(repeat (group regexp (string :tag "Command"))))
+
+;; Default unpacking commands
+
+(defcustom gnus-uu-default-archive-rules
+  '(("\\.tar$" "tar xf")
+    ("\\.zip$" "unzip -o")
+    ("\\.ar$" "ar x")
+    ("\\.arj$" "unarj x")
+    ("\\.zoo$" "zoo -e")
+    ("\\.\\(lzh\\|lha\\)$" "lha x")
+    ("\\.Z$" "uncompress")
+    ("\\.gz$" "gunzip")
+    ("\\.arc$" "arc -x"))
+  "*See `gnus-uu-user-archive-rules'."
+  :group 'gnus-extract-archive
+  :type '(repeat (group regexp (string :tag "Command"))))
+
+(defvar gnus-uu-destructive-archivers
+  (list "uncompress" "gunzip"))
+
+(defcustom gnus-uu-user-archive-rules nil
+  "A list that can be set to override the default archive unpacking commands.
+To use, for instance, `untar' to unpack tar files and `zip -x' to
+unpack zip files, say the following:
+  (setq gnus-uu-user-archive-rules
+    \\='((\"\\\\.tar$\" \"untar\")
+      (\"\\\\.zip$\" \"zip -x\")))"
+  :group 'gnus-extract-archive
+  :type '(repeat (group regexp (string :tag "Command"))))
+
+(defcustom gnus-uu-ignore-files-by-name nil
+  "*A regular expression saying what files should not be viewed based on name.
+If, for instance, you want gnus-uu to ignore all .au and .wav files,
+you could say something like
+
+  (setq gnus-uu-ignore-files-by-name \"\\\\.au$\\\\|\\\\.wav$\")
+
+Note that this variable can be used in conjunction with the
+`gnus-uu-ignore-files-by-type' variable."
+  :group 'gnus-extract
+  :type '(choice (const :tag "off" nil)
+                (regexp :format "%v")))
+
+(defcustom gnus-uu-ignore-files-by-type nil
+  "*A regular expression saying what files that shouldn't be viewed, based on MIME file type.
+If, for instance, you want gnus-uu to ignore all audio files and all mpegs,
+you could say something like
+
+  (setq gnus-uu-ignore-files-by-type \"audio/\\\\|video/mpeg\")
+
+Note that this variable can be used in conjunction with the
+`gnus-uu-ignore-files-by-name' variable."
+  :group 'gnus-extract
+  :type '(choice (const :tag "off" nil)
+                (regexp :format "%v")))
+
+;; Pseudo-MIME support
+
+(defconst gnus-uu-ext-to-mime-list
+  '(("\\.gif$" "image/gif")
+    ("\\.jpe?g$" "image/jpeg")
+    ("\\.tiff?$" "image/tiff")
+    ("\\.xwd$" "image/xwd")
+    ("\\.pbm$" "image/pbm")
+    ("\\.pgm$" "image/pgm")
+    ("\\.ppm$" "image/ppm")
+    ("\\.xbm$" "image/xbm")
+    ("\\.pcx$" "image/pcx")
+    ("\\.tga$" "image/tga")
+    ("\\.ps$" "image/postscript")
+    ("\\.fli$" "video/fli")
+    ("\\.wav$" "audio/wav")
+    ("\\.aiff$" "audio/aiff")
+    ("\\.hcom$" "audio/hcom")
+    ("\\.voc$" "audio/voc")
+    ("\\.smp$" "audio/smp")
+    ("\\.mod$" "audio/mod")
+    ("\\.dvi$" "image/dvi")
+    ("\\.mpe?g$" "video/mpeg")
+    ("\\.au$" "audio/basic")
+    ("\\.\\(te?xt\\|doc\\|c\\|h\\)$" "text/plain")
+    ("\\.\\(c\\|h\\)$" "text/source")
+    ("read.*me" "text/plain")
+    ("\\.html$" "text/html")
+    ("\\.bat$" "text/bat")
+    ("\\.[1-6]$" "text/man")
+    ("\\.flc$" "video/flc")
+    ("\\.rle$" "video/rle")
+    ("\\.pfx$" "video/pfx")
+    ("\\.avi$" "video/avi")
+    ("\\.sme$" "video/sme")
+    ("\\.rpza$" "video/prza")
+    ("\\.dl$" "video/dl")
+    ("\\.qt$" "video/qt")
+    ("\\.rsrc$" "video/rsrc")
+    ("\\..*$" "unknown/unknown")))
+
+;; Various variables users may set
+
+(defcustom gnus-uu-tmp-dir
+  (cond ((fboundp 'temp-directory) (temp-directory))
+       ((boundp 'temporary-file-directory) temporary-file-directory)
+       ("/tmp/"))
+  "*Variable saying where gnus-uu is to do its work.
+Default is \"/tmp/\"."
+  :group 'gnus-extract
+  :type 'directory)
+
+(defcustom gnus-uu-do-not-unpack-archives nil
+  "*Non-nil means that gnus-uu won't peek inside archives looking for files to display.
+Default is nil."
+  :group 'gnus-extract-archive
+  :type 'boolean)
+
+(defcustom gnus-uu-ignore-default-view-rules nil
+  "*Non-nil means that gnus-uu will ignore the default viewing rules.
+Only the user viewing rules will be consulted.  Default is nil."
+  :group 'gnus-extract-view
+  :type 'boolean)
+
+(defcustom gnus-uu-grabbed-file-functions nil
+  "Functions run on each file after successful decoding.
+They will be called with the name of the file as the argument.
+Likely functions you can use in this list are `gnus-uu-grab-view'
+and `gnus-uu-grab-move'."
+  :group 'gnus-extract
+  :options '(gnus-uu-grab-view gnus-uu-grab-move)
+  :type 'hook)
+
+(defcustom gnus-uu-ignore-default-archive-rules nil
+  "*Non-nil means that gnus-uu will ignore the default archive unpacking commands.
+Only the user unpacking commands will be consulted.  Default is nil."
+  :group 'gnus-extract-archive
+  :type 'boolean)
+
+(defcustom gnus-uu-kill-carriage-return t
+  "*Non-nil means that gnus-uu will strip all carriage returns from articles.
+Default is t."
+  :group 'gnus-extract
+  :type 'boolean)
+
+(defcustom gnus-uu-view-with-metamail nil
+  "*Non-nil means that files will be viewed with metamail.
+The gnus-uu viewing functions will be ignored and gnus-uu will try
+to guess at a content-type based on file name suffixes.  Default
+it nil."
+  :group 'gnus-extract
+  :type 'boolean)
+
+(defcustom gnus-uu-unmark-articles-not-decoded nil
+  "*Non-nil means that gnus-uu will mark articles that were unsuccessfully decoded as unread.
+Default is nil."
+  :group 'gnus-extract
+  :type 'boolean)
+
+(defcustom gnus-uu-correct-stripped-uucode nil
+  "*Non-nil means that gnus-uu will *try* to fix uuencoded files that have had trailing spaces deleted.
+Default is nil."
+  :group 'gnus-extract
+  :type 'boolean)
+
+(defcustom gnus-uu-save-in-digest nil
+  "*Non-nil means that gnus-uu, when asked to save without decoding, will save in digests.
+If this variable is nil, gnus-uu will just save everything in a
+file without any embellishments.  The digesting almost conforms to RFC1153 -
+no easy way to specify any meaningful volume and issue numbers were found,
+so I simply dropped them."
+  :group 'gnus-extract
+  :type 'boolean)
+
+(defcustom gnus-uu-pre-uudecode-hook nil
+  "Hook run before sending a message to uudecode."
+  :group 'gnus-extract
+  :type 'hook)
+
+(defcustom gnus-uu-digest-headers
+  '("^Date:" "^From:" "^To:" "^Cc:" "^Subject:" "^Message-ID:" "^Keywords:"
+    "^Summary:" "^References:" "^Content-Type:" "^Content-Transfer-Encoding:"
+    "^MIME-Version:" "^Content-Disposition:" "^Content-Description:"
+    "^Content-ID:")
+  "*List of regexps to match headers included in digested messages.
+The headers will be included in the sequence they are matched.  If nil
+include all headers."
+  :group 'gnus-extract
+  :type '(repeat regexp))
+
+(defcustom gnus-uu-save-separate-articles nil
+  "*Non-nil means that gnus-uu will save articles in separate files."
+  :group 'gnus-extract
+  :type 'boolean)
+
+(defcustom gnus-uu-be-dangerous 'ask
+  "*Specifies what to do if unusual situations arise during decoding.
+If nil, be as conservative as possible.  If t, ignore things that
+didn't work, and overwrite existing files.  Otherwise, ask each time."
+  :group 'gnus-extract
+  :type '(choice (const :tag "conservative" nil)
+                (const :tag "ask" ask)
+                (const :tag "liberal" t)))
+
+;; Internal variables
+
+(defvar gnus-uu-saved-article-name nil)
+
+(defvar gnus-uu-begin-string "^begin[ \t]+0?[0-7][0-7][0-7][ \t]+\\(.*\\)$")
+(defvar gnus-uu-end-string "^end[ \t]*$")
+
+(defvar gnus-uu-body-line "^M")
+(let ((i 61))
+  (while (> (setq i (1- i)) 0)
+    (setq gnus-uu-body-line (concat gnus-uu-body-line "[^a-z]")))
+  (setq gnus-uu-body-line (concat gnus-uu-body-line ".?$")))
+
+;"^M.............................................................?$"
+
+(defvar gnus-uu-shar-begin-string "^#! */bin/sh")
+
+(defvar gnus-uu-shar-name-marker
+  "begin 0?[0-7][0-7][0-7][ \t]+\\(\\(\\w\\|[.\\:]\\)*\\b\\)")
+
+(defvar gnus-uu-postscript-begin-string "^%!PS-")
+(defvar gnus-uu-postscript-end-string "^%%EOF$")
+
+(defvar gnus-uu-file-name nil)
+(defvar gnus-uu-uudecode-process nil)
+(defvar gnus-uu-binhex-article-name nil)
+(defvar gnus-uu-yenc-article-name nil)
+
+(defvar gnus-uu-work-dir nil)
+
+(defvar gnus-uu-output-buffer-name " *Gnus UU Output*")
+
+(defvar gnus-uu-default-dir gnus-article-save-directory)
+(defvar gnus-uu-digest-from-subject nil)
+(defvar gnus-uu-digest-buffer nil)
+
+;; Commands.
+
+(defun gnus-uu-decode-uu (&optional n)
+  "Uudecodes the current article."
+  (interactive "P")
+  (gnus-uu-decode-with-method 'gnus-uu-uustrip-article n))
+
+(defun gnus-uu-decode-uu-and-save (n dir)
+  "Decodes and saves the resulting file."
+  (interactive
+   (list current-prefix-arg
+        (file-name-as-directory
+         (read-directory-name "Uudecode and save in dir: "
+                         gnus-uu-default-dir
+                         gnus-uu-default-dir t))))
+  (gnus-uu-decode-with-method 'gnus-uu-uustrip-article n dir nil nil t))
+
+(defun gnus-uu-decode-unshar (&optional n)
+  "Unshars the current article."
+  (interactive "P")
+  (gnus-uu-decode-with-method 'gnus-uu-unshar-article n nil nil 'scan t))
+
+(defun gnus-uu-decode-unshar-and-save (n dir)
+  "Unshars and saves the current article."
+  (interactive
+   (list current-prefix-arg
+        (file-name-as-directory
+         (read-directory-name "Unshar and save in dir: "
+                         gnus-uu-default-dir
+                         gnus-uu-default-dir t))))
+  (gnus-uu-decode-with-method 'gnus-uu-unshar-article n dir nil 'scan t))
+
+(defun gnus-uu-decode-save (n file)
+  "Saves the current article."
+  (interactive
+   (list current-prefix-arg
+        (if gnus-uu-save-separate-articles
+            (read-directory-name
+             "Save articles in dir: " gnus-uu-default-dir gnus-uu-default-dir)
+          (read-file-name
+           "Save article in file: " gnus-uu-default-dir gnus-uu-default-dir))))
+  (setq gnus-uu-saved-article-name file)
+  (gnus-uu-decode-with-method 'gnus-uu-save-article n nil t))
+
+(defun gnus-uu-decode-binhex (n dir)
+  "Unbinhexes the current article."
+  (interactive
+   (list current-prefix-arg
+        (file-name-as-directory
+         (read-directory-name "Unbinhex and save in dir: "
+                         gnus-uu-default-dir
+                         gnus-uu-default-dir))))
+  (gnus-uu-initialize)
+  (setq gnus-uu-binhex-article-name
+       (mm-make-temp-file (expand-file-name "binhex" gnus-uu-work-dir)))
+  (gnus-uu-decode-with-method 'gnus-uu-binhex-article n dir))
+
+(defun gnus-uu-decode-yenc (n dir)
+  "Decode the yEnc-encoded current article."
+  (interactive
+   (list current-prefix-arg
+        (file-name-as-directory
+         (read-directory-name "yEnc decode and save in dir: "
+                         gnus-uu-default-dir
+                         gnus-uu-default-dir))))
+  (setq gnus-uu-yenc-article-name nil)
+  (gnus-uu-decode-with-method 'gnus-uu-yenc-article n dir nil t))
+
+(defun gnus-uu-decode-uu-view (&optional n)
+  "Uudecodes and views the current article."
+  (interactive "P")
+  (let ((gnus-view-pseudos (or gnus-view-pseudos 'automatic)))
+    (gnus-uu-decode-uu n)))
+
+(defun gnus-uu-decode-uu-and-save-view (n dir)
+  "Decodes, views and saves the resulting file."
+  (interactive
+   (list current-prefix-arg
+        (read-file-name "Uudecode, view and save in dir: "
+                        gnus-uu-default-dir
+                        gnus-uu-default-dir t)))
+  (let ((gnus-view-pseudos (or gnus-view-pseudos 'automatic)))
+    (gnus-uu-decode-uu-and-save n dir)))
+
+(defun gnus-uu-decode-unshar-view (&optional n)
+  "Unshars and views the current article."
+  (interactive "P")
+  (let ((gnus-view-pseudos (or gnus-view-pseudos 'automatic)))
+    (gnus-uu-decode-unshar n)))
+
+(defun gnus-uu-decode-unshar-and-save-view (n dir)
+  "Unshars and saves the current article."
+  (interactive
+   (list current-prefix-arg
+        (read-file-name "Unshar, view and save in dir: "
+                        gnus-uu-default-dir
+                        gnus-uu-default-dir t)))
+  (let ((gnus-view-pseudos (or gnus-view-pseudos 'automatic)))
+    (gnus-uu-decode-unshar-and-save n dir)))
+
+(defun gnus-uu-decode-save-view (n file)
+  "Saves and views the current article."
+  (interactive
+   (list current-prefix-arg
+        (if gnus-uu-save-separate-articles
+            (read-directory-name "Save articles in dir: "
+                                 gnus-uu-default-dir gnus-uu-default-dir)
+          (read-file-name "Save articles in file: "
+                          gnus-uu-default-dir gnus-uu-default-dir))))
+  (let ((gnus-view-pseudos (or gnus-view-pseudos 'automatic)))
+    (gnus-uu-decode-save n file)))
+
+(defun gnus-uu-decode-binhex-view (n file)
+  "Unbinhexes and views the current article."
+  (interactive
+   (list current-prefix-arg
+        (read-file-name "Unbinhex, view and save in dir: "
+                        gnus-uu-default-dir gnus-uu-default-dir)))
+  (gnus-uu-initialize)
+  (setq gnus-uu-binhex-article-name
+       (mm-make-temp-file (expand-file-name "binhex" gnus-uu-work-dir)))
+  (let ((gnus-view-pseudos (or gnus-view-pseudos 'automatic)))
+    (gnus-uu-decode-binhex n file)))
+
+
+;; Digest and forward articles
+
+(defun gnus-uu-digest-mail-forward (&optional n post)
+  "Digests and forwards all articles in this series."
+  (interactive "P")
+  (gnus-uu-initialize)
+  (let ((gnus-uu-save-in-digest t)
+       (file (mm-make-temp-file (nnheader-concat gnus-uu-work-dir "forward")))
+       (message-forward-as-mime message-forward-as-mime)
+       (mail-parse-charset gnus-newsgroup-charset)
+       (mail-parse-ignored-charsets gnus-newsgroup-ignored-charsets)
+       gnus-uu-digest-buffer subject from)
+    (if (and n (not (numberp n)))
+       (setq message-forward-as-mime (not message-forward-as-mime)
+             n nil))
+    (let ((gnus-article-reply (gnus-summary-work-articles n)))
+      (when (and (not n)
+                (= (length gnus-article-reply) 1))
+       ;; The case where neither a number of articles nor a region is
+       ;; specified.
+       (gnus-summary-top-thread)
+       (setq gnus-article-reply (nreverse (gnus-uu-find-articles-matching))))
+      (gnus-setup-message 'forward
+       (setq gnus-uu-digest-from-subject nil)
+       (setq gnus-uu-digest-buffer
+             (gnus-get-buffer-create " *gnus-uu-forward*"))
+       ;; Specify articles to be forwarded.  Note that they should be
+       ;; reversed; see `gnus-uu-get-list-of-articles'.
+       (let ((gnus-newsgroup-processable (reverse gnus-article-reply)))
+         (gnus-uu-decode-save n file)
+         (setq gnus-article-reply gnus-newsgroup-processable))
+       ;; Restore the value of `gnus-newsgroup-processable' to which
+       ;; it should be set when it is not `let'-bound.
+       (setq gnus-newsgroup-processable (reverse gnus-article-reply))
+       (switch-to-buffer gnus-uu-digest-buffer)
+       (let ((fs gnus-uu-digest-from-subject))
+         (when fs
+           (setq from (caar fs)
+                 subject (gnus-simplify-subject-fuzzy (cdar fs))
+                 fs (cdr fs))
+           (while (and fs (or from subject))
+             (when from
+               (unless (string= from (caar fs))
+                 (setq from nil)))
+             (when subject
+               (unless (string= (gnus-simplify-subject-fuzzy (cdar fs))
+                                subject)
+                 (setq subject nil)))
+             (setq fs (cdr fs))))
+         (unless subject
+           (setq subject "Digested Articles"))
+         (unless from
+           (setq from
+                 (if (gnus-news-group-p gnus-newsgroup-name)
+                     gnus-newsgroup-name
+                   "Various"))))
+       (goto-char (point-min))
+       (when (re-search-forward "^Subject: ")
+         (delete-region (point) (point-at-eol))
+         (insert subject))
+       (goto-char (point-min))
+       (when (re-search-forward "^From:")
+         (delete-region (point) (point-at-eol))
+         (insert " " from))
+       (let ((message-forward-decoded-p t))
+         (message-forward post t))))
+    (setq gnus-uu-digest-from-subject nil)))
+
+(defun gnus-uu-digest-post-forward (&optional n)
+  "Digest and forward to a newsgroup."
+  (interactive "P")
+  (gnus-uu-digest-mail-forward n t))
+
+;; Process marking.
+
+(defun gnus-message-process-mark (unmarkp new-marked)
+  (let ((old (- (length gnus-newsgroup-processable) (length new-marked))))
+    (gnus-message 6 "%d mark%s %s%s"
+                 (length new-marked)
+                 (if (= (length new-marked) 1) "" "s")
+                 (if unmarkp "removed" "added")
+                 (cond
+                  ((and (zerop old)
+                        (not unmarkp))
+                   "")
+                  (unmarkp
+                   (format ", %d remain marked"
+                           (length gnus-newsgroup-processable)))
+                  (t
+                   (format ", %d already marked" old))))))
+
+(defun gnus-new-processable (unmarkp articles)
+  (if unmarkp
+      (gnus-intersection gnus-newsgroup-processable articles)
+    (gnus-set-difference articles gnus-newsgroup-processable)))
+
+(defun gnus-uu-mark-by-regexp (regexp &optional unmark)
+  "Set the process mark on articles whose subjects match REGEXP.
+When called interactively, prompt for REGEXP.
+Optional UNMARK non-nil means unmark instead of mark."
+  (interactive "sMark (regexp): \nP")
+  (save-excursion
+    (let* ((articles (gnus-uu-find-articles-matching regexp))
+          (new-marked (gnus-new-processable unmark articles)))
+      (while articles
+       (if unmark
+           (gnus-summary-remove-process-mark (pop articles))
+         (gnus-summary-set-process-mark (pop articles))))
+      (gnus-message-process-mark unmark new-marked)))
+  (gnus-summary-position-point))
+
+(defun gnus-uu-unmark-by-regexp (regexp)
+  "Remove the process mark from articles whose subjects match REGEXP.
+When called interactively, prompt for REGEXP."
+  (interactive "sUnmark (regexp): ")
+  (gnus-uu-mark-by-regexp regexp t))
+
+(defun gnus-uu-mark-series (&optional silent)
+  "Mark the current series with the process mark."
+  (interactive)
+  (let* ((articles (gnus-uu-find-articles-matching))
+        (l (length articles)))
+    (while articles
+      (gnus-summary-set-process-mark (car articles))
+      (setq articles (cdr articles)))
+    (unless silent
+      (gnus-message 6 "Marked %d articles" l))
+    (gnus-summary-position-point)
+    l))
+
+(defun gnus-uu-mark-region (beg end &optional unmark)
+  "Set the process mark on all articles between point and mark."
+  (interactive "r")
+  (save-excursion
+    (goto-char beg)
+    (while (< (point) end)
+      (if unmark
+         (gnus-summary-remove-process-mark (gnus-summary-article-number))
+       (gnus-summary-set-process-mark (gnus-summary-article-number)))
+      (forward-line 1)))
+  (gnus-summary-position-point))
+
+(defun gnus-uu-unmark-region (beg end)
+  "Remove the process mark from all articles between point and mark."
+  (interactive "r")
+  (gnus-uu-mark-region beg end t))
+
+(defun gnus-uu-mark-buffer ()
+  "Set the process mark on all articles in the buffer."
+  (interactive)
+  (gnus-uu-mark-region (point-min) (point-max)))
+
+(defun gnus-uu-unmark-buffer ()
+  "Remove the process mark on all articles in the buffer."
+  (interactive)
+  (gnus-uu-mark-region (point-min) (point-max) t))
+
+(defun gnus-uu-mark-thread ()
+  "Marks all articles downwards in this thread."
+  (interactive)
+  (gnus-save-hidden-threads
+    (let ((level (gnus-summary-thread-level)))
+      (while (and (gnus-summary-set-process-mark
+                  (gnus-summary-article-number))
+                 (zerop (forward-line 1))
+                 (> (gnus-summary-thread-level) level)))))
+  (gnus-summary-position-point))
+
+(defun gnus-uu-unmark-thread ()
+  "Unmarks all articles downwards in this thread."
+  (interactive)
+  (let ((level (gnus-summary-thread-level)))
+    (while (and (gnus-summary-remove-process-mark
+                (gnus-summary-article-number))
+               (zerop (forward-line 1))
+               (> (gnus-summary-thread-level) level))))
+  (gnus-summary-position-point))
+
+(defun gnus-uu-invert-processable ()
+  "Invert the list of process-marked articles."
+  (interactive)
+  (let ((data gnus-newsgroup-data)
+       number)
+    (save-excursion
+      (while data
+       (if (memq (setq number (gnus-data-number (pop data)))
+                 gnus-newsgroup-processable)
+           (gnus-summary-remove-process-mark number)
+         (gnus-summary-set-process-mark number)))))
+  (gnus-summary-position-point))
+
+(defun gnus-uu-mark-over (&optional score)
+  "Mark all articles with a score over SCORE (the prefix)."
+  (interactive "P")
+  (let ((score (or score gnus-summary-default-score 0))
+       (data gnus-newsgroup-data))
+    (save-excursion
+      (while data
+       (when (> (or (cdr (assq (gnus-data-number (car data))
+                               gnus-newsgroup-scored))
+                    gnus-summary-default-score 0)
+                score)
+         (gnus-summary-set-process-mark (caar data)))
+       (setq data (cdr data))))
+    (gnus-summary-position-point)))
+
+(defun gnus-uu-mark-sparse ()
+  "Mark all series that have some articles marked."
+  (interactive)
+  (let ((marked (nreverse gnus-newsgroup-processable))
+       subject articles total headers)
+    (unless marked
+      (error "No articles marked with the process mark"))
+    (setq gnus-newsgroup-processable nil)
+    (save-excursion
+      (while marked
+       (and (vectorp (setq headers
+                           (gnus-summary-article-header (car marked))))
+            (setq subject (mail-header-subject headers)
+                  articles (gnus-uu-find-articles-matching
+                            (gnus-uu-reginize-string subject))
+                  total (nconc total articles)))
+       (while articles
+         (gnus-summary-set-process-mark (car articles))
+         (setcdr marked (delq (car articles) (cdr marked)))
+         (setq articles (cdr articles)))
+       (setq marked (cdr marked)))
+      (setq gnus-newsgroup-processable (nreverse total)))
+    (gnus-summary-position-point)))
+
+(defun gnus-uu-mark-all ()
+  "Mark all articles in \"series\" order."
+  (interactive)
+  (setq gnus-newsgroup-processable nil)
+  (save-excursion
+    (let ((data gnus-newsgroup-data)
+         (count 0)
+         number)
+      (while data
+       (when (and (not (memq (setq number (gnus-data-number (car data)))
+                             gnus-newsgroup-processable))
+                  (vectorp (gnus-data-header (car data))))
+         (gnus-summary-goto-subject number)
+         (setq count (+ count (gnus-uu-mark-series t))))
+       (setq data (cdr data)))
+      (gnus-message 6 "Marked %d articles" count)))
+  (gnus-summary-position-point))
+
+;; All PostScript functions written by Erik Selberg <speed@cs.washington.edu>.
+
+(defun gnus-uu-decode-postscript (&optional n)
+  "Gets PostScript of the current article."
+  (interactive "P")
+  (gnus-uu-decode-with-method 'gnus-uu-decode-postscript-article n))
+
+(defun gnus-uu-decode-postscript-view (&optional n)
+  "Gets and views the current article."
+  (interactive "P")
+  (let ((gnus-view-pseudos (or gnus-view-pseudos 'automatic)))
+    (gnus-uu-decode-postscript n)))
+
+(defun gnus-uu-decode-postscript-and-save (n dir)
+  "Extracts PostScript and saves the current article."
+  (interactive
+   (list current-prefix-arg
+        (file-name-as-directory
+         (read-directory-name "Save in dir: "
+                         gnus-uu-default-dir
+                         gnus-uu-default-dir t))))
+  (gnus-uu-decode-with-method 'gnus-uu-decode-postscript-article
+                             n dir nil nil t))
+
+(defun gnus-uu-decode-postscript-and-save-view (n dir)
+  "Decodes, views and saves the resulting file."
+  (interactive
+   (list current-prefix-arg
+        (read-file-name "Where do you want to save the file(s)? "
+                        gnus-uu-default-dir
+                        gnus-uu-default-dir t)))
+  (let ((gnus-view-pseudos (or gnus-view-pseudos 'automatic)))
+    (gnus-uu-decode-postscript-and-save n dir)))
+
+
+;; Internal functions.
+
+(defun gnus-uu-decode-with-method (method n &optional save not-insert
+                                         scan cdir)
+  (gnus-uu-initialize scan)
+  (when save
+    (setq gnus-uu-default-dir save))
+  ;; Create the directory we save to.
+  (when (and scan cdir save
+            (not (file-exists-p save)))
+    (make-directory save t))
+  (let ((articles (gnus-uu-get-list-of-articles n))
+       files)
+    (setq files (gnus-uu-grab-articles articles method t))
+    (let ((gnus-current-article (car articles)))
+      (when scan
+       (setq files (gnus-uu-scan-directory gnus-uu-work-dir))))
+    (when save
+      (gnus-uu-save-files files save))
+    (when (eq gnus-uu-do-not-unpack-archives nil)
+      (setq files (gnus-uu-unpack-files files)))
+    (setq files (nreverse (gnus-uu-get-actions files)))
+    (or not-insert (not gnus-insert-pseudo-articles)
+       (gnus-summary-insert-pseudos files save))))
+
+(defun gnus-uu-scan-directory (dir &optional rec)
+  "Return a list of all files under DIR."
+  (let ((files (directory-files dir t))
+       out file)
+    (while (setq file (pop files))
+      (unless (member (file-name-nondirectory file) '("." ".."))
+       (push (list (cons 'name file)
+                   (cons 'article gnus-current-article))
+             out)
+       (when (file-directory-p file)
+         (setq out (nconc (gnus-uu-scan-directory file t) out)))))
+    (if rec
+       out
+      (nreverse out))))
+
+(defun gnus-uu-save-files (files dir)
+  "Save FILES in DIR."
+  (let ((len (length files))
+       (reg (concat "^" (regexp-quote gnus-uu-work-dir)))
+       to-file file fromdir)
+    (while (setq file (cdr (assq 'name (pop files))))
+      (when (file-exists-p file)
+       (string-match reg file)
+       (setq fromdir (substring file (match-end 0)))
+       (if (file-directory-p file)
+           (gnus-make-directory (concat dir fromdir))
+         (setq to-file (concat dir fromdir))
+         (when (or (not (file-exists-p to-file))
+                   (eq gnus-uu-be-dangerous t)
+                   (and gnus-uu-be-dangerous
+                        (gnus-y-or-n-p (format "%s exists; overwrite? "
+                                               to-file))))
+           (copy-file file to-file t t)))))
+    (gnus-message 5 "Saved %d file%s" len (if (= len 1) "" "s"))))
+
+;; Functions for saving and possibly digesting articles without
+;; any decoding.
+
+;; Function called by gnus-uu-grab-articles to treat each article.
+(defun gnus-uu-save-article (buffer in-state)
+  (cond
+   (gnus-uu-save-separate-articles
+    (with-current-buffer buffer
+      (let ((coding-system-for-write mm-text-coding-system))
+       (gnus-write-buffer
+        (concat gnus-uu-saved-article-name gnus-current-article)))
+      (cond ((eq in-state 'first) (list gnus-uu-saved-article-name 'begin))
+           ((eq in-state 'first-and-last) (list gnus-uu-saved-article-name
+                                                'begin 'end))
+           ((eq in-state 'last) (list 'end))
+           (t (list 'middle)))))
+   ((not gnus-uu-save-in-digest)
+    (with-current-buffer buffer
+      (write-region (point-min) (point-max) gnus-uu-saved-article-name t)
+      (cond ((eq in-state 'first) (list gnus-uu-saved-article-name 'begin))
+           ((eq in-state 'first-and-last) (list gnus-uu-saved-article-name
+                                                'begin 'end))
+           ((eq in-state 'last) (list 'end))
+           (t (list 'middle)))))
+   (t
+    (let ((header (gnus-summary-article-header)))
+      (push (cons (mail-header-from header)
+                 (mail-header-subject header))
+           gnus-uu-digest-from-subject))
+    (let ((name (file-name-nondirectory gnus-uu-saved-article-name))
+         beg subj headers headline sorthead body end-string state)
+      (if (or (eq in-state 'first)
+             (eq in-state 'first-and-last))
+         (progn
+           (setq state (list 'begin))
+           (with-current-buffer (gnus-get-buffer-create "*gnus-uu-body*")
+             (erase-buffer))
+           (with-current-buffer (gnus-get-buffer-create "*gnus-uu-pre*")
+             (erase-buffer)
+             (insert (format
+                      "Date: %s\nFrom: %s\nSubject: %s Digest\n\n"
+                      (message-make-date) name name))
+             (when (and message-forward-as-mime gnus-uu-digest-buffer)
+               (insert
+                "<#mml type=message/rfc822>\nSubject: Topics\n\n<#/mml>\n")
+               (forward-line -1))
+             (insert "Topics:\n")))
+       (when (not (eq in-state 'end))
+         (setq state (list 'middle))))
+      (with-current-buffer "*gnus-uu-body*"
+       (goto-char (setq beg (point-max)))
+       (with-current-buffer buffer
+         (save-restriction
+           (let ((inhibit-read-only t))
+             (set-text-properties (point-min) (point-max) nil)
+             ;; These two are necessary for XEmacs 19.12 fascism.
+             (put-text-property (point-min) (point-max) 'invisible nil)
+             (put-text-property (point-min) (point-max) 'intangible nil))
+           (when (and message-forward-as-mime
+                      message-forward-show-mml
+                      gnus-uu-digest-buffer)
+             (mm-enable-multibyte)
+             (mime-to-mml))
+           (goto-char (point-min))
+           (search-forward "\n\n")
+           (unless (and message-forward-as-mime gnus-uu-digest-buffer)
+             ;; Quote all 30-dash lines.
+             (save-excursion
+               (while (re-search-forward "^-" nil t)
+                 (beginning-of-line)
+                 (delete-char 1)
+                 (insert "- "))))
+           (setq body (buffer-substring (1- (point)) (point-max)))
+           (narrow-to-region (point-min) (point))
+           (if (not (setq headers gnus-uu-digest-headers))
+               (setq sorthead (buffer-string))
+             (while headers
+               (setq headline (car headers))
+               (setq headers (cdr headers))
+               (goto-char (point-min))
+               (while (re-search-forward headline nil t)
+                 (setq sorthead
+                       (concat sorthead
+                               (buffer-substring
+                                (match-beginning 0)
+                                (or (and (re-search-forward "^[^ \t]" nil t)
+                                         (1- (point)))
+                                    (progn (forward-line 1) (point)))))))))))
+       (if (and message-forward-as-mime gnus-uu-digest-buffer)
+         (if message-forward-show-mml
+             (progn
+               (insert "\n<#mml type=message/rfc822>\n")
+               (insert sorthead) (goto-char (point-max))
+               (insert body) (goto-char (point-max))
+               (insert "\n<#/mml>\n"))
+           (let ((buf (mml-generate-new-buffer " *mml*")))
+             (with-current-buffer buf
+               (insert sorthead)
+               (goto-char (point-min))
+               (when (re-search-forward "^Subject: \\(.*\\)$" nil t)
+                 (setq subj (buffer-substring (match-beginning 1)
+                                              (match-end 1))))
+               (goto-char (point-max))
+               (insert body))
+             (insert "\n<#part type=message/rfc822"
+                     " buffer=\"" (buffer-name buf) "\">\n")))
+         (insert sorthead) (goto-char (point-max))
+         (insert body) (goto-char (point-max))
+         (insert (concat "\n" (make-string 30 ?-) "\n\n")))
+       (goto-char beg)
+       (when (re-search-forward "^Subject: \\(.*\\)$" nil t)
+         (setq subj (buffer-substring (match-beginning 1) (match-end 1))))
+       (when subj
+         (with-current-buffer "*gnus-uu-pre*"
+           (insert (format "   %s\n" subj)))))
+      (when (or (eq in-state 'last)
+               (eq in-state 'first-and-last))
+       (if (and message-forward-as-mime gnus-uu-digest-buffer)
+           (with-current-buffer gnus-uu-digest-buffer
+             (erase-buffer)
+             (insert-buffer-substring "*gnus-uu-pre*")
+             (goto-char (point-max))
+             (insert-buffer-substring "*gnus-uu-body*"))
+         (with-current-buffer "*gnus-uu-pre*"
+           (insert (format "\n\n%s\n\n" (make-string 70 ?-)))
+           (if gnus-uu-digest-buffer
+               (with-current-buffer gnus-uu-digest-buffer
+                 (erase-buffer)
+                 (insert-buffer-substring "*gnus-uu-pre*"))
+             (let ((coding-system-for-write mm-text-coding-system))
+               (gnus-write-buffer gnus-uu-saved-article-name))))
+         (with-current-buffer "*gnus-uu-body*"
+           (goto-char (point-max))
+           (insert
+            (concat (setq end-string (format "End of %s Digest" name))
+                    "\n"))
+           (insert (concat (make-string (length end-string) ?*) "\n"))
+           (if gnus-uu-digest-buffer
+               (with-current-buffer gnus-uu-digest-buffer
+                 (goto-char (point-max))
+                 (insert-buffer-substring "*gnus-uu-body*"))
+             (let ((coding-system-for-write mm-text-coding-system)
+                   (file-name-coding-system nnmail-pathname-coding-system))
+               (write-region
+                (point-min) (point-max) gnus-uu-saved-article-name t)))))
+       (gnus-kill-buffer "*gnus-uu-pre*")
+       (gnus-kill-buffer "*gnus-uu-body*")
+       (push 'end state))
+      (if (memq 'begin state)
+         (cons gnus-uu-saved-article-name state)
+       state)))))
+
+;; Binhex treatment - not very advanced.
+
+(defvar gnus-uu-binhex-body-line
+  "^[^:]...............................................................$")
+(defvar gnus-uu-binhex-begin-line
+  "^:...............................................................$")
+(defvar gnus-uu-binhex-end-line
+  ":$")
+
+(defun gnus-uu-binhex-article (buffer in-state)
+  (let (state start-char)
+    (with-current-buffer buffer
+      (widen)
+      (goto-char (point-min))
+      (when (not (re-search-forward gnus-uu-binhex-begin-line nil t))
+       (when (not (re-search-forward gnus-uu-binhex-body-line nil t))
+         (setq state (list 'wrong-type))))
+
+      (if (memq 'wrong-type state)
+         ()
+       (beginning-of-line)
+       (setq start-char (point))
+       (if (looking-at gnus-uu-binhex-begin-line)
+           (progn
+             (setq state (list 'begin))
+             (write-region (point-min) (point-min)
+                           gnus-uu-binhex-article-name))
+         (setq state (list 'middle)))
+       (goto-char (point-max))
+       (re-search-backward (concat gnus-uu-binhex-body-line "\\|"
+                                   gnus-uu-binhex-end-line)
+                           nil t)
+       (when (looking-at gnus-uu-binhex-end-line)
+         (setq state (if (memq 'begin state)
+                         (cons 'end state)
+                       (list 'end))))
+       (beginning-of-line)
+       (forward-line 1)
+       (when (file-exists-p gnus-uu-binhex-article-name)
+         (mm-append-to-file start-char (point) gnus-uu-binhex-article-name))))
+    (if (memq 'begin state)
+       (cons gnus-uu-binhex-article-name state)
+      state)))
+
+;; yEnc
+
+(defun gnus-uu-yenc-article (buffer in-state)
+  (with-current-buffer gnus-original-article-buffer
+    (widen)
+    (let ((file-name (yenc-extract-filename))
+         state start-char)
+      (when (not file-name)
+       (setq state (list 'wrong-type)))
+
+      (if (memq 'wrong-type state)
+         ()
+       (when (yenc-first-part-p)
+         (setq gnus-uu-yenc-article-name
+               (expand-file-name file-name gnus-uu-work-dir))
+         (push 'begin state))
+       (when (yenc-last-part-p)
+         (push 'end state))
+       (unless state
+         (push 'middle state))
+       (mm-with-unibyte-buffer
+         (insert-buffer-substring gnus-original-article-buffer)
+         (yenc-decode-region (point-min) (point-max))
+         (when (and (member 'begin state)
+                    (file-exists-p gnus-uu-yenc-article-name))
+           (delete-file gnus-uu-yenc-article-name))
+         (mm-append-to-file (point-min) (point-max)
+                            gnus-uu-yenc-article-name)))
+      (if (memq 'begin state)
+         (cons file-name state)
+       state))))
+
+;; PostScript
+
+(defun gnus-uu-decode-postscript-article (process-buffer in-state)
+  (let ((state (list 'ok))
+       start-char end-char file-name)
+    (with-current-buffer process-buffer
+      (goto-char (point-min))
+      (if (not (re-search-forward gnus-uu-postscript-begin-string nil t))
+         (setq state (list 'wrong-type))
+       (beginning-of-line)
+       (setq start-char (point))
+       (if (not (re-search-forward gnus-uu-postscript-end-string nil t))
+           (setq state (list 'wrong-type))
+         (setq end-char (point))
+         (set-buffer (gnus-get-buffer-create gnus-uu-output-buffer-name))
+         (insert-buffer-substring process-buffer start-char end-char)
+         (setq file-name (concat gnus-uu-work-dir
+                                 (cdr gnus-article-current) ".ps"))
+         (write-region (point-min) (point-max) file-name)
+         (setq state (list file-name 'begin 'end)))))
+    state))
+
+
+;; Find actions.
+
+(defun gnus-uu-get-actions (files)
+  (let ((ofiles files)
+       action name)
+    (while files
+      (setq name (cdr (assq 'name (car files))))
+      (and
+       (setq action (gnus-uu-get-action name))
+       (setcar files (nconc (list (if (string= action "gnus-uu-archive")
+                                     (cons 'action "file")
+                                   (cons 'action action))
+                                 (cons 'execute (gnus-uu-command
+                                                 action name)))
+                           (car files))))
+      (setq files (cdr files)))
+    ofiles))
+
+(defun gnus-uu-get-action (file-name)
+  (let (action)
+    (setq action
+         (gnus-uu-choose-action
+          file-name
+          (append
+           gnus-uu-user-view-rules
+           (if gnus-uu-ignore-default-view-rules
+               nil
+             gnus-uu-default-view-rules)
+           gnus-uu-user-view-rules-end)))
+    (when (and (not (string= (or action "") "gnus-uu-archive"))
+              gnus-uu-view-with-metamail)
+      (when (setq action
+                 (gnus-uu-choose-action file-name gnus-uu-ext-to-mime-list))
+       (setq action (format "metamail -d -b -c \"%s\"" action))))
+    action))
+
+
+;; Functions for treating subjects and collecting series.
+
+(defun gnus-uu-reginize-string (string)
+  ;; Takes a string and puts a \ in front of every special character;
+  ;; replaces the last thing that looks like "2/3" with "[0-9]+/3"
+  ;; or, if it can't find something like that, tries "2 of 3", then
+  ;; finally just replaces the next to last number with "[0-9]+".
+  (with-current-buffer (gnus-get-buffer-create gnus-uu-output-buffer-name)
+    (buffer-disable-undo)
+    (erase-buffer)
+    (insert (regexp-quote string))
+
+    (setq case-fold-search nil)
+
+    (end-of-line)
+    (if (re-search-backward "\\([^0-9]\\)[0-9]+/\\([0-9]+\\)" nil t)
+       (replace-match "\\1[0-9]+/\\2")
+
+      (end-of-line)
+      (if (re-search-backward "\\([^0-9]\\)[0-9]+[ \t]*of[ \t]*\\([0-9]+\\)"
+                             nil t)
+         (replace-match "\\1[0-9]+ of \\2")
+
+       (end-of-line)
+       (if (re-search-backward "\\([^0-9]\\)[0-9]+\\([^0-9]+\\)[0-9]+"
+                               nil t)
+           (replace-match "\\1[0-9]+\\2[0-9]+" t nil nil nil))))
+
+    (goto-char (point-min))
+    (while (re-search-forward "[ \t]+" nil t)
+      (replace-match "[ \t]+" t t))
+
+    (buffer-string)))
+
+(defun gnus-uu-get-list-of-articles (n)
+  ;; If N is non-nil, the article numbers of the N next articles
+  ;; will be returned.
+  ;; If any articles have been marked as processable, they will be
+  ;; returned.
+  ;; Failing that, articles that have subjects that are part of the
+  ;; same "series" as the current will be returned.
+  (let (articles)
+    (cond
+     (n
+      (setq n (prefix-numeric-value n))
+      (let ((backward (< n 0))
+           (n (abs n)))
+       (save-excursion
+         (while (and (> n 0)
+                     (push (gnus-summary-article-number)
+                           articles)
+                     (gnus-summary-search-forward nil nil backward))
+           (setq n (1- n))))
+       (nreverse articles)))
+     (gnus-newsgroup-processable
+      (reverse gnus-newsgroup-processable))
+     (t
+      (gnus-uu-find-articles-matching)))))
+
+(defun gnus-uu-string< (l1 l2)
+  (string< (car l1) (car l2)))
+
+(defun gnus-uu-find-articles-matching
+  (&optional subject only-unread do-not-translate)
+  ;; Finds all articles that matches the regexp SUBJECT.  If it is
+  ;; nil, the current article name will be used.  If ONLY-UNREAD is
+  ;; non-nil, only unread articles are chosen.  If DO-NOT-TRANSLATE is
+  ;; non-nil, article names are not equalized before sorting.
+  (let ((subject (or subject
+                    (gnus-uu-reginize-string (gnus-summary-article-subject))))
+       list-of-subjects)
+    (save-excursion
+      (when subject
+       ;; Collect all subjects matching subject.
+       (let ((case-fold-search t)
+             (data gnus-newsgroup-data)
+             subj mark d)
+         (while data
+           (setq d (pop data))
+           (and (not (gnus-data-pseudo-p d))
+                (or (not only-unread)
+                    (= (setq mark (gnus-data-mark d))
+                       gnus-unread-mark)
+                    (= mark gnus-ticked-mark)
+                    (= mark gnus-dormant-mark))
+                (setq subj (mail-header-subject (gnus-data-header d)))
+                (string-match subject subj)
+                (push (cons subj (gnus-data-number d))
+                      list-of-subjects))))
+
+       ;; Expand numbers, sort, and return the list of article
+       ;; numbers.
+       (mapcar 'cdr
+               (sort (gnus-uu-expand-numbers
+                      list-of-subjects
+                      (not do-not-translate))
+                     'gnus-uu-string<))))))
+
+(defun gnus-uu-expand-numbers (string-list &optional translate)
+  ;; Takes a list of strings and "expands" all numbers in all the
+  ;; strings.  That is, this function makes all numbers equal length by
+  ;; prepending lots of zeroes before each number.  This is to ease later
+  ;; sorting to find out what sequence the articles are supposed to be
+  ;; decoded in.  Returns the list of expanded strings.
+  (let ((out-list string-list)
+       string)
+    (with-current-buffer (gnus-get-buffer-create gnus-uu-output-buffer-name)
+      (buffer-disable-undo)
+      (while string-list
+       (erase-buffer)
+       (insert (caar string-list))
+       ;; Translate multiple spaces to one space.
+       (goto-char (point-min))
+       (while (re-search-forward "[ \t]+" nil t)
+         (replace-match " "))
+       ;; Translate all characters to "a".
+       (goto-char (point-min))
+       (when translate
+         (while (re-search-forward "[A-Za-z]" nil t)
+           (replace-match "a" t t)))
+       ;; Expand numbers.
+       (goto-char (point-min))
+       (while (re-search-forward "[0-9]+" nil t)
+         (ignore-errors
+           (replace-match
+            (format "%06d"
+                    (string-to-number (buffer-substring
+                                    (match-beginning 0) (match-end 0)))))))
+       (setq string (buffer-substring (point-min) (point-max)))
+       (setcar (car string-list) string)
+       (setq string-list (cdr string-list))))
+    out-list))
+
+
+;; `gnus-uu-grab-articles' is the general multi-article treatment
+;; function.  It takes a list of articles to be grabbed and a function
+;; to apply to each article.
+;;
+;; The function to be called should take two parameters.  The first
+;; parameter is the article buffer.  The function should leave the
+;; result, if any, in this buffer.  Most treatment functions will just
+;; generate files...
+;;
+;; The second parameter is the state of the list of articles, and can
+;; have four values: `first', `middle', `last' and `first-and-last'.
+;;
+;; The function should return a list.  The list may contain the
+;; following symbols:
+;; `error' if an error occurred
+;; `begin' if the beginning of an encoded file has been received
+;;   If the list returned contains a `begin', the first element of
+;;   the list *must* be a string with the file name of the decoded
+;;   file.
+;; `end' if the end of an encoded file has been received
+;; `middle' if the article was a body part of an encoded file
+;; `wrong-type' if the article was not a part of an encoded file
+;; `ok', which can be used everything is ok
+
+(defvar gnus-uu-has-been-grabbed nil)
+
+(defun gnus-uu-unmark-list-of-grabbed (&optional dont-unmark-last-article)
+  (let (art)
+    (if (not (and gnus-uu-has-been-grabbed
+                 gnus-uu-unmark-articles-not-decoded))
+       ()
+      (when dont-unmark-last-article
+       (setq art (car gnus-uu-has-been-grabbed))
+       (setq gnus-uu-has-been-grabbed (cdr gnus-uu-has-been-grabbed)))
+      (while gnus-uu-has-been-grabbed
+       (gnus-summary-tick-article (car gnus-uu-has-been-grabbed) t)
+       (setq gnus-uu-has-been-grabbed (cdr gnus-uu-has-been-grabbed)))
+      (when dont-unmark-last-article
+       (setq gnus-uu-has-been-grabbed (list art))))))
+
+;; This function takes a list of articles and a function to apply to
+;; each article grabbed.
+;;
+;; This function returns a list of files decoded if the grabbing and
+;; the process-function has been successful and nil otherwise.
+(defun gnus-uu-grab-articles (articles process-function
+                                      &optional sloppy limit no-errors)
+  (require 'gnus-async)
+  (let ((state 'first)
+       (gnus-asynchronous nil)
+       (gnus-inhibit-treatment t)
+       has-been-begin article result-file result-files process-state
+       gnus-summary-display-article-function
+       gnus-article-prepare-hook gnus-display-mime-function
+       article-series files)
+
+    (while (and articles
+               (not (memq 'error process-state))
+               (or sloppy
+                   (not (memq 'end process-state))))
+
+      (setq article (pop articles))
+      (when (vectorp (gnus-summary-article-header article))
+       (push article article-series)
+
+       (unless articles
+         (if (eq state 'first)
+             (setq state 'first-and-last)
+           (setq state 'last)))
+
+       (let ((part (gnus-uu-part-number article)))
+         (gnus-message 6 "Getting article %d%s..."
+                       article (if (string= part "") "" (concat ", " part))))
+       (gnus-summary-display-article article)
+
+       ;; Push the article to the processing function.
+       (with-current-buffer gnus-original-article-buffer
+         (let ((buffer-read-only nil))
+           (with-current-buffer gnus-summary-buffer
+             (setq process-state
+                   (funcall process-function
+                            gnus-original-article-buffer state)))))
+
+       (gnus-summary-remove-process-mark article)
+
+       ;; If this is the beginning of a decoded file, we push it
+       ;; on to a list.
+       (when (or (memq 'begin process-state)
+                 (and (or (eq state 'first)
+                          (eq state 'first-and-last))
+                      (memq 'ok process-state)))
+         (when has-been-begin
+           ;; If there is a `result-file' here, that means that the
+           ;; file was unsuccessfully decoded, so we delete it.
+           (when (and result-file
+                      (file-exists-p result-file)
+                      (not gnus-uu-be-dangerous)
+                      (or (eq gnus-uu-be-dangerous t)
+                          (gnus-y-or-n-p
+                           (format "Delete unsuccessfully decoded file %s? "
+                                   result-file))))
+             (delete-file result-file)))
+         (when (memq 'begin process-state)
+           (setq result-file (car process-state)))
+         (setq has-been-begin t))
+
+       ;; Check whether we have decoded one complete file.
+       (when (memq 'end process-state)
+         (setq article-series nil)
+         (setq has-been-begin nil)
+         (if (stringp result-file)
+             (setq files (list result-file))
+           (setq files result-file))
+         (setq result-file (car files))
+         (while files
+           (push (list (cons 'name (pop files))
+                       (cons 'article article))
+                 result-files))
+         ;; Allow user-defined functions to be run on this file.
+         (when gnus-uu-grabbed-file-functions
+           (let ((funcs gnus-uu-grabbed-file-functions))
+             (unless (listp funcs)
+               (setq funcs (list funcs)))
+             (while funcs
+               (funcall (pop funcs) result-file))))
+         (setq result-file nil)
+         ;; Check whether we have decoded enough articles.
+         (and limit (= (length result-files) limit)
+              (setq articles nil)))
+
+       ;; If this is the last article to be decoded, and
+       ;; we still haven't reached the end, then we delete
+       ;; the partially decoded file.
+       (and (or (eq state 'last) (eq state 'first-and-last))
+            (not (memq 'end process-state))
+            result-file
+            (file-exists-p result-file)
+            (not gnus-uu-be-dangerous)
+            (or (eq gnus-uu-be-dangerous t)
+                (gnus-y-or-n-p
+                 (format "Delete incomplete file %s? " result-file)))
+            (delete-file result-file))
+
+       ;; If this was a file of the wrong sort, then
+       (when (and (or (memq 'wrong-type process-state)
+                      (memq 'error process-state))
+                  gnus-uu-unmark-articles-not-decoded)
+         (gnus-summary-tick-article article t))
+
+       ;; Set the new series state.
+       (if (and (not has-been-begin)
+                (not sloppy)
+                (or (memq 'end process-state)
+                    (memq 'middle process-state)))
+           (progn
+             (setq process-state (list 'error))
+             (gnus-message 2 "No begin part at the beginning")
+             (sleep-for 2))
+         (setq state 'middle))))
+
+      ;; When there are no result-files, then something must be wrong.
+    (if result-files
+       (message "")
+      (cond
+       ((not has-been-begin)
+       (gnus-message 2 "Wrong type file"))
+       ((memq 'error process-state)
+       (gnus-message 2 "An error occurred during decoding"))
+       ((not (or (memq 'ok process-state)
+                (memq 'end process-state)))
+       (gnus-message 2 "End of articles reached before end of file")))
+      ;; Make unsuccessfully decoded articles unread.
+      (when gnus-uu-unmark-articles-not-decoded
+       (while article-series
+         (gnus-summary-tick-article (pop article-series) t))))
+
+    ;; 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)
+  "View FILE using the gnus-uu methods."
+  (let ((action (gnus-uu-get-action file)))
+    (gnus-execute-command
+     (if (string-match "%" action)
+        (format action file)
+       (concat action " " file))
+     (eq gnus-view-pseudos 'not-confirm))))
+
+(defun gnus-uu-grab-move (file)
+  "Move FILE to somewhere."
+  (when gnus-uu-default-dir
+    (let ((to-file (concat (file-name-as-directory gnus-uu-default-dir)
+                          (file-name-nondirectory file))))
+      (rename-file file to-file)
+      (unless (file-exists-p file)
+       (make-symbolic-link to-file file)))))
+
+(defun gnus-uu-part-number (article)
+  (let* ((header (gnus-summary-article-header article))
+        (subject (and header (mail-header-subject header)))
+        (part nil))
+    (if subject
+       (while (string-match "[0-9]+/[0-9]+\\|[0-9]+[ \t]+of[ \t]+[0-9]+"
+                            subject)
+         (setq part (match-string 0 subject))
+         (setq subject (substring subject (match-end 0)))))
+    (or part
+       (while (string-match "[0-9]+[^0-9]+[0-9]+" subject)
+         (setq part (match-string 0 subject))
+         (setq subject (substring subject (match-end 0)))))
+    (or part "")))
+
+(defun gnus-uu-uudecode-sentinel (process event)
+  (delete-process (get-process process)))
+
+(defun gnus-uu-uustrip-article (process-buffer in-state)
+  ;; Uudecodes a file asynchronously.
+  (with-current-buffer process-buffer
+    (let ((state (list 'wrong-type))
+         process-connection-type case-fold-search buffer-read-only
+         files start-char)
+      (goto-char (point-min))
+
+      ;; Deal with ^M at the end of the lines.
+      (when gnus-uu-kill-carriage-return
+       (save-excursion
+         (while (search-forward "\r" nil t)
+           (delete-char -1))))
+
+      (while (or (re-search-forward gnus-uu-begin-string nil t)
+                (re-search-forward gnus-uu-body-line nil t))
+       (setq state (list 'ok))
+       ;; Ok, we are at the first uucoded line.
+       (beginning-of-line)
+       (setq start-char (point))
+
+       (if (not (looking-at gnus-uu-begin-string))
+           (setq state (list 'middle))
+         ;; This is the beginning of a uuencoded article.
+         ;; We replace certain characters that could make things messy.
+         (setq gnus-uu-file-name
+               (gnus-map-function
+                mm-file-name-rewrite-functions
+                (file-name-nondirectory (match-string 1))))
+         (replace-match (concat "begin 644 " gnus-uu-file-name) t t)
+
+         ;; Remove any non gnus-uu-body-line right after start.
+         (forward-line 1)
+         (while (and (not (eobp))
+                     (not (looking-at gnus-uu-body-line)))
+           (gnus-delete-line))
+
+         ;; If a process is running, we kill it.
+         (when (and gnus-uu-uudecode-process
+                    (memq (process-status gnus-uu-uudecode-process)
+                          '(run stop)))
+           (delete-process gnus-uu-uudecode-process)
+           (gnus-uu-unmark-list-of-grabbed t))
+
+         ;; Start a new uudecoding process.
+         (let ((cdir default-directory))
+           (unwind-protect
+               (progn
+                 (cd gnus-uu-work-dir)
+                 (setq gnus-uu-uudecode-process
+                       (start-process
+                        "*uudecode*"
+                        (gnus-get-buffer-create gnus-uu-output-buffer-name)
+                        shell-file-name shell-command-switch
+                        (format "cd %s %s uudecode" gnus-uu-work-dir
+                                gnus-shell-command-separator))))
+             (cd cdir)))
+         (set-process-sentinel
+          gnus-uu-uudecode-process 'gnus-uu-uudecode-sentinel)
+         (setq state (list 'begin))
+         (push (concat gnus-uu-work-dir gnus-uu-file-name) files))
+
+       ;; We look for the end of the thing to be decoded.
+       (if (re-search-forward gnus-uu-end-string nil t)
+           (push 'end state)
+         (goto-char (point-max))
+         (re-search-backward gnus-uu-body-line nil t))
+
+       (forward-line 1)
+
+       (when gnus-uu-uudecode-process
+         (when (memq (process-status gnus-uu-uudecode-process) '(run stop))
+           ;; Try to correct mishandled uucode.
+           (when gnus-uu-correct-stripped-uucode
+             (gnus-uu-check-correct-stripped-uucode start-char (point)))
+           (gnus-run-hooks 'gnus-uu-pre-uudecode-hook)
+
+           ;; Send the text to the process.
+           (condition-case nil
+               (process-send-region
+                gnus-uu-uudecode-process start-char (point))
+             (error
+              (progn
+                (delete-process gnus-uu-uudecode-process)
+                (gnus-message 2 "gnus-uu: Couldn't uudecode")
+                (setq state (list 'wrong-type)))))
+
+           (if (memq 'end state)
+               (progn
+                 ;; Send an EOF, just in case.
+                 (ignore-errors
+                   (process-send-eof gnus-uu-uudecode-process))
+                 (while (memq (process-status gnus-uu-uudecode-process)
+                              '(open run))
+                   (accept-process-output gnus-uu-uudecode-process 1)))
+             (when (or (not gnus-uu-uudecode-process)
+                       (not (memq (process-status gnus-uu-uudecode-process)
+                                  '(run stop))))
+               (setq state (list 'wrong-type)))))))
+
+      (if (memq 'begin state)
+         (cons (if (= (length files) 1) (car files) files) state)
+       state))))
+
+(defvar gnus-uu-unshar-warning
+  "*** WARNING ***
+
+Shell archives are an archaic method of bundling files for distribution
+across computer networks.  During the unpacking process, arbitrary commands
+are executed on your system, and all kinds of nasty things can happen.
+Please examine the archive very carefully before you instruct Emacs to
+unpack it.  You can browse the archive buffer using \\[scroll-other-window].
+
+If you are unsure what to do, please answer \"no\"."
+  "Text of warning message displayed by `gnus-uu-unshar-article'.
+Make sure that this text consists only of few text lines.  Otherwise,
+Gnus might fail to display all of it.")
+
+
+;; This function is used by `gnus-uu-grab-articles' to treat
+;; a shared article.
+(defun gnus-uu-unshar-article (process-buffer in-state)
+  (let ((state (list 'ok))
+       start-char)
+    (with-current-buffer process-buffer
+      (goto-char (point-min))
+      (if (not (re-search-forward gnus-uu-shar-begin-string nil t))
+         (setq state (list 'wrong-type))
+       (save-window-excursion
+         (save-excursion
+           (switch-to-buffer (current-buffer))
+           (delete-other-windows)
+           (let ((buffer (get-buffer-create (generate-new-buffer-name
+                                             "*Warning*"))))
+             (unless
+                 (unwind-protect
+                     (with-current-buffer buffer
+                       (insert (substitute-command-keys
+                                gnus-uu-unshar-warning))
+                       (goto-char (point-min))
+                       (display-buffer buffer)
+                       (yes-or-no-p "This is a shell archive, unshar it? "))
+                   (kill-buffer buffer))
+               (setq state (list 'error))))))
+       (unless (memq 'error state)
+         (beginning-of-line)
+         (setq start-char (point))
+         (call-process-region
+          start-char (point-max) shell-file-name nil
+          (gnus-get-buffer-create gnus-uu-output-buffer-name) nil
+          shell-command-switch
+          (concat "cd " gnus-uu-work-dir " "
+                  gnus-shell-command-separator  " sh")))))
+    state))
+
+;; `gnus-uu-choose-action' chooses what action to perform given the name
+;; and `gnus-uu-file-action-list'.  Returns either nil if no action is
+;; found, or the name of the command to run if such a rule is found.
+(defun gnus-uu-choose-action (file-name file-action-list &optional no-ignore)
+  (let ((action-list (copy-sequence file-action-list))
+       (case-fold-search t)
+       rule action)
+    (and
+     (unless no-ignore
+       (and (not
+            (and gnus-uu-ignore-files-by-name
+                 (string-match gnus-uu-ignore-files-by-name file-name)))
+           (not
+            (and gnus-uu-ignore-files-by-type
+                 (string-match gnus-uu-ignore-files-by-type
+                               (or (gnus-uu-choose-action
+                                    file-name gnus-uu-ext-to-mime-list t)
+                                   ""))))))
+     (while (not (or (eq action-list ()) action))
+       (setq rule (car action-list))
+       (setq action-list (cdr action-list))
+       (when (string-match (car rule) file-name)
+        (setq action (cadr rule)))))
+    action))
+
+(defun gnus-uu-treat-archive (file-path)
+  ;; Unpacks an archive.  Returns t if unpacking is successful.
+  (let ((did-unpack t)
+       action command dir)
+    (setq action (gnus-uu-choose-action
+                 file-path (append gnus-uu-user-archive-rules
+                                   (if gnus-uu-ignore-default-archive-rules
+                                       nil
+                                     gnus-uu-default-archive-rules))))
+
+    (when (not action)
+      (error "No unpackers for the file %s" file-path))
+
+    (string-match "/[^/]*$" file-path)
+    (setq dir (substring file-path 0 (match-beginning 0)))
+
+    (when (member action gnus-uu-destructive-archivers)
+      (copy-file file-path (concat file-path "~") t))
+
+    (setq command (format "cd %s ; %s" dir (gnus-uu-command action file-path)))
+
+    (with-current-buffer (gnus-get-buffer-create gnus-uu-output-buffer-name)
+      (erase-buffer))
+
+    (gnus-message 5 "Unpacking: %s..." (gnus-uu-command action file-path))
+
+    (if (eq 0 (call-process shell-file-name nil
+                          (gnus-get-buffer-create gnus-uu-output-buffer-name)
+                          nil shell-command-switch command))
+       (message "")
+      (gnus-message 2 "Error during unpacking of archive")
+      (setq did-unpack nil))
+
+    (when (member action gnus-uu-destructive-archivers)
+      (rename-file (concat file-path "~") file-path t))
+
+    did-unpack))
+
+(defun gnus-uu-dir-files (dir)
+  (let ((dirs (directory-files dir t "[^/][^\\.][^\\.]?$"))
+       files file)
+    (while dirs
+      (if (file-directory-p (setq file (car dirs)))
+         (setq files (append files (gnus-uu-dir-files file)))
+       (push file files))
+      (setq dirs (cdr dirs)))
+    files))
+
+(defun gnus-uu-unpack-files (files &optional ignore)
+  ;; Go through FILES and look for files to unpack.
+  (let* ((totfiles (gnus-uu-ls-r gnus-uu-work-dir))
+        (ofiles files)
+        file did-unpack)
+    (while files
+      (setq file (cdr (assq 'name (car files))))
+      (when (and (not (member file ignore))
+                (equal (gnus-uu-get-action (file-name-nondirectory file))
+                       "gnus-uu-archive"))
+       (push file did-unpack)
+       (unless (gnus-uu-treat-archive file)
+         (gnus-message 2 "Error during unpacking of %s" file))
+       (let* ((newfiles (gnus-uu-ls-r gnus-uu-work-dir))
+              (nfiles newfiles))
+         (while nfiles
+           (unless (member (car nfiles) totfiles)
+             (push (list (cons 'name (car nfiles))
+                         (cons 'original file))
+                   ofiles))
+           (setq nfiles (cdr nfiles)))
+         (setq totfiles newfiles)))
+      (setq files (cdr files)))
+    (if did-unpack
+       (gnus-uu-unpack-files ofiles (append did-unpack ignore))
+      ofiles)))
+
+(defun gnus-uu-ls-r (dir)
+  (let* ((files (gnus-uu-directory-files dir t))
+        (ofiles files))
+    (while files
+      (when (file-directory-p (car files))
+       (setq ofiles (delete (car files) ofiles))
+       (setq ofiles (append ofiles (gnus-uu-ls-r (car files)))))
+      (setq files (cdr files)))
+    ofiles))
+
+;; Various stuff
+
+(defun gnus-uu-directory-files (dir &optional full)
+  (let (files out file)
+    (setq files (directory-files dir full))
+    (while files
+      (setq file (car files))
+      (setq files (cdr files))
+      (unless (member (file-name-nondirectory file) '("." ".."))
+       (push file out)))
+    (setq out (nreverse out))
+    out))
+
+(defun gnus-uu-check-correct-stripped-uucode (start end)
+  (save-excursion
+    (let (found beg length)
+      (unless gnus-uu-correct-stripped-uucode
+       (goto-char start)
+
+       (if (re-search-forward " \\|`" end t)
+           (progn
+             (goto-char start)
+             (while (not (eobp))
+               (progn
+                 (when (looking-at "\n")
+                   (replace-match ""))
+                 (forward-line 1))))
+
+         (while (not (eobp))
+           (unless (looking-at (concat gnus-uu-begin-string "\\|"
+                                       gnus-uu-end-string))
+             (when (not found)
+               (setq length (- (point-at-eol) (point-at-bol))))
+             (setq found t)
+             (beginning-of-line)
+             (setq beg (point))
+             (end-of-line)
+             (unless (= length (- (point) beg))
+               (insert (make-string (- length (- (point) beg)) ? ))))
+           (forward-line 1)))))))
+
+(defvar gnus-uu-tmp-alist nil)
+
+(defun gnus-uu-initialize (&optional scan)
+  (let (entry)
+    (if (and (not scan)
+            (when (setq entry (assoc gnus-newsgroup-name gnus-uu-tmp-alist))
+              (if (file-exists-p (cdr entry))
+                  (setq gnus-uu-work-dir (cdr entry))
+                (setq gnus-uu-tmp-alist (delq entry gnus-uu-tmp-alist))
+                nil)))
+       t
+      (setq gnus-uu-tmp-dir (file-name-as-directory
+                            (expand-file-name gnus-uu-tmp-dir)))
+      (if (not (file-directory-p gnus-uu-tmp-dir))
+         (error "Temp directory %s doesn't exist" gnus-uu-tmp-dir)
+       (when (not (file-writable-p gnus-uu-tmp-dir))
+         (error "Temp directory %s can't be written to"
+                gnus-uu-tmp-dir)))
+
+      (setq gnus-uu-work-dir
+           (mm-make-temp-file (concat gnus-uu-tmp-dir "gnus") 'dir))
+      (gnus-set-file-modes gnus-uu-work-dir 448)
+      (setq gnus-uu-work-dir (file-name-as-directory gnus-uu-work-dir))
+      (push (cons gnus-newsgroup-name gnus-uu-work-dir)
+           gnus-uu-tmp-alist))))
+
+
+;; Kills the temporary uu buffers, kills any processes, etc.
+(defun gnus-uu-clean-up ()
+  (let (buf)
+    (and gnus-uu-uudecode-process
+        (memq (process-status (or gnus-uu-uudecode-process "nevair"))
+              '(stop run))
+        (delete-process gnus-uu-uudecode-process))
+    (when (setq buf (get-buffer gnus-uu-output-buffer-name))
+      (kill-buffer buf))))
+
+;; Inputs an action and a filename and returns a full command, making sure
+;; that the filename will be treated as a single argument when the shell
+;; executes the command.
+(defun gnus-uu-command (action file)
+  (let ((quoted-file (shell-quote-argument file)))
+    (if (string-match "%s" action)
+       (format action quoted-file)
+      (concat action " " quoted-file))))
+
+(defun gnus-uu-delete-work-dir (&optional dir)
+  "Delete recursively all files and directories under `gnus-uu-work-dir'."
+  (if dir
+      (gnus-message 7 "Deleting directory %s..." dir)
+    (setq dir gnus-uu-work-dir))
+  (when (and dir
+            (file-exists-p dir))
+    (let ((files (directory-files dir t nil t))
+         file)
+      (while (setq file (pop files))
+       (unless (member (file-name-nondirectory file) '("." ".."))
+         (if (file-directory-p file)
+             (gnus-uu-delete-work-dir file)
+           (gnus-message 9 "Deleting file %s..." file)
+            (condition-case err
+                (delete-file file)
+              (error (gnus-message 3 "Deleting file %s failed... %s" file err))))))
+      (condition-case err
+          (delete-directory dir)
+        (error (gnus-message 3 "Deleting directory %s failed... %s" file err))))
+    (gnus-message 7 "")))
+
+;; Initializing
+
+(add-hook 'gnus-summary-prepare-exit-hook 'gnus-uu-clean-up)
+(add-hook 'gnus-summary-prepare-exit-hook 'gnus-uu-delete-work-dir)
+
+\f
+
+;;;
+;;; uuencoded posting
+;;;
+
+;; Any function that is to be used as and encoding method will take two
+;; parameters: PATH-NAME and FILE-NAME.  (E.g. "/home/gaga/spiral.jpg"
+;; and "spiral.jpg", respectively.) The function should return nil if
+;; the encoding wasn't successful.
+(defcustom gnus-uu-post-encode-method 'gnus-uu-post-encode-uuencode
+  "Function used for encoding binary files.
+There are three functions supplied with gnus-uu for encoding files:
+`gnus-uu-post-encode-uuencode', which does straight uuencoding;
+`gnus-uu-post-encode-mime', which encodes with base64 and adds MIME
+headers; and `gnus-uu-post-encode-mime-uuencode', which encodes with
+uuencode and adds MIME headers."
+  :group 'gnus-extract-post
+  :type '(radio (function-item gnus-uu-post-encode-uuencode)
+               (function-item gnus-uu-post-encode-mime)
+               (function-item gnus-uu-post-encode-mime-uuencode)
+               (function :tag "Other")))
+
+(defcustom gnus-uu-post-include-before-composing nil
+  "Non-nil means that gnus-uu will ask for a file to encode before you compose the article.
+If this variable is t, you can either include an encoded file with
+\\[gnus-uu-post-insert-binary-in-article] or have one included for you when you post the article."
+  :group 'gnus-extract-post
+  :type 'boolean)
+
+(defcustom gnus-uu-post-length 990
+  "Maximum length of an article.
+The encoded file will be split into how many articles it takes to
+post the entire file."
+  :group 'gnus-extract-post
+  :type 'integer)
+
+(defcustom gnus-uu-post-threaded nil
+  "Non-nil means that gnus-uu will post the encoded file in a thread.
+This may not be smart, as no other decoder I have seen are able to
+follow threads when collecting uuencoded articles.  (Well, I have seen
+one package that does that - gnus-uu, but somehow, I don't think that
+counts...)  The default is nil."
+  :group 'gnus-extract-post
+  :type 'boolean)
+
+(defcustom gnus-uu-post-separate-description t
+  "Non-nil means that the description will be posted in a separate article.
+The first article will typically be numbered (0/x).  If this variable
+is nil, the description the user enters will be included at the
+beginning of the first article, which will be numbered (1/x).  Default
+is t."
+  :group 'gnus-extract-post
+  :type 'boolean)
+
+(defvar gnus-uu-post-binary-separator "--binary follows this line--")
+(defvar gnus-uu-post-message-id nil)
+(defvar gnus-uu-post-inserted-file-name nil)
+(defvar gnus-uu-winconf-post-news nil)
+
+(defun gnus-uu-post-news ()
+  "Compose an article and post an encoded file."
+  (interactive)
+  (setq gnus-uu-post-inserted-file-name nil)
+  (setq gnus-uu-winconf-post-news (current-window-configuration))
+
+  (gnus-summary-post-news)
+
+  (let ((map (make-sparse-keymap)))
+    (set-keymap-parent map (current-local-map))
+    (use-local-map map))
+  ;;(local-set-key "\C-c\C-c" 'gnus-summary-edit-article-done)
+  (local-set-key "\C-c\C-c" 'gnus-uu-post-news-inews)
+  (local-set-key "\C-c\C-s" 'gnus-uu-post-news-inews)
+  (local-set-key "\C-c\C-i" 'gnus-uu-post-insert-binary-in-article)
+
+  (when gnus-uu-post-include-before-composing
+    (save-excursion (setq gnus-uu-post-inserted-file-name
+                         (gnus-uu-post-insert-binary)))))
+
+(defun gnus-uu-post-insert-binary-in-article ()
+  "Inserts an encoded file in the buffer.
+The user will be asked for a file name."
+  (interactive)
+  (save-excursion
+    (setq gnus-uu-post-inserted-file-name (gnus-uu-post-insert-binary))))
+
+;; Encodes with uuencode and substitutes all spaces with backticks.
+(defun gnus-uu-post-encode-uuencode (path file-name)
+  (when (gnus-uu-post-encode-file "uuencode" path file-name)
+    (goto-char (point-min))
+    (forward-line 1)
+    (while (search-forward " " nil t)
+      (replace-match "`"))
+    t))
+
+;; Encodes with uuencode and adds MIME headers.
+(defun gnus-uu-post-encode-mime-uuencode (path file-name)
+  (when (gnus-uu-post-encode-uuencode path file-name)
+    (gnus-uu-post-make-mime file-name "x-uue")
+    t))
+
+;; Encodes with base64 and adds MIME headers
+(defun gnus-uu-post-encode-mime (path file-name)
+  (when (eq 0 (call-process shell-file-name nil t nil shell-command-switch
+                           (format "%s %s -o %s" "mmencode" path file-name)))
+    (gnus-uu-post-make-mime file-name "base64")
+    t))
+
+;; Adds MIME headers.
+(defun gnus-uu-post-make-mime (file-name encoding)
+  (goto-char (point-min))
+  (insert (format "Content-Type: %s; name=\"%s\"\n"
+                 (gnus-uu-choose-action file-name gnus-uu-ext-to-mime-list)
+                 file-name))
+  (insert (format "Content-Transfer-Encoding: %s\n\n" encoding))
+  (save-restriction
+    (set-buffer gnus-message-buffer)
+    (goto-char (point-min))
+    (re-search-forward (concat "^" (regexp-quote mail-header-separator) "$"))
+    (forward-line -1)
+    (narrow-to-region (point-min) (point))
+    (unless (mail-fetch-field "mime-version")
+      (widen)
+      (insert "MIME-Version: 1.0\n"))
+    (widen)))
+
+;; Encodes a file PATH with COMMAND, leaving the result in the
+;; current buffer.
+(defun gnus-uu-post-encode-file (command path file-name)
+  (eq 0 (call-process shell-file-name nil t nil shell-command-switch
+                     (format "%s %s %s" command path file-name))))
+
+(defun gnus-uu-post-news-inews ()
+  "Posts the composed news article and encoded file.
+If no file has been included, the user will be asked for a file."
+  (interactive)
+
+  (let (file-name)
+
+    (if gnus-uu-post-inserted-file-name
+       (setq file-name gnus-uu-post-inserted-file-name)
+      (setq file-name (gnus-uu-post-insert-binary)))
+
+    (gnus-uu-post-encoded file-name gnus-uu-post-threaded))
+  (setq gnus-uu-post-inserted-file-name nil)
+  (when gnus-uu-winconf-post-news
+    (set-window-configuration gnus-uu-winconf-post-news)))
+
+;; Asks for a file to encode, encodes it and inserts the result in
+;; the current buffer.  Returns the file name the user gave.
+(defun gnus-uu-post-insert-binary ()
+  (let ((uuencode-buffer-name "*uuencode buffer*")
+       file-path uubuf file-name)
+
+    (setq file-path (read-file-name
+                    "What file do you want to encode? "))
+    (when (not (file-exists-p file-path))
+      (error "%s: No such file" file-path))
+
+    (goto-char (point-max))
+    (insert (format "\n%s\n" gnus-uu-post-binary-separator))
+
+    ;; #### Unix-specific?
+    (when (string-match "^~/" file-path)
+      (setq file-path (concat "$HOME" (substring file-path 1))))
+    ;; #### Unix-specific?
+    (if (string-match "/[^/]*$" file-path)
+       (setq file-name (substring file-path (1+ (match-beginning 0))))
+      (setq file-name file-path))
+
+    (unwind-protect
+       (if (with-current-buffer
+               (setq uubuf (gnus-get-buffer-create uuencode-buffer-name))
+             (erase-buffer)
+             (funcall gnus-uu-post-encode-method file-path file-name))
+           (insert-buffer-substring uubuf)
+         (error "Encoding unsuccessful"))
+      (kill-buffer uubuf))
+    file-name))
+
+;; Posts the article and all of the encoded file.
+(defun gnus-uu-post-encoded (file-name &optional threaded)
+  (let ((send-buffer-name "*uuencode send buffer*")
+       (encoded-buffer-name "*encoded buffer*")
+       (top-string "[ cut here %s (%s %d/%d) %s gnus-uu ]")
+       (separator (concat mail-header-separator "\n\n"))
+       uubuf length parts header i end beg
+       beg-line minlen post-buf whole-len beg-binary end-binary)
+
+    (setq post-buf (current-buffer))
+
+    (goto-char (point-min))
+    (when (not (re-search-forward
+               (if gnus-uu-post-separate-description
+                   (concat "^" (regexp-quote gnus-uu-post-binary-separator)
+                           "$")
+                 (concat "^" (regexp-quote mail-header-separator) "$"))
+               nil t))
+      (error "Internal error: No binary/header separator"))
+    (beginning-of-line)
+    (forward-line 1)
+    (setq beg-binary (point))
+    (setq end-binary (point-max))
+
+    (with-current-buffer
+       (setq uubuf (gnus-get-buffer-create encoded-buffer-name))
+      (erase-buffer)
+      (insert-buffer-substring post-buf beg-binary end-binary)
+      (goto-char (point-min))
+      (setq length (count-lines (point-min) (point-max)))
+      (setq parts (/ length gnus-uu-post-length))
+      (unless (< (% length gnus-uu-post-length) 4)
+       (incf parts)))
+
+    (when gnus-uu-post-separate-description
+      (forward-line -1))
+    (delete-region (point) (point-max))
+
+    (goto-char (point-min))
+    (re-search-forward
+     (concat "^" (regexp-quote mail-header-separator) "$") nil t)
+    (setq header (buffer-substring (point-min) (point-at-bol)))
+
+    (goto-char (point-min))
+    (when gnus-uu-post-separate-description
+      (when (re-search-forward "^Subject: " nil t)
+       (end-of-line)
+       (insert (format " (0/%d)" parts)))
+      (save-excursion
+       (message-send))
+      (setq gnus-uu-post-message-id (message-fetch-field "message-id")))
+
+    (save-excursion
+      (setq i 1)
+      (setq beg 1)
+      (while (not (> i parts))
+       (set-buffer (gnus-get-buffer-create send-buffer-name))
+       (erase-buffer)
+       (insert header)
+       (when (and threaded gnus-uu-post-message-id)
+         (insert "References: " gnus-uu-post-message-id "\n"))
+       (insert separator)
+       (setq whole-len
+             (- 62 (length (format top-string "" file-name i parts ""))))
+       (when (> 1 (setq minlen (/ whole-len 2)))
+         (setq minlen 1))
+       (setq
+        beg-line
+        (format top-string
+                (make-string minlen ?-)
+                file-name i parts
+                (make-string
+                 (if (= 0 (% whole-len 2)) (1- minlen) minlen) ?-)))
+
+       (goto-char (point-min))
+       (when (re-search-forward "^Subject: " nil t)
+         (end-of-line)
+         (insert (format " (%d/%d)" i parts)))
+
+       (goto-char (point-max))
+       (with-current-buffer uubuf
+         (goto-char beg)
+         (if (= i parts)
+             (goto-char (point-max))
+           (forward-line gnus-uu-post-length))
+         (when (and (= (1+ i) parts) (< (count-lines (point) (point-max)) 4))
+           (forward-line -4))
+         (setq end (point)))
+       (insert-buffer-substring uubuf beg end)
+       (insert beg-line "\n")
+       (setq beg end)
+       (incf i)
+       (goto-char (point-min))
+       (re-search-forward
+        (concat "^" (regexp-quote mail-header-separator) "$") nil t)
+       (beginning-of-line)
+       (forward-line 2)
+       (when (re-search-forward
+              (concat "^" (regexp-quote gnus-uu-post-binary-separator) "$")
+              nil t)
+         (replace-match "")
+         (forward-line 1))
+       (insert beg-line)
+       (insert "\n")
+       (let (message-sent-message-via)
+         (save-excursion
+           (message-send))
+         (setq gnus-uu-post-message-id
+               (concat (message-fetch-field "references") " "
+                       (message-fetch-field "message-id"))))))
+
+    (gnus-kill-buffer send-buffer-name)
+    (gnus-kill-buffer encoded-buffer-name)
+
+    (when (not gnus-uu-post-separate-description)
+      (set-buffer-modified-p nil)
+      (bury-buffer))))
+
+(provide 'gnus-uu)
+
+;;; gnus-uu.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-vm.el b/xemacs-packages/gnus/lisp/gnus-vm.el
new file mode 100644 (file)
index 0000000..5aa1ece
--- /dev/null
@@ -0,0 +1,102 @@
+;;; gnus-vm.el --- vm interface for Gnus
+
+;; Copyright (C) 1994-2016 Free Software Foundation, Inc.
+
+;; Author: Per Persson <pp@gnu.ai.mit.edu>
+;; Keywords: news, mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Major contributors:
+;;     Christian Limpach <Christian.Limpach@nice.ch>
+;; Some code stolen from:
+;;     Rick Sladkey <jrs@world.std.com>
+
+;;; Code:
+
+(require 'sendmail)
+(require 'message)
+(require 'gnus)
+(require 'gnus-msg)
+
+(eval-when-compile
+  (require 'cl))
+
+(autoload 'vm-mode "vm")
+(autoload 'vm-save-message "vm")
+
+(defvar gnus-vm-inhibit-window-system nil
+  "Inhibit loading `win-vm' if using a window-system.
+Has to be set before gnus-vm is loaded.")
+
+(unless gnus-vm-inhibit-window-system
+  (ignore-errors
+    (when window-system
+      (require 'win-vm))))
+
+(defun gnus-vm-make-folder (&optional buffer)
+  (require 'vm)
+  (let ((article (or buffer (current-buffer)))
+       (tmp-folder (generate-new-buffer " *tmp-folder*"))
+       (start (point-min))
+       (end (point-max)))
+    (set-buffer tmp-folder)
+    (insert-buffer-substring article start end)
+    (goto-char (point-min))
+    (if (looking-at "^\\(From [^ ]+ \\).*$")
+       (replace-match (concat "\\1" (current-time-string)))
+      (insert "From " gnus-newsgroup-name " "
+             (current-time-string) "\n"))
+    (while (re-search-forward "\n\nFrom " nil t)
+      (replace-match "\n\n>From "))
+    ;; insert a newline, otherwise the last line gets lost
+    (goto-char (point-max))
+    (insert "\n")
+    (vm-mode)
+    tmp-folder))
+
+(defun gnus-summary-save-article-vm (&optional arg)
+  "Append the current article to a vm folder.
+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-save-in-vm))
+    (gnus-summary-save-article arg)))
+
+(defun gnus-summary-save-in-vm (&optional folder)
+  (interactive)
+  (require 'vm)
+  (setq folder
+       (gnus-read-save-file-name
+        "Save %s in VM folder:" folder
+        gnus-mail-save-name gnus-newsgroup-name
+        gnus-current-headers 'gnus-newsgroup-last-mail))
+  (gnus-eval-in-buffer-window gnus-original-article-buffer
+    (save-excursion
+      (save-restriction
+       (widen)
+       (let ((vm-folder (gnus-vm-make-folder)))
+         (vm-save-message folder)
+         (kill-buffer vm-folder))))))
+
+(provide 'gnus-vm)
+
+;;; gnus-vm.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus-win.el b/xemacs-packages/gnus/lisp/gnus-win.el
new file mode 100644 (file)
index 0000000..b1498fd
--- /dev/null
@@ -0,0 +1,542 @@
+;;; gnus-win.el --- window configuration functions for Gnus
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'gnus)
+(require 'gnus-util)
+
+(defgroup gnus-windows nil
+  "Window configuration."
+  :group 'gnus)
+
+(defcustom gnus-use-full-window t
+  "*If non-nil, use the entire Emacs screen."
+  :group 'gnus-windows
+  :type 'boolean)
+
+(defcustom gnus-window-min-width 2
+  "*Minimum width of Gnus buffers."
+  :group 'gnus-windows
+  :type 'integer)
+
+(defcustom gnus-window-min-height 1
+  "*Minimum height of Gnus buffers."
+  :group 'gnus-windows
+  :type 'integer)
+
+(defcustom gnus-always-force-window-configuration nil
+  "*If non-nil, always force the Gnus window configurations."
+  :group 'gnus-windows
+  :type 'boolean)
+
+(defcustom gnus-use-frames-on-any-display nil
+  "*If non-nil, frames on all displays will be considered usable by Gnus.
+When nil, only frames on the same display as the selected frame will be
+used to display Gnus windows."
+  :version "22.1"
+  :group 'gnus-windows
+  :type 'boolean)
+
+(defvar gnus-buffer-configuration
+  '((group
+     (vertical 1.0
+              (group 1.0 point)))
+    (summary
+     (vertical 1.0
+              (summary 1.0 point)))
+    (article
+     (cond
+      (gnus-use-trees
+       '(vertical 1.0
+                 (summary 0.25 point)
+                 (tree 0.25)
+                 (article 1.0)))
+      (t
+       '(vertical 1.0
+                 (summary 0.25 point)
+                 (article 1.0)))))
+    (server
+     (vertical 1.0
+              (server 1.0 point)))
+    (browse
+     (vertical 1.0
+              (browse 1.0 point)))
+    (message
+     (vertical 1.0
+              (message 1.0 point)))
+    (pick
+     (vertical 1.0
+              (article 1.0 point)))
+    (info
+     (vertical 1.0
+              (info 1.0 point)))
+    (summary-faq
+     (vertical 1.0
+              (summary 0.25)
+              (faq 1.0 point)))
+    (only-article
+     (vertical 1.0
+              (article 1.0 point)))
+    (edit-article
+     (vertical 1.0
+              (article 1.0 point)))
+    (edit-form
+     (vertical 1.0
+              (group 0.5)
+              (edit-form 1.0 point)))
+    (edit-score
+     (vertical 1.0
+              (summary 0.25)
+              (edit-score 1.0 point)))
+    (edit-server
+     (vertical 1.0
+              (server 0.5)
+              (edit-form 1.0 point)))
+    (post
+     (vertical 1.0
+              (post 1.0 point)))
+    (reply
+     (vertical 1.0
+              (article 0.5)
+              (message 1.0 point)))
+    (forward
+     (vertical 1.0
+              (message 1.0 point)))
+    (reply-yank
+     (vertical 1.0
+              (message 1.0 point)))
+    (mail-bounce
+     (vertical 1.0
+              (article 0.5)
+              (message 1.0 point)))
+    (pipe
+     (vertical 1.0
+              (summary 0.25 point)
+              ("*Shell Command Output*" 1.0)))
+    (bug
+     (vertical 1.0
+              (if gnus-bug-create-help-buffer '("*Gnus Help Bug*" 0.5))
+              ("*Gnus Bug*" 1.0 point)))
+    (score-trace
+     (vertical 1.0
+              (summary 0.5 point)
+              ("*Score Trace*" 1.0)))
+    (score-words
+     (vertical 1.0
+              (summary 0.5 point)
+              ("*Score Words*" 1.0)))
+    (split-trace
+     (vertical 1.0
+              (summary 0.5 point)
+              ("*Split Trace*" 1.0)))
+    (category
+     (vertical 1.0
+              (category 1.0)))
+    (compose-bounce
+     (vertical 1.0
+              (article 0.5)
+              (message 1.0 point)))
+    (display-term
+     (vertical 1.0
+              ("*display*" 1.0)))
+    (mml-preview
+     (vertical 1.0
+              (message 0.5)
+              (mml-preview 1.0 point))))
+  "Window configuration for all possible Gnus buffers.
+See the Gnus manual for an explanation of the syntax used.")
+
+(defvar gnus-window-to-buffer
+  '((group . gnus-group-buffer)
+    (summary . gnus-summary-buffer)
+    (article . gnus-article-buffer)
+    (server . gnus-server-buffer)
+    (browse . "*Gnus Browse Server*")
+    (edit-group . gnus-group-edit-buffer)
+    (edit-form . gnus-edit-form-buffer)
+    (edit-server . gnus-server-edit-buffer)
+    (edit-score . gnus-score-edit-buffer)
+    (message . gnus-message-buffer)
+    (mail . gnus-message-buffer)
+    (post-news . gnus-message-buffer)
+    (faq . gnus-faq-buffer)
+    (tree . gnus-tree-buffer)
+    (score-trace . "*Score Trace*")
+    (split-trace . "*Split Trace*")
+    (info . gnus-info-buffer)
+    (category . gnus-category-buffer)
+    (article-copy . gnus-article-copy)
+    (draft . gnus-draft-buffer)
+    (mml-preview . mml-preview-buffer))
+  "Mapping from short symbols to buffer names or buffer variables.")
+
+(defcustom gnus-configure-windows-hook nil
+  "*A hook called when configuring windows."
+  :version "22.1"
+  :group 'gnus-windows
+  :type 'hook)
+
+;;; Internal variables.
+
+(defvar gnus-current-window-configuration nil
+  "The most recently set window configuration.")
+
+(defvar gnus-created-frames nil)
+(defvar gnus-window-frame-focus nil)
+
+(defun gnus-kill-gnus-frames ()
+  "Kill all frames Gnus has created."
+  (while gnus-created-frames
+    (when (frame-live-p (car gnus-created-frames))
+      ;; We slap a condition-case around this `delete-frame' to ensure
+      ;; against errors if we try do delete the single frame that's left.
+      (ignore-errors
+       (delete-frame (car gnus-created-frames))))
+    (pop gnus-created-frames)))
+
+;;;###autoload
+(defun gnus-add-configuration (conf)
+  "Add the window configuration CONF to `gnus-buffer-configuration'."
+  (setq gnus-buffer-configuration
+       (cons conf (delq (assq (car conf) gnus-buffer-configuration)
+                        gnus-buffer-configuration))))
+
+(defvar gnus-frame-list nil)
+
+(defun gnus-window-to-buffer-helper (obj)
+  (cond ((not (symbolp obj))
+        obj)
+       ((boundp obj)
+        (symbol-value obj))
+       ((fboundp obj)
+        (funcall obj))
+       (t
+        nil)))
+
+(defun gnus-configure-frame (split &optional window)
+  "Split WINDOW according to SPLIT."
+  (let* ((current-window (or (get-buffer-window (current-buffer))
+                             (selected-window)))
+         (window (or window current-window)))
+    (select-window window)
+    ;; The SPLIT might be something that is to be evalled to
+    ;; return a new SPLIT.
+    (while (and (not (assq (car split) gnus-window-to-buffer))
+               (symbolp (car split)) (fboundp (car split)))
+      (setq split (eval split)))
+    (let* ((type (car split))
+          (subs (cddr split))
+          (len (if (eq type 'horizontal) (window-width) (window-height)))
+          (total 0)
+          (window-min-width (or gnus-window-min-width window-min-width))
+          (window-min-height (or gnus-window-min-height window-min-height))
+          s result new-win rest comp-subs size sub)
+      (cond
+       ;; Nothing to do here.
+       ((null split))
+       ;; Don't switch buffers.
+       ((null type)
+       (and (memq 'point split) window))
+       ;; This is a buffer to be selected.
+       ((not (memq type '(frame horizontal vertical)))
+       (let ((buffer (cond ((stringp type) type)
+                           (t (cdr (assq type gnus-window-to-buffer))))))
+         (unless buffer
+           (error "Invalid buffer type: %s" type))
+         (let ((buf (gnus-get-buffer-create
+                     (gnus-window-to-buffer-helper buffer))))
+           (when (buffer-name buf)
+             (cond
+               ((eq buf (window-buffer (selected-window)))
+                (set-buffer buf))
+               ((eq t (window-dedicated-p
+                      ;; XEmacs version of `window-dedicated-p' requires it.
+                      (selected-window)))
+                ;; If the window is hard-dedicated, we have a problem because
+                ;; we just can't do what we're asked.  But signaling an error,
+                ;; like `switch-to-buffer' would do, is not an option because
+                ;; it would prevent things like "^" (to jump to the *Servers*)
+                ;; in a dedicated *Group*.
+                ;; FIXME: Maybe a better/additional fix would be to change
+                ;; gnus-configure-windows so that when called
+                ;; from a hard-dedicated frame, it creates (and
+                ;; configures) a new frame, leaving the dedicated frame alone.
+                (pop-to-buffer buf))
+               (t (switch-to-buffer buf)))))
+         (when (memq 'frame-focus split)
+           (setq gnus-window-frame-focus window))
+         ;; We return the window if it has the `point' spec.
+         (and (memq 'point split) window)))
+       ;; This is a frame split.
+       ((eq type 'frame)
+       (unless gnus-frame-list
+         (setq gnus-frame-list (list (window-frame current-window))))
+       (let ((i 0)
+             params frame fresult)
+         (while (< i (length subs))
+           ;; Frame parameter is gotten from the sub-split.
+           (setq params (cadr (elt subs i)))
+           ;; It should be a list.
+           (unless (listp params)
+             (setq params nil))
+           ;; Create a new frame?
+           (unless (setq frame (elt gnus-frame-list i))
+             (nconc gnus-frame-list (list (setq frame (make-frame params))))
+             (push frame gnus-created-frames))
+           ;; Is the old frame still alive?
+           (unless (frame-live-p frame)
+             (setcar (nthcdr i gnus-frame-list)
+                     (setq frame (make-frame params))))
+           ;; Select the frame in question and do more splits there.
+           (select-frame frame)
+           (setq fresult (or (gnus-configure-frame (elt subs i)) fresult))
+           (incf i))
+         ;; Select the frame that has the selected buffer.
+         (when fresult
+           (select-frame (window-frame fresult)))))
+       ;; This is a normal split.
+       (t
+       (when (> (length subs) 0)
+         ;; First we have to compute the sizes of all new windows.
+         (while subs
+           (setq sub (append (pop subs) nil))
+           (while (and (not (assq (car sub) gnus-window-to-buffer))
+                       (symbolp (car sub)) (fboundp (car sub)))
+             (setq sub (eval sub)))
+           (when sub
+             (push sub comp-subs)
+             (setq size (cadar comp-subs))
+             (cond ((equal size 1.0)
+                    (setq rest (car comp-subs))
+                    (setq s 0))
+                   ((floatp size)
+                    (setq s (floor (* size len))))
+                   ((integerp size)
+                    (setq s size))
+                   (t
+                    (error "Invalid size: %s" size)))
+             ;; Try to make sure that we are inside the safe limits.
+             (cond ((zerop s))
+                   ((eq type 'horizontal)
+                    (setq s (max s window-min-width)))
+                   ((eq type 'vertical)
+                    (setq s (max s window-min-height))))
+             (setcar (cdar comp-subs) s)
+             (incf total s)))
+         ;; Take care of the "1.0" spec.
+         (if rest
+             (setcar (cdr rest) (- len total))
+           (error "No 1.0 specs in %s" split))
+         ;; The we do the actual splitting in a nice recursive
+         ;; fashion.
+         (setq comp-subs (nreverse comp-subs))
+         (while comp-subs
+           (setq new-win
+                  (if (null (cdr comp-subs))
+                      window
+                   (split-window window (cadar comp-subs)
+                                 (eq type 'horizontal))))
+           (setq result (or (gnus-configure-frame
+                             (car comp-subs) window)
+                            result))
+           (select-window new-win)
+           (setq window new-win)
+           (setq comp-subs (cdr comp-subs))))
+       ;; Return the proper window, if any.
+       (when result
+         (select-window result)))))))
+
+(defvar gnus-frame-split-p nil)
+
+(defun gnus-configure-windows (setting &optional force)
+  (cond
+   ((null setting)
+    ;; Do nothing.
+    )
+   ((window-configuration-p setting)
+    (set-window-configuration setting))
+   (t
+    (setq gnus-current-window-configuration setting)
+    (setq force (or force gnus-always-force-window-configuration))
+    (let ((split (if (symbolp setting)
+                     (cadr (assq setting gnus-buffer-configuration))
+                   setting))
+          all-visible)
+
+      (setq gnus-frame-split-p nil)
+
+      (unless split
+        (error "No such setting in `gnus-buffer-configuration': %s" setting))
+
+      (if (and (setq all-visible (gnus-all-windows-visible-p split))
+               (not force))
+          ;; All the windows mentioned are already visible, so we just
+          ;; 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))
+
+        ;; Either remove all windows or just remove all Gnus windows.
+        (let ((frame (selected-frame)))
+          (unwind-protect
+              (if gnus-use-full-window
+                  ;; We want to remove all other windows.
+                  (if (not gnus-frame-split-p)
+                      ;; 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
+                    ;; on all frames.
+                    (gnus-delete-windows-in-gnusey-frames))
+                ;; Just remove some windows.
+                (gnus-remove-some-windows)
+                (if (featurep 'xemacs)
+                    (switch-to-buffer nntp-server-buffer)
+                  (set-buffer nntp-server-buffer)))
+            (select-frame frame)))
+
+        (let (gnus-window-frame-focus)
+          (if (featurep 'xemacs)
+              (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
+            (gnus-select-frame-set-input-focus
+             (window-frame gnus-window-frame-focus)))))))))
+
+(defun gnus-delete-windows-in-gnusey-frames ()
+  "Do a `delete-other-windows' in all frames that have Gnus windows."
+  (let ((buffers (gnus-buffers)))
+    (mapcar
+     (lambda (frame)
+       (unless (eq (cdr (assq 'minibuffer
+                             (frame-parameters frame)))
+                  'only)
+        (select-frame frame)
+        (let (do-delete)
+          (walk-windows
+           (lambda (window)
+             (when (memq (window-buffer window) buffers)
+               (setq do-delete t))))
+          (when do-delete
+            (delete-other-windows)))))
+     (frame-list))))
+
+(defun gnus-all-windows-visible-p (split)
+  "Say whether all buffers in SPLIT are currently visible.
+In particular, the value returned will be the window that
+should have point."
+  (let ((stack (list split))
+       (all-visible t)
+       type buffer win buf)
+    (while (and (setq split (pop stack))
+               all-visible)
+      (when (consp (car split))
+       (push 1.0 split)
+       (push 'vertical split))
+      ;; The SPLIT might be something that is to be evalled to
+      ;; return a new SPLIT.
+      (while (and (not (assq (car split) gnus-window-to-buffer))
+                 (symbolp (car split)) (fboundp (car split)))
+       (setq split (eval split)))
+
+      (setq type (elt split 0))
+      (cond
+       ;; Nothing here.
+       ((null split) t)
+       ;; A buffer.
+       ((not (memq type '(horizontal vertical frame)))
+       (setq buffer (cond ((stringp type) type)
+                          (t (cdr (assq type gnus-window-to-buffer)))))
+       (unless buffer
+         (error "Invalid buffer type: %s" type))
+       (if (and (setq buf (get-buffer (gnus-window-to-buffer-helper buffer)))
+                (buffer-live-p buf)
+                (setq win (gnus-get-buffer-window buf t)))
+           (if (memq 'point split)
+               (setq all-visible win))
+         (setq all-visible nil)))
+       (t
+       (when (eq type 'frame)
+         (setq gnus-frame-split-p t))
+       (setq stack (append (cddr split) stack)))))
+    (unless (eq all-visible t)
+      all-visible)))
+
+(defun gnus-window-top-edge (&optional window)
+  "Return the top coordinate of WINDOW."
+  (nth 1 (window-edges window)))
+
+(defun gnus-remove-some-windows ()
+  (let ((buffers (gnus-buffers))
+       buf bufs lowest-buf lowest)
+    (save-excursion
+      ;; Remove windows on all known Gnus buffers.
+      (while (setq buf (pop buffers))
+       (when (get-buffer-window buf)
+         (push buf bufs)
+         (pop-to-buffer buf)
+         (when (or (not lowest)
+                   (< (gnus-window-top-edge) lowest))
+           (setq lowest (gnus-window-top-edge)
+                 lowest-buf buf))))
+      (when lowest-buf
+       (pop-to-buffer lowest-buf)
+       (if (featurep 'xemacs)
+           (switch-to-buffer nntp-server-buffer)
+         (set-buffer nntp-server-buffer)))
+      (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-remove-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/xemacs-packages/gnus/lisp/gnus-xmas.el b/xemacs-packages/gnus/lisp/gnus-xmas.el
new file mode 100644 (file)
index 0000000..a84c138
--- /dev/null
@@ -0,0 +1,883 @@
+;;; gnus-xmas.el --- Gnus functions for XEmacs
+
+;; Copyright (C) 1995-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3, 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.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile
+  (autoload 'gnus-active "gnus" nil nil 'macro)
+  (autoload 'gnus-group-entry "gnus" nil nil 'macro)
+  (autoload 'gnus-info-level "gnus" nil nil 'macro)
+  (autoload 'gnus-info-marks "gnus" nil nil 'macro)
+  (autoload 'gnus-info-method "gnus" nil nil 'macro)
+  (autoload 'gnus-info-score "gnus" nil nil 'macro))
+
+(require 'text-props)
+(defvar menu-bar-mode (featurep 'menubar))
+(require 'messagexmas)
+(require 'wid-edit)
+(require 'gnus-util)
+
+(defgroup gnus-xmas nil
+  "XEmacsoid support for Gnus"
+  :group 'gnus)
+
+(defcustom gnus-xmas-glyph-directory nil
+  "Directory where Gnus logos and icons are located.
+If this variable is nil, Gnus will try to locate the directory
+automatically."
+  :type '(choice (const :tag "autodetect" nil)
+                directory)
+  :group 'gnus-xmas)
+
+(unless gnus-xmas-glyph-directory
+  (unless (setq gnus-xmas-glyph-directory
+               (message-xmas-find-glyph-directory "gnus"))
+    (error "Can't find glyph directory. \
+Possibly the `etc' directory has not been installed.")))
+
+;;; Internal variables.
+
+;; Don't warn about these undefined variables.
+
+;;defined in gnus.el
+(defvar gnus-active-hashtb)
+(defvar gnus-article-buffer)
+(defvar gnus-auto-center-summary)
+(defvar gnus-current-headers)
+(defvar gnus-level-killed)
+(defvar gnus-level-zombie)
+(defvar gnus-newsgroup-bookmarks)
+(defvar gnus-newsgroup-dependencies)
+(defvar gnus-newsgroup-selected-overlay)
+(defvar gnus-newsrc-hashtb)
+(defvar gnus-read-mark)
+(defvar gnus-refer-article-method)
+(defvar gnus-reffed-article-number)
+(defvar gnus-unread-mark)
+(defvar gnus-version)
+(defvar gnus-view-pseudos)
+(defvar gnus-view-pseudos-separately)
+(defvar gnus-visual)
+(defvar gnus-zombie-list)
+;;defined in gnus-msg.el
+(defvar gnus-article-copy)
+(defvar gnus-check-before-posting)
+;;defined in gnus-vis.el
+(defvar gnus-article-button-face)
+(defvar gnus-article-mouse-face)
+(defvar gnus-summary-selected-face)
+(defvar gnus-group-reading-menu)
+(defvar gnus-group-group-menu)
+(defvar gnus-group-misc-menu)
+(defvar gnus-summary-article-menu)
+(defvar gnus-summary-thread-menu)
+(defvar gnus-summary-misc-menu)
+(defvar gnus-summary-post-menu)
+(defvar gnus-summary-kill-menu)
+(defvar gnus-article-article-menu)
+(defvar gnus-article-treatment-menu)
+(defvar gnus-mouse-2)
+(defvar standard-display-table)
+(defvar gnus-tree-minimize-window)
+;;`gnus-agent-mode' in gnus-agent.el will define it.
+(defvar gnus-agent-summary-mode)
+(defvar gnus-draft-mode)
+
+(defcustom gnus-xmas-force-redisplay nil
+  "*If non-nil, force a redisplay before recentering the summary buffer.
+This is ugly, but it works around a bug in `window-displayed-height'."
+  :type 'boolean
+  :group 'gnus-xmas)
+
+(defun gnus-xmas-switch-horizontal-scrollbar-off ()
+  (when (featurep 'scrollbar)
+    (set-specifier scrollbar-height (cons (current-buffer) 0))))
+
+(defun gnus-xmas-summary-recenter ()
+  "\"Center\" point in the summary window.
+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.
+  ;; Force redisplay to get properly computed window height.
+  (when gnus-xmas-force-redisplay
+    (sit-for 0))
+  (when gnus-auto-center-summary
+    (let* ((height (if (fboundp 'window-displayed-height)
+                      (window-displayed-height)
+                    (- (window-height) 2)))
+          (top (cond ((< height 4) 0)
+                     ((< height 7) 1)
+                     (t (if (numberp gnus-auto-center-summary)
+                            gnus-auto-center-summary
+                          2))))
+          (bottom (save-excursion (goto-char (point-max))
+                                  (forward-line (- height))
+                                  (point)))
+          (window (get-buffer-window (current-buffer))))
+      (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
+       ;; possible valid number, or the second line from the top,
+       ;; whichever is the least.
+       ;; NOFORCE parameter suggested by Daniel Pittman <daniel@danann.net>.
+       (set-window-start
+        window (min bottom (save-excursion (forward-line (- top)) (point)))
+        t))
+      ;; Do horizontal recentering while we're at it.
+      (when (and (get-buffer-window (current-buffer) t)
+                (not (eq gnus-auto-center-summary 'vertical)))
+       (let ((selected (selected-window)))
+         (select-window (get-buffer-window (current-buffer) t))
+         (gnus-summary-position-point)
+         (gnus-horizontal-recenter)
+         (select-window selected))))))
+
+(defun gnus-xmas-summary-set-display-table ()
+  ;; Setup the display table -- like `gnus-summary-setup-display-table',
+  ;; but done in an XEmacsish way.
+  (let ((table (make-display-table))
+       (i 32))
+    ;; Nix out all the control chars...
+    (while (>= (setq i (1- i)) 0)
+      (gnus-put-display-table i [??] table))
+    ;; ... but not newline and cr, of course.  (cr is necessary for the
+    ;; selective display).
+    (gnus-put-display-table ?\n nil table)
+    (gnus-put-display-table ?\r nil table)
+    ;; We keep TAB as well.
+    (gnus-put-display-table ?\t nil table)
+    ;; We nix out any glyphs over 126 below ctl-arrow.
+    (let ((i (if (integerp ctl-arrow) ctl-arrow 160)))
+      (while (>= (setq i (1- i)) 127)
+       (unless (gnus-get-display-table i table)
+         (gnus-put-display-table i [??] table))))
+    ;; Can't use `set-specifier' because of a bug in 19.14 and earlier
+    (add-spec-to-specifier current-display-table table (current-buffer) nil)))
+
+(defun gnus-xmas-add-text-properties (start end props &optional object)
+  (add-text-properties start end props object)
+  (put-text-property start end 'start-closed nil object))
+
+(defun gnus-xmas-put-text-property (start end prop value &optional object)
+  (put-text-property start end prop value object)
+  (put-text-property start end 'start-closed nil object))
+
+(defun gnus-xmas-extent-start-open (point)
+  (map-extents (lambda (extent arg)
+                (set-extent-property extent 'start-open t))
+              nil point (min (1+ (point)) (point-max))))
+
+(defun gnus-xmas-article-push-button (event)
+  "Check text under the mouse pointer for a callback function.
+If the text under the mouse pointer has a `gnus-callback' property,
+call it with the value of the `gnus-data' text property."
+  (interactive "e")
+  (set-buffer (window-buffer (event-window event)))
+  (let* ((pos (event-closest-point event))
+        (data (get-text-property pos 'gnus-data))
+        (fun (get-text-property pos 'gnus-callback)))
+    (goto-char pos)
+    (when fun
+      (funcall fun data))))
+
+(defun gnus-xmas-kill-all-overlays ()
+  "Delete all extents in the current buffer."
+  (map-extents (lambda (extent ignore)
+                (delete-extent extent)
+                nil)))
+
+(defun gnus-xmas-window-top-edge (&optional window)
+  (nth 1 (window-pixel-edges window)))
+
+(defun gnus-xmas-tree-minimize ()
+  (when (and gnus-tree-minimize-window
+            (not (one-window-p)))
+    (let* ((window-min-height 2)
+          (height (1+ (count-lines (point-min) (point-max))))
+          (min (max (1- window-min-height) height))
+          (tot (if (numberp gnus-tree-minimize-window)
+                   (min gnus-tree-minimize-window min)
+                 min))
+          (win (get-buffer-window (current-buffer)))
+          (wh (and win (1- (window-height win)))))
+      (when (and win
+                (not (eq tot wh)))
+       (let ((selected (selected-window)))
+         (select-window win)
+         (enlarge-window (- tot wh))
+         (select-window selected))))))
+
+;; Select the lowest window on the frame.
+(defun gnus-xmas-select-lowest-window ()
+  (let* ((lowest-window (selected-window))
+        (bottom-edge (car (cdr (cdr (cdr (window-pixel-edges))))))
+        (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
+                                               this-window)))))))
+       (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 lowest-window)
+         (setq window-search nil))))))
+
+(defmacro gnus-xmas-menu-add (type &rest menus)
+  `(gnus-xmas-menu-add-1 ',type ',menus))
+(put 'gnus-xmas-menu-add 'lisp-indent-function 1)
+
+(defun gnus-xmas-menu-add-1 (type menus)
+  (when (and menu-bar-mode
+            (gnus-visual-p (intern (format "%s-menu" type)) 'menu))
+    (while menus
+      (easy-menu-add (symbol-value (pop menus))))))
+
+(defun gnus-xmas-group-menu-add ()
+  (gnus-xmas-menu-add group
+    gnus-group-reading-menu gnus-group-group-menu gnus-group-misc-menu))
+
+(defun gnus-xmas-summary-menu-add ()
+  (gnus-xmas-menu-add summary
+    gnus-summary-misc-menu gnus-summary-kill-menu
+    gnus-summary-article-menu gnus-summary-thread-menu
+    gnus-summary-post-menu ))
+
+(defun gnus-xmas-article-menu-add ()
+  (gnus-xmas-menu-add article
+    gnus-article-article-menu gnus-article-treatment-menu
+    gnus-article-post-menu gnus-article-commands-menu))
+
+(defun gnus-xmas-score-menu-add ()
+  (gnus-xmas-menu-add score
+    gnus-score-menu))
+
+(defun gnus-xmas-pick-menu-add ()
+  (gnus-xmas-menu-add pick
+    gnus-pick-menu))
+
+(defun gnus-xmas-topic-menu-add ()
+  (gnus-xmas-menu-add topic
+    gnus-topic-menu))
+
+(defun gnus-xmas-binary-menu-add ()
+  (gnus-xmas-menu-add binary
+    gnus-binary-menu))
+
+(defun gnus-xmas-agent-summary-menu-add ()
+  (gnus-xmas-menu-add agent-summary
+    gnus-agent-summary-menu))
+
+(defun gnus-xmas-agent-group-menu-add ()
+  (gnus-xmas-menu-add agent-group
+    gnus-agent-group-menu))
+
+(defun gnus-xmas-agent-server-menu-add ()
+  (gnus-xmas-menu-add agent-server
+    gnus-agent-server-menu))
+
+(defun gnus-xmas-tree-menu-add ()
+  (gnus-xmas-menu-add tree
+    gnus-tree-menu))
+
+(defun gnus-xmas-draft-menu-add ()
+  (gnus-xmas-menu-add draft
+    gnus-draft-menu))
+
+(defun gnus-xmas-server-menu-add ()
+  (gnus-xmas-menu-add menu
+    gnus-server-server-menu gnus-server-connections-menu))
+
+(defun gnus-xmas-browse-menu-add ()
+  (gnus-xmas-menu-add browse
+    gnus-browse-menu))
+
+(defun gnus-xmas-read-event-char (&optional prompt)
+  "Get the next event."
+  (when prompt
+    (display-message 'no-log (format "%s" prompt)))
+  (let ((event (next-command-event)))
+    (sit-for 0)
+    ;; We junk all non-key events.  Is this naughty?
+    (while (not (or (key-press-event-p event)
+                   (button-press-event-p event)))
+      (dispatch-event event)
+      (setq event (next-command-event)))
+    (cons (and (key-press-event-p event)
+              (event-to-character event))
+         event)))
+
+(defun gnus-xmas-article-describe-bindings (&optional prefix)
+  "Show a list of all defined keys, and their definitions.
+The optional argument PREFIX, if non-nil, should be a key sequence;
+then we display only bindings that start with that prefix."
+  (interactive)
+  (gnus-article-check-buffer)
+  (let ((keymap (copy-keymap gnus-article-mode-map))
+       (map (copy-keymap gnus-article-send-map))
+       (sumkeys (where-is-internal 'gnus-article-read-summary-keys))
+       parent agent draft)
+    (define-key keymap "S" map)
+    (set-keymap-default-binding map nil)
+    (with-current-buffer gnus-article-current-summary
+      (set-keymap-parent
+       keymap
+       (if (setq parent (keymap-parent gnus-article-mode-map))
+          (prog1
+              (setq parent (copy-keymap parent))
+            (set-keymap-parent parent (current-local-map)))
+        (current-local-map)))
+      (let ((def (key-binding "S"))
+           gnus-pick-mode)
+       (set-keymap-parent map (if (symbolp def)
+                                  (symbol-value def)
+                                def))
+       (dolist (key sumkeys)
+         (when (setq def (key-binding key))
+           (define-key keymap key def))))
+      (when (boundp 'gnus-agent-summary-mode)
+       (setq agent gnus-agent-summary-mode))
+      (when (boundp 'gnus-draft-mode)
+       (setq draft gnus-draft-mode)))
+    (with-temp-buffer
+      (setq major-mode 'gnus-article-mode)
+      (use-local-map keymap)
+      (set (make-local-variable 'gnus-agent-summary-mode) agent)
+      (set (make-local-variable 'gnus-draft-mode) draft)
+      (describe-bindings prefix))))
+
+(defun gnus-xmas-define ()
+  (setq gnus-mouse-2 [button2])
+  (setq gnus-mouse-3 [button3])
+  (setq gnus-widget-button-keymap widget-button-keymap)
+
+  (unless (memq 'underline (face-list))
+    (and (fboundp 'make-face)
+        (funcall (intern "make-face") 'underline)))
+  ;; Must avoid calling set-face-underline-p directly, because it
+  ;; is a defsubst in emacs19, and will make the .elc files non
+  ;; portable!
+  (unless (face-differs-from-default-p 'underline)
+    (funcall (intern "set-face-underline-p") 'underline t))
+
+  (defalias 'gnus-kill-all-overlays 'gnus-xmas-kill-all-overlays)
+  (defalias 'gnus-extent-detached-p 'extent-detached-p)
+  (defalias 'gnus-add-text-properties 'gnus-xmas-add-text-properties)
+  (defalias 'gnus-put-text-property 'gnus-xmas-put-text-property)
+  (defalias 'gnus-deactivate-mark 'ignore)
+  (defalias 'gnus-window-edges 'window-pixel-edges)
+  (defalias 'gnus-assq-delete-all 'gnus-xmas-assq-delete-all)
+
+  (unless (fboundp 'member-ignore-case)
+    (defun member-ignore-case (elt list)
+      (while (and list
+                 (or (not (stringp (car list)))
+                     (not (string= (downcase elt) (downcase (car list))))))
+       (setq list (cdr list)))
+      list))
+
+  (unless (boundp 'standard-display-table)
+    (setq standard-display-table nil))
+
+  (defvar gnus-mouse-face-prop 'highlight)
+
+  (unless (fboundp 'match-string-no-properties)
+    (defalias 'match-string-no-properties 'match-string))
+
+  (unless (fboundp 'char-width)
+    (defalias 'char-width (lambda (ch) 1))))
+
+(defun gnus-xmas-redefine ()
+  "Redefine lots of Gnus functions for XEmacs."
+  (defalias 'gnus-summary-set-display-table 'gnus-xmas-summary-set-display-table)
+  (defalias 'gnus-visual-turn-off-edit-menu 'identity)
+  (defalias 'gnus-summary-recenter 'gnus-xmas-summary-recenter)
+  (defalias 'gnus-extent-start-open 'gnus-xmas-extent-start-open)
+  (defalias 'gnus-article-push-button 'gnus-xmas-article-push-button)
+  (defalias 'gnus-window-top-edge 'gnus-xmas-window-top-edge)
+  (defalias 'gnus-read-event-char 'gnus-xmas-read-event-char)
+  (defalias 'gnus-group-startup-message 'gnus-xmas-group-startup-message)
+  (defalias 'gnus-tree-minimize 'gnus-xmas-tree-minimize)
+  (defalias 'gnus-select-lowest-window
+    'gnus-xmas-select-lowest-window)
+  (defalias 'gnus-mail-strip-quoted-names 'gnus-xmas-mail-strip-quoted-names)
+  (defalias 'gnus-character-to-event 'character-to-event)
+  (defalias 'gnus-mode-line-buffer-identification
+    'gnus-xmas-mode-line-buffer-identification)
+  (defalias 'gnus-key-press-event-p 'key-press-event-p)
+  (defalias 'gnus-region-active-p 'region-active-p)
+  (defalias 'gnus-mark-active-p 'region-exists-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-mime-security-button-menu
+    'gnus-xmas-mime-security-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)
+  (defalias 'gnus-article-describe-bindings
+    'gnus-xmas-article-describe-bindings)
+
+  ;; 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
+  ;; where each variable is defined, in order not to mess with user settings.
+  ;; -- didier
+  (add-hook 'gnus-score-mode-hook 'gnus-xmas-score-menu-add)
+  (add-hook 'gnus-binary-mode-hook 'gnus-xmas-binary-menu-add)
+  (add-hook 'gnus-server-mode-hook 'gnus-xmas-server-menu-add)
+  (add-hook 'gnus-browse-mode-hook 'gnus-xmas-browse-menu-add)
+  (add-hook 'gnus-draft-mode-hook 'gnus-xmas-draft-menu-add)
+  (add-hook 'gnus-mailing-list-mode-hook 'gnus-xmas-mailing-list-menu-add))
+
+
+;;; XEmacs logo and toolbar.
+
+(defun gnus-xmas-group-startup-message (&optional x y)
+  "Insert startup message in current buffer."
+  ;; Insert the message.
+  (erase-buffer)
+  (cond
+   ((and (console-on-window-system-p)
+        (or (featurep 'xpm)
+            (featurep 'xbm)))
+    (let* ((logo-xpm (expand-file-name "gnus.xpm" gnus-xmas-glyph-directory))
+          (logo-xbm (expand-file-name "gnus.xbm" gnus-xmas-glyph-directory))
+          (glyph (make-glyph
+                  (cond ((featurep 'xpm)
+                         `[xpm
+                           :file ,logo-xpm
+                           :color-symbols
+                           (("thing" . ,(car gnus-logo-colors))
+                            ("shadow" . ,(cadr gnus-logo-colors))
+                            ("oort" . "#eeeeee")
+                            ("background" . ,(face-background 'default)))])
+                        ((featurep 'xbm)
+                         `[xbm :file ,logo-xbm])
+                        (t [nothing])))))
+      (insert " ")
+      (set-extent-begin-glyph (make-extent (point) (point)) glyph)
+      (goto-char (point-min))
+      (while (not (eobp))
+       (insert (make-string (/ (max (- (window-width) (or x 35)) 0) 2)
+                            ?\ ))
+       (forward-line 1)))
+    (goto-char (point-min))
+    (let* ((pheight (+ 20 (count-lines (point-min) (point-max))))
+          (wheight (window-height))
+          (rest (- wheight pheight)))
+      (insert (make-string (max 0 (* 2 (/ rest 3))) ?\n))))
+   (t
+    (insert
+     (format "              %s
+          _    ___ _             _
+          _ ___ __ ___  __    _ ___
+          __   _     ___    __  ___
+              _           ___     _
+             _  _ __             _
+             ___   __            _
+                   __           _
+                    _      _   _
+                   _      _    _
+                      _  _    _
+                  __  ___
+                 _   _ _     _
+                _   _
+              _    _
+             _    _
+            _
+          __
+
+"
+            ""))
+    ;; And then hack it.
+    (gnus-indent-rigidly (point-min) (point-max)
+                        (/ (max (- (window-width) (or x 46)) 0) 2))
+    (goto-char (point-min))
+    (forward-line 1)
+    (let* ((pheight (count-lines (point-min) (point-max)))
+          (wheight (window-height))
+          (rest (- wheight pheight)))
+      (insert (make-string (max 0 (* 2 (/ rest 3))) ?\n)))
+    ;; Paint it.
+    (put-text-property (point-min) (point-max) 'face 'gnus-splash)))
+  (setq modeline-buffer-identification
+       (list (concat gnus-version ": *Group*")))
+  (set-buffer-modified-p t))
+
+
+;;; The toolbar.
+
+(defun gnus-xmas-update-toolbars ()
+  "Update the toolbars' appearance."
+  (when (and (not noninteractive)
+            (featurep 'gnus-xmas))
+    (save-excursion
+      (dolist (buffer (buffer-list))
+       (set-buffer buffer)
+       (cond ((eq major-mode 'gnus-group-mode)
+              (gnus-xmas-setup-group-toolbar))
+             ((eq major-mode 'gnus-summary-mode)
+              (gnus-xmas-setup-summary-toolbar)))))))
+
+(defcustom gnus-use-toolbar (if (featurep 'toolbar) 'default)
+  "*Position to display the toolbar.  Nil means do not use a toolbar.
+If it is non-nil, it should be one of the symbols `default', `top',
+`bottom', `right', and `left'.  `default' means to use the default
+toolbar, the rest mean to display the toolbar on the place which those
+names show."
+  :type '(choice (const default)
+                (const top) (const bottom) (const left) (const right)
+                (const :tag "no toolbar" nil))
+  :set (lambda (symbol value)
+        (set-default
+         symbol
+         (if (or (not value)
+                 (memq value (list 'default 'top 'bottom 'right 'left)))
+             value
+           'default))
+        (gnus-xmas-update-toolbars))
+  :group 'gnus-xmas)
+
+(defcustom gnus-toolbar-thickness
+  (if (featurep 'toolbar)
+      (cons (specifier-instance default-toolbar-height)
+           (specifier-instance default-toolbar-width)))
+  "*Cons of the height and the width specifying the thickness of a toolbar.
+The height is used for the toolbar displayed on the top or the bottom,
+the width is used for the toolbar displayed on the right or the left."
+  :type '(cons :tag "height & width"
+              (integer :tag "height") (integer :tag "width"))
+  :set (lambda (symbol value)
+        (set-default
+         symbol
+         (if (and (consp value) (natnump (car value)) (natnump (cdr value)))
+             value
+           '(37 . 40)))
+        (gnus-xmas-update-toolbars))
+  :group 'gnus-xmas)
+
+(defvar gnus-group-toolbar
+  '([gnus-group-get-new-news gnus-group-get-new-news t "Get new news"]
+    [gnus-group-get-new-news-this-group
+     gnus-group-get-new-news-this-group t "Get new news in this group"]
+    [gnus-group-catchup-current
+     gnus-group-catchup-current t "Catchup group"]
+    [gnus-group-describe-group
+     gnus-group-describe-group t "Describe group"]
+    [gnus-group-unsubscribe gnus-group-unsubscribe t "Unsubscribe group"]
+    [gnus-group-subscribe gnus-group-subscribe t "Subscribe group"]
+    [gnus-group-kill-group gnus-group-kill-group t "Kill group"]
+    [gnus-summary-mail-save
+     gnus-group-save-newsrc t "Save .newsrc files"] ; borrowed icon.
+    [gnus-group-exit gnus-group-exit t "Exit Gnus"])
+  "The group buffer toolbar.")
+
+(defvar gnus-summary-toolbar
+  '([gnus-summary-prev-unread
+     gnus-summary-prev-page-or-article t "Page up"]
+    [gnus-summary-next-unread
+     gnus-summary-next-page t "Page down"]
+    [gnus-summary-post-news
+     gnus-summary-post-news t "Post an article"]
+    [gnus-summary-followup-with-original
+     gnus-summary-followup-with-original t
+     "Post a followup and yank the original"]
+    [gnus-summary-followup
+     gnus-summary-followup t "Post a followup"]
+    [gnus-summary-reply-with-original
+     gnus-summary-reply-with-original t "Mail a reply and yank the original"]
+    [gnus-summary-reply
+     gnus-summary-reply t "Mail a reply"]
+    [gnus-summary-caesar-message
+     gnus-summary-caesar-message t "Rot 13"]
+    [gnus-uu-decode-uu
+     gnus-uu-decode-uu t "Decode uuencoded articles"]
+    [gnus-summary-save-article-file
+     gnus-summary-save-article-file t "Save article in file"]
+    [gnus-summary-save-article
+     gnus-summary-save-article t "Save article"]
+    [gnus-uu-post-news
+     gnus-uu-post-news t "Post a uuencoded article"]
+    [gnus-summary-cancel-article
+     gnus-summary-cancel-article t "Cancel article"]
+    [gnus-summary-catchup
+     gnus-summary-catchup t "Catchup"]
+    [gnus-summary-catchup-and-exit
+     gnus-summary-catchup-and-exit t "Catchup and exit"]
+    [gnus-summary-exit gnus-summary-exit t "Exit this summary"])
+  "The summary buffer toolbar.")
+
+(defvar gnus-summary-mail-toolbar
+  '(
+    [gnus-summary-prev-unread
+     gnus-summary-prev-unread-article t "Prev unread article"]
+    [gnus-summary-next-unread
+     gnus-summary-next-unread-article t "Next unread article"]
+    [gnus-summary-mail-reply gnus-summary-reply t "Reply"]
+    [gnus-summary-mail-originate gnus-summary-post-news t "Originate"]
+    [gnus-summary-mail-save gnus-summary-save-article t "Save"]
+    [gnus-summary-mail-copy gnus-summary-copy-article t "Copy message"]
+    [gnus-summary-mail-forward gnus-summary-mail-forward t "Forward message"]
+    [gnus-summary-caesar-message
+     gnus-summary-caesar-message t "Rot 13"]
+    [gnus-uu-decode-uu
+     gnus-uu-decode-uu t "Decode uuencoded articles"]
+    [gnus-summary-save-article-file
+     gnus-summary-save-article-file t "Save article in file"]
+    [gnus-summary-save-article
+     gnus-summary-save-article t "Save article"]
+    [gnus-summary-cancel-article ; usenet : cancellation :: mail : deletion.
+     gnus-summary-delete-article t "Delete message"]
+    [gnus-summary-catchup
+     gnus-summary-catchup t "Catchup"]
+    [gnus-summary-catchup-and-exit
+     gnus-summary-catchup-and-exit t "Catchup and exit"]
+    [gnus-summary-exit gnus-summary-exit t "Exit this summary"])
+  "The summary buffer mail toolbar.")
+
+(defun gnus-xmas-setup-toolbar (toolbar)
+  (when (featurep 'toolbar)
+    (if (and gnus-use-toolbar
+            (message-xmas-setup-toolbar toolbar nil "gnus"))
+       (let ((bar (or (intern-soft (format "%s-toolbar" gnus-use-toolbar))
+                      'default-toolbar))
+             (height (car gnus-toolbar-thickness))
+             (width (cdr gnus-toolbar-thickness))
+             (cur (current-buffer))
+             bars)
+         (set-specifier (symbol-value bar) toolbar cur)
+         (set-specifier default-toolbar-height height cur)
+         (set-specifier default-toolbar-width width cur)
+         (set-specifier top-toolbar-height height cur)
+         (set-specifier bottom-toolbar-height height cur)
+         (set-specifier right-toolbar-width width cur)
+         (set-specifier left-toolbar-width width cur)
+         (if (eq bar 'default-toolbar)
+             (progn
+               (remove-specifier default-toolbar-visible-p cur)
+               (remove-specifier top-toolbar cur)
+               (remove-specifier top-toolbar-visible-p cur)
+               (remove-specifier bottom-toolbar cur)
+               (remove-specifier bottom-toolbar-visible-p cur)
+               (remove-specifier right-toolbar cur)
+               (remove-specifier right-toolbar-visible-p cur)
+               (remove-specifier left-toolbar cur)
+               (remove-specifier left-toolbar-visible-p cur))
+           (set-specifier (symbol-value (intern (format "%s-visible-p" bar)))
+                          t cur)
+           (setq bars (delq bar (list 'default-toolbar
+                                      'bottom-toolbar 'top-toolbar
+                                      'right-toolbar 'left-toolbar)))
+           (while bars
+             (set-specifier (symbol-value (intern (format "%s-visible-p"
+                                                          (pop bars))))
+                            nil cur))))
+      (let ((cur (current-buffer)))
+       (set-specifier default-toolbar-visible-p nil cur)
+       (set-specifier top-toolbar-visible-p nil cur)
+       (set-specifier bottom-toolbar-visible-p nil cur)
+       (set-specifier right-toolbar-visible-p nil cur)
+       (set-specifier left-toolbar-visible-p nil cur)))))
+
+(defun gnus-xmas-setup-group-toolbar ()
+  (gnus-xmas-setup-toolbar gnus-group-toolbar))
+
+(defun gnus-xmas-setup-summary-toolbar ()
+  (gnus-xmas-setup-toolbar (if (gnus-news-group-p gnus-newsgroup-name)
+                              gnus-summary-toolbar
+                            gnus-summary-mail-toolbar)))
+
+(defun gnus-xmas-mail-strip-quoted-names (address)
+  "Protect mail-strip-quoted-names from nil input.
+XEmacs compatibility workaround."
+  (if (null address)
+      nil
+    (mail-strip-quoted-names address)))
+
+(defvar gnus-xmas-modeline-left-extent
+  (let ((ext (copy-extent modeline-buffer-id-left-extent)))
+    ext))
+
+(defvar gnus-xmas-modeline-right-extent
+  (let ((ext (copy-extent modeline-buffer-id-right-extent)))
+    ext))
+
+(defvar gnus-xmas-modeline-glyph
+  (progn
+    (let* ((file-xpm (expand-file-name "gnus-pointer.xpm"
+                                      gnus-xmas-glyph-directory))
+          (file-xbm (expand-file-name "gnus-pointer.xbm"
+                                      gnus-xmas-glyph-directory))
+          (glyph (make-glyph
+                  ;; Gag gag gag.
+                  (cond ((featurep 'xpm)
+                         ;; Let's try a nifty XPM
+                         `[xpm :file ,file-xpm])
+                        ((featurep 'xbm)
+                         ;; Then a not-so-nifty XBM
+                         `[xbm :file ,file-xbm])
+                        ;; Then the simple string
+                        (t [string :data "Gnus:"])))))
+      (set-glyph-face glyph 'modeline-buffer-id)
+      glyph)))
+
+(defun gnus-xmas-mode-line-buffer-identification (line)
+  (let ((line (car line))
+       chop)
+    (cond
+     ;; This is some weird type of id.
+     ((not (stringp line))
+      (list line))
+     ;; This is non-standard, so we just pass it through.
+     ((not (string-match "^Gnus:" line))
+      (list line))
+     ;; We have a standard line, so we colorize and glyphize it a bit.
+     (t
+      (setq chop (match-end 0))
+      (list
+       (if gnus-xmas-modeline-glyph
+          (cons gnus-xmas-modeline-left-extent gnus-xmas-modeline-glyph)
+        (cons gnus-xmas-modeline-left-extent (substring line 0 chop)))
+       (cons gnus-xmas-modeline-right-extent (substring line chop)))))))
+
+(defun gnus-xmas-annotation-in-region-p (b e)
+  (or (map-extents (lambda (e u) t) nil b e nil nil 'mm t)
+      (if (= b e)
+         (eq (cadr (memq 'gnus-undeletable (text-properties-at b))) t)
+       (text-property-any b e 'gnus-undeletable t))))
+
+(defun gnus-xmas-mime-button-menu (event prefix)
+  "Construct a context-sensitive menu of MIME commands."
+  (interactive "e\nP")
+  (let ((response (get-popup-menu-response
+                  `("MIME Part"
+                    ,@(mapcar (lambda (c) `[,(caddr c) ,(car c) t])
+                              gnus-mime-button-commands)))))
+    (set-buffer (event-buffer event))
+    (goto-char (event-point event))
+    (funcall (event-function response) (event-object response))))
+
+(defun gnus-xmas-mime-security-button-menu (event prefix)
+  "Construct a context-sensitive menu of security commands."
+  (interactive "e\nP")
+  (let ((response
+        (get-popup-menu-response
+         `("Security Part"
+           ,@(delq nil
+                   (mapcar (lambda (c)
+                             (unless (eq (car c) 'undefined)
+                               `[,(caddr c) ,(car c) t]))
+                           gnus-mime-security-button-commands))))))
+    (set-buffer (event-buffer event))
+    (goto-char (event-point event))
+    (funcall (event-function response) (event-object response))))
+
+(defun gnus-xmas-mailing-list-menu-add ()
+  (gnus-xmas-menu-add mailing-list
+                     gnus-mailing-list-menu))
+
+(defun gnus-xmas-image-type-available-p (type)
+  (and (if (fboundp 'display-images-p)
+          (display-images-p)
+        window-system)
+       (featurep (if (eq type 'pbm) 'xbm type))))
+
+(defun gnus-xmas-create-image (file &optional type data-p &rest props)
+  (let ((type (cond
+              (type
+               (symbol-name type))
+              ((and (not data-p)
+                    (string-match "[.]" file))
+               (car (last (split-string file "[.]"))))))
+       (face (plist-get props :face))
+       glyph)
+    (when (equal type "pbm")
+      (with-temp-buffer
+       (if data-p
+           (insert file)
+         (insert-file-contents-literally file))
+       (shell-command-on-region (point-min) (point-max)
+                                "ppmtoxpm 2>/dev/null" t)
+       (setq file (buffer-string)
+             type "xpm"
+             data-p t)))
+    (setq glyph
+         (if (equal type "xbm")
+             (make-glyph (list (cons 'x file)))
+           (with-temp-buffer
+             (if data-p
+                 (insert file)
+               (insert-file-contents-literally file))
+             (make-glyph
+              (vector
+               (if type
+                   (intern type)
+                 (mm-image-type-from-buffer))
+               :data (buffer-string))))))
+    (when face
+      (set-glyph-face glyph face))
+    glyph))
+
+(defun gnus-xmas-put-image (glyph &optional string category)
+  "Insert STRING, but display GLYPH.
+Warning: Don't insert text immediately after the image."
+  (let ((begin (point))
+       extent)
+    (if (and (bobp) (not string))
+       (setq string " "))
+    (if string
+       (insert string)
+      (setq begin (1- begin)))
+    (setq extent (make-extent begin (point)))
+    (set-extent-property extent 'gnus-image category)
+    (set-extent-property extent 'duplicable t)
+    (if string
+       (set-extent-property extent 'invisible t))
+    (set-extent-property extent 'end-glyph glyph))
+  glyph)
+
+(defun gnus-xmas-remove-image (image &optional category)
+  "Remove the image matching IMAGE and CATEGORY found first."
+  (map-extents
+   (lambda (ext unused)
+     (when (equal (extent-end-glyph ext) image)
+       (set-extent-property ext 'invisible nil)
+       (set-extent-property ext 'end-glyph nil)
+       t))
+   nil nil nil nil nil 'gnus-image category))
+
+(defun gnus-xmas-assq-delete-all (key alist)
+  (let ((elem nil))
+    (while (setq elem (assq key alist))
+      (setq alist (delq elem alist)))
+    alist))
+
+(provide 'gnus-xmas)
+
+;;; gnus-xmas.el ends here
diff --git a/xemacs-packages/gnus/lisp/gnus.el b/xemacs-packages/gnus/lisp/gnus.el
new file mode 100644 (file)
index 0000000..19807fc
--- /dev/null
@@ -0,0 +1,4443 @@
+;;; gnus.el --- a newsreader for GNU Emacs
+
+;; Copyright (C) 1987-1990, 1993-1998, 2000-2016 Free Software
+;; Foundation, Inc.
+
+;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
+;;     Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: news, mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval '(run-hooks 'gnus-load-hook))
+
+(eval-when-compile (require 'cl))
+(require 'wid-edit)
+(require 'mm-util)
+(require 'nnheader)
+(require 'gnus-compat)
+
+;; These are defined afterwards with gnus-define-group-parameter
+(defvar gnus-ham-process-destinations)
+(defvar gnus-parameter-ham-marks-alist)
+(defvar gnus-parameter-spam-marks-alist)
+(defvar gnus-spam-autodetect)
+(defvar gnus-spam-autodetect-methods)
+(defvar gnus-spam-newsgroup-contents)
+(defvar gnus-spam-process-destinations)
+(defvar gnus-spam-resend-to)
+(defvar gnus-ham-resend-to)
+(defvar gnus-spam-process-newsgroups)
+
+
+(defgroup gnus nil
+  "The coffee-brewing, all singing, all dancing, kitchen sink newsreader."
+  :group 'news
+  :group 'mail)
+
+(defgroup gnus-start nil
+  "Starting your favorite newsreader."
+  :group 'gnus)
+
+(defgroup gnus-format nil
+  "Dealing with formatting issues."
+  :group 'gnus)
+
+(defgroup gnus-charset nil
+  "Group character set issues."
+  :link '(custom-manual "(gnus)Charsets")
+  :version "21.1"
+  :group 'gnus)
+
+(defgroup gnus-cache nil
+  "Cache interface."
+  :link '(custom-manual "(gnus)Article Caching")
+  :group 'gnus)
+
+(defgroup gnus-registry nil
+  "Article Registry."
+  :group 'gnus)
+
+(defgroup gnus-start-server nil
+  "Server options at startup."
+  :group 'gnus-start)
+
+;; These belong to gnus-group.el.
+(defgroup gnus-group nil
+  "Group buffers."
+  :link '(custom-manual "(gnus)Group Buffer")
+  :group 'gnus)
+
+(defgroup gnus-group-foreign nil
+  "Foreign groups."
+  :link '(custom-manual "(gnus)Foreign Groups")
+  :group 'gnus-group)
+
+(defgroup gnus-group-new nil
+  "Automatic subscription of new groups."
+  :group 'gnus-group)
+
+(defgroup gnus-group-levels nil
+  "Group levels."
+  :link '(custom-manual "(gnus)Group Levels")
+  :group 'gnus-group)
+
+(defgroup gnus-group-select nil
+  "Selecting a Group."
+  :link '(custom-manual "(gnus)Selecting a Group")
+  :group 'gnus-group)
+
+(defgroup gnus-group-listing nil
+  "Showing slices of the group list."
+  :link '(custom-manual "(gnus)Listing Groups")
+  :group 'gnus-group)
+
+(defgroup gnus-group-visual nil
+  "Sorting the group buffer."
+  :link '(custom-manual "(gnus)Group Buffer Format")
+  :group 'gnus-group
+  :group 'gnus-visual)
+
+(defgroup gnus-group-various nil
+  "Various group options."
+  :link '(custom-manual "(gnus)Scanning New Messages")
+  :group 'gnus-group)
+
+;; These belong to gnus-sum.el.
+(defgroup gnus-summary nil
+  "Summary buffers."
+  :link '(custom-manual "(gnus)Summary Buffer")
+  :group 'gnus)
+
+(defgroup gnus-summary-exit nil
+  "Leaving summary buffers."
+  :link '(custom-manual "(gnus)Exiting the Summary Buffer")
+  :group 'gnus-summary)
+
+(defgroup gnus-summary-marks nil
+  "Marks used in summary buffers."
+  :link '(custom-manual "(gnus)Marking Articles")
+  :group 'gnus-summary)
+
+(defgroup gnus-thread nil
+  "Ordering articles according to replies."
+  :link '(custom-manual "(gnus)Threading")
+  :group 'gnus-summary)
+
+(defgroup gnus-summary-format nil
+  "Formatting of the summary buffer."
+  :link '(custom-manual "(gnus)Summary Buffer Format")
+  :group 'gnus-summary)
+
+(defgroup gnus-summary-choose nil
+  "Choosing Articles."
+  :link '(custom-manual "(gnus)Choosing Articles")
+  :group 'gnus-summary)
+
+(defgroup gnus-summary-maneuvering nil
+  "Summary movement commands."
+  :link '(custom-manual "(gnus)Summary Maneuvering")
+  :group 'gnus-summary)
+
+(defgroup gnus-picon nil
+  "Show pictures of people, domains, and newsgroups."
+  :group 'gnus-visual)
+
+(defgroup gnus-summary-mail nil
+  "Mail group commands."
+  :link '(custom-manual "(gnus)Mail Group Commands")
+  :group 'gnus-summary)
+
+(defgroup gnus-summary-sort nil
+  "Sorting the summary buffer."
+  :link '(custom-manual "(gnus)Sorting the Summary Buffer")
+  :group 'gnus-summary)
+
+(defgroup gnus-summary-visual nil
+  "Highlighting and menus in the summary buffer."
+  :link '(custom-manual "(gnus)Summary Highlighting")
+  :group 'gnus-visual
+  :group 'gnus-summary)
+
+(defgroup gnus-summary-various nil
+  "Various summary buffer options."
+  :link '(custom-manual "(gnus)Various Summary Stuff")
+  :group 'gnus-summary)
+
+(defgroup gnus-summary-pick nil
+  "Pick mode in the summary buffer."
+  :link '(custom-manual "(gnus)Pick and Read")
+  :prefix "gnus-pick-"
+  :group 'gnus-summary)
+
+(defgroup gnus-summary-tree nil
+  "Tree display of threads in the summary buffer."
+  :link '(custom-manual "(gnus)Tree Display")
+  :prefix "gnus-tree-"
+  :group 'gnus-summary)
+
+;; Belongs to gnus-uu.el
+(defgroup gnus-extract-view nil
+  "Viewing extracted files."
+  :link '(custom-manual "(gnus)Viewing Files")
+  :group 'gnus-extract)
+
+;; Belongs to gnus-score.el
+(defgroup gnus-score nil
+  "Score and kill file handling."
+  :group 'gnus)
+
+(defgroup gnus-score-kill nil
+  "Kill files."
+  :group 'gnus-score)
+
+(defgroup gnus-score-adapt nil
+  "Adaptive score files."
+  :group 'gnus-score)
+
+(defgroup gnus-score-default nil
+  "Default values for score files."
+  :group 'gnus-score)
+
+(defgroup gnus-score-expire nil
+  "Expiring score rules."
+  :group 'gnus-score)
+
+(defgroup gnus-score-decay nil
+  "Decaying score rules."
+  :group 'gnus-score)
+
+(defgroup gnus-score-files nil
+  "Score and kill file names."
+  :group 'gnus-score
+  :group 'gnus-files)
+
+(defgroup gnus-score-various nil
+  "Various scoring and killing options."
+  :group 'gnus-score)
+
+;; Other
+(defgroup gnus-visual nil
+  "Options controlling the visual fluff."
+  :group 'gnus
+  :group 'faces)
+
+(defgroup gnus-agent nil
+  "Offline support for Gnus."
+  :group 'gnus)
+
+(defgroup gnus-files nil
+  "Files used by Gnus."
+  :group 'gnus)
+
+(defgroup gnus-dribble-file nil
+  "Auto save file."
+  :link '(custom-manual "(gnus)Auto Save")
+  :group 'gnus-files)
+
+(defgroup gnus-newsrc nil
+  "Storing Gnus state."
+  :group 'gnus-files)
+
+(defgroup gnus-server nil
+  "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)
+
+(defgroup gnus-meta nil
+  "Meta variables controlling major portions of Gnus.
+In general, modifying these variables does not take effect until Gnus
+is restarted, and sometimes reloaded."
+  :group 'gnus)
+
+(defgroup gnus-various nil
+  "Other Gnus options."
+  :link '(custom-manual "(gnus)Various Various")
+  :group 'gnus)
+
+(defgroup gnus-exit nil
+  "Exiting Gnus."
+  :link '(custom-manual "(gnus)Exiting Gnus")
+  :group 'gnus)
+
+(defgroup gnus-fun nil
+  "Frivolous Gnus extensions."
+  :link '(custom-manual "(gnus)Exiting Gnus")
+  :group 'gnus)
+
+(defconst gnus-version-number "0.14"
+  "Version number for this version of Gnus.")
+
+(defconst gnus-version (format "Ma Gnus v%s" gnus-version-number)
+  "Version string for this version of Gnus.")
+
+(defcustom gnus-inhibit-startup-message nil
+  "If non-nil, the startup message will not be displayed.
+This variable is used before `.gnus.el' is loaded, so it should
+be set in `.emacs' instead."
+  :group 'gnus-start
+  :type 'boolean)
+
+(unless (featurep 'gnus-xmas)
+  (defalias 'gnus-extent-detached-p 'ignore)
+  (defalias 'gnus-extent-start-open 'ignore)
+  (defalias 'gnus-mail-strip-quoted-names 'mail-strip-quoted-names)
+  (defalias 'gnus-character-to-event 'identity)
+  (defalias 'gnus-assq-delete-all 'assq-delete-all)
+  (defalias 'gnus-add-text-properties 'add-text-properties)
+  (defalias 'gnus-put-text-property 'put-text-property)
+  (defvar gnus-mode-line-image-cache t)
+  (if (fboundp 'find-image)
+      (defun gnus-mode-line-buffer-identification (line)
+       (let ((str (car-safe line))
+             (load-path (append (mm-image-load-path) load-path)))
+         (if (and (display-graphic-p)
+                  (stringp str)
+                  (string-match "^Gnus:" str))
+             (progn (add-text-properties
+                     0 5
+                     (list 'display
+                           (if (eq t gnus-mode-line-image-cache)
+                               (setq gnus-mode-line-image-cache
+                                     (find-image
+                                      '((:type xpm :file "gnus-pointer.xpm"
+                                               :ascent center)
+                                        (:type xbm :file "gnus-pointer.xbm"
+                                               :ascent center))))
+                             gnus-mode-line-image-cache)
+                           'help-echo (format
+                                       "This is %s, %s."
+                                       gnus-version (gnus-emacs-version)))
+                     str)
+                    (list str))
+           line)))
+    (defalias 'gnus-mode-line-buffer-identification 'identity))
+  (defalias 'gnus-deactivate-mark 'deactivate-mark)
+  (defalias 'gnus-window-edges 'window-edges)
+  (defalias 'gnus-key-press-event-p 'numberp)
+  ;;(defalias 'gnus-decode-rfc1522 'ignore)
+  )
+
+;; We define these group faces here to avoid the display
+;; update forced when creating new faces.
+
+(defface gnus-group-news-1
+  '((((class color)
+      (background dark))
+     (:foreground "PaleTurquoise" :bold t))
+    (((class color)
+      (background light))
+     (:foreground "ForestGreen" :bold t))
+    (t
+     ()))
+  "Level 1 newsgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-news-1-face 'face-alias 'gnus-group-news-1)
+(put 'gnus-group-news-1-face 'obsolete-face "22.1")
+
+(defface gnus-group-news-1-empty
+  '((((class color)
+      (background dark))
+     (:foreground "PaleTurquoise"))
+    (((class color)
+      (background light))
+     (:foreground "ForestGreen"))
+    (t
+     ()))
+  "Level 1 empty newsgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-news-1-empty-face 'face-alias 'gnus-group-news-1-empty)
+(put 'gnus-group-news-1-empty-face 'obsolete-face "22.1")
+
+(defface gnus-group-news-2
+  '((((class color)
+      (background dark))
+     (:foreground "turquoise" :bold t))
+    (((class color)
+      (background light))
+     (:foreground "CadetBlue4" :bold t))
+    (t
+     ()))
+  "Level 2 newsgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-news-2-face 'face-alias 'gnus-group-news-2)
+(put 'gnus-group-news-2-face 'obsolete-face "22.1")
+
+(defface gnus-group-news-2-empty
+  '((((class color)
+      (background dark))
+     (:foreground "turquoise"))
+    (((class color)
+      (background light))
+     (:foreground "CadetBlue4"))
+    (t
+     ()))
+  "Level 2 empty newsgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-news-2-empty-face 'face-alias 'gnus-group-news-2-empty)
+(put 'gnus-group-news-2-empty-face 'obsolete-face "22.1")
+
+(defface gnus-group-news-3
+  '((((class color)
+      (background dark))
+     (:bold t))
+    (((class color)
+      (background light))
+     (:bold t))
+    (t
+     ()))
+  "Level 3 newsgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-news-3-face 'face-alias 'gnus-group-news-3)
+(put 'gnus-group-news-3-face 'obsolete-face "22.1")
+
+(defface gnus-group-news-3-empty
+  '((((class color)
+      (background dark))
+     ())
+    (((class color)
+      (background light))
+     ())
+    (t
+     ()))
+  "Level 3 empty newsgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-news-3-empty-face 'face-alias 'gnus-group-news-3-empty)
+(put 'gnus-group-news-3-empty-face 'obsolete-face "22.1")
+
+(defface gnus-group-news-4
+  '((((class color)
+      (background dark))
+     (:bold t))
+    (((class color)
+      (background light))
+     (:bold t))
+    (t
+     ()))
+  "Level 4 newsgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-news-4-face 'face-alias 'gnus-group-news-4)
+(put 'gnus-group-news-4-face 'obsolete-face "22.1")
+
+(defface gnus-group-news-4-empty
+  '((((class color)
+      (background dark))
+     ())
+    (((class color)
+      (background light))
+     ())
+    (t
+     ()))
+  "Level 4 empty newsgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-news-4-empty-face 'face-alias 'gnus-group-news-4-empty)
+(put 'gnus-group-news-4-empty-face 'obsolete-face "22.1")
+
+(defface gnus-group-news-5
+  '((((class color)
+      (background dark))
+     (:bold t))
+    (((class color)
+      (background light))
+     (:bold t))
+    (t
+     ()))
+  "Level 5 newsgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-news-5-face 'face-alias 'gnus-group-news-5)
+(put 'gnus-group-news-5-face 'obsolete-face "22.1")
+
+(defface gnus-group-news-5-empty
+  '((((class color)
+      (background dark))
+     ())
+    (((class color)
+      (background light))
+     ())
+    (t
+     ()))
+  "Level 5 empty newsgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-news-5-empty-face 'face-alias 'gnus-group-news-5-empty)
+(put 'gnus-group-news-5-empty-face 'obsolete-face "22.1")
+
+(defface gnus-group-news-6
+  '((((class color)
+      (background dark))
+     (:bold t))
+    (((class color)
+      (background light))
+     (:bold t))
+    (t
+     ()))
+  "Level 6 newsgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-news-6-face 'face-alias 'gnus-group-news-6)
+(put 'gnus-group-news-6-face 'obsolete-face "22.1")
+
+(defface gnus-group-news-6-empty
+  '((((class color)
+      (background dark))
+     ())
+    (((class color)
+      (background light))
+     ())
+    (t
+     ()))
+  "Level 6 empty newsgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-news-6-empty-face 'face-alias 'gnus-group-news-6-empty)
+(put 'gnus-group-news-6-empty-face 'obsolete-face "22.1")
+
+(defface gnus-group-news-low
+  '((((class color)
+      (background dark))
+     (:foreground "DarkTurquoise" :bold t))
+    (((class color)
+      (background light))
+     (:foreground "DarkGreen" :bold t))
+    (t
+     ()))
+  "Low level newsgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-news-low-face 'face-alias 'gnus-group-news-low)
+(put 'gnus-group-news-low-face 'obsolete-face "22.1")
+
+(defface gnus-group-news-low-empty
+  '((((class color)
+      (background dark))
+     (:foreground "DarkTurquoise"))
+    (((class color)
+      (background light))
+     (:foreground "DarkGreen"))
+    (t
+     ()))
+  "Low level empty newsgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-news-low-empty-face 'face-alias 'gnus-group-news-low-empty)
+(put 'gnus-group-news-low-empty-face 'obsolete-face "22.1")
+
+(defface gnus-group-mail-1
+  '((((class color)
+      (background dark))
+     (:foreground "#e1ffe1" :bold t))
+    (((class color)
+      (background light))
+     (:foreground "DeepPink3" :bold t))
+    (t
+     (:bold t)))
+  "Level 1 mailgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-mail-1-face 'face-alias 'gnus-group-mail-1)
+(put 'gnus-group-mail-1-face 'obsolete-face "22.1")
+
+(defface gnus-group-mail-1-empty
+  '((((class color)
+      (background dark))
+     (:foreground "#e1ffe1"))
+    (((class color)
+      (background light))
+     (:foreground "DeepPink3"))
+    (t
+     (:italic t :bold t)))
+  "Level 1 empty mailgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-mail-1-empty-face 'face-alias 'gnus-group-mail-1-empty)
+(put 'gnus-group-mail-1-empty-face 'obsolete-face "22.1")
+
+(defface gnus-group-mail-2
+  '((((class color)
+      (background dark))
+     (:foreground "DarkSeaGreen1" :bold t))
+    (((class color)
+      (background light))
+     (:foreground "HotPink3" :bold t))
+    (t
+     (:bold t)))
+  "Level 2 mailgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-mail-2-face 'face-alias 'gnus-group-mail-2)
+(put 'gnus-group-mail-2-face 'obsolete-face "22.1")
+
+(defface gnus-group-mail-2-empty
+  '((((class color)
+      (background dark))
+     (:foreground "DarkSeaGreen1"))
+    (((class color)
+      (background light))
+     (:foreground "HotPink3"))
+    (t
+     (:bold t)))
+  "Level 2 empty mailgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-mail-2-empty-face 'face-alias 'gnus-group-mail-2-empty)
+(put 'gnus-group-mail-2-empty-face 'obsolete-face "22.1")
+
+(defface gnus-group-mail-3
+  '((((class color)
+      (background dark))
+     (:foreground "aquamarine1" :bold t))
+    (((class color)
+      (background light))
+     (:foreground "magenta4" :bold t))
+    (t
+     (:bold t)))
+  "Level 3 mailgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-mail-3-face 'face-alias 'gnus-group-mail-3)
+(put 'gnus-group-mail-3-face 'obsolete-face "22.1")
+
+(defface gnus-group-mail-3-empty
+  '((((class color)
+      (background dark))
+     (:foreground "aquamarine1"))
+    (((class color)
+      (background light))
+     (:foreground "magenta4"))
+    (t
+     ()))
+  "Level 3 empty mailgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-mail-3-empty-face 'face-alias 'gnus-group-mail-3-empty)
+(put 'gnus-group-mail-3-empty-face 'obsolete-face "22.1")
+
+(defface gnus-group-mail-low
+  '((((class color)
+      (background dark))
+     (:foreground "aquamarine2" :bold t))
+    (((class color)
+      (background light))
+     (:foreground "DeepPink4" :bold t))
+    (t
+     (:bold t)))
+  "Low level mailgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-mail-low-face 'face-alias 'gnus-group-mail-low)
+(put 'gnus-group-mail-low-face 'obsolete-face "22.1")
+
+(defface gnus-group-mail-low-empty
+  '((((class color)
+      (background dark))
+     (:foreground "aquamarine2"))
+    (((class color)
+      (background light))
+     (:foreground "DeepPink4"))
+    (t
+     (:bold t)))
+  "Low level empty mailgroup face."
+  :group 'gnus-group)
+;; backward-compatibility alias
+(put 'gnus-group-mail-low-empty-face 'face-alias 'gnus-group-mail-low-empty)
+(put 'gnus-group-mail-low-empty-face 'obsolete-face "22.1")
+
+;; Summary mode faces.
+
+(defface gnus-summary-selected '((t (:underline t)))
+  "Face used for selected articles."
+  :group 'gnus-summary)
+;; backward-compatibility alias
+(put 'gnus-summary-selected-face 'face-alias 'gnus-summary-selected)
+(put 'gnus-summary-selected-face 'obsolete-face "22.1")
+
+(defface gnus-summary-cancelled
+  '((((class color))
+     (:foreground "yellow" :background "black")))
+  "Face used for canceled articles."
+  :group 'gnus-summary)
+;; backward-compatibility alias
+(put 'gnus-summary-cancelled-face 'face-alias 'gnus-summary-cancelled)
+(put 'gnus-summary-cancelled-face 'obsolete-face "22.1")
+
+(defface gnus-summary-high-ticked
+  '((((class color)
+      (background dark))
+     (:foreground "pink" :bold t))
+    (((class color)
+      (background light))
+     (:foreground "firebrick" :bold t))
+    (t
+     (:bold t)))
+  "Face used for high interest ticked articles."
+  :group 'gnus-summary)
+;; backward-compatibility alias
+(put 'gnus-summary-high-ticked-face 'face-alias 'gnus-summary-high-ticked)
+(put 'gnus-summary-high-ticked-face 'obsolete-face "22.1")
+
+(defface gnus-summary-low-ticked
+  '((((class color)
+      (background dark))
+     (:foreground "pink" :italic t))
+    (((class color)
+      (background light))
+     (:foreground "firebrick" :italic t))
+    (t
+     (:italic t)))
+  "Face used for low interest ticked articles."
+  :group 'gnus-summary)
+;; backward-compatibility alias
+(put 'gnus-summary-low-ticked-face 'face-alias 'gnus-summary-low-ticked)
+(put 'gnus-summary-low-ticked-face 'obsolete-face "22.1")
+
+(defface gnus-summary-normal-ticked
+  '((((class color)
+      (background dark))
+     (:foreground "pink"))
+    (((class color)
+      (background light))
+     (:foreground "firebrick"))
+    (t
+     ()))
+  "Face used for normal interest ticked articles."
+  :group 'gnus-summary)
+;; backward-compatibility alias
+(put 'gnus-summary-normal-ticked-face 'face-alias 'gnus-summary-normal-ticked)
+(put 'gnus-summary-normal-ticked-face 'obsolete-face "22.1")
+
+(defface gnus-summary-high-ancient
+  '((((class color)
+      (background dark))
+     (:foreground "SkyBlue" :bold t))
+    (((class color)
+      (background light))
+     (:foreground "RoyalBlue" :bold t))
+    (t
+     (:bold t)))
+  "Face used for high interest ancient articles."
+  :group 'gnus-summary)
+;; backward-compatibility alias
+(put 'gnus-summary-high-ancient-face 'face-alias 'gnus-summary-high-ancient)
+(put 'gnus-summary-high-ancient-face 'obsolete-face "22.1")
+
+(defface gnus-summary-low-ancient
+  '((((class color)
+      (background dark))
+     (:foreground "SkyBlue" :italic t))
+    (((class color)
+      (background light))
+     (:foreground "RoyalBlue" :italic t))
+    (t
+     (:italic t)))
+  "Face used for low interest ancient articles."
+  :group 'gnus-summary)
+;; backward-compatibility alias
+(put 'gnus-summary-low-ancient-face 'face-alias 'gnus-summary-low-ancient)
+(put 'gnus-summary-low-ancient-face 'obsolete-face "22.1")
+
+(defface gnus-summary-normal-ancient
+  '((((class color)
+      (background dark))
+     (:foreground "SkyBlue"))
+    (((class color)
+      (background light))
+     (:foreground "RoyalBlue"))
+    (t
+     ()))
+  "Face used for normal interest ancient articles."
+  :group 'gnus-summary)
+;; backward-compatibility alias
+(put 'gnus-summary-normal-ancient-face 'face-alias 'gnus-summary-normal-ancient)
+(put 'gnus-summary-normal-ancient-face 'obsolete-face "22.1")
+
+(defface gnus-summary-high-undownloaded
+   '((((class color)
+       (background light))
+      (:bold t :foreground "cyan4"))
+     (((class color) (background dark))
+      (:bold t :foreground "LightGray"))
+     (t (:inverse-video t :bold t)))
+  "Face used for high interest uncached articles."
+  :group 'gnus-summary)
+;; backward-compatibility alias
+(put 'gnus-summary-high-undownloaded-face 'face-alias 'gnus-summary-high-undownloaded)
+(put 'gnus-summary-high-undownloaded-face 'obsolete-face "22.1")
+
+(defface gnus-summary-low-undownloaded
+   '((((class color)
+       (background light))
+      (:italic t :foreground "cyan4" :bold nil))
+     (((class color) (background dark))
+      (:italic t :foreground "LightGray" :bold nil))
+     (t (:inverse-video t :italic t)))
+  "Face used for low interest uncached articles."
+  :group 'gnus-summary)
+;; backward-compatibility alias
+(put 'gnus-summary-low-undownloaded-face 'face-alias 'gnus-summary-low-undownloaded)
+(put 'gnus-summary-low-undownloaded-face 'obsolete-face "22.1")
+
+(defface gnus-summary-normal-undownloaded
+   '((((class color)
+       (background light))
+      (:foreground "cyan4" :bold nil))
+     (((class color) (background dark))
+      (:foreground "LightGray" :bold nil))
+     (t (:inverse-video t)))
+  "Face used for normal interest uncached articles."
+  :group 'gnus-summary)
+;; backward-compatibility alias
+(put 'gnus-summary-normal-undownloaded-face 'face-alias 'gnus-summary-normal-undownloaded)
+(put 'gnus-summary-normal-undownloaded-face 'obsolete-face "22.1")
+
+(defface gnus-summary-high-unread
+  '((t
+     (:bold t)))
+  "Face used for high interest unread articles."
+  :group 'gnus-summary)
+;; backward-compatibility alias
+(put 'gnus-summary-high-unread-face 'face-alias 'gnus-summary-high-unread)
+(put 'gnus-summary-high-unread-face 'obsolete-face "22.1")
+
+(defface gnus-summary-low-unread
+  '((t
+     (:italic t)))
+  "Face used for low interest unread articles."
+  :group 'gnus-summary)
+;; backward-compatibility alias
+(put 'gnus-summary-low-unread-face 'face-alias 'gnus-summary-low-unread)
+(put 'gnus-summary-low-unread-face 'obsolete-face "22.1")
+
+(defface gnus-summary-normal-unread
+  '((t
+     ()))
+  "Face used for normal interest unread articles."
+  :group 'gnus-summary)
+;; backward-compatibility alias
+(put 'gnus-summary-normal-unread-face 'face-alias 'gnus-summary-normal-unread)
+(put 'gnus-summary-normal-unread-face 'obsolete-face "22.1")
+
+(defface gnus-summary-high-read
+  '((((class color)
+      (background dark))
+     (:foreground "PaleGreen"
+                 :bold t))
+    (((class color)
+      (background light))
+     (:foreground "DarkGreen"
+                 :bold t))
+    (t
+     (:bold t)))
+  "Face used for high interest read articles."
+  :group 'gnus-summary)
+;; backward-compatibility alias
+(put 'gnus-summary-high-read-face 'face-alias 'gnus-summary-high-read)
+(put 'gnus-summary-high-read-face 'obsolete-face "22.1")
+
+(defface gnus-summary-low-read
+  '((((class color)
+      (background dark))
+     (:foreground "PaleGreen"
+                 :italic t))
+    (((class color)
+      (background light))
+     (:foreground "DarkGreen"
+                 :italic t))
+    (t
+     (:italic t)))
+  "Face used for low interest read articles."
+  :group 'gnus-summary)
+;; backward-compatibility alias
+(put 'gnus-summary-low-read-face 'face-alias 'gnus-summary-low-read)
+(put 'gnus-summary-low-read-face 'obsolete-face "22.1")
+
+(defface gnus-summary-normal-read
+  '((((class color)
+      (background dark))
+     (:foreground "PaleGreen"))
+    (((class color)
+      (background light))
+     (:foreground "DarkGreen"))
+    (t
+     ()))
+  "Face used for normal interest read articles."
+  :group 'gnus-summary)
+;; backward-compatibility alias
+(put 'gnus-summary-normal-read-face 'face-alias 'gnus-summary-normal-read)
+(put 'gnus-summary-normal-read-face 'obsolete-face "22.1")
+
+
+;;;
+;;; Gnus buffers
+;;;
+
+(defvar gnus-buffers nil
+  "List of buffers handled by Gnus.")
+
+(defun gnus-get-buffer-create (name)
+  "Do the same as `get-buffer-create', but store the created buffer."
+  (or (get-buffer name)
+      (car (push (get-buffer-create name) gnus-buffers))))
+
+(defun gnus-add-buffer ()
+  "Add the current buffer to the list of Gnus buffers."
+  (push (current-buffer) gnus-buffers))
+
+(defmacro gnus-kill-buffer (buffer)
+  "Kill BUFFER and remove from the list of Gnus buffers."
+  `(let ((buf ,buffer))
+     (when (gnus-buffer-exists-p buf)
+       (setq gnus-buffers (delete (get-buffer buf) gnus-buffers))
+       (kill-buffer buf))))
+
+(defun gnus-buffers ()
+  "Return a list of live Gnus buffers."
+  (while (and gnus-buffers
+             (not (buffer-name (car gnus-buffers))))
+    (pop gnus-buffers))
+  (let ((buffers gnus-buffers))
+    (while (cdr buffers)
+      (if (buffer-name (cadr buffers))
+         (pop buffers)
+       (setcdr buffers (cddr buffers)))))
+  gnus-buffers)
+
+;;; Splash screen.
+
+(defvar gnus-group-buffer "*Group*"
+  "Name of the Gnus group buffer.")
+
+(defface gnus-splash
+  '((((class color)
+      (background dark))
+     (:foreground "#cccccc"))
+    (((class color)
+      (background light))
+     (:foreground "#888888"))
+    (t
+     ()))
+  "Face for the splash screen."
+  :group 'gnus-start)
+;; backward-compatibility alias
+(put 'gnus-splash-face 'face-alias 'gnus-splash)
+(put 'gnus-splash-face 'obsolete-face "22.1")
+
+(defun gnus-splash ()
+  (save-excursion
+    (switch-to-buffer (gnus-get-buffer-create gnus-group-buffer))
+    (let ((buffer-read-only nil))
+      (erase-buffer)
+      (unless gnus-inhibit-startup-message
+       (gnus-group-startup-message)
+       (sit-for 0)))))
+
+(defun gnus-indent-rigidly (start end arg)
+  "Indent rigidly using only spaces and no tabs."
+  (save-excursion
+    (save-restriction
+      (narrow-to-region start end)
+      (let ((tab-width 8))
+       (indent-rigidly start end arg)
+       ;; We translate tabs into spaces -- not everybody uses
+       ;; an 8-character tab.
+       (goto-char (point-min))
+       (while (search-forward "\t" nil t)
+         (replace-match "        " t t))))))
+
+;;(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")
+    (storm "#666699" "#99ccff")
+    (pdino "#9999cc" "#99ccff")
+    (purp "#9999cc" "#666699")
+    (no "#ff0000" "#ffff00")
+    (neutral "#b4b4b4" "#878787")
+    (ma "#2020e0" "#8080ff")
+    (september "#bf9900" "#ffcc00"))
+  "Color alist used for the Gnus logo.")
+
+(defcustom gnus-logo-color-style 'ma
+  "*Color styles used for the Gnus logo."
+  :type `(choice ,@(mapcar (lambda (elem) (list 'const (car elem)))
+                          gnus-logo-color-alist))
+  :group 'gnus-xmas)
+
+(defvar gnus-logo-colors
+  (cdr (assq gnus-logo-color-style gnus-logo-color-alist))
+  "Colors used for the Gnus logo.")
+
+(declare-function image-size "image.c" (spec &optional pixels frame))
+
+(defun gnus-group-startup-message (&optional x y)
+  "Insert startup message in current buffer."
+  ;; Insert the message.
+  (erase-buffer)
+  (unless (and
+           (fboundp 'find-image)
+           (display-graphic-p)
+           ;; Make sure the library defining `image-load-path' is
+           ;; loaded (`find-image' is autoloaded) (and discard the
+           ;; result).  Else, we may get "defvar ignored because
+           ;; image-load-path is let-bound" when calling `find-image'
+           ;; below.
+           (or (find-image '(nil (:type xpm :file "gnus.xpm"))) t)
+           (let* ((data-directory (nnheader-find-etc-directory "images/gnus"))
+                  (image-load-path (cond (data-directory
+                                          (list data-directory))
+                                         ((boundp 'image-load-path)
+                                          (symbol-value 'image-load-path))
+                                         (t load-path)))
+                  (image (gnus-splash-svg-color-symbols (find-image
+                          `((:type svg :file "gnus.svg"
+                                   :color-symbols
+                                   (("#bf9900" . ,(car gnus-logo-colors))
+                                    ("#ffcc00" . ,(cadr gnus-logo-colors))))
+                            (:type xpm :file "gnus.xpm"
+                                   :color-symbols
+                                   (("thing" . ,(car gnus-logo-colors))
+                                    ("shadow" . ,(cadr gnus-logo-colors))))
+                            (:type png :file "gnus.png")
+                            (:type pbm :file "gnus.pbm"
+                                   ;; Account for the pbm's background.
+                                   :background ,(face-foreground 'gnus-splash)
+                                   :foreground ,(face-background 'default))
+                            (:type xbm :file "gnus.xbm"
+                                   ;; Account for the xbm's background.
+                                   :background ,(face-foreground 'gnus-splash)
+                                   :foreground ,(face-background 'default)))))))
+             (when image
+               (let ((size (image-size image)))
+                 (insert-char ?\n (max 0 (round (- (window-height)
+                                                   (or y (cdr size)) 1) 2)))
+                 (insert-char ?\  (max 0 (round (- (window-width)
+                                                   (or x (car size))) 2)))
+                 (insert-image image))
+              (goto-char (point-min))
+               t)))
+    (insert
+     (format "
+         _    ___ _             _
+         _ ___ __ ___  __    _ ___
+         __   _     ___    __  ___
+             _           ___     _
+            _  _ __             _
+            ___   __            _
+                  __           _
+                   _      _   _
+                  _      _    _
+                     _  _    _
+                 __  ___
+                _   _ _     _
+               _   _
+             _    _
+            _    _
+           _
+         __
+
+"))
+    ;; And then hack it.
+    (gnus-indent-rigidly (point-min) (point-max)
+                        (/ (max (- (window-width) (or x 46)) 0) 2))
+    (goto-char (point-min))
+    (forward-line 1)
+    (let* ((pheight (count-lines (point-min) (point-max)))
+          (wheight (window-height))
+          (rest (- wheight pheight)))
+      (insert (make-string (max 0 (* 2 (/ rest 3))) ?\n)))
+    ;; Fontify some.
+    (put-text-property (point-min) (point-max) 'face 'gnus-splash)
+    (goto-char (point-min))
+    (setq mode-line-buffer-identification (concat " " gnus-version))
+    (set-buffer-modified-p t)))
+
+(defun gnus-splash-svg-color-symbols (list)
+  "Do color-symbol search-and-replace in svg file."
+  (let ((type (plist-get (cdr list) :type))
+        (file (plist-get (cdr list) :file))
+        (color-symbols (plist-get (cdr list) :color-symbols)))
+    (if (string= type "svg")
+        (let ((data (with-temp-buffer (insert-file-contents file)
+                                      (buffer-string))))
+          (mapc (lambda (rule)
+                  (setq data (replace-regexp-in-string
+                              (concat "fill:" (car rule))
+                              (concat "fill:" (cdr rule)) data)))
+                color-symbols)
+          (cons (car list) (list :type type :data data)))
+       list)))
+
+(eval-when (load)
+  (let ((command (format "%s" this-command)))
+    (when (string-match "gnus" command)
+      (if (string-match "gnus-other-frame" command)
+         (gnus-get-buffer-create gnus-group-buffer)
+       (gnus-splash)))))
+
+;;; Do the rest.
+
+(require 'gnus-util)
+(require 'nnheader)
+
+(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%-23,23f%]%) %s\\n\")
+                 (gcc-self . t)
+                 (display . all))
+     (\"mail\\\\.me\" (gnus-use-scoring  t))
+     (\"list\\\\..*\" (total-expire . t)
+                 (broken-reply-to . t)))"
+  :version "22.1"
+  :group 'gnus-group-various
+  :type '(repeat (cons regexp
+                      (repeat sexp))))
+
+(defcustom gnus-parameters-case-fold-search 'default
+  "If it is t, ignore case of group names specified in `gnus-parameters'.
+If it is nil, don't ignore case.  If it is `default', which is for the
+backward compatibility, use the value of `case-fold-search'."
+  :version "22.1"
+  :group 'gnus-group-various
+  :type '(choice :format "%{%t%}:\n %[Value Menu%] %v"
+                (const :tag "Use `case-fold-search'" default)
+                (const nil)
+                (const t)))
+
+(defvar gnus-group-parameters-more nil)
+
+(defmacro gnus-define-group-parameter (param &rest rest)
+  "Define a group parameter PARAM.
+REST is a plist of following:
+:type               One of `bool', `list' or nil.
+:function           The name of the function.
+:function-document  The documentation of the function.
+:parameter-type     The type for customizing the parameter.
+:parameter-document The documentation for the parameter.
+:variable           The name of 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."
+  (let* ((type (plist-get rest :type))
+        (parameter-type (plist-get rest :parameter-type))
+        (parameter-document (plist-get rest :parameter-document))
+        (function (or (plist-get rest :function)
+                      (intern (format "gnus-parameter-%s" param))))
+        (function-document (or (plist-get rest :function-document) ""))
+        (variable (or (plist-get rest :variable)
+                      (intern (format "gnus-parameter-%s-alist" param))))
+        (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")
+                                          ,(car (cdr parameter-type)))))))
+        (variable-default (plist-get rest :variable-default)))
+    (list
+     'progn
+     `(defcustom ,variable ,variable-default
+       ,variable-document
+       :group 'gnus-group-parameter
+       :group ',variable-group
+       :type ,variable-type)
+     `(setq gnus-group-parameters-more
+           (delq (assq ',param gnus-group-parameters-more)
+                 gnus-group-parameters-more))
+     `(add-to-list 'gnus-group-parameters-more
+                  (list ',param
+                        ,parameter-type
+                        ,parameter-document))
+     (if (eq type 'bool)
+        `(defun ,function (name)
+           ,function-document
+           (let ((params (gnus-group-find-parameter name))
+                 val)
+             (cond
+              ((memq ',param params)
+               t)
+              ((setq val (assq ',param params))
+               (cdr val))
+              ((stringp ,variable)
+               (string-match ,variable name))
+              (,variable
+               (let ((alist ,variable)
+                     elem value)
+                 (while (setq elem (pop alist))
+                   (when (and name
+                              (string-match (car elem) name))
+                     (setq alist nil
+                           value (cdr elem))))
+                 (if (consp value) (car value) value))))))
+       `(defun ,function (name)
+         ,function-document
+         (and name
+              (or (gnus-group-find-parameter name ',param ,(and type t))
+                  (let ((alist ,variable)
+                        elem value)
+                    (while (setq elem (pop alist))
+                      (when (and name
+                                 (string-match (car elem) name))
+                        (setq alist nil
+                              value (cdr elem))))
+                    ,(if type
+                         'value
+                       '(if (consp value) (car value) value))))))))))
+
+(defcustom gnus-home-directory "~/"
+  "Directory variable that specifies the \"home\" directory.
+All other Gnus file and directory variables are initialized from this variable.
+
+Note that Gnus is mostly loaded when the `.gnus.el' file is read.
+This means that other directory variables that are initialized
+from this variable won't be set properly if you set this variable
+in `.gnus.el'.  Set this variable in `.emacs' instead."
+  :group 'gnus-files
+  :type 'directory)
+
+(defcustom gnus-directory (or (getenv "SAVEDIR")
+                             (nnheader-concat gnus-home-directory "News/"))
+  "*Directory variable from which all other Gnus file variables are derived.
+
+Note that Gnus is mostly loaded when the `.gnus.el' file is read.
+This means that other directory variables that are initialized from
+this variable won't be set properly if you set this variable in `.gnus.el'.
+Set this variable in `.emacs' instead."
+  :group 'gnus-files
+  :type 'directory)
+
+(defcustom gnus-default-directory nil
+  "*Default directory for all Gnus buffers."
+  :group 'gnus-files
+  :type '(choice (const :tag "current" nil)
+                directory))
+
+;; Site dependent variables.
+
+;; Should this be obsolete?
+(defcustom gnus-default-nntp-server nil
+  "The hostname of the default NNTP server.
+The empty string, or nil, means to use the local host.
+You may wish to set this on a site-wide basis.
+
+If you want to change servers, you should use `gnus-select-method'."
+  :group 'gnus-server
+  :type '(choice (const :tag "local host" nil)
+                 (string :tag "host name")))
+
+(defcustom gnus-nntpserver-file "/etc/nntpserver"
+  "A file with only the name of the nntp server in it."
+  :group 'gnus-files
+  :group 'gnus-server
+  :type 'file)
+
+(defun gnus-getenv-nntpserver ()
+  "Find default nntp server.
+Check the NNTPSERVER environment variable and the
+`gnus-nntpserver-file' file."
+  (or (getenv "NNTPSERVER")
+      (and (file-readable-p gnus-nntpserver-file)
+          (with-temp-buffer
+            (insert-file-contents gnus-nntpserver-file)
+            (when (re-search-forward "[^ \t\n\r]+" nil t)
+              (match-string 0))))))
+
+;; `M-x customize-variable RET gnus-select-method RET' should work without
+;; starting or even loading Gnus.
+;;;###autoload(when (fboundp 'custom-autoload)
+;;;###autoload  (custom-autoload 'gnus-select-method "gnus"))
+
+(defcustom gnus-select-method
+  (list 'nntp (or (gnus-getenv-nntpserver)
+                  (when (and gnus-default-nntp-server
+                             (not (string= gnus-default-nntp-server "")))
+                    gnus-default-nntp-server)
+                  "news"))
+  "Default method for selecting a newsgroup.
+This variable should be a list, where the first element is how the
+news is to be fetched, the second is the address.
+
+For instance, if you want to get your news via \"flab.flab.edu\" using
+NNTP, you could say:
+
+\(setq gnus-select-method \\='(nntp \"flab.flab.edu\"))
+
+If you want to use your local spool, say:
+
+\(setq gnus-select-method (list \\='nnspool (system-name)))
+
+If you use this variable, you must set `gnus-nntp-server' to nil.
+
+There is a lot more to know about select methods and virtual servers -
+see the manual for details."
+  ;; Emacs has set-after since 22.1.
+  ;set-after '(gnus-default-nntp-server)
+  :group 'gnus-server
+  :group 'gnus-start
+  :initialize 'custom-initialize-default
+  :type 'gnus-select-method)
+
+(defcustom gnus-message-archive-method "archive"
+  "*Method used for archiving messages you've sent.
+This should be a mail method.
+
+See also `gnus-update-message-archive-method'."
+  :group 'gnus-server
+  :group 'gnus-message
+  :type '(choice (const :tag "Default archive method" "archive")
+                gnus-select-method))
+
+(defcustom gnus-update-message-archive-method nil
+  "Non-nil means always update the saved \"archive\" method.
+
+The archive method is initially set according to the value of
+`gnus-message-archive-method' and is saved in the \"~/.newsrc.eld\" file
+so that it may be used as a real method of the server which is named
+\"archive\" ever since.  If it once has been saved, it will never be
+updated if the value of this variable is nil, even if you change the
+value of `gnus-message-archive-method' afterward.  If you want the
+saved \"archive\" method to be updated whenever you change the value of
+`gnus-message-archive-method', set this variable to a non-nil value."
+  :version "23.1"
+  :group 'gnus-server
+  :group 'gnus-message
+  :type 'boolean)
+
+(defcustom gnus-message-archive-group '((format-time-string "sent.%Y-%m"))
+  "*Name of the group in which to save the messages you've written.
+This can either be a string; a list of strings; or an alist
+of regexps/functions/forms to be evaluated to return a string (or a list
+of strings).  The functions are called with the name of the current
+group (or nil) as a parameter.
+
+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\")))
+
+Normally the group names returned by this variable should be
+unprefixed -- which implicitly means \"store on the archive server\".
+However, you may wish to store the message on some other server.  In
+that case, just return a fully prefixed name of the group --
+\"nnml+private:mail.misc\", for instance."
+  :version "24.1"
+  :group 'gnus-message
+  :type '(choice (const :tag "none" nil)
+                (const :tag "Weekly" ((format-time-string "sent.%Yw%U")))
+                (const :tag "Monthly" ((format-time-string "sent.%Y-%m")))
+                (const :tag "Yearly" ((format-time-string "sent.%Y")))
+                function
+                sexp
+                string))
+
+(defcustom gnus-secondary-servers nil
+  "List of NNTP servers that the user can choose between interactively.
+To make Gnus query you for a server, you have to give `gnus' a
+non-numeric prefix - `C-u M-x gnus', in short."
+  :group 'gnus-server
+  :type '(repeat string))
+(make-obsolete-variable 'gnus-secondary-servers 'gnus-select-method "24.1")
+
+(defcustom gnus-secondary-select-methods nil
+  "A list of secondary methods that will be used for reading news.
+This is a list where each element is a complete select method (see
+`gnus-select-method').
+
+If, for instance, you want to read your mail with the nnml back end,
+you could set this variable:
+
+\(setq gnus-secondary-select-methods \\='((nnml \"\")))"
+  :group 'gnus-server
+  :type '(repeat gnus-select-method))
+
+(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 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)
+                string))
+(make-obsolete-variable 'gnus-local-domain nil "Emacs 24.1")
+
+;; Customization variables
+
+(defcustom gnus-refer-article-method 'current
+  "Preferred method for fetching an article by Message-ID.
+The value of this variable must be a valid select method as discussed
+in the documentation of `gnus-select-method'.
+
+It can also be a list of select methods, as well as the special symbol
+`current', which means to use the current select method.  If it is a
+list, Gnus will try all the methods in the list until it finds a match."
+  :version "24.1"
+  :group 'gnus-server
+  :type '(choice (const :tag "default" nil)
+                (const current)
+                (const :tag "Google" (nnweb "refer" (nnweb-type google)))
+                gnus-select-method
+                sexp
+                (repeat :menu-tag "Try multiple"
+                        :tag "Multiple"
+                        :value (current (nnweb "refer" (nnweb-type google)))
+                        (choice :tag "Method"
+                                (const current)
+                                (const :tag "Google"
+                                       (nnweb "refer" (nnweb-type google)))
+                                gnus-select-method))))
+
+(defcustom gnus-use-cross-reference t
+  "*Non-nil means that cross referenced articles will be marked as read.
+If nil, ignore cross references.  If t, mark articles as read in
+subscribed newsgroups.  If neither t nor nil, mark as read in all
+newsgroups."
+  :group 'gnus-server
+  :type '(choice (const :tag "off" nil)
+                (const :tag "subscribed" t)
+                (sexp :format "all"
+                      :value always)))
+
+(defcustom gnus-process-mark ?#
+  "*Process mark."
+  :group 'gnus-group-visual
+  :group 'gnus-summary-marks
+  :type 'character)
+
+(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.
+If it is nil, no confirmation is required.
+
+Also see `gnus-large-ephemeral-newsgroup'."
+  :group 'gnus-group-select
+  :type '(choice (const :tag "No limit" nil)
+                integer))
+
+(defcustom gnus-use-long-file-name (not (memq system-type '(usg-unix-v)))
+  "Non-nil means that the default name of a file to save articles in is the group name.
+If it's nil, the directory form of the group name is used instead.
+
+If this variable is a list, and the list contains the element
+`not-score', long file names will not be used for score files; if it
+contains the element `not-save', long file names will not be used for
+saving; and if it contains the element `not-kill', long file names
+will not be used for kill files.
+
+Note that the default for this variable varies according to what system
+type you're using.  On `usg-unix-v' this variable defaults to nil while
+on all other systems it defaults to t."
+  :group 'gnus-start
+  :type '(radio (sexp :format "Non-nil\n"
+                     :match (lambda (widget value)
+                              (and value (not (listp value))))
+                     :value t)
+               (const nil)
+               (checklist (const :format "%v " not-score)
+                          (const :format "%v " not-save)
+                          (const not-kill))))
+
+(defcustom gnus-kill-files-directory gnus-directory
+  "*Name of the directory where kill files will be stored (default \"~/News\")."
+  :group 'gnus-score-files
+  :group 'gnus-score-kill
+  :type 'directory)
+
+(defcustom gnus-save-score nil
+  "*If non-nil, save group scoring info."
+  :group 'gnus-score-various
+  :group 'gnus-start
+  :type 'boolean)
+
+(defcustom gnus-use-undo t
+  "*If non-nil, allow undoing in Gnus group mode buffers."
+  :group 'gnus-meta
+  :type 'boolean)
+
+(defcustom gnus-use-adaptive-scoring nil
+  "*If non-nil, use some adaptive scoring scheme.
+If a list, then the values `word' and `line' are meaningful.  The
+former will perform adaption on individual words in the subject
+header while `line' will perform adaption on several headers."
+  :group 'gnus-meta
+  :group 'gnus-score-adapt
+  :type '(set (const word) (const line)))
+
+(defcustom gnus-use-cache 'passive
+  "*If nil, Gnus will ignore the article cache.
+If `passive', it will allow entering (and reading) articles
+explicitly entered into the cache.  If anything else, use the
+cache to the full extent of the law."
+  :group 'gnus-meta
+  :group 'gnus-cache
+  :type '(choice (const :tag "off" nil)
+                (const :tag "passive" passive)
+                (const :tag "active" t)))
+
+(defcustom gnus-use-trees nil
+  "*If non-nil, display a thread tree buffer."
+  :group 'gnus-meta
+  :type 'boolean)
+
+(defcustom gnus-keep-backlog 20
+  "*If non-nil, Gnus will keep read articles for later re-retrieval.
+If it is a number N, then Gnus will only keep the last N articles
+read.  If it is neither nil nor a number, Gnus will keep all read
+articles.  This is not a good idea."
+  :group 'gnus-meta
+  :type '(choice (const :tag "off" nil)
+                integer
+                (sexp :format "all"
+                      :value t)))
+
+(defcustom gnus-suppress-duplicates nil
+  "*If non-nil, Gnus will mark duplicate copies of the same article as read."
+  :group 'gnus-meta
+  :type 'boolean)
+
+(defcustom gnus-use-scoring t
+  "*If non-nil, enable scoring."
+  :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.
+It calls `gnus-summary-expire-articles' by default."
+  :group 'gnus-summary-exit
+  :type 'hook)
+
+(defcustom gnus-novice-user t
+  "*Non-nil means that you are a Usenet novice.
+If non-nil, verbose messages may be displayed and confirmations may be
+required."
+  :group 'gnus-meta
+  :type 'boolean)
+
+(defcustom gnus-expert-user nil
+  "*Non-nil means that you will never be asked for confirmation about anything.
+That doesn't mean *anything* anything; particularly destructive
+commands will still require prompting."
+  :group 'gnus-meta
+  :type 'boolean)
+
+(defcustom gnus-interactive-catchup t
+  "*If non-nil, require your confirmation when catching up a group."
+  :group 'gnus-group-select
+  :type 'boolean)
+
+(defcustom gnus-interactive-exit t
+  "*If non-nil, require your confirmation when exiting Gnus.
+If `quiet', update any active summary buffers automatically
+first before exiting."
+  :group 'gnus-exit
+  :type '(choice boolean
+                (const quiet)))
+
+(defcustom gnus-extract-address-components 'gnus-extract-address-components
+  "*Function for extracting address components from a From header.
+Two pre-defined function exist: `gnus-extract-address-components',
+which is the default, quite fast, and too simplistic solution, and
+`mail-extract-address-components', which works much better, but is
+slower."
+  :group 'gnus-summary-format
+  :type '(radio (function-item gnus-extract-address-components)
+               (function-item mail-extract-address-components)
+               (function :tag "Other")))
+
+(defcustom gnus-shell-command-separator ";"
+  "String used to separate shell commands."
+  :group 'gnus-files
+  :type 'string)
+
+(defcustom gnus-valid-select-methods
+  '(("nntp" post address prompt-address physical-address cloud)
+    ("nnspool" post address)
+    ("nnvirtual" post-mail virtual prompt-address)
+    ("nnmbox" 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)
+    ("nndoc" none address prompt-address)
+    ("nnbabyl" mail address respool)
+    ("nndraft" post-mail)
+    ("nnfolder" mail respool address)
+    ("nngateway" post-mail address prompt-address physical-address)
+    ("nnweb" none)
+    ("nnrss" none global)
+    ("nnagent" post-mail)
+    ("nnimap" post-mail address prompt-address physical-address respool
+     server-marks cloud)
+    ("nnmaildir" mail respool address server-marks)
+    ("nnnil" none))
+  "*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
+this method (i. e., `post', `mail', `none' or whatever) or other
+properties that this method has (like being respoolable).
+If you implement a new select method, all you should have to change is
+this variable.  I think."
+  :group 'gnus-server
+  :type '(repeat (group (string :tag "Name")
+                       (radio-button-choice (const :format "%v " post)
+                                            (const :format "%v " mail)
+                                            (const :format "%v " none)
+                                            (const post-mail))
+                       (checklist :inline t :greedy t
+                                  (const :format "%v " address)
+                                  (const global)
+                                  (const :format "%v " prompt-address)
+                                  (const :format "%v " physical-address)
+                                  (const virtual)
+                                  (const :format "%v " respool)
+                                  (const server-marks))))
+  :version "24.1")
+
+(defun gnus-redefine-select-method-widget ()
+  "Recomputes the select-method widget based on the value of
+`gnus-valid-select-methods'."
+  (define-widget 'gnus-select-method 'list
+    "Widget for entering a select method."
+    :value '(nntp "")
+    :tag "Select Method"
+    :args `((choice :tag "Method"
+                   ,@(mapcar (lambda (entry)
+                               (list 'const :format "%v\n"
+                                     (intern (car entry))))
+                             gnus-valid-select-methods)
+                   (symbol :tag "other"))
+           (string :tag "Address")
+           (repeat :tag "Options"
+                   :inline t
+                   (list :format "%v"
+                         variable
+                         (sexp :tag "Value"))))))
+
+(gnus-redefine-select-method-widget)
+
+(defcustom gnus-updated-mode-lines '(group article summary tree)
+  "List of buffers that should update their mode lines.
+The list may contain the symbols `group', `article', `tree' and
+`summary'.  If the corresponding symbol is present, Gnus will keep
+that mode line updated with information that may be pertinent.
+If this variable is nil, screen refresh may be quicker."
+  :group 'gnus-various
+  :type '(set (const group)
+             (const article)
+             (const summary)
+             (const tree)))
+
+(defcustom gnus-mode-non-string-length 30
+  "*Max length of mode-line non-string contents.
+If this is nil, Gnus will take space as is needed, leaving the rest
+of the mode line intact."
+  :version "24.1"
+  :group 'gnus-various
+  :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."
+ :variable-group gnus-group-parameter
+ :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
+mailing lists--mailing lists where it's expected that everybody that
+writes to the mailing list is subscribed to it.  Since using this
+parameter ensures that the mail only goes to the mailing list itself,
+it means that members won't receive two copies of your followups.
+
+Using `to-address' will actually work whether the group is foreign or
+not.  Let's say there's a group on the server that is called
+`fa.4ad-l'.  This is a real newsgroup, but the server has gotten the
+articles from a mail-to-news gateway.  Posting directly to this group
+is therefore impossible--you have to send mail to the mailing list
+address instead.
+
+The gnus-group-split mail splitting mechanism will behave as if this
+address was listed in gnus-group-split Addresses (see below).")
+
+(gnus-define-group-parameter
+ to-list
+ :function-document
+ "Return GROUP's to-list."
+ :variable-document
+ "*Alist of group regexps and correspondent to-lists."
+ :variable-group gnus-group-parameter
+ :parameter-type '(gnus-email-address :tag "To List")
+ :parameter-document "\
+This address will be used when doing a `a' in the group.
+
+It is totally ignored when doing a followup--except that if it is
+present in a news group, you'll get mail group semantics when doing
+`f'.
+
+The gnus-group-split mail splitting mechanism will behave as if this
+address was listed in gnus-group-split Addresses (see below).")
+
+(gnus-define-group-parameter
+ subscribed
+ :type bool
+ :function-document
+ "Return GROUP's subscription status."
+ :variable-document
+ "*Groups which are automatically considered subscribed."
+ :variable-group gnus-group-parameter
+ :parameter-type '(const :tag "Subscribed" t)
+ :parameter-document "\
+Gnus assumed that you are subscribed to the To/List address.
+
+When constructing a list of subscribed groups using
+`gnus-find-subscribed-addresses', Gnus includes the To address given
+above, or the list address (if the To address has not been set).")
+
+(gnus-define-group-parameter
+ auto-expire
+ :type bool
+ :function gnus-group-auto-expirable-p
+ :function-document
+ "Check whether GROUP is auto-expirable or not."
+ :variable gnus-auto-expirable-newsgroups
+ :variable-default nil
+ :variable-document
+ "*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.")
+
+(gnus-define-group-parameter
+ total-expire
+ :type bool
+ :function gnus-group-total-expirable-p
+ :function-document
+ "Check whether GROUP is total-expirable or not."
+ :variable gnus-total-expirable-newsgroups
+ :variable-default nil
+ :variable-document
+ "*Groups in which to perform expiry of all read articles.
+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
+
+This happens even if they are not marked as expirable.
+Use with caution.")
+
+(gnus-define-group-parameter
+ charset
+ :function-document
+ "Return the default charset of GROUP."
+ :variable gnus-group-charset-alist
+ :variable-default
+ '(("\\(^\\|:\\)hk\\>\\|\\(^\\|:\\)tw\\>\\|\\<big5\\>" cn-big5)
+   ("\\(^\\|:\\)cn\\>\\|\\<chinese\\>" cn-gb-2312)
+   ("\\(^\\|:\\)fj\\>\\|\\(^\\|:\\)japan\\>" iso-2022-jp-2)
+   ("\\(^\\|:\\)tnn\\>\\|\\(^\\|:\\)pin\\>\\|\\(^\\|:\\)sci.lang.japan" iso-2022-7bit)
+   ("\\(^\\|:\\)relcom\\>" koi8-r)
+   ("\\(^\\|:\\)fido7\\>" koi8-r)
+   ("\\(^\\|:\\)\\(cz\\|hun\\|pl\\|sk\\|hr\\)\\>" iso-8859-2)
+   ("\\(^\\|:\\)israel\\>" iso-8859-1)
+   ("\\(^\\|:\\)han\\>" euc-kr)
+   ("\\(^\\|:\\)alt.chinese.text.big5\\>" chinese-big5)
+   ("\\(^\\|:\\)soc.culture.vietnamese\\>" vietnamese-viqr)
+   ("\\(^\\|:\\)\\(comp\\|rec\\|alt\\|sci\\|soc\\|news\\|gnu\\|bofh\\)\\>" 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 "\
+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.")
+
+(gnus-define-group-parameter
+ large-newsgroup-initial
+ :type integer
+ :function-document
+ "Return GROUP's initial input of the number of articles."
+ :variable-document
+ "*Alist of group regexps and its initial input of the number of articles."
+ :variable-group gnus-group-parameter
+ :parameter-type '(choice :tag "Initial Input for Large Newsgroup"
+                         (const :tag "All" nil)
+                         (integer))
+ :parameter-document "\
+
+This number will be prompted as the initial value of the number of
+articles to list when the group is a large newsgroup (see
+`gnus-large-newsgroup').  If it is nil, the default value is the
+total number of articles in the group.")
+
+;; The Gnus registry's ignored groups
+(gnus-define-group-parameter
+ registry-ignore
+ :type list
+ :function-document
+ "Whether this group should be ignored by the registry."
+ :variable gnus-registry-ignored-groups
+ :variable-default (mapcar
+                    (lambda (g) (list g t))
+                    '("delayed$" "drafts$" "queue$" "INBOX$"
+                      "^nnmairix:" "^nnir:" "archive"))
+ :variable-document
+ "*Groups in which the registry should be turned off."
+ :variable-group gnus-registry
+ :variable-type '(repeat
+                 (list
+                  (regexp :tag "Group Name Regular Expression")
+                  (boolean :tag "Ignored")))
+
+ :parameter-type '(boolean :tag "Group Ignored by the Registry")
+ :parameter-document
+ "Whether the Gnus Registry should ignore this group.")
+
+;; group parameters for spam processing added by Ted Zlatanov <tzz@lifelogs.com>
+(defcustom gnus-install-group-spam-parameters t
+  "*Disable the group parameters for spam detection.
+Enable if `G c' in XEmacs is giving you trouble, and make sure to submit a bug report."
+  :version "22.1"
+  :type 'boolean
+  :group 'gnus-start)
+
+(when gnus-install-group-spam-parameters
+  (defvar gnus-group-spam-classification-spam t
+    "Spam group classification (requires spam.el).
+This group contains spam messages.  On summary entry, unread messages
+will be marked as spam.  On summary exit, the specified spam
+processors will be invoked on spam-marked messages, then those
+messages will be expired, so the spam processor will only see a
+spam-marked message once.")
+
+  (defvar gnus-group-spam-classification-ham 'ask
+    "The ham value for the spam group parameter (requires spam.el).
+On summary exit, the specified ham processors will be invoked on
+ham-marked messages.  Exercise caution, since the ham processor will
+see the same message more than once because there is no ham message
+registry.")
+
+  (gnus-define-group-parameter
+   spam-contents
+   :type list
+   :function-document
+   "The spam type (spam, ham, or neither) of the group."
+   :variable gnus-spam-newsgroup-contents
+   :variable-default nil
+   :variable-document
+   "*Group classification (spam, ham, or neither).  Only
+meaningful when spam.el is loaded.  If non-nil, this should be a
+list of group name regexps associated with a classification for
+each one.  In spam groups, new articles are marked as spam on
+summary entry.  There is other behavior associated with ham and
+no classification when spam.el is loaded - see the manual."
+   :variable-group spam
+   :variable-type '(repeat
+                   (list :tag "Group contents spam/ham classification"
+                         (regexp :tag "Group")
+                         (choice
+                          (variable-item gnus-group-spam-classification-spam)
+                          (variable-item gnus-group-spam-classification-ham)
+                          (const :tag "Unclassified" nil))))
+
+   :parameter-type '(list :tag "Group contents spam/ham classification"
+                         (choice :tag "Group contents classification for spam sorting"
+                                 (variable-item gnus-group-spam-classification-spam)
+                                 (variable-item gnus-group-spam-classification-ham)
+                                 (const :tag "Unclassified" nil)))
+   :parameter-document
+   "The spam classification (spam, ham, or neither) of this group.
+When a spam group is entered, all unread articles are marked as
+spam.  There is other behavior associated with ham and no
+classification when spam.el is loaded - see the manual.")
+
+  (gnus-define-group-parameter
+   spam-resend-to
+   :type list
+   :function-document
+   "The address to get spam resent (through spam-report-resend)."
+   :variable gnus-spam-resend-to
+   :variable-default nil
+   :variable-document
+   "The address to get spam resent (through spam-report-resend)."
+   :variable-group spam
+   :variable-type '(repeat
+                   (list :tag "Group address for resending spam"
+                         (regexp :tag "Group")
+                         (string :tag "E-mail address for resending spam (requires the spam-use-resend exit processor)")))
+   :parameter-type 'string :tag "E-mail address for resending spam (requires the spam-use-resend exit processor)"
+   :parameter-document
+   "The address to get spam resent (through spam-report-resend).")
+
+  (gnus-define-group-parameter
+   ham-resend-to
+   :type list
+   :function-document
+   "The address to get ham resent (through spam-report-resend)."
+   :variable gnus-ham-resend-to
+   :variable-default nil
+   :variable-document
+   "The address to get ham resent (through spam-report-resend)."
+   :variable-group spam
+   :variable-type '(repeat
+                   (list :tag "Group address for resending ham"
+                         (regexp :tag "Group")
+                         (string :tag "E-mail address for resending ham (requires the spam-use-resend exit processor)")))
+   :parameter-type 'string :tag "E-mail address for resending ham (requires the spam-use-resend exit processor)"
+   :parameter-document
+   "The address to get ham resent (through spam-report-resend).")
+
+  (defvar gnus-group-spam-exit-processor-ifile "ifile"
+    "OBSOLETE: The ifile summary exit spam processor.")
+
+  (defvar gnus-group-spam-exit-processor-stat "stat"
+    "OBSOLETE: The spam-stat summary exit spam processor.")
+
+  (defvar gnus-group-spam-exit-processor-bogofilter "bogofilter"
+    "OBSOLETE: The Bogofilter summary exit spam processor.")
+
+  (defvar gnus-group-spam-exit-processor-blacklist "blacklist"
+    "OBSOLETE: The Blacklist summary exit spam processor.")
+
+  (defvar gnus-group-spam-exit-processor-report-gmane "report-gmane"
+    "OBSOLETE: The Gmane reporting summary exit spam processor.
+Only applicable to NNTP groups with articles from Gmane.  See spam-report.el")
+
+  (defvar gnus-group-spam-exit-processor-spamoracle "spamoracle-spam"
+    "OBSOLETE: The spamoracle summary exit spam processor.")
+
+  (defvar gnus-group-ham-exit-processor-ifile "ifile-ham"
+    "OBSOLETE: The ifile summary exit ham processor.
+Only applicable to non-spam (unclassified and ham) groups.")
+
+  (defvar gnus-group-ham-exit-processor-bogofilter "bogofilter-ham"
+    "OBSOLETE: The Bogofilter summary exit ham processor.
+Only applicable to non-spam (unclassified and ham) groups.")
+
+  (defvar gnus-group-ham-exit-processor-stat "stat-ham"
+    "OBSOLETE: The spam-stat summary exit ham processor.
+Only applicable to non-spam (unclassified and ham) groups.")
+
+  (defvar gnus-group-ham-exit-processor-whitelist "whitelist"
+    "OBSOLETE: The whitelist summary exit ham processor.
+Only applicable to non-spam (unclassified and ham) groups.")
+
+  (defvar gnus-group-ham-exit-processor-BBDB "bbdb"
+    "OBSOLETE: The BBDB summary exit ham processor.
+Only applicable to non-spam (unclassified and ham) groups.")
+
+  (defvar gnus-group-ham-exit-processor-copy "copy"
+    "OBSOLETE: The ham copy exit ham processor.
+Only applicable to non-spam (unclassified and ham) groups.")
+
+  (defvar gnus-group-ham-exit-processor-spamoracle "spamoracle-ham"
+    "OBSOLETE: The spamoracle summary exit ham processor.
+Only applicable to non-spam (unclassified and ham) groups.")
+
+  (gnus-define-group-parameter
+   spam-process
+   :type list
+   :parameter-type
+   '(choice
+     :tag "Spam Summary Exit Processor"
+     :value nil
+     (list :tag "Spam Summary Exit Processor Choices"
+          (set
+           (const :tag "Spam: Bogofilter"    (spam spam-use-bogofilter))
+           (const :tag "Spam: Blacklist"     (spam spam-use-blacklist))
+           (const :tag "Spam: Bsfilter"      (spam spam-use-bsfilter))
+           (const :tag "Spam: Gmane Report"  (spam spam-use-gmane))
+           (const :tag "Spam: Resend Message"(spam spam-use-resend))
+           (const :tag "Spam: ifile"         (spam spam-use-ifile))
+           (const :tag "Spam: Spam Oracle"   (spam spam-use-spamoracle))
+           (const :tag "Spam: Spam-stat"     (spam spam-use-stat))
+           (const :tag "Spam: SpamAssassin"  (spam spam-use-spamassassin))
+           (const :tag "Spam: CRM114"        (spam spam-use-crm114))
+           (const :tag "Ham: BBDB"           (ham spam-use-BBDB))
+           (const :tag "Ham: Bogofilter"     (ham spam-use-bogofilter))
+           (const :tag "Ham: Bsfilter"       (ham spam-use-bsfilter))
+           (const :tag "Ham: Copy"           (ham spam-use-ham-copy))
+           (const :tag "Ham: Resend Message" (ham spam-use-resend))
+           (const :tag "Ham: ifile"          (ham spam-use-ifile))
+           (const :tag "Ham: Spam Oracle"    (ham spam-use-spamoracle))
+           (const :tag "Ham: Spam-stat"      (ham spam-use-stat))
+           (const :tag "Ham: SpamAssassin"   (ham spam-use-spamassassin))
+           (const :tag "Ham: CRM114"         (ham spam-use-crm114))
+           (const :tag "Ham: Whitelist"      (ham spam-use-whitelist))
+           (variable-item gnus-group-spam-exit-processor-ifile)
+           (variable-item gnus-group-spam-exit-processor-stat)
+           (variable-item gnus-group-spam-exit-processor-bogofilter)
+           (variable-item gnus-group-spam-exit-processor-blacklist)
+           (variable-item gnus-group-spam-exit-processor-spamoracle)
+           (variable-item gnus-group-spam-exit-processor-report-gmane)
+           (variable-item gnus-group-ham-exit-processor-bogofilter)
+           (variable-item gnus-group-ham-exit-processor-ifile)
+           (variable-item gnus-group-ham-exit-processor-stat)
+           (variable-item gnus-group-ham-exit-processor-whitelist)
+           (variable-item gnus-group-ham-exit-processor-BBDB)
+           (variable-item gnus-group-ham-exit-processor-spamoracle)
+           (variable-item gnus-group-ham-exit-processor-copy))))
+   :function-document
+   "Which spam or ham processors will be applied when the summary is exited."
+   :variable gnus-spam-process-newsgroups
+   :variable-default nil
+   :variable-document
+   "*Groups in which to automatically process spam or ham articles with
+a backend on summary exit.  If non-nil, this should be a list of group
+name regexps that should match all groups in which to do automatic
+spam processing, associated with the appropriate processor."
+   :variable-group spam
+   :variable-type
+   '(repeat :tag "Spam/Ham Processors"
+           (list :tag "Spam Summary Exit Processor Choices"
+                 (regexp :tag "Group Regexp")
+                 (set
+                  :tag "Spam/Ham Summary Exit Processor"
+                  (const :tag "Spam: Bogofilter"    (spam spam-use-bogofilter))
+                  (const :tag "Spam: Blacklist"     (spam spam-use-blacklist))
+                  (const :tag "Spam: Bsfilter"      (spam spam-use-bsfilter))
+                  (const :tag "Spam: Gmane Report"  (spam spam-use-gmane))
+                  (const :tag "Spam: Resend Message"(spam spam-use-resend))
+                  (const :tag "Spam: ifile"         (spam spam-use-ifile))
+                  (const :tag "Spam: Spam-stat"     (spam spam-use-stat))
+                  (const :tag "Spam: Spam Oracle"   (spam spam-use-spamoracle))
+                  (const :tag "Spam: SpamAssassin"  (spam spam-use-spamassassin))
+                  (const :tag "Spam: CRM114"        (spam spam-use-crm114))
+                  (const :tag "Ham: BBDB"           (ham spam-use-BBDB))
+                  (const :tag "Ham: Bogofilter"     (ham spam-use-bogofilter))
+                  (const :tag "Ham: Bsfilter"       (ham spam-use-bsfilter))
+                  (const :tag "Ham: Copy"           (ham spam-use-ham-copy))
+                  (const :tag "Ham: Resend Message" (ham spam-use-resend))
+                  (const :tag "Ham: ifile"          (ham spam-use-ifile))
+                  (const :tag "Ham: Spam-stat"      (ham spam-use-stat))
+                  (const :tag "Ham: Spam Oracle"    (ham spam-use-spamoracle))
+                  (const :tag "Ham: SpamAssassin"   (ham spam-use-spamassassin))
+                  (const :tag "Ham: CRM114"         (ham spam-use-crm114))
+                  (const :tag "Ham: Whitelist"      (ham spam-use-whitelist))
+                  (variable-item gnus-group-spam-exit-processor-ifile)
+                  (variable-item gnus-group-spam-exit-processor-stat)
+                  (variable-item gnus-group-spam-exit-processor-bogofilter)
+                  (variable-item gnus-group-spam-exit-processor-blacklist)
+                  (variable-item gnus-group-spam-exit-processor-spamoracle)
+                  (variable-item gnus-group-spam-exit-processor-report-gmane)
+                  (variable-item gnus-group-ham-exit-processor-bogofilter)
+                  (variable-item gnus-group-ham-exit-processor-ifile)
+                  (variable-item gnus-group-ham-exit-processor-stat)
+                  (variable-item gnus-group-ham-exit-processor-whitelist)
+                  (variable-item gnus-group-ham-exit-processor-BBDB)
+                  (variable-item gnus-group-ham-exit-processor-spamoracle)
+                  (variable-item gnus-group-ham-exit-processor-copy))))
+
+   :parameter-document
+   "Which spam or ham processors will be applied when the summary is exited.")
+
+  (gnus-define-group-parameter
+   spam-autodetect
+   :type list
+   :parameter-type
+   '(boolean :tag "Spam autodetection")
+   :function-document
+   "Should spam be autodetected (with spam-split) in this group?"
+   :variable gnus-spam-autodetect
+   :variable-default nil
+   :variable-document
+   "*Groups in which spam should be autodetected when they are entered.
+   Only unseen articles will be examined, unless
+   spam-autodetect-recheck-messages is set."
+   :variable-group spam
+   :variable-type
+   '(repeat
+     :tag "Autodetection setting"
+     (list
+      (regexp :tag "Group Regexp")
+      boolean))
+   :parameter-document
+   "Spam autodetection.
+Only unseen articles will be examined, unless
+spam-autodetect-recheck-messages is set.")
+
+  (gnus-define-group-parameter
+   spam-autodetect-methods
+   :type list
+   :parameter-type
+   '(choice :tag "Spam autodetection-specific methods"
+     (const none)
+     (const default)
+     (set :tag "Use specific methods"
+         (variable-item spam-use-blacklist)
+         (variable-item spam-use-gmane-xref)
+         (variable-item spam-use-regex-headers)
+         (variable-item spam-use-regex-body)
+         (variable-item spam-use-whitelist)
+         (variable-item spam-use-BBDB)
+         (variable-item spam-use-ifile)
+         (variable-item spam-use-spamoracle)
+         (variable-item spam-use-crm114)
+         (variable-item spam-use-spamassassin)
+         (variable-item spam-use-spamassassin-headers)
+         (variable-item spam-use-bsfilter)
+         (variable-item spam-use-bsfilter-headers)
+         (variable-item spam-use-stat)
+         (variable-item spam-use-blackholes)
+         (variable-item spam-use-hashcash)
+         (variable-item spam-use-bogofilter-headers)
+         (variable-item spam-use-bogofilter)))
+   :function-document
+   "Methods to be used for autodetection in each group"
+   :variable gnus-spam-autodetect-methods
+   :variable-default nil
+   :variable-document
+   "*Methods for autodetecting spam per group.
+Requires the spam-autodetect parameter.  Only unseen articles
+will be examined, unless spam-autodetect-recheck-messages is
+set."
+   :variable-group spam
+   :variable-type
+   '(repeat
+     :tag "Autodetection methods"
+     (list
+      (regexp :tag "Group Regexp")
+      (choice
+       (const none)
+       (const default)
+       (set :tag "Use specific methods"
+       (variable-item spam-use-blacklist)
+       (variable-item spam-use-gmane-xref)
+       (variable-item spam-use-regex-headers)
+       (variable-item spam-use-regex-body)
+       (variable-item spam-use-whitelist)
+       (variable-item spam-use-BBDB)
+       (variable-item spam-use-ifile)
+       (variable-item spam-use-spamoracle)
+       (variable-item spam-use-crm114)
+       (variable-item spam-use-stat)
+       (variable-item spam-use-blackholes)
+       (variable-item spam-use-hashcash)
+       (variable-item spam-use-spamassassin)
+       (variable-item spam-use-spamassassin-headers)
+       (variable-item spam-use-bsfilter)
+       (variable-item spam-use-bsfilter-headers)
+       (variable-item spam-use-bogofilter-headers)
+       (variable-item spam-use-bogofilter)))))
+     :parameter-document
+   "Spam autodetection methods.
+Requires the spam-autodetect parameter.  Only unseen articles
+will be examined, unless spam-autodetect-recheck-messages is
+set.")
+
+  (gnus-define-group-parameter
+   spam-process-destination
+   :type list
+   :parameter-type
+   '(choice :tag "Destination for spam-processed articles at summary exit"
+           (string :tag "Move to a group")
+           (repeat :tag "Move to multiple groups"
+                   (string :tag "Destination group"))
+           (const :tag "Expire" nil))
+   :function-document
+   "Where spam-processed articles will go at summary exit."
+   :variable gnus-spam-process-destinations
+   :variable-default nil
+   :variable-document
+   "*Groups in which to explicitly send spam-processed articles to
+another group, or expire them (the default).  If non-nil, this should
+be a list of group name regexps that should match all groups in which
+to do spam-processed article moving, associated with the destination
+group or nil for explicit expiration.  This only makes sense for
+mail groups."
+   :variable-group spam
+   :variable-type
+   '(repeat
+     :tag "Spam-processed articles destination"
+     (list
+      (regexp :tag "Group Regexp")
+      (choice
+       :tag "Destination for spam-processed articles at summary exit"
+       (string :tag "Move to a group")
+       (repeat :tag "Move to multiple groups"
+              (string :tag "Destination group"))
+       (const :tag "Expire" nil))))
+   :parameter-document
+   "Where spam-processed articles will go at summary exit.")
+
+  (gnus-define-group-parameter
+   ham-process-destination
+   :type list
+   :parameter-type
+   '(choice
+     :tag "Destination for ham articles at summary exit from a spam group"
+     (string :tag "Move to a group")
+     (repeat :tag "Move to multiple groups"
+            (string :tag "Destination group"))
+     (const :tag "Respool" respool)
+     (const :tag "Do nothing" nil))
+   :function-document
+   "Where ham articles will go at summary exit from a spam group."
+   :variable gnus-ham-process-destinations
+   :variable-default nil
+   :variable-document
+   "*Groups in which to explicitly send ham articles to
+another group, or do nothing (the default).  If non-nil, this should
+be a list of group name regexps that should match all groups in which
+to do ham article moving, associated with the destination
+group or nil for explicit ignoring.  This only makes sense for
+mail groups, and only works in spam groups."
+   :variable-group spam
+   :variable-type
+   '(repeat
+     :tag "Ham articles destination"
+     (list
+      (regexp :tag "Group Regexp")
+      (choice
+       :tag "Destination for ham articles at summary exit from spam group"
+       (string :tag "Move to a group")
+       (repeat :tag "Move to multiple groups"
+               (string :tag "Destination group"))
+       (const :tag "Respool" respool)
+       (const :tag "Expire" nil))))
+   :parameter-document
+   "Where ham articles will go at summary exit from a spam group.")
+
+  (gnus-define-group-parameter
+   ham-marks
+   :type 'list
+   :parameter-type '(list :tag "Ham mark choices"
+                         (set
+                          (variable-item gnus-del-mark)
+                          (variable-item gnus-read-mark)
+                          (variable-item gnus-ticked-mark)
+                          (variable-item gnus-killed-mark)
+                          (variable-item gnus-kill-file-mark)
+                          (variable-item gnus-low-score-mark)))
+
+   :parameter-document
+   "Marks considered ham (positively not spam).  Such articles will be
+processed as ham (non-spam) on group exit.  When nil, the global
+spam-ham-marks variable takes precedence."
+   :variable-default '((".*" ((gnus-del-mark
+                              gnus-read-mark
+                              gnus-killed-mark
+                              gnus-kill-file-mark
+                              gnus-low-score-mark))))
+   :variable-group spam
+   :variable-document
+   "*Groups in which to explicitly set the ham marks to some value.")
+
+  (gnus-define-group-parameter
+   spam-marks
+   :type 'list
+   :parameter-type '(list :tag "Spam mark choices"
+                         (set
+                          (variable-item gnus-spam-mark)
+                          (variable-item gnus-killed-mark)
+                          (variable-item gnus-kill-file-mark)
+                          (variable-item gnus-low-score-mark)))
+
+   :parameter-document
+   "Marks considered spam.
+Such articles will be processed as spam on group exit.  When nil, the global
+spam-spam-marks variable takes precedence."
+   :variable-default '((".*" ((gnus-spam-mark))))
+   :variable-group spam
+   :variable-document
+   "*Groups in which to explicitly set the spam marks to some value."))
+
+(defcustom gnus-group-uncollapsed-levels 1
+  "Number of group name elements to leave alone when making a short group name."
+  :group 'gnus-group-visual
+  :type 'integer)
+
+(defcustom gnus-group-use-permanent-levels nil
+  "*If non-nil, once you set a level, Gnus will use this level."
+  :group 'gnus-group-levels
+  :type 'boolean)
+
+;; Hooks.
+
+(defcustom gnus-load-hook nil
+  "A hook run while Gnus is loaded."
+  :group 'gnus-start
+  :type 'hook)
+
+(defcustom gnus-apply-kill-hook '(gnus-apply-kill-file)
+  "A hook called to apply kill files to a group.
+This hook is intended to apply a kill file to the selected newsgroup.
+The function `gnus-apply-kill-file' is called by default.
+
+Since a general kill file is too heavy to use only for a few
+newsgroups, I recommend you to use a lighter hook function.  For
+example, if you'd like to apply a kill file to articles which contains
+a string `rmgroup' in subject in newsgroup `control', you can use the
+following hook:
+
+ (setq gnus-apply-kill-hook
+      (list
+       (lambda ()
+         (cond ((string-match \"control\" gnus-newsgroup-name)
+                (gnus-kill \"Subject\" \"rmgroup\")
+                (gnus-expunge \"X\"))))))"
+  :group 'gnus-score-kill
+  :options '(gnus-apply-kill-file)
+  :type 'hook)
+
+(defcustom gnus-group-change-level-function nil
+  "Function run when a group level is changed.
+It is called with three parameters -- GROUP, LEVEL and OLDLEVEL."
+  :group 'gnus-group-levels
+  :type '(choice (const nil)
+                function))
+
+;;; Face thingies.
+
+(defcustom gnus-visual
+  '(summary-highlight group-highlight article-highlight
+                     mouse-face
+                     summary-menu group-menu article-menu
+                     tree-highlight menu highlight
+                     browse-menu server-menu
+                     page-marker tree-menu binary-menu pick-menu)
+  "*Enable visual features.
+If `visual' is disabled, there will be no menus and few faces.  Most of
+the visual customization options below will be ignored.  Gnus will use
+less space and be faster as a result.
+
+This variable can also be a list of visual elements to switch on.  For
+instance, to switch off all visual things except menus, you can say:
+
+   (setq gnus-visual \\='(menu))
+
+Valid elements include `summary-highlight', `group-highlight',
+`article-highlight', `mouse-face', `summary-menu', `group-menu',
+`article-menu', `tree-highlight', `menu', `highlight', `browse-menu',
+`server-menu', `page-marker', `tree-menu', `binary-menu', and`pick-menu'."
+  :group 'gnus-meta
+  :group 'gnus-visual
+  :type '(set (const summary-highlight)
+             (const group-highlight)
+             (const article-highlight)
+             (const mouse-face)
+             (const summary-menu)
+             (const group-menu)
+             (const article-menu)
+             (const tree-highlight)
+             (const menu)
+             (const highlight)
+             (const browse-menu)
+             (const server-menu)
+             (const page-marker)
+             (const tree-menu)
+             (const binary-menu)
+             (const pick-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)
+         (if (boundp 'gnus-mouse-face)
+             (or gnus-mouse-face 'highlight)
+           'highlight)
+       'default)
+    (error 'highlight))
+  "*Face used for group or summary buffer mouse highlighting.
+The line beneath the mouse pointer will be highlighted with this
+face."
+  :group 'gnus-visual
+  :type 'face)
+
+(defcustom gnus-article-save-directory gnus-directory
+  "*Name of the directory articles will be saved in (default \"~/News\")."
+  :group 'gnus-article-saving
+  :type 'directory)
+
+(defvar gnus-plugged t
+  "Whether Gnus is plugged or not.")
+
+(defcustom gnus-agent-cache t
+  "Controls use of the agent cache while plugged.
+When set, Gnus will prefer using the locally stored content rather
+than re-fetching it from the server.  You also need to enable
+`gnus-agent' for this to have any affect."
+  :version "22.1"
+  :group 'gnus-agent
+  :type 'boolean)
+
+(defcustom gnus-default-charset 'undecided
+  "Default charset assumed to be used when viewing non-ASCII characters.
+This variable is overridden on a group-to-group basis by the
+`gnus-group-charset-alist' variable and is only used on groups not
+covered by that variable."
+  :type 'symbol
+  :group 'gnus-charset)
+
+;; Fixme: Doc reference to agent.
+(defcustom gnus-agent t
+  "Whether we want to use the Gnus agent or not.
+
+You may customize gnus-agent to disable its use.  However, some
+back ends have started to use the agent as a client-side cache.
+Disabling the agent may result in noticeable loss of performance."
+  :version "22.1"
+  :group 'gnus-agent
+  :type 'boolean)
+
+(defcustom gnus-other-frame-function 'gnus
+  "Function called by the command `gnus-other-frame' when starting Gnus."
+  :group 'gnus-start
+  :type '(choice (function-item gnus)
+                (function-item gnus-no-server)
+                (function-item gnus-slave)
+                (function-item gnus-slave-no-server)))
+
+(defcustom gnus-other-frame-resume-function 'gnus-group-get-new-news
+  "Function called by the command `gnus-other-frame' when resuming Gnus."
+  :version "24.4"
+  :group 'gnus-start
+  :type '(choice (function-item gnus)
+                (function-item gnus-group-get-new-news)
+                (function-item gnus-no-server)
+                (function-item gnus-slave)
+                (function-item gnus-slave-no-server)))
+
+(defcustom gnus-other-frame-parameters nil
+  "Frame parameters used by `gnus-other-frame' to create a Gnus frame.
+This should be an alist for Emacs, or a plist for XEmacs."
+  :group 'gnus-start
+  :type (if (featurep 'xemacs)
+           '(repeat (list :inline t :format "%v"
+                          (symbol :tag "Property")
+                          (sexp :tag "Value")))
+         '(repeat (cons :format "%v"
+                        (symbol :tag "Parameter")
+                        (sexp :tag "Value")))))
+
+(defcustom gnus-user-agent '(emacs gnus type)
+  "Which information should be exposed in the User-Agent header.
+
+Can be a list of symbols or a string.  Valid symbols are `gnus'
+\(show Gnus version) and `emacs' \(show Emacs version).  In
+addition to the Emacs version, you can add `codename' \(show
+\(S)XEmacs codename) or either `config' \(show system
+configuration) or `type' \(show system type).  If you set it to
+a string, be sure to use a valid format, see RFC 2616."
+
+  :version "22.1"
+  :group 'gnus-message
+  :type '(choice (list (set :inline t
+                           (const gnus  :tag "Gnus version")
+                           (const emacs :tag "Emacs version")
+                           (choice :tag "system"
+                                   (const type   :tag "system type")
+                                   (const config :tag "system configuration"))
+                           (const codename :tag "Emacs codename")))
+                (string)))
+
+;; Convert old (< 2005-01-10) symbol type values:
+(when (symbolp gnus-user-agent)
+  (setq gnus-user-agent
+       (cond ((eq gnus-user-agent 'emacs-gnus-config)
+              '(emacs gnus config))
+             ((eq gnus-user-agent 'emacs-gnus-type)
+              '(emacs gnus type))
+             ((eq gnus-user-agent 'emacs-gnus)
+              '(emacs gnus))
+             ((eq gnus-user-agent 'gnus)
+              '(gnus))
+             (t gnus-user-agent)))
+  (gnus-message 1 "Converted `gnus-user-agent' to `%s'." gnus-user-agent)
+  (sit-for 1)
+  (if (get 'gnus-user-agent 'saved-value)
+      (customize-save-variable 'gnus-user-agent gnus-user-agent)
+    (gnus-message 1 "Edit your init file to make this change permanent.")
+    (sit-for 2)))
+
+\f
+;;; Internal variables
+
+(defvar gnus-agent-gcc-header "X-Gnus-Agent-Gcc")
+(defvar gnus-agent-meta-information-header "X-Gnus-Agent-Meta-Information")
+(defvar gnus-agent-method-p-cache nil
+  ; Reset each time gnus-agent-covered-methods is changed else
+  ; gnus-agent-method-p may mis-report a methods status.
+  )
+(defvar gnus-agent-target-move-group-header "X-Gnus-Agent-Move-To")
+(defvar gnus-draft-meta-information-header "X-Draft-From")
+(defvar gnus-group-get-parameter-function 'gnus-group-get-parameter)
+(defvar gnus-original-article-buffer " *Original Article*")
+(defvar gnus-newsgroup-name nil)
+(defvar gnus-ephemeral-servers nil)
+(defvar gnus-server-method-cache nil)
+(defvar gnus-extended-servers nil)
+
+;; The carpal mode has been removed, but define the variable for
+;; backwards compatibility.
+(defvar gnus-carpal nil)
+(make-obsolete-variable 'gnus-carpal nil "Emacs 24.1")
+
+(defvar gnus-agent-fetching nil
+  "Whether Gnus agent is in fetching mode.")
+
+(defvar gnus-agent-covered-methods nil
+  "A list of servers, NOT methods, showing which servers are covered by the agent.")
+
+(defvar gnus-command-method nil
+  "Dynamically bound variable that says what the current back end is.")
+
+(defvar gnus-current-select-method nil
+  "The current method for selecting a newsgroup.")
+
+(defvar gnus-tree-buffer "*Tree*"
+  "Buffer where Gnus thread trees are displayed.")
+
+;; Variable holding the user answers to all method prompts.
+(defvar gnus-method-history nil)
+
+;; Variable holding the user answers to all mail method prompts.
+(defvar gnus-mail-method-history nil)
+
+;; Variable holding the user answers to all group prompts.
+(defvar gnus-group-history nil)
+
+(defvar gnus-server-alist nil
+  "List of available servers.")
+
+(defcustom gnus-cache-directory
+  (nnheader-concat gnus-directory "cache/")
+  "*The directory where cached articles will be stored."
+  :group 'gnus-cache
+  :type 'directory)
+
+(defvar gnus-predefined-server-alist
+  `(("cache"
+     nnspool "cache"
+     (nnspool-spool-directory ,gnus-cache-directory)
+     (nnspool-nov-directory ,gnus-cache-directory)
+     (nnspool-active-file
+      ,(nnheader-concat gnus-cache-directory "active"))))
+  "List of predefined (convenience) servers.")
+
+(defconst gnus-article-mark-lists
+  '((marked . tick) (replied . reply)
+    (expirable . expire) (killed . killed)
+    (bookmarks . bookmark) (dormant . dormant)
+    (scored . score) (saved . save)
+    (cached . cache) (downloadable . download)
+    (unsendable . unsend) (forwarded . forward)
+    (seen . seen) (unexist . unexist)))
+
+(defconst gnus-article-special-mark-lists
+  '((seen range)
+    (unexist range)
+    (killed range)
+    (bookmark tuple)
+    (uid tuple)
+    (active 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
+;; `bookmark': don't propagated it, or fix the bug in update-mark.
+(defconst gnus-article-unpropagated-mark-lists
+  '(seen cache download unsend score bookmark unexist)
+  "Marks that shouldn't be propagated to back ends.
+Typical marks are those that make no sense in a standalone back end,
+such as a mark that says whether an article is stored in the cache
+\(which doesn't make sense in a standalone back end).")
+
+(defvar gnus-headers-retrieved-by nil)
+(defvar gnus-article-reply nil)
+(defvar gnus-override-method nil)
+(defvar gnus-opened-servers nil)
+
+(defvar gnus-current-kill-article nil)
+
+(defvar gnus-have-read-active-file nil)
+
+(defconst gnus-maintainer
+  "submit@debbugs.gnu.org (The Gnus Bugfixing Girls + Boys)"
+  "The mail address of the Gnus maintainers.")
+
+(defconst gnus-bug-package
+  "gnus"
+  "The package to use in the bug submission.")
+
+(defvar gnus-info-nodes
+  '((gnus-group-mode "(gnus)Group Buffer")
+    (gnus-summary-mode "(gnus)Summary Buffer")
+    (gnus-article-mode "(gnus)Article Buffer")
+    (gnus-server-mode "(gnus)Server Buffer")
+    (gnus-browse-mode "(gnus)Browse Foreign Server")
+    (gnus-tree-mode "(gnus)Tree Display"))
+  "Alist of major modes and related Info nodes.")
+
+(defvar gnus-summary-buffer "*Summary*")
+(defvar gnus-article-buffer "*Article*")
+(defvar gnus-server-buffer "*Server*")
+
+(defvar gnus-slave nil
+  "Whether this Gnus is a slave or not.")
+
+(defvar gnus-batch-mode nil
+  "Whether this Gnus is running in batch mode or not.")
+
+(defvar gnus-variable-list
+  '(gnus-newsrc-options gnus-newsrc-options-n
+                       gnus-newsrc-last-checked-date
+                       gnus-newsrc-alist gnus-server-alist
+                       gnus-killed-list gnus-zombie-list
+                       gnus-topic-topology gnus-topic-alist
+                       gnus-cloud-sequence
+                       gnus-cloud-covered-servers
+                       gnus-cloud-file-timestamps)
+  "Gnus variables saved in the quick startup file.")
+
+(defvar gnus-newsrc-alist nil
+  "Assoc list of read articles.
+`gnus-newsrc-hashtb' should be kept so that both hold the same information.")
+
+(defvar gnus-registry-alist nil
+  "Assoc list of registry data.
+gnus-registry.el will populate this if it's loaded.")
+
+(defvar gnus-newsrc-hashtb nil
+  "Hashtable of `gnus-newsrc-alist'.")
+
+(defvar gnus-killed-list nil
+  "List of killed newsgroups.")
+
+(defvar gnus-killed-hashtb nil
+  "Hash table equivalent of `gnus-killed-list'.")
+
+(defvar gnus-zombie-list nil
+  "List of almost dead newsgroups.")
+
+(defvar gnus-description-hashtb nil
+  "Descriptions of newsgroups.")
+
+(defvar gnus-list-of-killed-groups nil
+  "List of newsgroups that have recently been killed by the user.")
+
+(defvar gnus-active-hashtb nil
+  "Hashtable of active articles.")
+
+(defvar gnus-moderated-hashtb nil
+  "Hashtable of moderated newsgroups.")
+
+;; Save window configuration.
+(defvar gnus-prev-winconf nil)
+
+(defvar gnus-reffed-article-number nil)
+
+(defvar gnus-dead-summary nil)
+
+(defvar gnus-invalid-group-regexp "[: `'\"/]\\|^$"
+  "Regexp matching invalid groups.")
+
+(defvar gnus-other-frame-object nil
+  "A frame object which will be created by `gnus-other-frame'.")
+
+;;; End of variables.
+
+;; Define some autoload functions Gnus might use.
+(eval-and-compile
+
+  ;; This little mapcar goes through the list below and marks the
+  ;; symbols in question as autoloaded functions.
+  (mapc
+   (lambda (package)
+     (let ((interactive (nth 1 (memq ':interactive package))))
+       (mapcar
+       (lambda (function)
+         (let (keymap)
+           (when (consp function)
+             (setq keymap (car (memq 'keymap function)))
+             (setq function (car function)))
+           (unless (fboundp function)
+             (autoload function (car package) nil interactive keymap))))
+       (if (eq (nth 1 package) ':interactive)
+           (nthcdr 3 package)
+         (cdr package)))))
+   '(("info" :interactive t Info-goto-node)
+     ("pp" pp-to-string)
+     ("qp" quoted-printable-decode-region quoted-printable-decode-string)
+     ("ps-print" ps-print-preprint)
+     ("message" :interactive t
+      message-send-and-exit message-yank-original)
+     ("babel" babel-as-string)
+     ("nnmail" nnmail-split-fancy nnmail-article-group)
+     ("nnvirtual" nnvirtual-catchup-group nnvirtual-convert-headers)
+     ;; This is only used in message.el, which has an autoload.
+     ("rmailout" rmail-output)
+     ;; Next two used in gnus-util, which has autoloads, and contrib/sendmail.
+     ("rmail" rmail-count-new-messages rmail-show-message
+      ;; Next two only used in gnus-util.
+      rmail-summary-exists rmail-select-summary)
+     ;; Only used in gnus-util, which has an autoload.
+     ("rmailsum" rmail-update-summary)
+     ("gnus-xmas" gnus-xmas-splash)
+     ("score-mode" :interactive t gnus-score-mode)
+     ("gnus-mh" gnus-summary-save-article-folder
+      gnus-Folder-save-name gnus-folder-save-name)
+     ("gnus-mh" :interactive t gnus-summary-save-in-folder)
+     ("gnus-demon" gnus-demon-add-scanmail
+      gnus-demon-add-rescan gnus-demon-add-scan-timestamps
+      gnus-demon-add-disconnection gnus-demon-add-handler
+      gnus-demon-remove-handler)
+     ("gnus-demon" :interactive t
+      gnus-demon-init gnus-demon-cancel)
+     ("gnus-fun" gnus-convert-gray-x-face-to-xpm gnus-display-x-face-in-from
+      gnus-convert-image-to-gray-x-face gnus-convert-face-to-png
+      gnus-face-from-file)
+     ("gnus-salt" gnus-highlight-selected-tree gnus-possibly-generate-tree
+      gnus-tree-open gnus-tree-close)
+     ("gnus-srvr" gnus-enter-server-buffer gnus-server-set-info
+      gnus-server-server-name)
+     ("gnus-srvr" gnus-browse-foreign-server)
+     ("gnus-cite" :interactive t
+      gnus-article-highlight-citation gnus-article-hide-citation-maybe
+      gnus-article-hide-citation gnus-article-fill-cited-article
+      gnus-article-hide-citation-in-followups
+      gnus-article-fill-cited-long-lines)
+     ("gnus-kill" gnus-kill gnus-apply-kill-file-internal
+      gnus-kill-file-edit-file gnus-kill-file-raise-followups-to-author
+      gnus-execute gnus-expunge gnus-batch-kill gnus-batch-score)
+     ("gnus-registry" gnus-try-warping-via-registry
+      gnus-registry-handle-action)
+     ("gnus-cache" gnus-cache-possibly-enter-article gnus-cache-save-buffers
+      gnus-cache-possibly-remove-articles gnus-cache-request-article
+      gnus-cache-retrieve-headers gnus-cache-possibly-alter-active
+      gnus-cache-enter-remove-article gnus-cached-article-p
+      gnus-cache-open gnus-cache-close gnus-cache-update-article
+      gnus-cache-articles-in-group)
+     ("gnus-cache" :interactive t gnus-jog-cache gnus-cache-enter-article
+      gnus-cache-remove-article gnus-summary-insert-cached-articles)
+     ("gnus-score" :interactive t
+      gnus-summary-increase-score gnus-summary-set-score
+      gnus-summary-raise-thread gnus-summary-raise-same-subject
+      gnus-summary-raise-score gnus-summary-raise-same-subject-and-select
+      gnus-summary-lower-thread gnus-summary-lower-same-subject
+      gnus-summary-lower-score gnus-summary-lower-same-subject-and-select
+      gnus-summary-current-score gnus-score-delta-default
+      gnus-score-flush-cache gnus-score-close
+      gnus-possibly-score-headers gnus-score-followup-article
+      gnus-score-followup-thread)
+     ("gnus-score"
+      (gnus-summary-score-map keymap) gnus-score-save gnus-score-headers
+      gnus-current-score-file-nondirectory gnus-score-adaptive
+      gnus-score-find-trace gnus-score-file-name)
+     ("gnus-cus" :interactive t gnus-group-customize gnus-score-customize)
+     ("gnus-topic" :interactive t gnus-topic-mode)
+     ("gnus-topic" gnus-topic-remove-group gnus-topic-set-parameters
+      gnus-subscribe-topics)
+     ("gnus-salt" :interactive t gnus-pick-mode gnus-binary-mode)
+     ("gnus-uu" (gnus-uu-extract-map keymap) (gnus-uu-mark-map keymap))
+     ("gnus-uu" :interactive t
+      gnus-uu-digest-mail-forward gnus-uu-digest-post-forward
+      gnus-uu-mark-series gnus-uu-mark-region gnus-uu-mark-buffer
+      gnus-uu-mark-by-regexp gnus-uu-mark-all
+      gnus-uu-mark-sparse gnus-uu-mark-thread gnus-uu-decode-uu
+      gnus-uu-decode-uu-and-save gnus-uu-decode-unshar
+      gnus-uu-decode-unshar-and-save gnus-uu-decode-save
+      gnus-uu-decode-binhex gnus-uu-decode-uu-view
+      gnus-uu-decode-uu-and-save-view gnus-uu-decode-unshar-view
+      gnus-uu-decode-unshar-and-save-view gnus-uu-decode-save-view
+      gnus-uu-decode-binhex-view gnus-uu-unmark-thread
+      gnus-uu-mark-over gnus-uu-post-news gnus-uu-invert-processable)
+     ("gnus-uu" gnus-uu-delete-work-dir gnus-uu-unmark-thread)
+     ("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-group-news
+      gnus-summary-post-news gnus-summary-news-other-window
+      gnus-summary-followup gnus-summary-followup-with-original
+      gnus-summary-cancel-article gnus-summary-supersede-article
+      gnus-post-news gnus-summary-reply gnus-summary-reply-with-original
+      gnus-summary-mail-forward gnus-summary-mail-other-window
+      gnus-summary-resend-message gnus-summary-resend-bounced-mail
+      gnus-summary-wide-reply gnus-summary-followup-to-mail
+      gnus-summary-followup-to-mail-with-original gnus-bug
+      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-treat-from-picon)
+     ("smiley" :interactive t smiley-region)
+     ("gnus-win" gnus-configure-windows gnus-add-configuration)
+     ("gnus-sum" gnus-summary-insert-line gnus-summary-read-group
+      gnus-list-of-unread-articles gnus-list-of-read-articles
+      gnus-offer-save-summaries gnus-make-thread-indent-array
+      gnus-summary-exit gnus-update-read-articles gnus-summary-last-subject
+      gnus-summary-skip-intangible gnus-summary-article-number
+      gnus-data-header gnus-data-find)
+     ("gnus-group" gnus-group-insert-group-line gnus-group-quit
+      gnus-group-list-groups gnus-group-first-unread-group
+      gnus-group-set-mode-line gnus-group-set-info gnus-group-save-newsrc
+      gnus-group-setup-buffer gnus-group-get-new-news
+      gnus-group-make-help-group gnus-group-update-group
+      gnus-group-iterate gnus-group-group-name)
+     ("gnus-bcklg" gnus-backlog-request-article gnus-backlog-enter-article
+      gnus-backlog-remove-article)
+     ("gnus-art" gnus-article-read-summary-keys gnus-article-save
+      gnus-article-prepare gnus-article-set-window-start
+      gnus-article-next-page gnus-article-prev-page
+      gnus-request-article-this-buffer gnus-article-mode
+      gnus-article-setup-buffer gnus-narrow-to-page
+      gnus-article-delete-invisible-text gnus-treat-article)
+     ("gnus-art" :interactive t
+      gnus-article-hide-headers gnus-article-hide-boring-headers
+      gnus-article-treat-overstrike
+      gnus-article-remove-cr gnus-article-remove-trailing-blank-lines
+      gnus-article-display-x-face gnus-article-de-quoted-unreadable
+      gnus-article-de-base64-unreadable
+      gnus-article-decode-HZ
+      gnus-article-wash-html
+      gnus-article-unsplit-urls
+      gnus-article-hide-pem gnus-article-hide-signature
+      gnus-article-strip-leading-blank-lines gnus-article-date-local
+      gnus-article-date-original gnus-article-date-lapsed
+      ;;gnus-article-show-all-headers
+      gnus-article-edit-mode gnus-article-edit-article
+      gnus-article-edit-done gnus-article-decode-encoded-words
+      gnus-start-date-timer gnus-stop-date-timer
+      gnus-mime-view-all-parts)
+     ("gnus-int" gnus-request-type)
+     ("gnus-start" gnus-newsrc-parse-options gnus-1 gnus-no-server-1
+      gnus-dribble-enter gnus-read-init-file gnus-dribble-touch
+      gnus-check-reasonable-setup)
+     ("gnus-dup" gnus-dup-suppress-articles gnus-dup-unsuppress-article
+      gnus-dup-enter-articles)
+     ("gnus-range" gnus-copy-sequence)
+     ("gnus-eform" gnus-edit-form)
+     ("gnus-logic" gnus-score-advanced)
+     ("gnus-undo" gnus-undo-mode gnus-undo-register)
+     ("gnus-async" gnus-async-request-fetched-article gnus-async-prefetch-next
+      gnus-async-prefetch-article gnus-async-prefetch-remove-group
+      gnus-async-halt-prefetch)
+     ("gnus-agent" gnus-open-agent gnus-agent-get-function
+      gnus-agent-save-active gnus-agent-method-p
+      gnus-agent-get-undownloaded-list gnus-agent-fetch-session
+      gnus-summary-set-agent-mark gnus-agent-save-group-info
+      gnus-agent-request-article gnus-agent-retrieve-headers
+      gnus-agent-store-article gnus-agent-group-covered-p)
+     ("gnus-agent" :interactive t
+      gnus-unplugged gnus-agentize gnus-agent-batch)
+     ("gnus-vm" :interactive t gnus-summary-save-in-vm
+      gnus-summary-save-article-vm)
+     ("compface" uncompface)
+     ("gnus-draft" :interactive t gnus-draft-mode gnus-group-send-queue)
+     ("gnus-mlspl" gnus-group-split gnus-group-split-fancy)
+     ("gnus-mlspl" :interactive t gnus-group-split-setup
+      gnus-group-split-update)
+     ("gnus-delay" gnus-delay-initialize))))
+
+;;; gnus-sum.el thingies
+
+
+(defcustom gnus-summary-line-format "%U%R%z%I%(%[%4L: %-23,23f%]%) %s\n"
+  "*The format specification of the lines in the summary buffer.
+
+It works along the same lines as a normal formatting string,
+with some simple extensions.
+
+%N          Article number, left padded with spaces (string)
+%S          Subject (string)
+%s          Subject if it is at the root of a thread, and \"\"
+            otherwise (string)
+%n          Name of the poster (string)
+%a          Extracted name of the poster (string)
+%A          Extracted address of the poster (string)
+%F          Contents of the From: header (string)
+%f          Contents of the From: or To: headers (string)
+%x          Contents of the Xref: header (string)
+%D          Date of the article (string)
+%d          Date of the article (string) in DD-MMM format
+%o          Date of the article (string) in YYYYMMDD`T'HHMMSS
+            format
+%M          Message-id of the article (string)
+%r          References of the article (string)
+%c          Number of characters in the article (integer)
+%k          Pretty-printed version of the above (string)
+            For example, \"1.2k\" or \"0.4M\".
+%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)
+%U          \"Read\" status of this article.
+            See Info node `(gnus)Marking Articles'
+%[          Opening bracket (character, \"[\" or \"<\")
+%]          Closing bracket (character, \"]\" or \">\")
+%>          Spaces of length thread-level (string)
+%<          Spaces of length (- 20 thread-level) (string)
+%i          Article score (number)
+%z          Article zcore (character)
+%t          Number of articles under the current thread (number).
+%e          Whether the thread is empty or not (character).
+%V          Total thread score (number).
+%P          The line number (number).
+%O          Download mark (character).
+%*          If present, indicates desired cursor position
+            (instead of after first colon).
+%u          User defined specifier. The next character in the
+            format string should be a letter. Gnus will call the
+            function gnus-user-format-function-X, where X is the
+            letter following %u. The function will be passed the
+            current header as argument. The function should
+            return a string, which will be inserted into the
+            summary just like information from any other summary
+            specifier.
+&user-date; Age sensitive date format. Various date format is
+            defined in `gnus-user-date-format-alist'.
+
+
+The %U (status), %R (replied) and %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\" that.  This means that
+it is invalid to have these specs after a variable-length spec.  Well,
+you might not be arrested, but your summary buffer will look strange,
+which is bad enough.
+
+The smart choice is to have these specs as far to the left as
+possible.
+
+This restriction may disappear in later versions of Gnus.
+
+General format specifiers can also be used.
+See Info node `(gnus)Formatting Variables'."
+  :link '(custom-manual "(gnus)Formatting Variables")
+  :type 'string
+  :group 'gnus-summary-format)
+
+;;;
+;;; Skeleton keymaps
+;;;
+
+(defun gnus-suppress-keymap (keymap)
+  (suppress-keymap keymap)
+  (let ((keys `([delete] "\177" "\M-u"))) ;gnus-mouse-2
+    (while keys
+      (define-key keymap (pop keys) 'undefined))))
+
+(defvar gnus-article-mode-map
+  (let ((keymap (make-sparse-keymap)))
+    (gnus-suppress-keymap keymap)
+    keymap))
+(defvar gnus-summary-mode-map
+  (let ((keymap (make-keymap)))
+    (gnus-suppress-keymap keymap)
+    keymap))
+(defvar gnus-group-mode-map
+  (let ((keymap (make-keymap)))
+    (gnus-suppress-keymap keymap)
+    keymap))
+
+\f
+
+;; Fix by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>.
+;; If you want the cursor to go somewhere else, set these two
+;; functions in some startup hook to whatever you want.
+(defalias 'gnus-summary-position-point 'gnus-goto-colon)
+(defalias 'gnus-group-position-point 'gnus-goto-colon)
+
+;;; Various macros and substs.
+
+(defun gnus-header-from (header)
+  (mail-header-from header))
+
+(defmacro gnus-gethash (string hashtable)
+  "Get hash value of STRING in HASHTABLE."
+  `(symbol-value (intern-soft ,string ,hashtable)))
+
+(defmacro gnus-gethash-safe (string hashtable)
+  "Get hash value of STRING in HASHTABLE.
+Return nil if not defined."
+  `(let ((sym (intern-soft ,string ,hashtable)))
+     (and (boundp sym) (symbol-value sym))))
+
+(defmacro gnus-sethash (string value hashtable)
+  "Set hash value.  Arguments are STRING, VALUE, and HASHTABLE."
+  `(set (intern ,string ,hashtable) ,value))
+(put 'gnus-sethash 'edebug-form-spec '(form form form))
+
+(defmacro gnus-group-unread (group)
+  "Get the currently computed number of unread articles in GROUP."
+  `(car (gnus-gethash ,group gnus-newsrc-hashtb)))
+
+(defmacro gnus-group-entry (group)
+  "Get the newsrc entry for GROUP."
+  `(gnus-gethash ,group gnus-newsrc-hashtb))
+
+(defmacro gnus-active (group)
+  "Get active info on GROUP."
+  `(gnus-gethash ,group gnus-active-hashtb))
+
+(defmacro gnus-set-active (group active)
+  "Set GROUP's active info."
+  `(gnus-sethash ,group ,active gnus-active-hashtb))
+
+;; Info access macros.
+
+(defmacro gnus-info-group (info)
+  `(nth 0 ,info))
+(defmacro gnus-info-rank (info)
+  `(nth 1 ,info))
+(defmacro gnus-info-read (info)
+  `(nth 2 ,info))
+(defmacro gnus-info-marks (info)
+  `(nth 3 ,info))
+(defmacro gnus-info-method (info)
+  `(nth 4 ,info))
+(defmacro gnus-info-params (info)
+  `(nth 5 ,info))
+
+(defmacro gnus-info-level (info)
+  `(let ((rank (gnus-info-rank ,info)))
+     (if (consp rank)
+        (car rank)
+       rank)))
+(defmacro gnus-info-score (info)
+  `(let ((rank (gnus-info-rank ,info)))
+     (or (and (consp rank) (cdr rank)) 0)))
+
+(defmacro gnus-info-set-group (info group)
+  `(setcar ,info ,group))
+(defmacro gnus-info-set-rank (info rank)
+  `(setcar (nthcdr 1 ,info) ,rank))
+(defmacro gnus-info-set-read (info read)
+  `(setcar (nthcdr 2 ,info) ,read))
+(defmacro gnus-info-set-marks (info marks &optional extend)
+  (if extend
+      `(gnus-info-set-entry ,info ,marks 3)
+    `(setcar (nthcdr 3 ,info) ,marks)))
+(defmacro gnus-info-set-method (info method &optional extend)
+  (if extend
+      `(gnus-info-set-entry ,info ,method 4)
+    `(setcar (nthcdr 4 ,info) ,method)))
+(defmacro gnus-info-set-params (info params &optional extend)
+  (if extend
+      `(gnus-info-set-entry ,info ,params 5)
+    `(setcar (nthcdr 5 ,info) ,params)))
+
+(defun gnus-info-set-entry (info entry number)
+  ;; Extend the info until we have enough elements.
+  (while (<= (length info) number)
+    (nconc info (list nil)))
+  ;; Set the entry.
+  (setcar (nthcdr number info) entry))
+
+(defmacro gnus-info-set-level (info level)
+  `(let ((rank (cdr ,info)))
+     (if (consp (car rank))
+        (setcar (car rank) ,level)
+       (setcar rank ,level))))
+(defmacro gnus-info-set-score (info score)
+  `(let ((rank (cdr ,info)))
+     (if (consp (car rank))
+        (setcdr (car rank) ,score)
+       (setcar rank (cons (car rank) ,score)))))
+
+(defmacro gnus-get-info (group)
+  `(nth 2 (gnus-gethash ,group gnus-newsrc-hashtb)))
+
+(defun gnus-set-info (group info)
+  (setcar (nthcdr 2 (gnus-gethash group gnus-newsrc-hashtb))
+         info))
+
+;;; Load the compatibility functions.
+
+(require 'gnus-ems)
+
+\f
+;;;
+;;; Shutdown
+;;;
+
+(defvar gnus-shutdown-alist nil)
+
+(defun gnus-add-shutdown (function &rest symbols)
+  "Run FUNCTION whenever one of SYMBOLS is shut down."
+  (push (cons function symbols) gnus-shutdown-alist))
+
+(defun gnus-shutdown (symbol)
+  "Shut down everything that waits for SYMBOL."
+  (dolist (entry gnus-shutdown-alist)
+    (when (memq symbol (cdr entry))
+      (funcall (car entry)))))
+
+\f
+;;;
+;;; 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-parameter-subscribed group)
+       (setq address (mail-strip-quoted-names
+                      (or (gnus-group-fast-parameter group 'to-address)
+                          (gnus-group-fast-parameter group 'to-list))))
+       (when address
+         (add-to-list 'addresses address))))
+    (when addresses
+      (list (mapconcat 'regexp-quote addresses "\\|")))))
+
+(defmacro gnus-string-or (&rest strings)
+  "Return the first element of STRINGS that is a non-blank string.
+STRINGS will be evaluated in normal `or' order."
+  `(gnus-string-or-1 (list ,@strings)))
+
+(defun gnus-string-or-1 (strings)
+  (let (string)
+    (while strings
+      (setq string (pop strings))
+      (if (string-match "^[ \t]*$" string)
+         (setq string nil)
+       (setq strings nil)))
+    string))
+
+(defun gnus-version (&optional arg)
+  "Version number of this version of Gnus.
+If ARG, insert string at point."
+  (interactive "P")
+  (if arg
+      (insert (message gnus-version))
+    (message gnus-version)))
+
+(defun gnus-continuum-version (&optional version)
+  "Return VERSION as a floating point number."
+  (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)))
+         (number (match-string 2 version))
+         major minor least)
+      (unless (string-match
+              "\\([0-9]\\)\\.\\([0-9]+\\)\\.?\\([0-9]+\\)?" number)
+       (error "Invalid version string: %s" version))
+      (setq major (string-to-number (match-string 1 number))
+           minor (string-to-number (match-string 2 number))
+           least (if (match-beginning 3)
+                     (string-to-number (match-string 3 number))
+                   0))
+      (string-to-number
+       (if (zerop major)
+            (format "%1.2f00%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 (&optional nodename)
+  "Find Info documentation of Gnus."
+  (interactive)
+  ;; Enlarge info window if needed.
+  (let (gnus-info-buffer)
+    (Info-goto-node (or nodename (cadr (assq major-mode gnus-info-nodes))))
+    (setq gnus-info-buffer (current-buffer))
+    (gnus-configure-windows 'info)))
+
+;;;
+;;; gnus-interactive
+;;;
+
+(defvar gnus-current-prefix-symbol nil
+  "Current prefix symbol.")
+
+(defvar gnus-current-prefix-symbols nil
+  "List of current prefix symbols.")
+
+(defun gnus-interactive (string &optional params)
+  "Return a list that can be fed to `interactive'.
+See `interactive' for full documentation.
+
+Adds the following specs:
+
+y -- The current symbolic prefix.
+Y -- A list of the current symbolic prefix(es).
+A -- Article number.
+H -- Article header.
+g -- Group name."
+  (let ((i 0)
+       out c prompt)
+    (while (< i (length string))
+      (string-match ".\\([^\n]*\\)\n?" string i)
+      (setq c (aref string i))
+      (when (match-end 1)
+       (setq prompt (match-string 1 string)))
+      (setq i (match-end 0))
+      ;; We basically emulate just about everything that
+      ;; `interactive' does, but add the specs listed above.
+      (push
+       (cond
+       ((= c ?a)
+        (completing-read prompt obarray 'fboundp t))
+       ((= c ?b)
+        (read-buffer prompt (current-buffer) t))
+       ((= c ?B)
+        (read-buffer prompt (other-buffer (current-buffer))))
+       ((= c ?c)
+        (read-char))
+       ((= c ?C)
+        (completing-read prompt obarray 'commandp t))
+       ((= c ?d)
+        (point))
+       ((= c ?D)
+        (read-directory-name prompt nil default-directory 'lambda))
+       ((= c ?f)
+        (read-file-name prompt nil nil 'lambda))
+       ((= c ?F)
+        (read-file-name prompt))
+       ((= c ?k)
+        (read-key-sequence prompt))
+       ((= c ?K)
+        (error "Not implemented spec"))
+       ((= c ?e)
+        (error "Not implemented spec"))
+       ((= c ?m)
+        (mark))
+       ((= c ?N)
+        (error "Not implemented spec"))
+       ((= c ?n)
+        (string-to-number (read-from-minibuffer prompt)))
+       ((= c ?p)
+        (prefix-numeric-value current-prefix-arg))
+       ((= c ?P)
+        current-prefix-arg)
+       ((= c ?r)
+        'gnus-prefix-nil)
+       ((= c ?s)
+        (read-string prompt))
+       ((= c ?S)
+        (intern (read-string prompt)))
+       ((= c ?v)
+        (read-variable prompt))
+       ((= c ?x)
+        (read-minibuffer prompt))
+       ((= c ?x)
+        (eval-minibuffer prompt))
+       ;; And here the new specs come.
+       ((= c ?y)
+        gnus-current-prefix-symbol)
+       ((= c ?Y)
+        gnus-current-prefix-symbols)
+       ((= c ?g)
+        (gnus-group-group-name))
+       ((= c ?A)
+        (gnus-summary-skip-intangible)
+        (or (get-text-property (point) 'gnus-number)
+            (gnus-summary-last-subject)))
+       ((= c ?H)
+        (gnus-data-header (gnus-data-find (gnus-summary-article-number))))
+       (t
+        (error "Non-implemented spec")))
+       out)
+      (cond
+       ((= c ?r)
+       (push (if (< (point) (mark)) (point) (mark)) out)
+       (push (if (> (point) (mark)) (point) (mark)) out))))
+    (setq out (delq 'gnus-prefix-nil out))
+    (nreverse out)))
+
+(defun gnus-symbolic-argument (&optional arg)
+  "Read a symbolic argument and a command, and then execute command."
+  (interactive "P")
+  (let* ((in-command (this-command-keys))
+        (command in-command)
+        gnus-current-prefix-symbols
+        gnus-current-prefix-symbol
+        syms)
+    (while (equal in-command command)
+      (message "%s-" (key-description (this-command-keys)))
+      (push (intern (char-to-string (read-char))) syms)
+      (setq command (read-key-sequence nil t)))
+    (setq gnus-current-prefix-symbols (nreverse syms)
+         gnus-current-prefix-symbol (car gnus-current-prefix-symbols))
+    (call-interactively (key-binding command t))))
+
+;;; More various functions.
+
+(defsubst gnus-check-backend-function (func group)
+  "Check whether GROUP supports function FUNC.
+GROUP can either be a string (a group name) or a select method."
+  (ignore-errors
+    (let ((method (if (stringp group)
+                     (car (gnus-find-method-for-group group))
+                   group)))
+      (unless (featurep method)
+       (require method))
+      (fboundp (intern (format "%s-%s" method func))))))
+
+(defun gnus-group-read-only-p (&optional group)
+  "Check whether GROUP supports editing or not.
+If GROUP is nil, `gnus-newsgroup-name' will be checked instead.  Note
+that that variable is buffer-local to the summary buffers."
+  (let ((group (or group gnus-newsgroup-name)))
+    (not (gnus-check-backend-function 'request-replace-article group))))
+
+(defun gnus-virtual-group-p (group)
+  "Say whether GROUP is virtual or not."
+  (memq 'virtual (assoc (symbol-name (car (gnus-find-method-for-group group)))
+                       gnus-valid-select-methods)))
+
+(defun gnus-news-group-p (group &optional article)
+  "Return non-nil if GROUP (and ARTICLE) come from a news server."
+  (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.
+
+;; Check whether to use long file names.
+(defun gnus-use-long-file-name (symbol)
+  ;; The variable has to be set...
+  (and gnus-use-long-file-name
+       ;; If it isn't a list, then we return t.
+       (or (not (listp gnus-use-long-file-name))
+          ;; If it is a list, and the list contains `symbol', we
+          ;; return nil.
+          (not (memq symbol gnus-use-long-file-name)))))
+
+;; Generate a unique new group name.
+(defun gnus-generate-new-group-name (leaf)
+  (let ((name leaf)
+       (num 0))
+    (while (gnus-group-entry name)
+      (setq name (concat leaf "<" (int-to-string (setq num (1+ num))) ">")))
+    name))
+
+(defun gnus-ephemeral-group-p (group)
+  "Say whether GROUP is ephemeral or not."
+  (gnus-group-get-parameter group 'quit-config t))
+
+(defun gnus-group-quit-config (group)
+  "Return the quit-config of GROUP."
+  (gnus-group-get-parameter group 'quit-config t))
+
+(defun gnus-kill-ephemeral-group (group)
+  "Remove ephemeral GROUP from relevant structures."
+  (gnus-sethash group nil gnus-newsrc-hashtb))
+
+(defun gnus-simplify-mode-line ()
+  "Make mode lines a bit simpler."
+  (setq mode-line-modified (cdr gnus-mode-line-modified))
+  (when (listp mode-line-format)
+    (make-local-variable 'mode-line-format)
+    (setq mode-line-format (copy-sequence mode-line-format))
+    (when (equal (nth 3 mode-line-format) "   ")
+      (setcar (nthcdr 3 mode-line-format) " "))))
+
+;;; Servers and groups.
+
+(defsubst gnus-server-add-address (method)
+  (let ((method-name (symbol-name (car method))))
+    (if (and (memq 'address (assoc method-name gnus-valid-select-methods))
+            (not (assq (intern (concat method-name "-address")) method))
+            (memq 'physical-address (assq (car method)
+                                          gnus-valid-select-methods)))
+       (append method (list (list (intern (concat method-name "-address"))
+                                  (nth 1 method))))
+      method)))
+
+(defsubst gnus-method-to-server (method &optional nocache no-enter-cache)
+  (catch 'server-name
+    (setq method (or method gnus-select-method))
+
+    ;; Perhaps it is already in the cache.
+    (unless nocache
+      (mapc (lambda (name-method)
+             (if (equal (cdr name-method) method)
+                 (throw 'server-name (car name-method))))
+           gnus-server-method-cache))
+
+    (mapc
+     (lambda (server-alist)
+       (mapc (lambda (name-method)
+              (when (gnus-methods-equal-p (cdr name-method) method)
+                (unless (member name-method gnus-server-method-cache)
+                  (push name-method gnus-server-method-cache))
+                (throw 'server-name (car name-method))))
+            server-alist))
+     (list gnus-server-alist
+          gnus-predefined-server-alist))
+
+    (let* ((name (if (member (cadr method) '(nil ""))
+                    (format "%s" (car method))
+                  (format "%s:%s" (car method) (cadr method))))
+          (name-method (cons name method)))
+      (when (and (not (member name-method gnus-server-method-cache))
+                (not no-enter-cache)
+                (not (assoc (car name-method) gnus-server-method-cache)))
+       (push name-method gnus-server-method-cache))
+      name)))
+
+(defsubst gnus-server-to-method (server)
+  "Map virtual server names to select methods."
+  (or (and server (listp server) server)
+      (cdr (assoc server gnus-server-method-cache))
+      (let ((result
+            (or
+             ;; Perhaps this is the native server?
+             (and (equal server "native") gnus-select-method)
+             ;; It should be in the server alist.
+             (cdr (assoc server gnus-server-alist))
+             ;; It could be in the predefined server alist.
+             (cdr (assoc server gnus-predefined-server-alist))
+             ;; If not, we look through all the opened server
+             ;; to see whether we can find it there.
+             (let ((opened gnus-opened-servers))
+               (while (and opened
+                           (not (equal server (format "%s:%s" (caaar opened)
+                                                      (cadaar opened)))))
+                 (pop opened))
+               (caar opened))
+             ;; It could be a named method, search all servers
+             (let ((servers gnus-secondary-select-methods))
+               (while (and servers
+                           (not (equal server (format "%s:%s" (caar servers)
+                                                      (cadar servers)))))
+                 (pop servers))
+               (car servers))
+             ;; This could be some sort of foreign server that I
+             ;; simply haven't opened (yet).  Do a brute-force scan
+             ;; of the entire gnus-newsrc-alist for the server name
+             ;; of every method.  As a side-effect, loads the
+             ;; gnus-server-method-cache so this only happens once,
+             ;; if at all.
+             (let ((alist (cdr gnus-newsrc-alist))
+                   method match)
+               (while alist
+                 (setq method (gnus-info-method (pop alist)))
+                 (when (and (not (stringp method))
+                            (equal server
+                                   (gnus-method-to-server method nil t)))
+                   (setq match method
+                         alist nil)))
+               match))))
+       (when (and result
+                  (not (assoc server gnus-server-method-cache)))
+         (push (cons server result) gnus-server-method-cache))
+       result)))
+
+(defsubst gnus-server-get-method (group method)
+  ;; Input either a server name, and extended server name, or a
+  ;; select method, and return a select method.
+  (cond ((stringp method)
+        (gnus-server-to-method method))
+       ((equal method gnus-select-method)
+        gnus-select-method)
+       ((and (stringp (car method))
+             group)
+        (gnus-server-extend-method group method))
+       ((and method
+             (not group)
+             (equal (cadr method) ""))
+        method)
+       (t
+        (gnus-server-add-address method))))
+
+(defmacro gnus-method-equal (ss1 ss2)
+  "Say whether two servers are equal."
+  `(let ((s1 ,ss1)
+        (s2 ,ss2))
+     (or (equal s1 s2)
+        (and (= (length s1) (length s2))
+             (progn
+               (while (and s1 (member (car s1) s2))
+                 (setq s1 (cdr s1)))
+               (null s1))))))
+
+(defun gnus-methods-equal-p (m1 m2)
+  (let ((m1 (or m1 gnus-select-method))
+       (m2 (or m2 gnus-select-method)))
+    (or (equal m1 m2)
+       (and (eq (car m1) (car m2))
+            (or (not (memq 'address (assoc (symbol-name (car m1))
+                                           gnus-valid-select-methods)))
+                (equal (nth 1 m1) (nth 1 m2)))))))
+
+(defsubst gnus-sloppily-equal-method-parameters (m1 m2)
+  ;; Check parameters for sloppy equality.
+  (let ((p1 (copy-sequence (cddr m1)))
+       (p2 (copy-sequence (cddr m2)))
+       e1 e2)
+    (block nil
+      (while (setq e1 (pop p1))
+       (unless (setq e2 (assq (car e1) p2))
+         ;; The parameter doesn't exist in p2.
+         (return nil))
+       (setq p2 (delq e2 p2))
+       (unless (equal e1 e2)
+         (if (not (and (stringp (cadr e1))
+                       (stringp (cadr e2))))
+             (return nil)
+           ;; Special-case string parameter comparison so that we
+           ;; can uniquify them.
+           (let ((s1 (cadr e1))
+                 (s2 (cadr e2)))
+             (when (string-match "/$" s1)
+               (setq s1 (directory-file-name s1)))
+             (when (string-match "/$" s2)
+               (setq s2 (directory-file-name s2)))
+             (unless (equal s1 s2)
+               (return nil))))))
+      ;; If p2 now is empty, they were equal.
+      (null p2))))
+
+(defun gnus-method-ephemeral-p (method)
+  (let ((equal nil))
+    (dolist (ephemeral gnus-ephemeral-servers)
+      (when (gnus-sloppily-equal-method-parameters method ephemeral)
+       (setq equal t)))
+    equal))
+
+(defun gnus-methods-sloppily-equal (m1 m2)
+  ;; Same method.
+  (or
+   (eq m1 m2)
+   ;; Type and name are equal.
+   (and
+    (eq (car m1) (car m2))
+    (equal (cadr m1) (cadr m2))
+    (gnus-sloppily-equal-method-parameters m1 m2))))
+
+(defun gnus-server-equal (m1 m2)
+  "Say whether two methods are equal."
+  (let ((m1 (cond ((null m1) gnus-select-method)
+                 ((stringp m1) (gnus-server-to-method m1))
+                 (t m1)))
+       (m2 (cond ((null m2) gnus-select-method)
+                 ((stringp m2) (gnus-server-to-method m2))
+                 (t m2))))
+    (gnus-method-equal m1 m2)))
+
+(defun gnus-servers-using-backend (backend)
+  "Return a list of known servers using BACKEND."
+  (let ((opened gnus-opened-servers)
+       out)
+    (while opened
+      (when (eq backend (caaar opened))
+       (push (caar opened) out))
+      (pop opened))
+    out))
+
+(defun gnus-archive-server-wanted-p ()
+  "Say whether the user wants to use the archive server."
+  (cond
+   ((or (not gnus-message-archive-method)
+       (not gnus-message-archive-group))
+    nil)
+   ((and gnus-message-archive-method gnus-message-archive-group)
+    t)
+   (t
+    (let ((active (cadr (assq 'nnfolder-active-file
+                             gnus-message-archive-method))))
+      (and active
+          (file-exists-p active))))))
+
+(defsubst gnus-method-to-server-name (method)
+  (concat
+   (format "%s" (car method))
+   (when (and
+         (or (assoc (format "%s" (car method))
+                    (gnus-methods-using 'address))
+             (gnus-server-equal method gnus-message-archive-method))
+         (nth 1 method)
+         (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 &optional full)
+  "Return the whole name from GROUP and METHOD.
+Call with full set to get the fully qualified group name (even if the
+server is native)."
+  (when (stringp method)
+    (setq method (gnus-server-to-method method)))
+  (if (or (not method)
+         (and (not full) (gnus-server-equal method "native"))
+         ;;;!!! This might not be right.  We'll see...
+         ;(string-match ":" group)
+         )
+      group
+    (concat (gnus-method-to-server-name method) ":" group)))
+
+(defun gnus-group-full-name (group method)
+  "Return the full name from GROUP and METHOD, even if the method is native."
+  (gnus-group-prefixed-name group method t))
+
+(defun gnus-group-guess-full-name-from-command-method (group)
+  "Guess the full name from GROUP, even if the method is native."
+  (if (gnus-group-prefixed-p group)
+      group
+    (gnus-group-full-name group gnus-command-method)))
+
+(defun gnus-group-real-prefix (group)
+  "Return the prefix of the current group name."
+  (if (stringp group)
+      (if (string-match "^[^:]+:" group)
+         (substring group 0 (match-end 0))
+       "")
+    nil))
+
+(defun gnus-group-short-name (group)
+  "Return the short group name."
+  (let ((prefix (gnus-group-real-prefix group)))
+    (if (< 0 (length prefix))
+       (substring group (length prefix) nil)
+      group)))
+
+(defun gnus-group-prefixed-p (group)
+  "Return the prefix of the current group name."
+  (< 0 (length (gnus-group-real-prefix group))))
+
+(declare-function gnus-group-decoded-name "gnus-group" (string))
+
+(defun gnus-summary-buffer-name (group)
+  "Return the summary buffer name of GROUP."
+  (concat "*Summary " (gnus-group-decoded-name group) "*"))
+
+(defun gnus-group-method (group)
+  "Return the server or method used for selecting GROUP.
+You should probably use `gnus-find-method-for-group' instead."
+  (let ((prefix (gnus-group-real-prefix group)))
+    (if (equal prefix "")
+       gnus-select-method
+      (let ((servers gnus-opened-servers)
+           (server "")
+           backend possible found)
+       (if (string-match "^[^\\+]+\\+" prefix)
+           (setq backend (intern (substring prefix 0 (1- (match-end 0))))
+                 server (substring prefix (match-end 0) (1- (length prefix))))
+         (setq backend (intern (substring prefix 0 (1- (length prefix))))))
+       (while servers
+         (when (eq (caaar servers) backend)
+           (setq possible (caar servers))
+           (when (equal (cadaar servers) server)
+             (setq found (caar servers))))
+         (pop servers))
+       (or (car (rassoc found gnus-server-alist))
+           found
+           (car (rassoc possible gnus-server-alist))
+           possible
+           (list backend server))))))
+
+(defsubst gnus-native-method-p (method)
+  "Return whether METHOD is the native select method."
+  (gnus-method-equal method gnus-select-method))
+
+(defsubst gnus-secondary-method-p (method)
+  "Return whether METHOD is a secondary select method."
+  (let ((methods gnus-secondary-select-methods)
+       (gmethod (inline (gnus-server-get-method nil method))))
+    (while (and methods
+               (not (gnus-method-equal
+                     (inline (gnus-server-get-method nil (car methods)))
+                     gmethod)))
+      (setq methods (cdr methods)))
+    methods))
+
+(defun gnus-method-simplify (method)
+  "Return the shortest uniquely identifying string or method for METHOD."
+  (cond ((stringp method)
+        method)
+       ((gnus-native-method-p method)
+        nil)
+       ((gnus-secondary-method-p method)
+        (format "%s:%s" (nth 0 method) (nth 1 method)))
+       (t
+        method)))
+
+(defun gnus-groups-from-server (server)
+  "Return a list of all groups that are fetched from SERVER."
+  (let ((alist (cdr gnus-newsrc-alist))
+       info groups)
+    (while (setq info (pop alist))
+      (when (gnus-server-equal (gnus-info-method info) server)
+       (push (gnus-info-group info) groups)))
+    (sort groups 'string<)))
+
+(defun gnus-group-foreign-p (group)
+  "Say whether a group is foreign or not."
+  (and (not (gnus-group-native-p group))
+       (not (gnus-group-secondary-p group))))
+
+(defun gnus-group-native-p (group)
+  "Say whether the group is native or not."
+  (not (string-match ":" group)))
+
+(defun gnus-group-secondary-p (group)
+  "Say whether the group is secondary or not."
+  (gnus-secondary-method-p (gnus-find-method-for-group group)))
+
+(defun gnus-parameters-get-parameter (group)
+  "Return the group parameters for GROUP from `gnus-parameters'."
+  (let ((case-fold-search (if (eq gnus-parameters-case-fold-search 'default)
+                             case-fold-search
+                           gnus-parameters-case-fold-search))
+       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."
+  (let ((start (string-match match group)))
+    (if start
+        (let ((matched-string (substring group start (match-end 0))))
+          ;; Build match groups
+          (string-match match matched-string)
+          (replace-match value nil nil matched-string))
+      group)))
+
+(defun gnus-expand-group-parameters (match parameters group)
+  "Go through PARAMETERS and expand them according to the match data."
+  (let (new)
+    (dolist (elem parameters)
+      (cond
+       ((and (stringp (cdr elem))
+             (string-match "\\\\[0-9&]" (cdr elem)))
+        (push (cons (car elem)
+                    (gnus-expand-group-parameter match (cdr elem) group))
+              new))
+       ;; For `sieve' group parameters, perform substitutions for every
+       ;; string within the match rule.  This allows for parameters such
+       ;; as:
+       ;;  ("list\\.\\(.*\\)"
+       ;;   (sieve header :is "list-id" "<\\1.domain.org>"))
+       ((eq 'sieve (car elem))
+        (push (mapcar (lambda (sieve-elem)
+                        (if (and (stringp sieve-elem)
+                                 (string-match "\\\\[0-9&]" sieve-elem))
+                            (gnus-expand-group-parameter match sieve-elem
+                                                         group)
+                          sieve-elem))
+                      (cdr elem))
+              new))
+       (t
+       (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.
+  (let* ((params (funcall gnus-group-get-parameter-function group))
+        ;; Start easy, check the "real" group parameters.
+        (simple-results
+         (gnus-group-parameter-value params symbol allow-list t)))
+    (if simple-results
+       ;; Found results; return them.
+       (car simple-results)
+      ;; We didn't find 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.
+           (let ((this-result
+                  (gnus-group-parameter-value (cdr head) symbol allow-list t)))
+             (when this-result
+               (setq result (car this-result))
+               ;; Expand if necessary.
+               (cond
+                 ((and (stringp result) (string-match "\\\\[0-9&]" result))
+                  (setq result (gnus-expand-group-parameter
+                                (car head) result group)))
+                 ;; For `sieve' group parameters, perform substitutions
+                 ;; for every string within the match rule (see above).
+                 ((eq symbol 'sieve)
+                  (setq result
+                        (mapcar (lambda (elem)
+                                  (if (stringp elem)
+                                      (gnus-expand-group-parameter (car head)
+                                                                   elem group)
+                                    elem))
+                                result))))))))
+       ;; 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 you call this function inside a loop, consider using the faster
+`gnus-group-fast-parameter' instead."
+  (with-current-buffer (if (buffer-live-p (get-buffer gnus-group-buffer))
+                          gnus-group-buffer
+                        (current-buffer))
+    (if symbol
+       (gnus-group-fast-parameter group symbol allow-list)
+      (nconc
+       (copy-sequence
+       (funcall gnus-group-get-parameter-function group))
+       (gnus-parameters-get-parameter group)))))
+
+(defun gnus-group-get-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 ALLOW-LIST, also allow list as a result.
+Most functions should use `gnus-group-find-parameter', which
+also examines the topic parameters."
+  (let ((params (gnus-info-params (gnus-get-info group))))
+    (if symbol
+       (gnus-group-parameter-value params symbol allow-list)
+      params)))
+
+(defun gnus-group-parameter-value (params symbol &optional
+                                         allow-list present-p)
+  "Return the value of SYMBOL in group PARAMS.
+If ALLOW-LIST, also allow list as a result."
+  ;; We only wish to return group parameters (dotted lists) and
+  ;; not local variables, which may have the same names.
+  ;; But first we handle single elements...
+  (or (car (memq symbol params))
+      ;; Handle alist.
+      (let (elem)
+       (catch 'found
+         (while (setq elem (pop params))
+           (when (and (consp elem)
+                      (eq (car elem) symbol)
+                      (or allow-list
+                          (atom (cdr elem))))
+             (throw 'found (if present-p (list (cdr elem))
+                             (cdr elem)))))))))
+
+(defun gnus-group-add-parameter (group param)
+  "Add parameter PARAM to GROUP."
+  (let ((info (gnus-get-info group)))
+    (when info
+      (gnus-group-remove-parameter group (if (consp param) (car param) param))
+      ;; Cons the new param to the old one and update.
+      (gnus-group-set-info (cons param (gnus-info-params info))
+                          group 'params))))
+
+(defun gnus-group-set-parameter (group name value)
+  "Set parameter NAME to VALUE in GROUP.
+GROUP can also be an INFO structure."
+  (let ((info (if (listp group)
+                 group
+               (gnus-get-info group))))
+    (when info
+      (gnus-group-remove-parameter group name)
+      (let ((old-params (gnus-info-params info))
+           (new-params (list (cons name value))))
+       (while old-params
+         (when (or (not (listp (car old-params)))
+                   (not (eq (caar old-params) name)))
+           (setq new-params (append new-params (list (car old-params)))))
+         (setq old-params (cdr old-params)))
+       (if (listp group)
+           (gnus-info-set-params info new-params t)
+         (gnus-group-set-info new-params (gnus-info-group info) 'params))))))
+
+(defun gnus-group-remove-parameter (group name)
+  "Remove parameter NAME from GROUP.
+GROUP can also be an INFO structure."
+  (let ((info (if (listp group)
+                 group
+               (gnus-get-info group))))
+    (when info
+      (let ((params (gnus-info-params info)))
+       (when params
+         (setq params (delq name params))
+         (while (assq name params)
+           (gnus-alist-pull name params))
+         (gnus-info-set-params info params))))))
+
+(defun gnus-group-add-score (group &optional score)
+  "Add SCORE to the GROUP score.
+If SCORE is nil, add 1 to the score of GROUP."
+  (let ((info (gnus-get-info group)))
+    (when info
+      (gnus-info-set-score info (+ (gnus-info-score info) (or score 1))))))
+
+(defun gnus-short-group-name (group &optional levels)
+  "Collapse GROUP name LEVELS.
+Select methods are stripped and any remote host name is stripped down to
+just the host name."
+  (let* ((name "")
+        (foreign "")
+        (depth 0)
+        (skip 1)
+        (levels (or levels
+                    gnus-group-uncollapsed-levels
+                    (progn
+                      (while (string-match "\\." group skip)
+                        (setq skip (match-end 0)
+                              depth (+ depth 1)))
+                      depth))))
+    ;; Separate foreign select method from group name and collapse.
+   ;; 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)))
+          (plus (and server (string-match "+" server))))
+      (when server
+       (if plus
+           (setq foreign (substring server (+ 1 plus)
+                                    (string-match "\\." server))
+                 group (substring group (+ 1 colon)))
+         (setq foreign server
+               group (substring group (+ 1 colon))))
+       (setq foreign (concat foreign ":")))
+      ;; Collapse group name leaving LEVELS uncollapsed elements
+      (let* ((slist (split-string group "/"))
+            (slen (length slist))
+            (dlist (split-string group "\\."))
+            (dlen (length dlist))
+            glist
+            glen
+            gsep
+            res)
+       (if (> slen dlen)
+           (setq glist slist
+                 glen slen
+                 gsep "/")
+         (setq glist dlist
+               glen dlen
+               gsep "."))
+       (setq levels (- glen levels))
+       (dolist (g glist)
+         (push (if (>= (decf levels) 0)
+                   (if (zerop (length g))
+                       ""
+                     (substring g 0 1))
+                 g)
+               res))
+       (concat foreign (mapconcat 'identity (nreverse res) gsep))))))
+
+(defun gnus-narrow-to-body ()
+  "Narrow to the body of an article."
+  (narrow-to-region
+   (progn
+     (goto-char (point-min))
+     (or (search-forward "\n\n" nil t)
+        (point-max)))
+   (point-max)))
+
+\f
+;;;
+;;; Kill file handling.
+;;;
+
+(defun gnus-apply-kill-file ()
+  "Apply a kill file to the current newsgroup.
+Returns the number of articles marked as read."
+  (if (or (file-exists-p (gnus-newsgroup-kill-file nil))
+         (file-exists-p (gnus-newsgroup-kill-file gnus-newsgroup-name)))
+      (gnus-apply-kill-file-internal)
+    0))
+
+(defun gnus-kill-save-kill-buffer ()
+  (let ((file (gnus-newsgroup-kill-file gnus-newsgroup-name)))
+    (when (get-file-buffer file)
+      (with-current-buffer (get-file-buffer file)
+       (when (buffer-modified-p)
+         (save-buffer))
+       (kill-buffer (current-buffer))))))
+
+(defcustom gnus-kill-file-name "KILL"
+  "Suffix of the kill files."
+  :group 'gnus-score-kill
+  :group 'gnus-score-files
+  :type 'string)
+
+(defun gnus-newsgroup-kill-file (newsgroup)
+  "Return the name of a kill file name for NEWSGROUP.
+If NEWSGROUP is nil, return the global kill file name instead."
+  (cond
+   ;; The global KILL file is placed at top of the directory.
+   ((or (null newsgroup)
+       (string-equal newsgroup ""))
+    (expand-file-name gnus-kill-file-name
+                     gnus-kill-files-directory))
+   ;; Append ".KILL" to newsgroup name.
+   ((gnus-use-long-file-name 'not-kill)
+    (expand-file-name (concat (gnus-newsgroup-savable-name newsgroup)
+                             "." gnus-kill-file-name)
+                     gnus-kill-files-directory))
+   ;; Place "KILL" under the hierarchical directory.
+   (t
+    (expand-file-name (concat (gnus-newsgroup-directory-form newsgroup)
+                             "/" gnus-kill-file-name)
+                     gnus-kill-files-directory))))
+
+;;; Server things.
+
+(defun gnus-member-of-valid (symbol group)
+  "Find out if GROUP has SYMBOL as part of its \"valid\" spec."
+  (memq symbol (assoc
+               (symbol-name (car (gnus-find-method-for-group group)))
+               gnus-valid-select-methods)))
+
+(defun gnus-method-option-p (method option)
+  "Return non-nil if select METHOD has OPTION as a parameter."
+  (when (stringp method)
+    (setq method (gnus-server-to-method method)))
+  (memq option (assoc (format "%s" (car method))
+                     gnus-valid-select-methods)))
+
+(defun gnus-similar-server-opened (method)
+  "Return non-nil if we have a similar server opened.
+This is defined as a server with the same name, but different
+parameters."
+  (let ((opened gnus-opened-servers)
+       open)
+    (while (and method opened)
+      (setq open (car (pop opened)))
+      ;; Type and name are the same...
+      (when (and (equal (car method) (car open))
+                (equal (cadr method) (cadr open))
+                ;; ... but the rest of the parameters differ.
+                (not (gnus-methods-sloppily-equal method open)))
+       (setq method nil)))
+    (not method)))
+
+(defun gnus-server-extend-method (group method)
+  ;; This function "extends" a virtual server.  If the server is
+  ;; "hello", and the select method is ("hello" (my-var "something"))
+  ;; in the group "alt.alt", this will result in a new virtual server
+  ;; called "hello+alt.alt".
+  (if (or (not (inline (gnus-similar-server-opened method)))
+         (not (cddr method)))
+      method
+    (let ((address-slot
+          (intern (format "%s-address" (car method)))))
+      (setq method
+           (if (assq address-slot (cddr method))
+               `(,(car method) ,(concat (cadr method) "+" group)
+                 ,@(cddr method))
+             `(,(car method) ,(concat (cadr method) "+" group)
+               (,address-slot ,(cadr method))
+               ,@(cddr method))))
+      (push method gnus-extended-servers)
+      method)))
+
+(defun gnus-server-status (method)
+  "Return the status of METHOD."
+  (nth 1 (assoc method gnus-opened-servers)))
+
+(defun gnus-group-name-to-method (group)
+  "Guess a select method based on GROUP."
+  (if (string-match ":" group)
+      (let ((server (substring group 0 (match-beginning 0))))
+       (if (string-match "\\+" server)
+           (list (intern (substring server 0 (match-beginning 0)))
+                 (substring server (match-end 0)))
+         (list (intern server) "")))
+    gnus-select-method))
+
+(defun gnus-server-string (server)
+  "Return a readable string that describes SERVER."
+  (let* ((server (gnus-server-to-method server))
+        (address (nth 1 server)))
+    (if (and address
+            (not (zerop (length address))))
+       (format "%s using %s" address (car server))
+      (format "%s" (car server)))))
+
+(defun gnus-same-method-different-name (method)
+  (let ((slot (intern (concat (symbol-name (car method)) "-address"))))
+    (unless (assq slot (cddr method))
+      (setq method
+           (append method (list (list slot (nth 1 method)))))))
+  (let ((methods gnus-extended-servers)
+       open found)
+    (while (and (not found)
+               (setq open (pop methods)))
+      (when (and (eq (car method) (car open))
+                (gnus-sloppily-equal-method-parameters method open))
+       (setq found open)))
+    found))
+
+(defun gnus-find-method-for-group (group &optional info)
+  "Find the select method that GROUP uses."
+  (or gnus-override-method
+      (and (not group)
+          gnus-select-method)
+      (and (not (gnus-group-entry group))
+          ;; Killed or otherwise unknown group.
+          (or
+           ;; If we know a virtual server by that name, return its method.
+           (gnus-server-to-method (gnus-group-server group))
+           ;; Guess a new method as last resort.
+           (gnus-group-name-to-method group)))
+      (let ((info (or info (gnus-get-info group)))
+           method)
+       (if (or (not info)
+               (not (setq method (gnus-info-method info)))
+               (equal method "native"))
+           gnus-select-method
+         (setq method
+               (cond ((stringp method)
+                      (inline (gnus-server-to-method method)))
+                     ((stringp (cadr method))
+                      (or
+                       (inline
+                        (gnus-same-method-different-name method))
+                       (inline (gnus-server-extend-method group method))))
+                     (t
+                      method)))
+         (cond ((equal (cadr method) "")
+                method)
+               ((null (cadr method))
+                (list (car method) ""))
+               (t
+                (gnus-server-add-address method)))))))
+
+(defun gnus-methods-using (feature)
+  "Find all methods that have FEATURE."
+  (let ((valids gnus-valid-select-methods)
+       outs)
+    (while valids
+      (when (memq feature (car valids))
+       (push (car valids) outs))
+      (setq valids (cdr valids)))
+    outs))
+
+(autoload 'message-y-or-n-p "message" nil nil 'macro)
+
+(defun gnus-read-group (prompt &optional default)
+  "Prompt the user for a group name.
+Disallow invalid group names."
+  (let ((prefix "")
+       group)
+    (while (not group)
+      (when (string-match
+            gnus-invalid-group-regexp
+            (setq group (read-string (concat prefix prompt)
+                                     (cons (or default "") 0)
+                                     'gnus-group-history)))
+       (let ((match (match-string 0 group)))
+         ;; Might be okay (e.g. for nnimap), so ask the user:
+         (unless (and (not (string-match "^$\\|:" match))
+                      (message-y-or-n-p
+                       "Proceed and create group anyway? " t
+"The group name \"" group "\" contains a forbidden character: \"" match "\".
+
+Usually, it's dangerous to create a group with this name, because it's not
+supported by all back ends and servers.  On IMAP servers it should work,
+though.  If you are really sure, you can proceed anyway and create the group.
+
+You may customize the variable `gnus-invalid-group-regexp', which currently is
+set to \"" gnus-invalid-group-regexp
+"\", if you want to get rid of this query permanently."))
+           (setq prefix (format "Invalid group name: \"%s\".  " group)
+                 group nil)))))
+    group))
+
+(defun gnus-read-method (prompt)
+  "Prompt the user for a method.
+Allow completion over sensible values."
+  (let* ((open-servers
+         (mapcar (lambda (i) (cons (format "%s:%s" (caar i) (cadar i)) i))
+                 gnus-opened-servers))
+        (valid-methods
+         (let (methods)
+           (dolist (method gnus-valid-select-methods)
+             (if (or (memq 'prompt-address method)
+                     (not (assoc (format "%s:" (car method)) open-servers)))
+                 (push method methods)))
+           methods))
+        (servers
+         (append valid-methods
+                 open-servers
+                 gnus-predefined-server-alist
+                 gnus-server-alist))
+        (method
+         (gnus-completing-read
+          prompt (mapcar 'car servers)
+          t nil 'gnus-method-history)))
+    (cond
+     ((equal method "")
+      (setq method gnus-select-method))
+     ((assoc method gnus-valid-select-methods)
+      (let ((address (if (memq 'prompt-address
+                              (assoc method gnus-valid-select-methods))
+                        (read-string "Address: ")
+                      "")))
+       (or (cadr (assoc (format "%s:%s" method address) open-servers))
+           (list (intern method) address))))
+     ((assoc method servers)
+      method)
+     (t
+      (list (intern method) "")))))
+
+;;; Agent functions
+
+(defun gnus-agent-method-p (method-or-server)
+  "Say whether METHOD is covered by the agent."
+  (or (eq (car gnus-agent-method-p-cache) method-or-server)
+      (let* ((method (if (stringp method-or-server)
+                        (gnus-server-to-method method-or-server)
+                      method-or-server))
+            (server (gnus-method-to-server method t)))
+       (setq gnus-agent-method-p-cache
+             (cons method-or-server
+                   (member server gnus-agent-covered-methods)))))
+  (cdr gnus-agent-method-p-cache))
+
+(defun gnus-online (method)
+  (not
+   (if gnus-plugged
+       (eq (cadr (assoc method gnus-opened-servers)) 'offline)
+     (gnus-agent-method-p method))))
+
+;;; User-level commands.
+
+;;;###autoload
+(defun gnus-slave-no-server (&optional arg)
+  "Read network news as a slave, without connecting to the local server."
+  (interactive "P")
+  (gnus-no-server arg t))
+
+;;;###autoload
+(defun gnus-no-server (&optional arg slave)
+  "Read network news.
+If ARG is a positive number, Gnus will use that as the startup
+level. If ARG is nil, Gnus will be started at level 2.  If ARG is
+non-nil and not a positive number, Gnus will prompt the user for the
+name of an NNTP server to use.
+As opposed to `gnus', this command will not connect to the local
+server."
+  (interactive "P")
+  (gnus-no-server-1 arg slave))
+
+;;;###autoload
+(defun gnus-slave (&optional arg)
+  "Read news as a slave."
+  (interactive "P")
+  (gnus arg nil 'slave))
+
+(defun gnus-delete-gnus-frame ()
+  "Delete gnus frame unless it is the only one.
+Used for `gnus-exit-gnus-hook' in `gnus-other-frame'."
+  (when (and (frame-live-p gnus-other-frame-object)
+             (cdr (frame-list)))
+    (delete-frame gnus-other-frame-object))
+  (setq gnus-other-frame-object nil))
+
+;;;###autoload
+(defun gnus-other-frame (&optional arg display)
+  "Pop up a frame to read news.
+This will call one of the Gnus commands which is specified by the user
+option `gnus-other-frame-function' (default `gnus') with the argument
+ARG if Gnus is not running, otherwise pop up a Gnus frame and run the
+command specified by `gnus-other-frame-resume-function'.
+The optional second argument DISPLAY should be a standard display string
+such as \"unix:0\" to specify where to pop up a frame.  If DISPLAY is
+omitted or the function `make-frame-on-display' is not available, the
+current display is used."
+  (interactive "P")
+  (if (fboundp 'make-frame-on-display)
+      (unless display
+       (setq display (gnus-frame-or-window-display-name (selected-frame))))
+    (setq display nil))
+  (let ((alive (gnus-alive-p)))
+    (unless (and alive
+                (catch 'found
+                  (walk-windows
+                   (lambda (window)
+                     (when (and (or (not display)
+                                    (equal display
+                                           (gnus-frame-or-window-display-name
+                                            window)))
+                                (with-current-buffer (window-buffer window)
+                                  (string-match "\\`gnus-"
+                                                (symbol-name major-mode))))
+                       (gnus-select-frame-set-input-focus
+                        (setq gnus-other-frame-object (window-frame window)))
+                       (select-window window)
+                       (throw 'found t)))
+                   'ignore t)))
+      (gnus-select-frame-set-input-focus
+       (setq gnus-other-frame-object
+            (if display
+                (make-frame-on-display display gnus-other-frame-parameters)
+              (make-frame gnus-other-frame-parameters))))
+      (if alive
+         (progn (switch-to-buffer gnus-group-buffer)
+                (funcall gnus-other-frame-resume-function arg))
+       (funcall gnus-other-frame-function arg)
+       (add-hook 'gnus-exit-gnus-hook 'gnus-delete-gnus-frame)
+  ;; One might argue that `gnus-delete-gnus-frame' should not be called
+  ;; from `gnus-suspend-gnus-hook', but, on the other hand, one might
+  ;; argue that it should.  No matter what you think, for the sake of
+  ;; those who want it to be called from it, please keep (defun
+  ;; gnus-delete-gnus-frame) even if you remove the next `add-hook'.
+  (add-hook 'gnus-suspend-gnus-hook 'gnus-delete-gnus-frame)))))
+
+;;;###autoload
+(defun gnus (&optional arg dont-connect slave)
+  "Read network news.
+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")
+  ;; When using the development version of Gnus, load the gnus-load
+  ;; file.
+  (unless (string-match "^Gnus" gnus-version)
+    (load "gnus-load" nil t))
+  (unless (byte-code-function-p (symbol-function 'gnus))
+    (message "You should byte-compile Gnus")
+    (sit-for 2))
+  (let ((gnus-action-message-log (list nil)))
+    (gnus-1 arg dont-connect slave)
+    (gnus-final-warning)))
+
+(declare-function debbugs-gnu "ext:debbugs-gnu"
+                 (severities &optional packages archivedp suppress tags))
+
+(defun gnus-list-debbugs ()
+  "List all open Gnus bug reports."
+  (interactive)
+  (require 'debbugs-gnu)
+  (debbugs-gnu nil "gnus"))
+
+;; Allow redefinition of Gnus functions.
+
+(gnus-ems-redefine)
+
+(provide 'gnus)
+
+;;; gnus.el ends here
diff --git a/xemacs-packages/gnus/lisp/gravatar.el b/xemacs-packages/gnus/lisp/gravatar.el
new file mode 100644 (file)
index 0000000..8e5ea31
--- /dev/null
@@ -0,0 +1,166 @@
+;;; gravatar.el --- Get Gravatars
+
+;; Copyright (C) 2010-2016 Free Software Foundation, Inc.
+
+;; Author: Julien Danjou <julien@danjou.info>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'url)
+(require 'url-cache)
+
+(defgroup gravatar nil
+  "Gravatar."
+  :version "24.1"
+  :group 'comm)
+
+(defcustom gravatar-automatic-caching t
+  "Whether to cache retrieved gravatars."
+  :type 'boolean
+  :group 'gravatar)
+
+;; FIXME a time value is not the nicest format for a custom variable.
+(defcustom gravatar-cache-ttl (days-to-time 30)
+  "Time to live for gravatar cache entries."
+  :type '(repeat integer)
+  :group 'gravatar)
+
+;; FIXME Doc is tautological.  What are the options?
+(defcustom gravatar-rating "g"
+  "Default rating for gravatar."
+  :type 'string
+  :group 'gravatar)
+
+(defcustom gravatar-size 32
+  "Default size in pixels for gravatars."
+  :type 'integer
+  :group 'gravatar)
+
+(defconst gravatar-base-url
+  "http://www.gravatar.com/avatar"
+  "Base URL for getting gravatars.")
+
+(defun gravatar-hash (mail-address)
+  "Create an hash from MAIL-ADDRESS."
+  (md5 (downcase mail-address)))
+
+(defun gravatar-build-url (mail-address)
+  "Return an URL to retrieve MAIL-ADDRESS gravatar."
+  (format "%s/%s?d=404&r=%s&s=%d"
+          gravatar-base-url
+          (gravatar-hash mail-address)
+          gravatar-rating
+          gravatar-size))
+
+(defun gravatar-cache-expired (url)
+  "Check if URL is cached for more than `gravatar-cache-ttl'."
+  (cond (url-standalone-mode
+         (not (file-exists-p (url-cache-create-filename url))))
+        (t (let ((cache-time (url-is-cached url)))
+             (if cache-time
+                 (time-less-p
+                  (time-add
+                   cache-time
+                   gravatar-cache-ttl)
+                  (current-time))
+               t)))))
+
+(defun gravatar-get-data ()
+  "Get data from current buffer."
+  (save-excursion
+    (goto-char (point-min))
+    (when (re-search-forward "^HTTP/.+ 200 OK$" nil (line-end-position))
+      (when (search-forward "\n\n" nil t)
+        (buffer-substring (point) (point-max))))))
+
+(eval-and-compile
+  (cond ((featurep 'xemacs)
+        (require 'gnus-xmas)
+        (defalias 'gravatar-create-image 'gnus-xmas-create-image))
+       ((featurep 'gnus-ems)
+        (defalias 'gravatar-create-image 'gnus-create-image))
+       (t
+        (require 'image)
+        (defalias 'gravatar-create-image 'create-image))))
+
+(defun gravatar-data->image ()
+  "Get data of current buffer and return an image.
+If no image available, return 'error."
+  (let ((data (gravatar-get-data)))
+    (if data
+       (gravatar-create-image data nil t)
+      'error)))
+
+(autoload 'help-function-arglist "help-fns")
+
+;;;###autoload
+(defun gravatar-retrieve (mail-address cb &optional cbargs)
+  "Retrieve MAIL-ADDRESS gravatar and call CB on retrieval.
+You can provide a list of argument to pass to CB in CBARGS."
+  (let ((url (gravatar-build-url mail-address)))
+    (if (gravatar-cache-expired url)
+       (let ((args (list url
+                         'gravatar-retrieved
+                         (list cb (when cbargs cbargs)))))
+         (when (> (length (if (featurep 'xemacs)
+                              (cdr (split-string (function-arglist 'url-retrieve)))
+                            (help-function-arglist 'url-retrieve)))
+                  4)
+           (setq args (nconc args (list t))))
+         (apply #'url-retrieve args))
+      (apply cb
+               (with-temp-buffer
+                 (mm-disable-multibyte)
+                 (url-cache-extract (url-cache-create-filename url))
+                 (gravatar-data->image))
+               cbargs))))
+
+;;;###autoload
+(defun gravatar-retrieve-synchronously (mail-address)
+  "Retrieve MAIL-ADDRESS gravatar and returns it."
+  (let ((url (gravatar-build-url mail-address)))
+    (if (gravatar-cache-expired url)
+        (with-current-buffer (url-retrieve-synchronously url)
+         (when gravatar-automatic-caching
+            (url-store-in-cache (current-buffer)))
+          (let ((data (gravatar-data->image)))
+            (kill-buffer (current-buffer))
+            data))
+      (with-temp-buffer
+        (mm-disable-multibyte)
+        (url-cache-extract (url-cache-create-filename url))
+        (gravatar-data->image)))))
+
+
+(defun gravatar-retrieved (status cb &optional cbargs)
+  "Callback function used by `gravatar-retrieve'."
+  ;; Store gravatar?
+  (when gravatar-automatic-caching
+    (url-store-in-cache (current-buffer)))
+  (if (plist-get status :error)
+      ;; Error happened.
+      (apply cb 'error cbargs)
+    (apply cb (gravatar-data->image) cbargs))
+  (kill-buffer (current-buffer)))
+
+(provide 'gravatar)
+
+;;; gravatar.el ends here
diff --git a/xemacs-packages/gnus/lisp/gssapi.el b/xemacs-packages/gnus/lisp/gssapi.el
new file mode 100644 (file)
index 0000000..1f72805
--- /dev/null
@@ -0,0 +1,106 @@
+;;; gssapi.el --- GSSAPI/Kerberos 5 interface for Emacs
+
+;; Copyright (C) 2011-2016 Free Software Foundation, Inc.
+
+;; Author: Simon Josefsson <simon@josefsson.org>
+;;         Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: network
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'format-spec)
+
+(defcustom gssapi-program (list
+                          (concat "gsasl %s %p "
+                                  "--mechanism GSSAPI "
+                                  "--authentication-id %l")
+                          "imtest -m gssapi -u %l -p %p %s")
+  "List of strings containing commands for GSSAPI (krb5) authentication.
+%s is replaced with server hostname, %p with port to connect to,
+and %l with the user name.  The program should accept commands on
+stdin and return responses to stdout.  Each entry in the list is
+tried until a successful connection is made."
+  :version "24.1"
+  :group 'network
+  :type '(repeat string))
+
+(defun open-gssapi-stream (name buffer server port user)
+  (let ((cmds gssapi-program)
+       cmd done)
+    (with-current-buffer buffer
+      (while (and (not done)
+                 (setq cmd (pop cmds)))
+       (message "Opening GSSAPI connection with `%s'..." cmd)
+       (erase-buffer)
+       (let* ((coding-system-for-read 'binary)
+              (coding-system-for-write 'binary)
+              (process (start-process
+                        name buffer shell-file-name shell-command-switch
+                        (format-spec
+                         cmd
+                         (format-spec-make
+                          ?s server
+                          ?p (number-to-string port)
+                          ?l user))))
+              response)
+         (when process
+           (while (and (memq (process-status process) '(open run))
+                       (goto-char (point-min))
+                       ;; Athena IMTEST can output SSL verify errors
+                       (or (while (looking-at "^verify error:num=")
+                             (forward-line))
+                           t)
+                       (or (while (looking-at "^TLS connection established")
+                             (forward-line))
+                           t)
+                       ;; cyrus 1.6.x (13? < x <= 22) queries capabilities
+                       (or (while (looking-at "^C:")
+                             (forward-line))
+                           t)
+                       ;; cyrus 1.6 imtest print "S: " before server greeting
+                       (or (not (looking-at "S: "))
+                           (forward-char 3)
+                           t)
+                       ;; GNU SASL may print 'Trying ...' first.
+                       (or (not (looking-at "Trying "))
+                           (forward-line)
+                           t)
+                       (not (and (looking-at "\\* \\(OK\\|PREAUTH\\|BYE\\) ")
+                                 ;; success in imtest 1.6:
+                                 (re-search-forward
+                                  (concat "^\\(\\(Authenticat.*\\)\\|\\("
+                                          "Client authentication "
+                                          "finished.*\\)\\)")
+                                  nil t)
+                                 (setq response (match-string 1)))))
+             (accept-process-output process 1)
+             (sit-for 1))
+           (erase-buffer)
+           (message "GSSAPI connection: %s" (or response "failed"))
+           (if (and response (let ((case-fold-search nil))
+                               (not (string-match "failed" response))))
+               (setq done process)
+             (delete-process process)
+             nil))))
+      done)))
+
+(provide 'gssapi)
+
+;;; gssapi.el ends here
diff --git a/xemacs-packages/gnus/lisp/hashcash.el b/xemacs-packages/gnus/lisp/hashcash.el
new file mode 100644 (file)
index 0000000..e1cb7e2
--- /dev/null
@@ -0,0 +1,379 @@
+;;; hashcash.el --- Add hashcash payments to email
+
+;; Copyright (C) 2003-2005, 2007-2016 Free Software Foundation, Inc.
+
+;; Written by: Paul Foley <mycroft@actrix.gen.nz> (1997-2002)
+;; Maintainer: Paul Foley <mycroft@actrix.gen.nz>
+;; Keywords: mail, hashcash
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; The hashcash binary is at http://www.hashcash.org/.
+;;
+;; Call mail-add-payment to add a hashcash payment to a mail message
+;; in the current buffer.
+;;
+;; Call mail-add-payment-async after writing the addresses but before
+;; writing the mail to start calculating the hashcash payment
+;; asynchronously.
+;;
+;; The easiest way to do this automatically for all outgoing mail
+;; is to set `message-generate-hashcash' to t.  If you want more
+;; control, try the following hooks.
+;;
+;; To automatically add payments to all outgoing mail when sending:
+;;    (add-hook 'message-send-hook 'mail-add-payment)
+;;
+;; To start calculations automatically when addresses are prefilled:
+;;    (add-hook 'message-setup-hook 'mail-add-payment-async)
+;;
+;; To check whether calculations are done before sending:
+;;    (add-hook 'message-send-hook 'hashcash-wait-or-cancel)
+
+;;; Code:
+
+(eval-when-compile (require 'cl))      ; for case
+
+(defgroup hashcash nil
+  "Hashcash configuration."
+  :group 'mail)
+
+(defcustom hashcash-default-payment 20
+  "The default number of bits to pay to unknown users.
+If this is zero, no payment header will be generated.
+See `hashcash-payment-alist'."
+  :type 'integer
+  :group 'hashcash)
+
+(defcustom hashcash-payment-alist '()
+  "An association list mapping email addresses to payment amounts.
+Elements may consist of (ADDR AMOUNT) or (ADDR STRING AMOUNT), where
+ADDR is the email address of the intended recipient and AMOUNT is
+the value of hashcash payment to be made to that user.  STRING, if
+present, is the string to be hashed; if not present ADDR will be used."
+  :type '(repeat (choice (list :tag "Normal"
+                              (string :name "Address")
+                              (integer :name "Amount"))
+                        (list :tag "Replace hash input"
+                              (string :name "Address")
+                              (string :name "Hash input")
+                              (integer :name "Amount"))))
+  :group 'hashcash)
+
+(defcustom hashcash-default-accept-payment 20
+  "The default minimum number of bits to accept on incoming payments."
+  :type 'integer
+  :group 'hashcash)
+
+(defcustom hashcash-accept-resources `((,user-mail-address nil))
+  "An association list mapping hashcash resources to payment amounts.
+Resources named here are to be accepted in incoming payments.  If the
+corresponding AMOUNT is NIL, the value of `hashcash-default-accept-payment'
+is used instead."
+  :type 'alist
+  :group 'hashcash)
+
+(define-obsolete-variable-alias 'hashcash-path 'hashcash-program "24.4")
+(defcustom hashcash-program "hashcash"
+  "The name of the hashcash executable.
+If this is not in your PATH, specify an absolute file name."
+  :type '(choice (const nil) file)
+  :group 'hashcash)
+
+(defcustom hashcash-extra-generate-parameters nil
+  "A list of parameter strings passed to `hashcash-program' when minting.
+For example, you may want to set this to (\"-Z2\") to reduce header length."
+  :type '(repeat string)
+  :group 'hashcash)
+
+(defcustom hashcash-double-spend-database "hashcash.db"
+  "The name of the double-spending database file."
+  :type 'file
+  :group 'hashcash)
+
+(defcustom hashcash-in-news nil
+  "Specifies whether or not hashcash payments should be made to newsgroups."
+  :type 'boolean
+  :group 'hashcash)
+
+(defvar hashcash-process-alist nil
+  "Alist of asynchronous hashcash processes and buffers.")
+
+(require 'mail-utils)
+
+(eval-and-compile
+  (if (fboundp 'point-at-bol)
+      (defalias 'hashcash-point-at-bol 'point-at-bol)
+    (defalias 'hashcash-point-at-bol 'line-beginning-position))
+
+  (if (fboundp 'point-at-eol)
+      (defalias 'hashcash-point-at-eol 'point-at-eol)
+    (defalias 'hashcash-point-at-eol 'line-end-position)))
+
+(defun hashcash-strip-quoted-names (addr)
+  (setq addr (mail-strip-quoted-names addr))
+  (if (and addr (string-match "\\`\\([^+@]+\\)\\+[^@]*\\(@.+\\)" addr))
+      (concat (match-string 1 addr) (match-string 2 addr))
+    addr))
+
+(declare-function message-narrow-to-headers-or-head "message" ())
+(declare-function message-fetch-field "message" (header &optional not-all))
+(declare-function message-goto-eoh "message" ())
+(declare-function message-narrow-to-headers "message" ())
+
+(defun hashcash-token-substring ()
+  (save-excursion
+    (let ((token ""))
+      (loop
+       (setq token
+         (concat token (buffer-substring (point) (hashcash-point-at-eol))))
+       (goto-char (hashcash-point-at-eol))
+       (forward-char 1)
+       (unless (looking-at "[ \t]") (return token))
+       (while (looking-at "[ \t]") (forward-char 1))))))
+
+(defun hashcash-payment-required (addr)
+  "Return the hashcash payment value required for the given address."
+  (let ((val (assoc addr hashcash-payment-alist)))
+    (or (nth 2 val) (nth 1 val) hashcash-default-payment)))
+
+(defun hashcash-payment-to (addr)
+  "Return the string with which hashcash payments should collide."
+  (let ((val (assoc addr hashcash-payment-alist)))
+    (or (nth 1 val) (nth 0 val) addr)))
+
+(defun hashcash-generate-payment (str val)
+  "Generate a hashcash payment by finding a VAL-bit collison on STR."
+  (if (and (> val 0)
+          hashcash-program)
+      (with-current-buffer (get-buffer-create " *hashcash*")
+       (erase-buffer)
+       (apply 'call-process hashcash-program nil t nil
+              "-m" "-q" "-b" (number-to-string val) str
+              hashcash-extra-generate-parameters)
+       (goto-char (point-min))
+       (hashcash-token-substring))
+    (error "No `hashcash' binary found")))
+
+(defun hashcash-generate-payment-async (str val callback)
+  "Generate a hashcash payment by finding a VAL-bit collison on STR.
+Return immediately.  Call CALLBACK with process and result when ready."
+  (if (and (> val 0)
+          hashcash-program)
+      (let ((process (apply 'start-process "hashcash" nil
+                           hashcash-program "-m" "-q"
+                           "-b" (number-to-string val) str
+                           hashcash-extra-generate-parameters)))
+       (setq hashcash-process-alist (cons
+                                     (cons process (current-buffer))
+                                     hashcash-process-alist))
+       (set-process-filter process `(lambda (process output)
+                                      (funcall ,callback process output))))
+    (funcall callback nil nil)))
+
+(defun hashcash-check-payment (token str val)
+  "Check the validity of a hashcash payment."
+  (if hashcash-program
+      (zerop (call-process hashcash-program nil nil nil "-c"
+                          "-d" "-f" hashcash-double-spend-database
+                          "-b" (number-to-string val)
+                          "-r" str
+                          token))
+    (progn
+      (message "No hashcash binary found")
+      (sleep-for 1)
+      nil)))
+
+(defun hashcash-version (token)
+  "Find the format version of a hashcash token."
+  ;; Version 1.2 looks like n:yymmdd:rrrrr:xxxxxxxxxxxxxxxx
+  ;;   This carries its own version number embedded in the token,
+  ;;   so no further format number changes should be necessary
+  ;;   in the X-Payment header.
+  ;;
+  ;; Version 1.1 looks like yymmdd:rrrrr:xxxxxxxxxxxxxxxx
+  ;;   You need to upgrade your hashcash binary.
+  ;;
+  ;; Version 1.0 looked like nnnnnrrrrrxxxxxxxxxxxxxxxx
+  ;;   This is no longer supported.
+  (cond ((equal (aref token 1) ?:) 1.2)
+       ((equal (aref token 6) ?:) 1.1)
+       (t (error "Unknown hashcash format version"))))
+
+(defun hashcash-already-paid-p (recipient)
+  "Check for hashcash token to RECIPIENT in current buffer."
+  (save-excursion
+    (save-restriction
+      (message-narrow-to-headers-or-head)
+      (let ((token (message-fetch-field "x-hashcash"))
+           (case-fold-search t))
+       (and (stringp token)
+            (string-match (regexp-quote recipient) token))))))
+
+;;;###autoload
+(defun hashcash-insert-payment (arg)
+  "Insert X-Payment and X-Hashcash headers with a payment for ARG"
+  (interactive "sPay to: ")
+  (unless (hashcash-already-paid-p arg)
+    (let ((pay (hashcash-generate-payment (hashcash-payment-to arg)
+                                         (hashcash-payment-required arg))))
+      (when pay
+       (insert-before-markers "X-Hashcash: " pay "\n")))))
+
+;;;###autoload
+(defun hashcash-insert-payment-async (arg)
+  "Insert X-Payment and X-Hashcash headers with a payment for ARG
+Only start calculation.  Results are inserted when ready."
+  (interactive "sPay to: ")
+  (unless (hashcash-already-paid-p arg)
+    (hashcash-generate-payment-async
+     (hashcash-payment-to arg)
+     (hashcash-payment-required arg)
+     `(lambda (process payment)
+       (hashcash-insert-payment-async-2 ,(current-buffer) process payment)))))
+
+(defun hashcash-insert-payment-async-2 (buffer process pay)
+  (when (buffer-live-p buffer)
+    (with-current-buffer buffer
+      (save-excursion
+       (save-restriction
+         (setq hashcash-process-alist (delq
+                                       (assq process hashcash-process-alist)
+                                       hashcash-process-alist))
+         (message-goto-eoh)
+         (when pay
+           (insert-before-markers "X-Hashcash: " pay)))))))
+
+(defun hashcash-cancel-async (&optional buffer)
+  "Delete any hashcash processes associated with BUFFER.
+BUFFER defaults to the current buffer."
+  (interactive)
+  (unless buffer (setq buffer (current-buffer)))
+  (let (entry)
+    (while (setq entry (rassq buffer hashcash-process-alist))
+      (delete-process (car entry))
+      (setq hashcash-process-alist
+           (delq entry hashcash-process-alist)))))
+
+(defun hashcash-wait-async (&optional buffer)
+  "Wait for asynchronous hashcash processes in BUFFER to finish.
+BUFFER defaults to the current buffer."
+  (interactive)
+  (unless buffer (setq buffer (current-buffer)))
+  (let (entry)
+    (while (setq entry (rassq buffer hashcash-process-alist))
+      (accept-process-output (car entry) 1))))
+
+(defun hashcash-processes-running-p (buffer)
+  "Return non-nil if hashcash processes in BUFFER are still running."
+  (rassq buffer hashcash-process-alist))
+
+(defun hashcash-wait-or-cancel ()
+  "Ask user whether to wait for hashcash processes to finish."
+  (interactive)
+  (when (hashcash-processes-running-p (current-buffer))
+    (if (y-or-n-p
+         "Hashcash process(es) still running; wait for them to finish? ")
+       (hashcash-wait-async)
+      (hashcash-cancel-async))))
+
+;;;###autoload
+(defun hashcash-verify-payment (token &optional resource amount)
+  "Verify a hashcash payment"
+  (let* ((split (split-string token ":"))
+        (key (if (< (hashcash-version token) 1.2)
+                 (nth 1 split)
+                 (case (string-to-number (nth 0 split))
+                   (0 (nth 2 split))
+                   (1 (nth 3 split))))))
+    (cond ((null resource)
+          (let ((elt (assoc key hashcash-accept-resources)))
+            (and elt (hashcash-check-payment token (car elt)
+                       (or (cadr elt) hashcash-default-accept-payment)))))
+         ((equal token key)
+          (hashcash-check-payment token resource
+                               (or amount hashcash-default-accept-payment)))
+         (t nil))))
+
+;;;###autoload
+(defun mail-add-payment (&optional arg async)
+  "Add X-Payment: and X-Hashcash: headers with a hashcash payment
+for each recipient address.  Prefix arg sets default payment temporarily.
+Set ASYNC to t to start asynchronous calculation.  (See
+`mail-add-payment-async')."
+  (interactive "P")
+  (let ((hashcash-default-payment (if arg (prefix-numeric-value arg)
+                                   hashcash-default-payment))
+       (addrlist nil))
+    (save-excursion
+      (save-restriction
+       (message-narrow-to-headers)
+       (let ((to (hashcash-strip-quoted-names (mail-fetch-field "To" nil t)))
+             (cc (hashcash-strip-quoted-names (mail-fetch-field "Cc" nil t)))
+             (ng (hashcash-strip-quoted-names (mail-fetch-field "Newsgroups"
+                                                                nil t))))
+         (when to
+           (setq addrlist (split-string to ",[ \t\n]*")))
+         (when cc
+           (setq addrlist (nconc addrlist (split-string cc ",[ \t\n]*"))))
+         (when (and hashcash-in-news ng)
+           (setq addrlist (nconc addrlist (split-string ng ",[ \t\n]*")))))
+       (when addrlist
+         (mapc (if async
+                   #'hashcash-insert-payment-async
+                 #'hashcash-insert-payment)
+               addrlist)))))
+  t)
+
+;;;###autoload
+(defun mail-add-payment-async (&optional arg)
+  "Add X-Payment: and X-Hashcash: headers with a hashcash payment
+for each recipient address.  Prefix arg sets default payment temporarily.
+Calculation is asynchronous."
+  (interactive "P")
+  (mail-add-payment arg t))
+
+;;;###autoload
+(defun mail-check-payment (&optional arg)
+  "Look for a valid X-Payment: or X-Hashcash: header.
+Prefix arg sets default accept amount temporarily."
+  (interactive "P")
+  (let ((hashcash-default-accept-payment (if arg (prefix-numeric-value arg)
+                                          hashcash-default-accept-payment))
+       (version (hashcash-version (hashcash-generate-payment "x" 1))))
+    (save-excursion
+      (goto-char (point-min))
+      (search-forward "\n\n")
+      (beginning-of-line)
+      (let ((end (point))
+           (ok nil))
+       (goto-char (point-min))
+       (while (and (not ok) (search-forward "X-Payment: hashcash " end t))
+         (let ((value (split-string (hashcash-token-substring) " ")))
+           (when (equal (car value) (number-to-string version))
+             (setq ok (hashcash-verify-payment (cadr value))))))
+       (goto-char (point-min))
+       (while (and (not ok) (search-forward "X-Hashcash: " end t))
+         (setq ok (hashcash-verify-payment (hashcash-token-substring))))
+       (when ok
+         (message "Payment valid"))
+       ok))))
+
+(provide 'hashcash)
+
+;;; hashcash.el ends here
diff --git a/xemacs-packages/gnus/lisp/hex-util.el b/xemacs-packages/gnus/lisp/hex-util.el
new file mode 100644 (file)
index 0000000..4867359
--- /dev/null
@@ -0,0 +1,71 @@
+;;; hex-util.el --- Functions to encode/decode hexadecimal string.
+
+;; Copyright (C) 1999, 2001-2016 Free Software Foundation, Inc.
+
+;; Author: Shuhei KOBAYASHI <shuhei@aqua.ocn.ne.jp>
+;; Keywords: data
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; 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/xemacs-packages/gnus/lisp/hmac-def.el b/xemacs-packages/gnus/lisp/hmac-def.el
new file mode 100644 (file)
index 0000000..c5df4fd
--- /dev/null
@@ -0,0 +1,83 @@
+;;; hmac-def.el --- A macro for defining HMAC functions.
+
+;; Copyright (C) 1999, 2001, 2007-2016 Free Software Foundation, Inc.
+
+;; Author: Shuhei KOBAYASHI <shuhei@aqua.ocn.ne.jp>
+;; Keywords: HMAC, RFC2104
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This program is implemented from RFC2104,
+;; "HMAC: Keyed-Hashing for Message Authentication".
+
+;;; Code:
+
+(defmacro define-hmac-function (name H B L &optional bit)
+  "Define a function NAME(TEXT KEY) which computes HMAC with function H.
+
+HMAC function is H(KEY XOR opad, H(KEY XOR ipad, TEXT)):
+
+H is a cryptographic hash function, such as SHA1 and MD5, which takes
+a string and return a digest of it (in binary form).
+B is a byte-length of a block size of H. (B=64 for both SHA1 and MD5.)
+L is a byte-length of hash outputs. (L=16 for MD5, L=20 for SHA1.)
+If BIT is non-nil, truncate output to specified bits."
+  `(defun ,name (text key)
+     ,(concat "Compute "
+             (upcase (symbol-name name))
+             " over TEXT with KEY.")
+     (let ((key-xor-ipad (make-string ,B ?\x36))
+          (key-xor-opad (make-string ,B ?\x5C))
+          (len (length key))
+          (pos 0))
+       (unwind-protect
+          (progn
+            ;; if `key' is longer than the block size, apply hash function
+            ;; to `key' and use the result as a real `key'.
+            (if (> len ,B)
+                (setq key (,H key)
+                      len ,L))
+            (while (< pos len)
+              (aset key-xor-ipad pos (logxor (aref key pos) ?\x36))
+              (aset key-xor-opad pos (logxor (aref key pos) ?\x5C))
+              (setq pos (1+ pos)))
+            (setq key-xor-ipad (unwind-protect
+                                   (concat key-xor-ipad text)
+                                 (fillarray key-xor-ipad 0))
+                  key-xor-ipad (unwind-protect
+                                   (,H key-xor-ipad)
+                                 (fillarray key-xor-ipad 0))
+                  key-xor-opad (unwind-protect
+                                   (concat key-xor-opad key-xor-ipad)
+                                 (fillarray key-xor-opad 0))
+                  key-xor-opad (unwind-protect
+                                   (,H key-xor-opad)
+                                 (fillarray key-xor-opad 0)))
+            ;; now `key-xor-opad' contains
+            ;; H(KEY XOR opad, H(KEY XOR ipad, TEXT)).
+            ,(if (and bit (< (/ bit 8) L))
+                 `(substring key-xor-opad 0 ,(/ bit 8))
+               ;; return a copy of `key-xor-opad'.
+               `(concat key-xor-opad)))
+        ;; cleanup.
+        (fillarray key-xor-ipad 0)
+        (fillarray key-xor-opad 0)))))
+
+(provide 'hmac-def)
+
+;;; hmac-def.el ends here
diff --git a/xemacs-packages/gnus/lisp/hmac-md5.el b/xemacs-packages/gnus/lisp/hmac-md5.el
new file mode 100644 (file)
index 0000000..dfeeeaa
--- /dev/null
@@ -0,0 +1,82 @@
+;;; hmac-md5.el --- Compute HMAC-MD5.
+
+;; Copyright (C) 1999, 2001, 2007-2016 Free Software Foundation, Inc.
+
+;; Author: Shuhei KOBAYASHI <shuhei@aqua.ocn.ne.jp>
+;; Keywords: HMAC, RFC2104, HMAC-MD5, MD5, KEYED-MD5, CRAM-MD5
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Test cases from RFC 2202, "Test Cases for HMAC-MD5 and HMAC-SHA-1".
+;;
+;; (encode-hex-string (hmac-md5 "Hi There" (make-string 16 ?\x0b)))
+;;  => "9294727a3638bb1c13f48ef8158bfc9d"
+;;
+;; (encode-hex-string (hmac-md5 "what do ya want for nothing?" "Jefe"))
+;;  => "750c783e6ab0b503eaa86e310a5db738"
+;;
+;; (encode-hex-string (hmac-md5 (make-string 50 ?\xdd) (make-string 16 ?\xaa)))
+;;  => "56be34521d144c88dbb8c733f0e8b3f6"
+;;
+;; (encode-hex-string
+;;  (hmac-md5
+;;   (make-string 50 ?\xcd)
+;;   (decode-hex-string "0102030405060708090a0b0c0d0e0f10111213141516171819")))
+;;  => "697eaf0aca3a3aea3a75164746ffaa79"
+;;
+;; (encode-hex-string
+;;  (hmac-md5 "Test With Truncation" (make-string 16 ?\x0c)))
+;;  => "56461ef2342edc00f9bab995690efd4c"
+;;
+;; (encode-hex-string
+;;  (hmac-md5-96 "Test With Truncation" (make-string 16 ?\x0c)))
+;;  => "56461ef2342edc00f9bab995"
+;;
+;; (encode-hex-string
+;;  (hmac-md5
+;;   "Test Using Larger Than Block-Size Key - Hash Key First"
+;;   (make-string 80 ?\xaa)))
+;;  => "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd"
+;;
+;; (encode-hex-string
+;;  (hmac-md5
+;;   "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"
+;;   (make-string 80 ?\xaa)))
+;;  => "6f630fad67cda0ee1fb1f562db3aa53e"
+
+;;; Code:
+
+(eval-when-compile (require 'hmac-def))
+(require 'hex-util)                    ; (decode-hex-string STRING)
+(require 'md5)                         ; expects (md5 STRING)
+
+(defun md5-binary (string)
+  "Return the MD5 of STRING in binary form."
+  (if (condition-case nil
+         ;; `md5' of v21 takes 4th arg CODING (and 5th arg NOERROR).
+         (md5 "" nil nil 'binary)      ; => "d41d8cd98f00b204e9800998ecf8427e"
+       (wrong-number-of-arguments nil))
+      (decode-hex-string (md5 string nil nil 'binary))
+    (decode-hex-string (md5 string))))
+
+(define-hmac-function hmac-md5 md5-binary 64 16) ; => (hmac-md5 TEXT KEY)
+(define-hmac-function hmac-md5-96 md5-binary 64 16 96)
+
+(provide 'hmac-md5)
+
+;;; hmac-md5.el ends here
diff --git a/xemacs-packages/gnus/lisp/html2text.el b/xemacs-packages/gnus/lisp/html2text.el
new file mode 100644 (file)
index 0000000..2b1c205
--- /dev/null
@@ -0,0 +1,461 @@
+;;; html2text.el --- a simple html to plain text converter -*- coding: utf-8 -*-
+
+;; Copyright (C) 2002-2016 Free Software Foundation, Inc.
+
+;; Author: Joakim Hove <hove@phys.ntnu.no>
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; These functions provide a simple way to wash/clean html infected
+;; mails.  Definitely do not work in all cases, but some improvement
+;; in readability is generally obtained.  Formatting is only done in
+;; the buffer, so the next time you enter the article it will be
+;; "re-htmlized".
+;;
+;; The main function is `html2text'.
+
+;;; Code:
+
+;;
+;; <Global variables>
+;;
+
+(eval-when-compile
+  (require 'cl))
+
+(defvar html2text-format-single-element-list '(("hr" . html2text-clean-hr)))
+
+(defvar html2text-replace-list
+  '(("&acute;" . "`")
+    ("&amp;" . "&")
+    ("&apos;" . "'")
+    ("&brvbar;" . "|")
+    ("&cent;" . "c")
+    ("&circ;" . "^")
+    ("&copy;" . "(C)")
+    ("&curren;" . "(#)")
+    ("&deg;" . "degree")
+    ("&divide;" . "/")
+    ("&euro;" . "e")
+    ("&frac12;" . "1/2")
+    ("&gt;" . ">")
+    ("&iquest;" . "?")
+    ("&laquo;" . "<<")
+    ("&ldquo" . "\"")
+    ("&lsaquo;" . "(")
+    ("&lsquo;" . "`")
+    ("&lt;" . "<")
+    ("&mdash;" . "--")
+    ("&nbsp;" . " ")
+    ("&ndash;" . "-")
+    ("&permil;" . "%%")
+    ("&plusmn;" . "+-")
+    ("&pound;" . "£")
+    ("&quot;" . "\"")
+    ("&raquo;" . ">>")
+    ("&rdquo" . "\"")
+    ("&reg;" . "(R)")
+    ("&rsaquo;" . ")")
+    ("&rsquo;" . "'")
+    ("&sect;" . "§")
+    ("&sup1;" . "^1")
+    ("&sup2;" . "^2")
+    ("&sup3;" . "^3")
+    ("&tilde;" . "~"))
+  "The map of entity to text.
+
+This is an alist were each element is a dotted pair consisting of an
+old string, and a replacement string.  This replacement is done by the
+function `html2text-substitute' which basically performs a
+`replace-string' operation for every element in the list.  This is
+completely verbatim - without any use of REGEXP.")
+
+(defvar html2text-remove-tag-list
+  '("html" "body" "p" "img" "dir" "head" "div" "br" "font" "title" "meta")
+  "A list of removable tags.
+
+This is a list of tags which should be removed, without any
+formatting.  Note that tags in the list are presented *without*
+any \"<\" or \">\".  All occurrences of a tag appearing in this
+list are removed, irrespective of whether it is a closing or
+opening tag, or if the tag has additional attributes.  The
+deletion is done by the function `html2text-remove-tags'.
+
+For instance the text:
+
+\"Here comes something <font size\"+3\" face=\"Helvetica\"> big </font>.\"
+
+will be reduced to:
+
+\"Here comes something big.\"
+
+If this list contains the element \"font\".")
+
+(defvar html2text-format-tag-list
+  '(("b"         . html2text-clean-bold)
+    ("strong"     . html2text-clean-bold)
+    ("u"         . html2text-clean-underline)
+    ("i"         . html2text-clean-italic)
+    ("em"         . html2text-clean-italic)
+    ("blockquote" . html2text-clean-blockquote)
+    ("a"          . html2text-clean-anchor)
+    ("ul"         . html2text-clean-ul)
+    ("ol"         . html2text-clean-ol)
+    ("dl"         . html2text-clean-dl)
+    ("center"     . html2text-clean-center))
+  "An alist of tags and processing functions.
+
+This is an alist where each dotted pair consists of a tag, and then
+the name of a function to be called when this tag is found.  The
+function is called with the arguments p1, p2, p3 and p4. These are
+demonstrated below:
+
+\"<b> This is bold text </b>\"
+ ^   ^                 ^    ^
+ |   |                 |    |
+p1  p2                p3   p4
+
+Then the called function will typically format the text somewhat and
+remove the tags.")
+
+(defvar html2text-remove-tag-list2  '("li" "dt" "dd" "meta")
+  "Another list of removable tags.
+
+This is a list of tags which are removed similarly to the list
+`html2text-remove-tag-list' - but these tags are retained for the
+formatting, and then moved afterward.")
+
+;;
+;; </Global variables>
+;;
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;
+;; <Utility functions>
+;;
+
+
+(defun html2text-replace-string (from-string to-string min max)
+  "Replace FROM-STRING with TO-STRING in region from MIN to MAX."
+  (goto-char min)
+  (let ((delta (- (string-width to-string) (string-width from-string)))
+       (change 0))
+    (while (search-forward from-string max t)
+      (replace-match to-string)
+      (setq change (+ change delta)))
+    change))
+
+;;
+;; </Utility functions>
+;;
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;
+;; <Functions related to attributes> i.e. <font size=+3>
+;;
+
+(defun html2text-attr-value (list attribute)
+  "Get value of ATTRIBUTE from LIST."
+  (nth 1 (assoc attribute list)))
+
+(defun html2text-get-attr (p1 p2)
+  (goto-char p1)
+  (re-search-forward "\\s-+" p2 t)
+  (let (attr-list)
+    (while (re-search-forward "[-a-z0-9._]+" p2 t)
+      (setq attr-list
+           (cons
+            (list (match-string 0)
+                  (when (looking-at "\\s-*=")
+                    (goto-char (match-end 0))
+                    (skip-chars-forward "[:space:]")
+                    (when (or (looking-at "\"[^\"]*\"\\|'[^']*'")
+                              (looking-at "[-a-z0-9._:]+"))
+                      (goto-char (match-end 0))
+                      (match-string 0))))
+            attr-list)))
+    attr-list))
+
+;;
+;; </Functions related to attributes>
+;;
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;
+;; <Functions to be called to format a tag-pair>
+;;
+(defun html2text-clean-list-items (p1 p2 list-type)
+  (goto-char p1)
+  (let ((item-nr 0)
+       (items   0))
+    (while (search-forward "<li>" p2 t)
+      (setq items (1+ items)))
+    (goto-char p1)
+    (while (< item-nr items)
+      (setq item-nr (1+ item-nr))
+      (search-forward "<li>" (point-max) t)
+      (cond
+       ((string= list-type "ul") (insert " o "))
+       ((string= list-type "ol") (insert (format " %s: " item-nr)))
+       (t (insert " x "))))))
+
+(defun html2text-clean-dtdd (p1 p2)
+  (goto-char p1)
+  (let ((items   0)
+       (item-nr 0))
+    (while (search-forward "<dt>" p2 t)
+      (setq items (1+ items)))
+    (goto-char p1)
+    (while (< item-nr items)
+      (setq item-nr (1+ item-nr))
+      (re-search-forward "<dt>\\([ ]*\\)" (point-max) t)
+      (when (match-string 1)
+       (delete-region (point) (- (point) (string-width (match-string 1)))))
+      (let ((def-p1 (point))
+           (def-p2 0))
+       (re-search-forward "\\([ ]*\\)\\(</dt>\\|<dd>\\)" (point-max) t)
+       (if (match-string 1)
+           (progn
+             (let* ((mw1 (string-width (match-string 1)))
+                    (mw2 (string-width (match-string 2)))
+                    (mw  (+ mw1 mw2)))
+               (goto-char (- (point) mw))
+               (delete-region (point) (+ (point) mw1))
+               (setq def-p2 (point))))
+         (setq def-p2 (- (point) (string-width (match-string 2)))))
+       (put-text-property def-p1 def-p2 'face 'bold)))))
+
+(defun html2text-delete-tags (p1 p2 p3 p4)
+  (delete-region p1 p2)
+  (delete-region (- p3 (- p2 p1)) (- p4 (- p2 p1))))
+
+(defun html2text-delete-single-tag (p1 p2)
+  (delete-region p1 p2))
+
+(defun html2text-clean-hr (p1 p2)
+  (html2text-delete-single-tag p1 p2)
+  (goto-char p1)
+  (newline 1)
+  (insert (make-string fill-column ?-)))
+
+(defun html2text-clean-ul (p1 p2 p3 p4)
+  (html2text-delete-tags p1 p2 p3 p4)
+  (html2text-clean-list-items p1 (- p3 (- p1 p2)) "ul"))
+
+(defun html2text-clean-ol (p1 p2 p3 p4)
+  (html2text-delete-tags p1 p2 p3 p4)
+  (html2text-clean-list-items p1 (- p3 (- p1 p2)) "ol"))
+
+(defun html2text-clean-dl (p1 p2 p3 p4)
+  (html2text-delete-tags p1 p2 p3 p4)
+  (html2text-clean-dtdd p1 (- p3 (- p1 p2))))
+
+(defun html2text-clean-center (p1 p2 p3 p4)
+  (html2text-delete-tags p1 p2 p3 p4)
+  (center-region p1 (- p3 (- p2 p1))))
+
+(defun html2text-clean-bold (p1 p2 p3 p4)
+  (put-text-property p2 p3 'face 'bold)
+  (html2text-delete-tags p1 p2 p3 p4))
+
+(defun html2text-clean-title (p1 p2 p3 p4)
+  (put-text-property p2 p3 'face 'bold)
+  (html2text-delete-tags p1 p2 p3 p4))
+
+(defun html2text-clean-underline (p1 p2 p3 p4)
+  (put-text-property p2 p3 'face 'underline)
+  (html2text-delete-tags p1 p2 p3 p4))
+
+(defun html2text-clean-italic (p1 p2 p3 p4)
+  (put-text-property p2 p3 'face 'italic)
+  (html2text-delete-tags p1 p2 p3 p4))
+
+(defun html2text-clean-font (p1 p2 p3 p4)
+  (html2text-delete-tags p1 p2 p3 p4))
+
+(defun html2text-clean-blockquote (p1 p2 p3 p4)
+  (html2text-delete-tags p1 p2 p3 p4))
+
+(defun html2text-clean-anchor (p1 p2 p3 p4)
+  ;; If someone can explain how to make the URL clickable I will surely
+  ;; improve upon this.
+  ;; Maybe `goto-addr.el' can be used here.
+  (let* ((attr-list (html2text-get-attr p1 p2))
+        (href (html2text-attr-value attr-list "href")))
+    (delete-region p1 p4)
+    (when href
+      (goto-char p1)
+      (insert (if (string-match "\\`['\"].*['\"]\\'" href)
+                 (substring href 1 -1) href))
+      (put-text-property p1 (point) 'face 'bold))))
+
+;;
+;; </Functions to be called to format a tag-pair>
+;;
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;
+;; <Functions to be called to fix up paragraphs>
+;;
+
+(defun html2text-fix-paragraph (p1 p2)
+  (goto-char p1)
+  (let ((refill-start)
+       (refill-stop))
+    (when (re-search-forward "<br>$" p2 t)
+      (goto-char p1)
+      (when (re-search-forward ".+[^<][^b][^r][^>]$" p2 t)
+       (beginning-of-line)
+       (setq refill-start (point))
+       (goto-char p2)
+       (re-search-backward ".+[^<][^b][^r][^>]$" refill-start t)
+       (forward-line 1)
+       (end-of-line)
+       ;; refill-stop should ideally be adjusted to
+       ;; accommodate the "<br>" strings which are removed
+       ;; between refill-start and refill-stop.  Can simply
+       ;; be returned from my-replace-string
+       (setq refill-stop (+ (point)
+                            (html2text-replace-string
+                             "<br>" ""
+                             refill-start (point))))
+       ;; (message "Point = %s  refill-stop = %s" (point) refill-stop)
+       ;; (sleep-for 4)
+       (fill-region refill-start refill-stop))))
+  (html2text-replace-string "<br>" "" p1 p2))
+
+;;
+;; This one is interactive ...
+;;
+(defun html2text-fix-paragraphs ()
+  "This _tries_ to fix up the paragraphs - this is done in quite a ad-hook
+fashion, quite close to pure guess-work. It does work in some cases though."
+  (interactive)
+  (goto-char (point-min))
+  (while (re-search-forward "^<br>$" nil t)
+    (delete-region (match-beginning 0) (match-end 0)))
+  ;; Removing lonely <br> on a single line, if they are left intact we
+  ;; don't have any paragraphs at all.
+  (goto-char (point-min))
+  (while (not (eobp))
+    (let ((p1 (point)))
+      (forward-paragraph 1)
+      ;;(message "Kaller fix med p1=%s  p2=%s " p1 (1- (point))) (sleep-for 5)
+      (html2text-fix-paragraph p1 (1- (point)))
+      (goto-char p1)
+      (when (not (eobp))
+       (forward-paragraph 1)))))
+
+;;
+;; </Functions to be called to fix up paragraphs>
+;;
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;
+;; <Interactive functions>
+;;
+
+(defun html2text-remove-tags (tag-list)
+  "Removes the tags listed in the list `html2text-remove-tag-list'.
+See the documentation for that variable."
+  (interactive)
+  (dolist (tag tag-list)
+    (goto-char (point-min))
+    (while (re-search-forward (format "\\(</?%s[^>]*>\\)" tag) (point-max) t)
+      (delete-region (match-beginning 0) (match-end 0)))))
+
+(defun html2text-format-tags ()
+  "See the variable `html2text-format-tag-list' for documentation."
+  (interactive)
+  (dolist (tag-and-function html2text-format-tag-list)
+    (let ((tag      (car tag-and-function))
+         (function (cdr tag-and-function)))
+      (goto-char (point-min))
+      (while (re-search-forward (format "\\(<%s\\( [^>]*\\)?>\\)" tag)
+                               (point-max) t)
+       (let ((p1)
+             (p2 (point))
+             (p3) (p4))
+         (search-backward "<" (point-min) t)
+         (setq p1 (point))
+         (unless (search-forward (format "</%s>" tag) (point-max) t)
+           (goto-char p2)
+           (insert (format "</%s>" tag)))
+         (setq p4 (point))
+         (search-backward "</" (point-min) t)
+         (setq p3 (point))
+         (funcall function p1 p2 p3 p4)
+         (goto-char p1))))))
+
+(defun html2text-substitute ()
+  "See the variable `html2text-replace-list' for documentation."
+  (interactive)
+  (dolist (e html2text-replace-list)
+    (goto-char (point-min))
+    (let ((old-string (car e))
+         (new-string (cdr e)))
+      (html2text-replace-string old-string new-string (point-min) (point-max)))))
+
+(defun html2text-format-single-elements ()
+  (interactive)
+  (dolist (tag-and-function html2text-format-single-element-list)
+    (let ((tag      (car tag-and-function))
+         (function (cdr tag-and-function)))
+      (goto-char (point-min))
+      (while (re-search-forward (format "\\(<%s\\( [^>]*\\)?>\\)" tag)
+                               (point-max) t)
+       (let ((p1)
+             (p2 (point)))
+         (search-backward "<" (point-min) t)
+         (setq p1 (point))
+         (funcall function p1 p2))))))
+
+;;
+;; Main function
+;;
+
+;;;###autoload
+(defun html2text ()
+  "Convert HTML to plain text in the current buffer."
+  (interactive)
+  (save-excursion
+    (let ((case-fold-search t)
+         (buffer-read-only))
+      (html2text-remove-tags html2text-remove-tag-list)
+      (html2text-format-tags)
+      (html2text-remove-tags html2text-remove-tag-list2)
+      (html2text-substitute)
+      (html2text-format-single-elements)
+      (html2text-fix-paragraphs))))
+
+;;
+;; </Interactive functions>
+;;
+(provide 'html2text)
+
+;;; html2text.el ends here
diff --git a/xemacs-packages/gnus/lisp/ietf-drums.el b/xemacs-packages/gnus/lisp/ietf-drums.el
new file mode 100644 (file)
index 0000000..8008e32
--- /dev/null
@@ -0,0 +1,297 @@
+;;; ietf-drums.el --- Functions for parsing RFC822bis headers
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; DRUMS is an IETF Working Group that works (or worked) on the
+;; successor to RFC822, "Standard For The Format Of Arpa Internet Text
+;; Messages".  This library is based on
+;; draft-ietf-drums-msg-fmt-05.txt, released on 1998-08-05.
+
+;; Pending a real regression self test suite, Simon Josefsson added
+;; various self test expressions snipped from bug reports, and their
+;; expected value, below.  I you believe it could be useful, please
+;; add your own test cases, or write a real self test suite, or just
+;; remove this.
+
+;; <m3oekvfd50.fsf@whitebox.m5r.de>
+;; (ietf-drums-parse-address "'foo' <foo@example.com>")
+;; => ("foo@example.com" . "'foo'")
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(require 'mm-util)
+
+(defvar ietf-drums-no-ws-ctl-token "\001-\010\013\014\016-\037\177"
+  "US-ASCII control characters excluding CR, LF and white space.")
+(defvar ietf-drums-text-token "\001-\011\013\014\016-\177"
+  "US-ASCII characters excluding CR and LF.")
+(defvar ietf-drums-specials-token "()<>[]:;@\\,.\""
+  "Special characters.")
+(defvar ietf-drums-quote-token "\\"
+  "Quote character.")
+(defvar ietf-drums-wsp-token " \t"
+  "White space.")
+(defvar ietf-drums-fws-regexp
+  (concat "[" ietf-drums-wsp-token "]*\n[" ietf-drums-wsp-token "]+")
+  "Folding white space.")
+(defvar ietf-drums-atext-token "-^a-zA-Z0-9!#$%&'*+/=?_`{|}~"
+  "Textual token.")
+(defvar ietf-drums-dot-atext-token "-^a-zA-Z0-9!#$%&'*+/=?_`{|}~."
+  "Textual token including full stop.")
+(defvar ietf-drums-qtext-token
+  (concat ietf-drums-no-ws-ctl-token "\041\043-\133\135-\177")
+  "Non-white-space control characters, plus the rest of ASCII excluding
+backslash and doublequote.")
+(defvar ietf-drums-tspecials "][()<>@,;:\\\"/?="
+  "Tspecials.")
+
+(defvar ietf-drums-syntax-table
+  (let ((table (copy-syntax-table emacs-lisp-mode-syntax-table)))
+    (modify-syntax-entry ?\\ "/" table)
+    (modify-syntax-entry ?< "(" table)
+    (modify-syntax-entry ?> ")" table)
+    (modify-syntax-entry ?@ "w" table)
+    (modify-syntax-entry ?/ "w" table)
+    (modify-syntax-entry ?* "_" table)
+    (modify-syntax-entry ?\; "_" table)
+    (modify-syntax-entry ?\' "_" table)
+    (if (featurep 'xemacs)
+       (let ((i 128))
+         (while (< i 256)
+           (modify-syntax-entry i "w" table)
+           (setq i (1+ i)))))
+    table))
+
+(defun ietf-drums-token-to-list (token)
+  "Translate TOKEN into a list of characters."
+  (let ((i 0)
+       b e c out range)
+    (while (< i (length token))
+      (setq c (mm-char-int (aref token i)))
+      (incf i)
+      (cond
+       ((eq c (mm-char-int ?-))
+       (if b
+           (setq range t)
+         (push c out)))
+       (range
+       (while (<= b c)
+         (push (make-char 'ascii b) out)
+         (incf b))
+       (setq range nil))
+       ((= i (length token))
+       (push (make-char 'ascii c) out))
+       (t
+       (when b
+         (push (make-char 'ascii b) out))
+       (setq b c))))
+    (nreverse out)))
+
+(defsubst ietf-drums-init (string)
+  (set-syntax-table ietf-drums-syntax-table)
+  (insert string)
+  (ietf-drums-unfold-fws)
+  (goto-char (point-min)))
+
+(defun ietf-drums-remove-comments (string)
+  "Remove comments from STRING."
+  (with-temp-buffer
+    (let (c)
+      (ietf-drums-init string)
+      (while (not (eobp))
+       (setq c (char-after))
+       (cond
+        ((eq c ?\")
+         (condition-case err
+             (forward-sexp 1)
+           (error (goto-char (point-max)))))
+        ((eq c ?\()
+         (delete-region
+              (point)
+              (condition-case nil
+                  (with-syntax-table (copy-syntax-table ietf-drums-syntax-table)
+                    (modify-syntax-entry ?\" "w")
+                    (forward-sexp 1)
+                    (point))
+                (error (point-max)))))
+        (t
+         (forward-char 1))))
+      (buffer-string))))
+
+(defun ietf-drums-remove-whitespace (string)
+  "Remove whitespace from STRING."
+  (with-temp-buffer
+    (ietf-drums-init string)
+    (let (c)
+      (while (not (eobp))
+       (setq c (char-after))
+       (cond
+        ((eq c ?\")
+         (forward-sexp 1))
+        ((eq c ?\()
+         (forward-sexp 1))
+        ((memq c '(?\  ?\t ?\n))
+         (delete-char 1))
+        (t
+         (forward-char 1))))
+      (buffer-string))))
+
+(defun ietf-drums-get-comment (string)
+  "Return the first comment in STRING."
+  (with-temp-buffer
+    (ietf-drums-init string)
+    (let (result c)
+      (while (not (eobp))
+       (setq c (char-after))
+       (cond
+        ((eq c ?\")
+         (forward-sexp 1))
+        ((eq c ?\()
+         (setq result
+               (buffer-substring
+                (1+ (point))
+                (progn (forward-sexp 1) (1- (point))))))
+        (t
+         (forward-char 1))))
+      result)))
+
+(defun ietf-drums-strip (string)
+  "Remove comments and whitespace from STRING."
+  (ietf-drums-remove-whitespace (ietf-drums-remove-comments string)))
+
+(defun ietf-drums-parse-address (string)
+  "Parse STRING and return a MAILBOX / DISPLAY-NAME pair."
+  (with-temp-buffer
+    (let (display-name mailbox c display-string)
+      (ietf-drums-init string)
+      (while (not (eobp))
+       (setq c (char-after))
+       (cond
+        ((or (eq c ? )
+             (eq c ?\t))
+         (forward-char 1))
+        ((eq c ?\()
+         (forward-sexp 1))
+        ((eq c ?\")
+         (push (buffer-substring
+                (1+ (point)) (progn (forward-sexp 1) (1- (point))))
+               display-name))
+        ((looking-at (concat "[" ietf-drums-atext-token "@" "]"))
+         (push (buffer-substring (point) (progn (forward-sexp 1) (point)))
+               display-name))
+        ((eq c ?<)
+         (setq mailbox
+               (ietf-drums-remove-whitespace
+                (ietf-drums-remove-comments
+                 (buffer-substring
+                  (1+ (point))
+                  (progn (forward-sexp 1) (1- (point))))))))
+        (t
+         (forward-char 1))))
+      ;; If we found no display-name, then we look for comments.
+      (if display-name
+         (setq display-string
+               (mapconcat 'identity (reverse display-name) " "))
+       (setq display-string (ietf-drums-get-comment string)))
+      (if (not mailbox)
+         (when (and display-string
+                    (string-match "@" display-string))
+           (cons
+            (mapconcat 'identity (nreverse display-name) "")
+            (ietf-drums-get-comment string)))
+       (cons mailbox display-string)))))
+
+(defun ietf-drums-parse-addresses (string &optional rawp)
+  "Parse STRING and return a list of MAILBOX / DISPLAY-NAME pairs.
+If RAWP, don't actually parse the addresses, but instead return
+a list of address strings."
+  (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
+                 (if rawp
+                     (buffer-substring beg (point))
+                   (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
+             (if rawp
+                 (buffer-substring beg (point))
+               (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."
+  (goto-char (point-min))
+  (while (re-search-forward ietf-drums-fws-regexp nil t)
+    (replace-match " " t t))
+  (goto-char (point-min)))
+
+(defun ietf-drums-parse-date (string)
+  "Return an Emacs time spec from STRING."
+  (apply 'encode-time (parse-time-string string)))
+
+(defun ietf-drums-narrow-to-header ()
+  "Narrow to the header section in the current buffer."
+  (narrow-to-region
+   (goto-char (point-min))
+   (if (re-search-forward "^\r?$" nil 1)
+       (match-beginning 0)
+     (point-max)))
+  (goto-char (point-min)))
+
+(defun ietf-drums-quote-string (string)
+  "Quote string if it needs quoting to be displayed in a header."
+  (if (string-match (concat "[^" ietf-drums-atext-token "]") string)
+      (concat "\"" string "\"")
+    string))
+
+(defun ietf-drums-make-address (name address)
+  (if name
+      (concat (ietf-drums-quote-string name) " <" address ">")
+    address))
+
+(provide 'ietf-drums)
+
+;;; ietf-drums.el ends here
diff --git a/xemacs-packages/gnus/lisp/imap.el b/xemacs-packages/gnus/lisp/imap.el
new file mode 100644 (file)
index 0000000..a478225
--- /dev/null
@@ -0,0 +1,3097 @@
+;;; imap.el --- imap library
+
+;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+;;   2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+;; Author: Simon Josefsson <simon@josefsson.org>
+;; Keywords: mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; imap.el is an elisp library providing an interface for talking to
+;; IMAP servers.
+;;
+;; imap.el is roughly divided in two parts, one that parses IMAP
+;; responses from the server and storing data into buffer-local
+;; variables, and one for utility functions which send commands to
+;; server, waits for an answer, and return information.  The latter
+;; part is layered on top of the previous.
+;;
+;; The imap.el API consist of the following functions, other functions
+;; in this file should not be called directly and the result of doing
+;; so are at best undefined.
+;;
+;; Global commands:
+;;
+;; imap-open,       imap-opened,    imap-authenticate, imap-close,
+;; imap-capability, imap-namespace, imap-error-text
+;;
+;; Mailbox commands:
+;;
+;; imap-mailbox-get,       imap-mailbox-map,         imap-current-mailbox,
+;; imap-current-mailbox-p, imap-search,              imap-mailbox-select,
+;; imap-mailbox-examine,   imap-mailbox-unselect,    imap-mailbox-expunge
+;; imap-mailbox-close,     imap-mailbox-create,      imap-mailbox-delete
+;; imap-mailbox-rename,    imap-mailbox-lsub,        imap-mailbox-list
+;; imap-mailbox-subscribe, imap-mailbox-unsubscribe, imap-mailbox-status
+;; imap-mailbox-acl-get,   imap-mailbox-acl-set,     imap-mailbox-acl-delete
+;;
+;; Message commands:
+;;
+;; 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-from,        imap-message-envelope-sender,
+;; imap-message-envelope-reply-to,    imap-message-envelope-to,
+;; imap-message-envelope-cc,          imap-message-envelope-bcc
+;; imap-message-envelope-in-reply-to, imap-message-envelope-message-id
+;; imap-message-body,                 imap-message-flag-permanent-p
+;; imap-message-flags-set,            imap-message-flags-del
+;; imap-message-flags-add,            imap-message-copyuid
+;; imap-message-copy,                 imap-message-appenduid
+;; imap-message-append,               imap-envelope-from
+;; imap-body-lines
+;;
+;; It is my hope that these commands should be pretty self
+;; explanatory for someone that know IMAP.  All functions have
+;; additional documentation on how to invoke them.
+;;
+;; imap.el supports RFC1730/2060/RFC3501 (IMAP4/IMAP4rev1).  The implemented
+;; IMAP extensions are RFC2195 (CRAM-MD5), RFC2086 (ACL), RFC2342
+;; (NAMESPACE), RFC2359 (UIDPLUS), the IMAP-part of RFC2595 (STARTTLS,
+;; LOGINDISABLED) (with use of external library starttls.el and
+;; program starttls), and the GSSAPI / Kerberos V4 sections of RFC1731
+;; (with use of external program `imtest'), and RFC2971 (ID).  It also
+;; takes advantage of the UNSELECT extension in Cyrus IMAPD.
+;;
+;; Without the work of John McClary Prevost and Jim Radford this library
+;; would not have seen the light of day.  Many thanks.
+;;
+;; This is a transcript of a short interactive session for demonstration
+;; purposes.
+;;
+;; (imap-open "my.mail.server")
+;; => " *imap* my.mail.server:0"
+;;
+;; The rest are invoked with current buffer as the buffer returned by
+;; `imap-open'.  It is possible to do it all without this, but it would
+;; look ugly here since `buffer' is always the last argument for all
+;; imap.el API functions.
+;;
+;; (imap-authenticate "myusername" "mypassword")
+;; => auth
+;;
+;; (imap-mailbox-lsub "*")
+;; => ("INBOX.sentmail" "INBOX.private" "INBOX.draft" "INBOX.spam")
+;;
+;; (imap-mailbox-list "INBOX.n%")
+;; => ("INBOX.namedroppers" "INBOX.nnimap" "INBOX.ntbugtraq")
+;;
+;; (imap-mailbox-select "INBOX.nnimap")
+;; => "INBOX.nnimap"
+;;
+;; (imap-mailbox-get 'exists)
+;; => 166
+;;
+;; (imap-mailbox-get 'uidvalidity)
+;; => "908992622"
+;;
+;; (imap-search "FLAGGED SINCE 18-DEC-98")
+;; => (235 236)
+;;
+;; (imap-fetch 235 "RFC822.PEEK" 'RFC822)
+;; => "X-Sieve: cmu-sieve 1.3^M\nX-Username: <jas@pdc.kth.se>^M\r...."
+;;
+;; Todo:
+;;
+;; o Parse UIDs as strings? We need to overcome the 28 bit limit somehow.
+;;   Use IEEE floats (which are effectively exact)?  -- fx
+;; o Don't use `read' at all (important places already fixed)
+;; o Accept list of articles instead of message set string in most
+;;   imap-message-* functions.
+;; o Send strings as literal if they contain, e.g., ".
+;;
+;; Revision history:
+;;
+;;  - 19991218 added starttls/digest-md5 patch,
+;;             by Daiki Ueno <ueno@ueda.info.waseda.ac.jp>
+;;             NB! you need SLIM for starttls.el and digest-md5.el
+;;  - 19991023 committed to pgnus
+;;
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(eval-and-compile
+  (unless (fboundp 'declare-function) (defmacro declare-function (&rest r)))
+  (autoload 'starttls-open-stream "starttls")
+  (autoload 'starttls-negotiate "starttls")
+  (autoload 'sasl-find-mechanism "sasl")
+  (autoload 'digest-md5-parse-digest-challenge "digest-md5")
+  (autoload 'digest-md5-digest-response "digest-md5")
+  (autoload 'digest-md5-digest-uri "digest-md5")
+  (autoload 'digest-md5-challenge "digest-md5")
+  (autoload 'rfc2104-hash "rfc2104")
+  (autoload 'utf7-encode "utf7")
+  (autoload 'utf7-decode "utf7")
+  (autoload 'format-spec "format-spec")
+  (autoload 'format-spec-make "format-spec")
+  (autoload 'open-tls-stream "tls"))
+
+;; User variables.
+
+(defgroup imap nil
+  "Low-level IMAP issues."
+  :version "21.1"
+  :group 'mail)
+
+(defcustom imap-kerberos4-program '("imtest -m kerberos_v4 -u %l -p %p %s"
+                                   "imtest -kp %s %p")
+  "List of strings containing commands for Kerberos 4 authentication.
+%s is replaced with server hostname, %p with port to connect to, and
+%l with the value of `imap-default-user'.  The program should accept
+IMAP commands on stdin and return responses to stdout.  Each entry in
+the list is tried until a successful connection is made."
+  :group 'imap
+  :type '(repeat string))
+
+(defcustom imap-gssapi-program (list
+                               (concat "gsasl %s %p "
+                                       "--mechanism GSSAPI "
+                                       "--authentication-id %l")
+                               "imtest -m gssapi -u %l -p %p %s")
+  "List of strings containing commands for GSSAPI (krb5) authentication.
+%s is replaced with server hostname, %p with port to connect to, and
+%l with the value of `imap-default-user'.  The program should accept
+IMAP commands on stdin and return responses to stdout.  Each entry in
+the list is tried until a successful connection is made."
+  :group 'imap
+  :type '(repeat string))
+
+(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
+stdin and return responses to stdout.  Each entry in the list is tried
+until a successful connection is made."
+  :group 'imap
+  :type '(choice string
+                (repeat string)))
+
+(defcustom imap-shell-program '("ssh %s imapd"
+                               "rsh %s imapd"
+                               "ssh %g ssh %s imapd"
+                               "rsh %g rsh %s imapd")
+  "A list of strings, containing commands for IMAP connection.
+Within a string, %s is replaced with the server address, %p with port
+number on server, %g with `imap-shell-host', and %l with
+`imap-default-user'.  The program should read IMAP commands from stdin
+and write IMAP response to stdout.  Each entry in the list is tried
+until a successful connection is made."
+  :group 'imap
+  :type '(repeat string))
+
+(defcustom imap-process-connection-type nil
+  "*Value for `process-connection-type' to use for Kerberos4, GSSAPI and SSL.
+The `process-connection-type' variable controls the type of device
+used to communicate with subprocesses.  Values are nil to use a
+pipe, or t or `pty' to use a pty.  The value has no effect if the
+system has no ptys or if all ptys are busy: then a pipe is used
+in any case.  The value takes effect when an IMAP server is
+opened; changing it after that has no effect."
+  :version "22.1"
+  :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)
+
+(defcustom imap-log nil
+  "If non-nil, an imap session trace is placed in `imap-log-buffer'.
+Note that username, passwords and other privacy sensitive
+information (such as e-mail) may be stored in the buffer.
+It is not written to disk, however.  Do not enable this
+variable unless you are comfortable with that.
+
+See also `imap-debug'."
+  :group 'imap
+  :type 'boolean)
+
+(defcustom imap-debug nil
+  "If non-nil, trace imap- functions into `imap-debug-buffer'.
+Uses `trace-function-background', so you can turn it off with,
+say, `untrace-all'.
+
+Note that username, passwords and other privacy sensitive
+information (such as e-mail) may be stored in the buffer.
+It is not written to disk, however.  Do not enable this
+variable unless you are comfortable with that.
+
+This variable only takes effect when loading the `imap' library.
+See also `imap-log'."
+  :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)
+
+(defcustom imap-read-timeout (if (string-match
+                                 "windows-nt\\|os/2\\|emx\\|cygwin"
+                                 (symbol-name system-type))
+                                1.0
+                              0.1)
+  "*How long to wait between checking for the end of output.
+Shorter values mean quicker response, but is more CPU intensive."
+  :type 'number
+  :group 'imap)
+
+(defcustom imap-store-password nil
+  "If non-nil, store session password without prompting."
+  :group 'imap
+  :type 'boolean)
+
+;; Various variables.
+
+(defvar imap-fetch-data-hook nil
+  "Hooks called after receiving each FETCH response.")
+
+(defvar imap-streams '(gssapi kerberos4 starttls tls ssl network shell)
+  "Priority of streams to consider when opening connection to server.")
+
+(defvar imap-stream-alist
+  '((gssapi    imap-gssapi-stream-p    imap-gssapi-open)
+    (kerberos4 imap-kerberos4-stream-p imap-kerberos4-open)
+    (tls       imap-tls-p              imap-tls-open)
+    (ssl       imap-ssl-p              imap-ssl-open)
+    (network   imap-network-p          imap-network-open)
+    (shell     imap-shell-p            imap-shell-open)
+    (starttls  imap-starttls-p         imap-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.")
+
+(defvar imap-authenticators '(gssapi
+                             kerberos4
+                             digest-md5
+                             cram-md5
+                             ;;sasl
+                             login
+                             anonymous)
+  "Priority of authenticators to consider when authenticating to server.")
+
+(defvar imap-authenticator-alist
+  '((gssapi     imap-gssapi-auth-p    imap-gssapi-auth)
+    (kerberos4  imap-kerberos4-auth-p imap-kerberos4-auth)
+    (sasl      imap-sasl-auth-p      imap-sasl-auth)
+    (cram-md5   imap-cram-md5-p       imap-cram-md5-auth)
+    (login      imap-login-p          imap-login-auth)
+    (anonymous  imap-anonymous-p      imap-anonymous-auth)
+    (digest-md5 imap-digest-md5-p     imap-digest-md5-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.")
+
+(defvar imap-error nil
+  "Error codes from the last command.")
+
+(defvar imap-logout-timeout nil
+  "Close server immediately if it can't logout in this number of seconds.
+If it is nil, never close server until logout completes.  Normally,
+the value of this variable will be bound to a certain value to which
+an application program that uses this module specifies on a per-server
+basis.")
+
+;; Internal constants.  Change these and die.
+
+(defconst imap-default-port 143)
+(defconst imap-default-ssl-port 993)
+(defconst imap-default-tls-port 993)
+(defconst imap-default-stream 'network)
+(defconst imap-coding-system-for-read 'binary)
+(defconst imap-coding-system-for-write 'binary)
+(defconst imap-local-variables '(imap-server
+                                imap-port
+                                imap-client-eol
+                                imap-server-eol
+                                imap-auth
+                                imap-stream
+                                imap-username
+                                imap-password
+                                imap-current-mailbox
+                                imap-current-target-mailbox
+                                imap-message-data
+                                imap-capability
+                                imap-id
+                                imap-namespace
+                                imap-state
+                                imap-reached-tag
+                                imap-failed-tags
+                                imap-tag
+                                imap-process
+                                imap-calculate-literal-size-first
+                                imap-mailbox-data))
+(defconst imap-log-buffer "*imap-log*")
+(defconst imap-debug-buffer "*imap-debug*")
+
+;; Internal variables.
+
+(defvar imap-stream nil)
+(defvar imap-auth nil)
+(defvar imap-server nil)
+(defvar imap-port nil)
+(defvar imap-username nil)
+(defvar imap-password nil)
+(defvar imap-last-authenticator nil)
+(defvar imap-calculate-literal-size-first nil)
+(defvar imap-state 'closed
+  "IMAP state.
+Valid states are `closed', `initial', `nonauth', `auth', `selected'
+and `examine'.")
+
+(defvar imap-server-eol "\r\n"
+  "The EOL string sent from the server.")
+
+(defvar imap-client-eol "\r\n"
+  "The EOL string we send to the server.")
+
+(defvar imap-current-mailbox nil
+  "Current mailbox name.")
+
+(defvar imap-current-target-mailbox nil
+  "Current target mailbox for COPY and APPEND commands.")
+
+(defvar imap-mailbox-data nil
+  "Obarray with mailbox data.")
+
+(defvar imap-mailbox-prime 997
+  "Length of `imap-mailbox-data'.")
+
+(defvar imap-current-message nil
+  "Current message number.")
+
+(defvar imap-message-data nil
+  "Obarray with message data.")
+
+(defvar imap-message-prime 997
+  "Length of `imap-message-data'.")
+
+(defvar imap-capability nil
+  "Capability for server.")
+
+(defvar imap-id nil
+  "Identity of server.
+See RFC 2971.")
+
+(defvar imap-namespace nil
+  "Namespace for current server.")
+
+(defvar imap-reached-tag 0
+  "Lower limit on command tags that have been parsed.")
+
+(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
+human readable response text (a string).")
+
+(defvar imap-tag 0
+  "Command tag number.")
+
+(defvar imap-process nil
+  "Process.")
+
+(defvar imap-continuation nil
+  "Non-nil indicates that the server emitted a continuation request.
+The actual value is really the text on the continuation line.")
+
+(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.")
+
+(defvar imap-enable-exchange-bug-workaround nil
+  "Send FETCH UID commands as *:* instead of *.
+
+When non-nil, use an alternative UIDS form.  Enabling appears to
+be required for some servers (e.g., Microsoft Exchange 2007)
+which otherwise would trigger a response 'BAD The specified
+message set is invalid.'.  We don't unconditionally use this
+form, since this is said to be significantly inefficient.
+
+This variable is set to t automatically per server if the
+canonical form fails.")
+
+\f
+;; Utility functions:
+
+(defun imap-remassoc (key alist)
+  "Delete by side effect any elements of ALIST whose car is `equal' to KEY.
+The modified ALIST is returned.  If the first member
+of ALIST 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)
+    (set-buffer-multibyte nil)))
+
+(defsubst imap-utf7-encode (string)
+  (if imap-use-utf7
+      (and string
+          (condition-case ()
+              (utf7-encode string t)
+            (error (message
+                    "imap: Could not UTF7 encode `%s', using it unencoded..."
+                    string)
+                   string)))
+    string))
+
+(defsubst imap-utf7-decode (string)
+  (if imap-use-utf7
+      (and string
+          (condition-case ()
+              (utf7-decode string t)
+            (error (message
+                    "imap: Could not UTF7 decode `%s', using it undecoded..."
+                    string)
+                   string)))
+    string))
+
+(defsubst imap-ok-p (status)
+  (if (eq status 'OK)
+      t
+    (setq imap-error status)
+    nil))
+
+(defun imap-error-text (&optional buffer)
+  (with-current-buffer (or buffer (current-buffer))
+    (nth 3 (car imap-failed-tags))))
+
+\f
+;; Server functions; stream stuff:
+
+(defun imap-kerberos4-stream-p (buffer)
+  (imap-capability 'AUTH=KERBEROS_V4 buffer))
+
+(defun imap-kerberos4-open (name buffer server port)
+  (let ((cmds imap-kerberos4-program)
+       cmd done)
+    (while (and (not done) (setq cmd (pop cmds)))
+      (message "Opening Kerberos 4 IMAP connection with `%s'..." cmd)
+      (erase-buffer)
+      (let* ((port (or port imap-default-port))
+            (coding-system-for-read imap-coding-system-for-read)
+            (coding-system-for-write imap-coding-system-for-write)
+            (process-connection-type imap-process-connection-type)
+            (process (start-process
+                      name buffer shell-file-name shell-command-switch
+                      (format-spec
+                       cmd
+                       (format-spec-make
+                        ?s server
+                        ?p (number-to-string port)
+                        ?l imap-default-user))))
+            response)
+       (when process
+         (with-current-buffer buffer
+           (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))
+                       ;; Athena IMTEST can output SSL verify errors
+                       (or (while (looking-at "^verify error:num=")
+                             (forward-line))
+                           t)
+                       (or (while (looking-at "^TLS connection established")
+                             (forward-line))
+                           t)
+                       ;; cyrus 1.6.x (13? < x <= 22) queries capabilities
+                       (or (while (looking-at "^C:")
+                             (forward-line))
+                           t)
+                       ;; cyrus 1.6 imtest print "S: " before server greeting
+                       (or (not (looking-at "S: "))
+                           (forward-char 3)
+                           t)
+                       (not (and (imap-parse-greeting)
+                                 ;; success in imtest < 1.6:
+                                 (or (re-search-forward
+                                      "^__\\(.*\\)__\n" nil t)
+                                     ;; success in imtest 1.6:
+                                     (re-search-forward
+                                      "^\\(Authenticat.*\\)" nil t))
+                                 (setq response (match-string 1)))))
+             (accept-process-output process 1)
+             (sit-for 1))
+           (and imap-log
+                (with-current-buffer (get-buffer-create imap-log-buffer)
+                  (imap-disable-multibyte)
+                  (buffer-disable-undo)
+                  (goto-char (point-max))
+                  (insert-buffer-substring buffer)))
+           (erase-buffer)
+           (message "Opening Kerberos 4 IMAP connection with `%s'...%s" cmd
+                    (if response (concat "done, " response) "failed"))
+           (if (and response (let ((case-fold-search nil))
+                               (not (string-match "failed" response))))
+               (setq done process)
+             (if (memq (process-status process) '(open run))
+                 (imap-logout))
+             (delete-process process)
+             nil)))))
+    done))
+
+(defun imap-gssapi-stream-p (buffer)
+  (imap-capability 'AUTH=GSSAPI buffer))
+
+(defun imap-gssapi-open (name buffer server port)
+  (let ((cmds imap-gssapi-program)
+       cmd done)
+    (while (and (not done) (setq cmd (pop cmds)))
+      (message "Opening GSSAPI IMAP connection with `%s'..." cmd)
+      (erase-buffer)
+      (let* ((port (or port imap-default-port))
+            (coding-system-for-read imap-coding-system-for-read)
+            (coding-system-for-write imap-coding-system-for-write)
+            (process-connection-type imap-process-connection-type)
+            (process (start-process
+                      name buffer shell-file-name shell-command-switch
+                      (format-spec
+                       cmd
+                       (format-spec-make
+                        ?s server
+                        ?p (number-to-string port)
+                        ?l imap-default-user))))
+            response)
+       (when process
+         (with-current-buffer buffer
+           (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))
+                       ;; Athena IMTEST can output SSL verify errors
+                       (or (while (looking-at "^verify error:num=")
+                             (forward-line))
+                           t)
+                       (or (while (looking-at "^TLS connection established")
+                             (forward-line))
+                           t)
+                       ;; cyrus 1.6.x (13? < x <= 22) queries capabilities
+                       (or (while (looking-at "^C:")
+                             (forward-line))
+                           t)
+                       ;; cyrus 1.6 imtest print "S: " before server greeting
+                       (or (not (looking-at "S: "))
+                           (forward-char 3)
+                           t)
+                       ;; GNU SASL may print 'Trying ...' first.
+                       (or (not (looking-at "Trying "))
+                           (forward-line)
+                           t)
+                       (not (and (imap-parse-greeting)
+                                 ;; success in imtest 1.6:
+                                 (re-search-forward
+                                  (concat "^\\(\\(Authenticat.*\\)\\|\\("
+                                          "Client authentication "
+                                          "finished.*\\)\\)")
+                                  nil t)
+                                 (setq response (match-string 1)))))
+             (accept-process-output process 1)
+             (sit-for 1))
+           (and imap-log
+                (with-current-buffer (get-buffer-create imap-log-buffer)
+                  (imap-disable-multibyte)
+                  (buffer-disable-undo)
+                  (goto-char (point-max))
+                  (insert-buffer-substring buffer)))
+           (erase-buffer)
+           (message "GSSAPI IMAP connection: %s" (or response "failed"))
+           (if (and response (let ((case-fold-search nil))
+                               (not (string-match "failed" response))))
+               (setq done process)
+             (if (memq (process-status process) '(open run))
+                 (imap-logout))
+             (delete-process process)
+             nil)))))
+    done))
+
+(defun imap-ssl-p (buffer)
+  nil)
+
+(defun imap-ssl-open (name buffer server port)
+  "Open an SSL connection to SERVER."
+  (let ((cmds (if (listp imap-ssl-program) imap-ssl-program
+               (list imap-ssl-program)))
+       cmd done)
+    (while (and (not done) (setq cmd (pop cmds)))
+      (message "imap: Opening SSL connection with `%s'..." cmd)
+      (erase-buffer)
+      (let* ((port (or port imap-default-ssl-port))
+            (coding-system-for-read imap-coding-system-for-read)
+            (coding-system-for-write imap-coding-system-for-write)
+            (process-connection-type imap-process-connection-type)
+            (set-process-query-on-exit-flag
+             (if (fboundp 'set-process-query-on-exit-flag)
+                 'set-process-query-on-exit-flag
+               'process-kill-without-query))
+            process)
+       (when (progn
+               (setq process (start-process
+                              name buffer shell-file-name
+                              shell-command-switch
+                              (format-spec cmd
+                                           (format-spec-make
+                                            ?s server
+                                            ?p (number-to-string port)))))
+               (funcall set-process-query-on-exit-flag process nil)
+               process)
+         (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-buffer)
+                  (imap-disable-multibyte)
+                  (buffer-disable-undo)
+                  (goto-char (point-max))
+                  (insert-buffer-substring buffer)))
+           (erase-buffer)
+           (when (memq (process-status process) '(open run))
+             (setq done process))))))
+    (if done
+       (progn
+         (message "imap: Opening SSL connection with `%s'...done" cmd)
+         done)
+      (message "imap: Opening SSL connection with `%s'...failed" cmd)
+      nil)))
+
+(defun imap-tls-p (buffer)
+  nil)
+
+(defun imap-tls-open (name buffer server port)
+  (let* ((port (or port imap-default-tls-port))
+        (coding-system-for-read imap-coding-system-for-read)
+        (coding-system-for-write imap-coding-system-for-write)
+        (process (open-tls-stream name buffer server port)))
+    (when process
+      (while (and (memq (process-status process) '(open run))
+                 ;; FIXME: Per the "blue moon" comment, the process/buffer
+                 ;; handling here, and elsewhere in functions which open
+                 ;; streams, looks confused.  Obviously we can change buffers
+                 ;; if a different process handler kicks in from
+                 ;; `accept-process-output' or `sit-for' below, and TRT seems
+                 ;; to be to `save-buffer' around those calls.  (I wonder why
+                 ;; `sit-for' is used with a non-zero wait.)  -- fx
+                 (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-buffer)
+            (imap-disable-multibyte)
+            (buffer-disable-undo)
+            (goto-char (point-max))
+            (insert-buffer-substring buffer)))
+      (when (memq (process-status process) '(open run))
+       process))))
+
+(defun imap-network-p (buffer)
+  t)
+
+(defun imap-network-open (name buffer server port)
+  (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 (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-buffer)
+            (imap-disable-multibyte)
+            (buffer-disable-undo)
+            (goto-char (point-max))
+            (insert-buffer-substring buffer)))
+      (when (memq (process-status process) '(open run))
+       process))))
+
+(defun imap-shell-p (buffer)
+  nil)
+
+(defun imap-shell-open (name buffer server port)
+  (let ((cmds (if (listp imap-shell-program) imap-shell-program
+               (list imap-shell-program)))
+       cmd done)
+    (while (and (not done) (setq cmd (pop cmds)))
+      (message "imap: Opening IMAP connection with `%s'..." cmd)
+      (setq imap-client-eol "\n")
+      (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
+                      name buffer shell-file-name shell-command-switch
+                      (format-spec
+                       cmd
+                       (format-spec-make
+                        ?s server
+                        ?g imap-shell-host
+                        ?p (number-to-string port)
+                        ?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-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-buffer)
+                (imap-disable-multibyte)
+                (buffer-disable-undo)
+                (goto-char (point-max))
+                (insert-buffer-substring buffer)))
+         (erase-buffer)
+         (when (memq (process-status process) '(open run))
+           (setq done process)))))
+    (if done
+       (progn
+         (message "imap: Opening IMAP connection with `%s'...done" cmd)
+         done)
+      (message "imap: Opening IMAP connection with `%s'...failed" cmd)
+      nil)))
+
+(defun imap-starttls-p (buffer)
+  (imap-capability 'STARTTLS buffer))
+
+(defun imap-starttls-open (name buffer server port)
+  (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 (starttls-open-stream name buffer server port))
+        done tls-info)
+    (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-max))
+                 (forward-line -1)
+                 (not (imap-parse-greeting)))
+       (accept-process-output process 1)
+       (sit-for 1))
+      (imap-send-command "STARTTLS")
+      (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 (re-search-forward "[0-9]+ OK.*\r?\n" nil t)))
+       (accept-process-output process 1)
+       (sit-for 1))
+      (and imap-log
+          (with-current-buffer (get-buffer-create imap-log-buffer)
+            (buffer-disable-undo)
+            (goto-char (point-max))
+            (insert-buffer-substring buffer)))
+      (when (and (setq tls-info (starttls-negotiate process))
+                (memq (process-status process) '(open run)))
+       (setq done process)))
+    (if (stringp tls-info)
+       (message "imap: STARTTLS info: %s" tls-info))
+    (message "imap: Connecting with STARTTLS...%s" (if done "done" "failed"))
+    done))
+
+;; Server functions; authenticator stuff:
+
+(defun imap-interactive-login (buffer loginfunc)
+  "Login to server in BUFFER.
+LOGINFUNC is passed a username and a password, it should return t if
+it where successful authenticating itself to the server, nil otherwise.
+Returns t if login was successful, nil otherwise."
+  (with-current-buffer buffer
+    (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
+                       (concat "imap: username for " imap-server
+                               " (using stream `" (symbol-name imap-stream)
+                               "'): ")
+                       (or user imap-default-user))))
+       (setq passwd (or imap-password
+                        (read-passwd
+                         (concat "imap: password for " user "@"
+                                 imap-server " (using authenticator `"
+                                 (symbol-name imap-auth) "'): "))))
+       (when (and user passwd)
+         (if (funcall loginfunc user passwd)
+             (progn
+               (message "imap: Login successful...")
+               (setq ret t
+                     imap-username user)
+               (when (and (not imap-password)
+                          (or imap-store-password
+                              (y-or-n-p "imap: Store password for this IMAP session? ")))
+                 (setq imap-password passwd)))
+           (message "imap: Login failed...")
+           (setq passwd nil)
+           (setq imap-password 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 imap-gssapi-auth-p (buffer)
+  (eq imap-stream 'gssapi))
+
+(defun imap-gssapi-auth (buffer)
+  (message "imap: Authenticating using GSSAPI...%s"
+          (if (eq imap-stream 'gssapi) "done" "failed"))
+  (eq imap-stream 'gssapi))
+
+(defun imap-kerberos4-auth-p (buffer)
+  (and (imap-capability 'AUTH=KERBEROS_V4 buffer)
+       (eq imap-stream 'kerberos4)))
+
+(defun imap-kerberos4-auth (buffer)
+  (message "imap: Authenticating using Kerberos 4...%s"
+          (if (eq imap-stream 'kerberos4) "done" "failed"))
+  (eq imap-stream 'kerberos4))
+
+(defun imap-cram-md5-p (buffer)
+  (imap-capability 'AUTH=CRAM-MD5 buffer))
+
+(defun imap-cram-md5-auth (buffer)
+  "Login to server using the AUTH CRAM-MD5 method."
+  (message "imap: Authenticating using CRAM-MD5...")
+  (let ((done (imap-interactive-login
+              buffer
+              (lambda (user passwd)
+                (imap-ok-p
+                 (imap-send-command-wait
+                  (list
+                   "AUTHENTICATE CRAM-MD5"
+                   (lambda (challenge)
+                     (let* ((decoded (base64-decode-string challenge))
+                            (hash (rfc2104-hash 'md5 64 16 passwd decoded))
+                            (response (concat user " " hash))
+                            (encoded (base64-encode-string response)))
+                       encoded)))))))))
+    (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))
+       (not (imap-capability 'X-LOGIN-CMD-DISABLED buffer))))
+
+(defun imap-quote-specials (string)
+  (with-temp-buffer
+    (insert string)
+    (goto-char (point-min))
+    (while (re-search-forward "[\\\"]" nil t)
+      (forward-char -1)
+      (insert "\\")
+      (forward-char 1))
+    (buffer-string)))
+
+(defun imap-login-auth (buffer)
+  "Login to server using the LOGIN command."
+  (message "imap: Plaintext authentication...")
+  (imap-interactive-login buffer
+                         (lambda (user passwd)
+                           (imap-ok-p (imap-send-command-wait
+                                       (concat "LOGIN \""
+                                               (imap-quote-specials user)
+                                               "\" \""
+                                               (imap-quote-specials passwd)
+                                               "\""))))))
+
+(defun imap-anonymous-p (buffer)
+  t)
+
+(defun imap-anonymous-auth (buffer)
+  (message "imap: Logging in anonymously...")
+  (with-current-buffer buffer
+    (imap-ok-p (imap-send-command-wait
+               (concat "LOGIN anonymous \"" (concat (user-login-name) "@"
+                                                    (system-name)) "\"")))))
+
+;;; Compiler directives.
+
+(defvar imap-sasl-client)
+(defvar imap-sasl-step)
+
+(defun imap-sasl-make-mechanisms (buffer)
+  (let ((mecs '()))
+    (mapc (lambda (sym)
+           (let ((name (symbol-name sym)))
+             (if (and (> (length name) 5)
+                      (string-equal "AUTH=" (substring name 0 5 )))
+                 (setq mecs (cons (substring name 5) mecs)))))
+         (imap-capability nil buffer))
+    mecs))
+
+(declare-function sasl-find-mechanism "sasl" (mechanism))
+(declare-function sasl-mechanism-name "sasl" (mechanism))
+(declare-function sasl-make-client    "sasl" (mechanism name service server))
+(declare-function sasl-next-step      "sasl" (client step))
+(declare-function sasl-step-data      "sasl" (step))
+(declare-function sasl-step-set-data  "sasl" (step data))
+
+(defun imap-sasl-auth-p (buffer)
+  (and (condition-case ()
+          (require 'sasl)
+        (error nil))
+       (sasl-find-mechanism (imap-sasl-make-mechanisms buffer))))
+
+(defun imap-sasl-auth (buffer)
+  "Login to server using the SASL method."
+  (message "imap: Authenticating using SASL...")
+  (with-current-buffer buffer
+    (make-local-variable 'imap-username)
+    (make-local-variable 'imap-sasl-client)
+    (make-local-variable 'imap-sasl-step)
+    (let ((mechanism (sasl-find-mechanism (imap-sasl-make-mechanisms buffer)))
+         logged user)
+      (while (not logged)
+       (setq user (or imap-username
+                      (read-from-minibuffer
+                       (concat "IMAP username for " imap-server " using SASL "
+                               (sasl-mechanism-name mechanism) ": ")
+                       (or user imap-default-user))))
+       (when user
+         (setq imap-sasl-client (sasl-make-client mechanism user "imap2" imap-server)
+               imap-sasl-step (sasl-next-step imap-sasl-client nil))
+         (let ((tag (imap-send-command
+                     (if (sasl-step-data imap-sasl-step)
+                         (format "AUTHENTICATE %s %s"
+                                 (sasl-mechanism-name mechanism)
+                                 (sasl-step-data imap-sasl-step))
+                       (format "AUTHENTICATE %s" (sasl-mechanism-name mechanism)))
+                     buffer)))
+           (while (eq (imap-wait-for-tag tag) 'INCOMPLETE)
+             (sasl-step-set-data imap-sasl-step (base64-decode-string imap-continuation))
+             (setq imap-continuation nil
+                   imap-sasl-step (sasl-next-step imap-sasl-client imap-sasl-step))
+             (imap-send-command-1 (if (sasl-step-data imap-sasl-step)
+                                      (base64-encode-string (sasl-step-data imap-sasl-step) t)
+                                    "")))
+           (if (imap-ok-p (imap-wait-for-tag tag))
+               (setq imap-username user
+                     logged t)
+             (message "Login failed...")
+             (sit-for 1)))))
+      logged)))
+
+(defun imap-digest-md5-p (buffer)
+  (and (imap-capability 'AUTH=DIGEST-MD5 buffer)
+       (condition-case ()
+          (require 'digest-md5)
+        (error nil))))
+
+(defun imap-digest-md5-auth (buffer)
+  "Login to server using the AUTH DIGEST-MD5 method."
+  (message "imap: Authenticating using DIGEST-MD5...")
+  (imap-interactive-login
+   buffer
+   (lambda (user passwd)
+     (let ((tag
+           (imap-send-command
+            (list
+             "AUTHENTICATE DIGEST-MD5"
+             (lambda (challenge)
+               (digest-md5-parse-digest-challenge
+                (base64-decode-string challenge))
+               (let* ((digest-uri
+                       (digest-md5-digest-uri
+                        "imap" (digest-md5-challenge 'realm)))
+                      (response
+                       (digest-md5-digest-response
+                        user passwd digest-uri)))
+                 (base64-encode-string response 'no-line-break))))
+            )))
+       (if (not (eq (imap-wait-for-tag tag) 'INCOMPLETE))
+          nil
+        (setq imap-continuation nil)
+        (imap-send-command-1 "")
+        (imap-ok-p (imap-wait-for-tag tag)))))))
+
+;; Server functions:
+
+(defun imap-open-1 (buffer)
+  (with-current-buffer buffer
+    (erase-buffer)
+    (setq imap-current-mailbox nil
+         imap-current-message nil
+         imap-state 'initial
+         imap-process (condition-case ()
+                          (funcall (nth 2 (assq imap-stream
+                                                imap-stream-alist))
+                                   "imap" buffer imap-server imap-port)
+                        ((error quit) nil)))
+    (when imap-process
+      (set-process-filter imap-process 'imap-arrival-filter)
+      (set-process-sentinel imap-process 'imap-sentinel)
+      (while (and (eq imap-state 'initial)
+                 (memq (process-status imap-process) '(open run)))
+       (message "Waiting for response from %s..." imap-server)
+       (accept-process-output imap-process 1))
+      (message "Waiting for response from %s...done" imap-server)
+      (and (memq (process-status imap-process) '(open run))
+          imap-process))))
+
+(defun imap-open (server &optional port stream auth buffer)
+  "Open an IMAP connection to host SERVER at PORT returning a buffer.
+If PORT is unspecified, a default value is used (143 except
+for SSL which use 993).
+STREAM indicates the stream to use, see `imap-streams' for available
+streams.  If nil, it choices the best stream the server is capable of.
+AUTH indicates authenticator to use, see `imap-authenticators' for
+available authenticators.  If nil, it choices the best stream the
+server is capable of.
+BUFFER can be a buffer or a name of a buffer, which is created if
+necessary.  If nil, the buffer name is generated."
+  (setq buffer (or buffer (format " *imap* %s:%d" server (or port 0))))
+  (with-current-buffer (get-buffer-create buffer)
+    (if (imap-opened buffer)
+       (imap-close buffer))
+    (mapc 'make-local-variable imap-local-variables)
+    (imap-disable-multibyte)
+    (buffer-disable-undo)
+    (setq imap-server (or server imap-server))
+    (setq imap-port (or port imap-port))
+    (setq imap-auth (or auth imap-auth))
+    (setq imap-stream (or stream imap-stream))
+    (message "imap: Connecting to %s..." imap-server)
+    (if (null (let ((imap-stream (or imap-stream imap-default-stream)))
+               (imap-open-1 buffer)))
+       (progn
+         (message "imap: Connecting to %s...failed" imap-server)
+         nil)
+      (when (null imap-stream)
+       ;; Need to choose stream.
+       (let ((streams imap-streams))
+         (while (setq stream (pop streams))
+           ;; OK to use this stream?
+           (when (funcall (nth 1 (assq stream imap-stream-alist)) buffer)
+             ;; Stream changed?
+             (if (not (eq imap-default-stream stream))
+                 (with-current-buffer (get-buffer-create
+                                       (generate-new-buffer-name " *temp*"))
+                   (mapc 'make-local-variable imap-local-variables)
+                   (imap-disable-multibyte)
+                   (buffer-disable-undo)
+                   (setq imap-server (or server imap-server))
+                   (setq imap-port (or port imap-port))
+                   (setq imap-auth (or auth imap-auth))
+                   (message "imap: Reconnecting with stream `%s'..." stream)
+                   (if (null (let ((imap-stream stream))
+                               (imap-open-1 (current-buffer))))
+                       (progn
+                         (kill-buffer (current-buffer))
+                         (message
+                          "imap: Reconnecting with stream `%s'...failed"
+                          stream))
+                     ;; We're done, kill the first connection
+                     (imap-close buffer)
+                     (let ((name (if (stringp buffer)
+                                     buffer
+                                   (buffer-name buffer))))
+                       (kill-buffer buffer)
+                       (rename-buffer name)
+                       ;; set the passed buffer to the current one,
+                       ;; so that (imap-opened buffer) later will work
+                       (setq buffer (current-buffer)))
+                     (message "imap: Reconnecting with stream `%s'...done"
+                              stream)
+                     (setq imap-stream stream)
+                     (setq imap-capability nil)
+                     (setq streams nil)))
+               ;; We're done
+               (message "imap: Connecting to %s...done" imap-server)
+               (setq imap-stream stream)
+               (setq imap-capability nil)
+               (setq streams nil))))))
+      (when (imap-opened buffer)
+       (setq imap-mailbox-data (make-vector imap-mailbox-prime 0)))
+      ;; (debug "opened+state+auth+buffer" (imap-opened buffer) imap-state imap-auth buffer)
+      (when imap-stream
+       buffer))))
+
+(defcustom imap-ping-server t
+  "If non-nil, check if IMAP is open.
+See the function `imap-ping-server'."
+  :version "23.1" ;; No Gnus
+  :group 'imap
+  :type 'boolean)
+
+(defun imap-opened (&optional buffer)
+  "Return non-nil if connection to imap 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 imap-process
+             (memq (process-status imap-process) '(open run))
+             (if imap-ping-server
+                 (imap-ping-server)
+               t)))))
+
+(defun imap-ping-server (&optional buffer)
+  "Ping the IMAP server in BUFFER with a \"NOOP\" command.
+Return non-nil if the server responds, and nil if it does not
+respond.  If BUFFER is nil, the current buffer is used."
+  (condition-case ()
+      (imap-ok-p (imap-send-command-wait "NOOP" buffer))
+    (error nil)))
+
+(defun imap-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 imap-state 'nonauth))
+       (or (eq imap-state 'auth)
+           (eq imap-state 'selected)
+           (eq imap-state 'examine))
+      (make-local-variable 'imap-username)
+      (make-local-variable 'imap-password)
+      (make-local-variable 'imap-last-authenticator)
+      (when user (setq imap-username user))
+      (when passwd (setq imap-password passwd))
+      (if imap-auth
+         (and (setq imap-last-authenticator 
+                    (assq imap-auth imap-authenticator-alist))
+              (funcall (nth 2 imap-last-authenticator) (current-buffer))
+              (setq imap-state 'auth))
+       ;; Choose authenticator.
+       (let ((auths imap-authenticators)
+             auth)
+         (while (setq auth (pop auths))
+           ;; OK to use authenticator?
+           (setq imap-last-authenticator
+                 (assq auth imap-authenticator-alist))
+           (when (funcall (nth 1 imap-last-authenticator) (current-buffer))
+             (message "imap: Authenticating to `%s' using `%s'..."
+                      imap-server auth)
+             (setq imap-auth auth)
+             (if (funcall (nth 2 imap-last-authenticator) (current-buffer))
+                 (progn
+                   (message "imap: Authenticating to `%s' using `%s'...done"
+                            imap-server auth)
+                   ;; set imap-state correctly on successful auth attempt
+                   (setq imap-state 'auth)
+                   ;; stop iterating through the authenticator list
+                   (setq auths nil))
+               (message "imap: Authenticating to `%s' using `%s'...failed"
+                        imap-server auth)))))
+       imap-state))))
+
+(defun imap-close (&optional buffer)
+  "Close connection to server in BUFFER.
+If BUFFER is nil, the current buffer is used."
+  (with-current-buffer (or buffer (current-buffer))
+    (when (imap-opened)
+      (condition-case nil
+         (imap-logout-wait)
+       (quit nil)))
+    (when (and imap-process
+              (memq (process-status imap-process) '(open run)))
+      (delete-process imap-process))
+    (setq imap-current-mailbox nil
+         imap-current-message nil
+         imap-process nil)
+    (erase-buffer)
+    t))
+
+(defun imap-capability (&optional identifier buffer)
+  "Return a list of identifiers which server in BUFFER support.
+If IDENTIFIER, return non-nil if it's among the servers capabilities.
+If BUFFER is nil, the current buffer is assumed."
+  (with-current-buffer (or buffer (current-buffer))
+    (unless imap-capability
+      (unless (imap-ok-p (imap-send-command-wait "CAPABILITY"))
+       (setq imap-capability '(IMAP2))))
+    (if identifier
+       (memq (intern (upcase (symbol-name identifier))) imap-capability)
+      imap-capability)))
+
+(defun imap-id (&optional list-of-values buffer)
+  "Identify client to server in BUFFER, and return server identity.
+LIST-OF-VALUES is nil, or a plist with identifier and value
+strings to send to the server to identify the client.
+
+Return a list of identifiers which server in BUFFER support, or
+nil if it doesn't support ID or returns no information.
+
+If BUFFER is nil, the current buffer is assumed."
+  (with-current-buffer (or buffer (current-buffer))
+    (when (and (imap-capability 'ID)
+              (imap-ok-p (imap-send-command-wait
+                          (if (null list-of-values)
+                              "ID NIL"
+                            (concat "ID (" (mapconcat (lambda (el)
+                                                        (concat "\"" el "\""))
+                                                      list-of-values
+                                                      " ") ")")))))
+      imap-id)))
+
+(defun imap-namespace (&optional buffer)
+  "Return a namespace hierarchy at server in BUFFER.
+If BUFFER is nil, the current buffer is assumed."
+  (with-current-buffer (or buffer (current-buffer))
+    (unless imap-namespace
+      (when (imap-capability 'NAMESPACE)
+       (imap-send-command-wait "NAMESPACE")))
+    imap-namespace))
+
+(defun imap-send-command-wait (command &optional buffer)
+  (imap-wait-for-tag (imap-send-command command buffer) buffer))
+
+(defun imap-logout (&optional buffer)
+  (or buffer (setq buffer (current-buffer)))
+  (if imap-logout-timeout
+      (with-timeout (imap-logout-timeout
+                    (condition-case nil
+                        (with-current-buffer buffer
+                          (delete-process imap-process))
+                      (error)))
+       (imap-send-command "LOGOUT" buffer))
+    (imap-send-command "LOGOUT" buffer)))
+
+(defun imap-logout-wait (&optional buffer)
+  (or buffer (setq buffer (current-buffer)))
+  (if imap-logout-timeout
+      (with-timeout (imap-logout-timeout
+                    (condition-case nil
+                        (with-current-buffer buffer
+                          (delete-process imap-process))
+                      (error)))
+       (imap-send-command-wait "LOGOUT" buffer))
+    (imap-send-command-wait "LOGOUT" buffer)))
+
+\f
+;; Mailbox functions:
+
+(defun imap-mailbox-put (propname value &optional mailbox buffer)
+  (with-current-buffer (or buffer (current-buffer))
+    (if imap-mailbox-data
+       (put (intern (or mailbox imap-current-mailbox) imap-mailbox-data)
+            propname value)
+      (error "Imap-mailbox-data is nil, prop %s value %s mailbox %s buffer %s"
+            propname value mailbox (current-buffer)))
+    t))
+
+(defsubst imap-mailbox-get-1 (propname &optional mailbox)
+  (get (intern-soft (or mailbox imap-current-mailbox) imap-mailbox-data)
+       propname))
+
+(defun imap-mailbox-get (propname &optional mailbox buffer)
+  (let ((mailbox (imap-utf7-encode mailbox)))
+    (with-current-buffer (or buffer (current-buffer))
+      (imap-mailbox-get-1 propname (or mailbox imap-current-mailbox)))))
+
+(defun imap-mailbox-map-1 (func &optional mailbox-decoder buffer)
+  (with-current-buffer (or buffer (current-buffer))
+    (let (result)
+      (mapatoms
+       (lambda (s)
+        (push (funcall func (if mailbox-decoder
+                                (funcall mailbox-decoder (symbol-name s))
+                              (symbol-name s))) result))
+       imap-mailbox-data)
+      result)))
+
+(defun imap-mailbox-map (func &optional buffer)
+  "Map a function across each mailbox in `imap-mailbox-data', returning a list.
+Function should take a mailbox name (a string) as
+the only argument."
+  (imap-mailbox-map-1 func 'imap-utf7-decode buffer))
+
+(defun imap-current-mailbox (&optional buffer)
+  (with-current-buffer (or buffer (current-buffer))
+    (imap-utf7-decode imap-current-mailbox)))
+
+(defun imap-current-mailbox-p-1 (mailbox &optional examine)
+  (and (string= mailbox imap-current-mailbox)
+       (or (and examine
+               (eq imap-state 'examine))
+          (and (not examine)
+               (eq imap-state 'selected)))))
+
+(defun imap-current-mailbox-p (mailbox &optional examine buffer)
+  (with-current-buffer (or buffer (current-buffer))
+    (imap-current-mailbox-p-1 (imap-utf7-encode mailbox) examine)))
+
+(defun imap-mailbox-select-1 (mailbox &optional examine)
+  "Select MAILBOX on server in BUFFER.
+If EXAMINE is non-nil, do a read-only select."
+  (if (imap-current-mailbox-p-1 mailbox examine)
+      imap-current-mailbox
+    (setq imap-current-mailbox mailbox)
+    (if (imap-ok-p (imap-send-command-wait
+                   (concat (if examine "EXAMINE" "SELECT") " \""
+                           mailbox "\"")))
+       (progn
+         (setq imap-message-data (make-vector imap-message-prime 0)
+               imap-state (if examine 'examine 'selected))
+         imap-current-mailbox)
+      ;; Failed SELECT/EXAMINE unselects current mailbox
+      (setq imap-current-mailbox nil))))
+
+(defun imap-mailbox-select (mailbox &optional examine buffer)
+  (with-current-buffer (or buffer (current-buffer))
+    (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 'examine)))
+
+(defun imap-mailbox-examine (mailbox &optional buffer)
+  "Examine MAILBOX on server in BUFFER."
+  (imap-mailbox-select mailbox 'examine buffer))
+
+(defun imap-mailbox-unselect (&optional buffer)
+  "Close current folder in BUFFER, without expunging articles."
+  (with-current-buffer (or buffer (current-buffer))
+    (when (or (eq imap-state 'auth)
+             (and (imap-capability 'UNSELECT)
+                  (imap-ok-p (imap-send-command-wait "UNSELECT")))
+             (and (imap-ok-p
+                   (imap-send-command-wait (concat "EXAMINE \""
+                                                   imap-current-mailbox
+                                                   "\"")))
+                  (imap-ok-p (imap-send-command-wait "CLOSE"))))
+      (setq imap-current-mailbox nil
+           imap-message-data nil
+           imap-state 'auth)
+      t)))
+
+(defun imap-mailbox-expunge (&optional asynch buffer)
+  "Expunge articles in current folder in BUFFER.
+If ASYNCH, do not wait for successful 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)))
+      (if asynch
+         (imap-send-command "EXPUNGE")
+      (imap-ok-p (imap-send-command-wait "EXPUNGE"))))))
+
+(defun imap-mailbox-close (&optional asynch buffer)
+  "Expunge articles and close current folder in BUFFER.
+If ASYNCH, do not wait for successful completion of the command.
+If BUFFER is nil the current buffer is assumed."
+  (with-current-buffer (or buffer (current-buffer))
+    (when imap-current-mailbox
+      (if asynch
+         (imap-add-callback (imap-send-command "CLOSE")
+                            `(lambda (tag status)
+                               (message "IMAP mailbox `%s' closed... %s"
+                                        imap-current-mailbox status)
+                               (when (eq ,imap-current-mailbox
+                                         imap-current-mailbox)
+                                 ;; Don't wipe out data if another mailbox
+                                 ;; was selected...
+                                 (setq imap-current-mailbox nil
+                                       imap-message-data nil
+                                       imap-state 'auth))))
+       (when (imap-ok-p (imap-send-command-wait "CLOSE"))
+         (setq imap-current-mailbox nil
+               imap-message-data nil
+               imap-state 'auth)))
+      t)))
+
+(defun imap-mailbox-create-1 (mailbox)
+  (imap-ok-p (imap-send-command-wait (list "CREATE \"" mailbox "\""))))
+
+(defun imap-mailbox-create (mailbox &optional buffer)
+  "Create MAILBOX on server in BUFFER.
+If BUFFER is nil the current buffer is assumed."
+  (with-current-buffer (or buffer (current-buffer))
+    (imap-mailbox-create-1 (imap-utf7-encode mailbox))))
+
+(defun imap-mailbox-delete (mailbox &optional buffer)
+  "Delete MAILBOX on server in BUFFER.
+If BUFFER is nil the current buffer is assumed."
+  (let ((mailbox (imap-utf7-encode mailbox)))
+    (with-current-buffer (or buffer (current-buffer))
+      (imap-ok-p
+       (imap-send-command-wait (list "DELETE \"" mailbox "\""))))))
+
+(defun imap-mailbox-rename (oldname newname &optional buffer)
+  "Rename mailbox OLDNAME to NEWNAME on server in BUFFER.
+If BUFFER is nil the current buffer is assumed."
+  (let ((oldname (imap-utf7-encode oldname))
+       (newname (imap-utf7-encode newname)))
+    (with-current-buffer (or buffer (current-buffer))
+      (imap-ok-p
+       (imap-send-command-wait (list "RENAME \"" oldname "\" "
+                                    "\"" newname "\""))))))
+
+(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
+implementation-specific string that has to be passed to lsub command."
+  (with-current-buffer (or buffer (current-buffer))
+    ;; Make sure we know the hierarchy separator for root's hierarchy
+    (when (and add-delimiter (null (imap-mailbox-get-1 'delimiter root)))
+      (imap-send-command-wait (concat "LIST \"" reference "\" \""
+                                     (imap-utf7-encode root) "\"")))
+    ;; clear list data (NB not delimiter and other stuff)
+    (imap-mailbox-map-1 (lambda (mailbox)
+                         (imap-mailbox-put 'lsub nil mailbox)))
+    (when (imap-ok-p
+          (imap-send-command-wait
+           (concat "LSUB \"" reference "\" \"" (imap-utf7-encode root)
+                   (and add-delimiter (imap-mailbox-get-1 'delimiter root))
+                   "%\"")))
+      (let (out)
+       (imap-mailbox-map-1 (lambda (mailbox)
+                             (when (imap-mailbox-get-1 'lsub mailbox)
+                               (push (imap-utf7-decode mailbox) out))))
+       (nreverse out)))))
+
+(defun imap-mailbox-list (root &optional reference add-delimiter buffer)
+  "Return a list of mailboxes matching ROOT on server in BUFFER.
+If ADD-DELIMITER is non-nil, a hierarchy delimiter is added to
+root.  REFERENCE is a implementation-specific string that has to be
+passed to list command."
+  (with-current-buffer (or buffer (current-buffer))
+    ;; Make sure we know the hierarchy separator for root's hierarchy
+    (when (and add-delimiter (null (imap-mailbox-get-1 'delimiter root)))
+      (imap-send-command-wait (concat "LIST \"" reference "\" \""
+                                     (imap-utf7-encode root) "\"")))
+    ;; clear list data (NB not delimiter and other stuff)
+    (imap-mailbox-map-1 (lambda (mailbox)
+                         (imap-mailbox-put 'list nil mailbox)))
+    (when (imap-ok-p
+          (imap-send-command-wait
+           (concat "LIST \"" reference "\" \"" (imap-utf7-encode root)
+                   (and add-delimiter (imap-mailbox-get-1 'delimiter root))
+                   "%\"")))
+      (let (out)
+       (imap-mailbox-map-1 (lambda (mailbox)
+                             (when (imap-mailbox-get-1 'list mailbox)
+                               (push (imap-utf7-decode mailbox) out))))
+       (nreverse out)))))
+
+(defun imap-mailbox-subscribe (mailbox &optional buffer)
+  "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-utf7-encode mailbox)
+                                              "\"")))))
+
+(defun imap-mailbox-unsubscribe (mailbox &optional buffer)
+  "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-utf7-encode mailbox)
+                                              "\"")))))
+
+(defun imap-mailbox-status (mailbox items &optional buffer)
+  "Get status items ITEM in MAILBOX from server in BUFFER.
+ITEMS can be a symbol or a list of symbols, valid symbols are one of
+the STATUS data items -- i.e. `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 its value is returned."
+  (with-current-buffer (or buffer (current-buffer))
+    (when (imap-ok-p
+          (imap-send-command-wait (list "STATUS \""
+                                        (imap-utf7-encode mailbox)
+                                        "\" "
+                                        (upcase
+                                         (format "%s"
+                                                 (if (listp items)
+                                                     items
+                                                   (list items)))))))
+      (if (listp items)
+         (mapcar (lambda (item)
+                   (imap-mailbox-get item mailbox))
+                 items)
+       (imap-mailbox-get items mailbox)))))
+
+(defun imap-mailbox-status-asynch (mailbox items &optional buffer)
+  "Send status item request ITEM on MAILBOX to server in BUFFER.
+ITEMS can be a symbol or a list of symbols, valid symbols are one of
+the STATUS data items -- i.e. 'messages, 'recent, 'uidnext, 'uidvalidity
+or 'unseen.  The IMAP command tag is returned."
+  (with-current-buffer (or buffer (current-buffer))
+    (imap-send-command (list "STATUS \""
+                            (imap-utf7-encode mailbox)
+                            "\" "
+                            (upcase
+                             (format "%s"
+                                     (if (listp items)
+                                         items
+                                       (list items))))))))
+
+(defun imap-mailbox-acl-get (&optional mailbox buffer)
+  "Get ACL on MAILBOX from server in BUFFER."
+  (let ((mailbox (imap-utf7-encode mailbox)))
+    (with-current-buffer (or buffer (current-buffer))
+      (when (imap-ok-p
+            (imap-send-command-wait (list "GETACL \""
+                                          (or mailbox imap-current-mailbox)
+                                          "\"")))
+       (imap-mailbox-get-1 'acl (or mailbox imap-current-mailbox))))))
+
+(defun imap-mailbox-acl-set (identifier rights &optional mailbox buffer)
+  "Change/set ACL for IDENTIFIER to RIGHTS in MAILBOX from server in BUFFER."
+  (let ((mailbox (imap-utf7-encode mailbox)))
+    (with-current-buffer (or buffer (current-buffer))
+      (imap-ok-p
+       (imap-send-command-wait (list "SETACL \""
+                                    (or mailbox imap-current-mailbox)
+                                    "\" "
+                                    identifier
+                                    " "
+                                    rights))))))
+
+(defun imap-mailbox-acl-delete (identifier &optional mailbox buffer)
+  "Remove any <identifier,rights> pair for IDENTIFIER in MAILBOX from server in BUFFER."
+  (let ((mailbox (imap-utf7-encode mailbox)))
+    (with-current-buffer (or buffer (current-buffer))
+      (imap-ok-p
+       (imap-send-command-wait (list "DELETEACL \""
+                                    (or mailbox imap-current-mailbox)
+                                    "\" "
+                                    identifier))))))
+
+\f
+;; Message functions:
+
+(defun imap-current-message (&optional buffer)
+  (with-current-buffer (or buffer (current-buffer))
+    imap-current-message))
+
+(defun imap-list-to-message-set (list)
+  (mapconcat (lambda (item)
+              (number-to-string item))
+            (if (listp list)
+                list
+              (list list))
+            ","))
+
+(defun imap-range-to-message-set (range)
+  (mapconcat
+   (lambda (item)
+     (if (consp 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))
+     range)
+   ","))
+
+(defun imap-fetch-asynch (uids props &optional nouidfetch buffer)
+  (with-current-buffer (or buffer (current-buffer))
+    (imap-send-command (format "%sFETCH %s %s" (if nouidfetch "" "UID ")
+                              (if (listp uids)
+                                  (imap-list-to-message-set uids)
+                                uids)
+                              props))))
+
+(defun imap-fetch (uids props &optional receive nouidfetch buffer)
+  "Fetch properties PROPS from message set UIDS from server in BUFFER.
+UIDS can be a string, number or a list of numbers.  If RECEIVE
+is non-nil return these properties."
+  (with-current-buffer (or buffer (current-buffer))
+    (when (imap-ok-p (imap-send-command-wait
+                     (format "%sFETCH %s %s" (if nouidfetch "" "UID ")
+                             (if (listp uids)
+                                 (imap-list-to-message-set uids)
+                               uids)
+                             props)))
+      (if (or (null receive) (stringp uids))
+         t
+       (if (listp uids)
+           (mapcar (lambda (uid)
+                     (if (listp receive)
+                         (mapcar (lambda (prop)
+                                   (imap-message-get uid prop))
+                                 receive)
+                       (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
+       (put (intern (number-to-string uid) imap-message-data)
+            propname value)
+      (error "Imap-message-data is nil, uid %s prop %s value %s buffer %s"
+            uid propname value (current-buffer)))
+    t))
+
+(defun imap-message-get (uid propname &optional buffer)
+  (with-current-buffer (or buffer (current-buffer))
+    (get (intern-soft (number-to-string uid) imap-message-data)
+        propname)))
+
+(defun imap-message-map (func propname &optional buffer)
+  "Map a function across each message in `imap-message-data', returning a list."
+  (with-current-buffer (or buffer (current-buffer))
+    (let (result)
+      (mapatoms
+       (lambda (s)
+        (push (funcall func (get s 'UID) (get s propname)) result))
+       imap-message-data)
+      result)))
+
+(defmacro imap-message-envelope-date (uid &optional buffer)
+  `(with-current-buffer (or ,buffer (current-buffer))
+     (elt (imap-message-get ,uid 'ENVELOPE) 0)))
+
+(defmacro imap-message-envelope-subject (uid &optional buffer)
+  `(with-current-buffer (or ,buffer (current-buffer))
+     (elt (imap-message-get ,uid 'ENVELOPE) 1)))
+
+(defmacro imap-message-envelope-from (uid &optional buffer)
+  `(with-current-buffer (or ,buffer (current-buffer))
+     (elt (imap-message-get ,uid 'ENVELOPE) 2)))
+
+(defmacro imap-message-envelope-sender (uid &optional buffer)
+  `(with-current-buffer (or ,buffer (current-buffer))
+     (elt (imap-message-get ,uid 'ENVELOPE) 3)))
+
+(defmacro imap-message-envelope-reply-to (uid &optional buffer)
+  `(with-current-buffer (or ,buffer (current-buffer))
+     (elt (imap-message-get ,uid 'ENVELOPE) 4)))
+
+(defmacro imap-message-envelope-to (uid &optional buffer)
+  `(with-current-buffer (or ,buffer (current-buffer))
+     (elt (imap-message-get ,uid 'ENVELOPE) 5)))
+
+(defmacro imap-message-envelope-cc (uid &optional buffer)
+  `(with-current-buffer (or ,buffer (current-buffer))
+     (elt (imap-message-get ,uid 'ENVELOPE) 6)))
+
+(defmacro imap-message-envelope-bcc (uid &optional buffer)
+  `(with-current-buffer (or ,buffer (current-buffer))
+     (elt (imap-message-get ,uid 'ENVELOPE) 7)))
+
+(defmacro imap-message-envelope-in-reply-to (uid &optional buffer)
+  `(with-current-buffer (or ,buffer (current-buffer))
+     (elt (imap-message-get ,uid 'ENVELOPE) 8)))
+
+(defmacro imap-message-envelope-message-id (uid &optional buffer)
+  `(with-current-buffer (or ,buffer (current-buffer))
+     (elt (imap-message-get ,uid 'ENVELOPE) 9)))
+
+(defmacro imap-message-body (uid &optional buffer)
+  `(with-current-buffer (or ,buffer (current-buffer))
+     (imap-message-get ,uid 'BODY)))
+
+;; FIXME: Should this try to use CHARSET?  -- fx
+(defun imap-search (predicate &optional buffer)
+  (with-current-buffer (or buffer (current-buffer))
+    (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)
+         (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)
+  "Return t if FLAG can be permanently (between IMAP sessions) saved on articles, in MAILBOX on server in BUFFER."
+  (with-current-buffer (or buffer (current-buffer))
+    (or (member "\\*" (imap-mailbox-get 'permanentflags mailbox))
+       (member flag (imap-mailbox-get 'permanentflags mailbox)))))
+
+(defun imap-message-flags-set (articles flags &optional silent buffer)
+  (when (and articles flags)
+    (with-current-buffer (or buffer (current-buffer))
+      (imap-ok-p (imap-send-command-wait
+                 (concat "UID STORE " articles
+                         " FLAGS" (if silent ".SILENT") " (" flags ")"))))))
+
+(defun imap-message-flags-del (articles flags &optional silent buffer)
+  (when (and articles flags)
+    (with-current-buffer (or buffer (current-buffer))
+      (imap-ok-p (imap-send-command-wait
+                 (concat "UID STORE " articles
+                         " -FLAGS" (if silent ".SILENT") " (" flags ")"))))))
+
+(defun imap-message-flags-add (articles flags &optional silent buffer)
+  (when (and articles flags)
+    (with-current-buffer (or buffer (current-buffer))
+      (imap-ok-p (imap-send-command-wait
+                 (concat "UID STORE " articles
+                         " +FLAGS" (if silent ".SILENT") " (" flags ")"))))))
+
+;; Cf. http://thread.gmane.org/gmane.emacs.gnus.general/65317/focus=65343
+;; Signal an error if we'd get an integer overflow.
+;;
+;; FIXME: Identify relevant calls to `string-to-number' and replace them with
+;; `imap-string-to-integer'.
+(defun imap-string-to-integer (string &optional base)
+  (let ((number (string-to-number string base)))
+    (if (> number most-positive-fixnum)
+       (error
+        (format "String %s cannot be converted to a Lisp integer" number))
+      number)))
+
+(defun imap-fetch-safe (uids props &optional receive nouidfetch buffer)
+  "Like `imap-fetch', but DTRT with Exchange 2007 bug.
+However, UIDS here is a cons, where the car is the canonical form
+of the UIDS specification, and the cdr is the one which works with
+Exchange 2007 or, potentially, other buggy servers.
+See `imap-enable-exchange-bug-workaround'."
+  ;; The first time we get here for a given, we'll try the canonical
+  ;; form.  If we get the known error from the buggy server, set the
+  ;; flag buffer-locally (to account for connections to multiple
+  ;; servers), then re-try with the alternative UIDS spec.  We don't
+  ;; unconditionally use the alternative form, since the
+  ;; currently-used alternatives are seriously inefficient with some
+  ;; servers (although they are valid).
+  ;;
+  ;; FIXME:  Maybe it would be cleaner to have a flag to not signal
+  ;; the error (which otherwise gives a message), and test
+  ;; `imap-failed-tags'.  Also, Other IMAP clients use other forms of
+  ;; request which work with Exchange, e.g. Claws does "UID FETCH 1:*
+  ;; (UID)" rather than "FETCH UID 1,*".  Is there a good reason not
+  ;; to do the same?
+  (condition-case data
+      ;; Binding `debug-on-error' allows us to get the error from
+      ;; `imap-parse-response' -- it's normally caught by Emacs around
+      ;; execution of a process filter.
+      (let ((debug-on-error t))
+       (imap-fetch (if imap-enable-exchange-bug-workaround
+                       (cdr uids)
+                     (car uids))
+                   props receive nouidfetch buffer))
+    (error
+     (if (and (not imap-enable-exchange-bug-workaround)
+             ;; This is the Exchange 2007 response.  It may be more
+             ;; robust just to check for a BAD response to the
+             ;; attempted fetch.
+             (string-match "The specified message set is invalid"
+                           (cadr data)))
+        (with-current-buffer (or buffer (current-buffer))
+          (set (make-local-variable 'imap-enable-exchange-bug-workaround)
+               t)
+          (imap-fetch (cdr uids) props receive nouidfetch))
+       (signal (car data) (cdr data))))))
+
+(defun imap-message-copyuid-1 (mailbox)
+  (if (imap-capability 'UIDPLUS)
+      (list (nth 0 (imap-mailbox-get-1 'copyuid mailbox))
+           (string-to-number (nth 2 (imap-mailbox-get-1 'copyuid mailbox))))
+    (let ((old-mailbox imap-current-mailbox)
+         (state imap-state)
+         (imap-message-data (make-vector 2 0)))
+      (when (imap-mailbox-examine-1 mailbox)
+       (prog1
+           (and (imap-fetch-safe '("*" . "*:*") "UID")
+                (list (imap-mailbox-get-1 'uidvalidity mailbox)
+                      (apply 'max (imap-message-map
+                                   (lambda (uid prop) uid) 'UID))))
+         (if old-mailbox
+             (imap-mailbox-select old-mailbox (eq state 'examine))
+           (imap-mailbox-unselect)))))))
+
+(defun imap-message-copyuid (mailbox &optional buffer)
+  (with-current-buffer (or buffer (current-buffer))
+    (imap-message-copyuid-1 (imap-utf7-decode mailbox))))
+
+(defun imap-message-copy (articles mailbox
+                                  &optional dont-create no-copyuid buffer)
+  "Copy ARTICLES to MAILBOX on server in BUFFER.
+ARTICLES is a string message set.  Create mailbox if it doesn't exist,
+unless DONT-CREATE is non-nil.  On success, return a list with
+the UIDVALIDITY of the mailbox the article(s) was copied to as the
+first element.  The rest of list contains the saved articles' UIDs."
+  (when articles
+    (with-current-buffer (or buffer (current-buffer))
+      (let ((mailbox (imap-utf7-encode mailbox)))
+       (if (let ((cmd (concat "UID COPY " articles " \"" mailbox "\""))
+                 (imap-current-target-mailbox mailbox))
+             (if (imap-ok-p (imap-send-command-wait cmd))
+                 t
+               (when (and (not dont-create)
+                          ;; removed because of buggy Oracle server
+                          ;; that doesn't send TRYCREATE tags (which
+                          ;; is a MUST according to specifications):
+                          ;;(imap-mailbox-get-1 'trycreate mailbox)
+                          (imap-mailbox-create-1 mailbox))
+                 (imap-ok-p (imap-send-command-wait cmd)))))
+           (or no-copyuid
+               (imap-message-copyuid-1 mailbox)))))))
+
+;; FIXME: Amalgamate with imap-message-copyuid-1, using an extra arg, since it
+;; shares most of the code?  -- fx
+(defun imap-message-appenduid-1 (mailbox)
+  (if (imap-capability 'UIDPLUS)
+      (imap-mailbox-get-1 'appenduid mailbox)
+    (let ((old-mailbox imap-current-mailbox)
+         (state imap-state)
+         (imap-message-data (make-vector 2 0)))
+      (when (imap-mailbox-examine-1 mailbox)
+       (prog1
+           (and (imap-fetch-safe '("*" . "*:*") "UID")
+                (list (imap-mailbox-get-1 'uidvalidity mailbox)
+                      (apply 'max (imap-message-map
+                                   (lambda (uid prop) uid) 'UID))))
+         (if old-mailbox
+             (imap-mailbox-select old-mailbox (eq state 'examine))
+           (imap-mailbox-unselect)))))))
+
+(defun imap-message-appenduid (mailbox &optional buffer)
+  (with-current-buffer (or buffer (current-buffer))
+    (imap-message-appenduid-1 (imap-utf7-encode mailbox))))
+
+(defun imap-message-append (mailbox article &optional flags date-time buffer)
+  "Append ARTICLE (a buffer) to MAILBOX on server in BUFFER.
+FLAGS and DATE-TIME is currently not used.  Return a cons holding
+uidvalidity of MAILBOX and UID the newly created article got, or nil
+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
+              (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)
+      (if (stringp (car body))
+         (cond ((and (string= (upcase (car body)) "TEXT")
+                     (numberp (nth 7 body)))
+                (nth 7 body))
+               ((and (string= (upcase (car body)) "MESSAGE")
+                     (numberp (nth 9 body)))
+                (nth 9 body))
+               (t 0))
+       (apply '+ (mapcar 'imap-body-lines body)))
+    0))
+
+(defun imap-envelope-from (from)
+  "Return a from string line."
+  (and from
+       (concat (aref from 0)
+              (if (aref from 0) " <")
+              (aref from 2)
+              "@"
+              (aref from 3)
+              (if (aref from 0) ">"))))
+
+\f
+;; Internal functions.
+
+(defun imap-add-callback (tag func)
+  (setq imap-callbacks (append (list (cons tag func)) imap-callbacks)))
+
+(defun imap-send-command-1 (cmdstr)
+  (setq cmdstr (concat cmdstr imap-client-eol))
+  (and imap-log
+       (with-current-buffer (get-buffer-create imap-log-buffer)
+        (imap-disable-multibyte)
+        (buffer-disable-undo)
+        (goto-char (point-max))
+        (insert cmdstr)))
+  (process-send-string imap-process cmdstr))
+
+(defun imap-send-command (command &optional buffer)
+  (with-current-buffer (or buffer (current-buffer))
+    (if (not (listp command)) (setq command (list command)))
+    (let ((tag (setq imap-tag (1+ imap-tag)))
+         cmd cmdstr)
+      (setq cmdstr (concat (number-to-string imap-tag) " "))
+      (while (setq cmd (pop command))
+       (cond ((stringp cmd)
+              (setq cmdstr (concat cmdstr cmd)))
+             ((bufferp cmd)
+              (let ((eol imap-client-eol)
+                    (calcfirst imap-calculate-literal-size-first)
+                    size)
+                (with-current-buffer cmd
+                  (if calcfirst
+                      (setq size (buffer-size)))
+                  (when (not (equal eol "\r\n"))
+                    ;; XXX modifies buffer!
+                    (goto-char (point-min))
+                    (while (search-forward "\r\n" nil t)
+                      (replace-match eol)))
+                  (if (not calcfirst)
+                      (setq size (buffer-size))))
+                (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
+                      (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-buffer)
+                                 (imap-disable-multibyte)
+                                 (buffer-disable-undo)
+                                 (goto-char (point-max))
+                                 (insert-buffer-substring cmd)))
+                          (process-send-region process (point-min)
+                                               (point-max)))
+                        (process-send-string process imap-client-eol))))
+                (setq imap-continuation nil)))
+             ((functionp cmd)
+              (imap-send-command-1 cmdstr)
+              (setq cmdstr nil)
+              (unwind-protect
+                  (setq command
+                        (if (not (eq (imap-wait-for-tag tag) 'INCOMPLETE))
+                            nil ;; abort command if no cont-req
+                          (cons (funcall cmd imap-continuation)
+                                command)))
+                (setq imap-continuation nil)))
+             (t
+              (error "Unknown command type"))))
+      (if cmdstr
+         (imap-send-command-1 cmdstr))
+      tag)))
+
+(defun imap-wait-for-tag (tag &optional buffer)
+  (with-current-buffer (or buffer (current-buffer))
+    (let (imap-have-messaged)
+      (while (and (null imap-continuation)
+                 (memq (process-status imap-process) '(open run))
+                 (< imap-reached-tag tag))
+       (let ((len (/ (buffer-size) 1024))
+             message-log-max)
+         (unless (< len 10)
+           (setq imap-have-messaged t)
+           (message "imap read: %dk" len))
+         (accept-process-output imap-process
+                                (truncate imap-read-timeout)
+                                (truncate (* (- imap-read-timeout
+                                                (truncate imap-read-timeout))
+                                             1000)))))
+      ;; A process can die _before_ we have processed everything it
+      ;; has to say.  Moreover, this can happen in between the call to
+      ;; accept-process-output and the call to process-status in an
+      ;; iteration of the loop above.
+      (when (and (null imap-continuation)
+                (< imap-reached-tag tag))
+       (accept-process-output imap-process 0 0))
+      (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))
+
+(defun imap-find-next-line ()
+  "Return point at end of current line, taking into account literals.
+Return nil if no complete line has arrived."
+  (when (re-search-forward (concat imap-server-eol "\\|{\\([0-9]+\\)}"
+                                  imap-server-eol)
+                          nil t)
+    (if (match-string 1)
+       (if (< (point-max) (+ (point) (string-to-number (match-string 1))))
+           nil
+         (goto-char (+ (point) (string-to-number (match-string 1))))
+         (imap-find-next-line))
+      (point))))
+
+(defun imap-arrival-filter (proc string)
+  "IMAP process filter."
+  ;; Sometimes, we are called even though the process has died.
+  ;; Better abstain from doing stuff in that case.
+  (when (buffer-name (process-buffer proc))
+    (with-current-buffer (process-buffer proc)
+      (goto-char (point-max))
+      (insert string)
+      (and imap-log
+          (with-current-buffer (get-buffer-create imap-log-buffer)
+            (imap-disable-multibyte)
+            (buffer-disable-undo)
+            (goto-char (point-max))
+            (insert string)))
+      (let (end)
+       (goto-char (point-min))
+       (while (setq end (imap-find-next-line))
+         (save-restriction
+           (narrow-to-region (point-min) end)
+           (delete-backward-char (length imap-server-eol))
+           (goto-char (point-min))
+           (unwind-protect
+               (cond ((eq imap-state 'initial)
+                      (imap-parse-greeting))
+                     ((or (eq imap-state 'auth)
+                          (eq imap-state 'nonauth)
+                          (eq imap-state 'selected)
+                          (eq imap-state 'examine))
+                      (imap-parse-response))
+                     (t
+                      (message "Unknown state %s in arrival filter"
+                               imap-state)))
+             (delete-region (point-min) (point-max)))))))))
+
+\f
+;; Imap parser.
+
+(defsubst imap-forward ()
+  (or (eobp) (forward-char)))
+
+;;   number          = 1*DIGIT
+;;                       ; Unsigned 32-bit integer
+;;                       ; (0 <= n < 4,294,967,296)
+
+(defsubst imap-parse-number ()
+  (when (looking-at "[0-9]+")
+    (prog1
+       (string-to-number (match-string 0))
+      (goto-char (match-end 0)))))
+
+;;   literal         = "{" number "}" CRLF *CHAR8
+;;                       ; Number represents the number of CHAR8s
+
+(defsubst imap-parse-literal ()
+  (when (looking-at "{\\([0-9]+\\)}\r\n")
+    (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))))))
+
+;;   string          = quoted / literal
+;;
+;;   quoted          = DQUOTE *QUOTED-CHAR DQUOTE
+;;
+;;   QUOTED-CHAR     = <any TEXT-CHAR except quoted-specials> /
+;;                     "\" quoted-specials
+;;
+;;   quoted-specials = DQUOTE / "\"
+;;
+;;   TEXT-CHAR       = <any CHAR except CR and LF>
+
+(defsubst imap-parse-string ()
+  (cond ((eq (char-after) ?\")
+        (forward-char 1)
+        (let ((p (point)) (name ""))
+          (skip-chars-forward "^\"\\\\")
+          (setq name (buffer-substring p (point)))
+          (while (eq (char-after) ?\\)
+            (setq p (1+ (point)))
+            (forward-char 2)
+            (skip-chars-forward "^\"\\\\")
+            (setq name (concat name (buffer-substring p (point)))))
+          (forward-char 1)
+          name))
+       ((eq (char-after) ?{)
+        (imap-parse-literal))))
+
+;;   nil             = "NIL"
+
+(defsubst imap-parse-nil ()
+  (if (looking-at "NIL")
+      (goto-char (match-end 0))))
+
+;;   nstring         = string / nil
+
+(defsubst imap-parse-nstring ()
+  (or (imap-parse-string)
+      (and (imap-parse-nil)
+          nil)))
+
+;;   astring         = atom / string
+;;
+;;   atom            = 1*ATOM-CHAR
+;;
+;;   ATOM-CHAR       = <any CHAR except atom-specials>
+;;
+;;   atom-specials   = "(" / ")" / "{" / SP / CTL / list-wildcards /
+;;                     quoted-specials
+;;
+;;   list-wildcards  = "%" / "*"
+;;
+;;   quoted-specials = DQUOTE / "\"
+
+(defsubst imap-parse-astring ()
+  (or (imap-parse-string)
+      (buffer-substring (point)
+                       (if (re-search-forward "[(){ \r\n%*\"\\]" nil t)
+                           (goto-char (1- (match-end 0)))
+                         (end-of-line)
+                         (point)))))
+
+;;   address         = "(" addr-name SP addr-adl SP addr-mailbox SP
+;;                      addr-host ")"
+;;
+;;   addr-adl        = nstring
+;;                       ; Holds route from [RFC-822] route-addr if
+;;                       ; non-nil
+;;
+;;   addr-host       = nstring
+;;                       ; 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
+;;                       ; [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]
+;;                       ; mailbox after removing [RFC-822] quoting
+;;
+
+(defsubst imap-parse-address ()
+  (let (address)
+    (when (eq (char-after) ?\()
+      (imap-forward)
+      (setq address (vector (prog1 (imap-parse-nstring)
+                             (imap-forward))
+                           (prog1 (imap-parse-nstring)
+                             (imap-forward))
+                           (prog1 (imap-parse-nstring)
+                             (imap-forward))
+                           (imap-parse-nstring)))
+      (when (eq (char-after) ?\))
+       (imap-forward)
+       address))))
+
+;;   address-list    = "(" 1*address ")" / nil
+;;
+;;   nil             = "NIL"
+
+(defsubst imap-parse-address-list ()
+  (if (eq (char-after) ?\()
+      (let (address addresses)
+       (imap-forward)
+       (while (and (not (eq (char-after) ?\)))
+                   ;; next line for MS Exchange bug
+                   (progn (and (eq (char-after) ? ) (imap-forward)) t)
+                   (setq address (imap-parse-address)))
+         (setq addresses (cons address addresses)))
+       (when (eq (char-after) ?\))
+         (imap-forward)
+         (nreverse addresses)))
+    ;; With assert, the code might not be eval'd.
+    ;; (assert (imap-parse-nil) t "In imap-parse-address-list")
+    (imap-parse-nil)))
+
+;;   mailbox         = "INBOX" / astring
+;;                       ; INBOX is case-insensitive.  All case variants of
+;;                       ; INBOX (e.g. "iNbOx") MUST be interpreted as INBOX
+;;                       ; not as an astring.  An astring which consists of
+;;                       ; the case-insensitive sequence "I" "N" "B" "O" "X"
+;;                       ; is considered to be INBOX and not an astring.
+;;                       ;  Refer to section 5.1 for further
+;;                       ; semantic details of mailbox names.
+
+(defsubst imap-parse-mailbox ()
+  (let ((mailbox (imap-parse-astring)))
+    (if (string-equal "INBOX" (upcase mailbox))
+       "INBOX"
+      mailbox)))
+
+;;   greeting        = "*" SP (resp-cond-auth / resp-cond-bye) CRLF
+;;
+;;   resp-cond-auth  = ("OK" / "PREAUTH") SP resp-text
+;;                       ; Authentication condition
+;;
+;;   resp-cond-bye   = "BYE" SP resp-text
+
+(defun imap-parse-greeting ()
+  "Parse an IMAP greeting."
+  (cond ((looking-at "\\* OK ")
+        (setq imap-state 'nonauth))
+       ((looking-at "\\* PREAUTH ")
+        (setq imap-state 'auth))
+       ((looking-at "\\* BYE ")
+        (setq imap-state 'closed))))
+
+;;   response        = *(continue-req / response-data) response-done
+;;
+;;   continue-req    = "+" SP (resp-text / base64) CRLF
+;;
+;;   response-data   = "*" SP (resp-cond-state / resp-cond-bye /
+;;                     mailbox-data / message-data / capability-data) CRLF
+;;
+;;   response-done   = response-tagged / response-fatal
+;;
+;;   response-fatal  = "*" SP resp-cond-bye CRLF
+;;                       ; Server closes connection immediately
+;;
+;;   response-tagged = tag SP resp-cond-state CRLF
+;;
+;;   resp-cond-state = ("OK" / "NO" / "BAD") SP resp-text
+;;                       ; Status condition
+;;
+;;   resp-cond-bye   = "BYE" SP resp-text
+;;
+;;   mailbox-data    =  "FLAGS" SP flag-list /
+;;                     "LIST" SP mailbox-list /
+;;                      "LSUB" SP mailbox-list /
+;;                     "SEARCH" *(SP nz-number) /
+;;                      "STATUS" SP mailbox SP "("
+;;                           [status-att SP number *(SP status-att SP number)] ")" /
+;;                      number SP "EXISTS" /
+;;                     number SP "RECENT"
+;;
+;;   message-data    = nz-number SP ("EXPUNGE" / ("FETCH" SP msg-att))
+;;
+;;   capability-data = "CAPABILITY" *(SP capability) SP "IMAP4rev1"
+;;                     *(SP capability)
+;;                       ; IMAP4rev1 servers which offer RFC 1730
+;;                       ; compatibility MUST list "IMAP4" as the first
+;;                       ; capability.
+
+(defun imap-parse-response ()
+  "Parse a IMAP command response."
+  (let (token)
+    (case (setq token (read (current-buffer)))
+      (+ (setq imap-continuation
+              (or (buffer-substring (min (point-max) (1+ (point)))
+                                    (point-max))
+                  t)))
+      (* (case (prog1 (setq token (read (current-buffer)))
+                (imap-forward))
+          (OK         (imap-parse-resp-text))
+          (NO         (imap-parse-resp-text))
+          (BAD        (imap-parse-resp-text))
+          (BYE        (imap-parse-resp-text))
+          (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
+                       (read (concat "(" (buffer-substring (point) (point-max)) ")"))))
+          (STATUS     (imap-parse-status))
+          (CAPABILITY (setq imap-capability
+                              (read (concat "(" (upcase (buffer-substring
+                                                         (point) (point-max)))
+                                            ")"))))
+          (ID         (setq imap-id (read (buffer-substring (point)
+                                                            (point-max)))))
+          (ACL        (imap-parse-acl))
+          (t       (case (prog1 (read (current-buffer))
+                           (imap-forward))
+                     (EXISTS  (imap-mailbox-put 'exists token))
+                     (RECENT  (imap-mailbox-put 'recent token))
+                     (EXPUNGE t)
+                     (FETCH   (imap-parse-fetch token))
+                     (t       (message "Garbage: %s" (buffer-string)))))))
+      (t (let (status)
+          (if (not (integerp token))
+              (message "Garbage: %s" (buffer-string))
+            (case (prog1 (setq status (read (current-buffer)))
+                    (imap-forward))
+              (OK  (progn
+                     (setq imap-reached-tag (max imap-reached-tag token))
+                     (imap-parse-resp-text)))
+              (NO  (progn
+                     (setq imap-reached-tag (max imap-reached-tag token))
+                     (save-excursion
+                       (imap-parse-resp-text))
+                     (let (code text)
+                       (when (eq (char-after) ?\[)
+                         (setq code (buffer-substring (point)
+                                                      (search-forward "]")))
+                         (imap-forward))
+                       (setq text (buffer-substring (point) (point-max)))
+                       (push (list token status code text)
+                             imap-failed-tags))))
+              (BAD (progn
+                     (setq imap-reached-tag (max imap-reached-tag token))
+                     (save-excursion
+                       (imap-parse-resp-text))
+                     (let (code text)
+                       (when (eq (char-after) ?\[)
+                         (setq code (buffer-substring (point)
+                                                      (search-forward "]")))
+                         (imap-forward))
+                       (setq text (buffer-substring (point) (point-max)))
+                       (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))))
+            (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
+;;
+;;   text            = 1*TEXT-CHAR
+;;
+;;   TEXT-CHAR       = <any CHAR except CR and LF>
+
+(defun imap-parse-resp-text ()
+  (imap-parse-resp-text-code))
+
+;;   resp-text-code  = "ALERT" /
+;;                     "BADCHARSET [SP "(" astring *(SP astring) ")" ] /
+;;                     "NEWNAME" SP string SP string /
+;;                    "PARSE" /
+;;                     "PERMANENTFLAGS" SP "("
+;;                               [flag-perm *(SP flag-perm)] ")" /
+;;                     "READ-ONLY" /
+;;                    "READ-WRITE" /
+;;                    "TRYCREATE" /
+;;                     "UIDNEXT" SP nz-number /
+;;                    "UIDVALIDITY" SP nz-number /
+;;                     "UNSEEN" SP nz-number /
+;;                     resp-text-atom [SP 1*<any TEXT-CHAR except "]">]
+;;
+;;   resp_code_apnd  = "APPENDUID" SPACE nz_number SPACE uniqueid
+;;
+;;   resp_code_copy  = "COPYUID" SPACE nz_number SPACE set SPACE set
+;;
+;;   set             = sequence-num / (sequence-num ":" sequence-num) /
+;;                        (set "," set)
+;;                          ; Identifies a set of messages.  For message
+;;                          ; sequence numbers, these are consecutive
+;;                          ; numbers from 1 to the number of messages in
+;;                          ; the mailbox
+;;                          ; Comma delimits individual numbers, colon
+;;                          ; 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
+;;                          ; in the mailbox.  For unique identifiers, it is
+;;                          ; the unique identifier of the last message in
+;;                          ; the mailbox.
+;;
+;;   flag-perm       = flag / "\*"
+;;
+;;   flag            = "\Answered" / "\Flagged" / "\Deleted" /
+;;                     "\Seen" / "\Draft" / flag-keyword / flag-extension
+;;                       ; Does not include "\Recent"
+;;
+;;   flag-extension  = "\" atom
+;;                       ; Future expansion.  Client implementations
+;;                       ; MUST accept flag-extension flags.  Server
+;;                       ; implementations MUST NOT generate
+;;                       ; flag-extension flags except as defined by
+;;                       ; future standard or standards-track
+;;                       ; revisions of this specification.
+;;
+;;   flag-keyword    = atom
+;;
+;;   resp-text-atom  = 1*<any ATOM-CHAR except "]">
+
+(defun imap-parse-resp-text-code ()
+  ;; xxx next line for stalker communigate pro 3.3.1 bug
+  (when (looking-at " \\[")
+    (imap-forward))
+  (when (eq (char-after) ?\[)
+    (imap-forward)
+    (cond ((search-forward "PERMANENTFLAGS " nil t)
+          (imap-mailbox-put 'permanentflags (imap-parse-flag-list)))
+         ((search-forward "UIDNEXT \\([0-9]+\\)" nil t)
+          (imap-mailbox-put 'uidnext (match-string 1)))
+         ((search-forward "UNSEEN " nil t)
+          (imap-mailbox-put 'first-unseen (read (current-buffer))))
+         ((looking-at "UIDVALIDITY \\([0-9]+\\)")
+          (imap-mailbox-put 'uidvalidity (match-string 1)))
+         ((search-forward "READ-ONLY" nil t)
+          (imap-mailbox-put 'read-only t))
+         ((search-forward "NEWNAME " nil t)
+          (let (oldname newname)
+            (setq oldname (imap-parse-string))
+            (imap-forward)
+            (setq newname (imap-parse-string))
+            (imap-mailbox-put 'newname newname oldname)))
+         ((search-forward "TRYCREATE" nil t)
+          (imap-mailbox-put 'trycreate t imap-current-target-mailbox))
+         ((looking-at "APPENDUID \\([0-9]+\\) \\([0-9]+\\)")
+          (imap-mailbox-put 'appenduid
+                            (list (match-string 1)
+                                  (string-to-number (match-string 2)))
+                            imap-current-target-mailbox))
+         ((looking-at "COPYUID \\([0-9]+\\) \\([0-9,:]+\\) \\([0-9,:]+\\)")
+          (imap-mailbox-put 'copyuid (list (match-string 1)
+                                           (match-string 2)
+                                           (match-string 3))
+                            imap-current-target-mailbox))
+         ((search-forward "ALERT] " nil t)
+          (message "Imap server %s information: %s" imap-server
+                   (buffer-substring (point) (point-max)))))))
+
+;;   mailbox-list    = "(" [mbx-list-flags] ")" SP
+;;                      (DQUOTE QUOTED-CHAR DQUOTE / nil) SP mailbox
+;;
+;;   mbx-list-flags  = *(mbx-list-oflag SP) mbx-list-sflag
+;;                     *(SP mbx-list-oflag) /
+;;                     mbx-list-oflag *(SP mbx-list-oflag)
+;;
+;;   mbx-list-oflag  = "\Noinferiors" / flag-extension
+;;                       ; Other flags; multiple possible per LIST response
+;;
+;;   mbx-list-sflag  = "\Noselect" / "\Marked" / "\Unmarked"
+;;                       ; Selectability flags; only one per LIST response
+;;
+;;   QUOTED-CHAR     = <any TEXT-CHAR except quoted-specials> /
+;;                     "\" quoted-specials
+;;
+;;   quoted-specials = DQUOTE / "\"
+
+(defun imap-parse-data-list (type)
+  (let (flags delimiter mailbox)
+    (setq flags (imap-parse-flag-list))
+    (when (looking-at " NIL\\| \"\\\\?\\(.\\)\"")
+      (setq delimiter (match-string 1))
+      (goto-char (1+ (match-end 0)))
+      (when (setq mailbox (imap-parse-mailbox))
+       (imap-mailbox-put type t mailbox)
+       (imap-mailbox-put 'list-flags flags mailbox)
+       (imap-mailbox-put 'delimiter delimiter mailbox)))))
+
+;;  msg_att         ::= "(" 1#("ENVELOPE" SPACE envelope /
+;;                      "FLAGS" SPACE "(" #(flag / "\Recent") ")" /
+;;                      "INTERNALDATE" SPACE date_time /
+;;                      "RFC822" [".HEADER" / ".TEXT"] SPACE nstring /
+;;                      "RFC822.SIZE" SPACE number /
+;;                      "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 ()
+  (when (eq (char-after) ?\()
+    (let (strlist)
+      (while (not (eq (char-after) ?\)))
+       (imap-forward)
+       (push (imap-parse-astring) strlist))
+      (imap-forward)
+      (nreverse strlist))))
+
+(defsubst imap-parse-fetch-body-section ()
+  (let ((section
+        (buffer-substring (point) (1- (re-search-forward "[] ]" nil t)))))
+    (if (eq (char-before) ? )
+       (prog1
+           (mapconcat 'identity (cons section (imap-parse-header-list)) " ")
+         (search-forward "]" nil t))
+      section)))
+
+(defun imap-parse-fetch (response)
+  (when (eq (char-after) ?\()
+    (let (uid flags envelope internaldate rfc822 rfc822header rfc822text
+             rfc822size body bodydetail bodystructure flags-empty)
+      ;; Courier can insert spurious blank characters which will
+      ;; confuse `read', so skip past them.
+      (while (let ((moved (skip-chars-forward " \t")))
+              (prog1 (not (eq (char-after) ?\)))
+                (unless (= moved 0) (backward-char))))
+       (imap-forward)
+       (let ((token (read (current-buffer))))
+         (imap-forward)
+         (cond ((eq token 'UID)
+                (setq uid (condition-case ()
+                              (read (current-buffer))
+                            (error))))
+               ((eq token 'FLAGS)
+                (setq flags (imap-parse-flag-list))
+                (if (not flags)
+                    (setq flags-empty 't)))
+               ((eq token 'ENVELOPE)
+                (setq envelope (imap-parse-envelope)))
+               ((eq token 'INTERNALDATE)
+                (setq internaldate (imap-parse-string)))
+               ((eq token 'RFC822)
+                (setq rfc822 (imap-parse-nstring)))
+               ((eq token 'RFC822.HEADER)
+                (setq rfc822header (imap-parse-nstring)))
+               ((eq token 'RFC822.TEXT)
+                (setq rfc822text (imap-parse-nstring)))
+               ((eq token 'RFC822.SIZE)
+                (setq rfc822size (read (current-buffer))))
+               ((eq token 'BODY)
+                (if (eq (char-before) ?\[)
+                    (push (list
+                           (upcase (imap-parse-fetch-body-section))
+                           (and (eq (char-after) ?<)
+                                (buffer-substring (1+ (point))
+                                                  (search-forward ">" nil t)))
+                           (progn (imap-forward)
+                                  (imap-parse-nstring)))
+                          bodydetail)
+                  (setq body (imap-parse-body))))
+               ((eq token 'BODYSTRUCTURE)
+                (setq bodystructure (imap-parse-body))))))
+      (when uid
+       (setq imap-current-message uid)
+       (imap-message-put uid 'UID uid)
+       (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))
+       (and rfc822header (imap-message-put uid 'RFC822.HEADER rfc822header))
+       (and rfc822text (imap-message-put uid 'RFC822.TEXT rfc822text))
+       (and rfc822size (imap-message-put uid 'RFC822.SIZE rfc822size))
+       (and body (imap-message-put uid 'BODY body))
+       (and bodydetail (imap-message-put uid 'BODYDETAIL bodydetail))
+       (and bodystructure (imap-message-put uid 'BODYSTRUCTURE bodystructure))
+       (run-hooks 'imap-fetch-data-hook)))))
+
+;;   mailbox-data    =  ...
+;;                      "STATUS" SP mailbox SP "("
+;;                           [status-att SP number
+;;                            *(SP status-att SP number)] ")"
+;;                      ...
+;;
+;;   status-att      = "MESSAGES" / "RECENT" / "UIDNEXT" / "UIDVALIDITY" /
+;;                     "UNSEEN"
+
+(defun imap-parse-status ()
+  (let ((mailbox (imap-parse-mailbox)))
+    (if (eq (char-after) ? )
+       (forward-char))
+    (when (and mailbox (eq (char-after) ?\())
+      (while (and (not (eq (char-after) ?\)))
+                 (or (forward-char) t)
+                 (looking-at "\\([A-Za-z]+\\) "))
+       (let ((token (upcase (match-string 1))))
+         (goto-char (match-end 0))
+         (cond ((string= token "MESSAGES")
+                (imap-mailbox-put 'messages (read (current-buffer)) mailbox))
+               ((string= token "RECENT")
+                (imap-mailbox-put 'recent (read (current-buffer)) mailbox))
+               ((string= token "UIDNEXT")
+                (and (looking-at "[0-9]+")
+                     (imap-mailbox-put 'uidnext (match-string 0) mailbox)
+                     (goto-char (match-end 0))))
+               ((string= token "UIDVALIDITY")
+                (and (looking-at "[0-9]+")
+                     (imap-mailbox-put 'uidvalidity (match-string 0) mailbox)
+                     (goto-char (match-end 0))))
+               ((string= token "UNSEEN")
+                (imap-mailbox-put 'unseen (read (current-buffer)) mailbox))
+               (t
+                (message "Unknown status data %s in mailbox %s ignored"
+                         token mailbox)
+                (read (current-buffer)))))))))
+
+;;   acl_data        ::= "ACL" SPACE mailbox *(SPACE identifier SPACE
+;;                        rights)
+;;
+;;   identifier      ::= astring
+;;
+;;   rights          ::= astring
+
+(defun imap-parse-acl ()
+  (let ((mailbox (imap-parse-mailbox))
+       identifier rights acl)
+    (while (eq (char-after) ?\ )
+      (imap-forward)
+      (setq identifier (imap-parse-astring))
+      (imap-forward)
+      (setq rights (imap-parse-astring))
+      (setq acl (append acl (list (cons identifier rights)))))
+    (imap-mailbox-put 'acl acl mailbox)))
+
+;;   flag-list       = "(" [flag *(SP flag)] ")"
+;;
+;;   flag            = "\Answered" / "\Flagged" / "\Deleted" /
+;;                     "\Seen" / "\Draft" / flag-keyword / flag-extension
+;;                       ; Does not include "\Recent"
+;;
+;;   flag-keyword    = atom
+;;
+;;   flag-extension  = "\" atom
+;;                       ; Future expansion.  Client implementations
+;;                       ; MUST accept flag-extension flags.  Server
+;;                       ; implementations MUST NOT generate
+;;                       ; flag-extension flags except as defined by
+;;                       ; future standard or standards-track
+;;                       ; revisions of this specification.
+
+(defun imap-parse-flag-list ()
+  (let (flag-list start)
+    (assert (eq (char-after) ?\() nil "In imap-parse-flag-list 1")
+    (while (and (not (eq (char-after) ?\)))
+               (setq start (progn
+                             (imap-forward)
+                             ;; next line for Courier IMAP bug.
+                             (skip-chars-forward " ")
+                             (point)))
+               (> (skip-chars-forward "^ )" (point-at-eol)) 0))
+      (push (buffer-substring start (point)) flag-list))
+    (assert (eq (char-after) ?\)) nil "In imap-parse-flag-list 2")
+    (imap-forward)
+    (nreverse flag-list)))
+
+;;   envelope        = "(" env-date SP env-subject SP env-from SP env-sender SP
+;;                     env-reply-to SP env-to SP env-cc SP env-bcc SP
+;;                     env-in-reply-to SP env-message-id ")"
+;;
+;;   env-bcc         = "(" 1*address ")" / nil
+;;
+;;   env-cc          = "(" 1*address ")" / nil
+;;
+;;   env-date        = nstring
+;;
+;;   env-from        = "(" 1*address ")" / nil
+;;
+;;   env-in-reply-to = nstring
+;;
+;;   env-message-id  = nstring
+;;
+;;   env-reply-to    = "(" 1*address ")" / nil
+;;
+;;   env-sender      = "(" 1*address ")" / nil
+;;
+;;   env-subject     = nstring
+;;
+;;   env-to          = "(" 1*address ")" / nil
+
+(defun imap-parse-envelope ()
+  (when (eq (char-after) ?\()
+    (imap-forward)
+    (vector (prog1 (imap-parse-nstring)        ;; date
+             (imap-forward))
+           (prog1 (imap-parse-nstring) ;; subject
+             (imap-forward))
+           (prog1 (imap-parse-address-list) ;; from
+             (imap-forward))
+           (prog1 (imap-parse-address-list) ;; sender
+             (imap-forward))
+           (prog1 (imap-parse-address-list) ;; reply-to
+             (imap-forward))
+           (prog1 (imap-parse-address-list) ;; to
+             (imap-forward))
+           (prog1 (imap-parse-address-list) ;; cc
+             (imap-forward))
+           (prog1 (imap-parse-address-list) ;; bcc
+             (imap-forward))
+           (prog1 (imap-parse-nstring) ;; in-reply-to
+             (imap-forward))
+           (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
+        (let (strlist str)
+          (imap-forward)
+          (while (setq str (imap-parse-string))
+            (push str strlist)
+            ;; buggy stalker communigate pro 3.0 doesn't print SPC
+            ;; between body-fld-param's sometimes
+            (or (eq (char-after) ?\")
+                (imap-forward)))
+          (nreverse strlist)))
+       ((imap-parse-nil)
+        nil)))
+
+;;   body-extension  = nstring / number /
+;;                      "(" body-extension *(SP body-extension) ")"
+;;                       ; Future expansion.  Client implementations
+;;                       ; MUST accept body-extension fields.  Server
+;;                       ; implementations MUST NOT generate
+;;                       ; body-extension fields except as defined by
+;;                       ; future standard or standards-track
+;;                       ; revisions of this specification.
+
+(defun imap-parse-body-extension ()
+  (if (eq (char-after) ?\()
+      (let (b-e)
+       (imap-forward)
+       (push (imap-parse-body-extension) b-e)
+       (while (eq (char-after) ?\ )
+         (imap-forward)
+         (push (imap-parse-body-extension) b-e))
+       (assert (eq (char-after) ?\)) nil "In imap-parse-body-extension")
+       (imap-forward)
+       (nreverse b-e))
+    (or (imap-parse-number)
+       (imap-parse-nstring))))
+
+;;   body-ext-1part  = body-fld-md5 [SP body-fld-dsp [SP body-fld-lang
+;;                     *(SP body-extension)]]
+;;                       ; MUST NOT be returned on non-extensible
+;;                       ; "BODY" fetch
+;;
+;;   body-ext-mpart  = body-fld-param [SP body-fld-dsp [SP body-fld-lang
+;;                     *(SP body-extension)]]
+;;                       ; MUST NOT be returned on non-extensible
+;;                       ; "BODY" fetch
+
+(defsubst imap-parse-body-ext ()
+  (let (ext)
+    (when (eq (char-after) ?\ )        ;; body-fld-dsp
+      (imap-forward)
+      (let (dsp)
+       (if (eq (char-after) ?\()
+           (progn
+             (imap-forward)
+             (push (imap-parse-string) dsp)
+             (imap-forward)
+             (push (imap-parse-string-list) dsp)
+             (imap-forward))
+         ;; With assert, the code might not be eval'd.
+         ;; (assert (imap-parse-nil) t "In imap-parse-body-ext")
+         (imap-parse-nil))
+       (push (nreverse dsp) ext))
+      (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
+         (imap-forward)
+         (setq ext (append (imap-parse-body-extension) ext)))))
+    ext))
+
+;;   body            = "(" body-type-1part / body-type-mpart ")"
+;;
+;;   body-ext-1part  = body-fld-md5 [SP body-fld-dsp [SP body-fld-lang
+;;                     *(SP body-extension)]]
+;;                       ; MUST NOT be returned on non-extensible
+;;                       ; "BODY" fetch
+;;
+;;   body-ext-mpart  = body-fld-param [SP body-fld-dsp [SP body-fld-lang
+;;                     *(SP body-extension)]]
+;;                       ; MUST NOT be returned on non-extensible
+;;                       ; "BODY" fetch
+;;
+;;   body-fields     = body-fld-param SP body-fld-id SP body-fld-desc SP
+;;                     body-fld-enc SP body-fld-octets
+;;
+;;   body-fld-desc   = nstring
+;;
+;;   body-fld-dsp    = "(" string SP body-fld-param ")" / nil
+;;
+;;   body-fld-enc    = (DQUOTE ("7BIT" / "8BIT" / "BINARY" / "BASE64"/
+;;                     "QUOTED-PRINTABLE") DQUOTE) / string
+;;
+;;   body-fld-id     = nstring
+;;
+;;   body-fld-lang   = nstring / "(" string *(SP string) ")"
+;;
+;;   body-fld-lines  = number
+;;
+;;   body-fld-md5    = nstring
+;;
+;;   body-fld-octets = number
+;;
+;;   body-fld-param  = "(" string SP string *(SP string SP string) ")" / nil
+;;
+;;   body-type-1part = (body-type-basic / body-type-msg / body-type-text)
+;;                     [SP body-ext-1part]
+;;
+;;   body-type-basic = media-basic SP body-fields
+;;                       ; MESSAGE subtype MUST NOT be "RFC822"
+;;
+;;   body-type-msg   = media-message SP body-fields SP envelope
+;;                     SP body SP body-fld-lines
+;;
+;;   body-type-text  = media-text SP body-fields SP body-fld-lines
+;;
+;;   body-type-mpart = 1*body SP media-subtype
+;;                     [SP body-ext-mpart]
+;;
+;;   media-basic     = ((DQUOTE ("APPLICATION" / "AUDIO" / "IMAGE" /
+;;                     "MESSAGE" / "VIDEO") DQUOTE) / string) SP media-subtype
+;;                       ; Defined in [MIME-IMT]
+;;
+;;   media-message   = DQUOTE "MESSAGE" DQUOTE SP DQUOTE "RFC822" DQUOTE
+;;                      ; Defined in [MIME-IMT]
+;;
+;;   media-subtype   = string
+;;                       ; Defined in [MIME-IMT]
+;;
+;;   media-text      = DQUOTE "TEXT" DQUOTE SP media-subtype
+;;                       ; Defined in [MIME-IMT]
+
+(defun imap-parse-body ()
+  (let (body)
+    (when (eq (char-after) ?\()
+      (imap-forward)
+      (if (eq (char-after) ?\()
+         (let (subbody)
+           (while (and (eq (char-after) ?\()
+                       (setq subbody (imap-parse-body)))
+             ;; buggy stalker communigate pro 3.0 inserts 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:
+             (imap-forward)
+             (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) ?\)) nil "In imap-parse-body")
+           (imap-forward)
+           (nreverse body))
+
+       (push (imap-parse-string) body) ;; media-type
+       (imap-forward)
+       (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
+           (push (imap-parse-string-list) body)
+         (push (and (imap-parse-nil) nil) body))
+       (imap-forward)
+       (push (imap-parse-nstring) body) ;; body-fld-id
+       (imap-forward)
+       (push (imap-parse-nstring) body) ;; body-fld-desc
+       (imap-forward)
+       ;; Next `or' for Sun SIMS bug.  It regards body-fld-enc as a
+       ;; nstring and returns nil instead of defaulting back to 7BIT
+       ;; as the standard says.
+       ;; Exchange (2007, at least) does this as well.
+       (push (or (imap-parse-nstring) "7BIT") body) ;; body-fld-enc
+       (imap-forward)
+       ;; Exchange 2007 can return -1, contrary to the spec...
+       (if (eq (char-after) ?-)
+           (progn
+             (skip-chars-forward "-0-9")
+             (push nil body))
+         (push (imap-parse-number) body)) ;; body-fld-octets
+
+       ;; 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)...
+
+       (when (eq (char-after) ?\ )
+         (imap-forward)
+         (let (lines)
+           (cond ((eq (char-after) ?\() ;; body-type-msg:
+                  (push (imap-parse-envelope) body) ;; envelope
+                  (imap-forward)
+                  (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
+                 (t
+                  (backward-char))))) ;; no match...
+
+       ;; ...and then parse the third one here...
+
+       (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) ?\)) nil "In imap-parse-body 2")
+       (imap-forward)
+       (nreverse body)))))
+
+(when imap-debug                       ; (untrace-all)
+  (require 'trace)
+  (buffer-disable-undo (get-buffer-create imap-debug-buffer))
+  (mapc (lambda (f) (trace-function-background f imap-debug-buffer))
+       '(
+         imap-utf7-encode
+         imap-utf7-decode
+         imap-error-text
+         imap-kerberos4s-p
+         imap-kerberos4-open
+         imap-ssl-p
+         imap-ssl-open
+         imap-network-p
+         imap-network-open
+         imap-interactive-login
+         imap-kerberos4a-p
+         imap-kerberos4-auth
+         imap-cram-md5-p
+         imap-cram-md5-auth
+         imap-login-p
+         imap-login-auth
+         imap-anonymous-p
+         imap-anonymous-auth
+         imap-open-1
+         imap-open
+         imap-opened
+         imap-ping-server
+         imap-authenticate
+         imap-close
+         imap-capability
+         imap-namespace
+         imap-send-command-wait
+         imap-mailbox-put
+         imap-mailbox-get
+         imap-mailbox-map-1
+         imap-mailbox-map
+         imap-current-mailbox
+         imap-current-mailbox-p-1
+         imap-current-mailbox-p
+         imap-mailbox-select-1
+         imap-mailbox-select
+         imap-mailbox-examine-1
+         imap-mailbox-examine
+         imap-mailbox-unselect
+         imap-mailbox-expunge
+         imap-mailbox-close
+         imap-mailbox-create-1
+         imap-mailbox-create
+         imap-mailbox-delete
+         imap-mailbox-rename
+         imap-mailbox-lsub
+         imap-mailbox-list
+         imap-mailbox-subscribe
+         imap-mailbox-unsubscribe
+         imap-mailbox-status
+         imap-mailbox-acl-get
+         imap-mailbox-acl-set
+         imap-mailbox-acl-delete
+         imap-current-message
+         imap-list-to-message-set
+         imap-fetch-asynch
+         imap-fetch
+         imap-fetch-safe
+         imap-message-put
+         imap-message-get
+         imap-message-map
+         imap-search
+         imap-message-flag-permanent-p
+         imap-message-flags-set
+         imap-message-flags-del
+         imap-message-flags-add
+         imap-message-copyuid-1
+         imap-message-copyuid
+         imap-message-copy
+         imap-message-appenduid-1
+         imap-message-appenduid
+         imap-message-append
+         imap-body-lines
+         imap-envelope-from
+         imap-send-command-1
+         imap-send-command
+         imap-wait-for-tag
+         imap-sentinel
+         imap-find-next-line
+         imap-arrival-filter
+         imap-parse-greeting
+         imap-parse-response
+         imap-parse-resp-text
+         imap-parse-resp-text-code
+         imap-parse-data-list
+         imap-parse-fetch
+         imap-parse-status
+         imap-parse-acl
+         imap-parse-flag-list
+         imap-parse-envelope
+         imap-parse-body-extension
+         imap-parse-body
+         )))
+
+(provide 'imap)
+
+;; arch-tag: 27369ed6-33e4-482f-96f1-8bb906ba70f7
+;;; imap.el ends here
diff --git a/xemacs-packages/gnus/lisp/legacy-gnus-agent.el b/xemacs-packages/gnus/lisp/legacy-gnus-agent.el
new file mode 100644 (file)
index 0000000..7293e33
--- /dev/null
@@ -0,0 +1,260 @@
+;;; gnus-agent.el --- Legacy unplugged support for Gnus
+
+;; Copyright (C) 2004-2016 Free Software Foundation, Inc.
+
+;; Author: Kevin Greiner <kgreiner@xpediantsolutions.com>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Conversion functions for the Agent.
+
+;;; Code:
+(require 'gnus-start)
+(require 'gnus-util)
+(require 'gnus-range)
+(require 'gnus-agent)
+
+;; Oort Gnus v0.08 - This release updated agent to no longer use
+;;                   history file and to support a compressed alist.
+
+(defvar gnus-agent-compressed-agentview-search-only nil)
+
+(defun gnus-agent-convert-to-compressed-agentview (converting-to)
+  "Iterates over all agentview files to ensure that they have been
+converted to the compressed format."
+
+  (let ((search-in (list gnus-agent-directory))
+        here
+        members
+        member
+        converted-something)
+    (while (setq here (pop search-in))
+      (setq members (directory-files here t))
+      (while (setq member (pop members))
+        (cond ((string-match "/\\.\\.?$" member)
+              nil)
+             ((file-directory-p member)
+              (push member search-in))
+              ((equal (file-name-nondirectory member) ".agentview")
+               (setq converted-something
+                     (or (gnus-agent-convert-agentview member)
+                         converted-something))))))
+
+    (if converted-something
+        (gnus-message 4 "Successfully converted Gnus %s offline (agent) files to %s" gnus-newsrc-file-version converting-to))))
+
+(defun gnus-agent-convert-to-compressed-agentview-prompt ()
+  (catch 'found-file-to-convert
+    (let ((gnus-agent-compressed-agentview-search-only t))
+      (gnus-agent-convert-to-compressed-agentview nil))))
+
+(gnus-convert-mark-converter-prompt 'gnus-agent-convert-to-compressed-agentview 'gnus-agent-convert-to-compressed-agentview-prompt)
+
+(defun gnus-agent-convert-agentview (file)
+  "Load FILE and do a `read' there."
+  (with-temp-buffer
+      (nnheader-insert-file-contents file)
+      (goto-char (point-min))
+      (let ((inhibit-quit t)
+            (alist (read (current-buffer)))
+            (version (condition-case nil (read (current-buffer))
+                       (end-of-file 0)))
+            changed-version
+            history-file)
+
+        (cond
+        ((= version 0)
+         (let (entry
+                (gnus-command-method nil))
+            (mm-disable-multibyte) ;; everything is binary
+            (erase-buffer)
+            (insert "\n")
+            (let ((file (concat (file-name-directory file) "/history")))
+              (when (file-exists-p file)
+                (nnheader-insert-file-contents file)
+                (setq history-file file)))
+
+           (goto-char (point-min))
+           (while (not (eobp))
+             (if (and (looking-at
+                       "[^\t\n]+\t\\([0-9]+\\)\t\\([^ \n]+\\) \\([0-9]+\\)")
+                      (string= (gnus-agent-article-name ".agentview" (match-string 2))
+                               file)
+                      (setq entry (assoc (string-to-number (match-string 3)) alist)))
+                 (setcdr entry (string-to-number (match-string 1))))
+             (forward-line 1))
+           (setq changed-version t)))
+        ((= version 1)
+         (setq changed-version t)))
+
+        (when changed-version
+         (when gnus-agent-compressed-agentview-search-only
+           (throw 'found-file-to-convert t))
+
+          (erase-buffer)
+          (let (article-id day-of-download comp-list compressed)
+           (while alist
+             (setq article-id (caar alist)
+                   day-of-download (cdar alist)
+                   comp-list (assq day-of-download compressed)
+                   alist (cdr alist))
+             (if comp-list
+                 (setcdr comp-list (cons article-id (cdr comp-list)))
+               (push (list day-of-download article-id) compressed)))
+           (setq alist compressed)
+           (while alist
+             (setq comp-list (pop alist))
+             (setcdr comp-list
+                     (gnus-compress-sequence (nreverse (cdr comp-list)))))
+            (princ compressed (current-buffer)))
+          (insert "\n2\n")
+          (write-file file)
+          (when history-file
+            (delete-file history-file))
+          t))))
+
+;; End of Oort Gnus v0.08 updates
+
+;; No Gnus v0.3 - This release provides a mechanism for upgrading gnus
+;;                from previous versions.  Therefore, the previous
+;;                hacks to handle a gnus-agent-expire-days that
+;;                specifies a list of values can be removed.
+
+(defun gnus-agent-unlist-expire-days (converting-to)
+  (when (listp gnus-agent-expire-days)
+    (let (buffer)
+      (unwind-protect
+          (save-window-excursion
+            (setq buffer (gnus-get-buffer-create " *Gnus agent upgrade*"))
+            (set-buffer buffer)
+            (erase-buffer)
+            (insert "The definition of gnus-agent-expire-days has been changed.\nYou currently have it set to the list:\n  ")
+            (gnus-pp gnus-agent-expire-days)
+
+           (insert
+            (gnus-format-message
+             "\nIn order to use version `%s' of gnus, you will need to set\n"
+             converting-to))
+            (insert "gnus-agent-expire-days to an integer. If you still wish to set different\n")
+            (insert "expiration days to individual groups, you must instead set the\n")
+            (insert (gnus-format-message
+                    "`agent-days-until-old' group and/or topic parameter.\n"))
+            (insert "\n")
+            (insert "If you would like, gnus can iterate over every group comparing its name to the\n")
+            (insert "regular expressions that you currently have in gnus-agent-expire-days.  When\n")
+            (insert (gnus-format-message
+                    "gnus finds a match, it will update that group's `agent-days-until-old' group\n"))
+            (insert "parameter to the value associated with the regular expression.\n")
+            (insert "\n")
+            (insert "Whether gnus assigns group parameters, or not, gnus will terminate with an\n")
+            (insert "ERROR as soon as this function completes.  The reason is that you must\n")
+            (insert "manually edit your configuration to either not set gnus-agent-expire-days or\n")
+            (insert "to set it to an integer before gnus can be used.\n")
+            (insert "\n")
+            (insert "Once you have successfully edited gnus-agent-expire-days, gnus will be able to\n")
+            (insert "execute past this function.\n")
+            (insert "\n")
+            (insert "Should gnus use gnus-agent-expire-days to assign\n")
+            (insert "agent-days-until-old parameters to individual groups? (Y/N)")
+
+            (switch-to-buffer buffer)
+            (beep)
+            (beep)
+
+            (let ((echo-keystrokes 0)
+                  c)
+              (while (progn (setq c (read-char-exclusive))
+                            (cond ((or (eq c ?y) (eq c ?Y))
+                                         (save-excursion
+                                           (let ((groups (gnus-group-listed-groups)))
+                                             (while groups
+                                               (let* ((group (pop groups))
+                                                      (days gnus-agent-expire-days)
+                                                      (day (catch 'found
+                                                             (while days
+                                                               (when (eq 0 (string-match
+                                                                            (caar days)
+                                                                            group))
+                                                                 (throw 'found (cadr (car days))))
+                                                               (setq days (cdr days)))
+                                                             nil)))
+                                                 (when day
+                                                   (gnus-group-set-parameter group 'agent-days-until-old
+                                                                             day))))))
+                                   nil
+                                   )
+                                  ((or (eq c ?n) (eq c ?N))
+                                   nil)
+                                  (t
+                                   t))))))
+        (kill-buffer buffer))
+      (error "Change gnus-agent-expire-days to an integer for gnus to start"))))
+
+;; The gnus-agent-unlist-expire-days has its own conversion prompt.
+;; Therefore, hide the default prompt.
+(gnus-convert-mark-converter-prompt 'gnus-agent-unlist-expire-days t)
+
+(defun gnus-agent-unhook-expire-days (converting-to)
+  "Remove every lambda from `gnus-group-prepare-hook' that mention the
+symbol `gnus-agent-do-once' in their definition.  This should NOT be
+necessary as gnus-agent.el no longer adds them.  However, it is
+possible that the hook was persistently saved."
+    (let ((h t)) ; Iterate from bgn of hook.
+      (while h
+        (let ((func (progn (when (eq h t)
+                             ;; Init h to list of functions.
+                             (setq h (cond ((listp gnus-group-prepare-hook)
+                                            gnus-group-prepare-hook)
+                                           ((boundp 'gnus-group-prepare-hook)
+                                            (list gnus-group-prepare-hook)))))
+                           (pop h))))
+
+          (when (cond ((byte-code-function-p func)
+                       ;; Search def. of compiled function for
+                       ;; gnus-agent-do-once string.
+                       (let* (definition
+                               print-level
+                               print-length
+                               (standard-output
+                                (lambda (char)
+                                  (setq definition (cons char definition)))))
+                         (princ func) ; Populates definition with reversed list
+                                     ; of characters.
+                         (let* ((i (length definition))
+                                (s (make-string i 0)))
+                           (while definition
+                             (aset s (setq i (1- i)) (pop definition)))
+
+                           (string-match "\\bgnus-agent-do-once\\b" s))))
+                      ((listp func)
+                       (eq (cadr (nth 2 func)) 'gnus-agent-do-once) ; Handles eval'd lambda.
+                       ))
+
+            (remove-hook 'gnus-group-prepare-hook func)
+            ;; I don't what remove-hook is going to actually do to the
+            ;; hook list so start over from the beginning.
+            (setq h t))))))
+
+;; gnus-agent-unhook-expire-days is safe in that it does not modify
+;; the .newsrc.eld file.
+(gnus-convert-mark-converter-prompt 'gnus-agent-unhook-expire-days t)
+
+(provide 'legacy-gnus-agent)
+
+;;; legacy-gnus-agent.el ends here
diff --git a/xemacs-packages/gnus/lisp/lpath.el b/xemacs-packages/gnus/lisp/lpath.el
new file mode 100644 (file)
index 0000000..aba785f
--- /dev/null
@@ -0,0 +1,133 @@
+;; Shut up.
+
+(defun maybe-fbind (args)
+  (while args
+    (or (fboundp (car args))
+       (defalias (car args) 'ignore))
+    (setq args (cdr args))))
+
+(defun maybe-bind (args)
+  (mapcar (lambda (var) (unless (boundp var) (set var nil))) args))
+
+(unless (featurep 'xemacs)
+  (maybe-fbind '(pgg-display-output-buffer url-generic-parse-url))
+  (maybe-bind '(help-xref-stack-item url-version))
+
+  (when (<= emacs-major-version 23)
+    (maybe-bind '(mail-encode-mml syntax-propertize-function)))
+
+  (when (<= emacs-major-version 22)
+    (defun ecomplete-add-item (type key text))
+    (defun ecomplete-save nil)
+    (defun hashcash-wait-async (&optional buffer))
+    (defun mail-add-payment (&optional arg async))
+    (defun mail-add-payment-async (&optional arg))
+    (defun netrc-get (alist type))
+    (defun netrc-machine (list machine &optional port defaultport))
+    (defun netrc-machine-user-or-password (mode authinfo-file-or-list machines
+                                               ports defaults))
+    (defun netrc-parse (file))
+    (defun shr-put-image (data alt &optional flags))
+    (maybe-fbind
+     '(Info-index
+       Info-index-next Info-menu bbdb-complete-name bookmark-default-handler
+       bookmark-get-bookmark-record bookmark-make-record-default
+       bookmark-prop-get completion-at-point display-time-event-handler
+       epg-check-configuration find-coding-system frame-device gnutls-negotiate
+       libxml-parse-html-region recenter-top-bottom rmail-swap-buffers-maybe
+       shr-insert-document w3m-detect-meta-charset w3m-region))
+    (maybe-bind
+     '(epa-file-encrypt-to w3m-link-map))))
+
+(when (featurep 'xemacs)
+  (defun canlock-insert-header (&optional id-for-key id-for-lock password))
+  (defun ecomplete-add-item (type key text))
+  (defun ecomplete-save nil)
+  (defun gnus-html-prefetch-images (summary))
+  (defun hashcash-wait-async (&optional buffer))
+  (defun mail-add-payment (&optional arg async))
+  (defun mail-add-payment-async (&optional arg))
+  (defun netrc-get (alist type))
+  (defun netrc-machine (list machine &optional port defaultport))
+  (defun netrc-machine-user-or-password (mode authinfo-file-or-list machines
+                                             ports defaults))
+  (defun netrc-parse (file))
+  (defun split-line (&optional arg))
+  (defun shr-put-image (data alt &optional flags))
+  (eval-after-load "rmail"
+    '(defun rmail-toggle-header (&optional arg)))
+  (maybe-fbind
+   '(beginning-of-visual-line
+     bookmark-default-handler bookmark-get-bookmark-record
+     bookmark-make-record-default bookmark-prop-get clear-string codepage-setup
+     coding-system-from-name completion-at-point cp-supported-codepages
+     create-image debbugs-gnu cursor-sensor-mode detect-coding-string
+     display-time-event-handler epg-check-configuration event-click-count
+     event-end event-start find-coding-systems-for-charsets
+     find-coding-systems-region find-coding-systems-string find-image
+     float-time gnutls-negotiate font-lock-ensure font-lock-flush help-buffer
+     ido-completing-read image-size image-type-available-p insert-image
+     jka-compr-get-compression-info jka-compr-info-uncompress-args
+     jka-compr-info-uncompress-message jka-compr-info-uncompress-program
+     jka-compr-installed-p jka-compr-make-temp-name libxml-parse-html-region
+     mail-abbrevs-setup make-mode-line-mouse-map make-network-process make-term
+     mouse-minibuffer-check mouse-movement-p mouse-scroll-subr
+     pgg-display-output-buffer posn-point posn-window process-type put-image
+     read-char-choice read-event recenter-top-bottom
+     rmail-msg-restore-non-pruned-header rmail-swap-buffers-maybe
+     select-safe-coding-system set-network-process-option shr-insert-document
+     sort-coding-systems spam-initialize string-to-syntax term-char-mode
+     term-mode track-mouse ucs-to-char url-generic-parse-url
+     url-insert-file-contents vcard-pretty-print w3m-detect-meta-charset
+     w3m-region window-edges network-interface-list))
+  (maybe-bind
+   '(adaptive-fill-first-line-regexp
+     buffer-display-table buffer-save-without-query completion-styles
+     completion-styles-alist cursor-in-non-selected-windows cursor-sensor-mode
+     default-enable-multibyte-characters default-file-name-coding-system
+     epa-file-encrypt-to eudc-protocol filladapt-mode
+     gnus-agent-expire-current-dirs help-xref-stack-item idna-program
+     installation-directory iswitchb-mode iswitchb-temp-buflist line-spacing
+     mail-encode-mml mark-active mouse-selection-click-count
+     mouse-selection-click-count-buffer ps-print-color-p rmail-default-file
+     rmail-default-rmail-file rmail-insert-mime-forwarded-message-function
+     show-trailing-whitespace smtpmail-default-smtp-server
+     temporary-file-directory tool-bar-mode transient-mark-mode url-version
+     w3m-link-map))
+
+  (when (or (and (= emacs-major-version 21) (= emacs-minor-version 4))
+           (featurep 'sxemacs))
+    (maybe-fbind
+     '(current-idle-time
+       custom-autoload decode-char display-graphic-p display-images-p
+       display-visual-class get-display-table help-function-arglist
+       make-temp-file next-single-char-property-change put-display-table
+       select-frame-set-input-focus set-buffer-multibyte set-char-table-range
+       string-as-multibyte timer-set-function unicode-precedence-list
+       unicode-to-char))
+    (maybe-bind
+     '(header-line-format
+       scroll-margin timer-list)))
+
+  (unless (featurep 'mule)
+    (maybe-fbind
+     '(ccl-execute-on-string
+       char-charset charsetp coding-system-get find-charset-region
+       get-charset-property pgg-display-output-buffer unicode-precedence-list))
+    (maybe-bind
+     '(current-language-environment
+       language-info-alist)))
+
+  (unless (featurep 'file-coding)
+    (maybe-fbind
+     '(coding-system-aliasee
+       coding-system-base coding-system-change-eol-conversion coding-system-list
+       coding-system-p decode-coding-region decode-coding-string
+       detect-coding-region encode-coding-region encode-coding-string
+       find-coding-system))
+    (maybe-bind
+     '(buffer-file-coding-system
+       coding-system-for-read coding-system-for-write
+       enable-multibyte-characters file-name-coding-system))))
+
+(provide 'lpath)
diff --git a/xemacs-packages/gnus/lisp/mail-parse.el b/xemacs-packages/gnus/lisp/mail-parse.el
new file mode 100644 (file)
index 0000000..4fc7e46
--- /dev/null
@@ -0,0 +1,75 @@
+;;; mail-parse.el --- Interface functions for parsing mail
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This file contains wrapper functions for a wide range of mail
+;; parsing functions.  The idea is that there are low-level libraries
+;; that implement according to various specs (RFC2231, DRUMS, USEFOR),
+;; but that programmers that want to parse some header (say,
+;; Content-Type) will want to use the latest spec.
+;;
+;; So while each low-level library (rfc2231.el, for instance) decodes
+;; faithfully according to that (proposed) standard, this library is
+;; the interface library.  If some later RFC supersedes RFC2231, one
+;; would just have to write a new low-level library, adjust the
+;; aliases in this library, and the users and programmers won't notice
+;; any changes.
+
+;;; Code:
+
+(require 'mail-prsvr)
+(require 'ietf-drums)
+(require 'rfc2231)
+(require 'rfc2047)
+(require 'rfc2045)
+
+(defalias 'mail-header-parse-content-type 'rfc2231-parse-qp-string)
+(defalias 'mail-header-parse-content-disposition 'rfc2231-parse-qp-string)
+(defalias 'mail-content-type-get 'rfc2231-get-value)
+(defalias 'mail-header-encode-parameter 'rfc2047-encode-parameter)
+
+(defalias 'mail-header-remove-comments 'ietf-drums-remove-comments)
+(defalias 'mail-header-remove-whitespace 'ietf-drums-remove-whitespace)
+(defalias 'mail-header-strip 'ietf-drums-strip)
+(defalias 'mail-header-get-comment 'ietf-drums-get-comment)
+(defalias 'mail-header-parse-address 'ietf-drums-parse-address)
+(defalias 'mail-header-parse-addresses 'ietf-drums-parse-addresses)
+(defalias 'mail-header-parse-date 'ietf-drums-parse-date)
+(defalias 'mail-narrow-to-head 'ietf-drums-narrow-to-header)
+(defalias 'mail-quote-string 'ietf-drums-quote-string)
+(defalias 'mail-header-make-address 'ietf-drums-make-address)
+
+(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)
+(defalias 'mail-decode-encoded-word-region 'rfc2047-decode-region)
+(defalias 'mail-decode-encoded-word-string 'rfc2047-decode-string)
+(defalias 'mail-decode-encoded-address-region 'rfc2047-decode-address-region)
+(defalias 'mail-decode-encoded-address-string 'rfc2047-decode-address-string)
+
+(provide 'mail-parse)
+
+;;; mail-parse.el ends here
diff --git a/xemacs-packages/gnus/lisp/mail-prsvr.el b/xemacs-packages/gnus/lisp/mail-prsvr.el
new file mode 100644 (file)
index 0000000..789c002
--- /dev/null
@@ -0,0 +1,43 @@
+;;; mail-prsvr.el --- Interface variables for parsing mail
+
+;; Copyright (C) 1999-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(defvar mail-parse-charset nil
+  "Default charset used by low-level libraries.
+This variable should never be set.  Instead, it should be bound by
+functions that wish to call mail-parse functions and let them know
+what the desired charset is to be.")
+
+(defvar mail-parse-mule-charset nil
+  "Default MULE charset used by low-level libraries.
+This variable should never be set.")
+
+(defvar mail-parse-ignored-charsets nil
+  "Ignored charsets used by low-level libraries.
+This variable should never be set.  Instead, it should be bound by
+functions that wish to call mail-parse functions and let them know
+what the desired charsets is to be ignored.")
+
+(provide 'mail-prsvr)
+
+;;; mail-prsvr.el ends here
diff --git a/xemacs-packages/gnus/lisp/mail-source.el b/xemacs-packages/gnus/lisp/mail-source.el
new file mode 100644 (file)
index 0000000..f4a9e19
--- /dev/null
@@ -0,0 +1,1152 @@
+;;; mail-source.el --- functions for fetching mail
+
+;; Copyright (C) 1999-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: news, mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'format-spec)
+(eval-when-compile
+  (require 'cl)
+  (require 'imap))
+(autoload 'auth-source-search "auth-source")
+(autoload 'pop3-movemail "pop3")
+(autoload 'pop3-get-message-count "pop3")
+(autoload 'nnheader-cancel-timer "nnheader")
+(require 'mm-util)
+(require 'message) ;; for `message-directory'
+
+(defvar display-time-mail-function)
+
+(defgroup mail-source nil
+  "The mail-fetching library."
+  :version "21.1"
+  :group 'gnus)
+
+;; Define these at compile time to avoid dragging in imap always.
+(defconst mail-source-imap-authenticators
+  (eval-when-compile
+    (mapcar (lambda (a)
+             (list 'const (car a)))
+     imap-authenticator-alist)))
+(defconst mail-source-imap-streams
+  (eval-when-compile
+    (mapcar (lambda (a)
+             (list 'const (car a)))
+     imap-stream-alist)))
+
+(defcustom mail-sources '((file))
+  "Where the mail backends will look for incoming mail.
+This variable is a list of mail source specifiers.
+See Info node `(gnus)Mail Source Specifiers'."
+  :group 'mail-source
+  :version "24.4"
+  :link '(custom-manual "(gnus)Mail Source Specifiers")
+  :type `(choice
+         (const :tag "None" nil)
+         (repeat :tag "List"
+          (choice :format "%[Value Menu%] %v"
+                  :value (file)
+                  (cons :tag "Group parameter `mail-source'"
+                        (const :format "" group))
+                  (cons :tag "Spool file"
+                        (const :format "" file)
+                        (checklist :tag "Options" :greedy t
+                                   (group :inline t
+                                          (const :format "" :value :path)
+                                          file)))
+                  (cons :tag "Several files in a directory"
+                        (const :format "" directory)
+                        (checklist :tag "Options" :greedy t
+                                   (group :inline t
+                                          (const :format "" :value :path)
+                                          (directory :tag "Path"))
+                                   (group :inline t
+                                          (const :format "" :value :suffix)
+                                          (string :tag "Suffix"))
+                                   (group :inline t
+                                          (const :format "" :value :predicate)
+                                          (function :tag "Predicate"))
+                                   (group :inline t
+                                          (const :format "" :value :prescript)
+                                          (choice :tag "Prescript"
+                                                  :value nil
+                                                  (string :format "%v")
+                                                  (function :format "%v")))
+                                   (group :inline t
+                                          (const :format "" :value :postscript)
+                                          (choice :tag "Postscript"
+                                                  :value nil
+                                                  (string :format "%v")
+                                                  (function :format "%v")))
+                                   (group :inline t
+                                          (const :format "" :value :plugged)
+                                          (boolean :tag "Plugged"))))
+                  (cons :tag "POP3 server"
+                        (const :format "" pop)
+                        (checklist :tag "Options" :greedy t
+                                   (group :inline t
+                                          (const :format "" :value :server)
+                                          (string :tag "Server"))
+                                   (group :inline t
+                                          (const :format "" :value :port)
+                                          (choice :tag "Port"
+                                                  :value "pop3"
+                                                  (integer :format "%v")
+                                                  (string :format "%v")))
+                                   (group :inline t
+                                          (const :format "" :value :user)
+                                          (string :tag "User"))
+                                   (group :inline t
+                                          (const :format "" :value :password)
+                                          (string :tag "Password"))
+                                   (group :inline t
+                                          (const :format "" :value :program)
+                                          (string :tag "Program"))
+                                   (group :inline t
+                                          (const :format "" :value :prescript)
+                                          (choice :tag "Prescript"
+                                                  :value nil
+                                                  (string :format "%v")
+                                                  (function :format "%v")
+                                                  (const :tag "None" nil)))
+                                   (group :inline t
+                                          (const :format "" :value :postscript)
+                                          (choice :tag "Postscript"
+                                                  :value nil
+                                                  (string :format "%v")
+                                                  (function :format "%v")
+                                                  (const :tag "None" nil)))
+                                   (group :inline t
+                                          (const :format "" :value :function)
+                                          (function :tag "Function"))
+                                   (group :inline t
+                                          (const :format ""
+                                                 :value :authentication)
+                                          (choice :tag "Authentication"
+                                                  :value apop
+                                                  (const password)
+                                                  (const apop)))
+                                   (group :inline t
+                                          (const :format "" :value :plugged)
+                                          (boolean :tag "Plugged"))
+                                   (group :inline t
+                                          (const :format "" :value :stream)
+                                          (choice :tag "Stream"
+                                                  :value nil
+                                                  (const :tag "Clear" nil)
+                                                  (const starttls)
+                                                  (const :tag "SSL/TLS" ssl)))
+                                   (group :inline t
+                                          (const :format "" :value :leave)
+                                          (choice :format "\
+%{Leave mail on server%}:\n\t\t%[Value Menu%] %v"
+                                                  :value nil
+                                                  (const :tag "\
+Don't leave mails" nil)
+                                                  (const :tag "\
+Leave all mails" t)
+                                                  (number :tag "\
+Leave mails for this many days" :value 14)))))
+                  (cons :tag "Maildir (qmail, postfix...)"
+                        (const :format "" maildir)
+                        (checklist :tag "Options" :greedy t
+                                   (group :inline t
+                                          (const :format "" :value :path)
+                                          (directory :tag "Path"))
+                                   (group :inline t
+                                          (const :format "" :value :plugged)
+                                          (boolean :tag "Plugged"))))
+                  (cons :tag "IMAP server"
+                        (const :format "" imap)
+                        (checklist :tag "Options" :greedy t
+                                   (group :inline t
+                                          (const :format "" :value :server)
+                                          (string :tag "Server"))
+                                   (group :inline t
+                                          (const :format "" :value :port)
+                                          (choice :tag "Port"
+                                                  :value 143
+                                                  integer string))
+                                   (group :inline t
+                                          (const :format "" :value :user)
+                                          (string :tag "User"))
+                                   (group :inline t
+                                          (const :format "" :value :password)
+                                          (string :tag "Password"))
+                                   (group :inline t
+                                          (const :format "" :value :stream)
+                                          (choice :tag "Stream"
+                                                  :value network
+                                                  ,@mail-source-imap-streams))
+                                   (group :inline t
+                                          (const :format "" :value :program)
+                                          (string :tag "Program"))
+                                   (group :inline t
+                                          (const :format ""
+                                                 :value :authenticator)
+                                          (choice :tag "Authenticator"
+                                                  :value login
+                                                  ,@mail-source-imap-authenticators))
+                                   (group :inline t
+                                          (const :format "" :value :mailbox)
+                                          (string :tag "Mailbox"
+                                                  :value "INBOX"))
+                                   (group :inline t
+                                          (const :format "" :value :predicate)
+                                          (string :tag "Predicate"
+                                                  :value "UNSEEN UNDELETED"))
+                                   (group :inline t
+                                          (const :format "" :value :fetchflag)
+                                          (string :tag "Fetchflag"
+                                                  :value  "\\Deleted"))
+                                   (group :inline t
+                                          (const :format ""
+                                                 :value :dontexpunge)
+                                          (boolean :tag "Dontexpunge"))
+                                   (group :inline t
+                                          (const :format "" :value :plugged)
+                                          (boolean :tag "Plugged"))))))))
+
+(defcustom mail-source-ignore-errors nil
+  "*Ignore errors when querying mail sources.
+If nil, the user will be prompted when an error occurs.  If non-nil,
+the error will be ignored."
+  :version "22.1"
+  :group 'mail-source
+  :type 'boolean)
+
+(defcustom mail-source-primary-source nil
+  "*Primary source for incoming mail.
+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 message-directory
+  "Directory where incoming mail source files (if any) will be stored."
+  :group 'mail-source
+  :type 'directory)
+
+(defcustom mail-source-default-file-modes 384
+  "Set the mode bits of all new mail files to this integer."
+  :group 'mail-source
+  :type 'integer)
+
+(defcustom mail-source-delete-incoming
+  10 ;; development versions
+  ;; 2 ;; released versions
+  "If non-nil, delete incoming files after handling.
+If t, delete immediately, if nil, never delete.  If a positive number, delete
+files older than number of days.
+
+Removing of old files happens in `mail-source-callback', i.e. no
+old incoming files will be deleted unless you receive new mail.
+You may also set this variable to nil and call
+`mail-source-delete-old-incoming' interactively."
+  :group 'mail-source
+  :version "22.2" ;; No Gnus / Gnus 5.10.10 (default changed)
+  :type '(choice (const :tag "immediately" t)
+                (const :tag "never" nil)
+                (integer :tag "days")))
+
+(defcustom mail-source-delete-old-incoming-confirm nil
+  "If non-nil, ask for confirmation before deleting old incoming files.
+This variable only applies when `mail-source-delete-incoming' is a positive
+number."
+  :version "22.2" ;; No Gnus / Gnus 5.10.10 (default changed)
+  :group 'mail-source
+  :type 'boolean)
+
+(defcustom mail-source-incoming-file-prefix "Incoming"
+  "Prefix for file name for storing incoming mail"
+  :group 'mail-source
+  :type 'string)
+
+(defcustom mail-source-report-new-mail-interval 5
+  "Interval in minutes between checks for new mail."
+  :group 'mail-source
+  :type 'number)
+
+(defcustom mail-source-idle-time-delay 5
+  "Number of idle seconds to wait before checking for new mail."
+  :group 'mail-source
+  :type 'number)
+
+(defcustom mail-source-movemail-program nil
+  "If non-nil, name of program for fetching new mail."
+  :version "22.1"
+  :group 'mail-source
+  :type '(choice (const nil) string))
+
+;;; Internal variables.
+
+(defvar mail-source-string ""
+  "A dynamically bound string that says what the current mail source is.")
+
+(defvar mail-source-new-mail-available nil
+  "Flag indicating when new mail is available.")
+
+(eval-and-compile
+  (defvar mail-source-common-keyword-map
+    '((:plugged))
+    "Mapping from keywords to default values.
+Common keywords should be listed here.")
+
+  (defvar mail-source-keyword-map
+    '((file
+       (:prescript)
+       (:prescript-delay)
+       (:postscript)
+       (:path (or (getenv "MAIL")
+                 (expand-file-name (user-login-name) rmail-spool-directory))))
+      (directory
+       (:prescript)
+       (:prescript-delay)
+       (:postscript)
+       (:path)
+       (:suffix ".spool")
+       (:predicate identity))
+      (pop
+       (:prescript)
+       (:prescript-delay)
+       (:postscript)
+       ;; note server and port need to come before user and password
+       (:server (getenv "MAILHOST"))
+       (:port 110)
+       (:user (or (user-login-name) (getenv "LOGNAME") (getenv "USER")))
+       (:program)
+       (:function)
+       (:password)
+       (:authentication password)
+       (:stream nil)
+       (:leave))
+      (maildir
+       (:path (or (getenv "MAILDIR") "~/Maildir/"))
+       (:subdirs ("cur" "new"))
+       (:function))
+      (imap
+       ;; note server and port need to come before user and password
+       (:server (getenv "MAILHOST"))
+       (:port)
+       (:stream)
+       (:program)
+       (:authentication)
+       (:user (or (user-login-name) (getenv "LOGNAME") (getenv "USER")))
+       (:password)
+       (:mailbox "INBOX")
+       (:predicate "UNSEEN UNDELETED")
+       (:fetchflag "\\Deleted")
+       (:prescript)
+       (:prescript-delay)
+       (:postscript)
+       (:dontexpunge)))
+    "Mapping from keywords to default values.
+All keywords that can be used must be listed here."))
+
+(defvar mail-source-fetcher-alist
+  '((file mail-source-fetch-file)
+    (directory mail-source-fetch-directory)
+    (pop mail-source-fetch-pop)
+    (maildir mail-source-fetch-maildir)
+    (imap mail-source-fetch-imap))
+  "A mapping from source type to fetcher function.")
+
+(defvar mail-source-password-cache nil)
+
+(defvar mail-source-plugged t)
+
+;;; Functions
+
+(eval-and-compile
+  (defun mail-source-strip-keyword (keyword)
+    "Strip the leading colon off the KEYWORD."
+    (intern (substring (symbol-name keyword) 1))))
+
+;; generate a list of variable names paired with nil values
+;; suitable for usage in a `let' form
+(eval-and-compile
+  (defun mail-source-bind-1 (type)
+    (let* ((defaults (cdr (assq type mail-source-keyword-map)))
+          default bind)
+      (while (setq default (pop defaults))
+       (push (list (mail-source-strip-keyword (car default))
+                   nil)
+             bind))
+      bind)))
+
+(defmacro mail-source-bind (type-source &rest body)
+  "Return a `let' form that binds all variables in source TYPE.
+TYPE-SOURCE is a list where the first element is the TYPE, and
+the second variable is the SOURCE.
+At run time, the mail source specifier SOURCE will be inspected,
+and the variables will be set according to it.  Variables not
+specified will be given default values.
+
+The user and password will be loaded from the auth-source values
+if those are available.  They override the original user and
+password in a second `let' form.
+
+After this is done, BODY will be executed in the scope
+of the second `let' form.
+
+The variables bound and their default values are described by
+the `mail-source-keyword-map' variable."
+  `(let* ,(mail-source-bind-1 (car type-source))
+     (mail-source-set-1 ,(cadr type-source))
+     ,@body))
+
+(put 'mail-source-bind 'lisp-indent-function 1)
+(put 'mail-source-bind 'edebug-form-spec '(sexp body))
+
+(defun mail-source-set-1 (source)
+  (let* ((type (pop source))
+         (defaults (cdr (assq type mail-source-keyword-map)))
+         (search '(:max 1))
+         found default value keyword auth-info user-auth pass-auth)
+
+    ;; append to the search the useful info from the source and the defaults:
+    ;; user, host, and port
+
+    ;; the msname is the mail-source parameter
+    (dolist (msname '(:server :user :port))
+      ;; the asname is the auth-source parameter
+      (let* ((asname (case msname
+                       (:server :host)  ; auth-source uses :host
+                       (t msname)))
+             ;; this is the mail-source default
+             (msdef1 (or (plist-get source msname)
+                         (nth 1 (assoc msname defaults))))
+             ;; ...evaluated
+             (msdef (mail-source-value msdef1)))
+        (setq search (append (list asname
+                                   (if msdef msdef t))
+                             search))))
+    ;; if the port is unknown yet, get it from the mail-source type
+    (unless (plist-get search :port)
+      (setq search (append (list :port (symbol-name type)))))
+
+    (while (setq default (pop defaults))
+      ;; for each default :SYMBOL, set SYMBOL to the plist value for :SYMBOL
+      ;; using `mail-source-value' to evaluate the plist value
+      (set (mail-source-strip-keyword (setq keyword (car default)))
+           ;; note the following reasons for this structure:
+           ;; 1) the auth-sources user and password override everything
+           ;; 2) it avoids macros, so it's cleaner
+           ;; 3) it falls through to the mail-sources and then default values
+           (cond
+            ((and
+             (eq keyword :user)
+             (setq user-auth (plist-get
+                              ;; cache the search result in `found'
+                              (or found
+                                  (setq found (nth 0 (apply 'auth-source-search
+                                                            search))))
+                              :user)))
+             user-auth)
+            ((and
+              (eq keyword :password)
+              (setq pass-auth (plist-get
+                               ;; cache the search result in `found'
+                               (or found
+                                   (setq found (nth 0 (apply 'auth-source-search
+                                                             search))))
+                               :secret)))
+             ;; maybe set the password to the return of the :secret function
+             (if (functionp pass-auth)
+                 (setq pass-auth (funcall pass-auth))
+               pass-auth))
+            (t (if (setq value (plist-get source keyword))
+                 (mail-source-value value)
+               (mail-source-value (cadr default)))))))))
+
+(eval-and-compile
+  (defun mail-source-bind-common-1 ()
+    (let* ((defaults mail-source-common-keyword-map)
+          default bind)
+      (while (setq default (pop defaults))
+       (push (list (mail-source-strip-keyword (car default))
+                   nil)
+             bind))
+      bind)))
+
+(defun mail-source-set-common-1 (source)
+  (let* ((type (pop source))
+        (defaults mail-source-common-keyword-map)
+        (defaults-1 (cdr (assq type mail-source-keyword-map)))
+        default value keyword)
+    (while (setq default (pop defaults))
+      (set (mail-source-strip-keyword (setq keyword (car default)))
+          (if (setq value (plist-get source keyword))
+              (mail-source-value value)
+            (if (setq value (assq  keyword defaults-1))
+                (mail-source-value (cadr value))
+              (mail-source-value (cadr default))))))))
+
+(defmacro mail-source-bind-common (source &rest body)
+  "Return a `let' form that binds all common variables.
+See `mail-source-bind'."
+  `(let ,(mail-source-bind-common-1)
+     (mail-source-set-common-1 source)
+     ,@body))
+
+(put 'mail-source-bind-common 'lisp-indent-function 1)
+(put 'mail-source-bind-common 'edebug-form-spec '(sexp body))
+
+(defun mail-source-value (value)
+  "Return the value of VALUE."
+  (cond
+   ;; String
+   ((stringp value)
+    value)
+   ;; Function
+   ((and (listp value) (symbolp (car value)) (fboundp (car value)))
+    (eval value))
+   ;; Just return the value.
+   (t
+    value)))
+
+(autoload 'nnheader-message "nnheader")
+
+(defun mail-source-fetch (source callback &optional method)
+  "Fetch mail from SOURCE and call CALLBACK zero or more times.
+CALLBACK will be called with the name of the file where (some of)
+the mail from SOURCE is put.
+Return the number of files that were found."
+  (mail-source-bind-common source
+    (if (or mail-source-plugged plugged)
+       (save-excursion
+         ;; Special-case the `file' handler since it's so common and
+         ;; just adds noise.
+         (when (or (not (eq (car source) 'file))
+                   (mail-source-bind (file source)
+                     (file-exists-p path)))
+           (nnheader-message 4 "%sReading incoming mail from %s..."
+                             (if method
+                                 (format "%s: " method)
+                               "")
+                             (car source)))
+         (let ((function (cadr (assq (car source) mail-source-fetcher-alist)))
+               (found 0))
+           (unless function
+             (error "%S is an invalid mail source specification" source))
+           ;; If there's anything in the crash box, we do it first.
+           (when (file-exists-p mail-source-crash-box)
+             (message "Processing mail from %s..." mail-source-crash-box)
+             (setq found (mail-source-callback
+                          callback mail-source-crash-box))
+             (mail-source-delete-crash-box))
+           (+ found
+              (if (or debug-on-quit debug-on-error)
+                  (funcall function source callback)
+                (condition-case err
+                    (funcall function source callback)
+                  (error
+                   (if (and (not mail-source-ignore-errors)
+                            (not
+                             (yes-or-no-p
+                              (format "Mail source %s error (%s).  Continue? "
+                                      (if (memq ':password source)
+                                          (let ((s (copy-sequence source)))
+                                            (setcar (cdr (memq ':password s))
+                                                    "********")
+                                            s)
+                                        source)
+                                      (cadr err)))))
+                     (error "Cannot get new mail"))
+                   0)))))))))
+
+(declare-function gnus-message "gnus-util" (level &rest args))
+
+(defun mail-source-delete-old-incoming (&optional age confirm)
+  "Remove incoming files older than AGE days.
+If CONFIRM is non-nil, ask for confirmation before removing a file."
+  (interactive "P")
+  (require 'gnus-util)
+  (let* ((high2days (/ 65536.0 60 60 24));; convert high bits to days
+        (low2days  (/ 1.0 65536.0))     ;; convert low bits to days
+        (diff (if (natnump age) age 30));; fallback, if no valid AGE given
+        currday files)
+    (setq files (directory-files
+                mail-source-directory t
+                (concat "\\`"
+                        (regexp-quote mail-source-incoming-file-prefix)))
+         currday (* (car (current-time)) high2days)
+         currday (+ currday (* low2days (nth 1 (current-time)))))
+    (while files
+      (let* ((ffile (car files))
+            (bfile (gnus-replace-in-string
+                    ffile "\\`.*/\\([^/]+\\)\\'" "\\1"))
+            (filetime (nth 5 (file-attributes ffile)))
+            (fileday (* (car filetime) high2days))
+            (fileday (+ fileday (* low2days (nth 1 filetime)))))
+       (setq files (cdr files))
+       (when (and (> (- currday fileday) diff)
+                  (if confirm
+                      (y-or-n-p
+                       (gnus-format-message "\
+Delete old (> %s day(s)) incoming mail file `%s'? " diff bfile))
+                    (gnus-message 8 "\
+Deleting old (> %s day(s)) incoming mail file `%s'." diff bfile)
+                    t))
+         (delete-file ffile))))))
+
+(defun mail-source-callback (callback info)
+  "Call CALLBACK on the mail file.  Pass INFO on to CALLBACK."
+  (if (or (not (file-exists-p mail-source-crash-box))
+         (zerop (nth 7 (file-attributes mail-source-crash-box))))
+      (progn
+       (when (file-exists-p mail-source-crash-box)
+         (delete-file mail-source-crash-box))
+       0)
+    (funcall callback mail-source-crash-box info)))
+
+(autoload 'gnus-float-time "gnus-util")
+
+(defvar mail-source-incoming-last-checked-time nil)
+
+(defun mail-source-delete-crash-box ()
+  (when (file-exists-p mail-source-crash-box)
+    ;; Delete or move the incoming mail out of the way.
+    (if (eq mail-source-delete-incoming t)
+       (delete-file mail-source-crash-box)
+      (let ((incoming
+            (mm-make-temp-file
+             (expand-file-name
+              mail-source-incoming-file-prefix
+              mail-source-directory))))
+       (unless (file-exists-p (file-name-directory incoming))
+         (make-directory (file-name-directory incoming) t))
+       (rename-file mail-source-crash-box incoming t)
+       ;; remove old incoming files?
+       (when (natnump mail-source-delete-incoming)
+         ;; Don't check for old incoming files more than once per day to
+         ;; save a lot of file accesses.
+         (when (or (null mail-source-incoming-last-checked-time)
+                   (> (gnus-float-time
+                       (time-since mail-source-incoming-last-checked-time))
+                      (* 24 60 60)))
+           (setq mail-source-incoming-last-checked-time (current-time))
+           (mail-source-delete-old-incoming
+            mail-source-delete-incoming
+            mail-source-delete-old-incoming-confirm)))))))
+
+(defun mail-source-movemail (from to)
+  "Move FROM to TO using movemail."
+  (if (not (file-writable-p to))
+      (error "Can't write to crash box %s.  Not moving mail" to)
+    (let ((to (file-truename (expand-file-name to)))
+         errors result)
+      (setq to (file-truename to)
+           from (file-truename from))
+      ;; Set TO if have not already done so, and rename or copy
+      ;; the file FROM to TO if and as appropriate.
+      (cond
+       ((file-exists-p to)
+       ;; The crash box exists already.
+       t)
+       ((not (file-exists-p from))
+       ;; There is no inbox.
+       (setq to nil))
+       ((zerop (nth 7 (file-attributes from)))
+       ;; Empty file.
+       (setq to nil))
+       (t
+       ;; If getting from mail spool directory, use movemail to move
+       ;; rather than just renaming, so as to interlock with the
+       ;; mailer.
+       (unwind-protect
+           (save-excursion
+             (setq errors (generate-new-buffer " *mail source loss*"))
+             (let ((default-directory "/"))
+               (setq result
+                     (apply
+                      'call-process
+                      (append
+                       (list
+                        (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 (or (not (buffer-modified-p errors))
+                          (zerop (buffer-size errors)))
+                      (and (numberp result)
+                           (zerop result)))
+                 ;; No output => movemail won.
+                 t
+               (set-buffer errors)
+               ;; There may be a warning about older revisions.  We
+               ;; ignore that.
+               (goto-char (point-min))
+               (if (search-forward "older revision" nil t)
+                   t
+                 ;; Probably a real error.
+                 (subst-char-in-region (point-min) (point-max) ?\n ?\  )
+                 (goto-char (point-max))
+                 (skip-chars-backward " \t")
+                 (delete-region (point) (point-max))
+                 (goto-char (point-min))
+                 (when (looking-at "movemail: ")
+                   (delete-region (point-min) (match-end 0)))
+                 ;; Result may be a signal description string.
+                 (unless (yes-or-no-p
+                          (format "movemail: %s (%s return).  Continue? "
+                                  (buffer-string) result))
+                   (error "%s" (buffer-string)))
+                 (setq to nil)))))))
+      (when (and errors
+                (buffer-name errors))
+       (kill-buffer errors))
+      ;; Return whether we moved successfully or not.
+      to)))
+
+(defun mail-source-fetch-with-program (program)
+  (eq 0 (call-process shell-file-name nil nil nil
+                     shell-command-switch program)))
+
+(defun mail-source-run-script (script spec &optional delay)
+  (when script
+    (if (functionp script)
+       (funcall script)
+      (mail-source-call-script
+       (format-spec script spec))))
+  (when delay
+    (sleep-for delay)))
+
+(defun mail-source-call-script (script)
+  (let ((background nil)
+       (stderr (get-buffer-create " *mail-source-stderr*"))
+       result)
+    (when (string-match "& *$" script)
+      (setq script (substring script 0 (match-beginning 0))
+           background 0))
+    (setq result
+         (call-process shell-file-name nil stderr nil
+                       shell-command-switch script))
+    (if (and result
+             (not (zerop result)))
+        (progn
+          (split-window-vertically)
+          (other-window 1)
+          (switch-to-buffer stderr)
+          (message "Mail source error: %s " (buffer-string)))
+      (kill-buffer stderr))))
+
+;;;
+;;; Different fetchers
+;;;
+
+(defun mail-source-fetch-file (source callback)
+  "Fetcher for single-file sources."
+  (mail-source-bind (file source)
+    (mail-source-run-script
+     prescript (format-spec-make ?t mail-source-crash-box)
+     prescript-delay)
+    (let ((mail-source-string (format "file:%s" path)))
+      (if (mail-source-movemail path mail-source-crash-box)
+         (prog1
+             (mail-source-callback callback path)
+           (mail-source-run-script
+            postscript (format-spec-make ?t mail-source-crash-box))
+           (mail-source-delete-crash-box))
+       0))))
+
+(defun mail-source-fetch-directory (source callback)
+  "Fetcher for directory sources."
+  (mail-source-bind (directory source)
+    (mail-source-run-script
+     prescript (format-spec-make ?t path) prescript-delay)
+    (let ((found 0)
+         (mail-source-string (format "directory:%s" path)))
+      (dolist (file (directory-files
+                    path t (concat (regexp-quote suffix) "$")))
+       (when (and (file-regular-p file)
+                  (funcall predicate file)
+                  (mail-source-movemail file mail-source-crash-box))
+         (incf found (mail-source-callback callback file))
+         (mail-source-run-script postscript (format-spec-make ?t path))
+         (mail-source-delete-crash-box)))
+      found)))
+
+(defun mail-source-fetch-pop (source callback)
+  "Fetcher for single-file sources."
+  (mail-source-bind (pop source)
+    ;; fixme: deal with stream type in format specs
+    (mail-source-run-script
+     prescript
+     (format-spec-make ?p password ?t mail-source-crash-box
+                      ?s server ?P port ?u user)
+     prescript-delay)
+    (let ((from (format "%s:%s:%s" server user port))
+         (mail-source-string (format "pop:%s@%s" user server))
+         (process-environment (if server
+                                  (cons (concat "MAILHOST=" server)
+                                        process-environment)
+                                process-environment))
+         result)
+      (when (eq authentication 'password)
+       (setq password
+             (or password
+                 (cdr (assoc from mail-source-password-cache))
+                 (read-passwd
+                  (format "Password for %s at %s: " user server)))))
+      (setq result
+           (cond
+            (program
+             (mail-source-fetch-with-program
+              (format-spec
+               program
+               (format-spec-make ?p password ?t mail-source-crash-box
+                                 ?s server ?P port ?u user))))
+            (function
+             (funcall function mail-source-crash-box))
+            ;; The default is to use pop3.el.
+            (t
+             (require 'pop3)
+             (let ((pop3-password password)
+                   (pop3-maildrop user)
+                   (pop3-mailhost server)
+                   (pop3-port port)
+                   (pop3-authentication-scheme
+                    (if (eq authentication 'apop) 'apop 'pass))
+                   (pop3-stream-type stream)
+                   (pop3-leave-mail-on-server leave))
+               (if (or debug-on-quit debug-on-error)
+                   (save-excursion (pop3-movemail mail-source-crash-box))
+                 (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)
+             (unless (assoc from mail-source-password-cache)
+               (push (cons from password) mail-source-password-cache)))
+           (prog1
+               (mail-source-callback callback server)
+             ;; Update display-time's mail flag, if relevant.
+             (if (equal source mail-source-primary-source)
+                 (setq mail-source-new-mail-available nil))
+             (mail-source-run-script
+              postscript
+              (format-spec-make ?p password ?t mail-source-crash-box
+                                ?s server ?P port ?u user))
+             (mail-source-delete-crash-box)))
+       ;; 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))
+       0))))
+
+(defun mail-source-check-pop (source)
+  "Check whether there is new mail."
+  (mail-source-bind (pop source)
+    (let ((from (format "%s:%s:%s" server user port))
+         (mail-source-string (format "pop:%s@%s" user server))
+         (process-environment (if server
+                                  (cons (concat "MAILHOST=" server)
+                                        process-environment)
+                                process-environment))
+         result)
+      (when (eq authentication 'password)
+       (setq password
+             (or password
+                 (cdr (assoc from mail-source-password-cache))
+                 (read-passwd
+                  (format "Password for %s at %s: " user server))))
+       (unless (assoc from mail-source-password-cache)
+         (push (cons from password) mail-source-password-cache)))
+      (setq result
+           (cond
+            ;; No easy way to check whether mail is waiting for these.
+            (program)
+            (function)
+            ;; The default is to use pop3.el.
+            (t
+             (require 'pop3)
+             (let ((pop3-password password)
+                   (pop3-maildrop user)
+                   (pop3-mailhost server)
+                   (pop3-port port)
+                   (pop3-authentication-scheme
+                    (if (eq authentication 'apop) 'apop 'pass)))
+               (if (or debug-on-quit debug-on-error)
+                   (save-excursion (pop3-get-message-count))
+                 (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))
+       ;; 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)))
+      result)))
+
+(defun mail-source-touch-pop ()
+  "Open and close a POP connection shortly.
+POP server should be defined in `mail-source-primary-source' (which is
+preferred) or `mail-sources'.  You may use it for the POP-before-SMTP
+authentication.  To do that, you need to set the
+`message-send-mail-function' variable as `message-smtpmail-send-it'
+and put the following line in your ~/.gnus.el file:
+
+\(add-hook \\='message-send-mail-hook \\='mail-source-touch-pop)
+
+See the Gnus manual for details."
+  (let ((sources (if mail-source-primary-source
+                    (list mail-source-primary-source)
+                  mail-sources)))
+    (while sources
+      (if (eq 'pop (car (car sources)))
+         (mail-source-check-pop (car sources)))
+      (setq sources (cdr sources)))))
+
+(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)
+
+
+(defvar mail-source-report-new-mail nil)
+(defvar mail-source-report-new-mail-timer nil)
+(defvar mail-source-report-new-mail-idle-timer nil)
+
+(defun mail-source-start-idle-timer ()
+  ;; Start our idle timer if necessary, so we delay the check until the
+  ;; user isn't typing.
+  (unless mail-source-report-new-mail-idle-timer
+    (setq mail-source-report-new-mail-idle-timer
+         (run-with-idle-timer
+          mail-source-idle-time-delay
+          nil
+          (lambda ()
+            (unwind-protect
+                (mail-source-check-pop mail-source-primary-source)
+              (setq mail-source-report-new-mail-idle-timer nil)))))
+    ;; Since idle timers created when Emacs is already in the idle
+    ;; state don't get activated until Emacs _next_ becomes idle, we
+    ;; need to force our timer to be considered active now.  We do
+    ;; this by being naughty and poking the timer internals directly
+    ;; (element 0 of the vector is nil if the timer is active).
+    (aset mail-source-report-new-mail-idle-timer 0 nil)))
+
+(defun mail-source-report-new-mail (arg)
+  "Toggle whether to report when new mail is available.
+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"))
+  (let ((on (if (null arg)
+               (not mail-source-report-new-mail)
+             (> (prefix-numeric-value arg) 0))))
+    (setq mail-source-report-new-mail on)
+    (and mail-source-report-new-mail-timer
+        (nnheader-cancel-timer mail-source-report-new-mail-timer))
+    (and mail-source-report-new-mail-idle-timer
+        (nnheader-cancel-timer mail-source-report-new-mail-idle-timer))
+    (setq mail-source-report-new-mail-timer nil)
+    (setq mail-source-report-new-mail-idle-timer nil)
+    (if on
+       (progn
+         (require 'time)
+         ;; display-time-mail-function is an Emacs feature.
+         (setq display-time-mail-function #'mail-source-new-mail-p)
+         ;; Set up the main timer.
+         (setq mail-source-report-new-mail-timer
+               (run-at-time
+                (* 60 mail-source-report-new-mail-interval)
+                (* 60 mail-source-report-new-mail-interval)
+                #'mail-source-start-idle-timer))
+         ;; When you get new mail, clear "Mail" from the mode line.
+         (add-hook 'nnmail-post-get-new-mail-hook
+                   'display-time-event-handler)
+         (message "Mail check enabled"))
+      (setq display-time-mail-function nil)
+      (remove-hook 'nnmail-post-get-new-mail-hook
+                  'display-time-event-handler)
+      (message "Mail check disabled"))))
+
+(defun mail-source-fetch-maildir (source callback)
+  "Fetcher for maildir sources."
+  (mail-source-bind (maildir source)
+    (let ((found 0)
+         mail-source-string)
+      (unless (string-match "/$" path)
+       (setq path (concat path "/")))
+      (dolist (subdir subdirs)
+       (when (file-directory-p (concat path subdir))
+         (setq mail-source-string (format "maildir:%s%s" path subdir))
+         (dolist (file (directory-files (concat path subdir) t))
+           (when (and (not (file-directory-p file))
+                      (not (if function
+                               ;; `function' should return nil if successful.
+                               (funcall function file mail-source-crash-box)
+                             (let ((coding-system-for-write
+                                    mm-text-coding-system)
+                                   (coding-system-for-read
+                                    mm-text-coding-system))
+                               (with-temp-file mail-source-crash-box
+                                 (insert-file-contents file)
+                                 (goto-char (point-min))
+;;;                              ;; Unix mail format
+;;;                              (unless (looking-at "\n*From ")
+;;;                                (insert "From maildir "
+;;;                                        (current-time-string) "\n"))
+;;;                              (while (re-search-forward "^From " nil t)
+;;;                                (replace-match ">From "))
+;;;                              (goto-char (point-max))
+;;;                              (insert "\n\n")
+                                 ;; MMDF mail format
+                                 (insert "\001\001\001\001\n"))
+                               (delete-file file)
+                               nil))))
+             (incf found (mail-source-callback callback file))
+             (mail-source-delete-crash-box)))))
+      found)))
+
+(autoload 'imap-open "imap")
+(autoload 'imap-authenticate "imap")
+(autoload 'imap-mailbox-select "imap")
+(autoload 'imap-mailbox-unselect "imap")
+(autoload 'imap-mailbox-close "imap")
+(autoload 'imap-search "imap")
+(autoload 'imap-fetch "imap")
+(autoload 'imap-close "imap")
+(autoload 'imap-error-text "imap")
+(autoload 'imap-message-flags-add "imap")
+(autoload 'imap-list-to-message-set "imap")
+(autoload 'imap-range-to-message-set "imap")
+(autoload 'nnheader-ms-strip-cr "nnheader")
+
+(autoload 'gnus-compress-sequence "gnus-range")
+
+(defvar mail-source-imap-file-coding-system 'binary
+  "Coding system for the crashbox made by `mail-source-fetch-imap'.")
+
+;; Autoloads will bring in imap before this is called.
+(declare-function imap-capability "imap" (&optional identifier buffer))
+
+(defun mail-source-fetch-imap (source callback)
+  "Fetcher for imap sources."
+  (mail-source-bind (imap source)
+    (mail-source-run-script
+     prescript (format-spec-make ?p password ?t mail-source-crash-box
+                                ?s server ?P port ?u user)
+     prescript-delay)
+    (let ((from (format "%s:%s:%s" server user port))
+         (found 0)
+         (buf (generate-new-buffer " *imap source*"))
+         (mail-source-string (format "imap:%s:%s" server mailbox))
+         (imap-shell-program (or (list program) imap-shell-program))
+         remove)
+      (if (and (imap-open server port stream authentication buf)
+              (imap-authenticate
+               user (or (cdr (assoc from mail-source-password-cache))
+                         password) buf))
+          (let ((mailbox-list (if (listp mailbox) mailbox (list mailbox))))
+            (dolist (mailbox mailbox-list)
+              (when (imap-mailbox-select mailbox nil buf)
+         (let ((coding-system-for-write mail-source-imap-file-coding-system)
+               str)
+            (message "Fetching from %s..." mailbox)
+           (with-temp-file mail-source-crash-box
+             ;; Avoid converting 8-bit chars from inserted strings to
+             ;; multibyte.
+             (mm-disable-multibyte)
+             ;; remember password
+             (with-current-buffer buf
+               (when (and imap-password
+                          (not (assoc from mail-source-password-cache)))
+                 (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
+                           (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
+                   (insert str "\n\n"))
+                 (while (let ((case-fold-search nil))
+                          (re-search-forward "^From " nil t))
+                   (replace-match ">From "))
+                 (goto-char (point-max))))
+             (nnheader-ms-strip-cr))
+           (incf found (mail-source-callback callback server))
+           (mail-source-delete-crash-box)
+           (when (and remove fetchflag)
+             (setq remove (nreverse remove))
+             (imap-message-flags-add
+              (imap-range-to-message-set (gnus-compress-sequence remove))
+              fetchflag nil buf))
+           (if dontexpunge
+               (imap-mailbox-unselect buf)
+              (imap-mailbox-close nil buf)))))
+            (imap-close buf))
+       (imap-close buf)
+       ;; 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))
+       (error "IMAP error: %s" (imap-error-text buf)))
+      (kill-buffer buf)
+      (mail-source-run-script
+       postscript
+       (format-spec-make ?p password ?t mail-source-crash-box
+                        ?s server ?P port ?u user))
+      found)))
+
+(provide 'mail-source)
+
+;;; mail-source.el ends here
diff --git a/xemacs-packages/gnus/lisp/mailcap.el b/xemacs-packages/gnus/lisp/mailcap.el
new file mode 100644 (file)
index 0000000..bf7ba08
--- /dev/null
@@ -0,0 +1,1077 @@
+;;; mailcap.el --- MIME media types configuration
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: William M. Perry <wmperry@aventail.com>
+;;     Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: news, mail, multimedia
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Provides configuration of MIME media types from directly from Lisp
+;; and via the usual mailcap mechanism (RFC 1524).  Deals with
+;; mime.types similarly.
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(autoload 'mail-header-parse-content-type "mail-parse")
+
+;; `mm-delete-duplicates' is an alias for `delete-dups' in Emacs 22.
+(defalias 'mailcap-delete-duplicates
+  (if (fboundp 'delete-dups)
+      'delete-dups
+    (autoload 'mm-delete-duplicates "mm-util")
+    'mm-delete-duplicates))
+
+;; `mailcap-replace-in-string' is an alias like `gnus-replace-in-string'.
+(eval-and-compile
+  (cond
+   ((fboundp 'replace-regexp-in-string)
+    (defun mailcap-replace-in-string  (string regexp newtext &optional literal)
+      "Replace all matches for REGEXP with NEWTEXT in STRING.
+If LITERAL is non-nil, insert NEWTEXT literally.  Return a new
+string containing the replacements.
+This is a compatibility function for different Emacsen."
+      (replace-regexp-in-string regexp newtext string nil literal)))
+   ((fboundp 'replace-in-string)
+    (defalias 'mailcap-replace-in-string 'replace-in-string))))
+
+(defgroup mailcap nil
+  "Definition of viewers for MIME types."
+  :version "21.1"
+  :group 'mime)
+
+(defvar mailcap-parse-args-syntax-table
+  (let ((table (copy-syntax-table emacs-lisp-mode-syntax-table)))
+    (modify-syntax-entry ?' "\"" table)
+    (modify-syntax-entry ?` "\"" table)
+    (modify-syntax-entry ?{ "(" table)
+    (modify-syntax-entry ?} ")" table)
+    table)
+  "A syntax table for parsing SGML attributes.")
+
+(eval-and-compile
+  (when (featurep 'xemacs)
+    (condition-case nil
+       (require 'lpr)
+      (error nil))))
+
+(defvar mailcap-print-command
+  (mapconcat 'identity
+            (cons (if (boundp 'lpr-command)
+                      lpr-command
+                    "lpr")
+                  (when (boundp 'lpr-switches)
+                    (if (stringp lpr-switches)
+                        (list lpr-switches)
+                      lpr-switches)))
+            " ")
+  "Shell command (including switches) used to print PostScript files.")
+
+;; Postpone using defcustom for this as it's so big and we essentially
+;; have to have two copies of the data around then.  Perhaps just
+;; customize the Lisp viewers and rely on the normal configuration
+;; files for the rest?  -- fx
+(defvar mailcap-mime-data
+  `(("application"
+     ("vnd\\.ms-excel"
+      (viewer . "gnumeric %s")
+      (test   . (getenv "DISPLAY"))
+      (type . "application/vnd.ms-excel"))
+     ("x-x509-ca-cert"
+      (viewer . ssl-view-site-cert)
+      (type . "application/x-x509-ca-cert"))
+     ("x-x509-user-cert"
+      (viewer . ssl-view-user-cert)
+      (type . "application/x-x509-user-cert"))
+     ("octet-stream"
+      (viewer . mailcap-save-binary-file)
+      (non-viewer . t)
+      (type . "application/octet-stream"))
+     ("dvi"
+      (viewer . "xdvi -safer %s")
+      (test   . (eq window-system 'x))
+      ("needsx11")
+      (type   . "application/dvi")
+      ("print" . "dvips -qRP %s"))
+     ("dvi"
+      (viewer . "dvitty %s")
+      (test   . (not (getenv "DISPLAY")))
+      (type   . "application/dvi")
+      ("print" . "dvips -qRP %s"))
+     ("emacs-lisp"
+      (viewer . mailcap-maybe-eval)
+      (type   . "application/emacs-lisp"))
+     ("x-emacs-lisp"
+      (viewer . mailcap-maybe-eval)
+      (type   . "application/x-emacs-lisp"))
+     ("x-tar"
+      (viewer . mailcap-save-binary-file)
+      (non-viewer . t)
+      (type   . "application/x-tar"))
+     ("x-latex"
+      (viewer . tex-mode)
+      (type   . "application/x-latex"))
+     ("x-tex"
+      (viewer . tex-mode)
+      (type   . "application/x-tex"))
+     ("latex"
+      (viewer . tex-mode)
+      (type   . "application/latex"))
+     ("tex"
+      (viewer . tex-mode)
+      (type   . "application/tex"))
+     ("texinfo"
+      (viewer . texinfo-mode)
+      (type   . "application/tex"))
+     ("zip"
+      (viewer . mailcap-save-binary-file)
+      (non-viewer . t)
+      (type   . "application/zip")
+      ("copiousoutput"))
+     ("pdf"
+      (viewer . pdf-view-mode)
+      (type . "application/pdf")
+      (test . (eq window-system 'x)))
+     ("pdf"
+      (viewer . doc-view-mode)
+      (type . "application/pdf")
+      (test . (eq window-system 'x)))
+     ("pdf"
+      (viewer . "gv -safer %s")
+      (type . "application/pdf")
+      (test . window-system)
+      ("print" . ,(concat "pdf2ps %s - | " mailcap-print-command)))
+     ("pdf"
+      (viewer . "gpdf %s")
+      (type . "application/pdf")
+      ("print" . ,(concat "pdftops %s - | " mailcap-print-command))
+      (test . (eq window-system 'x)))
+     ("pdf"
+      (viewer . "xpdf %s")
+      (type . "application/pdf")
+      ("print" . ,(concat "pdftops %s - | " mailcap-print-command))
+      (test . (eq window-system 'x)))
+     ("pdf"
+      (viewer . ,(concat "pdftotext %s -"))
+      (type   . "application/pdf")
+      ("print" . ,(concat "pdftops %s - | " mailcap-print-command))
+      ("copiousoutput"))
+     ("postscript"
+      (viewer . "gv -safer %s")
+      (type . "application/postscript")
+      (test   . window-system)
+      ("print" . ,(concat mailcap-print-command " %s"))
+      ("needsx11"))
+     ("postscript"
+      (viewer . "ghostview -dSAFER %s")
+      (type . "application/postscript")
+      (test   . (eq window-system 'x))
+      ("print" . ,(concat mailcap-print-command " %s"))
+      ("needsx11"))
+     ("postscript"
+      (viewer . "ps2ascii %s")
+      (type . "application/postscript")
+      (test . (not (getenv "DISPLAY")))
+      ("print" . ,(concat mailcap-print-command " %s"))
+      ("copiousoutput"))
+     ("sieve"
+      (viewer . sieve-mode)
+      (type   . "application/sieve"))
+     ("pgp-keys"
+      (viewer . "gpg --import --interactive --verbose")
+      (type   . "application/pgp-keys")
+      ("needsterminal")))
+    ("audio"
+     ("x-mpeg"
+      (viewer . "maplay %s")
+      (type   . "audio/x-mpeg"))
+     (".*"
+      (viewer . "showaudio")
+      (type   . "audio/*")))
+    ("message"
+     ("rfc-*822"
+      (viewer . mm-view-message)
+      (test   . (and (featurep 'gnus)
+                    (gnus-alive-p)))
+      (type   . "message/rfc822"))
+     ("rfc-*822"
+      (viewer . vm-mode)
+      (type   . "message/rfc822"))
+     ("rfc-*822"
+      (viewer . view-mode)
+      (type   . "message/rfc822")))
+    ("image"
+     ("x-xwd"
+      (viewer  . "xwud -in %s")
+      (type    . "image/x-xwd")
+      ("compose" . "xwd -frame > %s")
+      (test    . (eq window-system 'x))
+      ("needsx11"))
+     ("x11-dump"
+      (viewer . "xwud -in %s")
+      (type . "image/x-xwd")
+      ("compose" . "xwd -frame > %s")
+      (test   . (eq window-system 'x))
+      ("needsx11"))
+     ("windowdump"
+      (viewer . "xwud -in %s")
+      (type . "image/x-xwd")
+      ("compose" . "xwd -frame > %s")
+      (test   . (eq window-system 'x))
+      ("needsx11"))
+     (".*"
+      (viewer . "display %s")
+      (type . "image/*")
+      (test   . (eq window-system 'x))
+      ("needsx11"))
+     (".*"
+      (viewer . "ee %s")
+      (type . "image/*")
+      (test   . (eq window-system 'x))
+      ("needsx11")))
+    ("text"
+     ("plain"
+      (viewer  . view-mode)
+      (type    . "text/plain"))
+     ("plain"
+      (viewer  . fundamental-mode)
+      (type    . "text/plain"))
+     ("enriched"
+      (viewer . enriched-decode)
+      (type   . "text/enriched"))
+     ("dns"
+      (viewer . dns-mode)
+      (type   . "text/dns")))
+    ("video"
+     ("mpeg"
+      (viewer . "mpeg_play %s")
+      (type   . "video/mpeg")
+      (test   . (eq window-system 'x))
+      ("needsx11")))
+    ("x-world"
+     ("x-vrml"
+      (viewer  . "webspace -remote %s -URL %u")
+      (type    . "x-world/x-vrml")
+      ("description"
+       "VRML document")))
+    ("archive"
+     ("tar"
+      (viewer . tar-mode)
+      (type . "archive/tar"))))
+  "The mailcap structure is an assoc list of assoc lists.
+1st assoc list is keyed on the major content-type
+2nd assoc list is keyed on the minor content-type (which can be a regexp)
+
+Which looks like:
+-----------------
+ ((\"application\"
+   (\"postscript\" . <info>))
+  (\"text\"
+   (\"plain\" . <info>)))
+
+Where <info> is another assoc list of the various information
+related to the mailcap RFC 1524.  This is keyed on the lowercase
+attribute name (viewer, test, etc).  This looks like:
+ ((viewer . VIEWERINFO)
+  (test   . TESTINFO)
+  (xxxx   . \"STRING\")
+  FLAG)
+
+Where VIEWERINFO specifies how the content-type is viewed.  Can be
+a string, in which case it is run through a shell, with appropriate
+parameters, or a symbol, in which case the symbol is `funcall'ed if
+and only if it exists as a function, with the buffer as an argument.
+
+TESTINFO is a test for the viewer's applicability, or nil.  If nil, it
+means the viewer is always valid.  If it is a Lisp function, it is
+called with a list of items from any extra fields from the
+Content-Type header as argument to return a boolean value for the
+validity.  Otherwise, if it is a non-function Lisp symbol or list
+whose car is a symbol, it is `eval'led to yield the validity.  If it
+is a string or list of strings, it represents a shell command to run
+to return a true or false shell value for the validity.")
+(put 'mailcap-mime-data 'risky-local-variable t)
+
+(defcustom mailcap-download-directory nil
+  "*Directory to which `mailcap-save-binary-file' downloads files by default.
+nil means your home directory."
+  :type '(choice (const :tag "Home directory" nil)
+                directory)
+  :group 'mailcap)
+
+(defvar mailcap-poor-system-types
+  '(ms-dos windows-nt)
+  "Systems that don't have a Unix-like directory hierarchy.")
+
+;;;
+;;; Utility functions
+;;;
+
+(defun mailcap-save-binary-file ()
+  (goto-char (point-min))
+  (unwind-protect
+      (let ((file (read-file-name
+                  "Filename to save as: "
+                  (or mailcap-download-directory "~/")))
+           (require-final-newline nil))
+       (write-region (point-min) (point-max) file))
+    (kill-buffer (current-buffer))))
+
+(defvar mailcap-maybe-eval-warning
+  "*** WARNING ***
+
+This MIME part contains untrusted and possibly harmful content.
+If you evaluate the Emacs Lisp code contained in it, a lot of nasty
+things can happen.  Please examine the code very carefully before you
+instruct Emacs to evaluate it.  You can browse the buffer containing
+the code using \\[scroll-other-window].
+
+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)))
+    (goto-char (point-min))
+    (when
+       (save-window-excursion
+         (delete-other-windows)
+         (let ((buffer (get-buffer-create (generate-new-buffer-name
+                                           "*Warning*"))))
+           (unwind-protect
+               (with-current-buffer buffer
+                 (insert (substitute-command-keys
+                          mailcap-maybe-eval-warning))
+                 (goto-char (point-min))
+                 (display-buffer buffer)
+                 (yes-or-no-p "This is potentially dangerous emacs-lisp code, evaluate it? "))
+             (kill-buffer buffer))))
+      (eval-buffer (current-buffer)))
+    (when (buffer-live-p lisp-buffer)
+      (with-current-buffer lisp-buffer
+       (emacs-lisp-mode)))))
+
+
+;;;
+;;; The mailcap parser
+;;;
+
+(defun mailcap-replace-regexp (regexp to-string)
+  ;; Quiet replace-regexp.
+  (goto-char (point-min))
+  (while (re-search-forward regexp nil t)
+    (replace-match to-string t nil)))
+
+(defvar mailcap-parsed-p nil)
+
+(defun mailcap-parse-mailcaps (&optional path force)
+  "Parse out all the mailcaps specified in a path string PATH.
+Components of PATH are separated by the `path-separator' character
+appropriate for this system.  If FORCE, re-parse even if already
+parsed.  If PATH is omitted, use the value of environment variable
+MAILCAPS if set; otherwise (on Unix) use the path from RFC 1524, plus
+/usr/local/etc/mailcap."
+  (interactive (list nil t))
+  (when (or (not mailcap-parsed-p)
+           force)
+    (cond
+     (path nil)
+     ((getenv "MAILCAPS") (setq path (getenv "MAILCAPS")))
+     ((memq system-type mailcap-poor-system-types)
+      (setq path '("~/.mailcap" "~/mail.cap" "~/etc/mail.cap")))
+     (t (setq path
+             ;; This is per RFC 1524, specifically
+             ;; with /usr before /usr/local.
+             '("~/.mailcap" "/etc/mailcap" "/usr/etc/mailcap"
+               "/usr/local/etc/mailcap"))))
+    (let ((fnames (reverse
+                  (if (stringp path)
+                      (split-string path path-separator t)
+                    path)))
+         fname)
+      (while fnames
+       (setq fname (car fnames))
+       (if (and (file-readable-p fname)
+                (file-regular-p fname))
+           (mailcap-parse-mailcap fname))
+       (setq fnames (cdr fnames))))
+      (setq mailcap-parsed-p t)))
+
+(defun mailcap-parse-mailcap (fname)
+  "Parse out the mailcap file specified by FNAME."
+  (let (major                          ; The major mime type (image/audio/etc)
+       minor                           ; The minor mime type (gif, basic, etc)
+       save-pos                        ; Misc saved positions used in parsing
+       viewer                          ; How to view this mime type
+       info                            ; Misc info about this mime type
+       )
+    (with-temp-buffer
+      (insert-file-contents fname)
+      (set-syntax-table mailcap-parse-args-syntax-table)
+      (mailcap-replace-regexp "#.*" "")        ; Remove all comments
+      (mailcap-replace-regexp "\\\\[ \t]*\n" " ") ; And collapse spaces
+      (mailcap-replace-regexp "\n+" "\n") ; And blank lines
+      (goto-char (point-max))
+      (skip-chars-backward " \t\n")
+      (delete-region (point) (point-max))
+      (while (not (bobp))
+       (skip-chars-backward " \t\n")
+       (beginning-of-line)
+       (setq save-pos (point)
+             info nil)
+       (skip-chars-forward "^/; \t\n")
+       (downcase-region save-pos (point))
+       (setq major (buffer-substring save-pos (point)))
+       (skip-chars-forward " \t")
+       (setq minor "")
+       (when (eq (char-after) ?/)
+         (forward-char)
+         (skip-chars-forward " \t")
+         (setq save-pos (point))
+         (skip-chars-forward "^; \t\n")
+         (downcase-region save-pos (point))
+         (setq minor
+               (cond
+                ((eq ?* (or (char-after save-pos) 0)) ".*")
+                ((= (point) save-pos) ".*")
+                (t (regexp-quote (buffer-substring save-pos (point)))))))
+       (skip-chars-forward " \t")
+       ;;; Got the major/minor chunks, now for the viewers/etc
+       ;;; The first item _must_ be a viewer, according to the
+       ;;; RFC for mailcap files (#1524)
+       (setq viewer "")
+       (when (eq (char-after) ?\;)
+         (forward-char)
+         (skip-chars-forward " \t")
+         (setq save-pos (point))
+         (skip-chars-forward "^;\n")
+         ;; skip \;
+         (while (eq (char-before) ?\\)
+           (backward-delete-char 1)
+           (forward-char)
+           (skip-chars-forward "^;\n"))
+         (if (eq (or (char-after save-pos) 0) ?')
+             (setq viewer (progn
+                            (narrow-to-region (1+ save-pos) (point))
+                            (goto-char (point-min))
+                            (prog1
+                                (read (current-buffer))
+                              (goto-char (point-max))
+                              (widen))))
+           (setq viewer (buffer-substring save-pos (point)))))
+       (setq save-pos (point))
+       (end-of-line)
+       (unless (equal viewer "")
+         (setq info (nconc (list (cons 'viewer viewer)
+                                 (cons 'type (concat major "/"
+                                                     (if (string= minor ".*")
+                                                         "*" minor))))
+                           (mailcap-parse-mailcap-extras save-pos (point))))
+         (mailcap-mailcap-entry-passes-test info)
+         (mailcap-add-mailcap-entry major minor info))
+       (beginning-of-line)))))
+
+(defun mailcap-parse-mailcap-extras (st nd)
+  "Grab all the extra stuff from a mailcap entry."
+  (let (
+       name                            ; From name=
+       value                           ; its value
+       results                         ; Assoc list of results
+       name-pos                        ; Start of XXXX= position
+       val-pos                         ; Start of value position
+       done                            ; Found end of \'d ;s?
+       )
+    (save-restriction
+      (narrow-to-region st nd)
+      (goto-char (point-min))
+      (skip-chars-forward " \n\t;")
+      (while (not (eobp))
+       (setq done nil)
+       (setq name-pos (point))
+       (skip-chars-forward "^ \n\t=;")
+       (downcase-region name-pos (point))
+       (setq name (buffer-substring name-pos (point)))
+       (skip-chars-forward " \t\n")
+       (if (not (eq (char-after (point)) ?=)) ; There is no value
+           (setq value t)
+         (skip-chars-forward " \t\n=")
+         (setq val-pos (point))
+         (if (memq (char-after val-pos) '(?\" ?'))
+             (progn
+               (setq val-pos (1+ val-pos))
+               (condition-case nil
+                   (progn
+                     (forward-sexp 1)
+                     (backward-char 1))
+                 (error (goto-char (point-max)))))
+           (while (not done)
+             (skip-chars-forward "^;")
+             (if (eq (char-after (1- (point))) ?\\ )
+                 (progn
+                   (subst-char-in-region (1- (point)) (point) ?\\ ? )
+                   (skip-chars-forward ";"))
+               (setq done t))))
+         (setq value (buffer-substring val-pos (point))))
+       ;; `test' as symbol, others like "copiousoutput" and "needsx11" as
+       ;; strings
+       (setq results (cons (cons (if (string-equal name "test")
+                                      'test
+                                    name)
+                                  value) results))
+       (skip-chars-forward " \";\n\t"))
+      results)))
+
+(defun mailcap-mailcap-entry-passes-test (info)
+  "Replace the test clause of INFO itself with a boolean for some cases.
+This function supports only `test -n $DISPLAY' and `test -z $DISPLAY',
+replaces them with t or nil.  As for others or if INFO has a interactive
+spec (needsterm, needsterminal, or needsx11) but DISPLAY is not set,
+the test clause will be unchanged."
+  (let ((test (assq 'test info))       ; The test clause
+       status)
+    (setq status (and test (split-string (cdr test) " ")))
+    (if (and (or (assoc "needsterm" info)
+                (assoc "needsterminal" info)
+                (assoc "needsx11" info))
+            (not (getenv "DISPLAY")))
+       (setq status nil)
+      (cond
+       ((and (equal (nth 0 status) "test")
+            (equal (nth 1 status) "-n")
+            (or (equal (nth 2 status) "$DISPLAY")
+                (equal (nth 2 status) "\"$DISPLAY\"")))
+       (setq status (if (getenv "DISPLAY") t nil)))
+       ((and (equal (nth 0 status) "test")
+            (equal (nth 1 status) "-z")
+            (or (equal (nth 2 status) "$DISPLAY")
+                (equal (nth 2 status) "\"$DISPLAY\"")))
+       (setq status (if (getenv "DISPLAY") nil t)))
+       (test nil)
+       (t nil)))
+    (and test (listp test) (setcdr test status))))
+
+;;;
+;;; The action routines.
+;;;
+
+(defun mailcap-possible-viewers (major minor)
+  "Return a list of possible viewers from MAJOR for minor type MINOR."
+  (let ((exact '())
+       (wildcard '()))
+    (while major
+      (cond
+       ((equal (car (car major)) minor)
+       (setq exact (cons (cdr (car major)) exact)))
+       ((and minor (string-match (concat "^" (car (car major)) "$") minor))
+       (setq wildcard (cons (cdr (car major)) wildcard))))
+      (setq major (cdr major)))
+    (nconc exact wildcard)))
+
+(defun mailcap-unescape-mime-test (test type-info)
+  (let (save-pos save-chr subst)
+    (cond
+     ((symbolp test) test)
+     ((and (listp test) (symbolp (car test))) test)
+     ((or (stringp test)
+         (and (listp test) (stringp (car test))
+              (setq test (mapconcat 'identity test " "))))
+      (with-temp-buffer
+       (insert test)
+       (goto-char (point-min))
+       (while (not (eobp))
+         (skip-chars-forward "^%")
+         (if (/= (- (point)
+                    (progn (skip-chars-backward "\\\\")
+                           (point)))
+                 0)                    ; It is an escaped %
+             (progn
+               (delete-char 1)
+               (skip-chars-forward "%."))
+           (setq save-pos (point))
+           (skip-chars-forward "%")
+           (setq save-chr (char-after (point)))
+           ;; Escapes:
+           ;; %s: name of a file for the body data
+           ;; %t: content-type
+           ;; %{<parameter name}: value of parameter in mailcap entry
+           ;; %n: number of sub-parts for multipart content-type
+           ;; %F: a set of content-type/filename pairs for multiparts
+           (cond
+            ((null save-chr) nil)
+            ((= save-chr ?t)
+             (delete-region save-pos (progn (forward-char 1) (point)))
+             (insert (or (cdr (assq 'type type-info)) "\"\"")))
+            ((memq save-chr '(?M ?n ?F))
+             (delete-region save-pos (progn (forward-char 1) (point)))
+             (insert "\"\""))
+            ((= save-chr ?{)
+             (forward-char 1)
+             (skip-chars-forward "^}")
+             (downcase-region (+ 2 save-pos) (point))
+             (setq subst (buffer-substring (+ 2 save-pos) (point)))
+             (delete-region save-pos (1+ (point)))
+             (insert (or (cdr (assoc subst type-info)) "\"\"")))
+            (t nil))))
+       (buffer-string)))
+     (t (error "Bad value to mailcap-unescape-mime-test: %s" test)))))
+
+(defvar mailcap-viewer-test-cache nil)
+
+(defun mailcap-viewer-passes-test (viewer-info type-info)
+  "Return non-nil if viewer specified by VIEWER-INFO passes its test clause.
+Also return non-nil if it has no test clause.  TYPE-INFO is an argument
+to supply to the test."
+  (let* ((test-info (assq 'test viewer-info))
+        (test (cdr test-info))
+        (otest test)
+        (viewer (cdr (assq 'viewer viewer-info)))
+        (default-directory (expand-file-name "~/"))
+        status parsed-test cache result)
+    (cond ((not (or (stringp viewer) (fboundp viewer)))
+          nil)                         ; Non-existent Lisp function
+         ((setq cache (assoc test mailcap-viewer-test-cache))
+          (cadr cache))
+         ((not test-info) t)           ; No test clause
+         (t
+          (setq
+           result
+           (cond
+            ((not test) nil)           ; Already failed test
+            ((eq test t) t)            ; Already passed test
+            ((functionp test)          ; Lisp function as test
+             (funcall test type-info))
+            ((and (symbolp test)       ; Lisp variable as test
+                  (boundp test))
+             (symbol-value test))
+            ((and (listp test)         ; List to be eval'd
+                  (symbolp (car test)))
+             (eval test))
+            (t
+             (setq test (mailcap-unescape-mime-test test type-info)
+                   test (list shell-file-name nil nil nil
+                              shell-command-switch test)
+                   status (apply 'call-process test))
+             (eq 0 status))))
+          (push (list otest result) mailcap-viewer-test-cache)
+          result))))
+
+(defun mailcap-add-mailcap-entry (major minor info)
+  (let ((old-major (assoc major mailcap-mime-data)))
+    (if (null old-major)               ; New major area
+       (setq mailcap-mime-data
+             (cons (cons major (list (cons minor info)))
+                   mailcap-mime-data))
+      (let ((cur-minor (assoc minor old-major)))
+       (cond
+        ((or (null cur-minor)          ; New minor area, or
+             (assq 'test info))        ; Has a test, insert at beginning
+         (setcdr old-major (cons (cons minor info) (cdr old-major))))
+        ((and (not (assq 'test info))  ; No test info, replace completely
+              (not (assq 'test cur-minor))
+              (equal (assq 'viewer info)  ; Keep alternative viewer
+                     (assq 'viewer cur-minor)))
+         (setcdr cur-minor info))
+        (t
+         (setcdr old-major (cons (cons minor info) (cdr old-major))))))
+      )))
+
+(defun mailcap-add (type viewer &optional test)
+  "Add VIEWER as a handler for TYPE.
+If TEST is not given, it defaults to t."
+  (let ((tl (split-string type "/")))
+    (when (or (not (car tl))
+             (not (cadr tl)))
+      (error "%s is not a valid MIME type" type))
+    (mailcap-add-mailcap-entry
+     (car tl) (cadr tl)
+     `((viewer . ,viewer)
+       (test . ,(if test test t))
+       (type . ,type)))))
+
+;;;
+;;; The main whabbo
+;;;
+
+(defun mailcap-viewer-lessp (x y)
+  "Return t if viewer X is more desirable than viewer Y."
+  (let ((x-wild (string-match "[*?]" (or (cdr-safe (assq 'type x)) "")))
+       (y-wild (string-match "[*?]" (or (cdr-safe (assq 'type y)) "")))
+       (x-lisp (not (stringp (or (cdr-safe (assq 'viewer x)) ""))))
+       (y-lisp (not (stringp (or (cdr-safe (assq 'viewer y)) "")))))
+    (cond
+     ((and x-wild (not y-wild))
+      nil)
+     ((and (not x-wild) y-wild)
+      t)
+     ((and (not y-lisp) x-lisp)
+      t)
+     (t nil))))
+
+(defun mailcap-mime-info (string &optional request no-decode)
+  "Get the MIME viewer command for STRING, return nil if none found.
+Expects a complete content-type header line as its argument.
+
+Second argument REQUEST specifies what information to return.  If it is
+nil or the empty string, the viewer (second field of the mailcap
+entry) will be returned.  If it is a string, then the mailcap field
+corresponding to that string will be returned (print, description,
+whatever).  If a number, then all the information for this specific
+viewer is returned.  If `all', then all possible viewers for
+this type is returned.
+
+If NO-DECODE is non-nil, don't decode STRING."
+  ;; NO-DECODE avoids calling `mail-header-parse-content-type' from
+  ;; `mail-parse.el'
+  (let (
+       major                           ; Major encoding (text, etc)
+       minor                           ; Minor encoding (html, etc)
+       info                            ; Other info
+       save-pos                        ; Misc. position during parse
+       major-info                      ; (assoc major mailcap-mime-data)
+       minor-info                      ; (assoc minor major-info)
+       test                            ; current test proc.
+       viewers                         ; Possible viewers
+       passed                          ; Viewers that passed the test
+       viewer                          ; The one and only viewer
+       ctl)
+    (save-excursion
+      (setq ctl
+           (if no-decode
+               (list (or string "text/plain"))
+             (mail-header-parse-content-type (or string "text/plain"))))
+      (setq major (split-string (car ctl) "/"))
+      (setq minor (cadr major)
+           major (car major))
+      (when (setq major-info (cdr (assoc major mailcap-mime-data)))
+       (when (setq viewers (mailcap-possible-viewers major-info minor))
+         (setq info (mapcar (lambda (a) (cons (symbol-name (car a))
+                                              (cdr a)))
+                            (cdr ctl)))
+         (while viewers
+           (if (mailcap-viewer-passes-test (car viewers) info)
+               (setq passed (cons (car viewers) passed)))
+           (setq viewers (cdr viewers)))
+         (setq passed (sort passed 'mailcap-viewer-lessp))
+         (setq viewer (car passed))))
+      (when (and (stringp (cdr (assq 'viewer viewer)))
+                passed)
+       (setq viewer (car passed)))
+      (cond
+       ((and (null viewer) (not (equal major "default")) request)
+       (mailcap-mime-info "default" request no-decode))
+       ((or (null request) (equal request ""))
+       (mailcap-unescape-mime-test (cdr (assq 'viewer viewer)) info))
+       ((stringp request)
+       (mailcap-unescape-mime-test
+        (cdr-safe (assoc request viewer)) info))
+       ((eq request 'all)
+       passed)
+       (t
+       ;; MUST make a copy *sigh*, else we modify mailcap-mime-data
+       (setq viewer (copy-sequence viewer))
+       (let ((view (assq 'viewer viewer))
+             (test (assq 'test viewer)))
+         (if view (setcdr view (mailcap-unescape-mime-test (cdr view) info)))
+         (if test (setcdr test (mailcap-unescape-mime-test (cdr test) info))))
+       viewer)))))
+
+;;;
+;;; Experimental MIME-types parsing
+;;;
+
+(defvar mailcap-mime-extensions
+  '((""       . "text/plain")
+    (".1"     . "text/plain")  ;; Manual pages
+    (".3"     . "text/plain")
+    (".8"     . "text/plain")
+    (".abs"   . "audio/x-mpeg")
+    (".aif"   . "audio/aiff")
+    (".aifc"  . "audio/aiff")
+    (".aiff"  . "audio/aiff")
+    (".ano"   . "application/x-annotator")
+    (".au"    . "audio/ulaw")
+    (".avi"   . "video/x-msvideo")
+    (".bcpio" . "application/x-bcpio")
+    (".bin"   . "application/octet-stream")
+    (".cdf"   . "application/x-netcdr")
+    (".cpio"  . "application/x-cpio")
+    (".csh"   . "application/x-csh")
+    (".css"   . "text/css")
+    (".dvi"   . "application/x-dvi")
+    (".diff"  . "text/x-patch")
+    (".dpatch". "test/x-patch")
+    (".el"    . "application/emacs-lisp")
+    (".eps"   . "application/postscript")
+    (".etx"   . "text/x-setext")
+    (".exe"   . "application/octet-stream")
+    (".fax"   . "image/x-fax")
+    (".gif"   . "image/gif")
+    (".hdf"   . "application/x-hdf")
+    (".hqx"   . "application/mac-binhex40")
+    (".htm"   . "text/html")
+    (".html"  . "text/html")
+    (".icon"  . "image/x-icon")
+    (".ief"   . "image/ief")
+    (".jpg"   . "image/jpeg")
+    (".macp"  . "image/x-macpaint")
+    (".man"   . "application/x-troff-man")
+    (".me"    . "application/x-troff-me")
+    (".mif"   . "application/mif")
+    (".mov"   . "video/quicktime")
+    (".movie" . "video/x-sgi-movie")
+    (".mp2"   . "audio/x-mpeg")
+    (".mp3"   . "audio/x-mpeg")
+    (".mp2a"  . "audio/x-mpeg2")
+    (".mpa"   . "audio/x-mpeg")
+    (".mpa2"  . "audio/x-mpeg2")
+    (".mpe"   . "video/mpeg")
+    (".mpeg"  . "video/mpeg")
+    (".mpega" . "audio/x-mpeg")
+    (".mpegv" . "video/mpeg")
+    (".mpg"   . "video/mpeg")
+    (".mpv"   . "video/mpeg")
+    (".ms"    . "application/x-troff-ms")
+    (".nc"    . "application/x-netcdf")
+    (".nc"    . "application/x-netcdf")
+    (".oda"   . "application/oda")
+    (".patch" . "text/x-patch")
+    (".pbm"   . "image/x-portable-bitmap")
+    (".pdf"   . "application/pdf")
+    (".pgm"   . "image/portable-graymap")
+    (".pict"  . "image/pict")
+    (".png"   . "image/png")
+    (".pnm"   . "image/x-portable-anymap")
+    (".pod"   . "text/plain")
+    (".ppm"   . "image/portable-pixmap")
+    (".ps"    . "application/postscript")
+    (".qt"    . "video/quicktime")
+    (".ras"   . "image/x-raster")
+    (".rgb"   . "image/x-rgb")
+    (".rtf"   . "application/rtf")
+    (".rtx"   . "text/richtext")
+    (".sh"    . "application/x-sh")
+    (".sit"   . "application/x-stuffit")
+    (".siv"   . "application/sieve")
+    (".snd"   . "audio/basic")
+    (".soa"   . "text/dns")
+    (".src"   . "application/x-wais-source")
+    (".tar"   . "archive/tar")
+    (".tcl"   . "application/x-tcl")
+    (".tex"   . "application/x-tex")
+    (".texi"  . "application/texinfo")
+    (".tga"   . "image/x-targa")
+    (".tif"   . "image/tiff")
+    (".tiff"  . "image/tiff")
+    (".tr"    . "application/x-troff")
+    (".troff" . "application/x-troff")
+    (".tsv"   . "text/tab-separated-values")
+    (".txt"   . "text/plain")
+    (".vbs"   . "video/mpeg")
+    (".vox"   . "audio/basic")
+    (".vrml"  . "x-world/x-vrml")
+    (".wav"   . "audio/x-wav")
+    (".xls"   . "application/vnd.ms-excel")
+    (".wrl"   . "x-world/x-vrml")
+    (".xbm"   . "image/xbm")
+    (".xpm"   . "image/xpm")
+    (".xwd"   . "image/windowdump")
+    (".zip"   . "application/zip")
+    (".ai"    . "application/postscript")
+    (".jpe"   . "image/jpeg")
+    (".jpeg"  . "image/jpeg")
+    (".org"   . "text/x-org"))
+  "An alist of file extensions and corresponding MIME content-types.
+This exists for you to customize the information in Lisp.  It is
+merged with values from mailcap files by `mailcap-parse-mimetypes'.")
+
+(defvar mailcap-mimetypes-parsed-p nil)
+
+(defun mailcap-parse-mimetypes (&optional path force)
+  "Parse out all the mimetypes specified in a Unix-style path string PATH.
+Components of PATH are separated by the `path-separator' character
+appropriate for this system.  If PATH is omitted, use the value of
+environment variable MIMETYPES if set; otherwise use a default path.
+If FORCE, re-parse even if already parsed."
+  (interactive (list nil t))
+  (when (or (not mailcap-mimetypes-parsed-p)
+           force)
+    (cond
+     (path nil)
+     ((getenv "MIMETYPES") (setq path (getenv "MIMETYPES")))
+     ((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
+             ;; on current GNUish systems.  The search order follows
+             ;; that for mailcap.
+             '("~/.mime.types"
+               "/etc/mime.types"
+               "/usr/etc/mime.types"
+               "/usr/local/etc/mime.types"
+               "/usr/local/www/conf/mime.types"
+               "~/.mime-types"
+               "/etc/mime-types"
+               "/usr/etc/mime-types"
+               "/usr/local/etc/mime-types"
+               "/usr/local/www/conf/mime-types"))))
+    (let ((fnames (reverse (if (stringp path)
+                              (split-string path path-separator t)
+                            path)))
+         fname)
+      (while fnames
+       (setq fname (car fnames))
+       (if (and (file-readable-p fname))
+           (mailcap-parse-mimetype-file fname))
+       (setq fnames (cdr fnames))))
+    (setq mailcap-mimetypes-parsed-p t)))
+
+(defun mailcap-parse-mimetype-file (fname)
+  "Parse out a mime-types file FNAME."
+  (let (type                           ; The MIME type for this line
+       extns                           ; The extensions for this line
+       save-pos                        ; Misc. saved buffer positions
+       )
+    (with-temp-buffer
+      (insert-file-contents fname)
+      (mailcap-replace-regexp "#.*" "")
+      (mailcap-replace-regexp "\n+" "\n")
+      (mailcap-replace-regexp "[ \t]+$" "")
+      (goto-char (point-max))
+      (skip-chars-backward " \t\n")
+      (delete-region (point) (point-max))
+      (goto-char (point-min))
+      (while (not (eobp))
+       (skip-chars-forward " \t\n")
+       (setq save-pos (point))
+       (skip-chars-forward "^ \t\n")
+       (downcase-region save-pos (point))
+       (setq type (buffer-substring save-pos (point)))
+       (while (not (eolp))
+         (skip-chars-forward " \t")
+         (setq save-pos (point))
+         (skip-chars-forward "^ \t\n")
+         (setq extns (cons (buffer-substring save-pos (point)) extns)))
+       (while extns
+         (setq mailcap-mime-extensions
+               (cons
+                (cons (if (= (string-to-char (car extns)) ?.)
+                          (car extns)
+                        (concat "." (car extns))) type)
+                mailcap-mime-extensions)
+               extns (cdr extns)))))))
+
+(defun mailcap-extension-to-mime (extn)
+  "Return the MIME content type of the file extensions EXTN."
+  (mailcap-parse-mimetypes)
+  (if (and (stringp extn)
+          (not (eq (string-to-char extn) ?.)))
+      (setq extn (concat "." extn)))
+  (cdr (assoc (downcase extn) mailcap-mime-extensions)))
+
+;; Unused?
+(defalias 'mailcap-command-p 'executable-find)
+
+(defun mailcap-mime-types ()
+  "Return a list of MIME media types."
+  (mailcap-parse-mimetypes)
+  (mailcap-delete-duplicates
+   (nconc
+    (mapcar 'cdr mailcap-mime-extensions)
+    (apply
+     'nconc
+     (mapcar
+      (lambda (l)
+       (delq nil
+             (mapcar
+              (lambda (m)
+                (let ((type (cdr (assq 'type (cdr m)))))
+                  (if (equal (cadr (split-string type "/"))
+                             "*")
+                      nil
+                    type)))
+              (cdr l))))
+      mailcap-mime-data)))))
+
+;;;
+;;; Useful supplementary functions
+;;;
+
+(defun mailcap-file-default-commands (files)
+  "Return a list of default commands for FILES."
+  (mailcap-parse-mailcaps)
+  (mailcap-parse-mimetypes)
+  (let* ((all-mime-type
+         ;; All unique MIME types from file extensions
+         (mailcap-delete-duplicates
+          (mapcar (lambda (file)
+                    (mailcap-extension-to-mime
+                     (file-name-extension file t)))
+                  files)))
+        (all-mime-info
+         ;; All MIME info lists
+         (mailcap-delete-duplicates
+          (mapcar (lambda (mime-type)
+                    (mailcap-mime-info mime-type 'all))
+                  all-mime-type)))
+        (common-mime-info
+         ;; Intersection of mime-infos from different mime-types;
+         ;; or just the first MIME info for a single MIME type
+         (if (cdr all-mime-info)
+             (delq nil (mapcar (lambda (mi1)
+                                 (unless (memq nil (mapcar
+                                                    (lambda (mi2)
+                                                      (member mi1 mi2))
+                                                    (cdr all-mime-info)))
+                                   mi1))
+                               (car all-mime-info)))
+           (car all-mime-info)))
+        (commands
+         ;; Command strings from `viewer' field of the MIME info
+         (mailcap-delete-duplicates
+          (delq nil (mapcar (lambda (mime-info)
+                              (let ((command (cdr (assoc 'viewer mime-info))))
+                                (if (stringp command)
+                                    (mailcap-replace-in-string
+                                     ;; Replace mailcap's `%s' placeholder
+                                     ;; with dired's `?' placeholder
+                                     (mailcap-replace-in-string
+                                      ;; Remove the final filename placeholder
+                                      command "[ \t\n]*\\('\\)?%s\\1?[ \t\n]*\\'" "" t)
+                                     "%s" "?" t))))
+                            common-mime-info)))))
+    commands))
+
+(defun mailcap-view-mime (type)
+  "View the data in the current buffer that has MIME type TYPE.
+`mailcap-mime-data' determines the method to use."
+  (let ((method (mailcap-mime-info type)))
+    (if (stringp method)
+       (shell-command-on-region (point-min) (point-max)
+                                ;; Use stdin as the "%s".
+                                (format method "-")
+                                (current-buffer)
+                                t)
+      (funcall method))))
+
+(provide 'mailcap)
+
+;;; mailcap.el ends here
diff --git a/xemacs-packages/gnus/lisp/md4.el b/xemacs-packages/gnus/lisp/md4.el
new file mode 100644 (file)
index 0000000..e75128b
--- /dev/null
@@ -0,0 +1,228 @@
+;;; md4.el --- MD4 Message Digest Algorithm.
+
+;; Copyright (C) 2001, 2004, 2007-2016 Free Software Foundation, Inc.
+
+;; Author: Taro Kawagishi <tarok@transpulse.org>
+;; Keywords: MD4
+;; Version: 1.00
+;; Created: February 2001
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Code:
+
+;;;
+;;; MD4 hash calculation
+
+(defvar md4-buffer (make-vector 4 '(0 . 0))
+  "Work buffer of four 32-bit integers.")
+
+(defun md4 (in n)
+  "Return the MD4 hash for a string IN of length N bytes.
+The returned hash is 16 bytes long.  N is required to handle
+strings containing the character 0."
+  (let (m
+       (b (cons 0 (* n 8)))
+       (i 0)
+       (buf (make-string 128 0)) c4)
+    ;; initial values
+    (aset md4-buffer 0 '(26437 . 8961))                ;0x67452301
+    (aset md4-buffer 1 '(61389 . 43913))       ;0xefcdab89
+    (aset md4-buffer 2 '(39098 . 56574))       ;0x98badcfe
+    (aset md4-buffer 3 '(4146 . 21622))                ;0x10325476
+
+    ;; process the string in 64 bits chunks
+    (while (> n 64)
+      (setq m (md4-copy64 (substring in 0 64)))
+      (md4-64 m)
+      (setq in (substring in 64))
+      (setq n (- n 64)))
+
+    ;; process the rest of the string (length is now n <= 64)
+    (setq i 0)
+    (while (< i n)
+      (aset buf i (aref in i))
+      (setq i (1+ i)))
+    (aset buf n 128)                   ;0x80
+    (if (<= n 55)
+       (progn
+         (setq c4 (md4-pack-int32 b))
+         (aset buf 56 (aref c4 0))
+         (aset buf 57 (aref c4 1))
+         (aset buf 58 (aref c4 2))
+         (aset buf 59 (aref c4 3))
+         (setq m (md4-copy64 buf))
+         (md4-64 m))
+      ;; else
+      (setq c4 (md4-pack-int32 b))
+      (aset buf 120 (aref c4 0))
+      (aset buf 121 (aref c4 1))
+      (aset buf 122 (aref c4 2))
+      (aset buf 123 (aref c4 3))
+      (setq m (md4-copy64 buf))
+      (md4-64 m)
+      (setq m (md4-copy64 (substring buf 64)))
+      (md4-64 m)))
+
+    (concat (md4-pack-int32 (aref md4-buffer 0))
+           (md4-pack-int32 (aref md4-buffer 1))
+           (md4-pack-int32 (aref md4-buffer 2))
+           (md4-pack-int32 (aref md4-buffer 3))))
+
+(defsubst md4-F (x y z) (logior (logand x y) (logand (lognot x) z)))
+(defsubst md4-G (x y z) (logior (logand x y) (logand x z) (logand y z)))
+(defsubst md4-H (x y z) (logxor x y z))
+
+(defmacro md4-make-step (name func)
+  `(defun ,name (a b c d xk s ac)
+     (let*
+         ((h1 (+ (car a) (,func (car b) (car c) (car d)) (car xk) (car ac)))
+          (l1 (+ (cdr a) (,func (cdr b) (cdr c) (cdr d)) (cdr xk) (cdr ac)))
+          (h2 (logand 65535 (+ h1 (lsh l1 -16))))
+          (l2 (logand 65535 l1))
+         ;; cyclic shift of 32 bits integer
+          (h3 (logand 65535 (if (> s 15)
+                                (+ (lsh h2 (- s 32)) (lsh l2 (- s 16)))
+                              (+ (lsh h2 s) (lsh l2 (- s 16))))))
+          (l3 (logand 65535 (if (> s 15)
+                                (+ (lsh l2 (- s 32)) (lsh h2 (- s 16)))
+                              (+ (lsh l2 s) (lsh h2 (- s 16)))))))
+       (cons h3 l3))))
+
+(md4-make-step md4-round1 md4-F)
+(md4-make-step md4-round2 md4-G)
+(md4-make-step md4-round3 md4-H)
+
+(defsubst md4-add (x y)
+  "Return 32-bit sum of 32-bit integers X and Y."
+  (let ((h (+ (car x) (car y)))
+       (l (+ (cdr x) (cdr y))))
+    (cons (logand 65535 (+ h (lsh l -16))) (logand 65535 l))))
+
+(defsubst md4-and (x y)
+  (cons (logand (car x) (car y)) (logand (cdr x) (cdr y))))
+
+(defun md4-64 (m)
+  "Calculate MD4 hash of M.
+M is a 64-bytes chunk, represented as 16 pairs of 32-bit integers.
+The resulting MD4 value is placed in `md4-buffer'."
+  (let ((a (aref md4-buffer 0))
+       (b (aref md4-buffer 1))
+       (c (aref md4-buffer 2))
+       (d (aref md4-buffer 3)))
+    (setq a (md4-round1 a b c d (aref m  0)   3 '(0 . 0))
+         d (md4-round1 d a b c (aref m  1)   7 '(0 . 0))
+         c (md4-round1 c d a b (aref m  2)  11 '(0 . 0))
+         b (md4-round1 b c d a (aref m  3)  19 '(0 . 0))
+         a (md4-round1 a b c d (aref m  4)   3 '(0 . 0))
+         d (md4-round1 d a b c (aref m  5)   7 '(0 . 0))
+         c (md4-round1 c d a b (aref m  6)  11 '(0 . 0))
+         b (md4-round1 b c d a (aref m  7)  19 '(0 . 0))
+         a (md4-round1 a b c d (aref m  8)   3 '(0 . 0))
+         d (md4-round1 d a b c (aref m  9)   7 '(0 . 0))
+         c (md4-round1 c d a b (aref m 10)  11 '(0 . 0))
+         b (md4-round1 b c d a (aref m 11)  19 '(0 . 0))
+         a (md4-round1 a b c d (aref m 12)   3 '(0 . 0))
+         d (md4-round1 d a b c (aref m 13)   7 '(0 . 0))
+         c (md4-round1 c d a b (aref m 14)  11 '(0 . 0))
+         b (md4-round1 b c d a (aref m 15)  19 '(0 . 0))
+
+         a (md4-round2 a b c d (aref m  0)   3 '(23170 . 31129)) ;0x5A827999
+         d (md4-round2 d a b c (aref m  4)   5 '(23170 . 31129))
+         c (md4-round2 c d a b (aref m  8)   9 '(23170 . 31129))
+         b (md4-round2 b c d a (aref m 12)  13 '(23170 . 31129))
+         a (md4-round2 a b c d (aref m  1)   3 '(23170 . 31129))
+         d (md4-round2 d a b c (aref m  5)   5 '(23170 . 31129))
+         c (md4-round2 c d a b (aref m  9)   9 '(23170 . 31129))
+         b (md4-round2 b c d a (aref m 13)  13 '(23170 . 31129))
+         a (md4-round2 a b c d (aref m  2)   3 '(23170 . 31129))
+         d (md4-round2 d a b c (aref m  6)   5 '(23170 . 31129))
+         c (md4-round2 c d a b (aref m 10)   9 '(23170 . 31129))
+         b (md4-round2 b c d a (aref m 14)  13 '(23170 . 31129))
+         a (md4-round2 a b c d (aref m  3)   3 '(23170 . 31129))
+         d (md4-round2 d a b c (aref m  7)   5 '(23170 . 31129))
+         c (md4-round2 c d a b (aref m 11)   9 '(23170 . 31129))
+         b (md4-round2 b c d a (aref m 15)  13 '(23170 . 31129))
+
+         a (md4-round3 a b c d (aref m  0)   3 '(28377 . 60321)) ;0x6ED9EBA1
+         d (md4-round3 d a b c (aref m  8)   9 '(28377 . 60321))
+         c (md4-round3 c d a b (aref m  4)  11 '(28377 . 60321))
+         b (md4-round3 b c d a (aref m 12)  15 '(28377 . 60321))
+         a (md4-round3 a b c d (aref m  2)   3 '(28377 . 60321))
+         d (md4-round3 d a b c (aref m 10)   9 '(28377 . 60321))
+         c (md4-round3 c d a b (aref m  6)  11 '(28377 . 60321))
+         b (md4-round3 b c d a (aref m 14)  15 '(28377 . 60321))
+         a (md4-round3 a b c d (aref m  1)   3 '(28377 . 60321))
+         d (md4-round3 d a b c (aref m  9)   9 '(28377 . 60321))
+         c (md4-round3 c d a b (aref m  5)  11 '(28377 . 60321))
+         b (md4-round3 b c d a (aref m 13)  15 '(28377 . 60321))
+         a (md4-round3 a b c d (aref m  3)   3 '(28377 . 60321))
+         d (md4-round3 d a b c (aref m 11)   9 '(28377 . 60321))
+         c (md4-round3 c d a b (aref m  7)  11 '(28377 . 60321))
+         b (md4-round3 b c d a (aref m 15)  15 '(28377 . 60321)))
+
+    (aset md4-buffer 0 (md4-add a (aref md4-buffer 0)))
+    (aset md4-buffer 1 (md4-add b (aref md4-buffer 1)))
+    (aset md4-buffer 2 (md4-add c (aref md4-buffer 2)))
+    (aset md4-buffer 3 (md4-add d (aref md4-buffer 3)))
+    ))
+
+(defun md4-copy64 (seq)
+  "Unpack a 64 bytes string into 16 pairs of 32 bits integers."
+  (let ((int32s (make-vector 16 0)) (i 0) j)
+    (while (< i 16)
+      (setq j (* i 4))
+      (aset int32s i (cons (+ (aref seq (+ j 2)) (lsh (aref seq (+ j 3)) 8))
+                          (+ (aref seq j) (lsh (aref seq (1+ j)) 8))))
+      (setq i (1+ i)))
+    int32s))
+
+;;;
+;;; sub functions
+
+(defun md4-pack-int16 (int16)
+  "Pack 16 bits integer in 2 bytes string as little endian."
+  (let ((str (make-string 2 0)))
+    (aset str 0 (logand int16 255))
+    (aset str 1 (lsh int16 -8))
+    str))
+
+(defun md4-pack-int32 (int32)
+  "Pack 32 bits integer in a 4 bytes string as little endian.
+A 32 bits integer is represented as a pair of two 16 bits
+integers (cons high low)."
+  (let ((str (make-string 4 0))
+       (h (car int32)) (l (cdr int32)))
+    (aset str 0 (logand l 255))
+    (aset str 1 (lsh l -8))
+    (aset str 2 (logand h 255))
+    (aset str 3 (lsh h -8))
+    str))
+
+(defun md4-unpack-int16 (str)
+  (if (eq 2 (length str))
+      (+ (lsh (aref str 1) 8) (aref str 0))
+    (error "%s is not 2 bytes long" str)))
+
+(defun md4-unpack-int32 (str)
+  (if (eq 4 (length str))
+      (cons (+ (lsh (aref str 3) 8) (aref str 2))
+           (+ (lsh (aref str 1) 8) (aref str 0)))
+    (error "%s is not 4 bytes long" str)))
+
+(provide 'md4)
+
+;;; md4.el ends here
diff --git a/xemacs-packages/gnus/lisp/message.el b/xemacs-packages/gnus/lisp/message.el
new file mode 100644 (file)
index 0000000..400ddd1
--- /dev/null
@@ -0,0 +1,8646 @@
+;;; message.el --- composing mail and news messages
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This mode provides mail-sending facilities from within Emacs.  It
+;; consists mainly of large chunks of code from the sendmail.el,
+;; gnus-msg.el and rnewspost.el files.
+
+;;; Code:
+
+(eval-when-compile
+  (require 'cl))
+
+(require 'mailheader)
+(require 'gmm-utils)
+(require 'mail-utils)
+;; Only for the trivial macros mail-header-from, mail-header-date
+;; mail-header-references, mail-header-subject, mail-header-id
+(eval-when-compile (require 'nnheader))
+;; This is apparently necessary even though things are autoloaded.
+;; Because we dynamically bind mail-abbrev-mode-regexp, we'd better
+;; require mailabbrev here.
+(if (featurep 'xemacs)
+    (require 'mail-abbrevs)
+  (require 'mailabbrev))
+(require 'mail-parse)
+(require 'mml)
+(require 'rfc822)
+(require 'format-spec)
+(require 'dired)
+
+(autoload 'mailclient-send-it "mailclient") ;; Emacs 22 or contrib/
+
+(defvar gnus-message-group-art)
+(defvar gnus-list-identifiers) ; gnus-sum is required where necessary
+(defvar rmail-enable-mime-composing)
+
+(defgroup message '((user-mail-address custom-variable)
+                   (user-full-name custom-variable))
+  "Mail and news message composing."
+  :link '(custom-manual "(message)Top")
+  :group 'mail
+  :group 'news)
+
+(put 'user-mail-address 'custom-type 'string)
+(put 'user-full-name 'custom-type 'string)
+
+(defgroup message-various nil
+  "Various Message Variables."
+  :link '(custom-manual "(message)Various Message Variables")
+  :group 'message)
+
+(defgroup message-buffers nil
+  "Message Buffers."
+  :link '(custom-manual "(message)Message Buffers")
+  :group 'message)
+
+(defgroup message-sending nil
+  "Message Sending."
+  :link '(custom-manual "(message)Sending Variables")
+  :group 'message)
+
+(defgroup message-interface nil
+  "Message Interface."
+  :link '(custom-manual "(message)Interface")
+  :group 'message)
+
+(defgroup message-forwarding nil
+  "Message Forwarding."
+  :link '(custom-manual "(message)Forwarding")
+  :group 'message-interface)
+
+(defgroup message-insertion nil
+  "Message Insertion."
+  :link '(custom-manual "(message)Insertion")
+  :group 'message)
+
+(defgroup message-headers nil
+  "Message Headers."
+  :link '(custom-manual "(message)Message Headers")
+  :group 'message)
+
+(defgroup message-news nil
+  "Composing News Messages."
+  :group 'message)
+
+(defgroup message-mail nil
+  "Composing Mail Messages."
+  :group 'message)
+
+(defgroup message-faces nil
+  "Faces used for message composing."
+  :group 'message
+  :group 'faces)
+
+(defcustom message-directory "~/Mail/"
+  "*Directory from which all other mail file variables are derived."
+  :group 'message-various
+  :type 'directory)
+
+(defcustom message-max-buffers 10
+  "*How many buffers to keep before starting to kill them off."
+  :group 'message-buffers
+  :type 'integer)
+
+(defcustom message-send-rename-function nil
+  "Function called to rename the buffer after sending it."
+  :group 'message-buffers
+  :type '(choice function (const nil)))
+
+(defcustom message-fcc-handler-function 'message-output
+  "*A function called to save outgoing articles.
+This function will be called with the name of the file to store the
+article in.  The default function is `message-output' which saves in Unix
+mailbox format."
+  :type '(radio (function-item message-output)
+               (function :tag "Other"))
+  :group 'message-sending)
+
+(defcustom message-fcc-externalize-attachments nil
+  "If non-nil, attachments are included as external parts in Fcc copies."
+  :version "22.1"
+  :type 'boolean
+  :group 'message-sending)
+
+(defcustom message-courtesy-message
+  "The following message is a courtesy copy of an article\nthat has been posted to %s as well.\n\n"
+  "*This is inserted at the start of a mailed copy of a posted message.
+If the string contains the format spec \"%s\", the Newsgroups
+the article has been posted to will be inserted there.
+If this variable is nil, no such courtesy message will be added."
+  :group 'message-sending
+  :type '(radio string (const nil)))
+
+(defcustom message-ignored-bounced-headers
+  "^\\(Received\\|Return-Path\\|Delivered-To\\):"
+  "*Regexp that matches headers to be removed in resent bounced mail."
+  :group 'message-interface
+  :type 'regexp)
+
+(defcustom message-from-style 'default
+  ;; In Emacs 24.1 this defaults to the value of `mail-from-style'
+  ;; that defaults to:
+  ;; `angles' in Emacs 22.1~23.1, XEmacs 21.4, 21.5, and SXEmacs 22.1;
+  ;; `system-default' in Emacs 23.2, and 24.1
+  "Specifies how \"From\" headers look.
+
+If nil, they contain just the return address like:
+       king@grassland.com
+If `parens', they look like:
+       king@grassland.com (Elvis Parsley)
+If `angles', they look like:
+       Elvis Parsley <king@grassland.com>
+
+Otherwise, most addresses look like `angles', but they look like
+`parens' if `angles' would need quoting and `parens' would not."
+  :version "23.2"
+  :type '(choice (const :tag "simple" nil)
+                (const parens)
+                (const angles)
+                (const default))
+  :group 'message-headers)
+
+(defcustom message-insert-canlock t
+  "Whether to insert a Cancel-Lock header in news postings."
+  :version "22.1"
+  :group 'message-headers
+  :type 'boolean)
+
+(defcustom message-syntax-checks
+  (if message-insert-canlock '((sender . disabled)) nil)
+  ;; Guess this one shouldn't be easy to customize...
+  "*Controls what syntax checks should not be performed on outgoing posts.
+To disable checking of long signatures, for instance, add
+ `(signature . disabled)' to this list.
+
+Don't touch this variable unless you really know what you're doing.
+
+Checks include `approved', `bogus-recipient', `continuation-headers',
+`control-chars', `empty', `existing-newsgroups', `from', `illegible-text',
+`invisible-text', `long-header-lines', `long-lines', `message-id',
+`multiple-headers', `new-text', `newsgroups', `quoting-style',
+`repeated-newsgroups', `reply-to', `sender', `sendsys', `shoot',
+`shorten-followup-to', `signature', `size', `subject', `subject-cmsg'
+and `valid-newsgroups'."
+  :group 'message-news
+  :type '(repeat sexp))                        ; Fixme: improve this
+
+(defcustom message-required-headers '((optional . References)
+                                     From)
+  "*Headers to be generated or prompted for when sending a message.
+Also see `message-required-news-headers' and
+`message-required-mail-headers'."
+  :version "22.1"
+  :group 'message-news
+  :group 'message-headers
+  :link '(custom-manual "(message)Message Headers")
+  :type '(repeat sexp))
+
+(defcustom message-draft-headers '(References From Date)
+  "*Headers to be generated when saving a draft message."
+  :version "22.1"
+  :group 'message-news
+  :group 'message-headers
+  :link '(custom-manual "(message)Message Headers")
+  :type '(repeat sexp))
+
+(defcustom message-required-news-headers
+  '(From Newsgroups Subject Date Message-ID
+        (optional . Organization)
+        (optional . User-Agent))
+  "*Headers to be generated or prompted for when posting an article.
+RFC977 and RFC1036 require From, Date, Newsgroups, Subject,
+Message-ID.  Organization, Lines, In-Reply-To, Expires, and
+User-Agent are optional.  If you don't want message to insert some
+header, remove it from this list."
+  :group 'message-news
+  :group 'message-headers
+  :link '(custom-manual "(message)Message Headers")
+  :type '(repeat sexp))
+
+(defcustom message-required-mail-headers
+  '(From Subject Date (optional . In-Reply-To) Message-ID
+        (optional . User-Agent))
+  "*Headers to be generated or prompted for when mailing a message.
+It is recommended that From, Date, To, Subject and Message-ID be
+included.  Organization and User-Agent are optional."
+  :group 'message-mail
+  :group 'message-headers
+  :link '(custom-manual "(message)Message Headers")
+  :type '(repeat sexp))
+
+(defcustom message-prune-recipient-rules nil
+  "Rules for how to prune the list of recipients when doing wide replies.
+This is a list of regexps and regexp matches."
+  :version "24.1"
+  :group 'message-mail
+  :group 'message-headers
+  :link '(custom-manual "(message)Wide Reply")
+  :type '(repeat regexp))
+
+(defcustom message-deletable-headers '(Message-ID Date Lines)
+  "Headers to be deleted if they already exist and were generated by message previously."
+  :group 'message-headers
+  :link '(custom-manual "(message)Message Headers")
+  :type 'sexp)
+
+(defcustom message-ignored-news-headers
+  "^NNTP-Posting-Host:\\|^Xref:\\|^[BGF]cc:\\|^Resent-Fcc:\\|^X-Draft-From:\\|^X-Gnus-Agent-Meta-Information:\\|^X-Message-SMTP-Method:\\|^X-Gnus-Delayed:"
+  "*Regexp of headers to be removed unconditionally before posting."
+  :group 'message-news
+  :group 'message-headers
+  :link '(custom-manual "(message)Message Headers")
+  :type '(repeat :value-to-internal (lambda (widget value)
+                                     (custom-split-regexp-maybe value))
+                :match (lambda (widget value)
+                         (or (stringp value)
+                             (widget-editable-list-match widget value)))
+                regexp))
+
+(defcustom message-ignored-mail-headers
+  "^\\([GF]cc\\|Resent-Fcc\\|Xref\\|X-Draft-From\\|X-Gnus-Agent-Meta-Information\\):"
+  "*Regexp of headers to be removed unconditionally before mailing."
+  :group 'message-mail
+  :group 'message-headers
+  :link '(custom-manual "(message)Mail Headers")
+  :type 'regexp)
+
+(defcustom message-ignored-supersedes-headers "^Path:\\|^Date\\|^NNTP-Posting-Host:\\|^Xref:\\|^Lines:\\|^Received:\\|^X-From-Line:\\|^X-Trace:\\|^X-ID:\\|^X-Complaints-To:\\|Return-Path:\\|^Supersedes:\\|^NNTP-Posting-Date:\\|^X-Trace:\\|^X-Complaints-To:\\|^Cancel-Lock:\\|^Cancel-Key:\\|^X-Hashcash:\\|^X-Payment:\\|^Approved:\\|^Injection-Date:\\|^Injection-Info:"
+  "*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."
+  :group 'message-interface
+  :link '(custom-manual "(message)Superseding")
+  :type '(repeat :value-to-internal (lambda (widget value)
+                                     (custom-split-regexp-maybe value))
+                :match (lambda (widget value)
+                         (or (stringp value)
+                             (widget-editable-list-match widget value)))
+                regexp))
+
+(defcustom message-subject-re-regexp
+  "^[ \t]*\\([Rr][Ee]\\(\\[[0-9]*\\]\\)*:[ \t]*\\)*[ \t]*"
+  "*Regexp matching \"Re: \" in the subject line."
+  :group 'message-various
+  :link '(custom-manual "(message)Message Headers")
+  :type 'regexp)
+
+;;; Start of variables adopted from `message-utils.el'.
+
+(defcustom message-subject-trailing-was-query t
+  "*What to do with trailing \"(was: <old subject>)\" in subject lines.
+If nil, leave the subject unchanged.  If it is the symbol `ask', query
+the user what do do.  In this case, the subject is matched against
+`message-subject-trailing-was-ask-regexp'.  If
+`message-subject-trailing-was-query' is t, always strip the trailing
+old subject.  In this case, `message-subject-trailing-was-regexp' is
+used."
+  :version "24.1"
+  :type '(choice (const :tag "never" nil)
+                (const :tag "always strip" t)
+                (const ask))
+  :link '(custom-manual "(message)Message Headers")
+  :group 'message-various)
+
+(defcustom message-subject-trailing-was-ask-regexp
+  "[ \t]*\\([[(]+[Ww][Aa][Ss]:?[ \t]*.*[])]+\\)"
+  "*Regexp matching \"(was: <old subject>)\" in the subject line.
+
+The function `message-strip-subject-trailing-was' uses this regexp if
+`message-subject-trailing-was-query' is set to the symbol `ask'.  If
+the variable is t instead of `ask', use
+`message-subject-trailing-was-regexp' instead.
+
+It is okay to create some false positives here, as the user is asked."
+  :version "22.1"
+  :group 'message-various
+  :link '(custom-manual "(message)Message Headers")
+  :type 'regexp)
+
+(defcustom message-subject-trailing-was-regexp
+  "[ \t]*\\((*[Ww][Aa][Ss]:[ \t]*.*)\\)"
+  "*Regexp matching \"(was: <old subject>)\" in the subject line.
+
+If `message-subject-trailing-was-query' is set to t, the subject is
+matched against `message-subject-trailing-was-regexp' in
+`message-strip-subject-trailing-was'.  You should use a regexp creating very
+few false positives here."
+  :version "22.1"
+  :group 'message-various
+  :link '(custom-manual "(message)Message Headers")
+  :type 'regexp)
+
+;;; marking inserted text
+
+(defcustom message-mark-insert-begin
+  "--8<---------------cut here---------------start------------->8---\n"
+  "How to mark the beginning of some inserted text."
+  :version "22.1"
+  :type 'string
+  :link '(custom-manual "(message)Insertion Variables")
+  :group 'message-various)
+
+(defcustom message-mark-insert-end
+  "--8<---------------cut here---------------end--------------->8---\n"
+  "How to mark the end of some inserted text."
+  :version "22.1"
+  :type 'string
+  :link '(custom-manual "(message)Insertion Variables")
+  :group 'message-various)
+
+(defcustom message-archive-header "X-No-Archive: Yes\n"
+  "Header to insert when you don't want your article to be archived.
+Archives \(such as groups.google.com) respect this header."
+  :version "22.1"
+  :type 'string
+  :link '(custom-manual "(message)Header Commands")
+  :group 'message-various)
+
+(defcustom message-archive-note
+  "X-No-Archive: Yes - save http://groups.google.com/"
+  "Note to insert why you wouldn't want this posting archived.
+If nil, don't insert any text in the body."
+  :version "22.1"
+  :type '(radio string (const nil))
+  :link '(custom-manual "(message)Header Commands")
+  :group 'message-various)
+
+;;; Crossposts and Followups
+;; inspired by JoH-followup-to by Jochem Huhman <joh  at gmx.de>
+;; new suggestions by R. Weikusat <rw at another.de>
+
+(defvar message-cross-post-old-target nil
+  "Old target for cross-posts or follow-ups.")
+(make-variable-buffer-local 'message-cross-post-old-target)
+
+(defcustom message-cross-post-default t
+  "When non-nil `message-cross-post-followup-to' will perform a crosspost.
+If nil, `message-cross-post-followup-to' will only do a followup.  Note that
+you can explicitly override this setting by calling
+`message-cross-post-followup-to' with a prefix."
+  :version "22.1"
+  :type 'boolean
+  :group 'message-various)
+
+(defcustom message-cross-post-note "Crosspost & Followup-To: "
+  "Note to insert before signature to notify of cross-post and follow-up."
+  :version "22.1"
+  :type 'string
+  :group 'message-various)
+
+(defcustom message-followup-to-note "Followup-To: "
+  "Note to insert before signature to notify of follow-up only."
+  :version "22.1"
+  :type 'string
+  :group 'message-various)
+
+(defcustom message-cross-post-note-function 'message-cross-post-insert-note
+  "Function to use to insert note about Crosspost or Followup-To.
+The function will be called with four arguments.  The function should not only
+insert a note, but also ensure old notes are deleted.  See the documentation
+for `message-cross-post-insert-note'."
+  :version "22.1"
+  :type 'function
+  :group 'message-various)
+
+;;; End of variables adopted from `message-utils.el'.
+
+(defcustom message-signature-separator "^-- $"
+  "Regexp matching the signature separator.
+This variable is used to strip off the signature from quoted text
+when `message-cite-function' is
+`message-cite-original-without-signature'.  Most useful values
+are \"^-- $\" (strict) and \"^-- *$\" (loose; allow missing
+whitespace)."
+  :type '(choice (const :tag "strict" "^-- $")
+                (const :tag "loose" "^-- *$")
+                regexp)
+  :version "22.3" ;; Gnus 5.10.12 (changed default)
+  :link '(custom-manual "(message)Various Message Variables")
+  :group 'message-various)
+
+(defcustom message-elide-ellipsis "\n[...]\n\n"
+  "*The string which is inserted for elided text.
+This is a format-spec string, and you can use %l to say how many
+lines were removed, and %c to say how many characters were
+removed."
+  :type 'string
+  :link '(custom-manual "(message)Various Commands")
+  :group 'message-various)
+
+(defcustom message-interactive t
+  ;; In Emacs 24.1 this defaults to the value of `mail-interactive'
+  ;; that defaults to:
+  ;; `nil' in Emacs 22.1~22.3, XEmacs 21.4, 21.5, and SXEmacs 22.1;
+  ;; `t' in Emacs 23.1~24.1
+  "Non-nil means when sending a message wait for and display errors.
+A value of nil means let mailer mail back a message to report errors."
+  :version "23.2"
+  :group 'message-sending
+  :group 'message-mail
+  :link '(custom-manual "(message)Sending Variables")
+  :type 'boolean)
+
+(defcustom message-confirm-send nil
+  "When non-nil, ask for confirmation when sending a message."
+  :group 'message-sending
+  :group 'message-mail
+  :version "23.1" ;; No Gnus
+  :link '(custom-manual "(message)Sending Variables")
+  :type 'boolean)
+
+(defcustom message-generate-new-buffers 'unsent
+  "*Say whether to create a new message buffer to compose a message.
+Valid values include:
+
+nil
+  Generate the buffer name in the Message way (e.g., *mail*, *news*,
+  *mail to whom*, *news on group*, etc.) and continue editing in the
+  existing buffer of that name.  If there is no such buffer, it will
+  be newly created.
+
+`unique' or t
+  Create the new buffer with the name generated in the Message way.
+
+`unsent'
+  Similar to `unique' but the buffer name begins with \"*unsent \".
+
+`standard'
+  Similar to nil but the buffer name is simpler like *mail message*.
+
+function
+  If this is a function, call that function with three parameters:
+  The type, the To address and the group name (any of these may be nil).
+  The function should return the new buffer name."
+  :version "24.1"
+  :group 'message-buffers
+  :link '(custom-manual "(message)Message Buffers")
+  :type '(choice (const nil)
+                (sexp :tag "unique" :format "unique\n" :value unique
+                      :match (lambda (widget value) (memq value '(unique t))))
+                (const unsent)
+                (const standard)
+                (function :format "\n    %{%t%}: %v")))
+
+(defcustom message-kill-buffer-on-exit nil
+  "*Non-nil means that the message buffer will be killed after sending a message."
+  :group 'message-buffers
+  :link '(custom-manual "(message)Message Buffers")
+  :type 'boolean)
+
+(defcustom message-kill-buffer-query t
+  "*Non-nil means that killing a modified message buffer has to be confirmed.
+This is used by `message-kill-buffer'."
+  :version "23.1" ;; No Gnus
+  :group 'message-buffers
+  :type 'boolean)
+
+(defcustom message-user-organization
+  (or (getenv "ORGANIZATION") t)
+  "String to be used as an Organization header.
+If t, use `message-user-organization-file'."
+  :group 'message-headers
+  :type '(choice string
+                (const :tag "consult file" t)))
+
+(defcustom message-user-organization-file
+  (let (orgfile)
+    (dolist (f (list "/etc/organization"
+                    "/etc/news/organization"
+                    "/usr/lib/news/organization"))
+      (when (file-readable-p f)
+       (setq orgfile f)))
+    orgfile)
+  "*Local news organization file."
+  :type '(choice (const nil) file)
+  :link '(custom-manual "(message)News Headers")
+  :group 'message-headers)
+
+(defcustom message-make-forward-subject-function
+  #'message-forward-subject-name-subject
+  "*List of functions called to generate subject headers for forwarded messages.
+The subject generated by the previous function is passed into each
+successive function.
+
+The provided functions are:
+
+* `message-forward-subject-author-subject' Source of article (author or
+      newsgroup), in brackets followed by the subject
+* `message-forward-subject-name-subject' Source of article (name of author
+      or newsgroup), in brackets followed by the subject
+* `message-forward-subject-fwd' Subject of article with `Fwd:' prepended
+      to it."
+  :group 'message-forwarding
+  :link '(custom-manual "(message)Forwarding")
+  :type '(radio (function-item message-forward-subject-author-subject)
+               (function-item message-forward-subject-fwd)
+               (function-item message-forward-subject-name-subject)
+               (repeat :tag "List of functions" function)))
+
+(defcustom message-forward-as-mime t
+  "*Non-nil means forward messages as an inline/rfc822 MIME section.
+Otherwise, directly inline the old message in the forwarded message."
+  :version "21.1"
+  :group 'message-forwarding
+  :link '(custom-manual "(message)Forwarding")
+  :type 'boolean)
+
+(defcustom message-forward-show-mml 'best
+  "*Non-nil means show forwarded messages as MML (decoded from MIME).
+Otherwise, forwarded messages are unchanged.
+Can also be the symbol `best' to indicate that MML should be
+used, except when it is a bad idea to use MML.  One example where
+it is a bad idea is when forwarding a signed or encrypted
+message, because converting MIME to MML would invalidate the
+digital signature."
+  :version "21.1"
+  :group 'message-forwarding
+  :type '(choice (const :tag "use MML" t)
+                (const :tag "don't use MML " nil)
+                (const :tag "use MML when appropriate" best)))
+
+(defcustom message-forward-before-signature t
+  "*Non-nil means put forwarded message before signature, else after."
+  :group 'message-forwarding
+  :type 'boolean)
+
+(defcustom message-wash-forwarded-subjects nil
+  "*Non-nil means try to remove as much cruft as possible from the subject.
+Done before generating the new subject of a forward."
+  :group 'message-forwarding
+  :link '(custom-manual "(message)Forwarding")
+  :type 'boolean)
+
+(defcustom message-ignored-resent-headers
+  ;; `Delivered-To' needs to be removed because some mailers use it to
+  ;; detect loops, so if you resend a message to an address that ultimately
+  ;; comes back to you (e.g. a mailing-list to which you subscribe, in which
+  ;; case you may be removed from the list on the grounds that mail to you
+  ;; bounced with a "mailing loop" error).
+  "^Return-receipt\\|^X-Gnus\\|^Gnus-Warning:\\|^>?From \\|^Delivered-To:\
+\\|^X-Content-Length:\\|^X-UIDL:"
+  "*All headers that match this regexp will be deleted when resending a message."
+  :version "24.4"
+  :group 'message-interface
+  :link '(custom-manual "(message)Resending")
+  :type '(repeat :value-to-internal (lambda (widget value)
+                                     (custom-split-regexp-maybe value))
+                :match (lambda (widget value)
+                         (or (stringp value)
+                             (widget-editable-list-match widget value)))
+                regexp))
+
+(defcustom message-forward-ignored-headers "^Content-Transfer-Encoding:\\|^X-Gnus"
+  "*All headers that match this regexp will be deleted when forwarding a message.
+This may also be a list of regexps."
+  :version "21.1"
+  :group 'message-forwarding
+  :type '(repeat :value-to-internal (lambda (widget value)
+                                     (custom-split-regexp-maybe value))
+                :match (lambda (widget value)
+                         (or (stringp value)
+                             (widget-editable-list-match widget value)))
+                regexp))
+
+(defcustom message-forward-included-headers nil
+  "If non-nil, delete non-matching headers when forwarding a message.
+Only headers that match this regexp will be included.  This
+variable should be a regexp or a list of regexps."
+  :version "25.1"
+  :group 'message-forwarding
+  :type '(repeat :value-to-internal (lambda (widget value)
+                                     (custom-split-regexp-maybe value))
+                :match (lambda (widget value)
+                         (or (stringp value)
+                             (widget-editable-list-match widget value)))
+                regexp))
+
+(defcustom message-ignored-cited-headers "."
+  "*Delete these headers from the messages you yank."
+  :group 'message-insertion
+  :link '(custom-manual "(message)Insertion Variables")
+  :type 'regexp)
+
+(defcustom message-cite-prefix-regexp
+  ;; In Emacs 24.1 this defaults to the value of
+  ;; `mail-citation-prefix-regexp'; the default value varies according
+  ;; to the Emacs version.  In XEmacs 21.4 and 21.5, sendmail.el
+  ;; provides it.
+  (if (string-match "[[:digit:]]" "1")
+      ;; Support POSIX?  XEmacs 21.5.27 doesn't.
+      "\\([ \t]*[_.[:word:]]+>+\\|[ \t]*[]>|]\\)+"
+    ;; ?-, ?_ or ?. MUST NOT be in syntax entry w.
+    (let (non-word-constituents)
+      (with-syntax-table text-mode-syntax-table
+       (setq non-word-constituents
+             (concat
+              (if (string-match "\\w" "_")  "" "_")
+              (if (string-match "\\w" ".")  "" "."))))
+      (if (equal non-word-constituents "")
+         "\\([ \t]*\\(\\w\\)+>+\\|[ \t]*[]>|]\\)+"
+       (concat "\\([ \t]*\\(\\w\\|["
+               non-word-constituents
+               "]\\)+>+\\|[ \t]*[]>|]\\)+"))))
+  "*Regexp matching the longest possible citation prefix on a line."
+  :version "24.1"
+  :group 'message-insertion
+  :link '(custom-manual "(message)Insertion Variables")
+  :type 'regexp
+  :set (lambda (symbol value)
+        (prog1
+            (custom-set-default symbol value)
+          (if (boundp 'gnus-message-cite-prefix-regexp)
+              (setq gnus-message-cite-prefix-regexp
+                    (concat "^\\(?:" value "\\)"))))))
+
+(defcustom message-cancel-message "I am canceling my own article.\n"
+  "Message to be inserted in the cancel message."
+  :group 'message-interface
+  :link '(custom-manual "(message)Canceling News")
+  :type 'string)
+
+(defun message-send-mail-function ()
+  "Return suitable value for the variable `message-send-mail-function'."
+  (cond ((and (require 'sendmail)
+             (boundp 'sendmail-program)
+             sendmail-program
+             (executable-find sendmail-program))
+        'message-send-mail-with-sendmail)
+       ((and (locate-library "smtpmail")
+             (boundp 'smtpmail-default-smtp-server)
+             smtpmail-default-smtp-server)
+        'message-smtpmail-send-it)
+       ((locate-library "mailclient")
+        'message-send-mail-with-mailclient)
+       (t
+        (error "Don't know how to send mail.  Please customize `message-send-mail-function'"))))
+
+(defun message-default-send-mail-function ()
+  (cond ((eq send-mail-function 'smtpmail-send-it) 'message-smtpmail-send-it)
+       ((eq send-mail-function 'feedmail-send-it) 'feedmail-send-it)
+       ((eq send-mail-function 'sendmail-query-once) 'sendmail-query-once)
+       ((eq send-mail-function 'mailclient-send-it)
+        'message-send-mail-with-mailclient)
+       (t (message-send-mail-function))))
+
+;; Useful to set in site-init.el
+(defcustom message-send-mail-function (message-default-send-mail-function)
+  "Function to call to send the current buffer as mail.
+The headers should be delimited by a line whose contents match the
+variable `mail-header-separator'.
+
+Valid values include `message-send-mail-with-sendmail'
+`message-send-mail-with-mh', `message-send-mail-with-qmail',
+`message-smtpmail-send-it', `smtpmail-send-it',
+`feedmail-send-it' and `message-send-mail-with-mailclient'.  The
+default is system dependent and determined by the function
+`message-send-mail-function'.
+
+See also `send-mail-function'."
+  :type '(radio (function-item message-send-mail-with-sendmail)
+               (function-item message-send-mail-with-mh)
+               (function-item message-send-mail-with-qmail)
+               (function-item message-smtpmail-send-it)
+               (function-item smtpmail-send-it)
+               (function-item feedmail-send-it)
+               (function-item message-send-mail-with-mailclient
+                              :tag "Use Mailclient package")
+               (function :tag "Other"))
+  :group 'message-sending
+  :version "23.2"
+  :initialize 'custom-initialize-default
+  :link '(custom-manual "(message)Mail Variables")
+  :group 'message-mail)
+
+(defcustom message-send-news-function 'message-send-news
+  "Function to call to send the current buffer as news.
+The headers should be delimited by a line whose contents match the
+variable `mail-header-separator'."
+  :group 'message-sending
+  :group 'message-news
+  :link '(custom-manual "(message)News Variables")
+  :type 'function)
+
+(defcustom message-reply-to-function nil
+  "If non-nil, function that should return a list of headers.
+This function should pick out addresses from the To, Cc, and From headers
+and respond with new To and Cc headers."
+  :group 'message-interface
+  :link '(custom-manual "(message)Reply")
+  :type '(choice function (const nil)))
+
+(defcustom message-wide-reply-to-function nil
+  "If non-nil, function that should return a list of headers.
+This function should pick out addresses from the To, Cc, and From headers
+and respond with new To and Cc headers."
+  :group 'message-interface
+  :link '(custom-manual "(message)Wide Reply")
+  :type '(choice function (const nil)))
+
+(defcustom message-followup-to-function nil
+  "If non-nil, function that should return a list of headers.
+This function should pick out addresses from the To, Cc, and From headers
+and respond with new To and Cc headers."
+  :group 'message-interface
+  :link '(custom-manual "(message)Followup")
+  :type '(choice function (const nil)))
+
+(defcustom message-extra-wide-headers nil
+  "If non-nil, a list of additional address headers.
+These are used when composing a wide reply."
+  :group 'message-sending
+  :type '(repeat string))
+
+(defcustom message-use-followup-to 'ask
+  "*Specifies what to do with Followup-To header.
+If nil, always ignore the header.  If it is t, use its value, but
+query before using the \"poster\" value.  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
+  :link '(custom-manual "(message)Followup")
+  :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."
+  :version "22.1"
+  :group 'message-interface
+  :link '(custom-manual "(message)Mailing Lists")
+  :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 subscription 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'."
+  :version "22.1"
+  :group 'message-interface
+  :link '(custom-manual "(message)Mailing Lists")
+  :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."
+  :version "22.1"
+  :group 'message-interface
+  :link '(custom-manual "(message)Mailing Lists")
+  :type '(radio file (const nil)))
+
+(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 conjunction with
+`message-subscribed-address-functions' and `message-subscribed-regexps'."
+  :version "22.1"
+  :group 'message-interface
+  :link '(custom-manual "(message)Mailing Lists")
+  :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 conjunction with
+`message-subscribed-address-functions' and `message-subscribed-addresses'."
+  :version "22.1"
+  :group 'message-interface
+  :link '(custom-manual "(message)Mailing Lists")
+  :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."
+  :version "22.1"
+  :group 'message-interface
+  :link '(custom-manual "(message)Message Headers")
+  :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."
+  :group 'message-sending
+  :link '(custom-manual "(message)Mail Variables")
+  :type 'boolean)
+
+(defcustom message-sendmail-envelope-from nil
+  ;; In Emacs 24.1 this defaults to the value of `mail-envelope-from'
+  ;; if it is available, or defaults to nil.  sendmail.el provides it;
+  ;; the default value is nil in all (X)Emacsen that Gnus supports.
+  "*Envelope-from when sending mail with sendmail.
+If this is nil, use `user-mail-address'.  If it is the symbol
+`header', use the From: header of the message."
+  :version "23.2"
+  :type '(choice (string :tag "From name")
+                (const :tag "Use From: header from message" header)
+                (const :tag "Use `user-mail-address'" nil))
+  :link '(custom-manual "(message)Mail Variables")
+  :group 'message-sending)
+
+(defcustom message-sendmail-extra-arguments nil
+  "Additional arguments to `sendmail-program'."
+  ;; E.g. '("-a" "account") for msmtp
+  :version "23.1" ;; No Gnus
+  :type '(repeat string)
+  ;; :link '(custom-manual "(message)Mail Variables")
+  :group 'message-sending)
+
+;; qmail-related stuff
+(defcustom message-qmail-inject-program "/var/qmail/bin/qmail-inject"
+  "Location of the qmail-inject program."
+  :group 'message-sending
+  :link '(custom-manual "(message)Mail Variables")
+  :type 'file)
+
+(defcustom message-qmail-inject-args nil
+  "Arguments passed to qmail-inject programs.
+This should be a list of strings, one string for each argument.
+It may also be a function.
+
+For e.g., if you wish to set the envelope sender address so that bounces
+go to the right place or to deal with listserv's usage of that address, you
+might set this variable to (\"-f\" \"you@some.where\")."
+  :group 'message-sending
+  :link '(custom-manual "(message)Mail Variables")
+  :type '(choice (function)
+                (repeat string)))
+
+(defvar gnus-post-method)
+(defvar gnus-select-method)
+(defcustom message-post-method
+  (cond ((and (boundp 'gnus-post-method)
+             (listp gnus-post-method)
+             gnus-post-method)
+        gnus-post-method)
+       ((boundp 'gnus-select-method)
+        gnus-select-method)
+       (t '(nnspool "")))
+  "*Method used to post news.
+Note that when posting from inside Gnus, for instance, this
+variable isn't used."
+  :group 'message-news
+  :group 'message-sending
+  ;; This should be the `gnus-select-method' widget, but that might
+  ;; create a dependence to `gnus.el'.
+  :type 'sexp)
+
+(defcustom message-generate-headers-first nil
+  "Which headers should be generated before starting to compose a message.
+If t, generate all required headers.  This can also be a list of headers to
+generate.  The variables `message-required-news-headers' and
+`message-required-mail-headers' specify which headers to generate.
+
+Note that the variable `message-deletable-headers' specifies headers which
+are to be deleted and then re-generated before sending, so this variable
+will not have a visible effect for those headers."
+  :group 'message-headers
+  :link '(custom-manual "(message)Message Headers")
+  :type '(choice (const :tag "None" nil)
+                (const :tag "All" t)
+                (repeat (sexp :tag "Header"))))
+
+(defcustom message-fill-column 72
+  "Column beyond which automatic line-wrapping should happen.
+Local value for message buffers.  If non-nil, also turn on
+auto-fill in message buffers."
+  :group 'message-various
+  ;; :link '(custom-manual "(message)Message Headers")
+  :type '(choice (const :tag "Don't turn on auto fill" nil)
+                (integer)))
+
+(defcustom message-setup-hook nil
+  "Normal hook, run each time a new outgoing message is initialized.
+The function `message-setup' runs this hook."
+  :group 'message-various
+  :link '(custom-manual "(message)Various Message Variables")
+  :type 'hook)
+
+(defcustom message-cancel-hook nil
+  "Hook run when canceling articles."
+  :group 'message-various
+  :link '(custom-manual "(message)Various Message Variables")
+  :type 'hook)
+
+(defcustom message-signature-setup-hook nil
+  "Normal hook, run each time a new outgoing message is initialized.
+It is run after the headers have been inserted and before
+the signature is inserted."
+  :group 'message-various
+  :link '(custom-manual "(message)Various Message Variables")
+  :type 'hook)
+
+(defcustom message-mode-hook nil
+  "Hook run in message mode buffers."
+  :group 'message-various
+  :type 'hook)
+
+(defcustom message-header-hook nil
+  "Hook run in a message mode buffer narrowed to the headers."
+  :group 'message-various
+  :type 'hook)
+
+(defcustom message-header-setup-hook nil
+  "Hook called narrowed to the headers when setting up a message buffer."
+  :group 'message-various
+  :link '(custom-manual "(message)Various Message Variables")
+  :type 'hook)
+
+(defcustom message-minibuffer-local-map
+  (let ((map (make-sparse-keymap 'message-minibuffer-local-map)))
+    (set-keymap-parent map minibuffer-local-map)
+    map)
+  "Keymap for `message-read-from-minibuffer'."
+  ;; FIXME improve type.
+  :type '(restricted-sexp :match-alternatives (symbolp keymapp))
+  :version "22.1"
+  :group 'message-various)
+
+(defcustom message-citation-line-function 'message-insert-citation-line
+  "*Function called to insert the \"Whomever writes:\" line.
+
+Predefined functions include `message-insert-citation-line' and
+`message-insert-formatted-citation-line' (see the variable
+`message-citation-line-format').
+
+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 '(choice
+         (function-item :tag "plain" message-insert-citation-line)
+         (function-item :tag "formatted" message-insert-formatted-citation-line)
+         (function :tag "Other"))
+  :link '(custom-manual "(message)Insertion Variables")
+  :group 'message-insertion)
+
+(defcustom message-citation-line-format "On %a, %b %d %Y, %N wrote:\n"
+  "Format of the \"Whomever writes:\" line.
+
+The string is formatted using `format-spec'.  The following constructs
+are replaced:
+
+  %f   The full From, e.g. \"John Doe <john.doe@example.invalid>\".
+  %n   The mail address, e.g. \"john.doe@example.invalid\".
+  %N   The real name if present, e.g.: \"John Doe\", else fall
+       back to the mail address.
+  %F   The first name if present, e.g.: \"John\", else fall
+       back to the mail address.
+  %L   The last name if present, e.g.: \"Doe\".
+  %Z, %z   The time zone in the numeric form, e.g.:\"+0000\".
+
+All other format specifiers are passed to `format-time-string'
+which is called using the date from the article your replying to, but
+the date in the formatted string will be expressed in the author's
+time zone as much as possible.
+Extracting the first (%F) and last name (%L) is done heuristically,
+so you should always check it yourself.
+
+Please also read the note in the documentation of
+`message-citation-line-function'."
+  :type '(choice (const :tag "Plain" "%f writes:")
+                (const :tag "Include date" "On %a, %b %d %Y, %n wrote:")
+                string)
+  :link '(custom-manual "(message)Insertion Variables")
+  :version "23.1" ;; No Gnus
+  :group 'message-insertion)
+
+(defcustom message-yank-prefix "> "
+  ;; In Emacs 24.1 this defaults to the value of `mail-yank-prefix'
+  ;; that defaults to:
+  ;; `nil' in Emacs 22.1~23.1;
+  ;; "> " in Emacs 23.2, 24.1, XEmacs 21.4, 21.5, and SXEmacs 22.1
+  "*Prefix inserted on the lines of yanked messages.
+Fix `message-cite-prefix-regexp' if it is set to an abnormal value.
+See also `message-yank-cited-prefix' and `message-yank-empty-prefix'."
+  :version "23.2"
+  :type 'string
+  :link '(custom-manual "(message)Insertion Variables")
+  :group 'message-insertion)
+
+(defcustom message-yank-cited-prefix ">"
+  "*Prefix inserted on cited lines of yanked messages.
+Fix `message-cite-prefix-regexp' if it is set to an abnormal value.
+See also `message-yank-prefix' and `message-yank-empty-prefix'."
+  :version "22.1"
+  :type 'string
+  :link '(custom-manual "(message)Insertion Variables")
+  :group 'message-insertion)
+
+(defcustom message-yank-empty-prefix ">"
+  "*Prefix inserted on empty lines of yanked messages.
+See also `message-yank-prefix' and `message-yank-cited-prefix'."
+  :version "22.1"
+  :type 'string
+  :link '(custom-manual "(message)Insertion Variables")
+  :group 'message-insertion)
+
+(defcustom message-indentation-spaces 3
+  ;; In Emacs 24.1 this defaults to the value of
+  ;; `mail-indentation-spaces' that defaults to `3' in Emacs 22.1~24.1,
+  ;; and SXEmacs 22.1.  In XEmacs 21.4 and 21.5, sendmail.el provides
+  ;; it; the defalut value is `3'.
+  "*Number of spaces to insert at the beginning of each cited line.
+Used by `message-yank-original' via `message-yank-cite'."
+  :version "23.2"
+  :group 'message-insertion
+  :link '(custom-manual "(message)Insertion Variables")
+  :type 'integer)
+
+(defcustom message-cite-function 'message-cite-original-without-signature
+  "*Function for citing an original message.
+Predefined functions include `message-cite-original' and
+`message-cite-original-without-signature'.
+Note that these functions use `mail-citation-hook' if that is non-nil."
+  :type '(radio (function-item message-cite-original)
+               (function-item message-cite-original-without-signature)
+               (function-item sc-cite-original)
+               (function :tag "Other"))
+  :link '(custom-manual "(message)Insertion Variables")
+  :version "22.3" ;; Gnus 5.10.12 (changed default)
+  :group 'message-insertion)
+
+(defcustom message-indent-citation-function 'message-indent-citation
+  "*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 (point) and (mark t).  And each function should leave
+point and mark around the citation text as modified."
+  :type 'function
+  :link '(custom-manual "(message)Insertion Variables")
+  :group 'message-insertion)
+
+(defcustom message-signature t
+  ;; In Emacs 24.1 this defaults to the value of `mail-signature' that
+  ;; defaults to:
+  ;; `nil' in Emacs 22.1~23.1, XEmacs 21.4, 21.5, and SXEmacs 22.1;
+  ;; `t' in Emacs 23.2, and 24.1
+  "*String to be inserted at the end of the message buffer.
+If t, the `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."
+  :version "23.2"
+  :type 'sexp
+  :link '(custom-manual "(message)Insertion Variables")
+  :group 'message-insertion)
+
+(defcustom message-signature-file "~/.signature"
+  ;; In Emacs 24.1 this defaults to the value of `mail-signature-file'
+  ;; that defaults to "~/.signature" in Emacs 22.1~24.1, and SXEmacs
+  ;; 22.1.  In XEmacs 21.4 and 21.5, sendmail.el provides it;
+  ;; the defalut value is "~/.signature".
+  "*Name of file containing the text inserted at end of message buffer.
+Ignored if the named file doesn't exist.
+If nil, don't insert a signature.
+If a path is specified, the value of `message-signature-directory' is ignored,
+even if set."
+  :version "23.2"
+  :type '(choice file (const :tags "None" nil))
+  :link '(custom-manual "(message)Insertion Variables")
+  :group 'message-insertion)
+
+(defcustom message-signature-directory nil
+  "*Name of directory containing signature files.
+Comes in handy if you have many such files, handled via posting styles for
+instance.
+If nil, `message-signature-file' is expected to specify the directory if
+needed."
+  :type '(choice string (const :tags "None" nil))
+  :link '(custom-manual "(message)Insertion Variables")
+  :group 'message-insertion)
+
+(defcustom message-signature-insert-empty-line t
+  "*If non-nil, insert an empty line before the signature separator."
+  :version "22.1"
+  :type 'boolean
+  :link '(custom-manual "(message)Insertion Variables")
+  :group 'message-insertion)
+
+(defcustom message-cite-reply-position 'traditional
+  "*Where the reply should be positioned.
+If `traditional', reply inline.
+If `above', reply above quoted text.
+If `below', reply below quoted text.
+
+Note: Many newsgroups frown upon nontraditional reply styles. You
+probably want to set this variable only for specific groups,
+e.g. using `gnus-posting-styles':
+
+  (eval (set (make-local-variable \\='message-cite-reply-position) \\='above))"
+  :version "24.1"
+  :type '(choice (const :tag "Reply inline" traditional)
+                (const :tag "Reply above" above)
+                (const :tag "Reply below" below))
+  :group 'message-insertion)
+
+(defcustom message-cite-style nil
+  "*The overall style to be used when yanking cited text.
+Value is either nil (no variable overrides) or a let-style list
+of pairs (VARIABLE VALUE) that will be bound in
+`message-yank-original' to do the quoting.
+
+Presets to impersonate popular mail agents are found in the
+message-cite-style-* variables.  This variable is intended for
+use in `gnus-posting-styles', such as:
+
+  ((posting-from-work-p) (eval (set (make-local-variable \\='message-cite-style) message-cite-style-outlook)))"
+  :version "24.1"
+  :group 'message-insertion
+  :type '(choice (const :tag "Do not override variables" :value nil)
+                (const :tag "MS Outlook" :value message-cite-style-outlook)
+                (const :tag "Mozilla Thunderbird" :value message-cite-style-thunderbird)
+                (const :tag "Gmail" :value message-cite-style-gmail)
+                (variable :tag "User-specified")))
+
+(defconst message-cite-style-outlook
+  '((message-cite-function  'message-cite-original)
+    (message-citation-line-function  'message-insert-formatted-citation-line)
+    (message-cite-reply-position 'above)
+    (message-yank-prefix  "")
+    (message-yank-cited-prefix  "")
+    (message-yank-empty-prefix  "")
+    (message-citation-line-format  "\n\n-----------------------\nOn %a, %b %d %Y, %N wrote:\n"))
+  "Message citation style used by MS Outlook. Use with message-cite-style.")
+
+(defconst message-cite-style-thunderbird
+  '((message-cite-function  'message-cite-original)
+    (message-citation-line-function  'message-insert-formatted-citation-line)
+    (message-cite-reply-position 'above)
+    (message-yank-prefix  "> ")
+    (message-yank-cited-prefix  ">")
+    (message-yank-empty-prefix  ">")
+    (message-citation-line-format "On %D %R %p, %N wrote:"))
+  "Message citation style used by Mozilla Thunderbird. Use with message-cite-style.")
+
+(defconst message-cite-style-gmail
+  '((message-cite-function  'message-cite-original)
+    (message-citation-line-function  'message-insert-formatted-citation-line)
+    (message-cite-reply-position 'above)
+    (message-yank-prefix  "    ")
+    (message-yank-cited-prefix  "    ")
+    (message-yank-empty-prefix  "    ")
+    (message-citation-line-format "On %e %B %Y %R, %f wrote:\n"))
+  "Message citation style used by Gmail. Use with message-cite-style.")
+
+(defcustom message-distribution-function nil
+  "*Function called to return a Distribution header."
+  :group 'message-news
+  :group 'message-headers
+  :link '(custom-manual "(message)News Headers")
+  :type '(choice function (const nil)))
+
+(defcustom message-expires 14
+  "Number of days before your article expires."
+  :group 'message-news
+  :group 'message-headers
+  :link '(custom-manual "(message)News Headers")
+  :type 'integer)
+
+(defcustom message-user-path nil
+  "If nil, use the NNTP server name in the Path header.
+If stringp, use this; if non-nil, use no host name (user name only)."
+  :group 'message-news
+  :group 'message-headers
+  :link '(custom-manual "(message)News Headers")
+  :type '(choice (const :tag "nntp" nil)
+                (string :tag "name")
+                (sexp :tag "none" :format "%t" t)))
+
+;; This can be the name of a buffer, or a cons cell (FUNCTION . ARGS)
+;; for yanking the original buffer.
+(defvar message-reply-buffer nil)
+(defvar message-reply-headers nil
+  "The headers of the current replied article.
+It is a vector of the following headers:
+[number subject from date id references chars lines xref extra].")
+(defvar message-newsreader nil)
+(defvar message-mailer nil)
+(defvar message-sent-message-via nil)
+(defvar message-checksum nil)
+(defvar message-send-actions nil
+  "A list of actions to be performed upon successful sending of a message.")
+(defvar message-return-action nil
+  "Action to return to the caller after sending or postponing a message.")
+(defvar message-exit-actions nil
+  "A list of actions to be performed upon exiting after sending a message.")
+(defvar message-kill-actions nil
+  "A list of actions to be performed before killing a message buffer.")
+(defvar message-postpone-actions nil
+  "A list of actions to be performed after postponing a message.")
+
+(define-widget 'message-header-lines 'text
+  "All header lines must be LFD terminated."
+  :format "%{%t%}:%n%v"
+  :valid-regexp "^\\'"
+  :error "All header lines must be newline terminated")
+
+(defcustom message-default-headers ""
+  "Header lines to be inserted in outgoing messages.
+This can be set to a string containing or a function returning
+header lines to be inserted before you edit the message, so you
+can edit or delete these lines.  If set to a function, it is
+called and its result is inserted."
+  :version "23.2"
+  :group 'message-headers
+  :link '(custom-manual "(message)Message Headers")
+  :type '(choice
+          (message-header-lines :tag "String")
+          (function :tag "Function")))
+
+(defcustom message-default-mail-headers
+  ;; Ease the transition from mail-mode to message-mode.  See bugs#4431, 5555.
+  (concat (if (and (boundp 'mail-default-reply-to)
+                  (stringp mail-default-reply-to))
+             (format "Reply-to: %s\n" mail-default-reply-to))
+         (if (and (boundp 'mail-self-blind)
+                  mail-self-blind)
+             (format "BCC: %s\n" user-mail-address))
+         (if (and (boundp 'mail-archive-file-name)
+                  (stringp mail-archive-file-name))
+             (format "FCC: %s\n" mail-archive-file-name))
+         ;; Use the value of `mail-default-headers' if available.
+         ;; Note: as for XEmacs 21.4 and 21.5, it is unavailable
+         ;; unless sendmail.el is loaded.
+         (if (boundp 'mail-default-headers)
+             mail-default-headers))
+  "*A string of header lines to be inserted in outgoing mails."
+  :version "23.2"
+  :group 'message-headers
+  :group 'message-mail
+  :link '(custom-manual "(message)Mail Headers")
+  :type 'message-header-lines)
+
+(defcustom message-default-news-headers ""
+  "*A string of header lines to be inserted in outgoing news articles."
+  :group 'message-headers
+  :group 'message-news
+  :link '(custom-manual "(message)News Headers")
+  :type 'message-header-lines)
+
+;; Note: could use /usr/ucb/mail instead of sendmail;
+;; options -t, and -v if not interactive.
+(defcustom message-mailer-swallows-blank-line
+  (if (and (string-match "sparc-sun-sunos\\(\\'\\|[^5]\\)"
+                        system-configuration)
+          (file-readable-p "/etc/sendmail.cf")
+          (with-temp-buffer
+             (insert-file-contents "/etc/sendmail.cf")
+             (goto-char (point-min))
+             (let ((case-fold-search nil))
+               (re-search-forward "^OR\\>" nil t))))
+      ;; According to RFC822, "The field-name must be composed of printable
+      ;; ASCII characters (i. e., characters that have decimal values between
+      ;; 33 and 126, except colon)", i. e., any chars except ctl chars,
+      ;; space, or colon.
+      '(looking-at "[ \t]\\|[][!\"#$%&'()*+,-./0-9;<=>?@A-Z\\\\^_`a-z{|}~]+:"))
+  "*Set this non-nil if the system's mailer runs the header and body together.
+\(This problem exists on Sunos 4 when sendmail is run in remote mode.)
+The value should be an expression to test whether the problem will
+actually occur."
+  :group 'message-sending
+  :link '(custom-manual "(message)Mail Variables")
+  :type 'sexp)
+
+;;;###autoload
+(define-mail-user-agent 'message-user-agent
+  'message-mail 'message-send-and-exit
+  'message-kill-buffer 'message-send-hook)
+
+(defvar message-mh-deletable-headers '(Message-ID Date Lines Sender)
+  "If non-nil, delete the deletable headers before feeding to mh.")
+
+(defvar message-send-method-alist
+  '((news message-news-p message-send-via-news)
+    (mail message-mail-p message-send-via-mail))
+  "Alist of ways to send outgoing messages.
+Each element has the form
+
+  (TYPE PREDICATE FUNCTION)
+
+where TYPE is a symbol that names the method; PREDICATE is a function
+called without any parameters to determine whether the message is
+a message of type TYPE; and FUNCTION is a function to be called if
+PREDICATE returns non-nil.  FUNCTION is called with one parameter --
+the prefix.")
+
+(defcustom message-mail-alias-type 'abbrev
+  "*What alias expansion type to use in Message buffers.
+The default is `abbrev', which uses mailabbrev.  `ecomplete' uses
+an electric completion mode.  nil switches mail aliases off.
+This can also be a list of values."
+  :group 'message
+  :link '(custom-manual "(message)Mail Aliases")
+  :type '(choice (const :tag "Use Mailabbrev" abbrev)
+                (const :tag "Use ecomplete" ecomplete)
+                (const :tag "No expansion" nil)))
+
+(defcustom message-self-insert-commands '(self-insert-command)
+  "List of `self-insert-command's used to trigger ecomplete.
+When one of those commands is invoked to enter a character in To or Cc
+header, ecomplete will suggest the candidates of recipients (see also
+`message-mail-alias-type').  If you use some tool to enter non-ASCII
+text and it replaces `self-insert-command' with the other command, e.g.
+`egg-self-insert-command', you may want to add it to this list."
+  :group 'message-various
+  :type '(repeat function))
+
+(defcustom message-auto-save-directory
+  (if (file-writable-p message-directory)
+      (file-name-as-directory (expand-file-name "drafts" message-directory))
+    "~/")
+  "*Directory where Message auto-saves buffers if Gnus isn't running.
+If nil, Message won't auto-save."
+  :group 'message-buffers
+  :link '(custom-manual "(message)Various Message Variables")
+  :type '(choice directory (const :tag "Don't auto-save" nil)))
+
+(defcustom message-default-charset
+  (and (not (mm-multibyte-p)) 'iso-8859-1)
+  "Default charset used in non-MULE Emacsen.
+If nil, you might be asked to input the charset."
+  :version "21.1"
+  :group 'message
+  :link '(custom-manual "(message)Various Message Variables")
+  :type 'symbol)
+
+(defcustom message-dont-reply-to-names
+  (and (boundp 'mail-dont-reply-to-names) mail-dont-reply-to-names)
+  "*Addresses to prune when doing wide replies.
+This can be a regexp or a list of regexps.  Also, a value of nil means
+exclude your own user name only."
+  :version "24.3"
+  :group 'message
+  :link '(custom-manual "(message)Wide Reply")
+  :type '(choice (const :tag "Yourself" nil)
+                regexp
+                (repeat :tag "Regexp List" regexp)))
+
+(defsubst message-dont-reply-to-names ()
+  (gmm-regexp-concat message-dont-reply-to-names))
+
+(defvar message-shoot-gnksa-feet nil
+  "*A list of GNKSA feet you are allowed to shoot.
+Gnus gives you all the opportunity you could possibly want for
+shooting yourself in the foot.  Also, Gnus allows you to shoot the
+feet of Good Net-Keeping Seal of Approval.  The following are foot
+candidates:
+`empty-article'     Allow you to post an empty article;
+`quoted-text-only'  Allow you to post quoted text only;
+`multiple-copies'   Allow you to post multiple copies;
+`cancel-messages'   Allow you to cancel or supersede messages from
+                   your other email addresses;
+`canlock-verify'    Allow you to cancel messages without verifying canlock.")
+
+(defsubst message-gnksa-enable-p (feature)
+  (or (not (listp message-shoot-gnksa-feet))
+      (memq feature message-shoot-gnksa-feet)))
+
+(defcustom message-hidden-headers '("^References:" "^Face:" "^X-Face:"
+                                   "^X-Draft-From:")
+  "Regexp of headers to be hidden when composing new messages.
+This can also be a list of regexps to match headers.  Or a list
+starting with `not' and followed by regexps."
+  :version "22.1"
+  :group 'message
+  :link '(custom-manual "(message)Message Headers")
+  :type '(choice
+         :format "%{%t%}: %[Value Type%] %v"
+         (regexp :menu-tag "regexp" :format "regexp\n%t: %v")
+         (repeat :menu-tag "(regexp ...)" :format "(regexp ...)\n%v%i"
+                 (regexp :format "%t: %v"))
+         (cons :menu-tag "(not regexp ...)" :format "(not regexp ...)\n%v"
+               (const not)
+               (repeat :format "%v%i"
+                       (regexp :format "%t: %v")))))
+
+(defcustom message-cite-articles-with-x-no-archive t
+  "If non-nil, cite text from articles that has X-No-Archive set."
+  :group 'message
+  :type 'boolean)
+
+;;; Internal variables.
+;;; Well, not really internal.
+
+(defvar message-mode-syntax-table
+  (let ((table (copy-syntax-table text-mode-syntax-table)))
+    (modify-syntax-entry ?% ". " table)
+    (modify-syntax-entry ?> ". " table)
+    (modify-syntax-entry ?< ". " table)
+    table)
+  "Syntax table used while in Message mode.")
+
+(defface message-header-to
+  '((((class color)
+      (background dark))
+     (:foreground "DarkOliveGreen1" :bold t))
+    (((class color)
+      (background light))
+     (:foreground "MidnightBlue" :bold t))
+    (t
+     (:bold t :italic t)))
+  "Face used for displaying From headers."
+  :group 'message-faces)
+;; backward-compatibility alias
+(put 'message-header-to-face 'face-alias 'message-header-to)
+(put 'message-header-to-face 'obsolete-face "22.1")
+
+(defface message-header-cc
+  '((((class color)
+      (background dark))
+     (:foreground "chartreuse1" :bold t))
+    (((class color)
+      (background light))
+     (:foreground "MidnightBlue"))
+    (t
+     (:bold t)))
+  "Face used for displaying Cc headers."
+  :group 'message-faces)
+;; backward-compatibility alias
+(put 'message-header-cc-face 'face-alias 'message-header-cc)
+(put 'message-header-cc-face 'obsolete-face "22.1")
+
+(defface message-header-subject
+  '((((class color)
+      (background dark))
+     (:foreground "OliveDrab1"))
+    (((class color)
+      (background light))
+     (:foreground "navy blue" :bold t))
+    (t
+     (:bold t)))
+  "Face used for displaying subject headers."
+  :group 'message-faces)
+;; backward-compatibility alias
+(put 'message-header-subject-face 'face-alias 'message-header-subject)
+(put 'message-header-subject-face 'obsolete-face "22.1")
+
+(defface message-header-newsgroups
+  '((((class color)
+      (background dark))
+     (:foreground "yellow" :bold t :italic t))
+    (((class color)
+      (background light))
+     (:foreground "blue4" :bold t :italic t))
+    (t
+     (:bold t :italic t)))
+  "Face used for displaying newsgroups headers."
+  :group 'message-faces)
+;; backward-compatibility alias
+(put 'message-header-newsgroups-face 'face-alias 'message-header-newsgroups)
+(put 'message-header-newsgroups-face 'obsolete-face "22.1")
+
+(defface message-header-other
+  '((((class color)
+      (background dark))
+     (:foreground "VioletRed1"))
+    (((class color)
+      (background light))
+     (:foreground "steel blue"))
+    (t
+     (:bold t :italic t)))
+  "Face used for displaying newsgroups headers."
+  :group 'message-faces)
+;; backward-compatibility alias
+(put 'message-header-other-face 'face-alias 'message-header-other)
+(put 'message-header-other-face 'obsolete-face "22.1")
+
+(defface message-header-name
+  '((((class color)
+      (background dark))
+     (:foreground "green"))
+    (((class color)
+      (background light))
+     (:foreground "cornflower blue"))
+    (t
+     (:bold t)))
+  "Face used for displaying header names."
+  :group 'message-faces)
+;; backward-compatibility alias
+(put 'message-header-name-face 'face-alias 'message-header-name)
+(put 'message-header-name-face 'obsolete-face "22.1")
+
+(defface message-header-xheader
+  '((((class color)
+      (background dark))
+     (:foreground "DeepSkyBlue1"))
+    (((class color)
+      (background light))
+     (:foreground "blue"))
+    (t
+     (:bold t)))
+  "Face used for displaying X-Header headers."
+  :group 'message-faces)
+;; backward-compatibility alias
+(put 'message-header-xheader-face 'face-alias 'message-header-xheader)
+(put 'message-header-xheader-face 'obsolete-face "22.1")
+
+(defface message-separator
+  '((((class color)
+      (background dark))
+     (:foreground "LightSkyBlue1"))
+    (((class color)
+      (background light))
+     (:foreground "brown"))
+    (t
+     (:bold t)))
+  "Face used for displaying the separator."
+  :group 'message-faces)
+;; backward-compatibility alias
+(put 'message-separator-face 'face-alias 'message-separator)
+(put 'message-separator-face 'obsolete-face "22.1")
+
+(defface message-cited-text
+  '((((class color)
+      (background dark))
+     (:foreground "LightPink1"))
+    (((class color)
+      (background light))
+     (:foreground "red"))
+    (t
+     (:bold t)))
+  "Face used for displaying cited text names."
+  :group 'message-faces)
+;; backward-compatibility alias
+(put 'message-cited-text-face 'face-alias 'message-cited-text)
+(put 'message-cited-text-face 'obsolete-face "22.1")
+
+(defface message-mml
+  '((((class color)
+      (background dark))
+     (:foreground "MediumSpringGreen"))
+    (((class color)
+      (background light))
+     (:foreground "ForestGreen"))
+    (t
+     (:bold t)))
+  "Face used for displaying MML."
+  :group 'message-faces)
+;; backward-compatibility alias
+(put 'message-mml-face 'face-alias 'message-mml)
+(put 'message-mml-face 'obsolete-face "22.1")
+
+(defun message-font-lock-make-header-matcher (regexp)
+  (let ((form
+        `(lambda (limit)
+           (let ((start (point)))
+             (save-restriction
+               (widen)
+               (goto-char (point-min))
+               (if (re-search-forward
+                    (concat "^" (regexp-quote mail-header-separator) "$")
+                    nil t)
+                   (setq limit (min limit (match-beginning 0))))
+               (goto-char start))
+             (and (< start limit)
+                  (re-search-forward ,regexp limit t))))))
+    (if (featurep 'bytecomp)
+       (byte-compile form)
+      form)))
+
+(defvar message-font-lock-keywords
+  (let ((content "[ \t]*\\(.+\\(\n[ \t].*\\)*\\)\n?"))
+    `((,(message-font-lock-make-header-matcher
+        (concat "^\\([Tt]o:\\)" content))
+       (1 'message-header-name)
+       (2 'message-header-to nil t))
+      (,(message-font-lock-make-header-matcher
+        (concat "^\\(^[GBF]?[Cc][Cc]:\\|^[Rr]eply-[Tt]o:\\)" content))
+       (1 'message-header-name)
+       (2 'message-header-cc nil t))
+      (,(message-font-lock-make-header-matcher
+        (concat "^\\([Ss]ubject:\\)" content))
+       (1 'message-header-name)
+       (2 'message-header-subject nil t))
+      (,(message-font-lock-make-header-matcher
+        (concat "^\\([Nn]ewsgroups:\\|Followup-[Tt]o:\\)" content))
+       (1 'message-header-name)
+       (2 'message-header-newsgroups nil t))
+      (,(message-font-lock-make-header-matcher
+        (concat "^\\(X-[A-Za-z0-9-]+:\\|In-Reply-To:\\)" content))
+       (1 'message-header-name)
+       (2 'message-header-xheader))
+      (,(message-font-lock-make-header-matcher
+        (concat "^\\([A-Z][^: \n\t]+:\\)" content))
+       (1 'message-header-name)
+       (2 'message-header-other nil t))
+      ,@(if (and mail-header-separator
+                (not (equal mail-header-separator "")))
+           `((,(concat "^\\(" (regexp-quote mail-header-separator) "\\)$")
+              1 'message-separator))
+         nil)
+      ((lambda (limit)
+        (re-search-forward (concat "^\\("
+                                   message-cite-prefix-regexp
+                                   "\\).*")
+                           limit t))
+       (0 'message-cited-text))
+      ("<#/?\\(multipart\\|part\\|external\\|mml\\|secure\\)[^>]*>"
+       (0 'message-mml))))
+  "Additional expressions to highlight in Message mode.")
+
+
+;; XEmacs does it like this.  For Emacs, we have to set the
+;; `font-lock-defaults' buffer-local variable.
+(put 'message-mode 'font-lock-defaults '(message-font-lock-keywords t))
+
+(defvar message-face-alist
+  '((bold . message-bold-region)
+    (underline . underline-region)
+    (default . (lambda (b e)
+                (message-unbold-region b e)
+                (ununderline-region b e))))
+  "Alist of mail and news faces for facemenu.
+The cdr of each entry is a function for applying the face to a region.")
+
+(defcustom message-send-hook nil
+  "Hook run before sending messages.
+This hook is run quite early when sending."
+  :group 'message-various
+  :options '(ispell-message)
+  :link '(custom-manual "(message)Various Message Variables")
+  :type 'hook)
+
+(defcustom message-send-mail-hook nil
+  "Hook run before sending mail messages.
+This hook is run very late -- just before the message is sent as
+mail."
+  :group 'message-various
+  :link '(custom-manual "(message)Various Message Variables")
+  :type 'hook)
+
+(defcustom message-send-news-hook nil
+  "Hook run before sending news messages.
+This hook is run very late -- just before the message is sent as
+news."
+  :group 'message-various
+  :link '(custom-manual "(message)Various Message Variables")
+  :type 'hook)
+
+(defcustom message-sent-hook nil
+  "Hook run after sending messages."
+  :group 'message-various
+  :type 'hook)
+
+(defvar message-send-coding-system 'binary
+  "Coding system to encode outgoing mail.")
+
+(defvar message-draft-coding-system
+  mm-auto-save-coding-system
+  "*Coding system to compose mail.
+If you'd like to make it possible to share draft files between XEmacs
+and Emacs, you may use `iso-2022-7bit' for this value at your own risk.
+Note that the coding-system `iso-2022-7bit' isn't suitable to all data.")
+
+(defcustom message-send-mail-partially-limit nil
+  "The limitation of messages sent as message/partial.
+The lower bound of message size in characters, beyond which the message
+should be sent in several parts.  If it is nil, the size is unlimited."
+  :version "24.1"
+  :group 'message-buffers
+  :link '(custom-manual "(message)Mail Variables")
+  :type '(choice (const :tag "unlimited" nil)
+                (integer 1000000)))
+
+(defcustom message-alternative-emails nil
+  "*Regexp matching alternative email addresses.
+The first address in the To, Cc or From headers of the original
+article matching this variable is used as the From field of
+outgoing messages.
+
+This variable has precedence over posting styles and anything that runs
+off `message-setup-hook'."
+  :group 'message-headers
+  :link '(custom-manual "(message)Message Headers")
+  :type '(choice (const :tag "Always use primary" nil)
+                regexp))
+
+(defcustom message-hierarchical-addresses nil
+  "A list of hierarchical mail address definitions.
+
+Inside each entry, the first address is the \"top\" address, and
+subsequent addresses are subaddresses; this is used to indicate that
+mail sent to the first address will automatically be delivered to the
+subaddresses.  So if the first address appears in the recipient list
+for a message, the subaddresses will be removed (if present) before
+the mail is sent.  All addresses in this structure should be
+downcased."
+  :version "22.1"
+  :group 'message-headers
+  :type '(repeat (repeat string)))
+
+(defcustom message-mail-user-agent nil
+  "Like `mail-user-agent'.
+Except if it is nil, use Gnus native MUA; if it is t, use
+`mail-user-agent'."
+  :version "22.1"
+  :type '(radio (const :tag "Gnus native"
+                      :format "%t\n"
+                      nil)
+               (const :tag "`mail-user-agent'"
+                      :format "%t\n"
+                      t)
+               (function-item :tag "Default Emacs mail"
+                              :format "%t\n"
+                              sendmail-user-agent)
+               (function-item :tag "Emacs interface to MH"
+                              :format "%t\n"
+                              mh-e-user-agent)
+               (function :tag "Other"))
+  :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."
+  :version "22.1"
+  :group 'message-headers
+  :link '(custom-manual "(message)Wide Reply")
+  :type 'boolean)
+
+(defcustom message-user-fqdn nil
+  "*Domain part of Message-Ids."
+  :version "22.1"
+  :group 'message-headers
+  :link '(custom-manual "(message)News Headers")
+  :type '(radio (const :format "%v  " nil)
+               (string :format "FQDN: %v")))
+
+(defcustom message-use-idna
+  (and (or (mm-coding-system-p 'utf-8)
+          (condition-case nil
+              (let (mucs-ignore-version-incompatibilities)
+                (require 'un-define))
+            (error)))
+       (condition-case nil
+          (require 'idna)
+        (file-error)
+        (invalid-operation))
+       idna-program
+       (executable-find idna-program)
+       (string= (idna-to-ascii "räksmörgås") "xn--rksmrgs-5wao1o")
+       t)
+  "Whether to encode non-ASCII in domain names into ASCII according to IDNA.
+GNU Libidn, and in particular the elisp package \"idna.el\" and
+the external program \"idn\", must be installed for this
+functionality to work."
+  :version "22.1"
+  :group 'message-headers
+  :link '(custom-manual "(message)IDNA")
+  :type '(choice (const :tag "Ask" ask)
+                (const :tag "Never" nil)
+                (const :tag "Always" t)))
+
+(defcustom message-generate-hashcash (if (executable-find "hashcash") 'opportunistic)
+  "*Whether to generate X-Hashcash: headers.
+If t, always generate hashcash headers.  If `opportunistic',
+only generate hashcash headers if it can be done without the user
+waiting (i.e., only asynchronously).
+
+You must have the \"hashcash\" binary installed, see `hashcash-path'."
+  :version "24.1"
+  :group 'message-headers
+  :link '(custom-manual "(message)Mail Headers")
+  :type '(choice (const :tag "Always" t)
+                (const :tag "Never" nil)
+                (const :tag "Opportunistic" opportunistic)))
+
+;;; Internal variables.
+
+(defvar message-sending-message "Sending...")
+(defvar message-buffer-list nil)
+(defvar message-this-is-news nil)
+(defvar message-this-is-mail nil)
+(defvar message-draft-article nil)
+(defvar message-mime-part nil)
+(defvar message-posting-charset nil)
+(defvar message-inserted-headers nil)
+(defvar message-inhibit-ecomplete nil)
+
+;; Byte-compiler warning
+(defvar gnus-active-hashtb)
+(defvar gnus-read-active-file)
+
+;;; Regexp matching the delimiter of messages in UNIX mail format
+;;; (UNIX From lines), minus the initial ^.  It should be a copy
+;;; of rmail.el's rmail-unix-mail-delimiter.
+(defvar message-unix-mail-delimiter
+  (let ((time-zone-regexp
+        (concat "\\([A-Z]?[A-Z]?[A-Z][A-Z]\\( DST\\)?"
+                "\\|[-+]?[0-9][0-9][0-9][0-9]"
+                "\\|"
+                "\\) *")))
+    (concat
+     "From "
+
+     ;; Many things can happen to an RFC 822 mailbox before it is put into
+     ;; a `From' line.  The leading phrase can be stripped, e.g.
+     ;; `Joe <@w.x:joe@y.z>' -> `<@w.x:joe@y.z>'.  The <> can be stripped, e.g.
+     ;; `<@x.y:joe@y.z>' -> `@x.y:joe@y.z'.  Everything starting with a CRLF
+     ;; can be removed, e.g.
+     ;;                From: joe@y.z (Joe      K
+     ;;                        User)
+     ;; can yield `From joe@y.z (Joe   K Fri Mar 22 08:11:15 1996', and
+     ;;                From: Joe User
+     ;;                        <joe@y.z>
+     ;; can yield `From Joe User Fri Mar 22 08:11:15 1996'.
+     ;; The mailbox can be removed or be replaced by white space, e.g.
+     ;;                From: "Joe User"{space}{tab}
+     ;;                        <joe@y.z>
+     ;; can yield `From {space}{tab} Fri Mar 22 08:11:15 1996',
+     ;; where {space} and {tab} represent the Ascii space and tab characters.
+     ;; We want to match the results of any of these manglings.
+     ;; The following regexp rejects names whose first characters are
+     ;; obviously bogus, but after that anything goes.
+     "\\([^\0-\b\n-\r\^?].*\\)?"
+
+     ;; The time the message was sent.
+     "\\([^\0-\r \^?]+\\) +"           ; day of the week
+     "\\([^\0-\r \^?]+\\) +"           ; month
+     "\\([0-3]?[0-9]\\) +"             ; day of month
+     "\\([0-2][0-9]:[0-5][0-9]\\(:[0-6][0-9]\\)?\\) *" ; time of day
+
+     ;; Perhaps a time zone, specified by an abbreviation, or by a
+     ;; numeric offset.
+     time-zone-regexp
+
+     ;; The year.
+     " \\([0-9][0-9]+\\) *"
+
+     ;; On some systems the time zone can appear after the year, too.
+     time-zone-regexp
+
+     ;; Old uucp cruft.
+     "\\(remote from .*\\)?"
+
+     "\n"))
+  "Regexp matching the delimiter of messages in UNIX mail format.")
+
+(defvar message-unsent-separator
+  (concat "^ *---+ +Unsent message follows +---+ *$\\|"
+         "^ *---+ +Returned message +---+ *$\\|"
+         "^Start of returned message$\\|"
+         "^ *---+ +Original message +---+ *$\\|"
+         "^ *--+ +begin message +--+ *$\\|"
+         "^ *---+ +Original message follows +---+ *$\\|"
+         "^ *---+ +Undelivered message follows +---+ *$\\|"
+         "^------ This is a copy of the message, including all the headers. ------ *$\\|"
+         "^|? *---+ +Message text follows: +---+ *|?$")
+  "A regexp that matches the separator before the text of a failed message.")
+
+(defvar message-field-fillers
+  '((To message-fill-field-address)
+    (Cc message-fill-field-address)
+    (From message-fill-field-address))
+  "Alist of header names/filler functions.")
+
+(defvar message-header-format-alist
+  `((From)
+    (Newsgroups)
+    (To)
+    (Cc)
+    (Subject)
+    (In-Reply-To)
+    (Fcc)
+    (Bcc)
+    (Date)
+    (Organization)
+    (Distribution)
+    (Lines)
+    (Expires)
+    (Message-ID)
+    (References . message-shorten-references)
+    (User-Agent))
+  "Alist used for formatting headers.")
+
+(defvar        message-options nil
+  "Some saved answers when sending message.")
+;; FIXME: On XEmacs this causes problems since let-binding like:
+;; (let ((message-options message-options)) ...)
+;; as in `message-send' and `mml-preview' loses to buffer-local
+;; variable initialization.
+(unless (featurep 'xemacs)
+  (make-variable-buffer-local 'message-options))
+
+(defvar message-send-mail-real-function nil
+  "Internal send mail function.")
+
+(defvar message-bogus-system-names "\\`localhost\\.\\|\\.local\\'"
+  "The regexp of bogus system names.")
+
+(defcustom message-valid-fqdn-regexp
+  (concat "[a-z0-9][-.a-z0-9]+\\." ;; [hostname.subdomain.]domain.
+         ;; valid TLDs:
+         "\\([a-z][a-z]\\|" ;; two letter country TDLs
+         "aero\\|arpa\\|asia\\|bitnet\\|biz\\|bofh\\|"
+         "cat\\|com\\|coop\\|edu\\|gov\\|"
+         "info\\|int\\|jobs\\|"
+         "mil\\|mobi\\|museum\\|name\\|net\\|"
+         "org\\|pro\\|tel\\|travel\\|uucp\\|"
+          ;; ICANN-era generic top-level domains
+          "academy\\|actor\\|agency\\|airforce\\|archi\\|associates\\|axa\\|"
+          "bar\\|bargains\\|bayern\\|beer\\|berlin\\|best\\|bid\\|bike\\|"
+          "biz\\|black\\|blackfriday\\|blue\\|boutique\\|build\\|builders\\|"
+          "buzz\\|cab\\|camera\\|camp\\|capital\\|cards\\|care\\|career\\|"
+          "careers\\|cash\\|catering\\|center\\|ceo\\|cheap\\|christmas\\|"
+          "church\\|citic\\|cleaning\\|clinic\\|clothing\\|club\\|codes\\|"
+          "coffee\\|college\\|cologne\\|com\\|community\\|company\\|computer\\|"
+          "construction\\|contractors\\|cooking\\|cool\\|country\\|creditcard\\|"
+          "cruises\\|dance\\|dating\\|democrat\\|dental\\|desi\\|design\\|"
+          "diamonds\\|directory\\|discount\\|domains\\|education\\|email\\|"
+          "engineering\\|enterprises\\|equipment\\|estate\\|eus\\|events\\|"
+          "exchange\\|expert\\|exposed\\|fail\\|farm\\|feedback\\|finance\\|"
+          "financial\\|fish\\|fishing\\|fitness\\|flights\\|florist\\|foo\\|"
+          "foundation\\|frogans\\|fund\\|furniture\\|futbol\\|gal\\|"
+          "gallery\\|gift\\|glass\\|globo\\|gmo\\|gop\\|graphics\\|gratis\\|"
+          "gripe\\|guide\\|guitars\\|guru\\|hamburg\\|haus\\|hiphop\\|"
+          "holdings\\|holiday\\|homes\\|horse\\|house\\|immobilien\\|"
+          "industries\\|info\\|ink\\|institute\\|insure\\|international\\|"
+          "investments\\|jetzt\\|juegos\\|kaufen\\|kim\\|kitchen\\|kiwi\\|"
+          "koeln\\|kred\\|land\\|lat\\|latino\\|lease\\|life\\|lighting\\|"
+          "limited\\|limo\\|link\\|loans\\|london\\|luxe\\|luxury\\|"
+          "management\\|mango\\|marketing\\|media\\|meet\\|menu\\|miami\\|"
+          "moda\\|moe\\|monash\\|moscow\\|motorcycles\\|nagoya\\|name\\|"
+          "net\\|neustar\\|ninja\\|nyc\\|okinawa\\|onl\\|org\\|paris\\|"
+          "partners\\|parts\\|photo\\|photography\\|photos\\|pics\\|"
+          "pictures\\|pink\\|plumbing\\|pro\\|productions\\|properties\\|"
+          "pub\\|qpon\\|quebec\\|recipes\\|red\\|reisen\\|ren\\|rentals\\|"
+          "repair\\|report\\|rest\\|reviews\\|rich\\|rocks\\|rodeo\\|"
+          "ruhr\\|ryukyu\\|saarland\\|schule\\|scot\\|services\\|sexy\\|"
+          "shiksha\\|shoes\\|singles\\|social\\|sohu\\|solar\\|solutions\\|"
+          "soy\\|supplies\\|supply\\|support\\|surgery\\|systems\\|tattoo\\|"
+          "tax\\|technology\\|tienda\\|tips\\|today\\|tokyo\\|tools\\|"
+          "town\\|toys\\|trade\\|training\\|university\\|uno\\|vacations\\|"
+          "vegas\\|ventures\\|viajes\\|villas\\|vision\\|vodka\\|vote\\|"
+          "voting\\|voto\\|voyage\\|wang\\|watch\\|webcam\\|wed\\|wien\\|"
+          "wiki\\|works\\|wtc\\|wtf\\|xyz\\|yachts\\|yokohama\\|you\\|"
+          "zone\\)")
+  ;; http://en.wikipedia.org/wiki/List_of_Internet_top-level_domains
+  ;; http://en.wikipedia.org/wiki/GTLD
+  ;; `approved, but not yet in operation': .xxx
+  ;; "dead" nato bitnet uucp
+  "Regular expression that matches a valid FQDN."
+  ;; see also: gnus-button-valid-fqdn-regexp
+  :version "25.1"
+  :group 'message-headers
+  :type 'regexp)
+
+(autoload 'gnus-alive-p "gnus-util")
+(autoload 'gnus-delay-article "gnus-delay")
+(autoload 'gnus-extract-address-components "gnus-util")
+(autoload 'gnus-find-method-for-group "gnus")
+(autoload 'gnus-group-decoded-name "gnus-group")
+(autoload 'gnus-group-name-charset "gnus-group")
+(autoload 'gnus-group-name-decode "gnus-group")
+(autoload 'gnus-groups-from-server "gnus")
+(autoload 'gnus-make-local-hook "gnus-util")
+(autoload 'gnus-open-server "gnus-int")
+(autoload 'gnus-output-to-mail "gnus-util")
+(autoload 'gnus-output-to-rmail "gnus-util")
+(autoload 'gnus-request-post "gnus-int")
+(autoload 'gnus-select-frame-set-input-focus "gnus-util")
+(autoload 'gnus-server-string "gnus")
+(autoload 'idna-to-ascii "idna")
+(autoload 'message-setup-toolbar "messagexmas")
+(autoload 'mh-new-draft-name "mh-comp")
+(autoload 'mh-send-letter "mh-comp")
+(autoload 'nndraft-request-associate-buffer "nndraft")
+(autoload 'nndraft-request-expire-articles "nndraft")
+(autoload 'nnvirtual-find-group-art "nnvirtual")
+(autoload 'rmail-msg-is-pruned "rmail")
+(autoload 'rmail-output "rmailout")
+
+;; Emacs < 24.1 do not have mail-dont-reply-to
+(unless (fboundp 'mail-dont-reply-to)
+  (defalias 'mail-dont-reply-to 'rmail-dont-reply-to))
+
+(eval-and-compile
+  (if (featurep 'emacs)
+      (progn
+       (defun message-kill-all-overlays ()
+         (mapcar #'delete-overlay (overlays-in (point-min) (point-max))))
+       (defalias 'message-window-inside-pixel-edges
+         'window-inside-pixel-edges))
+    (defun message-kill-all-overlays ()
+      (map-extents (lambda (extent ignore) (delete-extent extent))))
+    (defalias 'message-window-inside-pixel-edges 'ignore)))
+
+\f
+
+;;;
+;;; Utility functions.
+;;;
+
+(defmacro message-y-or-n-p (question show &rest text)
+  "Ask QUESTION, displaying remaining args in a temporary buffer if SHOW."
+  `(message-talkative-question 'y-or-n-p ,question ,show ,@text))
+
+(defmacro message-delete-line (&optional n)
+  "Delete the current line (and the next N lines)."
+  `(delete-region (progn (beginning-of-line) (point))
+                 (progn (forward-line ,(or n 1)) (point))))
+
+(defun message-mark-active-p ()
+  "Non-nil means the mark and region are currently active in this buffer."
+  mark-active)
+
+(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))
+
+(defun message-tokenize-header (header &optional separator)
+  "Split HEADER into a list of header elements.
+SEPARATOR is a string of characters to be used as separators.  \",\"
+is used by default."
+  (if (not header)
+      nil
+    (let ((regexp (format "[%s]+" (or separator ",")))
+         (first t)
+         beg quoted elems paren)
+      (with-temp-buffer
+       (mm-enable-multibyte)
+       (setq beg (point-min))
+       (insert header)
+       (goto-char (point-min))
+       (while (not (eobp))
+         (if first
+             (setq first nil)
+           (forward-char 1))
+         (cond ((and (> (point) beg)
+                     (or (eobp)
+                         (and (looking-at regexp)
+                              (not quoted)
+                              (not paren))))
+                (push (buffer-substring beg (point)) elems)
+                (setq beg (match-end 0)))
+               ((eq (char-after) ?\")
+                (setq quoted (not quoted)))
+               ((and (eq (char-after) ?\()
+                     (not quoted))
+                (setq paren t))
+               ((and (eq (char-after) ?\))
+                     (not quoted))
+                (setq paren nil))))
+       (nreverse elems)))))
+
+(autoload 'nnheader-insert-file-contents "nnheader")
+
+(defun message-mail-file-mbox-p (file)
+  "Say whether FILE looks like a Unix mbox file."
+  (when (and (file-exists-p file)
+            (file-readable-p file)
+            (file-regular-p file))
+    (with-temp-buffer
+      (nnheader-insert-file-contents file)
+      (goto-char (point-min))
+      (looking-at message-unix-mail-delimiter))))
+
+(defun message-fetch-field (header &optional not-all)
+  "The same as `mail-fetch-field', only remove all newlines.
+The buffer is expected to be narrowed to just the header of the message;
+see `message-narrow-to-headers-or-head'."
+  (let* ((inhibit-point-motion-hooks t)
+        (value (mail-fetch-field header nil (not not-all))))
+    (when value
+      (while (string-match "\n[\t ]+" value)
+       (setq value (replace-match " " t t value)))
+      value)))
+
+(defun message-field-value (header &optional not-all)
+  "The same as `message-fetch-field', only narrow to the headers first."
+  (save-excursion
+    (save-restriction
+      (message-narrow-to-headers-or-head)
+      (message-fetch-field header not-all))))
+
+(defun message-narrow-to-field ()
+  "Narrow the buffer to the header on the current line."
+  (beginning-of-line)
+  (while (looking-at "[ \t]")
+    (forward-line -1))
+  (narrow-to-region
+   (point)
+   (progn
+     (forward-line 1)
+     (if (re-search-forward "^[^ \n\t]" nil t)
+        (point-at-bol)
+       (point-max))))
+  (goto-char (point-min)))
+
+(defun message-add-header (&rest headers)
+  "Add the HEADERS to the message header, skipping those already present."
+  (while headers
+    (let (hclean)
+      (unless (string-match "^\\([^:]+\\):[ \t]*[^ \t]" (car headers))
+       (error "Invalid header `%s'" (car headers)))
+      (setq hclean (match-string 1 (car headers)))
+      (save-restriction
+       (message-narrow-to-headers)
+       (unless (re-search-forward (concat "^" (regexp-quote hclean) ":") nil t)
+         (goto-char (point-max))
+         (if (string-match "\n$" (car headers))
+             (insert (car headers))
+           (insert (car headers) ?\n)))))
+    (setq headers (cdr headers))))
+
+(defmacro message-with-reply-buffer (&rest forms)
+  "Evaluate FORMS in the reply buffer, if it exists."
+  `(when (and (bufferp message-reply-buffer)
+             (buffer-name message-reply-buffer))
+     (with-current-buffer message-reply-buffer
+       ,@forms)))
+
+(put 'message-with-reply-buffer 'lisp-indent-function 0)
+(put 'message-with-reply-buffer 'edebug-form-spec '(body))
+
+(defun message-fetch-reply-field (header)
+  "Fetch field HEADER from the message we're replying to."
+  (message-with-reply-buffer
+    (save-restriction
+      (mail-narrow-to-head)
+      (message-fetch-field header))))
+
+(defun message-strip-list-identifiers (subject)
+  "Remove list identifiers in `gnus-list-identifiers' from string SUBJECT."
+  (require 'gnus-sum)                  ; for gnus-list-identifiers
+  (let ((regexp (if (stringp gnus-list-identifiers)
+                   gnus-list-identifiers
+                 (mapconcat 'identity gnus-list-identifiers " *\\|"))))
+    (if (string-match (concat "\\(\\(\\(Re: +\\)?\\(" regexp
+                             " *\\)\\)+\\(Re: +\\)?\\)") subject)
+       (concat (substring subject 0 (match-beginning 1))
+               (or (match-string 3 subject)
+                   (match-string 5 subject))
+               (substring subject
+                          (match-end 1)))
+      subject)))
+
+(defun message-strip-subject-re (subject)
+  "Remove \"Re:\" from subject lines in string SUBJECT."
+  (if (string-match message-subject-re-regexp subject)
+      (substring subject (match-end 0))
+    subject))
+
+(defcustom message-replacement-char "."
+  "Replacement character used instead of unprintable or not decodable chars."
+  :group 'message-various
+  :version "22.1" ;; Gnus 5.10.9
+  :type '(choice string
+                (const ".")
+                (const "?")))
+
+;; FIXME: We also should call `message-strip-subject-encoded-words'
+;; when forwarding.  Probably in `message-make-forward-subject' and
+;; `message-forward-make-body'.
+
+(defun message-strip-subject-encoded-words (subject)
+  "Fix non-decodable words in SUBJECT."
+  ;; Cf. `gnus-simplify-subject-fully'.
+  (let* ((case-fold-search t)
+        (replacement-chars (format "[%s%s%s]"
+                                   message-replacement-char
+                                   message-replacement-char
+                                   message-replacement-char))
+        (enc-word-re "=\\?\\([^?]+\\)\\?\\([QB]\\)\\?\\([^?]+\\)\\(\\?=\\)")
+        cs-string
+        (have-marker
+         (with-temp-buffer
+           (insert subject)
+           (goto-char (point-min))
+           (when (re-search-forward enc-word-re nil t)
+             (setq cs-string (match-string 1)))))
+        cs-coding q-or-b word-beg word-end)
+    (if (or (not have-marker) ;; No encoded word found...
+           ;; ... or double encoding was correct:
+           (and (stringp cs-string)
+                (setq cs-string (downcase cs-string))
+                (mm-coding-system-p (intern cs-string))
+                (not (prog1
+                         (y-or-n-p
+                          (format "\
+Decoded Subject \"%s\"
+contains a valid encoded word.  Decode again? "
+                                  subject))
+                       (setq cs-coding (intern cs-string))))))
+       subject
+      (with-temp-buffer
+       (insert subject)
+       (goto-char (point-min))
+       (while (re-search-forward enc-word-re nil t)
+         (setq cs-string (downcase (match-string 1))
+               q-or-b    (match-string 2)
+               word-beg (match-beginning 0)
+               word-end (match-end 0))
+         (setq cs-coding
+               (if (mm-coding-system-p (intern cs-string))
+                   (setq cs-coding (intern cs-string))
+                 nil))
+         ;; No double encoded subject? => bogus charset.
+         (unless cs-coding
+           (setq cs-coding
+                 (mm-read-coding-system
+                  (gnus-format-message "\
+Decoded Subject \"%s\"
+contains an encoded word.  The charset `%s' is unknown or invalid.
+Hit RET to replace non-decodable characters with \"%s\" or enter replacement
+charset: "
+                          subject cs-string message-replacement-char)))
+           (if cs-coding
+               (replace-match (concat "=?" (symbol-name cs-coding)
+                                      "?\\2?\\3\\4\\5"))
+             (save-excursion
+               (goto-char word-beg)
+               (re-search-forward "=\\?\\([^?]+\\)\\?\\([QB]\\)\\?" word-end t)
+               (replace-match "")
+               ;; QP or base64
+               (if (string-match "\\`Q\\'" q-or-b)
+                   ;; QP
+                   (progn
+                     (message "Replacing non-decodable characters with \"%s\"."
+                              message-replacement-char)
+                     (while (re-search-forward "\\(=[A-F0-9][A-F0-9]\\)+"
+                                               word-end t)
+                       (replace-match message-replacement-char)))
+                 ;; base64
+                 (message "Replacing non-decodable characters with \"%s\"."
+                          replacement-chars)
+                 (re-search-forward "[^?]+" word-end t)
+                 (replace-match replacement-chars))
+               (re-search-forward "\\?=")
+               (replace-match "")))))
+       (rfc2047-decode-region (point-min) (point-max))
+       (buffer-string)))))
+
+;;; Start of functions adopted from `message-utils.el'.
+
+(defun message-strip-subject-trailing-was (subject)
+  "Remove trailing \"(was: <old subject>)\" from SUBJECT lines.
+Leading \"Re: \" is not stripped by this function.  Use the function
+`message-strip-subject-re' for this."
+  (let* ((query message-subject-trailing-was-query)
+        (new) (found))
+    (setq found
+         (string-match
+          (if (eq query 'ask)
+              message-subject-trailing-was-ask-regexp
+            message-subject-trailing-was-regexp)
+          subject))
+    (if found
+       (setq new (substring subject 0 (match-beginning 0))))
+    (if (or (not found) (eq query nil))
+       subject
+      (if (eq query 'ask)
+         (if (message-y-or-n-p
+              "Strip `(was: <old subject>)' in subject? " t
+              (concat
+               "Strip `(was: <old subject>)' in subject "
+               "and use the new one instead?\n\n"
+               "Current subject is:   \""
+               subject "\"\n\n"
+               "New subject would be: \""
+               new "\"\n\n"
+               "See the variable `message-subject-trailing-was-query' "
+               "to get rid of this query."
+               ))
+             new subject)
+       new))))
+
+;;; Suggested by Jonas Steverud  @  www.dtek.chalmers.se/~d4jonas/
+
+(defun message-change-subject (new-subject)
+  "Ask for NEW-SUBJECT header, append (was: <Old Subject>)."
+  (interactive
+   (list
+    (read-from-minibuffer "New subject: ")))
+  (cond ((and (not (or (null new-subject) ; new subject not empty
+                      (zerop (string-width new-subject))
+                      (string-match "^[ \t]*$" new-subject))))
+        (save-excursion
+          (let ((old-subject
+                 (save-restriction
+                   (message-narrow-to-headers)
+                   (message-fetch-field "Subject"))))
+            (cond ((not old-subject)
+                   (error "No current subject"))
+                  ((not (string-match
+                         (concat "^[ \t]*"
+                                 (regexp-quote new-subject)
+                                 "[ \t]*$")
+                         old-subject))  ; yes, it really is a new subject
+                   ;; delete eventual Re: prefix
+                   (setq old-subject
+                         (message-strip-subject-re old-subject))
+                   (message-goto-subject)
+                   (message-delete-line)
+                   (insert (concat "Subject: "
+                                   new-subject
+                                   " (was: "
+                                   old-subject ")\n")))))))))
+
+(defun message-mark-inserted-region (beg end &optional verbatim)
+  "Mark some region in the current article with enclosing tags.
+See `message-mark-insert-begin' and `message-mark-insert-end'.
+If VERBATIM, use slrn style verbatim marks (\"#v+\" and \"#v-\")."
+  (interactive "r\nP")
+  (save-excursion
+    ;; add to the end of the region first, otherwise end would be invalid
+    (goto-char end)
+    (insert (if verbatim "#v-\n" message-mark-insert-end))
+    (goto-char beg)
+    (insert (if verbatim "#v+\n" message-mark-insert-begin))))
+
+(defun message-mark-insert-file (file &optional verbatim)
+  "Insert FILE at point, marking it with enclosing tags.
+See `message-mark-insert-begin' and `message-mark-insert-end'.
+If VERBATIM, use slrn style verbatim marks (\"#v+\" and \"#v-\")."
+  (interactive "fFile to insert: \nP")
+    ;; reverse insertion to get correct result.
+  (let ((p (point)))
+    (insert (if verbatim "#v-\n" message-mark-insert-end))
+    (goto-char p)
+    (insert-file-contents file)
+    (goto-char p)
+    (insert (if verbatim "#v+\n" message-mark-insert-begin))))
+
+(defun message-add-archive-header ()
+  "Insert \"X-No-Archive: Yes\" in the header and a note in the body.
+The note can be customized using `message-archive-note'.  When called with a
+prefix argument, ask for a text to insert.  If you don't want the note in the
+body, set  `message-archive-note' to nil."
+  (interactive)
+  (if current-prefix-arg
+      (setq message-archive-note
+           (read-from-minibuffer "Reason for No-Archive: "
+                                 (cons message-archive-note 0))))
+    (save-excursion
+      (if (message-goto-signature)
+         (re-search-backward message-signature-separator))
+      (when message-archive-note
+       (insert message-archive-note)
+       (newline))
+      (message-add-header message-archive-header)
+      (message-sort-headers)))
+
+(defun message-cross-post-followup-to-header (target-group)
+  "Mangles FollowUp-To and Newsgroups header to point to TARGET-GROUP.
+With prefix-argument just set Follow-Up, don't cross-post."
+  (interactive
+   (list ; Completion based on Gnus
+    (completing-read "Followup To: "
+                    (if (boundp 'gnus-newsrc-alist)
+                        gnus-newsrc-alist)
+                    nil nil '("poster" . 0)
+                    (if (boundp 'gnus-group-history)
+                        'gnus-group-history))))
+  (message-remove-header "Follow[Uu]p-[Tt]o" t)
+  (message-goto-newsgroups)
+  (beginning-of-line)
+  ;; if we already did a crosspost before, kill old target
+  (if (and message-cross-post-old-target
+          (re-search-forward
+           (regexp-quote (concat "," message-cross-post-old-target))
+           nil t))
+      (replace-match ""))
+  ;; unless (followup is to poster or user explicitly asked not
+  ;; to cross-post, or target-group is already in Newsgroups)
+  ;; add target-group to Newsgroups line.
+  (cond ((and (or
+              ;; def: cross-post, req:no
+              (and message-cross-post-default (not current-prefix-arg))
+              ;; def: no-cross-post, req:yes
+              (and (not message-cross-post-default) current-prefix-arg))
+             (not (string-match "poster" target-group))
+             (not (string-match (regexp-quote target-group)
+                                (message-fetch-field "Newsgroups"))))
+        (end-of-line)
+        (insert (concat "," target-group))))
+  (end-of-line) ; ensure Followup: comes after Newsgroups:
+  ;; unless new followup would be identical to Newsgroups line
+  ;; make a new Followup-To line
+  (if (not (string-match (concat "^[ \t]*"
+                                target-group
+                                "[ \t]*$")
+                        (message-fetch-field "Newsgroups")))
+      (insert (concat "\nFollowup-To: " target-group)))
+  (setq message-cross-post-old-target target-group))
+
+(defun message-cross-post-insert-note (target-group cross-post in-old
+                                                   old-groups)
+  "Insert a in message body note about a set Followup or Crosspost.
+If there have been previous notes, delete them.  TARGET-GROUP specifies the
+group to Followup-To.  When CROSS-POST is t, insert note about
+crossposting.  IN-OLD specifies whether TARGET-GROUP is a member of
+OLD-GROUPS.  OLD-GROUPS lists the old-groups the posting would have
+been made to before the user asked for a Crosspost."
+  ;; start scanning body for previous uses
+  (message-goto-signature)
+  (let ((head (re-search-backward
+              (concat "^" mail-header-separator)
+              nil t))) ; just search in body
+    (message-goto-signature)
+    (while (re-search-backward
+           (concat "^" (regexp-quote message-cross-post-note) ".*")
+           head t)
+      (message-delete-line))
+    (message-goto-signature)
+    (while (re-search-backward
+           (concat "^" (regexp-quote message-followup-to-note) ".*")
+           head t)
+      (message-delete-line))
+    ;; insert new note
+    (if (message-goto-signature)
+       (re-search-backward message-signature-separator))
+    (if (or in-old
+           (not cross-post)
+           (string-match "^[ \t]*poster[ \t]*$" target-group))
+       (insert (concat message-followup-to-note target-group "\n"))
+      (insert (concat message-cross-post-note target-group "\n")))))
+
+(defun message-cross-post-followup-to (target-group)
+  "Crossposts message and set Followup-To to TARGET-GROUP.
+With prefix-argument just set Follow-Up, don't cross-post."
+  (interactive
+   (list ; Completion based on Gnus
+    (completing-read "Followup To: "
+                    (if (boundp 'gnus-newsrc-alist)
+                        gnus-newsrc-alist)
+                    nil nil '("poster" . 0)
+                    (if (boundp 'gnus-group-history)
+                        'gnus-group-history))))
+  (cond ((not (or (null target-group) ; new subject not empty
+                 (zerop (string-width target-group))
+                 (string-match "^[ \t]*$" target-group)))
+        (save-excursion
+          (let* ((old-groups (message-fetch-field "Newsgroups"))
+                 (in-old (string-match
+                          (regexp-quote target-group)
+                          (or old-groups ""))))
+            ;; check whether target exactly matches old Newsgroups
+            (cond ((not old-groups)
+                   (error "No current newsgroup"))
+                  ((or (not in-old)
+                       (not (string-match
+                             (concat "^[ \t]*"
+                                     (regexp-quote target-group)
+                                     "[ \t]*$")
+                             old-groups)))
+                   ;; yes, Newsgroups line must change
+                   (message-cross-post-followup-to-header target-group)
+                   ;; insert note whether we do cross-post or followup-to
+                   (funcall message-cross-post-note-function
+                            target-group
+                            (if (or (and message-cross-post-default
+                                         (not current-prefix-arg))
+                                    (and (not message-cross-post-default)
+                                         current-prefix-arg)) t)
+                            in-old old-groups))))))))
+
+;;; Reduce To: to Cc: or Bcc: header
+
+(defun message-reduce-to-to-cc ()
+ "Replace contents of To: header with contents of Cc: or Bcc: header."
+ (interactive)
+ (let ((cc-content
+       (save-restriction (message-narrow-to-headers)
+                         (message-fetch-field "cc")))
+       (bcc nil))
+   (if (and (not cc-content)
+           (setq cc-content
+                 (save-restriction
+                   (message-narrow-to-headers)
+                   (message-fetch-field "bcc"))))
+       (setq bcc t))
+   (cond (cc-content
+         (save-excursion
+           (message-goto-to)
+           (message-delete-line)
+           (insert (concat "To: " cc-content "\n"))
+           (save-restriction
+             (message-narrow-to-headers)
+             (message-remove-header (if bcc
+                                        "bcc"
+                                      "cc"))))))))
+
+;;; End of functions adopted from `message-utils.el'.
+
+(defun message-remove-header (header &optional is-regexp first reverse)
+  "Remove HEADER in the narrowed buffer.
+If IS-REGEXP, HEADER is a regular expression.
+If FIRST, only remove the first instance of the header.
+If REVERSE, remove headers that doesn't match HEADER.
+Return the number of headers removed."
+  (goto-char (point-min))
+  (let ((regexp (if is-regexp header (concat "^" (regexp-quote header) ":")))
+       (number 0)
+       (case-fold-search t)
+       last)
+    (while (and (not (eobp))
+               (not last))
+      (if (if reverse
+             (not (looking-at regexp))
+           (looking-at regexp))
+         (progn
+           (incf number)
+           (when first
+             (setq last t))
+           (delete-region
+            (point)
+            ;; There might be a continuation header, so we have to search
+            ;; until we find a new non-continuation line.
+            (progn
+              (forward-line 1)
+              (if (re-search-forward "^[^ \t]" nil t)
+                  (goto-char (match-beginning 0))
+                (point-max)))))
+       (forward-line 1)
+       (if (re-search-forward "^[^ \t]" nil t)
+           (goto-char (match-beginning 0))
+         (goto-char (point-max)))))
+    number))
+
+(defun message-remove-first-header (header)
+  "Remove the first instance of HEADER if there is more than one."
+  (let ((count 0)
+       (regexp (concat "^" (regexp-quote header) ":")))
+    (save-excursion
+      (goto-char (point-min))
+      (while (re-search-forward regexp nil t)
+       (incf count)))
+    (while (> count 1)
+      (message-remove-header header nil t)
+      (decf count))))
+
+(defun message-narrow-to-headers ()
+  "Narrow the buffer to the head of the message."
+  (widen)
+  (narrow-to-region
+   (goto-char (point-min))
+   (if (re-search-forward
+       (concat "^" (regexp-quote mail-header-separator) "\n") nil t)
+       (match-beginning 0)
+     (point-max)))
+  (goto-char (point-min)))
+
+(defun message-narrow-to-head-1 ()
+  "Like `message-narrow-to-head'.  Don't widen."
+  (narrow-to-region
+   (goto-char (point-min))
+   (if (search-forward "\n\n" nil 1)
+       (1- (point))
+     (point-max)))
+  (goto-char (point-min)))
+
+;; FIXME: clarify difference: message-narrow-to-head,
+;; message-narrow-to-headers-or-head, message-narrow-to-headers
+(defun message-narrow-to-head ()
+  "Narrow the buffer to the head of the message.
+Point is left at the beginning of the narrowed-to region."
+  (widen)
+  (message-narrow-to-head-1))
+
+(defun message-narrow-to-headers-or-head ()
+  "Narrow the buffer to the head of the message."
+  (widen)
+  (narrow-to-region
+   (goto-char (point-min))
+   (if (re-search-forward (concat "\\(\n\\)\n\\|^\\("
+                                 (regexp-quote mail-header-separator)
+                                 "\n\\)")
+                         nil t)
+       (or (match-end 1) (match-beginning 2))
+     (point-max)))
+  (goto-char (point-min)))
+
+(defun message-news-p ()
+  "Say whether the current buffer contains a news message."
+  (and (not message-this-is-mail)
+       (or message-this-is-news
+          (save-excursion
+            (save-restriction
+              (message-narrow-to-headers)
+              (and (message-fetch-field "newsgroups")
+                   (not (message-fetch-field "posted-to"))))))))
+
+(defun message-mail-p ()
+  "Say whether the current buffer contains a mail message."
+  (and (not message-this-is-news)
+       (or message-this-is-mail
+          (save-excursion
+            (save-restriction
+              (message-narrow-to-headers)
+              (or (message-fetch-field "to")
+                  (message-fetch-field "cc")
+                  (message-fetch-field "bcc")))))))
+
+(defun message-subscribed-p ()
+  "Say whether we need to insert a MFT header."
+  (or message-subscribed-regexps
+      message-subscribed-addresses
+      message-subscribed-address-file
+      message-subscribed-address-functions))
+
+(defun message-next-header ()
+  "Go to the beginning of the next header."
+  (beginning-of-line)
+  (or (eobp) (forward-char 1))
+  (not (if (re-search-forward "^[^ \t]" nil t)
+          (beginning-of-line)
+        (goto-char (point-max)))))
+
+(defun message-sort-headers-1 ()
+  "Sort the buffer as headers using `message-rank' text props."
+  (goto-char (point-min))
+  (require 'sort)
+  (sort-subr
+   nil 'message-next-header
+   (lambda ()
+     (message-next-header)
+     (unless (bobp)
+       (forward-char -1)))
+   (lambda ()
+     (or (get-text-property (point) 'message-rank)
+        10000))))
+
+(defun message-sort-headers ()
+  "Sort the headers of the current message according to `message-header-format-alist'."
+  (interactive)
+  (save-excursion
+    (save-restriction
+      (let ((max (1+ (length message-header-format-alist)))
+           rank)
+       (message-narrow-to-headers)
+       (while (re-search-forward "^[^ \n]+:" nil t)
+         (put-text-property
+          (match-beginning 0) (1+ (match-beginning 0))
+          'message-rank
+          (if (setq rank (length (memq (assq (intern (buffer-substring
+                                                      (match-beginning 0)
+                                                      (1- (match-end 0))))
+                                             message-header-format-alist)
+                                       message-header-format-alist)))
+              (- max rank)
+            (1+ max)))))
+      (message-sort-headers-1))))
+
+(defun message-kill-address ()
+  "Kill the address under point."
+  (interactive)
+  (let ((start (point)))
+    (message-skip-to-next-address)
+    (kill-region start (if (bolp) (1- (point)) (point)))))
+
+
+(autoload 'Info-goto-node "info")
+(defvar mml2015-use)
+
+(defun message-info (&optional arg)
+  "Display the Message manual.
+
+Prefixed with one \\[universal-argument], display the Emacs MIME
+manual.  With two \\[universal-argument]'s, display the EasyPG or
+PGG manual, depending on the value of `mml2015-use'."
+  (interactive "p")
+  ;; Don't use `info' because support for `(filename)nodename' is not
+  ;; available in XEmacs < 21.5.12.
+  (Info-goto-node (format "(%s)Top"
+                         (cond ((eq arg 16)
+                                (require 'mml2015)
+                                mml2015-use)
+                               ((eq arg  4) 'emacs-mime)
+                               ;; `booleanp' only available in Emacs 22+
+                               ((and (not (memq arg '(nil t)))
+                                     (symbolp arg))
+                                arg)
+                               (t
+                                'message)))))
+
+\f
+
+;;;
+;;; Message mode
+;;;
+
+;;; Set up keymap.
+
+(defvar message-mode-map nil)
+
+(unless message-mode-map
+  (setq message-mode-map (make-keymap))
+  (set-keymap-parent message-mode-map text-mode-map)
+  (define-key message-mode-map "\C-c?" 'describe-mode)
+
+  (define-key message-mode-map "\C-c\C-f\C-t" 'message-goto-to)
+  (define-key message-mode-map "\C-c\C-f\C-o" 'message-goto-from)
+  (define-key message-mode-map "\C-c\C-f\C-b" 'message-goto-bcc)
+  (define-key message-mode-map "\C-c\C-f\C-w" 'message-goto-fcc)
+  (define-key message-mode-map "\C-c\C-f\C-c" 'message-goto-cc)
+  (define-key message-mode-map "\C-c\C-f\C-s" 'message-goto-subject)
+  (define-key message-mode-map "\C-c\C-f\C-r" 'message-goto-reply-to)
+  (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-f\C-a"
+    'message-generate-unsubscribed-mail-followup-to)
+
+  ;; modify headers (and insert notes in body)
+  (define-key message-mode-map "\C-c\C-fs"    'message-change-subject)
+  ;;
+  (define-key message-mode-map "\C-c\C-fx"    'message-cross-post-followup-to)
+  ;; prefix+message-cross-post-followup-to = same w/o cross-post
+  (define-key message-mode-map "\C-c\C-ft"    'message-reduce-to-to-cc)
+  (define-key message-mode-map "\C-c\C-fa"    'message-add-archive-header)
+  ;; mark inserted text
+  (define-key message-mode-map "\C-c\M-m" 'message-mark-inserted-region)
+  (define-key message-mode-map "\C-c\M-f" 'message-mark-insert-file)
+
+  (define-key message-mode-map "\C-c\C-b" 'message-goto-body)
+  (define-key message-mode-map "\C-c\C-i" 'message-goto-signature)
+
+  (define-key message-mode-map "\C-c\C-t" 'message-insert-to)
+  (define-key message-mode-map "\C-c\C-fw" 'message-insert-wide-reply)
+  (define-key message-mode-map "\C-c\C-n" 'message-insert-newsgroups)
+  (define-key message-mode-map "\C-c\C-l" 'message-to-list-only)
+  (define-key message-mode-map "\C-c\C-f\C-e" 'message-insert-expires)
+
+  (define-key message-mode-map "\C-c\C-u" 'message-insert-or-toggle-importance)
+  (define-key message-mode-map "\C-c\M-n"
+    'message-insert-disposition-notification-to)
+
+  (define-key message-mode-map "\C-c\C-y" 'message-yank-original)
+  (define-key message-mode-map "\C-c\M-\C-y" 'message-yank-buffer)
+  (define-key message-mode-map "\C-c\C-q" 'message-fill-yanked-message)
+  (define-key message-mode-map "\C-c\C-w" 'message-insert-signature)
+  (define-key message-mode-map "\C-c\M-h" 'message-insert-headers)
+  (define-key message-mode-map "\C-c\C-r" 'message-caesar-buffer-body)
+  (define-key message-mode-map "\C-c\C-o" 'message-sort-headers)
+  (define-key message-mode-map "\C-c\M-r" 'message-rename-buffer)
+
+  (define-key message-mode-map "\C-c\C-c" 'message-send-and-exit)
+  (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\M-k" 'message-kill-address)
+  (define-key message-mode-map "\C-c\C-e" 'message-elide-region)
+  (define-key message-mode-map "\C-c\C-v" 'message-delete-not-region)
+  (define-key message-mode-map "\C-c\C-z" 'message-kill-to-signature)
+  (define-key message-mode-map "\M-\r" 'message-newline-and-reformat)
+  (define-key message-mode-map [remap split-line]  'message-split-line)
+
+  (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-n" 'message-display-abbrev))
+
+(easy-menu-define
+  message-mode-menu message-mode-map "Message Menu."
+  `("Message"
+    ["Yank Original" message-yank-original message-reply-buffer]
+    ["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 (message-mark-active-p)]
+    ["Elide Region" message-elide-region
+     :active (message-mark-active-p)
+     ,@(if (featurep 'xemacs) nil
+        '(:help "Replace text in region with an ellipsis"))]
+    ["Delete Outside Region" message-delete-not-region
+     :active (message-mark-active-p)
+     ,@(if (featurep 'xemacs) nil
+        '(:help "Delete all quoted text outside region"))]
+    ["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"))]
+    "----"
+    ["Insert Region Marked" message-mark-inserted-region
+     :active (message-mark-active-p)
+     ,@(if (featurep 'xemacs) nil
+        '(:help "Mark region with enclosing tags"))]
+    ["Insert File Marked..." message-mark-insert-file
+     ,@(if (featurep 'xemacs) '(t)
+        '(:help "Insert file at point marked with enclosing tags"))]
+    "----"
+    ["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"))]
+    "----"
+    ["Message manual" message-info
+     ,@(if (featurep 'xemacs) '(t)
+        '(:help "Display the Message manual"))]))
+
+(easy-menu-define
+  message-mode-field-menu message-mode-map ""
+  `("Field"
+    ["To" message-goto-to t]
+    ["From" message-goto-from t]
+    ["Subject" message-goto-subject t]
+    ["Change subject..." message-change-subject t]
+    ["Cc" message-goto-cc t]
+    ["Bcc" message-goto-bcc t]
+    ["Fcc" message-goto-fcc t]
+    ["Reply-To" message-goto-reply-to 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"))]
+    ["Request Receipt"
+     message-insert-disposition-notification-to
+     ,@(if (featurep 'xemacs) '(t)
+        '(:help "Request a receipt notification"))]
+    "----"
+    ;; (typical) news stuff
+    ["Summary" message-goto-summary t]
+    ["Keywords" message-goto-keywords t]
+    ["Newsgroups" message-goto-newsgroups t]
+    ["Fetch Newsgroups" message-insert-newsgroups t]
+    ["Followup-To" message-goto-followup-to t]
+    ;; ["Followup-To (with note in body)" message-cross-post-followup-to t]
+    ["Crosspost / Followup-To..." message-cross-post-followup-to t]
+    ["Distribution" message-goto-distribution t]
+    ["Expires" message-insert-expires t ]
+    ["X-No-Archive" message-add-archive-header t ]
+    "----"
+    ;; (typical) mailing-lists stuff
+    ["Fetch To" message-insert-to
+     ,@(if (featurep 'xemacs) '(t)
+        '(:help "Insert a To header that points to the author."))]
+    ["Fetch To and Cc" message-insert-wide-reply
+     ,@(if (featurep 'xemacs) '(t)
+        '(:help
+          "Insert To and Cc headers as if you were doing a wide reply."))]
+    "----"
+    ["Send to list only" message-to-list-only t]
+    ["Mail-Followup-To" message-goto-mail-followup-to t]
+    ["Unsubscribed list post" message-generate-unsubscribed-mail-followup-to
+     ,@(if (featurep 'xemacs) '(t)
+        '(:help "Insert a reasonable `Mail-Followup-To:' header."))]
+    ["Reduce To: to Cc:" message-reduce-to-to-cc t]
+    "----"
+    ["Sort Headers" message-sort-headers t]
+    ["Encode non-ASCII domain names" message-idna-to-ascii-rhs t]
+    ;; We hide `message-hidden-headers' by narrowing the buffer.
+    ["Show Hidden Headers" widen t]
+    ["Goto Body" message-goto-body t]
+    ["Goto Signature" message-goto-signature t]))
+
+(defvar message-tool-bar-map nil)
+
+(defvar facemenu-add-face-function)
+(defvar facemenu-remove-face-function)
+
+;;; Forbidden properties
+;;
+;; We use `after-change-functions' to keep special text properties
+;; that interfere 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."
+  :version "22.1"
+  :group 'message-various
+  :link '(custom-manual "(message)Various Message Variables")
+  :type 'boolean)
+
+(defvar 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 invisible nil intangible 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)))))
+
+(defsubst message-mail-alias-type-p (type)
+  (if (atom message-mail-alias-type)
+      (eq message-mail-alias-type type)
+    (memq type message-mail-alias-type)))
+
+(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-mail-alias-type-p 'ecomplete)
+            (memq this-command message-self-insert-commands))
+    (message-display-abbrev))
+  (when (and message-strip-special-text-properties
+            (message-tamago-not-in-use-p begin))
+    (let ((buffer-read-only nil)
+         (inhibit-read-only t))
+      (remove-text-properties begin end message-forbidden-properties))))
+
+(autoload 'ecomplete-setup "ecomplete") ;; for Emacs <23.
+
+(defvar message-smileys '(":-)" ":)"
+                          ":-(" ":("
+                          ";-)" ";)")
+  "A list of recognized smiley faces in `message-mode'.")
+
+(defun message--syntax-propertize (beg end)
+  "Syntax-propertize certain message text specially."
+  (let ((citation-regexp (concat "^" message-cite-prefix-regexp ".*$"))
+        (smiley-regexp (regexp-opt message-smileys)))
+    (goto-char beg)
+    (while (search-forward-regexp citation-regexp
+                                  end 'noerror)
+      (let ((start (match-beginning 0))
+            (end (match-end 0)))
+        (add-text-properties start (1+ start)
+                             `(syntax-table ,(string-to-syntax "<")))
+        (add-text-properties end (min (1+ end) (point-max))
+                             `(syntax-table ,(string-to-syntax ">")))))
+    (goto-char beg)
+    (while (search-forward-regexp smiley-regexp
+            end 'noerror)
+      (add-text-properties (match-beginning 0) (match-end 0)
+                           `(syntax-table ,(string-to-syntax "."))))))
+
+;;;###autoload
+(define-derived-mode message-mode text-mode "Message"
+  "Major mode for editing mail and news to be sent.
+Like Text Mode but with these additional commands:\\<message-mode-map>
+C-c C-s  `message-send' (send the message)  C-c C-c  `message-send-and-exit'
+C-c C-d  Postpone sending the message       C-c C-k  Kill the message
+C-c C-f  move to a header field (and create it if there isn't):
+        C-c C-f C-t  move to To        C-c C-f C-s  move to Subject
+        C-c C-f C-c  move to Cc        C-c C-f C-b  move to Bcc
+        C-c C-f C-w  move to Fcc       C-c C-f C-r  move to Reply-To
+        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-o  move to From (\"Originator\")
+        C-c C-f C-f  move to Followup-To
+        C-c C-f C-m  move to Mail-Followup-To
+        C-c C-f C-e  move to Expires
+        C-c C-f C-i  cycle through Importance values
+        C-c C-f s    change subject and append \"(was: <Old Subject>)\"
+        C-c C-f x    crossposting with FollowUp-To header and note in body
+        C-c C-f t    replace To: header with contents of Cc: or Bcc:
+        C-c C-f a    Insert X-No-Archive: header and a note in the body
+C-c C-t  `message-insert-to' (add a To header to a news followup)
+C-c C-l  `message-to-list-only' (removes all but list address in to/cc)
+C-c C-n  `message-insert-newsgroups' (add a Newsgroup header to a news reply)
+C-c C-b  `message-goto-body' (move to beginning of message text).
+C-c C-i  `message-goto-signature' (move to the beginning of the signature).
+C-c C-w  `message-insert-signature' (insert `message-signature-file' file).
+C-c C-y  `message-yank-original' (insert current message, if any).
+C-c C-q  `message-fill-yanked-message' (fill what was yanked).
+C-c C-e  `message-elide-region' (elide the text between point and mark).
+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).
+C-c M-n  `message-insert-disposition-notification-to'  (request receipt).
+C-c M-m  `message-mark-inserted-region' (mark region with enclosing tags).
+C-c M-f  `message-mark-insert-file' (insert file marked with enclosing tags).
+M-RET    `message-newline-and-reformat' (break the line and reformat)."
+  (set (make-local-variable 'message-reply-buffer) nil)
+  (set (make-local-variable 'message-inserted-headers) nil)
+  (set (make-local-variable 'message-send-actions) nil)
+  (set (make-local-variable 'message-return-action) nil)
+  (set (make-local-variable 'message-exit-actions) nil)
+  (set (make-local-variable 'message-kill-actions) nil)
+  (set (make-local-variable 'message-postpone-actions) nil)
+  (set (make-local-variable 'message-draft-article) nil)
+  (setq buffer-offer-save t)
+  (set (make-local-variable 'facemenu-add-face-function)
+       (lambda (face end)
+        (let ((face-fun (cdr (assq face message-face-alist))))
+          (if face-fun
+              (funcall face-fun (point) end)
+            (error "Face %s not configured for %s mode" face mode-name)))
+        ""))
+  (set (make-local-variable 'facemenu-remove-face-function) t)
+  (set (make-local-variable 'message-reply-headers) nil)
+  (make-local-variable 'message-newsreader)
+  (make-local-variable 'message-mailer)
+  (make-local-variable 'message-post-method)
+  (set (make-local-variable 'message-sent-message-via) nil)
+  (set (make-local-variable 'message-checksum) nil)
+  (set (make-local-variable 'message-mime-part) 0)
+  (message-setup-fill-variables)
+  (when message-fill-column
+    (setq fill-column message-fill-column)
+    (turn-on-auto-fill))
+  ;; Allow using comment commands to add/remove quoting.
+  ;; (set (make-local-variable 'comment-start) message-yank-prefix)
+  (when message-yank-prefix
+    (set (make-local-variable 'comment-start) message-yank-prefix)
+    (set (make-local-variable 'comment-start-skip)
+        (concat "^" (regexp-quote message-yank-prefix) "[ \t]*")))
+  (if (featurep 'xemacs)
+      (message-setup-toolbar)
+    (set (make-local-variable 'font-lock-defaults)
+        '(message-font-lock-keywords t))
+    (if (boundp 'tool-bar-map)
+       (set (make-local-variable 'tool-bar-map) (message-make-tool-bar))))
+  (easy-menu-add message-mode-menu message-mode-map)
+  (easy-menu-add message-mode-field-menu message-mode-map)
+  (gnus-make-local-hook 'after-change-functions)
+  ;; Mmmm... Forbidden properties...
+  (add-hook 'after-change-functions 'message-strip-forbidden-properties
+           nil 'local)
+  ;; Allow mail alias things.
+  (cond
+   ((message-mail-alias-type-p 'abbrev)
+    (if (fboundp 'mail-abbrevs-setup)
+       (mail-abbrevs-setup)
+      (if (fboundp 'mail-aliases-setup)        ; warning avoidance
+         (mail-aliases-setup))))
+   ((message-mail-alias-type-p 'ecomplete)
+    (ecomplete-setup)))
+  (add-hook 'completion-at-point-functions 'message-completion-function nil t)
+  (unless buffer-file-name
+    (message-set-auto-save-file-name))
+  (unless (buffer-base-buffer)
+    ;; Don't enable multibyte on an indirect buffer.  Maybe enabling
+    ;; multibyte is not necessary at all. -- zsh
+    (mm-enable-multibyte))
+  (set (make-local-variable 'indent-tabs-mode) nil) ;No tabs for indentation.
+  (mml-mode)
+  ;; Syntactic fontification. Helps `show-paren-mode',
+  ;; `electric-pair-mode', and C-M-* navigation by syntactically
+  ;; excluding citations and other artifacts.
+  ;;
+  (set (make-local-variable 'syntax-propertize-function) 'message--syntax-propertize)
+  (set (make-local-variable 'parse-sexp-ignore-comments) t))
+
+(defun message-setup-fill-variables ()
+  "Setup message fill variables."
+  (set (make-local-variable 'fill-paragraph-function)
+       'message-fill-paragraph)
+  (make-local-variable 'paragraph-separate)
+  (make-local-variable 'paragraph-start)
+  (make-local-variable 'adaptive-fill-regexp)
+  (unless (boundp 'adaptive-fill-first-line-regexp)
+    (setq adaptive-fill-first-line-regexp nil))
+  (make-local-variable 'adaptive-fill-first-line-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]*")))
+    (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
+                                       ; mml tags
+          "<#!*/?\\(multipart\\|part\\|external\\|mml\\|secure\\)"))
+    (setq paragraph-separate paragraph-start)
+    (setq 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)))
+  (make-local-variable 'auto-fill-inhibit-regexp)
+  ;;(setq auto-fill-inhibit-regexp "^[A-Z][^: \n\t]+:")
+  (setq auto-fill-inhibit-regexp nil)
+  (make-local-variable 'normal-auto-fill-function)
+  (setq normal-auto-fill-function 'message-do-auto-fill)
+  ;; KLUDGE: auto fill might already be turned on in `text-mode-hook'.
+  ;; In that case, ensure that it uses the right function.  The real
+  ;; solution would be not to use `define-derived-mode', and run
+  ;; `text-mode-hook' ourself at the end of the mode.
+  ;; -- Per Abrahamsen <abraham@dina.kvl.dk> Date: 2001-10-19.
+  ;; This kludge is unneeded in Emacs>=21 since define-derived-mode is
+  ;; now careful to run parent hooks after the body.  --Stef
+  (when auto-fill-function
+    (setq auto-fill-function normal-auto-fill-function)))
+
+\f
+
+;;;
+;;; Message mode commands
+;;;
+
+;;; Movement commands
+
+(defun message-goto-to ()
+  "Move point to the To header."
+  (interactive)
+  (push-mark)
+  (message-position-on-field "To"))
+
+(defun message-goto-from ()
+  "Move point to the From header."
+  (interactive)
+  (push-mark)
+  (message-position-on-field "From"))
+
+(defun message-goto-subject ()
+  "Move point to the Subject header."
+  (interactive)
+  (push-mark)
+  (message-position-on-field "Subject"))
+
+(defun message-goto-cc ()
+  "Move point to the Cc header."
+  (interactive)
+  (push-mark)
+  (message-position-on-field "Cc" "To"))
+
+(defun message-goto-bcc ()
+  "Move point to the Bcc  header."
+  (interactive)
+  (push-mark)
+  (message-position-on-field "Bcc" "Cc" "To"))
+
+(defun message-goto-fcc ()
+  "Move point to the Fcc header."
+  (interactive)
+  (push-mark)
+  (message-position-on-field "Fcc" "To" "Newsgroups"))
+
+(defun message-goto-reply-to ()
+  "Move point to the Reply-To header."
+  (interactive)
+  (push-mark)
+  (message-position-on-field "Reply-To" "Subject"))
+
+(defun message-goto-newsgroups ()
+  "Move point to the Newsgroups header."
+  (interactive)
+  (push-mark)
+  (message-position-on-field "Newsgroups"))
+
+(defun message-goto-distribution ()
+  "Move point to the Distribution header."
+  (interactive)
+  (push-mark)
+  (message-position-on-field "Distribution"))
+
+(defun message-goto-followup-to ()
+  "Move point to the Followup-To header."
+  (interactive)
+  (push-mark)
+  (message-position-on-field "Followup-To" "Newsgroups"))
+
+(defun message-goto-mail-followup-to ()
+  "Move point to the Mail-Followup-To header."
+  (interactive)
+  (push-mark)
+  (message-position-on-field "Mail-Followup-To" "To"))
+
+(defun message-goto-keywords ()
+  "Move point to the Keywords header."
+  (interactive)
+  (push-mark)
+  (message-position-on-field "Keywords" "Subject"))
+
+(defun message-goto-summary ()
+  "Move point to the Summary header."
+  (interactive)
+  (push-mark)
+  (message-position-on-field "Summary" "Subject"))
+
+(defun message-goto-body ()
+  "Move point to the beginning of the message body."
+  (interactive)
+  (when (and (gmm-called-interactively-p 'any)
+            (looking-at "[ \t]*\n"))
+    (expand-abbrev))
+  (push-mark)
+  (goto-char (point-min))
+  (or (search-forward (concat "\n" mail-header-separator "\n") nil t)
+      (search-forward-regexp "[^:]+:\\([^\n]\\|\n[ \t]\\)+\n\n" nil t)))
+
+(defun message-in-body-p ()
+  "Return t if point is in the message body."
+  (>= (point)
+      (save-excursion
+       (goto-char (point-min))
+       (or (search-forward (concat "\n" mail-header-separator "\n") nil t)
+           (search-forward-regexp "[^:]+:\\([^\n]\\|\n[ \t]\\)+\n\n" nil t))
+       (point))))
+
+(defun message-goto-eoh ()
+  "Move point to the end of the headers."
+  (interactive)
+  (message-goto-body)
+  (forward-line -1))
+
+(defun message-goto-signature ()
+  "Move point to the beginning of the message signature.
+If there is no signature in the article, go to the end and
+return nil."
+  (interactive)
+  (push-mark)
+  (goto-char (point-min))
+  (if (re-search-forward message-signature-separator nil t)
+      (forward-line 1)
+    (goto-char (point-max))
+    nil))
+
+(defun message-generate-unsubscribed-mail-followup-to (&optional include-cc)
+  "Insert a reasonable MFT header in a post to an unsubscribed list.
+When making original posts to a mailing list you are not subscribed to,
+you have to type in a MFT header by hand.  The contents, usually, are
+the addresses of the list and your own address.  This function inserts
+such a header automatically.  It fetches the contents of the To: header
+in the current mail buffer, and appends the current `user-mail-address'.
+
+If the optional argument INCLUDE-CC is non-nil, the addresses in the
+Cc: header are also put into the MFT."
+
+  (interactive "P")
+  (let* (cc tos)
+    (save-restriction
+      (message-narrow-to-headers)
+      (message-remove-header "Mail-Followup-To")
+      (setq cc (and include-cc (message-fetch-field "Cc")))
+      (setq tos (if cc
+                   (concat (message-fetch-field "To") "," cc)
+                 (message-fetch-field "To"))))
+    (message-goto-mail-followup-to)
+    (insert (concat tos ", " user-mail-address))))
+
+\f
+
+(defun message-insert-to (&optional force)
+  "Insert a To header that points to the author of the article being replied to.
+If the original author requested not to be sent mail, don't insert unless the
+prefix FORCE is given."
+  (interactive "P")
+  (let* ((mct (message-fetch-reply-field "mail-copies-to"))
+        (dont (and mct (or (equal (downcase mct) "never")
+                           (equal (downcase mct) "nobody"))))
+        (to (or (message-fetch-reply-field "mail-reply-to")
+                (message-fetch-reply-field "reply-to")
+                (message-fetch-reply-field "from"))))
+    (when (and dont to)
+      (message
+       (if force
+          "Ignoring the user request not to have copies sent via mail"
+        "Complying with the user request not to have copies sent via mail")))
+    (when (and force (not to))
+      (error "No mail address in the article"))
+    (when (and to (or force (not dont)))
+      (message-carefully-insert-headers (list (cons 'To to))))))
+
+(defun message-insert-wide-reply ()
+  "Insert To and Cc headers as if you were doing a wide reply."
+  (interactive)
+  (let ((headers (message-with-reply-buffer
+                  (message-get-reply-headers t))))
+    (message-carefully-insert-headers headers)))
+
+(defcustom message-header-synonyms
+  '((To Cc Bcc)
+    (Original-To))
+  "List of lists of header synonyms.
+E.g., if this list contains a member list with elements `Cc' and `To',
+then `message-carefully-insert-headers' will not insert a `To' header
+when the message is already `Cc'ed to the recipient."
+  :version "22.1"
+  :group 'message-headers
+  :link '(custom-manual "(message)Message Headers")
+  :type '(repeat sexp))
+
+(defun message-carefully-insert-headers (headers)
+  "Insert the HEADERS, an alist, into the message buffer.
+Does not insert the headers when they are already present there
+or in the synonym headers, defined by `message-header-synonyms'."
+  ;; FIXME: Should compare only the address and not the full name.  Comparison
+  ;; should be done case-folded (and with `string=' rather than
+  ;; `string-match').
+  ;; (mail-strip-quoted-names "Foo Bar <foo@bar>, bla@fasel (Bla Fasel)")
+  (dolist (header headers)
+    (let* ((header-name (symbol-name (car header)))
+          (new-header (cdr header))
+          (synonyms (loop for synonym in message-header-synonyms
+                          when (memq (car header) synonym) return synonym))
+          (old-header
+           (loop for synonym in synonyms
+                 for old-header = (mail-fetch-field (symbol-name synonym))
+                 when (and old-header (string-match new-header old-header))
+                 return synonym)))
+      (if old-header
+         (message "already have `%s' in `%s'" new-header old-header)
+       (when (and (message-position-on-field header-name)
+                  (setq old-header (mail-fetch-field header-name))
+                  (not (string-match "\\` *\\'" old-header)))
+         (insert ", "))
+       (insert new-header)))))
+
+(defun message-widen-reply ()
+  "Widen the reply to include maximum recipients."
+  (interactive)
+  (let ((follow-to
+        (and (bufferp message-reply-buffer)
+             (buffer-name message-reply-buffer)
+             (with-current-buffer message-reply-buffer
+               (message-get-reply-headers t)))))
+    (save-excursion
+      (save-restriction
+       (message-narrow-to-headers)
+       (dolist (elem follow-to)
+         (message-remove-header (symbol-name (car elem)))
+         (goto-char (point-min))
+         (insert (symbol-name (car elem)) ": "
+                 (cdr elem) "\n"))))))
+
+(defun message-insert-newsgroups ()
+  "Insert the Newsgroups header from the article being replied to."
+  (interactive)
+  (let ((old-newsgroups (mail-fetch-field "newsgroups"))
+       (new-newsgroups (message-fetch-reply-field "newsgroups"))
+       (first t)
+       insert-newsgroups)
+    (message-position-on-field "Newsgroups")
+    (cond
+     ((not new-newsgroups)
+      (error "No Newsgroups to insert"))
+     ((not old-newsgroups)
+      (insert new-newsgroups))
+     (t
+      (setq new-newsgroups (split-string new-newsgroups "[, ]+")
+           old-newsgroups (split-string old-newsgroups "[, ]+"))
+      (dolist (group new-newsgroups)
+       (unless (member group old-newsgroups)
+         (push group insert-newsgroups)))
+      (if (null insert-newsgroups)
+         (error "Newgroup%s already in the header"
+                (if (> (length new-newsgroups) 1)
+                    "s" ""))
+       (when old-newsgroups
+         (setq first nil))
+       (dolist (group insert-newsgroups)
+         (unless first
+           (insert ","))
+         (setq first nil)
+         (insert group)))))))
+
+\f
+
+;;; Various commands
+
+(defun message-delete-not-region (beg end)
+  "Delete everything in the body of the current message outside of the region."
+  (interactive "r")
+  (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)))
+
+(defun message-kill-to-signature (&optional arg)
+  "Kill all text up to the signature.
+If a numeric argument or prefix arg is given, leave that number
+of lines before the signature intact."
+  (interactive "P")
+  (save-excursion
+    (save-restriction
+      (let ((point (point)))
+       (narrow-to-region point (point-max))
+       (message-goto-signature)
+       (unless (eobp)
+         (if (and arg (numberp arg))
+             (forward-line (- -1 arg))
+           (end-of-line -1)))
+       (unless (= point (point))
+         (kill-region point (point))
+         (unless (bolp)
+           (insert "\n")))))))
+
+(defun message-newline-and-reformat (&optional arg not-break)
+  "Insert four newlines, and then reformat if inside quoted text.
+Prefix arg means justify as well."
+  (interactive (list (if current-prefix-arg 'full)))
+  (let (quoted point beg end leading-space bolp fill-paragraph-function)
+    (setq point (point))
+    (beginning-of-line)
+    (setq beg (point))
+    (setq bolp (= beg point))
+    ;; Find first line of the paragraph.
+    (if not-break
+       (while (and (not (eobp))
+                   (not (looking-at message-cite-prefix-regexp))
+                   (looking-at paragraph-start))
+         (forward-line 1)))
+    ;; Find the prefix
+    (when (looking-at message-cite-prefix-regexp)
+      (setq quoted (match-string 0))
+      (goto-char (match-end 0))
+      (looking-at "[ \t]*")
+      (setq leading-space (match-string 0)))
+    (if (and quoted
+            (not not-break)
+            (not bolp)
+            (< (- point beg) (length quoted)))
+       ;; break inside the cite prefix.
+       (setq quoted nil
+             end nil))
+    (if quoted
+       (progn
+         (forward-line 1)
+         (while (and (not (eobp))
+                     (not (looking-at paragraph-separate))
+                     (looking-at message-cite-prefix-regexp)
+                     (equal quoted (match-string 0)))
+           (goto-char (match-end 0))
+           (looking-at "[ \t]*")
+           (if (> (length leading-space) (length (match-string 0)))
+               (setq leading-space (match-string 0)))
+           (forward-line 1))
+         (setq end (point))
+         (goto-char beg)
+         (while (and (if (bobp) nil (forward-line -1) t)
+                     (not (looking-at paragraph-start))
+                     (looking-at message-cite-prefix-regexp)
+                     (equal quoted (match-string 0)))
+           (setq beg (point))
+           (goto-char (match-end 0))
+           (looking-at "[ \t]*")
+           (if (> (length leading-space) (length (match-string 0)))
+               (setq leading-space (match-string 0)))))
+      (while (and (not (eobp))
+                 (not (looking-at paragraph-separate))
+                 (not (looking-at message-cite-prefix-regexp)))
+       (forward-line 1))
+      (setq end (point))
+      (goto-char beg)
+      (while (and (if (bobp) nil (forward-line -1) t)
+                 (not (looking-at paragraph-start))
+                 (not (looking-at message-cite-prefix-regexp)))
+       (setq beg (point))))
+    (goto-char point)
+    (save-restriction
+      (narrow-to-region beg end)
+      (if not-break
+         (setq point nil)
+       (if bolp
+           (newline)
+         (newline)
+         (newline))
+       (setq point (point))
+       ;; (newline 2) doesn't mark both newline's as hard, so call
+       ;; newline twice. -jas
+       (newline)
+       (newline)
+       (delete-region (point) (re-search-forward "[ \t]*"))
+       (when (and quoted (not bolp))
+         (insert quoted leading-space)))
+      (undo-boundary)
+      (if quoted
+         (let* ((adaptive-fill-regexp
+                 (regexp-quote (concat quoted leading-space)))
+                (adaptive-fill-first-line-regexp
+                 adaptive-fill-regexp ))
+           (fill-paragraph arg))
+       (fill-paragraph arg))
+      (if point (goto-char point)))))
+
+(defun message-fill-paragraph (&optional arg)
+  "Message specific function to fill a paragraph.
+This function is used as the value of `fill-paragraph-function' in
+Message buffers and is not meant to be called directly."
+  (interactive (list (if current-prefix-arg 'full)))
+  (if (if (boundp 'filladapt-mode) filladapt-mode)
+      nil
+    (if (message-point-in-header-p)
+       (message-fill-field)
+      (message-newline-and-reformat arg t))
+    t))
+
+(defun message-point-in-header-p ()
+  "Return t if point is in the header."
+  (save-excursion
+    (and
+     (not
+      (re-search-backward
+       (concat "^" (regexp-quote mail-header-separator) "\n") nil t))
+     (re-search-forward
+      (concat "^" (regexp-quote mail-header-separator) "\n") nil 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'."
+  (interactive (list 0))
+  (let* ((signature
+         (cond
+          ((and (null message-signature)
+                (eq force 0))
+           (save-excursion
+             (goto-char (point-max))
+             (not (re-search-backward message-signature-separator nil t))))
+          ((and (null message-signature)
+                force)
+           t)
+          ((functionp message-signature)
+           (funcall message-signature))
+          ((listp message-signature)
+           (eval message-signature))
+          (t message-signature)))
+        signature-file)
+    (setq signature
+         (cond ((stringp signature)
+                signature)
+               ((and (eq t signature) message-signature-file)
+                (setq signature-file
+                      (if (and message-signature-directory
+                               ;; don't actually use the signature directory
+                               ;; if message-signature-file contains a path.
+                               (not (file-name-directory
+                                     message-signature-file)))
+                          (expand-file-name message-signature-file
+                                            message-signature-directory)
+                        message-signature-file))
+                (file-exists-p signature-file))))
+    (when signature
+      (goto-char (point-max))
+      ;; Insert the signature.
+      (unless (bolp)
+       (newline))
+      (when message-signature-insert-empty-line
+       (newline))
+      (insert "-- ")
+      (newline)
+      (if (eq signature t)
+         (insert-file-contents signature-file)
+       (insert signature))
+      (goto-char (point-max))
+      (or (bolp) (newline)))))
+
+(defun message-insert-importance-high ()
+  "Insert header to mark message as important."
+  (interactive)
+  (save-excursion
+    (save-restriction
+      (message-narrow-to-headers)
+      (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
+    (save-restriction
+      (message-narrow-to-headers)
+      (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 ((new "high")
+         cur)
+      (save-restriction
+       (message-narrow-to-headers)
+       (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-insert-disposition-notification-to ()
+  "Request a disposition notification (return receipt) to this message.
+Note that this should not be used in newsgroups."
+  (interactive)
+  (save-excursion
+    (save-restriction
+      (message-narrow-to-headers)
+      (message-remove-header "Disposition-Notification-To"))
+    (message-goto-eoh)
+    (insert (format "Disposition-Notification-To: %s\n"
+                   (or (message-field-value "Reply-to")
+                       (message-field-value "From")
+                       (message-make-from))))))
+
+(defun message-elide-region (b e)
+  "Elide the text in the region.
+An ellipsis (from `message-elide-ellipsis') will be inserted where the
+text was killed."
+  (interactive "r")
+  (let ((lines (count-lines b e))
+        (chars (- e b)))
+    (kill-region b e)
+    (insert (format-spec message-elide-ellipsis
+                         `((?l . ,lines)
+                           (?c . ,chars))))))
+
+(defvar message-caesar-translation-table nil)
+
+(defun message-caesar-region (b e &optional n)
+  "Caesar rotate region B to E by N, default 13, for decrypting netnews."
+  (interactive
+   (list
+    (min (point) (or (mark t) (point)))
+    (max (point) (or (mark t) (point)))
+    (when current-prefix-arg
+      (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
+             (= b e))                  ; no region to rotate
+    ;; We build the table, if necessary.
+    (when (or (not message-caesar-translation-table)
+             (/= (aref message-caesar-translation-table ?a) (+ ?a n)))
+      (setq message-caesar-translation-table
+           (message-make-caesar-translation-table n)))
+    (translate-region b e message-caesar-translation-table)))
+
+(defun message-make-caesar-translation-table (n)
+  "Create a rot table with offset N."
+  (let ((i -1)
+       (table (make-string 256 0)))
+    (while (< (incf i) 256)
+      (aset table i i))
+    (concat
+     (substring table 0 ?A)
+     (substring table (+ ?A n) (+ ?A n (- 26 n)))
+     (substring table ?A (+ ?A n))
+     (substring table (+ ?A 26) ?a)
+     (substring table (+ ?a n) (+ ?a n (- 26 n)))
+     (substring table ?a (+ ?a n))
+     (substring table (+ ?a 26) 255))))
+
+(defun message-caesar-buffer-body (&optional rotnum wide)
+  "Caesar rotate all letters in the current buffer by 13 places.
+Used to encode/decode possibly offensive messages (commonly in rec.humor).
+With prefix arg, specifies the number of places to rotate each letter forward.
+Mail and USENET news headers are not rotated unless WIDE is non-nil."
+  (interactive (if current-prefix-arg
+                  (list (prefix-numeric-value current-prefix-arg))
+                (list nil)))
+  (save-excursion
+    (save-restriction
+      (when (and (not wide) (message-goto-body))
+       (narrow-to-region (point) (point-max)))
+      (message-caesar-region (point-min) (point-max) rotnum))))
+
+(defun message-pipe-buffer-body (program)
+  "Pipe the message body in the current buffer through PROGRAM."
+  (save-excursion
+    (save-restriction
+      (when (message-goto-body)
+       (narrow-to-region (point) (point-max)))
+      (shell-command-on-region
+       (point-min) (point-max) program nil t))))
+
+(defun message-rename-buffer (&optional enter-string)
+  "Rename the *message* buffer to \"*message* RECIPIENT\".
+If the function is run with a prefix, it will ask for a new buffer
+name, rather than giving an automatic name."
+  (interactive "Pbuffer name: ")
+  (save-excursion
+    (save-restriction
+      (goto-char (point-min))
+      (narrow-to-region (point)
+                       (search-forward mail-header-separator nil 'end))
+      (let* ((mail-to (or
+                      (if (message-news-p) (message-fetch-field "Newsgroups")
+                        (message-fetch-field "To"))
+                      ""))
+            (mail-trimmed-to
+             (if (string-match "," mail-to)
+                 (concat (substring mail-to 0 (match-beginning 0)) ", ...")
+               mail-to))
+            (name-default (concat "*message* " mail-trimmed-to))
+            (name (if enter-string
+                      (read-string "New buffer name: " name-default)
+                    name-default)))
+       (rename-buffer name t)))))
+
+(defun message-fill-yanked-message (&optional justifyp)
+  "Fill the paragraphs of a message yanked into this one.
+Numeric argument means justify as well."
+  (interactive "P")
+  (save-excursion
+    (goto-char (point-min))
+    (search-forward (concat "\n" mail-header-separator "\n") nil t)
+    (let ((fill-prefix message-yank-prefix))
+      (fill-individual-paragraphs (point) (point-max) justifyp))))
+
+(defun message-indent-citation (&optional start end yank-only)
+  "Modify text just inserted from a message to be cited.
+The inserted text should be the region.
+When this function returns, the region is again around the modified text.
+
+Normally, indent each nonblank line `message-indentation-spaces' spaces.
+However, if `message-yank-prefix' is non-nil, insert that prefix on each line."
+  (unless start (setq start (point)))
+  (unless yank-only
+    ;; Remove unwanted headers.
+    (when message-ignored-cited-headers
+      (let (all-removed)
+       (save-restriction
+         (narrow-to-region
+          (goto-char start)
+          (if (search-forward "\n\n" nil t)
+              (1- (point))
+            (point)))
+         (message-remove-header message-ignored-cited-headers t)
+         (when (= (point-min) (point-max))
+           (setq all-removed t))
+         (goto-char (point-max)))
+       (if all-removed
+           (goto-char start)
+         (forward-line 1))))
+    ;; Delete blank lines at the start of the buffer.
+    (while (and (point-min)
+               (eolp)
+               (not (eobp)))
+      (message-delete-line))
+    ;; Delete blank lines at the end of the buffer.
+    (goto-char (point-max))
+    (unless (eq (preceding-char) ?\n)
+      (insert "\n"))
+    (while (and (zerop (forward-line -1))
+               (looking-at "$"))
+      (message-delete-line)))
+  ;; Do the indentation.
+  (if (null message-yank-prefix)
+      (indent-rigidly start (or end (mark t)) message-indentation-spaces)
+    (save-excursion
+      (goto-char start)
+      (while (< (point) (or end (mark t)))
+       (cond ((looking-at ">")
+              (insert message-yank-cited-prefix))
+             ((looking-at "^$")
+              (insert message-yank-empty-prefix))
+             (t
+              (insert message-yank-prefix)))
+       (forward-line 1))))
+  (goto-char start))
+
+(defun message-remove-blank-cited-lines (&optional remove)
+  "Remove cited lines containing only blanks.
+If REMOVE is non-nil, remove newlines, too.
+
+To use this automatically, you may add this function to
+`gnus-message-setup-hook'."
+  (interactive "P")
+  (let ((citexp
+        (concat
+         "^\\("
+         (when (boundp 'message-yank-cited-prefix)
+           (concat message-yank-cited-prefix "\\|"))
+         message-yank-prefix
+         "\\)+ *\n"
+         )))
+    (gnus-message 8 "removing `%s'" citexp)
+    (save-excursion
+      (message-goto-body)
+      (while (re-search-forward citexp nil t)
+       (replace-match (if remove "" "\n"))))))
+
+(defun message--yank-original-internal (arg)
+  (let ((modified (buffer-modified-p))
+       body-text)
+       (when (and message-reply-buffer
+                  message-cite-function)
+         (when (equal message-cite-reply-position 'above)
+           (save-excursion
+             (setq body-text
+                   (buffer-substring (message-goto-body)
+                                     (point-max)))
+             (delete-region (message-goto-body) (point-max))))
+         (if (bufferp message-reply-buffer)
+             (delete-windows-on message-reply-buffer t))
+         (push-mark (save-excursion
+                      (cond
+                       ((bufferp message-reply-buffer)
+                        (insert-buffer-substring message-reply-buffer))
+                       ((and (consp message-reply-buffer)
+                             (functionp (car message-reply-buffer)))
+                        (apply (car message-reply-buffer)
+                               (cdr message-reply-buffer))))
+                      (unless (bolp)
+                        (insert ?\n))
+                      (point)))
+         (unless arg
+           (funcall message-cite-function)
+           (unless (eq (char-before (mark t)) ?\n)
+             (let ((pt (point)))
+               (goto-char (mark t))
+               (insert-before-markers ?\n)
+               (goto-char pt))))
+         (case message-cite-reply-position
+           (above
+            (message-goto-body)
+            (insert body-text)
+            (insert (if (bolp) "\n" "\n\n"))
+            (message-goto-body))
+           (below
+            (message-goto-signature)))
+         ;; Add a `message-setup-very-last-hook' here?
+         ;; Add `gnus-article-highlight-citation' here?
+         (unless modified
+        (setq message-checksum (message-checksum))))))
+
+(defun message-yank-original (&optional arg)
+  "Insert the message being replied to, if any.
+Puts point before the text and mark after.
+Normally indents each nonblank line ARG spaces (default 3).  However,
+if `message-yank-prefix' is non-nil, insert that prefix on each line.
+
+This function uses `message-cite-function' to do the actual citing.
+
+Just \\[universal-argument] as argument means don't indent, insert no
+prefix, and don't delete any headers."
+  (interactive "P")
+  ;; eval the let forms contained in message-cite-style
+  (eval
+   `(let ,(if (symbolp message-cite-style)
+             (symbol-value message-cite-style)
+           message-cite-style)
+      (message--yank-original-internal ',arg))))
+
+(defun message-yank-buffer (buffer)
+  "Insert BUFFER into the current buffer and quote it."
+  (interactive "bYank buffer: ")
+  (let ((message-reply-buffer (get-buffer buffer)))
+    (save-window-excursion
+      (message-yank-original))))
+
+(defun message-buffers ()
+  "Return a list of active message buffers."
+  (let (buffers)
+    (save-current-buffer
+      (dolist (buffer (buffer-list t))
+       (set-buffer buffer)
+       (when (and (derived-mode-p 'message-mode)
+                  (null message-sent-message-via))
+         (push (buffer-name buffer) buffers))))
+    (nreverse buffers)))
+
+(defun message-cite-original-1 (strip-signature)
+  "Cite an original message.
+If STRIP-SIGNATURE is non-nil, strips off the signature from the
+original message.
+
+This function uses `mail-citation-hook' if that is non-nil."
+  (if (and (boundp 'mail-citation-hook)
+          mail-citation-hook)
+      (run-hooks 'mail-citation-hook)
+    (let* ((start (point))
+          (end (mark t))
+          (x-no-archive nil)
+          (functions
+           (when message-indent-citation-function
+             (if (listp message-indent-citation-function)
+                 message-indent-citation-function
+               (list message-indent-citation-function))))
+          ;; This function may be called by `gnus-summary-yank-message' and
+          ;; may insert a different article from the original.  So, we will
+          ;; modify the value of `message-reply-headers' with that article.
+          (message-reply-headers
+           (save-restriction
+             (narrow-to-region start end)
+             (message-narrow-to-head-1)
+             (setq x-no-archive (message-fetch-field "x-no-archive"))
+             (vector 0
+                     (or (message-fetch-field "subject") "none")
+                     (or (message-fetch-field "from") "nobody")
+                     (message-fetch-field "date")
+                     (message-fetch-field "message-id" t)
+                     (message-fetch-field "references")
+                     0 0 ""))))
+      (mml-quote-region start end)
+      (when strip-signature
+       ;; Allow undoing.
+       (undo-boundary)
+       (goto-char end)
+       (when (re-search-backward message-signature-separator start t)
+         ;; Also peel off any blank lines before the signature.
+         (forward-line -1)
+         (while (looking-at "^[ \t]*$")
+           (forward-line -1))
+         (forward-line 1)
+         (delete-region (point) end)
+         (unless (search-backward "\n\n" start t)
+           ;; Insert a blank line if it is peeled off.
+           (insert "\n"))))
+      (goto-char start)
+      (mapc 'funcall functions)
+      (when message-citation-line-function
+       (unless (bolp)
+         (insert "\n"))
+       (funcall message-citation-line-function))
+      (when (and x-no-archive
+                (not message-cite-articles-with-x-no-archive)
+                (string-match "yes" x-no-archive))
+       (undo-boundary)
+       (delete-region (point) (mark t))
+       (insert "> [Quoted text removed due to X-No-Archive]\n")
+       (push-mark)
+       (forward-line -1)))))
+
+(defun message-cite-original ()
+  "Cite function in the standard Message manner."
+  (message-cite-original-1 nil))
+
+(autoload 'format-spec "format-spec")
+(autoload 'gnus-date-get-time "gnus-util")
+
+(defun message-insert-formatted-citation-line (&optional from date tz)
+  "Function that inserts a formatted citation line.
+The optional FROM, and DATE are strings containing the contents of
+the From header and the Date header respectively.  The optional TZ
+is a number of seconds, overrides the time zone of DATE.
+
+See `message-citation-line-format'."
+  ;; The optional args are for testing/debugging.  They will disappear later.
+  ;; Example:
+  ;; (with-temp-buffer
+  ;;   (message-insert-formatted-citation-line
+  ;;    "John Doe <john.doe@example.invalid>"
+  ;;    (message-make-date))
+  ;;   (buffer-string))
+  (when (or message-reply-headers (and from date))
+    (unless from
+      (setq from (mail-header-from message-reply-headers)))
+    (let* ((data (condition-case ()
+                    (funcall (if (boundp 'gnus-extract-address-components)
+                                 gnus-extract-address-components
+                               'mail-extract-address-components)
+                             from)
+                  (error nil)))
+          (name (car data))
+          (fname name)
+          (lname name)
+          (net (car (cdr data)))
+          (name-or-net (or (car data)
+                           (car (cdr data)) from))
+          (time
+           (when (string-match "%[^fnNFL]" message-citation-line-format)
+             (cond ((numberp (car-safe date)) date) ;; backward compatibility
+                   (date (gnus-date-get-time date))
+                   (t
+                    (gnus-date-get-time
+                     (setq date (mail-header-date message-reply-headers)))))))
+          (tz (or tz
+                  (when (stringp date)
+                    (nth 8 (parse-time-string date)))))
+          (flist
+           (let ((i ?A) lst)
+             (when (stringp name)
+               ;; Guess first name and last name:
+               (let* ((names (delq
+                              nil
+                              (mapcar
+                               (lambda (x)
+                                 (if (string-match "\\`\\(\\w\\|[-.]\\)+\\'"
+                                                   x)
+                                     x
+                                   nil))
+                               (split-string name "[ \t]+"))))
+                      (count (length names)))
+                 (cond ((= count 1)
+                        (setq fname (car names)
+                              lname ""))
+                       ((or (= count 2) (= count 3))
+                        (setq fname (car names)
+                              lname (mapconcat 'identity (cdr names) " ")))
+                       ((> count 3)
+                        (setq fname (mapconcat 'identity
+                                               (butlast names (- count 2))
+                                               " ")
+                              lname (mapconcat 'identity
+                                               (nthcdr 2 names)
+                                               " "))))
+                  (when (string-match "\\(.*\\),\\'" fname)
+                    (let ((newlname (match-string 1 fname)))
+                      (setq fname lname lname newlname)))))
+             ;; The following letters are not used in `format-time-string':
+             (push ?E lst) (push "<E>" lst)
+             (push ?F lst) (push (or fname name-or-net) lst)
+             ;; We might want to use "" instead of "<X>" later.
+             (push ?J lst) (push "<J>" lst)
+             (push ?K lst) (push "<K>" lst)
+             (push ?L lst) (push lname lst)
+             (push ?N lst) (push name-or-net lst)
+             (push ?O lst) (push "<O>" lst)
+             (push ?P lst) (push "<P>" lst)
+             (push ?Q lst) (push "<Q>" lst)
+             (push ?f lst) (push from lst)
+             (push ?i lst) (push "<i>" lst)
+             (push ?n lst) (push net lst)
+             (push ?o lst) (push "<o>" lst)
+             (push ?q lst) (push "<q>" lst)
+             (push ?t lst) (push "<t>" lst)
+             (push ?v lst) (push "<v>" lst)
+             ;; Delegate the rest to `format-time-string':
+             (while (<= i ?z)
+               (when (and (not (memq i lst))
+                          ;; Skip (Z,a)
+                          (or (<= i ?Z)
+                              (>= i ?a)))
+                 (push i lst)
+                 (push (condition-case nil
+                           (gmm-format-time-string (format "%%%c" i) time tz)
+                         (error (format ">%c<" i)))
+                       lst))
+               (setq i (1+ i)))
+             (reverse lst)))
+          (spec (apply 'format-spec-make flist)))
+      (insert (format-spec message-citation-line-format spec)))
+    (newline)))
+
+(defun message-cite-original-without-signature ()
+  "Cite function in the standard Message manner.
+This function strips off the signature from the original message."
+  (message-cite-original-1 t))
+
+(defun message-insert-citation-line ()
+  "Insert a simple citation line."
+  (when message-reply-headers
+    (insert (mail-header-from message-reply-headers) " writes:")
+    (newline)
+    (newline)))
+
+(defun message-position-on-field (header &rest afters)
+  (let ((case-fold-search t))
+    (save-restriction
+      (narrow-to-region
+       (goto-char (point-min))
+       (progn
+        (re-search-forward
+         (concat "^" (regexp-quote mail-header-separator) "$"))
+        (match-beginning 0)))
+      (goto-char (point-min))
+      (if (re-search-forward (concat "^" (regexp-quote header) ":") nil t)
+         (progn
+           (re-search-forward "^[^ \t]" nil 'move)
+           (beginning-of-line)
+           (skip-chars-backward "\n")
+           t)
+       (while (and afters
+                   (not (re-search-forward
+                         (concat "^" (regexp-quote (car afters)) ":")
+                         nil t)))
+         (pop afters))
+       (when afters
+         (re-search-forward "^[^ \t]" nil 'move)
+         (beginning-of-line))
+       (insert header ": \n")
+       (forward-char -1)
+       nil))))
+
+\f
+
+;;;
+;;; Sending messages
+;;;
+
+(defun message-send-and-exit (&optional arg)
+  "Send message like `message-send', then, if no errors, exit from mail buffer.
+The usage of ARG is defined by the instance that called Message.
+It should typically alter the sending method in some way or other."
+  (interactive "P")
+  (let ((buf (current-buffer))
+       (actions message-exit-actions))
+    (when (and (message-send arg)
+              (buffer-name buf))
+      (message-bury buf)
+      (if message-kill-buffer-on-exit
+         (kill-buffer buf))
+      (message-do-actions actions)
+      t)))
+
+(defun message-dont-send ()
+  "Don't send the message you have been editing.
+Instead, just auto-save the buffer and then bury it."
+  (interactive)
+  (set-buffer-modified-p t)
+  (save-buffer)
+  (let ((actions message-postpone-actions))
+    (message-bury (current-buffer))
+    (message-do-actions actions)))
+
+(defun message-kill-buffer ()
+  "Kill the current buffer."
+  (interactive)
+  (when (or (not (buffer-modified-p))
+           (not message-kill-buffer-query)
+           (yes-or-no-p "Message modified; kill anyway? "))
+    (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)))
+                (progn
+                  ;; If the message buffer has lived in a dedicated window,
+                  ;; `kill-buffer' has killed the frame.  Thus the
+                  ;; `yes-or-no-p' may show up in a lowered frame.  Make sure
+                  ;; that the user can see the question by raising the
+                  ;; current frame:
+                  (raise-frame)
+                  (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)
+  "Bury this mail BUFFER."
+  ;; Note that this is not quite the same as (bury-buffer buffer),
+  ;; since bury-buffer does extra stuff with a nil argument.
+  ;; Eg http://lists.gnu.org/archive/html/emacs-devel/2014-01/msg00539.html
+  (with-current-buffer buffer (bury-buffer))
+  (if message-return-action
+      (apply (car message-return-action) (cdr message-return-action))))
+
+(defun message-send (&optional arg)
+  "Send the message in the current buffer.
+If `message-interactive' is non-nil, wait for success indication or
+error messages, and inform user.
+Otherwise any failure is reported in a message back to the user from
+the mailer.
+The usage of ARG is defined by the instance that called Message.
+It should typically alter the sending method in some way or other."
+  (interactive "P")
+  ;; Make it possible to undo the coming changes.
+  (undo-boundary)
+  (let ((inhibit-read-only t))
+    (put-text-property (point-min) (point-max) 'read-only nil))
+  (message-fix-before-sending)
+  (run-hooks 'message-send-hook)
+  (when message-confirm-send
+    (or (y-or-n-p "Send message? ")
+       (keyboard-quit)))
+  (message message-sending-message)
+  (let ((alist message-send-method-alist)
+       (success t)
+       elem sent dont-barf-on-no-method
+       (message-options message-options))
+    (message-options-set-recipient)
+    (while (and success
+               (setq elem (pop alist)))
+      (when (funcall (cadr elem))
+       (when (and (or (not (memq (car elem)
+                                 message-sent-message-via))
+                      (message-fetch-field "supersedes")
+                      (if (or (message-gnksa-enable-p 'multiple-copies)
+                              (not (eq (car elem) 'news)))
+                          (y-or-n-p
+                           (format
+                            "Already sent message via %s; resend? "
+                            (car elem)))
+                        (error "Denied posting -- multiple copies")))
+                  (setq success (funcall (caddr elem) arg)))
+         (setq sent t))))
+    (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 (or dont-barf-on-no-method
+             (and success sent))
+      (message-do-fcc)
+      (save-excursion
+       (run-hooks 'message-sent-hook))
+      (message "Sending...done")
+      ;; Do ecomplete address snarfing.
+      (when (and (message-mail-alias-type-p 'ecomplete)
+                (not message-inhibit-ecomplete))
+       (message-put-addresses-in-ecomplete))
+      ;; Mark the buffer as unmodified and delete auto-save.
+      (set-buffer-modified-p nil)
+      (delete-auto-save-file-if-necessary t)
+      (message-disassociate-draft)
+      ;; Delete other mail buffers and stuff.
+      (message-do-send-housekeeping)
+      (message-do-actions message-send-actions)
+      ;; Return success.
+      t)))
+
+(defun message-send-via-mail (arg)
+  "Send the current message via mail."
+  (message-send-mail arg))
+
+(defun message-send-via-news (arg)
+  "Send the current message via news."
+  (funcall message-send-news-function arg))
+
+(defmacro message-check (type &rest forms)
+  "Eval FORMS if TYPE is to be checked."
+  `(or (message-check-element ,type)
+       (save-excursion
+        ,@forms)))
+
+(put 'message-check 'lisp-indent-function 1)
+(put 'message-check 'edebug-form-spec '(form body))
+
+(defun message-text-with-property (prop &optional start end reverse)
+  "Return a list of start and end positions where the text has PROP.
+START and END bound the search, they default to `point-min' and
+`point-max' respectively.  If REVERSE is non-nil, find text which does
+not have PROP."
+  (unless start
+    (setq start (point-min)))
+  (unless end
+    (setq end (point-max)))
+  (let (next regions)
+    (if reverse
+       (while (and start
+                   (setq start (text-property-any start end prop nil)))
+         (setq next (next-single-property-change start prop nil end))
+         (push (cons start (or next end)) regions)
+         (setq start next))
+      (while (and start
+                 (or (get-text-property start prop)
+                     (and (setq start (next-single-property-change
+                                       start prop nil end))
+                          (get-text-property start prop))))
+       (setq next (text-property-any start end prop nil))
+       (push (cons start (or next end)) regions)
+       (setq start next)))
+    (nreverse regions)))
+
+(defcustom message-bogus-addresses
+  '("noreply" "nospam" "invalid" "@@" "[^[:ascii:]].*@" "[ \t]")
+  "List of regexps of potentially bogus mail addresses.
+See `message-check-recipients' how to setup checking.
+
+This list should make it possible to catch typos or warn about
+spam-trap addresses.  It doesn't aim to verify strict RFC
+conformance."
+  :version "23.1" ;; No Gnus
+  :group 'message-headers
+  :type '(choice
+         (const :tag "None" nil)
+         (list
+          (set :inline t
+               (const "noreply")
+               (const "nospam")
+               (const "invalid")
+               (const :tag "duplicate @" "@@")
+               (const :tag "non-ascii local part" "[^[:ascii:]].*@")
+               ;; Already caught by `message-valid-fqdn-regexp'
+               ;; (const :tag "`_' in domain part" "@.*_")
+               (const :tag "whitespace" "[ \t]"))
+          (repeat :inline t
+                  :tag "Other"
+                  (regexp)))))
+
+(defun message-fix-before-sending ()
+  "Do various things to make the message nice before sending it."
+  ;; Make sure there's a newline at the end of the message.
+  (goto-char (point-max))
+  (unless (bolp)
+    (insert "\n"))
+  ;; Make the hidden headers visible.
+  (widen)
+  ;; Sort headers before sending the message.
+  (message-sort-headers)
+  ;; Make invisible text visible.
+  ;; It doesn't seem as if this is useful, since the invisible property
+  ;; is clobbered by an after-change hook anyhow.
+  (message-check 'invisible-text
+    (let ((regions (message-text-with-property 'invisible))
+         from to)
+      (when regions
+       (while regions
+         (setq from (caar regions)
+               to (cdar regions)
+               regions (cdr regions))
+         (put-text-property from to 'invisible nil)
+         (overlay-put (make-overlay from to) 'face 'highlight))
+       (unless (yes-or-no-p
+                "Invisible text found and made visible; continue sending? ")
+         (error "Invisible text found and made visible")))))
+  (message-check 'illegible-text
+    (let (char found choice nul-chars)
+      (message-goto-body)
+      (setq nul-chars (save-excursion
+                       (search-forward "\000" nil t)))
+      (while (progn
+              (skip-chars-forward mm-7bit-chars)
+              (when (get-text-property (point) 'no-illegible-text)
+                ;; There is a signed or encrypted raw message part
+                ;; that is considered to be safe.
+                (goto-char (or (next-single-property-change
+                                (point) 'no-illegible-text)
+                               (point-max))))
+              (setq char (char-after)))
+       (when (or (< (mm-char-int char) 128)
+                 (and (mm-multibyte-p)
+                      (memq (char-charset char)
+                            '(eight-bit-control eight-bit-graphic
+                                                ;; Emacs 23, Bug#1770:
+                                                eight-bit
+                                                control-1))
+                      (not (get-text-property
+                            (point) 'untranslated-utf-8))))
+         (overlay-put (make-overlay (point) (1+ (point))) 'face 'highlight)
+         (setq found t))
+       (forward-char))
+      (when found
+       (setq choice
+             (gnus-multiple-choice
+              (if nul-chars
+                  "NUL characters found, which may cause problems.  Continue sending?"
+                "Non-printable characters found.  Continue sending?")
+              `((?d "Remove non-printable characters and send")
+                (?r ,(format
+                      "Replace non-printable characters with \"%s\" and send"
+                      message-replacement-char))
+                (?s "Send as is without removing anything")
+                (?e "Continue editing"))))
+       (if (eq choice ?e)
+         (error "Non-printable characters"))
+       (message-goto-body)
+       (skip-chars-forward mm-7bit-chars)
+       (while (not (eobp))
+         (when (let ((char (char-after)))
+                 (or (< (mm-char-int char) 128)
+                     (and (mm-multibyte-p)
+                          ;; FIXME: Wrong for Emacs 23 (unicode) and for
+                          ;; things like undecodable utf-8 (in Emacs 21?).
+                          ;; Should at least use find-coding-systems-region.
+                          ;; -- fx
+                          (memq (char-charset char)
+                                '(eight-bit-control eight-bit-graphic
+                                                    ;; Emacs 23, Bug#1770:
+                                                    eight-bit
+                                                    control-1))
+                          (not (get-text-property
+                                (point) 'untranslated-utf-8)))))
+           (if (eq choice ?i)
+               (message-kill-all-overlays)
+             (delete-char 1)
+             (when (eq choice ?r)
+               (insert message-replacement-char))))
+         (forward-char)
+         (skip-chars-forward mm-7bit-chars)))))
+  (message-check 'bogus-recipient
+    ;; Warn before sending a mail to an invalid address.
+    (message-check-recipients)))
+
+(defun message-bogus-recipient-p (recipients)
+  "Check if a mail address in RECIPIENTS looks bogus.
+
+RECIPIENTS is a mail header.  Return a list of potentially bogus
+addresses.  If none is found, return nil.
+
+An address might be bogus if the domain part is not fully
+qualified, see `message-valid-fqdn-regexp', or if there's a
+matching entry in `message-bogus-addresses'."
+  ;; FIXME: How about "foo@subdomain", when the MTA adds ".domain.tld"?
+  (let (found)
+    (mapc (lambda (address)
+           (setq address (or (cadr address) ""))
+           (when
+               (or (string= "" address)
+                    (not
+                    (or
+                     (not (string-match "@" address))
+                     (string-match
+                      (concat ".@.*\\("
+                              message-valid-fqdn-regexp "\\)\\'") address)))
+                   (and message-bogus-addresses
+                        (let ((re
+                               (if (listp message-bogus-addresses)
+                                   (mapconcat 'identity
+                                              message-bogus-addresses
+                                              "\\|")
+                                 message-bogus-addresses)))
+                          (string-match re address))))
+              (push address found)))
+         ;;
+         (mail-extract-address-components recipients t))
+    found))
+
+(defun message-check-recipients ()
+  "Warn before composing or sending a mail to an invalid address.
+
+This function could be useful in `message-setup-hook'."
+  (interactive)
+  (save-restriction
+    (message-narrow-to-headers)
+    (dolist (hdr '("To" "Cc" "Bcc"))
+      (let ((addr (message-fetch-field hdr)))
+       (when (stringp addr)
+         (dolist (bog (message-bogus-recipient-p addr))
+           (and bog
+                (not (y-or-n-p
+                      (gnus-format-message
+                       "Address `%s'%s might be bogus.  Continue? "
+                       bog
+                       ;; If the encoded version of the email address
+                       ;; is different from the unencoded version,
+                       ;; then we likely have invisible characters or
+                       ;; the like.  Display the encoded version,
+                       ;; too.
+                       (let ((encoded (rfc2047-encode-string bog)))
+                         (if (string= encoded bog)
+                             ""
+                           (format " (%s)" encoded))))))
+                (error "Bogus address"))))))))
+
+(custom-add-option 'message-setup-hook 'message-check-recipients)
+
+(defun message-add-action (action &rest types)
+  "Add ACTION to be performed when doing an exit of type TYPES."
+  (while types
+    (add-to-list (intern (format "message-%s-actions" (pop types)))
+                action)))
+
+(defun message-delete-action (action &rest types)
+  "Delete ACTION from lists of actions performed when doing an exit of type TYPES."
+  (let (var)
+    (while types
+      (set (setq var (intern (format "message-%s-actions" (pop types))))
+          (delq action (symbol-value var))))))
+
+(defun message-do-actions (actions)
+  "Perform all actions in ACTIONS."
+  ;; Now perform actions on successful sending.
+  (dolist (action actions)
+    (ignore-errors
+      (cond
+       ;; A simple function.
+       ((functionp action)
+       (funcall action))
+       ;; Something to be evalled.
+       (t
+       (eval action))))))
+
+(defun message-send-mail-partially ()
+  "Send mail as message/partial."
+  ;; replace the header delimiter with a blank line
+  (goto-char (point-min))
+  (re-search-forward
+   (concat "^" (regexp-quote mail-header-separator) "\n"))
+  (replace-match "\n")
+  (run-hooks 'message-send-mail-hook)
+  (let ((p (goto-char (point-min)))
+       (tembuf (message-generate-new-buffer-clone-locals " message temp"))
+       (curbuf (current-buffer))
+       (id (message-make-message-id)) (n 1)
+        plist total header)
+    (while (not (eobp))
+      (if (< (point-max) (+ p message-send-mail-partially-limit))
+         (goto-char (point-max))
+       (goto-char (+ p message-send-mail-partially-limit))
+       (beginning-of-line)
+       (if (<= (point) p) (forward-line 1))) ;; In case of bad message.
+      (push p plist)
+      (setq p (point)))
+    (setq total (length plist))
+    (push (point-max) plist)
+    (setq plist (nreverse plist))
+    (unwind-protect
+       (save-excursion
+         (setq p (pop plist))
+         (while plist
+           (set-buffer curbuf)
+           (copy-to-buffer tembuf p (car plist))
+           (set-buffer tembuf)
+           (goto-char (point-min))
+           (if header
+               (progn
+                 (goto-char (point-min))
+                 (narrow-to-region (point) (point))
+                 (insert header))
+             (message-goto-eoh)
+             (setq header (buffer-substring (point-min) (point)))
+             (goto-char (point-min))
+             (narrow-to-region (point) (point))
+             (insert header)
+             (message-remove-header "Mime-Version")
+             (message-remove-header "Content-Type")
+             (message-remove-header "Content-Transfer-Encoding")
+             (message-remove-header "Message-ID")
+             (message-remove-header "Lines")
+             (goto-char (point-max))
+             (insert "Mime-Version: 1.0\n")
+             (setq header (buffer-string)))
+           (goto-char (point-max))
+           (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)
+               (insert "Lines: " (message-make-lines) "\n"))
+             (message-goto-subject)
+             (end-of-line)
+             (insert (format " (%d/%d)" n total))
+             (widen)
+             (if message-send-mail-real-function
+                 (funcall message-send-mail-real-function)
+               (message-multi-smtp-send-mail)))
+           (setq n (+ n 1))
+           (setq p (pop plist))
+           (erase-buffer)))
+      (kill-buffer tembuf))))
+
+(declare-function hashcash-wait-async "hashcash" (&optional buffer))
+
+(defun message-send-mail (&optional arg)
+  (require 'mail-utils)
+  (let* ((tembuf (message-generate-new-buffer-clone-locals " message temp"))
+        (case-fold-search nil)
+        (news (message-news-p))
+        (mailbuf (current-buffer))
+        (message-this-is-mail t)
+        ;; gnus-setup-posting-charset is autoloaded in mml.el (FIXME
+        ;; maybe it should not be), which this file requires.  Hence
+        ;; the fboundp test is always true.  Loading it from gnus-msg
+        ;; loads many Gnus files (Bug#5642).  If
+        ;; gnus-group-posting-charset-alist hasn't been customized,
+        ;; this is just going to return nil anyway.  FIXME it would
+        ;; be good to improve this further, because even if g-g-p-c-a
+        ;; has been customized, that is likely to just be for news.
+        ;; Eg either move the definition from gnus-msg, or separate out
+        ;; the mail and news parts.
+        (message-posting-charset
+         (if (and (fboundp 'gnus-setup-posting-charset)
+                  (boundp 'gnus-group-posting-charset-alist))
+             (gnus-setup-posting-charset nil)
+           message-posting-charset))
+        (headers message-required-mail-headers)
+        options)
+    (when (and message-generate-hashcash
+              (not (eq message-generate-hashcash 'opportunistic)))
+      (message "Generating hashcash...")
+      (require 'hashcash)
+      ;; Wait for calculations already started to finish...
+      (hashcash-wait-async)
+      ;; ...and do calculations not already done.  mail-add-payment
+      ;; will leave existing X-Hashcash headers alone.
+      (mail-add-payment)
+      (message "Generating hashcash...done"))
+    (save-restriction
+      (message-narrow-to-headers)
+      ;; Generate the Mail-Followup-To header if the header is not there...
+      (if (and (message-subscribed-p)
+              (not (mail-fetch-field "mail-followup-to")))
+         (setq headers
+               (cons
+                (cons "Mail-Followup-To" (message-make-mail-followup-to))
+                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 headers))
+      ;; Check continuation headers.
+      (message-check 'continuation-headers
+       (goto-char (point-min))
+       (while (re-search-forward "^[^ \t\n][^ \t\n:]*[ \t\n]" nil t)
+         (goto-char (match-beginning 0))
+         (if (y-or-n-p "Fix continuation lines? ")
+             (insert " ")
+           (forward-line 1)
+           (unless (y-or-n-p "Send anyway? ")
+             (error "Failed to send the message")))))
+      ;; Let the user do all of the above.
+      (run-hooks 'message-header-hook))
+    (setq options message-options)
+    (unwind-protect
+       (with-current-buffer tembuf
+         (erase-buffer)
+         (setq message-options options)
+         ;; Avoid copying text props (except hard newlines).
+         (insert (with-current-buffer mailbuf
+                   (mml-buffer-substring-no-properties-except-hard-newlines
+                    (point-min) (point-max))))
+         ;; Remove some headers.
+         (message-encode-message-body)
+         (save-restriction
+           (message-narrow-to-headers)
+           ;; We (re)generate the Lines header.
+           (when (memq 'Lines message-required-mail-headers)
+             (message-generate-headers '(Lines)))
+           ;; Remove some headers.
+           (message-remove-header message-ignored-mail-headers t)
+           (let ((mail-parse-charset message-default-charset))
+             (mail-encode-encoded-word-buffer)))
+         (goto-char (point-max))
+         ;; require one newline at the end.
+         (or (= (preceding-char) ?\n)
+             (insert ?\n))
+         (message-cleanup-headers)
+         ;; FIXME: we're inserting the courtesy copy after encoding.
+         ;; This is wrong if the courtesy copy string contains
+         ;; non-ASCII characters. -- jh
+         (when
+             (save-restriction
+               (message-narrow-to-headers)
+               (and news
+                    (not (message-fetch-field "List-Post"))
+                    (not (message-fetch-field "List-ID"))
+                    (or (message-fetch-field "cc")
+                        (message-fetch-field "bcc")
+                        (message-fetch-field "to"))
+                    (let ((content-type (message-fetch-field
+                                         "content-type")))
+                      (and
+                       (or
+                        (not content-type)
+                        (string= "text/plain"
+                                 (car
+                                  (mail-header-parse-content-type
+                                   content-type))))
+                       (not
+                        (string= "base64"
+                                 (message-fetch-field
+                                  "content-transfer-encoding")))))))
+           (message-insert-courtesy-copy
+            (with-current-buffer mailbuf
+              message-courtesy-message)))
+          ;; Let's make sure we encoded all the body.
+          (assert (save-excursion
+                    (goto-char (point-min))
+                    (not (re-search-forward "[^\000-\377]" nil t))))
+          (mm-disable-multibyte)
+         (if (or (not message-send-mail-partially-limit)
+                 (< (buffer-size) message-send-mail-partially-limit)
+                 (not (message-y-or-n-p
+                       "The message size is too large, split? "
+                       t
+                       "\
+The message size, "
+                       (/ (buffer-size) 1000) "KB, is too large.
+
+Some mail gateways (MTA's) bounce large messages.  To avoid the
+problem, answer `y', and the message will be split into several
+smaller pieces, the size of each is about "
+                       (/ message-send-mail-partially-limit 1000)
+                       "KB except the last
+one.
+
+However, some mail readers (MUA's) can't read split messages, i.e.,
+mails in message/partially format. Answer `n', and the message will be
+sent in one piece.
+
+The size limit is controlled by `message-send-mail-partially-limit'.
+If you always want Gnus to send messages in one piece, set
+`message-send-mail-partially-limit' to nil.
+")))
+             (progn
+               (message "Sending via mail...")
+               (if message-send-mail-real-function
+                   (funcall message-send-mail-real-function)
+                 (message-multi-smtp-send-mail)))
+           (message-send-mail-partially))
+         (setq options message-options))
+      (kill-buffer tembuf))
+    (set-buffer mailbuf)
+    (setq message-options options)
+    (push 'mail message-sent-message-via)))
+
+(defvar sendmail-program)
+(defvar smtpmail-smtp-user)
+
+(defun message-multi-smtp-send-mail ()
+  "Send the current buffer to `message-send-mail-function'.
+Or, if there's a header that specifies a different method, use
+that instead."
+  (let ((method (message-field-value "X-Message-SMTP-Method")))
+    (if (not method)
+       (funcall message-send-mail-function)
+      (message-remove-header "X-Message-SMTP-Method")
+      (setq method (split-string method))
+      (cond
+       ((equal (car method) "sendmail")
+       (message-send-mail-with-sendmail))
+       ((equal (car method) "smtp")
+       (require 'smtpmail)
+       (let ((smtpmail-smtp-server (nth 1 method))
+             (smtpmail-smtp-service (nth 2 method))
+             (smtpmail-smtp-user (or (nth 3 method) smtpmail-smtp-user)))
+         (message-smtpmail-send-it)))
+       (t
+       (error "Unknown method %s" method))))))
+
+(defun message-send-mail-with-sendmail ()
+  "Send off the prepared buffer with sendmail."
+  (require 'sendmail)
+  (let ((errbuf (if message-interactive
+                   (message-generate-new-buffer-clone-locals
+                    " sendmail errors")
+                 0))
+       resend-to-addresses delimline)
+    (unwind-protect
+       (progn
+         (let ((case-fold-search t))
+           (save-restriction
+             (message-narrow-to-headers)
+             (setq resend-to-addresses (message-fetch-field "resent-to")))
+           ;; Change header-delimiter to be what sendmail expects.
+           (goto-char (point-min))
+           (re-search-forward
+            (concat "^" (regexp-quote mail-header-separator) "\n"))
+           (replace-match "\n")
+           (backward-char 1)
+           (setq delimline (point-marker))
+           (run-hooks 'message-send-mail-hook)
+           ;; Insert an extra newline if we need it to work around
+           ;; Sun's bug that swallows newlines.
+           (goto-char (1+ delimline))
+           (when (eval message-mailer-swallows-blank-line)
+             (newline))
+           (when message-interactive
+             (with-current-buffer errbuf
+               (erase-buffer))))
+         (let* ((default-directory "/")
+                (coding-system-for-write message-send-coding-system)
+                (cpr (apply
+                      'call-process-region
+                      (append
+                       (list (point-min) (point-max) sendmail-program
+                             nil errbuf nil "-oi")
+                       message-sendmail-extra-arguments
+                       ;; Always specify who from,
+                       ;; since some systems have broken sendmails.
+                       ;; But some systems are more broken with -f, so
+                       ;; we'll let users override this.
+                       (and (null message-sendmail-f-is-evil)
+                            (list "-f" (message-sendmail-envelope-from)))
+                       ;; These mean "report errors by mail"
+                       ;; and "deliver in background".
+                       (if (null message-interactive) '("-oem" "-odb"))
+                       ;; Get the addresses from the message
+                       ;; unless this is a resend.
+                       ;; We must not do that for a resend
+                       ;; because we would find the original addresses.
+                       ;; For a resend, include the specific addresses.
+                       (if resend-to-addresses
+                           (list resend-to-addresses)
+                         '("-t"))))))
+           (unless (or (null cpr) (and (numberp cpr) (zerop cpr)))
+             (when errbuf
+               (pop-to-buffer errbuf)
+               (setq errbuf nil))
+             (error "Sending...failed with exit value %d" cpr)))
+         (when message-interactive
+           (with-current-buffer errbuf
+             (goto-char (point-min))
+             (while (re-search-forward "\n+ *" nil t)
+               (replace-match "; "))
+             (if (not (zerop (buffer-size)))
+                 (error "Sending...failed to %s"
+                        (buffer-string))))))
+      (when (bufferp errbuf)
+       (kill-buffer errbuf)))))
+
+(defun message-send-mail-with-qmail ()
+  "Pass the prepared message buffer to qmail-inject.
+Refer to the documentation for the variable `message-send-mail-function'
+to find out how to use this."
+  ;; replace the header delimiter with a blank line
+  (goto-char (point-min))
+  (re-search-forward
+   (concat "^" (regexp-quote mail-header-separator) "\n"))
+  (replace-match "\n")
+  (run-hooks 'message-send-mail-hook)
+  ;; send the message
+  (case
+      (let ((coding-system-for-write message-send-coding-system))
+       (apply
+        'call-process-region (point-min) (point-max)
+        message-qmail-inject-program nil nil nil
+        ;; qmail-inject's default behavior is to look for addresses on the
+        ;; command line; if there're none, it scans the headers.
+        ;; yes, it does The Right Thing w.r.t. Resent-To and it's kin.
+        ;;
+        ;; in general, ALL of qmail-inject's defaults are perfect for simply
+        ;; reading a formatted (i. e., at least a To: or Resent-To header)
+        ;; message from stdin.
+        ;;
+        ;; qmail also has the advantage of not having been raped by
+        ;; various vendors, so we don't have to allow for that, either --
+        ;; compare this with message-send-mail-with-sendmail and weep
+        ;; for sendmail's lost innocence.
+        ;;
+        ;; all this is way cool coz it lets us keep the arguments entirely
+        ;; free for -inject-arguments -- a big win for the user and for us
+        ;; since we don't have to play that double-guessing game and the user
+        ;; gets full control (no gestapo'ish -f's, for instance).  --sj
+        (if (functionp message-qmail-inject-args)
+            (funcall message-qmail-inject-args)
+          message-qmail-inject-args)))
+    ;; qmail-inject doesn't say anything on it's stdout/stderr,
+    ;; we have to look at the retval instead
+    (0 nil)
+    (100 (error "qmail-inject reported permanent failure"))
+    (111 (error "qmail-inject reported transient failure"))
+    ;; should never happen
+    (t   (error "qmail-inject reported unknown failure"))))
+
+(defvar mh-previous-window-config)
+
+(defun message-send-mail-with-mh ()
+  "Send the prepared message buffer with mh."
+  (let ((mh-previous-window-config nil)
+       (name (mh-new-draft-name)))
+    (setq buffer-file-name name)
+    ;; MH wants to generate these headers itself.
+    (when message-mh-deletable-headers
+      (let ((headers message-mh-deletable-headers))
+       (while headers
+         (goto-char (point-min))
+         (and (re-search-forward
+               (concat "^" (symbol-name (car headers)) ": *") nil t)
+              (message-delete-line))
+         (pop headers))))
+    (run-hooks 'message-send-mail-hook)
+    ;; Pass it on to mh.
+    (mh-send-letter)))
+
+(defun message-smtpmail-send-it ()
+  "Send the prepared message buffer with `smtpmail-send-it'.
+The only difference from `smtpmail-send-it' is that this command
+evaluates `message-send-mail-hook' just before sending a message.
+It is useful if your ISP requires the POP-before-SMTP
+authentication.  See the Gnus manual for details."
+  (run-hooks 'message-send-mail-hook)
+  ;; Change header-delimiter to be what smtpmail expects.
+  (goto-char (point-min))
+  (when (re-search-forward
+        (concat "^" (regexp-quote mail-header-separator) "\n"))
+    (replace-match "\n"))
+  (smtpmail-send-it))
+
+(defun message-send-mail-with-mailclient ()
+  "Send the prepared message buffer with `mailclient-send-it'.
+The only difference from `mailclient-send-it' is that this
+command evaluates `message-send-mail-hook' just before sending a message."
+  (run-hooks 'message-send-mail-hook)
+  (mailclient-send-it))
+
+(defun message-canlock-generate ()
+  "Return a string that is non-trivial to guess.
+Do not use this for anything important, it is cryptographically weak."
+  (require 'sha1)
+  (let (sha1-maximum-internal-length)
+    (sha1 (concat (message-unique-id)
+                 (format "%x%x%x" (random) (random) (random))
+                 (prin1-to-string (recent-keys))
+                 (prin1-to-string (garbage-collect))))))
+
+(defvar canlock-password)
+(defvar canlock-password-for-verify)
+
+(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."
+  (require 'canlock)
+  (unless canlock-password
+    (customize-save-variable 'canlock-password (message-canlock-generate))
+    (setq canlock-password-for-verify canlock-password))
+  canlock-password)
+
+(defun message-insert-canlock ()
+  (when message-insert-canlock
+    (message-canlock-password)
+    (canlock-insert-header)))
+
+(autoload 'nnheader-get-report "nnheader")
+
+(declare-function gnus-setup-posting-charset "gnus-msg" (group))
+
+(defun message-send-news (&optional arg)
+  (require 'gnus-msg)
+  (let* ((tembuf (message-generate-new-buffer-clone-locals " *message temp*"))
+        (case-fold-search nil)
+        (method (if (functionp message-post-method)
+                    (funcall message-post-method arg)
+                  message-post-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 names with incompatible character sets.
+        ;; -- Per Abrahamsen <abraham@dina.kvl.dk> 2001-10-08.
+        (group-field-charset
+         (gnus-group-name-charset method newsgroups-field))
+        (followup-field-charset
+         (gnus-group-name-charset method (or followup-field "")))
+        (rfc2047-header-encoding-alist
+         (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 (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 newsgroups-field))
+        result)
+    (if (not (message-check-news-body-syntax))
+       nil
+      (save-restriction
+       (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))
+      ;; 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 (let ((message-post-method method))
+                (message-check-news-syntax)))
+         nil
+       (unwind-protect
+           (with-current-buffer tembuf
+             (buffer-disable-undo)
+             (erase-buffer)
+             ;; Avoid copying text props (except hard newlines).
+             (insert
+              (with-current-buffer messbuf
+                (mml-buffer-substring-no-properties-except-hard-newlines
+                 (point-min) (point-max))))
+             (message-encode-message-body)
+             ;; Remove some headers.
+             (save-restriction
+               (message-narrow-to-headers)
+               ;; We (re)generate the Lines header.
+               (when (memq 'Lines message-required-mail-headers)
+                 (message-generate-headers '(Lines)))
+               ;; Remove some headers.
+               (message-remove-header message-ignored-news-headers t)
+               (let ((mail-parse-charset message-default-charset))
+                 (mail-encode-encoded-word-buffer)))
+             (goto-char (point-max))
+             ;; require one newline at the end.
+             (or (= (preceding-char) ?\n)
+                 (insert ?\n))
+             (let ((case-fold-search t))
+               ;; Remove the delimiter.
+               (goto-char (point-min))
+               (re-search-forward
+                (concat "^" (regexp-quote mail-header-separator) "\n"))
+               (replace-match "\n")
+               (backward-char 1))
+             (run-hooks 'message-send-news-hook)
+             (gnus-open-server method)
+             (message "Sending news via %s..." (gnus-server-string method))
+             (setq result (let ((mail-header-separator ""))
+                            (gnus-request-post method))))
+         (kill-buffer tembuf))
+       (set-buffer messbuf)
+       (if result
+           (push 'news message-sent-message-via)
+         (message "Couldn't send message via news: %s"
+                  (nnheader-get-report (car method)))
+         nil)))))
+
+;;;
+;;; Header generation & syntax checking.
+;;;
+
+(defun message-check-element (type)
+  "Return non-nil if this TYPE is not to be checked."
+  (if (eq message-syntax-checks 'dont-check-for-anything-just-trust-me)
+      t
+    (let ((able (assq type message-syntax-checks)))
+      (and (consp able)
+          (eq (cdr able) 'disabled)))))
+
+(defun message-check-news-syntax ()
+  "Check the syntax of the message."
+  (save-excursion
+    (save-restriction
+      (widen)
+      ;; We narrow to the headers and check them first.
+      (save-excursion
+       (save-restriction
+         (message-narrow-to-headers)
+         (message-check-news-header-syntax))))))
+
+(defun message-check-news-header-syntax ()
+  (and
+   ;; Check Newsgroups header.
+   (message-check 'newsgroups
+     (let ((group (message-fetch-field "newsgroups")))
+       (or
+       (and group
+            (not (string-match "\\`[ \t]*\\'" group)))
+       (ignore
+        (message
+         "The newsgroups field is empty or missing.  Posting is denied.")))))
+   ;; Check the Subject header.
+   (message-check 'subject
+     (let* ((case-fold-search t)
+           (subject (message-fetch-field "subject")))
+       (or
+       (and subject
+            (not (string-match "\\`[ \t]*\\'" subject)))
+       (ignore
+        (message
+         "The subject field is empty or missing.  Posting is denied.")))))
+   ;; Check for commands in Subject.
+   (message-check 'subject-cmsg
+     (if (string-match "^cmsg " (message-fetch-field "subject"))
+        (y-or-n-p
+         "The control code \"cmsg\" is in the subject.  Really post? ")
+       t))
+   ;; Check long header lines.
+   (message-check 'long-header-lines
+     (let ((header nil)
+          (length 0)
+          found)
+       (while (and (not found)
+                  (re-search-forward "^\\([^ \t:]+\\): " nil t))
+        (if (> (- (point) (match-beginning 0)) 998)
+            (setq found t
+                  length (- (point) (match-beginning 0)))
+          (setq header (match-string-no-properties 1)))
+        (forward-line 1))
+       (if found
+          (y-or-n-p (format "Your %s header is too long (%d).  Really post? "
+                            header length))
+        t)))
+   ;; Check for multiple identical headers.
+   (message-check 'multiple-headers
+     (let (found)
+       (while (and (not found)
+                  (re-search-forward "^[^ \t:]+: " nil t))
+        (save-excursion
+          (or (re-search-forward
+               (concat "^"
+                       (regexp-quote
+                        (setq found
+                              (buffer-substring
+                               (match-beginning 0) (- (match-end 0) 2))))
+                       ":")
+               nil t)
+              (setq found nil))))
+       (if found
+          (y-or-n-p (format "Multiple %s headers.  Really post? " found))
+        t)))
+   ;; Check for Version and Sendsys.
+   (message-check 'sendsys
+     (if (re-search-forward "^Sendsys:\\|^Version:" nil t)
+        (y-or-n-p
+         (format "The article contains a %s command.  Really post? "
+                 (buffer-substring (match-beginning 0)
+                                   (1- (match-end 0)))))
+       t))
+   ;; See whether we can shorten Followup-To.
+   (message-check 'shorten-followup-to
+     (let ((newsgroups (message-fetch-field "newsgroups"))
+          (followup-to (message-fetch-field "followup-to"))
+          to)
+       (when (and newsgroups
+                 (string-match "," newsgroups)
+                 (not followup-to)
+                 (not
+                  (zerop
+                   (length
+                    (setq to (completing-read
+                              "Followups to (default no Followup-To header): "
+                              (mapcar #'list
+                                      (cons "poster"
+                                            (message-tokenize-header
+                                             newsgroups)))))))))
+        (goto-char (point-min))
+        (insert "Followup-To: " to "\n"))
+       t))
+   ;; Check "Shoot me".
+   (message-check 'shoot
+     (if (re-search-forward
+         "Message-ID.*.i-did-not-set--mail-host-address--so-tickle-me" nil t)
+        (y-or-n-p "You appear to have a misconfigured system.  Really post? ")
+       t))
+   ;; Check for Approved.
+   (message-check 'approved
+     (if (re-search-forward "^Approved:" nil t)
+        (y-or-n-p "The article contains an Approved header.  Really post? ")
+       t))
+   ;; Check the Message-ID header.
+   (message-check 'message-id
+     (let* ((case-fold-search t)
+           (message-id (message-fetch-field "message-id" t)))
+       (or (not message-id)
+          ;; Is there an @ in the ID?
+          (and (string-match "@" message-id)
+               ;; Is there a dot in the ID?
+               (string-match "@[^.]*\\." message-id)
+               ;; Does the ID end with a dot?
+               (not (string-match "\\.>" message-id)))
+          (y-or-n-p
+           (format "The Message-ID looks strange: \"%s\".  Really post? "
+                   message-id)))))
+   ;; Check the Newsgroups & Followup-To headers.
+   (message-check 'existing-newsgroups
+     (let* ((case-fold-search t)
+           (newsgroups (message-fetch-field "newsgroups"))
+           (followup-to (message-fetch-field "followup-to"))
+           (groups (message-tokenize-header
+                    (if followup-to
+                        (concat newsgroups "," followup-to)
+                      newsgroups)))
+           (post-method (if (functionp message-post-method)
+                            (funcall message-post-method)
+                          message-post-method))
+           ;; KLUDGE to handle nnvirtual groups.  Doing this right
+           ;; would probably involve a new nnoo function.
+           ;; -- Per Abrahamsen <abraham@dina.kvl.dk>, 2001-10-17.
+           (method (if (and (consp post-method)
+                            (eq (car post-method) 'nnvirtual)
+                            gnus-message-group-art)
+                       (let ((group (car (nnvirtual-find-group-art
+                                          (car gnus-message-group-art)
+                                          (cdr gnus-message-group-art)))))
+                         (gnus-find-method-for-group group))
+                     post-method))
+           (known-groups
+            (mapcar (lambda (n)
+                      (gnus-group-name-decode
+                       (gnus-group-real-name n)
+                       (gnus-group-name-charset method n)))
+                    (gnus-groups-from-server method)))
+           errors)
+       (while groups
+        (when (and (not (equal (car groups) "poster"))
+                   (not (member (car groups) known-groups))
+                   (not (member (car groups) errors)))
+          (push (car groups) errors))
+        (pop groups))
+       (cond
+       ;; Gnus is not running.
+       ((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.
+       ((and (or (not gnus-read-active-file)
+                 (eq gnus-read-active-file 'some))
+             errors)
+        (y-or-n-p
+         (format
+          "Really use %s possibly unknown group%s: %s? "
+          (if (= (length errors) 1) "this" "these")
+          (if (= (length errors) 1) "" "s")
+          (mapconcat 'identity errors ", "))))
+       ;; There were no errors.
+       ((not errors)
+        t)
+       ;; There are unknown groups.
+       (t
+        (y-or-n-p
+         (format
+          "Really post to %s unknown group%s: %s? "
+          (if (= (length errors) 1) "this" "these")
+          (if (= (length errors) 1) "" "s")
+          (mapconcat 'identity errors ", ")))))))
+   ;; Check continuation headers.
+   (message-check 'continuation-headers
+     (goto-char (point-min))
+     (let ((do-posting t))
+       (while (re-search-forward "^[^ \t\n][^ \t\n:]*[ \t\n]" nil t)
+        (goto-char (match-beginning 0))
+        (if (y-or-n-p "Fix continuation lines? ")
+            (insert " ")
+          (forward-line 1)
+          (unless (y-or-n-p "Send anyway? ")
+            (setq do-posting nil))))
+       do-posting))
+   ;; 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)))
+          ;; `rfc822-addresses' returns a string if parsing fails.
+          (while (and (consp 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
+   ;; Check for long lines.
+   (message-check 'long-lines
+     (goto-char (point-min))
+     (re-search-forward
+      (concat "^" (regexp-quote mail-header-separator) "$"))
+     (forward-line 1)
+     (while (and
+            (or (looking-at
+                 "<#\\(/\\)?\\(multipart\\|part\\|external\\|mml\\)")
+                (let ((p (point)))
+                  (end-of-line)
+                  (< (- (point) p) 80)))
+            (zerop (forward-line 1))))
+     (or (bolp)
+        (eobp)
+        (y-or-n-p
+         "You have lines longer than 79 characters.  Really post? ")))
+   ;; Check whether the article is empty.
+   (message-check 'empty
+     (goto-char (point-min))
+     (re-search-forward
+      (concat "^" (regexp-quote mail-header-separator) "$"))
+     (forward-line 1)
+     (let ((b (point)))
+       (goto-char (point-max))
+       (re-search-backward message-signature-separator nil t)
+       (beginning-of-line)
+       (or (re-search-backward "[^ \n\t]" b t)
+          (if (message-gnksa-enable-p 'empty-article)
+              (y-or-n-p "Empty article.  Really post? ")
+            (message "Denied posting -- Empty article.")
+            nil))))
+   ;; Check for control characters.
+   (message-check 'control-chars
+     (if (re-search-forward
+         (mm-string-to-multibyte "[\000-\007\013\015-\032\034-\037\200-\237]")
+         nil t)
+        (y-or-n-p
+         "The article contains control characters.  Really post? ")
+       t))
+   ;; Check excessive size.
+   (message-check 'size
+     (if (> (buffer-size) 60000)
+        (y-or-n-p
+         (format "The article is %d octets long.  Really post? "
+                 (buffer-size)))
+       t))
+   ;; Check whether any new text has been added.
+   (message-check 'new-text
+     (or
+      (not message-checksum)
+      (not (eq (message-checksum) message-checksum))
+      (if (message-gnksa-enable-p 'quoted-text-only)
+         (y-or-n-p
+          "It looks like no new text has been added.  Really post? ")
+       (message "Denied posting -- no new text has been added.")
+       nil)))
+   ;; Check the length of the signature.
+   (message-check 'signature
+     (let (sig-start sig-end)
+       (goto-char (point-max))
+       (if (not (re-search-backward message-signature-separator nil t))
+          t
+        (setq sig-start (1+ (point-at-eol)))
+        (setq sig-end
+              (if (re-search-forward
+                   "<#/?\\(multipart\\|part\\|external\\|mml\\)" nil t)
+                  (- (point-at-bol) 1)
+                (point-max)))
+        (if (>= (count-lines sig-start sig-end) 5)
+            (if (message-gnksa-enable-p 'signature)
+                (y-or-n-p
+                 (format "Signature is excessively long (%d lines).  Really post? "
+                         (count-lines sig-start sig-end)))
+              (message "Denied posting -- Excessive signature.")
+              nil)
+          t))))
+   ;; Ensure that text follows last quoted portion.
+   (message-check 'quoting-style
+     (goto-char (point-max))
+     (let ((no-problem t))
+       (when (search-backward-regexp "^>[^\n]*\n" nil t)
+        (setq no-problem (search-forward-regexp "^[ \t]*[^>\n]" nil t)))
+       (if no-problem
+          t
+        (if (message-gnksa-enable-p 'quoted-text-only)
+            (y-or-n-p "Your text should follow quoted text.  Really post? ")
+          ;; Ensure that
+          (goto-char (point-min))
+          (re-search-forward
+           (concat "^" (regexp-quote mail-header-separator) "$"))
+          (if (search-forward-regexp "^[ \t]*[^>\n]" nil t)
+              (y-or-n-p "Your text should follow quoted text.  Really post? ")
+            (message "Denied posting -- only quoted text.")
+            nil)))))))
+
+(defun message-checksum ()
+  "Return a \"checksum\" for the current buffer."
+  (let ((sum 0))
+    (save-excursion
+      (goto-char (point-min))
+      (re-search-forward
+       (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))))
+       (forward-char 1)))
+    sum))
+
+(defun message-do-fcc ()
+  "Process Fcc headers in the current buffer."
+  (let ((case-fold-search t)
+       (buf (current-buffer))
+       list file
+       (mml-externalize-attachments message-fcc-externalize-attachments))
+    (save-excursion
+      (save-restriction
+       (message-narrow-to-headers)
+       (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)
+             ;; FIXME this option, rmail-output (also used if
+             ;; message-fcc-handler-function is nil) is not
+             ;; documented anywhere AFAICS.  It should work in Emacs
+             ;; 23; I suspect it does not work in Emacs 22.
+             ;; FIXME I don't see the need for the two different cases here.
+             ;; mail-use-rfc822 makes no difference (in Emacs 23),and
+             ;; the third argument just controls \"Wrote file\" message.
+             (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."
+  (if (or (and (file-readable-p filename)
+              (mail-file-babyl-p filename))
+         ;; gnus-output-to-mail does the wrong thing with live, mbox
+         ;; Rmail buffers in Emacs 23.
+         ;; http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=597255
+         (let ((buff (find-buffer-visiting filename)))
+           (and buff (with-current-buffer buff
+                       (eq major-mode 'rmail-mode)))))
+      (gnus-output-to-rmail filename t)
+    (gnus-output-to-mail filename t)))
+
+(defun message-cleanup-headers ()
+  "Do various automatic cleanups of the headers."
+  ;; Remove empty lines in the header.
+  (save-restriction
+    (message-narrow-to-headers)
+    ;; Remove blank lines.
+    (while (re-search-forward "^[ \t]*\n" nil t)
+      (replace-match "" t t))
+
+    ;; Correct Newsgroups and Followup-To headers:  Change sequence of
+    ;; spaces to comma and eliminate spaces around commas.  Eliminate
+    ;; embedded line breaks.
+    (goto-char (point-min))
+    (while (re-search-forward "^\\(Newsgroups\\|Followup-To\\): +" nil t)
+      (save-restriction
+       (narrow-to-region
+        (point)
+        (if (re-search-forward "^[^ \t]" nil t)
+            (match-beginning 0)
+          (forward-line 1)
+          (point)))
+       (goto-char (point-min))
+       (while (re-search-forward "\n[ \t]+" nil t)
+         (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))
+       (goto-char (point-min))
+       ;; Remove trailing commas.
+       (when (re-search-forward ",+$" nil t)
+         (replace-match "" t t))))))
+
+(defun message-make-date (&optional now)
+  "Make a valid data header.
+If NOW, use that time instead."
+  (let ((system-time-locale "C"))
+    (format-time-string "%a, %d %b %Y %T %z" now)))
+
+(defun message-insert-expires (days)
+  "Insert the Expires header.  Expiry in DAYS days."
+  (interactive "NExpire article in how many days? ")
+  (save-excursion
+    (message-position-on-field "Expires" "X-Draft-From")
+    (insert (message-make-expires-date days))))
+
+(defun message-make-expires-date (days)
+  "Make date string for the Expires header.  Expiry in DAYS days.
+
+In posting styles use `(\"Expires\" (make-expires-date 30))'."
+  (let* ((cur (decode-time))
+        (nday (+ days (nth 3 cur))))
+    (setf (nth 3 cur) nday)
+    (message-make-date (apply 'encode-time cur))))
+
+(defun message-make-message-id ()
+  "Make a unique Message-ID."
+  (concat "<" (message-unique-id)
+         (let ((psubject (save-excursion (message-fetch-field "subject")))
+               (psupersedes
+                (save-excursion (message-fetch-field "supersedes"))))
+           (if (or
+                (and message-reply-headers
+                     (mail-header-references message-reply-headers)
+                     (mail-header-subject message-reply-headers)
+                     psubject
+                     (not (string=
+                           (message-strip-subject-re
+                            (mail-header-subject message-reply-headers))
+                           (message-strip-subject-re psubject))))
+                (and psupersedes
+                     (string-match "_-_@" psupersedes)))
+               "_-_" ""))
+         "@" (message-make-fqdn) ">"))
+
+(defvar message-unique-id-char nil)
+
+;; If you ever change this function, make sure the new version
+;; cannot generate IDs that the old version could.
+;; You might for example insert a "." somewhere (not next to another dot
+;; or string boundary), or modify the "fsf" string.
+(defun message-unique-id ()
+  ;; Don't use microseconds from (current-time), they may be unsupported.
+  ;; Instead we use this randomly inited counter.
+  (setq message-unique-id-char
+       (% (1+ (or message-unique-id-char
+                  (logand (random most-positive-fixnum) (1- (lsh 1 20)))))
+          ;; (current-time) returns 16-bit ints,
+          ;; and 2^16*25 just fits into 4 digits i base 36.
+          (* 25 25)))
+  (let ((tm (current-time)))
+    (concat
+     (if (or (eq system-type 'ms-dos)
+            ;; message-number-base36 doesn't handle bigints.
+            (floatp (user-uid)))
+        (let ((user (downcase (user-login-name))))
+          (while (string-match "[^a-z0-9_]" user)
+            (aset user (match-beginning 0) ?_))
+          user)
+       (message-number-base36 (user-uid) -1))
+     (message-number-base36 (+ (car tm)
+                              (lsh (% message-unique-id-char 25) 16)) 4)
+     (message-number-base36 (+ (nth 1 tm)
+                              (lsh (/ message-unique-id-char 25) 16)) 4)
+     ;; Append a given name, because while the generated ID is unique
+     ;; to this newsreader, other newsreaders might otherwise generate
+     ;; the same ID via another algorithm.
+     ".fsf")))
+
+(defun message-number-base36 (num len)
+  (if (if (< len 0)
+         (<= num 0)
+       (= len 0))
+      ""
+    (concat (message-number-base36 (/ num 36) (1- len))
+           (char-to-string (aref "zyxwvutsrqponmlkjihgfedcba9876543210"
+                                 (% num 36))))))
+
+(defun message-make-organization ()
+  "Make an Organization header."
+  (let* ((organization
+         (when message-user-organization
+           (if (functionp message-user-organization)
+               (funcall message-user-organization)
+             message-user-organization))))
+    (with-temp-buffer
+      (mm-enable-multibyte)
+      (cond ((stringp organization)
+            (insert organization))
+           ((and (eq t organization)
+                 message-user-organization-file
+                 (file-exists-p message-user-organization-file))
+            (insert-file-contents message-user-organization-file)))
+      (goto-char (point-min))
+      (while (re-search-forward "[\t\n]+" nil t)
+       (replace-match "" t t))
+      (unless (zerop (buffer-size))
+       (buffer-string)))))
+
+(defun message-make-lines ()
+  "Count the number of lines and return numeric string."
+  (save-excursion
+    (save-restriction
+      (widen)
+      (message-goto-body)
+      (int-to-string (count-lines (point) (point-max))))))
+
+(defun message-make-references ()
+  "Return the References header for this message."
+  (when message-reply-headers
+    (let ((message-id (mail-header-id message-reply-headers))
+         (references (mail-header-references message-reply-headers)))
+      (if (or references message-id)
+         (concat (or references "") (and references " ")
+                 (or message-id ""))
+       nil))))
+
+(defun message-make-in-reply-to ()
+  "Return the In-Reply-To header for this message."
+  (when message-reply-headers
+    (let ((from (mail-header-from message-reply-headers))
+         (date (mail-header-date message-reply-headers))
+         (msg-id (mail-header-id message-reply-headers)))
+      (when from
+       (let ((name (mail-extract-address-components from)))
+         (concat
+          msg-id (if msg-id " (")
+          (if (car name)
+              (if (string-match "[^\000-\177]" (car name))
+                  ;; Quote a string containing non-ASCII characters.
+                  ;; It will make the RFC2047 encoder cause an error
+                  ;; if there are special characters.
+                   (mm-with-multibyte-buffer
+                     (insert (car name))
+                     (goto-char (point-min))
+                     (while (search-forward "\"" nil t)
+                       (when (prog2
+                                 (backward-char)
+                                 (zerop (% (skip-chars-backward "\\\\") 2))
+                               (goto-char (match-beginning 0)))
+                         (insert "\\"))
+                       (forward-char))
+                     ;; Those quotes will be removed by the RFC2047 encoder.
+                     (concat "\"" (buffer-string) "\""))
+                (car name))
+            (nth 1 name))
+          "'s message of \""
+          (if (or (not date) (string= date ""))
+              "(unknown date)" date)
+          "\"" (if msg-id ")")))))))
+
+(defun message-make-distribution ()
+  "Make a Distribution header."
+  (let ((orig-distribution (message-fetch-reply-field "distribution")))
+    (cond ((functionp message-distribution-function)
+          (funcall message-distribution-function))
+         (t orig-distribution))))
+
+(defun message-make-expires ()
+  "Return an Expires header based on `message-expires'."
+  (let ((current (current-time))
+       (future (* 1.0 message-expires 60 60 24)))
+    ;; Add the future to current.
+    (setcar current (+ (car current) (round (/ future (expt 2 16)))))
+    (setcar (cdr current) (+ (nth 1 current) (% (round future) (expt 2 16))))
+    (message-make-date current)))
+
+(defun message-make-path ()
+  "Return uucp path."
+  (let ((login-name (user-login-name)))
+    (cond ((null message-user-path)
+          (concat (system-name) "!" login-name))
+         ((stringp message-user-path)
+          ;; Support GENERICPATH.  Suggested by vixie@decwrl.dec.com.
+          (concat message-user-path "!" login-name))
+         (t login-name))))
+
+(defun message-make-from (&optional name address)
+  "Make a From header."
+  (let* ((style message-from-style)
+        (login (or address (message-make-address)))
+        (fullname (or name
+                      (and (boundp 'user-full-name)
+                           user-full-name)
+                      (user-full-name))))
+    (when (string= fullname "&")
+      (setq fullname (user-login-name)))
+    (with-temp-buffer
+      (mm-enable-multibyte)
+      (cond
+       ((or (null style)
+           (equal fullname ""))
+       (insert login))
+       ((or (eq style 'angles)
+           (and (not (eq style 'parens))
+                ;; Use angles if no quoting is needed, or if parens would
+                ;; need quoting too.
+                (or (not (string-match "[^- !#-'*+/-9=?A-Z^-~]" fullname))
+                    (let ((tmp (concat fullname nil)))
+                      (while (string-match "([^()]*)" tmp)
+                        (aset tmp (match-beginning 0) ?-)
+                        (aset tmp (1- (match-end 0)) ?-))
+                      (string-match "[\\()]" tmp)))))
+       (insert fullname)
+       (goto-char (point-min))
+       ;; Look for a character that cannot appear unquoted
+       ;; according to RFC 822.
+       (when (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]" nil 1)
+         ;; Quote fullname, escaping specials.
+         (goto-char (point-min))
+         (insert "\"")
+         (while (re-search-forward "[\"\\]" nil 1)
+           (replace-match "\\\\\\&" t))
+         (insert "\""))
+       (insert " <" login ">"))
+       (t                              ; 'parens or default
+       (insert login " (")
+       (let ((fullname-start (point)))
+         (insert fullname)
+         (goto-char fullname-start)
+         ;; RFC 822 says \ and nonmatching parentheses
+         ;; must be escaped in comments.
+         ;; Escape every instance of ()\ ...
+         (while (re-search-forward "[()\\]" nil 1)
+           (replace-match "\\\\\\&" t))
+         ;; ... then undo escaping of matching parentheses,
+         ;; including matching nested parentheses.
+         (goto-char fullname-start)
+         (while (re-search-forward
+                 "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)"
+                 nil 1)
+           (replace-match "\\1(\\3)" t)
+           (goto-char fullname-start)))
+       (insert ")")))
+      (buffer-string))))
+
+(defun message-make-sender ()
+  "Return the \"real\" user address.
+This function tries to ignore all user modifications, and
+give as trustworthy answer as possible."
+  (concat (user-login-name) "@" (system-name)))
+
+(defun message-make-address ()
+  "Make the address of the user."
+  (or (message-user-mail-address)
+      (concat (user-login-name) "@" (message-make-domain))))
+
+(defun message-user-mail-address ()
+  "Return the pertinent part of `user-mail-address'."
+  (when (and user-mail-address
+            (string-match "@.*\\." user-mail-address))
+    (if (string-match " " user-mail-address)
+       (nth 1 (mail-extract-address-components user-mail-address))
+      user-mail-address)))
+
+(defun message-sendmail-envelope-from ()
+  "Return the envelope from."
+  (cond ((eq message-sendmail-envelope-from 'header)
+        (nth 1 (mail-extract-address-components
+                (message-fetch-field "from"))))
+       ((stringp message-sendmail-envelope-from)
+        message-sendmail-envelope-from)
+       (t
+        (message-make-address))))
+
+(defun message-make-fqdn ()
+  "Return user's fully qualified domain name."
+  (let* ((sysname (system-name))
+        (user-mail (message-user-mail-address))
+        (user-domain
+         (if (and user-mail
+                  (string-match "@\\(.*\\)\\'" user-mail))
+             (match-string 1 user-mail)))
+        (case-fold-search t))
+    (cond
+     ((and message-user-fqdn
+          (stringp message-user-fqdn)
+          (string-match message-valid-fqdn-regexp message-user-fqdn)
+          (not (string-match message-bogus-system-names message-user-fqdn)))
+      ;; `message-user-fqdn' seems to be valid
+      message-user-fqdn)
+     ((and (string-match message-valid-fqdn-regexp sysname)
+          (not (string-match message-bogus-system-names sysname)))
+      ;; `system-name' returned the right result.
+      sysname)
+     ;; Try `mail-host-address'.
+     ((and (boundp 'mail-host-address)
+          (stringp mail-host-address)
+          (string-match message-valid-fqdn-regexp mail-host-address)
+          (not (string-match message-bogus-system-names mail-host-address)))
+      mail-host-address)
+     ;; We try `user-mail-address' as a backup.
+     ((and user-domain
+          (stringp user-domain)
+          (string-match message-valid-fqdn-regexp user-domain)
+          (not (string-match message-bogus-system-names user-domain)))
+      user-domain)
+     ;; Default to this bogus thing.
+     (t
+      (concat sysname
+             ".i-did-not-set--mail-host-address--so-tickle-me")))))
+
+(defun message-make-domain ()
+  "Return the domain name."
+  (or mail-host-address
+      (message-make-fqdn)))
+
+(defun message-to-list-only ()
+  "Send a message to the list only.
+Remove all addresses but the list address from To and Cc headers."
+  (interactive)
+  (let ((listaddr (message-make-mail-followup-to t)))
+    (when listaddr
+      (save-excursion
+       (message-remove-header "to")
+       (message-remove-header "cc")
+       (message-position-on-field "To" "X-Draft-From")
+       (insert listaddr)))))
+
+(defun message-make-mail-followup-to (&optional only-show-subscribed)
+  "Return the Mail-Followup-To header.
+If passed the optional argument ONLY-SHOW-SUBSCRIBED only return the
+subscribed address (and not the additional To and Cc header contents)."
+  (let* ((case-fold-search t)
+        (to (message-fetch-field "To"))
+        (cc (message-fetch-field "cc"))
+        (msg-recipients (concat to (and to cc ", ") cc))
+        (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
+      (let ((list
+            (loop for recipient in recipients
+              when (loop for regexp in mft-regexps
+                     when (string-match regexp recipient) return t)
+              return recipient)))
+       (when list
+         (if only-show-subscribed
+             list
+           msg-recipients))))))
+
+(defun message-idna-to-ascii-rhs-1 (header)
+  "Interactively potentially IDNA encode domain names in HEADER."
+  (let ((field (message-fetch-field header))
+        ace)
+    (when field
+      (dolist (rhs
+              (mm-delete-duplicates
+               (mapcar (lambda (rhs) (or (cadr (split-string rhs "@")) ""))
+                       (mapcar 'downcase
+                               (mapcar
+                                (lambda (elem)
+                                  (or (cadr elem)
+                                      ""))
+                                (mail-extract-address-components field t))))))
+       ;; Note that `rhs' will be "" if the address does not have
+       ;; the domain part, i.e., if it is a local user's address.
+       (setq ace (if (string-match "\\`[[:ascii:]]*\\'" rhs)
+                     rhs
+                   (downcase (idna-to-ascii rhs))))
+       (when (and (not (equal rhs ace))
+                  (or (not (eq message-use-idna 'ask))
+                      (y-or-n-p (format "Replace %s with %s in %s:? "
+                                        rhs ace header))))
+         (goto-char (point-min))
+         (while (re-search-forward (concat "^" header ":") nil t)
+           (message-narrow-to-field)
+           (while (search-forward (concat "@" rhs) nil t)
+             (replace-match (concat "@" ace) t t))
+           (goto-char (point-max))
+           (widen)))))))
+
+(defun message-idna-to-ascii-rhs ()
+  "Possibly IDNA encode non-ASCII domain names in From:, To: and Cc: headers.
+See `message-idna-encode'."
+  (interactive)
+  (when message-use-idna
+    (save-excursion
+      (save-restriction
+       ;; `message-narrow-to-head' that recognizes only the first empty
+       ;; line as the message header separator used to be used here.
+       ;; However, since there is the "--text follows this line--" line
+       ;; normally, it failed in narrowing to the headers and potentially
+       ;; caused the IDNA encoding on lines that look like headers in
+       ;; the message body.
+       (message-narrow-to-headers-or-head)
+       (message-idna-to-ascii-rhs-1 "From")
+       (message-idna-to-ascii-rhs-1 "To")
+       (message-idna-to-ascii-rhs-1 "Reply-To")
+       (message-idna-to-ascii-rhs-1 "Mail-Reply-To")
+       (message-idna-to-ascii-rhs-1 "Mail-Followup-To")
+       (message-idna-to-ascii-rhs-1 "Cc")))))
+
+(defvar Date)
+(defvar Message-ID)
+(defvar Organization)
+(defvar From)
+(defvar Path)
+(defvar Subject)
+(defvar Newsgroups)
+(defvar In-Reply-To)
+(defvar References)
+(defvar To)
+(defvar Distribution)
+(defvar Lines)
+(defvar User-Agent)
+(defvar Expires)
+
+(defun message-generate-headers (headers)
+  "Prepare article HEADERS.
+Headers already prepared in the buffer are not modified."
+  (setq headers (append headers message-required-headers))
+  (save-restriction
+    (message-narrow-to-headers)
+    (let* ((Date (message-make-date))
+          (Message-ID (message-make-message-id))
+          (Organization (message-make-organization))
+          (From (message-make-from))
+          (Path (message-make-path))
+          (Subject nil)
+          (Newsgroups nil)
+          (In-Reply-To (message-make-in-reply-to))
+          (References (message-make-references))
+          (To nil)
+          (Distribution (message-make-distribution))
+          (Lines (message-make-lines))
+          (User-Agent message-newsreader)
+          (Expires (message-make-expires))
+          (case-fold-search t)
+          (optionalp nil)
+          header value elem header-string)
+      ;; First we remove any old generated headers.
+      (let ((headers message-deletable-headers))
+       (unless (buffer-modified-p)
+         (setq headers (delq 'Message-ID (copy-sequence headers))))
+       (while headers
+         (goto-char (point-min))
+         (and (re-search-forward
+               (concat "^" (symbol-name (car headers)) ": *") nil t)
+              (get-text-property (1+ (match-beginning 0)) 'message-deletable)
+              (message-delete-line))
+         (pop headers)))
+      ;; Go through all the required headers and see if they are in the
+      ;; articles already.  If they are not, or are empty, they are
+      ;; inserted automatically - except for Subject, Newsgroups and
+      ;; Distribution.
+      (while headers
+       (goto-char (point-min))
+       (setq elem (pop headers))
+       (if (consp elem)
+           (if (eq (car elem) 'optional)
+               (setq header (cdr elem)
+                     optionalp t)
+             (setq header (car elem)))
+         (setq header elem))
+       (setq header-string  (if (stringp header)
+                                header
+                              (symbol-name header)))
+       (when (or (not (re-search-forward
+                       (concat "^"
+                               (regexp-quote (downcase header-string))
+                               ":")
+                       nil t))
+                 (progn
+                   ;; The header was found.  We insert a space after the
+                   ;; colon, if there is none.
+                   (if (/= (char-after) ? ) (insert " ") (forward-char 1))
+                   ;; Find out whether the header is empty.
+                   (looking-at "[ \t]*\n[^ \t]")))
+         ;; So we find out what value we should insert.
+         (setq value
+               (cond
+                ((and (consp elem)
+                      (eq (car elem) 'optional)
+                      (not (member header-string message-inserted-headers)))
+                 ;; This is an optional header.  If the cdr of this
+                 ;; is something that is nil, then we do not insert
+                 ;; this header.
+                 (setq header (cdr elem))
+                 (or (and (functionp (cdr elem))
+                          (funcall (cdr elem)))
+                     (and (boundp (cdr elem))
+                          (symbol-value (cdr elem)))))
+                ((consp elem)
+                 ;; The element is a cons.  Either the cdr is a
+                 ;; string to be inserted verbatim, or it is a
+                 ;; function, and we insert the value returned from
+                 ;; this function.
+                 (or (and (stringp (cdr elem))
+                          (cdr elem))
+                     (and (functionp (cdr elem))
+                          (funcall (cdr elem)))))
+                ((and (boundp header)
+                      (symbol-value header))
+                 ;; The element is a symbol.  We insert the value
+                 ;; of this symbol, if any.
+                 (symbol-value header))
+                ((not (message-check-element
+                       (intern (downcase (symbol-name header)))))
+                 ;; We couldn't generate a value for this header,
+                 ;; so we just ask the user.
+                 (read-from-minibuffer
+                  (format "Empty header for %s; enter value: " header)))))
+         ;; Finally insert the header.
+         (when (and value
+                    (not (equal value "")))
+           (save-excursion
+             (if (bolp)
+                 (progn
+                   ;; This header didn't exist, so we insert it.
+                   (goto-char (point-max))
+                   (let ((formatter
+                          (cdr (assq header message-header-format-alist))))
+                     (if formatter
+                         (funcall formatter header value)
+                       (insert header-string ": " value))
+                     (push header-string message-inserted-headers)
+                     (goto-char (message-fill-field))
+                     ;; We check whether the value was ended by a
+                     ;; newline.  If not, we insert one.
+                     (unless (bolp)
+                       (insert "\n"))
+                     (forward-line -1)))
+               ;; The value of this header was empty, so we clear
+               ;; totally and insert the new value.
+               (delete-region (point) (point-at-eol))
+               ;; If the header is optional, and the header was
+               ;; empty, we can't insert it anyway.
+               (unless optionalp
+                 (push header-string message-inserted-headers)
+                 (insert value)
+                 (message-fill-field)))
+             ;; Add the deletable property to the headers that require it.
+             (and (memq header message-deletable-headers)
+                  (progn (beginning-of-line) (looking-at "[^:]+: "))
+                  (add-text-properties
+                   (point) (match-end 0)
+                   '(message-deletable t face italic) (current-buffer)))))))
+      ;; Insert new Sender if the From is strange.
+      (let ((from (message-fetch-field "from"))
+           (sender (message-fetch-field "sender"))
+           (secure-sender (message-make-sender)))
+       (when (and from
+                  (not (message-check-element 'sender))
+                  (not (string=
+                        (downcase
+                         (cadr (mail-extract-address-components from)))
+                        (downcase secure-sender)))
+                  (or (null sender)
+                      (not
+                       (string=
+                        (downcase
+                         (cadr (mail-extract-address-components sender)))
+                        (downcase secure-sender)))))
+         (goto-char (point-min))
+         ;; Rename any old Sender headers to Original-Sender.
+         (when (re-search-forward "^\\(Original-\\)*Sender:" nil t)
+           (beginning-of-line)
+           (insert "Original-")
+           (beginning-of-line))
+         (when (or (message-news-p)
+                   (string-match "@.+\\.." secure-sender))
+           (insert "Sender: " secure-sender "\n"))))
+      ;; Check for IDNA
+      (message-idna-to-ascii-rhs))))
+
+(defun message-insert-courtesy-copy (message)
+  "Insert a courtesy message in mail copies of combined messages."
+  (let (newsgroups)
+    (save-excursion
+      (save-restriction
+       (message-narrow-to-headers)
+       (when (setq newsgroups (message-fetch-field "newsgroups"))
+         (goto-char (point-max))
+         (insert "Posted-To: " newsgroups "\n")))
+      (forward-line 1)
+      (when message
+       (cond
+        ((string-match "%s" message)
+         (insert (format message newsgroups)))
+        (t
+         (insert message)))))))
+
+;;;
+;;; Setting up a message buffer
+;;;
+
+(defun message-skip-to-next-address ()
+  (let ((end (save-excursion
+              (message-next-header)
+              (point)))
+       quoted char)
+    (when (looking-at ",")
+      (forward-char 1))
+    (while (and (not (= (point) end))
+               (or (not (eq char ?,))
+                   quoted))
+      (skip-chars-forward "^,\"" end)
+      (when (eq (setq char (following-char)) ?\")
+       (setq quoted (not quoted)))
+      (unless (= (point) end)
+       (forward-char 1)))
+    (skip-chars-forward " \t\n")))
+
+(defun message-split-line ()
+  "Split current line, moving portion beyond point vertically down.
+If the current line has `message-yank-prefix', insert it on the new line."
+  (interactive "*")
+  (condition-case nil
+      (split-line message-yank-prefix) ;; Emacs 22.1+ supports arg.
+    (error
+     (split-line))))
+
+(defun message-insert-header (header value)
+  (insert (capitalize (symbol-name header))
+         ": "
+         (if (consp value) (car value) value)))
+
+(defun message-field-name ()
+  (save-excursion
+    (goto-char (point-min))
+    (when (looking-at "\\([^:]+\\):")
+      (intern (capitalize (match-string 1))))))
+
+(defun message-fill-field ()
+  (save-excursion
+    (save-restriction
+      (message-narrow-to-field)
+      (let ((field-name (message-field-name)))
+       (funcall (or (cadr (assq field-name message-field-fillers))
+                    'message-fill-field-general)))
+      (point-max))))
+
+(defun message-fill-field-address ()
+  (let (end last)
+    (while (not end)
+      (message-skip-to-next-address)
+      (cond ((bolp)
+            (end-of-line 0)
+            (setq end 1))
+           ((eobp)
+            (setq end 0)))
+      (when (and (> (current-column) 78)
+                last)
+       (save-excursion
+         (goto-char last)
+         (delete-char (- (skip-chars-backward " \t")))
+         (insert "\n\t")))
+      (setq last (point)))
+    (forward-line end)))
+
+(defun message-fill-field-general ()
+  (let ((begin (point))
+       (fill-column 78)
+       (fill-prefix "\t"))
+    (while (and (search-forward "\n" nil t)
+               (not (eobp)))
+      (replace-match " " t t))
+    (fill-region-as-paragraph begin (point-max))
+    ;; Tapdance around looong Message-IDs.
+    (forward-line -1)
+    (when (looking-at "[ \t]*$")
+      (message-delete-line))
+    (goto-char begin)
+    (search-forward ":" nil t)
+    (when (looking-at "\n[ \t]+")
+      (replace-match " " t t))
+    (goto-char (point-max))))
+
+(defun message-shorten-1 (list cut surplus)
+  "Cut SURPLUS elements out of LIST, beginning with CUTth one."
+  (setcdr (nthcdr (- cut 2) list)
+         (nthcdr (+ (- cut 2) surplus 1) list)))
+
+(defun message-shorten-references (header references)
+  "Trim REFERENCES to be 21 Message-ID long or less, and fold them.
+When sending via news, also check that the REFERENCES are less
+than 988 characters long, and if they are not, trim them until
+they are."
+  ;; 21 is the number suggested by USAGE.
+  (let ((maxcount 21)
+       (count 0)
+       (cut 2)
+       refs)
+    (with-temp-buffer
+      (insert references)
+      (goto-char (point-min))
+      ;; Cons a list of valid references.  GNKSA says we must not include MIDs
+      ;; with whitespace or missing brackets (7.a "Does not propagate broken
+      ;; Message-IDs in original References").
+      (while (re-search-forward "<[^ <]+@[^ <]+>" nil t)
+       (push (match-string 0) refs))
+      (setq refs (nreverse refs)
+           count (length refs)))
+
+    ;; If the list has more than MAXCOUNT elements, trim it by
+    ;; removing the CUTth element and the required number of
+    ;; elements that follow.
+    (when (> count maxcount)
+      (let ((surplus (- count maxcount)))
+       (message-shorten-1 refs cut surplus)
+       (decf count surplus)))
+
+    ;; When sending via news, make sure the total folded length will
+    ;; be less than 998 characters.  This is to cater to broken INN
+    ;; 2.3 which counts the total number of characters in a header
+    ;; rather than the physical line length of each line, as it should.
+    ;;
+    ;; This hack should be removed when it's believed than INN 2.3 is
+    ;; no longer widely used.
+    ;;
+    ;; At this point the headers have not been generated, thus we use
+    ;; message-this-is-news directly.
+    (when message-this-is-news
+      (while (< 998
+               (with-temp-buffer
+                 (message-insert-header
+                  header (mapconcat #'identity refs " "))
+                 (buffer-size)))
+       (message-shorten-1 refs cut 1)))
+    ;; Finally, collect the references back into a string and insert
+    ;; it into the buffer.
+    (message-insert-header header (mapconcat #'identity refs " "))))
+
+(defun message-position-point ()
+  "Move point to where the user probably wants to find it."
+  (message-narrow-to-headers)
+  (cond
+   ((re-search-forward "^[^:]+:[ \t]*$" nil t)
+    (search-backward ":" )
+    (widen)
+    (forward-char 1)
+    (if (eq (char-after) ? )
+       (forward-char 1)
+      (insert " ")))
+   (t
+    (goto-char (point-max))
+    (widen)
+    (forward-line 1)
+    (unless (looking-at "$")
+      (forward-line 2)))
+   (sit-for 0)))
+
+(defcustom message-beginning-of-line t
+  "Whether \\<message-mode-map>\\[message-beginning-of-line]\
+ goes to beginning of header values."
+  :version "22.1"
+  :group 'message-buffers
+  :link '(custom-manual "(message)Movement")
+  :type 'boolean)
+
+(defvar visual-line-mode)
+(declare-function beginning-of-visual-line "simple" (&optional n))
+
+(defun message-beginning-of-line (&optional n)
+  "Move point to beginning of header value or to beginning of line.
+The prefix argument N is passed directly to `beginning-of-line'.
+
+This command is identical to `beginning-of-line' if point is
+outside the message header or if the option `message-beginning-of-line'
+is nil.
+
+If point is in the message header and on a (non-continued) header
+line, move point to the beginning of the header value or the beginning of line,
+whichever is closer.  If point is already at beginning of line, move point to
+beginning of header value.  Therefore, repeated calls will toggle point
+between beginning of field and beginning of line."
+  (interactive "p")
+  (let ((zrs 'zmacs-region-stays))
+    (when (and (featurep 'xemacs) (interactive-p) (boundp zrs))
+      (set zrs t)))
+  (if (and message-beginning-of-line
+          (message-point-in-header-p))
+      (let* ((here (point))
+            (bol (progn (beginning-of-line n) (point)))
+            (eol (point-at-eol))
+            (eoh (re-search-forward ": *" eol t)))
+       (goto-char
+        (if (and eoh (or (< eoh here) (= bol here)))
+            eoh bol)))
+    (if (and (boundp 'visual-line-mode) visual-line-mode)
+       (beginning-of-visual-line n)
+      (beginning-of-line n))))
+
+(defun message-buffer-name (type &optional to group)
+  "Return a new (unique) buffer name based on TYPE and TO."
+  (cond
+   ;; Generate a new buffer name The Message Way.
+   ((memq message-generate-new-buffers '(unique t))
+    (generate-new-buffer-name
+     (concat "*" type
+            (if to
+                (concat " to "
+                        (or (car (mail-extract-address-components to))
+                            to) "")
+              "")
+            (if (and group (not (string= group ""))) (concat " on " group) "")
+            "*")))
+   ;; Check whether `message-generate-new-buffers' is a function,
+   ;; and if so, call it.
+   ((functionp message-generate-new-buffers)
+    (funcall message-generate-new-buffers type to group))
+   ((eq message-generate-new-buffers 'unsent)
+    (generate-new-buffer-name
+     (concat "*unsent " type
+            (if to
+                (concat " to "
+                        (or (car (mail-extract-address-components to))
+                            to) "")
+              "")
+            (if (and group (not (string= group ""))) (concat " on " group) "")
+            "*")))
+   ;; Search for the existing message buffer with the specified name.
+   (t
+    (let* ((new (if (eq message-generate-new-buffers 'standard)
+                   (generate-new-buffer-name (concat "*" type " message*"))
+                 (let ((message-generate-new-buffers 'unique))
+                   (message-buffer-name type to group))))
+          (regexp (concat "\\`"
+                          (regexp-quote
+                           (if (string-match "<[0-9]+>\\'" new)
+                               (substring new 0 (match-beginning 0))
+                             new))
+                          "\\(?:<\\([0-9]+\\)>\\)?\\'"))
+          (case-fold-search nil))
+      (or (cdar
+          (last
+           (sort
+            (delq nil
+                  (mapcar
+                   (lambda (b)
+                     (when (and (string-match regexp (setq b (buffer-name b)))
+                                (eq (with-current-buffer b major-mode)
+                                    'message-mode))
+                       (cons (string-to-number (or (match-string 1 b) "1"))
+                             b)))
+                   (buffer-list)))
+            'car-less-than-car)))
+         new)))))
+
+(defun message-pop-to-buffer (name &optional switch-function)
+  "Pop to buffer NAME, and warn if it already exists and is modified."
+  (let ((buffer (get-buffer name)))
+    (if (and buffer
+            (buffer-name buffer))
+       (let ((window (get-buffer-window buffer 0)))
+         (if window
+             ;; Raise the frame already displaying the message buffer.
+             (progn
+               (gnus-select-frame-set-input-focus (window-frame window))
+               (select-window window))
+           (funcall (or switch-function #'pop-to-buffer) buffer)
+           (set-buffer buffer))
+         (when (and (buffer-modified-p)
+                    (not (prog1
+                             (y-or-n-p
+                              "Message already being composed; erase? ")
+                           (message nil))))
+           (error "Message being composed")))
+      (funcall (or switch-function
+                  (if (fboundp #'pop-to-buffer-same-window)
+                      #'pop-to-buffer-same-window
+                    #'pop-to-buffer))
+              name)
+      (set-buffer name))
+    (erase-buffer)
+    (message-mode)))
+
+(defun message-do-send-housekeeping ()
+  "Kill old message buffers."
+  ;; We might have sent this buffer already.  Delete it from the
+  ;; list of buffers.
+  (setq message-buffer-list (delq (current-buffer) message-buffer-list))
+  (while (and message-max-buffers
+             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)))
+      (when (and (buffer-name buffer)
+                (not (buffer-modified-p buffer)))
+       (kill-buffer buffer))))
+  ;; Rename the buffer.
+  (if message-send-rename-function
+      (funcall message-send-rename-function)
+    (message-default-send-rename-function))
+  ;; Push the current buffer onto the list.
+  (when message-max-buffers
+    (setq message-buffer-list
+         (nconc message-buffer-list (list (current-buffer))))))
+
+(defun message-default-send-rename-function ()
+  ;; 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 (null name)
+                  (string-equal name "mail")
+                  (string-equal name "posting")))
+         (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
+              (to (concat "*sent mail to "
+                          (or (car (mail-extract-address-components to))
+                              to) "*"))
+              ((and group (not (string= group "")))
+               (concat "*sent posting on " group "*"))
+              (t "*sent mail*"))))
+      (unless (string-equal name (buffer-name))
+       (rename-buffer name t)))))
+
+(defun message-mail-user-agent ()
+  (let ((mua (cond
+             ((not message-mail-user-agent) nil)
+             ((eq message-mail-user-agent t) mail-user-agent)
+             (t message-mail-user-agent))))
+    (if (memq mua '(message-user-agent gnus-user-agent))
+       nil
+      mua)))
+
+;; YANK-ACTION, if non-nil, can be a buffer or a yank action of the
+;; form (FUNCTION . ARGS).
+(defun message-setup (headers &optional yank-action actions
+                             continue switch-function return-action)
+  (let ((mua (message-mail-user-agent))
+       subject to field)
+    (if (not (and message-this-is-mail mua))
+       (message-setup-1 headers yank-action actions return-action)
+      (setq headers (copy-sequence headers))
+      (setq field (assq 'Subject headers))
+      (when field
+       (setq subject (cdr field))
+       (setq headers (delq field headers)))
+      (setq field (assq 'To headers))
+      (when field
+       (setq to (cdr field))
+       (setq headers (delq field headers)))
+      (let ((mail-user-agent mua))
+       (compose-mail to subject
+                     (mapcar (lambda (item)
+                               (cons
+                                (format "%s" (car item))
+                                (cdr item)))
+                             headers)
+                     continue switch-function
+                     (if (bufferp yank-action)
+                         (list 'insert-buffer yank-action)
+                       yank-action)
+                     actions)))))
+
+(defun message-headers-to-generate (headers included-headers excluded-headers)
+  "Return a list that includes all headers from HEADERS.
+If INCLUDED-HEADERS is a list, just include those headers.  If it is
+t, include all headers.  In any case, headers from EXCLUDED-HEADERS
+are not included."
+  (let ((result nil)
+       header-name)
+    (dolist (header headers)
+      (setq header-name (cond
+                        ((and (consp header)
+                              (eq (car header) 'optional))
+                         ;; On the form (optional . Header)
+                         (cdr header))
+                        ((consp header)
+                         ;; On the form (Header . function)
+                         (car header))
+                        (t
+                         ;; Just a Header.
+                         header)))
+      (when (and (not (memq header-name excluded-headers))
+                (or (eq included-headers t)
+                    (memq header-name included-headers)))
+       (push header result)))
+    (nreverse result)))
+
+(defun message-setup-1 (headers &optional yank-action actions return-action)
+  (dolist (action actions)
+    (condition-case nil
+       (add-to-list 'message-send-actions
+                    `(apply ',(car action) ',(cdr action)))))
+  (setq message-return-action return-action)
+  (setq message-reply-buffer
+       (if (and (consp yank-action)
+                (eq (car yank-action) 'insert-buffer))
+           (nth 1 yank-action)
+         yank-action))
+  (goto-char (point-min))
+  ;; Insert all the headers.
+  (mail-header-format
+   (let ((h headers)
+        (alist message-header-format-alist))
+     (while h
+       (unless (assq (caar h) message-header-format-alist)
+        (push (list (caar h)) alist))
+       (pop h))
+     alist)
+   headers)
+  (delete-region (point) (progn (forward-line -1) (point)))
+  (when message-default-headers
+    (insert
+     (if (functionp message-default-headers)
+         (funcall message-default-headers)
+       message-default-headers))
+    (or (bolp) (insert ?\n)))
+  (insert (concat mail-header-separator "\n"))
+  (forward-line -1)
+  ;; If a crash happens while replying, the auto-save file would *not* have a
+  ;; `References:' header if `message-generate-headers-first' was nil.
+  ;; Therefore, always generate it first.
+  (let ((message-generate-headers-first
+         (if (eq message-generate-headers-first t)
+             t
+           (append message-generate-headers-first '(References)))))
+    (when (message-news-p)
+      (when message-default-news-headers
+        (insert message-default-news-headers)
+        (or (bolp) (insert ?\n)))
+      (message-generate-headers
+       (message-headers-to-generate
+        (append message-required-news-headers
+                message-required-headers)
+        message-generate-headers-first
+        '(Lines Subject))))
+    (when (message-mail-p)
+      (when message-default-mail-headers
+        (insert message-default-mail-headers)
+        (or (bolp) (insert ?\n)))
+      (message-generate-headers
+       (message-headers-to-generate
+        (append message-required-mail-headers
+                message-required-headers)
+        message-generate-headers-first
+        '(Lines Subject)))))
+  (run-hooks 'message-signature-setup-hook)
+  (message-insert-signature)
+  (save-restriction
+    (message-narrow-to-headers)
+    (run-hooks 'message-header-setup-hook))
+  (setq buffer-undo-list nil)
+  (when message-generate-hashcash
+    ;; Generate hashcash headers for recipients already known
+    (mail-add-payment-async))
+  ;; Gnus posting styles are applied via buffer-local `message-setup-hook'
+  ;; values.
+  (run-hooks 'message-setup-hook)
+  ;; Do this last to give it precedence over posting styles, etc.
+  (when (message-mail-p)
+    (save-restriction
+      (message-narrow-to-headers)
+      (if message-alternative-emails
+         (message-use-alternative-email-as-from))))
+  (message-position-point)
+  ;; Allow correct handling of `message-checksum' in `message-yank-original':
+  (set-buffer-modified-p nil)
+  (undo-boundary)
+  ;; rmail-start-mail expects message-mail to return t (Bug#9392)
+  t)
+
+(defun message-set-auto-save-file-name ()
+  "Associate the message buffer with a file in the drafts directory."
+  (when message-auto-save-directory
+    (unless (file-directory-p
+            (directory-file-name message-auto-save-directory))
+      (make-directory message-auto-save-directory t))
+    (if (gnus-alive-p)
+       (setq message-draft-article
+             (nndraft-request-associate-buffer "drafts"))
+
+      ;; If Gnus were alive, draft messages would be saved in the drafts folder.
+      ;; But Gnus is not alive, so arrange to save the draft message in a
+      ;; regular file in message-auto-save-directory.  Append a unique
+      ;; time-based suffix to the filename to allow multiple drafts to be saved
+      ;; simultaneously without overwriting each other (which mimics the
+      ;; functionality of the Gnus drafts folder).
+      (setq buffer-file-name (expand-file-name
+                             (concat
+                             (if (memq system-type
+                                       '(ms-dos windows-nt cygwin))
+                                 "message"
+                               "*message*")
+                              (format-time-string "-%Y%m%d-%H%M%S"))
+                             message-auto-save-directory))
+      (setq buffer-auto-save-file-name (make-auto-save-file-name)))
+    (clear-visited-file-modtime)
+    (setq buffer-file-coding-system message-draft-coding-system)))
+
+(defun message-disassociate-draft ()
+  "Disassociate the message buffer from the drafts directory."
+  (when message-draft-article
+    (nndraft-request-expire-articles
+     (list message-draft-article) "drafts" nil t)))
+
+(defun message-insert-headers ()
+  "Generate the headers for the article."
+  (interactive)
+  (save-excursion
+    (save-restriction
+      (message-narrow-to-headers)
+      (when (message-news-p)
+       (message-generate-headers
+        (delq 'Lines
+              (delq 'Subject
+                    (copy-sequence message-required-news-headers)))))
+      (when (message-mail-p)
+       (message-generate-headers
+        (delq 'Lines
+              (delq 'Subject
+                    (copy-sequence message-required-mail-headers))))))))
+
+\f
+
+;;;
+;;; Commands for interfacing with message
+;;;
+
+;;;###autoload
+(defun message-mail (&optional to subject other-headers continue
+                              switch-function yank-action send-actions
+                              return-action &rest ignored)
+  "Start editing a mail message to be sent.
+OTHER-HEADERS is an alist of header/value pairs.  CONTINUE says whether
+to continue editing a message already being composed.  SWITCH-FUNCTION
+is a function used to switch to and display the mail buffer."
+  (interactive)
+  (let ((message-this-is-mail t))
+    (unless (message-mail-user-agent)
+      (message-pop-to-buffer
+       ;; Search for the existing message buffer if `continue' is non-nil.
+       (let ((message-generate-new-buffers
+             (when (or (not continue)
+                       (eq message-generate-new-buffers 'standard)
+                       (functionp message-generate-new-buffers))
+               message-generate-new-buffers)))
+        (message-buffer-name "mail" to))
+       switch-function))
+    (message-setup
+     (nconc
+      `((To . ,(or to "")) (Subject . ,(or subject "")))
+      ;; C-h f compose-mail says that headers should be specified as
+      ;; (string . value); however all the rest of message expects
+      ;; headers to be symbols, not strings (eg message-header-format-alist).
+      ;; http://lists.gnu.org/archive/html/emacs-devel/2011-01/msg00337.html
+      ;; We need to convert any string input, eg from rmail-start-mail.
+      (dolist (h other-headers other-headers)
+       (if (stringp (car h)) (setcar h (intern (capitalize (car h)))))))
+     yank-action send-actions continue switch-function
+     return-action)))
+
+;;;###autoload
+(defun message-news (&optional newsgroups subject)
+  "Start editing a news article to be sent."
+  (interactive)
+  (let ((message-this-is-news t))
+    (message-pop-to-buffer (message-buffer-name "posting" nil newsgroups))
+    (message-setup `((Newsgroups . ,(or newsgroups ""))
+                    (Subject . ,(or subject ""))))))
+
+(defun message-alter-recipients-discard-bogus-full-name (addrcell)
+  "Discard mail address in full names.
+When the full name in reply headers contains the mail
+address (e.g. \"foo@bar <foo@bar>\"), discard full name.
+ADDRCELL is a cons cell where the car is the mail address and the
+cdr is the complete address (full name and mail address)."
+  (if (string-match (concat (regexp-quote (car addrcell)) ".*"
+                           (regexp-quote (car addrcell)))
+                   (cdr addrcell))
+      (cons (car addrcell) (car addrcell))
+    addrcell))
+
+(defcustom message-alter-recipients-function nil
+  "Function called to allow alteration of reply header structures.
+It is called in `message-get-reply-headers' for each recipient.
+The function is called with one parameter, a cons cell ..."
+  :type '(choice (const :tag "None" nil)
+                (const :tag "Discard bogus full name"
+                       message-alter-recipients-discard-bogus-full-name)
+                function)
+  :version "23.1" ;; No Gnus
+  :group 'message-headers)
+
+(defun message-get-reply-headers (wide &optional to-address address-headers)
+  (let (follow-to mct never-mct to cc author mft recipients extra)
+    ;; Find all relevant headers we need.
+    (save-restriction
+      (message-narrow-to-headers-or-head)
+      ;; Gmane renames "To".  Look at "Original-To", too, if it is present in
+      ;; message-header-synonyms.
+      (setq to (or (message-fetch-field "to")
+                  (and (loop for synonym in message-header-synonyms
+                             when (memq 'Original-To synonym)
+                             return t)
+                       (message-fetch-field "original-to")))
+           cc (message-fetch-field "cc")
+           extra (when message-extra-wide-headers
+                   (mapconcat 'identity
+                              (mapcar 'message-fetch-field
+                                      message-extra-wide-headers)
+                              ", "))
+           mct (message-fetch-field "mail-copies-to")
+           author (or (message-fetch-field "mail-reply-to")
+                      (message-fetch-field "reply-to"))
+           mft (and message-use-mail-followup-to
+                    (message-fetch-field "mail-followup-to")))
+      ;; Make sure this message goes to the author if this is a wide
+      ;; reply, since Reply-To address may be a list address a mailing
+      ;; list server added.
+      (when (and wide author)
+       (setq cc (concat author ", " cc)))
+      (when (or wide (not author))
+       (setq author (or (message-fetch-field "from") ""))))
+
+    ;; Handle special values of Mail-Copies-To.
+    (when mct
+      (cond ((or (equal (downcase mct) "never")
+                (equal (downcase mct) "nobody"))
+            (setq never-mct t)
+            (setq mct nil))
+           ((or (equal (downcase mct) "always")
+                (equal (downcase mct) "poster"))
+            (setq mct author))))
+
+    (save-match-data
+      ;; Build (textual) list of new recipient addresses.
+      (cond
+       (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))))
+       ((not wide)
+       (setq recipients (concat ", " author)))
+       (address-headers
+       (dolist (header address-headers)
+         (let ((value (message-fetch-field header)))
+           (when value
+             (setq recipients (concat recipients ", " value))))))
+       ((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") ".
+
+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 intended for discussion;
+responses here are directed to other addresses.
+
+You may customize the variable `message-use-mail-followup-to', if you
+want to get rid of this query permanently.")))
+       (setq recipients (concat ", " mft)))
+       (t
+       (setq recipients (if never-mct "" (concat ", " author)))
+       (if to (setq recipients (concat recipients ", " to)))
+       (if cc (setq recipients (concat recipients ", " cc)))
+       (if extra (setq recipients (concat recipients ", " extra)))
+       (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 `mail-dont-reply-to-names'.
+      (let* ((mail-dont-reply-to-names (message-dont-reply-to-names))
+            (rmail-dont-reply-to-names mail-dont-reply-to-names))
+       (setq recipients (mail-dont-reply-to recipients)))
+      ;; Perhaps "Mail-Copies-To: never" removed the only address?
+      (if (string-equal recipients "")
+         (setq recipients author))
+      ;; Convert string to a list of (("foo@bar" . "Name <Foo@BAR>") ...).
+      (setq recipients
+           (mapcar
+            (lambda (addr)
+              (if message-alter-recipients-function
+                  (funcall message-alter-recipients-function
+                           (cons (downcase (mail-strip-quoted-names addr))
+                                 addr))
+                (cons (downcase (mail-strip-quoted-names addr)) addr)))
+            (message-tokenize-header recipients)))
+      ;; Remove all duplicates.
+      (let ((s recipients))
+       (while s
+         (let ((address (car (pop s))))
+           (while (assoc address s)
+             (setq recipients (delq (assoc address s) recipients)
+                   s (delq (assoc address s) s))))))
+
+      ;; Remove hierarchical lists that are contained within each other,
+      ;; if message-hierarchical-addresses is defined.
+      (when message-hierarchical-addresses
+       (let ((plain-addrs (mapcar 'car recipients))
+             subaddrs recip)
+         (while plain-addrs
+           (setq subaddrs (assoc (car plain-addrs)
+                                 message-hierarchical-addresses)
+                 plain-addrs (cdr plain-addrs))
+           (when subaddrs
+             (setq subaddrs (cdr subaddrs))
+             (while subaddrs
+               (setq recip (assoc (car subaddrs) recipients)
+                     subaddrs (cdr subaddrs))
+               (if recip
+                   (setq recipients (delq recip recipients))))))))
+
+      (setq recipients (message-prune-recipients 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))
+
+(defun message-prune-recipients (recipients)
+  (dolist (rule message-prune-recipient-rules)
+    (let ((match (car rule))
+         dup-match
+         address)
+      (dolist (recipient recipients)
+       (setq address (car recipient))
+       (when (string-match match address)
+         (setq dup-match (replace-match (cadr rule) nil nil address))
+         (dolist (recipient recipients)
+           ;; Don't delete the address that triggered this.
+           (when (and (not (eq address (car recipient)))
+                      (string-match dup-match (car recipient)))
+             (setq recipients (delq recipient recipients))))))))
+  recipients)
+
+(defcustom message-simplify-subject-functions
+  '(message-strip-list-identifiers
+    message-strip-subject-re
+    message-strip-subject-trailing-was
+    message-strip-subject-encoded-words)
+  "List of functions taking a string argument that simplify subjects.
+The functions are applied when replying to a message.
+
+Useful functions to put in this list include:
+`message-strip-list-identifiers', `message-strip-subject-re',
+`message-strip-subject-trailing-was', and
+`message-strip-subject-encoded-words'."
+  :version "22.1" ;; Gnus 5.10.9
+  :group 'message-various
+  :type '(repeat function))
+
+(defun message-simplify-subject (subject &optional functions)
+  "Return simplified SUBJECT."
+  (unless functions
+    ;; Simplify fully:
+    (setq functions message-simplify-subject-functions))
+  (when (and (memq 'message-strip-list-identifiers functions)
+            gnus-list-identifiers)
+    (setq subject (message-strip-list-identifiers subject)))
+  (when (memq 'message-strip-subject-re functions)
+    (setq subject (concat "Re: " (message-strip-subject-re subject))))
+  (when (and (memq 'message-strip-subject-trailing-was functions)
+            message-subject-trailing-was-query)
+    (setq subject (message-strip-subject-trailing-was subject)))
+  (when (memq 'message-strip-subject-encoded-words functions)
+    (setq subject (message-strip-subject-encoded-words subject)))
+  subject)
+
+;;;###autoload
+(defun message-reply (&optional to-address wide switch-function)
+  "Start editing a reply to the article in the current buffer."
+  (interactive)
+  (require 'gnus-sum)                  ; for gnus-list-identifiers
+  (let ((cur (current-buffer))
+       from subject date
+       references message-id follow-to
+       (inhibit-point-motion-hooks t)
+       (message-this-is-mail t)
+       gnus-warning)
+    (save-restriction
+      (message-narrow-to-head-1)
+      ;; Allow customizations to have their say.
+      (if (not wide)
+         ;; This is a regular reply.
+         (when (functionp message-reply-to-function)
+           (save-excursion
+             (setq follow-to (funcall message-reply-to-function))))
+       ;; This is a followup.
+       (when (functionp message-wide-reply-to-function)
+         (save-excursion
+           (setq follow-to
+                 (funcall message-wide-reply-to-function)))))
+      (setq message-id (message-fetch-field "message-id" t)
+           references (message-fetch-field "references")
+           date (message-fetch-field "date")
+           from (or (message-fetch-field "from") "nobody")
+           subject (or (message-fetch-field "subject") "none"))
+
+      ;; Strip list identifiers, "Re: ", and "was:"
+      (setq subject (message-simplify-subject subject))
+
+      (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))))
+
+    (let ((headers
+          `((Subject . ,subject)
+            ,@follow-to)))
+      (unless (message-mail-user-agent)
+       (message-pop-to-buffer
+        (message-buffer-name
+         (if wide "wide reply" "reply") from
+         (if wide to-address nil))
+        switch-function))
+      (setq message-reply-headers
+           (vector 0 (cdr (assq 'Subject headers))
+                   from date message-id references 0 0 ""))
+      (message-setup headers cur))))
+
+;;;###autoload
+(defun message-wide-reply (&optional to-address)
+  "Make a \"wide\" reply to the message in the current buffer."
+  (interactive)
+  (message-reply to-address t))
+
+;;;###autoload
+(defun message-followup (&optional to-newsgroups)
+  "Follow up to the message in the current buffer.
+If TO-NEWSGROUPS, use that as the new Newsgroups line."
+  (interactive)
+  (require 'gnus-sum)                  ; for gnus-list-identifiers
+  (let ((cur (current-buffer))
+       from subject date reply-to mrt mct
+       references message-id follow-to
+       (inhibit-point-motion-hooks t)
+       (message-this-is-news t)
+       followup-to distribution newsgroups gnus-warning posted-to)
+    (save-restriction
+      (narrow-to-region
+       (goto-char (point-min))
+       (if (search-forward "\n\n" nil t)
+          (1- (point))
+        (point-max)))
+      (when (functionp message-followup-to-function)
+       (setq follow-to
+             (funcall message-followup-to-function)))
+      (setq from (message-fetch-field "from")
+           date (message-fetch-field "date")
+           subject (or (message-fetch-field "subject") "none")
+           references (message-fetch-field "references")
+           message-id (message-fetch-field "message-id" t)
+           followup-to (message-fetch-field "followup-to")
+           newsgroups (message-fetch-field "newsgroups")
+           posted-to (message-fetch-field "posted-to")
+           reply-to (message-fetch-field "reply-to")
+           mrt (message-fetch-field "mail-reply-to")
+           distribution (message-fetch-field "distribution")
+           mct (message-fetch-field "mail-copies-to"))
+      (when (and (setq gnus-warning (message-fetch-field "gnus-warning"))
+                (string-match "<[^>]+>" gnus-warning))
+       (setq message-id (match-string 0 gnus-warning)))
+      ;; Remove bogus distribution.
+      (when (and (stringp distribution)
+                (let ((case-fold-search t))
+                  (string-match "world" distribution)))
+       (setq distribution nil))
+      ;; Strip list identifiers, "Re: ", and "was:"
+      (setq subject (message-simplify-subject subject))
+      (widen))
+
+    (message-pop-to-buffer (message-buffer-name "followup" from newsgroups))
+
+    (setq message-reply-headers
+         (vector 0 subject from date message-id references 0 0 ""))
+
+    (message-setup
+     `((Subject . ,subject)
+       ,@(cond
+         (to-newsgroups
+          (list (cons 'Newsgroups to-newsgroups)))
+         (follow-to follow-to)
+         ((and followup-to message-use-followup-to)
+          (list
+           (cond
+            ((equal (downcase followup-to) "poster")
+             (if (or (eq message-use-followup-to 'use)
+                     (message-y-or-n-p "Obey Followup-To: poster? " t "\
+You should normally obey the Followup-To: header.
+
+`Followup-To: poster' sends your response via e-mail instead of news.
+
+A typical situation where `Followup-To: poster' is used is when the poster
+does not read the newsgroup, so he wouldn't see any replies sent to it.
+
+You may customize the variable `message-use-followup-to', if you
+want to get rid of this query permanently."))
+                 (progn
+                   (setq message-this-is-news nil)
+                   (cons 'To (or mrt reply-to from "")))
+               (cons 'Newsgroups newsgroups)))
+            (t
+             (if (or (equal followup-to newsgroups)
+                     (not (eq message-use-followup-to 'ask))
+                     (message-y-or-n-p
+                      (concat "Obey Followup-To: " followup-to "? ") t "\
+You should normally obey the Followup-To: header.
+
+       `Followup-To: " followup-to "'
+directs your response to " (if (string-match "," followup-to)
+                              "the specified newsgroups"
+                            "that newsgroup only") ".
+
+If a message is posted to several newsgroups, Followup-To is often
+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 intended for discussion;
+responses here are directed to other newsgroups.
+
+You may customize the variable `message-use-followup-to', if you
+want to get rid of this query permanently."))
+                 (cons 'Newsgroups followup-to)
+               (cons 'Newsgroups newsgroups))))))
+         (posted-to
+          `((Newsgroups . ,posted-to)))
+         (t
+          `((Newsgroups . ,newsgroups))))
+       ,@(and distribution (list (cons 'Distribution distribution)))
+       ,@(when (and mct
+                   (not (or (equal (downcase mct) "never")
+                            (equal (downcase mct) "nobody"))))
+          (list (cons 'Cc (if (or (equal (downcase mct) "always")
+                                  (equal (downcase mct) "poster"))
+                              (or mrt reply-to from "")
+                            mct)))))
+
+     cur)))
+
+(defun message-is-yours-p ()
+  "Non-nil means current article is yours.
+If you have added `cancel-messages' to `message-shoot-gnksa-feet', all articles
+are yours except those that have Cancel-Lock header not belonging to you.
+Instead of shooting GNKSA feet, you should modify `message-alternative-emails'
+regexp to match all of yours addresses."
+  ;; Canlock-logic as suggested by Per Abrahamsen
+  ;; <abraham@dina.kvl.dk>
+  ;;
+  ;; IF article has cancel-lock THEN
+  ;;   IF we can verify it THEN
+  ;;     issue cancel
+  ;;   ELSE
+  ;;     error: cancellock: article is not yours
+  ;; ELSE
+  ;;   Use old rules, comparing sender...
+  (save-excursion
+    (save-restriction
+      (message-narrow-to-head-1)
+      (if (and (message-fetch-field "Cancel-Lock")
+              (message-gnksa-enable-p 'canlock-verify))
+         (if (null (canlock-verify))
+             t
+           (error "Failed to verify Cancel-lock: This article is not yours"))
+       (let (sender from)
+         (or
+          (message-gnksa-enable-p 'cancel-messages)
+          (and (setq sender (message-fetch-field "sender"))
+               (string-equal (downcase sender)
+                             (downcase (message-make-sender))))
+          ;; Email address in From field equals to our address
+          (and (setq from (message-fetch-field "from"))
+               (string-equal
+                (downcase (car (mail-header-parse-address from)))
+                (downcase (car (mail-header-parse-address
+                                (message-make-from))))))
+          ;; Email address in From field matches
+          ;; 'message-alternative-emails' regexp
+          (and from
+               message-alternative-emails
+               (string-match
+                message-alternative-emails
+                (car (mail-header-parse-address from))))))))))
+
+;;;###autoload
+(defun message-cancel-news (&optional arg)
+  "Cancel an article you posted.
+If ARG, allow editing of the cancellation message."
+  (interactive "P")
+  (unless (message-news-p)
+    (error "This is not a news article; canceling is impossible"))
+  (let (from newsgroups message-id distribution buf)
+    (save-excursion
+      ;; Get header info from original article.
+      (save-restriction
+       (message-narrow-to-head-1)
+       (setq from (message-fetch-field "from")
+             newsgroups (message-fetch-field "newsgroups")
+             message-id (message-fetch-field "message-id" t)
+             distribution (message-fetch-field "distribution")))
+      ;; Make sure that this article was written by the user.
+      (unless (message-is-yours-p)
+       (error "This article is not yours"))
+      (when (yes-or-no-p "Do you really want to cancel this article? ")
+       ;; Make control message.
+       (if arg
+           (message-news)
+         (setq buf (set-buffer (get-buffer-create " *message cancel*"))))
+       (erase-buffer)
+       (insert "Newsgroups: " newsgroups "\n"
+               "From: " from "\n"
+               "Subject: cancel " message-id "\n"
+               "Control: cancel " message-id "\n"
+               (if distribution
+                   (concat "Distribution: " distribution "\n")
+                 "")
+               mail-header-separator "\n"
+               message-cancel-message)
+       (run-hooks 'message-cancel-hook)
+       (unless arg
+         (message "Canceling your article...")
+         (if (let ((message-syntax-checks
+                    'dont-check-for-anything-just-trust-me))
+               (funcall message-send-news-function))
+             (message "Canceling your article...done"))
+         (kill-buffer buf))))))
+
+;;;###autoload
+(defun message-supersede ()
+  "Start composing a message to supersede the current message.
+This is done simply by taking the old article and adding a Supersedes
+header line with the old Message-ID."
+  (interactive)
+  (let ((cur (current-buffer)))
+    ;; Check whether the user owns the article that is to be superseded.
+    (unless (message-is-yours-p)
+      (error "This article is not yours"))
+    ;; Get a normal message buffer.
+    (message-pop-to-buffer (message-buffer-name "supersede"))
+    (insert-buffer-substring cur)
+    (mime-to-mml)
+    (message-narrow-to-head-1)
+    ;; Remove unwanted headers.
+    (when message-ignored-supersedes-headers
+      (message-remove-header message-ignored-supersedes-headers t))
+    (goto-char (point-min))
+    (if (not (re-search-forward "^Message-ID: " nil t))
+       (error "No Message-ID in this article")
+      (replace-match "Supersedes: " t t))
+    (goto-char (point-max))
+    (insert mail-header-separator)
+    (widen)
+    (forward-line 1)))
+
+;;;###autoload
+(defun message-recover ()
+  "Reread contents of current buffer from its last auto-save file."
+  (interactive)
+  (let ((file-name (make-auto-save-file-name)))
+    (cond ((save-window-excursion
+            (with-output-to-temp-buffer "*Directory*"
+              (with-current-buffer standard-output
+                (fundamental-mode))    ; for Emacs 20.4+
+              (buffer-disable-undo standard-output)
+              (let ((default-directory "/"))
+                (call-process
+                 "ls" nil standard-output nil "-l" file-name)))
+            (yes-or-no-p (format "Recover auto save file %s? " file-name)))
+          (let ((buffer-read-only nil))
+            (erase-buffer)
+            (insert-file-contents file-name nil)))
+         (t (error "message-recover canceled")))))
+
+;;; Washing Subject:
+
+(defun message-wash-subject (subject)
+  "Remove junk like \"Re:\", \"(fwd)\", etc. added to subject string SUBJECT.
+Previous forwarders, repliers, etc. may add it."
+  (with-temp-buffer
+    (insert subject)
+    (goto-char (point-min))
+    ;; strip Re/Fwd stuff off the beginning
+    (while (re-search-forward
+           "\\([Rr][Ee]:\\|[Ff][Ww][Dd]\\(\\[[0-9]*\\]\\)?:\\|[Ff][Ww]:\\)" nil t)
+      (replace-match ""))
+
+    ;; and gnus-style forwards [foo@bar.com] subject
+    (goto-char (point-min))
+    (while (re-search-forward "\\[[^ \t]*\\(@\\|\\.\\)[^ \t]*\\]" nil t)
+      (replace-match ""))
+
+    ;; and off the end
+    (goto-char (point-max))
+    (while (re-search-backward "([Ff][Ww][Dd])" nil t)
+      (replace-match ""))
+
+    ;; and finally, any whitespace that was left-over
+    (goto-char (point-min))
+    (while (re-search-forward "^[ \t]+" nil t)
+      (replace-match ""))
+    (goto-char (point-max))
+    (while (re-search-backward "[ \t]+$" nil t)
+      (replace-match ""))
+
+    (buffer-string)))
+
+;;; Forwarding messages.
+
+(defvar message-forward-decoded-p nil
+  "Non-nil means the original message is decoded.")
+
+(defun message-forward-subject-name-subject (subject)
+  "Generate a SUBJECT for a forwarded message.
+The form is: [Source] Subject, where if the original message was mail,
+Source is the name of the sender, and if the original message was
+news, Source is the list of newsgroups is was posted to."
+  (let* ((group (message-fetch-field "newsgroups"))
+        (from (message-fetch-field "from"))
+        (prefix
+         (if group
+             (gnus-group-decoded-name group)
+           (or (and from (or
+                          (car (gnus-extract-address-components from))
+                          (cadr (gnus-extract-address-components from))))
+               "(nowhere)"))))
+    (concat "["
+           (if message-forward-decoded-p
+               prefix
+             (mail-decode-encoded-word-string prefix))
+           "] " subject)))
+
+(defun message-forward-subject-author-subject (subject)
+  "Generate a SUBJECT for a forwarded message.
+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."
+  (let* ((group (message-fetch-field "newsgroups"))
+        (prefix
+         (if group
+             (gnus-group-decoded-name group)
+           (or (message-fetch-field "from")
+               "(nowhere)"))))
+    (concat "["
+           (if message-forward-decoded-p
+               prefix
+             (mail-decode-encoded-word-string prefix))
+           "] " subject)))
+
+(defun message-forward-subject-fwd (subject)
+  "Generate a SUBJECT for a forwarded message.
+The form is: Fwd: Subject, where Subject is the original subject of
+the message."
+  (if (string-match "^Fwd: " subject)
+      subject
+    (concat "Fwd: " subject)))
+
+(defun message-make-forward-subject ()
+  "Return a Subject header suitable for the message in the current buffer."
+  (save-excursion
+    (save-restriction
+      (message-narrow-to-head-1)
+      (let ((funcs message-make-forward-subject-function)
+           (subject (message-fetch-field "Subject")))
+       (setq subject
+             (if subject
+                 (if message-forward-decoded-p
+                     subject
+                   (mail-decode-encoded-word-string subject))
+               ""))
+       (when message-wash-forwarded-subjects
+         (setq subject (message-wash-subject subject)))
+       ;; Make sure funcs is a list.
+       (and funcs
+            (not (listp funcs))
+            (setq funcs (list funcs)))
+       ;; Apply funcs in order, passing subject generated by previous
+       ;; func to the next one.
+       (dolist (func funcs)
+         (when (functionp func)
+           (setq subject (funcall func subject))))
+       subject))))
+
+(defvar gnus-article-decoded-p)
+
+
+;;;###autoload
+(defun message-forward (&optional news digest)
+  "Forward the current message via mail.
+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
+         (if (local-variable-p 'gnus-article-decoded-p (current-buffer))
+             gnus-article-decoded-p ;; In an article buffer.
+           message-forward-decoded-p))
+        (subject (message-make-forward-subject)))
+    (if news
+       (message-news nil subject)
+      (message-mail nil subject))
+    (message-forward-make-body cur digest)))
+
+(defun message-forward-make-body-plain (forward-buffer)
+  (insert
+   "\n-------------------- Start of forwarded message --------------------\n")
+  (let ((b (point))
+       (contents (with-current-buffer forward-buffer (buffer-string)))
+       e)
+    (unless (featurep 'xemacs)
+      (unless (mm-multibyte-string-p contents)
+       (error "Attempt to insert unibyte string from the buffer \"%s\"\
+ to the multibyte buffer \"%s\""
+              (if (bufferp forward-buffer)
+                  (buffer-name forward-buffer)
+                forward-buffer)
+              (buffer-name))))
+    (insert (mm-with-multibyte-buffer
+             (insert contents)
+             (mime-to-mml)
+             (goto-char (point-min))
+             (when (looking-at "From ")
+               (replace-match "X-From-Line: "))
+             (buffer-string)))
+    (unless (bolp) (insert "\n"))
+    (setq e (point))
+    (insert
+     "-------------------- End of forwarded message --------------------\n")
+    (message-remove-ignored-headers b e)))
+
+(defun message-remove-ignored-headers (b e)
+  (when (or message-forward-ignored-headers
+           message-forward-included-headers)
+    (save-restriction
+      (narrow-to-region b e)
+      (goto-char b)
+      (narrow-to-region (point)
+                       (or (search-forward "\n\n" nil t) (point)))
+      (when message-forward-ignored-headers
+       (let ((ignored (if (stringp message-forward-ignored-headers)
+                          (list message-forward-ignored-headers)
+                        message-forward-ignored-headers)))
+         (dolist (elem ignored)
+           (message-remove-header elem t))))
+      (when message-forward-included-headers
+       (message-remove-header
+        (if (listp message-forward-included-headers)
+            (regexp-opt message-forward-included-headers)
+          message-forward-included-headers)
+        t nil t)))))
+
+(defun message-forward-make-body-mime (forward-buffer &optional beg end)
+  (let ((b (point)))
+    (insert "\n\n<#part type=message/rfc822 disposition=inline raw=t>\n")
+    (save-restriction
+      (narrow-to-region (point) (point))
+      (insert-buffer-substring forward-buffer beg end)
+      (mml-quote-region (point-min) (point-max))
+      (goto-char (point-min))
+      (when (looking-at "From ")
+       (replace-match "X-From-Line: "))
+      (goto-char (point-max)))
+    (insert "<#/part>\n")
+    ;; Consider there is no illegible text.
+    (add-text-properties
+     b (point)
+     `(no-illegible-text t rear-nonsticky t start-open t))))
+
+(defun message-forward-make-body-mml (forward-buffer)
+  (insert "\n\n<#mml type=message/rfc822 disposition=inline>\n")
+  (let ((b (point)) e)
+    (if (not message-forward-decoded-p)
+       (let ((contents (with-current-buffer forward-buffer (buffer-string))))
+         (unless (featurep 'xemacs)
+           (unless (mm-multibyte-string-p contents)
+             (error "Attempt to insert unibyte string from the buffer \"%s\"\
+ to the multibyte buffer \"%s\""
+                    (if (bufferp forward-buffer)
+                        (buffer-name forward-buffer)
+                      forward-buffer)
+                    (buffer-name))))
+         (insert (mm-with-multibyte-buffer
+                   (insert contents)
+                   (mime-to-mml)
+                   (goto-char (point-min))
+                   (when (looking-at "From ")
+                     (replace-match "X-From-Line: "))
+                   (buffer-string))))
+      (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))
+    (insert "<#/mml>\n")
+    (when (not message-forward-decoded-p)
+      (message-remove-ignored-headers b e))))
+
+(defun message-forward-make-body-digest-plain (forward-buffer)
+  (insert
+   "\n-------------------- Start of forwarded message --------------------\n")
+  (mml-insert-buffer forward-buffer)
+  (insert
+   "\n-------------------- End of forwarded message --------------------\n"))
+
+(defun message-forward-make-body-digest-mime (forward-buffer)
+  (insert "\n<#multipart type=digest>\n")
+  (let ((b (point)) e)
+    (insert-buffer-substring forward-buffer)
+    (setq e (point))
+    (insert "<#/multipart>\n")
+    (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)))))
+
+(defun message-forward-make-body-digest (forward-buffer)
+  (if message-forward-as-mime
+      (message-forward-make-body-digest-mime forward-buffer)
+    (message-forward-make-body-digest-plain forward-buffer)))
+
+(autoload 'mm-uu-dissect-text-parts "mm-uu")
+(autoload 'mm-uu-dissect "mm-uu")
+
+(defun message-signed-or-encrypted-p (&optional dont-emulate-mime handles)
+  "Say whether the current buffer contains signed or encrypted message.
+If DONT-EMULATE-MIME is nil, this function does the MIME emulation on
+messages that don't conform to PGP/MIME described in RFC2015.  HANDLES
+is for the internal use."
+  (unless handles
+    (let ((mm-decrypt-option 'never)
+         (mm-verify-option 'never))
+      (if (setq handles (mm-dissect-buffer nil t))
+         (unless dont-emulate-mime
+           (mm-uu-dissect-text-parts handles))
+       (unless dont-emulate-mime
+         (setq handles (mm-uu-dissect))))))
+  ;; Check text/plain message in which there is a signed or encrypted
+  ;; body that has been encoded by B or Q.
+  (unless (or handles dont-emulate-mime)
+    (let ((cur (current-buffer))
+         (mm-decrypt-option 'never)
+         (mm-verify-option 'never))
+      (with-temp-buffer
+       (insert-buffer-substring cur)
+       (when (setq handles (mm-dissect-buffer t t))
+         (if (and (bufferp (car handles))
+                  (equal (mm-handle-media-type handles) "text/plain"))
+             (progn
+               (erase-buffer)
+               (insert-buffer-substring (car handles))
+               (mm-decode-content-transfer-encoding
+                (mm-handle-encoding handles))
+               (mm-destroy-parts handles)
+               (setq handles (mm-uu-dissect)))
+           (mm-destroy-parts handles)
+           (setq handles nil))))))
+  (when handles
+    (prog1
+       (catch 'found
+         (dolist (handle (if (stringp (car handles))
+                             (if (member (car handles)
+                                         '("multipart/signed"
+                                           "multipart/encrypted"))
+                                 (throw 'found t)
+                               (cdr handles))
+                           (list handles)))
+           (if (stringp (car handle))
+               (when (message-signed-or-encrypted-p dont-emulate-mime handle)
+                 (throw 'found t))
+             (when (and (bufferp (car handle))
+                        (equal (mm-handle-media-type handle)
+                               "message/rfc822"))
+               (with-current-buffer (mm-handle-buffer handle)
+                 (when (message-signed-or-encrypted-p dont-emulate-mime)
+                   (throw 'found t)))))))
+      (mm-destroy-parts handles))))
+
+;;;###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 digest
+      (message-forward-make-body-digest forward-buffer)
+    (if message-forward-as-mime
+       (if (and message-forward-show-mml
+                (not (and (eq message-forward-show-mml 'best)
+                          ;; Use the raw form in the body if it contains
+                          ;; signed or encrypted message so as not to be
+                          ;; destroyed by re-encoding.
+                          (with-current-buffer forward-buffer
+                            (condition-case nil
+                                (message-signed-or-encrypted-p)
+                              (error t))))))
+           (message-forward-make-body-mml forward-buffer)
+         (message-forward-make-body-mime forward-buffer))
+      (message-forward-make-body-plain forward-buffer)))
+  (message-position-point))
+
+(declare-function rmail-toggle-header "rmail" (&optional arg))
+
+;;;###autoload
+(defun message-forward-rmail-make-body (forward-buffer)
+  (save-window-excursion
+    (set-buffer forward-buffer)
+    (if (rmail-msg-is-pruned)
+       (if (fboundp 'rmail-msg-restore-non-pruned-header)
+           (rmail-msg-restore-non-pruned-header) ; Emacs 22
+         (rmail-toggle-header 0))))              ; Emacs 23
+  (message-forward-make-body forward-buffer))
+
+;; Fixme: Should have defcustom.
+;;;###autoload
+(defun message-insinuate-rmail ()
+  "Let RMAIL use message to forward."
+  (interactive)
+  (setq rmail-enable-mime-composing t)
+  (setq rmail-insert-mime-forwarded-message-function
+       'message-forward-rmail-make-body))
+
+(defvar message-inhibit-body-encoding nil)
+
+;;;###autoload
+(defun message-resend (address)
+  "Resend the current article to ADDRESS."
+  (interactive
+   (list (message-read-from-minibuffer "Resend message to: ")))
+  (message "Resending message to %s..." address)
+  (save-excursion
+    (let ((cur (current-buffer))
+         gcc beg)
+      ;; We first set up a normal mail buffer.
+      (unless (message-mail-user-agent)
+       (set-buffer (get-buffer-create " *message resend*"))
+       (let ((inhibit-read-only t))
+         (erase-buffer)))
+      (let ((message-this-is-mail t)
+           message-generate-hashcash
+           message-setup-hook)
+       (message-setup `((To . ,address))))
+      ;; Insert our usual headers.
+      (message-generate-headers '(From Date To Message-ID))
+      (message-narrow-to-headers)
+      (when (setq gcc (mail-fetch-field "gcc" nil t))
+       (message-remove-header "gcc"))
+      ;; Remove X-Draft-From header etc.
+      (message-remove-header message-ignored-mail-headers t)
+      ;; Rename them all to "Resent-*".
+      (goto-char (point-min))
+      (while (re-search-forward "^[A-Za-z]" nil t)
+       (forward-char -1)
+       (insert "Resent-"))
+      (widen)
+      (forward-line)
+      (let ((inhibit-read-only t))
+       (delete-region (point) (point-max)))
+      (setq beg (point))
+      ;; Insert the message to be resent.
+      (insert-buffer-substring cur)
+      (goto-char (point-min))
+      (search-forward "\n\n")
+      (forward-char -1)
+      (save-restriction
+       (narrow-to-region beg (point))
+       (message-remove-header message-ignored-resent-headers t)
+       (goto-char (point-max)))
+      (insert mail-header-separator)
+      ;; Rename all old ("Also-")Resent headers.
+      (while (re-search-backward "^\\(Also-\\)*Resent-" beg t)
+       (beginning-of-line)
+       (insert "Also-"))
+      ;; Quote any "From " lines at the beginning.
+      (goto-char beg)
+      (when (looking-at "From ")
+       (replace-match "X-From-Line: "))
+      ;; Send it.
+      (let ((message-inhibit-body-encoding
+            ;; Don't do any further encoding if it looks like the
+            ;; message has already been encoded.
+            (let ((case-fold-search t))
+              (re-search-forward "^mime-version:" nil t)))
+           (message-inhibit-ecomplete t)
+           message-required-mail-headers
+           message-generate-hashcash
+           rfc2047-encode-encoded-words)
+       (message-send-mail))
+      (when gcc
+       (message-goto-eoh)
+       (insert "Gcc: " gcc "\n"))
+      (run-hooks 'message-sent-hook)
+      (kill-buffer (current-buffer)))
+    (message "Resending message to %s...done" address)))
+
+;;;###autoload
+(defun message-bounce ()
+  "Re-mail the current message.
+This only makes sense if the current message is a bounce message that
+contains some mail you have written which has been bounced back to
+you."
+  (interactive)
+  (let ((handles (mm-dissect-buffer t))
+       boundary)
+    (message-pop-to-buffer (message-buffer-name "bounce"))
+    (if (stringp (car handles))
+       ;; This is a MIME bounce.
+       (mm-insert-part (car (last handles)))
+      ;; This is a non-MIME bounce, so we try to remove things
+      ;; manually.
+      (mm-insert-part handles)
+      (undo-boundary)
+      (goto-char (point-min))
+      (re-search-forward "\n\n+" nil t)
+      (setq boundary (point))
+      ;; We remove everything before the bounced mail.
+      (if (or (re-search-forward message-unsent-separator nil t)
+             (progn
+               (search-forward "\n\n" nil 'move)
+               (re-search-backward "^Return-Path:.*\n" boundary t)))
+         (progn
+           (forward-line 1)
+           (delete-region (point-min)
+                          (if (re-search-forward "^[^ \n\t]+:" nil t)
+                              (match-beginning 0)
+                            (point))))
+       (goto-char boundary)
+       (when (re-search-backward "^.?From .*\n" nil t)
+         (delete-region (match-beginning 0) (match-end 0)))))
+    (mime-to-mml)
+    (save-restriction
+      (message-narrow-to-head-1)
+      (message-remove-header message-ignored-bounced-headers t)
+      (goto-char (point-max))
+      (insert mail-header-separator))
+    (message-position-point)))
+
+;;;
+;;; Interactive entry points for new message buffers.
+;;;
+
+;;;###autoload
+(defun message-mail-other-window (&optional to subject)
+  "Like `message-mail' command, but display mail buffer in another window."
+  (interactive)
+  (unless (message-mail-user-agent)
+    (message-pop-to-buffer (message-buffer-name "mail" to)
+                          'switch-to-buffer-other-window))
+  (let ((message-this-is-mail t))
+    (message-setup `((To . ,(or to "")) (Subject . ,(or subject "")))
+                  nil nil nil 'switch-to-buffer-other-window)))
+
+;;;###autoload
+(defun message-mail-other-frame (&optional to subject)
+  "Like `message-mail' command, but display mail buffer in another frame."
+  (interactive)
+  (unless (message-mail-user-agent)
+    (message-pop-to-buffer (message-buffer-name "mail" to)
+                          'switch-to-buffer-other-frame))
+  (let ((message-this-is-mail t))
+    (message-setup `((To . ,(or to "")) (Subject . ,(or subject "")))
+                  nil nil nil 'switch-to-buffer-other-frame)))
+
+;;;###autoload
+(defun message-news-other-window (&optional newsgroups subject)
+  "Start editing a news article to be sent."
+  (interactive)
+  (message-pop-to-buffer (message-buffer-name "posting" nil newsgroups)
+                        'switch-to-buffer-other-window)
+  (let ((message-this-is-news t))
+    (message-setup `((Newsgroups . ,(or newsgroups ""))
+                    (Subject . ,(or subject ""))))))
+
+;;;###autoload
+(defun message-news-other-frame (&optional newsgroups subject)
+  "Start editing a news article to be sent."
+  (interactive)
+  (message-pop-to-buffer (message-buffer-name "posting" nil newsgroups)
+                        'switch-to-buffer-other-frame)
+  (let ((message-this-is-news t))
+    (message-setup `((Newsgroups . ,(or newsgroups ""))
+                    (Subject . ,(or subject ""))))))
+
+;;; underline.el
+
+;; This code should be moved to underline.el (from which it is stolen).
+
+;;;###autoload
+(defun message-bold-region (start end)
+  "Bold all nonblank characters in the region.
+Works by overstriking characters.
+Called from program, takes two arguments START and END
+which specify the range to operate on."
+  (interactive "r")
+  (save-excursion
+    (let ((end1 (make-marker)))
+      (move-marker end1 (max start end))
+      (goto-char (min start end))
+      (while (< (point) end1)
+       (or (looking-at "[_\^@- ]")
+           (insert (char-after) "\b"))
+       (forward-char 1)))))
+
+;;;###autoload
+(defun message-unbold-region (start end)
+  "Remove all boldness (overstruck characters) in the region.
+Called from program, takes two arguments START and END
+which specify the range to operate on."
+  (interactive "r")
+  (save-excursion
+    (let ((end1 (make-marker)))
+      (move-marker end1 (max start end))
+      (goto-char (min start end))
+      (while (search-forward "\b" end1 t)
+       (if (eq (char-after) (char-after (- (point) 2)))
+           (delete-char -2))))))
+
+(defun message-exchange-point-and-mark ()
+  "Exchange point and mark, but don't activate region if it was inactive."
+  (goto-char (prog1 (mark t)
+              (set-marker (mark-marker) (point)))))
+
+;; Support for toolbar
+(defvar tool-bar-mode)
+
+;; Note: The :set function in the `message-tool-bar*' variables will only
+;; affect _new_ message buffers.  We might add a function that walks thru all
+;; message-mode buffers and force the update.
+(defun message-tool-bar-update (&optional symbol value)
+  "Update message mode toolbar.
+Setter function for custom variables."
+  (setq-default message-tool-bar-map nil)
+  (when symbol
+    ;; When used as ":set" function:
+    (set-default symbol value)))
+
+(defcustom message-tool-bar (if (eq gmm-tool-bar-style 'gnome)
+                               'message-tool-bar-gnome
+                             'message-tool-bar-retro)
+  "Specifies the message mode tool bar.
+
+It can be either a list or a symbol referring to a list.  See
+`gmm-tool-bar-from-list' for the format of the list.  The
+default key map is `message-mode-map'.
+
+Pre-defined symbols include `message-tool-bar-gnome' and
+`message-tool-bar-retro'."
+  :type '(repeat gmm-tool-bar-list-item)
+  :type '(choice (const :tag "GNOME style" message-tool-bar-gnome)
+                (const :tag "Retro look"  message-tool-bar-retro)
+                (repeat :tag "User defined list" gmm-tool-bar-item)
+                (symbol))
+  :version "23.1" ;; No Gnus
+  :initialize 'custom-initialize-default
+  :set 'message-tool-bar-update
+  :group 'message)
+
+(defcustom message-tool-bar-gnome
+  '((ispell-message "spell" nil
+                   :vert-only t
+                   :visible (or (not (boundp 'flyspell-mode))
+                                (not flyspell-mode)))
+    (flyspell-buffer "spell" t
+                    :vert-only t
+                    :visible (and (boundp 'flyspell-mode)
+                                  flyspell-mode)
+                    :help "Flyspell whole buffer")
+    (message-send-and-exit "mail/send" t :label "Send")
+    (message-dont-send "mail/save-draft")
+    (mml-attach-file "attach" mml-mode-map :vert-only t)
+    (mml-preview "mail/preview" mml-mode-map)
+    (mml-secure-message-sign-encrypt "lock" mml-mode-map :visible nil)
+    (message-insert-importance-high "important" nil :visible nil)
+    (message-insert-importance-low "unimportant" nil :visible nil)
+    (message-insert-disposition-notification-to "receipt" nil :visible nil))
+  "List of items for the message tool bar (GNOME style).
+
+See `gmm-tool-bar-from-list' for details on the format of the list."
+  :type '(repeat gmm-tool-bar-item)
+  :version "23.1" ;; No Gnus
+  :initialize 'custom-initialize-default
+  :set 'message-tool-bar-update
+  :group 'message)
+
+(defcustom message-tool-bar-retro
+  '(;; Old Emacs 21 icon for consistency.
+    (message-send-and-exit "gnus/mail-send")
+    (message-kill-buffer "close")
+    (message-dont-send "cancel")
+    (mml-attach-file "attach" mml-mode-map)
+    (ispell-message "spell")
+    (mml-preview "preview" mml-mode-map)
+    (message-insert-importance-high "gnus/important")
+    (message-insert-importance-low "gnus/unimportant")
+    (message-insert-disposition-notification-to "gnus/receipt"))
+  "List of items for the message tool bar (retro style).
+
+See `gmm-tool-bar-from-list' for details on the format of the list."
+  :type '(repeat gmm-tool-bar-item)
+  :version "23.1" ;; No Gnus
+  :initialize 'custom-initialize-default
+  :set 'message-tool-bar-update
+  :group 'message)
+
+(defcustom message-tool-bar-zap-list
+  '(new-file open-file dired kill-buffer write-file
+            print-buffer customize help)
+  "List of icon items from the global tool bar.
+These items are not displayed on the message mode tool bar.
+
+See `gmm-tool-bar-from-list' for the format of the list."
+  :type 'gmm-tool-bar-zap-list
+  :version "23.1" ;; No Gnus
+  :initialize 'custom-initialize-default
+  :set 'message-tool-bar-update
+  :group 'message)
+
+(defvar image-load-path)
+
+(defun message-make-tool-bar (&optional force)
+  "Make a message mode tool bar from `message-tool-bar-list'.
+When FORCE, rebuild the tool bar."
+  (when (and (not (featurep 'xemacs))
+            (boundp 'tool-bar-mode)
+            tool-bar-mode
+            (or (not message-tool-bar-map) force))
+    (setq message-tool-bar-map
+         (let* ((load-path
+                 (gmm-image-load-path-for-library "message"
+                                                  "mail/save-draft.xpm"
+                                                  nil t))
+                (image-load-path (cons (car load-path)
+                                       (when (boundp 'image-load-path)
+                                         image-load-path))))
+           (gmm-tool-bar-from-list message-tool-bar
+                                   message-tool-bar-zap-list
+                                   'message-mode-map))))
+  message-tool-bar-map)
+
+;;; Group name completion.
+
+(defcustom message-newgroups-header-regexp
+  "^\\(Newsgroups\\|Followup-To\\|Posted-To\\|Gcc\\):"
+  "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)
+       '("^\\(Reply-To\\|From\\|Mail-Followup-To\\|Mail-Copies-To\\):"
+         . message-expand-name)
+       '("^\\(Disposition-Notification-To\\|Return-Receipt-To\\):"
+         . message-expand-name))
+  "Alist of (RE . FUN).  Use FUN for completion on header lines matching RE."
+  :version "22.1"
+  :group 'message
+  :type '(alist :key-type regexp :value-type function))
+
+(defcustom message-expand-name-databases
+  '(bbdb eudc)
+  "List of databases to try for name completion (`message-expand-name').
+Each element is a symbol and can be `bbdb' or `eudc'."
+  :group 'message
+  :type '(set (const bbdb) (const eudc)))
+
+(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."
+  :version "22.1"
+  :group 'message
+  :link '(custom-manual "(message)Various Commands")
+  :type '(choice (const nil)
+                function))
+
+(declare-function mail-abbrev-in-expansion-header-p "mailabbrev" ())
+
+(defun message-tab ()
+  "Complete names according to `message-completion-alist'.
+Execute function specified by `message-tab-body-function' when
+not in those headers.  If that variable is nil, indent with the
+regular text mode tabbing command."
+  (interactive)
+  (cond
+   ((if (and (boundp 'completion-fail-discreetly)
+             (fboundp 'completion-at-point))
+        (let ((completion-fail-discreetly t)) (completion-at-point))
+      (funcall (or (message-completion-function) #'ignore)))
+    ;; Completion was performed; nothing else to do.
+    nil)
+   (message-tab-body-function (funcall message-tab-body-function))
+   (t (funcall (or (lookup-key text-mode-map "\t")
+                   (lookup-key global-map "\t")
+                   'indent-relative)))))
+
+(defvar mail-abbrev-mode-regexp)
+
+(defun message-completion-function ()
+  (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)))
+    (when (cdar alist)
+      (lexical-let ((fun (cdar alist)))
+        ;; Even if completion fails, return a non-nil value, so as to avoid
+        ;; falling back to message-tab-body-function.
+        (lambda () (funcall fun) 'completion-attempted)))))
+
+(defun message-expand-group ()
+  "Expand the group name under point."
+  (let ((b (save-excursion
+            (save-restriction
+              (narrow-to-region
+               (save-excursion
+                 (beginning-of-line)
+                 (skip-chars-forward "^:")
+                 (1+ (point)))
+               (point))
+              (skip-chars-backward "^, \t\n") (point))))
+       (completion-ignore-case t)
+       (e (progn (skip-chars-forward "^,\t\n ") (point)))
+       group collection)
+    (when (and (boundp 'gnus-active-hashtb)
+              gnus-active-hashtb)
+      (mapatoms
+       (lambda (symbol)
+        (setq group (symbol-name symbol))
+        (push (if (string-match "[^\000-\177]" group)
+                  (gnus-group-decoded-name group)
+                group)
+              collection))
+       gnus-active-hashtb))
+    (message-completion-in-region b e collection)))
+
+(defalias 'message-completion-in-region
+  (if (fboundp 'completion-in-region)
+      'completion-in-region
+    (lambda (b e hashtb)
+      (let* ((string (buffer-substring b e))
+             (completions (all-completions string hashtb))
+             comp)
+        (delete-region b (point))
+        (cond
+         ((= (length completions) 1)
+          (if (string= (car completions) string)
+              (progn
+                (insert string)
+                (message "Only matching group"))
+            (insert (car completions))))
+         ((and (setq comp (try-completion string hashtb))
+               (not (string= comp string)))
+          (insert comp))
+         (t
+          (insert string)
+          (if (not comp)
+              (message "No matching groups")
+            (save-selected-window
+              (pop-to-buffer "*Completions*")
+              (buffer-disable-undo)
+              (let ((buffer-read-only nil))
+                (erase-buffer)
+                (let ((standard-output (current-buffer)))
+                  (display-completion-list (sort completions 'string<)))
+                (setq buffer-read-only nil)
+                (goto-char (point-min))
+                (delete-region (point)
+                               (progn (forward-line 3) (point))))))))))))
+
+(defun message-expand-name ()
+  (cond ((and (memq 'eudc message-expand-name-databases)
+                   (boundp 'eudc-protocol)
+                   eudc-protocol)
+        (eudc-expand-inline))
+       ((and (memq 'bbdb message-expand-name-databases)
+             (fboundp 'bbdb-complete-name))
+         (let ((starttick (buffer-modified-tick)))
+           (or (bbdb-complete-name)
+               ;; Apparently, bbdb-complete-name can return nil even when
+               ;; completion took place.  So let's double check the buffer was
+               ;; not modified.
+               (/= starttick (buffer-modified-tick)))))
+       (t
+        (expand-abbrev))))
+
+;;; Help stuff.
+
+(defun message-talkative-question (ask question show &rest text)
+  "Call FUNCTION with argument QUESTION; optionally display TEXT... args.
+If SHOW is non-nil, the arguments TEXT... are displayed in a temp buffer.
+The following arguments may contain lists of values."
+  (if (and show
+          (setq text (message-flatten-list text)))
+      (save-window-excursion
+        (with-output-to-temp-buffer " *MESSAGE information message*"
+          (with-current-buffer " *MESSAGE information message*"
+           (fundamental-mode)          ; for Emacs 20.4+
+           (mapc 'princ text)
+           (goto-char (point-min))))
+       (funcall ask question))
+    (funcall ask question)))
+
+(defun message-flatten-list (list)
+  "Return a new, flat list that contains all elements of LIST.
+
+\(message-flatten-list \\='(1 (2 3 (4 5 (6))) 7))
+=> (1 2 3 4 5 6 7)"
+  (cond ((consp list)
+        (apply 'append (mapcar 'message-flatten-list list)))
+       (list
+        (list list))))
+
+(defun message-generate-new-buffer-clone-locals (name &optional varstr)
+  "Create and return a buffer with name based on NAME using `generate-new-buffer'.
+Then clone the local variables and values from the old buffer to the
+new one, cloning only the locals having a substring matching the
+regexp VARSTR."
+  (let ((oldbuf (current-buffer)))
+    (with-current-buffer (generate-new-buffer name)
+      (message-clone-locals oldbuf varstr)
+      (current-buffer))))
+
+(defun message-clone-locals (buffer &optional varstr)
+  "Clone the local variables from BUFFER to the current buffer."
+  (let ((locals (with-current-buffer buffer (buffer-local-variables)))
+       (regexp "^gnus\\|^nn\\|^message\\|^sendmail\\|^smtp\\|^user-mail-address"))
+    (mapcar
+     (lambda (local)
+       (when (and (consp local)
+                 (car local)
+                 (string-match regexp (symbol-name (car local)))
+                 (or (null varstr)
+                     (string-match varstr (symbol-name (car local)))))
+        (ignore-errors
+          (set (make-local-variable (car local))
+               (cdr local)))))
+     locals)))
+
+;;;
+;;; MIME functions
+;;;
+
+(defun message-encode-message-body ()
+  (unless message-inhibit-body-encoding
+    (let ((mail-parse-charset (or mail-parse-charset
+                                 message-default-charset))
+         (case-fold-search t)
+         lines content-type-p)
+      (message-goto-body)
+      (save-restriction
+       (narrow-to-region (point) (point-max))
+       (let ((new (mml-generate-mime)))
+         (when new
+           (delete-region (point-min) (point-max))
+           (insert new)
+           (goto-char (point-min))
+           (if (eq (aref new 0) ?\n)
+               (delete-char 1)
+             (search-forward "\n\n")
+             (setq lines (buffer-substring (point-min) (1- (point))))
+             (delete-region (point-min) (point))))))
+      (save-restriction
+       (message-narrow-to-headers-or-head)
+       (message-remove-header "Mime-Version")
+       (goto-char (point-max))
+       (insert "MIME-Version: 1.0\n")
+       (when lines
+         (insert lines))
+       (setq content-type-p
+             (or mml-boundary
+                 (re-search-backward "^Content-Type:" nil t))))
+      (save-restriction
+       (message-narrow-to-headers-or-head)
+       (message-remove-first-header "Content-Type")
+       (message-remove-first-header "Content-Transfer-Encoding"))
+      ;; We always make sure that the message has a Content-Type
+      ;; header.  This is because some broken MTAs and MUAs get
+      ;; awfully confused when confronted with a message with a
+      ;; MIME-Version header and without a Content-Type header.  For
+      ;; instance, Solaris' /usr/bin/mail.
+      (unless content-type-p
+       (goto-char (point-min))
+       ;; 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 &optional initial-contents)
+  "Read from the minibuffer while providing abbrev expansion."
+  (if (fboundp 'mail-abbrevs-setup)
+      (let ((minibuffer-setup-hook 'mail-abbrevs-setup)
+           (minibuffer-local-map message-minibuffer-local-map))
+       (gmm-flet ((mail-abbrev-in-expansion-header-p nil t))
+         (read-from-minibuffer prompt initial-contents)))
+    (let ((minibuffer-setup-hook 'mail-abbrev-minibuffer-setup-hook)
+         (minibuffer-local-map message-minibuffer-local-map))
+      (read-string prompt initial-contents))))
+
+(defun message-use-alternative-email-as-from ()
+  "Set From field of the outgoing message to the first matching
+address in `message-alternative-emails', looking at To, Cc and
+From headers in the original article."
+  (require 'mail-utils)
+  (let* ((fields '("To" "Cc" "From"))
+        (emails
+         (split-string
+          (mail-strip-quoted-names
+           (mapconcat 'message-fetch-reply-field fields ","))
+          "[ \f\t\n\r\v,]+"))
+        email)
+    (while emails
+      (if (string-match message-alternative-emails (car emails))
+         (setq email (car emails)
+               emails nil))
+      (pop emails))
+    (unless (or (not email) (equal email user-mail-address))
+      (message-remove-header "From")
+      (goto-char (point-max))
+      (insert "From: " (let ((user-mail-address email)) (message-make-from))
+             "\n"))))
+
+(defun message-options-get (symbol)
+  (cdr (assq symbol message-options)))
+
+(defun message-options-set (symbol value)
+  (let ((the-cons (assq symbol message-options)))
+    (if the-cons
+       (if value
+           (setcdr the-cons value)
+         (setq message-options (delq the-cons message-options)))
+      (and value
+          (push (cons symbol value) message-options))))
+  value)
+
+(defun message-options-set-recipient ()
+  (save-restriction
+    (message-narrow-to-headers-or-head)
+    (message-options-set 'message-sender
+                        (mail-strip-quoted-names
+                         (message-fetch-field "from")))
+    (message-options-set 'message-recipients
+                        (mail-strip-quoted-names
+                         (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 "")))))))
+
+(defun message-hide-headers ()
+  "Hide headers based on the `message-hidden-headers' variable."
+  (let ((regexps (if (stringp message-hidden-headers)
+                    (list message-hidden-headers)
+                  message-hidden-headers))
+       (inhibit-point-motion-hooks t)
+       (inhibit-modification-hooks t)
+       (end-of-headers (point-min)))
+    (when regexps
+      (save-excursion
+       (save-restriction
+         (message-narrow-to-headers)
+         (goto-char (point-min))
+         (while (not (eobp))
+           (if (not (message-hide-header-p regexps))
+               (message-next-header)
+             (let ((begin (point))
+                   header header-len)
+               (message-next-header)
+               (setq header (buffer-substring begin (point))
+                     header-len (- (point) begin))
+               (delete-region begin (point))
+               (goto-char end-of-headers)
+               (insert header)
+               (setq end-of-headers
+                     (+ end-of-headers header-len))))))))
+    (narrow-to-region end-of-headers (point-max))))
+
+(defun message-hide-header-p (regexps)
+  (let ((result nil)
+       (reverse nil))
+    (when (eq (car regexps) 'not)
+      (setq reverse t)
+      (pop regexps))
+    (dolist (regexp regexps)
+      (setq result (or result (looking-at regexp))))
+    (if reverse
+       (not result)
+      result)))
+
+(declare-function ecomplete-add-item "ecomplete" (type key text))
+(declare-function ecomplete-save "ecomplete" ())
+
+(defun message-put-addresses-in-ecomplete ()
+  (require 'ecomplete)
+  (dolist (header '("to" "cc" "from" "reply-to"))
+    (let ((value (message-field-value header)))
+      (dolist (string (mail-header-parse-addresses value 'raw))
+       (setq string
+             (gnus-replace-in-string
+              (gnus-replace-in-string string "^ +\\| +$" "") "\n" ""))
+       (ecomplete-add-item 'mail (car (mail-header-parse-address string))
+                           string))))
+  (ecomplete-save))
+
+(autoload 'ecomplete-display-matches "ecomplete")
+
+(defun message-display-abbrev (&optional choose)
+  "Display the next possible abbrev for the text before point."
+  (interactive (list t))
+  (when (and (memq (char-after (point-at-bol)) '(?C ?T ?\t ? ))
+            (message-point-in-header-p)
+            (save-excursion
+              (beginning-of-line)
+              (while (and (memq (char-after) '(?\t ? ))
+                          (zerop (forward-line -1))))
+              (looking-at "To:\\|Cc:")))
+    (let* ((end (point))
+          (start (save-excursion
+                   (and (re-search-backward "[\n\t ]" nil t)
+                        (1+ (point)))))
+          (word (when start (buffer-substring start end)))
+          (match (when (and word
+                            (not (zerop (length word))))
+                   (ecomplete-display-matches 'mail word choose))))
+      (when (and choose match)
+       (delete-region start end)
+       (insert match)))))
+
+;; To send pre-formatted letters like the example below, you can use
+;; `message-send-form-letter':
+;; --8<---------------cut here---------------start------------->8---
+;; To: alice@invalid.invalid
+;; Subject: Verification of your contact information
+;; From: Contact verification <admin@foo.invalid>
+;; --text follows this line--
+;; Hi Alice,
+;; please verify that your contact information is still valid:
+;; Alice A, A avenue 11, 1111 A town, Austria
+;; ----------next form letter message follows this line----------
+;; To: bob@invalid.invalid
+;; Subject: Verification of your contact information
+;; From: Contact verification <admin@foo.invalid>
+;; --text follows this line--
+;; Hi Bob,
+;; please verify that your contact information is still valid:
+;; Bob, B street 22, 22222 Be town, Belgium
+;; ----------next form letter message follows this line----------
+;; To: charlie@invalid.invalid
+;; Subject: Verification of your contact information
+;; From: Contact verification <admin@foo.invalid>
+;; --text follows this line--
+;; Hi Charlie,
+;; please verify that your contact information is still valid:
+;; Charlie Chaplin, C plaza 33, 33333 C town, Chile
+;; --8<---------------cut here---------------end--------------->8---
+
+;; FIXME: What is the most common term (circular letter, form letter, serial
+;; letter, standard letter) for such kind of letter?  See also
+;; <http://en.wikipedia.org/wiki/Form_letter>
+
+;; FIXME: Maybe extent message-mode's font-lock support to recognize
+;; `message-form-letter-separator', i.e. highlight each message like a single
+;; message.
+
+(defcustom message-form-letter-separator
+  "\n----------next form letter message follows this line----------\n"
+  "Separator for `message-send-form-letter'."
+  ;; :group 'message-form-letter
+  :group 'message-various
+  :version "23.1" ;; No Gnus
+  :type 'string)
+
+(defcustom message-send-form-letter-delay 1
+  "Delay in seconds when sending a message with `message-send-form-letter'.
+Only used when `message-send-form-letter' is called with non-nil
+argument `force'."
+  ;; :group 'message-form-letter
+  :group 'message-various
+  :version "23.1" ;; No Gnus
+  :type 'integer)
+
+(defun message-send-form-letter (&optional force)
+  "Sent all form letter messages from current buffer.
+Unless FORCE, prompt before sending.
+
+The messages are separated by `message-form-letter-separator'.
+Header and body are separated by `mail-header-separator'."
+  (interactive "P")
+  (let ((sent 0) (skipped 0)
+       start end text
+       buff
+       to done)
+    (goto-char (point-min))
+    (while (not done)
+      (setq start (point)
+           end (if (search-forward message-form-letter-separator nil t)
+                   (- (point) (length message-form-letter-separator) -1)
+                 (setq done t)
+                 (point-max)))
+      (setq text
+           (buffer-substring-no-properties start end))
+      (setq buff (generate-new-buffer "*mail - form letter*"))
+      (with-current-buffer buff
+       (insert text)
+       (message-mode)
+       (setq to (message-fetch-field "To"))
+       (switch-to-buffer buff)
+       (when force
+         (sit-for message-send-form-letter-delay))
+       (if (or force
+                 (y-or-n-p (gnus-format-message "Send message to `%s'? " to)))
+           (progn
+             (setq sent (1+ sent))
+             (message-send-and-exit))
+         (message "Message to `%s' skipped." to)
+         (setq skipped (1+ skipped)))
+       (when (buffer-live-p buff)
+         (kill-buffer buff))))
+    (message "%s message(s) sent, %s skipped." sent skipped)))
+
+(defun message-replace-header (header new-value &optional after force)
+  "Remove HEADER and insert the NEW-VALUE.
+If AFTER, insert after this header.  If FORCE, insert new field
+even if NEW-VALUE is empty."
+  ;; Similar to `nnheader-replace-header' but for message buffers.
+  (save-excursion
+    (save-restriction
+      (message-narrow-to-headers)
+      (message-remove-header header))
+    (when (or force (> (length new-value) 0))
+      (if after
+         (message-position-on-field header after)
+       (message-position-on-field header))
+      (insert new-value))))
+
+(defcustom message-recipients-without-full-name
+  (list "ding@gnus.org"
+       "bugs@gnus.org"
+       "emacs-devel@gnu.org"
+       "emacs-pretest-bug@gnu.org"
+       "bug-gnu-emacs@gnu.org")
+  "Mail addresses that have no full name.
+Used in `message-simplify-recipients'."
+  ;; Maybe the addresses could be extracted from
+  ;; `gnus-parameter-to-list-alist'?
+  :type '(choice (const :tag "None" nil)
+                (repeat string))
+  :version "23.1" ;; No Gnus
+  :group 'message-headers)
+
+(defun message-simplify-recipients ()
+  (interactive)
+  (dolist (hdr '("Cc" "To"))
+    (message-replace-header
+     hdr
+     (mapconcat
+      (lambda (addrcomp)
+       (if (and message-recipients-without-full-name
+                (string-match
+                 (regexp-opt message-recipients-without-full-name)
+                 (cadr addrcomp)))
+           (cadr addrcomp)
+         (if (car addrcomp)
+             (message-make-from (car addrcomp) (cadr addrcomp))
+           (cadr addrcomp))))
+      (when (message-fetch-field hdr)
+       (mail-extract-address-components
+        (message-fetch-field hdr) t))
+      ", "))))
+
+;;; multipart/related and HTML support.
+
+(defun message-make-html-message-with-image-files (files)
+  "Make a message containing the current dired-marked image files."
+  (interactive (list (dired-get-marked-files nil current-prefix-arg)))
+  (message-mail)
+  (message-goto-body)
+  (insert "<#part type=text/html>\n\n")
+  (dolist (file files)
+    (insert (format "<img src=%S>\n\n" file)))
+  (message-toggle-image-thumbnails)
+  (message-goto-to))
+
+(defun message-toggle-image-thumbnails ()
+  "For any included image files, insert a thumbnail of that image."
+  (interactive)
+  (let ((overlays (overlays-in (point-min) (point-max)))
+       (displayed nil))
+    (while overlays
+      (let ((overlay (car overlays)))
+       (when (overlay-get overlay 'put-image)
+         (delete-overlay overlay)
+         (setq displayed t)))
+      (setq overlays (cdr overlays)))
+    (unless displayed
+      (save-excursion
+       (goto-char (point-min))
+       (while (re-search-forward "<img.*src=\"\\([^\"]+\\)" nil t)
+         (let ((file (match-string 1))
+               (edges (message-window-inside-pixel-edges
+                       (get-buffer-window (current-buffer)))))
+           (put-image
+            (create-image
+             file 'imagemagick nil
+             :max-width (truncate
+                         (* 0.7 (- (nth 2 edges) (nth 0 edges))))
+             :max-height (truncate
+                          (* 0.5 (- (nth 3 edges) (nth 1 edges)))))
+            (match-beginning 0)
+            " ")))))))
+
+(when (featurep 'xemacs)
+  (require 'messagexmas)
+  (message-xmas-redefine))
+
+(provide 'message)
+
+(run-hooks 'message-load-hook)
+
+;; Local Variables:
+;; coding: utf-8
+;; End:
+
+;;; message.el ends here
diff --git a/xemacs-packages/gnus/lisp/messagexmas.el b/xemacs-packages/gnus/lisp/messagexmas.el
new file mode 100644 (file)
index 0000000..4f5c302
--- /dev/null
@@ -0,0 +1,191 @@
+;;; messagexmas.el --- XEmacs extensions to message
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3, 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.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(require 'nnheader)
+
+(defvar message-xmas-dont-activate-region t
+  "If t, don't activate region after yanking.")
+
+(defvar message-xmas-glyph-directory nil
+  "*Directory where Message logos and icons are located.
+If this variable is nil, Message will try to locate the directory
+automatically.")
+
+(defvar message-use-toolbar (if (featurep 'toolbar) 'default)
+  "*Position to display the toolbar.  Nil means do not use a toolbar.
+If it is non-nil, it should be one of the symbols `default', `top',
+`bottom', `right', and `left'.  `default' means to use the default
+toolbar, the rest mean to display the toolbar on the place which those
+names show.")
+
+(defvar message-toolbar-thickness
+  (if (featurep 'toolbar)
+      (cons (specifier-instance default-toolbar-height)
+           (specifier-instance default-toolbar-width)))
+  "*Cons of the height and the width specifying the thickness of a toolbar.
+The height is used for the toolbar displayed on the top or the bottom,
+the width is used for the toolbar displayed on the right or the left.")
+
+(defvar message-toolbar
+  '([message-spell ispell-message t "Spell"]
+    [message-help (Info-goto-node "(Message)Top") t "Message help"])
+  "The message buffer toolbar.")
+
+(defun message-xmas-find-glyph-directory (&optional package)
+  (setq package (or package "message"))
+  (let ((dir (symbol-value
+             (intern-soft (concat package "-xmas-glyph-directory")))))
+    (if (and (stringp dir) (file-directory-p dir))
+       dir
+      (nnheader-find-etc-directory package))))
+
+(defun message-xmas-setup-toolbar (bar &optional force package)
+  (let ((dir (or (message-xmas-find-glyph-directory package)
+                (message-xmas-find-glyph-directory "gnus")))
+       (xpm (if (featurep 'xpm) "xpm" "xbm"))
+       icon up down disabled name)
+    (unless package
+      (setq message-xmas-glyph-directory dir))
+    (when dir
+      (while bar
+       (setq icon (aref (car bar) 0)
+             name (symbol-name icon)
+             bar (cdr bar))
+       (when (or force
+                 (not (boundp icon)))
+         (setq up (concat dir name "-up." xpm))
+         (setq down (concat dir name "-down." xpm))
+         (setq disabled (concat dir name "-disabled." xpm))
+         (if (not (file-exists-p up))
+             (setq bar nil
+                   dir nil)
+           (set icon (toolbar-make-button-list
+                      up (and (file-exists-p down) down)
+                      (and (file-exists-p disabled) disabled)))))))
+    dir))
+
+(defun message-setup-toolbar ()
+  (when (featurep 'toolbar)
+    (if (and message-use-toolbar
+            (message-xmas-setup-toolbar message-toolbar))
+       (let ((bar (or (intern-soft (format "%s-toolbar" message-use-toolbar))
+                      'default-toolbar))
+             (height (car message-toolbar-thickness))
+             (width (cdr message-toolbar-thickness))
+             (cur (current-buffer))
+             bars)
+         (set-specifier (symbol-value bar) message-toolbar cur)
+         (set-specifier default-toolbar-height height cur)
+         (set-specifier default-toolbar-width width cur)
+         (set-specifier top-toolbar-height height cur)
+         (set-specifier bottom-toolbar-height height cur)
+         (set-specifier right-toolbar-width width cur)
+         (set-specifier left-toolbar-width width cur)
+         (if (eq bar 'default-toolbar)
+             (progn
+               (remove-specifier default-toolbar-visible-p cur)
+               (remove-specifier top-toolbar cur)
+               (remove-specifier top-toolbar-visible-p cur)
+               (remove-specifier bottom-toolbar cur)
+               (remove-specifier bottom-toolbar-visible-p cur)
+               (remove-specifier right-toolbar cur)
+               (remove-specifier right-toolbar-visible-p cur)
+               (remove-specifier left-toolbar cur)
+               (remove-specifier left-toolbar-visible-p cur))
+           (set-specifier (symbol-value (intern (format "%s-visible-p" bar)))
+                          t cur)
+           (setq bars (delq bar (list 'default-toolbar
+                                      'bottom-toolbar 'top-toolbar
+                                      'right-toolbar 'left-toolbar)))
+           (while bars
+             (set-specifier (symbol-value (intern (format "%s-visible-p"
+                                                          (pop bars))))
+                            nil cur))))
+      (let ((cur (current-buffer)))
+       (set-specifier default-toolbar-visible-p nil cur)
+       (set-specifier top-toolbar-visible-p nil cur)
+       (set-specifier bottom-toolbar-visible-p nil cur)
+       (set-specifier right-toolbar-visible-p nil cur)
+       (set-specifier left-toolbar-visible-p nil cur)))))
+
+(defun message-xmas-exchange-point-and-mark ()
+  "Exchange point and mark, but allow for XEmacs's optional argument."
+  (exchange-point-and-mark message-xmas-dont-activate-region))
+
+(defun message-xmas-maybe-fontify ()
+  (when (featurep 'font-lock)
+    (font-lock-set-defaults)))
+
+(defun message-xmas-make-caesar-translation-table (n)
+  "Create a rot table with offset N."
+  (let ((i -1)
+       (table (make-string 256 0))
+       (a (mm-char-int ?a))
+       (A (mm-char-int ?A)))
+    (while (< (incf i) 256)
+      (aset table i i))
+    (concat
+     (substring table 0 A)
+     (substring table (+ A n) (+ A n (- 26 n)))
+     (substring table A (+ A n))
+     (substring table (+ A 26) a)
+     (substring table (+ a n) (+ a n (- 26 n)))
+     (substring table a (+ a n))
+     (substring table (+ a 26) 255))))
+
+(defun message-xmas-make-date (&optional now)
+  "Make a valid data header.
+If NOW, use that time instead."
+  (let ((zone (car (current-time-zone)))
+       sign)
+    (if (>= zone 0)
+       (setq sign "+")
+      (setq sign "-"
+           zone (- zone)))
+    (format "%s %s%02d%02d"
+           (format-time-string "%a, %d %b %Y %T" now)
+           sign
+           (/ zone 3600)
+           (/ (% zone 3600) 60))))
+
+(add-hook 'message-mode-hook 'message-xmas-maybe-fontify)
+
+(defun message-xmas-redefine ()
+  "Redefine message functions for XEmacs."
+  (defalias 'message-exchange-point-and-mark
+    'message-xmas-exchange-point-and-mark)
+  (defalias 'message-mark-active-p
+    'region-exists-p)
+  (defalias 'message-make-caesar-translation-table
+    'message-xmas-make-caesar-translation-table)
+  (defalias 'message-make-date 'message-xmas-make-date))
+
+(message-xmas-redefine)
+
+(provide 'messagexmas)
+
+;;; messagexmas.el ends here
diff --git a/xemacs-packages/gnus/lisp/messcompat.el b/xemacs-packages/gnus/lisp/messcompat.el
new file mode 100644 (file)
index 0000000..6eadf2a
--- /dev/null
@@ -0,0 +1,91 @@
+;;; messcompat.el --- making message mode compatible with mail mode
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This file tries to provide backward compatibility with sendmail.el
+;; for Message mode.  It should be used by simply adding
+;;
+;; (require 'messcompat)
+;;
+;; to the .emacs file.  Loading it after Message mode has been
+;; loaded will have no effect.
+
+;;; Code:
+
+(require 'sendmail)
+
+(defvar message-from-style mail-from-style
+  "*Specifies how \"From\" headers look.
+
+If nil, they contain just the return address like:
+       king@grassland.com
+If `parens', they look like:
+       king@grassland.com (Elvis Parsley)
+If `angles', they look like:
+       Elvis Parsley <king@grassland.com>
+
+Otherwise, most addresses look like `angles', but they look like
+`parens' if `angles' would need quoting and `parens' would not.")
+
+(defvar message-interactive mail-interactive
+  "Non-nil means when sending a message wait for and display errors.
+nil means let mailer mail back a message to report errors.")
+
+(defvar message-setup-hook mail-setup-hook
+  "Normal hook, run each time a new outgoing message is initialized.
+The function `message-setup' runs this hook.")
+
+(if (boundp 'mail-mode-hook)
+    (defvar message-mode-hook mail-mode-hook
+      "Hook run in message mode buffers."))
+
+(defvar message-indentation-spaces mail-indentation-spaces
+  "*Number of spaces to insert at the beginning of each cited line.
+Used by `message-yank-original' via `message-yank-cite'.")
+
+(defvar message-signature mail-signature
+  "*String to be inserted at the end of the message buffer.
+If t, the `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.")
+
+;; Deleted the autoload cookie because this crashes in loaddefs.el.
+(defvar message-signature-file mail-signature-file
+  "*File containing the text inserted at end of the message buffer.")
+
+(defvar message-default-headers mail-default-headers
+  "*A string containing header lines to be inserted in outgoing messages.
+It is inserted before you edit the message, so you can edit or delete
+these lines.")
+
+(defvar message-send-hook mail-send-hook
+  "Hook run before sending messages.")
+
+(defvar message-send-mail-function send-mail-function
+  "Function to call to send the current buffer as mail.
+The headers should be delimited by a line whose contents match the
+variable `mail-header-separator'.")
+
+(provide 'messcompat)
+
+;;; messcompat.el ends here
diff --git a/xemacs-packages/gnus/lisp/mm-archive.el b/xemacs-packages/gnus/lisp/mm-archive.el
new file mode 100644 (file)
index 0000000..45dbd90
--- /dev/null
@@ -0,0 +1,106 @@
+;;; mm-archive.el --- Functions for parsing archive files as MIME
+
+;; Copyright (C) 2012-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'mm-decode)
+(autoload 'gnus-recursive-directory-files "gnus-util")
+(autoload 'mailcap-extension-to-mime "mailcap")
+
+(defvar mm-archive-decoders
+  '(("application/ms-tnef" t "tnef" "-f" "-" "-C")
+    ("application/zip" nil "unzip" "-j" "-x" "%f" "-d")
+    ("application/x-gtar-compressed" nil "tar" "xzf" "-" "-C")
+    ("application/x-tar" nil "tar" "xf" "-" "-C")))
+
+(defun mm-archive-decoders () mm-archive-decoders)
+
+(defun mm-dissect-archive (handle)
+  (let ((decoder (cddr (assoc (car (mm-handle-type handle))
+                             mm-archive-decoders)))
+       (dir (mm-make-temp-file
+             (expand-file-name "emm." mm-tmp-directory) 'dir)))
+    (set-file-modes dir #o700)
+    (unwind-protect
+       (progn
+         (mm-with-unibyte-buffer
+           (mm-insert-part handle)
+           (if (member "%f" decoder)
+               (let ((file (expand-file-name "mail.zip" dir)))
+                 (write-region (point-min) (point-max) file nil 'silent)
+                 (setq decoder (copy-sequence decoder))
+                 (setcar (member "%f" decoder) file)
+                 (apply 'call-process (car decoder) nil nil nil
+                        (append (cdr decoder) (list dir)))
+                 (delete-file file))
+             (apply 'call-process-region (point-min) (point-max) (car decoder)
+                    nil (get-buffer-create "*tnef*")
+                    nil (append (cdr decoder) (list dir)))))
+         `("multipart/mixed"
+           ,handle
+           ,@(mm-archive-list-files (gnus-recursive-directory-files dir))))
+      (delete-directory dir t))))
+
+(defun mm-archive-list-files (files)
+  (let ((handles nil)
+       type disposition)
+    (dolist (file files)
+      (with-temp-buffer
+       (when (string-match "\\.\\([^.]+\\)$" file)
+         (setq type (mailcap-extension-to-mime (match-string 1 file))))
+       (unless type
+         (setq type "application/octet-stream"))
+       (setq disposition
+             (if (string-match "^image/\\|^text/" type)
+                 "inline"
+               "attachment"))
+       (insert (format "Content-type: %s\n" type))
+       (insert "Content-Transfer-Encoding: 8bit\n\n")
+       (insert-file-contents file)
+       (push
+        (mm-make-handle (mm-copy-to-buffer)
+                        (list type)
+                        '8bit nil
+                        `(,disposition (filename . ,file))
+                        nil nil nil)
+        handles)))
+    handles))
+
+(defun mm-archive-dissect-and-inline (handle)
+  (let ((start (point-marker)))
+    (save-restriction
+      (narrow-to-region (point) (point))
+      (dolist (handle (cddr (mm-dissect-archive handle)))
+       (goto-char (point-max))
+       (mm-display-inline handle))
+      (goto-char (point-max))
+      (mm-handle-set-undisplayer
+       handle
+       `(lambda ()
+         (let ((inhibit-read-only t)
+               (end ,(point-marker)))
+           (remove-images ,start end)
+           (delete-region ,start end)))))))
+
+(provide 'mm-archive)
+
+;; mm-archive.el ends here
diff --git a/xemacs-packages/gnus/lisp/mm-bodies.el b/xemacs-packages/gnus/lisp/mm-bodies.el
new file mode 100644 (file)
index 0000000..11449f9
--- /dev/null
@@ -0,0 +1,301 @@
+;;; mm-bodies.el --- Functions for decoding MIME things
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;;     MORIOKA Tomohiko <morioka@jaist.ac.jp>
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'mm-util)
+(require 'rfc2047)
+(require 'mm-encode)
+
+(defvar mm-uu-yenc-decode-function)
+(defvar mm-uu-decode-function)
+(defvar mm-uu-binhex-decode-function)
+
+;; 8bit treatment gets any char except: 0x32 - 0x7f, LF, TAB, BEL,
+;; BS, vertical TAB, form feed, and ^_
+;;
+;; Note that CR is *not* included, as that would allow a non-paired CR
+;; in the body contrary to RFC 2822:
+;;
+;;   - CR and LF MUST only occur together as CRLF; they MUST NOT
+;;     appear independently in the body.
+
+(defvar mm-7bit-chars "\x20-\x7f\n\t\x7\x8\xb\xc\x1f")
+
+(defcustom mm-body-charset-encoding-alist
+  '((iso-2022-jp . 7bit)
+    (iso-2022-jp-2 . 7bit)
+    ;; We MUST encode UTF-16 because it can contain \0's which is
+    ;; known to break servers.
+    ;; Note: UTF-16 variants are invalid for text parts [RFC 2781],
+    ;; so this can't happen :-/.
+    ;; PPS: Yes, it can happen if the user specifies UTF-16 in the MML
+    ;; markup. - jh.
+    (utf-16 . base64)
+    (utf-16be . base64)
+    (utf-16le . base64))
+  "Alist of MIME charsets to encodings.
+Valid encodings are `7bit', `8bit', `quoted-printable' and `base64'."
+  :type '(repeat (cons (symbol :tag "charset")
+                      (choice :tag "encoding"
+                              (const 7bit)
+                              (const 8bit)
+                              (const quoted-printable)
+                              (const base64))))
+  :group 'mime)
+
+(autoload 'message-options-get "message")
+(declare-function message-options-set "message" (symbol value))
+
+(defun mm-encode-body (&optional charset)
+  "Encode a body.
+Should be called narrowed to the body that is to be encoded.
+If there is more than one non-ASCII MULE charset in the body, then the
+list of MULE charsets found is returned.
+If CHARSET is non-nil, it is used as the MIME charset to encode the body.
+If successful, the MIME charset is returned.
+If no encoding was done, nil is returned."
+  (if (not (mm-multibyte-p))
+      ;; In the non-Mule case, we search for non-ASCII chars and
+      ;; return the value of `mail-parse-charset' if any are found.
+      (or charset
+         (save-excursion
+           (goto-char (point-min))
+           (if (re-search-forward "[^\x0-\x7f]" nil t)
+               (or mail-parse-charset
+                   (message-options-get 'mm-body-charset-encoding-alist)
+                   (message-options-set
+                    'mm-body-charset-encoding-alist
+                    (mm-read-coding-system "Charset used in the article: ")))
+             ;; The logic in `mml-generate-mime-1' confirms that it's OK
+             ;; to return nil here.
+             nil)))
+    (save-excursion
+      (if charset
+         (progn
+           (mm-encode-coding-region (point-min) (point-max)
+                                    (mm-charset-to-coding-system charset))
+           charset)
+       (goto-char (point-min))
+       (let ((charsets (mm-find-mime-charset-region (point-min) (point-max)
+                                                    mm-hack-charsets)))
+         (cond
+          ;; No encoding.
+          ((null charsets)
+           nil)
+          ;; Too many charsets.
+          ((> (length charsets) 1)
+           charsets)
+          ;; We encode.
+          (t
+           (prog1
+               (setq charset (car charsets))
+             (mm-encode-coding-region (point-min) (point-max)
+                                      (mm-charset-to-coding-system charset))))
+          ))))))
+
+(defun mm-long-lines-p (length)
+  "Say whether any of the lines in the buffer is longer than LENGTH."
+  (save-excursion
+    (goto-char (point-min))
+    (end-of-line)
+    (while (and (not (eobp))
+               (not (> (current-column) length)))
+      (forward-line 1)
+      (end-of-line))
+    (and (> (current-column) length)
+        (current-column))))
+
+(defvar message-posting-charset)
+
+(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)
+    (cond
+     ((and (not longp)
+          (not (and mm-use-ultra-safe-encoding
+                    (or (save-excursion (re-search-forward " $" nil t))
+                        (save-excursion (re-search-forward "^From " nil t)))))
+          (eq bits '7bit))
+      bits)
+     ((and (not mm-use-ultra-safe-encoding)
+          (not longp)
+          (not (cdr (assq charset mm-body-charset-encoding-alist)))
+          (or (eq t (cdr message-posting-charset))
+              (memq charset (cdr message-posting-charset))
+              (eq charset mail-parse-charset)))
+      bits)
+     (t
+      (let ((encoding (or encoding
+                         (cdr (assq charset mm-body-charset-encoding-alist))
+                         (mm-qp-or-base64))))
+       (when mm-use-ultra-safe-encoding
+         (setq encoding (mm-safer-encoding encoding)))
+       (mm-encode-content-transfer-encoding encoding "text/plain")
+       encoding)))))
+
+(defun mm-body-7-or-8 ()
+  "Say whether the body is 7bit or 8bit."
+  (if (save-excursion
+       (goto-char (point-min))
+       (skip-chars-forward mm-7bit-chars)
+       (eobp))
+      '7bit
+    '8bit))
+
+;;;
+;;; Functions for decoding
+;;;
+
+(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))
+           t)
+          ((eq encoding 'base64)
+           (base64-decode-region
+            (point-min)
+            ;; Some mailers insert whitespace
+            ;; junk at the end which
+            ;; base64-decode-region dislikes.
+            ;; Also remove possible junk which could
+            ;; have been added by mailing list software.
+            (save-excursion
+              (goto-char (point-min))
+              (while (re-search-forward "^[\t ]*\r?\n" nil t)
+                (delete-region (match-beginning 0) (match-end 0)))
+              (goto-char (point-max))
+              (when (re-search-backward "^[\t ]*[A-Za-z0-9+/]+=*[\t ]*$"
+                                        nil t)
+                (forward-line))
+              (point))))
+          ((memq encoding '(nil 7bit 8bit binary))
+           ;; Do nothing.
+           t)
+          ((memq encoding '(x-uuencode x-uue))
+           (require 'mm-uu)
+           (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))
+           t)
+          ((eq encoding 'x-yenc)
+           (require 'mm-uu)
+           (funcall mm-uu-yenc-decode-function (point-min) (point-max))
+           )
+          ((functionp encoding)
+           (funcall encoding (point-min) (point-max))
+           t)
+          (t
+           (message "Unknown encoding %s; defaulting to 8bit" encoding)))
+       (error
+        (message "Error while decoding: %s" error)
+        nil))
+    (when (and
+          type
+          (memq encoding '(base64 x-uuencode x-uue x-binhex x-yenc))
+          (string-match "\\`text/" type))
+      (goto-char (point-min))
+      (while (search-forward "\r\n" nil t)
+       (replace-match "\n" t t)))))
+
+(defun mm-decode-body (charset &optional encoding type)
+  "Decode the current article that has been encoded with ENCODING to CHARSET.
+ENCODING is a MIME content transfer encoding.
+CHARSET is the MIME charset with which to decode the data after transfer
+decoding.  If it is nil, default to `mail-parse-charset'."
+  (when (stringp charset)
+    (setq charset (intern (downcase 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))
+    (setq charset mail-parse-charset))
+  (save-excursion
+    (when encoding
+      (mm-decode-content-transfer-encoding encoding type))
+    (when (and (featurep 'mule) ;; Fixme: Wrong test for unibyte session.
+              (not (eq charset 'gnus-decoded)))
+      (let ((coding-system (mm-charset-to-coding-system
+                           ;; Allow overwrite using
+                           ;; `mm-charset-override-alist'.
+                           charset nil t)))
+       (if (and (not coding-system)
+                (listp mail-parse-ignored-charsets)
+                (memq 'gnus-unknown mail-parse-ignored-charsets))
+           (setq coding-system
+                 (mm-charset-to-coding-system mail-parse-charset)))
+       (when (and charset coding-system
+                  ;; buffer-file-coding-system
+                  ;;Article buffer is nil coding system
+                  ;;in XEmacs
+                  (mm-multibyte-p)
+                  (or (not (eq coding-system 'ascii))
+                      (setq coding-system mail-parse-charset)))
+         (mm-decode-coding-region (point-min) (point-max)
+                                  coding-system))
+       (setq buffer-file-coding-system
+             (if (boundp 'last-coding-system-used)
+                 (symbol-value 'last-coding-system-used)
+               coding-system))))))
+
+(defun mm-decode-string (string charset)
+  "Decode STRING with CHARSET."
+  (when (stringp charset)
+    (setq charset (intern (downcase 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))
+    (setq charset mail-parse-charset))
+  (or
+   (when (featurep 'mule)
+     (let ((coding-system (mm-charset-to-coding-system
+                          charset
+                          ;; Allow overwrite using
+                          ;; `mm-charset-override-alist'.
+                          nil t)))
+       (if (and (not coding-system)
+               (listp mail-parse-ignored-charsets)
+               (memq 'gnus-unknown mail-parse-ignored-charsets))
+          (setq coding-system
+                (mm-charset-to-coding-system mail-parse-charset)))
+       (when (and charset coding-system
+                 (mm-multibyte-p)
+                 (or (not (eq coding-system 'ascii))
+                     (setq coding-system mail-parse-charset)))
+        (mm-decode-coding-string string coding-system))))
+   string))
+
+(provide 'mm-bodies)
+
+;;; mm-bodies.el ends here
diff --git a/xemacs-packages/gnus/lisp/mm-decode.el b/xemacs-packages/gnus/lisp/mm-decode.el
new file mode 100644 (file)
index 0000000..79fc74a
--- /dev/null
@@ -0,0 +1,1932 @@
+;;; mm-decode.el --- Functions for decoding MIME things
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;;     MORIOKA Tomohiko <morioka@jaist.ac.jp>
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'mail-parse)
+(require 'mm-bodies)
+(eval-when-compile (require 'cl))
+
+(autoload 'gnus-map-function "gnus-util")
+(autoload 'gnus-replace-in-string "gnus-util")
+(autoload 'gnus-read-shell-command "gnus-util")
+
+(autoload 'mm-inline-partial "mm-partial")
+(autoload 'mm-inline-external-body "mm-extern")
+(autoload 'mm-extern-cache-contents "mm-extern")
+(autoload 'mm-insert-inline "mm-view")
+
+(autoload 'mm-archive-decoders "mm-archive")
+(autoload 'mm-archive-dissect-and-inline "mm-archive")
+(autoload 'mm-dissect-archive "mm-archive")
+
+(defvar gnus-current-window-configuration)
+
+(add-hook 'gnus-exit-gnus-hook 'mm-destroy-postponed-undisplay-list)
+(add-hook 'gnus-exit-gnus-hook 'mm-temp-files-delete)
+
+(defgroup mime-display ()
+  "Display of MIME in mail and news articles."
+  :link '(custom-manual "(emacs-mime)Display Customization")
+  :version "21.1"
+  :group 'mail
+  :group 'news
+  :group 'multimedia)
+
+(defgroup mime-security ()
+  "MIME security in mail and news articles."
+  :link '(custom-manual "(emacs-mime)Display Customization")
+  :group 'mail
+  :group 'news
+  :group 'multimedia)
+
+(defface mm-command-output
+  '((((class color)
+      (background dark))
+     (:foreground "ForestGreen"))
+    (((class color)
+      (background light))
+     (:foreground "red3"))
+    (t
+     (:italic t)))
+  "Face used for displaying output from commands."
+  :group 'mime-display)
+
+;;; Convenience macros.
+
+(defmacro mm-handle-buffer (handle)
+  `(nth 0 ,handle))
+(defmacro mm-handle-type (handle)
+  `(nth 1 ,handle))
+(defsubst mm-handle-media-type (handle)
+  (if (stringp (car handle))
+      (car handle)
+    (car (mm-handle-type handle))))
+(defsubst mm-handle-media-supertype (handle)
+  (car (split-string (mm-handle-media-type handle) "/")))
+(defsubst mm-handle-media-subtype (handle)
+  (cadr (split-string (mm-handle-media-type handle) "/")))
+(defmacro mm-handle-encoding (handle)
+  `(nth 2 ,handle))
+(defmacro mm-handle-undisplayer (handle)
+  `(nth 3 ,handle))
+(defmacro mm-handle-set-undisplayer (handle function)
+  `(setcar (nthcdr 3 ,handle) ,function))
+(defmacro mm-handle-disposition (handle)
+  `(nth 4 ,handle))
+(defmacro mm-handle-description (handle)
+  `(nth 5 ,handle))
+(defmacro mm-handle-cache (handle)
+  `(nth 6 ,handle))
+(defmacro mm-handle-set-cache (handle contents)
+  `(setcar (nthcdr 6 ,handle) ,contents))
+(defmacro mm-handle-id (handle)
+  `(nth 7 ,handle))
+(defmacro mm-handle-multipart-original-buffer (handle)
+  `(get-text-property 0 'buffer (car ,handle)))
+(defmacro mm-handle-multipart-from (handle)
+  `(get-text-property 0 'from (car ,handle)))
+(defmacro mm-handle-multipart-ctl-parameter (handle parameter)
+  `(get-text-property 0 ,parameter (car ,handle)))
+
+(defmacro mm-make-handle (&optional buffer type encoding undisplayer
+                                   disposition description cache
+                                   id)
+  `(list ,buffer ,type ,encoding ,undisplayer
+        ,disposition ,description ,cache ,id))
+
+(defcustom mm-text-html-renderer
+  (cond ((fboundp 'libxml-parse-html-region) 'shr)
+       ((executable-find "w3m") 'gnus-w3m)
+       ((executable-find "links") 'links)
+       ((executable-find "lynx") 'lynx)
+       ((locate-library "html2text") 'html2text)
+       (t nil))
+  "Render of HTML contents.
+It is one of defined renderer types, or a rendering function.
+The defined renderer types are:
+`shr': use the built-in Gnus HTML renderer;
+`gnus-w3m': use Gnus renderer based on w3m;
+`w3m': use emacs-w3m;
+`w3m-standalone': use plain w3m;
+`links': use links;
+`lynx': use lynx;
+`html2text': use html2text;
+nil    : use external viewer (default web browser)."
+  :version "24.1"
+  :type '(choice (const shr)
+                 (const gnus-w3m)
+                 (const w3m :tag "emacs-w3m")
+                (const w3m-standalone :tag "standalone w3m" )
+                (const links)
+                (const lynx)
+                (const html2text)
+                (const nil :tag "External viewer")
+                (function))
+  :group 'mime-display)
+
+(defcustom mm-inline-text-html-with-images nil
+  "If non-nil, Gnus will allow retrieving images in HTML that has <img> tags.
+See also the documentation for the `mm-w3m-safe-url-regexp'
+variable."
+  :version "22.1"
+  :type 'boolean
+  :group 'mime-display)
+
+(defcustom mm-w3m-safe-url-regexp "\\`cid:"
+  "Regexp matching URLs which are considered to be safe.
+Some HTML mails might contain a nasty trick used by spammers, using
+the <img> tag which is far more evil than the [Click Here!] button.
+It is most likely intended to check whether the ominous spam mail has
+reached your eyes or not, in which case the spammer knows for sure
+that your email address is valid.  It is done by embedding an
+identifier string into a URL that you might automatically retrieve
+when displaying the image.  The default value is \"\\\\`cid:\" which only
+matches parts embedded to the Multipart/Related type MIME contents and
+Gnus will never connect to the spammer's site arbitrarily.  You may
+set this variable to nil if you consider all urls to be safe."
+  :version "22.1"
+  :type '(choice (regexp :tag "Regexp")
+                (const :tag "All URLs are safe" nil))
+  :group 'mime-display)
+
+(defcustom mm-inline-text-html-with-w3m-keymap t
+  "If non-nil, use emacs-w3m command keys in the article buffer."
+  :version "22.1"
+  :type 'boolean
+  :group 'mime-display)
+
+(defcustom mm-enable-external t
+  "Indicate whether external MIME handlers should be used.
+
+If t, all defined external MIME handlers are used.  If nil, files are saved by
+`mailcap-save-binary-file'.  If it is the symbol `ask', you are prompted
+before the external MIME handler is invoked."
+  :version "22.1"
+  :type '(choice (const :tag "Always" t)
+                (const :tag "Never" nil)
+                (const :tag "Ask" ask))
+  :group 'mime-display)
+
+(defcustom mm-inline-media-tests
+  '(("image/p?jpeg"
+     mm-inline-image
+     (lambda (handle)
+       (mm-valid-and-fit-image-p 'jpeg handle)))
+    ("image/png"
+     mm-inline-image
+     (lambda (handle)
+       (mm-valid-and-fit-image-p 'png handle)))
+    ("image/gif"
+     mm-inline-image
+     (lambda (handle)
+       (mm-valid-and-fit-image-p 'gif handle)))
+    ("image/tiff"
+     mm-inline-image
+     (lambda (handle)
+       (mm-valid-and-fit-image-p 'tiff handle)))
+    ("image/xbm"
+     mm-inline-image
+     (lambda (handle)
+       (mm-valid-and-fit-image-p 'xbm handle)))
+    ("image/x-xbitmap"
+     mm-inline-image
+     (lambda (handle)
+       (mm-valid-and-fit-image-p 'xbm handle)))
+    ("image/xpm"
+     mm-inline-image
+     (lambda (handle)
+       (mm-valid-and-fit-image-p 'xpm handle)))
+    ("image/x-xpixmap"
+     mm-inline-image
+     (lambda (handle)
+       (mm-valid-and-fit-image-p 'xpm handle)))
+    ("image/bmp"
+     mm-inline-image
+     (lambda (handle)
+       (mm-valid-and-fit-image-p 'bmp handle)))
+    ("image/x-portable-bitmap"
+     mm-inline-image
+     (lambda (handle)
+       (mm-valid-and-fit-image-p 'pbm handle)))
+    ("text/plain" mm-inline-text identity)
+    ("text/enriched" mm-inline-text identity)
+    ("text/richtext" mm-inline-text identity)
+    ("text/x-patch" mm-display-patch-inline identity)
+    ;; In case mime.types uses x-diff (as does Debian's mime-support-3.40).
+    ("text/x-diff" mm-display-patch-inline identity)
+    ("application/emacs-lisp" mm-display-elisp-inline identity)
+    ("application/x-emacs-lisp" mm-display-elisp-inline identity)
+    ("application/x-shellscript" mm-display-shell-script-inline identity)
+    ("application/x-sh" mm-display-shell-script-inline identity)
+    ("text/x-sh" mm-display-shell-script-inline identity)
+    ("application/javascript" mm-display-javascript-inline identity)
+    ("text/dns" mm-display-dns-inline identity)
+    ("text/x-org" mm-display-org-inline identity)
+    ("text/html"
+     mm-inline-text-html
+     (lambda (handle)
+       mm-text-html-renderer))
+    ("text/x-vcard"
+     mm-inline-text-vcard
+     (lambda (handle)
+       (or (featurep 'vcard)
+          (locate-library "vcard"))))
+    ("message/delivery-status" mm-inline-text identity)
+    ("message/rfc822" mm-inline-message identity)
+    ("message/partial" mm-inline-partial identity)
+    ("message/external-body" mm-inline-external-body identity)
+    ("text/.*" mm-inline-text identity)
+    ("application/x-.?tar\\(-.*\\)?" mm-archive-dissect-and-inline identity)
+    ("application/zip" mm-archive-dissect-and-inline identity)
+    ("audio/wav" mm-inline-audio
+     (lambda (handle)
+       (and (or (featurep 'nas-sound) (featurep 'native-sound))
+           (device-sound-enabled-p))))
+    ("audio/au"
+     mm-inline-audio
+     (lambda (handle)
+       (and (or (featurep 'nas-sound) (featurep 'native-sound))
+           (device-sound-enabled-p))))
+    ("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)
+    ("image/.*"
+     mm-inline-image
+     (lambda (handle)
+       (and (mm-valid-image-format-p 'imagemagick)
+           (mm-with-unibyte-buffer
+             (mm-insert-part handle)
+             (let ((image
+                    (ignore-errors
+                      (if (fboundp 'create-image)
+                          (create-image (buffer-string) 'imagemagick 'data-p)
+                        (mm-create-image-xemacs
+                         (mm-handle-media-subtype handle))))))
+               (when image
+                 (setcar (cdr handle) (list "image/imagemagick"))
+                 (mm-image-fit-p handle)))))))
+    ;; 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 (regexp :tag "MIME type")
+                      (function :tag "Display function")
+                      (function :tag "Display test")))
+  :group 'mime-display)
+
+(defcustom mm-inlined-types
+  '("image/.*" "text/.*" "message/delivery-status" "message/rfc822"
+    "message/partial" "message/external-body" "application/emacs-lisp"
+    "application/x-emacs-lisp"
+    "application/pgp-signature" "application/x-pkcs7-signature"
+    "application/pkcs7-signature" "application/x-pkcs7-mime"
+    "application/pkcs7-mime"
+    "application/x-gtar-compressed"
+    "application/x-tar"
+    "application/zip"
+    ;; Mutt still uses this even though it has already been withdrawn.
+    "application/pgp")
+  "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 regexp)
+  :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."
+  :version "22.1"
+  :type '(repeat regexp)
+  :group 'mime-display)
+
+(defcustom mm-automatic-display
+  '("text/plain" "text/enriched" "text/richtext" "text/html" "text/x-verbatim"
+    "text/x-vcard" "image/.*" "message/delivery-status" "multipart/.*"
+    "message/rfc822" "text/x-patch" "text/dns" "application/pgp-signature"
+    "application/emacs-lisp" "application/x-emacs-lisp"
+    "application/x-pkcs7-signature"
+    "application/pkcs7-signature" "application/x-pkcs7-mime"
+    "application/pkcs7-mime"
+    ;; Mutt still uses this even though it has already been withdrawn.
+    "application/pgp\\'"
+     "text/x-org")
+  "A list of MIME types to be displayed automatically."
+  :type '(repeat regexp)
+  :group 'mime-display)
+
+(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 regexp)
+  :group 'mime-display)
+
+(defcustom mm-inline-override-types nil
+  "Types to be treated as attachments even if they can be displayed inline."
+  :type '(repeat regexp)
+  :group 'mime-display)
+
+(defcustom mm-automatic-external-display nil
+  "List of MIME type regexps that will be displayed externally automatically."
+  :type '(repeat regexp)
+  :group 'mime-display)
+
+(defcustom mm-discouraged-alternatives nil
+  "List of MIME types that are discouraged when viewing multipart/alternative.
+Viewing agents are supposed to view the 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, text/html parts are very unwanted, and text/richtext are
+somewhat unwanted, then the value of this variable should be set
+to:
+
+ (\"text/html\" \"text/richtext\")
+
+Adding \"image/.*\" might also be useful.  Spammers use it as the
+preferred part of multipart/alternative messages.  See also
+`gnus-buttonized-mime-types', to which adding \"multipart/alternative\"
+enables you to choose manually one of two types those mails include."
+  :type '(repeat regexp) ;; See `mm-preferred-alternative-precedence'.
+  :group 'mime-display)
+
+(defcustom mm-tmp-directory
+  (if (fboundp 'temp-directory)
+      (temp-directory)
+    (if (boundp 'temporary-file-directory)
+       temporary-file-directory
+      "/tmp/"))
+  "Where mm will store its temporary files."
+  :type 'directory
+  :group 'mime-display)
+
+(defcustom mm-inline-large-images nil
+  "If t, then all images fit in the buffer.
+If `resize', try to resize the images so they fit."
+  :type '(radio
+          (const :tag "Inline large images as they are." t)
+          (const :tag "Resize large images." resize)
+          (const :tag "Do not inline large images." nil))
+  :group 'mime-display)
+
+(defcustom mm-file-name-rewrite-functions
+  '(mm-file-name-delete-control mm-file-name-delete-gotchas)
+  "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-control',
+`mm-file-name-delete-gotchas' (you should not remove these two
+functions), `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'."
+  :type '(list (set :inline t
+                   (const mm-file-name-delete-control)
+                   (const mm-file-name-delete-gotchas)
+                   (const mm-file-name-delete-whitespace)
+                   (const mm-file-name-trim-whitespace)
+                   (const mm-file-name-collapse-whitespace)
+                   (const mm-file-name-replace-whitespace)
+                   (const capitalize)
+                   (const downcase)
+                   (const upcase)
+                   (const upcase-initials)
+              (repeat :inline t
+                      :tag "Function"
+                      function)))
+  :version "23.1" ;; No Gnus
+  :group 'mime-display)
+
+
+(defvar mm-path-name-rewrite-functions nil
+  "*List of functions for rewriting the full file names of MIME parts.
+This is used when viewing parts externally, and is meant for
+transforming the absolute 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 '(choice directory (const :tag "Default" nil))
+  :group 'mime-display)
+
+(defcustom mm-attachment-file-modes 384
+  "Set the mode bits of saved attachments to this integer."
+  :version "22.1"
+  :type 'integer
+  :group 'mime-display)
+
+(defcustom mm-external-terminal-program "xterm"
+  "The program to start an external terminal."
+  :version "22.1"
+  :type 'string
+  :group 'mime-display)
+
+;;; Internal variables.
+
+(defvar mm-last-shell-command "")
+(defvar mm-content-id-alist nil)
+(defvar mm-postponed-undisplay-list nil)
+(defvar mm-inhibit-auto-detect-attachment nil)
+(defvar mm-temp-files-to-be-deleted nil
+  "List of temporary files scheduled to be deleted.")
+(defvar mm-temp-files-cache-file (concat ".mm-temp-files-" (user-login-name))
+  "Name of a file that caches a list of temporary files to be deleted.
+The file will be saved in the directory `mm-tmp-directory'.")
+
+;; According to RFC2046, in particular, in a digest, the default
+;; Content-Type value for a body part is changed from "text/plain" to
+;; "message/rfc822".
+(defvar mm-dissect-default-type "text/plain")
+
+(autoload 'mml2015-verify "mml2015")
+(autoload 'mml2015-verify-test "mml2015")
+(autoload 'mml-smime-verify "mml-smime")
+(autoload 'mml-smime-verify-test "mml-smime")
+
+(defvar mm-verify-function-alist
+  '(("application/pgp-signature" mml2015-verify "PGP" mml2015-verify-test)
+    ("application/x-gnus-pgp-signature" mm-uu-pgp-signed-extract-1 "PGP"
+     mm-uu-pgp-signed-test)
+    ("application/pkcs7-signature" mml-smime-verify "S/MIME"
+     mml-smime-verify-test)
+    ("application/x-pkcs7-signature" mml-smime-verify "S/MIME"
+     mml-smime-verify-test)))
+
+(defcustom mm-verify-option 'never
+  "Option of verifying signed parts.
+`never', not verify; `always', always verify;
+`known', only verify known protocols.  Otherwise, ask user.
+
+When set to `always' or `known', you should add
+\"multipart/signed\" to `gnus-buttonized-mime-types' to see
+result of the verification."
+  :version "22.1"
+  :type '(choice (item always)
+                (item never)
+                (item :tag "only known protocols" known)
+                (item :tag "ask" nil))
+  :group 'mime-security)
+
+(autoload 'mml2015-decrypt "mml2015")
+(autoload 'mml2015-decrypt-test "mml2015")
+
+(defvar mm-decrypt-function-alist
+  '(("application/pgp-encrypted" mml2015-decrypt "PGP" mml2015-decrypt-test)
+    ("application/x-gnus-pgp-encrypted" mm-uu-pgp-encrypted-extract-1 "PGP"
+     mm-uu-pgp-encrypted-test)))
+
+(defcustom mm-decrypt-option nil
+  "Option of decrypting encrypted parts.
+`never', not decrypt; `always', always decrypt;
+`known', only decrypt known protocols.  Otherwise, ask user."
+  :version "22.1"
+  :type '(choice (item always)
+                (item never)
+                (item :tag "only known protocols" known)
+                (item :tag "ask" nil))
+  :group 'mime-security)
+
+(defvar mm-viewer-completion-map
+  (let ((map (make-sparse-keymap 'mm-viewer-completion-map)))
+    (set-keymap-parent map minibuffer-local-completion-map)
+    ;; Should we bind other key to minibuffer-complete-word?
+    (define-key map " " 'self-insert-command)
+    map)
+  "Keymap for input viewer with completion.")
+
+;;; The functions.
+
+(defun mm-alist-to-plist (alist)
+  "Convert association list ALIST into the equivalent property-list form.
+The plist is returned.  This converts from
+
+\((a . 1) (b . 2) (c . 3))
+
+into
+
+\(a 1 b 2 c 3)
+
+The original alist is not modified.  See also `destructive-alist-to-plist'."
+  (let (plist)
+    (while alist
+      (let ((el (car alist)))
+       (setq plist (cons (cdr el) (cons (car el) 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 HANDLE to FUNCTION.
+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-temp-files-delete ()
+  "Delete temporary files and those parent directories.
+Note that the deletion may fail if a program is catching hold of a file
+under Windows or Cygwin.  In that case, it schedules the deletion of
+files left at the next time."
+  (let* ((coding-system-for-read mm-universal-coding-system)
+        (coding-system-for-write mm-universal-coding-system)
+        (cache-file (expand-file-name mm-temp-files-cache-file
+                                      mm-tmp-directory))
+        (cache (when (file-exists-p cache-file)
+                 (mm-with-multibyte-buffer
+                   (insert-file-contents cache-file)
+                   (split-string (buffer-string) "\n" t))))
+        fails)
+    (dolist (temp (append cache mm-temp-files-to-be-deleted))
+      (when (and (file-exists-p temp)
+                (if (file-directory-p temp)
+                    ;; A parent directory left at the previous time.
+                    (progn
+                      (ignore-errors (delete-directory temp))
+                      (file-exists-p temp))
+                  ;; Delete a temporary file and its parent directory.
+                  (ignore-errors (delete-file temp))
+                  (or (file-exists-p temp)
+                      (progn
+                        (setq temp (file-name-directory temp))
+                        (ignore-errors (delete-directory temp))
+                        (file-exists-p temp)))))
+       (push temp fails)))
+    (if fails
+       ;; Schedule the deletion of the files left at the next time.
+       (progn
+         (write-region (concat (mapconcat 'identity (nreverse fails) "\n")
+                               "\n")
+                       nil cache-file nil 'silent)
+         (set-file-modes cache-file #o600))
+      (when (file-exists-p cache-file)
+       (ignore-errors (delete-file cache-file))))
+    (setq mm-temp-files-to-be-deleted nil)))
+
+(autoload 'message-fetch-field "message")
+
+(defun mm-dissect-buffer (&optional no-strict-mime loose-mime from)
+  "Dissect the current buffer and return a list of MIME handles.
+If NO-STRICT-MIME, don't require the message to have a
+MIME-Version header before proceeding."
+  (save-excursion
+    (let (ct ctl type subtype cte cd description id result)
+      (save-restriction
+       (mail-narrow-to-head)
+       (when (or no-strict-mime
+                 loose-mime
+                 (mail-fetch-field "mime-version"))
+         (setq ct (mail-fetch-field "content-type")
+               ctl (and ct (mail-header-parse-content-type ct))
+               cte (mail-fetch-field "content-transfer-encoding")
+                cd (or (mail-fetch-field "content-disposition")
+                       (when (and ctl
+                                  (eq 'mm-inline-text
+                                      (cadr (mm-assoc-string-match
+                                             mm-inline-media-tests
+                                             (car ctl)))))
+                         "inline"))
+               ;; Newlines in description should be stripped so as
+               ;; not to break the MIME tag into two or more lines.
+               description (message-fetch-field "content-description")
+               id (mail-fetch-field "content-id"))
+         (unless from
+           (setq from (mail-fetch-field "from")))
+         ;; FIXME: In some circumstances, this code is running within
+         ;; a unibyte macro.  mail-extract-address-components
+         ;; creates unibyte buffers. This `if', though not a perfect
+         ;; solution, avoids most of them.
+         (if from
+             (setq from (cadr (mail-extract-address-components from))))
+         (if description
+             (setq description (mail-decode-encoded-word-string
+                                description)))))
+      (if (or (not ctl)
+             (not (string-match "/" (car ctl))))
+           (mm-dissect-singlepart
+          (list mm-dissect-default-type)
+            (and cte (intern (downcase (mail-header-strip cte))))
+          no-strict-mime
+          (and cd (mail-header-parse-content-disposition cd))
+          description)
+       (setq type (split-string (car ctl) "/"))
+       (setq subtype (cadr type)
+             type (car type))
+       (setq
+        result
+        (cond
+         ((equal type "multipart")
+          (let ((mm-dissect-default-type (if (equal subtype "digest")
+                                             "message/rfc822"
+                                           "text/plain"))
+                (start (cdr (assq 'start (cdr 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 buffer
+            ;; name as a text property of the "multipart/whatever" string.
+            (add-text-properties 0 (length (car ctl))
+                                 (list 'buffer (mm-copy-to-buffer)
+                                       'from from
+                                       'start start)
+                                 (car ctl))
+            (cons (car ctl) (mm-dissect-multipart ctl from))))
+         (t
+          (mm-possibly-verify-or-decrypt
+           (mm-dissect-singlepart
+            ctl
+            (and cte (intern (downcase (mail-header-strip cte))))
+            no-strict-mime
+            (and cd (mail-header-parse-content-disposition cd))
+            description id)
+           ctl from))))
+       (when id
+         (when (string-match " *<\\(.*\\)> *" id)
+           (setq id (match-string 1 id)))
+         (push (cons id result) mm-content-id-alist))
+       result))))
+
+(defun mm-dissect-singlepart (ctl cte &optional force cdl description id)
+  (when (or force
+           (if (equal "text/plain" (car ctl))
+               (assoc 'format ctl)
+             t))
+    ;; Guess what the type of application/octet-stream parts should
+    ;; really be.
+    (let ((filename (cdr (assq 'filename (cdr cdl)))))
+      (when (and (not mm-inhibit-auto-detect-attachment)
+                (equal (car ctl) "application/octet-stream")
+                filename
+                (string-match "\\.\\([^.]+\\)$" filename))
+       (let ((new-type (mailcap-extension-to-mime (match-string 1 filename))))
+         (when new-type
+           (setcar ctl new-type)))))
+    (let ((handle
+          (mm-make-handle
+           (mm-copy-to-buffer) ctl cte nil cdl description nil id))
+         (decoder (assoc (car ctl) (mm-archive-decoders))))
+      (if (and decoder
+              ;; Do automatic decoding
+              (cadr decoder)
+              (executable-find (caddr decoder)))
+         (mm-dissect-archive handle)
+       handle))))
+
+(defun mm-dissect-multipart (ctl from)
+  (goto-char (point-min))
+  (let* ((boundary (concat "\n--" (mail-content-type-get ctl 'boundary)))
+        (close-delimiter (concat (regexp-quote boundary) "--[ \t]*$"))
+        start parts
+        (end (save-excursion
+               (goto-char (point-max))
+               (if (re-search-backward close-delimiter nil t)
+                   (match-beginning 0)
+                 (point-max))))
+        (mm-inhibit-auto-detect-attachment
+         (equal (car ctl) "multipart/encrypted")))
+    (setq boundary (concat (regexp-quote boundary) "[ \t]*$"))
+    (while (and (< (point) end) (re-search-forward boundary end t))
+      (goto-char (match-beginning 0))
+      (when start
+       (save-excursion
+         (save-restriction
+           (narrow-to-region start (point))
+           (setq parts (nconc (list (mm-dissect-buffer t nil from)) parts)))))
+      (end-of-line 2)
+      (or (looking-at boundary)
+         (forward-line 1))
+      (setq start (point)))
+    (when (and start (< start end))
+      (save-excursion
+       (save-restriction
+         (narrow-to-region start end)
+         (setq parts (nconc (list (mm-dissect-buffer t nil from)) parts)))))
+    (mm-possibly-verify-or-decrypt (nreverse parts) ctl from)))
+
+(defun mm-copy-to-buffer ()
+  "Copy the contents of the current buffer to a fresh buffer."
+  (let ((obuf (current-buffer))
+        (mb (mm-multibyte-p))
+        beg)
+    (goto-char (point-min))
+    (search-forward-regexp "^\n" nil t)
+    (setq beg (point))
+    (with-current-buffer
+          (generate-new-buffer " *mm*")
+      ;; Preserve the data's unibyteness (for url-insert-file-contents).
+      (mm-set-buffer-multibyte mb)
+      (insert-buffer-substring obuf beg)
+      (current-buffer))))
+
+(defun mm-display-parts (handle &optional no-default)
+  (if (stringp (car handle))
+      (mapcar 'mm-display-parts (cdr handle))
+    (if (bufferp (car handle))
+       (save-restriction
+         (narrow-to-region (point) (point))
+         (mm-display-part handle)
+         (goto-char (point-max)))
+      (mapcar 'mm-display-parts handle))))
+
+(autoload 'mailcap-parse-mailcaps "mailcap")
+(autoload 'mailcap-mime-info "mailcap")
+
+(defun mm-head-p (&optional point)
+  "Return non-nil if point is in the article header."
+  (let ((point (or point (point))))
+    (save-excursion
+      (goto-char point)
+      (and (not (re-search-backward "^$" nil t))
+          (re-search-forward "^$" nil t)))))
+
+(defun mm-display-part (handle &optional no-default force)
+  "Display the MIME part represented by HANDLE.
+Returns nil if the part is removed; inline if displayed inline;
+external if displayed external."
+  (save-excursion
+    (mailcap-parse-mailcaps)
+    (if (and (not force)
+            (mm-handle-displayed-p handle))
+       (mm-remove-part handle)
+      (let* ((ehandle (if (equal (mm-handle-media-type handle)
+                                "message/external-body")
+                         (progn
+                           (unless (mm-handle-cache handle)
+                             (mm-extern-cache-contents handle))
+                           (mm-handle-cache handle))
+                       handle))
+            (type (mm-handle-media-type ehandle))
+            (method (mailcap-mime-info type))
+            (filename (or (mail-content-type-get
+                           (mm-handle-disposition handle) 'filename)
+                          (mail-content-type-get
+                           (mm-handle-type handle) 'name)
+                          "<file>"))
+            (external mm-enable-external)
+            (decoder (assoc (car (mm-handle-type handle))
+                            (mm-archive-decoders))))
+       (cond
+        ((and decoder
+              (executable-find (caddr decoder)))
+         (mm-archive-dissect-and-inline handle)
+         'inline)
+        ((and (mm-inlinable-p ehandle)
+              (mm-inlined-p ehandle))
+         (when force
+           (if (mm-head-p)
+               (re-search-forward "^$" nil t)
+             (forward-line 1)))
+         (mm-display-inline handle)
+         'inline)
+        ((or method
+             (not no-default))
+         (if (and (not method)
+                  (equal "text" (car (split-string type "/"))))
+             (progn
+               (forward-line 1)
+               (mm-insert-inline handle (mm-get-part handle))
+               'inline)
+           (setq external
+                 (and method         ;; If nil, we always use "save".
+                      (or (eq mm-enable-external t)
+                          (and (eq mm-enable-external 'ask)
+                               (y-or-n-p
+                                (concat
+                                 "Display part (" type
+                                 ") "
+                                 (if (stringp method)
+                                     (concat
+                                      "using external program \""
+                                      (format method filename) "\"")
+                                   (gnus-format-message
+                                    "by calling `%s' on the contents)" method))
+                                 "? "))))))
+           (if external
+               (mm-display-external
+                handle (or method 'mailcap-save-binary-file))
+             (mm-display-external
+              handle 'mailcap-save-binary-file)))))))))
+
+(declare-function gnus-configure-windows "gnus-win" (setting &optional force))
+(defvar mailcap-mime-extensions)       ; mailcap-mime-info autoloads
+(declare-function term-mode "term" ())
+(declare-function term-char-mode "term" ())
+
+(defun mm-display-external (handle method)
+  "Display HANDLE using METHOD."
+  (let ((outbuf (current-buffer)))
+    (mm-with-unibyte-buffer
+      (if (functionp method)
+         (let ((cur (current-buffer)))
+           (if (eq method 'mailcap-save-binary-file)
+               (progn
+                 (set-buffer (generate-new-buffer " *mm*"))
+                 (setq method nil))
+             (mm-insert-part handle)
+             (mm-add-meta-html-tag handle)
+             (let ((win (get-buffer-window cur t)))
+               (when win
+                 (select-window win)))
+             (switch-to-buffer (generate-new-buffer " *mm*")))
+           (buffer-disable-undo)
+           (mm-set-buffer-file-coding-system mm-binary-coding-system)
+           (insert-buffer-substring cur)
+           (goto-char (point-min))
+           (when method
+             (message "Viewing with %s" method))
+           (let ((mm (current-buffer))
+                 (non-viewer (assq 'non-viewer
+                                   (mailcap-mime-info
+                                    (mm-handle-media-type handle) t))))
+             (unwind-protect
+                 (if method
+                     (progn
+                       (when (and (boundp 'gnus-summary-buffer)
+                                  (bufferp gnus-summary-buffer)
+                                  (buffer-name gnus-summary-buffer))
+                         ;; So that we pop back to the right place, sort of.
+                         (switch-to-buffer gnus-summary-buffer)
+                         (switch-to-buffer mm))
+                       (delete-other-windows)
+                       (funcall method))
+                   (mm-save-part handle))
+               (when (and (not non-viewer)
+                          method)
+                 (mm-handle-set-undisplayer handle mm)))))
+       ;; The function is a string to be executed.
+       (mm-insert-part handle)
+       (mm-add-meta-html-tag handle)
+       (let* ((dir (mm-make-temp-file
+                    (expand-file-name "emm." mm-tmp-directory) 'dir))
+              (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)
+                             (assoc "needsterminal" mime-info)))
+              (copiousoutput (assoc "copiousoutput" mime-info))
+              file buffer)
+         ;; We create a private sub-directory where we store our files.
+         (set-file-modes dir #o700)
+         (if filename
+             (setq file (expand-file-name
+                         (gnus-map-function mm-file-name-rewrite-functions
+                                            (file-name-nondirectory filename))
+                         dir))
+           ;; Use nametemplate (defined in RFC1524) if it is specified
+           ;; in mailcap.
+           (let ((suffix (cdr (assoc "nametemplate" mime-info))))
+             (if (and suffix
+                      (string-match "\\`%s\\(\\..+\\)\\'" suffix))
+                 (setq suffix (match-string 1 suffix))
+               ;; Otherwise, use a suffix according to
+               ;; `mailcap-mime-extensions'.
+               (setq suffix (car (rassoc (mm-handle-media-type handle)
+                                         mailcap-mime-extensions))))
+             (setq file (mm-make-temp-file (expand-file-name "mm." dir)
+                                           nil suffix))))
+         (let ((coding-system-for-write mm-binary-coding-system))
+           (write-region (point-min) (point-max) file nil 'nomesg))
+         ;; The file is deleted after the viewer exists.  If the users edits
+         ;; the file, changes will be lost.  Set file to read-only to make it
+         ;; clear.
+         (set-file-modes file #o400)
+         (message "Viewing with %s" method)
+         (cond
+          (needsterm
+           (let ((command (mm-mailcap-command
+                           method file (mm-handle-type handle))))
+             (unwind-protect
+                 (if window-system
+                     (set-process-sentinel
+                      (start-process "*display*" nil
+                                     mm-external-terminal-program
+                                     "-e" shell-file-name
+                                     shell-command-switch command)
+                      `(lambda (process state)
+                         (if (eq 'exit (process-status process))
+                             (run-at-time
+                              60.0 nil
+                              (lambda ()
+                                (ignore-errors (delete-file ,file))
+                                (ignore-errors (delete-directory
+                                                ,(file-name-directory
+                                                  file))))))))
+                   (require 'term)
+                   (require 'gnus-win)
+                   (set-buffer
+                    (setq buffer
+                          (make-term "display"
+                                     shell-file-name
+                                     nil
+                                     shell-command-switch command)))
+                   (term-mode)
+                   (term-char-mode)
+                   (set-process-sentinel
+                    (get-buffer-process buffer)
+                    `(lambda (process state)
+                       (when (eq 'exit (process-status process))
+                         (ignore-errors (delete-file ,file))
+                         (ignore-errors
+                           (delete-directory ,(file-name-directory file)))
+                         (gnus-configure-windows
+                          ',gnus-current-window-configuration))))
+                   (gnus-configure-windows 'display-term))
+               (mm-handle-set-external-undisplayer handle (cons file buffer))
+               (add-to-list 'mm-temp-files-to-be-deleted file t))
+             (message "Displaying %s..." command))
+           '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)
+                        (with-current-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
+           ;; Deleting the temp file should be postponed for some wrappers,
+           ;; shell scripts, and so on, which might exit right after having
+           ;; started a viewer command as a background job.
+           (let ((command (mm-mailcap-command
+                           method file (mm-handle-type handle))))
+             (unwind-protect
+                 (let ((process-connection-type nil))
+                   (start-process "*display*"
+                                  (setq buffer
+                                        (generate-new-buffer " *mm*"))
+                                  shell-file-name
+                                  shell-command-switch command)
+                   (set-process-sentinel
+                    (get-buffer-process buffer)
+                    (lexical-let ((outbuf outbuf)
+                                  (file file)
+                                  (buffer buffer)
+                                  (command command)
+                                  (handle handle))
+                      (lambda (process state)
+                        (when (eq (process-status process) 'exit)
+                          (run-at-time
+                           60.0 nil
+                           (lambda ()
+                             (ignore-errors (delete-file file))
+                             (ignore-errors (delete-directory
+                                             (file-name-directory file)))))
+                          (when (buffer-live-p outbuf)
+                            (with-current-buffer outbuf
+                              (let ((buffer-read-only nil)
+                                    (point (point)))
+                                (forward-line 2)
+                                (let ((start (point)))
+                                  (mm-insert-inline
+                                   handle (with-current-buffer buffer
+                                            (buffer-string)))
+                                  (put-text-property start (point)
+                                                     'face 'mm-command-output))
+                                (goto-char point))))
+                          (when (buffer-live-p buffer)
+                            (kill-buffer buffer)))
+                        (message "Displaying %s...done" command)))))
+               (mm-handle-set-external-undisplayer
+                handle (cons file buffer))
+               (add-to-list 'mm-temp-files-to-be-deleted file t))
+             (message "Displaying %s..." command))
+           'external)))))))
+
+(defun mm-mailcap-command (method file type-list)
+  (let ((ctl (cdr type-list))
+       (beg 0)
+       (uses-stdin t)
+       out sub total)
+    (while (string-match "%{\\([^}]+\\)}\\|'%s'\\|\"%s\"\\|%s\\|%t\\|%%"
+                        method beg)
+      (push (substring method beg (match-beginning 0)) out)
+      (setq beg (match-end 0)
+           total (match-string 0 method)
+           sub (match-string 1 method))
+      (cond
+       ((string= total "%%")
+       (push "%" out))
+       ((or (string= total "%s")
+           ;; We do our own quoting.
+           (string= total "'%s'")
+           (string= total "\"%s\""))
+       (setq uses-stdin nil)
+       (push (shell-quote-argument
+              (gnus-map-function mm-path-name-rewrite-functions file)) out))
+       ((string= total "%t")
+       (push (shell-quote-argument (car type-list)) out))
+       (t
+       (push (shell-quote-argument (or (cdr (assq (intern sub) ctl)) "")) out))))
+    (push (substring method beg (length method)) out)
+    (when uses-stdin
+      (push "<" out)
+      (push (shell-quote-argument
+            (gnus-map-function mm-path-name-rewrite-functions file))
+           out))
+    (mapconcat 'identity (nreverse out) "")))
+
+(defun mm-remove-parts (handles)
+  "Remove the displayed MIME parts represented by HANDLES."
+  (if (and (listp handles)
+          (bufferp (car handles)))
+      (mm-remove-part handles)
+    (let (handle)
+      (while (setq handle (pop handles))
+       (cond
+        ((stringp handle)
+         (when (buffer-live-p (get-text-property 0 'buffer handle))
+           (kill-buffer (get-text-property 0 'buffer handle))))
+        ((and (listp handle)
+              (stringp (car handle)))
+         (mm-remove-parts (cdr handle)))
+        (t
+         (mm-remove-part handle)))))))
+
+(defun mm-destroy-parts (handles)
+  "Remove the displayed MIME parts represented by HANDLES."
+  (if (and (listp handles)
+          (bufferp (car handles)))
+      (mm-destroy-part handles)
+    (let (handle)
+      (while (setq handle (pop handles))
+       (cond
+        ((stringp handle)
+         (when (buffer-live-p (get-text-property 0 'buffer handle))
+           (kill-buffer (get-text-property 0 'buffer handle))))
+        ((and (listp handle)
+              (stringp (car handle)))
+         (mm-destroy-parts handle))
+        (t
+         (mm-destroy-part handle)))))))
+
+(defun mm-remove-part (handle)
+  "Remove the displayed MIME part represented by HANDLE."
+  (when (listp handle)
+    (let ((object (mm-handle-undisplayer handle)))
+      (ignore-errors
+       (cond
+        ;; Internally displayed part.
+        ((mm-annotationp object)
+          (if (featurep 'xemacs)
+              (delete-annotation object)))
+        ((or (functionp object)
+             (and (listp object)
+                  (eq (car object) 'lambda)))
+         (funcall object))
+        ;; Externally displayed part.
+        ((consp object)
+         (condition-case ()
+             (while (get-buffer-process (cdr object))
+               (interrupt-process (get-buffer-process (cdr object)))
+               (message "Waiting for external displayer to die...")
+               (sit-for 1))
+           (quit)
+           (error))
+         (ignore-errors (and (cdr object) (kill-buffer (cdr object))))
+         (message "Waiting for external displayer to die...done")
+         (ignore-errors (delete-file (car object)))
+         (ignore-errors (delete-directory (file-name-directory
+                                           (car object)))))
+        ((bufferp object)
+         (when (buffer-live-p object)
+           (kill-buffer object)))))
+      (mm-handle-set-undisplayer handle nil))))
+
+(defun mm-display-inline (handle)
+  (let* ((type (mm-handle-media-type handle))
+        (function (cadr (mm-assoc-string-match mm-inline-media-tests type))))
+    (funcall function handle)
+    (goto-char (point-min))))
+
+(defun mm-assoc-string-match (alist type)
+  (dolist (elem alist)
+    (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 &optional type)
+  "Say whether HANDLE can be displayed inline.
+TYPE is the mime-type of the object; it defaults to the one given
+in HANDLE."
+  (unless type (setq type (mm-handle-media-type handle)))
+  (let ((alist mm-inline-media-tests)
+       test)
+    (while alist
+      (when (string-match (caar alist) type)
+       (setq test (caddar alist)
+             alist nil)
+       (setq test (funcall test handle)))
+      (pop alist))
+    test))
+
+(defun mm-inlined-p (handle)
+  "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))
+       (setq result t
+             methods nil)))
+    result))
+
+(defun mm-attachment-override-p (handle)
+  "Say whether HANDLE should have attachment behavior overridden."
+  (let ((types mm-attachment-override-types)
+       (type (mm-handle-media-type handle))
+       ty)
+    (catch 'found
+      (while (setq ty (pop types))
+       (when (and (string-match ty type)
+                  (mm-inlinable-p handle))
+         (throw 'found t))))))
+
+(defun mm-inline-override-p (handle)
+  "Say whether HANDLE should have inline behavior overridden."
+  (let ((types mm-inline-override-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-automatic-external-display-p (type)
+  "Return the user-defined method for TYPE."
+  (let ((methods mm-automatic-external-display)
+       method result)
+    (while (setq method (pop methods))
+      (when (string-match method type)
+       (setq result t
+             methods nil)))
+    result))
+
+(defun mm-destroy-part (handle)
+  "Destroy the data structures connected to HANDLE."
+  (when (listp handle)
+    (mm-remove-part handle)
+    (when (buffer-live-p (mm-handle-buffer handle))
+      (kill-buffer (mm-handle-buffer handle)))))
+
+(defun mm-handle-displayed-p (handle)
+  "Say whether HANDLE is displayed or not."
+  (mm-handle-undisplayer handle))
+
+;;;
+;;; Functions for outputting parts
+;;;
+
+(defmacro mm-with-part (handle &rest forms)
+  "Run FORMS in the temp buffer containing the contents of HANDLE."
+  ;; The handle-buffer's content is a sequence of bytes, not a sequence of
+  ;; chars, so the buffer should be unibyte.  It may happen that the
+  ;; handle-buffer is multibyte for some reason, in which case now is a good
+  ;; time to adjust it, since we know at this point that it should
+  ;; be unibyte.
+  `(let* ((handle ,handle))
+     (when (and (mm-handle-buffer handle)
+               (buffer-name (mm-handle-buffer handle)))
+       (with-temp-buffer
+        (mm-disable-multibyte)
+        (insert-buffer-substring (mm-handle-buffer handle))
+        (mm-decode-content-transfer-encoding
+         (mm-handle-encoding handle)
+         (mm-handle-media-type handle))
+        ,@forms))))
+(put 'mm-with-part 'lisp-indent-function 1)
+(put 'mm-with-part 'edebug-form-spec '(body))
+
+(defun mm-get-part (handle &optional no-cache)
+  "Return the contents of HANDLE as a string.
+If NO-CACHE is non-nil, cached contents of a message/external-body part
+are ignored."
+  (if (and (not no-cache)
+          (equal (mm-handle-media-type handle) "message/external-body"))
+      (progn
+       (unless (mm-handle-cache handle)
+         (mm-extern-cache-contents handle))
+       (with-current-buffer (mm-handle-buffer (mm-handle-cache handle))
+         (buffer-string)))
+    (mm-with-part handle
+      (buffer-string))))
+
+(defun mm-insert-part (handle &optional no-cache)
+  "Insert the contents of HANDLE in the current buffer.
+If NO-CACHE is non-nil, cached contents of a message/external-body part
+are ignored."
+  (let ((text (cond ((eq (mail-content-type-get (mm-handle-type handle)
+                                               'charset)
+                        'gnus-decoded)
+                    (with-current-buffer (mm-handle-buffer handle)
+                      (buffer-string)))
+                   ((mm-multibyte-p)
+                    (mm-string-to-multibyte (mm-get-part handle no-cache)))
+                   (t
+                    (mm-get-part handle no-cache)))))
+    (save-restriction
+      (widen)
+      (goto-char
+       (prog1
+          (point)
+        (if (and (eq (get-char-property (max (point-min) (1- (point))) 'face)
+                     'mm-uu-extract)
+                 (eq (get-char-property 0 'face text) 'mm-uu-extract))
+            ;; Separate the extracted parts that have the same faces.
+            (insert "\n" text)
+          (insert text)))))))
+
+(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 the option `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-file-name-delete-control (filename)
+  "Delete control characters from FILENAME."
+  (gnus-replace-in-string filename "[\x00-\x1f\x7f]" ""))
+
+(defun mm-file-name-delete-gotchas (filename)
+  "Delete shell gotchas from FILENAME."
+  (setq filename (gnus-replace-in-string filename "[<>|]" ""))
+  (gnus-replace-in-string filename "^[.-]+" ""))
+
+(defun mm-save-part (handle &optional prompt)
+  "Write HANDLE to a file.
+PROMPT overrides the default one used to ask user for a file name."
+  (let ((filename (or (mail-content-type-get
+                      (mm-handle-disposition handle) 'filename)
+                     (mail-content-type-get
+                      (mm-handle-type handle) 'name)))
+       file)
+    (when filename
+      (setq filename (gnus-map-function mm-file-name-rewrite-functions
+                                       (file-name-nondirectory filename))))
+    (while
+       (progn
+         (setq file
+               (read-file-name
+                (or prompt
+                    (format "Save MIME part to (default %s): "
+                            (or filename "")))
+                (or mm-default-directory default-directory)
+                (expand-file-name (or filename "")
+                                  (or mm-default-directory default-directory))))
+         (cond ((or (not file) (equal file ""))
+                (message "Please enter a file name")
+                t)
+               ((and (file-directory-p file)
+                     (not filename))
+                (message "Please enter a non-directory file name")
+                t)
+               (t nil)))
+      (sit-for 2)
+      (discard-input))
+    (if (file-directory-p file)
+       (setq file (expand-file-name filename file))
+      (setq file (expand-file-name
+                 file (or mm-default-directory default-directory))))
+    (setq mm-default-directory (file-name-directory file))
+    (and (or (not (file-exists-p file))
+            (yes-or-no-p (format "File %s already exists; overwrite? "
+                                 file)))
+        (progn
+          (mm-save-part-to-file handle file)
+          file))))
+
+(defun mm-add-meta-html-tag (handle &optional charset force-charset)
+  "Add meta html tag to specify CHARSET of HANDLE in the current buffer.
+CHARSET defaults to the one HANDLE specifies.  Existing meta tag that
+specifies charset will not be modified unless FORCE-CHARSET is non-nil.
+Return t if meta tag is added or replaced."
+  (when (equal (mm-handle-media-type handle) "text/html")
+    (when (or charset
+             (setq charset (mail-content-type-get (mm-handle-type handle)
+                                                  'charset)))
+      (setq charset (format "\
+<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">" charset))
+      (let ((case-fold-search t))
+       (goto-char (point-min))
+       (if (re-search-forward "\
+<meta\\s-+http-equiv=[\"']?content-type[\"']?\\s-+content=[\"']\
+text/\\(\\sw+\\)\\(?:;\\s-*charset=\\([^\"'>]+\\)\\)?[^>]*>" nil t)
+           (if (and (not force-charset)
+                    (match-beginning 2)
+                    (string-match "\\`html\\'" (match-string 1)))
+               ;; Don't modify existing meta tag.
+               nil
+             ;; Replace it with the one specifying charset.
+             (replace-match charset)
+             t)
+         (if (re-search-forward "<head>\\s-*" nil t)
+             (insert charset "\n")
+           (re-search-forward "<html\\(?:\\s-+[^>]+\\|\\s-*\\)>\\s-*" nil t)
+           (insert "<head>\n" charset "\n</head>\n"))
+         t)))))
+
+(defun mm-save-part-to-file (handle file)
+  (mm-with-unibyte-buffer
+    (mm-insert-part handle)
+    (mm-add-meta-html-tag handle)
+    (let ((current-file-modes (default-file-modes)))
+      (set-default-file-modes mm-attachment-file-modes)
+      (unwind-protect
+         ;; Don't re-compress .gz & al.  Arguably we should make
+         ;; `file-name-handler-alist' nil, but that would chop
+         ;; ange-ftp, which is reasonable to use here.
+         (mm-write-region (point-min) (point-max) file nil nil nil 'binary t)
+       (set-default-file-modes current-file-modes)))))
+
+(defun mm-pipe-part (handle &optional cmd)
+  "Pipe HANDLE to a process.
+Use CMD as the process."
+  (let ((name (mail-content-type-get (mm-handle-type handle) 'name))
+       (command (or cmd
+                    (gnus-read-shell-command
+                     "Shell command on MIME part: " mm-last-shell-command))))
+    (mm-with-unibyte-buffer
+      (mm-insert-part handle)
+      (mm-add-meta-html-tag handle)
+      (let ((coding-system-for-write 'binary))
+       (shell-command-on-region (point-min) (point-max) command nil)))))
+
+(autoload 'gnus-completing-read "gnus-util")
+
+(defun mm-interactively-view-part (handle)
+  "Display HANDLE using METHOD."
+  (let* ((type (mm-handle-media-type handle))
+        (methods
+         (mapcar (lambda (i) (cdr (assoc 'viewer i)))
+                 (mailcap-mime-info type 'all)))
+        (method (let ((minibuffer-local-completion-map
+                       mm-viewer-completion-map))
+                  (completing-read "Viewer: " methods))))
+    (when (string= method "")
+      (error "No method given"))
+    (if (string-match "^[^% \t]+$" method)
+       (setq method (concat method " %s")))
+    (mm-display-external handle method)))
+
+(defun mm-preferred-alternative (handles &optional preferred)
+  "Say which of HANDLES are preferred."
+  (let ((prec (if preferred (list preferred)
+               (mm-preferred-alternative-precedence handles)))
+       p h result type handle)
+    (while (setq p (pop prec))
+      (setq h handles)
+      (while h
+       (setq handle (car h))
+       (setq type (mm-handle-media-type handle))
+       (when (and (equal p type)
+                  (mm-automatic-display-p handle)
+                  (or (stringp (car handle))
+                      (not (mm-handle-disposition handle))
+                      (equal (car (mm-handle-disposition handle))
+                             "inline")))
+         (setq result handle
+               h nil
+               prec nil))
+       (pop h)))
+    result))
+
+(defun mm-preferred-alternative-precedence (handles)
+  "Return the precedence based on HANDLES and `mm-discouraged-alternatives'."
+  (setq handles (reverse handles))
+  (dolist (disc (reverse mm-discouraged-alternatives))
+    (dolist (handle (copy-sequence handles))
+      (when (string-match disc (mm-handle-media-type handle))
+       (setq handles (nconc (delete handle handles) (list handle))))))
+  ;; Remove empty parts.
+  (dolist (handle (copy-sequence handles))
+    (when (and (bufferp (mm-handle-buffer handle))
+              (not (with-current-buffer (mm-handle-buffer handle)
+                     (goto-char (point-min))
+                     (re-search-forward "[^ \t\n]" nil t))))
+      (setq handles (nconc (delete handle handles) (list handle)))))
+  (mapcar #'mm-handle-media-type handles))
+
+(defun mm-get-content-id (id)
+  "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))
+       spec)
+    ;; Allow some common translations.
+    (setq type
+         (cond
+          ((equal type "x-pixmap")
+           "xpm")
+          ((equal type "x-xbitmap")
+           "xbm")
+          ((equal type "x-portable-bitmap")
+           "pbm")
+          (t type)))
+    (or (mm-handle-cache handle)
+       (mm-with-unibyte-buffer
+         (mm-insert-part handle)
+         (prog1
+             (setq spec
+                   (ignore-errors
+                     ;; Avoid testing `make-glyph' since W3 may define
+                     ;; a bogus version of it.
+                     (if (fboundp 'create-image)
+                         (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)
+  (when (featurep 'xemacs)
+    (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 (mm-make-temp-file
+                  (expand-file-name "emm" mm-tmp-directory)
+                  nil ".xbm")))
+       (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)))))))
+
+(declare-function image-size "image.c" (spec &optional pixels frame))
+
+(defun mm-image-fit-p (handle)
+  "Say whether the image in HANDLE will fit the current window."
+  (let ((image (mm-get-image handle)))
+    (or (not image)
+       (if (featurep 'xemacs)
+           ;; XEmacs's glyphs can actually tell us about their width, so
+           ;; let's be nice and smart about them.
+           (or mm-inline-large-images
+               (and (<= (glyph-width image) (window-pixel-width))
+                    (<= (glyph-height image) (window-pixel-height))))
+         (let* ((size (image-size image))
+                (w (car size))
+                (h (cdr size)))
+           (or mm-inline-large-images
+               (and (<= h (1- (window-height))) ; Don't include mode line.
+                    (<= w (window-width)))))))))
+
+(defun mm-valid-image-format-p (format)
+  "Say whether FORMAT can be displayed natively by Emacs."
+  (cond
+   ;; Handle XEmacs
+   ((fboundp 'valid-image-instantiator-format-p)
+    (valid-image-instantiator-format-p format))
+   ;; Handle Emacs
+   ((fboundp 'image-type-available-p)
+    (and (display-graphic-p)
+        (image-type-available-p format)))
+   ;; Nobody else can do images yet.
+   (t
+    nil)))
+
+(defun mm-valid-and-fit-image-p (format handle)
+  "Say whether FORMAT can be displayed natively and HANDLE fits the window."
+  (and (mm-valid-image-format-p format)
+       (mm-image-fit-p handle)))
+
+(defun mm-find-part-by-type (handles type &optional notp recursive)
+  "Search in HANDLES for part with TYPE.
+If NOTP, returns first non-matching part.
+If RECURSIVE, search recursively."
+  (let (handle)
+    (while handles
+      (if (and recursive (stringp (caar handles)))
+         (if (setq handle (mm-find-part-by-type (cdar handles) type
+                                                notp recursive))
+             (setq handles nil))
+       (if (if notp
+               (not (equal (mm-handle-media-type (car handles)) type))
+             (equal (mm-handle-media-type (car handles)) type))
+           (setq handle (car handles)
+                 handles nil)))
+      (setq handles (cdr handles)))
+    handle))
+
+(defun mm-find-raw-part-by-type (ctl type &optional notp)
+  (goto-char (point-min))
+  (let* ((boundary (concat "--" (mm-handle-multipart-ctl-parameter ctl
+                                                                  'boundary)))
+        (close-delimiter (concat "^" (regexp-quote boundary) "--[ \t]*$"))
+        start
+        (end (save-excursion
+               (goto-char (point-max))
+               (if (re-search-backward close-delimiter nil t)
+                   (match-beginning 0)
+                 (point-max))))
+        result)
+    (setq boundary (concat "^" (regexp-quote boundary) "[ \t]*$"))
+    (while (and (not result)
+               (re-search-forward boundary end t))
+      (goto-char (match-beginning 0))
+      (when start
+       (save-excursion
+         (save-restriction
+           (narrow-to-region start (1- (point)))
+           (when (let* ((ct (mail-fetch-field "content-type"))
+                        (ctl (and ct (mail-header-parse-content-type ct))))
+                   (if notp
+                       (not (equal (car ctl) type))
+                     (equal (car ctl) type)))
+             (setq result (buffer-string))))))
+      (forward-line 1)
+      (setq start (point)))
+    (when (and (not result) start)
+      (save-excursion
+       (save-restriction
+         (narrow-to-region start end)
+         (when (let* ((ct (mail-fetch-field "content-type"))
+                      (ctl (and ct (mail-header-parse-content-type ct))))
+                 (if notp
+                     (not (equal (car ctl) type))
+                   (equal (car ctl) type)))
+           (setq result (buffer-string))))))
+    result))
+
+(defvar mm-security-handle nil)
+
+(defsubst mm-set-handle-multipart-parameter (handle parameter value)
+  ;; HANDLE could be a CTL.
+  (when handle
+    (put-text-property 0 (length (car handle)) parameter value
+                      (car handle))))
+
+(autoload 'mm-view-pkcs7 "mm-view")
+
+(defun mm-possibly-verify-or-decrypt (parts ctl &optional from)
+  (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 from))
+         (setq parts (mm-dissect-buffer t)))))
+     ((equal subtype "signed")
+      (unless (and (setq protocol
+                        (mm-handle-multipart-ctl-parameter ctl 'protocol))
+                  (not (equal protocol "multipart/mixed")))
+       ;; The message is broken or draft-ietf-openpgp-multsig-01.
+       (let ((protocols mm-verify-function-alist))
+         (while protocols
+           (if (and (or (not (setq functest (nth 3 (car protocols))))
+                        (funcall functest parts ctl))
+                    (mm-find-part-by-type parts (caar protocols) nil t))
+               (setq protocol (caar protocols)
+                     protocols nil)
+             (setq protocols (cdr protocols))))))
+      (setq func (nth 1 (assoc protocol mm-verify-function-alist)))
+      (when (cond
+            ((eq mm-verify-option 'never) nil)
+            ((eq mm-verify-option 'always) t)
+            ((eq mm-verify-option 'known)
+             (and func
+                  (or (not (setq functest
+                                 (nth 3 (assoc protocol
+                                               mm-verify-function-alist))))
+                      (funcall functest parts ctl))))
+            (t
+             (y-or-n-p
+              (format "Verify signed (%s) part? "
+                      (or (nth 2 (assoc protocol mm-verify-function-alist))
+                          (format "protocol=%s" protocol))))))
+       (save-excursion
+         (if func
+             (setq parts (funcall func parts ctl))
+           (mm-set-handle-multipart-parameter
+            mm-security-handle 'gnus-details
+            (format "Unknown sign protocol (%s)" protocol))))))
+     ((equal subtype "encrypted")
+      (unless (setq protocol
+                   (mm-handle-multipart-ctl-parameter ctl 'protocol))
+       ;; The message is broken.
+       (let ((parts parts))
+         (while parts
+           (if (assoc (mm-handle-media-type (car parts))
+                      mm-decrypt-function-alist)
+               (setq protocol (mm-handle-media-type (car parts))
+                     parts nil)
+             (setq parts (cdr parts))))))
+      (setq func (nth 1 (assoc protocol mm-decrypt-function-alist)))
+      (when (cond
+            ((eq mm-decrypt-option 'never) nil)
+            ((eq mm-decrypt-option 'always) t)
+            ((eq mm-decrypt-option 'known)
+             (and func
+                  (or (not (setq functest
+                                 (nth 3 (assoc protocol
+                                               mm-decrypt-function-alist))))
+                      (funcall functest parts ctl))))
+            (t
+             (y-or-n-p
+              (format "Decrypt (%s) part? "
+                      (or (nth 2 (assoc protocol mm-decrypt-function-alist))
+                          (format "protocol=%s" protocol))))))
+       (save-excursion
+         (if func
+             (setq parts (funcall func parts ctl))
+           (mm-set-handle-multipart-parameter
+            mm-security-handle 'gnus-details
+            (format "Unknown encrypt protocol (%s)" protocol))))))
+     (t nil))
+    parts))
+
+(defun mm-multiple-handles (handles)
+  (and (listp handles)
+       (> (length handles) 1)
+       (or (listp (car handles))
+          (stringp (car handles)))))
+
+(defun mm-complicated-handles (handles)
+  (and (listp (car handles))
+       (> (length handles) 1)))
+
+(defun mm-merge-handles (handles1 handles2)
+  (append
+   (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))))))
+
+(declare-function libxml-parse-html-region "xml.c"
+                 (start end &optional base-url discard-comments))
+(declare-function shr-insert-document "shr" (dom))
+(defvar shr-blocked-images)
+(defvar shr-use-fonts)
+(defvar gnus-inhibit-images)
+(autoload 'gnus-blocked-images "gnus-art")
+
+(defun mm-shr (handle)
+  ;; Require since we bind its variables.
+  (require 'shr)
+  (let ((article-buffer (current-buffer))
+       (shr-width (if (and (boundp 'shr-use-fonts)
+                           shr-use-fonts)
+                      nil
+                    fill-column))
+       (shr-content-function (lambda (id)
+                               (let ((handle (mm-get-content-id id)))
+                                 (when handle
+                                   (mm-with-part handle
+                                     (buffer-string))))))
+       shr-inhibit-images shr-blocked-images charset char)
+    (if (and (boundp 'gnus-summary-buffer)
+            (bufferp gnus-summary-buffer)
+            (buffer-name gnus-summary-buffer))
+       (with-current-buffer gnus-summary-buffer
+         (setq shr-inhibit-images gnus-inhibit-images
+               shr-blocked-images (gnus-blocked-images)))
+      (setq shr-inhibit-images gnus-inhibit-images
+           shr-blocked-images (gnus-blocked-images)))
+    (unless handle
+      (setq handle (mm-dissect-buffer t)))
+    (setq charset (mail-content-type-get (mm-handle-type handle) 'charset))
+    (save-restriction
+      (narrow-to-region (point) (point))
+      (shr-insert-document
+       (mm-with-part handle
+        (insert (prog1
+                    (if (and charset
+                             (setq charset
+                                   (mm-charset-to-coding-system charset
+                                                                nil t))
+                             (not (eq charset 'ascii)))
+                        (mm-decode-coding-string (buffer-string) charset)
+                      (mm-string-as-multibyte (buffer-string)))
+                  (erase-buffer)
+                  (mm-enable-multibyte)))
+        (goto-char (point-min))
+        (setq case-fold-search t)
+        (while (re-search-forward
+                "&#\\(?:x\\([89][0-9a-f]\\)\\|\\(1[2-5][0-9]\\)\\);" nil t)
+          (when (setq char
+                      (cdr (assq (if (match-beginning 1)
+                                     (string-to-number (match-string 1) 16)
+                                   (string-to-number (match-string 2)))
+                                 mm-extra-numeric-entities)))
+            (replace-match (char-to-string char))))
+        ;; Remove "soft hyphens".
+        (goto-char (point-min))
+        (while (search-forward "­" nil t)
+          (replace-match "" t t))
+        (libxml-parse-html-region (point-min) (point-max))))
+      (unless (bobp)
+       (insert "\n"))
+      (mm-convert-shr-links)
+      (mm-handle-set-undisplayer
+       handle
+       `(lambda ()
+         (let ((inhibit-read-only t))
+           (delete-region ,(point-min-marker)
+                          ,(point-max-marker))))))))
+
+(defvar shr-map)
+
+(autoload 'widget-convert-button "wid-edit")
+
+(defun mm-convert-shr-links ()
+  (let ((start (point-min))
+       end)
+    (while (and start
+               (< start (point-max)))
+      (when (setq start (text-property-not-all start (point-max) 'shr-url nil))
+       (setq end (next-single-property-change start 'shr-url nil (point-max)))
+       (widget-convert-button
+        'url-link start end
+        :help-echo (get-text-property start 'help-echo)
+        :keymap shr-map
+        (get-text-property start 'shr-url))
+       (put-text-property start end 'local-map nil)
+       (dolist (overlay (overlays-at start))
+         (overlay-put overlay 'face nil))
+       (setq start end)))))
+
+(defun mm-handle-filename (handle)
+  "Return filename of HANDLE if any."
+  (or (mail-content-type-get (mm-handle-type handle)
+                             'name)
+      (mail-content-type-get (mm-handle-disposition handle)
+                             'filename)))
+
+(provide 'mm-decode)
+
+;; Local Variables:
+;; coding: utf-8
+;; End:
+
+;;; mm-decode.el ends here
diff --git a/xemacs-packages/gnus/lisp/mm-encode.el b/xemacs-packages/gnus/lisp/mm-encode.el
new file mode 100644 (file)
index 0000000..6f80e01
--- /dev/null
@@ -0,0 +1,219 @@
+;;; mm-encode.el --- Functions for encoding MIME things
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;;     MORIOKA Tomohiko <morioka@jaist.ac.jp>
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(require 'mail-parse)
+(autoload 'mailcap-extension-to-mime "mailcap")
+(autoload 'mm-body-7-or-8 "mm-bodies")
+(autoload 'mm-long-lines-p "mm-bodies")
+
+(defcustom mm-content-transfer-encoding-defaults
+  '(("text/x-patch" 8bit)
+    ("text/.*" qp-or-base64)
+    ("message/rfc822" 8bit)
+    ("application/emacs-lisp" qp-or-base64)
+    ("application/x-emacs-lisp" qp-or-base64)
+    ("application/x-patch" 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.
+
+This list is only consulted when encoding MIME parts in the
+bodies -- not for the regular non-MIME-ish messages."
+  :type '(repeat (list (regexp :tag "MIME type")
+                      (choice :tag "encoding"
+                              (const 7bit)
+                              (const 8bit)
+                              (const qp-or-base64)
+                              (const quoted-printable)
+                              (const base64))))
+  :group 'mime)
+
+(defcustom mm-sign-option nil
+  "Option how to create signed parts.
+nil, use the default keys without asking;
+`guided', let you select signing keys from the menu."
+  :version "23.2" ;; No Gnus 0.12
+  :type '(choice (item guided)
+                (item :tag "default" nil))
+  :group 'mime-security)
+
+(defcustom mm-encrypt-option nil
+  "Option how to create encrypted parts.
+nil, use the default keys without asking;
+`guided', let you select recipients' keys from the menu."
+  :version "23.2" ;; No Gnus 0.12
+  :type '(choice (item guided)
+                (item :tag "default" nil))
+  :group 'mime-security)
+
+(defvar mm-use-ultra-safe-encoding nil
+  "If non-nil, use encodings aimed at Procrustean bed survival.
+
+This means that textual parts are encoded as quoted-printable if they
+contain lines longer than 76 characters or starting with \"From \" in
+the body.  Non-7bit encodings (8bit, binary) are generally disallowed.
+This is to reduce the probability that a broken MTA or MDA changes the
+message.
+
+This variable should never be set directly, but bound before a call to
+`mml-generate-mime' or similar functions.")
+
+(defun mm-insert-rfc822-headers (charset encoding)
+  "Insert text/plain headers with CHARSET and ENCODING."
+  (insert "MIME-Version: 1.0\n")
+  (insert "Content-Type: text/plain; charset="
+         (mail-quote-string (downcase (symbol-name charset))) "\n")
+  (insert "Content-Transfer-Encoding: "
+         (downcase (symbol-name encoding)) "\n"))
+
+(defun mm-insert-multipart-headers ()
+  "Insert multipart/mixed headers."
+  (let ((boundary "=-=-="))
+    (insert "MIME-Version: 1.0\n")
+    (insert "Content-Type: multipart/mixed; boundary=\"" boundary "\"\n")
+    boundary))
+
+;;;###autoload
+(defun mm-default-file-encoding (file)
+  "Return a default encoding for FILE."
+  (if (not (string-match "\\.[^.]+$" file))
+      "application/octet-stream"
+    (mailcap-extension-to-mime (match-string 0 file))))
+
+(defun mm-safer-encoding (encoding &optional type)
+  "Return an encoding similar to ENCODING but safer than it."
+  (cond
+   ((eq encoding '7bit) '7bit) ;; 7bit is considered safe.
+   ((memq encoding '(8bit quoted-printable))
+    ;; According to RFC2046, 5.2.1, RFC822 Subtype, "quoted-printable" is not
+    ;; a valid encoding for message/rfc822:
+    ;; No encoding other than "7bit", "8bit", or "binary" is permitted for the
+    ;; body of a "message/rfc822" entity.
+    (if (string= type "message/rfc822") '8bit 'quoted-printable))
+   ;; The remaining encodings are binary and base64 (and perhaps some
+   ;; non-standard ones), which are both turned into base64.
+   (t (if (string= type "message/rfc822") 'binary 'base64))))
+
+(defun mm-encode-content-transfer-encoding (encoding &optional type)
+  "Encode the current buffer with ENCODING for MIME type TYPE.
+ENCODING can be: nil (do nothing); one of `quoted-printable', `base64';
+`7bit', `8bit' or `binary' (all do nothing); a function to do the encoding."
+  (cond
+   ((eq encoding 'quoted-printable)
+    ;; This used to try to make a multibyte buffer unibyte.  That's
+    ;; completely wrong, since you'd get QP-encoded emacs-mule.  If
+    ;; this gets run on multibyte text it's an error that needs
+    ;; fixing, and the encoding function will signal an error.
+    ;; Likewise base64 below.
+    (quoted-printable-encode-region (point-min) (point-max) t))
+   ((eq encoding 'base64)
+    (when (string-match "\\`text/" type)
+      (goto-char (point-min))
+      (while (search-forward "\n" nil t)
+       (replace-match "\r\n" t t)))
+    (base64-encode-region (point-min) (point-max)))
+   ((memq encoding '(7bit 8bit binary))
+    ;; Do nothing.
+    )
+   ((null encoding)
+    ;; Do nothing.
+    )
+   ;; Fixme: Ignoring errors here looks bogus.
+   ((functionp encoding)
+    (ignore-errors (funcall encoding (point-min) (point-max))))
+   (t
+    (error "Unknown encoding %s" encoding))))
+
+(defun mm-encode-buffer (type &optional encoding)
+  "Encode the buffer which contains data of MIME type TYPE by ENCODING.
+TYPE is a string or a list of the components.
+The optional ENCODING overrides the encoding determined according to
+TYPE and `mm-content-transfer-encoding-defaults'.
+The encoding used is returned."
+  (let ((mime-type (if (stringp type) type (car type))))
+    (mm-encode-content-transfer-encoding
+     (or encoding
+        (setq encoding (or (and (listp type)
+                                (cadr (assq 'encoding type)))
+                           (mm-content-transfer-encoding mime-type))))
+     mime-type)
+    encoding))
+
+(defun mm-insert-headers (type encoding &optional file)
+  "Insert headers for TYPE."
+  (insert "Content-Type: " type)
+  (when file
+    (insert ";\n\tname=\"" (file-name-nondirectory file) "\""))
+  (insert "\n")
+  (insert (format "Content-Transfer-Encoding: %s\n" encoding))
+  (insert "Content-Disposition: inline")
+  (when file
+    (insert ";\n\tfilename=\"" (file-name-nondirectory file) "\""))
+  (insert "\n")
+  (insert "\n"))
+
+(defun mm-content-transfer-encoding (type)
+  "Return a CTE suitable for TYPE to encode the current buffer."
+  (let ((rules mm-content-transfer-encoding-defaults))
+    (catch 'found
+      (while rules
+       (when (string-match (caar rules) type)
+         (throw 'found
+                (let ((encoding
+                       (if (eq (cadr (car rules)) 'qp-or-base64)
+                           (mm-qp-or-base64)
+                         (cadr (car rules)))))
+                  (if mm-use-ultra-safe-encoding
+                      (mm-safer-encoding encoding type)
+                    encoding))))
+       (pop rules)))))
+
+(defun mm-qp-or-base64 ()
+  "Return the type with which to encode the buffer.
+This is either `base64' or `quoted-printable'."
+  (if (equal mm-use-ultra-safe-encoding '(sign . "pgp"))
+      ;; perhaps not always accurate?
+      'quoted-printable
+    (save-excursion
+      (let ((limit (min (point-max) (+ 2000 (point-min))))
+           (n8bit 0))
+       (goto-char (point-min))
+       (skip-chars-forward "\x20-\x7f\r\n\t" limit)
+       (while (< (point) limit)
+         (incf n8bit)
+         (forward-char 1)
+         (skip-chars-forward "\x20-\x7f\r\n\t" limit))
+       (if (or (< (* 6 n8bit) (- limit (point-min)))
+               ;; Don't base64, say, a short line with a single
+               ;; non-ASCII char when splitting parts by charset.
+               (= n8bit 1))
+           'quoted-printable
+         'base64)))))
+
+(provide 'mm-encode)
+
+;;; mm-encode.el ends here
diff --git a/xemacs-packages/gnus/lisp/mm-extern.el b/xemacs-packages/gnus/lisp/mm-extern.el
new file mode 100644 (file)
index 0000000..2ba108d
--- /dev/null
@@ -0,0 +1,165 @@
+;;; mm-extern.el --- showing message/external-body
+
+;; Copyright (C) 2000-2016 Free Software Foundation, Inc.
+
+;; Author: Shenghuo Zhu <zsh@cs.rochester.edu>
+;; Keywords: message external-body
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'mm-util)
+(require 'mm-decode)
+(require 'mm-url)
+
+(defvar gnus-article-mime-handles)
+
+(defvar mm-extern-function-alist
+  '((local-file . mm-extern-local-file)
+    (url . mm-extern-url)
+    (anon-ftp . mm-extern-anon-ftp)
+    (ftp . mm-extern-ftp)
+;;;     (tftp . mm-extern-tftp)
+    (mail-server . mm-extern-mail-server)
+;;;     (afs . mm-extern-afs))
+    ))
+
+(defvar mm-extern-anonymous "anonymous")
+
+(defun mm-extern-local-file (handle)
+  (erase-buffer)
+  (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"))
+    (mm-disable-multibyte)
+    (if (file-exists-p name)
+       (mm-insert-file-contents name nil nil nil nil t)
+      (error "File %s is gone" name))))
+
+(defun mm-extern-url (handle)
+  (erase-buffer)
+  (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"))
+    (mm-disable-multibyte)
+    (mm-url-insert-file-contents url)
+    (setq buffer-file-name name)))
+
+(defun mm-extern-anon-ftp (handle)
+  (erase-buffer)
+  (let* ((params (cdr (mm-handle-type handle)))
+        (name (cdr (assq 'name params)))
+        (site (cdr (assq 'site params)))
+        (directory (cdr (assq 'directory params)))
+        (mode (cdr (assq 'mode params)))
+        (path (concat "/" (or mm-extern-anonymous
+                              (read-string (format "ID for %s: " site)))
+                      "@" site ":" directory "/" name))
+        (coding-system-for-read mm-binary-coding-system))
+    (unless name
+      (error "The filename is not specified"))
+    (mm-disable-multibyte)
+    (mm-insert-file-contents path nil nil nil nil t)))
+
+(defun mm-extern-ftp (handle)
+  (let (mm-extern-anonymous)
+    (mm-extern-anon-ftp handle)))
+
+(declare-function message-goto-body "message" ())
+
+(defun mm-extern-mail-server (handle)
+  (require 'message)
+  (let* ((params (cdr (mm-handle-type handle)))
+        (server (cdr (assq 'server params)))
+        (subject (or (cdr (assq 'subject params)) "none"))
+        (buf (current-buffer))
+        info)
+    (if (y-or-n-p (format "Send a request message to %s? " server))
+       (save-window-excursion
+         (message-mail server subject)
+         (message-goto-body)
+         (delete-region (point) (point-max))
+         (insert-buffer-substring buf)
+         (message "Requesting external body...")
+         (message-send-and-exit)
+         (setq info "Request is sent.")
+         (message info))
+      (setq info "Request is not sent."))
+    (goto-char (point-min))
+    (insert "[" info "]\n\n")))
+
+;;;###autoload
+(defun mm-extern-cache-contents (handle)
+  "Put the external-body part of HANDLE into its cache."
+  (let* ((access-type (cdr (assq 'access-type
+                                (cdr (mm-handle-type handle)))))
+        (func (cdr (assq (intern
+                          (downcase
+                           (or access-type
+                               (error "Couldn't find access type"))))
+                         mm-extern-function-alist)))
+        handles)
+    (unless func
+      (error "Access type (%s) is not supported" access-type))
+    (mm-with-part handle
+      (goto-char (point-max))
+      (insert "\n\n")
+      ;; It should be just a single MIME handle.
+      (setq handles (mm-dissect-buffer t)))
+    (unless (bufferp (car handles))
+      (mm-destroy-parts handles)
+      (error "Multipart external body is not supported"))
+    (with-current-buffer (mm-handle-buffer handles)
+      (let (good)
+       (unwind-protect
+           (progn
+             (funcall func handle)
+             (setq good t))
+         (unless good
+           (mm-destroy-parts handles))))
+      (mm-handle-set-cache handle handles))
+    (setq gnus-article-mime-handles
+         (mm-merge-handles gnus-article-mime-handles handles))))
+
+;;;###autoload
+(defun mm-inline-external-body (handle &optional no-display)
+  "Show the external-body part of HANDLE.
+This function replaces the buffer of HANDLE with a buffer contains
+the entire message.
+If NO-DISPLAY is nil, display it. Otherwise, do nothing after replacing."
+  (unless (mm-handle-cache handle)
+    (mm-extern-cache-contents handle))
+  (unless no-display
+    (save-excursion
+      (save-restriction
+       (narrow-to-region (point) (point))
+       (mm-display-part (mm-handle-cache handle))))
+    ;; Move undisplayer added to the cached handle to the parent.
+    (mm-handle-set-undisplayer
+     handle (mm-handle-undisplayer (mm-handle-cache handle)))
+    (mm-handle-set-undisplayer (mm-handle-cache handle) nil)))
+
+(provide 'mm-extern)
+
+;;; mm-extern.el ends here
diff --git a/xemacs-packages/gnus/lisp/mm-partial.el b/xemacs-packages/gnus/lisp/mm-partial.el
new file mode 100644 (file)
index 0000000..523a53b
--- /dev/null
@@ -0,0 +1,150 @@
+;;; mm-partial.el --- showing message/partial
+
+;; Copyright (C) 2000-2016 Free Software Foundation, Inc.
+
+;; Author: Shenghuo Zhu <zsh@cs.rochester.edu>
+;; Keywords: message partial
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'gnus-sum)
+(require 'mm-util)
+(require 'mm-decode)
+
+(defun mm-partial-find-parts (id &optional art)
+  (let ((headers (with-current-buffer gnus-summary-buffer
+                  gnus-newsgroup-headers))
+       phandles header)
+    (while (setq header (pop headers))
+      (unless (eq (aref header 0) art)
+       (mm-with-unibyte-buffer
+         (gnus-request-article-this-buffer (aref header 0)
+                                           gnus-newsgroup-name)
+         (when (search-forward id nil t)
+           (let ((nhandles (mm-dissect-buffer
+                            nil gnus-article-loose-mime)) nid)
+             (if (consp (car nhandles))
+                 (mm-destroy-parts nhandles)
+               (setq nid (cdr (assq 'id
+                                    (cdr (mm-handle-type nhandles)))))
+               (if (not (equal id nid))
+                   (mm-destroy-parts nhandles)
+                 (push nhandles phandles))))))))
+    phandles))
+
+;;;###autoload
+(defun mm-inline-partial (handle &optional no-display)
+  "Show the partial part of HANDLE.
+This function replaces the buffer of HANDLE with a buffer contains
+the entire message.
+If NO-DISPLAY is nil, display it. Otherwise, do nothing after replacing."
+  (let ((id (cdr (assq 'id (cdr (mm-handle-type handle)))))
+       phandles
+       (b (point)) (n 1) total
+       phandle nn ntotal
+       gnus-displaying-mime handles buffer)
+    (unless (mm-handle-cache handle)
+      (unless id
+       (error "Can not find message/partial id"))
+      (setq phandles
+           (sort (cons handle
+                       (mm-partial-find-parts
+                        id
+                        (with-current-buffer gnus-summary-buffer
+                          (gnus-summary-article-number))))
+                 #'(lambda (a b)
+                     (let ((anumber (string-to-number
+                                     (cdr (assq 'number
+                                                (cdr (mm-handle-type a))))))
+                           (bnumber (string-to-number
+                                     (cdr (assq 'number
+                                                (cdr (mm-handle-type b)))))))
+                       (< anumber bnumber)))))
+      (setq gnus-article-mime-handles
+           (mm-merge-handles gnus-article-mime-handles phandles))
+      (with-current-buffer (generate-new-buffer " *mm*")
+       (while (setq phandle (pop phandles))
+         (setq nn (string-to-number
+                   (cdr (assq 'number
+                              (cdr (mm-handle-type phandle))))))
+         (setq ntotal (string-to-number
+                       (cdr (assq 'total
+                                  (cdr (mm-handle-type phandle))))))
+         (if ntotal
+             (if total
+                 (unless (eq total ntotal)
+                 (error "The numbers of total are different"))
+               (setq total ntotal)))
+         (unless (< nn n)
+           (unless (eq nn n)
+             (error "Missing part %d" n))
+           (mm-insert-part phandle)
+           (goto-char (point-max))
+           (when (not (eq 0 (skip-chars-backward "\r\n")))
+             ;; remove tail blank spaces except one
+             (if (looking-at "\r?\n")
+                 (goto-char (match-end 0)))
+             (delete-region (point) (point-max)))
+           (setq n (+ n 1))))
+       (unless total
+         (error "Don't known the total number of"))
+       (if (<= n total)
+           (error "Missing part %d" n))
+       (kill-buffer (mm-handle-buffer handle))
+       (goto-char (point-min))
+       (let ((point (if (search-forward "\n\n" nil t)
+                        (1- (point))
+                      (point-max))))
+         (goto-char (point-min))
+         (unless (re-search-forward "^mime-version:" point t)
+           (insert "MIME-Version: 1.0\n")))
+       (setcar handle (current-buffer))
+       (mm-handle-set-cache handle t)))
+    (unless no-display
+      (save-excursion
+       (save-restriction
+         (narrow-to-region b b)
+         (mm-insert-part handle)
+         (let (gnus-article-mime-handles)
+           (run-hooks 'gnus-article-decode-hook)
+           (gnus-article-prepare-display)
+           (setq handles gnus-article-mime-handles))
+         (when handles
+           ;; It is in article buffer.
+           (setq gnus-article-mime-handles
+                 (mm-merge-handles gnus-article-mime-handles handles)))
+         (mm-handle-set-undisplayer
+          handle
+          `(lambda ()
+             (let (buffer-read-only)
+               (condition-case nil
+                   ;; This is only valid on XEmacs.
+                   (mapcar (lambda (prop)
+                           (remove-specifier
+                            (face-property 'default prop) (current-buffer)))
+                           '(background background-pixmap foreground))
+                 (error nil))
+               (delete-region ,(point-min-marker) ,(point-max-marker))))))))))
+
+(provide 'mm-partial)
+
+;;; mm-partial.el ends here
diff --git a/xemacs-packages/gnus/lisp/mm-url.el b/xemacs-packages/gnus/lisp/mm-url.el
new file mode 100644 (file)
index 0000000..e5c43fd
--- /dev/null
@@ -0,0 +1,469 @@
+;;; mm-url.el --- a wrapper of url functions/commands for Gnus
+
+;; Copyright (C) 2001-2016 Free Software Foundation, Inc.
+
+;; Author: Shenghuo Zhu <zsh@cs.rochester.edu>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Some code is stolen from w3 and url packages. Some are moved from
+;; nnweb.
+
+;; TODO: Support POST, cookie.
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'mm-util)
+(require 'gnus)
+
+(defvar url-current-object)
+(defvar url-package-name)
+(defvar url-package-version)
+
+(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)
+                                 (error nil)))
+  "*If non-nil, use external grab program `mm-url-program'."
+  :version "22.1"
+  :type 'boolean
+  :group 'mm-url)
+
+(defvar mm-url-predefined-programs
+  '((wget "wget" "--user-agent=mm-url" "-q" "-O" "-")
+    (w3m  "w3m" "-dump_source")
+    (lynx "lynx" "-source")
+    (curl "curl" "--silent" "--user-agent" "mm-url" "--location")))
+
+(defcustom mm-url-program
+  (cond
+   ((executable-find "wget") 'wget)
+   ((executable-find "w3m") 'w3m)
+   ((executable-find "lynx") 'lynx)
+   ((executable-find "curl") 'curl)
+   (t "GET"))
+  "The url grab program.
+Likely values are `wget', `w3m', `lynx' and `curl'."
+  :version "22.1"
+  :type '(choice
+         (symbol :tag "wget" wget)
+         (symbol :tag "w3m" w3m)
+         (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'."
+  :version "22.1"
+  :type '(repeat string)
+  :group 'mm-url)
+
+\f
+;;; Internal variables
+
+;; 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-load-url ()
+  "Load `url-insert-file-contents'."
+  (unless (condition-case ()
+             (progn
+               (require 'url-handlers)
+               (require 'url-parse)
+               (require 'url-vars))
+           (error nil))
+    (require 'url)))
+
+;;;###autoload
+(defun mm-url-insert-file-contents (url)
+  "Insert file contents of URL.
+If `mm-url-use-external' is non-nil, use `mm-url-program'."
+  (if mm-url-use-external
+      (progn
+       (if (string-match "^file:/+" url)
+           (insert-file-contents (substring url (1- (match-end 0))))
+         (mm-url-insert-file-contents-external url))
+       (goto-char (point-min))
+       (if (fboundp 'url-generic-parse-url)
+           (setq url-current-object
+                 (url-generic-parse-url url)))
+       (list url (buffer-size)))
+    (mm-url-load-url)
+    (let ((name buffer-file-name)
+         (url-request-extra-headers
+          ;; ISTM setting a Connection header was a workaround for
+          ;; older versions of url included with w3, but it does more
+          ;; harm than good with the one shipped with Emacs. --ansel
+          (if (not (and (boundp 'url-version)
+                        (equal url-version "Emacs")))
+              (list (cons "Connection" "Close"))))
+         result)
+      (setq result (url-insert-file-contents url))
+      (save-excursion
+       (goto-char (point-min))
+       (while (re-search-forward "\r 1000\r ?" nil t)
+         (replace-match "")))
+      (setq buffer-file-name name)
+      (if (and (fboundp 'url-generic-parse-url)
+              (listp result))
+         (setq url-current-object (url-generic-parse-url
+                                   (car result))))
+      result)))
+
+;;;###autoload
+(defun mm-url-insert-file-contents-external (url)
+  "Insert file contents of URL using `mm-url-program'."
+  (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))))
+    (unless (eq 0 (apply 'call-process program nil t nil args))
+      (error "Couldn't fetch %s" url))))
+
+(defvar mm-url-timeout 30
+  "The number of seconds before timing out an URL fetch.")
+
+(defvar mm-url-retries 10
+  "The number of retries after timing out when fetching an URL.")
+
+(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."
+  (let ((times mm-url-retries)
+       (done nil)
+       (first t)
+       result)
+    (while (and (not (zerop (decf times)))
+               (not done))
+      (with-timeout (mm-url-timeout)
+       (unless first
+         (message "Trying again (%s)..." (- mm-url-retries times)))
+       (setq first nil)
+       (if follow-refresh
+           (save-restriction
+             (narrow-to-region (point) (point))
+             (mm-url-insert-file-contents url)
+             (goto-char (point-min))
+             (when (re-search-forward
+                    "<meta[ \t\r\n]*http-equiv=\"Refresh\"[^>]*URL=\\([^\"]+\\)\"" nil t)
+               (let ((url (match-string 1)))
+                 (delete-region (point-min) (point-max))
+                 (setq result (mm-url-insert url t)))))
+         (setq result (mm-url-insert-file-contents url)))
+       (setq done t)))
+    result))
+
+(defun mm-url-decode-entities ()
+  "Decode all HTML entities."
+  (goto-char (point-min))
+  (while (re-search-forward "&\\(#[0-9]+\\|#x[0-9a-f]+\\|[a-z]+[0-9]*\\);"
+                           nil t)
+    (let* ((entity (match-string 1))
+          (elem (if (eq (aref entity 0) ?\#)
+                    (let ((c
+                           ;; Hex number: &#x3212
+                           (if (eq (aref entity 1) ?x)
+                               (string-to-number (substring entity 2)
+                                                 16)
+                             ;; Decimal number: &#23
+                             (string-to-number (substring entity 1)))))
+                      (setq c (or (cdr (assq c mm-extra-numeric-entities))
+                                  (mm-ucs-to-char c)))
+                      (if (mm-char-or-char-int-p c) c ?#))
+                  (or (cdr (assq (intern entity)
+                                 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 &nbsp; 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-string)))
+
+(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)))
+
+  (if chunk
+      (mapconcat
+       (lambda (char)
+        (cond
+         ((= char ?  ) "+")
+         ((memq char mm-url-unreserved-chars) (char-to-string char))
+         (t (upcase (format "%%%02x" char)))))
+       (mm-encode-coding-string chunk
+                               (if (fboundp 'find-coding-systems-string)
+                                   (car (find-coding-systems-string chunk))
+                                 buffer-file-coding-system))
+       "")))
+
+(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 "&"))
+
+(autoload 'mml-compute-boundary "mml")
+
+(defun mm-url-encode-multipart-form-data (pairs &optional boundary)
+  "Return PAIRS encoded in multipart/form-data."
+  ;; RFC1867
+  ;; Get a good boundary
+  (unless boundary
+    (setq boundary (mml-compute-boundary '())))
+  (concat
+   ;; Start with the boundary
+   "--" boundary "\r\n"
+   ;; Create name value pairs
+   (mapconcat
+    'identity
+    ;; Delete any returned items that are empty
+    (delq nil
+          (mapcar (lambda (data)
+                    (cond ((equal (car data) "file")
+                           ;; For each pair
+                           (format
+                            ;; Encode the name
+                            "Content-Disposition: form-data; name=%S; filename=%S\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Transfer-Encoding: binary\r\n\r\n%s"
+                            (cdr (assoc "name" (cdr data))) (cdr (assoc "filename" (cdr data)))
+                            (cond ((stringp (cdr (assoc "filedata" (cdr data))))
+                                   (cdr (assoc "filedata" (cdr data))))
+                                  ((integerp (cdr (assoc "filedata" (cdr data))))
+                                   (number-to-string (cdr (assoc "filedata" (cdr data))))))))
+                          ((equal (car data) "submit")
+                           "Content-Disposition: form-data; name=\"submit\"\r\n\r\nSubmit\r\n")
+                          (t
+                           (format
+                            "Content-Disposition: form-data;name=%S\r\n\r\n%s\r\n"
+                            (car data) (concat (mm-url-form-encode-xwfu (cdr data)))
+                            ))))
+                  pairs))
+    ;; use the boundary as a separator
+    (concat "\r\n--" boundary "\r\n"))
+   ;; put a boundary at the end.
+   "--" boundary "--\r\n"))
+
+(defun mm-url-remove-markup ()
+  "Remove all HTML markup, leaving just plain text."
+  (goto-char (point-min))
+  (while (search-forward "<!--" nil t)
+    (delete-region (match-beginning 0)
+                   (or (search-forward "-->" nil t)
+                       (point-max))))
+  (goto-char (point-min))
+  (while (re-search-forward "<[^>]+>" nil t)
+    (replace-match "" t t)))
+
+(provide 'mm-url)
+
+;;; mm-url.el ends here
diff --git a/xemacs-packages/gnus/lisp/mm-util.el b/xemacs-packages/gnus/lisp/mm-util.el
new file mode 100644 (file)
index 0000000..fb97479
--- /dev/null
@@ -0,0 +1,1669 @@
+;;; mm-util.el --- Utility functions for Mule and low level things
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;;     MORIOKA Tomohiko <morioka@jaist.ac.jp>
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(require 'mail-prsvr)
+
+(eval-and-compile
+  (if (featurep 'xemacs)
+      (unless (ignore-errors
+               (require 'timer-funcs))
+       (require 'timer))
+    (require 'timer)))
+
+(defvar mm-mime-mule-charset-alist )
+;; Note this is not presently used on Emacs >= 23, which is good,
+;; since it means standalone message-mode (which requires mml and
+;; hence mml-util) does not load gnus-util.
+(autoload 'gnus-completing-read "gnus-util")
+
+;; Emulate functions that are not available in every (X)Emacs version.
+;; The name of a function is prefixed with mm-, like `mm-char-int' for
+;; `char-int' that is a native XEmacs function, not available in Emacs.
+;; Gnus programs all should use mm- functions, not the original ones.
+(eval-and-compile
+  (mapc
+   (lambda (elem)
+     (let ((nfunc (intern (format "mm-%s" (car elem)))))
+       (if (fboundp (car elem))
+          (defalias nfunc (car elem))
+        (defalias nfunc (cdr elem)))))
+   `(;; `coding-system-list' is not available in XEmacs 21.4 built
+     ;; without the `file-coding' feature.
+     (coding-system-list . ignore)
+     ;; `char-int' is an XEmacs function, not available in Emacs.
+     (char-int . identity)
+     ;; `coding-system-equal' is an Emacs function, not available in XEmacs.
+     (coding-system-equal . equal)
+     ;; `annotationp' is an XEmacs function, not available in Emacs.
+     (annotationp . ignore)
+     ;; `set-buffer-file-coding-system' is not available in XEmacs 21.4
+     ;; built without the `file-coding' feature.
+     (set-buffer-file-coding-system . ignore)
+     ;; `read-charset' is an Emacs function, not available in XEmacs.
+     (read-charset
+      . ,(lambda (prompt)
+          "Return a charset."
+          (intern
+           (gnus-completing-read
+            prompt
+            (mapcar (lambda (e) (symbol-name (car e)))
+                    mm-mime-mule-charset-alist)
+            t))))
+     ;; `subst-char-in-string' is not available in XEmacs 21.4.
+     (subst-char-in-string
+      . ,(lambda (from to string &optional inplace)
+          ;; stolen (and renamed) from nnheader.el
+          "Replace characters in STRING from FROM to TO.
+         Unless optional argument INPLACE is non-nil, return a new string."
+          (let ((string (if inplace string (copy-sequence string)))
+                (len (length string))
+                (idx 0))
+            ;; Replace all occurrences of FROM with TO.
+            (while (< idx len)
+              (when (= (aref string idx) from)
+                (aset string idx to))
+              (setq idx (1+ idx)))
+            string)))
+     ;; `replace-in-string' is an XEmacs function, not available in Emacs.
+     (replace-in-string
+      . ,(lambda (string regexp rep &optional literal)
+          "See `replace-regexp-in-string', only the order of args differs."
+          (replace-regexp-in-string regexp rep string nil literal)))
+     ;; `string-as-unibyte' is an Emacs function, not available in XEmacs.
+     (string-as-unibyte . identity)
+     ;; `string-make-unibyte' is an Emacs function, not available in XEmacs.
+     (string-make-unibyte . identity)
+     ;; string-as-multibyte often doesn't really do what you think it does.
+     ;; Example:
+     ;;    (aref (string-as-multibyte "\201") 0) -> 129 (aka ?\201)
+     ;;    (aref (string-as-multibyte "\300") 0) -> 192 (aka ?\300)
+     ;;    (aref (string-as-multibyte "\300\201") 0) -> 192 (aka ?\300)
+     ;;    (aref (string-as-multibyte "\300\201") 1) -> 129 (aka ?\201)
+     ;; but
+     ;;    (aref (string-as-multibyte "\201\300") 0) -> 2240
+     ;;    (aref (string-as-multibyte "\201\300") 1) -> <error>
+     ;; Better use string-to-multibyte or encode-coding-string.
+     ;; If you really need string-as-multibyte somewhere it's usually
+     ;; because you're using the internal emacs-mule representation (maybe
+     ;; because you're using string-as-unibyte somewhere), which is
+     ;; generally a problem in itself.
+     ;; Here is an approximate equivalence table to help think about it:
+     ;; (string-as-multibyte s)   ~= (decode-coding-string s 'emacs-mule)
+     ;; (string-to-multibyte s)   ~= (decode-coding-string s 'binary)
+     ;; (string-make-multibyte s) ~= (decode-coding-string s locale-coding-system)
+     ;; `string-as-multibyte' is an Emacs function, not available in XEmacs.
+     (string-as-multibyte . identity)
+     ;; `multibyte-string-p' is an Emacs function, not available in XEmacs.
+     (multibyte-string-p . ignore)
+     ;; `insert-byte' is available only in Emacs 23.1 or greater.
+     (insert-byte . insert-char)
+     ;; `multibyte-char-to-unibyte' is an Emacs function, not available
+     ;; in XEmacs.
+     (multibyte-char-to-unibyte . identity)
+     ;; `set-buffer-multibyte' is an Emacs function, not available in XEmacs.
+     (set-buffer-multibyte . ignore)
+     ;; `substring-no-properties' is available only in Emacs 22.1 or greater.
+     (substring-no-properties
+      . ,(lambda (string &optional from to)
+          "Return a substring of STRING, without text properties.
+It starts at index FROM and ending before TO.
+TO may be nil or omitted; then the substring runs to the end of STRING.
+If FROM is nil or omitted, the substring starts at the beginning of STRING.
+If FROM or TO is negative, it counts from the end.
+
+With one argument, just copy STRING without its properties."
+          (setq string (substring string (or from 0) to))
+          (set-text-properties 0 (length string) nil string)
+          string))
+     ;; `line-number-at-pos' is available only in Emacs 22.1 or greater
+     ;; and XEmacs 21.5.
+     (line-number-at-pos
+      . ,(lambda (&optional pos)
+          "Return (narrowed) buffer line number at position POS.
+If POS is nil, use current buffer location.
+Counting starts at (point-min), so the value refers
+to the contents of the accessible portion of the buffer."
+          (let ((opoint (or pos (point))) start)
+            (save-excursion
+              (goto-char (point-min))
+              (setq start (point))
+              (goto-char opoint)
+              (forward-line 0)
+              (1+ (count-lines start (point))))))))))
+
+;; `special-display-p' is an Emacs function, not available in XEmacs.
+(defalias 'mm-special-display-p
+  (if (featurep 'emacs)
+      'special-display-p
+    (lambda (buffer-name)
+      "Returns non-nil if a buffer named BUFFER-NAME gets a special frame."
+      (and special-display-function
+          (or (and (member buffer-name special-display-buffer-names) t)
+              (cdr (assoc buffer-name special-display-buffer-names))
+              (catch 'return
+                (dolist (elem special-display-regexps)
+                  (and (stringp elem)
+                       (string-match elem buffer-name)
+                       (throw 'return t))
+                  (and (consp elem)
+                       (stringp (car elem))
+                       (string-match (car elem) buffer-name)
+                       (throw 'return (cdr elem))))))))))
+
+;; `decode-coding-string', `encode-coding-string', `decode-coding-region'
+;; and `encode-coding-region' are available in Emacs and XEmacs built with
+;; the `file-coding' feature, but the XEmacs versions treat nil, that is
+;; given as the `coding-system' argument, as the `binary' coding system.
+(eval-and-compile
+  (if (featurep 'xemacs)
+      (if (featurep 'file-coding)
+         (progn
+           (defun mm-decode-coding-string (str coding-system)
+             (if coding-system
+                 (decode-coding-string str coding-system)
+               str))
+           (defun mm-encode-coding-string (str coding-system)
+             (if coding-system
+                 (encode-coding-string str coding-system)
+               str))
+           (defun mm-decode-coding-region (start end coding-system)
+             (if coding-system
+                 (decode-coding-region start end coding-system)))
+           (defun mm-encode-coding-region (start end coding-system)
+             (if coding-system
+                 (encode-coding-region start end coding-system))))
+       (defun mm-decode-coding-string (str coding-system) str)
+       (defun mm-encode-coding-string (str coding-system) str)
+       (defalias 'mm-decode-coding-region 'ignore)
+       (defalias 'mm-encode-coding-region 'ignore))
+    (defalias 'mm-decode-coding-string 'decode-coding-string)
+    (defalias 'mm-encode-coding-string 'encode-coding-string)
+    (defalias 'mm-decode-coding-region 'decode-coding-region)
+    (defalias 'mm-encode-coding-region 'encode-coding-region)))
+
+;; `string-to-multibyte' is available only in Emacs.
+(defalias 'mm-string-to-multibyte (if (featurep 'xemacs)
+                                     'identity
+                                   'string-to-multibyte))
+
+;; `char-or-char-int-p' is an XEmacs function, not available in Emacs.
+(eval-and-compile
+  (defalias 'mm-char-or-char-int-p
+    (cond
+     ((fboundp 'char-or-char-int-p) 'char-or-char-int-p)
+     ((fboundp 'char-valid-p) 'char-valid-p)
+     (t 'identity))))
+
+;; `ucs-to-char' is a function that Mule-UCS provides.
+(eval-and-compile
+  (if (featurep 'xemacs)
+      (cond ((and (fboundp 'unicode-to-char) ;; XEmacs 21.5.
+                 (subrp (symbol-function 'unicode-to-char)))
+            (if (featurep 'mule)
+                (defalias 'mm-ucs-to-char 'unicode-to-char)
+              (defun mm-ucs-to-char (codepoint)
+                "Convert Unicode codepoint to character."
+                (or (unicode-to-char codepoint) ?#))))
+           ((featurep 'mule)
+            (defun mm-ucs-to-char (codepoint)
+              "Convert Unicode codepoint to character."
+              (if (fboundp 'ucs-to-char) ;; Mule-UCS is loaded.
+                  (progn
+                    (defalias 'mm-ucs-to-char
+                      (lambda (codepoint)
+                        "Convert Unicode codepoint to character."
+                        (condition-case nil
+                            (or (ucs-to-char codepoint) ?#)
+                          (error ?#))))
+                    (mm-ucs-to-char codepoint))
+                (condition-case nil
+                    (or (int-to-char codepoint) ?#)
+                  (error ?#)))))
+           (t
+            (defun mm-ucs-to-char (codepoint)
+              "Convert Unicode codepoint to character."
+              (condition-case nil
+                  (or (int-to-char codepoint) ?#)
+                (error ?#)))))
+    (if (let ((char (make-char 'japanese-jisx0208 36 34)))
+         (eq char (decode-char 'ucs char)))
+       ;; Emacs 23.
+       (defalias 'mm-ucs-to-char 'identity)
+      (defun mm-ucs-to-char (codepoint)
+       "Convert Unicode codepoint to character."
+       (or (decode-char 'ucs codepoint) ?#)))))
+
+;; Fixme:  This seems always to be used to read a MIME charset, so it
+;; should be re-named and fixed (in Emacs) to offer completion only on
+;; proper charset names (base coding systems which have a
+;; mime-charset defined).  XEmacs doesn't believe in mime-charset;
+;; test with
+;;   `(or (coding-system-get 'iso-8859-1 'mime-charset)
+;;        (coding-system-get 'iso-8859-1 :mime-charset))'
+;; Actually, there should be an `mm-coding-system-mime-charset'.
+(eval-and-compile
+  (defalias 'mm-read-coding-system
+    (if (featurep 'emacs) '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."
+           (gnus-completing-read
+            prompt (mapcar (lambda (s) (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."
+  (or mm-coding-system-list
+      (setq mm-coding-system-list (mm-coding-system-list))))
+
+(defun mm-coding-system-p (cs)
+  "Return non-nil if CS is a symbol naming a coding system.
+In XEmacs, also return non-nil if CS is a coding system object.
+If CS is available, return CS itself in Emacs, and return a coding
+system object in XEmacs."
+  (if (fboundp 'find-coding-system)
+      (and cs (find-coding-system cs))
+    (if (fboundp 'coding-system-p)
+       (when (coding-system-p cs)
+         cs)
+      ;; no-MULE XEmacs:
+      (car (memq cs (mm-get-coding-system-list))))))
+
+(defvar mm-charset-synonym-alist
+  `(
+    ;; Not in XEmacs, but it's not a proper MIME charset anyhow.
+    ,@(unless (mm-coding-system-p 'x-ctext)
+       '((x-ctext . ctext)))
+    ;; ISO-8859-15 is very similar to ISO-8859-1.  But it's _different_ in 8
+    ;; positions!
+    ,@(unless (mm-coding-system-p 'iso-8859-15)
+       '((iso-8859-15 . iso-8859-1)))
+    ;; BIG-5HKSCS is similar to, but different than, BIG-5.
+    ,@(unless (mm-coding-system-p 'big5-hkscs)
+       '((big5-hkscs . big5)))
+    ;; A Microsoft misunderstanding.
+    ,@(when (and (not (mm-coding-system-p 'unicode))
+                (mm-coding-system-p 'utf-16-le))
+       '((unicode . utf-16-le)))
+    ;; A Microsoft misunderstanding.
+    ,@(unless (mm-coding-system-p 'ks_c_5601-1987)
+       (if (mm-coding-system-p 'cp949)
+           '((ks_c_5601-1987 . cp949))
+         '((ks_c_5601-1987 . euc-kr))))
+    ;; Windows-31J is Windows Codepage 932.
+    ,@(when (and (not (mm-coding-system-p 'windows-31j))
+                (mm-coding-system-p 'cp932))
+       '((windows-31j . cp932)))
+    ;; Charset name: GBK, Charset aliases: CP936, MS936, windows-936
+    ;; http://www.iana.org/assignments/charset-reg/GBK
+    ;; Emacs 22.1 has cp936, but not gbk, so we alias it:
+    ,@(when (and (not (mm-coding-system-p 'gbk))
+                (mm-coding-system-p 'cp936))
+       '((gbk . cp936)))
+    ;; UTF8 is a bogus name for UTF-8
+    ,@(when (and (not (mm-coding-system-p 'utf8))
+                (mm-coding-system-p 'utf-8))
+       '((utf8 . utf-8)))
+    ;; ISO8859-1 is a bogus name for ISO-8859-1
+    ,@(when (and (not (mm-coding-system-p 'iso8859-1))
+                (mm-coding-system-p 'iso-8859-1))
+       '((iso8859-1 . iso-8859-1)))
+    ;; ISO_8859-1 is a bogus name for ISO-8859-1
+    ,@(when (and (not (mm-coding-system-p 'iso_8859-1))
+                (mm-coding-system-p 'iso-8859-1))
+       '((iso_8859-1 . iso-8859-1)))
+    )
+  "A mapping from unknown or invalid charset names to the real charset names.
+
+See `mm-codepage-iso-8859-list' and `mm-codepage-ibm-list'.")
+
+(defun mm-codepage-setup (number &optional alias)
+  "Create a coding system cpNUMBER.
+The coding system is created using `codepage-setup'.  If ALIAS is
+non-nil, an alias is created and added to
+`mm-charset-synonym-alist'.  If ALIAS is a string, it's used as
+the alias.  Else windows-NUMBER is used."
+  (interactive
+   (let ((completion-ignore-case t)
+        (candidates (if (fboundp 'cp-supported-codepages)
+                        (cp-supported-codepages)
+                      ;; Removed in Emacs 23 (unicode), so signal an error:
+                      (error "`codepage-setup' not present in this Emacs version"))))
+     (list (gnus-completing-read "Setup DOS Codepage" candidates
+                                 t nil nil "437"))))
+  (when alias
+    (setq alias (if (stringp alias)
+                   (intern alias)
+                 (intern (format "windows-%s" number)))))
+  (let* ((cp (intern (format "cp%s" number))))
+    (unless (mm-coding-system-p cp)
+      (if (fboundp 'codepage-setup)    ; silence compiler
+         (codepage-setup number)
+       (error "`codepage-setup' not present in this Emacs version")))
+    (when (and alias
+              ;; Don't add alias if setup of cp failed.
+              (mm-coding-system-p cp))
+      (add-to-list 'mm-charset-synonym-alist (cons alias cp)))))
+
+(defcustom mm-codepage-iso-8859-list
+  (list 1250 ;; 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.
+       '(1252 . 1) ;; Windows-1252 is a superset of iso-8859-1 (West
+                   ;; Europe).  See also `gnus-article-dumbquotes-map'.
+       '(1254 . 9) ;; Windows-1254 is a superset of iso-8859-9 (Turkish).
+       '(1255 . 8));; Windows-1255 is a superset of iso-8859-8 (Hebrew).
+  "A list of Windows codepage numbers and iso-8859 charset numbers.
+
+If an element is a number corresponding to a supported windows
+codepage, appropriate entries to `mm-charset-synonym-alist' are
+added by `mm-setup-codepage-iso-8859'.  An element may also be a
+cons cell where the car is a codepage number and the cdr is the
+corresponding number of an iso-8859 charset."
+  :type '(list (set :inline t
+                   (const 1250 :tag "Central and East European")
+                   (const (1252 . 1) :tag "West European")
+                   (const (1254 . 9) :tag "Turkish")
+                   (const (1255 . 8) :tag "Hebrew"))
+              (repeat :inline t
+                      :tag "Other options"
+                      (choice
+                       (integer :tag "Windows codepage number")
+                       (cons (integer :tag "Windows codepage number")
+                             (integer :tag "iso-8859 charset  number")))))
+  :version "22.1" ;; Gnus 5.10.9
+  :group 'mime)
+
+(defcustom mm-codepage-ibm-list
+  (list 437 ;; (US etc.)
+       860 ;; (Portugal)
+       861 ;; (Iceland)
+       862 ;; (Israel)
+       863 ;; (Canadian French)
+       865 ;; (Nordic)
+       852 ;;
+       850 ;; (Latin 1)
+       855 ;; (Cyrillic)
+       866 ;; (Cyrillic - Russian)
+       857 ;; (Turkish)
+       864 ;; (Arabic)
+       869 ;; (Greek)
+       874);; (Thai)
+  ;; In Emacs 23 (unicode), cp... and ibm... are aliases.
+  ;; Cf. http://thread.gmane.org/v9lkng5nwy.fsf@marauder.physik.uni-ulm.de
+  "List of IBM codepage numbers.
+
+The codepage mappings slightly differ between IBM and other vendors.
+See \"ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/IBM/README.TXT\".
+
+If an element is a number corresponding to a supported windows
+codepage, appropriate entries to `mm-charset-synonym-alist' are
+added by `mm-setup-codepage-ibm'."
+  :type '(list (set :inline t
+                   (const 437 :tag "US etc.")
+                   (const 860 :tag "Portugal")
+                   (const 861 :tag "Iceland")
+                   (const 862 :tag "Israel")
+                   (const 863 :tag "Canadian French")
+                   (const 865 :tag "Nordic")
+                   (const 852)
+                   (const 850 :tag "Latin 1")
+                   (const 855 :tag "Cyrillic")
+                   (const 866 :tag "Cyrillic - Russian")
+                   (const 857 :tag "Turkish")
+                   (const 864 :tag "Arabic")
+                   (const 869 :tag "Greek")
+                   (const 874 :tag "Thai"))
+              (repeat :inline t
+                      :tag "Other options"
+                      (integer :tag "Codepage number")))
+  :version "22.1" ;; Gnus 5.10.9
+  :group 'mime)
+
+(defun mm-setup-codepage-iso-8859 (&optional list)
+  "Add appropriate entries to `mm-charset-synonym-alist'.
+Unless LIST is given, `mm-codepage-iso-8859-list' is used."
+  (unless list
+    (setq list mm-codepage-iso-8859-list))
+  (dolist (i list)
+    (let (cp windows iso)
+      (if (consp i)
+         (setq cp (intern (format "cp%d" (car i)))
+               windows (intern (format "windows-%d" (car i)))
+               iso (intern (format "iso-8859-%d" (cdr i))))
+       (setq cp (intern (format "cp%d" i))
+             windows (intern (format "windows-%d" i))))
+      (unless (mm-coding-system-p windows)
+       (if (mm-coding-system-p cp)
+           (add-to-list 'mm-charset-synonym-alist (cons windows cp))
+         (add-to-list 'mm-charset-synonym-alist (cons windows iso)))))))
+
+(defun mm-setup-codepage-ibm (&optional list)
+  "Add appropriate entries to `mm-charset-synonym-alist'.
+Unless LIST is given, `mm-codepage-ibm-list' is used."
+  (unless list
+    (setq list mm-codepage-ibm-list))
+  (dolist (number list)
+    (let ((ibm (intern (format "ibm%d" number)))
+         (cp  (intern (format "cp%d" number))))
+      (when (and (not (mm-coding-system-p ibm))
+                (mm-coding-system-p cp))
+       (add-to-list 'mm-charset-synonym-alist (cons ibm cp))))))
+
+;; Initialize:
+(mm-setup-codepage-iso-8859)
+(mm-setup-codepage-ibm)
+
+;; Note: this has to be defined before `mm-charset-to-coding-system'.
+(defcustom mm-charset-eval-alist
+  (if (featurep 'xemacs)
+      nil ;; I don't know what would be useful for XEmacs.
+    '(;; Emacs 22 provides autoloads for 1250-1258
+      ;; (i.e. `mm-codepage-setup' does nothing).
+      (windows-1250 . (mm-codepage-setup 1250 t))
+      (windows-1251 . (mm-codepage-setup 1251 t))
+      (windows-1253 . (mm-codepage-setup 1253 t))
+      (windows-1257 . (mm-codepage-setup 1257 t))))
+  "An alist of (CHARSET . FORM) pairs.
+If an article is encoded in an unknown CHARSET, FORM is
+evaluated.  This allows to load additional libraries providing
+charsets on demand.  If supported by your Emacs version, you
+could use `autoload-coding-system' here."
+  :version "22.1" ;; Gnus 5.10.9
+  :type '(list (set :inline t
+                   (const (windows-1250 . (mm-codepage-setup 1250 t)))
+                   (const (windows-1251 . (mm-codepage-setup 1251 t)))
+                   (const (windows-1253 . (mm-codepage-setup 1253 t)))
+                   (const (windows-1257 . (mm-codepage-setup 1257 t)))
+                   (const (cp850 . (mm-codepage-setup 850 nil))))
+              (repeat :inline t
+                      :tag "Other options"
+                      (cons (symbol :tag "charset")
+                            (symbol :tag "form"))))
+  :group 'mime)
+(put 'mm-charset-eval-alist 'risky-local-variable t)
+
+(defvar mm-charset-override-alist)
+
+;; Note: this function has to be defined before `mm-charset-override-alist'
+;; since it will use this function in order to determine its default value
+;; when loading mm-util.elc.
+(defun mm-charset-to-coding-system (charset &optional lbt
+                                           allow-override silent)
+  "Return coding-system corresponding to CHARSET.
+CHARSET is a symbol naming a MIME charset.
+If optional argument LBT (`unix', `dos' or `mac') is specified, it is
+used as the line break code type of the coding system.
+
+If ALLOW-OVERRIDE is given, use `mm-charset-override-alist' to
+map undesired charset names to their replacement.  This should
+only be used for decoding, not for encoding.
+
+A non-nil value of SILENT means don't issue a warning even if CHARSET
+is not available."
+  ;; OVERRIDE is used (only) in `mm-decode-body' and `mm-decode-string'.
+  (when (stringp charset)
+    (setq charset (intern (downcase charset))))
+  (when lbt
+    (setq charset (intern (format "%s-%s" charset lbt))))
+  (cond
+   ((null charset)
+    charset)
+   ;; Running in a non-MULE environment.
+   ((or (null (mm-get-coding-system-list))
+       (not (fboundp 'coding-system-get)))
+    charset)
+   ;; Check override list quite early.  Should only used for decoding, not for
+   ;; encoding!
+   ((and allow-override
+        (let ((cs (cdr (assq charset mm-charset-override-alist))))
+          (and cs (mm-coding-system-p cs) cs))))
+   ;; ascii
+   ((or (eq charset 'us-ascii)
+       (string-match "ansi.x3.4" (symbol-name charset)))
+    'ascii)
+   ;; Check to see whether we can handle this charset.  (This depends
+   ;; on there being some coding system matching each `mime-charset'
+   ;; 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)
+   ;; Use coding system Emacs knows.
+   ((and (fboundp 'coding-system-from-name)
+        (coding-system-from-name charset)))
+   ;; Eval expressions from `mm-charset-eval-alist'
+   ((let* ((el (assq charset mm-charset-eval-alist))
+          (cs (car el))
+          (form (cdr el)))
+      (and cs
+          form
+          (prog2
+              ;; Avoid errors...
+              (condition-case nil (eval form) (error nil))
+              ;; (message "Failed to eval `%s'" form))
+              (mm-coding-system-p cs)
+            (message "Added charset `%s' via `mm-charset-eval-alist'" cs))
+          cs)))
+   ;; Translate invalid charsets.
+   ((let ((cs (cdr (assq charset mm-charset-synonym-alist))))
+      (and cs
+          (mm-coding-system-p cs)
+          ;; (message
+          ;;  "Using synonym `%s' from `mm-charset-synonym-alist' for `%s'"
+          ;;  cs charset)
+          cs)))
+   ;; 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 (or (coding-system-get c :mime-charset)
+                                (coding-system-get c 'mime-charset))))
+           (setq cs c)))
+      (unless (or silent cs)
+       ;; Warn the user about unknown charset:
+       (if (fboundp 'gnus-message)
+           (gnus-message 7 "Unknown charset: %s" charset)
+         (message "Unknown charset: %s" charset)))
+      cs))))
+
+;; Note: `mm-charset-to-coding-system' has to be defined before this.
+(defcustom mm-charset-override-alist
+  ;; Note: pairs that cannot be used in the Emacs version currently running
+  ;; will be removed.
+  '((gb2312 . gbk)
+    (iso-8859-1 . windows-1252)
+    (iso-8859-8 . windows-1255)
+    (iso-8859-9 . windows-1254))
+  "A mapping from undesired charset names to their replacement.
+
+You may add pairs like (iso-8859-1 . windows-1252) here,
+i.e. treat iso-8859-1 as windows-1252.  windows-1252 is a
+superset of iso-8859-1."
+  :type
+  '(list
+    :convert-widget
+    (lambda (widget)
+      (let ((defaults
+             (delq nil
+                   (mapcar (lambda (pair)
+                             (if (mm-charset-to-coding-system (cdr pair)
+                                                              nil nil t)
+                                 pair))
+                           '((gb2312 . gbk)
+                             (iso-8859-1 . windows-1252)
+                             (iso-8859-8 . windows-1255)
+                             (iso-8859-9 . windows-1254)
+                             (undecided  . windows-1252)))))
+           (val (copy-sequence (default-value 'mm-charset-override-alist)))
+           pair rest)
+       (while val
+         (push (if (and (prog1
+                            (setq pair (assq (caar val) defaults))
+                          (setq defaults (delq pair defaults)))
+                        (equal (car val) pair))
+                   `(const ,pair)
+                 `(cons :format "%v"
+                        (const :format "(%v" ,(caar val))
+                        (symbol :size 3 :format " . %v)\n" ,(cdar val))))
+               rest)
+         (setq val (cdr val)))
+       (while defaults
+         (push `(const ,(pop defaults)) rest))
+       (widget-convert
+        'list
+        `(set :inline t :format "%v" ,@(nreverse rest))
+        `(repeat :inline t :tag "Other options"
+                 (cons :format "%v"
+                       (symbol :size 3 :format "(%v")
+                       (symbol :size 3 :format " . %v)\n")))))))
+  ;; Remove pairs that cannot be used in the Emacs version currently
+  ;; running.  Note that this section will be evaluated when loading
+  ;; mm-util.elc.
+  :set (lambda (symbol value)
+        (custom-set-default
+         symbol (delq nil
+                      (mapcar (lambda (pair)
+                                (if (mm-charset-to-coding-system (cdr pair)
+                                                                 nil nil t)
+                                    pair))
+                              value))))
+  :version "22.1" ;; Gnus 5.10.9
+  :group 'mime)
+
+(defvar mm-binary-coding-system
+  (cond
+   ((mm-coding-system-p 'binary) 'binary)
+   ((mm-coding-system-p 'no-conversion) 'no-conversion)
+   (t nil))
+  "100% binary coding system.")
+
+(defvar mm-text-coding-system
+  (or (if (memq system-type '(windows-nt ms-dos))
+         (and (mm-coding-system-p 'raw-text-dos) 'raw-text-dos)
+       (and (mm-coding-system-p 'raw-text) 'raw-text))
+      mm-binary-coding-system)
+  "Text-safe coding system (For removing ^M).")
+
+(defvar mm-text-coding-system-for-write nil
+  "Text coding system for write.")
+
+(defvar mm-auto-save-coding-system
+  (cond
+   ((mm-coding-system-p 'utf-8-emacs)  ; Mule 7
+    (if (memq system-type '(windows-nt ms-dos))
+       (if (mm-coding-system-p 'utf-8-emacs-dos)
+           'utf-8-emacs-dos mm-binary-coding-system)
+      'utf-8-emacs))
+   ((mm-coding-system-p 'emacs-mule)
+    (if (memq system-type '(windows-nt ms-dos))
+       (if (mm-coding-system-p 'emacs-mule-dos)
+           'emacs-mule-dos mm-binary-coding-system)
+      'emacs-mule))
+   ((mm-coding-system-p 'escape-quoted) 'escape-quoted)
+   (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)
+    (gbk chinese-gbk)
+    (gb18030 gb18030-2-byte
+            gb18030-4-byte-bmp gb18030-4-byte-smp
+            gb18030-4-byte-ext-1 gb18030-4-byte-ext-2)
+    (big5 chinese-big5-1 chinese-big5-2)
+    (tibetan tibetan)
+    (thai-tis620 thai-tis620)
+    (windows-1251 cyrillic-iso8859-5)
+    (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)
+    (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)
+    (iso-2022-jp-3 latin-jisx0201 japanese-jisx0208-1978 japanese-jisx0208
+                  japanese-jisx0213-1 japanese-jisx0213-2)
+    (shift_jis latin-jisx0201 katakana-jisx0201 japanese-jisx0208)
+    ,(cond ((fboundp 'unicode-precedence-list)
+           (cons 'utf-8 (delq 'ascii (mapcar 'charset-name
+                                             (unicode-precedence-list)))))
+          ((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))
+          (t ;; 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.")
+
+(defun mm-enrich-utf-8-by-mule-ucs ()
+  "Make the `utf-8' MIME charset usable by the Mule-UCS package.
+This function will run when the `un-define' module is loaded under
+XEmacs, and fill the `utf-8' entry in `mm-mime-mule-charset-alist'
+with Mule charsets.  It is completely useless for Emacs."
+  (when (boundp 'unicode-basic-translation-charset-order-list)
+    (condition-case nil
+       (let ((val (delq
+                   'ascii
+                   (copy-sequence
+                    (symbol-value
+                     'unicode-basic-translation-charset-order-list))))
+             (elem (assq 'utf-8 mm-mime-mule-charset-alist)))
+         (if elem
+             (setcdr elem val)
+           (setq mm-mime-mule-charset-alist
+                 (nconc mm-mime-mule-charset-alist
+                        (list (cons 'utf-8 val))))))
+      (error))))
+
+;; Correct by construction, but should be unnecessary for Emacs:
+(if (featurep 'xemacs)
+    (eval-after-load "un-define" '(mm-enrich-utf-8-by-mule-ucs))
+  (when (and (fboundp 'coding-system-list)
+            (fboundp 'sort-coding-systems))
+    (let ((css (sort-coding-systems (coding-system-list 'base-only)))
+         cs mime mule alist)
+      (while css
+       (setq cs (pop css)
+             mime (or (coding-system-get cs :mime-charset); Emacs 23 (unicode)
+                      (coding-system-get cs 'mime-charset)))
+       (when (and mime
+                  (not (eq t (setq mule
+                                   (coding-system-get cs 'safe-charsets))))
+                  (not (assq mime alist)))
+         (push (cons mime (delq 'ascii mule)) alist)))
+      (setq mm-mime-mule-charset-alist (nreverse alist)))))
+
+(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.")
+
+(defcustom mm-coding-system-priorities
+  (let ((lang (if (boundp 'current-language-environment)
+                 (symbol-value 'current-language-environment))))
+    (cond (;; XEmacs without Mule but with `file-coding'.
+          (not lang) nil)
+         ;; In XEmacs 21.5 it may be the one like "Japanese (UTF-8)".
+         ((string-match "\\`Japanese" lang)
+          ;; Japanese users prefer iso-2022-jp to others usually used
+          ;; for `buffer-file-coding-system', however iso-8859-1 should
+          ;; be used when there are only ASCII and Latin-1 characters.
+          '(iso-8859-1 iso-2022-jp utf-8))))
+  "Preferred coding systems for encoding outgoing messages.
+
+More than one suitable coding system may be found for some text.
+By default, the coding system with the highest priority is used
+to encode outgoing messages (see `sort-coding-systems').  If this
+variable is set, it overrides the default priority."
+  :version "24.4"
+  :type '(repeat (symbol :tag "Coding system"))
+  :group 'mime)
+
+;; ??
+(defvar mm-use-find-coding-systems-region
+  (fboundp 'find-coding-systems-region)
+  "Use `find-coding-systems-region' to find proper coding systems.
+
+Setting it to nil is useful on Emacsen supporting Unicode if sending
+mail with multiple parts is preferred to sending a Unicode one.")
+
+(defvar mm-extra-numeric-entities
+  (mapcar
+   (lambda (item)
+     (cons (car item) (mm-ucs-to-char (cdr item))))
+   '((#x80 . #x20AC) (#x82 . #x201A) (#x83 . #x0192) (#x84 . #x201E)
+     (#x85 . #x2026) (#x86 . #x2020) (#x87 . #x2021) (#x88 . #x02C6)
+     (#x89 . #x2030) (#x8A . #x0160) (#x8B . #x2039) (#x8C . #x0152)
+     (#x8E . #x017D) (#x91 . #x2018) (#x92 . #x2019) (#x93 . #x201C)
+     (#x94 . #x201D) (#x95 . #x2022) (#x96 . #x2013) (#x97 . #x2014)
+     (#x98 . #x02DC) (#x99 . #x2122) (#x9A . #x0161) (#x9B . #x203A)
+     (#x9C . #x0153) (#x9E . #x017E) (#x9F . #x0178)))
+  "*Alist of extra numeric entities and characters other than ISO 10646.
+This table is used for decoding extra numeric entities to characters,
+like \"&#128;\" to the euro sign, mainly in html messages.")
+
+;;; Internal variables:
+
+;;; Functions:
+
+(defun mm-mule-charset-to-mime-charset (charset)
+  "Return the MIME charset corresponding to the given Mule CHARSET."
+  (if (and (fboundp 'find-coding-systems-for-charsets)
+          (fboundp 'sort-coding-systems))
+      (let ((css (sort (sort-coding-systems
+                       (find-coding-systems-for-charsets (list charset)))
+                      'mm-sort-coding-systems-predicate))
+           cs mime)
+       (while (and (not mime)
+                   css)
+         (when (setq cs (pop css))
+           (setq mime (or (coding-system-get cs :mime-charset)
+                          (coding-system-get cs 'mime-charset)))))
+       mime)
+    (let ((alist (mapcar (lambda (cs)
+                          (assq cs mm-mime-mule-charset-alist))
+                        (sort (mapcar 'car mm-mime-mule-charset-alist)
+                              'mm-sort-coding-systems-predicate)))
+         out)
+      (while alist
+       (when (memq charset (cdar alist))
+         (setq out (caar alist)
+               alist nil))
+       (pop alist))
+      out)))
+
+(eval-and-compile
+  (if (featurep 'xemacs)
+      (defalias 'mm-enable-multibyte 'ignore)
+    (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."
+      (set-buffer-multibyte 'to)))
+
+  (if (featurep 'xemacs)
+      (defalias 'mm-disable-multibyte 'ignore)
+    (defun mm-disable-multibyte ()
+      "Unset the multibyte flag of in the current buffer.
+This is a no-op in XEmacs."
+      (set-buffer-multibyte nil))))
+
+(defun mm-preferred-coding-system (charset)
+  ;; A typo in some Emacs versions.
+  (or (get-charset-property charset 'preferred-coding-system)
+      (get-charset-property charset 'prefered-coding-system)))
+
+;; Mule charsets shouldn't be used.
+(defsubst mm-guess-charset ()
+  "Guess Mule charset from the language environment."
+  (or
+   mail-parse-mule-charset ;; cached mule-charset
+   (progn
+     (setq mail-parse-mule-charset
+          (and (boundp 'current-language-environment)
+               (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
+              (or (car (last (assq mail-parse-charset
+                                   mm-mime-mule-charset-alist)))
+                  ;; default
+                  'latin-iso8859-1)))
+     mail-parse-mule-charset)))
+
+(defun mm-charset-after (&optional pos)
+  "Return charset of a character in current buffer at position POS.
+If POS is nil, it defaults to the current point.
+If POS is out of range, the value is nil.
+If the charset is `composition', return the actual one."
+  (let ((char (char-after pos)) charset)
+    (if (< (mm-char-int char) 128)
+       (setq charset 'ascii)
+      ;; charset-after is fake in some Emacsen.
+      (setq charset (and (fboundp 'char-charset) (char-charset char)))
+      (if (eq charset 'composition)    ; Mule 4
+         (let ((p (or pos (point))))
+           (cadr (find-charset-region p (1+ p))))
+       (if (and charset (not (memq charset '(ascii eight-bit-control
+                                                   eight-bit-graphic))))
+           charset
+         (mm-guess-charset))))))
+
+(defun mm-mime-charset (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"))
+  (if (and (fboundp 'coding-system-get) (fboundp 'get-charset-property))
+      (or
+       (and (mm-preferred-coding-system charset)
+           (or (coding-system-get
+                (mm-preferred-coding-system charset) :mime-charset)
+               (coding-system-get
+                (mm-preferred-coding-system charset) 'mime-charset)))
+       (and (eq charset 'ascii)
+           'us-ascii)
+       (mm-preferred-coding-system charset)
+       (mm-mule-charset-to-mime-charset charset))
+    ;; This is for XEmacs.
+    (mm-mule-charset-to-mime-charset charset)))
+
+;; `delete-dups' is not available in XEmacs 21.4.
+(if (fboundp 'delete-dups)
+    (defalias 'mm-delete-duplicates 'delete-dups)
+  (defun mm-delete-duplicates (list)
+    "Destructively remove `equal' duplicates from LIST.
+Store the result in LIST and return it.  LIST must be a proper list.
+Of several `equal' occurrences of an element in LIST, the first
+one is kept.
+
+This is a compatibility function for Emacsen without `delete-dups'."
+    ;; Code from `subr.el' in Emacs 22:
+    (let ((tail list))
+      (while tail
+       (setcdr tail (delete (car tail) (cdr tail)))
+       (setq tail (cdr tail))))
+    list))
+
+;; Fixme:  This is used in places when it should be testing the
+;; default multibyteness.  See mm-default-multibyte-p.
+(eval-and-compile
+  (if (and (not (featurep 'xemacs))
+          (boundp 'enable-multibyte-characters))
+      (defun mm-multibyte-p ()
+       "Non-nil if multibyte is enabled in the current buffer."
+       enable-multibyte-characters)
+    (defun mm-multibyte-p () (featurep 'mule))))
+
+(defun mm-default-multibyte-p ()
+  "Return non-nil if the session is multibyte.
+This affects whether coding conversion should be attempted generally."
+  (if (featurep 'mule)
+      (if (boundp 'enable-multibyte-characters)
+         (default-value 'enable-multibyte-characters)
+       t)))
+
+(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)
+  (let ((priorities
+        (mapcar (lambda (cs)
+                  ;; Note: invalid entries are dropped silently
+                  (and (setq cs (mm-coding-system-p cs))
+                       (coding-system-base cs)))
+                mm-coding-system-priorities)))
+    (and (setq a (mm-coding-system-p a))
+        (if (setq b (mm-coding-system-p b))
+            (> (length (memq (coding-system-base a) priorities))
+               (length (memq (coding-system-base b) priorities)))
+          t))))
+
+(declare-function latin-unity-massage-name "ext:latin-unity")
+(declare-function latin-unity-maybe-remap "ext:latin-unity")
+(declare-function latin-unity-representations-feasible-region "ext:latin-unity")
+(declare-function latin-unity-representations-present-region "ext:latin-unity")
+
+(defvar latin-unity-coding-systems)
+(defvar latin-unity-ucs-list)
+
+(defun mm-xemacs-find-mime-charset-1 (begin end)
+  "Determine which MIME charset to use to send region as message.
+This uses the XEmacs-specific latin-unity package to better handle the
+case where identical characters from diverse ISO-8859-? character sets
+can be encoded using a single one of the corresponding coding systems.
+
+It treats `mm-coding-system-priorities' as the list of preferred
+coding systems; a useful example setting for this list in Western
+Europe would be (iso-8859-1 iso-8859-15 utf-8), which would default
+to the very standard Latin 1 coding system, and only move to coding
+systems that are less supported as is necessary to encode the
+characters that exist in the buffer.
+
+Latin Unity doesn't know about those non-ASCII Roman characters that
+are available in various East Asian character sets.  As such, its
+behavior if you have a JIS 0212 LATIN SMALL LETTER A WITH ACUTE in a
+buffer and it can otherwise be encoded as Latin 1, won't be ideal.
+But this is very much a corner case, so don't worry about it."
+  (let ((systems mm-coding-system-priorities) csets psets curset)
+
+    ;; Load the Latin Unity library, if available.
+    (when (and (not (featurep 'latin-unity)) (locate-library "latin-unity"))
+      (require 'latin-unity))
+
+    ;; Now, can we use it?
+    (if (featurep 'latin-unity)
+       (progn
+         (setq csets (latin-unity-representations-feasible-region begin end)
+               psets (latin-unity-representations-present-region begin end))
+
+         (catch 'done
+
+           ;; Pass back the first coding system in the preferred list
+           ;; that can encode the whole region.
+           (dolist (curset systems)
+             (setq curset (latin-unity-massage-name 'buffer-default curset))
+
+             ;; If the coding system is a universal coding system, then
+             ;; it can certainly encode all the characters in the region.
+             (if (memq curset latin-unity-ucs-list)
+                 (throw 'done (list curset)))
+
+             ;; If a coding system isn't universal, and isn't in
+             ;; the list that latin unity knows about, we can't
+             ;; decide whether to use it here. Leave that until later
+             ;; in `mm-find-mime-charset-region' function, whence we
+             ;; have been called.
+             (unless (memq curset latin-unity-coding-systems)
+               (throw 'done nil))
+
+             ;; Right, we know about this coding system, and it may
+             ;; conceivably be able to encode all the characters in
+             ;; the region.
+             (if (latin-unity-maybe-remap begin end curset csets psets t)
+                 (throw 'done (list curset))))
+
+           ;; Can't encode using anything from the
+           ;; `mm-coding-system-priorities' list.
+           ;; Leave `mm-find-mime-charset' to do most of the work.
+           nil))
+
+      ;; Right, latin unity isn't available; let `mm-find-charset-region'
+      ;; take its default action, which equally applies to GNU Emacs.
+      nil)))
+
+(defmacro mm-xemacs-find-mime-charset (begin end)
+  (when (featurep 'xemacs)
+    `(and (featurep 'mule) (mm-xemacs-find-mime-charset-1 ,begin ,end))))
+
+(declare-function mm-delete-duplicates "mm-util" (list))
+
+(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)
+            mm-use-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)))
+              (setq systems (delq 'compound-text systems))
+              (unless (equal systems '(undecided))
+                (while systems
+                  (let* ((head (pop systems))
+                         (cs (or (coding-system-get head :mime-charset)
+                                 (coding-system-get head 'mime-charset))))
+                    ;; The mime-charset (`x-ctext') of
+                    ;; `compound-text' is not in the IANA list.  We
+                    ;; shouldn't normally use anything here with a
+                    ;; mime-charset having an `x-' prefix.
+                    ;; Fixme:  Allow this to be overridden, since
+                    ;; there is existing use of x-ctext.
+                    ;; Also people apparently need the coding system
+                    ;; `iso-2022-jp-3' (which Mule-UCS defines with
+                    ;; mime-charset, though it's not valid).
+                    (if (and cs
+                             (not (string-match "^[Xx]-" (symbol-name cs)))
+                             ;; UTF-16 of any variety is invalid for
+                             ;; text parts and, unfortunately, has
+                             ;; mime-charset defined both in Mule-UCS
+                             ;; and versions of Emacs.  (The name
+                             ;; might be `mule-utf-16...'  or
+                             ;; `utf-16...'.)
+                             (not (string-match "utf-16" (symbol-name cs))))
+                        (setq systems nil
+                              charsets (list cs))))))
+              charsets))
+       ;; If we're XEmacs, and some coding system is appropriate,
+       ;; mm-xemacs-find-mime-charset will return an appropriate list.
+       ;; Otherwise, we'll get nil, and the next setq will get invoked.
+       (setq charsets (mm-xemacs-find-mime-charset b e))
+
+       ;; Fixme: won't work for unibyte Emacs 23:
+
+       ;; We're not multibyte, 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 (> (length charsets) 1)
+            (memq 'iso-8859-15 charsets)
+            (memq 'iso-8859-15 hack-charsets)
+            (save-excursion (mm-iso-8859-x-to-15-region b e)))
+       (dolist (x mm-iso-8859-15-compatible)
+         (setq charsets (delq (car x) charsets))))
+    (if (and (memq 'iso-2022-jp-2 charsets)
+            (memq 'iso-2022-jp-2 hack-charsets))
+       (setq charsets (delq 'iso-2022-jp charsets)))
+    ;; Attempt to reduce the number of charsets if utf-8 is available.
+    (if (and (featurep 'xemacs)
+            (> (length charsets) 1)
+            (mm-coding-system-p 'utf-8))
+       (let ((mm-coding-system-priorities
+              (cons 'utf-8 mm-coding-system-priorities)))
+         (setq charsets
+               (mm-delete-duplicates
+                (mapcar 'mm-mime-charset
+                        (delq 'ascii
+                              (mm-find-charset-region b e)))))))
+    charsets))
+
+(defmacro mm-with-unibyte-buffer (&rest forms)
+  "Create a temporary buffer, and evaluate FORMS there like `progn'.
+Use unibyte mode for this."
+  `(with-temp-buffer
+     (mm-disable-multibyte)
+     ,@forms))
+(put 'mm-with-unibyte-buffer 'lisp-indent-function 0)
+(put 'mm-with-unibyte-buffer 'edebug-form-spec '(body))
+
+(defmacro mm-with-multibyte-buffer (&rest forms)
+  "Create a temporary buffer, and evaluate FORMS there like `progn'.
+Use multibyte mode for this."
+  `(with-temp-buffer
+     (mm-enable-multibyte)
+     ,@forms))
+(put 'mm-with-multibyte-buffer 'lisp-indent-function 0)
+(put 'mm-with-multibyte-buffer 'edebug-form-spec '(body))
+
+(defmacro mm-with-unibyte-current-buffer (&rest forms)
+  "Evaluate FORMS with current buffer temporarily made unibyte.
+Equivalent to `progn' in XEmacs.
+
+Note: We recommend not using this macro any more; there should be
+better ways to do a similar thing.  The previous version of this macro
+bound the default value of `enable-multibyte-characters' to nil while
+evaluating FORMS but it is no longer done.  So, some programs assuming
+it if any may malfunction."
+  (declare (obsolete nil "25.1") (indent 0) (debug t))
+  (if (featurep 'xemacs)
+      `(progn ,@forms)
+    (let ((multibyte (make-symbol "multibyte")))
+      `(let ((,multibyte enable-multibyte-characters))
+        (when ,multibyte
+          (set-buffer-multibyte nil))
+        (prog1
+            (progn ,@forms)
+          (when ,multibyte
+            (set-buffer-multibyte t)))))))
+
+(defun mm-find-charset-region (b e)
+  "Return a list of Emacs charsets in the region B to E."
+  (cond
+   ((and (mm-multibyte-p)
+        (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)))
+      (dolist (cs
+              '(composition eight-bit-control eight-bit-graphic control-1)
+              css)
+       (setq css (delq cs css)))))
+   (t
+    ;; We are in a unibyte buffer or XEmacs non-mule, so we futz around a bit.
+    (save-excursion
+      (save-restriction
+       (narrow-to-region b e)
+       (goto-char (point-min))
+       (skip-chars-forward "\0-\177")
+       (if (eobp)
+           '(ascii)
+         (let (charset)
+           (setq charset
+                 (and (boundp 'current-language-environment)
+                      (car (last (assq 'charset
+                                       (assoc current-language-environment
+                                              language-info-alist))))))
+           (if (eq charset 'ascii) (setq charset nil))
+           (or charset
+               (setq charset
+                     (car (last (assq mail-parse-charset
+                                      mm-mime-mule-charset-alist)))))
+           (list 'ascii (or charset 'latin-iso8859-1)))))))))
+
+(defun mm-auto-mode-alist ()
+  "Return an `auto-mode-alist' with only the .gz (etc) thingies."
+  (let ((alist auto-mode-alist)
+       out)
+    (while alist
+      (when (listp (cdar alist))
+       (push (car alist) out))
+      (pop alist))
+    (nreverse out)))
+
+(defvar mm-inhibit-file-name-handlers
+  '(jka-compr-handler image-file-handler epa-file-handler)
+  "A list of handlers doing (un)compression (etc) thingies.")
+
+(defun mm-insert-file-contents (filename &optional visit beg end replace
+                                        inhibit)
+  "Like `insert-file-contents', but only reads in the file.
+A buffer may be modified in several ways after reading into the buffer due
+to advanced Emacs features, such as file-name-handlers, format decoding,
+`find-file-hooks', etc.
+If INHIBIT is non-nil, inhibit `mm-inhibit-file-name-handlers'.
+  This function ensures that none of these modifications will take place."
+  (letf* ((format-alist nil)
+          (auto-mode-alist (if inhibit nil (mm-auto-mode-alist)))
+          ((default-value 'major-mode) 'fundamental-mode)
+          (enable-local-variables nil)
+          (after-insert-file-functions nil)
+          (enable-local-eval nil)
+          (inhibit-file-name-operation (if inhibit
+                                           'insert-file-contents
+                                         inhibit-file-name-operation))
+          (inhibit-file-name-handlers
+           (if inhibit
+               (append mm-inhibit-file-name-handlers
+                       inhibit-file-name-handlers)
+             inhibit-file-name-handlers))
+          (ffh (if (boundp 'find-file-hook)
+                   'find-file-hook
+                 'find-file-hooks))
+          (val (symbol-value ffh)))
+    (set ffh nil)
+    (unwind-protect
+       (insert-file-contents filename visit beg end replace)
+      (set ffh val))))
+
+(defun mm-append-to-file (start end filename &optional codesys inhibit)
+  "Append the contents of the region to the end of file FILENAME.
+When called from a function, expects three arguments,
+START, END and FILENAME.  START and END are buffer positions
+saying what text to write.
+Optional fourth argument specifies the coding system to use when
+encoding the file.
+If INHIBIT is non-nil, inhibit `mm-inhibit-file-name-handlers'."
+  (let ((coding-system-for-write
+        (or codesys mm-text-coding-system-for-write
+            mm-text-coding-system))
+       (inhibit-file-name-operation (if inhibit
+                                        'append-to-file
+                                      inhibit-file-name-operation))
+       (inhibit-file-name-handlers
+        (if inhibit
+            (append mm-inhibit-file-name-handlers
+                    inhibit-file-name-handlers)
+          inhibit-file-name-handlers)))
+    (write-region start end filename t 'no-message)
+    (message "Appended to %s" filename)))
+
+(defun mm-write-region (start end filename &optional append visit lockname
+                             coding-system inhibit)
+
+  "Like `write-region'.
+If INHIBIT is non-nil, inhibit `mm-inhibit-file-name-handlers'."
+  (let ((coding-system-for-write
+        (or coding-system mm-text-coding-system-for-write
+            mm-text-coding-system))
+       (inhibit-file-name-operation (if inhibit
+                                        'write-region
+                                      inhibit-file-name-operation))
+       (inhibit-file-name-handlers
+        (if inhibit
+            (append mm-inhibit-file-name-handlers
+                    inhibit-file-name-handlers)
+          inhibit-file-name-handlers)))
+    (write-region start end filename append visit lockname)))
+
+(autoload 'gmm-write-region "gmm-utils")
+
+;; It is not a MIME function, but some MIME functions use it.
+(if (and (fboundp 'make-temp-file)
+        (ignore-errors
+          (let ((def (if (fboundp 'compiled-function-arglist) ;; XEmacs
+                         (eval (list 'compiled-function-arglist
+                                     (symbol-function 'make-temp-file)))
+                       (require 'help-fns)
+                       (help-function-arglist 'make-temp-file t))))
+            (and (>= (length def) 4)
+                 (eq (nth 3 def) 'suffix)))))
+    (defalias 'mm-make-temp-file 'make-temp-file)
+  ;; Stolen (and modified for XEmacs) from Emacs 22.
+  (defun mm-make-temp-file (prefix &optional dir-flag suffix)
+    "Create a temporary file.
+The returned file name (created by appending some random characters at the end
+of PREFIX, and expanding against `temporary-file-directory' if necessary),
+is guaranteed to point to a newly created empty file.
+You can then use `write-region' to write new data into the file.
+
+If DIR-FLAG is non-nil, create a new empty directory instead of a file.
+
+If SUFFIX is non-nil, add that at the end of the file name."
+    (let ((umask (default-file-modes))
+         file)
+      (unwind-protect
+         (progn
+           ;; Create temp files with strict access rights.  It's easy to
+           ;; loosen them later, whereas it's impossible to close the
+           ;; time-window of loose permissions otherwise.
+           (set-default-file-modes 448)
+           (while (condition-case err
+                      (progn
+                        (setq file
+                              (make-temp-name
+                               (expand-file-name
+                                prefix
+                                (if (fboundp 'temp-directory)
+                                    ;; XEmacs
+                                    (temp-directory)
+                                  temporary-file-directory))))
+                        (if suffix
+                            (setq file (concat file suffix)))
+                        (if dir-flag
+                            (make-directory file)
+                          ;; NOTE: This is unsafe if Emacs 20
+                          ;; users and XEmacs users don't use
+                          ;; a secure temp directory.
+                          (gmm-write-region "" nil file nil 'silent
+                                            nil 'excl))
+                        nil)
+                    (file-already-exists t)
+                    ;; The XEmacs version of `make-directory' issues
+                    ;; `file-error'.
+                    (file-error (or (and (featurep 'xemacs)
+                                         (file-exists-p file))
+                                    (signal (car err) (cdr err)))))
+             ;; the file was somehow created by someone else between
+             ;; `make-temp-name' and `write-region', let's try again.
+             nil)
+           file)
+       ;; Reset the umask.
+       (set-default-file-modes umask)))))
+
+(defvar mm-image-load-path-cache nil)
+
+(defun mm-image-load-path (&optional package)
+  (if (and mm-image-load-path-cache
+          (equal load-path (car mm-image-load-path-cache)))
+      (cdr mm-image-load-path-cache)
+    (let (dir result)
+      (dolist (path load-path)
+       (when (and path
+                  (file-directory-p
+                   (setq dir (concat (file-name-directory
+                                      (directory-file-name path))
+                                     "etc/images/" (or package "gnus/")))))
+         (push dir result)))
+      (setq result (nreverse result)
+           mm-image-load-path-cache (cons load-path result))
+      result)))
+
+;; Fixme: This doesn't look useful where it's used.
+(if (fboundp 'detect-coding-region)
+    (defun mm-detect-coding-region (start end)
+      "Like `detect-coding-region' except returning the best one."
+      (let ((coding-systems
+            (detect-coding-region start end)))
+       (or (car-safe coding-systems)
+           coding-systems)))
+  (defun mm-detect-coding-region (start end)
+    (let ((point (point)))
+      (goto-char start)
+      (skip-chars-forward "\0-\177" end)
+      (prog1
+         (if (eq (point) end) 'ascii (mm-guess-charset))
+       (goto-char point)))))
+
+(declare-function mm-detect-coding-region "mm-util" (start end))
+
+(if (fboundp 'coding-system-get)
+    (defun mm-detect-mime-charset-region (start end)
+      "Detect MIME charset of the text in the region between START and END."
+      (let ((cs (mm-detect-coding-region start end)))
+       (or (coding-system-get cs :mime-charset)
+           (coding-system-get cs 'mime-charset))))
+  (defun mm-detect-mime-charset-region (start end)
+    "Detect MIME charset of the text in the region between START and END."
+    (let ((cs (mm-detect-coding-region start end)))
+      cs)))
+
+(eval-when-compile
+  (unless (fboundp 'coding-system-to-mime-charset)
+    (defalias 'coding-system-to-mime-charset 'ignore)))
+
+(defun mm-coding-system-to-mime-charset (coding-system)
+  "Return the MIME charset corresponding to CODING-SYSTEM.
+To make this function work with XEmacs, the APEL package is required."
+  (when coding-system
+    (or (and (fboundp 'coding-system-get)
+            (or (coding-system-get coding-system :mime-charset)
+                (coding-system-get coding-system 'mime-charset)))
+       (and (featurep 'xemacs)
+            (or (and (fboundp 'coding-system-to-mime-charset)
+                     (not (eq (symbol-function 'coding-system-to-mime-charset)
+                              'ignore)))
+                (and (condition-case nil
+                         (require 'mcharset)
+                       (error nil))
+                     (fboundp 'coding-system-to-mime-charset)))
+            (coding-system-to-mime-charset coding-system)))))
+
+(defvar jka-compr-acceptable-retval-list)
+(declare-function jka-compr-make-temp-name "jka-compr" (&optional local))
+
+(defun mm-decompress-buffer (filename &optional inplace force)
+  "Decompress buffer's contents, depending on jka-compr.
+Only when FORCE is t or `auto-compression-mode' is enabled and FILENAME
+agrees with `jka-compr-compression-info-list', decompression is done.
+Signal an error if FORCE is neither nil nor t and compressed data are
+not decompressed because `auto-compression-mode' is disabled.
+If INPLACE is nil, return decompressed data or nil without modifying
+the buffer.  Otherwise, replace the buffer's contents with the
+decompressed data.  The buffer's multibyteness must be turned off."
+  (when (and filename
+            (if force
+                (prog1 t (require 'jka-compr))
+              (and (fboundp 'jka-compr-installed-p)
+                   (jka-compr-installed-p))))
+    (let ((info (jka-compr-get-compression-info filename)))
+      (when info
+       (unless (or (memq force (list nil t))
+                   (jka-compr-installed-p))
+         (error ""))
+       (let ((prog (jka-compr-info-uncompress-program info))
+             (args (jka-compr-info-uncompress-args info))
+             (msg (format "%s %s..."
+                          (jka-compr-info-uncompress-message info)
+                          filename))
+             (err-file (jka-compr-make-temp-name))
+             (cur (current-buffer))
+             (coding-system-for-read mm-binary-coding-system)
+             (coding-system-for-write mm-binary-coding-system)
+             retval err-msg)
+         (message "%s" msg)
+         (mm-with-unibyte-buffer
+           (insert-buffer-substring cur)
+           (condition-case err
+               (progn
+                 (unless (memq (apply 'call-process-region
+                                      (point-min) (point-max)
+                                      prog t (list t err-file) nil args)
+                               jka-compr-acceptable-retval-list)
+                   (erase-buffer)
+                   (insert (mapconcat 'identity
+                                      (split-string
+                                       (prog2
+                                           (insert-file-contents err-file)
+                                           (buffer-string)
+                                         (erase-buffer)) t)
+                                      " ")
+                           "\n")
+                   (setq err-msg
+                         (format "Error while executing \"%s %s < %s\""
+                                 prog (mapconcat 'identity args " ")
+                                 filename)))
+                 (setq retval (buffer-string)))
+             (error
+              (setq err-msg (error-message-string err)))))
+         (when (file-exists-p err-file)
+           (ignore-errors (delete-file err-file)))
+         (when inplace
+           (unless err-msg
+             (delete-region (point-min) (point-max))
+             (insert retval))
+           (setq retval nil))
+         (message "%s" (or err-msg (concat msg "done")))
+         retval)))))
+
+(eval-when-compile
+  (unless (fboundp 'coding-system-name)
+    (defalias 'coding-system-name 'ignore))
+  (unless (fboundp 'find-file-coding-system-for-read-from-filename)
+    (defalias 'find-file-coding-system-for-read-from-filename 'ignore))
+  (unless (fboundp 'find-operation-coding-system)
+    (defalias 'find-operation-coding-system 'ignore)))
+
+(defun mm-find-buffer-file-coding-system (&optional filename)
+  "Find coding system used to decode the contents of the current buffer.
+This function looks for the coding system magic cookie or examines the
+coding system specified by `file-coding-system-alist' being associated
+with FILENAME which defaults to `buffer-file-name'.  Data compressed by
+gzip, bzip2, etc. are allowed."
+  (unless filename
+    (setq filename buffer-file-name))
+  (save-excursion
+    (let ((decomp (unless ;; Not worth it to examine charset of tar files.
+                     (and filename
+                          (string-match
+                           "\\.\\(?:tar\\.[^.]+\\|tbz\\|tgz\\)\\'"
+                           filename))
+                   (mm-decompress-buffer filename nil t))))
+      (when decomp
+       (set-buffer (generate-new-buffer " *temp*"))
+        (mm-disable-multibyte)
+       (insert decomp)
+       (setq filename (file-name-sans-extension filename)))
+      (goto-char (point-min))
+      (unwind-protect
+         (cond
+          ((boundp 'set-auto-coding-function) ;; Emacs
+           (if filename
+               (or (funcall (symbol-value 'set-auto-coding-function)
+                            filename (- (point-max) (point-min)))
+                   (car (find-operation-coding-system 'insert-file-contents
+                                                      filename)))
+             (let (auto-coding-alist)
+               (condition-case nil
+                   (funcall (symbol-value 'set-auto-coding-function)
+                            nil (- (point-max) (point-min)))
+                 (error nil)))))
+          ((and (featurep 'xemacs) (featurep 'file-coding)) ;; XEmacs
+           (let ((case-fold-search t)
+                 (end (point-at-eol))
+                 codesys start)
+             (or
+              (and (re-search-forward "-\\*-+[\t ]*" end t)
+                   (progn
+                     (setq start (match-end 0))
+                     (re-search-forward "[\t ]*-+\\*-" end t))
+                   (progn
+                     (setq end (match-beginning 0))
+                     (goto-char start)
+                     (or (looking-at "coding:[\t ]*\\([^\t ;]+\\)")
+                         (re-search-forward
+                          "[\t ;]+coding:[\t ]*\\([^\t ;]+\\)"
+                          end t)))
+                   (find-coding-system (setq codesys
+                                             (intern (match-string 1))))
+                   codesys)
+              (and (re-search-forward "^[\t ]*;+[\t ]*Local[\t ]+Variables:"
+                                      nil t)
+                   (progn
+                     (setq start (match-end 0))
+                     (re-search-forward "^[\t ]*;+[\t ]*End:" nil t))
+                   (progn
+                     (setq end (match-beginning 0))
+                     (goto-char start)
+                     (re-search-forward
+                      "^[\t ]*;+[\t ]*coding:[\t ]*\\([^\t\n\r ]+\\)"
+                      end t))
+                   (find-coding-system (setq codesys
+                                             (intern (match-string 1))))
+                   codesys)
+              (and (progn
+                     (goto-char (point-min))
+                     (setq case-fold-search nil)
+                     (re-search-forward "^;;;coding system: "
+                                        ;;(+ (point-min) 3000) t))
+                                        nil t))
+                   (looking-at "[^\t\n\r ]+")
+                   (find-coding-system
+                    (setq codesys (intern (match-string 0))))
+                   codesys)
+              (and filename
+                   (setq codesys
+                         (find-file-coding-system-for-read-from-filename
+                          filename))
+                   (coding-system-name (coding-system-base codesys)))))))
+       (when decomp
+         (kill-buffer (current-buffer)))))))
+
+(provide 'mm-util)
+
+;;; mm-util.el ends here
diff --git a/xemacs-packages/gnus/lisp/mm-uu.el b/xemacs-packages/gnus/lisp/mm-uu.el
new file mode 100644 (file)
index 0000000..4197b2a
--- /dev/null
@@ -0,0 +1,778 @@
+;;; mm-uu.el --- Return uu stuff as mm handles
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Shenghuo Zhu <zsh@cs.rochester.edu>
+;; Keywords: postscript uudecode binhex shar forward gnatsweb pgp
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(require 'mail-parse)
+(require 'nnheader)
+(require 'mm-decode)
+(require 'mailcap)
+(require 'mml2015)
+
+(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")
+
+(autoload 'yenc-decode-region "yenc")
+(autoload 'yenc-extract-filename "yenc")
+
+(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 "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)
+
+(defcustom mm-uu-binhex-decode-function 'binhex-decode-region
+  "*Function to binhex decode.
+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 (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-yenc-decode-function 'yenc-decode-region)
+
+(defvar mm-uu-beginning-regexp nil)
+
+(defvar mm-dissect-disposition "inline"
+  "The default disposition of uu parts.
+This can be either \"inline\" or \"attachment\".")
+
+(defcustom mm-uu-emacs-sources-regexp "\\.emacs\\.sources"
+  "The regexp of Emacs sources groups."
+  :version "22.1"
+  :type 'regexp
+  :group 'gnus-article-mime)
+
+(defcustom mm-uu-diff-groups-regexp
+  "\\(gmane\\|gnu\\)\\..*\\(diff\\|commit\\|cvs\\|bug\\|devel\\)"
+  "Regexp matching diff groups."
+  :version "22.1"
+  :type 'regexp
+  :group 'gnus-article-mime)
+
+(defcustom mm-uu-tex-groups-regexp "\\.tex\\>"
+  "*Regexp matching TeX groups."
+  :version "23.1"
+  :type 'regexp
+  :group 'gnus-article-mime)
+
+(defvar mm-uu-type-alist
+  '((postscript
+     "^%!PS-"
+     "^%%EOF$"
+     mm-uu-postscript-extract
+     nil)
+    (uu ;; Maybe we should have a more strict test here.
+     "^begin[ \t]+0?[0-7][0-7][0-7][ \t]+"
+     "^end[ \t]*$"
+     mm-uu-uu-extract
+     mm-uu-uu-filename)
+    (binhex
+     "^:.\\{63,63\\}$"
+     ":$"
+     mm-uu-binhex-extract
+     nil
+     mm-uu-binhex-filename)
+    (yenc
+     "^=ybegin.*size=[0-9]+.*name=.*$"
+     "^=yend.*size=[0-9]+"
+     mm-uu-yenc-extract
+     mm-uu-yenc-filename)
+    (shar
+     "^#! */bin/sh"
+     "^exit 0$"
+     mm-uu-shar-extract)
+    (forward
+     ;; Thanks to Edward J. Sabol <sabol@alderaan.gsfc.nasa.gov> and
+     ;; Peter von der Ahé <pahe@daimi.au.dk>
+     "^-+ \\(Start of \\)?Forwarded message"
+     "^-+ End \\(of \\)?forwarded message"
+     mm-uu-forward-extract
+     nil
+     mm-uu-forward-test)
+    (gnatsweb
+     "^----gnatsweb-attachment----"
+     nil
+     mm-uu-gnatsweb-extract)
+    (pgp-signed
+     "^-----BEGIN PGP SIGNED MESSAGE-----"
+     "^-----END PGP SIGNATURE-----"
+     mm-uu-pgp-signed-extract
+     nil
+     nil)
+    (pgp-encrypted
+     "^-----BEGIN PGP MESSAGE-----"
+     "^-----END PGP MESSAGE-----"
+     mm-uu-pgp-encrypted-extract
+     nil
+     nil)
+    (pgp-key
+     "^-----BEGIN PGP PUBLIC KEY BLOCK-----"
+     "^-----END PGP PUBLIC KEY BLOCK-----"
+     mm-uu-pgp-key-extract
+     mm-uu-gpg-key-skip-to-last
+     nil)
+    (emacs-sources
+     "^;;;?[ \t]*[^ \t]+\\.el[ \t]*--"
+     "^;;;?[ \t]*\\([^ \t]+\\.el\\)[ \t]+ends here"
+     mm-uu-emacs-sources-extract
+     nil
+     mm-uu-emacs-sources-test)
+    (diff
+     "^Index: "
+     nil
+     mm-uu-diff-extract
+     nil
+     mm-uu-diff-test)
+    (diff
+     "^=== modified file "
+     nil
+     mm-uu-diff-extract
+     nil
+     mm-uu-diff-test)
+    (git-format-patch
+     "^diff --git "
+     "^-- "
+     mm-uu-diff-extract
+     nil
+     mm-uu-diff-test)
+    (message-marks
+     ;; Text enclosed with tags similar to `message-mark-insert-begin' and
+     ;; `message-mark-insert-end'.  Don't use those variables to avoid
+     ;; dependency on `message.el'.
+     "^-+[8<>]*-\\{9,\\}[a-z ]+-\\{9,\\}[a-z ]+-\\{9,\\}[8<>]*-+$"
+     "^-+[8<>]*-\\{9,\\}[a-z ]+-\\{9,\\}[a-z ]+-\\{9,\\}[8<>]*-+$"
+     (lambda () (mm-uu-verbatim-marks-extract 0 0 1 -1))
+     nil)
+    ;; Omitting [a-z8<] leads to false positives (bogus signature separators
+    ;; and mailing list banners).
+    (insert-marks
+     "^ *\\(-\\|_\\)\\{30,\\}.*[a-z8<].*\\(-\\|_\\)\\{30,\\} *$"
+     "^ *\\(-\\|_\\)\\{30,\\}.*[a-z8<].*\\(-\\|_\\)\\{30,\\} *$"
+     (lambda () (mm-uu-verbatim-marks-extract 0 0 1 -1))
+     nil)
+    (verbatim-marks
+     ;; slrn-style verbatim marks, see
+     ;; http://slrn.sourceforge.net/docs/slrn-manual-6.html#process_verbatim_marks
+     "^#v\\+"
+     "^#v\\-$"
+     (lambda () (mm-uu-verbatim-marks-extract 0 0))
+     nil)
+    (LaTeX
+     "^\\([\\\\%][^\n]+\n\\)*\\\\documentclass.*[[{%]"
+     "^\\\\end{document}"
+     mm-uu-latex-extract
+     nil
+     mm-uu-latex-test)
+    (org-src-code-block
+     "^[ \t]*#\\+begin_"
+     "^[ \t]*#\\+end_"
+     mm-uu-org-src-code-block-extract)
+    (org-meta-line
+     "^[ \t]*#\\+[[:alpha:]]+: "
+     "$"
+     mm-uu-org-src-code-block-extract))
+  "A list of specifications for non-MIME attachments.
+Each element consist of the following entries: label,
+start-regexp, end-regexp, extract-function, test-function.
+
+After modifying this list you must run \\[mm-uu-configure].
+
+You can disable elements from this list by customizing
+`mm-uu-configure-list'.")
+
+(defcustom mm-uu-configure-list '((shar . disabled))
+  "A list of mm-uu configuration.
+To disable dissecting shar codes, for instance, add
+`(shar . disabled)' to this list."
+  :type 'alist
+  :options (mapcar (lambda (entry)
+                    (list (car entry) '(const disabled)))
+                  mm-uu-type-alist)
+  :group 'gnus-article-mime)
+
+(defvar mm-uu-text-plain-type '("text/plain" (charset . gnus-decoded))
+  "MIME type and parameters for text/plain parts.
+`gnus-decoded' is a fake charset, which means no further decoding.")
+
+;; functions
+
+(defsubst mm-uu-type (entry)
+  (car entry))
+
+(defsubst mm-uu-beginning-regexp (entry)
+  (nth 1 entry))
+
+(defsubst mm-uu-end-regexp (entry)
+  (nth 2 entry))
+
+(defsubst mm-uu-function-extract (entry)
+  (nth 3 entry))
+
+(defsubst mm-uu-function-1 (entry)
+  (nth 4 entry))
+
+(defsubst mm-uu-function-2 (entry)
+  (nth 5 entry))
+
+;; In Emacs 22, we could use `min-colors' in the face definition.  But Emacs
+;; 21 and XEmacs don't support it.
+(defcustom mm-uu-hide-markers
+  (< 16 (or (and (fboundp 'defined-colors)
+                (length (defined-colors)))
+           (and (fboundp 'device-color-cells)
+                (device-color-cells))
+           0))
+  "If non-nil, hide verbatim markers.
+The value should be nil on displays where the face
+`mm-uu-extract' isn't distinguishable to the face `default'."
+  :type '(choice (const :tag "Hide" t)
+                (const :tag "Don't hide" nil))
+  :version "23.1" ;; No Gnus
+  :group 'gnus-article-mime)
+
+(defface mm-uu-extract '(;; Inspired by `gnus-cite-3'
+                        (((type tty)
+                          (class color)
+                          (background dark))
+                         (:background "dark blue"))
+                        (((class color)
+                          (background dark))
+                         (:foreground "light yellow"
+                          :background "dark green"))
+                        (((type tty)
+                          (class color)
+                          (background light))
+                         (:foreground "dark blue"))
+                        (((class color)
+                          (background light))
+                         (:foreground "dark green"
+                          :background "light yellow"))
+                        (t
+                         ()))
+  "Face for extracted buffers."
+  ;; See `mm-uu-verbatim-marks-extract'.
+  :version "23.1" ;; No Gnus
+  :group 'gnus-article-mime)
+
+(defun mm-uu-copy-to-buffer (&optional from to properties)
+  "Copy the contents of the current buffer to a fresh buffer.
+Return that buffer.
+
+If PROPERTIES is non-nil, PROPERTIES are applied to the buffer,
+see `set-text-properties'.  If PROPERTIES equals t, this means to
+apply the face `mm-uu-extract'."
+  (let ((obuf (current-buffer))
+        (multi (and (boundp 'enable-multibyte-characters)
+                    enable-multibyte-characters))
+       (coding-system
+         ;; Might not exist in non-MULE XEmacs
+         (when (boundp 'buffer-file-coding-system)
+           buffer-file-coding-system)))
+    (with-current-buffer (generate-new-buffer " *mm-uu*")
+      (if multi (mm-enable-multibyte) (mm-disable-multibyte))
+      (setq buffer-file-coding-system coding-system)
+      (insert-buffer-substring obuf from to)
+      (cond ((eq properties  t)
+            (set-text-properties (point-min) (point-max)
+                                 '(face mm-uu-extract)))
+           (properties
+            (set-text-properties (point-min) (point-max) properties)))
+      (current-buffer))))
+
+(defun mm-uu-configure-p  (key val)
+  (member (cons key val) mm-uu-configure-list))
+
+(defun mm-uu-configure (&optional symbol value)
+  "Configure detection of non-MIME attachments."
+  (interactive)
+  (if symbol (set-default symbol value))
+  (setq mm-uu-beginning-regexp nil)
+  (mapcar (lambda (entry)
+            (if (mm-uu-configure-p (mm-uu-type entry) 'disabled)
+                nil
+              (setq mm-uu-beginning-regexp
+                    (concat mm-uu-beginning-regexp
+                            (if mm-uu-beginning-regexp "\\|")
+                            (mm-uu-beginning-regexp entry)))))
+         mm-uu-type-alist))
+
+(mm-uu-configure)
+
+(defvar file-name)
+(defvar start-point)
+(defvar end-point)
+(defvar entry)
+
+(defun mm-uu-uu-filename ()
+  (if (looking-at ".+")
+      (setq file-name
+           (let ((nnheader-file-name-translation-alist
+                  '((?/ . ?,) (?\  . ?_) (?* . ?_) (?$ . ?_))))
+             (nnheader-translate-file-chars (match-string 0))))))
+
+(defun mm-uu-binhex-filename ()
+  (setq file-name
+       (ignore-errors
+         (binhex-decode-region start-point end-point t))))
+
+(defun mm-uu-yenc-filename ()
+  (goto-char start-point)
+  (setq file-name
+       (ignore-errors
+         (yenc-extract-filename))))
+
+(defun mm-uu-forward-test ()
+  (save-excursion
+    (goto-char start-point)
+    (forward-line)
+    (looking-at "[\r\n]*[a-zA-Z][a-zA-Z0-9-]*:")))
+
+(defun mm-uu-postscript-extract ()
+  (mm-make-handle (mm-uu-copy-to-buffer start-point end-point)
+                 '("application/postscript")))
+
+(defun mm-uu-verbatim-marks-extract (start-offset end-offset
+                                                 &optional
+                                                 start-hide
+                                                 end-hide)
+  (let ((start (or (and mm-uu-hide-markers
+                       start-hide)
+                  start-offset
+                  1))
+       (end   (or (and mm-uu-hide-markers
+                       end-hide)
+                  end-offset
+                  -1)))
+    (mm-make-handle
+     (mm-uu-copy-to-buffer
+      (progn (goto-char start-point)
+            (forward-line start)
+            (point))
+      (progn (goto-char end-point)
+          (forward-line end)
+          (point))
+      t)
+     '("text/x-verbatim" (charset . gnus-decoded)))))
+
+(defun mm-uu-latex-extract ()
+  (mm-make-handle
+   (mm-uu-copy-to-buffer start-point end-point t)
+   ;; application/x-tex?
+   '("text/x-verbatim" (charset . gnus-decoded))))
+
+(defun mm-uu-emacs-sources-extract ()
+  (mm-make-handle (mm-uu-copy-to-buffer start-point end-point)
+                 '("application/emacs-lisp" (charset . gnus-decoded))
+                 nil nil
+                 (list mm-dissect-disposition
+                       (cons 'filename file-name))))
+
+(defun mm-uu-org-src-code-block-extract ()
+  (mm-make-handle (mm-uu-copy-to-buffer start-point end-point)
+                  '("text/x-org")))
+
+(defvar gnus-newsgroup-name)
+
+(defun mm-uu-emacs-sources-test ()
+  (setq file-name (match-string 1))
+  (and gnus-newsgroup-name
+       mm-uu-emacs-sources-regexp
+       (string-match mm-uu-emacs-sources-regexp gnus-newsgroup-name)))
+
+(defun mm-uu-diff-extract ()
+  (mm-make-handle (mm-uu-copy-to-buffer start-point end-point)
+                 '("text/x-patch" (charset . gnus-decoded))))
+
+(defun mm-uu-diff-test ()
+  (and gnus-newsgroup-name
+       mm-uu-diff-groups-regexp
+       (string-match mm-uu-diff-groups-regexp gnus-newsgroup-name)))
+
+(defun mm-uu-latex-test ()
+  (and gnus-newsgroup-name
+       mm-uu-tex-groups-regexp
+       (string-match mm-uu-tex-groups-regexp gnus-newsgroup-name)))
+
+(defun mm-uu-forward-extract ()
+  (mm-make-handle (mm-uu-copy-to-buffer
+                  (progn
+                    (goto-char start-point)
+                    (forward-line)
+                    (skip-chars-forward "\n")
+                    (point))
+                  (progn (goto-char end-point) (forward-line -1) (point)))
+                 '("message/rfc822" (charset . gnus-decoded))))
+
+(defun mm-uu-uu-extract ()
+  (mm-make-handle (mm-uu-copy-to-buffer start-point end-point)
+                 (list (or (and file-name
+                                (string-match "\\.[^\\.]+$"
+                                              file-name)
+                                (mailcap-extension-to-mime
+                                 (match-string 0 file-name)))
+                           "application/octet-stream"))
+                 'x-uuencode nil
+                 (if (and file-name (not (equal file-name "")))
+                     (list mm-dissect-disposition
+                           (cons 'filename file-name)))))
+
+(defun mm-uu-binhex-extract ()
+  (mm-make-handle (mm-uu-copy-to-buffer start-point end-point)
+                 (list (or (and file-name
+                                (string-match "\\.[^\\.]+$" file-name)
+                                (mailcap-extension-to-mime
+                                 (match-string 0 file-name)))
+                           "application/octet-stream"))
+                 'x-binhex nil
+                 (if (and file-name (not (equal file-name "")))
+                     (list mm-dissect-disposition
+                           (cons 'filename file-name)))))
+
+(defvar gnus-original-article-buffer)   ; gnus.el
+
+(defun mm-uu-yenc-extract ()
+  ;; This might not be exactly correct, but we sure can't get the
+  ;; binary data from the article buffer, since that's already in a
+  ;; non-binary charset.  So get it from the original article buffer.
+  (mm-make-handle (with-current-buffer gnus-original-article-buffer
+                   (mm-uu-copy-to-buffer start-point end-point))
+                 (list (or (and file-name
+                                (string-match "\\.[^\\.]+$" file-name)
+                                (mailcap-extension-to-mime
+                                 (match-string 0 file-name)))
+                           "application/octet-stream"))
+                 'x-yenc nil
+                 (if (and file-name (not (equal file-name "")))
+                     (list mm-dissect-disposition
+                           (cons 'filename file-name)))))
+
+
+(defun mm-uu-shar-extract ()
+  (mm-make-handle (mm-uu-copy-to-buffer start-point end-point)
+                 '("application/x-shar")))
+
+(defun mm-uu-gnatsweb-extract ()
+  (save-restriction
+    (goto-char start-point)
+    (forward-line)
+    (narrow-to-region (point) end-point)
+    (mm-dissect-buffer t)))
+
+(defun mm-uu-pgp-signed-test (&rest rest)
+  (and
+   mml2015-use
+   (mml2015-clear-verify-function)
+   (cond
+    ((eq mm-verify-option 'never) nil)
+    ((eq mm-verify-option 'always) t)
+    ((eq mm-verify-option 'known) t)
+    (t (prog1
+          (y-or-n-p "Verify pgp signed part? ")
+        (message ""))))))
+
+(defvar gnus-newsgroup-charset)
+
+(defun mm-uu-pgp-signed-extract-1 (handles ctl)
+  (let ((buf (mm-uu-copy-to-buffer (point-min) (point-max))))
+    (with-current-buffer buf
+      (if (mm-uu-pgp-signed-test)
+         (progn
+           (mml2015-clean-buffer)
+           (let ((coding-system-for-write (or buffer-file-coding-system
+                                              gnus-newsgroup-charset
+                                              'iso-8859-1))
+                 (coding-system-for-read (or buffer-file-coding-system
+                                             gnus-newsgroup-charset
+                                             'iso-8859-1)))
+             (funcall (mml2015-clear-verify-function))))
+       (when (and mml2015-use (null (mml2015-clear-verify-function)))
+         (mm-set-handle-multipart-parameter
+          mm-security-handle 'gnus-details
+          (gnus-format-message
+           "Clear verification not supported by `%s'.\n" mml2015-use)))
+       (mml2015-extract-cleartext-signature))
+      (list (mm-make-handle buf mm-uu-text-plain-type)))))
+
+(defun mm-uu-pgp-signed-extract ()
+  (let ((mm-security-handle (list (format "multipart/signed"))))
+    (mm-set-handle-multipart-parameter
+     mm-security-handle 'protocol "application/x-gnus-pgp-signature")
+    (save-restriction
+      (narrow-to-region start-point end-point)
+      (add-text-properties 0 (length (car mm-security-handle))
+                          (list 'buffer (mm-uu-copy-to-buffer))
+                          (car mm-security-handle))
+      (setcdr mm-security-handle
+             (mm-uu-pgp-signed-extract-1 nil
+                                         mm-security-handle)))
+    mm-security-handle))
+
+(defun mm-uu-pgp-encrypted-test (&rest rest)
+  (and
+   mml2015-use
+   (mml2015-clear-decrypt-function)
+   (cond
+    ((eq mm-decrypt-option 'never) nil)
+    ((eq mm-decrypt-option 'always) t)
+    ((eq mm-decrypt-option 'known) t)
+    (t (prog1
+          (y-or-n-p "Decrypt pgp encrypted part? ")
+        (message ""))))))
+
+(defun mm-uu-pgp-encrypted-extract-1 (handles ctl)
+  (let ((buf (mm-uu-copy-to-buffer (point-min) (point-max)))
+       (first t)
+       charset)
+    ;; Make sure there's a blank line between header and body.
+    (with-current-buffer buf
+      (goto-char (point-min))
+      (while (prog2
+                (forward-line 1)
+                (if first
+                    (looking-at "[^\t\n ]+:")
+                  (looking-at "[^\t\n ]+:\\|[\t ]"))
+              (setq first nil)))
+      (unless (memq (char-after) '(?\n nil))
+       (insert "\n"))
+      (save-restriction
+       (narrow-to-region (point-min) (point))
+       (setq charset (mail-fetch-field "charset")))
+      (if (and (mm-uu-pgp-encrypted-test)
+              (progn
+                (mml2015-clean-buffer)
+                (funcall (mml2015-clear-decrypt-function))
+                (equal (mm-handle-multipart-ctl-parameter mm-security-handle
+                                                          'gnus-info)
+                       "OK")))
+         (progn
+           ;; Decode charset.
+           (if (and (or charset
+                        (setq charset gnus-newsgroup-charset))
+                    (setq charset (mm-charset-to-coding-system charset))
+                    (not (eq charset 'ascii)))
+               ;; Assume that buffer's multibyteness is turned off.
+               ;; See `mml2015-pgg-clear-decrypt'.
+               (insert (mm-decode-coding-string (prog1
+                                                    (buffer-string)
+                                                  (erase-buffer)
+                                                  (mm-enable-multibyte))
+                                                charset))
+             (mm-enable-multibyte))
+           (list (mm-make-handle buf mm-uu-text-plain-type)))
+       (list (mm-make-handle buf '("application/pgp-encrypted")))))))
+
+(defun mm-uu-pgp-encrypted-extract ()
+  (let ((mm-security-handle (list (format "multipart/encrypted"))))
+    (mm-set-handle-multipart-parameter
+     mm-security-handle 'protocol "application/x-gnus-pgp-encrypted")
+    (save-restriction
+      (narrow-to-region start-point end-point)
+      (add-text-properties 0 (length (car mm-security-handle))
+                          (list 'buffer (mm-uu-copy-to-buffer))
+                          (car mm-security-handle))
+      (setcdr mm-security-handle
+             (mm-uu-pgp-encrypted-extract-1 nil
+                                            mm-security-handle)))
+    mm-security-handle))
+
+(defun mm-uu-gpg-key-skip-to-last ()
+  (let ((point (point))
+       (end-regexp (mm-uu-end-regexp entry))
+       (beginning-regexp (mm-uu-beginning-regexp entry)))
+    (when (and end-regexp
+              (not (mm-uu-configure-p (mm-uu-type entry) 'disabled)))
+      (while (re-search-forward end-regexp nil t)
+       (skip-chars-forward " \t\n\r")
+       (if (looking-at beginning-regexp)
+           (setq point (match-end 0)))))
+    (goto-char point)))
+
+(defun mm-uu-pgp-key-extract ()
+  (let ((buf (mm-uu-copy-to-buffer start-point end-point)))
+    (mm-make-handle buf
+                   '("application/pgp-keys"))))
+
+;;;###autoload
+(defun mm-uu-dissect (&optional noheader mime-type)
+  "Dissect the current buffer and return a list of uu handles.
+The optional NOHEADER means there's no header in the buffer.
+MIME-TYPE specifies a MIME type and parameters, which defaults to the
+value of `mm-uu-text-plain-type'."
+  (let ((case-fold-search t)
+       (mm-uu-text-plain-type (or mime-type mm-uu-text-plain-type))
+       text-start start-point end-point file-name result entry func)
+    (save-excursion
+      (goto-char (point-min))
+      (cond
+       (noheader)
+       ((looking-at "\n")
+       (forward-line))
+       ((search-forward "\n\n" nil t)
+       t)
+       (t (goto-char (point-max))))
+      (setq text-start (point))
+      (while (re-search-forward mm-uu-beginning-regexp nil t)
+       (setq start-point (match-beginning 0)
+             entry nil)
+       (let ((alist mm-uu-type-alist)
+             (beginning-regexp (match-string 0)))
+         (while (not entry)
+           (if (string-match (mm-uu-beginning-regexp (car alist))
+                             beginning-regexp)
+               (setq entry (car alist))
+             (pop alist))))
+       (if (setq func (mm-uu-function-1 entry))
+           (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)))
+                    (if (not end-regexp)
+                        (or (setq end-point (point-max)) t)
+                      (prog1
+                          (re-search-forward end-regexp nil t)
+                        (forward-line)
+                        (setq end-point (point)))))
+                  (or (not (setq func (mm-uu-function-2 entry)))
+                      (funcall func)))
+         (if (and (> start-point text-start)
+                  (progn
+                    (goto-char text-start)
+                    (re-search-forward "." start-point t)))
+             (push
+              (mm-make-handle
+               (mm-uu-copy-to-buffer
+                text-start
+                ;; A start-separator is likely accompanied by
+                ;; a leading newline.
+                (if (and (eq (char-before start-point) ?\n)
+                         (eq (char-before (1- start-point)) ?\n))
+                    (1- start-point)
+                  start-point))
+               mm-uu-text-plain-type)
+              result))
+         (push
+          (funcall (mm-uu-function-extract entry))
+          result)
+         (goto-char (setq text-start end-point))))
+      (when result
+       (goto-char text-start)
+       (when (re-search-forward "." nil t)
+         (push (mm-make-handle
+                (mm-uu-copy-to-buffer
+                 ;; An end-separator is likely accompanied by
+                 ;; a trailing newline.
+                 (if (eq (char-after text-start) ?\n)
+                     (1+ text-start)
+                   text-start)
+                 (point-max))
+                mm-uu-text-plain-type)
+               result))
+       (setq result (cons "multipart/mixed" (nreverse result))))
+      result)))
+
+;;;###autoload
+(defun mm-uu-dissect-text-parts (handle &optional decoded)
+  "Dissect text parts and put uu handles into HANDLE.
+Assume text has been decoded if DECODED is non-nil."
+  (let ((buffer (mm-handle-buffer handle)))
+    (cond ((stringp buffer)
+          (dolist (elem (cdr handle))
+            (mm-uu-dissect-text-parts elem decoded)))
+         ((bufferp buffer)
+          (let ((type (mm-handle-media-type handle))
+                (case-fold-search t) ;; string-match
+                children charset encoding)
+            (when (and
+                   (stringp type)
+                   ;; Mutt still uses application/pgp even though
+                   ;; it has already been withdrawn.
+                   (string-match "\\`text/\\|\\`application/pgp\\'" type)
+                    (equal (car (mm-handle-disposition handle))
+                           "inline")
+                   (setq
+                    children
+                    (with-current-buffer buffer
+                      (cond
+                       ((or decoded
+                            (eq (setq charset (mail-content-type-get
+                                               (mm-handle-type handle)
+                                               'charset))
+                                'gnus-decoded))
+                        (setq decoded t)
+                        (mm-uu-dissect
+                         t (cons type '((charset . gnus-decoded)))))
+                       (charset
+                        (setq decoded t)
+                        (mm-with-multibyte-buffer
+                          (insert (mm-decode-string (mm-get-part handle)
+                                                    charset))
+                          (mm-uu-dissect
+                           t (cons type '((charset . gnus-decoded))))))
+                       ((setq encoding (mm-handle-encoding handle))
+                        (setq decoded nil)
+                        ;; Inherit the multibyteness of the `buffer'.
+                        (with-temp-buffer
+                          (insert-buffer-substring buffer)
+                          (mm-decode-content-transfer-encoding
+                           encoding type)
+                          (mm-uu-dissect t (list type))))
+                       (t
+                        (setq decoded nil)
+                        (mm-uu-dissect t (list type)))))))
+              ;; Ignore it if a given part is dissected into a single
+              ;; part of which the type is the same as the given one.
+              (if (and (<= (length children) 2)
+                       (string-equal (mm-handle-media-type (cadr children))
+                                     type))
+                  (kill-buffer (mm-handle-buffer (cadr children)))
+                (kill-buffer buffer)
+                (setcdr handle (cdr children))
+                (setcar handle (car children)) ;; "multipart/mixed"
+                (dolist (elem (cdr children))
+                  (mm-uu-dissect-text-parts elem decoded))))))
+         (t
+          (dolist (elem handle)
+            (mm-uu-dissect-text-parts elem decoded))))))
+
+(provide 'mm-uu)
+
+;; Local Variables:
+;; coding: utf-8
+;; End:
+
+;;; mm-uu.el ends here
diff --git a/xemacs-packages/gnus/lisp/mm-view.el b/xemacs-packages/gnus/lisp/mm-view.el
new file mode 100644 (file)
index 0000000..9942455
--- /dev/null
@@ -0,0 +1,661 @@
+;;; mm-view.el --- functions for viewing MIME objects
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(require 'mail-parse)
+(require 'mailcap)
+(require 'mm-bodies)
+(require 'mm-decode)
+(require 'smime)
+(require 'mml-smime)
+
+(autoload 'gnus-completing-read "gnus-util")
+(autoload 'gnus-window-inside-pixel-edges "gnus-ems")
+(autoload 'gnus-article-prepare-display "gnus-art")
+(autoload 'vcard-parse-string "vcard")
+(autoload 'vcard-format-string "vcard")
+(autoload 'fill-flowed "flow-fill")
+(autoload 'html2text "html2text" nil t)
+
+(defvar gnus-article-mime-handles)
+(defvar gnus-newsgroup-charset)
+(defvar smime-keys)
+(defvar w3m-cid-retrieve-function-alist)
+(defvar w3m-current-buffer)
+(defvar w3m-display-inline-images)
+(defvar w3m-minor-mode-map)
+
+(defvar mm-text-html-renderer-alist
+  '((shr . mm-shr)
+    (w3m . mm-inline-text-html-render-with-w3m)
+    (w3m-standalone . mm-inline-text-html-render-with-w3m-standalone)
+    (gnus-w3m . gnus-article-html)
+    (links mm-inline-render-with-file
+          mm-links-remove-leading-blank
+          "links" "-dump" file)
+    (lynx mm-inline-render-with-stdin nil
+         "lynx" "-dump" "-force_html" "-stdin" "-nolist")
+    (html2text mm-inline-render-with-function html2text))
+  "The attributes of renderer types for text/html.")
+
+(defcustom mm-fill-flowed t
+  "If non-nil a format=flowed article will be displayed flowed."
+  :type 'boolean
+  :version "22.1"
+  :group 'mime-display)
+
+(defcustom mm-inline-large-images-proportion 0.9
+  "Maximum proportion of large image resized when
+`mm-inline-large-images' is set to resize."
+  :type 'float
+  :version "24.1"
+  :group 'mime-display)
+
+;;; Internal variables.
+
+;;;
+;;; Functions for displaying various formats inline
+;;;
+
+(autoload 'gnus-rescale-image "gnus-util")
+
+(defun mm-inline-image-emacs (handle)
+  (let ((b (point-marker))
+       (inhibit-read-only t))
+    (put-image
+     (let ((image (mm-get-image handle)))
+       (if (eq mm-inline-large-images 'resize)
+           (gnus-rescale-image
+           image
+           (let ((edges (gnus-window-inside-pixel-edges
+                         (get-buffer-window (current-buffer)))))
+             (cons (truncate (* mm-inline-large-images-proportion
+                                (- (nth 2 edges) (nth 0 edges))))
+                   (truncate (* mm-inline-large-images-proportion
+                                (- (nth 3 edges) (nth 1 edges)))))))
+         image))
+     b)
+    (insert "\n")
+    (mm-handle-set-undisplayer
+     handle
+     `(lambda ()
+       (let ((b ,b)
+             (inhibit-read-only t))
+         (remove-images b b)
+         (delete-region b (1+ b)))))))
+
+(defun mm-inline-image-xemacs (handle)
+  (when (featurep 'xemacs)
+    (insert "\n")
+    (forward-char -1)
+    (let ((annot (make-annotation (mm-get-image handle) nil 'text))
+       (inhibit-read-only t))
+      (mm-handle-set-undisplayer
+       handle
+       `(lambda ()
+         (let ((b ,(point-marker))
+             (inhibit-read-only t))
+           (delete-annotation ,annot)
+           (delete-region (1- b) b))))
+      (set-extent-property annot 'mm t)
+      (set-extent-property annot 'duplicable t))))
+
+(eval-and-compile
+  (if (featurep 'xemacs)
+      (defalias 'mm-inline-image 'mm-inline-image-xemacs)
+    (defalias 'mm-inline-image 'mm-inline-image-emacs)))
+
+(defvar mm-w3m-setup nil
+  "Whether gnus-article-mode has been setup to use emacs-w3m.")
+
+;; External.
+(declare-function w3m-detect-meta-charset "ext:w3m" ())
+(declare-function w3m-region "ext:w3m" (start end &optional url charset))
+
+(defun mm-setup-w3m ()
+  "Setup gnus-article-mode to use emacs-w3m."
+  (unless mm-w3m-setup
+    (require 'w3m)
+    (unless (assq 'gnus-article-mode w3m-cid-retrieve-function-alist)
+      (push (cons 'gnus-article-mode 'mm-w3m-cid-retrieve)
+           w3m-cid-retrieve-function-alist))
+    (setq mm-w3m-setup t))
+  (setq w3m-display-inline-images mm-inline-text-html-with-images))
+
+(defun mm-w3m-cid-retrieve-1 (url handle)
+  (dolist (elem handle)
+    (when (consp elem)
+      (when (equal url (mm-handle-id elem))
+       (mm-insert-part elem)
+       (throw 'found-handle (mm-handle-media-type elem)))
+      (when (and (stringp (car elem))
+                (equal "multipart" (mm-handle-media-supertype elem)))
+       (mm-w3m-cid-retrieve-1 url elem)))))
+
+(defun mm-w3m-cid-retrieve (url &rest args)
+  "Insert a content pointed by URL if it has the cid: scheme."
+  (when (string-match "\\`cid:" url)
+    (or (catch 'found-handle
+         (mm-w3m-cid-retrieve-1
+          (setq url (concat "<" (substring url (match-end 0)) ">"))
+          (with-current-buffer w3m-current-buffer
+            gnus-article-mime-handles)))
+       (prog1
+           nil
+         (message "Failed to find \"Content-ID: %s\"" url)))))
+
+(defun mm-inline-text-html-render-with-w3m (handle)
+  "Render a text/html part using emacs-w3m."
+  (mm-setup-w3m)
+  (let ((text (mm-get-part handle))
+       (b (point))
+       (charset (or (mail-content-type-get (mm-handle-type handle) 'charset)
+                    mail-parse-charset)))
+    (save-excursion
+      (insert (if charset (mm-decode-string text charset) text))
+      (save-restriction
+       (narrow-to-region b (point))
+       (unless charset
+         (goto-char (point-min))
+         (when (setq charset (w3m-detect-meta-charset))
+           (delete-region (point-min) (point-max))
+           (insert (mm-decode-string text charset))))
+       (let ((w3m-safe-url-regexp mm-w3m-safe-url-regexp)
+             w3m-force-redisplay)
+         (w3m-region (point-min) (point-max) nil charset))
+       ;; Put the mark meaning this part was rendered by emacs-w3m.
+       (put-text-property (point-min) (point-max)
+                          'mm-inline-text-html-with-w3m t)
+       (when (and mm-inline-text-html-with-w3m-keymap
+                  (boundp 'w3m-minor-mode-map)
+                  w3m-minor-mode-map)
+         (if (and (boundp 'w3m-link-map)
+                  w3m-link-map)
+             (let* ((start (point-min))
+                    (end (point-max))
+                    (on (get-text-property start 'w3m-href-anchor))
+                    (map (copy-keymap w3m-link-map))
+                    next)
+               (set-keymap-parent map w3m-minor-mode-map)
+               (while (< start end)
+                 (if on
+                     (progn
+                       (setq next (or (text-property-any start end
+                                                         'w3m-href-anchor nil)
+                                      end))
+                       (put-text-property start next 'keymap map))
+                   (setq next (or (text-property-not-all start end
+                                                         'w3m-href-anchor nil)
+                                  end))
+                   (put-text-property start next 'keymap w3m-minor-mode-map))
+                 (setq start next
+                       on (not on))))
+           (put-text-property (point-min) (point-max)
+                              'keymap w3m-minor-mode-map)))
+       (mm-handle-set-undisplayer
+        handle
+        `(lambda ()
+           (let ((inhibit-read-only t))
+             (delete-region ,(point-min-marker)
+                            ,(point-max-marker)))))))))
+
+(defvar mm-w3m-standalone-supports-m17n-p (if (featurep 'mule) 'undecided)
+  "*T means the w3m command supports the m17n feature.")
+
+(defun mm-w3m-standalone-supports-m17n-p ()
+  "Say whether the w3m command supports the m17n feature."
+  (cond ((eq mm-w3m-standalone-supports-m17n-p t) t)
+       ((eq mm-w3m-standalone-supports-m17n-p nil) nil)
+       ((not (featurep 'mule)) (setq mm-w3m-standalone-supports-m17n-p nil))
+       ((condition-case nil
+            (let ((coding-system-for-write 'iso-2022-jp)
+                  (coding-system-for-read 'iso-2022-jp)
+                  (str (mm-decode-coding-string "\
+\e$B#D#o#e#s!!#w#3#m!!#s#u#p#p#o#r#t!!#m#1#7#n!)\e(B" 'iso-2022-jp)))
+              (mm-with-multibyte-buffer
+                (insert str)
+                (call-process-region
+                 (point-min) (point-max) "w3m" t t nil "-dump"
+                 "-T" "text/html" "-I" "iso-2022-jp" "-O" "iso-2022-jp")
+                (goto-char (point-min))
+                (search-forward str nil t)))
+          (error nil))
+        (setq mm-w3m-standalone-supports-m17n-p t))
+       (t
+        ;;(message "You had better upgrade your w3m command")
+        (setq mm-w3m-standalone-supports-m17n-p nil))))
+
+(defun mm-inline-text-html-render-with-w3m-standalone (handle)
+  "Render a text/html part using w3m."
+  (if (mm-w3m-standalone-supports-m17n-p)
+      (let ((source (mm-get-part handle))
+           (charset (or (mail-content-type-get (mm-handle-type handle)
+                                               'charset)
+                        (symbol-name mail-parse-charset)))
+           cs)
+       (if (and charset
+                (setq cs (mm-charset-to-coding-system charset nil t))
+                (not (eq cs 'ascii)))
+           (setq charset (format "%s" (mm-coding-system-to-mime-charset cs)))
+         ;; The default.
+         (setq charset "iso-8859-1"
+               cs 'iso-8859-1))
+       (mm-insert-inline
+        handle
+        (mm-with-unibyte-buffer
+          (insert source)
+          (mm-enable-multibyte)
+          (let ((coding-system-for-write 'binary)
+                (coding-system-for-read cs))
+            (call-process-region
+             (point-min) (point-max)
+             "w3m" t t nil "-dump" "-T" "text/html"
+             "-I" charset "-O" charset))
+          (buffer-string))))
+    (mm-inline-render-with-stdin handle nil "w3m" "-dump" "-T" "text/html")))
+
+(defun mm-links-remove-leading-blank ()
+  ;; Delete the annoying three spaces preceding each line of links
+  ;; output.
+  (goto-char (point-min))
+  (while (re-search-forward "^   " nil t)
+    (delete-region (match-beginning 0) (match-end 0))))
+
+(defun mm-inline-wash-with-file (post-func cmd &rest args)
+  (let ((file (mm-make-temp-file
+              (expand-file-name "mm" mm-tmp-directory))))
+    (let ((coding-system-for-write 'binary))
+      (write-region (point-min) (point-max) file nil 'silent))
+    (delete-region (point-min) (point-max))
+    (unwind-protect
+       (apply 'call-process cmd nil t nil (mapcar 'eval args))
+      (delete-file file))
+    (and post-func (funcall post-func))))
+
+(defun mm-inline-wash-with-stdin (post-func cmd &rest args)
+  (let ((coding-system-for-write 'binary))
+    (apply 'call-process-region (point-min) (point-max)
+          cmd t t nil args))
+  (and post-func (funcall post-func)))
+
+(defun mm-inline-render-with-file (handle post-func cmd &rest args)
+  (let ((source (mm-get-part handle)))
+    (mm-insert-inline
+     handle
+     (mm-with-unibyte-buffer
+       (insert source)
+       (apply 'mm-inline-wash-with-file post-func cmd args)
+       (buffer-string)))))
+
+(defun mm-inline-render-with-stdin (handle post-func cmd &rest args)
+  (let ((source (mm-get-part handle)))
+    (mm-insert-inline
+     handle
+     (mm-with-unibyte-buffer
+       (insert source)
+       (apply 'mm-inline-wash-with-stdin post-func cmd args)
+       (buffer-string)))))
+
+(defun mm-inline-render-with-function (handle func &rest args)
+  (let ((source (mm-get-part handle))
+       (charset (or (mail-content-type-get (mm-handle-type handle) 'charset)
+                    mail-parse-charset)))
+    (mm-insert-inline
+     handle
+     (mm-with-multibyte-buffer
+       (insert (if charset
+                  (mm-decode-string source charset)
+                source))
+       (apply func args)
+       (buffer-string)))))
+
+(defun mm-inline-text-html (handle)
+  (if (stringp (car handle))
+      (mapcar 'mm-inline-text-html (cdr handle))
+    (let* ((func mm-text-html-renderer)
+          (entry (assq func mm-text-html-renderer-alist))
+          (inhibit-read-only t))
+      (if entry
+         (setq func (cdr entry)))
+      (cond
+       ((functionp func)
+       (funcall func handle))
+       (t
+       (apply (car func) handle (cdr func)))))))
+
+(defun mm-inline-text-vcard (handle)
+  (let ((inhibit-read-only t))
+    (mm-insert-inline
+     handle
+     (concat "\n-- \n"
+            (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))))))))
+
+(defun mm-inline-text (handle)
+  (let ((b (point))
+       (type (mm-handle-media-subtype handle))
+       (charset (mail-content-type-get
+                 (mm-handle-type handle) 'charset))
+       (inhibit-read-only t))
+    (if (or (eq charset 'gnus-decoded)
+           ;; This is probably not entirely correct, but
+           ;; makes rfc822 parts with embedded multiparts work.
+           (eq mail-parse-charset 'gnus-decoded))
+       (save-restriction
+         (narrow-to-region (point) (point))
+         (mm-insert-part handle)
+         (goto-char (point-max)))
+      (mm-display-inline-fontify handle))
+    (when (and mm-fill-flowed
+              (equal type "plain")
+              (equal (cdr (assoc 'format (mm-handle-type handle)))
+                     "flowed"))
+      (save-restriction
+       (narrow-to-region b (point))
+       (goto-char b)
+       (fill-flowed nil (equal (cdr (assoc 'delsp (mm-handle-type handle)))
+                               "yes"))
+       (goto-char (point-max))))
+    (save-restriction
+      (narrow-to-region b (point))
+      (when (member type '("enriched" "richtext"))
+        (set-text-properties (point-min) (point-max) nil)
+       (ignore-errors
+         (enriched-decode (point-min) (point-max))))
+      (mm-handle-set-undisplayer
+       handle
+       `(lambda ()
+          (let ((inhibit-read-only t))
+           (delete-region ,(copy-marker (point-min) t)
+                          ,(point-max-marker))))))))
+
+(defun mm-insert-inline (handle text)
+  "Insert TEXT inline from HANDLE."
+  (let ((b (point)))
+    (insert text)
+    (unless (bolp)
+      (insert "\n"))
+    (mm-handle-set-undisplayer
+     handle
+     `(lambda ()
+       (let ((inhibit-read-only t))
+         (delete-region ,(copy-marker b t)
+                        ,(point-marker)))))))
+
+(defun mm-inline-audio (handle)
+  (message "Not implemented"))
+
+(defun mm-view-message ()
+  (mm-enable-multibyte)
+  (let (handles)
+    (let (gnus-article-mime-handles)
+      ;; Double decode problem may happen.  See mm-inline-message.
+      (run-hooks 'gnus-article-decode-hook)
+      (gnus-article-prepare-display)
+      (setq handles gnus-article-mime-handles))
+    (when handles
+      (setq gnus-article-mime-handles
+           (mm-merge-handles gnus-article-mime-handles handles))))
+  (fundamental-mode)
+  (goto-char (point-min)))
+
+(defun mm-inline-message (handle)
+  (let ((b (point))
+       (bolp (bolp))
+       (charset (mail-content-type-get
+                 (mm-handle-type handle) 'charset))
+       gnus-displaying-mime handles)
+    (when (and charset
+              (stringp charset))
+      (setq charset (intern (downcase charset)))
+      (when (eq charset 'us-ascii)
+       (setq charset nil)))
+    (save-excursion
+      (save-restriction
+       (narrow-to-region b b)
+       (mm-insert-part handle)
+       (let (gnus-article-mime-handles
+             ;; disable prepare hook
+             gnus-article-prepare-hook
+             (gnus-newsgroup-charset
+              (unless (eq charset 'gnus-decoded) ;; mm-uu might set it.
+                (or charset gnus-newsgroup-charset))))
+         (let ((gnus-original-article-buffer (mm-handle-buffer handle)))
+           (run-hooks 'gnus-article-decode-hook))
+         (gnus-article-prepare-display)
+         (setq handles gnus-article-mime-handles))
+       (goto-char (point-min))
+       (unless bolp
+         (insert "\n"))
+       (goto-char (point-max))
+       (unless (bolp)
+         (insert "\n"))
+       (insert "----------\n\n")
+       (when handles
+         (setq gnus-article-mime-handles
+               (mm-merge-handles gnus-article-mime-handles handles)))
+       (mm-handle-set-undisplayer
+        handle
+        `(lambda ()
+           (let ((inhibit-read-only t))
+             (if (fboundp 'remove-specifier)
+                 ;; This is only valid on XEmacs.
+                 (dolist (prop '(background background-pixmap foreground))
+                   (remove-specifier
+                    (face-property 'default prop) (current-buffer))))
+             (delete-region ,(point-min-marker) ,(point-max-marker)))))))))
+
+;; Shut up byte-compiler.
+(defvar font-lock-mode-hook)
+(defun mm-display-inline-fontify (handle &optional mode)
+  "Insert HANDLE inline fontifying with MODE.
+If MODE is not set, try to find mode automatically."
+  (let ((charset (mail-content-type-get (mm-handle-type handle) 'charset))
+       text coding-system)
+    (unless (eq charset 'gnus-decoded)
+      (mm-with-unibyte-buffer
+       (mm-insert-part handle)
+       (mm-decompress-buffer
+         (mm-handle-filename handle)
+        t t)
+       (unless charset
+         (setq coding-system (mm-find-buffer-file-coding-system)))
+       (setq text (buffer-string))))
+    ;; XEmacs @#$@ version of font-lock refuses to fully turn itself
+    ;; on for buffers whose name begins with " ".  That's why we use
+    ;; `with-current-buffer'/`generate-new-buffer' rather than
+    ;; `with-temp-buffer'.
+    (with-current-buffer (generate-new-buffer "*fontification*")
+      (buffer-disable-undo)
+      (mm-enable-multibyte)
+      (insert (cond ((eq charset 'gnus-decoded)
+                    (with-current-buffer (mm-handle-buffer handle)
+                      (buffer-string)))
+                   (coding-system
+                    (mm-decode-coding-string text coding-system))
+                   (charset
+                    (mm-decode-string text charset))
+                   (t
+                    text)))
+      (require 'font-lock)
+      ;; I find font-lock a bit too verbose.
+      (let ((font-lock-verbose nil)
+           (font-lock-support-mode nil))
+       ;; Disable support modes, e.g., jit-lock, lazy-lock, etc.
+       ;; Note: XEmacs people use `font-lock-mode-hook' to run those modes.
+       (set (make-local-variable 'font-lock-mode-hook) nil)
+        (setq buffer-file-name (mm-handle-filename handle))
+        (set (make-local-variable 'enable-local-variables) nil)
+       (with-demoted-errors
+         (if mode
+             (save-window-excursion
+               (switch-to-buffer (current-buffer))
+               (funcall mode))
+           (let ((auto-mode-alist
+                  (delq (rassq 'doc-view-mode-maybe auto-mode-alist)
+                        (copy-sequence auto-mode-alist))))
+             (set-auto-mode)))
+         ;; The mode function might have already turned on font-lock.
+         ;; Do not fontify if the guess mode is fundamental.
+         (unless (or font-lock-mode
+                     (eq major-mode 'fundamental-mode))
+            (if (fboundp 'font-lock-ensure)
+                (font-lock-ensure)
+              (font-lock-fontify-buffer)))))
+      ;; By default, XEmacs font-lock uses non-duplicable text
+      ;; properties.  This code forces all the text properties
+      ;; to be copied along with the text.
+      (when (featurep 'xemacs)
+       (map-extents (lambda (ext ignored)
+                      (set-extent-property ext 'duplicable t)
+                      nil)
+                    nil nil nil nil nil 'text-prop))
+      (setq text (buffer-string))
+      ;; Set buffer unmodified to avoid confirmation when killing the
+      ;; buffer.
+      (set-buffer-modified-p nil)
+      (kill-buffer (current-buffer)))
+    (mm-insert-inline handle text)))
+
+;; Shouldn't these functions check whether the user even wants to use
+;; font-lock?  At least under XEmacs, this fontification is pretty
+;; much unconditional.  Also, it would be nice to change for the size
+;; of the fontified region.
+
+(defun mm-display-patch-inline (handle)
+  (mm-display-inline-fontify handle 'diff-mode))
+
+(defun mm-display-elisp-inline (handle)
+  (mm-display-inline-fontify handle 'emacs-lisp-mode))
+
+(defun mm-display-dns-inline (handle)
+  (mm-display-inline-fontify handle 'dns-mode))
+
+(defun mm-display-org-inline (handle)
+  "Show an Org mode text from HANDLE inline."
+  (mm-display-inline-fontify handle 'org-mode))
+
+(defun mm-display-shell-script-inline (handle)
+  "Show a shell script from HANDLE inline."
+  (mm-display-inline-fontify handle 'shell-script-mode))
+
+(defun mm-display-javascript-inline (handle)
+  "Show JavsScript code from HANDLE inline."
+  (mm-display-inline-fontify handle 'javascript-mode))
+
+;;      id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+;;          us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 }
+(defvar mm-pkcs7-signed-magic
+  (concat
+    "0"
+    "\\(\\(\x80\\)"
+    "\\|\\(\x81\\(.\\|\n\\)\\{1\\}\\)"
+    "\\|\\(\x82\\(.\\|\n\\)\\{2\\}\\)"
+    "\\|\\(\x83\\(.\\|\n\\)\\{3\\}\\)"
+    "\\)"
+    "\x06\x09\\*\x86H\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
+  (concat
+    "0"
+    "\\(\\(\x80\\)"
+    "\\|\\(\x81\\(.\\|\n\\)\\{1\\}\\)"
+    "\\|\\(\x82\\(.\\|\n\\)\\{2\\}\\)"
+    "\\|\\(\x83\\(.\\|\n\\)\\{3\\}\\)"
+    "\\)"
+    "\x06\x09\\*\x86H\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 &optional from)
+  (case (mm-view-pkcs7-get-type handle)
+    (enveloped (mm-view-pkcs7-decrypt handle from))
+    (signed (mm-view-pkcs7-verify handle))
+    (otherwise (error "Unknown or unimplemented PKCS#7 type"))))
+
+(defun mm-view-pkcs7-verify (handle)
+  (let ((verified nil))
+    (with-temp-buffer
+      (insert "MIME-Version: 1.0\n")
+      (mm-insert-headers "application/pkcs7-mime" "base64" "smime.p7m")
+      (insert-buffer-substring (mm-handle-buffer handle))
+      (setq verified (smime-verify-region (point-min) (point-max))))
+    (goto-char (point-min))
+    (mm-insert-part handle)
+    (if (search-forward "Content-Type: " nil t)
+       (delete-region (point-min) (match-beginning 0)))
+    (goto-char (point-max))
+    (if (re-search-backward "--\r?\n?" nil t)
+       (delete-region (match-end 0) (point-max)))
+    (unless verified
+      (insert-buffer-substring smime-details-buffer)))
+  (goto-char (point-min))
+  (while (search-forward "\r\n" nil t)
+    (replace-match "\n"))
+  t)
+
+(autoload 'epg-decrypt-string "epg")
+
+(defun mm-view-pkcs7-decrypt (handle &optional from)
+  (insert-buffer-substring (mm-handle-buffer handle))
+  (goto-char (point-min))
+  (if (eq mml-smime-use 'epg)
+      ;; Use EPG/gpgsm
+      (let ((part (base64-decode-string (buffer-string))))
+       (erase-buffer)
+       (insert (epg-decrypt-string (epg-make-context 'CMS) part)))
+    ;; Use openssl
+    (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
+       (gnus-completing-read
+        "Decipher using key"
+        smime-keys nil nil nil (car-safe (car-safe smime-keys)))))
+     from))
+  (goto-char (point-min))
+  (while (search-forward "\r\n" nil t)
+    (replace-match "\n"))
+  (goto-char (point-min)))
+
+(provide 'mm-view)
+
+;;; mm-view.el ends here
diff --git a/xemacs-packages/gnus/lisp/mml-sec.el b/xemacs-packages/gnus/lisp/mml-sec.el
new file mode 100644 (file)
index 0000000..0a5f472
--- /dev/null
@@ -0,0 +1,958 @@
+;;; mml-sec.el --- A package with security functions for MML documents
+
+;; Copyright (C) 2000-2016 Free Software Foundation, Inc.
+
+;; Author: Simon Josefsson <simon@josefsson.org>
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'gnus-util)
+(require 'epg)
+
+(autoload 'mail-strip-quoted-names "mail-utils")
+(autoload 'mml2015-sign "mml2015")
+(autoload 'mml2015-encrypt "mml2015")
+(autoload 'mml1991-sign "mml1991")
+(autoload 'mml1991-encrypt "mml1991")
+(autoload 'message-fetch-field "message")
+(autoload 'message-goto-body "message")
+(autoload 'mml-insert-tag "mml")
+(autoload 'mml-smime-sign "mml-smime")
+(autoload 'mml-smime-encrypt "mml-smime")
+(autoload 'mml-smime-sign-query "mml-smime")
+(autoload 'mml-smime-encrypt-query "mml-smime")
+(autoload 'mml-smime-verify "mml-smime")
+(autoload 'mml-smime-verify-test "mml-smime")
+(autoload 'epa--select-keys "epa")
+
+(defvar mml-sign-alist
+  '(("smime"     mml-smime-sign-buffer     mml-smime-sign-query)
+    ("pgp"       mml-pgp-sign-buffer       list)
+    ("pgpauto"   mml-pgpauto-sign-buffer  list)
+    ("pgpmime"   mml-pgpmime-sign-buffer   list))
+  "Alist of MIME signer functions.")
+
+(defcustom mml-default-sign-method "pgpmime"
+  "Default sign method.
+The string must have an entry in `mml-sign-alist'."
+  :version "22.1"
+  :type '(choice (const "smime")
+                (const "pgp")
+                (const "pgpauto")
+                (const "pgpmime")
+                string)
+  :group 'message)
+
+(defvar mml-encrypt-alist
+  '(("smime"     mml-smime-encrypt-buffer     mml-smime-encrypt-query)
+    ("pgp"       mml-pgp-encrypt-buffer       list)
+    ("pgpauto"   mml-pgpauto-sign-buffer  list)
+    ("pgpmime"   mml-pgpmime-encrypt-buffer   list))
+  "Alist of MIME encryption functions.")
+
+(defcustom mml-default-encrypt-method "pgpmime"
+  "Default encryption method.
+The string must have an entry in `mml-encrypt-alist'."
+  :version "22.1"
+  :type '(choice (const "smime")
+                (const "pgp")
+                (const "pgpauto")
+                (const "pgpmime")
+                string)
+  :group 'message)
+
+(defcustom mml-signencrypt-style-alist
+  '(("smime"   separate)
+    ("pgp"     combined)
+    ("pgpauto" combined)
+    ("pgpmime" combined))
+  "Alist specifying if `signencrypt' results in two separate operations or not.
+The first entry indicates the MML security type, valid entries include
+the strings \"smime\", \"pgp\", and \"pgpmime\".  The second entry is
+a symbol `separate' or `combined' where `separate' means that MML signs
+and encrypt messages in a two step process, and `combined' means that MML
+signs and encrypt the message in one step.
+
+Note that the output generated by using a `combined' mode is NOT
+understood by all PGP implementations, in particular PGP version
+2 does not support it!  See Info node `(message) Security' for
+details."
+  :version "22.1"
+  :group 'message
+  :type '(repeat (list (choice (const :tag "S/MIME" "smime")
+                              (const :tag "PGP" "pgp")
+                              (const :tag "PGP/MIME" "pgpmime")
+                              (string :tag "User defined"))
+                      (choice (const :tag "Separate" separate)
+                              (const :tag "Combined" combined)))))
+
+(defcustom mml-secure-verbose nil
+  "If non-nil, ask the user about the current operation more verbosely."
+  :group 'message
+  :type 'boolean)
+
+(defcustom mml-secure-cache-passphrase
+  (if (boundp 'password-cache)
+      password-cache
+    t)
+  "If t, cache OpenPGP or S/MIME passphrases inside Emacs.
+Passphrase caching in Emacs is NOT recommended.  Use gpg-agent instead.
+See Info node `(message) Security'."
+  :group 'message
+  :type 'boolean)
+
+(defcustom mml-secure-passphrase-cache-expiry
+  (if (boundp 'password-cache-expiry)
+      password-cache-expiry
+    16)
+  "How many seconds the passphrase is cached.
+Whether the passphrase is cached at all is controlled by
+`mml-secure-cache-passphrase'."
+  :group 'message
+  :type 'integer)
+
+(defcustom mml-secure-safe-bcc-list nil
+  "List of e-mail addresses that are safe to use in Bcc headers.
+EasyPG encrypts e-mails to Bcc addresses, and the encrypted e-mail
+by default identifies the used encryption keys, giving away the
+Bcc'ed identities.  Clearly, this contradicts the original goal of
+*blind* copies.
+For an academic paper explaining the problem, see URL
+`http://crypto.stanford.edu/portia/papers/bb-bcc.pdf'.
+Use this variable to specify e-mail addresses whose owners do not
+mind if they are identifiable as recipients.  This may be useful if
+you use Bcc headers to encrypt e-mails to yourself."
+  :version "25.1"
+  :group 'message
+  :type '(repeat string))
+
+;;; Configuration/helper functions
+
+(defun mml-signencrypt-style (method &optional style)
+  "Function for setting/getting the signencrypt-style used.  Takes two
+arguments, the method (e.g. \"pgp\") and optionally the mode
+\(e.g. combined).  If the mode is omitted, the current value is returned.
+
+For example, if you prefer to use combined sign & encrypt with
+smime, putting the following in your Gnus startup file will
+enable that behavior:
+
+\(mml-set-signencrypt-style \"smime\" combined)
+
+You can also customize or set `mml-signencrypt-style-alist' instead."
+  (let ((style-item (assoc method mml-signencrypt-style-alist)))
+    (if style-item
+       (if (or (eq style 'separate)
+               (eq style 'combined))
+           ;; valid style setting?
+           (setf (second style-item) style)
+         ;; otherwise, just return the current value
+         (second style-item))
+      (message "Warning, attempt to set invalid signencrypt style"))))
+
+;;; Security functions
+
+(defun mml-smime-sign-buffer (cont)
+  (or (mml-smime-sign cont)
+      (error "Signing failed... inspect message logs for errors")))
+
+(defun mml-smime-encrypt-buffer (cont &optional sign)
+  (when sign
+    (message "Combined sign and encrypt S/MIME not support yet")
+    (sit-for 1))
+  (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 &optional sign)
+  (or (mml1991-encrypt cont sign)
+      (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")))
+
+(defun mml-pgpmime-encrypt-buffer (cont &optional sign)
+  (or (mml2015-encrypt cont sign)
+      (error "Encryption failed... inspect message logs for errors")))
+
+(defun mml-pgpauto-sign-buffer (cont)
+  (message-goto-body)
+  (or (if (re-search-backward "Content-Type: *multipart/.*" nil t) ; there must be a better way...
+         (mml2015-sign cont)
+       (mml1991-sign cont))
+      (error "Encryption failed... inspect message logs for errors")))
+
+(defun mml-pgpauto-encrypt-buffer (cont &optional sign)
+  (message-goto-body)
+  (or (if (re-search-backward "Content-Type: *multipart/.*" nil t) ; there must be a better way...
+         (mml2015-encrypt cont sign)
+       (mml1991-encrypt cont sign))
+      (error "Encryption failed... inspect message logs for errors")))
+
+(defun mml-secure-part (method &optional sign)
+  (save-excursion
+    (let ((tags (funcall (nth 2 (assoc method (if sign mml-sign-alist
+                                               mml-encrypt-alist))))))
+      (cond ((re-search-backward
+             "<#\\(multipart\\|part\\|external\\|mml\\)" nil t)
+            (goto-char (match-end 0))
+            (insert (if sign " sign=" " encrypt=") method)
+            (while tags
+              (let ((key (pop tags))
+                    (value (pop tags)))
+                (when value
+                  ;; Quote VALUE if it contains suspicious characters.
+                  (when (string-match "[\"'\\~/*;() \t\n]" value)
+                    (setq value (prin1-to-string value)))
+                  (insert (format " %s=%s" key value))))))
+           ((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"))))))
+
+(defvar mml-secure-method
+  (if (equal mml-default-encrypt-method mml-default-sign-method)
+      mml-default-sign-method
+    "pgpmime")
+  "Current security method.  Internal variable.")
+
+(defun mml-secure-sign (&optional method)
+  "Add MML tags to sign this MML part.
+Use METHOD if given.  Else use `mml-secure-method' or
+`mml-default-sign-method'."
+  (interactive)
+  (mml-secure-part
+   (or method mml-secure-method mml-default-sign-method)
+   'sign))
+
+(defun mml-secure-encrypt (&optional method)
+  "Add MML tags to encrypt this MML part.
+Use METHOD if given.  Else use `mml-secure-method' or
+`mml-default-sign-method'."
+  (interactive)
+  (mml-secure-part
+   (or method mml-secure-method mml-default-sign-method)))
+
+(defun mml-secure-sign-pgp ()
+  "Add MML tags to PGP sign this MML part."
+  (interactive)
+  (mml-secure-part "pgp" 'sign))
+
+(defun mml-secure-sign-pgpauto ()
+  "Add MML tags to PGP-auto sign this MML part."
+  (interactive)
+  (mml-secure-part "pgpauto" 'sign))
+
+(defun mml-secure-sign-pgpmime ()
+  "Add MML tags to PGP/MIME sign this MML part."
+  (interactive)
+  (mml-secure-part "pgpmime" 'sign))
+
+(defun mml-secure-sign-smime ()
+  "Add MML tags to S/MIME sign this MML part."
+  (interactive)
+  (mml-secure-part "smime" 'sign))
+
+(defun mml-secure-encrypt-pgp ()
+  "Add MML tags to PGP encrypt this MML part."
+  (interactive)
+  (mml-secure-part "pgp"))
+
+(defun mml-secure-encrypt-pgpmime ()
+  "Add MML tags to PGP/MIME encrypt this MML part."
+  (interactive)
+  (mml-secure-part "pgpmime"))
+
+(defun mml-secure-encrypt-smime ()
+  "Add MML tags to S/MIME encrypt this MML part."
+  (interactive)
+  (mml-secure-part "smime"))
+
+(defun mml-secure-is-encrypted-p ()
+  "Check whether secure encrypt tag is present."
+  (save-excursion
+    (goto-char (point-min))
+    (re-search-forward
+     (concat "^" (regexp-quote mail-header-separator) "\n"
+            "<#secure[^>]+encrypt")
+     nil t)))
+
+(defun mml-secure-bcc-is-safe ()
+  "Check whether usage of Bcc is safe (or absent).
+Bcc usage is safe in two cases: first, if the current message does
+not contain an MML secure encrypt tag;
+second, if the Bcc addresses are a subset of `mml-secure-safe-bcc-list'.
+In all other cases, ask the user whether Bcc usage is safe.
+Raise error if user answers no.
+Note that this function does not produce a meaningful return value:
+either an error is raised or not."
+  (when (mml-secure-is-encrypted-p)
+    (let ((bcc (mail-strip-quoted-names (message-fetch-field "bcc"))))
+      (when bcc
+       (let ((bcc-list (mapcar #'cadr
+                               (mail-extract-address-components bcc t))))
+         (unless (gnus-subsetp bcc-list mml-secure-safe-bcc-list)
+           (unless (yes-or-no-p "Message for encryption contains Bcc header.\
+  This may give away all Bcc'ed identities to all recipients.\
+  Are you sure that this is safe?\
+  (Customize `mml-secure-safe-bcc-list' to avoid this warning.) ")
+             (error "Aborted"))))))))
+
+;; defuns that add the proper <#secure ...> tag to the top of the message body
+(defun mml-secure-message (method &optional modesym)
+  (let ((mode (prin1-to-string modesym))
+       (tags (append
+              (if (or (eq modesym 'sign)
+                      (eq modesym 'signencrypt))
+                  (funcall (nth 2 (assoc method mml-sign-alist))))
+              (if (or (eq modesym 'encrypt)
+                      (eq modesym 'signencrypt))
+                  (funcall (nth 2 (assoc method mml-encrypt-alist))))))
+       insert-loc)
+    (mml-unsecure-message)
+    (save-excursion
+      (goto-char (point-min))
+      (cond ((re-search-forward
+             (concat "^" (regexp-quote mail-header-separator) "\n") nil t)
+            (goto-char (setq insert-loc (match-end 0)))
+            (unless (looking-at "<#secure")
+              (apply 'mml-insert-tag
+               'secure 'method method 'mode mode tags)))
+           (t (error
+               "The message is corrupted. No mail header separator"))))
+    (when (eql insert-loc (point))
+      (forward-line 1))))
+
+(defun mml-unsecure-message ()
+  "Remove security related MML tags from message."
+  (interactive)
+  (save-excursion
+    (goto-char (point-max))
+    (when (re-search-backward "^<#secure.*>\n" nil t)
+      (delete-region (match-beginning 0) (match-end 0)))))
+
+
+(defun mml-secure-message-sign (&optional method)
+  "Add MML tags to sign the entire message.
+Use METHOD if given. Else use `mml-secure-method' or
+`mml-default-sign-method'."
+  (interactive)
+  (mml-secure-message
+   (or method mml-secure-method mml-default-sign-method)
+   'sign))
+
+(defun mml-secure-message-sign-encrypt (&optional method)
+  "Add MML tag to sign and encrypt the entire message.
+Use METHOD if given. Else use `mml-secure-method' or
+`mml-default-sign-method'."
+  (interactive)
+  (mml-secure-message
+   (or method mml-secure-method mml-default-sign-method)
+   'signencrypt))
+
+(defun mml-secure-message-encrypt (&optional method)
+  "Add MML tag to encrypt the entire message.
+Use METHOD if given. Else use `mml-secure-method' or
+`mml-default-sign-method'."
+  (interactive)
+  (mml-secure-message
+   (or method mml-secure-method mml-default-sign-method)
+   'encrypt))
+
+(defun mml-secure-message-sign-smime ()
+  "Add MML tag to encrypt/sign the entire message."
+  (interactive)
+  (mml-secure-message "smime" 'sign))
+
+(defun mml-secure-message-sign-pgp ()
+  "Add MML tag to encrypt/sign the entire message."
+  (interactive)
+  (mml-secure-message "pgp" 'sign))
+
+(defun mml-secure-message-sign-pgpmime ()
+  "Add MML tag to encrypt/sign the entire message."
+  (interactive)
+  (mml-secure-message "pgpmime" 'sign))
+
+(defun mml-secure-message-sign-pgpauto ()
+  "Add MML tag to encrypt/sign the entire message."
+  (interactive)
+  (mml-secure-message "pgpauto" 'sign))
+
+(defun mml-secure-message-encrypt-smime (&optional dontsign)
+  "Add MML tag to encrypt and sign the entire message.
+If called with a prefix argument, only encrypt (do NOT sign)."
+  (interactive "P")
+  (mml-secure-message "smime" (if dontsign 'encrypt 'signencrypt)))
+
+(defun mml-secure-message-encrypt-pgp (&optional dontsign)
+  "Add MML tag to encrypt and sign the entire message.
+If called with a prefix argument, only encrypt (do NOT sign)."
+  (interactive "P")
+  (mml-secure-message "pgp" (if dontsign 'encrypt 'signencrypt)))
+
+(defun mml-secure-message-encrypt-pgpmime (&optional dontsign)
+  "Add MML tag to encrypt and sign the entire message.
+If called with a prefix argument, only encrypt (do NOT sign)."
+  (interactive "P")
+  (mml-secure-message "pgpmime" (if dontsign 'encrypt 'signencrypt)))
+
+(defun mml-secure-message-encrypt-pgpauto (&optional dontsign)
+  "Add MML tag to encrypt and sign the entire message.
+If called with a prefix argument, only encrypt (do NOT sign)."
+  (interactive "P")
+  (mml-secure-message "pgpauto" (if dontsign 'encrypt 'signencrypt)))
+
+;;; Common functionality for mml1991.el, mml2015.el, mml-smime.el
+
+(define-obsolete-variable-alias 'mml1991-signers 'mml-secure-openpgp-signers)
+(define-obsolete-variable-alias 'mml2015-signers 'mml-secure-openpgp-signers)
+(defcustom mml-secure-openpgp-signers nil
+  "A list of your own key ID(s) which will be used to sign OpenPGP messages.
+If set, it is added to the setting of `mml-secure-openpgp-sign-with-sender'."
+  :group 'mime-security
+  :type '(repeat (string :tag "Key ID")))
+
+(define-obsolete-variable-alias 'mml-smime-signers 'mml-secure-smime-signers)
+(defcustom mml-secure-smime-signers nil
+  "A list of your own key ID(s) which will be used to sign S/MIME messages.
+If set, it is added to the setting of `mml-secure-smime-sign-with-sender'."
+  :group 'mime-security
+  :type '(repeat (string :tag "Key ID")))
+
+(define-obsolete-variable-alias
+  'mml1991-encrypt-to-self 'mml-secure-openpgp-encrypt-to-self)
+(define-obsolete-variable-alias
+  'mml2015-encrypt-to-self 'mml-secure-openpgp-encrypt-to-self)
+(defcustom mml-secure-openpgp-encrypt-to-self nil
+  "List of own key ID(s) or t; determines additional recipients with OpenPGP.
+If t, also encrypt to key for message sender; if list, encrypt to those keys.
+With this variable, you can ensure that you can decrypt your own messages.
+Alternatives to this variable include Bcc'ing the message to yourself or
+using the encrypt-to or hidden-encrypt-to option in gpg.conf (see man gpg(1)).
+Note that this variable and the encrypt-to option give away your identity
+for *every* encryption without warning, which is not what you want if you are
+using, e.g., remailers.
+Also, use of Bcc gives away your identity for *every* encryption without
+warning, which is a bug, see:
+https://debbugs.gnu.org/cgi/bugreport.cgi?bug=18718"
+  :group 'mime-security
+  :type '(choice (const :tag "None" nil)
+                (const :tag "From address" t)
+                (repeat (string :tag "Key ID"))))
+
+(define-obsolete-variable-alias
+  'mml-smime-encrypt-to-self 'mml-secure-smime-encrypt-to-self)
+(defcustom mml-secure-smime-encrypt-to-self nil
+  "List of own key ID(s) or t; determines additional recipients with S/MIME.
+If t, also encrypt to key for message sender; if list, encrypt to those keys.
+With this variable, you can ensure that you can decrypt your own messages.
+Alternatives to this variable include Bcc'ing the message to yourself or
+using the encrypt-to option in gpgsm.conf (see man gpgsm(1)).
+Note that this variable and the encrypt-to option give away your identity
+for *every* encryption without warning, which is not what you want if you are
+using, e.g., remailers.
+Also, use of Bcc gives away your identity for *every* encryption without
+warning, which is a bug, see:
+https://debbugs.gnu.org/cgi/bugreport.cgi?bug=18718"
+  :group 'mime-security
+  :type '(choice (const :tag "None" nil)
+                (const :tag "From address" t)
+                (repeat (string :tag "Key ID"))))
+
+(define-obsolete-variable-alias
+  'mml2015-sign-with-sender 'mml-secure-openpgp-sign-with-sender)
+;mml1991-sign-with-sender did never exist.
+(defcustom mml-secure-openpgp-sign-with-sender nil
+  "If t, use message sender to find an OpenPGP key to sign with."
+  :group 'mime-security
+  :type 'boolean)
+
+(define-obsolete-variable-alias
+  'mml-smime-sign-with-sender 'mml-secure-smime-sign-with-sender)
+(defcustom mml-secure-smime-sign-with-sender nil
+  "If t, use message sender to find an S/MIME key to sign with."
+  :group 'mime-security
+  :type 'boolean)
+
+(define-obsolete-variable-alias
+  'mml2015-always-trust 'mml-secure-openpgp-always-trust)
+;mml1991-always-trust did never exist.
+(defcustom mml-secure-openpgp-always-trust t
+  "If t, skip key validation of GnuPG on encryption."
+  :group 'mime-security
+  :type 'boolean)
+
+(defcustom mml-secure-fail-when-key-problem nil
+  "If t, raise an error if some key is missing or several keys exist.
+Otherwise, ask the user."
+  :group 'mime-security
+  :type 'boolean)
+
+(defcustom mml-secure-key-preferences
+  '((OpenPGP (sign) (encrypt)) (CMS (sign) (encrypt)))
+  "Protocol- and usage-specific fingerprints of preferred keys.
+This variable is only relevant if a recipient owns multiple key pairs (for
+encryption) or you own multiple key pairs (for signing).  In such cases,
+you will be asked which key(s) should be used, and your choice can be
+customized in this variable."
+  :group 'mime-security
+  :type '(alist :key-type (symbol :tag "Protocol") :value-type
+               (alist :key-type (symbol :tag "Usage") :value-type
+                      (alist :key-type (string :tag "Name") :value-type
+                             (repeat (string :tag "Fingerprint"))))))
+
+(defun mml-secure-cust-usage-lookup (context usage)
+  "Return preferences for CONTEXT and USAGE."
+  (let* ((protocol (epg-context-protocol context))
+        (protocol-prefs (cdr (assoc protocol mml-secure-key-preferences))))
+    (assoc usage protocol-prefs)))
+
+(defun mml-secure-cust-fpr-lookup (context usage name)
+  "Return fingerprints of preferred keys for CONTEXT, USAGE, and NAME."
+  (let* ((usage-prefs (mml-secure-cust-usage-lookup context usage))
+        (fprs (assoc name (cdr usage-prefs))))
+    (when fprs
+      (cdr fprs))))
+
+(defun mml-secure-cust-record-keys (context usage name keys &optional save)
+  "For CONTEXT, USAGE, and NAME record fingerprint(s) of KEYS.
+If optional SAVE is not nil, save customized fingerprints.
+Return keys."
+  (assert keys)
+  (let* ((usage-prefs (mml-secure-cust-usage-lookup context usage))
+        (curr-fprs (cdr (assoc name (cdr usage-prefs))))
+        (key-fprs (mapcar 'mml-secure-fingerprint keys))
+        (new-fprs (gnus-union curr-fprs key-fprs :test 'equal)))
+    (if curr-fprs
+       (setcdr (assoc name (cdr usage-prefs)) new-fprs)
+      (setcdr usage-prefs (cons (cons name new-fprs) (cdr usage-prefs))))
+    (when save
+       (customize-save-variable
+        'mml-secure-key-preferences mml-secure-key-preferences))
+    keys))
+
+(defun mml-secure-cust-remove-keys (context usage name)
+  "Remove keys for CONTEXT, USAGE, and NAME.
+Return t if a customization for NAME was present (and has been removed)."
+  (let* ((usage-prefs (mml-secure-cust-usage-lookup context usage))
+        (current (assoc name usage-prefs)))
+    (when current
+      (setcdr usage-prefs (remove current (cdr usage-prefs)))
+      t)))
+
+(defvar mml-secure-secret-key-id-list nil)
+
+(defun mml-secure-add-secret-key-id (key-id)
+  "Record KEY-ID in list of secret keys."
+  (add-to-list 'mml-secure-secret-key-id-list key-id))
+
+(defun mml-secure-clear-secret-key-id-list ()
+  "Remove passwords from cache and clear list of secret keys."
+  ;; Loosely based on code inside mml2015-epg-encrypt,
+  ;; mml2015-epg-clear-decrypt, and mml2015-epg-decrypt
+  (dolist (key-id mml-secure-secret-key-id-list nil)
+    (password-cache-remove key-id))
+  (setq mml-secure-secret-key-id-list nil))
+
+(defvar mml1991-cache-passphrase)
+(defvar mml1991-passphrase-cache-expiry)
+
+(defun mml-secure-cache-passphrase-p (protocol)
+  "Return t if OpenPGP or S/MIME passphrases should be cached for PROTOCOL.
+Passphrase caching in Emacs is NOT recommended.  Use gpg-agent instead."
+  (or (and (eq 'OpenPGP protocol)
+          (or mml-secure-cache-passphrase
+              (and (boundp 'mml2015-cache-passphrase)
+                   mml2015-cache-passphrase)
+              (and (boundp 'mml1991-cache-passphrase)
+                   mml1991-cache-passphrase)))
+      (and (eq 'CMS protocol)
+          (or mml-secure-cache-passphrase
+              (and (boundp 'mml-smime-cache-passphrase)
+                   mml-smime-cache-passphrase)))))
+
+(defun mml-secure-cache-expiry-interval (protocol)
+  "Return time in seconds to cache passphrases for PROTOCOL.
+Passphrase caching in Emacs is NOT recommended.  Use gpg-agent instead."
+  (or (and (eq 'OpenPGP protocol)
+          (or (and (boundp 'mml2015-passphrase-cache-expiry)
+                   mml2015-passphrase-cache-expiry)
+              (and (boundp 'mml1991-passphrase-cache-expiry)
+                   mml1991-passphrase-cache-expiry)
+              mml-secure-passphrase-cache-expiry))
+      (and (eq 'CMS protocol)
+          (or (and (boundp 'mml-smime-passphrase-cache-expiry)
+                   mml-smime-passphrase-cache-expiry)
+              mml-secure-passphrase-cache-expiry))))
+
+(defun mml-secure-passphrase-callback (context key-id standard)
+  "Ask for passphrase in CONTEXT for KEY-ID for STANDARD.
+The passphrase is read and cached."
+  ;; Based on mml2015-epg-passphrase-callback.
+  (if (eq key-id 'SYM)
+      (epg-passphrase-callback-function context key-id nil)
+    (let* ((password-cache-key-id
+           (if (eq key-id 'PIN)
+               "PIN"
+              key-id))
+          (entry (assoc key-id epg-user-id-alist))
+          (passphrase
+           (password-read
+            (if (eq key-id 'PIN)
+                "Passphrase for PIN: "
+              (if entry
+                  (format "Passphrase for %s %s: " key-id (cdr entry))
+                (format "Passphrase for %s: " key-id)))
+            ;; TODO: With mml-smime.el, password-cache-key-id is not passed
+            ;; as argument to password-read.
+            ;; Is that on purpose?  If so, the following needs to be placed
+            ;; inside an if statement.
+            password-cache-key-id)))
+      (when passphrase
+       (let ((password-cache-expiry (mml-secure-cache-expiry-interval
+                                     (epg-context-protocol context))))
+         (password-cache-add password-cache-key-id passphrase))
+       (mml-secure-add-secret-key-id password-cache-key-id)
+       (copy-sequence passphrase)))))
+
+(defun mml-secure-check-user-id (key recipient)
+  "Check whether KEY has a non-revoked, non-expired UID for RECIPIENT."
+  ;; Based on mml2015-epg-check-user-id.
+  (let ((uids (epg-key-user-id-list key)))
+    (catch 'break
+      (dolist (uid uids nil)
+       (if (and (stringp (epg-user-id-string uid))
+                (equal (car (mail-header-parse-address
+                             (epg-user-id-string uid)))
+                       (car (mail-header-parse-address
+                             recipient)))
+                (not (memq (epg-user-id-validity uid)
+                           '(revoked expired))))
+           (throw 'break t))))))
+
+(defun mml-secure-secret-key-exists-p (context subkey)
+  "Return t if keyring for CONTEXT contains secret key for public SUBKEY."
+  (let* ((fpr (epg-sub-key-fingerprint subkey))
+        (candidates (epg-list-keys context fpr 'secret))
+        (candno (length candidates)))
+    ;; If two or more subkeys with the same fingerprint exist, something is
+    ;; terribly wrong.
+    (when (>= candno 2)
+      (error "Found %d secret keys with same fingerprint %s" candno fpr))
+    (= 1 candno)))
+
+(defun mml-secure-check-sub-key (context key usage &optional fingerprint)
+  "Check whether in CONTEXT the public KEY has a usable subkey for USAGE.
+This is the case if KEY is not disabled, and there is a subkey for
+USAGE that is neither revoked nor expired.  Additionally, if optional
+FINGERPRINT is present and if it is not the primary key's fingerprint, then
+the returned subkey must have that FINGERPRINT.  FINGERPRINT must consist of
+hexadecimal digits only (no leading \"0x\" allowed).
+If USAGE is not `encrypt', then additionally an appropriate secret key must
+be present in the keyring."
+  ;; Based on mml2015-epg-check-sub-key, extended by
+  ;; - check for secret keys if usage is not 'encrypt and
+  ;; - check for new argument FINGERPRINT.
+  (let* ((subkeys (epg-key-sub-key-list key))
+        (primary (car subkeys))
+        (fpr (epg-sub-key-fingerprint primary)))
+    ;; The primary key will be marked as disabled, when the entire
+    ;; key is disabled (see 12 Field, Format of colon listings, in
+    ;; gnupg/doc/DETAILS)
+    (unless (memq 'disabled (epg-sub-key-capability primary))
+      (catch 'break
+       (dolist (subkey subkeys nil)
+         (if (and (memq usage (epg-sub-key-capability subkey))
+                  (not (memq (epg-sub-key-validity subkey)
+                             '(revoked expired)))
+                  (or (eq 'encrypt usage) ; Encryption works with public key.
+                      ;; In contrast, signing requires secret key.
+                      (mml-secure-secret-key-exists-p context subkey))
+                  (or (not fingerprint)
+                      (gnus-string-match-p (concat fingerprint "$") fpr)
+                      (gnus-string-match-p (concat fingerprint "$")
+                                           (epg-sub-key-fingerprint subkey))))
+             (throw 'break t)))))))
+
+(defun mml-secure-find-usable-keys (context name usage &optional justone)
+  "In CONTEXT return a list of keys for NAME and USAGE.
+If USAGE is `encrypt' public keys are returned, otherwise secret ones.
+Only non-revoked and non-expired keys are returned whose primary key is
+not disabled.
+NAME can be an e-mail address or a key ID.
+If NAME just consists of hexadecimal digits (possibly prefixed by \"0x\"), it
+is treated as key ID for which at most one key must exist in the keyring.
+Otherwise, NAME is treated as user ID, for which no keys are returned if it
+is expired or revoked.
+If optional JUSTONE is not nil, return the first key instead of a list."
+  (let* ((keys (epg-list-keys context name))
+        (iskeyid (string-match "\\(0x\\)?\\([0-9a-fA-F]\\{8,\\}\\)" name))
+        (fingerprint (match-string 2 name))
+        result)
+    (when (and iskeyid (>= (length keys) 2))
+      (error
+       "Name %s (for %s) looks like a key ID but multiple keys found"
+       name usage))
+    (catch 'break
+      (dolist (key keys result)
+       (if (and (or iskeyid
+                    (mml-secure-check-user-id key name))
+                (mml-secure-check-sub-key context key usage fingerprint))
+           (if justone
+               (throw 'break key)
+             (push key result)))))))
+
+(defun mml-secure-select-preferred-keys (context names usage)
+  "Return list of preferred keys in CONTEXT for NAMES and USAGE.
+This inspects the keyrings to find keys for each name in NAMES.  If several
+keys are found for a name, `mml-secure-select-keys' is used to look for
+customized preferences or have the user select preferable ones.
+When `mml-secure-fail-when-key-problem' is t, fail with an error in
+case of missing, outdated, or multiple keys."
+  ;; Loosely based on code appearing inside mml2015-epg-sign and
+  ;; mml2015-epg-encrypt.
+  (apply
+   #'nconc
+   (mapcar
+    (lambda (name)
+      (let* ((keys (mml-secure-find-usable-keys context name usage))
+            (keyno (length keys)))
+       (cond ((= 0 keyno)
+              (when (or mml-secure-fail-when-key-problem
+                        (not (y-or-n-p
+                              (format "No %s key for %s; skip it? "
+                                      usage name))))
+                (error "No %s key for %s" usage name)))
+             ((= 1 keyno) keys)
+             (t (mml-secure-select-keys context name keys usage)))))
+    names)))
+
+(defun mml-secure-fingerprint (key)
+  "Return fingerprint for public KEY."
+  (epg-sub-key-fingerprint (car (epg-key-sub-key-list key))))
+
+(defun mml-secure-filter-keys (keys fprs)
+  "Filter KEYS to subset with fingerprints in FPRS."
+  (when keys
+    (if (member (mml-secure-fingerprint (car keys)) fprs)
+       (cons (car keys) (mml-secure-filter-keys (cdr keys) fprs))
+      (mml-secure-filter-keys (cdr keys) fprs))))
+
+(defun mml-secure-normalize-cust-name (name)
+  "Normalize NAME to be used for customization.
+Currently, remove ankle brackets."
+  (if (string-match "^<\\(.*\\)>$" name)
+      (match-string 1 name)
+    name))
+
+(defun mml-secure-select-keys (context name keys usage)
+  "In CONTEXT for NAME select among KEYS for USAGE.
+KEYS should be a list with multiple entries.
+NAME is normalized first as customized keys are inspected.
+When `mml-secure-fail-when-key-problem' is t, fail with an error in case of
+outdated or multiple keys."
+  (let* ((nname (mml-secure-normalize-cust-name name))
+        (fprs (mml-secure-cust-fpr-lookup context usage nname))
+        (usable-fprs (mapcar 'mml-secure-fingerprint keys)))
+    (if fprs
+       (if (gnus-subsetp fprs usable-fprs)
+           (mml-secure-filter-keys keys fprs)
+         (mml-secure-cust-remove-keys context usage nname)
+         (let ((diff (gnus-setdiff fprs usable-fprs)))
+           (if mml-secure-fail-when-key-problem
+               (error "Customization of %s keys for %s outdated" usage nname)
+             (mml-secure-select-keys-1
+              context nname keys usage (format "\
+Customized keys
+ (%s)
+for %s not available any more.
+Select anew.  "
+                                              diff nname)))))
+      (if mml-secure-fail-when-key-problem
+         (error "Multiple %s keys for %s" usage nname)
+       (mml-secure-select-keys-1
+        context nname keys usage (format "\
+Multiple %s keys for:
+ %s
+Select preferred one(s).  "
+                                        usage nname))))))
+
+(defun mml-secure-select-keys-1 (context name keys usage message)
+  "In CONTEXT for NAME let user select among KEYS for USAGE, showing MESSAGE.
+Return selected keys."
+  (let* ((selected (epa--select-keys message keys))
+        (selno (length selected))
+        ;; TODO: y-or-n-p does not always resize the echo area but may
+        ;; truncate the message.  Why?  The following does not help.
+        ;; yes-or-no-p shows full message, though.
+        (message-truncate-lines nil))
+    (if selected
+       (if (y-or-n-p
+            (format "%d %s key(s) selected.  Store for %s? "
+                    selno usage name))
+           (mml-secure-cust-record-keys context usage name selected 'save)
+         selected)
+      (unless (y-or-n-p
+              (format "No %s key for %s; skip it? " usage name))
+       (error "No %s key for %s" usage name)))))
+
+(defun mml-secure-signer-names (protocol sender)
+  "Determine signer names for PROTOCOL and message from SENDER.
+Returned names may be e-mail addresses or key IDs and are determined based
+on `mml-secure-openpgp-signers' and `mml-secure-openpgp-sign-with-sender' with
+OpenPGP or `mml-secure-smime-signers' and `mml-secure-smime-sign-with-sender'
+with S/MIME."
+  (if (eq 'OpenPGP protocol)
+      (append mml-secure-openpgp-signers
+             (if (and mml-secure-openpgp-sign-with-sender sender)
+                 (list (concat "<" sender ">"))))
+    (append mml-secure-smime-signers
+           (if (and mml-secure-smime-sign-with-sender sender)
+               (list (concat "<" sender ">"))))))
+
+(defun mml-secure-signers (context signer-names)
+  "Determine signing keys in CONTEXT from SIGNER-NAMES.
+If `mm-sign-option' is `guided', the user is asked to choose.
+Otherwise, `mml-secure-select-preferred-keys' is used."
+  ;; Based on code appearing inside mml2015-epg-sign and
+  ;; mml2015-epg-encrypt.
+  (if (eq mm-sign-option 'guided)
+      (epa-select-keys context "\
+Select keys for signing.
+If no one is selected, default secret key is used.  "
+                      signer-names t)
+    (mml-secure-select-preferred-keys context signer-names 'sign)))
+
+(defun mml-secure-self-recipients (protocol sender)
+  "Determine additional recipients based on encrypt-to-self variables.
+PROTOCOL specifies OpenPGP or S/MIME for a message from SENDER."
+  (let ((encrypt-to-self
+        (if (eq 'OpenPGP protocol)
+            mml-secure-openpgp-encrypt-to-self
+          mml-secure-smime-encrypt-to-self)))
+    (when encrypt-to-self
+      (if (listp encrypt-to-self)
+         encrypt-to-self
+       (list sender)))))
+
+(defun mml-secure-recipients (protocol context config sender)
+  "Determine encryption recipients.
+PROTOCOL specifies OpenPGP or S/MIME with matching CONTEXT and CONFIG
+for a message from SENDER."
+  ;; Based on code appearing inside mml2015-epg-encrypt.
+  (let ((recipients
+        (apply #'nconc
+               (mapcar
+                (lambda (recipient)
+                  (or (epg-expand-group config recipient)
+                      (list (concat "<" recipient ">"))))
+                (split-string
+                 (or (message-options-get 'message-recipients)
+                     (message-options-set 'message-recipients
+                                          (read-string "Recipients: ")))
+                 "[ \f\t\n\r\v,]+")))))
+    (nconc recipients (mml-secure-self-recipients protocol sender))
+    (if (eq mm-encrypt-option 'guided)
+       (setq recipients
+             (epa-select-keys context "\
+Select recipients for encryption.
+If no one is selected, symmetric encryption will be performed.  "
+                              recipients))
+      (setq recipients
+           (mml-secure-select-preferred-keys context recipients 'encrypt))
+      (unless recipients
+       (error "No recipient specified")))
+    recipients))
+
+(defun mml-secure-epg-encrypt (protocol cont &optional sign)
+  ;; Based on code appearing inside mml2015-epg-encrypt.
+  (let* ((context (epg-make-context protocol))
+        (config (epg-configuration))
+        (sender (message-options-get 'message-sender))
+        (recipients (mml-secure-recipients protocol context config sender))
+        (signer-names (mml-secure-signer-names protocol sender))
+        cipher signers)
+    (when sign
+      (setq signers (mml-secure-signers context signer-names))
+      (epg-context-set-signers context signers))
+    (when (eq 'OpenPGP protocol)
+      (epg-context-set-armor context t)
+      (epg-context-set-textmode context t))
+    (when (mml-secure-cache-passphrase-p protocol)
+      (epg-context-set-passphrase-callback
+       context
+       (cons 'mml-secure-passphrase-callback protocol)))
+    (condition-case error
+       (setq cipher
+             (if (eq 'OpenPGP protocol)
+                 (epg-encrypt-string context (buffer-string) recipients sign
+                                     mml-secure-openpgp-always-trust)
+               (epg-encrypt-string context (buffer-string) recipients))
+             mml-secure-secret-key-id-list nil)
+      (error
+       (mml-secure-clear-secret-key-id-list)
+       (signal (car error) (cdr error))))
+    cipher))
+
+(defun mml-secure-epg-sign (protocol mode)
+  ;; Based on code appearing inside mml2015-epg-sign.
+  (let* ((context (epg-make-context protocol))
+        (sender (message-options-get 'message-sender))
+        (signer-names (mml-secure-signer-names protocol sender))
+        (signers (mml-secure-signers context signer-names))
+        signature micalg)
+    (when (eq 'OpenPGP protocol)
+      (epg-context-set-armor context t)
+      (epg-context-set-textmode context t))
+    (epg-context-set-signers context signers)
+    (when (mml-secure-cache-passphrase-p protocol)
+      (epg-context-set-passphrase-callback
+       context
+       (cons 'mml-secure-passphrase-callback protocol)))
+    (condition-case error
+       (setq signature
+             (if (eq 'OpenPGP protocol)
+                 (epg-sign-string context (buffer-string) mode)
+               (epg-sign-string context
+                                (mm-replace-in-string (buffer-string)
+                                                      "\n" "\r\n") t))
+             mml-secure-secret-key-id-list nil)
+      (error
+       (mml-secure-clear-secret-key-id-list)
+       (signal (car error) (cdr error))))
+    (if (epg-context-result-for context 'sign)
+       (setq micalg (epg-new-signature-digest-algorithm
+                     (car (epg-context-result-for context 'sign)))))
+    (cons signature micalg)))
+
+(provide 'mml-sec)
+
+;;; mml-sec.el ends here
diff --git a/xemacs-packages/gnus/lisp/mml-smime.el b/xemacs-packages/gnus/lisp/mml-smime.el
new file mode 100644 (file)
index 0000000..a40595e
--- /dev/null
@@ -0,0 +1,451 @@
+;;; mml-smime.el --- S/MIME support for MML
+
+;; Copyright (C) 2000-2016 Free Software Foundation, Inc.
+
+;; Author: Simon Josefsson <simon@josefsson.org>
+;; Keywords: Gnus, MIME, S/MIME, MML
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'smime)
+(require 'mm-decode)
+(require 'mml-sec)
+(autoload 'message-narrow-to-headers "message")
+(autoload 'message-fetch-field "message")
+
+;; Prefer epg over openssl if it is available as epg uses GnuPG's gpgsm,
+;; which features full-fledged certificate management, while openssl requires
+;; major manual efforts for certificate revocation and expiry and has bugs
+;; as documented under man smime(1).
+(ignore-errors (require 'epg))
+
+(defcustom mml-smime-use (if (featurep 'epg) 'epg 'openssl)
+  "Whether to use OpenSSL or EasyPG (EPG) to handle S/MIME messages.
+Defaults to EPG if it's available.
+If you think about using OpenSSL, please read the BUGS section in the manual
+for the `smime' command coming with OpenSSL first.  EasyPG is recommended."
+  :group 'mime-security
+  :type '(choice (const :tag "EPG" epg)
+                 (const :tag "OpenSSL" openssl)))
+
+(defvar mml-smime-function-alist
+  '((openssl mml-smime-openssl-sign
+            mml-smime-openssl-encrypt
+            mml-smime-openssl-sign-query
+            mml-smime-openssl-encrypt-query
+            mml-smime-openssl-verify
+            mml-smime-openssl-verify-test)
+    (epg mml-smime-epg-sign
+        mml-smime-epg-encrypt
+        nil
+        nil
+        mml-smime-epg-verify
+        mml-smime-epg-verify-test)))
+
+(defcustom mml-smime-cache-passphrase mml-secure-cache-passphrase
+  "If t, cache passphrase."
+  :group 'mime-security
+  :type 'boolean)
+(make-obsolete-variable 'mml-smime-cache-passphrase
+                       'mml-secure-cache-passphrase
+                       "25.1")
+
+(defcustom mml-smime-passphrase-cache-expiry mml-secure-passphrase-cache-expiry
+  "How many seconds the passphrase is cached.
+Whether the passphrase is cached at all is controlled by
+`mml-smime-cache-passphrase'."
+  :group 'mime-security
+  :type 'integer)
+(make-obsolete-variable 'mml-smime-passphrase-cache-expiry
+                       'mml-secure-passphrase-cache-expiry
+                       "25.1")
+
+(defcustom mml-smime-signers nil
+  "A list of your own key ID which will be used to sign a message."
+  :group 'mime-security
+  :type '(repeat (string :tag "Key ID")))
+
+(defcustom mml-smime-sign-with-sender nil
+  "If t, use message sender so find a key to sign with."
+  :group 'mime-security
+  :version "24.4"
+  :type 'boolean)
+
+(defcustom mml-smime-encrypt-to-self nil
+  "If t, add your own key ID to recipient list when encryption."
+  :group 'mime-security
+  :version "24.4"
+  :type 'boolean)
+
+(defun mml-smime-sign (cont)
+  (let ((func (nth 1 (assq mml-smime-use mml-smime-function-alist))))
+    (if func
+       (funcall func cont)
+      (error "Cannot find sign function"))))
+
+(defun mml-smime-encrypt (cont)
+  (let ((func (nth 2 (assq mml-smime-use mml-smime-function-alist))))
+    (if func
+       (funcall func cont)
+      (error "Cannot find encrypt function"))))
+
+(defun mml-smime-sign-query ()
+  (let ((func (nth 3 (assq mml-smime-use mml-smime-function-alist))))
+    (if func
+       (funcall func))))
+
+(defun mml-smime-encrypt-query ()
+  (let ((func (nth 4 (assq mml-smime-use mml-smime-function-alist))))
+    (if func
+       (funcall func))))
+
+(defun mml-smime-verify (handle ctl)
+  (let ((func (nth 5 (assq mml-smime-use mml-smime-function-alist))))
+    (if func
+       (funcall func handle ctl)
+      handle)))
+
+(defun mml-smime-verify-test (handle ctl)
+  (let ((func (nth 6 (assq mml-smime-use mml-smime-function-alist))))
+    (if func
+       (funcall func handle ctl))))
+
+(defun mml-smime-openssl-sign (cont)
+  (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)))
+  (goto-char (point-min))
+  (while (search-forward "\r\n" nil t)
+    (replace-match "\n" t t))
+  (goto-char (point-max)))
+
+(defun mml-smime-openssl-encrypt (cont)
+  (let (certnames certfiles tmp file tmpfiles)
+    ;; xxx tmp files are always an security issue
+    (while (setq tmp (pop cont))
+      (if (and (consp tmp) (eq (car tmp) 'certfile))
+         (push (cdr tmp) certnames)))
+    (while (setq tmp (pop certnames))
+      (if (not (and (not (file-exists-p tmp))
+                   (get-buffer tmp)))
+         (push tmp certfiles)
+       (setq file (mm-make-temp-file (expand-file-name "mml."
+                                                       mm-tmp-directory)))
+       (with-current-buffer tmp
+         (write-region (point-min) (point-max) file))
+       (push file certfiles)
+       (push file tmpfiles)))
+    (if (smime-encrypt-buffer certfiles)
+       (progn
+         (while (setq tmp (pop tmpfiles))
+           (delete-file tmp))
+         t)
+      (while (setq tmp (pop tmpfiles))
+       (delete-file tmp))
+      nil))
+  (goto-char (point-max)))
+
+(defvar gnus-extract-address-components)
+
+(defun mml-smime-openssl-sign-query ()
+  ;; query information (what certificate) from user when MML tag is
+  ;; added, for use later by the signing process
+  (when (null smime-keys)
+    (customize-variable 'smime-keys)
+    (error "No S/MIME keys configured, use customize to add your key"))
+  (list 'keyfile
+       (if (= (length smime-keys) 1)
+           (cadar smime-keys)
+         (or (let ((from (cadr (funcall (if (boundp
+                                             'gnus-extract-address-components)
+                                            gnus-extract-address-components
+                                          'mail-extract-address-components)
+                                        (or (save-excursion
+                                              (save-restriction
+                                                (message-narrow-to-headers)
+                                                (message-fetch-field "from")))
+                                            "")))))
+               (and from (smime-get-key-by-email from)))
+             (smime-get-key-by-email
+              (gnus-completing-read "Sign this part with what signature"
+                                     (mapcar 'car smime-keys) nil nil nil
+                                     (and (listp (car-safe smime-keys))
+                                          (caar smime-keys))))))))
+
+(defun mml-smime-get-file-cert ()
+  (ignore-errors
+    (list 'certfile (read-file-name
+                    "File with recipient's S/MIME certificate: "
+                    smime-certificate-directory nil t ""))))
+
+(defun mml-smime-get-dns-cert ()
+  ;; todo: deal with comma separated multiple recipients
+  (let (result who bad cert)
+    (condition-case ()
+       (while (not result)
+         (setq who (read-from-minibuffer
+                    (format "%sLookup certificate for: " (or bad ""))
+                    (cadr (funcall (if (boundp
+                                        'gnus-extract-address-components)
+                                       gnus-extract-address-components
+                                     'mail-extract-address-components)
+                                   (or (save-excursion
+                                         (save-restriction
+                                           (message-narrow-to-headers)
+                                           (message-fetch-field "to")))
+                                       "")))))
+         (if (setq cert (smime-cert-by-dns who))
+             (setq result (list 'certfile (buffer-name cert)))
+           (setq bad (format "`%s' not found. " who))))
+      (quit))
+    result))
+
+(defun mml-smime-get-ldap-cert ()
+  ;; todo: deal with comma separated multiple recipients
+  (let (result who bad cert)
+    (condition-case ()
+       (while (not result)
+         (setq who (read-from-minibuffer
+                    (format "%sLookup certificate for: " (or bad ""))
+                    (cadr (funcall gnus-extract-address-components
+                                   (or (save-excursion
+                                         (save-restriction
+                                           (message-narrow-to-headers)
+                                           (message-fetch-field "to")))
+                                       "")))))
+         (if (setq cert (smime-cert-by-ldap who))
+             (setq result (list 'certfile (buffer-name cert)))
+           (setq bad (format "`%s' not found. " who))))
+      (quit))
+    result))
+
+(autoload 'gnus-completing-read "gnus-util")
+
+(defun mml-smime-openssl-encrypt-query ()
+  ;; todo: try dns/ldap automatically first, before prompting user
+  (let (certs done)
+    (while (not done)
+      (ecase (read (gnus-completing-read
+                   "Fetch certificate from"
+                   '("dns" "ldap" "file") t nil nil
+                    "ldap"))
+       (dns (setq certs (append certs
+                                (mml-smime-get-dns-cert))))
+       (ldap (setq certs (append certs
+                                 (mml-smime-get-ldap-cert))))
+       (file (setq certs (append certs
+                                 (mml-smime-get-file-cert)))))
+      (setq done (not (y-or-n-p "Add more recipients? "))))
+    certs))
+
+(defun mml-smime-openssl-verify (handle ctl)
+  (with-temp-buffer
+    (insert-buffer-substring (mm-handle-multipart-original-buffer ctl))
+    (goto-char (point-min))
+    (insert (format "Content-Type: %s; " (mm-handle-media-type ctl)))
+    (insert (format "protocol=\"%s\"; "
+                   (mm-handle-multipart-ctl-parameter ctl 'protocol)))
+    (insert (format "micalg=\"%s\"; "
+                   (mm-handle-multipart-ctl-parameter ctl 'micalg)))
+    (insert (format "boundary=\"%s\"\n\n"
+                   (mm-handle-multipart-ctl-parameter ctl 'boundary)))
+    (when (get-buffer smime-details-buffer)
+      (kill-buffer smime-details-buffer))
+    (let ((buf (current-buffer))
+         (good-signature (smime-noverify-buffer))
+         (good-certificate (and (or smime-CA-file smime-CA-directory)
+                                (smime-verify-buffer)))
+         addresses openssl-output)
+      (setq openssl-output (with-current-buffer smime-details-buffer
+                            (buffer-string)))
+      (if (not good-signature)
+         (progn
+           ;; we couldn't verify message, fail with openssl output as message
+           (mm-set-handle-multipart-parameter
+            mm-security-handle 'gnus-info "Failed")
+           (mm-set-handle-multipart-parameter
+            mm-security-handle 'gnus-details
+            (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))
+                  (smime-pkcs7-certificates-region (point-min) (point-max)))
+         (with-temp-buffer
+           (insert-buffer-substring buf)
+           (goto-char (point-min))
+           (while (re-search-forward "-----END CERTIFICATE-----" nil t)
+             (when (smime-pkcs7-email-region (point-min) (point))
+               (setq addresses (append (smime-buffer-as-string-region
+                                        (point-min) (point)) addresses)))
+             (delete-region (point-min) (point)))
+           (setq addresses (mapcar 'downcase addresses))))
+       (if (not (member (downcase (or (mm-handle-multipart-from ctl) "")) addresses))
+           (mm-set-handle-multipart-parameter
+            mm-security-handle 'gnus-info "Sender address forged")
+         (if good-certificate
+             (mm-set-handle-multipart-parameter
+              mm-security-handle 'gnus-info "Ok (sender authenticated)")
+           (mm-set-handle-multipart-parameter
+            mm-security-handle 'gnus-info "Ok (sender not trusted)")))
+       (mm-set-handle-multipart-parameter
+        mm-security-handle 'gnus-details
+        (concat "Sender claimed to be: " (mm-handle-multipart-from ctl) "\n"
+                (if addresses
+                    (concat "Addresses in certificate: "
+                            (mapconcat 'identity addresses ", "))
+                  "No addresses found in certificate. (Requires OpenSSL 0.9.6 or later.)")
+                "\n" "\n"
+                "OpenSSL output:\n"
+                "---------------\n" openssl-output "\n"
+                "Certificate(s) inside S/MIME signature:\n"
+                "---------------------------------------\n"
+                (buffer-string) "\n")))))
+  handle)
+
+(defun mml-smime-openssl-verify-test (handle ctl)
+  smime-openssl-program)
+
+(defvar epg-user-id-alist)
+(defvar epg-digest-algorithm-alist)
+(defvar inhibit-redisplay)
+(defvar password-cache-expiry)
+
+(eval-when-compile
+  (autoload 'epg-make-context "epg")
+  (autoload 'epg-context-set-armor "epg")
+  (autoload 'epg-context-set-signers "epg")
+  (autoload 'epg-context-result-for "epg")
+  (autoload 'epg-new-signature-digest-algorithm "epg")
+  (autoload 'epg-verify-result-to-string "epg")
+  (autoload 'epg-list-keys "epg")
+  (autoload 'epg-decrypt-string "epg")
+  (autoload 'epg-verify-string "epg")
+  (autoload 'epg-sign-string "epg")
+  (autoload 'epg-encrypt-string "epg")
+  (autoload 'epg-passphrase-callback-function "epg")
+  (autoload 'epg-context-set-passphrase-callback "epg")
+  (autoload 'epg-sub-key-fingerprint "epg")
+  (autoload 'epg-configuration "epg-config")
+  (autoload 'epg-expand-group "epg-config")
+  (autoload 'epa-select-keys "epa"))
+
+(declare-function epg-key-sub-key-list   "ext:epg" (key))
+(declare-function epg-sub-key-capability "ext:epg" (sub-key))
+(declare-function epg-sub-key-validity   "ext:epg" (sub-key))
+
+(autoload 'mml-compute-boundary "mml")
+
+;; We require mm-decode, which requires mm-bodies, which autoloads
+;; message-options-get (!).
+(declare-function message-options-set "message" (symbol value))
+
+(defun mml-smime-epg-sign (cont)
+  (let ((inhibit-redisplay t)
+       (boundary (mml-compute-boundary cont)))
+    (goto-char (point-min))
+    (let* ((pair (mml-secure-epg-sign 'CMS cont))
+          (signature (car pair))
+          (micalg (cdr pair)))
+      (insert (format "Content-Type: multipart/signed; boundary=\"%s\";\n"
+                     boundary))
+      (if micalg
+         (insert (format "\tmicalg=%s; "
+                         (downcase
+                          (cdr (assq micalg
+                                     epg-digest-algorithm-alist))))))
+      (insert "protocol=\"application/pkcs7-signature\"\n")
+      (insert (format "\n--%s\n" boundary))
+      (goto-char (point-max))
+      (insert (format "\n--%s\n" boundary))
+      (insert "Content-Type: application/pkcs7-signature; name=smime.p7s
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment; filename=smime.p7s
+
+")
+      (insert (base64-encode-string signature) "\n")
+      (goto-char (point-max))
+      (insert (format "--%s--\n" boundary))
+      (goto-char (point-max)))))
+
+(defun mml-smime-epg-encrypt (cont)
+  (let* ((inhibit-redisplay t)
+        (boundary (mml-compute-boundary cont))
+        (cipher (mml-secure-epg-encrypt 'CMS cont)))
+    (delete-region (point-min) (point-max))
+    (goto-char (point-min))
+    (insert "\
+Content-Type: application/pkcs7-mime;
+ smime-type=enveloped-data;
+ name=smime.p7m
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment; filename=smime.p7m
+
+")
+    (insert (base64-encode-string cipher))
+    (goto-char (point-max))))
+
+(defun mml-smime-epg-verify (handle ctl)
+  (catch 'error
+    (let ((inhibit-redisplay t)
+         context plain signature-file part signature)
+      (when (or (null (setq part (mm-find-raw-part-by-type
+                                 ctl (or (mm-handle-multipart-ctl-parameter
+                                          ctl 'protocol)
+                                         "application/pkcs7-signature")
+                                 t)))
+               (null (setq signature (or (mm-find-part-by-type
+                                          (cdr handle)
+                                          "application/pkcs7-signature"
+                                          nil t)
+                                         (mm-find-part-by-type
+                                          (cdr handle)
+                                          "application/x-pkcs7-signature"
+                                          nil t)))))
+       (mm-set-handle-multipart-parameter
+        mm-security-handle 'gnus-info "Corrupted")
+       (throw 'error handle))
+      (setq part (mm-replace-in-string part "\n" "\r\n")
+           context (epg-make-context 'CMS))
+      (condition-case error
+         (setq plain (epg-verify-string context (mm-get-part signature) part))
+       (error
+        (mm-set-handle-multipart-parameter
+         mm-security-handle 'gnus-info "Failed")
+        (if (eq (car error) 'quit)
+            (mm-set-handle-multipart-parameter
+             mm-security-handle 'gnus-details "Quit.")
+          (mm-set-handle-multipart-parameter
+           mm-security-handle 'gnus-details (format "%S" error)))
+        (throw 'error handle)))
+      (mm-set-handle-multipart-parameter
+       mm-security-handle 'gnus-info
+       (epg-verify-result-to-string (epg-context-result-for context 'verify)))
+      handle)))
+
+(defun mml-smime-epg-verify-test (handle ctl)
+  t)
+
+(provide 'mml-smime)
+
+;;; mml-smime.el ends here
diff --git a/xemacs-packages/gnus/lisp/mml.el b/xemacs-packages/gnus/lisp/mml.el
new file mode 100644 (file)
index 0000000..c767ceb
--- /dev/null
@@ -0,0 +1,1663 @@
+;;; mml.el --- A package for parsing and validating MML documents
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'mm-util)
+(require 'mm-bodies)
+(require 'mm-encode)
+(require 'mm-decode)
+(require 'mml-sec)
+(eval-when-compile (require 'cl))
+(eval-when-compile (require 'url))
+(eval-when-compile
+  (when (featurep 'xemacs)
+    (require 'easy-mmode))) ; for `define-minor-mode'
+
+(autoload 'message-make-message-id "message")
+(declare-function gnus-setup-posting-charset "gnus-msg" (group))
+(autoload 'gnus-make-local-hook "gnus-util")
+(autoload 'gnus-completing-read "gnus-util")
+(autoload 'message-fetch-field "message")
+(autoload 'message-mark-active-p "message")
+(autoload 'message-info "message")
+(autoload 'fill-flowed-encode "flow-fill")
+(autoload 'message-posting-charset "message")
+(autoload 'dnd-get-local-file-name "dnd")
+
+(autoload 'message-options-set    "message")
+(autoload 'message-narrow-to-head "message")
+(autoload 'message-in-body-p      "message")
+(autoload 'message-mail-p         "message")
+
+(defvar gnus-article-mime-handles)
+(defvar gnus-mouse-2)
+(defvar gnus-newsrc-hashtb)
+(defvar message-default-charset)
+(defvar message-deletable-headers)
+(defvar message-options)
+(defvar message-posting-charset)
+(defvar message-required-mail-headers)
+(defvar message-required-news-headers)
+(defvar dnd-protocol-alist)
+(defvar mml-dnd-protocol-alist)
+
+(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."
+  :version "22.1"
+  :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."
+  :version "22.1"
+  :type '(repeat (symbol :tag "Parameter"))
+  :group 'message)
+
+(defcustom mml-content-disposition-alist
+  '((text (rtf . "attachment") (t . "inline"))
+    (t . "attachment"))
+  "Alist of MIME types or regexps matching file names and default dispositions.
+Each element should be one of the following three forms:
+
+  (REGEXP . DISPOSITION)
+  (SUPERTYPE (SUBTYPE . DISPOSITION) (SUBTYPE . DISPOSITION)...)
+  (TYPE . DISPOSITION)
+
+Where REGEXP is a string which matches the file name (if any) of an
+attachment, SUPERTYPE, SUBTYPE and TYPE should be symbols which are a
+MIME supertype (e.g., text), a MIME subtype (e.g., plain) and a MIME
+type (e.g., text/plain) respectively, and DISPOSITION should be either
+the string \"attachment\" or the string \"inline\".  The value t for
+SUPERTYPE, SUBTYPE or TYPE matches any of those types.  The first
+match found will be used."
+  :version "23.1" ;; No Gnus
+  :type (let ((dispositions '(radio :format "DISPOSITION: %v"
+                                   :value "attachment"
+                                   (const :format "%v " "attachment")
+                                   (const :format "%v\n" "inline"))))
+         `(repeat
+           :offset 0
+           (choice :format "%[Value Menu%]%v"
+                   (cons :tag "(REGEXP . DISPOSITION)" :extra-offset 4
+                         (regexp :tag "REGEXP" :value ".*")
+                         ,dispositions)
+                   (cons :tag "(SUPERTYPE (SUBTYPE . DISPOSITION)...)"
+                         :indent 0
+                         (symbol :tag "    SUPERTYPE" :value text)
+                         (repeat :format "%v%i\n" :offset 0 :extra-offset 4
+                                 (cons :format "%v" :extra-offset 5
+                                       (symbol :tag "SUBTYPE" :value t)
+                                       ,dispositions)))
+                   (cons :tag "(TYPE . DISPOSITION)" :extra-offset 4
+                         (symbol :tag "TYPE" :value t)
+                         ,dispositions))))
+  :group 'message)
+
+(defcustom mml-insert-mime-headers-always t
+  "If non-nil, always put Content-Type: text/plain at top of empty parts.
+It is necessary to work against a bug in certain clients."
+  :version "24.1"
+  :type 'boolean
+  :group 'message)
+
+(defcustom mml-enable-flowed t
+  "If non-nil, enable format=flowed usage when encoding a message.
+This is only performed when filling on text/plain with hard
+newlines in the text."
+  :version "24.1"
+  :type 'boolean
+  :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-tweak-sexp-alist
+  '((mml-externalize-attachments . mml-tweak-externalize-attachments))
+  "A list of (SEXP . FUNCTION) for tweaking MML parts.
+SEXP is an s-expression.  If the evaluation of SEXP is non-nil, FUNCTION
+is called.  FUNCTION is a Lisp function which is called with the MML
+handle to tweak the part.")
+
+(defvar mml-externalize-attachments nil
+  "*If non-nil, local-file attachments are generated as external parts.")
+
+(defvar mml-generate-multipart-alist nil
+  "*Alist of multipart generation functions.
+Each entry has the form (NAME . FUNCTION), where
+NAME is a string containing the name of the part (without the
+leading \"/multipart/\"),
+FUNCTION is a Lisp function which is called to generate the part.
+
+The Lisp function has to supply the appropriate MIME headers and the
+contents of this part.")
+
+(defvar mml-syntax-table
+  (let ((table (copy-syntax-table emacs-lisp-mode-syntax-table)))
+    (modify-syntax-entry ?\\ "/" table)
+    (modify-syntax-entry ?< "(" table)
+    (modify-syntax-entry ?> ")" table)
+    (modify-syntax-entry ?@ "w" table)
+    (modify-syntax-entry ?/ "w" table)
+    (modify-syntax-entry ?= " " table)
+    (modify-syntax-entry ?* " " table)
+    (modify-syntax-entry ?\; " " table)
+    (modify-syntax-entry ?\' " " table)
+    table))
+
+(defvar mml-boundary-function 'mml-make-boundary
+  "A function called to suggest a boundary.
+The function may be called several times, and should try to make a new
+suggestion each time.  The function is called with one parameter,
+which is a number that says how many times the function has been
+called for this message.")
+
+(defvar mml-confirmation-set nil
+  "A list of symbols, each of which disables some warning.
+`unknown-encoding': always send messages contain characters with
+unknown encoding; `use-ascii': always use ASCII for those characters
+with unknown encoding; `multipart': always send messages with more than
+one charsets.")
+
+(defvar mml-generate-default-type "text/plain"
+  "Content type by which the Content-Type header can be omitted.
+The Content-Type header will not be put in the MIME part if the type
+equals the value and there's no parameter (e.g. charset, format, etc.)
+and `mml-insert-mime-headers-always' is nil.  The value will be bound
+to \"message/rfc822\" when encoding an article to be forwarded as a MIME
+part.  This is for the internal use, you should never modify the value.")
+
+(defvar mml-buffer-list nil)
+
+(defun mml-generate-new-buffer (name)
+  (let ((buf (generate-new-buffer name)))
+    (push buf mml-buffer-list)
+    buf))
+
+(defun mml-destroy-buffers ()
+  (let (kill-buffer-hook)
+    (mapc 'kill-buffer mml-buffer-list)
+    (setq mml-buffer-list nil)))
+
+(defun mml-parse ()
+  "Parse the current buffer as an MML document."
+  (save-excursion
+    (goto-char (point-min))
+    (with-syntax-table mml-syntax-table
+      (mml-parse-1))))
+
+(defun mml-parse-1 ()
+  "Parse the current buffer as an MML document."
+  (let (struct tag point contents charsets warn use-ascii no-markup-p raw)
+    (while (and (not (eobp))
+               (not (looking-at "<#/multipart")))
+      (cond
+       ((looking-at "<#secure")
+       ;; The secure part is essentially a meta-meta tag, which
+       ;; expands to either a part tag if there are no other parts in
+       ;; the document or a multipart tag if there are other parts
+       ;; included in the message
+       (let* (secure-mode
+              (taginfo (mml-read-tag))
+              (keyfile (cdr (assq 'keyfile taginfo)))
+              (certfiles (delq nil (mapcar (lambda (tag)
+                                             (if (eq (car-safe tag) 'certfile)
+                                                 (cdr tag)))
+                                           taginfo)))
+              (recipients (cdr (assq 'recipients taginfo)))
+              (sender (cdr (assq 'sender taginfo)))
+              (location (cdr (assq 'tag-location taginfo)))
+              (mode (cdr (assq 'mode taginfo)))
+              (method (cdr (assq 'method taginfo)))
+              tags)
+         (save-excursion
+           (if (re-search-forward
+                "<#/?\\(multipart\\|part\\|external\\|mml\\)." nil t)
+               (setq secure-mode "multipart")
+             (setq secure-mode "part")))
+         (save-excursion
+           (goto-char location)
+           (re-search-forward "<#secure[^\n]*>\n"))
+         (delete-region (match-beginning 0) (match-end 0))
+         (cond ((string= mode "sign")
+                (setq tags (list "sign" method)))
+               ((string= mode "encrypt")
+                (setq tags (list "encrypt" method)))
+               ((string= mode "signencrypt")
+                (setq tags (list "sign" method "encrypt" method)))
+               (t
+                (error "Unknown secure mode %s" mode)))
+         (eval `(mml-insert-tag ,secure-mode
+                                ,@tags
+                                ,(if keyfile "keyfile")
+                                ,keyfile
+                                ,@(apply #'append
+                                         (mapcar (lambda (certfile)
+                                                   (list "certfile" certfile))
+                                                 certfiles))
+                                ,(if recipients "recipients")
+                                ,recipients
+                                ,(if sender "sender")
+                                ,sender))
+         ;; restart the parse
+         (goto-char location)))
+       ((looking-at "<#multipart")
+       (push (nconc (mml-read-tag) (mml-parse-1)) struct))
+       ((looking-at "<#external")
+       (push (nconc (mml-read-tag) (list (cons 'contents (mml-read-part))))
+             struct))
+       (t
+       (if (or (looking-at "<#part") (looking-at "<#mml"))
+           (setq tag (mml-read-tag)
+                 no-markup-p nil
+                 warn nil)
+         (setq tag (list 'part '(type . "text/plain"))
+               no-markup-p t
+               warn t))
+       (setq raw (cdr (assq 'raw tag))
+             point (point)
+             contents (mml-read-part (eq 'mml (car tag)))
+             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)
+                 (message-options-get 'unknown-encoding)
+                 (and (y-or-n-p "\
+Message contains characters with unknown encoding.  Really send? ")
+                      (message-options-set 'unknown-encoding t)))
+             (if (setq use-ascii
+                       (or (memq 'use-ascii mml-confirmation-set)
+                           (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")))
+       (if (or raw
+               (eq 'mml (car tag))
+               (< (length charsets) 2))
+           (if (or (not no-markup-p)
+                   (string-match "[^ \t\r\n]" contents))
+               ;; Don't create blank parts.
+               (push (nconc tag (list (cons 'contents contents)))
+                     struct))
+         (let ((nstruct (mml-parse-singlepart-with-multiple-charsets
+                         tag point (point) use-ascii)))
+           (when (and warn
+                      (not (memq 'multipart mml-confirmation-set))
+                      (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)))
+                                (message-options-set 'multipart t))))
+             (error "Edit your message to use only one charset"))
+           (setq struct (nconc nstruct struct)))))))
+    (unless (eobp)
+      (forward-line 1))
+    (nreverse struct)))
+
+(defun mml-parse-singlepart-with-multiple-charsets
+  (orig-tag beg end &optional use-ascii)
+  (save-excursion
+    (save-restriction
+      (narrow-to-region beg end)
+      (goto-char (point-min))
+      (let ((current (or (mm-mime-charset (mm-charset-after))
+                        (and use-ascii 'us-ascii)))
+           charset struct space newline paragraph)
+       (while (not (eobp))
+         (setq charset (mm-mime-charset (mm-charset-after)))
+         (cond
+          ;; The charset remains the same.
+          ((eq charset 'us-ascii))
+          ((or (and use-ascii (not charset))
+               (eq charset current))
+           (setq space nil
+                 newline nil
+                 paragraph nil))
+          ;; The initial charset was ascii.
+          ((eq current 'us-ascii)
+           (setq current charset
+                 space nil
+                 newline nil
+                 paragraph nil))
+          ;; We have a change in charsets.
+          (t
+           (push (append
+                  orig-tag
+                  (list (cons 'contents
+                              (buffer-substring-no-properties
+                               beg (or paragraph newline space (point))))))
+                 struct)
+           (setq beg (or paragraph newline space (point))
+                 current charset
+                 space nil
+                 newline nil
+                 paragraph nil)))
+         ;; Compute places where it might be nice to break the part.
+         (cond
+          ((memq (following-char) '(?  ?\t))
+           (setq space (1+ (point))))
+          ((and (eq (following-char) ?\n)
+                (not (bobp))
+                (eq (char-after (1- (point))) ?\n))
+           (setq paragraph (point)))
+          ((eq (following-char) ?\n)
+           (setq newline (1+ (point)))))
+         (forward-char 1))
+       ;; Do the final part.
+       (unless (= beg (point))
+         (push (append orig-tag
+                       (list (cons 'contents
+                                   (buffer-substring-no-properties
+                                    beg (point)))))
+               struct))
+       struct))))
+
+(defun mml-read-tag ()
+  "Read a tag and return the contents."
+  (let ((orig-point (point))
+       contents name elem val)
+    (forward-char 2)
+    (setq name (buffer-substring-no-properties
+               (point) (progn (forward-sexp 1) (point))))
+    (skip-chars-forward " \t\n")
+    (while (not (looking-at ">[ \t]*\n?"))
+      (setq elem (buffer-substring-no-properties
+                 (point) (progn (forward-sexp 1) (point))))
+      (skip-chars-forward "= \t\n")
+      (setq val (buffer-substring-no-properties
+                (point) (progn (forward-sexp 1) (point))))
+      (when (string-match "\\`\"" val)
+       (setq val (read val))) ;; inverse of prin1 in mml-insert-tag
+      (push (cons (intern elem) val) contents)
+      (skip-chars-forward " \t\n"))
+    (goto-char (match-end 0))
+    ;; Don't skip the leading space.
+    ;;(skip-chars-forward " \t\n")
+    ;; Put the tag location into the returned contents
+    (setq contents (append (list (cons 'tag-location orig-point)) contents))
+    (cons (intern name) (nreverse contents))))
+
+(defun mml-buffer-substring-no-properties-except-hard-newlines (start end)
+  (let ((str (buffer-substring-no-properties start end))
+       (bufstart start) tmp)
+    (while (setq tmp (text-property-any start end 'hard 't))
+      (set-text-properties (- tmp bufstart) (- tmp bufstart -1)
+                          '(hard t) str)
+      (setq start (1+ tmp)))
+    str))
+
+(defun mml-read-part (&optional mml)
+  "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.
+    (when (looking-at "[ \t]*\n")
+      (forward-line 1))
+    (if mml
+       (progn
+         (while (and (> count 0) (not (eobp)))
+           (if (re-search-forward "<#\\(/\\)?mml." nil t)
+               (setq count (+ count (if (match-beginning 1) -1 1)))
+             (goto-char (point-max))))
+         (mml-buffer-substring-no-properties-except-hard-newlines
+          beg (if (> count 0)
+                  (point)
+                (match-beginning 0))))
+      (if (re-search-forward
+          "<#\\(/\\)?\\(multipart\\|part\\|external\\|mml\\)." nil t)
+         (prog1
+             (mml-buffer-substring-no-properties-except-hard-newlines
+              beg (match-beginning 0))
+           (if (or (not (match-beginning 1))
+                   (equal (match-string 2) "multipart"))
+               (goto-char (match-beginning 0))
+             (when (looking-at "[ \t]*\n")
+               (forward-line 1))))
+       (mml-buffer-substring-no-properties-except-hard-newlines
+        beg (goto-char (point-max)))))))
+
+(defvar mml-boundary nil)
+(defvar mml-base-boundary "-=-=")
+(defvar mml-multipart-number 0)
+(defvar mml-inhibit-compute-boundary nil)
+
+(declare-function libxml-parse-html-region "xml.c"
+                 (start end &optional base-url discard-comments))
+
+(defun mml-generate-mime (&optional multipart-type)
+  "Generate a MIME message based on the current MML document.
+MULTIPART-TYPE defaults to \"mixed\", but can also
+be \"related\" or \"alternate\"."
+  (let ((cont (mml-parse))
+       (mml-multipart-number mml-multipart-number)
+       (options message-options))
+    (if (not cont)
+       nil
+      (when (and (consp (car cont))
+                (= (length cont) 1)
+                (fboundp 'libxml-parse-html-region)
+                (equal (cdr (assq 'type (car cont))) "text/html"))
+       (setq cont (mml-expand-html-into-multipart-related (car cont))))
+      (prog1
+         (mm-with-multibyte-buffer
+           (setq message-options options)
+           (cond
+            ((and (consp (car cont))
+                  (= (length cont) 1))
+             (mml-generate-mime-1 (car cont)))
+            ((eq (car cont) 'multipart)
+             (mml-generate-mime-1 cont))
+            (t
+             (mml-generate-mime-1
+              (nconc (list 'multipart (cons 'type (or multipart-type "mixed")))
+                     cont))))
+           (setq options message-options)
+           (buffer-string))
+       (setq message-options options)))))
+
+(defun mml-expand-html-into-multipart-related (cont)
+  (let ((new-parts nil)
+       (cid 1))
+    (mm-with-multibyte-buffer
+      (insert (cdr (assq 'contents cont)))
+      (goto-char (point-min))
+      (with-syntax-table mml-syntax-table
+       (while (re-search-forward "<img\\b" nil t)
+         (goto-char (match-beginning 0))
+         (let* ((start (point))
+                (img (nth 2
+                          (nth 2
+                               (libxml-parse-html-region
+                                (point) (progn (forward-sexp) (point))))))
+                (end (point))
+                (parsed (url-generic-parse-url (cdr (assq 'src (cadr img))))))
+           (when (and (null (url-type parsed))
+                      (url-filename parsed)
+                      (file-exists-p (url-filename parsed)))
+             (goto-char start)
+             (when (search-forward (url-filename parsed) end t)
+               (let ((cid (format "fsf.%d" cid)))
+                 (replace-match (concat "cid:" cid) t t)
+                 (push (list cid (url-filename parsed)) new-parts))
+               (setq cid (1+ cid)))))))
+      ;; We have local images that we want to include.
+      (if (not new-parts)
+         (list cont)
+       (setcdr (assq 'contents cont) (buffer-string))
+       (setq cont
+             (nconc (list 'multipart (cons 'type "related"))
+                    (list cont)))
+       (dolist (new-part (nreverse new-parts))
+         (setq cont
+               (nconc cont
+                      (list `(part (type . "image/png")
+                                   (filename . ,(nth 1 new-part))
+                                   (id . ,(concat "<" (nth 0 new-part)
+                                                  ">")))))))
+       cont))))
+
+(defun mml-generate-mime-1 (cont)
+  (let ((mm-use-ultra-safe-encoding
+        (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)))
+              (filename (cdr (assq 'filename cont)))
+              (type (or (cdr (assq 'type cont))
+                        (if filename
+                            (or (mm-default-file-encoding filename)
+                                "application/octet-stream")
+                          "text/plain")))
+              (charset (cdr (assq 'charset cont)))
+              (coding (mm-charset-to-coding-system charset))
+              encoding flowed coded)
+         (cond ((eq coding 'ascii)
+                (setq charset nil
+                      coding nil))
+               (charset
+                ;; The value of `charset' might be a bogus alias that
+                ;; `mm-charset-synonym-alist' provides, like `utf8',
+                ;; so we prefer the MIME charset that Emacs knows for
+                ;; the coding system `coding'.
+                (setq charset (or (mm-coding-system-to-mime-charset coding)
+                                  (intern (downcase charset))))))
+         (if (and (not raw)
+                  (member (car (split-string type "/")) '("text" "message")))
+             (progn
+               (with-temp-buffer
+                 (cond
+                  ((cdr (assq 'buffer cont))
+                   (insert-buffer-substring (cdr (assq 'buffer cont))))
+                  ((and filename
+                        (not (equal (cdr (assq 'nofile cont)) "yes")))
+                   (let ((coding-system-for-read coding))
+                     (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\\|secure\\)"
+                             nil t)
+                       (delete-region (+ (match-beginning 0) 2)
+                                      (+ (match-beginning 0) 3))))))
+                 (cond
+                  ((eq (car cont) 'mml)
+                   (let ((mml-boundary (mml-compute-boundary cont))
+                         ;; It is necessary for the case where this
+                         ;; function is called recursively since
+                         ;; `m-g-d-t' will be bound to "message/rfc822"
+                         ;; when encoding an article to be forwarded.
+                         (mml-generate-default-type "text/plain"))
+                     (mml-to-mime)
+                     ;; Update handle so mml-compute-boundary can
+                     ;; detect collisions with the nested parts.
+                     (unless mml-inhibit-compute-boundary
+                       (setcdr (assoc 'contents cont) (buffer-string))))
+                   (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
+                   ;; Only perform format=flowed filling on text/plain
+                   ;; parts where there either isn't a format parameter
+                   ;; in the mml tag or it says "flowed" and there
+                   ;; actually are hard newlines in the text.
+                   (let (use-hard-newlines)
+                     (when (and mml-enable-flowed
+                                 (string= type "text/plain")
+                                (not (string= (cdr (assq 'sign cont)) "pgp"))
+                                (or (null (assq 'format cont))
+                                    (string= (cdr (assq 'format cont))
+                                             "flowed"))
+                                (setq use-hard-newlines
+                                      (text-property-any
+                                       (point-min) (point-max) 'hard 't)))
+                       (fill-flowed-encode)
+                       ;; Indicate that `mml-insert-mime-headers' should
+                       ;; insert a "; format=flowed" string unless the
+                       ;; user has already specified it.
+                       (setq flowed (null (assq 'format cont)))))
+                   ;; Prefer `utf-8' for text/calendar parts.
+                   (if (or charset
+                           (not (string= type "text/calendar")))
+                       (setq charset (mm-encode-body charset))
+                     (let ((mm-coding-system-priorities
+                            (cons 'utf-8 mm-coding-system-priorities)))
+                       (setq charset (mm-encode-body))))
+                   (setq encoding (mm-body-encoding
+                                   charset (cdr (assq 'encoding cont))))))
+                 (setq coded (buffer-string)))
+               (mml-insert-mime-headers cont type charset encoding flowed)
+               (insert "\n")
+               (insert coded))
+           (mm-with-unibyte-buffer
+             (cond
+              ((cdr (assq 'buffer cont))
+               (insert (mm-string-as-unibyte
+                        (with-current-buffer (cdr (assq 'buffer cont))
+                          (buffer-string)))))
+              ((and filename
+                    (not (equal (cdr (assq 'nofile cont)) "yes")))
+               (let ((coding-system-for-read mm-binary-coding-system))
+                 (mm-insert-file-contents filename nil nil nil nil t))
+               (unless charset
+                 (setq charset (mm-coding-system-to-mime-charset
+                                (mm-find-buffer-file-coding-system
+                                 filename)))))
+              (t
+               (let ((contents (cdr (assq 'contents cont))))
+                 (if (if (featurep 'xemacs)
+                         (string-match "[^\000-\377]" contents)
+                       (mm-multibyte-string-p contents))
+                     (progn
+                       (mm-enable-multibyte)
+                       (insert contents)
+                       (unless raw
+                         (setq charset (mm-encode-body charset))))
+                   (insert contents)))))
+             (if (setq encoding (cdr (assq 'encoding cont)))
+                 (setq encoding (intern (downcase encoding))))
+             (setq encoding (mm-encode-buffer type encoding)
+                   coded (mm-string-as-multibyte (buffer-string))))
+           (mml-insert-mime-headers cont type charset encoding nil)
+           (insert "\n" coded))))
+       ((eq (car cont) 'external)
+       (insert "Content-Type: message/external-body")
+       (let ((parameters (mml-parameter-string
+                          cont '(expiration size permission)))
+             (name (cdr (assq 'name cont)))
+             (url (cdr (assq 'url cont))))
+         (when name
+           (setq name (mml-parse-file-name name))
+           (if (stringp name)
+               (mml-insert-parameter
+                (mail-header-encode-parameter "name" name)
+                "access-type=local-file")
+             (mml-insert-parameter
+              (mail-header-encode-parameter
+               "name" (file-name-nondirectory (nth 2 name)))
+              (mail-header-encode-parameter "site" (nth 1 name))
+              (mail-header-encode-parameter
+               "directory" (file-name-directory (nth 2 name))))
+             (mml-insert-parameter
+              (concat "access-type="
+                      (if (member (nth 0 name) '("ftp@" "anonymous@"))
+                          "anon-ftp"
+                        "ftp")))))
+         (when url
+           (mml-insert-parameter
+            (mail-header-encode-parameter "url" url)
+            "access-type=url"))
+         (when parameters
+           (mml-insert-parameter-string
+            cont '(expiration size permission)))
+         (insert "\n\n")
+         (insert "Content-Type: "
+                 (or (cdr (assq 'type cont))
+                     (if name
+                         (or (mm-default-file-encoding name)
+                             "application/octet-stream")
+                       "text/plain"))
+                 "\n")
+         (insert "Content-ID: " (message-make-message-id) "\n")
+         (insert "Content-Transfer-Encoding: "
+                 (or (cdr (assq 'encoding cont)) "binary"))
+         (insert "\n\n")
+         (insert (or (cdr (assq 'contents cont))))
+         (insert "\n")))
+       ((eq (car cont) 'multipart)
+       (let* ((type (or (cdr (assq 'type cont)) "mixed"))
+              (mml-generate-default-type (if (equal type "digest")
+                                             "message/rfc822"
+                                           "text/plain"))
+              (handler (assoc type mml-generate-multipart-alist)))
+         (if handler
+             (funcall (cdr handler) cont)
+           ;; No specific handler.  Use default one.
+           (let ((mml-boundary (mml-compute-boundary cont)))
+             (insert (format "Content-Type: multipart/%s; boundary=\"%s\""
+                             type mml-boundary)
+                     (if (cdr (assq 'start cont))
+                         (format "; start=\"%s\"\n" (cdr (assq 'start cont)))
+                       "\n"))
+             (let ((cont cont) part)
+               (while (setq part (pop cont))
+                 ;; Skip `multipart' and attributes.
+                 (when (and (consp part) (consp (cdr part)))
+                   (insert "\n--" mml-boundary "\n")
+                   (mml-generate-mime-1 part)
+                   (goto-char (point-max)))))
+             (insert "\n--" mml-boundary "--\n")))))
+       (t
+       (error "Invalid element: %S" cont)))
+      ;; handle sign & encrypt tags in a semi-smart way.
+      (let ((sign-item (assoc (cdr (assq 'sign cont)) mml-sign-alist))
+           (encrypt-item (assoc (cdr (assq 'encrypt cont))
+                                mml-encrypt-alist))
+           sender recipients)
+       (when (or sign-item encrypt-item)
+         (when (setq sender (cdr (assq 'sender cont)))
+           (message-options-set 'mml-sender sender)
+           (message-options-set 'message-sender sender))
+         (if (setq recipients (cdr (assq 'recipients cont)))
+             (message-options-set 'message-recipients recipients))
+         (let ((style (mml-signencrypt-style
+                       (first (or sign-item encrypt-item)))))
+           ;; check if: we're both signing & encrypting, both methods
+           ;; are the same (why would they be different?!), and that
+           ;; the signencrypt style allows for combined operation.
+           (if (and sign-item encrypt-item (equal (first sign-item)
+                                                  (first encrypt-item))
+                    (equal style 'combined))
+               (funcall (nth 1 encrypt-item) cont t)
+             ;; otherwise, revert to the old behavior.
+             (when sign-item
+               (funcall (nth 1 sign-item) cont))
+             (when encrypt-item
+               (funcall (nth 1 encrypt-item) cont)))))))))
+
+(defun mml-compute-boundary (cont)
+  "Return a unique boundary that does not exist in CONT."
+  (let ((mml-boundary (funcall mml-boundary-function
+                              (incf mml-multipart-number))))
+    (unless mml-inhibit-compute-boundary
+      ;; This function tries again and again until it has found
+      ;; a unique boundary.
+      (while (not (catch 'not-unique
+                   (mml-compute-boundary-1 cont)))))
+    mml-boundary))
+
+(defun mml-compute-boundary-1 (cont)
+  (cond
+   ((member (car cont) '(part mml))
+    (mm-with-multibyte-buffer
+      (let ((mml-inhibit-compute-boundary t)
+           (mml-multipart-number 0)
+           mml-sign-alist mml-encrypt-alist)
+       (mml-generate-mime-1 cont))
+      (goto-char (point-min))
+      (when (re-search-forward (concat "^--" (regexp-quote mml-boundary))
+                              nil t)
+       (setq mml-boundary (funcall mml-boundary-function
+                                   (incf mml-multipart-number)))
+       (throw 'not-unique nil))))
+   ((eq (car cont) 'multipart)
+    (mapc 'mml-compute-boundary-1 (cddr cont))))
+  t)
+
+(defun mml-make-boundary (number)
+  (concat (make-string (% number 60) ?=)
+         (if (> number 17)
+             (format "%x" number)
+           "")
+         mml-base-boundary))
+
+(defun mml-content-disposition (type &optional filename)
+  "Return a default disposition name suitable to TYPE or FILENAME."
+  (let ((defs mml-content-disposition-alist)
+       disposition def types)
+    (while (and (not disposition) defs)
+      (setq def (pop defs))
+      (cond ((stringp (car def))
+            (when (and filename
+                       (string-match (car def) filename))
+              (setq disposition (cdr def))))
+           ((consp (cdr def))
+            (when (string= (car (setq types (split-string type "/")))
+                           (car def))
+              (setq type (cadr types)
+                    types (cdr def))
+              (while (and (not disposition) types)
+                (setq def (pop types))
+                (when (or (eq (car def) t) (string= type (car def)))
+                  (setq disposition (cdr def))))))
+           (t
+            (when (or (eq (car def) t) (string= type (car def)))
+              (setq disposition (cdr def))))))
+    (or disposition "attachment")))
+
+(defun mml-insert-mime-headers (cont type charset encoding flowed)
+  (let (parameters id disposition description)
+    (setq parameters
+         (mml-parameter-string
+          cont mml-content-type-parameters))
+    (when (or charset
+             parameters
+             flowed
+             (not (equal type mml-generate-default-type))
+             mml-insert-mime-headers-always)
+      (when (consp charset)
+       (error
+        "Can't encode a part with several charsets"))
+      (insert "Content-Type: " type)
+      (when charset
+       (mml-insert-parameter
+        (mail-header-encode-parameter "charset" (symbol-name charset))))
+      (when flowed
+       (mml-insert-parameter "format=flowed"))
+      (when parameters
+       (mml-insert-parameter-string
+        cont mml-content-type-parameters))
+      (insert "\n"))
+    (when (setq id (cdr (assq 'id cont)))
+      (insert "Content-ID: " id "\n"))
+    (setq parameters
+         (mml-parameter-string
+          cont mml-content-disposition-parameters))
+    (when (or (setq disposition (cdr (assq 'disposition cont)))
+             parameters)
+      (insert "Content-Disposition: "
+             (or disposition
+                 (mml-content-disposition type (cdr (assq 'filename cont)))))
+      (when parameters
+       (mml-insert-parameter-string
+        cont mml-content-disposition-parameters))
+      (insert "\n"))
+    (unless (eq encoding '7bit)
+      (insert (format "Content-Transfer-Encoding: %s\n" encoding)))
+    (when (setq description (cdr (assq 'description cont)))
+      (insert "Content-Description: ")
+      (setq description (prog1
+                           (point)
+                         (insert description "\n")))
+      (mail-encode-encoded-word-region description (point)))))
+
+(defun mml-parameter-string (cont types)
+  (let ((string "")
+       value type)
+    (while (setq type (pop types))
+      (when (setq value (cdr (assq type cont)))
+       ;; Strip directory component from the filename parameter.
+       (when (eq type 'filename)
+         (setq value (file-name-nondirectory value)))
+       (setq string (concat string "; "
+                            (mail-header-encode-parameter
+                             (symbol-name type) value)))))
+    (when (not (zerop (length string)))
+      string)))
+
+(defun mml-insert-parameter-string (cont types)
+  (let (value type)
+    (while (setq type (pop types))
+      (when (setq value (cdr (assq type cont)))
+       ;; Strip directory component from the filename parameter.
+       (when (eq type 'filename)
+         (setq value (file-name-nondirectory value)))
+       (mml-insert-parameter
+        (mail-header-encode-parameter
+         (symbol-name type) value))))))
+
+(defvar ange-ftp-name-format)
+(defvar efs-path-regexp)
+
+(defun mml-parse-file-name (path)
+  (if (if (boundp 'efs-path-regexp)
+         (string-match efs-path-regexp path)
+       (if (boundp 'ange-ftp-name-format)
+           (string-match (car ange-ftp-name-format) path)))
+      (list (match-string 1 path) (match-string 2 path)
+           (substring path (1+ (match-end 2))))
+    path))
+
+(defun mml-insert-buffer (buffer)
+  "Insert BUFFER at point and quote any MML markup."
+  (save-restriction
+    (narrow-to-region (point) (point))
+    (insert-buffer-substring buffer)
+    (mml-quote-region (point-min) (point-max))
+    (goto-char (point-max))))
+
+;;;
+;;; Transforming MIME to MML
+;;;
+
+;; message-narrow-to-head autoloads message.
+(declare-function message-remove-header "message"
+                  (header &optional is-regexp first reverse))
+
+(defun mime-to-mml (&optional handles)
+  "Translate the current buffer (which should be a message) into MML.
+If HANDLES is non-nil, use it instead reparsing the buffer."
+  ;; First decode the head.
+  (save-restriction
+    (message-narrow-to-head)
+    (let ((rfc2047-quote-decoded-words-containing-tspecials t))
+      (mail-decode-encoded-word-region (point-min) (point-max))))
+  (unless handles
+    (setq handles (mm-dissect-buffer t)))
+  (goto-char (point-min))
+  (search-forward "\n\n" nil t)
+  (delete-region (point) (point-max))
+  (if (stringp (car handles))
+      (mml-insert-mime handles)
+    (mml-insert-mime handles t))
+  (mm-destroy-parts handles)
+  (save-restriction
+    (message-narrow-to-head)
+    ;; 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")))
+
+(autoload 'message-encode-message-body "message")
+(declare-function message-narrow-to-headers-or-head "message" ())
+
+;;;###autoload
+(defun mml-to-mime ()
+  "Translate the current buffer from MML to MIME."
+  ;; `message-encode-message-body' will insert an encoded Content-Description
+  ;; header in the message header if the body contains a single part
+  ;; that is specified by a user with a MML tag containing a description
+  ;; token.  So, we encode the message header first to prevent the encoded
+  ;; Content-Description header from being encoded again.
+  (save-restriction
+    (message-narrow-to-headers-or-head)
+    ;; Skip past any From_ headers.
+    (while (looking-at "From ")
+      (forward-line 1))
+    (let ((mail-parse-charset message-default-charset))
+      (mail-encode-encoded-word-buffer)))
+  (message-encode-message-body))
+
+(defun mml-insert-mime (handle &optional no-markup)
+  (let (textp buffer mmlp)
+    ;; Determine type and stuff.
+    (unless (stringp (car handle))
+      (unless (setq textp (equal (mm-handle-media-supertype handle) "text"))
+       (with-current-buffer (setq buffer (mml-generate-new-buffer " *mml*"))
+         (if (eq (mail-content-type-get (mm-handle-type handle) 'charset)
+                 'gnus-decoded)
+             ;; A part that mm-uu dissected from a non-MIME message
+             ;; because of `gnus-article-emulate-mime'.
+             (progn
+               (mm-enable-multibyte)
+               (insert-buffer-substring (mm-handle-buffer handle)))
+           (mm-insert-part handle 'no-cache)
+           (if (setq mmlp (equal (mm-handle-media-type handle)
+                                 "message/rfc822"))
+               (mime-to-mml))))))
+    (if mmlp
+       (mml-insert-mml-markup handle nil t t)
+      (unless (and no-markup
+                  (equal (mm-handle-media-type handle) "text/plain"))
+       (mml-insert-mml-markup handle buffer textp)))
+    (cond
+     (mmlp
+      (insert-buffer-substring buffer)
+      (goto-char (point-max))
+      (insert "<#/mml>\n"))
+     ((stringp (car handle))
+      (mapc 'mml-insert-mime (cdr handle))
+      (insert "<#/multipart>\n"))
+     (textp
+      (let ((charset (mail-content-type-get
+                     (mm-handle-type handle) 'charset))
+           (start (point)))
+       (if (eq charset 'gnus-decoded)
+           (mm-insert-part handle)
+         (insert (mm-decode-string (mm-get-part handle) charset)))
+       (mml-quote-region start (point)))
+      (goto-char (point-max)))
+     (t
+      (insert "<#/part>\n")))))
+
+(defun mml-insert-mml-markup (handle &optional buffer nofile mmlp)
+  "Take a MIME handle and insert an MML tag."
+  (if (stringp (car handle))
+      (progn
+       (insert "<#multipart type=" (mm-handle-media-subtype handle))
+       (let ((start (mm-handle-multipart-ctl-parameter handle 'start)))
+         (when start
+           (insert " start=\"" start "\"")))
+       (insert ">\n"))
+    (if mmlp
+       (insert "<#mml type=" (mm-handle-media-type handle))
+      (insert "<#part type=" (mm-handle-media-type handle)))
+    (dolist (elem (append (cdr (mm-handle-type handle))
+                         (cdr (mm-handle-disposition handle))))
+      (unless (symbolp (cdr elem))
+       (insert " " (symbol-name (car elem)) "=\"" (cdr elem) "\"")))
+    (when (mm-handle-id handle)
+      (insert " id=\"" (mm-handle-id handle) "\""))
+    (when (mm-handle-disposition handle)
+      (insert " disposition=" (car (mm-handle-disposition handle))))
+    (when buffer
+      (insert " buffer=\"" (buffer-name buffer) "\""))
+    (when nofile
+      (insert " nofile=yes"))
+    (when (mm-handle-description handle)
+      (insert " description=\"" (mm-handle-description handle) "\""))
+    (insert ">\n")))
+
+(defun mml-insert-parameter (&rest parameters)
+  "Insert PARAMETERS in a nice way."
+  (let (start end)
+    (dolist (param parameters)
+      (insert ";")
+      (setq start (point))
+      (insert " " param)
+      (setq end (point))
+      (goto-char start)
+      (end-of-line)
+      (if (> (current-column) 76)
+         (progn
+           (goto-char start)
+           (insert "\n")
+           (goto-char (1+ end)))
+       (goto-char end)))))
+
+;;;
+;;; Mode for inserting and editing MML forms
+;;;
+
+(defvar mml-mode-map
+  (let ((sign (make-sparse-keymap))
+       (encrypt (make-sparse-keymap))
+       (signpart (make-sparse-keymap))
+       (encryptpart (make-sparse-keymap))
+       (map (make-sparse-keymap))
+       (main (make-sparse-keymap)))
+    (define-key map "\C-s" 'mml-secure-message-sign)
+    (define-key map "\C-c" 'mml-secure-message-encrypt)
+    (define-key map "\C-e" 'mml-secure-message-sign-encrypt)
+    (define-key map "\C-p\C-s" 'mml-secure-sign)
+    (define-key map "\C-p\C-c" 'mml-secure-encrypt)
+    (define-key sign "p" 'mml-secure-message-sign-pgpmime)
+    (define-key sign "o" 'mml-secure-message-sign-pgp)
+    (define-key sign "s" 'mml-secure-message-sign-smime)
+    (define-key signpart "p" 'mml-secure-sign-pgpmime)
+    (define-key signpart "o" 'mml-secure-sign-pgp)
+    (define-key signpart "s" 'mml-secure-sign-smime)
+    (define-key encrypt "p" 'mml-secure-message-encrypt-pgpmime)
+    (define-key encrypt "o" 'mml-secure-message-encrypt-pgp)
+    (define-key encrypt "s" 'mml-secure-message-encrypt-smime)
+    (define-key encryptpart "p" 'mml-secure-encrypt-pgpmime)
+    (define-key encryptpart "o" 'mml-secure-encrypt-pgp)
+    (define-key encryptpart "s" 'mml-secure-encrypt-smime)
+    (define-key map "\C-n" 'mml-unsecure-message)
+    (define-key map "f" 'mml-attach-file)
+    (define-key map "b" 'mml-attach-buffer)
+    (define-key map "e" 'mml-attach-external)
+    (define-key map "q" 'mml-quote-region)
+    (define-key map "m" 'mml-insert-multipart)
+    (define-key map "p" 'mml-insert-part)
+    (define-key map "v" 'mml-validate)
+    (define-key map "P" 'mml-preview)
+    (define-key map "s" sign)
+    (define-key map "S" signpart)
+    (define-key map "c" encrypt)
+    (define-key map "C" encryptpart)
+    ;;(define-key map "n" 'mml-narrow-to-part)
+    ;; `M-m' conflicts with `back-to-indentation'.
+    ;; (define-key main "\M-m" map)
+    (define-key main "\C-c\C-m" map)
+    main))
+
+(easy-menu-define
+  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
+     ,@(if (featurep 'xemacs) '(t)
+        '(:help "Attach a buffer to the outgoing message"))]
+    ["Attach External..." mml-attach-external
+     ,@(if (featurep 'xemacs) '(t)
+        '(:help "Attach reference to an external file"))]
+    ;; FIXME: Is it possible to do this without using
+    ;; `gnus-gcc-externalize-attachments'?
+    ["Externalize Attachments"
+     (lambda ()
+       (interactive)
+       (if (not (and (boundp 'gnus-gcc-externalize-attachments)
+                    (memq gnus-gcc-externalize-attachments
+                          '(all t nil))))
+          ;; Stupid workaround for XEmacs not honoring :visible.
+          (message "Can't handle this value of `gnus-gcc-externalize-attachments'")
+        (setq gnus-gcc-externalize-attachments
+              (not gnus-gcc-externalize-attachments))
+        (message "gnus-gcc-externalize-attachments is `%s'."
+                 gnus-gcc-externalize-attachments)))
+     ;; XEmacs barfs on :visible.
+     ,@(if (featurep 'xemacs) nil
+        '(:visible (and (boundp 'gnus-gcc-externalize-attachments)
+                        (memq gnus-gcc-externalize-attachments
+                              '(all t nil)))))
+     :style toggle
+     :selected gnus-gcc-externalize-attachments
+     ,@(if (featurep 'xemacs) nil
+        '(:help "Save attachments as external parts in Gcc copies"))]
+    "----"
+    ;;
+    ("Change Security Method"
+     ["PGP/MIME"
+      (lambda () (interactive) (setq mml-secure-method "pgpmime"))
+      ,@(if (featurep 'xemacs) nil
+         '(:help "Set Security Method to PGP/MIME"))
+      :style radio
+      :selected (equal mml-secure-method "pgpmime") ]
+     ["S/MIME"
+      (lambda () (interactive) (setq mml-secure-method "smime"))
+      ,@(if (featurep 'xemacs) nil
+         '(:help "Set Security Method to S/MIME"))
+      :style radio
+      :selected (equal mml-secure-method "smime") ]
+     ["Inline PGP"
+      (lambda () (interactive) (setq mml-secure-method "pgp"))
+      ,@(if (featurep 'xemacs) nil
+         '(:help "Set Security Method to inline PGP"))
+      :style radio
+      :selected (equal mml-secure-method "pgp") ] )
+    ;;
+    ["Sign Message" mml-secure-message-sign t]
+    ["Encrypt Message" mml-secure-message-encrypt t]
+    ["Sign and Encrypt Message" mml-secure-message-sign-encrypt t]
+    ["Encrypt/Sign off" mml-unsecure-message
+     ,@(if (featurep 'xemacs) '(t)
+        '(:help "Don't Encrypt/Sign Message"))]
+    ;; Do we have separate encrypt and encrypt/sign commands for parts?
+    ["Sign Part" mml-secure-sign t]
+    ["Encrypt Part" mml-secure-encrypt t]
+    "----"
+    ;; Maybe we could remove these, because people who write MML most probably
+    ;; don't use the menu:
+    ["Insert Part..." mml-insert-part
+     :active (message-in-body-p)]
+    ["Insert Multipart..." mml-insert-multipart
+     :active (message-in-body-p)]
+    ;;
+    ;;["Narrow" mml-narrow-to-part t]
+    ["Quote MML in region" mml-quote-region
+     :active (message-mark-active-p)
+     ,@(if (featurep 'xemacs) nil
+        '(:help "Quote MML tags in region"))]
+    ["Validate MML" mml-validate t]
+    ["Preview" mml-preview t]
+    "----"
+    ["Emacs MIME manual" (lambda () (interactive) (message-info 4))
+     ,@(if (featurep 'xemacs) '(t)
+        '(:help "Display the Emacs MIME manual"))]
+    ["PGG manual" (lambda () (interactive) (message-info mml2015-use))
+     ;; XEmacs barfs on :visible.
+     ,@(if (featurep 'xemacs) nil
+        '(:visible (and (boundp 'mml2015-use) (equal mml2015-use 'pgg))))
+     ,@(if (featurep 'xemacs) '(t)
+        '(:help "Display the PGG manual"))]
+    ["EasyPG manual" (lambda () (interactive) (require 'mml2015) (message-info mml2015-use))
+     ;; XEmacs barfs on :visible.
+     ,@(if (featurep 'xemacs) nil
+        '(:visible (and (boundp 'mml2015-use) (equal mml2015-use 'epg))))
+     ,@(if (featurep 'xemacs) '(t)
+        '(:help "Display the EasyPG manual"))]))
+
+(define-minor-mode mml-mode
+  "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}"
+  :lighter " MML" :keymap mml-mode-map
+  (when mml-mode
+    (easy-menu-add mml-menu mml-mode-map)
+    (when (boundp 'dnd-protocol-alist)
+      (set (make-local-variable 'dnd-protocol-alist)
+          (append mml-dnd-protocol-alist dnd-protocol-alist)))))
+
+;;;
+;;; Helper functions for reading MIME stuff from the minibuffer and
+;;; inserting stuff to the buffer.
+;;;
+
+(defcustom mml-default-directory mm-default-directory
+  "The default directory where mml will find files.
+If not set, `default-directory' will be used."
+  :type '(choice directory (const :tag "Default" nil))
+  :version "23.1" ;; No Gnus
+  :group 'message)
+
+(defun mml-minibuffer-read-file (prompt)
+  (let* ((completion-ignored-extensions nil)
+        (file (read-file-name prompt
+                              (or mml-default-directory default-directory)
+                              nil t)))
+    ;; 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))
+    (unless (file-exists-p file)
+      (error "No such file: %s" file))
+    (unless (file-readable-p file)
+      (error "Permission denied: %s" file))
+    file))
+
+(declare-function mailcap-parse-mimetypes "mailcap" (&optional path force))
+(declare-function mailcap-mime-types "mailcap" ())
+
+(defun mml-minibuffer-read-type (name &optional default)
+  (require 'mailcap)
+  (mailcap-parse-mimetypes)
+  (let* ((default (or default
+                     (mm-default-file-encoding name)
+                     ;; Perhaps here we should check what the file
+                     ;; looks like, and offer text/plain if it looks
+                     ;; like text/plain.
+                     "application/octet-stream"))
+        (string (gnus-completing-read
+                 "Content type"
+                 (mailcap-mime-types)
+                  nil nil nil default)))
+    (if (not (equal string ""))
+       string
+      default)))
+
+(defun mml-minibuffer-read-description (&optional default)
+  (let ((description (read-string "One line description: " default)))
+    (when (string-match "\\`[ \t]*\\'" description)
+      (setq description nil))
+    description))
+
+(defun mml-minibuffer-read-disposition (type &optional default filename)
+  (unless default
+    (setq default (mml-content-disposition type filename)))
+  (let ((disposition (gnus-completing-read
+                     "Disposition"
+                     '("attachment" "inline")
+                     t nil nil default)))
+    (if (not (equal disposition ""))
+       disposition
+      default)))
+
+(defun mml-quote-region (beg end)
+  "Quote the MML tags in the region."
+  (interactive "r")
+  (save-excursion
+    (save-restriction
+      ;; Temporarily narrow the region to defend from changes
+      ;; invalidating END.
+      (narrow-to-region beg end)
+      (goto-char (point-min))
+      ;; Quote parts.
+      (while (re-search-forward
+             "<#!*/?\\(multipart\\|part\\|external\\|mml\\|secure\\)" nil t)
+       ;; Insert ! after the #.
+       (goto-char (+ (match-beginning 0) 2))
+       (insert "!")))))
+
+(defun mml-insert-tag (name &rest plist)
+  "Insert an MML tag described by NAME and PLIST."
+  (when (symbolp name)
+    (setq name (symbol-name name)))
+  (insert "<#" name)
+  (while plist
+    (let ((key (pop plist))
+         (value (pop plist)))
+      (when value
+       ;; Quote VALUE if it contains suspicious characters.
+       (when (string-match "[\"'\\~/*;() \t\n]" value)
+         (setq value (with-output-to-string
+                       (let (print-escape-nonascii)
+                         (prin1 value)))))
+       (insert (format " %s=%s" key value)))))
+  (insert ">\n"))
+
+(defun mml-insert-empty-tag (name &rest plist)
+  "Insert an empty MML tag described by NAME and PLIST."
+  (when (symbolp name)
+    (setq name (symbol-name name)))
+  (apply #'mml-insert-tag name plist)
+  (insert "<#/" name ">\n"))
+
+;;; Attachment functions.
+
+(defcustom mml-dnd-protocol-alist
+  '(("^file:///" . mml-dnd-attach-file)
+    ("^file://"  . dnd-open-file)
+    ("^file:"    . mml-dnd-attach-file))
+  "The functions to call when a drop in `mml-mode' is made.
+See `dnd-protocol-alist' for more information.  When nil, behave
+as in other buffers."
+  :type '(choice (repeat (cons (regexp) (function)))
+                (const :tag "Behave as in other buffers" nil))
+  :version "22.1" ;; Gnus 5.10.9
+  :group 'message)
+
+(defcustom mml-dnd-attach-options nil
+  "Which options should be queried when attaching a file via drag and drop.
+
+If it is a list, valid members are `type', `description' and
+`disposition'.  `disposition' implies `type'.  If it is nil,
+don't ask for options.  If it is t, ask the user whether or not
+to specify options."
+  :type '(choice
+         (const :tag "None" nil)
+         (const :tag "Query" t)
+         (list :value (type description disposition)
+          (set :inline t
+               (const type)
+               (const description)
+               (const disposition))))
+  :version "22.1" ;; Gnus 5.10.9
+  :group 'message)
+
+;;;###autoload
+(defun mml-attach-file (file &optional type description disposition)
+  "Attach a file to the outgoing MIME message.
+The file is not inserted or encoded until you send the message with
+`\\[message-send-and-exit]' or `\\[message-send]' in Message mode,
+or `\\[mail-send-and-exit]' or `\\[mail-send]' in Mail mode.
+
+FILE is the name of the file to attach.  TYPE is its
+content-type, a string of the form \"type/subtype\".  DESCRIPTION
+is a one-line description of the attachment.  The DISPOSITION
+specifies how the attachment is intended to be displayed.  It can
+be either \"inline\" (displayed automatically within the message
+body) or \"attachment\" (separate from the body)."
+  (interactive
+   (let* ((file (mml-minibuffer-read-file "Attach file: "))
+         (type (mml-minibuffer-read-type file))
+         (description (mml-minibuffer-read-description))
+         (disposition (mml-minibuffer-read-disposition type nil file)))
+     (list file type description disposition)))
+  ;; If in the message header, attach at the end and leave point unchanged.
+  (let ((head (unless (message-in-body-p) (point))))
+    (if head (goto-char (point-max)))
+    (mml-insert-empty-tag 'part
+                         'type type
+                         ;; icicles redefines read-file-name and returns a
+                         ;; string w/ text properties :-/
+                         'filename (mm-substring-no-properties file)
+                         'disposition (or disposition "attachment")
+                         'description description)
+    ;; When using Mail mode, make sure it does the mime encoding
+    ;; when you send the message.
+    (or (eq mail-user-agent 'message-user-agent)
+       (setq mail-encode-mml t))
+    (when head
+      (unless (pos-visible-in-window-p)
+       (message "The file \"%s\" has been attached at the end of the message"
+                (file-name-nondirectory file)))
+      (goto-char head))))
+
+(defun mml-dnd-attach-file (uri action)
+  "Attach a drag and drop file.
+
+Ask for type, description or disposition according to
+`mml-dnd-attach-options'."
+  (let ((file (dnd-get-local-file-name uri t)))
+    (when (and file (file-regular-p file))
+      (let ((mml-dnd-attach-options mml-dnd-attach-options)
+           type description disposition)
+       (setq mml-dnd-attach-options
+             (when (and (eq mml-dnd-attach-options t)
+                        (not
+                         (y-or-n-p
+                          "Use default type, disposition and description? ")))
+               '(type description disposition)))
+       (when (or (memq 'type mml-dnd-attach-options)
+                 (memq 'disposition mml-dnd-attach-options))
+         (setq type (mml-minibuffer-read-type file)))
+       (when (memq 'description mml-dnd-attach-options)
+         (setq description (mml-minibuffer-read-description)))
+       (when (memq 'disposition mml-dnd-attach-options)
+         (setq disposition (mml-minibuffer-read-disposition type nil file)))
+       (mml-attach-file file type description disposition)))))
+
+(defun mml-attach-buffer (buffer &optional type description disposition)
+  "Attach a buffer to the outgoing MIME message.
+BUFFER is the name of the buffer to attach.  See
+`mml-attach-file' for details of operation."
+  (interactive
+   (let* ((buffer (read-buffer "Attach buffer: "))
+         (type (mml-minibuffer-read-type buffer "text/plain"))
+         (description (mml-minibuffer-read-description))
+         (disposition (mml-minibuffer-read-disposition type nil)))
+     (list buffer type description disposition)))
+  ;; If in the message header, attach at the end and leave point unchanged.
+  (let ((head (unless (message-in-body-p) (point))))
+    (if head (goto-char (point-max)))
+    (mml-insert-empty-tag 'part 'type type 'buffer buffer
+                         'disposition disposition
+                         'description description)
+    ;; When using Mail mode, make sure it does the mime encoding
+    ;; when you send the message.
+    (or (eq mail-user-agent 'message-user-agent)
+       (setq mail-encode-mml t))
+    (when head
+      (unless (pos-visible-in-window-p)
+       (message
+        "The buffer \"%s\" has been attached at the end of the message"
+        buffer))
+      (goto-char head))))
+
+(defun mml-attach-external (file &optional type description)
+  "Attach an external file into the buffer.
+FILE is an ange-ftp/efs specification of the part location.
+TYPE is the MIME type to use."
+  (interactive
+   (let* ((file (mml-minibuffer-read-file "Attach external file: "))
+         (type (mml-minibuffer-read-type file))
+         (description (mml-minibuffer-read-description)))
+     (list file type description)))
+  ;; If in the message header, attach at the end and leave point unchanged.
+  (let ((head (unless (message-in-body-p) (point))))
+    (if head (goto-char (point-max)))
+    (mml-insert-empty-tag 'external 'type type 'name file
+                         'disposition "attachment" 'description description)
+    ;; When using Mail mode, make sure it does the mime encoding
+    ;; when you send the message.
+    (or (eq mail-user-agent 'message-user-agent)
+       (setq mail-encode-mml t))
+    (when head
+      (unless (pos-visible-in-window-p)
+       (message "The file \"%s\" has been attached at the end of the message"
+                (file-name-nondirectory file)))
+      (goto-char head))))
+
+(defun mml-insert-multipart (&optional type)
+  (interactive (if (message-in-body-p)
+                  (list (gnus-completing-read "Multipart type"
+                                               '("mixed" "alternative"
+                                                 "digest" "parallel"
+                                                 "signed" "encrypted")
+                                               nil "mixed"))
+                (error "Use this command in the message body")))
+  (or type
+      (setq type "mixed"))
+  (mml-insert-empty-tag "multipart" 'type type)
+  ;; When using Mail mode, make sure it does the mime encoding
+  ;; when you send the message.
+  (or (eq mail-user-agent 'message-user-agent)
+      (setq mail-encode-mml t))
+  (forward-line -1))
+
+(defun mml-insert-part (&optional type)
+  (interactive (if (message-in-body-p)
+                  (list (mml-minibuffer-read-type ""))
+                (error "Use this command in the message body")))
+  ;; When using Mail mode, make sure it does the mime encoding
+  ;; when you send the message.
+  (or (eq mail-user-agent 'message-user-agent)
+      (setq mail-encode-mml t))
+  (mml-insert-tag 'part 'type type 'disposition "inline")
+  (save-excursion
+    (mml-insert-tag '/part)))
+
+(declare-function message-subscribed-p "message" ())
+(declare-function message-make-mail-followup-to "message"
+                  (&optional only-show-subscribed))
+(declare-function message-position-on-field "message" (header &rest afters))
+
+(defun mml-preview-insert-mail-followup-to ()
+  "Insert a Mail-Followup-To header before previewing an article.
+Should be adopted if code in `message-send-mail' is changed."
+  (when (and (message-mail-p)
+            (message-subscribed-p)
+            (not (mail-fetch-field "mail-followup-to"))
+            (message-make-mail-followup-to))
+    (message-position-on-field "Mail-Followup-To" "X-Draft-From")
+    (insert (message-make-mail-followup-to))))
+
+(defvar mml-preview-buffer nil)
+
+(autoload 'gnus-make-hashtable "gnus-util")
+(autoload 'widget-button-press "wid-edit" nil t)
+(declare-function widget-event-point "wid-edit" (event))
+;; If gnus-buffer-configuration is bound this is loaded.
+(declare-function gnus-configure-windows "gnus-win" (setting &optional force))
+;; Called after message-mail-p, which autoloads message.
+(declare-function message-news-p                "message" ())
+(declare-function message-options-set-recipient "message" ())
+(declare-function message-generate-headers      "message" (headers))
+(declare-function message-sort-headers          "message" ())
+
+(defun mml-preview (&optional raw)
+  "Display current buffer with Gnus, in a new buffer.
+If RAW, display a raw encoded MIME message.
+
+The window layout for the preview buffer is controlled by the variables
+`special-display-buffer-names', `special-display-regexps', or
+`gnus-buffer-configuration' (the first match made will be used),
+or the `pop-to-buffer' function."
+  (interactive "P")
+  (setq mml-preview-buffer (generate-new-buffer
+                           (concat (if raw "*Raw MIME preview of "
+                                     "*MIME preview of ") (buffer-name))))
+  (require 'gnus-msg)                ; for gnus-setup-posting-charset
+  (save-excursion
+    (let* ((buf (current-buffer))
+          (article-editing (eq major-mode 'gnus-article-edit-mode))
+          (message-options message-options)
+          (message-this-is-mail (message-mail-p))
+          (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)
+      (when (boundp 'gnus-buffers)
+       (push mml-preview-buffer gnus-buffers))
+      (save-restriction
+       (widen)
+       (set-buffer mml-preview-buffer)
+       (erase-buffer)
+       (insert-buffer-substring buf))
+      (mml-preview-insert-mail-followup-to)
+      (let ((message-deletable-headers (if (message-news-p)
+                                          nil
+                                        message-deletable-headers))
+           (mail-header-separator (if article-editing
+                                      ""
+                                    mail-header-separator)))
+       (message-generate-headers
+        (copy-sequence (if (message-news-p)
+                           message-required-news-headers
+                         message-required-mail-headers)))
+       (unless article-editing
+         (if (re-search-forward
+              (concat "^" (regexp-quote mail-header-separator) "\n") nil t)
+             (replace-match "\n"))
+         (setq mail-header-separator ""))
+       (message-sort-headers)
+       (mml-to-mime))
+      (if raw
+         (when (fboundp 'set-buffer-multibyte)
+           (let ((s (buffer-string)))
+             ;; Insert the content into unibyte buffer.
+             (erase-buffer)
+             (mm-disable-multibyte)
+             (insert s)))
+       (let ((gnus-newsgroup-charset (car message-posting-charset))
+             gnus-article-prepare-hook gnus-original-article-buffer
+             gnus-displaying-mime)
+         (run-hooks 'gnus-article-decode-hook)
+         (let ((gnus-newsgroup-name "dummy")
+               (gnus-newsrc-hashtb (or gnus-newsrc-hashtb
+                                       (gnus-make-hashtable 5))))
+           (gnus-article-prepare-display))))
+      ;; Disable article-mode-map.
+      (use-local-map nil)
+      (gnus-make-local-hook 'kill-buffer-hook)
+      (add-hook 'kill-buffer-hook
+               (lambda ()
+                 (mm-destroy-parts gnus-article-mime-handles)) nil t)
+      (setq buffer-read-only t)
+      (local-set-key "q" (lambda () (interactive) (kill-buffer nil)))
+      (local-set-key "=" (lambda () (interactive) (delete-other-windows)))
+      (local-set-key "\r"
+                    (lambda ()
+                      (interactive)
+                      (widget-button-press (point))))
+      (local-set-key gnus-mouse-2
+                    (lambda (event)
+                      (interactive "@e")
+                      (widget-button-press (widget-event-point event) event)))
+      ;; FIXME: Buffer is in article mode, but most tool bar commands won't
+      ;; work.  Maybe only keep the following icons: search, print, quit
+      (goto-char (point-min))))
+  (if (and (not (mm-special-display-p (buffer-name mml-preview-buffer)))
+          (boundp 'gnus-buffer-configuration)
+          (assq 'mml-preview gnus-buffer-configuration))
+      (let ((gnus-message-buffer (current-buffer)))
+       (gnus-configure-windows 'mml-preview))
+    (pop-to-buffer mml-preview-buffer)))
+
+(defun mml-validate ()
+  "Validate the current MML document."
+  (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)
+    (let ((alist mml-tweak-sexp-alist))
+      (while alist
+       (if (eval (caar alist))
+           (funcall (cdar alist) cont))
+       (setq alist (cdr alist)))))
+  cont)
+
+(defun mml-tweak-externalize-attachments (cont)
+  "Tweak attached files as external parts."
+  (let (filename-cons)
+    (when (and (eq (car cont) 'part)
+              (not (cdr (assq 'buffer cont)))
+              (and (setq filename-cons (assq 'filename cont))
+                   (not (equal (cdr (assq 'nofile cont)) "yes"))))
+      (setcar cont 'external)
+      (setcar filename-cons 'name))))
+
+(provide 'mml)
+
+;;; mml.el ends here
diff --git a/xemacs-packages/gnus/lisp/mml1991.el b/xemacs-packages/gnus/lisp/mml1991.el
new file mode 100644 (file)
index 0000000..bb5c940
--- /dev/null
@@ -0,0 +1,332 @@
+;;; mml1991.el --- Old PGP message format (RFC 1991) support for MML
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Sascha Lüdecke <sascha@meta-x.de>,
+;;     Simon Josefsson <simon@josefsson.org> (Mailcrypt interface, Gnus glue)
+;; Keywords: PGP
+
+;; This file is 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-and-compile
+  (if (locate-library "password-cache")
+      (require 'password-cache)
+    (require 'password)))
+
+(eval-when-compile
+  (require 'cl)
+  (require 'mm-util))
+
+(require 'mm-encode)
+(require 'mml-sec)
+
+(defvar mc-pgp-always-sign)
+
+(autoload 'quoted-printable-decode-region "qp")
+(autoload 'quoted-printable-encode-region "qp")
+
+(autoload 'mm-decode-content-transfer-encoding "mm-bodies")
+(autoload 'mm-encode-content-transfer-encoding "mm-bodies")
+(autoload 'message-options-get "message")
+(autoload 'message-options-set "message")
+
+(require 'mml2015)
+
+(defvar mml1991-use mml2015-use
+  "The package used for PGP.")
+
+(defvar mml1991-function-alist
+  '((mailcrypt mml1991-mailcrypt-sign
+              mml1991-mailcrypt-encrypt)
+    (pgg mml1991-pgg-sign
+        mml1991-pgg-encrypt)
+    (epg mml1991-epg-sign
+        mml1991-epg-encrypt))
+  "Alist of PGP functions.")
+
+(defvar mml1991-cache-passphrase mml-secure-cache-passphrase
+  "If t, cache passphrase.")
+(make-obsolete-variable 'mml1991-cache-passphrase
+                       'mml-secure-cache-passphrase
+                       "25.1")
+
+(defvar mml1991-passphrase-cache-expiry mml-secure-passphrase-cache-expiry
+  "How many seconds the passphrase is cached.
+Whether the passphrase is cached at all is controlled by
+`mml1991-cache-passphrase'.")
+(make-obsolete-variable 'mml1991-passphrase-cache-expiry
+                       'mml-secure-passphrase-cache-expiry
+                       "25.1")
+
+(defvar mml1991-signers nil
+  "A list of your own key ID which will be used to sign a message.")
+
+(defvar mml1991-encrypt-to-self nil
+  "If t, add your own key ID to recipient list when encryption.")
+
+
+;;; mailcrypt wrapper
+
+(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))
+    (unless (bobp)
+      (setq headers (buffer-string))
+      (delete-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-substring 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)
+      (delete-region (point-min) (point-max))
+      (if headers (insert headers))
+      (insert "\n")
+      (insert-buffer-substring signature)
+      (goto-char (point-max)))))
+
+(declare-function mc-encrypt-generic "ext:mc-toplev"
+                  (&optional recipients scheme start end from sign))
+
+(defun mml1991-mailcrypt-encrypt (cont &optional sign)
+  (let ((text (current-buffer))
+       (mc-pgp-always-sign
+        (or mc-pgp-always-sign
+            sign
+            (eq t (or (message-options-get 'message-sign-encrypt)
+                      (message-options-set
+                       'message-sign-encrypt
+                       (or (y-or-n-p "Sign the message? ")
+                           'not))))
+            'never))
+       cipher
+       (result-buffer (get-buffer-create "*GPG Result*")))
+    ;; Strip MIME Content[^ ]: headers since it will be ASCII ARMORED
+    (goto-char (point-min))
+    (while (looking-at "^Content[^ ]+:") (forward-line))
+    (unless (bobp)
+      (delete-region (point-min) (point)))
+    (with-temp-buffer
+      (inline (mm-disable-multibyte))
+      (setq cipher (current-buffer))
+      (insert-buffer-substring 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)
+      (delete-region (point-min) (point-max))
+      ;;(insert "Content-Type: application/pgp-encrypted\n\n")
+      ;;(insert "Version: 1\n\n")
+      (insert "\n")
+      (insert-buffer-substring cipher)
+      (goto-char (point-max)))))
+
+;; pgg wrapper
+
+(autoload 'pgg-sign-region "pgg")
+(autoload 'pgg-encrypt-region "pgg")
+
+(defvar pgg-default-user-id)
+(defvar pgg-errors-buffer)
+(defvar pgg-output-buffer)
+
+(defun mml1991-pgg-sign (cont)
+  (let ((pgg-text-mode t)
+       (pgg-default-user-id (or (message-options-get 'mml-sender)
+                                pgg-default-user-id))
+       headers cte)
+    ;; Don't sign headers.
+    (goto-char (point-min))
+    (when (re-search-forward "^$" nil t)
+      (setq headers (buffer-substring (point-min) (point)))
+      (save-restriction
+       (narrow-to-region (point-min) (point))
+       (setq cte (mail-fetch-field "content-transfer-encoding")))
+      (forward-line 1)
+      (delete-region (point-min) (point))
+      (when cte
+       (setq cte (intern (downcase cte)))
+       (mm-decode-content-transfer-encoding cte)))
+    (unless (pgg-sign-region (point-min) (point-max) t)
+      (pop-to-buffer pgg-errors-buffer)
+      (error "Encrypt error"))
+    (delete-region (point-min) (point-max))
+    (mm-with-unibyte-current-buffer
+      (insert-buffer-substring pgg-output-buffer)
+      (goto-char (point-min))
+      (while (re-search-forward "\r+$" nil t)
+       (replace-match "" t t))
+      (when cte
+       (mm-encode-content-transfer-encoding cte))
+      (goto-char (point-min))
+      (when headers
+       (insert headers))
+      (insert "\n"))
+    t))
+
+(defun mml1991-pgg-encrypt (cont &optional sign)
+  (goto-char (point-min))
+  (when (re-search-forward "^$" nil t)
+    (let ((cte (save-restriction
+                (narrow-to-region (point-min) (point))
+                (mail-fetch-field "content-transfer-encoding"))))
+      ;; Strip MIME headers since it will be ASCII armored.
+      (forward-line 1)
+      (delete-region (point-min) (point))
+      (when cte
+       (mm-decode-content-transfer-encoding (intern (downcase cte))))))
+  (unless (let ((pgg-text-mode t))
+           (pgg-encrypt-region
+            (point-min) (point-max)
+            (split-string
+             (or
+              (message-options-get 'message-recipients)
+              (message-options-set 'message-recipients
+                                   (read-string "Recipients: ")))
+             "[ \f\t\n\r\v,]+")
+            sign))
+    (pop-to-buffer pgg-errors-buffer)
+    (error "Encrypt error"))
+  (delete-region (point-min) (point-max))
+  (insert "\n")
+  (insert-buffer-substring pgg-output-buffer)
+  t)
+
+;; epg wrapper
+
+(defvar epg-user-id-alist)
+
+(autoload 'epg-make-context "epg")
+(autoload 'epg-passphrase-callback-function "epg")
+(autoload 'epa-select-keys "epa")
+(autoload 'epg-list-keys "epg")
+(autoload 'epg-context-set-armor "epg")
+(autoload 'epg-context-set-textmode "epg")
+(autoload 'epg-context-set-signers "epg")
+(autoload 'epg-context-set-passphrase-callback "epg")
+(autoload 'epg-key-sub-key-list "epg")
+(autoload 'epg-sub-key-capability "epg")
+(autoload 'epg-sub-key-validity "epg")
+(autoload 'epg-sub-key-fingerprint "epg")
+(autoload 'epg-sign-string "epg")
+(autoload 'epg-encrypt-string "epg")
+(autoload 'epg-configuration "epg-config")
+(autoload 'epg-expand-group "epg-config")
+
+(defun mml1991-epg-sign (cont)
+  (let ((inhibit-redisplay t)
+       headers cte)
+    ;; Don't sign headers.
+    (goto-char (point-min))
+    (when (re-search-forward "^$" nil t)
+      (setq headers (buffer-substring (point-min) (point)))
+      (save-restriction
+       (narrow-to-region (point-min) (point))
+       (setq cte (mail-fetch-field "content-transfer-encoding")))
+      (forward-line 1)
+      (delete-region (point-min) (point))
+      (when cte
+       (setq cte (intern (downcase cte)))
+       (mm-decode-content-transfer-encoding cte)))
+    (let* ((pair (mml-secure-epg-sign 'OpenPGP 'clear))
+          (signature (car pair)))
+      (delete-region (point-min) (point-max))
+      (mm-with-unibyte-current-buffer
+       (insert signature)
+       (goto-char (point-min))
+       (while (re-search-forward "\r+$" nil t)
+         (replace-match "" t t))
+       (when cte
+         (mm-encode-content-transfer-encoding cte))
+       (goto-char (point-min))
+       (when headers
+         (insert headers))
+       (insert "\n"))
+      t)))
+
+(defun mml1991-epg-encrypt (cont &optional sign)
+  (goto-char (point-min))
+  (when (re-search-forward "^$" nil t)
+    (let ((cte (save-restriction
+                (narrow-to-region (point-min) (point))
+                (mail-fetch-field "content-transfer-encoding"))))
+      ;; Strip MIME headers since it will be ASCII armored.
+      (forward-line 1)
+      (delete-region (point-min) (point))
+      (when cte
+       (mm-decode-content-transfer-encoding (intern (downcase cte))))))
+  (let ((cipher (mml-secure-epg-encrypt 'OpenPGP cont sign)))
+    (delete-region (point-min) (point-max))
+    (insert "\n" cipher))
+  t)
+
+;;;###autoload
+(defun mml1991-encrypt (cont &optional sign)
+  (let ((func (nth 2 (assq mml1991-use mml1991-function-alist))))
+    (if func
+       (funcall func cont sign)
+      (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: utf-8
+;; End:
+
+;;; mml1991.el ends here
diff --git a/xemacs-packages/gnus/lisp/mml2015.el b/xemacs-packages/gnus/lisp/mml2015.el
new file mode 100644 (file)
index 0000000..e2e9977
--- /dev/null
@@ -0,0 +1,1087 @@
+;;; mml2015.el --- MIME Security with Pretty Good Privacy (PGP)
+
+;; Copyright (C) 2000-2016 Free Software Foundation, Inc.
+
+;; Author: Shenghuo Zhu <zsh@cs.rochester.edu>
+;; Keywords: PGP MIME MML
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; RFC 2015 is updated by RFC 3156, this file should be compatible
+;; with both.
+
+;;; Code:
+
+(eval-and-compile
+  (if (locate-library "password-cache")
+      (require 'password-cache)
+    (require 'password)))
+
+(eval-when-compile (require 'cl))
+(require 'mm-decode)
+(require 'mm-util)
+(require 'mml)
+(require 'mml-sec)
+
+(defvar mc-pgp-always-sign)
+
+(declare-function epg-check-configuration "ext:epg-config"
+                  (config &optional minimum-version))
+(declare-function epg-configuration "ext:epg-config" ())
+
+;; Maybe this should be in eg mml-sec.el (and have a different name).
+;; Then mml1991 would not need to require mml2015, and mml1991-use
+;; could be removed.
+(defvar mml2015-use (or
+                    (progn
+                      (ignore-errors (require 'epg-config))
+                      (and (fboundp 'epg-check-configuration)
+                          'epg))
+                    (progn
+                      (let ((abs-file (locate-library "pgg")))
+                        ;; Don't load PGG if it is marked as obsolete
+                        ;; (Emacs 24).
+                        (when (and abs-file
+                                   (not (string-match "/obsolete/[^/]*\\'"
+                                                      abs-file)))
+                          (ignore-errors (require 'pgg))
+                          (and (fboundp 'pgg-sign-region)
+                               'pgg))))
+                    (progn (ignore-errors
+                             (load "mc-toplev"))
+                           (and (fboundp 'mc-encrypt-generic)
+                                (fboundp 'mc-sign-generic)
+                                (fboundp 'mc-cleanup-recipient-headers)
+                                'mailcrypt)))
+  "The package used for PGP/MIME.
+Valid packages include `epg', `pgg' and `mailcrypt'.")
+
+;; Something is not RFC2015.
+(defvar mml2015-function-alist
+  '((mailcrypt mml2015-mailcrypt-sign
+              mml2015-mailcrypt-encrypt
+              mml2015-mailcrypt-verify
+              mml2015-mailcrypt-decrypt
+              mml2015-mailcrypt-clear-verify
+              mml2015-mailcrypt-clear-decrypt)
+    (pgg mml2015-pgg-sign
+        mml2015-pgg-encrypt
+        mml2015-pgg-verify
+        mml2015-pgg-decrypt
+        mml2015-pgg-clear-verify
+        mml2015-pgg-clear-decrypt)
+    (epg mml2015-epg-sign
+        mml2015-epg-encrypt
+        mml2015-epg-verify
+        mml2015-epg-decrypt
+        mml2015-epg-clear-verify
+        mml2015-epg-clear-decrypt))
+  "Alist of PGP/MIME functions.")
+
+(defvar mml2015-result-buffer nil)
+
+(defcustom mml2015-unabbrev-trust-alist
+  '(("TRUST_UNDEFINED" . nil)
+    ("TRUST_NEVER"     . nil)
+    ("TRUST_MARGINAL"  . t)
+    ("TRUST_FULLY"     . t)
+    ("TRUST_ULTIMATE"  . t))
+  "Map GnuPG trust output values to a boolean saying if you trust the key."
+  :version "22.1"
+  :group 'mime-security
+  :type '(repeat (cons (regexp :tag "GnuPG output regexp")
+                      (boolean :tag "Trust key"))))
+
+(defcustom mml2015-cache-passphrase mml-secure-cache-passphrase
+  "If t, cache passphrase."
+  :group 'mime-security
+  :type 'boolean)
+(make-obsolete-variable 'mml2015-cache-passphrase
+                       'mml-secure-cache-passphrase
+                       "25.1")
+
+(defcustom mml2015-passphrase-cache-expiry mml-secure-passphrase-cache-expiry
+  "How many seconds the passphrase is cached.
+Whether the passphrase is cached at all is controlled by
+`mml2015-cache-passphrase'."
+  :group 'mime-security
+  :type 'integer)
+(make-obsolete-variable 'mml2015-passphrase-cache-expiry
+                       'mml-secure-passphrase-cache-expiry
+                       "25.1")
+
+(defcustom mml2015-signers nil
+  "A list of your own key ID(s) which will be used to sign a message.
+If set, it overrides the setting of `mml2015-sign-with-sender'."
+  :group 'mime-security
+  :type '(repeat (string :tag "Key ID")))
+
+(defcustom mml2015-sign-with-sender nil
+  "If t, use message sender so find a key to sign with."
+  :group 'mime-security
+  :type 'boolean
+  :version "24.1")
+
+(defcustom mml2015-encrypt-to-self nil
+  "If t, add your own key ID to recipient list when encryption."
+  :group 'mime-security
+  :type 'boolean)
+
+(defcustom mml2015-always-trust t
+  "If t, GnuPG skip key validation on encryption."
+  :group 'mime-security
+  :type 'boolean)
+
+(defcustom mml2015-maximum-key-image-dimension 64
+  "The maximum dimension (width or height) of any key images."
+  :version "24.4"
+  :group 'mime-security
+  :type 'integer)
+
+(defcustom mml2015-display-key-image t
+  "If t, try to display key images."
+  :version "24.5"
+  :group 'mime-security
+  :type 'boolean)
+
+;; Extract plaintext from cleartext signature.  IMO, this kind of task
+;; should be done by GnuPG rather than Elisp, but older PGP backends
+;; (such as Mailcrypt, and PGG) discard the output from GnuPG.
+(defun mml2015-extract-cleartext-signature ()
+  ;; Daiki Ueno in
+  ;; <54a15d860801080142l70b95d7dkac4bf51a86196011@mail.gmail.com>: ``I still
+  ;; believe that the right way is to use the plaintext output from GnuPG as
+  ;; it is, and mml2015-extract-cleartext-signature is just a kludge for
+  ;; misdesigned libraries like PGG, which have no ability to do that.  So, I
+  ;; think it should not have descriptive documentation.''
+  ;;
+  ;; This function doesn't handle NotDashEscaped correctly.  EasyPG handles it
+  ;; correctly.
+  ;; http://thread.gmane.org/gmane.emacs.gnus.general/66062/focus=66082
+  ;; http://thread.gmane.org/gmane.emacs.gnus.general/65087/focus=65109
+  (goto-char (point-min))
+  (forward-line)
+  ;; We need to be careful not to strip beyond the armor headers.
+  ;; Previously, an attacker could replace the text inside our
+  ;; markup with trailing garbage by injecting whitespace into the
+  ;; message.
+  (while (looking-at "Hash:")          ; The only header allowed in cleartext
+    (forward-line))                    ; signatures according to RFC2440.
+  (when (looking-at "[\t ]*$")
+    (forward-line))
+  (delete-region (point-min) (point))
+  (if (re-search-forward "^-----BEGIN PGP SIGNATURE-----" nil t)
+      (delete-region (match-beginning 0) (point-max)))
+  (goto-char (point-min))
+  (while (re-search-forward "^- " nil t)
+    (replace-match "" t t)
+    (forward-line 1)))
+
+;;; mailcrypt wrapper
+
+(autoload 'mailcrypt-decrypt "mailcrypt")
+(autoload 'mailcrypt-verify "mailcrypt")
+(autoload 'mc-pgp-always-sign "mailcrypt")
+(autoload 'mc-encrypt-generic "mc-toplev")
+(autoload 'mc-cleanup-recipient-headers "mc-toplev")
+(autoload 'mc-sign-generic "mc-toplev")
+
+(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)
+      (unless (setq child (mm-find-part-by-type
+                          (cdr handle)
+                          "application/octet-stream" nil t))
+       (mm-set-handle-multipart-parameter
+        mm-security-handle 'gnus-info "Corrupted")
+       (throw 'error handle))
+      (with-temp-buffer
+       (mm-insert-part child)
+       (setq result
+             (condition-case err
+                 (funcall mml2015-decrypt-function)
+               (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)))
+       (unless (car result)
+         (mm-set-handle-multipart-parameter
+          mm-security-handle 'gnus-info "Failed")
+         (throw 'error handle))
+       (setq handles (mm-dissect-buffer t)))
+      (mm-destroy-parts handle)
+      (mm-set-handle-multipart-parameter
+       mm-security-handle 'gnus-info
+       (concat "OK"
+              (let ((sig (with-current-buffer mml2015-result-buffer
+                           (mml2015-gpg-extract-signature-details))))
+                (concat ", Signer: " sig))))
+      (if (listp (car handles))
+         handles
+       (list handles)))))
+
+(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))
+  (let* ((expired (re-search-forward
+                  "^\\[GNUPG:\\] SIGEXPIRED$"
+                  nil t))
+        (signer (and (re-search-forward
+                      "^\\[GNUPG:\\] GOODSIG \\([0-9A-Za-z]*\\) \\(.*\\)$"
+                      nil t)
+                     (cons (match-string 1) (match-string 2))))
+        (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 trust mml2015-unabbrev-trust-alist))))
+    (cond ((and signer fprint)
+          (concat (cdr signer)
+                  (unless trust-good-enough-p
+                    (concat "\nUntrusted, Fingerprint: "
+                            (mml2015-gpg-pretty-print-fpr fprint)))
+                  (when expired
+                    (format "\nWARNING: Signature from expired key (%s)"
+                            (car signer)))))
+         ((re-search-forward
+           "^\\(gpg: \\)?Good signature from \"\\(.*\\)\"$" nil t)
+          (match-string 2))
+         (t
+          "From unknown user"))))
+
+(defun mml2015-mailcrypt-clear-decrypt ()
+  (let (result)
+    (setq result
+         (condition-case err
+             (funcall mml2015-decrypt-function)
+           (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)))
+    (if (car result)
+       (mm-set-handle-multipart-parameter
+        mm-security-handle 'gnus-info "OK")
+      (mm-set-handle-multipart-parameter
+       mm-security-handle 'gnus-info "Failed"))))
+
+(defun mml2015-fix-micalg (alg)
+  (and 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))))
+
+(defun mml2015-mailcrypt-verify (handle ctl)
+  (catch 'error
+    (let (part)
+      (unless (setq part (mm-find-raw-part-by-type
+                         ctl (or (mm-handle-multipart-ctl-parameter
+                                  ctl 'protocol)
+                                 "application/pgp-signature")
+                         t))
+       (mm-set-handle-multipart-parameter
+        mm-security-handle 'gnus-info "Corrupted")
+       (throw 'error handle))
+      (with-temp-buffer
+       (insert "-----BEGIN PGP SIGNED MESSAGE-----\n")
+       (insert (format "Hash: %s\n\n"
+                       (or (mml2015-fix-micalg
+                            (mm-handle-multipart-ctl-parameter
+                             ctl 'micalg))
+                           "SHA1")))
+       (save-restriction
+         (narrow-to-region (point) (point))
+         (insert part "\n")
+         (goto-char (point-min))
+         (while (not (eobp))
+           (if (looking-at "^-")
+               (insert "- "))
+           (forward-line)))
+       (unless (setq part (mm-find-part-by-type
+                           (cdr handle) "application/pgp-signature" nil t))
+         (mm-set-handle-multipart-parameter
+          mm-security-handle 'gnus-info "Corrupted")
+         (throw 'error handle))
+       (save-restriction
+         (narrow-to-region (point) (point))
+         (mm-insert-part part)
+         (goto-char (point-min))
+         (if (re-search-forward "^-----BEGIN PGP [^-]+-----\r?$" nil t)
+             (replace-match "-----BEGIN PGP SIGNATURE-----" t t))
+         (if (re-search-forward "^-----END PGP [^-]+-----\r?$" nil t)
+             (replace-match "-----END PGP SIGNATURE-----" t t)))
+       (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 ()
+  (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 "Failed")))
+  (mml2015-extract-cleartext-signature))
+
+(defun mml2015-mailcrypt-sign (cont)
+  (mc-sign-generic (message-options-get 'message-sender)
+                  nil nil nil nil)
+  (let ((boundary (mml-compute-boundary cont))
+       hash point)
+    (goto-char (point-min))
+    (unless (re-search-forward "^-----BEGIN PGP SIGNED MESSAGE-----\r?$" nil t)
+      (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"))
+    (setq hash (match-string 1))
+    (unless (re-search-forward "^$" nil t)
+      (error "Cannot not find PGP message"))
+    (forward-line 1)
+    (delete-region (point-min) (point))
+    (insert (format "Content-Type: multipart/signed; boundary=\"%s\";\n"
+                   boundary))
+    (insert (format "\tmicalg=pgp-%s; protocol=\"application/pgp-signature\"\n"
+                   (downcase hash)))
+    (insert (format "\n--%s\n" boundary))
+    (setq point (point))
+    (goto-char (point-max))
+    (unless (re-search-backward "^-----END PGP SIGNATURE-----\r?$" nil t)
+      (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"))
+    (replace-match "-----BEGIN PGP MESSAGE-----" t t)
+    (goto-char (match-beginning 0))
+    (save-restriction
+      (narrow-to-region point (point))
+      (goto-char point)
+      (while (re-search-forward "^- -" nil t)
+       (replace-match "-" t t))
+      (goto-char (point-max)))
+    (insert (format "--%s\n" boundary))
+    (insert "Content-Type: application/pgp-signature\n\n")
+    (goto-char (point-max))
+    (insert (format "--%s--\n" boundary))
+    (goto-char (point-max))))
+
+;; We require mm-decode, which requires mm-bodies, which autoloads
+;; message-options-get (!).
+(declare-function message-options-set "message" (symbol value))
+
+(defun mml2015-mailcrypt-encrypt (cont &optional sign)
+  (let ((mc-pgp-always-sign
+        (or mc-pgp-always-sign
+            sign
+            (eq t (or (message-options-get 'message-sign-encrypt)
+                      (message-options-set
+                       'message-sign-encrypt
+                       (or (y-or-n-p "Sign the message? ")
+                           'not))))
+            'never)))
+    (mm-with-unibyte-current-buffer
+      (mc-encrypt-generic
+       (or (message-options-get 'message-recipients)
+          (message-options-set 'message-recipients
+                             (mc-cleanup-recipient-headers
+                              (read-string "Recipients: "))))
+       nil nil nil
+       (message-options-get 'message-sender))))
+  (goto-char (point-min))
+  (unless (looking-at "-----BEGIN PGP MESSAGE-----")
+    (error "Fail to encrypt the message"))
+  (let ((boundary (mml-compute-boundary cont)))
+    (insert (format "Content-Type: multipart/encrypted; boundary=\"%s\";\n"
+                   boundary))
+    (insert "\tprotocol=\"application/pgp-encrypted\"\n\n")
+    (insert (format "--%s\n" boundary))
+    (insert "Content-Type: application/pgp-encrypted\n\n")
+    (insert "Version: 1\n\n")
+    (insert (format "--%s\n" boundary))
+    (insert "Content-Type: application/octet-stream\n\n")
+    (goto-char (point-max))
+    (insert (format "--%s--\n" boundary))
+    (goto-char (point-max))))
+
+;;; pgg wrapper
+
+(defvar pgg-default-user-id)
+(defvar pgg-errors-buffer)
+(defvar pgg-output-buffer)
+
+(autoload 'pgg-decrypt-region "pgg")
+(autoload 'pgg-verify-region "pgg")
+(autoload 'pgg-sign-region "pgg")
+(autoload 'pgg-encrypt-region "pgg")
+(autoload 'pgg-parse-armor "pgg-parse")
+
+(defun mml2015-pgg-decrypt (handle ctl)
+  (catch 'error
+    (let ((pgg-errors-buffer mml2015-result-buffer)
+         child handles result decrypt-status)
+      (unless (setq child (mm-find-part-by-type
+                          (cdr handle)
+                          "application/octet-stream" nil t))
+       (mm-set-handle-multipart-parameter
+        mm-security-handle 'gnus-info "Corrupted")
+       (throw 'error handle))
+      (with-temp-buffer
+       (mm-insert-part child)
+       (if (condition-case err
+               (prog1
+                   (pgg-decrypt-region (point-min) (point-max))
+                 (setq decrypt-status
+                       (with-current-buffer mml2015-result-buffer
+                         (buffer-string)))
+                 (mm-set-handle-multipart-parameter
+                  mm-security-handle 'gnus-details
+                  decrypt-status))
+             (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))
+           (with-current-buffer pgg-output-buffer
+             (goto-char (point-min))
+             (while (search-forward "\r\n" nil t)
+               (replace-match "\n" t t))
+             (setq handles (mm-dissect-buffer t))
+             (mm-destroy-parts handle)
+             (mm-set-handle-multipart-parameter
+              mm-security-handle 'gnus-info "OK")
+             (mm-set-handle-multipart-parameter
+              mm-security-handle 'gnus-details
+              (concat decrypt-status
+                      (when (stringp (car handles))
+                        "\n" (mm-handle-multipart-ctl-parameter
+                              handles 'gnus-details))))
+             (if (listp (car handles))
+                 handles
+               (list handles)))
+         (mm-set-handle-multipart-parameter
+          mm-security-handle 'gnus-info "Failed")
+         (throw 'error handle))))))
+
+(defun mml2015-pgg-clear-decrypt ()
+  (let ((pgg-errors-buffer mml2015-result-buffer))
+    (if (prog1
+           (pgg-decrypt-region (point-min) (point-max))
+         (mm-set-handle-multipart-parameter
+          mm-security-handle 'gnus-details
+          (with-current-buffer mml2015-result-buffer
+            (buffer-string))))
+       (progn
+         (erase-buffer)
+         ;; Treat data which pgg returns as a unibyte string.
+         (mm-disable-multibyte)
+         (insert-buffer-substring pgg-output-buffer)
+         (goto-char (point-min))
+         (while (search-forward "\r\n" nil t)
+           (replace-match "\n" t t))
+         (mm-set-handle-multipart-parameter
+          mm-security-handle 'gnus-info "OK"))
+      (mm-set-handle-multipart-parameter
+       mm-security-handle 'gnus-info "Failed"))))
+
+(defun mml2015-pgg-verify (handle ctl)
+  (let ((pgg-errors-buffer mml2015-result-buffer)
+       signature-file part signature)
+    (if (or (null (setq part (mm-find-raw-part-by-type
+                             ctl (or (mm-handle-multipart-ctl-parameter
+                                      ctl 'protocol)
+                                     "application/pgp-signature")
+                             t)))
+           (null (setq signature (mm-find-part-by-type
+                                  (cdr handle) "application/pgp-signature" nil t))))
+       (progn
+         (mm-set-handle-multipart-parameter
+          mm-security-handle 'gnus-info "Corrupted")
+         handle)
+      (with-temp-buffer
+       (insert part)
+       ;; Convert <LF> to <CR><LF> in signed text.  If --textmode is
+       ;; specified when signing, the conversion is not necessary.
+       (goto-char (point-min))
+       (end-of-line)
+       (while (not (eobp))
+         (unless (eq (char-before) ?\r)
+           (insert "\r"))
+         (forward-line)
+         (end-of-line))
+       (with-temp-file (setq signature-file (mm-make-temp-file "pgg"))
+         (mm-insert-part signature))
+       (if (condition-case err
+               (prog1
+                   (pgg-verify-region (point-min) (point-max)
+                                      signature-file t)
+                 (goto-char (point-min))
+                 (while (search-forward "\r\n" nil t)
+                   (replace-match "\n" t t))
+                 (mm-set-handle-multipart-parameter
+                  mm-security-handle 'gnus-details
+                  (concat (with-current-buffer pgg-output-buffer
+                            (buffer-string))
+                          (with-current-buffer pgg-errors-buffer
+                            (buffer-string)))))
+             (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))
+           (progn
+             (delete-file signature-file)
+             (mm-set-handle-multipart-parameter
+              mm-security-handle 'gnus-info
+              (with-current-buffer pgg-errors-buffer
+                (mml2015-gpg-extract-signature-details))))
+         (delete-file signature-file)
+         (mm-set-handle-multipart-parameter
+          mm-security-handle 'gnus-info "Failed")))))
+  handle)
+
+(defun mml2015-pgg-clear-verify ()
+  (let ((pgg-errors-buffer mml2015-result-buffer)
+       (text (buffer-string))
+       (coding-system buffer-file-coding-system))
+    (if (condition-case err
+           (prog1
+               (mm-with-unibyte-buffer
+                 (insert (mm-encode-coding-string text coding-system))
+                 (pgg-verify-region (point-min) (point-max) nil t))
+             (goto-char (point-min))
+             (while (search-forward "\r\n" nil t)
+               (replace-match "\n" t t))
+             (mm-set-handle-multipart-parameter
+              mm-security-handle 'gnus-details
+              (concat (with-current-buffer pgg-output-buffer
+                        (buffer-string))
+                      (with-current-buffer pgg-errors-buffer
+                        (buffer-string)))))
+         (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
+        (with-current-buffer pgg-errors-buffer
+          (mml2015-gpg-extract-signature-details)))
+      (mm-set-handle-multipart-parameter
+       mm-security-handle 'gnus-info "Failed")))
+  (mml2015-extract-cleartext-signature))
+
+(defun mml2015-pgg-sign (cont)
+  (let ((pgg-errors-buffer mml2015-result-buffer)
+       (boundary (mml-compute-boundary cont))
+       (pgg-default-user-id (or (message-options-get 'mml-sender)
+                                pgg-default-user-id))
+       (pgg-text-mode t)
+       entry)
+    (unless (pgg-sign-region (point-min) (point-max))
+      (pop-to-buffer mml2015-result-buffer)
+      (error "Sign error"))
+    (goto-char (point-min))
+    (insert (format "Content-Type: multipart/signed; boundary=\"%s\";\n"
+                   boundary))
+    (if (setq entry (assq 2 (pgg-parse-armor
+                            (with-current-buffer pgg-output-buffer
+                              (buffer-string)))))
+       (setq entry (assq 'hash-algorithm (cdr entry))))
+    (insert (format "\tmicalg=%s; "
+                   (if (cdr entry)
+                       (downcase (format "pgp-%s" (cdr entry)))
+                     "pgp-sha1")))
+    (insert "protocol=\"application/pgp-signature\"\n")
+    (insert (format "\n--%s\n" boundary))
+    (goto-char (point-max))
+    (insert (format "\n--%s\n" boundary))
+    (insert "Content-Type: application/pgp-signature\n\n")
+    (insert-buffer-substring pgg-output-buffer)
+    (goto-char (point-max))
+    (insert (format "--%s--\n" boundary))
+    (goto-char (point-max))))
+
+(defun mml2015-pgg-encrypt (cont &optional sign)
+  (let ((pgg-errors-buffer mml2015-result-buffer)
+       (pgg-text-mode t)
+       (boundary (mml-compute-boundary cont)))
+    (unless (pgg-encrypt-region (point-min) (point-max)
+                               (split-string
+                                (or
+                                 (message-options-get 'message-recipients)
+                                 (message-options-set 'message-recipients
+                                                      (read-string "Recipients: ")))
+                                "[ \f\t\n\r\v,]+")
+                               sign)
+      (pop-to-buffer mml2015-result-buffer)
+      (error "Encrypt error"))
+    (delete-region (point-min) (point-max))
+    (goto-char (point-min))
+    (insert (format "Content-Type: multipart/encrypted; boundary=\"%s\";\n"
+                   boundary))
+    (insert "\tprotocol=\"application/pgp-encrypted\"\n\n")
+    (insert (format "--%s\n" boundary))
+    (insert "Content-Type: application/pgp-encrypted\n\n")
+    (insert "Version: 1\n\n")
+    (insert (format "--%s\n" boundary))
+    (insert "Content-Type: application/octet-stream\n\n")
+    (insert-buffer-substring pgg-output-buffer)
+    (goto-char (point-max))
+    (insert (format "--%s--\n" boundary))
+    (goto-char (point-max))))
+
+;;; epg wrapper
+
+(defvar epg-user-id-alist)
+(defvar epg-digest-algorithm-alist)
+(defvar epg-gpg-program)
+(defvar inhibit-redisplay)
+
+(autoload 'epg-make-context "epg")
+(autoload 'epg-context-set-armor "epg")
+(autoload 'epg-context-set-textmode "epg")
+(autoload 'epg-context-set-signers "epg")
+(autoload 'epg-context-result-for "epg")
+(autoload 'epg-new-signature-digest-algorithm "epg")
+(autoload 'epg-list-keys "epg")
+(autoload 'epg-decrypt-string "epg")
+(autoload 'epg-verify-string "epg")
+(autoload 'epg-sign-string "epg")
+(autoload 'epg-encrypt-string "epg")
+(autoload 'epg-passphrase-callback-function "epg")
+(autoload 'epg-context-set-passphrase-callback "epg")
+(autoload 'epg-key-sub-key-list "epg")
+(autoload 'epg-sub-key-capability "epg")
+(autoload 'epg-sub-key-validity "epg")
+(autoload 'epg-sub-key-fingerprint "epg")
+(autoload 'epg-signature-key-id "epg")
+(autoload 'epg-signature-to-string "epg")
+(autoload 'epg-key-user-id-list "epg")
+(autoload 'epg-user-id-string "epg")
+(autoload 'epg-user-id-validity "epg")
+(autoload 'epg-configuration "epg-config")
+(autoload 'epg-expand-group "epg-config")
+(autoload 'epa-select-keys "epa")
+
+(autoload 'gnus-create-image "gnus-ems")
+
+(defun mml2015-epg-key-image (key-id)
+  "Return the image of a key, if any"
+  (with-temp-buffer
+    (mm-set-buffer-multibyte nil)
+    (let* ((coding-system-for-write 'binary)
+           (coding-system-for-read 'binary)
+           (data (shell-command-to-string
+                  (format "%s --list-options no-show-photos --attribute-fd 3 --list-keys %s 3>&1 >/dev/null 2>&1"
+                          (shell-quote-argument epg-gpg-program) key-id))))
+      (when (> (length data) 0)
+        (insert (substring data 16))
+       (condition-case nil
+           (gnus-create-image (buffer-string) nil t)
+         (error))))))
+
+(autoload 'gnus-rescale-image "gnus-util")
+
+(defun mml2015-epg-key-image-to-string (key-id)
+  "Return a string with the image of a key, if any"
+  (let ((key-image (mml2015-epg-key-image key-id)))
+    (if (not key-image)
+       ""
+      (condition-case error
+         (let ((result "  "))
+           (put-text-property
+            1 2 'display
+            (gnus-rescale-image key-image
+                                (cons mml2015-maximum-key-image-dimension
+                                      mml2015-maximum-key-image-dimension))
+            result)
+           result)
+       (error "")))))
+
+(defun mml2015-epg-signature-to-string (signature)
+  (concat (epg-signature-to-string signature)
+          (when mml2015-display-key-image
+            (mml2015-epg-key-image-to-string (epg-signature-key-id signature)))))
+
+(defun mml2015-epg-verify-result-to-string (verify-result)
+  (mapconcat #'mml2015-epg-signature-to-string verify-result "\n"))
+
+(defun mml2015-epg-decrypt (handle ctl)
+  (catch 'error
+    (let ((inhibit-redisplay t)
+         context plain child handles result decrypt-status)
+      (unless (setq child (mm-find-part-by-type
+                          (cdr handle)
+                          "application/octet-stream" nil t))
+       (mm-set-handle-multipart-parameter
+        mm-security-handle 'gnus-info "Corrupted")
+       (throw 'error handle))
+      (setq context (epg-make-context))
+      (if (or mml2015-cache-passphrase mml-secure-cache-passphrase)
+         (epg-context-set-passphrase-callback
+          context
+          (cons 'mml-secure-passphrase-callback 'OpenPGP)))
+      (condition-case error
+         (setq plain (epg-decrypt-string context (mm-get-part child))
+               mml-secure-secret-key-id-list nil)
+       (error
+        (mml-secure-clear-secret-key-id-list)
+        (mm-set-handle-multipart-parameter
+         mm-security-handle 'gnus-info "Failed")
+        (if (eq (car error) 'quit)
+            (mm-set-handle-multipart-parameter
+             mm-security-handle 'gnus-details "Quit.")
+          (mm-set-handle-multipart-parameter
+           mm-security-handle 'gnus-details (mml2015-format-error error)))
+        (throw 'error handle)))
+      (with-temp-buffer
+       (insert plain)
+       (goto-char (point-min))
+       (while (search-forward "\r\n" nil t)
+         (replace-match "\n" t t))
+       (setq handles (mm-dissect-buffer t))
+       (mm-destroy-parts handle)
+       (if (epg-context-result-for context 'verify)
+           (mm-set-handle-multipart-parameter
+            mm-security-handle 'gnus-info
+            (concat "OK\n"
+                    (mml2015-epg-verify-result-to-string
+                     (epg-context-result-for context 'verify))))
+         (mm-set-handle-multipart-parameter
+          mm-security-handle 'gnus-info "OK"))
+       (if (stringp (car handles))
+           (mm-set-handle-multipart-parameter
+            mm-security-handle 'gnus-details
+            (mm-handle-multipart-ctl-parameter handles 'gnus-details))))
+       (if (listp (car handles))
+           handles
+         (list handles)))))
+
+(defun mml2015-epg-clear-decrypt ()
+  (let ((inhibit-redisplay t)
+       (context (epg-make-context))
+       plain)
+    (if (or mml2015-cache-passphrase mml-secure-cache-passphrase)
+       (epg-context-set-passphrase-callback
+        context
+        (cons 'mml-secure-passphrase-callback 'OpenPGP)))
+    (condition-case error
+       (setq plain (epg-decrypt-string context (buffer-string))
+             mml-secure-secret-key-id-list nil)
+      (error
+       (mml-secure-clear-secret-key-id-list)
+       (mm-set-handle-multipart-parameter
+       mm-security-handle 'gnus-info "Failed")
+       (if (eq (car error) 'quit)
+          (mm-set-handle-multipart-parameter
+           mm-security-handle 'gnus-details "Quit.")
+        (mm-set-handle-multipart-parameter
+         mm-security-handle 'gnus-details (mml2015-format-error error)))))
+    (when plain
+      (erase-buffer)
+      ;; Treat data which epg returns as a unibyte string.
+      (mm-disable-multibyte)
+      (insert plain)
+      (goto-char (point-min))
+      (while (search-forward "\r\n" nil t)
+       (replace-match "\n" t t))
+      (mm-set-handle-multipart-parameter
+       mm-security-handle 'gnus-info "OK")
+      (if (epg-context-result-for context 'verify)
+         (mm-set-handle-multipart-parameter
+          mm-security-handle 'gnus-details
+          (mml2015-epg-verify-result-to-string
+           (epg-context-result-for context 'verify)))))))
+
+(defun mml2015-epg-verify (handle ctl)
+  (catch 'error
+    (let ((inhibit-redisplay t)
+         context plain signature-file part signature)
+      (when (or (null (setq part (mm-find-raw-part-by-type
+                                 ctl (or (mm-handle-multipart-ctl-parameter
+                                          ctl 'protocol)
+                                         "application/pgp-signature")
+                                 t)))
+               (null (setq signature (mm-find-part-by-type
+                                      (cdr handle) "application/pgp-signature"
+                                      nil t))))
+       (mm-set-handle-multipart-parameter
+        mm-security-handle 'gnus-info "Corrupted")
+       (throw 'error handle))
+      (setq part (mm-replace-in-string part "\n" "\r\n")
+           signature (mm-get-part signature)
+           context (epg-make-context))
+      (condition-case error
+         (setq plain (epg-verify-string context signature part))
+       (error
+        (mm-set-handle-multipart-parameter
+         mm-security-handle 'gnus-info "Failed")
+        (if (eq (car error) 'quit)
+            (mm-set-handle-multipart-parameter
+             mm-security-handle 'gnus-details "Quit.")
+          (mm-set-handle-multipart-parameter
+           mm-security-handle 'gnus-details (mml2015-format-error error)))
+        (throw 'error handle)))
+      (mm-set-handle-multipart-parameter
+       mm-security-handle 'gnus-info
+       (mml2015-epg-verify-result-to-string
+       (epg-context-result-for context 'verify)))
+      handle)))
+
+(defun mml2015-epg-clear-verify ()
+  (let ((inhibit-redisplay t)
+       (context (epg-make-context))
+       (signature (mm-encode-coding-string (buffer-string)
+                                           coding-system-for-write))
+       plain)
+    (condition-case error
+       (setq plain (epg-verify-string context signature))
+      (error
+       (mm-set-handle-multipart-parameter
+       mm-security-handle 'gnus-info "Failed")
+       (if (eq (car error) 'quit)
+          (mm-set-handle-multipart-parameter
+           mm-security-handle 'gnus-details "Quit.")
+        (mm-set-handle-multipart-parameter
+         mm-security-handle 'gnus-details (mml2015-format-error error)))))
+    (if plain
+       (progn
+         (mm-set-handle-multipart-parameter
+          mm-security-handle 'gnus-info
+          (mml2015-epg-verify-result-to-string
+           (epg-context-result-for context 'verify)))
+         (delete-region (point-min) (point-max))
+         (insert (mm-decode-coding-string plain coding-system-for-read)))
+      (mml2015-extract-cleartext-signature))))
+
+(defun mml2015-epg-sign (cont)
+  (let ((inhibit-redisplay t)
+       (boundary (mml-compute-boundary cont)))
+    ;; Signed data must end with a newline (RFC 3156, 5).
+    (goto-char (point-max))
+    (unless (bolp)
+      (insert "\n"))
+    (let* ((pair (mml-secure-epg-sign 'OpenPGP t))
+          (signature (car pair))
+          (micalg (cdr pair)))
+      (goto-char (point-min))
+      (insert (format "Content-Type: multipart/signed; boundary=\"%s\";\n"
+                     boundary))
+      (if micalg
+         (insert (format "\tmicalg=pgp-%s; "
+                         (downcase
+                          (cdr (assq micalg
+                                     epg-digest-algorithm-alist))))))
+      (insert "protocol=\"application/pgp-signature\"\n")
+      (insert (format "\n--%s\n" boundary))
+      (goto-char (point-max))
+      (insert (format "\n--%s\n" boundary))
+      (insert "Content-Type: application/pgp-signature; name=\"signature.asc\"\n\n")
+      (insert signature)
+      (goto-char (point-max))
+      (insert (format "--%s--\n" boundary))
+      (goto-char (point-max)))))
+
+(defun mml2015-epg-encrypt (cont &optional sign)
+  (let* ((inhibit-redisplay t)
+        (boundary (mml-compute-boundary cont))
+        (cipher (mml-secure-epg-encrypt 'OpenPGP cont sign)))
+    (delete-region (point-min) (point-max))
+    (goto-char (point-min))
+    (insert (format "Content-Type: multipart/encrypted; boundary=\"%s\";\n"
+                   boundary))
+    (insert "\tprotocol=\"application/pgp-encrypted\"\n\n")
+    (insert (format "--%s\n" boundary))
+    (insert "Content-Type: application/pgp-encrypted\n\n")
+    (insert "Version: 1\n\n")
+    (insert (format "--%s\n" boundary))
+    (insert "Content-Type: application/octet-stream\n\n")
+    (insert cipher)
+    (goto-char (point-max))
+    (insert (format "--%s--\n" boundary))
+    (goto-char (point-max))))
+
+;;; General wrapper
+
+(autoload 'gnus-buffer-live-p "gnus-util")
+(autoload 'gnus-get-buffer-create "gnus")
+
+(defun mml2015-clean-buffer ()
+  (if (gnus-buffer-live-p mml2015-result-buffer)
+      (with-current-buffer mml2015-result-buffer
+       (erase-buffer)
+       t)
+    (setq mml2015-result-buffer
+         (gnus-get-buffer-create " *MML2015 Result*"))
+    nil))
+
+(defsubst mml2015-clear-decrypt-function ()
+  (nth 6 (assq mml2015-use mml2015-function-alist)))
+
+(defsubst mml2015-clear-verify-function ()
+  (nth 5 (assq mml2015-use mml2015-function-alist)))
+
+;;;###autoload
+(defun mml2015-decrypt (handle ctl)
+  (mml2015-clean-buffer)
+  (let ((func (nth 4 (assq mml2015-use mml2015-function-alist))))
+    (if func
+       (funcall func handle ctl)
+      handle)))
+
+;;;###autoload
+(defun mml2015-decrypt-test (handle ctl)
+  mml2015-use)
+
+;;;###autoload
+(defun mml2015-verify (handle ctl)
+  (mml2015-clean-buffer)
+  (let ((func (nth 3 (assq mml2015-use mml2015-function-alist))))
+    (if func
+       (funcall func handle ctl)
+      handle)))
+
+;;;###autoload
+(defun mml2015-verify-test (handle ctl)
+  mml2015-use)
+
+;;;###autoload
+(defun mml2015-encrypt (cont &optional sign)
+  (mml2015-clean-buffer)
+  (let ((func (nth 2 (assq mml2015-use mml2015-function-alist))))
+    (if func
+       (funcall func cont sign)
+      (error "Cannot find encrypt function"))))
+
+;;;###autoload
+(defun mml2015-sign (cont)
+  (mml2015-clean-buffer)
+  (let ((func (nth 1 (assq mml2015-use mml2015-function-alist))))
+    (if func
+       (funcall func cont)
+      (error "Cannot find sign function"))))
+
+;;;###autoload
+(defun mml2015-self-encrypt ()
+  (mml2015-encrypt nil))
+
+(provide 'mml2015)
+
+;;; mml2015.el ends here
diff --git a/xemacs-packages/gnus/lisp/netrc.el b/xemacs-packages/gnus/lisp/netrc.el
new file mode 100644 (file)
index 0000000..274a038
--- /dev/null
@@ -0,0 +1,236 @@
+;;; netrc.el --- .netrc parsing functionality
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: news
+;;
+;;  Modularized by Ted Zlatanov <tzz@lifelogs.com>
+;;  when it was part of Gnus.
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Just the .netrc parsing functionality, abstracted so other packages
+;; besides Gnus can use it.
+
+;;; Code:
+
+;;;
+;;; .netrc and .authinfo rc parsing
+;;;
+
+(defgroup netrc nil
+ "Netrc configuration."
+ :group 'comm)
+
+(defcustom netrc-file "~/.authinfo"
+  "File where user credentials are stored."
+  :version "24.1"
+  :type 'file
+  :group 'netrc)
+
+(defvar netrc-services-file "/etc/services"
+  "The name of the services file.")
+
+(defvar netrc-cache nil)
+
+(defun netrc-parse (&optional file)
+  (interactive "fFile to Parse: ")
+  "Parse FILE and return a list of all entries in the file."
+  (unless file
+    (setq file netrc-file))
+  (if (listp file)
+      ;; We got already parsed contents; just return it.
+      file
+    (when (file-exists-p file)
+      (with-temp-buffer
+       (let ((tokens '("machine" "default" "login"
+                       "password" "account" "macdef" "force"
+                       "port"))
+             alist elem result pair)
+          (if (and netrc-cache
+                  (equal (car netrc-cache) (nth 5 (file-attributes file))))
+             (insert (base64-decode-string (rot13-string (cdr netrc-cache))))
+           (insert-file-contents file)
+           (when (string-match "\\.gpg\\'" file)
+             ;; Store the contents of the file heavily encrypted in memory.
+             (setq netrc-cache (cons (nth 5 (file-attributes file))
+                                     (rot13-string
+                                      (base64-encode-string
+                                       (buffer-string)))))))
+         (goto-char (point-min))
+         ;; Go through the file, line by line.
+         (while (not (eobp))
+           (narrow-to-region (point) (point-at-eol))
+           ;; For each line, get the tokens and values.
+           (while (not (eobp))
+             (skip-chars-forward "\t ")
+             ;; Skip lines that begin with a "#".
+             (if (eq (char-after) ?#)
+                 (goto-char (point-max))
+               (unless (eobp)
+                 (setq elem
+                       (if (= (following-char) ?\")
+                           (read (current-buffer))
+                         (buffer-substring
+                          (point) (progn (skip-chars-forward "^\t ")
+                                         (point)))))
+                 (cond
+                  ((equal elem "macdef")
+                   ;; We skip past the macro definition.
+                   (widen)
+                   (while (and (zerop (forward-line 1))
+                               (looking-at "$")))
+                   (narrow-to-region (point) (point)))
+                  ((member elem tokens)
+                   ;; Tokens that don't have a following value are ignored,
+                   ;; except "default".
+                   (when (and pair (or (cdr pair)
+                                       (equal (car pair) "default")))
+                     (push pair alist))
+                   (setq pair (list elem)))
+                  (t
+                   ;; Values that haven't got a preceding token are ignored.
+                   (when pair
+                     (setcdr pair elem)
+                     (push pair alist)
+                     (setq pair nil)))))))
+           (when alist
+             (push (nreverse alist) result))
+           (setq alist nil
+                 pair nil)
+           (widen)
+           (forward-line 1))
+         (nreverse result))))))
+
+(defun netrc-machine (list machine &optional port defaultport)
+  "Return the netrc values from LIST for MACHINE or for the default entry.
+If PORT specified, only return entries with matching port tokens.
+Entries without port tokens default to DEFAULTPORT."
+  (let ((rest list)
+       result)
+    (while list
+      (when (equal (cdr (assoc "machine" (car list))) machine)
+       (push (car list) result))
+      (pop list))
+    (unless result
+      ;; No machine name matches, so we look for default entries.
+      (while rest
+       (when (assoc "default" (car rest))
+         (let ((elem (car rest)))
+           (setq elem (delete (assoc "default" elem) elem))
+           (push elem result)))
+       (pop rest)))
+    (when result
+      (setq result (nreverse result))
+      (if (not port)
+         (car result)
+       (while (and result
+                   (not (netrc-port-equal
+                         (or port defaultport "nntp")
+                         ;; when port is not given in the netrc file,
+                         ;; it should mean "any port"
+                         (or (netrc-get (car result) "port")
+                             defaultport port))))
+         (pop result))
+       (car result)))))
+
+(defun netrc-machine-user-or-password (mode authinfo-file-or-list machines ports defaults)
+  "Get the user name or password according to MODE from AUTHINFO-FILE-OR-LIST.
+Matches a machine from MACHINES and a port from PORTS, giving
+default ports DEFAULTS to `netrc-machine'.
+
+MODE can be \"login\" or \"password\", suitable for passing to
+`netrc-get'."
+  (let ((authinfo-list (if (stringp authinfo-file-or-list)
+                          (netrc-parse authinfo-file-or-list)
+                        authinfo-file-or-list))
+       (ports (or ports '(nil)))
+       (defaults (or defaults '(nil)))
+       info)
+    (if (listp mode)
+       (setq info
+             (mapcar
+              (lambda (mode-element)
+                (netrc-machine-user-or-password
+                 mode-element
+                 authinfo-list
+                 machines
+                 ports
+                 defaults))
+              mode))
+      (dolist (machine machines)
+       (dolist (default defaults)
+         (dolist (port ports)
+           (let ((alist (netrc-machine authinfo-list machine port default)))
+             (setq info (or (netrc-get alist mode) info)))))))
+    info))
+
+(defun netrc-get (alist type)
+  "Return the value of token TYPE from ALIST."
+  (cdr (assoc type alist)))
+
+(defun netrc-port-equal (port1 port2)
+  (when (numberp port1)
+    (setq port1 (or (netrc-find-service-name port1) port1)))
+  (when (numberp port2)
+    (setq port2 (or (netrc-find-service-name port2) port2)))
+  (equal port1 port2))
+
+(defun netrc-parse-services ()
+  (when (file-exists-p netrc-services-file)
+    (let ((services nil))
+      (with-temp-buffer
+       (insert-file-contents netrc-services-file)
+       (while (search-forward "#" nil t)
+         (delete-region (1- (point)) (point-at-eol)))
+       (goto-char (point-min))
+       (while (re-search-forward
+               "^ *\\([^ \n\t]+\\)[ \t]+\\([0-9]+\\)/\\([^ \t\n]+\\)" nil t)
+         (push (list (match-string 1) (string-to-number (match-string 2))
+                     (intern (downcase (match-string 3))))
+               services))
+       (nreverse services)))))
+
+(defun netrc-find-service-name (number &optional type)
+  (let ((services (netrc-parse-services))
+       service)
+    (setq type (or type 'tcp))
+    (while (and (setq service (pop services))
+               (not (and (= number (cadr service))
+                         (eq type (car (cddr service)))))))
+    (car service)))
+
+;;;###autoload
+(defun netrc-credentials (machine &rest ports)
+  "Return a user name/password pair.
+Port specifications will be prioritized in the order they are
+listed in the PORTS list."
+  (let ((list (netrc-parse))
+       found)
+    (if (not ports)
+       (setq found (netrc-machine list machine))
+      (while (and ports
+                 (not found))
+       (setq found (netrc-machine list machine (pop ports)))))
+    (when found
+      (list (cdr (assoc "login" found))
+           (cdr (assoc "password" found))))))
+
+(provide 'netrc)
+
+;;; netrc.el ends here
diff --git a/xemacs-packages/gnus/lisp/nnagent.el b/xemacs-packages/gnus/lisp/nnagent.el
new file mode 100644 (file)
index 0000000..c303bd8
--- /dev/null
@@ -0,0 +1,266 @@
+;;; nnagent.el --- offline backend for Gnus
+
+;; Copyright (C) 1997-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: news, mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'nnheader)
+(require 'nnoo)
+(eval-when-compile (require 'cl))
+(require 'gnus-agent)
+(require 'nnml)
+
+(nnoo-declare nnagent
+  nnml)
+
+\f
+
+(defconst nnagent-version "nnagent 1.0")
+
+(defvoo nnagent-directory nil
+  "Internal variable."
+  nnml-directory)
+
+(defvoo nnagent-active-file nil
+  "Internal variable."
+  nnml-active-file)
+
+(defvoo nnagent-newsgroups-file nil
+  "Internal variable."
+  nnml-newsgroups-file)
+
+(defvoo nnagent-get-new-mail nil
+  "Internal variable."
+  nnml-get-new-mail)
+
+;;; Interface functions.
+
+(nnoo-define-basics nnagent)
+
+(defun nnagent-server (server)
+  (and server (format "%s+%s" (car gnus-command-method) server)))
+
+(deffoo nnagent-open-server (server &optional defs)
+  (setq defs
+       `((nnagent-directory ,(gnus-agent-directory))
+         (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
+                     (nnagent-server server)
+                     defs)
+  (let ((dir (gnus-agent-directory))
+       err)
+    (cond
+     ((not (condition-case arg
+              (file-exists-p dir)
+            (ftp-error (setq err (format "%s" arg)))))
+      (nnagent-close-server)
+      (nnheader-report
+       'nnagent (or err
+                   (format "No such file or directory: %s" dir))))
+     ((not (file-directory-p (file-truename dir)))
+      (nnagent-close-server)
+      (nnheader-report 'nnagent "Not a directory: %s" dir))
+     (t
+      (nnheader-report 'nnagent "Opened server %s using directory %s"
+                      server dir)
+      t))))
+
+(deffoo nnagent-retrieve-groups (groups &optional server)
+  (save-excursion
+    (cond
+     ((file-exists-p (gnus-agent-lib-file "groups"))
+      (nnmail-find-file (gnus-agent-lib-file "groups"))
+      'groups)
+     ((file-exists-p (gnus-agent-lib-file "active"))
+      (nnmail-find-file (gnus-agent-lib-file "active"))
+      'active)
+     (t nil))))
+
+(defun nnagent-request-type (group article)
+  (unless (stringp article)
+    (let ((gnus-agent nil))
+      (if (not (gnus-check-backend-function
+               'request-type (car gnus-command-method)))
+         'unknown
+       (funcall (gnus-get-function gnus-command-method 'request-type)
+                (gnus-group-real-name group) article)))))
+
+(deffoo nnagent-request-newgroups (date server)
+  nil)
+
+(deffoo nnagent-request-update-info (group info &optional server)
+  nil)
+
+(deffoo nnagent-request-post (&optional server)
+  (gnus-agent-insert-meta-information 'news gnus-command-method)
+  (gnus-request-accept-article "nndraft:queue" nil t t))
+
+(deffoo nnagent-request-set-mark (group action server)
+  (mm-with-unibyte-buffer
+    (insert "(gnus-agent-synchronize-group-flags \""
+           group
+           "\" '")
+    (gnus-pp action)
+    (insert " \""
+           (gnus-method-to-server gnus-command-method)
+           "\"")
+    (insert ")\n")
+    (let ((coding-system-for-write nnheader-file-coding-system))
+      (write-region (point-min) (point-max) (gnus-agent-lib-file "flags")
+                   t 'silent)))
+  ;; Also set the marks for the original back end that keeps marks in
+  ;; the local system.
+  (let ((gnus-agent nil))
+    (when (and (memq (car gnus-command-method) '(nntp))
+              (gnus-check-backend-function 'request-set-mark
+                                           (car gnus-command-method)))
+      (funcall (gnus-get-function gnus-command-method 'request-set-mark)
+              group action server)))
+  nil)
+
+(deffoo nnagent-retrieve-headers (articles &optional group server fetch-old)
+  (let ((file (gnus-agent-article-name ".overview" group))
+       arts n first)
+    (save-excursion
+      (gnus-agent-load-alist group)
+      (setq arts (gnus-sorted-difference
+                 articles (mapcar 'car gnus-agent-article-alist)))
+      ;; Assume that articles with smaller numbers than the first one
+      ;; Agent knows are gone.
+      (setq first (caar gnus-agent-article-alist))
+      (when first
+       (while (and arts (< (car arts) first))
+         (pop arts)))
+      (set-buffer nntp-server-buffer)
+      (erase-buffer)
+      (let ((file-name-coding-system nnmail-pathname-coding-system))
+       (nnheader-insert-nov-file file (car articles)))
+      (goto-char (point-min))
+      (gnus-parse-without-error
+       (while (and arts (not (eobp)))
+         (setq n (read (current-buffer)))
+         (when (> n (car arts))
+           (beginning-of-line))
+         (while (and arts (> n (car arts)))
+           (insert (format
+                    "%d\t[Undownloaded article %d]\tGnus Agent\t\t\t\n"
+                    (car arts) (car arts)))
+           (pop arts))
+         (when (and arts (= n (car arts)))
+           (pop arts))
+         (forward-line 1)))
+      (while arts
+       (insert (format
+                "%d\t[Undownloaded article %d]\tGnus Agent\t\t\t\n"
+                (car arts) (car arts)))
+       (pop arts))
+      (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)
+      'nov)))
+
+(deffoo nnagent-request-expire-articles (articles group &optional server force)
+  articles)
+
+(deffoo nnagent-request-group (group &optional server dont-check info)
+  (nnoo-parent-function 'nnagent 'nnml-request-group
+                       (list group (nnagent-server server) dont-check info)))
+
+(deffoo nnagent-close-group (group &optional server)
+  (nnoo-parent-function 'nnagent 'nnml-close-group
+                       (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)))
+
+(deffoo nnagent-request-article (id &optional group server buffer)
+  (nnoo-parent-function 'nnagent 'nnml-request-article
+                       (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)))
+
+(deffoo nnagent-request-delete-group (group &optional force server)
+  (nnoo-parent-function 'nnagent 'nnml-request-delete-group
+                       (list group force (nnagent-server server))))
+
+(deffoo nnagent-request-list (&optional 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))))
+
+(deffoo nnagent-request-move-article
+    (article group server accept-form &optional last move-is-internal)
+  (nnoo-parent-function 'nnagent 'nnml-request-move-article
+                       (list article group (nnagent-server server)
+                             accept-form last move-is-internal)))
+
+(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))))
+
+(deffoo nnagent-request-scan (&optional group server)
+  (nnoo-parent-function 'nnagent 'nnml-request-scan
+                       (list group (nnagent-server server))))
+
+(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))))
+
+(deffoo nnagent-server-opened (&optional server)
+  (nnoo-parent-function 'nnagent 'nnml-server-opened
+                       (list (nnagent-server server))))
+
+(deffoo nnagent-status-message (&optional server)
+  (nnoo-parent-function 'nnagent 'nnml-status-message
+                       (list (nnagent-server server))))
+
+(deffoo nnagent-request-regenerate (server)
+  (nnoo-parent-function 'nnagent 'nnml-request-regenerate
+                       (list (nnagent-server server))))
+
+(deffoo nnagent-retrieve-group-data-early (server infos)
+  nil)
+
+;; Use nnml functions for just about everything.
+(nnoo-import nnagent
+  (nnml))
+
+\f
+;;; Internal functions.
+
+(provide 'nnagent)
+
+;;; nnagent.el ends here
diff --git a/xemacs-packages/gnus/lisp/nnbabyl.el b/xemacs-packages/gnus/lisp/nnbabyl.el
new file mode 100644 (file)
index 0000000..3fb4c2e
--- /dev/null
@@ -0,0 +1,650 @@
+;;; nnbabyl.el --- rmail mbox access for Gnus
+
+;; Copyright (C) 1995-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;;     Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
+;; Keywords: news, mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; For an overview of what the interface functions do, please see the
+;; Gnus sources.
+
+;;; Code:
+
+(require 'nnheader)
+(condition-case nil
+    (require 'rmail)
+  (error (nnheader-message
+      5 "Ignore rmail errors from this file, you don't have rmail")))
+(require 'nnmail)
+(require 'nnoo)
+(eval-when-compile (require 'cl))
+
+(nnoo-declare nnbabyl)
+
+(defvoo nnbabyl-mbox-file (expand-file-name "~/RMAIL")
+  "The name of the rmail box file in the users home directory.")
+
+(defvoo nnbabyl-active-file (expand-file-name "~/.rmail-active")
+  "The name of the active file for the rmail box.")
+
+(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.")
+
+\f
+
+(defvar nnbabyl-mail-delimiter "\^_")
+
+(defconst nnbabyl-version "nnbabyl 1.0"
+  "nnbabyl version.")
+
+(defvoo nnbabyl-mbox-buffer nil)
+(defvoo nnbabyl-current-group nil)
+(defvoo nnbabyl-status-string "")
+(defvoo nnbabyl-group-alist nil)
+(defvoo nnbabyl-active-timestamp nil)
+
+(defvoo nnbabyl-previous-buffer-mode nil)
+
+\f
+
+;;; Interface functions
+
+(nnoo-define-basics nnbabyl)
+
+(deffoo nnbabyl-retrieve-headers (articles &optional group server fetch-old)
+  (with-current-buffer nntp-server-buffer
+    (erase-buffer)
+    (let ((number (length articles))
+         (count 0)
+         (delim (concat "^" nnbabyl-mail-delimiter))
+         article art-string start stop)
+      (nnbabyl-possibly-change-newsgroup group server)
+      (while (setq article (pop articles))
+       (setq art-string (nnbabyl-article-string article))
+       (set-buffer nnbabyl-mbox-buffer)
+       (end-of-line)
+       (when (or (search-forward art-string nil t)
+                 (search-backward art-string nil t))
+         (unless (re-search-backward delim nil t)
+           (goto-char (point-min)))
+         (while (and (not (looking-at ".+:"))
+                     (zerop (forward-line 1))))
+         (setq start (point))
+         (search-forward "\n\n" nil t)
+         (setq stop (1- (point)))
+         (set-buffer nntp-server-buffer)
+         (insert "221 ")
+         (princ article (current-buffer))
+         (insert " Article retrieved.\n")
+         (insert-buffer-substring nnbabyl-mbox-buffer start stop)
+         (goto-char (point-max))
+         (insert ".\n"))
+       (and (numberp nnmail-large-newsgroup)
+            (> number nnmail-large-newsgroup)
+            (zerop (% (incf count) 20))
+            (nnheader-message 5 "nnbabyl: Receiving headers... %d%%"
+                              (floor (* count 100.0) number))))
+
+      (and (numberp nnmail-large-newsgroup)
+          (> number nnmail-large-newsgroup)
+          (nnheader-message 5 "nnbabyl: Receiving headers...done"))
+
+      (set-buffer nntp-server-buffer)
+      (nnheader-fold-continuation-lines)
+      'headers)))
+
+(deffoo nnbabyl-open-server (server &optional defs)
+  (nnoo-change-server 'nnbabyl server defs)
+  (nnbabyl-create-mbox)
+  (cond
+   ((not (file-exists-p nnbabyl-mbox-file))
+    (nnbabyl-close-server)
+    (nnheader-report 'nnbabyl "No such file: %s" nnbabyl-mbox-file))
+   ((file-directory-p nnbabyl-mbox-file)
+    (nnbabyl-close-server)
+    (nnheader-report 'nnbabyl "Not a regular file: %s" nnbabyl-mbox-file))
+   (t
+    (nnheader-report 'nnbabyl "Opened server %s using mbox %s" server
+                    nnbabyl-mbox-file)
+    t)))
+
+(deffoo nnbabyl-close-server (&optional server)
+  ;; Restore buffer mode.
+  (when (and (nnbabyl-server-opened)
+            nnbabyl-previous-buffer-mode)
+    (with-current-buffer nnbabyl-mbox-buffer
+      (narrow-to-region
+       (caar nnbabyl-previous-buffer-mode)
+       (cdar nnbabyl-previous-buffer-mode))
+      (funcall (cdr nnbabyl-previous-buffer-mode))))
+  (nnoo-close-server 'nnbabyl server)
+  (setq nnbabyl-mbox-buffer nil)
+  t)
+
+(deffoo nnbabyl-server-opened (&optional server)
+  (and (nnoo-current-server-p 'nnbabyl server)
+       nnbabyl-mbox-buffer
+       (buffer-name nnbabyl-mbox-buffer)
+       nntp-server-buffer
+       (buffer-name nntp-server-buffer)))
+
+(deffoo nnbabyl-request-article (article &optional newsgroup server buffer)
+  (nnbabyl-possibly-change-newsgroup newsgroup server)
+  (with-current-buffer nnbabyl-mbox-buffer
+    (goto-char (point-min))
+    (when (search-forward (nnbabyl-article-string article) nil t)
+      (let (start stop summary-line)
+       (unless (re-search-backward (concat "^" nnbabyl-mail-delimiter) nil t)
+         (goto-char (point-min))
+         (end-of-line))
+       (while (and (not (looking-at ".+:"))
+                   (zerop (forward-line 1))))
+       (setq start (point))
+       (or (when (re-search-forward
+                  (concat "^" nnbabyl-mail-delimiter) nil t)
+             (beginning-of-line)
+             t)
+           (goto-char (point-max)))
+       (setq stop (point))
+       (let ((nntp-server-buffer (or buffer nntp-server-buffer)))
+         (set-buffer nntp-server-buffer)
+         (erase-buffer)
+         (insert-buffer-substring nnbabyl-mbox-buffer start stop)
+         (goto-char (point-min))
+         ;; If there is an EOOH header, then we have to remove some
+         ;; duplicated headers.
+         (setq summary-line (looking-at "Summary-line:"))
+         (when (search-forward "\n*** EOOH ***" nil t)
+           (if summary-line
+               ;; The headers to be deleted are located before the
+               ;; EOOH line...
+               (delete-region (point-min) (progn (forward-line 1)
+                                                 (point)))
+             ;; ...or after.
+             (delete-region (progn (beginning-of-line) (point))
+                            (or (search-forward "\n\n" nil t)
+                                (point)))))
+         (if (numberp article)
+             (cons nnbabyl-current-group article)
+           (nnbabyl-article-group-number)))))))
+
+(deffoo nnbabyl-request-group (group &optional server dont-check info)
+  (let ((active (cadr (assoc group nnbabyl-group-alist))))
+    (save-excursion
+      (cond
+       ((or (null active)
+           (null (nnbabyl-possibly-change-newsgroup group server)))
+       (nnheader-report 'nnbabyl "No such group: %s" group))
+       (dont-check
+       (nnheader-report 'nnbabyl "Selected group %s" group)
+       (nnheader-insert ""))
+       (t
+       (nnheader-report 'nnbabyl "Selected group %s" group)
+       (nnheader-insert "211 %d %d %d %s\n"
+                        (1+ (- (cdr active) (car active)))
+                        (car active) (cdr active) group))))))
+
+(deffoo nnbabyl-request-scan (&optional group server)
+  (nnbabyl-possibly-change-newsgroup group server)
+  (nnbabyl-read-mbox)
+  (nnmail-get-new-mail
+   'nnbabyl
+   (lambda ()
+     (with-current-buffer nnbabyl-mbox-buffer
+       (save-buffer)))
+   (file-name-directory nnbabyl-mbox-file)
+   group
+   (lambda ()
+     (save-excursion
+       (let ((in-buf (current-buffer)))
+        (goto-char (point-min))
+        (while (search-forward "\n\^_\n" nil t)
+          (delete-char -1))
+        (set-buffer nnbabyl-mbox-buffer)
+        (goto-char (point-max))
+        (search-backward "\n\^_" nil t)
+        (goto-char (match-end 0))
+        (insert-buffer-substring in-buf)))
+     (nnmail-save-active nnbabyl-group-alist nnbabyl-active-file))))
+
+(deffoo nnbabyl-close-group (group &optional server)
+  t)
+
+(deffoo nnbabyl-request-create-group (group &optional server args)
+  (nnmail-activate 'nnbabyl)
+  (unless (assoc group nnbabyl-group-alist)
+    (push (list group (cons 1 0))
+         nnbabyl-group-alist)
+    (nnmail-save-active nnbabyl-group-alist nnbabyl-active-file))
+  t)
+
+(deffoo nnbabyl-request-list (&optional server)
+  (save-excursion
+    (nnmail-find-file nnbabyl-active-file)
+    (setq nnbabyl-group-alist (nnmail-get-active))
+    t))
+
+(deffoo nnbabyl-request-newgroups (date &optional server)
+  (nnbabyl-request-list server))
+
+(deffoo nnbabyl-request-list-newsgroups (&optional server)
+  (nnheader-report 'nnbabyl "nnbabyl: LIST NEWSGROUPS is not implemented."))
+
+(deffoo nnbabyl-request-expire-articles
+    (articles newsgroup &optional server force)
+  (nnbabyl-possibly-change-newsgroup newsgroup server)
+  (let* ((is-old t)
+        rest)
+    (nnmail-activate 'nnbabyl)
+
+    (with-current-buffer nnbabyl-mbox-buffer
+      (set-text-properties (point-min) (point-max) nil)
+      (while (and articles is-old)
+       (goto-char (point-min))
+       (when (search-forward (nnbabyl-article-string (car articles)) nil t)
+         (if (setq is-old
+                   (nnmail-expired-article-p
+                    newsgroup
+                    (buffer-substring
+                     (point) (progn (end-of-line) (point))) force))
+             (progn
+               (unless (eq nnmail-expiry-target 'delete)
+                 (with-temp-buffer
+                   (nnbabyl-request-article (car articles)
+                                            newsgroup server
+                                            (current-buffer))
+                   (let ((nnml-current-directory nil))
+                     (nnmail-expiry-target-group
+                      nnmail-expiry-target newsgroup)))
+                 (nnbabyl-possibly-change-newsgroup newsgroup server))
+               (nnheader-message 5 "Deleting article %d in %s..."
+                                 (car articles) newsgroup)
+               (nnbabyl-delete-mail))
+           (push (car articles) rest)))
+       (setq articles (cdr articles)))
+      (save-buffer)
+      ;; Find the lowest active article in this group.
+      (let ((active (nth 1 (assoc newsgroup nnbabyl-group-alist))))
+       (goto-char (point-min))
+       (while (and (not (search-forward
+                         (nnbabyl-article-string (car active)) nil t))
+                   (<= (car active) (cdr active)))
+         (setcar active (1+ (car active)))
+         (goto-char (point-min))))
+      (nnmail-save-active nnbabyl-group-alist nnbabyl-active-file)
+      (nconc rest articles))))
+
+(deffoo nnbabyl-request-move-article
+    (article group server accept-form &optional last move-is-internal)
+  (let ((buf (get-buffer-create " *nnbabyl move*"))
+       result)
+    (and
+     (nnbabyl-request-article article group server)
+     (with-current-buffer buf
+       (insert-buffer-substring nntp-server-buffer)
+       (goto-char (point-min))
+       (while (re-search-forward
+              "^X-Gnus-Newsgroup:"
+              (save-excursion (search-forward "\n\n" nil t) (point)) t)
+        (delete-region (point-at-bol) (progn (forward-line 1) (point))))
+       (setq result (eval accept-form))
+       (kill-buffer (current-buffer))
+       result)
+     (save-excursion
+       (nnbabyl-possibly-change-newsgroup group server)
+       (set-buffer nnbabyl-mbox-buffer)
+       (goto-char (point-min))
+       (if (search-forward (nnbabyl-article-string article) nil t)
+          (nnbabyl-delete-mail))
+       (and last (save-buffer))))
+    result))
+
+(deffoo nnbabyl-request-accept-article (group &optional server last)
+  (nnbabyl-possibly-change-newsgroup group server)
+  (nnmail-check-syntax)
+  (let ((buf (current-buffer))
+       result beg)
+    (and
+     (nnmail-activate 'nnbabyl)
+     (save-excursion
+       (goto-char (point-min))
+       (search-forward "\n\n" nil t)
+       (forward-line -1)
+       (save-excursion
+        (while (re-search-backward "^X-Gnus-Newsgroup: " beg t)
+          (delete-region (point) (progn (forward-line 1) (point)))))
+       (when nnmail-cache-accepted-message-ids
+        (nnmail-cache-insert (nnmail-fetch-field "message-id")
+                             group
+                             (nnmail-fetch-field "subject")
+                             (nnmail-fetch-field "from")))
+       (setq result
+            (if (stringp group)
+                (list (cons group (nnbabyl-active-number group)))
+              (nnmail-article-group 'nnbabyl-active-number)))
+       (if (and (null result)
+               (yes-or-no-p "Moved to `junk' group; delete article? "))
+          (setq result 'junk)
+        (setq result (car (nnbabyl-save-mail result))))
+       (set-buffer nnbabyl-mbox-buffer)
+       (goto-char (point-max))
+       (search-backward "\n\^_")
+       (goto-char (match-end 0))
+       (insert-buffer-substring buf)
+       (when last
+        (when nnmail-cache-accepted-message-ids
+          (nnmail-cache-insert (nnmail-fetch-field "message-id")
+                               group
+                               (nnmail-fetch-field "subject")
+                               (nnmail-fetch-field "from")))
+        (save-buffer)
+        (nnmail-save-active nnbabyl-group-alist nnbabyl-active-file))
+       result))))
+
+(deffoo nnbabyl-request-replace-article (article group buffer)
+  (nnbabyl-possibly-change-newsgroup group)
+  (with-current-buffer nnbabyl-mbox-buffer
+    (goto-char (point-min))
+    (if (not (search-forward (nnbabyl-article-string article) nil t))
+       nil
+      (nnbabyl-delete-mail t t)
+      (insert-buffer-substring buffer)
+      (save-buffer)
+      t)))
+
+(deffoo nnbabyl-request-delete-group (group &optional force server)
+  (nnbabyl-possibly-change-newsgroup group server)
+  ;; Delete all articles in GROUP.
+  (if (not force)
+      ()                               ; Don't delete the articles.
+    (with-current-buffer nnbabyl-mbox-buffer
+      (goto-char (point-min))
+      ;; Delete all articles in this group.
+      (let ((ident (concat "\nX-Gnus-Newsgroup: " nnbabyl-current-group ":"))
+           found)
+       (while (search-forward ident nil t)
+         (setq found t)
+         (nnbabyl-delete-mail))
+       (when found
+         (save-buffer)))))
+  ;; Remove the group from all structures.
+  (setq nnbabyl-group-alist
+       (delq (assoc group nnbabyl-group-alist) nnbabyl-group-alist)
+       nnbabyl-current-group nil)
+  ;; Save the active file.
+  (nnmail-save-active nnbabyl-group-alist nnbabyl-active-file)
+  t)
+
+(deffoo nnbabyl-request-rename-group (group new-name &optional server)
+  (nnbabyl-possibly-change-newsgroup group server)
+  (with-current-buffer nnbabyl-mbox-buffer
+    (goto-char (point-min))
+    (let ((ident (concat "\nX-Gnus-Newsgroup: " nnbabyl-current-group ":"))
+         (new-ident (concat "\nX-Gnus-Newsgroup: " new-name ":"))
+         found)
+      (while (search-forward ident nil t)
+       (replace-match new-ident t t)
+       (setq found t))
+      (when found
+       (save-buffer))))
+  (let ((entry (assoc group nnbabyl-group-alist)))
+    (and entry (setcar entry new-name))
+    (setq nnbabyl-current-group nil)
+    ;; Save the new group alist.
+    (nnmail-save-active nnbabyl-group-alist nnbabyl-active-file)
+    t))
+
+\f
+;;; Internal functions.
+
+;; If FORCE, delete article no matter how many X-Gnus-Newsgroup
+;; headers there are.  If LEAVE-DELIM, don't delete the Unix mbox
+;; delimiter line.
+(defun nnbabyl-delete-mail (&optional force leave-delim)
+  ;; Delete the current X-Gnus-Newsgroup line.
+  (unless force
+    (delete-region (point-at-bol) (progn (forward-line 1) (point))))
+  ;; Beginning of the article.
+  (save-excursion
+    (save-restriction
+      (widen)
+      (narrow-to-region
+       (save-excursion
+        (unless (re-search-backward (concat "^" nnbabyl-mail-delimiter) nil t)
+          (goto-char (point-min))
+          (end-of-line))
+        (if leave-delim (progn (forward-line 1) (point))
+          (match-beginning 0)))
+       (progn
+        (forward-line 1)
+        (or (and (re-search-forward (concat "^" nnbabyl-mail-delimiter)
+                                    nil t)
+                 (match-beginning 0))
+            (point-max))))
+      (goto-char (point-min))
+      ;; Only delete the article if no other groups owns it as well.
+      (when (or force (not (re-search-forward "^X-Gnus-Newsgroup: " nil t)))
+       (delete-region (point-min) (point-max))))))
+
+(defun nnbabyl-possibly-change-newsgroup (newsgroup &optional server)
+  (when (and server
+            (not (nnbabyl-server-opened server)))
+    (nnbabyl-open-server server))
+  (when (or (not nnbabyl-mbox-buffer)
+           (not (buffer-name nnbabyl-mbox-buffer)))
+    (save-excursion (nnbabyl-read-mbox)))
+  (unless nnbabyl-group-alist
+    (nnmail-activate 'nnbabyl))
+  (if newsgroup
+      (if (assoc newsgroup nnbabyl-group-alist)
+         (setq nnbabyl-current-group newsgroup)
+       (nnheader-report 'nnbabyl "No such group in file"))
+    t))
+
+(defun nnbabyl-article-string (article)
+  (if (numberp article)
+      (concat "\nX-Gnus-Newsgroup: " nnbabyl-current-group ":"
+             (int-to-string article) " ")
+    (concat "\nMessage-ID: " article)))
+
+(defun nnbabyl-article-group-number ()
+  (save-excursion
+    (goto-char (point-min))
+    (when (re-search-forward "^X-Gnus-Newsgroup: +\\([^:]+\\):\\([0-9]+\\) "
+                            nil t)
+      (cons (buffer-substring (match-beginning 1) (match-end 1))
+           (string-to-number
+            (buffer-substring (match-beginning 2) (match-end 2)))))))
+
+(defun nnbabyl-insert-lines ()
+  "Insert how many lines and chars there are in the body of the mail."
+  (let (lines chars)
+    (save-excursion
+      (goto-char (point-min))
+      (when (search-forward "\n\n" nil t)
+       ;; There may be an EOOH line here...
+       (when (looking-at "\\*\\*\\* EOOH \\*\\*\\*")
+         (search-forward "\n\n" nil t))
+       (setq chars (- (point-max) (point))
+             lines (max (- (count-lines (point) (point-max)) 1) 0))
+       ;; Move back to the end of the headers.
+       (goto-char (point-min))
+       (search-forward "\n\n" nil t)
+       (forward-char -1)
+       (save-excursion
+         (when (re-search-backward "^Lines: " nil t)
+           (delete-region (point) (progn (forward-line 1) (point)))))
+       (insert (format "Lines: %d\n" lines))
+       chars))))
+
+(defun nnbabyl-save-mail (group-art)
+  ;; Called narrowed to an article.
+  (nnbabyl-insert-lines)
+  (nnmail-insert-xref group-art)
+  (nnbabyl-insert-newsgroup-line group-art)
+  (run-hooks 'nnbabyl-prepare-save-mail-hook)
+  group-art)
+
+(defun nnbabyl-insert-newsgroup-line (group-art)
+  (save-excursion
+    (goto-char (point-min))
+    (while (looking-at "From ")
+      (replace-match "Mail-from: From " t t)
+      (forward-line 1))
+    ;; If there is a C-l at the beginning of the narrowed region, this
+    ;; isn't really a "save", but rather a "scan".
+    (goto-char (point-min))
+    (unless (looking-at "\^L")
+      (save-excursion
+       (insert "\^L\n0, unseen,,\n*** EOOH ***\n")
+       (goto-char (point-max))
+       (insert "\^_\n")))
+    (when (search-forward "\n\n" nil t)
+      (forward-char -1)
+      (while group-art
+       (insert (format "X-Gnus-Newsgroup: %s:%d   %s\n"
+                       (caar group-art) (cdar group-art)
+                       (current-time-string)))
+       (setq group-art (cdr group-art))))
+    t))
+
+(defun nnbabyl-active-number (group)
+  ;; Find the next article number in GROUP.
+  (let ((active (cadr (assoc group nnbabyl-group-alist))))
+    (if active
+       (setcdr active (1+ (cdr active)))
+      ;; This group is new, so we create a new entry for it.
+      ;; This might be a bit naughty... creating groups on the drop of
+      ;; a hat, but I don't know...
+      (push (list group (setq active (cons 1 1)))
+           nnbabyl-group-alist))
+    (cdr active)))
+
+(defun nnbabyl-create-mbox ()
+  (unless (file-exists-p nnbabyl-mbox-file)
+    ;; Create a new, empty RMAIL mbox file.
+    (with-current-buffer (setq nnbabyl-mbox-buffer
+                              (create-file-buffer nnbabyl-mbox-file))
+      (setq buffer-file-name nnbabyl-mbox-file)
+      (insert "BABYL OPTIONS:\n\n\^_")
+      (nnmail-write-region
+       (point-min) (point-max) nnbabyl-mbox-file t 'nomesg))))
+
+(defun nnbabyl-read-mbox ()
+  (nnmail-activate 'nnbabyl)
+  (nnbabyl-create-mbox)
+
+  (unless (and nnbabyl-mbox-buffer
+              (buffer-name nnbabyl-mbox-buffer)
+              (with-current-buffer nnbabyl-mbox-buffer
+                (= (buffer-size) (nnheader-file-size nnbabyl-mbox-file))))
+    ;; This buffer has changed since we read it last.  Possibly.
+    (save-excursion
+      (let ((delim (concat "^" nnbabyl-mail-delimiter))
+           (alist nnbabyl-group-alist)
+           start end number)
+       (set-buffer (setq nnbabyl-mbox-buffer
+                         (nnheader-find-file-noselect
+                          nnbabyl-mbox-file nil t)))
+       ;; Save previous buffer mode.
+       (setq nnbabyl-previous-buffer-mode
+             (cons (cons (point-min) (point-max))
+                   major-mode))
+
+       (buffer-disable-undo)
+       (widen)
+       (setq buffer-read-only nil)
+       (fundamental-mode)
+
+       ;; Go through the group alist and compare against
+       ;; the rmail file.
+       (while alist
+         (goto-char (point-max))
+         (when (and (re-search-backward
+                     (format "^X-Gnus-Newsgroup: %s:\\([0-9]+\\) "
+                             (caar alist))
+                     nil t)
+                    (> (setq number
+                             (string-to-number
+                              (buffer-substring
+                               (match-beginning 1) (match-end 1))))
+                       (cdadar alist)))
+           (setcdr (cadar alist) number))
+         (setq alist (cdr alist)))
+
+       ;; We go through the mbox and make sure that each and
+       ;; every mail belongs to some group or other.
+       (goto-char (point-min))
+       (if (looking-at "\^L")
+           (setq start (point))
+         (re-search-forward delim nil t)
+         (setq start (match-end 0)))
+       (while (re-search-forward delim nil t)
+         (setq end (match-end 0))
+         (unless (search-backward "\nX-Gnus-Newsgroup: " start t)
+           (goto-char end)
+           (save-excursion
+             (save-restriction
+               (narrow-to-region (goto-char start) end)
+               (nnbabyl-save-mail
+                (nnmail-article-group 'nnbabyl-active-number))
+               (setq end (point-max)))))
+         (goto-char (setq start end)))
+       (when (buffer-modified-p (current-buffer))
+         (save-buffer))
+       (nnmail-save-active nnbabyl-group-alist nnbabyl-active-file)))))
+
+(defun nnbabyl-remove-incoming-delims ()
+  (goto-char (point-min))
+  (while (search-forward "\^_" nil t)
+    (replace-match "?" t t)))
+
+(defun nnbabyl-check-mbox ()
+  "Go through the nnbabyl mbox and make sure that no article numbers are reused."
+  (interactive)
+  (let ((idents (make-vector 1000 0))
+       id)
+    (save-excursion
+      (when (or (not nnbabyl-mbox-buffer)
+               (not (buffer-name nnbabyl-mbox-buffer)))
+       (nnbabyl-read-mbox))
+      (set-buffer nnbabyl-mbox-buffer)
+      (goto-char (point-min))
+      (while (re-search-forward "^X-Gnus-Newsgroup: \\([^ ]+\\) "  nil t)
+       (if (intern-soft (setq id (match-string 1)) idents)
+           (progn
+             (delete-region (point-at-bol) (progn (forward-line 1) (point)))
+             (nnheader-message 7 "Moving %s..." id)
+             (nnbabyl-save-mail
+              (nnmail-article-group 'nnbabyl-active-number)))
+         (intern id idents)))
+      (when (buffer-modified-p (current-buffer))
+       (save-buffer))
+      (nnmail-save-active nnbabyl-group-alist nnbabyl-active-file)
+      (nnheader-message 5 ""))))
+
+(provide 'nnbabyl)
+
+;;; nnbabyl.el ends here
diff --git a/xemacs-packages/gnus/lisp/nndiary.el b/xemacs-packages/gnus/lisp/nndiary.el
new file mode 100644 (file)
index 0000000..9245396
--- /dev/null
@@ -0,0 +1,1584 @@
+;;; nndiary.el --- A diary back end for Gnus
+
+;; Copyright (C) 1999-2016 Free Software Foundation, Inc.
+
+;; Author:        Didier Verna <didier@xemacs.org>
+;; Maintainer:    Didier Verna <didier@xemacs.org>
+;; Created:       Fri Jul 16 18:55:42 1999
+;; Keywords:      calendar mail news
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+
+;; Contents management by FCM version 0.1.
+
+;; Description:
+;; ===========
+
+;; nndiary is a mail back end designed to handle mails as diary event
+;; reminders. It is now fully documented in the Gnus manual.
+
+
+;; 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 back end 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 somewhere 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 back ends like this one, nnoo 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 other back ends,
+;;   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
+;;   back end based on another. Lisp is a reflexive language so that's a very
+;;   easy thing to do: inspect the function's form, replace occurrences of
+;;   <nnfrom> (even in strings) with <nnto>, and you're done.
+
+;; * nndiary-get-new-mail, nndiary-mail-source and nndiary-split-methods:
+;;   NNDiary has some experimental parts, in the sense Gnus normally uses only
+;;   one mail back ends for mail retrieval and splitting. This back end is
+;;   also an attempt to make it behave differently. For Gnus developers: 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))))
+
+
+;; Back End behavior customization ===========================================
+
+(defgroup nndiary nil
+  "The Gnus Diary back end."
+  :version "22.1"
+  :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 appointments.
+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
+appointment, 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 appointments of the day each morning at 00:00.
+
+- (1 . day): this means pop up the appointments the day before, at 00:00.
+
+- (6 . hour): for an appointment at 18:30, this would pop up the
+  appointment message at 12:00.
+
+- (360 . minute): for an appointment at 18:30 and 15 seconds, this would
+  pop up the appointment 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)
+
+
+(define-obsolete-variable-alias 'nndiary-request-create-group-hooks
+  'nndiary-request-create-group-functions "24.3")
+(defcustom nndiary-request-create-group-functions nil
+  "*Hook run after `nndiary-request-create-group' is executed.
+The hook functions will be called with the full group name as argument."
+  :group 'nndiary
+  :type 'hook)
+
+(define-obsolete-variable-alias 'nndiary-request-update-info-hooks
+  'nndiary-request-update-info-functions "24.3")
+(defcustom nndiary-request-update-info-functions nil
+  "*Hook run after `nndiary-request-update-info-group' is executed.
+The hook functions will be called with the full group name as argument."
+  :group 'nndiary
+  :type 'hook)
+
+(define-obsolete-variable-alias 'nndiary-request-accept-article-hooks
+  'nndiary-request-accept-article-functions "24.3")
+(defcustom nndiary-request-accept-article-functions nil
+  "*Hook run before accepting an article.
+Executed near the beginning of `nndiary-request-accept-article'.
+The hook functions 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)
+
+
+;; Back End declaration ======================================================
+
+;; Well, most of this is nnml clonage.
+
+(nnoo-declare nndiary)
+
+(defvoo nndiary-directory (nnheader-concat gnus-directory "diary/")
+  "Spool directory for the nndiary back end.")
+
+(defvoo nndiary-active-file
+    (expand-file-name "active" nndiary-directory)
+  "Active file for the nndiary back end.")
+
+(defvoo nndiary-newsgroups-file
+    (expand-file-name "newsgroups" nndiary-directory)
+  "Newsgroups description file for the nndiary back end.")
+
+(defvoo nndiary-get-new-mail nil
+  "Whether nndiary gets new mail and split it.
+Contrary to traditional mail back ends, this variable can be set to t
+even if your primary mail back end also retrieves mail. In such a case,
+NDiary uses its own mail-sources and split-methods.")
+
+(defvoo nndiary-nov-is-evil nil
+  "If non-nil, Gnus will never use nov databases for nndiary groups.
+Using nov databases will speed up header fetching considerably.
+This variable shouldn't be flipped much.  If you have, for some reason,
+set this to t, and want to set it to nil again, you should always run
+the `nndiary-generate-nov-databases' command.  The function will go
+through all nnml directories and generate nov databases for them
+all.  This may very well take some time.")
+
+(defvoo nndiary-prepare-save-mail-hook nil
+  "*Hook run narrowed to an article before saving.")
+
+(defvoo nndiary-inhibit-expiry nil
+  "If non-nil, inhibit expiry.")
+
+\f
+
+(defconst nndiary-version "0.2-b14"
+  "Current Diary back end version.")
+
+(defun nndiary-version ()
+  "Current Diary back end 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 unspecified
+  ;; 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)
+      (error
+       (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)
+    (with-current-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%%"
+                                    (floor (* count 100.0) 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-number (file-name-nondirectory path)))))))
+
+(deffoo nndiary-request-group (group &optional server dont-check info)
+  (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 back ends 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-functions
+                         (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 move-is-internal)
+  (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)
+       (with-current-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-functions)
+  (when (nndiary-schedule)
+    (let (result)
+      (when nnmail-cache-accepted-message-ids
+       (nnmail-cache-insert (nnmail-fetch-field "message-id")
+                            group
+                            (nnmail-fetch-field "subject")))
+      (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)
+  (with-current-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.
+       (with-current-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-number
+                           (buffer-substring
+                            (match-beginning 0) (match-end 0)))
+                          article)
+                       (zerop (forward-line 1)))))
+         (beginning-of-line)
+         (nnheader-insert-nov headers)
+         (nndiary-save-nov)
+         t)))))
+
+(deffoo nndiary-request-delete-group (group &optional force server)
+  (nndiary-possibly-change-directory group server)
+  (when force
+    ;; Delete all articles in GROUP.
+    (let ((articles
+          (directory-files
+           nndiary-current-directory t
+           (concat nnheader-numerical-short-files
+                   "\\|" (regexp-quote nndiary-nov-file-name) "$")))
+         article)
+      (while articles
+       (setq article (pop articles))
+       (when (file-writable-p article)
+         (nnheader-message 5 "Deleting article %s in %s..." article group)
+         (funcall nnmail-delete-file-function article))))
+    ;; Try to delete the directory itself.
+    (ignore-errors (delete-directory nndiary-current-directory)))
+  ;; Remove the group from all structures.
+  (setq nndiary-group-alist
+       (delq (assoc group nndiary-group-alist) nndiary-group-alist)
+       nndiary-current-group nil
+       nndiary-current-directory nil)
+  ;; Save the active file.
+  (nnmail-save-active nndiary-group-alist nndiary-active-file)
+  t)
+
+(deffoo nndiary-request-rename-group (group new-name &optional server)
+  (nndiary-possibly-change-directory group server)
+  (let ((new-dir (nnmail-group-pathname new-name nndiary-directory))
+       (old-dir (nnmail-group-pathname group nndiary-directory)))
+    (when (ignore-errors
+           (make-directory new-dir t)
+           t)
+      ;; We move the articles file by file instead of renaming
+      ;; the directory -- there may be subgroups in this group.
+      ;; One might be more clever, I guess.
+      (let ((files (nnheader-article-to-file-alist old-dir)))
+       (while files
+         (rename-file
+          (concat old-dir (cdar files))
+          (concat new-dir (cdar files)))
+         (pop files)))
+      ;; Move .overview file.
+      (let ((overview (concat old-dir nndiary-nov-file-name)))
+       (when (file-exists-p overview)
+         (rename-file overview (concat new-dir nndiary-nov-file-name))))
+      (when (<= (length (directory-files old-dir)) 2)
+       (ignore-errors (delete-directory old-dir)))
+      ;; That went ok, so we change the internal structures.
+      (let ((entry (assoc group nndiary-group-alist)))
+       (when entry
+         (setcar entry new-name))
+       (setq nndiary-current-directory nil
+             nndiary-current-group nil)
+       ;; Save the new group alist.
+       (nnmail-save-active nndiary-group-alist nndiary-active-file)
+       t))))
+
+(deffoo nndiary-set-status (article name value &optional group server)
+  (nndiary-possibly-change-directory group server)
+  (let ((file (nndiary-article-to-file article)))
+    (cond
+     ((not (file-exists-p file))
+      (nnheader-report 'nndiary "File %s does not exist" file))
+     (t
+      (with-temp-file file
+       (nnheader-insert-file-contents file)
+       (nnmail-replace-status name value))
+      t))))
+
+\f
+;;; Interface optional functions ============================================
+
+(deffoo nndiary-request-update-info (group info &optional server)
+  (nndiary-possibly-change-directory group)
+  (let ((timestamp (gnus-group-parameter-value (gnus-info-params info)
+                                              'timestamp t)))
+    (if (not timestamp)
+       (nnheader-report 'nndiary "Group %s doesn't have a timestamp" group)
+      ;; else
+      ;; Figure out which articles should be re-new'ed
+      (let ((articles (nndiary-flatten (gnus-info-read info) 0))
+           article file unread buf)
+       (save-excursion
+         (setq buf (nnheader-set-temp-buffer " *nndiary update*"))
+         (while (setq article (pop articles))
+           (setq file (concat nndiary-current-directory
+                              (int-to-string article)))
+           (and (file-exists-p file)
+                (nndiary-renew-article-p file timestamp)
+                (push article unread)))
+         ;;(message "unread: %s" unread)
+         (sit-for 1)
+         (kill-buffer buf))
+       (setq unread (sort unread '<))
+       (and unread
+            (gnus-info-set-read info (gnus-update-read-articles
+                                      (gnus-info-group info) unread t)))
+       ))
+    (run-hook-with-args 'nndiary-request-update-info-functions
+                       (gnus-info-group info))
+    t))
+
+
+\f
+;;; Internal functions ======================================================
+
+(defun nndiary-article-to-file (article)
+  (nndiary-update-file-alist)
+  (let (file)
+    (if (setq file (cdr (assq article nndiary-article-file-alist)))
+       (expand-file-name file nndiary-current-directory)
+      ;; Just to make sure nothing went wrong when reading over NFS --
+      ;; check once more.
+      (if nndiary-check-directory-twice
+         (when (file-exists-p
+                (setq file (expand-file-name (number-to-string article)
+                                             nndiary-current-directory)))
+           (nndiary-update-file-alist t)
+           file)))))
+
+(defun nndiary-deletable-article-p (group article)
+  "Say whether ARTICLE in GROUP can be deleted."
+  (let (path)
+    (when (setq path (nndiary-article-to-file article))
+      (when (file-writable-p path)
+       (or (not nnmail-keep-last-article)
+           (not (eq (cdr (nth 1 (assoc group nndiary-group-alist)))
+                    article)))))))
+
+;; Find an article number in the current group given the Message-ID.
+(defun nndiary-find-group-number (id)
+  (with-current-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" (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)
+       (with-current-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."
+  (with-current-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))))
+      (let ((headers (nnheader-parse-naked-head)))
+       (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))))
+       (with-current-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 ((nndiary-files (sort (nnheader-article-to-file-alist dir)
+                      'car-less-than-car)))
+      (if (not nndiary-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 nndiary-files)
+       (unless no-active
+         (nnmail-save-active nndiary-group-alist nndiary-active-file))))))
+
+(defvar nndiary-files) ; dynamically bound in nndiary-generate-nov-databases-1
+(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 nndiary-files) (1+ last))
+                     (max last
+                          (or (caar (last nndiary-files))
+                              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)
+    ;; Init the nov buffer.
+    (with-current-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)))
+           (with-current-buffer nov-buffer
+             (goto-char (point-max))
+             (nnheader-insert-nov headers)))
+         (widen))
+       (setq files (cdr files)))
+      (with-current-buffer nov-buffer
+       (nnmail-write-region 1 (point-max) nov nil 'nomesg)
+       (kill-buffer (current-buffer))))))
+
+(defun nndiary-nov-delete-article (group article)
+  (with-current-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-number (str min &optional max)
+  ;; Like `string-to-number' 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-number 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 `nndiary-schedule'.
+  (if (string-match "[ \t]*\\*[ \t]*" str)
+      ;; unspecified
+      nil
+    ;; specified
+    (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-number (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-number (car res) min-or-values max))
+                  (end (nndiary-string-to-number (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 `nndiary-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
+    (setcdr (nthcdr 5 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)))
+
+;; FIXME: "occurrence" is misspelled in this function name.
+
+(defun nndiary-last-occurence (sched)
+  ;; Returns the last occurrence 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 quite 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 occurrence.
+        ;; 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))
+       ))))
+
+;; FIXME: "occurrence" is misspelled in this function name.
+
+(defun nndiary-next-occurence (sched now)
+  ;; Returns the next occurrence of schedule SCHED, starting from time NOW.
+  ;; If there's no next occurrence, 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 occurrence 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 occurrence 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... ===============================================================
+
+(dolist (header nndiary-headers)
+  (setq header (intern (format "X-Diary-%s" (car header))))
+  ;; Required for building NOV databases and some other stuff.
+  (add-to-list 'gnus-extra-headers header)
+  (add-to-list 'nnmail-extra-headers header))
+
+(unless (assoc "nndiary" gnus-valid-select-methods)
+  (gnus-declare-backend "nndiary" 'post-mail 'respool 'address))
+
+(provide 'nndiary)
+
+;;; nndiary.el ends here
diff --git a/xemacs-packages/gnus/lisp/nndir.el b/xemacs-packages/gnus/lisp/nndir.el
new file mode 100644 (file)
index 0000000..5d59764
--- /dev/null
@@ -0,0 +1,97 @@
+;;; nndir.el --- single directory newsgroup access for Gnus
+
+;; Copyright (C) 1995-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'nnheader)
+(require 'nnmh)
+(require 'nnml)
+(require 'nnoo)
+(eval-when-compile (require 'cl))
+
+(nnoo-declare nndir
+  nnml nnmh)
+
+(defvoo nndir-directory nil
+  "Where nndir will look for groups."
+  nnml-current-directory nnmh-current-directory)
+
+(defvoo nndir-nov-is-evil nil
+  "*Non-nil means that nndir will never retrieve NOV headers."
+  nnml-nov-is-evil)
+
+\f
+
+(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)
+
+(defvoo nndir-status-string "" nil nnmh-status-string)
+(defconst nndir-version "nndir 1.0")
+
+\f
+
+;;; Interface functions.
+
+(nnoo-define-basics nndir)
+
+(deffoo nndir-open-server (server &optional defs)
+  (setq nndir-directory
+       (or (cadr (assq 'nndir-directory defs))
+           server))
+  (unless (assq 'nndir-directory defs)
+    (push `(nndir-directory ,server) defs))
+  (push `(nndir-current-group
+         ,(file-name-nondirectory (directory-file-name nndir-directory)))
+       defs)
+  (push `(nndir-top-directory
+         ,(file-name-directory (directory-file-name nndir-directory)))
+       defs)
+  (nnoo-change-server 'nndir server defs)
+  (let (err)
+    (cond
+     ((not (condition-case arg
+              (file-exists-p nndir-directory)
+            (ftp-error (setq err (format "%s" arg)))))
+      (nndir-close-server)
+      (nnheader-report
+       'nndir (or err "No such file or directory: %s" nndir-directory)))
+     ((not (file-directory-p (file-truename nndir-directory)))
+      (nndir-close-server)
+      (nnheader-report 'nndir "Not a directory: %s" nndir-directory))
+     (t
+      (nnheader-report 'nndir "Opened server %s using directory %s"
+                      server nndir-directory)
+      t))))
+
+(nnoo-map-functions nndir
+  (nnml-retrieve-headers 0 nndir-current-group 0 0)
+  (nnml-request-article 0 nndir-current-group 0 0)
+  (nnmh-request-group nndir-current-group 0 0)
+  (nnml-close-group nndir-current-group 0)
+  (nnml-request-list (nnoo-current-server 'nndir)))
+
+(provide 'nndir)
+
+;;; nndir.el ends here
diff --git a/xemacs-packages/gnus/lisp/nndoc.el b/xemacs-packages/gnus/lisp/nndoc.el
new file mode 100644 (file)
index 0000000..f8fefeb
--- /dev/null
@@ -0,0 +1,1104 @@
+;;; nndoc.el --- single file access for Gnus
+
+;; Copyright (C) 1995-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;;     Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; For Outlook mail boxes format, see http://mbx2mbox.sourceforge.net/
+
+;;; Code:
+
+(require 'nnheader)
+(require 'message)
+(require 'nnmail)
+(require 'nnoo)
+(require 'gnus-util)
+(require 'mm-util)
+(eval-when-compile (require 'cl))
+
+(nnoo-declare nndoc)
+
+(defvoo nndoc-article-type 'guess
+  "*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', `outlook', `oe-dbx',
+`mailman', `exim-bounce', or `guess'.")
+
+(defvoo nndoc-post-type 'mail
+  "*Whether the nndoc group is `mail' or `post'.")
+
+(defvoo nndoc-open-document-hook 'nnheader-ms-strip-cr
+  "Hook run after opening a document.
+The default function removes all trailing carriage returns
+from the document.")
+
+(defvar nndoc-type-alist
+  `((mmdf
+     (article-begin .  "^\^A\^A\^A\^A\n")
+     (body-end .  "^\^A\^A\^A\^A\n"))
+    (debbugs-db
+     (file-begin    . "^\005")
+     (article-begin . "^[\005\007]\n")
+     (body-end      . "^\003"))
+    (mime-digest
+     (article-begin . "")
+     (head-begin . "^ ?\n")
+     (head-end . "^ ?$")
+     (body-end . "")
+     (file-end . "")
+     (subtype digest guess))
+    (nsmail
+     (article-begin .  "^From - "))
+    (news
+     (article-begin . "^Path:"))
+    (rnews
+     (article-begin . "^#! *rnews +\\([0-9]+\\) *\n")
+     (body-end-function . nndoc-rnews-body-end))
+    (mbox
+     (article-begin-function . nndoc-mbox-article-begin)
+     (body-end-function . nndoc-mbox-body-end))
+    (babyl
+     (article-begin . "\^_\^L *\n")
+     (body-end . "\^_")
+     (body-begin-function . nndoc-babyl-body-begin)
+     (head-begin-function . nndoc-babyl-head-begin))
+    (mime-parts
+     (generate-head-function . nndoc-generate-mime-parts-head)
+     (article-transform-function . nndoc-transform-mime-parts))
+    (exim-bounce
+     (article-begin . "^------ This is a copy of the message, including all the headers. ------\n\n")
+     (body-end-function . nndoc-exim-bounce-body-end-function))
+    (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^ \\*")
+     (body-begin . "^\t")
+     (head-end . "^\t")
+     (generate-head-function . nndoc-generate-clari-briefs-head)
+     (article-transform-function . nndoc-transform-clari-briefs))
+
+    (standard-digest
+     (first-article . ,(concat "^" (make-string 70 ?-) "\n *\n+"))
+     (article-begin . ,(concat "^\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))
+    (slack-digest
+     (article-begin . "^------------------------------*[\n \t]+")
+     (head-end . "^ ?$")
+     (body-end-function . nndoc-digest-body-end)
+     (body-begin . "^ ?$")
+     (file-end . "^End of")
+     (prepare-body-function . nndoc-unquote-dashes)
+     (subtype digest guess))
+    (google
+     (pre-dissection-function . nndoc-decode-content-transfer-encoding)
+     (article-begin . "^== [0-9]+ of [0-9]+ ==$")
+     (head-begin . "^Date:")
+     (head-end . "^$")
+     (body-end-function . nndoc-digest-body-end)
+     (body-begin . "^$")
+     (file-end . "^==============================================================================$")
+     (prepare-body-function . nndoc-unquote-dashes)
+     (subtype digest guess))
+    (lanl-gov-announce
+     (article-begin . "^\\\\\\\\\n")
+     (head-begin . "^\\(Paper.*:\\|arXiv:\\)")
+     (head-end   . "\\(^\\\\\\\\.*\n\\|-----------------\\)")
+     (body-begin . "")
+     (body-end   . "\\(-------------------------------------------------\\|%-%-%-%-%-%-%-%-%-%-%-%-%-%-\\|%%--%%--%%--%%--%%--%%--%%--%%--\\|%%%---%%%---%%%---%%%---\\)")
+     (file-end   . "\\(^Title: Recent Seminal\\|%%%---%%%---%%%---%%%---\\)")
+     (generate-head-function . nndoc-generate-lanl-gov-head)
+     (article-transform-function . nndoc-transform-lanl-gov-announce)
+     (subtype preprints guess))
+    (git
+     (file-begin . "\n- Log ---.*")
+     (article-begin . "^commit ")
+     (head-begin . "^Author: ")
+     (body-begin . "^$")
+     (file-end . "\n-----------------------------------------------------------------------")
+     (article-transform-function . nndoc-transform-git-article)
+     (header-transform-function . nndoc-transform-git-headers))
+    (rfc822-forward
+     (article-begin . "^\n+")
+     (body-end-function . nndoc-rfc822-forward-body-end-function)
+     (generate-head-function . nndoc-rfc822-forward-generate-head)
+     (generate-article-function . nndoc-rfc822-forward-generate-article))
+    (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))
+    (mail-in-mail ;; Wild guess on mailer daemon's messages or others
+     (article-begin-function . nndoc-mail-in-mail-article-begin))
+    (guess
+     (guess . t)
+     (subtype nil))
+    (digest
+     (guess . t)
+     (subtype nil))
+    (preprints
+     (guess . t)
+     (subtype nil))))
+
+(defvar nndoc-binary-file-names ".[Dd][Bb][Xx]$"
+  "Regexp for binary nndoc file names.")
+
+\f
+(defvoo nndoc-file-begin nil)
+(defvoo nndoc-first-article nil)
+(defvoo nndoc-article-begin nil)
+(defvoo nndoc-head-begin nil)
+(defvoo nndoc-head-end nil)
+(defvoo nndoc-file-end nil)
+(defvoo nndoc-body-begin nil)
+(defvoo nndoc-body-end-function nil)
+(defvoo nndoc-body-begin-function nil)
+(defvoo nndoc-head-begin-function nil)
+(defvoo nndoc-body-end nil)
+;; nndoc-dissection-alist is a list of sublists.  Each sublist holds the
+;; following items.  ARTICLE acts as the association key and is an ordinal
+;; starting at 1.  HEAD-BEGIN [0], HEAD-END [1], BODY-BEGIN [2] and BODY-END
+;; [3] are positions in the `nndoc' buffer.  LINE-COUNT [4] is a count of
+;; lines in the body.  For MIME dissections only, ARTICLE-INSERT [5] and
+;; SUMMARY-INSERT [6] give headers to insert for full article or summary line
+;; generation, respectively.  Other headers usually follow directly from the
+;; buffer.  Value nil means no insert.
+(defvoo nndoc-dissection-alist nil)
+(defvoo nndoc-prepare-body-function nil)
+(defvoo nndoc-generate-head-function nil)
+(defvoo nndoc-article-transform-function nil)
+(defvoo nndoc-header-transform-function nil)
+(defvoo nndoc-article-begin-function nil)
+(defvoo nndoc-generate-article-function nil)
+(defvoo nndoc-dissection-function nil)
+(defvoo nndoc-pre-dissection-function nil)
+
+(defvoo nndoc-status-string "")
+(defvoo nndoc-group-alist nil)
+(defvoo nndoc-current-buffer nil
+  "Current nndoc news buffer.")
+(defvoo nndoc-address nil)
+
+(defconst nndoc-version "nndoc 1.0"
+  "nndoc version.")
+
+\f
+
+;;; Interface functions
+
+(nnoo-define-basics nndoc)
+
+(deffoo nndoc-retrieve-headers (articles &optional newsgroup server fetch-old)
+  (when (nndoc-possibly-change-buffer newsgroup server)
+    (with-current-buffer nntp-server-buffer
+      (erase-buffer)
+      (let (article entry)
+       (if (stringp (car articles))
+           'headers
+         (while articles
+           (when (setq entry (cdr (assq (setq article (pop articles))
+                                        nndoc-dissection-alist)))
+             (let ((start (point)))
+               (insert (format "221 %d Article retrieved.\n" article))
+               (if nndoc-generate-head-function
+                   (funcall nndoc-generate-head-function article)
+                 (insert-buffer-substring
+                  nndoc-current-buffer (car entry) (nth 1 entry)))
+               (goto-char (point-max))
+               (unless (eq (char-after (1- (point))) ?\n)
+                 (insert "\n"))
+               (insert (format "Lines: %d\n" (nth 4 entry)))
+               (insert ".\n")
+               (when nndoc-header-transform-function
+                 (save-excursion
+                   (save-restriction
+                     (narrow-to-region start (point))
+                     (funcall nndoc-header-transform-function entry)))))))
+         (nnheader-fold-continuation-lines)
+         'headers)))))
+
+(deffoo nndoc-request-article (article &optional newsgroup server buffer)
+  (nndoc-possibly-change-buffer newsgroup server)
+  (save-excursion
+    (let ((buffer (or buffer nntp-server-buffer))
+         (entry (cdr (assq article nndoc-dissection-alist)))
+         beg)
+      (set-buffer buffer)
+      (erase-buffer)
+      (when entry
+       (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")
+         (setq beg (point))
+         (insert-buffer-substring
+          nndoc-current-buffer (nth 2 entry) (nth 3 entry))
+         (goto-char beg)
+         (when nndoc-prepare-body-function
+           (funcall nndoc-prepare-body-function))
+         (when nndoc-article-transform-function
+           (funcall nndoc-article-transform-function article))
+         t))))))
+
+(deffoo nndoc-request-group (group &optional server dont-check info)
+  "Select news GROUP."
+  (let (number)
+    (cond
+     ((not (nndoc-possibly-change-buffer group server))
+      (nnheader-report 'nndoc "No such file or buffer: %s"
+                      nndoc-address))
+     (dont-check
+      (nnheader-report 'nndoc "Selected group %s" group)
+      t)
+     ((zerop (setq number (length nndoc-dissection-alist)))
+      (nndoc-close-group group)
+      (nnheader-report 'nndoc "No articles in group %s" group))
+     (t
+      (nnheader-insert "211 %d %d %d %s\n" number 1 number group)))))
+
+(deffoo nndoc-retrieve-groups (groups &optional server)
+  (dolist (group groups)
+    (nndoc-request-group group server))
+  t)
+
+(deffoo nndoc-request-type (group &optional article)
+  (cond ((not article) 'unknown)
+       (nndoc-post-type nndoc-post-type)
+       (t 'unknown)))
+
+(deffoo nndoc-close-group (group &optional server)
+  (nndoc-possibly-change-buffer group server)
+  (and nndoc-current-buffer
+       (buffer-name nndoc-current-buffer)
+       (kill-buffer nndoc-current-buffer))
+  (setq nndoc-group-alist (delq (assoc group nndoc-group-alist)
+                               nndoc-group-alist))
+  (setq nndoc-current-buffer nil)
+  (nnoo-close-server 'nndoc server)
+  (setq nndoc-dissection-alist nil)
+  t)
+
+(deffoo nndoc-request-list (&optional server)
+  t)
+
+(deffoo nndoc-request-newgroups (date &optional server)
+  nil)
+
+(deffoo nndoc-request-list-newsgroups (&optional server)
+  nil)
+
+\f
+;;; Internal functions.
+
+(defun nndoc-possibly-change-buffer (group source)
+  (let (buf)
+    (cond
+     ;; The current buffer is this group's buffer.
+     ((and nndoc-current-buffer
+          (buffer-name nndoc-current-buffer)
+          (eq nndoc-current-buffer
+              (setq buf (cdr (assoc group nndoc-group-alist))))))
+     ;; We change buffers by taking an old from the group alist.
+     ;; `source' is either a string (a file name) or a buffer object.
+     (buf
+      (setq nndoc-current-buffer buf))
+     ;; It's a totally new group.
+     ((or (and (bufferp nndoc-address)
+              (buffer-name nndoc-address))
+         (and (stringp nndoc-address)
+              (file-exists-p nndoc-address)
+              (not (file-directory-p nndoc-address))))
+      (push (cons group (setq nndoc-current-buffer
+                             (get-buffer-create
+                              (concat " *nndoc " group "*"))))
+           nndoc-group-alist)
+      (setq nndoc-dissection-alist nil)
+      (with-current-buffer nndoc-current-buffer
+       (erase-buffer)
+       (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))
+      (with-current-buffer nndoc-current-buffer
+       (nndoc-set-delims)
+       (if (eq nndoc-article-type 'mime-parts)
+           (nndoc-dissect-mime-parts)
+         (nndoc-dissect-buffer))))
+    (unless nndoc-current-buffer
+      (nndoc-close-server))
+    ;; Return whether we managed to select a file.
+    nndoc-current-buffer))
+
+;;;
+;;; Deciding what document type we have
+;;;
+
+(defun nndoc-set-delims ()
+  "Set the nndoc delimiter variables according to the type of the document."
+  (let ((vars '(nndoc-file-begin
+               nndoc-first-article
+               nndoc-article-begin-function
+               nndoc-head-begin nndoc-head-end
+               nndoc-file-end nndoc-article-begin
+               nndoc-body-begin nndoc-body-end-function nndoc-body-end
+               nndoc-prepare-body-function nndoc-article-transform-function
+               nndoc-header-transform-function
+               nndoc-generate-head-function nndoc-body-begin-function
+               nndoc-head-begin-function
+               nndoc-generate-article-function
+               nndoc-dissection-function
+               nndoc-pre-dissection-function)))
+    (while vars
+      (set (pop vars) nil)))
+  (let (defs)
+    ;; Guess away until we find the real file type.
+    (while (assq 'guess (setq defs (cdr (assq nndoc-article-type
+                                             nndoc-type-alist))))
+      (setq nndoc-article-type (nndoc-guess-type nndoc-article-type)))
+    ;; Set the nndoc variables.
+    (while defs
+      (set (intern (format "nndoc-%s" (caar defs)))
+          (cdr (pop defs))))))
+
+(defun nndoc-guess-type (subtype)
+  (let ((alist nndoc-type-alist)
+       results result entry)
+    (while (and (not result)
+               (setq entry (pop alist)))
+      (when (memq subtype (or (cdr (assq 'subtype entry)) '(guess)))
+       (goto-char (point-min))
+       ;; Remove blank lines.
+       (while (eq (following-char) ?\n)
+         (delete-char 1))
+       (when (numberp (setq result (funcall (intern
+                                             (format "nndoc-%s-type-p"
+                                                     (car entry))))))
+         (push (cons result entry) results)
+         (setq result nil))))
+    (unless (or result results)
+      (error "Document is not of any recognized type"))
+    (if result
+       (car entry)
+      (cadar (last (sort results 'car-less-than-car))))))
+
+;;;
+;;; Built-in type predicates and functions
+;;;
+
+(defun nndoc-mbox-type-p ()
+  (when (looking-at message-unix-mail-delimiter)
+    t))
+
+(defun nndoc-mbox-article-begin ()
+  (when (re-search-forward (concat "^" message-unix-mail-delimiter) nil t)
+    (goto-char (match-beginning 0))))
+
+(defun nndoc-mbox-body-end ()
+  (let ((beg (point))
+       len end)
+    (when
+       (save-excursion
+         (and (re-search-backward
+               (concat "^" message-unix-mail-delimiter) nil t)
+              (setq end (point))
+              (search-forward "\n\n" beg t)
+              (re-search-backward
+               "^Content-Length:[ \t]*\\([0-9]+\\) *$" end t)
+              (setq len (string-to-number (match-string 1)))
+              (search-forward "\n\n" beg t)
+              (unless (= (setq len (+ (point) len)) (point-max))
+                (and (< len (point-max))
+                     (goto-char len)
+                     (looking-at message-unix-mail-delimiter)))))
+      (goto-char len))))
+
+(defun nndoc-mmdf-type-p ()
+  (when (looking-at "\^A\^A\^A\^A$")
+    t))
+
+(defun nndoc-debbugs-db-type-p ()
+  (when (looking-at "\006$")
+    t))
+
+(defun nndoc-news-type-p ()
+  (when (looking-at "^Path:.*\n")
+    t))
+
+(defun nndoc-rnews-type-p ()
+  (when (looking-at "#! *rnews")
+    t))
+
+(defun nndoc-rnews-body-end ()
+  (and (re-search-backward nndoc-article-begin nil t)
+       (forward-line 1)
+       (goto-char (+ (point) (string-to-number (match-string 1))))))
+
+(defun nndoc-google-type-p ()
+  (when (re-search-forward "^=3D=3D 1 of [0-9]+ =3D=3D$" nil t)
+    t))
+
+(defun nndoc-decode-content-transfer-encoding ()
+  (let ((encoding
+        (save-restriction
+          (message-narrow-to-head)
+          (message-fetch-field "content-transfer-encoding"))))
+    (when (and encoding
+              (search-forward "\n\n" nil t))
+      (save-restriction
+       (narrow-to-region (point) (point-max))
+       (mm-decode-content-transfer-encoding
+        (intern (downcase (mail-header-strip encoding))))))))
+
+(defun nndoc-babyl-type-p ()
+  (when (re-search-forward "\^_\^L *\n" nil t)
+    t))
+
+(defun nndoc-babyl-body-begin ()
+  (re-search-forward "^\n" nil t)
+  (when (looking-at "\\*\\*\\* EOOH \\*\\*\\*")
+    (let ((next (or (save-excursion
+                     (re-search-forward nndoc-article-begin nil t))
+                   (point-max))))
+      (unless (re-search-forward "^\n" next t)
+       (goto-char next)
+       (forward-line -1)
+       (insert "\n")
+       (forward-line -1)))))
+
+(defun nndoc-babyl-head-begin ()
+  (when (re-search-forward "^[0-9].*\n" nil t)
+    (when (looking-at "\\*\\*\\* EOOH \\*\\*\\*")
+      (forward-line 1))
+    t))
+
+(defun nndoc-forward-type-p ()
+  (when (and (re-search-forward "^-+ \\(Start of \\)?forwarded message.*\n+"
+                               nil t)
+            (looking-at "[\r\n]*[a-zA-Z][a-zA-Z0-9-]*:\\|^>?From "))
+    t))
+
+(defun nndoc-rfc934-type-p ()
+  (when (and (re-search-forward "^-+ Start of forwarded.*\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)))
+    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)
+    (when (re-search-forward "^Content-Type: *message/rfc822" nil t)
+      t)))
+
+(defun nndoc-rfc822-forward-body-end-function ()
+  (goto-char (point-max)))
+
+(defun nndoc-rfc822-forward-generate-article (article &optional head)
+  (let ((entry (cdr (assq article nndoc-dissection-alist)))
+       (begin (point))
+       encoding)
+    (with-current-buffer nndoc-current-buffer
+      (save-restriction
+       (message-narrow-to-head)
+       (setq encoding (message-fetch-field "content-transfer-encoding"))))
+    (insert-buffer-substring nndoc-current-buffer (car entry) (nth 3 entry))
+    (when encoding
+      (save-restriction
+       (narrow-to-region begin (point-max))
+       (mm-decode-content-transfer-encoding
+        (intern (downcase (mail-header-strip encoding))))))
+    (when head
+      (goto-char begin)
+      (when (search-forward "\n\n" nil t)
+       (delete-region (1- (point)) (point-max)))))
+  t)
+
+(defun nndoc-rfc822-forward-generate-head (article)
+  (nndoc-rfc822-forward-generate-article article 'head))
+
+(defun nndoc-mime-parts-type-p ()
+  (let ((case-fold-search t)
+       (limit (search-forward "\n\n" nil t)))
+    (goto-char (point-min))
+    (when (and limit
+              (re-search-forward
+               (concat "\
+^Content-Type:[ \t]*multipart/[a-z]+ *; *\\(\\(\n[ \t]\\)?.*;\\)*"
+                       "\\(\n[ \t]\\)?[ \t]*boundary=\"?[^\"\n]*[^\" \t\n]")
+               limit t))
+      t)))
+
+(defun nndoc-transform-mime-parts (article)
+  (let* ((entry (cdr (assq article nndoc-dissection-alist)))
+        (headers (nth 5 entry)))
+    (when headers
+      (goto-char (point-min))
+      (insert headers))))
+
+(defun nndoc-generate-mime-parts-head (article)
+  (let* ((entry (cdr (assq article nndoc-dissection-alist)))
+        (headers (nth 6 entry)))
+    (save-restriction
+      (narrow-to-region (point) (point))
+      (insert-buffer-substring
+       nndoc-current-buffer (car entry) (nth 1 entry))
+      (goto-char (point-max)))
+    (when headers
+      (insert headers))))
+
+(defun nndoc-clari-briefs-type-p ()
+  (when (let ((case-fold-search nil))
+         (re-search-forward "^\t[^a-z]+ ([^a-z]+) --" nil t))
+    t))
+
+(defun nndoc-transform-clari-briefs (article)
+  (goto-char (point-min))
+  (when (looking-at " *\\*\\(.*\\)\n")
+    (replace-match "" t t))
+  (nndoc-generate-clari-briefs-head article))
+
+(defun nndoc-generate-clari-briefs-head (article)
+  (let ((entry (cdr (assq article nndoc-dissection-alist)))
+       subject from)
+    (with-current-buffer nndoc-current-buffer
+      (save-restriction
+       (narrow-to-region (car entry) (nth 3 entry))
+       (goto-char (point-min))
+       (when (looking-at " *\\*\\(.*\\)$")
+         (setq subject (match-string 1))
+         (when (string-match "[ \t]+$" subject)
+           (setq subject (substring subject 0 (match-beginning 0)))))
+       (when
+           (let ((case-fold-search nil))
+             (re-search-forward
+              "^\t\\([^a-z]+\\(,[^(]+\\)? ([^a-z]+)\\) --" nil t))
+         (setq from (match-string 1)))))
+    (insert "From: " "clari@clari.net (" (or from "unknown") ")"
+           "\nSubject: " (or subject "(no subject)") "\n")))
+
+(defun nndoc-exim-bounce-type-p ()
+  (and (re-search-forward "^------ This is a copy of the message, including all the headers. ------" nil t)
+       t))
+
+(defun nndoc-exim-bounce-body-end-function ()
+  (goto-char (point-max)))
+
+
+(defun nndoc-mime-digest-type-p ()
+  (let ((case-fold-search t)
+       boundary-id b-delimiter entry)
+    (when (and
+          (re-search-forward
+           (concat "^Content-Type: *multipart/digest;[ \t\n]*[ \t]"
+                   "boundary=\"?\\([^\"\n]*[^\" \t\n]\\)")
+           nil t)
+          (match-beginning 1))
+      (setq boundary-id (match-string 1)
+           b-delimiter (concat "\n--" boundary-id "[ \t]*$"))
+      (setq entry (assq 'mime-digest nndoc-type-alist))
+      (setcdr entry
+             (list
+              (cons 'head-begin "^ ?\n")
+              (cons 'head-end "^ ?$")
+              (cons 'body-begin "^ ?\n")
+              (cons 'article-begin b-delimiter)
+              (cons 'body-end-function 'nndoc-digest-body-end)
+              (cons 'file-end (concat "^--" boundary-id "--[ \t]*$"))))
+      t)))
+
+(defun nndoc-standard-digest-type-p ()
+  (when (and (re-search-forward (concat "^" (make-string 70 ?-) "\n\n") nil t)
+            (re-search-forward
+             (concat "\n\n" (make-string 30 ?-) "\n\n") nil t))
+    t))
+
+(defun nndoc-digest-body-end ()
+  (and (re-search-forward nndoc-article-begin nil t)
+       (goto-char (match-beginning 0))))
+
+(defun nndoc-slack-digest-type-p ()
+  0)
+
+(defun nndoc-git-type-p ()
+  (and (search-forward "\n- Log ---" nil t)
+       (search-forward "\ncommit " nil t)
+       (search-forward "\nAuthor: " nil t)))
+
+(defun nndoc-transform-git-article (article)
+  (goto-char (point-min))
+  (when (re-search-forward "^Author: " nil t)
+    (replace-match "From: " t t)))
+
+(defun nndoc-transform-git-headers (entry)
+  (goto-char (point-min))
+  (when (re-search-forward "^Author: " nil t)
+    (replace-match "From: " t t))
+  (let (subject)
+    (with-current-buffer nndoc-current-buffer
+      (goto-char (car entry))
+      (when (search-forward "\n\n" nil t)
+       (setq subject (buffer-substring (point) (line-end-position)))))
+    (when subject
+      (goto-char (point-min))
+      (forward-line 1)
+      (insert (format "Subject: %s\n" subject)))))
+
+(defun nndoc-lanl-gov-announce-type-p ()
+  (when (let ((case-fold-search nil))
+         (re-search-forward "^\\\\\\\\\n\\(Paper\\( (\\*cross-listing\\*)\\)?: [a-zA-Z-\\.]+/[0-9]+\\|arXiv:\\)" nil t))
+    t))
+
+(defun nndoc-transform-lanl-gov-announce (article)
+  (let ((case-fold-search nil))
+    (goto-char (point-max))
+    (when (re-search-backward "^\\\\\\\\ +( *\\([^ ]*\\) , *\\([^ ]*\\))" nil t)
+      (replace-match "\n\nGet it at \\1 (\\2)" t nil))
+    (goto-char (point-min))
+    (while (re-search-forward "^\\\\\\\\$" nil t)
+      (replace-match "" t nil))
+    (goto-char (point-min))
+    (when (re-search-forward "^replaced with revised version +\\(.*[^ ]\\) +" nil t)
+      (replace-match "Date: \\1 (revised) " t nil))
+    (goto-char (point-min))
+    (unless (re-search-forward "^From" nil t)
+      (goto-char (point-min))
+      (when (re-search-forward "^Authors?: \\(.*\\)" nil t)
+       (goto-char (point-min))
+       (insert "From: " (match-string 1) "\n")))
+    (when (re-search-forward "^arXiv:" nil t)
+      (replace-match "Paper: arXiv:" t nil))))
+
+(defun nndoc-generate-lanl-gov-head (article)
+  (let ((entry (cdr (assq article nndoc-dissection-alist)))
+       (from "<no address given>")
+       subject date)
+    (with-current-buffer nndoc-current-buffer
+      (save-restriction
+       (narrow-to-region (car entry) (nth 1 entry))
+       (goto-char (point-min))
+       (when (looking-at "^\\(Paper.*: \\|arXiv:\\)\\([0-9a-zA-Z-\\./]+\\)")
+         (setq subject (concat " (" (match-string 2) ")"))
+         (when (re-search-forward "^From: \\(.*\\)" nil t)
+           (setq from (concat "<"
+                              (cadr (funcall gnus-extract-address-components
+                                             (match-string 1))) ">")))
+         (if (re-search-forward "^Date: +\\([^(]*\\)" nil t)
+             (setq date (match-string 1))
+           (when (re-search-forward "^replaced with revised version +\\([^(]*\\)" nil t)
+             (setq date (match-string 1))))
+         (when (re-search-forward "^Title: \\([^\f]*\\)\nAuthors?: \\(.*\\)"
+                                  nil t)
+           (setq subject (concat (match-string 1) subject))
+           (setq from (concat (match-string 2) " " from))))))
+    (while (and from (string-match "([^)]*)" from))
+      (setq from (replace-match "" t t from)))
+    (insert "From: "  (or from "unknown")
+           "\nSubject: " (or subject "(no subject)") "\n")
+    (if date (insert "Date: " date))))
+
+(defun nndoc-nsmail-type-p ()
+  (when (looking-at "From - ")
+    t))
+
+(defun nndoc-outlook-article-begin ()
+  (prog1 (re-search-forward "From:\\|Received:" nil t)
+    (goto-char (match-beginning 0))))
+
+(defun nndoc-outlook-type-p ()
+  ;; FIXME: Is JMF the magic of outlook mailbox? -- ShengHuo.
+  (looking-at "JMF"))
+
+(defun nndoc-oe-dbx-type-p ()
+  (looking-at (mm-string-to-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-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))
+
+(defun nndoc-mail-in-mail-type-p ()
+  (let (found)
+    (save-excursion
+      (catch 'done
+       (while (re-search-forward "\n\n[-A-Za-z0-9]+:" nil t)
+         (setq found 0)
+         (forward-line)
+         (while (looking-at "[ \t]\\|[-A-Za-z0-9]+:")
+           (if (looking-at "[-A-Za-z0-9]+:")
+               (setq found (1+ found)))
+           (forward-line))
+         (if (and (> found 0) (looking-at "\n"))
+             (throw 'done 9999)))
+       nil))))
+
+(defun nndoc-mail-in-mail-article-begin ()
+  (let (point found)
+    (if (catch 'done
+         (while (re-search-forward "\n\n\\([-A-Za-z0-9]+:\\)" nil t)
+           (setq found 0)
+           (setq point (match-beginning 1))
+           (forward-line)
+           (while (looking-at "[ \t]\\|[-A-Za-z0-9]+:")
+             (if (looking-at "[-A-Za-z0-9]+:")
+                 (setq found (1+ found)))
+             (forward-line))
+           (if (and (> found 0) (looking-at "\n"))
+               (throw 'done t)))
+         nil)
+       (goto-char point))))
+
+(deffoo nndoc-request-accept-article (group &optional server last)
+  nil)
+
+;;;
+;;; Functions for dissecting the documents
+;;;
+
+(defun nndoc-search (regexp)
+  (prog1
+      (re-search-forward regexp nil t)
+    (beginning-of-line)))
+
+(defun nndoc-dissect-buffer ()
+  "Go through the document and partition it into heads/bodies/articles."
+  (let ((i 0)
+       (first t)
+       art-begin head-begin head-end body-begin body-end)
+    (setq nndoc-dissection-alist nil)
+    (with-current-buffer nndoc-current-buffer
+      (goto-char (point-min))
+      ;; Remove blank lines.
+      (while (eq (following-char) ?\n)
+       (delete-char 1))
+      (when nndoc-pre-dissection-function
+       (save-excursion
+         (funcall nndoc-pre-dissection-function)))
+      (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)
+                (if art-begin
+                    (goto-char art-begin)
+                  (nndoc-article-begin)))
+         (setq first nil
+               art-begin 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))
+               (and (nndoc-article-begin)
+                    (setq art-begin (point)))
+               (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)))))
+    (setq nndoc-dissection-alist (nreverse nndoc-dissection-alist))))
+
+(defun nndoc-article-begin ()
+  (if nndoc-article-begin-function
+      (funcall nndoc-article-begin-function)
+    (ignore-errors
+      (nndoc-search nndoc-article-begin))))
+
+(defun nndoc-unquote-dashes ()
+  "Unquote quoted non-separators in digests."
+  (while (re-search-forward "^- -"nil t)
+    (replace-match "-" t t)))
+
+;; Against compiler warnings.
+(defvar nndoc-mime-split-ordinal)
+
+(defun nndoc-dissect-mime-parts ()
+  "Go through a MIME composite article and partition it into sub-articles.
+When a MIME entity contains sub-entities, dissection produces one article for
+the header of this entity, and one article per sub-entity."
+  (setq nndoc-dissection-alist nil
+       nndoc-mime-split-ordinal 0)
+  (with-current-buffer nndoc-current-buffer
+    (nndoc-dissect-mime-parts-sub (point-min) (point-max) nil nil nil)))
+
+(defun nndoc-dissect-mime-parts-sub (head-begin body-end article-insert
+                                               position parent)
+  "Dissect an entity, within a composite MIME message.
+The complete message or MIME entity extends from HEAD-BEGIN to BODY-END.
+ARTICLE-INSERT should be added at beginning for generating a full article.
+The string POSITION holds a dotted decimal representation of the article
+position in the hierarchical structure, it is nil for the outer entity.
+PARENT is the message-ID of the parent summary line, or nil for none."
+  (let ((case-fold-search t)
+       (message-id (nnmail-message-id))
+       head-end body-begin summary-insert message-rfc822 multipart-any
+       subject content-type type subtype boundary-regexp)
+    ;; Gracefully handle a missing body.
+    (goto-char head-begin)
+    (if (or (and (eq (char-after) ?\n) (or (forward-char 1) t))
+           (search-forward "\n\n" body-end t))
+       (setq head-end (1- (point))
+             body-begin (point))
+      (setq head-end body-end
+           body-begin body-end))
+    (narrow-to-region head-begin head-end)
+    ;; Save MIME attributes.
+    (goto-char head-begin)
+    (setq content-type (message-fetch-field "Content-Type"))
+    (when content-type
+      (when (string-match
+            "^ *\\([^ \t\n/;]+\\)/\\([^ \t\n/;]+\\)" content-type)
+       (setq type (downcase (match-string 1 content-type))
+             subtype (downcase (match-string 2 content-type))
+             message-rfc822 (and (string= type "message")
+                                 (string= subtype "rfc822"))
+             multipart-any (string= type "multipart")))
+      (when (string-match ";[ \t\n]*name=\\([^ \t\n;]+\\)" content-type)
+       (setq subject (match-string 1 content-type)))
+      (when (string-match "boundary=\"?\\([^\"\n]*[^\" \t\n]\\)" content-type)
+       (setq boundary-regexp (concat "^--"
+                                     (regexp-quote
+                                      (match-string 1 content-type))
+                                     "\\(--\\)?[ \t]*\n"))))
+    (unless subject
+      (when (or multipart-any (not article-insert))
+       (setq subject (message-fetch-field "Subject"))))
+    (unless type
+      (setq type "text"
+           subtype "plain"))
+    ;; Prepare the article and summary inserts.
+    (unless article-insert
+      (setq article-insert (buffer-string)
+           head-end head-begin))
+    ;; Fix MIME-Version
+    (unless (string-match "MIME-Version:" article-insert)
+      (setq article-insert
+           (concat article-insert "MIME-Version: 1.0\n")))
+    (setq summary-insert article-insert)
+    ;; - summary Subject.
+    (setq summary-insert
+         (let ((line (concat "Subject: <" position
+                             (and position multipart-any ".")
+                             (and multipart-any "*")
+                             (and (or position multipart-any) " ")
+                             (cond ((string= subtype "plain") type)
+                                   ((string= subtype "basic") type)
+                                   (t subtype))
+                             ">"
+                             (and subject " ")
+                             subject
+                             "\n")))
+           (if (string-match "Subject:.*\n\\([ \t].*\n\\)*" summary-insert)
+               (replace-match line t t summary-insert)
+             (concat summary-insert line))))
+    ;; - summary Message-ID.
+    (setq summary-insert
+         (let ((line (concat "Message-ID: " message-id "\n")))
+           (if (string-match "Message-ID:.*\n\\([ \t].*\n\\)*" summary-insert)
+               (replace-match line t t summary-insert)
+             (concat summary-insert line))))
+    ;; - summary References.
+    (when parent
+      (setq summary-insert
+           (let ((line (concat "References: " parent "\n")))
+             (if (string-match "References:.*\n\\([ \t].*\n\\)*"
+                               summary-insert)
+                 (replace-match line t t summary-insert)
+               (concat summary-insert line)))))
+    ;; Generate dissection information for this entity.
+    (push (list (incf nndoc-mime-split-ordinal)
+               head-begin head-end body-begin body-end
+               (count-lines body-begin body-end)
+               article-insert summary-insert)
+         nndoc-dissection-alist)
+    ;; Recurse for all sub-entities, if any.
+    (widen)
+    (cond
+     (message-rfc822
+      (save-excursion
+       (nndoc-dissect-mime-parts-sub body-begin body-end nil
+                                     position message-id)))
+     ((and multipart-any boundary-regexp)
+      (let ((part-counter 0)
+           part-begin part-end eof-flag)
+       (while (string-match "\
+^\\(Lines\\|Content-\\(Type\\|Transfer-Encoding\\|Disposition\\)\\):.*\n\\([ \t].*\n\\)*"
+                            article-insert)
+         (setq article-insert (replace-match "" t t article-insert)))
+       (let ((case-fold-search nil))
+         (goto-char body-begin)
+         (setq eof-flag (not (re-search-forward boundary-regexp body-end t)))
+         (while (not eof-flag)
+           (setq part-begin (point))
+           (cond ((re-search-forward boundary-regexp body-end t)
+                  (or (not (match-string 1))
+                      (string= (match-string 1) "")
+                      (setq eof-flag t))
+                  (forward-line -1)
+                  (setq part-end (point))
+                  (forward-line 1))
+                 (t (setq part-end body-end
+                          eof-flag t)))
+           (save-excursion
+             (nndoc-dissect-mime-parts-sub
+              part-begin part-end article-insert
+              (concat position
+                      (and position ".")
+                      (format "%d" (incf part-counter)))
+              message-id)))))))))
+
+;;;###autoload
+(defun nndoc-add-type (definition &optional position)
+  "Add document DEFINITION to the list of nndoc document definitions.
+If POSITION is nil or `last', the definition will be added
+as the last checked definition, if t or `first', add as the
+first definition, and if any other symbol, add after that
+symbol in the alist."
+  ;; First remove any old instances.
+  (gnus-alist-pull (car definition) nndoc-type-alist)
+  ;; Then enter the new definition in the proper place.
+  (cond
+   ((or (null position) (eq position 'last))
+    (setq nndoc-type-alist (nconc nndoc-type-alist (list definition))))
+   ((or (eq position t) (eq position 'first))
+    (push definition nndoc-type-alist))
+   (t
+    (let ((list (memq (assq position nndoc-type-alist)
+                     nndoc-type-alist)))
+      (unless list
+       (error "No such position: %s" position))
+      (setcdr list (cons definition (cdr list)))))))
+
+(provide 'nndoc)
+
+;;; nndoc.el ends here
diff --git a/xemacs-packages/gnus/lisp/nndraft.el b/xemacs-packages/gnus/lisp/nndraft.el
new file mode 100644 (file)
index 0000000..5f57dd2
--- /dev/null
@@ -0,0 +1,354 @@
+;;; nndraft.el --- draft article access for Gnus
+
+;; Copyright (C) 1995-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'nnheader)
+(require 'nnmail)
+(require 'gnus-start)
+(require 'gnus-group)
+(require 'nnmh)
+(require 'nnoo)
+(require 'mm-util)
+(eval-when-compile (require 'cl))
+
+;; The nnoo-import at the end, I think.
+(declare-function nndraft-request-list "nndraft" (&rest args) t)
+
+(nnoo-declare nndraft
+  nnmh)
+
+(defvoo nndraft-directory (nnheader-concat gnus-directory "drafts/")
+  "Where nndraft will store its files."
+  nnmh-directory)
+
+(defvar nndraft-required-headers '(Date)
+  "*Headers to be generated when saving a draft message.
+The headers in this variable and the ones in `message-required-headers'
+are generated if and only if they are also in `message-draft-headers'.")
+
+\f
+
+(defvoo nndraft-current-group "" nil nnmh-current-group)
+(defvoo nndraft-get-new-mail nil nil nnmh-get-new-mail)
+(defvoo nndraft-current-directory nil nil nnmh-current-directory)
+
+(defconst nndraft-version "nndraft 1.0")
+(defvoo nndraft-status-string "" nil nnmh-status-string)
+
+\f
+
+;;; Interface functions.
+
+(nnoo-define-basics nndraft)
+
+(deffoo nndraft-open-server (server &optional defs)
+  (nnoo-change-server 'nndraft server defs)
+  (cond
+   ((not (file-exists-p nndraft-directory))
+    (nndraft-close-server)
+    (nnheader-report 'nndraft "No such file or directory: %s"
+                    nndraft-directory))
+   ((not (file-directory-p (file-truename nndraft-directory)))
+    (nndraft-close-server)
+    (nnheader-report 'nndraft "Not a directory: %s" nndraft-directory))
+   (t
+    (nnheader-report 'nndraft "Opened server %s using directory %s"
+                    server nndraft-directory)
+    t)))
+
+(deffoo nndraft-retrieve-headers (articles &optional group server fetch-old)
+  (nndraft-possibly-change-group group)
+  (with-current-buffer nntp-server-buffer
+    (erase-buffer)
+    (let (article lines chars)
+      ;; We don't support fetching by Message-ID.
+      (if (stringp (car articles))
+         'headers
+       (while articles
+         (narrow-to-region (point) (point))
+         (when (nndraft-request-article
+                (setq article (pop articles)) group server (current-buffer))
+           (goto-char (point-min))
+           (if (search-forward "\n\n" nil t)
+               (forward-line -1)
+             (goto-char (point-max)))
+           (setq lines (count-lines (point) (point-max))
+                 chars (- (point-max) (point)))
+           (delete-region (point) (point-max))
+           (goto-char (point-min))
+           (insert (format "221 %d Article retrieved.\n" article))
+           (insert (format "Lines: %d\nChars: %d\n" lines chars))
+           (widen)
+           (goto-char (point-max))
+           (insert ".\n")))
+
+       (nnheader-fold-continuation-lines)
+       'headers))))
+
+(deffoo nndraft-request-article (id &optional group server buffer)
+  (nndraft-possibly-change-group group)
+  (when (numberp id)
+    ;; We get the newest file of the auto-saved file and the
+    ;; "real" file.
+    (let* ((file (nndraft-article-filename id))
+          (auto (nndraft-auto-save-file-name file))
+          (newest (if (file-newer-than-file-p file auto) file auto))
+          (nntp-server-buffer (or buffer nntp-server-buffer)))
+      (when (and (file-exists-p newest)
+                (let ((nnmail-file-coding-system
+                       (if (file-newer-than-file-p file auto)
+                           (if (member group '("drafts" "delayed"))
+                               message-draft-coding-system
+                             mm-text-coding-system)
+                         mm-auto-save-coding-system)))
+                  (nnmail-find-file newest)))
+       (with-current-buffer nntp-server-buffer
+         (goto-char (point-min))
+         ;; If there's a mail header separator in this file,
+         ;; we remove it.
+         (when (re-search-forward
+                (concat "^" (regexp-quote mail-header-separator) "$") nil t)
+           (replace-match "" t t)))
+       t))))
+
+(deffoo nndraft-request-restore-buffer (article &optional group server)
+  "Request a new buffer that is restored to the state of ARTICLE."
+  (nndraft-possibly-change-group group)
+  (when (nndraft-request-article article group server (current-buffer))
+    (message-remove-header "xref")
+    (message-remove-header "lines")
+    ;; 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)
+  (nndraft-possibly-change-group group)
+  (gnus-info-set-read
+   info
+   (gnus-update-read-articles (gnus-group-prefixed-name group '(nndraft ""))
+                             (nndraft-articles) t))
+  (let ((marks (nth 3 info)))
+    (when marks
+      ;; Nix out all marks except the `unsend'-able article marks.
+      (setcar (nthcdr 3 info)
+             (if (assq 'unsend marks)
+                 (list (assq 'unsend marks))
+               nil))))
+  t)
+
+(defun nndraft-generate-headers ()
+  (save-excursion
+    (message-generate-headers
+     (message-headers-to-generate
+      nndraft-required-headers message-draft-headers nil))))
+
+(defun nndraft-update-unread-articles ()
+  "Update groups' unread articles in the group buffer."
+  (nndraft-request-list)
+  (with-current-buffer gnus-group-buffer
+    (let* ((groups (mapcar (lambda (elem)
+                            (gnus-group-prefixed-name (car elem)
+                                                      (list 'nndraft "")))
+                          (nnmail-get-active)))
+          (gnus-group-marked (copy-sequence groups))
+          ;; Don't send delayed articles.
+          (gnus-get-new-news-hook nil)
+          (inhibit-read-only t))
+      (gnus-group-get-new-news-this-group nil t)
+      (save-excursion
+       (dolist (group groups)
+         (unless (and gnus-permanently-visible-groups
+                      (string-match gnus-permanently-visible-groups
+                                    group))
+           (gnus-group-goto-group group)
+           (when (zerop (gnus-group-group-unread))
+             (gnus-delete-line))))))))
+
+(deffoo nndraft-request-associate-buffer (group)
+  "Associate the current buffer with some article in the draft group."
+  (nndraft-open-server "")
+  (nndraft-request-group group)
+  (nndraft-possibly-change-group group)
+  (let ((gnus-verbose-backends nil)
+       (buf (current-buffer))
+       article file)
+    (with-temp-buffer
+      (insert-buffer-substring buf)
+      (setq article (nndraft-request-accept-article
+                    group (nnoo-current-server 'nndraft) t 'noinsert)
+           file (nndraft-article-filename article)))
+    (setq buffer-file-name (expand-file-name file)
+         buffer-auto-save-file-name (make-auto-save-file-name))
+    (clear-visited-file-modtime)
+    (let ((hook (if (boundp 'write-contents-functions)
+                   'write-contents-functions
+                 'write-contents-hooks)))
+      (gnus-make-local-hook hook)
+      (add-hook hook 'nndraft-generate-headers nil t))
+    (gnus-make-local-hook 'after-save-hook)
+    (add-hook 'after-save-hook 'nndraft-update-unread-articles nil t)
+    (message-add-action '(nndraft-update-unread-articles)
+                       'exit 'postpone 'kill)
+    article))
+
+(deffoo nndraft-request-group (group &optional server dont-check info)
+  (nndraft-possibly-change-group group)
+  (unless dont-check
+    (let* ((pathname (nnmail-group-pathname group nndraft-directory))
+          (file-name-coding-system nnmail-pathname-coding-system)
+          dir file)
+      (nnheader-re-read-dir pathname)
+      (setq dir (mapcar (lambda (name) (string-to-number (substring name 1)))
+                       (ignore-errors (directory-files
+                                       pathname nil "^#[0-9]+#$" t))))
+      (dolist (n dir)
+       (unless (file-exists-p
+                (setq file (expand-file-name (int-to-string n) pathname)))
+         (rename-file (nndraft-auto-save-file-name file) file)))))
+  (nnoo-parent-function 'nndraft
+                       'nnmh-request-group
+                       (list group server dont-check)))
+
+(deffoo nndraft-request-move-article (article group server accept-form
+                                     &optional last move-is-internal)
+  (nndraft-possibly-change-group group)
+  (let ((buf (get-buffer-create " *nndraft move*"))
+       result)
+    (and
+     (nndraft-request-article article group server)
+     (with-current-buffer buf
+       (erase-buffer)
+       (insert-buffer-substring nntp-server-buffer)
+       (setq result (eval accept-form))
+       (kill-buffer (current-buffer))
+       result)
+     (null (nndraft-request-expire-articles (list article) group server 'force))
+     result)))
+
+(deffoo nndraft-request-expire-articles (articles group &optional server force)
+  (nndraft-possibly-change-group group)
+  (let* ((nnmh-allow-delete-final t)
+        (nnmail-expiry-target 'delete)
+        ;; FIXME: If we want to move a draft message to an expiry group,
+        ;; there are things to have to improve:
+        ;; - Remove a header separator.
+        ;; - Encode it, including attachments, into a MIME message.
+        ;;(nnmail-expiry-target
+        ;; (or (gnus-group-find-parameter
+        ;;      (gnus-group-prefixed-name group (list 'nndraft server))
+        ;;      'expiry-target t)
+        ;;     nnmail-expiry-target))
+        (res (nnoo-parent-function 'nndraft
+                                   'nnmh-request-expire-articles
+                                   (list articles group server force)))
+        article)
+    ;; Delete all the "state" files of articles that have been expired.
+    (while articles
+      (unless (memq (setq article (pop articles)) res)
+       (let ((auto (nndraft-auto-save-file-name
+                    (nndraft-article-filename article))))
+         (when (file-exists-p auto)
+           (funcall nnmail-delete-file-function auto)))
+       (dolist (backup
+                (let ((kept-new-versions 1)
+                      (kept-old-versions 0))
+                  (find-backup-file-name
+                   (nndraft-article-filename article))))
+         (when (file-exists-p backup)
+           (funcall nnmail-delete-file-function backup)))))
+    res))
+
+(deffoo nndraft-request-accept-article (group &optional server last noinsert)
+  (nndraft-possibly-change-group group)
+  (let ((gnus-verbose-backends nil))
+    (nnoo-parent-function 'nndraft 'nnmh-request-accept-article
+                         (list group server last noinsert))))
+
+(deffoo nndraft-request-replace-article (article group buffer)
+  (nndraft-possibly-change-group group)
+  (let ((nnmail-file-coding-system
+        (if (member group '("drafts" "delayed"))
+            message-draft-coding-system
+          mm-text-coding-system)))
+    (nnoo-parent-function 'nndraft 'nnmh-request-replace-article
+                         (list article group buffer))))
+
+(deffoo nndraft-request-create-group (group &optional server args)
+  (nndraft-possibly-change-group group)
+  (if (file-exists-p nndraft-current-directory)
+      (if (file-directory-p nndraft-current-directory)
+         t
+       nil)
+    (condition-case ()
+       (progn
+         (gnus-make-directory nndraft-current-directory)
+         t)
+      (file-error nil))))
+
+\f
+;;; Low-Level Interface
+
+(defun nndraft-possibly-change-group (group)
+  (when (and group
+            (not (equal group nndraft-current-group)))
+    (nndraft-open-server "")
+    (setq nndraft-current-group group)
+    (setq nndraft-current-directory
+         (nnheader-concat nndraft-directory group))))
+
+(defun nndraft-article-filename (article &rest args)
+  (apply 'concat
+        (file-name-as-directory nndraft-current-directory)
+        (int-to-string article)
+        args))
+
+(defun nndraft-auto-save-file-name (file)
+  (save-excursion
+    (prog1
+       (progn
+         (set-buffer (get-buffer-create " *draft tmp*"))
+         (setq buffer-file-name file)
+         (make-auto-save-file-name))
+      (kill-buffer (current-buffer)))))
+
+(defun nndraft-articles ()
+  "Return the list of messages in the group."
+  (gnus-make-directory nndraft-current-directory)
+  (sort
+   (mapcar 'string-to-number
+          (directory-files nndraft-current-directory nil "\\`[0-9]+\\'" t))
+   '<))
+
+(nnoo-import nndraft
+  (nnmh
+   nnmh-retrieve-headers
+   nnmh-request-group
+   nnmh-close-group
+   nnmh-request-list))
+
+(provide 'nndraft)
+
+;;; nndraft.el ends here
diff --git a/xemacs-packages/gnus/lisp/nneething.el b/xemacs-packages/gnus/lisp/nneething.el
new file mode 100644 (file)
index 0000000..e60a492
--- /dev/null
@@ -0,0 +1,425 @@
+;;; nneething.el --- arbitrary file access for Gnus
+
+;; Copyright (C) 1995-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;;     Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
+;; Keywords: news, mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'mailcap)
+(require 'nnheader)
+(require 'nnmail)
+(require 'nnoo)
+(require 'gnus-util)
+
+(nnoo-declare nneething)
+
+(defvoo nneething-map-file-directory
+  (nnheader-concat gnus-directory ".nneething/")
+  "Where nneething stores the map files.")
+
+(defvoo nneething-map-file ".nneething"
+  "Name of the map files.")
+
+(defvoo nneething-exclude-files nil
+  "Regexp saying what files to exclude from the group.
+If this variable is nil, no files will be excluded.")
+
+(defvoo nneething-include-files nil
+  "Regexp saying what files to include in the group.
+If this variable is non-nil, only files matching this regexp will be
+included.")
+
+\f
+
+;;; Internal variables.
+
+(defconst nneething-version "nneething 1.0"
+  "nneething version.")
+
+(defvoo nneething-current-directory nil
+  "Current news group directory.")
+
+(defvoo nneething-status-string "")
+
+(defvoo nneething-work-buffer " *nneething work*")
+
+(defvoo nneething-group nil)
+(defvoo nneething-map nil)
+(defvoo nneething-read-only nil)
+(defvoo nneething-active nil)
+(defvoo nneething-address nil)
+
+\f
+
+;;; Interface functions.
+
+(nnoo-define-basics nneething)
+
+(deffoo nneething-retrieve-headers (articles &optional group server fetch-old)
+  (nneething-possibly-change-directory group)
+
+  (with-current-buffer nntp-server-buffer
+    (erase-buffer)
+    (let* ((number (length articles))
+          (count 0)
+          (large (and (numberp nnmail-large-newsgroup)
+                      (> number nnmail-large-newsgroup)))
+          article file)
+
+      (if (stringp (car articles))
+         'headers
+
+       (while (setq article (pop articles))
+         (setq file (nneething-file-name article))
+
+         (when (and (file-exists-p file)
+                    (or (file-directory-p file)
+                        (not (zerop (nnheader-file-size file)))))
+           (insert (format "221 %d Article retrieved.\n" article))
+           (nneething-insert-head file)
+           (insert ".\n"))
+
+         (incf count)
+
+         (and large
+              (zerop (% count 20))
+              (nnheader-message 5 "nneething: Receiving headers... %d%%"
+                                (floor (* count 100.0) number))))
+
+       (when large
+         (nnheader-message 5 "nneething: Receiving headers...done"))
+
+       (nnheader-fold-continuation-lines)
+       'headers))))
+
+(deffoo nneething-request-article (id &optional group server buffer)
+  (nneething-possibly-change-directory group)
+  (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.
+        (file-exists-p file)           ; The file exists.
+        (not (file-directory-p file))  ; It's not a dir.
+        (save-excursion
+          (let ((nnmail-file-coding-system 'binary))
+            (nnmail-find-file file))   ; Insert the file in the nntp buf.
+          (unless (nnheader-article-p) ; Either it's a real article...
+            (let ((type
+                   (unless (file-directory-p file)
+                     (or (cdr (assoc (concat "." (file-name-extension file))
+                                     mailcap-mime-extensions))
+                         "text/plain")))
+                  (charset
+                   (mm-detect-mime-charset-region (point-min) (point-max)))
+                  (encoding))
+              (unless (string-match "\\`text/" type)
+                (base64-encode-region (point-min) (point-max))
+                (setq encoding "base64"))
+              (goto-char (point-min))
+              (nneething-make-head file (current-buffer)
+                                   nil type charset encoding))
+            (insert "\n"))
+          t))))
+
+(deffoo nneething-request-group (group &optional server dont-check info)
+  (nneething-possibly-change-directory group server)
+  (unless dont-check
+    (nneething-create-mapping)
+    (if (> (car nneething-active) (cdr nneething-active))
+       (nnheader-insert "211 0 1 0 %s\n" group)
+      (nnheader-insert
+       "211 %d %d %d %s\n"
+       (- (1+ (cdr nneething-active)) (car nneething-active))
+       (car nneething-active) (cdr nneething-active)
+       group)))
+  t)
+
+(deffoo nneething-request-list (&optional server dir)
+  (nnheader-report 'nneething "LIST is not implemented."))
+
+(deffoo nneething-request-newgroups (date &optional server)
+  (nnheader-report 'nneething "NEWSGROUPS is not implemented."))
+
+(deffoo nneething-request-type (group &optional article)
+  'unknown)
+
+(deffoo nneething-close-group (group &optional server)
+  (setq nneething-current-directory nil)
+  t)
+
+(deffoo nneething-open-server (server &optional defs)
+  (nnheader-init-server-buffer)
+  (if (nneething-server-opened server)
+      t
+    (unless (assq 'nneething-address defs)
+      (setq defs (append defs (list (list 'nneething-address server)))))
+    (nnoo-change-server 'nneething server defs)))
+
+\f
+;;; Internal functions.
+
+(defun nneething-possibly-change-directory (group &optional server)
+  (when (and server
+            (not (nneething-server-opened server)))
+    (nneething-open-server server))
+  (when (and group
+            (not (equal nneething-group group)))
+    (setq nneething-group group)
+    (setq nneething-map nil)
+    (setq nneething-active (cons 1 0))
+    (nneething-create-mapping)))
+
+(defun nneething-map-file ()
+  ;; We make sure that the .nneething directory exists.
+  (gnus-make-directory nneething-map-file-directory)
+  ;; We store it in a special directory under the user's home dir.
+  (concat (file-name-as-directory nneething-map-file-directory)
+         nneething-group nneething-map-file))
+
+(defun nneething-create-mapping ()
+  ;; Read nneething-active and nneething-map.
+  (when (file-exists-p nneething-address)
+    (let ((map-file (nneething-map-file))
+         (files (directory-files nneething-address))
+         touched map-files)
+      (when (file-exists-p map-file)
+       (ignore-errors
+         (load map-file nil t t)))
+      (unless nneething-active
+       (setq nneething-active (cons 1 0)))
+      ;; Old nneething had a different map format.
+      (when (and (cdar nneething-map)
+                (atom (cdar nneething-map)))
+       (setq nneething-map
+             (mapcar (lambda (n)
+                       (list (cdr n) (car n)
+                             (nth 5 (file-attributes
+                                     (nneething-file-name (car n))))))
+                     nneething-map)))
+      ;; Remove files matching the exclusion regexp.
+      (when nneething-exclude-files
+       (let ((f files)
+             prev)
+         (while f
+           (if (string-match nneething-exclude-files (car f))
+               (if prev (setcdr prev (cdr f))
+                 (setq files (cdr files)))
+             (setq prev f))
+           (setq f (cdr f)))))
+      ;; Remove files not matching the inclusion regexp.
+      (when nneething-include-files
+       (let ((f files)
+             prev)
+         (while f
+           (if (not (string-match nneething-include-files (car f)))
+               (if prev (setcdr prev (cdr f))
+                 (setq files (cdr files)))
+             (setq prev f))
+           (setq f (cdr f)))))
+      ;; Remove deleted files from the map.
+      (let ((map nneething-map)
+           prev)
+       (while map
+         (if (and (member (cadr (car map)) files)
+                 ;; We also remove files that have changed mod times.
+                  (equal (nth 5 (file-attributes
+                                 (nneething-file-name (cadr (car map)))))
+                         (cadr (cdar map))))
+             (progn
+               (push (cadr (car map)) map-files)
+               (setq prev map))
+           (setq touched t)
+           (if prev
+               (setcdr prev (cdr map))
+             (setq nneething-map (cdr nneething-map))))
+         (setq map (cdr map))))
+      ;; Find all new files and enter them into the map.
+      (while files
+       (unless (member (car files) map-files)
+         ;; This file is not in the map, so we enter it.
+         (setq touched t)
+         (setcdr nneething-active (1+ (cdr nneething-active)))
+         (push (list (cdr nneething-active) (car files)
+                     (nth 5 (file-attributes
+                             (nneething-file-name (car files)))))
+               nneething-map))
+       (setq files (cdr files)))
+      (when (and touched
+                (not nneething-read-only))
+       (with-temp-file map-file
+         (insert "(setq nneething-map '")
+         (gnus-prin1 nneething-map)
+         (insert ")\n(setq nneething-active '")
+         (gnus-prin1 nneething-active)
+         (insert ")\n"))))))
+
+(defun nneething-insert-head (file)
+  "Insert the head of FILE."
+  (when (nneething-get-head file)
+    (insert-buffer-substring nneething-work-buffer)
+    (goto-char (point-max))))
+
+(defun nneething-encode-file-name (file &optional coding-system)
+  "Encode the name of the FILE in CODING-SYSTEM."
+  (let ((pos 0) buf)
+    (setq file (mm-encode-coding-string
+               file (or coding-system nnmail-pathname-coding-system)))
+    (while (string-match "[^-0-9a-zA-Z_:/.]" file pos)
+      (setq buf (cons (format "%%%02x" (aref file (match-beginning 0)))
+                     (cons (substring file pos (match-beginning 0)) buf))
+           pos (match-end 0)))
+    (apply (function concat)
+          (nreverse (cons (substring file pos) buf)))))
+
+(defun nneething-decode-file-name (file &optional coding-system)
+  "Decode the name of the FILE is encoded in CODING-SYSTEM."
+  (let ((pos 0) buf)
+    (while (string-match "%\\([0-9a-fA-F][0-9a-fA-F]\\)" file pos)
+      (setq buf (cons (string (string-to-number (match-string 1 file) 16))
+                     (cons (substring file pos (match-beginning 0)) buf))
+           pos (match-end 0)))
+    (mm-decode-coding-string
+     (apply (function concat)
+           (nreverse (cons (substring file pos) buf)))
+     (or coding-system nnmail-pathname-coding-system))))
+
+(defun nneething-get-file-name (id)
+  "Extract the file name from the message ID string."
+  (when (string-match "\\`<nneething-\\([^@]+\\)@.*>\\'" id)
+    (nneething-decode-file-name (match-string 1 id))))
+
+(defun nneething-make-head (file &optional buffer extra-msg
+                                mime-type mime-charset mime-encoding)
+  "Create a head by looking at the file attributes of FILE."
+  (let ((atts (file-attributes file)))
+    (insert
+     "Subject: " (file-name-nondirectory file) (or extra-msg "") "\n"
+     "Message-ID: <nneething-" (nneething-encode-file-name file)
+     "@" (system-name) ">\n"
+     (if (equal '(0 0) (nth 5 atts)) ""
+       (concat "Date: " (current-time-string (nth 5 atts)) "\n"))
+     (or (when buffer
+          (with-current-buffer buffer
+            (when (re-search-forward "<[a-zA-Z0-9_]@[-a-zA-Z0-9_]>" 1000 t)
+              (concat "From: " (match-string 0) "\n"))))
+        (nneething-from-line (nth 2 atts) file))
+     (if (> (string-to-number (int-to-string (nth 7 atts))) 0)
+        (concat "Chars: " (int-to-string (nth 7 atts)) "\n")
+       "")
+     (if buffer
+        (with-current-buffer buffer
+          (concat "Lines: " (int-to-string
+                             (count-lines (point-min) (point-max)))
+                  "\n"))
+       "")
+     (if mime-type
+        (concat "Content-Type: " mime-type
+                (if mime-charset
+                    (concat "; charset="
+                            (if (stringp mime-charset)
+                                mime-charset
+                              (symbol-name mime-charset)))
+                  "")
+                (if mime-encoding
+                    (concat "\nContent-Transfer-Encoding: " mime-encoding)
+                  "")
+                "\nMIME-Version: 1.0\n")
+       ""))))
+
+(defun nneething-from-line (uid &optional file)
+  "Return a From header based of UID."
+  (let* ((login (condition-case nil
+                   (user-login-name uid)
+                 (error
+                  (cond ((= uid (user-uid)) (user-login-name))
+                        ((zerop uid) "root")
+                        (t (int-to-string uid))))))
+        (name (condition-case nil
+                  (user-full-name uid)
+                (error
+                 (cond ((= uid (user-uid)) (user-full-name))
+                       ((zerop uid) "Ms. Root")))))
+        (host (if  (string-match "\\`/[^/@]*@\\([^:/]+\\):" file)
+                  (prog1
+                      (substring file
+                                 (match-beginning 1)
+                                 (match-end 1))
+                    (when (string-match
+                           "/\\(users\\|home\\)/\\([^/]+\\)/" file)
+                      (setq login (substring file
+                                             (match-beginning 2)
+                                             (match-end 2))
+                            name nil)))
+                (system-name))))
+    (concat "From: " login "@" host
+           (if name (concat " (" name ")") "") "\n")))
+
+(defun nneething-get-head (file)
+  "Either find the head in FILE or make a head for FILE."
+  (with-current-buffer (get-buffer-create nneething-work-buffer)
+    (setq case-fold-search nil)
+    (buffer-disable-undo)
+    (erase-buffer)
+    (cond
+     ((not (file-exists-p file))
+      ;; The file do not exist.
+      nil)
+     ((or (file-directory-p file)
+         (file-symlink-p file))
+      ;; It's a dir, so we fudge a head.
+      (nneething-make-head file) t)
+     (t
+      ;; We examine the file.
+      (condition-case ()
+         (progn
+           (nnheader-insert-head file)
+           (if (nnheader-article-p)
+               (delete-region
+                (progn
+                  (goto-char (point-min))
+                  (or (and (search-forward "\n\n" nil t)
+                           (1- (point)))
+                      (point-max)))
+                (point-max))
+             (goto-char (point-min))
+             (nneething-make-head file (current-buffer))
+             (delete-region (point) (point-max))))
+       (file-error
+        (nneething-make-head file (current-buffer) " (unreadable)")))
+      t))))
+
+(defun nneething-file-name (article)
+  "Return the file name of ARTICLE."
+  (let ((dir (file-name-as-directory nneething-address))
+       fname)
+    (if (numberp article)
+       (if (setq fname (cadr (assq article nneething-map)))
+           (expand-file-name fname dir)
+         (make-temp-name (expand-file-name "nneething" dir)))
+      (expand-file-name article dir))))
+
+(provide 'nneething)
+
+;;; nneething.el ends here
diff --git a/xemacs-packages/gnus/lisp/nnfolder.el b/xemacs-packages/gnus/lisp/nnfolder.el
new file mode 100644 (file)
index 0000000..ee60e3e
--- /dev/null
@@ -0,0 +1,1181 @@
+;;; nnfolder.el --- mail folder access for Gnus
+
+;; Copyright (C) 1995-2016 Free Software Foundation, Inc.
+
+;; Author: Simon Josefsson <simon@josefsson.org>
+;;      ShengHuo Zhu <zsh@cs.rochester.edu> (adding NOV)
+;;      Scott Byer <byer@mv.us.adobe.com>
+;;     Lars Magne Ingebrigtsen <larsi@gnus.org>
+;;     Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
+;; Keywords: mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'nnheader)
+(require 'message)
+(require 'nnmail)
+(require 'nnoo)
+(eval-when-compile (require 'cl))
+(require 'gnus)
+(require 'gnus-util)
+(require 'gnus-range)
+
+;; FIXME not explicitly used in this file.
+(autoload 'gnus-article-unpropagatable-p "gnus-sum")
+
+(nnoo-declare nnfolder)
+
+(defvoo nnfolder-directory (expand-file-name message-directory)
+  "The name of the nnfolder directory.")
+
+(defvoo nnfolder-nov-directory nil
+  "The name of the nnfolder NOV directory.
+If nil, `nnfolder-directory' is used.")
+
+(defvoo nnfolder-active-file
+    (nnheader-concat nnfolder-directory "active")
+  "The name of the active file.")
+
+;; I renamed this variable to something more in keeping with the general GNU
+;; style. -SLB
+
+(defvoo nnfolder-ignore-active-file nil
+  "If non-nil, the active file is ignored.
+This causes nnfolder to do some extra work in order to determine the
+true active ranges of an mbox file.  Note that the active file is
+still saved, but its values are not used.  This costs some extra time
+when scanning an mbox when opening it.")
+
+(defvoo nnfolder-distrust-mbox nil
+  "If non-nil, the folder will be distrusted.
+This means that nnfolder will not trust the user with respect to
+inserting unaccounted for mail in the middle of an mbox file.  This
+can greatly slow down scans, which now must scan the entire file for
+unmarked messages.  When nil, scans occur forward from the last marked
+message, a huge time saver for large mailboxes.")
+
+(defvoo nnfolder-newsgroups-file
+    (concat (file-name-as-directory nnfolder-directory) "newsgroups")
+  "Mail newsgroups description file.")
+
+(defvoo nnfolder-get-new-mail t
+  "If non-nil, nnfolder will check the incoming mail file and split the mail.")
+
+(defvoo nnfolder-prepare-save-mail-hook nil
+  "Hook run narrowed to an article before saving.")
+
+(defvoo nnfolder-save-buffer-hook nil
+  "Hook run before saving the nnfolder mbox buffer.")
+
+
+(defvoo nnfolder-inhibit-expiry nil
+  "If non-nil, inhibit expiry.")
+
+\f
+
+(defconst nnfolder-version "nnfolder 2.0"
+  "nnfolder version.")
+
+(defconst nnfolder-article-marker "X-Gnus-Article-Number: "
+  "String used to demarcate what the article number for a message is.")
+
+(defvoo nnfolder-current-group nil)
+(defvoo nnfolder-current-buffer nil)
+(defvoo nnfolder-status-string "")
+(defvoo nnfolder-group-alist nil)
+(defvoo nnfolder-buffer-alist nil)
+(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
+    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.") ; 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.
+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 `nnfolder-generate-active-file' command.  The function will go
+through all nnfolder directories and generate nov databases for them
+all.  This may very well take some time.")
+
+(defvoo nnfolder-nov-file-suffix ".nov")
+
+(defvoo nnfolder-nov-buffer-alist nil)
+
+(defvar nnfolder-nov-buffer-file-name nil)
+
+\f
+
+;;; Interface functions
+
+(nnoo-define-basics nnfolder)
+
+(deffoo nnfolder-retrieve-headers (articles &optional group server fetch-old)
+  (with-current-buffer nntp-server-buffer
+    (erase-buffer)
+    (let (article start stop num)
+      (nnfolder-possibly-change-group group server)
+      (when nnfolder-current-buffer
+       (set-buffer nnfolder-current-buffer)
+       (goto-char (point-min))
+       (if (stringp (car articles))
+           'headers
+         (if (nnfolder-retrieve-headers-with-nov articles fetch-old)
+             'nov
+           (setq articles (gnus-sorted-intersection
+                           ;; Is ARTICLES sorted?
+                           (sort articles '<)
+                           (nnfolder-existing-articles)))
+           (while (setq article (pop articles))
+             (set-buffer nnfolder-current-buffer)
+             (cond ((nnfolder-goto-article article)
+                    (setq start (point))
+                    (setq stop (if (search-forward "\n\n" nil t)
+                                   (1- (point))
+                                 (point-max)))
+                    (set-buffer nntp-server-buffer)
+                    (insert (format "221 %d Article retrieved.\n" article))
+                    (insert-buffer-substring nnfolder-current-buffer
+                                             start stop)
+                    (goto-char (point-max))
+                    (insert ".\n"))
+
+                   ;; If we couldn't find this article, skip over ranges
+                   ;; of missing articles so we don't search the whole file
+                   ;; for each of them.
+                   ((numberp article)
+                    (setq start (point))
+                    (and
+                     ;; Check that we are either at BOF or after an
+                     ;; article with a lower number.  We do this so we
+                     ;; won't be confused by out-of-order article numbers,
+                     ;; as caused by active file bogosity.
+                     (cond
+                      ((bobp))
+                      ((search-backward (concat "\n" nnfolder-article-marker)
+                                        nil t)
+                       (goto-char (match-end 0))
+                       (setq num (string-to-number
+                                  (buffer-substring
+                                   (point) (point-at-eol))))
+                       (goto-char start)
+                       (< num article)))
+                     ;; Check that we are before an article with a
+                     ;; higher number.
+                     (search-forward (concat "\n" nnfolder-article-marker)
+                                     nil t)
+                     (progn
+                       (setq num (string-to-number
+                                  (buffer-substring
+                                   (point) (point-at-eol))))
+                       (> num article))
+                     ;; Discard any article numbers before the one we're
+                     ;; now looking at.
+                     (while (and articles
+                                 (< (car articles) num))
+                       (setq articles (cdr articles))))
+                    (goto-char start))))
+           (set-buffer nntp-server-buffer)
+           (nnheader-fold-continuation-lines)
+           'headers))))))
+
+(deffoo nnfolder-open-server (server &optional defs)
+  (nnoo-change-server 'nnfolder server defs)
+  (nnmail-activate 'nnfolder t)
+  (gnus-make-directory nnfolder-directory)
+  (unless (or gnus-nov-is-evil nnfolder-nov-is-evil)
+    (and nnfolder-nov-directory
+        (gnus-make-directory nnfolder-nov-directory)))
+  (cond
+   ((not (file-exists-p nnfolder-directory))
+    (nnfolder-close-server)
+    (nnheader-report 'nnfolder "Couldn't create directory: %s"
+                    nnfolder-directory))
+   ((not (file-directory-p (file-truename nnfolder-directory)))
+    (nnfolder-close-server)
+    (nnheader-report 'nnfolder "Not a directory: %s" nnfolder-directory))
+   (t
+    (nnmail-activate 'nnfolder)
+    (nnheader-report 'nnfolder "Opened server %s using directory %s"
+                    server nnfolder-directory)
+    t)))
+
+(deffoo nnfolder-request-close ()
+  (let ((alist nnfolder-buffer-alist))
+    (while alist
+      (nnfolder-close-group (caar alist) nil t)
+      (setq alist (cdr alist))))
+  (nnoo-close-server 'nnfolder)
+  (setq nnfolder-buffer-alist nil
+       nnfolder-group-alist nil))
+
+(deffoo nnfolder-request-article (article &optional group server buffer)
+  (nnfolder-possibly-change-group group server)
+  (with-current-buffer nnfolder-current-buffer
+    (goto-char (point-min))
+    (when (nnfolder-goto-article article)
+      (let (start stop)
+       (setq start (point))
+       (forward-line 1)
+       (unless (and (nnmail-search-unix-mail-delim)
+                    (forward-line -1))
+         (goto-char (point-max)))
+       (setq stop (point))
+       (let ((nntp-server-buffer (or buffer nntp-server-buffer)))
+         (set-buffer nntp-server-buffer)
+         (erase-buffer)
+         (insert-buffer-substring nnfolder-current-buffer start stop)
+         (goto-char (point-min))
+         (while (looking-at "From ")
+           (delete-char 5)
+           (insert "X-From-Line: ")
+           (forward-line 1))
+         (if (numberp article)
+             (cons nnfolder-current-group article)
+           (goto-char (point-min))
+           (cons nnfolder-current-group
+                 (if (search-forward (concat "\n" nnfolder-article-marker)
+                                     nil t)
+                     (string-to-number (buffer-substring
+                                     (point) (point-at-eol)))
+                   -1))))))))
+
+(deffoo nnfolder-request-group (group &optional server dont-check info)
+  (nnfolder-possibly-change-group group server t)
+  (save-excursion
+    (cond ((not (assoc group nnfolder-group-alist))
+          (nnheader-report 'nnfolder "No such group: %s" group))
+         ((file-directory-p (nnfolder-group-pathname group))
+          (nnheader-report 'nnfolder "%s is a directory"
+                           (file-name-as-directory
+                            (let ((nnmail-pathname-coding-system nil))
+                              (nnfolder-group-pathname group)))))
+         (dont-check
+          (nnheader-report 'nnfolder "Selected group %s" group)
+          t)
+         (t
+          (let* ((active (assoc group nnfolder-group-alist))
+                 (group (car active))
+                 (range (cadr active)))
+            (cond
+             ((null active)
+              (nnheader-report 'nnfolder "No such group: %s" group))
+             ((null nnfolder-current-group)
+              (nnheader-report 'nnfolder "Empty group: %s" group))
+             (t
+              (nnheader-report 'nnfolder "Selected group %s" group)
+              (nnheader-insert "211 %d %d %d %s\n"
+                               (1+ (- (cdr range) (car range)))
+                               (car range) (cdr range) group))))))))
+
+(deffoo nnfolder-request-scan (&optional group server)
+  (nnfolder-possibly-change-group nil server)
+  (when nnfolder-get-new-mail
+    (nnfolder-possibly-change-group group server)
+    (nnmail-get-new-mail
+     'nnfolder 'nnfolder-save-all-buffers
+     nnfolder-directory group)))
+
+(defun nnfolder-save-all-buffers ()
+  (let ((bufs nnfolder-buffer-alist))
+    (save-excursion
+      (while bufs
+       (if (not (gnus-buffer-live-p (nth 1 (car bufs))))
+           (setq nnfolder-buffer-alist
+                 (delq (car bufs) nnfolder-buffer-alist))
+         (set-buffer (nth 1 (car bufs)))
+         (nnfolder-save-buffer)
+         (kill-buffer (current-buffer)))
+       (setq bufs (cdr bufs))))))
+
+;; Don't close the buffer if we're not shutting down the server.  This way,
+;; we can keep the buffer in the group buffer cache, and not have to grovel
+;; over the buffer again unless we add new mail to it or modify it in some
+;; way.
+
+(deffoo nnfolder-close-group (group &optional server force)
+  ;; Make sure we _had_ the group open.
+  (when (or (assoc group nnfolder-buffer-alist)
+           (equal group nnfolder-current-group))
+    (let ((inf (assoc group nnfolder-buffer-alist)))
+      (when inf
+       (when (and nnfolder-current-group
+                  nnfolder-current-buffer)
+         (push (list nnfolder-current-group nnfolder-current-buffer)
+               nnfolder-buffer-alist))
+       (setq nnfolder-buffer-alist
+             (delq inf nnfolder-buffer-alist))
+       (setq nnfolder-current-buffer (cadr inf)
+             nnfolder-current-group (car inf))))
+    (when (and nnfolder-current-buffer
+              (buffer-name nnfolder-current-buffer))
+      (with-current-buffer nnfolder-current-buffer
+       ;; If the buffer was modified, write the file out now.
+       (nnfolder-save-buffer)
+       ;; If we're shutting the server down, we need to kill the
+       ;; buffer and remove it from the open buffer list.  Or, of
+       ;; course, if we're trying to minimize our space impact.
+       (kill-buffer (current-buffer))
+       (setq nnfolder-buffer-alist (delq (assoc group nnfolder-buffer-alist)
+                                         nnfolder-buffer-alist)))))
+  (setq nnfolder-current-group nil
+       nnfolder-current-buffer nil)
+  t)
+
+(deffoo nnfolder-request-create-group (group &optional server args)
+  (nnfolder-possibly-change-group nil server)
+  (nnmail-activate 'nnfolder)
+  (cond ((zerop (length group))
+        (nnheader-report 'nnfolder "Invalid (empty) group name"))
+       ((file-directory-p (nnfolder-group-pathname group))
+        (nnheader-report 'nnfolder "%s is a directory"
+                         (file-name-as-directory
+                          (let ((nnmail-pathname-coding-system nil))
+                            (nnfolder-group-pathname group)))))
+       ((assoc group nnfolder-group-alist)
+        t)
+       (t
+        (push (list group (cons 1 0)) nnfolder-group-alist)
+        (nnfolder-save-active nnfolder-group-alist nnfolder-active-file)
+        (save-current-buffer
+          (nnfolder-read-folder group))
+        t)))
+
+(deffoo nnfolder-request-list (&optional server)
+  (nnfolder-possibly-change-group nil server)
+  (save-excursion
+    (let ((nnmail-file-coding-system nnfolder-active-file-coding-system))
+      (nnmail-find-file nnfolder-active-file)
+      (setq nnfolder-group-alist (nnmail-get-active)))
+    t))
+
+(deffoo nnfolder-request-newgroups (date &optional server)
+  (nnfolder-possibly-change-group nil server)
+  (nnfolder-request-list server))
+
+(deffoo nnfolder-request-list-newsgroups (&optional server)
+  (nnfolder-possibly-change-group nil server)
+  (save-excursion
+    (let ((nnmail-file-coding-system nnfolder-file-coding-system))
+      (nnmail-find-file nnfolder-newsgroups-file))))
+
+;; Return a list consisting of all article numbers existing in the
+;; current folder.
+
+(defun nnfolder-existing-articles ()
+  (save-excursion
+    (when nnfolder-current-buffer
+      (set-buffer nnfolder-current-buffer)
+      (goto-char (point-min))
+      (let ((marker (concat "\n" nnfolder-article-marker))
+           (number "[0-9]+")
+           numbers)
+       (while (and (search-forward marker nil t)
+                   (re-search-forward number nil t))
+         (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.
+       (nreverse numbers)))))
+
+(autoload 'gnus-request-group "gnus-int")
+(declare-function gnus-request-create-group "gnus-int"
+                  (group &optional gnus-command-method args))
+
+(deffoo nnfolder-request-expire-articles (articles newsgroup
+                                                  &optional server force)
+  (nnfolder-possibly-change-group newsgroup server)
+  (let ((is-old t)
+       ;; The articles we have deleted so far.
+       (deleted-articles nil)
+       ;; The articles that really exist and will
+       ;; be expired if they are old enough.
+       (maybe-expirable
+        (gnus-sorted-intersection articles (nnfolder-existing-articles)))
+       target)
+    (nnmail-activate 'nnfolder)
+
+    (with-current-buffer nnfolder-current-buffer
+      ;; Since messages are sorted in arrival order and expired in the
+      ;; same order, we can stop as soon as we find a message that is
+      ;; too old.
+      (while (and maybe-expirable is-old)
+       (goto-char (point-min))
+       (when (and (nnfolder-goto-article (car maybe-expirable))
+                  (search-forward (concat "\n" nnfolder-article-marker)
+                                  nil t))
+         (forward-sexp)
+         (when (setq is-old
+                     (nnmail-expired-article-p
+                      newsgroup
+                      (buffer-substring
+                       (point) (progn (end-of-line) (point)))
+                      force nnfolder-inhibit-expiry))
+           (setq target nnmail-expiry-target)
+           (unless (eq target 'delete)
+             (with-temp-buffer
+               (nnfolder-request-article (car maybe-expirable)
+                                         newsgroup server (current-buffer))
+               (let ((nnfolder-current-directory nil))
+                 (when (functionp target)
+                   (setq target (funcall target newsgroup)))
+                 (when (and target (not (eq target 'delete)))
+                   (if (or (gnus-request-group target)
+                           (gnus-request-create-group target))
+                       (nnmail-expiry-target-group target newsgroup)
+                     (setq target nil)))))
+             (nnfolder-possibly-change-group newsgroup server))
+           (when target
+             (nnheader-message 5 "Deleting article %d in %s..."
+                               (car maybe-expirable) newsgroup)
+             (nnfolder-delete-mail)
+             (unless (or gnus-nov-is-evil nnfolder-nov-is-evil)
+               (nnfolder-nov-delete-article newsgroup (car maybe-expirable)))
+             ;; Must remember which articles were actually deleted
+             (push (car maybe-expirable) deleted-articles))))
+       (setq maybe-expirable (cdr maybe-expirable)))
+      (unless nnfolder-inhibit-expiry
+       (nnheader-message 5 "Deleting articles...done"))
+      (nnfolder-save-buffer)
+      (nnfolder-adjust-min-active newsgroup)
+      (nnfolder-save-active nnfolder-group-alist nnfolder-active-file)
+      (nnfolder-save-all-buffers)
+      (gnus-sorted-difference articles (nreverse deleted-articles)))))
+
+(deffoo nnfolder-request-move-article (article group server accept-form
+                                              &optional last move-is-internal)
+  (save-excursion
+    (let ((buf (get-buffer-create " *nnfolder move*"))
+         result)
+      (and
+       (nnfolder-request-article article group server)
+       (with-current-buffer buf
+        (erase-buffer)
+        (insert-buffer-substring nntp-server-buffer)
+        (goto-char (point-min))
+        (while (re-search-forward
+                (concat "^" nnfolder-article-marker)
+                (save-excursion (and (search-forward "\n\n" nil t) (point)))
+                t)
+          (gnus-delete-line))
+        (setq result (eval accept-form))
+        (kill-buffer buf)
+        result)
+       (save-excursion
+        (nnfolder-possibly-change-group group server)
+        (set-buffer nnfolder-current-buffer)
+        (goto-char (point-min))
+        (when (nnfolder-goto-article article)
+          (nnfolder-delete-mail))
+        (unless (or gnus-nov-is-evil nnfolder-nov-is-evil)
+          (nnfolder-nov-delete-article group article))
+        (when last
+          (nnfolder-save-buffer)
+          (nnfolder-adjust-min-active group)
+          (nnfolder-save-active nnfolder-group-alist nnfolder-active-file))))
+      result)))
+
+(deffoo nnfolder-request-accept-article (group &optional server last)
+  (save-excursion
+    (nnfolder-possibly-change-group group server)
+    (nnmail-check-syntax)
+    (let ((buf (current-buffer))
+         result art-group)
+      (goto-char (point-min))
+      (when (looking-at "X-From-Line: ")
+       (replace-match "From ")
+       (while (progn (forward-line) (looking-at "[ \t]"))
+         (delete-char -1)))
+      (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")
+                              group
+                              (nnmail-fetch-field "subject")
+                              (nnmail-fetch-field "from")))
+       (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"))
+      result)))
+
+(deffoo nnfolder-request-replace-article (article group buffer)
+  (nnfolder-possibly-change-group group)
+  (with-current-buffer buffer
+    (goto-char (point-min))
+    (if (not (looking-at "X-From-Line: "))
+       (insert "From nobody " (current-time-string) "\n")
+      (replace-match "From ")
+      (forward-line 1)
+      (while (looking-at "[ \t]")
+       (delete-char -1)
+       (forward-line 1)))
+    (nnfolder-normalize-buffer)
+    (set-buffer nnfolder-current-buffer)
+    (goto-char (point-min))
+    (if (not (nnfolder-goto-article article))
+       nil
+      (nnfolder-delete-mail)
+      (insert-buffer-substring buffer)
+      (unless (or gnus-nov-is-evil nnfolder-nov-is-evil)
+       (with-current-buffer buffer
+         (let ((headers (nnfolder-parse-head article
+                                             (point-min) (point-max))))
+           (with-current-buffer (nnfolder-open-nov group)
+             (if (nnheader-find-nov-line article)
+                 (delete-region (point) (progn (forward-line 1) (point))))
+             (nnheader-insert-nov headers)))))
+      (nnfolder-save-buffer)
+      t)))
+
+(deffoo nnfolder-request-delete-group (group &optional force server)
+  (nnfolder-close-group group server t)
+  ;; Delete all articles in GROUP.
+  (if (not force)
+      ()                               ; Don't delete the articles.
+    ;; Delete the file that holds the group.
+    (let ((data (nnfolder-group-pathname group))
+         (nov (nnfolder-group-nov-pathname group)))
+      (ignore-errors (delete-file data))
+      (ignore-errors (delete-file nov))))
+  ;; Remove the group from all structures.
+  (setq nnfolder-group-alist
+       (delq (assoc group nnfolder-group-alist) nnfolder-group-alist)
+       nnfolder-current-group nil
+       nnfolder-current-buffer nil)
+  ;; Save the active file.
+  (nnfolder-save-active nnfolder-group-alist nnfolder-active-file)
+  t)
+
+(deffoo nnfolder-request-rename-group (group new-name &optional server)
+  (nnfolder-possibly-change-group group server)
+  (with-current-buffer nnfolder-current-buffer
+    (and (file-writable-p buffer-file-name)
+        (ignore-errors
+          (let ((new-file (nnfolder-group-pathname new-name)))
+            (gnus-make-directory (file-name-directory new-file))
+            (rename-file buffer-file-name 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)))
+          t)
+        ;; That went ok, so we change the internal structures.
+        (let ((entry (assoc group nnfolder-group-alist)))
+          (and entry (setcar entry new-name))
+          (setq nnfolder-current-buffer nil
+                nnfolder-current-group nil)
+          ;; Save the new group alist.
+          (nnfolder-save-active nnfolder-group-alist nnfolder-active-file)
+          ;; We kill the buffer instead of renaming it and stuff.
+          (kill-buffer (current-buffer))
+          t))))
+
+(deffoo nnfolder-request-regenerate (server)
+  (nnfolder-possibly-change-group nil server)
+  (nnfolder-generate-active-file)
+  t)
+
+\f
+;;; Internal functions.
+
+(defun nnfolder-adjust-min-active (group)
+  ;; Find the lowest active article in this group.
+  (let* ((active (cadr (assoc group nnfolder-group-alist)))
+        (marker (concat "\n" nnfolder-article-marker))
+        (number "[0-9]+")
+        (activemin (cdr active)))
+    (with-current-buffer nnfolder-current-buffer
+      (goto-char (point-min))
+      (while (and (search-forward marker nil t)
+                 (re-search-forward number nil t))
+       (let ((newnum (string-to-number (match-string 0))))
+         (if (nnmail-within-headers-p)
+             (setq activemin (min activemin newnum)))))
+      (setcar active activemin))))
+
+(defun nnfolder-article-string (article)
+  (if (numberp article)
+      (concat "\n" nnfolder-article-marker (int-to-string article) " ")
+    (concat "\nMessage-ID: " article)))
+
+(defun nnfolder-goto-article (article)
+  "Place point at the start of the headers of ARTICLE.
+ARTICLE can be an article number or a Message-ID.
+Returns t if successful, nil otherwise."
+  (let ((art-string (nnfolder-article-string article))
+       start found)
+    ;; It is likely that we are at or before the delimiter line.
+    ;; We therefore go to the end of the previous line, and start
+    ;; searching from there.
+    (beginning-of-line)
+    (unless (bobp)
+      (forward-char -1))
+    (setq start (point))
+    ;; First search forward.
+    (while (and (setq found (search-forward art-string nil t))
+               (not (nnmail-within-headers-p))))
+    ;; If unsuccessful, search backward from where we started,
+    (unless found
+      (goto-char start)
+      (while (and (setq found (search-backward art-string nil t))
+                 (not (nnmail-within-headers-p)))))
+    (when found
+      (nnmail-search-unix-mail-delim-backward))))
+
+(defun nnfolder-delete-mail (&optional leave-delim)
+  "Delete the message that point is in.
+If optional argument LEAVE-DELIM is t, then mailbox delimiter is not
+deleted.  Point is left where the deleted region was."
+  (save-restriction
+    (narrow-to-region
+     (save-excursion
+       ;; In case point is at the beginning of the message already.
+       (forward-line 1)
+       (nnmail-search-unix-mail-delim-backward)
+       (if leave-delim (progn (forward-line 1) (point))
+        (point)))
+     (progn
+       (forward-line 1)
+       (if (nnmail-search-unix-mail-delim)
+          (point)
+        (point-max))))
+    (run-hooks 'nnfolder-delete-mail-hook)
+    (delete-region (point-min) (point-max))))
+
+(defun nnfolder-possibly-change-group (group &optional server dont-check)
+  ;; Change servers.
+  (when (and server
+            (not (nnfolder-server-opened server)))
+    (nnfolder-open-server server))
+  (unless (gnus-buffer-live-p nnfolder-current-buffer)
+    (setq nnfolder-current-buffer nil
+         nnfolder-current-group nil))
+  ;; Change group.
+  (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.
+         (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.
+         (when (and nnfolder-current-buffer
+                    (not (gnus-buffer-live-p nnfolder-current-buffer)))
+           (setq nnfolder-buffer-alist (delq inf nnfolder-buffer-alist)
+                 nnfolder-current-buffer nil))
+
+         (setq nnfolder-current-group group)
+
+         (when (or (not nnfolder-current-buffer)
+                   (not (verify-visited-file-modtime
+                         nnfolder-current-buffer)))
+           (save-excursion
+             (setq file (nnfolder-group-pathname group))
+             ;; 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
+                      (or nnfolder-file-coding-system-for-write
+                          nnfolder-file-coding-system-for-write)))
+                 (nnmail-write-region (point-min) (point-min)
+                                      file t 'nomesg)))
+             (when (setq nnfolder-current-buffer (nnfolder-read-folder group))
+               (set-buffer nnfolder-current-buffer)
+               (push (list group nnfolder-current-buffer)
+                     nnfolder-buffer-alist)))))))))
+
+(defun nnfolder-save-mail (group-art-list)
+  "Called narrowed to an article."
+  (let* (save-list group-art)
+    (goto-char (point-min))
+    ;; The From line may have been quoted by movemail.
+    (when (looking-at ">From")
+      (delete-char 1))
+    ;; This might come from somewhere else.
+    (unless (looking-at "From ")
+      (insert "From nobody " (current-time-string) "\n")
+      (goto-char (point-min)))
+    ;; Quote all "From " lines in the article.
+    (forward-line 1)
+    (let (case-fold-search)
+      (while (re-search-forward "^From " nil t)
+       (beginning-of-line)
+       (insert "> ")))
+    (setq save-list group-art-list)
+    (nnmail-insert-lines)
+    (nnmail-insert-xref group-art-list)
+    (run-hooks 'nnmail-prepare-save-mail-hook)
+    (run-hooks 'nnfolder-prepare-save-mail-hook)
+
+    ;; Insert the mail into each of the destination groups.
+    (while (setq group-art (pop group-art-list))
+      ;; Kill any previous newsgroup markers.
+      (goto-char (point-min))
+      (if (search-forward "\n\n" nil t)
+         (forward-line -1)
+       (goto-char (point-max)))
+      (while (search-backward (concat "\n" nnfolder-article-marker) nil t)
+       (delete-region (1+ (point)) (progn (forward-line 2) (point))))
+
+      ;; Insert the new newsgroup marker.
+      (nnfolder-insert-newsgroup-line group-art)
+
+      (save-excursion
+       (let ((beg (point-min))
+             (end (point-max))
+             (obuf (current-buffer)))
+         (nnfolder-possibly-change-folder (car group-art))
+         (let ((buffer-read-only nil))
+           (nnfolder-normalize-buffer)
+           (insert-buffer-substring obuf beg end))
+         (unless (or gnus-nov-is-evil nnfolder-nov-is-evil)
+           (set-buffer obuf)
+           (nnfolder-add-nov (car group-art) (cdr group-art)
+                             (nnfolder-parse-head nil beg end))))))
+
+    ;; Did we save it anywhere?
+    save-list))
+
+(defun nnfolder-normalize-buffer ()
+  "Make sure there are two newlines at the end of the buffer."
+  (goto-char (point-max))
+  (skip-chars-backward "\n")
+  (delete-region (point) (point-max))
+  (unless (bobp)
+    (insert "\n\n")))
+
+(defun nnfolder-insert-newsgroup-line (group-art)
+  (save-excursion
+    (goto-char (point-min))
+    (unless (search-forward "\n\n" nil t)
+      (goto-char (point-max))
+      (insert "\n"))
+    (forward-char -1)
+    (insert (format (concat nnfolder-article-marker "%d   %s\n")
+                   (cdr group-art) (message-make-date)))))
+
+(defun nnfolder-active-number (group)
+  ;; Find the next article number in GROUP.
+  (let ((active (cadr (assoc group nnfolder-group-alist))))
+    (if active
+       (setcdr active (1+ (cdr active)))
+      ;; This group is new, so we create a new entry for it.
+      ;; This might be a bit naughty... creating groups on the drop of
+      ;; a hat, but I don't know...
+      (push (list group (setq active (cons 1 1)))
+           nnfolder-group-alist))
+    (cdr active)))
+
+(defun nnfolder-possibly-change-folder (group)
+  (let ((inf (assoc group nnfolder-buffer-alist)))
+    (if (and inf
+            (gnus-buffer-live-p (cadr inf)))
+       (set-buffer (cadr inf))
+      (when inf
+       (setq nnfolder-buffer-alist (delq inf nnfolder-buffer-alist)))
+      (when nnfolder-group-alist
+       (nnfolder-save-active nnfolder-group-alist nnfolder-active-file))
+      (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.
+
+(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
+                        nnfolder-file-coding-system))
+                   (nnheader-find-file-noselect file t)))))
+    (mm-enable-multibyte) ;; Use multibyte buffer for future copying.
+    (buffer-disable-undo)
+    (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.
+       (if (file-exists-p file)
+           buffer
+         (push (list group buffer) nnfolder-buffer-alist)
+         (set-buffer-modified-p t)
+         (nnfolder-save-buffer))
+      ;; Parse the damn thing.
+      (save-excursion
+       (goto-char (point-min))
+       ;; Remove any blank lines at the start.
+       (while (eq (following-char) ?\n)
+         (delete-char 1))
+       (nnmail-activate 'nnfolder)
+       ;; Read in the file.
+       (let ((delim "^From ")
+             (marker (concat "\n" nnfolder-article-marker))
+             (number "[0-9]+")
+             (active (or (cadr (assoc group nnfolder-group-alist))
+                         (cons 1 0)))
+             (scantime (assoc group nnfolder-scantime-alist))
+             (minid (or (and (boundp 'most-positive-fixnum)
+                             most-positive-fixnum)
+                        (lsh -1 -1)))
+             maxid start end newscantime
+             novbuf articles newnum
+             buffer-read-only)
+         (setq maxid (cdr active))
+
+         (unless (or gnus-nov-is-evil nnfolder-nov-is-evil
+                     (and (file-exists-p nov)
+                          (file-newer-than-file-p nov file)))
+           (unless (file-exists-p nov)
+             (gnus-make-directory (file-name-directory nov)))
+           (with-current-buffer
+               (setq novbuf (nnfolder-open-nov group))
+             (goto-char (point-min))
+             (while (not (eobp))
+               (push (read novbuf) articles)
+               (forward-line 1))
+             (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.)
+         (when (or nnfolder-ignore-active-file
+                   novbuf
+                   (< maxid 2))
+           (while (and (search-forward marker nil t)
+                       (looking-at number))
+             (setq newnum (string-to-number (match-string 0)))
+             (when (nnmail-within-headers-p)
+               (setq maxid (max maxid newnum)
+                     minid (min minid newnum))
+               (when novbuf
+                 (if (memq newnum articles)
+                     (setq articles (delq newnum articles))
+                   (let ((headers (nnfolder-parse-head newnum)))
+                     (with-current-buffer novbuf
+                       (nnheader-find-nov-line newnum)
+                       (nnheader-insert-nov headers)))))))
+           (when (and novbuf articles)
+             (with-current-buffer novbuf
+               (dolist (article articles)
+                 (when (nnheader-find-nov-line article)
+                   (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.
+         (when (not (or nnfolder-distrust-mbox
+                        (< maxid 2)))
+           (goto-char (point-max))
+           (unless (re-search-backward marker nil t)
+             (goto-char (point-min)))
+           ;;(when (nnmail-search-unix-mail-delim)
+           ;;  (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.
+         (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
+           ;; them.
+           (while (looking-at delim)
+             (forward-line 1))
+           (set-marker end (if (nnmail-search-unix-mail-delim)
+                               (point)
+                             (point-max)))
+           (goto-char start)
+           (when (not (search-forward marker end t))
+             (narrow-to-region start end)
+             (nnmail-insert-lines)
+             (nnfolder-insert-newsgroup-line
+              (cons nil
+                    (setq newnum
+                          (nnfolder-active-number group))))
+             (when novbuf
+               (let ((headers (nnfolder-parse-head newnum (point-min)
+                                                   (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!
+         (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 group newscantime)
+                 nnfolder-scantime-alist))
+         ;; Save nov.
+         (when novbuf
+           (nnfolder-save-nov))
+         (current-buffer))))))
+
+(defun nnfolder-recursive-directory-files (dir prefix)
+  (let ((files nil))
+    (dolist (file (directory-files dir))
+      (cond
+       ((or (file-symlink-p (expand-file-name file dir))
+           (member file '("." "..")))
+       ;; Ignore
+       )
+       ((file-directory-p (expand-file-name file dir))
+       (setq files (nconc (nnfolder-recursive-directory-files
+                           (expand-file-name file dir)
+                           (if prefix
+                               (concat prefix "." (directory-file-name file))
+                             (file-name-nondirectory file)))
+                          files)))
+       ((file-regular-p (expand-file-name file dir))
+       (push (if prefix
+                 (concat prefix "." file)
+               file)
+             files))))
+    files))
+
+;;;###autoload
+(defun nnfolder-generate-active-file ()
+  "Look for mbox folders in the nnfolder directory and make them into groups.
+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
+                                      nnfolder-directory)
+                                  t
+                                  (concat
+                                   (regexp-quote nnfolder-nov-file-suffix)
+                                   "$")))
+      (when (not (message-mail-file-mbox-p file))
+       (ignore-errors
+         (delete-file file)))))
+    (dolist (file (if nnmail-use-long-file-names
+                     (directory-files nnfolder-directory)
+                   (nnfolder-recursive-directory-files
+                    nnfolder-directory nil)))
+      (when (and (not (backup-file-name-p file))
+                (message-mail-file-mbox-p
+                 (nnfolder-group-pathname 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))))
+    (nnheader-message 5 ""))
+
+(defun nnfolder-group-pathname (group)
+  "Make file name for GROUP."
+  (setq group
+       (mm-encode-coding-string group nnmail-pathname-coding-system))
+  (let ((dir (file-name-as-directory (expand-file-name nnfolder-directory))))
+    ;; If this file exists, we use it directly.
+    (if (or nnmail-use-long-file-names
+           (file-exists-p (concat dir group)))
+       (concat dir group)
+      ;; If not, we translate dots into slashes.
+      (concat dir (nnheader-replace-chars-in-string group ?. ?/)))))
+
+(defun nnfolder-group-nov-pathname (group)
+  "Make pathname for GROUP NOV."
+  (let ((nnfolder-directory
+        (or nnfolder-nov-directory nnfolder-directory)))
+    (concat (nnfolder-group-pathname group) nnfolder-nov-file-suffix)))
+
+(defvar copyright-update)
+
+(defun nnfolder-save-buffer ()
+  "Save the buffer."
+  (let ((delete-old-versions t))
+    (when (buffer-modified-p)
+      (run-hooks 'nnfolder-save-buffer-hook)
+      (gnus-make-directory (file-name-directory (buffer-file-name)))
+      (let ((coding-system-for-write
+            (or nnfolder-file-coding-system-for-write
+                nnfolder-file-coding-system)))
+       (set (make-local-variable 'copyright-update) nil)
+       (save-buffer)))
+    (unless (or gnus-nov-is-evil nnfolder-nov-is-evil)
+      (nnfolder-save-nov))))
+
+(defun nnfolder-save-active (group-alist active-file)
+  (let ((nnmail-active-file-coding-system
+        (or nnfolder-active-file-coding-system-for-write
+            nnfolder-active-file-coding-system)))
+    (nnmail-save-active group-alist active-file)))
+
+(defun nnfolder-open-nov (group)
+  (or (cdr (assoc group nnfolder-nov-buffer-alist))
+      (let ((buffer (get-buffer-create (format " *nnfolder overview %s*" group))))
+       (with-current-buffer buffer
+         (set (make-local-variable 'nnfolder-nov-buffer-file-name)
+              (nnfolder-group-nov-pathname group))
+         (erase-buffer)
+         (when (file-exists-p nnfolder-nov-buffer-file-name)
+           (nnheader-insert-file-contents nnfolder-nov-buffer-file-name)))
+       (push (cons group buffer) nnfolder-nov-buffer-alist)
+       buffer)))
+
+(defun nnfolder-save-nov ()
+  (save-excursion
+    (while nnfolder-nov-buffer-alist
+      (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
+                               nnfolder-nov-buffer-file-name))
+         (nnmail-write-region 1 (point-max) nnfolder-nov-buffer-file-name
+                              nil 'nomesg))
+       (set-buffer-modified-p nil)
+       (kill-buffer (current-buffer)))
+      (setq nnfolder-nov-buffer-alist (cdr nnfolder-nov-buffer-alist)))))
+
+(defun nnfolder-nov-delete-article (group article)
+  (with-current-buffer (nnfolder-open-nov group)
+    (when (nnheader-find-nov-line article)
+      (delete-region (point) (progn (forward-line 1) (point))))
+    t))
+
+(defun nnfolder-retrieve-headers-with-nov (articles &optional fetch-old)
+  (if (or gnus-nov-is-evil nnfolder-nov-is-evil)
+      nil
+    (let ((nov (nnfolder-group-nov-pathname nnfolder-current-group)))
+      (when (file-exists-p nov)
+       (with-current-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 nnfolder-parse-head (&optional number b e)
+  "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)
+       (let ((headers (nnheader-parse-naked-head)))
+         (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."
+  (with-current-buffer (nnfolder-open-nov group)
+    (goto-char (point-max))
+    (mail-header-set-number headers article)
+    (nnheader-insert-nov headers)))
+
+(provide 'nnfolder)
+
+;;; nnfolder.el ends here
diff --git a/xemacs-packages/gnus/lisp/nngateway.el b/xemacs-packages/gnus/lisp/nngateway.el
new file mode 100644 (file)
index 0000000..5d7b11b
--- /dev/null
@@ -0,0 +1,91 @@
+;;; nngateway.el --- posting news via mail gateways
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: news, mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(require 'nnoo)
+(require 'message)
+
+(nnoo-declare nngateway)
+
+(defvoo nngateway-address nil
+  "Address of the mail-to-news gateway.")
+
+(defvoo nngateway-header-transformation 'nngateway-simple-header-transformation
+  "Function to be called to rewrite the news headers into mail headers.
+It is called narrowed to the headers to be transformed with one
+parameter -- the gateway address.")
+
+;;; Interface functions
+
+(nnoo-define-basics nngateway)
+
+(deffoo nngateway-open-server (server &optional defs)
+  (if (nngateway-server-opened server)
+      t
+    (unless (assq 'nngateway-address defs)
+      (setq defs (append defs (list (list 'nngateway-address server)))))
+    (nnoo-change-server 'nngateway server defs)))
+
+(deffoo nngateway-request-post (&optional server)
+  (when (or (nngateway-server-opened server)
+           (nngateway-open-server server))
+    ;; Rewrite the header.
+    (let ((buf (current-buffer)))
+      (with-temp-buffer
+       (insert-buffer-substring buf)
+       (message-narrow-to-head)
+       (funcall nngateway-header-transformation nngateway-address)
+       (goto-char (point-max))
+       (insert mail-header-separator "\n")
+       (widen)
+       (let (message-required-mail-headers)
+         (funcall (or message-send-mail-real-function
+                      message-send-mail-function)))
+       t))))
+
+;;; Internal functions
+
+(defun nngateway-simple-header-transformation (gateway)
+  "Transform the headers to use GATEWAY."
+  (let ((newsgroups (mail-fetch-field "newsgroups")))
+    (message-remove-header "to")
+    (message-remove-header "cc")
+    (goto-char (point-min))
+    (insert "To: " (nnheader-replace-chars-in-string newsgroups ?. ?-)
+           "@" gateway "\n")))
+
+(defun nngateway-mail2news-header-transformation (gateway)
+  "Transform the headers for sending to a mail2news gateway."
+  (message-remove-header "to")
+  (message-remove-header "cc")
+  (goto-char (point-min))
+  (insert "To: " gateway "\n"))
+
+(nnoo-define-skeleton nngateway)
+
+(provide 'nngateway)
+
+;;; nngateway.el ends here
diff --git a/xemacs-packages/gnus/lisp/nnheader.el b/xemacs-packages/gnus/lisp/nnheader.el
new file mode 100644 (file)
index 0000000..cd43016
--- /dev/null
@@ -0,0 +1,1126 @@
+;;; nnheader.el --- header access macros for Gnus and its backends
+
+;; Copyright (C) 1987-1990, 1993-1998, 2000-2016 Free Software
+;; Foundation, Inc.
+
+;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
+;;     Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(defvar nnmail-extra-headers)
+(defvar gnus-newsgroup-name)
+(defvar nnheader-file-coding-system)
+(defvar jka-compr-compression-info-list)
+
+;; Requiring `gnus-util' at compile time creates a circular
+;; dependency between nnheader.el and gnus-util.el.
+;;(eval-when-compile (require 'gnus-util))
+
+(require 'mail-utils)
+(require 'mm-util)
+(require 'gnus-util)
+(autoload 'gnus-range-add "gnus-range")
+(autoload 'gnus-remove-from-range "gnus-range")
+;; FIXME none of these are used explicitly in this file.
+(autoload 'gnus-sorted-intersection "gnus-range")
+(autoload 'gnus-intersection "gnus-range")
+(autoload 'gnus-sorted-complement "gnus-range")
+(autoload 'gnus-sorted-difference "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 8192
+  "*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.")
+
+(defvar nnheader-read-timeout
+  (if (string-match "windows-nt\\|os/2\\|cygwin"
+                   (symbol-name system-type))
+      ;; http://thread.gmane.org/v9655t3pjo.fsf@marauder.physik.uni-ulm.de
+      ;;
+      ;; IIRC, values lower than 1.0 didn't/don't work on Windows/DOS.
+      ;;
+      ;; There should probably be a runtime test to determine the timing
+      ;; resolution, or a primitive to report it.  I don't know off-hand
+      ;; what's possible.  Perhaps better, maybe the Windows/DOS primitive
+      ;; could round up non-zero timeouts to a minimum of 1.0?
+      1.0
+    ;; 2008-05-19 change by Larsi:
+    ;; Change the default timeout from 0.1 seconds to 0.01 seconds.  This will
+    ;; make nntp and pop3 article retrieval faster in some cases, but might
+    ;; make CPU usage larger.  If this has any bad side effects, we might
+    ;; revert this change.
+    0.01)
+  ;; When changing this variable, consider changing `pop3-read-timeout' as
+  ;; well.
+  "How long nntp should wait between checking for the end of output.
+Shorter values mean quicker response, but are more CPU intensive.")
+
+(defvar nnheader-file-name-translation-alist
+  (let ((case-fold-search t))
+    (cond
+     ((string-match "windows-nt\\|os/2\\|cygwin"
+                   (symbol-name system-type))
+      (append (mapcar (lambda (c) (cons c ?_))
+                     '(?: ?* ?\" ?< ?> ??))
+             (if (string-match "windows-nt\\|cygwin"
+                               (symbol-name system-type))
+                 nil
+               '((?+ . ?-)))))
+     (t nil)))
+  "*Alist that says how to translate characters in file names.
+For instance, if \":\" is invalid as a file character in file names
+on your system, you could say something like:
+
+\(setq nnheader-file-name-translation-alist \\='((?: . ?_)))")
+
+(defvar nnheader-directory-separator-character
+  (string-to-char (substring (file-name-as-directory ".") -1))
+  "*A character used to a directory separator.")
+
+(autoload 'nnmail-message-id "nnmail")
+(autoload 'mail-position-on-field "sendmail")
+(autoload 'gnus-buffer-live-p "gnus-util")
+
+;;; Header access macros.
+
+;; These macros may look very much like the ones in GNUS 4.1.  They
+;; are, in a way, but you should note that the indices they use have
+;; been changed from the internal GNUS format to the NOV format.  The
+;; makes it possible to read headers from XOVER much faster.
+;;
+;; The format of a header is now:
+;; [number subject from date id references chars lines xref extra]
+;;
+;; (That next-to-last entry is defined as "misc" in the NOV format,
+;; but Gnus uses it for xrefs.)
+
+(defmacro mail-header-number (header)
+  "Return article number in HEADER."
+  `(aref ,header 0))
+
+(defmacro mail-header-set-number (header number)
+  "Set article number of HEADER to NUMBER."
+  `(aset ,header 0 ,number))
+
+(defmacro mail-header-subject (header)
+  "Return subject string in HEADER."
+  `(aref ,header 1))
+
+(defmacro mail-header-set-subject (header subject)
+  "Set article subject of HEADER to SUBJECT."
+  `(aset ,header 1 ,subject))
+
+(defmacro mail-header-from (header)
+  "Return author string in HEADER."
+  `(aref ,header 2))
+
+(defmacro mail-header-set-from (header from)
+  "Set article author of HEADER to FROM."
+  `(aset ,header 2 ,from))
+
+(defmacro mail-header-date (header)
+  "Return date in HEADER."
+  `(aref ,header 3))
+
+(defmacro mail-header-set-date (header date)
+  "Set article date of HEADER to DATE."
+  `(aset ,header 3 ,date))
+
+(defalias 'mail-header-message-id 'mail-header-id)
+(defmacro mail-header-id (header)
+  "Return Id in HEADER."
+  `(aref ,header 4))
+
+(defalias 'mail-header-set-message-id 'mail-header-set-id)
+(defmacro mail-header-set-id (header id)
+  "Set article Id of HEADER to ID."
+  `(aset ,header 4 ,id))
+
+(defmacro mail-header-references (header)
+  "Return references in HEADER."
+  `(aref ,header 5))
+
+(defmacro mail-header-set-references (header ref)
+  "Set article references of HEADER to REF."
+  `(aset ,header 5 ,ref))
+
+(defmacro mail-header-chars (header)
+  "Return number of chars of article in HEADER."
+  `(aref ,header 6))
+
+(defmacro mail-header-set-chars (header chars)
+  "Set number of chars in article of HEADER to CHARS."
+  `(aset ,header 6 ,chars))
+
+(defmacro mail-header-lines (header)
+  "Return lines in HEADER."
+  `(aref ,header 7))
+
+(defmacro mail-header-set-lines (header lines)
+  "Set article lines of HEADER to LINES."
+  `(aset ,header 7 ,lines))
+
+(defmacro mail-header-xref (header)
+  "Return xref string in HEADER."
+  `(aref ,header 8))
+
+(defmacro mail-header-set-xref (header xref)
+  "Set article XREF of HEADER to xref."
+  `(aset ,header 8 ,xref))
+
+(defmacro mail-header-extra (header)
+  "Return the extra headers in HEADER."
+  `(aref ,header 9))
+
+(defun mail-header-set-extra (header extra)
+  "Set the extra headers in HEADER to EXTRA."
+  (aset header 9 extra))
+
+(defsubst make-mail-header (&optional init)
+  "Create a new mail header structure initialized with INIT."
+  (make-vector 10 init))
+
+(defsubst make-full-mail-header (&optional number subject from date id
+                                          references chars lines xref
+                                          extra)
+  "Create a new mail header structure initialized with the parameters given."
+  (vector number subject from date id references chars lines xref extra))
+
+;; fake message-ids: generation and detection
+
+(defvar nnheader-fake-message-id 1)
+
+(defsubst nnheader-generate-fake-message-id (&optional number)
+  (if (numberp number)
+      (format "fake+none+%s+%d" gnus-newsgroup-name number)
+    (format "fake+none+%s+%s"
+           gnus-newsgroup-name
+           (int-to-string (incf nnheader-fake-message-id)))))
+
+(defsubst nnheader-fake-message-id-p (id)
+  (save-match-data                    ; regular message-id's are <.*>
+    (string-match "\\`fake\\+none\\+.*\\+[0-9]+\\'" id)))
+
+;; Parsing headers and NOV lines.
+
+(defsubst nnheader-remove-cr-followed-by-lf ()
+  (goto-char (point-max))
+  (while (search-backward "\r\n" nil t)
+    (delete-char 1)))
+
+(defsubst nnheader-header-value ()
+  (skip-chars-forward " \t")
+  (buffer-substring (point) (point-at-eol)))
+
+(autoload 'ietf-drums-unfold-fws "ietf-drums")
+
+(defun nnheader-parse-naked-head (&optional number)
+  ;; This function unfolds continuation lines in this buffer
+  ;; destructively.  When this side effect is unwanted, use
+  ;; `nnheader-parse-head' instead of this function.
+  (let ((case-fold-search t)
+       (buffer-read-only nil)
+       (cur (current-buffer))
+       (p (point-min))
+       in-reply-to lines ref)
+    (nnheader-remove-cr-followed-by-lf)
+    (ietf-drums-unfold-fws)
+    (subst-char-in-region (point-min) (point-max) ?\t ? )
+    (goto-char p)
+    (insert "\n")
+    (prog1
+       ;; This implementation of this function, with nine
+       ;; search-forwards instead of the one re-search-forward and a
+       ;; case (which basically was the old function) is actually
+       ;; about twice as fast, even though it looks messier.  You
+       ;; can't have everything, I guess.  Speed and elegance don't
+       ;; always go hand in hand.
+       (vector
+        ;; Number.
+        (or number 0)
+        ;; Subject.
+        (progn
+          (goto-char p)
+          (if (search-forward "\nsubject:" nil t)
+              (nnheader-header-value) "(none)"))
+        ;; From.
+        (progn
+          (goto-char p)
+          (if (search-forward "\nfrom:" nil t)
+              (nnheader-header-value) "(nobody)"))
+        ;; Date.
+        (progn
+          (goto-char p)
+          (if (search-forward "\ndate:" nil t)
+              (nnheader-header-value) ""))
+        ;; Message-ID.
+        (progn
+          (goto-char p)
+          (if (search-forward "\nmessage-id:" nil t)
+              (buffer-substring
+               (1- (or (search-forward "<" (point-at-eol) t)
+                       (point)))
+               (or (search-forward ">" (point-at-eol) t) (point)))
+            ;; If there was no message-id, we just fake one to make
+            ;; subsequent routines simpler.
+            (nnheader-generate-fake-message-id number)))
+        ;; References.
+        (progn
+          (goto-char p)
+          (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)
+                     (setq in-reply-to (nnheader-header-value))
+                     (string-match "<[^\n>]+>" in-reply-to))
+                (let (ref2)
+                  (setq ref (substring in-reply-to (match-beginning 0)
+                                       (match-end 0)))
+                  (while (string-match "<[^\n>]+>"
+                                       in-reply-to (match-end 0))
+                    (setq ref2 (substring in-reply-to (match-beginning 0)
+                                          (match-end 0)))
+                    (when (> (length ref2) (length ref))
+                      (setq ref ref2)))
+                  ref)
+              nil)))
+        ;; Chars.
+        0
+        ;; Lines.
+        (progn
+          (goto-char p)
+          (if (search-forward "\nlines: " nil t)
+              (if (numberp (setq lines (read cur)))
+                  lines 0)
+            0))
+        ;; Xref.
+        (progn
+          (goto-char p)
+          (and (search-forward "\nxref:" nil t)
+               (nnheader-header-value)))
+        ;; Extra.
+        (when nnmail-extra-headers
+          (let ((extra nnmail-extra-headers)
+                out)
+            (while extra
+              (goto-char p)
+              (when (search-forward
+                     (concat "\n" (symbol-name (car extra)) ":") nil t)
+                (push (cons (car extra) (nnheader-header-value))
+                      out))
+              (pop extra))
+            out)))
+      (goto-char p)
+      (delete-char 1))))
+
+(defun nnheader-parse-head (&optional naked)
+  (let ((cur (current-buffer)) num beg end)
+    (when (if naked
+             (setq num 0
+                   beg (point-min)
+                   end (point-max))
+           ;; Search to the beginning of the next header.  Error
+           ;; messages do not begin with 2 or 3.
+           (when (re-search-forward "^[23][0-9]+ " nil t)
+             (setq num (read cur)
+                   beg (point)
+                   end (if (search-forward "\n.\n" nil t)
+                           (goto-char  (- (point) 2))
+                         (point)))))
+      (with-temp-buffer
+       (insert-buffer-substring cur beg end)
+       (nnheader-parse-naked-head num)))))
+
+(defmacro nnheader-nov-skip-field ()
+  '(search-forward "\t" eol 'move))
+
+(defmacro nnheader-nov-field ()
+  '(buffer-substring (point) (if (nnheader-nov-skip-field) (1- (point)) eol)))
+
+(defmacro nnheader-nov-read-integer ()
+  '(prog1
+       (if (eq (char-after) ?\t)
+          0
+        (let ((num (condition-case nil
+                       (read (current-buffer))
+                     (error nil))))
+          (if (numberp num) num 0)))
+     (or (eobp) (forward-char 1))))
+
+(defmacro nnheader-nov-parse-extra ()
+  '(let (out string)
+     (while (not (memq (char-after) '(?\n nil)))
+       (setq string (nnheader-nov-field))
+       (when (string-match "^\\([^ :]+\\): " string)
+        (push (cons (intern (match-string 1 string))
+                    (substring string (match-end 0)))
+              out)))
+     out))
+
+(eval-and-compile
+  (defvar nnheader-uniquify-message-id nil))
+
+(defmacro nnheader-nov-read-message-id (&optional number)
+  `(let ((id (nnheader-nov-field)))
+     (if (string-match "^<[^>]+>$" id)
+        ,(if nnheader-uniquify-message-id
+             `(if (string-match "__[^@]+@" id)
+                  (concat (substring id 0 (match-beginning 0))
+                          (substring id (1- (match-end 0))))
+                id)
+           'id)
+       (nnheader-generate-fake-message-id ,number))))
+
+(defun nnheader-parse-nov ()
+  (let ((eol (point-at-eol))
+       (number (nnheader-nov-read-integer)))
+    (vector
+     number                            ; number
+     (nnheader-nov-field)              ; subject
+     (nnheader-nov-field)              ; from
+     (nnheader-nov-field)              ; date
+     (nnheader-nov-read-message-id number) ; id
+     (nnheader-nov-field)              ; refs
+     (nnheader-nov-read-integer)       ; chars
+     (nnheader-nov-read-integer)       ; lines
+     (if (eq (char-after) ?\n)
+        nil
+       (if (looking-at "Xref: ")
+          (goto-char (match-end 0)))
+       (nnheader-nov-field))           ; Xref
+     (nnheader-nov-parse-extra))))     ; extra
+
+(defun nnheader-insert-nov (header)
+  (princ (mail-header-number header) (current-buffer))
+  (let ((p (point)))
+    (insert
+     "\t"
+     (or (mail-header-subject header) "(none)") "\t"
+     (or (mail-header-from header) "(nobody)") "\t"
+     (or (mail-header-date header) "") "\t"
+     (or (mail-header-id header)
+        (nnmail-message-id))
+     "\t"
+     (or (mail-header-references header) "") "\t")
+    (princ (or (mail-header-chars header) 0) (current-buffer))
+    (insert "\t")
+    (princ (or (mail-header-lines header) 0) (current-buffer))
+    (insert "\t")
+    (when (mail-header-xref header)
+      (insert "Xref: " (mail-header-xref header)))
+    (when (or (mail-header-xref header)
+             (mail-header-extra header))
+      (insert "\t"))
+    (when (mail-header-extra header)
+      (let ((extra (mail-header-extra header)))
+       (while extra
+         (insert (symbol-name (caar extra))
+                 ": " (if (stringp (cdar extra)) (cdar extra) "") "\t")
+         (pop extra))))
+    (insert "\n")
+    (backward-char 1)
+    (while (search-backward "\n" p t)
+      (delete-char 1))
+    (forward-line 1)))
+
+(defun nnheader-parse-overview-file (file)
+  "Parse FILE and return a list of headers."
+  (mm-with-unibyte-buffer
+    (nnheader-insert-file-contents file)
+    (goto-char (point-min))
+    (let (headers)
+      (while (not (eobp))
+       (push (nnheader-parse-nov) headers)
+       (forward-line 1))
+      (nreverse headers))))
+
+(defun nnheader-write-overview-file (file headers)
+  "Write HEADERS to FILE."
+  (with-temp-file file
+    (mapcar 'nnheader-insert-nov headers)))
+
+(defun nnheader-insert-header (header)
+  (insert
+   "Subject: " (or (mail-header-subject header) "(none)") "\n"
+   "From: " (or (mail-header-from header) "(nobody)") "\n"
+   "Date: " (or (mail-header-date header) "") "\n"
+   "Message-ID: " (or (mail-header-id header) (nnmail-message-id)) "\n"
+   "References: " (or (mail-header-references header) "") "\n"
+   "Lines: ")
+  (princ (or (mail-header-lines header) 0) (current-buffer))
+  (insert "\n\n"))
+
+(defun nnheader-insert-article-line (article)
+  (goto-char (point-min))
+  (insert "220 ")
+  (princ article (current-buffer))
+  (insert " Article retrieved.\n")
+  (search-forward "\n\n" nil 'move)
+  (delete-region (point) (point-max))
+  (forward-char -1)
+  (insert "."))
+
+(defun nnheader-nov-delete-outside-range (beg end)
+  "Delete all NOV lines that lie outside the BEG to END range."
+  ;; First we find the first wanted line.
+  (nnheader-find-nov-line beg)
+  (delete-region (point-min) (point))
+  ;; Then we find the last wanted line.
+  (when (nnheader-find-nov-line end)
+    (forward-line 1))
+  (delete-region (point) (point-max)))
+
+(defun nnheader-find-nov-line (article)
+  "Put point at the NOV line that start with ARTICLE.
+If ARTICLE doesn't exist, put point where that line
+would have been.  The function will return non-nil if
+the line could be found."
+  ;; This function basically does a binary search.
+  (let ((max (point-max))
+       (min (goto-char (point-min)))
+       (cur (current-buffer))
+       (prev (point-min))
+       num found)
+    (while (not found)
+      (goto-char (+ min (/ (- max min) 2)))
+      (beginning-of-line)
+      (if (or (= (point) prev)
+             (eobp))
+         (setq found t)
+       (setq prev (point))
+       (while (and (not (numberp (setq num (read cur))))
+                   (not (eobp)))
+         (gnus-delete-line))
+       (cond ((> num article)
+              (setq max (point)))
+             ((< num article)
+              (setq min (point)))
+             (t
+              (setq found 'yes)))))
+    ;; We may be at the first line.
+    (when (and (not num)
+              (not (eobp)))
+      (setq num (read cur)))
+    ;; Now we may have found the article we're looking for, or we
+    ;; may be somewhere near it.
+    (when (and (not (eq found 'yes))
+              (not (eq num article)))
+      (setq found (point))
+      (while (and (< (point) max)
+                 (or (not (numberp num))
+                     (< num article)))
+       (forward-line 1)
+       (setq found (point))
+       (or (eobp)
+           (= (setq num (read cur)) article)))
+      (unless (eq num article)
+       (goto-char found)))
+    (beginning-of-line)
+    (eq num article)))
+
+;; Various cruft the backends and Gnus need to communicate.
+
+(defvar nntp-server-buffer nil)
+(defvar nntp-process-response nil)
+
+(defvar nnheader-callback-function nil)
+
+(defun nnheader-init-server-buffer ()
+  "Initialize the Gnus-backend communication buffer."
+  (unless (gnus-buffer-live-p nntp-server-buffer)
+    (setq nntp-server-buffer (get-buffer-create " *nntpd*")))
+  (with-current-buffer nntp-server-buffer
+    (erase-buffer)
+    (mm-enable-multibyte)
+    (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.
+
+(defun nnheader-file-error (file)
+  "Return a string that says what is wrong with FILE."
+  (format
+   (cond
+    ((not (file-exists-p file))
+     "%s does not exist")
+    ((file-directory-p file)
+     "%s is a directory")
+    ((not (file-readable-p file))
+     "%s is not readable"))
+   file))
+
+(defun nnheader-insert-head (file)
+  "Insert the head of the article."
+  (when (file-exists-p file)
+    (if (eq nnheader-max-head-length t)
+       ;; Just read the entire file.
+       (nnheader-insert-file-contents file)
+      ;; Read blocks of the size specified by `nnheader-head-chop-length'
+      ;; until we find a separator.
+      (let ((beg 0)
+           (start (point))
+           ;; Use `binary' to prevent the contents from being decoded,
+           ;; or it will change the number of characters that
+           ;; `insert-file-contents' returns.
+           (coding-system-for-read 'binary))
+       (while (and (eq nnheader-head-chop-length
+                       (nth 1 (mm-insert-file-contents
+                               file nil beg
+                               (incf beg nnheader-head-chop-length))))
+                   ;; CRLF or CR might be used for the line-break code.
+                   (prog1 (not (re-search-forward "\n\r?\n\\|\r\r" nil t))
+                     (goto-char (point-max)))
+                   (or (null nnheader-max-head-length)
+                       (< beg nnheader-max-head-length))))
+       ;; Finally decode the contents.
+       (when (mm-coding-system-p nnheader-file-coding-system)
+         (mm-decode-coding-region start (point-max)
+                                  nnheader-file-coding-system))))
+    t))
+
+(defun nnheader-article-p ()
+  "Say whether the current buffer looks like an article."
+  (goto-char (point-min))
+  (if (not (search-forward "\n\n" nil t))
+      nil
+    (narrow-to-region (point-min) (1- (point)))
+    (goto-char (point-min))
+    (while (looking-at "[a-zA-Z][^ \t]+:.*\n\\([ \t].*\n\\)*\\|From .*\n")
+      (goto-char (match-end 0)))
+    (prog1
+       (eobp)
+      (widen))))
+
+(defun nnheader-insert-references (references message-id)
+  "Insert a References header based on REFERENCES and MESSAGE-ID."
+  (if (and (not references) (not message-id))
+      ;; This is invalid, but not all articles have Message-IDs.
+      ()
+    (mail-position-on-field "References")
+    (let ((begin (point-at-bol))
+         (fill-column 78)
+         (fill-prefix "\t"))
+      (when references
+       (insert references))
+      (when (and references message-id)
+       (insert " "))
+      (when message-id
+       (insert message-id))
+      ;; Fold long References lines to conform to RFC1036 (sort of).
+      ;; The region must end with a newline to fill the region
+      ;; without inserting extra newline.
+      (fill-region-as-paragraph begin (1+ (point))))))
+
+(declare-function message-remove-header "message"
+                 (header &optional is-regexp first reverse))
+
+(defun nnheader-replace-header (header new-value)
+  "Remove HEADER and insert the NEW-VALUE."
+  (require 'message)
+  (save-excursion
+    (save-restriction
+      (nnheader-narrow-to-headers)
+      (prog1
+         (message-remove-header header)
+       (goto-char (point-max))
+       (insert header ": " new-value "\n")))))
+
+(defun nnheader-narrow-to-headers ()
+  "Narrow to the head of an article."
+  (widen)
+  (narrow-to-region
+   (goto-char (point-min))
+   (if (search-forward "\n\n" nil t)
+       (1- (point))
+     (point-max)))
+  (goto-char (point-min)))
+
+(defun nnheader-get-lines-and-char ()
+  "Return the number of lines and chars in the article body."
+  (goto-char (point-min))
+  (if (not (re-search-forward "\n\r?\n" nil t))
+      (list 0 0)
+    (list (count-lines (point) (point-max))
+         (- (point-max) (point)))))
+
+(defun nnheader-remove-body ()
+  "Remove the body from an article in this current buffer."
+  (goto-char (point-min))
+  (when (re-search-forward "\n\r?\n" nil t)
+    (delete-region (point) (point-max))))
+
+(defun nnheader-set-temp-buffer (name &optional noerase)
+  "Set-buffer to an empty (possibly new) buffer called NAME with undo disabled."
+  (set-buffer (get-buffer-create name))
+  (buffer-disable-undo)
+  (unless noerase
+    (erase-buffer))
+  (current-buffer))
+
+(defvar nnheader-numerical-files
+  (if (boundp 'jka-compr-compression-info-list)
+      (concat "\\([0-9]+\\)\\("
+             (mapconcat (lambda (i) (aref i 0))
+                        jka-compr-compression-info-list "\\|")
+             "\\)?")
+    "[0-9]+$")
+  "Regexp that match numerical files.")
+
+(defvar nnheader-numerical-short-files (concat "^" nnheader-numerical-files)
+  "Regexp that matches numerical file names.")
+
+(defvar nnheader-numerical-full-files (concat "/" nnheader-numerical-files)
+  "Regexp that matches numerical full file names.")
+
+(defsubst nnheader-file-to-number (file)
+  "Take a FILE name and return the article number."
+  (if (string= nnheader-numerical-short-files "^[0-9]+$")
+      (string-to-number file)
+    (string-match nnheader-numerical-short-files file)
+    (string-to-number (match-string 0 file))))
+
+(defvar nnheader-directory-files-is-safe
+  (or (eq system-type 'windows-nt)
+      (not (featurep 'xemacs)))
+  "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,
+`nnheader-directory-files-safe' is used.")
+
+(defun nnheader-directory-files-safe (&rest args)
+  "Execute `directory-files' twice and returns the longer result."
+  (let ((first (apply 'directory-files args))
+       (second (apply 'directory-files args)))
+    (if (> (length first) (length second))
+       first
+      second)))
+
+(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
+             (directory-files
+              dir nil nnheader-numerical-short-files t)
+           (nnheader-directory-files-safe
+            dir nil nnheader-numerical-short-files t))))
+
+(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
+             (directory-files
+              dir nil nnheader-numerical-short-files t)
+           (nnheader-directory-files-safe
+            dir nil nnheader-numerical-short-files t))))
+
+(defun nnheader-fold-continuation-lines ()
+  "Fold continuation lines in the current buffer."
+  (nnheader-replace-regexp "\\(\r?\n[ \t]+\\)+" " "))
+
+(defun nnheader-translate-file-chars (file &optional full)
+  "Translate FILE into something that can be a file name.
+If FULL, translate everything."
+  (if (null nnheader-file-name-translation-alist)
+      ;; No translation is necessary.
+      file
+    (let* ((i 0)
+          trans leaf path len)
+      (if full
+         ;; Do complete translation.
+         (setq leaf (copy-sequence file)
+               path ""
+               i (if (and (< 1 (length leaf)) (eq ?: (aref leaf 1)))
+                     2 0))
+       ;; We translate -- but only the file name.  We leave the directory
+       ;; alone.
+       (if (and (featurep 'xemacs)
+                (memq system-type '(windows-nt cygwin)))
+           ;; 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"
+           ;; "d:aaa\\bbb:ccc"   -> "d:aaa\\" "bbb:ccc"
+           ;; etc.
+           ;; to translate then only the file name part.
+           (progn
+             (setq leaf file
+                   path "")
+             (if (string-match "\\(^\\w:\\|[/\\]\\)\\([^/\\]+\\)$" file)
+                 (setq leaf (substring file (match-beginning 2))
+                       path (substring file 0 (match-beginning 2)))))
+         ;; Emacs DTRT, says andrewi.
+         (setq leaf (file-name-nondirectory file)
+               path (file-name-directory file))))
+      (setq len (length leaf))
+      (while (< i len)
+       (when (setq trans (cdr (assq (aref leaf i)
+                                    nnheader-file-name-translation-alist)))
+         (aset leaf i trans))
+       (incf i))
+      (concat path leaf))))
+
+(defun nnheader-report (backend &rest args)
+  "Report an error from the BACKEND.
+The first string in ARGS can be a format string."
+  (set (intern (format "%s-status-string" backend))
+       (if (< (length args) 2)
+          (car args)
+        (apply 'format args)))
+  nil)
+
+(defun nnheader-get-report-string (backend)
+  "Get the most recent report from BACKEND."
+  (condition-case ()
+      (format "%s" (symbol-value (intern (format "%s-status-string"
+                                                backend))))
+    (error "")))
+
+(defun nnheader-get-report (backend)
+  "Get the most recent report from BACKEND."
+  (nnheader-message 5 (nnheader-get-report-string backend)))
+
+(defun nnheader-insert (format &rest args)
+  "Clear the communication buffer and insert FORMAT and ARGS into the buffer.
+If FORMAT isn't a format string, it and all ARGS will be inserted
+without formatting."
+  (with-current-buffer nntp-server-buffer
+    (erase-buffer)
+    (if (string-match "%" format)
+       (insert (apply 'format format args))
+      (apply 'insert format args))
+    t))
+
+(defsubst nnheader-replace-chars-in-string (string from to)
+  (mm-subst-char-in-string from to string))
+
+(defun nnheader-replace-duplicate-chars-in-string (string from to)
+  "Replace characters in STRING from FROM to TO."
+  (let ((string (substring string 0))  ;Copy string.
+       (len (length string))
+       (idx 0) prev i)
+    ;; Replace all occurrences of FROM with TO.
+    (while (< idx len)
+      (setq i (aref string idx))
+      (when (and (eq prev from) (= i from))
+       (aset string (1- idx) to)
+       (aset string idx to))
+      (setq prev i)
+      (setq idx (1+ idx)))
+    string))
+
+(defun nnheader-file-to-group (file &optional top)
+  "Return a group name based on FILE and TOP."
+  (nnheader-replace-chars-in-string
+   (if (not top)
+       file
+     (condition-case ()
+        (substring (expand-file-name file)
+                   (length
+                    (expand-file-name
+                     (file-name-as-directory top))))
+       (error "")))
+   nnheader-directory-separator-character ?.))
+
+(defun nnheader-message (level &rest args)
+  "Message if the Gnus backends are talkative."
+  (if (or (not (numberp gnus-verbose-backends))
+         (<= level gnus-verbose-backends))
+      (if gnus-add-timestamp-to-message
+         (apply 'gnus-message-with-timestamp args)
+       (apply 'message args))
+    (apply 'format args)))
+
+(defun nnheader-be-verbose (level)
+  "Return whether the backends should be verbose on LEVEL."
+  (or (not (numberp gnus-verbose-backends))
+      (<= level gnus-verbose-backends)))
+
+(defvar nnheader-pathname-coding-system 'iso-8859-1
+  "*Coding system for file name.")
+
+(defun nnheader-group-pathname (group dir &optional file)
+  "Make file name for GROUP."
+  (concat
+   (let ((dir (file-name-as-directory (expand-file-name dir))))
+     ;; If this directory exists, we use it directly.
+     (file-name-as-directory
+      (if (file-directory-p (concat dir group))
+         (expand-file-name group dir)
+       ;; If not, we translate dots into slashes.
+       (expand-file-name (mm-encode-coding-string
+                          (nnheader-replace-chars-in-string group ?. ?/)
+                          nnheader-pathname-coding-system)
+                         dir))))
+   (cond ((null file) "")
+        ((numberp file) (int-to-string file))
+        (t file))))
+
+(defun nnheader-concat (dir &rest files)
+  "Concat DIR as directory to FILES."
+  (apply 'concat (file-name-as-directory dir) files))
+
+(defun nnheader-ms-strip-cr ()
+  "Strip ^M from the end of all lines."
+  (save-excursion
+    (nnheader-remove-cr-followed-by-lf)))
+
+(defun nnheader-file-size (file)
+  "Return the file size of FILE or 0."
+  (or (nth 7 (file-attributes file)) 0))
+
+(defun nnheader-find-etc-directory (package &optional file first)
+  "Go through `load-path' and find the \"../etc/PACKAGE\" directory.
+This function will look in the parent directory of each `load-path'
+entry, and look for the \"etc\" directory there.
+If FILE, find the \".../etc/PACKAGE\" file instead.
+If FIRST is non-nil, return the directory or the file found at the
+first.  Otherwise, find the newest one, though it may take a time."
+  (let ((path load-path)
+       dir results)
+    ;; We try to find the dir by looking at the load path,
+    ;; stripping away the last component and adding "etc/".
+    (while path
+      (if (and (car path)
+              (file-exists-p
+               (setq dir (concat
+                          (file-name-directory
+                           (directory-file-name (car path)))
+                          "etc/" package
+                          (if file "" "/"))))
+              (or file (file-directory-p dir)))
+         (progn
+           (or (member dir results)
+               (push dir results))
+           (setq path (if first nil (cdr path))))
+       (setq path (cdr path))))
+    (if (or first (not (cdr results)))
+       (car results)
+      (car (sort results 'file-newer-than-file-p)))))
+
+(defvar ange-ftp-path-format)
+(defvar efs-path-regexp)
+(defun nnheader-re-read-dir (path)
+  "Re-read directory PATH if PATH is on a remote system."
+  (if (and (fboundp 'efs-re-read-dir) (boundp 'efs-path-regexp))
+      (when (string-match efs-path-regexp path)
+       (efs-re-read-dir path))
+    (when (and (fboundp 'ange-ftp-re-read-dir) (boundp 'ange-ftp-path-format))
+      (when (string-match (car ange-ftp-path-format) path)
+       (ange-ftp-re-read-dir path)))))
+
+(defvar nnheader-file-coding-system 'raw-text
+  "Coding system used in file backends of Gnus.")
+
+(defun nnheader-insert-file-contents (filename &optional visit beg end replace)
+  "Like `insert-file-contents', q.v., but only reads in the file.
+A buffer may be modified in several ways after reading into the buffer due
+to advanced Emacs features, such as file-name-handlers, format decoding,
+find-file-hooks, etc.
+  This function ensures that none of these modifications will take place."
+  (let ((coding-system-for-read nnheader-file-coding-system))
+    (mm-insert-file-contents filename visit beg end replace)))
+
+(defun nnheader-insert-nov-file (file first)
+  (let ((size (nth 7 (file-attributes file)))
+       (cutoff (* 32 1024)))
+    (when size
+      (if (< size cutoff)
+          ;; If the file is small, we just load it.
+          (nnheader-insert-file-contents file)
+        ;; We start on the assumption that FIRST is pretty recent.  If
+        ;; not, we just insert the rest of the file as well.
+        (let (current)
+          (nnheader-insert-file-contents file nil (- size cutoff) size)
+          (goto-char (point-min))
+          (delete-region (point) (or (search-forward "\n" nil 'move) (point)))
+          (setq current (ignore-errors (read (current-buffer))))
+          (if (and (numberp current)
+                   (< current first))
+              t
+            (delete-region (point-min) (point-max))
+            (nnheader-insert-file-contents file)))))))
+
+(defun nnheader-find-file-noselect (&rest args)
+  "Open a file with some variables bound.
+See `find-file-noselect' for the arguments."
+  (letf* ((format-alist nil)
+          (auto-mode-alist (mm-auto-mode-alist))
+          ((default-value 'major-mode) 'fundamental-mode)
+          (enable-local-variables nil)
+          (after-insert-file-functions nil)
+          (enable-local-eval nil)
+          (coding-system-for-read nnheader-file-coding-system)
+          (version-control 'never)
+          (ffh (if (boundp 'find-file-hook)
+                   'find-file-hook
+                 'find-file-hooks))
+          (val (symbol-value ffh)))
+    (set ffh nil)
+    (unwind-protect
+       (apply 'find-file-noselect args)
+      (set ffh val))))
+
+(defun nnheader-directory-regular-files (dir)
+  "Return a list of all regular files in DIR."
+  (let ((files (directory-files dir t))
+       out)
+    (while files
+      (when (file-regular-p (car files))
+       (push (car files) out))
+      (pop files))
+    (nreverse out)))
+
+(defun nnheader-directory-files (&rest args)
+  "Same as `directory-files', but prune \".\" and \"..\"."
+  (let ((files (apply 'directory-files args))
+       out)
+    (while files
+      (unless (member (file-name-nondirectory (car files)) '("." ".."))
+       (push (car files) out))
+      (pop files))
+    (nreverse out)))
+
+(defmacro nnheader-skeleton-replace (from &optional to regexp)
+  `(let ((new (generate-new-buffer " *nnheader replace*"))
+        (cur (current-buffer))
+        (start (point-min)))
+     (set-buffer cur)
+     (goto-char (point-min))
+     (while (,(if regexp 're-search-forward 'search-forward)
+            ,from nil t)
+       (insert-buffer-substring
+       cur start (prog1 (match-beginning 0) (set-buffer new)))
+       (goto-char (point-max))
+       ,(when to `(insert ,to))
+       (set-buffer cur)
+       (setq start (point)))
+     (insert-buffer-substring
+      cur start (prog1 (point-max) (set-buffer new)))
+     (copy-to-buffer cur (point-min) (point-max))
+     (kill-buffer (current-buffer))
+     (set-buffer cur)))
+
+(defun nnheader-replace-string (from to)
+  "Do a fast replacement of FROM to TO from point to `point-max'."
+  (nnheader-skeleton-replace from to))
+
+(defun nnheader-replace-regexp (from to)
+  "Do a fast regexp replacement of FROM to TO from point to `point-max'."
+  (nnheader-skeleton-replace from to t))
+
+(defun nnheader-strip-cr ()
+  "Strip all \r's from the current buffer."
+  (nnheader-skeleton-replace "\r"))
+
+(defalias 'nnheader-cancel-timer 'cancel-timer)
+(defalias 'nnheader-cancel-function-timers 'cancel-function-timers)
+
+;; When changing this function, consider changing `pop3-accept-process-output'
+;; as well.
+(defun nnheader-accept-process-output (process)
+  (accept-process-output
+   process
+   (truncate nnheader-read-timeout)
+   (truncate (* (- nnheader-read-timeout
+                  (truncate nnheader-read-timeout))
+               1000))))
+
+(defun nnheader-update-marks-actions (backend-marks actions)
+  (dolist (action actions)
+    (let ((range (nth 0 action))
+         (what  (nth 1 action))
+         (marks (nth 2 action)))
+      (dolist (mark marks)
+       (setq backend-marks
+             (gnus-update-alist-soft
+              mark
+              (cond
+               ((eq what 'add)
+                (gnus-range-add (cdr (assoc mark backend-marks)) range))
+               ((eq what 'del)
+                (gnus-remove-from-range
+                 (cdr (assoc mark backend-marks)) range))
+               ((eq what 'set)
+                range))
+              backend-marks)))))
+  backend-marks)
+
+(defmacro nnheader-insert-buffer-substring (buffer &optional start end)
+  "Copy string from unibyte buffer to multibyte current buffer."
+  (if (featurep 'xemacs)
+      `(insert-buffer-substring ,buffer ,start ,end)
+    `(if enable-multibyte-characters
+        (insert (with-current-buffer ,buffer
+                  (mm-string-to-multibyte
+                   ,(if (or start end)
+                        `(buffer-substring (or ,start (point-min))
+                                           (or ,end (point-max)))
+                      '(buffer-string)))))
+       (insert-buffer-substring ,buffer ,start ,end))))
+
+(defvar nnheader-last-message-time '(0 0))
+(defun nnheader-message-maybe (&rest args)
+  (let ((now (current-time)))
+    (when (> (float-time (time-subtract now nnheader-last-message-time)) 1)
+      (setq nnheader-last-message-time now)
+      (apply 'nnheader-message args))))
+
+(when (featurep 'xemacs)
+  (require 'nnheaderxm))
+
+(run-hooks 'nnheader-load-hook)
+
+(provide 'nnheader)
+
+;;; nnheader.el ends here
diff --git a/xemacs-packages/gnus/lisp/nnheaderxm.el b/xemacs-packages/gnus/lisp/nnheaderxm.el
new file mode 100644 (file)
index 0000000..ff5fe21
--- /dev/null
@@ -0,0 +1,32 @@
+;;; nnheaderxm.el --- making Gnus backends work under XEmacs
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3, 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.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(defalias 'nnheader-cancel-timer 'delete-itimer)
+(defalias 'nnheader-string-as-multibyte 'identity)
+
+(provide 'nnheaderxm)
+
+;;; nnheaderxm.el ends here
diff --git a/xemacs-packages/gnus/lisp/nnimap.el b/xemacs-packages/gnus/lisp/nnimap.el
new file mode 100644 (file)
index 0000000..05251ed
--- /dev/null
@@ -0,0 +1,2228 @@
+;;; nnimap.el --- IMAP interface for Gnus
+
+;; Copyright (C) 2010-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;;         Simon Josefsson <simon@josefsson.org>
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; nnimap interfaces Gnus with IMAP servers.
+
+;;; Code:
+
+(eval-and-compile
+  (require 'nnheader)
+  ;; In Emacs 24, `open-protocol-stream' is an autoloaded alias for
+  ;; `make-network-stream'.
+  (unless (fboundp 'open-protocol-stream)
+    (require 'proto-stream)))
+
+(eval-when-compile
+  (require 'cl))
+
+(require 'nnheader)
+(require 'gnus-util)
+(require 'gnus)
+(require 'nnoo)
+(require 'netrc)
+(require 'utf7)
+(require 'tls)
+(require 'parse-time)
+(require 'nnmail)
+
+(autoload 'auth-source-forget+ "auth-source")
+(autoload 'auth-source-search "auth-source")
+
+(nnoo-declare nnimap)
+
+(defvoo nnimap-address nil
+  "The address of the IMAP server.")
+
+(defvoo nnimap-user nil
+  "Username to use for authentication to the IMAP server.")
+
+(defvoo nnimap-server-port nil
+  "The IMAP port used.
+If nnimap-stream is `ssl', this will default to `imaps'.  If not,
+it will default to `imap'.")
+
+(defvoo nnimap-stream 'undecided
+  "How nnimap talks to the IMAP server.
+The value should be either `undecided', `ssl' or `tls',
+`network', `starttls', `plain', or `shell'.
+
+If the value is `undecided', nnimap tries `ssl' first, then falls
+back on `network'.")
+
+(defvoo nnimap-shell-program (if (boundp 'imap-shell-program)
+                                (if (listp imap-shell-program)
+                                    (car imap-shell-program)
+                                  imap-shell-program)
+                              "ssh %s imapd"))
+
+(defvoo nnimap-inbox nil
+  "The mail box where incoming mail arrives and should be split out of.
+This can be a string or a list of strings
+For example, \"INBOX\" or (\"INBOX\" \"SENT\").")
+
+(defvoo nnimap-split-methods nil
+  "How mail is split.
+Uses the same syntax as `nnmail-split-methods'.")
+
+(defvoo nnimap-split-fancy nil
+  "Uses the same syntax as `nnmail-split-fancy'.")
+
+(defvoo nnimap-unsplittable-articles '(%Deleted %Seen)
+  "Articles with the flags in the list will not be considered when splitting.")
+
+(make-obsolete-variable 'nnimap-split-rule "see `nnimap-split-methods'."
+                       "Emacs 24.1")
+
+(defvoo nnimap-authenticator nil
+  "How nnimap authenticate itself to the server.
+Possible choices are nil (use default methods), `anonymous',
+`login', `plain' and `cram-md5'.")
+
+(defvoo nnimap-expunge t
+  "If non-nil, expunge articles after deleting them.
+This is always done if the server supports UID EXPUNGE, but it's
+not done by default on servers that doesn't support that command.")
+
+(defvoo nnimap-streaming t
+  "If non-nil, try to use streaming commands with IMAP servers.
+Switching this off will make nnimap slower, but it helps with
+some servers.")
+
+(defvoo nnimap-connection-alist nil)
+
+(defvoo nnimap-current-infos nil)
+
+(defvoo nnimap-fetch-partial-articles nil
+  "If non-nil, Gnus will fetch partial articles.
+If t, Gnus will fetch only the first part.  If a string, it
+will fetch all parts that have types that match that string.  A
+likely value would be \"text/\" to automatically fetch all
+textual parts.")
+
+(defgroup nnimap nil
+  "IMAP for Gnus."
+  :group 'gnus)
+
+(defcustom nnimap-request-articles-find-limit nil
+  "Limit the number of articles to look for after moving an article."
+  :type '(choice (const nil) integer)
+  :version "24.4"
+  :group 'nnimap)
+
+(defvar nnimap-process nil)
+
+(defvar nnimap-status-string "")
+
+(defvar nnimap-split-download-body-default nil
+  "Internal variable with default value for `nnimap-split-download-body'.")
+
+(defvar nnimap-keepalive-timer nil)
+(defvar nnimap-process-buffers nil)
+
+(defstruct nnimap
+  group process commands capabilities select-result newlinep server
+  last-command-time greeting examined stream-type initial-resync)
+
+(defvar nnimap-object nil)
+
+(defvar nnimap-mark-alist
+  '((read "\\Seen" %Seen)
+    (tick "\\Flagged" %Flagged)
+    (reply "\\Answered" %Answered)
+    (expire "gnus-expire")
+    (dormant "gnus-dormant")
+    (score "gnus-score")
+    (save "gnus-save")
+    (download "gnus-download")
+    (forward "gnus-forward")))
+
+(defvar nnimap-quirks
+  '(("QRESYNC" "Zimbra" "QRESYNC ")))
+
+(defvar nnimap-inhibit-logging nil)
+
+(defun nnimap-buffer ()
+  (nnimap-find-process-buffer nntp-server-buffer))
+
+(defun nnimap-header-parameters ()
+  (let (params)
+    (push "UID" params)
+    (push "RFC822.SIZE" params)
+    (when (nnimap-capability "X-GM-EXT-1")
+      (push "X-GM-LABELS" params))
+    (push "BODYSTRUCTURE" params)
+    (push (format
+          (if (nnimap-ver4-p)
+              "BODY.PEEK[HEADER.FIELDS %s]"
+            "RFC822.HEADER.LINES %s")
+          (append '(Subject From Date Message-Id
+                            References In-Reply-To Xref)
+                  nnmail-extra-headers))
+         params)
+    (format "%s" (nreverse params))))
+
+(deffoo nnimap-retrieve-headers (articles &optional group server _fetch-old)
+  (when group
+    (setq group (nnimap-decode-gnus-group group)))
+  (with-current-buffer nntp-server-buffer
+    (erase-buffer)
+    (when (nnimap-change-group group server)
+      (with-current-buffer (nnimap-buffer)
+       (erase-buffer)
+       (nnimap-wait-for-response
+        (nnimap-send-command
+         "UID FETCH %s %s"
+         (nnimap-article-ranges (gnus-compress-sequence articles))
+         (nnimap-header-parameters))
+        t)
+       (unless (process-live-p (get-buffer-process (current-buffer)))
+         (error "Server closed connection"))
+       (nnimap-transform-headers)
+       (nnheader-remove-cr-followed-by-lf))
+      (insert-buffer-substring
+       (nnimap-find-process-buffer (current-buffer))))
+    'headers))
+
+(defun nnimap-transform-headers ()
+  (goto-char (point-min))
+  (let (article lines size string labels)
+    (block nil
+      (while (not (eobp))
+       (while (not (looking-at "\\* [0-9]+ FETCH"))
+         (delete-region (point) (progn (forward-line 1) (point)))
+         (when (eobp)
+           (return)))
+       (goto-char (match-end 0))
+       ;; Unfold quoted {number} strings.
+       (while (re-search-forward
+               "[^]][ (]{\\([0-9]+\\)}\r?\n"
+               (save-excursion
+                 ;; Start of the header section.
+                 (or (re-search-forward "] {[0-9]+}\r?\n" nil t)
+                     ;; Start of the next FETCH.
+                     (re-search-forward "\\* [0-9]+ FETCH" nil t)
+                     (point-max)))
+               t)
+         (setq size (string-to-number (match-string 1)))
+         (delete-region (+ (match-beginning 0) 2) (point))
+         (setq string (buffer-substring (point) (+ (point) size)))
+         (delete-region (point) (+ (point) size))
+         (insert (format "%S" (mm-subst-char-in-string ?\n ?\s string))))
+       (beginning-of-line)
+       (setq article
+             (and (re-search-forward "UID \\([0-9]+\\)" (line-end-position)
+                                     t)
+                  (match-string 1)))
+       (setq lines nil)
+       (beginning-of-line)
+       (setq size
+             (and (re-search-forward "RFC822.SIZE \\([0-9]+\\)"
+                                     (line-end-position)
+                                     t)
+                  (match-string 1)))
+       (beginning-of-line)
+       (when (search-forward "X-GM-LABELS" (line-end-position) t)
+         (setq labels (ignore-errors (read (current-buffer)))))
+       (beginning-of-line)
+       (when (search-forward "BODYSTRUCTURE" (line-end-position) t)
+         (let ((structure (ignore-errors
+                            (read (current-buffer)))))
+           (while (and (consp structure)
+                       (not (atom (car structure))))
+             (setq structure (car structure)))
+           (setq lines (if (and
+                            (stringp (car structure))
+                            (equal (upcase (nth 0 structure)) "MESSAGE")
+                            (equal (upcase (nth 1 structure)) "RFC822"))
+                           (nth 9 structure)
+                         (nth 7 structure)))))
+       (delete-region (line-beginning-position) (line-end-position))
+       (insert (format "211 %s Article retrieved." article))
+       (forward-line 1)
+       (when size
+         (insert (format "Chars: %s\n" size)))
+       (when lines
+         (insert (format "Lines: %s\n" lines)))
+       (when labels
+         (insert (format "X-GM-LABELS: %s\n" labels)))
+       ;; Most servers have a blank line after the headers, but
+       ;; Davmail doesn't.
+       (unless (re-search-forward "^\r$\\|^)\r?$" nil t)
+         (goto-char (point-max)))
+       (delete-region (line-beginning-position) (line-end-position))
+       (insert ".")
+       (forward-line 1)))))
+
+(defun nnimap-unfold-quoted-lines ()
+  ;; Unfold quoted {number} strings.
+  (let (size string)
+    (while (re-search-forward " {\\([0-9]+\\)}\r?\n" nil t)
+      (setq size (string-to-number (match-string 1)))
+      (delete-region (1+ (match-beginning 0)) (point))
+      (setq string (buffer-substring (point) (+ (point) size)))
+      (delete-region (point) (+ (point) size))
+      (insert (format "%S" string)))))
+
+(defun nnimap-get-length ()
+  (and (re-search-forward "{\\([0-9]+\\)}" (line-end-position) t)
+       (string-to-number (match-string 1))))
+
+(defun nnimap-article-ranges (ranges)
+  (let (result)
+    (cond
+     ((numberp ranges)
+      (number-to-string ranges))
+     ((numberp (cdr ranges))
+      (format "%d:%d" (car ranges) (cdr ranges)))
+     (t
+      (dolist (elem ranges)
+       (push
+        (if (consp elem)
+            (format "%d:%d" (car elem) (cdr elem))
+          (number-to-string elem))
+        result))
+      (mapconcat #'identity (nreverse result) ",")))))
+
+(deffoo nnimap-open-server (server &optional defs no-reconnect)
+  (if (nnimap-server-opened server)
+      t
+    (unless (assq 'nnimap-address defs)
+      (setq defs (append defs (list (list 'nnimap-address server)))))
+    (nnoo-change-server 'nnimap server defs)
+    (if no-reconnect
+       (nnimap-find-connection nntp-server-buffer)
+      (or (nnimap-find-connection nntp-server-buffer)
+         (nnimap-open-connection nntp-server-buffer)))))
+
+(defun nnimap-make-process-buffer (buffer)
+  (with-current-buffer
+      (generate-new-buffer (format " *nnimap %s %s %s*"
+                                  nnimap-address nnimap-server-port
+                                  (gnus-buffer-exists-p buffer)))
+    (mm-disable-multibyte)
+    (buffer-disable-undo)
+    (gnus-add-buffer)
+    (set (make-local-variable 'after-change-functions) nil)
+    (set (make-local-variable 'nnimap-object)
+        (make-nnimap :server (nnoo-current-server 'nnimap)
+                     :initial-resync 0))
+    (push (list buffer (current-buffer)) nnimap-connection-alist)
+    (push (current-buffer) nnimap-process-buffers)
+    (current-buffer)))
+
+(defvar auth-source-creation-prompts)
+
+(defun nnimap-credentials (address ports user)
+  (let* ((auth-source-creation-prompts
+          '((user  . "IMAP user at %h: ")
+            (secret . "IMAP password for %u@%h: ")))
+         (found (nth 0 (auth-source-search :max 1
+                                           :host address
+                                           :port ports
+                                           :user user
+                                           :require '(:user :secret)
+                                           :create t))))
+    (if found
+        (list (plist-get found :user)
+             (let ((secret (plist-get found :secret)))
+               (if (functionp secret)
+                   (funcall secret)
+                 secret))
+             (plist-get found :save-function))
+      nil)))
+
+(defun nnimap-keepalive ()
+  (let ((now (current-time)))
+    (dolist (buffer nnimap-process-buffers)
+      (when (buffer-name buffer)
+       (with-current-buffer buffer
+         (when (and nnimap-object
+                    (nnimap-last-command-time nnimap-object)
+                    (> (gnus-float-time
+                        (time-subtract
+                         now
+                         (nnimap-last-command-time nnimap-object)))
+                       ;; More than five minutes since the last command.
+                       (* 5 60)))
+            (ignore-errors              ;E.g. "buffer foo has no process".
+              (nnimap-send-command "NOOP"))))))))
+
+(defun nnimap-open-connection (buffer)
+  ;; Be backwards-compatible -- the earlier value of nnimap-stream was
+  ;; `ssl' when nnimap-server-port was nil.  Sort of.
+  (when (and nnimap-server-port
+            (eq nnimap-stream 'undecided))
+    (setq nnimap-stream 'ssl))
+  (let ((stream
+        (if (eq nnimap-stream 'undecided)
+            (loop for type in '(ssl network)
+                  for stream = (let ((nnimap-stream type))
+                                 (nnimap-open-connection-1 buffer))
+                  while (eq stream 'no-connect)
+                  finally (return stream))
+          (nnimap-open-connection-1 buffer))))
+    (if (eq stream 'no-connect)
+       nil
+      stream)))
+
+(defun nnimap-map-port (port)
+  (if (equal port "imaps")
+      "993"
+    port))
+
+(defun nnimap-open-connection-1 (buffer)
+  (unless nnimap-keepalive-timer
+    (setq nnimap-keepalive-timer (run-at-time (* 60 15) (* 60 15)
+                                             #'nnimap-keepalive)))
+  (with-current-buffer (nnimap-make-process-buffer buffer)
+    (let* ((coding-system-for-read 'binary)
+          (coding-system-for-write 'binary)
+          (ports
+           (cond
+            ((memq nnimap-stream '(network plain starttls))
+             (nnheader-message 7 "Opening connection to %s..."
+                               nnimap-address)
+             '("imap" "143"))
+            ((eq nnimap-stream 'shell)
+             (nnheader-message 7 "Opening connection to %s via shell..."
+                               nnimap-address)
+             '("imap"))
+            ((memq nnimap-stream '(ssl tls))
+             (nnheader-message 7 "Opening connection to %s via tls..."
+                               nnimap-address)
+             '("imaps" "imap" "993" "143"))
+            (t
+             (error "Unknown stream type: %s" nnimap-stream))))
+           login-result credentials)
+      (when nnimap-server-port
+       (push nnimap-server-port ports))
+      (let* ((stream-list
+             (open-protocol-stream
+              "*nnimap*" (current-buffer) nnimap-address
+              (nnimap-map-port (car ports))
+              :type nnimap-stream
+              :warn-unless-encrypted t
+              :return-list t
+              :shell-command nnimap-shell-program
+              :capability-command "1 CAPABILITY\r\n"
+               :always-query-capabilities t
+              :end-of-command "\r\n"
+              :success " OK "
+              :starttls-function
+              (lambda (capabilities)
+                (when (gnus-string-match-p "STARTTLS" capabilities)
+                  "1 STARTTLS\r\n"))))
+            (stream (car stream-list))
+            (props (cdr stream-list))
+            (greeting (plist-get props :greeting))
+            (capabilities (plist-get props :capabilities))
+            (stream-type (plist-get props :type)))
+       (when (and stream (not (memq (process-status stream) '(open run))))
+         (setq stream nil))
+
+        (when (and (fboundp 'set-network-process-option) ;; Not in XEmacs.
+                   (fboundp 'process-type) ;; Emacs 22 doesn't provide it.
+                   (eq (process-type stream) 'network))
+          ;; Use TCP-keepalive so that connections that pass through a NAT
+          ;; router don't hang when left idle.
+          (set-network-process-option stream :keepalive t))
+
+       (setf (nnimap-process nnimap-object) stream)
+       (setf (nnimap-stream-type nnimap-object) stream-type)
+       (if (not stream)
+           (progn
+             (nnheader-report 'nnimap "Unable to contact %s:%s via %s"
+                              nnimap-address (car ports) nnimap-stream)
+             'no-connect)
+         (gnus-set-process-query-on-exit-flag stream nil)
+         (if (not (gnus-string-match-p "[*.] \\(OK\\|PREAUTH\\)" greeting))
+             (nnheader-report 'nnimap "%s" greeting)
+           ;; Store the greeting (for debugging purposes).
+           (setf (nnimap-greeting nnimap-object) greeting)
+           (setf (nnimap-capabilities nnimap-object)
+                 (mapcar #'upcase
+                         (split-string capabilities)))
+           (unless (gnus-string-match-p "[*.] PREAUTH" greeting)
+             (if (not (setq credentials
+                            (if (eq nnimap-authenticator 'anonymous)
+                                (list "anonymous"
+                                      (message-make-address))
+                               ;; Look for the credentials based on
+                               ;; the virtual server name and the address
+                               (nnimap-credentials
+                               (gnus-delete-duplicates
+                                (list
+                                  (nnoo-current-server 'nnimap)
+                                 nnimap-address))
+                                ports
+                                nnimap-user))))
+                 (setq nnimap-object nil)
+               (let ((nnimap-inhibit-logging t))
+                 (setq login-result
+                       (nnimap-login (car credentials) (cadr credentials))))
+               (if (car login-result)
+                   (progn
+                     ;; Save the credentials if a save function exists
+                     ;; (such a function will only be passed if a new
+                     ;; token was created).
+                     (when (functionp (nth 2 credentials))
+                       (funcall (nth 2 credentials)))
+                     ;; See if CAPABILITY is set as part of login
+                     ;; response.
+                     (dolist (response (cddr (nnimap-command "CAPABILITY")))
+                       (when (string= "CAPABILITY" (upcase (car response)))
+                         (setf (nnimap-capabilities nnimap-object)
+                               (mapcar #'upcase (cdr response))))))
+                 ;; If the login failed, then forget the credentials
+                 ;; that are now possibly cached.
+                 (dolist (host (list (nnoo-current-server 'nnimap)
+                                     nnimap-address))
+                   (dolist (port ports)
+                      (auth-source-forget+ :host host :port port)))
+                 (delete-process (nnimap-process nnimap-object))
+                 (setq nnimap-object nil))))
+           (when nnimap-object
+             (when (nnimap-capability "QRESYNC")
+               (nnimap-command "ENABLE QRESYNC"))
+              (nnheader-message 7 "Opening connection to %s...done"
+                               nnimap-address)
+             (nnimap-process nnimap-object))))))))
+
+(autoload 'rfc2104-hash "rfc2104")
+
+(defun nnimap-login (user password)
+  (cond
+   ;; Prefer plain LOGIN if it's enabled (since it requires fewer
+   ;; round trips than CRAM-MD5, and it's less likely to be buggy),
+   ;; and we're using an encrypted connection.
+   ((and (not (nnimap-capability "LOGINDISABLED"))
+        (eq (nnimap-stream-type nnimap-object) 'tls)
+        (or (null nnimap-authenticator)
+            (eq nnimap-authenticator 'login)))
+    (nnimap-command "LOGIN %S %S" user password))
+   ((and (nnimap-capability "AUTH=CRAM-MD5")
+        (or (null nnimap-authenticator)
+            (eq nnimap-authenticator 'cram-md5)))
+    (erase-buffer)
+    (let ((sequence (nnimap-send-command "AUTHENTICATE CRAM-MD5"))
+         (challenge (nnimap-wait-for-line "^\\+\\(.*\\)\n")))
+      (process-send-string
+       (get-buffer-process (current-buffer))
+       (concat
+       (base64-encode-string
+        (concat user " "
+                (rfc2104-hash 'md5 64 16 password
+                              (base64-decode-string challenge))))
+       "\r\n"))
+      (nnimap-wait-for-response sequence)))
+   ((and (not (nnimap-capability "LOGINDISABLED"))
+        (or (null nnimap-authenticator)
+            (eq nnimap-authenticator 'login)))
+    (nnimap-command "LOGIN %S %S" user password))
+   ((and (nnimap-capability "AUTH=PLAIN")
+        (or (null nnimap-authenticator)
+            (eq nnimap-authenticator 'plain)))
+    (nnimap-command
+     "AUTHENTICATE PLAIN %s"
+     (base64-encode-string
+      (format "\000%s\000%s"
+             (nnimap-quote-specials user)
+             (nnimap-quote-specials password)))))))
+
+(defun nnimap-quote-specials (string)
+  (with-temp-buffer
+    (insert string)
+    (goto-char (point-min))
+    (while (re-search-forward "[\\\"]" nil t)
+      (forward-char -1)
+      (insert "\\")
+      (forward-char 1))
+    (buffer-string)))
+
+(defun nnimap-find-parameter (parameter elems)
+  (let (result)
+    (dolist (elem elems)
+      (cond
+       ((equal (car elem) parameter)
+       (setq result (cdr elem)))
+       ((and (equal (car elem) "OK")
+            (consp (cadr elem))
+            (equal (caadr elem) parameter))
+       (setq result (cdr (cadr elem))))))
+    result))
+
+(deffoo nnimap-close-server (&optional server)
+  (when (nnoo-change-server 'nnimap server nil)
+    (ignore-errors
+      (delete-process (get-buffer-process (nnimap-buffer))))
+    (nnoo-close-server 'nnimap server)
+    t))
+
+(deffoo nnimap-request-close ()
+  t)
+
+(deffoo nnimap-server-opened (&optional server)
+  (and (nnoo-current-server-p 'nnimap server)
+       nntp-server-buffer
+       (gnus-buffer-live-p nntp-server-buffer)
+       (nnimap-find-connection nntp-server-buffer)))
+
+(deffoo nnimap-status-message (&optional _server)
+  nnimap-status-string)
+
+(deffoo nnimap-request-article (article &optional group server to-buffer)
+  (when group
+    (setq group (nnimap-decode-gnus-group group)))
+  (with-current-buffer nntp-server-buffer
+    (let ((result (nnimap-change-group group server))
+         parts structure)
+      (when (stringp article)
+       (setq article (nnimap-find-article-by-message-id group server article)))
+      (when (and result
+                article)
+       (erase-buffer)
+       (with-current-buffer (nnimap-buffer)
+         (erase-buffer)
+         (when nnimap-fetch-partial-articles
+           (nnimap-command "UID FETCH %d (BODYSTRUCTURE)" article)
+           (goto-char (point-min))
+           (when (re-search-forward "FETCH.*BODYSTRUCTURE" nil t)
+             (setq structure (ignore-errors
+                               (let ((start (point)))
+                                 (forward-sexp 1)
+                                 (downcase-region start (point))
+                                 (goto-char start)
+                                 (read (current-buffer))))
+                   parts (nnimap-find-wanted-parts structure))))
+         (when (if parts
+                   (nnimap-get-partial-article article parts structure)
+                 (nnimap-get-whole-article article))
+           (let ((buffer (current-buffer)))
+             (with-current-buffer (or to-buffer nntp-server-buffer)
+               (nnheader-insert-buffer-substring buffer)
+               (nnheader-ms-strip-cr)))
+           (cons group article)))))))
+
+(deffoo nnimap-request-head (article &optional group server to-buffer)
+  (when group
+    (setq group (nnimap-decode-gnus-group group)))
+  (when (nnimap-change-group group server)
+    (with-current-buffer (nnimap-buffer)
+      (when (stringp article)
+       (setq article (nnimap-find-article-by-message-id group server article)))
+      (if (null article)
+         nil
+       (nnimap-get-whole-article
+        article (format "UID FETCH %%d %s"
+                        (nnimap-header-parameters)))
+       (let ((buffer (current-buffer)))
+         (with-current-buffer (or to-buffer nntp-server-buffer)
+           (erase-buffer)
+           (insert-buffer-substring buffer)
+           (nnheader-ms-strip-cr)
+           (cons group article)))))))
+
+(deffoo nnimap-request-articles (articles &optional group server)
+  (when group
+    (setq group (nnimap-decode-gnus-group group)))
+  (with-current-buffer nntp-server-buffer
+    (let ((result (nnimap-change-group group server)))
+      (when result
+       (erase-buffer)
+       (with-current-buffer (nnimap-buffer)
+         (erase-buffer)
+         (when (nnimap-command
+                (if (nnimap-ver4-p)
+                    "UID FETCH %s BODY.PEEK[]"
+                  "UID FETCH %s RFC822.PEEK")
+                (nnimap-article-ranges (gnus-compress-sequence articles)))
+           (let ((buffer (current-buffer)))
+             (with-current-buffer nntp-server-buffer
+               (nnheader-insert-buffer-substring buffer)
+               (nnheader-ms-strip-cr)))
+           t))))))
+
+(defun nnimap-get-whole-article (article &optional command)
+  (let ((result
+        (nnimap-command
+         (or command
+             (if (nnimap-ver4-p)
+                 "UID FETCH %d BODY.PEEK[]"
+               "UID FETCH %d RFC822.PEEK"))
+         article)))
+    ;; Check that we really got an article.
+    (goto-char (point-min))
+    (unless (re-search-forward "\\* [0-9]+ FETCH" nil t)
+      (setq result nil))
+    (when result
+      ;; Remove any data that may have arrived before the FETCH data.
+      (beginning-of-line)
+      (unless (bobp)
+       (delete-region (point-min) (point)))
+      (let ((bytes (nnimap-get-length)))
+       (delete-region (line-beginning-position)
+                      (progn (forward-line 1) (point)))
+       (goto-char (+ (point) bytes))
+       (delete-region (point) (point-max)))
+      t)))
+
+(defun nnimap-capability (capability)
+  (member capability (nnimap-capabilities nnimap-object)))
+
+(defun nnimap-ver4-p ()
+  (nnimap-capability "IMAP4REV1"))
+
+(defun nnimap-get-partial-article (article parts structure)
+  (let ((result
+        (nnimap-command
+         "UID FETCH %d (%s %s)"
+         article
+         (if (nnimap-ver4-p)
+             "BODY.PEEK[HEADER]"
+           "RFC822.HEADER")
+         (if (nnimap-ver4-p)
+             (mapconcat (lambda (part)
+                          (format "BODY.PEEK[%s]" part))
+                        parts " ")
+           (mapconcat (lambda (part)
+                        (format "RFC822.PEEK[%s]" part))
+                      parts " ")))))
+    (when result
+      (nnimap-convert-partial-article structure))))
+
+(defun nnimap-convert-partial-article (structure)
+  ;; First just skip past the headers.
+  (goto-char (point-min))
+  (let ((bytes (nnimap-get-length))
+       id parts)
+    ;; Delete "FETCH" line.
+    (delete-region (line-beginning-position)
+                  (progn (forward-line 1) (point)))
+    (goto-char (+ (point) bytes))
+    ;; Collect all the body parts.
+    (while (looking-at ".*BODY\\[\\([.0-9]+\\)\\]")
+      (setq id (match-string 1)
+           bytes (or (nnimap-get-length) 0))
+      (beginning-of-line)
+      (delete-region (point) (progn (forward-line 1) (point)))
+      (push (list id (buffer-substring (point) (+ (point) bytes)))
+           parts)
+      (delete-region (point) (+ (point) bytes)))
+    ;; Delete trailing junk.
+    (delete-region (point) (point-max))
+    ;; Now insert all the parts again where they fit in the structure.
+    (nnimap-insert-partial-structure structure parts)
+    t))
+
+(defun nnimap-insert-partial-structure (structure parts &optional subp)
+  (let (type boundary)
+    (let ((bstruc structure))
+      (while (consp (car bstruc))
+       (pop bstruc))
+      (setq type (car bstruc))
+      (setq bstruc (car (cdr bstruc)))
+      (let ((has-boundary (member "boundary" bstruc)))
+        (when has-boundary
+          (setq boundary (cadr has-boundary)))))
+    (when subp
+      (insert (format "Content-type: multipart/%s; boundary=%S\n\n"
+                     (downcase type) boundary)))
+    (while (not (stringp (car structure)))
+      (insert "\n--" boundary "\n")
+      (if (consp (caar structure))
+         (nnimap-insert-partial-structure (pop structure) parts t)
+       (let ((bit (pop structure)))
+         (insert (format "Content-type: %s/%s"
+                         (downcase (nth 0 bit))
+                         (downcase (nth 1 bit))))
+         (if (member-ignore-case "CHARSET" (nth 2 bit))
+             (insert (format
+                      "; charset=%S\n"
+                      (cadr (member-ignore-case "CHARSET" (nth 2 bit)))))
+           (insert "\n"))
+         (insert (format "Content-transfer-encoding: %s\n"
+                         (nth 5 bit)))
+         (insert "\n")
+         (when (assoc (nth 9 bit) parts)
+           (insert (cadr (assoc (nth 9 bit) parts)))))))
+    (insert "\n--" boundary "--\n")))
+
+(defun nnimap-find-wanted-parts (structure)
+  (message-flatten-list (nnimap-find-wanted-parts-1 structure "")))
+
+(defun nnimap-find-wanted-parts-1 (structure prefix)
+  (let ((num 1)
+       parts)
+    (while (consp (car structure))
+      (let ((sub (pop structure)))
+       (if (consp (car sub))
+           (push (nnimap-find-wanted-parts-1
+                  sub (if (string= prefix "")
+                          (number-to-string num)
+                        (format "%s.%s" prefix num)))
+                 parts)
+         (let ((type (format "%s/%s" (nth 0 sub) (nth 1 sub)))
+               (id (if (string= prefix "")
+                       (number-to-string num)
+                     (format "%s.%s" prefix num))))
+           (setcar (nthcdr 9 sub) id)
+           (when (if (eq nnimap-fetch-partial-articles t)
+                     (equal id "1")
+                   (string-match nnimap-fetch-partial-articles type))
+             (push id parts))))
+       (incf num)))
+    (nreverse parts)))
+
+(defun nnimap-decode-gnus-group (group)
+  (decode-coding-string group 'utf-8))
+
+(deffoo nnimap-request-group (group &optional server dont-check info)
+  (setq group (nnimap-decode-gnus-group group))
+  (let ((result (nnimap-change-group
+                ;; Don't SELECT the group if we're going to select it
+                ;; later, anyway.
+                (if (and (not dont-check)
+                         (assoc group nnimap-current-infos))
+                    nil
+                  group)
+                server))
+       (info (when info (list info)))
+       active)
+    (with-current-buffer nntp-server-buffer
+      (when result
+       (when (or (not dont-check)
+                 (not (setq active
+                            (nth 2 (assoc group nnimap-current-infos)))))
+         (let ((sequences (nnimap-retrieve-group-data-early
+                           server info)))
+           (nnimap-finish-retrieve-group-infos server info sequences
+                                               t)
+           (setq active (nth 2 (assoc group nnimap-current-infos)))))
+       (setq active (or active '(0 . 1)))
+       (erase-buffer)
+       (insert (format "211 %d %d %d %S\n"
+                       (- (cdr active) (car active))
+                       (car active)
+                       (cdr active)
+                       group))
+       t))))
+
+(deffoo nnimap-request-group-scan (group &optional server info)
+  (setq group (nnimap-decode-gnus-group group))
+  (when (nnimap-change-group nil server)
+    (let (marks high low)
+      (with-current-buffer (nnimap-buffer)
+       (erase-buffer)
+       (let ((group-sequence
+              (nnimap-send-command "SELECT %S" (utf7-encode group t)))
+             (flag-sequence
+              (nnimap-send-command "UID FETCH 1:* FLAGS")))
+         (setf (nnimap-group nnimap-object) group)
+         (nnimap-wait-for-response flag-sequence)
+         (setq marks
+               (nnimap-flags-to-marks
+                (nnimap-parse-flags
+                 (list (list group-sequence flag-sequence
+                             1 group "SELECT")))))
+         (when (and info
+                    marks)
+           (nnimap-update-infos marks (list info))
+           (nnimap-store-info info (gnus-active (gnus-info-group info))))
+         (goto-char (point-max))
+         (let ((uidnext (nth 5 (car marks))))
+           (setq high (or (if uidnext
+                              (1- uidnext)
+                            (nth 3 (car marks)))
+                          0)
+                 low (or (nth 4 (car marks)) uidnext 1)))))
+      (with-current-buffer nntp-server-buffer
+       (erase-buffer)
+       (insert
+        (format
+         "211 %d %d %d %S\n" (1+ (- high low)) low high group))
+       t))))
+
+(deffoo nnimap-request-create-group (group &optional server _args)
+  (setq group (nnimap-decode-gnus-group group))
+  (when (nnimap-change-group nil server)
+    (with-current-buffer (nnimap-buffer)
+      (car (nnimap-command "CREATE %S" (utf7-encode group t))))))
+
+(deffoo nnimap-request-delete-group (group &optional _force server)
+  (setq group (nnimap-decode-gnus-group group))
+  (when (nnimap-change-group nil server)
+    (with-current-buffer (nnimap-buffer)
+      (car (nnimap-command "DELETE %S" (utf7-encode group t))))))
+
+(deffoo nnimap-request-rename-group (group new-name &optional server)
+  (setq group (nnimap-decode-gnus-group group))
+  (when (nnimap-change-group nil server)
+    (with-current-buffer (nnimap-buffer)
+      (nnimap-unselect-group)
+      (car (nnimap-command "RENAME %S %S"
+                          (utf7-encode group t) (utf7-encode new-name t))))))
+
+(defun nnimap-unselect-group ()
+  ;; Make sure we don't have this group open read/write by asking
+  ;; to examine a mailbox that doesn't exist.  This seems to be
+  ;; the only way that allows us to reliably go back to unselected
+  ;; state on Courier.
+  (nnimap-command "EXAMINE DOES.NOT.EXIST"))
+
+(deffoo nnimap-request-expunge-group (group &optional server)
+  (setq group (nnimap-decode-gnus-group group))
+  (when (nnimap-change-group group server)
+    (with-current-buffer (nnimap-buffer)
+      (car (nnimap-command "EXPUNGE")))))
+
+(defun nnimap-get-flags (spec)
+  (let ((articles nil)
+       elems end)
+    (with-current-buffer (nnimap-buffer)
+      (erase-buffer)
+      (nnimap-wait-for-response (nnimap-send-command
+                                "UID FETCH %s FLAGS" spec))
+      (setq end (point))
+      (subst-char-in-region (point-min) (point-max)
+                           ?\\ ?% t)
+      (goto-char (point-min))
+      (while (search-forward " FETCH " end t)
+       (setq elems (read (current-buffer)))
+       (push (cons (cadr (memq 'UID elems))
+                   (cadr (memq 'FLAGS elems)))
+             articles)))
+    (nreverse articles)))
+
+(deffoo nnimap-close-group (_group &optional _server)
+  t)
+
+(deffoo nnimap-request-move-article (article group server accept-form
+                                            &optional _last internal-move-group)
+  (setq group (nnimap-decode-gnus-group group))
+  (when internal-move-group
+    (setq internal-move-group (nnimap-decode-gnus-group internal-move-group)))
+  (with-temp-buffer
+    (mm-disable-multibyte)
+    (when (funcall (if internal-move-group
+                      'nnimap-request-head
+                    'nnimap-request-article)
+                  article group server (current-buffer))
+      ;; If the move is internal (on the same server), just do it the easy
+      ;; way.
+      (let ((message-id (message-field-value "message-id")))
+       (if internal-move-group
+            (with-current-buffer (nnimap-buffer)
+              (let* ((can-move (nnimap-capability "MOVE"))
+                    (command (if can-move
+                                 "UID MOVE %d %S"
+                               "UID COPY %d %S"))
+                    (result (nnimap-command command article
+                                            (utf7-encode internal-move-group t))))
+                (when (and (car result) (not can-move))
+                  (nnimap-delete-article article))
+                (cons internal-move-group
+                      (or (nnimap-find-uid-response "COPYUID" (caddr result))
+                          (nnimap-find-article-by-message-id
+                           internal-move-group server message-id
+                           nnimap-request-articles-find-limit)))))
+         ;; Move the article to a different method.
+         (let ((result (eval accept-form)))
+           (when result
+             (nnimap-change-group group server)
+             (nnimap-delete-article article)
+             result)))))))
+
+(deffoo nnimap-request-expire-articles (articles group &optional server force)
+  (setq group (nnimap-decode-gnus-group group))
+  (cond
+   ((null articles)
+    nil)
+   ((not (nnimap-change-group group server))
+    articles)
+   ((and force
+        (eq nnmail-expiry-target 'delete))
+    (unless (nnimap-delete-article (gnus-compress-sequence articles))
+      (nnheader-message 7 "Article marked for deletion, but not expunged."))
+    nil)
+   (t
+    (let ((deletable-articles
+          (if (or force
+                  (eq nnmail-expiry-wait 'immediate))
+              articles
+            (gnus-sorted-intersection
+             articles
+             (nnimap-find-expired-articles group)))))
+      (if (null deletable-articles)
+         articles
+       (if (eq nnmail-expiry-target 'delete)
+           (nnimap-delete-article (gnus-compress-sequence deletable-articles))
+         (setq deletable-articles
+               (nnimap-process-expiry-targets
+                deletable-articles group server)))
+       ;; Return the articles we didn't delete.
+       (gnus-sorted-complement articles deletable-articles))))))
+
+(defun nnimap-process-expiry-targets (articles group server)
+  (let ((deleted-articles nil)
+        (articles-to-delete nil))
+    (cond
+     ;; shortcut further processing if we're going to delete the articles
+     ((eq nnmail-expiry-target 'delete)
+      (setq articles-to-delete articles)
+      t)
+     ;; or just move them to another folder on the same IMAP server
+     ((and (not (functionp nnmail-expiry-target))
+          (gnus-server-equal (gnus-group-method nnmail-expiry-target)
+                             (gnus-server-to-method
+                              (format "nnimap:%s" server))))
+      (and (nnimap-change-group group server)
+          (with-current-buffer (nnimap-buffer)
+            (nnheader-message 7 "Expiring articles from %s: %s" group articles)
+             (let ((can-move (nnimap-capability "MOVE")))
+               (nnimap-command
+                (if can-move
+                    "UID MOVE %s %S"
+                  "UID COPY %s %S")
+                (nnimap-article-ranges (gnus-compress-sequence articles))
+                (utf7-encode (gnus-group-real-name nnmail-expiry-target) t))
+               (set (if can-move 'deleted-articles 'articles-to-delete) articles))))
+      t)
+     (t
+      (dolist (article articles)
+       (let ((target nnmail-expiry-target))
+         (with-temp-buffer
+           (mm-disable-multibyte)
+           (when (nnimap-request-article article group server (current-buffer))
+             (when (functionp target)
+               (setq target (funcall target group)))
+             (if (and target
+                      (not (eq target 'delete)))
+                 (if (or (gnus-request-group target t)
+                         (gnus-request-create-group target))
+                     (progn
+                       (nnmail-expiry-target-group target group)
+                       (nnheader-message 7 "Expiring article %s:%d to %s"
+                                         group article target))
+                   (setq target nil))
+               (nnheader-message 7 "Expiring article %s:%d" group article))
+             (when target
+               (push article articles-to-delete))))))
+      (setq articles-to-delete (nreverse articles-to-delete))))
+    ;; Change back to the current group again.
+    (nnimap-change-group group server)
+    (when articles-to-delete
+      (nnimap-delete-article (gnus-compress-sequence articles-to-delete))
+      (setq deleted-articles articles-to-delete))
+    deleted-articles))
+
+(defun nnimap-find-expired-articles (group)
+  (let ((cutoff (nnmail-expired-article-p group nil nil)))
+    (when cutoff
+      (with-current-buffer (nnimap-buffer)
+       (let ((result
+              (nnimap-command
+               "UID SEARCH SENTBEFORE %s"
+               (format-time-string
+                (format "%%d-%s-%%Y"
+                        (upcase
+                         (car (rassoc (nth 4 (decode-time cutoff))
+                                      parse-time-months))))
+                cutoff))))
+         (and (car result)
+              (delete 0 (mapcar #'string-to-number
+                                (cdr (assoc "SEARCH" (cdr result)))))))))))
+
+(defun nnimap-find-article-by-message-id (group server message-id
+                                               &optional limit)
+  "Search for message with MESSAGE-ID in GROUP from SERVER.
+If LIMIT, first try to limit the search to the N last articles."
+  (with-current-buffer (nnimap-buffer)
+    (erase-buffer)
+    (let* ((change-group-result (nnimap-change-group group server nil t))
+           (number-of-article
+            (and (listp change-group-result)
+                 (catch 'found
+                   (dolist (result (cdr change-group-result))
+                     (when (equal "EXISTS" (cadr result))
+                       (throw 'found (car result)))))))
+           (sequence
+            (nnimap-send-command
+            "UID SEARCH%s HEADER Message-Id %S"
+            (if (and limit number-of-article)
+                ;; The -1 is because IMAP message
+                ;; numbers are one-based rather than
+                ;; zero-based.
+                (format " %s:*" (- (string-to-number number-of-article)
+                                   limit -1))
+              "")
+            message-id)))
+      (when (nnimap-wait-for-response sequence)
+        (let ((article (car (last (cdr (assoc "SEARCH"
+                                             (nnimap-parse-response)))))))
+          (if article
+              (string-to-number article)
+            (when (and limit number-of-article)
+              (nnimap-find-article-by-message-id group server message-id))))))))
+
+(defun nnimap-delete-article (articles)
+  (with-current-buffer (nnimap-buffer)
+    (nnimap-command "UID STORE %s +FLAGS.SILENT (\\Deleted)"
+                   (nnimap-article-ranges articles))
+    (cond
+     ((nnimap-capability "UIDPLUS")
+      (nnimap-command "UID EXPUNGE %s"
+                     (nnimap-article-ranges articles))
+      t)
+     (nnimap-expunge
+      (nnimap-command "EXPUNGE")
+      t)
+     (t (gnus-message 7 (concat "nnimap: nnimap-expunge is not set and the "
+                                "server doesn't support UIDPLUS, so we won't "
+                                "delete this article now"))))))
+
+(deffoo nnimap-request-scan (&optional group server)
+  (when group
+    (setq group (nnimap-decode-gnus-group group)))
+  (when (and (nnimap-change-group nil server)
+            nnimap-inbox
+            nnimap-split-methods)
+    (nnheader-message 7 "nnimap %s splitting mail..." server)
+    (if (listp nnimap-inbox)
+       (dolist (nnimap-inbox nnimap-inbox)
+         (nnimap-split-incoming-mail))
+      (nnimap-split-incoming-mail))
+    (nnheader-message 7 "nnimap %s splitting mail...done" server)))
+
+(defun nnimap-marks-to-flags (marks)
+  (let (flags flag)
+    (dolist (mark marks)
+      (when (setq flag (cadr (assq mark nnimap-mark-alist)))
+       (push flag flags)))
+    flags))
+
+(deffoo nnimap-request-update-group-status (group status &optional server)
+  (setq group (nnimap-decode-gnus-group group))
+  (when (nnimap-change-group nil server)
+    (let ((command (assoc
+                   status
+                   '((subscribe "SUBSCRIBE")
+                     (unsubscribe "UNSUBSCRIBE")))))
+      (when command
+       (with-current-buffer (nnimap-buffer)
+         (nnimap-command "%s %S" (cadr command) (utf7-encode group t)))))))
+
+(deffoo nnimap-request-set-mark (group actions &optional server)
+  (setq group (nnimap-decode-gnus-group group))
+  (when (nnimap-change-group group server)
+    (let (sequence)
+      (with-current-buffer (nnimap-buffer)
+       (erase-buffer)
+       ;; Just send all the STORE commands without waiting for
+       ;; response.  If they're successful, they're successful.
+       (dolist (action actions)
+         (destructuring-bind (range action marks) action
+           (let ((flags (nnimap-marks-to-flags marks)))
+             (when flags
+               (setq sequence (nnimap-send-command
+                               "UID STORE %s %sFLAGS.SILENT (%s)"
+                               (nnimap-article-ranges range)
+                               (cond
+                                ((eq action 'del) "-")
+                                ((eq action 'add) "+")
+                                ((eq action 'set) ""))
+                               (mapconcat #'identity flags " ")))))))
+       ;; Wait for the last command to complete to avoid later
+       ;; synchronization problems with the stream.
+       (when sequence
+         (nnimap-wait-for-response sequence))))))
+
+(deffoo nnimap-request-accept-article (group &optional server _last)
+  (unless group
+    ;; We're respooling.  Find out where mail splitting would place
+    ;; this article.
+    (setq group
+         (caar
+          (nnmail-article-group
+           ;; We don't really care about the article number, because
+           ;; that's determined by the IMAP server later.  So just
+           ;; return the group name.
+           `(lambda (group)
+              (list (list group)))))))
+  (setq group (nnimap-decode-gnus-group group))
+  (when (nnimap-change-group nil server)
+    (nnmail-check-syntax)
+    (let ((message-id (message-field-value "message-id"))
+         sequence message)
+      (nnimap-add-cr)
+      (setq message (buffer-substring-no-properties (point-min) (point-max)))
+      (with-current-buffer (nnimap-buffer)
+       (when (setq message (or (nnimap-process-quirk "OK Gimap " 'append message)
+                               message))
+         ;; If we have this group open read-only, then unselect it
+         ;; before appending to it.
+         (when (equal (nnimap-examined nnimap-object) group)
+           (nnimap-unselect-group))
+         (erase-buffer)
+         (setq sequence (nnimap-send-command
+                         "APPEND %S {%d}" (utf7-encode group t)
+                         (length message)))
+         (unless nnimap-streaming
+           (nnimap-wait-for-connection "^[+]"))
+         (process-send-string (get-buffer-process (current-buffer)) message)
+         (process-send-string (get-buffer-process (current-buffer))
+                              (if (nnimap-newlinep nnimap-object)
+                                  "\n"
+                                "\r\n"))
+         (let ((result (nnimap-get-response sequence)))
+           (if (not (nnimap-ok-p result))
+               (progn
+                 (nnheader-report 'nnimap "%s" result)
+                 nil)
+             (cons group
+                   (or (nnimap-find-uid-response "APPENDUID" (car result))
+                       (nnimap-find-article-by-message-id
+                        group server message-id
+                         nnimap-request-articles-find-limit))))))))))
+
+(defun nnimap-process-quirk (greeting-match type data)
+  (when (and (nnimap-greeting nnimap-object)
+            (string-match greeting-match (nnimap-greeting nnimap-object))
+            (eq type 'append)
+            (string-match "\000" data))
+    (let ((choice (gnus-multiple-choice
+                  "Message contains NUL characters.  Delete, continue, abort? "
+                  '((?d "Delete NUL characters")
+                    (?c "Try to APPEND the message as is")
+                    (?a "Abort")))))
+      (cond
+       ((eq choice ?a)
+       (nnheader-report 'nnimap "Aborted APPEND due to NUL characters"))
+       ((eq choice ?c)
+       data)
+       (t
+       (with-temp-buffer
+         (insert data)
+         (goto-char (point-min))
+         (while (search-forward "\000" nil t)
+           (replace-match "" t t))
+         (buffer-string)))))))
+
+(defun nnimap-ok-p (value)
+  (and (consp value)
+       (consp (car value))
+       (equal (caar value) "OK")))
+
+(defun nnimap-find-uid-response (name list)
+  (let ((result (car (last (nnimap-find-response-element name list)))))
+    (and result
+        (string-to-number result))))
+
+(defun nnimap-find-response-element (name list)
+  (let (result)
+    (dolist (elem list)
+      (when (and (consp elem)
+                (equal name (car elem)))
+       (setq result elem)))
+    result))
+
+(deffoo nnimap-request-replace-article (article group buffer)
+  (setq group (nnimap-decode-gnus-group group))
+  (let (group-art)
+    (when (and (nnimap-change-group group)
+              ;; Put the article into the group.
+              (with-current-buffer buffer
+                (setq group-art
+                      (nnimap-request-accept-article group nil t))))
+      (nnimap-delete-article (list article))
+      ;; Return the new article number.
+      (cdr group-art))))
+
+(defun nnimap-add-cr ()
+  (goto-char (point-min))
+  (while (re-search-forward "\r?\n" nil t)
+    (replace-match "\r\n" t t)))
+
+(defun nnimap-get-groups ()
+  (erase-buffer)
+  (let ((sequence (nnimap-send-command "LIST \"\" \"*\""))
+       groups)
+    (nnimap-wait-for-response sequence)
+    (subst-char-in-region (point-min) (point-max)
+                         ?\\ ?% t)
+    (goto-char (point-min))
+    (nnimap-unfold-quoted-lines)
+    (goto-char (point-min))
+    (while (search-forward "* LIST " nil t)
+      (let ((flags (read (current-buffer)))
+           (_separator (read (current-buffer)))
+           (group (buffer-substring-no-properties
+                   (progn (skip-chars-forward " \"")
+                          (point))
+                   (progn (end-of-line)
+                          (skip-chars-backward " \r\"")
+                          (point)))))
+       (unless (member '%NoSelect flags)
+         (push (utf7-decode (if (stringp group)
+                                group
+                              (format "%s" group))
+                             t)
+               groups))))
+    (nreverse groups)))
+
+(defun nnimap-get-responses (sequences)
+  (let (responses)
+    (dolist (sequence sequences)
+      (goto-char (point-min))
+      (when (re-search-forward (format "^%d " sequence) nil t)
+        (push (list sequence (nnimap-parse-response))
+              responses)))
+    responses))
+
+(deffoo nnimap-request-list (&optional server)
+  (when (nnimap-change-group nil server)
+    (with-current-buffer nntp-server-buffer
+      (erase-buffer)
+      (let ((groups
+            (with-current-buffer (nnimap-buffer)
+              (nnimap-get-groups)))
+           sequences responses)
+       (when groups
+         (with-current-buffer (nnimap-buffer)
+           (setf (nnimap-group nnimap-object) nil)
+           (dolist (group groups)
+             (setf (nnimap-examined nnimap-object) group)
+             (push (list (nnimap-send-command "EXAMINE %S"
+                                              (utf7-encode group t))
+                         group)
+                   sequences))
+           (nnimap-wait-for-response (caar sequences))
+           (setq responses
+                 (nnimap-get-responses (mapcar #'car sequences))))
+         (dolist (response responses)
+           (let* ((sequence (car response))
+                  (response (cadr response))
+                  (group (cadr (assoc sequence sequences)))
+                  (egroup (encode-coding-string group 'utf-8)))
+             (when (and group
+                        (equal (caar response) "OK"))
+               (let ((uidnext (nnimap-find-parameter "UIDNEXT" response))
+                     highest exists)
+                 (dolist (elem response)
+                   (when (equal (cadr elem) "EXISTS")
+                     (setq exists (string-to-number (car elem)))))
+                 (when uidnext
+                   (setq highest (1- (string-to-number (car uidnext)))))
+                 (cond
+                  ((null highest)
+                   (insert (format "%S 0 1 y\n" egroup)))
+                  ((zerop exists)
+                   ;; Empty group.
+                   (insert (format "%S %d %d y\n" egroup
+                                   highest (1+ highest))))
+                  (t
+                   ;; Return the widest possible range.
+                   (insert (format "%S %d 1 y\n" egroup
+                                   (or highest exists)))))))))
+         t)))))
+
+(deffoo nnimap-request-newgroups (_date &optional server)
+  (when (nnimap-change-group nil server)
+    (with-current-buffer nntp-server-buffer
+      (erase-buffer)
+      (dolist (group (with-current-buffer (nnimap-buffer)
+                      (nnimap-get-groups)))
+       (unless (assoc group nnimap-current-infos)
+         ;; Insert dummy numbers here -- they don't matter.
+         (insert (format "%S 0 1 y\n" (encode-coding-string group 'utf-8)))))
+      t)))
+
+(deffoo nnimap-retrieve-group-data-early (server infos)
+  (when (and (nnimap-change-group nil server)
+            infos)
+    (with-current-buffer (nnimap-buffer)
+      (erase-buffer)
+      (setf (nnimap-group nnimap-object) nil)
+      (setf (nnimap-initial-resync nnimap-object) 0)
+      (let ((qresyncp (nnimap-capability "QRESYNC"))
+           params sequences active uidvalidity modseq group
+           unexist)
+       ;; Go through the infos and gather the data needed to know
+       ;; what and how to request the data.
+       (dolist (info infos)
+         (setq params (gnus-info-params info)
+               group (nnimap-decode-gnus-group
+                      (gnus-group-real-name (gnus-info-group info)))
+               active (cdr (assq 'active params))
+               unexist (assq 'unexist (gnus-info-marks info))
+               uidvalidity (cdr (assq 'uidvalidity params))
+               modseq (cdr (assq 'modseq params)))
+         (setf (nnimap-examined nnimap-object) group)
+         (if (and qresyncp
+                  uidvalidity
+                  active
+                  modseq
+                  unexist)
+             (push
+              (list (nnimap-send-command "EXAMINE %S (%s (%s %s))"
+                                         (utf7-encode group t)
+                                         (nnimap-quirk "QRESYNC")
+                                         uidvalidity modseq)
+                    'qresync
+                    nil group 'qresync)
+              sequences)
+           (let ((command
+                  (if uidvalidity
+                      "EXAMINE"
+                    ;; If we don't have a UIDVALIDITY, then this is
+                    ;; the first time we've seen the group, so we
+                    ;; have to do a SELECT (which is slower than an
+                    ;; examine), but will tell us whether the group
+                    ;; is read-only or not.
+                    "SELECT"))
+                 start)
+             (if (and active uidvalidity unexist)
+                 ;; Fetch the last 100 flags.
+                 (setq start (max 1 (- (cdr active) 100)))
+               (incf (nnimap-initial-resync nnimap-object))
+               (setq start 1))
+             (push (list (nnimap-send-command "%s %S" command
+                                              (utf7-encode group t))
+                         (nnimap-send-command "UID FETCH %d:* FLAGS" start)
+                         start group command)
+                   sequences))))
+       sequences))))
+
+(defun nnimap-quirk (command)
+  (let ((quirk (assoc command nnimap-quirks)))
+    ;; If this server is of a type that matches a quirk, then return
+    ;; the "quirked" command instead of the proper one.
+    (if (or (null quirk)
+           (not (string-match (nth 1 quirk) (nnimap-greeting nnimap-object))))
+       command
+      (nth 2 quirk))))
+
+(deffoo nnimap-finish-retrieve-group-infos (server infos sequences
+                                                  &optional dont-insert)
+  (when (and sequences
+            (nnimap-change-group nil server t)
+            ;; Check that the process is still alive.
+            (get-buffer-process (nnimap-buffer))
+            (memq (process-status (get-buffer-process (nnimap-buffer)))
+                  '(open run)))
+    (with-current-buffer (nnimap-buffer)
+      ;; Wait for the final data to trickle in.
+      (when (nnimap-wait-for-response (if (eq (cadar sequences) 'qresync)
+                                         (caar sequences)
+                                       (cadar sequences))
+                                     t)
+       ;; Now we should have most of the data we need, no matter
+       ;; whether we're QRESYNCING, fetching all the flags from
+       ;; scratch, or just fetching the last 100 flags per group.
+       (nnimap-update-infos (nnimap-flags-to-marks
+                             (nnimap-parse-flags
+                              (nreverse sequences)))
+                            infos)
+       (unless dont-insert
+         ;; Finally, just return something resembling an active file in
+         ;; the nntp buffer, so that the agent can save the info, too.
+         (with-current-buffer nntp-server-buffer
+           (erase-buffer)
+           (dolist (info infos)
+             (let* ((group (gnus-info-group info))
+                    (active (gnus-active group)))
+               (when active
+                 (insert (format "%S %d %d y\n"
+                                 (decode-coding-string
+                                  (gnus-group-real-name group) 'utf-8)
+                                 (cdr active)
+                                 (car active))))))))))))
+
+(defun nnimap-update-infos (flags infos)
+  (dolist (info infos)
+    (let* ((group (nnimap-decode-gnus-group
+                  (gnus-group-real-name (gnus-info-group info))))
+          (marks (cdr (assoc group flags))))
+      (when marks
+       (nnimap-update-info info marks)))))
+
+(defun nnimap-update-info (info marks)
+  (destructuring-bind (existing flags high low uidnext start-article
+                               permanent-flags uidvalidity
+                               vanished highestmodseq) marks
+    (cond
+     ;; Ignore groups with no UIDNEXT/marks.  This happens for
+     ;; completely empty groups.
+     ((and (not existing)
+          (not uidnext))
+      (let ((active (cdr (assq 'active (gnus-info-params info)))))
+       (when active
+         (gnus-set-active (gnus-info-group info) active))))
+     ;; We have a mismatch between the old and new UIDVALIDITY
+     ;; identifiers, so we have to re-request the group info (the next
+     ;; time).  This virtually never happens.
+     ((let ((old-uidvalidity
+            (cdr (assq 'uidvalidity (gnus-info-params info)))))
+       (and old-uidvalidity
+            (not (equal old-uidvalidity uidvalidity))
+             (or (not start-article)
+                 (> start-article 1))))
+      (gnus-group-remove-parameter info 'uidvalidity)
+      (gnus-group-remove-parameter info 'modseq))
+     ;; We have the data needed to update.
+     (t
+      (let* ((group (gnus-info-group info))
+            (completep (and start-article
+                            (= start-article 1)))
+            (active (or (gnus-active group)
+                        (cdr (assq 'active (gnus-info-params info))))))
+       (when uidnext
+         (setq high (1- uidnext)))
+       ;; First set the active ranges based on high/low.
+       (if (or completep
+               (not (gnus-active group)))
+           (gnus-set-active group
+                            (cond
+                             (active
+                              (cons (min (or low (car active))
+                                         (car active))
+                                    (max (or high (cdr active))
+                                         (cdr active))))
+                             ((and low high)
+                              (cons low high))
+                             (uidnext
+                              ;; No articles in this group.
+                              (cons uidnext (1- uidnext)))
+                             (start-article
+                              (cons start-article (1- start-article)))
+                             (t
+                              ;; No articles and no uidnext.
+                              nil)))
+         (gnus-set-active group
+                          (cons (car active)
+                                (or high (1- uidnext)))))
+       ;; See whether this is a read-only group.
+       (unless (eq permanent-flags 'not-scanned)
+         (gnus-group-set-parameter
+          info 'permanent-flags
+          (and (or (memq '%* permanent-flags)
+                   (memq '%Seen permanent-flags))
+               permanent-flags)))
+       ;; Update marks and read articles if this isn't a
+       ;; read-only IMAP group.
+       (when (setq permanent-flags
+                   (cdr (assq 'permanent-flags (gnus-info-params info))))
+         (if (and highestmodseq
+                  (not start-article))
+             ;; We've gotten the data by QRESYNCing.
+             (nnimap-update-qresync-info
+              info existing (nnimap-imap-ranges-to-gnus-ranges vanished) flags)
+           ;; Do normal non-QRESYNC flag updates.
+           ;; Update the list of read articles.
+           (let* ((unread
+                   (gnus-compress-sequence
+                    (gnus-set-difference
+                     (gnus-set-difference
+                      existing
+                      (gnus-sorted-union
+                       (cdr (assoc '%Seen flags))
+                       (cdr (assoc '%Deleted flags))))
+                     (cdr (assoc '%Flagged flags)))))
+                  (read (gnus-range-difference
+                         (cons start-article high) unread)))
+             (when (> start-article 1)
+               (setq read
+                     (gnus-range-nconcat
+                      (if (> start-article 1)
+                          (gnus-sorted-range-intersection
+                           (cons 1 (1- start-article))
+                           (gnus-info-read info))
+                        (gnus-info-read info))
+                      read)))
+             (when (or (not (listp permanent-flags))
+                       (memq '%Seen permanent-flags))
+               (gnus-info-set-read info read))
+             ;; Update the marks.
+             (setq marks (gnus-info-marks info))
+             (dolist (type (cdr nnimap-mark-alist))
+               (when (or (not (listp permanent-flags))
+                         (memq (car (assoc (caddr type) flags))
+                               permanent-flags)
+                         (memq '%* permanent-flags))
+                 (let ((old-marks (assoc (car type) marks))
+                       (new-marks
+                        (gnus-compress-sequence
+                         (cdr (or (assoc (caddr type) flags) ; %Flagged
+                                  (assoc (intern (cadr type) obarray) flags)
+                                  (assoc (cadr type) flags)))))) ; "\Flagged"
+                   (setq marks (delq old-marks marks))
+                   (pop old-marks)
+                   (when (and old-marks
+                              (> start-article 1))
+                     (setq old-marks (gnus-range-difference
+                                      old-marks
+                                      (cons start-article high)))
+                     (setq new-marks (gnus-range-nconcat old-marks new-marks)))
+                   (when new-marks
+                     (push (cons (car type) new-marks) marks)))))
+             ;; Keep track of non-existing articles.
+             (let* ((old-unexists (assq 'unexist marks))
+                    (active (gnus-active group))
+                    (unexists
+                     (if completep
+                         (gnus-range-difference
+                          active
+                          (gnus-compress-sequence existing))
+                       (gnus-add-to-range
+                        (cdr old-unexists)
+                        (gnus-list-range-difference
+                         existing (gnus-active group))))))
+               (when (> (car active) 1)
+                 (setq unexists (gnus-range-add
+                                 (cons 1 (1- (car active)))
+                                 unexists)))
+               (if old-unexists
+                   (setcdr old-unexists unexists)
+                 (push (cons 'unexist unexists) marks)))
+             (gnus-info-set-marks info marks t))))
+       ;; Tell Gnus whether there are any \Recent messages in any of
+       ;; the groups.
+       (let ((recent (cdr (assoc '%Recent flags))))
+         (when (and active
+                    recent
+                    (> (car (last recent)) (cdr active)))
+           (push (list (cons (gnus-group-real-name group) 0))
+                 nnmail-split-history)))
+       ;; Note the active level for the next run-through.
+       (gnus-group-set-parameter info 'active (gnus-active group))
+       (gnus-group-set-parameter info 'uidvalidity uidvalidity)
+       (gnus-group-set-parameter info 'modseq highestmodseq)
+       (nnimap-store-info info (gnus-active group)))))))
+
+(defun nnimap-update-qresync-info (info existing vanished flags)
+  ;; Add all the vanished articles to the list of read articles.
+  (gnus-info-set-read
+   info
+   (gnus-add-to-range
+    (gnus-add-to-range
+     (gnus-range-add (gnus-info-read info)
+                    vanished)
+     (cdr (assq '%Flagged flags)))
+    (cdr (assq '%Seen flags))))
+  (let ((marks (gnus-info-marks info)))
+    (dolist (type (cdr nnimap-mark-alist))
+      (let ((ticks (assoc (car type) marks))
+           (new-marks
+            (cdr (or (assoc (caddr type) flags) ; %Flagged
+                     (assoc (intern (cadr type) obarray) flags)
+                     (assoc (cadr type) flags))))) ; "\Flagged"
+       (setq marks (delq ticks marks))
+       (pop ticks)
+       ;; Add the new marks we got.
+       (setq ticks (gnus-add-to-range ticks new-marks))
+       ;; Remove the marks from messages that don't have them.
+       (setq ticks (gnus-remove-from-range
+                    ticks
+                    (gnus-compress-sequence
+                     (gnus-sorted-complement existing new-marks))))
+       (when ticks
+         (push (cons (car type) ticks) marks)))
+      (gnus-info-set-marks info marks t))
+    ;; Add vanished to the list of unexisting articles.
+    (when vanished
+      (let* ((old-unexists (assq 'unexist marks))
+            (unexists (gnus-range-add (cdr old-unexists) vanished)))
+       (if old-unexists
+           (setcdr old-unexists unexists)
+         (push (cons 'unexist unexists) marks)))
+      (gnus-info-set-marks info marks t))))
+
+(defun nnimap-imap-ranges-to-gnus-ranges (irange)
+  (if (zerop (length irange))
+      nil
+    (let ((result nil))
+      (dolist (elem (split-string irange ","))
+       (push
+        (if (string-match ":" elem)
+            (let ((numbers (split-string elem ":")))
+              (cons (string-to-number (car numbers))
+                    (string-to-number (cadr numbers))))
+          (string-to-number elem))
+        result))
+      (nreverse result))))
+
+(defun nnimap-store-info (info active)
+  (let* ((group (gnus-group-real-name (gnus-info-group info)))
+        (entry (assoc group nnimap-current-infos)))
+    (if entry
+       (setcdr entry (list info active))
+      (push (list group info active) nnimap-current-infos))))
+
+(defun nnimap-flags-to-marks (groups)
+  (let (data group uidnext articles start-article mark permanent-flags
+            uidvalidity vanished highestmodseq)
+    (dolist (elem groups)
+      (setq group (car elem)
+           uidnext (nth 1 elem)
+           start-article (nth 2 elem)
+           permanent-flags (nth 3 elem)
+           uidvalidity (nth 4 elem)
+           vanished (nth 5 elem)
+           highestmodseq (nth 6 elem)
+           articles (nthcdr 7 elem))
+      (let ((high (caar articles))
+           marks low existing)
+       (dolist (article articles)
+         (setq low (car article))
+         (push (car article) existing)
+         (dolist (flag (cdr article))
+           (setq mark (assoc flag marks))
+           (if (not mark)
+               (push (list flag (car article)) marks)
+             (setcdr mark (cons (car article) (cdr mark))))))
+       (push (list group existing marks high low uidnext start-article
+                   permanent-flags uidvalidity vanished highestmodseq)
+             data)))
+    data))
+
+(defun nnimap-parse-flags (sequences)
+  (goto-char (point-min))
+  ;; Change \Delete etc to %Delete, so that the Emacs Lisp reader can
+  ;; read it.
+  (subst-char-in-region (point-min) (point-max)
+                       ?\\ ?% t)
+  ;; Remove any MODSEQ entries in the buffer, because they may contain
+  ;; numbers that are too large for 32-bit Emacsen.
+  (while (re-search-forward " MODSEQ ([0-9]+)" nil t)
+    (replace-match "" t t))
+  (goto-char (point-min))
+  (let (start end articles groups uidnext elems permanent-flags
+             uidvalidity vanished highestmodseq)
+    (dolist (elem sequences)
+      (destructuring-bind (group-sequence flag-sequence totalp group command)
+         elem
+       (setq start (point))
+       (when (and
+              ;; The EXAMINE was successful.
+              (search-forward (format "\n%d OK " group-sequence) nil t)
+              (progn
+                (forward-line 1)
+                (setq end (point))
+                (goto-char start)
+                (setq permanent-flags
+                      (if (equal command "SELECT")
+                          (and (search-forward "PERMANENTFLAGS "
+                                               (or end (point-min)) t)
+                               (read (current-buffer)))
+                        'not-scanned))
+                (goto-char start)
+                (setq uidnext
+                      (and (search-forward "UIDNEXT "
+                                           (or end (point-min)) t)
+                           (read (current-buffer))))
+                (goto-char start)
+                (setq uidvalidity
+                      (and (re-search-forward "UIDVALIDITY \\([0-9]+\\)"
+                                              (or end (point-min)) t)
+                           ;; Store UIDVALIDITY as a string, as it's
+                           ;; too big for 32-bit Emacsen, usually.
+                           (match-string 1)))
+                (goto-char start)
+                (setq vanished
+                      (and (eq flag-sequence 'qresync)
+                           (re-search-forward "^\\* VANISHED .*? \\([0-9:,]+\\)"
+                                              (or end (point-min)) t)
+                           (match-string 1)))
+                (goto-char start)
+                (setq highestmodseq
+                      (and (re-search-forward "HIGHESTMODSEQ \\([0-9]+\\)"
+                                           (or end (point-min)) t)
+                           (match-string 1)))
+                (goto-char end)
+                (forward-line -1))
+              ;; The UID FETCH FLAGS was successful.
+              (or (eq flag-sequence 'qresync)
+                  (search-forward (format "\n%d OK " flag-sequence) nil t)))
+         (if (eq flag-sequence 'qresync)
+             (progn
+               (goto-char start)
+               (setq start end))
+           (setq start (point))
+           (goto-char end))
+         (while (re-search-forward "^\\* [0-9]+ FETCH " start t)
+           (progn
+             (setq elems (read (current-buffer)))
+             (push (cons (cadr (memq 'UID elems))
+                         (cadr (memq 'FLAGS elems)))
+                   articles)))
+         (push (nconc (list group uidnext totalp permanent-flags uidvalidity
+                            vanished highestmodseq)
+                      articles)
+               groups)
+         (if (eq flag-sequence 'qresync)
+             (goto-char end)
+           (setq end (point)))
+         (setq articles nil))))
+    groups))
+
+(defun nnimap-find-process-buffer (buffer)
+  (cadr (assoc buffer nnimap-connection-alist)))
+
+(deffoo nnimap-request-post (&optional _server)
+  (setq nnimap-status-string "Read-only server")
+  nil)
+
+(defvar gnus-refer-thread-use-nnir) ;; gnus-sum.el
+(declare-function gnus-fetch-headers "gnus-sum"
+                 (articles &optional limit force-new dependencies))
+
+(autoload 'nnir-search-thread "nnir")
+
+(deffoo nnimap-request-thread (header &optional group server)
+  (when group
+    (setq group (nnimap-decode-gnus-group group)))
+  (if gnus-refer-thread-use-nnir
+      (nnir-search-thread header)
+    (when (nnimap-change-group group server)
+      (let* ((cmd (nnimap-make-thread-query header))
+             (result (with-current-buffer (nnimap-buffer)
+                       (nnimap-command  "UID SEARCH %s" cmd))))
+        (when result
+          (gnus-fetch-headers
+           (and (car result)
+               (delete 0 (mapcar #'string-to-number
+                                 (cdr (assoc "SEARCH" (cdr result))))))
+           nil t))))))
+
+(defun nnimap-change-group (group &optional server no-reconnect read-only)
+  "Change group to GROUP if non-nil.
+If SERVER is set, check that server is connected, otherwise retry
+to reconnect, unless NO-RECONNECT is set to t.  Return nil if
+unsuccessful in connecting.
+If GROUP is nil, return t.
+If READ-ONLY is set, send EXAMINE rather than SELECT to the server.
+Return the server's response to the SELECT or EXAMINE command."
+  (let ((open-result t))
+    (when (and server
+              (not (nnimap-server-opened server)))
+      (setq open-result (nnimap-open-server server nil no-reconnect)))
+    (cond
+     ((not open-result)
+      nil)
+     ((not group)
+      t)
+     (t
+      (with-current-buffer (nnimap-buffer)
+        (let ((result (nnimap-command "%s %S"
+                                      (if read-only
+                                          "EXAMINE"
+                                        "SELECT")
+                                      (utf7-encode group t))))
+          (when (car result)
+            (setf (nnimap-group nnimap-object) group
+                  (nnimap-select-result nnimap-object) result)
+            result)))))))
+
+(defun nnimap-find-connection (buffer)
+  "Find the connection delivering to BUFFER."
+  (let ((entry (assoc buffer nnimap-connection-alist)))
+    (when entry
+      (if (and (buffer-name (cadr entry))
+              (get-buffer-process (cadr entry))
+              (memq (process-status (get-buffer-process (cadr entry)))
+                    '(open run)))
+         (get-buffer-process (cadr entry))
+       (setq nnimap-connection-alist (delq entry nnimap-connection-alist))
+       nil))))
+
+(defvar nnimap-sequence 0)
+
+(defun nnimap-send-command (&rest args)
+  (setf (nnimap-last-command-time nnimap-object) (current-time))
+  (process-send-string
+   (get-buffer-process (current-buffer))
+   (nnimap-log-command
+    (format "%d %s%s\n"
+           (incf nnimap-sequence)
+           (apply #'format args)
+           (if (nnimap-newlinep nnimap-object)
+               ""
+             "\r"))))
+  ;; Some servers apparently can't have many outstanding
+  ;; commands, so throttle them.
+  (unless nnimap-streaming
+    (nnimap-wait-for-response nnimap-sequence))
+  nnimap-sequence)
+
+(defvar nnimap-record-commands nil
+  "If non-nil, log commands to the \"*imap log*\" buffer.")
+
+(defun nnimap-log-buffer ()
+  (let ((name "*imap log*"))
+    (or (get-buffer name)
+        (with-current-buffer (get-buffer-create name)
+          (when (boundp 'window-point-insertion-type)
+            (make-local-variable 'window-point-insertion-type)
+            (setq window-point-insertion-type t))
+          (current-buffer)))))
+
+(defun nnimap-log-command (command)
+  (when nnimap-record-commands
+    (with-current-buffer (nnimap-log-buffer)
+      (goto-char (point-max))
+      (insert (format-time-string "%H:%M:%S")
+              " [" nnimap-address "] "
+              (if nnimap-inhibit-logging
+                  "(inhibited)\n"
+                command))))
+  command)
+
+(defun nnimap-command (&rest args)
+  (erase-buffer)
+  (let* ((sequence (apply #'nnimap-send-command args))
+        (response (nnimap-get-response sequence)))
+    (if (equal (caar response) "OK")
+       (cons t response)
+      (nnheader-report 'nnimap "%s"
+                      (mapconcat (lambda (a)
+                                   (format "%s" a))
+                                 (car response) " "))
+      nil)))
+
+(defun nnimap-get-response (sequence)
+  (nnimap-wait-for-response sequence)
+  (nnimap-parse-response))
+
+(defun nnimap-wait-for-connection (&optional regexp)
+  (nnimap-wait-for-line (or regexp "^[*.] .*\n") "[*.] \\([A-Z0-9]+\\)"))
+
+(defun nnimap-wait-for-line (regexp &optional response-regexp)
+  (let ((process (get-buffer-process (current-buffer))))
+    (goto-char (point-min))
+    (while (and (memq (process-status process)
+                     '(open run))
+               (not (re-search-forward regexp nil t)))
+      (nnheader-accept-process-output process)
+      (goto-char (point-min)))
+    (forward-line -1)
+    (and (looking-at (or response-regexp regexp))
+        (match-string 1))))
+
+(defun nnimap-wait-for-response (sequence &optional messagep)
+  (let ((process (get-buffer-process (current-buffer)))
+       openp)
+    (condition-case nil
+        (progn
+         (goto-char (point-max))
+         (while (and (setq openp (memq (process-status process)
+                                       '(open run)))
+                     (progn
+                       ;; Skip past any "*" lines that the server has
+                       ;; output.
+                       (while (and (not (bobp))
+                                   (progn
+                                     (forward-line -1)
+                                     (looking-at "\\*\\|[0-9]+ OK NOOP"))))
+                       (not (looking-at (format "%d .*\n" sequence)))))
+           (when messagep
+             (nnheader-message-maybe
+              7 "nnimap read %dk from %s%s" (/ (buffer-size) 1000)
+              nnimap-address
+              (if (not (zerop (nnimap-initial-resync nnimap-object)))
+                  (format " (initial sync of %d group%s; please wait)"
+                          (nnimap-initial-resync nnimap-object)
+                          (if (= (nnimap-initial-resync nnimap-object) 1)
+                              ""
+                            "s"))
+                "")))
+           (nnheader-accept-process-output process)
+           (goto-char (point-max)))
+         (setf (nnimap-initial-resync nnimap-object) 0)
+          openp)
+      (quit
+       (when debug-on-quit
+        (debug "Quit"))
+       ;; The user hit C-g while we were waiting: kill the process, in case
+       ;; it's a gnutls-cli process that's stuck (tends to happen a lot behind
+       ;; NAT routers).
+       (delete-process process)
+       nil))))
+
+(defun nnimap-parse-response ()
+  (let ((lines (split-string (nnimap-last-response-string) "\r\n" t))
+       result)
+    (dolist (line lines)
+      (push (cdr (nnimap-parse-line line)) result))
+    ;; Return the OK/error code first, and then all the "continuation
+    ;; lines" afterwards.
+    (cons (pop result)
+         (nreverse result))))
+
+;; Parse an IMAP response line lightly.  They look like
+;; "* OK [UIDVALIDITY 1164213559] UIDs valid", typically, so parse
+;; the lines into a list of strings and lists of string.
+(defun nnimap-parse-line (line)
+  (let (char result)
+    (with-temp-buffer
+      (mm-disable-multibyte)
+      (insert line)
+      (goto-char (point-min))
+      (while (not (eobp))
+       (if (eql (setq char (following-char)) ? )
+           (forward-char 1)
+         (push
+          (cond
+           ((eql char ?\[)
+            (split-string
+             (buffer-substring
+              (1+ (point))
+              (if (search-forward "]" (line-end-position) 'move)
+                  (1- (point))
+                (point)))))
+           ((eql char ?\()
+            (split-string
+             (buffer-substring
+              (1+ (point))
+              (if (search-forward ")" (line-end-position) 'move)
+                  (1- (point))
+                (point)))))
+           ((eql char ?\")
+            (forward-char 1)
+            (buffer-substring
+             (point)
+             (1- (or (search-forward "\"" (line-end-position) 'move)
+                     (point)))))
+           (t
+            (buffer-substring (point) (if (search-forward " " nil t)
+                                          (1- (point))
+                                        (goto-char (point-max))))))
+          result)))
+      (nreverse result))))
+
+(defun nnimap-last-response-string ()
+  (save-excursion
+    (forward-line 1)
+    (let ((end (point)))
+      (forward-line -1)
+      (when (not (bobp))
+       (forward-line -1)
+       (while (and (not (bobp))
+                   (eql (following-char) ?*))
+         (forward-line -1))
+       (unless (eql (following-char) ?*)
+         (forward-line 1)))
+      (buffer-substring (point) end))))
+
+(defvar nnimap-incoming-split-list nil)
+
+(defun nnimap-fetch-inbox (articles)
+  (erase-buffer)
+  (nnimap-wait-for-response
+   (nnimap-send-command
+    "UID FETCH %s %s"
+    (nnimap-article-ranges articles)
+    (format "(UID %s%s)"
+           (format
+            (if (nnimap-ver4-p)
+                "BODY.PEEK"
+              "RFC822.PEEK"))
+           (cond
+            (nnimap-split-download-body-default
+             "[]")
+            ((nnimap-ver4-p)
+             "[HEADER]")
+            (t
+             "[1]"))))
+   t))
+
+(defun nnimap-split-incoming-mail ()
+  (with-current-buffer (nnimap-buffer)
+    (let ((nnimap-incoming-split-list nil)
+         (nnmail-split-methods
+          (cond
+           ((eq nnimap-split-methods 'default)
+            nnmail-split-methods)
+           (nnimap-split-methods
+            nnimap-split-methods)
+           (nnimap-split-fancy
+            'nnmail-split-fancy)))
+         (nnmail-split-fancy (or nnimap-split-fancy
+                                 nnmail-split-fancy))
+         (nnmail-inhibit-default-split-group t)
+         (groups (nnimap-get-groups))
+          (can-move (nnimap-capability "MOVE"))
+         new-articles)
+      (erase-buffer)
+      (nnimap-command "SELECT %S" nnimap-inbox)
+      (setf (nnimap-group nnimap-object) nnimap-inbox)
+      (setq new-articles (nnimap-new-articles (nnimap-get-flags "1:*")))
+      (when new-articles
+       (nnimap-fetch-inbox new-articles)
+       (nnimap-transform-split-mail)
+       (nnheader-ms-strip-cr)
+       (nnmail-cache-open)
+       (nnmail-split-incoming (current-buffer)
+                              #'nnimap-save-mail-spec
+                              nil nil
+                              #'nnimap-dummy-active-number
+                              #'nnimap-save-mail-spec)
+       (when nnimap-incoming-split-list
+         (let ((specs (nnimap-make-split-specs nnimap-incoming-split-list))
+               sequences junk-articles)
+           ;; Create any groups that doesn't already exist on the
+           ;; server first.
+           (dolist (spec specs)
+             (when (and (not (member (car spec) groups))
+                        (not (eq (car spec) 'junk)))
+               (nnimap-command "CREATE %S" (utf7-encode (car spec) t))))
+           ;; Then copy over all the messages.
+           (erase-buffer)
+           (dolist (spec specs)
+             (let ((group (car spec))
+                   (ranges (cdr spec)))
+               (if (eq group 'junk)
+                   (setq junk-articles ranges)
+                 ;; Don't copy if the message is already in its
+                 ;; target group.
+                 (unless (string= group nnimap-inbox)
+                   (push (list (nnimap-send-command
+                                (if can-move
+                                    "UID MOVE %s %S"
+                                  "UID COPY %s %S")
+                                (nnimap-article-ranges ranges)
+                                (utf7-encode group t))
+                               ranges)
+                         sequences)))))
+           ;; Wait for the last COPY response...
+           (when (and (not can-move) sequences)
+             (nnimap-wait-for-response (caar sequences))
+             ;; And then mark the successful copy actions as deleted,
+             ;; and possibly expunge them.
+             (nnimap-mark-and-expunge-incoming
+              (nnimap-parse-copied-articles sequences)))
+            (nnimap-mark-and-expunge-incoming junk-articles)))))))
+
+(defun nnimap-mark-and-expunge-incoming (range)
+  (when range
+    (setq range (nnimap-article-ranges range))
+    (erase-buffer)
+    (let ((sequence
+          (nnimap-send-command
+           "UID STORE %s +FLAGS.SILENT (\\Deleted)" range)))
+      (cond
+       ;; If the server supports it, we now delete the message we have
+       ;; just copied over.
+       ((nnimap-capability "UIDPLUS")
+       (setq sequence (nnimap-send-command "UID EXPUNGE %s" range)))
+       ;; If it doesn't support UID EXPUNGE, then we only expunge if the
+       ;; user has configured it.
+       (nnimap-expunge
+       (setq sequence (nnimap-send-command "EXPUNGE"))))
+      (nnimap-wait-for-response sequence))))
+
+(defun nnimap-parse-copied-articles (sequences)
+  (let (sequence copied range)
+    (goto-char (point-min))
+    (while (re-search-forward "^\\([0-9]+\\) OK\\b" nil t)
+      (setq sequence (string-to-number (match-string 1)))
+      (when (setq range (cadr (assq sequence sequences)))
+       (push (gnus-uncompress-range range) copied)))
+    (gnus-compress-sequence (sort (apply #'nconc copied) #'<))))
+
+(defun nnimap-new-articles (flags)
+  (let (new)
+    (dolist (elem flags)
+      (unless (gnus-list-memq-of-list nnimap-unsplittable-articles
+                                     (cdr elem))
+       (push (car elem) new)))
+    (gnus-compress-sequence (nreverse new))))
+
+(defun nnimap-make-split-specs (list)
+  (let ((specs nil)
+       entry)
+    (dolist (elem list)
+      (destructuring-bind (article spec) elem
+       (dolist (group (delete nil (mapcar #'car spec)))
+         (unless (setq entry (assoc group specs))
+           (push (setq entry (list group)) specs))
+         (setcdr entry (cons article (cdr entry))))))
+    (dolist (entry specs)
+      (setcdr entry (gnus-compress-sequence (sort (cdr entry) #'<))))
+    specs))
+
+(defun nnimap-transform-split-mail ()
+  (goto-char (point-min))
+  (let (article bytes)
+    (block nil
+      (while (not (eobp))
+       (while (not (looking-at "\\* [0-9]+ FETCH.+UID \\([0-9]+\\)"))
+         (delete-region (point) (progn (forward-line 1) (point)))
+         (when (eobp)
+           (return)))
+       (setq article (match-string 1)
+             bytes (nnimap-get-length))
+       (delete-region (line-beginning-position) (line-end-position))
+       ;; Insert MMDF separator, and a way to remember what this
+       ;; article UID is.
+       (insert (format "\^A\^A\^A\^A\n\nX-nnimap-article: %s" article))
+       (forward-char (1+ bytes))
+       (setq bytes (nnimap-get-length))
+       (delete-region (line-beginning-position) (line-end-position))
+       ;; There's a body; skip past that.
+       (when bytes
+         (forward-char (1+ bytes))
+         (delete-region (line-beginning-position) (line-end-position)))))))
+
+(defun nnimap-dummy-active-number (_group &optional _server)
+  1)
+
+(defun nnimap-save-mail-spec (group-art &optional _server _full-nov)
+  (let (article)
+    (goto-char (point-min))
+    (if (not (re-search-forward "X-nnimap-article: \\([0-9]+\\)" nil t))
+       (error "Invalid nnimap mail")
+      (setq article (string-to-number (match-string 1))))
+    (push (list article
+               (if (eq group-art 'junk)
+                   (list (cons 'junk 1))
+                 group-art))
+         nnimap-incoming-split-list)))
+
+(defun nnimap-make-thread-query (header)
+  (let* ((id  (mail-header-id header))
+        (refs (split-string
+               (or (mail-header-references header)
+                   "")))
+        (value
+         (format
+          "(OR HEADER REFERENCES %S HEADER Message-Id %S)"
+          id id)))
+    (dolist (refid refs value)
+      (setq value (format
+                  "(OR (OR HEADER Message-Id %S HEADER REFERENCES %S) %s)"
+                  refid refid value)))))
+
+
+(provide 'nnimap)
+
+;;; nnimap.el ends here
diff --git a/xemacs-packages/gnus/lisp/nnir.el b/xemacs-packages/gnus/lisp/nnir.el
new file mode 100644 (file)
index 0000000..183e144
--- /dev/null
@@ -0,0 +1,1920 @@
+;;; nnir.el --- search mail with various search engines -*- coding: utf-8 -*-
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Kai Großjohann <grossjohann@ls6.cs.uni-dortmund.de>
+;; Swish-e and Swish++ backends by:
+;;   Christoph Conrad <christoph.conrad@gmx.de>.
+;; IMAP backend by: Simon Josefsson <jas@pdc.kth.se>.
+;; IMAP search by: Torsten Hilbrich <torsten.hilbrich <at> gmx.net>
+;; IMAP search improved by Daniel Pittman  <daniel@rimspace.net>.
+;; nnmaildir support for Swish++ and Namazu backends by:
+;;   Justus Piater <Justus <at> Piater.name>
+;; Keywords: news mail searching ir
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; What does it do?  Well, it allows you to search your mail using
+;; some search engine (imap, namazu, swish-e, gmane and others -- see
+;; later) by typing `G G' in the Group buffer.  You will then get a
+;; buffer which shows all articles matching the query, sorted by
+;; Retrieval Status Value (score).
+
+;; When looking at the retrieval result (in the Summary buffer) you
+;; can type `A W' (aka M-x gnus-warp-to-article RET) on an article.  You
+;; will be warped into the group this article came from. Typing `A T'
+;; (aka M-x gnus-summary-refer-thread RET) will warp to the group and
+;; also show the thread this article is part of.
+
+;; The Lisp setup may involve setting a few variables and setting up the
+;; search engine. You can define the variables in the server definition
+;; like this :
+;;   (setq gnus-secondary-select-methods '(
+;;       (nnimap "" (nnimap-address "localhost")
+;;                  (nnir-search-engine namazu)
+;;       )))
+;; The main variable to set is `nnir-search-engine'.  Choose one of
+;; the engines listed in `nnir-engines'.  (Actually `nnir-engines' is
+;; an alist, type `C-h v nnir-engines RET' for more information; this
+;; includes examples for setting `nnir-search-engine', too.)
+
+;; If you use one of the local indices (namazu, find-grep, swish) you
+;; must also set up a search engine backend.
+
+;; 1. Namazu
+;;
+;; The Namazu backend requires you to have one directory containing all
+;; index files, this is controlled by the `nnir-namazu-index-directory'
+;; variable.  To function the `nnir-namazu-remove-prefix' variable must
+;; also be correct, see the documentation for `nnir-namazu-remove-prefix'
+;; above.
+;;
+;; It is particularly important not to pass any any switches to namazu
+;; that will change the output format.  Good switches to use include
+;; `--sort', `--ascending', `--early' and `--late'.  Refer to the Namazu
+;; documentation for further information on valid switches.
+;;
+;; To index my mail with the `mknmz' program I use the following
+;; configuration file:
+;;
+;; ,----
+;; | package conf;  # Don't remove this line!
+;; |
+;; | # Paths which will not be indexed. Don't use `^' or `$' anchors.
+;; | $EXCLUDE_PATH = "spam|sent";
+;; |
+;; | # Header fields which should be searchable. case-insensitive
+;; | $REMAIN_HEADER = "from|date|message-id|subject";
+;; |
+;; | # Searchable fields. case-insensitive
+;; | $SEARCH_FIELD = "from|date|message-id|subject";
+;; |
+;; | # The max length of a word.
+;; | $WORD_LENG_MAX = 128;
+;; |
+;; | # The max length of a field.
+;; | $MAX_FIELD_LENGTH = 256;
+;; `----
+;;
+;; My mail is stored in the directories ~/Mail/mail/, ~/Mail/lists/ and
+;; ~/Mail/archive/, so to index them I go to the directory set in
+;; `nnir-namazu-index-directory' and issue the following command.
+;;
+;;      mknmz --mailnews ~/Mail/archive/ ~/Mail/mail/ ~/Mail/lists/
+;;
+;; For maximum searching efficiency I have a cron job set to run this
+;; command every four hours.
+
+;; 2. find-grep
+;;
+;; The find-grep engine simply runs find(1) to locate eligible
+;; articles and searches them with grep(1).  This, of course, is much
+;; slower than using a proper search engine but OTOH doesn't require
+;; maintenance of an index and is still faster than using any built-in
+;; means for searching.  The method specification of the server to
+;; search must include a directory for this engine to work (E.g.,
+;; `nnml-directory').  The tools must be POSIX compliant.  GNU Find
+;; prior to version 4.2.12 (4.2.26 on Linux due to incorrect ARG_MAX
+;; handling) does not work.
+;; ,----
+;; |    ;; find-grep configuration for searching the Gnus Cache
+;; |
+;; |   (nnml "cache"
+;; |          (nnml-get-new-mail nil)
+;; |          (nnir-search-engine find-grep)
+;; |          (nnml-directory "~/News/cache/")
+;; |          (nnml-active-file "~/News/cache/active"))
+;; `----
+
+;; Developer information:
+
+;; I have tried to make the code expandable.  Basically, it is divided
+;; into two layers.  The upper layer is somewhat like the `nnvirtual'
+;; backend: given a specification of what articles to show from
+;; another backend, it creates a group containing exactly those
+;; articles.  The lower layer issues a query to a search engine and
+;; produces such a specification of what articles to show from the
+;; other backend.
+
+;; The interface between the two layers consists of the single
+;; function `nnir-run-query', which dispatches the search to the
+;; proper search function.  The argument of `nnir-run-query' is an
+;; alist with two keys: 'nnir-query-spec and 'nnir-group-spec. The
+;; value for 'nnir-query-spec is an alist. The only required key/value
+;; pair is (query . "query") specifying the search string to pass to
+;; the query engine. Individual engines may have other elements. The
+;; value of 'nnir-group-spec is a list with the specification of the
+;; groups/servers to search.  The format of the 'nnir-group-spec is
+;; (("server1" ("group11" "group12")) ("server2" ("group21"
+;; "group22"))). If any of the group lists is absent then all groups
+;; on that server are searched.
+
+;; The output of `nnir-run-query' is supposed to be a vector, each
+;; element of which should in turn be a three-element vector.  The
+;; first element should be full group name of the article, the second
+;; element should be the article number, and the third element should
+;; be the Retrieval Status Value (RSV) as returned from the search
+;; engine.  An RSV is the score assigned to the document by the search
+;; engine.  For Boolean search engines, the RSV is always 1000 (or 1
+;; or 100, or whatever you like).
+
+;; The sorting order of the articles in the summary buffer created by
+;; nnir is based on the order of the articles in the above mentioned
+;; vector, so that's where you can do the sorting you'd like.  Maybe
+;; it would be nice to have a way of displaying the search result
+;; sorted differently?
+
+;; So what do you need to do when you want to add another search
+;; engine?  You write a function that executes the query.  Temporary
+;; data from the search engine can be put in `nnir-tmp-buffer'.  This
+;; function should return the list of articles as a vector, as
+;; described above.  Then, you need to register this backend in
+;; `nnir-engines'.  Then, users can choose the backend by setting
+;; `nnir-search-engine' as a server variable.
+
+;;; Code:
+
+;;; Setup:
+
+(require 'nnoo)
+(require 'gnus-group)
+(require 'message)
+(require 'gnus-util)
+(eval-when-compile
+  (require 'cl))
+
+;;; Internal Variables:
+
+(defvar nnir-memo-query nil
+  "Internal: stores current query.")
+
+(defvar nnir-memo-server nil
+  "Internal: stores current server.")
+
+(defvar nnir-artlist nil
+  "Internal: stores search result.")
+
+(defvar nnir-search-history ()
+  "Internal: the history for querying search options in nnir")
+
+(defconst nnir-tmp-buffer " *nnir*"
+  "Internal: temporary buffer.")
+
+
+;; Imap variables
+
+(defvar nnir-imap-search-arguments
+  '(("whole message" . "TEXT")
+    ("subject" . "SUBJECT")
+    ("to" . "TO")
+    ("from" . "FROM")
+    ("body" . "BODY")
+    ("imap" . ""))
+  "Mapping from user readable keys to IMAP search items for use in nnir")
+
+(defvar nnir-imap-search-other "HEADER %S"
+  "The IMAP search item to use for anything other than
+  `nnir-imap-search-arguments'. By default this is the name of an
+  email header field")
+
+(defvar nnir-imap-search-argument-history ()
+  "The history for querying search options in nnir")
+
+;;; Helper macros
+
+;; Data type article list.
+
+(defmacro nnir-artlist-length (artlist)
+  "Returns number of articles in artlist."
+  `(length ,artlist))
+
+(defmacro nnir-artlist-article (artlist n)
+  "Returns from ARTLIST the Nth artitem (counting starting at 1)."
+  `(when (> ,n 0)
+     (elt ,artlist (1- ,n))))
+
+(defmacro nnir-artitem-group (artitem)
+  "Returns the group from the ARTITEM."
+  `(elt ,artitem 0))
+
+(defmacro nnir-artitem-number (artitem)
+  "Returns the number from the ARTITEM."
+  `(elt ,artitem 1))
+
+(defmacro nnir-artitem-rsv (artitem)
+  "Returns the Retrieval Status Value (RSV, score) from the ARTITEM."
+  `(elt ,artitem 2))
+
+(defmacro nnir-article-group (article)
+  "Returns the group for ARTICLE"
+  `(nnir-artitem-group (nnir-artlist-article nnir-artlist ,article)))
+
+(defmacro nnir-article-number (article)
+  "Returns the number for ARTICLE"
+  `(nnir-artitem-number (nnir-artlist-article nnir-artlist ,article)))
+
+(defmacro nnir-article-rsv (article)
+  "Returns the rsv for ARTICLE"
+  `(nnir-artitem-rsv (nnir-artlist-article nnir-artlist ,article)))
+
+(defsubst nnir-article-ids (article)
+  "Returns the pair `(nnir id . real id)' of ARTICLE"
+  (cons article (nnir-article-number article)))
+
+(defmacro nnir-categorize (sequence keyfunc &optional valuefunc)
+  "Sorts a sequence into categories and returns a list of the form
+`((key1 (element11 element12)) (key2 (element21 element22))'.
+The category key for a member of the sequence is obtained
+as `(keyfunc member)' and the corresponding element is just
+`member'. If `valuefunc' is non-nil, the element of the list
+is `(valuefunc member)'."
+  `(unless (null ,sequence)
+     (let (value)
+       (mapc
+       (lambda (member)
+         (let ((y (,keyfunc member))
+               (x ,(if valuefunc
+                       `(,valuefunc member)
+                     'member)))
+           (if (assoc y value)
+               (push x (cadr (assoc y value)))
+             (push (list y (list x)) value))))
+       ,sequence)
+       value)))
+
+;;; Finish setup:
+
+(require 'gnus-sum)
+
+(nnoo-declare nnir)
+(nnoo-define-basics nnir)
+
+(gnus-declare-backend "nnir" 'mail 'virtual)
+
+
+;;; User Customizable Variables:
+
+(defgroup nnir nil
+  "Search groups in Gnus with assorted search engines."
+  :group 'gnus)
+
+(defcustom nnir-ignored-newsgroups ""
+  "*A regexp to match newsgroups in the active file that should
+  be skipped when searching."
+  :version "24.1"
+  :type '(regexp)
+  :group 'nnir)
+
+(defcustom nnir-summary-line-format nil
+  "*The format specification of the lines in an nnir summary buffer.
+
+All the items from `gnus-summary-line-format' are available, along
+with three items unique to nnir summary buffers:
+
+%Z    Search retrieval score value (integer)
+%G    Article original full group name (string)
+%g    Article original short group name (string)
+
+If nil this will use `gnus-summary-line-format'."
+  :version "24.1"
+  :type '(choice (const :tag "gnus-summary-line-format" nil) string)
+  :group 'nnir)
+
+(defcustom nnir-retrieve-headers-override-function nil
+  "*If non-nil, a function that accepts an article list and group
+and populates the `nntp-server-buffer' with the retrieved
+headers. Must return either 'nov or 'headers indicating the
+retrieved header format.
+
+If this variable is nil, or if the provided function returns nil for a search
+result, `gnus-retrieve-headers' will be called instead."
+  :version "24.1"
+  :type '(choice (const :tag "gnus-retrieve-headers" nil) function)
+  :group 'nnir)
+
+(defcustom nnir-imap-default-search-key "whole message"
+  "*The default IMAP search key for an nnir search. Must be one of
+  the keys in `nnir-imap-search-arguments'. To use raw imap queries
+  by default set this to \"imap\"."
+  :version "24.1"
+  :type `(choice ,@(mapcar (lambda (elem) (list 'const (car elem)))
+                          nnir-imap-search-arguments))
+  :group 'nnir)
+
+(defcustom nnir-swish++-configuration-file
+  (expand-file-name "~/Mail/swish++.conf")
+  "*Configuration file for swish++."
+  :type '(file)
+  :group 'nnir)
+
+(defcustom nnir-swish++-program "search"
+  "*Name of swish++ search executable."
+  :type '(string)
+  :group 'nnir)
+
+(defcustom nnir-swish++-additional-switches '()
+  "*A list of strings, to be given as additional arguments to swish++.
+
+Note that this should be a list.  I.e., do NOT use the following:
+    (setq nnir-swish++-additional-switches \"-i -w\") ; wrong
+Instead, use this:
+    (setq nnir-swish++-additional-switches \\='(\"-i\" \"-w\"))"
+  :type '(repeat (string))
+  :group 'nnir)
+
+(defcustom nnir-swish++-remove-prefix (concat (getenv "HOME") "/Mail/")
+  "*The prefix to remove from each file name returned by swish++
+in order to get a group name (albeit with / instead of .).  This is a
+regular expression.
+
+This variable is very similar to `nnir-namazu-remove-prefix', except
+that it is for swish++, not Namazu."
+  :type '(regexp)
+  :group 'nnir)
+
+;; Swish-E.
+;; URL: http://swish-e.org/
+;; Variables `nnir-swish-e-index-file', `nnir-swish-e-program' and
+;; `nnir-swish-e-additional-switches'
+
+(make-obsolete-variable 'nnir-swish-e-index-file
+                       'nnir-swish-e-index-files "Emacs 23.1")
+(defcustom nnir-swish-e-index-file
+  (expand-file-name "~/Mail/index.swish-e")
+  "*Index file for swish-e.
+This could be a server parameter.
+It is never consulted once `nnir-swish-e-index-files', which should be
+used instead, has been customized."
+  :type '(file)
+  :group 'nnir)
+
+(defcustom nnir-swish-e-index-files
+  (list nnir-swish-e-index-file)
+  "*List of index files for swish-e.
+This could be a server parameter."
+  :type '(repeat (file))
+  :group 'nnir)
+
+(defcustom nnir-swish-e-program "swish-e"
+  "*Name of swish-e search executable.
+This cannot be a server parameter."
+  :type '(string)
+  :group 'nnir)
+
+(defcustom nnir-swish-e-additional-switches '()
+  "*A list of strings, to be given as additional arguments to swish-e.
+
+Note that this should be a list.  I.e., do NOT use the following:
+    (setq nnir-swish-e-additional-switches \"-i -w\") ; wrong
+Instead, use this:
+    (setq nnir-swish-e-additional-switches \\='(\"-i\" \"-w\"))
+
+This could be a server parameter."
+  :type '(repeat (string))
+  :group 'nnir)
+
+(defcustom nnir-swish-e-remove-prefix (concat (getenv "HOME") "/Mail/")
+  "*The prefix to remove from each file name returned by swish-e
+in order to get a group name (albeit with / instead of .).  This is a
+regular expression.
+
+This variable is very similar to `nnir-namazu-remove-prefix', except
+that it is for swish-e, not Namazu.
+
+This could be a server parameter."
+  :type '(regexp)
+  :group 'nnir)
+
+;; HyREX engine, see <URL:http://ls6-www.cs.uni-dortmund.de/>
+
+(defcustom nnir-hyrex-program "nnir-search"
+  "*Name of the nnir-search executable."
+  :type '(string)
+  :group 'nnir)
+
+(defcustom nnir-hyrex-additional-switches '()
+  "*A list of strings, to be given as additional arguments for nnir-search.
+Note that this should be a list. I.e., do NOT use the following:
+    (setq nnir-hyrex-additional-switches \"-ddl ddl.xml -c nnir\") ; wrong !
+Instead, use this:
+    (setq nnir-hyrex-additional-switches \\='(\"-ddl\" \"ddl.xml\" \"-c\" \"nnir\"))"
+  :type '(repeat (string))
+  :group 'nnir)
+
+(defcustom nnir-hyrex-index-directory (getenv "HOME")
+  "*Index directory for HyREX."
+  :type '(directory)
+  :group 'nnir)
+
+(defcustom nnir-hyrex-remove-prefix (concat (getenv "HOME") "/Mail/")
+  "*The prefix to remove from each file name returned by HyREX
+in order to get a group name (albeit with / instead of .).
+
+For example, suppose that HyREX returns file names such as
+\"/home/john/Mail/mail/misc/42\".  For this example, use the following
+setting:  (setq nnir-hyrex-remove-prefix \"/home/john/Mail/\")
+Note the trailing slash.  Removing this prefix gives \"mail/misc/42\".
+`nnir' knows to remove the \"/42\" and to replace \"/\" with \".\" to
+arrive at the correct group name, \"mail.misc\"."
+  :type '(directory)
+  :group 'nnir)
+
+;; Namazu engine, see <URL:http://www.namazu.org/>
+
+(defcustom nnir-namazu-program "namazu"
+  "*Name of Namazu search executable."
+  :type '(string)
+  :group 'nnir)
+
+(defcustom nnir-namazu-index-directory (expand-file-name "~/Mail/namazu/")
+  "*Index directory for Namazu."
+  :type '(directory)
+  :group 'nnir)
+
+(defcustom nnir-namazu-additional-switches '()
+  "*A list of strings, to be given as additional arguments to namazu.
+The switches `-q', `-a', and `-s' are always used, very few other switches
+make any sense in this context.
+
+Note that this should be a list.  I.e., do NOT use the following:
+    (setq nnir-namazu-additional-switches \"-i -w\") ; wrong
+Instead, use this:
+    (setq nnir-namazu-additional-switches \\='(\"-i\" \"-w\"))"
+  :type '(repeat (string))
+  :group 'nnir)
+
+(defcustom nnir-namazu-remove-prefix (concat (getenv "HOME") "/Mail/")
+  "*The prefix to remove from each file name returned by Namazu
+in order to get a group name (albeit with / instead of .).
+
+For example, suppose that Namazu returns file names such as
+\"/home/john/Mail/mail/misc/42\".  For this example, use the following
+setting:  (setq nnir-namazu-remove-prefix \"/home/john/Mail/\")
+Note the trailing slash.  Removing this prefix gives \"mail/misc/42\".
+`nnir' knows to remove the \"/42\" and to replace \"/\" with \".\" to
+arrive at the correct group name, \"mail.misc\"."
+  :type '(directory)
+  :group 'nnir)
+
+(defcustom nnir-notmuch-program "notmuch"
+  "*Name of notmuch search executable."
+  :version "24.1"
+  :type '(string)
+  :group 'nnir)
+
+(defcustom nnir-notmuch-additional-switches '()
+  "*A list of strings, to be given as additional arguments to notmuch.
+
+Note that this should be a list.  I.e., do NOT use the following:
+    (setq nnir-notmuch-additional-switches \"-i -w\") ; wrong
+Instead, use this:
+    (setq nnir-notmuch-additional-switches \\='(\"-i\" \"-w\"))"
+  :version "24.1"
+  :type '(repeat (string))
+  :group 'nnir)
+
+(defcustom nnir-notmuch-remove-prefix (concat (getenv "HOME") "/Mail/")
+  "*The prefix to remove from each file name returned by notmuch
+in order to get a group name (albeit with / instead of .).  This is a
+regular expression.
+
+This variable is very similar to `nnir-namazu-remove-prefix', except
+that it is for notmuch, not Namazu."
+  :version "24.1"
+  :type '(regexp)
+  :group 'nnir)
+
+;;; Developer Extension Variable:
+
+(defvar nnir-engines
+  `((imap    nnir-run-imap
+             ((criteria
+              "Imap Search in"                   ; Prompt
+              ,(mapcar 'car nnir-imap-search-arguments) ; alist for completing
+              nil                                ; allow any user input
+              nil                                ; initial value
+              nnir-imap-search-argument-history  ; the history to use
+              ,nnir-imap-default-search-key      ; default
+              )))
+    (gmane   nnir-run-gmane
+            ((gmane-author . "Gmane Author: ")))
+    (swish++ nnir-run-swish++
+             ((swish++-group . "Swish++ Group spec (regexp): ")))
+    (swish-e nnir-run-swish-e
+             ((swish-e-group . "Swish-e Group spec (regexp): ")))
+    (namazu  nnir-run-namazu
+             ())
+    (notmuch nnir-run-notmuch
+             ())
+    (hyrex   nnir-run-hyrex
+            ((hyrex-group . "Hyrex Group spec (regexp): ")))
+    (find-grep nnir-run-find-grep
+              ((grep-options . "Grep options: "))))
+  "Alist of supported search engines.
+Each element in the alist is a three-element list (ENGINE FUNCTION ARGS).
+ENGINE is a symbol designating the searching engine.  FUNCTION is also
+a symbol, giving the function that does the search.  The third element
+ARGS is a list of cons pairs (PARAM . PROMPT).  When issuing a query,
+the FUNCTION will issue a query for each of the PARAMs, using PROMPT.
+
+The value of `nnir-search-engine' must be one of the ENGINE symbols.
+For example, for searching a server using namazu include
+    (nnir-search-engine namazu)
+in the server definition.  Note that you have to set additional
+variables for most backends.  For example, the `namazu' backend
+needs the variables `nnir-namazu-program',
+`nnir-namazu-index-directory' and `nnir-namazu-remove-prefix'.
+
+Add an entry here when adding a new search engine.")
+
+(defcustom nnir-method-default-engines  '((nnimap . imap) (nntp . gmane))
+  "*Alist of default search engines keyed by server method."
+  :version "24.1"
+  :group 'nnir
+  :type `(repeat (cons (choice (const nnimap) (const nntp) (const nnspool)
+                              (const nneething) (const nndir) (const nnmbox)
+                              (const nnml) (const nnmh) (const nndraft)
+                              (const nnfolder) (const nnmaildir))
+                      (choice
+                       ,@(mapcar (lambda (elem) (list 'const (car elem)))
+                                 nnir-engines)))))
+
+;; Gnus glue.
+
+(declare-function gnus-group-topic-name "gnus-topic" ())
+
+(defun gnus-group-make-nnir-group (nnir-extra-parms &optional specs)
+  "Create an nnir group.  Prompt for a search query and determine
+the groups to search as follows: if called from the *Server*
+buffer search all groups belonging to the server on the current
+line; if called from the *Group* buffer search any marked groups,
+or the group on the current line, or all the groups under the
+current topic. Calling with a prefix-arg prompts for additional
+search-engine specific constraints. A non-nil `specs' arg must be
+an alist with `nnir-query-spec' and `nnir-group-spec' keys, and
+skips all prompting."
+  (interactive "P")
+  (let* ((group-spec
+         (or (cdr (assq 'nnir-group-spec specs))
+           (if (gnus-server-server-name)
+               (list (list (gnus-server-server-name)))
+             (nnir-categorize
+              (or gnus-group-marked
+                  (if (gnus-group-group-name)
+                      (list (gnus-group-group-name))
+                    (cdr (assoc (gnus-group-topic-name) gnus-topic-alist))))
+              gnus-group-server))))
+        (query-spec
+         (or (cdr (assq 'nnir-query-spec specs))
+           (apply
+            'append
+            (list (cons 'query
+                        (read-string "Query: " nil 'nnir-search-history)))
+            (when nnir-extra-parms
+              (mapcar
+               (lambda (x)
+                 (nnir-read-parms (nnir-server-to-search-engine (car x))))
+               group-spec))))))
+    (gnus-group-read-ephemeral-group
+     (concat "nnir-" (message-unique-id))
+     (list 'nnir "nnir")
+     nil
+;     (cons (current-buffer) gnus-current-window-configuration)
+     nil
+     nil nil
+     (list
+      (cons 'nnir-specs (list (cons 'nnir-query-spec query-spec)
+                             (cons 'nnir-group-spec group-spec)))
+      (cons 'nnir-artlist nil)))))
+
+(defun gnus-summary-make-nnir-group (nnir-extra-parms)
+  "Search a group from the summary buffer."
+  (interactive "P")
+  (gnus-warp-to-article)
+  (let ((spec
+        (list
+         (cons 'nnir-group-spec
+               (list (list
+                      (gnus-group-server gnus-newsgroup-name)
+                      (list gnus-newsgroup-name)))))))
+    (gnus-group-make-nnir-group nnir-extra-parms spec)))
+
+
+;; Gnus backend interface functions.
+
+(deffoo nnir-open-server (server &optional definitions)
+  ;; Just set the server variables appropriately.
+  (let ((backend (car (gnus-server-to-method server))))
+    (if backend
+       (nnoo-change-server backend server definitions)
+      (add-hook 'gnus-summary-mode-hook 'nnir-mode)
+      (nnoo-change-server 'nnir server definitions))))
+
+(deffoo nnir-request-group (group &optional server dont-check info)
+  (nnir-possibly-change-group group server)
+  (let ((pgroup (gnus-group-guess-full-name-from-command-method group))
+       length)
+    ;; Check for cached search result or run the query and cache the
+    ;; result.
+    (unless (and nnir-artlist dont-check)
+      (gnus-group-set-parameter
+       pgroup 'nnir-artlist
+       (setq nnir-artlist
+            (nnir-run-query
+             (gnus-group-get-parameter pgroup 'nnir-specs t))))
+      (nnir-request-update-info pgroup (gnus-get-info pgroup)))
+    (with-current-buffer nntp-server-buffer
+      (if (zerop (setq length (nnir-artlist-length nnir-artlist)))
+          (progn
+            (nnir-close-group group)
+            (nnheader-report 'nnir "Search produced empty results."))
+        (nnheader-insert "211 %d %d %d %s\n"
+                         length    ; total #
+                         1         ; first #
+                         length    ; last #
+                         group)))) ; group name
+  nnir-artlist)
+
+(deffoo nnir-retrieve-headers (articles &optional group server fetch-old)
+  (with-current-buffer nntp-server-buffer
+    (let ((gnus-inhibit-demon t)
+         (articles-by-group (nnir-categorize
+                             articles nnir-article-group nnir-article-ids))
+         headers)
+      (while (not (null articles-by-group))
+       (let* ((group-articles (pop articles-by-group))
+              (artgroup (car group-articles))
+              (articleids (cadr group-articles))
+              (artlist (sort (mapcar 'cdr articleids) '<))
+              (server (gnus-group-server artgroup))
+              (gnus-override-method (gnus-server-to-method server))
+              parsefunc)
+         ;; (nnir-possibly-change-group nil server)
+         (erase-buffer)
+         (case (setq gnus-headers-retrieved-by
+                     (or
+                      (and
+                       nnir-retrieve-headers-override-function
+                       (funcall nnir-retrieve-headers-override-function
+                                artlist artgroup))
+                      (gnus-retrieve-headers artlist artgroup nil)))
+           (nov
+            (setq parsefunc 'nnheader-parse-nov))
+           (headers
+            (setq parsefunc 'nnheader-parse-head))
+           (t (error "Unknown header type %s while requesting articles \
+                    of group %s" gnus-headers-retrieved-by artgroup)))
+         (goto-char (point-min))
+         (while (not (eobp))
+           (let* ((novitem (funcall parsefunc))
+                  (artno (and novitem
+                              (mail-header-number novitem)))
+                  (art (car (rassq artno articleids))))
+             (when art
+               (mail-header-set-number novitem art)
+               (push novitem headers))
+             (forward-line 1)))))
+      (setq headers
+           (sort headers
+                 (lambda (x y)
+                   (< (mail-header-number x) (mail-header-number y)))))
+      (erase-buffer)
+      (mapc 'nnheader-insert-nov headers)
+      'nov)))
+
+(deffoo nnir-request-article (article &optional group server to-buffer)
+  (nnir-possibly-change-group group server)
+  (if (and (stringp article)
+          (not (eq 'nnimap (car (gnus-server-to-method server)))))
+      (nnheader-report
+       'nnir
+       "nnir-request-article only groks message ids for nnimap servers: %s"
+       server)
+    (save-excursion
+      (let ((article article)
+            query)
+        (when (stringp article)
+          (setq gnus-override-method (gnus-server-to-method server))
+          (setq query
+                (list
+                 (cons 'query (format "HEADER Message-ID %s" article))
+                 (cons 'criteria "")
+                 (cons 'shortcut t)))
+          (unless (and nnir-artlist (equal query nnir-memo-query)
+                       (equal server nnir-memo-server))
+            (setq nnir-artlist (nnir-run-imap query server)
+                 nnir-memo-query query
+                 nnir-memo-server server))
+          (setq article 1))
+        (unless (zerop (nnir-artlist-length nnir-artlist))
+          (let ((artfullgroup (nnir-article-group article))
+                (artno (nnir-article-number article)))
+            (message "Requesting article %d from group %s"
+                     artno artfullgroup)
+            (if to-buffer
+                (with-current-buffer to-buffer
+                  (let ((gnus-article-decode-hook nil))
+                    (gnus-request-article-this-buffer artno artfullgroup)))
+              (gnus-request-article artno artfullgroup))
+            (cons artfullgroup artno)))))))
+
+(deffoo nnir-request-move-article (article group server accept-form
+                                          &optional last internal-move-group)
+  (nnir-possibly-change-group group server)
+  (let* ((artfullgroup (nnir-article-group article))
+        (artno (nnir-article-number article))
+        (to-newsgroup (nth 1 accept-form))
+        (to-method (gnus-find-method-for-group to-newsgroup))
+        (from-method (gnus-find-method-for-group artfullgroup))
+        (move-is-internal (gnus-server-equal from-method to-method)))
+    (unless (gnus-check-backend-function
+            'request-move-article artfullgroup)
+      (error "The group %s does not support article moving" artfullgroup))
+    (gnus-request-move-article
+     artno
+     artfullgroup
+     (nth 1 from-method)
+     accept-form
+     last
+     (and move-is-internal
+         to-newsgroup          ; Not respooling
+         (gnus-group-real-name to-newsgroup)))))
+
+(deffoo nnir-request-expire-articles (articles group &optional server force)
+  (nnir-possibly-change-group group server)
+  (if force
+    (let ((articles-by-group (nnir-categorize
+                             articles nnir-article-group nnir-article-ids))
+         not-deleted)
+      (while (not (null articles-by-group))
+       (let* ((group-articles (pop articles-by-group))
+              (artgroup (car group-articles))
+              (articleids (cadr group-articles))
+              (artlist (sort (mapcar 'cdr articleids) '<)))
+         (unless (gnus-check-backend-function 'request-expire-articles
+                                              artgroup)
+           (error "The group %s does not support article deletion" artgroup))
+         (unless (gnus-check-server (gnus-find-method-for-group artgroup))
+           (error "Couldn't open server for group %s" artgroup))
+         (push (gnus-request-expire-articles
+                artlist artgroup force)
+               not-deleted)))
+      (sort (delq nil not-deleted) '<))
+    articles))
+
+(deffoo nnir-warp-to-article ()
+  (nnir-possibly-change-group gnus-newsgroup-name)
+  (let* ((cur (if (> (gnus-summary-article-number) 0)
+                 (gnus-summary-article-number)
+               (error "Can't warp to a pseudo-article")))
+        (backend-article-group (nnir-article-group cur))
+         (backend-article-number (nnir-article-number cur))
+        (quit-config (gnus-ephemeral-group-p gnus-newsgroup-name)))
+
+    ;; what should we do here? we could leave all the buffers around
+    ;; and assume that we have to exit from them one by one. or we can
+    ;; try to clean up directly
+
+    ;;first exit from the nnir summary buffer.
+;    (gnus-summary-exit)
+    ;; and if the nnir summary buffer in turn came from another
+    ;; summary buffer we have to clean that summary up too.
+ ;   (when (not (eq (cdr quit-config) 'group))
+;      (gnus-summary-exit))
+    (gnus-summary-read-group-1 backend-article-group t t  nil
+                               nil (list backend-article-number))))
+
+(deffoo nnir-request-update-mark (group article mark)
+  (let ((artgroup (nnir-article-group article))
+       (artnumber (nnir-article-number article)))
+    (when (and artgroup artnumber)
+      (gnus-request-update-mark artgroup artnumber mark))))
+
+(deffoo nnir-request-set-mark (group actions &optional server)
+  (nnir-possibly-change-group group server)
+  (let (mlist)
+    (dolist (action actions)
+      (destructuring-bind (range action marks) action
+        (let ((articles-by-group (nnir-categorize
+                                  (gnus-uncompress-range range)
+                                  nnir-article-group nnir-article-number)))
+          (dolist (artgroup articles-by-group)
+            (push (list
+                  (car artgroup)
+                  (list (gnus-compress-sequence
+                         (sort (cadr artgroup) '<)) action marks)) mlist)))))
+    (dolist (request (nnir-categorize  mlist car cadr))
+      (gnus-request-set-mark (car request) (cadr request)))))
+
+
+(deffoo nnir-request-update-info (group info &optional server)
+  (nnir-possibly-change-group group server)
+  ;; clear out all existing marks.
+  (gnus-info-set-marks info nil)
+  (gnus-info-set-read info nil)
+  (let ((group (gnus-group-guess-full-name-from-command-method group))
+       (articles-by-group
+        (nnir-categorize
+         (gnus-uncompress-range (cons 1 (nnir-artlist-length nnir-artlist)))
+         nnir-article-group nnir-article-ids)))
+    (gnus-set-active group
+                    (cons 1 (nnir-artlist-length nnir-artlist)))
+    (while (not (null articles-by-group))
+      (let* ((group-articles (pop articles-by-group))
+            (articleids (reverse (cadr group-articles)))
+            (group-info (gnus-get-info (car group-articles)))
+            (marks (gnus-info-marks group-info))
+            (read (gnus-info-read group-info)))
+       (gnus-info-set-read
+        info
+        (gnus-add-to-range
+         (gnus-info-read info)
+         (delq nil
+                 (mapcar
+                  #'(lambda (art)
+                    (when (gnus-member-of-range (cdr art) read) (car art)))
+                  articleids))))
+       (dolist (mark marks)
+         (destructuring-bind (type . range) mark
+           (gnus-add-marked-articles
+            group type
+            (delq nil
+                    (mapcar
+                     #'(lambda (art)
+                       (when (gnus-member-of-range (cdr art) range) (car art)))
+                     articleids)))))))))
+
+
+(deffoo nnir-close-group (group &optional server)
+  (nnir-possibly-change-group group server)
+  (let ((pgroup (gnus-group-guess-full-name-from-command-method group)))
+    (when (and nnir-artlist (not (gnus-ephemeral-group-p pgroup)))
+      (gnus-group-set-parameter  pgroup 'nnir-artlist nnir-artlist))
+    (setq nnir-artlist nil)
+    (when (gnus-ephemeral-group-p pgroup)
+      (gnus-kill-ephemeral-group pgroup)
+      (setq gnus-ephemeral-servers
+           (delq (assq 'nnir gnus-ephemeral-servers)
+                 gnus-ephemeral-servers)))))
+;; (gnus-opened-servers-remove
+;;  (car (assoc  '(nnir "nnir-ephemeral" (nnir-address "nnir"))
+;;             gnus-opened-servers))))
+
+
+
+
+(defmacro nnir-add-result (dirnam artno score prefix server artlist)
+  "Ask `nnir-compose-result' to construct a result vector,
+and if it is non-nil, add it to artlist."
+  `(let ((result (nnir-compose-result ,dirnam ,artno ,score ,prefix ,server)))
+     (when (not (null result))
+       (push result ,artlist))))
+
+(autoload 'nnmaildir-base-name-to-article-number "nnmaildir")
+
+;; Helper function currently used by the Swish++ and Namazu backends;
+;; perhaps useful for other backends as well
+(defun nnir-compose-result (dirnam article score prefix server)
+  "Extract the group from dirnam, and create a result vector
+ready to be added to the list of search results."
+
+  ;; remove nnir-*-remove-prefix from beginning of dirnam filename
+  (when (string-match (concat "^" prefix) dirnam)
+    (setq dirnam (replace-match "" t t dirnam)))
+
+  (when (file-readable-p (concat prefix dirnam article))
+    ;; remove trailing slash and, for nnmaildir, cur/new/tmp
+    (setq dirnam
+         (substring dirnam 0
+                    (if (string-match "\\`nnmaildir:" (gnus-group-server server))
+                        -5 -1)))
+
+    ;; Set group to dirnam without any leading dots or slashes,
+    ;; and with all subsequent slashes replaced by dots
+    (let ((group (gnus-replace-in-string
+                 (gnus-replace-in-string dirnam "^[./\\]" "" t)
+                 "[/\\]" "." t)))
+
+    (vector (gnus-group-full-name group server)
+           (if (string-match "\\`nnmaildir:" (gnus-group-server server))
+               (nnmaildir-base-name-to-article-number
+                (substring article 0 (string-match ":" article))
+                group nil)
+             (string-to-number article))
+           (string-to-number score)))))
+
+;;; Search Engine Interfaces:
+
+(autoload 'nnimap-change-group "nnimap")
+(declare-function nnimap-buffer "nnimap" ())
+(declare-function nnimap-command "nnimap" (&rest args))
+
+;; imap interface
+(defun nnir-run-imap (query srv &optional groups)
+  "Run a search against an IMAP back-end server.
+This uses a custom query language parser; see `nnir-imap-make-query' for
+details on the language and supported extensions."
+  (save-excursion
+    (let ((qstring (cdr (assq 'query query)))
+          (server (cadr (gnus-server-to-method srv)))
+          (defs (caddr (gnus-server-to-method srv)))
+          (criteria (or (cdr (assq 'criteria query))
+                        (cdr (assoc nnir-imap-default-search-key
+                                    nnir-imap-search-arguments))))
+          (gnus-inhibit-demon t)
+         (groups (or groups (nnir-get-active srv))))
+      (message "Opening server %s" server)
+      (apply
+       'vconcat
+       (catch 'found
+         (mapcar
+          #'(lambda (group)
+            (let (artlist)
+              (condition-case ()
+                  (when (nnimap-change-group
+                         (gnus-group-short-name group) server)
+                    (with-current-buffer (nnimap-buffer)
+                      (message "Searching %s..." group)
+                      (let ((arts 0)
+                            (result (nnimap-command "UID SEARCH %s"
+                                                    (if (string= criteria "")
+                                                        qstring
+                                                      (nnir-imap-make-query
+                                                       criteria qstring)))))
+                        (mapc
+                         (lambda (artnum)
+                           (let ((artn (string-to-number artnum)))
+                             (when (> artn 0)
+                               (push (vector group artn 100)
+                                     artlist)
+                               (when (assq 'shortcut query)
+                                 (throw 'found (list artlist)))
+                               (setq arts (1+ arts)))))
+                         (and (car result)
+                             (cdr (assoc "SEARCH" (cdr result)))))
+                        (message "Searching %s... %d matches" group arts)))
+                    (message "Searching %s...done" group))
+                (quit nil))
+              (nreverse artlist)))
+          groups))))))
+
+(defun nnir-imap-make-query (criteria qstring)
+  "Parse the query string and criteria into an appropriate IMAP search
+expression, returning the string query to make.
+
+This implements a little language designed to return the expected results
+to an arbitrary query string to the end user.
+
+The search is always case-insensitive, as defined by RFC2060, and supports
+the following features (inspired by the Google search input language):
+
+Automatic \"and\" queries
+    If you specify multiple words then they will be treated as an \"and\"
+    expression intended to match all components.
+
+Phrase searches
+    If you wrap your query in double-quotes then it will be treated as a
+    literal string.
+
+Negative terms
+    If you precede a term with \"-\" then it will negate that.
+
+\"OR\" queries
+    If you include an upper-case \"OR\" in your search it will cause the
+    term before it and the term after it to be treated as alternatives.
+
+In future the following will be added to the language:
+ * support for date matches
+ * support for location of text matching within the query
+ * from/to/etc headers
+ * additional search terms
+ * flag based searching
+ * anything else that the RFC supports, basically."
+  ;; Walk through the query and turn it into an IMAP query string.
+  (nnir-imap-query-to-imap criteria (nnir-imap-parse-query qstring)))
+
+
+(defun nnir-imap-query-to-imap (criteria query)
+  "Turn a s-expression format query into IMAP."
+  (mapconcat
+   ;; Turn the expressions into IMAP text
+   (lambda (item)
+     (nnir-imap-expr-to-imap criteria item))
+   ;; The query, already in s-expr format.
+   query
+   ;; Append a space between each expression
+   " "))
+
+
+(defun nnir-imap-expr-to-imap (criteria expr)
+  "Convert EXPR into an IMAP search expression on CRITERIA"
+  ;; What sort of expression is this, eh?
+  (cond
+   ;; Simple string term
+   ((stringp expr)
+    (format "%s %S" criteria expr))
+   ;; Trivial term: and
+   ((eq expr 'and) nil)
+   ;; Composite term: or expression
+   ((eq (car-safe expr) 'or)
+    (format "OR %s %s"
+           (nnir-imap-expr-to-imap criteria (second expr))
+           (nnir-imap-expr-to-imap criteria (third expr))))
+   ;; Composite term: just the fax, mam
+   ((eq (car-safe expr) 'not)
+    (format "NOT (%s)" (nnir-imap-query-to-imap criteria (rest expr))))
+   ;; Composite term: just expand it all.
+   ((and (not (null expr)) (listp expr))
+    (format "(%s)" (nnir-imap-query-to-imap criteria expr)))
+   ;; Complex value, give up for now.
+   (t (error "Unhandled input: %S" expr))))
+
+
+(defun nnir-imap-parse-query (string)
+  "Turn STRING into an s-expression based query based on the IMAP
+query language as defined in `nnir-imap-make-query'.
+
+This involves turning individual tokens into higher level terms
+that the search language can then understand and use."
+  (with-temp-buffer
+    ;; Set up the parsing environment.
+    (insert string)
+    (goto-char (point-min))
+    ;; Now, collect the output terms and return them.
+    (let (out)
+      (while (not (nnir-imap-end-of-input))
+       (push (nnir-imap-next-expr) out))
+      (reverse out))))
+
+
+(defun nnir-imap-next-expr (&optional count)
+  "Return the next expression from the current buffer."
+  (let ((term (nnir-imap-next-term count))
+       (next (nnir-imap-peek-symbol)))
+    ;; Are we looking at an 'or' expression?
+    (cond
+     ;; Handle 'expr or expr'
+     ((eq next 'or)
+      (list 'or term (nnir-imap-next-expr 2)))
+     ;; Anything else
+     (t term))))
+
+
+(defun nnir-imap-next-term (&optional count)
+  "Return the next TERM from the current buffer."
+  (let ((term (nnir-imap-next-symbol count)))
+    ;; What sort of term is this?
+    (cond
+     ;; and -- just ignore it
+     ((eq term 'and) 'and)
+     ;; negated term
+     ((eq term 'not) (list 'not (nnir-imap-next-expr)))
+     ;; generic term
+     (t term))))
+
+
+(defun nnir-imap-peek-symbol ()
+  "Return the next symbol from the current buffer, but don't consume it."
+  (save-excursion
+    (nnir-imap-next-symbol)))
+
+(defun nnir-imap-next-symbol (&optional count)
+  "Return the next symbol from the current buffer, or nil if we are
+at the end of the buffer.  If supplied COUNT skips some symbols before
+returning the one at the supplied position."
+  (when (and (numberp count) (> count 1))
+    (nnir-imap-next-symbol (1- count)))
+  (let ((case-fold-search t))
+    ;; end of input stream?
+    (unless (nnir-imap-end-of-input)
+      ;; No, return the next symbol from the stream.
+      (cond
+       ;; negated expression -- return it and advance one char.
+       ((looking-at "-") (forward-char 1) 'not)
+       ;; quoted string
+       ((looking-at "\"") (nnir-imap-delimited-string "\""))
+       ;; list expression -- we parse the content and return this as a list.
+       ((looking-at "(")
+       (nnir-imap-parse-query (nnir-imap-delimited-string ")")))
+       ;; keyword input -- return a symbol version
+       ((looking-at "\\band\\b") (forward-char 3) 'and)
+       ((looking-at "\\bor\\b")  (forward-char 2) 'or)
+       ((looking-at "\\bnot\\b") (forward-char 3) 'not)
+       ;; Simple, boring keyword
+       (t (let ((start (point))
+               (end (if (search-forward-regexp "[[:blank:]]" nil t)
+                        (prog1
+                            (match-beginning 0)
+                          ;; unskip if we hit a non-blank terminal character.
+                          (when (string-match "[^[:blank:]]" (match-string 0))
+                            (backward-char 1)))
+                      (goto-char (point-max)))))
+           (buffer-substring start end)))))))
+
+(defun nnir-imap-delimited-string (delimiter)
+  "Return a delimited string from the current buffer."
+  (let ((start (point)) end)
+    (forward-char 1)                   ; skip the first delimiter.
+    (while (not end)
+      (unless (search-forward delimiter nil t)
+       (error "Unmatched delimited input with %s in query" delimiter))
+      (let ((here (point)))
+       (unless (equal (buffer-substring (- here 2) (- here 1)) "\\")
+         (setq end (point)))))
+    (buffer-substring (1+ start) (1- end))))
+
+(defun nnir-imap-end-of-input ()
+  "Are we at the end of input?"
+  (skip-chars-forward "[[:blank:]]")
+  (looking-at "$"))
+
+
+;; Swish++ interface.
+;; -cc- Todo
+;; Search by
+;; - group
+;; Sort by
+;; - rank (default)
+;; - article number
+;; - file size
+;; - group
+(defun nnir-run-swish++ (query server &optional group)
+  "Run QUERY against swish++.
+Returns a vector of (group name, file name) pairs (also vectors,
+actually).
+
+Tested with swish++ 4.7 on GNU/Linux and with swish++ 5.0b2 on
+Windows NT 4.0."
+
+  ;; (when group
+  ;;   (error "The swish++ backend cannot search specific groups"))
+
+  (save-excursion
+    (let ( (qstring (cdr (assq 'query query)))
+          (groupspec (cdr (assq 'swish++-group query)))
+          (prefix (nnir-read-server-parm 'nnir-swish++-remove-prefix server))
+           artlist
+          ;; nnml-use-compressed-files might be any string, but probably this
+          ;; is sufficient.  Note that we can't only use the value of
+          ;; nnml-use-compressed-files because old articles might have been
+          ;; saved with a different value.
+          (article-pattern (if (string-match "\\`nnmaildir:"
+                                             (gnus-group-server server))
+                               ":[0-9]+"
+                             "^[0-9]+\\(\\.[a-z0-9]+\\)?$"))
+           score artno dirnam filenam)
+
+      (when (equal "" qstring)
+        (error "swish++: You didn't enter anything"))
+
+      (set-buffer (get-buffer-create nnir-tmp-buffer))
+      (erase-buffer)
+
+      (if groupspec
+          (message "Doing swish++ query %s on %s..." qstring groupspec)
+        (message "Doing swish++ query %s..." qstring))
+
+      (let* ((cp-list `( ,nnir-swish++-program
+                         nil            ; input from /dev/null
+                         t              ; output
+                         nil            ; don't redisplay
+                         "--config-file" ,(nnir-read-server-parm 'nnir-swish++-configuration-file server)
+                         ,@(nnir-read-server-parm 'nnir-swish++-additional-switches server)
+                         ,qstring       ; the query, in swish++ format
+                         ))
+             (exitstatus
+              (progn
+                (message "%s args: %s" nnir-swish++-program
+                         (mapconcat 'identity (cddddr cp-list) " ")) ;; ???
+                (apply 'call-process cp-list))))
+        (unless (or (null exitstatus)
+                    (zerop exitstatus))
+          (nnheader-report 'nnir "Couldn't run swish++: %s" exitstatus)
+          ;; swish++ failure reason is in this buffer, show it if
+          ;; the user wants it.
+          (when (> gnus-verbose 6)
+            (display-buffer nnir-tmp-buffer))))
+
+      ;; The results are output in the format of:
+      ;; V 4.7 Linux
+      ;; rank relative-path-name file-size file-title
+      ;; V 5.0b2:
+      ;; rank relative-path-name file-size topic??
+      ;; where rank is an integer from 1 to 100.
+      (goto-char (point-min))
+      (while (re-search-forward
+              "\\(^[0-9]+\\) \\([^ ]+\\) [0-9]+ \\(.*\\)$" nil t)
+        (setq score (match-string 1)
+             filenam (match-string 2)
+              artno (file-name-nondirectory filenam)
+              dirnam (file-name-directory filenam))
+
+        ;; don't match directories
+        (when (string-match article-pattern artno)
+          (when (not (null dirnam))
+
+           ;; maybe limit results to matching groups.
+           (when (or (not groupspec)
+                     (string-match groupspec dirnam))
+             (nnir-add-result dirnam artno score prefix server artlist)))))
+
+      (message "Massaging swish++ output...done")
+
+      ;; Sort by score
+      (apply 'vector
+             (sort artlist
+                   (function (lambda (x y)
+                               (> (nnir-artitem-rsv x)
+                                  (nnir-artitem-rsv y)))))))))
+
+;; Swish-E interface.
+(defun nnir-run-swish-e (query server &optional group)
+  "Run given query against swish-e.
+Returns a vector of (group name, file name) pairs (also vectors,
+actually).
+
+Tested with swish-e-2.0.1 on Windows NT 4.0."
+
+  ;; swish-e crashes with empty parameter to "-w" on commandline...
+  ;; (when group
+  ;;   (error "The swish-e backend cannot search specific groups"))
+
+  (save-excursion
+    (let ((qstring (cdr (assq 'query query)))
+         (prefix
+          (or (nnir-read-server-parm 'nnir-swish-e-remove-prefix server)
+              (error "Missing parameter `nnir-swish-e-remove-prefix'")))
+          artlist score artno dirnam group )
+
+      (when (equal "" qstring)
+        (error "swish-e: You didn't enter anything"))
+
+      (set-buffer (get-buffer-create nnir-tmp-buffer))
+      (erase-buffer)
+
+      (message "Doing swish-e query %s..." query)
+      (let* ((index-files
+             (or (nnir-read-server-parm
+                  'nnir-swish-e-index-files server)
+                 (error "Missing parameter `nnir-swish-e-index-files'")))
+            (additional-switches
+             (nnir-read-server-parm
+              'nnir-swish-e-additional-switches server))
+            (cp-list `(,nnir-swish-e-program
+                       nil             ; input from /dev/null
+                       t               ; output
+                       nil             ; don't redisplay
+                       "-f" ,@index-files
+                       ,@additional-switches
+                       "-w"
+                       ,qstring        ; the query, in swish-e format
+                       ))
+             (exitstatus
+              (progn
+                (message "%s args: %s" nnir-swish-e-program
+                         (mapconcat 'identity (cddddr cp-list) " "))
+                (apply 'call-process cp-list))))
+        (unless (or (null exitstatus)
+                    (zerop exitstatus))
+          (nnheader-report 'nnir "Couldn't run swish-e: %s" exitstatus)
+          ;; swish-e failure reason is in this buffer, show it if
+          ;; the user wants it.
+          (when (> gnus-verbose 6)
+            (display-buffer nnir-tmp-buffer))))
+
+      ;; The results are output in the format of:
+      ;; rank path-name file-title file-size
+      (goto-char (point-min))
+      (while (re-search-forward
+              "\\(^[0-9]+\\) \\([^ ]+\\) \"\\([^\"]+\\)\" [0-9]+$" nil t)
+        (setq score (match-string 1)
+              artno (match-string 3)
+              dirnam (file-name-directory (match-string 2)))
+
+        ;; don't match directories
+        (when (string-match "^[0-9]+$" artno)
+          (when (not (null dirnam))
+
+           ;; remove nnir-swish-e-remove-prefix from beginning of dirname
+            (when (string-match (concat "^" prefix) dirnam)
+              (setq dirnam (replace-match "" t t dirnam)))
+
+            (setq dirnam (substring dirnam 0 -1))
+           ;; eliminate all ".", "/", "\" from beginning. Always matches.
+            (string-match "^[./\\]*\\(.*\\)$" dirnam)
+            ;; "/" -> "."
+            (setq group (gnus-replace-in-string (match-string 1 dirnam) "/" "."))
+            ;; Windows "\\" -> "."
+            (setq group (gnus-replace-in-string group "\\\\" "."))
+
+            (push (vector (gnus-group-full-name group server)
+                          (string-to-number artno)
+                          (string-to-number score))
+                  artlist))))
+
+      (message "Massaging swish-e output...done")
+
+      ;; Sort by score
+      (apply 'vector
+             (sort artlist
+                   (function (lambda (x y)
+                               (> (nnir-artitem-rsv x)
+                                  (nnir-artitem-rsv y)))))))))
+
+;; HyREX interface
+(defun nnir-run-hyrex (query server &optional group)
+  (save-excursion
+    (let ((artlist nil)
+          (groupspec (cdr (assq 'hyrex-group query)))
+          (qstring (cdr (assq 'query query)))
+         (prefix (nnir-read-server-parm 'nnir-hyrex-remove-prefix server))
+         score artno dirnam)
+      (when (and (not groupspec) group)
+        (setq groupspec
+             (regexp-opt
+              (mapcar (lambda (x) (gnus-group-real-name x)) group))))
+      (set-buffer (get-buffer-create nnir-tmp-buffer))
+      (erase-buffer)
+      (message "Doing hyrex-search query %s..." query)
+      (let* ((cp-list
+             `( ,nnir-hyrex-program
+                nil                    ; input from /dev/null
+                t                      ; output
+                nil                    ; don't redisplay
+                "-i",(nnir-read-server-parm 'nnir-hyrex-index-directory server) ; index directory
+                ,@(nnir-read-server-parm 'nnir-hyrex-additional-switches server)
+                ,qstring          ; the query, in hyrex-search format
+                ))
+             (exitstatus
+              (progn
+                (message "%s args: %s" nnir-hyrex-program
+                         (mapconcat 'identity (cddddr cp-list) " "))
+                (apply 'call-process cp-list))))
+        (unless (or (null exitstatus)
+                    (zerop exitstatus))
+          (nnheader-report 'nnir "Couldn't run hyrex-search: %s" exitstatus)
+          ;; nnir-search failure reason is in this buffer, show it if
+          ;; the user wants it.
+          (when (> gnus-verbose 6)
+            (display-buffer nnir-tmp-buffer)))) ;; FIXME: Don't clear buffer !
+      (message "Doing hyrex-search query \"%s\"...done" qstring)
+      (sit-for 0)
+      ;; nnir-search returns:
+      ;;   for nnml/nnfolder: "filename mailid weight"
+      ;;   for nnimap:        "group mailid weight"
+      (goto-char (point-min))
+      (delete-non-matching-lines "^\\S + [0-9]+ [0-9]+$")
+      ;; HyREX doesn't search directly in groups -- so filter out here.
+      (when groupspec
+       (keep-lines groupspec))
+      ;; extract data from result lines
+      (goto-char (point-min))
+      (while (re-search-forward
+             "\\(\\S +\\) \\([0-9]+\\) \\([0-9]+\\)" nil t)
+       (setq dirnam (match-string 1)
+             artno (match-string 2)
+             score (match-string 3))
+       (when (string-match prefix dirnam)
+         (setq dirnam (replace-match "" t t dirnam)))
+       (push (vector (gnus-group-full-name
+                       (gnus-replace-in-string dirnam "/" ".") server)
+                     (string-to-number artno)
+                     (string-to-number score))
+             artlist))
+      (message "Massaging hyrex-search output...done.")
+      (apply 'vector
+            (sort artlist
+                   (function (lambda (x y)
+                               (if (string-lessp (nnir-artitem-group x)
+                                                 (nnir-artitem-group y))
+                                   t
+                                 (< (nnir-artitem-number x)
+                                    (nnir-artitem-number y)))))))
+      )))
+
+;; Namazu interface
+(defun nnir-run-namazu (query server &optional group)
+  "Run given query against Namazu.  Returns a vector of (group name, file name)
+pairs (also vectors, actually).
+
+Tested with Namazu 2.0.6 on a GNU/Linux system."
+  ;; (when group
+  ;;   (error "The Namazu backend cannot search specific groups"))
+  (save-excursion
+    (let ((article-pattern (if (string-match "\\`nnmaildir:"
+                                            (gnus-group-server server))
+                              ":[0-9]+"
+                            "^[0-9]+$"))
+          artlist
+         (qstring (cdr (assq 'query query)))
+         (prefix (nnir-read-server-parm 'nnir-namazu-remove-prefix server))
+          score group article
+          (process-environment (copy-sequence process-environment)))
+      (setenv "LC_MESSAGES" "C")
+      (set-buffer (get-buffer-create nnir-tmp-buffer))
+      (erase-buffer)
+      (let* ((cp-list
+              `( ,nnir-namazu-program
+                 nil                   ; input from /dev/null
+                 t                     ; output
+                 nil                   ; don't redisplay
+                 "-q"                  ; don't be verbose
+                 "-a"                  ; show all matches
+                 "-s"                  ; use short format
+                 ,@(nnir-read-server-parm 'nnir-namazu-additional-switches server)
+                 ,qstring              ; the query, in namazu format
+                 ,(nnir-read-server-parm 'nnir-namazu-index-directory server) ; index directory
+                 ))
+             (exitstatus
+              (progn
+                (message "%s args: %s" nnir-namazu-program
+                         (mapconcat 'identity (cddddr cp-list) " "))
+                (apply 'call-process cp-list))))
+        (unless (or (null exitstatus)
+                    (zerop exitstatus))
+          (nnheader-report 'nnir "Couldn't run namazu: %s" exitstatus)
+          ;; Namazu failure reason is in this buffer, show it if
+          ;; the user wants it.
+          (when (> gnus-verbose 6)
+            (display-buffer nnir-tmp-buffer))))
+
+      ;; Namazu output looks something like this:
+      ;; 2. Re: Gnus agent expire broken (score: 55)
+      ;; /home/henrik/Mail/mail/sent/1310 (4,138 bytes)
+
+      (goto-char (point-min))
+      (while (re-search-forward
+              "^\\([0-9,]+\\.\\).*\\((score: \\([0-9]+\\)\\))\n\\([^ ]+\\)"
+              nil t)
+        (setq score (match-string 3)
+              group (file-name-directory (match-string 4))
+              article (file-name-nondirectory (match-string 4)))
+
+        ;; make sure article and group is sane
+        (when (and (string-match article-pattern article)
+                   (not (null group)))
+         (nnir-add-result group article score prefix server artlist)))
+
+      ;; sort artlist by score
+      (apply 'vector
+             (sort artlist
+                   (function (lambda (x y)
+                               (> (nnir-artitem-rsv x)
+                                  (nnir-artitem-rsv y)))))))))
+
+(defun nnir-run-notmuch (query server &optional group)
+  "Run QUERY against notmuch.
+Returns a vector of (group name, file name) pairs (also vectors,
+actually)."
+
+  ;; (when group
+  ;;   (error "The notmuch backend cannot search specific groups"))
+
+  (save-excursion
+    (let ( (qstring (cdr (assq 'query query)))
+          (groupspec (cdr (assq 'notmuch-group query)))
+          (prefix (nnir-read-server-parm 'nnir-notmuch-remove-prefix server))
+           artlist
+          (article-pattern (if (string-match "\\`nnmaildir:"
+                                             (gnus-group-server server))
+                              ":[0-9]+"
+                            "^[0-9]+$"))
+           artno dirnam filenam)
+
+      (when (equal "" qstring)
+        (error "notmuch: You didn't enter anything"))
+
+      (set-buffer (get-buffer-create nnir-tmp-buffer))
+      (erase-buffer)
+
+      (if groupspec
+          (message "Doing notmuch query %s on %s..." qstring groupspec)
+        (message "Doing notmuch query %s..." qstring))
+
+      (let* ((cp-list `( ,nnir-notmuch-program
+                         nil            ; input from /dev/null
+                         t              ; output
+                         nil            ; don't redisplay
+                         "search"
+                         "--format=text"
+                         "--output=files"
+                         ,@(nnir-read-server-parm 'nnir-notmuch-additional-switches server)
+                         ,qstring       ; the query, in notmuch format
+                         ))
+             (exitstatus
+              (progn
+                (message "%s args: %s" nnir-notmuch-program
+                         (mapconcat 'identity (cddddr cp-list) " ")) ;; ???
+                (apply 'call-process cp-list))))
+        (unless (or (null exitstatus)
+                    (zerop exitstatus))
+          (nnheader-report 'nnir "Couldn't run notmuch: %s" exitstatus)
+          ;; notmuch failure reason is in this buffer, show it if
+          ;; the user wants it.
+          (when (> gnus-verbose 6)
+            (display-buffer nnir-tmp-buffer))))
+
+      ;; The results are output in the format of:
+      ;; absolute-path-name
+      (goto-char (point-min))
+      (while (not (eobp))
+        (setq filenam (buffer-substring-no-properties (line-beginning-position)
+                                                      (line-end-position))
+              artno (file-name-nondirectory filenam)
+              dirnam (file-name-directory filenam))
+        (forward-line 1)
+
+        ;; don't match directories
+        (when (string-match article-pattern artno)
+          (when (not (null dirnam))
+
+           ;; maybe limit results to matching groups.
+           (when (or (not groupspec)
+                     (string-match groupspec dirnam))
+             (nnir-add-result dirnam artno "" prefix server artlist)))))
+
+      (message "Massaging notmuch output...done")
+
+      artlist)))
+
+(defun nnir-run-find-grep (query server &optional grouplist)
+  "Run find and grep to obtain matching articles."
+  (let* ((method (gnus-server-to-method server))
+        (sym (intern
+              (concat (symbol-name (car method)) "-directory")))
+        (directory (cadr (assoc sym (cddr method))))
+        (regexp (cdr (assoc 'query query)))
+        (grep-options (cdr (assoc 'grep-options query)))
+        (grouplist (or grouplist (nnir-get-active server))))
+    (unless directory
+      (error "No directory found in method specification of server %s"
+            server))
+    (apply
+     'vconcat
+     (mapcar (lambda (x)
+              (let ((group x)
+                    artlist)
+                (message "Searching %s using find-grep..."
+                         (or group server))
+                (save-window-excursion
+                  (set-buffer (get-buffer-create nnir-tmp-buffer))
+                  (if (> gnus-verbose 6)
+                      (pop-to-buffer (current-buffer)))
+                  (cd directory) ; Using relative paths simplifies
+                                       ; postprocessing.
+                  (let ((group
+                         (if (not group)
+                             "."
+                           ;; Try accessing the group literally as
+                           ;; well as interpreting dots as directory
+                           ;; separators so the engine works with
+                           ;; plain nnml as well as the Gnus Cache.
+                           (let ((group (gnus-group-real-name group)))
+                             ;; Replace cl-func find-if.
+                             (if (file-directory-p group)
+                                 group
+                               (if (file-directory-p
+                                    (setq group
+                                          (gnus-replace-in-string
+                                           group
+                                           "\\." "/" t)))
+                                   group))))))
+                    (unless group
+                      (error "Cannot locate directory for group"))
+                    (save-excursion
+                      (apply
+                       'call-process "find" nil t
+                       "find" group "-maxdepth" "1" "-type" "f"
+                       "-name" "[0-9]*" "-exec"
+                       "grep"
+                       `("-l" ,@(and grep-options
+                                     (split-string grep-options "\\s-" t))
+                         "-e" ,regexp "{}" "+"))))
+
+                  ;; Translate relative paths to group names.
+                  (while (not (eobp))
+                    (let* ((path (split-string
+                                  (buffer-substring
+                                   (point)
+                                   (line-end-position)) "/" t))
+                           (art (string-to-number (car (last path)))))
+                      (while (string= "." (car path))
+                        (setq path (cdr path)))
+                      (let ((group (mapconcat 'identity
+                                              ;; Replace cl-func:
+                                              ;; (subseq path 0 -1)
+                                              (let ((end (1- (length path)))
+                                                    res)
+                                                (while
+                                                    (>= (setq end (1- end)) 0)
+                                                  (push (pop path) res))
+                                                (nreverse res))
+                                              ".")))
+                        (push
+                         (vector (gnus-group-full-name group server) art 0)
+                         artlist))
+                      (forward-line 1)))
+                  (message "Searching %s using find-grep...done"
+                           (or group server))
+                  artlist)))
+     grouplist))))
+
+(declare-function mm-url-insert "mm-url" (url &optional follow-refresh))
+(declare-function mm-url-encode-www-form-urlencoded "mm-url" (pairs))
+
+;; gmane interface
+(defun nnir-run-gmane (query srv &optional groups)
+  "Run a search against a gmane back-end server."
+      (let* ((case-fold-search t)
+            (qstring (cdr (assq 'query query)))
+            (server (cadr (gnus-server-to-method srv)))
+            (groupspec (mapconcat
+                        (lambda (x)
+                          (if (gnus-string-match-p "gmane" x)
+                              (format "group:%s" (gnus-group-short-name x))
+                            (error "Can't search non-gmane groups: %s" x)))
+                          groups " "))
+            (authorspec
+             (if (assq 'gmane-author query)
+                 (format "author:%s" (cdr (assq 'gmane-author query))) ""))
+            (search (format "%s %s %s"
+                            qstring groupspec authorspec))
+            (gnus-inhibit-demon t)
+            artlist)
+       (require 'mm-url)
+       (with-current-buffer (get-buffer-create nnir-tmp-buffer)
+         (erase-buffer)
+         (mm-url-insert
+          (concat
+           "http://search.gmane.org/nov.php"
+           "?"
+           (mm-url-encode-www-form-urlencoded
+            `(("query" . ,search)
+              ("HITSPERPAGE" . "999")))))
+         (unless (featurep 'xemacs) (set-buffer-multibyte t))
+         (mm-decode-coding-region (point-min) (point-max) 'utf-8)
+         (goto-char (point-min))
+         (forward-line 1)
+         (while (not (eobp))
+           (unless (or (eolp) (looking-at "\x0d"))
+             (let ((header (nnheader-parse-nov)))
+               (let ((xref (mail-header-xref header))
+                     (xscore (string-to-number (cdr (assoc 'X-Score
+                              (mail-header-extra header))))))
+                 (when (string-match " \\([^:]+\\)[:/]\\([0-9]+\\)" xref)
+                   (push
+                    (vector
+                     (gnus-group-prefixed-name (match-string 1 xref) srv)
+                     (string-to-number (match-string 2 xref)) xscore)
+                    artlist)))))
+           (forward-line 1)))
+       (apply 'vector (nreverse (mm-delete-duplicates artlist)))))
+
+;;; Util Code:
+
+(defun gnus-nnir-group-p (group)
+  "Say whether GROUP is nnir or not."
+  (if (gnus-group-prefixed-p group)
+      (eq 'nnir (car (gnus-find-method-for-group group)))
+    (and group (string-match "^nnir" group))))
+
+(defun nnir-read-parms (nnir-search-engine)
+  "Reads additional search parameters according to `nnir-engines'."
+  (let ((parmspec (caddr (assoc nnir-search-engine nnir-engines))))
+    (mapcar 'nnir-read-parm parmspec)))
+
+(defun nnir-read-parm (parmspec)
+  "Reads a single search parameter.
+`parmspec' is a cons cell, the car is a symbol, the cdr is a prompt."
+  (let ((sym (car parmspec))
+        (prompt (cdr parmspec)))
+    (if (listp prompt)
+       (let* ((result (apply 'gnus-completing-read prompt))
+              (mapping (or (assoc result nnir-imap-search-arguments)
+                           (cons nil nnir-imap-search-other))))
+         (cons sym (format (cdr mapping) result)))
+      (cons sym (read-string prompt)))))
+
+(defun nnir-run-query (specs)
+  "Invoke appropriate search engine function (see `nnir-engines')."
+  (apply 'vconcat
+        (mapcar
+         (lambda (x)
+           (let* ((server (car x))
+                  (search-engine (nnir-server-to-search-engine server))
+                  (search-func (cadr (assoc search-engine nnir-engines))))
+             (and search-func
+                  (funcall search-func (cdr (assq 'nnir-query-spec specs))
+                           server (cadr x)))))
+         (cdr (assq 'nnir-group-spec specs)))))
+
+(defun nnir-server-to-search-engine (server)
+  (or (nnir-read-server-parm 'nnir-search-engine server t)
+      (cdr (assoc (car (gnus-server-to-method server))
+                 nnir-method-default-engines))))
+
+(defun nnir-read-server-parm (key server &optional not-global)
+  "Returns the parameter value corresponding to `key' for
+`server'. If no server-specific value is found consult the global
+environment unless `not-global' is non-nil."
+  (let ((method (gnus-server-to-method server)))
+    (cond ((and method (assq key (cddr method)))
+           (nth 1 (assq key (cddr method))))
+          ((and (not not-global) (boundp key)) (symbol-value key))
+          (t nil))))
+
+(defun nnir-possibly-change-group (group &optional server)
+  (or (not server) (nnir-server-opened server) (nnir-open-server server))
+  (when (gnus-nnir-group-p group)
+    (setq nnir-artlist (gnus-group-get-parameter
+                       (gnus-group-prefixed-name
+                        (gnus-group-short-name group) '(nnir "nnir"))
+                       'nnir-artlist t))))
+
+(defun nnir-server-opened (&optional server)
+  (let ((backend (car (gnus-server-to-method server))))
+    (nnoo-current-server-p (or backend 'nnir) server)))
+
+(autoload 'nnimap-make-thread-query "nnimap")
+(declare-function gnus-registry-get-id-key "gnus-registry" (id key))
+
+(defun nnir-search-thread (header)
+  "Make an nnir group based on the thread containing the article
+header. The current server will be searched. If the registry is
+installed, the server that the registry reports the current
+article came from is also searched."
+  (let* ((query
+         (list (cons 'query (nnimap-make-thread-query header))
+               (cons 'criteria "")))
+        (server
+         (list (list (gnus-method-to-server
+          (gnus-find-method-for-group gnus-newsgroup-name)))))
+        (registry-group (and
+                         (gnus-bound-and-true-p 'gnus-registry-enabled)
+                         (car (gnus-registry-get-id-key
+                               (mail-header-id header) 'group))))
+        (registry-server
+         (and registry-group
+              (gnus-method-to-server
+               (gnus-find-method-for-group registry-group)))))
+    (when registry-server (add-to-list 'server (list registry-server)))
+    (gnus-group-make-nnir-group nil (list
+                                    (cons 'nnir-query-spec query)
+                                    (cons 'nnir-group-spec server)))
+    (gnus-summary-goto-subject (gnus-id-to-article (mail-header-id header)))))
+
+(defun nnir-get-active (srv)
+  (let ((method (gnus-server-to-method srv))
+       groups)
+    (gnus-request-list method)
+    (with-current-buffer nntp-server-buffer
+      (let ((cur (current-buffer))
+           name)
+       (goto-char (point-min))
+       (unless (or (null nnir-ignored-newsgroups)
+                   (string= nnir-ignored-newsgroups ""))
+         (delete-matching-lines nnir-ignored-newsgroups))
+       (if (eq (car method) 'nntp)
+           (while (not (eobp))
+             (ignore-errors
+               (push (mm-string-as-unibyte
+                      (gnus-group-full-name
+                       (buffer-substring
+                        (point)
+                        (progn
+                          (skip-chars-forward "^ \t")
+                          (point))) method))
+                     groups))
+             (forward-line))
+         (while (not (eobp))
+           (ignore-errors
+             (push (mm-string-as-unibyte
+                    (if (eq (char-after) ?\")
+                        (gnus-group-full-name (read cur) method)
+                      (let ((p (point)) (name ""))
+                        (skip-chars-forward "^ \t\\\\")
+                        (setq name (buffer-substring p (point)))
+                        (while (eq (char-after) ?\\)
+                          (setq p (1+ (point)))
+                          (forward-char 2)
+                          (skip-chars-forward "^ \t\\\\")
+                          (setq name (concat name (buffer-substring
+                                                   p (point)))))
+                        (gnus-group-full-name name method))))
+                   groups))
+           (forward-line)))))
+    groups))
+
+;; Behind gnus-registry-enabled test.
+(declare-function gnus-registry-action "gnus-registry"
+                  (action data-header from &optional to method))
+
+(defun nnir-registry-action (action data-header from &optional to method)
+  "Call `gnus-registry-action' with the original article group."
+  (gnus-registry-action
+   action
+   data-header
+   (nnir-article-group (mail-header-number data-header))
+   to
+   method))
+
+(defun nnir-mode ()
+  (when (eq (car (gnus-find-method-for-group gnus-newsgroup-name)) 'nnir)
+    (setq gnus-summary-line-format
+         (or nnir-summary-line-format gnus-summary-line-format))
+    (when (gnus-bound-and-true-p 'gnus-registry-enabled)
+      (remove-hook 'gnus-summary-article-delete-hook 'gnus-registry-action t)
+      (remove-hook 'gnus-summary-article-move-hook 'gnus-registry-action t)
+      (remove-hook 'gnus-summary-article-expire-hook 'gnus-registry-action t)
+      (add-hook 'gnus-summary-article-delete-hook 'nnir-registry-action t t)
+      (add-hook 'gnus-summary-article-move-hook 'nnir-registry-action t t)
+      (add-hook 'gnus-summary-article-expire-hook 'nnir-registry-action t t))))
+
+
+(defun gnus-summary-create-nnir-group ()
+  (interactive)
+  (or (nnir-server-opened "") (nnir-open-server "nnir"))
+  (let ((name (gnus-read-group "Group name: "))
+       (method '(nnir ""))
+       (pgroup
+        (gnus-group-guess-full-name-from-command-method gnus-newsgroup-name)))
+    (with-current-buffer gnus-group-buffer
+      (gnus-group-make-group
+       name method nil
+       (gnus-group-find-parameter pgroup)))))
+
+
+(deffoo nnir-request-create-group (group &optional server args)
+  (message "Creating nnir group %s" group)
+  (let* ((group (gnus-group-prefixed-name  group '(nnir "nnir")))
+         (specs (assq 'nnir-specs args))
+         (query-spec
+          (or (cdr (assq 'nnir-query-spec specs))
+              (list (cons 'query
+                          (read-string "Query: " nil 'nnir-search-history)))))
+         (group-spec
+          (or (cdr (assq 'nnir-group-spec specs))
+              (list (list (read-string "Server: " nil nil)))))
+         (nnir-specs (list (cons 'nnir-query-spec query-spec)
+                           (cons 'nnir-group-spec group-spec))))
+    (gnus-group-set-parameter group 'nnir-specs nnir-specs)
+    (gnus-group-set-parameter
+     group 'nnir-artlist
+     (or (cdr (assq 'nnir-artlist args))
+         (nnir-run-query nnir-specs)))
+    (nnir-request-update-info group (gnus-get-info group)))
+  t)
+
+(deffoo nnir-request-delete-group (group &optional force server)
+  t)
+
+(deffoo nnir-request-list (&optional server)
+  t)
+
+(deffoo nnir-request-scan (group method)
+  t)
+
+(deffoo nnir-request-close ()
+  t)
+
+(nnoo-define-skeleton nnir)
+
+;; The end.
+(provide 'nnir)
+
+;;; nnir.el ends here
diff --git a/xemacs-packages/gnus/lisp/nnmail.el b/xemacs-packages/gnus/lisp/nnmail.el
new file mode 100644 (file)
index 0000000..3d4178d
--- /dev/null
@@ -0,0 +1,2096 @@
+;;; nnmail.el --- mail support functions for the Gnus mail backends
+
+;; Copyright (C) 1995-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: news, mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'gnus)                                ; for macro gnus-kill-buffer, at least
+(require 'nnheader)
+(require 'message)
+(require 'gnus-util)
+(require 'mail-source)
+(require 'mm-util)
+(require 'gnus-int)
+
+(autoload 'gnus-add-buffer "gnus")
+(autoload 'gnus-kill-buffer "gnus")
+(autoload 'mail-send-and-exit "sendmail" nil t)
+
+(defgroup nnmail nil
+  "Reading mail with Gnus."
+  :group 'gnus)
+
+(defgroup nnmail-retrieve nil
+  "Retrieving new mail."
+  :group 'nnmail)
+
+(defgroup nnmail-prepare nil
+  "Preparing (or mangling) new mail after retrieval."
+  :group 'nnmail)
+
+(defgroup nnmail-duplicate nil
+  "Handling of duplicate mail messages."
+  :group 'nnmail)
+
+(defgroup nnmail-split nil
+  "Organizing the incoming mail in folders."
+  :group 'nnmail)
+
+(defgroup nnmail-files nil
+  "Mail files."
+  :group 'gnus-files
+  :group 'nnmail)
+
+(defgroup nnmail-expire nil
+  "Expiring old mail."
+  :group 'nnmail)
+
+(defgroup nnmail-procmail nil
+  "Interfacing with procmail and other mail agents."
+  :group 'nnmail)
+
+(defgroup nnmail-various nil
+  "Various mail options."
+  :group 'nnmail)
+
+(defcustom nnmail-split-methods '(("mail.misc" ""))
+  "*Incoming mail will be split according to this variable.
+
+If you'd like, for instance, one mail group for mail from the
+\"4ad-l\" mailing list, one group for junk mail and one for everything
+else, you could do something like this:
+
+ (setq nnmail-split-methods
+       \\='((\"mail.4ad\" \"From:.*4ad\")
+        (\"mail.junk\" \"From:.*Lars\\\\|Subject:.*buy\")
+        (\"mail.misc\" \"\")))
+
+As you can see, this variable is a list of lists, where the first
+element in each \"rule\" is the name of the group (which, by the way,
+does not have to be called anything beginning with \"mail\",
+\"yonka.zow\" is a fine, fine name), and the second is a regexp that
+nnmail will try to match on the header to find a fit.
+
+The second element can also be a function.  In that case, it will be
+called narrowed to the headers with the first element of the rule as
+the argument.  It should return a non-nil value if it thinks that the
+mail belongs in that group.
+
+The last element should always have \"\" as the regexp.
+
+This variable can also have a function as its value, and it can
+also have a fancy split method as its value.  See
+`nnmail-split-fancy' for an explanation of that syntax."
+  :group 'nnmail-split
+  :type '(choice (repeat :tag "Alist" (group (string :tag "Name")
+                                            (choice regexp function)))
+                (function-item nnmail-split-fancy)
+                (function :tag "Other")))
+
+;; Suggested by Erik Selberg <speed@cs.washington.edu>.
+(defcustom nnmail-crosspost t
+  "If non-nil, do crossposting if several split methods match the mail.
+If nil, the first match found will be used."
+  :group 'nnmail-split
+  :type 'boolean)
+
+(defcustom nnmail-split-fancy-with-parent-ignore-groups nil
+  "Regexp that matches group names to be ignored when applying `nnmail-split-fancy-with-parent'.
+This can also be a list of regexps."
+  :version "22.1"
+  :group 'nnmail-split
+  :type '(choice (const :tag "none" nil)
+                (regexp :value ".*")
+                (repeat :value (".*") regexp)))
+
+(defcustom nnmail-cache-ignore-groups nil
+  "Regexp that matches group names to be ignored when inserting message ids into the cache (`nnmail-cache-insert').
+This can also be a list of regexps."
+  :version "22.1"
+  :group 'nnmail-split
+  :type '(choice (const :tag "none" nil)
+                (regexp :value ".*")
+                (repeat :value (".*") regexp)))
+
+;; Added by gord@enci.ucalgary.ca (Gordon Matzigkeit).
+(defcustom nnmail-keep-last-article nil
+  "If non-nil, nnmail will never delete/move a group's last article.
+It can be marked expirable, so it will be deleted when it is no longer last.
+
+You may need to set this variable if other programs are putting
+new mail into folder numbers that Gnus has marked as expired."
+  :group 'nnmail-procmail
+  :group 'nnmail-various
+  :type 'boolean)
+
+(defcustom nnmail-use-long-file-names nil
+  "If non-nil the mail backends will use long file and directory names.
+If nil, groups like \"mail.misc\" will end up in directories like
+\"mail/misc/\"."
+  :group 'nnmail-files
+  :type 'boolean)
+
+(defcustom nnmail-default-file-modes 384
+  "Set the mode bits of all new mail files to this integer."
+  :group 'nnmail-files
+  :type 'integer)
+
+(defcustom nnmail-expiry-wait 7
+  "*Expirable articles that are older than this will be expired.
+This variable can either be a number (which will be interpreted as a
+number of days) -- this doesn't have to be an integer.  This variable
+can also be `immediate' and `never'."
+  :group 'nnmail-expire
+  :type '(choice (const immediate)
+                (number :tag "days")
+                (const never)))
+
+(defcustom nnmail-expiry-wait-function nil
+  "Variable that holds function to specify how old articles should be before they are expired.
+The function will be called with the name of the group that the expiry
+is to be performed in, and it should return an integer that says how
+many days an article can be stored before it is considered \"old\".
+It can also return the values `never' and `immediate'.
+
+E.g.:
+
+\(setq nnmail-expiry-wait-function
+      (lambda (newsgroup)
+       (cond ((string-match \"private\" newsgroup) 31)
+             ((string-match \"junk\" newsgroup) 1)
+             ((string-match \"important\" newsgroup) \\='never)
+             (t 7))))"
+  :group 'nnmail-expire
+  :type '(choice (const :tag "nnmail-expiry-wait" nil)
+                (function :format "%v" nnmail-)))
+
+(defcustom nnmail-expiry-target 'delete
+  "*Variable that says where expired messages should end up.
+The default value is `delete' (which says to delete the messages),
+but it can also be a string or a function.  If it is a string, expired
+messages end up in that group.  If it is a function, the function is
+called in a buffer narrowed to the message in question.  The function
+receives one argument, the name of the group the message comes from.
+The return value should be `delete' or a group name (a string)."
+  :version "21.1"
+  :group 'nnmail-expire
+  :type '(choice (const delete)
+                function
+                string))
+
+(defcustom nnmail-fancy-expiry-targets nil
+  "Determine expiry target based on articles using fancy techniques.
+
+This is a list of (\"HEADER\" \"REGEXP\" \"TARGET\") entries.  If
+`nnmail-expiry-target' is set to the function
+`nnmail-fancy-expiry-target' and HEADER of the article matches REGEXP,
+the message will be expired to a group determined by invoking
+`format-time-string' with TARGET used as the format string and the
+time extracted from the articles' Date header (if missing the current
+time is used).
+
+In the special cases that HEADER is the symbol `to-from', the regexp
+will try to match against both the From and the To header.
+
+Example:
+
+\(setq nnmail-fancy-expiry-targets
+      \\='((to-from \"boss\" \"nnfolder:Work\")
+       (\"Subject\" \"IMPORTANT\" \"nnfolder:IMPORTANT.%Y.%b\")
+       (\"from\" \".*\" \"nnfolder:Archive-%Y\")))
+
+In this case, articles containing the string \"boss\" in the To or the
+From header will be expired to the group \"nnfolder:Work\";
+articles containing the string \"IMPORTANT\" in the Subject header will
+be expired to the group \"nnfolder:IMPORTANT.YYYY.MMM\"; and
+everything else will be expired to \"nnfolder:Archive-YYYY\"."
+  :version "22.1"
+  :group 'nnmail-expire
+  :type '(repeat (list (choice :tag "Match against"
+                              (string :tag "Header")
+                              (const to-from))
+                      regexp
+                      (string :tag "Target group format string"))))
+
+(defcustom nnmail-cache-accepted-message-ids nil
+  "If non-nil, put Message-IDs of Gcc'd articles into the duplicate cache.
+If non-nil, also update the cache when copy or move articles."
+  :group 'nnmail
+  :type 'boolean)
+
+(make-obsolete-variable 'nnmail-spool-file 'mail-sources
+                       "Gnus 5.9 (Emacs 22.1)")
+;; revision 5.29 / p0-85 / Gnus 5.9
+;; Variable removed in No Gnus v0.7
+
+(defcustom nnmail-resplit-incoming nil
+  "*If non-nil, re-split incoming procmail sorted mail."
+  :group 'nnmail-procmail
+  :type 'boolean)
+
+(defcustom nnmail-scan-directory-mail-source-once nil
+  "*If non-nil, scan all incoming procmail sorted mails once.
+It scans low-level sorted spools even when not required."
+  :version "21.1"
+  :group 'nnmail-procmail
+  :type 'boolean)
+
+(defcustom nnmail-delete-file-function 'delete-file
+  "Function called to delete files in some mail backends."
+  :group 'nnmail-files
+  :type 'function)
+
+(defcustom nnmail-crosspost-link-function
+  (if (string-match "windows-nt" (symbol-name system-type))
+      'copy-file
+    'add-name-to-file)
+  "*Function called to create a copy of a file.
+This is `add-name-to-file' by default, which means that crossposts
+will use hard links.  If your file system doesn't allow hard
+links, you could set this variable to `copy-file' instead."
+  :group 'nnmail-files
+  :type '(radio (function-item add-name-to-file)
+               (function-item copy-file)
+               (function :tag "Other")))
+
+(defcustom nnmail-read-incoming-hook
+  (if (eq system-type 'windows-nt)
+      '(nnheader-ms-strip-cr)
+    nil)
+  "*Hook that will be run after the incoming mail has been transferred.
+The incoming mail is moved from the specified spool file (which normally is
+something like \"/usr/spool/mail/$user\") to the user's home
+directory.  This hook is called after the incoming mail box has been
+emptied, and can be used to call any mail box programs you have
+running (\"xwatch\", etc.)
+
+E.g.:
+
+\(add-hook \\='nnmail-read-incoming-hook
+         (lambda ()
+           (call-process \"/local/bin/mailsend\" nil nil nil
+                         \"read\"
+                         ;; The incoming mail box file.
+                         (expand-file-name (user-login-name)
+                                           rmail-spool-directory))))
+
+If you have xwatch running, this will alert it that mail has been
+read.
+
+If you use `display-time', you could use something like this:
+
+\(add-hook \\='nnmail-read-incoming-hook
+         (lambda ()
+           ;; Update the displayed time, since that will clear out
+           ;; the flag that says you have mail.
+           (when (eq (process-status \"display-time\") \\='run)
+             (display-time-filter display-time-process \"\"))))"
+  :group 'nnmail-prepare
+  :type 'hook)
+
+(defcustom nnmail-prepare-incoming-hook nil
+  "Hook called before treating incoming mail.
+The hook is run in a buffer with all the new, incoming mail."
+  :group 'nnmail-prepare
+  :type 'hook)
+
+(defcustom nnmail-prepare-incoming-header-hook nil
+  "Hook called narrowed to the headers of each message.
+This can be used to remove excessive spaces (and stuff like
+that) from the headers before splitting and saving the messages."
+  :group 'nnmail-prepare
+  :type 'hook)
+
+(defcustom nnmail-prepare-incoming-message-hook nil
+  "Hook called narrowed to each message."
+  :group 'nnmail-prepare
+  :type 'hook)
+
+(defcustom nnmail-list-identifiers nil
+  "Regexp that matches list identifiers to be removed.
+This can also be a list of regexps."
+  :group 'nnmail-prepare
+  :type '(choice (const :tag "none" nil)
+                (regexp :value ".*")
+                (repeat :value (".*") regexp)))
+
+(defcustom nnmail-pre-get-new-mail-hook nil
+  "Hook called just before starting to handle new incoming mail."
+  :group 'nnmail-retrieve
+  :type 'hook)
+
+(defcustom nnmail-post-get-new-mail-hook nil
+  "Hook called just after finishing handling new incoming mail."
+  :group 'nnmail-retrieve
+  :type 'hook)
+
+(defcustom nnmail-split-hook nil
+  "Hook called before deciding where to split an article.
+The functions in this hook are free to modify the buffer
+contents in any way they choose -- the buffer contents are
+discarded after running the split process."
+  :group 'nnmail-split
+  :type 'hook)
+
+(defcustom nnmail-spool-hook nil
+  "*A hook called when a new article is spooled."
+  :version "22.1"
+  :group 'nnmail
+  :type 'hook)
+
+(defcustom nnmail-large-newsgroup 50
+  "*The number of articles which indicates a large newsgroup or nil.
+If the number of articles is greater than the value, verbose
+messages will be shown to indicate the current status."
+  :group 'nnmail-various
+  :type '(choice (const :tag "infinite" nil)
+                 (number :tag "count")))
+
+(define-widget 'nnmail-lazy 'default
+  "Base widget for recursive data structures.
+
+This is copy of the `lazy' widget in Emacs 22.1 provided for compatibility."
+  :format "%{%t%}: %v"
+  :convert-widget 'widget-value-convert-widget
+  :value-create (lambda (widget)
+                  (let ((value (widget-get widget :value))
+                        (type (widget-get widget :type)))
+                    (widget-put widget :children
+                                (list (widget-create-child-value
+                                       widget (widget-convert type) value)))))
+  :value-delete 'widget-children-value-delete
+  :value-get (lambda (widget)
+               (widget-value (car (widget-get widget :children))))
+  :value-inline (lambda (widget)
+                  (widget-apply (car (widget-get widget :children))
+                                :value-inline))
+  :default-get (lambda (widget)
+                 (widget-default-get
+                  (widget-convert (widget-get widget :type))))
+  :match (lambda (widget value)
+           (widget-apply (widget-convert (widget-get widget :type))
+                         :match value))
+  :validate (lambda (widget)
+              (widget-apply (car (widget-get widget :children)) :validate)))
+
+(define-widget 'nnmail-split-fancy 'nnmail-lazy
+  "Widget for customizing splits in the variable of the same name."
+  :tag "Split"
+  :type '(menu-choice :value (any ".*value.*" "misc")
+                      :tag "Type"
+                      (string :tag "Destination")
+                      (list :tag "Use first match (|)" :value (|)
+                            (const :format "" |)
+                            (editable-list :inline t nnmail-split-fancy))
+                      (list :tag "Use all matches (&)" :value (&)
+                            (const :format "" &)
+                            (editable-list :inline t nnmail-split-fancy))
+                      (list :tag "Function with fixed arguments (:)"
+                            :value (:)
+                            (const :format "" :value :)
+                            function
+                            (editable-list :inline t (sexp :tag "Arg"))
+                            )
+                      (list :tag "Function with split arguments (!)"
+                            :value (!)
+                            (const :format "" !)
+                            function
+                            (editable-list :inline t nnmail-split-fancy))
+                      (list :tag "Field match"
+                            (choice :tag "Field"
+                                    regexp symbol)
+                            (choice :tag "Match"
+                                    regexp
+                                    (symbol :value mail))
+                            (repeat :inline t
+                                    :tag "Restrictions"
+                                    (group :inline t
+                                           (const :format "" -)
+                                           regexp))
+                            nnmail-split-fancy)
+                      (const :tag "Junk (delete mail)" junk)))
+
+(defcustom nnmail-split-fancy "mail.misc"
+  "Incoming mail can be split according to this fancy variable.
+To enable this, set `nnmail-split-methods' to `nnmail-split-fancy'.
+
+The format of this variable is SPLIT, where SPLIT can be one of
+the following:
+
+GROUP: Mail will be stored in GROUP (a string).
+
+\(FIELD VALUE [- RESTRICT [- RESTRICT [...]]] SPLIT): If the message
+  field FIELD (a regexp) contains VALUE (a regexp), store the messages
+  as specified by SPLIT.  If RESTRICT (a regexp) matches some string
+  after FIELD and before the end of the matched VALUE, return nil,
+  otherwise process SPLIT.  Multiple RESTRICTs add up, further
+  restricting the possibility of processing SPLIT.
+
+\(| SPLIT...): Process each SPLIT expression until one of them matches.
+  A SPLIT expression is said to match if it will cause the mail
+  message to be stored in one or more groups.
+
+\(& SPLIT...): Process each SPLIT expression.
+
+\(: FUNCTION optional args): Call FUNCTION with the optional args, in
+  the buffer containing the message headers.  The return value FUNCTION
+  should be a split, which is then recursively processed.
+
+\(! FUNCTION SPLIT): Call FUNCTION with the result of SPLIT.  The
+  return value FUNCTION should be a split, which is then recursively
+  processed.
+
+junk: Mail will be deleted.  Use with care!  Do not submerge in water!
+  Example:
+  (setq nnmail-split-fancy
+       \\='(| (\"Subject\" \"MAKE MONEY FAST\" junk)
+           ...other.rules.omitted...))
+
+FIELD must match a complete field name.  VALUE must match a complete
+word according to the `nnmail-split-fancy-syntax-table' syntax table.
+You can use \".*\" in the regexps to match partial field names or words.
+
+FIELD and VALUE can also be Lisp symbols, in that case they are expanded
+as specified in `nnmail-split-abbrev-alist'.
+
+GROUP can contain \\& and \\N which will substitute from matching
+\\(\\) patterns in the previous VALUE.
+
+Example:
+
+\(setq nnmail-split-methods \\='nnmail-split-fancy
+      nnmail-split-fancy
+      ;; Messages from the mailer daemon are not crossposted to any of
+      ;; the ordinary groups.  Warnings are put in a separate group
+      ;; from real errors.
+      \\='(| (\"from\" mail (| (\"subject\" \"warn.*\" \"mail.warning\")
+                         \"mail.misc\"))
+         ;; Non-error messages are crossposted to all relevant
+         ;; groups, but we don't crosspost between the group for the
+         ;; (ding) list and the group for other (ding) related mail.
+         (& (| (any \"ding@ifi\\\\.uio\\\\.no\" \"ding.list\")
+               (\"subject\" \"ding\" \"ding.misc\"))
+            ;; Other mailing lists...
+            (any \"procmail@informatik\\\\.rwth-aachen\\\\.de\" \"procmail.list\")
+            (any \"SmartList@informatik\\\\.rwth-aachen\\\\.de\" \"SmartList.list\")
+            ;; Both lists below have the same suffix, so prevent
+            ;; cross-posting to mkpkg.list of messages posted only to
+            ;; the bugs- list, but allow cross-posting when the
+            ;; message was really cross-posted.
+            (any \"bugs-mypackage@somewhere\" \"mypkg.bugs\")
+            (any \"mypackage@somewhere\" - \"bugs-mypackage\" \"mypkg.list\")
+            ;;
+            ;; People...
+            (any \"larsi@ifi\\\\.uio\\\\.no\" \"people.Lars Magne Ingebrigtsen\"))
+         ;; Unmatched mail goes to the catch all group.
+         \"misc.misc\"))"
+  :group 'nnmail-split
+  :type 'nnmail-split-fancy)
+
+(defcustom nnmail-split-abbrev-alist
+  '((any . "from\\|to\\|cc\\|sender\\|apparently-to\\|resent-from\\|resent-to\\|resent-cc")
+    (mail . "mailer-daemon\\|postmaster\\|uucp")
+    (to . "to\\|cc\\|apparently-to\\|resent-to\\|resent-cc")
+    (from . "from\\|sender\\|resent-from")
+    (nato . "to\\|cc\\|resent-to\\|resent-cc")
+    (naany . "from\\|to\\|cc\\|sender\\|resent-from\\|resent-to\\|resent-cc"))
+  "*Alist of abbreviations allowed in `nnmail-split-fancy'."
+  :group 'nnmail-split
+  :type '(repeat (cons :format "%v" symbol regexp)))
+
+(defcustom nnmail-message-id-cache-length 1000
+  "*The approximate number of Message-IDs nnmail will keep in its cache.
+If this variable is nil, no checking on duplicate messages will be
+performed."
+  :group 'nnmail-duplicate
+  :type '(choice (const :tag "disable" nil)
+                (integer :format "%v")))
+
+(defcustom nnmail-message-id-cache-file
+  (nnheader-concat gnus-home-directory ".nnmail-cache")
+  "The file name of the nnmail Message-ID cache."
+  :group 'nnmail-duplicate
+  :group 'nnmail-files
+  :type 'file)
+
+(defcustom nnmail-treat-duplicates 'warn
+  "*If non-nil, nnmail keep a cache of Message-IDs to discover mail duplicates.
+Three values are valid: nil, which means that nnmail is not to keep a
+Message-ID cache; `warn', which means that nnmail should insert extra
+headers to warn the user about the duplication (this is the default);
+and `delete', which means that nnmail will delete duplicated mails.
+
+This variable can also be a function.  It will be called from a buffer
+narrowed to the article in question with the Message-ID as a
+parameter.  It should return nil, `warn' or `delete'."
+  :group 'nnmail-duplicate
+  :type '(choice (const :tag "off" nil)
+                (const warn)
+                (const delete)))
+
+(defcustom nnmail-extra-headers '(To Newsgroups Cc)
+  "Extra headers to parse.
+In addition to the standard headers, these extra headers will be
+included in NOV headers (and the like) when backends parse headers."
+  :version "24.3"
+  :group 'nnmail
+  :type '(repeat symbol))
+
+(defcustom nnmail-split-header-length-limit 2048
+  "Header lines longer than this limit are excluded from the split function."
+  :version "21.1"
+  :group 'nnmail
+  :type 'integer)
+
+(defcustom nnmail-mail-splitting-charset nil
+  "Default charset to be used when splitting incoming mail."
+  :version "22.1"
+  :group 'nnmail
+  :type 'symbol)
+
+(defcustom nnmail-mail-splitting-decodes nil
+  "Whether the nnmail splitting functionality should MIME decode headers."
+  :version "22.1"
+  :group 'nnmail
+  :type 'boolean)
+
+(defcustom nnmail-split-fancy-match-partial-words nil
+  "Whether to match partial words when fancy splitting.
+Normally, regexes given in `nnmail-split-fancy' are implicitly surrounded
+by \"\\=\\<...\\>\".  If this variable is true, they are not implicitly\
+ surrounded
+by anything."
+  :version "22.1"
+  :group 'nnmail
+  :type 'boolean)
+
+(defcustom nnmail-split-lowercase-expanded t
+  "Whether to lowercase expanded entries (i.e. \\N) when splitting mails.
+This avoids the creation of multiple groups when users send to an address
+using different case (i.e. mailing-list@domain vs Mailing-List@Domain)."
+  :version "22.1"
+  :group 'nnmail
+  :type 'boolean)
+
+;;; Internal variables.
+
+(defvar nnmail-article-buffer " *nnmail incoming*"
+  "The buffer used for splitting incoming mails.")
+
+(defvar nnmail-split-history nil
+  "List of group/article elements that say where the previous split put messages.")
+
+(defvar nnmail-split-fancy-syntax-table
+  (let ((table (make-syntax-table)))
+    ;; support the %-hack
+    (modify-syntax-entry ?\% "." table)
+    table)
+  "Syntax table used by `nnmail-split-fancy'.")
+
+(defvar nnmail-prepare-save-mail-hook nil
+  "Hook called before saving mail.")
+
+(defvar nnmail-split-tracing nil)
+(defvar nnmail-split-trace nil)
+(defvar nnmail-inhibit-default-split-group nil)
+
+\f
+
+(defun nnmail-request-post (&optional server)
+  (mail-send-and-exit nil))
+
+(defvar nnmail-file-coding-system 'raw-text
+  "Coding system used in nnmail.")
+
+(defvar nnmail-incoming-coding-system
+  mm-text-coding-system
+  "Coding system used in reading inbox")
+
+(defvar nnmail-pathname-coding-system
+  ;; This causes Emacs 22.2 and 22.3 to issue a useless warning.
+  ;;(if (and (featurep 'xemacs) (featurep 'file-coding))
+  (if (featurep 'xemacs)
+      (if (featurep 'file-coding)
+         ;; Work around a bug in many XEmacs 21.5 betas.
+         ;; Cf. http://thread.gmane.org/gmane.emacs.gnus.general/68134
+         (setq file-name-coding-system (coding-system-aliasee 'file-name))))
+  "*Coding system for file name.")
+
+(defun nnmail-find-file (file)
+  "Insert FILE in server buffer safely."
+  (set-buffer nntp-server-buffer)
+  (delete-region (point-min) (point-max))
+  (let ((format-alist nil)
+       (after-insert-file-functions nil))
+    (condition-case ()
+       (let ((coding-system-for-read nnmail-file-coding-system)
+             (auto-mode-alist (mm-auto-mode-alist))
+             (file-name-coding-system nnmail-pathname-coding-system))
+         (insert-file-contents file)
+         t)
+      (file-error nil))))
+
+(defun nnmail-group-pathname (group dir &optional file)
+  "Make file name for GROUP."
+  (concat
+   (let ((dir (file-name-as-directory (expand-file-name dir))))
+     (setq group (nnheader-replace-duplicate-chars-in-string
+                 (nnheader-replace-chars-in-string group ?/ ?_)
+                 ?. ?_))
+     (setq group (nnheader-translate-file-chars group))
+     ;; If this directory exists, we use it directly.
+     (file-name-as-directory
+      (if (or nnmail-use-long-file-names
+             (file-directory-p (concat dir group)))
+         (expand-file-name group dir)
+       ;; If not, we translate dots into slashes.
+       (expand-file-name
+        (nnheader-replace-chars-in-string group ?. ?/)
+        dir))))
+   (or file "")))
+
+(defun nnmail-get-active ()
+  "Returns an assoc of group names and active ranges.
+nn*-request-list should have been called before calling this function."
+  ;; Go through all groups from the active list.
+  (with-current-buffer nntp-server-buffer
+    (nnmail-parse-active)))
+
+(defun nnmail-parse-active ()
+  "Parse the active file in the current buffer and return an alist."
+  (goto-char (point-min))
+  (unless (re-search-forward "[\\\"]" nil t)
+    (goto-char (point-max))
+    (while (re-search-backward "[][';?()#]" nil t)
+      (insert ?\\)))
+  (goto-char (point-min))
+  (let ((buffer (current-buffer))
+       group-assoc group max min)
+    (while (not (eobp))
+      (condition-case err
+         (progn
+           (narrow-to-region (point) (point-at-eol))
+           (setq group (read buffer))
+           (unless (stringp group)
+             (setq group (symbol-name group)))
+           (if (and (numberp (setq max (read buffer)))
+                    (numberp (setq min (read buffer))))
+               (push (list (mm-string-as-unibyte group) (cons min max))
+                     group-assoc)))
+       (error nil))
+      (widen)
+      (forward-line 1))
+    group-assoc))
+
+(defvar nnmail-active-file-coding-system 'raw-text
+  "*Coding system for active file.")
+
+(defun nnmail-save-active (group-assoc file-name)
+  "Save GROUP-ASSOC in ACTIVE-FILE."
+  (let ((coding-system-for-write nnmail-active-file-coding-system))
+    (when file-name
+      (with-temp-file file-name
+       (mm-disable-multibyte)
+       (nnmail-generate-active group-assoc)))))
+
+(defun nnmail-generate-active (alist)
+  "Generate an active file from group-alist ALIST."
+  (erase-buffer)
+  (let (group)
+    (while (setq group (pop alist))
+      (insert (format "%S %d %d y\n" (intern (car group)) (cdadr group)
+                     (caadr group))))
+    (goto-char (point-max))
+    (while (search-backward "\\." nil t)
+      (delete-char 1))))
+
+(defun nnmail-get-split-group (file source)
+  "Find out whether this FILE is to be split into GROUP only.
+If SOURCE is a directory spec, try to return the group name component."
+  (if (eq (car source) 'directory)
+      (let ((file (file-name-nondirectory file)))
+       (mail-source-bind (directory source)
+         (if (string-match (concat (regexp-quote suffix) "$") file)
+             (substring file 0 (match-beginning 0))
+           nil)))
+    nil))
+
+(defun nnmail-process-babyl-mail-format (func artnum-func)
+  (let ((case-fold-search t)
+       (count 0)
+       start message-id content-length do-search end)
+    (while (not (eobp))
+      (goto-char (point-min))
+      (re-search-forward
+       "\f\n0, *unseen,+\n\\(\\*\\*\\* EOOH \\*\\*\\*\n\\)?" nil t)
+      (goto-char (match-end 0))
+      (delete-region (match-beginning 0) (match-end 0))
+      (narrow-to-region
+       (setq start (point))
+       (progn
+        ;; Skip all the headers in case there are more "From "s...
+        (or (search-forward "\n\n" nil t)
+            (search-forward-regexp "^[^:]*\\( .*\\|\\)$" nil t)
+            (search-forward "\1f\f"))
+        (point)))
+      ;; Unquote the ">From " line, if any.
+      (goto-char (point-min))
+      (when (looking-at ">From ")
+       (replace-match "X-From-Line: ") )
+      (run-hooks 'nnmail-prepare-incoming-header-hook)
+      (goto-char (point-max))
+      ;; Find the Message-ID header.
+      (save-excursion
+       (if (re-search-backward
+            "^Message-ID[ \t]*:[ \n\t]*\\(<[^>]*>\\)" nil t)
+           (setq message-id (buffer-substring (match-beginning 1)
+                                              (match-end 1)))
+         ;; There is no Message-ID here, so we create one.
+         (save-excursion
+           (when (re-search-backward "^Message-ID[ \t]*:" nil t)
+             (beginning-of-line)
+             (insert "Original-")))
+         (forward-line -1)
+         (insert "Message-ID: " (setq message-id (nnmail-message-id))
+                 "\n")))
+      ;; Look for a Content-Length header.
+      (if (not (save-excursion
+                (and (re-search-backward
+                      "^Content-Length:[ \t]*\\([0-9]+\\)" start t)
+                     (setq content-length (string-to-number
+                                           (buffer-substring
+                                            (match-beginning 1)
+                                            (match-end 1))))
+                     ;; We destroy the header, since none of
+                     ;; the backends ever use it, and we do not
+                     ;; want to confuse other mailers by having
+                     ;; a (possibly) faulty header.
+                     (progn (insert "X-") t))))
+         (setq do-search t)
+       (widen)
+       (if (or (= (+ (point) content-length) (point-max))
+               (save-excursion
+                 (goto-char (+ (point) content-length))
+                 (looking-at "\1f")))
+           (progn
+             (goto-char (+ (point) content-length))
+             (setq do-search nil))
+         (setq do-search t)))
+      (widen)
+      ;; Go to the beginning of the next article - or to the end
+      ;; of the buffer.
+      (when do-search
+       (if (re-search-forward "^\1f" nil t)
+           (goto-char (match-beginning 0))
+         (goto-char (1- (point-max)))))
+      (delete-char 1)                  ; delete ^_
+      (save-excursion
+       (save-restriction
+         (narrow-to-region start (point))
+         (goto-char (point-min))
+         (nnmail-check-duplication message-id func artnum-func)
+         (incf count)
+         (setq end (point-max))))
+      (goto-char end))
+    count))
+
+(defsubst nnmail-search-unix-mail-delim ()
+  "Put point at the beginning of the next Unix mbox message."
+  ;; Algorithm used to find the next article in the
+  ;; brain-dead Unix mbox format:
+  ;;
+  ;; 1) Search for "^From ".
+  ;; 2) If we find it, then see whether the previous
+  ;;    line is blank and the next line looks like a header.
+  ;; Then it's possible that this is a mail delim, and we use it.
+  (let ((case-fold-search nil)
+       found)
+    (while (not found)
+      (if (not (re-search-forward "^From " nil t))
+         (setq found 'no)
+       (save-excursion
+         (beginning-of-line)
+         (when (and (or (bobp)
+                        (save-excursion
+                          (forward-line -1)
+                          (eq (char-after) ?\n)))
+                    (save-excursion
+                      (forward-line 1)
+                      (while (looking-at ">From \\|From ")
+                        (forward-line 1))
+                      (looking-at "[^ \n\t:]+[ \n\t]*:")))
+           (setq found 'yes)))))
+    (beginning-of-line)
+    (eq found 'yes)))
+
+(defun nnmail-search-unix-mail-delim-backward ()
+  "Put point at the beginning of the current Unix mbox message."
+  ;; Algorithm used to find the next article in the
+  ;; brain-dead Unix mbox format:
+  ;;
+  ;; 1) Search for "^From ".
+  ;; 2) If we find it, then see whether the previous
+  ;;    line is blank and the next line looks like a header.
+  ;; Then it's possible that this is a mail delim, and we use it.
+  (let ((case-fold-search nil)
+       found)
+    (while (not found)
+      (if (not (re-search-backward "^From " nil t))
+         (setq found 'no)
+       (save-excursion
+         (beginning-of-line)
+         (when (and (or (bobp)
+                        (save-excursion
+                          (forward-line -1)
+                          (eq (char-after) ?\n)))
+                    (save-excursion
+                      (forward-line 1)
+                      (while (looking-at ">From \\|From ")
+                        (forward-line 1))
+                      (looking-at "[^ \n\t:]+[ \n\t]*:")))
+           (setq found 'yes)))))
+    (beginning-of-line)
+    (eq found 'yes)))
+
+(defun nnmail-process-unix-mail-format (func artnum-func)
+  (let ((case-fold-search t)
+       (count 0)
+       start message-id content-length end skip head-end)
+    (goto-char (point-min))
+    (if (not (and (re-search-forward "^From " nil t)
+                 (goto-char (match-beginning 0))))
+       ;; Possibly wrong format?
+       (error "Error, unknown mail format! (Possibly corrupted %s `%s'.)"
+              (if (buffer-file-name) "file" "buffer")
+              (or (buffer-file-name) (buffer-name)))
+      ;; Carry on until the bitter end.
+      (while (not (eobp))
+       (setq start (point)
+             end nil)
+       ;; Find the end of the head.
+       (narrow-to-region
+        start
+        (if (search-forward "\n\n" nil t)
+            (1- (point))
+          ;; This will never happen, but just to be on the safe side --
+          ;; if there is no head-body delimiter, we search a bit manually.
+          (while (and (looking-at "From \\|[^ \t]+:")
+                      (not (eobp)))
+            (forward-line 1))
+          (point)))
+       ;; Find the Message-ID header.
+       (goto-char (point-min))
+       (if (re-search-forward "^Message-ID[ \t]*:[ \n\t]*\\(<[^>]+>\\)" nil t)
+           (setq message-id (match-string 1))
+         (save-excursion
+           (when (re-search-forward "^Message-ID[ \t]*:" nil t)
+             (beginning-of-line)
+             (insert "Original-")))
+         ;; There is no Message-ID here, so we create one.
+         (forward-line 1)
+         (insert "Message-ID: " (setq message-id (nnmail-message-id)) "\n"))
+       ;; Look for a Content-Length header.
+       (goto-char (point-min))
+       (if (not (re-search-forward
+                 "^Content-Length:[ \t]*\\([0-9]+\\)" nil t))
+           (setq content-length nil)
+         (setq content-length (string-to-number (match-string 1)))
+         ;; We destroy the header, since none of the backends ever
+         ;; use it, and we do not want to confuse other mailers by
+         ;; having a (possibly) faulty header.
+         (beginning-of-line)
+         (insert "X-"))
+       (run-hooks 'nnmail-prepare-incoming-header-hook)
+       ;; Find the end of this article.
+       (goto-char (point-max))
+       (widen)
+       (setq head-end (point))
+       ;; We try the Content-Length value.  The idea: skip over the header
+       ;; separator, then check what happens content-length bytes into the
+       ;; message body.  This should be either the end of the buffer, the
+       ;; message separator or a blank line followed by the separator.
+       ;; The blank line should probably be deleted.  If neither of the
+       ;; three is met, the content-length header is probably invalid.
+       (when content-length
+         (forward-line 1)
+         (setq skip (+ (point) content-length))
+         (goto-char skip)
+         (cond ((or (= skip (point-max))
+                    (= (1+ skip) (point-max)))
+                (setq end (point-max)))
+               ((looking-at "From ")
+                (setq end skip))
+               ((looking-at "[ \t]*\n\\(From \\)")
+                (setq end (match-beginning 1)))
+               (t (setq end nil))))
+       (if end
+           (goto-char end)
+         ;; No Content-Length, so we find the beginning of the next
+         ;; article or the end of the buffer.
+         (goto-char head-end)
+         (or (nnmail-search-unix-mail-delim)
+             (goto-char (point-max))))
+       ;; Allow the backend to save the article.
+       (save-excursion
+         (save-restriction
+           (narrow-to-region start (point))
+           (goto-char (point-min))
+           (incf count)
+           (nnmail-check-duplication message-id func artnum-func)
+           (setq end (point-max))))
+       (goto-char end)))
+    count))
+
+(defun nnmail-process-mmdf-mail-format (func artnum-func &optional junk-func)
+  (let ((delim "^\^A\^A\^A\^A$")
+       (case-fold-search t)
+       (count 0)
+       start message-id end)
+    (goto-char (point-min))
+    (if (not (and (re-search-forward delim nil t)
+                 (forward-line 1)))
+       ;; Possibly wrong format?
+       (error "Error, unknown mail format! (Possibly corrupted.)")
+      ;; Carry on until the bitter end.
+      (while (not (eobp))
+       (setq start (point))
+       ;; Find the end of the head.
+       (narrow-to-region
+        start
+        (if (search-forward "\n\n" nil t)
+            (1- (point))
+          ;; This will never happen, but just to be on the safe side --
+          ;; if there is no head-body delimiter, we search a bit manually.
+          (while (and (looking-at "From \\|[^ \t]+:")
+                      (not (eobp)))
+            (forward-line 1))
+          (point)))
+       ;; Find the Message-ID header.
+       (goto-char (point-min))
+       (if (re-search-forward "^Message-ID[ \t]*:[ \n\t]*\\(<[^>]+>\\)" nil t)
+           (setq message-id (match-string 1))
+         ;; There is no Message-ID here, so we create one.
+         (save-excursion
+           (when (re-search-backward "^Message-ID[ \t]*:" nil t)
+             (beginning-of-line)
+             (insert "Original-")))
+         (forward-line 1)
+         (insert "Message-ID: " (setq message-id (nnmail-message-id)) "\n"))
+       (run-hooks 'nnmail-prepare-incoming-header-hook)
+       ;; Find the end of this article.
+       (goto-char (point-max))
+       (widen)
+       (if (re-search-forward delim nil t)
+           (beginning-of-line)
+         (goto-char (point-max)))
+       ;; Allow the backend to save the article.
+       (save-excursion
+         (save-restriction
+           (narrow-to-region start (point))
+           (goto-char (point-min))
+           (incf count)
+           (nnmail-check-duplication message-id func artnum-func junk-func)
+           (setq end (point-max))))
+       (goto-char end)
+       (forward-line 2)))
+    count))
+
+(defun nnmail-process-maildir-mail-format (func artnum-func)
+  ;; In a maildir, every file contains exactly one mail.
+  (let ((case-fold-search t)
+       message-id)
+    (goto-char (point-min))
+    ;; Find the end of the head.
+    (narrow-to-region
+     (point-min)
+     (if (search-forward "\n\n" nil t)
+        (1- (point))
+       ;; This will never happen, but just to be on the safe side --
+       ;; if there is no head-body delimiter, we search a bit manually.
+       (while (and (looking-at "From \\|[^ \t]+:")
+                  (not (eobp)))
+        (forward-line 1))
+       (point)))
+    ;; Find the Message-ID header.
+    (goto-char (point-min))
+    (if (re-search-forward "^Message-ID:[ \t]*\\(<[^>]+>\\)" nil t)
+       (setq message-id (match-string 1))
+      ;; There is no Message-ID here, so we create one.
+      (save-excursion
+       (when (re-search-backward "^Message-ID[ \t]*:" nil t)
+         (beginning-of-line)
+         (insert "Original-")))
+      (forward-line 1)
+      (insert "Message-ID: " (setq message-id (nnmail-message-id)) "\n"))
+    (run-hooks 'nnmail-prepare-incoming-header-hook)
+    ;; Allow the backend to save the article.
+    (widen)
+    (save-excursion
+      (goto-char (point-min))
+      (nnmail-check-duplication message-id func artnum-func))
+    1))
+
+(defvar nnmail-group-names-not-encoded-p nil
+  "Non-nil means group names are not encoded.")
+
+(defun nnmail-split-incoming (incoming func &optional exit-func
+                                      group artnum-func junk-func)
+  "Go through the entire INCOMING file and pick out each individual mail.
+FUNC will be called with the buffer narrowed to each mail.
+INCOMING can also be a buffer object.  In that case, the mail
+will be copied over from that buffer."
+  (let ( ;; If this is a group-specific split, we bind the split
+       ;; methods to just this group.
+       (nnmail-split-methods (if (and group
+                                      (not nnmail-resplit-incoming))
+                                 (list (list group ""))
+                               nnmail-split-methods))
+       (nnmail-group-names-not-encoded-p t))
+    ;; Insert the incoming file.
+    (with-current-buffer (get-buffer-create nnmail-article-buffer)
+      (erase-buffer)
+      (if (bufferp incoming)
+         (insert-buffer-substring incoming)
+       (let ((coding-system-for-read nnmail-incoming-coding-system))
+         (mm-insert-file-contents incoming)))
+      (prog1
+         (if (zerop (buffer-size))
+             0
+           (goto-char (point-min))
+           (save-excursion (run-hooks 'nnmail-prepare-incoming-hook))
+           ;; Handle both babyl, MMDF and unix mail formats, since
+           ;; movemail will use the former when fetching from a
+           ;; mailbox, the latter when fetching from a file.
+           (cond ((or (looking-at "\^L")
+                      (looking-at "BABYL OPTIONS:"))
+                  (nnmail-process-babyl-mail-format func artnum-func))
+                 ((looking-at "\^A\^A\^A\^A")
+                  (nnmail-process-mmdf-mail-format
+                   func artnum-func junk-func))
+                 ((looking-at "Return-Path:")
+                  (nnmail-process-maildir-mail-format func artnum-func))
+                 (t
+                  (nnmail-process-unix-mail-format func artnum-func))))
+       (when exit-func
+         (funcall exit-func))
+       (kill-buffer (current-buffer))))))
+
+(defun nnmail-article-group (func &optional trace junk-func)
+  "Look at the headers and return an alist of groups that match.
+FUNC will be called with the group name to determine the article number."
+  (let ((methods (or nnmail-split-methods '(("bogus" ""))))
+       (obuf (current-buffer))
+       group-art method grp)
+    (if (and (sequencep methods)
+            (= (length methods) 1)
+            (not nnmail-inhibit-default-split-group))
+       ;; If there is only just one group to put everything in, we
+       ;; just return a list with just this one method in.
+       (setq group-art
+             (list (cons (caar methods) (funcall func (caar methods)))))
+      ;; We do actual comparison.
+      ;; Copy the article into the work buffer.
+      (with-current-buffer nntp-server-buffer
+       (erase-buffer)
+       (insert-buffer-substring obuf)
+       ;; Narrow to headers.
+       (narrow-to-region
+        (goto-char (point-min))
+        (if (search-forward "\n\n" nil t)
+            (point)
+          (point-max)))
+       (goto-char (point-min))
+       ;; Decode MIME headers and charsets.
+       (when nnmail-mail-splitting-decodes
+         (let ((mail-parse-charset nnmail-mail-splitting-charset))
+           (mail-decode-encoded-word-region (point-min) (point-max))))
+       ;; Fold continuation lines.
+       (goto-char (point-min))
+       (while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t)
+         (replace-match " " t t))
+       ;; Nuke pathologically long headers.  Since Gnus applies
+       ;; pathologically complex regexps to the buffer, lines
+       ;; that are looong will take longer than the Universe's
+       ;; existence to process.
+       (goto-char (point-min))
+       (while (not (eobp))
+         (unless (< (move-to-column nnmail-split-header-length-limit)
+                    nnmail-split-header-length-limit)
+           (delete-region (point) (point-at-eol)))
+         (forward-line 1))
+       ;; Allow washing.
+       (goto-char (point-min))
+       (run-hooks 'nnmail-split-hook)
+       (when (setq nnmail-split-tracing trace)
+         (setq nnmail-split-trace nil))
+       (if (or (and (symbolp nnmail-split-methods)
+                    (fboundp nnmail-split-methods))
+               (not (consp (car-safe nnmail-split-methods)))
+               (and (listp nnmail-split-methods)
+                    ;; Not a regular split method, so it has to be a
+                    ;; fancy one.
+                    (not (let ((top-element (car-safe nnmail-split-methods)))
+                           (and (= 2 (length top-element))
+                                (stringp (nth 0 top-element))
+                                (stringp (nth 1 top-element)))))))
+           (let* ((method-function
+                   (if (and (symbolp nnmail-split-methods)
+                            (fboundp nnmail-split-methods))
+                       nnmail-split-methods
+                     'nnmail-split-fancy))
+                  (split
+                   (condition-case error-info
+                       ;; `nnmail-split-methods' is a function, so we
+                       ;; just call this function here and use the
+                       ;; result.
+                       (or (funcall method-function)
+                           (and (not nnmail-inhibit-default-split-group)
+                                '("bogus")))
+                     (error
+                      (nnheader-message
+                       5 "Error in `nnmail-split-methods'; using `bogus' mail group: %S" error-info)
+                      (sit-for 1)
+                      '("bogus")))))
+             (setq split (mm-delete-duplicates split))
+             ;; The article may be "cross-posted" to `junk'.  What
+             ;; to do?  Just remove the `junk' spec.  Don't really
+             ;; see anything else to do...
+             (when (and (memq 'junk split)
+                        junk-func)
+               (funcall junk-func 'junk))
+             (setq split (delq 'junk split))
+             (when split
+               (setq group-art
+                     (mapcar
+                      (lambda (group) (cons group (funcall func group)))
+                      split))))
+         ;; Go through the split methods to find a match.
+         (while (and methods
+                     (or nnmail-crosspost
+                         (not group-art)))
+           (goto-char (point-max))
+           (setq method (pop methods)
+                 grp (car method))
+           (if (or methods
+                   (not (equal "" (nth 1 method))))
+               (when (and
+                      (ignore-errors
+                        (if (stringp (nth 1 method))
+                            (let ((expand (string-match "\\\\[0-9&]" grp))
+                                  (pos (re-search-backward (cadr method)
+                                                           nil t)))
+                              (and expand
+                                   (setq grp (nnmail-expand-newtext grp)))
+                              pos)
+                          ;; Function to say whether this is a match.
+                          (funcall (nth 1 method) grp)))
+                      ;; Don't enter the article into the same
+                      ;; group twice.
+                      (not (assoc grp group-art)))
+                 (push (cons grp (funcall func grp))
+                       group-art))
+             ;; This is the final group, which is used as a
+             ;; catch-all.
+             (when (and (not group-art)
+                        (or (equal "" (nth 1 method))
+                            (not nnmail-inhibit-default-split-group)))
+               (setq group-art
+                     (list (cons (car method)
+                                 (funcall func (car method))))))))
+         ;; Fall back on "bogus" if all else fails.
+         (when (and (not group-art)
+                    (not nnmail-inhibit-default-split-group))
+           (setq group-art (list (cons "bogus" (funcall func "bogus"))))))
+       ;; Produce a trace if non-empty.
+       (when (and trace nnmail-split-trace)
+         (let ((restore (current-buffer)))
+           (nnheader-set-temp-buffer "*Split Trace*")
+           (gnus-add-buffer)
+           (dolist (trace (nreverse nnmail-split-trace))
+             (prin1 trace (current-buffer))
+             (insert "\n"))
+           (goto-char (point-min))
+           (gnus-configure-windows 'split-trace)
+           (set-buffer restore)))
+       (widen)
+       ;; See whether the split methods returned `junk'.
+       (if (equal group-art '(junk))
+           nil
+         ;; The article may be "cross-posted" to `junk'.  What
+         ;; to do?  Just remove the `junk' spec.  Don't really
+         ;; see anything else to do...
+         (let (elem)
+           (while (setq elem (car (memq 'junk group-art)))
+             (setq group-art (delq elem group-art)))
+           (nreverse group-art)))))))
+
+(defun nnmail-insert-lines ()
+  "Insert how many lines there are in the body of the mail.
+Return the number of characters in the body."
+  (let (lines chars)
+    (save-excursion
+      (goto-char (point-min))
+      (unless (search-forward "\n\n" nil t)
+       (goto-char (point-max))
+       (insert "\n"))
+      (setq chars (- (point-max) (point)))
+      (setq lines (count-lines (point) (point-max)))
+      (forward-char -1)
+      (save-excursion
+       (when (re-search-backward "^Lines: " nil t)
+         (delete-region (point) (progn (forward-line 1) (point)))))
+      (beginning-of-line)
+      (insert (format "Lines: %d\n" (max lines 0)))
+      chars)))
+
+(defun nnmail-insert-xref (group-alist)
+  "Insert an Xref line based on the (group . article) alist."
+  (save-excursion
+    (goto-char (point-min))
+    (unless (search-forward "\n\n" nil t)
+      (goto-char (point-max))
+      (insert "\n"))
+    (forward-char -1)
+    (when (re-search-backward "^Xref: " nil t)
+      (delete-region (match-beginning 0)
+                    (progn (forward-line 1) (point))))
+    (insert (format "Xref: %s" (system-name)))
+    (while group-alist
+      (insert (if (mm-multibyte-p)
+                 (mm-string-as-multibyte
+                  (format " %s:%d" (caar group-alist) (cdar group-alist)))
+               (mm-string-as-unibyte
+                (format " %s:%d" (caar group-alist) (cdar group-alist)))))
+      (setq group-alist (cdr group-alist)))
+    (insert "\n")))
+
+;;; Message washing functions
+
+(defun nnmail-remove-leading-whitespace ()
+  "Remove excessive whitespace from all headers."
+  (goto-char (point-min))
+  (while (re-search-forward "^\\([^ :]+: \\) +" nil t)
+    (replace-match "\\1" t)))
+
+(defun nnmail-remove-list-identifiers ()
+  "Remove list identifiers from Subject headers."
+  (let ((regexp
+        (if (consp nnmail-list-identifiers)
+            (mapconcat 'identity nnmail-list-identifiers " *\\|")
+          nnmail-list-identifiers)))
+    (when regexp
+      (goto-char (point-min))
+      (while (re-search-forward
+             (concat "^Subject: +\\(R[Ee]: +\\)*\\(" regexp " *\\)")
+             nil t)
+       (delete-region (match-beginning 2) (match-end 0))
+       (beginning-of-line))
+      (when (re-search-forward "^Subject: +\\(\\(R[Ee]: +\\)+\\)R[Ee]: +"
+                              nil t)
+       (delete-region (match-beginning 1) (match-end 1))
+       (beginning-of-line)))))
+
+(defun nnmail-remove-tabs ()
+  "Translate TAB characters into SPACE characters."
+  (subst-char-in-region (point-min) (point-max) ?\t ?  t))
+
+(defcustom nnmail-broken-references-mailers
+  "^X-Mailer:.*\\(Eudora\\|Pegasus\\)"
+  "Header line matching mailer producing bogus References lines.
+See `nnmail-ignore-broken-references'."
+  :group 'nnmail-prepare
+  :version "23.1" ;; No Gnus
+  :type 'regexp)
+
+(defun nnmail-ignore-broken-references ()
+  "Ignore the References line and use In-Reply-To
+
+Eudora has a broken References line, but an OK In-Reply-To."
+  (goto-char (point-min))
+  (when (re-search-forward nnmail-broken-references-mailers nil t)
+    (goto-char (point-min))
+    (when (re-search-forward "^References:" nil t)
+      (beginning-of-line)
+      (insert "X-Gnus-Broken-Eudora-"))
+    (goto-char (point-min))
+    (when (re-search-forward "^\\(In-Reply-To:[^\n]+\\)\n[ \t]+" nil t)
+      (replace-match "\\1" t))))
+
+(defalias 'nnmail-fix-eudora-headers 'nnmail-ignore-broken-references)
+(make-obsolete 'nnmail-fix-eudora-headers 'nnmail-ignore-broken-references "Emacs 23.1")
+
+(custom-add-option 'nnmail-prepare-incoming-header-hook
+                  'nnmail-ignore-broken-references)
+
+;;; Utility functions
+
+(declare-function gnus-activate-group "gnus-start"
+                  (group &optional scan dont-check method dont-sub-check))
+
+(defun nnmail-do-request-post (accept-func &optional server)
+  "Utility function to directly post a message to an nnmail-derived group.
+Calls ACCEPT-FUNC (which should be `nnchoke-request-accept-article')
+to actually put the message in the right group."
+  (let ((success t))
+    (dolist (mbx (message-unquote-tokens
+                 (message-tokenize-header
+                  (message-fetch-field "Newsgroups") ", ")) success)
+      (let ((to-newsgroup (gnus-group-prefixed-name mbx gnus-command-method)))
+       (or (gnus-active to-newsgroup)
+           (gnus-activate-group to-newsgroup)
+           (if (gnus-y-or-n-p (format "No such group: %s.  Create it? "
+                                      to-newsgroup))
+               (or (and (gnus-request-create-group
+                         to-newsgroup gnus-command-method)
+                        (gnus-activate-group to-newsgroup nil nil
+                                             gnus-command-method))
+                   (error "Couldn't create group %s" to-newsgroup)))
+           (error "No such group: %s" to-newsgroup))
+       (unless (funcall accept-func mbx (nth 1 gnus-command-method))
+         (setq success nil))))))
+
+(defun nnmail-split-fancy ()
+  "Fancy splitting method.
+See the documentation for the variable `nnmail-split-fancy' for details."
+  (with-syntax-table nnmail-split-fancy-syntax-table
+    (nnmail-split-it nnmail-split-fancy)))
+
+(defvar nnmail-split-cache nil)
+;; Alist of split expressions their equivalent regexps.
+
+(defun nnmail-split-it (split)
+  ;; Return a list of groups matching SPLIT.
+  (let (cached-pair)
+    (cond
+     ;; nil split
+     ((null split)
+      nil)
+
+     ;; A group name.  Do the \& and \N subs into the string.
+     ((stringp split)
+      (when nnmail-split-tracing
+       (push split nnmail-split-trace))
+      (list (nnmail-expand-newtext split t)))
+
+     ;; Junk the message.
+     ((eq split 'junk)
+      (when nnmail-split-tracing
+       (push "junk" nnmail-split-trace))
+      (list 'junk))
+
+     ;; Builtin & operation.
+     ((eq (car split) '&)
+      (apply 'nconc (mapcar 'nnmail-split-it (cdr split))))
+
+     ;; Builtin | operation.
+     ((eq (car split) '|)
+      (let (done)
+       (while (and (not done) (cdr split))
+         (setq split (cdr split)
+               done (nnmail-split-it (car split))))
+       done))
+
+     ;; Builtin : operation.
+     ((eq (car split) ':)
+      (when nnmail-split-tracing
+       (push split nnmail-split-trace))
+      (nnmail-split-it (save-excursion (eval (cdr split)))))
+
+     ;; Builtin ! operation.
+     ((eq (car split) '!)
+      (funcall (cadr split) (nnmail-split-it (caddr split))))
+
+     ;; Check the cache for the regexp for this split.
+     ((setq cached-pair (assq split nnmail-split-cache))
+      (let (split-result
+           match-data
+           (end-point (point-max))
+           (value (nth 1 split)))
+       (if (symbolp value)
+           (setq value (cdr (assq value nnmail-split-abbrev-alist))))
+       (while (and (goto-char end-point)
+                   (re-search-backward (cdr cached-pair) nil t))
+         (setq match-data (match-data))
+         (when nnmail-split-tracing
+           (push split nnmail-split-trace))
+         (let ((split-rest (cddr split))
+               (end (match-end 0))
+               ;; The searched regexp is \(\(FIELD\).*\)\(VALUE\).
+               ;; So, start-of-value is the point just before the
+               ;; beginning of the value, whereas after-header-name
+               ;; is the point just after the field name.
+               (start-of-value (match-end 1))
+               (after-header-name (match-end 2)))
+           ;; Start the next search just before the beginning of the
+           ;; VALUE match.
+           (setq end-point (1- start-of-value))
+           ;; Handle - RESTRICTs
+           (while (eq (car split-rest) '-)
+             ;; RESTRICT must start after-header-name and
+             ;; end after start-of-value, so that, for
+             ;; (any "foo" - "x-foo" "foo.list")
+             ;; we do not exclude foo.list just because
+             ;; the header is: ``To: x-foo, foo''
+             (goto-char end)
+             (if (and (re-search-backward (cadr split-rest)
+                                          after-header-name t)
+                      (> (match-end 0) start-of-value))
+                 (setq split-rest nil)
+               (setq split-rest (cddr split-rest))))
+           (when split-rest
+             (goto-char end)
+             ;; Someone might want to do a \N sub on this match, so
+             ;; restore the match data.
+             (set-match-data match-data)
+             (dolist (sp (nnmail-split-it (car split-rest)))
+               (unless (member sp split-result)
+                 (push sp split-result))))))
+       split-result))
+
+     ;; Not in cache, compute a regexp for the field/value pair.
+     (t
+      (let ((field (nth 0 split))
+           (value (nth 1 split))
+           (split-rest (cddr split))
+           partial-front
+           partial-rear
+           regexp)
+       (if (symbolp value)
+           (setq value (cdr (assq value nnmail-split-abbrev-alist))))
+       (if (and (>= (length value) 2)
+                (string= ".*" (substring value 0 2)))
+           (setq value (substring value 2)
+                 partial-front ""))
+       ;; Same trick for the rear of the regexp
+       (if (and (>= (length value) 2)
+                (string= ".*" (substring value -2)))
+           (setq value (substring value 0 -2)
+                 partial-rear ""))
+       ;; Invert the match-partial-words behavior if the optional
+       ;; last element is specified.
+       (while (eq (car split-rest) '-)
+         (setq split-rest (cddr split-rest)))
+       (when (if (cadr split-rest)
+                 (not nnmail-split-fancy-match-partial-words)
+               nnmail-split-fancy-match-partial-words)
+         (setq partial-front ""
+               partial-rear ""))
+       (setq regexp (concat "^\\(\\("
+                            (if (symbolp field)
+                                (cdr (assq field nnmail-split-abbrev-alist))
+                              field)
+                            "\\):.*\\)"
+                            (or partial-front "\\<")
+                            "\\("
+                            value
+                            "\\)"
+                            (or partial-rear "\\>")))
+       (push (cons split regexp) nnmail-split-cache)
+       ;; Now that it's in the cache, just call nnmail-split-it again
+       ;; on the same split, which will find it immediately in the cache.
+       (nnmail-split-it split))))))
+
+(defun nnmail-expand-newtext (newtext &optional fancyp)
+  (let ((len (length newtext))
+       (pos 0)
+       c expanded beg N did-expand)
+    (while (< pos len)
+      (setq beg pos)
+      (while (and (< pos len)
+                 (not (= (aref newtext pos) ?\\)))
+       (setq pos (1+ pos)))
+      (unless (= beg pos)
+       (push (substring newtext beg pos) expanded))
+      (when (< pos len)
+       ;; We hit a \; expand it.
+       (setq did-expand t
+             pos (1+ pos)
+             c (aref newtext pos))
+       (if (not (or (= c ?\&)
+                    (and (>= c ?1)
+                         (<= c ?9))))
+           ;; \ followed by some character we don't expand.
+           (push (char-to-string c) expanded)
+         ;; \& or \N
+         (if (= c ?\&)
+             (setq N 0)
+           (setq N (- c ?0)))
+         ;; We wrapped the searches in parentheses, so we have to
+         ;; add some parentheses here...
+         (when fancyp
+           (setq N (+ N 3)))
+         (when (match-beginning N)
+           (push (if nnmail-split-lowercase-expanded
+                     (downcase (buffer-substring (match-beginning N)
+                                                 (match-end N)))
+                   (buffer-substring (match-beginning N) (match-end N)))
+                 expanded))))
+      (setq pos (1+ pos)))
+    (if did-expand
+       (apply 'concat (nreverse expanded))
+      newtext)))
+
+;; Activate a backend only if it isn't already activated.
+;; If FORCE, re-read the active file even if the backend is
+;; already activated.
+(defun nnmail-activate (backend &optional force)
+  (nnheader-init-server-buffer)
+  (let (file timestamp file-time)
+    (if (or (not (symbol-value (intern (format "%s-group-alist" backend))))
+           force
+           (and (setq file (ignore-errors
+                             (symbol-value (intern (format "%s-active-file"
+                                                           backend)))))
+                (setq file-time (nth 5 (file-attributes file)))
+                (or (not
+                     (setq timestamp
+                           (condition-case ()
+                               (symbol-value (intern
+                                              (format "%s-active-timestamp"
+                                                      backend)))
+                             (error 'none))))
+                    (not (consp timestamp))
+                    (equal timestamp '(0 0))
+                    (> (nth 0 file-time) (nth 0 timestamp))
+                    (and (= (nth 0 file-time) (nth 0 timestamp))
+                         (> (nth 1 file-time) (nth 1 timestamp))))))
+       (save-excursion
+         (or (eq timestamp 'none)
+             (set (intern (format "%s-active-timestamp" backend))
+                  file-time))
+         (funcall (intern (format "%s-request-list" backend)))))
+    t))
+
+(defun nnmail-message-id ()
+  (concat "<" (message-unique-id) "@totally-fudged-out-message-id>"))
+
+;;;
+;;; nnmail duplicate handling
+;;;
+
+(defvar nnmail-cache-buffer nil)
+
+(defun nnmail-cache-open ()
+  (if (or (not nnmail-treat-duplicates)
+         (and nnmail-cache-buffer
+              (buffer-name nnmail-cache-buffer)))
+      ()                               ; The buffer is open.
+    (with-current-buffer
+       (setq nnmail-cache-buffer
+            (get-buffer-create " *nnmail message-id cache*"))
+      (gnus-add-buffer)
+      (when (file-exists-p nnmail-message-id-cache-file)
+       (nnheader-insert-file-contents nnmail-message-id-cache-file))
+      (set-buffer-modified-p nil)
+      (current-buffer))))
+
+(defun nnmail-cache-close ()
+  (when (and nnmail-cache-buffer
+            nnmail-treat-duplicates
+            (buffer-name nnmail-cache-buffer)
+            (buffer-modified-p nnmail-cache-buffer))
+    (with-current-buffer nnmail-cache-buffer
+      ;; Weed out the excess number of Message-IDs.
+      (goto-char (point-max))
+      (when (search-backward "\n" nil t nnmail-message-id-cache-length)
+       (progn
+         (beginning-of-line)
+         (delete-region (point-min) (point))))
+      ;; Save the buffer.
+      (or (file-exists-p (file-name-directory nnmail-message-id-cache-file))
+         (make-directory (file-name-directory nnmail-message-id-cache-file)
+                         t))
+      (nnmail-write-region (point-min) (point-max)
+                          nnmail-message-id-cache-file nil 'silent)
+      (set-buffer-modified-p nil)
+      (setq nnmail-cache-buffer nil)
+      (gnus-kill-buffer (current-buffer)))))
+
+(defun nnmail-cache-insert (id grp &optional subject sender)
+  (when (stringp id)
+    ;; this will handle cases like `B r' where the group is nil
+    (let ((grp (or grp gnus-newsgroup-name "UNKNOWN")))
+      (run-hook-with-args 'nnmail-spool-hook
+                         id grp subject sender))
+    (when nnmail-treat-duplicates
+      ;; Store some information about the group this message is written
+      ;; to.  This is passed in as the grp argument -- all locations this
+      ;; has been called from have been checked and the group is available.
+      ;; The only ambiguous case is nnmail-check-duplication which will only
+      ;; pass the first (of possibly >1) group which matches. -Josh
+      (unless (gnus-buffer-live-p nnmail-cache-buffer)
+       (nnmail-cache-open))
+      (with-current-buffer nnmail-cache-buffer
+       (goto-char (point-max))
+       (if (and grp (not (string= "" grp))
+                (gnus-methods-equal-p gnus-command-method
+                                      (nnmail-cache-primary-mail-backend)))
+           (let ((regexp (if (consp nnmail-cache-ignore-groups)
+                             (mapconcat 'identity nnmail-cache-ignore-groups
+                                        "\\|")
+                           nnmail-cache-ignore-groups)))
+             (unless (and regexp (string-match regexp grp))
+               (insert id "\t" grp "\n")))
+         (insert id "\n"))))))
+
+(defun nnmail-cache-primary-mail-backend ()
+  (let ((be-list (cons gnus-select-method gnus-secondary-select-methods))
+       (be nil)
+       (res nil)
+        (get-new-mail nil))
+    (while (and (null res) be-list)
+      (setq be (car be-list))
+      (setq be-list (cdr be-list))
+      (when (and (gnus-method-option-p be 'respool)
+                 (setq get-new-mail
+                       (intern (format "%s-get-new-mail" (car be))))
+                 (boundp get-new-mail)
+                (symbol-value get-new-mail))
+       (setq res be)))
+    res))
+
+;; Fetch the group name corresponding to the message id stored in the
+;; cache.
+(defun nnmail-cache-fetch-group (id)
+  (when (and nnmail-treat-duplicates nnmail-cache-buffer)
+    (with-current-buffer nnmail-cache-buffer
+      (goto-char (point-max))
+      (when (search-backward id nil t)
+       (beginning-of-line)
+       (skip-chars-forward "^\n\r\t")
+       (unless (looking-at "[\r\n]")
+         (forward-char 1)
+         (buffer-substring (point) (point-at-eol)))))))
+
+;; Function for nnmail-split-fancy: look up all references in the
+;; cache and if a match is found, return that group.
+(defun nnmail-split-fancy-with-parent ()
+  "Split this message into the same group as its parent.
+This function can be used as an entry in `nnmail-split-fancy', for
+example like this: (: nnmail-split-fancy-with-parent)
+For a message to be split, it looks for the parent message in the
+References or In-Reply-To header and then looks in the message id
+cache file (given by the variable `nnmail-message-id-cache-file') to
+see which group that message was put in.  This group is returned.
+
+See the Info node `(gnus)Fancy Mail Splitting' for more details."
+  (let* ((refstr (or (message-fetch-field "references")
+                    (message-fetch-field "in-reply-to")))
+        (references nil)
+        (res nil)
+        (regexp (if (consp nnmail-split-fancy-with-parent-ignore-groups)
+                    (mapconcat
+                     (lambda (x) (format "\\(%s\\)" x))
+                     nnmail-split-fancy-with-parent-ignore-groups
+                     "\\|")
+                  nnmail-split-fancy-with-parent-ignore-groups)))
+    (when refstr
+      (setq references (nreverse (gnus-split-references refstr)))
+      (unless (gnus-buffer-live-p nnmail-cache-buffer)
+       (nnmail-cache-open))
+      (dolist (x references)
+       (setq res (or (nnmail-cache-fetch-group x) res))
+       (when (or (member res '("delayed" "drafts" "queue"))
+                 (and regexp res (string-match regexp res)))
+         (setq res nil)))
+      res)))
+
+(defun nnmail-cache-id-exists-p (id)
+  (when nnmail-treat-duplicates
+    (with-current-buffer nnmail-cache-buffer
+      (goto-char (point-max))
+      (search-backward id nil t))))
+
+(defun nnmail-fetch-field (header)
+  (save-excursion
+    (save-restriction
+      (message-narrow-to-head)
+      (message-fetch-field header))))
+
+(defun nnmail-check-duplication (message-id func artnum-func
+                                           &optional junk-func)
+  (run-hooks 'nnmail-prepare-incoming-message-hook)
+  ;; If this is a duplicate message, then we do not save it.
+  (let* ((duplication (nnmail-cache-id-exists-p message-id))
+        (case-fold-search t)
+        (action (when duplication
+                  (cond
+                   ((memq nnmail-treat-duplicates '(warn delete))
+                    nnmail-treat-duplicates)
+                   ((functionp nnmail-treat-duplicates)
+                    (funcall nnmail-treat-duplicates message-id))
+                   (t
+                    nnmail-treat-duplicates))))
+        group-art)
+    ;; We insert a line that says what the mail source is.
+    (let ((case-fold-search t))
+      (goto-char (point-min))
+      (re-search-forward "^message-id[ \t]*:" nil t)
+      (beginning-of-line)
+      (insert (format "X-Gnus-Mail-Source: %s\n" mail-source-string)))
+
+    ;; Let the backend save the article (or not).
+    (cond
+     ((not duplication)
+      (funcall func (setq group-art
+                         (nreverse (nnmail-article-group
+                                    artnum-func nil junk-func))))
+      (nnmail-cache-insert message-id (caar group-art)))
+     ((eq action 'delete)
+      (setq group-art nil))
+     ((eq action 'warn)
+      ;; We insert a warning.
+      (let ((case-fold-search t))
+       (goto-char (point-min))
+       (re-search-forward "^message-id[ \t]*:" nil t)
+       (beginning-of-line)
+       (insert
+        "Gnus-Warning: This is a duplicate of message " message-id "\n")
+       (funcall func (setq group-art
+                           (nreverse (nnmail-article-group artnum-func))))))
+     (t
+      (funcall func (setq group-art
+                         (nreverse (nnmail-article-group artnum-func))))))
+    ;; Add the group-art list to the history list.
+    (if group-art
+       (push group-art nnmail-split-history)
+      (delete-region (point-min) (point-max)))))
+
+;;; Get new mail.
+
+(defvar nnmail-fetched-sources nil)
+
+(defun nnmail-get-value (&rest args)
+  (let ((sym (intern (apply 'format args))))
+    (when (boundp sym)
+      (symbol-value sym))))
+
+(defun nnmail-get-new-mail (method exit-func temp
+                           &optional group spool-func)
+  "Read new incoming mail."
+  (nnmail-get-new-mail-1 method exit-func temp group nil spool-func))
+
+(defun nnmail-get-new-mail-per-group ()
+  "Tell us whether the mail-sources specify that `nnmail-get-new-mail' should
+be called once per group or once for all groups."
+  (or (assq 'group mail-sources)
+      (assq 'directory mail-sources)))
+
+(defun nnmail-get-new-mail-1 (method exit-func temp
+                             group in-group spool-func)
+  (let* ((sources mail-sources)
+        fetching-sources
+        (i 0)
+        (new 0)
+        (total 0)
+        source)
+    (when (and (nnmail-get-value "%s-get-new-mail" method)
+              sources)
+      (while (setq source (pop sources))
+       ;; Use group's parameter
+       (when (and (eq (car source) 'group)
+                  group)
+         (let ((mail-sources
+                (list
+                 (gnus-group-find-parameter
+                  (concat (symbol-name method) ":" group)
+                  'mail-source t))))
+           (nnmail-get-new-mail-1 method exit-func temp
+                                  group group spool-func))
+         (setq source nil))
+       ;; Hack to only fetch the contents of a single group's spool file.
+       (when (and (eq (car source) 'directory)
+                  (null nnmail-scan-directory-mail-source-once)
+                  group)
+         (mail-source-bind (directory source)
+           (setq source (append source
+                                (list
+                                 :predicate
+                                 (gnus-byte-compile
+                                  `(lambda (file)
+                                     (string-equal
+                                      ,(concat group suffix)
+                                      (file-name-nondirectory file)))))))))
+       (when nnmail-fetched-sources
+         (if (member source nnmail-fetched-sources)
+             (setq source nil)
+           (push source nnmail-fetched-sources)
+           (push source fetching-sources)))))
+    (when fetching-sources
+      ;; We first activate all the groups.
+      (nnmail-activate method)
+      ;; Allow the user to hook.
+      (run-hooks 'nnmail-pre-get-new-mail-hook)
+      ;; Open the message-id cache.
+      (nnmail-cache-open)
+      ;; The we go through all the existing mail source specification
+      ;; and fetch the mail from each.
+      (while (setq source (pop fetching-sources))
+       (when (setq new
+                   (condition-case cond
+                       (mail-source-fetch
+                        source
+                        (gnus-byte-compile
+                         `(lambda (file orig-file)
+                            (nnmail-split-incoming
+                             file ',(intern (format "%s-save-mail" method))
+                             ',spool-func
+                             (or in-group
+                                 (if (equal file orig-file)
+                                     nil
+                                   (nnmail-get-split-group orig-file
+                                                           ',source)))
+                             ',(intern (format "%s-active-number" method))))))
+                     ((error quit)
+                      (message "Mail source %s failed: %s" source cond)
+                      0)))
+         (incf total new)
+         (incf i)))
+      ;; If we did indeed read any incoming spools, we save all info.
+      (if (zerop total)
+         (when mail-source-plugged
+           (nnheader-message 4 "%s: Reading incoming mail (no new mail)...done"
+                             method (car source)))
+       (nnmail-save-active
+        (nnmail-get-value "%s-group-alist" method)
+        (nnmail-get-value "%s-active-file" method))
+       (when exit-func
+         (funcall exit-func))
+       (run-hooks 'nnmail-read-incoming-hook)
+       (nnheader-message 4 "%s: Reading incoming mail (%d new)...done" method
+                         total))
+      ;; Close the message-id cache.
+      (nnmail-cache-close)
+      ;; Allow the user to hook.
+      (run-hooks 'nnmail-post-get-new-mail-hook))))
+
+(defun nnmail-expired-article-p (group time force &optional inhibit)
+  "Say whether an article that is TIME old in GROUP should be expired.
+If TIME is nil, then return the cutoff time for oldness instead."
+  (if force
+      (if (null time)
+         (current-time)
+       t)
+    (let ((days (or (and nnmail-expiry-wait-function
+                        (funcall nnmail-expiry-wait-function group))
+                   nnmail-expiry-wait)))
+      (cond ((or (eq days 'never)
+                (and (not force)
+                     inhibit))
+            ;; This isn't an expirable group.
+            nil)
+           ((eq days 'immediate)
+            ;; We expire all articles on sight.
+            (if (null time)
+                (current-time)
+              t))
+           ((equal time '(0 0))
+           ;; This is an ange-ftp group, and we don't have any dates.
+            nil)
+           ((numberp days)
+            (setq days (days-to-time days))
+            ;; Compare the time with the current time.
+            (if (null time)
+                (time-subtract (current-time) days)
+              (ignore-errors (time-less-p days (time-since time)))))))))
+
+(declare-function gnus-group-mark-article-read "gnus-group" (group article))
+
+(defun nnmail-expiry-target-group (target group)
+  ;; Do not invoke this from nntp-server-buffer!  At least nnfolder clears
+  ;; that buffer if the nnfolder group isn't selected.
+  (let (nnmail-cache-accepted-message-ids)
+    ;; Don't enter Message-IDs into cache.
+    ;; Let users hack it in TARGET function.
+    (when (functionp target)
+      (setq target (funcall target group)))
+    (unless (eq target 'delete)
+      (when (or (gnus-request-group target nil nil (gnus-get-info target))
+               (gnus-request-create-group target))
+       (let ((group-art (gnus-request-accept-article target nil nil t)))
+         (when (and (consp group-art)
+                    (cdr group-art))
+           (gnus-group-mark-article-read target (cdr group-art))))))))
+
+(defun nnmail-fancy-expiry-target (group)
+  "Returns a target expiry group determined by `nnmail-fancy-expiry-targets'."
+  (let* (header
+        (case-fold-search nil)
+        (from (or (message-fetch-field "from") ""))
+        (to (or (message-fetch-field "to") ""))
+        (date (message-fetch-field "date"))
+        (target 'delete))
+    (setq date (if date
+                  (condition-case err
+                      (date-to-time date)
+                    (error
+                     (message "%s" (error-message-string err))
+                     (current-time)))
+                (current-time)))
+    (dolist (regexp-target-pair (reverse nnmail-fancy-expiry-targets) target)
+      (setq header (car regexp-target-pair))
+      (cond
+       ;; If the header is to-from then match against the
+       ;; To or From header
+       ((and (equal header 'to-from)
+            (or (string-match (cadr regexp-target-pair) from)
+                (and (string-match (cadr regexp-target-pair) to)
+                     (let* ((mail-dont-reply-to-names
+                             (message-dont-reply-to-names))
+                            (rmail-dont-reply-to-names ; obsolete since 24.1
+                             mail-dont-reply-to-names))
+                       (equal (if (fboundp 'rmail-dont-reply-to)
+                                  (rmail-dont-reply-to from)
+                                (mail-dont-reply-to from)) "")))))
+       (setq target (format-time-string (caddr regexp-target-pair) date)))
+       ((and (not (equal header 'to-from))
+            (string-match (cadr regexp-target-pair)
+                          (or
+                           (message-fetch-field header)
+                           "")))
+       (setq target
+             (format-time-string (caddr regexp-target-pair) date)))))))
+
+(defun nnmail-check-syntax ()
+  "Check (and modify) the syntax of the message in the current buffer."
+  (save-restriction
+    (message-narrow-to-head)
+    (let ((case-fold-search t))
+      (unless (re-search-forward "^Message-ID[ \t]*:" nil t)
+       (insert "Message-ID: " (nnmail-message-id) "\n")))))
+
+(defun nnmail-write-region (start end filename &optional append visit lockname)
+  "Do a `write-region', and then set the file modes."
+  (let ((coding-system-for-write nnmail-file-coding-system)
+       (file-name-coding-system nnmail-pathname-coding-system))
+    (write-region start end filename append visit lockname)
+    (set-file-modes filename nnmail-default-file-modes)))
+
+;;;
+;;; Status functions
+;;;
+
+(defun nnmail-replace-status (name value)
+  "Make status NAME and VALUE part of the current status line."
+  (save-restriction
+    (message-narrow-to-head)
+    (let ((status (nnmail-decode-status)))
+      (setq status (delq (member name status) status))
+      (when value
+       (push (cons name value) status))
+      (message-remove-header "status")
+      (goto-char (point-max))
+      (insert "Status: " (nnmail-encode-status status) "\n"))))
+
+(defun nnmail-decode-status ()
+  "Return a status-value alist from STATUS."
+  (goto-char (point-min))
+  (when (re-search-forward "^Status: " nil t)
+    (let (name value status)
+      (save-restriction
+       ;; Narrow to the status.
+       (narrow-to-region
+        (point)
+        (if (re-search-forward "^[^ \t]" nil t)
+            (1- (point))
+          (point-max)))
+       ;; Go through all elements and add them to the list.
+       (goto-char (point-min))
+       (while (re-search-forward "[^ \t=]+" nil t)
+         (setq name (match-string 0))
+         (if (not (eq (char-after) ?=))
+             ;; Implied "yes".
+             (setq value "yes")
+           (forward-char 1)
+           (if (not (eq (char-after) ?\"))
+               (if (not (looking-at "[^ \t]"))
+                   ;; Implied "no".
+                   (setq value "no")
+                 ;; Unquoted value.
+                 (setq value (match-string 0))
+                 (goto-char (match-end 0)))
+             ;; Quoted value.
+             (setq value (read (current-buffer)))))
+         (push (cons name value) status)))
+      status)))
+
+(defun nnmail-encode-status (status)
+  "Return a status string from STATUS."
+  (mapconcat
+   (lambda (elem)
+     (concat
+      (car elem) "="
+      (if (string-match "[ \t]" (cdr elem))
+         (prin1-to-string (cdr elem))
+       (cdr elem))))
+   status " "))
+
+(defun nnmail-split-history ()
+  "Generate an overview of where the last mail split put articles."
+  (interactive)
+  (unless nnmail-split-history
+    (error "No current split history"))
+  (with-output-to-temp-buffer "*nnmail split history*"
+    (with-current-buffer standard-output
+      (fundamental-mode))              ; for Emacs 20.4+
+      (dolist (elem nnmail-split-history)
+       (princ (mapconcat (lambda (ga)
+                           (concat (car ga) ":" (int-to-string (cdr ga))))
+                         elem
+                         ", "))
+       (princ "\n"))))
+
+(defun nnmail-purge-split-history (group)
+  "Remove all instances of GROUP from `nnmail-split-history'."
+  (let ((history nnmail-split-history))
+    (while history
+      (setcar history (gnus-remove-if (lambda (e) (string= (car e) group))
+                                     (car history)))
+      (pop history))
+    (setq nnmail-split-history (delq nil nnmail-split-history))))
+
+(defun nnmail-new-mail-p (group)
+  "Say whether GROUP has new mail."
+  (let ((his nnmail-split-history)
+       found)
+    (while his
+      (when (assoc group (pop his))
+       (setq found t
+             his nil)))
+    found))
+
+(defun nnmail-within-headers-p ()
+  "Check to see if point is within the headers of a unix mail message.
+Doesn't change point."
+  (let ((pos (point)))
+    (save-excursion
+      (and (nnmail-search-unix-mail-delim-backward)
+          (not (search-forward "\n\n" pos t))))))
+
+(run-hooks 'nnmail-load-hook)
+
+(provide 'nnmail)
+
+;;; nnmail.el ends here
diff --git a/xemacs-packages/gnus/lisp/nnmaildir.el b/xemacs-packages/gnus/lisp/nnmaildir.el
new file mode 100644 (file)
index 0000000..3d8926b
--- /dev/null
@@ -0,0 +1,1813 @@
+;;; nnmaildir.el --- maildir backend for Gnus
+
+;; This file is in the public domain.
+
+;; Author: Paul Jarc <prj@po.cwru.edu>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Maildir format is documented at <URL:http://cr.yp.to/proto/maildir.html>
+;; and in the maildir(5) man page from qmail (available at
+;; <URL:http://www.qmail.org/man/man5/maildir.html>).  nnmaildir also stores
+;; extra information in the .nnmaildir/ directory within a maildir.
+;;
+;; Some goals of nnmaildir:
+;; * Everything Just Works, and correctly.  E.g., NOV data is automatically
+;;   regenerated when stale; no need for manually running
+;;   *-generate-nov-databases.
+;; * Perfect reliability: [C-g] will never corrupt its data in memory, and
+;;   SIGKILL will never corrupt its data in the filesystem.
+;; * Allow concurrent operation as much as possible.  If files change out
+;;   from under us, adapt to the changes or degrade gracefully.
+;; * We use the filesystem as a database, so that, e.g., it's easy to
+;;   manipulate marks from outside Gnus.
+;; * All information about a group is stored in the maildir, for easy backup,
+;;   copying, restoring, etc.
+;;
+;; Todo:
+;; * When moving an article for expiry, copy all the marks except 'expire
+;;   from the original article.
+;; * Add a hook for when moving messages from new/ to cur/, to support
+;;   nnmail's duplicate detection.
+;; * Improve generated Xrefs, so crossposts are detectable.
+;; * Improve code readability.
+
+;;; Code:
+
+;; eval this before editing
+[(progn
+   (put 'nnmaildir--with-nntp-buffer 'lisp-indent-function 0)
+   (put 'nnmaildir--with-work-buffer 'lisp-indent-function 0)
+   (put 'nnmaildir--with-nov-buffer  'lisp-indent-function 0)
+   (put 'nnmaildir--with-move-buffer 'lisp-indent-function 0)
+   (put 'nnmaildir--condcase         'lisp-indent-function 2)
+   )
+]
+
+(require 'nnheader)
+(require 'gnus)
+(require 'gnus-util)
+(require 'gnus-range)
+(require 'gnus-start)
+(require 'gnus-int)
+(require 'message)
+(require 'nnmail)
+
+(eval-when-compile
+  (require 'cl))
+
+(defconst nnmaildir-version "Gnus")
+
+(defconst nnmaildir-flag-mark-mapping
+  '((?F . tick)
+    (?P . forward)
+    (?R . reply)
+    (?S . read))
+  "Alist mapping Maildir filename flags to Gnus marks.
+Maildir filenames are of the form \"unique-id:2,FLAGS\",
+where FLAGS are a string of characters in ASCII order.
+Some of the FLAGS correspond to Gnus marks.")
+
+(defsubst nnmaildir--mark-to-flag (mark)
+  "Find the Maildir flag that corresponds to MARK (an atom).
+Return a character, or nil if not found.
+See `nnmaildir-flag-mark-mapping'."
+  (car (rassq mark nnmaildir-flag-mark-mapping)))
+
+(defsubst nnmaildir--flag-to-mark (flag)
+  "Find the Gnus mark that corresponds to FLAG (a character).
+Return an atom, or nil if not found.
+See `nnmaildir-flag-mark-mapping'."
+  (cdr (assq flag nnmaildir-flag-mark-mapping)))
+
+(defun nnmaildir--ensure-suffix (filename)
+  "Ensure that FILENAME contains the suffix \":2,\"."
+  (if (gnus-string-match-p ":2," filename)
+      filename
+    (concat filename ":2,")))
+
+(defun nnmaildir--add-flag (flag suffix)
+  "Return a copy of SUFFIX where FLAG is set.
+SUFFIX should start with \":2,\"."
+  (unless (gnus-string-match-p "^:2," suffix)
+    (error "Invalid suffix `%s'" suffix))
+  (let* ((flags (substring suffix 3))
+        (flags-as-list (append flags nil))
+        (new-flags
+         (concat (gnus-delete-duplicates
+                  ;; maildir flags must be sorted
+                  (sort (cons flag flags-as-list) '<)))))
+    (concat ":2," new-flags)))
+
+(defun nnmaildir--remove-flag (flag suffix)
+  "Return a copy of SUFFIX where FLAG is cleared.
+SUFFIX should start with \":2,\"."
+  (unless (gnus-string-match-p "^:2," suffix)
+    (error "Invalid suffix `%s'" suffix))
+  (let* ((flags (substring suffix 3))
+        (flags-as-list (append flags nil))
+        (new-flags (concat (delq flag flags-as-list))))
+    (concat ":2," new-flags)))
+
+(defvar nnmaildir-article-file-name nil
+  "*The filename of the most recently requested article.  This variable is set
+by nnmaildir-request-article.")
+
+;; The filename of the article being moved/copied:
+(defvar nnmaildir--file nil)
+
+;; Variables to generate filenames of messages being delivered:
+(defvar   nnmaildir--delivery-time "")
+(defconst nnmaildir--delivery-pid (concat "P" (number-to-string (emacs-pid))))
+(defvar   nnmaildir--delivery-count nil)
+
+;; An obarry containing symbols whose names are server names and whose values
+;; are servers:
+(defvar nnmaildir--servers (make-vector 3 0))
+;; The current server:
+(defvar nnmaildir--cur-server nil)
+
+;; A copy of nnmail-extra-headers
+(defvar nnmaildir--extra nil)
+
+;; A NOV structure looks like this (must be prin1-able, so no defstruct):
+["subject\tfrom\tdate"
+ "references\tchars\tlines"
+ "To: you\tIn-Reply-To: <your.mess@ge>"
+ (12345 67890)     ;; modtime of the corresponding article file
+ (to in-reply-to)] ;; contemporary value of nnmail-extra-headers
+(defconst nnmaildir--novlen 5)
+(defmacro nnmaildir--nov-new (beg mid end mtime extra)
+  `(vector ,beg ,mid ,end ,mtime ,extra))
+(defmacro nnmaildir--nov-get-beg   (nov) `(aref ,nov 0))
+(defmacro nnmaildir--nov-get-mid   (nov) `(aref ,nov 1))
+(defmacro nnmaildir--nov-get-end   (nov) `(aref ,nov 2))
+(defmacro nnmaildir--nov-get-mtime (nov) `(aref ,nov 3))
+(defmacro nnmaildir--nov-get-extra (nov) `(aref ,nov 4))
+(defmacro nnmaildir--nov-set-beg   (nov value) `(aset ,nov 0 ,value))
+(defmacro nnmaildir--nov-set-mid   (nov value) `(aset ,nov 1 ,value))
+(defmacro nnmaildir--nov-set-end   (nov value) `(aset ,nov 2 ,value))
+(defmacro nnmaildir--nov-set-mtime (nov value) `(aset ,nov 3 ,value))
+(defmacro nnmaildir--nov-set-extra (nov value) `(aset ,nov 4 ,value))
+
+(defstruct nnmaildir--art
+  (prefix nil :type string)  ;; "time.pid.host"
+  (suffix nil :type string)  ;; ":2,flags"
+  (num    nil :type natnum)  ;; article number
+  (msgid  nil :type string)  ;; "<mess.age@id>"
+  (nov    nil :type vector)) ;; cached nov structure, or nil
+
+(defstruct nnmaildir--grp
+  (name  nil :type string)  ;; "group.name"
+  (new   nil :type list)    ;; new/ modtime
+  (cur   nil :type list)    ;; cur/ modtime
+  (min   1   :type natnum)  ;; minimum article number
+  (count 0   :type natnum)  ;; count of articles
+  (nlist nil :type list)    ;; list of articles, ordered descending by number
+  (flist nil :type vector)  ;; obarray mapping filename prefix->article
+  (mlist nil :type vector)  ;; obarray mapping message-id->article
+  (cache nil :type vector)  ;; nov cache
+  (index nil :type natnum)  ;; index of next cache entry to replace
+  (mmth  nil :type vector)) ;; obarray mapping mark name->dir modtime
+                                       ; ("Mark Mod Time Hash")
+
+(defstruct nnmaildir--srv
+  (address      nil :type string)         ;; server address string
+  (method       nil :type list)           ;; (nnmaildir "address" ...)
+  (prefix       nil :type string)         ;; "nnmaildir+address:"
+  (dir          nil :type string)         ;; "/expanded/path/to/server/dir/"
+  (ls           nil :type function)       ;; directory-files function
+  (groups       nil :type vector)         ;; obarray mapping group name->group
+  (curgrp       nil :type nnmaildir--grp) ;; current group, or nil
+  (error        nil :type string)         ;; last error message, or nil
+  (mtime        nil :type list)           ;; modtime of dir
+  (gnm          nil)                      ;; flag: split from mail-sources?
+  (target-prefix nil :type string))        ;; symlink target prefix
+
+(defun nnmaildir--article-set-flags (article new-suffix curdir)
+  (let* ((prefix (nnmaildir--art-prefix article))
+        (suffix (nnmaildir--art-suffix article))
+        (article-file (concat curdir prefix suffix))
+        (new-name (concat curdir prefix new-suffix)))
+    (unless (file-exists-p article-file)
+      (error "Couldn't find article file %s" article-file))
+    (rename-file article-file new-name 'replace)
+    (setf (nnmaildir--art-suffix article) new-suffix)))
+
+(defun nnmaildir--expired-article (group article)
+  (setf (nnmaildir--art-nov article) nil)
+  (let ((flist  (nnmaildir--grp-flist group))
+       (mlist  (nnmaildir--grp-mlist group))
+       (min    (nnmaildir--grp-min   group))
+       (count  (1- (nnmaildir--grp-count group)))
+       (prefix (nnmaildir--art-prefix article))
+       (msgid  (nnmaildir--art-msgid  article))
+       (new-nlist nil)
+       (nlist-pre '(nil . nil))
+       nlist-post num)
+    (unless (zerop count)
+      (setq nlist-post (nnmaildir--grp-nlist group)
+           num (nnmaildir--art-num article))
+      (if (eq num (caar nlist-post))
+         (setq new-nlist (cdr nlist-post))
+       (setq new-nlist nlist-post
+             nlist-pre nlist-post
+             nlist-post (cdr nlist-post))
+       (while (/= num (caar nlist-post))
+         (setq nlist-pre nlist-post
+               nlist-post (cdr nlist-post)))
+       (setq nlist-post (cdr nlist-post))
+       (if (eq num min)
+           (setq min (caar nlist-pre)))))
+    (let ((inhibit-quit t))
+      (setf (nnmaildir--grp-min   group) min)
+      (setf (nnmaildir--grp-count group) count)
+      (setf (nnmaildir--grp-nlist group) new-nlist)
+      (setcdr nlist-pre nlist-post)
+      (unintern prefix flist)
+      (unintern msgid mlist))))
+
+(defun nnmaildir--nlist-art (group num)
+  (let ((entry (assq num (nnmaildir--grp-nlist group))))
+    (if entry
+       (cdr entry))))
+(defmacro nnmaildir--flist-art (list file)
+  `(symbol-value (intern-soft ,file ,list)))
+(defmacro nnmaildir--mlist-art (list msgid)
+  `(symbol-value (intern-soft ,msgid ,list)))
+
+(defun nnmaildir--pgname (server gname)
+  (let ((prefix (nnmaildir--srv-prefix server)))
+    (if prefix (concat prefix gname)
+      (setq gname (gnus-group-prefixed-name gname
+                                           (nnmaildir--srv-method server)))
+      (setf (nnmaildir--srv-prefix server) (gnus-group-real-prefix gname))
+      gname)))
+
+(defun nnmaildir--param (pgname param)
+  (setq param (gnus-group-find-parameter pgname param 'allow-list))
+  (if (vectorp param) (setq param (aref param 0)))
+  (eval param))
+
+(defmacro nnmaildir--with-nntp-buffer (&rest body)
+  (declare (debug (body)))
+  `(with-current-buffer nntp-server-buffer
+     ,@body))
+(defmacro nnmaildir--with-work-buffer (&rest body)
+  (declare (debug (body)))
+  `(with-current-buffer (get-buffer-create " *nnmaildir work*")
+     ,@body))
+(defmacro nnmaildir--with-nov-buffer (&rest body)
+  (declare (debug (body)))
+  `(with-current-buffer (get-buffer-create " *nnmaildir nov*")
+     ,@body))
+(defmacro nnmaildir--with-move-buffer (&rest body)
+  (declare (debug (body)))
+  `(with-current-buffer (get-buffer-create " *nnmaildir move*")
+     ,@body))
+
+(defsubst nnmaildir--subdir (dir subdir)
+  (file-name-as-directory (concat dir subdir)))
+(defsubst nnmaildir--srvgrp-dir (srv-dir gname)
+  (nnmaildir--subdir srv-dir gname))
+(defsubst nnmaildir--tmp       (dir) (nnmaildir--subdir dir "tmp"))
+(defsubst nnmaildir--new       (dir) (nnmaildir--subdir dir "new"))
+(defsubst nnmaildir--cur       (dir) (nnmaildir--subdir dir "cur"))
+(defsubst nnmaildir--nndir     (dir) (nnmaildir--subdir dir ".nnmaildir"))
+(defsubst nnmaildir--nov-dir   (dir) (nnmaildir--subdir dir "nov"))
+(defsubst nnmaildir--marks-dir (dir) (nnmaildir--subdir dir "marks"))
+(defsubst nnmaildir--num-dir   (dir) (nnmaildir--subdir dir "num"))
+
+(defmacro nnmaildir--unlink (file-arg)
+  `(let ((file ,file-arg))
+     (if (file-attributes file) (delete-file file))))
+(defun nnmaildir--mkdir (dir)
+  (or (file-exists-p (file-name-as-directory dir))
+      (make-directory-internal (directory-file-name dir))))
+(defun nnmaildir--mkfile (file)
+  (write-region "" nil file nil 'no-message))
+(defun nnmaildir--delete-dir-files (dir ls)
+  (when (file-attributes dir)
+    (mapc 'delete-file (funcall ls dir 'full "\\`[^.]" 'nosort))
+    (delete-directory dir)))
+
+(defun nnmaildir--group-maxnum (server group)
+  (catch 'return
+    (if (zerop (nnmaildir--grp-count group)) (throw 'return 0))
+    (let ((dir (nnmaildir--srvgrp-dir (nnmaildir--srv-dir server)
+                                   (nnmaildir--grp-name group)))
+         (number-opened 1)
+         attr ino-opened nlink number-linked)
+      (setq dir (nnmaildir--nndir dir)
+           dir (nnmaildir--num-dir dir))
+      (while t
+       (setq attr (file-attributes
+                   (concat dir (number-to-string number-opened))))
+       (or attr (throw 'return (1- number-opened)))
+       (setq ino-opened (nth 10 attr)
+             nlink (nth 1 attr)
+             number-linked (+ number-opened nlink))
+       (if (or (< nlink 1) (< number-linked nlink))
+           (signal 'error '("Arithmetic overflow")))
+       (setq attr (file-attributes
+                   (concat dir (number-to-string number-linked))))
+       (or attr (throw 'return (1- number-linked)))
+       (unless (equal ino-opened (nth 10 attr))
+         (setq number-opened number-linked))))))
+
+;; Make the given server, if non-nil, be the current server.  Then make the
+;; given group, if non-nil, be the current group of the current server.  Then
+;; return the group object for the current group.
+(defun nnmaildir--prepare (server group)
+  (catch 'return
+    (if (null server)
+       (unless (setq server nnmaildir--cur-server)
+         (throw 'return nil))
+      (unless (setq server (intern-soft server nnmaildir--servers))
+       (throw 'return nil))
+      (setq server (symbol-value server)
+           nnmaildir--cur-server server))
+    (let ((groups (nnmaildir--srv-groups server)))
+      (when groups
+       (unless (nnmaildir--srv-method server)
+         (setf (nnmaildir--srv-method server)
+               (or (gnus-server-to-method
+                    (concat "nnmaildir:" (nnmaildir--srv-address server)))
+                   (throw 'return nil))))
+       (if (null group)
+           (nnmaildir--srv-curgrp server)
+         (symbol-value (intern-soft group groups)))))))
+
+(defun nnmaildir--tab-to-space (string)
+  (let ((pos 0))
+    (while (string-match "\t" string pos)
+      (aset string (match-beginning 0) ? )
+      (setq pos (match-end 0))))
+  string)
+
+(defmacro nnmaildir--condcase (errsym body &rest handler)
+  (declare (debug (sexp form body)))
+  `(condition-case ,errsym
+       (let ((system-messages-locale "C")) ,body)
+     (error . ,handler)))
+
+(defun nnmaildir--emlink-p (err)
+  (and (eq (car err) 'file-error)
+       (string= (downcase (caddr err)) "too many links")))
+
+(defun nnmaildir--enoent-p (err)
+  (and (eq (car err) 'file-error)
+       (string= (downcase (caddr err)) "no such file or directory")))
+
+(defun nnmaildir--eexist-p (err)
+  (eq (car err) 'file-already-exists))
+
+(defun nnmaildir--new-number (nndir)
+  "Allocate a new article number by atomically creating a file under NNDIR."
+  (let ((numdir (nnmaildir--num-dir nndir))
+       (make-new-file t)
+       (number-open 1)
+       number-link previous-number-link path-open path-link ino-open)
+    (nnmaildir--mkdir numdir)
+    (catch 'return
+      (while t
+       (setq path-open (concat numdir (number-to-string number-open)))
+       (if (not make-new-file)
+           (setq previous-number-link number-link)
+         (nnmaildir--mkfile path-open)
+         ;; If Emacs had O_CREAT|O_EXCL, we could return number-open here.
+         (setq make-new-file nil
+               previous-number-link 0))
+       (let* ((attr (file-attributes path-open))
+              (nlink (nth 1 attr)))
+         (setq ino-open (nth 10 attr)
+               number-link (+ number-open nlink))
+         (if (or (< nlink 1) (< number-link nlink))
+             (signal 'error '("Arithmetic overflow"))))
+       (if (= number-link previous-number-link)
+           ;; We've already tried this number, in the previous loop iteration,
+           ;; and failed.
+           (signal 'error `("Corrupt internal nnmaildir data" ,path-open)))
+       (setq path-link (concat numdir (number-to-string number-link)))
+       (nnmaildir--condcase err
+           (progn
+             (add-name-to-file path-open path-link)
+             (throw 'return number-link))
+         (cond
+          ((nnmaildir--emlink-p err)
+           (setq make-new-file t
+                 number-open number-link))
+          ((nnmaildir--eexist-p err)
+           (let ((attr (file-attributes path-link)))
+             (unless (equal (nth 10 attr) ino-open)
+               (setq number-open number-link
+                     number-link 0))))
+          (t (signal (car err) (cdr err)))))))))
+
+(defun nnmaildir--update-nov (server group article)
+  (let ((nnheader-file-coding-system 'binary)
+       (srv-dir (nnmaildir--srv-dir server))
+       (storage-version 1) ;; [version article-number msgid [...nov...]]
+       dir gname pgname msgdir prefix suffix file attr mtime novdir novfile
+       nov msgid nov-beg nov-mid nov-end field val old-extra num
+       deactivate-mark)
+    (catch 'return
+      (setq gname (nnmaildir--grp-name group)
+           pgname (nnmaildir--pgname server gname)
+           dir (nnmaildir--srvgrp-dir srv-dir gname)
+           msgdir (if (nnmaildir--param pgname 'read-only)
+                      (nnmaildir--new dir) (nnmaildir--cur dir))
+           prefix (nnmaildir--art-prefix article)
+           suffix (nnmaildir--art-suffix article)
+           file (concat msgdir prefix suffix)
+           attr (file-attributes file))
+      (unless attr
+       (nnmaildir--expired-article group article)
+       (throw 'return nil))
+      (setq mtime (nth 5 attr)
+           attr (nth 7 attr)
+           nov (nnmaildir--art-nov article)
+           dir (nnmaildir--nndir dir)
+           novdir (nnmaildir--nov-dir dir)
+           novfile (concat novdir prefix))
+      (unless (equal nnmaildir--extra nnmail-extra-headers)
+       (setq nnmaildir--extra (copy-sequence nnmail-extra-headers)))
+      (nnmaildir--with-nov-buffer
+       ;; First we'll check for already-parsed NOV data.
+       (cond ((not (file-exists-p novfile))
+              ;; The NOV file doesn't exist; we have to parse the message.
+              (setq nov nil))
+             ((not nov)
+              ;; The file exists, but the data isn't in memory; read the file.
+              (erase-buffer)
+              (nnheader-insert-file-contents novfile)
+              (setq nov (read (current-buffer)))
+              (if (not (and (vectorp nov)
+                            (/= 0 (length nov))
+                            (equal storage-version (aref nov 0))))
+                  ;; This NOV data seems to be in the wrong format.
+                  (setq nov nil)
+                (unless (nnmaildir--art-num   article)
+                  (setf (nnmaildir--art-num   article) (aref nov 1)))
+                (unless (nnmaildir--art-msgid article)
+                  (setf (nnmaildir--art-msgid article) (aref nov 2)))
+                (setq nov (aref nov 3)))))
+       ;; Now check whether the already-parsed data (if we have any) is
+       ;; usable: if the message has been edited or if nnmail-extra-headers
+       ;; has been augmented since this data was parsed from the message,
+       ;; then we have to reparse.  Otherwise it's up-to-date.
+       (when (and nov (equal mtime (nnmaildir--nov-get-mtime nov)))
+         ;; The timestamp matches.  Now check nnmail-extra-headers.
+         (setq old-extra (nnmaildir--nov-get-extra nov))
+         (when (equal nnmaildir--extra old-extra) ;; common case
+           ;; Save memory; use a single copy of the list value.
+           (nnmaildir--nov-set-extra nov nnmaildir--extra)
+           (throw 'return nov))
+         ;; They're not equal, but maybe the new is a subset of the old.
+         (if (null nnmaildir--extra)
+             ;; The empty set is a subset of every set.
+             (throw 'return nov))
+         (if (not (memq nil (mapcar (lambda (e) (memq e old-extra))
+                                    nnmaildir--extra)))
+             (throw 'return nov)))
+       ;; Parse the NOV data out of the message.
+       (erase-buffer)
+       (nnheader-insert-file-contents file)
+       (insert "\n")
+       (goto-char (point-min))
+       (save-restriction
+         (if (search-forward "\n\n" nil 'noerror)
+             (progn
+               (setq nov-mid (count-lines (point) (point-max)))
+               (narrow-to-region (point-min) (1- (point))))
+           (setq nov-mid 0))
+         (goto-char (point-min))
+         (delete-char 1)
+         (setq nov (nnheader-parse-naked-head)
+               field (or (mail-header-lines nov) 0)))
+       (unless (or (zerop field) (nnmaildir--param pgname 'distrust-Lines:))
+         (setq nov-mid field))
+       (setq nov-mid (number-to-string nov-mid)
+             nov-mid (concat (number-to-string attr) "\t" nov-mid))
+       (save-match-data
+         (setq field (or (mail-header-references nov) ""))
+         (nnmaildir--tab-to-space field)
+         (setq nov-mid (concat field "\t" nov-mid)
+               nov-beg (mapconcat
+                         (lambda (f) (nnmaildir--tab-to-space (or f "")))
+                         (list (mail-header-subject nov)
+                               (mail-header-from nov)
+                               (mail-header-date nov)) "\t")
+               nov-end (mapconcat
+                         (lambda (extra)
+                           (setq field (symbol-name (car extra))
+                                 val (cdr extra))
+                           (nnmaildir--tab-to-space field)
+                           (nnmaildir--tab-to-space val)
+                           (concat field ": " val))
+                         (mail-header-extra nov) "\t")))
+       (setq msgid (mail-header-id nov))
+       (if (or (null msgid) (nnheader-fake-message-id-p msgid))
+           (setq msgid (concat "<" prefix "@nnmaildir>")))
+       (nnmaildir--tab-to-space msgid)
+       ;; The data is parsed; create an nnmaildir NOV structure.
+       (setq nov (nnmaildir--nov-new nov-beg nov-mid nov-end mtime
+                                     nnmaildir--extra)
+             num (nnmaildir--art-num article))
+       (unless num
+         (setq num (nnmaildir--new-number dir))
+         (setf (nnmaildir--art-num article) num))
+       ;; Store this new NOV data in a file
+       (erase-buffer)
+       (prin1 (vector storage-version num msgid nov) (current-buffer))
+       (setq file (concat novfile ":"))
+       (nnmaildir--unlink file)
+       (gmm-write-region (point-min) (point-max) file nil 'no-message nil
+                         'excl))
+      (rename-file file novfile 'replace)
+      (setf (nnmaildir--art-msgid article) msgid)
+      nov)))
+
+(defun nnmaildir--cache-nov (group article nov)
+  (let ((cache (nnmaildir--grp-cache group))
+       (index (nnmaildir--grp-index group))
+       goner)
+    (unless (nnmaildir--art-nov article)
+      (setq goner (aref cache index))
+      (if goner (setf (nnmaildir--art-nov goner) nil))
+      (aset cache index article)
+      (setf (nnmaildir--grp-index group) (% (1+ index) (length cache))))
+    (setf (nnmaildir--art-nov article) nov)))
+
+(defun nnmaildir--grp-add-art (server group article)
+  (let ((nov (nnmaildir--update-nov server group article))
+       count num min nlist nlist-cdr insert-nlist)
+    (when nov
+      (setq count (1+ (nnmaildir--grp-count group))
+           num (nnmaildir--art-num article)
+           min (if (= count 1) num
+                 (min num (nnmaildir--grp-min group)))
+           nlist (nnmaildir--grp-nlist group))
+      (if (or (null nlist) (> num (caar nlist)))
+         (setq nlist (cons (cons num article) nlist))
+       (setq insert-nlist t
+             nlist-cdr (cdr nlist))
+       (while (and nlist-cdr (< num (caar nlist-cdr)))
+         (setq nlist nlist-cdr
+               nlist-cdr (cdr nlist))))
+      (let ((inhibit-quit t))
+       (setf (nnmaildir--grp-count group) count)
+       (setf (nnmaildir--grp-min group) min)
+       (if insert-nlist
+           (setcdr nlist (cons (cons num article) nlist-cdr))
+         (setf (nnmaildir--grp-nlist group) nlist))
+       (set (intern (nnmaildir--art-prefix article)
+                    (nnmaildir--grp-flist group))
+            article)
+       (set (intern (nnmaildir--art-msgid article)
+                    (nnmaildir--grp-mlist group))
+            article)
+       (set (intern (nnmaildir--grp-name group)
+                    (nnmaildir--srv-groups server))
+            group))
+      (nnmaildir--cache-nov group article nov)
+      t)))
+
+(defun nnmaildir--group-ls (server pgname)
+  (or (nnmaildir--param pgname 'directory-files)
+      (nnmaildir--srv-ls server)))
+
+(defun nnmaildir-article-number-to-file-name
+  (number group-name server-address-string)
+  (let ((group (nnmaildir--prepare server-address-string group-name))
+       article dir pgname)
+    (catch 'return
+      (unless group
+       ;; The given group or server does not exist.
+       (throw 'return nil))
+      (setq article (nnmaildir--nlist-art group number))
+      (unless article
+       ;; The given article number does not exist in this group.
+       (throw 'return nil))
+      (setq pgname (nnmaildir--pgname nnmaildir--cur-server group-name)
+           dir (nnmaildir--srv-dir nnmaildir--cur-server)
+           dir (nnmaildir--srvgrp-dir dir group-name)
+           dir (if (nnmaildir--param pgname 'read-only)
+                   (nnmaildir--new dir) (nnmaildir--cur dir)))
+      (concat dir (nnmaildir--art-prefix article)
+             (nnmaildir--art-suffix article)))))
+
+(defun nnmaildir-article-number-to-base-name
+  (number group-name server-address-string)
+  (let ((x (nnmaildir--prepare server-address-string group-name)))
+    (when x
+      (setq x (nnmaildir--nlist-art x number))
+      (and x (cons (nnmaildir--art-prefix x)
+                  (nnmaildir--art-suffix x))))))
+
+(defun nnmaildir-base-name-to-article-number
+  (base-name group-name server-address-string)
+  (let ((x (nnmaildir--prepare server-address-string group-name)))
+    (when x
+      (setq x (nnmaildir--grp-flist x)
+           x (nnmaildir--flist-art x base-name))
+      (and x (nnmaildir--art-num x)))))
+
+(defun nnmaildir--nlist-iterate (nlist ranges func)
+  (let (entry high low nlist2)
+    (if (eq ranges 'all)
+       (setq ranges `((1 . ,(caar nlist)))))
+    (while ranges
+      (setq entry (car ranges) ranges (cdr ranges))
+      (while (and ranges (eq entry (car ranges)))
+       (setq ranges (cdr ranges))) ;; skip duplicates
+      (if (numberp entry)
+         (setq low entry
+               high entry)
+       (setq low (car entry)
+             high (cdr entry)))
+      (setq nlist2 nlist) ;; Don't assume any sorting of ranges
+      (catch 'iterate-loop
+       (while nlist2
+         (if (<= (caar nlist2) high) (throw 'iterate-loop nil))
+         (setq nlist2 (cdr nlist2))))
+      (catch 'iterate-loop
+       (while nlist2
+         (setq entry (car nlist2) nlist2 (cdr nlist2))
+         (if (< (car entry) low) (throw 'iterate-loop nil))
+         (funcall func (cdr entry)))))))
+
+(defun nnmaildir--up2-1 (n)
+  (if (zerop n) 1 (1- (lsh 1 (1+ (logb n))))))
+
+(defun nnmaildir--system-name ()
+  (gnus-replace-in-string
+   (gnus-replace-in-string
+    (gnus-replace-in-string
+     (system-name)
+     "\\\\" "\\134" 'literal)
+    "/" "\\057" 'literal)
+   ":" "\\072" 'literal))
+
+(defun nnmaildir-request-type (_group &optional _article)
+  'mail)
+
+(defun nnmaildir-status-message (&optional server)
+  (nnmaildir--prepare server nil)
+  (nnmaildir--srv-error nnmaildir--cur-server))
+
+(defun nnmaildir-server-opened (&optional server)
+  (and nnmaildir--cur-server
+       (if server
+          (string-equal server (nnmaildir--srv-address nnmaildir--cur-server))
+        t)
+       (nnmaildir--srv-groups nnmaildir--cur-server)
+       t))
+
+(defun nnmaildir-open-server (server &optional defs)
+  (let ((x server)
+       dir size)
+    (catch 'return
+      (setq server (intern-soft x nnmaildir--servers))
+      (if server
+         (and (setq server (symbol-value server))
+              (nnmaildir--srv-groups server)
+              (setq nnmaildir--cur-server server)
+              (throw 'return t))
+       (setq server (make-nnmaildir--srv :address x))
+       (let ((inhibit-quit t))
+         (set (intern x nnmaildir--servers) server)))
+      (setq dir (assq 'directory defs))
+      (unless dir
+       (setf (nnmaildir--srv-error server)
+             "You must set \"directory\" in the select method")
+       (throw 'return nil))
+      (setq dir (cadr dir)
+           dir (eval dir)
+           dir (expand-file-name dir)
+           dir (file-name-as-directory dir))
+      (unless (file-exists-p dir)
+       (setf (nnmaildir--srv-error server) (concat "No such directory: " dir))
+       (throw 'return nil))
+      (setf (nnmaildir--srv-dir server) dir)
+      (setq x (assq 'directory-files defs))
+      (if (null x)
+         (setq x (if nnheader-directory-files-is-safe 'directory-files
+                   'nnheader-directory-files-safe))
+       (setq x (cadr x))
+       (unless (functionp x)
+         (setf (nnmaildir--srv-error server)
+               (concat "Not a function: " (prin1-to-string x)))
+         (throw 'return nil)))
+      (setf (nnmaildir--srv-ls server) x)
+      (setq size (length (funcall x dir nil "\\`[^.]" 'nosort))
+           size (nnmaildir--up2-1 size))
+      (and (setq x (assq 'get-new-mail defs))
+          (setq x (cdr x))
+          (car x)
+          (setf (nnmaildir--srv-gnm server) t)
+          (require 'nnmail))
+      (setq x (assq 'target-prefix defs))
+      (if x
+         (progn
+           (setq x (cadr x)
+                 x (eval x))
+           (setf (nnmaildir--srv-target-prefix server) x))
+       (setq x (assq 'create-directory defs))
+       (if x
+           (progn
+             (setq x (cadr x)
+                   x (eval x)
+                   x (file-name-as-directory x))
+             (setf (nnmaildir--srv-target-prefix server) x))
+         (setf (nnmaildir--srv-target-prefix server) "")))
+      (setf (nnmaildir--srv-groups server) (make-vector size 0))
+      (setq nnmaildir--cur-server server)
+      t)))
+
+(defun nnmaildir--parse-filename (file)
+  (let ((prefix (car file))
+       timestamp len)
+    (if (string-match "\\`\\([0-9]+\\)\\(\\..*\\)\\'" prefix)
+       (progn
+         (setq timestamp (concat "0000" (match-string 1 prefix))
+               len (- (length timestamp) 4))
+         (vector (string-to-number (substring timestamp 0 len))
+                 (string-to-number (substring timestamp len))
+                 (match-string 2 prefix)
+                 file))
+      file)))
+
+(defun nnmaildir--sort-files (a b)
+  (catch 'return
+    (if (consp a)
+       (throw 'return (and (consp b) (string-lessp (car a) (car b)))))
+    (if (consp b) (throw 'return t))
+    (if (< (aref a 0) (aref b 0)) (throw 'return t))
+    (if (> (aref a 0) (aref b 0)) (throw 'return nil))
+    (if (< (aref a 1) (aref b 1)) (throw 'return t))
+    (if (> (aref a 1) (aref b 1)) (throw 'return nil))
+    (string-lessp (aref a 2) (aref b 2))))
+
+(defun nnmaildir--scan (gname scan-msgs groups _method srv-dir srv-ls)
+  (catch 'return
+    (let ((36h-ago (- (car (current-time)) 2))
+         absdir nndir tdir ndir cdir nattr cattr isnew pgname read-only ls
+         files num dir flist group x)
+      (setq absdir (nnmaildir--srvgrp-dir srv-dir gname)
+           nndir (nnmaildir--nndir absdir))
+      (unless (file-exists-p absdir)
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (concat "No such directory: " absdir))
+       (throw 'return nil))
+      (setq tdir (nnmaildir--tmp absdir)
+           ndir (nnmaildir--new absdir)
+           cdir (nnmaildir--cur absdir)
+           nattr (file-attributes ndir)
+           cattr (file-attributes cdir))
+      (unless (and (file-exists-p tdir) nattr cattr)
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (concat "Not a maildir: " absdir))
+       (throw 'return nil))
+      (setq group (nnmaildir--prepare nil gname)
+           pgname (nnmaildir--pgname nnmaildir--cur-server gname))
+      (if group
+         (setq isnew nil)
+       (setq isnew t
+             group (make-nnmaildir--grp :name gname :index 0))
+       (nnmaildir--mkdir nndir)
+       (nnmaildir--mkdir (nnmaildir--nov-dir   nndir))
+       (nnmaildir--mkdir (nnmaildir--marks-dir nndir)))
+      (setq read-only (nnmaildir--param pgname 'read-only)
+           ls (or (nnmaildir--param pgname 'directory-files) srv-ls))
+      (unless read-only
+       (setq x (nth 11 (file-attributes tdir)))
+       (unless (and (equal x (nth 11 nattr)) (equal x (nth 11 cattr)))
+         (setf (nnmaildir--srv-error nnmaildir--cur-server)
+               (concat "Maildir spans filesystems: " absdir))
+         (throw 'return nil))
+       (dolist (file (funcall ls tdir 'full "\\`[^.]" 'nosort))
+         (setq x (file-attributes file))
+         (if (or (> (cadr x) 1) (< (car (nth 4 x)) 36h-ago))
+             (delete-file file))))
+      (or scan-msgs
+         isnew
+         (throw 'return t))
+      (setq nattr (nth 5 nattr))
+      (if (equal nattr (nnmaildir--grp-new group))
+         (setq nattr nil))
+      (if read-only (setq dir (and (or isnew nattr) ndir))
+       (when (or isnew nattr)
+         (dolist (file  (funcall ls ndir nil "\\`[^.]" 'nosort))
+           (setq x (concat ndir file))
+           (and (time-less-p (nth 5 (file-attributes x)) (current-time))
+                (rename-file x (concat cdir (nnmaildir--ensure-suffix file)))))
+         (setf (nnmaildir--grp-new group) nattr))
+       (setq cattr (nth 5 (file-attributes cdir)))
+       (if (equal cattr (nnmaildir--grp-cur group))
+           (setq cattr nil))
+       (setq dir (and (or isnew cattr) cdir)))
+      (unless dir (throw 'return t))
+      (setq files (funcall ls dir nil "\\`[^.]" 'nosort)
+           files (save-match-data
+                   (mapcar
+                    (lambda (f)
+                      (string-match "\\`\\([^:]*\\)\\(\\(:.*\\)?\\)\\'" f)
+                      (cons (match-string 1 f) (match-string 2 f)))
+                    files)))
+      (when isnew
+       (setq num (nnmaildir--up2-1 (length files)))
+       (setf (nnmaildir--grp-flist group) (make-vector num 0))
+       (setf (nnmaildir--grp-mlist group) (make-vector num 0))
+       (setf (nnmaildir--grp-mmth group) (make-vector 1 0))
+       (setq num (nnmaildir--param pgname 'nov-cache-size))
+       (if (numberp num) (if (< num 1) (setq num 1))
+         (setq num 16
+               cdir (nnmaildir--marks-dir nndir)
+               ndir (nnmaildir--subdir cdir "tick")
+               cdir (nnmaildir--subdir cdir "read"))
+         (dolist (prefix-suffix files)
+           (let ((prefix (car prefix-suffix))
+                 (suffix (cdr prefix-suffix)))
+             ;; increase num for each unread or ticked article
+             (when (or
+                    ;; first look for marks in suffix, if it's valid...
+                    (when (and (stringp suffix)
+                               (gnus-string-prefix-p ":2," suffix))
+                      (or
+                       (not (gnus-string-match-p
+                             (string (nnmaildir--mark-to-flag 'read)) suffix))
+                       (gnus-string-match-p
+                        (string (nnmaildir--mark-to-flag 'tick)) suffix)))
+                    ;; then look in marks directories
+                    (not (file-exists-p (concat cdir prefix)))
+                    (file-exists-p (concat ndir prefix)))
+               (incf num)))))
+       (setf (nnmaildir--grp-cache group) (make-vector num nil))
+        (let ((inhibit-quit t))
+          (set (intern gname groups) group))
+       (or scan-msgs (throw 'return t)))
+      (setq flist (nnmaildir--grp-flist group)
+           files (mapcar
+                  (lambda (file)
+                    (and (null (nnmaildir--flist-art flist (car file)))
+                         file))
+                  files)
+           files (delq nil files)
+           files (mapcar 'nnmaildir--parse-filename files)
+           files (sort files 'nnmaildir--sort-files))
+      (dolist (file files)
+       (setq file (if (consp file) file (aref file 3))
+             x (make-nnmaildir--art :prefix (car file) :suffix (cdr file)))
+       (nnmaildir--grp-add-art nnmaildir--cur-server group x))
+      (if read-only (setf (nnmaildir--grp-new group) nattr)
+       (setf (nnmaildir--grp-cur group) cattr)))
+    t))
+
+(defvar nnmaildir-get-new-mail)
+(defvar nnmaildir-group-alist)
+(defvar nnmaildir-active-file)
+
+(defun nnmaildir-request-scan (&optional scan-group server)
+  (let ((coding-system-for-write nnheader-file-coding-system)
+       (buffer-file-coding-system nil)
+       (file-coding-system-alist nil)
+       (nnmaildir-get-new-mail t)
+       (nnmaildir-group-alist nil)
+       (nnmaildir-active-file nil)
+       x srv-ls srv-dir method groups target-prefix dirs seen
+       deactivate-mark)
+    (nnmaildir--prepare server nil)
+    (setq srv-ls (nnmaildir--srv-ls nnmaildir--cur-server)
+         srv-dir (nnmaildir--srv-dir nnmaildir--cur-server)
+         method (nnmaildir--srv-method nnmaildir--cur-server)
+         groups (nnmaildir--srv-groups nnmaildir--cur-server)
+         target-prefix (nnmaildir--srv-target-prefix nnmaildir--cur-server))
+    (nnmaildir--with-work-buffer
+      (save-match-data
+       (if (stringp scan-group)
+           (if (nnmaildir--scan scan-group t groups method srv-dir srv-ls)
+               (if (nnmaildir--srv-gnm nnmaildir--cur-server)
+                   (nnmail-get-new-mail 'nnmaildir nil nil scan-group))
+             (unintern scan-group groups))
+         (setq x (nth 5 (file-attributes srv-dir))
+               scan-group (null scan-group))
+         (if (equal x (nnmaildir--srv-mtime nnmaildir--cur-server))
+             (if scan-group
+                 (mapatoms (lambda (sym)
+                             (nnmaildir--scan (symbol-name sym) t groups
+                                              method srv-dir srv-ls))
+                           groups))
+           (setq dirs (funcall srv-ls srv-dir nil "\\`[^.]" 'nosort)
+                 dirs (if (zerop (length target-prefix))
+                          dirs
+                        (gnus-remove-if
+                         (lambda (dir)
+                           (and (>= (length dir) (length target-prefix))
+                                (string= (substring dir 0
+                                                    (length target-prefix))
+                                         target-prefix)))
+                         dirs))
+                 seen (nnmaildir--up2-1 (length dirs))
+                 seen (make-vector seen 0))
+           (dolist (grp-dir dirs)
+             (if (nnmaildir--scan grp-dir scan-group groups method srv-dir
+                                  srv-ls)
+                 (intern grp-dir seen)))
+           (setq x nil)
+           (mapatoms (lambda (group)
+                       (setq group (symbol-name group))
+                       (unless (intern-soft group seen)
+                         (setq x (cons group x))))
+                     groups)
+           (dolist (grp x)
+             (unintern grp groups))
+           (setf (nnmaildir--srv-mtime nnmaildir--cur-server)
+                 (nth 5 (file-attributes srv-dir))))
+         (and scan-group
+              (nnmaildir--srv-gnm nnmaildir--cur-server)
+              (nnmail-get-new-mail 'nnmaildir nil nil))))))
+  t)
+
+(defun nnmaildir-request-list (&optional server)
+  (nnmaildir-request-scan 'find-new-groups server)
+  (let (pgname ro deactivate-mark)
+    (nnmaildir--prepare server nil)
+    (nnmaildir--with-nntp-buffer
+      (erase-buffer)
+      (mapatoms (lambda (group)
+                 (setq pgname (symbol-name group)
+                       pgname (nnmaildir--pgname nnmaildir--cur-server pgname)
+                       group (symbol-value group)
+                       ro (nnmaildir--param pgname 'read-only))
+                 (insert (gnus-replace-in-string
+                          (nnmaildir--grp-name group) " " "\\ " t)
+                         " ")
+                  (princ (nnmaildir--group-maxnum nnmaildir--cur-server group)
+                        nntp-server-buffer)
+                 (insert " ")
+                  (princ (nnmaildir--grp-min group) nntp-server-buffer)
+                 (insert " " (if ro "n" "y") "\n"))
+               (nnmaildir--srv-groups nnmaildir--cur-server))))
+  t)
+
+(defun nnmaildir-request-newgroups (_date &optional server)
+  (nnmaildir-request-list server))
+
+(defun nnmaildir-retrieve-groups (groups &optional server)
+  (let (group deactivate-mark)
+    (nnmaildir--prepare server nil)
+    (nnmaildir--with-nntp-buffer
+      (erase-buffer)
+      (dolist (gname groups)
+       (setq group (nnmaildir--prepare nil gname))
+       (if (null group) (insert "411 no such news group\n")
+         (insert "211 ")
+         (princ (nnmaildir--grp-count group) nntp-server-buffer)
+         (insert " ")
+         (princ (nnmaildir--grp-min   group) nntp-server-buffer)
+         (insert " ")
+         (princ (nnmaildir--group-maxnum nnmaildir--cur-server group)
+                nntp-server-buffer)
+         (insert " "
+                 (gnus-replace-in-string gname " " "\\ " t)
+                 "\n")))))
+  'group)
+
+(defun nnmaildir-request-update-info (gname info &optional server)
+  (let* ((group (nnmaildir--prepare server gname))
+        (curdir (nnmaildir--cur
+                 (nnmaildir--srvgrp-dir
+                  (nnmaildir--srv-dir nnmaildir--cur-server) gname)))
+        (curdir-mtime (nth 5 (file-attributes curdir)))
+        pgname flist always-marks never-marks old-marks dir
+        all-marks marks ranges markdir read ls
+        old-mmth new-mmth mtime existing missing deactivate-mark)
+    (catch 'return
+      (unless group
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (concat "No such group: " gname))
+       (throw 'return nil))
+      (setq gname (nnmaildir--grp-name group)
+           pgname (nnmaildir--pgname nnmaildir--cur-server gname)
+           flist (nnmaildir--grp-flist group))
+      (when (zerop (nnmaildir--grp-count group))
+       (gnus-info-set-read info nil)
+       (gnus-info-set-marks info nil 'extend)
+       (throw 'return info))
+      (setq old-marks (cons 'read (gnus-info-read info))
+           old-marks (cons old-marks (gnus-info-marks info))
+           always-marks (nnmaildir--param pgname 'always-marks)
+           never-marks (nnmaildir--param pgname 'never-marks)
+           existing (nnmaildir--grp-nlist group)
+           existing (mapcar 'car existing)
+           existing (nreverse existing)
+           existing (gnus-compress-sequence existing 'always-list)
+           missing (list (cons 1 (nnmaildir--group-maxnum
+                                  nnmaildir--cur-server group)))
+           missing (gnus-range-difference missing existing)
+           dir (nnmaildir--srv-dir nnmaildir--cur-server)
+           dir (nnmaildir--srvgrp-dir dir gname)
+           dir (nnmaildir--nndir dir)
+           dir (nnmaildir--marks-dir dir)
+            ls (nnmaildir--group-ls nnmaildir--cur-server pgname)
+           all-marks (gnus-delete-duplicates
+                      ;; get mark names from mark dirs and from flag
+                      ;; mappings
+                      (append
+                       (mapcar 'cdr nnmaildir-flag-mark-mapping)
+                       (mapcar 'intern (funcall ls dir nil "\\`[^.]" 'nosort))))
+           new-mmth (nnmaildir--up2-1 (length all-marks))
+           new-mmth (make-vector new-mmth 0)
+           old-mmth (nnmaildir--grp-mmth group))
+      (dolist (mark all-marks)
+       (setq markdir (nnmaildir--subdir dir (symbol-name mark))
+             ranges nil)
+       (catch 'got-ranges
+         (if (memq mark never-marks) (throw 'got-ranges nil))
+         (when (memq mark always-marks)
+           (setq ranges existing)
+           (throw 'got-ranges nil))
+         ;; Find the mtime for this mark.  If this mark can be expressed as
+         ;; a filename flag, get the later of the mtimes for markdir and
+         ;; curdir, otherwise only the markdir counts.
+         (setq mtime
+               (let ((markdir-mtime (nth 5 (file-attributes markdir))))
+                 (cond
+                  ((null (nnmaildir--mark-to-flag mark))
+                   markdir-mtime)
+                  ((null markdir-mtime)
+                   curdir-mtime)
+                  ((null curdir-mtime)
+                   ;; this should never happen...
+                   markdir-mtime)
+                  ((time-less-p markdir-mtime curdir-mtime)
+                   curdir-mtime)
+                  (t
+                   markdir-mtime))))
+         (set (intern (symbol-name mark) new-mmth) mtime)
+         (when (equal mtime (symbol-value (intern-soft (symbol-name mark) old-mmth)))
+           (setq ranges (assq mark old-marks))
+           (if ranges (setq ranges (cdr ranges)))
+           (throw 'got-ranges nil))
+         (let ((article-list nil))
+           ;; Consider the article marked if it either has the flag in the
+           ;; filename, or is in the markdir.  As you'd rarely remove a
+           ;; flag/mark, this should avoid losing information in the most
+           ;; common usage pattern.
+           (or
+            (let ((flag (nnmaildir--mark-to-flag mark)))
+              ;; If this mark has a corresponding maildir flag...
+              (when flag
+                (let ((regexp
+                       (concat "\\`[^.].*:2,[A-Z]*" (string flag))))
+                  ;; ...then find all files with that flag.
+                  (dolist (filename (funcall ls curdir nil regexp 'nosort))
+                    (let* ((prefix (car (split-string filename ":2,")))
+                           (article (nnmaildir--flist-art flist prefix)))
+                      (when article
+                        (push (nnmaildir--art-num article) article-list)))))))
+            ;; Also check Gnus-specific mark directory, if it exists.
+            (when (file-directory-p markdir)
+              (dolist (prefix (funcall ls markdir nil "\\`[^.]" 'nosort))
+                (let ((article (nnmaildir--flist-art flist prefix)))
+                  (when article
+                    (push (nnmaildir--art-num article) article-list))))))
+           (setq ranges (gnus-add-to-range ranges (sort article-list '<)))))
+       (if (eq mark 'read) (setq read ranges)
+         (if ranges (setq marks (cons (cons mark ranges) marks)))))
+      (gnus-info-set-read info (gnus-range-add read missing))
+      (gnus-info-set-marks info marks 'extend)
+      (setf (nnmaildir--grp-mmth group) new-mmth)
+      info)))
+
+(defun nnmaildir-request-group (gname &optional server fast _info)
+  (let ((group (nnmaildir--prepare server gname))
+       deactivate-mark)
+    (catch 'return
+      (unless group
+       ;; (insert "411 no such news group\n")
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (concat "No such group: " gname))
+       (throw 'return nil))
+      (setf (nnmaildir--srv-curgrp nnmaildir--cur-server) group)
+      (if fast (throw 'return t))
+      (nnmaildir--with-nntp-buffer
+       (erase-buffer)
+       (insert "211 ")
+       (princ (nnmaildir--grp-count group) nntp-server-buffer)
+       (insert " ")
+       (princ (nnmaildir--grp-min   group) nntp-server-buffer)
+       (insert " ")
+       (princ (nnmaildir--group-maxnum nnmaildir--cur-server group)
+              nntp-server-buffer)
+       (insert " " (gnus-replace-in-string gname " " "\\ " t) "\n")
+       t))))
+
+(defun nnmaildir-request-create-group (gname &optional server _args)
+  (nnmaildir--prepare server nil)
+  (catch 'return
+    (let ((target-prefix (nnmaildir--srv-target-prefix nnmaildir--cur-server))
+         srv-dir dir groups)
+      (when (zerop (length gname))
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             "Invalid (empty) group name")
+       (throw 'return nil))
+      (when (eq (aref "." 0) (aref gname 0))
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             "Group names may not start with \".\"")
+       (throw 'return nil))
+      (when (save-match-data (string-match "[\0/\t]" gname))
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (concat "Invalid characters (null, tab, or /) in group name: "
+                     gname))
+       (throw 'return nil))
+      (setq groups (nnmaildir--srv-groups nnmaildir--cur-server))
+      (when (intern-soft gname groups)
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (concat "Group already exists: " gname))
+       (throw 'return nil))
+      (setq srv-dir (nnmaildir--srv-dir nnmaildir--cur-server))
+      (if (file-name-absolute-p target-prefix)
+         (setq dir (expand-file-name target-prefix))
+       (setq dir srv-dir
+             dir (file-truename dir)
+             dir (concat dir target-prefix)))
+      (setq dir (nnmaildir--subdir dir gname))
+      (nnmaildir--mkdir dir)
+      (nnmaildir--mkdir (nnmaildir--tmp dir))
+      (nnmaildir--mkdir (nnmaildir--new dir))
+      (nnmaildir--mkdir (nnmaildir--cur dir))
+      (unless (string= target-prefix "")
+       (make-symbolic-link (concat target-prefix gname)
+                           (concat srv-dir gname)))
+      (nnmaildir-request-scan 'find-new-groups))))
+
+(defun nnmaildir-request-rename-group (gname new-name &optional server)
+  (let ((group (nnmaildir--prepare server gname))
+       (coding-system-for-write nnheader-file-coding-system)
+       (buffer-file-coding-system nil)
+       (file-coding-system-alist nil)
+       srv-dir x groups)
+    (catch 'return
+      (unless group
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (concat "No such group: " gname))
+       (throw 'return nil))
+      (when (zerop (length new-name))
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             "Invalid (empty) group name")
+       (throw 'return nil))
+      (when (eq (aref "." 0) (aref new-name 0))
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             "Group names may not start with \".\"")
+       (throw 'return nil))
+      (when (save-match-data (string-match "[\0/\t]" new-name))
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (concat "Invalid characters (null, tab, or /) in group name: "
+                     new-name))
+       (throw 'return nil))
+      (if (string-equal gname new-name) (throw 'return t))
+      (when (intern-soft new-name
+                        (nnmaildir--srv-groups nnmaildir--cur-server))
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (concat "Group already exists: " new-name))
+       (throw 'return nil))
+      (setq srv-dir (nnmaildir--srv-dir nnmaildir--cur-server))
+      (condition-case err
+         (rename-file (concat srv-dir gname)
+                      (concat srv-dir new-name))
+       (error
+        (setf (nnmaildir--srv-error nnmaildir--cur-server)
+              (concat "Error renaming link: " (prin1-to-string err)))
+        (throw 'return nil)))
+      (setq x (nnmaildir--srv-groups nnmaildir--cur-server)
+           groups (make-vector (length x) 0))
+      (mapatoms (lambda (sym)
+                 (unless (eq (symbol-value sym) group)
+                   (set (intern (symbol-name sym) groups)
+                        (symbol-value sym))))
+               x)
+      (setq group (copy-sequence group))
+      (setf (nnmaildir--grp-name group) new-name)
+      (set (intern new-name groups) group)
+      (setf (nnmaildir--srv-groups nnmaildir--cur-server) groups)
+      t)))
+
+(defun nnmaildir-request-delete-group (gname force &optional server)
+  (let ((group (nnmaildir--prepare server gname))
+       pgname grp-dir target dir ls deactivate-mark)
+    (catch 'return
+      (unless group
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (concat "No such group: " gname))
+       (throw 'return nil))
+      (setq gname (nnmaildir--grp-name group)
+           pgname (nnmaildir--pgname nnmaildir--cur-server gname)
+           grp-dir (nnmaildir--srv-dir nnmaildir--cur-server)
+           target (car (file-attributes (concat grp-dir gname)))
+           grp-dir (nnmaildir--srvgrp-dir grp-dir gname))
+      (unless (or force (stringp target))
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (concat "Not a symlink: " gname))
+       (throw 'return nil))
+      (if (eq group (nnmaildir--srv-curgrp nnmaildir--cur-server))
+         (setf (nnmaildir--srv-curgrp nnmaildir--cur-server) nil))
+      (unintern gname (nnmaildir--srv-groups nnmaildir--cur-server))
+      (if (not force)
+         (progn
+           (setq grp-dir (directory-file-name grp-dir))
+           (nnmaildir--unlink grp-dir))
+       (setq ls (nnmaildir--group-ls nnmaildir--cur-server pgname))
+       (if (nnmaildir--param pgname 'read-only)
+           (progn (delete-directory  (nnmaildir--tmp grp-dir))
+                  (nnmaildir--unlink (nnmaildir--new grp-dir))
+                  (delete-directory  (nnmaildir--cur grp-dir)))
+         (nnmaildir--delete-dir-files (nnmaildir--tmp grp-dir) ls)
+         (nnmaildir--delete-dir-files (nnmaildir--new grp-dir) ls)
+         (nnmaildir--delete-dir-files (nnmaildir--cur grp-dir) ls))
+       (setq dir (nnmaildir--nndir grp-dir))
+       (dolist (subdir `(,(nnmaildir--nov-dir dir) ,(nnmaildir--num-dir dir)
+                         ,@(funcall ls (nnmaildir--marks-dir dir)
+                                    'full "\\`[^.]" 'nosort)))
+         (nnmaildir--delete-dir-files subdir ls))
+       (setq dir (nnmaildir--nndir grp-dir))
+       (nnmaildir--unlink (concat dir "markfile"))
+       (nnmaildir--unlink (concat dir "markfile{new}"))
+       (delete-directory (nnmaildir--marks-dir dir))
+       (delete-directory dir)
+       (if (not (stringp target))
+           (delete-directory grp-dir)
+         (setq grp-dir (directory-file-name grp-dir)
+               dir target)
+         (unless (eq (aref "/" 0) (aref dir 0))
+           (setq dir (concat (file-truename
+                              (nnmaildir--srv-dir nnmaildir--cur-server))
+                             dir)))
+         (delete-directory dir)
+         (nnmaildir--unlink grp-dir)))
+      t)))
+
+(defun nnmaildir-retrieve-headers (articles &optional gname server fetch-old)
+  (let ((group (nnmaildir--prepare server gname))
+       nlist mlist article num start stop nov insert-nov
+       deactivate-mark)
+    (setq insert-nov
+         (lambda (article)
+           (setq nov (nnmaildir--update-nov nnmaildir--cur-server group
+                                            article))
+           (when nov
+             (nnmaildir--cache-nov group article nov)
+             (setq num (nnmaildir--art-num article))
+             (princ num nntp-server-buffer)
+             (insert "\t" (nnmaildir--nov-get-beg nov) "\t"
+                     (nnmaildir--art-msgid article) "\t"
+                     (nnmaildir--nov-get-mid nov) "\tXref: nnmaildir "
+                     (gnus-replace-in-string gname " " "\\ " t) ":")
+             (princ num nntp-server-buffer)
+             (insert "\t" (nnmaildir--nov-get-end nov) "\n"))))
+    (catch 'return
+      (unless group
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (if gname (concat "No such group: " gname) "No current group"))
+       (throw 'return nil))
+      (nnmaildir--with-nntp-buffer
+       (erase-buffer)
+       (setq mlist (nnmaildir--grp-mlist group)
+             nlist (nnmaildir--grp-nlist group)
+             gname (nnmaildir--grp-name group))
+       (cond
+        ((null nlist))
+        ((and fetch-old (not (numberp fetch-old)))
+         (nnmaildir--nlist-iterate nlist 'all insert-nov))
+        ((null articles))
+        ((stringp (car articles))
+         (dolist (msgid articles)
+           (setq article (nnmaildir--mlist-art mlist msgid))
+           (if article (funcall insert-nov article))))
+        (t
+         (if fetch-old
+             ;; Assume the article range list is sorted ascending
+             (setq stop (car articles)
+                   start (car (last articles))
+                   stop  (if (numberp stop)  stop  (car stop))
+                   start (if (numberp start) start (cdr start))
+                   stop (- stop fetch-old)
+                   stop (if (< stop 1) 1 stop)
+                   articles (list (cons stop start))))
+         (nnmaildir--nlist-iterate nlist articles insert-nov)))
+       (sort-numeric-fields 1 (point-min) (point-max))
+       'nov))))
+
+(defun nnmaildir-request-article (num-msgid &optional gname server to-buffer)
+  (let ((group (nnmaildir--prepare server gname))
+       (case-fold-search t)
+       list article dir pgname deactivate-mark)
+    (catch 'return
+      (unless group
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (if gname (concat "No such group: " gname) "No current group"))
+       (throw 'return nil))
+      (if (numberp num-msgid)
+         (setq article (nnmaildir--nlist-art group num-msgid))
+       (setq list (nnmaildir--grp-mlist group)
+             article (nnmaildir--mlist-art list num-msgid))
+       (if article (setq num-msgid (nnmaildir--art-num article))
+         (catch 'found
+           (mapatoms
+              (lambda (group-sym)
+                (setq group (symbol-value group-sym)
+                      list (nnmaildir--grp-mlist group)
+                      article (nnmaildir--mlist-art list num-msgid))
+                (when article
+                  (setq num-msgid (nnmaildir--art-num article))
+                  (throw 'found nil)))
+              (nnmaildir--srv-groups nnmaildir--cur-server))))
+       (unless article
+         (setf (nnmaildir--srv-error nnmaildir--cur-server) "No such article")
+         (throw 'return nil)))
+      (setq gname (nnmaildir--grp-name group)
+           pgname (nnmaildir--pgname nnmaildir--cur-server gname)
+           dir (nnmaildir--srv-dir nnmaildir--cur-server)
+           dir (nnmaildir--srvgrp-dir dir gname)
+           dir (if (nnmaildir--param pgname 'read-only)
+                   (nnmaildir--new dir) (nnmaildir--cur dir))
+           nnmaildir-article-file-name
+           (concat dir
+                   (nnmaildir--art-prefix article)
+                   (nnmaildir--art-suffix article)))
+      (unless (file-exists-p nnmaildir-article-file-name)
+       (nnmaildir--expired-article group article)
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             "Article has expired")
+       (throw 'return nil))
+      (with-current-buffer (or to-buffer nntp-server-buffer)
+       (erase-buffer)
+       (nnheader-insert-file-contents nnmaildir-article-file-name))
+      (cons gname num-msgid))))
+
+(defun nnmaildir-request-post (&optional _server)
+  (let (message-required-mail-headers)
+    (funcall message-send-mail-function)))
+
+(defun nnmaildir-request-replace-article (number gname buffer)
+  (let ((group (nnmaildir--prepare nil gname))
+       (coding-system-for-write nnheader-file-coding-system)
+       (buffer-file-coding-system nil)
+       (file-coding-system-alist nil)
+       dir file article suffix tmpfile deactivate-mark)
+    (catch 'return
+      (unless group
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (concat "No such group: " gname))
+       (throw 'return nil))
+      (when (nnmaildir--param (nnmaildir--pgname nnmaildir--cur-server gname)
+                             'read-only)
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (concat "Read-only group: " group))
+       (throw 'return nil))
+      (setq dir (nnmaildir--srv-dir nnmaildir--cur-server)
+           dir (nnmaildir--srvgrp-dir dir gname)
+           article (nnmaildir--nlist-art group number))
+      (unless article
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (concat "No such article: " (number-to-string number)))
+       (throw 'return nil))
+      (setq suffix (nnmaildir--art-suffix article)
+           file (nnmaildir--art-prefix article)
+           tmpfile (concat (nnmaildir--tmp dir) file))
+      (when (file-exists-p tmpfile)
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (concat "File exists: " tmpfile))
+       (throw 'return nil))
+      (with-current-buffer buffer
+       (gmm-write-region (point-min) (point-max) tmpfile nil 'no-message nil
+                         'excl))
+      (unix-sync) ;; no fsync :(
+      (rename-file tmpfile (concat (nnmaildir--cur dir) file suffix) 'replace)
+      t)))
+
+(defun nnmaildir-request-move-article (article gname server accept-form
+                                      &optional _last _move-is-internal)
+  (let ((group (nnmaildir--prepare server gname))
+       pgname suffix result nnmaildir--file deactivate-mark)
+    (catch 'return
+      (unless group
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (concat "No such group: " gname))
+       (throw 'return nil))
+      (setq gname (nnmaildir--grp-name group)
+           pgname (nnmaildir--pgname nnmaildir--cur-server gname)
+           article (nnmaildir--nlist-art group article))
+      (unless article
+       (setf (nnmaildir--srv-error nnmaildir--cur-server) "No such article")
+       (throw 'return nil))
+      (setq suffix (nnmaildir--art-suffix article)
+           nnmaildir--file (nnmaildir--srv-dir nnmaildir--cur-server)
+           nnmaildir--file (nnmaildir--srvgrp-dir nnmaildir--file gname)
+           nnmaildir--file (if (nnmaildir--param pgname 'read-only)
+                               (nnmaildir--new nnmaildir--file)
+                             (nnmaildir--cur nnmaildir--file))
+           nnmaildir--file (concat nnmaildir--file
+                                   (nnmaildir--art-prefix article)
+                                   suffix))
+      (unless (file-exists-p nnmaildir--file)
+       (nnmaildir--expired-article group article)
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             "Article has expired")
+       (throw 'return nil))
+      (nnmaildir--with-move-buffer
+       (erase-buffer)
+       (nnheader-insert-file-contents nnmaildir--file)
+       (setq result (eval accept-form)))
+      (unless (or (null result) (nnmaildir--param pgname 'read-only))
+       (nnmaildir--unlink nnmaildir--file)
+       (nnmaildir--expired-article group article))
+      result)))
+
+(defun nnmaildir-request-accept-article (gname &optional server _last)
+  (let ((group (nnmaildir--prepare server gname))
+       (coding-system-for-write nnheader-file-coding-system)
+       (buffer-file-coding-system nil)
+       (file-coding-system-alist nil)
+       srv-dir dir file time tmpfile curfile 24h article)
+    (catch 'return
+      (unless group
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (concat "No such group: " gname))
+       (throw 'return nil))
+      (setq gname (nnmaildir--grp-name group))
+      (when (nnmaildir--param (nnmaildir--pgname nnmaildir--cur-server gname)
+                             'read-only)
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (concat "Read-only group: " gname))
+       (throw 'return nil))
+      (setq srv-dir (nnmaildir--srv-dir nnmaildir--cur-server)
+           dir (nnmaildir--srvgrp-dir srv-dir gname)
+           time (current-time)
+           file (format-time-string "%s." time))
+      (unless (string-equal nnmaildir--delivery-time file)
+       (setq nnmaildir--delivery-time file
+             nnmaildir--delivery-count 0))
+      (when (and (consp (cdr time))
+                (consp (cddr time)))
+       (setq file (concat file "M" (number-to-string (caddr time)))))
+      (setq file (concat file nnmaildir--delivery-pid)
+           file (concat file "Q" (number-to-string nnmaildir--delivery-count))
+           file (concat file "." (nnmaildir--system-name))
+           tmpfile (concat (nnmaildir--tmp dir) file)
+           curfile (concat (nnmaildir--cur dir) file ":2,"))
+      (when (file-exists-p tmpfile)
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (concat "File exists: " tmpfile))
+       (throw 'return nil))
+      (when (file-exists-p curfile)
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (concat "File exists: " curfile))
+       (throw 'return nil))
+      (setq nnmaildir--delivery-count (1+ nnmaildir--delivery-count)
+           24h (run-with-timer 86400 nil
+                               (lambda ()
+                                 (nnmaildir--unlink tmpfile)
+                                 (setf (nnmaildir--srv-error
+                                         nnmaildir--cur-server)
+                                       "24-hour timer expired")
+                                 (throw 'return nil))))
+      (condition-case nil (add-name-to-file nnmaildir--file tmpfile)
+       (error
+        (gmm-write-region (point-min) (point-max) tmpfile nil 'no-message nil
+                          'excl)
+        (when (fboundp 'unix-sync)
+          (unix-sync)))) ;; no fsync :(
+      (nnheader-cancel-timer 24h)
+      (condition-case err
+         (add-name-to-file tmpfile curfile)
+       (error
+        (setf (nnmaildir--srv-error nnmaildir--cur-server)
+              (concat "Error linking: " (prin1-to-string err)))
+        (nnmaildir--unlink tmpfile)
+        (throw 'return nil)))
+      (nnmaildir--unlink tmpfile)
+      (setq article (make-nnmaildir--art :prefix file :suffix ":2,"))
+      (if (nnmaildir--grp-add-art nnmaildir--cur-server group article)
+         (cons gname (nnmaildir--art-num article))))))
+
+(defun nnmaildir-save-mail (group-art)
+  (catch 'return
+    (unless group-art
+      (throw 'return nil))
+    (let (ga gname x groups nnmaildir--file deactivate-mark)
+      (save-excursion
+       (goto-char (point-min))
+       (save-match-data
+         (while (looking-at "From ")
+           (replace-match "X-From-Line: ")
+           (forward-line 1))))
+      (setq groups (nnmaildir--srv-groups nnmaildir--cur-server)
+           ga (car group-art) group-art (cdr group-art)
+           gname (car ga))
+      (or (intern-soft gname groups)
+         (nnmaildir-request-create-group gname)
+         (throw 'return nil)) ;; not that nnmail bothers to check :(
+      (unless (nnmaildir-request-accept-article gname)
+       (throw 'return nil))
+      (setq nnmaildir--file (nnmaildir--srv-dir nnmaildir--cur-server)
+           nnmaildir--file (nnmaildir--srvgrp-dir nnmaildir--file gname)
+           x (nnmaildir--prepare nil gname)
+           x (nnmaildir--grp-nlist x)
+           x (cdar x)
+           nnmaildir--file (concat nnmaildir--file
+                                   (nnmaildir--art-prefix x)
+                                   (nnmaildir--art-suffix x)))
+      (delq nil
+           (mapcar
+            (lambda (ga)
+              (setq gname (car ga))
+              (and (or (intern-soft gname groups)
+                       (nnmaildir-request-create-group gname))
+                   (nnmaildir-request-accept-article gname)
+                   ga))
+            group-art)))))
+
+(defun nnmaildir-active-number (_gname)
+  0)
+
+(declare-function gnus-group-mark-article-read "gnus-group" (group article))
+
+(defun nnmaildir-request-expire-articles (ranges &optional gname server force)
+  (let ((no-force (not force))
+       (group (nnmaildir--prepare server gname))
+       pgname time boundary bound-iter high low target dir nlist
+       didnt nnmaildir--file nnmaildir-article-file-name
+       deactivate-mark)
+    (catch 'return
+      (unless group
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (if gname (concat "No such group: " gname) "No current group"))
+       (throw 'return (gnus-uncompress-range ranges)))
+      (setq gname (nnmaildir--grp-name group)
+           pgname (nnmaildir--pgname nnmaildir--cur-server gname))
+      (if (nnmaildir--param pgname 'read-only)
+         (throw 'return (gnus-uncompress-range ranges)))
+      (setq time (nnmaildir--param pgname 'expire-age))
+      (unless time
+       (setq time (or (and nnmail-expiry-wait-function
+                           (funcall nnmail-expiry-wait-function gname))
+                      nnmail-expiry-wait))
+       (if (eq time 'immediate)
+           (setq time 0)
+         (if (numberp time)
+             (setq time (round (* time 86400))))))
+      (when no-force
+       (unless (integerp time) ;; handle 'never
+         (throw 'return (gnus-uncompress-range ranges)))
+       (setq boundary (current-time)
+             high (- (car boundary) (/ time 65536))
+             low (- (cadr boundary) (% time 65536)))
+       (if (< low 0)
+           (setq low (+ low 65536)
+                 high (1- high)))
+       (setcar (cdr boundary) low)
+       (setcar boundary high))
+      (setq dir (nnmaildir--srv-dir nnmaildir--cur-server)
+           dir (nnmaildir--srvgrp-dir dir gname)
+           dir (nnmaildir--cur dir)
+           nlist (nnmaildir--grp-nlist group)
+           ranges (reverse ranges))
+      (nnmaildir--with-move-buffer
+       (nnmaildir--nlist-iterate
+        nlist ranges
+        (lambda (article)
+          (setq nnmaildir--file (nnmaildir--art-prefix article)
+                nnmaildir--file (concat dir nnmaildir--file
+                                        (nnmaildir--art-suffix article))
+                time (file-attributes nnmaildir--file))
+          (cond
+           ((null time)
+            (nnmaildir--expired-article group article))
+           ((and no-force
+                 (progn
+                   (setq time (nth 5 time)
+                         bound-iter boundary)
+                   (while (and bound-iter time
+                               (= (car bound-iter) (car time)))
+                     (setq bound-iter (cdr bound-iter)
+                           time (cdr time)))
+                   (and bound-iter time
+                        (car-less-than-car bound-iter time))))
+            (setq didnt (cons (nnmaildir--art-num article) didnt)))
+           (t
+            (setq nnmaildir-article-file-name nnmaildir--file
+                  target (if force nil
+                           (save-excursion
+                             (save-restriction
+                               (nnmaildir--param pgname 'expire-group)))))
+            (when (and (stringp target)
+                       (not (string-equal target pgname))) ;; Move it.
+              (erase-buffer)
+              (nnheader-insert-file-contents nnmaildir--file)
+              (let ((group-art (gnus-request-accept-article
+                                target nil nil 'no-encode)))
+                (when (consp group-art)
+                  ;; Maybe also copy: dormant forward reply save tick
+                  ;; (gnus-add-mark? gnus-request-set-mark?)
+                  (gnus-group-mark-article-read target (cdr group-art)))))
+            (if (equal target pgname)
+                ;; Leave it here.
+                (setq didnt (cons (nnmaildir--art-num article) didnt))
+              (nnmaildir--unlink nnmaildir--file)
+              (nnmaildir--expired-article group article))))))
+       (erase-buffer))
+      didnt)))
+
+(defvar nnmaildir--article)
+
+(defun nnmaildir-request-set-mark (gname actions &optional server)
+  (let* ((group (nnmaildir--prepare server gname))
+        (curdir (nnmaildir--cur
+                 (nnmaildir--srvgrp-dir
+                  (nnmaildir--srv-dir nnmaildir--cur-server)
+                  gname)))
+        (coding-system-for-write nnheader-file-coding-system)
+        (buffer-file-coding-system nil)
+        (file-coding-system-alist nil)
+        marksdir nlist
+        ranges all-marks todo-marks mdir mfile
+        pgname ls permarkfile deactivate-mark
+        (del-mark
+         (lambda (mark)
+           (let ((prefix (nnmaildir--art-prefix nnmaildir--article))
+                 (suffix (nnmaildir--art-suffix nnmaildir--article))
+                 (flag (nnmaildir--mark-to-flag mark)))
+             (when flag
+               ;; If this mark corresponds to a flag, remove the flag from
+               ;; the file name.
+               (nnmaildir--article-set-flags
+                nnmaildir--article (nnmaildir--remove-flag flag suffix)
+                curdir))
+             ;; We still want to delete the hardlink in the marks dir if
+             ;; present, regardless of whether this mark has a maildir flag or
+             ;; not, to avoid getting out of sync.
+             (setq mfile (nnmaildir--subdir marksdir (symbol-name mark))
+                   mfile (concat mfile prefix))
+             (nnmaildir--unlink mfile))))
+        (del-action (lambda (article)
+                      (let ((nnmaildir--article article))
+                        (mapcar del-mark todo-marks))))
+        (add-action
+         (lambda (article)
+           (mapcar
+            (lambda (mark)
+              (let ((prefix (nnmaildir--art-prefix article))
+                    (suffix (nnmaildir--art-suffix article))
+                    (flag (nnmaildir--mark-to-flag mark)))
+                (if flag
+                    ;; If there is a corresponding maildir flag, just rename
+                    ;; the file.
+                    (nnmaildir--article-set-flags
+                     article (nnmaildir--add-flag flag suffix) curdir)
+                  ;; Otherwise, use nnmaildir-specific marks dir.
+                  (setq mdir (nnmaildir--subdir marksdir (symbol-name mark))
+                        permarkfile (concat mdir ":")
+                        mfile (concat mdir prefix))
+                  (nnmaildir--condcase err (add-name-to-file permarkfile mfile)
+                    (cond
+                     ((nnmaildir--eexist-p err))
+                     ((nnmaildir--enoent-p err)
+                      (nnmaildir--mkdir mdir)
+                      (nnmaildir--mkfile permarkfile)
+                      (add-name-to-file permarkfile mfile))
+                     ((nnmaildir--emlink-p err)
+                      (let ((permarkfilenew (concat permarkfile "{new}")))
+                        (nnmaildir--mkfile permarkfilenew)
+                        (rename-file permarkfilenew permarkfile 'replace)
+                        (add-name-to-file permarkfile mfile)))
+                     (t (signal (car err) (cdr err))))))))
+            todo-marks)))
+        (set-action (lambda (article)
+                      (funcall add-action article)
+                      (let ((nnmaildir--article article))
+                        (mapcar (lambda (mark)
+                                  (unless (memq mark todo-marks)
+                                    (funcall del-mark mark)))
+                                all-marks)))))
+    (catch 'return
+      (unless group
+       (setf (nnmaildir--srv-error nnmaildir--cur-server)
+             (concat "No such group: " gname))
+       (dolist (action actions)
+         (setq ranges (gnus-range-add ranges (car action))))
+       (throw 'return ranges))
+      (setq nlist (nnmaildir--grp-nlist group)
+           marksdir (nnmaildir--srv-dir nnmaildir--cur-server)
+           marksdir (nnmaildir--srvgrp-dir marksdir gname)
+           marksdir (nnmaildir--nndir marksdir)
+           marksdir (nnmaildir--marks-dir marksdir)
+           gname (nnmaildir--grp-name group)
+            pgname (nnmaildir--pgname nnmaildir--cur-server gname)
+            ls (nnmaildir--group-ls nnmaildir--cur-server pgname)
+           all-marks (funcall ls marksdir nil "\\`[^.]" 'nosort)
+           all-marks (gnus-delete-duplicates
+                      ;; get mark names from mark dirs and from flag
+                      ;; mappings
+                      (append
+                       (mapcar 'cdr nnmaildir-flag-mark-mapping)
+                       (mapcar 'intern all-marks))))
+      (dolist (action actions)
+       (setq ranges (car action)
+             todo-marks (caddr action))
+       (dolist (mark todo-marks)
+         (pushnew mark all-marks :test #'equal))
+       (if (numberp (cdr ranges)) (setq ranges (list ranges)))
+       (nnmaildir--nlist-iterate nlist ranges
+                                 (cond ((eq 'del (cadr action)) del-action)
+                                       ((eq 'add (cadr action)) add-action)
+                                       ((eq 'set (cadr action)) set-action))))
+      nil)))
+
+(defun nnmaildir-close-group (gname &optional server)
+  (let ((group (nnmaildir--prepare server gname))
+       pgname ls dir msgdir files flist dirs)
+    (if (null group)
+       (progn
+         (setf (nnmaildir--srv-error nnmaildir--cur-server)
+               (concat "No such group: " gname))
+         nil)
+      (setq pgname (nnmaildir--pgname nnmaildir--cur-server gname)
+           ls (nnmaildir--group-ls nnmaildir--cur-server pgname)
+           dir (nnmaildir--srv-dir nnmaildir--cur-server)
+           dir (nnmaildir--srvgrp-dir dir gname)
+           msgdir (if (nnmaildir--param pgname 'read-only)
+                      (nnmaildir--new dir) (nnmaildir--cur dir))
+           dir (nnmaildir--nndir dir)
+           dirs (cons (nnmaildir--nov-dir dir)
+                      (funcall ls (nnmaildir--marks-dir dir) 'full "\\`[^.]"
+                               'nosort))
+           dirs (mapcar
+                 (lambda (dir)
+                   (cons dir (funcall ls dir nil "\\`[^.]" 'nosort)))
+                 dirs)
+           files (funcall ls msgdir nil "\\`[^.]" 'nosort)
+           flist (nnmaildir--up2-1 (length files))
+           flist (make-vector flist 0))
+      (save-match-data
+       (dolist (file files)
+         (string-match "\\`\\([^:]*\\)\\(:.*\\)?\\'" file)
+         (intern (match-string 1 file) flist)))
+      (dolist (dir dirs)
+       (setq files (cdr dir)
+             dir (file-name-as-directory (car dir)))
+       (dolist (file files)
+         (unless (or (intern-soft file flist) (string= file ":"))
+           (setq file (concat dir file))
+           (delete-file file))))
+      t)))
+
+(defun nnmaildir-close-server (&optional server)
+  (defvar flist) (defvar ls) (defvar dirs) (defvar dir)
+  (defvar files) (defvar file) (defvar x)
+  (let (flist ls dirs dir files file x)
+    (nnmaildir--prepare server nil)
+    (when nnmaildir--cur-server
+      (setq server nnmaildir--cur-server
+           nnmaildir--cur-server nil)
+      (unintern (nnmaildir--srv-address server) nnmaildir--servers)))
+  t)
+
+(defun nnmaildir-request-close ()
+  (let (servers buffer)
+    (mapatoms (lambda (server)
+               (setq servers (cons (symbol-name server) servers)))
+             nnmaildir--servers)
+    (mapc 'nnmaildir-close-server servers)
+    (setq buffer (get-buffer " *nnmaildir work*"))
+    (if buffer (kill-buffer buffer))
+    (setq buffer (get-buffer " *nnmaildir nov*"))
+    (if buffer (kill-buffer buffer))
+    (setq buffer (get-buffer " *nnmaildir move*"))
+    (if buffer (kill-buffer buffer)))
+  t)
+
+(provide 'nnmaildir)
+
+;; Local Variables:
+;; indent-tabs-mode: t
+;; fill-column: 77
+;; End:
+
+;;; nnmaildir.el ends here
diff --git a/xemacs-packages/gnus/lisp/nnmairix.el b/xemacs-packages/gnus/lisp/nnmairix.el
new file mode 100644 (file)
index 0000000..d5fa4fa
--- /dev/null
@@ -0,0 +1,2028 @@
+;;; nnmairix.el --- Mairix back end for Gnus, the Emacs newsreader
+
+;; Copyright (C) 2007-2016 Free Software Foundation, Inc.
+
+;; Author: David Engster <dengste@eml.cc>
+;; Keywords: mail searching
+;; Old-Version: 0.6
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This is a back end for using the mairix search engine with
+;; Gnus.  Mairix is a tool for searching words in locally stored
+;; mail.  Mairix is very fast which allows using it efficiently for
+;; "smart folders", e.g. folders which are associated with search
+;; queries.  Of course, you can also use this back end just for
+;; calling mairix with some search query.
+;;
+;; Mairix is written by Richard Curnow.  More information can be found at
+;; http://www.rpcurnow.force9.co.uk/mairix/
+
+;; Commentary on the code: nnmairix sits between Gnus and the "real"
+;; back end which handles the mail (currently nnml, nnimap and
+;; nnmaildir were tested). I know this is all a bit hacky, but so far
+;; it works for me.  This is the first back end I've written for Gnus,
+;; so I'd appreciate any comments, suggestions, bug reports (and, of
+;; course, patches) for improving nnmairix.
+
+;; nnmairix does not use an active file, since I wanted to contain the
+;; back end "inside Gnus" as much as possible without the need of an
+;; external file.  It stores the query/folder information in the group
+;; parameters instead.  This also implies that once you kill a mairix
+;; group, it's gone for good.  I don't think that this is really
+;; problematic, since I don't see the need in unsubscribing and
+;; re-subscribing search groups
+
+;; Every mairix server is "responsible" for one mairix installation,
+;; i.e. you can have several mairix servers for different mairix
+;; configurations.  Not that I think anyone will actually do this, but
+;; I thought it would be a "nice to have feature"...
+
+;; KNOWN BUGS:
+;; * Mairix does only support us-ascii characters.
+
+;; TODO/MISSING FEATURES:
+;; * Support of more back ends (nnmh, nnfolder, nnmbox...)?
+;; * Maybe use an active file instead of group parameters?
+;; * Maybe use "-a" when updating groups which are not newly created?
+
+;;; Changelog:
+;; 05/30/2008 - version 0.6
+;;
+;;    * It is now possible to propagate marks from the nnmairix groups
+;;      to the original messages (and for maildir also vice versa). See
+;;      the docs for details on this feature - it's pretty delicate
+;;      and currently needs a patched mairix binary to work smoothly.
+;;
+;;    * Keep messages in nnmairix groups always read/unread
+;;      (bound to 'G b r').
+;;
+;;    * Recreate back end folder for nnmairix groups in case you
+;;      somehow get wrong article counts (bound to 'G b d').
+;;
+;;    * New group parameter 'allow-fast'. Toggling of parameter bound
+;;      to 'G b a'. The default is nil, meaning that the group will
+;;      always be updated with a mairix search, even when only entered.
+;;
+;;    * More/Better use of the registry (if available). Can now also
+;;      deal with duplicate messages in different groups.
+;;
+;; 02/06/2008 - version 0.5
+;;
+;;    * New function: nnmairix-goto-original-article. Uses the
+;;      registry or the mail file path for determining original group.
+;;
+;;    * Deal with empty Xref header
+;;
+;;    * Changed summary mode keybindings since the old ones were
+;;      already taken
+;;
+;;   (Thanks to Tassilo Horn and Ted Zlatanov for their help)
+;;
+;; 01/07/2008 - version 0.4
+;;
+;;    * New/fixed doc strings and code cleanup.
+;;
+;; 11/18/2007 - version 0.3
+;;
+;;    * Fixed bugs when dealing with nnml and native servers
+;;
+;;    * Make variables customizable
+;;
+;; 10/10/2007 - version 0.2
+;;
+;;    * Use nnml-directory/directory server variables for nnml and
+;;    nnmaildir back ends as path for search folders. This way it
+;;    becomes independent of 'base' setting in .mairixirc (but not for
+;;    nnimap).
+;;
+;;    * As a result: Changed nnmairix-backend-to-server so that user
+;;    is asked when more than one nnmairix server exists and we do not
+;;    know which one is responsible for current back end.
+;;
+;;    * Rename files when using nnml back ends so that there are no
+;;    holes in article numbers. This should fix all problems regarding
+;;    wrong article counts with nnml.
+;;
+;;    * More commands for creating queries (using widgets or the
+;;    minibuffer).
+;;
+;;    * Fixed bug in nnmairix-create-search-group-from-message
+;;
+;;    * Changed copyright to FSF
+;;
+;;      (Thanks to Georg C. F. Greve and Bastien for suggestions and
+;;      ideas!)
+;;
+;; 10/03/2007 - version 0.1 - first release
+
+
+;;; Code:
+
+(eval-when-compile (require 'cl))       ;For (pop (cdr ogroup)).
+
+(require 'nnoo)
+(require 'gnus-group)
+(require 'gnus-sum)
+(require 'message)
+(require 'nnml)
+(require 'widget)
+
+(nnoo-declare nnmairix)
+
+;;; === Keymaps
+
+(eval-when-compile
+  (when (featurep 'xemacs)
+    ;; The `kbd' macro requires that the `read-kbd-macro' macro is available.
+    (require 'edmacro)))
+
+;; Group mode
+(defun nnmairix-group-mode-hook ()
+  "Nnmairix group mode keymap."
+  (define-key gnus-group-mode-map
+    (kbd "G b") (make-sparse-keymap))
+  (define-key gnus-group-mode-map
+    (kbd "G b g") 'nnmairix-create-search-group)
+  (define-key gnus-group-mode-map
+    (kbd "G b c") 'nnmairix-create-server-and-default-group)
+  (define-key gnus-group-mode-map
+    (kbd "G b q") 'nnmairix-group-change-query-this-group)
+  (define-key gnus-group-mode-map
+    (kbd "G b t") 'nnmairix-group-toggle-threads-this-group)
+  (define-key gnus-group-mode-map
+    (kbd "G b u") 'nnmairix-update-database)
+  (define-key gnus-group-mode-map
+    (kbd "G b s") 'nnmairix-search)
+  (define-key gnus-group-mode-map
+    (kbd "G b i") 'nnmairix-search-interactive)
+  (define-key gnus-group-mode-map
+    (kbd "G b m") 'nnmairix-widget-search)
+  (define-key gnus-group-mode-map
+    (kbd "G b p") 'nnmairix-group-toggle-propmarks-this-group)
+  (define-key gnus-group-mode-map
+    (kbd "G b r") 'nnmairix-group-toggle-readmarks-this-group)
+  (define-key gnus-group-mode-map
+    (kbd "G b d") 'nnmairix-group-delete-recreate-this-group)
+  (define-key gnus-group-mode-map
+    (kbd "G b a") 'nnmairix-group-toggle-allowfast-this-group)
+  (define-key gnus-group-mode-map
+    (kbd "G b o") 'nnmairix-propagate-marks))
+
+;; Summary mode
+(defun nnmairix-summary-mode-hook ()
+  "Nnmairix summary mode keymap."
+  (define-key gnus-summary-mode-map
+    (kbd "G G t") 'nnmairix-search-thread-this-article)
+  (define-key gnus-summary-mode-map
+    (kbd "G G f") 'nnmairix-search-from-this-article)
+  (define-key gnus-summary-mode-map
+    (kbd "G G m") 'nnmairix-widget-search-from-this-article)
+  (define-key gnus-summary-mode-map
+    (kbd "G G g") 'nnmairix-create-search-group-from-message)
+  (define-key gnus-summary-mode-map
+    (kbd "G G o") 'nnmairix-goto-original-article)
+  (define-key gnus-summary-mode-map
+    (kbd "G G u") 'nnmairix-remove-tick-mark-original-article))
+
+(add-hook 'gnus-group-mode-hook 'nnmairix-group-mode-hook)
+(add-hook 'gnus-summary-mode-hook 'nnmairix-summary-mode-hook)
+
+;; ;;;###autoload
+;; (defun nnmairix-initialize (&optional force)
+;;   (interactive "P")
+;;   (if (not (or (file-readable-p "~/.mairixrc")
+;;            force))
+;;       (message "No file `~/.mairixrc', skipping nnmairix setup")
+;;     (add-hook 'gnus-group-mode-hook 'nnmairix-group-mode-hook)
+;;     (add-hook 'gnus-summary-mode-hook 'nnmairix-summary-mode-hook)))
+
+;; Customizable stuff
+
+(defgroup nnmairix nil
+  "Back end for the Mairix mail search engine."
+  :group 'gnus)
+
+(defcustom nnmairix-group-prefix "zz_mairix"
+  "Prefix for mairix search groups on back end server.
+nnmairix will create these groups automatically on the back end
+server for each nnmairix search group.  The name on the back end
+server will be this prefix plus a random number.  You can delete
+unused nnmairix groups on the back end using
+`nnmairix-purge-old-groups'."
+  :version "23.1"
+  :type 'string
+  :group 'nnmairix)
+
+(defcustom nnmairix-mairix-output-buffer "*mairix output*"
+  "Buffer used for mairix output."
+  :version "23.1"
+  :type 'string
+  :group 'nnmairix)
+
+(defcustom nnmairix-customize-query-buffer "*mairix query*"
+  "Name of the buffer for customizing Mairix queries."
+  :version "23.1"
+  :type 'string
+  :group 'nnmairix)
+
+(defcustom nnmairix-mairix-update-options '("-F" "-Q")
+  "Options when calling mairix for updating the database.
+The default is \"-F\" and \"-Q\" for making updates faster.  You
+should call mairix without these options from time to
+time (e.g. via cron job)."
+  :version "23.1"
+  :type '(repeat string)
+  :group 'nnmairix)
+
+(defcustom nnmairix-mairix-search-options '("-Q")
+  "Options when calling mairix for searching.
+The default is \"-Q\" for making searching faster."
+  :version "23.1"
+  :type '(repeat string)
+  :group 'nnmairix)
+
+(defcustom nnmairix-mairix-synchronous-update nil
+  "Set this to t if you want Emacs to wait for mairix updating the database."
+  :version "23.1"
+  :type 'boolean
+  :group 'nnmairix)
+
+(defcustom nnmairix-rename-files-for-nnml t
+  "Rename nnml mail files so that they are consecutively numbered.
+When using nnml as back end, mairix might produce holes in the
+article numbers which will produce wrong article counts by
+Gnus.  This option controls whether nnmairix should rename the
+files consecutively."
+  :version "23.1"
+  :type 'boolean
+  :group 'nnmairix)
+
+(defcustom nnmairix-widget-fields-list
+  '(("from" "f" "From") ("to" "t" "To") ("cc" "c" "Cc")
+    ("subject" "s" "Subject")  ("to" "tc" "To or Cc")
+    ("from" "a" "Address") (nil "b" "Body") (nil "n" "Attachment")
+    ("Message-ID" "m" "Message ID") (nil "s" "Size") (nil "d" "Date"))
+  "Fields that should be editable during interactive query customization.
+
+Header, corresponding mairix command and description for editable
+fields in interactive query customization.  The header specifies
+which header contents should be inserted into the editable field
+when creating a Mairix query based on the current message (can be
+nil for disabling this)."
+  :version "23.1"
+  :type '(repeat (list
+                 (choice :tag "Field"
+                         (const :tag "none" nil)
+                         (const :tag "From" "from")
+                         (const :tag "To" "to")
+                         (const :tag "Cc" "cc")
+                         (const :tag "Subject" "subject")
+                         (const :tag "Message ID" "Message-ID"))
+                 (string :tag "Command")
+                 (string :tag "Description")))
+  :group 'nnmairix)
+
+(defcustom nnmairix-widget-select-window-function
+  (lambda () (select-window (get-largest-window)))
+  "Function for selecting the window for customizing the mairix query.
+The default chooses the largest window in the current frame."
+  :version "23.1"
+  :type 'function
+  :group 'nnmairix)
+
+(defcustom nnmairix-propagate-marks-upon-close t
+  "Flag if marks should be propagated upon closing a group.
+The default of this variable is t.  If set to 'ask, the
+user will be asked if the flags should be propagated when the
+group is closed.  If set to nil, the user will have to manually
+call `nnmairix-propagate-marks'."
+  :version "23.1"
+  :type '(choice (const :tag "always" t)
+                (const :tag "ask" ask)
+                (const :tag "never" nil))
+  :group 'nnmairix)
+
+(defcustom nnmairix-propagate-marks-to-nnmairix-groups nil
+  "Flag if marks from original articles should be seen in nnmairix groups.
+The default is nil since it will only work if the articles are in
+maildir format and NOT managed by the nnmaildir back end but
+e.g. an IMAP server (which stores the marks in the maildir file
+name).  You may safely set this to t for testing - the worst that
+can happen are wrong marks in nnmairix groups."
+  :version "23.1"
+  :type 'boolean
+  :group 'nnmairix)
+
+(defcustom nnmairix-only-use-registry nil
+  "Use only the registry for determining original group(s).
+If set to t, nnmairix will only use the registry for determining
+the original group(s) of an article (which is also necessary for
+propagating marks).  If set to nil, it will also try to determine
+the group from an additional mairix search which might be slow
+when propagating lots of marks."
+  :version "23.1"
+  :type 'boolean
+  :group 'nnmairix)
+
+(defcustom nnmairix-allowfast-default nil
+  "Whether fast entering should be the default for nnmairix groups.
+You may set this to t to make entering the group faster, but note that
+this might lead to problems, especially when used with marks propagation."
+  :version "23.1"
+  :type 'boolean
+  :group 'nnmairix)
+
+;; ==== Other variables
+
+(defvar nnmairix-widget-other
+  '(threads flags)
+  "Other editable mairix commands when using customization widgets.
+Currently there are 'threads and 'flags.")
+
+(defvar nnmairix-interactive-query-parameters
+  '((?f "from" "f" "From") (?t "to" "t" "To") (?c "to" "tc" "To or Cc")
+    (?a "from" "a" "Address") (?s "subject" "s" "Subject") (?b nil "b" "Body")
+    (?d nil "d" "Date") (?n nil "n" "Attachment"))
+  "Things that should be editable during interactive query generation.
+Every list element consists of the following entries: Keystroke,
+message field (if any), mairix command and description.")
+
+(defvar nnmairix-delete-and-create-on-change '(nnimap nnmaildir nnml)
+  "Controls on which back ends groups should be deleted and re-created.
+This variable is a list of back ends where the search group
+should be completely deleted and re-created when the query or
+thread parameter changes.  The default is to this for all
+currently supported back ends.  It usually also corrects the
+problem of \"holes\" in the article numbers which often lead to a
+wrong count of total articles shown by Gnus.")
+
+;;; === Server variables
+
+(defvoo nnmairix-backend  nil
+  "Back end where mairix stores its searches.")
+
+(defvoo nnmairix-backend-server nil
+  "Name of the server where mairix stores its searches.")
+
+(defvoo nnmairix-mairix-command "mairix"
+  "Command to call mairix for this nnmairix server.")
+
+(defvoo nnmairix-hidden-folders nil
+  "Set this to t if the back end server uses hidden directories for
+its maildir mail folders (e.g. the Dovecot IMAP server or mutt).")
+
+(defvoo nnmairix-default-group nil
+  "Default search group. This is the group which is used for all
+temporary searches, e.g. nnmairix-search.")
+
+;;; === Internal variables
+
+(defconst nnmairix-group-regexp
+  (format "%s-\\(.*\\)-[0-9]+" nnmairix-group-prefix)
+  "Regexp for mairix groups on back end.")
+
+(defconst nnmairix-valid-backends '(nnimap nnml nnmaildir)
+  "Back ends supported by nnmairix.
+Other back ends might or might not work.")
+
+(defvar nnmairix-last-server nil
+  "Last chosen server.")
+
+(defvar nnmairix-current-server nil
+  "Current server.")
+
+(defvar nnmairix-marks-cache nil
+  "Cache for marks which should be set upon closing current group.")
+
+(defvar nnmairix-version-output nil
+  "Version string of mairix binary.")
+
+;;; === Gnus back end functions
+
+(nnoo-define-basics nnmairix)
+
+(gnus-declare-backend "nnmairix" 'mail 'address 'virtual)
+
+(deffoo nnmairix-open-server (server &optional definitions)
+  ;; just set server variables
+  (setq nnmairix-current-server server)
+  (nnoo-change-server 'nnmairix server definitions))
+
+(deffoo nnmairix-request-group (group &optional server fast info)
+  ;; Call mairix and request group on back end server
+  (when server (nnmairix-open-server server))
+  (let* ((qualgroup (if server
+                       (gnus-group-prefixed-name group (list 'nnmairix server))
+                     group))
+        (folder (gnus-group-get-parameter qualgroup 'folder))
+        (allowfast (gnus-group-get-parameter qualgroup 'allow-fast))
+        (query (gnus-group-get-parameter qualgroup 'query t))
+        (threads (gnus-group-get-parameter qualgroup 'threads))
+        (backendmethod (gnus-server-to-method
+                        (format "%s:%s" (symbol-name nnmairix-backend)
+                                nnmairix-backend-server)))
+        rval mfolder folderpath args)
+    (cond
+     ((not folder)
+      ;; No folder parameter -> error
+      (nnheader-report 'nnmairix "Check folder parameter for group %s" group)
+      nil)
+     ((not query)
+      ;; No query -> return empty group
+      (with-current-buffer nntp-server-buffer
+       (erase-buffer)
+       (insert (concat "211 0 1 0 " group))
+       t))
+     (t
+      ;; For maildir++ folders: create a hidden directory (prepend dot)
+      (setq mfolder (if (and nnmairix-hidden-folders
+                            (not (string-match "^\\." folder)))
+                       (concat "." folder)
+                     folder))
+      ;; For nnml and nnmaildir, precede mfolder with directory where mail
+      ;; is actually stored so that it's independent of 'base' setting
+      ;; in .mairixrc.
+      (when (eq nnmairix-backend 'nnml)
+       (setq folderpath (cadr (assoc 'nnml-directory backendmethod)))
+       ;; if nnml-directory is not explicitly set, use global value
+       (when (not folderpath)
+         (setq folderpath nnml-directory)))
+      (when (eq nnmairix-backend 'nnmaildir)
+       (setq folderpath
+             (cadr (assoc 'directory backendmethod))))
+      (when folderpath
+       (setq mfolder
+             (concat
+              (file-name-as-directory
+               (expand-file-name
+                folderpath))
+              mfolder)))
+      ;; If (not fast), call Mairix binary
+      ;; recreate underlying folder on the back end
+      (setq rval
+           (if (and fast allowfast)
+               0
+             (nnmairix-call-mairix-binary
+              (split-string nnmairix-mairix-command)
+              mfolder query threads)))
+      ;; Check return value
+      (cond
+       ((zerop rval)                   ; call was successful
+       (nnmairix-call-backend
+        "open-server" nnmairix-backend-server)
+       ;; If we're dealing with nnml, rename files
+       ;; consecutively and make new active file for this
+       ;; group
+       (when (eq nnmairix-backend 'nnml)
+         (when nnmairix-rename-files-for-nnml
+           (nnmairix-rename-files-consecutively mfolder))
+         (nnml-generate-nov-databases-directory mfolder nil t))
+       (nnmairix-call-backend
+        "request-scan" folder nnmairix-backend-server)
+       (if (and fast allowfast)
+           t
+         (nnmairix-request-group-with-article-number-correction
+          folder qualgroup)))
+       ((and (= rval 1)
+            (with-current-buffer nnmairix-mairix-output-buffer
+              (goto-char (point-min))
+              (looking-at "^Matched 0 messages")))
+       ;; No messages found -> return empty group
+       (nnheader-message 5 "Mairix: No matches found.")
+       (set-buffer nntp-server-buffer)
+       (erase-buffer)
+       (insert (concat "211 0 1 0 " group))
+       t)
+       ;; Everything else is an error
+       (t
+       (nnheader-report
+        'nnmairix "Error running mairix. See buffer %s for details"
+        nnmairix-mairix-output-buffer)
+       nil))))))
+
+
+(deffoo nnmairix-request-create-group (group &optional server args)
+  (let ((qualgroup (if server (gnus-group-prefixed-name group (list 'nnmairix server))
+                    group))
+       (exist t)
+       (count 0)
+       groupname info)
+    (when server (nnmairix-open-server server))
+    (gnus-group-add-parameter qualgroup '(query . nil))
+    (gnus-group-add-parameter qualgroup '(threads . nil))
+    (while exist
+      (setq count (1+ count))
+      (setq groupname (format "%s-%s-%s" nnmairix-group-prefix group
+                             (number-to-string count)))
+      (setq exist (nnmairix-call-backend
+                  "request-group" groupname nnmairix-backend-server)))
+    (nnmairix-call-backend
+     "request-create-group" groupname nnmairix-backend-server)
+    (gnus-group-add-parameter qualgroup '(folder . nil))
+    (when nnmairix-allowfast-default
+      (gnus-group-add-parameter qualgroup '(allow-fast . t)))
+    (gnus-group-set-parameter qualgroup 'folder groupname))
+  t)
+
+
+(deffoo nnmairix-retrieve-headers (articles group &optional server fetch-old)
+  (when server (nnmairix-open-server server))
+  (let* ((folder (nnmairix-get-backend-folder group server))
+        (corr (nnmairix-get-numcorr group server))
+        (numcorr 0)
+        rval)
+    (when (and corr
+              (not (zerop (cadr corr)))
+              (numberp (car articles)))
+      (setq numcorr (cadr corr))
+      (setq articles
+           (mapcar
+            (lambda (arg) (- arg numcorr))
+            articles)))
+    (setq rval
+         (if (eq nnmairix-backend 'nnimap)
+             (let ((gnus-nov-is-evil t))
+               (nnmairix-call-backend
+                "retrieve-headers" articles folder nnmairix-backend-server fetch-old))
+           (nnmairix-call-backend
+            "retrieve-headers" articles folder nnmairix-backend-server fetch-old)))
+    (nnmairix-replace-group-and-numbers articles folder group numcorr rval)
+    rval))
+
+(deffoo nnmairix-request-article (article &optional group server to-buffer)
+  (when server (nnmairix-open-server server))
+  (let ((folder (nnmairix-get-backend-folder group server))
+       (corr (nnmairix-get-numcorr group server)))
+    (when (and
+          (numberp article)
+          corr
+          (not (zerop (cadr corr))))
+      (setq article (- article (cadr corr))))
+    (nnmairix-call-backend
+     "request-article" article folder nnmairix-backend-server to-buffer))
+  t)
+
+(deffoo nnmairix-request-list (&optional server)
+  (when server (nnmairix-open-server server))
+  (if (nnmairix-call-backend "request-list" nnmairix-backend-server)
+      (let (cpoint cur qualgroup folder)
+       (with-current-buffer nntp-server-buffer
+         (goto-char (point-min))
+         (setq cpoint (point))
+         (while (re-search-forward nnmairix-group-regexp (point-max) t)
+           (setq cur (match-string 1)
+                 qualgroup (gnus-group-prefixed-name cur
+                                                     (list 'nnmairix server)))
+           (if (and (gnus-group-entry qualgroup)
+                    (string= (match-string 0)
+                             (gnus-group-get-parameter qualgroup 'folder)))
+               (progn
+                 (replace-match cur)
+                 (delete-region cpoint (point-at-bol))
+                 (forward-line)
+                 (setq cpoint (point)))
+             (forward-line)))
+         (delete-region cpoint (point-max)))
+       t)
+    nil))
+
+;; Silence byte-compiler.
+(autoload 'gnus-registry-get-id-key "gnus-registry")
+
+(deffoo nnmairix-request-set-mark (group actions &optional server)
+  (when server
+    (nnmairix-open-server server))
+  (let* ((qualgroup (gnus-group-prefixed-name group (list 'nnmairix nnmairix-current-server)))
+        (propmarks (gnus-group-get-parameter qualgroup 'propmarks))
+        (propto (gnus-group-get-parameter qualgroup 'propto t))
+        (corr (nnmairix-get-numcorr group server))
+        (folder (nnmairix-get-backend-folder group server)))
+    (save-excursion
+      (dolist (cur actions)
+       (let ((type (nth 1 cur))
+             (cmdmarks (nth 2 cur))
+             (range (gnus-uncompress-range (nth 0 cur)))
+             mid ogroup number method temp)
+         (when (and corr
+                    (not (zerop (cadr corr))))
+           (setq range (mapcar (lambda (arg)
+                                 (- arg (cadr corr)))
+                               range)))
+         (when propmarks
+           (nnheader-message 7 "nnmairix: Setting marks...")
+             (dolist (article range)
+               ;; get article (header) and extract message id
+               ;; we try to determine as many original articles as possible
+               (catch 'problem
+                 (nnmairix-call-backend "open-server" nnmairix-backend-server)
+                 (unless (gnus-request-head
+                          article
+                          (gnus-group-prefixed-name
+                           folder
+                           (list nnmairix-backend nnmairix-backend-server)))
+                   (nnheader-message
+                    3 "Unable to set mark: couldn't fetch article header for article number %d"
+                    article)
+                   (throw 'problem nil))
+                 (set-buffer nntp-server-buffer)
+                 (goto-char (point-min))
+                 (let ((case-fold-search t))
+                   (re-search-forward "^message-id:.*\\(<.+>\\)" nil t))
+                 (setq mid (match-string 1))
+                 (unless mid
+                   (nnheader-message
+                    3 "Unable to set mark: article number %d has no message-id header"
+                    article)
+                   (throw 'problem nil))
+                 ;; get original group. First try registry, then file path
+                 (setq ogroup
+                       (nnmairix-determine-original-group-from-registry mid))
+                 (unless (or ogroup
+                             nnmairix-only-use-registry)
+                   (setq ogroup
+                         (nnmairix-determine-original-group-from-path
+                          mid nnmairix-current-server)))
+                 (unless ogroup
+                   (nnheader-message
+                    3 "Unable to set mark: couldn't find original group for %s" mid)
+                   (throw 'problem nil))
+                 ;; store original groups with mid's. We cannot get
+                 ;; the article number immediately since this would
+                 ;; generate problems with maildir (articles might
+                 ;; get moved from /new to /cur and further marks
+                 ;; could then not be set)
+                 (dolist (cur ogroup)
+                   (setq temp (assoc cur
+                                     nnmairix-marks-cache))
+                   (if temp
+                       (nconc temp (list (list mid type cmdmarks)))
+                     (push (list cur (list mid type cmdmarks))
+                           nnmairix-marks-cache)))))
+             (nnheader-message 7 "nnmairix: Setting marks... done")))))))
+
+(deffoo nnmairix-close-group (group &optional server)
+  (when server
+    (nnmairix-open-server server))
+  (let* ((qualgroup (gnus-group-prefixed-name group (list 'nnmairix nnmairix-current-server)))
+        (propmarks (gnus-group-get-parameter qualgroup 'propmarks))
+        method)
+    (when (and propmarks
+              nnmairix-marks-cache)
+      (when (or (eq nnmairix-propagate-marks-upon-close t)
+               (and (eq nnmairix-propagate-marks-upon-close 'ask)
+                    (y-or-n-p "Propagate marks to original articles? ")))
+      (with-current-buffer gnus-group-buffer
+       (nnmairix-propagate-marks)
+       ;; update mairix group
+       (gnus-group-jump-to-group qualgroup)
+       (gnus-group-get-new-news-this-group))))))
+
+(autoload 'nnimap-request-update-info-internal "nnimap")
+
+(deffoo nnmairix-request-marks (group info &optional server)
+;; propagate info from underlying IMAP folder to nnmairix group
+;; This is currently experimental and must be explicitly activated
+;; with nnmairix-propagate-marks-to-nnmairix-group
+  (when server
+    (nnmairix-open-server server))
+  (let* ((qualgroup (gnus-group-prefixed-name
+                   group
+                   (list 'nnmairix nnmairix-current-server)))
+        (readmarks (gnus-group-get-parameter qualgroup 'readmarks))
+        (propmarks (gnus-group-get-parameter qualgroup 'propmarks))
+        (folder (nnmairix-get-backend-folder group server))
+        (corr (nnmairix-get-numcorr group server))
+        (docorr (and corr (not (zerop (cadr corr)))))
+        (folderinfo `(,group 1 ((1 . 1))))
+        readrange marks)
+      (when (and propmarks
+                nnmairix-propagate-marks-to-nnmairix-groups)
+       ;; these groups are not subscribed, so we have to ask the back end directly
+       (if (eq nnmairix-backend 'nnimap)
+           (nnimap-request-update-info-internal folder folderinfo nnmairix-backend-server)
+         (nnmairix-call-backend "request-update-info" folder folderinfo nnmairix-backend-server))
+       ;; set range of read articles
+       (gnus-info-set-read
+        info
+        (if docorr
+            (nnmairix-map-range
+             `(lambda (x) (+ x ,(cadr corr)))
+             (gnus-info-read folderinfo))
+          (gnus-info-read folderinfo)))
+       ;; set other marks
+       (gnus-info-set-marks
+        info
+        (if docorr
+            (mapcar (lambda (cur)
+                        (cons
+                         (car cur)
+                         (nnmairix-map-range
+                          `(lambda (x) (+ x ,(cadr corr)))
+                          (list (cadr cur)))))
+                    (gnus-info-marks folderinfo))
+          (gnus-info-marks folderinfo))))
+      (when (eq readmarks 'unread)
+       (gnus-info-set-read info nil))
+      (when (eq readmarks 'read)
+       (gnus-info-set-read info (gnus-active qualgroup))))
+  t)
+
+(nnoo-define-skeleton nnmairix)
+
+
+;;; === Interactive functions
+
+(defun nnmairix-create-search-group (server group query threads)
+  "Create on SERVER nnmairix search group GROUP with QUERY.
+If THREADS is t, include whole threads from found messages.  If
+called interactively, user will be asked for parameters."
+  (interactive
+   (list
+    (gnus-server-to-method (car (nnmairix-get-server)))
+    (read-string "Group name: ")
+    (read-string "Query: ")
+    (y-or-n-p "Include threads? ")))
+  (when (and (stringp query)
+            (string-match "\\s-" query))
+    (setq query (split-string query)))
+  (when (not (listp query))
+    (setq query (list query)))
+  (when (and server group query)
+    (save-excursion
+      (let ((groupname (gnus-group-prefixed-name group server))
+           info)
+       (set-buffer gnus-group-buffer)
+       (gnus-group-make-group group server)
+       (gnus-group-set-parameter groupname 'query  query)
+       (gnus-group-set-parameter groupname 'threads threads)
+       (nnmairix-update-and-clear-marks groupname)))))
+
+(defun nnmairix-search-interactive ()
+  "Create mairix search interactively with the minibuffer."
+  (interactive)
+  (let ((char-header nnmairix-interactive-query-parameters)
+       header finished query achar)
+    (while (not finished)
+      (while (not achar)
+       (message "Query (%s): " (nnmairix-create-message-line-for-search))
+         (setq achar (read-char))
+         (when (not (assoc achar char-header))
+           (setq achar nil)))
+      (setq header (read-string
+                   (concat "Match " (nth 3 (assoc achar char-header)) " on: ")))
+       (push  (concat (nth 2 (assoc achar char-header)) ":" header) query)
+       (setq finished (not (y-or-n-p "Add another search query? "))
+             achar nil))
+    (nnmairix-search
+     (mapconcat 'identity query " ")
+     (car (nnmairix-get-server))
+     (y-or-n-p "Include whole threads? "))))
+
+(defun nnmairix-create-search-group-from-message ()
+  "Interactively create search group with query based on current message."
+  (interactive)
+  (let ((char-header nnmairix-interactive-query-parameters)
+       (server (nnmairix-backend-to-server gnus-current-select-method))
+        query achar header finished group threads cq)
+    (when (or (not (gnus-buffer-live-p gnus-article-buffer))
+             (not (gnus-buffer-live-p gnus-summary-buffer)))
+      (error "No article or summary buffer"))
+    (when (not server)
+      (error "No nnmairix server found for back end %s:%s"
+            (symbol-name (car gnus-current-select-method))
+            (nth 1 gnus-current-select-method)))
+    (while (not finished)
+      (save-excursion
+       (gnus-summary-toggle-header 1)
+       (while (not achar)
+         (message "Query (%s): " (nnmairix-create-message-line-for-search))
+         (setq achar (read-char))
+         (when (not (assoc achar char-header))
+           (setq achar nil)))
+       (set-buffer gnus-article-buffer)
+       (setq header nil)
+       (when (setq cq (nth 1 (assoc achar char-header)))
+         (setq header
+               (nnmairix-replace-illegal-chars
+                (gnus-fetch-field (nth 1 (assoc achar char-header))))))
+       (setq header (read-string
+                     (concat "Match " (nth 3 (assoc achar char-header)) " on: ")
+                     header))
+       (push  (concat (nth 2 (assoc achar char-header)) ":" header) query)
+       (setq finished (not (y-or-n-p "Add another search query? "))
+             achar nil)))
+    (setq threads (y-or-n-p "Include whole threads? "))
+    (setq group (read-string "Group name: "))
+    (set-buffer gnus-summary-buffer)
+    (message "Creating group %s on server %s with query %s." group
+            (gnus-method-to-server server) (mapconcat 'identity query " "))
+    (nnmairix-create-search-group server group query threads)))
+
+(defun nnmairix-create-server-and-default-group ()
+  "Interactively create new nnmairix server with default search group.
+All necessary information will be queried from the user."
+  (interactive)
+  (let* ((name (read-string "Name of the mairix server: "))
+       (server (gnus-completing-read "Back end server"
+                                (nnmairix-get-valid-servers) t))
+       (mairix (read-string "Command to call mairix: " "mairix"))
+       (defaultgroup (read-string "Default search group: "))
+       (backend (symbol-name (car (gnus-server-to-method server))))
+       (servername (nth 1 (gnus-server-to-method server)))
+       (hidden (and (string-match "^nn\\(imap\\|maildir\\)$" backend)
+                    (y-or-n-p
+                     "Does the back end server work with maildir++ (i.e. hidden directories)? ")))
+       create)
+
+    (apply (intern (format "%s-%s" backend "open-server"))
+          (list servername))
+
+    (when (and hidden
+              (string-match "^\\." defaultgroup))
+      (setq defaultgroup (substring defaultgroup 1)))
+    ;; Create default search group
+    (gnus-group-make-group
+     defaultgroup (list 'nnmairix name  (list 'nnmairix-backend (intern backend))
+                       (list 'nnmairix-backend-server servername)
+                       (list 'nnmairix-mairix-command mairix)
+                       (list 'nnmairix-hidden-folders hidden)
+                       (list 'nnmairix-default-group defaultgroup)))))
+
+(defun nnmairix-group-change-query-this-group (&optional query)
+  "Set QUERY for group under cursor."
+  (interactive)
+  (let* ((group (gnus-group-group-name))
+        (method (gnus-find-method-for-group group))
+        (oldquery (gnus-group-get-parameter group 'query t)))
+    (if (eq (car method) 'nnmairix)
+       (progn
+         (when (listp oldquery)
+           (setq oldquery (mapconcat 'identity oldquery " ")))
+         (setq query (or query
+                         (read-string "New query: " oldquery)))
+         (when (stringp query)
+           (setq query (split-string query)))
+         (when query
+           (gnus-group-set-parameter group 'query query)
+           (nnmairix-update-and-clear-marks group)))
+      (error "This is no nnmairix group"))))
+
+
+(defun nnmairix-group-toggle-threads-this-group (&optional threads)
+  "Toggle threads parameter for this group.
+If THREADS is a positive number, set threads parameter to t.
+If THREADS is a negative number, set it to nil."
+  (interactive)
+  (let ((group (gnus-group-group-name)))
+    (when (nnmairix-group-toggle-parameter
+          group 'threads "Threads" threads)
+      (nnmairix-update-and-clear-marks group))))
+
+(defun nnmairix-group-toggle-propmarks-this-group (&optional propmarks)
+  "Toggle marks propagation for this group.
+If PROPMARKS is a positive number, set parameter to t.
+If PROPMARKS is a negative number, set it to nil."
+  (interactive)
+  (unless (nnmairix-check-mairix-version "maildirpatch")
+    (error "You need a mairix binary with maildir patch to use this feature.  See docs for details"))
+  (let ((group (gnus-group-group-name)))
+    (when (or (not (string= (gnus-group-short-name group)
+                           (cadr (assoc 'nnmairix-default-group
+                                       (gnus-find-method-for-group group)))))
+             (y-or-n-p "You should not activate marks propagation for the default \
+search group.  Are you sure? "))
+      (nnmairix-group-toggle-parameter
+       group 'propmarks "Marks propagation" propmarks))))
+
+(defun nnmairix-group-toggle-allowfast-this-group (&optional allowfast)
+  "Toggle fast entering for this group.
+If ALLOWFAST is a positive number, set parameter to t.
+If ALLOWFAST is a negative number, set it to nil."
+  (interactive)
+  (nnmairix-group-toggle-parameter
+   (gnus-group-group-name) 'allow-fast "Fast entering" allowfast))
+
+
+(defun nnmairix-group-toggle-readmarks-this-group (&optional readmarks)
+  "Toggle read/unread marks for this group.
+If READMARKS is a positive number, articles will always be read.
+If READMARKS is a negative number, articles will always be unread.
+If READMARKS is t or zero, marks will stay unchanged."
+  (interactive)
+  (let*  ((group (gnus-group-group-name))
+         (method (gnus-find-method-for-group group))
+         (readmarks (or readmarks
+                        (gnus-group-get-parameter group 'readmarks))))
+    (if (eq (car method) 'nnmairix)
+       (cond
+        ((or (and (numberp readmarks) (< readmarks 0))
+             (eq readmarks 'read))
+         (gnus-group-set-parameter group 'readmarks 'unread)
+         (nnheader-message 3 "Articles in %s always unread." group))
+        ((or (and (numberp readmarks) (> readmarks 0))
+             (not readmarks))
+             (gnus-group-set-parameter group 'readmarks 'read)
+             (nnheader-message 3 "Articles in %s always read." group))
+        (t
+         (gnus-group-set-parameter group 'readmarks nil)
+         (nnheader-message 3 "Read marks in %s stay unchanged." group)))
+      (error "This is no nnmairix group"))))
+
+
+(defun nnmairix-search (query &optional server threads)
+  "Sends QUERY to nnmairix backend SERVER, using default its search group.
+
+Default search group is automatically entered and results are shown.
+If THREADS is t, enable threads.
+If THREADS is a negative number, disable threads.
+Otherwise, leave threads parameter as it is."
+  (interactive (list (read-string "Query: ")))
+  (when (not server)
+    (setq server (car (nnmairix-get-server))))
+  (if (not server)
+      (error "No opened nnmairix server found")
+    (setq server (gnus-server-to-method server)))
+  (nnmairix-open-server (nth 1 server))
+  (let* ((qualgroup (gnus-group-prefixed-name nnmairix-default-group
+                                             (list 'nnmairix (nth 1 server)))))
+    (set-buffer gnus-group-buffer)
+    (when (stringp query)
+      (setq query (split-string query)))
+    (gnus-group-set-parameter qualgroup 'query query)
+    (if (symbolp threads)
+       (when (eq threads 't)
+         (gnus-group-set-parameter qualgroup 'threads t))
+      (when (< threads 0)
+       (gnus-group-set-parameter qualgroup 'threads nil)))
+    (nnmairix-update-and-clear-marks qualgroup)
+    (unless (equal (gnus-active qualgroup) '(1 . 0))
+      (gnus-group-read-group nil t qualgroup))))
+
+(defun nnmairix-search-thread-this-article ()
+  "Search thread for the current article.
+This is effectively a shortcut for calling `nnmairix-search'
+with m:msgid of the current article and enabled threads."
+  (interactive)
+  (let* ((server
+         (nnmairix-backend-to-server gnus-current-select-method))
+        mid)
+    (if server
+       (if (gnus-buffer-live-p gnus-article-buffer)
+           (progn
+             (with-current-buffer gnus-article-buffer
+               (gnus-summary-toggle-header 1)
+               (setq mid (message-fetch-field "Message-ID")))
+             (while (string-match "[<>]" mid)
+               (setq mid (replace-match "" t t mid)))
+             (nnmairix-search (concat "m:" mid) server t))
+         (message "No article buffer."))
+      (error "No nnmairix server found for back end %s:%s"
+            (symbol-name (car gnus-current-select-method))
+            (nth 1 gnus-current-select-method)))))
+
+(defun nnmairix-search-from-this-article ()
+  "Search messages from sender of the current article.
+This is effectively a shortcut for calling `nnmairix-search' with
+f:current_from."
+  (interactive)
+  (let* ((server
+         (nnmairix-backend-to-server gnus-current-select-method))
+        from)
+    (if server
+       (if (gnus-buffer-live-p gnus-article-buffer)
+           (progn
+             (with-current-buffer gnus-article-buffer
+               (gnus-summary-toggle-header 1)
+               (setq from (cadr (gnus-extract-address-components
+                                 (gnus-fetch-field "From"))))
+               (nnmairix-search (concat "f:" from) server -1)))
+         (message "No article buffer."))
+      (error "No nnmairix server found for back end %s:%s"
+            (symbol-name (car gnus-current-select-method))
+            (nth 1 gnus-current-select-method)))))
+
+
+(defun nnmairix-purge-old-groups (&optional dontask server)
+  "Delete mairix search groups which are no longer used.
+
+You may want to call this from time to time if you are creating
+and deleting lots of nnmairix groups.  If DONTASK is t, do not ask
+before deleting a group on the back end.  SERVER specifies nnmairix server."
+  (interactive)
+  (let ((server (or server
+                   (gnus-server-to-method (car (nnmairix-get-server))))))
+    (if (nnmairix-open-server (nth 1 server))
+       (when (nnmairix-call-backend
+              "request-list" nnmairix-backend-server)
+         (let (cur qualgroup folder)
+           (with-current-buffer nntp-server-buffer
+             (goto-char (point-min))
+             (while (re-search-forward nnmairix-group-regexp (point-max) t)
+               (setq cur (match-string 0)
+                     qualgroup (gnus-group-prefixed-name
+                                (match-string 1) server))
+               (when (not (and (gnus-group-entry qualgroup)
+                               (string= cur
+                                        (gnus-group-get-parameter
+                                         qualgroup 'folder))))
+                 (when (or dontask
+                           (y-or-n-p
+                            (concat "Delete group " cur
+                                    " on server " nnmairix-backend-server "? ")))
+                   (nnmairix-call-backend
+                    "request-delete-group" cur t nnmairix-backend-server)))))))
+      (message "Couldn't open server %s" (nth 1 server)))))
+
+
+(defun nnmairix-update-database (&optional servers)
+  "Call mairix for updating the database for SERVERS.
+
+If SERVERS is nil, do update for all nnmairix servers.  Mairix
+will be called asynchronously unless
+`nnmairix-mairix-synchronous-update' is t.  Mairix will be called
+with `nnmairix-mairix-update-options'."
+  (interactive)
+  (let ((servers (or servers
+                    (nnmairix-get-nnmairix-servers)))
+       args cur commandsplit)
+    (while servers
+      (setq cur (car (pop servers)))
+      (nnmairix-open-server
+       (nth 1 (gnus-server-to-method cur)))
+      (setq commandsplit (split-string nnmairix-mairix-command))
+      (nnheader-message 7 "Updating mairix database for %s..." cur)
+      (if nnmairix-mairix-synchronous-update
+         (progn
+           (setq args (append (list (car commandsplit) nil
+                                    (get-buffer nnmairix-mairix-output-buffer)
+                                    nil)))
+           (if (> (length commandsplit) 1)
+               (setq args (append args (cdr commandsplit) nnmairix-mairix-update-options))
+             (setq args (append args nnmairix-mairix-update-options)))
+           (apply 'call-process args)
+           (nnheader-message 7 "Updating mairix database for %s... done" cur))
+       (progn
+         (setq args (append (list cur (get-buffer nnmairix-mairix-output-buffer)
+                                  (car commandsplit))))
+         (if (> (length commandsplit) 1)
+             (setq args (append args (cdr commandsplit) nnmairix-mairix-update-options))
+           (setq args (append args nnmairix-mairix-update-options)))
+         (set-process-sentinel (apply 'start-process args)
+                               'nnmairix-sentinel-mairix-update-finished))))))
+
+(defun nnmairix-group-delete-recreate-this-group ()
+  "Deletes and recreates group on the back end.
+You can use this function on nnmairix groups which continuously
+show wrong article counts."
+  (interactive)
+  (let* ((group (gnus-group-group-name))
+        (method (gnus-find-method-for-group group)))
+    (unless (eq (car method) 'nnmairix)
+      (error "This is not a nnmairix group"))
+    (when (y-or-n-p
+          (format "Really recreate group %s on the back end? " group))
+      (nnmairix-delete-recreate-group group)
+      (gnus-group-get-new-news-this-group))))
+
+(defun nnmairix-propagate-marks (&optional server)
+  "Propagate marks from nnmairix group to original articles.
+Unless SERVER is explicitly specified, will use the last opened
+nnmairix server. Only marks from current session will be set."
+  (interactive)
+  (if server
+      (nnmairix-open-server server)
+    (unless (eq (car gnus-current-select-method) 'nnmairix)
+      (if nnmairix-current-server
+         (nnmairix-open-server nnmairix-current-server)
+       (error "No opened nnmairix server"))))
+  (if nnmairix-marks-cache
+      (let (number ogroup number-cache method mid-marks temp)
+       ;; first we get the article numbers
+       (catch 'problem
+         (while (setq ogroup (pop nnmairix-marks-cache))
+           (while (setq mid-marks (pop (cdr ogroup)))
+             (setq number
+                   (cdr
+                    (gnus-request-head (car mid-marks) (car ogroup))))
+             (unless number
+               (nnheader-message
+                3 "Unable to set mark: couldn't determine article number for %s in %s"
+                (car mid-marks) (car ogroup))
+               (throw 'problem nil))
+             (setq temp (assoc (car ogroup) number-cache))
+             (if temp
+                 (catch 'done
+                   (dolist (cur (cdr temp))
+                     (when (equal (cdr cur) (list (nth 1 mid-marks) (nth 2 mid-marks)))
+                       (nconc (car cur) (list number))
+                       (throw 'done nil)))
+                   (nconc temp (list (list (list number) (nth 1 mid-marks) (nth 2 mid-marks)))))
+               (push (list (car ogroup) (list (list number) (nth 1 mid-marks) (nth 2 mid-marks)))
+                     number-cache)))))
+       ;; now we set the marks
+       (with-current-buffer gnus-group-buffer
+         (nnheader-message 5 "nnmairix: Propagating marks...")
+         (dolist (cur number-cache)
+           (setq method (gnus-find-method-for-group (car cur)))
+           (apply (intern (format "%s-%s"
+                                  (symbol-name (car method))
+                                  "request-set-mark"))
+                  (gnus-group-short-name (car cur))
+                  (cdr cur)
+                  (list (nth 1 method)))
+           (gnus-group-jump-to-group (car cur))
+           (gnus-group-get-new-news-this-group)))
+       (nnheader-message 5 "nnmairix: Propagating marks... done"))
+    (nnheader-message 3 "No marks to propagate.")))
+
+(defun nnmairix-update-groups (servername &optional skipdefault updatedb)
+  "Update all search groups on SERVERNAME.
+If SKIPDEFAULT is t, the default search group will not be
+updated.
+If UPDATEDB is t, database for SERVERNAME will be updated first."
+  (interactive (list (gnus-completing-read "Update groups on server"
+                               (nnmairix-get-nnmairix-servers))))
+  (save-excursion
+    (when (string-match ".*:\\(.*\\)" servername)
+      (setq servername (match-string 1 servername)))
+    (if (not (assoc (format "nnmairix:%s" servername)
+                   (nnmairix-get-nnmairix-servers)))
+       (nnheader-message 3 "Server %s not opened" servername)
+      (when updatedb
+       (let ((nnmairix-mairix-synchronous-update t))
+         (nnmairix-update-database
+          (list (list (format "nnmairix:%s" servername))))))
+      (let ((groups (nnmairix-get-groups-from-server servername))
+           default)
+       (when skipdefault
+         (setq default
+               (format "nnmairix+%s:%s"
+                       servername
+                       (cadr
+                        (assoc 'nnmairix-default-group
+                               (gnus-server-to-method
+                                (format "nnmairix:%s" servername)))))))
+       (dolist (cur groups)
+         (unless (and skipdefault
+                      (string= (car cur) default))
+           (gnus-group-jump-to-group (car cur))
+           (gnus-group-mark-group 1)))
+       (gnus-group-get-new-news-this-group)))))
+
+(defun nnmairix-remove-tick-mark-original-article ()
+  "Remove tick mark from original article.
+Marks propagation has to be enabled for this to work."
+  (interactive)
+  (unless (eq (car gnus-current-select-method) 'nnmairix)
+    (error "Not in a nnmairix group"))
+  (save-excursion
+    (let ((mid (mail-header-message-id (gnus-summary-article-header)))
+         groups cur)
+      (when mid
+       (setq groups (nnmairix-determine-original-group-from-registry mid))
+       (unless (or groups
+                   nnmairix-only-use-registry)
+         (setq groups
+               (nnmairix-determine-original-group-from-path mid nnmairix-current-server)))
+       (unless groups
+         (error "Couldn't find original article"))
+       (dolist (cur groups)
+         (push `(,cur (,mid del (tick))) nnmairix-marks-cache))
+       (nnheader-message 5 "Will remove tick mark for %s upon closing." mid)))))
+
+;;; ==== Helper functions
+
+(defun nnmairix-request-group-with-article-number-correction (folder qualgroup)
+  "Request FOLDER on back end for nnmairix QUALGROUP and article number correction."
+  (save-excursion
+    (nnmairix-call-backend "request-group" folder nnmairix-backend-server)
+    (set-buffer nnmairix-mairix-output-buffer)
+    (goto-char (point-min))
+    (re-search-forward "^Matched.*messages")
+    (nnheader-message 7 (match-string 0))
+    (set-buffer nntp-server-buffer)
+    (goto-char (point-min))
+    (let ((status (read (current-buffer)))
+         (total (read (current-buffer)))
+         (low (read (current-buffer)))
+         (high (read (current-buffer)))
+         (corr (gnus-group-get-parameter qualgroup 'numcorr t)))
+      (if (= status 211)
+         (progn
+           ;; Article number correction
+           (if (and corr
+                    (> (+ (car (cddr corr)) high) 0))
+               (progn
+                 (when (car corr) ;Group has changed
+                   (setq corr
+                         (list nil
+                               (car (cddr corr))
+                               (+ (car (cddr corr)) high)))
+                   (gnus-group-set-parameter
+                    qualgroup 'numcorr corr))
+                 (setq low (+ low (cadr corr))
+                       high (+ high (cadr corr))))
+             (when (member nnmairix-backend
+                           nnmairix-delete-and-create-on-change)
+               (gnus-group-set-parameter
+                qualgroup 'numcorr (list nil 0 high))))
+           (erase-buffer)
+           (insert (format "%d %d %d %d %s" status total low high
+                           (gnus-group-real-name qualgroup)))
+           t)
+       (progn
+         (nnheader-report
+          'nnmairix "Error calling back end on group %s" folder)
+         nil)))))
+
+(defun nnmairix-call-mairix-binary (command folder searchquery threads)
+  "Call mairix binary with COMMAND, using FOLDER and SEARCHQUERY.
+If THREADS is non-nil, enable full threads."
+  (let ((args (cons (car command) '(nil t nil))))
+    (with-current-buffer
+       (get-buffer-create nnmairix-mairix-output-buffer)
+      (erase-buffer)
+      (when (> (length command) 1)
+       (setq args (append args (cdr command))))
+      (when nnmairix-mairix-search-options
+       (setq args (append args nnmairix-mairix-search-options)))
+      ;; If we have a patched mairix binary, call it with "-c"
+      (when (nnmairix-check-mairix-version "maildirpatch")
+       (setq args (append args '("-c"))))
+      (when threads
+       (setq args (append args '("-t"))))
+      (apply 'call-process
+            (append args (list "-o" folder) searchquery)))))
+
+(defun nnmairix-call-mairix-binary-raw (command query)
+  "Call mairix binary with COMMAND and QUERY in raw mode."
+  (let ((args (cons (car command) '(nil t nil))))
+    (with-current-buffer
+       (get-buffer-create nnmairix-mairix-output-buffer)
+      (erase-buffer)
+      (when (> (length command) 1)
+        (setq args (append args (cdr command))))
+      (setq args (append args '("-r")))
+      (apply 'call-process
+             (append args query)))))
+
+(defun nnmairix-get-server ()
+  "If there exists just one nnmairix server, return its value.
+Otherwise, ask user for server."
+  (let ((openedserver (nnmairix-get-nnmairix-servers)))
+    (when (not openedserver)
+      (error "No opened nnmairix server found"))
+    (if (> (length openedserver) 1)
+       (progn
+         (while
+             (equal '("")
+                 (setq nnmairix-last-server
+                       (list (gnus-completing-read "Server" openedserver t
+                                              (or nnmairix-last-server
+                                                  "nnmairix:"))))))
+         nnmairix-last-server)
+      (car openedserver))))
+
+(defun nnmairix-get-nnmairix-servers (&optional all)
+  "Return available nnmairix servers.
+If ALL is t, return also the unopened/failed ones."
+  (let ((alist gnus-opened-servers)
+       server openedserver)
+    (while alist
+      (setq server (pop alist))
+      (when (and server
+                (or all
+                    (eq (cadr server) 'ok))
+                (eq (caar server) 'nnmairix)
+                (not (member (car server) gnus-ephemeral-servers)))
+       (setq server
+             (concat (symbol-name (caar server)) ":" (nth 1 (car server))))
+       (push (list server) openedserver)))
+    openedserver))
+
+(defun nnmairix-get-valid-servers ()
+  "Return list of valid back end servers for nnmairix groups."
+  (let ((alist gnus-opened-servers)
+       (mairixservers (nnmairix-get-nnmairix-servers t))
+       server mserver openedserver occ cur)
+    ;; Get list of all nnmairix backends (i.e. backends which are
+    ;; already occupied)
+    (dolist (cur mairixservers)
+      (push
+       (concat
+       (symbol-name
+        (cadr (assoc 'nnmairix-backend
+                     (gnus-server-to-method (car cur)))))
+        ":"
+        (cadr (assoc 'nnmairix-backend-server
+                     (gnus-server-to-method (car cur)))))
+       occ))
+    (while alist
+      (setq server (pop alist))
+      (setq mserver (gnus-method-to-server (car server)))
+      ;; If this is the native server, convert it to the real server
+      ;; name to avoid confusion
+      (when (string= mserver "native")
+       (setq mserver (format "%s:%s"
+                             (caar server)
+                             (nth 1 (car server)))))
+      (when (and server
+                (eq (cadr server) 'ok)
+                (member (caar server) nnmairix-valid-backends)
+                (not (member (car server) gnus-ephemeral-servers))
+                (not (member (gnus-method-to-server (car server)) occ)))
+       (push
+        mserver
+        openedserver)))
+    openedserver))
+
+(defun nnmairix-get-groups-from-server (servername)
+  "Return all groups for nnmairix server SERVERNAME."
+  (let ((searchstring (format "nnmairix\\+%s:" servername))
+       groups)
+    (dolist (cur gnus-newsrc-alist)
+      (when (string-match searchstring
+                         (car cur))
+       (push (list (car cur)) groups)))
+    groups))
+
+(defun nnmairix-call-backend (func &rest args)
+  "Call a function FUNC on backend with ARGS."
+  (apply (intern (format "%s-%s" (symbol-name nnmairix-backend) func)) args))
+
+(defun nnmairix-get-backend-folder (group &optional server)
+  "Return back end GROUP from nnmairix group on SERVER."
+  (let* ((qualgroup (if server
+                       (gnus-group-prefixed-name group (list 'nnmairix server))
+                     group))
+        (folder (gnus-group-get-parameter qualgroup 'folder)))
+    folder))
+
+(defun nnmairix-get-numcorr (group &optional server)
+  "Return values for article number correction nnmairix GROUP on SERVER."
+  (let* ((qualgroup (if server
+                       (gnus-group-prefixed-name group (list 'nnmairix server))
+                     group))
+        (corr (gnus-group-get-parameter qualgroup 'numcorr t)))
+    corr))
+
+
+(defun nnmairix-rename-files-consecutively (path)
+  "Rename all nnml mail files in PATH so that they have consecutive numbers.
+This should correct problems of wrong article counts when using
+nnmairix with nnml backends."
+  (let* ((files
+        (sort
+         (mapcar 'string-to-number
+                 (directory-files path nil "[0-9]+" t))
+         '<))
+        (lastplusone (car files))
+        (path (file-name-as-directory path)))
+    (dolist (cur files)
+      (when (not (= cur lastplusone))
+       (rename-file (concat path
+                            (number-to-string cur))
+                    (concat path
+                            (number-to-string lastplusone)))
+       (setq cur lastplusone))
+      (setq lastplusone (1+ cur)))))
+
+(defun nnmairix-replace-group-and-numbers (articles backendgroup mairixgroup numc type)
+  "Replace folder names in Xref header and correct article numbers.
+Do this for all ARTICLES on BACKENDGROUP.  Replace using
+MAIRIXGROUP.  NUMC contains values for article number correction.
+TYPE is either 'nov or 'headers."
+  (nnheader-message 7 "nnmairix: Rewriting headers...")
+  (cond
+   ((eq type 'nov)
+    (let ((buf (get-buffer-create " *nnmairix buffer*"))
+         (corr (not (zerop numc)))
+         (name (buffer-name nntp-server-buffer))
+         header cur xref)
+      (with-current-buffer buf
+       (erase-buffer)
+       (set-buffer nntp-server-buffer)
+       (goto-char (point-min))
+       (mapc
+        (lambda (article)
+          (when (or (looking-at (number-to-string article))
+                    (nnheader-find-nov-line article))
+            (setq cur (nnheader-parse-nov))
+            (when corr
+              (setq article (+ (mail-header-number cur) numc))
+              (mail-header-set-number cur article))
+            (setq xref (mail-header-xref cur))
+            (when (and (stringp xref)
+                       (string-match (format "[ \t]%s:[0-9]+" backendgroup) xref))
+              (setq xref (replace-match (format " %s:%d" mairixgroup article) t nil xref))
+              (mail-header-set-xref cur xref))
+            (set-buffer buf)
+            (nnheader-insert-nov cur)
+            (set-buffer nntp-server-buffer)
+            (when (not (eobp))
+              (forward-line 1))))
+        articles)
+       (kill-buffer nntp-server-buffer)
+       (set-buffer buf)
+       (rename-buffer name)
+       (setq nntp-server-buffer buf))))
+   ((and (eq type 'headers)
+        (not (zerop numc)))
+    (with-current-buffer nntp-server-buffer
+      (save-excursion
+       (goto-char (point-min))
+       (while (re-search-forward "^[23][0-9]+ \\([0-9]+\\)" nil t)
+         (replace-match (number-to-string
+                         (+ (string-to-number (match-string 1)) numc))
+                        t t nil 1))))))
+  (nnheader-message 7 "nnmairix: Rewriting headers... done"))
+
+(defun nnmairix-backend-to-server (server)
+  "Return nnmairix server most probably responsible for back end SERVER.
+User will be asked if this cannot be determined.  Result is saved in
+parameter 'indexed-servers of corresponding default search
+group."
+  (let ((allservers (nnmairix-get-nnmairix-servers))
+       mairixserver found defaultgroup)
+    (if (> (length allservers) 1)
+       (progn
+         ;; If there is more than one nnmairix server, we go through them
+         (while (and allservers (not found))
+           (setq mairixserver (gnus-server-to-method (car (pop allservers))))
+           ;; First we look if SERVER is the backend of current nnmairix server
+           (setq found (and (eq (cadr (assoc 'nnmairix-backend mairixserver))
+                                (car server))
+                            (string= (cadr (assoc 'nnmairix-backend-server mairixserver))
+                                     (nth 1 server))))
+           ;; If that's not the case, we look at 'indexed-servers
+           ;; variable in default search group
+           (when (not found)
+             (setq defaultgroup (cadr (assoc 'nnmairix-default-group mairixserver)))
+             (setq found (member (gnus-method-to-server server)
+                                 (gnus-group-get-parameter
+                                  (gnus-group-prefixed-name defaultgroup
+                                                            mairixserver)
+                                  'indexed-servers t)))))
+         ;; If still not found, we ask user
+         (when (not found)
+           (setq mairixserver
+                 (gnus-server-to-method
+                  (gnus-completing-read
+                   (format "Cannot determine which nnmairix server indexes %s. Please specify"
+                           (gnus-method-to-server server))
+                   (nnmairix-get-nnmairix-servers) nil "nnmairix:")))
+           ;; Save result in parameter of default search group so that
+           ;; we don't have to ask again
+           (setq defaultgroup (gnus-group-prefixed-name
+                               (cadr (assoc 'nnmairix-default-group mairixserver)) mairixserver))
+           (gnus-group-set-parameter
+            defaultgroup
+            'indexed-servers
+            (append (gnus-group-get-parameter defaultgroup 'indexed-servers t)
+                    (list (gnus-method-to-server server)))))
+         mairixserver)
+      ;; If there is just one (or none) nnmairix server:
+      (gnus-server-to-method (caar allservers)))))
+
+
+(defun nnmairix-delete-recreate-group (group)
+  "Delete and recreate folder from GROUP on the back end."
+  (when (member nnmairix-backend nnmairix-delete-and-create-on-change)
+    (let ((folder (gnus-group-get-parameter group 'folder)))
+      (if (string-match nnmairix-group-regexp folder)
+         (progn
+           (nnmairix-call-backend "open-server"
+                                  nnmairix-backend-server)
+           (nnmairix-call-backend "request-delete-group"
+                                  folder t nnmairix-backend-server)
+           (nnmairix-call-backend "request-create-group"
+                                  folder nnmairix-backend-server))
+       (error "`nnmairix-delete-recreate-group' called on \
+non-mairix group.  Check folder parameter")))))
+
+(defun nnmairix-update-and-clear-marks (group &optional method)
+  "Update group and clear all marks from GROUP using METHOD."
+  (let ((method (or method
+                   (gnus-find-method-for-group group)))
+       (corr (gnus-group-get-parameter group 'numcorr t))
+       info)
+    (unless (or (gnus-group-prefixed-p group)
+               (not method))
+      (setq group (gnus-group-prefixed-name group method)))
+    (if (eq (nth 0 method) 'nnmairix)
+       (save-excursion
+         (nnmairix-open-server (nth 1 method))
+         (set-buffer gnus-group-buffer)
+         ;; (gnus-group-set-parameter group 'propmarks nil)
+         (setq info (gnus-get-info group))
+         ;; Clear active and info
+         (gnus-set-active group nil)
+         (gnus-info-clear-data info)
+         ;; Delete and re-create group if needed
+         (nnmairix-delete-recreate-group group)
+         ;; set flag that group has changed for article number correction
+         (when (member nnmairix-backend nnmairix-delete-and-create-on-change)
+           (when corr
+             (setcar corr t)
+             (gnus-group-set-parameter group 'numcorr corr)))
+         (gnus-group-jump-to-group group)
+         (gnus-group-get-new-news-this-group))
+      (error "`nnmairix-update-and-clear-marks' called with non-nnmairix group"))))
+
+(defun nnmairix-sentinel-mairix-update-finished (proc status)
+  "Sentinel for mairix update process PROC with STATUS."
+  (if (equal status "finished\n")
+      (nnheader-message 7 "Updating mairix database for %s... done" proc)
+    (error "There was an error updating the mairix database for server %s.  \
+See %s for details" proc nnmairix-mairix-output-buffer)))
+
+(defun nnmairix-create-message-line-for-search ()
+  "Create message line for interactive query in minibuffer."
+  (mapconcat
+   (function
+    (lambda (cur)
+      (format "%c=%s" (car cur) (nth 3 cur))))
+   nnmairix-interactive-query-parameters ","))
+
+(defun nnmairix-replace-illegal-chars (header)
+  "Replace illegal characters in HEADER for mairix query."
+  (when header
+    (while (string-match "[^-.@/,& [:alnum:]]" header)
+      (setq header (replace-match "" t t header)))
+    (while (string-match "[-& ]" header)
+      (setq header (replace-match "," t t header)))
+    header))
+
+(defun nnmairix-group-toggle-parameter (group parameter description &optional par)
+  "Toggle on GROUP a certain PARAMETER.
+DESCRIPTION will be shown to the user with the activation
+status.  If PAR is a positive number, the group parameter will be
+set to t and to nil otherwise."
+  (let* ((method (gnus-find-method-for-group group))
+        (par (or par
+                 (not (gnus-group-get-parameter group parameter)))))
+    (if (eq (car method) 'nnmairix)
+       (progn
+         (when (numberp par)
+           (setq par (> par 0)))
+         (gnus-group-set-parameter group parameter par)
+         (if par
+             (message "%s activated for group %s" description group)
+           (message "%s deactivated for group %s" description group))
+         t)
+      (error "This is no nnmairix group")
+      nil)))
+
+;; Search for original article helper functions
+
+(defun nnmairix-goto-original-article (&optional no-registry)
+  "Jump to the original group and display article.
+The original group of the article is first determined with the
+registry (if enabled).  If the registry is not enabled or did not
+find the article or the prefix NO-REGISTRY is non-nil, this
+function will try to determine the original group form the path
+of the mail file.  The path is obtained through another mairix
+search in raw mode."
+  (interactive "P")
+  (when (not (eq (car gnus-current-select-method) 'nnmairix))
+    (let ((method (gnus-find-method-for-group gnus-newsgroup-name)))
+      (if (eq (car method) 'nnmairix)
+         (nnmairix-open-server (nth 1 method))
+       (error "Not in a nnmairix group"))))
+  (when (not (gnus-buffer-live-p gnus-article-buffer))
+    (error "No article buffer available"))
+  (let ((server (nth 1 gnus-current-select-method))
+       mid rval group allgroups)
+    ;; get message id
+    (with-current-buffer gnus-article-buffer
+      (gnus-summary-toggle-header 1)
+      (setq mid (message-fetch-field "Message-ID"))
+      ;; first check the registry (if available)
+      (unless no-registry
+       (setq allgroups (nnmairix-determine-original-group-from-registry mid)))
+      (unless (or allgroups
+                 nnmairix-only-use-registry)
+       ;; registry was not available or did not find article
+       ;; so we search again with mairix in raw mode to get filename
+       (setq allgroups
+             (nnmairix-determine-original-group-from-path mid server)))
+      (if (> (length allgroups) 1)
+         (setq group
+               (gnus-completing-read
+                "Message exists in more than one group. Choose"
+                allgroups t))
+       (setq group (car allgroups))))
+    (if group
+       ;; show article in summary buffer
+       (nnmairix-show-original-article group mid)
+      (nnheader-message 3 "Couldn't find original article"))))
+
+(defun nnmairix-determine-original-group-from-registry (mid)
+  "Try to determine original group for message-id MID from the registry."
+  (when (gnus-bound-and-true-p 'gnus-registry-enabled)
+    (unless (string-match "^<" mid)
+      (set mid (concat "<" mid)))
+    (unless (string-match ">$" mid)
+      (set mid (concat mid ">")))
+    (gnus-registry-get-id-key mid 'group)))
+
+(defun nnmairix-determine-original-group-from-path (mid server)
+  "Determine original group(s) for message-id MID from the file path.
+The file path is obtained through a mairix search for the id on
+SERVER."
+  (nnmairix-open-server server)
+  (while (string-match "[<>]" mid)
+    (setq mid (replace-match "" t t mid)))
+  ;; mairix somehow does not like '$' in message-id
+  (when (string-match "\\$" mid)
+    (setq mid (concat mid "=")))
+  (while (string-match "\\$" mid)
+    (setq mid (replace-match "=," t t mid)))
+  (let (allgroups)
+    (if (zerop (nnmairix-call-mairix-binary-raw
+               (split-string nnmairix-mairix-command)
+               (list (concat "m:" mid))))
+       (with-current-buffer nnmairix-mairix-output-buffer
+         (goto-char (point-min))
+         (while (re-search-forward "^/.*$" nil t)
+           (push (nnmairix-get-group-from-file-path (match-string 0))
+                 allgroups)
+           (forward-line 1)))
+      (error "Mairix could not find original article.  See buffer %s for details"
+            nnmairix-mairix-output-buffer))
+    allgroups))
+
+(defun nnmairix-get-group-from-file-path (file)
+  "Get group by parsing the message location FILE."
+  (let (path filename serverbase group maildirflag allgroups)
+    (string-match "^\\(.*\\)/\\(.*?\\)$" file)
+    (setq path (expand-file-name (match-string 1 file)))
+    (setq filename (match-string 2 file))
+    ;; when we deal with maildir, remove cur/new/tmp from path
+    (setq maildirflag (string-match ".+\\..+\\..+" filename))
+    (when maildirflag
+      (setq path
+           (replace-regexp-in-string
+            ".*\\(/cur\\|/new\\|/tmp\\)$" "" path t t 1)))
+    ;; we first check nnml and nnmaildir servers
+    (setq
+     group
+     (catch 'found
+       (dolist (cur gnus-opened-servers)
+        (when (or (and (not maildirflag)
+                       (eq (caar cur) 'nnml))
+                  (and maildirflag
+                       (eq (caar cur) 'nnmaildir)))
+          ;; get base path from server
+          (if maildirflag
+              (setq serverbase (cadr (assoc 'directory (car cur))))
+            (setq serverbase (cadr (assoc 'nnml-directory (car cur))))
+            (unless serverbase
+              (setq serverbase nnml-directory)))
+          (setq serverbase (file-name-as-directory
+                            (expand-file-name serverbase)))
+          (when (string-match (concat serverbase "\\(.*\\)") path)
+            ;; looks good - rest of the path should be the group
+            (setq group (match-string 1 path))
+            (when (string-match "/$" group)
+              (setq group (replace-match "" t t group)))
+            (unless maildirflag
+              ;; for nnml: convert slashes to dots
+              (while (string-match "/" group)
+                (setq group (replace-match "." t t group))))
+            (setq group (gnus-group-prefixed-name group (car cur)))
+            ;; check whether this group actually exists
+            (when (gnus-group-entry group)
+              (throw 'found group)))))))
+    (unless group
+      ;; we haven't found it yet --> look for nnimap groups. Assume
+      ;; last element of the path is the group. This might fail since
+      ;; IMAP servers may present groups to the client in arbitrary
+      ;; ways...
+      (string-match "^.*/\\.?\\(.*\\)$" path)
+      (setq group (match-string 1 path))
+      ;; convert dots to slashes (nested group)
+      (while (string-match "\\." group)
+       (setq group (replace-match "/" t t group)))
+      (dolist (cur gnus-opened-servers)
+       (when (eq (caar cur) 'nnimap)
+         (when (gnus-group-entry
+                (gnus-group-prefixed-name group (car cur)))
+           (push
+            (gnus-group-prefixed-name group (car cur))
+            allgroups))))
+      (if (> (length allgroups) 1)
+         (setq group (gnus-completing-read
+                      "Group %s exists on more than one IMAP server. Choose"
+                      allgroups t))
+       (setq group (car allgroups))))
+    group))
+
+(defun nnmairix-show-original-article (group mid)
+  "Switch to GROUP and display Article with message-id MID."
+  (unless (string-match "^<" mid)
+    (set mid (concat "<" mid)))
+  (unless (string-match ">$" mid)
+    (set mid (concat mid ">")))
+  (when (string-match "Summary" (buffer-name (current-buffer)))
+    (gnus-summary-exit))
+  (pop-to-buffer gnus-group-buffer)
+  (gnus-group-jump-to-group group)
+  (gnus-summary-read-group group 1 t)
+  (gnus-summary-refer-article mid)
+  (gnus-summary-limit-to-headers (format "message-id: %s" mid))
+  (gnus-summary-select-article)
+  ;; Force redisplay
+  (gnus-summary-show-article)
+  (nnheader-message 5 "Switched to group %s." group))
+
+(defun nnmairix-map-range (func range)
+  "Map function FUNC on all members of RANGE."
+  (cond
+   ((numberp range)
+    (funcall func range))
+   (t
+    (mapcar (lambda (cur)
+             (cond
+              ((listp cur)
+               (cons
+                (funcall func (car cur))
+                (funcall func (cdr cur))))
+              ((numberp cur)
+               (funcall func cur))))
+           range))))
+
+(defun nnmairix-check-mairix-version (version &optional server)
+  "Check mairix VERSION on SERVER.
+If VERSION is a number: specifies the minimum version.
+If VERSION is a string: must be contained in mairix version output."
+  (unless server
+    (setq server nnmairix-current-server))
+  (let ((versionstring (cadr (assoc server nnmairix-version-output))))
+    (unless versionstring
+      ;; call "mairix -V" to get the version string
+      (with-temp-buffer
+       (setq versionstring
+             (let* ((commandsplit (split-string nnmairix-mairix-command))
+                    (args (append (list (car commandsplit))
+                                 `(nil t nil) (cdr commandsplit) '("-V"))))
+             (apply 'call-process args)
+             (goto-char (point-min))
+             (re-search-forward "mairix.*")
+             (match-string 0))))
+      ;; save version string for current session
+      (setq nnmairix-version-output
+           (append nnmairix-version-output
+                   (list (list server versionstring)))))
+    (cond
+     ((stringp version)
+      (string-match version versionstring))
+     ((numberp version)
+      (<= version (string-to-number
+                  (progn
+                    (string-match "mairix \\([0-9\\.]+\\)" versionstring)
+                    (match-string 1 versionstring))))))))
+
+;; ==== Widget stuff
+
+(defvar nnmairix-widgets)
+(defvar nnmairix-widgets-values nil)
+
+(defun nnmairix-widget-search-from-this-article ()
+  "Create mairix query based on current article using graphical widgets."
+  (interactive)
+  (nnmairix-widget-search
+   (nnmairix-widget-get-values)))
+
+(defun nnmairix-widget-get-values ()
+  "Create values for editable fields from current article."
+  (if (not (gnus-buffer-live-p gnus-article-buffer))
+      (error "No article buffer available")
+    (save-excursion
+      (gnus-summary-toggle-header 1)
+      (set-buffer gnus-article-buffer)
+      (mapcar
+       (function
+       (lambda (field)
+         (list (car (cddr field))
+               (if (car field)
+                   (nnmairix-replace-illegal-chars
+                    (gnus-fetch-field (car field)))
+                 nil))))
+       nnmairix-widget-fields-list))))
+
+
+(defun nnmairix-widget-search (&optional mvalues)
+  "Create mairix query interactively using graphical widgets.
+MVALUES may contain values from current article."
+  (interactive)
+  ;; Select window for mairix customization
+  (funcall nnmairix-widget-select-window-function)
+  ;; generate widgets
+  (nnmairix-widget-create-query mvalues)
+  ;; generate Buttons
+  (widget-create 'push-button
+                :notify
+                (if mvalues
+                    (lambda (&rest ignore)
+                      (nnmairix-widget-send-query nnmairix-widgets
+                                                  t))
+                  (lambda (&rest ignore)
+                    (nnmairix-widget-send-query nnmairix-widgets
+                                                nil)))
+                "Send Query")
+  (widget-insert "   ")
+  (widget-create 'push-button
+                :notify
+                (if mvalues
+                    (lambda (&rest ignore)
+                      (nnmairix-widget-create-group nnmairix-widgets
+                                                    t))
+                  (lambda (&rest ignore)
+                    (nnmairix-widget-create-group nnmairix-widgets
+                                                  nil)))
+                "Create permanent group")
+  (widget-insert "   ")
+  (widget-create 'push-button
+                :notify (lambda (&rest ignore)
+                          (kill-buffer nnmairix-customize-query-buffer))
+                "Cancel")
+  (use-local-map widget-keymap)
+  (widget-setup)
+  (goto-char (point-min)))
+
+(defun nnmairix-widget-send-query (widgets &optional withvalues)
+  "Send query from WIDGETS to mairix binary.
+If WITHVALUES is t, query is based on current article."
+  (nnmairix-search
+   (nnmairix-widget-make-query-from-widgets widgets)
+   (if withvalues
+       (gnus-method-to-server
+       (nnmairix-backend-to-server gnus-current-select-method))
+     (car (nnmairix-get-server)))
+   (if (widget-value (cadr (assoc "Threads" widgets)))
+       t
+     -1))
+  (kill-buffer nnmairix-customize-query-buffer))
+
+(defun nnmairix-widget-create-group (widgets &optional withvalues)
+  "Create nnmairix group based on current widget values WIDGETS.
+If WITHVALUES is t, query is based on current article."
+  (let ((group (read-string "Name of the group: ")))
+    (when (not (zerop (length group)))
+      (nnmairix-create-search-group
+       (if withvalues
+          (gnus-method-to-server
+           (nnmairix-backend-to-server gnus-current-select-method))
+        (car (nnmairix-get-server)))
+       group
+       (nnmairix-widget-make-query-from-widgets widgets)
+       (widget-value (cadr (assoc "Threads" widgets))))))
+  (kill-buffer nnmairix-customize-query-buffer))
+
+
+(defun nnmairix-widget-make-query-from-widgets (widgets)
+  "Create mairix query from widget values WIDGETS."
+  (let (query temp flag)
+    ;; first we do the editable fields
+    (dolist (cur nnmairix-widget-fields-list)
+      ;; See if checkbox is checked
+      (when (widget-value
+            (cadr (assoc (concat "c" (car (cddr cur))) widgets)))
+       ;; create query for the field
+       (push
+        (concat
+         (nth 1 cur)
+         ":"
+         (nnmairix-replace-illegal-chars
+          (widget-value
+          (cadr (assoc (concat "e" (car (cddr cur))) widgets)))))
+        query)))
+    ;; Flags
+    (when (member 'flags nnmairix-widget-other)
+      (setq flag
+           (mapconcat
+            (function
+             (lambda (flag)
+               (setq temp
+                     (widget-value (cadr (assoc (car flag) nnmairix-widgets))))
+               (if (string= "yes" temp)
+                   (cadr flag)
+                 (if (string= "no" temp)
+                     (concat "-" (cadr flag))))))
+            '(("seen" "s") ("replied" "r") ("flagged" "f")) ""))
+      (when (not (zerop (length flag)))
+       (push (concat "F:" flag) query)))
+    ;; return query string
+    (mapconcat 'identity query " ")))
+
+
+(defun nnmairix-widget-create-query (&optional values)
+  "Create widgets for creating mairix queries.
+Fill in VALUES if based on an article."
+  (let (allwidgets)
+    (when (get-buffer nnmairix-customize-query-buffer)
+      (kill-buffer nnmairix-customize-query-buffer))
+    (switch-to-buffer nnmairix-customize-query-buffer)
+    (kill-all-local-variables)
+    (erase-buffer)
+    (widget-insert "Specify your query for Mairix (check boxes for activating fields):\n\n")
+    (widget-insert
+     (substitute-command-keys
+      "(Whitespaces will be converted to `,' (i.e. AND). Use `/' for OR.)\n\n"))
+;    (make-local-variable 'nnmairix-widgets)
+    (setq nnmairix-widgets (nnmairix-widget-build-editable-fields values))
+    (when (member 'flags nnmairix-widget-other)
+      (widget-insert "\nFlags:\n      Seen:     ")
+      (nnmairix-widget-add "seen"
+                          'menu-choice
+                          :value "ignore"
+                          '(item "yes") '(item "no") '(item "ignore"))
+      (widget-insert "      Replied:  ")
+      (nnmairix-widget-add "replied"
+                          'menu-choice
+                          :value "ignore"
+                          '(item "yes") '(item "no") '(item "ignore"))
+      (widget-insert "      Ticked:   ")
+      (nnmairix-widget-add "flagged"
+                          'menu-choice
+                          :value "ignore"
+                          '(item "yes") '(item "no") '(item "ignore")))
+    (when (member 'threads nnmairix-widget-other)
+      (widget-insert "\n")
+      (nnmairix-widget-add "Threads" 'checkbox nil))
+      (widget-insert " Show full threads\n\n")))
+
+(defun nnmairix-widget-build-editable-fields (values)
+  "Build editable field widgets in `nnmairix-widget-fields-list'.
+VALUES may contain values for editable fields from current article."
+  ;; how can this be done less ugly?
+  (let ((ret))
+    (mapc
+     (function
+      (lambda (field)
+       (setq field (car (cddr field)))
+       (setq ret
+             (nconc
+              (list
+               (list
+                (concat "c" field)
+                (widget-create 'checkbox
+                               :tag field
+                               :notify (lambda (widget &rest ignore)
+                                         (nnmairix-widget-toggle-activate widget))
+                               nil)))
+              (list
+               (list
+                (concat "e" field)
+                (widget-create 'editable-field
+                               :size 60
+                               :format (concat " " field ":"
+                                               (make-string (- 11 (length field)) ?\ )
+                                               "%v")
+                               :value (or (cadr (assoc field values)) ""))))
+              ret))
+       (widget-insert "\n")
+       ;; Deactivate editable field
+       (widget-apply (cadr (nth 1 ret)) :deactivate)))
+     nnmairix-widget-fields-list)
+    ret))
+
+(defun nnmairix-widget-add (name &rest args)
+  "Add a widget NAME with optional ARGS."
+  (push
+   (list name
+        (apply 'widget-create args))
+   nnmairix-widgets))
+
+(defun nnmairix-widget-toggle-activate (widget)
+  "Toggle activation status of WIDGET depending on corresponding checkbox value."
+  (let ((field (widget-get widget :tag)))
+    (if (widget-value widget)
+       (widget-apply
+        (cadr (assoc (concat "e" field) nnmairix-widgets))
+        :activate)
+      (widget-apply
+       (cadr (assoc (concat "e" field) nnmairix-widgets))
+       :deactivate)))
+  (widget-setup))
+
+(provide 'nnmairix)
+
+;;; nnmairix.el ends here
diff --git a/xemacs-packages/gnus/lisp/nnmbox.el b/xemacs-packages/gnus/lisp/nnmbox.el
new file mode 100644 (file)
index 0000000..b4b697d
--- /dev/null
@@ -0,0 +1,713 @@
+;;; nnmbox.el --- mail mbox access for Gnus
+
+;; Copyright (C) 1995-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;;     Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
+;; Keywords: news, mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; For an overview of what the interface functions do, please see the
+;; Gnus sources.
+
+;;; Code:
+
+(require 'nnheader)
+(require 'message)
+(require 'nnmail)
+(require 'nnoo)
+(require 'gnus-range)
+(eval-when-compile (require 'cl))
+
+(nnoo-declare nnmbox)
+
+(defvoo nnmbox-mbox-file (expand-file-name "~/mbox")
+  "The name of the mail box file in the user's home directory.")
+
+(defvoo nnmbox-active-file (expand-file-name "~/.mbox-active")
+  "The name of the active file for the mail box.")
+
+(defvoo nnmbox-get-new-mail t
+  "If non-nil, nnmbox will check the incoming mail file and split the mail.")
+
+(defvoo nnmbox-prepare-save-mail-hook nil
+  "Hook run narrowed to an article before saving.")
+
+\f
+
+(defconst nnmbox-version "nnmbox 1.0"
+  "nnmbox version.")
+
+(defvoo nnmbox-current-group nil
+  "Current nnmbox news group directory.")
+
+(defvar nnmbox-mbox-buffer nil)
+
+(defvoo nnmbox-status-string "")
+
+(defvoo nnmbox-group-alist nil)
+(defvoo nnmbox-active-timestamp nil)
+
+(defvoo nnmbox-file-coding-system mm-binary-coding-system)
+(defvoo nnmbox-file-coding-system-for-write nil)
+(defvoo nnmbox-active-file-coding-system mm-binary-coding-system)
+(defvoo nnmbox-active-file-coding-system-for-write nil)
+
+(defvar nnmbox-group-building-active-articles nil)
+(defvar nnmbox-group-active-articles nil)
+\f
+
+;;; Interface functions
+
+(nnoo-define-basics nnmbox)
+
+(deffoo nnmbox-retrieve-headers (sequence &optional newsgroup server fetch-old)
+  (with-current-buffer nntp-server-buffer
+    (erase-buffer)
+    (let ((number (length sequence))
+         (count 0)
+         article start stop)
+      (nnmbox-possibly-change-newsgroup newsgroup server)
+      (while sequence
+       (setq article (car sequence))
+       (set-buffer nnmbox-mbox-buffer)
+       (when (nnmbox-find-article article)
+         (setq start
+               (save-excursion
+                 (re-search-backward
+                  (concat "^" message-unix-mail-delimiter) nil t)
+                 (point)))
+         (search-forward "\n\n" nil t)
+         (setq stop (1- (point)))
+         (set-buffer nntp-server-buffer)
+         (insert (format "221 %d Article retrieved.\n" article))
+         (insert-buffer-substring nnmbox-mbox-buffer start stop)
+         (goto-char (point-max))
+         (insert ".\n"))
+       (setq sequence (cdr sequence))
+       (setq count (1+ count))
+       (and (numberp nnmail-large-newsgroup)
+            (> number nnmail-large-newsgroup)
+            (zerop (% count 20))
+            (nnheader-message 5 "nnmbox: Receiving headers... %d%%"
+                              (floor (* count 100.0) number))))
+
+      (and (numberp nnmail-large-newsgroup)
+          (> number nnmail-large-newsgroup)
+          (nnheader-message 5 "nnmbox: Receiving headers...done"))
+
+      (set-buffer nntp-server-buffer)
+      (nnheader-fold-continuation-lines)
+      'headers)))
+
+(deffoo nnmbox-open-server (server &optional defs)
+  (nnoo-change-server 'nnmbox server defs)
+  (nnmbox-create-mbox)
+  (cond
+   ((not (file-exists-p nnmbox-mbox-file))
+    (nnmbox-close-server)
+    (nnheader-report 'nnmbox "No such file: %s" nnmbox-mbox-file))
+   ((file-directory-p nnmbox-mbox-file)
+    (nnmbox-close-server)
+    (nnheader-report 'nnmbox "Not a regular file: %s" nnmbox-mbox-file))
+   (t
+    (nnheader-report 'nnmbox "Opened server %s using mbox %s" server
+                    nnmbox-mbox-file)
+    t)))
+
+(deffoo nnmbox-close-server (&optional server)
+  (when (and nnmbox-mbox-buffer
+            (buffer-name nnmbox-mbox-buffer))
+    (kill-buffer nnmbox-mbox-buffer))
+  (nnoo-close-server 'nnmbox server)
+  t)
+
+(deffoo nnmbox-server-opened (&optional server)
+  (and (nnoo-current-server-p 'nnmbox server)
+       nnmbox-mbox-buffer
+       (buffer-name nnmbox-mbox-buffer)
+       nntp-server-buffer
+       (buffer-name nntp-server-buffer)))
+
+(deffoo nnmbox-request-article (article &optional newsgroup server buffer)
+  (nnmbox-possibly-change-newsgroup newsgroup server)
+  (with-current-buffer nnmbox-mbox-buffer
+    (save-excursion
+      (when (nnmbox-find-article article)
+        (let (start stop)
+          (re-search-backward (concat "^" message-unix-mail-delimiter) nil t)
+          (setq start (point))
+          (forward-line 1)
+          (setq stop (if (re-search-forward (concat "^"
+                                                    message-unix-mail-delimiter)
+                                            nil 'move)
+                         (match-beginning 0)
+                       (point)))
+          (let ((nntp-server-buffer (or buffer nntp-server-buffer)))
+            (set-buffer nntp-server-buffer)
+            (erase-buffer)
+            (insert-buffer-substring nnmbox-mbox-buffer start stop)
+            (goto-char (point-min))
+            (while (looking-at "From ")
+              (delete-char 5)
+              (insert "X-From-Line: ")
+              (forward-line 1))
+            (if (numberp article)
+                (cons nnmbox-current-group article)
+              (nnmbox-article-group-number nil))))))))
+
+(deffoo nnmbox-request-group (group &optional server dont-check info)
+  (nnmbox-possibly-change-newsgroup nil server)
+  (let ((active (cadr (assoc group nnmbox-group-alist))))
+    (cond
+     ((or (null active)
+         (null (nnmbox-possibly-change-newsgroup group server)))
+      (nnheader-report 'nnmbox "No such group: %s" group))
+     (dont-check
+      (nnheader-report 'nnmbox "Selected group %s" group)
+      (nnheader-insert ""))
+     (t
+      (nnheader-report 'nnmbox "Selected group %s" group)
+      (nnheader-insert "211 %d %d %d %s\n"
+                      (1+ (- (cdr active) (car active)))
+                      (car active) (cdr active) group)))))
+
+(defun nnmbox-save-buffer ()
+  (let ((coding-system-for-write
+        (or nnmbox-file-coding-system-for-write
+            nnmbox-file-coding-system)))
+    (save-buffer)))
+
+(defun nnmbox-save-active (group-alist active-file)
+  (let ((nnmail-active-file-coding-system
+        (or nnmbox-active-file-coding-system-for-write
+            nnmbox-active-file-coding-system)))
+    (nnmail-save-active group-alist active-file)))
+
+(deffoo nnmbox-request-scan (&optional group server)
+  (nnmbox-possibly-change-newsgroup group server)
+  (nnmbox-read-mbox)
+  (nnmail-get-new-mail
+   'nnmbox
+   (lambda ()
+     (with-current-buffer nnmbox-mbox-buffer
+       (nnmbox-save-buffer)))
+   (file-name-directory nnmbox-mbox-file)
+   group
+   (lambda ()
+     (save-excursion
+       (let ((in-buf (current-buffer)))
+        (set-buffer nnmbox-mbox-buffer)
+        (goto-char (point-max))
+        (insert-buffer-substring in-buf)))
+     (nnmbox-save-active nnmbox-group-alist nnmbox-active-file))))
+
+(deffoo nnmbox-close-group (group &optional server)
+  t)
+
+(deffoo nnmbox-request-create-group (group &optional server args)
+  (nnmail-activate 'nnmbox)
+  (unless (assoc group nnmbox-group-alist)
+    (push (list group (cons 1 0))
+         nnmbox-group-alist)
+    (nnmbox-save-active nnmbox-group-alist nnmbox-active-file))
+  t)
+
+(deffoo nnmbox-request-list (&optional server)
+  (save-excursion
+    (let ((nnmail-file-coding-system
+          nnmbox-active-file-coding-system))
+      (nnmail-find-file nnmbox-active-file))
+    (setq nnmbox-group-alist (nnmail-get-active))
+    t))
+
+(deffoo nnmbox-request-newgroups (date &optional server)
+  (nnmbox-request-list server))
+
+(deffoo nnmbox-request-list-newsgroups (&optional server)
+  (nnheader-report 'nnmbox "LIST NEWSGROUPS is not implemented."))
+
+(deffoo nnmbox-request-expire-articles
+    (articles newsgroup &optional server force)
+  (nnmbox-possibly-change-newsgroup newsgroup server)
+  (let* ((is-old t)
+        rest)
+    (nnmail-activate 'nnmbox)
+
+    (with-current-buffer nnmbox-mbox-buffer
+      (while (and articles is-old)
+       (when (nnmbox-find-article (car articles))
+         (if (setq is-old
+                   (nnmail-expired-article-p
+                    newsgroup
+                    (buffer-substring (point) (line-end-position))
+                    force))
+             (progn
+               (unless (eq nnmail-expiry-target 'delete)
+                 (with-temp-buffer
+                   (nnmbox-request-article (car articles)
+                                           newsgroup server
+                                           (current-buffer))
+                   (let ((nnml-current-directory nil))
+                     (nnmail-expiry-target-group
+                      nnmail-expiry-target newsgroup)))
+                 (nnmbox-possibly-change-newsgroup newsgroup server))
+               (nnheader-message 5 "Deleting article %d in %s..."
+                                 (car articles) newsgroup)
+               (nnmbox-delete-mail))
+           (push (car articles) rest)))
+       (setq articles (cdr articles)))
+      (nnmbox-save-buffer)
+      ;; Find the lowest active article in this group.
+      (let ((active (nth 1 (assoc newsgroup nnmbox-group-alist))))
+       (while (and (not (nnmbox-find-article (car active)))
+                   (<= (car active) (cdr active)))
+         (setcar active (1+ (car active)))))
+      (nnmbox-save-active nnmbox-group-alist nnmbox-active-file)
+      (nconc rest articles))))
+
+(deffoo nnmbox-request-move-article
+    (article group server accept-form &optional last move-is-internal)
+  (let ((buf (get-buffer-create " *nnmbox move*"))
+       result)
+    (and
+     (nnmbox-request-article article group server)
+     (with-current-buffer buf
+       (erase-buffer)
+       (insert-buffer-substring nntp-server-buffer)
+       (goto-char (point-min))
+       (while (re-search-forward
+              "^X-Gnus-Newsgroup:"
+              (save-excursion (search-forward "\n\n" nil t) (point)) t)
+        (gnus-delete-line))
+       (setq result (eval accept-form))
+       (kill-buffer buf)
+       result)
+     (save-excursion
+       (nnmbox-possibly-change-newsgroup group server)
+       (set-buffer nnmbox-mbox-buffer)
+       (when (nnmbox-find-article article)
+        (nnmbox-delete-mail))
+       (and last (nnmbox-save-buffer))))
+    result))
+
+(deffoo nnmbox-request-accept-article (group &optional server last)
+  (nnmbox-possibly-change-newsgroup group server)
+  (nnmail-check-syntax)
+  (let ((buf (current-buffer))
+       result cont)
+    (and
+     (nnmail-activate 'nnmbox)
+     (with-temp-buffer
+       (insert-buffer-substring buf)
+       (goto-char (point-min))
+       (cond (;; The From line may have been quoted by movemail.
+             (looking-at (concat ">" message-unix-mail-delimiter))
+             (delete-char 1)
+             (forward-line 1))
+            ((looking-at "X-From-Line: ")
+             (replace-match "From ")
+             (forward-line 1))
+            (t
+             (insert "From nobody " (current-time-string) "\n")))
+       (narrow-to-region (point)
+                        (if (search-forward "\n\n" nil 'move)
+                            (1- (point))
+                          (point)))
+       (while (re-search-backward "^X-Gnus-Newsgroup: " nil t)
+        (delete-region (point) (progn (forward-line 1) (point))))
+       (when nnmail-cache-accepted-message-ids
+        (nnmail-cache-insert (message-fetch-field "message-id")
+                             group
+                             (message-fetch-field "subject")
+                             (message-fetch-field "from")))
+       (widen)
+       (setq result (if (stringp group)
+                       (list (cons group (nnmbox-active-number group)))
+                     (nnmail-article-group 'nnmbox-active-number)))
+       (prog1
+          (if (and (null result)
+                   (yes-or-no-p "Moved to `junk' group; delete article? "))
+              (setq result 'junk)
+            (setq result (car (nnmbox-save-mail result))))
+        (setq cont (buffer-string))))
+     (with-current-buffer nnmbox-mbox-buffer
+       (goto-char (point-max))
+       (insert cont)
+       (when last
+        (when nnmail-cache-accepted-message-ids
+          (nnmail-cache-close))
+        (nnmbox-save-active nnmbox-group-alist nnmbox-active-file)
+        (nnmbox-save-buffer))))
+    result))
+
+(deffoo nnmbox-request-replace-article (article group buffer)
+  (nnmbox-possibly-change-newsgroup group)
+  (with-current-buffer nnmbox-mbox-buffer
+    (if (not (nnmbox-find-article article))
+       nil
+      (nnmbox-delete-mail t t)
+      (insert
+       (with-temp-buffer
+        (insert-buffer-substring buffer)
+        (goto-char (point-min))
+        (when (looking-at "X-From-Line:")
+          (delete-region (point) (progn (forward-line 1) (point))))
+        (while (re-search-forward (concat "^" message-unix-mail-delimiter)
+                                  nil t)
+          (goto-char (match-beginning 0))
+          (insert ">"))
+        (goto-char (point-max))
+        (unless (bolp)
+          (insert "\n"))
+        (buffer-string)))
+      (nnmbox-save-buffer)
+      t)))
+
+(deffoo nnmbox-request-delete-group (group &optional force server)
+  (nnmbox-possibly-change-newsgroup group server)
+  ;; Delete all articles in GROUP.
+  (if (not force)
+      ()                               ; Don't delete the articles.
+    (with-current-buffer nnmbox-mbox-buffer
+      (goto-char (point-min))
+      ;; Delete all articles in this group.
+      (let ((ident (concat "\nX-Gnus-Newsgroup: " nnmbox-current-group ":"))
+           found)
+       (while (search-forward ident nil t)
+         (setq found t)
+         (nnmbox-delete-mail))
+       (when found
+         (nnmbox-save-buffer)))))
+  ;; Remove the group from all structures.
+  (setq nnmbox-group-alist
+       (delq (assoc group nnmbox-group-alist) nnmbox-group-alist)
+       nnmbox-current-group nil)
+  ;; Save the active file.
+  (nnmbox-save-active nnmbox-group-alist nnmbox-active-file)
+  t)
+
+(deffoo nnmbox-request-rename-group (group new-name &optional server)
+  (nnmbox-possibly-change-newsgroup group server)
+  (with-current-buffer nnmbox-mbox-buffer
+    (goto-char (point-min))
+    (let ((ident (concat "\nX-Gnus-Newsgroup: " nnmbox-current-group ":"))
+         (new-ident (concat "\nX-Gnus-Newsgroup: " new-name ":"))
+         found)
+      (while (search-forward ident nil t)
+       (replace-match new-ident t t)
+       (setq found t))
+      (when found
+       (nnmbox-save-buffer))))
+  (let ((entry (assoc group nnmbox-group-active-articles)))
+    (when entry
+      (setcar entry new-name)))
+  (let ((entry (assoc group nnmbox-group-alist)))
+    (when entry
+      (setcar entry new-name))
+    (setq nnmbox-current-group nil)
+    ;; Save the new group alist.
+    (nnmbox-save-active nnmbox-group-alist nnmbox-active-file)
+    t))
+
+\f
+;;; Internal functions.
+
+;; If FORCE, delete article no matter how many X-Gnus-Newsgroup
+;; headers there are.  If LEAVE-DELIM, don't delete the Unix mbox
+;; delimiter line.
+(defun nnmbox-delete-mail (&optional force leave-delim)
+  ;; Delete the current X-Gnus-Newsgroup line.
+  ;; First delete record of active article, unless the article is being
+  ;; replaced, indicated by FORCE being non-nil.
+  (if (not force)
+      (nnmbox-record-deleted-article (nnmbox-article-group-number t)))
+  (or force
+      (gnus-delete-line))
+  ;; Beginning of the article.
+  (save-excursion
+    (save-restriction
+      (narrow-to-region
+       (prog2
+          (re-search-backward (concat "^" message-unix-mail-delimiter) nil t)
+          (if leave-delim (progn (forward-line 1) (point))
+            (match-beginning 0))
+        (forward-line 1))
+       (or (and (re-search-forward (concat "^" message-unix-mail-delimiter)
+                                  nil t)
+               (match-beginning 0))
+          (point-max)))
+      (goto-char (point-min))
+      ;; Only delete the article if no other group owns it as well.
+      (when (or force
+               (not (re-search-forward "^X-Gnus-Newsgroup: " nil t))
+               (search-backward "\n\n" nil t))
+       (delete-region (point-min) (point-max))))))
+
+(defun nnmbox-possibly-change-newsgroup (newsgroup &optional server)
+  (when (and server
+            (not (nnmbox-server-opened server)))
+    (nnmbox-open-server server))
+  (when (or (not nnmbox-mbox-buffer)
+           (not (buffer-name nnmbox-mbox-buffer)))
+    (nnmbox-read-mbox))
+  (when (not nnmbox-group-alist)
+    (nnmail-activate 'nnmbox))
+  (if newsgroup
+      (when (assoc newsgroup nnmbox-group-alist)
+       (setq nnmbox-current-group newsgroup))
+    t))
+
+(defun nnmbox-article-string (article)
+  (if (numberp article)
+      (concat "\nX-Gnus-Newsgroup: " nnmbox-current-group ":"
+             (int-to-string article) " ")
+    (concat "\nMessage-ID: " article)))
+
+(defun nnmbox-article-group-number (this-line)
+  (save-excursion
+    (if this-line
+       (beginning-of-line)
+      (goto-char (point-min)))
+    (when (re-search-forward "^X-Gnus-Newsgroup: +\\([^:]+\\):\\([0-9]+\\) "
+                            nil t)
+      (cons (buffer-substring (match-beginning 1) (match-end 1))
+           (string-to-number
+            (buffer-substring (match-beginning 2) (match-end 2)))))))
+
+(defun nnmbox-in-header-p (pos)
+  "Return non-nil if POS is in the header of an article."
+  (save-excursion
+    (goto-char pos)
+    (re-search-backward (concat "^" message-unix-mail-delimiter) nil t)
+    (search-forward "\n\n" nil t)
+    (< pos (point))))
+
+(defun nnmbox-find-article (article)
+  "Leaves point on the relevant X-Gnus-Newsgroup line if found."
+  ;; Check that article is in the active range first, to avoid an
+  ;; expensive exhaustive search if it isn't.
+  (if (and (numberp article)
+          (not (nnmbox-is-article-active-p article)))
+      nil
+    (let ((art-string (nnmbox-article-string article))
+         (found nil))
+      ;; There is the possibility that the X-Gnus-Newsgroup line appears
+      ;; in the body of an article (for instance, if an article has been
+      ;; forwarded from someone using Gnus as their mailer), so check
+      ;; that the line is actually part of the article header.
+      (or (and (search-forward art-string nil t)
+              (nnmbox-in-header-p (point)))
+         (progn
+           (goto-char (point-min))
+           (while (and (not found)
+                       (search-forward art-string nil t))
+             (setq found (nnmbox-in-header-p (point))))
+           found)))))
+
+(defun nnmbox-record-active-article (group-art)
+  (let* ((group (car group-art))
+        (article (cdr group-art))
+        (entry
+         (or (assoc group nnmbox-group-active-articles)
+             (progn
+               (push (list group)
+                     nnmbox-group-active-articles)
+               (car nnmbox-group-active-articles)))))
+    ;; add article to index, either by building complete list
+    ;; in reverse order, or as a list of ranges.
+    (if (not nnmbox-group-building-active-articles)
+       (setcdr entry (gnus-add-to-range (cdr entry) (list article)))
+      (when (memq article (cdr entry))
+       (switch-to-buffer nnmbox-mbox-buffer)
+       (error "Article %s:%d already exists!" group article))
+      (when (and (cadr entry) (< article (cadr entry)))
+       (switch-to-buffer nnmbox-mbox-buffer)
+       (error "Article %s:%d out of order" group article))
+      (setcdr entry (cons article (cdr entry))))))
+
+(defun nnmbox-record-deleted-article (group-art)
+  (let* ((group (car group-art))
+        (article (cdr group-art))
+        (entry
+         (or (assoc group nnmbox-group-active-articles)
+             (progn
+               (push (list group)
+                     nnmbox-group-active-articles)
+               (car nnmbox-group-active-articles)))))
+    ;; remove article from index
+    (setcdr entry (gnus-remove-from-range (cdr entry) (list article)))))
+
+(defun nnmbox-is-article-active-p (article)
+  (gnus-member-of-range
+   article
+   (cdr (assoc nnmbox-current-group
+              nnmbox-group-active-articles))))
+
+(defun nnmbox-save-mail (group-art)
+  "Called narrowed to an article."
+  (let ((delim (concat "^" message-unix-mail-delimiter)))
+    (goto-char (point-min))
+    ;; This might come from somewhere else.
+    (if (looking-at delim)
+       (forward-line 1)
+      (insert "From nobody " (current-time-string) "\n"))
+    ;; Quote all "From " lines in the article.
+    (while (re-search-forward delim nil t)
+      (goto-char (match-beginning 0))
+      (insert ">")))
+  (goto-char (point-max))
+  (unless (bolp)
+    (insert "\n"))
+  (nnmail-insert-lines)
+  (nnmail-insert-xref group-art)
+  (nnmbox-insert-newsgroup-line group-art)
+  (let ((alist group-art))
+    (while alist
+      (nnmbox-record-active-article (car alist))
+      (setq alist (cdr alist))))
+  (run-hooks 'nnmail-prepare-save-mail-hook)
+  (run-hooks 'nnmbox-prepare-save-mail-hook)
+  group-art)
+
+(defun nnmbox-insert-newsgroup-line (group-art)
+  (save-excursion
+    (goto-char (point-min))
+    (when (search-forward "\n\n" nil t)
+      (forward-char -1)
+      (while group-art
+       (insert (format "X-Gnus-Newsgroup: %s:%d   %s\n"
+                       (caar group-art) (cdar group-art)
+                       (current-time-string)))
+       (setq group-art (cdr group-art))))
+    t))
+
+(defun nnmbox-active-number (group)
+  ;; Find the next article number in GROUP.
+  (let ((active (cadr (assoc group nnmbox-group-alist))))
+    (if active
+       (setcdr active (1+ (cdr active)))
+      ;; This group is new, so we create a new entry for it.
+      ;; This might be a bit naughty... creating groups on the drop of
+      ;; a hat, but I don't know...
+      (push (list group (setq active (cons 1 1)))
+           nnmbox-group-alist))
+    (cdr active)))
+
+(defun nnmbox-create-mbox ()
+  (when (not (file-exists-p nnmbox-mbox-file))
+    (let ((nnmail-file-coding-system
+          (or nnmbox-file-coding-system-for-write
+              nnmbox-file-coding-system))
+         (dir (file-name-directory nnmbox-mbox-file)))
+      (and dir (gnus-make-directory dir))
+      (nnmail-write-region (point-min) (point-min)
+                          nnmbox-mbox-file t 'nomesg))))
+
+(defun nnmbox-read-mbox ()
+  (nnmail-activate 'nnmbox)
+  (nnmbox-create-mbox)
+  (if (and nnmbox-mbox-buffer
+          (buffer-name nnmbox-mbox-buffer)
+          (with-current-buffer nnmbox-mbox-buffer
+            (= (buffer-size) (nnheader-file-size nnmbox-mbox-file))))
+      ()
+    (save-excursion
+      (let ((delim (concat "^" message-unix-mail-delimiter))
+           (alist nnmbox-group-alist)
+           (nnmbox-group-building-active-articles t)
+           start end end-header number)
+       (set-buffer (setq nnmbox-mbox-buffer
+                         (let ((nnheader-file-coding-system
+                                nnmbox-file-coding-system))
+                           (nnheader-find-file-noselect
+                            nnmbox-mbox-file t t))))
+       (mm-enable-multibyte)
+       (buffer-disable-undo)
+       (gnus-add-buffer)
+
+       ;; Go through the group alist and compare against the mbox file.
+       (while alist
+         (goto-char (point-max))
+         (when (and (re-search-backward
+                     (format "^X-Gnus-Newsgroup: %s:\\([0-9]+\\) "
+                             (caar alist)) nil t)
+                    (> (setq number
+                             (string-to-number
+                              (buffer-substring
+                               (match-beginning 1) (match-end 1))))
+                       (cdadar alist)))
+           (setcdr (cadar alist) number))
+         (setq alist (cdr alist)))
+
+       ;; Examine all articles for our private X-Gnus-Newsgroup
+       ;; headers.  This is done primarily as a consistency check, but
+       ;; it is convenient for building an index of the articles
+       ;; present, to avoid costly searches for missing articles
+       ;; (eg. when expiring articles).
+       (goto-char (point-min))
+       (setq nnmbox-group-active-articles nil)
+       (while (re-search-forward delim nil t)
+         (setq start (match-beginning 0))
+         (save-excursion
+           (search-forward "\n\n" nil t)
+           (setq end-header (point))
+           (setq end (or (and
+                          (re-search-forward delim nil t)
+                          (match-beginning 0))
+                         (point-max))))
+         (if (search-forward "\nX-Gnus-Newsgroup: " end-header t)
+             ;; Build a list of articles in each group, remembering
+             ;; that each article may be in more than one group.
+             (progn
+               (nnmbox-record-active-article (nnmbox-article-group-number t))
+               (while (search-forward "\nX-Gnus-Newsgroup: " end-header t)
+                 (nnmbox-record-active-article (nnmbox-article-group-number t))))
+           ;; The article is either new, or for some other reason
+           ;; hasn't got our private headers, so add them now.  The
+           ;; only situation I've encountered when the X-Gnus-Newsgroup
+           ;; header is missing is if the article contains a forwarded
+           ;; message which does contain that header line (earlier
+           ;; versions of Gnus didn't restrict their search to the
+           ;; headers).  In this case, there is an Xref line which
+           ;; provides the relevant information to construct the
+           ;; missing header(s).
+           (save-excursion
+             (save-restriction
+               (narrow-to-region start end)
+               (if (re-search-forward "\nXref: [^ ]+" end-header t)
+                   ;; generate headers from Xref:
+                   (let (alist)
+                     (while (re-search-forward " \\([^:]+\\):\\([0-9]+\\)" end-header t)
+                       (push (cons (match-string 1)
+                                   (string-to-number (match-string 2))) alist))
+                     (nnmbox-insert-newsgroup-line alist))
+                 ;; this is really a new article
+                 (nnmbox-save-mail
+                  (nnmail-article-group 'nnmbox-active-number))))))
+         (goto-char end))
+       ;; put article lists in order
+       (setq alist nnmbox-group-active-articles)
+       (while alist
+         (setcdr (car alist) (gnus-compress-sequence (nreverse (cdar alist))))
+         (setq alist (cdr alist)))))))
+
+(provide 'nnmbox)
+
+;;; nnmbox.el ends here
diff --git a/xemacs-packages/gnus/lisp/nnmh.el b/xemacs-packages/gnus/lisp/nnmh.el
new file mode 100644 (file)
index 0000000..c60e845
--- /dev/null
@@ -0,0 +1,583 @@
+;;; nnmh.el --- mhspool access for Gnus
+
+;; Copyright (C) 1995-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;;     Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
+;; Keywords: news, mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Based on nnspool.el by Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>.
+;; For an overview of what the interface functions do, please see the
+;; Gnus sources.
+
+;;; Code:
+
+(require 'nnheader)
+(require 'nnmail)
+(require 'gnus-start)
+(require 'nnoo)
+(eval-when-compile (require 'cl))
+
+(nnoo-declare nnmh)
+
+(defvoo nnmh-directory message-directory
+  "Mail spool directory.")
+
+(defvoo nnmh-get-new-mail t
+  "If non-nil, nnmh will check the incoming mail file and split the mail.")
+
+(defvoo nnmh-prepare-save-mail-hook nil
+  "Hook run narrowed to an article before saving.")
+
+(defvoo nnmh-be-safe nil
+  "If non-nil, nnmh will check all articles to make sure whether they are new or not.
+Go through the .nnmh-articles file and compare with the actual
+articles in this folder.  The articles that are \"new\" will be marked
+as unread by Gnus.")
+
+\f
+
+(defconst nnmh-version "nnmh 1.0"
+  "nnmh version.")
+
+(defvoo nnmh-current-directory nil
+  "Current news group directory.")
+
+(defvoo nnmh-status-string "")
+(defvoo nnmh-group-alist nil)
+;; Don't even think about setting this variable.  It does not exist.
+;; Forget about it.  Uh-huh.  Nope.  Nobody here.  It's only bound
+;; dynamically by certain functions in nndraft.
+(defvar nnmh-allow-delete-final nil)
+
+\f
+
+;;; Interface functions.
+
+(nnoo-define-basics nnmh)
+
+(deffoo nnmh-retrieve-headers (articles &optional newsgroup server fetch-old)
+  (with-current-buffer nntp-server-buffer
+    (erase-buffer)
+    (let* ((file nil)
+          (number (length articles))
+          (large (and (numberp nnmail-large-newsgroup)
+                      (> number nnmail-large-newsgroup)))
+          (count 0)
+          (file-name-coding-system nnmail-pathname-coding-system)
+          beg article)
+      (nnmh-possibly-change-directory newsgroup server)
+      ;; We don't support fetching by Message-ID.
+      (if (stringp (car articles))
+         'headers
+       (while articles
+         (when (and (file-exists-p
+                     (setq file (concat (file-name-as-directory
+                                         nnmh-current-directory)
+                                        (int-to-string
+                                         (setq article (pop articles))))))
+                    (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 count (1+ count))
+
+         (and large
+              (zerop (% count 20))
+              (nnheader-message 5 "nnmh: Receiving headers... %d%%"
+                                (floor (* count 100.0) number))))
+
+       (when large
+         (nnheader-message 5 "nnmh: Receiving headers...done"))
+
+       (nnheader-fold-continuation-lines)
+       'headers))))
+
+(deffoo nnmh-open-server (server &optional defs)
+  (nnoo-change-server 'nnmh server defs)
+  (when (not (file-exists-p nnmh-directory))
+    (condition-case ()
+       (make-directory nnmh-directory t)
+      (error t)))
+  (cond
+   ((not (file-exists-p nnmh-directory))
+    (nnmh-close-server)
+    (nnheader-report 'nnmh "Couldn't create directory: %s" nnmh-directory))
+   ((not (file-directory-p (file-truename nnmh-directory)))
+    (nnmh-close-server)
+    (nnheader-report 'nnmh "Not a directory: %s" nnmh-directory))
+   (t
+    (nnheader-report 'nnmh "Opened server %s using directory %s"
+                    server nnmh-directory)
+    t)))
+
+(deffoo nnmh-request-article (id &optional newsgroup server buffer)
+  (nnmh-possibly-change-directory newsgroup server)
+  (let ((file (if (stringp id)
+                 nil
+               (concat nnmh-current-directory (int-to-string id))))
+       (file-name-coding-system nnmail-pathname-coding-system)
+       (nntp-server-buffer (or buffer nntp-server-buffer)))
+    (and (stringp file)
+        (file-exists-p file)
+        (not (file-directory-p file))
+        (save-excursion (nnmail-find-file file))
+        (string-to-number (file-name-nondirectory file)))))
+
+(deffoo nnmh-request-group (group &optional server dont-check info)
+  (nnheader-init-server-buffer)
+  (nnmh-possibly-change-directory group server)
+  (let ((pathname (nnmail-group-pathname group nnmh-directory))
+       (file-name-coding-system nnmail-pathname-coding-system)
+       dir)
+    (cond
+     ((not (file-directory-p pathname))
+      (nnheader-report
+       'nnmh "Can't select group (no such directory): %s" group))
+     (t
+      (setq nnmh-current-directory pathname)
+      (and nnmh-get-new-mail
+          nnmh-be-safe
+          (nnmh-update-gnus-unreads group))
+      (cond
+       (dont-check
+       (nnheader-report 'nnmh "Selected group %s" group)
+       t)
+       (t
+       ;; Re-scan the directory if it's on a foreign system.
+       (nnheader-re-read-dir pathname)
+       (setq dir
+             (sort
+              (mapcar 'string-to-number
+                      (directory-files pathname nil "^[0-9]+$" t))
+              '<))
+       (cond
+        (dir
+         (setq nnmh-group-alist
+               (delq (assoc group nnmh-group-alist) nnmh-group-alist))
+         (push (list group (cons (car dir) (car (last dir))))
+               nnmh-group-alist)
+         (nnheader-report 'nnmh "Selected group %s" group)
+         (nnheader-insert
+          "211 %d %d %d %s\n" (length dir) (car dir)
+          (car (last dir)) group))
+        (t
+         (nnheader-report 'nnmh "Empty group %s" group)
+         (nnheader-insert (format "211 0 1 0 %s\n" group))))))))))
+
+(deffoo nnmh-request-scan (&optional group server)
+  (nnmail-get-new-mail 'nnmh nil nnmh-directory group))
+
+(deffoo nnmh-request-list (&optional server dir)
+  (nnheader-insert "")
+  (nnmh-possibly-change-directory nil server)
+  (let ((file-name-coding-system nnmail-pathname-coding-system)
+       (nnmh-toplev
+        (file-truename (or dir (file-name-as-directory nnmh-directory)))))
+    (nnmh-request-list-1 nnmh-toplev))
+  (setq nnmh-group-alist (nnmail-get-active))
+  t)
+
+(defvar nnmh-toplev)
+(defun nnmh-request-list-1 (dir)
+  (setq dir (expand-file-name dir))
+  ;; Recurse down all directories.
+  (let ((files (nnheader-directory-files dir t nil t))
+       (max 0)
+       min rdir num subdirectoriesp file)
+    ;; Recurse down directories.
+    (setq subdirectoriesp
+         ;; nth 1 of file-attributes always 1 on MS Windows :(
+         (/= (nth 1 (file-attributes (file-truename dir))) 2))
+    (dolist (rdir files)
+      (if (or (not subdirectoriesp)
+             (file-regular-p rdir))
+         (progn
+           (setq file (file-name-nondirectory rdir))
+           (when (string-match "^[0-9]+$" file)
+             (setq num (string-to-number file))
+             (setq max (max max num))
+             (when (or (null min)
+                       (< num min))
+               (setq min num))))
+       ;; This is a directory.
+       (when (and (file-readable-p rdir)
+                  (not (equal (file-truename rdir)
+                              (file-truename dir))))
+         (nnmh-request-list-1 rdir))))
+    ;; For each directory, generate an active file line.
+    (unless (string= (expand-file-name nnmh-toplev) dir)
+      (with-current-buffer nntp-server-buffer
+       (goto-char (point-max))
+       (insert
+        (format
+         "%s %.0f %.0f y\n"
+         (progn
+           (string-match
+            (regexp-quote
+             (file-truename (file-name-as-directory
+                             (expand-file-name nnmh-toplev))))
+            dir)
+           (mm-string-to-multibyte ;Why?  Isn't it multibyte already?
+            (mm-encode-coding-string
+             (nnheader-replace-chars-in-string
+              (substring dir (match-end 0))
+              ?/ ?.)
+             nnmail-pathname-coding-system)))
+         (or max 0)
+         (or min 1))))))
+  t)
+
+(deffoo nnmh-request-newgroups (date &optional server)
+  (nnmh-request-list server))
+
+(deffoo nnmh-request-expire-articles (articles newsgroup
+                                              &optional server force)
+  (nnmh-possibly-change-directory newsgroup server)
+  (let ((is-old t)
+       (dir nnmh-current-directory)
+       article rest mod-time)
+    (nnheader-init-server-buffer)
+
+    (while (and articles is-old)
+      (setq article (concat dir (int-to-string (car articles))))
+      (when (setq mod-time (nth 5 (file-attributes article)))
+       (if (and (nnmh-deletable-article-p newsgroup (car articles))
+                (setq is-old
+                      (nnmail-expired-article-p newsgroup mod-time force)))
+           (progn
+             ;; Allow a special target group. -- jcn
+             (unless (eq nnmail-expiry-target 'delete)
+               (with-temp-buffer
+                 (nnmh-request-article (car articles)
+                                       newsgroup server (current-buffer))
+                 (nnmail-expiry-target-group
+                  nnmail-expiry-target newsgroup)))
+             (nnheader-message 5 "Deleting article %s in %s..."
+                               article newsgroup)
+             (condition-case ()
+                 (funcall nnmail-delete-file-function article)
+               (file-error
+                (nnheader-message 1 "Couldn't delete article %s in %s"
+                                  article newsgroup)
+                (push (car articles) rest))))
+         (push (car articles) rest)))
+      (setq articles (cdr articles)))
+    (nnheader-message 5 "")
+    (nconc rest articles)))
+
+(deffoo nnmh-close-group (group &optional server)
+  t)
+
+(deffoo nnmh-request-move-article (article group server accept-form
+                                          &optional last move-is-internal)
+  (let ((buf (get-buffer-create " *nnmh move*"))
+       result)
+    (and
+     (nnmh-deletable-article-p group article)
+     (nnmh-request-article article group server)
+     (with-current-buffer buf
+       (erase-buffer)
+       (insert-buffer-substring nntp-server-buffer)
+       (setq result (eval accept-form))
+       (kill-buffer (current-buffer))
+       result)
+     (progn
+       (nnmh-possibly-change-directory group server)
+       (condition-case ()
+          (funcall nnmail-delete-file-function
+                   (concat nnmh-current-directory (int-to-string article)))
+        (file-error nil))))
+    result))
+
+(deffoo nnmh-request-accept-article (group &optional server last noinsert)
+  (nnmh-possibly-change-directory group server)
+  (nnmail-check-syntax)
+  (when nnmail-cache-accepted-message-ids
+    (nnmail-cache-insert (nnmail-fetch-field "message-id")
+                        group
+                        (nnmail-fetch-field "subject")
+                        (nnmail-fetch-field "from")))
+  (nnheader-init-server-buffer)
+  (prog1
+      (if (stringp group)
+         (if noinsert
+             (nnmh-active-number group)
+           (car (nnmh-save-mail
+                 (list (cons group (nnmh-active-number group)))
+                 noinsert)))
+       (let ((res (nnmail-article-group 'nnmh-active-number)))
+         (if (and (null res)
+                  (yes-or-no-p "Moved to `junk' group; delete article? "))
+             'junk
+           (car (nnmh-save-mail res noinsert)))))
+    (when (and last nnmail-cache-accepted-message-ids)
+      (nnmail-cache-close))))
+
+(deffoo nnmh-request-replace-article (article group buffer)
+  (nnmh-possibly-change-directory group)
+  (with-current-buffer buffer
+    (nnmh-possibly-create-directory group)
+    (ignore-errors
+      (nnmail-write-region
+       (point-min) (point-max)
+       (concat nnmh-current-directory (int-to-string article))
+       nil (if (nnheader-be-verbose 5) nil 'nomesg))
+      t)))
+
+(deffoo nnmh-request-create-group (group &optional server args)
+  (nnheader-init-server-buffer)
+  (unless (assoc group nnmh-group-alist)
+    (let (active)
+      (push (list group (setq active (cons 1 0)))
+           nnmh-group-alist)
+      (nnmh-possibly-create-directory group)
+      (nnmh-possibly-change-directory group server)
+      (let ((articles (mapcar 'string-to-number
+                             (directory-files
+                              nnmh-current-directory nil "^[0-9]+$"))))
+       (when articles
+         (setcar active (apply 'min articles))
+         (setcdr active (apply 'max articles))))))
+  t)
+
+(deffoo nnmh-request-delete-group (group &optional force server)
+  (nnmh-possibly-change-directory group server)
+  ;; Delete all articles in GROUP.
+  (if (not force)
+      ()                               ; Don't delete the articles.
+    (let ((articles (directory-files nnmh-current-directory t "^[0-9]+$")))
+      (while articles
+       (when (file-writable-p (car articles))
+         (nnheader-message 5 "Deleting article %s in %s..."
+                           (car articles) group)
+         (funcall nnmail-delete-file-function (car articles)))
+       (setq articles (cdr articles))))
+    ;; Try to delete the directory itself.
+    (ignore-errors
+      (delete-directory nnmh-current-directory)))
+  ;; Remove the group from all structures.
+  (setq nnmh-group-alist
+       (delq (assoc group nnmh-group-alist) nnmh-group-alist)
+       nnmh-current-directory nil)
+  t)
+
+(deffoo nnmh-request-rename-group (group new-name &optional server)
+  (nnmh-possibly-change-directory group server)
+  (let ((new-dir (nnmail-group-pathname new-name nnmh-directory))
+       (old-dir (nnmail-group-pathname group nnmh-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)))
+      (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 nnmh-group-alist)))
+       (when entry
+         (setcar entry new-name))
+       (setq nnmh-current-directory nil)
+       t))))
+
+(nnoo-define-skeleton nnmh)
+
+\f
+;;; Internal functions.
+
+(defun nnmh-possibly-change-directory (newsgroup &optional server)
+  (when (and server
+            (not (nnmh-server-opened server)))
+    (nnmh-open-server server))
+  (when newsgroup
+    (let ((pathname (nnmail-group-pathname newsgroup nnmh-directory))
+         (file-name-coding-system nnmail-pathname-coding-system))
+      (if (file-directory-p pathname)
+         (setq nnmh-current-directory pathname)
+       (nnheader-report 'nnmh "Not a directory: %s" nnmh-directory)))))
+
+(defun nnmh-possibly-create-directory (group)
+  (let (dir dirs)
+    (setq dir (nnmail-group-pathname group nnmh-directory))
+    (while (not (file-directory-p dir))
+      (push dir dirs)
+      (setq dir (file-name-directory (directory-file-name dir))))
+    (while dirs
+      (when (make-directory (directory-file-name (car dirs)))
+       (error "Could not create directory %s" (car dirs)))
+      (nnheader-message 5 "Creating mail directory %s" (car dirs))
+      (setq dirs (cdr dirs)))))
+
+(defun nnmh-save-mail (group-art &optional noinsert)
+  "Called narrowed to an article."
+  (unless noinsert
+    (nnmail-insert-lines)
+    (nnmail-insert-xref group-art))
+  (run-hooks 'nnmail-prepare-save-mail-hook)
+  (run-hooks 'nnmh-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 newsgroups it belongs in.
+  (let ((ga group-art)
+       first)
+    (while ga
+      (nnmh-possibly-create-directory (caar ga))
+      (let ((file (concat (nnmail-group-pathname
+                          (caar ga) nnmh-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 nil)
+         (setq first file)))
+      (setq ga (cdr ga))))
+  group-art)
+
+(defun nnmh-active-number (group)
+  "Compute the next article number in GROUP."
+  (let ((active (cadr (assoc group nnmh-group-alist)))
+       (dir (nnmail-group-pathname group nnmh-directory))
+       (file-name-coding-system nnmail-pathname-coding-system)
+       file)
+    (unless active
+      ;; The group wasn't known to nnmh, so we just create an active
+      ;; entry for it.
+      (setq active (cons 1 0))
+      (push (list group active) nnmh-group-alist)
+      (unless (file-exists-p dir)
+       (gnus-make-directory dir))
+      ;; Find the highest number in the group.
+      (let ((files (sort
+                   (mapcar 'string-to-number
+                           (directory-files dir nil "^[0-9]+$"))
+                   '>)))
+       (when files
+         (setcdr active (car files)))))
+    (setcdr active (1+ (cdr active)))
+    (while (or
+           ;; See whether the file exists...
+           (file-exists-p
+            (setq file (concat (nnmail-group-pathname group nnmh-directory)
+                               (int-to-string (cdr active)))))
+           ;; ... or there is a buffer that will make that file exist
+           ;; in the future.
+           (get-file-buffer file))
+      ;; Skip past that file.
+      (setcdr active (1+ (cdr active))))
+    (cdr active)))
+
+(defun nnmh-update-gnus-unreads (group)
+  ;; Go through the .nnmh-articles file and compare with the actual
+  ;; articles in this folder.  The articles that are "new" will be
+  ;; marked as unread by Gnus.
+  (let* ((dir nnmh-current-directory)
+        (files (sort (mapcar 'string-to-number
+                             (directory-files nnmh-current-directory
+                                              nil "^[0-9]+$" t))
+                     '<))
+        (nnmh-file (concat dir ".nnmh-articles"))
+        new articles)
+    ;; Load the .nnmh-articles file.
+    (when (file-exists-p nnmh-file)
+      (setq articles
+           (let (nnmh-newsgroup-articles)
+             (ignore-errors (load nnmh-file nil t t))
+             nnmh-newsgroup-articles)))
+    ;; Add all new articles to the `new' list.
+    (let ((art files))
+      (while art
+       (unless (assq (car art) articles)
+         (push (car art) new))
+       (setq art (cdr art))))
+    ;; Remove all deleted articles.
+    (let ((art articles))
+      (while art
+       (unless (memq (caar art) files)
+         (setq articles (delq (car art) articles)))
+       (setq art (cdr art))))
+    ;; Check whether the articles really are the ones that Gnus thinks
+    ;; they are by looking at the time-stamps.
+    (let ((arts articles)
+         art)
+      (while (setq art (pop arts))
+       (when (not (equal
+                   (nth 5 (file-attributes
+                           (concat dir (int-to-string (car art)))))
+                   (cdr art)))
+         (setq articles (delq art articles))
+         (push (car art) new))))
+    ;; Go through all the new articles and add them, and their
+    ;; time-stamps, to the list.
+    (setq articles
+         (nconc articles
+                (mapcar
+                 (lambda (art)
+                   (cons art
+                         (nth 5 (file-attributes
+                                 (concat dir (int-to-string art))))))
+                 new)))
+    ;; Make Gnus mark all new articles as unread.
+    (when new
+      (gnus-make-articles-unread
+       (gnus-group-prefixed-name group (list 'nnmh ""))
+       (setq new (sort new '<))))
+    ;; Sort the article list with highest numbers first.
+    (setq articles (sort articles (lambda (art1 art2)
+                                   (> (car art1) (car art2)))))
+    ;; Finally write this list back to the .nnmh-articles file.
+    (with-temp-file nnmh-file
+      (insert ";; Gnus article active file for " group "\n\n")
+      (insert "(setq nnmh-newsgroup-articles '")
+      (gnus-prin1 articles)
+      (insert ")\n"))))
+
+(defun nnmh-deletable-article-p (group article)
+  "Say whether ARTICLE in GROUP can be deleted."
+  (let ((path (concat nnmh-current-directory (int-to-string article))))
+    ;; Writable.
+    (and (file-writable-p path)
+        (or
+         ;; We can never delete the last article in the group.
+         (not (eq (cdr (nth 1 (assoc group nnmh-group-alist)))
+                  article))
+         ;; Well, we can.
+         nnmh-allow-delete-final))))
+
+(provide 'nnmh)
+
+;;; nnmh.el ends here
diff --git a/xemacs-packages/gnus/lisp/nnml.el b/xemacs-packages/gnus/lisp/nnml.el
new file mode 100644 (file)
index 0000000..3350933
--- /dev/null
@@ -0,0 +1,1212 @@
+;;; nnml.el --- mail spool access for Gnus
+
+;; Copyright (C) 1995-2016 Free Software Foundation, Inc.
+
+;; Authors: Didier Verna <didier@xemacs.org> (adding compaction)
+;;     Simon Josefsson <simon@josefsson.org>
+;;     Lars Magne Ingebrigtsen <larsi@gnus.org>
+;;     Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
+;; Keywords: news, mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Based on nnspool.el by Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>.
+;; For an overview of what the interface functions do, please see the
+;; Gnus sources.
+
+;;; Code:
+
+(require 'gnus)
+(require 'nnheader)
+(require 'nnmail)
+(require 'nnoo)
+(eval-when-compile (require 'cl))
+
+;; FIXME first is unused in this file.
+(autoload 'gnus-article-unpropagatable-p "gnus-sum")
+(autoload 'gnus-backlog-remove-article "gnus-bcklg")
+
+(nnoo-declare nnml)
+
+(defvoo nnml-directory message-directory
+  "Spool directory for the nnml mail backend.")
+
+(defvoo nnml-active-file
+    (expand-file-name "active" nnml-directory)
+  "Mail active file.")
+
+(defvoo nnml-newsgroups-file
+    (expand-file-name "newsgroups" nnml-directory)
+  "Mail newsgroups description file.")
+
+(defvoo nnml-get-new-mail t
+  "If non-nil, nnml will check the incoming mail file and split the mail.")
+
+(defvoo nnml-nov-is-evil nil
+  "If non-nil, Gnus will never generate and use nov databases for mail spools.
+Using nov databases will speed up header fetching considerably.
+This variable shouldn't be flipped much.  If you have, for some reason,
+set this to t, and want to set it to nil again, you should always run
+the `nnml-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 nnml-prepare-save-mail-hook nil
+  "Hook run narrowed to an article before saving.")
+
+(defvoo nnml-inhibit-expiry nil
+  "If non-nil, inhibit expiry.")
+
+(defvoo nnml-use-compressed-files nil
+  "If non-nil, allow using compressed message files.
+
+If it is a string, use it as the file extension which specifies
+the compression program.  You can set it to \".bz2\" if your Emacs
+supports auto-compression using the bzip2 program.  A value of t
+is equivalent to \".gz\".")
+
+(defvoo nnml-compressed-files-size-threshold 1000
+  "Default size threshold for compressed message files.
+Message files with bodies larger than that many characters will
+be automatically compressed if `nnml-use-compressed-files' is
+non-nil.")
+
+\f
+
+(defconst nnml-version "nnml 1.0"
+  "nnml version.")
+
+(defvoo nnml-nov-file-name ".overview")
+
+(defvoo nnml-current-directory nil)
+(defvoo nnml-current-group nil)
+(defvoo nnml-status-string "")
+(defvoo nnml-nov-buffer-alist nil)
+(defvoo nnml-group-alist nil)
+(defvoo nnml-active-timestamp nil)
+(defvoo nnml-article-file-alist nil)
+
+(defvoo nnml-generate-active-function 'nnml-generate-active-info)
+
+(defvar nnml-nov-buffer-file-name nil)
+
+(defvoo nnml-file-coding-system nnmail-file-coding-system)
+
+\f
+;;; Interface functions.
+
+(nnoo-define-basics nnml)
+
+(eval-when-compile
+  (defsubst nnml-group-name-charset (group server-or-method)
+    (gnus-group-name-charset
+     (if (stringp server-or-method)
+        (gnus-server-to-method
+         (if (string-match "\\+" server-or-method)
+             (concat (substring server-or-method 0 (match-beginning 0))
+                     ":" (substring server-or-method (match-end 0)))
+           (concat "nnml:" server-or-method)))
+       (or server-or-method gnus-command-method '(nnml "")))
+     group)))
+
+(defun nnml-decoded-group-name (group &optional server-or-method)
+  "Return a decoded group name of GROUP on SERVER-OR-METHOD."
+  (if nnmail-group-names-not-encoded-p
+      group
+    (mm-decode-coding-string
+     group
+     (nnml-group-name-charset group server-or-method))))
+
+(defun nnml-encoded-group-name (group &optional server-or-method)
+  "Return an encoded group name of GROUP on SERVER-OR-METHOD."
+  (mm-encode-coding-string
+   group
+   (nnml-group-name-charset group server-or-method)))
+
+(defun nnml-group-pathname (group &optional file server)
+  "Return an absolute file name of FILE for GROUP on SERVER."
+  (nnmail-group-pathname (inline (nnml-decoded-group-name group server))
+                        nnml-directory file))
+
+(deffoo nnml-retrieve-headers (sequence &optional group server fetch-old)
+  (when (nnml-possibly-change-directory group server)
+    (with-current-buffer nntp-server-buffer
+      (erase-buffer)
+      (let* ((file nil)
+            (number (length sequence))
+            (count 0)
+            (file-name-coding-system nnmail-pathname-coding-system)
+            beg article)
+       (if (stringp (car sequence))
+           'headers
+         (if (nnml-retrieve-headers-with-nov sequence fetch-old)
+             'nov
+           (while sequence
+             (setq article (car sequence))
+             (setq file (nnml-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 (re-search-forward "\n\r?\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 "nnml: Receiving headers... %d%%"
+                                    (floor (* count 100.0) number))))
+
+           (and (numberp nnmail-large-newsgroup)
+                (> number nnmail-large-newsgroup)
+                (nnheader-message 6 "nnml: Receiving headers...done"))
+
+           (nnheader-fold-continuation-lines)
+           'headers))))))
+
+(deffoo nnml-open-server (server &optional defs)
+  (nnoo-change-server 'nnml server defs)
+  (when (not (file-exists-p nnml-directory))
+    (ignore-errors (make-directory nnml-directory t)))
+  (cond
+   ((not (file-exists-p nnml-directory))
+    (nnml-close-server)
+    (nnheader-report 'nnml "Couldn't create directory: %s" nnml-directory))
+   ((not (file-directory-p (file-truename nnml-directory)))
+    (nnml-close-server)
+    (nnheader-report 'nnml "Not a directory: %s" nnml-directory))
+   (t
+    (nnheader-report 'nnml "Opened server %s using directory %s"
+                    server nnml-directory)
+    t)))
+
+(deffoo nnml-request-regenerate (server)
+  (nnml-possibly-change-directory nil server)
+  (nnml-generate-nov-databases server)
+  t)
+
+(deffoo nnml-request-article (id &optional group server buffer)
+  (nnml-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 (nnml-find-group-number id server))
+                  (cdr
+                   (assq (cdr group-num)
+                         (nnheader-article-to-file-alist
+                          (setq gpath (nnml-group-pathname (car group-num)
+                                                           nil server))))))
+         (nnml-update-file-alist)
+         (setq path (concat gpath (if nnml-use-compressed-files
+                                      (cdr (assq (cdr group-num)
+                                                 nnml-article-file-alist))
+                                    (number-to-string (cdr group-num))))))
+      (setq path (nnml-article-to-file id)))
+    (cond
+     ((not path)
+      (nnheader-report 'nnml "No such article: %s" id))
+     ((not (file-exists-p path))
+      (nnheader-report 'nnml "No such file: %s" path))
+     ((file-directory-p path)
+      (nnheader-report 'nnml "File is a directory: %s" path))
+     ((not (save-excursion (let ((nnmail-file-coding-system
+                                 nnml-file-coding-system))
+                            (nnmail-find-file path))))
+      (nnheader-report 'nnml "Couldn't read file: %s" path))
+     (t
+      (nnheader-report 'nnml "Article %s retrieved" id)
+      ;; We return the article number.
+      (cons (if group-num (car group-num) group)
+           (string-to-number (file-name-nondirectory path)))))))
+
+(deffoo nnml-request-group (group &optional server dont-check info)
+  (let ((file-name-coding-system nnmail-pathname-coding-system)
+       (decoded (nnml-decoded-group-name group server)))
+    (cond
+     ((not (nnml-possibly-change-directory group server))
+      (nnheader-report 'nnml "Invalid group (no such directory)"))
+     ((not (file-exists-p nnml-current-directory))
+      (nnheader-report 'nnml "Directory %s does not exist"
+                      nnml-current-directory))
+     ((not (file-directory-p nnml-current-directory))
+      (nnheader-report 'nnml "%s is not a directory" nnml-current-directory))
+     (dont-check
+      (nnheader-report 'nnml "Group %s selected" decoded)
+      t)
+     (t
+      (nnheader-re-read-dir nnml-current-directory)
+      (nnmail-activate 'nnml)
+      (let ((active (nth 1 (assoc group nnml-group-alist))))
+       (if (not active)
+           (nnheader-report 'nnml "No such group: %s" decoded)
+         (nnheader-report 'nnml "Selected group %s" decoded)
+         (nnheader-insert "211 %d %d %d %s\n"
+                          (max (1+ (- (cdr active) (car active))) 0)
+                          (car active) (cdr active) group)))))))
+
+(deffoo nnml-request-scan (&optional group server)
+  (setq nnml-article-file-alist nil)
+  (nnml-possibly-change-directory group server)
+  (cond
+   (group
+    (nnmail-get-new-mail 'nnml 'nnml-save-incremental-nov nnml-directory group))
+   ((nnmail-get-new-mail-per-group)
+    (nnml-request-list)
+    (dolist (entry nnml-group-alist)
+      (nnml-request-scan (car entry) server)))
+   (t
+    (nnmail-get-new-mail 'nnml 'nnml-save-incremental-nov nnml-directory nil))))
+
+(deffoo nnml-close-group (group &optional server)
+  (setq nnml-article-file-alist nil)
+  t)
+
+(deffoo nnml-request-create-group (group &optional server args)
+  (nnml-possibly-change-directory nil server)
+  (nnmail-activate 'nnml)
+  (cond
+   ((let ((file (directory-file-name (nnml-group-pathname group nil server)))
+         (file-name-coding-system nnmail-pathname-coding-system))
+      (and (file-exists-p file)
+          (not (file-directory-p file))))
+    (nnheader-report 'nnml "%s is a file"
+                    (directory-file-name (nnml-group-pathname group
+                                                              nil server))))
+   ((assoc group nnml-group-alist)
+    t)
+   (t
+    (let (active)
+      (push (list group (setq active (cons 1 0)))
+           nnml-group-alist)
+      (nnml-possibly-create-directory group server)
+      (nnml-possibly-change-directory group server)
+      (let* ((file-name-coding-system nnmail-pathname-coding-system)
+            (articles (nnml-directory-articles nnml-current-directory)))
+       (when articles
+         (setcar active (apply 'min articles))
+         (setcdr active (apply 'max articles))))
+      (nnmail-save-active nnml-group-alist nnml-active-file)
+      t))))
+
+(deffoo nnml-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 nnml-active-file))
+    (setq nnml-group-alist (nnmail-get-active))
+    t))
+
+(deffoo nnml-request-newgroups (date &optional server)
+  (nnml-request-list server))
+
+(deffoo nnml-request-list-newsgroups (&optional server)
+  (save-excursion
+    (nnmail-find-file nnml-newsgroups-file)))
+
+(deffoo nnml-request-expire-articles (articles group &optional server force)
+  (nnml-possibly-change-directory group server)
+  (let* ((file-name-coding-system nnmail-pathname-coding-system)
+        (active-articles
+         (nnml-directory-articles nnml-current-directory))
+        (is-old t)
+        (decoded (nnml-decoded-group-name group server))
+        article rest mod-time number target)
+    (nnmail-activate 'nnml)
+
+    (setq active-articles (sort active-articles '<))
+    ;; Articles not listed in active-articles are already gone,
+    ;; so don't try to expire them.
+    (setq articles (gnus-sorted-intersection articles active-articles))
+
+    (while (and articles is-old)
+      (if (and (setq article (nnml-article-to-file
+                             (setq number (pop articles))))
+              (setq mod-time (nth 5 (file-attributes article)))
+              (nnml-deletable-article-p group number)
+              (setq is-old (nnmail-expired-article-p group mod-time force
+                                                     nnml-inhibit-expiry)))
+         (progn
+           ;; Allow a special target group.
+           (setq target nnmail-expiry-target)
+           (unless (eq target 'delete)
+             (with-temp-buffer
+               (nnml-request-article number group server (current-buffer))
+               (let (nnml-current-directory
+                     nnml-current-group
+                     nnml-article-file-alist)
+                 (when (functionp target)
+                   (setq target (funcall target group)))
+                 (when (and target (not (eq target 'delete)))
+                   (if (or (gnus-request-group target)
+                           (gnus-request-create-group target))
+                       (nnmail-expiry-target-group target group)
+                     (setq target nil)))))
+             ;; Maybe directory is changed during nnmail-expiry-target-group.
+             (nnml-possibly-change-directory group server))
+           (if target
+               (progn
+                 (nnheader-message 5 "Deleting article %s in %s"
+                                   number decoded)
+                 (condition-case ()
+                     (funcall nnmail-delete-file-function article)
+                   (file-error
+                    (push number rest)))
+                 (setq active-articles (delq number active-articles))
+                 (nnml-nov-delete-article group number))
+             (push number rest)))
+       (push number rest)))
+    (let ((active (nth 1 (assoc group nnml-group-alist))))
+      (when active
+       (setcar active (or (and active-articles
+                               (apply 'min active-articles))
+                          (1+ (cdr active)))))
+      (nnmail-save-active nnml-group-alist nnml-active-file))
+    (nnml-save-nov)
+    (nconc rest articles)))
+
+(deffoo nnml-request-move-article
+    (article group server accept-form &optional last move-is-internal)
+  (let ((buf (get-buffer-create " *nnml move*"))
+       (file-name-coding-system nnmail-pathname-coding-system)
+       result)
+    (nnml-possibly-change-directory group server)
+    (nnml-update-file-alist)
+    (and
+     (nnml-deletable-article-p group article)
+     (nnml-request-article article group server)
+     (let (nnml-current-directory
+          nnml-current-group
+          nnml-article-file-alist)
+       (with-current-buffer buf
+        (insert-buffer-substring nntp-server-buffer)
+        (setq result (eval accept-form))
+        (kill-buffer (current-buffer))
+        result))
+     (progn
+       (nnml-possibly-change-directory group server)
+       (condition-case ()
+          (funcall nnmail-delete-file-function
+                   (nnml-article-to-file  article))
+        (file-error nil))
+       (nnml-nov-delete-article group article)
+       (when last
+        (nnml-save-nov)
+        (nnmail-save-active nnml-group-alist nnml-active-file))))
+    result))
+
+(deffoo nnml-request-accept-article (group &optional server last)
+  (nnml-possibly-change-directory group server)
+  (nnmail-check-syntax)
+  (let (result)
+    (when nnmail-cache-accepted-message-ids
+      (nnmail-cache-insert (nnmail-fetch-field "message-id")
+                          group
+                          (nnmail-fetch-field "subject")
+                          (nnmail-fetch-field "from")))
+    (if (stringp group)
+       (and
+        (nnmail-activate 'nnml)
+        (setq result (car (nnml-save-mail
+                           (list (cons group (nnml-active-number group
+                                                                 server)))
+                           server t)))
+        (progn
+          (nnmail-save-active nnml-group-alist nnml-active-file)
+          (and last (nnml-save-nov))))
+      (and
+       (nnmail-activate 'nnml)
+       (if (and (not (setq result (nnmail-article-group
+                                  `(lambda (group)
+                                     (nnml-active-number group ,server)))))
+               (yes-or-no-p "Moved to `junk' group; delete article? "))
+          (setq result 'junk)
+        (setq result (car (nnml-save-mail result server t))))
+       (when last
+        (nnmail-save-active nnml-group-alist nnml-active-file)
+        (when nnmail-cache-accepted-message-ids
+          (nnmail-cache-close))
+        (nnml-save-nov))))
+    result))
+
+(deffoo nnml-request-post (&optional server)
+  (nnmail-do-request-post 'nnml-request-accept-article server))
+
+(deffoo nnml-request-replace-article (article group buffer)
+  (nnml-possibly-change-directory group)
+  (with-current-buffer buffer
+    (nnml-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 (nnml-article-to-file article)
+                  (expand-file-name (int-to-string article)
+                                    nnml-current-directory))
+              nil (if (nnheader-be-verbose 5) nil 'nomesg))
+             t)
+       (setq headers (nnml-parse-head chars article))
+       ;; Replace the NOV line in the NOV file.
+       (with-current-buffer (nnml-open-nov group)
+         (goto-char (point-min))
+         (if (or (looking-at art)
+                 (search-forward (concat "\n" art) nil t))
+             ;; Delete the old NOV line.
+             (gnus-delete-line)
+           ;; 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-number
+                           (buffer-substring
+                            (match-beginning 0) (match-end 0)))
+                          article)
+                       (zerop (forward-line 1)))))
+         (beginning-of-line)
+         (nnheader-insert-nov headers)
+         (nnml-save-nov)
+         t)))))
+
+(deffoo nnml-request-delete-group (group &optional force server)
+  (nnml-possibly-change-directory group server)
+  (let ((file (directory-file-name nnml-current-directory))
+       (file-name-coding-system nnmail-pathname-coding-system))
+    (if (file-exists-p file)
+       (if (file-directory-p file)
+           (progn
+             (when force
+               ;; Delete all articles in GROUP.
+               (let ((articles
+                      (directory-files
+                       nnml-current-directory t
+                       (concat
+                        nnheader-numerical-short-files
+                        "\\|" (regexp-quote nnml-nov-file-name) "$")))
+                     (decoded (nnml-decoded-group-name group server)))
+                 (dolist (article articles)
+                   (when (file-writable-p article)
+                     (nnheader-message 5 "Deleting article %s in %s..."
+                                       (file-name-nondirectory article)
+                                       decoded)
+                     (funcall nnmail-delete-file-function article))))
+               ;; Try to delete the directory itself.
+               (ignore-errors (delete-directory nnml-current-directory))))
+         (nnheader-report 'nnml "%s is not a directory" file))
+      (nnheader-report 'nnml "No such directory: %s/" file))
+    ;; Remove the group from all structures.
+    (setq nnml-group-alist
+         (delq (assoc group nnml-group-alist) nnml-group-alist)
+         nnml-current-group nil
+         nnml-current-directory nil)
+    ;; Save the active file.
+    (nnmail-save-active nnml-group-alist nnml-active-file))
+  t)
+
+(deffoo nnml-request-rename-group (group new-name &optional server)
+  (nnml-possibly-change-directory group server)
+  (let ((new-dir (nnml-group-pathname new-name nil server))
+       (old-dir (nnml-group-pathname group nil server))
+       (file-name-coding-system nnmail-pathname-coding-system))
+    (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.
+      (dolist (file (nnheader-article-to-file-alist old-dir))
+       (rename-file
+        (concat old-dir (cdr file))
+        (concat new-dir (cdr file))))
+      ;; Move .overview file.
+      (let ((overview (concat old-dir nnml-nov-file-name)))
+       (when (file-exists-p overview)
+         (rename-file overview (concat new-dir nnml-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 nnml-group-alist)))
+       (when entry
+         (setcar entry new-name))
+       (setq nnml-current-directory nil
+             nnml-current-group nil)
+       ;; Save the new group alist.
+       (nnmail-save-active nnml-group-alist nnml-active-file)
+       t))))
+
+(deffoo nnml-set-status (article name value &optional group server)
+  (nnml-possibly-change-directory group server)
+  (let ((file (nnml-article-to-file article)))
+    (cond
+     ((not (file-exists-p file))
+      (nnheader-report 'nnml "File %s does not exist" file))
+     (t
+      (with-temp-file file
+       (nnheader-insert-file-contents file)
+       (nnmail-replace-status name value))
+      t))))
+
+\f
+;;; Internal functions.
+
+(defun nnml-article-to-file (article)
+  (nnml-update-file-alist)
+  (let (file)
+    (if (setq file
+             (if nnml-use-compressed-files
+                 (cdr (assq article nnml-article-file-alist))
+               (number-to-string article)))
+       (expand-file-name file nnml-current-directory)
+      (when (not nnheader-directory-files-is-safe)
+       ;; Just to make sure nothing went wrong when reading over NFS --
+       ;; check once more.
+       (when (file-exists-p
+              (setq file (expand-file-name (number-to-string article)
+                                           nnml-current-directory)))
+         (nnml-update-file-alist t)
+         file)))))
+
+(defun nnml-deletable-article-p (group article)
+  "Say whether ARTICLE in GROUP can be deleted."
+  (let ((file-name-coding-system nnmail-pathname-coding-system)
+       path)
+    (when (setq path (nnml-article-to-file article))
+      (when (file-writable-p path)
+       (or (not nnmail-keep-last-article)
+           (not (eq (cdr (nth 1 (assoc group nnml-group-alist)))
+                    article)))))))
+
+;; Find an article number in the current group given the Message-ID.
+(defun nnml-find-group-number (id server)
+  (with-current-buffer (get-buffer-create " *nnml id*")
+    (let ((alist nnml-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 (nnml-find-id nnml-current-group id server))
+         (cons nnml-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) nnml-current-group)
+             (setq number (nnml-find-id (caar alist) id server)))
+         (or number
+             (setq alist (cdr alist))))
+       (and number
+            (cons (caar alist) number))))))
+
+(defun nnml-find-id (group id server)
+  (erase-buffer)
+  (let ((nov (nnml-group-pathname group nnml-nov-file-name server))
+       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" (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 nnml-retrieve-headers-with-nov (articles &optional fetch-old)
+  (if (or gnus-nov-is-evil nnml-nov-is-evil)
+      nil
+    (let ((nov (expand-file-name nnml-nov-file-name nnml-current-directory)))
+      (when (file-exists-p nov)
+       (with-current-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 nnml-possibly-change-directory (group &optional server)
+  (when (and server
+            (not (nnml-server-opened server)))
+    (nnml-open-server server))
+  (if (not group)
+      t
+    (let ((pathname (nnml-group-pathname group nil server))
+         (file-name-coding-system nnmail-pathname-coding-system))
+      (when (not (equal pathname nnml-current-directory))
+       (setq nnml-current-directory pathname
+             nnml-current-group group
+             nnml-article-file-alist nil))
+      (file-exists-p nnml-current-directory))))
+
+(defun nnml-possibly-create-directory (group &optional server)
+  (let ((dir (nnml-group-pathname group nil server))
+       (file-name-coding-system nnmail-pathname-coding-system))
+    (unless (file-exists-p dir)
+      (make-directory (directory-file-name dir) t)
+      (nnheader-message 5 "Creating mail directory %s" dir))))
+
+(defun nnml-save-mail (group-art &optional server full-nov)
+  "Save a mail into the groups GROUP-ART in the nnml server SERVER.
+GROUP-ART is a list that each element is a cons of a group name and an
+article number.  This function is called narrowed to an article."
+  (let* ((chars (nnmail-insert-lines))
+        (extension (and nnml-use-compressed-files
+                        (> chars nnml-compressed-files-size-threshold)
+                        (if (stringp nnml-use-compressed-files)
+                            nnml-use-compressed-files
+                          ".gz")))
+        decoded dec file first headers)
+    (when nnmail-group-names-not-encoded-p
+      (dolist (ga (prog1 group-art (setq group-art nil)))
+       (setq group-art (nconc group-art
+                              (list (cons (nnml-encoded-group-name (car ga)
+                                                                   server)
+                                          (cdr ga))))
+             decoded (nconc decoded (list (car ga)))))
+      (setq dec decoded))
+    (nnmail-insert-xref group-art)
+    (run-hooks 'nnmail-prepare-save-mail-hook)
+    (run-hooks 'nnml-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.
+    (dolist (ga group-art)
+      (if nnmail-group-names-not-encoded-p
+         (progn
+           (nnml-possibly-create-directory (car decoded) server)
+           (setq file (nnmail-group-pathname
+                       (pop decoded) nnml-directory
+                       (concat (number-to-string (cdr ga)) extension))))
+       (nnml-possibly-create-directory (car ga) server)
+       (setq file (nnml-group-pathname
+                   (car ga) (concat (number-to-string (cdr ga)) extension)
+                   server)))
+      (if first
+         ;; It was already saved, so we just make a hard link.
+         (let ((file-name-coding-system nnmail-pathname-coding-system))
+           (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)))
+    ;; Generate a nov line for this article.  We generate the nov
+    ;; line after saving, because nov generation destroys the
+    ;; header.
+    (setq headers (nnml-parse-head chars))
+    ;; Output the nov line to all nov databases that should have it.
+    (let ((func (if full-nov
+                   'nnml-add-nov
+                 'nnml-add-incremental-nov)))
+      (if nnmail-group-names-not-encoded-p
+         (dolist (ga group-art)
+           (funcall func (pop dec) (cdr ga) headers))
+       (dolist (ga group-art)
+         (funcall func (car ga) (cdr ga) headers)))))
+  group-art)
+
+(defun nnml-active-number (group &optional server)
+  "Compute the next article number in GROUP on SERVER."
+  (let* ((encoded (if nnmail-group-names-not-encoded-p
+                     (nnml-encoded-group-name group server)))
+        (active (cadr (assoc (or encoded group) nnml-group-alist))))
+    ;; The group wasn't known to nnml, 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.
+      (nnml-possibly-create-directory group server)
+      (nnml-possibly-change-directory group server)
+      (unless nnml-article-file-alist
+       (setq nnml-article-file-alist
+             (sort
+              (nnml-current-group-article-to-file-alist)
+              'car-less-than-car)))
+      (setq active
+           (if nnml-article-file-alist
+               (cons (caar nnml-article-file-alist)
+                     (caar (last nnml-article-file-alist)))
+             (cons 1 0)))
+      (push (list (or encoded group) active) nnml-group-alist))
+    (setcdr active (1+ (cdr active)))
+    (while (file-exists-p
+           (nnml-group-pathname group (int-to-string (cdr active)) server))
+      (setcdr active (1+ (cdr active))))
+    (cdr active)))
+
+(defvar nnml-incremental-nov-buffer-alist nil)
+
+(defun nnml-save-incremental-nov ()
+  (save-excursion
+    (while nnml-incremental-nov-buffer-alist
+      (when (buffer-name (cdar nnml-incremental-nov-buffer-alist))
+       (set-buffer (cdar nnml-incremental-nov-buffer-alist))
+       (when (buffer-modified-p)
+         (nnmail-write-region (point-min) (point-max)
+                              nnml-nov-buffer-file-name t 'nomesg))
+       (set-buffer-modified-p nil)
+       (kill-buffer (current-buffer)))
+      (setq nnml-incremental-nov-buffer-alist
+           (cdr nnml-incremental-nov-buffer-alist)))))
+
+(defun nnml-open-incremental-nov (group)
+  (or (cdr (assoc group nnml-incremental-nov-buffer-alist))
+      (let ((buffer (nnml-get-nov-buffer group t)))
+       (push (cons group buffer) nnml-incremental-nov-buffer-alist)
+       buffer)))
+
+(defun nnml-add-incremental-nov (group article headers)
+  "Add a nov line for the GROUP nov headers, incrementally."
+  (with-current-buffer (nnml-open-incremental-nov group)
+    (goto-char (point-max))
+    (mail-header-set-number headers article)
+    (nnheader-insert-nov headers)))
+
+(defun nnml-add-nov (group article headers)
+  "Add a nov line for the GROUP base."
+  (with-current-buffer (nnml-open-nov group)
+    (goto-char (point-max))
+    (mail-header-set-number headers article)
+    (nnheader-insert-nov headers)))
+
+(defsubst nnml-header-value ()
+  (buffer-substring (match-end 0) (point-at-eol)))
+
+(defun nnml-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 (re-search-forward "\n\r?\n" nil t)
+            (1- (point))
+          (point-max))))
+      (let ((headers (nnheader-parse-naked-head)))
+       (mail-header-set-chars headers chars)
+       (mail-header-set-number headers number)
+       headers))))
+
+(defun nnml-get-nov-buffer (group &optional incrementalp)
+  (let* ((decoded (nnml-decoded-group-name group))
+        (buffer (get-buffer-create (format " *nnml %soverview %s*"
+                                           (if incrementalp
+                                               "incremental "
+                                             "")
+                                           decoded)))
+        (file-name-coding-system nnmail-pathname-coding-system))
+    (with-current-buffer buffer
+      (set (make-local-variable 'nnml-nov-buffer-file-name)
+          (nnmail-group-pathname decoded nnml-directory nnml-nov-file-name))
+      (erase-buffer)
+      (when (and (not incrementalp)
+                (file-exists-p nnml-nov-buffer-file-name))
+       (nnheader-insert-file-contents nnml-nov-buffer-file-name)))
+    buffer))
+
+(defun nnml-open-nov (group)
+  (or (let ((buffer (cdr (assoc group nnml-nov-buffer-alist))))
+       (and (buffer-name buffer)
+            buffer))
+      (let ((buffer (nnml-get-nov-buffer group)))
+       (push (cons group buffer) nnml-nov-buffer-alist)
+       buffer)))
+
+(defun nnml-save-nov ()
+  (save-excursion
+    (while nnml-nov-buffer-alist
+      (when (buffer-name (cdar nnml-nov-buffer-alist))
+       (set-buffer (cdar nnml-nov-buffer-alist))
+       (when (buffer-modified-p)
+         (nnmail-write-region (point-min) (point-max)
+                              nnml-nov-buffer-file-name nil 'nomesg))
+       (set-buffer-modified-p nil)
+       (kill-buffer (current-buffer)))
+      (setq nnml-nov-buffer-alist (cdr nnml-nov-buffer-alist)))))
+
+;;;###autoload
+(defun nnml-generate-nov-databases (&optional server)
+  "Generate NOV databases in all nnml directories."
+  (interactive (list (or (nnoo-current-server 'nnml) "")))
+  ;; Read the active file to make sure we don't re-use articles
+  ;; numbers in empty groups.
+  (nnmail-activate 'nnml)
+  (unless (nnml-server-opened server)
+    (nnml-open-server server))
+  (setq nnml-directory (expand-file-name nnml-directory))
+  ;; Recurse down the directories.
+  (nnml-generate-nov-databases-directory nnml-directory nil t)
+  ;; Save the active file.
+  (nnmail-save-active nnml-group-alist nnml-active-file))
+
+(defvar nnml-files)
+(defun nnml-generate-nov-databases-directory (dir &optional seen no-active)
+  "Regenerate the NOV database in DIR.
+
+Unless no-active is non-nil, update the active file too."
+  (interactive (list (let ((file-name-coding-system
+                           nnmail-pathname-coding-system))
+                      (read-directory-name "Regenerate NOV in: "
+                                           nnml-directory nil t))))
+  (setq dir (file-name-as-directory dir))
+  (let ((file-name-coding-system nnmail-pathname-coding-system))
+    ;; 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
+      (dolist (dir (directory-files dir t nil t))
+       (when (and (not (string-match "^\\." (file-name-nondirectory dir)))
+                  (file-directory-p dir))
+         (nnml-generate-nov-databases-directory dir seen)))
+      ;; Do this directory.
+      (let ((nnml-files (sort (nnheader-article-to-file-alist dir)
+                        'car-less-than-car)))
+       (if (not nnml-files)
+           (let* ((group (nnheader-file-to-group
+                          (directory-file-name dir) nnml-directory))
+                  (info (cadr (assoc group nnml-group-alist))))
+             (when info
+               (setcar info (1+ (cdr info)))))
+         (funcall nnml-generate-active-function dir)
+         ;; Generate the nov file.
+         (nnml-generate-nov-file dir nnml-files)
+         (unless no-active
+           (nnmail-save-active nnml-group-alist nnml-active-file)))))))
+
+(defun nnml-generate-active-info (dir)
+  ;; Update the active info for this group.
+  (let ((group (directory-file-name dir))
+       entry last)
+    (setq group (nnheader-file-to-group (nnml-encoded-group-name group)
+                                       nnml-directory)
+         entry (assoc group nnml-group-alist)
+         last (or (caadr entry) 0)
+         nnml-group-alist (delq entry nnml-group-alist))
+    (push (list group
+               (cons (or (caar nnml-files) (1+ last))
+                     (max last
+                          (or (caar (last nnml-files))
+                              0))))
+         nnml-group-alist)))
+
+(defun nnml-generate-nov-file (dir files)
+  (let* ((dir (file-name-as-directory dir))
+        (nov (concat dir nnml-nov-file-name))
+        (nov-buffer (get-buffer-create " *nov*"))
+        chars file headers)
+    (with-current-buffer nov-buffer
+      ;; Init the 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))
+      (dolist (file files)
+       (let ((path (concat dir (cdr file))))
+         (unless (file-directory-p path)
+           (erase-buffer)
+           (nnheader-insert-file-contents path)
+           (narrow-to-region
+            (goto-char (point-min))
+            (progn
+              (re-search-forward "\n\r?\n" nil t)
+              (setq chars (- (point-max) (point)))
+              (max (point-min) (1- (point)))))
+           (unless (zerop (buffer-size))
+             (goto-char (point-min))
+             (setq headers (nnml-parse-head chars (car file)))
+             (with-current-buffer nov-buffer
+               (goto-char (point-max))
+               (nnheader-insert-nov headers)))
+           (widen))))
+      (with-current-buffer nov-buffer
+       (nnmail-write-region (point-min) (point-max) nov nil 'nomesg)
+       (kill-buffer (current-buffer))))))
+
+(defun nnml-nov-delete-article (group article)
+  (with-current-buffer (nnml-open-nov group)
+    (when (nnheader-find-nov-line article)
+      (delete-region (point) (progn (forward-line 1) (point)))
+      (when (bobp)
+       (let ((active (cadr (assoc group nnml-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 nnml-update-file-alist (&optional force)
+  (when nnml-use-compressed-files
+    (when (or (not nnml-article-file-alist)
+             force)
+      (setq nnml-article-file-alist
+           (nnml-current-group-article-to-file-alist)))))
+
+(defun nnml-directory-articles (dir)
+  "Return a list of all article files in a directory.
+Use the nov database for that directory if available."
+  (if (or gnus-nov-is-evil nnml-nov-is-evil
+         (not (file-exists-p
+               (expand-file-name nnml-nov-file-name dir))))
+      (nnheader-directory-articles dir)
+    ;; build list from .overview if available
+    ;; We would use nnml-open-nov, except that nnml-nov-buffer-alist is
+    ;; defvoo'd, and we might get called when it hasn't been swapped in.
+    (with-current-buffer (nnml-get-nov-buffer nnml-current-group)
+      (let ((list nil)
+           art)
+       (goto-char (point-min))
+       (while (not (eobp))
+         (setq art (read (current-buffer)))
+         (push art list)
+         (forward-line 1))
+       list))))
+
+(defun nnml-current-group-article-to-file-alist ()
+  "Return an alist of article/file pairs in the current group.
+Use the nov database for the current group if available."
+  (if (or nnml-use-compressed-files
+         gnus-nov-is-evil
+         nnml-nov-is-evil
+         (not (file-exists-p
+               (expand-file-name nnml-nov-file-name
+                                 nnml-current-directory))))
+      (nnheader-article-to-file-alist nnml-current-directory)
+    ;; build list from .overview if available
+    (with-current-buffer (nnml-get-nov-buffer nnml-current-group)
+      (let ((alist nil)
+           art)
+       (goto-char (point-min))
+       (while (not (eobp))
+         (setq art (read (current-buffer)))
+         ;; assume file name is unadorned (ie. not compressed etc)
+         (push (cons art (int-to-string art)) alist)
+         (forward-line 1))
+       alist))))
+
+;;;
+;;; Group and server compaction. -- dvl
+;;;
+
+;; #### FIXME: this function handles self Xref: entry correctly, but I don't
+;; #### know how to handle external cross-references. I actually don't know if
+;; #### this is handled correctly elsewhere. For instance, what happens if you
+;; #### move all articles to a new group (that's what people do for manual
+;; #### compaction) ?
+
+;; #### NOTE: the function below handles the article backlog. This is
+;; #### conceptually the wrong place to do it because the backend is at a
+;; #### lower level. However, this is the only place where we have the needed
+;; #### information to do the job. Ideally, this function should not handle
+;; #### the backlog by itself, but return a list of moved groups / articles to
+;; #### the caller. This will become important to avoid code duplication when
+;; #### other backends get a compaction feature. Also, note that invalidating
+;; #### the "original article buffer" is already done at an upper level.
+
+;; Shouldn't `nnml-request-compact-group' be interactive? --rsteib
+
+(defun nnml-request-compact-group (group &optional server save)
+  (nnml-possibly-change-directory group server)
+  (unless nnml-article-file-alist
+    (setq nnml-article-file-alist
+         (sort (nnml-current-group-article-to-file-alist)
+               'car-less-than-car)))
+  (if (not nnml-article-file-alist)
+      ;; The group is empty: do nothing but return t
+      t
+    ;; The group is not empty:
+    (let* ((group-full-name
+           (gnus-group-prefixed-name
+            group
+            (gnus-server-to-method (format "nnml:%s" server))))
+          (info (gnus-get-info group-full-name))
+          (new-number 1)
+          compacted)
+      (let ((articles nnml-article-file-alist)
+           article)
+       (while (setq article (pop articles))
+         (let ((old-number (car article)))
+           (when (> old-number new-number)
+             ;; There is a gap here:
+             (let ((old-number-string (int-to-string old-number))
+                   (new-number-string (int-to-string new-number)))
+               (setq compacted t)
+               ;; #### NOTE: `nnml-article-to-file' calls
+               ;; #### `nnml-update-file-alist'  (which in turn calls
+               ;; #### `nnml-current-group-article-to-file-alist', which
+               ;; #### might use the NOV database). This might turn out to be
+               ;; #### inefficient. In that case, we will do the work
+               ;; #### manually.
+               ;; 1/ Move the article to a new file:
+               (let* ((oldfile (nnml-article-to-file old-number))
+                      (newfile
+                       (gnus-replace-in-string
+                        oldfile
+                        ;; nnml-use-compressed-files might be any string, but
+                        ;; probably it's sufficient to take into account only
+                        ;; "\\.[a-z0-9]+".  Note that we can't only use the
+                        ;; value of nnml-use-compressed-files because old
+                        ;; articles might have been saved with a different
+                        ;; value.
+                        (concat
+                         "\\(" old-number-string "\\)\\(\\(\\.[a-z0-9]+\\)?\\)$")
+                        (concat new-number-string "\\2"))))
+                 (with-current-buffer nntp-server-buffer
+                   (nnmail-find-file oldfile)
+                   ;; Update the Xref header in the article itself:
+                   (when (and (re-search-forward "^Xref: [^ ]+ " nil t)
+                              (re-search-forward
+                               (concat "\\<"
+                                       (regexp-quote
+                                        (concat group ":" old-number-string))
+                                       "\\>")
+                               (point-at-eol) t))
+                     (replace-match
+                      (concat group ":" new-number-string)))
+                   ;; Save to the new file:
+                   (nnmail-write-region (point-min) (point-max) newfile))
+                 (condition-case ()
+                     (funcall nnmail-delete-file-function oldfile)
+                   (file-error
+                    (message "Couldn't delete %s" oldfile))))
+               ;; 2/ Update all marks for this article:
+               ;; #### NOTE: it is possible that the new article number
+               ;; #### already belongs to a range, whereas the corresponding
+               ;; #### article doesn't exist (for example, if you delete an
+               ;; #### article). For that reason, it is important to update
+               ;; #### the ranges (meaning remove nonexistent articles) before
+               ;; #### doing anything on them.
+               ;; 2 a/ read articles:
+               (let ((read (gnus-info-read info)))
+                 (setq read (gnus-remove-from-range read (list new-number)))
+                 (when (gnus-member-of-range old-number read)
+                   (setq read (gnus-remove-from-range read (list old-number)))
+                   (setq read (gnus-add-to-range read (list new-number))))
+                 (gnus-info-set-read info read))
+               ;; 2 b/ marked articles:
+               (let ((oldmarks (gnus-info-marks info))
+                     mark newmarks)
+                 (while (setq mark (pop oldmarks))
+                   (setcdr mark (gnus-remove-from-range (cdr mark)
+                                                        (list new-number)))
+                   (when (gnus-member-of-range old-number (cdr mark))
+                     (setcdr mark (gnus-remove-from-range (cdr mark)
+                                                          (list old-number)))
+                     (setcdr mark (gnus-add-to-range (cdr mark)
+                                                     (list new-number))))
+                   (push mark newmarks))
+                 (gnus-info-set-marks info newmarks))
+               ;; 3/ Update the NOV entry for this article:
+               (unless nnml-nov-is-evil
+                 (with-current-buffer (nnml-open-nov group)
+                   (when (nnheader-find-nov-line old-number)
+                     ;; Replace the article number:
+                     (looking-at old-number-string)
+                     (replace-match new-number-string nil t)
+                     ;; Update the Xref header:
+                     (when (re-search-forward
+                            (concat "\\(Xref:[^\t\n]* \\)\\<"
+                                    (regexp-quote
+                                     (concat group ":" old-number-string))
+                                    "\\>")
+                            (point-at-eol) t)
+                       (replace-match
+                        (concat "\\1" group ":" new-number-string))))))
+               ;; 4/ Possibly remove the article from the backlog:
+               (when gnus-keep-backlog
+                 ;; #### NOTE: instead of removing the article, we could
+                 ;; #### modify the backlog to reflect the numbering change,
+                 ;; #### but I don't think it's worth it.
+                 (gnus-backlog-remove-article group-full-name old-number)
+                 (gnus-backlog-remove-article group-full-name new-number))))
+           (setq new-number (1+ new-number)))))
+      (if (not compacted)
+         ;; No compaction had to be done:
+         t
+       ;; Some articles have actually been renamed:
+       ;; 1/ Rebuild active information:
+       (let ((entry (assoc group nnml-group-alist))
+             (active (cons 1 (1- new-number))))
+         (setq nnml-group-alist (delq entry nnml-group-alist))
+         (push (list group active) nnml-group-alist)
+         ;; Update the active hashtable to let the *Group* buffer display
+         ;; up-to-date lines. I don't think that either gnus-newsrc-hashtb or
+         ;; gnus-newwrc-alist are out of date, since all we did is to modify
+         ;; the info of the group internally.
+         (gnus-set-active group-full-name active))
+       ;; 1 bis/
+       ;; #### NOTE: normally, we should save the overview (NOV) file
+       ;; #### here. However, there is no such function as
+       ;; #### nnml-save-nov for a single group. Only for all
+       ;; #### groups. Gnus inconsistency is getting worse every
+       ;; #### day...  ;; 3/ Save everything if this was not part of
+       ;; #### a bigger operation:
+       (if (not save)
+           ;; Nothing to save (yet):
+           t
+         ;; Something to save:
+         ;; a/ Save the NOV databases:
+         ;; #### NOTE: this should be done directory per directory in 1bis
+         ;; #### above. See comment there.
+         (nnml-save-nov)
+         ;; b/ Save the active file:
+         (nnmail-save-active nnml-group-alist nnml-active-file)
+         t)))))
+
+(defun nnml-request-compact (&optional server)
+  "Request compaction of all SERVER nnml groups."
+  (interactive (list (or (nnoo-current-server 'nnml) "")))
+  (nnmail-activate 'nnml)
+  (unless (nnml-server-opened server)
+    (nnml-open-server server))
+  (setq nnml-directory (expand-file-name nnml-directory))
+  (let* ((groups (gnus-groups-from-server
+                 (gnus-server-to-method (format "nnml:%s" server))))
+        (first (pop groups))
+        group)
+    (when first
+      (while (setq group (pop groups))
+       (nnml-request-compact-group (gnus-group-real-name group) server))
+      (nnml-request-compact-group (gnus-group-real-name first) server t))))
+
+
+(provide 'nnml)
+
+;;; nnml.el ends here
diff --git a/xemacs-packages/gnus/lisp/nnnil.el b/xemacs-packages/gnus/lisp/nnnil.el
new file mode 100644 (file)
index 0000000..e40126d
--- /dev/null
@@ -0,0 +1,81 @@
+;;; nnnil.el --- empty backend for Gnus
+
+;; This file is in the public domain.
+
+;; Author: Paul Jarc <prj@po.cwru.edu>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; nnnil is a Gnus backend that provides no groups or articles.  It's useful
+;; as a primary select method when you want all your real select methods to
+;; be secondary or foreign.
+
+;;; Code:
+
+(eval-and-compile
+  (require 'nnheader))
+
+(defvar nnnil-status-string "")
+
+(defun nnnil-retrieve-headers (articles &optional group server fetch-old)
+  (with-current-buffer nntp-server-buffer
+    (erase-buffer))
+  'nov)
+
+(defun nnnil-open-server (server &optional definitions)
+  t)
+
+(defun nnnil-close-server (&optional server)
+  t)
+
+(defun nnnil-request-close ()
+  t)
+
+(defun nnnil-server-opened (&optional server)
+  t)
+
+(defun nnnil-status-message (&optional server)
+  nnnil-status-string)
+
+(defun nnnil-request-article (article &optional group server to-buffer)
+  (setq nnnil-status-string "No such group")
+  nil)
+
+(defun nnnil-request-group (group &optional server fast info)
+  (let (deactivate-mark)
+    (with-current-buffer nntp-server-buffer
+      (erase-buffer)
+      (insert "411 no such news group\n")))
+  (setq nnnil-status-string "No such group")
+  nil)
+
+(defun nnnil-close-group (group &optional server)
+  t)
+
+(defun nnnil-request-list (&optional server)
+  (with-current-buffer nntp-server-buffer
+    (erase-buffer))
+  t)
+
+(defun nnnil-request-post (&optional server)
+  (setq nnnil-status-string "Read-only server")
+  nil)
+
+(provide 'nnnil)
+
+;;; nnnil.el ends here
diff --git a/xemacs-packages/gnus/lisp/nnoo.el b/xemacs-packages/gnus/lisp/nnoo.el
new file mode 100644 (file)
index 0000000..5193580
--- /dev/null
@@ -0,0 +1,324 @@
+;;; nnoo.el --- OO Gnus Backends
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'nnheader)
+(eval-when-compile (require 'cl))
+
+(defvar nnoo-definition-alist nil)
+(defvar nnoo-state-alist nil)
+(defvar nnoo-parent-backend nil)
+
+(defmacro defvoo (var init &optional doc &rest map)
+  "The same as `defvar', only takes list of variables to MAP to."
+  `(prog1
+       ,(if doc
+           `(defvar ,var ,init ,(concat doc "\n\nThis is a Gnus server variable.  See Info node `(gnus)Select Methods'."))
+         `(defvar ,var ,init))
+     (nnoo-define ',var ',map)))
+(put 'defvoo 'lisp-indent-function 2)
+(put 'defvoo 'edebug-form-spec '(var init &optional doc &rest map))
+
+(defmacro deffoo (func args &rest forms)
+  "The same as `defun', only register FUNC."
+  `(prog1
+       (defun ,func ,args ,@forms)
+     (nnoo-register-function ',func)))
+(put 'deffoo 'lisp-indent-function 2)
+(put 'deffoo 'edebug-form-spec '(&define name lambda-list def-body))
+
+(defun nnoo-register-function (func)
+  (let ((funcs (nthcdr 3 (assoc (nnoo-backend func)
+                               nnoo-definition-alist))))
+    (unless funcs
+      (error "%s belongs to a backend that hasn't been declared" func))
+    (setcar funcs (cons func (car funcs)))))
+
+(defmacro nnoo-declare (backend &rest parents)
+  `(eval-and-compile
+     (if (assq ',backend nnoo-definition-alist)
+        (setcar (cdr (assq ',backend nnoo-definition-alist))
+                (mapcar 'list ',parents))
+       (push (list ',backend
+                  (mapcar 'list ',parents)
+                  nil nil)
+            nnoo-definition-alist))
+     (unless (assq ',backend nnoo-state-alist)
+       (push (list ',backend "*internal-non-initialized-backend*")
+            nnoo-state-alist))))
+(put 'nnoo-declare 'lisp-indent-function 1)
+
+(defun nnoo-parents (backend)
+  (nth 1 (assoc backend nnoo-definition-alist)))
+
+(defun nnoo-variables (backend)
+  (nth 2 (assoc backend nnoo-definition-alist)))
+
+(defun nnoo-functions (backend)
+  (nth 3 (assoc backend nnoo-definition-alist)))
+
+(defmacro nnoo-import (backend &rest imports)
+  `(nnoo-import-1 ',backend ',imports))
+(put 'nnoo-import 'lisp-indent-function 1)
+
+(defun nnoo-import-1 (backend imports)
+  (let ((call-function
+        (if (symbolp (car imports)) (pop imports) 'nnoo-parent-function))
+       imp functions function)
+    (while (setq imp (pop imports))
+      (setq functions
+           (or (cdr imp)
+               (nnoo-functions (car imp))))
+      (while functions
+       (unless (fboundp
+                (setq function
+                      (nnoo-symbol backend
+                                   (nnoo-rest-symbol (car functions)))))
+         (eval `(deffoo ,function (&rest args)
+                  (,call-function ',backend ',(car functions) args))))
+       (pop functions)))))
+
+(defun nnoo-parent-function (backend function args)
+  (let ((pbackend (nnoo-backend function))
+       (nnoo-parent-backend backend))
+    (nnoo-change-server pbackend
+                       (nnoo-current-server backend)
+                       (cdr (assq pbackend (nnoo-parents backend))))
+    (prog1
+       (apply function args)
+      ;; Copy the changed variables back into the child.
+      (let ((vars (cdr (assq pbackend (nnoo-parents backend)))))
+       (while vars
+         (set (cadar vars) (symbol-value (caar vars)))
+         (setq vars (cdr vars)))))))
+
+(defun nnoo-execute (backend function &rest args)
+  "Execute FUNCTION on behalf of BACKEND."
+  (let ((pbackend (nnoo-backend function))
+       (nnoo-parent-backend backend))
+    (nnoo-change-server pbackend
+                       (nnoo-current-server backend)
+                       (cdr (assq pbackend (nnoo-parents backend))))
+    (prog1
+       (apply function args)
+      ;; Copy the changed variables back into the child.
+      (let ((vars (cdr (assq pbackend (nnoo-parents backend)))))
+       (while vars
+         (set (cadar vars) (symbol-value (caar vars)))
+         (setq vars (cdr vars)))))))
+
+(defmacro nnoo-map-functions (backend &rest maps)
+  `(nnoo-map-functions-1 ',backend ',maps))
+(put 'nnoo-map-functions 'lisp-indent-function 1)
+
+(defun nnoo-map-functions-1 (backend maps)
+  (let (m margs i)
+    (while (setq m (pop maps))
+      (setq i 0
+           margs nil)
+      (while (< i (length (cdr m)))
+       (if (numberp (nth i (cdr m)))
+           (push `(nth ,i args) margs)
+         (push (nth i (cdr m)) margs))
+       (incf i))
+      (eval `(deffoo ,(nnoo-symbol backend (nnoo-rest-symbol (car m)))
+                (&rest args)
+              (nnoo-parent-function ',backend ',(car m)
+                                    ,(cons 'list (nreverse margs))))))))
+
+(defun nnoo-backend (symbol)
+  (string-match "^[^-]+-" (symbol-name symbol))
+  (intern (substring (symbol-name symbol) 0 (1- (match-end 0)))))
+
+(defun nnoo-rest-symbol (symbol)
+  (string-match "^[^-]+-" (symbol-name symbol))
+  (intern (substring (symbol-name symbol) (match-end 0))))
+
+(defun nnoo-symbol (backend symbol)
+  (intern (format "%s-%s" backend symbol)))
+
+(defun nnoo-define (var map)
+  (let* ((backend (nnoo-backend var))
+        (def (assq backend nnoo-definition-alist))
+        (parents (nth 1 def)))
+    (unless def
+      (error "%s belongs to a backend that hasn't been declared" var))
+    (setcar (nthcdr 2 def)
+           (delq (assq var (nth 2 def)) (nth 2 def)))
+    (setcar (nthcdr 2 def)
+           (cons (cons var (symbol-value var))
+                 (nth 2 def)))
+    (while map
+      (nconc (assq (nnoo-backend (car map)) parents)
+            (list (list (pop map) var))))))
+
+(defun nnoo-change-server (backend server defs)
+  (let* ((bstate (cdr (assq backend nnoo-state-alist)))
+        (current (car bstate))
+        (parents (nnoo-parents backend))
+        (server (if nnoo-parent-backend
+                    (format "%s+%s" nnoo-parent-backend server)
+                  server))
+        (bvariables (nnoo-variables backend))
+        state def)
+    ;; If we don't have a current state, we push an empty state
+    ;; onto the alist.
+    (unless bstate
+      (push (setq bstate (list backend nil))
+           nnoo-state-alist)
+      (pop bstate))
+    (if (equal server current)
+       t
+      (nnoo-push-server backend current)
+      (setq state (or (cdr (assoc server (cddr bstate)))
+                     (nnoo-variables backend)))
+      (while state
+       (set (caar state) (cdar state))
+       (pop state))
+      (setcar bstate server)
+      (unless (cdr (assoc server (cddr bstate)))
+       (while (setq def (pop defs))
+         (unless (assq (car def) bvariables)
+           (nconc bvariables
+                  (list (cons (car def) (and (boundp (car def))
+                                             (symbol-value (car def)))))))
+         (if (equal server "*internal-non-initialized-backend*")
+             (set (car def) (symbol-value (cadr def)))
+           (set (car def) (cadr def)))))
+      (while parents
+       (nnoo-change-server
+        (caar parents) (format "%s+%s" backend server)
+        (mapcar (lambda (def) (list (car def) (symbol-value (cadr def))))
+                (cdar parents)))
+       (pop parents))))
+  t)
+
+(defun nnoo-push-server (backend current)
+  (let ((bstate (assq backend nnoo-state-alist))
+       (defs (nnoo-variables backend)))
+    ;; Remove the old definition.
+    (setcdr (cdr bstate) (delq (assoc current (cddr bstate)) (cddr bstate)))
+    ;; If this is the first time we push the server (i. e., this is
+    ;; the nil server), then we update the default values of
+    ;; all the variables to reflect the current values.
+    (when (equal current "*internal-non-initialized-backend*")
+      (let ((defaults (nnoo-variables backend))
+           def)
+       (while (setq def (pop defaults))
+         (setcdr def (symbol-value (car def))))))
+    (let (state)
+      (while defs
+       (push (cons (caar defs) (symbol-value (caar defs)))
+             state)
+       (pop defs))
+      (nconc bstate (list (cons current state))))))
+
+(defsubst nnoo-current-server-p (backend server)
+  (equal (nnoo-current-server backend)
+        (if nnoo-parent-backend
+            (format "%s+%s" nnoo-parent-backend server)
+          server)))
+
+(defun nnoo-current-server (backend)
+  (nth 1 (assq backend nnoo-state-alist)))
+
+(defun nnoo-close-server (backend &optional server)
+  (unless server
+    (setq server (nnoo-current-server backend)))
+  (when server
+    (let* ((bstate (cdr (assq backend nnoo-state-alist)))
+          (defs (assoc server (cdr bstate))))
+      (when bstate
+       (setcar bstate nil)
+       (setcdr bstate (delq defs (cdr bstate)))
+       (pop defs)
+       (while defs
+         (set (car (pop defs)) nil)))))
+  t)
+
+(defun nnoo-close (backend)
+  (setq nnoo-state-alist
+       (delq (assq backend nnoo-state-alist)
+             nnoo-state-alist))
+  t)
+
+(defun nnoo-status-message (backend server)
+  (nnheader-get-report backend))
+
+(defun nnoo-server-opened (backend server)
+  (and (nnoo-current-server-p backend server)
+       nntp-server-buffer
+       (buffer-name nntp-server-buffer)))
+
+(defmacro nnoo-define-basics (backend)
+  "Define `close-server', `server-opened' and `status-message'."
+  `(eval-and-compile
+     (nnoo-define-basics-1 ',backend)))
+
+(defun nnoo-define-basics-1 (backend)
+  (let ((functions '(close-server server-opened status-message)))
+    (while functions
+      (eval `(deffoo ,(nnoo-symbol backend (car functions))
+                (&optional server)
+              (,(nnoo-symbol 'nnoo (pop functions)) ',backend server)))))
+  (eval `(deffoo ,(nnoo-symbol backend 'open-server)
+            (server &optional defs)
+          (nnoo-change-server ',backend server defs))))
+
+(defmacro nnoo-define-skeleton (backend)
+  "Define all required backend functions for BACKEND.
+All functions will return nil and report an error."
+  `(eval-and-compile
+     (nnoo-define-skeleton-1 ',backend)))
+
+(defun nnoo-define-skeleton-1 (backend)
+  (let ((functions '(retrieve-headers
+                    request-close request-article
+                    request-group close-group
+                    request-list request-post request-list-newsgroups))
+       function fun)
+    (while (setq function (pop functions))
+      (when (not (fboundp (setq fun (nnoo-symbol backend function))))
+       (eval `(deffoo ,fun
+                  (&rest args)
+                (nnheader-report ',backend ,(format "%s-%s not implemented"
+                                                    backend function))))))))
+
+(defun nnoo-set (server &rest args)
+  (let ((parents (nnoo-parents (car server)))
+       (nnoo-parent-backend (car server)))
+    (while parents
+      (nnoo-change-server (caar parents)
+                         (cadr server)
+                         (cdar parents))
+      (pop parents)))
+  (nnoo-change-server (car server)
+                     (cadr server) (cddr server))
+  (while args
+    (set (pop args) (pop args))))
+
+(provide 'nnoo)
+
+;;; nnoo.el ends here
diff --git a/xemacs-packages/gnus/lisp/nnregistry.el b/xemacs-packages/gnus/lisp/nnregistry.el
new file mode 100644 (file)
index 0000000..6cf4c9d
--- /dev/null
@@ -0,0 +1,66 @@
+;;; nnregistry.el --- access to articles via Gnus' message-id registry
+;;; -*- coding: utf-8 -*-
+
+;; Copyright (C) 2010-2016 Free Software Foundation, Inc.
+
+;; Authors: Ludovic Courtès <ludo@gnu.org>
+;; Keywords: news, mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This file provides the `nnregistry' Gnus back-end.  It can be used
+;; in `gnus-refer-article-method' to quickly search for a message by
+;; id, regardless of the back-end that stores it.  See the Gnus manual
+;; for usage examples and more information.
+
+;;; Code:
+
+(require 'nnoo)
+(require 'gnus-registry)
+(require 'gnus-int)
+
+(nnoo-declare nnregistry)
+
+(deffoo nnregistry-server-opened (server)
+  gnus-registry-enabled)
+
+(deffoo nnregistry-close-server (server)
+  t)
+
+(deffoo nnregistry-status-message (server)
+  nil)
+
+(deffoo nnregistry-open-server (server &optional defs)
+  gnus-registry-enabled)
+
+(defvar nnregistry-within-nnregistry nil)
+
+(deffoo nnregistry-request-article (id &optional group server buffer)
+  (and (not nnregistry-within-nnregistry)
+       (let* ((nnregistry-within-nnregistry t)
+             (group (nth 0 (gnus-registry-get-id-key id 'group)))
+             (gnus-override-method nil))
+        (message "nnregistry: requesting article `%s' in group `%s'"
+                 id group)
+        (and group
+             (gnus-check-group group)
+             (gnus-request-article id group buffer)))))
+
+(provide 'nnregistry)
+
+;;; nnregistry.el ends here
diff --git a/xemacs-packages/gnus/lisp/nnrss.el b/xemacs-packages/gnus/lisp/nnrss.el
new file mode 100644 (file)
index 0000000..c17a13c
--- /dev/null
@@ -0,0 +1,1044 @@
+;;; nnrss.el --- interfacing with RSS
+
+;; Copyright (C) 2001-2016 Free Software Foundation, Inc.
+
+;; Author: Shenghuo Zhu <zsh@cs.rochester.edu>
+;; Keywords: RSS
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'gnus)
+(require 'nnoo)
+(require 'nnmail)
+(require 'message)
+(require 'mm-util)
+(require 'gnus-util)
+(require 'time-date)
+(require 'rfc2231)
+(require 'mm-url)
+(require 'rfc2047)
+(require 'mml)
+(eval-when-compile
+  (ignore-errors
+   (require 'xml)))
+(eval '(require 'xml))
+
+(nnoo-declare nnrss)
+
+(defvoo nnrss-directory (nnheader-concat gnus-directory "rss/")
+  "Where nnrss will save its files.")
+
+(defvoo nnrss-ignore-article-fields '(slash:comments)
+  "*List of fields that should be ignored when comparing RSS articles.
+Some RSS feeds update article fields during their lives, e.g. to
+indicate the number of comments or the number of times the
+articles have been seen.  However, if there is a difference
+between the local article and the distant one, the latter is
+considered to be new.  To avoid this and discard some fields, set
+this variable to the list of fields to be ignored.")
+
+;; (group max rss-url)
+(defvoo nnrss-server-data nil)
+
+;; (num timestamp url subject author date extra)
+(defvoo nnrss-group-data nil)
+(defvoo nnrss-group-max 0)
+(defvoo nnrss-group-min 1)
+(defvoo nnrss-group nil)
+(defvoo nnrss-group-hashtb (make-hash-table :test 'equal))
+(defvoo nnrss-status-string "")
+
+(defconst nnrss-version "nnrss 1.0")
+
+(defvar nnrss-group-alist '()
+  "List of RSS addresses.")
+
+(defvar nnrss-use-local nil
+  "If non-nil nnrss will read the feeds from local files in nnrss-directory.")
+
+(defvar nnrss-description-field 'X-Gnus-Description
+  "Field name used for DESCRIPTION.
+To use the description in headers, put this name into `nnmail-extra-headers'.")
+
+(defvar nnrss-url-field 'X-Gnus-Url
+  "Field name used for URL.
+To use the description in headers, put this name into `nnmail-extra-headers'.")
+
+(defvar nnrss-content-function nil
+  "A function which is called in `nnrss-request-article'.
+The arguments are (ENTRY GROUP ARTICLE).
+ENTRY is the record of the current headline.  GROUP is the group name.
+ARTICLE is the article number of the current headline.")
+
+(defvar nnrss-file-coding-system mm-universal-coding-system
+  "*Coding system used when reading and writing files.
+If you run Gnus with various versions of Emacsen, the value of this
+variable should be the coding system that all those Emacsen support.
+Note that you have to regenerate all the nnrss groups if you change
+the value.  Moreover, you should be patient even if you are made to
+read the same articles twice, that arises for the difference of the
+versions of xml.el.")
+
+(defvar nnrss-compatible-encoding-alist
+  (delq nil (mapcar (lambda (elem)
+                     (if (and (mm-coding-system-p (car elem))
+                              (mm-coding-system-p (cdr elem)))
+                         elem))
+                   mm-charset-override-alist))
+  "Alist of encodings and those supersets.
+The cdr of each element is used to decode data if it is available when
+the car is what the data specify as the encoding.  Or, the car is used
+for decoding when the cdr that the data specify is not available.")
+
+(nnoo-define-basics nnrss)
+
+;;; Interface functions
+
+(defsubst nnrss-format-string (string)
+  (gnus-replace-in-string string " *\n *" " "))
+
+(defun nnrss-decode-group-name (group)
+  (if (and group (mm-coding-system-p 'utf-8))
+      (setq group (mm-decode-coding-string group 'utf-8))
+    group))
+
+(deffoo nnrss-retrieve-headers (articles &optional group server fetch-old)
+  (setq group (nnrss-decode-group-name group))
+  (nnrss-possibly-change-group group server)
+  (let (e)
+    (with-current-buffer nntp-server-buffer
+      (erase-buffer)
+      (dolist (article articles)
+       (if (setq e (assq article nnrss-group-data))
+           (insert (number-to-string (car e)) "\t" ;; number
+                   ;; subject
+                   (or (nth 3 e) "")
+                   "\t"
+                   ;; from
+                   (or (nth 4 e) "(nobody)")
+                   "\t"
+                   ;; date
+                   (or (nth 5 e) "")
+                   "\t"
+                   ;; id
+                   (format "<%d@%s.nnrss>" (car e) group)
+                   "\t"
+                   ;; refs
+                   "\t"
+                   ;; chars
+                   "-1" "\t"
+                   ;; lines
+                   "-1" "\t"
+                   ;; Xref
+                   "" "\t"
+                   (if (and (nth 6 e)
+                            (memq nnrss-description-field
+                                  nnmail-extra-headers))
+                       (concat (symbol-name nnrss-description-field)
+                               ": "
+                               (nnrss-format-string (nth 6 e))
+                               "\t")
+                     "")
+                   (if (and (nth 2 e)
+                            (memq nnrss-url-field
+                                  nnmail-extra-headers))
+                       (concat (symbol-name nnrss-url-field)
+                               ": "
+                               (nnrss-format-string (nth 2 e))
+                               "\t")
+                     "")
+                   "\n")))))
+  'nov)
+
+(deffoo nnrss-request-group (group &optional server dont-check info)
+  (setq group (nnrss-decode-group-name group))
+  (nnheader-message 6 "nnrss: Requesting %s..." group)
+  (nnrss-possibly-change-group group server)
+  (prog1
+      (if dont-check
+         t
+       (nnrss-check-group group server)
+       (nnheader-report 'nnrss "Opened group %s" group)
+       (nnheader-insert
+        "211 %d %d %d %s\n" nnrss-group-max nnrss-group-min nnrss-group-max
+        (prin1-to-string group)
+        t))
+    (nnheader-message 6 "nnrss: Requesting %s...done" group)))
+
+(deffoo nnrss-close-group (group &optional server)
+  t)
+
+(deffoo nnrss-request-article (article &optional group server buffer)
+  (setq group (nnrss-decode-group-name group))
+  (when (stringp article)
+    (setq article (if (string-match "\\`<\\([0-9]+\\)@" article)
+                     (string-to-number (match-string 1 article))
+                   0)))
+  (nnrss-possibly-change-group group server)
+  (let ((e (assq article nnrss-group-data))
+       (nntp-server-buffer (or buffer nntp-server-buffer))
+       post err)
+    (when e
+      (with-current-buffer nntp-server-buffer
+       (erase-buffer)
+       (if group
+           (insert "Newsgroups: " group "\n"))
+       (if (nth 3 e)
+           (insert "Subject: " (nth 3 e) "\n"))
+       (if (nth 4 e)
+           (insert "From: " (nth 4 e) "\n"))
+       (if (nth 5 e)
+           (insert "Date: " (nnrss-format-string (nth 5 e)) "\n"))
+       (let ((header (buffer-string))
+             (text (nth 6 e))
+             (link (nth 2 e))
+             (enclosure (nth 7 e))
+             (comments (nth 8 e))
+             (rfc2047-header-encoding-alist
+              (if (mm-coding-system-p 'utf-8)
+                  (cons '("Newsgroups" . utf-8)
+                        rfc2047-header-encoding-alist)
+                rfc2047-header-encoding-alist))
+             rfc2047-encode-encoded-words body fn)
+         (when (or text link enclosure comments)
+           (insert "\n")
+           (insert "<#multipart type=alternative>\n"
+                   "<#part type=\"text/plain\">\n")
+           (setq body (point))
+           (when text
+             (insert text)
+             (goto-char body)
+             (while (re-search-forward "\n+" nil t)
+               (replace-match " "))
+             (goto-char body)
+             ;; See `nnrss-check-group', which inserts "<br /><br />".
+             (when (search-forward "<br /><br />" nil t)
+               (if (eobp)
+                   (replace-match "\n")
+                 (replace-match "\n\n")))
+             (unless (eobp)
+               (let ((fill-column (default-value 'fill-column))
+                     (window (get-buffer-window nntp-server-buffer)))
+                 (when window
+                   (setq fill-column
+                         (max 1 (/ (* (window-width window) 7) 8))))
+                 (fill-region (point) (point-max))
+                 (goto-char (point-max))
+                 ;; XEmacs version of `fill-region' inserts newline.
+                 (unless (bolp)
+                   (insert "\n"))))
+             (when (or link enclosure)
+               (insert "\n")))
+           (when link
+             (insert link "\n"))
+           (when enclosure
+             (insert (car enclosure) " "
+                     (nth 2 enclosure) " "
+                     (nth 3 enclosure) "\n"))
+           (when comments
+             (insert comments "\n"))
+           (setq body (buffer-substring body (point)))
+           (insert "<#/part>\n"
+                   "<#part type=\"text/html\">\n"
+                   "<html><head></head><body>\n")
+           (when text
+             (insert text "\n"))
+           (when link
+             (insert "<p><a href=\"" link "\">link</a></p>\n"))
+           (when enclosure
+             (insert "<p><a href=\"" (car enclosure) "\">"
+                     (cadr enclosure) "</a> " (nth 2 enclosure)
+                     " " (nth 3 enclosure) "</p>\n"))
+           (when comments
+             (insert "<p><a href=\"" comments "\">comments</a></p>\n"))
+           (insert "</body></html>\n"
+                   "<#/part>\n"
+                   "<#/multipart>\n"))
+         (condition-case nil
+             ;; Allow `mml-to-mime' to generate MIME article without
+             ;; making inquiry to a user for unknown encoding.
+             (let ((mml-confirmation-set
+                    (cons 'unknown-encoding mml-confirmation-set)))
+               (mml-to-mime))
+           (error
+            (erase-buffer)
+            (insert header
+                    "Content-Type: text/plain; charset=gnus-decoded\n"
+                    "Content-Transfer-Encoding: 8bit\n\n"
+                    body)
+            (nnheader-message
+             3 "Warning - there might be invalid characters"))))
+       (goto-char (point-min))
+       (search-forward "\n\n")
+       (forward-line -1)
+       (insert (format "Message-ID: <%d@%s.nnrss>\n"
+                       (car e)
+                       (let ((rfc2047-encoding-type 'mime)
+                             rfc2047-encode-max-chars)
+                         (rfc2047-encode-string
+                          (gnus-replace-in-string group "[\t\n ]+" "_")))))
+       (when nnrss-content-function
+         (funcall nnrss-content-function e group article))))
+    (cond
+     (err
+      (nnheader-report 'nnrss err))
+     ((not e)
+      (nnheader-report 'nnrss "no such id: %d" article))
+     (t
+      (nnheader-report 'nnrss "article %s retrieved" (car e))
+      ;; we return the article number.
+      (cons nnrss-group (car e))))))
+
+(deffoo nnrss-open-server (server &optional defs connectionless)
+  (nnrss-read-server-data server)
+  (nnoo-change-server 'nnrss server defs)
+  t)
+
+(deffoo nnrss-request-expire-articles
+    (articles group &optional server force)
+  (setq group (nnrss-decode-group-name group))
+  (nnrss-possibly-change-group group server)
+  (let (e days not-expirable changed)
+    (dolist (art articles)
+      (if (and (setq e (assq art nnrss-group-data))
+              (nnmail-expired-article-p
+               group
+               (if (listp (setq days (nth 1 e))) days
+                 (days-to-time (- days (time-to-days '(0 0)))))
+               force))
+         (setq nnrss-group-data (delq e nnrss-group-data)
+               changed t)
+       (push art not-expirable)))
+    (if changed
+       (nnrss-save-group-data group server))
+    not-expirable))
+
+(deffoo nnrss-request-delete-group (group &optional force server)
+  (setq group (nnrss-decode-group-name group))
+  (nnrss-possibly-change-group group server)
+  (let (elem)
+    ;; There may be two or more entries in `nnrss-group-alist' since
+    ;; this function didn't delete them formerly.
+    (while (setq elem (assoc group nnrss-group-alist))
+      (setq nnrss-group-alist (delq elem nnrss-group-alist))))
+  (setq nnrss-server-data
+       (delq (assoc group nnrss-server-data) nnrss-server-data))
+  (nnrss-save-server-data server)
+  (ignore-errors
+    (let ((file-name-coding-system nnmail-pathname-coding-system))
+      (delete-file (nnrss-make-filename group server))))
+  t)
+
+(deffoo nnrss-request-list-newsgroups (&optional server)
+  (nnrss-possibly-change-group nil server)
+  (with-current-buffer nntp-server-buffer
+    (erase-buffer)
+    (dolist (elem nnrss-group-alist)
+      (if (third elem)
+         (insert (car elem) "\t" (third elem) "\n"))))
+  t)
+
+(deffoo nnrss-retrieve-groups (groups &optional server)
+  (dolist (group groups)
+    (setq group (nnrss-decode-group-name group))
+    (nnrss-possibly-change-group group server)
+    (nnrss-check-group group server))
+  (with-current-buffer nntp-server-buffer
+    (erase-buffer)
+    (dolist (group groups)
+      (let ((elem (assoc (gnus-group-decoded-name group) nnrss-server-data)))
+       (insert (format "%S %s 1 y\n" group (or (cadr elem) 0)))))
+    'active))
+
+(nnoo-define-skeleton nnrss)
+
+;;; Internal functions
+(eval-when-compile (defun xml-rpc-method-call (&rest args)))
+
+(defun nnrss-get-encoding ()
+  "Return an encoding attribute specified in the current xml contents.
+If `nnrss-compatible-encoding-alist' specifies the compatible encoding,
+it is used instead.  If the xml contents doesn't specify the encoding,
+return `utf-8' which is the default encoding for xml if it is available,
+otherwise return nil."
+  (goto-char (point-min))
+  (if (re-search-forward
+       "<\\?[^>]*encoding=\\(?:\"\\([^\">]+\\)\"\\|'\\([^'>]+\\)'\\)"
+       nil t)
+      (let ((encoding (intern (downcase (or (match-string 1)
+                                           (match-string 2))))))
+       (or
+        (mm-coding-system-p (cdr (assq encoding
+                                       nnrss-compatible-encoding-alist)))
+        (mm-coding-system-p encoding)
+        (mm-coding-system-p (car (rassq encoding
+                                        nnrss-compatible-encoding-alist)))))
+    (mm-coding-system-p 'utf-8)))
+
+(declare-function libxml-parse-html-region "xml.c"
+                 (start end &optional base-url discard-comments))
+(defun nnrss-fetch (url &optional local)
+  "Fetch URL and put it in a the expected Lisp structure."
+  (mm-with-unibyte-buffer
+    ;;some versions of url.el need this to close the connection quickly
+    (let (cs xmlform htmlform)
+      ;; bit o' work necessary for w3 pre-cvs and post-cvs
+      (if local
+         (let ((coding-system-for-read 'binary))
+           (insert-file-contents url))
+       ;; FIXME: shouldn't binding `coding-system-for-read' be moved
+       ;; to `mm-url-insert'?
+       (let ((coding-system-for-read 'binary))
+         (condition-case err
+             (mm-url-insert url)
+           (error (if (or debug-on-quit debug-on-error)
+                      (signal (car err) (cdr err))
+                    (message "nnrss: Failed to fetch %s" url))))))
+      (nnheader-remove-cr-followed-by-lf)
+      ;; Decode text according to the encoding attribute.
+      (when (setq cs (nnrss-get-encoding))
+       (insert (prog1
+                   (mm-decode-coding-string (buffer-string) cs)
+                 (erase-buffer)
+                 (mm-enable-multibyte))))
+      (goto-char (point-min))
+
+      (condition-case err1
+         (setq xmlform (xml-parse-region (point-min) (point-max)))
+       (error
+        (condition-case err2
+            (setq htmlform (libxml-parse-html-region (point-min) (point-max)))
+          (error
+           (message "\
+nnrss: %s: Not valid XML %s and libxml-parse-html-region doesn't work %s"
+                    url err1 err2)))))
+      (if htmlform
+         htmlform
+       xmlform))))
+
+(defun nnrss-possibly-change-group (&optional group server)
+  (when (and server
+            (not (nnrss-server-opened server)))
+    (nnrss-open-server server))
+  (when (and group (not (equal group nnrss-group)))
+    (nnrss-read-group-data group server)
+    (setq nnrss-group group)))
+
+(autoload 'timezone-parse-date "timezone")
+
+(defun nnrss-normalize-date (date)
+  "Return a date string of DATE in the RFC822 style.
+This function handles the ISO 8601 date format described in
+URL `http://www.w3.org/TR/NOTE-datetime', and also the RFC822 style
+which RSS 2.0 allows."
+  (let (case-fold-search vector year month day time zone cts given)
+    (cond ((null date))                        ; do nothing for this case
+         ;; if the date is just digits (unix time stamp):
+         ((string-match "^[0-9]+$" date)
+          (setq given (seconds-to-time (string-to-number date))))
+         ;; RFC822
+         ((string-match " [0-9]+ " date)
+          (setq vector (timezone-parse-date date)
+                year (string-to-number (aref vector 0)))
+          (when (>= year 1969)
+            (setq month (string-to-number (aref vector 1))
+                  day (string-to-number (aref vector 2)))
+            (unless (>= (length (setq time (aref vector 3))) 3)
+              (setq time "00:00:00"))
+            (when (and (setq zone (aref vector 4))
+                       (not (string-match "\\`[A-Z+-]" zone)))
+              (setq zone nil))))
+         ;; ISO 8601
+         ((string-match
+           (eval-when-compile
+             (concat
+              ;; 1. year
+              "\\(199[0-9]\\|20[0-9][0-9]\\)"
+              "\\(?:-"
+              ;; 2. month
+              "\\([01][0-9]\\)"
+              "\\(?:-"
+              ;; 3. day
+              "\\([0-3][0-9]\\)"
+              "\\)?\\)?\\(?:T"
+              ;; 4. hh:mm
+              "\\([012][0-9]:[0-5][0-9]\\)"
+              "\\(?:"
+              ;; 5. :ss
+              "\\(:[0-5][0-9]\\)"
+              "\\(?:\\.[0-9]+\\)?\\)?\\)?"
+              ;; 6+7,8,9. zone
+              "\\(?:\\(?:\\([+-][012][0-9]\\):\\([0-5][0-9]\\)\\)"
+              "\\|\\([+-][012][0-9][0-5][0-9]\\)"
+              "\\|\\(Z\\)\\)?"))
+           date)
+          (setq year (string-to-number (match-string 1 date))
+                month (string-to-number (or (match-string 2 date) "1"))
+                day (string-to-number (or (match-string 3 date) "1"))
+                time (if (match-beginning 5)
+                         (substring date (match-beginning 4) (match-end 5))
+                       (concat (or (match-string 4 date) "00:00") ":00"))
+                zone (cond ((match-beginning 6)
+                            (concat (match-string 6 date)
+                                    (match-string 7 date)))
+                           ((match-beginning 9) ;; Z
+                            "+0000")
+                           (t ;; nil if zone is not provided.
+                            (match-string 8 date))))))
+    (if month
+       (progn
+         (setq cts (current-time-string (encode-time 0 0 0 day month year)))
+         (format "%s, %02d %s %04d %s%s"
+                 (substring cts 0 3) day (substring cts 4 7) year time
+                 (if zone
+                     (concat " " zone)
+                   "")))
+      (message-make-date given))))
+
+;;; data functions
+
+(defun nnrss-read-server-data (server)
+  (setq nnrss-server-data nil)
+  (let ((file (nnrss-make-filename "nnrss" server))
+       (file-name-coding-system nnmail-pathname-coding-system))
+    (when (file-exists-p file)
+      (load file nil t t))))
+
+(defun nnrss-save-server-data (server)
+  (gnus-make-directory nnrss-directory)
+  (let ((coding-system-for-write nnrss-file-coding-system)
+       (file-name-coding-system nnmail-pathname-coding-system))
+    (with-temp-file (nnrss-make-filename "nnrss" server)
+      (insert (format ";; -*- coding: %s; -*-\n"
+                     nnrss-file-coding-system))
+      (gnus-prin1 `(setq nnrss-group-alist ',nnrss-group-alist))
+      (insert "\n")
+      (gnus-prin1 `(setq nnrss-server-data ',nnrss-server-data)))))
+
+(defun nnrss-read-group-data (group server)
+  (setq nnrss-group-data nil)
+  (if (hash-table-p nnrss-group-hashtb)
+      (clrhash nnrss-group-hashtb)
+    (setq nnrss-group-hashtb (make-hash-table :test 'equal)))
+  (let ((pair (assoc group nnrss-server-data)))
+    (setq nnrss-group-max (or (cadr pair) 0))
+    (setq nnrss-group-min (+ nnrss-group-max 1)))
+  (let ((file (nnrss-make-filename group server))
+       (file-name-coding-system nnmail-pathname-coding-system))
+    (when (file-exists-p file)
+      (load file nil t t)
+      (dolist (e nnrss-group-data)
+       (puthash (nth 9 e) t nnrss-group-hashtb)
+       (when (and (car e) (> nnrss-group-min (car e)))
+         (setq nnrss-group-min (car e)))
+       (when (and (car e) (< nnrss-group-max (car e)))
+         (setq nnrss-group-max (car e)))))))
+
+(defun nnrss-save-group-data (group server)
+  (gnus-make-directory nnrss-directory)
+  (let ((coding-system-for-write nnrss-file-coding-system)
+       (file-name-coding-system nnmail-pathname-coding-system))
+    (with-temp-file (nnrss-make-filename group server)
+      (insert (format ";; -*- coding: %s; -*-\n"
+                     nnrss-file-coding-system))
+      (gnus-prin1 `(setq nnrss-group-data ',nnrss-group-data)))))
+
+(defun nnrss-make-filename (name server)
+  (expand-file-name
+   (nnrss-translate-file-chars
+    (concat name
+           (and server
+                (not (equal server ""))
+                "-")
+           server
+           ".el"))
+   nnrss-directory))
+
+(gnus-add-shutdown 'nnrss-close 'gnus)
+
+(defun nnrss-close ()
+  "Clear internal nnrss variables."
+  (setq nnrss-group-data nil
+       nnrss-server-data nil
+       nnrss-group-hashtb nil
+       nnrss-group-alist nil))
+
+;;; URL interface
+
+(defun nnrss-no-cache (url)
+  "")
+
+(defun nnrss-insert (url)
+  (mm-with-unibyte-current-buffer
+    (condition-case err
+       (mm-url-insert url)
+      (error (if (or debug-on-quit debug-on-error)
+                (signal (car err) (cdr err))
+              (message "nnrss: Failed to fetch %s" url))))))
+
+(defun nnrss-decode-entities-string (string)
+  (if string
+      (mm-with-multibyte-buffer
+       (insert string)
+       (mm-url-decode-entities-nbsp)
+       (buffer-string))))
+
+(defun nnrss-mime-encode-string (string)
+  (mm-with-multibyte-buffer
+    (insert string)
+    (mm-url-decode-entities-nbsp)
+    (goto-char (point-min))
+    (while (re-search-forward "[\t\n ]+" nil t)
+      (replace-match " "))
+    (goto-char (point-min))
+    (skip-chars-forward " ")
+    (delete-region (point-min) (point))
+    (goto-char (point-max))
+    (skip-chars-forward " ")
+    (delete-region (point) (point-max))
+    (let ((rfc2047-encoding-type 'mime)
+         rfc2047-encode-max-chars)
+      (rfc2047-encode-region (point-min) (point-max)))
+    (goto-char (point-min))
+    (while (search-forward "\n" nil t)
+      (delete-char -1))
+    (buffer-string)))
+
+;;; Snarf functions
+(defun nnrss-make-hash-index (item)
+  (gnus-message 9 "nnrss: Making hash index of %s" (gnus-prin1-to-string item))
+  (setq item (gnus-remove-if
+             (lambda (field)
+               (when (listp field)
+                 (memq (car field) nnrss-ignore-article-fields)))
+             item))
+  (md5 (gnus-prin1-to-string item)
+       nil nil
+       nnrss-file-coding-system))
+
+(defun nnrss-check-group (group server)
+  (let (file xml subject url extra changed author date feed-subject
+            enclosure comments rss-ns rdf-ns content-ns dc-ns
+            hash-index)
+    (if (and nnrss-use-local
+            (file-exists-p (setq file (expand-file-name
+                                       (nnrss-translate-file-chars
+                                        (concat group ".xml"))
+                                       nnrss-directory))))
+       (setq xml (nnrss-fetch file t))
+      (setq url (or (nth 2 (assoc group nnrss-server-data))
+                   (second (assoc group nnrss-group-alist))))
+      (unless url
+       (setq url
+             (cdr
+              (assoc 'href
+                     (nnrss-discover-feed
+                      (read-string
+                       (format "URL to search for %s: " group) "http://")))))
+       (let ((pair (assoc group nnrss-server-data)))
+         (if pair
+             (setcdr (cdr pair) (list url))
+           (push (list group nnrss-group-max url) nnrss-server-data)))
+       (setq changed t))
+      (setq xml (nnrss-fetch url)))
+    (setq dc-ns (nnrss-get-namespace-prefix xml "http://purl.org/dc/elements/1.1/")
+         rdf-ns (nnrss-get-namespace-prefix xml "http://www.w3.org/1999/02/22-rdf-syntax-ns#")
+         rss-ns (nnrss-get-namespace-prefix xml "http://purl.org/rss/1.0/")
+         content-ns (nnrss-get-namespace-prefix xml "http://purl.org/rss/1.0/modules/content/"))
+    (dolist (item (nreverse (nnrss-find-el (intern (concat rss-ns "item")) xml)))
+      (when (and (listp item)
+                (string= (concat rss-ns "item") (car item))
+                (progn (setq hash-index (nnrss-make-hash-index item))
+                       (not (gethash hash-index nnrss-group-hashtb))))
+       (setq subject (nnrss-node-text rss-ns 'title item))
+       (setq url (nnrss-decode-entities-string
+                  (nnrss-node-text rss-ns 'link (cddr item))))
+       (setq extra (or (nnrss-node-text content-ns 'encoded item)
+                       (nnrss-node-text rss-ns 'description item)))
+       (if (setq feed-subject (nnrss-node-text dc-ns 'subject item))
+           (setq extra (concat feed-subject "<br /><br />" extra)))
+       (setq author (or (nnrss-node-text rss-ns 'author item)
+                        (nnrss-node-text dc-ns 'creator item)
+                        (nnrss-node-text dc-ns 'contributor item)))
+       (setq date (nnrss-normalize-date
+                   (or (nnrss-node-text dc-ns 'date item)
+                       (nnrss-node-text rss-ns 'pubDate item))))
+       (setq comments (nnrss-node-text rss-ns 'comments item))
+       (when (setq enclosure (cadr (assq (intern (concat rss-ns "enclosure")) item)))
+         (let ((url (cdr (assq 'url enclosure)))
+               (len (cdr (assq 'length enclosure)))
+               (type (cdr (assq 'type enclosure)))
+               (name))
+           (setq len
+                 (if (and len (integerp (setq len (string-to-number len))))
+                     ;; actually already in `ls-lisp-format-file-size' but
+                     ;; probably not worth to require it for one function
+                     (do ((size (/ len 1.0) (/ size 1024.0))
+                          (post-fixes (list "" "k" "M" "G" "T" "P" "E")
+                                      (cdr post-fixes)))
+                         ((< size 1024)
+                          (format "%.1f%s" size (car post-fixes))))
+                   "0"))
+           (setq url (or url ""))
+           (setq name (if (string-match "/\\([^/]*\\)$" url)
+                          (match-string 1 url)
+                        "file"))
+           (setq type (or type ""))
+           (setq enclosure (list url name len type))))
+       (push
+        (list
+         (incf nnrss-group-max)
+         (current-time)
+         url
+         (and subject (nnrss-mime-encode-string subject))
+         (and author (nnrss-mime-encode-string author))
+         date
+         (and extra (nnrss-decode-entities-string extra))
+         enclosure
+         comments
+         hash-index)
+        nnrss-group-data)
+       (puthash hash-index t nnrss-group-hashtb)
+       (setq changed t))
+      (setq extra nil))
+    (when changed
+      (nnrss-save-group-data group server)
+      (let ((pair (assoc group nnrss-server-data)))
+       (if pair
+           (setcar (cdr pair) nnrss-group-max)
+         (push (list group nnrss-group-max) nnrss-server-data)))
+      (nnrss-save-server-data server))))
+
+(declare-function gnus-group-make-rss-group "gnus-group" (&optional url))
+
+(defun nnrss-opml-import (opml-file)
+  "OPML subscriptions import.
+Read the file and attempt to subscribe to each Feed in the file."
+  (interactive "fImport file: ")
+  (mapc
+   (lambda (node)
+     (let ((xmlurl (cdr (assq 'xmlUrl (cadr node)))))
+       (when (and xmlurl
+                 (not (string-match "\\`[\t ]*\\'" xmlurl))
+                 (prog1
+                     (y-or-n-p (format "Subscribe to %s " xmlurl))
+                   (message "")))
+        (condition-case err
+            (progn
+              (gnus-group-make-rss-group xmlurl)
+              (forward-line 1))
+          (error
+           (message
+            "Failed to subscribe to %s (%s); type any key to continue: "
+            xmlurl
+            (error-message-string err))
+           (let ((echo-keystrokes 0))
+             (read-char)))))))
+   (nnrss-find-el 'outline
+                 (mm-with-multibyte-buffer
+                   (insert-file-contents opml-file)
+                   (xml-parse-region (point-min) (point-max))))))
+
+(defun nnrss-opml-export ()
+  "OPML subscription export.
+Export subscriptions to a buffer in OPML Format."
+  (interactive)
+  (with-current-buffer (get-buffer-create "*OPML Export*")
+    (mm-set-buffer-file-coding-system 'utf-8)
+    (insert "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+           "<!-- OPML generated by Emacs Gnus' nnrss.el -->\n"
+           "<opml version=\"1.1\">\n"
+           "  <head>\n"
+           "    <title>mySubscriptions</title>\n"
+           "    <dateCreated>" (format-time-string "%a, %d %b %Y %T %z")
+           "</dateCreated>\n"
+           "    <ownerEmail>" user-mail-address "</ownerEmail>\n"
+           "    <ownerName>" (user-full-name) "</ownerName>\n"
+           "  </head>\n"
+           "  <body>\n")
+    (dolist (sub nnrss-group-alist)
+      (insert "    <outline text=\"" (car sub)
+             "\" xmlUrl=\"" (cadr sub) "\"/>\n"))
+    (insert "  </body>\n"
+           "</opml>\n"))
+  (pop-to-buffer "*OPML Export*")
+  (when (fboundp 'sgml-mode)
+    (sgml-mode)))
+
+(defun nnrss-generate-download-script ()
+  "Generate a download script in the current buffer.
+It is useful when `(setq nnrss-use-local t)'."
+  (interactive)
+  (insert "#!/bin/sh\n")
+  (insert "WGET=wget\n")
+  (insert "RSSDIR='" (expand-file-name nnrss-directory) "'\n")
+  (dolist (elem nnrss-server-data)
+    (let ((url (or (nth 2 elem)
+                  (second (assoc (car elem) nnrss-group-alist)))))
+      (insert "$WGET -q -O \"$RSSDIR\"/'"
+             (nnrss-translate-file-chars (concat (car elem) ".xml"))
+             "' '" url "'\n"))))
+
+(defun nnrss-translate-file-chars (name)
+  (let ((nnheader-file-name-translation-alist
+        (append nnheader-file-name-translation-alist '((?' . ?_)))))
+    (nnheader-translate-file-chars name)))
+
+(defun nnrss-node-text (namespace local-name element)
+  (let* ((node (assq (intern (concat namespace (symbol-name local-name)))
+                    element))
+        (text (if (and node (listp node))
+                  (nnrss-node-just-text node)
+                node))
+        (cleaned-text (if text
+                          (gnus-replace-in-string
+                           (gnus-replace-in-string
+                            text "^[\000-\037\177]+\\|^ +\\| +$" "")
+                           "\r\n" "\n"))))
+    (if (string-equal "" cleaned-text)
+       nil
+      cleaned-text)))
+
+(defun nnrss-node-just-text (node)
+  (if (and node (listp node))
+      (mapconcat 'nnrss-node-just-text (cddr node) " ")
+    node))
+
+(defun nnrss-find-el (tag data &optional found-list)
+  "Find the all matching elements in the data.
+Careful with this on large documents!"
+  (when (consp data)
+    (dolist (bit data)
+      (when (car-safe bit)
+       (when (equal tag (car bit))
+         ;; Old xml.el may return a list of string.
+         (when (and (consp (caddr bit))
+                    (stringp (caaddr bit)))
+           (setcar (cddr bit) (caaddr bit)))
+         (setq found-list
+               (append found-list
+                       (list bit))))
+       (if (and (consp (car-safe (caddr bit)))
+                (not (stringp (caddr bit))))
+           (setq found-list
+                 (append found-list
+                         (nnrss-find-el
+                          tag (caddr bit))))
+         (setq found-list
+               (append found-list
+                       (nnrss-find-el
+                        tag (cddr bit))))))))
+  found-list)
+
+(defun nnrss-rsslink-p (el)
+  "Test if the element we are handed is an RSS autodiscovery link."
+  (and (eq (car-safe el) 'link)
+       (string-equal (cdr (assoc 'rel (cadr el))) "alternate")
+       (or (string-equal (cdr (assoc 'type (cadr el)))
+                        "application/rss+xml")
+          (string-equal (cdr (assoc 'type (cadr el))) "text/xml"))))
+
+(defun nnrss-get-rsslinks (data)
+  "Extract the <link> elements that are links to RSS from the parsed data."
+  (delq nil (mapcar
+            (lambda (el)
+              (if (nnrss-rsslink-p el) el))
+            (nnrss-find-el 'link data))))
+
+(defun nnrss-extract-hrefs (data)
+  "Recursively extract hrefs from a page's source.
+DATA should be the output of `xml-parse-region'."
+  (mapcar (lambda (ahref)
+           (cdr (assoc 'href (cadr ahref))))
+         (nnrss-find-el 'a data)))
+
+(defmacro nnrss-match-macro (base-uri item onsite-list offsite-list)
+  `(cond ((or (string-match (concat "^" ,base-uri) ,item)
+             (not (string-match "://" ,item)))
+         (setq ,onsite-list (append ,onsite-list (list ,item))))
+        (t (setq ,offsite-list (append ,offsite-list (list ,item))))))
+
+(defun nnrss-order-hrefs (base-uri hrefs)
+  "Given a list of hrefs, sort them using the following priorities:
+  1. links ending in .rss
+  2. links ending in .rdf
+  3. links ending in .xml
+  4. links containing the above
+  5. offsite links
+
+BASE-URI is used to determine the location of the links and
+whether they are `offsite' or `onsite'."
+  (let (rss-onsite-end  rdf-onsite-end  xml-onsite-end
+       rss-onsite-in   rdf-onsite-in   xml-onsite-in
+       rss-offsite-end rdf-offsite-end xml-offsite-end
+       rss-offsite-in rdf-offsite-in xml-offsite-in)
+    (dolist (href hrefs)
+      (cond ((null href))
+           ((string-match "\\.rss$" href)
+            (nnrss-match-macro
+             base-uri href rss-onsite-end rss-offsite-end))
+           ((string-match "\\.rdf$" href)
+            (nnrss-match-macro
+             base-uri href rdf-onsite-end rdf-offsite-end))
+           ((string-match "\\.xml$" href)
+            (nnrss-match-macro
+             base-uri href xml-onsite-end xml-offsite-end))
+           ((string-match "rss" href)
+            (nnrss-match-macro
+             base-uri href rss-onsite-in rss-offsite-in))
+           ((string-match "rdf" href)
+            (nnrss-match-macro
+             base-uri href rdf-onsite-in rdf-offsite-in))
+           ((string-match "xml" href)
+            (nnrss-match-macro
+             base-uri href xml-onsite-in xml-offsite-in))))
+    (append
+     rss-onsite-end  rdf-onsite-end  xml-onsite-end
+     rss-onsite-in   rdf-onsite-in   xml-onsite-in
+     rss-offsite-end rdf-offsite-end xml-offsite-end
+     rss-offsite-in rdf-offsite-in xml-offsite-in)))
+
+(defun nnrss-discover-feed (url)
+  "Given a page, find an RSS feed.
+Use Mark Pilgrim's `ultra-liberal rss locator'."
+  (let ((parsed-page (nnrss-fetch url)))
+    ;;    1. if this url is the rss, use it.
+    (if (nnrss-rss-p parsed-page)
+       (let ((rss-ns (nnrss-get-namespace-prefix parsed-page "http://purl.org/rss/1.0/")))
+         (nnrss-rss-title-description rss-ns parsed-page url))
+
+      ;;    2. look for the <link rel="alternate"
+      ;;    type="application/rss+xml" and use that if it is there.
+      (let ((links (nnrss-get-rsslinks parsed-page)))
+       (if links
+           (let* ((xml (nnrss-fetch
+                        (cdr (assoc 'href (cadar links)))))
+                  (rss-ns (nnrss-get-namespace-prefix
+                           xml "http://purl.org/rss/1.0/")))
+             (nnrss-rss-title-description
+              rss-ns xml (cdr (assoc 'href (cadar links)))))
+
+         ;;    3. look for links on the site in the following order:
+         ;;       - onsite links ending in .rss, .rdf, or .xml
+         ;;       - onsite links containing any of the above
+         ;;       - offsite links ending in .rss, .rdf, or .xml
+         ;;       - offsite links containing any of the above
+         (let* ((base-uri (progn (string-match ".*://[^/]+/?" url)
+                                 (match-string 0 url)))
+                (hrefs (nnrss-order-hrefs
+                        base-uri (nnrss-extract-hrefs parsed-page)))
+                (rss-link nil))
+           (while (and (eq rss-link nil) (not (eq hrefs nil)))
+             (let ((href-data (nnrss-fetch (car hrefs))))
+               (if (nnrss-rss-p href-data)
+                   (let* ((rss-ns (nnrss-get-namespace-prefix href-data "http://purl.org/rss/1.0/")))
+                     (setq rss-link (nnrss-rss-title-description
+                                     rss-ns href-data (car hrefs))))
+                 (setq hrefs (cdr hrefs)))))
+           (if rss-link
+               rss-link
+             ;;    4. check syndic8
+             (nnrss-find-rss-via-syndic8 url))))))))
+
+(defun nnrss-find-rss-via-syndic8 (url)
+  "Query syndic8 for the rss feeds it has for URL."
+  (if (not (locate-library "xml-rpc"))
+      (progn
+       (message "XML-RPC is not available... not checking Syndic8.")
+       nil)
+    (require 'xml-rpc)
+    (let ((feedid (xml-rpc-method-call
+                  "http://www.syndic8.com/xmlrpc.php"
+                  'syndic8.FindSites
+                  url)))
+      (when feedid
+       (let* ((feedinfo (xml-rpc-method-call
+                         "http://www.syndic8.com/xmlrpc.php"
+                         'syndic8.GetFeedInfo
+                         feedid))
+              (urllist
+               (delq nil
+                     (mapcar
+                      (lambda (listinfo)
+                        (if (string-equal
+                             (cdr (assoc "status" listinfo))
+                             "Syndicated")
+                            (cons
+                             (cdr (assoc "sitename" listinfo))
+                             (list
+                              (cons 'title
+                                    (cdr (assoc
+                                          "sitename" listinfo)))
+                              (cons 'href
+                                    (cdr (assoc
+                                          "dataurl" listinfo)))))))
+                      feedinfo))))
+         (if (not (> (length urllist) 1))
+             (cdar urllist)
+           (let ((completion-ignore-case t)
+                 (selection
+                  (mapcar (lambda (listinfo)
+                            (cons (cdr (assoc "sitename" listinfo))
+                                  (string-to-number
+                                   (cdr (assoc "feedid" listinfo)))))
+                          feedinfo)))
+             (cdr (assoc
+                   (gnus-completing-read
+                    "Multiple feeds found. Select one"
+                    selection t) urllist)))))))))
+
+(defun nnrss-rss-p (data)
+  "Test if DATA is an RSS feed.
+Simply ensures that the first element is rss or rdf."
+  (or (eq (caar data) 'rss)
+      (eq (caar data) 'rdf:RDF)))
+
+(defun nnrss-rss-title-description (rss-namespace data url)
+  "Return the title of an RSS feed."
+  (if (nnrss-rss-p data)
+      (let ((description (intern (concat rss-namespace "description")))
+           (title (intern (concat rss-namespace "title")))
+           (channel (nnrss-find-el (intern (concat rss-namespace "channel"))
+                                   data)))
+       (list
+        (cons 'description (caddr (nth 0 (nnrss-find-el description channel))))
+        (cons 'title (caddr (nth 0 (nnrss-find-el title channel))))
+        (cons 'href url)))))
+
+(defun nnrss-get-namespace-prefix (el uri)
+  "Given EL (containing a parsed element) and URI (containing a string
+that gives the URI for which you want to retrieve the namespace
+prefix), return the prefix."
+  (let* ((prefix (car (rassoc uri (cadar el))))
+        (nslist (if prefix
+                    (split-string (symbol-name prefix) ":")))
+        (ns (cond ((eq (length nslist) 1) ; no prefix given
+                   "")
+                  ((eq (length nslist) 2) ; extract prefix
+                   (cadr nslist)))))
+    (if (and ns (not (string= ns "")))
+       (concat ns ":")
+      ns)))
+
+(provide 'nnrss)
+
+;;; nnrss.el ends here
diff --git a/xemacs-packages/gnus/lisp/nnspool.el b/xemacs-packages/gnus/lisp/nnspool.el
new file mode 100644 (file)
index 0000000..620b8ac
--- /dev/null
@@ -0,0 +1,476 @@
+;;; nnspool.el --- spool access for GNU Emacs
+
+;; Copyright (C) 1988-1990, 1993-1998, 2000-2016 Free Software
+;; Foundation, Inc.
+
+;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
+;;     Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'nnheader)
+(require 'nntp)
+(require 'nnoo)
+(eval-when-compile (require 'cl))
+
+;; Probably this entire thing should be obsolete.
+;; It's only used to init nnspool-spool-directory, so why not just
+;; set that variable's default directly?
+(eval-and-compile
+  (defvar news-directory (if (file-exists-p "/usr/spool/news/")
+                            "/usr/spool/news/"
+                          "/var/spool/news/")
+    "The root directory below which all news files are stored.")
+  (defvaralias 'news-path 'news-directory))
+
+;; Ditto re obsolescence.
+(defvar news-inews-program
+  (cond ((file-exists-p "/usr/bin/inews") "/usr/bin/inews")
+       ((file-exists-p "/usr/local/inews") "/usr/local/inews")
+       ((file-exists-p "/usr/local/bin/inews") "/usr/local/bin/inews")
+       ((file-exists-p "/usr/contrib/lib/news/inews") "/usr/contrib/lib/news/inews")
+       ((file-exists-p "/usr/lib/news/inews") "/usr/lib/news/inews")
+       (t "inews"))
+  "Program to post news.")
+
+(nnoo-declare nnspool)
+
+(defvoo nnspool-inews-program news-inews-program
+  "Program to post news.
+This is most commonly `inews' or `injnews'.")
+
+(defvoo nnspool-inews-switches '("-h" "-S")
+  "Switches for nnspool-request-post to pass to `inews' for posting news.
+If you are using Cnews, you probably should set this variable to nil.")
+
+(defvoo nnspool-spool-directory
+    (file-name-as-directory (if (boundp 'news-directory)
+                               (symbol-value 'news-directory)
+                             news-path))
+  "Local news spool directory.")
+
+(defvoo nnspool-nov-directory (concat nnspool-spool-directory "over.view/")
+  "Local news nov directory.")
+
+(defvoo nnspool-lib-dir
+    (if (file-exists-p "/usr/lib/news/active")
+       "/usr/lib/news/"
+      "/var/lib/news/")
+  "Where the local news library files are stored.")
+
+(defvoo nnspool-active-file (concat nnspool-lib-dir "active")
+  "Local news active file.")
+
+(defvoo nnspool-newsgroups-file (concat nnspool-lib-dir "newsgroups")
+  "Local news newsgroups file.")
+
+(defvoo nnspool-distributions-file (concat nnspool-lib-dir "distribs.pat")
+  "Local news distributions file.")
+
+(defvoo nnspool-history-file (concat nnspool-lib-dir "history")
+  "Local news history file.")
+
+(defvoo nnspool-active-times-file (concat nnspool-lib-dir "active.times")
+  "Local news active date file.")
+
+(defvoo nnspool-large-newsgroup 50
+  "The number of articles which indicates a large newsgroup.
+If the number of articles is greater than the value, verbose
+messages will be shown to indicate the current status.")
+
+(defvoo nnspool-nov-is-evil nil
+  "Non-nil means that nnspool will never return NOV lines instead of headers.")
+
+(defconst nnspool-sift-nov-with-sed nil
+  "If non-nil, use sed to get the relevant portion from the overview file.
+If nil, nnspool will load the entire file into a buffer and process it
+there.")
+
+(defvoo nnspool-rejected-article-hook nil
+  "*A hook that will be run when an article has been rejected by the server.")
+
+(defvoo nnspool-file-coding-system nnheader-file-coding-system
+  "Coding system for nnspool.")
+
+\f
+
+(defconst nnspool-version "nnspool 2.0"
+  "Version numbers of this version of NNSPOOL.")
+
+(defvoo nnspool-current-directory nil
+  "Current news group directory.")
+
+(defvoo nnspool-current-group nil)
+(defvoo nnspool-status-string "")
+
+\f
+;;; Interface functions.
+
+(nnoo-define-basics nnspool)
+
+(deffoo nnspool-retrieve-headers (articles &optional group server fetch-old)
+  "Retrieve the headers of ARTICLES."
+  (with-current-buffer nntp-server-buffer
+    (erase-buffer)
+    (when (nnspool-possibly-change-directory group)
+      (let* ((number (length articles))
+            (count 0)
+            (default-directory nnspool-current-directory)
+            (do-message (and (numberp nnspool-large-newsgroup)
+                             (> number nnspool-large-newsgroup)))
+            (nnheader-file-coding-system nnspool-file-coding-system)
+            file beg article ag)
+       (if (and (numberp (car articles))
+                (nnspool-retrieve-headers-with-nov articles fetch-old))
+           ;; We successfully retrieved the NOV headers.
+           'nov
+         ;; No NOV headers here, so we do it the hard way.
+         (while (setq article (pop articles))
+           (if (stringp article)
+               ;; This is a Message-ID.
+               (setq ag (nnspool-find-id article)
+                     file (and ag (nnspool-article-pathname
+                                   (car ag) (cdr ag)))
+                     article (cdr ag))
+             ;; This is an article in the current group.
+             (setq file (int-to-string article)))
+           ;; Insert the head of the article.
+           (when (and file
+                      (file-exists-p file))
+             (insert "221 ")
+             (princ article (current-buffer))
+             (insert " Article retrieved.\n")
+             (setq beg (point))
+             (inline (nnheader-insert-head file))
+             (goto-char beg)
+             (if (search-forward "\n\n" nil t)
+                 (progn
+                   (forward-char -1)
+                   (insert ".\n"))
+               (goto-char (point-max))
+               (if (bolp)
+                   (insert ".\n")
+                 (insert "\n.\n")))
+             (delete-region (point) (point-max)))
+
+           (and do-message
+                (zerop (% (incf count) 20))
+                (nnheader-message 5 "nnspool: Receiving headers... %d%%"
+                                  (floor (* count 100.0) number))))
+
+         (when do-message
+           (nnheader-message 5 "nnspool: Receiving headers...done"))
+
+         ;; Fold continuation lines.
+         (nnheader-fold-continuation-lines)
+         'headers)))))
+
+(deffoo nnspool-open-server (server &optional defs)
+  (nnoo-change-server 'nnspool server defs)
+  (cond
+   ((not (file-exists-p nnspool-spool-directory))
+    (nnspool-close-server)
+    (nnheader-report 'nnspool "Spool directory doesn't exist: %s"
+                    nnspool-spool-directory))
+   ((not (file-directory-p
+         (directory-file-name
+          (file-truename nnspool-spool-directory))))
+    (nnspool-close-server)
+    (nnheader-report 'nnspool "Not a directory: %s" nnspool-spool-directory))
+   ((not (file-exists-p nnspool-active-file))
+    (nnheader-report 'nnspool "The active file doesn't exist: %s"
+                    nnspool-active-file))
+   (t
+    (nnheader-report 'nnspool "Opened server %s using directory %s"
+                    server nnspool-spool-directory)
+    t)))
+
+(deffoo nnspool-request-article (id &optional group server buffer)
+  "Select article by message ID (or number)."
+  (nnspool-possibly-change-directory group)
+  (let ((nntp-server-buffer (or buffer nntp-server-buffer))
+       file ag)
+    (if (stringp id)
+       ;; This is a Message-ID.
+       (when (setq ag (nnspool-find-id id))
+         (setq file (nnspool-article-pathname (car ag) (cdr ag))))
+      (setq file (nnspool-article-pathname nnspool-current-group id)))
+    (and file
+        (file-exists-p file)
+        (not (file-directory-p file))
+        (save-excursion (nnspool-find-file file))
+        ;; We return the article number and group name.
+        (if (numberp id)
+            (cons nnspool-current-group id)
+          ag))))
+
+(deffoo nnspool-request-body (id &optional group server)
+  "Select article body by message ID (or number)."
+  (nnspool-possibly-change-directory group)
+  (let ((res (nnspool-request-article id)))
+    (when res
+      (with-current-buffer nntp-server-buffer
+       (goto-char (point-min))
+       (when (search-forward "\n\n" nil t)
+         (delete-region (point-min) (point)))
+       res))))
+
+(deffoo nnspool-request-head (id &optional group server)
+  "Select article head by message ID (or number)."
+  (nnspool-possibly-change-directory group)
+  (let ((res (nnspool-request-article id)))
+    (when res
+      (with-current-buffer nntp-server-buffer
+       (goto-char (point-min))
+       (when (search-forward "\n\n" nil t)
+         (delete-region (1- (point)) (point-max)))
+       (nnheader-fold-continuation-lines)))
+    res))
+
+(deffoo nnspool-request-group (group &optional server dont-check info)
+  "Select news GROUP."
+  (let ((pathname (nnspool-article-pathname group))
+       dir)
+    (if (not (file-directory-p pathname))
+       (nnheader-report
+        'nnspool "Invalid group name (no such directory): %s" group)
+      (setq nnspool-current-directory pathname)
+      (nnheader-report 'nnspool "Selected group %s" group)
+      (if dont-check
+         (progn
+           (nnheader-report 'nnspool "Selected group %s" group)
+           t)
+       ;; Yes, completely empty spool directories *are* possible.
+       ;; Fix by Sudish Joseph <joseph@cis.ohio-state.edu>
+       (when (setq dir (directory-files pathname nil "^[0-9]+$" t))
+         (setq dir (sort (mapcar 'string-to-number dir) '<)))
+       (if dir
+           (nnheader-insert
+            "211 %d %d %d %s\n" (length dir) (car dir)
+            (car (last dir)) group)
+         (nnheader-report 'nnspool "Empty group %s" group)
+         (nnheader-insert "211 0 0 0 %s\n" group))))))
+
+(deffoo nnspool-request-type (group &optional article)
+  'news)
+
+(deffoo nnspool-close-group (group &optional server)
+  t)
+
+(deffoo nnspool-request-list (&optional server)
+  "List active newsgroups."
+  (save-excursion
+    (or (nnspool-find-file nnspool-active-file)
+       (nnheader-report 'nnspool (nnheader-file-error nnspool-active-file)))))
+
+(deffoo nnspool-request-list-newsgroups (&optional server)
+  "List newsgroups (defined in NNTP2)."
+  (save-excursion
+    (or (nnspool-find-file nnspool-newsgroups-file)
+       (nnheader-report 'nnspool (nnheader-file-error
+                                  nnspool-newsgroups-file)))))
+
+(deffoo nnspool-request-list-distributions (&optional server)
+  "List distributions (defined in NNTP2)."
+  (save-excursion
+    (or (nnspool-find-file nnspool-distributions-file)
+       (nnheader-report 'nnspool (nnheader-file-error
+                                  nnspool-distributions-file)))))
+
+;; Suggested by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>.
+(deffoo nnspool-request-newgroups (date &optional server)
+  "List groups created after DATE."
+  (if (nnspool-find-file nnspool-active-times-file)
+      (save-excursion
+       ;; Find the last valid line.
+       (goto-char (point-max))
+       (while (and (not (looking-at
+                         "\\([^ ]+\\) +\\([0-9]+\\)[0-9][0-9][0-9] "))
+                   (zerop (forward-line -1))))
+       ;; We require nnheader which requires gnus-util.
+       (let ((seconds (gnus-float-time (date-to-time date)))
+             groups)
+         ;; Go through lines and add the latest groups to a list.
+         (while (and (looking-at "\\([^ ]+\\) +[0-9]+ ")
+                     (progn
+                       ;; We insert a .0 to make the list reader
+                       ;; interpret the number as a float.  It is far
+                       ;; too big to be stored in a lisp integer.
+                       (goto-char (1- (match-end 0)))
+                       (insert ".0")
+                       (> (progn
+                            (goto-char (match-end 1))
+                            (read (current-buffer)))
+                          seconds))
+                     (push (buffer-substring
+                            (match-beginning 1) (match-end 1))
+                           groups)
+                     (zerop (forward-line -1))))
+         (erase-buffer)
+         (dolist (group groups)
+           (insert group " 0 0 y\n")))
+       t)
+    nil))
+
+(deffoo nnspool-request-post (&optional server)
+  "Post a new news in current buffer."
+  (save-excursion
+    (let* ((process-connection-type nil) ; t bugs out on Solaris
+          (inews-buffer (generate-new-buffer " *nnspool post*"))
+          (proc
+           (condition-case err
+               (apply 'start-process "*nnspool inews*" inews-buffer
+                      nnspool-inews-program nnspool-inews-switches)
+             (error
+              (nnheader-report 'nnspool "inews error: %S" err)))))
+      (if (not proc)
+         ;; The inews program failed.
+         ()
+       (nnheader-report 'nnspool "")
+       (set-process-sentinel proc 'nnspool-inews-sentinel)
+       (mm-with-unibyte-current-buffer
+         (process-send-region proc (point-min) (point-max)))
+       ;; We slap a condition-case around this, because the process may
+       ;; have exited already...
+       (ignore-errors
+         (process-send-eof proc))
+       t))))
+
+
+\f
+;;; Internal functions.
+
+(defun nnspool-inews-sentinel (proc status)
+  (with-current-buffer (process-buffer proc)
+    (goto-char (point-min))
+    (if (or (zerop (buffer-size))
+           (search-forward "spooled" nil t))
+       (kill-buffer (current-buffer))
+      ;; Make status message by folding lines.
+      (while (re-search-forward "[ \t\n]+" nil t)
+       (replace-match " " t t))
+      (nnheader-report 'nnspool "%s" (buffer-string))
+      (nnheader-message 5 "nnspool: %s" nnspool-status-string)
+      (ding)
+      (run-hooks 'nnspool-rejected-article-hook))))
+
+(defun nnspool-retrieve-headers-with-nov (articles &optional fetch-old)
+  (if (or gnus-nov-is-evil nnspool-nov-is-evil)
+      nil
+    (let ((nov (nnheader-group-pathname
+               nnspool-current-group nnspool-nov-directory ".overview"))
+         (arts articles)
+         (nnheader-file-coding-system nnspool-file-coding-system)
+         last)
+      (if (not (file-exists-p nov))
+         ()
+       (with-current-buffer nntp-server-buffer
+         (erase-buffer)
+         (if nnspool-sift-nov-with-sed
+             (nnspool-sift-nov-with-sed articles nov)
+           (nnheader-insert-file-contents nov)
+           (if (and fetch-old
+                    (not (numberp fetch-old)))
+               t                       ; We want all the headers.
+             (ignore-errors
+               ;; Delete unwanted NOV lines.
+               (nnheader-nov-delete-outside-range
+                (if fetch-old (max 1 (- (car articles) fetch-old))
+                  (car articles))
+                (car (last articles)))
+               ;; If the buffer is empty, this wasn't very successful.
+               (unless (zerop (buffer-size))
+                 ;; We check what the last article number was.
+                 ;; The NOV file may be out of sync with the articles
+                 ;; in the group.
+                 (forward-line -1)
+                 (setq last (read (current-buffer)))
+                 (if (= last (car articles))
+                     ;; Yup, it's all there.
+                     t
+                   ;; Perhaps not.  We try to find the missing articles.
+                   (while (and arts
+                               (<= last (car arts)))
+                     (pop arts))
+                   ;; The articles in `arts' are missing from the buffer.
+                   (mapc 'nnspool-insert-nov-head arts)
+                   t))))))))))
+
+(defun nnspool-insert-nov-head (article)
+  "Read the head of ARTICLE, convert to NOV headers, and insert."
+  (save-excursion
+    (let ((cur (current-buffer))
+          buf)
+      (setq buf (nnheader-set-temp-buffer " *nnspool head*"))
+      (when (nnheader-insert-head
+             (nnspool-article-pathname nnspool-current-group article))
+        (nnheader-insert-article-line article)
+        (goto-char (point-min))
+        (let ((headers (nnheader-parse-head)))
+          (set-buffer cur)
+          (goto-char (point-max))
+          (nnheader-insert-nov headers)))
+      (kill-buffer buf))))
+
+(defun nnspool-sift-nov-with-sed (articles file)
+  (let ((first (car articles))
+       (last (car (last articles))))
+    (call-process "awk" nil t nil
+                 (format "BEGIN {firstmsg=%d; lastmsg=%d;}\n $1 >= firstmsg && $1 <= lastmsg {print;}"
+                         (1- first) (1+ last))
+                 file)))
+
+;; Fixed by fdc@cliwe.ping.de (Frank D. Cringle).
+;; Find out what group an article identified by a Message-ID is in.
+(defun nnspool-find-id (id)
+  (with-temp-buffer
+    (ignore-errors
+      (call-process "grep" nil t nil (regexp-quote id) nnspool-history-file))
+    (goto-char (point-min))
+    (when (looking-at "<[^>]+>[ \t]+[-0-9~]+[ \t]+\\([^ /\t\n]+\\)/\\([0-9]+\\)[ \t\n]")
+      (cons (match-string 1) (string-to-number (match-string 2))))))
+
+(defun nnspool-find-file (file)
+  "Insert FILE in server buffer safely."
+  (set-buffer nntp-server-buffer)
+  (erase-buffer)
+  (condition-case ()
+      (let ((coding-system-for-read nnspool-file-coding-system))
+       (mm-insert-file-contents file)
+       t)
+    (file-error nil)))
+
+(defun nnspool-possibly-change-directory (group)
+  (if (not group)
+      t
+    (let ((pathname (nnspool-article-pathname group)))
+      (if (file-directory-p pathname)
+         (setq nnspool-current-directory pathname
+               nnspool-current-group group)
+       (nnheader-report 'nnspool "No such newsgroup: %s" group)))))
+
+(defun nnspool-article-pathname (group &optional article)
+  "Find the file name for GROUP."
+  (nnheader-group-pathname group nnspool-spool-directory article))
+
+(provide 'nnspool)
+
+;;; nnspool.el ends here
diff --git a/xemacs-packages/gnus/lisp/nntp.el b/xemacs-packages/gnus/lisp/nntp.el
new file mode 100644 (file)
index 0000000..0e10dfd
--- /dev/null
@@ -0,0 +1,2078 @@
+;;; nntp.el --- nntp access for Gnus
+
+;; Copyright (C) 1987-1990, 1992-1998, 2000-2016 Free Software
+;; Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-and-compile
+  ;; In Emacs 24, `open-protocol-stream' is an autoloaded alias for
+  ;; `make-network-stream'.
+  (unless (fboundp 'open-protocol-stream)
+    (require 'proto-stream)))
+
+(require 'nnheader)
+(require 'nnoo)
+(require 'gnus-util)
+(require 'gnus)
+(require 'gnus-group) ;; gnus-group-name-charset
+
+(nnoo-declare nntp)
+
+(eval-when-compile (require 'cl))
+
+(autoload 'auth-source-search "auth-source")
+
+(defgroup nntp nil
+  "NNTP access for Gnus."
+  :group 'gnus)
+
+(defvoo nntp-address nil
+  "Address of the physical nntp server.")
+
+(defvoo nntp-port-number "nntp"
+  "Port number on the physical nntp server.")
+
+(defvoo nntp-server-opened-hook '(nntp-send-mode-reader)
+  "*Hook used for sending commands to the server at startup.
+The default value is `nntp-send-mode-reader', which makes an innd
+server spawn an nnrpd server.")
+
+(defvoo nntp-authinfo-function 'nntp-send-authinfo
+  "Function used to send AUTHINFO to the server.
+It is called with no parameters.")
+
+(defvoo nntp-server-action-alist
+    '(("nntpd 1\\.5\\.11t"
+       (remove-hook 'nntp-server-opened-hook 'nntp-send-mode-reader))
+      ("NNRP server Netscape"
+       (setq nntp-server-list-active-group nil)))
+  "Alist of regexps to match on server types and actions to be taken.
+For instance, if you want Gnus to beep every time you connect
+to innd, you could say something like:
+
+\(setq nntp-server-action-alist
+       \\='((\"innd\" (ding))))
+
+You probably don't want to do that, though.")
+
+(defvoo nntp-open-connection-function 'nntp-open-network-stream
+  "Method for connecting to a remote system.
+It should be a function, which is called with the output buffer
+as its single argument, or one of the following special values:
+
+- `nntp-open-network-stream' specifies a network connection,
+  upgrading to a TLS connection via STARTTLS if possible.
+- `nntp-open-plain-stream' specifies an unencrypted network
+  connection (no STARTTLS upgrade is attempted).
+- `nntp-open-ssl-stream' or `nntp-open-tls-stream' specify a TLS
+  network connection.
+
+Apart from the above special values, valid functions are as
+follows; please refer to their respective doc string for more
+information.
+For direct connections:
+- `nntp-open-netcat-stream'
+- `nntp-open-telnet-stream'
+For indirect connections:
+- `nntp-open-via-rlogin-and-netcat'
+- `nntp-open-via-rlogin-and-telnet'
+- `nntp-open-via-telnet-and-telnet'")
+
+(defvoo nntp-never-echoes-commands nil
+  "*Non-nil means the nntp server never echoes commands.
+It is reported that some nntps server doesn't echo commands.  So, you
+may want to set this to non-nil in the method for such a server setting
+`nntp-open-connection-function' to `nntp-open-ssl-stream' for example.
+Note that the `nntp-open-connection-functions-never-echo-commands'
+variable overrides the nil value of this variable.")
+
+(defvoo nntp-open-connection-functions-never-echo-commands
+    '(nntp-open-network-stream)
+  "*List of functions that never echo commands.
+Add or set a function which you set to `nntp-open-connection-function'
+to this list if it does not echo commands.  Note that a non-nil value
+of the `nntp-never-echoes-commands' variable overrides this variable.")
+
+(defvoo nntp-pre-command nil
+  "*Pre-command to use with the various nntp-open-via-* methods.
+This is where you would put \"runsocks\" or stuff like that.")
+
+(defvoo nntp-telnet-command "telnet"
+  "*Telnet command used to connect to the nntp server.
+This command is used by the methods `nntp-open-telnet-stream',
+`nntp-open-via-rlogin-and-telnet' and `nntp-open-via-telnet-and-telnet'.")
+
+(defvoo nntp-telnet-switches '("-8")
+  "*Switches given to the telnet command `nntp-telnet-command'.")
+
+(defvoo nntp-end-of-line "\r\n"
+  "*String to use on the end of lines when talking to the NNTP server.
+This is \"\\r\\n\" by default, but should be \"\\n\" when using an indirect
+connection method (nntp-open-via-*).")
+
+(defvoo nntp-via-rlogin-command "rsh"
+  "*Rlogin command used to connect to an intermediate host.
+This command is used by the methods `nntp-open-via-rlogin-and-telnet'
+and `nntp-open-via-rlogin-and-netcat'.  The default is \"rsh\", but \"ssh\"
+is a popular alternative.")
+
+(defvoo nntp-via-rlogin-command-switches nil
+  "*Switches given to the rlogin command `nntp-via-rlogin-command'.
+If you use \"ssh\" for `nntp-via-rlogin-command', you may set this to
+\(\"-C\") in order to compress all data connections, otherwise set this
+to \(\"-t\" \"-e\" \"none\") or (\"-C\" \"-t\" \"-e\" \"none\") if the telnet
+command requires a pseudo-tty allocation on an intermediate host.")
+
+(defvoo nntp-via-telnet-command "telnet"
+  "*Telnet command used to connect to an intermediate host.
+This command is used by the `nntp-open-via-telnet-and-telnet' method.")
+
+(defvoo nntp-via-telnet-switches '("-8")
+  "*Switches given to the telnet command `nntp-via-telnet-command'.")
+
+(defvoo nntp-netcat-command "nc"
+  "*Netcat command used to connect to the nntp server.
+This command is used by the `nntp-open-netcat-stream' and
+`nntp-open-via-rlogin-and-netcat' methods.")
+
+(defvoo nntp-netcat-switches nil
+  "*Switches given to the netcat command `nntp-netcat-command'.")
+
+(defvoo nntp-via-user-name nil
+  "*User name to log in on an intermediate host with.
+This variable is used by the various nntp-open-via-* methods.")
+
+(defvoo nntp-via-user-password nil
+  "*Password to use to log in on an intermediate host with.
+This variable is used by the `nntp-open-via-telnet-and-telnet' method.")
+
+(defvoo nntp-via-address nil
+  "*Address of an intermediate host to connect to.
+This variable is used by the various nntp-open-via-* methods.")
+
+(defvoo nntp-via-envuser nil
+  "*Whether both telnet client and server support the ENVIRON option.
+If non-nil, there will be no prompt for a login name.")
+
+(defvoo nntp-via-shell-prompt "bash\\|[$>] *\r?$"
+  "*Regular expression to match the shell prompt on an intermediate host.
+This variable is used by the `nntp-open-via-telnet-and-telnet' method.")
+
+(defvoo nntp-large-newsgroup 50
+  "*The number of articles which indicates a large newsgroup.
+If the number of articles is greater than the value, verbose
+messages will be shown to indicate the current status.")
+
+(defvoo nntp-maximum-request 400
+  "*The maximum number of the requests sent to the NNTP server at one time.
+If Emacs hangs up while retrieving headers, set the variable to a
+lower value.")
+
+(defvoo nntp-nov-is-evil nil
+  "*If non-nil, nntp will never attempt to use XOVER when talking to the server.")
+
+(defvoo nntp-xover-commands '("XOVER" "XOVERVIEW")
+  "*List of strings that are used as commands to fetch NOV lines from a server.
+The strings are tried in turn until a positive response is gotten.  If
+none of the commands are successful, nntp will just grab headers one
+by one.")
+
+(defvoo nntp-nov-gap 5
+  "*Maximum allowed gap between two articles.
+If the gap between two consecutive articles is bigger than this
+variable, split the XOVER request into two requests.")
+
+(defvoo nntp-xref-number-is-evil nil
+  "*If non-nil, Gnus never trusts article numbers in the Xref header.
+Some news servers, e.g., ones running Diablo, run multiple engines
+having the same articles but article numbers are not kept synchronized
+between them.  If you connect to such a server, set this to a non-nil
+value, and Gnus never uses article numbers (that appear in the Xref
+header and vary by which engine is chosen) to refer to articles.")
+
+(defvoo nntp-prepare-server-hook nil
+  "*Hook run before a server is opened.
+If can be used to set up a server remotely, for instance.  Say you
+have an account at the machine \"other.machine\".  This machine has
+access to an NNTP server that you can't access locally.  You could
+then use this hook to rsh to the remote machine and start a proxy NNTP
+server there that you can connect to.  See also
+`nntp-open-connection-function'")
+
+(defcustom nntp-authinfo-file "~/.authinfo"
+  ".netrc-like file that holds nntp authinfo passwords."
+  :group 'nntp
+  :type
+  '(choice file
+          (repeat :tag "Entries"
+                  :menu-tag "Inline"
+                  (list :format "%v"
+                        :value ("" ("login" . "") ("password" . ""))
+                        (string :tag "Host")
+                        (checklist :inline t
+                                   (cons :format "%v"
+                                         (const :format "" "login")
+                                         (string :format "Login: %v"))
+                                   (cons :format "%v"
+                                         (const :format "" "password")
+                                         (string :format "Password: %v")))))))
+
+(make-obsolete 'nntp-authinfo-file nil "Emacs 24.1")
+
+\f
+
+(defvoo nntp-connection-timeout nil
+  "*Number of seconds to wait before an nntp connection times out.
+If this variable is nil, which is the default, no timers are set.
+NOTE: This variable is never seen to work in Emacs 20 and XEmacs 21.")
+
+(defvoo nntp-prepare-post-hook nil
+  "*Hook run just before posting an article.  It is supposed to be used
+to insert Cancel-Lock headers.")
+
+(defvoo nntp-server-list-active-group 'try
+  "If nil, then always use GROUP instead of LIST ACTIVE.
+This is usually slower, but on misconfigured servers that don't
+update their active files often, this can help.")
+
+;;; Internal variables.
+
+(defvoo nntp-retrieval-in-progress nil)
+(defvar nntp-record-commands nil
+  "*If non-nil, nntp will record all commands in the \"*nntp-log*\" buffer.")
+
+(defvar nntp-have-messaged nil)
+
+(defvar nntp-process-wait-for nil)
+(defvar nntp-process-to-buffer nil)
+(defvar nntp-process-callback nil)
+(defvar nntp-process-decode nil)
+(defvar nntp-process-start-point nil)
+(defvar nntp-inside-change-function nil)
+(defvoo nntp-last-command-time nil)
+(defvoo nntp-last-command nil)
+(defvoo nntp-authinfo-password nil)
+(defvoo nntp-authinfo-user nil)
+(defvoo nntp-authinfo-force nil)
+
+(defvar nntp-connection-list nil)
+
+(defvoo nntp-server-type nil)
+(defvoo nntp-connection-alist nil)
+(defvoo nntp-status-string "")
+(defconst nntp-version "nntp 5.0")
+(defvoo nntp-inhibit-erase nil)
+(defvoo nntp-inhibit-output nil)
+
+(defvoo nntp-server-xover 'try)
+
+(defvar nntp-async-timer nil)
+(defvar nntp-async-process-list nil)
+
+(defvar nntp-authinfo-rejected nil
+"A custom error condition used to report `Authentication Rejected' errors.
+Condition handlers that match just this condition ensure that the nntp
+backend doesn't catch this error.")
+(put 'nntp-authinfo-rejected 'error-conditions '(error nntp-authinfo-rejected))
+(put 'nntp-authinfo-rejected 'error-message "Authorization Rejected")
+
+\f
+
+;;; Internal functions.
+
+(defsubst nntp-send-string (process string)
+  "Send STRING to PROCESS."
+  ;; We need to store the time to provide timeouts, and
+  ;; to store the command so the we can replay the command
+  ;; if the server gives us an AUTHINFO challenge.
+  (setq nntp-last-command-time (current-time)
+       nntp-last-command string)
+  (when nntp-record-commands
+    (nntp-record-command string))
+  (process-send-string process (concat string nntp-end-of-line))
+  (or (memq (process-status process) '(open run))
+      (nntp-report "Server closed connection")))
+
+(defun nntp-record-command (string)
+  "Record the command STRING."
+  (with-current-buffer (get-buffer-create "*nntp-log*")
+    (goto-char (point-max))
+    (insert (format-time-string "%Y%m%dT%H%M%S.%3N")
+           " " nntp-address " " string "\n")))
+
+(defvar nntp--report-1 nil)
+
+(defun nntp-report (&rest args)
+  "Report an error from the nntp backend.  The first string in ARGS
+can be a format string.  For some commands, the failed command may be
+retried once before actually displaying the error report."
+  (if nntp--report-1
+      (progn
+        ;; Throw out to nntp-with-open-group-error so that the connection may
+        ;; be restored and the command retried."
+        (when nntp-record-commands
+          (nntp-record-command "*** CONNECTION LOST ***"))
+        (throw 'nntp-with-open-group-error t))
+
+    (when nntp-record-commands
+      (nntp-record-command "*** CALLED nntp-report ***"))
+
+    (nnheader-report 'nntp args)
+
+    (apply 'error args)))
+
+(defmacro nntp-copy-to-buffer (buffer start end)
+  "Copy string from unibyte current buffer to multibyte buffer."
+  (if (featurep 'xemacs)
+      `(copy-to-buffer ,buffer ,start ,end)
+    `(let ((string (buffer-substring ,start ,end)))
+       (with-current-buffer ,buffer
+        (erase-buffer)
+        (insert (if enable-multibyte-characters
+                    (mm-string-to-multibyte string)
+                  string))
+        (goto-char (point-min))
+        nil))))
+
+(defsubst nntp-wait-for (process wait-for buffer &optional decode discard)
+  "Wait for WAIT-FOR to arrive from PROCESS."
+
+  (with-current-buffer (process-buffer process)
+    (goto-char (point-min))
+
+    (while (and (or (not (memq (char-after (point)) '(?2 ?3 ?4 ?5)))
+                   (looking-at "48[02]"))
+               (memq (process-status process) '(open run)))
+      (cond ((looking-at "480")
+            (nntp-handle-authinfo process))
+           ((looking-at "482")
+            (nnheader-report 'nntp "%s"
+                             (get 'nntp-authinfo-rejected 'error-message))
+            (signal 'nntp-authinfo-rejected nil))
+           ((looking-at "^.*\n")
+            (delete-region (point) (progn (forward-line 1) (point)))))
+      (nntp-accept-process-output process)
+      (goto-char (point-min)))
+    (prog1
+       (cond
+        ((looking-at "[45]")
+         (progn
+           (nntp-snarf-error-message)
+           nil))
+        ((not (memq (process-status process) '(open run)))
+         (nntp-report "Server closed connection"))
+        (t
+         (goto-char (point-max))
+         (let ((limit (point-min))
+               response)
+           (while (not (re-search-backward wait-for limit t))
+             (nntp-accept-process-output process)
+             ;; We assume that whatever we wait for is less than 1000
+             ;; characters long.
+             (setq limit (max (- (point-max) 1000) (point-min)))
+             (goto-char (point-max)))
+           (setq response (match-string 0))
+           (with-current-buffer nntp-server-buffer
+             (setq nntp-process-response response)))
+         (nntp-decode-text (not decode))
+         (unless discard
+           (with-current-buffer buffer
+             (goto-char (point-max))
+             (nnheader-insert-buffer-substring (process-buffer process))
+             ;; Nix out "nntp reading...." message.
+             (when nntp-have-messaged
+               (setq nntp-have-messaged nil)
+               (nnheader-message 5 ""))))
+         t))
+      (unless discard
+       (erase-buffer)))))
+
+(defun nntp-kill-buffer (buffer)
+  (when (buffer-name buffer)
+    (let ((process (get-buffer-process buffer)))
+      (when process
+       (delete-process process)))
+    (kill-buffer buffer)
+    (nnheader-init-server-buffer)))
+
+(defun nntp-erase-buffer (buffer)
+  "Erase contents of BUFFER."
+  (with-current-buffer buffer
+    (erase-buffer)))
+
+(defsubst nntp-find-connection (buffer)
+  "Find the connection delivering to BUFFER."
+  (let ((alist nntp-connection-alist)
+       (buffer (if (stringp buffer) (get-buffer buffer) buffer))
+       process entry)
+    (while (and alist (setq entry (pop alist)))
+      (when (eq buffer (cadr entry))
+       (setq process (car entry)
+             alist nil)))
+    (when process
+      (if (memq (process-status process) '(open run))
+         process
+       (nntp-kill-buffer (process-buffer process))
+       (setq nntp-connection-alist (delq entry nntp-connection-alist))
+       nil))))
+
+(defsubst nntp-find-connection-entry (buffer)
+  "Return the entry for the connection to BUFFER."
+  (assq (nntp-find-connection buffer) nntp-connection-alist))
+
+(defun nntp-find-connection-buffer (buffer)
+  "Return the process connection buffer tied to BUFFER."
+  (let ((process (nntp-find-connection buffer)))
+    (when process
+      (process-buffer process))))
+
+(defsubst nntp-retrieve-data (command address port buffer
+                                     &optional wait-for callback decode)
+  "Use COMMAND to retrieve data into BUFFER from PORT on ADDRESS."
+  (let ((process (or (nntp-find-connection buffer)
+                    (nntp-open-connection buffer))))
+    (if process
+        (progn
+          (unless (or nntp-inhibit-erase nnheader-callback-function)
+           (nntp-erase-buffer (process-buffer process)))
+          (condition-case err
+              (progn
+                (when command
+                  (nntp-send-string process command))
+                (cond
+                 ((eq callback 'ignore)
+                  t)
+                 ((and callback wait-for)
+                  (nntp-async-wait process wait-for buffer decode callback)
+                  t)
+                 (wait-for
+                  (nntp-wait-for process wait-for buffer decode))
+                 (t t)))
+           (nntp-authinfo-rejected
+            (signal 'nntp-authinfo-rejected (cdr err)))
+            (error
+             (nnheader-report 'nntp "Couldn't open connection to %s: %s"
+                              address err))
+            (quit
+             (message "Quit retrieving data from nntp")
+             (signal 'quit nil)
+             nil)))
+      (nnheader-report 'nntp "Couldn't open connection to %s" address))))
+
+(defsubst nntp-send-command (wait-for &rest strings)
+  "Send STRINGS to server and wait until WAIT-FOR returns."
+  (when (and (not nnheader-callback-function)
+            (not nntp-inhibit-output))
+    (nntp-erase-buffer nntp-server-buffer))
+  (let* ((command (mapconcat 'identity strings " "))
+        (process (nntp-find-connection nntp-server-buffer))
+        (buffer (and process (process-buffer process)))
+        (pos (and buffer (with-current-buffer buffer (point)))))
+    (if process
+       (prog1
+           (nntp-retrieve-data command
+                               nntp-address nntp-port-number
+                               nntp-server-buffer
+                               wait-for nnheader-callback-function)
+         ;; If nothing to wait for, still remove possibly echo'ed commands.
+         ;; We don't have echoes if `nntp-never-echoes-commands' is non-nil
+         ;; or the value of `nntp-open-connection-function' is in
+         ;; `nntp-open-connection-functions-never-echo-commands', so we
+         ;; skip this in that cases.
+         (unless (or wait-for
+                     nntp-never-echoes-commands
+                     (memq
+                      nntp-open-connection-function
+                      nntp-open-connection-functions-never-echo-commands))
+           (nntp-accept-response)
+           (with-current-buffer buffer
+             (goto-char pos)
+             (if (looking-at (regexp-quote command))
+                 (delete-region pos (progn (forward-line 1)
+                                           (point-at-bol)))))))
+      (nnheader-report 'nntp "Couldn't open connection to %s."
+                      nntp-address))))
+
+(defun nntp-send-command-nodelete (wait-for &rest strings)
+  "Send STRINGS to server and wait until WAIT-FOR returns."
+  (let* ((command (mapconcat 'identity strings " "))
+        (process (nntp-find-connection nntp-server-buffer))
+        (buffer (and process (process-buffer process)))
+        (pos (and buffer (with-current-buffer buffer (point)))))
+    (if process
+       (prog1
+           (nntp-retrieve-data command
+                               nntp-address nntp-port-number
+                               nntp-server-buffer
+                               wait-for nnheader-callback-function)
+         ;; If nothing to wait for, still remove possibly echo'ed commands
+         (unless wait-for
+           (nntp-accept-response)
+           (with-current-buffer buffer
+             (goto-char pos)
+             (if (looking-at (regexp-quote command))
+                 (delete-region pos (progn (forward-line 1)
+                                           (point-at-bol)))))))
+      (nnheader-report 'nntp "Couldn't open connection to %s."
+                      nntp-address))))
+
+(defun nntp-send-command-and-decode (wait-for &rest strings)
+  "Send STRINGS to server and wait until WAIT-FOR returns."
+  (when (and (not nnheader-callback-function)
+            (not nntp-inhibit-output))
+    (nntp-erase-buffer nntp-server-buffer))
+  (let* ((command (mapconcat 'identity strings " "))
+        (process (nntp-find-connection nntp-server-buffer))
+        (buffer (and process (process-buffer process)))
+        (pos (and buffer (with-current-buffer buffer (point)))))
+    (if process
+       (prog1
+           (nntp-retrieve-data command
+                               nntp-address nntp-port-number
+                               nntp-server-buffer
+                               wait-for nnheader-callback-function t)
+         ;; If nothing to wait for, still remove possibly echo'ed commands
+         (unless wait-for
+           (nntp-accept-response)
+           (with-current-buffer buffer
+             (goto-char pos)
+             (if (looking-at (regexp-quote command))
+                 (delete-region pos (progn (forward-line 1) (point-at-bol))))
+             )))
+      (nnheader-report 'nntp "Couldn't open connection to %s."
+                      nntp-address))))
+
+
+(defun nntp-send-buffer (wait-for)
+  "Send the current buffer to server and wait until WAIT-FOR returns."
+  (when (and (not nnheader-callback-function)
+            (not nntp-inhibit-output))
+    (nntp-erase-buffer
+     (nntp-find-connection-buffer nntp-server-buffer)))
+  (nntp-encode-text)
+  ;; Make sure we did not forget to encode some of the content.
+  (assert (save-excursion (goto-char (point-min))
+                          (not (re-search-forward "[^\000-\377]" nil t))))
+  (mm-disable-multibyte)
+  (process-send-region (nntp-find-connection nntp-server-buffer)
+                       (point-min) (point-max))
+  (nntp-retrieve-data
+   nil nntp-address nntp-port-number nntp-server-buffer
+   wait-for nnheader-callback-function))
+
+\f
+
+;;; Interface functions.
+
+(nnoo-define-basics nntp)
+
+(defsubst nntp-next-result-arrived-p ()
+  (cond
+   ;; A result that starts with a 2xx code is terminated by
+   ;; a line with only a "." on it.
+   ((eq (char-after) ?2)
+    (if (re-search-forward "\n\\.\r?\n" nil t)
+       (progn
+         ;; Some broken news servers add another dot at the end.
+         ;; Protect against inflooping there.
+         (while (looking-at "^\\.\r?\n")
+           (forward-line 1))
+         t)
+      nil))
+   ;; A result that starts with a 3xx or 4xx code is terminated
+   ;; by a newline.
+   ((looking-at "[34]")
+    (if (search-forward "\n" nil t)
+       t
+      nil))
+   ;; No result here.
+   (t
+    nil)))
+
+(defun nntp-with-open-group-function (-group -server -connectionless -bodyfun)
+  "Protect against servers that don't like clients that keep idle connections opens.
+The problem being that these servers may either close a connection or
+simply ignore any further requests on a connection.  Closed
+connections are not detected until `accept-process-output' has updated
+the `process-status'.  Dropped connections are not detected until the
+connection timeouts (which may be several minutes) or
+`nntp-connection-timeout' has expired.  When these occur
+`nntp-with-open-group', opens a new connection then re-issues the NNTP
+command whose response triggered the error."
+  (let ((nntp-report-n nntp--report-1)
+        (nntp--report-1 t)
+        (nntp-with-open-group-internal nil))
+    (while (catch 'nntp-with-open-group-error
+             ;; Open the connection to the server
+             ;; NOTE: Existing connections are NOT tested.
+             (nntp-possibly-change-group -group -server -connectionless)
+
+             (let ((-timer
+                    (and nntp-connection-timeout
+                         (run-at-time
+                          nntp-connection-timeout nil
+                          (lambda ()
+                            (let* ((-process (nntp-find-connection
+                                             nntp-server-buffer))
+                                   (-buffer  (and -process
+                                                  (process-buffer -process))))
+                              ;; When I an able to identify the
+                              ;; connection to the server AND I've
+                              ;; received NO response for
+                              ;; nntp-connection-timeout seconds.
+                              (when (and -buffer (eq 0 (buffer-size -buffer)))
+                                ;; Close the connection.  Take no
+                                ;; other action as the accept input
+                                ;; code will handle the closed
+                                ;; connection.
+                                (nntp-kill-buffer -buffer))))))))
+               (unwind-protect
+                   (setq nntp-with-open-group-internal
+                         (condition-case nil
+                             (funcall -bodyfun)
+                           (quit
+                            (unless debug-on-quit
+                              (nntp-close-server))
+                            (signal 'quit nil))))
+                 (when -timer
+                   (nnheader-cancel-timer -timer)))
+               nil))
+      (setq nntp--report-1 nntp-report-n))
+    nntp-with-open-group-internal))
+
+(defmacro nntp-with-open-group (group server &optional connectionless &rest forms)
+  "Protect against servers that don't like clients that keep idle connections opens.
+The problem being that these servers may either close a connection or
+simply ignore any further requests on a connection.  Closed
+connections are not detected until `accept-process-output' has updated
+the `process-status'.  Dropped connections are not detected until the
+connection timeouts (which may be several minutes) or
+`nntp-connection-timeout' has expired.  When these occur
+`nntp-with-open-group', opens a new connection then re-issues the NNTP
+command whose response triggered the error."
+  (declare (indent 2) (debug (form form [&optional symbolp] def-body)))
+  (when (and (listp connectionless)
+            (not (eq connectionless nil)))
+    (setq forms (cons connectionless forms)
+         connectionless nil))
+  `(nntp-with-open-group-function ,group ,server ,connectionless (lambda () ,@forms)))
+
+(deffoo nntp-retrieve-headers (articles &optional group server fetch-old)
+  "Retrieve the headers of ARTICLES."
+  (nntp-with-open-group
+   group server
+   (with-current-buffer (nntp-find-connection-buffer nntp-server-buffer)
+     (erase-buffer)
+     (if (and (not gnus-nov-is-evil)
+              (not nntp-nov-is-evil)
+              (nntp-retrieve-headers-with-xover articles fetch-old))
+         ;; We successfully retrieved the headers via XOVER.
+         'nov
+       ;; XOVER didn't work, so we do it the hard, slow and inefficient
+       ;; way.
+       (let ((number (length articles))
+             (articles articles)
+             (count 0)
+             (received 0)
+             (last-point (point-min))
+             (buf (nntp-find-connection-buffer nntp-server-buffer))
+             (nntp-inhibit-erase t)
+             article)
+         ;; Send HEAD commands.
+         (while (setq article (pop articles))
+           (nntp-send-command
+            nil
+            "HEAD" (if (numberp article)
+                       (int-to-string article)
+                     ;; `articles' is either a list of article numbers
+                     ;; or a list of article IDs.
+                     article))
+           (incf count)
+           ;; Every 400 requests we have to read the stream in
+           ;; order to avoid deadlocks.
+           (when (or (null articles)    ;All requests have been sent.
+                     (zerop (% count nntp-maximum-request)))
+             (nntp-accept-response)
+             (while (progn
+                      (set-buffer buf)
+                      (goto-char last-point)
+                      ;; Count replies.
+                      (while (nntp-next-result-arrived-p)
+                        (setq last-point (point))
+                        (incf received))
+                      (< received count))
+               ;; If number of headers is greater than 100, give
+               ;;  informative messages.
+               (and (numberp nntp-large-newsgroup)
+                    (> number nntp-large-newsgroup)
+                    (zerop (% received 20))
+                    (nnheader-message 6 "NNTP: Receiving headers... %d%%"
+                                      (floor (* received 100.0) number)))
+               (nntp-accept-response))))
+         (and (numberp nntp-large-newsgroup)
+              (> number nntp-large-newsgroup)
+              (nnheader-message 6 "NNTP: Receiving headers...done"))
+
+         ;; Now all of replies are received.  Fold continuation lines.
+         (nnheader-fold-continuation-lines)
+         ;; Remove all "\r"'s.
+         (nnheader-strip-cr)
+        (nntp-copy-to-buffer nntp-server-buffer (point-min) (point-max))
+         'headers)))))
+
+(deffoo nntp-retrieve-group-data-early (server infos)
+  "Retrieve group info on INFOS."
+  (nntp-with-open-group nil server
+    (let ((buffer (nntp-find-connection-buffer nntp-server-buffer)))
+      (unless infos
+       (with-current-buffer buffer
+         (setq nntp-retrieval-in-progress nil)))
+      (when (and buffer
+                infos
+                (with-current-buffer buffer
+                  (not nntp-retrieval-in-progress)))
+       ;; The first time this is run, this variable is `try'.  So we
+       ;; try.
+       (when (eq nntp-server-list-active-group 'try)
+         (nntp-try-list-active
+          (gnus-group-real-name (gnus-info-group (car infos)))))
+       (with-current-buffer buffer
+         (erase-buffer)
+         ;; Mark this buffer as "in use" in case we try to issue two
+         ;; retrievals from the same server.  This shouldn't happen,
+         ;; so this is mostly a sanity check.
+         (setq nntp-retrieval-in-progress t)
+         (let ((nntp-inhibit-erase t)
+               (command (if nntp-server-list-active-group
+                            "LIST ACTIVE" "GROUP")))
+           (dolist (info infos)
+             (nntp-send-command
+              nil command (gnus-group-real-name (gnus-info-group info)))))
+         (length infos))))))
+
+(deffoo nntp-finish-retrieve-group-infos (server infos count)
+  (nntp-with-open-group nil server
+    (let ((buf (nntp-find-connection-buffer nntp-server-buffer))
+         (method (gnus-find-method-for-group
+                  (gnus-info-group (car infos))
+                  (car infos)))
+         (received 0)
+         (last-point 1))
+      (with-current-buffer buf
+       (setq nntp-retrieval-in-progress nil))
+      (when (and buf
+                count)
+       (with-current-buffer buf
+         (while (and (gnus-buffer-live-p buf)
+                     (progn
+                       (goto-char last-point)
+                       ;; Count replies.
+                       (while (re-search-forward
+                               (if nntp-server-list-active-group
+                                   "^[.]"
+                                 "^[0-9]")
+                               nil t)
+                         (incf received))
+                       (setq last-point (point))
+                       (< received count)))
+           (nntp-accept-response))
+         ;; We now have all the entries.  Remove CRs.
+         (nnheader-strip-cr)
+         (if (not nntp-server-list-active-group)
+             (progn
+               (nntp-copy-to-buffer nntp-server-buffer
+                                    (point-min) (point-max))
+               (with-current-buffer nntp-server-buffer
+                 (gnus-groups-to-gnus-format method gnus-active-hashtb t)))
+           ;; We have read active entries, so we just delete the
+           ;; superfluous gunk.
+           (goto-char (point-min))
+           (while (re-search-forward "^[.2-5]" nil t)
+             (delete-region (match-beginning 0)
+                            (progn (forward-line 1) (point))))
+           (nntp-copy-to-buffer nntp-server-buffer (point-min) (point-max))
+           (with-current-buffer nntp-server-buffer
+             (gnus-active-to-gnus-format
+              ;; Kludge to use the extended method name if you have
+              ;; an extended one.
+              (if (consp (gnus-info-method (car infos)))
+                  (gnus-info-method (car infos))
+                method)
+              gnus-active-hashtb nil t))))))))
+
+(deffoo nntp-retrieve-groups (groups &optional server)
+  "Retrieve group info on GROUPS."
+  (nntp-with-open-group
+   nil server
+   (when (and (nntp-find-connection-buffer nntp-server-buffer)
+             (with-current-buffer
+                 (nntp-find-connection-buffer nntp-server-buffer)
+               (if (not nntp-retrieval-in-progress)
+                   t
+                 (message "Warning: Refusing to do retrieval from %s because a retrieval is already happening"
+                          server)
+                 nil)))
+     (catch 'done
+       (save-excursion
+         ;; Erase nntp-server-buffer before nntp-inhibit-erase.
+        (nntp-erase-buffer nntp-server-buffer)
+         (set-buffer (nntp-find-connection-buffer nntp-server-buffer))
+         ;; The first time this is run, this variable is `try'.  So we
+         ;; try.
+         (when (eq nntp-server-list-active-group 'try)
+           (nntp-try-list-active (car groups)))
+         (erase-buffer)
+         (let ((count 0)
+               (groups groups)
+               (received 0)
+               (last-point (point-min))
+               (nntp-inhibit-erase t)
+               (buf (nntp-find-connection-buffer nntp-server-buffer))
+               (command (if nntp-server-list-active-group
+                            "LIST ACTIVE" "GROUP")))
+           (while groups
+             ;; Timeout may have killed the buffer.
+             (unless (gnus-buffer-live-p buf)
+               (nnheader-report 'nntp "Connection to %s is closed." server)
+               (throw 'done nil))
+             ;; Send the command to the server.
+             (nntp-send-command nil command (pop groups))
+             (incf count)
+             ;; Every 400 requests we have to read the stream in
+             ;; order to avoid deadlocks.
+             (when (or (null groups)    ;All requests have been sent.
+                       (zerop (% count nntp-maximum-request)))
+               (nntp-accept-response)
+               (while (and (gnus-buffer-live-p buf)
+                           (progn
+                             ;; Search `blue moon' in this file for the
+                             ;; reason why set-buffer here.
+                             (set-buffer buf)
+                             (goto-char last-point)
+                             ;; Count replies.
+                             (while (re-search-forward "^[0-9]" nil t)
+                               (incf received))
+                             (setq last-point (point))
+                             (< received count)))
+                 (nntp-accept-response))))
+
+           ;; Wait for the reply from the final command.
+           (unless (gnus-buffer-live-p buf)
+             (nnheader-report 'nntp "Connection to %s is closed." server)
+             (throw 'done nil))
+           (set-buffer buf)
+           (goto-char (point-max))
+           (re-search-backward "^[0-9]" nil t)
+           (when (looking-at "^[23]")
+             (while (and (gnus-buffer-live-p buf)
+                         (progn
+                           (set-buffer buf)
+                           (goto-char (point-max))
+                           (if (not nntp-server-list-active-group)
+                               (not (re-search-backward "\r?\n"
+                                                       (- (point) 3) t))
+                             (not (re-search-backward "^\\.\r?\n"
+                                                      (- (point) 4) t)))))
+               (nntp-accept-response)))
+
+           ;; Now all replies are received.  We remove CRs.
+           (unless (gnus-buffer-live-p buf)
+             (nnheader-report 'nntp "Connection to %s is closed." server)
+             (throw 'done nil))
+           (set-buffer buf)
+           (goto-char (point-min))
+           (while (search-forward "\r" nil t)
+             (replace-match "" t t))
+
+           (if (not nntp-server-list-active-group)
+               (progn
+                (nntp-copy-to-buffer nntp-server-buffer
+                                     (point-min) (point-max))
+                 'group)
+             ;; We have read active entries, so we just delete the
+             ;; superfluous gunk.
+             (goto-char (point-min))
+             (while (re-search-forward "^[.2-5]" nil t)
+               (delete-region (match-beginning 0)
+                              (progn (forward-line 1) (point))))
+            (nntp-copy-to-buffer nntp-server-buffer (point-min) (point-max))
+             'active)))))))
+
+(deffoo nntp-retrieve-articles (articles &optional group server)
+  (nntp-with-open-group
+    group server
+   (save-excursion
+     (let ((number (length articles))
+           (articles articles)
+           (count 0)
+           (received 0)
+           (last-point (point-min))
+           (buf (nntp-find-connection-buffer nntp-server-buffer))
+           (nntp-inhibit-erase t)
+           (map (apply 'vector articles))
+           (point 1)
+           article)
+       (set-buffer buf)
+       (erase-buffer)
+       ;; Send ARTICLE command.
+       (while (setq article (pop articles))
+         (nntp-send-command
+          nil
+          "ARTICLE" (if (numberp article)
+                        (int-to-string article)
+                      ;; `articles' is either a list of article numbers
+                      ;; or a list of article IDs.
+                      article))
+         (incf count)
+         ;; Every 400 requests we have to read the stream in
+         ;; order to avoid deadlocks.
+         (when (or (null articles)     ;All requests have been sent.
+                   (zerop (% count nntp-maximum-request)))
+           (nntp-accept-response)
+           (while (progn
+                    (set-buffer buf)
+                    (goto-char last-point)
+                    ;; Count replies.
+                    (while (nntp-next-result-arrived-p)
+                      (aset map received (cons (aref map received) (point)))
+                      (setq last-point (point))
+                      (incf received))
+                    (< received count))
+             ;; If number of headers is greater than 100, give
+             ;;  informative messages.
+             (and (numberp nntp-large-newsgroup)
+                  (> number nntp-large-newsgroup)
+                  (zerop (% received 20))
+                  (nnheader-message 6 "NNTP: Receiving articles... %d%%"
+                                    (floor (* received 100.0) number)))
+             (nntp-accept-response))))
+       (and (numberp nntp-large-newsgroup)
+            (> number nntp-large-newsgroup)
+            (nnheader-message 6 "NNTP: Receiving articles...done"))
+
+       ;; Now we have all the responses.  We go through the results,
+       ;; wash it and copy it over to the server buffer.
+       (set-buffer nntp-server-buffer)
+       (erase-buffer)
+       (setq last-point (point-min))
+       (mapcar
+        (lambda (entry)
+          (narrow-to-region
+           (setq point (goto-char (point-max)))
+           (progn
+            (nnheader-insert-buffer-substring buf last-point (cdr entry))
+             (point-max)))
+          (setq last-point (cdr entry))
+          (nntp-decode-text)
+          (widen)
+          (cons (car entry) point))
+        map)))))
+
+(defun nntp-try-list-active (group)
+  (nntp-list-active-group group)
+  (with-current-buffer nntp-server-buffer
+    (goto-char (point-min))
+    (cond ((or (eobp)
+              (looking-at "5[0-9]+"))
+          (setq nntp-server-list-active-group nil))
+         (t
+          (setq nntp-server-list-active-group t)))))
+
+(deffoo nntp-list-active-group (group &optional server)
+  "Return the active info on GROUP (which can be a regexp)."
+  (nntp-with-open-group
+   nil server
+   (nntp-send-command "^\\.*\r?\n" "LIST ACTIVE" group)))
+
+(deffoo nntp-request-group-articles (group &optional server)
+  "Return the list of existing articles in GROUP."
+  (nntp-with-open-group
+   nil server
+   (nntp-send-command "^\\.*\r?\n" "LISTGROUP" group)))
+
+(deffoo nntp-request-article (article &optional group server buffer command)
+  (nntp-with-open-group
+      group server
+    (when (nntp-send-command-and-decode
+           "\r?\n\\.\r?\n" "ARTICLE"
+           (if (numberp article) (int-to-string article) article))
+      (when (and buffer
+                (not (equal buffer nntp-server-buffer)))
+       (with-current-buffer nntp-server-buffer
+         (copy-to-buffer buffer (point-min) (point-max))))
+      (nntp-find-group-and-number group))))
+
+(deffoo nntp-request-head (article &optional group server)
+  (nntp-with-open-group
+   group server
+   (when (nntp-send-command
+          "\r?\n\\.\r?\n" "HEAD"
+          (if (numberp article) (int-to-string article) article))
+     (prog1
+         (nntp-find-group-and-number group)
+       (nntp-decode-text)))))
+
+(deffoo nntp-request-body (article &optional group server)
+  (nntp-with-open-group
+   group server
+   (nntp-send-command-and-decode
+    "\r?\n\\.\r?\n" "BODY"
+    (if (numberp article) (int-to-string article) article))))
+
+(deffoo nntp-request-group (group &optional server dont-check info)
+  (nntp-with-open-group
+    nil server
+    (when (nntp-send-command "^[245].*\n" "GROUP" group)
+      (let ((entry (nntp-find-connection-entry nntp-server-buffer)))
+        (setcar (cddr entry) group)))))
+
+(deffoo nntp-close-group (group &optional server)
+  t)
+
+(deffoo nntp-server-opened (&optional server)
+  "Say whether a connection to SERVER has been opened."
+  (and (nnoo-current-server-p 'nntp server)
+       nntp-server-buffer
+       (gnus-buffer-live-p nntp-server-buffer)
+       (nntp-find-connection nntp-server-buffer)))
+
+(deffoo nntp-open-server (server &optional defs connectionless)
+  (nnheader-init-server-buffer)
+  (if (nntp-server-opened server)
+      t
+    (when (or (stringp (car defs))
+             (numberp (car defs)))
+      (setq defs (cons (list 'nntp-port-number (car defs)) (cdr defs))))
+    (unless (assq 'nntp-address defs)
+      (setq defs (append defs (list (list 'nntp-address server)))))
+    (nnoo-change-server 'nntp server defs)
+    (if connectionless
+       t
+      (or (nntp-find-connection nntp-server-buffer)
+         (nntp-open-connection nntp-server-buffer)))))
+
+(deffoo nntp-close-server (&optional server)
+  (nntp-possibly-change-group nil server t)
+  (let ((process (nntp-find-connection nntp-server-buffer)))
+    (while process
+      (when (memq (process-status process) '(open run))
+       (ignore-errors
+         (nntp-send-string process "QUIT")
+         (unless (eq nntp-open-connection-function 'nntp-open-network-stream)
+           ;; Ok, this is evil, but when using telnet and stuff
+           ;; as the connection method, it's important that the
+           ;; QUIT command actually is sent out before we kill
+           ;; the process.
+           (sleep-for 1))))
+      (nntp-kill-buffer (process-buffer process))
+      (setq process (car (pop nntp-connection-alist))))
+    (nnoo-close-server 'nntp)))
+
+(deffoo nntp-request-close ()
+  (let (process)
+    (while (setq process (pop nntp-connection-list))
+      (when (memq (process-status process) '(open run))
+       (ignore-errors
+         (nntp-send-string process "QUIT")
+         (unless (eq nntp-open-connection-function 'nntp-open-network-stream)
+           ;; Ok, this is evil, but when using telnet and stuff
+           ;; as the connection method, it's important that the
+           ;; QUIT command actually is sent out before we kill
+           ;; the process.
+           (sleep-for 1))))
+      (nntp-kill-buffer (process-buffer process)))))
+
+(deffoo nntp-request-list (&optional server)
+  (nntp-with-open-group
+   nil server
+   (nntp-send-command-and-decode "\r?\n\\.\r?\n" "LIST")))
+
+(deffoo nntp-request-list-newsgroups (&optional server)
+  (nntp-with-open-group
+   nil server
+   (nntp-send-command "\r?\n\\.\r?\n" "LIST NEWSGROUPS")))
+
+(deffoo nntp-request-newgroups (date &optional server)
+  (nntp-with-open-group
+   nil server
+   (with-current-buffer nntp-server-buffer
+     (let* ((time (date-to-time date))
+            (ls (- (cadr time) (nth 8 (decode-time time)))))
+       (cond ((< ls 0)
+              (setcar time (1- (car time)))
+              (setcar (cdr time) (+ ls 65536)))
+             ((>= ls 65536)
+              (setcar time (1+ (car time)))
+              (setcar (cdr time) (- ls 65536)))
+             (t
+              (setcar (cdr time) ls)))
+       (prog1
+           (nntp-send-command
+            "^\\.\r?\n" "NEWGROUPS"
+            (format-time-string "%y%m%d %H%M%S" time)
+            "GMT")
+         (nntp-decode-text))))))
+
+(deffoo nntp-request-post (&optional server)
+  (nntp-with-open-group
+   nil server
+   (when (nntp-send-command "^[23].*\r?\n" "POST")
+     (let ((response (with-current-buffer nntp-server-buffer
+                       nntp-process-response))
+           server-id)
+       (when (and response
+                  (string-match "^[23].*\\(<[^\t\n @<>]+@[^\t\n @<>]+>\\)"
+                                response))
+         (setq server-id (match-string 1 response))
+         (narrow-to-region (goto-char (point-min))
+                           (if (search-forward "\n\n" nil t)
+                               (1- (point))
+                             (point-max)))
+         (unless (mail-fetch-field "Message-ID")
+           (goto-char (point-min))
+           (insert "Message-ID: " server-id "\n"))
+         (widen))
+       (run-hooks 'nntp-prepare-post-hook)
+       (nntp-send-buffer "^[23].*\n")))))
+
+(deffoo nntp-request-type (group article)
+  'news)
+
+(deffoo nntp-asynchronous-p ()
+  t)
+
+
+;;; Hooky functions.
+
+(defun nntp-send-mode-reader ()
+  "Send the MODE READER command to the nntp server.
+This function is supposed to be called from `nntp-server-opened-hook'.
+It will make innd servers spawn an nnrpd process to allow actual article
+reading."
+  (nntp-send-command "^.*\n" "MODE READER"))
+
+(declare-function netrc-parse "netrc" (&optional file))
+(declare-function netrc-machine "netrc"
+                 (list machine &optional port defaultport))
+(declare-function netrc-get "netrc" (alist type))
+
+(defun nntp-send-authinfo (&optional send-if-force)
+  "Send the AUTHINFO to the nntp server.
+It will look in the \"~/.authinfo\" file for matching entries.  If
+nothing suitable is found there, it will prompt for a user name
+and a password.
+
+If SEND-IF-FORCE, only send authinfo to the server if the
+.authinfo file has the FORCE token."
+  (require 'netrc)
+  (let* ((list (netrc-parse nntp-authinfo-file))
+        (alist (netrc-machine list nntp-address "nntp"))
+         (auth-info
+          (nth 0 (auth-source-search
+                 :max 1
+                 :host (list nntp-address (nnoo-current-server 'nntp))
+                 :port `("119" "nntp" ,(format "%s" nntp-port-number)
+                         "563" "nntps" "snews"))))
+         (auth-user (plist-get auth-info :user))
+         (auth-force (plist-get auth-info :force))
+         (auth-passwd (plist-get auth-info :secret))
+         (auth-passwd (if (functionp auth-passwd)
+                          (funcall auth-passwd)
+                        auth-passwd))
+        (force (or (netrc-get alist "force")
+                    nntp-authinfo-force
+                    auth-force))
+        (user (or
+               ;; this is preferred to netrc-*
+               auth-user
+               (netrc-get alist "login")
+               nntp-authinfo-user))
+        (passwd (or
+                 ;; this is preferred to netrc-*
+                 auth-passwd
+                 (netrc-get alist "password"))))
+    (when (or (not send-if-force)
+             force)
+      (unless user
+       (setq user (read-string (format "NNTP (%s) user name: " nntp-address))
+             nntp-authinfo-user user))
+      (unless (member user '(nil ""))
+       (nntp-send-command "^3.*\r?\n" "AUTHINFO USER" user)
+       (let ((result
+              (nntp-send-command
+               "^2.*\r?\n" "AUTHINFO PASS"
+               (or passwd
+                   nntp-authinfo-password
+                   (setq nntp-authinfo-password
+                         (read-passwd (format "NNTP (%s@%s) password: "
+                                              user nntp-address)))))))
+         (if (not result)
+             (signal 'nntp-authinfo-rejected "Password rejected")
+           result))))))
+
+;;; Internal functions.
+
+(defun nntp-handle-authinfo (process)
+  "Take care of an authinfo response from the server."
+  (let ((last nntp-last-command))
+    (funcall nntp-authinfo-function)
+    ;; We have to re-send the function that was interrupted by
+    ;; the authinfo request.
+    (nntp-erase-buffer nntp-server-buffer)
+    (nntp-send-string process last)))
+
+(defun nntp-make-process-buffer (buffer)
+  "Create a new, fresh buffer usable for nntp process connections."
+  (with-current-buffer
+      (generate-new-buffer
+       (format " *server %s %s %s*"
+               nntp-address nntp-port-number
+               (gnus-buffer-exists-p buffer)))
+    (mm-disable-multibyte)
+    (set (make-local-variable 'after-change-functions) nil)
+    (set (make-local-variable 'nntp-process-wait-for) nil)
+    (set (make-local-variable 'nntp-process-callback) nil)
+    (set (make-local-variable 'nntp-process-to-buffer) nil)
+    (set (make-local-variable 'nntp-process-start-point) nil)
+    (set (make-local-variable 'nntp-process-decode) nil)
+    (set (make-local-variable 'nntp-retrieval-in-progress) nil)
+    (current-buffer)))
+
+(defun nntp-open-connection (buffer)
+  "Open a connection to PORT on ADDRESS delivering output to BUFFER."
+  (run-hooks 'nntp-prepare-server-hook)
+  (let* ((pbuffer (nntp-make-process-buffer buffer))
+        (timer
+         (and nntp-connection-timeout
+              (run-at-time
+               nntp-connection-timeout nil
+               `(lambda ()
+                  (nntp-kill-buffer ,pbuffer)))))
+        (process
+         (condition-case err
+             (let ((coding-system-for-read 'binary)
+                   (coding-system-for-write 'binary)
+                   (map '((nntp-open-network-stream network)
+                          (network-only plain) ; compat
+                          (nntp-open-plain-stream plain)
+                          (nntp-open-ssl-stream tls)
+                          (nntp-open-tls-stream tls))))
+               (if (assoc nntp-open-connection-function map)
+                   (open-protocol-stream
+                    "nntpd" pbuffer nntp-address nntp-port-number
+                    :type (cadr (assoc nntp-open-connection-function map))
+                    :end-of-command "^\\([2345]\\|[.]\\).*\n"
+                    :capability-command "HELP\r\n"
+                    :success "^3"
+                    :starttls-function
+                    (lambda (capabilities)
+                      (if (not (string-match "STARTTLS" capabilities))
+                          nil
+                        "STARTTLS\r\n")))
+                 (funcall nntp-open-connection-function pbuffer)))
+           (error
+            (nnheader-report 'nntp ">>> %s" err))
+           (quit
+            (message "Quit opening connection to %s" nntp-address)
+            (nntp-kill-buffer pbuffer)
+            (signal 'quit nil)
+            nil))))
+    (when timer
+      (nnheader-cancel-timer timer))
+    (when (and process
+              (not (memq (process-status process) '(open run))))
+      (with-current-buffer pbuffer
+       (goto-char (point-min))
+       (nnheader-report 'nntp "Error when connecting: %s"
+                        (buffer-substring (point) (line-end-position))))
+      (setq process nil))
+    (unless process
+      (nntp-kill-buffer pbuffer))
+    (when (and (buffer-name pbuffer)
+              process)
+      (when (and (fboundp 'set-network-process-option) ;; Unavailable in XEmacs.
+                (fboundp 'process-type) ;; Emacs 22 doesn't provide it.
+                 (eq (process-type process) 'network))
+        ;; Use TCP-keepalive so that connections that pass through a NAT router
+        ;; don't hang when left idle.
+        (set-network-process-option process :keepalive t))
+      (gnus-set-process-query-on-exit-flag process nil)
+      (if (and (nntp-wait-for process "^2.*\n" buffer nil t)
+              (memq (process-status process) '(open run)))
+         (prog1
+             (caar (push (list process buffer nil) nntp-connection-alist))
+           (push process nntp-connection-list)
+           (with-current-buffer pbuffer
+             (nntp-read-server-type)
+             (erase-buffer)
+             (set-buffer nntp-server-buffer)
+             (let ((nnheader-callback-function nil))
+               (run-hooks 'nntp-server-opened-hook)
+               (nntp-send-authinfo t))))
+       (nntp-kill-buffer (process-buffer process))
+       nil))))
+
+(defun nntp-read-server-type ()
+  "Find out what the name of the server we have connected to is."
+  ;; Wait for the status string to arrive.
+  (setq nntp-server-type (buffer-string))
+  (let ((case-fold-search t))
+    ;; Run server-specific commands.
+    (dolist (entry nntp-server-action-alist)
+      (when (string-match (car entry) nntp-server-type)
+       (if (and (listp (cadr entry))
+                (not (eq 'lambda (caadr entry))))
+           (eval (cadr entry))
+         (funcall (cadr entry)))))))
+
+(defun nntp-async-wait (process wait-for buffer decode callback)
+  (with-current-buffer (process-buffer process)
+    (unless nntp-inside-change-function
+      (erase-buffer))
+    (setq nntp-process-wait-for wait-for
+         nntp-process-to-buffer buffer
+         nntp-process-decode decode
+         nntp-process-callback callback
+         nntp-process-start-point (point-max))
+    (setq after-change-functions '(nntp-after-change-function))))
+
+(defun nntp-async-stop (proc)
+  (setq nntp-async-process-list (delq proc nntp-async-process-list))
+  (when (and nntp-async-timer (not nntp-async-process-list))
+    (nnheader-cancel-timer nntp-async-timer)
+    (setq nntp-async-timer nil)))
+
+(defun nntp-after-change-function (beg end len)
+  (unwind-protect
+      ;; we only care about insertions at eob
+      (when (and (eq 0 len) (eq (point-max) end))
+       (save-match-data
+         (let ((proc (get-buffer-process (current-buffer))))
+           (when proc
+             (nntp-async-trigger proc)))))
+    ;; any throw from after-change-functions will leave it
+    ;; set to nil.  so we reset it here, if necessary.
+    (when quit-flag
+      (setq after-change-functions '(nntp-after-change-function)))))
+
+(defun nntp-async-trigger (process)
+  (with-current-buffer (process-buffer process)
+    (when nntp-process-callback
+      ;; do we have an error message?
+      (goto-char nntp-process-start-point)
+      (if (memq (following-char) '(?4 ?5))
+         ;; wants credentials?
+         (if (looking-at "480")
+             (nntp-handle-authinfo process)
+           ;; report error message.
+           (nntp-snarf-error-message)
+           (nntp-do-callback nil))
+
+       ;; got what we expect?
+       (goto-char (point-max))
+       (when (re-search-backward
+              nntp-process-wait-for nntp-process-start-point t)
+         (let ((response (match-string 0)))
+           (with-current-buffer nntp-server-buffer
+             (setq nntp-process-response response)))
+         (nntp-async-stop process)
+         ;; convert it.
+         (when (gnus-buffer-exists-p nntp-process-to-buffer)
+           (let ((buf (current-buffer))
+                 (start nntp-process-start-point)
+                 (decode nntp-process-decode))
+             (with-current-buffer nntp-process-to-buffer
+               (goto-char (point-max))
+               (save-restriction
+                 (narrow-to-region (point) (point))
+                 (nnheader-insert-buffer-substring buf start)
+                 (when decode
+                   (nntp-decode-text))))))
+         ;; report it.
+         (goto-char (point-max))
+         (nntp-do-callback
+          (buffer-name (get-buffer nntp-process-to-buffer))))))))
+
+(defun nntp-do-callback (arg)
+  (let ((callback nntp-process-callback)
+       (nntp-inside-change-function t))
+    (setq nntp-process-callback nil)
+    (funcall callback arg)))
+
+(defun nntp-snarf-error-message ()
+  "Save the error message in the current buffer."
+  (let ((message (buffer-string)))
+    (while (string-match "[\r\n]+" message)
+      (setq message (replace-match " " t t message)))
+    (nnheader-report 'nntp "%s" message)
+    message))
+
+(defun nntp-accept-process-output (process)
+  "Wait for output from PROCESS and message some dots."
+  (with-current-buffer (or (nntp-find-connection-buffer nntp-server-buffer)
+                           nntp-server-buffer)
+    (let ((len (/ (buffer-size) 1024))
+         message-log-max)
+      (unless (< len 10)
+       (setq nntp-have-messaged t)
+       (nnheader-message 7 "nntp read: %dk" len)))
+    (prog1
+       (nnheader-accept-process-output process)
+      ;; accept-process-output may update status of process to indicate
+      ;; that the server has closed the connection.  This MUST be
+      ;; handled here as the buffer restored by the save-excursion may
+      ;; be the process's former output buffer (i.e. now killed)
+      (or (and process
+              (memq (process-status process) '(open run)))
+          (nntp-report "Server closed connection")))))
+
+(defun nntp-accept-response ()
+  "Wait for output from the process that outputs to BUFFER."
+  (nntp-accept-process-output (nntp-find-connection nntp-server-buffer)))
+
+(defun nntp-possibly-change-group (group server &optional connectionless)
+  (let ((nnheader-callback-function nil))
+    (when server
+      (or (nntp-server-opened server)
+         (nntp-open-server server nil connectionless)))
+
+    (unless connectionless
+      (or (nntp-find-connection nntp-server-buffer)
+         (nntp-open-connection nntp-server-buffer))))
+
+  (when group
+    (let ((entry (nntp-find-connection-entry nntp-server-buffer)))
+      (cond ((not entry)
+             (nntp-report "Server closed connection"))
+            ((not (equal group (caddr entry)))
+             (with-current-buffer (process-buffer (car entry))
+               (erase-buffer)
+               (nntp-send-command "^[245].*\n" "GROUP" group)
+               (setcar (cddr entry) group)
+               (erase-buffer)
+              (nntp-erase-buffer nntp-server-buffer)))))))
+
+(defun nntp-decode-text (&optional cr-only)
+  "Decode the text in the current buffer."
+  (goto-char (point-min))
+  (while (search-forward "\r" nil t)
+    (delete-char -1))
+  (unless cr-only
+    ;; Remove trailing ".\n" end-of-transfer marker.
+    (goto-char (point-max))
+    (forward-line -1)
+    (when (looking-at ".\n")
+      (delete-char 2))
+    ;; Delete status line.
+    (goto-char (point-min))
+    (while (looking-at "[1-5][0-9][0-9] .*\n")
+      ;; For some unknown reason, there is more than one status line.
+      (delete-region (point) (progn (forward-line 1) (point))))
+    ;; Remove "." -> ".." encoding.
+    (while (search-forward "\n.." nil t)
+      (delete-char -1))))
+
+(defun nntp-encode-text ()
+  "Encode the text in the current buffer."
+  (save-excursion
+    ;; Replace "." at beginning of line with "..".
+    (goto-char (point-min))
+    (while (re-search-forward "^\\." nil t)
+      (insert "."))
+    (goto-char (point-max))
+    ;; Insert newline at the end of the buffer.
+    (unless (bolp)
+      (insert "\n"))
+    ;; Insert `.' at end of buffer (end of text mark).
+    (goto-char (point-max))
+    (insert ".\n")
+    (goto-char (point-min))
+    (while (not (eobp))
+      (end-of-line)
+      (delete-char 1)
+      (insert nntp-end-of-line))))
+
+(defun nntp-retrieve-headers-with-xover (articles &optional fetch-old)
+  (set-buffer nntp-server-buffer)
+  (erase-buffer)
+  (cond
+
+   ;; This server does not talk NOV.
+   ((not nntp-server-xover)
+    nil)
+
+   ;; We don't care about gaps.
+   ((or (not nntp-nov-gap)
+       fetch-old)
+    (nntp-send-xover-command
+     (if fetch-old
+        (if (numberp fetch-old)
+            (max 1 (- (car articles) fetch-old))
+          1)
+       (car articles))
+     (car (last articles)) 'wait)
+
+    (goto-char (point-min))
+    (when (looking-at "[1-5][0-9][0-9] .*\n")
+      (delete-region (point) (progn (forward-line 1) (point))))
+    (while (search-forward "\r" nil t)
+      (replace-match "" t t))
+    (goto-char (point-max))
+    (forward-line -1)
+    (when (looking-at "\\.")
+      (delete-region (point) (progn (forward-line 1) (point)))))
+
+   ;; We do it the hard way.  For each gap, an XOVER command is sent
+   ;; to the server.  We do not wait for a reply from the server, we
+   ;; just send them off as fast as we can.  That means that we have
+   ;; to count the number of responses we get back to find out when we
+   ;; have gotten all we asked for.
+   ((numberp nntp-nov-gap)
+    (let ((count 0)
+         (received 0)
+         last-point
+         in-process-buffer-p
+         (buf nntp-server-buffer)
+         (process-buffer (nntp-find-connection-buffer nntp-server-buffer))
+         first last status)
+      ;; We have to check `nntp-server-xover'.  If it gets set to nil,
+      ;; that means that the server does not understand XOVER, but we
+      ;; won't know that until we try.
+      (while (and nntp-server-xover articles)
+       (setq first (car articles))
+       ;; Search forward until we find a gap, or until we run out of
+       ;; articles.
+       (while (and (cdr articles)
+                   (< (- (nth 1 articles) (car articles)) nntp-nov-gap))
+         (setq articles (cdr articles)))
+
+       (setq in-process-buffer-p (stringp nntp-server-xover))
+        (nntp-send-xover-command first (setq last (car articles)))
+        (setq articles (cdr articles))
+
+       (when (and nntp-server-xover in-process-buffer-p)
+         ;; Don't count tried request.
+         (setq count (1+ count))
+
+         ;; Every 400 requests we have to read the stream in
+         ;; order to avoid deadlocks.
+         (when (or (null articles)     ;All requests have been sent.
+                   (= 1 (% count nntp-maximum-request)))
+
+           (nntp-accept-response)
+           ;; On some Emacs versions the preceding function has a
+           ;; tendency to change the buffer.  Perhaps.  It's quite
+           ;; difficult to reproduce, because it only seems to happen
+           ;; once in a blue moon.
+           (set-buffer process-buffer)
+           (while (progn
+                    (goto-char (or last-point (point-min)))
+                    ;; Count replies.
+                    (while (re-search-forward "^\\([0-9][0-9][0-9]\\) .*\n"
+                                              nil t)
+                      (incf received)
+                      (setq status (match-string 1))
+                      (if (string-match "^[45]" status)
+                          (setq status 'error)
+                        (setq status 'ok)))
+                    (setq last-point (point))
+                    (or (< received count)
+                        (if (eq status 'error)
+                            nil
+                          ;; I haven't started reading the final response
+                          (progn
+                            (goto-char (point-max))
+                            (forward-line -1)
+                            (not (looking-at "^\\.\r?\n"))))))
+             ;; I haven't read the end of the final response
+             (nntp-accept-response)
+             (set-buffer process-buffer))))
+
+        ;; Some nntp servers seem to have an extension to the XOVER
+        ;; extension.  On these servers, requesting an article range
+        ;; preceding the active range does not return an error as
+        ;; specified in the RFC.  What we instead get is the NOV entry
+        ;; for the first available article.  Obviously, a client can
+        ;; use that entry to avoid making unnecessary requests.  The
+        ;; only problem is for a client that assumes that the response
+        ;; will always be within the requested range.  For such a
+        ;; client, we can get N copies of the same entry (one for each
+        ;; XOVER command sent to the server).
+
+        (when (<= count 1)
+          (goto-char (point-min))
+          (when (re-search-forward "^[0-9][0-9][0-9] .*\n\\([0-9]+\\)" nil t)
+            (let ((low-limit (string-to-number
+                             (buffer-substring (match-beginning 1)
+                                               (match-end 1)))))
+              (while (and articles (<= (car articles) low-limit))
+                (setq articles (cdr articles))))))
+        (set-buffer buf))
+
+      (when nntp-server-xover
+       (when in-process-buffer-p
+         (set-buffer buf)
+         (goto-char (point-max))
+         (nnheader-insert-buffer-substring process-buffer)
+         (set-buffer process-buffer)
+         (erase-buffer)
+         (set-buffer buf))
+
+       ;; We remove any "." lines and status lines.
+       (goto-char (point-min))
+       (while (search-forward "\r" nil t)
+         (delete-char -1))
+       (goto-char (point-min))
+       (delete-matching-lines "^\\.$\\|^[1-5][0-9][0-9] ")
+       t))))
+
+  nntp-server-xover)
+
+(defun nntp-send-xover-command (beg end &optional wait-for-reply)
+  "Send the XOVER command to the server."
+  (let ((range (format "%d-%d" beg end))
+       (nntp-inhibit-erase t))
+    (if (stringp nntp-server-xover)
+       ;; If `nntp-server-xover' is a string, then we just send this
+       ;; command.
+       (if wait-for-reply
+           (nntp-send-command-nodelete
+            "\r?\n\\.\r?\n" nntp-server-xover range)
+         ;; We do not wait for the reply.
+         (nntp-send-command-nodelete nil nntp-server-xover range))
+      (let ((commands nntp-xover-commands))
+       ;; `nntp-xover-commands' is a list of possible XOVER commands.
+       ;; We try them all until we get at positive response.
+       (while (and commands (eq nntp-server-xover 'try))
+         (nntp-send-command-nodelete "\r?\n\\.\r?\n" (car commands) range)
+         (with-current-buffer nntp-server-buffer
+           (goto-char (point-min))
+           (and (looking-at "[23]")    ; No error message.
+                ;; We also have to look at the lines.  Some buggy
+                ;; servers give back simple lines with just the
+                ;; article number.  How... helpful.
+                (progn
+                  (forward-line 1)
+                  ;; More text after number, or a dot.
+                  (looking-at "[0-9]+\t...\\|\\.\r?\n"))
+                (setq nntp-server-xover (car commands))))
+         (setq commands (cdr commands)))
+       ;; If none of the commands worked, we disable XOVER.
+       (when (eq nntp-server-xover 'try)
+         (nntp-erase-buffer nntp-server-buffer)
+         (setq nntp-server-xover nil))
+        nntp-server-xover))))
+
+(defun nntp-find-group-and-number (&optional group)
+  (save-excursion
+    (save-restriction
+      ;; FIXME: This is REALLY FISHY: set-buffer after save-restriction?!?
+      (set-buffer nntp-server-buffer)
+      (narrow-to-region (goto-char (point-min))
+                       (or (search-forward "\n\n" nil t) (point-max)))
+      (goto-char (point-min))
+      ;; We first find the number by looking at the status line.
+      (let ((number (and (looking-at "2[0-9][0-9] +\\([0-9]+\\) ")
+                        (string-to-number
+                         (buffer-substring (match-beginning 1)
+                                           (match-end 1)))))
+           newsgroups xref)
+       (and number (zerop number) (setq number nil))
+       (if number
+           ;; Then we find the group name.
+           (setq group
+                 (cond
+                  ;; If there is only one group in the Newsgroups
+                  ;; header, then it seems quite likely that this
+                  ;; article comes from that group, I'd say.
+                  ((and (setq newsgroups
+                              (mail-fetch-field "newsgroups"))
+                        (not (string-match "," newsgroups)))
+                   newsgroups)
+                  ;; If there is more than one group in the
+                  ;; Newsgroups header, then the Xref header should
+                  ;; be filled out.  We hazard a guess that the group
+                  ;; that has this article number in the Xref header
+                  ;; is the one we are looking for.  This might very
+                  ;; well be wrong if this article happens to have
+                  ;; the same number in several groups, but that's
+                  ;; life.
+                  ((and (setq xref (mail-fetch-field "xref"))
+                        number
+                        (string-match
+                         (format "\\([^ :]+\\):%d" number) xref))
+                   (match-string 1 xref))
+                  (t "")))
+         (cond
+          ((and (not nntp-xref-number-is-evil)
+                (setq xref (mail-fetch-field "xref"))
+                (string-match
+                 (if group
+                     (concat "\\(" (regexp-quote group) "\\):\\([0-9]+\\)")
+                   "\\([^ :]+\\):\\([0-9]+\\)")
+                 xref))
+           (setq group (match-string 1 xref)
+                 number (string-to-number (match-string 2 xref))))
+          ((and (setq newsgroups
+                      (mail-fetch-field "newsgroups"))
+                (not (string-match "," newsgroups)))
+           (setq group newsgroups))
+          (group)
+          (t (setq group ""))))
+       (when (string-match "\r" group)
+         (setq group (substring group 0 (match-beginning 0))))
+       (cons group number)))))
+
+(defun nntp-wait-for-string (regexp)
+  "Wait until string arrives in the buffer."
+  (let ((buf (current-buffer))
+       proc)
+    (goto-char (point-min))
+    (while (and (setq proc (get-buffer-process buf))
+               (memq (process-status proc) '(open run))
+               (not (re-search-forward regexp nil t)))
+      (accept-process-output proc 0.1)
+      (set-buffer buf)
+      (goto-char (point-min)))))
+
+
+;; ==========================================================================
+;; Obsolete nntp-open-* connection methods -- drv
+;; ==========================================================================
+
+(defvoo nntp-open-telnet-envuser nil
+  "*If non-nil, telnet session (client and server both) will support the ENVIRON option and not prompt for login name.")
+
+(defvoo nntp-telnet-shell-prompt "bash\\|[$>] *\r?$"
+  "*Regular expression to match the shell prompt on the remote machine.")
+
+(defvoo nntp-rlogin-program "rsh"
+  "*Program used to log in on remote machines.
+The default is \"rsh\", but \"ssh\" is a popular alternative.")
+
+(defvoo nntp-rlogin-parameters '("telnet" "-8" "${NNTPSERVER:=news}" "nntp")
+  "*Parameters to `nntp-open-rlogin'.
+That function may be used as `nntp-open-connection-function'.  In that
+case, this list will be used as the parameter list given to rsh.")
+
+(defvoo nntp-rlogin-user-name nil
+  "*User name on remote system when using the rlogin connect method.")
+
+(defvoo nntp-telnet-parameters
+    '("exec" "telnet" "-8" "${NNTPSERVER:=news}" "nntp")
+  "*Parameters to `nntp-open-telnet'.
+That function may be used as `nntp-open-connection-function'.  In that
+case, this list will be executed as a command after logging in
+via telnet.")
+
+(defvoo nntp-telnet-user-name nil
+  "User name to log in via telnet with.")
+
+(defvoo nntp-telnet-passwd nil
+  "Password to use to log in via telnet with.")
+
+(defun nntp-service-to-port (svc)
+  (cond
+   ((integerp svc) (number-to-string svc))
+   ((string-match "\\`[0-9]+\\'" svc) svc)
+   (t
+    (with-temp-buffer
+      (ignore-errors (insert-file-contents "/etc/services"))
+      (goto-char (point-min))
+      (if (re-search-forward (concat "^" (regexp-quote svc)
+                                     "[ \t]+\\([0-9]+\\)/tcp"))
+          (match-string 1)
+        svc)))))
+
+(defun nntp-open-telnet (buffer)
+  (with-current-buffer buffer
+    (erase-buffer)
+    (let ((proc (apply
+                'start-process
+                "nntpd" buffer nntp-telnet-command nntp-telnet-switches))
+         (case-fold-search t))
+      (when (memq (process-status proc) '(open run))
+       (nntp-wait-for-string "^r?telnet")
+       (process-send-string proc "set escape \^X\n")
+       (cond
+        ((and nntp-open-telnet-envuser nntp-telnet-user-name)
+         (process-send-string proc (concat "open " "-l" nntp-telnet-user-name
+                                           nntp-address "\n")))
+        (t
+         (process-send-string proc (concat "open " nntp-address "\n"))))
+       (cond
+        ((not nntp-open-telnet-envuser)
+         (nntp-wait-for-string "^\r*.?login:")
+         (process-send-string
+          proc (concat
+                (or nntp-telnet-user-name
+                    (setq nntp-telnet-user-name (read-string "login: ")))
+                "\n"))))
+       (nntp-wait-for-string "^\r*.?password:")
+       (process-send-string
+        proc (concat
+              (or nntp-telnet-passwd
+                  (setq nntp-telnet-passwd
+                        (read-passwd "Password: ")))
+              "\n"))
+       (nntp-wait-for-string nntp-telnet-shell-prompt)
+       (process-send-string
+        proc (concat (mapconcat 'identity nntp-telnet-parameters " ") "\n"))
+       (nntp-wait-for-string "^\r*20[01]")
+       (beginning-of-line)
+       (delete-region (point-min) (point))
+       (process-send-string proc "\^]")
+       (nntp-wait-for-string "^r?telnet")
+       (process-send-string proc "mode character\n")
+       (accept-process-output proc 1)
+       (sit-for 1)
+       (goto-char (point-min))
+       (forward-line 1)
+       (delete-region (point) (point-max)))
+      proc)))
+
+(defun nntp-open-rlogin (buffer)
+  "Open a connection to SERVER using rsh."
+  (let ((proc (if nntp-rlogin-user-name
+                 (apply 'start-process
+                        "nntpd" buffer nntp-rlogin-program
+                        nntp-address "-l" nntp-rlogin-user-name
+                        nntp-rlogin-parameters)
+               (apply 'start-process
+                      "nntpd" buffer nntp-rlogin-program nntp-address
+                      nntp-rlogin-parameters))))
+    (with-current-buffer buffer
+      (nntp-wait-for-string "^\r*20[01]")
+      (beginning-of-line)
+      (delete-region (point-min) (point))
+      proc)))
+
+
+;; ==========================================================================
+;; Replacements for the nntp-open-* functions -- drv
+;; ==========================================================================
+
+(defun nntp-open-telnet-stream (buffer)
+  "Open a nntp connection by telnet'ing the news server.
+`nntp-open-netcat-stream' is recommended in place of this function
+because it is more reliable.
+
+Please refer to the following variables to customize the connection:
+- `nntp-pre-command',
+- `nntp-telnet-command',
+- `nntp-telnet-switches',
+- `nntp-address',
+- `nntp-port-number',
+- `nntp-end-of-line'."
+  (let ((command `(,nntp-telnet-command
+                  ,@nntp-telnet-switches
+                  ,nntp-address
+                  ,(nntp-service-to-port nntp-port-number)))
+       proc)
+    (and nntp-pre-command
+        (push nntp-pre-command command))
+    (setq proc (apply 'start-process "nntpd" buffer command))
+    (with-current-buffer buffer
+      (nntp-wait-for-string "^\r*20[01]")
+      (beginning-of-line)
+      (delete-region (point-min) (point))
+      proc)))
+
+(defun nntp-open-via-rlogin-and-telnet (buffer)
+  "Open a connection to an nntp server through an intermediate host.
+First rlogin to the remote host, and then telnet the real news server
+from there.
+`nntp-open-via-rlogin-and-netcat' is recommended in place of this function
+because it is more reliable.
+
+Please refer to the following variables to customize the connection:
+- `nntp-pre-command',
+- `nntp-via-rlogin-command',
+- `nntp-via-rlogin-command-switches',
+- `nntp-via-user-name',
+- `nntp-via-address',
+- `nntp-telnet-command',
+- `nntp-telnet-switches',
+- `nntp-address',
+- `nntp-port-number',
+- `nntp-end-of-line'."
+  (let ((command `(,nntp-via-address
+                  ,nntp-telnet-command
+                  ,@nntp-telnet-switches))
+       proc)
+    (when nntp-via-user-name
+      (setq command `("-l" ,nntp-via-user-name ,@command)))
+    (when nntp-via-rlogin-command-switches
+      (setq command (append nntp-via-rlogin-command-switches command)))
+    (push nntp-via-rlogin-command command)
+    (and nntp-pre-command
+        (push nntp-pre-command command))
+    (setq proc (apply 'start-process "nntpd" buffer command))
+    (with-current-buffer buffer
+      (nntp-wait-for-string "^r?telnet")
+      (process-send-string proc (concat "open " nntp-address " "
+                                       (nntp-service-to-port nntp-port-number)
+                                       "\n"))
+      (nntp-wait-for-string "^\r*20[01]")
+      (beginning-of-line)
+      (delete-region (point-min) (point))
+      (process-send-string proc "\^]")
+      (nntp-wait-for-string "^r?telnet")
+      (process-send-string proc "mode character\n")
+      (accept-process-output proc 1)
+      (sit-for 1)
+      (goto-char (point-min))
+      (forward-line 1)
+      (delete-region (point) (point-max)))
+    proc))
+
+(defun nntp-open-via-rlogin-and-netcat (buffer)
+  "Open a connection to an nntp server through an intermediate host.
+First rlogin to the remote host, and then connect to the real news
+server from there using the netcat command.
+
+Please refer to the following variables to customize the connection:
+- `nntp-pre-command',
+- `nntp-via-rlogin-command',
+- `nntp-via-rlogin-command-switches',
+- `nntp-via-user-name',
+- `nntp-via-address',
+- `nntp-netcat-command',
+- `nntp-netcat-switches',
+- `nntp-address',
+- `nntp-port-number'."
+  (let ((command `(,@(when nntp-pre-command
+                      (list nntp-pre-command))
+                  ,nntp-via-rlogin-command
+                  ,@nntp-via-rlogin-command-switches
+                  ,@(when nntp-via-user-name
+                      (list "-l" nntp-via-user-name))
+                  ,nntp-via-address
+                  ,nntp-netcat-command
+                  ,@nntp-netcat-switches
+                  ,nntp-address
+                  ,(nntp-service-to-port nntp-port-number))))
+    ;; A non-nil connection type results in mightily odd behavior where
+    ;; (process-send-string proc "\^M") ends up sending a "\n" to the
+    ;; ssh process.  --Stef
+    ;; Also a nil connection allow ssh-askpass to work under X11.
+    (let ((process-connection-type nil))
+      (apply 'start-process "nntpd" buffer command))))
+
+(defun nntp-open-netcat-stream (buffer)
+  "Open a connection to an nntp server through netcat.
+I.e. use the `nc' command rather than Emacs's builtin networking code.
+
+Please refer to the following variables to customize the connection:
+- `nntp-pre-command',
+- `nntp-netcat-command',
+- `nntp-netcat-switches',
+- `nntp-address',
+- `nntp-port-number'."
+  (let ((command `(,nntp-netcat-command
+                  ,@nntp-netcat-switches
+                   ,nntp-address
+                   ,(nntp-service-to-port nntp-port-number))))
+    (and nntp-pre-command (push nntp-pre-command command))
+    (let ((process-connection-type nil)) ;See `nntp-open-via-rlogin-and-netcat'.
+      (apply 'start-process "nntpd" buffer command))))
+
+
+(defun nntp-open-via-telnet-and-telnet (buffer)
+  "Open a connection to an nntp server through an intermediate host.
+First telnet the remote host, and then telnet the real news server
+from there.
+
+Please refer to the following variables to customize the connection:
+- `nntp-pre-command',
+- `nntp-via-telnet-command',
+- `nntp-via-telnet-switches',
+- `nntp-via-address',
+- `nntp-via-envuser',
+- `nntp-via-user-name',
+- `nntp-via-user-password',
+- `nntp-via-shell-prompt',
+- `nntp-telnet-command',
+- `nntp-telnet-switches',
+- `nntp-address',
+- `nntp-port-number',
+- `nntp-end-of-line'."
+  (with-current-buffer buffer
+    (erase-buffer)
+    (let ((command `(,nntp-via-telnet-command ,@nntp-via-telnet-switches))
+         (case-fold-search t)
+         proc)
+      (and nntp-pre-command (push nntp-pre-command command))
+      (setq proc (apply 'start-process "nntpd" buffer command))
+      (when (memq (process-status proc) '(open run))
+       (nntp-wait-for-string "^r?telnet")
+       (process-send-string proc "set escape \^X\n")
+       (cond
+        ((and nntp-via-envuser nntp-via-user-name)
+         (process-send-string proc (concat "open " "-l" nntp-via-user-name
+                                           nntp-via-address "\n")))
+        (t
+         (process-send-string proc (concat "open " nntp-via-address
+                                           "\n"))))
+       (when (not nntp-via-envuser)
+         (nntp-wait-for-string "^\r*.?login:")
+         (process-send-string proc
+                              (concat
+                               (or nntp-via-user-name
+                                   (setq nntp-via-user-name
+                                         (read-string "login: ")))
+                               "\n")))
+       (nntp-wait-for-string "^\r*.?password:")
+       (process-send-string proc
+                            (concat
+                             (or nntp-via-user-password
+                                 (setq nntp-via-user-password
+                                       (read-passwd "Password: ")))
+                             "\n"))
+       (nntp-wait-for-string nntp-via-shell-prompt)
+       (let ((real-telnet-command `("exec"
+                                    ,nntp-telnet-command
+                                    ,@nntp-telnet-switches
+                                    ,nntp-address
+                                    ,(nntp-service-to-port nntp-port-number))))
+         (process-send-string proc
+                              (concat (mapconcat 'identity
+                                                 real-telnet-command " ")
+                                      "\n")))
+       (nntp-wait-for-string "^\r*20[01]")
+       (beginning-of-line)
+       (delete-region (point-min) (point))
+       (process-send-string proc "\^]")
+       (nntp-wait-for-string "^r?telnet")
+       (process-send-string proc "mode character\n")
+       (accept-process-output proc 1)
+       (sit-for 1)
+       (goto-char (point-min))
+       (forward-line 1)
+       (delete-region (point) (point-max)))
+      proc)))
+
+(provide 'nntp)
+
+;;; nntp.el ends here
diff --git a/xemacs-packages/gnus/lisp/nnvirtual.el b/xemacs-packages/gnus/lisp/nnvirtual.el
new file mode 100644 (file)
index 0000000..c309d53
--- /dev/null
@@ -0,0 +1,804 @@
+;;; nnvirtual.el --- virtual newsgroups access for Gnus
+
+;; Copyright (C) 1994-2016 Free Software Foundation, Inc.
+
+;; Author: David Moore <dmoore@ucsd.edu>
+;;     Lars Magne Ingebrigtsen <larsi@gnus.org>
+;;     Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; The other access methods (nntp, nnspool, etc) are general news
+;; access methods.  This module relies on Gnus and can not be used
+;; separately.
+
+;;; Code:
+
+(require 'nntp)
+(require 'nnheader)
+(require 'gnus)
+(require 'nnoo)
+(require 'gnus-util)
+(require 'gnus-start)
+(require 'gnus-sum)
+(require 'gnus-msg)
+(eval-when-compile (require 'cl))
+
+(nnoo-declare nnvirtual)
+
+(defvoo nnvirtual-always-rescan t
+  "If non-nil, always scan groups for unread articles when entering a group.
+If this variable is nil and you read articles in a component group
+after the virtual group has been activated, the read articles from the
+component group will show up when you enter the virtual group.")
+
+(defvoo nnvirtual-component-regexp nil
+  "Regexp to match component groups.")
+
+(defvoo nnvirtual-component-groups nil
+  "Component group in this nnvirtual group.")
+
+\f
+
+(defconst nnvirtual-version "nnvirtual 1.1")
+
+(defvoo nnvirtual-current-group nil)
+
+(defvoo nnvirtual-mapping-table nil
+  "Table of rules on how to map between component group and article number to virtual article number.")
+
+(defvoo nnvirtual-mapping-offsets nil
+  "Table indexed by component group to an offset to be applied to article numbers in that group.")
+
+(defvoo nnvirtual-mapping-len 0
+  "Number of articles in this virtual group.")
+
+(defvoo nnvirtual-mapping-reads nil
+  "Compressed sequence of read articles on the virtual group as computed from the unread status of individual component groups.")
+
+(defvoo nnvirtual-mapping-marks nil
+  "Compressed marks alist for the virtual group as computed from the marks of individual component groups.")
+
+(defvoo nnvirtual-info-installed nil
+  "T if we have already installed the group info for this group, and shouldn't blast over it again.")
+
+(defvoo nnvirtual-status-string "")
+
+(autoload 'gnus-cache-articles-in-group "gnus-cache")
+
+\f
+
+;;; Interface functions.
+
+(nnoo-define-basics nnvirtual)
+
+
+(deffoo nnvirtual-retrieve-headers (articles &optional newsgroup
+                                            server fetch-old)
+  (when (nnvirtual-possibly-change-server server)
+    (with-current-buffer nntp-server-buffer
+      (erase-buffer)
+      (if (stringp (car articles))
+         'headers
+       (let ((vbuf (nnheader-set-temp-buffer
+                    (get-buffer-create " *virtual headers*")))
+             (carticles (nnvirtual-partition-sequence articles))
+             (sysname (system-name))
+             cgroup carticle article result prefix)
+         (while carticles
+           (setq cgroup (caar carticles))
+           (setq articles (cdar carticles))
+           (pop carticles)
+           (when (and articles
+                      (gnus-check-server
+                       (gnus-find-method-for-group cgroup) t)
+                      (gnus-request-group cgroup t)
+                      (setq prefix (gnus-group-real-prefix cgroup))
+                      ;; FIX FIX FIX we want to check the cache!
+                      ;; This is probably evil if people have set
+                      ;; gnus-use-cache to nil themselves, but I
+                      ;; have no way of finding the true value of it.
+                      (let ((gnus-use-cache t))
+                        (setq result (gnus-retrieve-headers
+                                      articles cgroup nil))))
+             (set-buffer nntp-server-buffer)
+             ;; If we got HEAD headers, we convert them into NOV
+             ;; headers.  This is slow, inefficient and, come to think
+             ;; of it, downright evil.  So sue me.  I couldn't be
+             ;; bothered to write a header parse routine that could
+             ;; parse a mixed HEAD/NOV buffer.
+             (when (eq result 'headers)
+               (nnvirtual-convert-headers))
+             (goto-char (point-min))
+             (while (not (eobp))
+               (delete-region (point)
+                              (progn
+                                (setq carticle (read nntp-server-buffer))
+                                (point)))
+
+               ;; We remove this article from the articles list, if
+               ;; anything is left in the articles list after going through
+               ;; the entire buffer, then those articles have been
+               ;; expired or canceled, so we appropriately update the
+               ;; component group below.  They should be coming up
+               ;; generally in order, so this shouldn't be slow.
+               (setq articles (delq carticle articles))
+
+               (setq article (nnvirtual-reverse-map-article cgroup carticle))
+               (if (null article)
+                   ;; This line has no reverse mapping, that means it
+                   ;; was an extra article reference returned by nntp.
+                   (progn
+                     (beginning-of-line)
+                     (delete-region (point) (progn (forward-line 1) (point))))
+                 ;; Otherwise insert the virtual article number,
+                 ;; and clean up the xrefs.
+                 (princ article nntp-server-buffer)
+                 (nnvirtual-update-xref-header cgroup carticle
+                                               prefix sysname)
+                 (forward-line 1))
+               )
+
+             (set-buffer vbuf)
+             (goto-char (point-max))
+             (insert-buffer-substring nntp-server-buffer))
+           ;; Anything left in articles is expired or canceled.
+           ;; Could be smart and not tell it about articles already known?
+           (when articles
+             (gnus-group-make-articles-read cgroup articles))
+           )
+
+         ;; The headers are ready for reading, so they are inserted into
+         ;; the nntp-server-buffer, which is where Gnus expects to find
+         ;; them.
+         (prog1
+             (with-current-buffer nntp-server-buffer
+               (erase-buffer)
+               (insert-buffer-substring vbuf)
+               ;; FIX FIX FIX, we should be able to sort faster than
+               ;; this if needed, since each cgroup is sorted, we just
+               ;; need to merge
+               (sort-numeric-fields 1 (point-min) (point-max))
+               'nov)
+           (kill-buffer vbuf)))))))
+
+
+(defvoo nnvirtual-last-accessed-component-group nil)
+
+(deffoo nnvirtual-request-article (article &optional group server buffer)
+  (when (nnvirtual-possibly-change-server server)
+    (if (stringp article)
+       ;; This is a fetch by Message-ID.
+       (cond
+        ((not nnvirtual-last-accessed-component-group)
+         (nnheader-report
+          'nnvirtual "Don't know what server to request from"))
+        (t
+         (save-excursion
+           (when buffer
+             (set-buffer buffer))
+           (let* ((gnus-override-method nil)
+                  (gnus-command-method
+                   (gnus-find-method-for-group
+                    nnvirtual-last-accessed-component-group)))
+             (funcall (gnus-get-function gnus-command-method 'request-article)
+                      article nil (nth 1 gnus-command-method) buffer)))))
+      ;; This is a fetch by number.
+      (let* ((amap (nnvirtual-map-article article))
+            (cgroup (car amap)))
+       (cond
+        ((not amap)
+         (nnheader-report 'nnvirtual "No such article: %s" article))
+        ((not (gnus-check-group cgroup))
+         (nnheader-report
+          'nnvirtual "Can't open server where %s exists" cgroup))
+        ((not (gnus-request-group cgroup t))
+         (nnheader-report 'nnvirtual "Can't open component group %s" cgroup))
+        (t
+         (setq nnvirtual-last-accessed-component-group cgroup)
+         (if buffer
+             (with-current-buffer buffer
+               ;; We bind this here to avoid double decoding.
+               (let ((gnus-article-decode-hook nil))
+                 (gnus-request-article-this-buffer (cdr amap) cgroup)))
+           (gnus-request-article (cdr amap) cgroup))))))))
+
+
+(deffoo nnvirtual-open-server (server &optional defs)
+  (unless (assq 'nnvirtual-component-regexp defs)
+    (push `(nnvirtual-component-regexp ,server)
+         defs))
+  (nnoo-change-server 'nnvirtual server defs)
+  (if nnvirtual-component-groups
+      t
+    (setq nnvirtual-mapping-table nil
+         nnvirtual-mapping-offsets nil
+         nnvirtual-mapping-len 0
+         nnvirtual-mapping-reads nil
+         nnvirtual-mapping-marks nil
+         nnvirtual-info-installed nil)
+    (when nnvirtual-component-regexp
+      ;; Go through the newsrc alist and find all component groups.
+      (let ((newsrc (cdr gnus-newsrc-alist))
+           group)
+       (while (setq group (car (pop newsrc)))
+         (when (string-match nnvirtual-component-regexp group) ; Match
+           ;; Add this group to the list of component groups.
+           (setq nnvirtual-component-groups
+                 (cons group (delete group nnvirtual-component-groups)))))))
+    (if (not nnvirtual-component-groups)
+       (nnheader-report 'nnvirtual "No component groups: %s" server)
+      t)))
+
+
+(deffoo nnvirtual-request-group (group &optional server dont-check info)
+  (nnvirtual-possibly-change-server server)
+  (setq nnvirtual-component-groups
+       (delete (nnvirtual-current-group) nnvirtual-component-groups))
+  (cond
+   ((null nnvirtual-component-groups)
+    (setq nnvirtual-current-group nil)
+    (nnheader-report 'nnvirtual "No component groups in %s" group))
+   (t
+    (setq nnvirtual-current-group group)
+    (nnvirtual-create-mapping dont-check)
+    (when nnvirtual-always-rescan
+      (nnvirtual-request-update-info
+       (nnvirtual-current-group)
+       (gnus-get-info (nnvirtual-current-group))))
+    (nnheader-insert "211 %d 1 %d %s\n"
+                    nnvirtual-mapping-len nnvirtual-mapping-len group))))
+
+
+(deffoo nnvirtual-request-type (group &optional article)
+  (if (not article)
+      'unknown
+    (if (numberp article)
+       (let ((mart (nnvirtual-map-article article)))
+         (if mart
+             (gnus-request-type (car mart) (cdr mart))))
+      (gnus-request-type
+       nnvirtual-last-accessed-component-group nil))))
+
+(deffoo nnvirtual-request-update-mark (group article mark)
+  (let* ((nart (nnvirtual-map-article article))
+        (cgroup (car nart)))
+    (when (and nart
+              (memq mark gnus-auto-expirable-marks)
+              ;; The component group might be a virtual group.
+              (= mark (gnus-request-update-mark cgroup (cdr nart) mark))
+              (gnus-group-auto-expirable-p cgroup))
+      (setq mark gnus-expirable-mark)))
+  mark)
+
+
+(deffoo nnvirtual-close-group (group &optional server)
+  (when (and (nnvirtual-possibly-change-server server)
+            (not (gnus-ephemeral-group-p (nnvirtual-current-group))))
+    (nnvirtual-update-read-and-marked t t))
+  t)
+
+
+(deffoo nnvirtual-request-newgroups (date &optional server)
+  (nnheader-report 'nnvirtual "NEWGROUPS is not supported."))
+
+
+(deffoo nnvirtual-request-list-newsgroups (&optional server)
+  (nnheader-report 'nnvirtual "LIST NEWSGROUPS is not implemented."))
+
+
+(deffoo nnvirtual-request-update-info (group info &optional server)
+  (when (and (nnvirtual-possibly-change-server server)
+            (not nnvirtual-info-installed))
+    ;; Install the precomputed lists atomically, so the virtual group
+    ;; is not left in a half-way state in case of C-g.
+    (gnus-atomic-progn
+      (setcar (cddr info) nnvirtual-mapping-reads)
+      (if (nthcdr 3 info)
+         (setcar (nthcdr 3 info) nnvirtual-mapping-marks)
+       (when nnvirtual-mapping-marks
+         (setcdr (nthcdr 2 info) (list nnvirtual-mapping-marks))))
+      (setq nnvirtual-info-installed t))
+    t))
+
+
+(deffoo nnvirtual-catchup-group (group &optional server all)
+  (when (and (nnvirtual-possibly-change-server server)
+            (not (gnus-ephemeral-group-p (nnvirtual-current-group))))
+    ;; copy over existing marks first, in case they set anything
+    (nnvirtual-update-read-and-marked nil nil)
+    ;; do a catchup on all component groups
+    (let ((gnus-group-marked (copy-sequence nnvirtual-component-groups))
+         (gnus-expert-user t))
+      ;; Make sure all groups are activated.
+      (mapc
+       (lambda (g)
+        (when (not (numberp (gnus-group-unread g)))
+          (gnus-activate-group g)))
+       nnvirtual-component-groups)
+      (with-current-buffer gnus-group-buffer
+       (gnus-group-catchup-current nil all)))))
+
+
+(deffoo nnvirtual-find-group-art (group article)
+  "Return the real group and article for virtual GROUP and ARTICLE."
+  (nnvirtual-map-article article))
+
+
+(deffoo nnvirtual-request-post (&optional server)
+  (if (not gnus-message-group-art)
+      (nnheader-report 'nnvirtual "Can't post to an nnvirtual group")
+    (let ((group (car (nnvirtual-find-group-art
+                      (car gnus-message-group-art)
+                      (cdr gnus-message-group-art)))))
+      (gnus-request-post (gnus-find-method-for-group group)))))
+
+
+(deffoo nnvirtual-request-expire-articles (articles group
+                                                   &optional server force)
+  (nnvirtual-possibly-change-server server)
+  (setq nnvirtual-component-groups
+       (delete (nnvirtual-current-group) nnvirtual-component-groups))
+  (let (unexpired)
+    (dolist (group nnvirtual-component-groups)
+      (setq unexpired (nconc unexpired
+                            (mapcar
+                             #'(lambda (article)
+                                 (nnvirtual-reverse-map-article
+                                  group article))
+                             (gnus-uncompress-range
+                              (gnus-group-expire-articles-1 group))))))
+    (sort (delq nil unexpired) '<)))
+
+\f
+;;; Internal functions.
+
+(defun nnvirtual-convert-headers ()
+  "Convert HEAD headers into NOV headers."
+  (with-current-buffer nntp-server-buffer
+    (let* ((dependencies (make-vector 100 0))
+          (headers (gnus-get-newsgroup-headers dependencies)))
+      (erase-buffer)
+      (mapc 'nnheader-insert-nov headers))))
+
+
+(defun nnvirtual-update-xref-header (group article prefix sysname)
+  "Edit current NOV header in current buffer to have an xref to the component group, and also server prefix any existing xref lines."
+  ;; Move to beginning of Xref field, creating a slot if needed.
+  (beginning-of-line)
+  (looking-at
+   "[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t")
+  (goto-char (match-end 0))
+  (unless (search-forward "\t" (point-at-eol) 'move)
+    (insert "\t"))
+
+  ;; Remove any spaces at the beginning of the Xref field.
+  (while (eq (char-after (1- (point))) ? )
+    (forward-char -1)
+    (delete-char 1))
+
+  (insert "Xref: " sysname " " group ":")
+  (princ article (current-buffer))
+  (insert " ")
+
+  ;; If there were existing xref lines, clean them up to have the correct
+  ;; component server prefix.
+  (save-restriction
+    (narrow-to-region (point)
+                     (or (search-forward "\t" (point-at-eol) t)
+                         (point-at-eol)))
+    (goto-char (point-min))
+    (when (re-search-forward "Xref: *[^\n:0-9 ]+ *" nil t)
+      (replace-match "" t t))
+    (goto-char (point-min))
+    (when (re-search-forward
+          (concat (regexp-quote (gnus-group-real-name group)) ":[0-9]+")
+          nil t)
+      (replace-match "" t t))
+    (unless (eobp)
+      (insert " ")
+      (when (not (string= "" prefix))
+       (while (re-search-forward "[^ ]+:[0-9]+" nil t)
+         (save-excursion
+           (goto-char (match-beginning 0))
+           (insert prefix))))))
+
+  ;; Ensure a trailing \t.
+  (end-of-line)
+  (or (eq (char-after (1- (point))) ?\t)
+      (insert ?\t)))
+
+
+(defun nnvirtual-possibly-change-server (server)
+  (or (not server)
+      (nnoo-current-server-p 'nnvirtual server)
+      (nnvirtual-open-server server)))
+
+
+(defun nnvirtual-update-read-and-marked (read-p update-p)
+  "Copy marks from the virtual group to the component groups.
+If READ-P is not nil, update the (un)read status of the components.
+If UPDATE-P is not nil, call gnus-group-update-group on the components."
+  (when nnvirtual-current-group
+    (let ((unreads (and read-p
+                       (nnvirtual-partition-sequence
+                        (gnus-list-of-unread-articles
+                         (nnvirtual-current-group)))))
+         (type-marks
+          (delq nil
+                (mapcar (lambda (ml)
+                          (if (eq (car ml) 'score)
+                              nil
+                            (cons (car ml)
+                                  (nnvirtual-partition-sequence (cdr ml)))))
+                        (gnus-info-marks (gnus-get-info
+                                          (nnvirtual-current-group))))))
+         type groups info)
+
+      ;; Ok, atomically move all of the (un)read info, clear any old
+      ;; marks, and move all of the current marks.  This way if someone
+      ;; hits C-g, you won't leave the component groups in a half-way state.
+      (progn
+       ;; move (un)read
+       ;; bind for workaround guns-update-read-articles
+       (let ((gnus-newsgroup-active nil))
+         (dolist (entry unreads)
+           (gnus-update-read-articles (car entry) (cdr entry))))
+
+       ;; clear all existing marks on the component groups
+       (dolist (group nnvirtual-component-groups)
+         (when (and (setq info (gnus-get-info group))
+                    (gnus-info-marks info))
+           (gnus-info-set-marks
+            info
+            (if (assq 'score (gnus-info-marks info))
+                (list (assq 'score (gnus-info-marks info)))
+              nil))))
+
+       ;; Ok, currently type-marks is an assq list with keys of a mark type,
+       ;; with data of an assq list with keys of component group names
+       ;; and the articles which correspond to that key/group pair.
+       (dolist (mark type-marks)
+         (setq type (car mark))
+         (setq groups (cdr mark))
+         (dolist (carticles groups)
+           (gnus-add-marked-articles (car carticles) type (cdr carticles)
+                                     nil t))))
+
+      ;; possibly update the display, it is really slow
+      (when update-p
+       (dolist (group nnvirtual-component-groups)
+         (gnus-group-update-group group t))))))
+
+
+(defun nnvirtual-current-group ()
+  "Return the prefixed name of the current nnvirtual group."
+  (concat "nnvirtual:" nnvirtual-current-group))
+
+
+
+;;; This is currently O(kn^2) to merge n lists of length k.
+;;; You could do it in O(knlogn), but we have a small n, and the
+;;; overhead of the other approach is probably greater.
+(defun nnvirtual-merge-sorted-lists (&rest lists)
+  "Merge many sorted lists of numbers."
+  (if (null (cdr lists))
+      (car lists)
+    (sort (apply 'nconc lists) '<)))
+
+
+;;; We map between virtual articles and real articles in a manner
+;;; which keeps the size of the virtual active list the same as the
+;;; sum of the component active lists.
+
+;;; To achieve fair mixing of the groups, the last article in each of
+;;; N component groups will be in the last N articles in the virtual
+;;; group.
+
+;;; If you have 3 components A, B and C, with articles 1-8, 1-5, and
+;;; 6-7 respectively, then the virtual article numbers look like:
+;;;
+;;;  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15
+;;;  A1 A2 A3 A4 B1 A5 B2 A6 B3 A7 B4 C6 A8 B5 C7
+
+;;; To compute these mappings we generate a couple tables and then
+;;; do some fast operations on them.  Tables for the example above:
+;;;
+;;; Offsets - [(A 0) (B -3) (C -1)]
+;;;
+;;;               a  b  c  d  e
+;;; Mapping - ([  3  0  1  3  0 ]
+;;;            [  6  3  2  9  3 ]
+;;;            [  8  6  3 15  9 ])
+;;;
+;;; (note column 'e' is different in real algorithm, which is slightly
+;;;  different than described here, but this gives you the methodology.)
+;;;
+;;; The basic idea is this, when going from component->virtual, apply
+;;; the appropriate offset to the article number.  Then search the first
+;;; column of the table for a row where 'a' is less than or equal to the
+;;; modified number.  You can see that only group A can therefore go to
+;;; the first row, groups A and B to the second, and all to the last.
+;;; The third column of the table is telling us the number of groups
+;;; which might be able to reach that row (it might increase by more than
+;;; 1 if several groups have the same size).
+;;; Then column 'b' provides an additional offset you apply when you have
+;;; found the correct row.  You then multiply by 'c' and add on the groups
+;;; _position_ in the offset table.  The basic idea here is that on
+;;; any given row we are going to map back and forth using X'=X*c+Y and
+;;; X=(X'/c), Y=(X' mod c).  Then once you've done this transformation,
+;;; you apply a final offset from column 'e' to give the virtual article.
+;;;
+;;; Going the other direction, you instead search on column 'd' instead
+;;; of 'a', and apply everything in reverse order.
+
+;;; Convert component -> virtual:
+;;; set num = num - Offset(group)
+;;; find first row in Mapping where num <= 'a'
+;;; num = (num-'b')*c + Position(group) + 'e'
+
+;;; Convert virtual -> component:
+;;; find first row in Mapping where num <= 'd'
+;;; num = num - 'e'
+;;; group_pos = num mod 'c'
+;;; num = (num / 'c') + 'b' + Offset(group_pos)
+
+;;; Easy no? :)
+;;;
+;;; Well actually, you need to keep column e offset smaller by the 'c'
+;;; column for that line, and always add 1 more when going from
+;;; component -> virtual.  Otherwise you run into a problem with
+;;; unique reverse mapping.
+
+(defun nnvirtual-map-article (article)
+  "Return a cons of the component group and article corresponding to the given virtual ARTICLE."
+  (let ((table nnvirtual-mapping-table)
+       entry group-pos)
+    (while (and table
+               (> article (aref (car table) 3)))
+      (setq table (cdr table)))
+    (when (and table
+              (> article 0))
+      (setq entry (car table))
+      (setq article (- article (aref entry 4) 1))
+      (setq group-pos (mod article (aref entry 2)))
+      (cons (car (aref nnvirtual-mapping-offsets group-pos))
+           (+ (/ article (aref entry 2))
+              (aref entry 1)
+              (cdr (aref nnvirtual-mapping-offsets group-pos)))
+           ))
+    ))
+
+
+
+(defun nnvirtual-reverse-map-article (group article)
+  "Return the virtual article number corresponding to the given component GROUP and ARTICLE."
+  (when (numberp article)
+    (let ((table nnvirtual-mapping-table)
+         (group-pos 0)
+         entry)
+      (while (not (string= group (car (aref nnvirtual-mapping-offsets
+                                           group-pos))))
+       (setq group-pos (1+ group-pos)))
+      (setq article (- article (cdr (aref nnvirtual-mapping-offsets
+                                         group-pos))))
+      (while (and table
+                 (> article (aref (car table) 0)))
+       (setq table (cdr table)))
+      (setq entry (car table))
+      (when (and entry
+                (> article 0)
+                (< group-pos (aref entry 2))) ; article not out of range below
+       (+ (aref entry 4)
+          group-pos
+          (* (- article (aref entry 1))
+             (aref entry 2))
+          1))
+      )))
+
+
+(defsubst nnvirtual-reverse-map-sequence (group articles)
+  "Return list of virtual article numbers for all ARTICLES in GROUP.
+The ARTICLES should be sorted, and can be a compressed sequence.
+If any of the article numbers has no corresponding virtual article,
+then it is left out of the result."
+  (when (numberp (cdr-safe articles))
+    (setq articles (list articles)))
+  (let (result a i j new-a)
+    (while (setq a (pop articles))
+      (if (atom a)
+         (setq i a
+               j a)
+       (setq i (car a)
+             j (cdr a)))
+      (while (<= i j)
+       ;; If this is slow, you can optimize by moving article checking
+       ;; into here.  You don't have to recompute the group-pos,
+       ;; nor scan the table every time.
+       (when (setq new-a (nnvirtual-reverse-map-article group i))
+         (push new-a result))
+       (setq i (1+ i))))
+    (nreverse result)))
+
+
+(defun nnvirtual-partition-sequence (articles)
+  "Return an association list of component article numbers.
+These are indexed by elements of nnvirtual-component-groups, based on
+the sequence ARTICLES of virtual article numbers.  ARTICLES should be
+sorted, and can be a compressed sequence.  If any of the article
+numbers has no corresponding component article, then it is left out of
+the result."
+  (when (numberp (cdr-safe articles))
+    (setq articles (list articles)))
+  (let ((carticles (mapcar 'list nnvirtual-component-groups))
+       a i j article entry)
+    (while (setq a (pop articles))
+      (if (atom a)
+         (setq i a
+               j a)
+       (setq i (car a)
+             j (cdr a)))
+      (while (<= i j)
+       (when (setq article (nnvirtual-map-article i))
+         (setq entry (assoc (car article) carticles))
+         (setcdr entry (cons (cdr article) (cdr entry))))
+       (setq i (1+ i))))
+    (mapc (lambda (x) (setcdr x (nreverse (cdr x))))
+         carticles)
+    carticles))
+
+
+(defun nnvirtual-create-mapping (dont-check)
+  "Build the tables necessary to map between component (group, article) to virtual article.
+Generate the set of read messages and marks for the virtual group
+based on the marks on the component groups."
+  (let ((cnt 0)
+       (tot 0)
+       (M 0)
+       (i 0)
+       actives all-unreads all-marks
+       active min max size unreads marks
+       next-M next-tot
+       reads beg)
+    ;; Ok, we loop over all component groups and collect a lot of
+    ;; information:
+    ;; Into actives we place (g size max), where size is max-min+1.
+    ;; Into all-unreads we put (g unreads).
+    ;; Into all-marks we put (g marks).
+    ;; We also increment cnt and tot here, and compute M (max of sizes).
+    (mapc (lambda (g)
+           (setq active (or (and dont-check
+                                 (gnus-active g))
+                            (gnus-activate-group g))
+                 min (car active)
+                 max (cdr active))
+           (when (and active (>= max min) (not (zerop max)))
+             ;; store active information
+             (push (list g (- max min -1) max) actives)
+             ;; collect unread/mark info for later
+             (setq unreads (gnus-list-of-unread-articles g))
+             (setq marks (gnus-info-marks (gnus-get-info g)))
+             (when gnus-use-cache
+               (push (cons 'cache
+                           (gnus-cache-articles-in-group g))
+                     marks))
+             (push (cons g unreads) all-unreads)
+             (push (cons g marks) all-marks)
+             ;; count groups, total #articles, and max size
+             (setq size (- max min -1))
+             (setq cnt (1+ cnt)
+                   tot (+ tot size)
+                   M (max M size))))
+         nnvirtual-component-groups)
+
+    ;; Number of articles in the virtual group.
+    (setq nnvirtual-mapping-len tot)
+
+
+    ;; We want the actives list sorted by size, to build the tables.
+    (setq actives (sort actives (lambda (g1 g2) (< (nth 1 g1) (nth 1 g2)))))
+
+    ;; Build the offset table.  Largest sized groups are at the front.
+    (setq nnvirtual-mapping-offsets
+         (vconcat
+          (nreverse
+           (mapcar (lambda (entry)
+                     (cons (nth 0 entry)
+                           (- (nth 2 entry) M)))
+                   actives))))
+
+    ;; Build the mapping table.
+    (setq nnvirtual-mapping-table nil)
+    (setq actives (mapcar (lambda (entry) (nth 1 entry)) actives))
+    (while actives
+      (setq size (car actives))
+      (setq next-M (- M size))
+      (setq next-tot (- tot (* cnt size)))
+      ;; make current row in table
+      (push (vector M next-M cnt tot (- next-tot cnt))
+           nnvirtual-mapping-table)
+      ;; update M and tot
+      (setq M next-M)
+      (setq tot next-tot)
+      ;; subtract the current size from all entries.
+      (setq actives (mapcar (lambda (x) (- x size)) actives))
+      ;; remove anything that went to 0.
+      (while (and actives
+                 (= (car actives) 0))
+       (pop actives)
+       (setq cnt (- cnt 1))))
+
+
+    ;; Now that the mapping tables are generated, we can convert
+    ;; and combine the separate component unreads and marks lists
+    ;; into single lists of virtual article numbers.
+    (setq unreads (apply 'nnvirtual-merge-sorted-lists
+                        (mapcar (lambda (x)
+                                  (nnvirtual-reverse-map-sequence
+                                   (car x) (cdr x)))
+                                all-unreads)))
+    (setq marks (mapcar
+                (lambda (type)
+                  (cons (cdr type)
+                        (gnus-compress-sequence
+                         (apply
+                          'nnvirtual-merge-sorted-lists
+                          (mapcar (lambda (x)
+                                    (nnvirtual-reverse-map-sequence
+                                     (car x)
+                                     (cdr (assq (cdr type) (cdr x)))))
+                                  all-marks)))))
+                gnus-article-mark-lists))
+
+    ;; Remove any empty marks lists, and store.
+    (setq nnvirtual-mapping-marks nil)
+    (dolist (mark marks)
+      (when (cdr mark)
+       (push mark nnvirtual-mapping-marks)))
+
+    ;; We need to convert the unreads to reads.  We compress the
+    ;; sequence as we go, otherwise it could be huge.
+    (while (and (<= (incf i) nnvirtual-mapping-len)
+               unreads)
+      (if (= i (car unreads))
+         (setq unreads (cdr unreads))
+       ;; try to get a range.
+       (setq beg i)
+       (while (and (<= (incf i) nnvirtual-mapping-len)
+                   (not (= i (car unreads)))))
+       (setq i (- i 1))
+       (if (= i beg)
+           (push i reads)
+         (push (cons beg i) reads))
+       ))
+    (when (<= i nnvirtual-mapping-len)
+      (if (= i nnvirtual-mapping-len)
+         (push i reads)
+       (push (cons i nnvirtual-mapping-len) reads)))
+
+    ;; Store the reads list for later use.
+    (setq nnvirtual-mapping-reads (nreverse reads))
+
+    ;; Throw flag to show we changed the info.
+    (setq nnvirtual-info-installed nil)
+    ))
+
+(provide 'nnvirtual)
+
+;;; nnvirtual.el ends here
diff --git a/xemacs-packages/gnus/lisp/nnweb.el b/xemacs-packages/gnus/lisp/nnweb.el
new file mode 100644 (file)
index 0000000..925f65f
--- /dev/null
@@ -0,0 +1,603 @@
+;;; nnweb.el --- retrieving articles via web search engines
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'nnoo)
+(require 'message)
+(require 'gnus-util)
+(require 'gnus)
+(require 'nnmail)
+(require 'mm-util)
+(require 'mm-url)
+(eval-and-compile
+  (ignore-errors
+    (require 'url)))
+
+(nnoo-declare nnweb)
+
+(defvoo nnweb-directory (nnheader-concat gnus-directory "nnweb/")
+  "Where nnweb will save its files.")
+
+(defvoo nnweb-type 'google
+  "What search engine type is being used.
+Valid types include `google', `dejanews', and `gmane'.")
+
+(defvar nnweb-type-definition
+  '((google
+     (id . "http://www.google.com/groups?as_umsgid=%s&hl=en&dmode=source")
+     (result . "http://groups.google.com/group/%s/msg/%s?dmode=source")
+     (article . nnweb-google-wash-article)
+     (reference . identity)
+     (map . nnweb-google-create-mapping)
+     (search . nnweb-google-search)
+     (address . "http://groups.google.com/groups")
+     (base    . "http://groups.google.com")
+     (identifier . nnweb-google-identity))
+    (dejanews ;; alias of google
+     (id . "http://www.google.com/groups?as_umsgid=%s&hl=en&dmode=source")
+     (result . "http://groups.google.com/group/%s/msg/%s?dmode=source")
+     (article . nnweb-google-wash-article)
+     (reference . identity)
+     (map . nnweb-google-create-mapping)
+     (search . nnweb-google-search)
+     (address . "http://groups.google.com/groups")
+     (base    . "http://groups.google.com")
+     (identifier . nnweb-google-identity))
+    (gmane
+     (article . nnweb-gmane-wash-article)
+     (id . "http://gmane.org/view.php?group=%s")
+     (reference . identity)
+     (map . nnweb-gmane-create-mapping)
+     (search . nnweb-gmane-search)
+     (address . "http://search.gmane.org/nov.php")
+     (identifier . nnweb-gmane-identity)))
+  "Type-definition alist.")
+
+(defvoo nnweb-search nil
+  "Search string to feed to Google.")
+
+(defvoo nnweb-max-hits 999
+  "Maximum number of hits to display.")
+
+(defvoo nnweb-ephemeral-p nil
+  "Whether this nnweb server is ephemeral.")
+
+;;; Internal variables
+
+(defvoo nnweb-articles nil)
+(defvoo nnweb-buffer nil)
+(defvoo nnweb-group-alist nil)
+(defvoo nnweb-group nil)
+(defvoo nnweb-hashtb nil)
+
+;;; Interface functions
+
+(nnoo-define-basics nnweb)
+
+(deffoo nnweb-retrieve-headers (articles &optional group server fetch-old)
+  (nnweb-possibly-change-server group server)
+  (with-current-buffer nntp-server-buffer
+    (erase-buffer)
+    (let (article header)
+      (mm-with-unibyte-current-buffer
+       (while (setq article (pop articles))
+         (when (setq header (cadr (assq article nnweb-articles)))
+           (nnheader-insert-nov header))))
+      'nov)))
+
+(deffoo nnweb-request-scan (&optional group server)
+  (nnweb-possibly-change-server group server)
+  (if nnweb-ephemeral-p
+      (setq nnweb-hashtb (gnus-make-hashtable 4095))
+    (unless nnweb-articles
+      (nnweb-read-overview group)))
+  (funcall (nnweb-definition 'map))
+  (unless nnweb-ephemeral-p
+    (nnweb-write-active)
+    (nnweb-write-overview group)))
+
+(deffoo nnweb-request-group (group &optional server dont-check info)
+  (nnweb-possibly-change-server group server)
+  (unless (or nnweb-ephemeral-p
+             dont-check
+             nnweb-articles)
+    (nnweb-read-overview group))
+  (cond
+   ((not nnweb-articles)
+    (nnheader-report 'nnweb "No matching articles"))
+   (t
+    (let ((active (if nnweb-ephemeral-p
+                     (cons (caar nnweb-articles)
+                           (caar (last nnweb-articles)))
+                   (cadr (assoc group nnweb-group-alist)))))
+      (nnheader-report 'nnweb "Opened group %s" group)
+      (nnheader-insert
+       "211 %d %d %d %s\n" (length nnweb-articles)
+       (car active) (cdr active) group)))))
+
+(deffoo nnweb-close-group (group &optional server)
+  (nnweb-possibly-change-server group server)
+  (when (gnus-buffer-live-p nnweb-buffer)
+    (with-current-buffer nnweb-buffer
+      (set-buffer-modified-p nil)
+      (kill-buffer nnweb-buffer)))
+  t)
+
+(deffoo nnweb-request-article (article &optional group server buffer)
+  (nnweb-possibly-change-server group server)
+  (with-current-buffer (or buffer nntp-server-buffer)
+    (let* ((header (cadr (assq article nnweb-articles)))
+          (url (and header (mail-header-xref header))))
+      (when (or (and url
+                    (mm-with-unibyte-current-buffer
+                      (mm-url-insert url)))
+               (and (stringp article)
+                    (nnweb-definition 'id t)
+                    (let ((fetch (nnweb-definition 'id))
+                          art active)
+                      (when (string-match "^<\\(.*\\)>$" article)
+                        (setq art (match-string 1 article)))
+                      (when (and fetch art)
+                        (setq url (format fetch
+                                          (mm-url-form-encode-xwfu art)))
+                        (mm-with-unibyte-current-buffer
+                          (mm-url-insert url))
+                        (if (nnweb-definition 'reference t)
+                            (setq article
+                                  (funcall (nnweb-definition
+                                            'reference) article)))))))
+       (unless nnheader-callback-function
+         (funcall (nnweb-definition 'article)))
+       (nnheader-report 'nnweb "Fetched article %s" article)
+       (cons group (and (numberp article) article))))))
+
+(deffoo nnweb-close-server (&optional server)
+  (when (and (nnweb-server-opened server)
+            (gnus-buffer-live-p nnweb-buffer))
+    (with-current-buffer nnweb-buffer
+      (set-buffer-modified-p nil)
+      (kill-buffer nnweb-buffer)))
+  (nnoo-close-server 'nnweb server))
+
+(deffoo nnweb-request-list (&optional server)
+  (nnweb-possibly-change-server nil server)
+  (with-current-buffer nntp-server-buffer
+    (nnmail-generate-active (list (assoc server nnweb-group-alist)))
+    t))
+
+(deffoo nnweb-request-update-info (group info &optional server))
+
+(deffoo nnweb-asynchronous-p ()
+  nil)
+
+(deffoo nnweb-request-create-group (group &optional server args)
+  (nnweb-possibly-change-server nil server)
+  (nnweb-request-delete-group group)
+  (push `(,group ,(cons 1 0)) nnweb-group-alist)
+  (nnweb-write-active)
+  t)
+
+(deffoo nnweb-request-delete-group (group &optional force server)
+  (nnweb-possibly-change-server group server)
+  (gnus-alist-pull group nnweb-group-alist t)
+  (nnweb-write-active)
+  (gnus-delete-file (nnweb-overview-file group))
+  t)
+
+(nnoo-define-skeleton nnweb)
+
+;;; Internal functions
+
+(defun nnweb-read-overview (group)
+  "Read the overview of GROUP and build the map."
+  (when (file-exists-p (nnweb-overview-file group))
+    (mm-with-unibyte-buffer
+      (nnheader-insert-file-contents (nnweb-overview-file group))
+      (goto-char (point-min))
+      (let (header)
+       (while (not (eobp))
+         (setq header (nnheader-parse-nov))
+         (forward-line 1)
+         (push (list (mail-header-number header)
+                     header (mail-header-xref header))
+               nnweb-articles)
+         (nnweb-set-hashtb header (car nnweb-articles)))))))
+
+(defun nnweb-write-overview (group)
+  "Write the overview file for GROUP."
+  (with-temp-file (nnweb-overview-file group)
+    (let ((articles nnweb-articles))
+      (while articles
+       (nnheader-insert-nov (cadr (pop articles)))))))
+
+(defun nnweb-set-hashtb (header data)
+  (gnus-sethash (nnweb-identifier (mail-header-xref header))
+               data nnweb-hashtb))
+
+(defun nnweb-get-hashtb (url)
+  (gnus-gethash (nnweb-identifier url) nnweb-hashtb))
+
+(defun nnweb-identifier (ident)
+  (funcall (nnweb-definition 'identifier) ident))
+
+(defun nnweb-overview-file (group)
+  "Return the name of the overview file of GROUP."
+  (nnheader-concat nnweb-directory group ".overview"))
+
+(defun nnweb-write-active ()
+  "Save the active file."
+  (gnus-make-directory nnweb-directory)
+  (with-temp-file (nnheader-concat nnweb-directory "active")
+    (prin1 `(setq nnweb-group-alist ',nnweb-group-alist) (current-buffer))))
+
+(defun nnweb-read-active ()
+  "Read the active file."
+  (load (nnheader-concat nnweb-directory "active") t t t))
+
+(defun nnweb-definition (type &optional noerror)
+  "Return the definition of TYPE."
+  (let ((def (cdr (assq type (assq nnweb-type nnweb-type-definition)))))
+    (when (and (not def)
+              (not noerror))
+      (error "Undefined definition %s" type))
+    def))
+
+(defun nnweb-possibly-change-server (&optional group server)
+  (when server
+    (unless (nnweb-server-opened server)
+      (nnweb-open-server server))
+    (nnweb-init server))
+  (unless nnweb-group-alist
+    (nnweb-read-active))
+  (unless nnweb-hashtb
+    (setq nnweb-hashtb (gnus-make-hashtable 4095)))
+  (when group
+    (setq nnweb-group group)))
+
+(defun nnweb-init (server)
+  "Initialize buffers and such."
+  (unless (gnus-buffer-live-p nnweb-buffer)
+    (setq nnweb-buffer
+         (save-current-buffer
+            (nnheader-set-temp-buffer
+             (format " *nnweb %s %s %s*"
+                     nnweb-type nnweb-search server))
+            (mm-disable-multibyte)
+            (current-buffer)))))
+
+;;;
+;;; groups.google.com
+;;;
+
+(defun nnweb-google-wash-article ()
+  ;; We have Google's masked e-mail addresses here.  :-/
+  (let ((case-fold-search t)
+       (start-re "<pre>[\r\n ]*")
+       (end-re "[\r\n ]*</pre>"))
+    (goto-char (point-min))
+    (if (save-excursion
+         (or (re-search-forward "The requested message.*could not be found."
+                                nil t)
+             (not (and (re-search-forward start-re nil t)
+                       (re-search-forward end-re nil t)))))
+       ;; FIXME: Don't know how to indicate "not found".
+       ;; Should this function throw an error?  --rsteib
+       (progn
+         (gnus-message 3 "Requested article not found")
+         (erase-buffer))
+      (delete-region (point-min)
+                    (re-search-forward start-re))
+      (goto-char (point-min))
+      (delete-region (progn
+                      (re-search-forward end-re)
+                      (match-beginning 0))
+                    (point-max))
+      (mm-url-decode-entities))))
+
+(defun nnweb-google-parse-1 (&optional Message-ID)
+  "Parse search result in current buffer."
+  (let ((i 0)
+       (case-fold-search t)
+       (active (cadr (assoc nnweb-group nnweb-group-alist)))
+       Subject Score Date Newsgroups From
+       map url mid)
+    (unless active
+      (push (list nnweb-group (setq active (cons 1 0)))
+           nnweb-group-alist))
+    ;; Go through all the article hits on this page.
+    (goto-char (point-min))
+    (while
+       (re-search-forward
+        "a +href=\"/group/\\([^>\"]+\\)/browse_thread/[^>]+#\\([0-9a-f]+\\)"
+        nil t)
+      (setq Newsgroups (match-string-no-properties 1)
+           ;; Note: Starting with Google Groups 2, `mid' is a Google-internal
+           ;; ID, not a proper Message-ID.
+           mid (match-string-no-properties 2)
+           url (format
+                (nnweb-definition 'result) Newsgroups mid))
+      (narrow-to-region (search-forward ">" nil t)
+                       (search-forward "</a>" nil t))
+      (mm-url-remove-markup)
+      (mm-url-decode-entities)
+      (setq Subject (buffer-string))
+      (goto-char (point-max))
+      (widen)
+      (narrow-to-region (point)
+                       (search-forward "</table" nil t))
+
+      (mm-url-remove-markup)
+      (mm-url-decode-entities)
+      (goto-char (point-max))
+      (when
+         (re-search-backward
+          "^\\(?:\\(\\w+\\) \\([0-9]+\\)\\|\\S-+\\)\\(?: \\([0-9]\\{4\\}\\)\\)? by ?\\(.*\\)"
+          nil t)
+       (setq Date (if (match-string 1)
+                      (format "%s %s 00:00:00 %s"
+                              (match-string 1)
+                              (match-string 2)
+                              (or (match-string 3)
+                                  (format-time-string "%Y")))
+                    (current-time-string)))
+       (setq From (match-string 4)))
+      (widen)
+      (incf i)
+      (unless (nnweb-get-hashtb url)
+       (push
+        (list
+         (incf (cdr active))
+         (make-full-mail-header
+          (cdr active) (if Newsgroups
+                           (concat  "(" Newsgroups ") " Subject)
+                         Subject)
+          From Date (or Message-ID mid)
+          nil 0 0 url))
+        map)
+       (nnweb-set-hashtb (cadar map) (car map))))
+    map))
+
+(defun nnweb-google-reference (id)
+  (let ((map (nnweb-google-parse-1 id)) header)
+    (setq nnweb-articles
+         (nconc nnweb-articles map))
+    (when (setq header (cadar map))
+      (mm-with-unibyte-current-buffer
+       (mm-url-insert (mail-header-xref header)))
+      (caar map))))
+
+(defun nnweb-google-create-mapping ()
+  "Perform the search and create a number-to-url alist."
+  (with-current-buffer nnweb-buffer
+    (erase-buffer)
+    (nnheader-message 7 "Searching google...")
+    (when (funcall (nnweb-definition 'search) nnweb-search)
+       (let ((more t)
+             (i 0))
+         (while more
+           (setq nnweb-articles
+                 (nconc nnweb-articles (nnweb-google-parse-1)))
+           ;; Check if there are more articles to fetch
+           (goto-char (point-min))
+           (incf i 100)
+           (if (or (not (re-search-forward
+                         "<a [^>]+href=\"\n?\\([^>\" \n\t]+\\)[^<]*<img[^>]+src=[^>]+next"
+                         nil t))
+                   (>= i nnweb-max-hits))
+               (setq more nil)
+             ;; Yup, there are more articles
+             (setq more (concat (nnweb-definition 'base) (match-string 1)))
+           (when more
+             (erase-buffer)
+             (nnheader-message 7 "Searching google...(%d)" i)
+             (mm-url-insert more))))
+         ;; Return the articles in the right order.
+         (nnheader-message 7 "Searching google...done")
+         (setq nnweb-articles
+               (sort nnweb-articles 'car-less-than-car))))))
+
+(defun nnweb-google-search (search)
+  (mm-url-insert
+   (concat
+    (nnweb-definition 'address)
+    "?"
+    (mm-url-encode-www-form-urlencoded
+     `(("q" . ,search)
+       ("num" . ,(number-to-string
+                 (min 100 nnweb-max-hits)))
+       ("hq" . "")
+       ("hl" . "en")
+       ("lr" . "")
+       ("safe" . "off")
+       ("sites" . "groups")
+       ("filter" . "0")))))
+  t)
+
+(defun nnweb-google-identity (url)
+  "Return a unique identifier based on URL."
+  (if (string-match "selm=\\([^ &>]+\\)" url)
+      (match-string 1 url)
+    url))
+
+;;;
+;;; gmane.org
+;;;
+(defun nnweb-gmane-create-mapping ()
+  "Perform the search and create a number-to-url alist."
+  (with-current-buffer nnweb-buffer
+    (let ((case-fold-search t)
+         (active (or (cadr (assoc nnweb-group nnweb-group-alist))
+                     (cons 1 0)))
+         map)
+      (erase-buffer)
+      (nnheader-message 7 "Searching Gmane..." )
+      (when (funcall (nnweb-definition 'search) nnweb-search)
+       (goto-char (point-min))
+       ;; Skip the status line
+       (forward-line 1)
+       ;; Thanks to Olly Betts we now have NOV lines in our buffer!
+       (while (not (eobp))
+         (unless (or (eolp) (looking-at "\x0d"))
+           (let ((header (nnheader-parse-nov)))
+             (let ((xref (mail-header-xref header))
+                   (from (mail-header-from header))
+                   (subject (mail-header-subject header))
+                   (rfc2047-encoding-type 'mime))
+               (when (string-match " \\([^:]+\\)[:/]\\([0-9]+\\)" xref)
+                 (mail-header-set-xref
+                  header
+                  (format "http://article.gmane.org/%s/%s/raw"
+                          (match-string 1 xref)
+                          (match-string 2 xref))))
+
+               ;; Add host part to gmane-encrypted addresses
+               (when (string-match "@$" from)
+                 (mail-header-set-from header
+                                       (concat from "public.gmane.org")))
+
+               (mail-header-set-subject header
+                                        (rfc2047-encode-string subject))
+
+               (unless (nnweb-get-hashtb (mail-header-xref header))
+                 (mail-header-set-number header (incf (cdr active)))
+                 (push (list (mail-header-number header) header) map)
+                 (nnweb-set-hashtb (cadar map) (car map))))))
+         (forward-line 1)))
+      (nnheader-message 7 "Searching Gmane...done")
+      (setq nnweb-articles
+           (sort (nconc nnweb-articles map) 'car-less-than-car)))))
+
+(defun nnweb-gmane-wash-article ()
+  (let ((case-fold-search t))
+    (goto-char (point-min))
+    (when (search-forward "<!--X-Head-of-Message-->" nil t)
+      (delete-region (point-min) (point))
+      (goto-char (point-min))
+      (while (looking-at "^<li><em>\\([^ ]+\\)</em>.*</li>")
+       (replace-match "\\1\\2" t)
+       (forward-line 1))
+      (mm-url-remove-markup))))
+
+(defun nnweb-gmane-search (search)
+  (mm-url-insert
+   (concat
+    (nnweb-definition 'address)
+    "?"
+    (mm-url-encode-www-form-urlencoded
+     `(("query" . ,search)
+       ("HITSPERPAGE" . ,(number-to-string nnweb-max-hits))
+       ;;("TOPDOC" . "1000")
+       ))))
+  (setq buffer-file-name nil)
+  (unless (featurep 'xemacs) (set-buffer-multibyte t))
+  (mm-decode-coding-region (point-min) (point-max) 'utf-8)
+  t)
+
+(defun nnweb-gmane-identity (url)
+  "Return a unique identifier based on URL."
+  (if (string-match "group=\\(.+\\)" url)
+      (match-string 1 url)
+    url))
+
+;;;
+;;; General web interface utility functions
+;;;
+
+(defun nnweb-insert-html (parse)
+  "Insert HTML based on a w3 parse tree."
+  (if (stringp parse)
+      ;; We used to call nnheader-string-as-multibyte here, but it cannot
+      ;; be right, so I removed it.  If a bug shows up because of this change,
+      ;; please do not blindly revert the change, but help me find the real
+      ;; cause of the bug instead.  --Stef
+      (insert parse)
+    (insert "<" (symbol-name (car parse)) " ")
+    (insert (mapconcat
+            (lambda (param)
+              (concat (symbol-name (car param)) "="
+                      (prin1-to-string
+                       (if (consp (cdr param))
+                           (cadr param)
+                         (cdr param)))))
+            (nth 1 parse)
+            " "))
+    (insert ">\n")
+    (mapc 'nnweb-insert-html (nth 2 parse))
+    (insert "</" (symbol-name (car parse)) ">\n")))
+
+(defun nnweb-parse-find (type parse &optional maxdepth)
+  "Find the element of TYPE in PARSE."
+  (catch 'found
+    (nnweb-parse-find-1 type parse maxdepth)))
+
+(defun nnweb-parse-find-1 (type contents maxdepth)
+  (when (or (null maxdepth)
+           (not (zerop maxdepth)))
+    (when (consp contents)
+      (when (eq (car contents) type)
+       (throw 'found contents))
+      (when (listp (cdr contents))
+       (dolist (element contents)
+         (when (consp element)
+           (nnweb-parse-find-1 type element
+                               (and maxdepth (1- maxdepth)))))))))
+
+(defun nnweb-parse-find-all (type parse)
+  "Find all elements of TYPE in PARSE."
+  (catch 'found
+    (nnweb-parse-find-all-1 type parse)))
+
+(defun nnweb-parse-find-all-1 (type contents)
+  (let (result)
+    (when (consp contents)
+      (if (eq (car contents) type)
+         (push contents result)
+       (when (listp (cdr contents))
+         (dolist (element contents)
+           (when (consp element)
+             (setq result
+                   (nconc result (nnweb-parse-find-all-1 type element))))))))
+    result))
+
+(defvar nnweb-text)
+(defun nnweb-text (parse)
+  "Return a list of text contents in PARSE."
+  (let ((nnweb-text nil))
+    (nnweb-text-1 parse)
+    (nreverse nnweb-text)))
+
+(defun nnweb-text-1 (contents)
+  (dolist (element contents)
+    (if (stringp element)
+       (push element nnweb-text)
+      (when (and (consp element)
+                (listp (cdr element)))
+       (nnweb-text-1 element)))))
+
+(provide 'nnweb)
+
+;;; nnweb.el ends here
diff --git a/xemacs-packages/gnus/lisp/ntlm.el b/xemacs-packages/gnus/lisp/ntlm.el
new file mode 100644 (file)
index 0000000..6d49426
--- /dev/null
@@ -0,0 +1,692 @@
+;;; ntlm.el --- NTLM (NT LanManager) authentication support
+
+;; Copyright (C) 2001, 2007-2016 Free Software Foundation, Inc.
+
+;; Author: Taro Kawagishi <tarok@transpulse.org>
+;; Maintainer: Thomas Fitzsimmons <fitzsim@fitzsim.org>
+;; Keywords: NTLM, SASL, comm
+;; Version: 2.0.0
+;; Created: February 2001
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This library is a direct translation of the Samba release 2.2.0
+;; implementation of Windows NT and LanManager compatible password
+;; encryption.
+;;
+;; Interface functions:
+;;
+;; ntlm-build-auth-request
+;;   This will return a binary string, which should be used in the
+;;   base64 encoded form and it is the caller's responsibility to encode
+;;   the returned string with base64.
+;;
+;; ntlm-build-auth-response
+;;   It is the caller's responsibility to pass a base64 decoded string
+;;   (which will be a binary string) as the first argument and to
+;;   encode the returned string with base64.  The second argument user
+;;   should be given in user@domain format.
+;;
+;; ntlm-get-password-hashes
+;;
+;;
+;; NTLM authentication procedure example:
+;;
+;;  1. Open a network connection to the Exchange server at the IMAP port (143)
+;;  2. Receive an opening message such as:
+;;     "* OK Microsoft Exchange IMAP4rev1 server version 5.5.2653.7 (XXXX) ready"
+;;  3. Ask for IMAP server capability by sending "NNN capability"
+;;  4. Receive a capability message such as:
+;;     "* CAPABILITY IMAP4 IMAP4rev1 IDLE LITERAL+ LOGIN-REFERRALS MAILBOX-REFERRALS NAMESPACE AUTH=NTLM"
+;;  5. Ask for NTLM authentication by sending a string
+;;     "NNN authenticate ntlm"
+;;  6. Receive continuation acknowledgment "+"
+;;  7. Send NTLM authentication request generated by 'ntlm-build-auth-request
+;;  8. Receive NTLM challenge string following acknowledgment "+"
+;;  9. Generate response to challenge by 'ntlm-build-auth-response
+;;     (here two hash function values of the user password are encrypted)
+;; 10. Receive authentication completion message such as
+;;     "NNN OK AUTHENTICATE NTLM completed."
+
+;;; Code:
+
+(require 'md4)
+(require 'hmac-md5)
+(require 'calc)
+
+(defgroup ntlm nil
+  "NTLM (NT LanManager) authentication."
+  :version "25.1"
+  :group 'comm)
+
+(defcustom ntlm-compatibility-level 5
+  "The NTLM compatibility level.
+Ordered from 0, the oldest, least-secure level through 5, the
+newest, most-secure level.  Newer servers may reject lower
+levels.  At levels 3 through 5, send LMv2 and NTLMv2 responses.
+At levels 0, 1 and 2, send LM and NTLM responses.
+
+In this implementation, levels 0, 1 and 2 are the same (old,
+insecure), and levels 3, 4 and 5 are the same (new, secure).  If
+NTLM authentication isn't working at level 5, try level 0.  The
+other levels are only present because other clients have six
+levels."
+  :type '(choice (const 0) (const 1) (const 2) (const 3) (const 4) (const 5)))
+
+;;;
+;;; NTLM authentication interface functions
+
+(defun ntlm-build-auth-request (user &optional domain)
+  "Return the NTLM authentication request string for USER and DOMAIN.
+USER is a string representing a user name to be authenticated and
+DOMAIN is a NT domain.  USER can include a NT domain part as in
+user@domain where the string after @ is used as the domain if DOMAIN
+is not given."
+  (interactive)
+  (let ((request-ident (concat "NTLMSSP" (make-string 1 0)))
+       (request-msgType (concat (make-string 1 1) (make-string 3 0)))
+                                       ;0x01 0x00 0x00 0x00
+       (request-flags (concat (make-string 1 7) (make-string 1 178)
+                              (make-string 1 8) (make-string 1 0)))
+                                       ;0x07 0xb2 0x08 0x00
+       lu ld off-d off-u)
+    (when (string-match "@" user)
+      (unless domain
+       (setq domain (substring user (1+ (match-beginning 0)))))
+      (setq user (substring user 0 (match-beginning 0))))
+    ;; set fields offsets within the request struct
+    (setq lu (length user))
+    (setq ld (length domain))
+    (setq off-u 32)                    ;offset to the string 'user
+    (setq off-d (+ 32 lu))             ;offset to the string 'domain
+    ;; pack the request struct in a string
+    (concat request-ident              ;8 bytes
+           request-msgType     ;4 bytes
+           request-flags               ;4 bytes
+           (md4-pack-int16 lu) ;user field, count field
+           (md4-pack-int16 lu) ;user field, max count field
+           (md4-pack-int32 (cons 0 off-u)) ;user field, offset field
+           (md4-pack-int16 ld) ;domain field, count field
+           (md4-pack-int16 ld) ;domain field, max count field
+           (md4-pack-int32 (cons 0 off-d)) ;domain field, offset field
+           user                        ;buffer field
+           domain              ;buffer field
+           )))
+
+(eval-when-compile
+  (defmacro ntlm-string-as-unibyte (string)
+    (if (fboundp 'string-as-unibyte)
+       `(string-as-unibyte ,string)
+      string))
+  (defmacro ntlm-string-make-unibyte (string)
+    (if (fboundp 'string-make-unibyte)
+       `(string-make-unibyte ,string)
+      string))
+  (defmacro ntlm-unibyte-string (&rest bytes)
+    (if (fboundp 'unibyte-string)
+       `(unibyte-string ,@bytes)
+      `(concat (vector ,@bytes)))))
+
+(eval-and-compile
+  (autoload 'sha1 "sha1")
+  (if (fboundp 'secure-hash)
+      (defalias 'ntlm-secure-hash 'secure-hash)
+    (defun ntlm-secure-hash (algorithm object &optional start end binary)
+      "Return the secure hash of OBJECT, a buffer or string.
+ALGORITHM is a symbol specifying the hash to use: md5, sha1.
+
+The two optional arguments START and END are positions specifying for
+which part of OBJECT to compute the hash.  If nil or omitted, uses the
+whole OBJECT.
+
+If BINARY is non-nil, returns a string in binary form."
+      (cond ((eq algorithm 'md5)
+            (if binary
+                (let* ((hex (md5 object start end))
+                       (len (length hex))
+                       (beg 0)
+                       rest)
+                  (while (< beg len)
+                    (push (ntlm-string-make-unibyte
+                           (char-to-string
+                            (string-to-number
+                             (substring hex beg (setq beg (+ beg 2)))
+                             16)))
+                          rest))
+                  (apply #'concat (nreverse rest)))
+              (md5 object start end)))
+           ((eq algorithm 'sha1)
+            (sha1 object start end binary))
+           (t
+            (error "(ntlm-secure-hash) Unsupported algorithm: %s"
+                   algorithm))))))
+
+(defun ntlm-compute-timestamp ()
+  "Compute an NTLMv2 timestamp.
+Return a unibyte string representing the number of tenths of a
+microsecond since January 1, 1601 as a 64-bit little-endian
+signed integer."
+  (let* ((s-to-tenths-of-us "mul(add(lsh($1,16),$2),10000000)")
+        (us-to-tenths-of-us "mul($3,10)")
+        (ps-to-tenths-of-us "idiv($4,100000)")
+        (tenths-of-us-since-jan-1-1601
+         (apply 'calc-eval (concat "add(add(add("
+                                   s-to-tenths-of-us ","
+                                   us-to-tenths-of-us "),"
+                                   ps-to-tenths-of-us "),"
+                                   ;; tenths of microseconds between
+                                   ;; 1601-01-01 and 1970-01-01
+                                   "116444736000000000)")
+                ;; add trailing zeros to support old current-time formats
+                'rawnum (append (current-time) '(0 0))))
+        result-bytes)
+    (dotimes (byte 8)
+      (push (calc-eval "and($1,16#FF)" 'rawnum tenths-of-us-since-jan-1-1601)
+           result-bytes)
+      (setq tenths-of-us-since-jan-1-1601
+           (calc-eval "rsh($1,8,64)" 'rawnum tenths-of-us-since-jan-1-1601)))
+    (apply 'ntlm-unibyte-string (nreverse result-bytes))))
+
+(defun ntlm-generate-nonce ()
+  "Generate a random nonce, not to be used more than once.
+Return a random eight byte unibyte string."
+  (ntlm-unibyte-string
+   (random 256) (random 256) (random 256) (random 256)
+   (random 256) (random 256) (random 256) (random 256)))
+
+(defun ntlm-build-auth-response (challenge user password-hashes)
+  "Return the response string to a challenge string CHALLENGE given by
+the NTLM based server for the user USER and the password hash list
+PASSWORD-HASHES.  NTLM uses two hash values which are represented
+by PASSWORD-HASHES.  PASSWORD-HASHES should be a return value of
+ (list (ntlm-smb-passwd-hash password) (ntlm-md4hash password))"
+  (let* ((rchallenge (ntlm-string-as-unibyte challenge))
+        ;; get fields within challenge struct
+        ;;(ident (substring rchallenge 0 8))   ;ident, 8 bytes
+        ;;(msgType (substring rchallenge 8 12))        ;msgType, 4 bytes
+        (uDomain (substring rchallenge 12 20)) ;uDomain, 8 bytes
+        (flags (substring rchallenge 20 24))   ;flags, 4 bytes
+        (challengeData (substring rchallenge 24 32)) ;challengeData, 8 bytes
+        uDomain-len uDomain-offs
+        ;; response struct and its fields
+        lmRespData                     ;lmRespData, 24 bytes
+        ntRespData                     ;ntRespData, variable length
+        domain                         ;ascii domain string
+        lu ld ln off-lm off-nt off-d off-u off-w off-s)
+    ;; extract domain string from challenge string
+    (setq uDomain-len (md4-unpack-int16 (substring uDomain 0 2)))
+    (setq uDomain-offs (md4-unpack-int32 (substring uDomain 4 8)))
+    (setq domain
+         (ntlm-unicode2ascii (substring challenge
+                                        (cdr uDomain-offs)
+                                        (+ (cdr uDomain-offs) uDomain-len))
+                             (/ uDomain-len 2)))
+    ;; overwrite domain in case user is given in <user>@<domain> format
+    (when (string-match "@" user)
+      (setq domain (substring user (1+ (match-beginning 0))))
+      (setq user (substring user 0 (match-beginning 0))))
+
+    (unless (and (integerp ntlm-compatibility-level)
+                (>= ntlm-compatibility-level 0)
+                (<= ntlm-compatibility-level 5))
+      (error "Invalid ntlm-compatibility-level value"))
+    (if (and (>= ntlm-compatibility-level 3)
+            (<= ntlm-compatibility-level 5))
+       ;; extract target information block, if it is present
+       (if (< (cdr uDomain-offs) 48)
+           (error "Failed to find target information block")
+         (let* ((targetInfo-len (md4-unpack-int16 (substring rchallenge
+                                                             40 42)))
+                (targetInfo-offs (md4-unpack-int32 (substring rchallenge
+                                                              44 48)))
+                (targetInfo (substring rchallenge
+                                       (cdr targetInfo-offs)
+                                       (+ (cdr targetInfo-offs)
+                                          targetInfo-len)))
+                (upcase-user (upcase (ntlm-ascii2unicode user (length user))))
+                (ntlmv2-hash (hmac-md5 (concat upcase-user
+                                               (ntlm-ascii2unicode
+                                                domain (length domain)))
+                                       (cadr password-hashes)))
+                (nonce (ntlm-generate-nonce))
+                (blob (concat (make-string 2 1)
+                              (make-string 2 0)        ; blob signature
+                              (make-string 4 0)        ; reserved value
+                              (ntlm-compute-timestamp) ; timestamp
+                              nonce                    ; client nonce
+                              (make-string 4 0)        ; unknown
+                              targetInfo               ; target info
+                              (make-string 4 0)))      ; unknown
+                ;; for reference: LMv2 interim calculation
+                ;; (lm-interim (hmac-md5 (concat challengeData nonce)
+                ;;                       ntlmv2-hash))
+                (nt-interim (hmac-md5 (concat challengeData blob)
+                                      ntlmv2-hash)))
+           ;; for reference: LMv2 field, but match other clients that
+           ;; send all zeros
+           ;; (setq lmRespData (concat lm-interim nonce))
+           (setq lmRespData (make-string 24 0))
+           (setq ntRespData (concat nt-interim blob))))
+      ;; compatibility level is 2, 1 or 0
+      ;; level 2 should be treated specially but it's not clear how,
+      ;; so just treat it the same as levels 0 and 1
+      ;; check if "negotiate NTLM2 key" flag is set in type 2 message
+      (if (not (zerop (logand (aref flags 2) 8)))
+         (let (randomString
+               sessionHash)
+           ;; generate NTLM2 session response data
+           (setq randomString (ntlm-generate-nonce))
+           (setq sessionHash (ntlm-secure-hash
+                              'md5 (concat challengeData randomString)
+                              nil nil t))
+           (setq sessionHash (substring sessionHash 0 8))
+           (setq lmRespData (concat randomString (make-string 16 0)))
+           (setq ntRespData (ntlm-smb-owf-encrypt
+                             (cadr password-hashes) sessionHash)))
+       ;; generate response data
+       (setq lmRespData
+             (ntlm-smb-owf-encrypt (car password-hashes) challengeData))
+       (setq ntRespData
+             (ntlm-smb-owf-encrypt (cadr password-hashes) challengeData))))
+
+    ;; get offsets to fields to pack the response struct in a string
+    (setq lu (length user))
+    (setq ld (length domain))
+    (setq ln (length ntRespData))
+    (setq off-lm 64)                   ;offset to string 'lmResponse
+    (setq off-nt (+ 64 24))            ;offset to string 'ntResponse
+    (setq off-d (+ 64 24 ln))          ;offset to string 'uDomain
+    (setq off-u (+ 64 24 ln (* 2 ld))) ;offset to string 'uUser
+    (setq off-w (+ 64 24 ln (* 2 (+ ld lu)))) ;offset to string 'uWks
+    (setq off-s (+ 64 24 ln (* 2 (+ ld lu lu)))) ;offset to string 'sessionKey
+    ;; pack the response struct in a string
+    (concat "NTLMSSP\0"                        ;response ident field, 8 bytes
+           (md4-pack-int32 '(0 . 3))   ;response msgType field, 4 bytes
+
+           ;; lmResponse field, 8 bytes
+           ;;AddBytes(response,lmResponse,lmRespData,24);
+           (md4-pack-int16 24)         ;len field
+           (md4-pack-int16 24)         ;maxlen field
+           (md4-pack-int32 (cons 0 off-lm)) ;field offset
+
+           ;; ntResponse field, 8 bytes
+           ;;AddBytes(response,ntResponse,ntRespData,ln);
+           (md4-pack-int16 ln) ;len field
+           (md4-pack-int16 ln) ;maxlen field
+           (md4-pack-int32 (cons 0 off-nt)) ;field offset
+
+           ;; uDomain field, 8 bytes
+           ;;AddUnicodeString(response,uDomain,domain);
+           ;;AddBytes(response, uDomain, udomain, 2*ld);
+           (md4-pack-int16 (* 2 ld))   ;len field
+           (md4-pack-int16 (* 2 ld))   ;maxlen field
+           (md4-pack-int32 (cons 0 off-d)) ;field offset
+
+           ;; uUser field, 8 bytes
+           ;;AddUnicodeString(response,uUser,u);
+           ;;AddBytes(response, uUser, uuser, 2*lu);
+           (md4-pack-int16 (* 2 lu))   ;len field
+           (md4-pack-int16 (* 2 lu))   ;maxlen field
+           (md4-pack-int32 (cons 0 off-u)) ;field offset
+
+           ;; uWks field, 8 bytes
+           ;;AddUnicodeString(response,uWks,u);
+           (md4-pack-int16 (* 2 lu))   ;len field
+           (md4-pack-int16 (* 2 lu))   ;maxlen field
+           (md4-pack-int32 (cons 0 off-w)) ;field offset
+
+           ;; sessionKey field, 8 bytes
+           ;;AddString(response,sessionKey,NULL);
+           (md4-pack-int16 0)          ;len field
+           (md4-pack-int16 0)          ;maxlen field
+           (md4-pack-int32 (cons 0 (- off-s off-lm))) ;field offset
+
+           ;; flags field, 4 bytes
+           flags                       ;
+
+           ;; buffer field
+           lmRespData                  ;lmResponse, 24 bytes
+           ntRespData                  ;ntResponse, 24 bytes
+           (ntlm-ascii2unicode domain  ;Unicode domain string, 2*ld bytes
+                               (length domain)) ;
+           (ntlm-ascii2unicode user    ;Unicode user string, 2*lu bytes
+                               (length user)) ;
+           (ntlm-ascii2unicode user    ;Unicode user string, 2*lu bytes
+                               (length user)) ;
+           )))
+
+(defun ntlm-get-password-hashes (password)
+  "Return a pair of SMB hash and NT MD4 hash of the given password PASSWORD."
+  (list (ntlm-smb-passwd-hash password)
+       (ntlm-md4hash password)))
+
+(defun ntlm-ascii2unicode (str len)
+  "Convert an ASCII string into a NT Unicode string, which is
+little-endian utf16."
+  (let ((utf (make-string (* 2 len) 0)) (i 0) val)
+    (while (and (< i len)
+               (not (zerop (setq val (aref str i)))))
+      (aset utf (* 2 i) val)
+      (aset utf (1+ (* 2 i)) 0)
+      (setq i (1+ i)))
+    utf))
+
+(defun ntlm-unicode2ascii (str len)
+  "Extract 7 bits ASCII part of a little endian utf16 string STR of length LEN."
+  (let ((buf (make-string len 0)) (i 0) (j 0))
+    (while (< i len)
+      (aset buf i (logand (aref str j) 127)) ;(string-to-number "7f" 16)
+      (setq i (1+ i)
+           j (+ 2 j)))
+    buf))
+
+(defun ntlm-smb-passwd-hash (passwd)
+  "Return the SMB password hash string of 16 bytes long for the given password
+string PASSWD.  PASSWD is truncated to 14 bytes if longer."
+  (let ((len (min (length passwd) 14)))
+    (ntlm-smb-des-e-p16
+     (concat (substring (upcase passwd) 0 len) ;fill top 14 bytes with passwd
+            (make-string (- 15 len) 0)))))
+
+(defun ntlm-smb-owf-encrypt (passwd c8)
+  "Return the response string of 24 bytes long for the given password
+string PASSWD based on the DES encryption.  PASSWD is of at most 14
+bytes long and the challenge string C8 of 8 bytes long."
+  (let ((len (min (length passwd) 16)) p22)
+    (setq p22 (concat (substring passwd 0 len) ;fill top 16 bytes with passwd
+                     (make-string (- 22 len) 0)))
+    (ntlm-smb-des-e-p24 p22 c8)))
+
+(defun ntlm-smb-des-e-p24 (p22 c8)
+  "Return a 24 bytes hashed string for a 21 bytes string P22 and a 8 bytes
+string C8."
+  (concat (ntlm-smb-hash c8 p22 t)             ;hash first 8 bytes of p22
+         (ntlm-smb-hash c8 (substring p22 7) t)
+         (ntlm-smb-hash c8 (substring p22 14) t)))
+
+(defconst ntlm-smb-sp8 [75 71 83 33 64 35 36 37])
+
+(defun ntlm-smb-des-e-p16 (p15)
+  "Return a 16 bytes hashed string for a 15 bytes string P15."
+  (concat (ntlm-smb-hash ntlm-smb-sp8 p15 t)   ;hash of first 8 bytes of p15
+         (ntlm-smb-hash ntlm-smb-sp8           ;hash of last 8 bytes of p15
+                        (substring p15 7) t)))
+
+(defun ntlm-smb-hash (in key forw)
+  "Return the hash string of length 8 for a string IN of length 8 and
+a string KEY of length 8.  FORW is t or nil."
+  (let ((out (make-string 8 0))
+       outb                            ;string of length 64
+       (inb (make-string 64 0))
+       (keyb (make-string 64 0))
+       (key2 (ntlm-smb-str-to-key key))
+       (i 0) aa)
+    (while (< i 64)
+      (unless (zerop (logand (aref in (/ i 8)) (lsh 1 (- 7 (% i 8)))))
+       (aset inb i 1))
+      (unless (zerop (logand (aref key2 (/ i 8)) (lsh 1 (- 7 (% i 8)))))
+       (aset keyb i 1))
+      (setq i (1+ i)))
+    (setq outb (ntlm-smb-dohash inb keyb forw))
+    (setq i 0)
+    (while (< i 64)
+      (unless (zerop (aref outb i))
+       (setq aa (aref out (/ i 8)))
+       (aset out (/ i 8)
+             (logior aa (lsh 1 (- 7 (% i 8))))))
+      (setq i (1+ i)))
+    out))
+
+(defun ntlm-smb-str-to-key (str)
+  "Return a string of length 8 for the given string STR of length 7."
+  (let ((key (make-string 8 0))
+       (i 7))
+    (aset key 0 (lsh (aref str 0) -1))
+    (aset key 1 (logior
+                (lsh (logand (aref str 0) 1) 6)
+                (lsh (aref str 1) -2)))
+    (aset key 2 (logior
+                (lsh (logand (aref str 1) 3) 5)
+                (lsh (aref str 2) -3)))
+    (aset key 3 (logior
+                (lsh (logand (aref str 2) 7) 4)
+                (lsh (aref str 3) -4)))
+    (aset key 4 (logior
+                (lsh (logand (aref str 3) 15) 3)
+                (lsh (aref str 4) -5)))
+    (aset key 5 (logior
+                (lsh (logand (aref str 4) 31) 2)
+                (lsh (aref str 5) -6)))
+    (aset key 6 (logior
+                (lsh (logand (aref str 5) 63) 1)
+                (lsh (aref str 6) -7)))
+    (aset key 7 (logand (aref str 6) 127))
+    (while (>= i 0)
+      (aset key i (lsh (aref key i) 1))
+      (setq i (1- i)))
+    key))
+
+(defconst ntlm-smb-perm1 [57 49 41 33 25 17  9
+                    1 58 50 42 34 26 18
+                    10  2 59 51 43 35 27
+                    19 11  3 60 52 44 36
+                    63 55 47 39 31 23 15
+                    7 62 54 46 38 30 22
+                    14  6 61 53 45 37 29
+                    21 13  5 28 20 12  4])
+
+(defconst ntlm-smb-perm2 [14 17 11 24  1  5
+                    3 28 15  6 21 10
+                    23 19 12  4 26  8
+                    16  7 27 20 13  2
+                    41 52 31 37 47 55
+                    30 40 51 45 33 48
+                    44 49 39 56 34 53
+                    46 42 50 36 29 32])
+
+(defconst ntlm-smb-perm3 [58 50 42 34 26 18 10  2
+                    60 52 44 36 28 20 12  4
+                    62 54 46 38 30 22 14  6
+                    64 56 48 40 32 24 16  8
+                    57 49 41 33 25 17  9  1
+                    59 51 43 35 27 19 11  3
+                    61 53 45 37 29 21 13  5
+                    63 55 47 39 31 23 15  7])
+
+(defconst ntlm-smb-perm4 [32  1  2  3  4  5
+                    4  5  6  7  8  9
+                    8  9 10 11 12 13
+                    12 13 14 15 16 17
+                    16 17 18 19 20 21
+                    20 21 22 23 24 25
+                    24 25 26 27 28 29
+                    28 29 30 31 32  1])
+
+(defconst ntlm-smb-perm5 [16  7 20 21
+                    29 12 28 17
+                    1 15 23 26
+                    5 18 31 10
+                    2  8 24 14
+                    32 27  3  9
+                    19 13 30  6
+                    22 11  4 25])
+
+(defconst ntlm-smb-perm6 [40  8 48 16 56 24 64 32
+                    39  7 47 15 55 23 63 31
+                    38  6 46 14 54 22 62 30
+                    37  5 45 13 53 21 61 29
+                    36  4 44 12 52 20 60 28
+                    35  3 43 11 51 19 59 27
+                    34  2 42 10 50 18 58 26
+                    33  1 41  9 49 17 57 25])
+
+(defconst ntlm-smb-sc [1 1 2 2 2 2 2 2 1 2 2 2 2 2 2 1])
+
+(defconst ntlm-smb-sbox [[[14  4 13  1  2 15 11  8  3 10  6 12  5  9  0  7]
+                    [ 0 15  7  4 14  2 13  1 10  6 12 11  9  5  3  8]
+                    [ 4  1 14  8 13  6  2 11 15 12  9  7  3 10  5  0]
+                    [15 12  8  2  4  9  1  7  5 11  3 14 10  0  6 13]]
+                   [[15  1  8 14  6 11  3  4  9  7  2 13 12  0  5 10]
+                    [ 3 13  4  7 15  2  8 14 12  0  1 10  6  9 11  5]
+                    [ 0 14  7 11 10  4 13  1  5  8 12  6  9  3  2 15]
+                    [13  8 10  1  3 15  4  2 11  6  7 12  0  5 14  9]]
+                   [[10  0  9 14  6  3 15  5  1 13 12  7 11  4  2  8]
+                    [13  7  0  9  3  4  6 10  2  8  5 14 12 11 15  1]
+                    [13  6  4  9  8 15  3  0 11  1  2 12  5 10 14  7]
+                    [ 1 10 13  0  6  9  8  7  4 15 14  3 11  5  2 12]]
+                   [[ 7 13 14  3  0  6  9 10  1  2  8  5 11 12  4 15]
+                    [13  8 11  5  6 15  0  3  4  7  2 12  1 10 14  9]
+                    [10  6  9  0 12 11  7 13 15  1  3 14  5  2  8  4]
+                    [ 3 15  0  6 10  1 13  8  9  4  5 11 12  7  2 14]]
+                   [[ 2 12  4  1  7 10 11  6  8  5  3 15 13  0 14  9]
+                    [14 11  2 12  4  7 13  1  5  0 15 10  3  9  8  6]
+                    [ 4  2  1 11 10 13  7  8 15  9 12  5  6  3  0 14]
+                    [11  8 12  7  1 14  2 13  6 15  0  9 10  4  5  3]]
+                   [[12  1 10 15  9  2  6  8  0 13  3  4 14  7  5 11]
+                    [10 15  4  2  7 12  9  5  6  1 13 14  0 11  3  8]
+                    [ 9 14 15  5  2  8 12  3  7  0  4 10  1 13 11  6]
+                    [ 4  3  2 12  9  5 15 10 11 14  1  7  6  0  8 13]]
+                   [[ 4 11  2 14 15  0  8 13  3 12  9  7  5 10  6  1]
+                    [13  0 11  7  4  9  1 10 14  3  5 12  2 15  8  6]
+                    [ 1  4 11 13 12  3  7 14 10 15  6  8  0  5  9  2]
+                    [ 6 11 13  8  1  4 10  7  9  5  0 15 14  2  3 12]]
+                   [[13  2  8  4  6 15 11  1 10  9  3 14  5  0 12  7]
+                    [ 1 15 13  8 10  3  7  4 12  5  6 11  0 14  9  2]
+                    [ 7 11  4  1  9 12 14  2  0  6 10 13 15  3  5  8]
+                    [ 2  1 14  7  4 10  8 13 15 12  9  0  3  5  6 11]]])
+
+(defsubst ntlm-string-permute (in perm n)
+  "Return a string of length N for a string IN and a permutation vector
+PERM of size N.  The length of IN should be height of PERM."
+  (let ((i 0) (out (make-string n 0)))
+    (while (< i n)
+      (aset out i (aref in (- (aref perm i) 1)))
+      (setq i (1+ i)))
+    out))
+
+(defsubst ntlm-string-lshift (str count len)
+  "Return a string by circularly shifting a string STR by COUNT to the left.
+length of STR is LEN."
+  (let ((c (% count len)))
+    (concat (substring str c len) (substring str 0 c))))
+
+(defsubst ntlm-string-xor (in1 in2 n)
+  "Return exclusive-or of sequences in1 and in2"
+  (let ((w (make-string n 0)) (i 0))
+    (while (< i n)
+      (aset w i (logxor (aref in1 i) (aref in2 i)))
+      (setq i (1+ i)))
+    w))
+
+(defun ntlm-smb-dohash (in key forw)
+  "Return the hash value for a string IN and a string KEY.
+Length of IN and KEY are 64.  FORW non-nil means forward, nil means
+backward."
+  (let (pk1                            ;string of length 56
+       c                               ;string of length 28
+       d                               ;string of length 28
+       cd                              ;string of length 56
+       (ki (make-vector 16 0))         ;vector of string of length 48
+       pd1                             ;string of length 64
+       l                               ;string of length 32
+       r                               ;string of length 32
+       rl                              ;string of length 64
+       (i 0) (j 0) (k 0))
+    (setq pk1 (ntlm-string-permute key ntlm-smb-perm1 56))
+    (setq c (substring pk1 0 28))
+    (setq d (substring pk1 28 56))
+
+    (setq i 0)
+    (while (< i 16)
+      (setq c (ntlm-string-lshift c (aref ntlm-smb-sc i) 28))
+      (setq d (ntlm-string-lshift d (aref ntlm-smb-sc i) 28))
+      (setq cd (concat (substring c 0 28) (substring d 0 28)))
+      (aset ki i (ntlm-string-permute cd ntlm-smb-perm2 48))
+      (setq i (1+ i)))
+
+    (setq pd1 (ntlm-string-permute in ntlm-smb-perm3 64))
+
+    (setq l (substring pd1 0 32))
+    (setq r (substring pd1 32 64))
+
+    (setq i 0)
+    (let (er                           ;string of length 48
+         erk                           ;string of length 48
+         (b (make-vector 8 0))         ;vector of strings of length 6
+         cb                            ;string of length 32
+         pcb                           ;string of length 32
+         r2                            ;string of length 32
+         jj m n bj sbox-jmn)
+      (while (< i 16)
+       (setq er (ntlm-string-permute r ntlm-smb-perm4 48))
+       (setq erk (ntlm-string-xor er
+                      (aref ki (if forw i (- 15 i)))
+                      48))
+       (setq j 0)
+       (while (< j 8)
+         (setq jj (* 6 j))
+         (aset b j (substring erk jj (+ jj 6)))
+         (setq j (1+ j)))
+       (setq j 0)
+       (while (< j 8)
+         (setq bj (aref b j))
+         (setq m (logior (lsh (aref bj 0) 1) (aref bj 5)))
+         (setq n (logior (lsh (aref bj 1) 3)
+                         (lsh (aref bj 2) 2)
+                         (lsh (aref bj 3) 1)
+                         (aref bj 4)))
+         (setq k 0)
+         (setq sbox-jmn (aref (aref (aref ntlm-smb-sbox j) m) n))
+         (while (< k 4)
+           (aset bj k
+                 (if (zerop (logand sbox-jmn (lsh 1 (- 3 k))))
+                     0 1))
+           (setq k (1+ k)))
+         (setq j (1+ j)))
+
+       (setq j 0)
+       (setq cb nil)
+       (while (< j 8)
+         (setq cb (concat cb (substring (aref b j) 0 4)))
+         (setq j (1+ j)))
+
+       (setq pcb (ntlm-string-permute cb ntlm-smb-perm5 32))
+       (setq r2 (ntlm-string-xor l pcb 32))
+       (setq l r)
+       (setq r r2)
+       (setq i (1+ i))))
+    (setq rl (concat r l))
+    (ntlm-string-permute rl ntlm-smb-perm6 64)))
+
+(defun ntlm-md4hash (passwd)
+  "Return the 16 bytes MD4 hash of a string PASSWD after converting it
+into a Unicode string.  PASSWD is truncated to 128 bytes if longer."
+  (let (len wpwd)
+    ;; Password cannot be longer than 128 characters
+    (setq len (length passwd))
+    (if (> len 128)
+       (setq len 128))
+    ;; Password must be converted to NT Unicode
+    (setq wpwd (ntlm-ascii2unicode passwd len))
+    ;; Calculate length in bytes
+    (setq len (* len 2))
+    (md4 wpwd len)))
+
+(provide 'ntlm)
+
+;;; ntlm.el ends here
diff --git a/xemacs-packages/gnus/lisp/parse-time.el b/xemacs-packages/gnus/lisp/parse-time.el
new file mode 100644 (file)
index 0000000..c4d3e0a
--- /dev/null
@@ -0,0 +1,303 @@
+;;; parse-time.el --- parsing time strings
+
+;; Copyright (C) 1996, 2000-2016 Free Software Foundation, Inc.
+
+;; Author: Erik Naggum <erik@naggum.no>
+;; Keywords: util
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; With the introduction of the `encode-time', `decode-time', and
+;; `format-time-string' functions, dealing with time became simpler in
+;; Emacs.  However, parsing time strings is still largely a matter of
+;; heuristics and no common interface has been designed.
+
+;; `parse-time-string' parses a time in a string and returns a list of 9
+;; values, just like `decode-time', where unspecified elements in the
+;; string are returned as nil.  `encode-time' may be applied on these
+;; values to obtain an internal time value.
+
+;;; Code:
+
+(eval-and-compile
+  (ignore-errors (require 'cl-lib)))
+(eval-when-compile
+  (require 'cl)                                ;and ah ain't kiddin' 'bout it
+  (defalias 'parse-time-incf (if (featurep 'cl-lib) 'cl-incf 'incf)))
+
+;; Byte-compiler warnings
+(defvar parse-time-elt)
+(defvar parse-time-val)
+
+(eval-and-compile
+  (if (featurep 'xemacs)
+      (progn
+       (defvar parse-time-syntax (make-vector 256 nil))
+       (loop for i from ?0 to ?9
+             do (aset parse-time-syntax i ?0))
+       (loop for i from ?A to ?Z
+             do (aset parse-time-syntax i ?A))
+       (loop for i from ?a to ?z
+             do (aset parse-time-syntax i ?a))
+       (aset parse-time-syntax ?+ 1)
+       (aset parse-time-syntax ?- -1)
+       (aset parse-time-syntax ?: ?d)
+       (defsubst parse-time-string-chars (char)
+         (and (< char (length parse-time-syntax))
+              (aref parse-time-syntax char))))
+    (defsubst parse-time-string-chars (char)
+      (save-match-data
+       (let (case-fold-search str)
+         (cond ((eq char ?+) 1)
+               ((eq char ?-) -1)
+               ((eq char ?:) ?d)
+               ((string-match "[[:upper:]]" (setq str (string char))) ?A)
+               ((string-match "[[:lower:]]" str) ?a)
+               ((string-match "[[:digit:]]" str) ?0)))))))
+
+(eval-and-compile
+  (if (fboundp 'cl-parse-integer)
+      (defalias 'parse-time-integer 'cl-parse-integer)
+    (defvar parse-time-digits (make-vector 256 nil))
+    (loop for i from ?0 to ?9
+         do (aset parse-time-digits i (- i ?0)))
+    (defun parse-time-integer (string &rest keys)
+      "[CL] Parse and return the integer in STRING, or nil if none."
+      (let* ((start (plist-get keys :start))
+            (end (or (plist-get keys :end) (length string)))
+            (integer 0)
+            (digit 0)
+            (index (or start 0)))
+       (when (< index end)
+         (let ((sign (aref string index)))
+           (if (or (eq sign ?+) (eq sign ?-))
+               (setq sign (parse-time-string-chars sign)
+                     index (1+ index))
+             (setq sign 1))
+           (while (and (< index end)
+                       (setq digit (aref parse-time-digits
+                                         (aref string index))))
+             (setq integer (+ (* integer 10) digit)
+                   index (1+ index)))
+           (if (/= index end)
+               (error "Not an integer string: `%s'" string)
+             (* sign integer))))))))
+
+(defun parse-time-tokenize (string)
+  "Tokenize STRING into substrings."
+  (let ((start nil)
+       (end (length string))
+       (all-digits nil)
+       (list ())
+       (index 0)
+       (c nil))
+    (while (< index end)
+      (while (and (< index end)                ;Skip invalid characters.
+                 (not (setq c (parse-time-string-chars (aref string index)))))
+       (parse-time-incf index))
+      (setq start index all-digits (eq c ?0))
+      (while (and (< (parse-time-incf index) end) ;Scan valid characters.
+                 (setq c (parse-time-string-chars (aref string index))))
+       (setq all-digits (and all-digits (eq c ?0))))
+      (if (<= index end)
+         (push (if all-digits (parse-time-integer string
+                                                  :start start :end index)
+                 (substring string start index))
+               list)))
+    (nreverse list)))
+
+(defvar parse-time-months '(("jan" . 1) ("feb" . 2) ("mar" . 3)
+                           ("apr" . 4) ("may" . 5) ("jun" . 6)
+                           ("jul" . 7) ("aug" . 8) ("sep" . 9)
+                           ("oct" . 10) ("nov" . 11) ("dec" . 12)
+                           ("january" . 1) ("february" . 2)
+                           ("march" . 3) ("april" . 4) ("june" . 6)
+                           ("july" . 7) ("august" . 8)
+                           ("september" . 9) ("october" . 10)
+                           ("november" . 11) ("december" . 12)))
+(defvar parse-time-weekdays '(("sun" . 0) ("mon" . 1) ("tue" . 2)
+                             ("wed" . 3) ("thu" . 4) ("fri" . 5)
+                             ("sat" . 6) ("sunday" . 0) ("monday" . 1)
+                             ("tuesday" . 2) ("wednesday" . 3)
+                             ("thursday" . 4) ("friday" . 5)
+                             ("saturday" . 6)))
+(defvar parse-time-zoneinfo `(("z" 0) ("ut" 0) ("gmt" 0)
+                             ("pst" ,(* -8 3600)) ("pdt" ,(* -7 3600) t)
+                             ("mst" ,(* -7 3600)) ("mdt" ,(* -6 3600) t)
+                             ("cst" ,(* -6 3600)) ("cdt" ,(* -5 3600) t)
+                             ("est" ,(* -5 3600)) ("edt" ,(* -4 3600) t))
+  "(zoneinfo seconds-off daylight-savings-time-p)")
+
+(defvar parse-time-rules
+  `(((6) parse-time-weekdays)
+    ((3) (1 31))
+    ((4) parse-time-months)
+    ((5) (100 ,most-positive-fixnum))
+    ((2 1 0)
+     ,#'(lambda () (and (stringp parse-time-elt)
+                       (= (length parse-time-elt) 8)
+                       (= (aref parse-time-elt 2) ?:)
+                       (= (aref parse-time-elt 5) ?:)))
+     [0 2] [3 5] [6 8])
+    ((8 7) parse-time-zoneinfo
+     ,#'(lambda () (car parse-time-val))
+     ,#'(lambda () (cadr parse-time-val)))
+    ((8)
+     ,#'(lambda ()
+         (and (stringp parse-time-elt)
+              (= 5 (length parse-time-elt))
+              (or (= (aref parse-time-elt 0) ?+)
+                  (= (aref parse-time-elt 0) ?-))))
+     ,#'(lambda () (* 60 (+ (parse-time-integer parse-time-elt :start 3 :end 5)
+                           (* 60 (parse-time-integer parse-time-elt
+                                                     :start 1 :end 3)))
+                     (if (= (aref parse-time-elt 0) ?-) -1 1))))
+    ((5 4 3)
+     ,#'(lambda () (and (stringp parse-time-elt)
+                       (= (length parse-time-elt) 10)
+                       (= (aref parse-time-elt 4) ?-)
+                       (= (aref parse-time-elt 7) ?-)))
+     [0 4] [5 7] [8 10])
+    ((2 1 0)
+     ,#'(lambda () (and (stringp parse-time-elt)
+                       (= (length parse-time-elt) 5)
+                       (= (aref parse-time-elt 2) ?:)))
+     [0 2] [3 5] ,#'(lambda () 0))
+    ((2 1 0)
+     ,#'(lambda () (and (stringp parse-time-elt)
+                       (= (length parse-time-elt) 4)
+                       (= (aref parse-time-elt 1) ?:)))
+     [0 1] [2 4] ,#'(lambda () 0))
+    ((2 1 0)
+     ,#'(lambda () (and (stringp parse-time-elt)
+                       (= (length parse-time-elt) 7)
+                       (= (aref parse-time-elt 1) ?:)))
+     [0 1] [2 4] [5 7])
+    ((5) (50 110) ,#'(lambda () (+ 1900 parse-time-elt)))
+    ((5) (0 49) ,#'(lambda () (+ 2000 parse-time-elt))))
+  "(slots predicate extractor...)")
+;;;###autoload(put 'parse-time-rules 'risky-local-variable t)
+
+;;;###autoload
+(defun parse-time-string (string)
+  "Parse the time-string STRING into (SEC MIN HOUR DAY MON YEAR DOW DST TZ).
+The values are identical to those of `decode-time', but any values that are
+unknown are returned as nil."
+  (let ((time (list nil nil nil nil nil nil nil nil nil))
+       (temp (parse-time-tokenize (downcase string))))
+    (while temp
+      (let ((parse-time-elt (pop temp))
+           (rules parse-time-rules)
+           (exit nil))
+       (while (and rules (not exit))
+         (let* ((rule (pop rules))
+                (slots (pop rule))
+                (predicate (pop rule))
+                (parse-time-val))
+           (when (and (not (nth (car slots) time)) ;not already set
+                      (setq parse-time-val
+                            (cond ((and (consp predicate)
+                                        (not (eq (car predicate)
+                                                 'lambda)))
+                                   (and (numberp parse-time-elt)
+                                        (<= (car predicate) parse-time-elt)
+                                        (<= parse-time-elt (cadr predicate))
+                                        parse-time-elt))
+                                  ((symbolp predicate)
+                                   (cdr (assoc parse-time-elt
+                                               (symbol-value predicate))))
+                                  ((funcall predicate)))))
+             (setq exit t)
+             (while slots
+               (let ((new-val (if rule
+                                  (let ((this (pop rule)))
+                                    (if (vectorp this)
+                                        (parse-time-integer
+                                         parse-time-elt
+                                         :start (aref this 0)
+                                         :end (aref this 1))
+                                      (funcall this)))
+                                parse-time-val)))
+                 (rplaca (nthcdr (pop slots) time) new-val))))))))
+    time))
+
+(defconst parse-time-iso8601-regexp
+  (let* ((dash "-?")
+        (colon ":?")
+        (4digit "\\([0-9][0-9][0-9][0-9]\\)")
+        (2digit "\\([0-9][0-9]\\)")
+        (date-fullyear 4digit)
+        (date-month 2digit)
+        (date-mday 2digit)
+        (time-hour 2digit)
+        (time-minute 2digit)
+        (time-second 2digit)
+        (time-secfrac "\\(\\.[0-9]+\\)?")
+        (time-numoffset (concat "[-+]\\(" time-hour "\\):" time-minute))
+        (time-offset (concat "Z" time-numoffset))
+        (partial-time (concat time-hour colon time-minute colon time-second
+                              time-secfrac))
+        (full-date (concat date-fullyear dash date-month dash date-mday))
+        (full-time (concat partial-time time-offset))
+        (date-time (concat full-date "T" full-time)))
+    (list (concat "^" full-date)
+         (concat "T" partial-time)
+         (concat "Z" time-numoffset)))
+  "List of regular expressions matching ISO 8601 dates.
+1st regular expression matches the date.
+2nd regular expression matches the time.
+3rd regular expression matches the (optional) timezone specification.")
+
+(defun parse-iso8601-time-string (date-string)
+  (let* ((date-re (nth 0 parse-time-iso8601-regexp))
+        (time-re (nth 1 parse-time-iso8601-regexp))
+        (tz-re (nth 2 parse-time-iso8601-regexp))
+        re-start
+        time seconds minute hour fractional-seconds
+        day month year day-of-week dst tz)
+    ;; We need to populate 'time' with
+    ;; (SEC MIN HOUR DAY MON YEAR DOW DST TZ)
+
+    ;; Nobody else handles iso8601 correctly, let's do it ourselves.
+    (when (string-match date-re date-string re-start)
+      (setq year (string-to-number (match-string 1 date-string))
+           month (string-to-number (match-string 2 date-string))
+           day (string-to-number (match-string 3 date-string))
+           re-start (match-end 0))
+      (when (string-match time-re date-string re-start)
+       (setq hour (string-to-number (match-string 1 date-string))
+             minute (string-to-number (match-string 2 date-string))
+             seconds (string-to-number (match-string 3 date-string))
+             fractional-seconds (string-to-number (or
+                                                    (match-string 4 date-string)
+                                                    "0"))
+             re-start (match-end 0))
+       (when (string-match tz-re date-string re-start)
+         (setq tz (match-string 1 date-string)))
+       (setq time (list seconds minute hour day month year day-of-week dst tz))))
+
+    ;; Fall back to having Gnus do fancy things for us.
+    (when (not time)
+      (setq time (parse-time-string date-string)))
+
+    (and time
+        (apply 'encode-time time))))
+
+(provide 'parse-time)
+
+;;; parse-time.el ends here
diff --git a/xemacs-packages/gnus/lisp/password-cache.el b/xemacs-packages/gnus/lisp/password-cache.el
new file mode 100644 (file)
index 0000000..1a771a8
--- /dev/null
@@ -0,0 +1,144 @@
+;;; password-cache.el --- Read passwords, possibly using a password cache.
+
+;; Copyright (C) 1999-2000, 2003-2016 Free Software Foundation, Inc.
+
+;; Author: Simon Josefsson <simon@josefsson.org>
+;; Created: 2003-12-21
+;; Keywords: password cache passphrase key
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Greatly influenced by pgg.el written by Daiki Ueno, with timer
+;; fixes for XEmacs by Katsumi Yamaoka.  In fact, this is mostly just
+;; a rip-off.
+;;
+;; (password-read "Password? " "test")
+;; ;; Minibuffer prompt for password.
+;;  => "foo"
+;;
+;; (password-cache-add "test" "foo")
+;;  => nil
+
+;; (password-read "Password? " "test")
+;; ;; No minibuffer prompt
+;;  => "foo"
+;;
+;; (password-read "Password? " "test")
+;; ;; No minibuffer prompt
+;;  => "foo"
+;;
+;; ;; Wait `password-cache-expiry' seconds.
+;;
+;; (password-read "Password? " "test")
+;; ;; Minibuffer prompt for password is back.
+;;  => "foo"
+
+;;; Code:
+
+;; Options are autoloaded since they are used by eg mml-sec.el.
+
+;;;###autoload
+(defcustom password-cache t
+  "Whether to cache passwords."
+  :group 'password
+  :type 'boolean)
+
+;;;###autoload
+(defcustom password-cache-expiry 16
+  "How many seconds passwords are cached, or nil to disable expiring.
+Whether passwords are cached at all is controlled by `password-cache'."
+  :group 'password
+  :type '(choice (const :tag "Never" nil)
+                (integer :tag "Seconds")))
+
+(defvar password-data (make-vector 7 0))
+
+(defun password-read-from-cache (key)
+  "Obtain passphrase for KEY from time-limited passphrase cache.
+Custom variables `password-cache' and `password-cache-expiry'
+regulate cache behavior."
+  (and password-cache
+       key
+       (symbol-value (intern-soft key password-data))))
+
+;;;###autoload
+(defun password-in-cache-p (key)
+  "Check if KEY is in the cache."
+  (and password-cache
+       key
+       (intern-soft key password-data)))
+
+(defun password-read (prompt &optional key)
+  "Read password, for use with KEY, from user, or from cache if wanted.
+KEY indicate the purpose of the password, so the cache can
+separate passwords.  The cache is not used if KEY is nil.  It is
+typically a string.
+The variable `password-cache' control whether the cache is used."
+  (or (password-read-from-cache key)
+      (read-passwd prompt)))
+
+(defun password-read-and-add (prompt &optional key)
+  "Read password, for use with KEY, from user, or from cache if wanted.
+Then store the password in the cache.  Uses `password-read' and
+`password-cache-add'.  Custom variables `password-cache' and
+`password-cache-expiry' regulate cache behavior.
+
+Warning: the password is cached without checking that it is
+correct.  It is better to check the password before caching.  If
+you must use this function, take care to check passwords and
+remove incorrect ones from the cache."
+  (declare (obsolete password-read "23.1"))
+  (let ((password (password-read prompt key)))
+    (when (and password key)
+      (password-cache-add key password))
+    password))
+
+(defun password-cache-remove (key)
+  "Remove password indexed by KEY from password cache.
+This is typically run by a timer setup from `password-cache-add',
+but can be invoked at any time to forcefully remove passwords
+from the cache.  This may be useful when it has been detected
+that a password is invalid, so that `password-read' query the
+user again."
+  (let ((sym (intern-soft key password-data)))
+    (when sym
+      (let ((password (symbol-value sym)))
+        (when (stringp password)
+          (if (fboundp 'clear-string)
+              (clear-string password)
+            (fillarray password ?_)))
+        (unintern key password-data)))))
+
+(defun password-cache-add (key password)
+  "Add password to cache.
+The password is removed by a timer after `password-cache-expiry' seconds."
+  (when (and password-cache-expiry (null (intern-soft key password-data)))
+    (run-at-time password-cache-expiry nil
+                #'password-cache-remove
+                key))
+  (set (intern key password-data) password)
+  nil)
+
+(defun password-reset ()
+  "Clear the password cache."
+  (interactive)
+  (fillarray password-data 0))
+
+(provide 'password-cache)
+
+;;; password-cache.el ends here
diff --git a/xemacs-packages/gnus/lisp/plstore.el b/xemacs-packages/gnus/lisp/plstore.el
new file mode 100644 (file)
index 0000000..e327bbd
--- /dev/null
@@ -0,0 +1,582 @@
+;;; plstore.el --- secure plist store -*- lexical-binding: t -*-
+;; Copyright (C) 2011-2016 Free Software Foundation, Inc.
+
+;; Author: Daiki Ueno <ueno@unixuser.org>
+;; Keywords: PGP, GnuPG
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary
+
+;; Plist based data store providing search and partial encryption.
+;;
+;; Creating:
+;;
+;; ;; Open a new store associated with ~/.emacs.d/auth.plist.
+;; (setq store (plstore-open (expand-file-name "~/.emacs.d/auth.plist")))
+;; ;; Both `:host' and `:port' are public property.
+;; (plstore-put store "foo" '(:host "foo.example.org" :port 80) nil)
+;; ;; No encryption will be needed.
+;; (plstore-save store)
+;;
+;; ;; `:user' is marked as secret.
+;; (plstore-put store "bar" '(:host "bar.example.org") '(:user "test"))
+;; ;; `:password' is marked as secret.
+;; (plstore-put store "baz" '(:host "baz.example.org") '(:password "test"))
+;; ;; Those secret properties are encrypted together.
+;; (plstore-save store)
+;;
+;; ;; Kill the buffer visiting ~/.emacs.d/auth.plist.
+;; (plstore-close store)
+;;
+;; Searching:
+;;
+;; (setq store (plstore-open (expand-file-name "~/.emacs.d/auth.plist")))
+;;
+;; ;; As the entry "foo" associated with "foo.example.org" has no
+;; ;; secret properties, no need to decryption.
+;; (plstore-find store '(:host ("foo.example.org")))
+;;
+;; ;; As the entry "bar" associated with "bar.example.org" has a
+;; ;; secret property `:user', Emacs tries to decrypt the secret (and
+;; ;; thus you will need to input passphrase).
+;; (plstore-find store '(:host ("bar.example.org")))
+;;
+;; ;; While the entry "baz" associated with "baz.example.org" has also
+;; ;; a secret property `:password', it is encrypted together with
+;; ;; `:user' of "bar", so no need to decrypt the secret.
+;; (plstore-find store '(:host ("bar.example.org")))
+;;
+;; (plstore-close store)
+;;
+;; Editing:
+;;
+;; This file also provides `plstore-mode', a major mode for editing
+;; the PLSTORE format file.  Visit a non-existing file and put the
+;; following line:
+;;
+;; (("foo" :host "foo.example.org" :secret-user "user"))
+;;
+;; where the prefixing `:secret-' means the property (without
+;; `:secret-' prefix) is marked as secret.  Thus, when you save the
+;; buffer, the `:secret-user' property is encrypted as `:user'.
+;;
+;; You can toggle the view between encrypted form and the decrypted
+;; form with C-c C-c.
+
+;;; Code:
+
+(require 'epg)
+
+(defgroup plstore nil
+  "Searchable, partially encrypted, persistent plist store"
+  :version "24.1"
+  :group 'files)
+
+(defcustom plstore-select-keys 'silent
+  "Control whether or not to pop up the key selection dialog.
+
+If t, always asks user to select recipients.
+If nil, query user only when a file's default recipients are not
+known (i.e. `plstore-encrypt-to' is not locally set in the buffer
+visiting a plstore file).
+If neither t nor nil, doesn't ask user."
+  :type '(choice (const :tag "Ask always" t)
+                (const :tag "Ask when recipients are not set" nil)
+                (const :tag "Don't ask" silent))
+  :group 'plstore)
+
+(defvar plstore-encrypt-to nil
+  "*Recipient(s) used for encrypting secret entries.
+May either be a string or a list of strings.  If it is nil,
+symmetric encryption will be used.")
+
+(put 'plstore-encrypt-to 'safe-local-variable
+     (lambda (val)
+       (or (stringp val)
+          (and (listp val)
+               (catch 'safe
+                 (mapc (lambda (elt)
+                         (unless (stringp elt)
+                           (throw 'safe nil)))
+                       val)
+                 t)))))
+
+(put 'plstore-encrypt-to 'permanent-local t)
+
+(defvar plstore-encoded nil)
+
+(put 'plstore-encoded 'permanent-local t)
+
+(defvar plstore-cache-passphrase-for-symmetric-encryption nil)
+(defvar plstore-passphrase-alist nil)
+
+(defun plstore-passphrase-callback-function (_context _key-id plstore)
+  (if plstore-cache-passphrase-for-symmetric-encryption
+      (let* ((file (file-truename (plstore-get-file plstore)))
+            (entry (assoc file plstore-passphrase-alist))
+            passphrase)
+       (or (copy-sequence (cdr entry))
+           (progn
+             (unless entry
+               (setq entry (list file)
+                     plstore-passphrase-alist
+                     (cons entry
+                           plstore-passphrase-alist)))
+             (setq passphrase
+                   (read-passwd (format "Passphrase for PLSTORE %s: "
+                                        (plstore--get-buffer plstore))))
+             (setcdr entry (copy-sequence passphrase))
+             passphrase)))
+    (read-passwd (format "Passphrase for PLSTORE %s: "
+                        (plstore--get-buffer plstore)))))
+
+(defun plstore-progress-callback-function (_context _what _char current total
+                                                   handback)
+  (if (= current total)
+      (message "%s...done" handback)
+    (message "%s...%d%%" handback
+            (if (> total 0) (floor (* (/ current (float total)) 100)) 0))))
+
+(defun plstore--get-buffer (arg)
+  (aref arg 0))
+
+(defun plstore--get-alist (arg)
+  (aref arg 1))
+
+(defun plstore--get-encrypted-data (arg)
+  (aref arg 2))
+
+(defun plstore--get-secret-alist (arg)
+  (aref arg 3))
+
+(defun plstore--get-merged-alist (arg)
+  (aref arg 4))
+
+(defun plstore--set-buffer (arg buffer)
+  (aset arg 0 buffer))
+
+(defun plstore--set-alist (arg plist)
+  (aset arg 1 plist))
+
+(defun plstore--set-encrypted-data (arg encrypted-data)
+  (aset arg 2 encrypted-data))
+
+(defun plstore--set-secret-alist (arg secret-alist)
+  (aset arg 3 secret-alist))
+
+(defun plstore--set-merged-alist (arg merged-alist)
+  (aset arg 4 merged-alist))
+
+(defun plstore-get-file (arg)
+  (buffer-file-name (plstore--get-buffer arg)))
+
+(defun plstore--make (&optional buffer alist encrypted-data secret-alist
+                               merged-alist)
+  (vector buffer alist encrypted-data secret-alist merged-alist))
+
+(defun plstore--init-from-buffer (plstore)
+  (goto-char (point-min))
+  (when (looking-at ";;; public entries")
+    (forward-line)
+    (plstore--set-alist plstore (read (point-marker)))
+    (forward-sexp)
+    (forward-char)
+    (when (looking-at ";;; secret entries")
+      (forward-line)
+      (plstore--set-encrypted-data plstore (read (point-marker))))
+    (plstore--merge-secret plstore)))
+
+;;;###autoload
+(defun plstore-open (file)
+  "Create a plstore instance associated with FILE."
+  (let* ((filename (file-truename file))
+        (buffer (or (find-buffer-visiting filename)
+                    (generate-new-buffer (format " plstore %s" filename))))
+        (store (plstore--make buffer)))
+    (with-current-buffer buffer
+      (erase-buffer)
+      (condition-case nil
+         (insert-file-contents-literally file)
+       (error))
+      (setq buffer-file-name (file-truename file))
+      (set-buffer-modified-p nil)
+      (plstore--init-from-buffer store)
+      store)))
+
+(defun plstore-revert (plstore)
+  "Replace current data in PLSTORE with the file on disk."
+  (with-current-buffer (plstore--get-buffer plstore)
+    (revert-buffer t t)
+    (plstore--init-from-buffer plstore)))
+
+(defun plstore-close (plstore)
+  "Destroy a plstore instance PLSTORE."
+  (kill-buffer (plstore--get-buffer plstore)))
+
+(defun plstore--merge-secret (plstore)
+  (let ((alist (plstore--get-secret-alist plstore))
+       modified-alist
+       modified-plist
+       modified-entry
+       entry
+       plist
+       placeholder)
+    (plstore--set-merged-alist
+     plstore
+     (copy-tree (plstore--get-alist plstore)))
+    (setq modified-alist (plstore--get-merged-alist plstore))
+    (while alist
+      (setq entry (car alist)
+           alist (cdr alist)
+           plist (cdr entry)
+           modified-entry (assoc (car entry) modified-alist)
+           modified-plist (cdr modified-entry))
+      (while plist
+       (setq placeholder
+             (plist-member
+              modified-plist
+              (intern (concat ":secret-"
+                              (substring (symbol-name (car plist)) 1)))))
+       (if placeholder
+           (setcar placeholder (car plist)))
+       (setq modified-plist
+             (plist-put modified-plist (car plist) (car (cdr plist))))
+       (setq plist (nthcdr 2 plist)))
+      (setcdr modified-entry modified-plist))))
+
+(defun plstore--decrypt (plstore)
+  (if (plstore--get-encrypted-data plstore)
+      (let ((context (epg-make-context 'OpenPGP))
+           plain)
+       (epg-context-set-passphrase-callback
+        context
+        (cons #'plstore-passphrase-callback-function
+              plstore))
+       (epg-context-set-progress-callback
+        context
+        (cons #'plstore-progress-callback-function
+              (format "Decrypting %s" (plstore-get-file plstore))))
+       (condition-case error
+           (setq plain
+                 (epg-decrypt-string context
+                                     (plstore--get-encrypted-data plstore)))
+         (error
+          (let ((entry (assoc (plstore-get-file plstore)
+                              plstore-passphrase-alist)))
+            (if entry
+                (setcdr entry nil)))
+          (signal (car error) (cdr error))))
+       (plstore--set-secret-alist plstore (car (read-from-string plain)))
+       (plstore--merge-secret plstore)
+       (plstore--set-encrypted-data plstore nil))))
+
+(defun plstore--match (entry keys skip-if-secret-found)
+  (let ((result t) key-name key-value prop-value secret-name)
+    (while keys
+      (setq key-name (car keys)
+           key-value (car (cdr keys))
+           prop-value (plist-get (cdr entry) key-name))
+       (unless (member prop-value key-value)
+         (if skip-if-secret-found
+             (progn
+               (setq secret-name
+                     (intern (concat ":secret-"
+                                     (substring (symbol-name key-name) 1))))
+               (if (plist-member (cdr entry) secret-name)
+                   (setq result 'secret)
+                 (setq result nil
+                       keys nil)))
+           (setq result nil
+                 keys nil)))
+       (setq keys (nthcdr 2 keys)))
+    result))
+
+(defun plstore-find (plstore keys)
+  "Perform search on PLSTORE with KEYS.
+KEYS is a plist."
+  (let (entries alist entry match decrypt plist)
+    ;; First, go through the merged plist alist and collect entries
+    ;; matched with keys.
+    (setq alist (plstore--get-merged-alist plstore))
+    (while alist
+      (setq entry (car alist)
+           alist (cdr alist)
+           match (plstore--match entry keys t))
+      (if (eq match 'secret)
+         (setq decrypt t)
+       (when match
+         (setq plist (cdr entry))
+         (while plist
+           (if (string-match "\\`:secret-" (symbol-name (car plist)))
+               (setq decrypt t
+                     plist nil))
+           (setq plist (nthcdr 2 plist)))
+         (setq entries (cons entry entries)))))
+    ;; Second, decrypt the encrypted plist and try again.
+    (when decrypt
+      (setq entries nil)
+      (plstore--decrypt plstore)
+      (setq alist (plstore--get-merged-alist plstore))
+      (while alist
+       (setq entry (car alist)
+             alist (cdr alist)
+             match (plstore--match entry keys nil))
+       (if match
+           (setq entries (cons entry entries)))))
+    (nreverse entries)))
+
+(defun plstore-get (plstore name)
+  "Get an entry with NAME in PLSTORE."
+  (let ((entry (assoc name (plstore--get-merged-alist plstore)))
+       plist)
+    (setq plist (cdr entry))
+    (while plist
+      (if (string-match "\\`:secret-" (symbol-name (car plist)))
+         (progn
+           (plstore--decrypt plstore)
+           (setq entry (assoc name (plstore--get-merged-alist plstore))
+                 plist nil))
+       (setq plist (nthcdr 2 plist))))
+    entry))
+
+(defun plstore-put (plstore name keys secret-keys)
+  "Put an entry with NAME in PLSTORE.
+KEYS is a plist containing non-secret data.
+SECRET-KEYS is a plist containing secret data."
+  (let (entry
+       plist
+       secret-plist
+       symbol)
+    (if secret-keys
+       (plstore--decrypt plstore))
+    (while secret-keys
+      (setq symbol
+           (intern (concat ":secret-"
+                           (substring (symbol-name (car secret-keys)) 1))))
+      (setq plist (plist-put plist symbol t)
+           secret-plist (plist-put secret-plist
+                                   (car secret-keys) (car (cdr secret-keys)))
+           secret-keys (nthcdr 2 secret-keys)))
+    (while keys
+      (setq symbol
+           (intern (concat ":secret-"
+                           (substring (symbol-name (car keys)) 1))))
+      (setq plist (plist-put plist (car keys) (car (cdr keys)))
+           keys (nthcdr 2 keys)))
+    (setq entry (assoc name (plstore--get-alist plstore)))
+    (if entry
+       (setcdr entry plist)
+      (plstore--set-alist
+       plstore
+       (cons (cons name plist) (plstore--get-alist plstore))))
+    (when secret-plist
+      (setq entry (assoc name (plstore--get-secret-alist plstore)))
+      (if entry
+         (setcdr entry secret-plist)
+       (plstore--set-secret-alist
+        plstore
+        (cons (cons name secret-plist) (plstore--get-secret-alist plstore)))))
+    (plstore--merge-secret plstore)))
+
+(defun plstore-delete (plstore name)
+  "Delete an entry with NAME from PLSTORE."
+  (let ((entry (assoc name (plstore--get-alist plstore))))
+    (if entry
+       (plstore--set-alist
+        plstore
+        (delq entry (plstore--get-alist plstore))))
+    (setq entry (assoc name (plstore--get-secret-alist plstore)))
+    (if entry
+       (plstore--set-secret-alist
+        plstore
+        (delq entry (plstore--get-secret-alist plstore))))
+    (setq entry (assoc name (plstore--get-merged-alist plstore)))
+    (if entry
+       (plstore--set-merged-alist
+        plstore
+        (delq entry (plstore--get-merged-alist plstore))))))
+
+(defvar pp-escape-newlines)
+(defun plstore--insert-buffer (plstore)
+  (insert ";;; public entries -*- mode: plstore -*- \n"
+         (pp-to-string (plstore--get-alist plstore)))
+  (if (plstore--get-secret-alist plstore)
+      (let ((context (epg-make-context 'OpenPGP))
+           (pp-escape-newlines nil)
+           (recipients
+            (cond
+             ((listp plstore-encrypt-to) plstore-encrypt-to)
+             ((stringp plstore-encrypt-to) (list plstore-encrypt-to))))
+           cipher)
+       (epg-context-set-armor context t)
+       (epg-context-set-passphrase-callback
+        context
+        (cons #'plstore-passphrase-callback-function
+              plstore))
+       (setq cipher (epg-encrypt-string
+                     context
+                     (pp-to-string
+                      (plstore--get-secret-alist plstore))
+                     (if (or (eq plstore-select-keys t)
+                             (and (null plstore-select-keys)
+                                  (not (local-variable-p 'plstore-encrypt-to
+                                                         (current-buffer)))))
+                         (epa-select-keys
+                          context
+                          "Select recipients for encryption.
+If no one is selected, symmetric encryption will be performed.  "
+                          recipients)
+                       (if plstore-encrypt-to
+                           (epg-list-keys context recipients)))))
+       (goto-char (point-max))
+       (insert ";;; secret entries\n" (pp-to-string cipher)))))
+
+(defun plstore-save (plstore)
+  "Save the contents of PLSTORE associated with a FILE."
+  (with-current-buffer (plstore--get-buffer plstore)
+    (erase-buffer)
+    (plstore--insert-buffer plstore)
+    (save-buffer)))
+
+(defun plstore--encode (plstore)
+  (plstore--decrypt plstore)
+  (let ((merged-alist (plstore--get-merged-alist plstore)))
+    (concat "("
+           (mapconcat
+            (lambda (entry)
+              (setq entry (copy-sequence entry))
+              (let ((merged-plist (cdr (assoc (car entry) merged-alist)))
+                    (plist (cdr entry)))
+                (while plist
+                  (if (string-match "\\`:secret-" (symbol-name (car plist)))
+                      (setcar (cdr plist)
+                              (plist-get
+                               merged-plist
+                               (intern (concat ":"
+                                               (substring (symbol-name
+                                                           (car plist))
+                                                          (match-end 0)))))))
+                  (setq plist (nthcdr 2 plist)))
+                (prin1-to-string entry)))
+            (plstore--get-alist plstore)
+            "\n")
+           ")")))
+
+(defun plstore--decode (string)
+  (let* ((alist (car (read-from-string string)))
+        (pointer alist)
+        secret-alist
+        plist
+        entry)
+    (while pointer
+      (unless (stringp (car (car pointer)))
+       (error "Invalid PLSTORE format %s" string))
+      (setq plist (cdr (car pointer)))
+      (while plist
+       (when (string-match "\\`:secret-" (symbol-name (car plist)))
+         (setq entry (assoc (car (car pointer)) secret-alist))
+         (unless entry
+           (setq entry (list (car (car pointer)))
+                 secret-alist (cons entry secret-alist)))
+         (setcdr entry (plist-put (cdr entry)
+                                  (intern (concat ":"
+                                               (substring (symbol-name
+                                                           (car plist))
+                                                          (match-end 0))))
+                                  (car (cdr plist))))
+         (setcar (cdr plist) t))
+       (setq plist (nthcdr 2 plist)))
+      (setq pointer (cdr pointer)))
+    (plstore--make nil alist nil secret-alist)))
+
+(defun plstore--write-contents-functions ()
+  (when plstore-encoded
+    (let ((store (plstore--decode (buffer-string)))
+         (file (buffer-file-name)))
+      (unwind-protect
+         (progn
+           (set-visited-file-name nil)
+           (with-temp-buffer
+             (plstore--insert-buffer store)
+             (write-region (buffer-string) nil file)))
+       (set-visited-file-name file)
+       (set-buffer-modified-p nil))
+      t)))
+
+(defun plstore-mode-original ()
+  "Show the original form of the this buffer."
+  (interactive)
+  (when plstore-encoded
+    (if (and (buffer-modified-p)
+            (y-or-n-p "Save buffer before reading the original form? "))
+       (save-buffer))
+    (erase-buffer)
+    (insert-file-contents-literally (buffer-file-name))
+    (set-buffer-modified-p nil)
+    (setq plstore-encoded nil)))
+
+(defun plstore-mode-decoded ()
+  "Show the decoded form of the this buffer."
+  (interactive)
+  (unless plstore-encoded
+    (if (and (buffer-modified-p)
+            (y-or-n-p "Save buffer before decoding? "))
+       (save-buffer))
+    (let ((store (plstore--make (current-buffer))))
+      (plstore--init-from-buffer store)
+      (erase-buffer)
+      (insert
+       (substitute-command-keys "\
+;;; You are looking at the decoded form of the PLSTORE file.\n\
+;;; To see the original form content, do \\[plstore-mode-toggle-display]\n\n"))
+      (insert (plstore--encode store))
+      (set-buffer-modified-p nil)
+      (setq plstore-encoded t))))
+
+(defun plstore-mode-toggle-display ()
+  "Toggle the display mode of PLSTORE between the original and decoded forms."
+  (interactive)
+  (if plstore-encoded
+      (plstore-mode-original)
+    (plstore-mode-decoded)))
+
+(eval-when-compile
+  (defmacro plstore-called-interactively-p (kind)
+    (condition-case nil
+        (progn
+          (eval '(called-interactively-p 'any))
+          ;; Emacs >=23.2
+          `(called-interactively-p ,kind))
+      ;; Emacs <23.2
+      (wrong-number-of-arguments '(called-interactively-p))
+      ;; XEmacs
+      (void-function '(interactive-p)))))
+
+;;;###autoload
+(define-derived-mode plstore-mode emacs-lisp-mode "PLSTORE"
+  "Major mode for editing PLSTORE files."
+  (make-local-variable 'plstore-encoded)
+  (add-hook 'write-contents-functions #'plstore--write-contents-functions)
+  (define-key plstore-mode-map "\C-c\C-c" #'plstore-mode-toggle-display)
+  ;; to create a new file with plstore-mode, mark it as already decoded
+  (if (plstore-called-interactively-p 'any)
+      (setq plstore-encoded t)
+    (plstore-mode-decoded)))
+
+(provide 'plstore)
+
+;;; plstore.el ends here
diff --git a/xemacs-packages/gnus/lisp/pop3.el b/xemacs-packages/gnus/lisp/pop3.el
new file mode 100644 (file)
index 0000000..fc59380
--- /dev/null
@@ -0,0 +1,929 @@
+;;; pop3.el --- Post Office Protocol (RFC 1460) interface
+
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
+
+;; Author: Richard L. Pieri <ratinox@peorth.gweep.net>
+;; Maintainer: emacs-devel@gnu.org
+;; Keywords: mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Most of the standard Post Office Protocol version 3 (RFC 1460) commands
+;; are implemented.  The LIST command has not been implemented due to lack
+;; of actual usefulness.
+;; The optional POP3 command TOP has not been implemented.
+
+;; This program was inspired by Kyle E. Jones's vm-pop program.
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(eval-and-compile
+  ;; In Emacs 24, `open-protocol-stream' is an autoloaded alias for
+  ;; `make-network-stream'.
+  (unless (fboundp 'open-protocol-stream)
+    (require 'proto-stream)))
+
+(require 'mail-utils)
+(defvar parse-time-months)
+
+(defgroup pop3 nil
+  "Post Office Protocol."
+  :group 'mail
+  :group 'mail-source)
+
+(defcustom pop3-maildrop (or (user-login-name)
+                            (getenv "LOGNAME")
+                            (getenv "USER"))
+  "*POP3 maildrop."
+  :version "22.1" ;; Oort Gnus
+  :type 'string
+  :group 'pop3)
+
+(defcustom pop3-mailhost (or (getenv "MAILHOST") ;; nil -> mismatch
+                            "pop3")
+  "*POP3 mailhost."
+  :version "22.1" ;; Oort Gnus
+  :type 'string
+  :group 'pop3)
+
+(defcustom pop3-port 110
+  "*POP3 port."
+  :version "22.1" ;; Oort Gnus
+  :type 'number
+  :group 'pop3)
+
+(defcustom pop3-password-required t
+  "*Non-nil if a password is required when connecting to POP server."
+  :version "22.1" ;; Oort Gnus
+  :type 'boolean
+  :group 'pop3)
+
+;; Should this be customizable?
+(defvar pop3-password nil
+  "*Password to use when connecting to POP server.")
+
+(defcustom pop3-authentication-scheme 'pass
+  "*POP3 authentication scheme.
+Defaults to `pass', for the standard USER/PASS authentication.  The other
+valid value is `apop'."
+  :type '(choice (const :tag "Normal user/password" pass)
+                (const :tag "APOP" apop))
+  :version "22.1" ;; Oort Gnus
+  :group 'pop3)
+
+(defcustom pop3-stream-length 100
+  "How many messages should be requested at one time.
+The lower the number, the more latency-sensitive the fetching
+will be.  If your pop3 server doesn't support streaming at all,
+set this to 1."
+  :type 'number
+  :version "24.1"
+  :group 'pop3)
+
+(defcustom pop3-leave-mail-on-server nil
+  "Non-nil if the mail is to be left on the POP server after fetching.
+Mails once fetched will never be fetched again by the UIDL control.
+
+If this is neither nil nor a number, all mails will be left on the
+server.  If this is a number, leave mails on the server for this many
+days since you first checked new mails.  If this is nil, mails will be
+deleted on the server right after fetching.
+
+Gnus users should use the `:leave' keyword in a mail source to direct
+the behavior per server, rather than directly modifying this value.
+
+Note that POP servers maintain no state information between sessions,
+so what the client believes is there and what is actually there may
+not match up.  If they do not, then you may get duplicate mails or
+the whole thing can fall apart and leave you with a corrupt mailbox."
+  :version "24.4"
+  :type '(choice (const :tag "Don't leave mails" nil)
+                (const :tag "Leave all mails" t)
+                (number :tag "Leave mails for this many days" :value 14))
+  :group 'pop3)
+
+(defcustom pop3-uidl-file "~/.pop3-uidl"
+  "File used to save UIDL."
+  :version "24.4"
+  :type 'file
+  :group 'pop3)
+
+(defcustom pop3-uidl-file-backup '(0 9)
+  "How to backup the UIDL file `pop3-uidl-file' when updating.
+If it is a list of numbers, the first one binds `kept-old-versions' and
+the other binds `kept-new-versions' to keep number of oldest and newest
+versions.  Otherwise, the value binds `version-control' (which see).
+
+Note: Backup will take place whenever you check new mails on a server.
+So, you may lose the backup files having been saved before a trouble
+if you set it so as to make too few backups whereas you have access to
+many servers."
+  :version "24.4"
+  :type '(choice (group :tag "Keep versions" :format "\n%v" :indent 3
+                       (number :tag "oldest")
+                       (number :tag "newest"))
+                (sexp :format "%v"
+                      :match (lambda (widget value)
+                               (condition-case nil
+                                   (not (and (numberp (car value))
+                                             (numberp (car (cdr value)))))
+                                 (error t)))))
+  :group 'pop3)
+
+(defvar pop3-timestamp nil
+  "Timestamp returned when initially connected to the POP server.
+Used for APOP authentication.")
+
+(defvar pop3-read-point nil)
+(defvar pop3-debug nil)
+
+;; Borrowed from nnheader-accept-process-output in nnheader.el.  See the
+;; comments there for explanations about the values.
+
+(eval-and-compile
+  (if (and (fboundp 'nnheader-accept-process-output)
+          (boundp 'nnheader-read-timeout))
+      (defalias 'pop3-accept-process-output 'nnheader-accept-process-output)
+    ;; Borrowed from `nnheader.el':
+    (defvar pop3-read-timeout
+      (if (string-match "windows-nt\\|os/2\\|cygwin"
+                       (symbol-name system-type))
+         1.0
+       0.01)
+      "How long pop3 should wait between checking for the end of output.
+Shorter values mean quicker response, but are more CPU intensive.")
+    (defun pop3-accept-process-output (process)
+      (accept-process-output
+       process
+       (truncate pop3-read-timeout)
+       (truncate (* (- pop3-read-timeout
+                      (truncate pop3-read-timeout))
+                   1000))))))
+
+(defvar pop3-uidl)
+;; List of UIDLs of existing messages at present in the server:
+;; ("UIDL1" "UIDL2" "UIDL3"...)
+
+(defvar pop3-uidl-saved)
+;; Locally saved UIDL data; an alist of the server, the user, and the UIDL
+;; and timestamp pairs:
+;; (("SERVER_A" ("USER_A1" "UIDL1" TIMESTAMP1 "UIDL2" TIMESTAMP2...)
+;;              ("USER_A2" "UIDL1" TIMESTAMP1 "UIDL2" TIMESTAMP2...)
+;;              ...)
+;;  ("SERVER_B" ("USER_B1" "UIDL1" TIMESTAMP1 "UIDL2" TIMESTAMP2...)
+;;              ("USER_B2" "UIDL1" TIMESTAMP1 "UIDL2" TIMESTAMP2...)
+;;              ...))
+;; Where TIMESTAMP is the most significant two digits of an Emacs time,
+;; i.e. the return value of `current-time'.
+
+;;;###autoload
+(defun pop3-movemail (file)
+  "Transfer contents of a maildrop to the specified FILE.
+Use streaming commands."
+  (let ((process (pop3-open-server pop3-mailhost pop3-port))
+       messages total-size
+       pop3-uidl
+       pop3-uidl-saved)
+    (pop3-logon process)
+    (if pop3-leave-mail-on-server
+       (setq messages (pop3-uidl-stat process)
+             total-size (cadr messages)
+             messages (car messages))
+      (let ((size (pop3-stat process)))
+       (dotimes (i (car size)) (push (1+ i) messages))
+       (setq messages (nreverse messages)
+             total-size (cadr size))))
+    (when messages
+      (with-current-buffer (process-buffer process)
+       (pop3-send-streaming-command process "RETR" messages total-size)
+       (pop3-write-to-file file messages)
+       (unless pop3-leave-mail-on-server
+         (pop3-send-streaming-command process "DELE" messages nil))))
+    (if pop3-leave-mail-on-server
+       (when (prog1 (pop3-uidl-dele process) (pop3-quit process))
+         (pop3-uidl-save))
+      (pop3-quit process)
+      ;; Remove UIDL data for the account that got not to leave mails.
+      (setq pop3-uidl-saved (pop3-uidl-load))
+      (let ((elt (assoc pop3-maildrop
+                       (cdr (assoc pop3-mailhost pop3-uidl-saved)))))
+       (when elt
+         (setcdr elt nil)
+         (pop3-uidl-save))))
+    t))
+
+(defun pop3-send-streaming-command (process command messages total-size)
+  (erase-buffer)
+  (let ((count (length messages))
+       (i 1)
+       (start-point (point-min))
+       (waited-for 0))
+    (while messages
+      (process-send-string process (format "%s %d\r\n" command (pop messages)))
+      ;; Only do 100 messages at a time to avoid pipe stalls.
+      (when (zerop (% i pop3-stream-length))
+       (setq start-point
+             (pop3-wait-for-messages process pop3-stream-length
+                                     total-size start-point))
+       (incf waited-for pop3-stream-length))
+      (incf i))
+    (pop3-wait-for-messages process (- count waited-for)
+                           total-size start-point)))
+
+(defun pop3-wait-for-messages (process count total-size start-point)
+  (while (> count 0)
+    (goto-char start-point)
+    (while (or (and (re-search-forward "^\\+OK" nil t)
+                   (or (not total-size)
+                       (re-search-forward "^\\.\r?\n" nil t)))
+              (re-search-forward "^-ERR " nil t))
+      (decf count)
+      (setq start-point (point)))
+    (unless (memq (process-status process) '(open run))
+      (error "pop3 process died"))
+    (when total-size
+      (let ((size 0))
+       (goto-char (point-min))
+       (while (re-search-forward "^\\+OK.*\n" nil t)
+         (setq size (+ size (- (point))
+                       (if (re-search-forward "^\\.\r?\n" nil 'move)
+                           (match-beginning 0)
+                         (point)))))
+       (message "pop3 retrieved %dKB (%d%%)"
+                (truncate (/ size 1000))
+                (truncate (* (/ (* size 1.0) total-size) 100)))))
+    (pop3-accept-process-output process))
+  start-point)
+
+(defun pop3-write-to-file (file messages)
+  (let ((pop-buffer (current-buffer))
+       (start (point-min))
+       beg end
+       temp-buffer)
+    (with-temp-buffer
+      (setq temp-buffer (current-buffer))
+      (with-current-buffer pop-buffer
+       (goto-char (point-min))
+       (while (re-search-forward "^\\+OK" nil t)
+         (forward-line 1)
+         (setq beg (point))
+         (when (re-search-forward "^\\.\r?\n" nil t)
+           (setq start (point))
+           (forward-line -1)
+           (setq end (point)))
+         (with-current-buffer temp-buffer
+           (goto-char (point-max))
+           (let ((hstart (point)))
+             (insert-buffer-substring pop-buffer beg end)
+             (pop3-clean-region hstart (point))
+             (goto-char (point-max))
+             (pop3-munge-message-separator hstart (point))
+             (when pop3-leave-mail-on-server
+               (pop3-uidl-add-xheader hstart (pop messages)))
+             (goto-char (point-max))))))
+      (let ((coding-system-for-write 'binary))
+       (goto-char (point-min))
+       ;; Check whether something inserted a newline at the start and
+       ;; delete it.
+       (when (eolp)
+         (delete-char 1))
+       (write-region (point-min) (point-max) file nil 'nomesg)))))
+
+(defun pop3-logon (process)
+  (let ((pop3-password pop3-password))
+    ;; for debugging only
+    (if pop3-debug (switch-to-buffer (process-buffer process)))
+    ;; query for password
+    (if (and pop3-password-required (not pop3-password))
+       (setq pop3-password
+             (read-passwd (format "Password for %s: " pop3-maildrop))))
+    (cond ((equal 'apop pop3-authentication-scheme)
+          (pop3-apop process pop3-maildrop))
+         ((equal 'pass pop3-authentication-scheme)
+          (pop3-user process pop3-maildrop)
+          (pop3-pass process))
+         (t (error "Invalid POP3 authentication scheme")))))
+
+(defun pop3-get-message-count ()
+  "Return the number of messages in the maildrop."
+  (let* ((process (pop3-open-server pop3-mailhost pop3-port))
+        message-count
+        (pop3-password pop3-password))
+    ;; for debugging only
+    (if pop3-debug (switch-to-buffer (process-buffer process)))
+    ;; query for password
+    (if (and pop3-password-required (not pop3-password))
+       (setq pop3-password
+             (read-passwd (format "Password for %s: " pop3-maildrop))))
+    (cond ((equal 'apop pop3-authentication-scheme)
+          (pop3-apop process pop3-maildrop))
+         ((equal 'pass pop3-authentication-scheme)
+          (pop3-user process pop3-maildrop)
+          (pop3-pass process))
+         (t (error "Invalid POP3 authentication scheme")))
+    (setq message-count (car (pop3-stat process)))
+    (pop3-quit process)
+    message-count))
+
+(defun pop3-uidl-stat (process)
+  "Return a list of unread message numbers and total size."
+  (pop3-send-command process "UIDL")
+  (let (err messages size)
+    (if (condition-case code
+           (progn
+             (pop3-read-response process)
+             t)
+         (error (setq err (error-message-string code))
+                nil))
+       (let ((start pop3-read-point)
+             saved list)
+         (with-current-buffer (process-buffer process)
+           (while (not (re-search-forward "^\\.\r\n" nil t))
+             (unless (memq (process-status process) '(open run))
+               (error "pop3 server closed the connection"))
+             (pop3-accept-process-output process)
+             (goto-char start))
+           (setq pop3-read-point (point-marker)
+                 pop3-uidl nil)
+           (while (progn (forward-line -1) (>= (point) start))
+             (when (looking-at "[0-9]+ \\([^\n\r ]+\\)")
+               (push (match-string 1) pop3-uidl)))
+           (when pop3-uidl
+             (setq pop3-uidl-saved (pop3-uidl-load)
+                   saved (cdr (assoc pop3-maildrop
+                                     (cdr (assoc pop3-mailhost
+                                                 pop3-uidl-saved)))))
+             (let ((i (length pop3-uidl)))
+               (while (> i 0)
+                 (unless (member (nth (1- i) pop3-uidl) saved)
+                   (push i messages))
+                 (decf i)))
+             (when messages
+               (setq list (pop3-list process)
+                     size 0)
+               (dolist (msg messages)
+                 (setq size (+ size (cdr (assq msg list)))))
+               (list messages size)))))
+      (message "%s doesn't support UIDL (%s), so we try a regressive way..."
+              pop3-mailhost err)
+      (sit-for 1)
+      (setq size (pop3-stat process))
+      (dotimes (i (car size)) (push (1+ i) messages))
+      (setcar size (nreverse messages))
+      size)))
+
+(defun pop3-uidl-dele (process)
+  "Delete messages according to `pop3-leave-mail-on-server'.
+Return non-nil if it is necessary to update the local UIDL file."
+  (let* ((ctime (current-time))
+        (srvr (assoc pop3-mailhost pop3-uidl-saved))
+        (saved (assoc pop3-maildrop (cdr srvr)))
+        i uidl mod new tstamp dele)
+    (setcdr (cdr ctime) nil)
+    ;; Add new messages to the data to be saved.
+    (cond ((and pop3-uidl saved)
+          (setq i (1- (length pop3-uidl)))
+          (while (>= i 0)
+            (unless (member (setq uidl (nth i pop3-uidl)) (cdr saved))
+              (push ctime new)
+              (push uidl new))
+            (decf i)))
+         (pop3-uidl
+          (setq new (apply 'nconc (mapcar (lambda (elt) (list elt ctime))
+                                          pop3-uidl)))))
+    (when new (setq mod t))
+    ;; List expirable messages and delete them from the data to be saved.
+    (setq ctime (when (numberp pop3-leave-mail-on-server)
+                 (/ (+ (* (car ctime) 65536.0) (cadr ctime)) 86400))
+         i (1- (length saved)))
+    (while (> i 0)
+      (if (member (setq uidl (nth (1- i) saved)) pop3-uidl)
+         (progn
+           (setq tstamp (nth i saved))
+           (if (and ctime
+                    (> (- ctime (/ (+ (* (car tstamp) 65536.0) (cadr tstamp))
+                                   86400))
+                       pop3-leave-mail-on-server))
+               ;; Mails to delete.
+               (progn
+                 (setq mod t)
+                 (push uidl dele))
+             ;; Mails to keep.
+             (push tstamp new)
+             (push uidl new)))
+       ;; Mails having been deleted in the server.
+       (setq mod t))
+      (decf i 2))
+    (cond (saved
+          (setcdr saved new))
+         (srvr
+          (setcdr (last srvr) (list (cons pop3-maildrop new))))
+         (t
+          (add-to-list 'pop3-uidl-saved
+                       (list pop3-mailhost (cons pop3-maildrop new))
+                       t)))
+    ;; Actually delete the messages in the server.
+    (when dele
+      (setq uidl nil
+           i (length pop3-uidl))
+      (while (> i 0)
+       (when (member (nth (1- i) pop3-uidl) dele)
+         (push i uidl))
+       (decf i))
+      (when uidl
+       (pop3-send-streaming-command process "DELE" uidl nil)))
+    mod))
+
+(defun pop3-uidl-load ()
+  "Load saved UIDL."
+  (when (file-exists-p pop3-uidl-file)
+    (with-temp-buffer
+      (condition-case code
+         (progn
+           (insert-file-contents pop3-uidl-file)
+           (goto-char (point-min))
+           (read (current-buffer)))
+       (error
+        (message "Error while loading %s (%s)"
+                 pop3-uidl-file (error-message-string code))
+        (sit-for 1)
+        nil)))))
+
+(defun pop3-uidl-save ()
+  "Save UIDL."
+  (with-temp-buffer
+    (if pop3-uidl-saved
+       (progn
+         (insert "(")
+         (dolist (srvr pop3-uidl-saved)
+           (when (cdr srvr)
+             (insert "(\"" (pop srvr) "\"\n  ")
+             (dolist (elt srvr)
+               (when (cdr elt)
+                 (insert "(\"" (pop elt) "\"\n   ")
+                 (while elt
+                   (insert (format "\"%s\" %s\n   " (pop elt) (pop elt))))
+                 (delete-char -4)
+                 (insert ")\n  ")))
+             (delete-char -3)
+             (if (eq (char-before) ?\))
+                 (insert ")\n ")
+               (goto-char (1+ (point-at-bol)))
+               (delete-region (point) (point-max)))))
+         (when (eq (char-before) ? )
+           (delete-char -2))
+         (insert ")\n"))
+      (insert "()\n"))
+    (let ((buffer-file-name pop3-uidl-file)
+         (delete-old-versions t)
+         (kept-new-versions kept-new-versions)
+         (kept-old-versions kept-old-versions)
+         (version-control version-control))
+      (if (consp pop3-uidl-file-backup)
+         (setq kept-new-versions (cadr pop3-uidl-file-backup)
+               kept-old-versions (car pop3-uidl-file-backup)
+               version-control t)
+       (setq version-control pop3-uidl-file-backup))
+      (save-buffer))))
+
+(defun pop3-uidl-add-xheader (start msgno)
+  "Add X-UIDL header."
+  (let ((case-fold-search t))
+    (save-restriction
+      (narrow-to-region start (progn
+                               (goto-char start)
+                               (search-forward "\n\n" nil 'move)
+                               (1- (point))))
+      (goto-char start)
+      (while (re-search-forward "^x-uidl:" nil t)
+       (while (progn
+                (forward-line 1)
+                (memq (char-after) '(?\t ? ))))
+       (delete-region (match-beginning 0) (point)))
+      (goto-char (point-max))
+      (insert "X-UIDL: " (nth (1- msgno) pop3-uidl) "\n"))))
+
+(defcustom pop3-stream-type nil
+  "*Transport security type for POP3 connections.
+This may be either nil (plain connection), `ssl' (use an
+SSL/TSL-secured stream) or `starttls' (use the starttls mechanism
+to turn on TLS security after opening the stream).  However, if
+this is nil, `ssl' is assumed for connections to port
+995 (pop3s)."
+  :version "23.1" ;; No Gnus
+  :group 'pop3
+  :type '(choice (const :tag "Plain" nil)
+                (const :tag "SSL/TLS" ssl)
+                (const starttls)))
+
+(eval-and-compile
+  (if (fboundp 'set-process-query-on-exit-flag)
+      (defalias 'pop3-set-process-query-on-exit-flag
+       'set-process-query-on-exit-flag)
+    (defalias 'pop3-set-process-query-on-exit-flag
+      'process-kill-without-query)))
+
+(defun pop3-open-server (mailhost port)
+  "Open TCP connection to MAILHOST on PORT.
+Returns the process associated with the connection."
+  (let ((coding-system-for-read 'binary)
+       (coding-system-for-write 'binary)
+       result)
+    (with-current-buffer
+        (get-buffer-create (concat " trace of POP session to "
+                                   mailhost))
+      (erase-buffer)
+      (setq pop3-read-point (point-min))
+      (setq result
+           (open-protocol-stream
+            "POP" (current-buffer) mailhost port
+            :type (cond
+                   ((or (eq pop3-stream-type 'ssl)
+                        (and (not pop3-stream-type)
+                             (member port '(995 "pop3s"))))
+                    'tls)
+                   (t
+                    (or pop3-stream-type 'network)))
+            :warn-unless-encrypted t
+            :capability-command "CAPA\r\n"
+            :end-of-command "^\\(-ERR\\|+OK\\).*\n"
+            :end-of-capability "^\\.\r?\n\\|^-ERR"
+            :success "^\\+OK.*\n"
+            :return-list t
+            :starttls-function
+            (lambda (capabilities)
+              (and (string-match "\\bSTLS\\b" capabilities)
+                   "STLS\r\n"))))
+      (when result
+       (let ((response (plist-get (cdr result) :greeting)))
+         (setq pop3-timestamp
+               (substring response (or (string-match "<" response) 0)
+                          (+ 1 (or (string-match ">" response) -1)))))
+       (pop3-set-process-query-on-exit-flag (car result) nil)
+       (erase-buffer)
+       (car result)))))
+
+;; Support functions
+
+(defun pop3-send-command (process command)
+  (set-buffer (process-buffer process))
+  (goto-char (point-max))
+  ;; (if (= (aref command 0) ?P)
+  ;;     (insert "PASS <omitted>\r\n")
+  ;;   (insert command "\r\n"))
+  (setq pop3-read-point (point))
+  (goto-char (point-max))
+  (process-send-string process (concat command "\r\n")))
+
+(defun pop3-read-response (process &optional return)
+  "Read the response from the server.
+Return the response string if optional second argument is non-nil."
+  (let ((case-fold-search nil)
+       match-end)
+    (with-current-buffer (process-buffer process)
+      (goto-char pop3-read-point)
+      (while (and (memq (process-status process) '(open run))
+                 (not (search-forward "\r\n" nil t)))
+       (pop3-accept-process-output process)
+       (goto-char pop3-read-point))
+      (setq match-end (point))
+      (goto-char pop3-read-point)
+      (if (looking-at "-ERR")
+         (error "%s" (buffer-substring (point) (- match-end 2)))
+       (if (not (looking-at "+OK"))
+           (progn (setq pop3-read-point match-end) nil)
+         (setq pop3-read-point match-end)
+         (if return
+             (buffer-substring (point) match-end)
+           t)
+         )))))
+
+(defun pop3-clean-region (start end)
+  (setq end (set-marker (make-marker) end))
+  (save-excursion
+    (goto-char start)
+    (while (and (< (point) end) (search-forward "\r\n" end t))
+      (replace-match "\n" t t))
+    (goto-char start)
+    (while (and (< (point) end) (re-search-forward "^\\." end t))
+      (replace-match "" t t)
+      (forward-char)))
+  (set-marker end nil))
+
+;; Copied from message-make-date.
+(defun pop3-make-date (&optional now)
+  "Make a valid date header.
+If NOW, use that time instead."
+  (require 'parse-time)
+  (let* ((now (or now (current-time)))
+        (zone (nth 8 (decode-time now)))
+        (sign "+"))
+    (when (< zone 0)
+      (setq sign "-")
+      (setq zone (- zone)))
+    (concat
+     (format-time-string "%d" now)
+     ;; The month name of the %b spec is locale-specific.  Pfff.
+     (format " %s "
+            (capitalize (car (rassoc (nth 4 (decode-time now))
+                                     parse-time-months))))
+     (format-time-string "%Y %H:%M:%S " now)
+     ;; We do all of this because XEmacs doesn't have the %z spec.
+     (format "%s%02d%02d" sign (/ zone 3600) (/ (% zone 3600) 60)))))
+
+(defun pop3-munge-message-separator (start end)
+  "Check to see if a message separator exists.  If not, generate one."
+  (save-excursion
+    (save-restriction
+      (narrow-to-region start end)
+      (goto-char (point-min))
+      (if (not (or (looking-at "From .?") ; Unix mail
+                  (looking-at "\001\001\001\001\n") ; MMDF
+                  (looking-at "BABYL OPTIONS:") ; Babyl
+                  ))
+         (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
+           ;; should be
+           ;; Tue Jul 9 09:04:21 1996
+
+           ;; Fixme: This should use timezone on the date field contents.
+           (setq date
+                 (cond ((not date)
+                        "Tue Jan 1 00:00:0 1900")
+                       ((string-match "[A-Z]" (nth 0 date))
+                        (format "%s %s %s %s %s"
+                                (nth 0 date) (nth 2 date) (nth 1 date)
+                                (nth 4 date) (nth 3 date)))
+                       (t
+                        ;; this really needs to be better but I don't feel
+                        ;; like writing a date to day converter.
+                        (format "Sun %s %s %s %s"
+                                (nth 1 date) (nth 0 date)
+                                (nth 3 date) (nth 2 date)))
+                       ))
+           (setq From_ (format "\nFrom %s  %s\n" from date))
+           (while (string-match "," From_)
+             (setq From_ (concat (substring From_ 0 (match-beginning 0))
+                                 (substring From_ (match-end 0)))))
+           (goto-char (point-min))
+           (insert From_)
+           (if (search-forward "\n\n" nil t)
+               nil
+             (goto-char (point-max))
+             (insert "\n"))
+           (let ((size (- (point-max) (point))))
+             (forward-line -1)
+             (insert (format "Content-Length: %s\n" size)))
+           )))))
+
+;; The Command Set
+
+;; AUTHORIZATION STATE
+
+(defun pop3-user (process user)
+  "Send USER information to POP3 server."
+  (pop3-send-command process (format "USER %s" user))
+  (let ((response (pop3-read-response process t)))
+    (if (not (and response (string-match "+OK" response)))
+       (error "USER %s not valid" user))))
+
+(defun pop3-pass (process)
+  "Send authentication information to the server."
+  (pop3-send-command process (format "PASS %s" pop3-password))
+  (let ((response (pop3-read-response process t)))
+    (if (not (and response (string-match "+OK" response)))
+       (pop3-quit process))))
+
+(defun pop3-apop (process user)
+  "Send alternate authentication information to the server."
+  (let ((pass pop3-password))
+    (if (and pop3-password-required (not pass))
+       (setq pass
+             (read-passwd (format "Password for %s: " pop3-maildrop))))
+    (if pass
+       (let ((hash (md5 (concat pop3-timestamp pass) nil nil 'binary)))
+         (pop3-send-command process (format "APOP %s %s" user hash))
+         (let ((response (pop3-read-response process t)))
+           (if (not (and response (string-match "+OK" response)))
+               (pop3-quit process)))))
+    ))
+
+;; TRANSACTION STATE
+
+(defun pop3-stat (process)
+  "Return the number of messages in the maildrop and the maildrop's size."
+  (pop3-send-command process "STAT")
+  (let ((response (pop3-read-response process t)))
+    (list (string-to-number (nth 1 (split-string response " ")))
+         (string-to-number (nth 2 (split-string response " "))))
+    ))
+
+(defun pop3-list (process &optional msg)
+  "If MSG is nil, return an alist of (MESSAGE-ID . SIZE) pairs.
+Otherwise, return the size of the message-id MSG"
+  (pop3-send-command process (if msg
+                                (format "LIST %d" msg)
+                              "LIST"))
+  (let ((response (pop3-read-response process t)))
+    (if msg
+       (string-to-number (nth 2 (split-string response " ")))
+      (let ((start pop3-read-point) end)
+       (with-current-buffer (process-buffer process)
+         (while (not (re-search-forward "^\\.\r\n" nil t))
+           (pop3-accept-process-output process)
+           (goto-char start))
+         (setq pop3-read-point (point-marker))
+         (goto-char (match-beginning 0))
+         (setq end (point-marker))
+         (mapcar #'(lambda (s) (let ((split (split-string s " ")))
+                                 (cons (string-to-number (nth 0 split))
+                                       (string-to-number (nth 1 split)))))
+                 (split-string (buffer-substring start end) "\r\n" t)))))))
+
+(defun pop3-retr (process msg crashbuf)
+  "Retrieve message-id MSG to buffer CRASHBUF."
+  (pop3-send-command process (format "RETR %s" msg))
+  (pop3-read-response process)
+  (let ((start pop3-read-point) end)
+    (with-current-buffer (process-buffer process)
+      (while (not (re-search-forward "^\\.\r\n" nil t))
+       (unless (memq (process-status process) '(open run))
+         (error "pop3 server closed the connection"))
+       (pop3-accept-process-output process)
+       (goto-char start))
+      (setq pop3-read-point (point-marker))
+      ;; this code does not seem to work for some POP servers...
+      ;; and I cannot figure out why not.
+      ;;      (goto-char (match-beginning 0))
+      ;;      (backward-char 2)
+      ;;      (if (not (looking-at "\r\n"))
+      ;;         (insert "\r\n"))
+      ;;      (re-search-forward "\\.\r\n")
+      (goto-char (match-beginning 0))
+      (setq end (point-marker))
+      (pop3-clean-region start end)
+      (pop3-munge-message-separator start end)
+      (with-current-buffer crashbuf
+       (erase-buffer))
+      (copy-to-buffer crashbuf start end)
+      (delete-region start end)
+      )))
+
+(defun pop3-dele (process msg)
+  "Mark message-id MSG as deleted."
+  (pop3-send-command process (format "DELE %s" msg))
+  (pop3-read-response process))
+
+(defun pop3-noop (process msg)
+  "No-operation."
+  (pop3-send-command process "NOOP")
+  (pop3-read-response process))
+
+(defun pop3-last (process)
+  "Return highest accessed message-id number for the session."
+  (pop3-send-command process "LAST")
+  (let ((response (pop3-read-response process t)))
+    (string-to-number (nth 1 (split-string response " ")))
+    ))
+
+(defun pop3-rset (process)
+  "Remove all delete marks from current maildrop."
+  (pop3-send-command process "RSET")
+  (pop3-read-response process))
+
+;; UPDATE
+
+(defun pop3-quit (process)
+  "Close connection to POP3 server.
+Tell server to remove all messages marked as deleted, unlock the maildrop,
+and close the connection."
+  (pop3-send-command process "QUIT")
+  (pop3-read-response process t)
+  (if process
+      (with-current-buffer (process-buffer process)
+       (goto-char (point-max))
+       (delete-process process))))
+\f
+;; Summary of POP3 (Post Office Protocol version 3) commands and responses
+
+;;; AUTHORIZATION STATE
+
+;; Initial TCP connection
+;; Arguments: none
+;; Restrictions: none
+;; Possible responses:
+;;  +OK [POP3 server ready]
+
+;; USER name
+;; Arguments: a server specific user-id (required)
+;; Restrictions: authorization state [after unsuccessful USER or PASS
+;; Possible responses:
+;;  +OK [valid user-id]
+;;  -ERR [invalid user-id]
+
+;; PASS string
+;; Arguments: a server/user-id specific password (required)
+;; Restrictions: authorization state, after successful USER
+;; Possible responses:
+;;  +OK [maildrop locked and ready]
+;;  -ERR [invalid password]
+;;  -ERR [unable to lock maildrop]
+
+;; STLS      (RFC 2595)
+;; Arguments: none
+;; Restrictions: Only permitted in AUTHORIZATION state.
+;; Possible responses:
+;;  +OK
+;;  -ERR
+
+;;; TRANSACTION STATE
+
+;; STAT
+;; Arguments: none
+;; Restrictions: transaction state
+;; Possible responses:
+;;  +OK nn mm [# of messages, size of maildrop]
+
+;; LIST [msg]
+;; Arguments: a message-id (optional)
+;; Restrictions: transaction state; msg must not be deleted
+;; Possible responses:
+;;  +OK [scan listing follows]
+;;  -ERR [no such message]
+
+;; RETR msg
+;; Arguments: a message-id (required)
+;; Restrictions: transaction state; msg must not be deleted
+;; Possible responses:
+;;  +OK [message contents follow]
+;;  -ERR [no such message]
+
+;; DELE msg
+;; Arguments: a message-id (required)
+;; Restrictions: transaction state; msg must not be deleted
+;; Possible responses:
+;;  +OK [message deleted]
+;;  -ERR [no such message]
+
+;; NOOP
+;; Arguments: none
+;; Restrictions: transaction state
+;; Possible responses:
+;;  +OK
+
+;; LAST
+;; Arguments: none
+;; Restrictions: transaction state
+;; Possible responses:
+;;  +OK nn [highest numbered message accessed]
+
+;; RSET
+;; Arguments: none
+;; Restrictions: transaction state
+;; Possible responses:
+;;  +OK [all delete marks removed]
+
+;; UIDL [msg]
+;; Arguments: a message-id (optional)
+;; Restrictions: transaction state; msg must not be deleted
+;; Possible responses:
+;;  +OK [uidl listing follows]
+;;  -ERR [no such message]
+
+;;; UPDATE STATE
+
+;; QUIT
+;; Arguments: none
+;; Restrictions: none
+;; Possible responses:
+;;  +OK [TCP connection closed]
+
+(provide 'pop3)
+
+;;; pop3.el ends here
diff --git a/xemacs-packages/gnus/lisp/proto-stream.el b/xemacs-packages/gnus/lisp/proto-stream.el
new file mode 100644 (file)
index 0000000..11ffd0c
--- /dev/null
@@ -0,0 +1,292 @@
+;;; proto-stream.el --- negotiating TLS, STARTTLS and other connections
+
+;; Copyright (C) 2010-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: network
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This library is meant to provide the glue between modules that want
+;; to establish a network connection to a server for protocols such as
+;; IMAP, NNTP, SMTP and POP3.
+
+;; The main problem is that there's more than a couple of interfaces
+;; towards doing this.  You have normal, plain connections, which are
+;; no trouble at all, but you also have TLS/SSL connections, and you
+;; have STARTTLS.  Negotiating this for each protocol can be rather
+;; tedious, so this library provides a single entry point, and hides
+;; much of the ugliness.
+
+;; Usage example:
+
+;; (open-protocol-stream
+;;  "*nnimap*" buffer address port
+;;  :type 'network
+;;  :capability-command "1 CAPABILITY\r\n"
+;;  :success " OK "
+;;  :starttls-function
+;;  (lambda (capabilities)
+;;    (if (not (string-match "STARTTLS" capabilities))
+;;        nil
+;;      "1 STARTTLS\r\n")))
+
+;;; Code:
+
+(require 'tls)
+(require 'starttls)
+
+(autoload 'gnutls-negotiate "gnutls")
+(autoload 'open-gnutls-stream "gnutls")
+
+;;;###autoload
+(defun open-protocol-stream (name buffer host service &rest parameters)
+  "Open a network stream to HOST, possibly with encryption.
+Normally, return a network process object; with a non-nil
+:return-list parameter, return a list instead (see below).
+
+The first four parameters, NAME, BUFFER, HOST, and SERVICE, have
+the same meanings as in `open-network-stream'.  The remaining
+PARAMETERS should be a sequence of keywords and values:
+
+:type specifies the connection type, one of the following:
+  nil or `network'
+             -- Begin with an ordinary network connection, and if
+                the parameters :success and :capability-command
+                are also supplied, try to upgrade to an encrypted
+                connection via STARTTLS.  Even if that
+                fails (e.g. if HOST does not support TLS), retain
+                an unencrypted connection.
+  `plain'    -- An ordinary, unencrypted network connection.
+  `starttls' -- Begin with an ordinary connection, and try
+                upgrading via STARTTLS.  If that fails for any
+                reason, drop the connection; in that case the
+                returned object is a killed process.
+  `tls'      -- A TLS connection.
+  `ssl'      -- Equivalent to `tls'.
+  `shell'    -- A shell connection.
+
+:return-list specifies this function's return value.
+  If omitted or nil, return a process object.  A non-nil means to
+  return (PROC . PROPS), where PROC is a process object and PROPS
+  is a plist of connection properties, with these keywords:
+   :greeting -- the greeting returned by HOST (a string), or nil.
+   :capabilities -- a string representing HOST's capabilities,
+                    or nil if none could be found.
+   :type -- the resulting connection type; `plain' (unencrypted)
+            or `tls' (TLS-encrypted).
+
+:end-of-command specifies a regexp matching the end of a command.
+  If non-nil, it defaults to \"\\n\".
+
+:end-of-capability specifies a regexp matching the end of the
+  response to the command specified for :capability-command.
+  It defaults to the regexp specified for :end-of-command.
+
+:success specifies a regexp matching a message indicating a
+  successful STARTTLS negotiation.  For instance, the default
+  should be \"^3\" for an NNTP connection.
+
+:capability-command specifies a command used to query the HOST
+  for its capabilities.  For instance, for IMAP this should be
+  \"1 CAPABILITY\\r\\n\".
+
+:starttls-function specifies a function for handling STARTTLS.
+  This function should take one parameter, the response to the
+  capability command, and should return the command to switch on
+  STARTTLS if the server supports STARTTLS, and nil otherwise."
+  (let ((type (plist-get parameters :type))
+       (return-list (plist-get parameters :return-list)))
+    (if (and (not return-list)
+            (or (eq type 'plain)
+                (and (memq type '(nil network))
+                     (not (and (plist-get parameters :success)
+                               (plist-get parameters :capability-command))))))
+       ;; The simplest case is equivalent to `open-network-stream'.
+       (open-network-stream name buffer host service)
+      ;; For everything else, refer to proto-stream-open-*.
+      (unless (plist-get parameters :end-of-command)
+       (setq parameters (append '(:end-of-command "\r\n") parameters)))
+      (let* ((connection-function
+             (cond
+              ((eq type 'plain) 'proto-stream-open-plain)
+              ((memq type '(nil network starttls))
+               'proto-stream-open-starttls)
+              ((memq type '(tls ssl)) 'proto-stream-open-tls)
+              ((eq type 'shell) 'proto-stream-open-shell)
+              (t (error "Invalid connection type %s" type))))
+            (result (funcall connection-function
+                             name buffer host service parameters)))
+       (if return-list
+           (list (car result)
+                 :greeting     (nth 1 result)
+                 :capabilities (nth 2 result)
+                 :type         (nth 3 result))
+         (car result))))))
+
+(defun proto-stream-open-plain (name buffer host service parameters)
+  (let ((start (with-current-buffer buffer (point)))
+       (stream (open-network-stream name buffer host service)))
+    (list stream
+         (proto-stream-get-response stream start
+                                    (plist-get parameters :end-of-command))
+         nil
+         'plain)))
+
+(defun proto-stream-open-starttls (name buffer host service parameters)
+  (let* ((start (with-current-buffer buffer (point)))
+        (require-tls    (eq (plist-get parameters :type) 'starttls))
+        (starttls-function  (plist-get parameters :starttls-function))
+        (success-string     (plist-get parameters :success))
+        (capability-command (plist-get parameters :capability-command))
+        (eoc                (plist-get parameters :end-of-command))
+        (eo-capa            (or (plist-get parameters :end-of-capability)
+                                eoc))
+        ;; Return (STREAM GREETING CAPABILITIES RESULTING-TYPE)
+        (stream (open-network-stream name buffer host service))
+        (greeting (proto-stream-get-response stream start eoc))
+        (capabilities (when capability-command
+                        (proto-stream-command stream
+                                              capability-command
+                                              (or eo-capa eoc))))
+        (resulting-type 'plain)
+        (builtin-starttls (and (fboundp 'gnutls-available-p)
+                               (gnutls-available-p)))
+        starttls-command)
+
+    ;; If we have built-in STARTTLS support, try to upgrade the
+    ;; connection.
+    (when (and (or builtin-starttls
+                  (and require-tls
+                       (executable-find "gnutls-cli")))
+              capabilities success-string starttls-function
+              (setq starttls-command
+                    (funcall starttls-function capabilities)))
+      ;; If using external STARTTLS, drop this connection and start
+      ;; anew with `starttls-open-stream'.
+      (unless builtin-starttls
+       (delete-process stream)
+       (setq start (with-current-buffer buffer (point-max)))
+       (let* ((starttls-use-gnutls t)
+              (starttls-extra-arguments
+               (if require-tls
+                   starttls-extra-arguments
+                 ;; For opportunistic TLS upgrades, we don't really
+                 ;; care about the identity of the peer.
+                 (cons "--insecure" starttls-extra-arguments))))
+         (setq stream (starttls-open-stream name buffer host service)))
+       (proto-stream-get-response stream start eoc))
+      (when (string-match success-string
+                         (proto-stream-command stream starttls-command eoc))
+       ;; The server said it was OK to begin STARTTLS negotiations.
+       (if builtin-starttls
+           (gnutls-negotiate :process stream :hostname host)
+         (unless (starttls-negotiate stream)
+           (delete-process stream)))
+       (if (memq (process-status stream) '(open run))
+           (setq resulting-type 'tls)
+         ;; We didn't successfully negotiate STARTTLS; if TLS
+         ;; isn't demanded, reopen an unencrypted connection.
+         (unless require-tls
+           (setq stream (open-network-stream name buffer host service))
+           (proto-stream-get-response stream start eoc)))
+       ;; Re-get the capabilities, which may have now changed.
+       (setq capabilities
+             (proto-stream-command stream capability-command eo-capa))))
+
+    ;; If TLS is mandatory, close the connection if it's unencrypted.
+    (and require-tls
+        (eq resulting-type 'plain)
+        (delete-process stream))
+    ;; Return value:
+    (list stream greeting capabilities resulting-type)))
+
+(defun proto-stream-command (stream command eoc)
+  (let ((start (with-current-buffer (process-buffer stream) (point-max))))
+    (process-send-string stream command)
+    (proto-stream-get-response stream start eoc)))
+
+(defun proto-stream-get-response (stream start end-of-command)
+  (with-current-buffer (process-buffer stream)
+    (save-excursion
+      (goto-char start)
+      (while (and (memq (process-status stream)
+                       '(open run))
+                 (not (re-search-forward end-of-command nil t)))
+       (accept-process-output stream 0 50)
+       (goto-char start))
+      (if (= start (point))
+         ;; The process died; return nil.
+         nil
+       ;; Return the data we got back.
+       (buffer-substring start (point))))))
+
+(defun proto-stream-open-tls (name buffer host service parameters)
+  (with-current-buffer buffer
+    (let* ((start (point-max))
+          (builtin-starttls (and (fboundp 'gnutls-available-p)
+                                 (gnutls-available-p)))
+          (stream
+           (funcall (if builtin-starttls
+                        'open-gnutls-stream
+                      'open-tls-stream)
+                    name buffer host service))
+          (eoc (plist-get parameters :end-of-command)))
+      (if (null stream)
+         (list nil nil nil 'plain)
+       ;; If we're using tls.el, we have to delete the output from
+       ;; openssl/gnutls-cli.
+       (unless builtin-starttls
+         (proto-stream-get-response stream start eoc)
+         (goto-char (point-min))
+         (when (re-search-forward eoc nil t)
+           (goto-char (match-beginning 0))
+           (delete-region (point-min) (line-beginning-position))))
+       (proto-stream-capability-open start stream parameters 'tls)))))
+
+(defun proto-stream-open-shell (name buffer host service parameters)
+  (require 'format-spec)
+  (proto-stream-capability-open
+   (with-current-buffer buffer (point))
+   (let ((process-connection-type nil))
+     (start-process name buffer shell-file-name
+                   shell-command-switch
+                   (format-spec
+                    (plist-get parameters :shell-command)
+                    (format-spec-make
+                     ?s host
+                     ?p service))))
+   parameters 'plain))
+
+(defun proto-stream-capability-open (start stream parameters stream-type)
+  (let* ((capability-command (plist-get parameters :capability-command))
+        (greeting (proto-stream-get-response
+                   stream start
+                   (plist-get parameters :end-of-command))))
+    (list stream greeting
+         (and capability-command
+              (proto-stream-command
+               stream capability-command
+               (or
+                (plist-get parameters :end-of-capability)
+                (plist-get parameters :end-of-command))))
+         stream-type)))
+
+(provide 'proto-stream)
+
+;;; proto-stream.el ends here
diff --git a/xemacs-packages/gnus/lisp/qp.el b/xemacs-packages/gnus/lisp/qp.el
new file mode 100644 (file)
index 0000000..d179cbb
--- /dev/null
@@ -0,0 +1,179 @@
+;;; qp.el --- Quoted-Printable functions
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: mail, extensions
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Functions for encoding and decoding quoted-printable text as
+;; defined in RFC 2045.
+
+;;; Code:
+
+(require 'mm-util)
+(defvar mm-use-ultra-safe-encoding)
+
+;;;###autoload
+(defun quoted-printable-decode-region (from to &optional coding-system)
+  "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.
+
+Interactively, you can supply the CODING-SYSTEM argument
+with \\[universal-coding-system-argument].
+
+The CODING-SYSTEM argument is a historical hangover and is deprecated.
+QP encodes raw bytes and should be decoded into raw bytes.  Decoding
+them into characters should be done separately."
+  (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
+    (save-restriction
+      ;; RFC 2045:  ``An "=" followed by two hexadecimal digits, one
+      ;; or both of which are lowercase letters in "abcdef", is
+      ;; formally illegal. A robust implementation might choose to
+      ;; recognize them as the corresponding uppercase letters.''
+      (let ((case-fold-search t))
+       (narrow-to-region from to)
+       ;; Do this in case we're called from Gnus, say, in a buffer
+       ;; which already contains non-ASCII characters which would
+       ;; then get doubly-decoded below.
+       (if coding-system
+           (mm-encode-coding-region (point-min) (point-max) coding-system))
+       (goto-char (point-min))
+       (while (and (skip-chars-forward "^=")
+                   (not (eobp)))
+         (cond ((eq (char-after (1+ (point))) ?\n)
+                (delete-char 2))
+               ((looking-at "\\(=[0-9A-F][0-9A-F]\\)+")
+                ;; Decode this sequence at once; i.e. by a single
+                ;; deletion and insertion.
+                (let* ((n (/ (- (match-end 0) (point)) 3))
+                       (str (make-string n 0)))
+                  (dotimes (i n)
+                     (let ((n1 (char-after (1+ (point))))
+                           (n2 (char-after (+ 2 (point)))))
+                       (aset str i
+                             (+ (* 16 (- n1 (if (<= n1 ?9) ?0
+                                              (if (<= n1 ?F) (- ?A 10)
+                                                (- ?a 10)))))
+                                (- n2 (if (<= n2 ?9) ?0
+                                        (if (<= n2 ?F) (- ?A 10)
+                                          (- ?a 10)))))))
+                    (forward-char 3))
+                  (delete-region (match-beginning 0) (match-end 0))
+                  (insert str)))
+               (t
+                (message "Malformed quoted-printable text")
+                (forward-char)))))
+      (if coding-system
+         (mm-decode-coding-region (point-min) (point-max) coding-system)))))
+
+(defun quoted-printable-decode-string (string &optional coding-system)
+  "Decode the quoted-printable encoded STRING and return the result.
+If CODING-SYSTEM is non-nil, decode the string with coding-system.
+Use of CODING-SYSTEM is deprecated; this function should deal with
+raw bytes, and coding conversion should be done separately."
+  (mm-with-unibyte-buffer
+    (insert string)
+    (quoted-printable-decode-region (point-min) (point-max) coding-system)
+    (buffer-string)))
+
+(defun quoted-printable-encode-region (from to &optional fold class)
+  "Quoted-printable encode the region between FROM and TO per RFC 2045.
+
+If FOLD, fold long lines at 76 characters (as required by the RFC).
+If CLASS is non-nil, translate the characters not matched by that
+regexp class, which is in the form expected by `skip-chars-forward'.
+You should probably avoid non-ASCII characters in this arg.
+
+If `mm-use-ultra-safe-encoding' is set, fold lines unconditionally and
+encode lines starting with \"From\"."
+  (interactive "r")
+  (unless class
+    ;; Avoid using 8bit characters. = is \075.
+    ;; Equivalent to "^\000-\007\013\015-\037\200-\377="
+    (setq class "\010-\012\014\040-\074\076-\177"))
+  (save-excursion
+    (goto-char from)
+    (if (re-search-forward (mm-string-to-multibyte "[^\x0-\x7f\x80-\xff]")
+                          to t)
+       (error "Multibyte character in QP encoding region"))
+    (save-restriction
+      (narrow-to-region from to)
+      ;; Encode all the non-ascii and control characters.
+      (goto-char (point-min))
+      (while (and (skip-chars-forward class)
+                 (not (eobp)))
+       (insert
+        (prog1
+            ;; To unibyte in case of Emacs 23 (unicode) eight-bit.
+            (format "=%02X" (mm-multibyte-char-to-unibyte (char-after)))
+          (delete-char 1))))
+      ;; Encode white space at the end of lines.
+      (goto-char (point-min))
+      (while (re-search-forward "[ \t]+$" nil t)
+       (goto-char (match-beginning 0))
+       (while (not (eolp))
+         (insert
+          (prog1
+              (format "=%02X" (char-after))
+            (delete-char 1)))))
+      (let ((mm-use-ultra-safe-encoding
+            (and (boundp 'mm-use-ultra-safe-encoding)
+                 mm-use-ultra-safe-encoding)))
+       (when (or fold mm-use-ultra-safe-encoding)
+         (let ((tab-width 1)           ; HTAB is one character.
+               (case-fold-search nil))
+           (goto-char (point-min))
+           (while (not (eobp))
+             ;; In ultra-safe mode, encode "From " at the beginning
+             ;; of a line.
+             (when mm-use-ultra-safe-encoding
+               (if (looking-at "From ")
+                   (replace-match "From=20" nil t)
+                 (if (looking-at "-")
+                     (replace-match "=2D" nil t))))
+             (end-of-line)
+             ;; Fold long lines.
+             (while (> (current-column) 76) ; tab-width must be 1.
+               (beginning-of-line)
+               (forward-char 75)       ; 75 chars plus an "="
+               (search-backward "=" (- (point) 2) t)
+               (insert "=\n")
+               (end-of-line))
+             (forward-line))))))))
+
+(defun quoted-printable-encode-string (string)
+  "Encode the STRING as quoted-printable and return the result."
+  (with-temp-buffer
+    (if (mm-multibyte-string-p string)
+       (mm-enable-multibyte)
+      (mm-disable-multibyte))
+    (insert string)
+    (quoted-printable-encode-region (point-min) (point-max))
+    (buffer-string)))
+
+(provide 'qp)
+
+;;; qp.el ends here
diff --git a/xemacs-packages/gnus/lisp/registry.el b/xemacs-packages/gnus/lisp/registry.el
new file mode 100644 (file)
index 0000000..950bbc8
--- /dev/null
@@ -0,0 +1,398 @@
+;;; registry.el --- Track and remember data items by various fields
+
+;; Copyright (C) 2011-2016 Free Software Foundation, Inc.
+
+;; Author: Teodor Zlatanov <tzz@lifelogs.com>
+;; Keywords: data
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This library provides a general-purpose EIEIO-based registry
+;; database with persistence, initialized with these fields:
+
+;; version: a float
+
+;; max-size: an integer, default most-positive-fixnum
+
+;; prune-factor: a float between 0 and 1, default 0.1
+
+;; precious: a list of symbols
+
+;; tracked: a list of symbols
+
+;; tracker: a hashtable tuned for 100 symbols to track (you should
+;; only access this with the :lookup2-function and the
+;; :lookup2+-function)
+
+;; data: a hashtable with default size 10K and resize threshold 2.0
+;; (this reflects the expected usage so override it if you know better)
+
+;; ...plus methods to do all the work: `registry-search',
+;; `registry-lookup', `registry-lookup-secondary',
+;; `registry-lookup-secondary-value', `registry-insert',
+;; `registry-delete', `registry-prune', `registry-size' which see
+
+;; and with the following properties:
+
+;; Every piece of data has a unique ID and some general-purpose fields
+;; (F1=D1, F2=D2, F3=(a b c)...) expressed as an alist, e.g.
+
+;; ((F1 D1) (F2 D2) (F3 a b c))
+
+;; Note that whether a field has one or many pieces of data, the data
+;; is always a list of values.
+
+;; The user decides which fields are "precious", F2 for example.  When
+;; the registry is pruned, any entries without the F2 field will be
+;; removed until the size is :max-size * :prune-factor _less_ than the
+;; maximum database size. No entries with the F2 field will be removed
+;; at PRUNE TIME, which means it may not be possible to prune back all
+;; the way to the target size.
+
+;; When an entry is inserted, the registry will reject new entries if
+;; they bring it over the :max-size limit, even if they have the F2
+;; field.
+
+;; The user decides which fields are "tracked", F1 for example.  Any
+;; new entry is then indexed by all the tracked fields so it can be
+;; quickly looked up that way.  The data is always a list (see example
+;; above) and each list element is indexed.
+
+;; Precious and tracked field names must be symbols.  All other
+;; fields can be any other Emacs Lisp types.
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(eval-and-compile
+  (or (ignore-errors (progn
+                       (require 'eieio)
+                       (require 'eieio-base)))
+      ;; gnus-fallback-lib/ from gnus/lisp/gnus-fallback-lib
+      (ignore-errors
+        (let ((load-path (cons (expand-file-name
+                                "gnus-fallback-lib/eieio"
+                                (file-name-directory (locate-library "gnus")))
+                               load-path)))
+          (require 'eieio)
+          (require 'eieio-base)))
+      (error
+       "eieio not found in `load-path' or gnus-fallback-lib/ directory.")))
+
+(eval-when-compile
+  (unless (fboundp 'cl-remf)
+    (defalias 'cl-remf 'remf)
+    (defalias 'cl-loop 'loop)
+    (defalias 'cl-subseq 'subseq)))
+
+;; The version number needs to be kept outside of the class definition
+;; itself.  The persistent-save process does *not* write to file any
+;; slot values that are equal to the default :initform value.  If a
+;; database object is at the most recent version, therefore, its
+;; version number will not be written to file.  That makes it
+;; difficult to know when a database needs to be upgraded.
+(defvar registry-db-version 0.2
+  "The current version of the registry format.")
+
+(eval `
+(defclass registry-db (eieio-persistent)
+  ((version :initarg :version
+            :initform nil
+            :type (or null float)
+            :documentation "The registry version.")
+   (max-size :initarg :max-size
+            ;; EIEIO's :initform is not 100% compatible with CLOS in
+            ;; that if the form is an atom, it assumes it's constant
+            ;; value rather than an expression, so in order to get the value
+            ;; of `most-positive-fixnum', we need to use an
+            ;; expression that's not just a symbol.
+             :initform ,(symbol-value 'most-positive-fixnum)
+             :type integer
+             :custom integer
+             :documentation "The maximum number of registry entries.")
+   (prune-factor
+    :initarg :prune-factor
+    :initform 0.1
+    :type float
+    :custom float
+    :documentation "Prune to (:max-size * :prune-factor) less
+    than the :max-size limit.  Should be a float between 0 and 1.")
+   (tracked :initarg :tracked
+            :initform nil
+            :type t
+            :documentation "The tracked (indexed) fields, a list of symbols.")
+   (precious :initarg :precious
+             :initform nil
+             :type t
+             :documentation "The precious fields, a list of symbols.")
+   (tracker :initarg :tracker
+            :type hash-table
+            :documentation "The field tracking hashtable.")
+   (data :initarg :data
+         :type hash-table
+         :documentation "The data hashtable.")))
+)
+
+(defmethod initialize-instance :BEFORE ((this registry-db) slots)
+  "Check whether a registry object needs to be upgraded."
+  ;; Hardcoded upgrade routines.  Version 0.1 to 0.2 requires the
+  ;; :max-soft slot to disappear, and the :max-hard slot to be renamed
+  ;; :max-size.
+  (let ((current-version
+        (and (plist-member slots :version)
+             (plist-get slots :version))))
+    (when (or (null current-version)
+             (eql current-version 0.1))
+      (setq slots
+           (plist-put slots :max-size (plist-get slots :max-hard)))
+      (setq slots
+           (plist-put slots :version registry-db-version))
+      (cl-remf slots :max-hard)
+      (cl-remf slots :max-soft))))
+
+(defmethod initialize-instance :AFTER ((this registry-db) slots)
+  "Set value of data slot of THIS after initialization."
+  (with-slots (data tracker) this
+    (unless (member :data slots)
+      (setq data
+           (make-hash-table :size 10000 :rehash-size 2.0 :test 'equal)))
+    (unless (member :tracker slots)
+      (setq tracker (make-hash-table :size 100 :rehash-size 2.0)))))
+
+(defmethod registry-lookup ((db registry-db) keys)
+  "Search for KEYS in the registry-db THIS.
+Returns an alist of the key followed by the entry in a list, not a cons cell."
+  (let ((data (oref db data)))
+    (delq nil
+         (mapcar
+          (lambda (k)
+            (when (gethash k data)
+              (list k (gethash k data))))
+          keys))))
+
+(defmethod registry-lookup-breaks-before-lexbind ((db registry-db) keys)
+  "Search for KEYS in the registry-db THIS.
+Returns an alist of the key followed by the entry in a list, not a cons cell."
+  (let ((data (oref db data)))
+    (delq nil
+         (loop for key in keys
+               when (gethash key data)
+               collect (list key (gethash key data))))))
+
+(defmethod registry-lookup-secondary ((db registry-db) tracksym
+                                     &optional create)
+  "Search for TRACKSYM in the registry-db THIS.
+When CREATE is not nil, create the secondary index hashtable if needed."
+  (let ((h (gethash tracksym (oref db :tracker))))
+    (if h
+       h
+      (when create
+       (puthash tracksym
+                (make-hash-table :size 800 :rehash-size 2.0 :test 'equal)
+                (oref db tracker))
+       (gethash tracksym (oref db tracker))))))
+
+(defmethod registry-lookup-secondary-value ((db registry-db) tracksym val
+                                           &optional set)
+  "Search for TRACKSYM with value VAL in the registry-db THIS.
+When SET is not nil, set it for VAL (use t for an empty list)."
+  ;; either we're asked for creation or there should be an existing index
+  (when (or set (registry-lookup-secondary db tracksym))
+    ;; set the entry if requested,
+    (when set
+      (puthash val (if (eq t set) '() set)
+              (registry-lookup-secondary db tracksym t)))
+    (gethash val (registry-lookup-secondary db tracksym))))
+
+(defun registry--match (mode entry check-list)
+  ;; for all members
+  (when check-list
+    (let ((key (nth 0 (nth 0 check-list)))
+          (vals (cdr-safe (nth 0 check-list)))
+          found)
+      (while (and key vals (not found))
+        (setq found (case mode
+                      (:member
+                       (member (car-safe vals) (cdr-safe (assoc key entry))))
+                      (:regex
+                       (string-match (car vals)
+                                     (mapconcat
+                                      'prin1-to-string
+                                      (cdr-safe (assoc key entry))
+                                      "\0"))))
+              vals (cdr-safe vals)))
+      (or found
+          (registry--match mode entry (cdr-safe check-list))))))
+
+(defmethod registry-search ((db registry-db) &rest spec)
+  "Search for SPEC across the registry-db THIS.
+For example calling with `:member \\='(a 1 2)' will match entry \((a 3 1)).
+Calling with `:all t' (any non-nil value) will match all.
+Calling with `:regex \\='(a \"h.llo\")' will match entry \(a \"hullo\" \"bye\").
+The test order is to check :all first, then :member, then :regex."
+  (when db
+    (let ((all (plist-get spec :all))
+         (member (plist-get spec :member))
+         (regex (plist-get spec :regex)))
+      (loop for k being the hash-keys of (oref db data)
+           using (hash-values v)
+           when (or
+                 ;; :all non-nil returns all
+                 all
+                 ;; member matching
+                 (and member (registry--match :member v member))
+                 ;; regex matching
+                 (and regex (registry--match :regex v regex)))
+           collect k))))
+
+(defmethod registry-delete ((db registry-db) keys assert &rest spec)
+  "Delete KEYS from the registry-db THIS.
+If KEYS is nil, use SPEC to do a search.
+Updates the secondary ('tracked') indices as well.
+With assert non-nil, errors out if the key does not exist already."
+  (let* ((data (oref db data))
+        (keys (or keys
+                  (apply 'registry-search db spec)))
+        (tracked (oref db tracked)))
+
+    (dolist (key keys)
+      (let ((entry (gethash key data)))
+       (when assert
+         (assert entry nil
+                 "Key %s does not exist in database" key))
+       ;; clean entry from the secondary indices
+       (dolist (tr tracked)
+         ;; is this tracked symbol indexed?
+         (when (registry-lookup-secondary db tr)
+           ;; for every value in the entry under that key...
+           (dolist (val (cdr-safe (assq tr entry)))
+             (let* ((value-keys (registry-lookup-secondary-value
+                                 db tr val)))
+               (when (member key value-keys)
+                 ;; override the previous value
+                 (registry-lookup-secondary-value
+                  db tr val
+                  ;; with the indexed keys MINUS the current key
+                  ;; (we pass t when the list is empty)
+                  (or (delete key value-keys) t)))))))
+       (remhash key data)))
+    keys))
+
+(defmethod registry-size ((db registry-db))
+  "Returns the size of the registry-db object THIS.
+This is the key count of the `data' slot."
+  (hash-table-count (oref db data)))
+
+(defmethod registry-full ((db registry-db))
+  "Checks if registry-db THIS is full."
+  (>= (registry-size db)
+      (oref db max-size)))
+
+(defmethod registry-insert ((db registry-db) key entry)
+  "Insert ENTRY under KEY into the registry-db THIS.
+Updates the secondary ('tracked') indices as well.
+Errors out if the key exists already."
+
+  (assert (not (gethash key (oref db data))) nil
+         "Key already exists in database")
+
+  (assert (not (registry-full db))
+         nil
+         "registry max-size limit reached")
+
+  ;; store the entry
+  (puthash key entry (oref db data))
+
+  ;; store the secondary indices
+  (dolist (tr (oref db tracked))
+    ;; for every value in the entry under that key...
+    (dolist (val (cdr-safe (assq tr entry)))
+      (let* ((value-keys (registry-lookup-secondary-value db tr val)))
+       (pushnew key value-keys :test 'equal)
+       (registry-lookup-secondary-value db tr val value-keys))))
+  entry)
+
+(defmethod registry-reindex ((db registry-db))
+  "Rebuild the secondary indices of registry-db THIS."
+  (let ((count 0)
+       (expected (* (length (oref db tracked)) (registry-size db))))
+    (dolist (tr (oref db tracked))
+      (let (values)
+       (maphash
+        (lambda (key v)
+          (incf count)
+          (when (and (< 0 expected)
+                     (= 0 (mod count 1000)))
+            (message "reindexing: %d of %d (%.2f%%)"
+                     count expected (/ (* 100.0 count) expected)))
+          (dolist (val (cdr-safe (assq tr v)))
+            (let* ((value-keys (registry-lookup-secondary-value db tr val)))
+              (push key value-keys)
+              (registry-lookup-secondary-value db tr val value-keys))))
+        (oref db data))))))
+
+(defmethod registry-prune ((db registry-db) &optional sortfunc)
+  "Prunes the registry-db object DB.
+
+Attempts to prune the number of entries down to \(*
+:max-size :prune-factor) less than the max-size limit, so
+pruning doesn't need to happen on every save. Removes only
+entries without the :precious keys, so it may not be possible to
+reach the target limit.
+
+Entries to be pruned are first sorted using SORTFUNC.  Entries
+from the front of the list are deleted first.
+
+Returns the number of deleted entries."
+  (let ((size (registry-size db))
+       (target-size
+        (floor (- (oref db max-size)
+                  (* (oref db max-size)
+                     (oref db prune-factor)))))
+       candidates)
+    (if (registry-full db)
+       (progn
+         (setq candidates
+               (registry-collect-prune-candidates
+                db (- size target-size) sortfunc))
+         (length (registry-delete db candidates nil)))
+      0)))
+
+(defmethod registry-collect-prune-candidates ((db registry-db) limit sortfunc)
+  "Collects pruning candidates from the registry-db object DB.
+
+Proposes only entries without the :precious keys, and attempts to
+return LIMIT such candidates.  If SORTFUNC is provided, sort
+entries first and return candidates from beginning of list."
+  (let* ((precious (oref db precious))
+        (precious-p (lambda (entry-key)
+                      (cdr (memq (car entry-key) precious))))
+        (data (oref db data))
+        (candidates (cl-loop for k being the hash-keys of data
+                             using (hash-values v)
+                             when (notany precious-p v)
+                             collect (cons k v))))
+    ;; We want the full entries for sorting, but should only return a
+    ;; list of entry keys.
+    (when sortfunc
+      (setq candidates (sort candidates sortfunc)))
+    (cl-subseq (mapcar #'car candidates) 0 (min limit (length candidates)))))
+
+(provide 'registry)
+;;; registry.el ends here
diff --git a/xemacs-packages/gnus/lisp/rfc1843.el b/xemacs-packages/gnus/lisp/rfc1843.el
new file mode 100644 (file)
index 0000000..1dbd11d
--- /dev/null
@@ -0,0 +1,189 @@
+;;; rfc1843.el --- HZ (rfc1843) decoding
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Shenghuo Zhu <zsh@cs.rochester.edu>
+;; Keywords: news HZ HZ+ mail i18n
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Usage:
+;; (require 'rfc1843)
+;; (rfc1843-gnus-setup)
+;;
+;; Test:
+;; (rfc1843-decode-string  "~{<:Ky2;S{#,NpJ)l6HK!#~}")
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(require 'mm-util)
+
+(defvar gnus-decode-encoded-word-function)
+(defvar gnus-decode-header-function)
+(defvar gnus-newsgroup-name)
+
+(defvar rfc1843-word-regexp
+  "~\\({\\([\041-\167][\041-\176]\\| \\)+\\)\\(~}\\|$\\)")
+
+(defvar rfc1843-word-regexp-strictly
+  "~\\({\\([\041-\167][\041-\176]\\)+\\)\\(~}\\|$\\)")
+
+(defvar rfc1843-hzp-word-regexp
+  "~\\({\\([\041-\167][\041-\176]\\| \\)+\\|\
+[<>]\\([\041-\175][\041-\176]\\| \\)+\\)\\(~}\\|$\\)")
+
+(defvar rfc1843-hzp-word-regexp-strictly
+  "~\\({\\([\041-\167][\041-\176]\\)+\\|\
+[<>]\\([\041-\175][\041-\176]\\)+\\)\\(~}\\|$\\)")
+
+(defcustom rfc1843-decode-loosely nil
+  "Loosely check HZ encoding if non-nil.
+When it is set non-nil, only buffers or strings with strictly
+HZ-encoded are decoded."
+  :type 'boolean
+  :group 'mime)
+
+(defcustom rfc1843-decode-hzp t
+  "HZ+ decoding support if non-nil.
+HZ+ specification (also known as HZP) is to provide a standardized
+7-bit representation of mixed Big5, GB, and ASCII text for convenient
+e-mail transmission, news posting, etc.
+The document of HZ+ 0.78 specification can be found at
+ftp://ftp.math.psu.edu/pub/simpson/chinese/hzp/hzp.doc"
+  :type 'boolean
+  :group 'mime)
+
+(defcustom rfc1843-newsgroups-regexp "chinese\\|hz"
+  "Regexp of newsgroups in which might be HZ encoded."
+  :type 'string
+  :group 'mime)
+
+(defun rfc1843-decode-region (from to)
+  "Decode HZ in the region between FROM and TO."
+  (interactive "r")
+  (let (str firstc)
+    (save-excursion
+      (goto-char from)
+      (if (or rfc1843-decode-loosely
+             (re-search-forward (if rfc1843-decode-hzp
+                                    rfc1843-hzp-word-regexp-strictly
+                                  rfc1843-word-regexp-strictly) to t))
+         (save-restriction
+           (narrow-to-region from to)
+           (goto-char (point-min))
+           (while (re-search-forward (if rfc1843-decode-hzp
+                                         rfc1843-hzp-word-regexp
+                                       rfc1843-word-regexp) (point-max) t)
+             ;;; Text with extents may cause XEmacs crash
+             (setq str (buffer-substring-no-properties
+                        (match-beginning 1)
+                        (match-end 1)))
+             (setq firstc (aref str 0))
+             (insert (mm-decode-coding-string
+                      (rfc1843-decode
+                       (prog1
+                           (substring str 1)
+                         (delete-region (match-beginning 0) (match-end 0)))
+                       firstc)
+                      (if (eq firstc ?{) 'cn-gb-2312 'cn-big5))))
+           (goto-char (point-min))
+           (while (search-forward "~" (point-max) t)
+             (cond ((eq (char-after) ?\n)
+                    (delete-char -1)
+                    (delete-char 1))
+                   ((eq (char-after) ?~)
+                    (delete-char 1)))))))))
+
+(defun rfc1843-decode-string (string)
+  "Decode HZ STRING and return the results."
+  (let ((m (mm-multibyte-p)))
+    (with-temp-buffer
+      (when m
+       (mm-enable-multibyte))
+      (insert string)
+      (inline
+       (rfc1843-decode-region (point-min) (point-max)))
+      (buffer-string))))
+
+(defun rfc1843-decode (word &optional firstc)
+  "Decode HZ WORD and return it."
+  (let ((i -1) (s (substring word 0)) v)
+    (if (or (not firstc) (eq firstc ?{))
+       (while (< (incf i) (length s))
+         (if (eq (setq v (aref s i)) ? ) nil
+           (aset s i (+ 128 v))))
+      (while (< (incf i) (length s))
+       (if (eq (setq v (aref s i)) ? ) nil
+         (setq v (+ (* 94 v) (aref s (1+ i)) -3135))
+         (aset s i (+ (/ v 157) (if (eq firstc ?<) 201 161)))
+         (setq v (% v 157))
+         (aset s (incf i) (+ v (if (< v 63) 64 98))))))
+    s))
+
+(autoload 'mail-header-parse-content-type "mail-parse")
+(autoload 'message-narrow-to-head "message")
+(declare-function message-fetch-field "message" (header &optional not-all))
+
+(defun rfc1843-decode-article-body ()
+  "Decode HZ encoded text in the article body."
+  (if (string-match (concat "\\<\\(" rfc1843-newsgroups-regexp "\\)\\>")
+                   (or gnus-newsgroup-name ""))
+      (save-excursion
+       (save-restriction
+         (message-narrow-to-head)
+         (let* ((inhibit-point-motion-hooks t)
+                (case-fold-search t)
+                (ct (message-fetch-field "Content-Type" t))
+                (ctl (and ct (mail-header-parse-content-type ct))))
+           (if (and ctl (not (string-match "/" (car ctl))))
+               (setq ctl nil))
+           (goto-char (point-max))
+           (widen)
+           (forward-line 1)
+           (narrow-to-region (point) (point-max))
+           (when (or (not ctl)
+                     (equal (car ctl) "text/plain"))
+             (rfc1843-decode-region (point) (point-max))))))))
+
+(defvar gnus-decode-header-methods)
+(defvar gnus-decode-encoded-word-methods)
+
+(defun rfc1843-gnus-setup ()
+  "Setup HZ decoding for Gnus."
+  (require 'gnus-art)
+  (require 'gnus-sum)
+  (add-hook 'gnus-article-decode-hook 'rfc1843-decode-article-body t)
+  (setq gnus-decode-encoded-word-function
+       'gnus-multi-decode-encoded-word-string
+       gnus-decode-header-function
+       'gnus-multi-decode-header
+       gnus-decode-encoded-word-methods
+       (nconc gnus-decode-encoded-word-methods
+              (list
+               (cons (concat "\\<\\(" rfc1843-newsgroups-regexp "\\)\\>")
+                     'rfc1843-decode-string)))
+       gnus-decode-header-methods
+       (nconc gnus-decode-header-methods
+              (list
+               (cons (concat "\\<\\(" rfc1843-newsgroups-regexp "\\)\\>")
+                     'rfc1843-decode-region)))))
+
+(provide 'rfc1843)
+
+;;; rfc1843.el ends here
diff --git a/xemacs-packages/gnus/lisp/rfc2045.el b/xemacs-packages/gnus/lisp/rfc2045.el
new file mode 100644 (file)
index 0000000..c2ddf90
--- /dev/null
@@ -0,0 +1,41 @@
+;;; rfc2045.el --- Functions for decoding rfc2045 headers
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;; RFC 2045 is: "Multipurpose Internet Mail Extensions (MIME) Part
+;; One:  Format of Internet Message Bodies".
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ietf-drums)
+
+(defun rfc2045-encode-string (param value)
+  "Return and PARAM=VALUE string encoded according to RFC2045."
+  (if (or (string-match (concat "[" ietf-drums-no-ws-ctl-token "]") value)
+         (string-match (concat "[" ietf-drums-tspecials "]") value)
+         (string-match "[ \n\t]" value)
+         (not (string-match (concat "[" ietf-drums-text-token "]") value)))
+      (concat param "=" (format "%S" value))
+    (concat param "=" value)))
+
+(provide 'rfc2045)
+
+;;; rfc2045.el ends here
diff --git a/xemacs-packages/gnus/lisp/rfc2047.el b/xemacs-packages/gnus/lisp/rfc2047.el
new file mode 100644 (file)
index 0000000..6647d10
--- /dev/null
@@ -0,0 +1,1175 @@
+;;; rfc2047.el --- functions for encoding and decoding rfc2047 messages
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;;     MORIOKA Tomohiko <morioka@jaist.ac.jp>
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; RFC 2047 is "MIME (Multipurpose Internet Mail Extensions) Part
+;; Three:  Message Header Extensions for Non-ASCII Text".
+
+;;; Code:
+
+(eval-when-compile
+  (require 'cl))
+(defvar message-posting-charset)
+
+(require 'mm-util)
+(require 'ietf-drums)
+;; Fixme: Avoid this (used for mail-parse-charset) mm dependence on gnus.
+(require 'mail-prsvr)
+(require 'rfc2045) ;; rfc2045-encode-string
+(autoload 'mm-body-7-or-8 "mm-bodies")
+
+(defvar rfc2047-header-encoding-alist
+  '(("Newsgroups" . nil)
+    ("Followup-To" . nil)
+    ("Message-ID" . nil)
+    ("\\(Resent-\\)?\\(From\\|Cc\\|To\\|Bcc\\|\\(In-\\)?Reply-To\\|Sender\
+\\|Mail-Followup-To\\|Mail-Copies-To\\|Approved\\)" . address-mime)
+    (t . mime))
+  "*Header/encoding method alist.
+The list is traversed sequentially.  The keys can either be
+header regexps or t.
+
+The values can be:
+
+1) nil, in which case no encoding is done;
+2) `mime', in which case the header will be encoded according to RFC2047;
+3) `address-mime', like `mime', but takes account of the rules for address
+   fields (where quoted strings and comments must be treated separately);
+4) a charset, in which case it will be encoded as that charset;
+5) `default', in which case the field will be encoded as the rest
+   of the article.")
+
+(defvar rfc2047-charset-encoding-alist
+  '((us-ascii . nil)
+    (iso-8859-1 . Q)
+    (iso-8859-2 . Q)
+    (iso-8859-3 . Q)
+    (iso-8859-4 . Q)
+    (iso-8859-5 . B)
+    (koi8-r . B)
+    (iso-8859-7 . B)
+    (iso-8859-8 . B)
+    (iso-8859-9 . Q)
+    (iso-8859-14 . Q)
+    (iso-8859-15 . Q)
+    (iso-2022-jp . B)
+    (iso-2022-kr . B)
+    (gb2312 . B)
+    (gbk . B)
+    (gb18030 . B)
+    (big5 . B)
+    (cn-big5 . B)
+    (cn-gb . B)
+    (cn-gb-2312 . B)
+    (euc-kr . B)
+    (iso-2022-jp-2 . B)
+    (iso-2022-int-1 . B)
+    (viscii . Q))
+  "Alist of MIME charsets to RFC2047 encodings.
+Valid encodings are nil, `Q' and `B'.  These indicate binary (no) encoding,
+quoted-printable and base64 respectively.")
+
+(defvar rfc2047-encode-function-alist
+  '((Q . rfc2047-q-encode-string)
+    (B . rfc2047-b-encode-string)
+    (nil . identity))
+  "Alist of RFC2047 encodings to encoding functions.")
+
+(defvar rfc2047-encode-encoded-words t
+  "Whether encoded words should be encoded again.")
+
+(defvar rfc2047-allow-irregular-q-encoded-words t
+  "*Whether to decode irregular Q-encoded words.")
+
+(eval-and-compile ;; Necessary to hard code them in `rfc2047-decode-region'.
+  (defconst rfc2047-encoded-word-regexp
+    "=\\?\\([^][\000-\040()<>@,;:*\\\"/?.=]+\\)\\(?:\\*[^?]+\\)?\\?\
+\\(B\\?[+/0-9A-Za-z]*=*\
+\\|Q\\?[ ->@-~]*\
+\\)\\?="
+    "Regexp that matches encoded word."
+    ;; The patterns for the B encoding and the Q encoding, i.e. the ones
+    ;; beginning with "B" and "Q" respectively, are restricted into only
+    ;; the characters that those encodings may generally use.
+    )
+  (defconst rfc2047-encoded-word-regexp-loose
+    "=\\?\\([^][\000-\040()<>@,;:*\\\"/?.=]+\\)\\(?:\\*[^?]+\\)?\\?\
+\\(B\\?[+/0-9A-Za-z]*=*\
+\\|Q\\?\\(?:\\?+[ -<>@-~]\\)?\\(?:[ ->@-~]+\\?+[ -<>@-~]\\)*[ ->@-~]*\\?*\
+\\)\\?="
+    "Regexp that matches encoded word allowing loose Q encoding."
+    ;; The pattern for the Q encoding, i.e. the one beginning with "Q",
+    ;; is similar to:
+    ;; "Q\\?\\(\\?+[^\n=?]\\)?\\([^\n?]+\\?+[^\n=?]\\)*[^\n?]*\\?*"
+    ;;      <--------1-------><----------2,3----------><--4--><-5->
+    ;; They mean:
+    ;; 1. After "Q?", allow "?"s that follow a character other than "=".
+    ;; 2. Allow "=" after "Q?"; it isn't regarded as the terminator.
+    ;; 3. In the middle of an encoded word, allow "?"s that follow a
+    ;;    character other than "=".
+    ;; 4. Allow any characters other than "?" in the middle of an
+    ;;    encoded word.
+    ;; 5. At the end, allow "?"s.
+    ))
+
+;;;
+;;; Functions for encoding RFC2047 messages
+;;;
+
+(defun rfc2047-qp-or-base64 ()
+  "Return the type with which to encode the buffer.
+This is either `base64' or `quoted-printable'."
+  (save-excursion
+    (let ((limit (min (point-max) (+ 2000 (point-min))))
+         (n8bit 0))
+      (goto-char (point-min))
+      (skip-chars-forward "\x20-\x7f\r\n\t" limit)
+      (while (< (point) limit)
+       (incf n8bit)
+       (forward-char 1)
+       (skip-chars-forward "\x20-\x7f\r\n\t" limit))
+      (if (or (< (* 6 n8bit) (- limit (point-min)))
+             ;; Don't base64, say, a short line with a single
+             ;; non-ASCII char when splitting parts by charset.
+             (= n8bit 1))
+         'quoted-printable
+       'base64))))
+
+(defun rfc2047-narrow-to-field ()
+  "Narrow the buffer to the header on the current line."
+  (beginning-of-line)
+  (narrow-to-region
+   (point)
+   (progn
+     (forward-line 1)
+     (if (re-search-forward "^[^ \n\t]" nil t)
+        (point-at-bol)
+       (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-no-properties (point) (point-max)))))
+
+(defun rfc2047-quote-special-characters-in-quoted-strings (&optional
+                                                          encodable-regexp)
+  "Quote special characters with `\\'s in quoted strings.
+Quoting will not be done in a quoted string if it contains characters
+matching ENCODABLE-REGEXP or it is within parentheses."
+  (goto-char (point-min))
+  (let ((tspecials (concat "[" ietf-drums-tspecials "]"))
+       (start (point))
+       beg end)
+    (with-syntax-table (standard-syntax-table)
+      (while (not (eobp))
+       (if (ignore-errors
+             (forward-list 1)
+             (eq (char-before) ?\)))
+           (forward-list -1)
+         (goto-char (point-max)))
+       (save-restriction
+         (narrow-to-region start (point))
+         (goto-char start)
+         (while (search-forward "\"" nil t)
+           (setq beg (match-beginning 0))
+           (unless (eq (char-before beg) ?\\)
+             (goto-char beg)
+             (setq beg (1+ beg))
+             (condition-case nil
+                 (progn
+                   (forward-sexp)
+                   (setq end (1- (point)))
+                   (goto-char beg)
+                   (if (and encodable-regexp
+                            (re-search-forward encodable-regexp end t))
+                       (goto-char (1+ end))
+                     (save-restriction
+                       (narrow-to-region beg end)
+                       (while (re-search-forward tspecials nil 'move)
+                         (if (eq (char-before) ?\\)
+                             (if (looking-at tspecials) ;; Already quoted.
+                                 (forward-char)
+                               (insert "\\"))
+                           (goto-char (match-beginning 0))
+                           (insert "\\")
+                           (forward-char))))
+                     (forward-char)))
+               (error
+                (goto-char beg)))))
+         (goto-char (point-max)))
+       (forward-list 1)
+       (setq start (point))))))
+
+(defvar rfc2047-encoding-type 'address-mime
+  "The type of encoding done by `rfc2047-encode-region'.
+This should be dynamically bound around calls to
+`rfc2047-encode-region' to either `mime' or `address-mime'.  See
+`rfc2047-header-encoding-alist', for definitions.")
+
+(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."
+  (interactive "*")
+  (save-excursion
+    (goto-char (point-min))
+    (let (alist elem method charsets)
+      (while (not (eobp))
+       (save-restriction
+         (rfc2047-narrow-to-field)
+         (setq method nil
+               alist rfc2047-header-encoding-alist
+               charsets (mm-find-mime-charset-region (point-min) (point-max)))
+         ;; M$ Outlook boycotts decoding of a header if it consists
+         ;; of two or more encoded words and those charsets differ;
+         ;; it seems to decode all words in a header from a charset
+         ;; found first in the header.  So, we unify the charsets into
+         ;; a single one used for encoding the whole text in a header.
+         (let ((mm-coding-system-priorities
+                (if (= (length charsets) 1)
+                    (cons (mm-charset-to-coding-system (car charsets))
+                          mm-coding-system-priorities)
+                  mm-coding-system-priorities)))
+           (while (setq elem (pop alist))
+             (when (or (and (stringp (car elem))
+                            (looking-at (car elem)))
+                       (eq (car elem) t))
+               (setq alist nil
+                     method (cdr elem))))
+           (if (not (rfc2047-encodable-p))
+               (prog2
+                   (when (eq method 'address-mime)
+                     (rfc2047-quote-special-characters-in-quoted-strings))
+                   (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.
+                       (mm-encode-coding-region
+                        (point-min) (point-max)
+                        (mm-charset-to-coding-system
+                         (car message-posting-charset))))
+                 ;; No encoding necessary, but folding is nice
+                 (when nil
+                   (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.
+             (re-search-forward "^[^:]+: *" nil t)
+             (cond
+              ((eq method 'address-mime)
+               (rfc2047-encode-region (point) (point-max)))
+              ((eq method 'mime)
+               (let ((rfc2047-encoding-type 'mime))
+                 (rfc2047-encode-region (point) (point-max))))
+              ((eq method 'default)
+               (if (and (featurep 'mule)
+                        (if (boundp 'enable-multibyte-characters)
+                            (default-value 'enable-multibyte-characters))
+                        mail-parse-charset)
+                   (mm-encode-coding-region (point) (point-max)
+                                            mail-parse-charset)))
+              ;; We get this when CC'ing messages to newsgroups with
+              ;; 8-bit names.  The group name mail copy just got
+              ;; unconditionally encoded.  Previously, it would ask
+              ;; whether to encode, which was quite confusing for the
+              ;; user.  If the new behavior is wrong, tell me.  I have
+              ;; left the old code commented out below.
+              ;; -- Per Abrahamsen <abraham@dina.kvl.dk> Date: 2001-10-07.
+              ;; Modified by Dave Love, with the commented-out code changed
+              ;; in accordance with changes elsewhere.
+              ((null method)
+               (rfc2047-encode-region (point) (point-max)))
+;;;           ((null method)
+;;;            (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 (or (and (featurep 'mule)
+                            (if (boundp 'enable-multibyte-characters)
+                                (default-value 'enable-multibyte-characters)))
+                       (featurep 'file-coding))
+                   (mm-encode-coding-region (point) (point-max) method)))
+              ;; Hm.
+              (t)))
+           (goto-char (point-max))))))))
+
+;; Fixme: This, and the require below may not be the Right Thing, but
+;; should be safe just before release.  -- fx 2001-02-08
+
+(defun rfc2047-encodable-p ()
+  "Return non-nil if any characters in current buffer need encoding in headers.
+The buffer may be narrowed."
+  (require 'message)                   ; for message-posting-charset
+  (let ((charsets
+        (mm-find-mime-charset-region (point-min) (point-max))))
+    (goto-char (point-min))
+    (or (and rfc2047-encode-encoded-words
+            (prog1
+                (re-search-forward rfc2047-encoded-word-regexp nil t)
+              (goto-char (point-min))))
+       (and charsets
+            (not (equal charsets (list (car message-posting-charset))))))))
+
+;; Use this syntax table when parsing into regions that may need
+;; encoding.  Double quotes are string delimiters, backslash is
+;; character quoting, and all other RFC 2822 special characters are
+;; treated as punctuation so we can use forward-sexp/forward-word to
+;; skip to the end of regions appropriately.  Nb. ietf-drums does
+;; things differently.
+(defconst rfc2047-syntax-table
+  ;; (make-char-table 'syntax-table '(2)) only works in Emacs.
+  (let ((table (make-syntax-table)))
+    ;; The following is done to work for setting all elements of the table;
+    ;; it appears to be the cleanest way.
+    ;; Play safe and don't assume the form of the word syntax entry --
+    ;; copy it from ?a.
+    (if (featurep 'xemacs)
+       (put-char-table t (get-char-table ?a (standard-syntax-table)) table)
+      (set-char-table-range table t (aref (standard-syntax-table) ?a)))
+    (modify-syntax-entry ?\\ "\\" table)
+    (modify-syntax-entry ?\" "\"" table)
+    (modify-syntax-entry ?\( "(" table)
+    (modify-syntax-entry ?\) ")" table)
+    (modify-syntax-entry ?\< "." table)
+    (modify-syntax-entry ?\> "." table)
+    (modify-syntax-entry ?\[ "." table)
+    (modify-syntax-entry ?\] "." table)
+    (modify-syntax-entry ?: "." table)
+    (modify-syntax-entry ?\; "." table)
+    (modify-syntax-entry ?, "." table)
+    (modify-syntax-entry ?@ "." table)
+    table))
+
+(defun rfc2047-encode-region (b e &optional dont-fold)
+  "Encode words in region B to E that need encoding.
+By default, the region is treated as containing RFC2822 addresses.
+Dynamically bind `rfc2047-encoding-type' to change that."
+  (save-restriction
+    (narrow-to-region b e)
+    (let ((encodable-regexp (if rfc2047-encode-encoded-words
+                               "[^\000-\177]+\\|=\\?"
+                             "[^\000-\177]+"))
+         start                         ; start of current token
+         end begin csyntax
+         ;; Whether there's an encoded word before the current token,
+         ;; either immediately or separated by space.
+         last-encoded
+         (orig-text (buffer-substring-no-properties b e)))
+      (if (eq 'mime rfc2047-encoding-type)
+         ;; Simple case.  Continuous words in which all those contain
+         ;; non-ASCII characters are encoded collectively.  Encoding
+         ;; ASCII words, including `Re:' used in Subject headers, is
+         ;; avoided for interoperability with non-MIME clients and
+         ;; for making it easy to find keywords.
+         (progn
+           (goto-char (point-min))
+           (while (progn (skip-chars-forward " \t\n")
+                         (not (eobp)))
+             (setq start (point))
+             (while (and (looking-at "[ \t\n]*\\([^ \t\n]+\\)")
+                         (progn
+                           (setq end (match-end 0))
+                           (re-search-forward encodable-regexp end t)))
+               (goto-char end))
+             (if (> (point) start)
+                 (rfc2047-encode start (point))
+               (goto-char end))))
+       ;; `address-mime' case -- take care of quoted words, comments.
+       (rfc2047-quote-special-characters-in-quoted-strings encodable-regexp)
+       (with-syntax-table rfc2047-syntax-table
+         (goto-char (point-min))
+         (condition-case err           ; in case of unbalanced quotes
+             ;; Look for rfc2822-style: sequences of atoms, quoted
+             ;; strings, specials, whitespace.  (Specials mustn't be
+             ;; encoded.)
+             (while (not (eobp))
+               ;; Skip whitespace.
+               (skip-chars-forward " \t\n")
+               (setq start (point))
+               (cond
+                ((not (char-after)))   ; eob
+                ;; else token start
+                ((eq ?\" (setq csyntax (char-syntax (char-after))))
+                 ;; Quoted word.
+                 (forward-sexp)
+                 (setq end (point))
+                 ;; Does it need encoding?
+                 (goto-char start)
+                 (if (re-search-forward encodable-regexp end 'move)
+                     ;; It needs encoding.  Strip the quotes first,
+                     ;; since encoded words can't occur in quotes.
+                     (progn
+                       (goto-char end)
+                       (delete-char -1)
+                       (goto-char start)
+                       (delete-char 1)
+                       (when last-encoded
+                         ;; There was a preceding quoted word.  We need
+                         ;; to include any separating whitespace in this
+                         ;; word to avoid it getting lost.
+                         (skip-chars-backward " \t")
+                         ;; A space is needed between the encoded words.
+                         (insert ? )
+                         (setq start (point)
+                               end (1+ end)))
+                       ;; Adjust the end position for the deleted quotes.
+                       (rfc2047-encode start (- end 2))
+                       (setq last-encoded t)) ; record that it was encoded
+                   (setq last-encoded  nil)))
+                ((eq ?. csyntax)
+                 ;; Skip other delimiters, but record that they've
+                 ;; potentially separated quoted words.
+                 (forward-char)
+                 (setq last-encoded nil))
+                ((eq ?\) csyntax)
+                 (error "Unbalanced parentheses"))
+                ((eq ?\( csyntax)
+                 ;; Look for the end of parentheses.
+                 (forward-list)
+                 ;; Encode text as an unstructured field.
+                 (let ((rfc2047-encoding-type 'mime))
+                   (rfc2047-encode-region (1+ start) (1- (point))))
+                 (skip-chars-forward ")"))
+                (t                 ; normal token/whitespace sequence
+                 ;; Find the end.
+                 ;; Skip one ASCII word, or encode continuous words
+                 ;; in which all those contain non-ASCII characters.
+                 (setq end nil)
+                 (while (not (or end (eobp)))
+                   (when (looking-at "[\000-\177]+")
+                     (setq begin (point)
+                           end (match-end 0))
+                     (when (progn
+                             (while (and (or (re-search-forward
+                                              "[ \t\n]\\|\\Sw" end 'move)
+                                             (setq end nil))
+                                         (eq ?\\ (char-syntax (char-before))))
+                               ;; Skip backslash-quoted characters.
+                               (forward-char))
+                             end)
+                       (setq end (match-beginning 0))
+                       (if rfc2047-encode-encoded-words
+                           (progn
+                             (goto-char begin)
+                             (when (search-forward "=?" end 'move)
+                               (goto-char (match-beginning 0))
+                               (setq end nil)))
+                         (goto-char end))))
+                   ;; Where the value nil of `end' means there may be
+                   ;; text to have to be encoded following the point.
+                   ;; Otherwise, the point reached to the end of ASCII
+                   ;; words separated by whitespace or a special char.
+                   (unless end
+                     (when (looking-at encodable-regexp)
+                       (goto-char (setq begin (match-end 0)))
+                       (while (and (looking-at "[ \t\n]+\\([^ \t\n]+\\)")
+                                   (setq end (match-end 0))
+                                   (progn
+                                     (while (re-search-forward
+                                             encodable-regexp end t))
+                                     (< begin (point)))
+                                   (goto-char begin)
+                                   (or (not (re-search-forward "\\Sw" end t))
+                                       (progn
+                                         (goto-char (match-beginning 0))
+                                         nil)))
+                         (goto-char end))
+                       (when (looking-at "[^ \t\n]+")
+                         (setq end (match-end 0))
+                         (if (re-search-forward "\\Sw+" end t)
+                             ;; There are special characters better
+                             ;; to be encoded so that MTAs may parse
+                             ;; them safely.
+                             (cond ((= end (point)))
+                                   ((looking-at (concat "\\sw*\\("
+                                                        encodable-regexp
+                                                        "\\)"))
+                                    (setq end nil))
+                                   (t
+                                    (goto-char (1- (match-end 0)))
+                                    (unless (= (point) (match-beginning 0))
+                                      ;; Separate encodable text and
+                                      ;; delimiter.
+                                      (insert " "))))
+                           (goto-char end)
+                           (skip-chars-forward " \t\n")
+                           (if (and (looking-at "[^ \t\n]+")
+                                    (string-match encodable-regexp
+                                                  (match-string 0)))
+                               (setq end nil)
+                             (goto-char end)))))))
+                 (skip-chars-backward " \t\n")
+                 (setq end (point))
+                 (goto-char start)
+                 (if (re-search-forward encodable-regexp end 'move)
+                     (progn
+                       (unless (memq (char-before start) '(nil ?\t ? ))
+                         (if (progn
+                               (goto-char start)
+                               (skip-chars-backward "^ \t\n")
+                               (and (looking-at "\\Sw+")
+                                    (= (match-end 0) start)))
+                             ;; Also encode bogus delimiters.
+                             (setq start (point))
+                           ;; Separate encodable text and delimiter.
+                           (goto-char start)
+                           (insert " ")
+                           (setq start (1+ start)
+                                 end (1+ end))))
+                       (rfc2047-encode start end)
+                       (setq last-encoded t))
+                   (setq last-encoded nil)))))
+           (error
+            (if (or debug-on-quit debug-on-error)
+                (signal (car err) (cdr err))
+              (error "Invalid data for rfc2047 encoding: %s"
+                     (mm-replace-in-string orig-text "[ \t\n]+" " "))))))))
+    (unless dont-fold
+      (rfc2047-fold-region b (point)))
+    (goto-char (point-max))))
+
+(defun rfc2047-encode-string (string &optional dont-fold)
+  "Encode words in STRING.
+By default, the string is treated as containing addresses (see
+`rfc2047-encoding-type')."
+  (mm-with-multibyte-buffer
+    (insert string)
+    (rfc2047-encode-region (point-min) (point-max) dont-fold)
+    (buffer-string)))
+
+;; From RFC 2047:
+;; 2. Syntax of encoded-words
+;;    [...]
+;;    While there is no limit to the length of a multiple-line header
+;;    field, each line of a header field that contains one or more
+;;    'encoded-word's is limited to 76 characters.
+;;
+;; In `rfc2047-encode-parameter' it is bound to nil, so don't defconst it.
+(defvar rfc2047-encode-max-chars 76
+  "Maximum characters of each header line that contain encoded-words.
+According to RFC 2047, it is 76.  If it is nil, encoded-words
+will not be folded.  Too small value may cause an error.  You
+should not change this value.")
+
+(defun rfc2047-encode-1 (column string cs encoder start crest tail
+                               &optional eword)
+  "Subroutine used by `rfc2047-encode'."
+  (cond ((string-equal string "")
+        (or eword ""))
+       ((not rfc2047-encode-max-chars)
+        (concat start
+                (funcall encoder (if cs
+                                     (mm-encode-coding-string string cs)
+                                   string))
+                "?="))
+       ((>= column rfc2047-encode-max-chars)
+        (when eword
+          (cond ((string-match "\n[ \t]+\\'" eword)
+                 ;; Remove a superfluous empty line.
+                 (setq eword (substring eword 0 (match-beginning 0))))
+                ((string-match "(+\\'" eword)
+                 ;; Break the line before the open parenthesis.
+                 (setq crest (concat crest (match-string 0 eword))
+                       eword (substring eword 0 (match-beginning 0))))))
+        (rfc2047-encode-1 (length crest) string cs encoder start " " tail
+                          (concat eword "\n" crest)))
+       (t
+        (let ((index 0)
+              (limit (1- (length string)))
+              (prev "")
+              next len)
+          (while (and prev
+                      (<= index limit))
+            (setq next (concat start
+                               (funcall encoder
+                                        (if cs
+                                            (mm-encode-coding-string
+                                             (substring string 0 (1+ index))
+                                             cs)
+                                          (substring string 0 (1+ index))))
+                               "?=")
+                  len (+ column (length next)))
+            (if (> len rfc2047-encode-max-chars)
+                (setq next prev
+                      prev nil)
+              (if (or (< index limit)
+                      (<= (+ len (or (string-match "\n" tail)
+                                     (length tail)))
+                          rfc2047-encode-max-chars))
+                  (setq prev next
+                        index (1+ index))
+                (if (string-match "\\`)+" tail)
+                    ;; Break the line after the close parenthesis.
+                    (setq tail (concat (substring tail 0 (match-end 0))
+                                       "\n "
+                                       (substring tail (match-end 0)))
+                          prev next
+                          index (1+ index))
+                  (setq next prev
+                        prev nil)))))
+          (if (> index limit)
+              (concat eword next tail)
+            (if (= 0 index)
+                (if (and eword
+                         (string-match "(+\\'" eword))
+                    (setq crest (concat crest (match-string 0 eword))
+                          eword (substring eword 0 (match-beginning 0)))
+                  (setq eword (concat eword next)))
+              (setq crest " "
+                    eword (concat eword next)))
+            (when (string-match "\n[ \t]+\\'" eword)
+              ;; Remove a superfluous empty line.
+              (setq eword (substring eword 0 (match-beginning 0))))
+            (rfc2047-encode-1 (length crest) (substring string index)
+                              cs encoder start " " tail
+                              (concat eword "\n" crest)))))))
+
+(defun rfc2047-encode (b e)
+  "Encode the word(s) in the region B to E.
+Point moves to the end of the region."
+  (let ((mime-charset (or (mm-find-mime-charset-region b e) (list 'us-ascii)))
+       cs encoding tail crest eword)
+    ;; Use utf-8 as a last resort if determining charset of text fails.
+    (if (memq nil mime-charset)
+       (setq mime-charset (list 'utf-8)))
+    (cond ((> (length mime-charset) 1)
+          (error "Can't rfc2047-encode `%s'"
+                 (buffer-substring-no-properties b e)))
+         ((= (length mime-charset) 1)
+          (setq mime-charset (car mime-charset)
+                cs (mm-charset-to-coding-system mime-charset))
+          (unless (and (mm-multibyte-p)
+                       (mm-coding-system-p cs))
+            (setq cs nil))
+          (save-restriction
+            (narrow-to-region b e)
+            (setq encoding
+                  (or (cdr (assq mime-charset
+                                 rfc2047-charset-encoding-alist))
+                      ;; For the charsets that don't have a preferred
+                      ;; encoding, choose the one that's shorter.
+                      (if (eq (rfc2047-qp-or-base64) 'base64)
+                          'B
+                        'Q)))
+            (widen)
+            (goto-char e)
+            (skip-chars-forward "^ \t\n")
+            ;; `tail' may contain a close parenthesis.
+            (setq tail (buffer-substring-no-properties e (point)))
+            (goto-char b)
+            (setq b (point-marker)
+                  e (set-marker (make-marker) e))
+            (rfc2047-fold-region (point-at-bol) b)
+            (goto-char b)
+            (skip-chars-backward "^ \t\n")
+            (unless (= 0 (skip-chars-backward " \t"))
+              ;; `crest' may contain whitespace and an open parenthesis.
+              (setq crest (buffer-substring-no-properties (point) b)))
+            (setq eword (rfc2047-encode-1
+                         (- b (point-at-bol))
+                         (mm-replace-in-string
+                          (buffer-substring-no-properties b e)
+                          "\n\\([ \t]?\\)" "\\1")
+                         cs
+                         (or (cdr (assq encoding
+                                        rfc2047-encode-function-alist))
+                             'identity)
+                         (concat "=?" (downcase (symbol-name mime-charset))
+                                 "?" (upcase (symbol-name encoding)) "?")
+                         (or crest " ")
+                         tail))
+            (delete-region (if (eq (aref eword 0) ?\n)
+                               (if (bolp)
+                                   ;; The line was folded before encoding.
+                                   (1- (point))
+                                 (point))
+                             (goto-char b))
+                           (+ e (length tail)))
+            ;; `eword' contains `crest' and `tail'.
+            (insert eword)
+            (set-marker b nil)
+            (set-marker e nil)
+            (unless (or (/= 0 (length tail))
+                        (eobp)
+                        (looking-at "[ \t\n)]"))
+              (insert " "))))
+         (t
+          (goto-char e)))))
+
+(defun rfc2047-fold-field ()
+  "Fold the current header field."
+  (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
+    (narrow-to-region b e)
+    (goto-char (point-min))
+    (let ((break nil)
+         (qword-break nil)
+         (first t)
+         (bol (save-restriction
+                (widen)
+                (point-at-bol))))
+      (while (not (eobp))
+       (when (and (or break qword-break)
+                  (> (- (point) bol) 76))
+         (goto-char (or break qword-break))
+         (setq break nil
+               qword-break nil)
+         (skip-chars-backward " \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)))
+       (cond
+        ((eq (char-after) ?\n)
+         (forward-char 1)
+         (setq bol (point)
+               break nil
+               qword-break nil)
+         (skip-chars-forward " \t")
+         (unless (or (eobp) (eq (char-after) ?\n))
+           (forward-char 1)))
+        ((eq (char-after) ?\r)
+         (forward-char 1))
+        ((memq (char-after) '(?  ?\t))
+         (skip-chars-forward " \t")
+         (unless first ;; Don't break just after the header name.
+           (setq break (point))))
+        ((not break)
+         (if (not (looking-at "=\\?[^=]"))
+             (if (eq (char-after) ?=)
+                 (forward-char 1)
+               (skip-chars-forward "^ \t\n\r="))
+           ;; Don't break at the start of the field.
+           (unless (= (point) b)
+             (setq qword-break (point)))
+           (skip-chars-forward "^ \t\n\r")))
+        (t
+         (skip-chars-forward "^ \t\n\r")))
+       (setq first nil))
+      (when (and (or break qword-break)
+                (> (- (point) bol) 76))
+       (goto-char (or break qword-break))
+       (setq break nil
+             qword-break nil)
+       (if (or (> 0 (skip-chars-backward " \t"))
+               (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))))))
+
+(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."
+  (save-restriction
+    (narrow-to-region b e)
+    (goto-char (point-min))
+    (let ((bol (save-restriction
+                (widen)
+                (point-at-bol)))
+         (eol (point-at-eol)))
+      (forward-line 1)
+      (while (not (eobp))
+       (if (and (looking-at "[ \t]")
+                (< (- (point-at-eol) bol) 76))
+           (delete-region eol (progn
+                                (goto-char eol)
+                                (skip-chars-forward "\r\n")
+                                (point)))
+         (setq bol (point-at-bol)))
+       (setq eol (point-at-eol))
+       (forward-line 1)))))
+
+(defun rfc2047-b-encode-string (string)
+  "Base64-encode the header contained in STRING."
+  (base64-encode-string string t))
+
+(autoload 'quoted-printable-encode-region "qp")
+
+(defun rfc2047-q-encode-string (string)
+  "Quoted-printable-encode the header in STRING."
+  (mm-with-unibyte-buffer
+    (insert string)
+    (quoted-printable-encode-region
+     (point-min) (point-max) nil
+     ;; = (\075), _ (\137), ? (\077) are used in the encoded word.
+     ;; Avoid using 8bit characters.
+     ;; This list excludes `especials' (see the RFC2047 syntax),
+     ;; meaning that some characters in non-structured fields will
+     ;; get encoded when they con't need to be.  The following is
+     ;; what it used to be.
+     ;;;  ;; Equivalent to "^\000-\007\011\013\015-\037\200-\377=_?"
+     ;;;  "\010\012\014\040-\074\076\100-\136\140-\177")
+     "-\b\n\f !#-'*+0-9A-Z\\^`-~\d")
+    (subst-char-in-region (point-min) (point-max) ?  ?_)
+    (buffer-string)))
+
+(defun rfc2047-encode-parameter (param value)
+  "Return and PARAM=VALUE string encoded in the RFC2047-like style.
+This is a substitution for the `rfc2231-encode-string' function, that
+is the standard but many mailers don't support it."
+  (let ((rfc2047-encoding-type 'mime)
+       (rfc2047-encode-max-chars nil))
+    (rfc2045-encode-string param (rfc2047-encode-string value t))))
+
+;;;
+;;; Functions for decoding RFC2047 messages
+;;;
+
+(defvar rfc2047-quote-decoded-words-containing-tspecials nil
+  "If non-nil, quote decoded words containing special characters.")
+
+(defvar rfc2047-allow-incomplete-encoded-text t
+  "*Non-nil means allow incomplete encoded-text in successive encoded-words.
+Dividing of encoded-text in the place other than character boundaries
+violates RFC2047 section 5, while we have a capability to decode it.
+If it is non-nil, the decoder will decode B- or Q-encoding in each
+encoded-word, concatenate them, and decode it by charset.  Otherwise,
+the decoder will fully decode each encoded-word before concatenating
+them.")
+
+(defun rfc2047-strip-backslashes-in-quoted-strings ()
+  "Strip backslashes in quoted strings.  `\\\"' remains."
+  (goto-char (point-min))
+  (let (beg)
+    (with-syntax-table (standard-syntax-table)
+      (while (search-forward "\"" nil t)
+       (unless (eq (char-before) ?\\)
+         (setq beg (match-end 0))
+         (goto-char (match-beginning 0))
+         (condition-case nil
+             (progn
+               (forward-sexp)
+               (save-restriction
+                 (narrow-to-region beg (1- (point)))
+                 (goto-char beg)
+                 (while (search-forward "\\" nil 'move)
+                   (unless (memq (char-after) '(?\"))
+                     (delete-char -1))
+                   (forward-char)))
+               (forward-char))
+           (error
+            (goto-char beg))))))))
+
+(defun rfc2047-charset-to-coding-system (charset &optional allow-override)
+  "Return coding-system corresponding to MIME CHARSET.
+If your Emacs implementation can't decode CHARSET, return nil.
+
+If allow-override is given, use `mm-charset-override-alist' to
+map undesired charset names to their replacement.  This should
+only be used for decoding, not for encoding."
+  (when (stringp charset)
+    (setq charset (intern (downcase 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))
+    (setq charset mail-parse-charset))
+  (let ((cs (mm-charset-to-coding-system charset nil allow-override)))
+    (cond ((eq cs 'ascii)
+          (setq cs (or (mm-charset-to-coding-system mail-parse-charset)
+                       'raw-text)))
+         ((mm-coding-system-p cs))
+         ((and charset
+               (listp mail-parse-ignored-charsets)
+               (memq 'gnus-unknown mail-parse-ignored-charsets))
+          (setq cs (mm-charset-to-coding-system mail-parse-charset))))
+    (if (eq cs 'ascii)
+       'raw-text
+      cs)))
+
+(autoload 'quoted-printable-decode-string "qp")
+
+(defun rfc2047-decode-encoded-words (words)
+  "Decode successive encoded-words in WORDS and return a decoded string.
+Each element of WORDS looks like (CHARSET ENCODING ENCODED-TEXT
+ENCODED-WORD)."
+  (let (word charset cs encoding text rest)
+    (while words
+      (setq word (pop words))
+      (if (and (setq cs (rfc2047-charset-to-coding-system
+                        (setq charset (car word)) t))
+              (condition-case code
+                  (cond ((char-equal ?B (nth 1 word))
+                         (setq text (base64-decode-string
+                                     (rfc2047-pad-base64 (nth 2 word)))))
+                        ((char-equal ?Q (nth 1 word))
+                         (setq text (quoted-printable-decode-string
+                                     (mm-subst-char-in-string
+                                      ?_ ?  (nth 2 word) t)))))
+                (error
+                 (message "%s" (error-message-string code))
+                 nil)))
+         (if (and rfc2047-allow-incomplete-encoded-text
+                  (eq cs (caar rest)))
+             ;; Concatenate text of which the charset is the same.
+             (setcdr (car rest) (concat (cdar rest) text))
+           (push (cons cs text) rest))
+       ;; Don't decode encoded-word.
+       (push (cons nil (nth 3 word)) rest)))
+    (while rest
+      (setq words (concat
+                  (or (and (setq cs (caar rest))
+                           (condition-case code
+                               (mm-decode-coding-string (cdar rest) cs)
+                             (error
+                              (message "%s" (error-message-string code))
+                              nil)))
+                      (concat (when (cdr rest) " ")
+                              (cdar rest)
+                              (when (and words
+                                         (not (eq (string-to-char words) ? )))
+                                " ")))
+                  words)
+           rest (cdr rest)))
+    words))
+
+;; Fixme: This should decode in place, not cons intermediate strings.
+;; Also check whether it needs to worry about delimiting fields like
+;; encoding.
+
+;; In fact it's reported that (invalid) encoding of mailboxes in
+;; addr-specs is in use, so delimiting fields might help.  Probably
+;; not decoding a word which isn't properly delimited is good enough
+;; and worthwhile (is it more correct or not?), e.g. something like
+;; `=?iso-8859-1?q?foo?=@'.
+
+(defun rfc2047-decode-region (start end &optional address-mime)
+  "Decode MIME-encoded words in region between START and END.
+If ADDRESS-MIME is non-nil, strip backslashes which precede characters
+other than `\"' and `\\' in quoted strings."
+  (interactive "r")
+  (let ((case-fold-search t)
+       (eword-regexp
+        (if rfc2047-allow-irregular-q-encoded-words
+            (eval-when-compile
+              (concat "[\n\t ]*\\(" rfc2047-encoded-word-regexp-loose "\\)"))
+          (eval-when-compile
+            (concat "[\n\t ]*\\(" rfc2047-encoded-word-regexp "\\)"))))
+       b e match words)
+    (save-excursion
+      (save-restriction
+       (narrow-to-region start end)
+       (when address-mime
+         (rfc2047-strip-backslashes-in-quoted-strings))
+       (goto-char (setq b start))
+       ;; Look for the encoded-words.
+       (while (setq match (re-search-forward eword-regexp nil t))
+         (setq e (match-beginning 1)
+               end (match-end 0)
+               words nil)
+         (while match
+           (push (list (match-string 2) ;; charset
+                       (char-after (match-beginning 3)) ;; encoding
+                       (substring (match-string 3) 2) ;; encoded-text
+                       (match-string 1)) ;; encoded-word
+                 words)
+           ;; Look for the subsequent encoded-words.
+           (when (setq match (looking-at eword-regexp))
+             (goto-char (setq end (match-end 0)))))
+         ;; Replace the encoded-words with the decoded one.
+         (delete-region e end)
+         (insert (rfc2047-decode-encoded-words (nreverse words)))
+         (save-restriction
+           (narrow-to-region e (point))
+           (goto-char e)
+           ;; Remove newlines between decoded words, though such
+           ;; things essentially must not be there.
+           (while (re-search-forward "[\n\r]+" nil t)
+             (replace-match " "))
+           (setq end (point-max))
+           ;; Quote decoded words if there are special characters
+           ;; which might violate RFC2822.
+           (when (and rfc2047-quote-decoded-words-containing-tspecials
+                      (let ((regexp (car (rassq
+                                          'address-mime
+                                          rfc2047-header-encoding-alist))))
+                        (when regexp
+                          (save-restriction
+                            (widen)
+                            (and
+                             ;; Don't quote words if already quoted.
+                             (not (and (eq (char-before e) ?\")
+                                       (eq (char-after end) ?\")))
+                             (progn
+                               (beginning-of-line)
+                               (while (and (memq (char-after) '(?  ?\t))
+                                           (zerop (forward-line -1))))
+                               (looking-at regexp)))))))
+             (let (quoted)
+               (goto-char e)
+               (skip-chars-forward " \t")
+               (setq start (point))
+               (setq quoted (eq (char-after) ?\"))
+               (goto-char (point-max))
+               (skip-chars-backward " \t" start)
+               (if (setq quoted (and quoted
+                                     (> (point) (1+ start))
+                                     (eq (char-before) ?\")))
+                   (progn
+                     (backward-char)
+                     (setq start (1+ start)
+                           end (point-marker)))
+                 (setq end (point-marker)))
+               (goto-char start)
+               (while (search-forward "\"" end t)
+                 (when (prog2
+                           (backward-char)
+                           (zerop (% (skip-chars-backward "\\\\") 2))
+                         (goto-char (match-beginning 0)))
+                   (insert "\\"))
+                 (forward-char))
+               (when (and (not quoted)
+                          (progn
+                            (goto-char start)
+                            (re-search-forward
+                             (concat "[" ietf-drums-tspecials "]")
+                             end t)))
+                 (goto-char start)
+                 (insert "\"")
+                 (goto-char end)
+                 (insert "\""))
+               (set-marker end nil)))
+           (goto-char (point-max)))
+         (when (and (mm-multibyte-p)
+                    mail-parse-charset
+                    (not (eq mail-parse-charset 'us-ascii))
+                    (not (eq mail-parse-charset 'gnus-decoded)))
+           (mm-decode-coding-region b e mail-parse-charset))
+         (setq b (point)))
+       (when (and (mm-multibyte-p)
+                  mail-parse-charset
+                  (not (eq mail-parse-charset 'us-ascii))
+                  (not (eq mail-parse-charset 'gnus-decoded)))
+         (mm-decode-coding-region b (point-max) mail-parse-charset))))))
+
+(defun rfc2047-decode-address-region (start end)
+  "Decode MIME-encoded words in region between START and END.
+Backslashes which precede characters other than `\"' and `\\' in quoted
+strings are stripped."
+  (rfc2047-decode-region start end t))
+
+(defun rfc2047-decode-string (string &optional address-mime)
+  "Decode MIME-encoded STRING and return the result.
+If ADDRESS-MIME is non-nil, strip backslashes which precede characters
+other than `\"' and `\\' in quoted strings."
+  ;; (let ((m (mm-multibyte-p)))
+    (if (string-match "=\\?" string)
+       (with-temp-buffer
+          ;; We used to only call mm-enable-multibyte if `m' is non-nil,
+          ;; but this can't be the right criterion.  Don't just revert this
+          ;; change if it encounters a bug.  Please help me fix it
+          ;; right instead.  --Stef
+          ;; The string returned should always be multibyte in a multibyte
+         ;; session, i.e. the buffer should be multibyte before
+         ;; `buffer-string' is called.
+          (mm-enable-multibyte)
+         (insert string)
+         (inline
+           (rfc2047-decode-region (point-min) (point-max) address-mime))
+         (buffer-string))
+      (when address-mime
+       (setq string
+             (with-temp-buffer
+               (when (mm-multibyte-string-p string)
+                 (mm-enable-multibyte))
+               (insert string)
+               (rfc2047-strip-backslashes-in-quoted-strings)
+               (buffer-string))))
+      ;; Fixme: As above, `m' here is inappropriate.
+      (if (and ;; m
+              mail-parse-charset
+              (not (eq mail-parse-charset 'us-ascii))
+              (not (eq mail-parse-charset 'gnus-decoded)))
+         ;; `decode-coding-string' in Emacs offers a third optional
+         ;; arg NOCOPY to avoid consing a new string if the decoding
+         ;; is "trivial".  Unfortunately it currently doesn't
+         ;; consider anything else than a nil coding system
+         ;; trivial.
+         ;; `rfc2047-decode-string' is called multiple times for each
+         ;; article during summary buffer generation, and we really
+         ;; want to avoid unnecessary consing.  So we bypass
+         ;; `decode-coding-string' if the string is purely ASCII.
+         (if (and (fboundp 'detect-coding-string)
+                  ;; string is purely ASCII
+                  (eq (detect-coding-string string t) 'undecided))
+              string
+            (mm-decode-coding-string string mail-parse-charset))
+        (mm-string-to-multibyte string)))) ;; )
+
+(defun rfc2047-decode-address-string (string)
+  "Decode MIME-encoded STRING and return the result.
+Backslashes which precede characters other than `\"' and `\\' in quoted
+strings are stripped."
+  (rfc2047-decode-string string t))
+
+(defun rfc2047-pad-base64 (string)
+  "Pad STRING to quartets."
+  ;; Be more liberal to accept buggy base64 strings. If
+  ;; base64-decode-string accepts buggy strings, this function could
+  ;; be aliased to identity.
+  (if (= 0 (mod (length string) 4))
+      string
+    (when (string-match "=+$" string)
+      (setq string (substring string 0 (match-beginning 0))))
+    (case (mod (length string) 4)
+      (0 string)
+      (1 string) ;; Error, don't pad it.
+      (2 (concat string "=="))
+      (3 (concat string "=")))))
+
+(provide 'rfc2047)
+
+;;; rfc2047.el ends here
diff --git a/xemacs-packages/gnus/lisp/rfc2104.el b/xemacs-packages/gnus/lisp/rfc2104.el
new file mode 100644 (file)
index 0000000..d579f8f
--- /dev/null
@@ -0,0 +1,124 @@
+;;; rfc2104.el --- RFC2104 Hashed Message Authentication Codes
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Simon Josefsson <jas@pdc.kth.se>
+;; Keywords: mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This is a high performance implementation of RFC2104.
+;;
+;; Example:
+;;
+;; (require 'md5)
+;; (rfc2104-hash 'md5 64 16 "Jefe" "what do ya want for nothing?")
+;; "750c783e6ab0b503eaa86e310a5db738"
+;;
+;; (require 'sha1)
+;; (rfc2104-hash 'sha1 64 20 "Jefe" "what do ya want for nothing?")
+;; "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"
+;;
+;; 64 is block length of hash function (64 for MD5 and SHA), 16 is
+;; resulting hash length (16 for MD5, 20 for SHA).
+;;
+;; Tested with Emacs 20.2 and XEmacs 20.3.
+;;
+;; Test case reference: RFC 2202.
+
+;;; History:
+
+;; 1998-08-16  initial release posted to gnu.emacs.sources
+;; 1998-08-17  use append instead of char-list-to-string
+;; 1998-08-26  don't require hexl
+;; 1998-09-25  renamed from hmac.el to rfc2104.el, also renamed functions
+;; 1999-10-23  included in pgnus
+;; 2000-08-15  `rfc2104-hexstring-to-bitstring'
+;; 2000-05-12  added sha-1 example, added test case reference
+;; 2003-11-13  change rfc2104-hexstring-to-bitstring to ...-byte-list
+;; 2008-04-25  rewrite rfc2104-hash for speed
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+;; Magic character for inner HMAC round. 0x36 == 54 == '6'
+(defconst rfc2104-ipad ?\x36)
+
+;; Magic character for outer HMAC round. 0x5C == 92 == '\'
+(defconst rfc2104-opad ?\x5C)
+
+(defconst rfc2104-nybbles
+  (let ((v (make-vector
+            ;; Find upper bound to save some space.
+            (1+ (max ?0 ?9 ?a ?f ?A ?F))
+            ;; Use non-numeric default to catch bogus hex strings.
+            nil))
+        (ls '((?0 . 0)  (?a . 10)   (?A . 10)
+              (?1 . 1)  (?b . 11)   (?B . 11)
+              (?2 . 2)  (?c . 12)   (?C . 12)
+              (?3 . 3)  (?d . 13)   (?D . 13)
+              (?4 . 4)  (?e . 14)   (?E . 14)
+              (?5 . 5)  (?f . 15)   (?F . 15)
+              (?6 . 6)
+              (?7 . 7)
+              (?8 . 8)
+              (?9 . 9))))
+    (while ls
+      (aset v (caar ls) (cdar ls))
+      (setq ls (cdr ls)))
+    v))
+
+(eval-when-compile
+  (defmacro rfc2104-string-make-unibyte (string)
+    "Return the unibyte equivalent of STRING.
+In XEmacs return just STRING."
+    (if (featurep 'xemacs)
+       string
+      `(string-make-unibyte ,string))))
+
+(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)
+                 (funcall hash key) key))
+         (len (length key))
+        (ipad (make-string    block-length              rfc2104-ipad))
+        (opad (make-string (+ block-length hash-length) rfc2104-opad))
+         c partial)
+    ;; Prefix *pad with key, appropriately XORed.
+    (do ((i 0 (1+ i)))
+        ((= len i))
+      (setq c (aref key i))
+      (aset ipad i (logxor rfc2104-ipad c))
+      (aset opad i (logxor rfc2104-opad c)))
+    ;; Perform inner hash.
+    (setq partial (rfc2104-string-make-unibyte
+                  (funcall hash (concat ipad text))))
+    ;; Pack latter part of opad.
+    (do ((r 0 (+ 2 r))
+         (w block-length (1+ w)))
+        ((= (* 2 hash-length) r))
+      (aset opad w
+            (+ (* 16 (aref rfc2104-nybbles (aref partial     r)))
+               (      aref rfc2104-nybbles (aref partial (1+ r))))))
+    ;; Perform outer hash.
+    (rfc2104-string-make-unibyte (funcall hash opad))))
+
+(provide 'rfc2104)
+
+;;; rfc2104.el ends here
diff --git a/xemacs-packages/gnus/lisp/rfc2231.el b/xemacs-packages/gnus/lisp/rfc2231.el
new file mode 100644 (file)
index 0000000..34c8ecd
--- /dev/null
@@ -0,0 +1,307 @@
+;;; rfc2231.el --- Functions for decoding rfc2231 headers
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(require 'ietf-drums)
+(require 'rfc2047)
+(autoload 'mm-encode-body "mm-bodies")
+(autoload 'mail-header-remove-whitespace "mail-parse")
+(autoload 'mail-header-remove-comments "mail-parse")
+
+(defun rfc2231-get-value (ct attribute)
+  "Return the value of ATTRIBUTE from CT."
+  (cdr (assq attribute (cdr ct))))
+
+(defun rfc2231-parse-qp-string (string)
+  "Parse QP-encoded string using `rfc2231-parse-string'.
+N.B.  This is in violation with RFC2047, but it seem to be in common use."
+  (rfc2231-parse-string (rfc2047-decode-string string)))
+
+(defun rfc2231-parse-string (string &optional signal-error)
+  "Parse STRING and return a list.
+The list will be on the form
+ `(name (attribute . value) (attribute . value)...)'.
+
+If the optional SIGNAL-ERROR is non-nil, signal an error when this
+function fails in parsing of parameters.  Otherwise, this function
+must never cause a Lisp error."
+  (with-temp-buffer
+    (let ((ttoken (ietf-drums-token-to-list ietf-drums-text-token))
+         (stoken (ietf-drums-token-to-list ietf-drums-tspecials))
+         (ntoken (ietf-drums-token-to-list "0-9"))
+         c type attribute encoded number parameters value)
+      (ietf-drums-init
+       (condition-case nil
+          (mail-header-remove-whitespace
+           (mail-header-remove-comments string))
+        ;; The most likely cause of an error is unbalanced parentheses
+        ;; or double-quotes.  If all parentheses and double-quotes are
+        ;; quoted meaninglessly with backslashes, removing them might
+        ;; make it parsable.  Let's try...
+        (error
+         (let (mod)
+           (when (and (string-match "\\\\\"" string)
+                      (not (string-match "\\`\"\\|[^\\]\"" string)))
+             (setq string (mm-replace-in-string string "\\\\\"" "\"")
+                   mod t))
+           (when (and (string-match "\\\\(" string)
+                      (string-match "\\\\)" string)
+                      (not (string-match "\\`(\\|[^\\][()]" string)))
+             (setq string (mm-replace-in-string string "\\\\\\([()]\\)" "\\1")
+                   mod t))
+           (or (and mod
+                    (ignore-errors
+                      (mail-header-remove-whitespace
+                       (mail-header-remove-comments string))))
+               ;; Finally, attempt to extract only type.
+               (if (string-match
+                    (concat "\\`[\t\n ]*\\([^" ietf-drums-tspecials "\t\n ]+"
+                            "\\(?:/[^" ietf-drums-tspecials
+                            "\t\n ]+\\)?\\)\\(?:[\t\n ;]\\|\\'\\)")
+                    string)
+                   (match-string 1 string)
+                 ""))))))
+      (let ((table (copy-syntax-table ietf-drums-syntax-table)))
+       (modify-syntax-entry ?\' "w" table)
+       (modify-syntax-entry ?* " " table)
+       (modify-syntax-entry ?\; " " table)
+       (modify-syntax-entry ?= " " table)
+       ;; The following isn't valid, but one should be liberal
+       ;; in what one receives.
+       (modify-syntax-entry ?\: "w" table)
+       (set-syntax-table table))
+      (setq c (char-after))
+      (when (and (memq c ttoken)
+                (not (memq c stoken))
+                (setq type (ignore-errors
+                             (downcase
+                              (buffer-substring (point) (progn
+                                                          (forward-sexp 1)
+                                                          (point)))))))
+       ;; Do the params
+       (condition-case err
+           (progn
+             (while (not (eobp))
+               (setq c (char-after))
+               (unless (eq c ?\;)
+                 (error "Invalid header: %s" string))
+               (forward-char 1)
+               ;; If c in nil, then this is an invalid header, but
+               ;; since elm generates invalid headers on this form,
+               ;; we allow it.
+               (when (setq c (char-after))
+                 (if (and (memq c ttoken)
+                          (not (memq c stoken)))
+                     (setq attribute
+                           (intern
+                            (downcase
+                             (buffer-substring
+                              (point) (progn (forward-sexp 1) (point))))))
+                   (error "Invalid header: %s" string))
+                 (setq c (char-after))
+                 (if (eq c ?*)
+                     (progn
+                       (forward-char 1)
+                       (setq c (char-after))
+                       (if (not (memq c ntoken))
+                           (setq encoded t
+                                 number nil)
+                         (setq number
+                               (string-to-number
+                                (buffer-substring
+                                 (point) (progn (forward-sexp 1) (point)))))
+                         (setq c (char-after))
+                         (when (eq c ?*)
+                           (setq encoded t)
+                           (forward-char 1)
+                           (setq c (char-after)))))
+                   (setq number nil
+                         encoded nil))
+                 (unless (eq c ?=)
+                   (error "Invalid header: %s" string))
+                 (forward-char 1)
+                 (setq c (char-after))
+                 (cond
+                  ((eq c ?\")
+                   (setq value (buffer-substring (1+ (point))
+                                                 (progn
+                                                   (forward-sexp 1)
+                                                   (1- (point)))))
+                   (when encoded
+                     (setq value (mapconcat (lambda (c) (format "%%%02x" c))
+                                            value ""))))
+                  ((and (or (memq c ttoken)
+                            ;; EXTENSION: Support non-ascii chars.
+                            (> c ?\177))
+                        (not (memq c stoken)))
+                   (setq value
+                         (buffer-substring
+                          (point)
+                          (progn
+                            ;; Jump over asterisk, non-ASCII
+                            ;; and non-boundary characters.
+                            (while (and c
+                                        (or (eq c ?*)
+                                            (> c ?\177)
+                                            (not (eq (char-syntax c) ? ))))
+                              (forward-char 1)
+                              (setq c (char-after)))
+                            (point)))))
+                  (t
+                   (error "Invalid header: %s" string)))
+                 (push (list attribute value number encoded)
+                       parameters))))
+         (error
+          (setq parameters nil)
+          (when signal-error
+            (signal (car err) (cdr err)))))
+
+       ;; Now collect and concatenate continuation parameters.
+       (let ((cparams nil)
+             elem)
+         (loop for (attribute value part encoded)
+               in (sort parameters (lambda (e1 e2)
+                                     (< (or (caddr e1) 0)
+                                        (or (caddr e2) 0))))
+               do (cond
+                   ;; First part.
+                   ((or (not (setq elem (assq attribute cparams)))
+                        (and (numberp part)
+                             (zerop part)))
+                    (push (list attribute value encoded) cparams))
+                   ;; Repetition of a part; do nothing.
+                   ((and elem
+                         (null number))
+                    )
+                   ;; Concatenate continuation parts.
+                   (t
+                    (setcar (cdr elem) (concat (cadr elem) value)))))
+         ;; Finally decode encoded values.
+         (cons type (mapcar
+                     (lambda (elem)
+                       (cons (car elem)
+                             (if (nth 2 elem)
+                                 (rfc2231-decode-encoded-string (nth 1 elem))
+                               (nth 1 elem))))
+                     (nreverse cparams))))))))
+
+(defun rfc2231-decode-encoded-string (string)
+  "Decode an RFC2231-encoded string.
+These look like:
+ \"us-ascii\\='en-us\\='This%20is%20%2A%2A%2Afun%2A%2A%2A\",
+ \"us-ascii\\='\\='This%20is%20%2A%2A%2Afun%2A%2A%2A\",
+ \"\\='en-us\\='This%20is%20%2A%2A%2Afun%2A%2A%2A\",
+ \"\\='\\='This%20is%20%2A%2A%2Afun%2A%2A%2A\", or
+ \"This is ***fun***\"."
+  (string-match "\\`\\(?:\\([^']+\\)?'\\([^']+\\)?'\\)?\\(.+\\)" string)
+  (let ((coding-system (mm-charset-to-coding-system
+                       (match-string 1 string) nil t))
+       ;;(language (match-string 2 string))
+       (value (match-string 3 string)))
+    (mm-with-unibyte-buffer
+      (insert value)
+      (goto-char (point-min))
+      (while (re-search-forward "%\\([0-9A-Fa-f][0-9A-Fa-f]\\)" nil t)
+       (insert
+        (prog1
+            (string-to-number (match-string 1) 16)
+          (delete-region (match-beginning 0) (match-end 0)))))
+      ;; Decode using the charset, if any.
+      (if (memq coding-system '(nil ascii))
+         (buffer-string)
+       (mm-decode-coding-string (buffer-string) coding-system)))))
+
+(defun rfc2231-encode-string (param value)
+  "Return and PARAM=VALUE string encoded according to RFC2231.
+Use `mml-insert-parameter' or `mml-insert-parameter-string' to insert
+the result of this function."
+  (let ((control (ietf-drums-token-to-list ietf-drums-no-ws-ctl-token))
+       (tspecial (ietf-drums-token-to-list ietf-drums-tspecials))
+       (special (ietf-drums-token-to-list "*'%\n\t"))
+       (ascii (ietf-drums-token-to-list ietf-drums-text-token))
+       (num -1)
+       ;; Don't make lines exceeding 76 column.
+       (limit (- 74 (length param)))
+       spacep encodep charsetp charset broken)
+    (mm-with-multibyte-buffer
+      (insert value)
+      (goto-char (point-min))
+      (while (not (eobp))
+       (cond
+        ((or (memq (following-char) control)
+             (memq (following-char) tspecial)
+             (memq (following-char) special))
+         (setq encodep t))
+        ((eq (following-char) ? )
+         (setq spacep t))
+        ((not (memq (following-char) ascii))
+         (setq charsetp t)))
+       (forward-char 1))
+      (when charsetp
+       (setq charset (mm-encode-body)))
+      (mm-disable-multibyte)
+      (cond
+       ((or encodep charsetp
+           (progn
+             (end-of-line)
+             (> (current-column) (if spacep (- limit 2) limit))))
+       (setq limit (- limit 6))
+       (goto-char (point-min))
+       (insert (symbol-name (or charset 'us-ascii)) "''")
+       (while (not (eobp))
+         (if (or (not (memq (following-char) ascii))
+                 (memq (following-char) control)
+                 (memq (following-char) tspecial)
+                 (memq (following-char) special)
+                 (eq (following-char) ? ))
+             (progn
+               (when (>= (current-column) (1- limit))
+                 (insert ";\n")
+                 (setq broken t))
+               (insert "%" (format "%02x" (following-char)))
+               (delete-char 1))
+           (when (> (current-column) limit)
+             (insert ";\n")
+             (setq broken t))
+           (forward-char 1)))
+       (goto-char (point-min))
+       (if (not broken)
+           (insert param "*=")
+         (while (not (eobp))
+           (insert (if (>= num 0) " " "")
+                   param "*" (format "%d" (incf num)) "*=")
+           (forward-line 1))))
+       (spacep
+       (goto-char (point-min))
+       (insert param "=\"")
+       (goto-char (point-max))
+       (insert "\""))
+       (t
+       (goto-char (point-min))
+       (insert param "=")))
+      (buffer-string))))
+
+(provide 'rfc2231)
+
+;;; rfc2231.el ends here
diff --git a/xemacs-packages/gnus/lisp/rtree.el b/xemacs-packages/gnus/lisp/rtree.el
new file mode 100644 (file)
index 0000000..662e043
--- /dev/null
@@ -0,0 +1,281 @@
+;;; rtree.el --- functions for manipulating range trees
+
+;; Copyright (C) 2010-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; A "range tree" is a binary tree that stores ranges.  They are
+;; similar to interval trees, but do not allow overlapping intervals.
+
+;; A range is an ordered list of number intervals, like this:
+
+;; ((10 . 25) 56 78 (98 . 201))
+
+;; Common operations, like lookup, deletion and insertion are O(n) in
+;; a range, but an rtree is O(log n) in all these operations.
+;; Transformation between a range and an rtree is O(n).
+
+;; The rtrees are quite simple.  The structure of each node is
+
+;; (cons (cons low high) (cons left right))
+
+;; That is, they are three cons cells, where the car of the top cell
+;; is the actual range, and the cdr has the left and right child.  The
+;; rtrees aren't automatically balanced, but are balanced when
+;; created, and can be rebalanced when deemed necessary.
+
+;;; Code:
+
+(eval-when-compile
+  (require 'cl))
+
+(defmacro rtree-make-node ()
+  `(list (list nil) nil))
+
+(defmacro rtree-set-left (node left)
+  `(setcar (cdr ,node) ,left))
+
+(defmacro rtree-set-right (node right)
+  `(setcdr (cdr ,node) ,right))
+
+(defmacro rtree-set-range (node range)
+  `(setcar ,node ,range))
+
+(defmacro rtree-low (node)
+  `(caar ,node))
+
+(defmacro rtree-high (node)
+  `(cdar ,node))
+
+(defmacro rtree-set-low (node number)
+  `(setcar (car ,node) ,number))
+
+(defmacro rtree-set-high (node number)
+  `(setcdr (car ,node) ,number))
+
+(defmacro rtree-left (node)
+  `(cadr ,node))
+
+(defmacro rtree-right (node)
+  `(cddr ,node))
+
+(defmacro rtree-range (node)
+  `(car ,node))
+
+(defsubst rtree-normalize-range (range)
+  (when (numberp range)
+    (setq range (cons range range)))
+  range)
+
+(define-obsolete-function-alias 'rtree-normalise-range
+  'rtree-normalize-range "25.1")
+
+(defun rtree-make (range)
+  "Make an rtree from RANGE."
+  ;; Normalize the range.
+  (unless (listp (cdr-safe range))
+    (setq range (list range)))
+  (rtree-make-1 (cons nil range) (length range)))
+
+(defun rtree-make-1 (range length)
+  (let ((mid (/ length 2))
+       (node (rtree-make-node)))
+    (when (> mid 0)
+      (rtree-set-left node (rtree-make-1 range mid)))
+    (rtree-set-range node (rtree-normalize-range (cadr range)))
+    (setcdr range (cddr range))
+    (when (> (- length mid 1) 0)
+      (rtree-set-right node (rtree-make-1 range (- length mid 1))))
+    node))
+
+(defun rtree-memq (tree number)
+  "Return non-nil if NUMBER is present in TREE."
+  (while (and tree
+             (not (and (>= number (rtree-low tree))
+                       (<= number (rtree-high tree)))))
+    (setq tree
+         (if (< number (rtree-low tree))
+             (rtree-left tree)
+           (rtree-right tree))))
+  tree)
+
+(defun rtree-add (tree number)
+  "Add NUMBER to TREE."
+  (while tree
+    (cond
+     ;; It's already present, so we don't have to do anything.
+     ((and (>= number (rtree-low tree))
+          (<= number (rtree-high tree)))
+      (setq tree nil))
+     ((< number (rtree-low tree))
+      (cond
+       ;; Extend the low range.
+       ((= number (1- (rtree-low tree)))
+       (rtree-set-low tree number)
+       ;; Check whether we need to merge this node with the child.
+       (when (and (rtree-left tree)
+                  (= (rtree-high (rtree-left tree)) (1- number)))
+         ;; Extend the range to the low from the child.
+         (rtree-set-low tree (rtree-low (rtree-left tree)))
+         ;; The child can't have a right child, so just transplant the
+         ;; child's left tree to our left tree.
+         (rtree-set-left tree (rtree-left (rtree-left tree))))
+       (setq tree nil))
+       ;; Descend further to the left.
+       ((rtree-left tree)
+       (setq tree (rtree-left tree)))
+       ;; Add a new node.
+       (t
+       (let ((new-node (rtree-make-node)))
+         (rtree-set-low new-node number)
+         (rtree-set-high new-node number)
+         (rtree-set-left tree new-node)
+         (setq tree nil)))))
+     (t
+      (cond
+       ;; Extend the high range.
+       ((= number (1+ (rtree-high tree)))
+       (rtree-set-high tree number)
+       ;; Check whether we need to merge this node with the child.
+       (when (and (rtree-right tree)
+                  (= (rtree-low (rtree-right tree)) (1+ number)))
+         ;; Extend the range to the high from the child.
+         (rtree-set-high tree (rtree-high (rtree-right tree)))
+         ;; The child can't have a left child, so just transplant the
+         ;; child's left right to our right tree.
+         (rtree-set-right tree (rtree-right (rtree-right tree))))
+       (setq tree nil))
+       ;; Descend further to the right.
+       ((rtree-right tree)
+       (setq tree (rtree-right tree)))
+       ;; Add a new node.
+       (t
+       (let ((new-node (rtree-make-node)))
+         (rtree-set-low new-node number)
+         (rtree-set-high new-node number)
+         (rtree-set-right tree new-node)
+         (setq tree nil))))))))
+
+(defun rtree-delq (tree number)
+  "Remove NUMBER from TREE destructively.  Returns the new tree."
+  (let ((result tree)
+       prev)
+    (while tree
+      (cond
+       ((< number (rtree-low tree))
+       (setq prev tree
+             tree (rtree-left tree)))
+       ((> number (rtree-high tree))
+       (setq prev tree
+             tree (rtree-right tree)))
+       ;; The number is in this node.
+       (t
+       (cond
+        ;; The only entry; delete the node.
+        ((= (rtree-low tree) (rtree-high tree))
+         (cond
+          ;; Two children.  Replace with successor value.
+          ((and (rtree-left tree) (rtree-right tree))
+           (let ((parent tree)
+                 (successor (rtree-right tree)))
+             (while (rtree-left successor)
+               (setq parent successor
+                     successor (rtree-left successor)))
+             ;; We now have the leftmost child of our right child.
+             (rtree-set-range tree (rtree-range successor))
+             ;; Transplant the child (if any) to the parent.
+             (rtree-set-left parent (rtree-right successor))))
+          (t
+           (let ((rest (or (rtree-left tree)
+                           (rtree-right tree))))
+             ;; One or zero children.  Remove the node.
+             (cond
+              ((null prev)
+               (setq result rest))
+              ((eq (rtree-left prev) tree)
+               (rtree-set-left prev rest))
+              (t
+               (rtree-set-right prev rest)))))))
+        ;; The lowest in the range; just adjust.
+        ((= number (rtree-low tree))
+         (rtree-set-low tree (1+ number)))
+        ;; The highest in the range; just adjust.
+        ((= number (rtree-high tree))
+         (rtree-set-high tree (1- number)))
+        ;; We have to split this range.
+        (t
+         (let ((new-node (rtree-make-node)))
+           (rtree-set-low new-node (rtree-low tree))
+           (rtree-set-high new-node (1- number))
+           (rtree-set-low tree (1+ number))
+           (cond
+            ;; Two children; insert the new node as the predecessor
+            ;; node.
+            ((and (rtree-left tree) (rtree-right tree))
+             (let ((predecessor (rtree-left tree)))
+               (while (rtree-right predecessor)
+                 (setq predecessor (rtree-right predecessor)))
+               (rtree-set-right predecessor new-node)))
+            ((rtree-left tree)
+             (rtree-set-right new-node tree)
+             (rtree-set-left new-node (rtree-left tree))
+             (rtree-set-left tree nil)
+             (cond
+              ((null prev)
+               (setq result new-node))
+              ((eq (rtree-left prev) tree)
+               (rtree-set-left prev new-node))
+              (t
+               (rtree-set-right prev new-node))))
+            (t
+             (rtree-set-left tree new-node))))))
+       (setq tree nil))))
+    result))
+
+(defun rtree-extract (tree)
+  "Convert TREE to range form."
+  (let (stack result)
+    (while (or stack
+              tree)
+      (if tree
+         (progn
+           (push tree stack)
+           (setq tree (rtree-right tree)))
+       (setq tree (pop stack))
+       (push (if (= (rtree-low tree)
+                    (rtree-high tree))
+                 (rtree-low tree)
+               (rtree-range tree))
+             result)
+       (setq tree (rtree-left tree))))
+    result))
+
+(defun rtree-length (tree)
+  "Return the number of numbers stored in TREE."
+  (if (null tree)
+      0
+    (+ (rtree-length (rtree-left tree))
+       (1+ (- (rtree-high tree)
+             (rtree-low tree)))
+       (rtree-length (rtree-right tree)))))
+
+(provide 'rtree)
+
+;;; rtree.el ends here
diff --git a/xemacs-packages/gnus/lisp/sasl-cram.el b/xemacs-packages/gnus/lisp/sasl-cram.el
new file mode 100644 (file)
index 0000000..1ac72fe
--- /dev/null
@@ -0,0 +1,50 @@
+;;; sasl-cram.el --- CRAM-MD5 module for the SASL client framework
+
+;; Copyright (C) 2000, 2007-2016 Free Software Foundation, Inc.
+
+;; Author: Daiki Ueno <ueno@unixuser.org>
+;;     Kenichi OKADA <okada@opaopa.org>
+;; Keywords: SASL, CRAM-MD5
+;; Package: sasl
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+(require 'sasl)
+(require 'hmac-md5)
+
+(defconst sasl-cram-md5-steps
+  '(ignore                             ;no initial response
+    sasl-cram-md5-response))
+
+(defun sasl-cram-md5-response (client step)
+  (let ((passphrase
+        (sasl-read-passphrase
+         (format "CRAM-MD5 passphrase for %s: "
+                 (sasl-client-name client)))))
+    (unwind-protect
+       (concat (sasl-client-name client) " "
+               (encode-hex-string
+                (hmac-md5 (sasl-step-data step) passphrase)))
+      (fillarray passphrase 0))))
+
+(put 'sasl-cram 'sasl-mechanism
+     (sasl-make-mechanism "CRAM-MD5" sasl-cram-md5-steps))
+
+(provide 'sasl-cram)
+
+;;; sasl-cram.el ends here
diff --git a/xemacs-packages/gnus/lisp/sasl-digest.el b/xemacs-packages/gnus/lisp/sasl-digest.el
new file mode 100644 (file)
index 0000000..0c77f00
--- /dev/null
@@ -0,0 +1,157 @@
+;;; sasl-digest.el --- DIGEST-MD5 module for the SASL client framework
+
+;; Copyright (C) 2000, 2007-2016 Free Software Foundation, Inc.
+
+;; Author: Daiki Ueno <ueno@unixuser.org>
+;;     Kenichi OKADA <okada@opaopa.org>
+;; Keywords: SASL, DIGEST-MD5
+;; Package: sasl
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This program is implemented from draft-leach-digest-sasl-05.txt.
+;;
+;; It is caller's responsibility to base64-decode challenges and
+;; base64-encode responses in IMAP4 AUTHENTICATE command.
+;;
+;; Passphrase should be longer than 16 bytes. (See RFC 2195)
+
+;;; Commentary:
+
+(require 'sasl)
+(require 'hmac-md5)
+
+(defvar sasl-digest-md5-nonce-count 1)
+(defvar sasl-digest-md5-unique-id-function
+  sasl-unique-id-function)
+
+(defvar sasl-digest-md5-syntax-table
+  (let ((table (make-syntax-table)))
+    (modify-syntax-entry ?= "." table)
+    (modify-syntax-entry ?, "." table)
+    table)
+  "A syntax table for parsing digest-challenge attributes.")
+
+(defconst sasl-digest-md5-steps
+  '(ignore                             ;no initial response
+    sasl-digest-md5-response
+    ignore))                           ;""
+
+(defun sasl-digest-md5-parse-string (string)
+  "Parse STRING and return a property list.
+The value is a cons cell of the form \(realm nonce qop-options stale maxbuf
+charset algorithm cipher-opts auth-param)."
+  (with-temp-buffer
+    (set-syntax-table sasl-digest-md5-syntax-table)
+    (save-excursion
+      (insert string)
+      (goto-char (point-min))
+      (insert "(")
+      (while (progn (forward-sexp) (not (eobp)))
+       (delete-char 1)
+       (insert " "))
+      (insert ")")
+      (read (point-min-marker)))))
+
+(defun sasl-digest-md5-digest-uri (serv-type host &optional serv-name)
+  (concat serv-type "/" host
+         (if (and serv-name
+                  (not (string= host serv-name)))
+             (concat "/" serv-name))))
+
+(defun sasl-digest-md5-cnonce ()
+  (let ((sasl-unique-id-function sasl-digest-md5-unique-id-function))
+    (sasl-unique-id)))
+
+(defun sasl-digest-md5-response-value (username
+                                      realm
+                                      nonce
+                                      cnonce
+                                      nonce-count
+                                      qop
+                                      digest-uri
+                                      authzid)
+  (let ((passphrase
+        (sasl-read-passphrase
+         (format "DIGEST-MD5 passphrase for %s: "
+                 username))))
+    (unwind-protect
+       (encode-hex-string
+        (md5-binary
+         (concat
+          (encode-hex-string
+           (md5-binary (concat (md5-binary
+                                (concat username ":" realm ":" passphrase))
+                               ":" nonce ":" cnonce
+                               (if authzid
+                                   (concat ":" authzid)))))
+          ":" nonce
+          ":" (format "%08x" nonce-count) ":" cnonce ":" qop ":"
+          (encode-hex-string
+           (md5-binary
+            (concat "AUTHENTICATE:" digest-uri
+                    (if (member qop '("auth-int" "auth-conf"))
+                        ":00000000000000000000000000000000")))))))
+      (fillarray passphrase 0))))
+
+(defun sasl-digest-md5-response (client step)
+  (let* ((plist
+         (sasl-digest-md5-parse-string (sasl-step-data step)))
+        (realm
+         (or (sasl-client-property client 'realm)
+             (plist-get plist 'realm))) ;need to check
+        (nonce-count
+         (or (sasl-client-property client 'nonce-count)
+              sasl-digest-md5-nonce-count))
+        (qop
+         (or (sasl-client-property client 'qop)
+             "auth"))
+        (digest-uri
+         (sasl-digest-md5-digest-uri
+          (sasl-client-service client)(sasl-client-server client)))
+        (cnonce
+         (or (sasl-client-property client 'cnonce)
+             (sasl-digest-md5-cnonce))))
+    (sasl-client-set-property client 'nonce-count (1+ nonce-count))
+    (unless (string= qop "auth")
+      (sasl-error (format "Unsupported \"qop-value\": %s" qop)))
+    (concat
+     "username=\"" (sasl-client-name client) "\","
+     "realm=\"" realm "\","
+     "nonce=\"" (plist-get plist 'nonce) "\","
+     "cnonce=\"" cnonce "\","
+     (format "nc=%08x," nonce-count)
+     "digest-uri=\"" digest-uri "\","
+     "qop=" qop ","
+     "response="
+     (sasl-digest-md5-response-value
+      (sasl-client-name client)
+      realm
+      (plist-get plist 'nonce)
+      cnonce
+      nonce-count
+      qop
+      digest-uri
+      (plist-get plist 'authzid)))))
+
+(put 'sasl-digest 'sasl-mechanism
+     (sasl-make-mechanism "DIGEST-MD5" sasl-digest-md5-steps))
+
+(provide 'sasl-digest)
+
+;;; sasl-digest.el ends here
diff --git a/xemacs-packages/gnus/lisp/sasl-ntlm.el b/xemacs-packages/gnus/lisp/sasl-ntlm.el
new file mode 100644 (file)
index 0000000..66b6ab5
--- /dev/null
@@ -0,0 +1,66 @@
+;;; sasl-ntlm.el --- NTLM (NT Lan Manager) module for the SASL client framework
+
+;; Copyright (C) 2000, 2007-2016 Free Software Foundation, Inc.
+
+;; Author: Taro Kawagishi <tarok@transpulse.org>
+;; Keywords: SASL, NTLM
+;; Version: 1.00
+;; Created: February 2001
+;; Package: sasl
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This is a SASL interface layer for NTLM authentication message
+;; generation by ntlm.el
+
+;;; Code:
+
+(require 'sasl)
+(require 'ntlm)
+
+(defconst sasl-ntlm-steps
+  '(ignore                             ;nothing to do before making
+    sasl-ntlm-request                  ;authentication request
+    sasl-ntlm-response)                        ;response to challenge
+  "A list of functions to be called in sequence for the NTLM
+authentication steps.  They are called by `sasl-next-step'.")
+
+(defun sasl-ntlm-request (client step)
+  "SASL step function to generate a NTLM authentication request to the server.
+Called from `sasl-next-step'.
+CLIENT is a vector [mechanism user service server sasl-client-properties]
+STEP is a vector [<previous step function> <result of previous step function>]"
+  (let ((user (sasl-client-name client)))
+    (ntlm-build-auth-request user)))
+
+(defun sasl-ntlm-response (client step)
+  "SASL step function to generate a NTLM response against the server
+challenge stored in the 2nd element of STEP.  Called from `sasl-next-step'."
+  (let* ((user (sasl-client-name client))
+        (passphrase
+         (sasl-read-passphrase (format "NTLM passphrase for %s: " user)))
+        (challenge (sasl-step-data step)))
+    (ntlm-build-auth-response challenge user
+                             (ntlm-get-password-hashes passphrase))))
+
+(put 'sasl-ntlm 'sasl-mechanism
+     (sasl-make-mechanism "NTLM" sasl-ntlm-steps))
+
+(provide 'sasl-ntlm)
+
+;;; sasl-ntlm.el ends here
diff --git a/xemacs-packages/gnus/lisp/sasl-scram-rfc.el b/xemacs-packages/gnus/lisp/sasl-scram-rfc.el
new file mode 100644 (file)
index 0000000..9304518
--- /dev/null
@@ -0,0 +1,246 @@
+;;; sasl-scram-rfc.el --- SCRAM-SHA-1 module for the SASL client framework  -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2014-2016 Free Software Foundation, Inc.
+
+;; Author: Magnus Henoch <magnus.henoch@gmail.com>
+;; Package: sasl
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This program is implemented from RFC 5802.  It implements the
+;; SCRAM-SHA-1 SASL mechanism.
+;;
+;; RFC 5802 foresees "hash agility", i.e. new mechanisms based on the
+;; same protocol but using a different hash function.  Likewise, this
+;; module attempts to separate generic and specific functions, which
+;; should make it easy to implement any future SCRAM-* SASL mechanism.
+;; It should be as simple as copying the SCRAM-SHA-1 section below and
+;; replacing all SHA-1 references.
+;;
+;; This module does not yet implement the variants with channel
+;; binding, i.e. SCRAM-*-PLUS.  That would require cooperation from
+;; the TLS library.
+
+;;; Code:
+
+(ignore-errors (require 'cl-lib))
+
+(require 'sasl)
+(require 'hex-util)
+(require 'rfc2104)
+
+;;; Generic for SCRAM-*
+
+(defun sasl-scram-client-first-message (client _step)
+  (let ((c-nonce (sasl-unique-id)))
+    (sasl-client-set-property client 'c-nonce c-nonce))
+  (concat
+   ;; n = client doesn't support channel binding
+   "n,"
+   ;; TODO: where would we get authorization id from?
+   ","
+   (sasl-scram--client-first-message-bare client)))
+
+(defun sasl-scram--client-first-message-bare (client)
+  (let ((c-nonce (sasl-client-property client 'c-nonce)))
+    (concat
+     ;; TODO: saslprep username or disallow non-ASCII characters
+     "n=" (sasl-client-name client) ","
+     "r=" c-nonce)))
+
+(eval-and-compile
+  (declare-function sasl-cl-coerce "sasl-scram-rfc")
+  (declare-function sasl-cl-mapcar-many "sasl-scram-rfc")
+  (if (fboundp 'cl-map)
+      (defalias 'sasl-cl-map 'cl-map)
+    (defun sasl-cl-mapcar-many (func seqs)
+      (if (cdr (cdr seqs))
+         (let* ((res nil)
+                (n (apply 'min (mapcar 'length seqs)))
+                (i 0)
+                (args (copy-sequence seqs))
+                p1 p2)
+           (setq seqs (copy-sequence seqs))
+           (while (< i n)
+             (setq p1 seqs p2 args)
+             (while p1
+               (setcar p2
+                       (if (consp (car p1))
+                           (prog1 (car (car p1))
+                             (setcar p1 (cdr (car p1))))
+                         (aref (car p1) i)))
+               (setq p1 (cdr p1) p2 (cdr p2)))
+             (push (apply func args) res)
+             (setq i (1+ i)))
+           (nreverse res))
+       (let ((res nil)
+             (x (car seqs))
+             (y (nth 1 seqs)))
+         (let ((n (min (length x) (length y)))
+               (i -1))
+           (while (< (setq i (1+ i)) n)
+             (push (funcall func
+                            (if (consp x) (pop x) (aref x i))
+                            (if (consp y) (pop y) (aref y i)))
+                   res)))
+         (nreverse res))))
+
+    (defun sasl-cl-coerce (x type)
+      "Coerce OBJECT to type TYPE.
+TYPE is a Common Lisp type specifier.
+\n(fn OBJECT TYPE)"
+      (cond ((eq type 'list) (if (listp x) x (append x nil)))
+           ((eq type 'vector) (if (vectorp x) x (vconcat x)))
+           ((eq type 'string) (if (stringp x) x (concat x)))
+           ((eq type 'array) (if (arrayp x) x (vconcat x)))
+           ((and (eq type 'character) (stringp x) (= (length x) 1)) (aref x 0))
+           ((and (eq type 'character) (symbolp x))
+            (sasl-cl-coerce (symbol-name x) type))
+           ((eq type 'float) (float x))
+           ;;((cl-typep x type) x)
+           (t (error "Can't coerce %s to type %s" x type))))
+
+    (defun sasl-cl-map (type func seq &rest rest)
+      "Map a FUNCTION across one or more SEQUENCEs, returning a sequence.
+TYPE is the sequence type to return.
+\n(fn TYPE FUNCTION SEQUENCE...)"
+      (let (res y)
+       (if rest
+           (if (or (cdr rest) (nlistp seq) (nlistp (car rest)))
+               (setq res (sasl-cl-mapcar-many func (cons seq rest)))
+             (setq y (car rest))
+             (while (and seq y)
+               (push (funcall func (pop seq) (pop y)) res))
+             (setq res (nreverse res)))
+         (setq res (mapcar func seq)))
+       (and type (sasl-cl-coerce res type)))))
+
+  (if (fboundp 'string-prefix-p)
+      (defalias 'sasl-string-prefix-p 'string-prefix-p)
+    (defun sasl-string-prefix-p (prefix string &optional ignore-case)
+      "Return non-nil if PREFIX is a prefix of STRING.
+If IGNORE-CASE is non-nil, the comparison is done without paying attention
+to case differences."
+      (let ((prefix-length (length prefix)))
+       (cond ((> prefix-length (length string)) nil)
+             (ignore-case
+              (string-equal (downcase prefix)
+                            (downcase (substring string 0 prefix-length))))
+             (t
+              (string-equal prefix (substring string 0 prefix-length))))))))
+
+(defun sasl-scram--client-final-message (hash-fun block-length hash-length client step)
+  (unless (string-match
+          "^r=\\([^,]+\\),s=\\([^,]+\\),i=\\([0-9]+\\)\\(?:$\\|,\\)"
+          (sasl-step-data step))
+    (sasl-error "Unexpected server response"))
+  (let* ((hmac-fun (lambda (text key)
+                    (decode-hex-string
+                     (rfc2104-hash hash-fun block-length hash-length key text))))
+        (step-data (sasl-step-data step))
+        (nonce (match-string 1 step-data))
+        (salt-base64 (match-string 2 step-data))
+        (iteration-count (string-to-number (match-string 3 step-data)))
+
+        (c-nonce (sasl-client-property client 'c-nonce))
+        ;; no channel binding, no authorization id
+        (cbind-input "n,,"))
+    (unless (sasl-string-prefix-p c-nonce nonce)
+      (sasl-error "Invalid nonce from server"))
+    (let* ((client-final-message-without-proof
+           (concat "c=" (base64-encode-string cbind-input) ","
+                   "r=" nonce))
+          (password
+           ;; TODO: either apply saslprep or disallow non-ASCII characters
+           (sasl-read-passphrase
+            (format "%s passphrase for %s: "
+                    (sasl-mechanism-name (sasl-client-mechanism client))
+                    (sasl-client-name client))))
+          (salt (base64-decode-string salt-base64))
+          (salted-password
+           ;; Hi(str, salt, i):
+           (let ((digest (concat salt (string 0 0 0 1)))
+                 (xored nil))
+             (dotimes (_i iteration-count xored)
+               (setq digest (funcall hmac-fun digest password))
+               (setq xored (if (null xored)
+                               digest
+                             (sasl-cl-map 'string 'logxor xored digest))))))
+          (client-key
+           (funcall hmac-fun "Client Key" salted-password))
+          (stored-key (decode-hex-string (funcall hash-fun client-key)))
+          (auth-message
+           (concat
+            (sasl-scram--client-first-message-bare client) ","
+            step-data ","
+            client-final-message-without-proof))
+          (client-signature (funcall hmac-fun (encode-coding-string auth-message 'utf-8) stored-key))
+          (client-proof (sasl-cl-map 'string 'logxor client-key client-signature))
+          (client-final-message
+           (concat client-final-message-without-proof ","
+                   "p=" (base64-encode-string client-proof))))
+      (sasl-client-set-property client 'auth-message auth-message)
+      (sasl-client-set-property client 'salted-password salted-password)
+      client-final-message)))
+
+(defun sasl-scram--authenticate-server (hash-fun block-length hash-length client step)
+  (cond
+   ((string-match "^e=\\([^,]+\\)" (sasl-step-data step))
+    (sasl-error (format "Server error: %s" (match-string 1 (sasl-step-data step)))))
+   ((string-match "^v=\\([^,]+\\)" (sasl-step-data step))
+    (let* ((hmac-fun (lambda (text key)
+                      (decode-hex-string
+                       (rfc2104-hash hash-fun block-length hash-length key text))))
+          (verifier (base64-decode-string (match-string 1 (sasl-step-data step))))
+          (auth-message (sasl-client-property client 'auth-message))
+          (salted-password (sasl-client-property client 'salted-password))
+          (server-key (funcall hmac-fun "Server Key" salted-password))
+          (expected-server-signature
+           (funcall hmac-fun (encode-coding-string auth-message 'utf-8) server-key)))
+      (unless (string= expected-server-signature verifier)
+       (sasl-error "Server not authenticated"))))
+   (t
+    (sasl-error "Invalid response from server"))))
+
+;;; SCRAM-SHA-1
+
+(defconst sasl-scram-sha-1-steps
+  '(sasl-scram-client-first-message
+    sasl-scram-sha-1-client-final-message
+    sasl-scram-sha-1-authenticate-server))
+
+(defun sasl-scram-sha-1-client-final-message (client step)
+  (sasl-scram--client-final-message
+   ;; HMAC-SHA1 uses block length 64 and hash length 20; see RFC 2104.
+   'sha1 64 20 client step))
+
+(defun sasl-scram-sha-1-authenticate-server (client step)
+  (sasl-scram--authenticate-server
+   'sha1 64 20 client step))
+
+;; This needs to be at the end, because of how `sasl-make-mechanism'
+;; handles step function names.
+(put 'sasl-scram-sha-1 'sasl-mechanism
+     (sasl-make-mechanism "SCRAM-SHA-1" sasl-scram-sha-1-steps))
+
+(put 'sasl-scram-rfc 'sasl-mechanism (get 'sasl-scram-sha-1 'sasl-mechanism))
+
+(provide 'sasl-scram-sha-1)
+
+(provide 'sasl-scram-rfc)
+;;; sasl-scram-rfc.el ends here
diff --git a/xemacs-packages/gnus/lisp/sasl.el b/xemacs-packages/gnus/lisp/sasl.el
new file mode 100644 (file)
index 0000000..419fef0
--- /dev/null
@@ -0,0 +1,270 @@
+;;; sasl.el --- SASL client framework
+
+;; Copyright (C) 2000, 2007-2016 Free Software Foundation, Inc.
+
+;; Author: Daiki Ueno <ueno@unixuser.org>
+;; Keywords: SASL
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This module provides common interface functions to share several
+;; SASL mechanism drivers.  The toplevel is designed to be mostly
+;; compatible with [Java-SASL].
+;;
+;; [SASL] J. Myers, "Simple Authentication and Security Layer (SASL)",
+;;     RFC 2222, October 1997.
+;;
+;; [Java-SASL] R. Weltman & R. Lee, "The Java SASL Application Program
+;;     Interface", draft-weltman-java-sasl-03.txt, March 2000.
+
+;;; Code:
+
+(defvar sasl-mechanisms
+  '("SCRAM-SHA-1" "CRAM-MD5" "DIGEST-MD5" "PLAIN" "LOGIN" "ANONYMOUS"
+    "NTLM"))
+
+(defvar sasl-mechanism-alist
+  '(("CRAM-MD5" sasl-cram)
+    ("DIGEST-MD5" sasl-digest)
+    ("PLAIN" sasl-plain)
+    ("LOGIN" sasl-login)
+    ("ANONYMOUS" sasl-anonymous)
+    ("NTLM" sasl-ntlm)
+    ("SCRAM-SHA-1" sasl-scram-rfc)))
+
+(defvar sasl-unique-id-function #'sasl-unique-id-function)
+
+(put 'sasl-error 'error-message "SASL error")
+(put 'sasl-error 'error-conditions '(sasl-error error))
+
+(defun sasl-error (datum)
+  (signal 'sasl-error (list datum)))
+
+;;; @ SASL client
+;;;
+
+(defun sasl-make-client (mechanism name service server)
+  "Return a newly allocated SASL client.
+NAME is name of the authorization.  SERVICE is name of the service desired.
+SERVER is the fully qualified host name of the server to authenticate to."
+  (vector mechanism name service server (make-symbol "sasl-client-properties")))
+
+(defun sasl-client-mechanism (client)
+  "Return the authentication mechanism driver of CLIENT."
+  (aref client 0))
+
+(defun sasl-client-name (client)
+  "Return the authorization name of CLIENT, a string."
+  (aref client 1))
+
+(defun sasl-client-service (client)
+  "Return the service name of CLIENT, a string."
+  (aref client 2))
+
+(defun sasl-client-server (client)
+  "Return the server name of CLIENT, a string."
+  (aref client 3))
+
+(defun sasl-client-set-properties (client plist)
+  "Destructively set the properties of CLIENT.
+The second argument PLIST is the new property list."
+  (setplist (aref client 4) plist))
+
+(defun sasl-client-set-property (client property value)
+  "Add the given PROPERTY/VALUE to CLIENT."
+  (put (aref client 4) property value))
+
+(defun sasl-client-property (client property)
+  "Return the value of the PROPERTY of CLIENT."
+  (get (aref client 4) property))
+
+(defun sasl-client-properties (client)
+  "Return the properties of CLIENT."
+  (symbol-plist (aref client 4)))
+
+;;; @ SASL mechanism
+;;;
+
+(defun sasl-make-mechanism (name steps)
+  "Make an authentication mechanism.
+NAME is a IANA registered SASL mechanism name.
+STEPS is list of continuation functions."
+  (vector name
+         (mapcar
+          (lambda (step)
+            (let ((symbol (make-symbol (symbol-name step))))
+              (fset symbol (symbol-function step))
+              symbol))
+          steps)))
+
+(defun sasl-mechanism-name (mechanism)
+  "Return name of MECHANISM, a string."
+  (aref mechanism 0))
+
+(defun sasl-mechanism-steps (mechanism)
+  "Return the authentication steps of MECHANISM, a list of functions."
+  (aref mechanism 1))
+
+(defun sasl-find-mechanism (mechanisms)
+  "Retrieve an appropriate mechanism object from MECHANISMS hints."
+  (let* ((sasl-mechanisms sasl-mechanisms)
+        (mechanism
+         (catch 'done
+           (while sasl-mechanisms
+             (if (member (car sasl-mechanisms) mechanisms)
+                 (throw 'done (nth 1 (assoc (car sasl-mechanisms)
+                                            sasl-mechanism-alist))))
+             (setq sasl-mechanisms (cdr sasl-mechanisms))))))
+    (if mechanism
+       (require mechanism))
+    (get mechanism 'sasl-mechanism)))
+
+;;; @ SASL authentication step
+;;;
+
+(defun sasl-step-data (step)
+  "Return the data which STEP holds, a string."
+  (aref step 1))
+
+(defun sasl-step-set-data (step data)
+  "Store DATA string to STEP."
+  (aset step 1 data))
+
+(defun sasl-next-step (client step)
+  "Evaluate the challenge and prepare an appropriate next response.
+The data type of the value and 2nd argument STEP is nil or opaque
+authentication step which holds the reference to the next action and
+the current challenge.  At the first time STEP should be set to nil."
+  (let* ((steps
+         (sasl-mechanism-steps
+          (sasl-client-mechanism client)))
+        (function
+         (if (vectorp step)
+             (nth 1 (memq (aref step 0) steps))
+           (car steps))))
+    (if function
+       (vector function (funcall function client step)))))
+
+(defvar sasl-read-passphrase nil)
+(defun sasl-read-passphrase (prompt)
+  (if (not sasl-read-passphrase)
+      (if (functionp 'read-passwd)
+         (setq sasl-read-passphrase 'read-passwd)
+       (if (load "passwd" t)
+           (setq sasl-read-passphrase 'read-passwd)
+         (autoload 'ange-ftp-read-passwd "ange-ftp")
+         (setq sasl-read-passphrase 'ange-ftp-read-passwd))))
+  (funcall sasl-read-passphrase prompt))
+
+(defun sasl-unique-id ()
+  "Compute a data string which must be different each time.
+It contain at least 64 bits of entropy."
+  (concat (funcall sasl-unique-id-function)(funcall sasl-unique-id-function)))
+
+(defvar sasl-unique-id-char nil)
+
+;; stolen (and renamed) from message.el
+(defun sasl-unique-id-function ()
+  ;; Don't use microseconds from (current-time), they may be unsupported.
+  ;; Instead we use this randomly inited counter.
+  (setq sasl-unique-id-char
+       (% (1+ (or sasl-unique-id-char (logand (random) (1- (lsh 1 20)))))
+          ;; (current-time) returns 16-bit ints,
+          ;; and 2^16*25 just fits into 4 digits i base 36.
+          (* 25 25)))
+  (let ((tm (current-time)))
+    (concat
+     (sasl-unique-id-number-base36
+      (+ (car   tm)
+        (lsh (% sasl-unique-id-char 25) 16)) 4)
+     (sasl-unique-id-number-base36
+      (+ (nth 1 tm)
+        (lsh (/ sasl-unique-id-char 25) 16)) 4))))
+
+(defun sasl-unique-id-number-base36 (num len)
+  (if (if (< len 0)
+         (<= num 0)
+       (= len 0))
+      ""
+    (concat (sasl-unique-id-number-base36 (/ num 36) (1- len))
+           (char-to-string (aref "zyxwvutsrqponmlkjihgfedcba9876543210"
+                                 (% num 36))))))
+
+;;; PLAIN (RFC2595 Section 6)
+(defconst sasl-plain-steps
+  '(sasl-plain-response))
+
+(defun sasl-plain-response (client step)
+  (let ((passphrase
+        (sasl-read-passphrase
+         (format "PLAIN passphrase for %s: " (sasl-client-name client))))
+       (authenticator-name
+        (sasl-client-property
+         client 'authenticator-name))
+       (name (sasl-client-name client)))
+    (unwind-protect
+       (if (and authenticator-name
+                (not (string= authenticator-name name)))
+           (concat authenticator-name "\0" name "\0" passphrase)
+         (concat "\0" name "\0" passphrase))
+      (fillarray passphrase 0))))
+
+(put 'sasl-plain 'sasl-mechanism
+     (sasl-make-mechanism "PLAIN" sasl-plain-steps))
+
+(provide 'sasl-plain)
+
+;;; LOGIN (No specification exists)
+(defconst sasl-login-steps
+  '(ignore                             ;no initial response
+    sasl-login-response-1
+    sasl-login-response-2))
+
+(defun sasl-login-response-1 (client step)
+;;;  (unless (string-match "^Username:" (sasl-step-data step))
+;;;    (sasl-error (format "Unexpected response: %s" (sasl-step-data step))))
+  (sasl-client-name client))
+
+(defun sasl-login-response-2 (client step)
+;;;  (unless (string-match "^Password:" (sasl-step-data step))
+;;;    (sasl-error (format "Unexpected response: %s" (sasl-step-data step))))
+  (sasl-read-passphrase
+   (format "LOGIN passphrase for %s: " (sasl-client-name client))))
+
+(put 'sasl-login 'sasl-mechanism
+     (sasl-make-mechanism "LOGIN" sasl-login-steps))
+
+(provide 'sasl-login)
+
+;;; ANONYMOUS (RFC2245)
+(defconst sasl-anonymous-steps
+  '(ignore                             ;no initial response
+    sasl-anonymous-response))
+
+(defun sasl-anonymous-response (client step)
+  (or (sasl-client-property client 'trace)
+      (sasl-client-name client)))
+
+(put 'sasl-anonymous 'sasl-mechanism
+     (sasl-make-mechanism "ANONYMOUS" sasl-anonymous-steps))
+
+(provide 'sasl-anonymous)
+
+(provide 'sasl)
+
+;;; sasl.el ends here
diff --git a/xemacs-packages/gnus/lisp/score-mode.el b/xemacs-packages/gnus/lisp/score-mode.el
new file mode 100644 (file)
index 0000000..8413f22
--- /dev/null
@@ -0,0 +1,110 @@
+;;; score-mode.el --- mode for editing Gnus score files
+
+;; Copyright (C) 1996, 2001-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: news, mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(require 'mm-util)                     ; for mm-universal-coding-system
+(require 'gnus-util)                   ; for gnus-pp, gnus-run-mode-hooks
+
+(defvar gnus-score-edit-done-hook nil
+  "*Hook run at the end of closing the score buffer.")
+
+(defvar gnus-score-mode-hook nil
+  "*Hook run in score mode buffers.")
+
+(defvar gnus-score-menu-hook nil
+  "*Hook run after creating the score mode menu.")
+
+(defvar gnus-score-edit-exit-function nil
+  "Function run on exit from the score buffer.")
+
+(defvar gnus-score-mode-map
+  (let ((map (make-sparse-keymap)))
+    (set-keymap-parent map emacs-lisp-mode-map)
+    (define-key map "\C-c\C-c" 'gnus-score-edit-exit)
+    (define-key map "\C-c\C-d" 'gnus-score-edit-insert-date)
+    (define-key map "\C-c\C-p" 'gnus-score-pretty-print)
+    map))
+
+(defvar score-mode-syntax-table
+  (let ((table (copy-syntax-table lisp-mode-syntax-table)))
+    (modify-syntax-entry ?| "w" table)
+    table)
+  "Syntax table used in score-mode buffers.")
+
+;; We need this to cope with non-ASCII scoring.
+(defvar score-mode-coding-system mm-universal-coding-system)
+
+;;;###autoload
+(define-derived-mode gnus-score-mode emacs-lisp-mode "Score"
+  "Mode for editing Gnus score files.
+This mode is an extended emacs-lisp mode.
+
+\\{gnus-score-mode-map}"
+  (gnus-score-make-menu-bar)
+  (make-local-variable 'gnus-score-edit-exit-function))
+
+(defun gnus-score-make-menu-bar ()
+  (unless (boundp 'gnus-score-menu)
+    (easy-menu-define
+     gnus-score-menu gnus-score-mode-map ""
+     '("Score"
+       ["Exit" gnus-score-edit-exit t]
+       ["Insert date" gnus-score-edit-insert-date t]
+       ["Format" gnus-score-pretty-print t]))
+    (run-hooks 'gnus-score-menu-hook)))
+
+(defun gnus-score-edit-insert-date ()
+  "Insert date in numerical format."
+  (interactive)
+  (princ (time-to-days (current-time)) (current-buffer)))
+
+(defun gnus-score-pretty-print ()
+  "Format the current score file."
+  (interactive)
+  (goto-char (point-min))
+  (let ((form (read (current-buffer))))
+    (erase-buffer)
+    (let ((emacs-lisp-mode-syntax-table score-mode-syntax-table))
+      (gnus-pp form)))
+  (goto-char (point-min)))
+
+(defun gnus-score-edit-exit ()
+  "Stop editing the score file."
+  (interactive)
+  (unless (file-exists-p (file-name-directory (buffer-file-name)))
+    (make-directory (file-name-directory (buffer-file-name)) t))
+  (let ((coding-system-for-write score-mode-coding-system))
+    (save-buffer))
+  (bury-buffer (current-buffer))
+  (let ((buf (current-buffer)))
+    (when gnus-score-edit-exit-function
+      (funcall gnus-score-edit-exit-function))
+    (when (eq buf (current-buffer))
+      (switch-to-buffer (other-buffer (current-buffer))))))
+
+(provide 'score-mode)
+
+;;; score-mode.el ends here
diff --git a/xemacs-packages/gnus/lisp/sha1.el b/xemacs-packages/gnus/lisp/sha1.el
new file mode 100644 (file)
index 0000000..7f6ab4e
--- /dev/null
@@ -0,0 +1,441 @@
+;;; sha1.el --- SHA1 Secure Hash Algorithm in Emacs-Lisp
+
+;; Copyright (C) 1999, 2001-2016 Free Software Foundation, Inc.
+
+;; Author: Shuhei KOBAYASHI <shuhei@aqua.ocn.ne.jp>
+;; Keywords: SHA1, FIPS 180-1
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This program is implemented from the definition of SHA-1 in FIPS PUB
+;; 180-1 (Federal Information Processing Standards Publication 180-1),
+;; "Announcing the Standard for SECURE HASH STANDARD".
+;; <URL:http://www.itl.nist.gov/div897/pubs/fip180-1.htm>
+;; (EXCEPTION; two optimizations taken from GnuPG/cipher/sha1.c)
+;;
+;; Test cases from FIPS PUB 180-1.
+;;
+;; (sha1 "abc")
+;; => a9993e364706816aba3e25717850c26c9cd0d89d
+;;
+;; (sha1 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")
+;; => 84983e441c3bd26ebaae4aa1f95129e5e54670f1
+;;
+;; (sha1 (make-string 1000000 ?a))
+;; => 34aa973cd4c4daa4f61eeb2bdbad27316534016f
+;;
+;; BUGS:
+;;  * It is assumed that length of input string is less than 2^29 bytes.
+;;  * It is caller's responsibility to make string (or region) unibyte.
+;;
+;; TODO:
+;;  * Rewrite from scratch!
+;;    This version is much faster than Keiichi Suzuki's another sha1.el,
+;;    but it is too dirty.
+
+;;; Code:
+
+(require 'hex-util)
+
+;;;
+;;; external SHA1 function.
+;;;
+
+(defgroup sha1 nil
+  "Elisp interface for SHA1 hash computation."
+  :version "22.1"
+  :group 'extensions)
+
+(defcustom 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 external program only.
+If this variable is set to nil, use internal function only."
+  :type 'integer
+  :group 'sha1)
+
+(defcustom sha1-program '("sha1sum")
+  "Name of program to compute SHA1.
+It must be a string \(program name\) or list of strings \(name and its args\)."
+  :type '(repeat string)
+  :group 'sha1)
+
+(defcustom sha1-use-external (condition-case ()
+                                (executable-find (car sha1-program))
+                              (error))
+  "Use external SHA1 program.
+If this variable is set to nil, use internal function only."
+  :type 'boolean
+  :group 'sha1)
+
+(defun sha1-string-external (string &optional binary)
+  (let ((default-directory "/") ;; in case otherwise non-existent
+        (process-connection-type nil) ;; pipe
+        prog args digest)
+    (if (consp sha1-program)
+       (setq prog (car sha1-program)
+             args (cdr sha1-program))
+      (setq prog sha1-program
+           args nil))
+    (with-temp-buffer
+      (unless (featurep 'xemacs) (set-buffer-multibyte nil))
+      (insert string)
+      (apply (function call-process-region)
+            (point-min) (point-max)
+            prog t t nil args)
+      ;; SHA1 is 40 bytes long in hexadecimal form.
+      (setq digest (buffer-substring (point-min)(+ (point-min) 40))))
+    (if binary
+       (decode-hex-string digest)
+      digest)))
+
+(defun sha1-region-external (beg end &optional binary)
+  (sha1-string-external (buffer-substring-no-properties beg end) binary))
+
+;;;
+;;; 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 &optional binary)
+  (if binary
+      (sha1-binary string)
+    (encode-hex-string (sha1-binary string))))
+
+(defun sha1-region-internal (beg end &optional binary)
+  (sha1-string-internal (buffer-substring-no-properties beg end) binary))
+
+;;;
+;;; application interface.
+;;;
+
+(defun sha1-region (beg end &optional binary)
+  (if (and sha1-use-external
+          sha1-maximum-internal-length
+          (> (abs (- end beg)) sha1-maximum-internal-length))
+      (sha1-region-external beg end binary)
+    (sha1-region-internal beg end binary)))
+
+(defun sha1-string (string &optional binary)
+  (if (and sha1-use-external
+          sha1-maximum-internal-length
+          (> (length string) sha1-maximum-internal-length))
+      (sha1-string-external string binary)
+    (sha1-string-internal string binary)))
+
+;;;###autoload
+(defun sha1 (object &optional beg end binary)
+  "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 BINARY is non-nil, return a string in binary form."
+  (if (stringp object)
+      (sha1-string object binary)
+    (with-current-buffer object
+      (sha1-region (or beg (point-min)) (or end (point-max)) binary))))
+
+(provide 'sha1)
+
+;;; sha1.el ends here
diff --git a/xemacs-packages/gnus/lisp/sieve-manage.el b/xemacs-packages/gnus/lisp/sieve-manage.el
new file mode 100644 (file)
index 0000000..212a7fd
--- /dev/null
@@ -0,0 +1,576 @@
+;;; sieve-manage.el --- Implementation of the managesieve protocol in elisp
+
+;; Copyright (C) 2001-2016 Free Software Foundation, Inc.
+
+;; Author: Simon Josefsson <simon@josefsson.org>
+;;         Albert Krewinkel <tarleb@moltkeplatz.de>
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This library provides an elisp API for the managesieve network
+;; protocol.
+;;
+;; It uses the SASL library for authentication, which means it
+;; supports DIGEST-MD5, CRAM-MD5, SCRAM-MD5, NTLM, PLAIN and LOGIN
+;; methods.  STARTTLS is not well tested, but should be easy to get to
+;; work if someone wants.
+;;
+;; 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-listscripts'
+;; `sieve-manage-deletescript'
+;; `sieve-manage-getscript'
+;; performs managesieve protocol actions
+;;
+;; and that's it.  Example of a managesieve session in *scratch*:
+;;
+;; (with-current-buffer (sieve-manage-open "mail.example.com")
+;;   (sieve-manage-authenticate)
+;;   (sieve-manage-listscripts))
+;;
+;; => ((active . "main") "vacation")
+;;
+;; 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.
+;; 2002-07-27 Added DELETESCRIPT.  Suggested by Ned Ludd.
+;; 2002-08-03 Use SASL library.
+;; 2013-06-05 Enabled STARTTLS support, fixed bit rot.
+
+;;; Code:
+
+(if (locate-library "password-cache")
+    (require 'password-cache)
+  (require 'password))
+
+(eval-when-compile
+  (require 'cl)                                ; caddr
+  (require 'sasl)
+  (require 'starttls))
+(autoload 'sasl-find-mechanism "sasl")
+(autoload 'auth-source-search "auth-source")
+
+;; 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
+  :group 'sieve-manage)
+
+(defcustom sieve-manage-server-eol "\r\n"
+  "The EOL string sent from the server."
+  :type 'string
+  :group 'sieve-manage)
+
+(defcustom sieve-manage-client-eol "\r\n"
+  "The EOL string we send to the server."
+  :type 'string
+  :group 'sieve-manage)
+
+(defcustom sieve-manage-authenticators '(digest-md5
+                                        cram-md5
+                                        scram-md5
+                                        ntlm
+                                        plain
+                                        login)
+  "Priority of authenticators to consider when authenticating to server."
+  ;; FIXME Improve this.  It's not `set'.
+  ;; It's like (repeat (choice (const ...))), where each choice can
+  ;; only appear once.
+  :type '(repeat symbol)
+  :group 'sieve-manage)
+
+(defcustom sieve-manage-authenticator-alist
+  '((cram-md5   sieve-manage-cram-md5-p       sieve-manage-cram-md5-auth)
+    (digest-md5 sieve-manage-digest-md5-p     sieve-manage-digest-md5-auth)
+    (scram-md5  sieve-manage-scram-md5-p      sieve-manage-scram-md5-auth)
+    (ntlm       sieve-manage-ntlm-p           sieve-manage-ntlm-auth)
+    (plain      sieve-manage-plain-p          sieve-manage-plain-auth)
+    (login      sieve-manage-login-p          sieve-manage-login-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."
+  :type '(repeat (list (symbol :tag "Name") (function :tag "Check function")
+                      (function :tag "Authentication function")))
+  :group 'sieve-manage)
+
+(defcustom sieve-manage-default-port "sieve"
+  "Default port number or service name for managesieve protocol."
+  :type '(choice integer string)
+  :version "24.4"
+  :group 'sieve-manage)
+
+(defcustom sieve-manage-default-stream 'network
+  "Default stream type to use for `sieve-manage'."
+  :version "24.1"
+  :type 'symbol
+  :group 'sieve-manage)
+
+;; Internal variables:
+
+(defconst sieve-manage-local-variables '(sieve-manage-server
+                                        sieve-manage-port
+                                        sieve-manage-auth
+                                        sieve-manage-stream
+                                        sieve-manage-process
+                                        sieve-manage-client-eol
+                                        sieve-manage-server-eol
+                                        sieve-manage-capability))
+(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-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
+(autoload 'mm-enable-multibyte "mm-util")
+
+(defun sieve-manage-make-process-buffer ()
+  (with-current-buffer
+      (generate-new-buffer (format " *sieve %s:%s*"
+                                   sieve-manage-server
+                                   sieve-manage-port))
+    (mapc 'make-local-variable sieve-manage-local-variables)
+    (mm-enable-multibyte)
+    (buffer-disable-undo)
+    (current-buffer)))
+
+(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)
+          (mm-enable-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-server (server port &optional stream buffer)
+  "Open network connection to SERVER on PORT.
+Return the buffer associated with the connection."
+  (with-current-buffer buffer
+    (sieve-manage-erase)
+    (setq sieve-manage-state 'initial)
+    (destructuring-bind (proc . props)
+        (open-protocol-stream
+         "SIEVE" buffer server port
+         :type stream
+         :capability-command "CAPABILITY\r\n"
+         :end-of-command "^\\(OK\\|NO\\).*\n"
+         :success "^OK.*\n"
+         :return-list t
+         :starttls-function
+         (lambda (capabilities)
+           (when (string-match "\\bSTARTTLS\\b" capabilities)
+             "STARTTLS\r\n")))
+      (setq sieve-manage-process proc)
+      (setq sieve-manage-capability
+            (sieve-manage-parse-capability (plist-get props :capabilities)))
+      ;; Ignore new capabilities issues after successful STARTTLS
+      (when (and (memq stream '(nil network starttls))
+                 (eq (plist-get props :type) 'tls))
+        (sieve-manage-drop-next-answer))
+      (current-buffer))))
+
+;; Authenticators
+(defun sieve-sasl-auth (buffer mech)
+  "Login to server using the SASL MECH method."
+  (message "sieve: Authenticating using %s..." mech)
+  (with-current-buffer buffer
+    (let* ((auth-info (auth-source-search :host sieve-manage-server
+                                          :port "sieve"
+                                          :max 1
+                                          :create t))
+           (user-name (or (plist-get (nth 0 auth-info) :user) ""))
+           (user-password (or (plist-get (nth 0 auth-info) :secret) ""))
+           (user-password (if (functionp user-password)
+                              (funcall user-password)
+                            user-password))
+           (client (sasl-make-client (sasl-find-mechanism (list mech))
+                                     user-name "sieve" sieve-manage-server))
+           (sasl-read-passphrase
+            ;; We *need* to copy the password, because sasl will modify it
+            ;; somehow.
+            `(lambda (prompt) ,(copy-sequence user-password)))
+           (step (sasl-next-step client nil))
+           (tag (sieve-manage-send
+                 (concat
+                  "AUTHENTICATE \""
+                  mech
+                  "\""
+                  (and (sasl-step-data step)
+                       (concat
+                        " \""
+                        (base64-encode-string
+                         (sasl-step-data step)
+                         'no-line-break)
+                        "\"")))))
+           data rsp)
+      (catch 'done
+        (while t
+          (setq rsp nil)
+          (goto-char (point-min))
+          (while (null (or (progn
+                             (setq rsp (sieve-manage-is-string))
+                             (if (not (and rsp (looking-at
+                                                sieve-manage-server-eol)))
+                                 (setq rsp nil)
+                               (goto-char (match-end 0))
+                               rsp))
+                           (setq rsp (sieve-manage-is-okno))))
+            (accept-process-output sieve-manage-process 1)
+            (goto-char (point-min)))
+          (sieve-manage-erase)
+          (when (sieve-manage-ok-p rsp)
+            (when (and (cadr rsp)
+                       (string-match "^SASL \"\\([^\"]+\\)\"" (cadr rsp)))
+              (sasl-step-set-data
+               step (base64-decode-string (match-string 1 (cadr rsp)))))
+            (if (and (setq step (sasl-next-step client step))
+                     (setq data (sasl-step-data step)))
+                ;; We got data for server but it's finished
+                (error "Server not ready for SASL data: %s" data)
+              ;; The authentication process is finished.
+              (throw 'done t)))
+          (unless (stringp rsp)
+            (error "Server aborted SASL authentication: %s" (caddr rsp)))
+          (sasl-step-set-data step (base64-decode-string rsp))
+          (setq step (sasl-next-step client step))
+          (sieve-manage-send
+           (if (sasl-step-data step)
+               (concat "\""
+                       (base64-encode-string (sasl-step-data step)
+                                             'no-line-break)
+                       "\"")
+             ""))))
+      (message "sieve: Login using %s...done" mech))))
+
+(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."
+  (sieve-sasl-auth buffer "CRAM-MD5"))
+
+(defun sieve-manage-digest-md5-p (buffer)
+  (sieve-manage-capability "SASL" "DIGEST-MD5" buffer))
+
+(defun sieve-manage-digest-md5-auth (buffer)
+  "Login to managesieve server using the DIGEST-MD5 SASL method."
+  (sieve-sasl-auth buffer "DIGEST-MD5"))
+
+(defun sieve-manage-scram-md5-p (buffer)
+  (sieve-manage-capability "SASL" "SCRAM-MD5" buffer))
+
+(defun sieve-manage-scram-md5-auth (buffer)
+  "Login to managesieve server using the SCRAM-MD5 SASL method."
+  (sieve-sasl-auth buffer "SCRAM-MD5"))
+
+(defun sieve-manage-ntlm-p (buffer)
+  (sieve-manage-capability "SASL" "NTLM" buffer))
+
+(defun sieve-manage-ntlm-auth (buffer)
+  "Login to managesieve server using the NTLM SASL method."
+  (sieve-sasl-auth buffer "NTLM"))
+
+(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."
+  (sieve-sasl-auth buffer "PLAIN"))
+
+(defun sieve-manage-login-p (buffer)
+  (sieve-manage-capability "SASL" "LOGIN" buffer))
+
+(defun sieve-manage-login-auth (buffer)
+  "Login to managesieve server using the LOGIN SASL method."
+  (sieve-sasl-auth buffer "LOGIN"))
+
+;; Managesieve API
+
+(defun sieve-manage-open (server &optional port stream auth buffer)
+  "Open a network connection to a managesieve SERVER (string).
+Optional argument PORT is port number (integer) on remote server.
+Optional argument STREAM is any of `sieve-manage-streams' (a symbol).
+Optional argument AUTH indicates authenticator to use, see
+`sieve-manage-authenticators' for available authenticators.
+If nil, chooses the best stream the server is capable of.
+Optional argument BUFFER is buffer (buffer, or string naming buffer)
+to work in."
+  (setq sieve-manage-port (or port sieve-manage-default-port))
+  (with-current-buffer (or buffer (sieve-manage-make-process-buffer))
+    (setq sieve-manage-server (or server
+                                  sieve-manage-server)
+          sieve-manage-stream (or stream
+                                  sieve-manage-stream
+                                  sieve-manage-default-stream)
+          sieve-manage-auth   (or auth
+                                  sieve-manage-auth))
+    (message "sieve: Connecting to %s..." sieve-manage-server)
+    (sieve-manage-open-server sieve-manage-server
+                              sieve-manage-port
+                              sieve-manage-stream
+                              (current-buffer))
+    (when (sieve-manage-opened (current-buffer))
+      ;; Choose authenticator
+      (when (and (null sieve-manage-auth)
+                 (not (eq sieve-manage-state 'auth)))
+        (dolist (auth sieve-manage-authenticators)
+          (when (funcall (nth 1 (assq auth sieve-manage-authenticator-alist))
+                       buffer)
+            (setq sieve-manage-auth auth)
+            (return)))
+        (unless sieve-manage-auth
+          (error "Couldn't figure out authenticator for server")))
+      (sieve-manage-erase)
+      (current-buffer))))
+
+(defun sieve-manage-authenticate (&optional buffer)
+  "Authenticate on server in BUFFER.
+Return `sieve-manage-state' value."
+  (with-current-buffer (or buffer (current-buffer))
+    (if (eq sieve-manage-state 'nonauth)
+        (when (funcall (nth 2 (assq sieve-manage-auth
+                                    sieve-manage-authenticator-alist))
+                       (current-buffer))
+          (setq sieve-manage-state 'auth))
+      sieve-manage-state)))
+
+(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-capability (&optional name value buffer)
+  "Check if capability NAME of server BUFFER match VALUE.
+If it does, return the server value of NAME. If not returns nil.
+If VALUE is nil, do not check VALUE and return server value.
+If NAME is nil, return the full server list of capabilities."
+  (with-current-buffer (or buffer (current-buffer))
+    (if (null name)
+       sieve-manage-capability
+      (let ((server-value (cadr (assoc name sieve-manage-capability))))
+        (when (or (null value)
+                  (and server-value
+                       (string-match value server-value)))
+          server-value)))))
+
+(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)))
+
+(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
+                               ;; Here we assume that the coding-system will
+                               ;; replace each char with a single byte.
+                               ;; This is always the case if `content' is
+                               ;; a unibyte string.
+                              (length content)
+                              sieve-manage-client-eol content))
+    (sieve-manage-parse-okno)))
+
+(defun sieve-manage-deletescript (name &optional buffer)
+  (with-current-buffer (or buffer (current-buffer))
+    (sieve-manage-send (format "DELETESCRIPT \"%s\"" name))
+    (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-wait-for-answer ()
+  (let ((pattern "^\\(OK\\|NO\\).*\n")
+        pos)
+    (while (not pos)
+      (setq pos (search-forward-regexp pattern nil t))
+      (goto-char (point-min))
+      (sleep-for 0 50))
+    pos))
+
+(defun sieve-manage-drop-next-answer ()
+  (sieve-manage-wait-for-answer)
+  (sieve-manage-erase))
+
+(defun sieve-manage-ok-p (rsp)
+  (string= (downcase (or (car-safe rsp) "")) "ok"))
+
+(defun sieve-manage-is-okno ()
+  (when (looking-at (concat
+                    "^\\(OK\\|NO\\)\\( (\\([^)]+\\))\\)?\\( \\(.*\\)\\)?"
+                    sieve-manage-server-eol))
+    (let ((status (match-string 1))
+         (resp-code (match-string 3))
+         (response (match-string 5)))
+      (when response
+       (goto-char (match-beginning 5))
+       (setq response (sieve-manage-is-string)))
+      (list status resp-code response))))
+
+(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 (str)
+  "Parse managesieve capability string `STR'.
+Set variable `sieve-manage-capability' to "
+  (let ((capas (delq nil
+                     (mapcar #'split-string-and-unquote
+                             (split-string str "\n")))))
+    (when (string= "OK" (caar (last capas)))
+      (setq sieve-manage-state 'nonauth))
+    capas))
+
+(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)
+        (mm-enable-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/xemacs-packages/gnus/lisp/sieve-mode.el b/xemacs-packages/gnus/lisp/sieve-mode.el
new file mode 100644 (file)
index 0000000..5ea687d
--- /dev/null
@@ -0,0 +1,222 @@
+;;; sieve-mode.el --- Sieve code editing commands for Emacs
+
+;; Copyright (C) 2001-2016 Free Software Foundation, Inc.
+
+;; Author: Simon Josefsson <simon@josefsson.org>
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; 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
+
+;;; Code:
+
+(autoload 'sieve-manage "sieve")
+(autoload 'sieve-upload "sieve")
+(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 name used for Sieve Control Commands.")
+
+(defface sieve-control-commands
+  '((((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."
+  :group 'sieve)
+;; backward-compatibility alias
+(put 'sieve-control-commands-face 'face-alias 'sieve-control-commands)
+(put 'sieve-control-commands-face 'obsolete-face "22.1")
+
+(defvar sieve-action-commands-face 'sieve-action-commands
+  "Face name used for Sieve Action Commands.")
+
+(defface sieve-action-commands
+  '((((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."
+  :group 'sieve)
+;; backward-compatibility alias
+(put 'sieve-action-commands-face 'face-alias 'sieve-action-commands)
+(put 'sieve-action-commands-face 'obsolete-face "22.1")
+
+(defvar sieve-test-commands-face 'sieve-test-commands
+  "Face name used for Sieve Test Commands.")
+
+(defface sieve-test-commands
+  '((((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."
+  :group 'sieve)
+;; backward-compatibility alias
+(put 'sieve-test-commands-face 'face-alias 'sieve-test-commands)
+(put 'sieve-test-commands-face 'obsolete-face "22.1")
+
+(defvar sieve-tagged-arguments-face 'sieve-tagged-arguments
+  "Face name used for Sieve Tagged Arguments.")
+
+(defface sieve-tagged-arguments
+  '((((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."
+  :group 'sieve)
+;; backward-compatibility alias
+(put 'sieve-tagged-arguments-face 'face-alias 'sieve-tagged-arguments)
+(put 'sieve-tagged-arguments-face 'obsolete-face "22.1")
+
+
+(defconst sieve-font-lock-keywords
+  (eval-when-compile
+    (list
+     ;; control commands
+     (cons (regexp-opt '("require" "if" "else" "elsif" "stop")
+                       'words)
+          'sieve-control-commands-face)
+     ;; action commands
+     (cons (regexp-opt '("fileinto" "redirect" "reject" "keep" "discard")
+                       'words)
+          'sieve-action-commands-face)
+     ;; test commands
+     (cons (regexp-opt '("address" "allof" "anyof" "exists" "false"
+                        "true" "header" "not" "size" "envelope"
+                         "body")
+                       'words)
+          '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-c" 'sieve-upload-and-kill)
+    (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 'easy-menu-add-item "easymenu")
+
+;;;###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/xemacs-packages/gnus/lisp/sieve.el b/xemacs-packages/gnus/lisp/sieve.el
new file mode 100644 (file)
index 0000000..2046e53
--- /dev/null
@@ -0,0 +1,372 @@
+;;; sieve.el --- Utilities to manage sieve scripts
+
+;; Copyright (C) 2001-2016 Free Software Foundation, Inc.
+
+;; Author: Simon Josefsson <simon@josefsson.org>
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This file contain utilities to facilitate 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.
+;; 2002-07-27 Fix down-mouse-2 and down-mouse-3 in manage-mode.  Fix menubar
+;;            in manage-mode.  Change some messages.  Added sieve-deactivate*,
+;;            sieve-remove.  Fixed help text in manage-mode.  Suggested by
+;;            Ned Ludd.
+;;
+;; 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."
+  :version "22.1"
+  :group 'tools)
+
+(defcustom sieve-new-script "<new script>"
+  "Name of name script indicator."
+  :type 'string
+  :group 'sieve)
+
+(defcustom sieve-buffer "*sieve*"
+  "Name of sieve management buffer."
+  :type 'string
+  :group 'sieve)
+
+(defcustom sieve-template "\
+require \"fileinto\";
+
+# Example script (remove comment character '#' to make it effective!):
+#
+# if header :contains \"from\" \"coyote\" {
+#   discard;
+# } elsif header :contains [\"subject\"] [\"$$$\"] {
+#   discard;
+# } else {
+#  fileinto \"INBOX\";
+# }
+"
+  "Template sieve script."
+  :type 'string
+  :group 'sieve)
+
+;; Internal variables:
+
+(defvar sieve-manage-buffer nil)
+(defvar sieve-buffer-header-end nil)
+(defvar sieve-buffer-script-name nil
+  "The real script name of the buffer.")
+(make-local-variable 'sieve-buffer-script-name)
+
+;; Sieve-manage mode:
+
+(defvar sieve-manage-mode-map
+  (let ((map (make-sparse-keymap)))
+    ;; various
+    (define-key map "?" 'sieve-help)
+    (define-key map "h" 'sieve-help)
+    ;; activating
+    (define-key map "m" 'sieve-activate)
+    (define-key map "u" 'sieve-deactivate)
+    (define-key map "\M-\C-?" 'sieve-deactivate-all)
+    ;; navigation keys
+    (define-key map "\C-p" 'sieve-prev-line)
+    (define-key map [up] 'sieve-prev-line)
+    (define-key map "\C-n" 'sieve-next-line)
+    (define-key map [down] 'sieve-next-line)
+    (define-key map " " 'sieve-next-line)
+    (define-key map "n" 'sieve-next-line)
+    (define-key map "p" 'sieve-prev-line)
+    (define-key map "\C-m" 'sieve-edit-script)
+    (define-key map "f" 'sieve-edit-script)
+    (define-key map "o" 'sieve-edit-script-other-window)
+    (define-key map "r" 'sieve-remove)
+    (define-key map "q" 'sieve-bury-buffer)
+    (define-key map "Q" 'sieve-manage-quit)
+    (define-key map [(down-mouse-2)] 'sieve-edit-script)
+    (define-key map [(down-mouse-3)] 'sieve-manage-mode-menu)
+    map)
+  "Keymap for `sieve-manage-mode'.")
+
+(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]))
+
+(define-derived-mode sieve-manage-mode fundamental-mode "Sieve-manage"
+  "Mode used for sieve script management."
+  (buffer-disable-undo (current-buffer))
+  (setq truncate-lines t)
+  (easy-menu-add sieve-manage-mode-menu sieve-manage-mode-map))
+
+(put 'sieve-manage-mode 'mode-class 'special)
+
+;; Commands used in sieve-manage mode:
+
+(defun sieve-manage-quit ()
+  "Quit Manage Sieve and close the connection."
+  (interactive)
+  (sieve-manage-close sieve-manage-buffer)
+  (kill-buffer sieve-manage-buffer)
+  (kill-buffer (current-buffer)))
+
+(defun sieve-bury-buffer ()
+  "Bury the Manage Sieve buffer without closing the connection."
+  (interactive)
+  (bury-buffer))
+
+(defun sieve-activate (&optional pos)
+  (interactive "d")
+  (let ((name (sieve-script-at-point)) err)
+    (when (or (null name) (string-equal name sieve-new-script))
+      (error "No sieve script at point"))
+    (message "Activating script %s..." name)
+    (setq err (sieve-manage-setactive name sieve-manage-buffer))
+    (sieve-refresh-scriptlist)
+    (if (sieve-manage-ok-p err)
+       (message "Activating script %s...done" name)
+      (message "Activating script %s...failed: %s" name (nth 2 err)))))
+
+(defun sieve-deactivate-all (&optional pos)
+  (interactive "d")
+  (let ((name (sieve-script-at-point)) err)
+    (message "Deactivating scripts...")
+    (setq err (sieve-manage-setactive "" sieve-manage-buffer))
+    (sieve-refresh-scriptlist)
+    (if (sieve-manage-ok-p err)
+       (message "Deactivating scripts...done")
+      (message "Deactivating scripts...failed: %s" (nth 2 err)))))
+
+(defalias 'sieve-deactivate 'sieve-deactivate-all)
+
+(defun sieve-remove (&optional pos)
+  (interactive "d")
+  (let ((name (sieve-script-at-point)) err)
+    (when (or (null name) (string-equal name sieve-new-script))
+      (error "No sieve script at point"))
+    (message "Removing sieve script %s..." name)
+    (setq err (sieve-manage-deletescript name sieve-manage-buffer))
+    (unless (sieve-manage-ok-p err)
+      (error "Removing sieve script %s...failed: " err))
+    (sieve-refresh-scriptlist)
+    (message "Removing sieve script %s...done" name)))
+
+(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)
+    (setq sieve-buffer-script-name name)
+    (goto-char (point-min))
+    (message
+     (substitute-command-keys
+      "Press \\[sieve-upload] to upload script to server."))))
+
+(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)
+
+(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 "%s" (substitute-command-keys
+             "`\\[sieve-edit-script]':edit `\\[sieve-activate]':activate `\\[sieve-deactivate]':deactivate `\\[sieve-remove]':remove"))))
+
+;; Create buffer:
+
+(defun sieve-setup-buffer (server port)
+  (setq buffer-read-only nil)
+  (erase-buffer)
+  (buffer-disable-undo)
+  (let* ((port (or port sieve-manage-default-port))
+         (header (format "Server : %s:%s\n\n" server port)))
+    (insert header))
+  (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))
+
+(defun sieve-highlight (on)
+  "Turn ON or off highlighting on the current language overlay."
+  (overlay-put (car (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 (make-overlay p (point)))
+      (overlay-put ext 'mouse-face 'highlight)
+      (overlay-put ext 'script-name (if (consp script)
+                                       (cdr script)
+                                     script))
+      (insert "\n"))))
+
+(defun sieve-open-server (server &optional port)
+  "Open SERVER (on PORT) and authenticate."
+  (with-current-buffer
+      (or ;; open server
+       (set (make-local-variable 'sieve-manage-buffer)
+           (sieve-manage-open server port))
+       (error "Error opening server %s" server))
+    (sieve-manage-authenticate)))
+
+(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
+           (substitute-command-keys
+            (format
+             "No scripts on server, press \\[sieve-edit-script] on %s to create a new script.\n"
+             sieve-new-script)))
+       (insert
+         (substitute-command-keys
+          (format (concat "%d script%s on server, press \\[sieve-edit-script] on a script "
+                          "name edits it, or\npress \\[sieve-edit-script] 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)
+  (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
+                   (or name sieve-buffer-script-name (buffer-name))
+                   script sieve-manage-buffer))
+       (if (sieve-manage-ok-p err)
+           (message (substitute-command-keys
+                     "Sieve upload done.  Use \\[sieve-manage] to manage scripts."))
+         (message "Sieve upload failed: %s" (nth 2 err)))))))
+
+;;;###autoload
+(defun sieve-upload-and-bury (&optional name)
+  (interactive)
+  (sieve-upload name)
+  (bury-buffer))
+
+;;;###autoload
+(defun sieve-upload-and-kill (&optional name)
+  (interactive)
+  (sieve-upload name)
+  (kill-buffer))
+
+(provide 'sieve)
+
+;; sieve.el ends here
diff --git a/xemacs-packages/gnus/lisp/smiley.el b/xemacs-packages/gnus/lisp/smiley.el
new file mode 100644 (file)
index 0000000..ac19799
--- /dev/null
@@ -0,0 +1,357 @@
+;;; smiley.el --- displaying smiley faces
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
+
+;; Author: Wes Hardaker <hardaker@ece.ucdavis.edu>
+;; Keywords: fun
+
+;; 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:
+
+;;
+;; comments go here.
+;;
+
+;;; Test smileys:  :-] :-o :-) ;-) :-\ :-| :-d :-P 8-| :-(
+
+;; To use:
+;; (require 'smiley)
+;; (setq gnus-treat-display-smileys t)
+
+;; The smilies were drawn by Joe Reiss <jreiss@vt.edu>.
+
+(require 'cl)
+(require 'custom)
+
+(eval-and-compile
+  (when (featurep 'xemacs)
+    (require 'annotations)
+    (require 'messagexmas)))
+
+(defgroup smiley nil
+  "Turn :-)'s into real images."
+  :group 'gnus-visual)
+
+;; FIXME: Where is the directory when using Emacs?
+(defcustom smiley-data-directory 
+  (if (featurep 'xemacs)
+    (message-xmas-find-glyph-directory "smilies")
+    "/usr/local/lib/xemacs/xemacs-packages/etc/smilies")
+  "*Location of the smiley faces files."
+  :type 'directory
+  :group 'smiley)
+
+;; Notice the subtle differences in the regular expressions in the
+;; two alists below.
+
+(defcustom smiley-deformed-regexp-alist
+  '(("\\(\\^_?\\^;;;\\)\\W" 1 "WideFaceAse3.xbm")
+    ("\\(\\^_?\\^;;\\)\\W" 1 "WideFaceAse2.xbm")
+    ("\\(\\^_?\\^;\\)\\W" 1 "WideFaceAse1.xbm")
+    ("\\(\\^_?\\^\\)\\W" 1 "WideFaceSmile.xbm")
+    ("\\(;_;\\)\\W" 1 "WideFaceWeep.xbm")
+    ("\\(T_T\\)\\W" 1 "WideFaceWeep.xbm")
+    ("\\(:-*[<«]+\\)\\W" 1 "FaceAngry.xpm")
+    ("\\(:-+\\]+\\)\\W" 1 "FaceGoofy.xpm")
+    ("\\(:-*D\\)\\W" 1 "FaceGrinning.xpm")
+    ("\\(:-*[)>}»]+\\)\\W" 1 "FaceHappy.xpm")
+    ("\\(=[)»]+\\)\\W" 1 "FaceHappy.xpm")
+    ("\\(:-*[/\\\"]\\)[^/]\\W" 1 "FaceIronic.xpm")
+    ("[^.0-9]\\([8|]-*[|Oo%]\\)\\W" 1 "FaceKOed.xpm")
+    ("\\([:|]-*#+\\)\\W" 1 "FaceNyah.xpm")
+    ("\\(:-*[({]+\\)\\W" 1 "FaceSad.xpm")
+    ("\\(=[({]+\\)\\W" 1 "FaceSad.xpm")
+    ("\\(:-*[Oo\*]\\)\\W" 1 "FaceStartled.xpm")
+    ("\\(:-*|\\)\\W" 1 "FaceStraight.xpm")
+    ("\\(:-*p\\)\\W" 1 "FaceTalking.xpm")
+    ("\\(:-*d\\)\\W" 1 "FaceTasty.xpm")
+    ("\\(;-*[>)}»]+\\)\\W" 1 "FaceWinking.xpm")
+    ("\\(:-*[Vvµ]\\)\\W" 1 "FaceWry.xpm")
+    ("\\([:|]-*P\\)\\W" 1 "FaceYukky.xpm"))
+  "*Normal and deformed faces for smilies."
+  :type '(repeat (list regexp
+                      (integer :tag "Match")
+                      (string :tag "Image")))
+  :group 'smiley)
+
+(defcustom smiley-nosey-regexp-alist
+  '(("\\(:-+[<«]+\\)\\W" 1 "FaceAngry.xpm")
+    ("\\(:-+\\]+\\)\\W" 1 "FaceGoofy.xpm")
+    ("\\(:-+D\\)\\W" 1 "FaceGrinning.xpm")
+    ("\\(:-+[}»]+\\)\\W" 1 "FaceHappy.xpm")
+    ("\\(:-*)+\\)\\W" 1 "FaceHappy.xpm")
+    ("\\(=[)]+\\)\\W" 1 "FaceHappy.xpm")
+    ("\\(:-+[/\\\"]+\\)\\W" 1 "FaceIronic.xpm")
+    ("\\([8|]-+[|Oo%]\\)\\W" 1 "FaceKOed.xpm")
+    ("\\([:|]-+#+\\)\\W" 1 "FaceNyah.xpm")
+    ("\\(:-+[({]+\\)\\W" 1 "FaceSad.xpm")
+    ("\\(=[({]+\\)\\W" 1 "FaceSad.xpm")
+    ("\\(:-+[Oo\*]\\)\\W" 1 "FaceStartled.xpm")
+    ("\\(:-+|\\)\\W" 1 "FaceStraight.xpm")
+    ("\\(:-+p\\)\\W" 1 "FaceTalking.xpm")
+    ("\\(:-+d\\)\\W" 1 "FaceTasty.xpm")
+    ("\\(;-+[>)}»]+\\)\\W" 1 "FaceWinking.xpm")
+    ("\\(:-+[Vvµ]\\)\\W" 1 "FaceWry.xpm")
+    ("\\(][:8B]-[)>]\\)\\W" 1 "FaceDevilish.xpm")
+    ("\\([:|]-+P\\)\\W" 1 "FaceYukky.xpm"))
+  "*Smileys with noses.  These get less false matches."
+  :type '(repeat (list regexp
+                      (integer :tag "Match")
+                      (string :tag "Image")))
+  :group 'smiley)
+
+(defcustom smiley-regexp-alist smiley-deformed-regexp-alist
+  "*A list of regexps to map smilies to real images.
+Defaults to the contents of `smiley-deformed-regexp-alist'.
+An alternative is `smiley-nosey-regexp-alist' that matches less
+aggressively.
+If this is a symbol, take its value."
+  :type '(radio (variable-item smiley-deformed-regexp-alist)
+               (variable-item smiley-nosey-regexp-alist)
+               symbol
+               (repeat (list regexp
+                             (integer :tag "Match")
+                             (string :tag "Image"))))
+  :group 'smiley)
+
+(defcustom smiley-flesh-color "yellow"
+  "*Flesh color."
+  :type 'string
+  :group 'smiley)
+
+(defcustom smiley-features-color "black"
+  "*Features color."
+  :type 'string
+  :group 'smiley)
+
+(defcustom smiley-tongue-color "red"
+  "*Tongue color."
+  :type 'string
+  :group 'smiley)
+
+(defcustom smiley-circle-color "black"
+  "*Circle color."
+  :type 'string
+  :group 'smiley)
+
+(defcustom smiley-mouse-face 'highlight
+  "*Face used for mouse highlighting in the smiley buffer.
+
+Smiley buttons will be displayed in this face when the cursor is
+above them."
+  :type 'face
+  :group 'smiley)
+
+(defvar smiley-glyph-cache nil)
+
+(defvar smiley-map (make-sparse-keymap "smiley-keys")
+  "Keymap to toggle smiley states.")
+
+(define-key smiley-map [(button2)] 'smiley-toggle-extent)
+(define-key smiley-map [(button3)] 'smiley-popup-menu)
+
+(defun smiley-popup-menu (e)
+  (interactive "e")
+  (popup-menu
+   `("Smilies"
+     ["Toggle This Smiley" (smiley-toggle-extent ,e) t]
+     ["Toggle All Smilies" (smiley-toggle-extents ,e) t])))
+
+(defun smiley-create-glyph (smiley pixmap)
+  (or
+   (cdr-safe (assoc pixmap smiley-glyph-cache))
+   (let* ((xpm-color-symbols
+          (and (featurep 'xpm)
+               (append `(("flesh" ,smiley-flesh-color)
+                         ("features" ,smiley-features-color)
+                         ("tongue" ,smiley-tongue-color))
+                       xpm-color-symbols)))
+         (glyph (make-glyph
+                 (list
+                  (cons (if (featurep 'gtk) 'gtk 'x)
+                        (expand-file-name pixmap smiley-data-directory))
+                  (cons 'mswindows
+                        (expand-file-name pixmap smiley-data-directory))
+                  (cons 'tty smiley)))))
+     (setq smiley-glyph-cache (cons (cons pixmap glyph) smiley-glyph-cache))
+     (set-glyph-face glyph 'default)
+     glyph)))
+
+;;;###autoload
+(defun smiley-region (beg end)
+  "Smilify the region between point and mark."
+  (interactive "r")
+  (smiley-buffer (current-buffer) beg end))
+
+(defun smiley-toggle-extent (event)
+  "Toggle smiley at given point."
+  (interactive "e")
+  (let* ((ant (event-glyph-extent event))
+        (pt (event-closest-point event))
+        ext)
+    (if (annotationp ant)
+       (when (extentp (setq ext (extent-property ant 'smiley-extent)))
+         (set-extent-property ext 'invisible nil)
+         (hide-annotation ant))
+      (when pt
+       (while (setq ext (extent-at pt (event-buffer event) nil ext 'at))
+         (when (annotationp (setq ant
+                                  (extent-property ext 'smiley-annotation)))
+           (reveal-annotation ant)
+           (set-extent-property ext 'invisible t)))))))
+
+(defun smiley-toggle-extents (e)
+  (interactive "e")
+  (map-extents
+   (lambda (e void)
+     (let (ant)
+       (if (annotationp (setq ant (extent-property e 'smiley-annotation)))
+          (if (eq (extent-property e 'invisible) nil)
+              (progn
+                (reveal-annotation ant)
+                (set-extent-property e 'invisible t)
+                )
+            (hide-annotation ant)
+            (set-extent-property e 'invisible nil)))
+       nil))
+   (event-buffer e)))
+
+;;;###autoload
+(defun smiley-buffer (&optional buffer st nd)
+  (interactive)
+  (when (featurep '(or x gtk mswindows))
+    (save-excursion
+      (when buffer
+       (set-buffer buffer))
+      (let ((buffer-read-only nil)
+           (alist (if (symbolp smiley-regexp-alist)
+                      (symbol-value smiley-regexp-alist)
+                    smiley-regexp-alist))
+           (case-fold-search nil)
+           entry regexp beg group file)
+       (map-extents
+        (lambda (e void)
+          (when (or (extent-property e 'smiley-extent)
+                    (extent-property e 'smiley-annotation))
+            (delete-extent e)))
+        buffer st nd)
+       (goto-char (or st (point-min)))
+       (setq beg (point))
+       ;; loop through alist
+       (while (setq entry (pop alist))
+         (setq regexp (car entry)
+               group (cadr entry)
+               file (caddr entry))
+         (goto-char beg)
+         (while (re-search-forward regexp nd t)
+           (let* ((start (match-beginning group))
+                  (end (match-end group))
+                  (glyph (smiley-create-glyph (buffer-substring start end)
+                                              file)))
+             (when glyph
+               (mapcar 'delete-annotation (annotations-at end))
+               (let ((ext (make-extent start end))
+                     (ant (make-annotation glyph end 'text)))
+                 ;; set text extent params
+                 (set-extent-property ext 'end-open t)
+                 (set-extent-property ext 'start-open t)
+                 (set-extent-property ext 'invisible t)
+                 (set-extent-property ext 'keymap smiley-map)
+                 (set-extent-property ext 'mouse-face smiley-mouse-face)
+                 (set-extent-property ext 'intangible t)
+                 ;; set annotation params
+                 (set-extent-property ant 'mouse-face smiley-mouse-face)
+                 (set-extent-property ant 'keymap smiley-map)
+                 ;; remember each other
+                 (set-extent-property ant 'smiley-extent ext)
+                 (set-extent-property ext 'smiley-annotation ant)
+                 ;; Help
+                 (set-extent-property
+                  ext 'help-echo
+                  "button2 toggles smiley, button3 pops up menu")
+                 (set-extent-property
+                  ant 'help-echo
+                  "button2 toggles smiley, button3 pops up menu")
+                 (set-extent-property ext 'balloon-help
+                                      "Mouse button2 - toggle smiley
+Mouse button3 - menu")
+                 (set-extent-property ant 'balloon-help
+                                      "Mouse button2 - toggle smiley
+Mouse button3 - menu"))
+               (when (smiley-end-paren-p start end)
+                 (make-annotation ")" end 'text))
+               (goto-char end)))))))))
+
+(defun smiley-end-paren-p (start end)
+  "Try to guess whether the current smiley is an end-paren smiley."
+  (save-excursion
+    (goto-char start)
+    (when (and (re-search-backward "[()]" nil t)
+              (eq (char-after) ?\()
+              (goto-char end)
+              (or (not (re-search-forward "[()]" nil t))
+                  (eq (char-after (1- (point))) ?\()))
+      t)))
+
+(defun smiley-toggle-buffer (&optional arg buffer st nd)
+  "Toggle displaying smiley faces.
+With arg, turn displaying on if and only if arg is positive."
+  (interactive "P")
+  (let (on off)
+    (map-extents
+     (lambda (e void)
+       (let (ant)
+        (if (annotationp (setq ant (extent-property e 'smiley-annotation)))
+            (if (eq (extent-property e 'invisible) nil)
+                (setq off (cons (cons ant e) off))
+              (setq on (cons (cons ant e) on)))))
+       nil)
+     buffer st nd)
+    (if (and (not (and (numberp arg) (< arg 0)))
+            (or (and (numberp arg) (> arg 0))
+                (null on)))
+       (if off
+           (while off
+             (reveal-annotation (caar off))
+             (set-extent-property (cdar off) 'invisible t)
+             (setq off (cdr off)))
+         (smiley-buffer))
+      (while on
+       (hide-annotation (caar on))
+       (set-extent-property (cdar on) 'invisible nil)
+       (setq on (cdr on))))))
+
+(defvar gnus-article-buffer)
+;;;###autoload
+(defun gnus-smiley-display (&optional arg)
+  "Display \"smileys\" as small graphical icons.
+With arg, turn displaying on if and only if arg is positive."
+  (interactive "P")
+  (save-excursion
+    (article-goto-body)
+    (let (buffer-read-only)
+      (smiley-toggle-buffer arg (current-buffer) (point) (point-max)))))
+
+(provide 'smiley)
+
+;; Local Variables:
+;; coding: iso-8859-1
+;; End:
+
+;;; smiley.el ends here
diff --git a/xemacs-packages/gnus/lisp/smime-ldap.el b/xemacs-packages/gnus/lisp/smime-ldap.el
new file mode 100644 (file)
index 0000000..66ae9c5
--- /dev/null
@@ -0,0 +1,181 @@
+;;; smime-ldap.el --- client interface to LDAP for Emacs
+
+;; Copyright (C) 1998, 1999, 2000, 2005 Free Software Foundation, Inc.
+
+;; Author: Oscar Figueiredo <Oscar.Figueiredo@di.epfl.ch>
+;; Maintainer: Arne J\e,Ax\e(Brgensen <arne@arnested.dk>
+;; Created: February 2005
+;; Keywords: comm
+
+;; 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 3, 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.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This file has a slightly changed implementation of Emacs 21.3's
+;; ldap-search and ldap-search-internal from ldap.el. The changes are
+;; made to achieve compatibility with OpenLDAP v2 and to make it
+;; possible to retrieve LDAP attributes that are tagged ie ";binary".
+
+;; The file also adds a compatibility layer for Emacs and XEmacs.
+
+;;; Code:
+
+(require 'ldap)
+
+(defun smime-ldap-search (filter &optional host attributes attrsonly withdn)
+  "Perform an LDAP search.
+FILTER is the search filter in RFC1558 syntax.
+HOST is the LDAP host on which to perform the search.
+ATTRIBUTES are the specific attributes to retrieve, nil means
+retrieve all.
+ATTRSONLY, if non-nil, retrieves the attributes only, without
+the associated values.
+If WITHDN is non-nil, each entry in the result will be prepended with
+its distinguished name WITHDN.
+Additional search parameters can be specified through
+`ldap-host-parameters-alist', which see."
+  (interactive "sFilter:")
+  ;; for XEmacs
+  (if (fboundp 'ldap-search-entries)
+      (ldap-search-entries filter host attributes attrsonly)
+    ;; for Emacs
+    (cdr (ldap-search filter host attributes attrsonly))))
+
+(defun smime-ldap-search-internal (search-plist)
+  "Perform a search on a LDAP server.
+SEARCH-PLIST is a property list describing the search request.
+Valid keys in that list are:
+`host' is a string naming one or more (blank-separated) LDAP servers to
+to try to connect to.  Each host name may optionally be of the form HOST:PORT.
+`filter' is a filter string for the search as described in RFC 1558.
+`attributes' is a list of strings indicating which attributes to retrieve
+for each matching entry. If nil, return all available attributes.
+`attrsonly', if non-nil, indicates that only attributes are retrieved,
+not their associated values.
+`base' is the base for the search as described in RFC 1779.
+`scope' is one of the three symbols `sub', `base' or `one'.
+`binddn' is the distinguished name of the user to bind as (in RFC 1779 syntax).
+`passwd' is the password to use for simple authentication.
+`deref' is one of the symbols `never', `always', `search' or `find'.
+`timelimit' is the timeout limit for the connection in seconds.
+`sizelimit' is the maximum number of matches to return.
+`withdn' if non-nil each entry in the result will be prepended with
+its distinguished name DN.
+The function returns a list of matching entries.  Each entry is itself
+an alist of attribute/value pairs."
+  (let ((buf (get-buffer-create " *ldap-search*"))
+       (bufval (get-buffer-create " *ldap-value*"))
+       (host (or (plist-get search-plist 'host)
+                 ldap-default-host))
+       (filter (plist-get search-plist 'filter))
+       (attributes (plist-get search-plist 'attributes))
+       (attrsonly (plist-get search-plist 'attrsonly))
+       (base (or (plist-get search-plist 'base)
+                 ldap-default-base))
+       (scope (plist-get search-plist 'scope))
+       (binddn (plist-get search-plist 'binddn))
+       (passwd (plist-get search-plist 'passwd))
+       (deref (plist-get search-plist 'deref))
+       (timelimit (plist-get search-plist 'timelimit))
+       (sizelimit (plist-get search-plist 'sizelimit))
+       (withdn (plist-get search-plist 'withdn))
+       (numres 0)
+       arglist dn name value record result)
+    (if (or (null filter)
+           (equal "" filter))
+       (error "No search filter"))
+    (setq filter (cons filter attributes))
+    (with-current-buffer buf
+      (erase-buffer)
+      (if (and host
+              (not (equal "" host)))
+         (setq arglist (nconc arglist (list (format "-h%s" host)))))
+      (if (and attrsonly
+              (not (equal "" attrsonly)))
+         (setq arglist (nconc arglist (list "-A"))))
+      (if (and base
+              (not (equal "" base)))
+         (setq arglist (nconc arglist (list (format "-b%s" base)))))
+      (if (and scope
+              (not (equal "" scope)))
+         (setq arglist (nconc arglist (list (format "-s%s" scope)))))
+      (if (and binddn
+              (not (equal "" binddn)))
+         (setq arglist (nconc arglist (list (format "-D%s" binddn)))))
+      (if (and passwd
+              (not (equal "" passwd)))
+         (setq arglist (nconc arglist (list (format "-w%s" passwd)))))
+      (if (and deref
+              (not (equal "" deref)))
+         (setq arglist (nconc arglist (list (format "-a%s" deref)))))
+      (if (and timelimit
+              (not (equal "" timelimit)))
+         (setq arglist (nconc arglist (list (format "-l%s" timelimit)))))
+      (if (and sizelimit
+              (not (equal "" sizelimit)))
+         (setq arglist (nconc arglist (list (format "-z%s" sizelimit)))))
+      (eval `(call-process ldap-ldapsearch-prog
+                          nil
+                          buf
+                          nil
+                          ,@arglist
+                          "-tt"                ; Write values to temp files
+                          "-x"
+                          "-LL"
+                          ;                       ,@ldap-ldapsearch-args
+                          ,@filter))
+      (insert "\n")
+      (goto-char (point-min))
+
+      (while (re-search-forward "[\t\n\f]+ " nil t)
+       (replace-match "" nil nil))
+      (goto-char (point-min))
+
+      (if (looking-at "usage")
+         (error "Incorrect ldapsearch invocation")
+       (message "Parsing results... ")
+       (while (progn
+                (skip-chars-forward " \t\n")
+                (not (eobp)))
+         (setq dn (buffer-substring (point) (save-excursion
+                                              (end-of-line)
+                                              (point))))
+         (forward-line 1)
+         (while (looking-at (concat "^\\(\\w*\\)\\(;\\w*\\)?[=:\t ]+"
+                                    "\\(<[\t ]*file://\\)?\\(.*\\)$"))
+           (setq name (match-string 1)
+                 value (match-string 4))
+           (with-current-buffer bufval
+             (erase-buffer)
+             (insert-file-contents-literally value)
+             (delete-file value)
+             (setq value (buffer-substring (point-min) (point-max))))
+           (setq record (cons (list name value)
+                              record))
+           (forward-line 1))
+         (setq result (cons (if withdn
+                                (cons dn (nreverse record))
+                              (nreverse record)) result))
+         (setq record nil)
+         (skip-chars-forward " \t\n")
+         (message "Parsing results... %d" numres)
+         (1+ numres))
+       (message "Parsing results... done")
+       (nreverse result)))))
+
+(provide 'smime-ldap)
+
+;;; smime-ldap.el ends here
diff --git a/xemacs-packages/gnus/lisp/smime.el b/xemacs-packages/gnus/lisp/smime.el
new file mode 100644 (file)
index 0000000..d1077a9
--- /dev/null
@@ -0,0 +1,716 @@
+;;; smime.el --- S/MIME support library
+
+;; Copyright (C) 2000-2016 Free Software Foundation, Inc.
+
+;; Author: Simon Josefsson <simon@josefsson.org>
+;; Keywords: SMIME X.509 PEM OpenSSL
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This library perform S/MIME operations from within Emacs.
+;;
+;; Functions for fetching certificates from public repositories are
+;; provided, currently from DNS and LDAP.
+;;
+;; It uses OpenSSL (tested with version 0.9.5a and 0.9.6) for signing,
+;; encryption and decryption.
+;;
+;; Some general knowledge of S/MIME, X.509, PKCS#12, PEM etc is
+;; probably required to use this library in any useful way.
+;; Especially, don't expect this library to buy security for you.  If
+;; you don't understand what you are doing, you're as likely to lose
+;; security than gain any by using this library.
+;;
+;; This library is not intended to provide a "raw" API for S/MIME,
+;; 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, but also available from
+;; http://josefsson.org/smime.html.
+
+;;; Quick introduction:
+
+;; Get your S/MIME certificate from VeriSign or someplace.  I used
+;; Netscape to generate the key and certificate request and stuff, and
+;; Netscape can export the key into PKCS#12 format.
+;;
+;; Enter OpenSSL.  To be able to use this library, it need to have the
+;; SMIME key readable in PEM format.  OpenSSL is used to convert the
+;; key:
+;;
+;; $ openssl pkcs12 -in mykey.p12 -clcerts -nodes > mykey.pem
+;; ...
+;;
+;; Now, use M-x customize-variable smime-keys and add mykey.pem as
+;; a key.
+;;
+;; Now you should be able to sign messages!  Create a buffer and write
+;; something and run M-x smime-sign-buffer RET RET and you should see
+;; your message MIME armored and a signature.  Encryption, M-x
+;; smime-encrypt-buffer, should also work.
+;;
+;; To be able to verify messages you need to build up trust with
+;; someone.  Perhaps you trust the CA that issued your certificate, at
+;; least I did, so I export it's certificates from my PKCS#12
+;; certificate with:
+;;
+;; $ openssl pkcs12 -in mykey.p12 -cacerts -nodes > cacert.pem
+;; ...
+;;
+;; Now, use M-x customize-variable smime-CAs and add cacert.pem as a
+;; CA certificate.
+;;
+;; You should now be able to sign messages, and even verify messages
+;; sent by others that use the same CA as you.
+
+;; Bugs:
+;;
+;; Don't complain that this package doesn't do encrypted PEM files,
+;; submit a patch instead.  I store my keys in a safe place, so I
+;; didn't need the encryption.  Also, programming was made easier by
+;; that decision.  One might think that this even influenced were I
+;; store my keys, and one would probably be right. :-)
+;;
+;; Update: Mathias Herberts sent the patch.  However, it uses
+;; 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
+;; don't want to recommend them.
+;;
+;; Why can't someone write a simple introduction to all this stuff?
+;; Until then, much of this resemble security by obscurity.
+;;
+;; Also, I'm not going to mention anything about the wonders of
+;; cryptopolitics.  Oops, I just did.
+;;
+;; end rant
+
+;;; Revision history:
+
+;; 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
+;; 2005-02-13  retrieve certificates via LDAP
+
+;;; Code:
+
+(require 'dig)
+
+(if (locate-library "password-cache")
+    (require 'password-cache)
+  (require 'password))
+
+(eval-when-compile (require 'cl))
+
+(eval-and-compile
+  (cond
+   ((fboundp 'replace-in-string)
+    (defalias 'smime-replace-in-string 'replace-in-string))
+   ((fboundp 'replace-regexp-in-string)
+    (defun smime-replace-in-string  (string regexp newtext &optional literal)
+      "Replace all matches for REGEXP with NEWTEXT in STRING.
+If LITERAL is non-nil, insert NEWTEXT literally.  Return a new
+string containing the replacements.
+
+This is a compatibility function for different Emacsen."
+      (replace-regexp-in-string regexp newtext string nil literal)))))
+
+(defgroup smime nil
+  "S/MIME configuration."
+  :group 'mime)
+
+(defcustom smime-keys nil
+  "*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")
+                      (repeat :tag "Additional certificate files"
+                              (file :tag "File name"))))
+  :group 'smime)
+
+(defcustom smime-CA-directory nil
+  "*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:
+
+$ ln -s ca.pem \\=`openssl x509 -noout -hash -in ca.pem\\=`.0
+
+where `ca.pem' is the file containing a PEM encoded X.509 CA
+certificate."
+  :type '(choice (const :tag "none" nil)
+                directory)
+  :group 'smime)
+
+(defcustom smime-CA-file nil
+  "*Files containing certificates for CAs you trust.
+File should contain certificates in PEM format."
+  :version "22.1"
+  :type '(choice (const :tag "none" nil)
+                file)
+  :group 'smime)
+
+(defcustom smime-certificate-directory "~/Mail/certs/"
+  "*Directory containing other people's certificates.
+It should contain files named to the X.509 hash of the certificate,
+and the files themselves should be in PEM format."
+;The S/MIME library provide simple functionality for fetching
+;certificates into this directory, so there is no need to populate it
+;manually.
+  :type 'directory
+  :group 'smime)
+
+(defcustom smime-openssl-program
+  (and (condition-case ()
+          (eq 0 (call-process "openssl" nil nil nil "version"))
+        (error nil))
+       "openssl")
+  "*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."
+  :version "22.1"
+  :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-crl-check nil
+  "*Check revocation status of signers certificate using CRLs.
+Enabling this will have OpenSSL check the signers certificate
+against a certificate revocation list (CRL).
+
+For this to work the CRL must be up-to-date and since they are
+normally updated quite often (i.e., several times a day) you
+probably need some tool to keep them up-to-date. Unfortunately
+Gnus cannot do this for you.
+
+The CRL should either be appended (in PEM format) to your
+`smime-CA-file' or be located in a file (also in PEM format) in
+your `smime-certificate-directory' named to the X.509 hash of the
+certificate with .r0 as file name extension.
+
+At least OpenSSL version 0.9.7 is required for this to work."
+  :type '(choice (const :tag "No check" nil)
+                (const :tag "Check certificate" "-crl_check")
+                (const :tag "Check certificate chain" "-crl_check_all"))
+  :group 'smime)
+
+(defcustom smime-dns-server nil
+  "*DNS server to query certificates from.
+If nil, use system defaults."
+  :version "22.1"
+  :type '(choice (const :tag "System defaults")
+                string)
+  :group 'smime)
+
+(defcustom smime-ldap-host-list nil
+  "A list of LDAP hosts with S/MIME user certificates.
+If needed search base, binddn, passwd, etc. for the LDAP host
+must be set in `ldap-host-parameters-alist'."
+  :type '(repeat (string :tag "Host name"))
+  :version "23.1" ;; No Gnus
+  :group 'smime)
+
+(defvar smime-details-buffer "*OpenSSL output*")
+
+;; Use mm-util?
+(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)
+        (if (fboundp 'temp-directory)
+            (temp-directory)
+          temporary-file-directory))))))
+
+;; Password dialog function
+(declare-function password-read-and-add "password-cache" (prompt &optional key))
+
+(defun smime-ask-passphrase (&optional cache-key)
+  "Asks the passphrase to unlock the secret key.
+If `cache-key' and `password-cache' is non-nil then cache the
+password under `cache-key'."
+  (let ((passphrase
+        (password-read-and-add
+         "Passphrase for secret key (RET for no passphrase): " cache-key)))
+    (if (string= passphrase "")
+       nil
+      passphrase)))
+
+;; OpenSSL wrappers.
+
+(defun smime-call-openssl-region (b e buf &rest args)
+  (case (apply 'call-process-region b e smime-openssl-program nil buf nil args)
+    (0 t)
+    (1 (message "OpenSSL: An error occurred parsing the command options.") nil)
+    (2 (message "OpenSSL: One of the input files could not be read.") nil)
+    (3 (message "OpenSSL: An error occurred creating the PKCS#7 file or when reading the MIME message.") nil)
+    (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.
+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 as its car, and a list of additional
+certificates to include in its caar.  If no additional certificates is
+included, KEYFILE may be the file containing the PEM encoded private
+key and certificate itself."
+  (smime-new-details-buffer)
+  (let* ((certfiles (and (cdr-safe keyfile) (cadr keyfile)))
+        (keyfile (or (car-safe keyfile) keyfile))
+        (buffer (generate-new-buffer " *smime*"))
+        (passphrase (smime-ask-passphrase (expand-file-name keyfile)))
+        (tmpfile (smime-make-temp-file "smime")))
+    (if passphrase
+       (setenv "GNUS_SMIME_PASSPHRASE" passphrase))
+    (prog1
+       (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-substring buffer)
+         (goto-char b)
+         (when (looking-at "^MIME-Version: 1.0$")
+           (delete-region (point) (progn (forward-line 1) (point))))
+         t)
+      (with-current-buffer smime-details-buffer
+       (goto-char (point-max))
+       (insert-buffer-substring buffer))
+      (kill-buffer buffer))))
+
+(defun smime-encrypt-region (b e certfiles)
+  "Encrypt region for recipients specified in CERTFILES.
+If encryption fails, the buffer is not modified.  Region is assumed to
+have proper MIME tags.  CERTFILES is a list of filenames, each file
+is expected to contain of a PEM encoded certificate."
+  (smime-new-details-buffer)
+  (let ((buffer (generate-new-buffer " *smime*"))
+       (tmpfile (smime-make-temp-file "smime")))
+    (prog1
+       (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-substring buffer)
+         (goto-char b)
+         (when (looking-at "^MIME-Version: 1.0$")
+           (delete-region (point) (progn (forward-line 1) (point))))
+         t)
+      (with-current-buffer smime-details-buffer
+       (goto-char (point-max))
+       (insert-buffer-substring buffer))
+      (kill-buffer buffer))))
+
+;; Sign+encrypt buffer
+
+(defun smime-sign-buffer (&optional keyfile buffer)
+  "S/MIME sign BUFFER with key in KEYFILE.
+KEYFILE should contain a PEM encoded key and certificate."
+  (interactive)
+  (with-current-buffer (or buffer (current-buffer))
+    (unless (smime-sign-region
+            (point-min) (point-max)
+            (if keyfile
+                keyfile
+              (smime-get-key-with-certs-by-email
+               (gnus-completing-read
+                "Sign using key"
+                smime-keys nil (car-safe (car-safe smime-keys))))))
+      (error "Signing failed"))))
+
+(defun smime-encrypt-buffer (&optional certfiles buffer)
+  "S/MIME encrypt BUFFER for recipients specified in CERTFILES.
+CERTFILES is a list of filenames, each file is expected to consist of
+a PEM encoded key and certificate.  Uses current buffer if BUFFER is
+nil."
+  (interactive)
+  (with-current-buffer (or buffer (current-buffer))
+    (unless (smime-encrypt-region
+            (point-min) (point-max)
+            (or certfiles
+                (list (read-file-name "Recipient's S/MIME certificate: "
+                                      smime-certificate-directory nil))))
+      (error "Encryption failed"))))
+
+;; Verify+decrypt region
+
+(defun smime-verify-region (b e)
+  "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 smime-crl-check
+       (add-to-list 'CAs smime-crl-check))
+    (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)
+  "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 &optional from)
+  "Decrypt S/MIME message in region between B and E with key in KEYFILE.
+Optional FROM specifies sender's mail address.
+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 " *smime*"))
+       CAs (passphrase (smime-ask-passphrase (expand-file-name keyfile)))
+       (tmpfile (smime-make-temp-file "smime")))
+    (if passphrase
+       (setenv "GNUS_SMIME_PASSPHRASE" passphrase))
+    (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)
+         (when from
+           (insert "From: " from "\n"))
+         (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. 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.
+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, 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
+     (point-min) (point-max)
+     (expand-file-name
+      (or keyfile
+         (smime-get-key-by-email
+          (gnus-completing-read
+           "Decipher using key"
+           smime-keys nil (car-safe (car-safe smime-keys)))))))))
+
+;; 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."
+  (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."
+  (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."
+  (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)))))
+
+(defun smime-buffer-as-string-region (b e)
+  "Return each line in region between B and E as a list of strings."
+  (save-excursion
+    (goto-char b)
+    (let (res)
+      (while (< (point) e)
+       (let ((str (buffer-substring (point) (point-at-eol))))
+         (unless (string= "" str)
+           (push str res)))
+       (forward-line))
+      res)))
+
+;; Find certificates
+
+(defun smime-mail-to-domain (mailaddr)
+  (if (string-match "@" mailaddr)
+      (replace-match "." 'fixedcase 'literal mailaddr)
+    mailaddr))
+
+(defun smime-cert-by-dns (mail)
+  "Find certificate via DNS for address MAIL."
+  (let* ((dig-dns-server smime-dns-server)
+        (digbuf (dig-invoke (smime-mail-to-domain mail) "cert" nil nil "+vc"))
+        (retbuf (generate-new-buffer (format "*certificate for %s*" mail)))
+        (certrr (with-current-buffer digbuf
+                  (dig-extract-rr (smime-mail-to-domain mail) "cert")))
+        (cert (and certrr (dig-rr-get-pkix-cert certrr))))
+      (if cert
+         (with-current-buffer retbuf
+           (insert "-----BEGIN CERTIFICATE-----\n")
+           (let ((i 0) (len (length cert)))
+             (while (> (- len 64) i)
+               (insert (substring cert i (+ i 64)) "\n")
+               (setq i (+ i 64)))
+             (insert (substring cert i len) "\n"))
+           (insert "-----END CERTIFICATE-----\n"))
+       (kill-buffer retbuf)
+       (setq retbuf nil))
+      (kill-buffer digbuf)
+      retbuf))
+
+(declare-function ldap-search "ldap"
+                 (filter &optional host attributes attrsonly withdn))
+
+(defun smime-cert-by-ldap-1 (mail host)
+  "Get certificate for MAIL from the ldap server at HOST."
+  (let ((ldapresult
+        (funcall
+         (if (featurep 'xemacs)
+             (progn
+               (require 'smime-ldap)
+               'smime-ldap-search)
+           (progn
+             (require 'ldap)
+             'ldap-search))
+         (concat "mail=" mail)
+         host '("userCertificate") nil))
+       (retbuf (generate-new-buffer (format "*certificate for %s*" mail)))
+       cert)
+    (if (and (>= (length ldapresult) 1)
+             (> (length (cadaar ldapresult)) 0))
+       (with-current-buffer retbuf
+         ;; Certificates on LDAP servers _should_ be in DER format,
+         ;; but there are some servers out there that distributes the
+         ;; certificates in PEM format (with or without
+         ;; header/footer) so we try to handle them anyway.
+         (if (or (string= (substring (cadaar ldapresult) 0 27)
+                          "-----BEGIN CERTIFICATE-----")
+                 (string= (substring (cadaar ldapresult) 0 3)
+                          "MII"))
+             (setq cert
+                   (smime-replace-in-string
+                    (cadaar ldapresult)
+                    (concat "\\(\n\\|\r\\|-----BEGIN CERTIFICATE-----\\|"
+                            "-----END CERTIFICATE-----\\)")
+                    "" t))
+           (setq cert (base64-encode-string (cadaar ldapresult) t)))
+         (insert "-----BEGIN CERTIFICATE-----\n")
+         (let ((i 0) (len (length cert)))
+           (while (> (- len 64) i)
+             (insert (substring cert i (+ i 64)) "\n")
+             (setq i (+ i 64)))
+           (insert (substring cert i len) "\n"))
+         (insert "-----END CERTIFICATE-----\n"))
+      (kill-buffer retbuf)
+      (setq retbuf nil))
+    retbuf))
+
+(defun smime-cert-by-ldap (mail)
+  "Find certificate via LDAP for address MAIL."
+  (if smime-ldap-host-list
+      (catch 'certbuf
+       (dolist (host smime-ldap-host-list)
+         (let ((retbuf (smime-cert-by-ldap-1 mail host)))
+           (when retbuf
+             (throw 'certbuf retbuf)))))))
+
+;; User interface.
+
+(defvar smime-buffer "*SMIME*")
+
+(defvar smime-mode-map
+  (let ((map (make-sparse-keymap)))
+    (suppress-keymap map)
+    (define-key map "q" 'smime-exit)
+    (define-key map "f" 'smime-certificate-info)
+    map))
+
+(autoload 'gnus-completing-read "gnus-util")
+
+(put 'smime-mode 'mode-class 'special)
+(define-derived-mode smime-mode fundamental-mode ;special-mode
+  "SMIME"
+  "Major mode for browsing, viewing and fetching certificates.
+
+All normal editing commands are switched off.
+\\<smime-mode-map>
+
+The following commands are available:
+
+\\{smime-mode-map}"
+  (setq mode-line-process nil)
+  (buffer-disable-undo)
+  (setq truncate-lines t)
+  (setq buffer-read-only t))
+
+(defun smime-certificate-info (certfile)
+  (interactive "fCertificate file: ")
+  (let ((buffer (get-buffer-create (format "*certificate %s*" certfile))))
+    (switch-to-buffer buffer)
+    (erase-buffer)
+    (call-process smime-openssl-program nil buffer 'display
+                 "x509" "-in" (expand-file-name certfile) "-text")
+    (fundamental-mode)
+    (set-buffer-modified-p nil)
+    (setq buffer-read-only t)
+    (goto-char (point-min))))
+
+(defun smime-draw-buffer ()
+  (with-current-buffer smime-buffer
+    (let (buffer-read-only)
+      (erase-buffer)
+      (insert "\nYour keys:\n")
+      (dolist (key smime-keys)
+       (insert
+        (format "\t\t%s: %s\n" (car key) (cadr key))))
+      (insert "\nTrusted Certificate Authorities:\n")
+      (insert "\nKnown Certificates:\n"))))
+
+(defun smime ()
+  "Go to the SMIME buffer."
+  (interactive)
+  (unless (get-buffer smime-buffer)
+    (with-current-buffer (get-buffer-create smime-buffer)
+      (smime-mode)))
+  (smime-draw-buffer)
+  (switch-to-buffer smime-buffer))
+
+(defun smime-exit ()
+  "Quit the S/MIME buffer."
+  (interactive)
+  (kill-buffer (current-buffer)))
+
+;; Other functions
+
+(defun smime-get-key-by-email (email)
+  (cadr (assoc email smime-keys)))
+
+(defun smime-get-key-with-certs-by-email (email)
+  (cdr (assoc email smime-keys)))
+
+(provide 'smime)
+
+;;; smime.el ends here
diff --git a/xemacs-packages/gnus/lisp/spam-report.el b/xemacs-packages/gnus/lisp/spam-report.el
new file mode 100644 (file)
index 0000000..0086dd1
--- /dev/null
@@ -0,0 +1,386 @@
+;;; spam-report.el --- Reporting spam
+
+;; Copyright (C) 2002-2016 Free Software Foundation, Inc.
+
+;; Author: Ted Zlatanov <tzz@lifelogs.com>
+;; Keywords: network, spam, mail, gmane, report
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; This module addresses a few aspects of spam reporting under Gnus.  Page
+;;; breaks are used for grouping declarations and documentation relating to
+;;; each particular aspect.
+
+;;; Code:
+(require 'gnus)
+(require 'gnus-sum)
+
+(autoload 'mm-url-insert "mm-url")
+
+(defgroup spam-report nil
+  "Spam reporting configuration."
+  :group 'mail
+  :group 'news)
+
+(defcustom spam-report-gmane-regex nil
+  "Regexp matching Gmane newsgroups, e.g. \"^nntp\\+.*:gmane\\.\"
+If you are using spam.el, consider setting gnus-spam-process-newsgroups
+or the gnus-group-spam-exit-processor-report-gmane group/topic parameter
+instead."
+  :type '(radio (const nil)
+               (regexp :value "^nntp\\+.*:gmane\\."))
+  :group 'spam-report)
+
+(defcustom spam-report-gmane-use-article-number t
+  "Whether the article number (faster!) or the header should be used.
+
+You must set this to nil if you don't read Gmane groups directly
+from news.gmane.org, e.g. when using local newsserver such as
+leafnode."
+  :type 'boolean
+  :group 'spam-report)
+
+(defcustom spam-report-url-ping-function
+  'spam-report-url-ping-plain
+  "Function to use for url ping spam reporting.
+The function must accept the arguments `host' and `report'."
+  :type '(choice
+         (const :tag "Connect directly"
+                spam-report-url-ping-plain)
+         (const :tag "Use the external program specified in `mm-url-program'"
+                spam-report-url-ping-mm-url)
+         (const :tag "Store request URLs in `spam-report-requests-file'"
+                spam-report-url-to-file)
+         (function :tag "User defined function" nil))
+  :group 'spam-report)
+
+(defcustom spam-report-requests-file
+  (nnheader-concat gnus-directory "spam/" "spam-report-requests.url")
+  ;; Is there a convention for the extension of such a file?
+  ;; Should we use `spam-directory'?
+  "File where spam report request are stored."
+  :type 'file
+  :group 'spam-report)
+
+(defcustom spam-report-resend-to nil
+  "Email address that spam articles are resent to when reporting.
+If not set, the user will be prompted to enter a value which will be
+saved for future use."
+  :type '(choice (const :tag "Prompt" nil) string)
+  :group 'spam-report)
+
+(defvar spam-report-url-ping-temp-agent-function nil
+  "Internal variable for `spam-report-agentize' and `spam-report-deagentize'.
+This variable will store the value of `spam-report-url-ping-function' from
+before `spam-report-agentize' was run, so that `spam-report-deagentize' can
+undo that change.")
+
+(defun spam-report-resend (articles &optional ham)
+  "Report an article as spam by resending via email.
+Reports is as ham when HAM is set."
+  (dolist (article articles)
+    (gnus-message 6
+                 "Reporting %s article %d to <%s>..."
+                 (if ham "ham" "spam")
+                 article spam-report-resend-to)
+    (unless spam-report-resend-to
+      (customize-set-variable
+       spam-report-resend-to
+       (read-from-minibuffer "email address to resend SPAM/HAM to? ")))
+    ;; This is yanked from the `gnus-summary-resend-message' function.
+    ;; It involves rendering the SPAM, which is undesirable, but there does
+    ;; not seem to be a nicer way to achieve this.
+    ;; select this particular article
+    (gnus-summary-select-article nil nil nil article)
+    ;; resend it to the destination address
+    (with-current-buffer gnus-original-article-buffer
+      (message-resend spam-report-resend-to))))
+
+(defun spam-report-resend-ham (articles)
+  "Report an article as ham by resending via email."
+  (spam-report-resend articles t))
+
+(defconst spam-report-gmane-max-requests 4
+  "Number of reports to send before waiting for a response.")
+
+(defvar spam-report-gmane-wait nil
+  "When non-nil, wait until we get a server response.
+This makes sure we don't DOS the host, if many reports are
+submitted at once.  Internal variable.")
+
+(defun spam-report-gmane-ham (&rest articles)
+  "Report ARTICLES as ham (unregister) through Gmane."
+  (interactive (gnus-summary-work-articles current-prefix-arg))
+  (let ((count 0))
+    (dolist (article articles)
+      (setq count (1+ count))
+      (let ((spam-report-gmane-wait
+            (zerop (% count spam-report-gmane-max-requests))))
+       (spam-report-gmane-internal t article)))))
+
+(defun spam-report-gmane-spam (&rest articles)
+  "Report ARTICLES as spam through Gmane."
+  (interactive (gnus-summary-work-articles current-prefix-arg))
+  (let ((count 0))
+    (dolist (article articles)
+      (setq count (1+ count))
+      (let ((spam-report-gmane-wait
+            (zerop (% count spam-report-gmane-max-requests))))
+       (spam-report-gmane-internal nil article)))))
+
+;; `spam-report-gmane' was an interactive entry point, so we should provide an
+;; alias.
+(defalias 'spam-report-gmane 'spam-report-gmane-spam)
+
+(defun spam-report-gmane-internal (unspam article)
+  "Report ARTICLE as spam or not-spam through Gmane, depending on UNSPAM."
+  (when (and gnus-newsgroup-name
+            (or (null spam-report-gmane-regex)
+                (string-match spam-report-gmane-regex gnus-newsgroup-name)))
+    (let ((rpt-host (if unspam "unspam.gmane.org" "spam.gmane.org")))
+      (gnus-message 6 "Reporting article %d to %s..." article rpt-host)
+      (cond
+       ;; Special-case nnweb groups -- these have the URL to use in
+       ;; the Xref headers.
+       ((eq (car (gnus-find-method-for-group gnus-newsgroup-name)) 'nnweb)
+       (spam-report-url-ping
+        rpt-host
+        (concat
+         "/"
+         (gnus-replace-in-string
+          (gnus-replace-in-string
+           (gnus-replace-in-string
+            (mail-header-xref (gnus-summary-article-header article))
+            "/raw" ":silent")
+           "^.*article.gmane.org/" "")
+          "/" ":"))))
+       (spam-report-gmane-use-article-number
+       (spam-report-url-ping
+        rpt-host
+        (format "/%s:%d"
+                (gnus-group-real-name gnus-newsgroup-name)
+                article)))
+       (t
+       (with-current-buffer nntp-server-buffer
+         (erase-buffer)
+         (gnus-request-head article gnus-newsgroup-name)
+         (let ((case-fold-search t)
+               field host report url)
+           ;; First check for X-Report-Spam because it's more specific to
+           ;; spam reporting than Archived-At.  OTOH, all new articles on
+           ;; Gmane don't have X-Report-Spam anymore (unless Lars changes his
+           ;; mind :-)).
+           ;;
+           ;; There might be more than one Archived-At header so we need to
+           ;; find (and transform) the one related to Gmane.
+           (setq field (or (gnus-fetch-field "X-Report-Spam")
+                           (gnus-fetch-field "X-Report-Unspam")
+                           (gnus-fetch-field "Archived-At")))
+           (if (not (stringp field))
+               (if (and (setq field (gnus-fetch-field "Xref"))
+                        (string-match "[^ ]+ +\\([^ ]+\\)" field))
+                   (setq report (concat "/" (match-string 1 field))
+                         host rpt-host))
+             (setq host
+                   (progn
+                     (string-match
+                      (concat "http://\\([a-z]+\\.gmane\\.org\\)"
+                              "\\(/[^:/]+[:/][0-9]+\\)")
+                      field)
+                     (match-string 1 field)))
+             (setq report (match-string 2 field)))
+           (when host
+             (when (string-equal "permalink.gmane.org" host)
+               (setq host rpt-host)
+               (setq report (gnus-replace-in-string
+                             report "/\\([0-9]+\\)$" ":\\1")))
+             (setq url (format "http://%s%s" host report)))
+           (if (not (and host report url))
+               (gnus-message
+                3 "Could not find a spam report header in article %d..."
+                article)
+             (gnus-message 7 "Reporting article through URL %s..." url)
+             (spam-report-url-ping host report)))))))))
+
+(defun spam-report-url-ping (host report)
+  "Ping a host through HTTP, addressing a specific GET resource using
+the function specified by `spam-report-url-ping-function'."
+  ;; Example:
+  ;; host: "spam.gmane.org"
+  ;; report: "/gmane.some.group:123456"
+  (funcall spam-report-url-ping-function host report))
+
+(defcustom spam-report-user-mail-address
+  (and (stringp user-mail-address)
+       (gnus-replace-in-string user-mail-address "@" "<at>"))
+  "Mail address of this user used for spam reports to Gmane.
+This is initialized based on `user-mail-address'."
+  :type '(choice string
+                (const :tag "Don't expose address" nil))
+  :version "23.1" ;; No Gnus
+  :group 'spam-report)
+
+(defvar spam-report-user-agent
+  (if spam-report-user-mail-address
+      (format "%s (%s) %s" "spam-report.el"
+             spam-report-user-mail-address
+             (gnus-extended-version))
+    (format "%s %s" "spam-report.el"
+           (gnus-extended-version))))
+
+(defun spam-report-url-ping-plain (host report)
+  "Ping a host through HTTP, addressing a specific GET resource."
+  (let ((tcp-connection))
+    (with-temp-buffer
+      (or (setq tcp-connection
+               (open-network-stream
+                "URL ping"
+                (buffer-name)
+                host
+                80))
+         (error "Could not open connection to %s" host))
+      (set-marker (process-mark tcp-connection) (point-min))
+      (gnus-set-process-query-on-exit-flag tcp-connection nil)
+      (process-send-string
+       tcp-connection
+       (format "GET %s HTTP/1.1\nUser-Agent: %s\nHost: %s\n\n"
+              report spam-report-user-agent host))
+      ;; Wait until we get something so we don't DOS the host, if
+      ;; `spam-report-gmane-wait' is let-bound to t.
+      (when spam-report-gmane-wait
+       (gnus-message 7 "Waiting for response from %s..." host)
+       (while (and (memq (process-status tcp-connection) '(open run))
+                   (zerop (buffer-size)))
+         (accept-process-output tcp-connection 1))
+       (gnus-message 7 "Waiting for response from %s... done" host)))))
+
+;;;###autoload
+(defun spam-report-process-queue (&optional file keep)
+  "Report all queued requests from `spam-report-requests-file'.
+
+If FILE is given, use it instead of `spam-report-requests-file'.
+If KEEP is t, leave old requests in the file.  If KEEP is the
+symbol `ask', query before flushing the queue file."
+  (interactive
+   (list (read-file-name
+         "File: "
+         (file-name-directory spam-report-requests-file)
+         spam-report-requests-file
+         nil
+         (file-name-nondirectory spam-report-requests-file))
+        current-prefix-arg))
+  (if (eq spam-report-url-ping-function 'spam-report-url-to-file)
+      (error (concat "Cannot process requests when "
+                    "`spam-report-url-ping-function' is "
+                    "`spam-report-url-to-file'."))
+    (gnus-message 7 "Processing requests using `%s'."
+                 spam-report-url-ping-function))
+  (or file (setq file spam-report-requests-file))
+  (with-current-buffer (find-file-noselect file)
+    (goto-char (point-min))
+    (while (and (not (eobp))
+               (re-search-forward
+                "http://\\([^/]+\\)\\(/.*\\) *$" (point-at-eol) t))
+      (let ((spam-report-gmane-wait
+            (zerop (% (mm-line-number-at-pos)
+                      spam-report-gmane-max-requests))))
+       (gnus-message 6 "Reporting %s%s..."
+                     (match-string 1) (match-string 2))
+       (funcall spam-report-url-ping-function
+                (match-string 1) (match-string 2)))
+      (forward-line 1))
+    (if (or (eq keep nil)
+           (and (eq keep 'ask)
+                (y-or-n-p
+                 (gnus-format-message
+                  "Flush requests from `%s'? " (current-buffer)))))
+       (progn
+         (gnus-message 7 "Flushing request file `%s'"
+                       spam-report-requests-file)
+         (erase-buffer)
+         (save-buffer)
+         (kill-buffer (current-buffer)))
+      (gnus-message 7 "Keeping requests in `%s'" spam-report-requests-file))))
+
+;;;###autoload
+(defun spam-report-url-ping-mm-url (host report)
+  "Ping a host through HTTP, addressing a specific GET resource. Use
+the external program specified in `mm-url-program' to connect to
+server."
+  (with-temp-buffer
+    (let ((url (format "http://%s%s" host report)))
+      (mm-url-insert url t))))
+
+;;;###autoload
+(defun spam-report-url-to-file (host report)
+  "Collect spam report requests in `spam-report-requests-file'.
+Customize `spam-report-url-ping-function' to use this function."
+  (let ((url (format "http://%s%s" host report))
+       (file spam-report-requests-file))
+    (gnus-make-directory (file-name-directory file))
+    (gnus-message 9 "Writing URL `%s' to file `%s'" url file)
+    (with-temp-buffer
+      (insert url)
+      (newline)
+      (append-to-file (point-min) (point-max) file))))
+
+;;;###autoload
+(defun spam-report-agentize ()
+  "Add spam-report support to the Agent.
+Spam reports will be queued with \\[spam-report-url-to-file] when
+the Agent is unplugged, and will be submitted in a batch when the
+Agent is plugged."
+  (interactive)
+  (add-hook 'gnus-agent-plugged-hook 'spam-report-plug-agent)
+  (add-hook 'gnus-agent-unplugged-hook 'spam-report-unplug-agent))
+
+;;;###autoload
+(defun spam-report-deagentize ()
+  "Remove spam-report support from the Agent.
+Spam reports will be queued with the method used when
+\\[spam-report-agentize] was run."
+  (interactive)
+  (remove-hook 'gnus-agent-plugged-hook 'spam-report-plug-agent)
+  (remove-hook 'gnus-agent-unplugged-hook 'spam-report-unplug-agent))
+
+(defun spam-report-plug-agent ()
+  "Adjust spam report settings for plugged state.
+Process queued spam reports."
+  ;; Process the queue, unless the user only wanted to report to a file
+  ;; anyway.
+  (unless (equal spam-report-url-ping-temp-agent-function
+                'spam-report-url-to-file)
+    (spam-report-process-queue))
+  ;; Set the reporting function, if we have memorized something otherwise,
+  ;; stick with plain URL reporting.
+  (setq spam-report-url-ping-function
+       (or spam-report-url-ping-temp-agent-function
+           'spam-report-url-ping-plain)))
+
+(defun spam-report-unplug-agent ()
+  "Restore spam report settings for unplugged state."
+  ;; save the old value
+  (setq spam-report-url-ping-temp-agent-function
+       spam-report-url-ping-function)
+  ;; store all reports to file
+  (setq spam-report-url-ping-function
+       'spam-report-url-to-file))
+
+(provide 'spam-report)
+
+;;; spam-report.el ends here.
diff --git a/xemacs-packages/gnus/lisp/spam-stat.el b/xemacs-packages/gnus/lisp/spam-stat.el
new file mode 100644 (file)
index 0000000..afcc541
--- /dev/null
@@ -0,0 +1,678 @@
+;;; spam-stat.el --- detecting spam based on statistics
+
+;; Copyright (C) 2002-2016 Free Software Foundation, Inc.
+
+;; Author: Alex Schroeder <alex@gnu.org>
+;; Keywords: network
+;; URL: http://www.emacswiki.org/cgi-bin/wiki.pl?SpamStat
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This implements spam analysis according to Paul Graham in "A Plan
+;; for Spam".  The basis for all this is a statistical distribution of
+;; words for your spam and non-spam mails.  We need this information
+;; in a hash-table so that the analysis can use the information when
+;; looking at your mails.  Therefore, before you begin, you need tons
+;; of mails (Graham uses 4000 non-spam and 4000 spam mails for his
+;; experiments).
+;;
+;; The main interface to using spam-stat, are the following functions:
+;;
+;; `spam-stat-buffer-is-spam' -- called in a buffer, that buffer is
+;; considered to be a new spam mail; use this for new mail that has
+;; not been processed before
+;;
+;; `spam-stat-buffer-is-non-spam' -- called in a buffer, that buffer
+;; is considered to be a new non-spam mail; use this for new mail that
+;; has not been processed before
+;;
+;; `spam-stat-buffer-change-to-spam' -- called in a buffer, that
+;; buffer is no longer considered to be normal mail but spam; use this
+;; to change the status of a mail that has already been processed as
+;; non-spam
+;;
+;; `spam-stat-buffer-change-to-non-spam' -- called in a buffer, that
+;; buffer is no longer considered to be spam but normal mail; use this
+;; to change the status of a mail that has already been processed as
+;; spam
+;;
+;; `spam-stat-save' -- save the hash table to the file; the filename
+;; used is stored in the variable `spam-stat-file'
+;;
+;; `spam-stat-load' -- load the hash table from a file; the filename
+;; used is stored in the variable `spam-stat-file'
+;;
+;; `spam-stat-score-word' -- return the spam score for a word
+;;
+;; `spam-stat-score-buffer' -- return the spam score for a buffer
+;;
+;; `spam-stat-split-fancy' -- for fancy mail splitting; add
+;; the rule (: spam-stat-split-fancy) to `nnmail-split-fancy'
+;;
+;; This requires the following in your ~/.gnus file:
+;;
+;; (require 'spam-stat)
+;; (spam-stat-load)
+
+;;; Testing:
+
+;; Typical test will involve calls to the following functions:
+;;
+;; Reset: (spam-stat-reset)
+;; Learn spam: (spam-stat-process-spam-directory "~/Mail/mail/spam")
+;; Learn non-spam: (spam-stat-process-non-spam-directory "~/Mail/mail/misc")
+;; Save table: (spam-stat-save)
+;; File size: (nth 7 (file-attributes spam-stat-file))
+;; Number of words: (hash-table-count spam-stat)
+;; Test spam: (spam-stat-test-directory "~/Mail/mail/spam")
+;; Test non-spam: (spam-stat-test-directory "~/Mail/mail/misc")
+;; Reduce table size: (spam-stat-reduce-size)
+;; Save table: (spam-stat-save)
+;; File size: (nth 7 (file-attributes spam-stat-file))
+;; Number of words: (hash-table-count spam-stat)
+;; Test spam: (spam-stat-test-directory "~/Mail/mail/spam")
+;; Test non-spam: (spam-stat-test-directory "~/Mail/mail/misc")
+
+;;; Dictionary Creation:
+
+;; Typically, you will filter away mailing lists etc. using specific
+;; rules in `nnmail-split-fancy'.  Somewhere among these rules, you
+;; will filter spam.  Here is how you would create your dictionary:
+
+;; Reset: (spam-stat-reset)
+;; Learn spam: (spam-stat-process-spam-directory "~/Mail/mail/spam")
+;; Learn non-spam: (spam-stat-process-non-spam-directory "~/Mail/mail/misc")
+;; Repeat for any other non-spam group you need...
+;; Reduce table size: (spam-stat-reduce-size)
+;; Save table: (spam-stat-save)
+
+;;; Todo:
+
+;; Speed it up.  Integrate with Gnus such that it uses spam and expiry
+;; marks to call the appropriate functions when leaving the summary
+;; buffer and saves the hash table when leaving Gnus.  More testing:
+;; More mails, disabling SpamAssassin, double checking algorithm, find
+;; improved algorithm.
+
+;;; Thanks:
+
+;; Ted Zlatanov <tzz@lifelogs.com>
+;; Jesper Harder <harder@myrealbox.com>
+;; Dan Schmidt <dfan@dfan.org>
+;; Lasse Rasinen <lrasinen@iki.fi>
+;; Milan Zamazal <pdm@zamazal.org>
+
+\f
+
+;;; Code:
+(require 'mail-parse)
+
+(defvar gnus-original-article-buffer)
+
+(defgroup spam-stat nil
+  "Statistical spam detection for Emacs.
+Use the functions to build a dictionary of words and their statistical
+distribution in spam and non-spam mails.  Then use a function to determine
+whether a buffer contains spam or not."
+  :version "22.1"
+  :group 'gnus)
+
+(defcustom spam-stat-file "~/.spam-stat.el"
+  "File used to save and load the dictionary.
+See `spam-stat-to-hash-table' for the format of the file."
+  :type 'file
+  :group 'spam-stat)
+
+(defcustom spam-stat-unknown-word-score 0.2
+  "The score to use for unknown words.
+Also used for words that don't appear often enough."
+  :type 'number
+  :group 'spam-stat)
+
+(defcustom spam-stat-max-word-length 15
+  "Only words shorter than this will be considered."
+  :type 'integer
+  :group 'spam-stat)
+
+(defcustom spam-stat-max-buffer-length 10240
+  "Only the beginning of buffers will be analyzed.
+This variable says how many characters this will be."
+  :type 'integer
+  :group 'spam-stat)
+
+(defcustom spam-stat-split-fancy-spam-group "mail.spam"
+  "Name of the group where spam should be stored.
+If `spam-stat-split-fancy' is used in fancy splitting rules.  Has
+no effect when spam-stat is invoked through spam.el."
+  :type 'string
+  :group 'spam-stat)
+
+(defcustom spam-stat-split-fancy-spam-threshold 0.9
+  "Spam score threshold in spam-stat-split-fancy."
+  :type 'number
+  :group 'spam-stat)
+
+(defcustom spam-stat-washing-hook nil
+  "Hook applied to each message before analysis."
+  :type 'hook
+  :group 'spam-stat)
+
+(defcustom spam-stat-score-buffer-user-functions nil
+  "List of additional scoring functions.
+Called  one by one on the buffer.
+
+If all of these functions return non-nil answers, these numerical
+answers are added to the computed spam stat score on the buffer.  If
+you defun such functions, make sure they don't return the buffer in a
+narrowed state or such: use, for example, `save-excursion'.  Each of
+your functions is also passed the initial spam-stat score which might
+aid in your scoring.
+
+Also be careful when defining such functions.  If they take a long
+time, they will slow down your mail splitting.  Thus, if the buffer is
+large, don't forget to use smaller regions, by wrapping your work in,
+say, `with-spam-stat-max-buffer-size'."
+  :type '(repeat sexp)
+  :group 'spam-stat)
+
+(defcustom spam-stat-process-directory-age 90
+  "Max. age of files to be processed in directory, in days.
+When using `spam-stat-process-spam-directory' or
+`spam-stat-process-non-spam-directory', only files that have
+been touched in this many days will be considered.  Without
+this filter, re-training spam-stat with several thousand messages
+will start to take a very long time."
+  :type 'number
+  :group 'spam-stat)
+
+(defvar spam-stat-last-saved-at nil
+  "Time stamp of last change of spam-stat-file on this run")
+
+(defvar spam-stat-syntax-table
+  (let ((table (copy-syntax-table text-mode-syntax-table)))
+    (modify-syntax-entry ?- "w" table)
+    (modify-syntax-entry ?_ "w" table)
+    (modify-syntax-entry ?. "w" table)
+    (modify-syntax-entry ?! "w" table)
+    (modify-syntax-entry ?? "w" table)
+    (modify-syntax-entry ?+ "w" table)
+    table)
+  "Syntax table used when processing mails for statistical analysis.
+The important part is which characters are word constituents.")
+
+(defvar spam-stat-dirty nil
+  "Whether the spam-stat database needs saving.")
+
+(defvar spam-stat-buffer nil
+  "Buffer to use for scoring while splitting.
+This is set by hooking into Gnus.")
+
+(defvar spam-stat-buffer-name " *spam stat buffer*"
+  "Name of the `spam-stat-buffer'.")
+
+(defvar spam-stat-coding-system
+  (if (mm-coding-system-p 'emacs-mule) 'emacs-mule 'raw-text)
+  "Coding system used for `spam-stat-file'.")
+
+;; Hooking into Gnus
+
+(defun spam-stat-store-current-buffer ()
+  "Store a copy of the current buffer in `spam-stat-buffer'."
+  (let ((buf (current-buffer)))
+    (with-current-buffer (get-buffer-create spam-stat-buffer-name)
+      (erase-buffer)
+      (insert-buffer-substring buf)
+      (setq spam-stat-buffer (current-buffer)))))
+
+(defun spam-stat-store-gnus-article-buffer ()
+  "Store a copy of the current article in `spam-stat-buffer'.
+This uses `gnus-article-buffer'."
+  (with-current-buffer gnus-original-article-buffer
+    (spam-stat-store-current-buffer)))
+
+;; Data -- not using defstruct in order to save space and time
+
+(defvar spam-stat (make-hash-table :test 'equal)
+  "Hash table used to store the statistics.
+Use `spam-stat-load' to load the file.
+Every word is used as a key in this table.  The value is a vector.
+Use `spam-stat-ngood', `spam-stat-nbad', `spam-stat-good',
+`spam-stat-bad', and `spam-stat-score' to access this vector.")
+
+(defvar spam-stat-ngood 0
+  "The number of good mails in the dictionary.")
+
+(defvar spam-stat-nbad 0
+  "The number of bad mails in the dictionary.")
+
+(defvar spam-stat-error-holder nil
+  "A holder for condition-case errors while scoring buffers.")
+
+(defsubst spam-stat-good (entry)
+  "Return the number of times this word belongs to good mails."
+  (aref entry 0))
+
+(defsubst spam-stat-bad (entry)
+  "Return the number of times this word belongs to bad mails."
+  (aref entry 1))
+
+(defsubst spam-stat-score (entry)
+  "Set the score of this word."
+  (if entry
+      (aref entry 2)
+    spam-stat-unknown-word-score))
+
+(defsubst spam-stat-set-good (entry value)
+  "Set the number of times this word belongs to good mails."
+  (aset entry 0 value))
+
+(defsubst spam-stat-set-bad (entry value)
+  "Set the number of times this word belongs to bad mails."
+  (aset entry 1 value))
+
+(defsubst spam-stat-set-score (entry value)
+  "Set the score of this word."
+  (aset entry 2 value))
+
+(defsubst spam-stat-make-entry (good bad)
+  "Return a vector with the given properties."
+  (let ((entry (vector good bad nil)))
+    (spam-stat-set-score entry (spam-stat-compute-score entry))
+    entry))
+
+;; Computing
+
+(defun spam-stat-compute-score (entry)
+  "Compute the score of this word.  1.0 means spam."
+   ;; promote all numbers to floats for the divisions
+   (let* ((g (* 2.0 (spam-stat-good entry)))
+         (b (float (spam-stat-bad entry))))
+     (cond ((< (+ g b) 5)
+           .2)
+          ((= 0 spam-stat-ngood)
+           .99)
+          ((= 0 spam-stat-nbad)
+           .01)
+          (t
+           (max .01
+                (min .99 (/ (/ b spam-stat-nbad)
+                            (+ (/ g spam-stat-ngood)
+                               (/ b spam-stat-nbad)))))))))
+
+;; Parsing
+
+(defmacro with-spam-stat-max-buffer-size (&rest body)
+  "Narrow the buffer down to the first 4k characters, then evaluate BODY."
+  `(save-restriction
+     (when (> (- (point-max)
+                (point-min))
+             spam-stat-max-buffer-length)
+       (narrow-to-region (point-min)
+                        (+ (point-min) spam-stat-max-buffer-length)))
+     ,@body))
+
+(defun spam-stat-buffer-words ()
+  "Return a hash table of words and number of occurrences in the buffer."
+  (run-hooks 'spam-stat-washing-hook)
+  (with-spam-stat-max-buffer-size
+   (with-syntax-table spam-stat-syntax-table
+     (goto-char (point-min))
+     (let ((result (make-hash-table :test 'equal))
+          word count)
+       (while (re-search-forward "\\w+" nil t)
+        (setq word (match-string-no-properties 0)
+              count (1+ (gethash word result 0)))
+        (when (< (length word) spam-stat-max-word-length)
+          (puthash word count result)))
+       result))))
+
+(defun spam-stat-buffer-is-spam ()
+  "Consider current buffer to be a new spam mail."
+  (setq spam-stat-nbad (1+ spam-stat-nbad))
+  (maphash
+   (lambda (word count)
+     (let ((entry (gethash word spam-stat)))
+       (if entry
+          (spam-stat-set-bad entry (+ count (spam-stat-bad entry)))
+        (setq entry (spam-stat-make-entry 0 count)))
+       (spam-stat-set-score entry (spam-stat-compute-score entry))
+       (puthash word entry spam-stat)))
+   (spam-stat-buffer-words))
+  (setq spam-stat-dirty t))
+
+(defun spam-stat-buffer-is-non-spam ()
+  "Consider current buffer to be a new non-spam mail."
+  (setq spam-stat-ngood (1+ spam-stat-ngood))
+  (maphash
+   (lambda (word count)
+     (let ((entry (gethash word spam-stat)))
+       (if entry
+          (spam-stat-set-good entry (+ count (spam-stat-good entry)))
+        (setq entry (spam-stat-make-entry count 0)))
+       (spam-stat-set-score entry (spam-stat-compute-score entry))
+       (puthash word entry spam-stat)))
+   (spam-stat-buffer-words))
+  (setq spam-stat-dirty t))
+
+(autoload 'gnus-message "gnus-util")
+
+(defun spam-stat-buffer-change-to-spam ()
+  "Consider current buffer no longer normal mail but spam."
+  (setq spam-stat-nbad (1+ spam-stat-nbad)
+       spam-stat-ngood (1- spam-stat-ngood))
+  (maphash
+   (lambda (word count)
+     (let ((entry (gethash word spam-stat)))
+       (if (not entry)
+          (gnus-message 8 "This buffer has unknown words in it")
+        (spam-stat-set-good entry (- (spam-stat-good entry) count))
+        (spam-stat-set-bad entry (+ (spam-stat-bad entry) count))
+        (spam-stat-set-score entry (spam-stat-compute-score entry))
+        (puthash word entry spam-stat))))
+   (spam-stat-buffer-words))
+  (setq spam-stat-dirty t))
+
+(defun spam-stat-buffer-change-to-non-spam ()
+  "Consider current buffer no longer spam but normal mail."
+  (setq spam-stat-nbad (1- spam-stat-nbad)
+       spam-stat-ngood (1+ spam-stat-ngood))
+  (maphash
+   (lambda (word count)
+     (let ((entry (gethash word spam-stat)))
+       (if (not entry)
+          (gnus-message 8 "This buffer has unknown words in it")
+        (spam-stat-set-good entry (+ (spam-stat-good entry) count))
+        (spam-stat-set-bad entry (- (spam-stat-bad entry) count))
+        (spam-stat-set-score entry (spam-stat-compute-score entry))
+        (puthash word entry spam-stat))))
+   (spam-stat-buffer-words))
+  (setq spam-stat-dirty t))
+
+;; Saving and Loading
+
+(defun spam-stat-save (&optional force)
+  "Save the `spam-stat' hash table as lisp file.
+With a prefix argument save unconditionally."
+  (interactive "P")
+  (when (or force spam-stat-dirty)
+    (let ((coding-system-for-write spam-stat-coding-system))
+      (with-temp-file spam-stat-file
+       (let ((standard-output (current-buffer)))
+         (insert (format ";-*- coding: %s; -*-\n" spam-stat-coding-system))
+         (insert (format "(setq spam-stat-ngood %d spam-stat-nbad %d
+spam-stat (spam-stat-to-hash-table '(" spam-stat-ngood spam-stat-nbad))
+         (maphash (lambda (word entry)
+                    (prin1 (list word
+                                 (spam-stat-good entry)
+                                 (spam-stat-bad entry))))
+                  spam-stat)
+         (insert ")))"))))
+    (message "Saved %s."  spam-stat-file)
+    (setq spam-stat-dirty nil
+          spam-stat-last-saved-at (nth 5 (file-attributes spam-stat-file)))))
+
+(defun spam-stat-load ()
+  "Read the `spam-stat' hash table from disk."
+  ;; TODO: maybe we should warn the user if spam-stat-dirty is t?
+  (let ((coding-system-for-read spam-stat-coding-system))
+    (cond (spam-stat-dirty (message "Spam stat not loaded: spam-stat-dirty t"))
+          ((or (not (boundp 'spam-stat-last-saved-at))
+               (null spam-stat-last-saved-at)
+               (not (equal spam-stat-last-saved-at
+                           (nth 5 (file-attributes spam-stat-file)))))
+           (progn
+             (load-file spam-stat-file)
+             (setq spam-stat-dirty nil
+                   spam-stat-last-saved-at
+                   (nth 5 (file-attributes spam-stat-file)))))
+          (t (message "Spam stat file not loaded: no change in disk.")))))
+
+(defun spam-stat-to-hash-table (entries)
+  "Turn list ENTRIES into a hash table and store as `spam-stat'.
+Every element in ENTRIES has the form \(WORD GOOD BAD) where WORD is
+the word string, NGOOD is the number of good mails it has appeared in,
+NBAD is the number of bad mails it has appeared in, GOOD is the number
+of times it appeared in good mails, and BAD is the number of times it
+has appeared in bad mails."
+  (let ((table (make-hash-table :size (length entries)
+                               :test 'equal)))
+    (mapc (lambda (l)
+           (puthash (car l)
+                    (spam-stat-make-entry (nth 1 l) (nth 2 l))
+                    table))
+         entries)
+    table))
+
+(defun spam-stat-reset ()
+  "Reset `spam-stat' to an empty hash-table.
+This deletes all the statistics."
+  (interactive)
+  (setq spam-stat (make-hash-table :test 'equal)
+       spam-stat-ngood 0
+       spam-stat-nbad 0)
+  (setq spam-stat-dirty t))
+
+;; Scoring buffers
+
+(defvar spam-stat-score-data nil
+  "Raw data used in the last run of `spam-stat-score-buffer'.")
+
+(defsubst spam-stat-score-word (word)
+  "Return score for WORD.
+The default score for unknown words is stored in
+`spam-stat-unknown-word-score'."
+  (spam-stat-score (gethash word spam-stat)))
+
+(defun spam-stat-buffer-words-with-scores ()
+  "Process current buffer, return the 15 most conspicuous words.
+These are the words whose spam-stat differs the most from 0.5.
+The list returned contains elements of the form \(WORD SCORE DIFF),
+where DIFF is the difference between SCORE and 0.5."
+  (let (result word score)
+    (maphash (lambda (word ignore)
+              (setq score (spam-stat-score-word word)
+                    result (cons (list word score (abs (- score 0.5)))
+                                 result)))
+            (spam-stat-buffer-words))
+    (setq result (sort result (lambda (a b) (< (nth 2 b) (nth 2 a)))))
+    (setcdr (nthcdr 14 result) nil)
+    result))
+
+(eval-when-compile
+  (defmacro spam-stat-called-interactively-p (kind)
+    (condition-case nil
+       (progn
+         (eval '(called-interactively-p 'any))
+         ;; Emacs >=23.2
+         `(called-interactively-p ,kind))
+      ;; Emacs <23.2
+      (wrong-number-of-arguments '(called-interactively-p))
+      ;; XEmacs
+      (void-function '(interactive-p)))))
+
+(defun spam-stat-score-buffer ()
+  "Return a score describing the spam-probability for this buffer.
+Add user supplied modifications if supplied."
+  (interactive) ; helps in debugging.
+  (setq spam-stat-score-data (spam-stat-buffer-words-with-scores))
+  (let* ((probs (mapcar 'cadr spam-stat-score-data))
+        (prod (apply #'* probs))
+        (score0
+         (/ prod (+ prod (apply #'* (mapcar #'(lambda (x) (- 1 x))
+                                            probs)))))
+        (score1s
+         (condition-case
+             spam-stat-error-holder
+             (spam-stat-score-buffer-user score0)
+           (error nil)))
+        (ans
+         (if score1s (+ score0 score1s) score0)))
+    (when (spam-stat-called-interactively-p 'any)
+      (message "%S" ans))
+    ans))
+
+(defun spam-stat-score-buffer-user (&rest args)
+  (let* ((scores
+         (mapcar
+          (lambda (fn)
+            (apply fn args))
+          spam-stat-score-buffer-user-functions)))
+    (if (memq nil scores) nil
+      (apply #'+ scores))))
+
+(defun spam-stat-split-fancy ()
+  "Return the name of the spam group if the current mail is spam.
+Use this function on `nnmail-split-fancy'.  If you are interested in
+the raw data used for the last run of `spam-stat-score-buffer',
+check the variable `spam-stat-score-data'."
+  (condition-case spam-stat-error-holder
+      (progn
+       (set-buffer spam-stat-buffer)
+       (goto-char (point-min))
+       (when (> (spam-stat-score-buffer) spam-stat-split-fancy-spam-threshold)
+         (when (boundp 'nnmail-split-trace)
+           (mapc (lambda (entry)
+                   (push entry nnmail-split-trace))
+                 spam-stat-score-data))
+         spam-stat-split-fancy-spam-group))
+    (error (message "Error in spam-stat-split-fancy: %S" spam-stat-error-holder)
+          nil)))
+
+;; Testing
+
+(defun spam-stat-strip-xref ()
+  "Strip the Xref header."
+  (save-restriction
+    (mail-narrow-to-head)
+    (when (re-search-forward "^Xref:.*\n" nil t)
+      (delete-region (match-beginning 0) (match-end 0)))))
+
+(autoload 'time-to-number-of-days "time-date")
+
+(defun spam-stat-process-directory (dir func)
+  "Process all the regular files in directory DIR using function FUNC."
+  (let* ((files (directory-files dir t "^[^.]"))
+        (max (/ (length files) 100.0))
+        (count 0))
+    (with-temp-buffer
+      (dolist (f files)
+       (when (and (file-readable-p f)
+                  (file-regular-p f)
+                   (> (nth 7 (file-attributes f)) 0)
+                  (< (time-to-number-of-days (time-since (nth 5 (file-attributes f))))
+                     spam-stat-process-directory-age))
+         (setq count (1+ count))
+         (message "Reading %s: %.2f%%" dir (/ count max))
+         (insert-file-contents-literally f)
+         (spam-stat-strip-xref)
+         (funcall func)
+         (erase-buffer))))))
+
+(defun spam-stat-process-spam-directory (dir)
+  "Process all the regular files in directory DIR as spam."
+  (interactive "D")
+  (spam-stat-process-directory dir 'spam-stat-buffer-is-spam))
+
+(defun spam-stat-process-non-spam-directory (dir)
+  "Process all the regular files in directory DIR as non-spam."
+  (interactive "D")
+  (spam-stat-process-directory dir 'spam-stat-buffer-is-non-spam))
+
+(defun spam-stat-count ()
+  "Return size of `spam-stat'."
+  (interactive)
+  (hash-table-count spam-stat))
+
+(defun spam-stat-test-directory (dir &optional verbose)
+  "Test all the regular files in directory DIR for spam.
+If the result is 1.0, then all files are considered spam.
+If the result is 0.0, non of the files is considered spam.
+You can use this to determine error rates.
+
+If VERBOSE is non-nil display names of files detected as spam or
+non-spam in a temporary buffer.  If it is the symbol `ham',
+display non-spam files; otherwise display spam files."
+  (interactive "DDirectory: ")
+  (let* ((files (directory-files dir t "^[^.]"))
+        display-files
+        buffer-score
+        (total (length files))
+        (score 0.0); float
+        (max (/ total 100.0)); float
+        (count 0))
+    (with-temp-buffer
+      (dolist (f files)
+       (when (and (file-readable-p f)
+                  (file-regular-p f)
+                   (> (nth 7 (file-attributes f)) 0))
+         (setq count (1+ count))
+         (message "Reading %.2f%%, score %.2f"
+                  (/ count max) (/ score count))
+         (insert-file-contents-literally f)
+         (setq buffer-score (spam-stat-score-buffer))
+         (when (> buffer-score 0.9)
+           (setq score (1+ score)))
+         (when verbose
+           (if (> buffer-score 0.9)
+               (unless (eq verbose 'ham) (push f display-files))
+             (when (eq verbose 'ham) (push f display-files))))
+         (erase-buffer))))
+    (when display-files
+      (with-output-to-temp-buffer "*spam-stat results*"
+       (dolist (file display-files)
+         (princ file)
+         (terpri))))
+    (message "Final score: %d / %d = %f" score total (/ score total))))
+
+;; Shrinking the dictionary
+
+(defun spam-stat-reduce-size (&optional count)
+  "Reduce the size of `spam-stat'.
+This removes all words that occur less than COUNT from the dictionary.
+COUNT defaults to 5"
+  (interactive)
+  (setq count (or count 5))
+  (maphash (lambda (key entry)
+            (when (< (+ (spam-stat-good entry)
+                        (spam-stat-bad entry))
+                     count)
+              (remhash key spam-stat)))
+          spam-stat)
+  (setq spam-stat-dirty t))
+
+(defun spam-stat-install-hooks-function ()
+  "Install the spam-stat function hooks."
+  (interactive)
+  (add-hook 'nnmail-prepare-incoming-message-hook
+           'spam-stat-store-current-buffer)
+  (add-hook 'gnus-select-article-hook
+           'spam-stat-store-gnus-article-buffer))
+
+(defun spam-stat-unload-hook ()
+  "Uninstall the spam-stat function hooks."
+  (interactive)
+  (remove-hook 'nnmail-prepare-incoming-message-hook
+              'spam-stat-store-current-buffer)
+  (remove-hook 'gnus-select-article-hook
+              'spam-stat-store-gnus-article-buffer))
+
+(add-hook 'spam-stat-unload-hook 'spam-stat-unload-hook)
+
+(provide 'spam-stat)
+
+;;; spam-stat.el ends here
diff --git a/xemacs-packages/gnus/lisp/spam-wash.el b/xemacs-packages/gnus/lisp/spam-wash.el
new file mode 100644 (file)
index 0000000..2bb9171
--- /dev/null
@@ -0,0 +1,72 @@
+;;; spam-wash.el --- wash spam before analysis
+
+;; Copyright (C) 2004, 2007-2016 Free Software Foundation, Inc.
+
+;; Author: Andrew Cohen <cohen@andy.bu.edu>
+;; Keywords: mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This library decodes MIME encodings such as base64 and
+;; quoted-printable to allow for better spam analysis.
+;;
+;; `spam-wash' should be called in a buffer containing the message.
+
+;;; Code:
+
+(require 'gnus-art)
+
+(defun spam-wash ()
+  "Treat the current buffer prior to spam analysis."
+  (interactive)
+  (run-hooks 'gnus-article-decode-hook)
+  (save-excursion
+    (save-restriction
+      (let* ((buffer-read-only  nil)
+            (gnus-inhibit-treatment t)
+            (gnus-article-buffer (current-buffer))
+            (handles (or (mm-dissect-buffer nil gnus-article-loose-mime)
+                         (and gnus-article-emulate-mime
+                              (mm-uu-dissect))))
+            handle)
+         (when gnus-article-mime-handles
+           (mm-destroy-parts gnus-article-mime-handles)
+           (setq gnus-article-mime-handle-alist nil))
+         (setq gnus-article-mime-handles handles)
+         (when (and handles
+                  (or (not (stringp (car handles)))
+                      (cdr handles)))
+               (article-goto-body)
+               (delete-region (point) (point-max))
+               (spam-treat-parts handles))))))
+
+(defun spam-treat-parts (handle)
+  (if (stringp (car handle))
+      (mapcar 'spam-treat-parts (cdr handle))
+    (if (bufferp (car handle))
+       (save-restriction
+         (narrow-to-region (point) (point))
+       (when (let ((case-fold-search t))
+               (string-match "text" (car (mm-handle-type handle))))
+         (mm-insert-part handle))
+         (goto-char (point-max)))
+      (mapcar 'spam-treat-parts handle))))
+
+(provide 'spam-wash)
+
+;;; spam-wash.el ends here
diff --git a/xemacs-packages/gnus/lisp/spam.el b/xemacs-packages/gnus/lisp/spam.el
new file mode 100644 (file)
index 0000000..ab0584f
--- /dev/null
@@ -0,0 +1,2932 @@
+;;; spam.el --- Identifying spam
+
+;; Copyright (C) 2002-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Maintainer: Ted Zlatanov <tzz@lifelogs.com>
+;; Keywords: network, spam, mail, bogofilter, BBDB, dspam, dig, whitelist, blacklist, gmane, hashcash, spamassassin, bsfilter, ifile, stat, crm114, spamoracle
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; This module addresses a few aspects of spam control under Gnus.  Page
+;;; breaks are used for grouping declarations and documentation relating to
+;;; each particular aspect.
+
+;;; The integration with Gnus is not yet complete.  See various `FIXME'
+;;; comments, below, for supplementary explanations or discussions.
+
+;;; Several TODO items are marked as such
+
+;; TODO: cross-server splitting, remote processing, training through files
+
+;;; Code:
+
+;;{{{ compilation directives and autoloads/requires
+
+(eval-when-compile (require 'cl))
+
+(require 'message)              ;for the message-fetch-field functions
+(require 'gnus-sum)
+(require 'gnus-uu)                      ; because of key prefix issues
+;;; for the definitions of group content classification and spam processors
+(require 'gnus)
+
+(eval-when-compile (require 'hashcash))
+
+;; for nnimap-split-download-body-default
+(eval-when-compile (require 'nnimap))
+
+;; autoload query-dig
+(autoload 'query-dig "dig")
+
+;; autoload spam-report
+(autoload 'spam-report-gmane "spam-report")
+(autoload 'spam-report-gmane-spam "spam-report")
+(autoload 'spam-report-gmane-ham "spam-report")
+(autoload 'spam-report-resend "spam-report")
+
+;; autoload gnus-registry
+(autoload 'gnus-registry-group-count "gnus-registry")
+(autoload 'gnus-registry-get-id-key "gnus-registry")
+(autoload 'gnus-registry-set-id-key "gnus-registry")
+(autoload 'gnus-registry-handle-action "gnus-registry")
+
+;; autoload dns-query
+(autoload 'dns-query "dns")
+
+;;}}}
+
+;;{{{ Main parameters.
+(defvar spam-backends nil
+  "List of spam.el backends with all the pertinent data.
+Populated by `spam-install-backend-super'.")
+
+(defgroup spam nil
+  "Spam configuration."
+  :version "22.1"
+  :group 'mail
+  :group 'news)
+
+(defcustom spam-summary-exit-behavior 'default
+  "Exit behavior at the time of summary exit.
+Note that setting the `spam-use-move' or `spam-use-copy' backends on
+a group through group/topic parameters overrides this mechanism."
+  :type '(choice
+          (const
+           :tag "Move spam out of all groups and ham out of spam groups"
+           default)
+          (const
+           :tag "Move spam out of all groups and ham out of all groups"
+           move-all)
+          (const
+           :tag "Never move spam or ham out of any groups"
+           move-none))
+  :group 'spam)
+
+(defcustom spam-directory (nnheader-concat gnus-directory "spam/")
+  "Directory for spam whitelists and blacklists."
+  :type 'directory
+  :group 'spam)
+
+(defcustom spam-mark-new-messages-in-spam-group-as-spam t
+  "Whether new messages in a spam group should get the spam-mark."
+  :type 'boolean
+  ;; :version "22.1" ;; Gnus 5.10.8 / No Gnus 0.3
+  :group 'spam)
+
+(defcustom spam-log-to-registry nil
+  "Whether spam/ham processing should be logged in the registry."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-split-symbolic-return nil
+  "Whether `spam-split' should work with symbols or group names."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-split-symbolic-return-positive nil
+  "Whether `spam-split' should ALWAYS work with symbols or group names.
+Do not set this if you use `spam-split' in a fancy split method."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-mark-only-unseen-as-spam t
+  "Whether only unseen articles should be marked as spam in spam groups.
+When nil, all unread articles in a spam group are marked as
+spam.  Set this if you want to leave an article unread in a spam group
+without losing it to the automatic spam-marking process."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-mark-ham-unread-before-move-from-spam-group nil
+  "Whether ham should be marked unread before it's moved.
+The article is moved out of a spam group according to `ham-process-destination'.
+This variable is an official entry in the international Longest Variable Name
+Competition."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-disable-spam-split-during-ham-respool nil
+  "Whether `spam-split' should be ignored while resplitting ham.
+This is useful to prevent ham from ending up in the same spam
+group after the resplit.  Don't set this to t if you have `spam-split' as the
+last rule in your split configuration."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-autodetect-recheck-messages nil
+  "Should spam.el recheck all messages when autodetecting?
+Normally this is nil, so only unseen messages will be checked."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-whitelist (expand-file-name "whitelist" spam-directory)
+  "The location of the whitelist.
+The file format is one regular expression per line.
+The regular expression is matched against the address."
+  :type 'file
+  :group 'spam)
+
+(defcustom spam-blacklist (expand-file-name "blacklist" spam-directory)
+  "The location of the blacklist.
+The file format is one regular expression per line.
+The regular expression is matched against the address."
+  :type 'file
+  :group 'spam)
+
+(defcustom spam-use-dig t
+  "Whether `query-dig' should be used instead of `dns-query'."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-use-gmane-xref nil
+  "Whether the Gmane spam xref should be used by `spam-split'."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-use-blacklist nil
+  "Whether the blacklist should be used by `spam-split'."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-blacklist-ignored-regexes nil
+  "Regular expressions that the blacklist should ignore."
+  :type '(repeat (regexp :tag "Regular expression to ignore when blacklisting"))
+  :group 'spam)
+
+(defcustom spam-use-whitelist nil
+  "Whether the whitelist should be used by `spam-split'."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-use-whitelist-exclusive nil
+  "Whether whitelist-exclusive should be used by `spam-split'.
+Exclusive whitelisting means that all messages from senders not in the whitelist
+are considered spam."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-use-blackholes nil
+  "Whether blackholes should be used by `spam-split'."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-use-hashcash nil
+  "Whether hashcash payments should be detected by `spam-split'."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-use-regex-headers nil
+  "Whether a header regular expression match should be used by `spam-split'.
+Also see the variables `spam-regex-headers-spam' and `spam-regex-headers-ham'."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-use-regex-body nil
+  "Whether a body regular expression match should be used by `spam-split'.
+Also see the variables `spam-regex-body-spam' and `spam-regex-body-ham'."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-use-bogofilter-headers nil
+  "Whether bogofilter headers should be used by `spam-split'.
+Enable this if you pre-process messages with Bogofilter BEFORE Gnus sees them."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-use-bogofilter nil
+  "Whether bogofilter should be invoked by `spam-split'.
+Enable this if you want Gnus to invoke Bogofilter on new messages."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-use-bsfilter-headers nil
+  "Whether bsfilter headers should be used by `spam-split'.
+Enable this if you pre-process messages with Bsfilter BEFORE Gnus sees them."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-use-bsfilter nil
+  "Whether bsfilter should be invoked by `spam-split'.
+Enable this if you want Gnus to invoke Bsfilter on new messages."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-use-BBDB nil
+  "Whether BBDB should be used by `spam-split'."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-use-BBDB-exclusive nil
+  "Whether BBDB-exclusive should be used by `spam-split'.
+Exclusive BBDB means that all messages from senders not in the BBDB are
+considered spam."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-use-ifile nil
+  "Whether ifile should be used by `spam-split'."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-use-stat nil
+  "Whether `spam-stat' should be used by `spam-split'."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-use-spamoracle nil
+  "Whether spamoracle should be used by `spam-split'."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-use-spamassassin nil
+  "Whether spamassassin should be invoked by `spam-split'.
+Enable this if you want Gnus to invoke SpamAssassin on new messages."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-use-spamassassin-headers nil
+  "Whether spamassassin headers should be checked by `spam-split'.
+Enable this if you pre-process messages with SpamAssassin BEFORE Gnus sees
+them."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-use-crm114 nil
+  "Whether the CRM114 Mailfilter should be used by `spam-split'."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-install-hooks (or
+                               spam-use-dig
+                               spam-use-gmane-xref
+                               spam-use-blacklist
+                               spam-use-whitelist
+                               spam-use-whitelist-exclusive
+                               spam-use-blackholes
+                               spam-use-hashcash
+                               spam-use-regex-headers
+                               spam-use-regex-body
+                               spam-use-bogofilter
+                               spam-use-bogofilter-headers
+                               spam-use-spamassassin
+                               spam-use-spamassassin-headers
+                               spam-use-bsfilter
+                               spam-use-bsfilter-headers
+                               spam-use-BBDB
+                               spam-use-BBDB-exclusive
+                               spam-use-ifile
+                               spam-use-stat
+                               spam-use-spamoracle
+                               spam-use-crm114)
+  "Whether the spam hooks should be installed.
+Default to t if one of the spam-use-* variables is set."
+  :group 'spam
+  :type 'boolean)
+
+(defcustom spam-split-group "spam"
+  "Group name where incoming spam should be put by `spam-split'."
+  :type 'string
+  :group 'spam)
+
+;;; TODO: deprecate this variable, it's confusing since it's a list of strings,
+;;; not regular expressions
+(defcustom spam-junk-mailgroups (cons
+                                 spam-split-group
+                                 '("mail.junk" "poste.pourriel"))
+  "Mailgroups with spam contents.
+All unmarked article in such group receive the spam mark on group entry."
+  :type '(repeat (string :tag "Group"))
+  :group 'spam)
+
+
+(defcustom spam-gmane-xref-spam-group "gmane.spam.detected"
+  "The group where spam xrefs can be found on Gmane.
+Only meaningful if you enable `spam-use-gmane-xref'."
+  :type 'string
+  :group 'spam)
+
+(defcustom spam-blackhole-servers '("bl.spamcop.net" "relays.ordb.org"
+                                    "dev.null.dk" "relays.visi.com")
+  "List of blackhole servers.
+Only meaningful if you enable `spam-use-blackholes'."
+  :type '(repeat (string :tag "Server"))
+  :group 'spam)
+
+(defcustom spam-blackhole-good-server-regex nil
+  "String matching IP addresses that should not be checked in the blackholes.
+Only meaningful if you enable `spam-use-blackholes'."
+  :type '(radio (const nil) regexp)
+  :group 'spam)
+
+(defface spam
+  '((((class color) (type tty) (background dark))
+     (:foreground "gray80" :background "gray50"))
+    (((class color) (type tty) (background light))
+     (:foreground "gray50" :background "gray80"))
+    (((class color) (background dark))
+     (:foreground "ivory2"))
+    (((class color) (background light))
+     (:foreground "ivory4"))
+    (t :inverse-video t))
+  "Face for spam-marked articles."
+  :group 'spam)
+;; backward-compatibility alias
+(put 'spam-face 'face-alias 'spam)
+(put 'spam-face 'obsolete-face "22.1")
+
+(defcustom spam-face 'spam
+  "Face for spam-marked articles."
+  :type 'face
+  :group 'spam)
+
+(defcustom spam-regex-headers-spam '("^X-Spam-Flag: YES")
+  "Regular expression for positive header spam matches.
+Only meaningful if you enable `spam-use-regex-headers'."
+  :type '(repeat (regexp :tag "Regular expression to match spam header"))
+  :group 'spam)
+
+(defcustom spam-regex-headers-ham '("^X-Spam-Flag: NO")
+  "Regular expression for positive header ham matches.
+Only meaningful if you enable `spam-use-regex-headers'."
+  :type '(repeat (regexp :tag "Regular expression to match ham header"))
+  :group 'spam)
+
+(defcustom spam-regex-body-spam '()
+  "Regular expression for positive body spam matches.
+Only meaningful if you enable `spam-use-regex-body'."
+  :type '(repeat (regexp :tag "Regular expression to match spam body"))
+  :group 'spam)
+
+(defcustom spam-regex-body-ham '()
+  "Regular expression for positive body ham matches.
+Only meaningful if you enable `spam-use-regex-body'."
+  :type '(repeat (regexp :tag "Regular expression to match ham body"))
+  :group 'spam)
+
+(defcustom spam-summary-score-preferred-header nil
+  "Preferred header to use for `spam-summary-score'."
+  :type '(choice :tag "Header name"
+          (symbol :tag "SpamAssassin etc" X-Spam-Status)
+          (symbol :tag "Bogofilter"       X-Bogosity)
+          (const  :tag "No preference, take best guess." nil))
+  :group 'spam)
+
+(defgroup spam-ifile nil
+  "Spam ifile configuration."
+  :group 'spam)
+
+(make-obsolete-variable 'spam-ifile-path 'spam-ifile-program
+                        "Gnus 5.10.9 (Emacs 22.1)")
+(defcustom spam-ifile-program (executable-find "ifile")
+  "Name of the ifile program."
+  :type '(choice (file :tag "Location of ifile")
+                 (const :tag "ifile is not installed"))
+  :group 'spam-ifile)
+
+(make-obsolete-variable 'spam-ifile-database-path 'spam-ifile-database
+                        "Gnus 5.10.9 (Emacs 22.1)")
+(defcustom spam-ifile-database nil
+  "File name of the ifile database."
+  :type '(choice (file :tag "Location of the ifile database")
+                 (const :tag "Use the default"))
+  :group 'spam-ifile)
+
+(defcustom spam-ifile-spam-category "spam"
+  "Name of the spam ifile category."
+  :type 'string
+  :group 'spam-ifile)
+
+(defcustom spam-ifile-ham-category nil
+  "Name of the ham ifile category.
+If nil, the current group name will be used."
+  :type '(choice (string :tag "Use a fixed category")
+                 (const :tag "Use the current group name"))
+  :group 'spam-ifile)
+
+(defcustom spam-ifile-all-categories nil
+  "Whether the ifile check will return all categories, or just spam.
+Set this to t if you want to use the `spam-split' invocation of ifile as
+your main source of newsgroup names."
+  :type 'boolean
+  :group 'spam-ifile)
+
+(defgroup spam-bogofilter nil
+  "Spam bogofilter configuration."
+  :group 'spam)
+
+(make-obsolete-variable 'spam-bogofilter-path 'spam-bogofilter-program
+                        "Gnus 5.10.9 (Emacs 22.1)")
+(defcustom spam-bogofilter-program (executable-find "bogofilter")
+  "Name of the Bogofilter program."
+  :type '(choice (file :tag "Location of bogofilter")
+                 (const :tag "Bogofilter is not installed"))
+  :group 'spam-bogofilter)
+
+(defvar spam-bogofilter-valid 'unknown "Is the bogofilter version valid?")
+
+(defcustom spam-bogofilter-header "X-Bogosity"
+  "The header that Bogofilter inserts in messages."
+  :type 'string
+  :group 'spam-bogofilter)
+
+(defcustom spam-bogofilter-spam-switch "-s"
+  "The switch that Bogofilter uses to register spam messages."
+  :type 'string
+  :group 'spam-bogofilter)
+
+(defcustom spam-bogofilter-ham-switch "-n"
+  "The switch that Bogofilter uses to register ham messages."
+  :type 'string
+  :group 'spam-bogofilter)
+
+(defcustom spam-bogofilter-spam-strong-switch "-S"
+  "The switch that Bogofilter uses to unregister ham messages."
+  :type 'string
+  :group 'spam-bogofilter)
+
+(defcustom spam-bogofilter-ham-strong-switch "-N"
+  "The switch that Bogofilter uses to unregister spam messages."
+  :type 'string
+  :group 'spam-bogofilter)
+
+(defcustom spam-bogofilter-bogosity-positive-spam-header "^\\(Yes\\|Spam\\)"
+  "The regex on `spam-bogofilter-header' for positive spam identification."
+  :type 'regexp
+  :group 'spam-bogofilter)
+
+(defcustom spam-bogofilter-database-directory nil
+  "Location of the Bogofilter database.
+When nil, use the default location."
+  :type '(choice (directory
+                  :tag "Location of the Bogofilter database directory")
+                 (const :tag "Use the default"))
+  :group 'spam-bogofilter)
+
+(defgroup spam-bsfilter nil
+  "Spam bsfilter configuration."
+  :group 'spam)
+
+(make-obsolete-variable 'spam-bsfilter-path 'spam-bsfilter-program
+                        "Gnus 5.10.9 (Emacs 22.1)")
+(defcustom spam-bsfilter-program (executable-find "bsfilter")
+  "Name of the Bsfilter program."
+  :type '(choice (file :tag "Location of bsfilter")
+                 (const :tag "Bsfilter is not installed"))
+  :group 'spam-bsfilter)
+
+(defcustom spam-bsfilter-header "X-Spam-Flag"
+  "The header inserted by Bsfilter to flag spam."
+  :type 'string
+  :group 'spam-bsfilter)
+
+(defcustom spam-bsfilter-probability-header "X-Spam-Probability"
+  "The header that Bsfilter inserts in messages."
+  :type 'string
+  :group 'spam-bsfilter)
+
+(defcustom spam-bsfilter-spam-switch "--add-spam"
+  "The switch that Bsfilter uses to register spam messages."
+  :type 'string
+  :group 'spam-bsfilter)
+
+(defcustom spam-bsfilter-ham-switch "--add-clean"
+  "The switch that Bsfilter uses to register ham messages."
+  :type 'string
+  :group 'spam-bsfilter)
+
+(defcustom spam-bsfilter-spam-strong-switch "--sub-spam"
+  "The switch that Bsfilter uses to unregister ham messages."
+  :type 'string
+  :group 'spam-bsfilter)
+
+(defcustom spam-bsfilter-ham-strong-switch "--sub-clean"
+  "The switch that Bsfilter uses to unregister spam messages."
+  :type 'string
+  :group 'spam-bsfilter)
+
+(defcustom spam-bsfilter-database-directory nil
+  "Directory path of the Bsfilter databases."
+  :type '(choice (directory
+                  :tag "Location of the Bsfilter database directory")
+                 (const :tag "Use the default"))
+  :group 'spam-bsfilter)
+
+(defgroup spam-spamoracle nil
+  "Spam spamoracle configuration."
+  :group 'spam)
+
+(defcustom spam-spamoracle-database nil
+  "Location of spamoracle database file.
+When nil, use the default spamoracle database."
+  :type '(choice (directory :tag "Location of spamoracle database file.")
+                 (const :tag "Use the default"))
+  :group 'spam-spamoracle)
+
+(defcustom spam-spamoracle-binary (executable-find "spamoracle")
+  "Location of the spamoracle binary."
+  :type '(choice (directory :tag "Location of the spamoracle binary")
+                 (const :tag "Use the default"))
+  :group 'spam-spamoracle)
+
+(defgroup spam-spamassassin nil
+  "Spam SpamAssassin configuration."
+  :group 'spam)
+
+(make-obsolete-variable 'spam-spamassassin-path
+  'spam-spamassassin-program "Gnus 5.10.9 (Emacs 22.1)")
+(defcustom spam-assassin-program (executable-find "spamassassin")
+  "Name of the spamassassin program.
+Hint: set this to \"spamc\" if you have spamd running.  See the spamc and
+spamd man pages for more information on these programs."
+  :type '(choice (file :tag "Location of spamc")
+                 (const :tag "spamassassin is not installed"))
+  :group 'spam-spamassassin)
+
+(defcustom spam-spamassassin-arguments ()
+  "Arguments to pass to the spamassassin executable.
+This must be a list.  For example, `(\"-C\" \"configfile\")'."
+  :type '(restricted-sexp :match-alternatives (listp))
+  :group 'spam-spamassassin)
+
+(defcustom spam-spamassassin-spam-flag-header "X-Spam-Flag"
+  "The header inserted by SpamAssassin to flag spam."
+  :type 'string
+  :group 'spam-spamassassin)
+
+(defcustom spam-spamassassin-positive-spam-flag-header "YES"
+  "The regex on `spam-spamassassin-spam-flag-header' for positive spam
+identification"
+  :type 'string
+  :group 'spam-spamassassin)
+
+(defcustom spam-spamassassin-spam-status-header "X-Spam-Status"
+  "The header inserted by SpamAssassin, giving extended scoring information"
+  :type 'string
+  :group 'spam-spamassassin)
+
+(make-obsolete-variable 'spam-sa-learn-path 'spam-sa-learn-program
+                        "Gnus 5.10.9 (Emacs 22.1)")
+(defcustom spam-sa-learn-program (executable-find "sa-learn")
+  "Name of the sa-learn program."
+  :type '(choice (file :tag "Location of spamassassin")
+                 (const :tag "spamassassin is not installed"))
+  :group 'spam-spamassassin)
+
+(defcustom spam-sa-learn-rebuild t
+  "Whether sa-learn should rebuild the database every time it is called
+Enable this if you want sa-learn to rebuild the database automatically.  Doing
+this will slightly increase the running time of the spam registration process.
+If you choose not to do this, you will have to run \"sa-learn --rebuild\" in
+order for SpamAssassin to recognize the new registered spam."
+  :type 'boolean
+  :group 'spam-spamassassin)
+
+(defcustom spam-sa-learn-spam-switch "--spam"
+  "The switch that sa-learn uses to register spam messages."
+  :type 'string
+  :group 'spam-spamassassin)
+
+(defcustom spam-sa-learn-ham-switch "--ham"
+  "The switch that sa-learn uses to register ham messages."
+  :type 'string
+  :group 'spam-spamassassin)
+
+(defcustom spam-sa-learn-unregister-switch "--forget"
+  "The switch that sa-learn uses to unregister messages messages."
+  :type 'string
+  :group 'spam-spamassassin)
+
+(defgroup spam-crm114 nil
+  "Spam CRM114 Mailfilter configuration."
+  :group 'spam)
+
+(defcustom spam-crm114-program (executable-find "mailfilter.crm")
+  "File path of the CRM114 Mailfilter executable program."
+  :type '(choice (file :tag "Location of CRM114 Mailfilter")
+         (const :tag "CRM114 Mailfilter is not installed"))
+  :group 'spam-crm114)
+
+(defcustom spam-crm114-header "X-CRM114-Status"
+  "The header that CRM114 Mailfilter inserts in messages."
+  :type 'string
+  :group 'spam-crm114)
+
+(defcustom spam-crm114-spam-switch "--learnspam"
+  "The switch that CRM114 Mailfilter uses to register spam messages."
+  :type 'string
+  :group 'spam-crm114)
+
+(defcustom spam-crm114-ham-switch "--learnnonspam"
+  "The switch that CRM114 Mailfilter uses to register ham messages."
+  :type 'string
+  :group 'spam-crm114)
+
+(defcustom spam-crm114-spam-strong-switch "--unlearn"
+  "The switch that CRM114 Mailfilter uses to unregister ham messages."
+  :type 'string
+  :group 'spam-crm114)
+
+(defcustom spam-crm114-ham-strong-switch "--unlearn"
+  "The switch that CRM114 Mailfilter uses to unregister spam messages."
+  :type 'string
+  :group 'spam-crm114)
+
+(defcustom spam-crm114-positive-spam-header "^SPAM"
+  "The regex on `spam-crm114-header' for positive spam identification."
+  :type 'regexp
+  :group 'spam-crm114)
+
+(defcustom spam-crm114-database-directory nil
+  "Directory path of the CRM114 Mailfilter databases."
+  :type '(choice (directory
+          :tag "Location of the CRM114 Mailfilter database directory")
+         (const :tag "Use the default"))
+  :group 'spam-crm114)
+
+;;; Key bindings for spam control.
+
+(gnus-define-keys gnus-summary-mode-map
+  "St" spam-generic-score
+  "Sx" gnus-summary-mark-as-spam
+  "Mst" spam-generic-score
+  "Msx" gnus-summary-mark-as-spam
+  "\M-d" gnus-summary-mark-as-spam
+  "$" gnus-summary-mark-as-spam)
+
+(defvar spam-cache-lookups t
+  "Whether spam.el will try to cache lookups using `spam-caches'.")
+
+(defvar spam-caches (make-hash-table
+                     :size 10
+                     :test 'equal)
+  "Cache of spam detection entries.")
+
+(defvar spam-old-articles nil
+  "List of old ham and spam articles, generated when a group is entered.")
+
+(defvar spam-split-disabled nil
+  "If non-nil, `spam-split' is disabled, and always returns nil.")
+
+(defvar spam-split-last-successful-check nil
+  "Internal variable.
+`spam-split' will set this to nil or a spam-use-XYZ check if it
+finds ham or spam.")
+
+;; internal variables for backends
+;; TODO: find a way to create these on the fly in spam-install-backend-super
+(defvar spam-use-copy nil)
+(defvar spam-use-move nil)
+(defvar spam-use-gmane nil)
+(defvar spam-use-resend nil)
+
+;;}}}
+
+;;{{{ convenience functions
+
+(defun spam-clear-cache (symbol)
+  "Clear the `spam-caches' entry for a check."
+  (remhash symbol spam-caches))
+
+(defun spam-xor (a b)
+  "Logical A xor B."
+  (and (or a b) (not (and a b))))
+
+(defun spam-set-difference (list1 list2)
+  "Return a set difference of LIST1 and LIST2.
+When either list is nil, the other is returned."
+  (if (and list1 list2)
+      ;; we have two non-nil lists
+      (progn
+        (dolist (item (append list1 list2))
+          (when (and (memq item list1) (memq item list2))
+            (setq list1 (delq item list1))
+            (setq list2 (delq item list2))))
+        (append list1 list2))
+    ;; if either of the lists was nil, return the other one
+    (if list1 list1 list2)))
+
+(defun spam-group-ham-mark-p (group mark &optional spam)
+  "Checks if MARK is considered a ham mark in GROUP."
+  (when (stringp group)
+    (let* ((marks (spam-group-ham-marks group spam))
+           (marks (if (symbolp mark)
+                      marks
+                    (mapcar 'symbol-value marks))))
+      (memq mark marks))))
+
+(defun spam-group-spam-mark-p (group mark)
+  "Checks if MARK is considered a spam mark in GROUP."
+  (spam-group-ham-mark-p group mark t))
+
+(defun spam-group-ham-marks (group &optional spam)
+  "In GROUP, get all the ham marks."
+  (when (stringp group)
+    (let* ((marks (if spam
+                      (gnus-parameter-spam-marks group)
+                    (gnus-parameter-ham-marks group)))
+           (marks (car marks))
+           (marks (if (listp (car marks)) (car marks) marks)))
+      marks)))
+
+(defun spam-group-spam-marks (group)
+  "In GROUP, get all the spam marks."
+  (spam-group-ham-marks group t))
+
+(defun spam-group-spam-contents-p (group)
+  "Is GROUP a spam group?"
+  (if (and (stringp group) (< 0 (length group)))
+      (or (member group spam-junk-mailgroups)
+          (memq 'gnus-group-spam-classification-spam
+                (gnus-parameter-spam-contents group)))
+    nil))
+
+(defun spam-group-ham-contents-p (group)
+  "Is GROUP a ham group?"
+  (if (stringp group)
+      (memq 'gnus-group-spam-classification-ham
+            (gnus-parameter-spam-contents group))
+    nil))
+
+(defun spam-classifications ()
+  "Return list of valid classifications"
+  '(spam ham))
+
+(defun spam-classification-valid-p (classification)
+  "Is CLASSIFICATION a valid spam/ham classification?"
+  (memq classification (spam-classifications)))
+
+(defun spam-backend-properties ()
+  "Return list of valid classifications."
+  '(statistical mover check hrf srf huf suf))
+
+(defun spam-backend-property-valid-p (property)
+  "Is PROPERTY a valid backend property?"
+  (memq property (spam-backend-properties)))
+
+(defun spam-backend-function-type-valid-p (type)
+  (or (eq type 'registration)
+      (eq type 'unregistration)))
+
+(defun spam-process-type-valid-p (process-type)
+  (or (eq process-type 'incoming)
+      (eq process-type 'process)))
+
+(defun spam-list-articles (articles classification)
+  (let ((mark-check (if (eq classification 'spam)
+                        'spam-group-spam-mark-p
+                      'spam-group-ham-mark-p))
+        alist mark-cache-yes mark-cache-no)
+    (dolist (article articles)
+      (let ((mark (gnus-summary-article-mark article)))
+        (unless (or (memq mark mark-cache-yes)
+                    (memq mark mark-cache-no))
+          (if (funcall mark-check
+                       gnus-newsgroup-name
+                       mark)
+              (push mark mark-cache-yes)
+            (push mark mark-cache-no)))
+        (when (memq mark mark-cache-yes)
+          (push article alist))))
+    alist))
+
+;;}}}
+
+;;{{{ backend installation functions and procedures
+
+(defun spam-install-backend-super (backend &rest properties)
+  "Install BACKEND for spam.el.
+Accepts incoming CHECK, ham registration function HRF, spam
+registration function SRF, ham unregistration function HUF, spam
+unregistration function SUF, and an indication whether the
+backend is STATISTICAL."
+  (setq spam-backends (add-to-list 'spam-backends backend))
+  (while properties
+    (let ((property (pop properties))
+          (value (pop properties)))
+      (if (spam-backend-property-valid-p property)
+          (put backend property value)
+        (gnus-error
+         5
+         "spam-install-backend-super got an invalid property %s"
+         property)))))
+
+(defun spam-backend-list (&optional type)
+  "Return a list of all the backend symbols, constrained by TYPE.
+When TYPE is 'non-mover, only non-mover backends are returned.
+When TYPE is 'mover, only mover backends are returned."
+  (let (list)
+    (dolist (backend spam-backends)
+      (when (or
+             (null type)                ;either no type was requested
+             ;; or the type is 'mover and the backend is a mover
+             (and
+              (eq type 'mover)
+              (spam-backend-mover-p backend))
+             ;; or the type is 'non-mover and the backend is not a mover
+             (and
+              (eq type 'non-mover)
+              (not (spam-backend-mover-p backend))))
+        (push backend list)))
+      list))
+
+(defun spam-backend-check (backend)
+  "Get the check function for BACKEND.
+Each individual check may return nil, t, or a mailgroup name.
+The value nil means that the check does not yield a decision, and
+so, that further checks are needed.  The value t means that the
+message is definitely not spam, and that further spam checks
+should be inhibited.  Otherwise, a mailgroup name or the symbol
+'spam (depending on `spam-split-symbolic-return') is returned where
+the mail should go, and further checks are also inhibited.  The
+usual mailgroup name is the value of `spam-split-group', meaning
+that the message is definitely a spam."
+  (get backend 'check))
+
+(defun spam-backend-valid-p (backend)
+  "Is BACKEND valid?"
+  (member backend (spam-backend-list)))
+
+(defun spam-backend-info (backend)
+  "Return information about BACKEND."
+  (if (spam-backend-valid-p backend)
+      (let (info)
+        (setq info (format "Backend %s has the following properties:\n"
+                           backend))
+        (dolist (property (spam-backend-properties))
+          (setq info (format "%s%s=%s\n"
+                             info
+                             property
+                             (get backend property))))
+        info)
+    (gnus-error 5 "spam-backend-info was asked about an invalid backend %s"
+                backend)))
+
+(defun spam-backend-function (backend classification type)
+  "Get the BACKEND function for CLASSIFICATION and TYPE.
+TYPE is 'registration or 'unregistration.
+CLASSIFICATION is 'ham or 'spam."
+  (if (and
+       (spam-classification-valid-p classification)
+       (spam-backend-function-type-valid-p type))
+      (let ((retrieval
+             (intern
+              (format "spam-backend-%s-%s-function"
+                      classification
+                      type))))
+        (funcall retrieval backend))
+    (gnus-error
+     5
+     "%s was passed invalid backend %s, classification %s, or type %s"
+     "spam-backend-function"
+     backend
+     classification
+     type)))
+
+(defun spam-backend-article-list-property (classification
+                                           &optional unregister)
+  "Property name of article list with CLASSIFICATION and UNREGISTER."
+  (let* ((r (if unregister "unregister" "register"))
+         (prop (format "%s-%s" classification r)))
+    prop))
+
+(defun spam-backend-get-article-todo-list (backend
+                                           classification
+                                           &optional unregister)
+  "Get the articles to be processed for BACKEND and CLASSIFICATION.
+With UNREGISTER, get articles to be unregistered.
+This is a temporary storage function - nothing here persists."
+  (get
+   backend
+   (intern (spam-backend-article-list-property classification unregister))))
+
+(defun spam-backend-put-article-todo-list (backend classification list
+                                                   &optional unregister)
+  "Set the LIST of articles to be processed for BACKEND and CLASSIFICATION.
+With UNREGISTER, set articles to be unregistered.
+This is a temporary storage function - nothing here persists."
+  (put
+   backend
+   (intern (spam-backend-article-list-property classification unregister))
+   list))
+
+(defun spam-backend-ham-registration-function (backend)
+  "Get the ham registration function for BACKEND."
+  (get backend 'hrf))
+
+(defun spam-backend-spam-registration-function (backend)
+  "Get the spam registration function for BACKEND."
+  (get backend 'srf))
+
+(defun spam-backend-ham-unregistration-function (backend)
+  "Get the ham unregistration function for BACKEND."
+  (get backend 'huf))
+
+(defun spam-backend-spam-unregistration-function (backend)
+  "Get the spam unregistration function for BACKEND."
+  (get backend 'suf))
+
+(defun spam-backend-statistical-p (backend)
+  "Is BACKEND statistical?"
+  (get backend 'statistical))
+
+(defun spam-backend-mover-p (backend)
+  "Is BACKEND a mover?"
+  (get backend 'mover))
+
+(defun spam-install-backend-alias (backend alias)
+  "Add ALIAS to an existing BACKEND.
+The previous backend settings for ALIAS are erased."
+
+  ;; install alias with no properties at first
+  (spam-install-backend-super alias)
+
+  (dolist (property (spam-backend-properties))
+    (put alias property (get backend property))))
+
+(defun spam-install-checkonly-backend (backend check)
+  "Install a BACKEND than can only CHECK for spam."
+  (spam-install-backend-super backend 'check check))
+
+(defun spam-install-mover-backend (backend hrf srf huf suf)
+  "Install a BACKEND than can move articles at summary exit.
+Accepts ham registration function HRF, spam registration function
+SRF, ham unregistration function HUF, spam unregistration
+function SUF.  The backend has no incoming check and can't be
+statistical."
+  (spam-install-backend-super
+   backend
+   'hrf hrf 'srf srf 'huf huf 'suf suf 'mover t))
+
+(defun spam-install-nocheck-backend (backend hrf srf huf suf)
+  "Install a BACKEND than has no check.
+Accepts ham registration function HRF, spam registration function
+SRF, ham unregistration function HUF, spam unregistration
+function SUF.  The backend has no incoming check and can't be
+statistical (it could be, but in practice that doesn't happen)."
+  (spam-install-backend-super
+   backend
+   'hrf hrf 'srf srf 'huf huf 'suf suf))
+
+(defun spam-install-backend (backend check hrf srf huf suf)
+  "Install a BACKEND.
+Accepts incoming CHECK, ham registration function HRF, spam
+registration function SRF, ham unregistration function HUF, spam
+unregistration function SUF.  The backend won't be
+statistical (use `spam-install-statistical-backend' for that)."
+  (spam-install-backend-super
+   backend
+   'check check 'hrf hrf 'srf srf 'huf huf 'suf suf))
+
+(defun spam-install-statistical-backend (backend check hrf srf huf suf)
+  "Install a BACKEND.
+Accepts incoming CHECK, ham registration function HRF, spam
+registration function SRF, ham unregistration function HUF, spam
+unregistration function SUF.  The backend will be
+statistical (use `spam-install-backend' for non-statistical
+backends)."
+  (spam-install-backend-super
+   backend
+   'check check 'statistical t 'hrf hrf 'srf srf 'huf huf 'suf suf))
+
+(defun spam-install-statistical-checkonly-backend (backend check)
+  "Install a statistical BACKEND than can only CHECK for spam."
+  (spam-install-backend-super
+   backend
+   'check check 'statistical t))
+
+;;}}}
+
+;;{{{ backend installations
+(spam-install-checkonly-backend 'spam-use-blackholes
+                                'spam-check-blackholes)
+
+(spam-install-checkonly-backend 'spam-use-hashcash
+                                'spam-check-hashcash)
+
+(spam-install-checkonly-backend 'spam-use-spamassassin-headers
+                                'spam-check-spamassassin-headers)
+
+(spam-install-checkonly-backend 'spam-use-bogofilter-headers
+                                'spam-check-bogofilter-headers)
+
+(spam-install-checkonly-backend 'spam-use-bsfilter-headers
+                                'spam-check-bsfilter-headers)
+
+(spam-install-checkonly-backend 'spam-use-gmane-xref
+                                'spam-check-gmane-xref)
+
+(spam-install-checkonly-backend 'spam-use-regex-headers
+                                'spam-check-regex-headers)
+
+(spam-install-statistical-checkonly-backend 'spam-use-regex-body
+                                            'spam-check-regex-body)
+
+;; TODO: NOTE: spam-use-ham-copy is now obsolete, use (ham spam-use-copy)
+(spam-install-mover-backend 'spam-use-move
+                            'spam-move-ham-routine
+                            'spam-move-spam-routine
+                            nil
+                            nil)
+
+(spam-install-nocheck-backend 'spam-use-copy
+                              'spam-copy-ham-routine
+                              'spam-copy-spam-routine
+                              nil
+                              nil)
+
+(spam-install-nocheck-backend 'spam-use-gmane
+                              'spam-report-gmane-unregister-routine
+                              'spam-report-gmane-register-routine
+                              'spam-report-gmane-register-routine
+                              'spam-report-gmane-unregister-routine)
+
+(spam-install-nocheck-backend 'spam-use-resend
+                              'spam-report-resend-register-ham-routine
+                              'spam-report-resend-register-routine
+                              nil
+                              nil)
+
+(spam-install-backend 'spam-use-BBDB
+                      'spam-check-BBDB
+                      'spam-BBDB-register-routine
+                      nil
+                      'spam-BBDB-unregister-routine
+                      nil)
+
+(spam-install-backend-alias 'spam-use-BBDB 'spam-use-BBDB-exclusive)
+
+(spam-install-backend 'spam-use-blacklist
+                      'spam-check-blacklist
+                      nil
+                      'spam-blacklist-register-routine
+                      nil
+                      'spam-blacklist-unregister-routine)
+
+(spam-install-backend 'spam-use-whitelist
+                      'spam-check-whitelist
+                      'spam-whitelist-register-routine
+                      nil
+                      'spam-whitelist-unregister-routine
+                      nil)
+
+(spam-install-statistical-backend 'spam-use-ifile
+                                  'spam-check-ifile
+                                  'spam-ifile-register-ham-routine
+                                  'spam-ifile-register-spam-routine
+                                  'spam-ifile-unregister-ham-routine
+                                  'spam-ifile-unregister-spam-routine)
+
+(spam-install-statistical-backend 'spam-use-spamoracle
+                                  'spam-check-spamoracle
+                                  'spam-spamoracle-learn-ham
+                                  'spam-spamoracle-learn-spam
+                                  'spam-spamoracle-unlearn-ham
+                                  'spam-spamoracle-unlearn-spam)
+
+(spam-install-statistical-backend 'spam-use-stat
+                                  'spam-check-stat
+                                  'spam-stat-register-ham-routine
+                                  'spam-stat-register-spam-routine
+                                  'spam-stat-unregister-ham-routine
+                                  'spam-stat-unregister-spam-routine)
+
+(spam-install-statistical-backend 'spam-use-spamassassin
+                                  'spam-check-spamassassin
+                                  'spam-spamassassin-register-ham-routine
+                                  'spam-spamassassin-register-spam-routine
+                                  'spam-spamassassin-unregister-ham-routine
+                                  'spam-spamassassin-unregister-spam-routine)
+
+(spam-install-statistical-backend 'spam-use-bogofilter
+                                  'spam-check-bogofilter
+                                  'spam-bogofilter-register-ham-routine
+                                  'spam-bogofilter-register-spam-routine
+                                  'spam-bogofilter-unregister-ham-routine
+                                  'spam-bogofilter-unregister-spam-routine)
+
+(spam-install-statistical-backend 'spam-use-bsfilter
+                                  'spam-check-bsfilter
+                                  'spam-bsfilter-register-ham-routine
+                                  'spam-bsfilter-register-spam-routine
+                                  'spam-bsfilter-unregister-ham-routine
+                                  'spam-bsfilter-unregister-spam-routine)
+
+(spam-install-statistical-backend 'spam-use-crm114
+                                  'spam-check-crm114
+                                  'spam-crm114-register-ham-routine
+                                  'spam-crm114-register-spam-routine
+                                  'spam-crm114-unregister-ham-routine
+                                  'spam-crm114-unregister-spam-routine)
+;;}}}
+
+;;{{{ scoring and summary formatting
+(defun spam-necessary-extra-headers ()
+  "Return the extra headers spam.el thinks are necessary."
+  (let (list)
+    (when (or spam-use-spamassassin
+              spam-use-spamassassin-headers
+              spam-use-regex-headers)
+      (push 'X-Spam-Status list))
+    (when (or spam-use-bogofilter
+              spam-use-regex-headers)
+      (push 'X-Bogosity list))
+    (when (or spam-use-crm114
+              spam-use-regex-headers)
+      (push 'X-CRM114-Status list))
+    list))
+
+(defun spam-user-format-function-S (headers)
+  (when headers
+    (format "%3.2f"
+            (spam-summary-score headers spam-summary-score-preferred-header))))
+
+(defun spam-article-sort-by-spam-status (h1 h2)
+  "Sort articles by score."
+  (let (result)
+    (dolist (header (spam-necessary-extra-headers))
+      (let ((s1 (spam-summary-score h1 header))
+            (s2 (spam-summary-score h2 header)))
+      (unless (= s1 s2)
+        (setq result (< s1 s2))
+        (return))))
+    result))
+
+(defvar spam-spamassassin-score-regexp
+  ".*\\b\\(?:score\\|hits\\)=\\(-?[0-9.]+\\)"
+  "Regexp matching SpamAssassin score header.
+The first group must match the number.")
+
+(defun spam-extra-header-to-number (header headers)
+  "Transform an extra HEADER to a number, using list of HEADERS.
+Note this has to be fast."
+  (let ((header-content (gnus-extra-header header headers)))
+    (if header-content
+        (cond
+         ((eq header 'X-Spam-Status)
+          (string-to-number (gnus-replace-in-string
+                             header-content
+                             spam-spamassassin-score-regexp
+                             "\\1")))
+         ;; for CRM checking, it's probably faster to just do the string match
+         ((string-match "( pR: \\([0-9.-]+\\)" header-content)
+          (- (string-to-number (match-string 1 header-content))))
+         ((eq header 'X-Bogosity)
+          (string-to-number (gnus-replace-in-string
+                             (gnus-replace-in-string
+                              header-content
+                              ".*spamicity=" "")
+                             ",.*" "")))
+         (t nil))
+      nil)))
+
+(defun spam-summary-score (headers &optional specific-header)
+  "Score an article for the summary buffer, as fast as possible.
+With SPECIFIC-HEADER, returns only that header's score.
+Will not return a nil score."
+  (let (score)
+    (dolist (header
+             (if specific-header
+                 (list specific-header)
+               (spam-necessary-extra-headers)))
+      (setq score
+            (spam-extra-header-to-number header headers))
+      (when score
+        (return)))
+    (or score 0)))
+
+(defun spam-generic-score (&optional recheck)
+  "Invoke whatever scoring method we can."
+  (interactive "P")
+  (cond
+   ((or spam-use-spamassassin spam-use-spamassassin-headers)
+    (spam-spamassassin-score recheck))
+   ((or spam-use-bsfilter spam-use-bsfilter-headers)
+    (spam-bsfilter-score recheck))
+   (spam-use-crm114
+    (spam-crm114-score))
+   (t (spam-bogofilter-score recheck))))
+;;}}}
+
+;;{{{ set up widening, processor checks
+
+;;; set up IMAP widening if it's necessary
+(defun spam-setup-widening ()
+  (when (spam-widening-needed-p)
+    (setq nnimap-split-download-body-default t)))
+
+(defun spam-widening-needed-p (&optional force-symbols)
+  (let (found)
+    (dolist (backend (spam-backend-list))
+      (when (and (spam-backend-statistical-p backend)
+                 (or (symbol-value backend)
+                     (memq backend force-symbols)))
+        (setq found backend)))
+    found))
+
+(defvar spam-list-of-processors
+  ;; note the nil processors are not defined in gnus.el
+  '((gnus-group-spam-exit-processor-bogofilter   spam spam-use-bogofilter)
+    (gnus-group-spam-exit-processor-bsfilter     spam spam-use-bsfilter)
+    (gnus-group-spam-exit-processor-blacklist    spam spam-use-blacklist)
+    (gnus-group-spam-exit-processor-ifile        spam spam-use-ifile)
+    (gnus-group-spam-exit-processor-stat         spam spam-use-stat)
+    (gnus-group-spam-exit-processor-spamoracle   spam spam-use-spamoracle)
+    (gnus-group-spam-exit-processor-spamassassin spam spam-use-spamassassin)
+    (gnus-group-spam-exit-processor-report-gmane spam spam-use-gmane) ;; Buggy?
+    (gnus-group-ham-exit-processor-ifile         ham spam-use-ifile)
+    (gnus-group-ham-exit-processor-bogofilter    ham spam-use-bogofilter)
+    (gnus-group-ham-exit-processor-bsfilter      ham spam-use-bsfilter)
+    (gnus-group-ham-exit-processor-stat          ham spam-use-stat)
+    (gnus-group-ham-exit-processor-whitelist     ham spam-use-whitelist)
+    (gnus-group-ham-exit-processor-BBDB          ham spam-use-BBDB)
+    (gnus-group-ham-exit-processor-copy          ham spam-use-ham-copy)
+    (gnus-group-ham-exit-processor-spamassassin  ham spam-use-spamassassin)
+    (gnus-group-ham-exit-processor-spamoracle    ham spam-use-spamoracle))
+  "The OBSOLETE `spam-list-of-processors' list.
+This list contains pairs associating the obsolete ham/spam exit
+processor variables with a classification and a spam-use-*
+variable.  When the processor variable is nil, just the
+classification and spam-use-* check variable are used.  This is
+superseded by the new spam backend code, so it's only consulted
+for backwards compatibility.")
+(make-obsolete-variable 'spam-list-of-processors nil "22.1")
+
+(defun spam-group-processor-p (group backend &optional classification)
+  "Checks if GROUP has a BACKEND with CLASSIFICATION registered.
+Also accepts the obsolete processors, which can be found in
+gnus.el and in spam-list-of-processors.  In the case of mover
+backends, checks the setting of `spam-summary-exit-behavior' in
+addition to the set values for the group."
+  (if (and (stringp group)
+           (symbolp backend))
+      (let ((old-style (assq backend spam-list-of-processors))
+            (parameters (nth 0 (gnus-parameter-spam-process group)))
+            found)
+        (if old-style  ; old-style processor
+            (spam-group-processor-p group (nth 2 old-style) (nth 1 old-style))
+          ;; now search for the parameter
+          (dolist (parameter parameters)
+            (when (and (null found)
+                       (listp parameter)
+                       (eq classification (nth 0 parameter))
+                       (eq backend (nth 1 parameter)))
+              (setq found t)))
+
+          ;; now, if the parameter was not found, do the
+          ;; spam-summary-exit-behavior-logic for mover backends
+          (unless found
+            (when (spam-backend-mover-p backend)
+              (setq
+               found
+               (cond
+                ((eq spam-summary-exit-behavior 'move-all) t)
+                ((eq spam-summary-exit-behavior 'move-none) nil)
+                ((eq spam-summary-exit-behavior 'default)
+                 (or (eq classification 'spam) ;move spam out of all groups
+                     ;; move ham out of spam groups
+                     (and (eq classification 'ham)
+                          (spam-group-spam-contents-p group))))
+                (t (gnus-error 5 "Unknown spam-summary-exit-behavior: %s"
+                               spam-summary-exit-behavior))))))
+
+          found))
+    nil))
+
+;;}}}
+
+;;{{{ Summary entry and exit processing.
+
+(defun spam-mark-junk-as-spam-routine ()
+  ;; check the global list of group names spam-junk-mailgroups and the
+  ;; group parameters
+  (when (spam-group-spam-contents-p gnus-newsgroup-name)
+    (gnus-message 6 "Marking %s articles as spam"
+                  (if spam-mark-only-unseen-as-spam
+                      "unseen"
+                    "unread"))
+    (let ((articles (if spam-mark-only-unseen-as-spam
+                        gnus-newsgroup-unseen
+                      gnus-newsgroup-unreads)))
+      (if spam-mark-new-messages-in-spam-group-as-spam
+          (dolist (article articles)
+            (gnus-summary-mark-article article gnus-spam-mark))
+        (gnus-message 9 "Did not mark new messages as spam.")))))
+
+(defun spam-summary-prepare ()
+  (setq spam-old-articles
+        (list (cons 'ham (spam-list-articles gnus-newsgroup-articles 'ham))
+              (cons 'spam (spam-list-articles gnus-newsgroup-articles 'spam))))
+  (spam-mark-junk-as-spam-routine))
+
+;; The spam processors are invoked for any group, spam or ham or neither
+(defun spam-summary-prepare-exit ()
+  (unless gnus-group-is-exiting-without-update-p
+    (gnus-message 6 "Exiting summary buffer and applying spam rules")
+
+    ;; before we begin, remove any article limits
+;    (ignore-errors
+;      (gnus-summary-pop-limit t))
+
+    ;; first of all, unregister any articles that are no longer ham or spam
+    ;; we have to iterate over the processors, or else we'll be too slow
+    (dolist (classification (spam-classifications))
+      (let* ((old-articles (cdr-safe (assq classification spam-old-articles)))
+             (new-articles (spam-list-articles
+                            gnus-newsgroup-articles
+                            classification))
+             (changed-articles (spam-set-difference new-articles old-articles)))
+        ;; now that we have the changed articles, we go through the processors
+        (dolist (backend (spam-backend-list))
+          (let (unregister-list)
+            (dolist (article changed-articles)
+              (let ((id (spam-fetch-field-message-id-fast article)))
+                (when (spam-log-unregistration-needed-p
+                       id 'process classification backend)
+                  (push article unregister-list))))
+            ;; call spam-register-routine with specific articles to unregister,
+            ;; when there are articles to unregister and the check is enabled
+            (when (and unregister-list (symbol-value backend))
+              (spam-backend-put-article-todo-list backend
+                                                  classification
+                                                  unregister-list
+                                                  t))))))
+
+    ;; do the non-moving backends first, then the moving ones
+    (dolist (backend-type '(non-mover mover))
+      (dolist (classification (spam-classifications))
+        (dolist (backend (spam-backend-list backend-type))
+          (when (spam-group-processor-p
+                 gnus-newsgroup-name
+                 backend
+                 classification)
+            (spam-backend-put-article-todo-list backend
+                                                classification
+                                                (spam-list-articles
+                                                 gnus-newsgroup-articles
+                                                 classification))))))
+
+    (spam-resolve-registrations-routine) ; do the registrations now
+
+    ;; we mark all the leftover spam articles as expired at the end
+    (dolist (article (spam-list-articles
+                      gnus-newsgroup-articles
+                      'spam))
+      (gnus-summary-mark-article article gnus-expirable-mark)))
+
+  (setq spam-old-articles nil))
+
+;;}}}
+
+;;{{{ spam-use-move and spam-use-copy backend support functions
+
+(defun spam-copy-or-move-routine (copy groups articles classification)
+
+  (when (and (car-safe groups) (listp (car-safe groups)))
+    (setq groups (pop groups)))
+
+  (unless (listp groups)
+    (setq groups (list groups)))
+
+    ;; remove the current process mark
+  (gnus-summary-kill-process-mark)
+
+  (let ((backend-supports-deletions
+         (gnus-check-backend-function
+          'request-move-article gnus-newsgroup-name))
+        (respool-method (gnus-find-method-for-group gnus-newsgroup-name))
+        article mark deletep respool valid-move-destinations)
+
+    (when (member 'respool groups)
+      (setq respool t)                  ; boolean for later
+      (setq groups '("fake"))) ; when respooling, groups are dynamic so fake it
+
+    ;; exclude invalid move destinations
+    (dolist (group groups)
+      (unless
+          (or
+           (and
+            (eq classification 'spam)
+            (spam-group-spam-contents-p gnus-newsgroup-name)
+            (spam-group-spam-contents-p group)
+            (gnus-message
+             3
+             "Sorry, can't move spam from spam group %s to spam group %s"
+             gnus-newsgroup-name
+             group))
+           (and
+            (eq classification 'ham)
+            (spam-group-ham-contents-p gnus-newsgroup-name)
+            (spam-group-ham-contents-p group)
+            (gnus-message
+             3
+             "Sorry, can't move ham from ham group %s to ham group %s"
+             gnus-newsgroup-name
+             group)))
+        (push group valid-move-destinations)))
+
+    (setq groups (nreverse valid-move-destinations))
+
+    ;; now do the actual move
+    (dolist (group groups)
+
+      (when (and articles (stringp group))
+
+        ;; first, mark the article with the process mark and, if needed,
+        ;; the unread or expired mark (for ham and spam respectively)
+        (dolist (article articles)
+          (when (and (eq classification 'ham)
+                     spam-mark-ham-unread-before-move-from-spam-group)
+            (gnus-message 9 "Marking ham article %d unread before move"
+                          article)
+            (gnus-summary-mark-article article gnus-unread-mark))
+          (when (and (eq classification 'spam)
+                     (not copy))
+            (gnus-message 9 "Marking spam article %d expirable before move"
+                          article)
+            (gnus-summary-mark-article article gnus-expirable-mark))
+          (gnus-summary-set-process-mark article)
+
+          (if respool              ; respooling is with a "fake" group
+              (let ((spam-split-disabled
+                     (or spam-split-disabled
+                         (and (eq classification 'ham)
+                              spam-disable-spam-split-during-ham-respool))))
+                (gnus-message 9 "Respooling article %d with method %s"
+                              article respool-method)
+                (gnus-summary-respool-article nil respool-method))
+            ;; else, we are not respooling
+            (if (or (not backend-supports-deletions)
+                    (> (length groups) 1))
+                (progn              ; if copying, copy and set deletep
+                  (gnus-message 9 "Copying article %d to group %s"
+                                article group)
+                  (gnus-summary-copy-article nil group)
+                  (setq deletep t))
+              (gnus-message 9 "Moving article %d to group %s"
+                            article group)
+              (gnus-summary-move-article nil group)))))) ; else move articles
+
+    ;; now delete the articles, unless a) copy is t, and there was a copy done
+    ;;                                 b) a move was done to a single group
+    ;;                                 c) backend-supports-deletions is nil
+    (unless copy
+      (when (and deletep backend-supports-deletions)
+       (dolist (article articles)
+         (gnus-summary-set-process-mark article)
+         (gnus-message 9 "Deleting article %d" article))
+       (when articles
+         (let ((gnus-novice-user nil)) ; don't ask me if I'm sure
+           (gnus-summary-delete-article nil)))))
+    (gnus-summary-yank-process-mark)
+    (length articles)))
+
+(defun spam-copy-spam-routine (articles)
+  (spam-copy-or-move-routine
+   t
+   (gnus-parameter-spam-process-destination gnus-newsgroup-name)
+   articles
+   'spam))
+
+(defun spam-move-spam-routine (articles)
+  (spam-copy-or-move-routine
+   nil
+   (gnus-parameter-spam-process-destination gnus-newsgroup-name)
+   articles
+   'spam))
+
+(defun spam-copy-ham-routine (articles)
+  (spam-copy-or-move-routine
+   t
+   (gnus-parameter-ham-process-destination gnus-newsgroup-name)
+   articles
+   'ham))
+
+(defun spam-move-ham-routine (articles)
+  (spam-copy-or-move-routine
+   nil
+   (gnus-parameter-ham-process-destination gnus-newsgroup-name)
+   articles
+   'ham))
+
+;;}}}
+
+;;{{{ article and field retrieval code
+(defun spam-get-article-as-string (article)
+  (when (numberp article)
+    (with-temp-buffer
+      (gnus-request-article-this-buffer
+       article
+       gnus-newsgroup-name)
+      (buffer-string))))
+
+;; disabled for now
+;; (defun spam-get-article-as-filename (article)
+;;   (let ((article-filename))
+;;     (when (numberp article)
+;;       (nnml-possibly-change-directory
+;;        (gnus-group-real-name gnus-newsgroup-name))
+;;       (setq article-filename (expand-file-name
+;;                              (int-to-string article) nnml-current-directory)))
+;;     (if (file-exists-p article-filename)
+;;      article-filename
+;;       nil)))
+
+(defun spam-fetch-field-fast (article field &optional prepared-data-header)
+  "Fetch a FIELD for ARTICLE with the internal `gnus-data-list' function.
+When PREPARED-DATA-HEADER is given, don't look in the Gnus data.
+When FIELD is 'number, ARTICLE can be any number (since we want
+to find it out)."
+  (when (numberp article)
+    (let* ((data-header (or prepared-data-header
+                            (spam-fetch-article-header article))))
+      (cond
+       ((not (arrayp data-header))
+        (gnus-message 6 "Article %d has a nil data header" article))
+       ((equal field 'number)
+       (mail-header-number data-header))
+       ((equal field 'from)
+       (mail-header-from data-header))
+       ((equal field 'message-id)
+       (mail-header-message-id data-header))
+       ((equal field 'subject)
+       (mail-header-subject data-header))
+       ((equal field 'references)
+       (mail-header-references data-header))
+       ((equal field 'date)
+       (mail-header-date data-header))
+       ((equal field 'xref)
+       (mail-header-xref data-header))
+       ((equal field 'extra)
+       (mail-header-extra data-header))
+       (t
+       (gnus-error
+        5
+        "spam-fetch-field-fast: unknown field %s requested"
+        field)
+       nil)))))
+
+(defun spam-fetch-field-from-fast (article &optional prepared-data-header)
+  (spam-fetch-field-fast article 'from prepared-data-header))
+
+(defun spam-fetch-field-subject-fast (article &optional prepared-data-header)
+  (spam-fetch-field-fast article 'subject prepared-data-header))
+
+(defun spam-fetch-field-message-id-fast (article &optional prepared-data-header)
+  (spam-fetch-field-fast article 'message-id prepared-data-header))
+
+(defun spam-generate-fake-headers (article)
+  (let ((dh (spam-fetch-article-header article)))
+    (if dh
+        (concat
+         (format
+          ;; 80-character limit makes for strange constructs
+          (concat "From: %s\nSubject: %s\nMessage-ID: %s\n"
+                  "Date: %s\nReferences: %s\nXref: %s\n")
+          (spam-fetch-field-fast article 'from dh)
+          (spam-fetch-field-fast article 'subject dh)
+          (spam-fetch-field-fast article 'message-id dh)
+          (spam-fetch-field-fast article 'date dh)
+          (spam-fetch-field-fast article 'references dh)
+          (spam-fetch-field-fast article 'xref dh))
+         (when (spam-fetch-field-fast article 'extra dh)
+           (format "%s\n" (spam-fetch-field-fast article 'extra dh))))
+      (gnus-message
+       5
+       "spam-generate-fake-headers: article %d didn't have a valid header"
+       article))))
+
+(defun spam-fetch-article-header (article)
+  (with-current-buffer gnus-summary-buffer
+    (gnus-read-header article)
+    (nth 3 (assq article gnus-newsgroup-data))))
+;;}}}
+
+;;{{{ Spam determination.
+
+(defun spam-split (&rest specific-checks)
+  "Split this message into the `spam' group if it is spam.
+This function can be used as an entry in the variable `nnmail-split-fancy',
+for example like this: (: spam-split).  It can take checks as
+parameters.  A string as a parameter will set the
+`spam-split-group' to that string.
+
+See the Info node `(gnus)Fancy Mail Splitting' for more details."
+  (interactive)
+  (setq spam-split-last-successful-check nil)
+  (unless spam-split-disabled
+    (let ((spam-split-group-choice spam-split-group))
+      (dolist (check specific-checks)
+        (when (stringp check)
+          (setq spam-split-group-choice check)
+          (setq specific-checks (delq check specific-checks))))
+
+      (let ((spam-split-group spam-split-group-choice)
+            (widening-needed-check (spam-widening-needed-p specific-checks)))
+        (save-excursion
+          (save-restriction
+            (when widening-needed-check
+              (widen)
+              (gnus-message 8 "spam-split: widening the buffer (%s requires it)"
+                            widening-needed-check))
+            (let ((backends (spam-backend-list))
+                  decision)
+              (while (and backends (not decision))
+                (let* ((backend (pop backends))
+                       (check-function (spam-backend-check backend))
+                       (spam-split-group (if spam-split-symbolic-return
+                                             'spam
+                                           spam-split-group)))
+                  (when (or
+                         ;; either, given specific checks, this is one of them
+                         (memq backend specific-checks)
+                         ;; or, given no specific checks, spam-use-CHECK is set
+                         (and (null specific-checks) (symbol-value backend)))
+                    (gnus-message 6 "spam-split: calling the %s function"
+                                  check-function)
+                    (setq decision (funcall check-function))
+                    ;; if we got a decision at all, save the current check
+                    (when decision
+                      (setq spam-split-last-successful-check backend))
+
+                    (when (eq decision 'spam)
+                      (unless spam-split-symbolic-return
+                        (gnus-error
+                         5
+                         (format "spam-split got %s but %s is nil"
+                                 decision
+                                 spam-split-symbolic-return)))))))
+              (if (eq decision t)
+                  (if spam-split-symbolic-return-positive 'ham nil)
+                decision))))))))
+
+(defun spam-find-spam ()
+  "Detect spam in the current newsgroup using `spam-split'."
+  (interactive)
+
+  (let* ((group gnus-newsgroup-name)
+         (autodetect (gnus-parameter-spam-autodetect group))
+         (methods (gnus-parameter-spam-autodetect-methods group))
+         (first-method (nth 0 methods))
+         (articles (if spam-autodetect-recheck-messages
+                       gnus-newsgroup-articles
+                     gnus-newsgroup-unseen))
+         article-cannot-be-faked)
+
+
+    (dolist (backend methods)
+      (when (spam-backend-statistical-p backend)
+        (setq article-cannot-be-faked t)
+        (return)))
+
+    (when (memq 'default methods)
+      (setq article-cannot-be-faked t))
+
+    (when (and autodetect
+               (not (equal first-method 'none)))
+      (mapcar
+       (lambda (article)
+         (let ((id (spam-fetch-field-message-id-fast article))
+               (subject (spam-fetch-field-subject-fast article))
+               (sender (spam-fetch-field-from-fast article))
+               registry-lookup)
+
+           (unless id
+             (gnus-message 6 "Article %d has no message ID!" article))
+
+           (when (and id spam-log-to-registry)
+             (setq registry-lookup (spam-log-registration-type id 'incoming))
+             (when registry-lookup
+               (gnus-message
+                9
+                "spam-find-spam: message %s was already registered incoming"
+                id)))
+
+           (let* ((spam-split-symbolic-return t)
+                  (spam-split-symbolic-return-positive t)
+                  (fake-headers (spam-generate-fake-headers article))
+                  (split-return
+                   (or registry-lookup
+                       (with-temp-buffer
+                         (if article-cannot-be-faked
+                             (gnus-request-article-this-buffer
+                              article
+                              group)
+                           ;; else, we fake the article
+                           (when fake-headers (insert fake-headers)))
+                         (if (or (null first-method)
+                                 (equal first-method 'default))
+                             (spam-split)
+                           (apply 'spam-split methods))))))
+             (if (equal split-return 'spam)
+                 (gnus-summary-mark-article article gnus-spam-mark))
+
+             (when (and id split-return spam-log-to-registry)
+               (when (zerop (gnus-registry-group-count id))
+                 (gnus-registry-handle-action id nil group subject sender))
+
+               (unless registry-lookup
+                 (spam-log-processing-to-registry
+                  id
+                  'incoming
+                  split-return
+                  spam-split-last-successful-check
+                  group))))))
+       articles))))
+
+;;}}}
+
+;;{{{ registration/unregistration functions
+
+(defun spam-resolve-registrations-routine ()
+  "Go through the backends and register or unregister articles as needed."
+  (dolist (backend-type '(non-mover mover))
+    (dolist (classification (spam-classifications))
+      (dolist (backend (spam-backend-list backend-type))
+        (let ((rlist (spam-backend-get-article-todo-list
+                      backend classification))
+              (ulist (spam-backend-get-article-todo-list
+                      backend classification t))
+              (delcount 0))
+
+          ;; clear the old lists right away
+          (spam-backend-put-article-todo-list backend
+                                              classification
+                                              nil
+                                              nil)
+          (spam-backend-put-article-todo-list backend
+                                              classification
+                                              nil
+                                              t)
+
+          ;; eliminate duplicates
+          (dolist (article (copy-sequence ulist))
+            (when (memq article rlist)
+              (incf delcount)
+              (setq rlist (delq article rlist))
+              (setq ulist (delq article ulist))))
+
+          (unless (zerop delcount)
+            (gnus-message
+             9
+             "%d messages did not have to unregister and then register"
+             delcount))
+
+          ;; unregister articles
+          (unless (zerop (length ulist))
+            (let ((num (spam-unregister-routine classification backend ulist)))
+              (when (> num 0)
+                (gnus-message
+                 6
+                 "%d %s messages were unregistered by backend %s."
+                 num
+                 classification
+                 backend))))
+
+            ;; register articles
+            (unless (zerop (length rlist))
+              (let ((num (spam-register-routine classification backend rlist)))
+                (when (> num 0)
+                  (gnus-message
+                   6
+                   "%d %s messages were registered by backend %s."
+                   num
+                   classification
+                   backend)))))))))
+
+(defun spam-unregister-routine (classification
+                                backend
+                                specific-articles)
+  (spam-register-routine classification backend specific-articles t))
+
+(defun spam-register-routine (classification
+                              backend
+                              specific-articles
+                              &optional unregister)
+  (when (and (spam-classification-valid-p classification)
+             (spam-backend-valid-p backend))
+    (let* ((register-function
+            (spam-backend-function backend classification 'registration))
+           (unregister-function
+            (spam-backend-function backend classification 'unregistration))
+           (run-function (if unregister
+                             unregister-function
+                           register-function))
+           (log-function (if unregister
+                             'spam-log-undo-registration
+                           'spam-log-processing-to-registry))
+           article articles)
+
+      (when run-function
+        ;; make list of articles, using specific-articles if given
+        (setq articles (or specific-articles
+                           (spam-list-articles
+                            gnus-newsgroup-articles
+                            classification)))
+        ;; process them
+        (when (> (length articles) 0)
+          (gnus-message 5 "%s %d %s articles as %s using backend %s"
+                        (if unregister "Unregistering" "Registering")
+                        (length articles)
+                        (if specific-articles "specific" "")
+                        classification
+                        backend)
+          (funcall run-function articles)
+          ;; now log all the registrations (or undo them, depending on
+          ;; unregister)
+          (dolist (article articles)
+            (funcall log-function
+                     (spam-fetch-field-message-id-fast article)
+                     'process
+                     classification
+                     backend
+                     gnus-newsgroup-name))))
+      ;; return the number of articles processed
+      (length articles))))
+
+;;; log a ham- or spam-processor invocation to the registry
+(defun spam-log-processing-to-registry (id type classification backend group)
+  (when spam-log-to-registry
+    (if (and (stringp id)
+             (stringp group)
+             (spam-process-type-valid-p type)
+             (spam-classification-valid-p classification)
+             (spam-backend-valid-p backend))
+        (let ((cell-list (gnus-registry-get-id-key id type))
+              (cell (list classification backend group)))
+          (push cell cell-list)
+          (gnus-registry-set-id-key id type cell-list))
+
+      (gnus-error
+       7
+       (format
+        "%s call with bad ID, type, classification, spam-backend, or group"
+        "spam-log-processing-to-registry")))))
+
+;;; check if a ham- or spam-processor registration has been done
+(defun spam-log-registered-p (id type)
+  (when spam-log-to-registry
+    (if (and (stringp id)
+             (spam-process-type-valid-p type))
+        (gnus-registry-get-id-key id type)
+      (progn
+        (gnus-error
+         7
+         (format "%s called with bad ID, type, classification, or spam-backend"
+                 "spam-log-registered-p"))
+        nil))))
+
+;;; check what a ham- or spam-processor registration says
+;;; returns nil if conflicting registrations are found
+(defun spam-log-registration-type (id type)
+  (let ((count 0)
+        decision)
+    (dolist (reg (spam-log-registered-p id type))
+      (let ((classification (nth 0 reg)))
+        (when (spam-classification-valid-p classification)
+          (when (and decision
+                     (not (eq classification decision)))
+            (setq count (+ 1 count)))
+          (setq decision classification))))
+    (if (< 0 count)
+        nil
+      decision)))
+
+
+;;; check if a ham- or spam-processor registration needs to be undone
+(defun spam-log-unregistration-needed-p (id type classification backend)
+  (when spam-log-to-registry
+    (if (and (stringp id)
+             (spam-process-type-valid-p type)
+             (spam-classification-valid-p classification)
+             (spam-backend-valid-p backend))
+        (let ((cell-list (gnus-registry-get-id-key id type))
+              found)
+          (dolist (cell cell-list)
+            (unless found
+              (when (and (eq classification (nth 0 cell))
+                         (eq backend (nth 1 cell)))
+                (setq found t))))
+          found)
+      (progn
+        (gnus-error
+         7
+         (format "%s called with bad ID, type, classification, or spam-backend"
+                 "spam-log-unregistration-needed-p"))
+        nil))))
+
+
+;;; undo a ham- or spam-processor registration (the group is not used)
+(defun spam-log-undo-registration (id type classification backend
+                                      &optional group)
+  (when (and spam-log-to-registry
+             (spam-log-unregistration-needed-p id type classification backend))
+    (if (and (stringp id)
+             (spam-process-type-valid-p type)
+             (spam-classification-valid-p classification)
+             (spam-backend-valid-p backend))
+        (let ((cell-list (gnus-registry-get-id-key id type))
+              new-cell-list found)
+          (dolist (cell cell-list)
+            (unless (and (eq classification (nth 0 cell))
+                         (eq backend (nth 1 cell)))
+              (push cell new-cell-list)))
+          (gnus-registry-set-id-key id type new-cell-list))
+      (progn
+        (gnus-error 7 (format
+                       "%s call with bad ID, type, spam-backend, or group"
+                       "spam-log-undo-registration"))
+        nil))))
+
+;;}}}
+
+;;{{{ backend functions
+
+;;{{{ Gmane xrefs
+(defun spam-check-gmane-xref ()
+  (let ((header (or
+                 (message-fetch-field "Xref")
+                 (message-fetch-field "Newsgroups"))))
+    (when header                        ; return nil when no header
+      (when (string-match spam-gmane-xref-spam-group
+                          header)
+          spam-split-group))))
+
+;;}}}
+
+;;{{{ Regex body
+
+(defun spam-check-regex-body ()
+  (let ((spam-regex-headers-ham spam-regex-body-ham)
+        (spam-regex-headers-spam spam-regex-body-spam))
+    (spam-check-regex-headers t)))
+
+;;}}}
+
+;;{{{ Regex headers
+
+(defun spam-check-regex-headers (&optional body)
+  (let ((type (if body "body" "header"))
+        ret found)
+    (dolist (h-regex spam-regex-headers-ham)
+      (unless found
+        (goto-char (point-min))
+        (when (re-search-forward h-regex nil t)
+          (message "Ham regex %s search positive." type)
+          (setq found t))))
+    (dolist (s-regex spam-regex-headers-spam)
+      (unless found
+        (goto-char (point-min))
+        (when (re-search-forward s-regex nil t)
+          (message "Spam regex %s search positive." type)
+          (setq found t)
+          (setq ret spam-split-group))))
+    ret))
+
+;;}}}
+
+;;{{{ Blackholes.
+
+(defun spam-reverse-ip-string (ip)
+  (when (stringp ip)
+    (mapconcat 'identity
+               (nreverse (split-string ip "\\."))
+               ".")))
+
+(defun spam-check-blackholes ()
+  "Check the Received headers for blackholed relays."
+  (let ((headers (message-fetch-field "received"))
+        ips matches)
+    (when headers
+      (with-temp-buffer
+        (insert headers)
+        (goto-char (point-min))
+        (gnus-message 6 "Checking headers for relay addresses")
+        (while (re-search-forward
+                "\\([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\)" nil t)
+          (gnus-message 9 "Blackhole search found host IP %s." (match-string 1))
+          (push (spam-reverse-ip-string (match-string 1))
+                ips)))
+      (dolist (server spam-blackhole-servers)
+        (dolist (ip ips)
+          (unless (and spam-blackhole-good-server-regex
+                       ;; match against the reversed (again) IP string
+                       (string-match
+                        spam-blackhole-good-server-regex
+                        (spam-reverse-ip-string ip)))
+            (unless matches
+              (let ((query-string (concat ip "." server)))
+                (if spam-use-dig
+                    (let ((query-result (query-dig query-string)))
+                      (when query-result
+                        (gnus-message 6 "(DIG): positive blackhole check `%s'"
+                                      query-result)
+                        (push (list ip server query-result)
+                              matches)))
+                  ;; else, if not using dig.el
+                  (when (dns-query query-string)
+                    (gnus-message 6 "positive blackhole check")
+                    (push (list ip server (dns-query query-string 'TXT))
+                          matches)))))))))
+    (when matches
+      spam-split-group)))
+;;}}}
+
+;;{{{ Hashcash.
+
+(defun spam-check-hashcash ()
+  "Check the headers for hashcash payments."
+  (ignore-errors (mail-check-payment)))  ;mail-check-payment returns a boolean
+
+;;}}}
+
+;;{{{ BBDB
+
+;;; original idea for spam-check-BBDB from Alexander Kotelnikov
+;;; <sacha@giotto.sj.ru>
+
+;; all this is done inside a condition-case to trap errors
+
+;; Autoloaded in message, which we require.
+(declare-function gnus-extract-address-components "gnus-util" (from))
+
+(eval-and-compile
+  (condition-case nil
+      (progn
+       (require 'bbdb)
+       (require 'bbdb-com))
+    (file-error
+     ;; `bbdb-records' should not be bound as an autoload function
+     ;; before loading bbdb because of `bbdb-hashtable-size'.
+     (defalias 'bbdb-buffer 'ignore)
+     (defalias 'bbdb-create-internal 'ignore)
+     (defalias 'bbdb-records 'ignore)
+     (defalias 'spam-BBDB-register-routine 'ignore)
+     (defalias 'spam-enter-ham-BBDB 'ignore)
+     (defalias 'spam-exists-in-BBDB-p 'ignore)
+     (defalias 'bbdb-gethash 'ignore)
+     nil)))
+
+(eval-and-compile
+  (when (featurep 'bbdb-com)
+    ;; when the BBDB changes, we want to clear out our cache
+    (defun spam-clear-cache-BBDB (&rest immaterial)
+      (spam-clear-cache 'spam-use-BBDB))
+
+    (add-hook 'bbdb-change-hook 'spam-clear-cache-BBDB)
+
+    (defun spam-enter-ham-BBDB (addresses &optional remove)
+      "Enter an address into the BBDB; implies ham (non-spam) sender"
+      (dolist (from addresses)
+        (when (stringp from)
+          (let* ((parsed-address (gnus-extract-address-components from))
+                 (name (or (nth 0 parsed-address) "Ham Sender"))
+                 (remove-function (if remove
+                                      'bbdb-delete-record-internal
+                                    'ignore))
+                 (net-address (nth 1 parsed-address))
+                 (record (and net-address
+                              (spam-exists-in-BBDB-p net-address))))
+            (when net-address
+              (gnus-message 6 "%s address %s %s BBDB"
+                            (if remove "Deleting" "Adding")
+                            from
+                            (if remove "from" "to"))
+              (if record
+                  (funcall remove-function record)
+                (bbdb-create-internal name nil net-address nil nil
+                                      "ham sender added by spam.el")))))))
+
+    (defun spam-BBDB-register-routine (articles &optional unregister)
+      (let (addresses)
+        (dolist (article articles)
+          (when (stringp (spam-fetch-field-from-fast article))
+            (push (spam-fetch-field-from-fast article) addresses)))
+        ;; now do the register/unregister action
+        (spam-enter-ham-BBDB addresses unregister)))
+
+    (defun spam-BBDB-unregister-routine (articles)
+      (spam-BBDB-register-routine articles t))
+
+    (defsubst spam-exists-in-BBDB-p (net)
+      (when (and (stringp net) (not (zerop (length net))))
+        (bbdb-records)
+        (bbdb-gethash (downcase net))))
+
+    (defun spam-check-BBDB ()
+      "Mail from people in the BBDB is classified as ham or non-spam"
+      (let ((net (message-fetch-field "from")))
+        (when net
+          (setq net (nth 1 (gnus-extract-address-components net)))
+          (if (spam-exists-in-BBDB-p net)
+              t
+            (if spam-use-BBDB-exclusive
+                spam-split-group
+              nil)))))))
+
+;;}}}
+
+;;{{{ ifile
+
+;;; check the ifile backend; return nil if the mail was NOT classified
+;;; as spam
+
+
+(defun spam-get-ifile-database-parameter ()
+  "Return the command-line parameter for ifile's database.
+See `spam-ifile-database'."
+  (if spam-ifile-database
+      (format "--db-file=%s" spam-ifile-database)
+    nil))
+
+(defun spam-check-ifile ()
+  "Check the ifile backend for the classification of this message."
+  (let ((article-buffer-name (buffer-name))
+        category return)
+    (with-temp-buffer
+      (let ((temp-buffer-name (buffer-name))
+            (db-param (spam-get-ifile-database-parameter)))
+        (with-current-buffer article-buffer-name
+          (apply 'call-process-region
+                 (point-min) (point-max) spam-ifile-program
+                 nil temp-buffer-name nil "-c"
+                 (if db-param `(,db-param "-q") `("-q"))))
+        ;; check the return now (we're back in the temp buffer)
+        (goto-char (point-min))
+        (if (not (eobp))
+            (setq category (buffer-substring (point) (point-at-eol))))
+        (when (not (zerop (length category))) ; we need a category here
+          (if spam-ifile-all-categories
+              (setq return category)
+            ;; else, if spam-ifile-all-categories is not set...
+            (when (string-equal spam-ifile-spam-category category)
+              (setq return spam-split-group)))))) ; note return is nil otherwise
+    return))
+
+(defun spam-ifile-register-with-ifile (articles category &optional unregister)
+  "Register an article, given as a string, with a category.
+Uses `gnus-newsgroup-name' if category is nil (for ham registration)."
+  (let ((category (or category gnus-newsgroup-name))
+        (add-or-delete-option (if unregister "-d" "-i"))
+        (db (spam-get-ifile-database-parameter))
+        parameters)
+    (with-temp-buffer
+      (dolist (article articles)
+        (let ((article-string (spam-get-article-as-string article)))
+          (when (stringp article-string)
+            (insert article-string))))
+      (apply 'call-process-region
+             (point-min) (point-max) spam-ifile-program
+             nil nil nil
+             add-or-delete-option category
+             (if db `(,db "-h") `("-h"))))))
+
+(defun spam-ifile-register-spam-routine (articles &optional unregister)
+  (spam-ifile-register-with-ifile articles spam-ifile-spam-category unregister))
+
+(defun spam-ifile-unregister-spam-routine (articles)
+  (spam-ifile-register-spam-routine articles t))
+
+(defun spam-ifile-register-ham-routine (articles &optional unregister)
+  (spam-ifile-register-with-ifile articles spam-ifile-ham-category unregister))
+
+(defun spam-ifile-unregister-ham-routine (articles)
+  (spam-ifile-register-ham-routine articles t))
+
+;;}}}
+
+;;{{{ spam-stat
+
+(require 'spam-stat)
+
+(defun spam-check-stat ()
+  "Check the spam-stat backend for the classification of this message"
+  (let ((spam-stat-split-fancy-spam-group spam-split-group) ; override
+       (spam-stat-buffer (buffer-name)) ; stat the current buffer
+       category return)
+    (spam-stat-split-fancy)))
+
+(defun spam-stat-register-spam-routine (articles &optional unregister)
+  (dolist (article articles)
+    (let ((article-string (spam-get-article-as-string article)))
+      (with-temp-buffer
+       (insert article-string)
+       (if unregister
+           (spam-stat-buffer-change-to-non-spam)
+         (spam-stat-buffer-is-spam))))))
+
+(defun spam-stat-unregister-spam-routine (articles)
+  (spam-stat-register-spam-routine articles t))
+
+(defun spam-stat-register-ham-routine (articles &optional unregister)
+  (dolist (article articles)
+    (let ((article-string (spam-get-article-as-string article)))
+      (with-temp-buffer
+       (insert article-string)
+       (if unregister
+           (spam-stat-buffer-change-to-spam)
+         (spam-stat-buffer-is-non-spam))))))
+
+(defun spam-stat-unregister-ham-routine (articles)
+  (spam-stat-register-ham-routine articles t))
+
+(defun spam-maybe-spam-stat-load ()
+  (when spam-use-stat (spam-stat-load)))
+
+(defun spam-maybe-spam-stat-save ()
+  (when spam-use-stat (spam-stat-save)))
+
+;;}}}
+
+;;{{{ Blacklists and whitelists.
+
+(defvar spam-whitelist-cache nil)
+(defvar spam-blacklist-cache nil)
+
+(defun spam-kill-whole-line ()
+  (beginning-of-line)
+  (let ((kill-whole-line t))
+    (kill-line)))
+
+;;; address can be a list, too
+(defun spam-enter-whitelist (address &optional remove)
+  "Enter ADDRESS (list or single) into the whitelist.
+With a non-nil REMOVE, remove them."
+  (interactive "sAddress: ")
+  (spam-enter-list address spam-whitelist remove)
+  (setq spam-whitelist-cache nil)
+  (spam-clear-cache 'spam-use-whitelist))
+
+;;; address can be a list, too
+(defun spam-enter-blacklist (address &optional remove)
+  "Enter ADDRESS (list or single) into the blacklist.
+With a non-nil REMOVE, remove them."
+  (interactive "sAddress: ")
+  (spam-enter-list address spam-blacklist remove)
+  (setq spam-blacklist-cache nil)
+  (spam-clear-cache 'spam-use-whitelist))
+
+(defun spam-enter-list (addresses file &optional remove)
+  "Enter ADDRESSES into the given FILE.
+Either the whitelist or the blacklist files can be used.
+With a non-nil REMOVE, remove the ADDRESSES."
+  (if (stringp addresses)
+      (spam-enter-list (list addresses) file remove)
+    ;; else, we have a list of addresses here
+    (unless (file-exists-p (file-name-directory file))
+      (make-directory (file-name-directory file) t))
+    (with-current-buffer
+       (find-file-noselect file)
+      (dolist (a addresses)
+        (when (stringp a)
+          (goto-char (point-min))
+          (if (re-search-forward (regexp-quote a) nil t)
+              ;; found the address
+              (when remove
+                (spam-kill-whole-line))
+            ;; else, the address was not found
+            (unless remove
+              (goto-char (point-max))
+              (unless (bobp)
+                (insert "\n"))
+              (insert a "\n")))))
+      (save-buffer))))
+
+(defun spam-filelist-build-cache (type)
+  (let ((cache (if (eq type 'spam-use-blacklist)
+                   spam-blacklist-cache
+                 spam-whitelist-cache))
+        parsed-cache)
+    (unless (gethash type spam-caches)
+      (while cache
+        (let ((address (pop cache)))
+          (unless (zerop (length address)) ; 0 for a nil address too
+            (setq address (regexp-quote address))
+            ;; fix regexp-quote's treatment of user-intended regexes
+            (while (string-match "\\\\\\*" address)
+              (setq address (replace-match ".*" t t address))))
+          (push address parsed-cache)))
+      (puthash type parsed-cache spam-caches))))
+
+(defun spam-filelist-check-cache (type from)
+  (when (stringp from)
+    (spam-filelist-build-cache type)
+    (let (found)
+      (dolist (address (gethash type spam-caches))
+        (when (and address (string-match address from))
+          (setq found t)
+          (return)))
+      found)))
+
+;;; returns t if the sender is in the whitelist, nil or
+;;; spam-split-group otherwise
+(defun spam-check-whitelist ()
+  ;; FIXME!  Should it detect when file timestamps change?
+  (unless spam-whitelist-cache
+    (setq spam-whitelist-cache (spam-parse-list spam-whitelist)))
+  (if (spam-from-listed-p 'spam-use-whitelist)
+      t
+    (if spam-use-whitelist-exclusive
+        spam-split-group
+      nil)))
+
+(defun spam-check-blacklist ()
+  ;; FIXME!  Should it detect when file timestamps change?
+  (unless spam-blacklist-cache
+    (setq spam-blacklist-cache (spam-parse-list spam-blacklist)))
+  (and (spam-from-listed-p 'spam-use-blacklist)
+       spam-split-group))
+
+(defun spam-parse-list (file)
+  (when (file-readable-p file)
+    (let (contents address)
+      (with-temp-buffer
+        (insert-file-contents file)
+        (while (not (eobp))
+          (setq address (buffer-substring (point) (point-at-eol)))
+          (forward-line 1)
+          ;; insert the e-mail address if detected, otherwise the raw data
+          (unless (zerop (length address))
+            (let ((pure-address
+                   (nth 1 (gnus-extract-address-components address))))
+              (push (or pure-address address) contents)))))
+      (nreverse contents))))
+
+(defun spam-from-listed-p (type)
+  (let ((from (message-fetch-field "from"))
+        found)
+    (spam-filelist-check-cache type from)))
+
+(defun spam-filelist-register-routine (articles blacklist &optional unregister)
+  (let ((de-symbol (if blacklist 'spam-use-whitelist 'spam-use-blacklist))
+        (declassification (if blacklist 'ham 'spam))
+        (enter-function
+         (if blacklist 'spam-enter-blacklist 'spam-enter-whitelist))
+        (remove-function
+         (if blacklist 'spam-enter-whitelist 'spam-enter-blacklist))
+        from addresses unregister-list article-unregister-list)
+    (dolist (article articles)
+      (let ((from (spam-fetch-field-from-fast article))
+            (id (spam-fetch-field-message-id-fast article))
+            sender-ignored)
+        (when (stringp from)
+          (dolist (ignore-regex spam-blacklist-ignored-regexes)
+            (when (and (not sender-ignored)
+                       (stringp ignore-regex)
+                       (string-match ignore-regex from))
+              (setq sender-ignored t)))
+          ;; remember the messages we need to unregister, unless remove is set
+          (when (and
+                 (null unregister)
+                 (spam-log-unregistration-needed-p
+                  id 'process declassification de-symbol))
+            (push article article-unregister-list)
+            (push from unregister-list))
+          (unless sender-ignored
+            (push from addresses)))))
+
+    (if unregister
+        (funcall enter-function addresses t) ; unregister all these addresses
+      ;; else, register normally and unregister what we need to
+      (funcall remove-function unregister-list t)
+      (dolist (article article-unregister-list)
+        (spam-log-undo-registration
+         (spam-fetch-field-message-id-fast article)
+         'process
+         declassification
+         de-symbol))
+      (funcall enter-function addresses nil))))
+
+(defun spam-blacklist-unregister-routine (articles)
+  (spam-blacklist-register-routine articles t))
+
+(defun spam-blacklist-register-routine (articles &optional unregister)
+  (spam-filelist-register-routine articles t unregister))
+
+(defun spam-whitelist-unregister-routine (articles)
+  (spam-whitelist-register-routine articles t))
+
+(defun spam-whitelist-register-routine (articles &optional unregister)
+  (spam-filelist-register-routine articles nil unregister))
+
+;;}}}
+
+;;{{{ Spam-report glue (gmane and resend reporting)
+(defun spam-report-gmane-register-routine (articles)
+  (when articles
+    (apply 'spam-report-gmane-spam articles)))
+
+(defun spam-report-gmane-unregister-routine (articles)
+  (when articles
+    (apply 'spam-report-gmane-ham articles)))
+
+(defun spam-report-resend-register-ham-routine (articles)
+  (spam-report-resend-register-routine articles t))
+
+(defvar spam-report-resend-to)
+
+(defun spam-report-resend-register-routine (articles &optional ham)
+  (require 'spam-report)
+  (let* ((resend-to-gp
+          (if ham
+              (gnus-parameter-ham-resend-to gnus-newsgroup-name)
+            (gnus-parameter-spam-resend-to gnus-newsgroup-name)))
+         (spam-report-resend-to (or (car-safe resend-to-gp)
+                                    spam-report-resend-to)))
+    (spam-report-resend articles ham)))
+
+;;}}}
+
+;;{{{ Bogofilter
+(defun spam-check-bogofilter-headers (&optional score)
+  (let ((header (message-fetch-field spam-bogofilter-header)))
+    (when header                        ; return nil when no header
+      (if score                         ; scoring mode
+          (if (string-match "spamicity=\\([0-9.]+\\)" header)
+              (match-string 1 header)
+            "0")
+        ;; spam detection mode
+        (when (string-match spam-bogofilter-bogosity-positive-spam-header
+                            header)
+          spam-split-group)))))
+
+;; return something sensible if the score can't be determined
+(defun spam-bogofilter-score (&optional recheck)
+  "Get the Bogofilter spamicity score."
+  (interactive "P")
+  (save-window-excursion
+    (gnus-summary-show-article t)
+    (set-buffer gnus-article-buffer)
+    (let ((score (or (unless recheck
+                       (spam-check-bogofilter-headers t))
+                     (spam-check-bogofilter t))))
+      (gnus-summary-show-article)
+      (message "Spamicity score %s" score)
+      (or score "0"))))
+
+(defun spam-verify-bogofilter ()
+  "Verify the Bogofilter version is sufficient."
+  (when (eq spam-bogofilter-valid 'unknown)
+    (setq spam-bogofilter-valid
+          (not (string-match "^bogofilter version 0\\.\\([0-9]\\|1[01]\\)\\."
+                             (shell-command-to-string
+                              (format "%s -V" spam-bogofilter-program))))))
+  spam-bogofilter-valid)
+
+(defun spam-check-bogofilter (&optional score)
+  "Check the Bogofilter backend for the classification of this message."
+  (if (spam-verify-bogofilter)
+      (let ((article-buffer-name (buffer-name))
+            (db spam-bogofilter-database-directory)
+            return)
+        (with-temp-buffer
+          (let ((temp-buffer-name (buffer-name)))
+            (with-current-buffer article-buffer-name
+              (apply 'call-process-region
+                     (point-min) (point-max)
+                     spam-bogofilter-program
+                     nil temp-buffer-name nil
+                     (if db `("-d" ,db "-v") `("-v"))))
+            (setq return (spam-check-bogofilter-headers score))))
+        return)
+    (gnus-error 5 "`spam.el' doesn't support obsolete bogofilter versions")))
+
+(defun spam-bogofilter-register-with-bogofilter (articles
+                                                 spam
+                                                 &optional unregister)
+  "Register an article, given as a string, as spam or non-spam."
+  (if (spam-verify-bogofilter)
+      (dolist (article articles)
+        (let ((article-string (spam-get-article-as-string article))
+              (db spam-bogofilter-database-directory)
+              (switch (if unregister
+                          (if spam
+                              spam-bogofilter-spam-strong-switch
+                            spam-bogofilter-ham-strong-switch)
+                        (if spam
+                            spam-bogofilter-spam-switch
+                          spam-bogofilter-ham-switch))))
+          (when (stringp article-string)
+            (with-temp-buffer
+              (insert article-string)
+
+              (apply 'call-process-region
+                     (point-min) (point-max)
+                     spam-bogofilter-program
+                     nil nil nil switch
+                     (if db `("-d" ,db "-v") `("-v")))))))
+    (gnus-error 5 "`spam.el' doesn't support obsolete bogofilter versions")))
+
+(defun spam-bogofilter-register-spam-routine (articles &optional unregister)
+  (spam-bogofilter-register-with-bogofilter articles t unregister))
+
+(defun spam-bogofilter-unregister-spam-routine (articles)
+  (spam-bogofilter-register-spam-routine articles t))
+
+(defun spam-bogofilter-register-ham-routine (articles &optional unregister)
+  (spam-bogofilter-register-with-bogofilter articles nil unregister))
+
+(defun spam-bogofilter-unregister-ham-routine (articles)
+  (spam-bogofilter-register-ham-routine articles t))
+
+
+;;}}}
+
+;;{{{ spamoracle
+(defun spam-check-spamoracle ()
+  "Run spamoracle on an article to determine whether it's spam."
+  (let ((article-buffer-name (buffer-name)))
+    (with-temp-buffer
+      (let ((temp-buffer-name (buffer-name)))
+        (with-current-buffer article-buffer-name
+          (let ((status
+                 (apply 'call-process-region
+                        (point-min) (point-max)
+                        spam-spamoracle-binary
+                        nil temp-buffer-name nil
+                        (if spam-spamoracle-database
+                            `("-f" ,spam-spamoracle-database "mark")
+                          '("mark")))))
+            (if (eq 0 status)
+                (progn
+                  (set-buffer temp-buffer-name)
+                  (goto-char (point-min))
+                  (when (re-search-forward "^X-Spam: yes;" nil t)
+                    spam-split-group))
+              (error "Error running spamoracle: %s" status))))))))
+
+(defun spam-spamoracle-learn (articles article-is-spam-p &optional unregister)
+  "Run spamoracle in training mode."
+  (with-temp-buffer
+    (let ((temp-buffer-name (buffer-name)))
+      (save-excursion
+        (goto-char (point-min))
+        (dolist (article articles)
+          (insert (spam-get-article-as-string article)))
+        (let* ((arg (if (spam-xor unregister article-is-spam-p)
+                        "-spam"
+                      "-good"))
+               (status
+                (apply 'call-process-region
+                       (point-min) (point-max)
+                       spam-spamoracle-binary
+                       nil temp-buffer-name nil
+                       (if spam-spamoracle-database
+                           `("-f" ,spam-spamoracle-database
+                             "add" ,arg)
+                         `("add" ,arg)))))
+          (unless (eq 0 status)
+            (error "Error running spamoracle: %s" status)))))))
+
+(defun spam-spamoracle-learn-ham (articles &optional unregister)
+  (spam-spamoracle-learn articles nil unregister))
+
+(defun spam-spamoracle-unlearn-ham (articles &optional unregister)
+  (spam-spamoracle-learn-ham articles t))
+
+(defun spam-spamoracle-learn-spam (articles &optional unregister)
+  (spam-spamoracle-learn articles t unregister))
+
+(defun spam-spamoracle-unlearn-spam (articles &optional unregister)
+  (spam-spamoracle-learn-spam articles t))
+
+;;}}}
+
+;;{{{ SpamAssassin
+;;; based mostly on the bogofilter code
+(defun spam-check-spamassassin-headers (&optional score)
+  "Check the SpamAssassin headers for the classification of this message."
+  (if score                             ; scoring mode
+      (let ((header (message-fetch-field spam-spamassassin-spam-status-header)))
+        (when header
+          (if (string-match spam-spamassassin-score-regexp header)
+              (match-string 1 header)
+            "0")))
+    ;; spam detection mode
+    (let ((header (message-fetch-field spam-spamassassin-spam-flag-header)))
+          (when header                  ; return nil when no header
+            (when (string-match spam-spamassassin-positive-spam-flag-header
+                                header)
+              spam-split-group)))))
+
+(defun spam-check-spamassassin (&optional score)
+  "Check the SpamAssassin backend for the classification of this message."
+  (let ((article-buffer-name (buffer-name)))
+    (with-temp-buffer
+      (let ((temp-buffer-name (buffer-name)))
+        (with-current-buffer article-buffer-name
+          (apply 'call-process-region
+                 (point-min) (point-max) spam-assassin-program
+                 nil temp-buffer-name nil spam-spamassassin-arguments))
+        ;; check the return now (we're back in the temp buffer)
+        (goto-char (point-min))
+        (spam-check-spamassassin-headers score)))))
+
+;; return something sensible if the score can't be determined
+(defun spam-spamassassin-score (&optional recheck)
+  "Get the SpamAssassin score"
+  (interactive "P")
+  (save-window-excursion
+    (gnus-summary-show-article t)
+    (set-buffer gnus-article-buffer)
+    (let ((score (or (unless recheck
+                       (spam-check-spamassassin-headers t))
+                     (spam-check-spamassassin t))))
+      (gnus-summary-show-article)
+      (message "SpamAssassin score %s" score)
+      (or score "0"))))
+
+(defun spam-spamassassin-register-with-sa-learn (articles spam
+                                                 &optional unregister)
+  "Register articles with spamassassin's sa-learn as spam or non-spam."
+  (if articles
+      (let ((action (if unregister spam-sa-learn-unregister-switch
+                      (if spam spam-sa-learn-spam-switch
+                        spam-sa-learn-ham-switch)))
+            (summary-buffer-name (buffer-name)))
+        (with-temp-buffer
+          ;; group the articles into mbox format
+          (dolist (article articles)
+            (let (article-string)
+              (with-current-buffer summary-buffer-name
+                (setq article-string (spam-get-article-as-string article)))
+              (when (stringp article-string)
+                ;; mbox separator
+                (insert (concat "From nobody " (current-time-string) "\n"))
+                (insert article-string)
+                (insert "\n"))))
+          ;; call sa-learn on all messages at the same time
+          (apply 'call-process-region
+                 (point-min) (point-max)
+                 spam-sa-learn-program
+                 nil nil nil "--mbox"
+                 (if spam-sa-learn-rebuild
+                     (list action)
+                   `("--no-rebuild" ,action)))))))
+
+(defun spam-spamassassin-register-spam-routine (articles &optional unregister)
+  (spam-spamassassin-register-with-sa-learn articles t unregister))
+
+(defun spam-spamassassin-register-ham-routine (articles &optional unregister)
+  (spam-spamassassin-register-with-sa-learn articles nil unregister))
+
+(defun spam-spamassassin-unregister-spam-routine (articles)
+  (spam-spamassassin-register-with-sa-learn articles t t))
+
+(defun spam-spamassassin-unregister-ham-routine (articles)
+  (spam-spamassassin-register-with-sa-learn articles nil t))
+
+;;}}}
+
+;;{{{ Bsfilter
+;;; based mostly on the bogofilter code
+(defun spam-check-bsfilter-headers (&optional score)
+  (if score
+      (or (nnmail-fetch-field spam-bsfilter-probability-header)
+          "0")
+    (let ((header (nnmail-fetch-field spam-bsfilter-header)))
+      (when header ; return nil when no header
+        (when (string-match "YES" header)
+          spam-split-group)))))
+
+;; return something sensible if the score can't be determined
+(defun spam-bsfilter-score (&optional recheck)
+  "Get the Bsfilter spamicity score."
+  (interactive "P")
+  (save-window-excursion
+    (gnus-summary-show-article t)
+    (set-buffer gnus-article-buffer)
+    (let ((score (or (unless recheck
+                       (spam-check-bsfilter-headers t))
+                     (spam-check-bsfilter t))))
+      (gnus-summary-show-article)
+      (message "Spamicity score %s" score)
+      (or score "0"))))
+
+(defun spam-check-bsfilter (&optional score)
+  "Check the Bsfilter backend for the classification of this message."
+  (let ((article-buffer-name (buffer-name))
+        (dir spam-bsfilter-database-directory)
+        return)
+    (with-temp-buffer
+      (let ((temp-buffer-name (buffer-name)))
+        (with-current-buffer article-buffer-name
+          (apply 'call-process-region
+                 (point-min) (point-max)
+                 spam-bsfilter-program
+                 nil temp-buffer-name nil
+                 "--pipe"
+                 "--insert-flag"
+                 "--insert-probability"
+                 (when dir
+                   (list "--homedir" dir))))
+        (setq return (spam-check-bsfilter-headers score))))
+    return))
+
+(defun spam-bsfilter-register-with-bsfilter (articles
+                                             spam
+                                             &optional unregister)
+  "Register an article, given as a string, as spam or non-spam."
+  (dolist (article articles)
+    (let ((article-string (spam-get-article-as-string article))
+          (switch (if unregister
+                      (if spam
+                          spam-bsfilter-spam-strong-switch
+                        spam-bsfilter-ham-strong-switch)
+                    (if spam
+                        spam-bsfilter-spam-switch
+                      spam-bsfilter-ham-switch))))
+      (when (stringp article-string)
+        (with-temp-buffer
+          (insert article-string)
+          (apply 'call-process-region
+                 (point-min) (point-max)
+                 spam-bsfilter-program
+                 nil nil nil switch
+                 "--update"
+                 (when spam-bsfilter-database-directory
+                   (list "--homedir"
+                         spam-bsfilter-database-directory))))))))
+
+(defun spam-bsfilter-register-spam-routine (articles &optional unregister)
+  (spam-bsfilter-register-with-bsfilter articles t unregister))
+
+(defun spam-bsfilter-unregister-spam-routine (articles)
+  (spam-bsfilter-register-spam-routine articles t))
+
+(defun spam-bsfilter-register-ham-routine (articles &optional unregister)
+  (spam-bsfilter-register-with-bsfilter articles nil unregister))
+
+(defun spam-bsfilter-unregister-ham-routine (articles)
+  (spam-bsfilter-register-ham-routine articles t))
+
+;;}}}
+
+;;{{{ CRM114 Mailfilter
+(defun spam-check-crm114-headers (&optional score)
+  (let ((header (message-fetch-field spam-crm114-header)))
+    (when header                        ; return nil when no header
+      (if score                         ; scoring mode
+          (if (string-match "( pR: \\([0-9.-]+\\)" header)
+              (match-string 1 header)
+            "0")
+        ;; spam detection mode
+        (when (string-match spam-crm114-positive-spam-header
+                            header)
+          spam-split-group)))))
+
+;; return something sensible if the score can't be determined
+(defun spam-crm114-score ()
+  "Get the CRM114 Mailfilter pR."
+  (interactive)
+  (save-window-excursion
+    (gnus-summary-show-article t)
+    (set-buffer gnus-article-buffer)
+    (let ((score (or (spam-check-crm114-headers t)
+                     (spam-check-crm114 t))))
+      (gnus-summary-show-article)
+      (message "pR: %s" score)
+      (or score "0"))))
+
+(defun spam-check-crm114 (&optional score)
+  "Check the CRM114 Mailfilter backend for the classification of this message."
+  (let ((article-buffer-name (buffer-name))
+        (db spam-crm114-database-directory)
+        return)
+    (with-temp-buffer
+      (let ((temp-buffer-name (buffer-name)))
+        (with-current-buffer article-buffer-name
+          (apply 'call-process-region
+                 (point-min) (point-max)
+                 spam-crm114-program
+                 nil temp-buffer-name nil
+                 (when db (list (concat "--fileprefix=" db)))))
+        (setq return (spam-check-crm114-headers score))))
+    return))
+
+(defun spam-crm114-register-with-crm114 (articles
+                                         spam
+                                         &optional unregister)
+  "Register an article, given as a string, as spam or non-spam."
+  (dolist (article articles)
+    (let ((article-string (spam-get-article-as-string article))
+          (db spam-crm114-database-directory)
+          (switch (if unregister
+                      (if spam
+                          spam-crm114-spam-strong-switch
+                        spam-crm114-ham-strong-switch)
+                    (if spam
+                        spam-crm114-spam-switch
+                      spam-crm114-ham-switch))))
+      (when (stringp article-string)
+        (with-temp-buffer
+          (insert article-string)
+
+          (apply 'call-process-region
+                 (point-min) (point-max)
+                 spam-crm114-program
+                 nil nil nil
+                 (when db (list switch (concat "--fileprefix=" db)))))))))
+
+(defun spam-crm114-register-spam-routine (articles &optional unregister)
+  (spam-crm114-register-with-crm114 articles t unregister))
+
+(defun spam-crm114-unregister-spam-routine (articles)
+  (spam-crm114-register-spam-routine articles t))
+
+(defun spam-crm114-register-ham-routine (articles &optional unregister)
+  (spam-crm114-register-with-crm114 articles nil unregister))
+
+(defun spam-crm114-unregister-ham-routine (articles)
+  (spam-crm114-register-ham-routine articles t))
+
+;;}}}
+
+;;}}}
+
+;;{{{ Hooks
+
+;;;###autoload
+(defun spam-initialize (&rest symbols)
+  "Install the spam.el hooks and do other initialization.
+When SYMBOLS is given, set those variables to t.  This is so you
+can call `spam-initialize' before you set spam-use-* variables on
+explicitly, and matters only if you need the extra headers
+installed through `spam-necessary-extra-headers'."
+  (interactive)
+
+  (when spam-install-hooks
+    (dolist (var symbols)
+      (set var t))
+
+    (dolist (header (spam-necessary-extra-headers))
+      (add-to-list 'nnmail-extra-headers header)
+      (add-to-list 'gnus-extra-headers header))
+
+    ;; TODO: How do we redo this every time the `spam' face is customized?
+    (push '((eq mark gnus-spam-mark) . spam)
+         gnus-summary-highlight)
+    ;; Add hooks for loading and saving the spam stats
+    (add-hook 'gnus-save-newsrc-hook 'spam-maybe-spam-stat-save)
+    (add-hook 'gnus-get-top-new-news-hook 'spam-maybe-spam-stat-load)
+    (add-hook 'gnus-startup-hook 'spam-maybe-spam-stat-load)
+    (add-hook 'gnus-summary-prepare-exit-hook 'spam-summary-prepare-exit)
+    (add-hook 'gnus-summary-prepare-hook 'spam-summary-prepare)
+    (add-hook 'gnus-get-new-news-hook 'spam-setup-widening)
+    (add-hook 'gnus-summary-prepared-hook 'spam-find-spam)
+    ;; Don't install things more than once.
+    (setq spam-install-hooks nil)))
+
+(defun spam-unload-hook ()
+  "Uninstall the spam.el hooks."
+  (interactive)
+  (remove-hook 'gnus-save-newsrc-hook 'spam-maybe-spam-stat-save)
+  (remove-hook 'gnus-get-top-new-news-hook 'spam-maybe-spam-stat-load)
+  (remove-hook 'gnus-startup-hook 'spam-maybe-spam-stat-load)
+  (remove-hook 'gnus-summary-prepare-exit-hook 'spam-summary-prepare-exit)
+  (remove-hook 'gnus-summary-prepare-hook 'spam-summary-prepare)
+  (remove-hook 'gnus-get-new-news-hook 'spam-setup-widening)
+  (remove-hook 'gnus-summary-prepare-hook 'spam-find-spam))
+
+(add-hook 'spam-unload-hook 'spam-unload-hook)
+
+;;}}}
+
+(provide 'spam)
+
+;;; spam.el ends here
diff --git a/xemacs-packages/gnus/lisp/starttls.el b/xemacs-packages/gnus/lisp/starttls.el
new file mode 100644 (file)
index 0000000..f3ef5e0
--- /dev/null
@@ -0,0 +1,311 @@
+;;; starttls.el --- STARTTLS functions
+
+;; Copyright (C) 1999-2016 Free Software Foundation, Inc.
+
+;; Author: Daiki Ueno <ueno@unixuser.org>
+;; Author: Simon Josefsson <simon@josefsson.org>
+;; Created: 1999/11/20
+;; Keywords: TLS, SSL, OpenSSL, GnuTLS, 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This module defines some utility functions for STARTTLS profiles.
+
+;; [RFC 2595] "Using TLS with IMAP, POP3 and ACAP"
+;;     by Chris Newman <chris.newman@innosoft.com> (1999/06)
+
+;; This file now contains a combination of the two previous
+;; implementations both called "starttls.el".  The first one is Daiki
+;; Ueno's starttls.el which uses his own "starttls" command line tool,
+;; and the second one is Simon Josefsson's starttls.el which uses
+;; "gnutls-cli" from GnuTLS.
+;;
+;; If "starttls" is available, it is preferred by the code over
+;; "gnutls-cli", for backwards compatibility.  Use
+;; `starttls-use-gnutls' to toggle between implementations if you have
+;; both tools installed.  It is recommended to use GnuTLS, though, as
+;; it performs more verification of the certificates.
+
+;; The GnuTLS support requires GnuTLS 0.9.90 (released 2003-10-08) or
+;; later, from <http://www.gnu.org/software/gnutls/>, or "starttls"
+;; from <ftp://ftp.opaopa.org/pub/elisp/>.
+
+;; Usage is similar to `open-network-stream'.  For example:
+;;
+;; (when (setq tmp (starttls-open-stream
+;;                     "test" (current-buffer) "yxa.extundo.com" 25))
+;;   (accept-process-output tmp 15)
+;;   (process-send-string tmp "STARTTLS\n")
+;;   (accept-process-output tmp 15)
+;;   (message "STARTTLS output:\n%s" (starttls-negotiate tmp))
+;;   (process-send-string tmp "EHLO foo\n"))
+
+;; An example run yields the following output:
+;;
+;; 220 yxa.extundo.com ESMTP Sendmail 8.12.11/8.12.11/Debian-3; Wed, 26 May 2004 19:12:29 +0200; (No UCE/UBE) logging access from: c494102a.s-bi.bostream.se(OK)-c494102a.s-bi.bostream.se [217.215.27.65]
+;; 220 2.0.0 Ready to start TLS
+;; 250-yxa.extundo.com Hello c494102a.s-bi.bostream.se [217.215.27.65], pleased to meet you
+;; 250-ENHANCEDSTATUSCODES
+;; 250-PIPELINING
+;; 250-EXPN
+;; 250-VERB
+;; 250-8BITMIME
+;; 250-SIZE
+;; 250-DSN
+;; 250-ETRN
+;; 250-AUTH DIGEST-MD5 CRAM-MD5 PLAIN LOGIN
+;; 250-DELIVERBY
+;; 250 HELP
+;; nil
+;;
+;; With the message buffer containing:
+;;
+;; STARTTLS output:
+;; *** Starting TLS handshake
+;; - Server's trusted authorities:
+;;    [0]: C=SE,ST=Stockholm,L=Stockholm,O=YXA,OU=CA,CN=yxa.extundo.com,EMAIL=staff@yxa.extundo.com
+;; - Certificate type: X.509
+;;  - Got a certificate list of 2 certificates.
+;;
+;;  - Certificate[0] info:
+;;  # The hostname in the certificate matches 'yxa.extundo.com'.
+;;  # valid since: Wed May 26 12:16:00 CEST 2004
+;;  # expires at: Wed Jul 26 12:16:00 CEST 2023
+;;  # serial number: 04
+;;  # fingerprint: 7c 04 4b c1 fa 26 9b 5d 90 22 52 3c 65 3d 85 3a
+;;  # version: #1
+;;  # public key algorithm: RSA
+;;  #   Modulus: 1024 bits
+;;  # Subject's DN: C=SE,ST=Stockholm,L=Stockholm,O=YXA,OU=Mail server,CN=yxa.extundo.com,EMAIL=staff@yxa.extundo.com
+;;  # Issuer's DN: C=SE,ST=Stockholm,L=Stockholm,O=YXA,OU=CA,CN=yxa.extundo.com,EMAIL=staff@yxa.extundo.com
+;;
+;;  - Certificate[1] info:
+;;  # valid since: Sun May 23 11:35:00 CEST 2004
+;;  # expires at: Sun Jul 23 11:35:00 CEST 2023
+;;  # serial number: 00
+;;  # fingerprint: fc 76 d8 63 1a c9 0b 3b fa 40 fe ed 47 7a 58 ae
+;;  # version: #3
+;;  # public key algorithm: RSA
+;;  #   Modulus: 1024 bits
+;;  # Subject's DN: C=SE,ST=Stockholm,L=Stockholm,O=YXA,OU=CA,CN=yxa.extundo.com,EMAIL=staff@yxa.extundo.com
+;;  # Issuer's DN: C=SE,ST=Stockholm,L=Stockholm,O=YXA,OU=CA,CN=yxa.extundo.com,EMAIL=staff@yxa.extundo.com
+;;
+;; - Peer's certificate issuer is unknown
+;; - Peer's certificate is NOT trusted
+;; - Version: TLS 1.0
+;; - Key Exchange: RSA
+;; - Cipher: ARCFOUR 128
+;; - MAC: SHA
+;; - Compression: NULL
+
+;;; Code:
+
+(defgroup starttls nil
+  "Support for `Transport Layer Security' protocol."
+  :version "21.1"
+  :group 'mail)
+
+(defcustom starttls-gnutls-program "gnutls-cli"
+  "Name of GnuTLS command line tool.
+This program is used when GnuTLS is used, i.e. when
+`starttls-use-gnutls' is non-nil."
+  :version "22.1"
+  :type 'string
+  :group 'starttls)
+
+(defcustom starttls-program "starttls"
+  "The program to run in a subprocess to open an TLSv1 connection.
+This program is used when the `starttls' command is used,
+i.e. when `starttls-use-gnutls' is nil."
+  :type 'string
+  :group 'starttls)
+
+(defcustom starttls-use-gnutls (not (executable-find starttls-program))
+  "*Whether to use GnuTLS instead of the `starttls' command."
+  :version "22.1"
+  :type 'boolean
+  :group 'starttls)
+
+(defcustom starttls-extra-args nil
+  "Extra arguments to `starttls-program'.
+These apply when the `starttls' command is used, i.e. when
+`starttls-use-gnutls' is nil."
+  :type '(repeat string)
+  :group 'starttls)
+
+(defcustom starttls-extra-arguments nil
+  "Extra arguments to `starttls-gnutls-program'.
+These apply when GnuTLS is used, i.e. when `starttls-use-gnutls' is non-nil.
+
+For example, non-TLS compliant servers may require
+'(\"--protocols\" \"ssl3\").  Invoke \"gnutls-cli --help\" to
+find out which parameters are available."
+  :version "22.1"
+  :type '(repeat string)
+  :group 'starttls)
+
+(defcustom starttls-process-connection-type nil
+  "*Value for `process-connection-type' to use when starting STARTTLS process."
+  :version "22.1"
+  :type 'boolean
+  :group 'starttls)
+
+(defcustom starttls-connect "- Simple Client Mode:\n\n"
+  "*Regular expression indicating successful connection.
+The default is what GnuTLS's \"gnutls-cli\" outputs."
+  ;; GnuTLS cli.c:main() prints this string when it is starting to run
+  ;; in the application read/write phase.  If the logic, or the string
+  ;; itself, is modified, this must be updated.
+  :version "22.1"
+  :type 'regexp
+  :group 'starttls)
+
+(defcustom starttls-failure "\\*\\*\\* Handshake has failed"
+  "*Regular expression indicating failed TLS handshake.
+The default is what GnuTLS's \"gnutls-cli\" outputs."
+  ;; GnuTLS cli.c:do_handshake() prints this string on failure.  If the
+  ;; logic, or the string itself, is modified, this must be updated.
+  :version "22.1"
+  :type 'regexp
+  :group 'starttls)
+
+(defcustom starttls-success "- Compression: "
+  "*Regular expression indicating completed TLS handshakes.
+The default is what GnuTLS's \"gnutls-cli\" outputs."
+  ;; GnuTLS cli.c:do_handshake() calls, on success,
+  ;; common.c:print_info(), that unconditionally print this string
+  ;; last.  If that logic, or the string itself, is modified, this
+  ;; must be updated.
+  :version "22.1"
+  :type 'regexp
+  :group 'starttls)
+
+(defun starttls-negotiate-gnutls (process)
+  "Negotiate TLS on PROCESS opened by `open-starttls-stream'.
+This should typically only be done once.  It typically returns a
+multi-line informational message with information about the
+handshake, or nil on failure."
+  (let (buffer info old-max done-ok done-bad)
+    (if (null (setq buffer (process-buffer process)))
+       ;; XXX How to remove/extract the TLS negotiation junk?
+       (signal-process (process-id process) 'SIGALRM)
+      (with-current-buffer buffer
+       (save-excursion
+         (setq old-max (goto-char (point-max)))
+         (signal-process (process-id process) 'SIGALRM)
+         (while (and (processp process)
+                     (eq (process-status process) 'run)
+                     (save-excursion
+                       (goto-char old-max)
+                       (not (or (setq done-ok (re-search-forward
+                                               starttls-success nil t))
+                                (setq done-bad (re-search-forward
+                                                starttls-failure nil t))))))
+           (accept-process-output process 1 100)
+           (sit-for 0.1))
+         (setq info (buffer-substring-no-properties old-max (point-max)))
+         (delete-region old-max (point-max))
+         (if (or (and done-ok (not done-bad))
+                 ;; Prevent mitm that fake success msg after failure msg.
+                 (and done-ok done-bad (< done-ok done-bad)))
+             info
+           (message "STARTTLS negotiation failed: %s" info)
+           nil))))))
+
+(defun starttls-negotiate (process)
+  (if starttls-use-gnutls
+      (starttls-negotiate-gnutls process)
+    (signal-process (process-id process) 'SIGALRM)))
+
+(eval-and-compile
+  (if (fboundp 'set-process-query-on-exit-flag)
+      (defalias 'starttls-set-process-query-on-exit-flag
+       'set-process-query-on-exit-flag)
+    (defalias 'starttls-set-process-query-on-exit-flag
+      'process-kill-without-query)))
+
+(defun starttls-open-stream-gnutls (name buffer host port)
+  (message "Opening STARTTLS connection to `%s:%s'..." host port)
+  (let* (done
+        (old-max (with-current-buffer buffer (point-max)))
+        (process-connection-type starttls-process-connection-type)
+        (process (apply #'start-process name buffer
+                        starttls-gnutls-program "-s" host
+                        "-p" (if (integerp port)
+                                 (int-to-string port)
+                               port)
+                        starttls-extra-arguments)))
+    (starttls-set-process-query-on-exit-flag process nil)
+    (while (and (processp process)
+               (eq (process-status process) 'run)
+               (with-current-buffer buffer
+                 (goto-char old-max)
+                 (not (setq done (re-search-forward
+                                  starttls-connect nil t)))))
+      (accept-process-output process 0 100)
+      (sit-for 0.1))
+    (if done
+       (with-current-buffer buffer
+         (delete-region old-max done))
+      (delete-process process)
+      (setq process nil))
+    (message "Opening STARTTLS connection to `%s:%s'...%s"
+            host port (if done "done" "failed"))
+    process))
+
+;;;###autoload
+(defun starttls-open-stream (name buffer host port)
+  "Open a TLS connection for a port to a host.
+Returns a subprocess object to represent the connection.
+Input and output work as for subprocesses; `delete-process' closes it.
+Args are NAME BUFFER HOST PORT.
+NAME is name for process.  It is modified if necessary to make it unique.
+BUFFER is the buffer (or `buffer-name') to associate with the process.
+ Process output goes at end of that buffer, unless you specify
+ an output stream or filter function to handle the output.
+ BUFFER may be also nil, meaning that this process is not associated
+ with any buffer
+Third arg is name of the host to connect to, or its IP address.
+Fourth arg PORT is an integer specifying a port to connect to.
+If `starttls-use-gnutls' is nil, this may also be a service name, but
+GnuTLS requires a port number."
+  (if starttls-use-gnutls
+      (starttls-open-stream-gnutls name buffer host port)
+    (message "Opening STARTTLS connection to `%s:%s'" host (format "%s" port))
+    (let* ((process-connection-type starttls-process-connection-type)
+          (process (apply #'start-process
+                          name buffer starttls-program
+                          host (format "%s" port)
+                          starttls-extra-args)))
+      (starttls-set-process-query-on-exit-flag process nil)
+      process)))
+
+(defun starttls-available-p ()
+  "Say whether the STARTTLS programs are available."
+  (and (not (memq system-type '(windows-nt ms-dos)))
+       (executable-find (if starttls-use-gnutls
+                           starttls-gnutls-program
+                         starttls-program))))
+
+(defalias 'starttls-any-program-available 'starttls-available-p)
+(make-obsolete 'starttls-any-program-available 'starttls-available-p
+              "2011-08-02")
+
+(provide 'starttls)
+
+;;; starttls.el ends here
diff --git a/xemacs-packages/gnus/lisp/tests/gnustest-gnus-util.el b/xemacs-packages/gnus/lisp/tests/gnustest-gnus-util.el
new file mode 100644 (file)
index 0000000..b40ad85
--- /dev/null
@@ -0,0 +1,100 @@
+;;; gnustest-gnus-util.el --- Selectived tests only.
+;; Copyright (C) 2015 Free Software Foundation, Inc.
+
+;; Author: Jens Lechtenbörger <jens.lechtenboerger@fsfe.org>
+
+;; This file is not 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 3, 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.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; The tests here are restricted to three functions:
+;; gnus-test-list, gnus-subsetp, gnus-setdiff
+;;
+;; Run as follows:
+;; emacs -Q -batch -L .. -l gnustest-gnus-util.el -f ert-run-tests-batch-and-exit
+
+;;; Code:
+
+(require 'ert)
+(require 'gnus-util)
+
+(ert-deftest test-list ()
+  ;; False for non-lists.
+  (should-not (gnus-test-list 1 'listp))
+  (should-not (gnus-test-list "42" 'listp))
+
+  ;; False for empty lists.
+  (should-not (gnus-test-list '() 'listp))
+  (should-not (gnus-test-list '() 'nlistp))
+
+  ;; Real tests for other lists.
+  (should (gnus-test-list '(()) 'listp))
+  (should (gnus-test-list '(() ()) 'listp))
+  (should-not (gnus-test-list '(1) 'listp))
+  (should-not (gnus-test-list '(() 1) 'listp))
+  (should-not (gnus-test-list '(1 ()) 'listp))
+  (should-not (gnus-test-list '(() 1 ()) 'listp))
+  )
+
+(ert-deftest subsetp ()
+  ;; False for non-lists.
+  (should-not (gnus-subsetp "1" "1"))
+  (should-not (gnus-subsetp "1" '("1")))
+  (should-not (gnus-subsetp '("1") "1"))
+
+  ;; Real tests.
+  (should (gnus-subsetp '() '()))
+  (should (gnus-subsetp '() '("1")))
+  (should (gnus-subsetp '("1") '("1")))
+  (should (gnus-subsetp '(42) '("1" 42)))
+  (should (gnus-subsetp '(42) '(42 "1")))
+  (should (gnus-subsetp '(42) '("1" 42 2)))
+  (should-not (gnus-subsetp '("1") '()))
+  (should-not (gnus-subsetp '("1") '(2)))
+  (should-not (gnus-subsetp '("1" 2) '(2)))
+  (should-not (gnus-subsetp '(2 "1") '(2)))
+  (should-not (gnus-subsetp '("1" 2) '(2 3)))
+
+  ;; Duplicates don't matter for sets.
+  (should (gnus-subsetp '("1" "1") '("1")))
+  (should (gnus-subsetp '("1" 2 "1") '(2 "1")))
+  (should (gnus-subsetp '("1" 2 "1") '(2 "1" "1" 2)))
+  (should-not (gnus-subsetp '("1" 2 "1" 3) '(2 "1" "1" 2))))
+
+(ert-deftest setdiff ()
+  ;; False for non-lists.
+  (should-not (gnus-setdiff "1" "1"))
+  (should-not (gnus-setdiff "1" '()))
+  (should-not (gnus-setdiff '() "1"))
+
+  ;; Real tests.
+  (should-not (gnus-setdiff '() '()))
+  (should-not (gnus-setdiff '() '("1")))
+  (should-not (gnus-setdiff '("1") '("1")))
+  (should (equal '("1") (gnus-setdiff '("1") '())))
+  (should (equal '("1") (gnus-setdiff '("1") '(2))))
+  (should (equal '("1") (gnus-setdiff '("1" 2) '(2))))
+  (should (equal '("1") (gnus-setdiff '("1" 2 3) '(3 2))))
+  (should (equal '("1") (gnus-setdiff '(2 "1" 3) '(3 2))))
+  (should (equal '("1") (gnus-setdiff '(2 3 "1") '(3 2))))
+  (should (equal '(2 "1") (gnus-setdiff '(2 3 "1") '(3))))
+
+  ;; Duplicates aren't touched for sets if they are not removed.
+  (should-not (gnus-setdiff '("1" "1") '("1")))
+  (should (equal '("1") (gnus-setdiff '(2 "1" 2) '(2))))
+  (should (equal '("1" "1") (gnus-setdiff '(2 "1" 2 "1") '(2)))))
+
+;;; gnustest-gnus-util.el ends here
diff --git a/xemacs-packages/gnus/lisp/tests/gnustest-mml-sec.README b/xemacs-packages/gnus/lisp/tests/gnustest-mml-sec.README
new file mode 100644 (file)
index 0000000..f8920f5
--- /dev/null
@@ -0,0 +1,45 @@
+* Prerequisites
+I tested against Emacs versions 24.3 (precompiled on my system, with Gnus
+v5.13) and 25.0.50 (compiled from git source, with the included v5.13 and with
+Ma Gnus v0.14).
+In general, I recommend that you use GnuPG version 1.x for tests.  Obviously,
+for gpgsm you need 2.x, which works for me with 2.0.x but not 2.1.x; see
+mml-secure-run-tests-with-gpg2 in gnustest-mml-sec.el.  When running tests
+with different versions of GnuPG make sure that proper versions of gpg-agent
+are running (kill all prior to testing, if in doubt).
+
+
+* Test keys
+The subdirectory mml-gpghome contains OpenPGP and S/MIME test keyrings for
+GnuPG’s gpg and gpgsm commands.  In addition, it contains a file
+gpg-agent.conf where all options are commented out.  In particular, by
+activating the debug settings one can verify whether the correct version of
+gpg-agent is running and whether pinentry problems arise with the current
+setup.
+
+Most keys in the test keyrings come with empty passphrases, while the keys
+associated with the user ID “No Expiry two UIDs” have the passphrase
+“Passphrase”.  You can see all public keys and user IDs as follows:
+$ gpg --homedir ./mml-gpghome --fingerprint -k --list-options show-unusable-subkeys,show-unusable-uids
+$ gpgsm --homedir ./mml-gpghome -k
+
+
+* Running tests
+To run all tests:
+$ cd <path-to-gnus/lisp/test>
+$ emacs -Q -batch -L .. -l gnustest-mml-sec.el -f mml-secure-run-tests
+
+However, in the above case gpgsm will ask for passphrases, even empty ones.
+To omit those tests:
+$ emacs -Q -batch -L .. -l gnustest-mml-sec.el -f mml-secure-run-tests-without-smime
+
+To run all tests with epg-gpg-program set to "gpg2":
+$ emacs -Q -batch -L .. -l gnustest-mml-sec.el -f mml-secure-run-tests-with-gpg2
+
+To check an issue with truncation of y-or-n-p questions:
+$ emacs -Q -L .. -l gnustest-mml-sec.el -f mml-secure-select-preferred-keys-todo
+Then mark one or two keys and select “OK”.  The following question should be
+truncated.  Answer “n” to avoid storage of that choice in your ~/.emacs.
+
+To see that question entirely (outside an encryption context):
+$ emacs -Q -L .. -l gnustest-mml-sec.el -f mml-secure-select-preferred-keys-ok
diff --git a/xemacs-packages/gnus/lisp/tests/gnustest-mml-sec.el b/xemacs-packages/gnus/lisp/tests/gnustest-mml-sec.el
new file mode 100644 (file)
index 0000000..e9533bb
--- /dev/null
@@ -0,0 +1,858 @@
+;;; gnustest-mml-sec.el --- Tests mml-sec.el, see README-mml-secure.txt.
+;; Copyright (C) 2015 Free Software Foundation, Inc.
+
+;; Author: Jens Lechtenbörger <jens.lechtenboerger@fsfe.org>
+
+;; This file is not 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 3, 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.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+
+(require 'message)
+(require 'epa)
+(require 'epg)
+(require 'mml-sec)
+(require 'gnus-sum)
+
+(defvar with-smime t
+  "If nil, exclude S/MIME from tests as passphrases need to entered manually.
+Mostly, the empty passphrase is used.  However, the keys for
+ \"No Expiry two UIDs\" have the passphrase \"Passphrase\" (for OpenPGP as well
+ as S/MIME).")
+
+(defun enc-standards ()
+  (if with-smime '(enc-pgp enc-pgp-mime enc-smime)
+    '(enc-pgp enc-pgp-mime)))
+(defun enc-sign-standards ()
+  (if with-smime
+      '(enc-sign-pgp enc-sign-pgp-mime enc-sign-smime)
+    '(enc-sign-pgp enc-sign-pgp-mime)))
+(defun sign-standards ()
+  (if with-smime
+      '(sign-pgp sign-pgp-mime sign-smime)
+    '(sign-pgp sign-pgp-mime)))
+
+(defun mml-secure-test-fixture (body &optional interactive)
+  "Setup GnuPG home containing test keys and prepare environment for BODY.
+If optional INTERACTIVE is non-nil, allow questions to the user in case of
+key problems.
+This fixture temporarily unsets GPG_AGENT_INFO to enable passphrase tests,
+which will neither work with gpgsm nor GnuPG 2.1 any longer, I guess.
+Actually, I'm not sure why people would want to cache passwords in Emacs
+instead of gpg-agent."
+  (unwind-protect
+      (let ((agent-info (getenv "GPG_AGENT_INFO"))
+           (gpghome (getenv "GNUPGHOME")))
+       (condition-case error
+           (let ((epg-gpg-home-directory
+                  (expand-file-name
+                   "mml-gpghome" (getenv "EMACS_TEST_DIRECTORY")))
+                 (mml-smime-use 'epg)
+                 ;; Create debug output in empty epg-debug-buffer.
+                 (epg-debug t)
+                 (epg-debug-buffer (get-buffer-create " *epg-test*"))
+                 (mml-secure-fail-when-key-problem (not interactive)))
+             (with-current-buffer epg-debug-buffer
+               (erase-buffer))
+             ;; Unset GPG_AGENT_INFO to enable passphrase caching inside Emacs.
+             ;; Just for testing.  Jens does not recommend this for daily use.
+             (setenv "GPG_AGENT_INFO")
+             ;; Set GNUPGHOME as gpg-agent started by gpgsm does
+             ;; not look in the proper places otherwise, see:
+             ;; https://bugs.gnupg.org/gnupg/issue2126
+             (setenv "GNUPGHOME" epg-gpg-home-directory)
+             (funcall body))
+         (error
+          (setenv "GPG_AGENT_INFO" agent-info)
+          (setenv "GNUPGHOME" gpghome)
+          (signal (car error) (cdr error))))
+       (setenv "GPG_AGENT_INFO" agent-info)
+       (setenv "GNUPGHOME" gpghome))))
+
+(defun mml-secure-test-message-setup (method to from &optional text bcc)
+  "Setup a buffer with MML METHOD, TO, and FROM headers.
+Optionally, a message TEXT and BCC header can be passed."
+  (with-temp-buffer
+    (when bcc (insert (format "Bcc: %s\n" bcc)))
+    (insert (format "To: %s
+From: %s
+Subject: Test
+%s\n" to from mail-header-separator))
+    (if text
+       (insert (format "%s" text))
+      (spook))
+    (cond ((eq method 'enc-pgp-mime)
+          (mml-secure-message-encrypt-pgpmime 'nosig))
+         ((eq method 'enc-sign-pgp-mime)
+          (mml-secure-message-encrypt-pgpmime))
+         ((eq method 'enc-pgp) (mml-secure-message-encrypt-pgp 'nosig))
+         ((eq method 'enc-sign-pgp) (mml-secure-message-encrypt-pgp))
+         ((eq method 'enc-smime) (mml-secure-message-encrypt-smime 'nosig))
+         ((eq method 'enc-sign-smime) (mml-secure-message-encrypt-smime))
+         ((eq method 'sign-pgp-mime) (mml-secure-message-sign-pgpmime))
+         ((eq method 'sign-pgp) (mml-secure-message-sign-pgp))
+         ((eq method 'sign-smime) (mml-secure-message-sign-smime))
+         (t (error "Unknown method")))
+    (buffer-string)))
+
+(defun mml-secure-test-mail-fixture (method to from body2
+                                           &optional interactive)
+  "Setup buffer encrypted using METHOD for TO from FROM, call BODY2.
+Pass optional INTERACTIVE to mml-secure-test-fixture."
+  (mml-secure-test-fixture
+   (lambda ()
+     (let ((context (if (memq method '(enc-smime enc-sign-smime sign-smime))
+                       (epg-make-context 'CMS)
+                     (epg-make-context 'OpenPGP)))
+          ;; Verify and decrypt by default.
+          (mm-verify-option 'known)
+          (mm-decrypt-option 'known)
+          (plaintext "The Magic Words are Squeamish Ossifrage"))
+       (with-temp-buffer
+        (insert (mml-secure-test-message-setup method to from plaintext))
+        (message-options-set-recipient)
+        (message-encode-message-body)
+        ;; Replace separator line with newline.
+        (goto-char (point-min))
+        (re-search-forward
+         (concat "^" (regexp-quote mail-header-separator) "\n"))
+        (replace-match "\n")
+        ;; The following treatment of handles, plainbuf, and multipart
+        ;; resulted from trial-and-error.
+        ;; Someone with more knowledge on how to decrypt messages and verify
+        ;; signatures might know more appropriate functions to invoke
+        ;; instead.
+        (let* ((handles (or (mm-dissect-buffer)
+                            (mm-uu-dissect)))
+               (isplain (bufferp (car handles)))
+               (ismultipart (equal (car handles) "multipart/mixed"))
+               (plainbuf (if isplain
+                             (car handles)
+                           (if ismultipart
+                               (car (cadadr handles))
+                             (caadr handles))))
+               (decrypted
+                (with-current-buffer plainbuf (buffer-string)))
+               (gnus-info
+                (if isplain
+                    nil
+                  (if ismultipart
+                      (or (mm-handle-multipart-ctl-parameter
+                           (cadr handles) 'gnus-details)
+                          (mm-handle-multipart-ctl-parameter
+                           (cadr handles) 'gnus-info))
+                    (mm-handle-multipart-ctl-parameter
+                     handles 'gnus-info)))))
+          (funcall body2 gnus-info plaintext decrypted)))))
+   interactive))
+
+;; TODO If the variable BODY3 is renamed to BODY, an infinite recursion
+;; occurs.  Emacs bug?
+(defun mml-secure-test-key-fixture (body3)
+  "Customize unique keys for sub@example.org and call BODY3.
+For OpenPGP, we have:
+- 1E6B FA97 3D9E 3103 B77F  D399 C399 9CF1 268D BEA2
+  uid                  Different subkeys <sub@example.org>
+- 1463 2ECA B9E2 2736 9C8D  D97B F7E7 9AB7 AE31 D471
+  uid                  Second Key Pair <sub@example.org>
+
+For S/MIME:
+          ID: 0x479DC6E2
+      Subject: /CN=Second Key Pair
+          aka: sub@example.org
+  fingerprint: 0E:58:22:9B:80:EE:33:95:9F:F7:18:FE:EF:25:40:2B:47:9D:C6:E2
+
+           ID: 0x5F88E9FC
+      Subject: /CN=Different subkeys
+          aka: sub@example.org
+  fingerprint: 4F:96:2A:B7:F4:76:61:6A:78:3D:72:AA:40:35:D5:9B:5F:88:E9:FC
+
+In both cases, the first key is customized for signing and encryption."
+  (mml-secure-test-fixture
+   (lambda ()
+     (let* ((mml-secure-key-preferences
+            '((OpenPGP (sign) (encrypt)) (CMS (sign) (encrypt))))
+           (pcontext (epg-make-context 'OpenPGP))
+           (pkey (epg-list-keys pcontext "C3999CF1268DBEA2"))
+           (scontext (epg-make-context 'CMS))
+           (skey (epg-list-keys scontext "0x479DC6E2")))
+       (mml-secure-cust-record-keys pcontext 'encrypt "sub@example.org" pkey)
+       (mml-secure-cust-record-keys pcontext 'sign "sub@example.org" pkey)
+       (mml-secure-cust-record-keys scontext 'encrypt "sub@example.org" skey)
+       (mml-secure-cust-record-keys scontext 'sign "sub@example.org" skey)
+       (funcall body3)))))
+
+(ert-deftest mml-secure-key-checks ()
+  "Test mml-secure-check-user-id and mml-secure-check-sub-key on sample keys."
+  (mml-secure-test-fixture
+   (lambda ()
+     (let* ((context (epg-make-context 'OpenPGP))
+           (keys1 (epg-list-keys context "expired@example.org"))
+           (keys2 (epg-list-keys context "no-exp@example.org"))
+           (keys3 (epg-list-keys context "sub@example.org"))
+           (keys4 (epg-list-keys context "revoked-uid@example.org"))
+           (keys5 (epg-list-keys context "disabled@example.org"))
+           (keys6 (epg-list-keys context "sign@example.org"))
+           (keys7 (epg-list-keys context "jens.lechtenboerger@fsfe"))
+           )
+       (should (and (= 1 (length keys1)) (= 1 (length keys2))
+                   (= 2 (length keys3))
+                   (= 1 (length keys4)) (= 1 (length keys5))
+                   ))
+       ;; key1 is expired
+       (should-not (mml-secure-check-user-id (car keys1) "expired@example.org"))
+       (should-not (mml-secure-check-sub-key context (car keys1) 'encrypt))
+       (should-not (mml-secure-check-sub-key context (car keys1) 'sign))
+
+       ;; key2 does not expire, but does not have the UID expired@example.org
+       (should-not (mml-secure-check-user-id (car keys2) "expired@example.org"))
+       (should (mml-secure-check-user-id (car keys2) "no-exp@example.org"))
+       (should (mml-secure-check-sub-key context (car keys2) 'encrypt))
+       (should (mml-secure-check-sub-key context (car keys2) 'sign))
+
+       ;; Two keys exist for sub@example.org.
+       (should (mml-secure-check-user-id (car keys3) "sub@example.org"))
+       (should (mml-secure-check-sub-key context (car keys3) 'encrypt))
+       (should (mml-secure-check-sub-key context (car keys3) 'sign))
+       (should (mml-secure-check-user-id (cadr keys3) "sub@example.org"))
+       (should (mml-secure-check-sub-key context (cadr keys3) 'encrypt))
+       (should (mml-secure-check-sub-key context (cadr keys3) 'sign))
+
+       ;; The UID revoked-uid@example.org is revoked.  The key itself is
+       ;; usable, though (with the UID sub@example.org).
+       (should-not
+       (mml-secure-check-user-id (car keys4) "revoked-uid@example.org"))
+       (should (mml-secure-check-sub-key context (car keys4) 'encrypt))
+       (should (mml-secure-check-sub-key context (car keys4) 'sign))
+       (should (mml-secure-check-user-id (car keys4) "sub@example.org"))
+
+       ;; The next key is disabled and, thus, unusable.
+       (should (mml-secure-check-user-id (car keys5) "disabled@example.org"))
+       (should-not (mml-secure-check-sub-key context (car keys5) 'encrypt))
+       (should-not (mml-secure-check-sub-key context (car keys5) 'sign))
+
+       ;; The next key has multiple subkeys.
+       ;; 42466F0F is valid sign subkey, 501FFD98 is expired
+       (should (mml-secure-check-sub-key context (car keys6) 'sign "42466F0F"))
+       (should-not
+       (mml-secure-check-sub-key context (car keys6) 'sign "501FFD98"))
+       ;; DC7F66E7 is encrypt subkey
+       (should
+       (mml-secure-check-sub-key context (car keys6) 'encrypt "DC7F66E7"))
+       (should-not
+       (mml-secure-check-sub-key context (car keys6) 'sign "DC7F66E7"))
+       (should-not
+       (mml-secure-check-sub-key context (car keys6) 'encrypt "42466F0F"))
+
+       ;; The final key is just a public key.
+       (should (mml-secure-check-sub-key context (car keys7) 'encrypt))
+       (should-not (mml-secure-check-sub-key context (car keys7) 'sign))
+       ))))
+
+(ert-deftest mml-secure-find-usable-keys-1 ()
+  "Make sure that expired and disabled keys and revoked UIDs are not used."
+  (mml-secure-test-fixture
+   (lambda ()
+     (let ((context (epg-make-context 'OpenPGP)))
+       (should-not
+       (mml-secure-find-usable-keys context "expired@example.org" 'encrypt))
+       (should-not
+       (mml-secure-find-usable-keys context "expired@example.org" 'sign))
+
+       (should-not
+       (mml-secure-find-usable-keys context "disabled@example.org" 'encrypt))
+       (should-not
+       (mml-secure-find-usable-keys context "disabled@example.org" 'sign))
+
+       (should-not
+       (mml-secure-find-usable-keys
+        context "<revoked-uid@example.org>" 'encrypt))
+       (should-not
+       (mml-secure-find-usable-keys
+        context "<revoked-uid@example.org>" 'sign))
+       ;; Same test without ankles.  Will fail for Ma Gnus v0.14 and earlier.
+       (should-not
+       (mml-secure-find-usable-keys
+        context "revoked-uid@example.org" 'encrypt))
+
+       ;; Expired key should not be usable.
+       ;; Will fail for Ma Gnus v0.14 and earlier.
+       ;; sign@example.org has the expired subkey 0x501FFD98.
+       (should-not
+       (mml-secure-find-usable-keys context "0x501FFD98" 'sign))
+
+       (should
+       (mml-secure-find-usable-keys context "no-exp@example.org" 'encrypt))
+       (should
+       (mml-secure-find-usable-keys context "no-exp@example.org" 'sign))
+       ))))
+
+(ert-deftest mml-secure-find-usable-keys-2 ()
+  "Test different ways to search for keys."
+  (mml-secure-test-fixture
+   (lambda ()
+     (let ((context (epg-make-context 'OpenPGP)))
+       ;; Plain substring search is not supported.
+       (should
+       (= 0 (length
+             (mml-secure-find-usable-keys context "No Expiry" 'encrypt))))
+       (should
+       (= 0 (length
+             (mml-secure-find-usable-keys context "No Expiry" 'sign))))
+
+       ;; Search for e-mail addresses works with and without ankle brackets.
+       (should
+       (= 1 (length (mml-secure-find-usable-keys
+                     context "<no-exp@example.org>" 'encrypt))))
+       (should
+       (= 1 (length (mml-secure-find-usable-keys
+                     context "<no-exp@example.org>" 'sign))))
+       (should
+       (= 1 (length (mml-secure-find-usable-keys
+                     context "no-exp@example.org" 'encrypt))))
+       (should
+       (= 1 (length (mml-secure-find-usable-keys
+                     context "no-exp@example.org" 'sign))))
+
+       ;; Use full UID string.
+       (should
+       (= 1 (length (mml-secure-find-usable-keys
+                     context "No Expiry <no-exp@example.org>" 'encrypt))))
+       (should
+       (= 1 (length (mml-secure-find-usable-keys
+                     context "No Expiry <no-exp@example.org>" 'sign))))
+
+       ;; If just the public key is present, only encryption is possible.
+       ;; Search works with key IDs, with and without prefix "0x".
+       (should
+       (= 1 (length (mml-secure-find-usable-keys
+                     context "A142FD84" 'encrypt))))
+       (should
+       (= 1 (length (mml-secure-find-usable-keys
+                     context "0xA142FD84" 'encrypt))))
+       (should
+       (= 0 (length (mml-secure-find-usable-keys
+                     context "A142FD84" 'sign))))
+       (should
+       (= 0 (length (mml-secure-find-usable-keys
+                     context "0xA142FD84" 'sign))))
+       ))))
+
+(ert-deftest mml-secure-select-preferred-keys-1 ()
+  "If only one key exists for an e-mail address, it is the preferred one."
+  (mml-secure-test-fixture
+   (lambda ()
+     (let ((context (epg-make-context 'OpenPGP)))
+       (should (equal "832F3CC6518D37BC658261B802372A42CA6D40FB"
+                     (mml-secure-fingerprint
+                      (car (mml-secure-select-preferred-keys
+                            context '("no-exp@example.org") 'encrypt)))))))))
+
+(ert-deftest mml-secure-select-preferred-keys-2 ()
+  "If multiple keys exists for an e-mail address, customization is necessary."
+  (mml-secure-test-fixture
+   (lambda ()
+     (let* ((context (epg-make-context 'OpenPGP))
+           (mml-secure-key-preferences
+            '((OpenPGP (sign) (encrypt)) (CMS (sign) (encrypt))))
+           (pref (car (mml-secure-find-usable-keys
+                       context "sub@example.org" 'encrypt))))
+       (should-error (mml-secure-select-preferred-keys
+                     context '("sub@example.org") 'encrypt))
+       (mml-secure-cust-record-keys
+       context 'encrypt "sub@example.org" (list pref))
+       (should (mml-secure-select-preferred-keys
+               context '("sub@example.org") 'encrypt))
+       (should-error (mml-secure-select-preferred-keys
+                     context '("sub@example.org") 'sign))
+       (should (mml-secure-select-preferred-keys
+                       context '("sub@example.org") 'encrypt))
+       (should
+       (equal (list (mml-secure-fingerprint pref))
+              (mml-secure-cust-fpr-lookup context 'encrypt "sub@example.org")))
+       (should (mml-secure-cust-remove-keys context 'encrypt "sub@example.org"))
+       (should-error (mml-secure-select-preferred-keys
+                             context '("sub@example.org") 'encrypt))))))
+
+(ert-deftest mml-secure-select-preferred-keys-3 ()
+  "Expired customized keys are removed if multiple keys are available."
+  (mml-secure-test-fixture
+   (lambda ()
+     (let ((context (epg-make-context 'OpenPGP))
+          (mml-secure-key-preferences
+           '((OpenPGP (sign) (encrypt)) (CMS (sign) (encrypt)))))
+       ;; sub@example.org has two keys (268DBEA2, AE31D471).
+       ;; Normal preference works.
+       (mml-secure-cust-record-keys
+               context 'encrypt "sub@example.org" (epg-list-keys context "268DBEA2"))
+       (should (mml-secure-select-preferred-keys
+               context '("sub@example.org") 'encrypt))
+       (mml-secure-cust-remove-keys context 'encrypt "sub@example.org")
+
+       ;; Fake preference for expired (unrelated) key CE15FAE7,
+       ;; results in error (and automatic removal of outdated preference).
+       (mml-secure-cust-record-keys
+               context 'encrypt "sub@example.org" (epg-list-keys context "CE15FAE7"))
+       (should-error (mml-secure-select-preferred-keys
+                     context '("sub@example.org") 'encrypt))
+       (should-not
+       (mml-secure-cust-remove-keys context 'encrypt "sub@example.org"))))))
+
+(ert-deftest mml-secure-select-preferred-keys-4 ()
+  "Multiple keys can be recorded per recipient or signature."
+  (mml-secure-test-fixture
+   (lambda ()
+     (let ((pcontext (epg-make-context 'OpenPGP))
+          (scontext (epg-make-context 'CMS))
+          (pkeys '("1E6BFA973D9E3103B77FD399C3999CF1268DBEA2"
+                   "14632ECAB9E227369C8DD97BF7E79AB7AE31D471"))
+          (skeys  '("0x5F88E9FC" "0x479DC6E2"))
+          (mml-secure-key-preferences
+           '((OpenPGP (sign) (encrypt)) (CMS (sign) (encrypt)))))
+
+       ;; OpenPGP preferences via pcontext
+       (dolist (key pkeys nil)
+        (mml-secure-cust-record-keys
+         pcontext 'encrypt "sub@example.org" (epg-list-keys pcontext key))
+        (mml-secure-cust-record-keys
+         pcontext 'sign "sub@example.org" (epg-list-keys pcontext key 'secret)))
+       (let ((p-e-fprs (mml-secure-cust-fpr-lookup
+                       pcontext 'encrypt "sub@example.org"))
+            (p-s-fprs (mml-secure-cust-fpr-lookup
+                       pcontext 'sign "sub@example.org")))
+        (should (= 2 (length p-e-fprs)))
+        (should (= 2 (length p-s-fprs)))
+        (should (member "1E6BFA973D9E3103B77FD399C3999CF1268DBEA2" p-e-fprs))
+        (should (member "14632ECAB9E227369C8DD97BF7E79AB7AE31D471" p-e-fprs))
+        (should (member "1E6BFA973D9E3103B77FD399C3999CF1268DBEA2" p-s-fprs))
+        (should (member "14632ECAB9E227369C8DD97BF7E79AB7AE31D471" p-s-fprs)))
+       ;; Duplicate record does not change anything.
+       (mml-secure-cust-record-keys
+       pcontext 'encrypt "sub@example.org"
+       (epg-list-keys pcontext "1E6BFA973D9E3103B77FD399C3999CF1268DBEA2"))
+       (mml-secure-cust-record-keys
+       pcontext 'sign "sub@example.org"
+       (epg-list-keys pcontext "1E6BFA973D9E3103B77FD399C3999CF1268DBEA2"))
+       (let ((p-e-fprs (mml-secure-cust-fpr-lookup
+                       pcontext 'encrypt "sub@example.org"))
+            (p-s-fprs (mml-secure-cust-fpr-lookup
+                       pcontext 'sign "sub@example.org")))
+        (should (= 2 (length p-e-fprs)))
+        (should (= 2 (length p-s-fprs))))
+
+       ;; S/MIME preferences via scontext
+       (dolist (key skeys nil)
+        (mml-secure-cust-record-keys
+         scontext 'encrypt "sub@example.org"
+         (epg-list-keys scontext key))
+        (mml-secure-cust-record-keys
+         scontext 'sign "sub@example.org"
+         (epg-list-keys scontext key 'secret)))
+       (let ((s-e-fprs (mml-secure-cust-fpr-lookup
+                       scontext 'encrypt "sub@example.org"))
+            (s-s-fprs (mml-secure-cust-fpr-lookup
+                       scontext 'sign "sub@example.org")))
+        (should (= 2 (length s-e-fprs)))
+        (should (= 2 (length s-s-fprs))))
+       ))))
+
+(defun mml-secure-test-en-decrypt
+    (method to from
+           &optional checksig checkplain enc-keys expectfail interactive)
+  "Encrypt message using METHOD, addressed to TO, from FROM.
+If optional CHECKSIG is non-nil, it must be a number, and a signature check is
+performed; the number indicates how many signatures are expected.
+If optional CHECKPLAIN is non-nil, the expected plaintext should be obtained
+via decryption.
+If optional ENC-KEYS is non-nil, it is a list of pairs of encryption keys (for
+OpenPGP and S/SMIME) expected in `epg-debug-buffer'.
+If optional EXPECTFAIL is non-nil, a decryption failure is expected.
+Pass optional INTERACTIVE to mml-secure-test-mail-fixture."
+  (mml-secure-test-mail-fixture method to from
+   (lambda (gnus-info plaintext decrypted)
+     (if expectfail
+        (should-not (equal plaintext decrypted))
+       (when checkplain
+        (should (equal plaintext decrypted)))
+       (let ((protocol (if (memq method
+                                '(enc-smime enc-sign-smime sign-smime))
+                          'CMS
+                        'OpenPGP)))
+        (when checksig
+          (let* ((context (epg-make-context protocol))
+                 (signer-names (mml-secure-signer-names protocol from))
+                 (signer-keys (mml-secure-signers context signer-names))
+                 (signer-fprs (mapcar 'mml-secure-fingerprint signer-keys)))
+            (should (eq checksig (length signer-fprs)))
+            (if (eq checksig 0)
+                ;; First key in keyring
+                (should (string-match-p
+                         (concat "Good signature from "
+                                 (if (eq protocol 'CMS)
+                                     "0E58229B80EE33959FF718FEEF25402B479DC6E2"
+                                   "02372A42CA6D40FB"))
+                         gnus-info)))
+            (dolist (fpr signer-fprs nil)
+              ;; OpenPGP: "Good signature from 02372A42CA6D40FB No Expiry <no-exp@example.org> (trust undefined) created ..."
+              ;; S/MIME:  "Good signature from D06AA118653CC38E9D0CAF56ED7A2135E1582177 /CN=No Expiry (trust full) ..."
+              (should (string-match-p
+                       (concat "Good signature from "
+                               (if (eq protocol 'CMS)
+                                   fpr
+                                 (substring fpr -16 nil)))
+                       gnus-info)))))
+        (when enc-keys
+          (with-current-buffer epg-debug-buffer
+            (goto-char (point-min))
+            ;; The following regexp does not necessarily match at the
+            ;; start of the line as a path may or may not be present.
+            ;; Also note that gpg.* matches gpg2 and gpgsm as well.
+            (let* ((line (concat "gpg.*--encrypt.*$"))
+                   (end (re-search-forward line))
+                   (match (match-string 0)))
+              (should (and end match))
+              (dolist (pair enc-keys nil)
+                (let ((fpr (if (eq protocol 'OpenPGP)
+                               (car pair)
+                             (cdr pair))))
+                  (should (string-match-p (concat "-r " fpr) match))))
+              (goto-char (point-max))
+              ))))))
+   interactive))
+
+(defun mml-secure-test-en-decrypt-with-passphrase
+    (method to from checksig jl-passphrase do-cache
+           &optional enc-keys expectfail)
+  "Call mml-secure-test-en-decrypt with changed passphrase caching.
+Args METHOD, TO, FROM, CHECKSIG are passed to mml-secure-test-en-decrypt.
+JL-PASSPHRASE is fixed as return value for `read-passwd',
+boolean DO-CACHE determines whether to cache the passphrase.
+If optional ENC-KEYS is non-nil, it is a list of encryption keys expected
+in `epg-debug-buffer'.
+If optional EXPECTFAIL is non-nil, a decryption failure is expected."
+  (let ((mml-secure-cache-passphrase do-cache)
+       (mml1991-cache-passphrase do-cache)
+       (mml2015-cache-passphrase do-cache)
+       (mml-smime-cache-passphrase do-cache)
+       )
+    (cl-letf (((symbol-function 'read-passwd)
+              (lambda (prompt &optional confirm default) jl-passphrase)))
+      (mml-secure-test-en-decrypt method to from checksig t enc-keys expectfail)
+      )))
+
+(ert-deftest mml-secure-en-decrypt-1 ()
+  "Encrypt message; then decrypt and test for expected result.
+In this test, the single matching key is chosen automatically."
+  (dolist (method (enc-standards) nil)
+    ;; no-exp@example.org with single encryption key
+    (mml-secure-test-en-decrypt
+     method "no-exp@example.org" "sub@example.org" nil t
+     (list (cons "02372A42CA6D40FB" "ED7A2135E1582177")))))
+
+(ert-deftest mml-secure-en-decrypt-2 ()
+  "Encrypt message; then decrypt and test for expected result.
+In this test, the encryption key needs to fixed among multiple ones."
+  ;; sub@example.org with multiple candidate keys,
+  ;; fixture customizes preferred ones.
+  (mml-secure-test-key-fixture
+   (lambda ()
+     (dolist (method (enc-standards) nil)
+       (mml-secure-test-en-decrypt
+       method "sub@example.org" "no-exp@example.org" nil t
+       (list (cons "C3999CF1268DBEA2" "EF25402B479DC6E2")))))))
+
+(ert-deftest mml-secure-en-decrypt-3 ()
+  "Encrypt message; then decrypt and test for expected result.
+In this test, encrypt-to-self variables are set to t."
+  ;; sub@example.org with multiple candidate keys,
+  ;; fixture customizes preferred ones.
+  (mml-secure-test-key-fixture
+   (lambda ()
+     (let ((mml-secure-openpgp-encrypt-to-self t)
+          (mml-secure-smime-encrypt-to-self t))
+       (dolist (method (enc-standards) nil)
+        (mml-secure-test-en-decrypt
+         method "sub@example.org" "no-exp@example.org" nil t
+         (list (cons "C3999CF1268DBEA2" "EF25402B479DC6E2")
+               (cons "02372A42CA6D40FB" "ED7A2135E1582177"))))))))
+
+(ert-deftest mml-secure-en-decrypt-4 ()
+  "Encrypt message; then decrypt and test for expected result.
+In this test, encrypt-to-self variables are set to lists."
+  ;; Send from sub@example.org, which has two keys; encrypt to both.
+  (let ((mml-secure-openpgp-encrypt-to-self
+        '("C3999CF1268DBEA2" "F7E79AB7AE31D471"))
+       (mml-secure-smime-encrypt-to-self
+        '("EF25402B479DC6E2" "4035D59B5F88E9FC")))
+    (dolist (method (enc-standards) nil)
+      (mml-secure-test-en-decrypt
+       method "no-exp@example.org" "sub@example.org" nil t
+       (list (cons "C3999CF1268DBEA2" "EF25402B479DC6E2")
+            (cons "F7E79AB7AE31D471" "4035D59B5F88E9FC"))))))
+
+(ert-deftest mml-secure-en-decrypt-sign-1 ()
+  "Sign and encrypt message; then decrypt and test for expected result.
+In this test, just multiple encryption and signing keys may be available."
+  (mml-secure-test-key-fixture
+   (lambda ()
+     (let ((mml-secure-openpgp-sign-with-sender t)
+          (mml-secure-smime-sign-with-sender t))
+       (dolist (method (enc-sign-standards) nil)
+        ;; no-exp with just one key
+        (mml-secure-test-en-decrypt
+         method "no-exp@example.org" "no-exp@example.org" 1 t)
+        ;; customized choice for encryption key
+        (mml-secure-test-en-decrypt
+         method "sub@example.org" "no-exp@example.org" 1 t)
+        ;; customized choice for signing key
+        (mml-secure-test-en-decrypt
+         method "no-exp@example.org" "sub@example.org" 1 t)
+        ;; customized choice for both keys
+        (mml-secure-test-en-decrypt
+         method "sub@example.org" "sub@example.org" 1 t)
+        )
+
+       ;; Now use both keys to sign.  The customized one via sign-with-sender,
+       ;; the other one via the following setting.
+       (let ((mml-secure-openpgp-signers '("F7E79AB7AE31D471"))
+            (mml-secure-smime-signers '("0x5F88E9FC")))
+        (dolist (method (enc-sign-standards) nil)
+          (mml-secure-test-en-decrypt
+           method "no-exp@example.org" "sub@example.org" 2 t)
+        )))
+
+     ;; Now use both keys for sub@example.org to sign an e-mail from
+     ;; a different address (without associated keys).
+     (let ((mml-secure-openpgp-sign-with-sender nil)
+          (mml-secure-smime-sign-with-sender nil)
+          (mml-secure-openpgp-signers
+           '("F7E79AB7AE31D471" "C3999CF1268DBEA2"))
+          (mml-secure-smime-signers '("0x5F88E9FC" "0x479DC6E2")))
+       (dolist (method (enc-sign-standards) nil)
+        (mml-secure-test-en-decrypt
+         method "no-exp@example.org" "no-keys@example.org" 2 t)
+        )))))
+
+(ert-deftest mml-secure-en-decrypt-sign-2 ()
+  "Sign and encrypt message; then decrypt and test for expected result.
+In this test, lists of encryption and signing keys are customized."
+  (mml-secure-test-key-fixture
+   (lambda ()
+     (let ((mml-secure-key-preferences
+           '((OpenPGP (sign) (encrypt)) (CMS (sign) (encrypt))))
+          (pcontext (epg-make-context 'OpenPGP))
+          (scontext (epg-make-context 'CMS))
+          (mml-secure-openpgp-sign-with-sender t)
+          (mml-secure-smime-sign-with-sender t))
+       (dolist (key '("F7E79AB7AE31D471" "C3999CF1268DBEA2") nil)
+        (mml-secure-cust-record-keys
+         pcontext 'encrypt "sub@example.org" (epg-list-keys pcontext key))
+        (mml-secure-cust-record-keys
+         pcontext 'sign "sub@example.org" (epg-list-keys pcontext key t)))
+       (dolist (key '("0x5F88E9FC" "0x479DC6E2") nil)
+        (mml-secure-cust-record-keys
+         scontext 'encrypt "sub@example.org" (epg-list-keys scontext key))
+        (mml-secure-cust-record-keys
+         scontext 'sign "sub@example.org" (epg-list-keys scontext key t)))
+       (dolist (method (enc-sign-standards) nil)
+        ;; customized choice for encryption key
+        (mml-secure-test-en-decrypt
+         method "sub@example.org" "no-exp@example.org" 1 t)
+        ;; customized choice for signing key
+        (mml-secure-test-en-decrypt
+         method "no-exp@example.org" "sub@example.org" 2 t)
+        ;; customized choice for both keys
+        (mml-secure-test-en-decrypt
+         method "sub@example.org" "sub@example.org" 2 t)
+        )))))
+
+(ert-deftest mml-secure-en-decrypt-sign-3 ()
+  "Sign and encrypt message; then decrypt and test for expected result.
+Use sign-with-sender and encrypt-to-self."
+  (mml-secure-test-key-fixture
+   (lambda ()
+     (let ((mml-secure-openpgp-sign-with-sender t)
+          (mml-secure-openpgp-encrypt-to-self t)
+          (mml-secure-smime-sign-with-sender t)
+          (mml-secure-smime-encrypt-to-self t))
+       (dolist (method (enc-sign-standards) nil)
+        (mml-secure-test-en-decrypt
+         method "sub@example.org" "no-exp@example.org" 1 t
+         (list (cons "C3999CF1268DBEA2" "EF25402B479DC6E2")
+               (cons "02372A42CA6D40FB" "ED7A2135E1582177"))))
+       ))))
+
+(ert-deftest mml-secure-sign-verify-1 ()
+  "Sign message with sender; then verify and test for expected result."
+  (mml-secure-test-key-fixture
+   (lambda ()
+     (dolist (method (sign-standards) nil)
+       (let ((mml-secure-openpgp-sign-with-sender t)
+            (mml-secure-smime-sign-with-sender t))
+        ;; A single signing key for sender sub@example.org is customized
+        ;; in the fixture.
+        (mml-secure-test-en-decrypt
+         method "uid1@example.org" "sub@example.org" 1 nil)
+
+        ;; From sub@example.org, sign with two keys;
+        ;; sign-with-sender and one from signers-variable:
+        (let ((mml-secure-openpgp-signers '("02372A42CA6D40FB"))
+              (mml-secure-smime-signers
+               '("D06AA118653CC38E9D0CAF56ED7A2135E1582177")))
+          (mml-secure-test-en-decrypt
+           method "no-exp@example.org" "sub@example.org" 2 nil))
+        )))))
+
+(ert-deftest mml-secure-sign-verify-2 ()
+  "Sign message without sender; then verify and test for expected result."
+  (mml-secure-test-key-fixture
+   (lambda ()
+     (dolist (method (sign-standards) nil)
+       (let ((mml-secure-openpgp-sign-with-sender nil)
+            (mml-secure-smime-sign-with-sender nil))
+        ;; A single signing key for sender sub@example.org is customized
+        ;; in the fixture, but not used here.
+        ;; By default, gpg uses the first secret key in the keyring, which
+        ;; is 02372A42CA6D40FB (OpenPGP) or
+        ;; 0E58229B80EE33959FF718FEEF25402B479DC6E2 (S/MIME) here.
+        (mml-secure-test-en-decrypt
+         method "uid1@example.org" "sub@example.org" 0 nil)
+
+        ;; From sub@example.org, sign with specified key:
+        (let ((mml-secure-openpgp-signers '("02372A42CA6D40FB"))
+              (mml-secure-smime-signers
+               '("D06AA118653CC38E9D0CAF56ED7A2135E1582177")))
+          (mml-secure-test-en-decrypt
+           method "no-exp@example.org" "sub@example.org" 1 nil))
+
+        ;; From sub@example.org, sign with different specified key:
+        (let ((mml-secure-openpgp-signers '("C3999CF1268DBEA2"))
+              (mml-secure-smime-signers
+               '("0E58229B80EE33959FF718FEEF25402B479DC6E2")))
+          (mml-secure-test-en-decrypt
+           method "no-exp@example.org" "sub@example.org" 1 nil))
+        )))))
+
+(ert-deftest mml-secure-sign-verify-3 ()
+  "Try to sign message with expired OpenPGP subkey, which raises an error.
+With Ma Gnus v0.14 and earlier a signature would be created with a wrong key."
+  (should-error
+   (mml-secure-test-key-fixture
+    (lambda ()
+      (let ((with-smime nil)
+           (mml-secure-openpgp-sign-with-sender nil)
+           (mml-secure-openpgp-signers '("501FFD98")))
+       (dolist (method (sign-standards) nil)
+         (mml-secure-test-en-decrypt
+          method "no-exp@example.org" "sign@example.org" 1 nil)
+         ))))))
+
+;; TODO Passphrase passing and caching in Emacs does not seem to work
+;; with gpgsm at all.
+;; Independently of caching settings, a pinentry dialogue is displayed.
+;; Thus, the following tests require the user to enter the correct gpgsm
+;; passphrases at the correct points in time.  (Either empty string or
+;; "Passphrase".)
+(ert-deftest mml-secure-en-decrypt-passphrase-cache ()
+  "Encrypt message; then decrypt and test for expected result.
+In this test, a key is used that requires the passphrase \"Passphrase\".
+In the first decryption this passphrase is hardcoded, in the second one it
+ is taken from a cache."
+  (mml-secure-test-key-fixture
+   (lambda ()
+     (dolist (method (enc-standards) nil)
+       (mml-secure-test-en-decrypt-with-passphrase
+       method "uid1@example.org" "sub@example.org" nil
+       ;; Beware!  For passphrases copy-sequence is necessary, as they may
+       ;; be erased, which actually changes the function's code and causes
+       ;; multiple invokations to fail.  I was surprised...
+       (copy-sequence "Passphrase") t)
+       (mml-secure-test-en-decrypt-with-passphrase
+       method "uid1@example.org" "sub@example.org" nil
+       (copy-sequence "Incorrect") t)))))
+
+(defun mml-secure-en-decrypt-passphrase-no-cache (method)
+  "Encrypt message with METHOD; then decrypt and test for expected result.
+In this test, a key is used that requires the passphrase \"Passphrase\".
+In the first decryption this passphrase is hardcoded, but caching disabled.
+So the second decryption fails."
+  (mml-secure-test-key-fixture
+   (lambda ()
+     (mml-secure-test-en-decrypt-with-passphrase
+      method "uid1@example.org" "sub@example.org" nil
+      (copy-sequence "Passphrase") nil)
+     (mml-secure-test-en-decrypt-with-passphrase
+      method "uid1@example.org" "sub@example.org" nil
+      (copy-sequence "Incorrect") nil nil t))))
+
+(ert-deftest mml-secure-en-decrypt-passphrase-no-cache-openpgp-todo ()
+  "Passphrase caching with OpenPGP only for GnuPG 1.x."
+  (skip-unless (string< (cdr (assq 'version (epg-configuration))) "2"))
+  (mml-secure-en-decrypt-passphrase-no-cache 'enc-pgp)
+  (mml-secure-en-decrypt-passphrase-no-cache 'enc-pgp-mime))
+
+(ert-deftest mml-secure-en-decrypt-passphrase-no-cache-smime-todo ()
+  "Passphrase caching does not work with S/MIME (and gpgsm)."
+  :expected-result :failed
+  (if with-smime
+      (mml-secure-en-decrypt-passphrase-no-cache 'enc-smime)
+    (should nil)))
+
+
+;; Test truncation of question in y-or-n-p.
+(defun mml-secure-select-preferred-keys-todo ()
+  "Manual customization with truncated question."
+  (mml-secure-test-key-fixture
+   (lambda ()
+     (mml-secure-test-en-decrypt
+      'enc-pgp-mime
+      "jens.lechtenboerger@informationelle-selbstbestimmung-im-internet.de"
+      "no-exp@example.org" nil t nil nil t))))
+
+(defun mml-secure-select-preferred-keys-ok ()
+  "Manual customization with entire question."
+  (mml-secure-test-fixture
+   (lambda ()
+     (mml-secure-select-preferred-keys
+      (epg-make-context 'OpenPGP)
+      '("jens.lechtenboerger@informationelle-selbstbestimmung-im-internet.de")
+      'encrypt))
+   t))
+
+
+;; ERT entry points
+(defun mml-secure-run-tests ()
+    "Run all tests with defaults."
+  (ert-run-tests-batch))
+
+(defun mml-secure-run-tests-with-gpg2 ()
+  "Run all tests with gpg2 instead of gpg."
+  (let* ((epg-gpg-program "gpg2"); ~/local/gnupg-2.1.9/PLAY/inst/bin/gpg2
+        (gpg-version (cdr (assq 'version (epg-configuration))))
+        ;; Empty passphrases do not seem to work with gpgsm in 2.1.x:
+        ;; https://lists.gnupg.org/pipermail/gnupg-users/2015-October/054575.html
+        (with-smime (string< gpg-version "2.1")))
+    (ert-run-tests-batch)))
+
+(defun mml-secure-run-tests-without-smime ()
+    "Skip S/MIME tests (as they require manual passphrase entry)."
+  (let ((with-smime nil))
+    (ert-run-tests-batch)))
+
+;;; gnustest-mml-sec.el ends here
diff --git a/xemacs-packages/gnus/lisp/tests/gnustest-nntp.el b/xemacs-packages/gnus/lisp/tests/gnustest-nntp.el
new file mode 100644 (file)
index 0000000..42d4d2e
--- /dev/null
@@ -0,0 +1,98 @@
+;;; gnustest-nntp.el --- Simple NNTP testing for Gnus
+;; Copyright (C) 2011-2016 Free Software Foundation, Inc.
+
+;; Author: David Engster <dengste@eml.cc>
+
+;; This file is not 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 3, 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.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This test will
+;;
+;;   - Fire up Gnus
+;;   - Connect to Gmane
+;;   - Subscribe to gmane.discuss
+;;   - Get its active info
+;;   - Get one specific article by message-id and check its subject
+;;   - Quit Gnus
+
+;;; Code:
+
+(require 'ert)
+(require 'net-utils)
+
+(defvar gnustest-nntp-server "news.gmane.org"
+  "NNTP server used for testing.")
+
+(defun gnustest-ping-host (host)
+  "Ping HOST once and return non-nil if successful."
+  (let* ((ping-program-options '("-c" "1"))
+        (buf (ping host))
+        proc)
+    ;; sleep-for does not work correctly with async processes running
+    (call-process "sleep" nil nil nil "2")
+    (with-current-buffer buf
+      (accept-process-output (get-buffer-process (current-buffer)) 2)
+      (goto-char (point-min))
+      (prog1
+         (re-search-forward ",[ ]*1.*?received,[ ]*0" nil t)
+       (when (setq proc (get-buffer-process (current-buffer)))
+         (set-process-query-on-exit-flag proc nil))
+       (kill-buffer)))))
+
+(setq gnus-home-directory (concat temporary-file-directory (make-temp-name "gnus-test-")))
+(message "***** Using %s as temporary Gnus home." gnus-home-directory)
+(mkdir gnus-home-directory)
+(setq-default gnus-init-file nil)
+
+(require 'gnus-load)
+
+(setq gnus-select-method `(nntp ,gnustest-nntp-server))
+
+
+(if (null (gnustest-ping-host gnustest-nntp-server))
+    (message "***** Skipping tests: Gmane doesn't seem to be available.")
+  ;; Server seems to be available, so start Gnus.
+  (message "***** Firing up Gnus; connecting to Gmane.")
+  (gnus)
+
+  (ert-deftest gnustest-nntp-run-simple-test ()
+    "Test Gnus with gmane.discuss."
+    (set-buffer gnus-group-buffer)
+    (gnus-group-jump-to-group "gmane.discuss")
+    (gnus-group-get-new-news-this-group 1)
+    (gnus-active "gmane.discuss")
+    (message "***** Reading active from gmane.discuss.")
+    (should (> (car (gnus-active "gmane.discuss")) 0))
+    (should (> (cdr (gnus-active "gmane.discuss")) 10000))
+    (gnus-group-unsubscribe-current-group)
+    (gnus-group-set-current-level 1 1)
+    (gnus-group-select-group 5)
+    (message "***** Getting article with certain MID and check subject.")
+    (set-buffer gnus-summary-buffer)
+    (gnus-summary-refer-article "m3mxr8pa1t.fsf@quimbies.gnus.org")
+    (should (string= (gnus-summary-article-subject) "Re: gwene idea: strip from from subject if present"))
+    (gnus-summary-exit)
+    (message "***** Quitting Gnus.")
+    (set-buffer gnus-group-buffer)
+    (gnus-group-save-newsrc)
+    (gnus-group-exit))
+)
+
+;; Local Variables:
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; End:
diff --git a/xemacs-packages/gnus/lisp/tests/gnustest-registry.el b/xemacs-packages/gnus/lisp/tests/gnustest-registry.el
new file mode 100644 (file)
index 0000000..ea8c64b
--- /dev/null
@@ -0,0 +1,259 @@
+;;; gnustest-registry.el --- Registry and Gnus registry testing for Gnus
+;; Copyright (C) 2011-2016 Free Software Foundation, Inc.
+
+;; Author: Ted Zlatanov <tzz@lifelogs.com>
+
+;; This file is not 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 3, 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.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile
+  (when (null (ignore-errors (require 'ert)))
+    (defmacro* ert-deftest (name () &body docstring-keys-and-body))))
+
+(ignore-errors
+  (require 'ert))
+
+(require 'registry)
+(require 'gnus-registry)
+
+(ert-deftest gnustest-registry-instantiation-test ()
+  (should (registry-db "Testing")))
+
+(ert-deftest gnustest-registry-match-test ()
+  (let ((entry '((hello "goodbye" "bye") (blank))))
+
+    (message "Testing :regex matching")
+    (should (registry--match :regex entry '((hello "nye" "bye"))))
+    (should (registry--match :regex entry '((hello "good"))))
+    (should-not (registry--match :regex entry '((hello "nye"))))
+    (should-not (registry--match :regex entry '((hello))))
+
+    (message "Testing :member matching")
+    (should (registry--match :member entry '((hello "bye"))))
+    (should (registry--match :member entry '((hello "goodbye"))))
+    (should-not (registry--match :member entry '((hello "good"))))
+    (should-not (registry--match :member entry '((hello "nye"))))
+    (should-not (registry--match :member entry '((hello)))))
+  (message "Done with matching testing."))
+
+(defun gnustest-registry-sort-function (l r)
+  "Sort lower values of sort-field earlier."
+  (< (cadr (assq 'sort-field l))
+     (cadr (assq 'sort-field r))))
+
+(defun gnustest-registry-make-testable-db (n &optional prune-factor name file)
+  (let* ((db (registry-db
+              (or name "Testing")
+              :file (or file "unused")
+              :max-size n
+             :prune-factor (or prune-factor 0.1)
+              :precious '(extra more-extra)
+              :tracked '(sender subject groups))))
+    (dotimes (i n)
+      (registry-insert db i `((sender "me")
+                              (subject "about you")
+                              (more-extra) ; Empty data key should be pruned.
+                              ;; First 5 entries will NOT have this extra data.
+                              ,@(when (< 4 i) (list (list 'extra "more data")))
+                             (sort-field ,(- n i))
+                              (groups ,(number-to-string i)))))
+    db))
+
+(ert-deftest gnustest-registry-usage-test ()
+  (let* ((n 100)
+         (db (gnustest-registry-make-testable-db n)))
+    (message "size %d" n)
+    (should (= n (registry-size db)))
+    (message "max-hard test")
+    (should-error (registry-insert db "new" '()))
+    (message "Individual lookup")
+    (should (= 58 (caadr (registry-lookup db '(1 58 99)))))
+    (message "Grouped individual lookup")
+    (should (= 3 (length (registry-lookup db '(1 58 99)))))
+    (when (boundp 'lexical-binding)
+      (message "Individual lookup (breaks before lexbind)")
+      (should (= 58
+                 (caadr (registry-lookup-breaks-before-lexbind db '(1 58 99)))))
+      (message "Grouped individual lookup (breaks before lexbind)")
+      (should (= 3
+                 (length (registry-lookup-breaks-before-lexbind db
+                                                                '(1 58 99))))))
+    (message "Search")
+    (should (= n (length (registry-search db :all t))))
+    (should (= n (length (registry-search db :member '((sender "me"))))))
+    (message "Secondary index search")
+    (should (= n (length (registry-lookup-secondary-value db 'sender "me"))))
+    (should (equal '(74) (registry-lookup-secondary-value db 'groups "74")))
+    (message "Delete")
+    (should (registry-delete db '(1) t))
+    (decf n)
+    (message "Search after delete")
+    (should (= n (length (registry-search db :all t))))
+    (message "Secondary search after delete")
+    (should (= n (length (registry-lookup-secondary-value db 'sender "me"))))
+    (message "Done with usage testing.")))
+
+(ert-deftest gnustest-registry-pruning-test ()
+  "Check that precious entries are never pruned."
+  (let ((dbs (list
+             ;; Can prune fully without touching precious entries.
+             (gnustest-registry-make-testable-db 10 0.1)
+             ;; Pruning limited by precious entries.
+             (gnustest-registry-make-testable-db 10 0.6))))
+    (dolist (db dbs)
+      (message "Pruning")
+      (let* ((size (registry-size db))
+            (limit (- (oref db :max-size)
+                      (* (oref db :max-size)
+                         (oref db :prune-factor))))
+            (keepers (registry-search db :member '((extra "more data"))))
+            (expected-prune-count (min (- size (length keepers))
+                                       (- size limit)))
+            (actual-prune-count (registry-prune db)))
+       (ert-info
+           ((format "Expected to prune %d entries but pruned %d"
+                    expected-prune-count actual-prune-count)
+            :prefix "Error: ")
+         (should (= expected-prune-count actual-prune-count)))))))
+
+(ert-deftest gnustest-registry-pruning-sort-test ()
+  "Check that entries are sorted properly before pruning."
+  (let ((db (gnustest-registry-make-testable-db 10 0.4))
+       ;; These entries have the highest 'sort-field values.  Pruning
+       ;; sorts by lowest values first, then prunes from the front of
+       ;; the list, so these entries survive
+       (expected-survivors '(5 6 7 8 9 0))
+       actual-survivors disjunct)
+    (registry-prune
+     db #'gnustest-registry-sort-function)
+    (maphash (lambda (k v) (push k actual-survivors))
+            (oref db :data))
+    (setq disjunct (cl-set-exclusive-or
+                   expected-survivors
+                   actual-survivors))
+    (ert-info
+       ((format "Incorrect pruning: %s" disjunct)
+        :prefix "Error: ")
+      (should (null disjunct)))))
+
+(ert-deftest gnustest-registry-persistence-test ()
+  (let* ((n 100)
+         (tempfile (make-temp-file "registry-persistence-"))
+         (name "persistence tester")
+         (db (gnustest-registry-make-testable-db n nil name tempfile))
+         size back)
+    (message "Saving to %s" tempfile)
+    (eieio-persistent-save db)
+    (setq size (nth 7 (file-attributes tempfile)))
+    (message "Saved to %s: size %d" tempfile size)
+    (should (< 0 size))
+    (with-temp-buffer
+      (insert-file-contents-literally tempfile)
+      (should (looking-at (concat ";; Object "
+                                  name
+                                  "\n;; EIEIO PERSISTENT OBJECT"))))
+    (message "Reading object back")
+    (setq back (eieio-persistent-read tempfile))
+    (should back)
+    (message "Read object back: %d keys, expected %d==%d"
+             (registry-size back) n (registry-size db))
+    (should (= (registry-size back) n))
+    (should (= (registry-size back) (registry-size db)))
+    (delete-file tempfile))
+  (message "Done with persistence testing."))
+
+(ert-deftest gnustest-gnus-registry-misc-test ()
+  (should-error (gnus-registry-extract-addresses '("" "")))
+
+  (should (equal '("Ted Zlatanov <tzz@lifelogs.com>"
+                   "noname <ed@you.me>"
+                   "noname <cyd@stupidchicken.com>"
+                   "noname <tzz@lifelogs.com>")
+                 (gnus-registry-extract-addresses
+                  (concat "Ted Zlatanov <tzz@lifelogs.com>, "
+                          "ed <ed@you.me>, " ; "ed" is not a valid name here
+                          "cyd@stupidchicken.com, "
+                          "tzz@lifelogs.com")))))
+
+(ert-deftest gnustest-gnus-registry-usage-test ()
+  (let* ((n 100)
+         (tempfile (make-temp-file "gnus-registry-persist"))
+         (db (gnus-registry-make-db tempfile))
+         (gnus-registry-db db)
+         back size)
+    (message "Adding %d keys to the test Gnus registry" n)
+    (dotimes (i n)
+      (let ((id (number-to-string i)))
+        (gnus-registry-handle-action id
+                                     (if (>= 50 i) "fromgroup" nil)
+                                     "togroup"
+                                     (when (>= 70 i)
+                                       (format "subject %d" (mod i 10)))
+                                     (when (>= 80 i)
+                                       (format "sender %d" (mod i 10))))))
+    (message "Testing Gnus registry size is %d" n)
+    (should (= n (registry-size db)))
+    (message "Looking up individual keys (registry-lookup)")
+    (should (equal (loop for e
+                         in (mapcar 'cadr
+                                    (registry-lookup db '("20" "83" "72")))
+                         collect (assq 'subject e)
+                         collect (assq 'sender e)
+                         collect (assq 'group e))
+                   '((subject "subject 0") (sender "sender 0") (group "togroup")
+                     (subject) (sender) (group "togroup")
+                     (subject) (sender "sender 2") (group "togroup"))))
+
+    (message "Looking up individual keys (gnus-registry-id-key)")
+    (should (equal (gnus-registry-get-id-key "34" 'group) '("togroup")))
+    (should (equal (gnus-registry-get-id-key "34" 'subject) '("subject 4")))
+    (message "Trying to insert a duplicate key")
+    (should-error (gnus-registry-insert db "55" '()))
+    (message "Looking up individual keys (gnus-registry-get-or-make-entry)")
+    (should (gnus-registry-get-or-make-entry "22"))
+    (message "Saving the Gnus registry to %s" tempfile)
+    (should (gnus-registry-save tempfile db))
+    (setq size (nth 7 (file-attributes tempfile)))
+    (message "Saving the Gnus registry to %s: size %d" tempfile size)
+    (should (< 0 size))
+    (with-temp-buffer
+      (insert-file-contents-literally tempfile)
+      (should (looking-at (concat ";; Object "
+                                  "Gnus Registry"
+                                  "\n;; EIEIO PERSISTENT OBJECT"))))
+    (message "Reading Gnus registry back")
+    (setq back (eieio-persistent-read tempfile))
+    (should back)
+    (message "Read Gnus registry back: %d keys, expected %d==%d"
+             (registry-size back) n (registry-size db))
+    (should (= (registry-size back) n))
+    (should (= (registry-size back) (registry-size db)))
+    (delete-file tempfile)
+    (message "Pruning Gnus registry to 0 by setting :max-size")
+    (oset db :max-size 0)
+    (registry-prune db)
+    (should (= (registry-size db) 0)))
+  (message "Done with Gnus registry usage testing."))
+
+(provide 'gnustest-registry)
+
+;; Local Variables:
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; End:
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/.gpg-v21-migrated b/xemacs-packages/gnus/lisp/tests/mml-gpghome/.gpg-v21-migrated
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/gpg-agent.conf b/xemacs-packages/gnus/lisp/tests/mml-gpghome/gpg-agent.conf
new file mode 100644 (file)
index 0000000..2019299
--- /dev/null
@@ -0,0 +1,5 @@
+# pinentry-program /usr/bin/pinentry-gtk-2
+
+# verbose
+# log-file /tmp/gpg-agent.log
+# debug-all
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/02089CDDC6DFE93B8EA10D9E876F983E61FEC476.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/02089CDDC6DFE93B8EA10D9E876F983E61FEC476.key
new file mode 100644 (file)
index 0000000..58fd0b5
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/02089CDDC6DFE93B8EA10D9E876F983E61FEC476.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/171B444DE92BEF997229000D9784118A94EEC1C9.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/171B444DE92BEF997229000D9784118A94EEC1C9.key
new file mode 100644 (file)
index 0000000..62f4ab2
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/171B444DE92BEF997229000D9784118A94EEC1C9.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/19FFEBC04DF3E037E16F6A4474DCB7984406975D.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/19FFEBC04DF3E037E16F6A4474DCB7984406975D.key
new file mode 100644 (file)
index 0000000..2a8ce13
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/19FFEBC04DF3E037E16F6A4474DCB7984406975D.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/1E36D27DF9DAB96302D35268DADC5CE73EF45A2A.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/1E36D27DF9DAB96302D35268DADC5CE73EF45A2A.key
new file mode 100644 (file)
index 0000000..9f8de71
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/1E36D27DF9DAB96302D35268DADC5CE73EF45A2A.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/293109315BE584AB2EFEFCFCAD64666221D8B36C.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/293109315BE584AB2EFEFCFCAD64666221D8B36C.key
new file mode 100644 (file)
index 0000000..6e4a4e5
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/293109315BE584AB2EFEFCFCAD64666221D8B36C.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/335689599E1C0F66D73ADCF51E03EE36C97D121F.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/335689599E1C0F66D73ADCF51E03EE36C97D121F.key
new file mode 100644 (file)
index 0000000..cff58ed
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/335689599E1C0F66D73ADCF51E03EE36C97D121F.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/40BF94E540E3726CB150A1ADF7C1B514444B3FA6.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/40BF94E540E3726CB150A1ADF7C1B514444B3FA6.key
new file mode 100644 (file)
index 0000000..14af866
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/40BF94E540E3726CB150A1ADF7C1B514444B3FA6.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/515D4637EFC6C09DB1F78BE8C2F2A3D63E7756C3.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/515D4637EFC6C09DB1F78BE8C2F2A3D63E7756C3.key
new file mode 100644 (file)
index 0000000..207a723
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/515D4637EFC6C09DB1F78BE8C2F2A3D63E7756C3.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/5A11B1935C46D0B227A73978DCA1293A85604F1D.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/5A11B1935C46D0B227A73978DCA1293A85604F1D.key
new file mode 100644 (file)
index 0000000..85ca78d
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/5A11B1935C46D0B227A73978DCA1293A85604F1D.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/62643CEBC7AEBE6817577A34399483700D76BD64.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/62643CEBC7AEBE6817577A34399483700D76BD64.key
new file mode 100644 (file)
index 0000000..79f3cd2
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/62643CEBC7AEBE6817577A34399483700D76BD64.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/680D01F368916A0021C14E3453B27B3C5F900683.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/680D01F368916A0021C14E3453B27B3C5F900683.key
new file mode 100644 (file)
index 0000000..776ddf7
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/680D01F368916A0021C14E3453B27B3C5F900683.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/6DF2D9DF7AED06F0524BEB642DF0FB48EFDBDB93.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/6DF2D9DF7AED06F0524BEB642DF0FB48EFDBDB93.key
new file mode 100644 (file)
index 0000000..2b464f0
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/6DF2D9DF7AED06F0524BEB642DF0FB48EFDBDB93.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/78C17E134E86E691297F7B719B2F2CDF41976234.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/78C17E134E86E691297F7B719B2F2CDF41976234.key
new file mode 100644 (file)
index 0000000..28a0766
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/78C17E134E86E691297F7B719B2F2CDF41976234.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/7F714F4D9D9676638214991E96D45704E4FFC409.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/7F714F4D9D9676638214991E96D45704E4FFC409.key
new file mode 100644 (file)
index 0000000..1376596
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/7F714F4D9D9676638214991E96D45704E4FFC409.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/854752F5D8090CA36EFBDD79C72BDFF6FA2D1FF0.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/854752F5D8090CA36EFBDD79C72BDFF6FA2D1FF0.key
new file mode 100644 (file)
index 0000000..c99824c
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/854752F5D8090CA36EFBDD79C72BDFF6FA2D1FF0.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/93FF37C268FDBF0767F5FFDC49409DDAC9388B2C.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/93FF37C268FDBF0767F5FFDC49409DDAC9388B2C.key
new file mode 100644 (file)
index 0000000..49c2dc5
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/93FF37C268FDBF0767F5FFDC49409DDAC9388B2C.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/A3BA94EAE83509CC90DB1B77B54A51959D8DABEA.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/A3BA94EAE83509CC90DB1B77B54A51959D8DABEA.key
new file mode 100644 (file)
index 0000000..ca12840
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/A3BA94EAE83509CC90DB1B77B54A51959D8DABEA.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/A73E9D01F0465B518E8E7D5AD529077AAC1603B4.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/A73E9D01F0465B518E8E7D5AD529077AAC1603B4.key
new file mode 100644 (file)
index 0000000..3f14b40
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/A73E9D01F0465B518E8E7D5AD529077AAC1603B4.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/AE6A24B17A8D0CAF9B7E000AA77F0B41D7BFFFCF.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/AE6A24B17A8D0CAF9B7E000AA77F0B41D7BFFFCF.key
new file mode 100644 (file)
index 0000000..06adc06
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/AE6A24B17A8D0CAF9B7E000AA77F0B41D7BFFFCF.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/C072AF82DCCCB9A7F1B85FFA10B802DC4ED16703.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/C072AF82DCCCB9A7F1B85FFA10B802DC4ED16703.key
new file mode 100644 (file)
index 0000000..cf9a60d
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/C072AF82DCCCB9A7F1B85FFA10B802DC4ED16703.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/C43E1A079B28DFAEBB39CBA01793BDE11EF4B490.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/C43E1A079B28DFAEBB39CBA01793BDE11EF4B490.key
new file mode 100644 (file)
index 0000000..0ed3517
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/C43E1A079B28DFAEBB39CBA01793BDE11EF4B490.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/C67DAD345455EAD6D51368008FC3A53B8D195B5A.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/C67DAD345455EAD6D51368008FC3A53B8D195B5A.key
new file mode 100644 (file)
index 0000000..090059d
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/C67DAD345455EAD6D51368008FC3A53B8D195B5A.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/CB5E00CE582C2645D2573FC16B2F14F85A7F47AA.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/CB5E00CE582C2645D2573FC16B2F14F85A7F47AA.key
new file mode 100644 (file)
index 0000000..9061f67
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/CB5E00CE582C2645D2573FC16B2F14F85A7F47AA.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/CC68630A06B048F5A91136C162C7A3273E20DE6F.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/CC68630A06B048F5A91136C162C7A3273E20DE6F.key
new file mode 100644 (file)
index 0000000..89f6013
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/CC68630A06B048F5A91136C162C7A3273E20DE6F.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/E7E73903E1BF93481DE0E7C9769D6C31E1863CFF.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/E7E73903E1BF93481DE0E7C9769D6C31E1863CFF.key
new file mode 100644 (file)
index 0000000..41dac37
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/E7E73903E1BF93481DE0E7C9769D6C31E1863CFF.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/F0117468BE801ED4B81972E159A98FDD4814DCEC.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/F0117468BE801ED4B81972E159A98FDD4814DCEC.key
new file mode 100644 (file)
index 0000000..5df7b4a
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/F0117468BE801ED4B81972E159A98FDD4814DCEC.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/F4C5EFD5779BE892CAFD5B721D68DED677C9B151.key b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/F4C5EFD5779BE892CAFD5B721D68DED677C9B151.key
new file mode 100644 (file)
index 0000000..03daf80
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/private-keys-v1.d/F4C5EFD5779BE892CAFD5B721D68DED677C9B151.key differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/pubring.gpg b/xemacs-packages/gnus/lisp/tests/mml-gpghome/pubring.gpg
new file mode 100644 (file)
index 0000000..6bd1699
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/pubring.gpg differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/pubring.gpg~ b/xemacs-packages/gnus/lisp/tests/mml-gpghome/pubring.gpg~
new file mode 100644 (file)
index 0000000..6bd1699
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/pubring.gpg~ differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/pubring.kbx b/xemacs-packages/gnus/lisp/tests/mml-gpghome/pubring.kbx
new file mode 100644 (file)
index 0000000..399a041
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/pubring.kbx differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/pubring.kbx~ b/xemacs-packages/gnus/lisp/tests/mml-gpghome/pubring.kbx~
new file mode 100644 (file)
index 0000000..0635271
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/pubring.kbx~ differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/secring.gpg b/xemacs-packages/gnus/lisp/tests/mml-gpghome/secring.gpg
new file mode 100644 (file)
index 0000000..b323c07
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/secring.gpg differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/trustdb.gpg b/xemacs-packages/gnus/lisp/tests/mml-gpghome/trustdb.gpg
new file mode 100644 (file)
index 0000000..09ebd8d
Binary files /dev/null and b/xemacs-packages/gnus/lisp/tests/mml-gpghome/trustdb.gpg differ
diff --git a/xemacs-packages/gnus/lisp/tests/mml-gpghome/trustlist.txt b/xemacs-packages/gnus/lisp/tests/mml-gpghome/trustlist.txt
new file mode 100644 (file)
index 0000000..f886572
--- /dev/null
@@ -0,0 +1,26 @@
+# This is the list of trusted keys.  Comment lines, like this one, as
+# well as empty lines are ignored.  Lines have a length limit but this
+# is not a serious limitation as the format of the entries is fixed and
+# checked by gpg-agent.  A non-comment line starts with optional white
+# space, followed by the SHA-1 fingerpint in hex, followed by a flag
+# which may be one of 'P', 'S' or '*' and optionally followed by a list of
+# other flags.  The fingerprint may be prefixed with a '!' to mark the
+# key as not trusted.  You should give the gpg-agent a HUP or run the
+# command "gpgconf --reload gpg-agent" after changing this file.
+
+
+# Include the default trust list
+include-default
+
+
+# CN=No Expiry
+D0:6A:A1:18:65:3C:C3:8E:9D:0C:AF:56:ED:7A:21:35:E1:58:21:77 S relax
+
+# CN=Second Key Pair
+0E:58:22:9B:80:EE:33:95:9F:F7:18:FE:EF:25:40:2B:47:9D:C6:E2 S relax
+
+# CN=No Expiry two UIDs
+D4:CA:78:E1:47:0B:9F:C2:AE:45:D7:84:64:9B:8C:E6:4E:BB:32:0C S relax
+
+# CN=Different subkeys
+4F:96:2A:B7:F4:76:61:6A:78:3D:72:AA:40:35:D5:9B:5F:88:E9:FC S relax
diff --git a/xemacs-packages/gnus/lisp/time-date.el b/xemacs-packages/gnus/lisp/time-date.el
new file mode 100644 (file)
index 0000000..da3e2a2
--- /dev/null
@@ -0,0 +1,440 @@
+;;; time-date.el --- Date and time handling functions
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;;     Masanobu Umeda <umerin@mse.kyutech.ac.jp>
+;; Keywords: mail news util
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Time values come in several formats.  The oldest format is a cons
+;; cell of the form (HIGH . LOW).  This format is obsolete, but still
+;; supported.  The other formats are the lists (HIGH LOW), (HIGH LOW
+;; USEC), and (HIGH LOW USEC PSEC).  These formats specify the time
+;; value equal to HIGH * 2^16 + LOW + USEC * 10^-6 + PSEC * 10^-12
+;; seconds, where missing components are treated as zero.  HIGH can be
+;; negative, either because the value is a time difference, or because
+;; it represents a time stamp before the epoch.  Typically, there are
+;; more time values than the underlying system time type supports,
+;; but the reverse can also be true.
+
+;;; Code:
+
+(defmacro with-decoded-time-value (varlist &rest body)
+  "Decode a time value and bind it according to VARLIST, then eval BODY.
+
+The value of the last form in BODY is returned.
+
+Each element of the list VARLIST is a list of the form
+\(HIGH-SYMBOL LOW-SYMBOL MICRO-SYMBOL [PICO-SYMBOL [TYPE-SYMBOL]] TIME-VALUE).
+The time value TIME-VALUE is decoded and the result is bound to
+the symbols HIGH-SYMBOL, LOW-SYMBOL and MICRO-SYMBOL.
+The optional PICO-SYMBOL is bound to the picoseconds part.
+
+The optional TYPE-SYMBOL is bound to the type of the time value.
+Type 0 is the cons cell (HIGH . LOW), type 1 is the list (HIGH
+LOW), type 2 is the list (HIGH LOW MICRO), and type 3 is the
+list (HIGH LOW MICRO PICO)."
+  (declare (indent 1)
+          (debug ((&rest (symbolp symbolp symbolp
+                           &or [symbolp symbolp form] [symbolp form] form))
+                  body)))
+  (if varlist
+      (let* ((elt (pop varlist))
+            (high (pop elt))
+            (low (pop elt))
+            (micro (pop elt))
+            (pico (unless (<= (length elt) 2)
+                    (pop elt)))
+            (type (unless (eq (length elt) 1)
+                    (pop elt)))
+            (time-value (car elt))
+            (gensym (make-symbol "time")))
+       `(let* ,(append `((,gensym (or ,time-value (current-time)))
+                         (,gensym
+                          (cond
+                           ((integerp ,gensym)
+                            (list (ash ,gensym -16)
+                                  (logand ,gensym 65535)))
+                           ((floatp ,gensym)
+                            (let* ((usec (* 1000000 (mod ,gensym 1)))
+                                   (ps (round (* 1000000 (mod usec 1))))
+                                   (us (floor usec))
+                                   (lo (floor (mod ,gensym 65536)))
+                                   (hi (floor ,gensym 65536)))
+                              (if (eq ps 1000000)
+                                  (progn
+                                    (setq ps 0)
+                                    (setq us (1+ us))
+                                    (if (eq us 1000000)
+                                        (progn
+                                          (setq us 0)
+                                          (setq lo (1+ lo))
+                                          (if (eq lo 65536)
+                                              (progn
+                                                (setq lo 0)
+                                                (setq hi (1+ hi))))))))
+                              (list hi lo us ps)))
+                           (t ,gensym)))
+                         (,high (pop ,gensym))
+                         ,low ,micro)
+                       (when pico `(,pico))
+                       (when type `(,type)))
+          (if (consp ,gensym)
+              (progn
+                (setq ,low (pop ,gensym))
+                (if ,gensym
+                    (progn
+                      (setq ,micro (car ,gensym))
+                      ,(cond (pico
+                              `(if (cdr ,gensym)
+                                   ,(append `(setq ,pico (cadr ,gensym))
+                                            (when type `(,type 3)))
+                                 ,(append `(setq ,pico 0)
+                                          (when type `(,type 2)))))
+                             (type
+                              `(setq type 2))))
+                  ,(append `(setq ,micro 0)
+                           (when pico `(,pico 0))
+                           (when type `(,type 1)))))
+            ,(append `(setq ,low ,gensym ,micro 0)
+                     (when pico `(,pico 0))
+                     (when type `(,type 0))))
+          (with-decoded-time-value ,varlist ,@body)))
+    `(progn ,@body)))
+
+(defun encode-time-value (high low micro pico &optional type)
+  "Encode HIGH, LOW, MICRO, and PICO into a time value of type TYPE.
+Type 0 is the cons cell (HIGH . LOW), type 1 is the list (HIGH LOW),
+type 2 is (HIGH LOW MICRO), and type 3 is (HIGH LOW MICRO PICO).
+
+For backward compatibility, if only four arguments are given,
+it is assumed that PICO was omitted and should be treated as zero."
+  (cond
+   ((eq type 0) (cons high low))
+   ((eq type 1) (list high low))
+   ((eq type 2) (list high low micro))
+   ((eq type 3) (list high low micro pico))
+   ((null type) (encode-time-value high low micro 0 pico))))
+
+(when (and (fboundp 'time-add) (subrp (symbol-function 'time-add)))
+  (make-obsolete 'encode-time-value nil "25.1")
+  (make-obsolete 'with-decoded-time-value nil "25.1"))
+
+(autoload 'parse-time-string "parse-time")
+(autoload 'timezone-make-date-arpa-standard "timezone")
+
+;;;###autoload
+;; `parse-time-string' isn't sufficiently general or robust.  It fails
+;; to grok some of the formats that timezone does (e.g. dodgy
+;; post-2000 stuff from some Elms) and either fails or returns bogus
+;; values.  timezone-make-date-arpa-standard should help.
+(defun date-to-time (date)
+  "Parse a string DATE that represents a date-time and return a time value.
+If DATE lacks timezone information, GMT is assumed."
+  (condition-case err
+      (apply 'encode-time (parse-time-string date))
+    (error
+     (let ((overflow-error '(error "Specified time is not representable")))
+       (if (equal err overflow-error)
+          (apply 'signal err)
+        (condition-case err
+            (apply 'encode-time
+                   (parse-time-string
+                    (timezone-make-date-arpa-standard date)))
+          (error
+           (if (equal err overflow-error)
+               (apply 'signal err)
+             (error "Invalid date: %s" date)))))))))
+
+;; Bit of a mess.  Emacs has float-time since at least 21.1.
+;; This file is synced to Gnus, and XEmacs packages may have been written
+;; using time-to-seconds from the Gnus library.
+;;;###autoload(if (or (featurep 'emacs)
+;;;###autoload        (and (fboundp 'float-time)
+;;;###autoload             (subrp (symbol-function 'float-time))))
+;;;###autoload    (defalias 'time-to-seconds 'float-time)
+;;;###autoload  (autoload 'time-to-seconds "time-date"))
+
+(eval-when-compile
+  (or (featurep 'emacs)
+      (and (fboundp 'float-time)
+           (subrp (symbol-function 'float-time)))
+      (defun time-to-seconds (&optional time)
+        "Convert optional value TIME to a floating point number.
+TIME defaults to the current time."
+        (with-decoded-time-value ((high low micro pico _type
+                                  (or time (current-time))))
+          (+ (* high 65536.0)
+             low
+            (/ (+ (* micro 1e6) pico) 1e12))))))
+
+;;;###autoload
+(defun seconds-to-time (seconds)
+  "Convert SECONDS to a time value."
+  (time-add 0 seconds))
+
+;;;###autoload
+(defun days-to-time (days)
+  "Convert DAYS into a time value."
+  (let ((time (condition-case nil (seconds-to-time (* 86400.0 days))
+               (range-error (list most-positive-fixnum 65535)))))
+    (if (integerp days)
+       (setcdr (cdr time) nil))
+    time))
+
+;;;###autoload
+(defun time-since (time)
+  "Return the time elapsed since TIME.
+TIME should be either a time value or a date-time string."
+  (when (stringp time)
+    ;; Convert date strings to internal time.
+    (setq time (date-to-time time)))
+  (time-subtract nil time))
+
+;;;###autoload
+(defalias 'subtract-time 'time-subtract)
+
+;; These autoloads do nothing in Emacs 25, where the functions are builtin.
+;;;###autoload(autoload 'time-add "time-date")
+;;;###autoload(autoload 'time-subtract "time-date")
+;;;###autoload(autoload 'time-less-p "time-date")
+
+(eval-and-compile
+  (when (not (and (fboundp 'time-add) (subrp (symbol-function 'time-add))))
+
+    (defun time-add (t1 t2)
+      "Add two time values T1 and T2.  One should represent a time difference."
+      (with-decoded-time-value ((high low micro pico type t1)
+                               (high2 low2 micro2 pico2 type2 t2))
+       (setq high (+ high high2)
+             low (+ low low2)
+             micro (+ micro micro2)
+             pico (+ pico pico2)
+             type (max type type2))
+       (when (>= pico 1000000)
+         (setq micro (1+ micro)
+               pico (- pico 1000000)))
+       (when (>= micro 1000000)
+         (setq low (1+ low)
+               micro (- micro 1000000)))
+       (when (>= low 65536)
+         (setq high (1+ high)
+               low (- low 65536)))
+       (encode-time-value high low micro pico type)))
+
+    (defun time-subtract (t1 t2)
+      "Subtract two time values, T1 minus T2.
+Return the difference in the format of a time value."
+      (with-decoded-time-value ((high low micro pico type t1)
+                               (high2 low2 micro2 pico2 type2 t2))
+       (setq high (- high high2)
+             low (- low low2)
+             micro (- micro micro2)
+             pico (- pico pico2)
+             type (max type type2))
+       (when (< pico 0)
+         (setq micro (1- micro)
+               pico (+ pico 1000000)))
+       (when (< micro 0)
+         (setq low (1- low)
+               micro (+ micro 1000000)))
+       (when (< low 0)
+         (setq high (1- high)
+               low (+ low 65536)))
+       (encode-time-value high low micro pico type)))
+
+    (defun time-less-p (t1 t2)
+      "Return non-nil if time value T1 is earlier than time value T2."
+      (with-decoded-time-value ((high1 low1 micro1 pico1 _type1 t1)
+                               (high2 low2 micro2 pico2 _type2 t2))
+       (or (< high1 high2)
+           (and (= high1 high2)
+                (or (< low1 low2)
+                    (and (= low1 low2)
+                         (or (< micro1 micro2)
+                             (and (= micro1 micro2)
+                                  (< pico1 pico2)))))))))))
+
+;;;###autoload
+(defun date-to-day (date)
+  "Return the number of days between year 1 and DATE.
+DATE should be a date-time string."
+  (time-to-days (date-to-time date)))
+
+;;;###autoload
+(defun days-between (date1 date2)
+  "Return the number of days between DATE1 and DATE2.
+DATE1 and DATE2 should be date-time strings."
+  (- (date-to-day date1) (date-to-day date2)))
+
+;;;###autoload
+(defun date-leap-year-p (year)
+  "Return t if YEAR is a leap year."
+  (or (and (zerop (% year 4))
+          (not (zerop (% year 100))))
+      (zerop (% year 400))))
+
+(defun time-date--day-in-year (tim)
+  "Return the day number within the year corresponding to the decoded time TIM."
+  (let* ((month (nth 4 tim))
+        (day (nth 3 tim))
+        (year (nth 5 tim))
+        (day-of-year (+ day (* 31 (1- month)))))
+    (when (> month 2)
+      (setq day-of-year (- day-of-year (/ (+ 23 (* 4 month)) 10)))
+      (when (date-leap-year-p year)
+       (setq day-of-year (1+ day-of-year))))
+    day-of-year))
+
+;;;###autoload
+(defun time-to-day-in-year (time)
+  "Return the day number within the year corresponding to TIME."
+  (time-date--day-in-year (decode-time time)))
+
+;;;###autoload
+(defun time-to-days (time)
+  "The number of days between the Gregorian date 0001-12-31bce and TIME.
+TIME should be a time value.
+The Gregorian date Sunday, December 31, 1bce is imaginary."
+  (let* ((tim (decode-time time))
+        (year (nth 5 tim)))
+    (+ (time-date--day-in-year tim)    ;       Days this year
+       (* 365 (1- year))               ;       + Days in prior years
+       (/ (1- year) 4)                 ;       + Julian leap years
+       (- (/ (1- year) 100))           ;       - century years
+       (/ (1- year) 400))))            ;       + Gregorian leap years
+
+(defun time-to-number-of-days (time)
+  "Return the number of days represented by TIME.
+Returns a floating point number."
+  (/ (funcall (eval-when-compile
+                (if (or (featurep 'emacs)
+                        (and (fboundp 'float-time)
+                             (subrp (symbol-function 'float-time))))
+                    'float-time
+                  'time-to-seconds)) time) (* 60 60 24)))
+
+;;;###autoload
+(defun safe-date-to-time (date)
+  "Parse a string DATE that represents a date-time and return a time value.
+If DATE is malformed, return a time value of zeros."
+  (condition-case ()
+      (date-to-time date)
+    (error '(0 0))))
+
+\f
+;;;###autoload
+(defun format-seconds (string seconds)
+  "Use format control STRING to format the number SECONDS.
+The valid format specifiers are:
+%y is the number of (365-day) years.
+%d is the number of days.
+%h is the number of hours.
+%m is the number of minutes.
+%s is the number of seconds.
+%z is a non-printing control flag (see below).
+%% is a literal \"%\".
+
+Upper-case specifiers are followed by the unit-name (e.g. \"years\").
+Lower-case specifiers return only the unit.
+
+\"%\" may be followed by a number specifying a width, with an
+optional leading \".\" for zero-padding.  For example, \"%.3Y\" will
+return something of the form \"001 year\".
+
+The \"%z\" specifier does not print anything.  When it is used, specifiers
+must be given in order of decreasing size.  To the left of \"%z\", nothing
+is output until the first non-zero unit is encountered.
+
+This function does not work for SECONDS greater than `most-positive-fixnum'."
+  (let ((start 0)
+        (units '(("y" "year"   31536000)
+                 ("d" "day"       86400)
+                 ("h" "hour"       3600)
+                 ("m" "minute"       60)
+                 ("s" "second"        1)
+                 ("z")))
+        (case-fold-search t)
+        spec match usedunits zeroflag larger prev name unit num zeropos)
+    (while (string-match "%\\.?[0-9]*\\(.\\)" string start)
+      (setq start (match-end 0)
+            spec (match-string 1 string))
+      (unless (string-equal spec "%")
+        (or (setq match (assoc (downcase spec) units))
+            (error "Bad format specifier: `%s'" spec))
+        (if (assoc (downcase spec) usedunits)
+            (error "Multiple instances of specifier: `%s'" spec))
+        (if (string-equal (car match) "z")
+            (setq zeroflag t)
+          (unless larger
+            (setq unit (nth 2 match)
+                  larger (and prev (> unit prev))
+                  prev unit)))
+        (push match usedunits)))
+    (and zeroflag larger
+         (error "Units are not in decreasing order of size"))
+    (dolist (u units)
+      (setq spec (car u)
+            name (cadr u)
+            unit (nth 2 u))
+      (when (string-match (format "%%\\(\\.?[0-9]+\\)?\\(%s\\)" spec) string)
+        (if (string-equal spec "z")     ; must be last in units
+            (setq string
+                  (replace-regexp-in-string
+                   "%z" ""
+                   (substring string (min (or zeropos (match-end 0))
+                                          (match-beginning 0)))))
+          ;; Cf article-make-date-line in gnus-art.
+          (setq num (floor seconds unit)
+                seconds (- seconds (* num unit)))
+          ;; Start position of the first non-zero unit.
+          (or zeropos
+              (setq zeropos (unless (zerop num) (match-beginning 0))))
+          (setq string
+                (replace-match
+                 (format (concat "%" (match-string 1 string) "d%s") num
+                         (if (string-equal (match-string 2 string) spec)
+                             ""       ; lower-case, no unit-name
+                           (format " %s%s" name
+                                   (if (= num 1) "" "s"))))
+                 t t string))))))
+  (replace-regexp-in-string "%%" "%" string))
+
+(defvar seconds-to-string
+  (list (list 1 "ms" 0.001)
+        (list 100 "s" 1)
+        (list (* 60 100) "m" 60.0)
+        (list (* 3600 30) "h" 3600.0)
+        (list (* 3600 24 400) "d" (* 3600.0 24.0))
+        (list nil "y" (* 365.25 24 3600)))
+  "Formatting used by the function `seconds-to-string'.")
+;;;###autoload
+(defun seconds-to-string (delay)
+  "Convert the time interval in seconds to a short string."
+  (cond ((> 0 delay) (concat "-" (seconds-to-string (- delay))))
+        ((= 0 delay) "0s")
+        (t (let ((sts seconds-to-string) here)
+             (while (and (car (setq here (pop sts)))
+                         (<= (car here) delay)))
+             (concat (format "%.2f" (/ delay (car (cddr here)))) (cadr here))))))
+
+(provide 'time-date)
+
+;;; time-date.el ends here
diff --git a/xemacs-packages/gnus/lisp/tls.el b/xemacs-packages/gnus/lisp/tls.el
new file mode 100644 (file)
index 0000000..3e5d974
--- /dev/null
@@ -0,0 +1,306 @@
+;;; tls.el --- TLS/SSL support via wrapper around GnuTLS
+
+;; Copyright (C) 1996-1999, 2002-2016 Free Software Foundation, Inc.
+
+;; Author: Simon Josefsson <simon@josefsson.org>
+;; Keywords: comm, tls, gnutls, ssl
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package implements a simple wrapper around "gnutls-cli" to
+;; make Emacs support TLS/SSL.
+;;
+;; Usage is the same as `open-network-stream', i.e.:
+;;
+;; (setq tmp (open-tls-stream "test" (current-buffer) "news.mozilla.org" 563))
+;; ...
+;; #<process test>
+;; (process-send-string tmp "mode reader\n")
+;; 200 secnews.netscape.com Netscape-Collabra/3.52 03615 NNRP ready ...
+;; nil
+;; (process-send-string tmp "quit\n")
+;; 205
+;; nil
+
+;; To use this package as a replacement for ssl.el by William M. Perry
+;; <wmperry@cs.indiana.edu>, you need to evaluate the following:
+;;
+;; (defalias 'open-ssl-stream 'open-tls-stream)
+
+;;; Code:
+
+(autoload 'format-spec "format-spec")
+(autoload 'format-spec-make "format-spec")
+
+(defgroup tls nil
+  "Transport Layer Security (TLS) parameters."
+  :group 'comm)
+
+(defcustom tls-end-of-info
+  (concat
+   "\\("
+   ;; `openssl s_client' regexp.  See ssl/ssl_txt.c lines 219-220.
+   ;; According to apps/s_client.c line 1515 `---' is always the last
+   ;; line that is printed by s_client before the real data.
+   "^    Verify return code: .+\n---\n\\|"
+   ;; `gnutls' regexp. See src/cli.c lines 721-.
+   "^- Simple Client Mode:\n"
+   "\\(\n\\|"                           ; ignore blank lines
+   ;; According to GnuTLS v2.1.5 src/cli.c lines 640-650 and 705-715
+   ;; in `main' the handshake will start after this message.  If the
+   ;; handshake fails, the programs will abort.
+   "^\\*\\*\\* Starting TLS handshake\n\\)*"
+   "\\)")
+  "Regexp matching end of TLS client informational messages.
+Client data stream begins after the last character matched by
+this.  The default matches `openssl s_client' (version 0.9.8c)
+and `gnutls-cli' (version 2.0.1) output."
+  :version "22.2"
+  :type 'regexp
+  :group 'tls)
+
+(defcustom tls-program '("gnutls-cli --insecure -p %p %h"
+                        "gnutls-cli --insecure -p %p %h --protocols ssl3"
+                        "openssl s_client -connect %h:%p -no_ssl2 -ign_eof")
+  "List of strings containing commands to start TLS stream to a host.
+Each entry in the list is tried until a connection is successful.
+%h is replaced with server hostname, %p with port to connect to.
+The program should read input on stdin and write output to stdout.
+
+See `tls-checktrust' on how to check trusted root certs.
+
+Also see `tls-success' for what the program should output after
+successful negotiation."
+  :type
+  '(choice
+    (const :tag "Default list of commands"
+          ("gnutls-cli --insecure -p %p %h"
+           "gnutls-cli --insecure -p %p %h --protocols ssl3"
+           "openssl s_client -connect %h:%p -no_ssl2 -ign_eof"))
+    (list :tag "Choose commands"
+         :value
+         ("gnutls-cli --insecure -p %p %h"
+          "gnutls-cli --insecure -p %p %h --protocols ssl3"
+          "openssl s_client -connect %h:%p -no_ssl2 -ign_eof")
+         (set :inline t
+              ;; FIXME: add brief `:tag "..."' descriptions.
+              ;; (repeat :inline t :tag "Other" (string))
+              ;; See `tls-checktrust':
+              (const "gnutls-cli --x509cafile /etc/ssl/certs/ca-certificates.crt -p %p %h")
+              (const "gnutls-cli --x509cafile /etc/ssl/certs/ca-certificates.crt -p %p %h --protocols ssl3")
+              (const "openssl s_client -connect %h:%p -CAfile /etc/ssl/certs/ca-certificates.crt -no_ssl2 -ign_eof")
+              ;; No trust check:
+              (const "gnutls-cli --insecure -p %p %h")
+              (const "gnutls-cli --insecure -p %p %h --protocols ssl3")
+              (const "openssl s_client -connect %h:%p -no_ssl2 -ign_eof"))
+         (repeat :inline t :tag "Other" (string)))
+    (list :tag "List of commands"
+         (repeat :tag "Command" (string))))
+  :version "22.1"
+  :group 'tls)
+
+(defcustom tls-process-connection-type nil
+  "Value for `process-connection-type' to use when starting TLS process."
+  :version "22.1"
+  :type 'boolean
+  :group 'tls)
+
+(defcustom tls-success "- Handshake was completed\\|SSL handshake has read "
+  "Regular expression indicating completed TLS handshakes.
+The default is what GnuTLS's \"gnutls-cli\" or OpenSSL's
+\"openssl s_client\" outputs."
+  :version "22.1"
+  :type 'regexp
+  :group 'tls)
+
+(defcustom tls-checktrust nil
+  "Indicate if certificates should be checked against trusted root certs.
+If this is `ask', the user can decide whether to accept an
+untrusted certificate.  You may have to adapt `tls-program' in
+order to make this feature work properly, i.e., to ensure that
+the external program knows about the root certificates you
+consider trustworthy, e.g.:
+
+\(setq tls-program
+      \\='(\"gnutls-cli --x509cafile /etc/ssl/certs/ca-certificates.crt -p %p %h\"
+       \"gnutls-cli --x509cafile /etc/ssl/certs/ca-certificates.crt -p %p %h --protocols ssl3\"
+       \"openssl s_client -connect %h:%p -CAfile /etc/ssl/certs/ca-certificates.crt -no_ssl2 -ign_eof\"))"
+  :type '(choice (const :tag "Always" t)
+                (const :tag "Never" nil)
+                (const :tag "Ask" ask))
+  :version "23.1" ;; No Gnus
+  :group 'tls)
+
+(defcustom tls-untrusted
+  "- Peer's certificate is NOT trusted\\|Verify return code: \\([^0] \\|.[^ ]\\)"
+  "Regular expression indicating failure of TLS certificate verification.
+The default is what GnuTLS's \"gnutls-cli\" or OpenSSL's
+\"openssl s_client\" return in the event of unsuccessful
+verification."
+  :type 'regexp
+  :version "23.1" ;; No Gnus
+  :group 'tls)
+
+(defcustom tls-hostmismatch
+  "# The hostname in the certificate does NOT match"
+  "Regular expression indicating a host name mismatch in certificate.
+When the host name specified in the certificate doesn't match the
+name of the host you are connecting to, gnutls-cli issues a
+warning to this effect.  There is no such feature in openssl.  Set
+this to nil if you want to ignore host name mismatches."
+  :type 'regexp
+  :version "23.1" ;; No Gnus
+  :group 'tls)
+
+(defcustom tls-certtool-program "certtool"
+  "Name of GnuTLS certtool.
+Used by `tls-certificate-information'."
+  :version "22.1"
+  :type 'string
+  :group 'tls)
+
+(defalias 'tls-format-message
+  (if (fboundp 'format-message) 'format-message
+    ;; for Emacs < 25, and XEmacs, don't worry about quote translation.
+    'format))
+
+(defun tls-certificate-information (der)
+  "Parse X.509 certificate in DER format into an assoc list."
+  (let ((certificate (concat "-----BEGIN CERTIFICATE-----\n"
+                            (base64-encode-string der)
+                            "\n-----END CERTIFICATE-----\n"))
+       (exit-code 0))
+    (with-current-buffer (get-buffer-create " *certtool*")
+      (erase-buffer)
+      (insert certificate)
+      (setq exit-code (condition-case ()
+                         (call-process-region (point-min) (point-max)
+                                              tls-certtool-program
+                                              t (list (current-buffer) nil) t
+                                              "--certificate-info")
+                       (error -1)))
+      (if (/= exit-code 0)
+         nil
+       (let ((vals nil))
+         (goto-char (point-min))
+         (while (re-search-forward "^\\([^:]+\\): \\(.*\\)" nil t)
+           (push (cons (match-string 1) (match-string 2)) vals))
+         (nreverse vals))))))
+
+(defun open-tls-stream (name buffer host port)
+  "Open a TLS connection for a port to a host.
+Returns a subprocess-object to represent the connection.
+Input and output work as for subprocesses; `delete-process' closes it.
+Args are NAME BUFFER HOST PORT.
+NAME is name for process.  It is modified if necessary to make it unique.
+BUFFER is the buffer (or buffer name) to associate with the process.
+ Process output goes at end of that buffer, unless you specify
+ an output stream or filter function to handle the output.
+ BUFFER may be also nil, meaning that this process is not associated
+ with any buffer
+Third arg is name of the host to connect to, or its IP address.
+Fourth arg PORT is an integer specifying a port to connect to."
+  (let ((cmds tls-program)
+       (use-temp-buffer (null buffer))
+       process cmd done)
+    (if use-temp-buffer
+       (setq buffer (generate-new-buffer " TLS"))
+      ;; BUFFER is a string but does not exist as a buffer object.
+      (unless (and (get-buffer buffer)
+                  (buffer-name (get-buffer buffer)))
+       (generate-new-buffer buffer)))
+    (with-current-buffer buffer
+      (message "Opening TLS connection to `%s'..." host)
+      (while (and (not done) (setq cmd (pop cmds)))
+       (let ((process-connection-type tls-process-connection-type)
+             (formatted-cmd
+              (format-spec
+               cmd
+               (format-spec-make
+                ?h host
+                ?p (if (integerp port)
+                       (int-to-string port)
+                     port)))))
+         (message "Opening TLS connection with `%s'..." formatted-cmd)
+         (setq process (start-process
+                        name buffer shell-file-name shell-command-switch
+                        formatted-cmd))
+         (while (and process
+                     (memq (process-status process) '(open run))
+                     (progn
+                       (goto-char (point-min))
+                       (not (setq done (re-search-forward
+                                        tls-success nil t)))))
+           (unless (accept-process-output process 1)
+             (sit-for 1)))
+         (message "Opening TLS connection with `%s'...%s" formatted-cmd
+                  (if done "done" "failed"))
+         (if (not done)
+             (delete-process process)
+           ;; advance point to after all informational messages that
+           ;; `openssl s_client' and `gnutls' print
+           (let ((start-of-data nil))
+             (while
+                 (not (setq start-of-data
+                            ;; the string matching `tls-end-of-info'
+                            ;; might come in separate chunks from
+                            ;; `accept-process-output', so start the
+                            ;; search where `tls-success' ended
+                            (save-excursion
+                              (if (re-search-forward tls-end-of-info nil t)
+                                  (match-end 0)))))
+               (accept-process-output process 1))
+             (if start-of-data
+                 ;; move point to start of client data
+                 (goto-char start-of-data)))
+           (setq done process))))
+      (when (and done
+                (or
+                 (and tls-checktrust
+                      (save-excursion
+                        (goto-char (point-min))
+                        (re-search-forward tls-untrusted nil t))
+                      (or
+                       (and (not (eq tls-checktrust 'ask))
+                            (message "The certificate presented by `%s' is \
+NOT trusted." host))
+                       (not (yes-or-no-p
+                             (tls-format-message "\
+The certificate presented by `%s' is NOT trusted. Accept anyway? " host)))))
+                 (and tls-hostmismatch
+                      (save-excursion
+                        (goto-char (point-min))
+                        (re-search-forward tls-hostmismatch nil t))
+                      (not (yes-or-no-p
+                            (format "Host name in certificate doesn't \
+match `%s'. Connect anyway? " host))))))
+       (setq done nil)
+       (delete-process process))
+      ;; Delete all the informational messages that could confuse
+      ;; future uses of `buffer'.
+      (delete-region (point-min) (point)))
+    (message "Opening TLS connection to `%s'...%s"
+            host (if done "done" "failed"))
+    (when use-temp-buffer
+      (if done (set-process-buffer process nil))
+      (kill-buffer buffer))
+    done))
+
+(provide 'tls)
+
+;;; tls.el ends here
diff --git a/xemacs-packages/gnus/lisp/utf7.el b/xemacs-packages/gnus/lisp/utf7.el
new file mode 100644 (file)
index 0000000..9b7191b
--- /dev/null
@@ -0,0 +1,231 @@
+;;; utf7.el --- UTF-7 encoding/decoding for Emacs   -*-coding: utf-8;-*-
+
+;; Copyright (C) 1999-2016 Free Software Foundation, Inc.
+
+;; Author: Jon K Hellan <hellan@acm.org>
+;; Maintainer: bugs@gnus.org
+;; Keywords: mail
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; UTF-7 - A Mail-Safe Transformation Format of Unicode - RFC 2152
+;; This is a transformation format of Unicode that contains only 7-bit
+;; ASCII octets and is intended to be readable by humans in the limiting
+;; case that the document consists of characters from the US-ASCII
+;; repertoire.
+;; In short, runs of characters outside US-ASCII are encoded as base64
+;; inside delimiters.
+;; A variation of UTF-7 is specified in IMAP 4rev1 (RFC 2060) as the way
+;; to represent characters outside US-ASCII in mailbox names in IMAP.
+;; This library supports both variants, but the IMAP variation was the
+;; reason I wrote it.
+;; The routines convert UTF-7 -> UTF-16 (16 bit encoding of Unicode)
+;; -> current character set, and vice versa.
+;; However, until Emacs supports Unicode, the only Emacs character set
+;; supported here is ISO-8859.1, which can trivially be converted to/from
+;; Unicode.
+;; When decoding results in a character outside the Emacs character set,
+;; an error is thrown.  It is up to the application to recover.
+
+;; UTF-7 should be done by providing a coding system.  Mule-UCS does
+;; already, but I don't know if it does the IMAP version and it's not
+;; clear whether that should really be a coding system.  The UTF-16
+;; part of the conversion can be done with coding systems available
+;; with Mule-UCS or some versions of Emacs.  Unfortunately these were
+;; done wrongly (regarding handling of byte-order marks and how the
+;; variants were named), so we don't have a consistent name for the
+;; necessary coding system.  The code below doesn't seem to DTRT
+;; generally.  E.g.:
+;;
+;; (utf7-encode "a+£")
+;;   => "a+ACsAow-"
+;;
+;; $ echo "a+£"|iconv -f utf-8 -t utf-7
+;; a+-+AKM
+;;
+;;  -- fx
+
+
+;;; Code:
+
+(require 'base64)
+(eval-when-compile (require 'cl))
+(require 'mm-util)
+
+(defconst utf7-direct-encoding-chars " -%'-*,-[]-}"
+  "Character ranges which do not need escaping in UTF-7.")
+
+(defconst utf7-imap-direct-encoding-chars
+  (concat utf7-direct-encoding-chars "+\\~")
+  "Character ranges which do not need escaping in the IMAP variant of UTF-7.")
+
+(defconst utf7-utf-16-coding-system
+  (cond ((mm-coding-system-p 'utf-16-be-no-signature) ; Mule-UCS
+        'utf-16-be-no-signature)
+       ((and (mm-coding-system-p 'utf-16-be) ; Emacs
+             ;; Avoid versions with BOM.
+             (= 2 (length (encode-coding-string "a" 'utf-16-be))))
+        'utf-16-be)
+       ((mm-coding-system-p 'utf-16-be-nosig) ; ?
+        'utf-16-be-nosig))
+  "Coding system which encodes big endian UTF-16 without a BOM signature.")
+
+(defsubst utf7-imap-get-pad-length (len modulus)
+  "Return required length of padding for IMAP modified base64 fragment."
+  (mod (- len) modulus))
+
+(defun utf7-encode-internal (&optional for-imap)
+  "Encode text in (temporary) buffer as UTF-7.
+Use IMAP modification if FOR-IMAP is non-nil."
+  (let ((start (point-min))
+       (end (point-max)))
+    (narrow-to-region start end)
+    (goto-char start)
+    (let* ((esc-char (if for-imap ?& ?+))
+          (direct-encoding-chars
+           (if for-imap utf7-imap-direct-encoding-chars
+             utf7-direct-encoding-chars))
+          (not-direct-encoding-chars (concat "^" direct-encoding-chars)))
+      (while (not (eobp))
+       (skip-chars-forward direct-encoding-chars)
+       (unless (eobp)
+         (insert esc-char)
+         (let ((p (point))
+               (fc (following-char))
+               (run-length
+                (skip-chars-forward not-direct-encoding-chars)))
+           (if (and (= fc esc-char)
+                    (= run-length 1))  ; Lone esc-char?
+               (delete-char -1)        ; Now there's one too many
+             (utf7-fragment-encode p (point) for-imap))
+           (insert "-")))))))
+
+(defun utf7-fragment-encode (start end &optional for-imap)
+  "Encode text from START to END in buffer as UTF-7 escape fragment.
+Use IMAP modification if FOR-IMAP is non-nil."
+  (save-restriction
+    (narrow-to-region start end)
+    (funcall (utf7-get-u16char-converter 'to-utf-16))
+    (mm-with-unibyte-current-buffer
+      (base64-encode-region start (point-max)))
+    (goto-char start)
+    (let ((pm (point-max)))
+      (when for-imap
+       (while (search-forward "/" nil t)
+         (replace-match ",")))
+      (skip-chars-forward "^= \t\n" pm)
+      (delete-region (point) pm))))
+
+(defun utf7-decode-internal (&optional for-imap)
+  "Decode UTF-7 text in (temporary) buffer.
+Use IMAP modification if FOR-IMAP is non-nil."
+  (let ((start (point-min))
+       (end (point-max)))
+    (goto-char start)
+    (let* ((esc-pattern (concat "^" (char-to-string (if for-imap ?& ?+))))
+          (base64-chars (concat "A-Za-z0-9+"
+                                (char-to-string (if for-imap ?, ?/)))))
+      (while (not (eobp))
+       (skip-chars-forward esc-pattern)
+       (unless (eobp)
+         (forward-char)
+         (let ((p (point))
+               (run-length (skip-chars-forward base64-chars)))
+           (when (and (not (eobp)) (= (following-char) ?-))
+             (delete-char 1))
+           (unless (= run-length 0)    ; Encoded lone esc-char?
+             (save-excursion
+               (utf7-fragment-decode p (point) for-imap)
+               (goto-char p)
+               (delete-char -1)))))))))
+
+(defun utf7-fragment-decode (start end &optional for-imap)
+  "Decode base64 encoded fragment from START to END of UTF-7 text in buffer.
+Use IMAP modification if FOR-IMAP is non-nil."
+  (save-restriction
+    (narrow-to-region start end)
+    (when for-imap
+      (goto-char start)
+      (while (search-forward "," nil 'move-to-end) (replace-match "/")))
+    (let ((pl (utf7-imap-get-pad-length (- end start) 4)))
+      (insert (make-string pl ?=))
+      (base64-decode-region start (+ end pl)))
+    (funcall (utf7-get-u16char-converter 'from-utf-16))))
+
+(defun utf7-get-u16char-converter (which-way)
+  "Return a function to convert between UTF-16 and current character set."
+  (if utf7-utf-16-coding-system
+      (if (eq which-way 'to-utf-16)
+         (lambda ()
+           (encode-coding-region (point-min) (point-max)
+                                 utf7-utf-16-coding-system))
+       (lambda ()
+         (decode-coding-region (point-min) (point-max)
+                               utf7-utf-16-coding-system)))
+    ;; Add test to check if we are really Latin-1.
+    (if (eq which-way 'to-utf-16)
+       'utf7-latin1-u16-char-converter
+      'utf7-u16-latin1-char-converter)))
+
+(defun utf7-latin1-u16-char-converter ()
+  "Convert latin 1 (ISO-8859.1) characters to 16 bit Unicode.
+Characters are converted to raw byte pairs in narrowed buffer."
+  (mm-encode-coding-region (point-min) (point-max) 'iso-8859-1)
+  (mm-disable-multibyte)
+  (goto-char (point-min))
+  (while (not (eobp))
+    (insert 0)
+    (forward-char)))
+
+(defun utf7-u16-latin1-char-converter ()
+  "Convert 16 bit Unicode characters to latin 1 (ISO-8859.1).
+Characters are in raw byte pairs in narrowed buffer."
+  (goto-char (point-min))
+  (while (not (eobp))
+    (if (= 0 (following-char))
+       (delete-char 1)
+       (error "Unable to convert from Unicode"))
+    (forward-char))
+  (mm-decode-coding-region (point-min) (point-max) 'iso-8859-1)
+  (mm-enable-multibyte))
+
+;;;###autoload
+(defun utf7-encode (string &optional for-imap)
+  "Encode UTF-7 STRING.  Use IMAP modification if FOR-IMAP is non-nil."
+  (if (and (coding-system-p 'utf-7) (coding-system-p 'utf-7-imap))
+      ;; Emacs 23 with proper support for IMAP
+      (encode-coding-string string (if for-imap 'utf-7-imap 'utf-7))
+    (mm-with-multibyte-buffer
+     (insert string)
+     (utf7-encode-internal for-imap)
+     (buffer-string))))
+
+(defun utf7-decode (string &optional for-imap)
+  "Decode UTF-7 STRING.  Use IMAP modification if FOR-IMAP is non-nil."
+  (if (and (coding-system-p 'utf-7) (coding-system-p 'utf-7-imap))
+      ;; Emacs 23 with proper support for IMAP
+      (decode-coding-string string (if for-imap 'utf-7-imap 'utf-7))
+    (mm-with-unibyte-buffer
+     (insert string)
+     (utf7-decode-internal for-imap)
+     (mm-enable-multibyte)
+     (buffer-string))))
+
+(provide 'utf7)
+
+;;; utf7.el ends here
diff --git a/xemacs-packages/gnus/lisp/uudecode.el b/xemacs-packages/gnus/lisp/uudecode.el
new file mode 100644 (file)
index 0000000..6a45a13
--- /dev/null
@@ -0,0 +1,238 @@
+;;; uudecode.el -- elisp native uudecode
+
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+;; Author: Shenghuo Zhu <zsh@cs.rochester.edu>
+;; Keywords: uudecode 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(eval-and-compile
+  (defalias 'uudecode-char-int
+    (if (fboundp 'char-int)
+       'char-int
+      'identity)))
+
+(defgroup uudecode nil
+  "Decoding of uuencoded data."
+  :group 'mail
+  :group 'news)
+
+(defcustom uudecode-decoder-program "uudecode"
+  "Non-nil value should be a string that names a uu decoder.
+The program should expect to read uu data on its standard
+input and write the converted data to its standard output."
+  :type 'string
+  :group 'uudecode)
+
+(defcustom uudecode-decoder-switches nil
+  "List of command line flags passed to `uudecode-decoder-program'."
+  :group 'uudecode
+  :type '(repeat string))
+
+(defcustom uudecode-use-external
+  (executable-find uudecode-decoder-program)
+  "Use external uudecode program."
+  :version "22.1"
+  :group 'uudecode
+  :type 'boolean)
+
+(defconst uudecode-alphabet "\040-\140")
+
+(defconst uudecode-begin-line "^begin[ \t]+[0-7][0-7][0-7][ \t]+\\(.*\\)$")
+(defconst uudecode-end-line "^end[ \t]*$")
+
+(defconst uudecode-body-line
+  (let ((i 61) (str "^M"))
+    (while (> (setq i (1- i)) 0)
+      (setq str (concat str "[^a-z]")))
+    (concat str ".?$")))
+
+(defvar uudecode-temporary-file-directory
+  (cond ((fboundp 'temp-directory) (temp-directory))
+       ((boundp 'temporary-file-directory) temporary-file-directory)
+       ("/tmp")))
+
+;;;###autoload
+(defun uudecode-decode-region-external (start end &optional file-name)
+  "Uudecode region between START and END using external program.
+If FILE-NAME is non-nil, save the result to FILE-NAME.  The program
+used is specified by `uudecode-decoder-program'."
+  (interactive "r\nP")
+  (let ((cbuf (current-buffer)) tempfile firstline status)
+    (save-excursion
+      (goto-char start)
+      (when (re-search-forward uudecode-begin-line nil t)
+       (forward-line 1)
+       (setq firstline (point))
+       (cond ((null file-name))
+             ((stringp file-name))
+             (t
+              (setq file-name (read-file-name "File to Name:"
+                                              nil nil nil
+                                              (match-string 1)))))
+       (setq tempfile (if file-name
+                          (expand-file-name file-name)
+                          (if (fboundp 'make-temp-file)
+                              (let ((temporary-file-directory
+                                     uudecode-temporary-file-directory))
+                                (make-temp-file "uu"))
+                            (expand-file-name
+                             (make-temp-name "uu")
+                             uudecode-temporary-file-directory))))
+       (let ((cdir default-directory)
+             (default-process-coding-system
+               (if (featurep 'xemacs)
+                   ;; In XEmacs, nil is not a valid coding system.
+                   '(binary . binary)
+                 nil)))
+         (unwind-protect
+             (with-temp-buffer
+               (insert "begin 600 " (file-name-nondirectory tempfile) "\n")
+               (insert-buffer-substring cbuf firstline end)
+               (cd (file-name-directory tempfile))
+               (apply 'call-process-region
+                      (point-min)
+                      (point-max)
+                      uudecode-decoder-program
+                      nil
+                      nil
+                      nil
+                      uudecode-decoder-switches))
+           (cd cdir) (set-buffer cbuf)))
+       (if (file-exists-p tempfile)
+           (unless file-name
+             (goto-char start)
+             (delete-region start end)
+             (let (format-alist)
+               (insert-file-contents-literally tempfile)))
+         (message "Can not uudecode")))
+      (ignore-errors (or file-name (delete-file tempfile))))))
+
+(eval-and-compile
+  (defalias 'uudecode-string-to-multibyte
+    (cond
+     ((featurep 'xemacs)
+      'identity)
+     ((fboundp 'string-to-multibyte)
+      'string-to-multibyte)
+     (t
+      (lambda (string)
+       "Return a multibyte string with the same individual chars as string."
+       (mapconcat
+        (lambda (ch) (string-as-multibyte (char-to-string ch)))
+        string ""))))))
+
+;;;###autoload
+(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 ((done nil)
+       (counter 0)
+       (remain 0)
+       (bits 0)
+       (lim 0) inputpos result
+       (non-data-chars (concat "^" uudecode-alphabet)))
+    (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 unexpectedly")
+           (setq done t))
+          ((and (= (point) end) (not done))
+           ;;(error "uucode ends unexpectedly")
+           (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
+            (with-temp-file file-name
+              (unless (featurep 'xemacs) (set-buffer-multibyte nil))
+              (insert (apply 'concat (nreverse result))))
+         (or (markerp end) (setq end (set-marker (make-marker) end)))
+         (goto-char start)
+         (if enable-multibyte-characters
+             (dolist (x (nreverse result))
+                (insert (uudecode-string-to-multibyte x)))
+           (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)
+
+;;; uudecode.el ends here
diff --git a/xemacs-packages/gnus/lisp/yenc.el b/xemacs-packages/gnus/lisp/yenc.el
new file mode 100644 (file)
index 0000000..cfac06d
--- /dev/null
@@ -0,0 +1,139 @@
+;;; yenc.el --- elisp native yenc decoder
+
+;; Copyright (C) 2002-2016 Free Software Foundation, Inc.
+
+;; Author: Jesper Harder <harder@ifa.au.dk>
+;; Keywords: yenc 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Functions for decoding yenc encoded messages.
+;;
+;; Limitations:
+;;
+;; * Does not handle multipart messages.
+;; * No support for external decoders.
+;; * Doesn't check the crc32 checksum (if present).
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(defconst yenc-begin-line
+  "^=ybegin.*$")
+
+(defconst yenc-decoding-vector
+  [214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
+       231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
+       248 249 250 251 252 253 254 255 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+       16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
+       39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
+       62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
+       85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
+       106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
+       123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
+       140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
+       157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
+       174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
+       191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
+       208 209 210 211 212 213])
+
+(defun yenc-first-part-p ()
+  "Say whether the buffer contains the first part of a yEnc file."
+  (save-excursion
+    (goto-char (point-min))
+    (re-search-forward "^=ybegin part=1 " nil t)))
+
+(defun yenc-last-part-p ()
+  "Say whether the buffer contains the last part of a yEnc file."
+  (save-excursion
+    (goto-char (point-min))
+    (let (total-size end-size)
+      (when (re-search-forward "^=ybegin.*size=\\([0-9]+\\)" nil t)
+       (setq total-size (match-string 1)))
+      (when (re-search-forward "^=ypart.*end=\\([0-9]+\\)" nil t)
+       (setq end-size (match-string 1)))
+      (and total-size
+          end-size
+          (string= total-size end-size)))))
+
+;;;###autoload
+(defun yenc-decode-region (start end)
+  "Yenc decode region between START and END using an internal decoder."
+  (interactive "r")
+  (let (work-buffer)
+    (unwind-protect
+       (save-excursion
+         (goto-char start)
+         (when (re-search-forward yenc-begin-line end t)
+           (let ((first (match-end 0))
+                 (header-alist (yenc-parse-line (match-string 0)))
+                 bytes last footer-alist char)
+             (when (re-search-forward "^=ypart.*$" end t)
+               (setq first (match-end 0)))
+             (when (re-search-forward "^=yend.*$" end t)
+               (setq last (match-beginning 0))
+               (setq footer-alist (yenc-parse-line (match-string 0)))
+               (setq work-buffer (generate-new-buffer " *yenc-work*"))
+               (unless (featurep 'xemacs)
+                 (with-current-buffer work-buffer (set-buffer-multibyte nil)))
+               (while (< first last)
+                 (setq char (char-after first))
+                 (cond ((or (eq char ?\r)
+                            (eq char ?\n)))
+                       ((eq char ?=)
+                        (setq char (char-after (incf first)))
+                        (with-current-buffer work-buffer
+                          (insert-char (mod (- char 106) 256) 1)))
+                       (t
+                        (with-current-buffer work-buffer
+                          ;;(insert-char (mod (- char 42) 256) 1)
+                          (insert-char (aref yenc-decoding-vector char) 1))))
+                 (incf first))
+               (setq bytes (buffer-size work-buffer))
+               (unless (and (= (cdr (assq 'size header-alist)) bytes)
+                            (= (cdr (assq 'size footer-alist)) bytes))
+                 (message "Warning: Size mismatch while decoding."))
+               (goto-char start)
+               (delete-region start end)
+               (insert-buffer-substring work-buffer))))
+         (and work-buffer (kill-buffer work-buffer))))))
+
+;;;###autoload
+(defun yenc-extract-filename ()
+  "Extract file name from an yenc header."
+  (save-excursion
+    (when (re-search-forward yenc-begin-line nil t)
+      (cdr (assoc 'name (yenc-parse-line (match-string 0)))))))
+
+(defun yenc-parse-line (str)
+  "Extract file name and size from STR."
+  (let (result name)
+    (when (string-match "^=y.*size=\\([0-9]+\\)" str)
+      (push (cons 'size (string-to-number (match-string 1 str))) result))
+    (when (string-match "^=y.*name=\\(.*\\)$" str)
+      (setq name (match-string 1 str))
+      ;; Remove trailing white space
+      (when (string-match " +$" name)
+       (setq name (substring name 0 (match-beginning 0))))
+      (push (cons 'name name) result))
+    result))
+
+(provide 'yenc)
+
+;;; yenc.el ends here
diff --git a/xemacs-packages/gnus/make.bat b/xemacs-packages/gnus/make.bat
new file mode 100644 (file)
index 0000000..f305b09
--- /dev/null
@@ -0,0 +1,337 @@
+@echo OFF\r
+REM Change this to ON when debugging this batch file.\r
+\r
+rem Written by Frank Schmitt (ich@frank-schmitt.net)\r
+rem based on the work by David Charlap (shamino@writeme.com)\r
+rem .\r
+rem .\r
+rem Clear PWD so emacs doesn't get confused\r
+set GNUS_PWD_SAVE=%PWD%\r
+set PWD=\r
+set ERROR=:\r
+REM set pause=\r
+\r
+if %1p == p goto usage\r
+\r
+echo * Installing Gnus on your system.  Operating system:\r
+ver\r
+rem Emacs 20.7 no longer includes emacs.bat. Use emacs.exe if the batch file is\r
+rem not present -- this also fixes the problem about too many parameters on Win9x.\r
+if exist %1\emacs.bat goto ebat\r
+if exist %1\emacs.exe goto eexe\r
+if exist %1\xemacs.exe goto xemacs\r
+goto noemacs\r
+\r
+:ebat\r
+set EMACS=emacs.bat\r
+echo.\r
+echo ***************************************************************************\r
+echo * Using emacs.bat  (If you've got Emacs 20.3 or higher please remove\r
+echo * Emacs.bat, it isn't needed anymore.)\r
+echo ***************************************************************************\r
+echo.\r
+goto emacs\r
+\r
+:eexe\r
+set EMACS=emacs.exe\r
+echo.\r
+echo ***************************************************************************\r
+echo * Using emacs.exe\r
+echo ***************************************************************************\r
+echo.\r
+goto emacs\r
+\r
+:emacs\r
+if not "%2" == "/copy" goto emacsnocopy\r
+if not exist %1\..\site-lisp\nul mkdir %1\..\site-lisp\r
+if not exist %1\..\site-lisp\gnus\nul mkdir %1\..\site-lisp\gnus\r
+if not exist %1\..\site-lisp\subdirs.el set subdirwarning=yes\r
+:emacsnocopy\r
+set EMACS_ARGS=-batch -q -no-site-file\r
+set GNUS_INFO_DIR=%1\..\info\r
+set GNUS_LISP_DIR=%1\..\site-lisp\gnus\lisp\r
+set GNUS_ETC_DIR=%1\..\site-lisp\gnus\etc\r
+goto lisp\r
+\r
+:xemacs\r
+set EMACS=xemacs.exe\r
+if not "%2" == "/copy" goto xemacsnocopy\r
+if not exist %1\..\..\site-packages\nul mkdir %1\..\..\site-packages\\r
+if not exist %1\..\..\site-packages\info\nul mkdir %1\..\..\site-packages\info\r
+if not exist %1\..\..\site-packages\lisp\nul mkdir %1\..\..\site-packages\lisp\r
+if not exist %1\..\..\site-packages\etc\nul mkdir %1\..\..\site-packages\etc\r
+:xemacsnocopy\r
+set EMACS_ARGS=-batch -no-autoloads\r
+set GNUS_INFO_DIR=%1\..\..\site-packages\info\r
+set GNUS_LISP_DIR=%1\..\..\site-packages\lisp\gnus\r
+set GNUS_ETC_DIR=%1\..\..\site-packages\etc\r
+echo.\r
+echo ***************************************************************************\r
+echo * Using xemacs.exe\r
+echo ***************************************************************************\r
+echo.\r
+goto lisp\r
+\r
+:lisp\r
+if "%pause%" == "pause" pause\r
+set EMACSBATCH=call %1\%EMACS% %EMACS_ARGS%\r
+cd lisp\r
+if exist gnus-load.el attrib -r gnus-load.el\r
+if exist gnus-load.el del gnus-load.el\r
+echo.\r
+echo * Stand by while generating autoloads.\r
+echo.\r
+%EMACSBATCH% -l ./dgnushack.el -f dgnushack-make-cus-load .\r
+if ErrorLevel 1 set ERROR=make-cus-load\r
+%EMACSBATCH% -l ./dgnushack.el -f dgnushack-make-auto-load .\r
+if ErrorLevel 1 set ERROR=%ERROR%,make-auto-load\r
+%EMACSBATCH% -l ./dgnushack.el -f dgnushack-make-load\r
+if ErrorLevel 1 set ERROR=%ERROR%,make-load\r
+echo.\r
+echo * Stand by while compiling lisp files.\r
+echo.\r
+%EMACSBATCH% -l ./dgnushack.el -f dgnushack-compile\r
+if ErrorLevel 1 set ERROR=%ERROR%,compile\r
+\r
+if not "%2" == "/copy" goto infotest\r
+echo.\r
+echo * Stand by while copying lisp files.\r
+echo.\r
+if not exist %GNUS_LISP_DIR%\nul mkdir %GNUS_LISP_DIR%\r
+xcopy /R /Q /Y *.el* %GNUS_LISP_DIR%\r
+if ErrorLevel 1 set ERROR=%ERROR%,copy-lisp\r
+goto infotest\r
+\r
+:infotest\r
+cd ..\texi\r
+if exist sieve attrib -r sieve\r
+if exist sieve del sieve\r
+\r
+echo * Checking if makeinfo is available...\r
+makeinfo sieve.texi\r
+if exist sieve goto minfo\r
+echo * No makeinfo found, using infohack.el.\r
+set EMACSINFO=%EMACSBATCH% -l infohack.el -f batch-makeinfo\r
+echo.\r
+echo ***************************************************************************\r
+echo * Using infohack.el, if you've got makeinfo.exe put it in PATH.\r
+echo ***************************************************************************\r
+echo.\r
+goto info\r
+\r
+:minfo\r
+set EMACSINFO=makeinfo\r
+echo.\r
+echo ***************************************************************************\r
+echo * Using makeinfo\r
+echo ***************************************************************************\r
+echo.\r
+goto info\r
+\r
+:info\r
+if "%pause%" == "pause" pause\r
+echo.\r
+echo * Stand by while generating info files.\r
+echo.\r
+%EMACSINFO% emacs-mime.texi\r
+if ErrorLevel 1 set ERROR=%ERROR%,emacs-mime.texi\r
+%EMACSINFO% gnus.texi\r
+if ErrorLevel 1 set ERROR=%ERROR%,gnus.texi\r
+%EMACSINFO% sieve.texi\r
+if ErrorLevel 1 set ERROR=%ERROR%,sieve.texi\r
+%EMACSINFO% pgg.texi\r
+if ErrorLevel 1 set ERROR=%ERROR%,pgg.texi\r
+%EMACSINFO% message.texi\r
+if ErrorLevel 1 set ERROR=%ERROR%,message.texi\r
+%EMACSINFO% sasl.texi\r
+if ErrorLevel 1 set ERROR=%ERROR%,sasl.texi\r
+\r
+if not "%2" == "/copy" goto nocopy\r
+if not exist %GNUS_INFO_DIR%\nul mkdir %GNUS_INFO_DIR%\r
+\r
+echo.\r
+echo * Stand by while copying info files.\r
+echo.\r
+xcopy /R /Q /Y gnus       %GNUS_INFO_DIR%\r
+if ErrorLevel 1 set ERROR=%ERROR%,copy-gnus-info\r
+xcopy /R /Q /Y gnus-?     %GNUS_INFO_DIR%\r
+if ErrorLevel 1 set ERROR=%ERROR%,copy-gnus-x-info\r
+xcopy /R /Q /Y gnus-??    %GNUS_INFO_DIR%\r
+if ErrorLevel 1 set ERROR=%ERROR%,copy-gnus-xx-info\r
+xcopy /R /Q /Y message    %GNUS_INFO_DIR%\r
+if ErrorLevel 1 set ERROR=%ERROR%,copy-message-info\r
+if exist message-1 xcopy /R /Q /Y message-?  %GNUS_INFO_DIR%\r
+if ErrorLevel 1 set ERROR=%ERROR%,copy-message-x-info\r
+xcopy /R /Q /Y emacs-mime %GNUS_INFO_DIR%\r
+if ErrorLevel 1 set ERROR=%ERROR%,copy-emacs-mime-info\r
+xcopy /R /Q /Y sieve      %GNUS_INFO_DIR%\r
+if ErrorLevel 1 set ERROR=%ERROR%,copy-sieve-info\r
+xcopy /R /Q /Y pgg        %GNUS_INFO_DIR%\r
+if ErrorLevel 1 set ERROR=%ERROR%,copy-pgg-info\r
+xcopy /R /Q /Y sasl        %GNUS_INFO_DIR%\r
+if ErrorLevel 1 set ERROR=%ERROR%,copy-sasl-info\r
+\r
+echo.\r
+echo ***************************************************************************\r
+echo * You should add the following lines to\r
+echo * %GNUS_INFO_DIR%\dir\r
+echo * if they aren't already there:\r
+echo *\r
+echo * * PGG: (pgg).   Emacs interface to various PGP implementations.\r
+echo * * Sieve: (sieve).       Managing Sieve scripts in Emacs.\r
+echo * * SASL: (sasl). The Emacs SASL library.\r
+echo ***************************************************************************\r
+echo.\r
+\r
+:etc\r
+if "%pause%" == "pause" pause\r
+cd ..\etc\r
+echo.\r
+echo * Stand by while copying etc files.\r
+echo.\r
+REM\r
+if not exist %GNUS_ETC_DIR% mkdir %GNUS_ETC_DIR%\r
+echo ** gnus-tut.txt ...\r
+xcopy /R /Q /Y gnus-tut.txt %GNUS_ETC_DIR%\r
+if ErrorLevel 1 set ERROR=%ERROR%,copy-etc-gnus-tut-txt\r
+REM\r
+REM FIXME: Instead of C&P, we should use a FOR loop.\r
+REM\r
+set i=images\r
+if not exist %GNUS_ETC_DIR%\%i%\nul mkdir %GNUS_ETC_DIR%\%i%\r
+echo ** .\%i%\ ...\r
+xcopy /R /Q /Y .\%i%\*.* %GNUS_ETC_DIR%\%i%\\r
+if ErrorLevel 1 set ERROR=%ERROR%,copy-etc-%i%\r
+REM\r
+set i=images\mail\r
+if not exist %GNUS_ETC_DIR%\%i%\nul mkdir %GNUS_ETC_DIR%\%i%\r
+echo ** .\%i%\ ...\r
+xcopy /R /Q /Y .\%i%\*.* %GNUS_ETC_DIR%\%i%\\r
+if ErrorLevel 1 set ERROR=%ERROR%,copy-etc-%i%\r
+REM\r
+set i=images\gnus\r
+if not exist %GNUS_ETC_DIR%\%i%\nul mkdir %GNUS_ETC_DIR%\%i%\r
+echo ** .\%i%\ ...\r
+xcopy /R /Q /Y .\%i%\*.* %GNUS_ETC_DIR%\%i%\\r
+if ErrorLevel 1 set ERROR=%ERROR%,copy-etc-%i%\r
+REM\r
+set i=images\smilies\r
+if not exist %GNUS_ETC_DIR%\%i%\nul mkdir %GNUS_ETC_DIR%\%i%\r
+echo ** .\%i%\ ...\r
+xcopy /R /Q /Y .\%i%\*.* %GNUS_ETC_DIR%\%i%\\r
+if ErrorLevel 1 set ERROR=%ERROR%,copy-etc-%i%\r
+REM\r
+set i=images\smilies\grayscale\r
+if not exist %GNUS_ETC_DIR%\%i%\nul mkdir %GNUS_ETC_DIR%\%i%\r
+echo ** .\%i%\ ...\r
+xcopy /R /Q /Y .\%i%\*.* %GNUS_ETC_DIR%\%i%\\r
+if ErrorLevel 1 set ERROR=%ERROR%,copy-etc-%i%\r
+REM\r
+set i=images\smilies\medium\r
+if not exist %GNUS_ETC_DIR%\%i%\nul mkdir %GNUS_ETC_DIR%\%i%\r
+echo ** .\%i%\ ...\r
+xcopy /R /Q /Y .\%i%\*.* %GNUS_ETC_DIR%\%i%\\r
+if ErrorLevel 1 set ERROR=%ERROR%,copy-etc-%i%\r
+REM\r
+set i=\r
+goto warnings\r
+\r
+:nocopy\r
+echo.\r
+echo ***************************************************************************\r
+echo * You chose not to copy the files, therefore you should add the\r
+echo * following lines to the TOP of your [X]emacs customization file:\r
+echo *\r
+echo * (add-to-list 'load-path "/Path/to/gnus/lisp")\r
+echo * (if (featurep 'xemacs)\r
+echo *     (add-to-list 'Info-directory-list "c:/Path/to/gnus/texi/")\r
+echo *   (add-to-list 'Info-default-directory-list "c:/Path/to/gnus/texi/"))\r
+echo * (require 'gnus-load)\r
+echo *\r
+echo * Replace c:/Path/to/gnus with the Path where your new Gnus is (that's here\r
+echo * and yes, you've got to use forward slashes).\r
+echo ***************************************************************************\r
+echo.\r
+\r
+:warnings\r
+if not "%subdirwarning%" == "yes" goto warngnusload\r
+echo.\r
+echo ***************************************************************************\r
+echo * There's no subdirs.el file in your site-lisp directory, you should\r
+echo * therefor add the following line to the TOP of your Emacs\r
+echo * customization file:\r
+echo *\r
+echo * (add-to-list 'load-path "/Path/to/emacs-site-lisp-directory/gnus/lisp")\r
+echo * (require 'gnus-load)\r
+echo * Yes, it must be forward slashes.\r
+echo ***************************************************************************\r
+echo.\r
+goto warnerrors\r
+\r
+:warngnusload\r
+echo.\r
+echo ***************************************************************************\r
+echo * You should add the following line to the TOP of your Emacs\r
+echo * customization file:\r
+echo *\r
+echo * (require 'gnus-load)\r
+echo ***************************************************************************\r
+echo.\r
+\r
+:warnerrors\r
+if "%ERROR%"==":" goto noerrors\r
+set errorlevel=1\r
+echo.\r
+echo ***************************************************************************\r
+echo * WARNING ERRORS OCCURRED!\r
+echo * You should look for error messages in the output of the called programs\r
+echo * and try to find out what exactly went wrong.\r
+echo * Errors occured in the following modules:\r
+echo * %ERROR%\r
+echo ***************************************************************************\r
+echo.\r
+goto done\r
+\r
+:noerrors\r
+set errorlevel=0\r
+\r
+:done\r
+cd ..\r
+goto end\r
+\r
+:noemacs\r
+echo.\r
+echo ***************************************************************************\r
+echo * Unable to find emacs.exe or xemacs.exe on the path you specified!\r
+echo * STOP!\r
+echo ***************************************************************************\r
+echo.\r
+goto usage\r
+\r
+:usage\r
+echo.\r
+echo ***************************************************************************\r
+REM echo * Usage: make.bat :[X]Emacs-exe-dir: [/copy] [ ^> inst-log.txt 2^>^&1 ]\r
+echo * Usage: make.bat :[X]Emacs-exe-dir: [/copy]\r
+echo *\r
+echo * where: :[X]Emacs-exe-dir: is the directory your\r
+echo *           emacs.exe respectively xemacs.exe resides in,\r
+echo *           e.g. G:\Programme\XEmacs\XEmacs-21.4.11\i586-pc-win32\\r
+echo *           or G:\Emacs\bin\r
+echo *        /copy indicates that the compiled files should be copied to your\r
+echo *           emacs lisp, info, and etc site directories.\r
+REM echo *        ^> inst-log.txt 2^>^&1\r
+REM echo *           Log output to inst-log.txt\r
+echo ***************************************************************************\r
+echo.\r
+\r
+:end\r
+rem Restore environment variables\r
+set PWD=%GNUS_PWD_SAVE%\r
+set GNUS_PWD_SAVE=\r
+set EMACSBATCH=\r
+set GNUS_LISP_DIR=\r
+set GNUS_INFO_DIR=\r
+set GNUS_ETC_DIR=\r
+set subdirwarning=\r
+set ERROR=\r
diff --git a/xemacs-packages/gnus/makepub b/xemacs-packages/gnus/makepub
new file mode 100755 (executable)
index 0000000..58c51cb
--- /dev/null
@@ -0,0 +1,61 @@
+#!/bin/bash
+name="Ma Gnus"
+
+if [ `whoami` != "larsi" ]; then
+    echo "This script is for larsi only"
+    exit
+fi
+
+# First do a release commit on the current version.
+
+version=`grep "defconst gnus-version-number" lisp/gnus.el | \
+    sed 's/[^.0-9]//g'`
+
+initial=`echo "$name" | sed 's/^\([A-Z]\).*/\1/g' | tr A-Z a-z`
+
+prefix=`echo $version | sed 's/^\(.*[.]\)\([0-9][0-9]*\)/\1/'`
+next_version=`echo $version | sed 's/^\(.*[.]\)\([0-9][0-9]*\)/\2/'`
+next_version=`expr $next_version + 1`
+next_version="$prefix$next_version"
+
+date=`TZ=Z date "+%Y-%m-%d"`
+echo -e "$date  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>\n\n\t* gnus.el: $name v$next_version is released.\n"\
+  > /tmp/changelog
+cat lisp/ChangeLog >> /tmp/changelog
+mv /tmp/changelog lisp/ChangeLog
+
+# Then update the sources to the next version.
+
+sed "s/$name v[.0-9]*/$name v$next_version/" texi/gnus.texi > g.texi.tmp
+mv g.texi.tmp texi/gnus.texi
+sed "s/$name v[.0-9]*/$name v$next_version/" texi/message.texi > m.texi.tmp
+mv m.texi.tmp texi/message.texi
+sed "s/defconst gnus-version-number \"$version\"/defconst gnus-version-number \"$next_version\"/" lisp/gnus.el > g.el.tmp
+mv g.el.tmp lisp/gnus.el
+
+git commit -a -m "$name v$next_version is released"
+
+tversion=`echo $next_version | sed 's/[.]/-/g'`
+
+git tag -a "$initial$tversion" -m "$name v$next_version is released"
+
+git push && git push origin tag "$initial$tversion"
+
+# Increase the number, yet again, to start the next development cycle.
+
+version=$next_version
+
+prefix=`echo $version | sed 's/^\(.*[.]\)\([0-9][0-9]*\)/\1/'`
+next_version=`echo $version | sed 's/^\(.*[.]\)\([0-9][0-9]*\)/\2/'`
+next_version=`expr $next_version + 1`
+next_version="$prefix$next_version"
+
+sed "s/$name v[.0-9]*/$name v$next_version/" texi/gnus.texi > g.texi.tmp
+mv g.texi.tmp texi/gnus.texi
+sed "s/$name v[.0-9]*/$name v$next_version/" texi/message.texi > m.texi.tmp
+mv m.texi.tmp texi/message.texi
+sed "s/defconst gnus-version-number \"$version\"/defconst gnus-version-number \"$next_version\"/" lisp/gnus.el > g.el.tmp
+mv g.el.tmp lisp/gnus.el
+
+git commit -a -m "$name v$next_version is begun"
+git push
diff --git a/xemacs-packages/gnus/mkinstalldirs b/xemacs-packages/gnus/mkinstalldirs
new file mode 100755 (executable)
index 0000000..fb06c4e
--- /dev/null
@@ -0,0 +1,154 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+
+scriptversion=2006-05-11.19
+
+# Original author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain.
+#
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+nl='
+'
+IFS=" ""       $nl"
+errstatus=0
+dirmode=
+
+usage="\
+Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ...
+
+Create each directory DIR (with mode MODE, if specified), including all
+leading file name components.
+
+Report bugs to <bug-automake@gnu.org>."
+
+# process command line arguments
+while test $# -gt 0 ; do
+  case $1 in
+    -h | --help | --h*)         # -h for help
+      echo "$usage"
+      exit $?
+      ;;
+    -m)                         # -m PERM arg
+      shift
+      test $# -eq 0 && { echo "$usage" 1>&2; exit 1; }
+      dirmode=$1
+      shift
+      ;;
+    --version)
+      echo "$0 $scriptversion"
+      exit $?
+      ;;
+    --)                         # stop option processing
+      shift
+      break
+      ;;
+    -*)                         # unknown option
+      echo "$usage" 1>&2
+      exit 1
+      ;;
+    *)                          # first non-opt arg
+      break
+      ;;
+  esac
+done
+
+for file
+do
+  if test -d "$file"; then
+    shift
+  else
+    break
+  fi
+done
+
+case $# in
+  0) exit 0 ;;
+esac
+
+# Solaris 8's mkdir -p isn't thread-safe.  If you mkdir -p a/b and
+# mkdir -p a/c at the same time, both will detect that a is missing,
+# one will create a, then the other will try to create a and die with
+# a "File exists" error.  This is a problem when calling mkinstalldirs
+# from a parallel make.  We use --version in the probe to restrict
+# ourselves to GNU mkdir, which is thread-safe.
+case $dirmode in
+  '')
+    if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
+      echo "mkdir -p -- $*"
+      exec mkdir -p -- "$@"
+    else
+      # On NextStep and OpenStep, the `mkdir' command does not
+      # recognize any option.  It will interpret all options as
+      # directories to create, and then abort because `.' already
+      # exists.
+      test -d ./-p && rmdir ./-p
+      test -d ./--version && rmdir ./--version
+    fi
+    ;;
+  *)
+    if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 &&
+       test ! -d ./--version; then
+      echo "mkdir -m $dirmode -p -- $*"
+      exec mkdir -m "$dirmode" -p -- "$@"
+    else
+      # Clean up after NextStep and OpenStep mkdir.
+      for d in ./-m ./-p ./--version "./$dirmode";
+      do
+        test -d $d && rmdir $d
+      done
+    fi
+    ;;
+esac
+
+for file
+do
+  case $file in
+    /*) pathcomp=/ ;;
+    *)  pathcomp= ;;
+  esac
+  oIFS=$IFS
+  IFS=/
+  set fnord $file
+  shift
+  IFS=$oIFS
+
+  for d
+  do
+    test "x$d" = x && continue
+
+    pathcomp=$pathcomp$d
+    case $pathcomp in
+      -*) pathcomp=./$pathcomp ;;
+    esac
+
+    if test ! -d "$pathcomp"; then
+      echo "mkdir $pathcomp"
+
+      mkdir "$pathcomp" || lasterr=$?
+
+      if test ! -d "$pathcomp"; then
+       errstatus=$lasterr
+      else
+       if test ! -z "$dirmode"; then
+         echo "chmod $dirmode $pathcomp"
+         lasterr=
+         chmod "$dirmode" "$pathcomp" || lasterr=$?
+
+         if test ! -z "$lasterr"; then
+           errstatus=$lasterr
+         fi
+       fi
+      fi
+    fi
+
+    pathcomp=$pathcomp/
+  done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/xemacs-packages/gnus/texi/.gitignore b/xemacs-packages/gnus/texi/.gitignore
new file mode 100644 (file)
index 0000000..c0750fe
--- /dev/null
@@ -0,0 +1,2 @@
+*.pdf
+epa
diff --git a/xemacs-packages/gnus/texi/ChangeLog b/xemacs-packages/gnus/texi/ChangeLog
new file mode 100644 (file)
index 0000000..65ba0e5
--- /dev/null
@@ -0,0 +1,7637 @@
+2015-12-13  Jens Lechtenboerger  <jens.lechtenboerger@fsfe.org>
+
+       * message.texi (Security, Using S/MIME):
+       Update for refactoring mml-smime.el, mml1991.el, mml2015.el.
+       (Using OpenPGP): Rename from "Using PGP/MIME"; update contents.
+       (Passphrase caching, Encrypt-to-self, Bcc Warning): New sections.
+
+2015-09-16  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-faq.texi (FAQ 5-8):
+       Avoid undefined behavior in suggested sed backslash usage.
+
+2015-09-08  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-faq.texi (FAQ 5-13, FAQ 6-2):
+       * gnus.texi (Score Decays, SpamAssassin): Prefer grave quoting in
+       source-code strings used to generate help and diagnostics.
+
+2015-09-04  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-faq.texi (FAQ 4-8, FAQ 4-12, FAQ 4-14):
+       * gnus.texi (Archived Messages): Fix minor problems with " in manual.
+
+2015-08-31  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-faq.texi (FAQ 5-13, FAQ 6-2):
+       * gnus.texi (Score Decays, SpamAssassin):
+       Prefer curved quotes in examples if users will typically see curved
+       quotes when the examples run.
+
+2015-07-09  Nikolaus Rath  <Nikolaus@rath.org>
+
+       * gnus.texi (Customizing the IMAP Connection):
+       Document the 'plain option.
+
+2015-05-02  Eli Zaretskii  <eliz@gnu.org>
+
+       * docstyle.texi: Use "@set txicodequoteundirected" and
+       "@set txicodequotebacktick" instead of "@codequotebacktick on" and
+       "@codequoteundirected on", respectively, to avoid requiring
+       Texinfo 5.x for Emacs documentation.
+
+2015-05-01  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * docstyle.texi: New file, which specifies treatment for grave accent
+       and apostrophe, as well as the document encoding.
+
+       * auth.texi, emacs-mime.texi, epa.texi, gnus-coding.texi:
+       * gnus-faq.texi, gnus.texi, message.texi, sasl.texi, sieve.texi:
+       Use it instead of '@documentencoding UTF-8', to lessen the need for
+       global changes like this in the future.
+
+2015-02-05  Glenn Morris  <rgm@gnu.org>
+
+       * auth.texi (Multiple GMail accounts with Gnus): Markup fix.
+
+2015-02-05  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth.texi (Multiple GMail accounts with Gnus): Add FAQ.
+
+2015-02-05  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Using IMAP): Fix menu node name.
+
+2015-02-05  Trevor Murphy  <trevor.m.murphy@gmail.com>
+
+       * gnus.texi (Support for IMAP Extensions): Document the Gmail label
+       extension.
+
+2014-12-18  Eric Abrahamsen  <eric@ericabrahamsen.net>
+
+       * gnus.texi (Gnus Registry Setup): Explain pruning changes. Mention
+       gnus-registry-prune-factor. Explain sorting changes and
+       gnus-registry-default-sort-function. Correct file extension.
+
+2014-11-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Top): Add missing `HTML' menu.
+       (HTML): Fix xref to FAQ 4-16.
+
+2014-11-07  Tassilo Horn  <tsdh@gnu.org>
+
+       * gnus.texi (HTML): Update section so that it mentions shr and w3m.
+       Also link the full EWW manual that explains more on shr, too.
+
+       * gnus-faq.texi (FAQ 4 - Reading messages, FAQ 4-16): Add Q&A on how to
+       increase contrast when displaying HTML mail with shr.
+
+2014-11-02  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth.texi (Help for users): Explain quoting rules better.
+
+2014-10-25  Eric S. Raymond  <esr@thyrsus.com>
+
+       * gnus-coding.texi: Neutralized language specific to a repository type.
+
+2014-07-31  Tassilo Horn  <tsdh@gnu.org>
+
+       * gnus.texi (Group Parameters): Document that `gcc-self' may also be a
+       list.
+
+2014-07-18  Albert Krewinkel  <albert+gnus@zeitkraut.de>
+
+       * gnus.texi (Posting Styles): Document the possibility to perform
+       string replacements when matching against headers.
+
+2014-06-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * Makefile.in (.texi, makeinfo): Don't split info files.
+       (install): Compress info files.
+       (uninstall): Remove compressed info files.
+       (gnus-manual-a4.ps.gz, gnus-manual-standard.ps.gz): Use GZIP_PROG.
+
+       * infohack.el (infohack): Don't split info files.
+
+       * gnus.texi (Ma Gnus): Mention that Lisp source files and info files
+       to be installed will be compressed by gzip by default.
+
+2014-06-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       Add .info extension to info files.
+
+       * Makefile.in (.texi, makeinfo):
+       Don't specify output file name for makeinfo.
+       (clean, distclean, install, uninstall): Delete old info files.
+
+2014-06-10  Glenn Morris  <rgm@gnu.org>
+
+       * auth.texi, emacs-mime.texi, epa.texi, gnus-coding.texi, gnus.texi,
+       message.texi, sieve.texi: Add .info extension to @setfilename commands.
+
+2014-05-04  Glenn Morris  <rgm@gnu.org>
+
+       * message.texi (Header Commands): Replace `iff'.
+
+2014-03-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Ma Gnus): Mention header attachment buttons.
+
+2014-03-12  Glenn Morris  <rgm@gnu.org>
+
+       * auth.texi, epa.texi, gnus.texi, message.texi:
+       Use @file for buffers, per the Texinfo manual.
+
+2014-03-05  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * emacs-mime.texi (MML Definition): Document recipient-filename.
+
+2014-02-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * epa.texi (Caching Passphrases): Don't give argument to @item used in
+       @enumerate section so as to be able to be formatted with MAKEINFO=no.
+
+       * infohack.el (texinfo-format-comma): Support @comma.
+       (infohack-replace-unsupported): New function.
+       (infohack): Use it.
+
+2014-02-08  Glenn Morris  <rgm@gnu.org>
+
+       * auth.texi (GnuPG and EasyPG Assistant Configuration):
+       Be agnostic about authinfo/authinfo.gpg default order.  (Bug#16642)
+
+2014-02-06  Glenn Morris  <rgm@gnu.org>
+
+       * epa.texi (Mail-mode integration): Mention epa-mail-aliases.
+
+2014-02-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (MIME Commands): Mention
+       gnus-mime-buttonize-attachments-in-header and
+       gnus-mime-display-attachment-buttons-in-header.
+
+2014-02-05  Glenn Morris  <rgm@gnu.org>
+
+       * epa.texi: Add indices.
+
+2014-02-01  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * message.texi (Forwarding): Mention
+       `message-forward-included-headers'.
+
+2014-01-31  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi: w3 is no longer supported by Gnus.
+
+2014-01-24  Glenn Morris  <rgm@gnu.org>
+
+       * emacs-mime.texi (time-date): Use float-time.
+
+2014-01-05  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Specify .texi encoding (Bug#16292).
+       * auth.texi, epa.texi, gnus-coding.texi, gnus-faq.texi, message.texi:
+       * sasl.texi, sieve.texi: Add @documentencoding.
+
+2013-08-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * emacs-mime.texi (Encoding Customization): Exclude iso-2022-jp-2 and
+       shift_jis from the default value set to mm-coding-system-priorities for
+       Japanese users.
+
+2013-08-13  Glenn Morris  <rgm@gnu.org>
+
+       * epa.texi (Encrypting/decrypting gpg files):
+       Rename nodes to avoid characters that can cause Texinfo problems.
+
+2013-08-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Mail Source Specifiers): Fix description for pop3's :leave.
+
+2013-08-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Basic Usage): Mention that warp means jump here.
+       (The notmuch Engine): Mention notmuch.
+
+2013-07-30  Tassilo Horn  <tsdh@gnu.org>
+
+       * gnus.texi (Sorting the Summary Buffer): Document new defcustom
+       `gnus-subthread-sort-functions' and remove the obsolete documentation
+       of `gnus-sort-threads-recursively'.
+
+2013-07-26  Tassilo Horn  <tsdh@gnu.org>
+
+       * gnus.texi (Sorting the Summary Buffer): Document new defcustom
+       `gnus-sort-threads-recursively'.
+
+2013-07-19  Geoff Kuenning  <geoff@cs.hmc.edu>  (tiny change)
+
+       * gnus.texi (Customizing Articles): Document function predicates.
+
+2013-07-08  Tassilo Horn  <tsdh@gnu.org>
+
+       * gnus.texi (lines): Correct description of
+       `gnus-registry-track-extra's default value.  Mention
+       `gnus-registry-remove-extra-data'.
+
+2013-07-06  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Group Parameters): Mention regexp
+       substitutions (bug#11688).
+
+2013-07-06  Nathan Trapuzzano  <nbtrap@nbtrap.com>  (tiny change)
+
+       * gnus.texi (Generic Marking Commands): Fix grammar (bug#13368).
+
+2013-07-06  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Emacsen): Fix version.
+
+       * gnus-faq.texi (FAQ 1-6): Mention the correct Emacs version.
+
+2013-07-06  Glenn Morris  <rgm@gnu.org>
+
+       * gnus.texi (Top): Restrict "Other related manuals" to info output.
+       (Foreign Groups): Use @indicateurl for examples.
+       (Direct Functions): Remove defunct URL.
+       (RSS): Update URL.
+
+       * gnus-faq.texi (FAQ 5-8, FAQ 6-3): Remove defunct URLs.
+       (FAQ 7-1): Update URL.
+
+2013-06-13  Albert Krewinkel  <tarleb@moltkeplatz.de>
+
+       * sieve.texi (Managing Sieve): Fix port in example, fix documentation
+       for keys q and Q.
+       (Standards): Reference RFC5804 as the defining document of the
+       managesieve protocol.
+
+2013-06-10  Glenn Morris  <rgm@gnu.org>
+
+       * epa.texi (Cryptographic operations on files): Update epa-decrypt-file.
+
+2013-06-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Article Date):
+       Fix description of gnus-article-update-date-headers.
+
+2013-05-19  Adam Sjøgren  <asjo@koldfront.dk>
+
+       * gnus.texi (Fancy Mail Splitting): Fix typo.
+
+2013-03-17  Paul Eggert  <eggert@cs.ucla.edu>
+
+       doc: convert some TeX accents to UTF-8
+       * emacs-mime.texi (Interface Functions): Use 'ï' rather than
+       '@"{@dotless{i}}'.
+
+2013-03-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-faq.texi (FAQ 3-11): Now Gnus supports POP3 UIDL.
+
+2013-03-07  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * emacs-mime.texi, gnus-coding.texi: Specify utf-8, not iso-8859-1, for
+       ASCII files.
+
+2013-03-04  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * emacs-mime.texi: Switch from Latin-1 to UTF-8.
+
+2013-02-13  Glenn Morris  <rgm@gnu.org>
+
+       * message.texi (News Headers): Don't mention yow any more.
+
+2013-01-05  Andreas Schwab  <schwab@linux-m68k.org>
+
+       * auth.texi (VERSION): Set before first use.
+
+2012-12-27  Glenn Morris  <rgm@gnu.org>
+
+       * auth.texi (Help for users): Break long lines.
+
+2012-12-25  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Customizing the IMAP Connection): Mention the other
+       authenticators.
+
+2012-12-24  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Browse Foreign Server): Document
+       `gnus-browse-delete-group'.
+
+2012-12-21  Glenn Morris  <rgm@gnu.org>
+
+       * auth.texi, epa.texi, gnus-coding.texi, sasl.texi:
+       May as well just include doclicense.texi in everything.
+
+       * auth.texi, emacs-mime.texi, epa.texi, gnus-coding.texi, gnus.texi,
+       message.texi, sasl.texi, sieve.texi: Do not mention buying copies from
+       the FSF, which does not publish these manuals.
+
+2012-12-06  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * doclicense.texi: Update to latest version from FSF.
+       This is just a minor editorial change.
+
+2012-11-24  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * doclicense.texi: Update to latest version from FSF.
+       This is just a minor editorial change.
+
+2012-10-24  Paul Eggert  <eggert@penguin.cs.ucla.edu>
+
+       Update manual for new time stamp format (Bug#12706).
+       * emacs-mime.texi (time-date): Update for new format.
+       Also, fix bogus time stamp and modernize a bit.
+
+2012-10-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Mail Source Specifiers):
+       Document :leave keyword used for pop mail source.
+
+2012-06-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (POP before SMTP): POP-before-SMTP works with all sending
+       methods, so don't mention smtpmail here.
+
+2012-05-04  Wolfgang Jenkner  <wjenkner@inode.at>
+
+       * gnus.texi (Picons): Document gnus-picon-properties.
+
+2012-06-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Group Timestamp): Mention where to find documentation for
+       the `gnus-tmp-' variables (bug#11601).
+
+2012-06-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi: Remove mention of compilation, as that's no longer
+       supported.
+
+2012-05-01  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth.texi (Help for users): Update for .gpg file being second.
+
+2012-04-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * epa.texi: New file imported from Emacs.
+
+       * pgg.texi: Remove.
+
+       * Makefile.in: Replace pgg.* with epa.*.
+
+2012-04-05  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth.texi (Secret Service API): Edit further and give examples.
+       (Secret Service API): Adjust @samp to @code for collection names.
+
+2012-04-04  Glenn Morris  <rgm@gnu.org>
+
+       * auth.texi (Secret Service API): Copyedits.
+       (Help for developers): Fill in some missing function doc-strings.
+       (Help for users, Help for developers)
+       (GnuPG and EasyPG Assistant Configuration): Markup fixes.
+
+2012-04-04  Michael Albinus  <michael.albinus@gmx.de>
+
+       * auth.texi (Secret Service API): Add the missing text.
+
+2012-04-04  Chong Yidong  <cyd@gnu.org>
+
+       * message.texi (Using PGP/MIME): Note that epg is now the default.
+
+       * gnus.texi: Reduce references to obsolete pgg library.
+       (Security): Note that epg is now the default.
+
+       * gnus-faq.texi (FAQ 8-2): Mention EasyPG.
+
+2012-03-22  Peder O. Klingenberg  <peder@klingenberg.no>  (tiny change)
+
+       * gnus.texi (Archived Messages): Update `gnus-message-archive-group' to
+       reflect the new default.
+
+2012-03-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Client-Side IMAP Splitting): Note that `nnimap-inbox' now
+       can be a list.
+
+2012-03-14  Christopher Schmidt  <christopher@ch.ristopher.com>
+
+       * gnus.texi (Archived Messages): Mention gnus-gcc-pre-body-encode-hook
+       and gnus-gcc-post-body-encode-hook.
+
+2012-02-28  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-faq.texi, gnus-news.texi, gnus.texi:
+       Standardize possessive apostrophe usage.
+
+2012-02-17  Glenn Morris  <rgm@gnu.org>
+
+       * gnus.texi (Posting Styles): Fix cross-refs to other manual.
+
+2012-02-16  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Various Summary Stuff): Remove mention of
+       `gnus-propagate-marks'.
+
+2012-02-15  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi: Remove mentions of nnml/nnfolder/nntp backend marks, which
+       no longer exist.
+
+2012-02-13  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Customizing the IMAP Connection): Mention
+       nnimap-record-commands.
+
+2012-02-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Archived Messages): Document gnus-gcc-self-resent-messages.
+
+2012-02-07  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Mail Source Specifiers): Add a pop3 via an SSH tunnel
+       example (modified from an example by Michael Albinus).
+
+2012-02-06  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * message.texi (Mail Variables): Mention the optional user parameter
+       for X-Message-SMTP-Method.
+
+2012-02-02  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Posting Styles): Mention X-Message-SMTP-Method.
+
+       * message.texi (Mail Variables): Document X-Message-SMTP-Method.
+
+2012-01-31  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Key Index): Change encoding to utf-8.
+
+2012-01-30  Philipp Haselwarter  <philipp.haselwarter@gmx.de>  (tiny change)
+
+       * gnus.texi (Agent Basics): Fix outdated description of
+       `gnus-agent-auto-agentize-methods'.
+
+2012-01-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Group Parameters): Really note precedence.
+
+2012-01-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Group Parameters): Note precedence.
+
+2011-12-30  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus.texi (Filtering New Groups, Score File Format): Spelling fix.
+
+2011-12-28  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus.texi (Mail Source Customization, Mail Back End Variables):
+       Use octal notation for file permissions, which are normally
+       thought of in octal.
+       (Mail Back End Variables): Use more-plausible modes in example.
+
+2011-12-21  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * auth.texi (Help for developers): Spelling fix.
+
+2011-12-14  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus.texi (Using MIME, Score File Syntax): Spelling fix.
+
+2011-12-12  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * emacs-mime.texi (Display Customization):
+       * gnus-faq.texi (FAQ 6-3):
+       * gnus.texi (Sieve Commands, Other Decode Variables): Spelling fix.
+
+2011-12-06  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus-faq.texi (FAQ 2-1, FAQ 3-8, FAQ 4-14, FAQ 9-1): Fix typos.
+
+2011-12-05  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus.texi (Article Washing): Spelling fix.
+
+2011-12-04  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * message.el (Insertion Variables): Spelling fix.
+
+2011-11-27  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus.texi (Propagating marks, Red Gnus): Spelling fix.
+
+2011-11-25  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus.texi (The swish++ Engine, The swish-e Engine):
+       * message.texi (IDNA): Spelling fix.
+
+2011-11-24  Glenn Morris  <rgm@gnu.org>
+
+       * gnus.texi: Fix case of "GnuTLS".
+
+2011-11-22  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-refcard.tex: Spelling fix; remove trailing whitespace.
+
+       * gnus.texi (nnmairix caveats): Spelling fix.
+
+2011-11-20  Glenn Morris  <rgm@gnu.org>
+
+       * gnus.texi (Group Information):
+       Remove gnus-group-fetch-faq, command deleted 2010-09-24.
+
+2011-11-20  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus-coding.texi (Gnus Maintenance Guide):
+       Rename from "Gnus Maintainance Guide".
+
+       * gnus.texi (Article Washing):
+       * gnus-news.texi: Fix typos.
+
+2011-11-20  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-news.texi (Changes in group mode):
+       * gnus.texi (The imap Engine, The gmane Engine)
+       (Extending the Spam package): Spelling fix.
+
+2011-11-19  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus.texi (Score File Syntax):
+       * message.texi (Various Message Variables): Spelling fix.
+
+2011-11-17  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus.texi (Contributors):
+       * pgg.texi (Architecture): Spelling fix.
+
+2011-11-15  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus.texi (Sending or Not Sending): Fix typo.
+
+2011-11-15  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * emacs-mime.texi (Flowed text):
+       * gnus-faq.texi (FAQ 4-15):
+       * gnus.texi (Sticky Articles, Diary Summary Line Format): Spelling fix.
+
+2011-11-09  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * auth.texi (GnuPG and EasyPG Assistant Configuration):
+       * gnus.texi (Customizations): Spelling fix.
+
+2011-10-31  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Other Gnus Versions): Remove.
+
+2011-10-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Gnus Utility Functions): Add more references and
+       explanations (bug#9683).
+
+2011-09-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Archived Messages): Note the default (bug#9552).
+
+2011-09-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Listing Groups): Explain `gnus-group-list-limit'.
+       (Finding the News): Doc clarification.
+       (Terminology): Mention naming.
+
+2011-09-10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi: Remove mentions of `recent', which are now obsolete.
+       (Interactive): Document `quiet'.
+
+2011-07-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Expiring Mail): Document gnus-auto-expirable-marks.
+       (Filtering New Groups): Clarify how simple the "options -n" format is.
+       (Agent Expiry): Remove mention of `gnus-request-expire-articles', which
+       is internal.
+
+2011-07-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Subscription Methods): Link to "Group Levels" to explain
+       zombies.
+       (Checking New Groups): Ditto (bug#8974).
+       (Checking New Groups): Moved the reference to the right place.
+
+2011-07-03  Dave Abrahams  <dave@boostpro.com>  (tiny change)
+
+       * gnus.texi (Startup Files): Clarify that we're talking about numbered
+       backups, and not actual vc (bug#8975).
+
+2011-06-26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Summary Mail Commands): Document
+       `gnus-summary-reply-to-list-with-original'.
+
+2011-05-31  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Store custom flags and keywords): Refer to
+       `gnus-registry-article-marks-to-{chars,names}' instead of
+       `gnus-registry-user-format-function-{M,M2}'.
+
+2011-05-18  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Gnus Registry Setup): Rename from "Setup".
+       (Store custom flags and keywords): Mention
+       `gnus-registry-user-format-function-M' and
+       `gnus-registry-user-format-function-M2'.
+
+2011-05-17  Glenn Morris  <rgm@gnu.org>
+
+       * gnus.texi (Face): Fix typo.
+
+2011-05-03  Peter Münster  <pmlists@free.fr>  (tiny change)
+
+       * gnus.texi (Summary Buffer Lines):
+       gnus-summary-user-date-format-alist does not exist.
+       (Sorting the Summary Buffer): More about sorting threads.
+
+2011-04-14  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (nnmairix caveats, Setup, Registry Article Refer Method)
+       (Fancy splitting to parent, Store arbitrary data): Updated
+       gnus-registry docs.
+
+2011-04-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Window Layout): @itemize @code doesn't exist.
+       It's @table @code.
+
+2011-03-19  Antoine Levitt  <antoine.levitt@gmail.com>
+
+       * gnus.texi (Listing Groups): Document gnus-group-list-ticked.
+
+2011-03-15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.texi (Various Commands): Document format specs in the
+       ellipsis.
+
+2011-03-15  Antoine Levitt  <antoine.levitt@gmail.com>
+
+       * message.texi (Insertion Variables): Document message-cite-style.
+
+2011-03-12  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth.texi (Help for developers): Update docs to explain that the
+       :save-function will only run the first time.
+
+2011-03-08  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth.texi (Help for developers): Show example of using
+       `auth-source-search' with prompts and :save-function.
+
+2011-03-07  Antoine Levitt  <antoine.levitt@gmail.com>
+
+       * message.texi (Message Buffers): Update default value of
+       message-generate-new-buffers.
+
+2011-02-23  Glenn Morris  <rgm@gnu.org>
+
+       * gnus.texi: Standardize some Emacs/XEmacs terminology.
+
+2011-02-22  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth.texi (Help for users): Mention ~/.netrc is also searched by
+       default now.
+
+2011-02-21  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Article Date): Clarify gnus-article-update-date-headers.
+
+2011-02-20  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Window Layout): Document layout names.
+
+2011-02-19  Eli Zaretskii  <eliz@gnu.org>
+
+       * auth.texi: Sync @dircategory with Emacs/info/dir.
+       * emacs-mime.texi: Sync @dircategory with Emacs/info/dir.
+       * gnus.texi: Sync @dircategory with Emacs/info/dir.
+       * message.texi: Sync @dircategory with Emacs/info/dir.
+       * pgg.texi: Sync @dircategory with Emacs/info/dir.
+       * sasl.texi: Sync @dircategory with Emacs/info/dir.
+       * sieve.texi: Sync @dircategory with Emacs/info/dir.
+
+2011-02-17  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth.texi (Help for users): Use :port instead of :protocol for all
+       auth-source docs.
+       (GnuPG and EasyPG Assistant Configuration): Mention the default now is
+       to have two files in `auth-sources'.
+
+2011-02-14  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth.texi (Help for users):
+       Login collection is "Login" and not "login".
+
+2011-02-11  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth.texi (Overview, Help for users, Help for developers):
+       Update docs.
+       (Help for users): Talk about spaces.
+
+2011-02-05  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-overrides.texi: Renamed from overrides.texi and all the relevant
+       manuals use it now.
+
+       * Makefile.in (nowebhack): Fixed to use -D flag instead of overrides.
+
+2011-02-04  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * overrides.texi: New file to set or clear WEBHACKDEVEL.
+
+       * sieve.texi: Use WEBHACKDEVEL.
+
+       * sasl.texi: Use WEBHACKDEVEL.
+
+       * pgg.texi: Use WEBHACKDEVEL.
+
+       * message.texi: Use WEBHACKDEVEL.
+
+       * gnus.texi: Use WEBHACKDEVEL.
+
+       * emacs-mime.texi: Use WEBHACKDEVEL.
+
+       * auth.texi: Use WEBHACKDEVEL.
+
+       * Makefile.in (webhack, nowebhack): Hacks to produce for-the-web
+       manuals.
+
+2011-02-04  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi: Add DEVEL header (suggested by Andreas Schwab).
+
+2011-02-03  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Article Date): Remove mention of gnus-stop-date-timer,
+       since it's run automatically.
+
+2011-02-01  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Customizing Articles): Fix typo.
+
+2011-01-31  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Customizing Articles): Document the new way of customizing
+       the date headers(s).
+
+2011-01-30  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Client-Side IMAP Splitting): Add a complete nnimap fancy
+       splitting example.
+
+2011-01-26  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Article Date): Document gnus-article-update-lapsed-header.
+
+2011-01-24  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * message.texi (IDNA): Explain what it is.
+
+2011-01-24  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (The Empty Backend): Document nnnil (bug #7653).
+
+2010-12-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Archived Messages): Remove outdated text.
+
+2010-12-16  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Foreign Groups): Added clarification of foreign groups.
+
+2010-12-15  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * gnus.texi (The hyrex Engine): Say that this engine is obsolete.
+
+2010-12-14  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * gnus.texi (The swish++ Engine): Add customizable parameters
+       descriptions.
+       (The swish-e Engine): Ditto.
+
+2010-12-13  Andrew Cohen  <cohen@andy.bu.edu>
+
+       * gnus.texi: First pass at adding (rough) nnir documentation.
+
+2010-12-13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Filtering New Groups):
+       Mention gnus-auto-subscribed-categories.
+       (The First Time): Remove, since default-subscribed-newsgroups has been
+       removed.
+
+2010-12-06  Tassilo Horn  <tassilo@member.fsf.org>
+
+       * gnus.texi (Server Commands): Point to the rest of the server
+       commands.
+
+2010-12-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Paging the Article): Note the reverse meanings of `C-u C-u
+       g'.
+
+2010-12-02  Julien Danjou  <julien@danjou.info>
+
+       * gnus.texi (Archived Messages): Remove gnus-outgoing-message-group.
+
+2010-11-28  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Customizing the IMAP Connection): Note the new defaults.
+       (Direct Functions): Note the STARTTLS upgrade.
+
+2010-11-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Server Commands): Document gnus-server-show-server.
+
+2010-11-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Misc Article): Document gnus-inhibit-images.
+
+2010-11-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Article Washing): Fix typo.
+
+2010-11-09  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Article Washing): Document gnus-article-treat-non-ascii.
+
+2010-11-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Customizing the IMAP Connection): Remove nnir mention,
+       since that works by default.
+
+2010-11-03  Kan-Ru Chen  <kanru@kanru.info>  (tiny change)
+
+       * gnus.texi (Customizing the IMAP Connection): Document
+       `nnimap-expunge' and remove `nnimap-expunge-inbox' from example.
+
+2010-11-03  Glenn Morris  <rgm@gnu.org>
+
+       * gnus.texi (Agent Variables, Configuring nnmairix): Spelling fix.
+
+2010-10-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Paging the Article): Document C-u g/C-u C-u g.
+
+2010-10-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Client-Side IMAP Splitting): Mention
+       nnimap-unsplittable-articles.
+
+2010-10-29  Julien Danjou  <julien@danjou.info>
+
+       * gnus.texi (Finding the News): Remove references to obsoletes
+       variables `gnus-nntp-server' and `gnus-secondary-servers'.
+
+2010-10-24  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus.texi (Group Parameters, Buttons): Fix typos.
+
+2010-10-22  Tassilo Horn  <tassilo@member.fsf.org>
+
+       * gnus.texi (Subscription Commands): Mention that you can also
+       subscribe to new groups via the Server buffer, which is probably more
+       convenient when subscribing to many groups.
+
+2010-10-21  Julien Danjou  <julien@danjou.info>
+
+       * message.texi (Message Headers): Allow message-default-headers to be a
+       function.
+
+2010-10-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-news.texi: Mention new archive defaults.
+
+2010-10-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (RSS): Remove nnrss-wash-html-in-text-plain-parts.
+
+2010-10-20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (HTML): Document the function value of
+       gnus-blocked-images.
+       (Article Washing): shr and gnus-w3m, not the direct function names.
+
+2010-10-20  Julien Danjou  <julien@danjou.info>
+
+       * emacs-mime.texi (Flowed text): Add a note about mml-enable-flowed
+       variable.
+
+2010-10-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Customizing the IMAP Connection): The port strings are
+       strings.
+       (Document Groups): Mention git.
+
+2010-10-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-coding.texi (Gnus Maintainance Guide): Update to mention Emacs
+       bzr/Gnus git sync.
+
+2010-10-15  Eli Zaretskii  <eliz@gnu.org>
+
+       * auth.texi (GnuPG and EasyPG Assistant Configuration): Fix last
+       change.
+
+2010-10-13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * auth.texi (GnuPG and EasyPG Assistant Configuration): Fix up the
+       @item syntax for in-Emacs makeinfo.
+
+2010-10-13  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth.texi (GnuPG and EasyPG Assistant Configuration): Fix syntax and
+       trim sentence.
+
+2010-10-12  Daiki Ueno  <ueno@unixuser.org>
+
+       * auth.texi (GnuPG and EasyPG Assistant Configuration): Clarify
+       some configurations require to set up gpg-agent.
+
+2010-10-09  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Spam Package Introduction): Mention `$'.
+
+2010-10-09  Glenn Morris  <rgm@gnu.org>
+
+       * gnus.texi (Article Washing): Fix previous change.
+
+2010-10-08  Julien Danjou  <julien@danjou.info>
+
+       * gnus.texi: Add mm-shr.
+
+2010-10-08  Ludovic Courtès  <ludo@gnu.org>
+
+       * gnus.texi (Finding the Parent, The Gnus Registry)
+       (Registry Article Refer Method): Update docs for nnregistry.el.
+
+2010-10-08  Daiki Ueno  <ueno@unixuser.org>
+
+       * auth.texi (Help for users)
+       (GnuPG and EasyPG Assistant Configuration): Update docs.
+
+2010-10-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Gravatars): Document gnus-gravatar-too-ugly.
+
+2010-10-06  Julien Danjou  <julien@danjou.info>
+
+       * sieve.texi (Manage Sieve API): Document sieve-manage-authenticate.
+
+       * message.texi (PGP Compatibility): Remove reference to gpg-2comp,
+       broken link.
+
+       * Makefile.in: Remove xml2texi stuff.
+
+       * gnus-faq.texi (FAQ 8-3): Remove references to my.gnus.org.
+
+       * gnus.texi (Comparing Mail Back Ends): Remove broken link and allusion
+       to ReiserFS.
+
+       * gnus-faq.texi (FAQ 5-5): Fix Flyspell URL.
+       (FAQ 7-1): Fix getmail URL.
+
+2010-10-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Misc Article): Document gnus-widen-article-window.
+
+2010-10-03  Julien Danjou  <julien@danjou.info>
+
+       * emacs-mime.texi (Display Customization): Update
+       mm-inline-large-images documentation and add documentation for
+       mm-inline-large-images-proportion.
+
+2010-10-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Splitting Mail): Fix @xref syntax.
+       (Splitting Mail): Really fix the @ref syntax.
+
+2010-10-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Splitting Mail): Mention the new fancy splitting
+       function.
+       (Article Hiding): Add google banner example.  Suggested by Benjamin
+       Xu.
+
+2010-09-30  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Spam Package Configuration Examples, SpamOracle): Remove
+       nnimap-split-rule from examples.
+
+2010-09-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Mail Source Specifiers): Remove webmail.el mentions.
+       (NNTP): Document nntp-server-list-active-group.  Suggested by Barry
+       Fishman.
+       (Client-Side IMAP Splitting): Add nnimap-split-fancy.
+
+2010-09-30  Julien Danjou  <julien@danjou.info>
+
+       * gnus.texi (Gravatars): Fix documentation about
+       gnu-gravatar-properties.
+
+2010-09-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Using IMAP): Remove the @acronyms from the headings.
+       (Client-Side IMAP Splitting): Document 'default.
+
+2010-09-27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Customizing the IMAP Connection): Document
+       nnimap-fetch-partial-articles.
+
+2010-09-26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-news.texi: Mention nnimap-inbox.
+
+       * gnus.texi (Picons): Document gnus-picon-inhibit-top-level-domains.
+
+2010-09-26  Julien Danjou  <julien@danjou.info>
+
+       * gnus.texi (Oort Gnus): Remove mention of ssl.el.
+
+2010-09-26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Security): Remove gpg.el mention.
+
+2010-09-26  Andreas Seltenreich  <seltenreich@gmx.de>
+
+       * gnus.texi (Browse Foreign Server): New variable
+       gnus-browse-subscribe-newsgroup-method.
+
+       * gnus-news.texi: Mention it.
+
+2010-09-26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (NoCeM): Removed.
+       (Startup Variables): No jingle.
+
+2010-09-25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Article Commands): Document gnus-fetch-partial-articles.
+       (Unavailable Servers): Document gnus-server-copy-server.
+       (Using IMAP): Document the new nnimap.
+
+2010-09-25  Julien Danjou  <julien@danjou.info>
+
+       * gnus.texi (Customizing Articles): Remove gnus-treat-translate.
+
+2010-09-24  Julien Danjou  <julien@danjou.info>
+
+       * gnus.texi: Add Gravatars.
+
+2010-09-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Startup Variables): Mention gnus-use-backend-marks.
+
+2010-09-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Expunging mailboxes): Update name of the expunging
+       command.
+
+2010-09-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * emacs-mime.texi (rfc2047): Update description for
+       rfc2047-encode-parameter.
+
+2010-09-20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-news.texi: Say what Emacs versions we support.
+
+2010-09-04  Julien Danjou  <julien@danjou.info>  (tiny change)
+
+       * gnus.texi (Adaptive Scoring): Fix typo.
+
+2010-09-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Article Display): Document gnus-html-show-images.
+
+2010-09-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (HTML): Document gnus-max-image-proportion.
+
+2010-08-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (HTML): Document gnus-blocked-images.
+
+       * message.texi (Wide Reply): Document message-prune-recipient-rules.
+
+2010-08-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Summary Mail Commands): Note that only the addresses from
+       the first message are used for wide replies.
+       (Changing Servers): Remove documentation on gnus-change-server and
+       friends, since it's been removed.
+
+2010-08-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Drafts): Mention B DEL.
+
+2010-08-29  Tim Landscheidt  <tim@tim-landscheidt.de>  (tiny change)
+
+       * gnus.texi (Delayed Articles): Mention that the Date header is the
+       original one, even if you delay.
+
+2010-08-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Asynchronous Fetching): Document
+       gnus-async-post-fetch-function.
+       (HTML): Made into its own section.
+
+2010-06-24  Glenn Morris  <rgm@gnu.org>
+
+       * auth.texi, emacs-mime.texi, gnus.texi, message.texi, pgg.texi:
+       * sasl.texi: Start direntry descriptions in column 32, per Texinfo
+       convention.  Make them end with a period.
+
+2010-06-23  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-faq.texi, pgg.texi, sasl.texi, sieve.texi: Untabify.
+
+2010-06-07  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Interactive): Explain effect of gnus-expert-user better.
+
+2010-05-08  Štěpán Němec  <stepnem@gmail.com>  (tiny change)
+
+       * message.texi (Header Commands, Responses): Fix typos.
+
+2010-04-17  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Gnus Versions, Oort Gnus): Mention the Git repo instead of
+       the CVS repo.  Put the Git repo in the news section.
+
+       * gnus-coding.texi (Gnus Maintainance Guide): Fixed title typo.
+       Removed some mentions of CVS.  Mention the new Git repo.
+
+2010-04-15  Andreas Seltenreich  <seltenreich@gmx.de>
+
+       * gnus.texi (Score File Format): Fix typo.  Reported by Štěpán Němec.
+       (Mail Group Commands): Add index entry.
+
+2010-04-01  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Finding the News): Add pointers to the Server buffer
+       because it's essential.
+
+2010-03-31  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (MIME Commands): Update description of
+       gnus-article-browse-html-article.
+
+2010-03-27  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth.texi (Secret Service API): Add TODO node.
+       (Help for users): Explain the new source options for `auth-sources'.
+
+2010-01-21  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Score File Format): Fix typo.
+
+2010-01-04  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus.texi (Posting Styles): Use with-current-buffer.
+
+2009-12-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Direct Functions): Add missing port number to tls method.
+
+2009-09-22  Daiki Ueno  <ueno@unixuser.org>
+
+       * gnus.texi (Security): Document mm-sign-option and mm-encrypt-option.
+
+2009-09-02  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth.texi (Help for users): Corrected markup.
+
+2009-09-02  Glenn Morris  <rgm@gnu.org>
+
+       * emacs-mime.texi (time-date): Mention float-time.
+
+2009-08-28  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth.texi: Rewritten for coverage and clarity.
+
+2009-08-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Expiring Mail): Mention
+       gnus-mark-copied-or-moved-articles-as-expirable.
+       (Various Various): Mention gnus-safe-html-newsgroups.
+
+       * gnus-news.texi: Mention
+       gnus-mark-copied-or-moved-articles-as-expirable.
+
+       * emacs-mime.texi (Display Customization): Add xref to
+       gnus-safe-html-newsgroups.
+
+2009-07-16  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-refcard.tex: Condense a few sentences in order to
+       make them fit on one line, and add some page breaks, to improve the
+       layout in the pdfs.
+
+2009-07-15  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-refcard.tex (Copyright): Add 2009.
+       (Notes): Add missing line-break.
+       (Threading): Reword to fit on one line.
+
+2009-07-15  Glenn Morris  <rgm@gnu.org>
+
+       * Makefile.in (gnus-booklet.pdf): Use jobname rather than
+       clobbering gnus-refcard.pdf.
+
+2009-06-04  Daiki Ueno  <ueno@unixuser.org>
+
+       * gnus.texi (Security): Fix wording; add a link to epa.info.
+
+2009-06-04  Ryan Yeske  <rcyeske@gmail.com>
+
+       * message.texi (Header Commands): Fix descriptions to match
+       keybindings.
+
+2009-04-22  Daiki Ueno  <ueno@unixuser.org>
+
+       * gnus.texi (Security): Mention that EasyPG is the current default.
+
+2009-04-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * auth.texi: Synch up with Emacs---change Info file name auth.info to
+       auth; remove duplicate @settitle, @dircategory, and @direntry sections;
+       fix Tex switches.
+
+2009-04-05  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-faq.texi (FAQ 8-4): Fix wrong group name of
+       news.software.readers.  Reported by Florian Rehnisch.
+
+2009-04-02  Glenn Morris  <rgm@gnu.org>
+
+       * auth.texi: Capitalize direntry.
+
+2009-03-03  Glenn Morris  <rgm@gnu.org>
+
+       * auth.texi: Fix @setfilename.
+
+2009-02-26  Glenn Morris  <rgm@gnu.org>
+
+       * gnus.texi: Minor updates for mbox Rmail.
+
+2009-02-26  Karl Berry  <karl@gnu.org>
+
+       * gnus-coding.texi,
+       * gnus.texi,
+       * message.texi,
+       * pgg.texi,
+       * sasl.texi,
+       * sieve.texi: Consistently use @insertcopying in the Top node,
+       @contents at the front (after @end titlepage),
+       and @direntry after @copying.
+       (Bug#1988)
+
+2009-02-20  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * dir: Add auth.texi.
+
+       * Makefile.in (INSTALL_DATA, INFO_DEPS, dvi, pdf, latex): Add
+       auth.texi.
+
+2009-02-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (NoCeM): Fix description of gnus-use-nocem.
+
+2009-02-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (NoCeM): Update default values for gnus-nocem-groups,
+       gnus-nocem-issuers, and gnus-nocem-verifyer.
+
+2009-02-13  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth.texi: New file documenting auth-source.
+
+2009-02-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-news.texi: Print version about Incoming*.
+
+2009-01-17  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Limiting): `/ N' and `/ o' are not really limiting
+       commands as described at the top.  Reported by Allan Gottlieb
+       <gottlieb@nyu.edu>.
+
+2009-01-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Non-ASCII Group Names, RSS): Update description of
+       nnmail-pathname-coding-system.
+
+2009-01-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Group Parameters): Add note for local variables.
+
+2008-12-26  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Converting Kill Files): Fix URL.  Include
+       gnus-kill-to-score.el in contrib directory.
+
+2008-12-21  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Startup Variables): Fix gnus-before-startup-hook.
+       Reported by Leo <sdl.web@gmail.com>.  (Bug#1660)
+       (Paging the Article): Add index entry.
+
+2008-12-08  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.texi (Insertion Variables): Don't advertise sc-cite-original.
+
+2008-12-04  David Engster  <dengste@eml.cc>
+
+       * gnus.texi (nnmairix): Mention mairix.el.  Point out the importance
+         of nnml-get-new-mail.  Change URL for mairix patch.
+
+2008-11-19  Glenn Morris  <rgm@gnu.org>
+
+       * doclicense.texi: Change to FDL 1.3.
+       Relicense all texi files under FDL 1.3 or later.
+
+2008-09-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * infohack.el (infohack): Use Info-split-threshold to decide whether to
+       split Info files.
+
+2008-09-25  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * message.texi (Sending Variables): Fixed variable documentation to
+       avoid the "y/n" wording.
+
+2008-09-24  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * message.texi (Sending Variables): Added `message-confirm-send' doc.
+
+2008-09-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * infohack.el (infohack-include-files): New function.
+       (infohack): Use it to insert @include files before performing
+       texinfo-every-node-update.
+
+       * gnus.texi (The Gnus Registry): Don't give argument to @item used in
+       @enumerate section so as to be able to be formatted with MAKEINFO=no.
+
+2008-09-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Top, Setup, Fancy splitting to parent)
+       (Store custom flags and keywords, Store arbitrary data): Clean up
+       markup.
+
+2008-09-16  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (The Gnus Registry): Document it.
+
+2008-09-08  David Engster  <dengste@eml.cc>
+
+       * gnus.texi (nnmairix): Point out that nnml uses MH format.  Clarify
+       section about choosing back end servers.
+
+2008-07-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Sorting the Summary Buffer, Summary Sorting): Add
+       gnus-summary-sort-by-most-recent-number and
+       gnus-summary-sort-by-most-recent-date.
+       (Summary Sorting): Explain prefix argument.
+
+2008-07-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Saving Articles): Mention symbolic prefix `r' for
+       gnus-summary-pipe-output.
+
+2008-07-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Saving Articles): Describe the 2nd argument of
+       gnus-summary-save-in-pipe.
+       (SpamAssassin): Use it.
+
+2008-07-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (SpamAssassin): Fix gnus-summary-save-in-pipe usage.
+
+2008-07-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Saving Articles): Mention
+       gnus-summary-pipe-output-default-command and gnus-summary-save-in-pipe.
+
+2008-06-16  Glenn Morris  <rgm@gnu.org>
+
+       * pgg.texi, sasl.texi: Add Cover-Texts.
+
+2008-06-15  Glenn Morris  <rgm@gnu.org>
+
+       * sasl.texi: Refer to license in Emacs manual.
+
+       * gnus-coding.texi: Refer to license in Gnus manual.
+
+       * emacs-mime.texi, gnus.texi, message.texi, sieve.texi:
+       Remove references to external license, since doclicense is included.
+
+2008-06-13  Glenn Morris  <rgm@gnu.org>
+
+       * emacs-mime.texi, gnus-coding.texi, gnus.texi, message.texi
+       * sieve.texi: Update Back-Cover Text as per maintain.info.
+
+2008-06-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-faq.texi: Generate.  Change node names to "FAQ N-M".
+
+       * Makefile.in (gnus-faq-clean): Don't remove gnus-faq.texi.
+       (gnus-faq.xml): Update repository host.
+
+       * xml2texi.scm (boilerplate): Update copyright years.
+       (format-q-level): Change node names to "FAQ N-M", since period in
+       "[N.M]" is invalid, see "(texinfo)Node Line Requirements".
+
+       * gnus-faq.texi: Generate from gnus-faq.xml (sourceforge.net).
+
+2008-06-15  Frank Schmitt  <ich@frank-schmitt.net>
+
+       * gnus-faq.texi ([5.12]): Add entry about message-kill-buffer-on-exit.
+       Fix a typo.
+
+2008-06-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Mail Source Customization): Correct values of
+       `mail-source-delete-incoming'.  Reported by Tassilo Horn.
+       (Oort Gnus): Fix version comment for mml-dnd-protocol-alist.
+
+2008-06-14  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (nnmairix): Eliminate wrong use of `path', cf. the GNU
+       coding standards.
+
+2008-06-14  David Engster  <dengste@eml.cc>
+
+       * gnus.texi (nnmairix): Markup fixes.
+
+2008-06-05  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (nnmairix): Markup and other minor fixes.
+
+2008-06-05  David Engster  <dengste@eml.cc>
+
+       * gnus.texi (nnmairix): New nodes describing nnmairix.el.
+
+2008-06-05  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Group Parameters): Change ~/.gnus to ~/.gnus.el.
+       (Searching, nnir, nnmairix): New stub nodes.
+
+2008-05-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Filling In Threads): Additions to gnus-fetch-old-headers.
+
+2008-05-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Scoring On Other Headers): Fix typo.  Rearrange.
+
+2008-05-01  Lars Magne Ingebrigtsen  <lars@ingebrigtsen.no>
+
+       * gnus.texi, gnus-faq.texi, message.texi: Bump version to 0.11.
+
+2008-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Various Summary Stuff): Add gnus-propagate-marks.
+       (Various Summary Stuff): Fix typo in last xref.
+
+2008-04-13  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Oort Gnus): Add message-fill-column.
+
+2008-04-12  Adrian Aichner  <adrian@xemacs.org>
+
+       * gnus.texi (Mail Source Specifiers): Typo fix.
+
+2008-04-12  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Diary Headers Generation): Update key binding for
+       `gnus-diary-check-message'.
+
+2008-04-11  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi, gnus-faq.texi, message.texi: Bump version to 0.9.
+
+2008-04-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Emacsen): Addition.
+
+2008-04-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Emacsen): Give recommendations for Emacs 22 and Emacs 23.
+
+2008-04-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi, gnus-faq.texi, message.texi: No Gnus v0.8 is released.
+
+2008-04-09  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Oort Gnus): Mention customizing of tool bars.
+
+2008-04-09  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-news.texi: Update tool bar item.
+
+2008-04-09  Sven Joachim  <svenjoac@gmx.de>
+
+       * gnus-news.texi: Fix typos.
+
+2008-03-29  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Top): Fix version.  Add SASL.
+
+2008-03-22  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Foreign Groups): Add gnus-read-ephemeral-gmane-group,
+       gnus-read-ephemeral-gmane-group-url,
+       gnus-read-ephemeral-emacs-bug-group,
+       gnus-read-ephemeral-debian-bug-group.
+
+2008-03-21  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (MIME Commands): Add gnus-article-browse-html-article.
+
+       * gnus-news.texi: Add EasyPG.  Add gnus-article-browse-html-article.
+       Add FIXMEs for Bookmarks and gnus-registry-marks.
+
+2008-03-16  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Smileys): Document `smiley-style'.
+
+2008-03-21  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Gnus Development): Clarify difference between ding and
+       gnu.emacs.gnus.
+       (MIME Commands, Using MIME, RSS): Fix markup.
+
+       * gnus-faq.texi ([8.4]): Ditto.
+
+2008-03-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Emacsen): Remove obsolete stuff.
+
+2008-03-19  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Oort Gnus): Add version info WRT
+       `mail-source-delete-incoming'.
+
+2008-03-16  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Top): Add "Other related manuals" and version info in
+       `iftex' output.
+       (Formatting Fonts): Add index entries for gnus-mouse-face, gnus-face-0,
+       gnus-balloon-face-0 and the corresponding format specifiers.
+
+2008-03-14  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus.texi (Example Methods, Direct Functions, Indirect Functions)
+       (Common Variables): Give precedence to the netcat methods over the
+       telnet methods, and mention that they are more reliable.
+
+2008-03-08  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Mail Source Customization, Gnus Development, Oort Gnus):
+       Update for change of `mail-source-delete-incoming'.
+
+       * gnus-news.texi: Ditto.
+
+2008-03-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-coding.texi (Gnus Maintainance Guide): Update conventions for
+       custom versions.
+
+2008-03-01  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Update copyright years.
+
+2008-02-26  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-news.texi: Mention problem with coding system `utf-8-emacs' when
+       using different Emacs versions.
+
+2008-02-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * Makefile.in (datarootdir): Define.
+       (install, uninstall): Quote directory name that might contain
+       whitespace.
+
+       * gnus-news.texi: Mention that spaces and tabs are allowed in the
+       installation directory name.
+
+       * ps/Makefile.in (datarootdir): Define.
+
+2008-01-24  Michael Sperber  <sperber@deinprogramm.de>
+
+       * gnus.texi (Mail Source Specifiers): Document `group' specifier.
+       (Group Parameters): Document `mail-source' parameter.
+
+2008-01-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-news.texi: Mention gnus-article-describe-bindings.
+
+2008-01-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-news.texi: Mention gnus-article-wide-reply-with-original.
+
+2008-01-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Article Keymap): Add gnus-article-wide-reply-with-original;
+       fix descriptions of gnus-article-reply-with-original and
+       gnus-article-followup-with-original.
+
+2008-01-05  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.texi (Mail Variables): Add some text from "(gnus)Posting
+       Server".  Add `message-send-mail-with-mailclient'.
+
+       * gnus.texi (Posting Server): Move some text to "(message)Mail
+       Variables" and add a reference here.
+
+2007-12-18  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Group Parameters): Reorder the text and add a note about
+       `gnus-parameters' near the beginning of the node.
+
+2007-12-17  IRIE Tetsuya  <irie@t.email.ne.jp>  (tiny change)
+
+       * gnus.texi (Score File Editing): Fix function name.
+
+2007-12-14  Sven Joachim  <svenjoac@gmx.de>
+
+       * gnus.texi (Score Variables): Fix typo.
+
+2007-12-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Other Files): Add the yenc command.
+
+2007-11-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (MIME Commands): Default of gnus-article-loose-mime is t
+       since 2004-08-06.
+
+2007-11-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Fancy Mail Splitting): Fix description of splitting based
+       on body.
+
+2007-11-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * emacs-mime.texi (rfc2047): Mention rfc2047-encoded-word-regexp-loose
+       and rfc2047-allow-irregular-q-encoded-words; fix description of
+       rfc2047-encode-encoded-words.
+
+2007-11-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Fetching Mail): Remove obsoleted `nnmail-spool-file'.
+
+2007-11-05  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-news.texi: Fix spelling.
+       `message-insert-formatted-citation-line', not
+       `message-insert-formated-citation-line'.
+
+2007-10-29  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-refcard.tex: Restore Feb 2007 copyright clarifications
+       lost in update to Gnus trunk.
+
+2007-10-27  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Troubleshooting): Adjust Gnus version number.
+
+2007-10-14  Emanuele Giaquinta  <e.giaquinta@glauco.it>  (tiny change)
+
+       * gnus-faq.texi ([5.12]): Remove reference to discontinued service.
+
+2007-10-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-news.texi: Remove Oort Gnus stuff.
+
+2007-10-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-news.texi: Mention non-ASCII group names; move new text about
+       `New make.bat', `~/News/overview/ not used', `(require 'gnus-load)',
+       and `Gnus no longer generate the Sender: header' from GNUS-NEWS.
+
+2007-10-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Relicense "GPLv2 or later" files to "GPLv3 or later".
+
+2007-10-03  Holger Schauer  <Holger.Schauer@gmx.de>
+
+       * gnus.texi (X-Face): Fix typo.
+
+2007-09-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Slow/Expensive Connection): Merge explanation for NOV into
+       the Terminology section.
+       (Terminology): Do.
+
+2007-09-23  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Sorting the Summary Buffer): Remove
+       gnus-article-sort-by-date-reverse.
+
+       * gnus-coding.texi (Gnus Coding Style) <message>: Add "patches
+       welcome".
+       (Gnus Coding Style) <General purpose libraries>: Move hex-util.el here.
+
+2007-09-20  Jim Meyering  <jim@meyering.net>  (tiny change)
+
+       * gnus.texi (On Writing Manuals): Fix typos.
+
+2007-09-17  Lowell Gilbert  <lgusenet@be-well.ilk.org>  (tiny change)
+
+       * gnus.texi (Slow/Expensive Connection): Improve descriptions.
+
+2007-09-17  Allan Gottlieb  <gottlieb@nyu.edu>  (tiny change)
+
+       * gnus.texi (Slow/Expensive Connection): Improve descriptions.
+
+2007-09-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Crosspost Handling): Replace gnus-nov-is-evil with
+       nntp-nov-is-evil; move vindex to gnus-nov-is-evil to Slow/Expensive
+       Connection; add xref to Slow/Expensive Connection.
+       (Slow/Expensive Connection): Describe not only NNTP connection; improve
+       gnus-nov-is-evil; add an explanation of NOV.
+       (Slow Machine): Add xref to Slow/Expensive Connection.
+
+2007-09-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Selecting a Group): Rename gnus-maximum-newsgroup to
+       gnus-newsgroup-maximum-articles.  Suggested by Leo <sdl.web@gmail.com>.
+       (Non-ASCII Group Names): Fix select method example.
+
+2007-09-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Non-ASCII Group Names): New node.
+       (Misc Group Stuff): Move gnus-group-name-charset-method-alist and
+       gnus-group-name-charset-group-alist to Non-ASCII Group Names node.
+
+2007-08-31  Michaël Cadilhac  <michael@cadilhac.name>
+
+       * gnus.texi (Mail Source Specifiers, IMAP): Add a notice on the need to
+       clean the output of the program `imap-shell-program'.
+
+2007-08-25  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-coding.texi (Gnus Coding Style) <Encryption and security>: Add
+       sha1.el and hex-util.el.
+       (Gnus Coding Style) <Networking>: Write dns.el and dns-mode.el instead
+       of dns*.el.
+       (Gnus Coding Style) <Mail and News related RFCs>: Document missing Gnus
+       dependencies.
+       (Gnus Maintainance Guide): Give advice for post-Emacs-22.1 defcustoms.
+       Say that it should also be used when the default changed.
+       (Gnus Coding Style) <Compatibility>: Adjust versions for 5.10.10.
+       (Gnus Coding Style) <Emacs MIME>: Add "patches welcome".
+       (Gnus Coding Style) <Gnus backends>: Clean up.
+
+2007-08-24  IRIE Tetsuya  <irie@t.email.ne.jp>  (tiny change)
+
+       * message.texi (MIME): Replace mml-attach with mml-attach-file.
+
+2007-08-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (IMAP): Mention nnimap-logout-timeout.
+
+2007-08-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Selecting a Group): Mention gnus-maximum-newsgroup.
+
+2007-08-13  Tassilo Horn  <tassilo@member.fsf.org>
+
+       * gnus-news.texi: Mention sticky article buffers.
+
+       * gnus.texi (Sticky Articles): Documentation for sticky article buffers.
+
+2007-08-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (NNTP): Mention nntp-xref-number-is-evil.
+
+2007-08-08  Glenn Morris  <rgm@gnu.org>
+
+       * gnus.texi, sieve.texi: Replace `iff'.
+
+2007-07-25  Glenn Morris  <rgm@gnu.org>
+
+       * Relicense all FSF files to GPLv3 or later.
+
+2007-07-20  Michaël Cadilhac  <michael@cadilhac.name>
+
+       * gnus.texi (RSS): Document nnrss-ignore-article-fields.
+
+2007-07-13  Eli Zaretskii  <eliz@gnu.org>
+
+       * emacs-mime.texi: Add @documentencoding directive.
+
+2007-07-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Splitting Mail): Fix description of
+       nnmail-mail-splitting-decodes.
+
+2007-07-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-news.texi: Add message-citation-line-format.
+
+2007-07-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-coding.texi (Gnus Maintainance Guide): Update for Emacs 22.1.
+
+2007-07-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-faq.texi ([3.2]): Fix locating of environment variables in the
+       Control Panel.
+
+       * gnus.texi (Misc Article): Add index entry for
+       gnus-single-article-buffer.
+
+2007-06-27  Andreas Seltenreich  <andreas@gate450.dyndns.org>
+
+       * gnus.texi (Starting Up): Fix typo.
+
+2007-06-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Asynchronous Fetching): Fix typo.
+
+2007-06-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Various Various): Mention gnus-add-timestamp-to-message.
+
+2007-06-06  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus.texi (Article Buttons, Mail Source Customization)
+       (Sending or Not Sending, Customizing NNDiary):
+       * message.texi (Message Headers): Fix typos.
+
+2007-06-06  Andreas Seltenreich  <andreas@gate450.dyndns.org>
+
+       * gnus.texi (Misc Group Stuff, Summary Buffer)
+       (Server Commands, Article Keymap): Fix typo.  s/function/command/.
+
+2007-06-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Archived Messages): Document
+       gnus-update-message-archive-method.
+
+2007-05-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Limiting): Document gnus-summary-limit-to-address.
+
+2007-05-11  Michaël Cadilhac  <michael@cadilhac.name>
+
+       * gnus.texi (Group Maneuvering): Document
+       `gnus-summary-next-group-on-exit'.
+
+2007-05-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Really Various Summary Commands): Mention
+       gnus-auto-select-on-ephemeral-exit.
+
+2007-05-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Running NNDiary): Use ~/.gnus.el instead of gnusrc.
+
+2007-05-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi, message.texi: Bump version number.
+
+       * doclicense.texi: Update to version 1.2 from Emacs CVS.
+
+2007-04-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Article Highlighting): Clarify gnus-cite-parse-max-size.
+
+2007-04-15  Chong Yidong  <cyd@stupidchicken.com>
+
+       * gnus.texi, message.texi, pgg.texi, sieve.texi: Include GFDL.
+
+2007-04-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Group Line Specification, Misc Group Stuff)
+       (Server Commands): Parenthesize @pxref{Mail Spool}.
+
+2007-04-11  Didier Verna  <didier@xemacs.org>
+
+       New user option: message-signature-directory.
+       * gnus-news.texi: Advertise it.
+       * message.texi (Insertion Variables): Document it.
+       * gnus.texi (Posting Styles): Ditto.
+
+2007-04-11  Didier Verna  <didier@xemacs.org>
+
+       * gnus.texi (Group Line Specification):
+       * gnus.texi (Misc Group Stuff):
+       * gnus.texi (Server Commands): Document the group compaction feature.
+       * gnus-news.texi: Ditto.
+
+2007-04-01  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-faq.texi ([5.2]): Adjust for message-fill-column.
+
+       * gnus-news.texi: Add message-fill-column.
+
+       * message.texi (Various Message Variables): Add message-fill-column.
+
+       * gnus-news.el (gnus-news-header-disclaimer): Add newlines.
+
+2007-03-31  Eli Zaretskii  <eliz@gnu.org>
+
+       * emacs-mime.texi (Non-MIME): Postscript -> PostScript.
+
+2007-03-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi: Untabify.
+
+2007-03-28  Didier Verna  <didier@xemacs.org>
+
+       * gnus.texi (Group Parameters): Document the posting-style merging
+       process in topic-mode.
+
+2007-03-26  Richard Stallman  <rms@gnu.org>
+
+       * pgg.texi (Caching passphrase): Clean up previous change.
+
+2007-03-25  Thien-Thi Nguyen  <ttn@gnu.org>
+
+       * gnus.texi (Setting Process Marks): Fix typo.
+
+2007-03-24  Thien-Thi Nguyen  <ttn@gnu.org>
+
+       * gnus.texi (Splitting Mail): Reword "splitting"-as-adj to be -as-noun.
+
+       * gnus.texi (Mail Source Specifiers): Fix typo.
+
+2007-03-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Scoring On Other Headers): Add gnus-inhibit-slow-scoring.
+
+       * gnus-news.el (gnus-news-header-disclaimer, gnus-news-trailer): Switch
+       to standard GPL text for license.  Update copyright for years from
+       Emacs 21 to present (mainly adding 2001).  Text taken from Glenn
+       Morris' change to GNUS-NEWS in Emacs / v5-10.
+
+2007-03-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi, message.texi: Bump No Gnus version.
+
+2007-03-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.texi (Message Buffers): Update documentation for
+       message-generate-new-buffers.
+
+2007-03-15  Daiki Ueno  <ueno@unixuser.org>
+
+       * pgg.texi (Caching passphrase): Describe pgg-passphrase-coding-system.
+
+2007-03-11  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * gnus.texi (Mail and Post): Update documentation for gnus-user-agent.
+       The variable now uses a list of symbols instead of just a symbol.
+       Reported by Christoph Conrad <christoph.conrad@gmx.de>.
+
+2007-02-27  Chong Yidong  <cyd@stupidchicken.com>
+
+       * pgg.texi (Caching passphrase): Document gpg-agent usage, gpg-agent
+       problems on the console, and security risk in not using gpg-agent.
+
+2007-02-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (NNTP): Mention nntp-never-echoes-commands and
+       nntp-open-connection-functions-never-echo-commands.
+
+2007-01-28  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * gnus.texi (Batching Agents): Fix example.  Reported by Tassilo Horn
+       <tassilo@member.fsf.org>.
+
+2007-01-13  Romain Francoise  <romain@orebokech.com>
+
+       * gnus.texi (Mail Spool): Fix typo.
+       Update copyright.
+
+2007-01-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Customizing Articles): Use index entries for gnus-treat-*
+       variables only in info to avoid redundant entries in the printed
+       manual.
+
+2007-01-02  Daiki Ueno  <ueno@unixuser.org>
+
+       * message.texi (Using PGP/MIME): Document gpg-agent usage.
+
+2007-01-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.texi (Security): Split into sub-nodes.
+
+2006-12-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Limiting): Add gnus-summary-limit-to-singletons.
+
+2006-12-30  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * gnus.texi (Summary Generation Commands):
+       * gnus-news.texi: Add gnus-summary-insert-ticked-articles.
+
+2006-12-29  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Customizing Articles): Add index entries for all
+       gnus-treat-* variables.
+
+2006-12-29  Jouni K. Seppänen  <jks@iki.fi>
+
+       * gnus.texi (IMAP): Fix incorrect explanation of
+       nnimap-search-uids-not-since-is-evil in documentation for
+       nnimap-expunge-search-string.
+
+2006-12-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Mail and Post): Index gnus-message-highlight-citation.
+       (SpamAssassin back end): Rename spam-spamassassin-path to
+       spam-spamassassin-program.
+       (ifile spam filtering): Rename spam-ifile-database-path to
+       spam-ifile-database.
+
+2006-12-26  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-news.texi: Add gnus-message-highlight-citation.
+
+       * gnus.texi (Mail and Post): Add gnus-message-highlight-citation.
+
+       * gnus.texi (Spam Package Configuration Examples): Don't encourage to
+       rebind C-s.
+
+2006-12-26  Jouni K. Seppänen  <jks@iki.fi>
+
+       * gnus.texi (Group Parameters, Group Maintenance, Topic Commands)
+       (Mail Group Commands, Expiring Mail, IMAP): Add index entries for
+       "expiring mail".
+       (IMAP): Document nnimap-search-uids-not-since-is-evil and
+       nnimap-nov-is-evil.
+
+2006-12-24  Chong Yidong  <cyd@stupidchicken.com>
+
+       * pgg.texi (Caching passphrase): Default for pgg-gpg-use-agent changed
+       to t.
+       (Prerequisites): Add explanation about gpg-agent.
+
+2006-12-17  Sascha Wilde  <wilde@sha-bang.de>
+
+       * pgg.texi: Added short note on gpg-agent to the introduction.
+
+2006-12-13  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Hiding Headers): Document that `long-to' and `many-to'
+       also applies to Cc.
+
+2006-12-12  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (X-Face): Clarify.  Say which programs are required
+       on Windows.
+
+2006-11-24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Limiting): Add gnus-summary-limit-to-headers.
+
+2006-11-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.texi (Mail Headers): Document `opportunistic'.
+
+2006-10-13  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * gnus.texi (Other modes): Fix typo.  Add alternative index entry for
+       gnus-dired-attach.
+       (Selecting a Group): Fix typo.
+
+2006-10-06  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Image Enhancements): Update for Emacs 22.
+
+       * gnus-faq.texi ([1.3]): Update.
+
+2006-10-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Foreign Groups): Say where change of editing commands are
+       stored.  Add reference to `gnus-parameters'.
+
+2006-09-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * emacs-mime.texi (Encoding Customization): Explain how to set
+       mm-coding-system-priorities per hierarchy.
+
+2006-09-14  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-news.texi: Addition for `mm-fill-flowed'.
+
+       * gnus.texi (Oort Gnus): Add @xref for `mm-fill-flowed'.
+
+2006-09-09  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Mail Source Specifiers): Mention problem of duplicate
+       mails with pop3-leave-mail-on-server.  Fix wording.
+       (Limiting): Improve gnus-summary-limit-to-articles.
+       (X-Face): Fix typo.
+
+2006-07-24  Richard Stallman  <rms@gnu.org>
+
+       * pgg.texi: Move periods and commas inside quotes.
+
+2006-07-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Oort Gnus): Mention that the Lisp files are now installed
+       in .../site-lisp/gnus/ by default.
+       [ From gnus-news.texi in the trunk. ]
+
+2006-07-27  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (MIME Commands): Additions for yEnc.
+
+2006-07-10  Nick Roberts  <nickrob@snap.net.nz>
+
+       * gnus.texi, message.texi: Fix typos.
+
+2006-05-29  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * gnus.texi (Example Setup): Use ;; instead of ;;; to better follow
+       coding conventions.
+
+2006-06-24  Andreas Seltenreich  <uwi7@rz.uni-karlsruhe.de>
+
+       * gnus.texi (Summary Buffer Lines): Fix typo.
+
+2006-06-22  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Washing Mail): Add nnmail-ignore-broken-references and
+       nnmail-broken-references-mailers instead of nnmail-fix-eudora-headers.
+
+2006-06-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.texi (News Headers): Update message-syntax-checks section.
+
+2006-05-30  Didier Verna  <didier@xemacs.org>
+
+       * message.texi (Wide Reply): Update documentation of
+       message-dont-reply-to-names (now allowing a list of regexps).
+
+2006-05-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Saving Articles): Addition.
+
+2006-05-18  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Saving Articles): Clarify gnus-summary-save-article-mail.
+
+2006-05-12  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.texi (Interface): Add tool bar customization.
+       (MIME): Index and text additions for mml-attach.
+
+       * gnus.texi (Oort Gnus): Reorder entries in sections.  Fix some
+       entries.
+       (Starting Up): Add references to "Emacs for Heathens" and to
+       "Finding the News".  Add user-full-name and user-mail-address.
+       (Group Buffer Format): Add tool bar customization and update.
+       (Summary Buffer): Add tool bar customization.
+       (Posting Styles): Add message-alternative-emails.
+
+2006-04-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Spam Package Introduction): Fix spam menu and links.
+
+2006-04-26  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * pgg.texi (Caching passphrase): Fix markup and typos.  Simplify.
+
+2006-04-26  Sascha Wilde  <wilde@sha-bang.de>
+
+       * pgg.texi (Caching passphrase): Added documentation for
+       pgg-gpg-use-agent.
+
+2006-04-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Spam Statistics Package): Fix typo in @pxref.
+       (Splitting mail using spam-stat): Fix @xref.
+
+2006-04-20  Chong Yidong  <cyd@stupidchicken.com>
+
+       * gnus.texi (Spam Package): Major revision of the text.
+       Previouly this node was "Filtering Spam Using The Spam ELisp Package".
+2006-04-18  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-refcard.tex: Remove duplicate \def's.  Update date.
+
+2006-04-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (SpamAssassin back end): Fix typo.
+
+       * sieve.texi (Examples): Fix grammar.
+
+2006-04-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Searching for Articles): Document M-S and M-R.
+       (Limiting): Document / b.
+
+2006-04-15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Thread Commands): T M-^.
+
+2006-04-14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.texi (Mail Aliases): Document ecomplete.
+       (Mail Aliases): Fix typo.
+
+2006-04-11  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi, gnus-faq.texi, message.texi: No Gnus v0.4 is released.
+
+2006-04-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Misc Group Stuff, Summary Buffer, Article Keymap)
+       (Server Commands): Key `v' is reserved for users.
+
+2006-04-07  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Summary Buffer Lines): Add `*'.
+
+2006-04-07  Jochen Küpper  <jochen@fhi-berlin.mpg.de>
+
+       * gnus.texi (Group Parameters): Mention
+       gnus-permanently-visible-groups.
+
+2006-04-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Face): Restore xref to gnus-face-properties-alist;
+       fix typo.
+
+2006-04-05  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (X-Face): Clarify.
+       (Face): Need Emacs with PNG support.
+
+2006-04-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi, message.texi: Bump version.
+
+2006-04-04  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Security): Improve.
+
+2006-03-31  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-news.texi: Restore customizable tool bar item.  Markup
+       fixes.  Minor rewording.  Add "New packages and libraries",
+       "summary and article", "Appearance" and "Miscellaneous".  Remove
+       "Major new features" and "Other changes".  Add some @xref-s.
+
+2006-03-31  Romain Francoise  <romain@orebokech.com>
+
+       * gnus.texi (Virtual Groups): `nnvirtual-always-rescan' defaults
+       to t, not nil (and has for the past eight years).
+
+2006-03-30  Romain Francoise  <romain@orebokech.com>
+
+       * gnus-news.texi: Reorder entries in sections.  Fix typos.
+       Add local variables section.
+
+       * gnus-news.el (gnus-news-header-disclaimer): Delete top section.
+       (gnus-news-fill-column): Increment to 80.
+       (gnus-news-translate-file): Support nested list items.
+
+2006-03-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-news.texi: Add gnus-group-update-tool-bar.
+
+2006-03-29  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Top): Add comment about version line.
+
+       * message.texi (Top): Ditto.  Change to take named versions into
+       account.
+
+       * gnus-news.texi: Add customizable tool bar.
+
+2006-03-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Posting Styles): Add x-face-file to example.
+       (X-Face): Refer to posting styles.
+
+       * gnus-faq.texi ([5.8]): Add x-face-file.
+       ([8.4]): Add links to gmane.emacs.gnus.user and
+       gmane.emacs.gnus.general.
+
+2006-03-27  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * sasl.texi: Use @copyright{} instead of (C).  Update copyright.
+
+2006-03-27  Karl Berry  <karl@gnu.org>
+
+       * gnus.texi, message.texi, emacs-mime.texi, sieve.texi, pgg.texi:
+       Do not indent copyright year list.
+
+2006-03-27  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-faq.texi: Use .invalid.
+       ([5.4]): Fix gnus-posting-styles example.
+
+2006-03-20  Romain Francoise  <romain@orebokech.com>
+
+       * gnus.texi (Mail Folders, Mail Spool): Grammar fixes.
+
+2006-03-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (NoCeM): Mention gnus-use-nocem can also be a number.
+
+2006-03-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Fancy Mail Splitting): Improve sentences so as to be
+       easy to understand.
+
+2006-03-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi: Markup fix.
+       (Fancy Mail Splitting): Specify new feature.
+
+2006-03-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Fancy Mail Splitting): Improve descriptions about
+       partial-words matching.
+
+2006-03-07  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * emacs-mime.texi (Display Customization): Reword image/.* stuff.
+
+       * gnus.texi (Oort Gnus): Add note about `gnus-load'.
+       (MIME Commands): Fix mm-discouraged-alternatives.
+
+2006-03-06  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-news.el, gnus-news.texi: Update copyright.
+
+2006-03-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * xemacs.mak: Remove outdated file.  Use make.bat instead.
+
+       * gnus.texi (Oort Gnus): Add `mm-fill-flowed'.
+
+2006-02-09  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Mail Spool): nnml-use-compressed-files can be a
+       string.
+       (Gnus Versions): Add history beyond start of Oort.
+
+       * gnus-news.texi: Add nnml-use-compressed-files.
+
+2006-01-31  Romain Francoise  <romain@orebokech.com>
+
+       * message.texi: Update copyright year.
+
+2006-01-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * ps/Makefile.in (distclean): Remove Makefile.
+
+       * Makefile.in (almost-clean): Rename from clean.
+       (clean): Rename from veryclean.
+       (distclean): Use clean.
+       (pspackage): Use almost-clean.
+
+2006-01-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi: Update copyright.
+
+2006-01-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Article Washing): Additions.
+
+2006-01-08  Alex Schroeder  <alex@gnu.org>
+
+       * pgg.texi (Caching passphrase): Rewording.
+
+2006-01-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (RSS): Document nnrss-wash-html-in-text-plain-parts.
+
+2006-01-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Group Parameters): Fix description.
+       (RSS): Addition.
+
+2005-12-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Summary Post Commands): Fix function bound to `S O p'.
+
+2005-12-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * emacs-mime.texi (Display Customization): Add setting example to
+       mm-discouraged-alternatives.
+
+2005-12-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Gmane Spam Reporting): Fix
+       spam-report-gmane-use-article-number.  Add
+       spam-report-user-mail-address.
+
+2005-12-13  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-news.el (gnus-news-translate-file): Fix previous commit.
+
+       * gnus-coding.texi (Gnus Coding Style): Add `uudecode.el'.
+       (Gnus Maintainance Guide): Add ref to "Gnus Development".  Add
+       conventions about custom versions.
+
+2005-12-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (MIME Commands): Mention addition of
+       multipart/alternative to gnus-buttonized-mime-types and add xref
+       to mm-discouraged-alternatives.
+
+       * emacs-mime.texi (Display Customization): Mention addition of
+       "image/.*" and add xref to gnus-buttonized-mime-types in the
+       mm-discouraged-alternatives section.
+
+2005-12-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-news.el: Markup and description fixes and additions.
+
+2005-12-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * pgg.texi (User Commands): Fix description of pgg-verify-region.
+       (Selecting an implementation): Fix descriptions.
+
+2005-12-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-news.el: Update Copyright.
+       (gnus-news-translate-file): Avoid "*Note" at beginning of line.
+
+2005-12-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * emacs-mime.texi (Non-MIME): x-gnus-verbatim -> x-verbatim.
+
+2005-11-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.texi (Various Message Variables): Addition.
+
+2005-11-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.texi: Fix default values.
+
+2005-11-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.texi (Header Commands): Clarify descriptions of
+       message-cross-post-followup-to, message-reduce-to-to-cc, and
+       message-insert-wide-reply.
+       (Various Commands): Fix kindex for message-kill-to-signature;
+       clarify description of message-tab.
+
+2005-11-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.texi (Mailing Lists): Fix description about MFT.
+
+       * gnus.texi (Emacs Lisp): Use ~/.gnus.el instead of ~/.emacs.
+
+2005-11-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Slow Terminal Connection): Replace old description
+       with new one.
+
+2005-11-16  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Oort Gnus): Use ~/.gnus.el instead of ~/.emacs;
+       replace X-Draft-Headers with X-Draft-From.
+
+2005-11-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Various Various): Fix the default value of
+       nnheader-max-head-length.
+       (Gnus Versions): Fix typo.
+
+2005-11-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-coding.texi (Gnus Coding Style): Add MIME subsection.
+       (Gnus Maintainance Guide): Improvements.
+
+       * gnus.texi (Sorting the Summary Buffer): Replace 2005-10-29
+       change by a reference to `Group Parameters'.  Use `(not ...)' in
+       example instead of `lambda' expression.
+       (Group Parameters): Add simplified sorting example based on
+       example for `Sorting the Summary Buffer' from Jari Aalto
+       <jari.aalto@cante.net>.
+       (Example Methods): Add example for an indirect connection.
+
+2005-11-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (XVarious): Fix description of gnus-use-toolbar; add
+       new variable gnus-toolbar-thickness.
+
+2005-11-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Agent and flags): Add it to the detailmenu.
+
+2005-11-08  Kevin Greiner  <kevin.greiner@compsol.cc>
+
+       * gnus.texi (nntp-open-via-telnet-and-telnet): Fixed grammar.
+       (Agent Parameters): Updated parameter names to match code.
+       (Group Agent Commands): Corrected 'gnus-agent-fetch-series' as
+       'gnus-agent-summary-fetch-series'.
+       (Agent and flags): New section providing a generalized discussion
+       of flag handling.
+       (Agent and IMAP): Removed flag discussion.
+       (Agent Variables): Added 'gnus-agent-synchronize-flags'.
+
+2005-11-08  Romain Francoise  <romain@orebokech.com>
+
+       * gnus.texi (Exiting the Summary Buffer): Add new function
+       `gnus-summary-catchup-and-goto-prev-group', bound to `Z p'.
+
+2005-11-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (XVarious): Revert description of gnus-use-toolbar.
+
+2005-11-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (X-Face): Fix description.
+       (XVarious): Remove gnus-xmas-logo-color-alist and
+       gnus-xmas-logo-color-style; fix description of gnus-use-toolbar.
+
+2005-11-04  Ken Manheimer  <ken.manheimer@gmail.com>
+
+       * pgg.texi (User Commands): Document additional passphrase
+       argument for pgg-encrypt-*, pgg-decrypt-*, and pgg-sign-* functions.
+       (Backend methods): Likewise for corresponding pgg-scheme-* functions.
+
+2005-11-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Conformity): Fix typo.
+       (Customizing Articles): Document `first'.
+
+2005-11-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Group Parameters): Mention new variable
+       gnus-parameters-case-fold-search.
+       (Home Score File): Addition.
+
+2005-10-29  Sascha Wilde  <wilde@sha-bang.de>
+
+       * pgg.texi (How to use): Update the example to add autoload of
+       pgg-encrypt-symmetric-region.
+       (User Commands): Document pgg-encrypt-symmetric-region.
+       (Backend methods): Document pgg-scheme-encrypt-symmetric-region.
+
+2005-10-29  Jari Aalto  <jari.aalto@cante.net>
+
+       * gnus.texi (Sorting the Summary Buffer):
+       Add `gnus-thread-sort-by-date-reverse'.  Add example
+       host to different sorting in NNTP and RSS groups.
+
+2005-10-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-coding.texi: Split into nodes.
+       (Gnus Coding Style): Add flow-fill.el.
+
+2005-10-25  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-coding.texi (Dependencies): Add some text.
+       (Dependencies): Update encrypt.el.
+
+2005-10-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Document Groups): Remove duplicate item.
+
+2005-10-14  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Document Server Internals): Addition.
+
+2005-10-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (A note on namespaces): Fix RFC reference.
+
+2005-10-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (RSS): Fix key description.
+
+2005-10-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi: Emacs/w3 -> Emacs/W3.
+       (Browsing the Web): Fix description.
+       (Web Searches): Ditto.
+       (Customizing W3): Ditto.
+
+2005-10-07  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Maildir): Clarify expire-age and expire-group.
+
+2005-10-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-news.texi: Mention that the Lisp files are now installed in
+       .../site-lisp/gnus/ by default.
+
+2005-10-03  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-news.texi: Fix typo.
+
+2005-09-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-coding.texi: Added  some comments.
+
+       * message.texi (Insertion): Describe prefix for
+       message-mark-inserted-region and message-mark-insert-file.
+
+2005-09-28  Simon Josefsson  <jas@extundo.com>
+
+       * message.texi (IDNA): Fix.
+
+2005-09-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (NNTP): Remove nntp-buggy-select, nntp-read-timeout,
+       nntp-server-hook, and nntp-warn-about-losing-connection; fix
+       description of nntp-open-connection-function.
+       (Common Variables): Fix descriptions.
+
+2005-09-27  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * emacs-mime.texi (Non-MIME): Add Slrn-style verbatim marks and
+       LaTeX documents.  Describe "text/x-gnus-verbatim".
+
+2005-09-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Server Buffer Format): Document the %a format spec.
+
+2005-09-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Mail): Fix gnus-confirm-mail-reply-to-news entry.
+
+2005-09-21  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Blacklists and Whitelists)
+       (Blacklists and Whitelists, BBDB Whitelists)
+       (Gmane Spam Reporting, Bogofilter, spam-stat spam filtering)
+       (spam-stat spam filtering, SpamOracle)
+       (Extending the Spam ELisp package): Removed extra quote symbol for
+       clarity.
+
+2005-09-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (MIME Commands): Add gnus-article-save-part-and-strip,
+       gnus-article-delete-part and gnus-article-replace-part.
+       (Using MIME): Add gnus-mime-replace-part.
+
+       * gnus-news.texi: Add gnus-mime-replace-part and
+       gnus-article-replace-part.  Use @xref.
+
+2005-09-20  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-coding.texi: New file, from Reiner Steib
+       <reiner.steib@gmx.de>.
+
+2005-09-17  Romain Francoise  <romain@orebokech.com>
+
+       Update all files to specify GFDL version 1.2.
+
+       * doclicense.texi (GNU Free Documentation License): Update to
+       version 1.2.
+
+2005-09-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Finding the Parent): Fix description of how Gnus
+       finds article.
+
+2005-09-14  Jari Aalto  <jari.aalto@cante.net>
+
+       * gnus.texi (Advanced Scoring Examples): New exmples to teach how
+       to drop off non-answered articles.
+
+2005-09-11  Romain Francoise  <romain@orebokech.com>
+
+       * message.texi (Message Headers): Explain what
+       `message-alternative-emails' does in more detail.
+
+       * gnus.texi (Mail Spool): Mention that `nnml-use-compressed-files'
+       requires `auto-compression-mode' to be enabled.  Add new nnml
+       variable `nnml-compressed-files-size-threshold'.
+
+2005-09-07  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Sorting the Summary Buffer): Added
+       gnus-thread-sort-by-recipient.
+
+2005-09-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-news.texi: Fix reference.
+
+2005-09-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Mail Source Customization): Fix descriptions of
+       mail-source-incoming-file-prefix.
+
+       * message.texi (MIME): Describe mml-dnd-protocol-alist and
+       mml-dnd-attach-options.
+
+       * gnus-news.texi: Added reference.
+
+2005-09-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Choosing Variables): Fix descriptions.
+
+2005-08-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * emacs-mime.texi (time-date): Fix description of safe-date-to-time.
+
+2005-08-18  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * emacs-mime.texi (Handles): Remove duplicate item.
+       (Encoding Customization): Fix the default value for
+       mm-coding-system-priorities.
+       (Charset Translation): Emacs doesn't use mm-mime-mule-charset-alist.
+       (Basic Functions): Fix reference.
+
+2005-08-10  Romain Francoise  <romain@orebokech.com>
+
+       * gnus-news.texi: Mention new variable `message-yank-empty-prefix'.
+
+2005-08-09  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Charsets): Fj hierarchy uses iso-2022-jp.
+
+2005-08-08  Romain Francoise  <romain@orebokech.com>
+
+       * message.texi (Insertion Variables): Mention new variable
+       `message-yank-empty-prefix'.  Change `message-yank-cited-prefix'
+       documentation accordingly.
+
+2005-07-27  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Startup Files): Fix name of gnus-site-init-file.
+       Mention that gnus-init-file is not read when Emacs is invoked with
+       --no-init-file or -q.
+
+2005-07-20  Didier Verna  <didier@xemacs.org>
+
+       * gnus.texi (Email Based Diary): New. Proper documentation for the
+       nndiary back end and the gnus-diary library.
+
+2005-07-18  Romain Francoise  <romain@orebokech.com>
+
+       * gnus.texi (To From Newsgroups): Mention new variables
+       `gnus-summary-to-prefix' and `gnus-summary-newsgroup-prefix'.
+
+       * gnus-news.texi: Ditto.
+
+2005-06-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (NoCeM): gnus-nocem-verifyer defaults to pgg-verify.
+
+2005-06-23  Juanma Barranquero  <lekktu@gmail.com>
+
+       * gnus.texi (MIME Commands, Fancy Mail Splitting, Agent Visuals)
+       (Agent Variables):
+       * message.texi (Message Headers):
+       Texinfo usage fix.
+
+2005-03-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Makefile.in (gnus-booklet.dvi, gnus-booklet.pdf): Simplify.
+       (gnus-faq-texi): Renamed from gnus-faq.texi to avoid unsolicited
+       download.
+
+2005-03-29  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Makefile.in (gnus-booklet.dvi, gnus-booklet.pdf)
+       (gnus-refcard.dvi, gnus-refcard.pdf): New targets replacing
+       refcard.* and booklet.*.
+
+       * gnus-refcard.tex: Merged from refcard.tex and gnusref.tex.
+       Removed refcard.tex gnusref.tex booklet.tex bk-lt.tex bk-a4.tex.
+
+       * gnus-logo.eps: Renamed from gnuslogo-booklet.eps.
+       gnuslogo-refcard.eps: Removed.
+
+       * Makefile.in (gnus-faq.texi): Depend on xml2texi.*.  Fix sed
+       command.
+
+2005-03-23  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * Makefile.in (gnus-faq-full-update, gnus-faq-clean)
+       (gnus-faq.texi): New targets.
+       (distclean): Remove some gnus-faq.* files.
+
+       * xml2texi.sh: Mention requirements.
+
+       * xml2texi.scm (boilerplate): Add "Do not modify ...".
+
+       * gnus-faq.texi: Generated.
+
+2005-03-22  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-faq.texi: Generated from gnus-faq.xml using xml2texi.*.
+
+       * message.texi, gnus.texi: Update copyright.
+
+       * xml2texi.scm (+tag-for-gnus-faq-texi+): New variable.
+       (transform): Use it.  From Karl Pflästerer <sigurd@12move.de> with
+       minor modifications.
+       (boilerplate): Update copyright for the output file.
+
+2005-03-21  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * xml2texi.sh: Fix arch tag.
+
+2005-03-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * xml2texi.scm, xml2texi.sh: Added copyright.
+       (transform): Avoid redundant entries in @urefs.
+       (format-node): Don't insert optional arguments of @node.
+
+2005-03-20  Karl Pflästerer  <sigurd@12move.de>
+
+       * xml2texi.scm, xml2texi.sh: New files.  PLT Scheme program to
+       convert FAQ from xml to texi.
+
+2005-03-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Slow/Expensive Connection): Don't abbreviate "very".
+
+2005-02-14  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-news.texi: Add.
+
+2005-02-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Using MIME): gnus-mime-copy-part supports the charset
+       stuff; gnus-mime-inline-part does the automatic decompression.
+
+2005-02-08  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Spam ELisp Package Configuration Examples):
+       "training.ham" should be "training.spam".
+
+2005-02-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.texi (Mail Variables): Fix the default value for
+       message-send-mail-function.
+
+2005-02-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Optional Back End Functions): nntp-request-update-info
+       always returns nil exceptionally.
+
+2005-01-27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi: Some edits based on comments from David Abrahams.
+       Bump version numbers.
+
+2005-01-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (RSS): Fix the keystroke.
+
+2005-01-16  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Article Washing): Add libidn URL.  Suggested by
+       Michael Cook <michael@waxrat.com>.
+
+       * gnus-news.texi: Ditto.
+
+2005-01-16  Xavier Maillard  <zedek@gnu-rox.org>  (tiny change)
+
+       * gnus-faq.texi ([4.1]): Typo.
+
+2005-01-15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Topic Commands): Fix next/previous.
+
+2005-01-15  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Article Washing): Mention `W i'.
+
+       * gnus-news.texi: Mention De-IDNA washing.
+
+2005-01-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.texi (Reply): `message-reply-to-function' should return
+       a list.  Suggested by ARISAWA Akihiro <ari@mbf.ocn.co.jp>.
+
+2005-01-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * Makefile.in (.texi): Use LC_ALL instead of LANG.
+       (makeinfo): Ditto.
+
+2005-01-04  Jochen Küpper  <jochen@fhi-berlin.mpg.de>
+
+       * gnus.texi (Group Parameters): Slight extension of sieve
+       parameter description.
+
+2005-01-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-news.texi: Mention change new behavior of
+       `gnus-decay-scores'.  Added some references.
+
+       * gnus.texi (Score Decays): `gnus-decay-scores' can be a regexp
+       matching score files as well.
+       (Picons): Describe `gnus-picon-style'.
+
+2005-01-02  Romain Francoise  <romain@orebokech.com>
+
+       * gnus-news.texi: Mention the new method used to hide headers.
+       Remove duplicate item about `/ r'.  Add missing @code.
+
+       * message.texi (Message Headers): Mention that headers are hidden
+       using narrowing, and how to expose them.
+       Update copyright.
+
+2005-01-02  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-news.texi: Add.
+
+2004-12-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-news.texi: Addition.
+
+       * gnus.texi (RSS): Addition.
+
+2004-12-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * Makefile.in (.texi): Set LANG=C to avoid NLS translations.
+       (makeinfo): Ditto.
+
+2004-12-08  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnusref.tex: Mention `gnus-summary-limit-to-recipient' and
+       `gnus-summary-sort-by-recipient'.
+
+2004-12-08  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-faq.texi ([5.1]): Added missing bracket.
+
+       * message.texi (Various Message Variables): Mention that all mail
+       file variables are derived from `message-directory'.
+
+       * gnus.texi (Splitting Mail): Clarify bogus group.
+
+2004-12-07  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Filtering Spam Using The Spam ELisp Package)
+       (Spam ELisp Package Filtering of Incoming Mail)
+       (Spam ELisp Package Sorting and Score Display in Summary Buffer):
+       replace @code{spam.el} with @file{spam.el} where the file spam.el
+       is intended as the subject.
+
+2004-12-06  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-news.texi: Mention `gnus-summary-limit-to-recipient' and
+       `gnus-summary-sort-by-recipient'.
+
+       * gnus.texi (Filtering Spam Using The Spam ELisp Package): Index
+       `spam-initialize'.
+       (Limiting): Add `gnus-summary-limit-to-recipient'.
+       (Summary Sorting): Add `gnus-summary-sort-by-recipient'.
+
+2004-11-30  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Misc Article): Add, suggested by Reiner Steib
+       <reinersteib+gmane@imap.cc>.
+
+2004-11-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Finding the News): Markup fix.
+
+2004-11-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Finding the News): Add a note for NNTP marks.
+       Improved by Romain Francoise.
+
+2004-11-23  Romain Francoise  <romain@orebokech.com>
+
+       * gnus.texi (NNTP marks): New node.
+       (NNTP): Move NNTP marks variables to the new node.
+
+2004-11-21  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi, gnus-news.texi, pgg.texi, sasl.texi: backend -> back
+       end.
+
+       * gnus.texi (MIME Commands, Hashcash): Markup fix.
+
+2004-11-17  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi: replaced @file{spam.el} with @code{spam.el}
+       everywhere for consistency.
+       (Filtering Spam Using The Spam ELisp Package): admonish again.
+       (Spam ELisp Package Sequence of Events): this is Gnus, say so.
+       Say "regular expression" instead of "regex."  Admonish.  Pick
+       other words to sound better (s/so/thus/).
+       (Spam ELisp Package Filtering of Incoming Mail): mention
+       statistical filters.  Remove old TODO.
+       (Spam ELisp Package Sorting and Score Display in Summary Buffer):
+       new section on sorting and displaying the spam score.
+       (BBDB Whitelists): mention spam-use-BBDB-exclusive is not a
+       backend but an alias to spam-use-BBDB.
+       (Extending the Spam ELisp package): rewrite the example using the
+       new backend functionality.
+
+2004-11-16  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (NNTP): Mention nntp-marks-is-evil and
+       nntp-marks-directory, from Romain Francoise
+       <romain@orebokech.com>.
+
+2004-11-14  Magnus Henoch  <mange@freemail.hu>
+
+       * gnus.texi (Hashcash): New default value of
+       hashcash-default-payment.
+
+2004-10-26  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Hashcash): Fix URL.  Add pref to spam section.
+       (Anti-spam Hashcash Payments): No need to load hashcash.el now.
+
+2004-10-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (New Features): Add 5.11.
+
+       * message.texi (Resending): Remove wrong default value.
+
+       * gnus.texi (Mail Source Specifiers): Describe possible problems
+       of `pop3-leave-mail-on-server'.  Add `pop3-movemail' and
+       `pop3-leave-mail-on-server' to the index.
+
+2004-10-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Adaptive Scoring): Added gnus-adaptive-pretty-print.
+
+2004-10-15  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.texi (Canceling News): Add how to set a password.
+
+2004-10-10  Juri Linkov  <juri@jurta.org>
+
+       * gnus.texi (Top, Marking Articles): Join two menus in one node
+       because a node can have only one menu.
+
+2004-10-09  Juri Linkov  <juri@jurta.org>
+
+       * gnus.texi (Fancy Mail Splitting): Remove backslash in the
+       example of nnmail-split-fancy.
+
+2004-10-12  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-faq.texi ([5.9]): Improve code for reply-in-news.
+
+2004-10-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (X-Face): Revert 2004-02-17 change.
+       (Slow Machine): Ditto.
+
+2004-10-02  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (documentencoding): Add, to avoid warnings.
+
+2004-09-30  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-news.texi: Add.
+
+       * message.texi (Mail Headers): Add.
+
+       * gnus.texi (Hashcash): Fix.
+
+2004-09-29  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-news.texi: Add.
+
+2004-09-29  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Hashcash): changed location of library, also mention
+       that payments can be verified and fix the name of the
+       hashcash-path variable.
+
+2004-09-23  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-faq.texi ([5.12]): Use 5.10 instead of 5.10.0.
+
+2004-09-14  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi: Markup fixes.
+
+       * emacs-mime.texi (Display Customization): XEmacs -> Emacs.
+
+2004-09-11  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-news.texi: Mention text/dns.
+
+2004-09-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * texi2latex.el (latexi-translate-file): Support @copying and
+       @insertcopying.
+       (latexi-copying-text): New variable.
+       (latexi-copying): New function.
+       (latexi-insertcopying): New function.
+
+2004-09-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-news.texi: Fix typo in previous commit.
+
+       * gnus-news.el (gnus-news-makeinfo-switches): Add --no-validate to
+       allow unresolved references.
+
+       * gnus-news.texi: Use xref.  Add `gnus-picon-style'.
+
+       * Makefile.in (GNUS-NEWS): Depend on gnus-news.el.
+
+2004-09-02  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-news.texi: Comment out comment stuff.
+       Don't use xref's, GNUS-NEWS look wrong.
+       Add nntp marks stuff.
+       Add (copied from Oort Gnus GNUS-NEWS).
+
+       * Makefile.in (GNUS-NEWS): Move to "..".
+
+2004-09-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * infohack.el: Support @copying and @insertcopying for Emacs 21.3
+       and lesser and XEmacs.
+
+2004-08-31  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * emacs-mime.texi, gnus-faq.texi, gnus.texi, message.texi,
+       * pgg.texi, sieve.texi: Use @copying and @insertcopying.
+
+2004-08-22  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Mail Source Specifiers): Describe
+       `pop3-leave-mail-on-server'.
+
+2004-08-17  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (IMAP): Add comments about imaps synonym to imap in
+       netrc syntax.
+
+2004-08-15  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (IMAP): Add example.  Suggested and partially written
+       by Steinar Bang <sb@dod.no>.
+
+2004-08-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Posting Styles): Addition.
+
+2004-08-06  Simon Josefsson  <jas@extundo.com>
+
+       * gnus-news.el (gnus-news-header-disclaimer): Fix.
+
+       * gnus-news.texi: Add.
+
+2004-07-22  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * emacs-mime.texi (rfc2047): Update.
+
+2004-07-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Splitting Mail): Add nnmail-split-lowercase-expanded.
+       (Fancy Mail Splitting): Ditto.
+
+2004-07-02  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * emacs-mime.texi (Encoding Customization): Addition.
+
+2004-06-29  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * emacs-mime.texi (Encoding Customization): Add a note to the
+       mm-content-transfer-encoding-defaults entry.
+
+2004-06-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * emacs-mime.texi (Encoding Customization): Fix
+       mm-coding-system-priorities entry.
+
+2004-06-28  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Setting Process Marks): Fix `M P a' entry.
+
+2004-06-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Article Highlighting): Add
+       gnus-cite-ignore-quoted-from.
+
+2004-06-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.texi (Various Message Variables): Add.
+
+2004-06-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Mail Source Customization): Clarify
+       `mail-source-directory'.
+
+2004-05-28  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-faq.texi: Untabify.
+       ([6.3]): nnir.el is in contrib directory.
+
+       * message.texi (News Headers): Clarify how a unique ID is created.
+
+       * gnus.texi (Splitting Mail): Mention gnus-group-find-new-groups.
+
+2004-05-19  Andre Srinivasan  <andre@e2open.com>
+
+       * gnus.texi (Group Parameters): Added more on hooks.  (Small
+       change.)
+
+2004-05-19  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Oort Gnus): Mention new behavior of `F' and `R' when
+       the region is active.
+       (Article Display): Add `gnus-picon-style'.
+
+2004-05-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.texi (Various Commands): Add.
+
+2004-05-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (MIME Commands): Added
+       gnus-mime-display-multipart-as-mixed,
+       gnus-mime-display-multipart-alternative-as-mixed,
+       gnus-mime-display-multipart-related-as-mixed.
+
+2004-04-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (SpamAssassin backend): Add it to the detailmenu.
+
+2004-04-16  Florian Weimer  <fw@deneb.enyo.de>
+
+       * gnus.texi (Charsets): Point to relevant section in emacs-mime.
+
+2004-04-14  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus.texi (Agent Visuals): Referenced new F(etched) group line
+       format.
+       (Group Line Specification): Added F(etched) group line format.
+
+2004-04-12  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Indirect Functions): Add
+       nntp-open-via-rlogin-and-netcat.
+
+2004-04-11  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-news.texi: Add OPML.
+
+       * gnus.texi (RSS): do.
+
+2004-04-10  Jesper Harder  <harder@ifa.au.dk>
+
+       * emacs-mime.texi (Flowed text): Markup fix.
+
+2004-04-07  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Blacklists and Whitelists, BBDB Whitelists)
+       (Bogofilter, spam-stat spam filtering, SpamOracle): old incorrect
+       warning about ham processors in spam groups removed.
+
+2004-04-02  Teodor Zlatanov  <tzz@lifelogs.com>
+       From Hubert Chan <hubert@uhoreg.ca>
+
+       * gnus.texi (SpamAssassin backend): added new node about SpamAssassin.
+
+2004-03-29  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Spam ELisp Package Sequence of Events): Some clarifications.
+       (Spam ELisp Package Global Variables): More clarifications.
+
+2004-03-18  Helmut Waitzmann  <Helmut.Waitzmann@web.de>  (tiny change)
+
+       * gnus.texi (Various Summary Stuff): Fix the documentation for
+       gnus-newsgroup-variables.
+
+2004-03-18  Raymond Scholz  <ray-2004@zonix.de>  (tiny change)
+
+       * gnus.texi (Misc Article): Refer to `Summary Buffer Mode Line' in
+       the gnus-article-mode-line-format section.
+
+2004-03-18  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-news.texi: Addition.
+
+2004-03-08  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Category Syntax): Markup fix.
+
+2004-03-08  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (POP before SMTP): Addition.
+
+2004-03-05  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Spam ELisp Package Sequence of Events): Index.
+       (Mailing List): Typo.
+       (Customizing Articles): Add gnus-treat-ansi-sequences.
+       (Article Washing): Index.
+
+       * message.texi: Use m-dash consistently.
+
+       * emacs-mime.texi: do.
+
+2004-03-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (POP before SMTP): New node.
+
+2004-03-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (X-Face, Face): Add gnus-x-face and
+       gnus-face-properties-alist.
+
+2004-03-04  Jesper Harder  <harder@ifa.au.dk>
+
+       * texi2latex.el (latexi-translate-file): Support accents.
+
+       * gnus.texi: Don't use 8bit chars (except ¬).
+
+       * emacs-mime.texi: do.
+
+       * Makefile.in (.texi, makeinfo): Use --enable-encoding.
+
+       * gnus.texi: Move @documentencoding back, and change to latin-1.
+
+       * emacs-mime.texi: do.
+
+       * infohack.el (infohack): Support @documentencoding in Emacs 21.3.
+
+2004-03-03  Jesper Harder  <harder@ifa.au.dk>
+
+       * Makefile.in: Add gnus-news.
+
+       * texi2latex.el (latexi-translate): Add gnus-news.
+       (latexi-translate-file): Add @documentencoding.
+
+2004-03-03  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi: Enclose the iflatex section with iftex.
+       (Gnus Unplugged): Use pxref instead of xref.
+
+       * emacs-mime.texi: Enclose the iflatex section with iftex.
+
+2004-03-02  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * emacs-mime.texi: Wrapped documentencoding inside of iflatex as
+       documentencoding is not supported by infohack.
+
+       * gnus.texi: Wrapped documentencoding inside of iflatex as
+       documentencoding is not supported by infohack.
+       Changed file's character coding to utf-8 as the file contains
+       characters that can not be encoded using iso-8859-1.
+       (Gnus Unplugged): Reference gnus-agent variable.
+       (Agent Variables): Added gnus-agent.
+
+
+2004-02-17  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (X-Face): Add uncompface-use-external.
+       (Slow Machine): Ditto.
+
+2004-02-06  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-news.texi: dnd attachments.
+
+       * message.texi (MIME): do.
+
+2004-02-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Batching Agents): Fixed typo in example.  Reported
+       by Hiroshi Fujishima <pooh@nature.tsukuba.ac.jp>.
+
+2004-01-30  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi: Set documentencoding.
+
+       * emacs-mime.texi: do.
+
+2004-01-27  Simon Josefsson  <jas@extundo.com>
+
+       * emacs-mime.texi (Flowed text): Add.
+
+2004-01-23  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Spam ELisp Package Filtering of Incoming Mail):
+       Mention spam-split does not modify incoming mail.
+
+2004-01-23  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (GroupLens): Remove.
+
+2004-01-22  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Spam ELisp Package Sequence of Events): Fix typo.
+
+2004-01-21  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus.texi (Outgoing Messages, Agent Variables): Add
+       gnus-agent-queue-mail and gnus-agent-prompt-send-queue.
+       Suggested by Gaute Strokkenes <gs234@srcf.ucam.org>
+
+       * gnus.texi (agent-disable-undownloaded-faces): Replaced with
+       agent-enable-undownloaded-faces.
+
+2004-01-17  Jesper Harder  <harder@ifa.au.dk>
+
+       * sieve.texi (Manage Sieve API): nil -> @code{nil}.
+
+       * pgg.texi (User Commands, Backend methods): do.
+
+       * gnus.texi (Debugging IMAP): Fix.
+       (Thwarting Email Spam): Avoid overfull hboxes in printed
+       version.  Markup fixes.
+
+2004-01-12  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (The problem of spam): fixed so many countries and
+       continents are used as examples of why blocking by country blocks
+       is a bad idea.
+
+2004-01-11  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (The problem of spam): Fix, reported by Cheng Gao
+       <chenggao@cyberhut.org> and suggested by Richard Hoskins
+       <rmh@apk.net>  (tiny change).
+
+2004-01-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * dir: Add SASL.
+
+       * sasl.texi: Markup fixes.
+
+       * gnus.texi (Fancy Mail Splitting, SpamAssassin)
+       (Spam ELisp Package Sequence of Events)
+       (Spam ELisp Package Global Variables)
+       (Spam ELisp Package Configuration Examples): do.
+
+2004-01-07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Summary Mail Commands): S D e.
+
+2004-01-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Limiting): Add gnus-summary-limit-to-replied.
+
+       * gnusref.tex: do.
+
+2004-01-06  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (SpamOracle): Fixed typo.
+       (Article Washing): Add `gnus-article-treat-ansi-sequences'.
+
+       * gnus-news.texi, gnus-news.el: New files.
+
+       * Makefile.in: Use `gnus-news.*' to create GNUS-NEWS.
+
+       * gnus.texi (No Gnus): New node.  Includes `gnus-news.texi'.
+
+2004-01-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi: Fix the last commit.
+
+2004-01-05  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Top): Add SASL.
+       * texi2latex.el (latexi-translate): Do sasl.
+
+       * pgg.texi (Caching passphrase): Fix PGG passphrase caching
+       section.
+
+       * sasl.texi: New file.
+       * Makefile.in: Add sasl.texi.
+
+2004-01-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Emacsen): Bump numbers.
+
+2004-01-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Spam ELisp Package Configuration Examples): Markup fixes.
+
+2004-01-03  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Spam ELisp Package Sequence of Events): explain more
+       about the sequence of events and what happens with read-only
+       backends.
+       (Spam ELisp Package Global Variables): explain what happens with
+       read-only backends.
+       (Spam ELisp Package Configuration Examples): added Reiner Steib
+       and Ted Zlatanov's setups.
+
+2004-01-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * emacs-mime.texi (Display Customization): Add mm-enable-external.
+
+2004-01-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Category Syntax):
+       gnus-agent-cat-enable-undownloaded-faces.
+
+2004-01-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.texi, gnus.texi, gnus-faq.texi: Update copyright.
+
+       * gnus-faq.texi ([5.12]): Fix code example for FQDN in Message-Ids.
+
+       * message.texi (Message Headers): Add message-header-synonyms.
+
+       * gnus.texi (Other modes): New node.
+       (Oort Gnus): Refer to the above in "Dired integration".
+
+2004-01-02  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Top): updated menu with new manual nodes.
+       (The problem of spam): more ranting.
+       (Anti-Spam Basics): "spammers are wise to [filtering on From:]".
+       (SpamAssassin): mention spam.el.
+       (Hashcash): do not a sentence end proposition with
+       (Filtering Spam Using The Spam ELisp Package): more and better
+       explanation, took lots of information out into subsections.
+       (Spam ELisp Package Sequence of Events)
+       (Spam ELisp Package Filtering of Incoming Mail)
+       (Spam ELisp Package Global Variables): new or updated content all
+       around.
+       (Spam ELisp Package Configuration Examples): promised new
+       section, empty for now.
+       (Blacklists and Whitelists, BBDB Whitelists)
+       (Gmane Spam Reporting, Bogofilter, spam-stat spam filtering)
+       (SpamOracle): mention that spam/ham processor variables are being
+       obsoleted.
+       (Extending the Spam ELisp package): add some new documentation
+       for adding a new backend to spam.el.
+
+2004-01-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Foreign Groups): Add `gnus-group-read-ephemeral-group'.
+       (Oort Gnus): Ditto.
+
+2004-01-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.texi (Key Index): Untabified.
+
+       * gnus.texi (RSS): kindex.
+
+2003-12-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Summary Score Commands): Add `f' to
+       `gnus-score-find-trace'.
+       (Score File Editing): Added `V t'.
+
+2003-12-31  Steve Youngs  <sryoungs@bigpond.net.au>
+
+       * gnus.texi (XEmacs): Update list of Gnus XEmacs package
+       requirements.
+
+2003-12-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Canceling and Superseding): Mention `Cancel-Lock'.
+
+2003-12-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Maildir): Filled.
+       (Key Index): Untabified.
+
+2003-12-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Group Parameters): Clarification.
+
+2003-12-29  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Agent Variables): Add.
+
+2003-12-23  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Oort Gnus): Mention change of `e' in draft groups.
+
+2003-12-15  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Group Parameters): Clarify.
+
+2003-12-11  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus.texi (Agent Parameters): Added references in Topic and
+       Group Parameters.  Added gnus-agent-cat-disable-undownloaded-faces
+       to the list of documented agent parameters.
+
+2003-12-11  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.texi (Mailing Lists): Fix typo.
+
+2003-12-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Fancy Mail Splitting): Close paren of a Lisp function.
+       (SpamAssassin): Ditto.
+
+2003-12-04  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (SpamAssassin, Fancy Mail Splitting): add
+       save-restriction before (widen) in the example.  From Kevin Ryde
+       <user42@zip.com.au>.
+
+2003-12-03  Simon Josefsson  <jas@extundo.com>
+
+       * emacs-mime.texi (Flowed text): Fix.
+
+2003-12-02  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Agent Variables): Fix.
+
+2003-12-01  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi: Add missing mode to some @kindex'es.
+
+2003-11-30  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (RSS): Add nnrss-use-local.
+       (Foreign Groups): Add `G R'.
+
+2003-11-29  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnusref.tex (subsection*{Notes}): Add `G R'.
+
+2003-11-25  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Hiding Headers): Update.
+
+2003-11-20  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Debugging IMAP): minor corrections.
+
+2003-11-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Finding the Parent): nnml does supports fetching by
+       MID.
+
+2003-11-20  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Debugging IMAP): Add.
+
+2003-11-19  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Score Decays): Update the gnus-decay-score function.
+
+2003-11-17  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Troubleshooting): Update.
+
+2003-11-03  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Filtering Spam Using The Spam ELisp Package): added
+       some clarifications.
+
+2003-10-30  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Fancy Mail Splitting): added mention of
+       nnmail-split-fancy-match-partial-words.
+
+2003-10-30  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Slashdot, SpamAssassin, Score File Format): Fix
+       overfull hbox.
+       (Topic Parameters): @group.
+       (Slashdot): Fix.
+
+2003-10-27  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Filtering Spam Using The Spam ELisp Package): added
+       example of using a string as a parameter to spam-split in order
+       to override the default spam-split-group value.
+
+2003-10-27  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnusref.tex (subsection*{Notes}): do.
+
+       * gnus.texi (Exiting the Summary Buffer): Add keybinding.
+
+2003-10-23  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * emacs-mime.texi: Markup: Use @acronym for MML and MIME.
+
+       * message.texi: Ditto.
+
+       * gnus.texi: Ditto.
+
+2003-10-23  Simon Josefsson  <jas@extundo.com>
+
+       * emacs-mime.texi (MML Definition): Add format.
+
+2003-10-22  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Filtering Spam Using The Spam ELisp Package):
+       changed to use the new spam-initialize function.
+
+2003-10-19  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.texi (Mailing Lists): Add Mail-Followup-To to index.
+
+       * gnus.texi (Group Parameters): Add Mail-Followup-To to index.
+       (Emacsen): Fixed typo.
+       (Oort Gnus): Mention message-forward-show-mml change (Sync with
+       GNUS-NEWS).
+
+2003-10-12  Adrian Aichner  <adrian@xemacs.org>
+
+       * gnus.texi (Mail Source Specifiers): uref fixes.
+
+2003-10-18  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Group Mail Splitting)
+       (Filtering Spam Using The Spam ELisp Package): Markup fixes.
+
+       * message.texi (Security): @url -> @uref.
+
+2003-10-18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi: Define gnusasis and gnusurl.
+
+2003-10-12  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Group Mail Splitting): Markup fix.
+
+2003-10-03  Jesper Harder  <harder@ifa.au.dk>
+
+       * emacs-mime.texi (Files and Directories): Update.
+
+2003-10-02  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Filtering Spam Using The Spam ELisp Package): added
+       spam-process-ham-in-spam-groups and
+       spam-process-ham-in-nonham-groups variable descriptions.
+
+2003-10-01  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.texi (Various Message Variables): Typo.
+
+       * gnus.texi (Oort Gnus): Typo.
+       (Filtering Spam Using The Spam ELisp Package): Just remember,
+       kids: There is no 'c' in 'supersede'.
+
+2003-09-27  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.texi (Reply): Fix typo.
+
+2003-09-22  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Fancy Mail Splitting, SpamAssassin): corrected fancy
+       split example to use current buffer, mentioned
+       nnimap-split-download-body.
+
+2003-09-22  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi, gnus-faq.texi, message.texi: gnus -> Gnus.
+
+       * message.texi: Fixes.
+
+2003-09-20  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Fancy Mail Splitting): Make split-on-body work for
+       respooling.  Suggested by Harald Maier <maierh@myself.com>.
+       (Fancy Mail Splitting): Reformat.
+
+2003-09-15  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Posting Styles): Fix typo.  @itemize attribute names.
+
+2003-09-14  Jesper Harder  <harder@ifa.au.dk>
+
+       * pgg.texi (Selecting an implementation, Caching passphrase)
+       (Initializing): Markup fix.
+
+2003-09-12  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Summary Buffer Lines): Formatting fix.
+
+2003-09-03  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Creating a Virtual Server): Use nnml for the example.
+       nnspool doesn't work on ms-windows due to file name restrictions.
+
+2003-08-29  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Gmane Spam Reporting): added explanation of
+       spam-report-gmane-use-article-number.
+
+2003-08-25  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Customizing Articles): xface -> x-face.
+
+2003-08-20  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (GroupLens): Move text around.
+
+2003-08-16  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Searching for Articles): Fix example.
+
+2003-08-08  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Kibozed Groups): Fix.
+
+2003-08-04  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Group Parameters): Add expiry-target.
+       (Archived Messages): Layout fix.
+
+2003-07-22  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Top): Menu fixes and additions.
+
+2003-07-19  Jesper Harder  <harder@ifa.au.dk>
+
+       * emacs-mime.texi (Encoding Customization): Fix.
+       (MML Definition): Typo.
+
+2003-07-17  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Sorting the Summary Buffer): Index.
+
+2003-07-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-faq.texi ([3.8]): Fixed example.
+
+2003-07-14  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Filtering Spam Using The Spam ELisp Package):
+       mentioned the spam-install-hooks mess.
+
+2003-07-11  Matthias Andree  <ma@dt.e-technik.uni-dortmund.de>  (tiny change)
+
+       * gnus.texi (Splitting in IMAP): Typos.
+
+2003-07-11  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Splitting in IMAP): Mention Sieve.
+
+2003-07-10  Simon Josefsson  <jas@extundo.com>
+
+       * message.texi (Security): Discuss the PGP 2.x compatibility
+       problem.
+
+2003-06-24  Jesper Harder  <harder@ifa.au.dk>
+
+       * sieve.texi (Sieve Mode): Formatting fix.
+
+       * gnus.texi (Agent Basics, Group Parameters, Quassia Gnus): do.
+
+2003-06-24  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Summary Mail Commands): Make note of
+       Mail-Followup-To.
+
+2003-06-23  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi: Formatting fixes.
+
+2003-06-22  Simon Josefsson  <jas@extundo.com>
+
+       * message.texi (Security): Mention S/MIME passphrases.
+
+2003-06-20  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi: Add @command.
+
+       * texi2latex.el (latexi-translate-file): Add @command and @:.
+
+       * gnus.texi (Face): Use @uref.
+
+2003-06-19  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Sieve Commands, Agent Basics, SpamOracle): @xref
+       fixes.
+
+2003-06-18  Didier Verna  <didier@xemacs.org>
+
+       * gnus.texi (Face): New node.
+       * gnus.texi (Article Display): Reference it.
+       * gnus.texi (Customizing Articles): Ditto.
+       * gnus.texi (Image Enhancements): Put the Face node into the menu.
+
+2003-06-17  Kai Großjohann  <kai.grossjohann@gmx.net>
+
+       * gnus.texi (Splitting Mail): Add "splitting" entry and concept
+       index entries.  Small patch from Karl Pflästerer
+       <sigurd@12move.de>.
+
+2003-06-15  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Daemons): Fixed typo.
+
+2003-06-15  Kai Großjohann  <kai.grossjohann@gmx.net>
+
+       * message.texi (Message Headers): Extend
+       `message-subject-re-regexp' example.  From Niklas Morberg
+       <niklas.morberg@axis.com>.
+
+2003-06-11  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Bogofilter): revise docs to mention threshold is now
+       user-controllable.
+
+2003-06-10  Jesper Harder  <harder@ifa.au.dk>
+
+       * emacs-mime.texi: Use two spaces consistently to end sentences.
+
+       * message.texi: do.
+
+       * gnus.texi: do.
+
+2003-06-09  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Filtering Spam Using The Spam ELisp Package): new
+       SpamOracle node.
+       (SpamOracle): document new SpamOracle code.
+
+2003-06-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Article Buttons, Splitting in IMAP)
+       (Category Syntax, Picons): Preemptive strike by
+       alt.possesive.its.has.no.apostrophe.
+
+2003-06-03  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Fancy Mail Splitting): Explain some entries in
+       nnmail-split-abbrev-alist.
+
+2003-05-17  Adrian Aichner  <adrian@xemacs.org>
+
+       * emacs-mime.texi (Charset Translation): Ruthless typo fixing.
+       * gnus.texi (Top): Ditto.
+       * gnus.texi (Selecting a Group): Ditto.
+       * gnus.texi (Delayed Articles): Ditto.
+       * gnus.texi (Hiding Headers): Ditto.
+       * gnus.texi (Getting Mail): Ditto.
+       * gnus.texi (Comparing Mail Back Ends): Ditto.
+       * gnus.texi (IMAP): Ditto.
+       * gnus.texi (Required Back End Functions): Ditto.
+       * gnusref.tex (MIMESummary): Ditto.
+       * message.texi (Message Headers): Ditto.
+       * message.texi (Mail Variables): Ditto.
+       * pgg.texi (Prerequisites): Ditto.
+       * pgg.texi (Architecture): Ditto.
+       * pgg.texi (Backend methods): Ditto.
+       * sieve.texi (Managing Sieve): Ditto.
+
+2003-05-17  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnusref.tex (subsection*{Notes}): Fix.
+
+2003-05-13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Anti-Spam Basics): Removed mention of gnus-junk.
+
+2003-05-13  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Agent Variables, Score File Format)
+       (Troubleshooting, Editing IMAP ACLs, Conformity): a -> an.
+
+       * message.texi (Insertion Variables): do.
+
+2003-05-13  Niklas Morberg  <niklas.morberg@axis.com>  (tiny change)
+
+       * gnus.texi (IMAP, Agent and IMAP, Oort Gnus): s/a/an/.
+
+2003-05-12  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus.texi (Agent Visuals): Add.
+
+2003-05-09  Simon Josefsson  <jas@extundo.com>
+
+       * pgg.texi (Default user identity): Add.
+
+2003-05-08  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Selecting a Group): Mention nil value
+       gnus-large-newsgroup.
+
+2003-05-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (MIME Commands): Fix typo.
+
+2003-05-05  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnusref.tex: Additions.
+
+       * gnus.texi (Oort Gnus): Fix typo.
+
+2003-05-03  Kai Großjohann  <kai.grossjohann@gmx.net>
+
+       * gnus.texi (Agent Basics): Explain that some servers can be
+       agentized, whereas others aren't.
+
+2003-05-01  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Oort Gnus): Add prefix limit feature.
+       (Oort Gnus): Fix last commit.
+
+2003-05-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Emacsen): Update.
+
+2003-05-01  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (IMAP): Document nnimap-need-unselect-to-notice-new-mail.
+
+2003-05-01  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Wide Characters): Proportional -> fixed width.
+
+       * texi2latex.el (latexi-translate-file): Add @syncodeindex.
+
+       * gnus.texi: Markup and formatting improvements.
+       Use @syncodeindex for merging indexes to get the same font for
+       @defvar and @vindex entries.  Be more consistent about the case
+       of index entries.
+
+
+2003-04-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Top, Appendices): Fixed Gnus FAQ entry.
+
+       * gnus-faq.texi: Wrap long lines in menus.  Index.
+
+       * gnus.texi (Image Enhancements): Mention missing images support
+       of Emacs on MS Windows.
+       (Oort Gnus): Mention Gnus FAQ.
+
+2003-04-30  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Filtering Spam Using The Spam ELisp Package): revised
+       documentation.
+       (Gmane Spam Reporting, Anti-spam Hashcash Payments): new sections.
+
+2003-04-30  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Oort Gnus): New features in Gnus 5.10 from GNUS-NEWS.
+
+2003-04-30  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Filtering Spam Using The Spam ELisp Package): Index.
+       Add gnus-spam-mark.
+       (Various Summary Stuff): Add gnus-summary-display-arrow.
+
+       * gnus.texi: Fix typos.
+
+2003-04-27  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Group Parameters): Fix markup.
+       (Web Archive): Ditto.
+
+2003-04-27  Jesper Harder  <harder@ifa.au.dk>
+
+       * texi2latex.el (latexi-translate-file): Support @display,
+       @group, @smallexample, @subsubheading.
+
+       * gnus.texi, gnus-faq.texi: Fix some of the worst overfull and
+       underfull hboxes.
+
+       * message.texi, gnus.texi: Use the second arg to @uref where it
+       makes sense to make HTML and PDF output look nicer.
+
+2003-04-26  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus-faq.texi: Make it compile in the LaTeX version.  Remove
+       redundant entries in @urefs.
+       (FAQ - Glossary): Remove the final @bye since it breaks the Gnus
+       manual.
+       ([1.2]): @subsection -> @subheading.
+
+       * texi2latex.el (latexi-translate-file): Support @r, @env,
+       @heading, @subheading, @TeX.
+
+       * gnus.texi, message.texi, emacs-mime.texi: Markup improvements
+       and fixes.
+
+2003-04-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Selecting a Group): Add gnus-large-ephemeral-newsgroup.
+       (Filling In Threads): Add gnus-fetch-old-ephemeral-headers.
+       (Terminology): Index.
+
+2003-04-22  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi: nil -> @code{nil}.  Capitalize "Rmail" and "Babyl"
+       consistently.
+
+2003-04-22  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-faq.texi: Allow inclusion in `gnus.texi' again.
+
+2003-04-21  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus-faq.texi: New, the Gnus FAQ from http://my.gnus.org/FAQ.
+       From Frank Schmitt <ich@frank-schmitt.net>.
+
+       * gnus.texi (Server Variables): Added server parameters and index.
+
+2003-04-21  Kai Großjohann  <kai.grossjohann@gmx.net>
+
+       * gnus.texi (Group Parameters): Pointer to
+       gnus-newsgroup-variables.
+
+2003-04-20  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Summary Buffer Lines): Add
+       gnus-sum-thread-tree-false-root.
+
+2003-04-15  Michael Shields  <shields@msrl.com>
+
+       * gnus.texi (Group Parameters, Hiding Headers): Document that
+       the broken-reply-to group parameter now also affects header
+       hiding.
+       * gnus.texi (Summary Mail Commands): Suggest setting the
+       broken-reply-to parameter if you find yourself using `B r'.
+
+2003-04-16  Simon Josefsson  <jas@extundo.com>
+
+       * emacs-mime.texi (MML Definition): Add sender tag.
+
+2003-04-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Group Line Specification): Add.
+
+2003-04-13  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Security): Add text about PGP key snarf.
+
+2003-04-13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Misc Article): Addition.
+
+2003-04-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.texi (Message Headers): Addition.
+
+2003-04-12  Jesper Harder  <harder@ifa.au.dk>
+
+       * emacs-mime.texi (Encoding Customization): Update default for
+       mm-body-charset-encoding-alist.
+
+2003-04-08  Jesper Harder  <harder@ifa.au.dk>
+
+       * emacs-mime.texi (Non-MIME): Add diff.
+
+2003-04-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.texi (Security): Fix typo.
+
+2003-04-06  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi: Change ~/.gnus and .gnus.el to ~/.gnus.el.
+
+2003-04-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Gnus Versions): Index.
+       (Summary Score Commands): Decribe keys in `*Score Trace*' buffer.
+
+2003-04-01  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Article Button Levels): Added
+       `gnus-button-ctan-directory-regexp'.
+
+2003-04-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Indirect Functions): Fix examples for
+       nntp-via-rlogin-command-switches.
+
+2003-03-31  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Article Button Levels): New node.
+       (Article Buttons): Additions.
+
+2003-03-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Exiting Gnus): Removed gnus-unload.
+
+2003-03-31  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (IMAP): Add.
+
+2003-03-27  Paul Jarc  <prj@po.cwru.edu>
+
+       * gnus.texi (Comparing Mail Back Ends): Note nnmaildir's
+       incompatibilities more prominently.
+
+2003-03-27  Paul Jarc  <prj@po.cwru.edu>
+
+       * gnus.texi (Maildir): Note nnmail-expiry-target incompatibility.
+
+2003-03-27  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Adaptive Scoring): Fix.
+
+2003-03-23  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Direct Functions, Common Variables)
+       (Mail Source Specifiers, IMAP): Add TLS wherever SSL is mentioned
+       now.
+
+2003-03-23  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Group Information, Article Washing)
+       (Formatting Fonts, Group Parameters): Fix external xrefs.
+
+       * message.texi (Mailing Lists): do.
+
+2003-03-22  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Troubleshooting): Fix typo.
+       (Drafts): Mention how to restore special property, suggested by
+       Florian Weimer <fw@deneb.enyo.de>.
+
+2003-03-19  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Misc Article): Add.
+       (Agent Basics): Fix makeinfo warnings.
+
+       * message.texi (IDNA): New.
+
+2003-03-18  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus.texi (Gnus Unplugged): Refer to new agent Group/Topic
+       parameters.
+       (Category Syntax): New description.
+       (Category Buffer): New command.
+       (Category Variables): New variables.
+       (Agent as Cache): Expanded description.
+       (Agent Expiry): Expanded description.
+       (Agent Variables): Fixed and new descriptions.
+
+       * infohack.el (batch-makeinfo): Provide local implementation of
+       subst-char-in-region as the built-in implementation is unreliable
+       on Windows XP (Intermittent failure results in build looping
+       forever).
+
+2003-03-18  Paul Jarc  <prj@po.cwru.edu>
+
+       * gnus.texi (Maildir): Replace create-directory with
+       target-prefix.
+
+2003-03-18  Paul Jarc  <prj@po.cwru.edu>
+
+       * gnus.texi (Maildir): More info for expire-group; add
+       distrust-Lines:.
+
+2003-03-17  Paul Jarc  <prj@po.cwru.edu>
+
+       * gnus.texi (Comparing Mail Back Ends): nnmaildir fixes.
+
+2003-03-17  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Using MIME): Added gnus-mime-delete-part.
+
+2003-03-17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Required Back End Functions): Add.
+
+2003-03-17  Frank Haun  <pille3003@fhaun.de>  (tiny change)
+
+       * pgg.texi: Fix setfilename.
+
+2003-03-09  Paul Jarc  <prj@po.cwru.edu>
+
+       * gnus.texi (Top): Added menu item for Maildir node.
+
+2003-03-11  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Paging the Article): Addition.
+
+2003-03-10  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Customizing Articles): Additions.
+
+2003-03-09  Paul Jarc  <prj@po.cwru.edu>
+
+       * gnus.texi (Maildir): New node.
+
+2003-03-08  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnusref.tex: Update.
+
+2003-03-03  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Mail and Post): Updated `gnus-user-agent'.
+       (Mail Source Customization): Added `mail-source-delete-incoming'
+       and `mail-source-delete-old-incoming-confirm'.
+
+2003-03-01  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Troubleshooting): Fix typo.
+       (Group Parameters): Markup fix.
+       (Article Hiding, Splitting Mail, Fancy Mail Splitting)
+       (Document Server Internals, Score Variables, Adaptive Scoring)
+       (X-Face, Hashcash): do.
+
+2003-02-28  Vasily Korytov  <deskpot@myrealbox.com>
+
+       * gnus.texi: New values, 'to-list and 'cc-list, for
+       gnus-boring-article-headers.
+
+2003-02-28  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Extending the spam elisp package): added mention of
+       spam-list-of-statistical-checks.
+
+2003-02-27  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi: Remove the dependence on ssl.el.
+
+2003-02-26  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.texi (Mail Variables): Add
+       message-sendmail-envelope-from.
+
+2003-02-24  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Mail and Post): Added `gnus-user-agent', removed
+       `gnus-version-expose-system'.
+
+2003-02-24  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi: Markup fixes.
+
+       * message.texi: do.
+
+       * emacs-mime.texi: do.
+
+2003-02-20  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.texi (News Headers): Update description of Message-ID.
+
+2003-02-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Startup Files): Addition.
+
+2003-02-22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Mail Source Specifiers): Addition.
+
+2003-02-22  Jesper Harder  <harder@ifa.au.dk>
+
+       * emacs-mime.texi (Files and Directories): New node.
+
+2003-02-21  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Mailing List): Fix.
+
+       * gnus.texi: Markup fixes.
+
+2003-02-18  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Article Washing): Mention `g'.
+       (Customizing Articles): Added cross reference.
+
+2003-02-12  Michael Shields  <shields@msrl.com>
+
+       * gnus.texi (Paging the Article): Document
+       gnus-article-boring-faces.
+       (Choosing Commands): Explain that SPACE in the summary buffer
+       is used for both selecting and scrolling.
+
+       * gnus.texi (Article Keymap): Say that SPACE and DEL in the
+       summary buffer are the same as switching to the article buffer
+       and using SPACE and DEL; since now that is the case.
+
+2003-02-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Topic Commands): Addition.
+
+2003-02-07  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (BBDB Whitelists, Blacklists and Whitelists):
+       corrected existing docs, added spam-use-whitelist-exclusive and
+       spam-use-BBDB-exclusive to list of variables.
+
+2003-02-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (The problem of spam): Don't use @email for examples
+       -- it creates a mailto-link in HTML and PDF.
+
+2003-02-07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Mail Source Customization): Addition.
+
+2003-02-04  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.texi (Mail Variables): Added index entry for
+       `message-send-mail-partially-limit'.
+
+2003-01-30  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Batching Agents): Index.
+       (Agent Commands): do.
+       (Delayed Articles): do.
+       (Drafts): do.
+       (Web Archive): do.
+       (Article Washing): do.
+       (Slave Gnusae): do.
+       (Agent Basics): do.
+       (Exiting Gnus): do.
+       (Article Date): do.
+       (X-Face): do.
+       (Exiting the Summary Buffer): do.
+       (Charsets): do.
+       (Mail Group Commands): do.
+
+       * gnus.texi: Mark-up fixes.
+
+2003-01-27  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi: replace `H' mark with `$' mark.
+       (Blackholes): add spam-blackhole-good-server-regex variable.
+
+2003-01-26  Simon Josefsson  <jas@extundo.com>
+
+       * sieve.texi (Installation): Extension .sv is also used.
+
+2003-01-26  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Article Backlog): Update.
+
+2003-01-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (NNTP): Addition.
+
+2003-01-23  Teodor Zlatanov  <tzz@bwh.harvard.edu>
+
+       * gnus.texi (Regular Expressions Header Matching): documentation
+       for new spam splitting functionality.
+
+2003-01-23  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Signing and encrypting): Index.
+       (Smileys): Update.
+       (Toolbar): Move to XVarious because it's XEmacs specific.
+
+2003-01-22  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Picons): Update.
+
+2003-01-22  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus.texi (Agent Expiry, Agent Variables): Don't use @pxref for
+       index entries.
+
+2003-01-22  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (IMAP): Add.
+       (Expiring in IMAP): Typo fixes.
+
+2003-01-22  Kevin Greiner  <kgreiner@xpediantsolutions.com>
+
+       * gnus.texi (Agent Regeneration): New node.
+       (gnus-select-article-hook): clarified.
+       (gnus-downloaded-mark): Added definition.
+       (gnus-undownloaded-mark): Updated definition to reference the new
+       %O spec.
+       (gnus-agent-catchup): Identified articles that are NOT marked as read.
+       (gnus-agent-fetch-group): New command.
+       (gnus-agent-fetch-series): New command.
+       (Agent Expiry): Added comment to document that
+       gnus-request-expire-articles may invoke gnus-agent-expire.
+       (gnus-agent-mark-unread-after-downloaded): New variable.
+       (gnus-agent-consider-all-articles): New variable.
+       (gnus-agent-max-fetch-size): New variable.
+
+2003-01-22  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnusref.tex (subsection*{Notes}): do.
+
+       * gnus.texi (Article Hiding): Remove gnus-article-hide-pgp.
+       (Customizing Articles): Remove gnus-treat-strip-pgp.
+
+2003-01-21  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Various Summary Stuff): Add
+       gnus-summary-display-while-building.
+       (Group Parameters): Index gnus-parameters.
+       (Startup Files): Index gnus-site-init-file.
+
+2003-01-20  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Summary Buffer Lines): Additions to %B.
+
+       * gnus.texi: Markup fixes: use @code for nil and t, use @file for
+       files.
+
+       * message.texi: do.
+
+       * emacs-mime.texi: do.
+
+2003-01-19  Jesper Harder  <harder@ifa.au.dk>
+
+       * dir (File): Add pgg.
+
+       * gnus.texi (Selecting a Group): Index gnus-auto-select-subject.
+
+       * emacs-mime.texi (Display Customization):
+       Add mm-keep-viewer-alive-types.
+
+2003-01-16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Summary Agent Commands): Addition.
+
+2003-01-16  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Filtering Spam Using The Spam ELisp Package):
+       clarified syntax of gnus-spam-process-destinations and
+       gnus-ham-process-destinations variables.
+       (Extending the spam elisp package): fixed typo in node name.
+       (Bogofilter): new functionality and variables noted.
+       (Filtering Spam Using The Spam ELisp Package): added mention of
+       nnimap-split-download-body.
+
+2003-01-15  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi: Don't use `path' in some cases.
+       From the GNU coding standards:
+
+           Please do not use the term ``pathname'' that is used in Unix
+           documentation; use ``file name'' (two words) instead.  We use
+           the term ``path'' only for search paths, which are lists of
+           directory names.
+
+       * message.texi: Ditto.
+
+2003-01-15  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (X-Face): Revert substantial part of last fix.
+       (Splitting in IMAP): Add.
+
+2003-01-15  Kevin Ryde  <user42@zip.com.au>
+
+       * gnus.texi (Using MIME): Mention auto-compression-mode with
+       gnus-mime-copy-part.
+
+2003-01-13  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Window Layout): Fixed braces in example.
+
+2003-01-13  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Article Washing): Use new function names in
+       `deuglify.el'.  Addition.
+
+2003-01-13  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (X-Face): Fix.
+
+       * message.texi (Security): Fix.
+
+       * gnus.texi (Security): Fix.
+       (Signing and encrypting): Fix.
+
+2003-01-12  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Filtering Spam Using The Spam ELisp Package): removed
+       spam.el and spam-stat.el from the node and section names wherever
+       possible, since info indexing doesn't like `.' in the name.
+
+2003-01-12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Article Display): Addition.
+
+2003-01-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.texi (Header Commands): Addition.
+
+2003-01-10  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Article Washing): Added gnus-outlook-unwrap-lines,
+       gnus-outlook-repair-attribution, gnus-outlook-rearrange-citation.
+
+2003-01-11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi: Change .gnus to .gnus.el.
+       (Agent Commands): Remove batch here.
+       (MIME Commands): Add.
+
+       * message.texi (Canceling News): Document canlock.
+
+2003-01-10  Alex Schroeder  <alex@emacswiki.org>
+
+       * gnus.texi (Creating a spam-stat dictionary): Explain how using
+       the Gnus Agent with nnimap might work to do this.
+       (Splitting mail using spam-stat): Use nnimap-split-fancy if you
+       use the nnimap back end.
+
+2003-01-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Filtering Spam Using spam.el): Trivial fix.
+
+2003-01-10  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Choosing Variables, Agent Caveats): Add.
+
+2003-01-09  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Filtering Spam Using spam.el, ifile spam filtering)
+       (spam-stat spam filtering): added new functionality and explained
+       old functionality better, especially where it has changed in
+       ham/spam/unclassified group exit processing.
+
+2003-01-09  Alex Schroeder  <alex@emacswiki.org>
+
+       * gnus.texi (Splitting mail using spam-stat): Fix typo.
+       (Creating a spam-stat dictionary, Splitting mail using spam-stat):
+       Fix markup in a few places.
+
+2003-01-08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Positioning Point): %~ => ~*.
+
+2003-01-07  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * message.texi: Updated copyright line.
+       (Mailing Lists): Updated (renamed) function names.
+       (Header Commands): Updated (renamed) function names.
+       (Header Commands): Added message-to-list-only,
+       message-change-subject, message-cross-post-followup-to,
+       message-reduce-to-to-cc and message-add-archive-header.  Moved
+       message-sort-headers, message-insert-to, message-insert-newsgroups
+       and message-insert-disposition-notification-to from other
+       sections.
+       (Insertion): Added message-mark-inserted-region,
+       message-mark-insert-file.  Moved
+       message-insert-disposition-notification-to to section (Header
+       Commands).
+       (Various Commands): Moved message-insert-wide-reply,
+       message-insert-to, message-insert-newsgroups and
+       message-sort-headers to (Header Commands) section.
+       (Message Headers): Added message-subject-trailing-was-query.
+       (Insertion Variables): Added message-mark-insert-begin and
+       message-mark-insert-end.
+
+2003-01-08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Optional Back End Functions): Addition.
+       (Positioning Point): Changed to %~.
+
+2003-01-08  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (MIME Commands): Add.
+
+2003-01-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.texi (Various Commands): Addition.
+
+2003-01-05  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Filtering Spam Using spam.el)
+       (Blacklists and Whitelists, BBDB Whitelists, Blackholes)
+       (Bogofilter, Ifile spam filtering, Extending spam.el): updated
+       documentation for the new spam.el functionality.
+
+2003-01-05  Jesper Harder  <harder@ifa.au.dk>
+
+       * refcard.tex: Fix pagebreak.
+
+       * gnusref.tex: Additions and fixes.
+
+       * booklet.tex: Add missing sections.
+
+       * gnus.texi (Mail Group Commands): Fix typo.
+       (XEmacs): Add sh-script.
+       (Article Washing): Fix.
+
+2003-01-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Setting Process Marks): Addition.
+       (Group Line Specification): Addition.
+
+2003-01-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Group Line Specification): Addition.
+
+2003-01-03  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi: Fix typos.
+
+2003-01-02  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Troubleshooting): Add.
+
+2003-01-02  Reiner Steib  <Reiner.Steib@gmx.de>
+
+       * gnus.texi (Article Buttons): Regexps are case insensitive here.
+
+2003-01-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Summary Generation Commands): Addition.
+
+2003-01-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.texi (Message Headers): Added example.
+       (Message Headers): Addition.
+
+2002-12-31  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus.texi (Top): Add pointers to related manuals.  Suggested by
+       Reiner Steib.
+
+2002-12-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Saving Articles): Addition.
+
+2002-12-30  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Blackholes): added information on query-dig and
+       dig.el; users are told that using blackhole checks is OK now.
+
+2002-12-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Loose Threads): add
+       gnus-summary-make-false-root-always.
+       (Finding the Parent): Change name of nnweb server.
+
+2002-12-22  Jesper Harder  <harder@ifa.au.dk>
+
+       * emacs-mime.texi: Fix typos.  Index variables.  Add
+       mm-automatic-external-display, mm-w3m-safe-url-regexp and
+       mm-external-terminal-program.
+
+2002-12-20  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.texi (Message Headers): Add message-allow-no-recipients.
+       (Various Commands): Add TAB and message-tab-body-function.
+
+2002-12-19  Paul Jarc  <prj@po.cwru.edu>
+
+       * gnus.texi (Optional Back End Functions):
+       nnchoke-request-update-info need not return the info object.
+
+2002-12-15  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnusref.tex: Additions.
+
+2002-12-14  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Mail): Explain nil value of gnus-uu-digest-headers.
+
+2002-12-10  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus.texi (Posting Styles): Clarify the `(header MATCH REGEXP)'
+       case.
+       (Back End Interface): Mention nnnotbackends.  Suggested by Jan
+       Rychter.
+
+2002-11-29  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus.texi (MIME Commands): Document gnus-inhibit-mime-unbuttonizing.
+
+2002-11-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Expiring in IMAP): backend -> back end.
+       (Wide Characters): The default value of
+       gnus-use-correct-string-widths under Emacs is nil.
+       (Filtering Spam Using spam.el): backend -> back end.
+       (Extending spam.el): backend -> back end.
+       (Filtering Spam Using Statistics (spam-stat.el)): Fix typo.
+       (Creating a spam-stat dictionary): Fix typo.
+       (Creating a spam-stat dictionary): backend -> back end.
+
+2002-11-22  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Extending spam.el): fixed typos and wrong @items.
+
+2002-11-21  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi:
+       added new keyboard commands.
+
+       * gnus.texi: added extended section on spam.
+
+2002-11-18  jas
+
+       * gnus.texi: Fix IMAP expiring typos.
+
+2002-11-18  kaig
+
+       * gnus.texi: *** empty log message ***
+
+2002-11-18  jas
+
+       * gnus.texi: More morse.
+
+       * gnus.texi (Article Washing): Add morse.
+
+2002-11-17  jas
+
+       * gnus.texi: Fix typo.
+
+       * gnus.texi (Expiring in IMAP): Add.
+       (Group Parameters): Add reference.
+
+2002-11-16  Kai Großjohann  <kai.grossjohann@uni-duisburg.de>
+
+       * gnus.texi (Expiring Mail): Give summary on difference between
+       auto-expire and total-expire and provide information for choosing
+       between them.
+
+2002-11-18  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Article Washing): Add morse.
+
+2002-11-17  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Expiring in IMAP): Add.
+       (Group Parameters): Add reference.
+
+2002-10-24  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (RSS): Add gnus-summary-mark-as-read-forward into the
+       example code. From Christoph Conrad <christoph.conrad@gmx.de>.
+
+2002-10-17  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Other Marks): Document gnus-downloadable-mark and
+       gnus-undownloaded-mark.  Adapted idea from Sriram Karra
+       <karra@shakti.homelinux.net>.
+       (Formatting Fonts): Say that guillemets are wrong.  (How to enter
+       guillemets in Texinfo files?)
+
+2002-10-12  Simon Josefsson  <jas@extundo.com>
+
+       * message.texi (Movement): Add.
+
+2002-10-11  Jesper harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Formatting Fonts): Fix for balloon help in GNU Emacs.
+
+2002-10-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Delayed Articles): Fix gnus-delay-initialize.
+
+2002-10-10  Simon Josefsson  <jas@extundo.com>
+
+       * message.texi (Security): Fix.
+
+2002-10-04  Simon Josefsson  <jas@extundo.com>
+
+       * pgg.texi: Document sign parameter.
+
+       * gnus.texi: Add \gnuskey tex command.
+
+       * texi2latex.el (latexi-translate-file): Do PGG.  (Poor) support
+       of @set, @deffn, @defvar, @defun, @key.  Improve error.
+
+       * Makefile.in: Add PGG.
+
+       * pgg.texi: New file.
+
+2002-10-03  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Group Information): Mention prefix argument for
+       gnus-group-fetch-charter and gnus-group-fetch-control.
+       From Jesper Harder.
+
+2002-09-26  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Agent Variables): Add.
+
+2002-09-25  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Troubleshooting): Add.
+
+2002-09-23  Jesper harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Summary Maneuvering): Fix gnus-auto-select-next.
+
+2002-09-19  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (X-Face): Add GIF.
+
+2002-09-18  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (A note on namespaces): New.
+
+2002-09-16  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Splitting Mail): "By default, splitting is performed
+       on all incoming messages."  This sentence had a "not" too many.
+       Explicitly say that `nnmail-resplit-incoming' has effect only for
+       `directory' mail-sources entries.
+
+2002-09-15  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Mail Source Specifiers): Say "one-to-one
+       correspondence" in the description of `directory'.
+
+2002-09-11  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Top, Summary Buffer): Add info to "Delayed Articles"
+       menu line.
+
+2002-09-11  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Article Hiding): Add a document for
+       gnus-article-address-banner-alist.
+
+2002-09-11  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Splitting in IMAP): Fix.
+
+2002-09-10  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Other Marks): Fix.
+
+2002-09-09  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Splitting Mail): Typo.
+       (Comparing Mail Back Ends): Say "back end" instead of "backend".
+       (Terminology): Try to explain "back end" better.
+
+2002-09-09  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Article Buttons): Add.
+
+2002-09-09  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Splitting Mail): Document nnmail-resplit-incoming,
+       xref to Mail Source Specifiers.
+       (Mail Source Specifiers): Add index entry for
+       nnmail-scan-directory-mail-source-once.  Add index entry for
+       nnmail-resplit-incoming, with xref to Splitting Mail.
+
+2002-09-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Browse Foreign Server): Addition.
+       (Limiting): Addition.articles.
+
+2002-09-04  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Mail Source Specifiers): Fix.
+
+2002-09-03  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Direct Functions, Common Variables): Named ports like
+       "snews" doesn't work with some external tools.  Thanks to
+       "D. Watson" <djwatson@u.washington.edu> for noting this.
+
+2002-09-01  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Gnus Unplugged): Fix, agent is now enabled by default.
+       (Agent as Cache): New.
+
+2002-08-26  Jesper harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Group Information): Add gnus-group-fetch-charter and
+       gnus-group-fetch-control.
+
+2002-08-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Posting Server): Document message-smtpmail-send-it.
+
+       * message.texi (Mail Variables): Add message-smtpmail-send-it.
+
+2002-08-27  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Mail Source Specifiers): Fix :path default.
+
+2002-08-22  Jesper harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Summary Mail Commands): Add
+       gnus-summary-reply-broken-reply-to and
+       gnus-summary-reply-broken-reply-to-with-original.
+       (Setting Process Marks): Add gnus-uu-unmark-region.
+       (Article Header): Fix typo.
+       (MIME Commands): Fix typo.
+       (MIME Commands): Index gnus-article-decode-mime-words,
+       gnus-article-decode-charset and gnus-mime-view-all-parts.
+
+2002-08-20  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Mail Source Specifiers): Mention variable
+       nnmail-resplit-incoming under `directory' specifier.
+
+2002-08-18  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Summary Buffer Lines): Document the %k specifier.
+
+2002-08-15  Jesper harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Group Line Specification): Add %C.
+       (Group Parameters): Comments can be displayed in the group line.
+
+2002-08-07  Jesper harder  <harder@ifa.au.dk>
+
+       * emacs-mime.texi (Non-MIME): Add yenc.
+       (yenc): New node.
+
+2002-08-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Summary Sorting): Document randomization.
+
+2002-07-28  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Web Searches): Added gmane and removed old
+       non-functioning search engines.  From Niklas Morberg
+       <niklas.morberg@axis.com>.
+
+2002-07-21  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Sorting Groups): Add key bindings for
+       gnus-group-sort-groups-by-real-name and
+       gnus-group-sort-selected-groups-by-real-name.
+
+2002-05-14  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Summary Buffer Lines): Fix typo.
+
+2002-07-27  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Summary Mail Commands): Trivial fix from Reiner Steib
+       <4uce.02.r.steib@gmx.net>.
+
+2002-07-18  Karl Kleinpaste  <karl@charcoal.com>
+
+       * gnus.texi (To From Newsgroups): Additional text regarding how to
+       regenerate overviews via server buffer, and note to news admins
+       about overview.fmt.
+
+2002-07-14  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Posting Styles): Fix example (it was using the To
+       header instead of the From header).  From Christopher Splinter
+       <cs@splinter.inka.de>.
+
+2002-07-07  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Top): Move hashcash down into spam chapter.
+       (Top): New spam menu.
+       (Various): Remove hashcash.
+       (Thwarting Email Spam): Split into introduction and "Anti-Spam
+       Basics" node.
+       (SpamAssassin): Add.
+       (Hashcash): Add.
+
+2002-06-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (NNTP): Doc fix.
+
+2002-07-02  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Washing Mail): Document the shortcoming of
+       nnmail-remove-leading-whitespace.
+
+2002-06-30  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * message.texi (News Headers): Include example for removing an
+       entry from message-required-news-headers.
+
+2002-06-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (NNTP): Add nntp-via-rlogin-command-switches.
+
+2002-06-27  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Mail Back End Variables): Document
+       nnmail-cache-ignore-groups.  Xref Fancy Mail Splitting.
+       (Fancy Mail Splitting): Mention nnmail-cache-ignore-groups and
+       why it is useful.
+
+2002-06-25  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Fancy Mail Splitting): Include all necessary
+       variables in the Lisp example.
+
+2002-06-22  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Pay Hashcash): Add.
+
+2002-06-03  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Splitting Mail): Add.
+
+2002-05-23  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Web Searches): Fix.  Trivial change from Niklas
+       Morberg <niklas.morberg@axis.com>.
+
+2002-05-22  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Mail): Add variable.
+
+2002-05-16  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Loose Threads): Add gnus-simplify-all-whitespace.
+
+2002-05-08  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Mail-To-News Gateways): The default
+       nngateway-header-transformation function inserts a "To" header,
+       not a "From" header.  From Jesper Harder <harder@ifa.au.dk>.
+
+2002-05-08  Josh Huber  <huber@alum.wpi.edu>
+
+       * message.texi (Security): Added a note about the signencrypt
+       style, and how to change it using `mml-signencrypt-style.'.
+
+2002-05-04  Simon Josefsson  <jas@extundo.com>
+
+       * emacs-mime.texi (Encoding Customization): Fix.
+
+2002-05-04  Simon Josefsson  <jas@extundo.com>
+
+       * emacs-mime.texi: Move two chapters "Interface Functions" and
+       "Basic Functions" after the Decoding and Encoding chapters.  (No
+       text modified.)
+
+2002-05-04  Simon Josefsson  <jas@extundo.com>
+
+       * emacs-mime.texi (Top): Change scope of manual to include users.
+       (Customization): Rename to Display Customization.
+       (MML Definition): Add cross references.
+       (Encoding Customization): New section.
+       (Charset Translation): More info and cross references.
+
+2002-05-01  Josh Huber  <huber@alum.wpi.edu>
+
+       * gnus.texi (Signing and encrypting): Fix doc.  Also, add a
+       paragraph about replysign/replyencrypt/replysignencryped use.
+
+2002-05-01  Lars Magne Ingebrigtsen  <larsi@quimbies.gnus.org>
+
+       * message.texi (Message Headers): Remove colon from index
+       entries.
+
+2002-05-01  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Group Mail Splitting): Fix example.
+       (Article Buttons): Document that REGEXP can be a variable as well.
+
+       * message.texi (Message Headers): Fix example.
+
+2002-04-26  Steve Youngs  <youngs@xemacs.org>
+
+       * Makefile.in (infodir): Set to '@info_dir@' so we can separate
+       defaults for XEmacs and Emacs.
+
+2002-04-27  Jesper Harder  <harder@ifa.au.dk>
+
+       * emacs-mime.texi (Customization): Update info on HTML renderers.
+
+       * gnus.texi (Article Washing): Update information on HTML washing.
+       Fix typos.
+
+2002-04-09  Paul Jarc  <prj@po.cwru.edu>
+
+       * .cvsignore: added message-[0-9]*.
+
+2002-04-08  Paul Jarc  <prj@po.cwru.edu>
+
+       * gnus.texi (Group Parameters): Point to the message manual for a
+       full explanation of MFT.
+       * message.texi (Mailing Lists): Mention
+       message-gen-unsubscribed-mft.
+       From Karra <karra@cs.utah.edu>.
+
+2002-04-05  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Saving Articles): Add xref to Mail Group Commands
+       because people might be interested in `B c' for saving articles.
+       (Archived Messages): Ditto.
+
+2002-04-01  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Sorting Groups): Add gnus-group-sort-selected-groups.
+       (Article Washing): Fix typo.
+
+       * message.texi (Various Commands): Index message-elide-ellipsis.
+       Add message-sort-headers.
+       (Mail Variables): Add message-qmail-inject-args,
+       message-mailer-swallows-blank-line, message-sendmail-f-is-evil,
+       message-qmail-inject-program.
+       (Various Message Variables): Add message-auto-save-directory,
+       message-strip-special-text-properties, message-cancel-hook.
+       (News Headers): Index message-user-organization etc.
+       (Forwarding): Add message-forward-before-signature.
+       (Mailing Lists): Index message-subscribed-address-file.
+       (Wide Reply): Add message-wide-reply-confirm-recipients.
+       (Canceling News): Add message-cancel-message.
+       (Sending Variables): Add message-interactive.
+
+2002-03-25  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Mail Spool): Add cindex for marks.
+       (Mail Folders): Add cindex for marks.
+
+2002-03-24  Raymond Scholz  <rscholz@zonix.de>
+
+       * gnus.texi (Summary Buffer Lines): Fix doc.
+
+2002-03-24  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * Makefile.in (booklet.dvi, booklet.pdf): Support booklet.
+
+2002-03-24  Felix Natter  <fnatter@gmx.net>
+
+       * booklet.tex, bk-at.tex, bk-lt.tex, gnuslog-booklet.eps: New file.
+       * gnusref.tex, refcard.tex: Support booklet.
+
+2002-03-24  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnusref.tex: Addition.
+
+       * gnus.texi: Don't use @sc in headings.
+       (Article Display): Fix.
+       (Signing and encrypting): Add mml-unsecure-message.
+       (IMAP): Remove @. to make texi2latex work.
+       (Thread Commands): Fix.
+       (Unavailable Servers): Add gnus-server-offline-server.
+       (Topic Sorting): Add gnus-topic-sort-groups.
+       (Limiting): Fix.
+       (Article Washing): Fix gnus-article-strip-headers-in-body, add
+       gnus-article-outlook-deuglify-article.
+       (Article Header): Add gnus-article-remove-leading-whitespace.
+       (Customizing Articles): Add gnus-treat-leading-whitespace.
+       (Summary Score Commands): Add gnus-score-find-favourite-words.
+       (Mailing List): Index gnus-mailing-list-insinuate.
+       (Mail Group Commands): Add gnus-article-encrypt-body,
+       gnus-summary-create-article.  Don't use @var if not
+       metasyntactic. Index gnus-summary-edit-article-done.
+
+       * message.texi (Security): Add mml-unsecure-message.
+       (Mailing Lists): Index message-goto-mail-followup-to.
+
+2002-03-23  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnusref.tex, refcard.tex: Addition.
+
+2002-03-21  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.texi (Sending Variables): Fix typo.
+       Trivial change from Raymond Scholz <rscholz@zonix.de>
+
+2002-03-09  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Other Marks): Remove duplication.
+       Trivial change from David Aspinwall <aspinwall@timesten.com>
+
+2002-03-09  Paul Jarc  <prj@po.cwru.edu>
+
+       * gnus.texi: Mention nnmaildir where appropriate; fix some typos.
+
+2002-03-01  Paul Jarc  <prj@po.cwru.edu>
+
+       * message.texi (Mailing Lists): 'use is the default for
+       message-use-mail-followup-to, not nil; 'use is also not t.
+       Mention why an unsubscribed list poster might use MFT, and how to
+       disable MFT for a single message.
+
+2002-02-25  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Splitting Mail): Addition.
+
+2002-02-23  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnusref.tex (subsection*{Notes}): Addition.
+       Suggested by Felix Natter <fnatter@gmx.net>
+
+2002-02-22  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Splitting Mail): Addition.
+
+2002-02-20  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Slave Gnusae): Addition.
+       From  David S. Goldberg <david.goldberg6@verizon.net>
+
+2002-02-18  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * emacs-mime.texi (mailcap): Addition.
+
+       * gnus.texi (Using MIME): Rename functions. Addition.
+
+2002-02-16  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Top): Change description of Posting Server node.
+       (Composing Messages): Ditto.
+       (Posting Server): Add some mail stuff.
+       (IMAP): Terminate @, from Emacs Gnus manual.
+       (Thwarting Email Spam): Use @sc.
+
+2002-02-16  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnusref.tex (subsection*{Notes}): Update.
+       From: Felix Natter <fnatter@gmx.net>
+
+2002-02-14  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Document Groups): Addition.
+
+2002-02-13  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * message.texi (Security): Fix @findex for the key `C-c C-m s p'.
+
+2002-02-13  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       Reinstate some changes to make latexpdf work.
+
+       * message.texi (Security): Don't use @key.
+       (Various Commands): Don't use @point.
+
+       * gnus.texi (Mail Source Specifiers): Use @uref.
+
+2002-02-13  Jesper Harder  <harder@ifa.au.dk>
+
+       * message.texi, gnus.texi, emacs-mime.texi: Use small caps
+       consistently.  MIME, NOV, NNTP, HTML, IMAP are written with @sc
+       most places -- it looks better if it's the same *everywhere*.
+       @kbd instead of @code for key sequences. @file instead of @code
+       for files.
+
+       * message.texi (Various Commands): use the proper @point glyph.
+
+       * gnus.texi (Summary Mail Commands): ß doesn't work.  A German
+       spelling reform changed the correct spelling to "muss" anyway (I
+       think).
+
+       * gnus.texi (Mail sources): § doesn't work. Use "section" instead.
+
+       * gnus.texi (Mail Source Specifiers): use @url.
+
+       * message.texi, emacs-mime.texi: update copyright year.
+
+2002-02-12  Paul Jarc  <prj@po.cwru.edu>
+
+       * gnus.texi (Required Back End Functions): specify the lowest and
+       highest article numbers for empty groups for nnchoke-request-list
+       and nnchoke-request-group.
+
+2002-02-12  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.texi (Sending Variables): Addition.
+
+       * gnus.texi (Group Parameters): Add unread, not read.
+       (Archived Messages): Addition.
+
+2002-02-09  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Group Parameters): Addition.
+       From: Steinar Bang <steinar@bang.priv.no>
+
+2002-02-08  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Article Washing): Addition.
+       From: Michael Cook <michael.cook@cisco.com>
+
+2002-02-06  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Gnus Unplugged): Use (setq gnus-agent t).
+       (Example Setup): Ditto.
+       (Category Syntax): Require gnus-agent.
+
+2002-02-06  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Posting Styles): Addition.
+
+2002-02-05  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.texi (Mailing Lists): Addition.
+       * gnus.texi (Group Parameters): Addition.
+       From Sriram Karra <karra@cs.utah.edu>.
+
+2002-02-03  Karl Kleinpaste  <karl@charcoal.com>
+
+       * gnus.texi (Summary Score Commands): Added detail on "extra"
+       header scoring.
+       (Score File Format): ditto.
+
+2002-02-01  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * emacs-mime.texi (Customization): Addition.
+
+2002-01-31  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Posting Styles): Addition. Suggested by
+       Michael Cook <michael@waxrat.com>.
+
+2002-01-30  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * emacs-mime.texi (Customization): Move emacs-w3m stuff backward;
+       added documentation for `mm-inline-text-html-with-w3m-keymap'.
+
+2002-01-28  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Agent Expiry): Addition.
+
+2002-01-28  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * emacs-mime.texi (Customization): Added documentation for
+       `mm-inline-text-html-with-images'.
+
+       * gnus.texi (Article Washing): Replace w3m to emacs-w3m.
+
+2002-01-26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Mail Spool): Addition.
+
+2002-01-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * emacs-mime.texi (Customization): Added documentation for
+       `mm-inline-text-html-renderer'.
+
+2002-01-23  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Article Washing): Add URL about w3m.
+
+2002-01-22  Josh Huber  <huber@alum.wpi.edu>
+
+       * emacs-mime.texi (MML Definition): Added a few words about the
+       recipients option.
+       * message.texi (Security): Changed documentation to reflect use of
+       the new secure tag.
+
+2002-01-21  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Article Washing): Addition.
+
+2002-01-20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Document Groups): Added info on more doc types.
+       (More Threading): Move documentation here.
+
+2002-01-20  Simon Josefsson  <jas@extundo.com>
+
+       * message.texi (Mailing Lists): Fix.  From Love
+       <lha@stacken.kth.se>.
+
+2002-01-20  Patric Mueller  <bhaak@gmx.net>
+
+       * gnus.texi (Group Timestamp): Typo fix.
+
+2002-01-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Selecting a Group): Addition.
+
+2002-01-19  Lars Magne Ingebrigtsen  <karra@cs.utah.edu>
+
+       * gnus.texi (Mail Spool): Note that the .marks files can be
+       removed.
+
+2002-01-17  Paul Jarc  <prj@po.cwru.edu>
+
+       * gnus.texi (Choosing a Mail Back End): mention nnmaildir.
+       (Comparing Mail Backends): briefly describe nnmaildir.
+
+2002-01-17  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Agent Commands): Use gnus-agent-batch instead of
+       gnus-agent-batch-fetch.
+
+2002-01-15  Jari Aalto  <jari.aalto@poboxes.com>
+
+       * gnus.texi (Really Various Summary Commands): Added commands how
+       to create nnvirtual group and and how to modify the nnvirtual
+       regexp.
+
+2002-01-12  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Agent Caveats): Add agent cache.
+       (Agent Variables): Addition.
+
+2002-01-12  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Conformity): Fix typo.
+
+       * emacs-mime.texi (Flowed text, Standards): Add.
+
+2002-01-11  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.texi (Mailing Lists): Addition.
+       * gnus.texi (Group Parameters): Addition.
+       From Sriram Karra <karra@cs.utah.edu>.
+
+2002-01-10  Colin Marquardt  <c.marquardt@alcatel.de>
+
+       * gnus.texi (Changing Servers): Addition.
+
+2002-01-06  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Archived Messages): Rename
+       gnus-inews-mark-gcc-as-read to gnus-gcc-mark-as-read.
+
+       * Makefile.in (clean): Clean thumb*.
+
+2002-01-05  Harry Putnam  <reader@newsguy.com>
+
+       * gnus.texi (Score Variables): Clarify.
+
+2002-01-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Agent Expiry): Addition.
+       (Sorting the Summary Buffer): Addition.
+
+2002-01-05  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Conformity): Add MIME and Disposition Notifications.
+
+       * message.texi (Header Commands): Fix.  Add m-goto-from.
+       (Insertion): Add m-i-disposition-notification-to.
+
+2002-01-05  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * Makefile.in (.latexi.pdf-x): Use thumbpdf.
+
+       * gnus.texi (Advanced Formatting): Double @'s. Use thumbpdf.
+       colorlinks=true.
+
+2002-01-05  Norman Walsh  <ndw@nwalsh.com>
+
+       * gnus-faq.texi: Fix typo.
+
+2002-01-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Sorting the Summary Buffer): Addition.
+
+2002-01-04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Virtual Groups): Addition.
+
+2002-01-03  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Article Keymap): Addition.
+       (Summary Mail Commands): Fix.
+
+2002-01-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Group Timestamp): Addition.  Example from Andras
+       BALI.
+       (X-Face): Addition.
+       (Advanced Formatting): Add example.
+
+2002-01-01  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Conformity): Add and fix.
+
+       * message.texi (Security): Mention gpg-temp-directory.
+
+       * gnus.texi (Article Washing): Link to Security section.
+       (Security): Fix.
+       (Signing and Encrypting): Renamed from Using GPG.
+       (IMAP): Fixes.
+
+2002-01-01  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Customizing Articles): Add crossreference links.  Add
+       gnus-body-boundary-delimiter.
+
+2002-01-01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Choosing Commands): Addition.
+       (Article Display): Update.
+       (Article Display): Addition.
+       (Article Header): New.
+       (Slow Terminal Connection): Addition.
+       (Predicate Specifiers): New.
+       (To From Newsgroups): Addition.
+       (Topic Commands): Addition.
+       Update the menus.
+       Fix some references b0rked up by the menu fixing.
+
+2001-12-31  Rui Zhu  <sprache@iname.com>
+
+       * emacs-mime.texi (Customization): Typo fix.
+
+2001-12-31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Article Display): Addition.
+
+       * emacs-mime.texi (Interface Functions): Addition.
+
+       * gnus.texi (Using MIME): Addition.
+
+2001-12-30  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (X-Face): Made into own node.
+       (Article Display): New.
+
+       * emacs-mime.texi (Interface Functions): Addition.
+
+       * message.texi (Message Headers): Addition.
+
+2001-12-29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * emacs-mime.texi (Customization): Added example.
+
+       * gnus.texi (Selecting a Group): Addition.
+       (Tree Display): Addition.
+
+2001-12-26  Florian Weimer  <fw@deneb.enyo.de>
+
+       * gnus.texi (Using GPG): Remove obsolete reference to gpg-2comp.
+
+2001-12-26  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Summary Buffer Lines): Add xrefs.  Suggested by
+       Arcady Genkin <agenkin-dated-1010249095.131f22@thpoon.com>.
+
+2001-12-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (NNTP): Add a note for `nntp-prepare-post-hook'.
+
+2001-12-18  Josh Huber  <huber@alum.wpi.edu>
+
+       * ChangeLog, gnus.texi, emacs-mime.texi: (oops) removed
+       buffer-file-coding-system.
+
+2001-12-18 00:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * ChangeLog, gnus.texi, emacs-mime.texi: Local Variables `coding'
+       MUST be added!
+
+2001-12-17  Josh Huber  <huber@alum.wpi.edu>
+
+       * ChangeLog: changed coding to buffer-file-coding-system.
+       * emacs-mime.texi: changed -*- magic cookie -*- to Local Variables.
+       * gnus.texi: same.
+       * gnus-ref.tex: same.
+       * refcard.tex: same.
+
+2001-12-16  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Saving Articles): Add muttprint.
+       (Article Commands): Mention muttprint.
+
+2001-12-15  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Virtual Groups): Fix.  From Raymond Scholz
+       <ray-2001@zonix.de>.
+
+2001-12-15 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi, emacs-mime.texi: Fix the header.
+
+2001-12-12  Didier Verna  <didier@lrde.epita.fr>
+
+       * gnus.texi (Misc Group Stuff): advertise `gnus-group-news'.
+       * gnus.texi (Summary Mail Commands): advertise
+       `gnus-summary-news-other-window'.
+
+2001-12-10  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Advanced Scoring Examples): Clarify that the
+       examples are rules, not complete score files.
+
+2001-12-09  Nevin Kapur  <nevin@jhu.edu>
+
+       * gnus.texi (Expiring Mail): Add.
+
+2001-12-05  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Splitting in IMAP): Typo.  From Colin Marquardt
+       <c.marquardt@alcatel.de>.
+
+2001-12-03 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * infohack.el (infohack): To process write-protected files safely,
+       make this buffer be writable after `find-file'.
+       From TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+2001-12-03 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * Makefile.in: Dependence.
+
+       * emacs-mime.texi: Add coding header.
+
+2001-12-01  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Group Line Specification, Summary Buffer Lines):
+       Cross reference Positioning Point.
+
+2001-11-25 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Limiting): Addition.
+
+2001-11-19  Simon Josefsson  <jas@extundo.com>
+
+       * message.texi (Header Commands, Insertion): Use C-c C-f C-i for
+       Importance: instead of C-c C-u.  Move to Header Commands from
+       Insertion. Suggested by Per Abrahamsen <abraham@dina.kvl.dk>.
+
+2001-11-17  Simon Josefsson  <jas@extundo.com>
+
+       * message.texi (Insertion): Use C-c C-u for Importance: instead of
+       C-c C-p (used by SC).
+
+2001-11-15  Simon Josefsson  <jas@extundo.com>
+
+       * message.texi (Insertion): Add C-c C-p,
+       message-insert-importance-{low,high}.
+       (Various Commands): Fix typo.
+       (Insertion Variables): New section, all variables moved from
+       Commands->Insertion into this node, Variables->Insertion
+       Variables.
+
+2001-11-15 14:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Various Summary Stuff): Add gnus-newsgroup-variables.
+
+2001-11-15 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.texi (Security): @uref not @url.
+
+2001-11-15  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * sieve.texi (Standards): Changed @samp to @uref.
+
+       * message.texi (Security): Changed @code to @uref.
+
+       * gnus-faq.texi: Changed a lot of @file to @uref.
+
+       * emacs-mime.texi (Standards): Changed @samp to @uref.
+
+2001-11-13  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Article Washing): Add `W s'.
+
+2001-11-12  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Security, Using GPG):
+       * message.texi (Security):
+       * emacs-mime.texi (MML Definition): Add PGP.
+
+2001-11-09  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * message.texi (Movement): message-beginning-of-line.
+
+2001-11-07  Simon Josefsson  <jas@extundo.com>
+
+       * sieve.texi (Examples): Add.
+       (Top): Add.
+
+       * gnus.texi (Saving Articles): Add gnus-summary-write-to-file.
+
+2001-11-07  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Misc Group Stuff): Add cross reference to Composing
+       Messages.  Suggested by "Golubev I. N." <gin@mo.msk.ru>.
+
+2001-11-04 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi: Use C-M- instead of M-C-.
+       * message.texi (Insertion): Ditto.
+       * sieve.texi (Managing Sieve): Ditto.
+       Suggested by Eli Zaretskii <eliz@is.elta.co.il>.
+
+2001-11-02  Simon Josefsson  <jas@extundo.com>
+
+       * dir (File): Add Sieve.
+
+       * gnus.texi (Sieve Commands): Add crossposting.
+
+2001-11-01 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * texi2latex.el (latexi-translate): Typo.
+       (latexi-translate-file): Nine in a herd is enough.
+
+2001-11-01  Simon Josefsson  <jas@extundo.com>
+
+       * sieve.texi (Installation): Workaround texi2latex bug (replacing
+       inside verbatim needs a \end{verbatim} earlier in the file).
+
+       * texi2latex.el (latexi-translate): Add sieve.
+
+2001-11-01 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Article Washing): Add a note.
+
+2001-11-01  Simon Josefsson  <jas@extundo.com>
+
+       * Makefile.in: Add sieve.
+
+       * gnus.texi (Misc Group Stuff):
+       (Group Parameters): Add Sieve Commands.
+       (top-level): Include Sieve manual after Emacs MIME.
+
+2001-10-31  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Group Parameters): Add integer `display'.
+       (IMAP): Fix.
+
+2001-10-31  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (NNTP): Added documentation for
+       `nntp-prepare-post-hook'.
+
+2001-10-29  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Customizing Articles): Sort list. Remove
+       duplicate. Suggested by Henrik Holm <henrik@tele.ntnu.no>.
+
+2001-10-27  Simon Josefsson  <jas@extundo.com>
+
+       * message.texi (Insertion): Fix message-yank*-prefix.
+
+2001-10-25  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Mail Source Specifiers): More info on SSL, kerberos etc.
+       (IMAP): Ditto.  Suggested by Martin Blais <blais@discreet.com>.
+
+2001-10-23  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus.texi (Posting Server): Use `native' instead of `nil' for
+       posting to native server.
+
+2001-10-22  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * dir (File): Add standard explanation header.
+
+2001-10-21  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Mail Source Specifiers): Explain more explicitly what
+       happens for the `directory' entries.  Say that mail from foo.spool
+       goes in the group foo.
+
+2001-10-19  Simon Josefsson  <jas@extundo.com>
+
+       * Makefile.in (clean): rm gnus.out.
+       (distclean): rm gnusconfig.tex (moved from "clean").
+
+       * gnus.texi (Using MIME): s/mime/MIME/ for PDF version.
+
+2001-10-19  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Finding the News): Disrecommend nnspool for Leafnode
+       users.
+
+2001-10-17 21:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Archived Messages): Add new line after @item.
+       From: Jesper Harder <harder@ifa.au.dk>
+
+2001-10-17 21:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Formatting Basics): Extended format specs.
+
+2001-10-17  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus.texi (Summary Buffer Lines): Documment %( and %).
+
+2001-09-04 21:43:05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Topic Sorting): Addition.
+
+2001-10-13 19:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * refcard.tex, gnusref.tex: Merge with the version
+       from Felix Natter <f.natter@ndh.net>
+
+2001-10-13 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * refcard.tex: Set version to Oort.
+
+       * gnusref.tex: New key bindings in Oort Gnus.
+
+2001-10-12 18:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * Makefile.in (.dvi.ps): Use TEXPICTS.
+       (.latexi.dvi-x): Remove gnus.toc as well.
+
+       * gnuslogo-refcard.eps: Remove BeginProcSet.
+
+2001-10-12  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Misc Group Stuff): Add UTF-8.
+       (Misc Article): Document wash status characters.  Suggested by
+       david.goldberg6@verizon.net (David S. Goldberg).
+
+2001-10-10 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnusref.tex, refcard.tex: Use epsfig.
+
+       * gnuslogo-refcard.eps: Rename from gnuslog.refcard, and set a
+       suitable bounding box.
+
+       * Makefile.in (.dvi.ps): New rule.
+       (refcard.pdf): Use gnuslogo-refcard.eps.
+
+2001-10-09 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi: Add href and bookmarks for pdf version.
+
+2001-10-06 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * Makefile.in (uninstall): Add uninstall.
+
+2001-10-05  Simon Josefsson  <jas@extundo.com>
+
+       * Makefile.in (clean): Add gnusconfig.tex.  Suggested by Henrik
+       Enberg <henrik@enberg.org>.
+
+2001-10-04  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Mail Source Customization): Add.
+
+2001-10-04 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * Makefile.in (dvi): Don't depend on tmps.
+
+2001-10-03 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * emacs-mime.texi (mailcap): rvplayer -> wavplayer.  Thanks to
+       Martin Kretzschmar <Martin.Kretzschmar@inf.tu-dresden.de>.
+
+2001-09-29  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Foreign Groups): Fix.  Add "mailman".
+       (Document Groups): Ditto.
+
+2001-09-28 07:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * Makefile.in (.texi): Remove $@ first.
+
+       * infohack.el (infohack-remove-unsupported): Remove @iflatex lines.
+       (infohack): Specify a coding-system to save info files.
+       From Katsumi Yamaoka  <yamaoka@jpl.org>
+
+2001-09-28 00:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnusconfig.tex.in: Use cmss if pfu is not found.
+
+2001-09-27 18:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * Makefile.in: Illustrated manual.
+       * gnus.texi: Put message.texi and emacs-mime.texi in the
+       illustrated manual.
+       * texi2latex.el: Ditto.
+
+2001-09-27 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi: Remove the extra white-space.
+
+2001-09-27 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnusconfig.tex.in: New.
+       * gnus.texi: Use it.
+       * pagestyle.sty: Don't set verbatim font.
+       * postamble.tex: Set in ...
+       * bembo.sty: Removed.
+       * Makefile.in (gnusconfig.tex): Check gnusconfig.tex.in.
+       (LATEX): Use configure.
+
+2001-09-26 00:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Limiting): Addition.
+
+2001-09-25 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Pterodactyl Gnus): Put @item in one line.
+
+2001-09-24 19:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi: eps path fix.
+       * postamble.tex: Ditto.
+       * texi2latex.el: Ditto.
+
+       * Makefile.in: Move some to ps/Makefile.in.
+
+2001-09-24  Simon Josefsson  <jas@extundo.com>
+
+       * etc/*, herds/*, misc/*, picons/*, screen/*, smilies/*, xface/*:
+       New files, from pspackage.tar.gz.
+
+       * Makefile.in (distclean): Make veryclean.
+
+       * gnus.texi (Summary Mail Commands): Fix.
+       (Summary Post Commands): Fix.
+       (The Manual): Fix.
+
+2001-09-23 02:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi: Use "back end".
+
+2001-09-23  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Top): Move IMAP up from "Other Sources" to "Select
+       Methods".
+       (Charsets): Update default value.
+       (Finding the Parent): Add nnimap.
+       (Security): Add.
+       (Mailing List): Add.
+       (Archived Messages): Comment out XEmacs 19 stuff.
+       (Using GPG): Add reference to message manual.
+       (Direct Functions): Mention OpenSSL as well as SSLeay.
+       (Mail Source Specifiers): Add recent IMAP :stream and
+       :authentication.
+       (Agent Commands): Fix.
+       (GroupLens): Add URL and note about this being historical.
+       (Wide Characters): Update default value.
+       (Picon Requirements): Remove old XEmacs 19 stuff.
+
+2001-09-22  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Other Marks): Add Recent.
+
+2001-09-14  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Mail Folders): Add.
+
+2001-09-11  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Delayed Articles): Fix.  Suggested by Paul Jarc
+       <prj@po.cwru.edu>.
+
+2001-09-08  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (MIME Commands): Add gnus-buttonized-mime-types.
+
+2001-09-08  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Topic Commands): Make this the first subsection of
+       `Group Topics'.  Rearrange keys to mention the most important keys
+       first and to have subsections.  Add some more explanation for
+       C-k/C-y.
+       (Group Buffer): Add comment from Alex Schroeder as todo item.
+
+2001-09-06  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Fancy Mail Splitting): Mention `delete' near the
+       explanation of `junk'.
+
+2001-09-04  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Optional Backend Functions): The default function to
+       make a date format is `message-make-date', which should produce a
+       time zone.
+
+2001-09-04  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Optional Backend Functions): More detail about the
+       DATE arg for nnchoke-request-newgroups.  Reported by Paul Jarc.
+
+2001-09-01  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Hooking New Backends Into Gnus): Say where to put the
+       call for gnus-declare-backend.  Add an index entry for
+       gnus-declare-backend.  Suggested by Paul Jarc.
+
+2001-08-29  Simon Josefsson  <jas@extundo.com>
+       From Anders Jackson <jackson@hig.se>
+
+       * gnus.texi (Group Parameters): Fix.
+
+2001-08-27  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Archiving Mail): Add.
+
+2001-08-25  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Mail Spool): Add marks.
+       (MH Spool): Doesn't use marks file.
+       (Mail Folders): Add marks.
+
+2001-08-25  Simon Josefsson  <jas@extundo.com>
+       From Henrik Enberg <henrik@enberg.org>
+
+       * gnus.texi (Group Parameters): Fix.
+
+2001-08-24 16:03:31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Group Parameters): Fix.
+
+2001-08-24  Simon Josefsson  <jas@extundo.com>
+
+       * Makefile.in (latexps): Make tmps.
+
+2001-08-24  Simon Josefsson  <jas@extundo.com>
+       From Jesper Harder <harder@ifa.au.dk>
+
+       * Makefile.in (latexps): Escape {.
+
+       * splitindex: Ditto.
+
+2001-08-23 19:22:59  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Group Parameters): Fix.
+       (Group Parameters): Addition.
+       (Limiting): Addition.
+
+2001-08-21 23:55:48  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Score Variables): Fix.
+
+2001-08-20  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Delayed Articles): New section.  Documents
+       gnus-delay.el.
+       (Fancy Mail Splitting): Say that nnmail-cache-accepted-message-ids
+       must be non-nil for splitting with parents to work.
+
+2001-08-19 17:31:15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Other Marks): Addition.
+       (Positioning Point): New.
+       (Tabulation): New.
+
+2001-08-19  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Getting Started Reading Mail): Use (nnml "") rather
+       than (nnml "private") as the example server specification.  This
+       way, the example group names a few paragraphs further down are
+       correct, and I expect that most people are going to use the empty
+       string as name, anyway.  Please holler if that is wrong.
+
+2001-08-18  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (Optional Backend Functions): Remove `set'
+       request-set-mark action.
+
+2001-08-18 00:40:10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Wide Characters): New section.
+
+2001-08-17  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi: Replace 20,20 with 23,23 for
+       gnus-summary-line-format.
+
+2001-08-17 14:24:14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Group Parameters): Document regexp substitution.
+       (Group Parameters): Addition.
+
+2001-08-11 23:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+       From Nevin Kapur <nevin@jhu.edu>
+
+       * gnus.texi (September Gnus): Typo.
+
+2001-08-12  Simon Josefsson  <jas@extundo.com>
+       Suggested by Kai.Grossjohann@CS.Uni-Dortmund.DE.
+
+       * gnus.texi (Other Marks): Add recent.
+       (Optional Backend Functions): Add forward and recent.
+
+2001-08-12  Kai Grossjohann  <grossjoh@ls6.informatik.uni-dortmund.de>
+
+       * gnus.texi (Window Layout): Renamed from `Windows
+       Configuration'.  After all, we're not talking about Microsoft.
+       Suggested by Barry Fishman.
+
+2001-08-11  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Summary Mail Commands): Remove duplicate explanation
+       of `S W'.  Reported by Norbert Koch.
+
+2001-08-09 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+       From Benjamin Rutt <brutt@bloomington.in.us>
+
+       * gnus.texi (Troubleshooting): Addition.
+
+2001-08-09  Simon Josefsson  <jas@extundo.com>
+       From Benjamin Rutt <brutt@bloomington.in.us>
+
+       * gnus.texi (Mail Backend Variables): Fix.
+
+2001-08-04  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Summary Buffer Lines): Mention `gnus-goto-colon'.
+
+2001-08-03  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Backend Interface): Explain about article numbers.
+       Suggested by Paul Jarc.
+
+2001-08-02 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * emacs-mime.texi (Non-MIME): Addition.
+
+       * gnus.texi (Group Parameters): Addition.
+       (Mailing List): Addition.
+
+2001-08-01  Simon Josefsson  <jas@extundo.com>
+
+       * texi2latex.el (latexi-translate-file): Don't use point-at-bol.
+       (latexi-translate-file): Translate some more things, including
+       some hardcoded things that cause problems for LaTeX.  From Jesper
+       Harder <harder@ifa.au.dk>.
+
+2001-07-31  Simon Josefsson  <jas@extundo.com>
+
+       * bembo.sty: New file.
+
+       * texi2latex.el (latexi-translate-file): Support @noindent.
+
+       * gnus-faq.texi (Reading News FAQ): Fix (@email -> @samp).
+
+2001-07-28 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+       From Janne Rinta-Manty <rintaman@cs.helsinki.fi>
+
+       * gnus.texi (Read Articles): Typo.
+
+2001-07-25 22:22:22  Raymond Scholz  <rscholz@zonix.de>
+
+       * gnus.texi (Fancy Mail Splitting): New variable
+       nnmail-split-fancy-with-parent-ignore-groups.
+
+2001-07-24  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Duplicates): Make split method regexp more specific,
+       in case other `Gnus-Warning' headers are added in the future.
+       Suggested by Karl Kleinpaste.
+
+2001-07-23 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+       From Karl Kleinpaste <karl@charcoal.com>
+
+       * gnus.texi (Summary Buffer Lines): Add %B.
+
+2001-07-20 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+       From Jesper Harder <harder@myrealbox.com>
+
+       * message.texi (Insertion): Addition.
+
+2001-07-19 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Charsets): Addition.
+
+2001-07-17 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Searching for Articles): Raw articles.
+
+2001-07-16  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * message.texi (Insertion): Refer to gnus-cite-attribution-suffix.
+
+2001-07-13 12:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (RSS): Add.
+       From Christoph Conrad <cc@cli.de>.
+
+2001-07-13 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Incorporating Old Mail): Add index.
+
+2001-07-13 00:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Group Parameters): Add.
+
+2001-07-04  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (IMAP): Add.
+
+2001-07-04  Didier Verna  <didier@lrde.epita.fr>
+
+       * gnus.texi (Example Methods): use the new nntp-open-connection
+       methods in the examples.
+       * gnus.texi (NNTP): update for the new nntp-open-connection methods.
+       * gnus.texi (Direct Functions): new node.
+       * gnus.texi (Indirect Functions): new node.
+       * gnus.texi (Common Variables): new node.
+
+2001-06-27  Simon Josefsson  <jas@extundo.com>
+       From Ralph Schleicher <rs@nunatak.allgaeu.org>
+
+       * gnus.texi (MIME Commands): Add.
+
+2001-06-24  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Summary Score Commands): Say that some commands
+       create ADAPT files.
+
+2001-06-23  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Duplicates): Contents of Gnus-Warning header have
+       changed.  Reported by Peter J Acklam.
+
+2001-06-19  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (IMAP): Fix `imtest' discussion.
+
+       * gnus-faq.texi (Frequently Asked Questions): Fix URL.
+
+2001-06-17  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Group Line Specification): Explain why %t is only an
+       estimate.
+
+2001-06-16  Simon Josefsson  <jas@extundo.com>
+
+       * gnus.texi (IMAP): Add.
+
+2001-06-13 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Article Washing): Add.
+
+2001-06-11 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi: behaviour -> behavior. Suggested by Eli Zaretskii
+       <eliz@is.elta.co.il>.
+
+2001-06-09 20:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi: Apply "overfull hbox" patch from Eli Zaretskii
+       <eliz@is.elta.co.il>.
+
+2001-06-07 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (RSS): Add.
+
+2001-05-31 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Setting Marks): Add.
+
+2001-05-27  Simon Josefsson  <simon@josefsson.org>
+
+       * message.texi (Insertion): Add message-yank-cited-prefix.
+
+2001-05-22  Simon Josefsson  <simon@josefsson.org>
+       From Jesper Harder <harder@ifa.au.dk>
+
+       * gnus.texi (Article Washing): Add.
+
+2001-05-16  Simon Josefsson  <simon@josefsson.org>
+       From Jesper Harder <harder@ifa.au.dk>
+
+       * texi2latex.el (latexi-translate-file): Also exchange ref.
+
+       * gnus.texi: Add \gnusref and \gnusuref.
+
+2001-05-16  Simon Josefsson  <simon@josefsson.org>
+       From Raymond Scholz <ray-2001@zonix.de>
+
+       * gnus.texi (Using MIME): Add and fix.
+
+2001-05-05  Florian Weimer  <fw@deneb.enyo.de>
+
+       * gnus.texi (IMAP): Remove double paragraph (suggest by Norbert
+       Koch), fix NNTP reference.
+
+2001-05-04 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+       Suggested by Dan Christensen <jdc@uwo.ca>
+
+       * gnus.texi (Mail Group Commands): Add pxref.
+       (Group Maintenance): Ditto.
+       (Topic Commands): Ditto.
+       (Expiring Mail): Typo.
+
+2001-05-04 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+       From Raymond Scholz <ray-2001@zonix.de>
+
+       * gnus.texi (Summary Buffer Lines): Mention the meaning of a
+       colon.
+
+2001-05-03 07:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+       From Sriram Karra <karra@cs.utah.edu>.
+
+       * gnus.texi: Add default value.
+
+2001-05-03 06:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Using GPG): Use example environment.
+
+2001-05-02 17:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Expunging mailboxes): Typo.
+
+2001-04-15 19:38:54  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Mail and Post): Fix.
+
+2001-04-29 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi: Remove a few The's.
+       (RSS): New.
+
+2001-04-26  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Unread Articles): Say that dormants are similar to
+       ticked.
+
+2001-04-13  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Sorting Groups): Note `C-k' and `C-y' for manually
+       moving groups around.
+
+2001-04-07  Ryan Yeske  <rcyeske@vcn.bc.ca>
+
+       * gnus.texi (Splitting in IMAP): Fix.
+
+2001-04-07  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (More Threading): Fix.
+
+2001-04-01 00:32:46  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (S): Renamed.
+       (Summary Sorting): Addition.
+
+2001-03-31 00:40:44  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Other Marks): Additon.
+       (The End): Remove "The" from menus.
+
+2001-03-30 23:34:02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Adaptive Scoring): Addition.
+       (Summary Mail Commands): Addition.
+
+2001-03-17  Matthias Wiehl  <mwiehl@gmx.de>
+
+       * message.texi (Security): Typos.
+
+2001-03-15  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Hiding Headers): Typos.  Reported by Sriram Karra
+       <karra@cs.utah.edu>.
+
+2001-03-11  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * message.texi (Message Headers): Update doc for
+       `message-generate-headers-first'.
+
+2001-03-14 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+       From Nevin Kapur <nevin@jhu.edu>
+
+       * gnus.texi (Mail Source Specifiers): Fix.
+
+2001-03-04 09:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+       From "Yair Friedman (Jerusalem)" <YAIRFR@amdocs.com>
+
+       * infohack.el (infohack): Set max-lisp-eval-depth to 600+.
+
+2001-03-03  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Posting Styles): Posting styles have (NAME VALUE),
+       not (NAME . VALUE).
+
+2001-02-25 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+       From Michael Totschnig <michaelt@supernet.ca>.
+
+       * gnus.texi (Article Fontisizing): Fix.
+
+2001-02-23  Simon Josefsson  <simon@josefsson.org>
+
+       * gnus.texi (Posting Server): Fix, due to change of default value
+       of `gnus-post-method' to `current'.
+
+2001-02-23 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi: Remove double words. From Gerd Moellmann.
+
+       * infohack.el (batch-makeinfo): New.
+
+       * Makefile.in (EMACSINFO): Use it.
+
+2001-02-17 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Posting Styles): Doc fix.
+
+2001-02-16  Simon Josefsson  <sjosefsson@rsasecurity.com>
+
+       * gnus.texi (Optional Backend Functions): Fix case.
+
+2001-02-14  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Unread Articles): Say that Gnus itself never expires
+       ticked articles.  Suggested by M D Greenhow
+       mdg@greenhow36.clara.co.uk.
+
+2001-02-13 19:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Saving Articles): Addition.
+
+2001-02-14 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Group Parameters): Addition.
+
+2001-02-11 13:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Choosing Commands): Move `G j' here.
+
+2001-02-09 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Pterodactyl Gnus): Added.
+       (Newest Features): Removed. Suggested by RMS.
+
+2001-02-08  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Group Parameters): Mention `G c' in addition to `G p'.
+
+2001-02-07  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (To From Newsgroups): Make it clear where to put the
+       sample code.  Suggested by Dan Jacobson.
+
+       * gnus.texi (Mail Source Specifiers, IMAP, Agent and IMAP):
+       Improve IMAP discussion.
+
+2001-02-07  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * message.texi (Message Headers): `message-generate-headers-first'.
+
+2001-02-06 19:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Using GPG): Key binding.
+
+       * message.texi (Security): Ditto.
+
+2001-02-06 18:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Top): Add Using GPG.
+
+2001-02-02  David Masterson  <dmasters@Rational.Com>
+
+       * gnus.texi (The Server is Down): Add link to Group Levels.
+
+2001-01-24  Simon Josefsson  <sj@extundo.com>
+
+       * gnus.texi (Mail Source Specifiers): Add IMAP :program, fix POP
+       :program typo.
+
+2001-01-15 16:15:20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (The Active File): Only old versionf of leafnode
+       doesn't do some.
+
+2001-01-23 23:28:08  Satomi Suzuki  <pan@mba.nifty.ne.jp>
+
+       * message.texi (message-ignored-news-headers): Add "X-Draft-From:".
+       (message-ignored-mail-headers): Ditto.
+
+2001-01-21  Raymond Scholz  <ray-2001@zonix.de>
+
+       * message.texi: Rename X-Mailer and X-Newsreader to User-Agent.
+
+2001-01-19 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * infohack.el: New file.
+
+       * Makefile.in: Use it.
+
+2001-01-18 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Hiding Headers): Add.
+
+       * emacs-mime.texi: Set dircategory to Emacs.
+
+2001-01-16  Jesper Harder  <harder@ifa.au.dk>
+
+       * gnus.texi (Group Line Specification): Add.
+
+2001-01-15 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Using GPG): Doc fix.
+
+2001-01-15  Simon Josefsson  <simon@josefsson.org>
+
+       * message.texi (Security): Requires OpenSSL 0.9.6+.
+
+2001-01-13  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Mail): Move explanation of
+       `message-send-mail-partially-limit' to message.texi.
+
+       * message.texi (Mail Variables): Ditto.
+
+2001-01-10 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Article Washing): makeinfo 1.69 doesn't grok `anchor'.
+
+2001-01-07 18:18:53  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (myself): Quote .
+
+2001-01-05  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Choosing Commands): Add xref for redisplaying the
+       group.  Suggestion from Galen Boyer <galenboyer@yahoo.com>.
+       (The Summary Buffer): Mention reselecting the current group in the
+       menu.  Suggestion from Galen Boyer <galenboyer@yahoo.com>.
+       (Followups To Yourself): Add Lisp example.
+
+2001-01-05 06:53:13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * emacs-mime.texi (time-date): Addition.
+       (time-date): Addition.
+
+2001-01-04 22:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Newest Features): uref, not url.
+
+       * texi2latex.el (latexi-translate-file): Ignore anchor.
+
+2001-01-04  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Article Washing): Refer to `Customizing Articles' for
+       permanent changes.  Suggested by Russell Marks (russel dot marks
+       at ntlworld dot com).
+
+2001-01-03  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Article Washing): Mention `C-u g' as a sort of
+       anti-washing.
+
+2001-01-01 11:40:34  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (extensions): Removed.
+
+2000-12-31 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * texi2latex.el (latexi-translate-file): Understand uref.
+
+2000-12-30  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Selecting a Group): Explain in more detail, what a
+       prefix arg means for SPC.  Refer people to M-g command from
+       summary buffer.  Suggested by Paul Repacholi
+       <prep@prep.synonet.com> and Dan Jacobson <jidanni@kimo.com.tw>.
+
+2000-12-29 21:43:20  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.texi (Spelling): New.
+
+2000-12-29 10:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * texi2latex.el (latexi-translate-file): Support srcdir.
+       (latexi-translate-file): Understand ifnottex, dircategory, and
+       direntry. Set coding-system-for-write to iso-8859-1.
+
+       * Makefile.in: Fix for srcdir.
+
+       * gnus.texi (NoCeM): Use file instead of uref.
+       (Mail Source Specifiers): Use subsubsection instead of
+       subsubheading.
+
+2000-12-29 01:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Top): Set version to Oort Gnus v0.01.
+
+       * Makefile.in (install): The info files are in the current
+       directory.
+
+2000-12-29  Christopher Splinter  <chris@splinter.inka.de>
+
+       * gnus.texi (Customizing Articles): Added documentation for
+       `gnus-treat-hide-citation-maybe', `gnus-treat-date-iso8601' and
+       `gnus-treat-date-user-defined'.
+
+2000-12-29 00:38:59  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Posting Styles): Addition.
+
+2000-12-28 20:04:26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.texi (Buffer Entry): New section.
+
+2000-12-22  Christopher Splinter  <chris@splinter.inka.de>
+
+       * gnus.texi (Group Parameters): Add documentation for the `banner'
+       group parameter.
+
+2000-12-22 11:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Adaptive Scoring): Use setq by Thomas Seck
+       <tmseck@web.de>.
+
+2000-12-21  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Article Washing): Doc addition by Paul Stevenson
+       <p.stevenson@surrey.ac.uk>.
+
+2000-12-10  Jim Meyering  <meyering@lucent.com>
+
+       * Makefile.in (.texi): Use `-I $(srcdir)' with `makeinfo' so that
+       non-srcdir builds work.
+
+2000-11-29 20:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Fancy Mail Splitting): Add.
+
+2000-11-20 08:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Archived Messages): Add.
+
+2000-11-20  Jochen Küpper  <jochen@pc1.uni-duesseldorf.de>
+
+       * gnus.texi (Security): Fix typo.
+
+2000-11-20 00:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi: Add.
+
+2000-11-12  Florian Weimer  <fw@deneb.enyo.de>
+
+       * message.texi (Security): Fixed typo, change "PGP" to "OpenPGP".
+
+2000-11-12  David Edmondson  <dme@dme.org>
+
+       * gnus.texi: remove `gnus-cite-prefix-regexp'.
+
+       * message.texi (Insertion): move `gnus-cite-prefix-regexp' from
+       gnus.texi to here and rename to `message-cite-prefix-regexp'.
+
+2000-11-11  Simon Josefsson  <sj@extundo.com>
+
+       * message.texi (Security): Add.
+
+       * emacs-mime.texi (MML Definition): Add sign, encrypt, keyfile and
+       certfile.
+
+2000-11-07  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Mail Group Commands): `gnus-move-split-methods' uses
+       group names as target, where `gnus-split-methods' uses file
+       names.  Suggested by Nevin Kapur.
+
+2000-11-07  Martin Buchholz  <martin@xemacs.org>
+
+       * gnus.texi: Doc fix.
+
+2000-11-01  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Fancy Mail Splitting): Explain
+       `nnmail-split-fancy-with-parent'.
+
+2000-11-01 09:12:24  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Finding the News): @env is not supported in texinfo 3.12.
+
+2000-10-31  Jorge Godoy  <godoy@conectiva.com>
+
+       * gnus.texi: gnus-gpg document.
+
+2000-10-31  Simon Josefsson  <sj@extundo.com>
+
+       * gnus.texi (NNTP): Explain `port'.
+
+2000-10-30  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Archived Messages): Explain what happens when group
+       names mentioned in `gnus-message-archive-group' contain a select
+       method.
+
+2000-10-28  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Group Levels): Explain meaning of subscribed,
+       unsubscribed, zombie, killed groups.
+
+2000-10-26  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Gnus Development): nnmail-delete-incoming -->
+       mail-source-delete-incoming.  Suggested by Karl Kleinpaste
+       <karl@charcoal.com>.
+
+2000-10-18  Dave Love  <fx@gnu.org>
+
+       * gnus.texi (NoCeM): Update.
+
+2000-10-17  Simon Josefsson  <simon@josefsson.org>
+
+       * gnus.texi (IMAP): Add.
+
+2000-10-05  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Windows Configuration): add examples; first example
+       suggested by Stein A. Strømme <stromme@mi.uib.no>.  (The actual
+       Lisp code is also from him.)
+
+2000-10-07  Dave Love  <fx@gnu.org>
+
+       * doclicense.texi: New file.
+
+2000-10-07 16:50:14  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * Makefile.in: Use install-info.
+
+2000-10-06 14:38:27  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * message.texi (Message Headers): Add.
+
+2000-10-04 09:23:49  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Article Hiding): Add.
+       (Using MIME): Add.
+
+2000-09-30  Simon Josefsson  <simon@josefsson.org>
+
+       * gnus.texi (Agent and IMAP): Add.
+       (Splitting in IMAP): Fix.
+
+2000-09-29  Simon Josefsson  <simon@josefsson.org>
+
+       * gnus.texi (Converting Kill Files): Fix URL.
+       (Posting Styles): Fix regexp.
+       (Mail Source Specifiers): Fix.
+
+2000-09-29 12:53:27  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * Makefile.in: A workaround for @ifnottex.
+
+2000-09-29 12:36:13  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi: Remove @c lines in the directory due to a bug in
+       makeinfo 1.68 (GNU texinfo 3.12).
+
+2000-09-22  Dave Love  <fx@gnu.org>
+
+       * message.texi, gnus.texi, emacs-mime.texi: Convert to GFDL.
+
+2000-09-20  John H. Palmieri  <palmieri@math.washington.edu>
+
+       * gnus.texi (Mail Source Customization): Document of
+       mail-source-incoming-file-prefix.
+
+2000-09-20  Simon Josefsson  <simon@josefsson.org>
+
+       * gnus.texi (IMAP): Add examples.
+
+2000-09-19  Kai Großjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (IMAP): Add pointer to description of ~/.authinfo file
+       format.
+
+2000-09-17  Felix Natter  <f.natter@ndh.net>
+
+       * gnusref.tex: New version.
+
+       * refcard.tex: New version.
+
+2000-09-17 18:03:52  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Article Hiding): Doc fix as suggested by Felix Natter
+       <fnatter@gmx.net>.
+
+2000-06-22  Michael Totschnig  <michaelt@supernet.ca>
+
+       * gnus.texi (Agent Basics): Doc fix.
+
+2000-09-14  Jason R. Mastaler  <jason@mastaler.com>
+
+       * gnus.texi (Mail Source Specifiers): Use $HOME.
+
+2000-08-14  Kai Grossjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Mail Source Specifiers): Replace `@paragraph' with
+       `@subsubheading'.
+
+2000-08-14  Kai Grossjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Mail Source Specifiers): Try to document the
+       interface to the functions called via (among others) the
+       `:function' keyword.
+
+2000-08-13 20:00:35  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Topic Commands): Fix typo.
+
+2000-08-13 20:20:56  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Topic Commands): Addition.
+
+2000-08-11  Kai Grossjohann  <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+       * gnus.texi (Expiring Mail): Extend documentation of variable
+       `nnmail-expiry-target' and of group parameter `expiry-target'.
+       Explain interaction between these.  Add Lisp example for setting
+       `nnmail-expiry-target'.
+
+2000-08-04  Andreas Oeldenberger  <andreas.oeldenberger@gmx.net>
+
+       * message.texi (Forwarding): Fix.
+
+2000-07-15  Simon Josefsson  <simon@josefsson.org>
+
+       * gnus.texi (nnimap-authinfo-file):
+       (gnus-invalid-group-regexp): Add.
+       (Mail Source Specifiers): Fix.
+       (IMAP): Fix.
+       (Agent Basics): Fix.
+
+2000-07-12 19:37:19  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Article Washing): Add keystroke `t'.
+
+2000-07-12 15:49:34  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * Makefile.in: Add EMACS. Test -x "$(MAKEINFO)" does not work.
+       Use sed instead of perl (suggested by Nick V. Pakoulin).
+
+2000-07-03 00:24:55  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Splitting Mail): Mention gnus-summary-respool-trace.
+       (Searching for Articles): Fix.
+       (Newest Features): Fix.
+
+2000-06-28  Simon Josefsson  <simon@josefsson.org>
+
+       * gnus.texi (Splitting in IMAP): Update.
+
+2000-05-19 15:18:32  Dmitry Yaitskov  <dimas@home.com>
+
+       * message.texi (Reply): Doc fix.
+
+2000-05-17 00:50:29  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Listing Groups): Addition.
+
+2000-05-16 21:46:40  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Misc Group Stuff): Addition.
+       (Article Washing): Ditto.
+
+2000-05-15 10:16:29  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Mail Source Specifiers): Update maildir.
+
+2000-05-07  Pavel Janik  <Pavel.Janik@inet.cz>
+
+       * gnus.texi: direntry added.
+
+       * message.texi: direntry added.
+
+       * emacs-mime.texi: direntry added.
+
+2000-05-02  Pavel Janik  <Pavel.Janik@inet.cz>
+
+       * gnus.texi (MIME comands): Spelling fix.
+
+2000-05-03 21:12:05  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Summary Mail Commands): Addition.
+       (Summary Post Commands): Ditto.
+
+2000-04-27  Dave Love  <fx@gnu.org>
+
+       * gnus.texi (Article Washing): Update x-face bit.
+
+2000-04-26  Florian Weimer  <fw@deneb.cygnus.argh.org>
+
+       * message.texi (Various Message Variables): Document
+       message-default-charset.
+
+       * emacs-mime.texi (Charset Translation): New section.
+
+2000-04-26 02:30:06  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Posting Styles): Addition.
+
+2000-04-24 17:09:17  Felix Natter  <f.natter@ndh.net>
+
+       * gnusref.tex: New version.
+
+       * refcard.tex: New version.
+
+2000-04-23 00:32:23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Thread Commands): Add keystrokes.
+       (Various Summary Stuff): Addition.
+
+2000-04-22 21:12:25  Alan Shutko  <ats@acm.org>
+
+       * Makefile.in: Add pdf support.
+
+2000-04-21 12:07:20  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Listing Groups): Addition.
+
+2000-04-21 13:45:52  Pavel Janik  <Pavel.Janik@inet.cz>
+
+       * gnus.texi (Mail Source Specifiers): Example for :plugged.
+
+2000-04-20 20:37:48  Pavel Janik  <Pavel.Janik@inet.cz>
+
+       * gnus.texi (Limiting): Fix.
+
+2000-04-20 20:32:40  Dmitry Yaitskov  <dimas@home.com>
+
+       * gnus.texi (Charsets): Typo fix.
+
+2000-03-19  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus.texi (IMAP): Addition.
+
+2000-03-13 17:44:59  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Process/Prefix): Addition.
+
+2000-02-04  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus.texi (IMAP): Fix.
+
+2000-01-27 18:06:35  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Remember): Addition.
+
+2000-01-21  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus.texi (Splitting in IMAP): Addition.
+       (Mail Source Specifiers): Add fetchflag setting in example.
+
+2000-01-08 08:10:04  Martin Bialasinski  <agr30+news@uni-koeln.de>
+
+       * gnus.texi (Mail and Post): Example.
+
+2000-01-08 07:46:13  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Customizing w3): New.
+
+2000-01-08 07:46:06  Hamish Macdonald  <hamishm@lucent.com>
+
+       * gnus.texi (Customizing w3): Example.
+
+2000-01-06 17:55:28  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Charsets): Addition.
+
+2000-01-05 15:58:48  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Mail Group Commands): Addition.
+       (Top): Added detailmenu.
+
+2000-01-03 01:31:02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (MIME Commands): Fix.
+
+2000-01-03  Karl Kleinpaste  <karl@justresearch.com>
+
+       * gnus.texi (Splitting in IMAP): Add '.' after @xref.
+
+2000-01-02 08:39:18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi: Closing paren.
+       Doc fix.
+
+1999-12-28  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus.texi (Article Hiding): Addition.
+       (Splitting in IMAP): Addition.
+
+1999-12-17 12:12:41  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Mail Source Specifiers): Addition.
+
+1999-12-13 23:47:50  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Mail Source Specifiers): Addition.
+
+1999-12-07 00:19:31  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Web Archive): Addition.
+
+1999-12-06 05:17:15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Slashdot): Addition.
+
+1999-12-05 00:54:28  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Mail Source Specifiers): Removed backslashes.
+
+1999-12-04 07:35:51  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Setting Process Marks): Addition.
+
+1999-12-04 05:09:46  Manoj Srivastava  <srivasta@golden-gryphon.com>
+
+       * gnus.texi: Use defface instead of face-spec-set.
+
+1999-12-04 02:31:25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (extension): Posting server fix.
+       Url update.
+
+1999-12-04 01:16:52  Yoshiki Hayashi  <t90553@m.ecc.u-tokyo.ac.jp>
+
+       * gnus.texi (group-buffer): Fix "theese".
+
+1999-12-04 01:13:51  Thomas Gellekum  <tg@ihf.rwth-aachen.de>
+
+       * gnus.texi (Height): Typo fix.
+
+1999-11-13  Adrian Aichner  <aichner@ecf.teradyne.com>
+
+       * xemacs.mak: New NMAKE file to support build and install of info
+       documentation on Windows NT, requiring the `texinfo' XEmacs
+       package.
+
+1999-12-03 00:02:11  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Other Gnus Versions): New.
+       (Gnus Versions): Made into own node.
+
+1999-12-02 00:00:00  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Paging the Article): Addition.
+       (History): Addition.
+
+1999-11-24  Carsten Leonhardt  <leo@arioch.oche.de>
+
+       * gnus.texi (Mail Source Specifiers): Mention maildir in the
+         overview and the possibility to use remote maildirs.
+
+1999-12-01 14:21:19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Topic Parameters): Addition.
+       (Summary Message Commands): New.
+       (Canceling and Superseding): Made into subsection.
+       (Charsets): Addition.
+
+1999-11-30 10:54:31  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Mail Source Specifiers): Add a note.
+
+1999-11-27 17:15:00  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi: Typo fixes and @sc.
+
+1999-11-26 16:59:29  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (On Writing Manuals): New.
+
+1999-11-23 17:23:37  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Mail Source Specifiers): Update.
+
+1999-11-23 05:07:59  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Web Archive): Add nnwarchive.
+
+1999-11-23 03:05:32  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Mail Source Specifiers): Add webmail.
+
+1999-11-19 12:15:23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Slashdot): Addition.
+
+1999-11-17  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus.texi (Finding the Parent): Fix example.
+
+1999-11-16 10:09:44  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi: Addition.
+       (present): Addition.
+
+1999-11-13  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus.texi (Mail Source Specifiers): Fix. Added documentation for
+       IMAP mail-source keywords `fetchflag' and `dontexpunge'.
+
+1999-11-12 18:00:56  Eli Zaretskii  <eliz@is.elta.co.il>
+
+       * gnus.texi (Fancy Mail Splitting): Fix @vars.
+
+1999-11-12 17:08:35  Gunnar Evermann  <ge204@eng.cam.ac.uk>
+
+       * gnus.texi (Splitting in IMAP): @@ fix.
+
+1999-11-12 08:17:49  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Mail Source Specifiers): Addition.
+
+1999-11-12 08:17:44  Ulf Betlehem  <flu@iki.fi>
+
+       * gnus.texi (Mail Source Specifiers): Example.
+
+1999-11-12 05:26:22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Slashdot): Addition.
+
+1999-11-11 04:32:57  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.texi (News Headers): Fix.
+
+       * gnus.texi (Browsing the Web): New.
+       (Slashdot): New.
+       (Ultimate): New.
+
+1999-11-10 11:32:00  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Archived Messages): Fix.
+
+1999-11-07 01:28:07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (MIME Commands): Addition.
+
+1999-11-06 23:09:31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Customizing Articles): Fix.
+
+1999-11-05 22:34:23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Posting Styles): Addition.
+
+1999-10-29  David S. Goldberg  <dsg@mitre.org>
+
+       * emacs-mime.texi (Customization): Document mm-inline-override-types.
+
+1999-10-23  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus.texi (Mail Source Specifiers): Add imap mail-source.
+       (IMAP): New subsection.
+       (SOUP): Typo.
+
+1999-09-27 16:07:31  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * emacs-mime.texi (New Viewers): Fix.
+
+1999-10-29  David S. Goldberg  <dsg@mitre.org>
+
+       * emacs-mime.texi (Customization): Document mm-inline-override-types.
+
+1999-09-25 10:58:17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.texi (Forwarding): Updated.
+
+       * emacs-mime.texi (New Viewers): New.
+
+1999-09-24 18:52:34  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Group Line Specification): Doc fix.
+
+1999-09-24 18:06:33  Bill White  <billw@wolfram.com>
+
+       * gnus.texi (Article Washing): Fix.
+
+1999-08-27 20:47:39  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Posting Styles): Doc fix.
+
+1999-08-27 18:51:42  Robin S. Socha  <robin@socha.net>
+
+       * gnus.texi: Typo fix.
+
+1999-08-27 15:09:01  Jim Meyering  <meyering@ascend.com>
+
+       * gnus.texi (The Active File): Typo fix.
+
+1999-08-27 15:00:23  Yoshiki Hayashi  <t90553@m.ecc.u-tokyo.ac.jp>
+
+       * gnus.texi (Generic Marking Commands): Typo fixes.
+
+1999-08-27 14:46:21  Lee Willis  <lee@gbdirect.co.uk>
+
+       * gnus.texi (Customizing Articles): More explanation.
+
+1999-07-10  Mike McEwan  <mike@lotusland.demon.co.uk>
+
+       * gnus.texi (More Threading): Document new variable
+       `gnus-sort-gathered-threads-function'.
+
+1999-07-30  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus.texi: Added `gnus-list-identifiers' stuff.
+
+1999-07-09 19:41:34  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Using MIME): Addition.
+       (Topic Commands): Addition.
+
+1999-07-06 05:37:46  Alexandre Oliva  <oliva@dcc.unicamp.br>
+
+       * gnus.texi (Fancy Mail Splitting): Document RESTRICT.
+
+1999-07-07 10:26:59  Robin S. Socha  <robin@socha.net>
+
+       * gnus.texi (Scoring Tips): Typo.
+
+1999-07-06 11:41:59  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Mail Source Specifiers): Fix.
+       (Mail Source Customization): Deleted obsolete vars.
+
+1999-07-05 05:16:55  Laura Conrad  <lconrad@world.std.com>
+
+       * gnus.texi (Mail in a Newsreader): Rewrite.
+
+1999-07-04 04:33:50  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Posting Styles): Fix.
+       (Mail in a Newsreader): New.
+
+1999-06-13 02:29:22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (MIME Commands): Addition.
+       (Article Miscellania): New.
+       (Customizing Articles): Addition.
+
+1999-06-12 00:13:25  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Comparing Mail Backends): Slight edits.
+
+1999-06-12 00:13:20  Karl Kleinpaste  <karl@justresearch.com>
+
+       * gnus.texi (Comparing Mail Backends): New.
+
+1999-06-11 21:47:22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Group Score): Doc fix.
+       (The Active File): Addition.
+       (Document Groups): Addition.
+
+1999-04-18  Didier Verna  <verna@inf.enst.fr>
+
+       * gnus.texi (Article treatment): document the new variable
+       `gnus-article-date-lapsed-new-header'.
+
+1999-04-26  Robert Bihlmeyer  <robbe@orcus.priv.at>
+
+       * gnus.texi (Posting Styles): Typo.
+
+1999-04-18 12:46:33  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Summary Score Commands): Typo.
+       (Choosing a Mail Backend): Addition.
+
+1999-04-18 09:24:51  Yoshiki Hayashi  <g740685@komaba.ecc.u-tokyo.ac.jp>
+
+       * gnus.texi (Startup Variables): Fix.
+
+1999-04-18 09:12:28  Starback  <starback@ling.uu.se>
+
+       * gnus.texi (Subscription Methods): Typo.
+
+1999-04-18 08:22:27  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Little Disk Space): Addition.
+
+1999-03-25  Erik Toubro Nielsen  <erik@ifad.dk>
+
+       * gnus.texi (gnus-thread-sort-functions). 'reverse' => 'not'.
+
+1999-04-17 10:21:01  Jack Twilley  <jmt+usenet@nycap.rr.com>
+
+       * gnus.texi (Fancy Mail Splitting): Addition.
+
+1999-04-07 06:13:08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Gnus Development): New.
+
+1999-03-06 20:12:50  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Generic Marking Commands): New.
+
+1999-03-01 16:41:42  Rob Browning  <rlb@cs.utexas.edu>
+
+       * gnus.texi (Score Variables): Clarify.
+
+1999-02-26  Andreas Jaeger  <aj@arthur.rhein-neckar.de>
+
+       * gnus.texi: Add ',' after @xrefs.
+
+1999-02-26 20:54:34  Jason R. Mastaler  <jason@4b.org>
+
+       * gnus.texi (Article Date): Added joke by Colin Rafferty
+       <colin@xemacs.org>.
+
+1999-02-26 08:26:10  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Mail Source Specifiers): Fix.
+
+Thu Feb 25 00:28:49 1999  Shenghuo ZHU  <zsh@cs.rochester.edu>
+
+       * gnus.texi (Category Syntax): Typo fix.
+
+1999-02-25  Didier Verna  <verna@inf.enst.fr>
+
+       * gnus.texi (Fancy Mail Splitting): update the doc about the new syntax
+       `(! FUNC SPLIT)'.
+
+1999-02-21 11:42:54  Vladimir Volovich  <vvv@vvv.vsu.ru>
+
+       * Makefile.in (.texi): Fix check for MAKEINFO.
+
+1999-02-20 17:33:55  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Mail Source Specifiers): Addition.
+
+1999-02-11 19:19:02  Carsten Leonhardt  <leo@arioch.oche.de>
+
+       * gnus.texi (Mail Source Specifiers): Document maildir.
+
+1999-02-09 16:21:35  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Charsets): New.
+
+1999-02-04 03:45:15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * emacs-mime.texi (Conversion): New.
+
+1999-02-03 03:04:18  Miguel de Icaza  <miguel@nuclecu.unam.mx>
+
+       * gnus.texi (Fetching Mail): Typo fix.
+
+1999-02-02 22:28:42  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Mail Source Specifiers): Addition.
+
+1999-02-01 21:05:18  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Article Hiding): Addition.
+
+1999-01-28 08:08:28  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Washing Mail): Addition.
+
+1999-01-27 14:30:39  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Article Washing): Addition.
+
+1999-01-25 04:24:01  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.texi (MIME): New.
+
+       * gnus.texi (Mail Sources): New.
+       (Mail Source Specifiers): New.
+       (Mail Source Customization): New.
+       (Fetching Mail): New.
+
+1999-01-23 09:47:16  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Article Washing): Removed.
+       (Customizing Articles): Addition.
+
+1999-01-16 20:36:48  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Customizing Articles): Rewrite.
+       Remove mention of gnus-article-display-hook.
+
+1999-01-12 07:14:12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (To From Newsgroups): Addition.
+
+1999-01-03 13:54:51  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Group Agent Commands): Addition.
+
+1998-12-19 23:29:50  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Splitting Mail): Addition.
+
+1998-12-13 08:54:07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.texi (Insertion): Add.
+
+1998-12-03 13:34:48  James Troup  <james@nocrew.org>
+
+       * gnus.texi (MIME Commands): Typo fix.
+
+1998-12-03  Didier Verna  <verna@inf.enst.fr>
+
+       * gnus.texi (Group Parameters): update for the posting-style group
+       parameter.
+
+1998-12-02 01:04:22  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Emacsen): Addition.
+       (Picon Useless Configuration): Addition.
+
+1998-12-01 00:27:04  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * emacs-mime.texi (rfc2045): New.
+
+1998-11-29 00:03:43  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * emacs-mime.texi (Composing): New chapter.
+
+1998-11-25  Karl Eichwalder  <ke@gnu.franken.de>
+
+       * Makefile.in (install): Remove emacs-info, add emacs-mime.
+
+1998-11-25 10:56:08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (To From Newsgroups): Addition.
+       (Anything Groups): Addition.
+       (Article Washing): Addition.
+       (MIME Commands): Addition.
+
+1998-11-19 04:05:15  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Really Various Summary Commands): Addition.
+
+1998-11-18 00:52:46  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (MIME Commands): Addition.
+       (Expiring Mail): Addition.
+
+1998-11-08 03:37:42  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus.texi (Topic Commands): New expiry command.  Reordered.
+
+1998-11-07 17:18:07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Gnus Reference Guide): Renamed.
+
+1998-10-26 22:03:08  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Article Washing): Fix.
+       (MIME Commands): Change.
+
+1998-10-25 01:51:56  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Headers): Addition.
+
+1998-10-24 08:37:12  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Summary Buffer Lines): Addition.
+       (To): New.
+       (To): Addition.
+
+1998-10-15 18:15:34  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus.texi (Group Info): Must be list of ranges.
+
+1998-10-19 01:27:26  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Article Washing): Addition.
+
+1998-10-18 00:20:58  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Changing Servers): Addition.
+
+1998-10-17 21:34:57  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Windows Configuration): Addition.
+
+1998-10-01 07:55:35  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Splitting Mail): Fix.
+       (Washing Mail): Fix.
+
+1998-09-30 05:54:45  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Selecting a Group): Addition.
+
+1998-09-26 19:33:58  Simon Josefsson  <jas@pdc.kth.se>
+
+       * gnus.texi (Optional Backend Functions): New item,
+       nnchoke-request-set-mark.
+
+1998-09-13 08:58:56  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * dir (File): Updated.
+
+1998-09-12 08:53:05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * emacs-mime.texi: New file.
+
+       * gnus.texi (Misc Article): Addition.
+
+1998-09-11 08:52:50  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Group Score Commands): Fix.
+       (Saving Articles): Fix.
+       (Agent Expiry): Fix.
+       (Using MIME): Change.
+
+1998-09-10 03:19:14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Windows Configuration): Addition.
+
+1998-09-06  Mike McEwan  <mike@lotusland.demon.co.uk>
+
+       * gnus.texi (Category Syntax): Added doc about agent categories
+       and download scoring.
+
+1998-09-05 17:36:14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Sorting Groups): Change.
+       (Various Summary Stuff): Addition.
+
+1998-09-04 00:40:07  David S. Goldberg  <dsg@mitre.org>
+
+       * gnus.texi (Article Hiding): Verify.
+
+1998-08-31 11:46:57  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Mail Folders): Addition.
+       (Group Parameters): Addition.
+       (MIME Commands): New.
+
+1998-08-27 07:29:17  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus.texi (Mail Folders): Addition.
+
+  Copyright (C) 1998-2016 Free Software Foundation, Inc.
+
+  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 3, 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.  If not, see <http://www.gnu.org/licenses/>.
+
+;; Local Variables:
+;; coding: utf-8
+;; fill-column: 79
+;; add-log-time-zone-rule: t
+;; End:
diff --git a/xemacs-packages/gnus/texi/Makefile.in b/xemacs-packages/gnus/texi/Makefile.in
new file mode 100644 (file)
index 0000000..5bbe579
--- /dev/null
@@ -0,0 +1,273 @@
+prefix = @prefix@
+datarootdir = @datarootdir@
+infodir = @info_dir@
+srcdir = @srcdir@
+subdir = texi
+top_srcdir = @top_srcdir@
+
+VPATH=$(srcdir)
+TEXI2DVI=texi2dvi
+TEXI2PDF=texi2pdf
+MAKEINFO=@MAKEINFO@
+EMACS=@EMACS@
+EMACSCOMP=$(EMACS) -batch -q -no-site-file
+EMACSINFO=$(EMACSCOMP) -l $(srcdir)/infohack.el -f batch-makeinfo
+PDFLATEX=pdflatex
+LATEX=@LATEX@
+DVIPS=dvips
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+SHELL = /bin/sh
+PAPERTYPE=a4
+INFO_DEPS=gnus message emacs-mime sieve epa auth sasl
+REFCARD=gnus-refcard
+LOGO=gnus-logo
+GZIP_PROG = @GZIP_PROG@
+COMPRESS_INSTALL = @COMPRESS_INSTALL@
+
+all: $(INFO_DEPS)
+
+# please modify this for all the web manual targets
+webhack: clean
+       $(MAKE) pdf MAKEINFO_OPTS="-DWEBHACKDEVEL $(MAKEINFO_OPTS)"
+
+most: texi2latex.elc latex latexps
+
+.SUFFIXES: .texi .dvi .ps .pdf .latexi .dvi-x .pdf-x
+
+.texi:
+       rm -f $@{,-[0-9],.info,.info-[0-9]}; \
+       if test "x$(MAKEINFO)" != "xno" ; then \
+         LC_ALL=C $(MAKEINFO) -I $(srcdir) --enable-encoding --no-split $<; \
+       else \
+         $(EMACSINFO) $<; \
+       fi
+
+# Files included in gnus.texi
+gnus.texi: gnus-faq.texi gnus-news.texi
+
+# FIXME: A cvs commit script could automatically create it.
+GNUS-NEWS:     gnus-news.texi gnus-news.el
+       $(EMACSCOMP) -l $(srcdir)/gnus-news.el -f batch-gnus-news $< $@
+       mv $@ ../$@
+
+dvi: gnus.dvi message.dvi $(REFCARD).dvi emacs-mime.dvi sieve.dvi epa.dvi auth.dvi sasl.dvi
+
+pdf: gnus.pdf message.pdf $(REFCARD).pdf emacs-mime.pdf sieve.pdf epa.pdf auth.pdf sasl.pdf
+
+.texi.dvi :
+       sed -e '/@iflatex/,/@end iflatex/d' $< > gnustmp.texi
+       $(TEXI2DVI) -I $(srcdir) gnustmp.texi
+       cp gnustmp.dvi $*.dvi
+       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 -f gnustmp.*
+
+$(LOGO).pdf:   $(LOGO).eps
+       epstopdf $< --outfile=$@
+
+$(REFCARD).dvi: $(REFCARD).tex $(LOGO).eps
+       TEXINPUTS=$(srcdir):$$TEXINPUTS:: $(LATEX) $(REFCARD).tex
+
+$(REFCARD).pdf: $(REFCARD).tex $(LOGO).pdf
+       TEXINPUTS=$(srcdir):$$TEXINPUTS:: $(PDFLATEX) $(REFCARD).tex
+
+gnus-booklet.dvi: $(REFCARD).tex $(LOGO).eps
+       if [ "$(PAPERTYPE)" == a4 ]; then \
+         TEXINPUTS=$(srcdir):$$TEXINPUTS:: \
+          $(LATEX) '\def\booklettrue{}\input{$(REFCARD)}' ;\
+       else \
+         TEXINPUTS=$(srcdir):$$TEXINPUTS:: \
+          $(LATEX) '\def\booklettrue{}\def\letterpapertrue{}\input{$(REFCARD)}' ;\
+       fi
+       mv $(REFCARD).dvi $@
+
+gnus-booklet.pdf: $(REFCARD).tex  $(LOGO).pdf
+       if [ "$(PAPERTYPE)" == a4 ]; then \
+         TEXINPUTS=$(srcdir):$$TEXINPUTS:: \
+          $(PDFLATEX) -jobname=gnus-booklet '\def\booklettrue{}\input{$(REFCARD)}' ;\
+       else \
+         TEXINPUTS=$(srcdir):$$TEXINPUTS:: \
+          $(PDFLATEX) -jobname=gnus-booklet '\def\booklettrue{}\def\letterpapertrue{}\input{$(REFCARD)}' ;\
+       fi
+
+almost-clean:
+       rm -f *.[cgk]idx *.aux *.cp *.cps *.dvi *.dvi-x *.fn *.ky       \
+       *.kys *.latexi *.log *.orig *.pdf *.pdf-x *.pg *.rej            \
+       *.tmplatexi *.toc *.tp *.vr gnus.*.bak gnus.[cgk]ind gnus.idx   \
+       gnus.ilg gnus.ind gnus.latexi*~* gnus.out gnus.tmplatexi1       \
+       gnustmp.texi picons.tex smiley.tex texput.log thumb*.png        \
+       thumbdta.tex xface.tex *.tpt gnus-manual-*.pdf gnus-manual-*.ps.gz
+
+makeinfo:
+       LC_ALL=C makeinfo --enable-encoding --no-split gnus.texi
+       LC_ALL=C makeinfo --enable-encoding --no-split message.texi
+
+texi2latex.elc: texi2latex.el
+       srcdir=$(srcdir)/../lisp $(EMACSCOMP) -l $(srcdir)/../lisp/dgnushack.el --eval '(byte-compile-file "$(srcdir)/texi2latex.el")'
+
+latex: gnus.latexi gnus-faq.latexi message.latexi emacs-mime.latexi sieve.latexi epa.latexi auth.latexi sasl.latexi gnus-news.latexi
+
+gnus.latexi gnus-faq.latexi message.latexi emacs-mime.latexi sieve.latexi epa.latexi auth.latexi sasl.latexi gnus-news.latexi: $(srcdir)/gnus.texi $(srcdir)/gnus-faq.texi $(srcdir)/message.texi $(srcdir)/emacs-mime.texi $(srcdir)/sieve.texi $(srcdir)/epa.texi $(srcdir)/sasl.texi $(srcdir)/gnus-news.texi texi2latex.elc
+       srcdir=$(srcdir) $(EMACSCOMP) -l ./texi2latex.elc -f latexi-translate
+
+.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.tmplatexi
+       cat $(srcdir)/postamble.tex >> gnus.tmplatexi
+       TEXINPUTS=$(srcdir):$$TEXINPUTS $(PDFLATEX) gnus.tmplatexi
+       #thumbpdf gnus.pdf
+       #TEXINPUTS=$(srcdir):$$TEXINPUTS $(PDFLATEX) gnus.tmplatexi
+       mv gnus.pdf $@
+
+latexps: gnus.dvi-x
+       TEXPICTS=$(srcdir) $(DVIPS) -t a4 -f $< > gnus.ps
+
+latexpdf: 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_PROG) -c > $@
+
+gnus-manual-standard.ps.gz: gnus-manual-standard.dvi-x
+       TEXPICTS=$(srcdir) $(DVIPS) -t letter -f $< | $(GZIP_PROG) -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:
+       scp gnus-manual-*.ps.gz gnus-manual-*.pdf www@quimby:html/gnus/documents
+
+clean: almost-clean
+       @for file in $(INFO_DEPS); do \
+         echo "rm -f $$file{,-[0-9]}"; \
+         rm -f $$file{,-[0-9]}; \
+       done
+       rm -f gnus.dvi gnus.ps texi2latex.elc
+       rm -f gnus-manual-a4.* gnus-manual-standard.*
+
+distclean: clean
+       @for file in $(INFO_DEPS); do \
+         echo "rm -f $$file{,-[0-9],.info,.info-[0-9]}"; \
+         rm -f $$file{,-[0-9],.info,.info-[0-9]}; \
+       done
+       rm -f *.orig *.rej *.elc *~ Makefile
+       rm -f gnusconfig.tex
+
+install: $(INFO_DEPS)
+       $(SHELL) $(top_srcdir)/mkinstalldirs "$(DESTDIR)$(infodir)"
+       @for file in $(INFO_DEPS); do \
+         rm -f "$(DESTDIR)$(infodir)"/$$file{,-[0-9],.info,.info-[0-9]}; \
+         rm -f "$(DESTDIR)$(infodir)"/$$file{,-[0-9],.info,.info-[0-9]}.gz; \
+         for ifile in `echo $$file.info $$file.info-[0-9]`; do \
+           if test -f $$ifile; then \
+             echo "$(INSTALL_DATA) $$ifile \"$(DESTDIR)$(infodir)/$$ifile\""; \
+             $(INSTALL_DATA) $$ifile "$(DESTDIR)$(infodir)/$$ifile"; \
+             if test $(COMPRESS_INSTALL) = yes -a -n "$(GZIP_PROG)"; then \
+               $(GZIP_PROG) -9n "$(DESTDIR)$(infodir)/$$ifile"; \
+             fi;\
+           else : ; fi; \
+         done; \
+       done
+       @if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then \
+         for file in $(INFO_DEPS); do \
+           echo "install-info --info-dir=\"$(DESTDIR)$(infodir)\" \"$(DESTDIR)$(infodir)/$$file.info\"";\
+           install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$$file.info" || :;\
+         done; \
+       else : ; fi
+
+uninstall:
+       @if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then \
+         for file in $(INFO_DEPS); do \
+           echo "install-info --delete --info-dir=\"$(DESTDIR)$(infodir)\" \"$(DESTDIR)$(infodir)/$$file.info\"";\
+           install-info --delete --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$$file.info" || :;\
+         done; \
+       else : ; fi
+       @for file in $(INFO_DEPS); do \
+         echo "rm -f \"$(DESTDIR)$(infodir)\"/$$file{,-[0-9],.info,.info-[0-9]}"; \
+         rm -f "$(DESTDIR)$(infodir)"/$$file{,-[0-9],.info,.info-[0-9]}; \
+         echo "rm -f \"$(DESTDIR)$(infodir)\"/$$file{,-[0-9],.info,.info-[0-9]}.gz"; \
+         rm -f "$(DESTDIR)$(infodir)"/$$file{,-[0-9],.info,.info-[0-9]}.gz; \
+       done
+
+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
+       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 almost-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
+
+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/xemacs-packages/gnus/texi/auth.texi b/xemacs-packages/gnus/texi/auth.texi
new file mode 100644 (file)
index 0000000..b769653
--- /dev/null
@@ -0,0 +1,567 @@
+\input texinfo                  @c -*-texinfo-*-
+
+@include gnus-overrides.texi
+
+@set VERSION 0.3
+
+@setfilename auth.info
+@settitle Emacs auth-source Library @value{VERSION}
+@include docstyle.texi
+
+@copying
+This file describes the Emacs auth-source library.
+
+Copyright @copyright{} 2008--2016 Free Software Foundation, Inc.
+
+@quotation
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 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''.
+
+(a) The FSF's Back-Cover Text is: ``You have the freedom to copy and
+modify this GNU manual.''
+@end quotation
+@end copying
+
+@dircategory Emacs lisp libraries
+@direntry
+* Auth-source: (auth).          The Emacs auth-source library.
+@end direntry
+
+@titlepage
+@ifset WEBHACKDEVEL
+@title Emacs auth-source Library (DEVELOPMENT VERSION)
+@end ifset
+@ifclear WEBHACKDEVEL
+@title Emacs auth-source Library
+@end ifclear
+@author by Ted Zlatanov
+@page
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+
+@contents
+
+@ifnottex
+@node Top
+@top Emacs auth-source
+This manual describes the Emacs auth-source library.
+
+It is a way for multiple applications to share a single configuration
+(in Emacs and in files) for user convenience.
+
+@insertcopying
+
+@menu
+* Overview::                    Overview of the auth-source library.
+* Help for users::
+* Multiple GMail accounts with Gnus::
+* Secret Service API::
+* Help for developers::
+* GnuPG and EasyPG Assistant Configuration::
+* GNU Free Documentation License::  The license for this documentation.
+* Index::
+* Function Index::
+* Variable Index::
+@end menu
+@end ifnottex
+
+@node Overview
+@chapter Overview
+
+The auth-source library is simply a way for Emacs and Gnus, among
+others, to answer the old burning question ``What are my user name and
+password?''
+
+(This is different from the old question about burning ``Where is the
+fire extinguisher, please?''.)
+
+The auth-source library supports more than just the user name or the
+password (known as the secret).
+
+Similarly, the auth-source library supports multiple storage backend,
+currently either the classic ``netrc'' backend, examples of which you
+can see later in this document, or the Secret Service API@.  This is
+done with EIEIO-based backends and you can write your own if you want.
+
+@node Help for users
+@chapter Help for users
+
+``Netrc'' files are a de facto standard.  They look like this:
+@example
+machine @var{mymachine} login @var{myloginname} password @var{mypassword} port @var{myport}
+@end example
+
+The @code{machine} is the server (either a DNS name or an IP address).
+It's known as @var{:host} in @code{auth-source-search} queries.  You
+can also use @code{host}.
+
+The @code{port} is the connection port or protocol.  It's known as
+@var{:port} in @code{auth-source-search} queries.
+
+The @code{user} is the user name.  It's known as @var{:user} in
+@code{auth-source-search} queries.  You can also use @code{login} and
+@code{account}.
+
+You can use spaces inside a password or other token by surrounding the
+token with either single or double quotes.
+
+You can use apostrophes inside a password or other token by
+surrounding it with double quotes, e.g., @code{"he'llo"}. Similarly you
+can use double quotes inside a password or other token by surrounding
+it with apostrophes, e.g., @code{'he"llo'}. You can't mix both (so a
+password or other token can't have both apostrophes and double quotes).
+
+All this is optional. You could just say (but we don't recommend it,
+we're just showing that it's possible)
+
+@example
+password @var{mypassword}
+@end example
+
+to use the same password everywhere.  Again, @emph{DO NOT DO THIS} or
+you will be pwned as the kids say.
+
+``Netrc'' files are usually called @file{.authinfo} or @file{.netrc};
+nowadays @file{.authinfo} seems to be more popular and the auth-source
+library encourages this confusion by accepting both, as you'll see
+later.
+
+If you have problems with the search, set @code{auth-source-debug} to
+@code{'trivia} and see what host, port, and user the library is
+checking in the @file{*Messages*} buffer.  Ditto for any other
+problems, your first step is always to see what's being checked.  The
+second step, of course, is to write a blog entry about it and wait for
+the answer in the comments.
+
+You can customize the variable @code{auth-sources}.  The following may
+be needed if you are using an older version of Emacs or if the
+auth-source library is not loaded for some other reason.
+
+@lisp
+(require 'auth-source)             ;; probably not necessary
+(customize-variable 'auth-sources) ;; optional, do it once
+@end lisp
+
+@defvar auth-sources
+
+The @code{auth-sources} variable tells the auth-source library where
+your netrc files or Secret Service API collection items live for a
+particular host and protocol.  While you can get fancy, the default
+and simplest configuration is:
+
+@lisp
+;;; old default: required :host and :port, not needed anymore
+(setq auth-sources '((:source "~/.authinfo.gpg" :host t :port t)))
+;;; mostly equivalent (see below about fallbacks) but shorter:
+(setq auth-sources '((:source "~/.authinfo.gpg")))
+;;; even shorter and the @emph{default}:
+(setq auth-sources '("~/.authinfo.gpg" "~/.authinfo" "~/.netrc"))
+;;; use the Secrets API @var{Login} collection
+;;; (@pxref{Secret Service API})
+(setq auth-sources '("secrets:Login"))
+@end lisp
+
+By adding multiple entries to @code{auth-sources} with a particular
+host or protocol, you can have specific netrc files for that host or
+protocol.  Usually this is unnecessary but may make sense if you have
+shared netrc files or some other unusual setup (90% of Emacs users
+have unusual setups and the remaining 10% are @emph{really} unusual).
+
+Here's a mixed example using two sources:
+
+@lisp
+(setq auth-sources '((:source (:secrets default)
+                      :host "myserver" :user "joe")
+                     "~/.authinfo.gpg"))
+@end lisp
+
+@end defvar
+
+If you don't customize @code{auth-sources}, you'll have to live with
+the defaults: the unencrypted netrc file @file{~/.authinfo} will be
+used for any host and any port.
+
+If that fails, any host and any port are looked up in the netrc file
+@file{~/.authinfo.gpg}, which is a GnuPG encrypted file (@pxref{GnuPG
+and EasyPG Assistant Configuration}).
+
+Finally, the unencrypted netrc file @file{~/.netrc} will be used for
+any host and any port.
+
+The typical netrc line example is without a port.
+
+@example
+machine YOURMACHINE login YOU password YOURPASSWORD
+@end example
+
+This will match any authentication port.  Simple, right?  But what if
+there's a SMTP server on port 433 of that machine that needs a
+different password from the IMAP server?
+
+@example
+machine YOURMACHINE login YOU password SMTPPASSWORD port 433
+machine YOURMACHINE login YOU password GENERALPASSWORD
+@end example
+
+For url-auth authentication (HTTP/HTTPS), you need to put this in your
+netrc file:
+
+@example
+machine yourmachine.com:80 port http login testuser password testpass
+@end example
+
+This will match any realm and authentication method (basic or digest)
+over HTTP@.  HTTPS is set up similarly.  If you want finer controls,
+explore the url-auth source code and variables.
+
+For Tramp authentication, use:
+
+@example
+machine yourmachine.com port scp login testuser password testpass
+@end example
+
+Note that the port denotes the Tramp connection method.  When you
+don't use a port entry, you match any Tramp method, as explained
+earlier.  Since Tramp has about 88 connection methods, this may be
+necessary if you have an unusual (see earlier comment on those) setup.
+
+@node Multiple GMail accounts with Gnus
+@chapter Multiple GMail accounts with Gnus
+
+For multiple GMail accounts with Gnus, you have to make two nnimap
+entries in your @code{gnus-secondary-select-methods} with distinct
+names:
+
+@example
+(setq gnus-secondary-select-methods '((nnimap "gmail"
+                                         (nnimap-address "imap.gmail.com"))
+                                      (nnimap "gmail2"
+                                         (nnimap-address "imap.gmail.com"))))
+@end example
+
+Your netrc entries will then be:
+
+@example
+machine gmail login account@@gmail.com password "account password" port imap
+machine gmail2 login account2@@gmail.com password "account2 password" port imap
+@end example
+
+@node Secret Service API
+@chapter Secret Service API
+
+The @dfn{Secret Service API} is a standard from
+@uref{http://www.freedesktop.org/wiki/Specifications/secret-storage-spec,,freedesktop.org}
+to securely store passwords and other confidential information.  This
+API is implemented by system daemons such as the GNOME Keyring and the
+KDE Wallet (these are GNOME and KDE packages respectively and should
+be available on most modern GNU/Linux systems).
+
+The auth-source library uses the @file{secrets.el} library to connect
+through the Secret Service API@.  You can also use that library in
+other packages, it's not exclusive to auth-source.
+
+@defvar secrets-enabled
+After loading @file{secrets.el}, a non-@code{nil} value of this
+variable indicates the existence of a daemon providing the Secret
+Service API.
+@end defvar
+
+@deffn Command secrets-show-secrets
+This command shows all collections, items, and their attributes.
+@end deffn
+
+The atomic objects managed by the Secret Service API are @dfn{secret
+items}, which contain things an application wishes to store securely,
+like a password.  Secret items have a label (a name), the @dfn{secret}
+(which is the string we want, like a password), and a set of lookup
+attributes.  The attributes can be used to search and retrieve a
+secret item at a later date.
+
+Secret items are grouped in @dfn{collections}.  A collection is
+sometimes called a @samp{keyring} or @samp{wallet} in GNOME Keyring
+and KDE Wallet but it's the same thing, a group of secrets.
+Collections are personal and protected so only the owner can open them.
+
+The most common collection is called @code{"login"}.
+
+A collection can have an alias.  The alias @code{"default"} is
+commonly used so the clients don't have to know the specific name of
+the collection they open.  Other aliases are not supported yet.
+Since aliases are globally accessible, set the @code{"default"} alias
+only when you're sure it's appropriate.
+
+@defun secrets-list-collections
+This function returns all the collection names as a list.
+@end defun
+
+@defun secrets-set-alias collection alias
+Set @var{alias} as alias of collection labeled @var{collection}.
+Currently only the alias @code{"default"} is supported.
+@end defun
+
+@defun secrets-get-alias alias
+Return the collection name @var{alias} is referencing to.
+Currently only the alias @code{"default"} is supported.
+@end defun
+
+Collections can be created and deleted by the functions
+@code{secrets-create-collection} and @code{secrets-delete-collection}.
+Usually, this is not done from within Emacs.  Do not delete standard
+collections such as @code{"login"}.
+
+The special collection @code{"session"} exists for the lifetime of the
+corresponding client session (in our case, Emacs's lifetime).  It is
+created automatically when Emacs uses the Secret Service interface and
+it is deleted when Emacs is killed.  Therefore, it can be used to
+store and retrieve secret items temporarily.  The @code{"session"}
+collection is better than a persistent collection when the secret
+items should not live longer than Emacs.  The session collection can
+be specified either by the string @code{"session"}, or by @code{nil},
+whenever a collection parameter is needed in the following functions.
+
+@defun secrets-list-items collection
+Returns all the item labels of @var{collection} as a list.
+@end defun
+
+@defun secrets-create-item collection item password &rest attributes
+This function creates a new item in @var{collection} with label
+@var{item} and password @var{password}.  @var{attributes} are
+key-value pairs set for the created item.  The keys are keyword
+symbols, starting with a colon.  Example:
+
+@example
+;;; The session "session", the label is "my item"
+;;; and the secret (password) is "geheim"
+(secrets-create-item "session" "my item" "geheim"
+ :method "sudo" :user "joe" :host "remote-host")
+@end example
+@end defun
+
+@defun secrets-get-secret collection item
+Return the secret of item labeled @var{item} in @var{collection}.
+If there is no such item, return @code{nil}.
+@end defun
+
+@defun secrets-delete-item collection item
+This function deletes item @var{item} in @var{collection}.
+@end defun
+
+The lookup attributes, which are specified during creation of a
+secret item, must be a key-value pair.  Keys are keyword symbols,
+starting with a colon; values are strings.  They can be retrieved
+from a given secret item and they can be used for searching of items.
+
+@defun secrets-get-attribute collection item attribute
+Returns the value of key @var{attribute} of item labeled @var{item} in
+@var{collection}.  If there is no such item, or the item doesn't own
+this key, the function returns @code{nil}.
+@end defun
+
+@defun secrets-get-attributes collection item
+Return the lookup attributes of item labeled @var{item} in
+@var{collection}.  If there is no such item, or the item has no
+attributes, it returns @code{nil}.  Example:
+
+@example
+(secrets-get-attributes "session" "my item")
+     @result{} ((:user . "joe") (:host ."remote-host"))
+@end example
+@end defun
+
+@defun secrets-search-items collection &rest attributes
+Search for the items in @var{collection} with matching
+@var{attributes}.  The @var{attributes} are key-value pairs, as used
+in @code{secrets-create-item}.  Example:
+
+@example
+(secrets-search-items "session" :user "joe")
+     @result{} ("my item" "another item")
+@end example
+@end defun
+
+The auth-source library uses the @file{secrets.el} library and thus
+the Secret Service API when you specify a source matching
+@code{"secrets:COLLECTION"}.  For instance, you could use
+@code{"secrets:session"} to use the @code{"session"} collection, open only
+for the lifetime of Emacs.  Or you could use @code{"secrets:Login"} to
+open the @code{"Login"} collection.  As a special case, you can use the
+symbol @code{default} in @code{auth-sources} (not a string, but a
+symbol) to specify the @code{"default"} alias.  Here is a contrived
+example that sets @code{auth-sources} to search three collections and
+then fall back to @file{~/.authinfo.gpg}.
+
+@example
+(setq auth-sources '(default
+                     "secrets:session"
+                     "secrets:Login"
+                     "~/.authinfo.gpg"))
+@end example
+
+@node Help for developers
+@chapter Help for developers
+
+The auth-source library lets you control logging output easily.
+
+@defvar auth-source-debug
+Set this variable to @code{'trivia} to see lots of output in
+@file{*Messages*}, or set it to a function that behaves like
+@code{message} to do your own logging.
+@end defvar
+
+The auth-source library only has a few functions for external use.
+
+@defun auth-source-search &rest spec &key type max host user port secret require create delete &allow-other-keys
+This function searches (or modifies) authentication backends according
+to @var{spec}.  See the function's doc-string for details.
+@c TODO more details.
+@end defun
+
+Let's take a look at an example of using @code{auth-source-search}
+from Gnus's @code{nnimap.el}.
+
+@example
+(defun nnimap-credentials (address ports)
+  (let* ((auth-source-creation-prompts
+          '((user  . "IMAP user at %h: ")
+            (secret . "IMAP password for %u@@%h: ")))
+         (found (nth 0 (auth-source-search :max 1
+                                           :host address
+                                           :port ports
+                                           :require '(:user :secret)
+                                           :create t))))
+    (if found
+        (list (plist-get found :user)
+              (let ((secret (plist-get found :secret)))
+                (if (functionp secret)
+                    (funcall secret)
+                  secret))
+              (plist-get found :save-function))
+      nil)))
+@end example
+
+This call requires the user and password (secret) to be in the
+results.  It also requests that an entry be created if it doesn't
+exist already.  While the created entry is being assembled, the shown
+prompts will be used to interact with the user.  The caller can also
+pass data in @code{auth-source-creation-defaults} to supply defaults
+for any of the prompts.
+
+Note that the password needs to be evaluated if it's a function.  It's
+wrapped in a function to provide some security.
+
+Later, after a successful login, @code{nnimap.el} calls the
+@code{:save-function} like so:
+
+@example
+(when (functionp (nth 2 credentials))
+   (funcall (nth 2 credentials)))
+@end example
+
+This will work whether the @code{:save-function} was provided or not.
+@code{:save-function} will be provided only when a new entry was
+created, so this effectively says ``after a successful login, save the
+authentication information we just used, if it was newly created.''
+
+After the first time it's called, the @code{:save-function} will not
+run again (but it will log something if you have set
+@code{auth-source-debug} to @code{'trivia}).  This is so it won't ask
+the same question again, which is annoying.  This is so it won't ask
+the same question again, which is annoying.  This is so it won't ask
+the same question again, which is annoying.
+
+So the responsibility of the API user that specified @code{:create t}
+is to call the @code{:save-function} if it's provided.
+
+@defun auth-source-delete &rest spec &key delete &allow-other-keys
+This function deletes entries matching @var{spec} from the
+authentication backends.  It returns the entries that were deleted.
+The backend may not actually delete the entries.
+@end defun
+
+@defun auth-source-forget spec
+This function forgets any cached data that exactly matches @var{spec}.
+It returns @code{t} if it forget some data, and @code{nil} if no
+matching data was found.
+@end defun
+
+@defun auth-source-forget+ &rest spec &allow-other-keys
+This function forgets any cached data matching @var{spec}.
+It returns the number of items forgotten.
+@end defun
+
+@node GnuPG and EasyPG Assistant Configuration
+@appendix GnuPG and EasyPG Assistant Configuration
+
+If the @code{auth-sources} variable contains @file{~/.authinfo.gpg}
+before @file{~/.authinfo}, the auth-source library will try to
+read the GnuPG encrypted @file{.gpg} file first, before
+the unencrypted file.
+
+In Emacs 23 or later there is an option @code{auto-encryption-mode} to
+automatically decrypt @file{*.gpg} files.  It is enabled by default.
+If you are using earlier versions of Emacs, you will need:
+
+@lisp
+(require 'epa-file)
+(epa-file-enable)
+@end lisp
+
+If you want your GnuPG passwords to be cached, set up @code{gpg-agent}
+or EasyPG Assistant
+(@pxref{Caching Passphrases, , Caching Passphrases, epa}).
+
+To quick start, here are some questions:
+
+@enumerate
+@item
+Do you use GnuPG version 2 instead of GnuPG version 1?
+@item
+Do you use symmetric encryption rather than public key encryption?
+@item
+Do you want to use gpg-agent?
+@end enumerate
+
+Here are configurations depending on your answers:
+
+@multitable {111} {222} {333} {configuration configuration configuration}
+@item @b{1} @tab @b{2} @tab @b{3} @tab Configuration
+@item Yes @tab Yes @tab Yes @tab Set up gpg-agent.
+@item Yes @tab Yes @tab No @tab You can't, without gpg-agent.
+@item Yes @tab No @tab Yes @tab Set up gpg-agent.
+@item Yes @tab No @tab No @tab You can't, without gpg-agent.
+@item No @tab Yes @tab Yes @tab Set up elisp passphrase cache.
+@item No @tab Yes @tab No @tab Set up elisp passphrase cache.
+@item No @tab No @tab Yes @tab Set up gpg-agent.
+@item No @tab No @tab No @tab You can't, without gpg-agent.
+@end multitable
+
+To set up gpg-agent, follow the instruction in GnuPG manual
+(@pxref{Invoking GPG-AGENT, , Invoking GPG-AGENT, gnupg}).
+
+To set up elisp passphrase cache, set
+@code{epa-file-cache-passphrase-for-symmetric-encryption}.
+
+@node GNU Free Documentation License
+@appendix GNU Free Documentation License
+@include doclicense.texi
+
+@node Index
+@unnumbered Index
+@printindex cp
+
+@node Function Index
+@unnumbered Function Index
+@printindex fn
+
+@node Variable Index
+@unnumbered Variable Index
+@printindex vr
+
+@bye
+
+@c End:
diff --git a/xemacs-packages/gnus/texi/dir b/xemacs-packages/gnus/texi/dir
new file mode 100644 (file)
index 0000000..f101c2f
--- /dev/null
@@ -0,0 +1,25 @@
+-*- Text -*-
+The Gnus-related top node.
+
+This is the file .../info/dir, which contains the topmost node of the
+Info hierarchy.  The first time you invoke Info you start off
+looking at that node, which is (dir)Top.
+\1f
+File: dir      Node: Top       This is the Gnus Info tree
+  This (the Directory node) gives a menu of major topics. 
+  Typing "d" returns here, "q" exits, "?" lists all INFO commands, "h" 
+  gives a primer for first-timers, "mEmacs<Return>" visits the Emacs topic,
+  etc.
+  In Emacs, you can click mouse button 2 on a menu item or cross reference
+  to select it.
+  --- PLEASE ADD DOCUMENTATION TO THIS TREE. (See INFO topic first.) ---
+
+* Menu: 
+
+* Gnus: (gnus).                        The news reader Gnus.
+* Message: (message).          The Message sending thingamabob.
+* Emacs MIME: (emacs-mime).    Libraries for handling MIME.
+* Sieve: (sieve).              Managing Sieve scripts in Emacs.
+* PGG: (pgg).                  Emacs interface to various PGP implementations.
+* auth-source: (auth).         Emacs interface to keeping login information.
+* SASL: (sasl).                The Emacs SASL library.
diff --git a/xemacs-packages/gnus/texi/doclicense.texi b/xemacs-packages/gnus/texi/doclicense.texi
new file mode 100644 (file)
index 0000000..9c3bbe5
--- /dev/null
@@ -0,0 +1,505 @@
+@c The GNU Free Documentation License.
+@center Version 1.3, 3 November 2008
+
+@c This file is intended to be included within another document,
+@c hence no sectioning command or @node.
+
+@display
+Copyright @copyright{} 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
+@uref{http://fsf.org/}
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+@end display
+
+@enumerate 0
+@item
+PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document @dfn{free} in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of ``copyleft'', which means that derivative
+works of the document must themselves be free in the same sense.  It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does.  But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book.  We recommend this License
+principally for works whose purpose is instruction or reference.
+
+@item
+APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License.  Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein.  The ``Document'', below,
+refers to any such manual or work.  Any member of the public is a
+licensee, and is addressed as ``you''.  You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A ``Modified Version'' of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A ``Secondary Section'' is a named appendix or a front-matter section
+of the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall
+subject (or to related matters) and contains nothing that could fall
+directly within that overall subject.  (Thus, if the Document is in
+part a textbook of mathematics, a Secondary Section may not explain
+any mathematics.)  The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The ``Invariant Sections'' are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License.  If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant.  The Document may contain zero
+Invariant Sections.  If the Document does not identify any Invariant
+Sections then there are none.
+
+The ``Cover Texts'' are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License.  A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A ``Transparent'' copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters.  A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text.  A copy that is not ``Transparent'' is called ``Opaque''.
+
+Examples of suitable formats for Transparent copies include plain
+ASCII without markup, Texinfo input format, La@TeX{} input
+format, SGML or XML using a publicly available
+DTD, and standard-conforming simple HTML,
+PostScript or PDF designed for human modification.  Examples
+of transparent image formats include PNG, XCF and
+JPG@.  Opaque formats include proprietary formats that can be
+read and edited only by proprietary word processors, SGML or
+XML for which the DTD and/or processing tools are
+not generally available, and the machine-generated HTML,
+PostScript or PDF produced by some word processors for
+output purposes only.
+
+The ``Title Page'' means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page.  For works in
+formats which do not have any title page as such, ``Title Page'' means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+The ``publisher'' means any person or entity that distributes copies
+of the Document to the public.
+
+A section ``Entitled XYZ'' means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language.  (Here XYZ stands for a
+specific section name mentioned below, such as ``Acknowledgements'',
+``Dedications'', ``Endorsements'', or ``History''.)  To ``Preserve the Title''
+of such a section when you modify the Document means that it remains a
+section ``Entitled XYZ'' according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document.  These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+@item
+VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no other
+conditions whatsoever to those of this License.  You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute.  However, you may accept
+compensation in exchange for copies.  If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+@item
+COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover.  Both covers must also clearly and legibly identify
+you as the publisher of these copies.  The front cover must present
+the full title with all words of the title equally prominent and
+visible.  You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to give
+them a chance to provide you with an updated version of the Document.
+
+@item
+MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it.  In addition, you must do these things in the Modified Version:
+
+@enumerate A
+@item
+Use in the Title Page (and on the covers, if any) a title distinct
+from that of the Document, and from those of previous versions
+(which should, if there were any, be listed in the History section
+of the Document).  You may use the same title as a previous version
+if the original publisher of that version gives permission.
+
+@item
+List on the Title Page, as authors, one or more persons or entities
+responsible for authorship of the modifications in the Modified
+Version, together with at least five of the principal authors of the
+Document (all of its principal authors, if it has fewer than five),
+unless they release you from this requirement.
+
+@item
+State on the Title page the name of the publisher of the
+Modified Version, as the publisher.
+
+@item
+Preserve all the copyright notices of the Document.
+
+@item
+Add an appropriate copyright notice for your modifications
+adjacent to the other copyright notices.
+
+@item
+Include, immediately after the copyright notices, a license notice
+giving the public permission to use the Modified Version under the
+terms of this License, in the form shown in the Addendum below.
+
+@item
+Preserve in that license notice the full lists of Invariant Sections
+and required Cover Texts given in the Document's license notice.
+
+@item
+Include an unaltered copy of this License.
+
+@item
+Preserve the section Entitled ``History'', Preserve its Title, and add
+to it an item stating at least the title, year, new authors, and
+publisher of the Modified Version as given on the Title Page.  If
+there is no section Entitled ``History'' in the Document, create one
+stating the title, year, authors, and publisher of the Document as
+given on its Title Page, then add an item describing the Modified
+Version as stated in the previous sentence.
+
+@item
+Preserve the network location, if any, given in the Document for
+public access to a Transparent copy of the Document, and likewise
+the network locations given in the Document for previous versions
+it was based on.  These may be placed in the ``History'' section.
+You may omit a network location for a work that was published at
+least four years before the Document itself, or if the original
+publisher of the version it refers to gives permission.
+
+@item
+For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve
+the Title of the section, and preserve in the section all the
+substance and tone of each of the contributor acknowledgements and/or
+dedications given therein.
+
+@item
+Preserve all the Invariant Sections of the Document,
+unaltered in their text and in their titles.  Section numbers
+or the equivalent are not considered part of the section titles.
+
+@item
+Delete any section Entitled ``Endorsements''.  Such a section
+may not be included in the Modified Version.
+
+@item
+Do not retitle any existing section to be Entitled ``Endorsements'' or
+to conflict in title with any Invariant Section.
+
+@item
+Preserve any Warranty Disclaimers.
+@end enumerate
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant.  To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled ``Endorsements'', provided it contains
+nothing but endorsements of your Modified Version by various
+parties---for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version.  Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity.  If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+@item
+COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy.  If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled ``History''
+in the various original documents, forming one section Entitled
+``History''; likewise combine any sections Entitled ``Acknowledgements'',
+and any sections Entitled ``Dedications''.  You must delete all
+sections Entitled ``Endorsements.''
+
+@item
+COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other documents
+released under this License, and replace the individual copies of this
+License in the various documents with a single copy that is included in
+the collection, provided that you follow the rules of this License for
+verbatim copying of each of the documents in all other respects.
+
+You may extract a single document from such a collection, and distribute
+it individually under this License, provided you insert a copy of this
+License into the extracted document, and follow this License in all
+other respects regarding verbatim copying of that document.
+
+@item
+AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an ``aggregate'' if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+@item
+TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections.  You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers.  In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled ``Acknowledgements'',
+``Dedications'', or ``History'', the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+@item
+TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense, or distribute it is void, and
+will automatically terminate your rights under this License.
+
+However, if you cease all violation of this License, then your license
+from a particular copyright holder is reinstated (a) provisionally,
+unless and until the copyright holder explicitly and finally
+terminates your license, and (b) permanently, if the copyright holder
+fails to notify you of the violation by some reasonable means prior to
+60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, receipt of a copy of some or all of the same material does
+not give you any rights to use it.
+
+@item
+FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions
+of the GNU Free Documentation License from time to time.  Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.  See
+@uref{http://www.gnu.org/copyleft/}.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License ``or any later version'' applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation.  If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.  If the Document
+specifies that a proxy can decide which future versions of this
+License can be used, that proxy's public statement of acceptance of a
+version permanently authorizes you to choose that version for the
+Document.
+
+@item
+RELICENSING
+
+``Massive Multiauthor Collaboration Site'' (or ``MMC Site'') means any
+World Wide Web server that publishes copyrightable works and also
+provides prominent facilities for anybody to edit those works.  A
+public wiki that anybody can edit is an example of such a server.  A
+``Massive Multiauthor Collaboration'' (or ``MMC'') contained in the
+site means any set of copyrightable works thus published on the MMC
+site.
+
+``CC-BY-SA'' means the Creative Commons Attribution-Share Alike 3.0
+license published by Creative Commons Corporation, a not-for-profit
+corporation with a principal place of business in San Francisco,
+California, as well as future copyleft versions of that license
+published by that same organization.
+
+``Incorporate'' means to publish or republish a Document, in whole or
+in part, as part of another Document.
+
+An MMC is ``eligible for relicensing'' if it is licensed under this
+License, and if all works that were first published under this License
+somewhere other than this MMC, and subsequently incorporated in whole
+or in part into the MMC, (1) had no cover texts or invariant sections,
+and (2) were thus incorporated prior to November 1, 2008.
+
+The operator of an MMC Site may republish an MMC contained in the site
+under CC-BY-SA on the same site at any time before August 1, 2009,
+provided the MMC is eligible for relicensing.
+
+@end enumerate
+
+@page
+@heading ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+@smallexample
+@group
+  Copyright (C)  @var{year}  @var{your name}.
+  Permission is granted to copy, distribute and/or modify this document
+  under the terms of the GNU Free Documentation License, Version 1.3
+  or any later version published by the Free Software Foundation;
+  with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+  Texts.  A copy of the license is included in the section entitled ``GNU
+  Free Documentation License''.
+@end group
+@end smallexample
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the ``with@dots{}Texts.''@: line with this:
+
+@smallexample
+@group
+    with the Invariant Sections being @var{list their titles}, with
+    the Front-Cover Texts being @var{list}, and with the Back-Cover Texts
+    being @var{list}.
+@end group
+@end smallexample
+
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
+
+@c Local Variables:
+@c ispell-local-pdict: "ispell-dict"
+@c End:
diff --git a/xemacs-packages/gnus/texi/docstyle.texi b/xemacs-packages/gnus/texi/docstyle.texi
new file mode 100644 (file)
index 0000000..dfd1430
--- /dev/null
@@ -0,0 +1,10 @@
+@c Emacs documentation style settings
+@documentencoding UTF-8
+@c These two require Texinfo 5.0 or later, so we use the older
+@c equivalent @set variables supported in 4.11 and hence
+@ignore
+@codequotebacktick on
+@codequoteundirected on
+@end ignore
+@set txicodequoteundirected
+@set txicodequotebacktick
diff --git a/xemacs-packages/gnus/texi/emacs-mime.texi b/xemacs-packages/gnus/texi/emacs-mime.texi
new file mode 100644 (file)
index 0000000..57bf9af
--- /dev/null
@@ -0,0 +1,1899 @@
+\input texinfo
+
+@include gnus-overrides.texi
+
+@setfilename emacs-mime.info
+@settitle Emacs MIME Manual
+@include docstyle.texi
+@synindex fn cp
+@synindex vr cp
+@synindex pg cp
+
+@copying
+This file documents the Emacs MIME interface functionality.
+
+Copyright @copyright{} 1998--2016 Free Software Foundation, Inc.
+
+@quotation
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 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''.
+
+(a) The FSF's Back-Cover Text is: ``You have the freedom to copy and
+modify this GNU manual.''
+@end quotation
+@end copying
+
+@c Node ``Interface Functions'' uses non-ASCII characters
+
+@dircategory Emacs lisp libraries
+@direntry
+* Emacs MIME: (emacs-mime).     Emacs MIME de/composition library.
+@end direntry
+@iftex
+@finalout
+@end iftex
+@setchapternewpage odd
+
+@titlepage
+@ifset WEBHACKDEVEL
+@title Emacs MIME Manual (DEVELOPMENT VERSION)
+@end ifset
+@ifclear WEBHACKDEVEL
+@title Emacs MIME Manual
+@end ifclear
+
+@author by Lars Magne Ingebrigtsen
+@page
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+
+@contents
+
+@node Top
+@top Emacs MIME
+
+This manual documents the libraries used to compose and display
+@acronym{MIME} messages.
+
+This manual is directed at users who want to modify the behavior of
+the @acronym{MIME} encoding/decoding process or want a more detailed
+picture of how the Emacs @acronym{MIME} library works, and people who want
+to write functions and commands that manipulate @acronym{MIME} elements.
+
+@acronym{MIME} is short for @dfn{Multipurpose Internet Mail Extensions}.
+This standard is documented in a number of RFCs; mainly RFC2045 (Format
+of Internet Message Bodies), RFC2046 (Media Types), RFC2047 (Message
+Header Extensions for Non-@acronym{ASCII} Text), RFC2048 (Registration
+Procedures), RFC2049 (Conformance Criteria and Examples).  It is highly
+recommended that anyone who intends writing @acronym{MIME}-compliant software
+read at least RFC2045 and RFC2047.
+
+@ifnottex
+@insertcopying
+@end ifnottex
+
+@menu
+* Decoding and Viewing::  A framework for decoding and viewing.
+* Composing::             @acronym{MML}; a language for describing @acronym{MIME} parts.
+* Interface Functions::   An abstraction over the basic functions.
+* Basic Functions::       Utility and basic parsing functions.
+* Standards::             A summary of RFCs and working documents used.
+* GNU Free Documentation License:: The license for this documentation.
+* Index::                 Function and variable index.
+@end menu
+
+
+@node Decoding and Viewing
+@chapter Decoding and Viewing
+
+This chapter deals with decoding and viewing @acronym{MIME} messages on a
+higher level.
+
+The main idea is to first analyze a @acronym{MIME} article, and then allow
+other programs to do things based on the list of @dfn{handles} that are
+returned as a result of this analysis.
+
+@menu
+* Dissection::             Analyzing a @acronym{MIME} message.
+* Non-MIME::               Analyzing a non-@acronym{MIME} message.
+* Handles::                Handle manipulations.
+* Display::                Displaying handles.
+* Display Customization::  Variables that affect display.
+* Files and Directories::  Saving and naming attachments.
+* New Viewers::            How to write your own viewers.
+@end menu
+
+
+@node Dissection
+@section Dissection
+
+The @code{mm-dissect-buffer} is the function responsible for dissecting
+a @acronym{MIME} article.  If given a multipart message, it will recursively
+descend the message, following the structure, and return a tree of
+@acronym{MIME} handles that describes the structure of the message.
+
+@node Non-MIME
+@section Non-MIME
+@vindex mm-uu-configure-list
+
+Gnus also understands some non-@acronym{MIME} attachments, such as
+postscript, uuencode, binhex, yenc, shar, forward, gnatsweb, pgp,
+diff.  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 yenc
+@findex yenc
+Yenc encoded file.
+
+@item shar
+@findex shar
+Shar archive file.
+
+@item forward
+@findex forward
+Non-@acronym{MIME} forwarded message.
+
+@item gnatsweb
+@findex gnatsweb
+Gnatsweb attachment.
+
+@item pgp-signed
+@findex pgp-signed
+@acronym{PGP} signed clear text.
+
+@item pgp-encrypted
+@findex pgp-encrypted
+@acronym{PGP} encrypted clear text.
+
+@item pgp-key
+@findex pgp-key
+@acronym{PGP} public keys.
+
+@item emacs-sources
+@findex emacs-sources
+@vindex mm-uu-emacs-sources-regexp
+Emacs source code.  This item works only in the groups matching
+@code{mm-uu-emacs-sources-regexp}.
+
+@item diff
+@vindex diff
+@vindex mm-uu-diff-groups-regexp
+Patches.  This is intended for groups where diffs of committed files
+are automatically sent to.  It only works in groups matching
+@code{mm-uu-diff-groups-regexp}.
+
+@item verbatim-marks
+@cindex verbatim-marks
+Slrn-style verbatim marks.
+
+@item LaTeX
+@cindex LaTeX
+LaTeX documents.  It only works in groups matching
+@code{mm-uu-tex-groups-regexp}.
+
+@end table
+
+@cindex text/x-verbatim
+@c Is @vindex suitable for a face?
+@vindex mm-uu-extract
+Some inlined non-@acronym{MIME} attachments are displayed using the face
+@code{mm-uu-extract}.  By default, no @acronym{MIME} button for these
+parts is displayed.  You can force displaying a button using @kbd{K b}
+(@code{gnus-summary-display-buttonized}) or add @code{text/x-verbatim}
+to @code{gnus-buttonized-mime-types}, @xref{MIME Commands, ,MIME
+Commands, gnus, Gnus Manual}.
+
+@node Handles
+@section Handles
+
+A @acronym{MIME} handle is a list that fully describes a @acronym{MIME}
+component.
+
+The following macros can be used to access elements in a handle:
+
+@table @code
+@item mm-handle-buffer
+@findex mm-handle-buffer
+Return the buffer that holds the contents of the undecoded @acronym{MIME}
+part.
+
+@item mm-handle-type
+@findex mm-handle-type
+Return the parsed @code{Content-Type} of the part.
+
+@item mm-handle-encoding
+@findex mm-handle-encoding
+Return the @code{Content-Transfer-Encoding} of the part.
+
+@item mm-handle-undisplayer
+@findex mm-handle-undisplayer
+Return the object that can be used to remove the displayed part (if it
+has been displayed).
+
+@item mm-handle-set-undisplayer
+@findex mm-handle-set-undisplayer
+Set the undisplayer object.
+
+@item mm-handle-disposition
+@findex mm-handle-disposition
+Return the parsed @code{Content-Disposition} of the part.
+
+@item mm-get-content-id
+Returns the handle(s) referred to by @code{Content-ID}.
+
+@end table
+
+
+@node Display
+@section Display
+
+Functions for displaying, removing and saving.
+
+@table @code
+@item mm-display-part
+@findex mm-display-part
+Display the part.
+
+@item mm-remove-part
+@findex mm-remove-part
+Remove the part (if it has been displayed).
+
+@item mm-inlinable-p
+@findex mm-inlinable-p
+Say whether a @acronym{MIME} type can be displayed inline.
+
+@item mm-automatic-display-p
+@findex mm-automatic-display-p
+Say whether a @acronym{MIME} type should be displayed automatically.
+
+@item mm-destroy-part
+@findex mm-destroy-part
+Free all resources occupied by a part.
+
+@item mm-save-part
+@findex mm-save-part
+Offer to save the part in a file.
+
+@item mm-pipe-part
+@findex mm-pipe-part
+Offer to pipe the part to some process.
+
+@item mm-interactively-view-part
+@findex mm-interactively-view-part
+Prompt for a mailcap method to use to view the part.
+
+@end table
+
+
+@node Display Customization
+@section Display Customization
+
+@table @code
+
+@item mm-inline-media-tests
+@vindex mm-inline-media-tests
+This is an alist where the key is a @acronym{MIME} type, the second element
+is a function to display the part @dfn{inline} (i.e., inside Emacs), and
+the third element is a form to be @code{eval}ed to say whether the part
+can be displayed inline.
+
+This variable specifies whether a part @emph{can} be displayed inline,
+and, if so, how to do it.  It does not say whether parts are
+@emph{actually} displayed inline.
+
+@item mm-inlined-types
+@vindex mm-inlined-types
+This, on the other hand, says what types are to be displayed inline, if
+they satisfy the conditions set by the variable above.  It's a list of
+@acronym{MIME} media types.
+
+@item mm-automatic-display
+@vindex mm-automatic-display
+This is a list of types that are to be displayed ``automatically'', but
+only if the above variable allows it.  That is, only inlinable parts can
+be displayed automatically.
+
+@item mm-automatic-external-display
+@vindex mm-automatic-external-display
+This is a list of types that will be displayed automatically in an
+external viewer.
+
+@item mm-keep-viewer-alive-types
+@vindex mm-keep-viewer-alive-types
+This is a list of media types for which the external viewer will not
+be killed when selecting a different article.
+
+@item mm-attachment-override-types
+@vindex mm-attachment-override-types
+Some @acronym{MIME} agents create parts that have a content-disposition of
+@samp{attachment}.  This variable allows overriding that disposition and
+displaying the part inline.  (Note that the disposition is only
+overridden if we are able to, and want to, display the part inline.)
+
+@item mm-discouraged-alternatives
+@vindex mm-discouraged-alternatives
+List of @acronym{MIME} types that are discouraged when viewing
+@samp{multipart/alternative}.  Viewing agents are supposed to view the
+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/richtext} parts are somewhat unwanted,
+you could say something like:
+
+@lisp
+(setq mm-discouraged-alternatives
+      '("text/html" "text/richtext")
+      mm-automatic-display
+      (remove "text/html" mm-automatic-display))
+@end lisp
+
+Adding @code{"image/.*"} might also be useful.  Spammers use images as
+the preferred part of @samp{multipart/alternative} messages, so you might
+not notice there are other parts.  See also
+@code{gnus-buttonized-mime-types}, @ref{MIME Commands, ,MIME Commands,
+gnus, Gnus Manual}.  After adding @code{"multipart/alternative"} to
+@code{gnus-buttonized-mime-types} you can choose manually which
+alternative you'd like to view.  For example, you can set those
+variables like:
+
+@lisp
+(setq gnus-buttonized-mime-types
+      '("multipart/alternative" "multipart/signed")
+      mm-discouraged-alternatives
+      '("text/html" "image/.*"))
+@end lisp
+
+In this case, Gnus will display radio buttons for such a kind of spam
+message as follows:
+
+@example
+1.  (*) multipart/alternative  ( ) image/gif
+
+2.  (*) text/plain          ( ) text/html
+@end example
+
+@item mm-inline-large-images
+@vindex mm-inline-large-images
+When displaying inline images that are larger than the window, Emacs
+does not enable scrolling, which means that you cannot see the whole
+image. To prevent this, the library tries to determine the image size
+before displaying it inline, and if it doesn't fit the window, the
+library will display it externally (e.g., with @samp{ImageMagick} or
+@samp{xv}). Setting this variable to @code{t} disables this check and
+makes the library display all inline images as inline, regardless of
+their size. If you set this variable to @code{resize}, the image will
+be displayed resized to fit in the window, if Emacs has the ability to
+resize images.
+
+@item mm-inline-large-images-proportion
+@vindex mm-inline-images-max-proportion
+The proportion used when resizing large images.
+
+@item mm-inline-override-types
+@vindex mm-inline-override-types
+@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
+as an attachment, that can be accomplished by setting this variable to a
+list containing that type.  For example assuming @code{mm-inlined-types}
+includes @samp{text/.*}, then including @samp{text/html} in this
+variable will cause @samp{text/html} parts to be treated as attachments.
+
+@item mm-text-html-renderer
+@vindex mm-text-html-renderer
+This selects the function used to render @acronym{HTML}.  The predefined
+renderers are selected by the symbols @code{gnus-article-html},
+@code{w3m}@footnote{See @uref{http://emacs-w3m.namazu.org/} for more
+information about emacs-w3m}, @code{links}, @code{lynx},
+@code{w3m-standalone} or @code{html2text}.  If @code{nil} use an
+external viewer.  You can also specify a function, which will be
+called with a @acronym{MIME} handle as the argument.
+
+@item mm-inline-text-html-with-images
+@vindex mm-inline-text-html-with-images
+Some @acronym{HTML} mails might have the trick of spammers using
+@samp{<img>} tags.  It is likely to be intended to verify whether you
+have read the mail.  You can prevent your personal information from
+leaking by setting this option to @code{nil} (which is the default).
+For emacs-w3m, you may use the command @kbd{t} on the image anchor to
+show an image even if it is @code{nil}.@footnote{The command @kbd{T}
+will load all images.  If you have set the option
+@code{w3m-key-binding} to @code{info}, use @kbd{i} or @kbd{I}
+instead.}
+
+@item mm-w3m-safe-url-regexp
+@vindex mm-w3m-safe-url-regexp
+A regular expression that matches safe URL names, i.e., URLs that are
+unlikely to leak personal information when rendering @acronym{HTML}
+email (the default value is @samp{\\`cid:}).  If @code{nil} consider
+all URLs safe.  In Gnus, this will be overridden according to the value
+of the variable @code{gnus-safe-html-newsgroups}, @xref{Various
+Various, ,Various Various, gnus, Gnus Manual}.
+
+@item mm-inline-text-html-with-w3m-keymap
+@vindex mm-inline-text-html-with-w3m-keymap
+You can use emacs-w3m command keys in the inlined text/html part by
+setting this option to non-@code{nil}.  The default value is @code{t}.
+
+@item mm-external-terminal-program
+@vindex mm-external-terminal-program
+The program used to start an external terminal.
+
+@item mm-enable-external
+@vindex mm-enable-external
+Indicate whether external @acronym{MIME} handlers should be used.
+
+If @code{t}, all defined external @acronym{MIME} handlers are used.  If
+@code{nil}, files are saved to disk (@code{mailcap-save-binary-file}).
+If it is the symbol @code{ask}, you are prompted before the external
+@acronym{MIME} handler is invoked.
+
+When you launch an attachment through mailcap (@pxref{mailcap}) an
+attempt is made to use a safe viewer with the safest options---this isn't
+the case if you save it to disk and launch it in a different way
+(command line or double-clicking).  Anyhow, if you want to be sure not
+to launch any external programs, set this variable to @code{nil} or
+@code{ask}.
+
+@end table
+
+@node Files and Directories
+@section Files and Directories
+
+@table @code
+
+@item mm-default-directory
+@vindex mm-default-directory
+The default directory for saving attachments.  If @code{nil} use
+@code{default-directory}.
+
+@item mm-tmp-directory
+@vindex mm-tmp-directory
+Directory for storing temporary files.
+
+@item mm-file-name-rewrite-functions
+@vindex mm-file-name-rewrite-functions
+A list of functions used for rewriting file names of @acronym{MIME}
+parts.  Each function is applied successively to the file name.
+Ready-made functions include
+
+@table @code
+@item mm-file-name-delete-control
+@findex mm-file-name-delete-control
+Delete all control characters.
+
+@item mm-file-name-delete-gotchas
+@findex mm-file-name-delete-gotchas
+Delete characters that could have unintended consequences when used
+with flawed shell scripts, i.e., @samp{|}, @samp{>} and @samp{<}; and
+@samp{-}, @samp{.} as the first character.
+
+@item mm-file-name-delete-whitespace
+@findex mm-file-name-delete-whitespace
+Remove all whitespace.
+
+@item mm-file-name-trim-whitespace
+@findex mm-file-name-trim-whitespace
+Remove leading and trailing whitespace.
+
+@item mm-file-name-collapse-whitespace
+@findex mm-file-name-collapse-whitespace
+Collapse multiple whitespace characters.
+
+@item mm-file-name-replace-whitespace
+@findex mm-file-name-replace-whitespace
+@vindex mm-file-name-replace-whitespace
+Replace whitespace with underscores.  Set the variable
+@code{mm-file-name-replace-whitespace} to any other string if you do
+not like underscores.
+@end table
+
+The standard Emacs functions @code{capitalize}, @code{downcase},
+@code{upcase} and @code{upcase-initials} might also prove useful.
+
+@item mm-path-name-rewrite-functions
+@vindex mm-path-name-rewrite-functions
+List of functions used for rewriting the full file names of @acronym{MIME}
+parts.  This is used when viewing parts externally, and is meant for
+transforming the absolute name so that non-compliant programs can find
+the file where it's saved.
+
+@end table
+
+@node New Viewers
+@section New Viewers
+
+Here's an example viewer for displaying @code{text/enriched} inline:
+
+@lisp
+(defun mm-display-enriched-inline (handle)
+  (let (text)
+    (with-temp-buffer
+      (mm-insert-part handle)
+      (save-window-excursion
+        (enriched-decode (point-min) (point-max))
+        (setq text (buffer-string))))
+    (mm-insert-inline handle text)))
+@end lisp
+
+We see that the function takes a @acronym{MIME} handle as its parameter.  It
+then goes to a temporary buffer, inserts the text of the part, does some
+work on the text, stores the result, goes back to the buffer it was
+called from and inserts the result.
+
+The two important helper functions here are @code{mm-insert-part} and
+@code{mm-insert-inline}.  The first function inserts the text of the
+handle in the current buffer.  It handles charset and/or content
+transfer decoding.  The second function just inserts whatever text you
+tell it to insert, but it also sets things up so that the text can be
+``undisplayed'' in a convenient manner.
+
+
+@node Composing
+@chapter Composing
+@cindex Composing
+@cindex MIME Composing
+@cindex MML
+@cindex MIME Meta Language
+
+Creating a @acronym{MIME} message is boring and non-trivial.  Therefore,
+a library called @code{mml} has been defined that parses a language
+called @acronym{MML} (@acronym{MIME} Meta Language) and generates
+@acronym{MIME} messages.
+
+@findex mml-generate-mime
+The main interface function is @code{mml-generate-mime}.  It will
+examine the contents of the current (narrowed-to) buffer and return a
+string containing the @acronym{MIME} message.
+
+@menu
+* Simple MML Example::             An example @acronym{MML} document.
+* MML Definition::                 All valid @acronym{MML} elements.
+* Advanced MML Example::           Another example @acronym{MML} document.
+* Encoding Customization::         Variables that affect encoding.
+* Charset Translation::            How charsets are mapped from @sc{mule} to @acronym{MIME}.
+* Conversion::                     Going from @acronym{MIME} to @acronym{MML} and vice versa.
+* Flowed text::                    Soft and hard newlines.
+@end menu
+
+
+@node Simple MML Example
+@section Simple MML Example
+
+Here's a simple @samp{multipart/alternative}:
+
+@example
+<#multipart type=alternative>
+This is a plain text part.
+<#part type=text/enriched>
+<center>This is a centered enriched part</center>
+<#/multipart>
+@end example
+
+After running this through @code{mml-generate-mime}, we get this:
+
+@example
+Content-Type: multipart/alternative; boundary="=-=-="
+
+
+--=-=-=
+
+
+This is a plain text part.
+
+--=-=-=
+Content-Type: text/enriched
+
+
+<center>This is a centered enriched part</center>
+
+--=-=-=--
+@end example
+
+
+@node MML Definition
+@section MML Definition
+
+The @acronym{MML} language is very simple.  It looks a bit like an SGML
+application, but it's not.
+
+The main concept of @acronym{MML} is the @dfn{part}.  Each part can be of a
+different type or use a different charset.  The way to delineate a part
+is with a @samp{<#part ...>} tag.  Multipart parts can be introduced
+with the @samp{<#multipart ...>} tag.  Parts are ended by the
+@samp{<#/part>} or @samp{<#/multipart>} tags.  Parts started with the
+@samp{<#part ...>} tags are also closed by the next open tag.
+
+There's also the @samp{<#external ...>} tag.  These introduce
+@samp{external/message-body} parts.
+
+Each tag can contain zero or more parameters on the form
+@samp{parameter=value}.  The values may be enclosed in quotation marks,
+but that's not necessary unless the value contains white space.  So
+@samp{filename=/home/user/#hello$^yes} is perfectly valid.
+
+The following parameters have meaning in @acronym{MML}; parameters that have no
+meaning are ignored.  The @acronym{MML} parameter names are the same as the
+@acronym{MIME} parameter names; the things in the parentheses say which
+header it will be used in.
+
+@table @samp
+@item type
+The @acronym{MIME} type of the part (@code{Content-Type}).
+
+@item filename
+Use the contents of the file in the body of the part
+(@code{Content-Disposition}).
+
+@item recipient-filename
+Use this as the file name in the generated @acronym{MIME} message for
+the recipient.  That is, even if the file is called @file{foo.txt}
+locally, use this name instead in the @code{Content-Disposition} in
+the sent message.
+
+@item charset
+The contents of the body of the part are to be encoded in the character
+set specified (@code{Content-Type}). @xref{Charset Translation}.
+
+@item name
+Might be used to suggest a file name if the part is to be saved
+to a file (@code{Content-Type}).
+
+@item disposition
+Valid values are @samp{inline} and @samp{attachment}
+(@code{Content-Disposition}).
+
+@item encoding
+Valid values are @samp{7bit}, @samp{8bit}, @samp{quoted-printable} and
+@samp{base64} (@code{Content-Transfer-Encoding}). @xref{Charset
+Translation}.
+
+@item description
+A description of the part (@code{Content-Description}).
+
+@item creation-date
+RFC822 date when the part was created (@code{Content-Disposition}).
+
+@item modification-date
+RFC822 date when the part was modified (@code{Content-Disposition}).
+
+@item read-date
+RFC822 date when the part was read (@code{Content-Disposition}).
+
+@item recipients
+Who to encrypt/sign the part to.  This field is used to override any
+auto-detection based on the To/CC headers.
+
+@item sender
+Identity used to sign the part.  This field is used to override the
+default key used.
+
+@item size
+The size (in octets) of the part (@code{Content-Disposition}).
+
+@item sign
+What technology to sign this @acronym{MML} part with (@code{smime}, @code{pgp}
+or @code{pgpmime})
+
+@item encrypt
+What technology to encrypt this @acronym{MML} part with (@code{smime},
+@code{pgp} or @code{pgpmime})
+
+@end table
+
+Parameters for @samp{text/plain}:
+
+@table @samp
+@item format
+Formatting parameter for the text, valid values include @samp{fixed}
+(the default) and @samp{flowed}.  Normally you do not specify this
+manually, since it requires the textual body to be formatted in a
+special way described in RFC 2646.  @xref{Flowed text}.
+@end table
+
+Parameters for @samp{application/octet-stream}:
+
+@table @samp
+@item type
+Type of the part; informal---meant for human readers
+(@code{Content-Type}).
+@end table
+
+Parameters for @samp{message/external-body}:
+
+@table @samp
+@item access-type
+A word indicating the supported access mechanism by which the file may
+be obtained.  Values include @samp{ftp}, @samp{anon-ftp}, @samp{tftp},
+@samp{localfile}, and @samp{mailserver}.  (@code{Content-Type}.)
+
+@item expiration
+The RFC822 date after which the file may no longer be fetched.
+(@code{Content-Type}.)
+
+@item size
+The size (in octets) of the file.  (@code{Content-Type}.)
+
+@item permission
+Valid values are @samp{read} and @samp{read-write}
+(@code{Content-Type}).
+
+@end table
+
+Parameters for @samp{sign=smime}:
+
+@table @samp
+
+@item keyfile
+File containing key and certificate for signer.
+
+@end table
+
+Parameters for @samp{encrypt=smime}:
+
+@table @samp
+
+@item certfile
+File containing certificate for recipient.
+
+@end table
+
+
+@node Advanced MML Example
+@section Advanced MML Example
+
+Here's a complex multipart message.  It's a @samp{multipart/mixed} that
+contains many parts, one of which is a @samp{multipart/alternative}.
+
+@example
+<#multipart type=mixed>
+<#part type=image/jpeg filename=~/rms.jpg disposition=inline>
+<#multipart type=alternative>
+This is a plain text part.
+<#part type=text/enriched name=enriched.txt>
+<center>This is a centered enriched part</center>
+<#/multipart>
+This is a new plain text part.
+<#part disposition=attachment>
+This plain text part is an attachment.
+<#/multipart>
+@end example
+
+And this is the resulting @acronym{MIME} message:
+
+@example
+Content-Type: multipart/mixed; boundary="=-=-="
+
+
+--=-=-=
+
+
+
+--=-=-=
+Content-Type: image/jpeg;
+ filename="~/rms.jpg"
+Content-Disposition: inline;
+ filename="~/rms.jpg"
+Content-Transfer-Encoding: base64
+
+/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRof
+Hh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAwADABAREA/8QAHwAA
+AQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQR
+BRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RF
+RkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ip
+qrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEB
+AAA/AO/rifFHjldNuGsrDa0qcSSHkA+gHrXKw+LtWLrMb+RgTyhbr+HSug07xNqV9fQtZrNI
+AyiaE/NuBPOOOP0rvRNE880KOC8TbXXGCv1FPqjrF4LDR7u5L7SkTFT/ALWOP1xXgTuXfc7E
+sx6nua6rwp4IvvEM8chCxWxOdzn7wz6V9AaB4S07w9p5itow0rDLSY5Pt9K43xO66P4xs71m
+2QXiGCbA4yOVJ9+1aYORkdK434lyNH4ahCnG66VT9Nj15JFbPdX0MS43M4VQf5/yr2vSpLnw
+5ZW8dlCZ8KFXjOPX0/mK6rSPEGt3Angu44fNEReHYNvIH3TzXDeKNO8RX+kSX2ouZkicTIOc
+L+g7E810ulFjpVtv3bwgB3HJyK5L4quY/C9sVxk3ij/xx6850u7t1mtp/wDlpEw3An3Jr3Dw
+34gsbWza4nBlhC5LDsaW6+IFgupQyCF3iHH7gA7c9R9ay7zx6t7aX9jHC4smhfBkGCvHGfrm
+tLQ7hbnRrV1GPkAP1x1/Hr+Ncr8Vzjwrbf8AX6v/AKA9eQRyYlQk8Yx9K6XTNbkgia2ciSIn
+7p5Ga9Atte0LTLKO6it4i7dVRFJDcZ4PvXN+JvEMF9bILVGXJLSZ4zkjivRPDaeX4b08HOTC
+pOffmua+KkbS+GLVUGT9tT/0B68eeIpIFYjB70+OOVXyoOM9+M1eaWeCLzHPyHGO/NVWvJJm
+jQ8KGH1NfQWhXSXmh2c8eArRLwO3HSv/2Q==
+
+--=-=-=
+Content-Type: multipart/alternative; boundary="==-=-="
+
+
+--==-=-=
+
+
+This is a plain text part.
+
+--==-=-=
+Content-Type: text/enriched;
+ name="enriched.txt"
+
+
+<center>This is a centered enriched part</center>
+
+--==-=-=--
+
+--=-=-=
+
+This is a new plain text part.
+
+--=-=-=
+Content-Disposition: attachment
+
+
+This plain text part is an attachment.
+
+--=-=-=--
+@end example
+
+@node Encoding Customization
+@section Encoding Customization
+
+@table @code
+
+@item mm-body-charset-encoding-alist
+@vindex mm-body-charset-encoding-alist
+Mapping from @acronym{MIME} charset to encoding to use.  This variable is
+usually used except, e.g., when other requirements force a specific
+encoding (digitally signed messages require 7bit encodings).  The
+default is
+
+@lisp
+((iso-2022-jp . 7bit)
+ (iso-2022-jp-2 . 7bit)
+ (utf-16 . base64)
+ (utf-16be . base64)
+ (utf-16le . base64))
+@end lisp
+
+As an example, if you do not want to have ISO-8859-1 characters
+quoted-printable encoded, you may add @code{(iso-8859-1 . 8bit)} to
+this variable.  You can override this setting on a per-message basis
+by using the @code{encoding} @acronym{MML} tag (@pxref{MML Definition}).
+
+@item mm-coding-system-priorities
+@vindex mm-coding-system-priorities
+Prioritize coding systems to use for outgoing messages.  The default
+is @code{nil}, which means to use the defaults in Emacs, but is
+@code{(iso-8859-1 iso-2022-jp utf-8)} when running Emacs in the Japanese
+language environment.  It is a list of coding system symbols (aliases of
+coding systems are also allowed, use @kbd{M-x describe-coding-system} to
+make sure you are specifying correct coding system names).  For example,
+if you have configured Emacs to prefer UTF-8, but wish that outgoing
+messages should be sent in ISO-8859-1 if possible, you can set this
+variable to @code{(iso-8859-1)}.  You can override this setting on a
+per-message basis by using the @code{charset} @acronym{MML} tag
+(@pxref{MML Definition}).
+
+As different hierarchies prefer different charsets, you may want to set
+@code{mm-coding-system-priorities} according to the hierarchy in Gnus.
+Here's an example:
+
+@c Corrections about preferred charsets are welcome.  de, fr and fj
+@c should be correct, I don't know about the rest (so these are only
+@c examples):
+@lisp
+(add-to-list 'gnus-newsgroup-variables 'mm-coding-system-priorities)
+(setq gnus-parameters
+      (nconc
+       ;; Some charsets are just examples!
+       '(("^cn\\." ;; Chinese
+          (mm-coding-system-priorities
+           '(iso-8859-1 cn-big5 chinese-iso-7bit utf-8)))
+         ("^cz\\.\\|^pl\\." ;; Central and Eastern European
+          (mm-coding-system-priorities '(iso-8859-2 utf-8)))
+         ("^de\\." ;; German language
+          (mm-coding-system-priorities '(iso-8859-1 iso-8859-15 utf-8)))
+         ("^fr\\." ;; French
+          (mm-coding-system-priorities '(iso-8859-15 iso-8859-1 utf-8)))
+         ("^fj\\." ;; Japanese
+          (mm-coding-system-priorities
+           '(iso-8859-1 iso-2022-jp utf-8)))
+         ("^ru\\." ;; Cyrillic
+          (mm-coding-system-priorities
+           '(koi8-r iso-8859-5 iso-8859-1 utf-8))))
+       gnus-parameters))
+@end lisp
+
+@item mm-content-transfer-encoding-defaults
+@vindex mm-content-transfer-encoding-defaults
+Mapping from @acronym{MIME} types to encoding to use.  This variable is usually
+used except, e.g., when other requirements force a safer encoding
+(digitally signed messages require 7bit encoding).  Besides the normal
+@acronym{MIME} encodings, @code{qp-or-base64} may be used to indicate that for
+each case the most efficient of quoted-printable and base64 should be
+used.
+
+@code{qp-or-base64} has another effect.  It will fold long lines so that
+MIME parts may not be broken by MTA@.  So do @code{quoted-printable} and
+@code{base64}.
+
+Note that it affects body encoding only when a part is a raw forwarded
+message (which will be made by @code{gnus-summary-mail-forward} with the
+arg 2 for example) or is neither the @samp{text/*} type nor the
+@samp{message/*} type.  Even though in those cases, you can override
+this setting on a per-message basis by using the @code{encoding}
+@acronym{MML} tag (@pxref{MML Definition}).
+
+@item mm-use-ultra-safe-encoding
+@vindex mm-use-ultra-safe-encoding
+When this is non-@code{nil}, it means that textual parts are encoded as
+quoted-printable if they contain lines longer than 76 characters or
+starting with "From " in the body.  Non-7bit encodings (8bit, binary)
+are generally disallowed.  This reduce the probability that a non-8bit
+clean MTA or MDA changes the message.  This should never be set
+directly, but bound by other functions when necessary (e.g., when
+encoding messages that are to be digitally signed).
+
+@end table
+
+@node Charset Translation
+@section Charset Translation
+@cindex charsets
+
+During translation from @acronym{MML} to @acronym{MIME}, for each
+@acronym{MIME} part which has been composed inside Emacs, an appropriate
+charset has to be chosen.
+
+@vindex mail-parse-charset
+If you are running a non-@sc{mule} Emacs, this process is simple: If the
+part contains any non-@acronym{ASCII} (8-bit) characters, the @acronym{MIME} charset
+given by @code{mail-parse-charset} (a symbol) is used.  (Never set this
+variable directly, though.  If you want to change the default charset,
+please consult the documentation of the package which you use to process
+@acronym{MIME} messages.
+@xref{Various Message Variables, , Various Message Variables, message,
+      Message Manual}, for example.)
+If there are only @acronym{ASCII} characters, the @acronym{MIME} charset US-ASCII is
+used, of course.
+
+@cindex MULE
+@cindex UTF-8
+@cindex Unicode
+@vindex mm-mime-mule-charset-alist
+Things are slightly more complicated when running Emacs with @sc{mule}
+support.  In this case, a list of the @sc{mule} charsets used in the
+part is obtained, and the @sc{mule} charsets are translated to
+@acronym{MIME} charsets by consulting the table provided by Emacs itself
+or the variable @code{mm-mime-mule-charset-alist} for XEmacs.
+If this results in a single @acronym{MIME} charset, this is used to encode
+the part.  But if the resulting list of @acronym{MIME} charsets contains more
+than one element, two things can happen: If it is possible to encode the
+part via UTF-8, this charset is used.  (For this, Emacs must support
+the @code{utf-8} coding system, and the part must consist entirely of
+characters which have Unicode counterparts.)  If UTF-8 is not available
+for some reason, the part is split into several ones, so that each one
+can be encoded with a single @acronym{MIME} charset.  The part can only be
+split at line boundaries, though---if more than one @acronym{MIME} charset is
+required to encode a single line, it is not possible to encode the part.
+
+When running Emacs with @sc{mule} support, the preferences for which
+coding system to use is inherited from Emacs itself.  This means that
+if Emacs is set up to prefer UTF-8, it will be used when encoding
+messages.  You can modify this by altering the
+@code{mm-coding-system-priorities} variable though (@pxref{Encoding
+Customization}).
+
+The charset to be used can be overridden by setting the @code{charset}
+@acronym{MML} tag (@pxref{MML Definition}) when composing the message.
+
+The encoding of characters (quoted-printable, 8bit, etc.)@: is orthogonal
+to the discussion here, and is controlled by the variables
+@code{mm-body-charset-encoding-alist} and
+@code{mm-content-transfer-encoding-defaults} (@pxref{Encoding
+Customization}).
+
+@node Conversion
+@section Conversion
+
+@findex mime-to-mml
+A (multipart) @acronym{MIME} message can be converted to @acronym{MML}
+with the @code{mime-to-mml} function.  It works on the message in the
+current buffer, and substitutes @acronym{MML} markup for @acronym{MIME}
+boundaries.  Non-textual parts do not have their contents in the buffer,
+but instead have the contents in separate buffers that are referred to
+from the @acronym{MML} tags.
+
+@findex mml-to-mime
+An @acronym{MML} message can be converted back to @acronym{MIME} by the
+@code{mml-to-mime} function.
+
+These functions are in certain senses ``lossy''---you will not get back
+an identical message if you run @code{mime-to-mml} and then
+@code{mml-to-mime}.  Not only will trivial things like the order of the
+headers differ, but the contents of the headers may also be different.
+For instance, the original message may use base64 encoding on text,
+while @code{mml-to-mime} may decide to use quoted-printable encoding, and
+so on.
+
+In essence, however, these two functions should be the inverse of each
+other.  The resulting contents of the message should remain equivalent,
+if not identical.
+
+
+@node Flowed text
+@section Flowed text
+@cindex format=flowed
+
+The Emacs @acronym{MIME} library will respect the @code{use-hard-newlines}
+variable (@pxref{Hard and Soft Newlines, ,Hard and Soft Newlines,
+emacs, Emacs Manual}) when encoding a message, and the
+``format=flowed'' Content-Type parameter when decoding a message.
+
+On encoding text, regardless of @code{use-hard-newlines}, lines
+terminated by soft newline characters are filled together and wrapped
+after the column decided by @code{fill-flowed-encode-column}.
+Quotation marks (matching @samp{^>* ?}) are respected.  The variable
+controls how the text will look in a client that does not support
+flowed text, the default is to wrap after 66 characters.  If hard
+newline characters are not present in the buffer, no flow encoding
+occurs.
+
+You can customize the value of the @code{mml-enable-flowed} variable
+to enable or disable the flowed encoding usage when newline
+characters are present in the buffer.
+
+On decoding flowed text, lines with soft newline characters are filled
+together and wrapped after the column decided by
+@code{fill-flowed-display-column}.  The default is to wrap after
+@code{fill-column}.
+
+@table @code
+@item mm-fill-flowed
+@vindex mm-fill-flowed
+If non-@code{nil} a format=flowed article will be displayed flowed.
+@end table
+
+
+@node Interface Functions
+@chapter Interface Functions
+@cindex interface functions
+@cindex mail-parse
+
+The @code{mail-parse} library is an abstraction over the actual
+low-level libraries that are described in the next chapter.
+
+Standards change, and so programs have to change to fit in the new
+mold.  For instance, RFC2045 describes a syntax for the
+@code{Content-Type} header that only allows @acronym{ASCII} characters in the
+parameter list.  RFC2231 expands on RFC2045 syntax to provide a scheme
+for continuation headers and non-@acronym{ASCII} characters.
+
+The traditional way to deal with this is just to update the library
+functions to parse the new syntax.  However, this is sometimes the wrong
+thing to do.  In some instances it may be vital to be able to understand
+both the old syntax as well as the new syntax, and if there is only one
+library, one must choose between the old version of the library and the
+new version of the library.
+
+The Emacs @acronym{MIME} library takes a different tack.  It defines a
+series of low-level libraries (@file{rfc2047.el}, @file{rfc2231.el}
+and so on) that parses strictly according to the corresponding
+standard.  However, normal programs would not use the functions
+provided by these libraries directly, but instead use the functions
+provided by the @code{mail-parse} library.  The functions in this
+library are just aliases to the corresponding functions in the latest
+low-level libraries.  Using this scheme, programs get a consistent
+interface they can use, and library developers are free to create
+write code that handles new standards.
+
+The following functions are defined by this library:
+
+@table @code
+@item mail-header-parse-content-type
+@findex mail-header-parse-content-type
+Parse a @code{Content-Type} header and return a list on the following
+format:
+
+@lisp
+("type/subtype"
+ (attribute1 . value1)
+ (attribute2 . value2)
+ ...)
+@end lisp
+
+Here's an example:
+
+@example
+(mail-header-parse-content-type
+ "image/gif; name=\"b980912.gif\"")
+@result{} ("image/gif" (name . "b980912.gif"))
+@end example
+
+@item mail-header-parse-content-disposition
+@findex mail-header-parse-content-disposition
+Parse a @code{Content-Disposition} header and return a list on the same
+format as the function above.
+
+@item mail-content-type-get
+@findex mail-content-type-get
+Takes two parameters---a list on the format above, and an attribute.
+Returns the value of the attribute.
+
+@example
+(mail-content-type-get
+ '("image/gif" (name . "b980912.gif")) 'name)
+@result{} "b980912.gif"
+@end example
+
+@item mail-header-encode-parameter
+@findex mail-header-encode-parameter
+Takes a parameter string and returns an encoded version of the string.
+This is used for parameters in headers like @code{Content-Type} and
+@code{Content-Disposition}.
+
+@item mail-header-remove-comments
+@findex mail-header-remove-comments
+Return a comment-free version of a header.
+
+@example
+(mail-header-remove-comments
+ "Gnus/5.070027 (Pterodactyl Gnus v0.27) (Finnish Landrace)")
+@result{} "Gnus/5.070027  "
+@end example
+
+@item mail-header-remove-whitespace
+@findex mail-header-remove-whitespace
+Remove linear white space from a header.  Space inside quoted strings
+and comments is preserved.
+
+@example
+(mail-header-remove-whitespace
+ "image/gif; name=\"Name with spaces\"")
+@result{} "image/gif;name=\"Name with spaces\""
+@end example
+
+@item mail-header-get-comment
+@findex mail-header-get-comment
+Return the last comment in a header.
+
+@example
+(mail-header-get-comment
+ "Gnus/5.070027 (Pterodactyl Gnus v0.27) (Finnish Landrace)")
+@result{} "Finnish Landrace"
+@end example
+
+@item mail-header-parse-address
+@findex mail-header-parse-address
+Parse an address and return a list containing the mailbox and the
+plaintext name.
+
+@example
+(mail-header-parse-address
+ "Hrvoje Niksic <hniksic@@srce.hr>")
+@result{} ("hniksic@@srce.hr" . "Hrvoje Niksic")
+@end example
+
+@item mail-header-parse-addresses
+@findex mail-header-parse-addresses
+Parse a string with list of addresses and return a list of elements like
+the one described above.
+
+@example
+(mail-header-parse-addresses
+ "Hrvoje Niksic <hniksic@@srce.hr>, Steinar Bang <sb@@metis.no>")
+@result{} (("hniksic@@srce.hr" . "Hrvoje Niksic")
+     ("sb@@metis.no" . "Steinar Bang"))
+@end example
+
+@item mail-header-parse-date
+@findex mail-header-parse-date
+Parse a date string and return an Emacs time structure.
+
+@item mail-narrow-to-head
+@findex mail-narrow-to-head
+Narrow the buffer to the header section of the buffer.  Point is placed
+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.  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
+Encode the non-@acronym{ASCII} words in the region.  For instance,
+@samp{Naïve} is encoded as @samp{=?iso-8859-1?q?Na=EFve?=}.
+
+@item mail-encode-encoded-word-buffer
+@findex mail-encode-encoded-word-buffer
+Encode the non-@acronym{ASCII} words in the current buffer.  This function is
+meant to be called narrowed to the headers of a message.
+
+@item mail-encode-encoded-word-string
+@findex mail-encode-encoded-word-string
+Encode the words that need encoding in a string, and return the result.
+
+@example
+(mail-encode-encoded-word-string
+ "This is naïve, baby")
+@result{} "This is =?iso-8859-1?q?na=EFve,?= baby"
+@end example
+
+@item mail-decode-encoded-word-region
+@findex mail-decode-encoded-word-region
+Decode the encoded words in the region.
+
+@item mail-decode-encoded-word-string
+@findex mail-decode-encoded-word-string
+Decode the encoded words in the string and return the result.
+
+@example
+(mail-decode-encoded-word-string
+ "This is =?iso-8859-1?q?na=EFve,?= baby")
+@result{} "This is naïve, baby"
+@end example
+
+@end table
+
+Currently, @code{mail-parse} is an abstraction over @code{ietf-drums},
+@code{rfc2047}, @code{rfc2045} and @code{rfc2231}.  These are documented
+in the subsequent sections.
+
+
+
+@node Basic Functions
+@chapter Basic Functions
+
+This chapter describes the basic, ground-level functions for parsing and
+handling.  Covered here is parsing @code{From} lines, removing comments
+from header lines, decoding encoded words, parsing date headers and so
+on.  High-level functionality is dealt with in the first chapter
+(@pxref{Decoding and Viewing}).
+
+@menu
+* rfc2045::      Encoding @code{Content-Type} headers.
+* rfc2231::      Parsing @code{Content-Type} headers.
+* ietf-drums::   Handling mail headers defined by RFC822bis.
+* rfc2047::      En/decoding encoded words in headers.
+* time-date::    Functions for parsing dates and manipulating time.
+* qp::           Quoted-Printable en/decoding.
+* base64::       Base64 en/decoding.
+* binhex::       Binhex decoding.
+* uudecode::     Uuencode decoding.
+* yenc::         Yenc decoding.
+* rfc1843::      Decoding HZ-encoded text.
+* mailcap::      How parts are displayed is specified by the @file{.mailcap} file
+@end menu
+
+
+@node rfc2045
+@section rfc2045
+
+RFC2045 is the ``main'' @acronym{MIME} document, and as such, one would
+imagine that there would be a lot to implement.  But there isn't, since
+most of the implementation details are delegated to the subsequent
+RFCs.
+
+So @file{rfc2045.el} has only a single function:
+
+@table @code
+@item rfc2045-encode-string
+@findex rfc2045-encode-string
+Takes a parameter and a value and returns a @samp{PARAM=VALUE} string.
+@var{value} will be quoted if there are non-safe characters in it.
+@end table
+
+
+@node rfc2231
+@section rfc2231
+
+RFC2231 defines a syntax for the @code{Content-Type} and
+@code{Content-Disposition} headers.  Its snappy name is @dfn{MIME
+Parameter Value and Encoded Word Extensions: Character Sets, Languages,
+and Continuations}.
+
+In short, these headers look something like this:
+
+@example
+Content-Type: application/x-stuff;
+ title*0*=us-ascii'en'This%20is%20even%20more%20;
+ title*1*=%2A%2A%2Afun%2A%2A%2A%20;
+ title*2="isn't it!"
+@end example
+
+They usually aren't this bad, though.
+
+The following functions are defined by this library:
+
+@table @code
+@item rfc2231-parse-string
+@findex rfc2231-parse-string
+Parse a @code{Content-Type} header and return a list describing its
+elements.
+
+@example
+(rfc2231-parse-string
+ "application/x-stuff;
+ title*0*=us-ascii'en'This%20is%20even%20more%20;
+ title*1*=%2A%2A%2Afun%2A%2A%2A%20;
+ title*2=\"isn't it!\"")
+@result{} ("application/x-stuff"
+    (title . "This is even more ***fun*** isn't it!"))
+@end example
+
+@item rfc2231-get-value
+@findex rfc2231-get-value
+Takes one of the lists on the format above and returns
+the value of the specified attribute.
+
+@item rfc2231-encode-string
+@findex rfc2231-encode-string
+Encode a parameter in headers likes @code{Content-Type} and
+@code{Content-Disposition}.
+
+@end table
+
+
+@node ietf-drums
+@section ietf-drums
+
+@dfn{drums} is an IETF working group that is working on the replacement
+for RFC822.
+
+The functions provided by this library include:
+
+@table @code
+@item ietf-drums-remove-comments
+@findex ietf-drums-remove-comments
+Remove the comments from the argument and return the results.
+
+@item ietf-drums-remove-whitespace
+@findex ietf-drums-remove-whitespace
+Remove linear white space from the string and return the results.
+Spaces inside quoted strings and comments are left untouched.
+
+@item ietf-drums-get-comment
+@findex ietf-drums-get-comment
+Return the last most comment from the string.
+
+@item ietf-drums-parse-address
+@findex ietf-drums-parse-address
+Parse an address string and return a list that contains the mailbox and
+the plain text name.
+
+@item ietf-drums-parse-addresses
+@findex ietf-drums-parse-addresses
+Parse a string that contains any number of comma-separated addresses and
+return a list that contains mailbox/plain text pairs.
+
+@item ietf-drums-parse-date
+@findex ietf-drums-parse-date
+Parse a date string and return an Emacs time structure.
+
+@item ietf-drums-narrow-to-header
+@findex ietf-drums-narrow-to-header
+Narrow the buffer to the header section of the current buffer.
+
+@end table
+
+
+@node rfc2047
+@section rfc2047
+
+RFC2047 (Message Header Extensions for Non-@acronym{ASCII} Text) specifies how
+non-@acronym{ASCII} text in headers are to be encoded.  This is actually rather
+complicated, so a number of variables are necessary to tweak what this
+library does.
+
+The following variables are tweakable:
+
+@table @code
+@item rfc2047-header-encoding-alist
+@vindex rfc2047-header-encoding-alist
+This is an alist of header / encoding-type pairs.  Its main purpose is
+to prevent encoding of certain headers.
+
+The keys can either be header regexps, or @code{t}.
+
+The values can be @code{nil}, in which case the header(s) in question
+won't be encoded, @code{mime}, which means that they will be encoded, or
+@code{address-mime}, which means the header(s) will be encoded carefully
+assuming they contain addresses.
+
+@item rfc2047-charset-encoding-alist
+@vindex rfc2047-charset-encoding-alist
+RFC2047 specifies two forms of encoding---@code{Q} (a
+Quoted-Printable-like encoding) and @code{B} (base64).  This alist
+specifies which charset should use which encoding.
+
+@item rfc2047-encode-function-alist
+@vindex rfc2047-encode-function-alist
+This is an alist of encoding / function pairs.  The encodings are
+@code{Q}, @code{B} and @code{nil}.
+
+@item rfc2047-encoded-word-regexp
+@vindex rfc2047-encoded-word-regexp
+When decoding words, this library looks for matches to this regexp.
+
+@item rfc2047-encoded-word-regexp-loose
+@vindex rfc2047-encoded-word-regexp-loose
+This is a version from which the regexp for the Q encoding pattern of
+@code{rfc2047-encoded-word-regexp} is made loose.
+
+@item rfc2047-encode-encoded-words
+@vindex rfc2047-encode-encoded-words
+The boolean variable specifies whether encoded words
+(e.g., @samp{=?us-ascii?q?hello?=}) should be encoded again.
+@code{rfc2047-encoded-word-regexp} is used to look for such words.
+
+@item rfc2047-allow-irregular-q-encoded-words
+@vindex rfc2047-allow-irregular-q-encoded-words
+The boolean variable specifies whether irregular Q encoded words
+(e.g., @samp{=?us-ascii?q?hello??=}) should be decoded.  If it is
+non-@code{nil}, @code{rfc2047-encoded-word-regexp-loose} is used instead
+of @code{rfc2047-encoded-word-regexp} to look for encoded words.
+
+@end table
+
+Those were the variables, and these are this functions:
+
+@table @code
+@item rfc2047-narrow-to-field
+@findex rfc2047-narrow-to-field
+Narrow the buffer to the header on the current line.
+
+@item rfc2047-encode-message-header
+@findex rfc2047-encode-message-header
+Should be called narrowed to the header of a message.  Encodes according
+to @code{rfc2047-header-encoding-alist}.
+
+@item rfc2047-encode-region
+@findex rfc2047-encode-region
+Encodes all encodable words in the region specified.
+
+@item rfc2047-encode-string
+@findex rfc2047-encode-string
+Encode a string and return the results.
+
+@item rfc2047-decode-region
+@findex rfc2047-decode-region
+Decode the encoded words in the region.
+
+@item rfc2047-decode-string
+@findex rfc2047-decode-string
+Decode a string and return the results.
+
+@item rfc2047-encode-parameter
+@findex rfc2047-encode-parameter
+Encode a parameter in the RFC2047-like style.  This is a substitution
+for the @code{rfc2231-encode-string} function, that is the standard but
+many mailers don't support it.  @xref{rfc2231}.
+
+@end table
+
+
+@node time-date
+@section time-date
+
+While not really a part of the @acronym{MIME} library, it is convenient to
+document this library here.  It deals with parsing @code{Date} headers
+and manipulating time.  (Not by using tesseracts, though, I'm sorry to
+say.)
+
+These functions convert between five formats: A date string, an Emacs
+time structure, a decoded time list, a second number, and a day number.
+
+Here's a bunch of time/date/second/day examples:
+
+@example
+(parse-time-string "Sat Sep 12 12:21:54 1998 +0200")
+@result{} (54 21 12 12 9 1998 6 nil 7200)
+
+(date-to-time "Sat Sep 12 12:21:54 1998 +0200")
+@result{} (13818 19266)
+
+(float-time '(13818 19266))
+@result{} 905595714.0
+
+(seconds-to-time 905595714.0)
+@result{} (13818 19266 0 0)
+
+(time-to-days '(13818 19266))
+@result{} 729644
+
+(days-to-time 729644)
+@result{} (961933 512)
+
+(time-since '(13818 19266))
+@result{} (6797 9607 984839 247000)
+
+(time-less-p '(13818 19266) '(13818 19145))
+@result{} nil
+
+(subtract-time '(13818 19266) '(13818 19145))
+@result{} (0 121)
+
+(days-between "Sat Sep 12 12:21:54 1998 +0200"
+              "Sat Sep 07 12:21:54 1998 +0200")
+@result{} 5
+
+(date-leap-year-p 2000)
+@result{} t
+
+(time-to-day-in-year '(13818 19266))
+@result{} 255
+
+(time-to-number-of-days
+ (time-since
+  (date-to-time "Mon, 01 Jan 2001 02:22:26 GMT")))
+@result{} 4314.095589286675
+@end example
+
+And finally, we have @code{safe-date-to-time}, which does the same as
+@code{date-to-time}, but returns a zero time if the date is
+syntactically malformed.
+
+The five data representations used are the following:
+
+@table @var
+@item date
+An RFC822 (or similar) date string.  For instance: @code{"Sat Sep 12
+12:21:54 1998 +0200"}.
+
+@item time
+An internal Emacs time.  For instance: @code{(13818 26466 0 0)}.
+
+@item seconds
+A floating point representation of the internal Emacs time.  For
+instance: @code{905595714.0}.
+
+@item days
+An integer number representing the number of days since 00000101.  For
+instance: @code{729644}.
+
+@item decoded time
+A list of decoded time.  For instance: @code{(54 21 12 12 9 1998 6 t
+7200)}.
+@end table
+
+All the examples above represent the same moment.
+
+These are the functions available:
+
+@table @code
+@item date-to-time
+Take a date and return a time.
+
+@item float-time
+Take a time and return seconds.  (This is a built-in function.)
+
+@item seconds-to-time
+Take seconds and return a time.
+
+@item time-to-days
+Take a time and return days.
+
+@item days-to-time
+Take days and return a time.
+
+@item date-to-day
+Take a date and return days.
+
+@item time-to-number-of-days
+Take a time and return the number of days that represents.
+
+@item safe-date-to-time
+Take a date and return a time.  If the date is not syntactically valid,
+return a ``zero'' time.
+
+@item time-less-p
+Take two times and say whether the first time is less (i.e., earlier)
+than the second time.
+
+@item time-since
+Take a time and return a time saying how long it was since that time.
+
+@item subtract-time
+Take two times and subtract the second from the first.  I.e., return
+the time between the two times.
+
+@item days-between
+Take two days and return the number of days between those two days.
+
+@item date-leap-year-p
+Take a year number and say whether it's a leap year.
+
+@item time-to-day-in-year
+Take a time and return the day number within the year that the time is
+in.
+
+@end table
+
+
+@node qp
+@section qp
+
+This library deals with decoding and encoding Quoted-Printable text.
+
+Very briefly explained, qp encoding means translating all 8-bit
+characters (and lots of control characters) into things that look like
+@samp{=EF}; that is, an equal sign followed by the byte encoded as a hex
+string.
+
+The following functions are defined by the library:
+
+@table @code
+@item quoted-printable-decode-region
+@findex quoted-printable-decode-region
+QP-decode all the encoded text in the specified region.
+
+@item quoted-printable-decode-string
+@findex quoted-printable-decode-string
+Decode the QP-encoded text in a string and return the results.
+
+@item quoted-printable-encode-region
+@findex quoted-printable-encode-region
+QP-encode all the encodable characters in the specified region.  The third
+optional parameter @var{fold} specifies whether to fold long lines.
+(Long here means 72.)
+
+@item quoted-printable-encode-string
+@findex quoted-printable-encode-string
+QP-encode all the encodable characters in a string and return the
+results.
+
+@end table
+
+
+@node base64
+@section base64
+@cindex base64
+
+Base64 is an encoding that encodes three bytes into four characters,
+thereby increasing the size by about 33%.  The alphabet used for
+encoding is very resistant to mangling during transit.
+
+The following functions are defined by this library:
+
+@table @code
+@item base64-encode-region
+@findex base64-encode-region
+base64 encode the selected region.  Return the length of the encoded
+text.  Optional third argument @var{no-line-break} means do not break
+long lines into shorter lines.
+
+@item base64-encode-string
+@findex base64-encode-string
+base64 encode a string and return the result.
+
+@item base64-decode-region
+@findex base64-decode-region
+base64 decode the selected region.  Return the length of the decoded
+text.  If the region can't be decoded, return @code{nil} and don't
+modify the buffer.
+
+@item base64-decode-string
+@findex base64-decode-string
+base64 decode a string and return the result.  If the string can't be
+decoded, @code{nil} is returned.
+
+@end table
+
+
+@node binhex
+@section binhex
+@cindex binhex
+@cindex Apple
+@cindex Macintosh
+
+@code{binhex} is an encoding that originated in Macintosh environments.
+The following function is supplied to deal with these:
+
+@table @code
+@item binhex-decode-region
+@findex binhex-decode-region
+Decode the encoded text in the region.  If given a third parameter, only
+decode the @code{binhex} header and return the filename.
+
+@end table
+
+@node uudecode
+@section uudecode
+@cindex uuencode
+@cindex uudecode
+
+@code{uuencode} is probably still the most popular encoding of binaries
+used on Usenet, although @code{base64} rules the mail world.
+
+The following function is supplied by this package:
+
+@table @code
+@item uudecode-decode-region
+@findex uudecode-decode-region
+Decode the text in the region.
+@end table
+
+
+@node yenc
+@section yenc
+@cindex yenc
+
+@code{yenc} is used for encoding binaries on Usenet.  The following
+function is supplied by this package:
+
+@table @code
+@item yenc-decode-region
+@findex yenc-decode-region
+Decode the encoded text in the region.
+
+@end table
+
+
+@node rfc1843
+@section rfc1843
+@cindex rfc1843
+@cindex HZ
+@cindex Chinese
+
+RFC1843 deals with mixing Chinese and @acronym{ASCII} characters in messages.  In
+essence, RFC1843 switches between @acronym{ASCII} and Chinese by doing this:
+
+@example
+This sentence is in @acronym{ASCII}.
+The next sentence is in GB.~@{<:Ky2;S@{#,NpJ)l6HK!#~@}Bye.
+@end example
+
+Simple enough, and widely used in China.
+
+The following functions are available to handle this encoding:
+
+@table @code
+@item rfc1843-decode-region
+Decode HZ-encoded text in the region.
+
+@item rfc1843-decode-string
+Decode a HZ-encoded string and return the result.
+
+@end table
+
+
+@node mailcap
+@section mailcap
+
+The @file{~/.mailcap} file is parsed by most @acronym{MIME}-aware message
+handlers and describes how elements are supposed to be displayed.
+Here's an example file:
+
+@example
+image/*; gimp -8 %s
+audio/wav; wavplayer %s
+application/msword; catdoc %s ; copiousoutput ; nametemplate=%s.doc
+@end example
+
+This says that all image files should be displayed with @code{gimp},
+that WAVE audio files should be played by @code{wavplayer}, and that
+MS-WORD files should be inlined by @code{catdoc}.
+
+The @code{mailcap} library parses this file, and provides functions for
+matching types.
+
+@table @code
+@item mailcap-mime-data
+@vindex mailcap-mime-data
+This variable is an alist of alists containing backup viewing rules.
+
+@end table
+
+Interface functions:
+
+@table @code
+@item mailcap-parse-mailcaps
+@findex mailcap-parse-mailcaps
+Parse the @file{~/.mailcap} file.
+
+@item mailcap-mime-info
+Takes a @acronym{MIME} type as its argument and returns the matching viewer.
+
+@end table
+
+
+
+
+@node Standards
+@chapter Standards
+
+The Emacs @acronym{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 @uref{http://quimby.gnus.org/notes/}.
+
+@table @dfn
+@item RFC822
+@itemx STD11
+Standard for the Format of ARPA Internet Text Messages.
+
+@item RFC1036
+Standard for Interchange of USENET Messages
+
+@item RFC2045
+Format of Internet Message Bodies
+
+@item RFC2046
+Media Types
+
+@item RFC2047
+Message Header Extensions for Non-@acronym{ASCII} Text
+
+@item RFC2048
+Registration Procedures
+
+@item RFC2049
+Conformance Criteria and Examples
+
+@item RFC2231
+@acronym{MIME} Parameter Value and Encoded Word Extensions: Character Sets,
+Languages, and Continuations
+
+@item RFC1843
+HZ---A Data Format for Exchanging Files of Arbitrarily Mixed Chinese and
+@acronym{ASCII} characters
+
+@item draft-ietf-drums-msg-fmt-05.txt
+Draft for the successor of RFC822
+
+@item RFC2112
+The @acronym{MIME} Multipart/Related Content-type
+
+@item RFC1892
+The Multipart/Report Content Type for the Reporting of Mail System
+Administrative Messages
+
+@item RFC2183
+Communicating Presentation Information in Internet Messages: The
+Content-Disposition Header Field
+
+@item RFC2646
+Documentation of the text/plain format parameter for flowed text.
+
+@end table
+
+@node GNU Free Documentation License
+@chapter GNU Free Documentation License
+@include doclicense.texi
+
+@node Index
+@chapter Index
+@printindex cp
+
+@bye
+
+\f
+@c Local Variables:
+@c mode: texinfo
+@c coding: utf-8
+@c End:
diff --git a/xemacs-packages/gnus/texi/epa.texi b/xemacs-packages/gnus/texi/epa.texi
new file mode 100644 (file)
index 0000000..07b6af4
--- /dev/null
@@ -0,0 +1,519 @@
+\input texinfo                  @c -*- mode: texinfo -*-
+@c %**start of header
+@setfilename epa.info
+@settitle EasyPG Assistant User's Manual
+@include docstyle.texi
+@c %**end of header
+
+@set VERSION 1.0.0
+
+@copying
+This file describes EasyPG Assistant @value{VERSION}.
+
+Copyright @copyright{} 2007--2016 Free Software Foundation, Inc.
+
+@quotation
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 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''.
+
+(a) The FSF's Back-Cover Text is: ``You have the freedom to copy and
+modify this GNU manual.''
+@end quotation
+@end copying
+
+@dircategory Emacs misc features
+@direntry
+* EasyPG Assistant: (epa).      An Emacs user interface to GNU Privacy Guard.
+@end direntry
+
+@titlepage
+@title EasyPG Assistant
+
+@author by Daiki Ueno
+@page
+
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+
+@contents
+
+@node Top
+@top EasyPG Assistant user's manual
+
+EasyPG Assistant is an Emacs user interface to GNU Privacy Guard
+(GnuPG, @pxref{Top, , Top, gnupg, Using the GNU Privacy Guard}).
+
+EasyPG Assistant is a part of the package called EasyPG, an all-in-one
+GnuPG interface for Emacs.  EasyPG also contains the library interface
+called EasyPG Library.
+
+@ifnottex
+@insertcopying
+@end ifnottex
+
+@menu
+* Overview::
+* Quick start::
+* Commands::
+* Caching Passphrases::
+* Bug Reports::
+* GNU Free Documentation License::  The license for this documentation.
+* Key Index::
+* Function Index::
+* Variable Index::
+@end menu
+
+@node  Overview
+@chapter Overview
+
+EasyPG Assistant provides the following features.
+
+@itemize @bullet
+@item Key management.
+@item Cryptographic operations on regions.
+@item Cryptographic operations on files.
+@item Dired integration.
+@item Mail-mode integration.
+@item Automatic encryption/decryption of *.gpg files.
+@end itemize
+
+@node  Quick start
+@chapter Quick start
+
+EasyPG Assistant commands are prefixed by @samp{epa-}.  For example,
+
+@itemize @bullet
+@item To browse your keyring, type @kbd{M-x epa-list-keys}
+
+@item To create a cleartext signature of the region, type @kbd{M-x epa-sign-region}
+
+@item To encrypt a file, type @kbd{M-x epa-encrypt-file}
+@end itemize
+
+EasyPG Assistant provides several cryptographic features which can be
+integrated into other Emacs functionalities.  For example, automatic
+encryption/decryption of @file{*.gpg} files.
+
+@node Commands
+@chapter Commands
+
+This chapter introduces various commands for typical use cases.
+
+@menu
+* Key management::
+* Cryptographic operations on regions::
+* Cryptographic operations on files::
+* Dired integration::
+* Mail-mode integration::
+* Encrypting/decrypting gpg files::
+@end menu
+
+@node Key management
+@section Key management
+Probably the first step of using EasyPG Assistant is to browse your
+keyring.  @kbd{M-x epa-list-keys} is corresponding to @samp{gpg
+--list-keys} from the command line.
+
+@deffn Command epa-list-keys name mode
+Show all keys matched with @var{name} from the public keyring.
+@end deffn
+
+@noindent
+The output looks as follows.
+
+@example
+  u A5B6B2D4B15813FE Daiki Ueno <ueno@@unixuser.org>
+@end example
+
+@noindent
+A character on the leftmost column indicates the trust level of the
+key.  If it is @samp{u}, the key is marked as ultimately trusted.  The
+second column is the key ID, and the rest is the user ID.
+
+You can move over entries by @key{TAB}.  If you type @key{RET} or
+click button1 on an entry, you will see more detailed information
+about the key you selected.
+
+@example
+ u Daiki Ueno <ueno@@unixuser.org>
+ u A5B6B2D4B15813FE 1024bits DSA
+        Created: 2001-10-09
+        Expires: 2007-09-04
+        Capabilities: sign certify
+        Fingerprint: 8003 7CD0 0F1A 9400 03CA  50AA A5B6 B2D4 B158 13FE
+ u 4447461B2A9BEA2D 2048bits ELGAMAL_E
+        Created: 2001-10-09
+        Expires: 2007-09-04
+        Capabilities: encrypt
+        Fingerprint: 9003 D76B 73B7 4A8A E588  10AF 4447 461B 2A9B EA2D
+@end example
+
+@noindent
+To browse your private keyring, use @kbd{M-x epa-list-secret-keys}.
+
+@deffn Command epa-list-secret-keys name
+Show all keys matched with @var{name} from the private keyring.
+@end deffn
+
+@noindent
+In @file{*Keys*} buffer, several commands are available.  The common
+use case is to export some keys to a file.  To do that, type @kbd{m}
+to select keys, type @kbd{o}, and then supply the filename.
+
+Below are other commands related to key management.  Some of them take
+a file as input/output, and others take the current region.
+
+@deffn Command epa-insert-keys keys
+Insert selected @var{keys} after the point.  It will let you select
+keys before insertion.  By default, it will encode keys in the OpenPGP
+armor format.
+@end deffn
+
+@deffn Command epa-import-keys file
+Import keys from @var{file} to your keyring.
+@end deffn
+
+@deffn Command epa-import-keys-region start end
+Import keys from the current region between @var{start} and @var{end}
+to your keyring.
+@end deffn
+
+@deffn Command epa-import-armor-in-region start end
+Import keys in the OpenPGP armor format in the current region between
+@var{start} and @var{end}.  The difference from
+@code{epa-import-keys-region} is that
+@code{epa-import-armor-in-region} searches armors in the region and
+applies @code{epa-import-keys-region} to each of them.
+@end deffn
+
+@deffn Command epa-delete-keys allow-secret
+Delete selected keys.  If @var{allow-secret} is non-@code{nil}, it
+also delete the secret keys.
+@end deffn
+
+@node Cryptographic operations on regions
+@section Cryptographic operations on regions
+
+@deffn Command epa-decrypt-region start end
+Decrypt the current region between @var{start} and @var{end}.  It
+replaces the region with the decrypted text.
+@end deffn
+
+@deffn Command epa-decrypt-armor-in-region start end
+Decrypt OpenPGP armors in the current region between @var{start} and
+@var{end}.  The difference from @code{epa-decrypt-region} is that
+@code{epa-decrypt-armor-in-region} searches armors in the region
+and applies @code{epa-decrypt-region} to each of them.  That is, this
+command does not alter the original text around armors.
+@end deffn
+
+@deffn Command epa-verify-region start end
+Verify the current region between @var{start} and @var{end}.  It sends
+the verification result to the minibuffer or a popup window.  It
+replaces the region with the signed text.
+@end deffn
+
+@deffn Command epa-verify-cleartext-in-region
+Verify OpenPGP cleartext blocks in the current region between
+@var{start} and @var{end}.  The difference from
+@code{epa-verify-region} is that @code{epa-verify-cleartext-in-region}
+searches OpenPGP cleartext blocks in the region and applies
+@code{epa-verify-region} to each of them.  That is, this command does
+not alter the original text around OpenPGP cleartext blocks.
+@end deffn
+
+@deffn Command epa-sign-region start end signers type
+Sign the current region between @var{start} and @var{end}.  By
+default, it creates a cleartext signature.  If a prefix argument is
+given, it will let you select signing keys, and then a signature
+type.
+@end deffn
+
+@deffn Command epa-encrypt-region start end recipients sign signers
+Encrypt the current region between @var{start} and @var{end}.  It will
+let you select recipients.  If a prefix argument is given, it will
+also ask you whether or not to sign the text before encryption and if
+you answered yes, it will let you select the signing keys.
+@end deffn
+
+@node Cryptographic operations on files
+@section Cryptographic operations on files
+
+@deffn Command epa-decrypt-file file &optional output
+Decrypt @var{file}.  If you do not specify the name @var{output} to
+use for the decrypted file, this function prompts for the value to use.
+@end deffn
+
+@deffn Command epa-verify-file file
+Verify @var{file}.
+@end deffn
+
+@deffn Command epa-sign-file file signers type
+Sign @var{file}.  If a prefix argument is given, it will let you
+select signing keys, and then a signature type.
+@end deffn
+
+@deffn Command epa-encrypt-file file recipients
+Encrypt @var{file}.  It will let you select recipients.
+@end deffn
+
+@node Dired integration
+@section Dired integration
+
+EasyPG Assistant extends Dired Mode for GNU Emacs to allow users to
+easily do cryptographic operations on files.  For example,
+
+@example
+M-x dired
+(mark some files)
+: e (or M-x epa-dired-do-encrypt)
+(select recipients by 'm' and click [OK])
+@end example
+
+@noindent
+The following keys are assigned.
+
+@table @kbd
+@item : d
+@kindex @kbd{: d}
+@findex epa-dired-do-decrypt
+Decrypt marked files.
+
+@item : v
+@kindex @kbd{: v}
+@findex epa-dired-do-verify
+Verify marked files.
+
+@item : s
+@kindex @kbd{: s}
+@findex epa-dired-do-sign
+Sign marked files.
+
+@item : e
+@kindex @kbd{: e}
+@findex epa-dired-do-encrypt
+Encrypt marked files.
+
+@end table
+
+@node Mail-mode integration
+@section Mail-mode integration
+
+EasyPG Assistant provides a minor mode @code{epa-mail-mode} to help
+user compose inline OpenPGP messages.  Inline OpenPGP is a traditional
+style of sending signed/encrypted emails by embedding raw OpenPGP
+blobs inside a message body, not using modern MIME format.
+
+NOTE: Inline OpenPGP is not recommended and you should consider to use
+PGP/MIME@.  See
+@uref{http://josefsson.org/inline-openpgp-considered-harmful.html,
+Inline OpenPGP in E-mail is bad@comma{} Mm'kay?}.
+
+@noindent
+Once @code{epa-mail-mode} is enabled, the following keys are assigned.
+You can do it by @kbd{C-u 1 M-x epa-mail-mode} or through the Customize
+interface.  Try @kbd{M-x customize-variable epa-global-mail-mode}.
+
+@table @kbd
+@item C-c C-e C-d and C-c C-e d
+@kindex @kbd{C-c C-e C-d}
+@kindex @kbd{C-c C-e d}
+@findex epa-mail-decrypt
+Decrypt OpenPGP armors in the current buffer.
+
+@item C-c C-e C-v and C-c C-e v
+@kindex @kbd{C-c C-e C-v}
+@kindex @kbd{C-c C-e v}
+@findex epa-mail-verify
+Verify OpenPGP cleartext signed messages in the current buffer.
+
+@item C-c C-e C-s and C-c C-e s
+@kindex @kbd{C-c C-e C-s}
+@kindex @kbd{C-c C-e s}
+@findex epa-mail-sign
+Compose a signed message from the current buffer.
+
+@item C-c C-e C-e and C-c C-e e
+@kindex @kbd{C-c C-e C-e}
+@kindex @kbd{C-c C-e e}
+@findex epa-mail-encrypt
+@vindex epa-mail-aliases
+Compose an encrypted message from the current buffer.
+By default it tries to build the recipient list from @samp{to},
+@samp{cc}, and @samp{bcc} fields of the mail header.  To include your
+key in the recipient list, use @samp{encrypt-to} option in
+@file{~/.gnupg/gpg.conf}.  This function translates recipient
+addresses using the @code{epa-mail-aliases} list.  You can also
+use that option to ignore specific recipients for encryption purposes.
+
+@end table
+
+@node Encrypting/decrypting gpg files
+@section Encrypting/decrypting gpg files
+By default, every file whose name ends with @file{.gpg} will be
+treated as encrypted.  That is, when you open such a file, the
+decrypted text is inserted in the buffer rather than encrypted one.
+Similarly, when you save the buffer to a @file{foo.gpg} file,
+encrypted data is written.
+
+The file name pattern for encrypted files can be controlled by
+@var{epa-file-name-regexp}.
+
+@defvar epa-file-name-regexp
+Regexp which matches filenames treated as encrypted.
+@end defvar
+
+You can disable this behavior with @kbd{M-x epa-file-disable}, and
+then get it back with @kbd{M-x epa-file-enable}.
+
+@deffn Command epa-file-disable
+Disable automatic encryption/decryption of *.gpg files.
+@end deffn
+
+@deffn Command epa-file-enable
+Enable automatic encryption/decryption of *.gpg files.
+@end deffn
+
+@noindent
+By default, @code{epa-file} will try to use symmetric encryption, aka
+password-based encryption.  If you want to use public key encryption
+instead, do @kbd{M-x epa-file-select-keys}, which pops up the key
+selection dialog.
+
+@deffn Command epa-file-select-keys
+Select recipient keys to encrypt the currently visiting file with
+public key encryption.
+@end deffn
+
+You can also change the default behavior with the variable
+@var{epa-file-select-keys}.
+
+@defvar epa-file-select-keys
+Control whether or not to pop up the key selection dialog.
+@end defvar
+
+For frequently visited files, it might be a good idea to tell Emacs
+which encryption method should be used through @xref{File Variables, ,
+, emacs, the Emacs Manual}.  Use the @code{epa-file-encrypt-to} local
+variable for this.
+@vindex epa-file-encrypt-to
+
+For example, if you want an Elisp file to be encrypted with a
+public key associated with an email address @samp{ueno@@unixuser.org},
+add the following line to the beginning of the file.
+
+@cartouche
+@lisp
+;; -*- epa-file-encrypt-to: ("ueno@@unixuser.org") -*-
+@end lisp
+@end cartouche
+
+Instead, if you want the file always (regardless of the value of the
+@code{epa-file-select-keys} variable) encrypted with symmetric
+encryption, change the line as follows.
+
+@cartouche
+@lisp
+;; -*- epa-file-encrypt-to: nil -*-
+@end lisp
+@end cartouche
+
+Other variables which control the automatic encryption/decryption
+behavior are below.
+
+@defvar epa-file-cache-passphrase-for-symmetric-encryption
+If non-@code{nil}, cache passphrase for symmetric encryption.  The
+default value is @code{nil}.
+@end defvar
+
+@defvar epa-file-inhibit-auto-save
+If non-@code{nil}, disable auto-saving when opening an encrypted file.
+The default value is @code{t}.
+@end defvar
+
+@node Caching Passphrases
+@chapter Caching Passphrases
+
+Typing passphrases is an irritating task if you frequently open and
+close the same file.  GnuPG and EasyPG Assistant provide mechanisms to
+remember your passphrases.  However, the configuration is a bit
+confusing since it depends on your GnuPG installation (GnuPG version 1 or
+GnuPG version 2), encryption method (symmetric or public key), and whether or
+not you want to use gpg-agent.  Here are some questions:
+
+@enumerate
+@item
+Do you use GnuPG version 2 instead of GnuPG version 1?
+@item
+Do you use symmetric encryption rather than public key encryption?
+@item
+Do you want to use gpg-agent?
+@end enumerate
+
+Here are configurations depending on your answers:
+
+@multitable {111} {222} {333} {configuration configuration configuration}
+@item @b{1} @tab @b{2} @tab @b{3} @tab Configuration
+@item Yes @tab Yes @tab Yes @tab Set up gpg-agent.
+@item Yes @tab Yes @tab No @tab You can't, without gpg-agent.
+@item Yes @tab No @tab Yes @tab Set up gpg-agent.
+@item Yes @tab No @tab No @tab You can't, without gpg-agent.
+@item No @tab Yes @tab Yes @tab Set up elisp passphrase cache.
+@item No @tab Yes @tab No @tab Set up elisp passphrase cache.
+@item No @tab No @tab Yes @tab Set up gpg-agent.
+@item No @tab No @tab No @tab You can't, without gpg-agent.
+@end multitable
+
+To set up gpg-agent, follow the instruction in GnuPG manual.
+@pxref{Invoking GPG-AGENT, , Invoking GPG-AGENT, gnupg}.
+
+To set up elisp passphrase cache, set
+@code{epa-file-cache-passphrase-for-symmetric-encryption}.
+@xref{Encrypting/decrypting gpg files}.
+
+@node Bug Reports
+@chapter Bug Reports
+
+Bugs and problems with EasyPG Assistant are actively worked on by the
+Emacs development team.  Feature requests and suggestions are also
+more than welcome.  Use @kbd{M-x report-emacs-bug}, @pxref{Bugs, ,
+Bugs, emacs, Reporting Bugs}.
+
+When submitting a bug report, please try to describe in excruciating
+detail the steps required to reproduce the problem.  Also try to
+collect necessary information to fix the bug, such as:
+
+@itemize @bullet
+@item the GnuPG version.  Send the output of @samp{gpg --version}.
+@item the GnuPG configuration.  Send the contents of @file{~/.gnupg/gpg.conf}.
+@end itemize
+
+Before reporting the bug, you should set @code{epg-debug} in the
+@file{~/.emacs} file and repeat the bug.  Then, include the contents
+of the @file{ *epg-debug*} buffer.  Note that the first letter of the
+buffer name is a whitespace.
+
+@node GNU Free Documentation License
+@appendix GNU Free Documentation License
+@include doclicense.texi
+
+@node Key Index
+@unnumbered Key Index
+@printindex ky
+
+@node Function Index
+@unnumbered Function Index
+@printindex fn
+
+@node Variable Index
+@unnumbered Variable Index
+@printindex vr
+
+@bye
+
+@c End:
diff --git a/xemacs-packages/gnus/texi/etc/bar.xpm b/xemacs-packages/gnus/texi/etc/bar.xpm
new file mode 100644 (file)
index 0000000..2985065
--- /dev/null
@@ -0,0 +1,54 @@
+/* XPM */
+static char * picon-bar_xpm[] = {
+"6 48 2 1",
+"      c white s background",
+".     c black",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  ",
+"  ..  "};
diff --git a/xemacs-packages/gnus/texi/etc/gnus-group-catchup-current-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-group-catchup-current-up.xpm
new file mode 100644 (file)
index 0000000..0504f9d
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-group-catchup-current.xpm b/xemacs-packages/gnus/texi/etc/gnus-group-catchup-current.xpm
new file mode 100644 (file)
index 0000000..bea4643
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-group-describe-group-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-group-describe-group-up.xpm
new file mode 100644 (file)
index 0000000..e0ffde7
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-group-exit-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-group-exit-up.xpm
new file mode 100644 (file)
index 0000000..1b8982f
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-group-get-new-news-this-group-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-group-get-new-news-this-group-up.xpm
new file mode 100644 (file)
index 0000000..918fd2e
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-group-get-new-news-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-group-get-new-news-up.xpm
new file mode 100644 (file)
index 0000000..d324784
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-group-kill-group-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-group-kill-group-up.xpm
new file mode 100644 (file)
index 0000000..e728bf5
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-group-subscribe-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-group-subscribe-up.xpm
new file mode 100644 (file)
index 0000000..15f7d43
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-group-unsubscribe-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-group-unsubscribe-up.xpm
new file mode 100644 (file)
index 0000000..7c7ce5b
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-summary-caesar-message-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-summary-caesar-message-up.xpm
new file mode 100644 (file)
index 0000000..6f56aa9
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-summary-cancel-article-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-summary-cancel-article-up.xpm
new file mode 100644 (file)
index 0000000..fa7c639
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-summary-catchup-and-exit-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-summary-catchup-and-exit-up.xpm
new file mode 100644 (file)
index 0000000..a5d8ba6
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-summary-catchup-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-summary-catchup-up.xpm
new file mode 100644 (file)
index 0000000..9de9baf
--- /dev/null
@@ -0,0 +1,37 @@
+/* XPM */
+static char * icon-catchup2_xpm[] = {
+"32 32 2 1",
+"      c #000000000000",
+".     c #BFBFBFBFBFBF s backgroundToolBarColor",
+" ... ... ... ... ... ... ... ...",
+"................................",
+"................................",
+"................................",
+" ... ... ... ... ... ... ... ...",
+"................................",
+"................................",
+".................  .............",
+" ... ... ... ...   . ... ... ...",
+"................  ..............",
+"............... ................",
+"................................",
+" ... ... ... ... ... ... ... ...",
+"................................",
+"................................",
+".............  ..........  .....",
+" ... ... ...   . ... ...   . ...",
+"............  ..........  ......",
+"........... ........... ........",
+"............  .......... .......",
+" ... ... ... . . ... ... ... ...",
+"...............  .....          ",
+"................      ... ......",
+"........  ..... ... ...... .....",
+" ... ..   .. . . . .  .. .     .",
+".......  .... .... ... .. . ... ",
+"...... ...... ... .....  ... ...",
+"......    .. .... ......   .. ..",
+" ... ... .       ... ..  ..   ..",
+"........... ....      . ....   .",
+".......... ..... .....      .. .",
+".......... ..... ....... ...    "};
diff --git a/xemacs-packages/gnus/texi/etc/gnus-summary-exit-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-summary-exit-up.xpm
new file mode 100644 (file)
index 0000000..d1ab26a
--- /dev/null
@@ -0,0 +1,37 @@
+/* XPM */
+static char * icon-exit-summary_xpm[] = {
+"32 32 2 1",
+"      c #000000000000",
+".     c #BFBFBFBFBFBF s backgroundToolBarColor",
+" ... ... ... ... ... ... ... ...",
+"................................",
+"................................",
+"................................",
+" ... ......              ... ...",
+"........  .......        .......",
+"........ ...........     .......",
+"........  ..........     .......",
+" ... ... ... .......     ... ...",
+"................ ...     .......",
+"....................     .......",
+"........  ..........     .......",
+" ... ... ... .......     ... ...",
+"........  .......  .     .......",
+"........ .......   .     .......",
+"........  .......  .     .......",
+" ... ... ... .......     ... ...",
+"........  ..........     .......",
+"........ ...........     .......",
+"................ ...     .......",
+" ... ....... .......     ... ...",
+"........  ..........     .......",
+"........  ........   . . .......",
+"........ ....   . . . . ........",
+" ... .. ..       . . . . ... ...",
+"................................",
+"................................",
+"................................",
+" ... ... ... ... ... ... ... ...",
+"................................",
+"................................",
+"................................"};
diff --git a/xemacs-packages/gnus/texi/etc/gnus-summary-followup-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-summary-followup-up.xpm
new file mode 100644 (file)
index 0000000..3cee12e
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-summary-followup-with-original-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-summary-followup-with-original-up.xpm
new file mode 100644 (file)
index 0000000..baffb6b
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-summary-mail-copy-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-summary-mail-copy-up.xpm
new file mode 100644 (file)
index 0000000..e73e6d5
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-summary-mail-delete-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-summary-mail-delete-up.xpm
new file mode 100644 (file)
index 0000000..932d8f2
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-summary-mail-forward-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-summary-mail-forward-up.xpm
new file mode 100644 (file)
index 0000000..19db803
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-summary-mail-get-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-summary-mail-get-up.xpm
new file mode 100644 (file)
index 0000000..ffdb84c
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-summary-mail-originate-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-summary-mail-originate-up.xpm
new file mode 100644 (file)
index 0000000..8ba8bc2
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-summary-mail-reply-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-summary-mail-reply-up.xpm
new file mode 100644 (file)
index 0000000..20fe672
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-summary-mail-save-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-summary-mail-save-up.xpm
new file mode 100644 (file)
index 0000000..fd4824b
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-summary-next-unread-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-summary-next-unread-up.xpm
new file mode 100644 (file)
index 0000000..e525816
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-summary-post-news-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-summary-post-news-up.xpm
new file mode 100644 (file)
index 0000000..46be7c1
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-summary-prev-unread-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-summary-prev-unread-up.xpm
new file mode 100644 (file)
index 0000000..b2088fb
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-summary-reply-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-summary-reply-up.xpm
new file mode 100644 (file)
index 0000000..255f7a1
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-summary-reply-with-original-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-summary-reply-with-original-up.xpm
new file mode 100644 (file)
index 0000000..1135bfa
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-summary-save-article-file-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-summary-save-article-file-up.xpm
new file mode 100644 (file)
index 0000000..ea30122
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-summary-save-article-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-summary-save-article-up.xpm
new file mode 100644 (file)
index 0000000..fd4824b
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-uu-decode-uu-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-uu-decode-uu-up.xpm
new file mode 100644 (file)
index 0000000..568315c
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus-uu-post-news-up.xpm b/xemacs-packages/gnus/texi/etc/gnus-uu-post-news-up.xpm
new file mode 100644 (file)
index 0000000..f4a7e3a
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/etc/gnus.xpm b/xemacs-packages/gnus/texi/etc/gnus.xpm
new file mode 100644 (file)
index 0000000..b51c903
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/gnus-coding.texi b/xemacs-packages/gnus/texi/gnus-coding.texi
new file mode 100644 (file)
index 0000000..3b2c4af
--- /dev/null
@@ -0,0 +1,392 @@
+\input texinfo
+
+@setfilename gnus-coding.info
+@settitle Gnus Coding Style and Maintenance Guide
+@include docstyle.texi
+@syncodeindex fn cp
+@syncodeindex vr cp
+@syncodeindex pg cp
+
+@copying
+Copyright @copyright{} 2004--2005, 2007--2016 Free Software
+Foundation, Inc.
+
+@quotation
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 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''.
+
+(a) The FSF's Back-Cover Text is: ``You have the freedom to copy and
+modify this GNU manual.''
+@end quotation
+@end copying
+
+
+@titlepage
+@title Gnus Coding Style and Maintenance Guide
+
+@author by Reiner Steib  <Reiner.Steib@@gmx.de>
+
+@insertcopying
+@end titlepage
+
+@c Obviously this is only a very rudimentary draft.  We put it in the
+@c repository anyway hoping that it might annoy someone enough to fix
+@c it.  ;-) Fixing only a paragraph also is appreciated.
+
+@ifnottex
+@node Top
+@top Gnus Coding Style and Maintenance Guide
+This manual describes @dots{}
+
+@insertcopying
+@end ifnottex
+
+@menu
+* Gnus Coding Style:: Gnus Coding Style
+* Gnus Maintenance Guide:: Gnus Maintenance Guide
+* GNU Free Documentation License::  The license for this documentation.
+@end menu
+
+@c @ref{Gnus Reference Guide, ,Gnus Reference Guide, gnus, The Gnus Newsreader}
+
+@node Gnus Coding Style
+@chapter Gnus Coding Style
+@section Dependencies
+
+The Gnus distribution contains a lot of libraries that have been written
+for Gnus and used intensively for Gnus.  But many of those libraries are
+useful on their own.  E.g., other Emacs Lisp packages might use the
+@acronym{MIME} library @xref{Top, ,Top, emacs-mime, The Emacs MIME
+Manual}.
+
+@subsection General purpose libraries
+
+@table @file
+
+@item netrc.el
+@file{.netrc} parsing functionality.
+@c As of 2005-10-21...
+There are no Gnus dependencies in this file.
+
+@item format-spec.el
+Functions for formatting arbitrary formatting strings.
+@c As of 2005-10-21...
+There are no Gnus dependencies in this file.
+
+@item hex-util.el
+Functions to encode/decode hexadecimal string.
+@c As of 2007-08-25...
+There are no Gnus dependencies in these files.
+@end table
+
+@subsection Encryption and security
+
+@table @file
+@item encrypt.el
+File encryption routines
+@c As of 2005-10-25...
+There are no Gnus dependencies in this file.
+
+@item password.el
+Read passwords from user, possibly using a password cache.
+@c As of 2005-10-21...
+There are no Gnus dependencies in this file.
+
+@item tls.el
+TLS/SSL support via wrapper around GnuTLS
+@c As of 2005-10-21...
+There are no Gnus dependencies in this file.
+
+@item pgg*.el
+Glue for the various PGP implementations.
+@c As of 2005-10-21...
+There are no Gnus dependencies in these files.
+
+@item sha1.el
+SHA1 Secure Hash Algorithm.
+@c As of 2007-08-25...
+There are no Gnus dependencies in these files.
+@end table
+
+@subsection Networking
+
+@table @file
+@item dig.el
+Domain Name System dig interface.
+@c As of 2005-10-21...
+There are no serious Gnus dependencies in this file.  Uses
+@code{gnus-run-mode-hooks} (a wrapper function).
+
+@item dns.el, dns-mode.el
+Domain Name Service lookups.
+@c As of 2005-10-21...
+There are no Gnus dependencies in these files.
+@end table
+
+@subsection Mail and News related RFCs
+
+@table @file
+@item pop3.el
+Post Office Protocol (RFC 1460) interface.
+@c As of 2005-10-21...
+There are no Gnus dependencies in this file.
+
+@item imap.el
+@acronym{IMAP} library.
+@c As of 2005-10-21...
+There are no Gnus dependencies in this file.
+
+@item ietf-drums.el
+Functions for parsing RFC822bis headers.
+@c As of 2005-10-21...
+There are no Gnus dependencies in this file.
+
+@item rfc1843.el
+HZ (rfc1843) decoding.  HZ is a data format for exchanging files of
+arbitrarily mixed Chinese and @acronym{ASCII} characters.
+@c As of 2005-10-21...
+@code{rfc1843-gnus-setup} seem to be useful only for Gnus.  Maybe this
+function should be relocated to remove dependencies on Gnus.  Other
+minor dependencies: @code{gnus-newsgroup-name} could be eliminated by
+using an optional argument to @code{rfc1843-decode-article-body}.
+
+@item rfc2045.el
+Functions for decoding rfc2045 headers
+@c As of 2007-08-25...
+There are no Gnus dependencies in these files.
+
+@item rfc2047.el
+Functions for encoding and decoding rfc2047 messages
+@c As of 2007-08-25...
+There are no Gnus dependencies in these files.
+@c
+Only a couple of tests for gnusy symbols.
+
+@item rfc2104.el
+RFC2104 Hashed Message Authentication Codes
+@c As of 2007-08-25...
+There are no Gnus dependencies in these files.
+
+@item rfc2231.el
+Functions for decoding rfc2231 headers
+@c As of 2007-08-25...
+There are no Gnus dependencies in these files.
+
+@item flow-fill.el
+Interpret RFC2646 "flowed" text.
+@c As of 2005-10-27...
+There are no Gnus dependencies in this file.
+
+@item uudecode.el
+Elisp native uudecode.
+@c As of 2005-12-06...
+There are no Gnus dependencies in this file.
+@c ... but the custom group is gnus-extract.
+
+@item canlock.el
+Functions for Cancel-Lock feature
+@c Cf. draft-ietf-usefor-cancel-lock-01.txt
+@c Although this draft has expired, Canlock-Lock revived in 2007 when
+@c major news providers (e.g., news.individual.org) started to use it.
+@c As of 2007-08-25...
+There are no Gnus dependencies in these files.
+
+@end table
+
+@subsection message
+
+All message composition from Gnus (both mail and news) takes place in
+Message mode buffers.  Message mode is intended to be a replacement for
+Emacs mail mode.  There should be no Gnus dependencies in
+@file{message.el}.  Alas it is not anymore.  Patches and suggestions to
+remove the dependencies are welcome.
+
+@c message.el requires nnheader which requires gnus-util.
+
+@subsection Emacs @acronym{MIME}
+
+The files @file{mml*.el} and @file{mm-*.el} provide @acronym{MIME}
+functionality for Emacs.
+
+@acronym{MML} (@acronym{MIME} Meta Language) is supposed to be
+independent from Gnus.  Alas it is not anymore.  Patches and suggestions
+to remove the dependencies are welcome.
+
+@subsection Gnus backends
+
+The files @file{nn*.el} provide functionality for accessing NNTP
+(@file{nntp.el}), IMAP (@file{nnimap.el}) and several other Mail back
+ends (probably @file{nnml.el}, @file{nnfolder.el} and
+@file{nnmaildir.el} are the most widely used mail back ends).
+
+@c mm-uu requires nnheader which requires gnus-util.  message.el also
+@c requires nnheader.
+
+
+@section Compatibility
+
+No Gnus and Gnus 5.10.10 and up should work on:
+@itemize @bullet
+@item
+Emacs 21.1 and up.
+@item
+XEmacs 21.4 and up.
+@end itemize
+
+Gnus 5.10.8 and below should work on:
+@itemize @bullet
+@item
+Emacs 20.7 and up.
+@item
+XEmacs 21.1 and up.
+@end itemize
+
+@node Gnus Maintenance Guide
+@chapter Gnus Maintenance Guide
+
+@section Stable and development versions
+
+The development of Gnus normally is done on the Git repository trunk
+as of April 19, 2010 (formerly it was done in CVS; the repository is
+at http://git.gnus.org), i.e., there are no separate branches to
+develop and test new features.  Most of the time, the trunk is
+developed quite actively with more or less daily changes.  Only after
+a new major release, e.g., 5.10.1, there's usually a feature period of
+several months.  After the release of Gnus 5.10.6 the development of
+new features started again on the trunk while the 5.10 series is
+continued on the stable branch (v5-10) from which more stable releases
+will be done when needed (5.10.8, @dots{}).  @ref{Gnus Development,
+,Gnus Development, gnus, The Gnus Newsreader}
+
+Stable releases of Gnus finally become part of Emacs.  E.g., Gnus 5.8
+became a part of Emacs 21 (relabeled to Gnus 5.9).  The 5.10 series
+became part of Emacs 22 as Gnus 5.11.
+
+@section Syncing
+
+@c Some MIDs related to this follow.  Use http://thread.gmane.org/MID
+@c (and click on the subject) to get the thread on Gmane.
+
+@c Some quotes from Miles Bader follow...
+
+@c <v9eklyke6b.fsf@marauder.physik.uni-ulm.de>
+@c <buovfd71nkk.fsf@mctpc71.ucom.lsi.nec.co.jp>
+
+In the past, the inclusion of Gnus into Emacs was quite cumbersome.  For
+each change made to Gnus in Emacs repository, it had to be checked that
+it was applied to the new Gnus version, too.  Else, bug fixes done in
+Emacs repository might have been lost.
+
+With the inclusion of Gnus 5.10, Miles Bader has set up an Emacs-Gnus
+gateway to ensure the bug fixes from Emacs CVS are propagated to Gnus
+CVS semi-automatically.
+
+After Emacs moved to bzr and Gnus moved to git, Katsumi Yamaoka has
+taken over the chore of keeping Emacs and Gnus in sync.  In general,
+changes made to one repository will usually be replicated in the other
+within a few days.
+
+Basically the idea is that the gateway will cause all common files in
+Emacs and Gnus v5-13 to be identical except when there's a very good
+reason (e.g., the Gnus version string in Emacs says @samp{5.11}, but
+the v5-13 version string remains @samp{5.13.x}).  Furthermore, all
+changes in these files in either Emacs or the v5-13 branch will be
+installed into the Gnus git trunk, again except where there's a good
+reason.
+
+@c (typically so far the only exception has been that the changes
+@c already exist in the trunk in modified form).
+Because of this, when the next major version of Gnus will be included in
+Emacs, it should be very easy---just plonk in the files from the Gnus
+trunk without worrying about lost changes from the Emacs tree.
+
+The effect of this is that as hacker, you should generally only have to
+make changes in one place:
+
+@itemize
+@item
+If it's a file which is thought of as being outside of Gnus (e.g., the
+new @file{encrypt.el}), you should probably make the change in the Emacs
+tree, and it will show up in the Gnus tree a few days later.
+
+If you don't have Emacs repository access (or it's inconvenient), you
+can change such a file in the v5-10 branch, and it should propagate to
+the Emacs repository---however, it will get some extra scrutiny (by
+Miles) to see if the changes are possibly controversial and need
+discussion on the mailing list.  Many changes are obvious bug-fixes
+however, so often there won't be any problem.
+
+@item
+If it's to a Gnus file, and it's important enough that it should be part
+of Emacs and the v5-10 branch, then you can make the change on the v5-10
+branch, and it will go into Emacs and the Gnus git trunk (a few days
+later).  The most prominent examples for such changes are bug-fixed
+including improvements on the documentation.
+
+If you know that there will be conflicts (perhaps because the affected
+source code is different in v5-10 and the Gnus git trunk), then you can
+install your change in both places, and when I try to sync them, there
+will be a conflict---however, since in most such cases there would be a
+conflict @emph{anyway}, it's often easier for me to resolve it simply if
+I see two @samp{identical} changes, and can just choose the proper one,
+rather than having to actually fix the code.
+
+@item
+For general Gnus development changes, of course you just make the
+change on the Gnus Git trunk and it goes into Emacs a few years
+later... :-)
+
+@end itemize
+
+Of course in any case, if you just can't wait for me to sync your
+change, you can commit it in more than one place and probably there will
+be no problem; usually the changes are textually identical anyway, so
+can be easily resolved automatically (sometimes I notice silly things in
+such multiple commits, like whitespace differences, and unify those ;-).
+
+
+@c I do Emacs->Gnus less often (than Gnus->Emacs) because it tends to
+@c require more manual work.
+
+@c By default I sync about once a week.  I also try to follow any Gnus
+@c threads on the mailing lists and make sure any changes being discussed
+@c are kept more up-to-date (so say 1-2 days delay for "topical" changes).
+
+@c <buovfd71nkk.fsf@mctpc71.ucom.lsi.nec.co.jp>
+
+@c BTW, just to add even more verbose explanation about the syncing thing:
+
+@section Miscellanea
+
+@heading @file{GNUS-NEWS}
+
+Starting from No Gnus, the @file{GNUS-NEWS} is created from
+@file{texi/gnus-news.texi}.  Don't edit @file{GNUS-NEWS}.  Edit
+@file{texi/gnus-news.texi}, type @command{make GNUS-NEWS} in the
+@file{texi} directory and commit @file{GNUS-NEWS} and
+@file{texi/gnus-news.texi}.
+
+@heading Conventions for version information in defcustoms
+
+For new customizable variables introduced in Oort Gnus (including the
+v5-10 branch) use @code{:version "22.1" ;; Oort Gnus} (including the
+comment) or, e.g., @code{:version "22.2" ;; Gnus 5.10.10} if the feature
+was added for Emacs 22.2 and Gnus 5.10.10.
+@c
+If the variable is new in No Gnus use @code{:version "23.1" ;; No Gnus}.
+
+The same applies for customizable variables when its default value was
+changed.
+
+@node GNU Free Documentation License
+@appendix GNU Free Documentation License
+@include doclicense.texi
+
+@c Local Variables:
+@c mode: texinfo
+@c coding: utf-8
+@c End:
diff --git a/xemacs-packages/gnus/texi/gnus-faq.texi b/xemacs-packages/gnus/texi/gnus-faq.texi
new file mode 100644 (file)
index 0000000..90bb10f
--- /dev/null
@@ -0,0 +1,2309 @@
+@c \input texinfo @c -*-texinfo-*-
+@c Uncomment 1st line before texing this file alone.
+@c %**start of header
+@c Copyright (C) 1995, 2001-2016 Free Software Foundation, Inc.
+@c
+@c @setfilename gnus-faq.info
+@c @settitle Frequently Asked Questions
+@c @include docstyle.texi
+@c %**end of header
+@c
+
+@node Frequently Asked Questions
+@section Frequently Asked Questions
+
+@menu
+* FAQ - Changes::
+* FAQ - Introduction::                       About Gnus and this FAQ.
+* FAQ 1 - Installation FAQ::                 Installation of Gnus.
+* FAQ 2 - Startup / Group buffer::           Start up questions and the
+                                             first buffer Gnus shows you.
+* FAQ 3 - Getting Messages::                 Making Gnus read your mail
+                                             and news.
+* FAQ 4 - Reading messages::                 How to efficiently read
+                                             messages.
+* FAQ 5 - Composing messages::               Composing mails or Usenet
+                                             postings.
+* FAQ 6 - Old messages::                     Importing, archiving,
+                                             searching and deleting messages.
+* FAQ 7 - Gnus in a dial-up environment::    Reading mail and news while
+                                             offline.
+* FAQ 8 - Getting help::                     When this FAQ isn't enough.
+* FAQ 9 - Tuning Gnus::                      How to make Gnus faster.
+* FAQ - Glossary::                           Terms used in the FAQ
+                                             explained.
+@end menu
+
+@subheading Abstract
+
+This is the new Gnus Frequently Asked Questions list.
+
+Please submit features and suggestions to the
+@email{ding@@gnus.org, ding list}.
+
+@node FAQ - Changes
+@subsection Changes
+
+
+
+@itemize @bullet
+
+@item
+2008-06-15: Adjust for message-fill-column.  Add x-face-file.
+Clarify difference between ding and gnu.emacs.gnus.  Remove
+reference to discontinued service.
+
+@item
+2006-04-15: Added tip on how to delete sent buffer on exit.
+@end itemize
+
+@node FAQ - Introduction
+@subsection Introduction
+
+This is the Gnus Frequently Asked Questions list.
+
+Gnus is a Usenet Newsreader and Electronic Mail User Agent implemented
+as a part of Emacs. It's been around in some form for almost a decade
+now, and has been distributed as a standard part of Emacs for much of
+that time. Gnus 5 is the latest (and greatest) incarnation. The
+original version was called GNUS, and was written by Masanobu UMEDA@.
+When autumn crept up in '94, Lars Magne Ingebrigtsen grew bored and
+decided to rewrite Gnus.
+
+Its biggest strength is the fact that it is extremely
+customizable. It is somewhat intimidating at first glance, but
+most of the complexity can be ignored until you're ready to take
+advantage of it. If you receive a reasonable volume of e-mail
+(you're on various mailing lists), or you would like to read
+high-volume mailing lists but cannot keep up with them, or read
+high volume newsgroups or are just bored, then Gnus is what you
+want.
+
+This FAQ was maintained by Justin Sheehy until March 2002. He
+would like to thank Steve Baur and Per Abrahamsen for doing a wonderful
+job with this FAQ before him. We would like to do the same: thanks,
+Justin!
+
+This version is much nicer than the unofficial hypertext
+versions that are archived at Utrecht, Oxford, Smart Pages, Ohio
+State, and other FAQ archives. See the resources question below
+if you want information on obtaining it in another format.
+
+The information contained here was compiled with the assistance
+of the Gnus development mailing list, and any errors or
+misprints are the Gnus team's fault, sorry.
+
+@node FAQ 1 - Installation FAQ
+@subsection Installation FAQ
+
+@menu
+* FAQ 1-1::    What is the latest version of Gnus?
+* FAQ 1-2::    What's new in 5.10?
+* FAQ 1-3::    Where and how to get Gnus?
+* FAQ 1-4::    What to do with the tarball now?
+* FAQ 1-5::    I sometimes read references to No Gnus and Oort Gnus,
+               what are those?
+* FAQ 1-6::    Which version of Emacs do I need?
+* FAQ 1-7::    How do I run Gnus on both Emacs and XEmacs?
+@end menu
+
+@node FAQ 1-1
+@subsubheading Question 1.1
+
+What is the latest version of Gnus?
+
+@subsubheading Answer
+
+Jingle please: Gnus 5.10 is released, get it while it's
+hot! As well as the step in version number is rather
+small, Gnus 5.10 has tons of new features which you
+shouldn't miss. The current release (5.13) should be at
+least as stable as the latest release of the 5.8 series.
+
+@node FAQ 1-2
+@subsubheading Question 1.2
+
+What's new in 5.10?
+
+@subsubheading Answer
+
+First of all, you should have a look into the file
+GNUS-NEWS in the toplevel directory of the Gnus tarball,
+there the most important changes are listed. Here's a
+short list of the changes I find especially
+important/interesting:
+
+@itemize @bullet
+
+@item
+Major rewrite of the Gnus agent, Gnus agent is now
+active by default.
+
+@item
+Many new article washing functions for dealing with
+ugly formatted articles.
+
+@item
+Anti Spam features.
+
+@item
+Message-utils now included in Gnus.
+
+@item
+New format specifiers for summary lines, e.g., %B for
+a complex trn-style thread tree.
+@end itemize
+
+@node FAQ 1-3
+@subsubheading Question 1.3
+
+Where and how to get Gnus?
+
+@subsubheading Answer
+
+Gnus is released independent from releases of Emacs and XEmacs.
+Therefore, the version bundled with Emacs or the version in XEmacs's
+package system might not be up to date (e.g., Gnus 5.9 bundled with Emacs
+21 is outdated).
+You can get the latest released version of Gnus from
+@uref{http://www.gnus.org/dist/gnus.tar.gz}
+or via anonymous FTP from
+@uref{ftp://ftp.gnus.org/pub/gnus/gnus.tar.gz}.
+
+@node FAQ 1-4
+@subsubheading Question 1.4
+
+What to do with the tarball now?
+
+@subsubheading Answer
+
+Untar it via @samp{tar xvzf gnus.tar.gz} and do the common
+@samp{./configure; make; make install} circle.
+(under MS-Windows either get the Cygwin environment from
+@uref{http://www.cygwin.com}
+which allows you to do what's described above or unpack the
+tarball with some packer (e.g., Winace from
+@uref{http://www.winace.com})
+and use the batch-file make.bat included in the tarball to install
+Gnus.) If you don't want to (or aren't allowed to) install Gnus
+system-wide, you can install it in your home directory and add the
+following lines to your ~/.xemacs/init.el or ~/.emacs:
+
+@example
+(add-to-list 'load-path "/path/to/gnus/lisp")
+(if (featurep 'xemacs)
+    (add-to-list 'Info-directory-list "/path/to/gnus/texi/")
+  (add-to-list 'Info-default-directory-list "/path/to/gnus/texi/"))
+@end example
+@noindent
+
+Make sure that you don't have any Gnus related stuff
+before this line, on MS Windows use something like
+"C:/path/to/lisp" (yes, "/").
+
+@node FAQ 1-5
+@subsubheading Question 1.5
+
+I sometimes read references to No Gnus and Oort Gnus,
+what are those?
+
+@subsubheading Answer
+
+Oort Gnus was the name of the development version of
+Gnus, which became Gnus 5.10 in autumn 2003. No Gnus is
+the name of the current development version which will
+once become Gnus 5.12 or Gnus 6. (If you're wondering why
+not 5.11, the odd version numbers are normally used for
+the Gnus versions bundled with Emacs)
+
+@node FAQ 1-6
+@subsubheading Question 1.6
+
+Which version of Emacs do I need?
+
+@subsubheading Answer
+
+Gnus 5.13 requires an Emacs version that is greater than or equal
+to Emacs 23.1 or XEmacs 21.1, although there are some features that
+only work on Emacs 24.
+
+@node FAQ 1-7
+@subsubheading Question 1.7
+
+How do I run Gnus on both Emacs and XEmacs?
+
+@subsubheading Answer
+
+You can't use the same copy of Gnus in both as the Lisp
+files are byte-compiled to a format which is different
+depending on which Emacs did the compilation. Get one copy
+of Gnus for Emacs and one for XEmacs.
+
+@node FAQ 2 - Startup / Group buffer
+@subsection Startup / Group buffer
+
+@menu
+* FAQ 2-1::    Every time I start Gnus I get a message "Gnus auto-save
+               file exists. Do you want to read it?", what does this mean and
+               how to prevent it?
+* FAQ 2-2::    Gnus doesn't remember which groups I'm subscribed to,
+               what's this?
+* FAQ 2-3::    How to change the format of the lines in Group buffer?
+* FAQ 2-4::    My group buffer becomes a bit crowded, is there a way to
+               sort my groups into categories so I can easier browse through
+               them?
+* FAQ 2-5::    How to manually sort the groups in Group buffer? How to
+               sort the groups in a topic?
+@end menu
+
+@node FAQ 2-1
+@subsubheading Question 2.1
+
+Every time I start Gnus I get a message "Gnus auto-save
+file exists. Do you want to read it?", what does this mean
+and how to prevent it?
+
+@subsubheading Answer
+
+This message means that the last time you used Gnus, it
+wasn't properly exited and therefore couldn't write its
+information to disk (e.g., which messages you read), you
+are now asked if you want to restore that information
+from the auto-save file.
+
+To prevent this message make sure you exit Gnus
+via @samp{q} in group buffer instead of
+just killing Emacs.
+
+@node FAQ 2-2
+@subsubheading Question 2.2
+
+Gnus doesn't remember which groups I'm subscribed to,
+what's this?
+
+@subsubheading Answer
+
+You get the message described in the q/a pair above while
+starting Gnus, right? It's an other symptom for the same
+problem, so read the answer above.
+
+@node FAQ 2-3
+@subsubheading Question 2.3
+
+How to change the format of the lines in Group buffer?
+
+@subsubheading Answer
+
+You've got to tweak the value of the variable
+gnus-group-line-format. See the manual node "Group Line
+Specification" for information on how to do this. An
+example for this (guess from whose .gnus :-)):
+
+@example
+(setq gnus-group-line-format "%P%M%S[%5t]%5y : %(%g%)\n")
+@end example
+@noindent
+
+@node FAQ 2-4
+@subsubheading Question 2.4
+
+My group buffer becomes a bit crowded, is there a way to
+sort my groups into categories so I can easier browse
+through them?
+
+@subsubheading Answer
+
+Gnus offers the topic mode, it allows you to sort your
+groups in, well, topics, e.g., all groups dealing with
+Linux under the topic linux, all dealing with music under
+the topic music and all dealing with scottish music under
+the topic scottish which is a subtopic of music.
+
+To enter topic mode, just hit t while in Group buffer. Now
+you can use @samp{T n} to create a topic
+at point and @samp{T m} to move a group to
+a specific topic. For more commands see the manual or the
+menu. You might want to include the %P specifier at the
+beginning of your gnus-group-line-format variable to have
+the groups nicely indented.
+
+@node FAQ 2-5
+@subsubheading Question 2.5
+
+How to manually sort the groups in Group buffer? How to
+sort the groups in a topic?
+
+@subsubheading Answer
+
+Move point over the group you want to move and
+hit @samp{C-k}, now move point to the
+place where you want the group to be and
+hit @samp{C-y}.
+
+@node FAQ 3 - Getting Messages
+@subsection Getting Messages
+
+@menu
+* FAQ 3-1::     I just installed Gnus, started it via  @samp{M-x gnus}
+                but it only says "nntp (news) open error", what to do?
+* FAQ 3-2::     I'm working under Windows and have no idea what
+                ~/.gnus.el means.
+* FAQ 3-3::     My news server requires authentication, how to store
+                user name and password on disk?
+* FAQ 3-4::     Gnus seems to start up OK, but I can't find out how to
+                subscribe to a group.
+* FAQ 3-5::     Gnus doesn't show all groups / Gnus says I'm not allowed
+                to post on this server as well as I am, what's that?
+* FAQ 3-6::     I want Gnus to fetch news from several servers, is this
+                possible?
+* FAQ 3-7::     And how about local spool files?
+* FAQ 3-8::     OK, reading news works now, but I want to be able to
+                read my mail with Gnus, too. How to do it?
+* FAQ 3-9::     And what about IMAP?
+* FAQ 3-10::    At the office we use one of those MS Exchange servers,
+                can I use Gnus to read my mail from it?
+* FAQ 3-11::    Can I tell Gnus not to delete the mails on the server it
+                retrieves via POP3?
+@end menu
+
+@node FAQ 3-1
+@subsubheading Question 3.1
+
+I just installed Gnus, started it via
+@samp{M-x gnus}
+but it only says "nntp (news) open error", what to do?
+
+@subsubheading Answer
+
+You've got to tell Gnus where to fetch the news from. Read
+the documentation for information on how to do this. As a
+first start, put those lines in @file{~/.gnus.el}:
+
+@example
+(setq gnus-select-method '(nntp "news.yourprovider.net"))
+(setq user-mail-address "you@@yourprovider.net")
+(setq user-full-name "Your Name")
+@end example
+@noindent
+
+@node FAQ 3-2
+@subsubheading Question 3.2
+
+I'm working under Windows and have no idea what @file{~/.gnus.el} means.
+
+@subsubheading Answer
+
+The ~/ means the home directory where Gnus and Emacs look
+for the configuration files.  However, you don't really
+need to know what this means, it suffices that Emacs knows
+what it means :-) You can type
+@samp{C-x C-f ~/.gnus.el RET }
+(yes, with the forward slash, even on Windows), and
+Emacs will open the right file for you.  (It will most
+likely be new, and thus empty.)
+However, I'd discourage you from doing so, since the
+directory Emacs chooses will most certainly not be what
+you want, so let's do it the correct way.
+The first thing you've got to do is to
+create a suitable directory (no blanks in directory name
+please), e.g., c:\myhome. Then you must set the environment
+variable HOME to this directory.  To do this under Windows 9x
+or Me include the line
+
+@example
+SET HOME=C:\myhome
+@end example
+@noindent
+
+in your autoexec.bat and reboot.  Under NT, 2000 and XP, hit
+Winkey+Pause/Break to enter system options (if it doesn't work, go
+to Control Panel -> System -> Advanced). There you'll find the
+possibility to set environment variables.  Create a new one with
+name HOME and value C:\myhome.  Rebooting is not necessary.
+
+Now to create @file{~/.gnus.el}, say
+@samp{C-x C-f ~/.gnus.el RET C-x C-s}.
+in Emacs.
+
+@node FAQ 3-3
+@subsubheading Question 3.3
+
+My news server requires authentication, how to store
+user name and password on disk?
+
+@subsubheading Answer
+
+Create a file ~/.authinfo which includes for each server a line like this
+
+@example
+machine news.yourprovider.net login YourUserName password YourPassword
+@end example
+@noindent
+.
+Make sure that the file isn't readable to others if you
+work on a OS which is capable of doing so.  (Under Unix
+say
+@example
+chmod 600 ~/.authinfo
+@end example
+@noindent
+
+in a shell.)
+
+@node FAQ 3-4
+@subsubheading Question 3.4
+
+Gnus seems to start up OK, but I can't find out how to
+subscribe to a group.
+
+@subsubheading Answer
+
+If you know the name of the group say @samp{U
+name.of.group RET} in group buffer (use the
+tab-completion Luke). Otherwise hit ^ in group buffer,
+this brings you to the server buffer. Now place point (the
+cursor) over the server which carries the group you want,
+hit @samp{RET}, move point to the group
+you want to subscribe to and say @samp{u}
+to subscribe to it.
+
+@node FAQ 3-5
+@subsubheading Question 3.5
+
+Gnus doesn't show all groups / Gnus says I'm not allowed to
+post on this server as well as I am, what's that?
+
+@subsubheading Answer
+
+Some providers allow restricted anonymous access and full
+access only after authorization. To make Gnus send authinfo
+to those servers append
+
+@example
+force yes
+@end example
+@noindent
+
+to the line for those servers in ~/.authinfo.
+
+@node FAQ 3-6
+@subsubheading Question 3.6
+
+I want Gnus to fetch news from several servers, is this possible?
+
+@subsubheading Answer
+
+Of course. You can specify more sources for articles in the
+variable gnus-secondary-select-methods. Add something like
+this in @file{~/.gnus.el}:
+
+@example
+(add-to-list 'gnus-secondary-select-methods
+             '(nntp "news.yourSecondProvider.net"))
+(add-to-list 'gnus-secondary-select-methods
+             '(nntp "news.yourThirdProvider.net"))
+@end example
+@noindent
+
+@node FAQ 3-7
+@subsubheading Question 3.7
+
+And how about local spool files?
+
+@subsubheading Answer
+
+No problem, this is just one more select method called
+nnspool, so you want this:
+
+@example
+(add-to-list 'gnus-secondary-select-methods '(nnspool ""))
+@end example
+@noindent
+
+Or this if you don't want an NNTP Server as primary news source:
+
+@example
+(setq gnus-select-method '(nnspool ""))
+@end example
+@noindent
+
+Gnus will look for the spool file in /usr/spool/news, if you
+want something different, change the line above to something like this:
+
+@example
+(add-to-list 'gnus-secondary-select-methods
+             '(nnspool ""
+                       (nnspool-directory "/usr/local/myspoolddir")))
+@end example
+@noindent
+
+This sets the spool directory for this server only.
+You might have to specify more stuff like the program used
+to post articles, see the Gnus manual on how to do this.
+
+@node FAQ 3-8
+@subsubheading Question 3.8
+
+OK, reading news works now, but I want to be able to read my mail
+with Gnus, too. How to do it?
+
+@subsubheading Answer
+
+That's a bit harder since there are many possible sources
+for mail, many possible ways for storing mail and many
+different ways for sending mail. The most common cases are
+these: 1: You want to read your mail from a pop3 server and
+send them directly to a SMTP Server 2: Some program like
+fetchmail retrieves your mail and stores it on disk from
+where Gnus shall read it. Outgoing mail is sent by
+Sendmail, Postfix or some other MTA@. Sometimes, you even
+need a combination of the above cases.
+
+However, the first thing to do is to tell Gnus in which way
+it should store the mail, in Gnus terminology which back end
+to use. Gnus supports many different back ends, the most
+commonly used one is nnml. It stores every mail in one file
+and is therefore quite fast. However you might prefer a one
+file per group approach if your file system has problems with
+many small files, the nnfolder back end is then probably the
+choice for you.  To use nnml add the following to @file{~/.gnus.el}:
+
+@example
+(add-to-list 'gnus-secondary-select-methods '(nnml ""))
+@end example
+@noindent
+
+As you might have guessed, if you want nnfolder, it's
+
+@example
+(add-to-list 'gnus-secondary-select-methods '(nnfolder ""))
+@end example
+@noindent
+
+Now we need to tell Gnus, where to get its mail from. If
+it's a POP3 server, then you need something like this:
+
+@example
+(eval-after-load "mail-source"
+  '(add-to-list 'mail-sources '(pop :server "pop.YourProvider.net"
+                                    :user "yourUserName"
+                                    :password "yourPassword")))
+@end example
+@noindent
+
+Make sure @file{~/.gnus.el} isn't readable to others if you store
+your password there. If you want to read your mail from a
+traditional spool file on your local machine, it's
+
+@example
+(eval-after-load "mail-source"
+  '(add-to-list 'mail-sources '(file :path "/path/to/spool/file"))
+@end example
+@noindent
+
+If it's a Maildir, with one file per message as used by
+postfix, Qmail and (optionally) fetchmail it's
+
+@example
+(eval-after-load "mail-source"
+  '(add-to-list 'mail-sources '(maildir :path "/path/to/Maildir/"
+                                        :subdirs ("cur" "new")))
+@end example
+@noindent
+
+And finally if you want to read your mail from several files
+in one directory, for example because procmail already split your
+mail, it's
+
+@example
+(eval-after-load "mail-source"
+  '(add-to-list 'mail-sources
+                '(directory :path "/path/to/procmail-dir/"
+                            :suffix ".prcml")))
+@end example
+@noindent
+
+Where :suffix ".prcml" tells Gnus only to use files with the
+suffix .prcml.
+
+OK, now you only need to tell Gnus how to send mail. If you
+want to send mail via sendmail (or whichever MTA is playing
+the role of sendmail on your system), you don't need to do
+anything. However, if you want to send your mail to an
+SMTP Server you need the following in your @file{~/.gnus.el}
+
+@example
+(setq send-mail-function 'smtpmail-send-it)
+(setq message-send-mail-function 'smtpmail-send-it)
+(setq smtpmail-default-smtp-server "smtp.yourProvider.net")
+@end example
+@noindent
+
+@node FAQ 3-9
+@subsubheading Question 3.9
+
+And what about IMAP?
+
+@subsubheading Answer
+
+There are two ways of using IMAP with Gnus. The first one is
+to use IMAP like POP3, that means Gnus fetches the mail from
+the IMAP server and stores it on disk. If you want to do
+this (you don't really want to do this) add the following to
+@file{~/.gnus.el}
+
+@example
+(add-to-list 'mail-sources '(imap :server "mail.mycorp.com"
+                                  :user "username"
+                                  :pass "password"
+                                  :stream network
+                                  :authentication login
+                                  :mailbox "INBOX"
+                                  :fetchflag "\\Seen"))
+@end example
+@noindent
+
+You might have to tweak the values for stream and/or
+authentication, see the Gnus manual node "Mail Source
+Specifiers" for possible values.
+
+If you want to use IMAP the way it's intended, you've got to
+follow a different approach.  You've got to add the nnimap
+back end to your select method and give the information
+about the server there.
+
+@example
+(add-to-list 'gnus-secondary-select-methods
+             '(nnimap "Give the baby a name"
+                      (nnimap-address "imap.yourProvider.net")
+                      (nnimap-port 143)
+                      (nnimap-list-pattern "archive.*")))
+@end example
+@noindent
+
+Again, you might have to specify how to authenticate to the
+server if Gnus can't guess the correct way, see the Manual
+Node "IMAP" for detailed information.
+
+@node FAQ 3-10
+@subsubheading Question 3.10
+
+At the office we use one of those MS Exchange servers, can I use
+Gnus to read my mail from it?
+
+@subsubheading Answer
+
+Offer your administrator a pair of new running shoes for
+activating IMAP on the server and follow the instructions
+above.
+
+@node FAQ 3-11
+@subsubheading Question 3.11
+
+Can I tell Gnus not to delete the mails on the server it
+retrieves via POP3?
+
+@subsubheading Answer
+
+Yes, if the POP3 server supports the UIDL control (maybe almost servers
+do it nowadays).  To do that, add a @code{:leave VALUE} pair to each
+POP3 mail source.  See @pxref{Mail Source Specifiers} for VALUE.
+
+@node FAQ 4 - Reading messages
+@subsection Reading messages
+
+@menu
+* FAQ 4-1::     When I enter a group, all read messages are gone. How to
+                view them again?
+* FAQ 4-2::     How to tell Gnus to show an important message every time
+                I enter a group, even when it's read?
+* FAQ 4-3::     How to view the headers of a message?
+* FAQ 4-4::     How to view the raw unformatted message?
+* FAQ 4-5::     How can I change the headers Gnus displays by default at
+                the top of the article buffer?
+* FAQ 4-6::     I'd like Gnus NOT to render HTML-mails but show me the
+                text part if it's available. How to do it?
+* FAQ 4-7::     Can I use some other browser than shr to render my
+                HTML-mails?
+* FAQ 4-8::     Is there anything I can do to make poorly formatted
+                mails more readable?
+* FAQ 4-9::     Is there a way to automatically ignore posts by specific
+                authors or with specific words in the subject? And can I
+                highlight more interesting ones in some way?
+* FAQ 4-10::    How can I disable threading in some (e.g., mail-) groups,
+                or set other variables specific for some groups?
+* FAQ 4-11::    Can I highlight messages written by me and follow-ups to
+                those?
+* FAQ 4-12::    The number of total messages in a group which Gnus
+                displays in group buffer is by far to high, especially in mail
+                groups. Is this a bug?
+* FAQ 4-13::    I don't like the layout of summary and article buffer,
+                how to change it? Perhaps even a three pane display?
+* FAQ 4-14::    I don't like the way the Summary buffer looks, how to
+                tweak it?
+* FAQ 4-15::    How to split incoming mails in several groups?
+* FAQ 4-16::    How can I ensure more contrast when viewing HTML mail?
+@end menu
+
+@node FAQ 4-1
+@subsubheading Question 4.1
+
+When I enter a group, all read messages are gone. How to view them again?
+
+@subsubheading Answer
+
+If you enter the group by saying
+@samp{RET}
+in group buffer with point over the group, only unread and ticked messages are loaded. Say
+@samp{C-u RET}
+instead to load all available messages. If you want only the 300 newest say
+@samp{C-u 300 RET}
+
+Loading only unread messages can be annoying if you have threaded view enabled, say
+
+@example
+(setq gnus-fetch-old-headers 'some)
+@end example
+@noindent
+
+in @file{~/.gnus.el} to load enough old articles to prevent teared threads, replace 'some with @code{t} to load
+all articles (Warning: Both settings enlarge the amount of data which is
+fetched when you enter a group and slow down the process of entering a group).
+
+If you already use Gnus 5.10, you can say
+@samp{/o N}
+In summary buffer to load the last N messages, this feature is not available in 5.8.8
+
+If you don't want all old messages, but the parent of the message you're just reading,
+you can say @samp{^}, if you want to retrieve the whole thread
+the message you're just reading belongs to, @samp{A T} is your friend.
+
+@node FAQ 4-2
+@subsubheading Question 4.2
+
+How to tell Gnus to show an important message every time I
+enter a group, even when it's read?
+
+@subsubheading Answer
+
+You can tick important messages. To do this hit
+@samp{u} while point is in summary buffer
+over the message. When you want to remove the mark, hit
+either @samp{d} (this deletes the tick
+mark and set's unread mark) or @samp{M c}
+(which deletes all marks for the message).
+
+@node FAQ 4-3
+@subsubheading Question 4.3
+
+How to view the headers of a message?
+
+@subsubheading Answer
+
+Say @samp{t}
+to show all headers, one more
+@samp{t}
+hides them again.
+
+@node FAQ 4-4
+@subsubheading Question 4.4
+
+How to view the raw unformatted message?
+
+@subsubheading Answer
+
+Say
+@samp{C-u g}
+to show the raw message
+@samp{g}
+returns to normal view.
+
+@node FAQ 4-5
+@subsubheading Question 4.5
+
+How can I change the headers Gnus displays by default at
+the top of the article buffer?
+
+@subsubheading Answer
+
+The variable gnus-visible-headers controls which headers
+are shown, its value is a regular expression, header lines
+which match it are shown. So if you want author, subject,
+date, and if the header exists, Followup-To and MUA / NUA
+say this in @file{~/.gnus.el}:
+
+@example
+(setq gnus-visible-headers
+      '("^From" "^Subject" "^Date" "^Newsgroups" "^Followup-To"
+        "^User-Agent" "^X-Newsreader" "^X-Mailer"))
+@end example
+@noindent
+
+@node FAQ 4-6
+@subsubheading Question 4.6
+
+I'd like Gnus NOT to render HTML-mails but show me the
+text part if it's available. How to do it?
+
+@subsubheading Answer
+
+Say
+
+@example
+(eval-after-load "mm-decode"
+ '(progn
+      (add-to-list 'mm-discouraged-alternatives "text/html")
+      (add-to-list 'mm-discouraged-alternatives "text/richtext")))
+@end example
+@noindent
+
+in @file{~/.gnus.el}. If you don't want HTML rendered, even if there's no text alternative add
+
+@example
+(setq mm-automatic-display (remove "text/html" mm-automatic-display))
+@end example
+@noindent
+
+too.
+
+@node FAQ 4-7
+@subsubheading Question 4.7
+
+Can I use some other browser than w3m to render my HTML-mails?
+
+@subsubheading Answer
+
+Only if you use Gnus 5.10 or younger. In this case you've got the
+choice between shr, w3m, links, lynx and html2text, which
+one is used can be specified in the variable
+mm-text-html-renderer, so if you want links to render your
+mail say
+
+@example
+(setq mm-text-html-renderer 'links)
+@end example
+@noindent
+
+@node FAQ 4-8
+@subsubheading Question 4.8
+
+Is there anything I can do to make poorly formatted mails
+more readable?
+
+@subsubheading Answer
+
+Gnus offers you several functions to ``wash'' incoming mail, you can
+find them if you browse through the menu, item
+Article->Washing. The most interesting ones are probably ``Wrap
+long lines'' (@samp{W w}), ``Decode ROT13''
+(@samp{W r}) and ``Outlook Deuglify'' which repairs
+the dumb quoting used by many users of Microsoft products
+(@samp{W Y f} gives you full deuglify.
+See @samp{W Y C-h} or have a look at the menus for
+other deuglifications).  Outlook deuglify is only available since
+Gnus 5.10.
+
+@node FAQ 4-9
+@subsubheading Question 4.9
+
+Is there a way to automatically ignore posts by specific
+authors or with specific words in the subject? And can I
+highlight more interesting ones in some way?
+
+@subsubheading Answer
+
+You want Scoring. Scoring means, that you define rules
+which assign each message an integer value. Depending on
+the value the message is highlighted in summary buffer (if
+it's high, say +2000) or automatically marked read (if the
+value is low, say -800) or some other action happens.
+
+There are basically three ways of setting up rules which assign
+the scoring-value to messages. The first and easiest way is to set
+up rules based on the article you are just reading. Say you're
+reading a message by a guy who always writes nonsense and you want
+to ignore his messages in the future. Hit
+@samp{L}, to set up a rule which lowers the score.
+Now Gnus asks you which the criteria for lowering the Score shall
+be. Hit @samp{?} twice to see all possibilities,
+we want @samp{a} which means the author (the from
+header). Now Gnus wants to know which kind of matching we want.
+Hit either @samp{e} for an exact match or
+@samp{s} for substring-match and delete afterwards
+everything but the name to score down all authors with the given
+name no matter which email address is used. Now you need to tell
+Gnus when to apply the rule and how long it should last, hit
+@samp{p} to apply the rule now and let it last
+forever. If you want to raise the score instead of lowering it say
+@samp{I} instead of @samp{L}.
+
+You can also set up rules by hand. To do this say @samp{V
+f} in summary buffer. Then you are asked for the name
+of the score file, it's name.of.group.SCORE for rules valid in
+only one group or all.Score for rules valid in all groups. See the
+Gnus manual for the exact syntax, basically it's one big list
+whose elements are lists again. the first element of those lists
+is the header to score on, then one more list with what to match,
+which score to assign, when to expire the rule and how to do the
+matching. If you find me very interesting, you could add the
+following to your all.Score:
+
+@example
+(("references" ("hschmi22.userfqdn.rz-online.de" 500 nil s))
+ ("message-id" ("hschmi22.userfqdn.rz-online.de" 999 nil s)))
+@end example
+@noindent
+
+This would add 999 to the score of messages written by me
+and 500 to the score of messages which are a (possibly
+indirect) answer to a message written by me. Of course
+nobody with a sane mind would do this :-)
+
+The third alternative is adaptive scoring. This means Gnus
+watches you and tries to find out what you find
+interesting and what annoying and sets up rules
+which reflect this. Adaptive scoring can be a huge help
+when reading high traffic groups. If you want to activate
+adaptive scoring say
+
+@example
+(setq gnus-use-adaptive-scoring t)
+@end example
+@noindent
+
+in @file{~/.gnus.el}.
+
+@node FAQ 4-10
+@subsubheading Question 4.10
+
+How can I disable threading in some (e.g., mail-) groups, or
+set other variables specific for some groups?
+
+@subsubheading Answer
+
+While in group buffer move point over the group and hit
+@samp{G c}, this opens a buffer where you
+can set options for the group. At the bottom of the buffer
+you'll find an item that allows you to set variables
+locally for the group. To disable threading enter
+gnus-show-threads as name of variable and @code{nil} as
+value. Hit button done at the top of the buffer when
+you're ready.
+
+@node FAQ 4-11
+@subsubheading Question 4.11
+
+Can I highlight messages written by me and follow-ups to
+those?
+
+@subsubheading Answer
+
+Stop those "Can I ..." questions, the answer is always yes
+in Gnus Country :-). It's a three step process: First we
+make faces (specifications of how summary-line shall look
+like) for those postings, then we'll give them some
+special score and finally we'll tell Gnus to use the new
+faces.
+
+@node FAQ 4-12
+@subsubheading Question 4.12
+
+The number of total messages in a group which Gnus
+displays in group buffer is by far to high, especially in
+mail groups. Is this a bug?
+
+@subsubheading Answer
+
+No, that's a matter of design of Gnus, fixing this would
+mean reimplementation of major parts of Gnus'
+back ends. Gnus thinks ``highest-article-number @minus{}
+lowest-article-number = total-number-of-articles''. This
+works OK for Usenet groups, but if you delete and move
+many messages in mail groups, this fails. To cure the
+symptom, enter the group via @samp{C-u RET}
+(this makes Gnus get all messages), then
+hit @samp{M P b} to mark all messages and
+then say @samp{B m name.of.group} to move
+all messages to the group they have been in before, they
+get new message numbers in this process and the count is
+right again (until you delete and move your mail to other
+groups again).
+
+@node FAQ 4-13
+@subsubheading Question 4.13
+
+I don't like the layout of summary and article buffer, how
+to change it? Perhaps even a three pane display?
+
+@subsubheading Answer
+
+You can control the windows configuration by calling the
+function gnus-add-configuration. The syntax is a bit
+complicated but explained very well in the manual node
+"Window Layout". Some popular examples:
+
+Instead 25% summary 75% article buffer 35% summary and 65%
+article (the 1.0 for article means "take the remaining
+space"):
+
+@example
+(gnus-add-configuration
+ '(article (vertical 1.0 (summary .35 point) (article 1.0))))
+@end example
+@noindent
+
+A three pane layout, Group buffer on the left, summary
+buffer top-right, article buffer bottom-right:
+
+@example
+(gnus-add-configuration
+ '(article
+   (horizontal 1.0
+               (vertical 25
+                         (group 1.0))
+               (vertical 1.0
+                         (summary 0.25 point)
+                         (article 1.0)))))
+(gnus-add-configuration
+ '(summary
+   (horizontal 1.0
+               (vertical 25
+                         (group 1.0))
+               (vertical 1.0
+                         (summary 1.0 point)))))
+@end example
+@noindent
+
+@node FAQ 4-14
+@subsubheading Question 4.14
+
+I don't like the way the Summary buffer looks, how to tweak it?
+
+@subsubheading Answer
+
+You've got to play around with the variable
+gnus-summary-line-format. Its value is a string of
+symbols which stand for things like author, date, subject
+etc. A list of the available specifiers can be found in the
+manual node ``Summary Buffer Lines'' and the often forgotten
+node ``Formatting Variables'' and its sub-nodes. There
+you'll find useful things like positioning the cursor and
+tabulators which allow you a summary in table form, but
+sadly hard tabulators are broken in 5.8.8.
+
+Since 5.10, Gnus offers you some very nice new specifiers,
+e.g., %B which draws a thread-tree and %&user-date which
+gives you a date where the details are dependent of the
+articles age. Here's an example which uses both:
+
+@example
+(setq gnus-summary-line-format ":%U%R %B %s %-60=|%4L |%-20,20f |%&user-date; \n")
+@end example
+@noindent
+
+resulting in:
+
+@example
+:O     Re: [Richard Stallman] rfc2047.el          |  13 |Lars Magne Ingebrigt |Sat 23:06
+:O     Re: Revival of the ding-patches list       |  13 |Lars Magne Ingebrigt |Sat 23:12
+:R  >  Re: Find correct list of articles for a gro|  25 |Lars Magne Ingebrigt |Sat 23:16
+:O  \->  ...                                      |  21 |Kai Grossjohann      | 0:01
+:R  >  Re: Cry for help: deuglify.el - moving stuf|  28 |Lars Magne Ingebrigt |Sat 23:34
+:O  \->  ...                                      | 115 |Raymond Scholz       | 1:24
+:O    \->  ...                                    |  19 |Lars Magne Ingebrigt |15:33
+:O     Slow mailing list                          |  13 |Lars Magne Ingebrigt |Sat 23:49
+:O     Re: '@@' mark not documented                |  13 |Lars Magne Ingebrigt |Sat 23:50
+:R  >  Re: Gnus still doesn't count messages prope|  23 |Lars Magne Ingebrigt |Sat 23:57
+:O  \->  ...                                      |  18 |Kai Grossjohann      | 0:35
+:O    \->  ...                                    |  13 |Lars Magne Ingebrigt | 0:56
+@end example
+@noindent
+
+@node FAQ 4-15
+@subsubheading Question 4.15
+
+How to split incoming mails in several groups?
+
+@subsubheading Answer
+
+Gnus offers two possibilities for splitting mail, the easy
+nnmail-split-methods and the more powerful Fancy Mail
+Splitting. I'll only talk about the first one, refer to
+the manual, node "Fancy Mail Splitting" for the latter.
+
+The value of nnmail-split-methods is a list, each element
+is a list which stands for a splitting rule. Each rule has
+the form "group where matching articles should go to",
+"regular expression which has to be matched", the first
+rule which matches wins. The last rule must always be a
+general rule (regular expression .*) which denotes where
+articles should go which don't match any other rule. If
+the folder doesn't exist yet, it will be created as soon
+as an article lands there.  By default the mail will be
+send to all groups whose rules match. If you
+don't want that (you probably don't want), say
+
+@example
+(setq nnmail-crosspost nil)
+@end example
+@noindent
+
+in @file{~/.gnus.el}.
+
+An example might be better than thousand words, so here's
+my nnmail-split-methods. Note that I send duplicates in a
+special group and that the default group is spam, since I
+filter all mails out which are from some list I'm
+subscribed to or which are addressed directly to me
+before. Those rules kill about 80% of the Spam which
+reaches me (Email addresses are changed to prevent spammers
+from using them):
+
+@example
+(setq nnmail-split-methods
+  '(("duplicates" "^Gnus-Warning:.*duplicate")
+    ("XEmacs-NT" "^\\(To:\\|CC:\\).*localpart@@xemacs.invalid.*")
+    ("Gnus-Tut" "^\\(To:\\|CC:\\).*localpart@@socha.invalid.*")
+    ("tcsh" "^\\(To:\\|CC:\\).*localpart@@mx.gw.invalid.*")
+    ("BAfH" "^\\(To:\\|CC:\\).*localpart@@.*uni-muenchen.invalid.*")
+    ("Hamster-src" "^\\(CC:\\|To:\\).*hamster-sourcen@@yahoogroups.\\(de\\|com\\).*")
+    ("Tagesschau" "^From: tagesschau <localpart@@www.tagesschau.invalid>$")
+    ("Replies" "^\\(CC:\\|To:\\).*localpart@@Frank-Schmitt.invalid.*")
+    ("EK" "^From:.*\\(localpart@@privateprovider.invalid\\|localpart@@workplace.invalid\\).*")
+    ("Spam" "^Content-Type:.*\\(ks_c_5601-1987\\|EUC-KR\\|big5\\|iso-2022-jp\\).*")
+    ("Spam" "^Subject:.*\\(This really work\\|XINGA\\|ADV:\\|XXX\\|adult\\|sex\\).*")
+    ("Spam" "^Subject:.*\\(\=\?ks_c_5601-1987\?\\|\=\?euc-kr\?\\|\=\?big5\?\\).*")
+    ("Spam" "^X-Mailer:\\(.*BulkMailer.*\\|.*MIME::Lite.*\\|\\)")
+    ("Spam" "^X-Mailer:\\(.*CyberCreek Avalanche\\|.*http\:\/\/GetResponse\.com\\)")
+    ("Spam" "^From:.*\\(verizon\.net\\|prontomail\.com\\|money\\|ConsumerDirect\\).*")
+    ("Spam" "^Delivered-To: GMX delivery to spamtrap@@gmx.invalid$")
+    ("Spam" "^Received: from link2buy.com")
+    ("Spam" "^CC: .*azzrael@@t-online.invalid")
+    ("Spam" "^X-Mailer-Version: 1.50 BETA")
+    ("Uni" "^\\(CC:\\|To:\\).*localpart@@uni-koblenz.invalid.*")
+    ("Inbox" "^\\(CC:\\|To:\\).*\\(my\ name\\|address@@one.invalid\\|address@@two.invalid\\)")
+    ("Spam" "")))
+@end example
+@noindent
+
+@node FAQ 4-16
+@subsubheading Question 4.16
+
+How can I ensure more contrast when viewing HTML mail?
+
+@subsubheading Answer
+
+Gnus' built-in simple HTML renderer (you use it if the value of
+@code{mm-text-html-renderer} is @code{shr}) uses the colors which are
+declared in the HTML mail.  However, it adjusts them in order to
+prevent situations like dark gray text on black background.  In case
+the results still have a too low contrast for you, increase the values
+of the variables @code{shr-color-visible-distance-min} and
+@code{shr-color-visible-luminance-min}.
+
+@node FAQ 5 - Composing messages
+@subsection Composing messages
+
+@menu
+* FAQ 5-1::     What are the basic commands I need to know for sending
+                mail and postings?
+* FAQ 5-2::     How to enable automatic word-wrap when composing
+                messages?
+* FAQ 5-3::     How to set stuff like From, Organization, Reply-To,
+                signature...?
+* FAQ 5-4::     Can I set things like From, Signature etc. group based on
+                the group I post too?
+* FAQ 5-5::     Is there a spell-checker? Perhaps even on-the-fly
+                spell-checking?
+* FAQ 5-6::     Can I set the dictionary based on the group I'm posting
+                to?
+* FAQ 5-7::     Is there some kind of address-book, so I needn't
+                remember all those email addresses?
+* FAQ 5-8::     Sometimes I see little images at the top of article
+                buffer. What's that and how can I send one with my postings,
+                too?
+* FAQ 5-9::     Sometimes I accidentally hit r instead of f in
+                newsgroups. Can Gnus warn me, when I'm replying by mail in
+                newsgroups?
+* FAQ 5-10::    How to tell Gnus not to generate a sender header?
+* FAQ 5-11::    I want Gnus to locally store copies of my send mail and
+                news, how to do it?
+* FAQ 5-12::    I want Gnus to kill the buffer after successful sending
+                instead of keeping it alive as "Sent mail to...", how to do it?
+* FAQ 5-13::    People tell me my Message-IDs are not correct, why
+                aren't they and how to fix it?
+@end menu
+
+@node FAQ 5-1
+@subsubheading Question 5.1
+
+What are the basic commands I need to know for sending mail and postings?
+
+@subsubheading Answer
+
+To start composing a new mail hit @samp{m}
+either in Group or Summary buffer, for a posting, it's
+either @samp{a} in Group buffer and
+filling the Newsgroups header manually
+or @samp{a} in the Summary buffer of the
+group where the posting shall be send to. Replying by mail
+is
+@samp{r} if you don't want to cite the
+author, or import the cited text manually and
+@samp{R} to cite the text of the original
+message. For a follow up to a newsgroup, it's
+@samp{f} and @samp{F}
+(analogously to @samp{r} and
+@samp{R}).
+
+Enter new headers above the line saying "--text follows
+this line--", enter the text below the line. When ready
+hit @samp{C-c C-c}, to send the message,
+if you want to finish it later hit @samp{C-c
+C-d} to save it in the drafts group, where you
+can start editing it again by saying @samp{D
+e}.
+
+@node FAQ 5-2
+@subsubheading Question 5.2
+
+How to enable automatic word-wrap when composing messages?
+
+@subsubheading Answer
+
+Starting from No Gnus, automatic word-wrap is already enabled by
+default, see the variable message-fill-column.
+
+For other versions of Gnus, say
+
+@example
+(unless (boundp 'message-fill-column)
+  (add-hook 'message-mode-hook
+            (lambda ()
+              (setq fill-column 72)
+              (turn-on-auto-fill))))
+@end example
+@noindent
+
+in @file{~/.gnus.el}.
+
+You can reformat a paragraph by hitting @samp{M-q}
+(as usual).
+
+@node FAQ 5-3
+@subsubheading Question 5.3
+
+How to set stuff like From, Organization, Reply-To, signature...?
+
+@subsubheading Answer
+
+There are other ways, but you should use posting styles
+for this. (See below why).
+This example should make the syntax clear:
+
+@example
+(setq gnus-posting-styles
+  '((".*"
+     (name "Frank Schmitt")
+     (address "me@@there.invalid")
+     (organization "Hamme net, kren mer och nimmi")
+     (signature-file "~/.signature")
+     ("X-SampleHeader" "foobar")
+     (eval (setq some-variable "Foo bar")))))
+@end example
+@noindent
+
+The ".*" means that this settings are the default ones
+(see below), valid values for the first element of the
+following lists are signature, signature-file,
+organization, address, name or body.  The attribute name
+can also be a string.  In that case, this will be used as
+a header name, and the value will be inserted in the
+headers of the article; if the value is @code{nil}, the header
+name will be removed. You can also say (eval (foo bar)),
+then the function foo will be evaluated with argument bar
+and the result will be thrown away.
+
+@node FAQ 5-4
+@subsubheading Question 5.4
+
+Can I set things like From, Signature etc group based on the group I post too?
+
+@subsubheading Answer
+
+That's the strength of posting styles. Before, we used ".*"
+to set the default for all groups. You can use a regexp
+like "^gmane" and the following settings are only applied
+to postings you send to the gmane hierarchy, use
+".*binaries" instead and they will be applied to postings
+send to groups containing the string binaries in their
+name etc.
+
+You can instead of specifying a regexp specify a function
+which is evaluated, only if it returns true, the
+corresponding settings take effect. Two interesting
+candidates for this are message-news-p which returns t if
+the current Group is a newsgroup and the corresponding
+message-mail-p.
+
+Note that all forms that match are applied, that means in
+the example below, when I post to
+gmane.mail.spam.spamassassin.general, the settings under
+".*" are applied and the settings under message-news-p and
+those under "^gmane" and those under
+"^gmane\\.mail\\.spam\\.spamassassin\\.general$". Because
+of this put general settings at the top and specific ones
+at the bottom.
+
+@example
+(setq gnus-posting-styles
+      '((".*" ;;default
+         (name "Frank Schmitt")
+         (organization "Hamme net, kren mer och nimmi")
+         (signature-file "~/.signature"))
+        ((message-news-p) ;;Usenet news?
+         (address "mySpamTrap@@Frank-Schmitt.invalid")
+         (reply-to "hereRealRepliesOnlyPlease@@Frank-Schmitt.invalid"))
+        ((message-mail-p) ;;mail?
+         (address "usedForMails@@Frank-Schmitt.invalid"))
+        ("^gmane" ;;this is mail, too in fact
+         (address "usedForMails@@Frank-Schmitt.invalid")
+         (reply-to nil))
+        ("^gmane\\.mail\\.spam\\.spamassassin\\.general$"
+         (eval (set (make-local-variable 'message-sendmail-envelope-from)
+                    "Azzrael@@rz-online.de")))))
+@end example
+@noindent
+
+@node FAQ 5-5
+@subsubheading Question 5.5
+
+Is there a spell-checker? Perhaps even on-the-fly spell-checking?
+
+@subsubheading Answer
+
+You can use ispell.el to spell-check stuff in Emacs. So the
+first thing to do is to make sure that you've got either
+@uref{http://fmg-www.cs.ucla.edu/fmg-members/geoff/ispell.html, ispell}
+or @uref{http://aspell.sourceforge.net/, aspell}
+installed and in your Path. Then you need
+@uref{http://www.kdstevens.com/~stevens/ispell-page.html, ispell.el}
+and for on-the-fly spell-checking
+@uref{http://www-sop.inria.fr/members/Manuel.Serrano/flyspell/flyspell.html, flyspell.el}.
+Ispell.el is shipped with Emacs and available through the XEmacs package system,
+flyspell.el is shipped with Emacs and part of XEmacs text-modes package which is
+available through the package system, so there should be no need to install them
+manually.
+
+Ispell.el assumes you use ispell, if you choose aspell say
+
+@example
+(setq ispell-program-name "aspell")
+@end example
+@noindent
+
+in your Emacs configuration file.
+
+If you want your outgoing messages to be spell-checked, say
+
+@example
+(add-hook 'message-send-hook 'ispell-message)
+@end example
+@noindent
+
+In your @file{~/.gnus.el}, if you prefer on-the-fly spell-checking say
+
+@example
+(add-hook 'message-mode-hook (lambda () (flyspell-mode 1)))
+@end example
+@noindent
+
+@node FAQ 5-6
+@subsubheading Question 5.6
+
+Can I set the dictionary based on the group I'm posting to?
+
+@subsubheading Answer
+
+Yes, say something like
+
+@example
+(add-hook 'gnus-select-group-hook
+          (lambda ()
+            (cond
+             ((string-match
+               "^de\\." (gnus-group-real-name gnus-newsgroup-name))
+              (ispell-change-dictionary "deutsch8"))
+             (t
+              (ispell-change-dictionary "english")))))
+@end example
+@noindent
+
+in @file{~/.gnus.el}. Change "^de\\." and "deutsch8" to something
+that suits your needs.
+
+@node FAQ 5-7
+@subsubheading Question 5.7
+
+Is there some kind of address-book, so I needn't remember
+all those email addresses?
+
+@subsubheading Answer
+
+There's an very basic solution for this, mail aliases.
+You can store your mail addresses in a ~/.mailrc file using a simple
+alias syntax:
+
+@example
+alias al        "Al <al@@english-heritage.invalid>"
+@end example
+@noindent
+
+Then typing your alias (followed by a space or punctuation
+character) on a To: or Cc: line in the message buffer will
+cause Gnus to insert the full address for you. See the
+node "Mail Aliases" in Message (not Gnus) manual for
+details.
+
+However, what you really want is the Insidious Big Brother
+Database bbdb. Get it through the XEmacs package system or from
+@uref{http://bbdb.sourceforge.net/, bbdb's homepage}.
+Now place the following in @file{~/.gnus.el}, to activate bbdb for Gnus:
+
+@example
+(require 'bbdb)
+(bbdb-initialize 'gnus 'message)
+@end example
+@noindent
+
+Now you probably want some general bbdb configuration,
+place them in ~/.emacs:
+
+@example
+(require 'bbdb)
+;;If you don't live in Northern America, you should disable the
+;;syntax check for telephone numbers by saying
+(setq bbdb-north-american-phone-numbers-p nil)
+;;Tell bbdb about your email address:
+(setq bbdb-user-mail-names
+      (regexp-opt '("Your.Email@@here.invalid"
+                    "Your.other@@mail.there.invalid")))
+;;cycling while completing email addresses
+(setq bbdb-complete-name-allow-cycling t)
+;;No popup-buffers
+(setq bbdb-use-pop-up nil)
+@end example
+@noindent
+
+Now you should be ready to go. Say @samp{M-x bbdb RET
+RET} to open a bbdb buffer showing all
+entries. Say @samp{c} to create a new
+entry, @samp{b} to search your BBDB and
+@samp{C-o} to add a new field to an
+entry. If you want to add a sender to the BBDB you can
+also just hit @kbd{:} on the posting in the summary buffer and
+you are done. When you now compose a new mail,
+hit @samp{TAB} to cycle through know
+recipients.
+
+@node FAQ 5-8
+@subsubheading Question 5.8
+
+Sometimes I see little images at the top of article
+buffer. What's that and how can I send one with my
+postings, too?
+
+@subsubheading Answer
+
+Those images are called X-Faces. They are 48*48 pixel b/w
+pictures, encoded in a header line. If you want to include
+one in your posts, you've got to convert some image to a
+X-Face. So fire up some image manipulation program (say
+Gimp), open the image you want to include, cut out the
+relevant part, reduce color depth to 1 bit, resize to
+48*48 and save as bitmap. Now you should get the compface
+package from
+@uref{ftp://ftp.cs.indiana.edu:/pub/faces/, this site}.
+and create the actual X-face by saying
+
+@example
+cat file.xbm | xbm2ikon | compface > file.face
+cat file.face | sed 's/["\\]/\\&/g' > file.face.quoted
+@end example
+@noindent
+
+If you can't use compface, there's an online X-face converter at
+@uref{http://www.dairiki.org/xface/}.
+If you use MS Windows, you could also use the WinFace program,
+which used to be available from
+@indicateurl{http://www.xs4all.nl/~walterln/winface/}.
+Now you only have to tell Gnus to include the X-face in your postings by saying
+
+@example
+(setq message-default-headers
+        (with-temp-buffer
+          (insert "X-Face: ")
+          (insert-file-contents "~/.xface")
+          (buffer-string)))
+@end example
+@noindent
+
+in @file{~/.gnus.el}.  If you use Gnus 5.10, you can simply add an entry
+
+@example
+(x-face-file "~/.xface")
+@end example
+@noindent
+
+to gnus-posting-styles.
+
+@node FAQ 5-9
+@subsubheading Question 5.9
+
+Sometimes I accidentally hit r instead of f in
+newsgroups. Can Gnus warn me, when I'm replying by mail in
+newsgroups?
+
+@subsubheading Answer
+
+Put this in @file{~/.gnus.el}:
+
+@example
+(setq gnus-confirm-mail-reply-to-news t)
+@end example
+@noindent
+
+if you already use Gnus 5.10, if you still use 5.8.8 or
+5.9 try this instead:
+
+@example
+(eval-after-load "gnus-msg"
+  '(unless (boundp 'gnus-confirm-mail-reply-to-news)
+     (defadvice gnus-summary-reply (around reply-in-news activate)
+       "Request confirmation when replying to news."
+       (interactive)
+       (when (or (not (gnus-news-group-p gnus-newsgroup-name))
+                 (y-or-n-p "Really reply by mail to article author? "))
+         ad-do-it))))
+@end example
+@noindent
+
+@node FAQ 5-10
+@subsubheading Question 5.10
+
+How to tell Gnus not to generate a sender header?
+
+@subsubheading Answer
+
+Since 5.10 Gnus doesn't generate a sender header by
+default. For older Gnus' try this in @file{~/.gnus.el}:
+
+@example
+(eval-after-load "message"
+      '(add-to-list 'message-syntax-checks '(sender . disabled)))
+@end example
+@noindent
+
+@node FAQ 5-11
+@subsubheading Question 5.11
+
+I want Gnus to locally store copies of my send mail and
+news, how to do it?
+
+@subsubheading Answer
+
+You must set the variable gnus-message-archive-group to do
+this. You can set it to a string giving the name of the
+group where the copies shall go or like in the example
+below use a function which is evaluated and which returns
+the group to use.
+
+@example
+(setq gnus-message-archive-group
+        '((if (message-news-p)
+              "nnml:Send-News"
+            "nnml:Send-Mail")))
+@end example
+@noindent
+
+@node FAQ 5-12
+@subsubheading Question 5.12
+
+I want Gnus to kill the buffer after successful sending instead of keeping
+it alive as "Sent mail to...", how to do it?
+
+@subsubheading Answer
+
+Add this to your ~/.gnus:
+
+@example
+(setq message-kill-buffer-on-exit t)
+@end example
+@noindent
+
+@node FAQ 5-13
+@subsubheading Question 5.13
+
+People tell me my Message-IDs are not correct, why
+aren't they and how to fix it?
+
+@subsubheading Answer
+
+The message-ID is a unique identifier for messages you
+send. To make it unique, Gnus need to know which machine
+name to put after the "@@". If the name of the machine
+where Gnus is running isn't suitable (it probably isn't
+at most private machines) you can tell Gnus what to use
+by saying:
+
+@example
+(setq message-user-fqdn "yourmachine.yourdomain.tld")
+@end example
+@noindent
+
+in @file{~/.gnus.el}.  If you use Gnus 5.9 or earlier, you can use this
+instead (works for newer versions as well):
+
+@example
+(eval-after-load "message"
+  '(let ((fqdn "yourmachine.yourdomain.tld"));; <-- Edit this!
+     (if (boundp 'message-user-fqdn)
+         (setq message-user-fqdn fqdn)
+       (gnus-message 1 "Redefining `message-make-fqdn'.")
+       (defun message-make-fqdn ()
+         "Return user's fully qualified domain name."
+         fqdn))))
+@end example
+@noindent
+
+If you have no idea what to insert for
+"yourmachine.yourdomain.tld", you've got several
+choices. You can either ask your provider if he allows
+you to use something like
+yourUserName.userfqdn.provider.net, or you can use
+somethingUnique.yourdomain.tld if you own the domain
+yourdomain.tld, or you can register at a service which
+gives private users a FQDN for free.
+
+Finally you can tell Gnus not to generate a Message-ID
+for News at all (and letting the server do the job) by saying
+
+@example
+(setq message-required-news-headers
+  (remove' Message-ID message-required-news-headers))
+@end example
+@noindent
+
+you can also tell Gnus not to generate Message-IDs for mail by saying
+
+@example
+(setq message-required-mail-headers
+  (remove' Message-ID message-required-mail-headers))
+@end example
+@noindent
+
+, however some mail servers don't generate proper
+Message-IDs, too, so test if your Mail Server behaves
+correctly by sending yourself a Mail and looking at the Message-ID.
+
+@node FAQ 6 - Old messages
+@subsection Old messages
+
+@menu
+* FAQ 6-1::    How to import my old mail into Gnus?
+* FAQ 6-2::    How to archive interesting messages?
+* FAQ 6-3::    How to search for a specific message?
+* FAQ 6-4::    How to get rid of old unwanted mail?
+* FAQ 6-5::    I want that all read messages are expired (at least in
+               some groups). How to do it?
+* FAQ 6-6::    I don't want expiration to delete my mails but to move
+               them to another group.
+@end menu
+
+@node FAQ 6-1
+@subsubheading Question 6.1
+
+How to import my old mail into Gnus?
+
+@subsubheading Answer
+
+The easiest way is to tell your old mail program to
+export the messages in mbox format. Most Unix mailers
+are able to do this, if you come from the MS Windows
+world, you may find tools at
+@uref{http://mbx2mbox.sourceforge.net/}.
+
+Now you've got to import this mbox file into Gnus. To do
+this, create a nndoc group based on the mbox file by
+saying @samp{G f /path/file.mbox RET} in
+Group buffer. You now have read-only access to your
+mail. If you want to import the messages to your normal
+Gnus mail groups hierarchy, enter the nndoc group you've
+just created by saying @samp{C-u RET}
+(thus making sure all messages are retrieved), mark all
+messages by saying @samp{M P b} and
+either copy them to the desired group by saying
+@samp{B c name.of.group RET} or send them
+through nnmail-split-methods (respool them) by saying
+@samp{B r}.
+
+@node FAQ 6-2
+@subsubheading Question 6.2
+
+How to archive interesting messages?
+
+@subsubheading Answer
+
+If you stumble across an interesting message, say in
+gnu.emacs.gnus and want to archive it there are several
+solutions. The first and easiest is to save it to a file
+by saying @samp{O f}. However, wouldn't
+it be much more convenient to have more direct access to
+the archived message from Gnus? If you say yes, put this
+snippet by Frank Haun <pille3003@@fhaun.de> in
+@file{~/.gnus.el}:
+
+@example
+(defun my-archive-article (&optional n)
+  "Copies one or more article(s) to a corresponding `nnml:' group, e.g.,
+`gnus.ding' goes to `nnml:1.gnus.ding'. And `nnml:List-gnus.ding' goes
+to `nnml:1.List-gnus-ding'.
+
+Use process marks or mark a region in the summary buffer to archive
+more then one article."
+  (interactive "P")
+  (let ((archive-name
+         (format
+          "nnml:1.%s"
+          (if (featurep 'xemacs)
+              (replace-in-string gnus-newsgroup-name "^.*:" "")
+            (replace-regexp-in-string "^.*:" "" gnus-newsgroup-name)))))
+    (gnus-summary-copy-article n archive-name)))
+@end example
+@noindent
+
+You can now say @samp{M-x
+my-archive-article} in summary buffer to
+archive the article under the cursor in a nnml
+group. (Change nnml to your preferred back end)
+
+Of course you can also make sure the cache is enabled by saying
+
+@example
+(setq gnus-use-cache t)
+@end example
+@noindent
+
+then you only have to set either the tick or the dormant
+mark for articles you want to keep, setting the read
+mark will remove them from cache.
+
+@node FAQ 6-3
+@subsubheading Question 6.3
+
+How to search for a specific message?
+
+@subsubheading Answer
+
+There are several ways for this, too. For a posting from
+a Usenet group the easiest solution is probably to ask
+@uref{http://groups.google.com, groups.google.com},
+if you found the posting there, tell Google to display
+the raw message, look for the message-id, and say
+@samp{M-^ the@@message.id RET} in a
+summary buffer.
+Since Gnus 5.10 there's also a Gnus interface for
+groups.google.com which you can call with
+@samp{G W}) in group buffer.
+
+Another idea which works for both mail and news groups
+is to enter the group where the message you are
+searching is and use the standard Emacs search
+@samp{C-s}, it's smart enough to look at
+articles in collapsed threads, too. If you want to
+search bodies, too try @samp{M-s}
+instead. Further on there are the
+gnus-summary-limit-to-foo functions, which can help you,
+too.
+
+Of course you can also use grep to search through your
+local mail, but this is both slow for big archives and
+inconvenient since you are not displaying the found mail
+in Gnus.  Here nnir comes into action.  Nnir is a front end
+to search engines like swish-e or swish++ and
+others.  You index your mail with one of those search
+engines and with the help of nnir you can search through
+the indexed mail and generate a temporary group with all
+messages which met your search criteria.  If this sounds
+cool to you, get nnir.el from
+@c FIXME Isn't this file in Gnus?
+@ignore
+@c Dead link 2013/7.
+@uref{ftp://ls6-ftp.cs.uni-dortmund.de/pub/src/emacs/}
+or
+@end ignore
+@uref{ftp://ftp.is.informatik.uni-duisburg.de/pub/src/emacs/}.
+Instructions on how to use it are at the top of the file.
+
+@node FAQ 6-4
+@subsubheading Question 6.4
+
+How to get rid of old unwanted mail?
+
+@subsubheading Answer
+
+You can of course just mark the mail you don't need
+anymore by saying @samp{#} with point
+over the mail and then say @samp{B DEL}
+to get rid of them forever. You could also instead of
+actually deleting them, send them to a junk-group by
+saying @samp{B m nnml:trash-bin} which
+you clear from time to time, but both are not the intended
+way in Gnus.
+
+In Gnus, we let mail expire like news expires on a news
+server. That means you tell Gnus the message is
+expirable (you tell Gnus "I don't need this mail
+anymore") by saying @samp{E} with point
+over the mail in summary buffer. Now when you leave the
+group, Gnus looks at all messages which you marked as
+expirable before and if they are old enough (default is
+older than a week) they are deleted.
+
+@node FAQ 6-5
+@subsubheading Question 6.5
+
+I want that all read messages are expired (at least in
+some groups). How to do it?
+
+@subsubheading Answer
+
+If you want all read messages to be expired (e.g., in
+mailing lists where there's an online archive), you've
+got two choices: auto-expire and
+total-expire. Auto-expire means, that every article
+which has no marks set and is selected for reading is
+marked as expirable, Gnus hits @samp{E}
+for you every time you read a message. Total-expire
+follows a slightly different approach, here all article
+where the read mark is set are expirable.
+
+To activate auto-expire, include auto-expire in the
+Group parameters for the group. (Hit @samp{G
+c} in summary buffer with point over the
+group to change group parameters). For total-expire add
+total-expire to the group-parameters.
+
+Which method you choose is merely a matter of taste:
+Auto-expire is faster, but it doesn't play together with
+Adaptive Scoring, so if you want to use this feature,
+you should use total-expire.
+
+If you want a message to be excluded from expiration in
+a group where total or auto expire is active, set either
+tick (hit @samp{u}) or dormant mark (hit
+@samp{u}), when you use auto-expire, you
+can also set the read mark (hit
+@samp{d}).
+
+@node FAQ 6-6
+@subsubheading Question 6.6
+
+I don't want expiration to delete my mails but to move them
+to another group.
+
+@subsubheading Answer
+
+Say something like this in @file{~/.gnus.el}:
+
+@example
+(setq nnmail-expiry-target "nnml:expired")
+@end example
+@noindent
+
+(If you want to change the value of nnmail-expiry-target
+on a per group basis see the question "How can I disable
+threading in some (e.g., mail-) groups, or set other
+variables specific for some groups?")
+
+@node FAQ 7 - Gnus in a dial-up environment
+@subsection Gnus in a dial-up environment
+
+@menu
+* FAQ 7-1::    I don't have a permanent connection to the net, how can I
+               minimize the time I've got to be connected?
+* FAQ 7-2::    So what was this thing about the Agent?
+* FAQ 7-3::    I want to store article bodies on disk, too. How to do
+               it?
+* FAQ 7-4::    How to tell Gnus not to try to send mails / postings
+               while I'm offline?
+@end menu
+
+@node FAQ 7-1
+@subsubheading Question 7.1
+
+I don't have a permanent connection to the net, how can
+I minimize the time I've got to be connected?
+
+@subsubheading Answer
+
+You've got basically two options: Either you use the
+Gnus Agent (see below) for this, or you can install
+programs which fetch your news and mail to your local
+disk and Gnus reads the stuff from your local
+machine.
+
+If you want to follow the second approach, you need a
+program which fetches news and offers them to Gnus, a
+program which does the same for mail and a program which
+receives the mail you write from Gnus and sends them
+when you're online.
+
+Let's talk about Unix systems first: For the news part,
+the easiest solution is a small nntp server like
+@uref{http://www.leafnode.org/, Leafnode} or
+@uref{http://infa.abo.fi/~patrik/sn/, sn},
+of course you can also install a full featured news
+server like
+@uref{http://www.isc.org/software/inn/, inn}.
+Then you want to fetch your Mail, popular choices
+are @uref{http://www.catb.org/~esr/fetchmail/, fetchmail}
+and @uref{http://pyropus.ca/software/getmail/, getmail}.
+You should tell those to write the mail to your disk and
+Gnus to read it from there. Last but not least the mail
+sending part: This can be done with every MTA like
+@uref{http://www.sendmail.org/, sendmail},
+@uref{http://www.qmail.org/, postfix},
+@uref{http://www.exim.org/, exim} or
+@uref{http://www.qmail.org/, qmail}.
+
+On windows boxes I'd vote for
+@uref{http://www.tglsoft.de/, Hamster},
+it's a small freeware, open-source program which fetches
+your mail and news from remote servers and offers them
+to Gnus (or any other mail and/or news reader) via nntp
+respectively POP3 or IMAP@. It also includes a smtp
+server for receiving mails from Gnus.
+
+@node FAQ 7-2
+@subsubheading Question 7.2
+
+So what was this thing about the Agent?
+
+@subsubheading Answer
+
+The Gnus agent is part of Gnus, it allows you to fetch
+mail and news and store them on disk for reading them
+later when you're offline. It kind of mimics offline
+newsreaders like Forte Agent. If you want to use
+the Agent place the following in @file{~/.gnus.el} if you are
+still using 5.8.8 or 5.9 (it's the default since 5.10):
+
+@example
+(setq gnus-agent t)
+@end example
+@noindent
+
+Now you've got to select the servers whose groups can be
+stored locally.  To do this, open the server buffer
+(that is press @samp{^} while in the
+group buffer).  Now select a server by moving point to
+the line naming that server.  Finally, agentize the
+server by typing @samp{J a}.  If you
+make a mistake, or change your mind, you can undo this
+action by typing @samp{J r}.  When
+you're done, type 'q' to return to the group buffer.
+Now the next time you enter a group on a agentized
+server, the headers will be stored on disk and read from
+there the next time you enter the group.
+
+@node FAQ 7-3
+@subsubheading Question 7.3
+
+I want to store article bodies on disk, too. How to do it?
+
+@subsubheading Answer
+
+You can tell the agent to automatically fetch the bodies
+of articles which fulfill certain predicates, this is
+done in a special buffer which can be reached by
+saying @samp{J c} in group
+buffer. Please refer to the documentation for
+information which predicates are possible and how
+exactly to do it.
+
+Further on you can tell the agent manually which
+articles to store on disk. There are two ways to do
+this: Number one: In the summary buffer, process mark a
+set of articles that shall be stored in the agent by
+saying @samp{#} with point over the
+article and then type @samp{J s}. The
+other possibility is to set, again in the summary
+buffer, downloadable (%) marks for the articles you
+want by typing @samp{@@} with point over
+the article and then typing @samp{J u}.
+What's the difference? Well, process marks are erased as
+soon as you exit the summary buffer while downloadable
+marks are permanent.  You can actually set downloadable
+marks in several groups then use fetch session ('J s' in
+the GROUP buffer) to fetch all of those articles.  The
+only downside is that fetch session also fetches all of
+the headers for every selected group on an agentized
+server.  Depending on the volume of headers, the initial
+fetch session could take hours.
+
+@node FAQ 7-4
+@subsubheading Question 7.4
+
+How to tell Gnus not to try to send mails / postings
+while I'm offline?
+
+@subsubheading Answer
+
+All you've got to do is to tell Gnus when you are online
+(plugged) and when you are offline (unplugged), the rest
+works automatically. You can toggle plugged/unplugged
+state by saying @samp{J j} in group
+buffer. To start Gnus unplugged say @samp{M-x
+gnus-unplugged} instead of
+@samp{M-x gnus}. Note that for this to
+work, the agent must be active.
+
+@node FAQ 8 - Getting help
+@subsection Getting help
+
+@menu
+* FAQ 8-1::    How to find information and help inside Emacs?
+* FAQ 8-2::    I can't find anything in the Gnus manual about X (e.g.,
+               attachments, PGP, MIME...), is it not documented?
+* FAQ 8-3::    Which websites should I know?
+* FAQ 8-4::    Which mailing lists and newsgroups are there?
+* FAQ 8-5::    Where to report bugs?
+* FAQ 8-6::    I need real-time help, where to find it?
+@end menu
+
+@node FAQ 8-1
+@subsubheading Question 8.1
+
+How to find information and help inside Emacs?
+
+@subsubheading Answer
+
+The first stop should be the Gnus manual (Say
+@samp{C-h i d m Gnus RET} to start the
+Gnus manual, then walk through the menus or do a
+full-text search with @samp{s}). Then
+there are the general Emacs help commands starting with
+C-h, type @samp{C-h ? ?} to get a list
+of all available help commands and their meaning. Finally
+@samp{M-x apropos-command} lets you
+search through all available functions and @samp{M-x
+apropos} searches the bound variables.
+
+@node FAQ 8-2
+@subsubheading Question 8.2
+
+I can't find anything in the Gnus manual about X
+(e.g., attachments, PGP, MIME...), is it not documented?
+
+@subsubheading Answer
+
+There's not only the Gnus manual but also the manuals for message,
+emacs-mime, sieve, EasyPG Assistant, and pgg. Those packages are
+distributed with Gnus and used by Gnus but aren't really part of core
+Gnus, so they are documented in different info files, you should have
+a look in those manuals, too.
+
+@node FAQ 8-3
+@subsubheading Question 8.3
+
+Which websites should I know?
+
+@subsubheading Answer
+
+The most important one is the
+@uref{http://www.gnus.org, official Gnus website}.
+
+Tell me about other sites which are interesting.
+
+@node FAQ 8-4
+@subsubheading Question 8.4
+
+Which mailing lists and newsgroups are there?
+
+@subsubheading Answer
+
+There's the newsgroup gnu.emacs.gnus (also available as
+@uref{http://dir.gmane.org/gmane.emacs.gnus.user,
+gmane.emacs.gnus.user}) which deals with general Gnus
+questions.  If you have questions about development versions of
+Gnus, you should better ask on the ding mailing list, see below.
+
+If you want to stay in the big8,
+news.software.readers is also read by some Gnus
+users (but chances for qualified help are much better in
+the above groups).  If you speak German, there's
+de.comm.software.gnus.
+
+The ding mailing list (ding@@gnus.org) deals with development of
+Gnus. You can read the ding list via NNTP, too under the name
+@uref{http://dir.gmane.org/gmane.emacs.gnus.general,
+gmane.emacs.gnus.general} from news.gmane.org.
+
+@node FAQ 8-5
+@subsubheading Question 8.5
+
+Where to report bugs?
+
+@subsubheading Answer
+
+Say @samp{M-x gnus-bug}, this will start
+a message to the
+@email{bugs@@gnus.org, gnus bug mailing list}
+including information about your environment which make
+it easier to help you.
+
+@node FAQ 8-6
+@subsubheading Question 8.6
+
+I need real-time help, where to find it?
+
+@subsubheading Answer
+
+Point your IRC client to irc.freenode.net, channel #gnus.
+
+@node FAQ 9 - Tuning Gnus
+@subsection Tuning Gnus
+
+@menu
+* FAQ 9-1::    Starting Gnus is really slow, how to speed it up?
+* FAQ 9-2::    How to speed up the process of entering a group?
+* FAQ 9-3::    Sending mail becomes slower and slower, what's up?
+@end menu
+
+@node FAQ 9-1
+@subsubheading Question 9.1
+
+Starting Gnus is really slow, how to speed it up?
+
+@subsubheading Answer
+
+The reason for this could be the way Gnus reads its
+active file, see the node "The Active File" in the Gnus
+manual for things you might try to speed the process up.
+An other idea would be to byte compile your @file{~/.gnus.el} (say
+@samp{M-x byte-compile-file RET ~/.gnus.el
+RET} to do it). Finally, if you have require
+statements in your .gnus, you could replace them with
+eval-after-load, which loads the stuff not at startup
+time, but when it's needed. Say you've got this in your
+@file{~/.gnus.el}:
+
+@example
+(require 'message)
+(add-to-list 'message-syntax-checks '(sender . disabled))
+@end example
+@noindent
+
+then as soon as you start Gnus, message.el is loaded. If
+you replace it with
+
+@example
+(eval-after-load "message"
+      '(add-to-list 'message-syntax-checks '(sender . disabled)))
+@end example
+@noindent
+
+it's loaded when it's needed.
+
+@node FAQ 9-2
+@subsubheading Question 9.2
+
+How to speed up the process of entering a group?
+
+@subsubheading Answer
+
+A speed killer is setting the variable
+gnus-fetch-old-headers to anything different from @code{nil},
+so don't do this if speed is an issue. To speed up
+building of summary say
+
+@example
+(gnus-compile)
+@end example
+@noindent
+
+at the bottom of your @file{~/.gnus.el}, this will make gnus
+byte-compile things like
+gnus-summary-line-format.
+then you could increase the value of gc-cons-threshold
+by saying something like
+
+@example
+(setq gc-cons-threshold 3500000)
+@end example
+@noindent
+
+in ~/.emacs. If you don't care about width of CJK
+characters or use Gnus 5.10 or younger together with a
+recent GNU Emacs, you should say
+
+@example
+(setq gnus-use-correct-string-widths nil)
+@end example
+@noindent
+
+in @file{~/.gnus.el} (thanks to Jesper harder for the last
+two suggestions). Finally if you are still using 5.8.8
+or 5.9 and experience speed problems with summary
+buffer generation, you definitely should update to
+5.10 since there quite some work on improving it has
+been done.
+
+@node FAQ 9-3
+@subsubheading Question 9.3
+
+Sending mail becomes slower and slower, what's up?
+
+@subsubheading Answer
+
+The reason could be that you told Gnus to archive the
+messages you wrote by setting
+gnus-message-archive-group. Try to use a nnml group
+instead of an archive group, this should bring you back
+to normal speed.
+
+@node FAQ - Glossary
+@subsection Glossary
+
+@table @dfn
+
+@item ~/.gnus.el
+When the term @file{~/.gnus.el} is used it just means your Gnus
+configuration file. You might as well call it @file{~/.gnus} or
+specify another name.
+
+@item Back End
+In Gnus terminology a back end is a virtual server, a layer
+between core Gnus and the real NNTP-, POP3-, IMAP- or
+whatever-server which offers Gnus a standardized interface
+to functions like "get message", "get Headers" etc.
+
+@item Emacs
+When the term Emacs is used in this FAQ, it means either GNU
+Emacs or XEmacs.
+
+@item Message
+In this FAQ message means a either a mail or a posting to a
+Usenet Newsgroup or to some other fancy back end, no matter
+of which kind it is.
+
+@item MUA
+MUA is an acronym for Mail User Agent, it's the program you
+use to read and write e-mails.
+
+@item NUA
+NUA is an acronym for News User Agent, it's the program you
+use to read and write Usenet news.
+
+@end table
diff --git a/xemacs-packages/gnus/texi/gnus-logo.eps b/xemacs-packages/gnus/texi/gnus-logo.eps
new file mode 100644 (file)
index 0000000..54deefd
--- /dev/null
@@ -0,0 +1,1073 @@
+%!PS-Adobe-2.0 EPSF-2.0
+% Copyright (C) 2000-2016 Free Software Foundation, Inc.
+%
+% Author: Luis Fernandes <elf@ee.ryerson.ca>
+%
+% 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+%
+%%Title: gnuslogo1.ps
+%%BoundingBox: 0 0 493 505
+%%Pages: 1
+%%DocumentFonts:
+%%EndComments
+%%EndProlog
+
+%%Page: 1 1
+
+% remember original state
+/origstate save def
+
+% build a temporary dictionary
+20 dict begin
+
+% define string to hold a scanline's worth of data
+/pix 62 string def
+
+% lower left corner
+0 0 translate
+
+% size of image (on paper, in 1/72inch coords)
+493.0 505.0 scale
+
+% dimensions of data
+493 505 1
+
+% mapping matrix
+[493 0 0 -505 0 505]
+
+{currentfile pix readhexstring pop}
+image
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff01fffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffff8003ffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffff0000ffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffff8000007ffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffff0000003ffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffe0000000ffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffff000000003fff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffff000000000fff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffc0000000007ff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffff80000000003ff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffff00000000001ff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffe00000000000ff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffc00000000000ff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffff8000000000007f8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffff0000000000003f8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffff0000000000003f8
+fffffffffffffffffffffffffff800ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffe0000000000001f8
+fffffffffffffffffffffffffff0001fffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffc0000000000000f8
+ffffffffffffffffffffffffffc00007ffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffc0000000000000f8
+ffffffffffffffffffffffffff000001ffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff8000000000000078
+fffffffffffffffffffffffffe0000003ffffffffffff0001fffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff0000000000000038
+fffffffffffffffffffffffffc0000001fffffffffffe00007ffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffe0000000000000038
+fffffffffffffffffffffffff800000007ffffffffff800001ffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffe0000000000000038
+fffffffffffffffffffffffff000000003fffffffffe0000003fffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffc0000000000000018
+ffffffffffffffffffffffffe000000001fffffffff80000000fffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffc0000000000000018
+ffffffffffffffffffffffffc000000000ffffffffe000000003ffffffffffffffffffff
+fffffffffffffffffffffffffffffffffff80000000000000018
+ffffffffffffffffffffffff80000000007fffffff8000000000ffffffffffffffffffff
+fffffffffffffffffffffffffffffffffff80000000000000008
+ffffffffffffffffffffffff00000000003fffffff00000000007fffffffffffffffffff
+fffffffffffffffffffffffffffffffffff00000000000000008
+fffffffffffffffffffffffe00000000001ffffffe00000000001fffffffffffffffffff
+fffffffffffffffffffffffffffffffffff00000000000000008
+fffffffffffffffffffffffc00000000000ffffff8000000000007ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffe00000000000000008
+fffffffffffffffffffffff8000000000007fffff0000000000007ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffe00000000000000008
+fffffffffffffffffffffff0000000000001ffffe0000000000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffc00000000000000000
+ffffffffffffffffffffffe0000000000000ffffc00000000000007fffffffffffffffff
+ffffffffffffffffffffffffffffffffffc00000000000000000
+ffffffffffffffffffffffc00000000000007fff800000000000001fffffffffffffffff
+ffffffffffffffffffffffffffffffffff800000000000000000
+ffffffffffffffffffffff800000000000003fff000000000000000fffffffffffffffff
+ffffffffffffffffffffffffffffffffff800000000000000000
+ffffffffffffffffffffff000000000000003fff0000000000000007ffffffffffffffff
+ffffffffffffffffffffffffffffffffff000040000000000000
+fffffffffffffffffffffe000000000000000ffe0000000000000001ffffffffffffffff
+ffffffffffffffffffffffffffffffffff0007ffc00000000000
+fffffffffffffffffffffc000000000000000ffc0000000000000000ffffffffffffffff
+fffffffffffffffffffffffffffffffffe001ffffc0000000000
+fffffffffffffffffffffc0000000000000007fc00000000000000007fffffffffffffff
+fffffffffffffffffffffffffffffffffc003ffffe0000000000
+fffffffffffffffffffff80000000000000007f800000000000000003fffffffffffffff
+fffffffffffffffffffffffffffffffffc007fffffc000000000
+fffffffffffffffffffff00000000000000001f000000000000000001fffffffffffffff
+fffffffffffffffffffffffffffffffff800fffffff000000000
+ffffffffffffffffffffe00000000000000001f000000000000000000fffffffffffffff
+fffffffffffffffffffffffffffffffff801fffffff800000000
+ffffffffffffffffffffc00000000000000000e0000000000000000007ffffffffffffff
+fffffffffffffffffffffffffffffffff003ffffffff00000000
+ffffffffffffffffffff800000000000000000c0000000000000000003ffffffffffffff
+fffffffffffffffffffffffffffffffff007ffffffff00000000
+ffffffffffffffffffff00000000000000000000000000000000000000ffffffffffffff
+ffffffffffffffffffffffffffffffffe00fffffffff80000000
+fffffffffffffffffffe00000000000000000000000000000000000000ffffffffffffff
+ffffffffffffffffffffffffffffffffe01fffffffffc0000008
+fffffffffffffffffffc000000000000000000000000000000000000007fffffffffffff
+ffffffffffffffffffffffffffffffffc03fffffffffc0000008
+fffffffffffffffffff8000000000000000000000000000000000000001fffffffffffff
+ffffffffffffffffffffffffffffffffc07ffffffffff0000000
+fff9fffffffffffffff800000fe00000000000000000000000000000001fffffffffffff
+ffffffffffffffffffffffffffffffff807ffffffffff0000000
+fff9fffffffffffffff000001ff80000000000000000000000000000000fffffffffffff
+ffffffffffffffffffffffffffffffff80fffffffffff0000008
+fff0ffffffffffffffc000007ffc00000000000000000000000000000007ffffffffffff
+ffffffffffffffffffffffffffffffff81fffffffffff8000008
+fff0ffffffffffffffc00000fffc00000000000000000000000000000003ffffffffffff
+ffffffffffffffffffffffffffffffff01fffffffffff8000008
+ffe07fffffffffffff800001ffff00000000000000000000000000000001ffffffffffff
+ffffffffffffffffffffffffffffffff03fffffffffffc000008
+ffe07fffffffffffff00000fffffc0000000000000000000000000000000ffffffffffff
+fffffffffffffffffffffffffffffffe03fffffffffffc000008
+ffe03ffffffffffffc00001fffffe00000000000000000000000000000007fffffffffff
+fffffffffffffffffffffffffffffffe07fffffffffffe000008
+ffe03ffffffffffff800003ffffff00000000000000000000000000000003fffffffffff
+fffffffffffffffffffffffffffffffe07fffffffffffe000008
+ffc03ffffffffffff000007ffffff80000000000000f80000000000000003fffffffffff
+fffffffffffffffffffffffffffffffe0ffffffffffffe000008
+ffc01fffffffffffe00001fffffffe000000000000fffe000000000000001fffffffffff
+fffffffffffffffffffffffffffffffc0ffffffffffffe000008
+ffc00fffffffffffc00003ffffffff000000000001ffff800000000000000fffffffffff
+fffffffffffffffffffffffffffffffc1fffffffffffff000008
+ff800fffffffffff800003ffffffff800000000007ffffc000000000000007ffffffffff
+fffffffffffffffffffffffffffffffc3fffffffffffff000008
+ff8007fffffffffe00000fffffffffc0000000001ffffffc00000000000003ffffffffff
+fffffffffffffffffffffffffffffff87fffffffffffff000008
+ff8007fffffffffc00000fffffffffe0000000005ffffffe00000000000001ffffffffff
+fffffffffffffffffffffffffffffff87fffffffffffff000008
+ff8003fffffffff800001ffffffffff000000000ffffffffc0000000000000ffffffffff
+fffffffffffffffffffffffffffffff87fffffffffffff000008
+ff0001fffffffff000003ffffffffffc00000007fffffffff80000000000007fffffffff
+fffffffffffffffffffffffffffffff8ffffffffffffff000008
+ff0000ffffffffe000003ffffffffffc0000000ffffffffffc0000000000007fffffffff
+fffffffffffffffffffffffffffffffcffffffffffffff000008
+fe00007fffffff800000ffffffffffff0000001ffffffffffe0000000000001fffffffff
+ffffffffffffffffffffffffffffe7fdffffffffffffff000008
+fe00007fffffff000001ffffffffffff8000003fffffffffff0000000000001fffffffff
+ffffffffffffffffffffffffffffe7fdffffffffffffff000008
+fc00001ffffffc000003ffffffffffffc000007fffffffffffe0000000000007ffffffff
+ffffffffffffffffffffffffffffc7ffffffffffffffff000008
+fc00001ffffff0000003ffffffffffffe00000fffffffffffff0000000000007ffffffff
+fffffffffeffffffffffffffffff87ffffffffffffffff000008
+f800000fffffe0000007fffffffffffff00000fffffffffffff8000000000003ffffffff
+fffffffffcffffffffffffffffff87ffffffffffffffff000008
+f8000003ffff0000000ffffffffffffff80001fffffffffffffc000000000001ffffffff
+fffffffff8ffffffffffffffffff07ffffffffffffffff000008
+f8000001fffe0000001ffffffffffffff80001ffffffffffffff000000000000ffffffff
+fffffffff8fffffffffffffffffe0fffffffffffffffff000008
+f0000000fff00000003ffffffffffffffc0001ffffffffffffff8000000000007fffffff
+fffffffff0fffffffffffffffffe0fffffffffffffffff000018
+e00000001a000000007ffffffffffffffe0003ffffffffffffffc000000000003fffffff
+fffffffff0fffffffffffffffffc0fffffffffffffffff000018
+e000000000000000007fffffffffffffff0003ffffffffffffffc000000000003fffffff
+ffffffffe0fffffffffffffffffc1fffffffffffffffff000018
+c00000000000000000ffffffffffffffff0007ffffffffffffffe000000000001fffffff
+ffffffffe0fffffffffffffffff81fffffffffffffffff000018
+c00000000000000001ffffffffffffffff0007fffffffffffffff0000000000007ffffff
+ffffffffc0fffffffffffffffff83fffffffffffffffff000018
+800000000000000007ffffffffffffffff800ffffffffffffffffc000000000003ffffff
+ffffffff01fffffffffffffffff03fffffffffffffffff000038
+800000000000000007ffffffffffffffff800ffffffffffffffffe000000000001ffffff
+ffffffff01fffffffffffffffff03fffffffffffffffff800038
+00000000000000000fffffffffffffffffc00fffffffffffffffff000000000000ffffff
+fffffffe03ffffffffffffffffe07fffffffffffffffff800038
+00000000000000001fffffffffffffffffc01fffffffffffffffff8000000000007fffff
+fffffffc03ffffffffffffffffe07fffffffffffffffff800038
+00000000000000003fffffffffffffffffe03fffffffffffffffffc000000000003fffff
+fffffff803ffffffffffffffffc07fffffffffffffffff800038
+00000000000000007ffffffffffffffffff03fffffffffffffffffe000000000000fffff
+fffffff007ffffffffffffffffc0ffffffffffffffffff800038
+0000000000000000fffffffffffffffffff07ffffffffffffffffff000000000000fffff
+fffffff007ffffffffffffffff80ffffffffffffffffff800078
+0000000000000003ffffffffffffffff8ff87ffffffffffffffffff8000000000001ffff
+ffffffc00fffffffffffffffff81ffffffffffffffffff800078
+8000000000000007ffffffffffffffff0ff8fffffffffffffffffffc000000000000ffff
+ffffffc00fffffffffffffffff01ffffffffffffffffff8000f8
+8000000000000007fffffffffffffffe0ffffffffffffffffffffffe0000000000007fff
+ffffff801fffffffffffffffff03ffffffffffffffffff8000f8
+c00000000000001ffffffffffffffffc0fffffffffffffffffffffff0000000000001fff
+fffffe001ffffffffffffffffe07ffffffffffffffffff8000f8
+e00000000000007ffffffffffffffff83fffffffffffffffffffffffc0000000000007ff
+fffff8003ffffffffffffffffc07ffffffffffffffffff8000f8
+f00000000000007ffffffffffffffff03fffffffffffffffffffffffc0000000000001ff
+fffff0003ffffffffffffffff80fffffffffffffffffff8000f8
+f0000000000000fffffffffffffffff07fffffffffffffffffffffffe0000000000000ff
+ffffe0003ffffffffffffffff00fffffffffffffffffff8001f8
+f8000000000003ffffffffffffffffe07ffffffffffffffffffffffff00000000000000f
+ffff00007fffffffffffffffe01fffffffffffffffffff0001f8
+fc000000000007ffffffffffffffffc07ffffffffffffffffffffffff800000000000007
+fffc00007fffffffffffffffc01fffffffffffffffffff0001f8
+fc000000000007ffffffffffffffffc0fffffffffffffffffffffffff800000000000000
+ffe000007ffffbffffffffff801fffffffffffffffffff0001f8
+fe00000000001fffffffffffffffff03fffffffffffffffffffffffffe00000000000000
+00000000fffff3ffffffffff003fffffffffffffffffff0001f8
+fe00000000003fffffffffffffffff03ffffffffffffffffffffffffff00000000000000
+00000001fffff1fffffffffe003fffffffffffffffffff0003f8
+ff00000000007ffffffffffffffffe03ffffffffffffffffffffffffff00000000000000
+00000001ffffe1fffffffffc007fffffffffffffffffff0003f8
+ff8000000001fffffffffffffffffc07ffffffffffffffffffffffffff80000000000000
+00000003ffffe0fffffffff0007fffffffffffffffffff0003f8
+ffc000000003fffffffffffffffffc0fffffffffffffffffffffffffffc0000000000000
+00000003ffffc0ffffffffe0007fffffffffffffffffff0003f8
+ffe00000000ffffffffffffffffff81fffffffffffffffffffffffffffe0000000000000
+00000007ffffc07fffffff8000ffffffffffffffffffff0003f8
+fff00000003ffffffffffffffffff01ffffffffffffffffffffffffffff0000000000000
+00000007ffff803fffffff0000fffffffffffffffffffe0007f8
+fff8000000ffffffffffffffffffe03ffffffffffffffffffffffffffff8000000000000
+00000007ffff801ffffffc0001fffffffffffffffffffe0007f8
+fffc000001ffffffffffffffffffe07ffffffffffffffffffffffffffffc000000000000
+0000000fffff000ffffff80003fffffffffffffffffffe0007f8
+fffe00000fffffffffffffffffffc07ffffffffffffffffffffffffffffc000000000000
+0000000fffff0007ffffe00003fffffffffffffffffffe0007f8
+ffff80007fffffffffffffffffff80fffffffffffffffffffffffffffffe000000000000
+0000001ffffe0001ffff800007fffffffffffffffffffe000ff8
+ffffe007ffffffffffffffffffff80ffffffffffffffffffffffffffffff000000000000
+0000001ffffe0000fffc000007fffffffffffffffffffe000ff8
+ffffffffffffffffffffffffffff01ffffffffffffffffffffffffffffff800000000000
+0000003ffffe0000000000000ffffffffffffffffffffe000ff8
+fffffffffffffffffffffffffffe03ffffffffffffffffffffffffffffffc00000000000
+0000003ffffc0000000000000ffffffffffffffffffffe000ff8
+fffffffffffffffffffffffffffe03ffffffffffffffffffffffffffffffe00000000000
+0000007ffff80000000000001ffffffffffffffffffffe001ff8
+fffffffffffffffffffffffffffc07fffffffffffffffffffffffffffffff00000000000
+0000007ffff80000000000001ffffffffffffffffffffe001ff8
+fffffffffffffffffffffffffff807fffffffffffffffffffffffffffffff80000000000
+000000fffff80000000000003ffffffffffffffffffffc001ff8
+fffffffffffffffffffffffffff80ffffffffffffffffffffffffffffffffc0000000000
+000003fffff00000000000007ffffffffffffffffffffc001ff8
+fffffffffffffffffffffffffff01ffffffffffffffffffffffffffffffffe0000000000
+000007ffffe00000000000007ffffffffffffffffffffe003ff8
+fffffffffffffffffffffffffff01fffffffffffffffffffffffffffffffff0000000000
+000007ffffe0000000000000fffffffffffffffffffffc003ff8
+ffffffffffffffffffffffffffc07fffffffffffffffffffffffffffffffff8000000000
+00001fffffc0000000000001fffffffffffffffffffffc003ff8
+ffffffffffffffffffffffffffc07fffffffffffffffffffffffffffffffffe000000000
+00001fffffc0000000000003fffffffffffffffffffffc003ff8
+ffffffffffffffffffffffffffc07ffffffffffffffffffffffffffffffffff000000000
+00003fffff80000000000003fffffffffffffffffffffc007ff8
+ffffffffffffffffffffffffff01fffffffffffffffffffffffffffffffffff800000000
+00007fffff80000000000007fffffffffffffffffffffc007ff8
+ffffffffffffffffffffffffff03fffffffffffffffffffffffffffffffffffc00000000
+0000ffffff0000000000000ffffffffffffffffffffffc007ff8
+fffffffffffffffffffffffffe03fffffffffffffffffffffffffffffffffffc00000000
+0001ffffff0000000000001ffffffffffffffffffffffc007ff8
+fffffffffffffffffffffffffc07ffffffffffffffffffffffffffffffffffff00000000
+0003fffffe0000000000001ffffffffffffffffffffff800fff8
+fffffffffffffffffffffffff80fffffffffffffffffffffffffffffffffffff80000000
+0007fffffe0000000000003ffffffffffffffffffffff800fff8
+fffffffffffffffffffffffff01ffffffffffffffffffffffffffffffffffffff0000000
+001ffffffc0000000000007ffffffffffffffffffffff800fff8
+fffffffffffffffffffffffff03ffffffffffffffffffffffffffffffffffffff8000000
+003ffffffc000000000000fffffffffffffffffffffff800fff8
+ffffffffffffffffffffffffe07ffffffffffffffffffffffffffffffffffffffe000000
+00fffffff8000000000003fffffffffffffffffffffff001fff8
+ffffffffffffffffffffffffe07fffffffffffffffffffffffffffffffffffffff800000
+03fffffff8000000000003fffffffffffffffffffffff001fff8
+ffffffffffffffffffffffffc0ffffffffffffffffffffffffffffffffffffffffc00000
+07fffffff0000000000007fffffffffffffffffffffff001fff8
+ffffffffffffffffffffffff80fffffffffffffffffffffffffffffffffffffffffc0000
+3ffffffff000000000000ffffffffffffffffffffffff003fff8
+ffffffffffffffffffffffff01ffffffffffffffffffffffffffffffffffffffffffe03f
+fffffffff000000000003ffffffffffffffffffffffff003fff8
+ffffffffffffffffffffffff01ffffffffffffffffffffffffffffffffffffffffffffff
+fffffffff800000000007ffffffffffffffffffffffff003fff8
+fffffffffffffffffffffffe03ffffffffffffffffffffffffffffffffffffffffffffff
+fffffffff80000000000ffffffffffffffffffffffffe003fff8
+fffffffffffffffffffffffc07ffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffc0000000003ffffffffffffffffffffffffe007fff8
+fffffffffffffffffffffffc0fffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffe0000000007ffffffffffffffffffffffffe007fff8
+fffffffffffffffffffffff81fffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffe000000000fffffffffffffffffffffffffe00ffff8
+fffffffffffffffffffffff01fffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffff000000001fffffffffffffffffffffffffe00ffff8
+ffffffffffffffffffffffe03ffffffffffffffffffffffffbffffffffffffffffffffff
+ffffffffff800000007fffffffffffffffffffffffffc00ffff8
+ffffffffffffffffffffffe07ffffffffffffffffffdfffff1ffffffffffffffffffffff
+ffffffffffc0000000ffffffffffffffffffffffffffc00ffff8
+ffffffffffffffffffffffe07ffffffffffffffffff9fffff07fffffffffffffffffffff
+ffffffffffe0000001ffffffffffffffffffffffffffc00ffff8
+ffffffffffffffffffffffc0ffffffffffffffffffe3ffffe03fffffffffffffffffffff
+fffffffffff800001fffffffffffffffffffffffffffc01ffff8
+ffffffffffffffffffffff81ffffffffffffffffffc7ffffc00fffffffffffffffffffff
+fffffffffffe00007fffffffffffffffffffffffffffc01ffff8
+ffffffffffffffffffffff81ffffffffffffffffff87ffffc007ffffffffffffffffffff
+ffffffffffff8003ffffffffffffffffffffffffffff801ffff8
+ffffffffffffffffffffff03ffffffffffffffffff0fffff8007ffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffff803ffff8
+fffffffffffffffffffffe07fffffffffffffffffe0fffff8001ffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffff803ffff8
+fffffffffffffffffffffe07fffffffffffffffffc1fffff0000ffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffff803ffff8
+fffffffffffffffffffffc0ffffffffffffffffff83ffffe00007fffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffff007ffff8
+fffffffffffffffffffff81fffffffffffffffffe03ffffe00007fffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffff007ffff8
+fffffffffffffffffffff83fffffffffffffffffc07ffffc00003fffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffff007ffff8
+fffffffffffffffffffff03fffffffffffffffff80fffff800001fffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffe00fffff8
+ffffffffffffffffffffe07fffffffffffffffff00fffff800000fffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffe00fffff8
+ffffffffffffffffffffe0fffffffffffffffffe01fffff0000007ffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffe00fffff8
+ffffffffffffffffffffc0fffffffffffffffffc01ffffe0000003ffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffe00fffff8
+ffffffffffffffffffff81fffffffffffffffff803ffffe0000003ffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffe01fffff8
+ffffffffffffffffffff81ffffffffffffffffe007ffffc0000003ffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffc01fffff8
+ffffffffffffffffffff83ffffffffffffffffe007ffffc0000001ffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffc01fffff8
+ffffffffffffffffffff07ffffffffffffffff800fffff80000000ffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffc01fffff8
+fffffffffffffffffffe07ffffffffffffffff800fffff00000000ffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffc03fffff8
+fffffffffffffffffffc0ffffffffffffffffe001fffff00000000ffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffff803fffff8
+fffffffffffffffffffc0ffffffffffffffffc003ffffe000000007fffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffff803fffff8
+fffffffffffffffffff81ffffffffffffffff0003ffffc000000007fffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffff007fffff8
+fffffffffffffffffff01fffffffffffffffe0007ffffc000000003fffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffff007fffff8
+fffffffffffffffffff03fffffffffffffffe000fffff8000000001fffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffff007fffff8
+ffffffffffffffffffe07fffffffffffffff8000fffff0000000001fffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffe00ffffff8
+ffffffffffffffffffc07fffffffffffffff0001fffff0000000001fffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffe00ffffff8
+ffffffffffffffffffc0fffffffffffffffe0001ffffe0000000000fffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffe00ffffff8
+ffffffffffffffffff80fffffffffffffff80003ffffe0000000000fffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffe01ffffff8
+ffffffffffffffffff81fffffffffffffff00007ffffc0000000000fffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffc01ffffff8
+ffffffffffffffffff81ffffffffffffffe00007ffffc00000000007ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffc01ffffff8
+ffffffffffffffffff03ffffffffffffffc0000fffffc00000000007ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffc03ffffff8
+fffffffffffffffffe03ffffffffffffff00000fffffe00000000007ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff803ffffff8
+fffffffffffffffffc07fffffffffffffe00001ffffff00000000007ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff803ffffff8
+fffffffffffffffffc07fffffffffffffc00007ffffffc0000000007ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff807ffffff8
+fffffffffffffffff807fffffffffffff00001fffffffe0000000003ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff807ffffff8
+fffffffffffffffff807ffffffffffffe00003ffffffff0000000003ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff007ffffff8
+fffffffffffffffff00fffffffffffff800007ffffffff8000000003ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff00fffffff8
+fffffffffffffffff00fffffffffffff00000fffffffffc000000001ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff00fffffff8
+ffffffffffffffffe00ffffffffffffc00003fffffffffe000000001ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffe01fffffff8
+ffffffffffffffffe00ffffffffffff800007ffffffffff000000001ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffe01fffffff8
+ffffffffffffffffc00ffffffffffff00000fffffffffff800000001ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffe01fffffff8
+ffffffffffffffff800fffffffffffc00001fffffffffffc00000001ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffe03fffffff8
+ffffffffffffffff800fffffffffff000007fffffffffffe00000001ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffe03fffffff8
+ffffffffffffffff001ffffffffffe00000fffffffffffff00000001ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffc07fffffff8
+ffffffffffffffff001ffffffffffc00001fffffffffffff80000001ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffc07fffffff8
+fffffffffffffffe000fffffffffe000003fffffffffffff80000001ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffff807fffffff8
+fffffffffffffffe000fffffffffc000007fffffffffffffc0000000ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffff807fffffff8
+fffffffffffffffc000fffffffff800000ffffffffffffffe0000000ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffff80ffffffff8
+fffffffffffffffc0007fffffffe000001fffffffffffffff0000000ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffff80ffffffff8
+fffffffffffffffc0003fffffffc000003fffffffffffffff0000000ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffff01ffffffff8
+fffffffffffffff80001fffffff8000007fffffffffffffff8000000ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffff01ffffffff8
+fffffffffffffff80000ffffffc000001ffffffffffffffff8000000ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffff01ffffffff8
+fffffffffffffff800003fffff0000003ffffffffffffffffc000000ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffe01ffffffff8
+fffffffffffffff000000000000000007ffffffffffffffffc000000ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffe03ffffffff8
+ffffffffffffffe00000000000000000fffffffffffffffffe000000ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffe03ffffffff8
+ffffffffffffffe00000000000000001fffffffffffffffffe000000ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffc07ffffffff8
+ffffffffffffffc00000000000000003fffffffffffffffffe000000ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffc07ffffffff8
+ffffffffffffffc00000000000000007ffffffffffffffffff000000ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffc07ffffffff8
+ffffffffffffffc0000000000000000fffffffffffffffffff000000ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffc0fffffffff8
+ffffffffffffff80000000000000003fffffffffffffffffff800000ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffc0fffffffff8
+ffffffffffffff80000000000000007fffffffffffffffffff800001ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffff80fffffffff8
+ffffffffffffff8000000000000001ffffffffffffffffffff800001ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffff81fffffffff8
+ffffffffffffff8000000000000001ffffffffffffffffffffc00001ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffff81fffffffff8
+ffffffffffffff8000000000000003ffffffffffffffffffffe00001ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffff01fffffffff8
+ffffffffffffff000000000000000fffffffffffffffffffffe00001ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffff03fffffffff8
+ffffffffffffff000000000000001ffffffffffffffffffffff00001ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffe03fffffffff8
+fffffffffffffe000000000000003ffffffffffffffffffffff00001ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffe03fffffffff8
+fffffffffffffe000000000000007ffffffffffffffffffffff00001ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffe03fffffffff8
+fffffffffffffc00000000000001fffffffffffffffffffffff00001ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffe07fffffffff8
+fffffffffffffc00000000000007fffffffffffffffffffffff00001ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffc07fffffffff8
+fffffffffffffc00000000000007fffffffffffffffffffffff00001ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffc07fffffffff8
+fffffffffffffc0000000000003ffffffffffffffffffffffff80003ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffc0ffffffffff8
+fffffffffffffc0000000000007ffffffffffffffffffffffff80003ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffc0ffffffffff8
+fffffffffffffc000000000000fffffffffffffffffffffffff80003ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffff80ffffffffff8
+fffffffffffffc000000000003fffffffffffffffffffffffff80003ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffff80ffffffffff8
+fffffffffffffc000000000007fffffffffffffffffffffffff80003ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffff00ffffffffff8
+fffffffffffffc00000000001ffffffffffffffffffffffffff80007ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffff01ffffffffff8
+fffffffffffffe00000000001ffffffffffffffffffffffffff80007ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffff01ffffffffff8
+fffffffffffffe0000000000fffffffffffffffffffffffffff80007ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffe01ffffffffff8
+ffffffffffffff0000000001fffffffffffffffffffffffffff80007ffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffe03ffffffffff8
+ffffffffffffff000000000ffffffffffffffffffffffffffff80007ffffffffffffffff
+fffffffffffffffffffdffffffffffffffffffe03ffffffffff8
+ffffffffffffff800000003ffffffffffffffffffffffffffff80007ffffffffffffffff
+fffffffffffffffffff9ffffffffffffffffffc03ffffffffff8
+ffffffffffffffe0000001fffffffffffffffffffffffffffff80007ffffffffffffffff
+fffffffffffffffffff1ffffffffffffffffff807ffffffffff8
+fffffffffffffff0000001fffffffffffffffffffffffffffff8000fffffffffffffffff
+fffffffffffffffffff1ffffffffffffffffff807ffffffffff8
+fffffffffffffff800000ffffffffffffffffffffffffffffffc000fffffffffffffffff
+fffffffffffffffffff1ffffffffffffffffff807ffffffffff8
+fffffffffffffffe0003fffffffffffffffffffffffffffffffc000fffffffffffffffff
+ffffffffffffffffffe1ffffffffffffffffff807ffffffffff8
+ffffffffffffffff4007fffffffffffffffffffffffffffffffc001fffffffffffffffff
+ffffffffffffffffffc1ffffffffffffffffff00fffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffc001fffffffffffffffff
+ffffffffffffffffff83ffffffffffffffffff00fffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffc001fffffffffffffffff
+ffffffffffffffffff83ffffffffffffffffff00fffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffc001fffffffffffffffff
+ffffffffffffffffff03ffffffffffffffffff00fffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffc001fffffffffffffffff
+ffffffffffffffffff03ffffffffffffffffff01fffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffc003fffffffffffffffff
+ffffffffffffffffff07ffffffffffffffffff01fffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffc003fffffffffffffffff
+fffffffffffffffffe07fffffffffffffffffe01fffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffc003fffffffffffffffff
+fffffffffffffffffc07fffffffffffffffffe03fffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffc007fffffffffffffffff
+fffffffffffffffffc07fffffffffffffffffc03fffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffc007fffffffffffffffff
+fffffffffffffffff80ffffffffffffffffffc03fffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffe007fffffffffffffffff
+fffffffffffffffff80ffffffffffffffffffc03fffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffe007fffffffffffffffff
+fffffffffffffffff80ffffffffffffffffffc03fffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffe00ffffffffffffffffff
+fffffffffffffffff03ffffffffffffffffff807fffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffe00ffffffffffffffffff
+ffffffffffffffffe01ffffffffffffffffff807fffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffe01ffffffffffffffffff
+ffffffffffffffffe03ffffffffffffffffff807fffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffe01ffffffffffffffffff
+ffffffffffffffffc07ffffffffffffffffff00ffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffe03ffffffffffffffffff
+ffffffffffffffffc07ffffffffffffffffff00ffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffe03ffffffffffffffffff
+ffffffffffffffff80fffffffffffffffffff00ffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffe07ffffffffffffffffff
+ffffffffffffffff80fffffffffffffffffff00ffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffff07ffffffffffffffffff
+ffffffffffffffff00ffffffffffffffffffe01ffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffff07ffffffffffffffffff
+fffffffffffffffe00ffffffffffffffffffe01ffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffff0fffffffffffffffffff
+fffffffffffffffe00ffffffffffffffffffe01ffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffff0fffffffffffffffffff
+fffffffffffffffc01ffffffffffffffffffc01ffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffff1fffffffffffffffffff
+fffffffffffffffc03ffffffffffffffffffc01ffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffff3fffffffffffffffffff
+fffffffffffffffc03ffffffffffffffffffc03ffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffff
+fffffffffffffff807ffffffffffffffffffc03ffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffff807ffffffffffffffffff803ffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffff00fffffffffffffffffff803ffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffff00fffffffffffffffffff807ffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffe01fffffffffffffffffff807ffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffe03fffffffffffffffffff807ffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffc03fffffffffffffffffff807ffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffff807fffffffffffffffffff00fffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffff807fffffffffffffffffff00fffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffff00ffffffffffffffffffff00fffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffff00fffffffffffffffffffe00fffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffe01fffffffffffffffffffe01fffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffe03fffffffffffffffffffe01fffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffc03fffffffffffffffffffc01fffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffc07fffffffffffffffffffc01fffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffff807fffffffffffffffffffc03fffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffff00ffffffffffffffffffffc03fffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffff00ffffffffffffffffffff803fffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffe01ffffffffffffffffffff803fffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffe01ffffffffffffffffffff803fffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffc03ffffffffffffffffffff807fffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffc03ffffffffffffffffffff007fffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff807ffffffffffffffffffff007fffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff807ffffffffffffffffffff007fffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff00fffffffffffffffffffff007fffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffe00ffffffffffffffffffffe00ffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffe01ffffffffffffffffffffe00ffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9fffffffffffff
+fffffffffffc01ffffffffffffffffffffe00ffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1fffffffffffff
+fffffffffffc03ffffffffffffffffffffe00ffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1fffffffffffff
+fffffffffff803ffffffffffffffffffffc00ffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1fffffffffffff
+fffffffffff807ffffffffffffffffffffc00ffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1fffffffffffff
+fffffffffff00fffffffffffffffffffffc01ffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3fffffffffffff
+fffffffffff00fffffffffffffffffffffc01ffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffff83fffffffffffff
+ffffffffffc01fffffffffffffffffffffc01ffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffff07fffffffffffff
+ffffffffffc01fffffffffffffffffffffc01ffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffff07fffffffffffff
+ffffffffff801fffffffffffffffffffff801ffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffff07fffffffffffff
+ffffffffff803fffffffffffffffffffff801ffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0ffffffffffffff
+ffffffffff003fffffffffffffffffffff803ffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0ffffffffffffff
+fffffffffe007fffffffffffffffffffff803ffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1ffffffffffffff
+fffffffffc007fffffffffffffffffffff003ffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffff81ffffffffffffff
+fffffffffc00ffffffffffffffffffffff003ffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffff01ffffffffffffff
+fffffffff800ffffffffffffffffffffff003ffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffff01ffffffffffffff
+fffffffff801ffffffffffffffffffffff003ffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffff03ffffffffffffff
+fffffffff803ffffffffffffffffffffff007ffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffe07ffffffffffffff
+fffffffff003fffffffffffffffffffffe007ffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffc07ffffffffffffff
+ffffffffe007fffffffffffffffffffffe007ffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffffff807ffffffffffffff
+ffffffffc007fffffffffffffffffffffe007ffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffffff007ffffffffffffff
+ffffffffc007fffffffffffffffffffffe007ffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffffff00fffffffffffffff
+ffffffff800ffffffffffffffffffffffe00fffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffffff00fffffffffffffff
+ffffffff000ffffffffffffffffffffffe00fffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffe00fffffffffffffff
+fffffffe001ffffffffffffffffffffffe00fffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffc01fffffffffffffff
+fffffffc003ffffffffffffffffffffffe00fffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffc01fffffffffffffff
+9ffffffc003ffffffffffffffffffffffe00fffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff803fffffffffffffff
+0ffffff8003ffffffffffffffffffffffc01fffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff003ffffffffffffffe
+07fffff0007ffffffffffffffffffffffc01fffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff003ffffffffffffffe
+07ffffe000fffffffffffffffffffffffc01fffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffffe007ffffffffffffff8
+03ffffc000fffffffffffffffffffffffc01fffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffffe007ffffffffffffff0
+03ffff8001fffffffffffffffffffffff801fffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffffc007ffffffffffffff0
+01ffff0003fffffffffffffffffffffff803fffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffff800ffffffffffffffe0
+00fffe0003fffffffffffffffffffffff803fffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffff800ffffffffffffffe0
+00fffe0003fffffffffffffffffffffff803fffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffff001ffffffffffffffc0
+003ffc0007fffffffffffffffffffffff003fffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffe003ffffffffffffff80
+001fe0001ffffffffffffffffffffffff003fffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffe003ffffffffffffff00
+000fc0001ffffffffffffffffffffffff007fffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffffc007fffffffffffffe00
+000000001ffffffffffffffffffffffff007fffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffff8007fffffffffffffe00
+000000003ffffffffffffffffffffffff007fffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffff800ffffffffffffffc00
+000000003ffffffffffffffffffffffff007fffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffff000ffffffffffffff800
+000000007fffffffffffffffffffffffe007fffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffe001ffffffffffffff800
+000000007fffffffffffffffffffffffe007fffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffe001ffffffffffffff000
+00000001ffffffffffffffffffffffffe007fffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffc003ffffffffffffff000
+00000001ffffffffffffffffffffffffe007fffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffffc007fffffffffffffe000
+00000001ffffffffffffffffffffffffe007fffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffff0007fffffffffffffc000
+00000003ffffffffffffffffffffffffc00ffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffff000ffffffffffffffc000
+00000003ffffffffffffffffffffffffc00ffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffe000ffffffffffffff8000
+00000007ffffffffffffffffffffffffc00ffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffc001ffffffffffffff0000
+0000000fffffffffffffffffffffffffc01ffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffffc003ffffffffffffff0000
+0000001fffffffffffffffffffffffffc01ffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffff8003fffffffffffffe0000
+0000001fffffffffffffffffffffffffc01ffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffff0007fffffffffffffe0000
+0000003fffffffffffffffffffffffffc01ffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffe000ffffffffffffffc0000
+0000007fffffffffffffffffffffffff801ffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffe000ffffffffffffff80000
+0000007fffffffffffffffffffffffff801ffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffffc001ffffffffffffff80000
+000000ffffffffffffffffffffffffff801ffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffff8001ffffffffffffff00000
+000001ffffffffffffffffffffffffff801ffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffff0003ffffffffffffff00000
+000001ffffffffffffffffffffffffff801ffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffff0003ffffffffffffff00000
+000003ffffffffffffffffffffffffff801ffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffe0007fffffffffffffe00000
+000003ffffffffffffffffffffffffff801ffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffe000ffffffffffffffe00000
+000007ffffffffffffffffffffffffff803ffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffffc000ffffffffffffffc00000
+00000fffffffffffffffffffffffffff003ffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffff8001ffffffffffffff800000
+00000fffffffffffffffffffffffffff803ffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffff0003ffffffffffffff800000
+00001fffffffffffffffffffffffffff803ffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffff0007ffffffffffffff000200
+00003fffffffffffffffffffffffffff007ffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffe0007fffffffffffffe000700
+00007fffffffffffffffffffffffffff00fffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffffc000ffffffffffffffe001f80
+0000ffffffffffffffffffffffffffff00fffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffff8000ffffffffffffffe001f80
+0001ffffffffffffffffffffffffffff00fffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffff8000ffffffffffffffc003fc0
+0001ffffffffffffffffffffffffffff00fffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffff0001ffffffffffffff8007fe0
+0003ffffffffffffffffffffffffffff01fffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffe0003ffffffffffffff0007fe0
+0007ffffffffffffffffffffffffffff01fffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffe0007ffffffffffffff000fff0
+0007ffffffffffffffffffffffffffff01fffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffffc000ffffffffffffffe003fff8
+001fffffffffffffffffffffffffffff07fffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffff8000ffffffffffffffe003fffc
+007fffffffffffffffffffffffffffff07fffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffff8000ffffffffffffffe003fffe
+00ffffffffffffffffffffffffffffff07fffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffff0001ffffffffffffffc007ffff
+dfffffffffffffffffffffffffffffff0ffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffe0003ffffffffffffff800fffff
+fffffffffffffffffffffffffffffffe1ffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffc0007ffffffffffffff800fffff
+fffffffffffffffffffffffffffffffe1ffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffffc0007ffffffffffffff001fffff
+fffffffffffffffffffffffffffffffe1ffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffff8000fffffffffffffff003fffff
+fffffffffffffffffffffffffffffffe3ffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffe003fffff
+ffffffffffffffffffffffffffffffff3ffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffe0001ffffffffffffffc007fffff
+ffffffffffffffffffffffffffffffff3ffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffe0003ffffffffffffffc007fffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffffc0007ffffffffffffffc00ffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffff8000fffffffffffffff800ffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffff8000fffffffffffffff801ffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffe0000fffffffffffffff001ffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffc0001fffffffffffffff003ffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffffc0003ffffffffffffffe007ffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffff80007ffffffffffffffe007ffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffff0000fffffffffffffffc00fffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffff0000fffffffffffffffc00fffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffe0001fffffffffffffffc00fffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffc0001fffffffffffffff801fffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffffc0003fffffffffffffff801fffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffff80003fffffffffffffff003fffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffff007fffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffe0000ffffffffffffffff007fffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffc0001fffffffffffffffc007fffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffffc0001fffffffffffffffc00ffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffff80003fffffffffffffffc01ffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffff801ffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffe0001ffffffffffffffff801ffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffc0001ffffffffffffffff803ffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffffc0003ffffffffffffffff803ffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffff80003fffffffffffffffe007ffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffff80007fffffffffffffffe007ffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffe00fffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffc00fffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffffc0001ffffffffffffffff801fffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffff80003ffffffffffffffff803fffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffff80003ffffffffffffffff003fffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffff00007ffffffffffffffff003fffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffe0000ffffffffffffffffe007fffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffe0000ffffffffffffffffc007fffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffffc0001ffffffffffffffffc00ffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffff80007ffffffffffffffffc00ffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffff00007ffffffffffffffff801ffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffff00007ffffffffffffffff801ffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffe0000fffffffffffffffff003ffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffffc0001fffffffffffffffff003ffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffff80003ffffffffffffffffe007ffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffff80003ffffffffffffffffe007ffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffe00007ffffffffffffffffc00fffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffe0000fffffffffffffffffc00fffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffffe0000fffffffffffffffffc00fffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffff80001fffffffffffffffff801fffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffff00003fffffffffffffffff801fffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffff00007fffffffffffffffff003fffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffe00007fffffffffffffffff007fffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffc0000ffffffffffffffffff007fffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffffc0001fffffffffffffffffc007fffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffff80003fffffffffffffffffc00ffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffff80007fffffffffffffffffc01ffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffff00007fffffffffffffffff801ffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffff0000ffffffffffffffffff801ffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffffc0001ffffffffffffffffff803ffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffff80003ffffffffffffffffff803ffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffff00007ffffffffffffffffff007ffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffff00007ffffffffffffffffff007ffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffe0000ffffffffffffffffffe00fffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffc0000ffffffffffffffffffe00fffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffffc0001ffffffffffffffffffe01fffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffff80003ffffffffffffffffffc03fffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffff00007ffffffffffffffffffc03fffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffe00007ffffffffffffffffffc03fffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffe00007ffffffffffffffffffc07fffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffffc0001fffffffffffffffffff807fffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffff80003fffffffffffffffffff80ffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffff80003fffffffffffffffffff80ffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffff00007fffffffffffffffffff81ffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffe0000ffffffffffffffffffff01ffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffe0001ffffffffffffffffffff03ffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffffc0003ffffffffffffffffffff03ffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffff80003fffffffffffffffffffe07ffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffff00007fffffffffffffffffffe07ffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffe00007fffffffffffffffffffe0fffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffe0000ffffffffffffffffffffc0fffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffe0000ffffffffffffffffffffc1fffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffffc0001ffffffffffffffffffffc1fffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffff80007ffffffffffffffffffff83fffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffff00007ffffffffffffffffffff83fffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffe00007ffffffffffffffffffff83fffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffe0000fffffffffffffffffffff87fffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffc0001fffffffffffffffffffff87fffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffffc0001fffffffffffffffffffff0ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffff80003fffffffffffffffffffff0ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffff00007fffffffffffffffffffff0ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffff0000ffffffffffffffffffffff1ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffe0000fffffffffffffffffffffe1ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffffc0001fffffffffffffffffffffe3ffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffff80003fffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffff00007fffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffe0001ffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffe0001ffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffc0003ffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffffc0007ffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffff0000fffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffff0000fffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffe0001fffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffc0003fffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffc0003fffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffffc0007fffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffff8000ffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffff8001ffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffff0001ffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffff0003ffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffff0003ffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffe0007ffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffffc000fffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffff8001fffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffff8001fffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffff8003fffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffff8007fffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffff8007fffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffff0007fffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffe000ffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffe001ffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffc001ffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffc007ffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffc00fffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffffc01fffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffff801fffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffff003fffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffff003fffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffe00ffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffe01ffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffc03ffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffffc03ffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffff807ffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffff807ffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffff80fffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffff00fffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+fffffffffffffffffffffff01fffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffe03fffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffe07fffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffe07fffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffe0ffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffc1ffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffc1ffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffffc3ffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffff83ffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffff87ffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffff8fffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffff8fffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffff1fffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffff1fffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+ffffffffffffffffffffff3fffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffff8
+
+
+showpage
+
+% stop using temporary dictionary
+end
+
+% restore original state
+origstate restore
+
+%%Trailer
diff --git a/xemacs-packages/gnus/texi/gnus-news.el b/xemacs-packages/gnus/texi/gnus-news.el
new file mode 100644 (file)
index 0000000..5ccd3f4
--- /dev/null
@@ -0,0 +1,115 @@
+;;; gnus-news.el --- a hack to create GNUS-NEWS from texinfo source
+;; Copyright (C) 2004-2016 Free Software Foundation, Inc.
+
+;; Author: Reiner Steib  <Reiner.Steib@gmx.de>
+;; Keywords: tools
+
+;; 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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(defvar gnus-news-header-disclaimer
+"GNUS NEWS -- history of user-visible changes.
+
+Copyright (C) 1999-2016 Free Software Foundation, Inc.
+See the end of the file for license conditions.
+
+Please send Gnus bug reports to bugs@gnus.org.
+For older news, see Gnus info node \"New Features\".\n\n")
+
+(defvar gnus-news-trailer
+"\f
+* For older news, see Gnus info node \"New Features\".
+
+----------------------------------------------------------------------
+\f
+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 3 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+\f\nLocal variables:\nmode: outline
+paragraph-separate: \"[        \f]*$\"\nend:\n")
+
+(defvar gnus-news-makeinfo-command "makeinfo")
+
+(defvar gnus-news-fill-column 80)
+
+(defvar gnus-news-makeinfo-switches
+  (concat " --no-headers --paragraph-indent=0"
+         " --no-validate" ;; Allow unresolved references.
+         " --fill-column=" (number-to-string
+                            (+ 3 ;; will strip leading spaces later
+                               (or gnus-news-fill-column 80)))))
+
+(defun batch-gnus-news ()
+  "Make GNUS-NEWS in batch mode."
+  (let (infile outfile)
+    (setq infile (car command-line-args-left)
+         command-line-args-left (cdr command-line-args-left)
+         outfile (car command-line-args-left)
+         command-line-args-left nil)
+    (if (and infile outfile)
+       (message "Creating `%s' from `%s'..." outfile infile)
+      (error "Not enough files given."))
+    (gnus-news-translate-file infile outfile)))
+
+(defun gnus-news-translate-file (infile outfile)
+  "Translate INFILE (texinfo) to OUTFILE (GNUS-NEWS)."
+  (let* ((dir (concat (or (getenv "srcdir") ".") "/"))
+        (infile (concat dir infile))
+        (buffer (find-file-noselect (concat dir outfile))))
+    (with-temp-buffer
+      ;; Could be done using 'texinfmt' stuff as in 'infohack.el'.
+      (insert
+       (shell-command-to-string
+       (concat gnus-news-makeinfo-command " "
+               gnus-news-makeinfo-switches " " infile)))
+      (goto-char (point-max))
+      (delete-char -1)
+      (goto-char (point-min))
+      (save-excursion
+       (while (re-search-forward "^   \\* " nil t)
+         (replace-match "\f\n* ")))
+      (save-excursion
+       (while (re-search-forward "^        \\* " nil t)
+         (replace-match "** ")))
+      (save-excursion
+       (while (re-search-forward "^     " nil t)
+         (replace-match "")))
+      ;; Avoid '*' from @ref at beginning of line:
+      (save-excursion
+       (while (re-search-forward "^\\*Note" nil t)
+         (replace-match " \\&")))
+      (goto-char (point-min))
+      (insert gnus-news-header-disclaimer)
+      (goto-char (point-max))
+      (insert gnus-news-trailer)
+      (write-region (point-min) (point-max) outfile))))
+
+;;; gnus-news.el ends here
diff --git a/xemacs-packages/gnus/texi/gnus-news.texi b/xemacs-packages/gnus/texi/gnus-news.texi
new file mode 100644 (file)
index 0000000..d1e83a7
--- /dev/null
@@ -0,0 +1,371 @@
+@c -*-texinfo-*-
+
+@c Copyright (C) 2004-2016 Free Software Foundation, Inc.
+
+@c    Permission is granted to anyone to make or distribute verbatim copies
+@c    of this document as received, in any medium, provided that the
+@c    copyright notice and this permission notice are preserved,
+@c    thus giving the recipient permission to redistribute in turn.
+
+@c    Permission is granted to distribute modified versions
+@c    of this document, or of portions of it,
+@c    under the above conditions, provided also that they
+@c    carry prominent notices stating who last changed them.
+
+@c This file contains a list of news features Gnus.  It is supposed to be
+@c included in 'gnus.texi'.  'GNUS-NEWS' is automatically generated from
+@c this file (see 'gnus-news.el').
+
+@itemize @bullet
+
+@item Supported Emacs versions
+The following Emacs versions are supported by No Gnus:
+@itemize @bullet
+
+@item Emacs 22 and up
+@item XEmacs 21.4
+@item XEmacs 21.5
+@item SXEmacs
+
+@end itemize
+
+@item Installation changes
+
+@itemize @bullet
+@item Upgrading from previous (stable) version if you have used No Gnus.
+
+If you have tried No Gnus (the unstable Gnus branch leading to this
+release) but went back to a stable version, be careful when upgrading
+to this version.  In particular, you will probably want to remove the
+@file{~/News/marks} directory (perhaps selectively), so that flags are
+read from your @file{~/.newsrc.eld} instead of from the stale marks
+file, where this release will store flags for nntp.  See a later entry
+for more information about nntp marks.  Note that downgrading isn't
+safe in general.
+
+@item Incompatibility when switching from Emacs 23 to Emacs 22 
+In Emacs 23, Gnus uses Emacs's new internal coding system @code{utf-8-emacs}
+for saving articles drafts and @file{~/.newsrc.eld}.  These files may not
+be read correctly in Emacs 22 and below.  If you want to use Gnus across
+different Emacs versions, you may set @code{mm-auto-save-coding-system}
+to @code{emacs-mule}.
+@c FIXME: Untested.  (Or did anyone test it?)
+@c Cf. http://thread.gmane.org/gmane.emacs.gnus.general/66251/focus=66344
+
+@item Lisp files are now installed in @file{.../site-lisp/gnus/} by default.
+It defaulted to @file{.../site-lisp/} formerly.  In addition to this,
+the new installer issues a warning if other Gnus installations which
+will shadow the latest one are detected.  You can then remove those
+shadows manually or remove them using @code{make
+remove-installed-shadows}.
+
+@item The installation directory name is allowed to have spaces and/or tabs.
+@end itemize
+
+@item New packages and libraries within Gnus
+
+@itemize @bullet
+
+@item New version of @code{nnimap}
+
+@code{nnimap} has been reimplemented in a mostly-compatible way.  See
+the Gnus manual for a description of the new interface.  In
+particular, @code{nnimap-inbox} and the client side split method has
+changed.
+
+@item Gnus includes the Emacs Lisp @acronym{SASL} library.
+
+This provides a clean @acronym{API} to @acronym{SASL} mechanisms from
+within Emacs.  The user visible aspects of this, compared to the earlier
+situation, include support for @acronym{DIGEST}-@acronym{MD5} and
+@acronym{NTLM}.   @xref{Top, ,Emacs SASL, sasl, Emacs SASL}.
+
+@item ManageSieve connections uses the @acronym{SASL} library by default.
+
+The primary change this brings is support for @acronym{DIGEST-MD5} and
+@acronym{NTLM}, when the server supports it.
+
+@item Gnus includes a password cache mechanism in password.el.
+
+It is enabled by default (see @code{password-cache}), with a short
+timeout of 16 seconds (see @code{password-cache-expiry}).  If
+@acronym{PGG} is used as the @acronym{PGP} back end, the @acronym{PGP}
+passphrase is managed by this mechanism.  Passwords for ManageSieve
+connections are managed by this mechanism, after querying the user
+about whether to do so.
+
+@item Using EasyPG with Gnus
+When EasyPG, is available, Gnus will use it instead of @acronym{PGG}.
+EasyPG is an Emacs user interface to GNU Privacy Guard.  @xref{Top,
+,EasyPG Assistant user's manual, epa, EasyPG Assistant user's manual}.
+EasyPG is included in Emacs 23 and available separately as well.
+@end itemize
+
+@item Changes in group mode
+@c ************************
+
+@itemize @bullet
+
+@item
+Symbols like @code{gcc-self} now have the same precedence rules in
+@code{gnus-parameters} as other ``real'' variables: The last match
+wins instead of the first match.
+
+@item
+Old intermediate incoming mail files (@file{Incoming*}) are deleted
+after a couple of days, not immediately.  @xref{Mail Source
+Customization}.
+(New in Gnus 5.10.10 / No Gnus 0.8)
+@c This entry is also present in the node "Oort Gnus".
+
+@end itemize
+
+@item Changes in summary and article mode
+
+@itemize @bullet
+
+@item There's now only one variable that determines how @acronym{HTML}
+is rendered: @code{mm-text-html-renderer}.
+
+@item Gnus now supports sticky article buffers.  Those are article buffers
+that are not reused when you select another article.  @xref{Sticky
+Articles}.
+
+@c @item Bookmarks
+@c FIXME: To be added
+
+@item Gnus can selectively display @samp{text/html} articles
+with a WWW browser with @kbd{K H}.  @xref{MIME Commands}.
+
+@c gnus-registry-marks
+@c FIXME: To be added
+
+@item International host names (@acronym{IDNA}) can now be decoded
+inside article bodies using @kbd{W i}
+(@code{gnus-summary-idna-message}).  This requires that GNU Libidn
+(@url{http://www.gnu.org/software/libidn/}) has been installed.
+@c FIXME: Also mention @code{message-use-idna}?
+
+@item The non-@acronym{ASCII} group names handling has been much
+improved.  The back ends that fully support non-@acronym{ASCII} group
+names are now @code{nntp}, @code{nnml}, and @code{nnrss}.  Also the
+agent, the cache, and the marks features work with those back ends.
+@xref{Non-ASCII Group Names}.
+
+@item Gnus now displays @acronym{DNS} master files sent as text/dns
+using dns-mode.
+
+@item Gnus supports new limiting commands in the Summary buffer:
+@kbd{/ r} (@code{gnus-summary-limit-to-replied}) and @kbd{/ R}
+(@code{gnus-summary-limit-to-recipient}).  @xref{Limiting}.
+
+@item You can now fetch all ticked articles from the server using
+@kbd{Y t} (@code{gnus-summary-insert-ticked-articles}).  @xref{Summary
+Generation Commands}.
+
+@item Gnus supports a new sort command in the Summary buffer:
+@kbd{C-c C-s C-t} (@code{gnus-summary-sort-by-recipient}).  @xref{Summary
+Sorting}.
+
+@item @acronym{S/MIME} now features @acronym{LDAP} user certificate searches.
+You need to configure the server in @code{smime-ldap-host-list}.
+
+@item URLs inside Open@acronym{PGP} headers are retrieved and imported
+to your PGP key ring when you click on them.
+
+@item
+Picons can be displayed right from the textual address, see
+@code{gnus-picon-style}.  @xref{Picons}.
+
+@item @acronym{ANSI} @acronym{SGR} control sequences can be transformed
+using @kbd{W A}.
+
+@acronym{ANSI} sequences are used in some Chinese hierarchies for
+highlighting articles (@code{gnus-article-treat-ansi-sequences}).
+
+@item Gnus now MIME decodes articles even when they lack "MIME-Version" header.
+This changes the default of @code{gnus-article-loose-mime}.
+
+@item @code{gnus-decay-scores} can be a regexp matching score files.
+For example, set it to @samp{\\.ADAPT\\'} and only adaptive score files
+will be decayed.  @xref{Score Decays}.
+
+@item Strings prefixing to the @code{To} and @code{Newsgroup} headers in
+summary lines when using @code{gnus-ignored-from-addresses} can be
+customized with @code{gnus-summary-to-prefix} and
+@code{gnus-summary-newsgroup-prefix}.  @xref{To From Newsgroups}.
+
+@item You can replace @acronym{MIME} parts with external bodies.
+See @code{gnus-mime-replace-part} and @code{gnus-article-replace-part}.
+@xref{MIME Commands}, @ref{Using MIME}.
+
+@item
+The option @code{mm-fill-flowed} can be used to disable treatment of
+format=flowed messages.  Also, flowed text is disabled when sending
+inline @acronym{PGP} signed messages.  @xref{Flowed text, ,Flowed text,
+emacs-mime, The Emacs MIME Manual}.  (New in Gnus 5.10.7)
+@c This entry is also present in the node "Oort Gnus".
+
+@item Now the new command @kbd{S W}
+(@code{gnus-article-wide-reply-with-original}) for a wide reply in the
+article buffer yanks a text that is in the active region, if it is set,
+as well as the @kbd{R} (@code{gnus-article-reply-with-original}) command.
+Note that the @kbd{R} command in the article buffer no longer accepts a
+prefix argument, which was used to make it do a wide reply.
+@xref{Article Keymap}.
+
+@item The new command @kbd{C-h b}
+(@code{gnus-article-describe-bindings}) used in the article buffer now
+shows not only the article commands but also the real summary commands
+that are accessible from the article buffer.
+
+@end itemize
+
+@item Changes in Message mode
+
+@itemize @bullet
+@item Gnus now defaults to saving all outgoing messages in per-month
+nnfolder archives.
+
+@item Gnus now supports the ``hashcash'' client puzzle anti-spam mechanism.
+Use @code{(setq message-generate-hashcash t)} to enable.
+@xref{Hashcash}.
+
+@item You can now drag and drop attachments to the Message buffer.
+See @code{mml-dnd-protocol-alist} and @code{mml-dnd-attach-options}.
+@xref{MIME, ,MIME, message, Message Manual}.
+
+@item The option @code{message-yank-empty-prefix} now controls how
+empty lines are prefixed in cited text.  @xref{Insertion Variables,
+,Insertion Variables, message, Message Manual}.
+
+@item Gnus uses narrowing to hide headers in Message buffers.
+The @code{References} header is hidden by default.  To make all
+headers visible, use @code{(setq message-hidden-headers nil)}.
+@xref{Message Headers, ,Message Headers, message, Message Manual}.
+
+@item You can highlight different levels of citations like in the
+article buffer.  See @code{gnus-message-highlight-citation}.
+
+@item @code{auto-fill-mode} is enabled by default in Message mode.
+See @code{message-fill-column}.  @xref{Various Message Variables, ,
+Message Headers, message, Message Manual}.
+
+@item You can now store signature files in a special directory
+named @code{message-signature-directory}.
+
+@item The option @code{message-citation-line-format} controls the format
+of the "Whomever writes:" line.  You need to set
+@code{message-citation-line-function} to
+@code{message-insert-formatted-citation-line} as well.
+@end itemize
+
+@item Changes in Browse Server mode
+
+@itemize @bullet
+@item Gnus' sophisticated subscription methods are now available in
+Browse Server buffers as well using the variable
+@code{gnus-browse-subscribe-newsgroup-method}.
+
+@end itemize
+
+
+@item Changes in back ends
+
+@itemize @bullet
+@item The nntp back end stores article marks in @file{~/News/marks}.
+
+The directory can be changed using the (customizable) variable
+@code{nntp-marks-directory}, and marks can be disabled using the
+(back end) variable @code{nntp-marks-is-evil}.  The advantage of this
+is that you can copy @file{~/News/marks} (using rsync, scp or
+whatever) to another Gnus installation, and it will realize what
+articles you have read and marked.  The data in @file{~/News/marks}
+has priority over the same data in @file{~/.newsrc.eld}.
+
+@item
+You can import and export your @acronym{RSS} subscriptions from
+@acronym{OPML} files.  @xref{RSS}.
+
+@item @acronym{IMAP} identity (@acronym{RFC} 2971) is supported.
+
+By default, Gnus does not send any information about itself, but you can
+customize it using the variable @code{nnimap-id}.
+
+@item The @code{nnrss} back end now supports multilingual text.
+Non-@acronym{ASCII} group names for the @code{nnrss} groups are also
+supported.  @xref{RSS}.
+
+@item Retrieving mail with @acronym{POP3} is supported over @acronym{SSL}/@acronym{TLS} and with StartTLS.
+
+@item The nnml back end allows other compression programs beside @file{gzip}
+for compressed message files.  @xref{Mail Spool}.
+
+@item The nnml back end supports group compaction.
+
+This feature, accessible via the functions
+@code{gnus-group-compact-group} (@kbd{G z} in the group buffer) and
+@code{gnus-server-compact-server} (@kbd{z} in the server buffer)
+renumbers all articles in a group, starting from 1 and removing gaps.
+As a consequence, you get a correct total article count (until
+messages are deleted again).
+
+@c @item nnmairix.el
+@c FIXME
+
+@c @item nnir.el
+@c FIXME
+
+@end itemize
+
+@item Appearance
+@c Maybe it's not worth to separate this from "Miscellaneous"?
+
+@itemize @bullet
+
+@item The tool bar has been updated to use GNOME icons.
+You can also customize the tool bars: @kbd{M-x customize-apropos RET
+-tool-bar$} should get you started.  (Only for Emacs, not in XEmacs.)
+@c FIXME: Document this in the manual
+
+@item The tool bar icons are now (de)activated correctly
+in the group buffer, see the variable @code{gnus-group-update-tool-bar}.
+Its default value depends on your Emacs version.
+@c FIXME: Document this in the manual
+
+@item You can change the location of XEmacs's toolbars in Gnus buffers.
+See @code{gnus-use-toolbar} and @code{message-use-toolbar}.
+
+@end itemize
+
+@item Miscellaneous changes
+
+@itemize @bullet
+@item Having edited the select-method for the foreign server in the
+server buffer is immediately reflected to the subscription of the groups
+which use the server in question.  For instance, if you change
+@code{nntp-via-address} into @samp{bar.example.com} from
+@samp{foo.example.com}, Gnus will connect to the news host by way of the
+intermediate host @samp{bar.example.com} from next time.
+
+@item The @file{all.SCORE} file can be edited from the group buffer
+using @kbd{W e}.
+
+@item You can set @code{gnus-mark-copied-or-moved-articles-as-expirable}
+to a non-@code{nil} value so that articles that have been read may be
+marked as expirable automatically when copying or moving them to a group
+that has auto-expire turned on.  The default is @code{nil} and copying
+and moving of articles behave as before; i.e., the expirable marks will
+be unchanged except that the marks will be removed when copying or
+moving articles to a group that has not turned auto-expire on.
+@xref{Expiring Mail}.
+
+@item NoCeM support has been removed.
+
+@item Carpal mode has been removed.
+
+@end itemize
+
+@end itemize
+
+@c gnus-news.texi ends here.
diff --git a/xemacs-packages/gnus/texi/gnus-overrides.texi b/xemacs-packages/gnus/texi/gnus-overrides.texi
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/xemacs-packages/gnus/texi/gnus-refcard.tex b/xemacs-packages/gnus/texi/gnus-refcard.tex
new file mode 100644 (file)
index 0000000..d51e2ac
--- /dev/null
@@ -0,0 +1,1426 @@
+\documentclass{article}
+
+% Previously we had five input LaTeX files (booklet.tex bk-lt.tex bk-a4.tex
+% refcard.tex gnusref.tex) and two logo files (gnuslogo-refcard.eps and
+% gnuslogo-booklet.eps).
+%
+% From this LaTeX file (gnus-refcard.tex) plus a single logo (gnus-logo.eps),
+% we can generate the refcard and the booklet version.  This simplifies to
+% distribute the refcard with Emacs.  Appropriate Makefile rules were added in
+% gnus/texi/Makefile.
+
+% For Emacs, we may use the following commands (w/o) using Gnus' Makefile:
+%
+%   latex gnus-refcard.tex &&
+%   dvips -t letter -f gnus-refcard.dvi > gnus-refcard.ps
+%
+%   latex '\def\booklettrue{}\def\letterpapertrue{}\input{gnus-refcard}' &&
+%   mv gnus-refcard.dvi gnus-booklet.dvi &&
+%   dvips -t letter -f gnus-booklet.dvi > gnus-booklet.ps
+
+\usepackage{ifthen}
+\ifthenelse{\isundefined{\booklettrue}}{
+  \typeout{Creating reference card...}
+}{
+  \typeout{Creating reference booklet...}}
+
+\usepackage{supertabular}
+
+\newlength{\logowidth}  \setlength{\logowidth} {6.861in}
+\newlength{\logoheight} \setlength{\logoheight}{7.013in}
+
+\usepackage{graphicx}
+
+\usepackage{geometry}
+
+\ifthenelse{\isundefined{\booklettrue}}{% ifcard %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Reference Card
+
+  \def\Guide{Card}\def\guide{card}
+  \def\logoscale{0.25}
+
+  % Page setup for the refcard:
+
+  % \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.
+  % \setlength{\oddsidemargin}{-0.5in} \setlength{\evensidemargin}{-0.5in}
+
+  \ifthenelse{\isundefined{\letterpapertrue}}{
+    \geometry{a4paper,hmargin=10mm,tmargin=10mm,bmargin=35mm}
+  }{
+    \geometry{hmargin=20mm,tmargin=10mm,bmargin=12mm}
+  }
+
+}{ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Reference Booklet
+
+  \def\Guide{Booklet}\def\guide{booklet}
+  \def\logoscale{0.5}% FIXME: too large for 2up printing?  --rsteib
+
+  \ifthenelse{\isundefined{\letterpapertrue}}{
+    \geometry{a5paper,hmargin=10mm,tmargin=10mm,bmargin=4mm}
+  }{
+    \geometry{a5paper,hmargin=20mm,tmargin=10mm,bmargin=4mm}
+  }
+
+  \def\sec{\section}
+  \def\subsec{\subsection}
+  \def\subsubsec{\subsubsection}
+  \def\blankpage{\vspace*{\fill}\par
+  %\centerline{(This page intentionally left blank.)}
+  \par\vspace*{\fill}\pagebreak}
+}%ifbooklet% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% \input{gnusref} % % % % % % % % % % % % % % % % % % % % % % % % % %
+%% include file for the Gnus refcard and booklet
+
+\def\progver{5.11} % program version
+% \def\refver{5.10-2} % refcard version (not used)
+\def\date{April, 2006}
+\def\author{Gnus Bugfixing Girls + Boys $<$bugs@gnus.org$>$}
+
+%%
+\newlength{\keycolwidth}
+\newenvironment{keys}[1]% #1 is the widest key
+{\nopagebreak%\noindent%
+  \settowidth{\keycolwidth}{#1}%
+  \addtolength{\keycolwidth}{\tabcolsep}%
+  \addtolength{\keycolwidth}{-\columnwidth}%
+  \begin{supertabular}{@{}l@{\hspace{\tabcolsep}}p{-\keycolwidth}@{}}}%
+  {\end{supertabular}\\}
+
+%% uncomment the first definition if you do not want pagebreaks in maps
+%%\newcommand{\esamepage}{\samepage}
+\newcommand{\esamepage}{}
+
+\newcommand*{\B}[1]{{\bf#1})}    % bold l)etter
+
+\newcommand{\Title}{%
+  \begin{center}
+    {\bf\LARGE Gnus \progver\ Reference \Guide\\}
+                                %{\normalsize \Guide\ version \refver}
+  \end{center}
+  }
+
+% \newcommand*{\LogoOLD}[1]{\centerline{%
+%     \makebox[\logoscale\logowidth][l]{\vbox to \logoscale\logoheight
+%       {\vfill\epsfig{figure=gnuslogo-#1}}\vspace{-\baselineskip}}}}
+
+\newcommand*{\Logo}[1]{\centerline{%
+    \includegraphics[width=\logoscale\logowidth]{gnus-logo}}}
+
+%%  Contributions by:
+%% 1995 Vladimir Alexiev <vladimir@cs.ualberta.ca>
+%% 2000 Felix Natter <fnatter@gmx.net>
+%% 2001, 2002, 2003, 2005 \author.
+%% Original Gnus manual 1994 Lars Magne Ingebrigtsen
+%% Some material from Emacs Help Bindings feature (C-h b).
+%% Gnus logo by Luis Fernandes.
+\newcommand{\Copyright}{%
+  \begin{center}
+    Copyright \copyright\ 1995, 2000, 2002--2016 Free Software Foundation, Inc.\\*
+  \end{center}
+
+  Permission is granted to make and distribute copies of this reference
+  \guide{} provided the copyright notice and this permission are preserved on
+  all copies.  Please send corrections, additions and suggestions to the
+  current maintainer's email address. \Guide{} last edited on \date.
+  }
+
+\newcommand{\Notes}{%
+  \subsection*{Notes}
+  {\esamepage
+    Gnus is complex. Currently it has some 876 interactive (user-callable)
+    functions. Of these 618 are in the two major modes (Group and
+    Summary/Article). Many of these functions have more than one binding, some
+    have 3 or even 4 bindings. The total number of keybindings is 677. So in
+    order to save 40\% space, every function is listed only once on this
+    \guide, under the ``more logical'' binding. Alternative bindings are given
+    in parentheses in the beginning of the description.
+
+    Many Gnus commands are affected by the numeric prefix. Normally you enter a
+    prefix by holding the Meta key and typing a number, but in most Gnus modes
+    you don't need to use Meta since the digits are not self-inserting. The
+    prefixed behavior of commands is given in [brackets]. Often the prefix is
+    used to specify:
+
+    \quad [distance] How many objects to move the point over.
+
+    \quad [scope] How many objects to operate on (including current one).
+
+    \quad [p/p] The ``Process/Prefix Convention'': If a prefix is given then it
+    determines how many objects to operate on. Else if there are some objects
+    marked with the process mark \#, these are operated on. Else only the
+    current object is affected.
+
+    \quad [level] A group subscribedness level. Only groups with a lower or
+    equal level will be affected by the operation. If no prefix is given,
+    `gnus-group-default-list-level' is used.  If
+    `gnus-group-use-permanent-levels', then a prefix to the `g' and `l'
+    commands will also set the default level.
+
+    \quad [score] An article score. If no prefix is given,
+    `gnus-summary-default-score' is used. \\*[\baselineskip]
+                                % some keys
+    Gnus startup-commands:\\*
+    \begin{keys}{M-x gnus-unplugged}
+      M-x gnus           & start Gnus. \\
+      M-x gnus-no-server & start Gnus without connecting to server
+      (i.e. to read mail). \\
+    \end{keys}
+    Additionally, there are two commands \texttt{gnus-plugged} and
+    \texttt{gnus-unplugged}, which are only used if you want to download
+    news and/or read previously downloaded news offline (see C-c C-i g Gnus
+    Unplugged RET). Note: \texttt{gnus-no-server} ignores the stuff in
+    \texttt{gnus-agent-directory}, and thus does not allow you to use Gnus
+    Unplugged.\\
+                                %
+    \begin{keys}{C-c C-i}
+      C-c C-i & Go to the Gnus online {\bf info}.\\
+      C-c C-b & Send a Gnus {\bf bug} report.\\
+    \end{keys}
+    }}
+
+\newcommand{\GroupLevels}{%
+  The table below assumes that you use the default Gnus levels.
+  Fill your user-specific levels in the blank cells.\\[1\baselineskip]
+  \begin{tabular}{|c|l|l|}
+    \hline
+    Level & Groups & Status \\
+    \hline
+    1 & draft/mail groups   &              \\
+    2 & mail groups         &              \\
+    3 &                     & subscribed   \\
+    4 &                     &              \\
+    5 & default list level  &              \\
+    \hline
+    6 &                     & unsubscribed \\
+    7 &                     &              \\
+    \hline
+    8 &                     & zombies      \\
+    \hline
+    9 &                     & killed       \\
+    \hline
+  \end{tabular}}
+
+\newcommand{\MarkCharacters}{%
+  {\esamepage If a command directly sets a mark, it is shown in parentheses.\\*
+    \newlength{\markcolwidth}
+    \settowidth{\markcolwidth}{` '}% widest character
+    \addtolength{\markcolwidth}{4\tabcolsep}
+    \addtolength{\markcolwidth}{-\columnwidth}
+    \newlength{\markdblcolwidth}
+    \setlength{\markdblcolwidth}{\columnwidth}
+    \addtolength{\markdblcolwidth}{-2\tabcolsep}
+    \begin{tabular}{|c|p{-\markcolwidth}|}
+      \hline
+      \multicolumn{2}{|p{\markdblcolwidth}|}{{\bf ``Read'' Marks.}
+        All these marks appear in the first column of the summary line, and so
+        are mutually exclusive.}\\
+      \hline
+      ` ' & (M-u, M SPC, M c) Not read.\\
+      !   & (!, M !, M t) Ticked (interesting).\\
+      ?   & (?, M ?) Dormant (only followups are interesting).\\
+      E   & (E, M e, M x) {\bf Expirable}. Only has effect in mail groups.\\
+      G   & (C, B DEL) Canceled article (or deleted in mailgroups).\\
+      \$  & (M-d, M s x, S x).  Marked as spam.\\
+      \hline\hline
+      \multicolumn{2}{|p{\markdblcolwidth}|}
+      {The marks below mean that the article
+        is read (killed, uninteresting), and have more or less the same effect.
+        Some commands however explicitly differentiate between them (e.g.\ M
+        M-C-r, adaptive scoring).}\\
+      \hline
+      r   & (d, M d, M r) Deleted (marked as {\bf read}).\\
+      C   & (M C; M C-c; M H; c, Z c; Z n; Z C) Killed by {\bf catch-up}.\\
+      F   & SOUPed article. See the manual.\\
+      O   & {\bf Old} (read in a previous session).\\
+      K   & (k, M k; C-k, M K) {\bf Killed}.\\
+      M   & Article marked as read by duplicate suppression.\\
+      Q   & Article is part of a sparse thread (see ``Threading''
+      in manual).\\
+      R   & {\bf Read} (viewed in actuality).\\
+      X   & Killed by a kill file.\\
+      Y   & Killed due to low score.\\
+      \hline\multicolumn{2}{c}{\vspace{1ex}}\\\hline
+      \multicolumn{2}{|p{\markdblcolwidth}|}
+      {{\bf Marks not affecting visibility}}\\
+      \hline
+      \#  & (\#, M \#, M P p) Processable (affected by next operation).
+      [2]\\
+      A   & {\bf Answered} (followed-up or replied). [2]\\
+      F   & Forwarded. [2]\\
+      $\ast$  & Cached. [2]\\
+      S   & Saved. [2]\\
+      N   & Recently arrived. [2]\\
+      .   & Unseen. [2]\\
+      +   & Over default score. [3]\\
+      $-$ & Under default score. [3]\\
+      $=$ & Has children (thread underneath it). Add `\%e' to
+      `gnus-summary-line-format'. [3]\\
+      \hline
+    \end{tabular}
+    }}
+
+\newcommand{\GroupModeGeneral}{%
+  \begin{keys}{C-c M-C-x}
+    RET     & (=) Enter this group. [Prefix: how many (read) articles to fetch.
+    Positive: newest articles, negative: oldest ones; non-numerical:
+    view all articles, not just unread]\\
+    M-RET   & Enter group quickly.\\
+    M-SPC   & Same as RET but does not expunge and hide dormants.\\
+    M-C-RET & Enter group without any processing, changes will not be permanent.\\
+    SPC     & Select this group and display the first (unread) article. [Same
+    prefix as above.]\\
+    ?       & Give a very short help message.\\
+    $<$     & Go to the beginning of the Group buffer.\\
+    $>$     & Go to the end of the Group buffer.\\
+    ,       & Jump to the lowest-level group with unread articles.\\
+    .       & Jump to the first group with unread articles.\\
+    \^{}      & Enter the Server buffer mode.\\
+    a       & Post an {\bf article} to a group
+              [Prefix: use group under point to find posting-style].\\
+    b       & Find {\bf bogus} groups and delete them.\\
+    c       & Mark all unticked articles in group as read ({\bf catch-up}).
+    [p/p]\\
+    g       & Check the server for new articles ({\bf get}). [level]\\
+    M-g     & Check the server for new articles in this group ({\bf get}). [p/p]\\
+    j       & {\bf Jump} to a group.\\
+    m       & {\bf Mail} a message to someone
+              [Prefix: use group under point to find posting-style].\\
+    n       & Go to the {\bf next} group with unread articles. [distance]\\
+    M-n     & Go to the {\bf next} group on the same or lower level.
+    [distance]\\
+    p       & (DEL) Go to the {\bf previous} group with unread articles.
+    [distance]\\
+    M-p     & Go to the {\bf previous} group on the same or lower level. [distance]\\
+    q       & {\bf Quit} Gnus.\\
+    r       & Re-read the init file ({\bf reset}).\\
+    s       & {\bf Save} `.newsrc.eld' file (and `.newsrc' if
+    `gnus-save-newsrc-file').\\
+    z       & Suspend (kill all buffers of) Gnus.\\
+    B       & {\bf Browse} a foreign server.\\
+    C       & Mark all articles in this group as read ({\bf Catch-up}). [p/p]\\
+    F       & {\bf Find} new groups and process them.\\
+    N       & Go to the {\bf next} group. [distance]\\
+    P       & Go to the {\bf previous} group. [distance]\\
+    Q       & {\bf Quit} Gnus without saving any startup (.newsrc) files.\\
+    R       & {\bf Restart} Gnus.\\
+    Z       & Clear the dribble buffer.\\
+    M-c     & Clear data from group (marks and list of read articles). \\
+    C-c C-s & {\bf Sort} the groups by name, number of unread articles, or level
+    (depending on `gnus-group-sort-function').\\
+    C-c C-x & Run all expirable articles in group through the {\bf expiry}
+    process.\\
+    C-c M-C-x & Run all articles in all groups through the {\bf expiry} process.\\
+    C-c M-g & Activate all {\bf groups}.\\
+    C-c C-i & Gnus online-manual ({\bf info}).\\
+    C-x C-t & {\bf Transpose} two groups.\\
+    H f     & Fetch this group's {\bf FAQ} (using ange-ftp).\\
+    H c     & Display this group's {\bf charter}. [Prefix: query for group]\\
+    H C     & Display this group's {\bf control message} (using
+    ange-ftp). [Prefix: query for group]\\
+    H v     & (V) Display the Gnus {\bf version} number.\\
+    H d     & (C-c C-d) Show the {\bf description} of this group
+    [Prefix: re-read from server].\\
+    M-d     & {\bf Describe} all groups. [Prefix: re-read from server]\\
+    D g     & Regenerate a Sieve script from group parameters.\\
+    D u     & Regenerate Sieve script and {\bf upload} to server.\\
+  \end{keys}
+  }
+
+\newcommand{\ListGroups}{%
+  {\esamepage
+    \begin{keys}{A M}
+      A d     & (C-c C-M-a) List all groups whose names or {\bf descriptions} match a regexp.\\
+      A k     & (C-c C-l) List all {\bf killed} groups.
+      [Prefix: look at active-file from server]\\
+      A l     & List all groups on a specific level.
+      [Prefix: also list groups with no unread articles]\\
+      A a     & (C-c C-a) List all groups whose names match a regexp
+      ({\bf apropos}).\\
+      A A     & List the server's active-file.\\
+      A M     & List groups that {\bf match} a regexp.\\
+      A m     & List groups that {\bf match} a regexp and have unread articles.
+      [level]\\
+      A s     & (l) List all {\bf subscribed} groups with unread articles.
+      [level; 5 and lower is the default]\\
+      A u     & (L) List all groups (including read and {\bf unsubscribed}).
+      [level; 7 and lower is the default]\\
+      A z     & List all {\bf zombie} groups.\\
+      A c     & List all groups with cached articles. [level]\\
+      A ?     & List all groups with dormant articles. [level]\\
+    \end{keys}
+  }
+
+  \newcommand{\CreateEditGroups}{%
+    {\esamepage
+      The select methods are indicated in parentheses.\\*
+      \begin{keys}{G DEL}
+        G a     & Make the Gnus list {\bf archive} group. (nndir over ange-ftp)\\
+        G c     & {\bf Customize} this group's parameters.\\
+        G d     & Make a {\bf directory} group (every file must be a posting and files
+        must have numeric names). (nndir)\\
+        G D     & Enter a {\bf directory} as a (temporary) group.
+        (nneething without recording articles read)\\
+        G e     & (M-e) {\bf Edit} this group's select method.\\
+        G E     & {\bf Edit} this group's info (select method, articles read, etc).\\
+        G f     & Make a group based on a {\bf file}. (nndoc)\\
+        G h     & Make the Gnus {\bf help} (documentation) group. (nndoc)\\
+        G k     & Make a {\bf kiboze} group. (nnkiboze)\\
+        G m     & {\bf Make} a new group.\\
+        G p     & Edit this group's {\bf parameters}.\\
+        G r     & Rename this group (does not work with read-only groups!).\\
+        G u     & Create one of the groups mentioned in gnus-{\bf useful}-groups.\\
+        G v     & Add this group to a {\bf virtual} group. [p/p]\\
+        G V     & Make a new empty {\bf virtual} group. (nnvirtual)\\
+        G w     & Create ephemeral group based on web-search. [Prefix: make solid group
+        instead]\\
+        G R     & Make an {\bf RSS} group.\\
+        G DEL   & {\bf Delete} group [Prefix: delete all articles as well].\\
+        G x     & Expunge all deleted articles in an nnimap mailbox.\\
+        G l     & Edit ACL (Access Control {\bf List}) for an nnimap mailbox.\\
+      \end{keys}
+      You can also create mail-groups and read your mail with Gnus (very useful
+      if you are subscribed to mailing lists), using one of the methods
+      nnmbox, nnbabyl, nnml, nnmh, or nnfolder. Read about it in the online info
+      (C-c C-i g Reading Mail RET).
+      }}
+
+                                % TODO:
+  \newcommand{\SoupCommands}{%
+    \begin{keys}{G s w}
+      G s b   & gnus-group-brew-soup: not documented.\\
+      G s p   & gnus-soup-pack-packet: not documented.\\
+      G s r   & nnsoup-pack-replies: not documented.\\
+      G s s   & gnus-soup-send-replies: not documented.\\
+      G s w   & gnus-soup-save-areas: not documented.\\
+    \end{keys}}
+
+  \newcommand{\MarkGroups}{%
+    \begin{keys}{M m}
+      M m     & (\#) Set the process {\bf mark} on this group. [scope]\\
+      M r     & Mark all groups matching regular expression.\\
+      M u     & (M-\#) Remove process mark from this group ({\bf unmark}).
+      [scope]\\
+      M U     & Remove the process mark from all groups (\textbf{unmark all}).\\
+      M w     & Mark all groups in the current region. [prefix: unmark]\\
+      M b     & Mark all groups in the {\bf buffer}. [prefix: unmark]\\
+    \end{keys}}
+
+  \newcommand{\GroupTopicsGeneral}{%
+    {\esamepage
+      Topics are ``categories'' for groups. Press t in the group-buffer to
+      toggle gnus-topic-mode (C-c C-i g Group Topics RET).\\*
+      \begin{keys}{C-c C-x}
+        T n     & Prompt for topic {\bf name} and create it.\\
+        T m     & {\bf Move} the current group to some other topic [p/p].\\
+        T j     & {\bf Jump} to a topic.\\
+        T c     & {\bf Copy} the current group to some other topic [p/p].\\
+        T D     & Remove (not delete) the current group [p/p].\\
+        T M     & {\bf Move} all groups matching a regexp to a topic.\\
+        T C     & {\bf Copy} all groups matching a regexp to a topic.\\
+        T H     & Toggle {\bf hiding} of empty topics.\\
+        T r     & {\bf Rename} a topic.\\
+        T DEL   & Delete an empty topic.\\
+        T \#    & Mark all groups in the current topic with the process-mark.\\
+        T M-\#  & Remove the process-mark from all groups in the current topic.\\
+        T TAB   & (TAB) Indent current topic [Prefix: unindent].\\
+        M-TAB   & Unindent the current topic.\\
+        RET     & (SPC) Either unfold topic or enter group [level].\\
+        T s     & {\bf Show} the current topic. [Prefix: show permanently]\\
+        T h     & {\bf Hide} the current topic. [Prefix: hide permanently]\\
+        C-c C-x & Expire all articles in current group or topic.\\
+        C-k     & {\bf Kill} a group or topic.\\
+        C-y     & {\bf Yank} a group or topic.\\
+        A T     & List active-file using {\bf topics}.\\
+        G p     & Edit topic-{\bf parameters}.\\
+        T M-n   & Go to {\bf next} topic. [distance]\\
+        T M-p   & Go to {\bf previous} topic. [distance]\\
+      \end{keys}
+      }
+    }
+
+  \newcommand{\TopicSorting}{%
+    {\esamepage
+      \begin{keys}{T S m}
+        T S a  & Sort {\bf alphabetically}.\\
+        T S u  & Sort by number of {\bf unread} articles.\\
+        T S l  & Sort by group {\bf level}.\\
+        T S v  & Sort by group score ({\bf value}).\\
+        T S r  & Sort by group {\bf rank}.\\
+        T S m  & Sort by {\bf method}.\\
+        T S e  & Sort by {\bf server} name.\\
+        T S s  & Sort according to `gnus-group-sort-function'.\\
+      \end{keys}
+      With a prefix these commands will sort in reverse order.
+      }
+    }
+
+  \newcommand{\SubscribeKillYankGroups}{%
+    {\esamepage
+      \begin{keys}{S C-k}
+        S k     & (C-k) {\bf Kill} this group.\\
+        S l     & Set the {\bf level} of this group. [p/p]\\
+        S s     & (U) Prompt for a group and toggle its {\bf subscription}.\\
+        S t     & (u) {\bf Toggle} subscription to this group. [p/p]\\
+        S w     & (C-w) Kill all groups in the region.\\
+        S y     & (C-y) {\bf Yank} the last killed group.\\
+        S z     & Kill all {\bf zombie} groups.\\
+        S C-k   & Kill all groups on a certain level.\\
+      \end{keys}
+      }
+    }
+
+  \newcommand{\SummaryModeGeneral}{%
+    {\esamepage
+      \begin{keys}{M-RET}
+        SPC     & (A SPC, A n) Select an article, scroll it one page, move to the
+        next one.\\
+        DEL     & (A DEL, A p, b) Scroll this article one page back. [distance]\\
+        RET     & (A RET) Scroll this article one line forward. [distance]\\
+        M-RET   & (A M-RET) Scroll this article one line backward. [distance]\\
+        =       & Expand the Summary window (fullsize).
+        [Prefix: shrink to display article window]\\
+                                %
+        \&      & Execute a command on all articles whose header matches a regexp.
+        [Prefix: move backwards]\\
+        M-\&    & Execute a command on all articles having the process mark.\\
+                                %
+        M-n     & (G M-n) Go to {\bf next} summary line of unread article.
+        [distance]\\
+        M-p     & (G M-p) Go to {\bf previous} summary line of an unread article.
+        [distance]\\
+        M-s     & {\bf Search} through all subsequent articles for a regexp.\\
+        M-r     & Search through all previous articles for a regexp.\\
+                                %
+        A P     & {\bf Postscript}-print current buffer.\\
+                                %
+        M-k     & Edit this group's {\bf kill} file.\\
+        M-K     & Edit the general {\bf kill} file.\\
+                                %
+        C-t     & Toggle {\bf truncation} of summary lines.\\
+        Y g     & Regenerate the summary-buffer.\\
+        Y c     & Insert all cached articles into the summary-buffer.\\
+                                %
+        M-C-e   & {\bf Edit} the group-parameters.\\
+        M-C-a   & Customize the group-parameters.\\
+                                %
+                                % article handling
+                                %
+        A $<$   & ($<$, A b) Scroll to the beginning of this article.\\
+        A $>$   & ($>$, A e) Scroll to the end of this article.\\
+        A s     & (s) Perform an i{\bf search} in the article buffer.\\
+                                %
+        A D     & (C-d) Un{\bf digestify} this article into a separate group.
+        [Prefix: force digest]\\
+        M-C-d   & Like C-d, but open several documents in nndoc-groups, wrapped
+        in an nnvirtual group [p/p]\\
+                                %
+        A g     & (g) (Re)fetch this article ({\bf get}). [Prefix: get raw version]\\
+        A r     & (\^{}, A \^{}) Fetch the parent(s) of this article.
+        [Prefix: if positive fetch \textit{n} ancestors;
+        negative: fetch only the \textit{n}th ancestor]\\
+        A t     & {\bf Translate} this article.\\
+        A R     & Fetch all articles mentioned in the {\bf References}-header.\\
+        A T     & Fetch full \textbf{thread} in which the current article appears.\\
+        M-\^{}  & Fetch the article with a given Message-ID.\\
+        S y     & {\bf Yank} the current article into an existing message-buffer.
+        [p/p]\\
+        A M     & Setup group parameters for {\bf mailing} lists from
+        headers. [Prefix: replace old settings]\\
+      \end{keys}
+      }
+    }
+
+  \newcommand{\MIMESummary}{%
+    {\esamepage
+      For the commands operating on one MIME part (a subset of gnus-article-*), a
+      prefix selects which part to operate on. If the point is placed over a
+      MIME button in the article buffer, use the corresponding bindings for the
+      article buffer instead.
+
+      \begin{keys}{W M w}
+        K v      & (b, W M b) {\bf View} the MIME-part.\\
+        K o      & {\bf Save} the MIME part.\\
+        K c      & {\bf Copy} the MIME part.\\
+        K e      & View the MIME part {\bf externally}.\\
+        K i      & View the MIME part {\bf internally}.\\
+        K $\mid$ & Pipe the MIME part to an external command.\\
+        K b      & Make all the MIME parts have buttons in front of them.\\
+        K m      & Try to repair {\bf multipart-headers}.\\
+        K C      & View the MIME part using a different {\bf charset}.\\
+        X m      & Save all parts matching a MIME type to a directory. [p/p]\\
+        M-t      & Toggle the buttonized display of the article buffer.\\
+        W M w    & Decode RFC2047-encoded words in the article headers.\\
+        W M c    & Decode encoded article bodies. [Prefix: prompt for charset]\\
+        W M v    & View all MIME parts in the current article.\\
+      \end{keys}
+      }
+    }
+
+  \newcommand{\SortSummary}{%
+    {\esamepage
+      \begin{keys}{C-c C-s C-a}
+        C-c C-s C-a & Sort the summary-buffer by {\bf author}.\\
+        C-c C-s C-t & Sort the summary-buffer by {\bf recipient}.\\
+        C-c C-s C-d & Sort the summary-buffer by {\bf date}.\\
+        C-c C-s C-i & Sort the summary-buffer by article score.\\
+        C-c C-s C-l & Sort the summary-buffer by amount of {\bf lines}.\\
+        C-c C-s C-c & Sort the summary-buffer by length.\\
+        C-c C-s C-n & Sort the summary-buffer by article {\bf number}.\\
+        C-c C-s C-s & Sort the summary-buffer by {\bf subject}.\\
+        C-c C-s C-r & Sort the summary-buffer {\bf randomly}.\\
+        C-c C-s C-o & Sort the summary-buffer using the default method.\\
+      \end{keys}
+      With a prefix these functions sort in reverse order.
+      }
+    }
+
+  \newcommand{\MailGroups}{% formerly \Bsubmap
+    {\esamepage
+      These commands (except `B c') are only valid in a mail group.\\*
+      \begin{keys}{B M-C-e}
+        B DEL   & (B backspace, B delete) {\bf Delete} the mail article from disk (!).
+        [p/p]\\
+        B B     & Crosspost this article to another group.\\
+        B c     & {\bf Copy} this article from any group to a mail group. [p/p]\\
+        B e     & {\bf Expire} all expirable articles in this group. [p/p]\\
+        B i     & {\bf Import} a random file into this group.\\
+        B I     & Create an empty article in this group.\\
+        B m     & {\bf Move} the article from one mail group to another. [p/p]\\
+        B p     & Query whether the article was {\bf posted} as well.\\
+        B q     & {\bf Query} where the article will end up after fancy splitting\\
+        B r     & {\bf Respool} this mail article. [p/p]\\
+        B t     & {\bf Trace} the fancy splitting patterns applied to this article.\\
+        B w     & (e) Edit this article.\\
+        B M-C-e & {\bf Expunge} (delete from disk) all expirable articles in this group
+        (!). [p/p]\\
+        K E     & {\bf Encrypt} article body. [p/p]\\
+      \end{keys}
+      }
+    }
+
+  \newcommand{\DraftGroup}{% formerly \Dsubmap
+    {\esamepage
+      The ``drafts''-group contains messages that have been saved but not sent
+      and rejected articles. \\*
+      \begin{keys}{B DEL}
+        D e      & \textbf{edit} message.\\
+        D s      & \textbf{Send} message. [p/p]\\
+        D S      & \textbf{Send} all messages.\\
+        D t      & \textbf{Toggle} sending (mark as unsendable).\\
+        B DEL    & \textbf{Delete} message (like in mailgroup).\\
+      \end{keys}
+      }
+    }
+
+  \newcommand{\SelectArticles}{% formerly \Gsubmap
+    {\esamepage
+      These commands select the target article. They do not use the prefix.\\*
+      \begin{keys}{G C-n}
+        h       & Enter article-buffer.\\
+        G b     & (,) Go to the {\bf best} article (the one with highest score).\\
+        G f     & (.) Go to the {\bf first} unread article.\\
+        G n     & (n) Go to the {\bf next} unread article.\\
+        G p     & (p) Go to the {\bf previous} unread article.\\
+                                %
+        G N     & (N) Go to {\bf the} next article.\\
+        G P     & (P) Go to the {\bf previous} article.\\
+                                %
+        G C-n   & (M-C-n) Go to the {\bf next} article with the same subject.\\
+        G C-p   & (M-C-p) Go to the {\bf previous} article with the same subject.\\
+                                %
+        G l     & (l) Go to the previously read article ({\bf last-read-article}).\\
+        G o     & Pop an article off the summary history and go to it.\\
+                                %
+        G g     & Search an article via subject.\\
+        G j     & (j) Search an article via Message-Id or subject.\\
+      \end{keys}
+      }
+    }
+
+  \newcommand{\ArticleModeGeneral}{%
+    {\esamepage
+      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.\\
+        h       & Go to the \textbf{header}-line of the article in the
+        summary-buffer.\\
+        s       & Go to \textbf{summary}-buffer.\\
+        RET     & (middle mouse button) Activate the button at point to follow
+        an URL or Message-ID.\\
+        TAB     & Move the point to the next button.\\
+        M-TAB   & Move point to previous button.\\
+      \end{keys}
+      }
+    }
+
+  \newcommand{\WashArticle}{% formerly \Wsubmap
+    {\esamepage
+      \begin{keys}{W W H}
+        W 6     & Translate a base64 article.\\
+        W a     & Strip certain {\bf headers} from body.\\
+        W b     & Make Message-IDs and URLs in the article mouse-clickable
+        {\bf buttons}.\\
+        W c     & Translate CRLF-pairs to LF and then remaining CR's to LF's.\\
+        W d     & Treat {\bf dumbquotes}.\\
+        W e     & Treat {\bf emphasized} text.\\
+        W h     & Treat {\bf HTML}.\\
+        W l     & (w) Remove page breaks ({\bf\^{}L}) from the article.\\
+        W m     & {\bf Morse} decode article.\\
+        W o     & Treat {\bf overstrike} or underline (\^{}H\_) in the article.\\
+        W p     & Verify X-{\bf PGP}-Sig header.\\
+        W q     & Treat {\bf quoted}-printable in the article.\\
+        W r     & (C-c C-r) Do a Caesar {\bf rotate} (rot13) on the article.\\
+        W s     & Verify (and decrypt) a {\bf signed} message.\\
+        W t     & (t) {\bf Toggle} display of all headers.\\
+        W u     & {\bf Unsplit} broken URLs.\\
+        W v     & (v) Toggle permanent {\bf verbose} displaying of all headers.\\
+        W w     & Do word {\bf wrap} in the article.\\
+        W B     & Add clickable {\bf buttons} to the article headers.\\
+        W C     & {\bf Capitalize} first word in each sentence.\\
+        W Q     & Fill long lines.\\
+        W Z     & Translate a HZ-encoded article.\\
+                                %
+        W G u   & {\bf Unfold} folded header lines.\\
+        W G f   & {\bf Fold} all header lines.\\
+        W G n   & Unfold {\bf Newsgroups:} and Follow-Up-To:.\\
+                                %
+        W Y c   & Repair broken {\bf citations}.\\
+        W Y a   & Repair broken {\bf attribution} lines.\\
+        W Y u   & {\bf Unwrap} broken citation lines.\\
+        W Y f   & Do a {\bf full} deuglification (W Y c, W Y a, W Y u).\\
+      \end{keys}
+      }
+    }
+
+  \newcommand{\BlankAndWhitespace}{%
+    {\esamepage
+      \begin{keys}{W E w}
+        W E l   & Strip blank {\bf lines} from the beginning of the article.\\
+        W E m   & Replace blank lines with empty lines and remove {\bf multiple}
+        blank lines.\\
+        W E t   & Remove {\bf trailing} blank lines.\\
+        W E a   & Strip blank lines at start and end
+        (W E l, W E m and W E t).\\
+        W E A   & Strip {\bf all} blank lines.\\
+        W E s   & Strip leading blank lines from the article body.\\
+        W E e   & Strip trailing blank lines from the article body.\\
+        W E w   & Remove leading {\bf whitespace} from all headers.\\
+      \end{keys}
+      }
+    }
+
+  \newcommand{\Picons}{%
+    {\esamepage
+      \begin{keys}{W D D}
+        W D s   & (W g) Display {\bf smilies}.\\
+        W D x   & (W f) Look for and display any X-{\bf Face} headers.\\
+        W D d   & Display any Face headers.\\
+        W D n   & Toggle picons in {\bf Newsgroups} and Followup-To.\\
+        W D m   & Toggle picons in {\bf mail} headers (To and Cc).\\
+        W D f   & Toggle picons in {\bf From}.\\
+        W D D   & Remove all images from the article buffer.\\
+      \end{keys}
+      }
+    }
+
+  \newcommand{\TimeAndDate}{%
+    {\esamepage
+      \begin{keys}{W T u}
+        W T u   & (W T z) Display the article timestamp in GMT ({\bf UT, ZULU}).\\
+        W T i   & Display the article timestamp in {\bf ISO} 8601.\\
+        W T l   & Display the article timestamp in the {\bf local} timezone.\\
+        W T s   & Display according to `gnus-article-time-format'.\\
+        W T e   & Display the time {\bf elapsed} since it was sent.\\
+        W T o   & Display the {\bf original} timestamp.\\
+        W T p   & Display the date in format that's {\bf
+          pronounceable} in English.\\
+      \end{keys}
+      }
+    }
+
+  \newcommand{\HideHighlightArticle}{%
+    {\esamepage
+      \begin{keys}{W W C-c}
+        W W a   & Hide {\bf all} unwanted parts. Calls W W h, W W s, W W C-c.\\
+        W W h   & Hide article {\bf headers}.\\
+        W W b   & Hide {\bf boring} headers.\\
+        W W s   & Hide {\bf signature}.\\
+        W W l   & Hide {\bf list} identifiers in subject-header.\\
+        W W P   & Hide {\bf PEM} (privacy enhanced messages).\\
+        W W B   & Hide banner specified by group parameter.\\
+        W W c   & Hide {\bf citation}.\\
+        W W C-c & Hide {\bf citation} using a more intelligent algorithm.\\
+        W W C   & Hide cited text in articles that aren't roots.\\
+        W H a   & Highlight {\bf all} parts. Calls W b, W H c, W H h, W H s.\\
+        W H c   & Highlight article {\bf citations}.\\
+        W H h   & Highlight article {\bf headers}.\\
+        W H s   & Highlight article {\bf signature}.\\
+      \end{keys}
+      For all hiding-commands: A positive prefix always hides, and a negative
+      prefix will show what was previously hidden.
+      }}
+
+  \newcommand{\MIMEArticleMode}{%
+    {\esamepage
+      \begin{keys}{RET}
+        RET     & (BUTTON-2) Toggle display of the MIME object.\\
+        v       & Prompt for a method and then view object using this method.\\
+        o       & Prompt for a filename and save the MIME object.\\
+        C-o     & Prompt for a filename to save the MIME object to and remove it.\\
+        d       & {\bf Delete} the MIME object.\\
+        c       & {\bf Copy} the MIME object to a new buffer and display this buffer.\\
+        i       & Display the MIME object in this buffer.\\
+        C       & Copy the MIME object to a new buffer and display this buffer using {\bf Charset} \\
+        E       & View internally. \\
+        e       & View {\bf externally}. \\
+        t       & View the MIME object as a different {\bf type}.\\
+        p       & {\bf Print} the MIME object.\\
+        $\mid$  & Pipe the MIME object to a process.\\
+        .       & Take action on the MIME object.\\
+      \end{keys}
+      }
+    }
+
+  %% end of article mode for reading ..........................................
+
+  \newcommand{\MarkArticlesGeneral}{% formerly \Msubmap
+    {\esamepage
+      \begin{keys}{M M-C-r}
+        d       & (M d, M r) Mark this article as read and move to the next one.
+        [scope]\\
+        D       & Mark this article as read and move to previous one. [scope]\\
+        !       & (u, M !, M t) Tick this article (mark it as interesting) and move
+        to the next one. [scope]\\
+        U       & Tick this article and move to the previous one. [scope]\\
+        M ?     & (?) Mark this article as dormant (only followups are
+        interesting). [scope]\\
+        M D     & Show all {\bf dormant} articles (normally they are hidden unless they
+        have any followups).\\
+        M M-D   & Hide all {\bf dormant} articles.\\
+        C-w     & Mark all articles between point and mark as read.\\
+        M-u     & (M SPC, M c) Clear all marks from this article and move to the next
+        one. [scope]\\
+        M-U     & Clear all marks from this article and move to the previous one.
+        [scope]\\
+                                %
+        M e     & (E, M x) Mark this article as {\bf expirable}. [scope]\\
+                                %
+        M k     & (k) {\bf Kill} all articles with same subject, select
+        next unread one.\\
+        M K     & (C-k) {\bf Kill} all articles with the same subject as this one.\\
+                                %
+        M C     & {\bf Catch-up} the articles that are not ticked and not dormant.\\
+        M C-c   & {\bf Catch-up} all articles in this group.\\
+        M H     & {\bf Catch-up} (mark read) this group to point (to-{\bf here}).\\
+                                %
+        M b     & Set a {\bf bookmark} in this article.\\
+        M B     & Remove the {\bf bookmark} from this article.\\
+                                %
+        M M-r   & (x) Expunge all {\bf read} articles from this group.\\
+        M M-C-r & Expunge all articles having a given mark.\\
+        M S     & (C-c M-C-s) {\bf Show} all expunged articles.\\
+        M M C-h & Displays some more keys doing ticking slightly differently.\\
+      \end{keys}
+      The variable `gnus-summary-goto-unread' controls what happens after a mark
+      has been set (C-x C-i g Setting Marks RET)
+      }}
+
+  \newcommand{\MarkByScore}{%
+    \begin{keys}{M V m}
+      M V c   & {\bf Clear} all marks from all high-scored articles. [score]\\
+      M V k   & {\bf Kill} all low-scored articles. [score]\\
+      M V m   & Mark all high-scored articles with a given {\bf mark}. [score]\\
+      M V u   & Mark all high-scored articles as interesting (tick them). [score]\\
+    \end{keys}
+    }
+  }
+
+\newcommand{\ProcessMark}{%
+  {\esamepage
+    These commands set and remove the process mark (\#). You only need to use
+    it if the set of articles you want to operate on is non-contiguous. Else
+    use a numeric prefix.\\*
+    \begin{keys}{M P R}
+      M P p   & (\#, M \#) Mark this article.\\
+      M P u   & (M-\#, M M-\#) \textbf{unmark} this article.\\
+      M P b   & Mark all articles in {\bf buffer}.\\
+      M P r   & Mark all articles in the {\bf region}.\\
+      M P g   & Unmark all articles in the region.\\
+      M P R   & Mark all articles matching a {\bf regexp}.\\
+      M P G   & Unmark all articles matching a regexp.\\
+      M P t   & Mark all articles in this (sub){\bf thread}.\\
+      M P T   & Unmark all articles in this (sub){\bf thread}.\\
+      M P s   & Mark all articles in the current {\bf series}.\\
+      M P S   & Mark all {\bf series} that already contain a marked article.\\
+      M P a   & Mark {\bf all} articles (in series order).\\
+      M P U   & \textbf{unmark} all articles.\\
+      M P i   & {\bf Invert} the list of process-marked articles.\\
+      M P k   & Push process-mark set onto stack and unmark
+      all articles.\\
+      M P y   & Pop process-mark set from stack and restore it.\\
+      M P w   & Push process-mark set on the stack.\\
+      M P v   & Mark all articles with score over default score. [Prefix: score]\\
+    \end{keys}
+    }
+  }
+
+\newcommand{\Limiting}{%
+  {\esamepage
+    \begin{keys}{/M}
+      //   & (/s) Limit the summary-buffer to articles matching {\bf subject}.\\
+      /a   & Limit the summary-buffer to articles matching {\bf author}.\\
+      /R   & Limit the summary-buffer to articles matching {\bf recipient}.\\
+      /x   & Limit depending on ``extra'' headers.\\
+      /u   & (x) Limit to {\bf unread} articles.
+      [Prefix: also exclude ticked and dormant articles]\\
+      /.   & Limit to unseen articles.\\
+      /m   & Limit to articles marked with specified {\bf mark}.\\
+      /t   & Ask for a number and exclude articles younger than that many days.
+      [Prefix: exclude older articles]\\
+      /n   & Limit to current article. [p/p]\\
+      /w   & Pop previous limit off stack and restore it.
+      [Prefix: pop all limits]\\
+      /v   & Limit to score. [score]\\
+      /E   & (M S) Include all expunged articles in the limit.\\
+      /D   & Include all dormant 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.\\
+      /c   & Exclude all dormant articles that have no children from the limit.\\
+      /C   & Mark all excluded unread articles as read.
+      [Prefix: also mark ticked and dormant articles]\\
+      /o   & Insert all {\bf old} articles. [Prefix: how many]\\
+      /N   & Insert all {\bf new} articles.\\
+      /p   & Limit to articles {\bf predicated} in the `display' group parameter.\\
+      /r   & Limit to {\bf replied} articles. [Prefix: unreplied]\\
+    \end{keys}
+    }
+  }
+
+\newcommand{\OutputArticles}{% formerly \Osubmap
+  {\esamepage
+    \begin{keys}{O m}
+      O o     & (o, C-o) Save this article using the default article saver. [p/p]\\
+      O b     & Save this article's {\bf body} in plain file format [p/p]\\
+      O f     & Save this article in plain {\bf file} format. [p/p]\\
+      O F     & like O f, but overwrite file's contents. [p/p]\\
+      O h     & Save this article in {\bf mh} folder format. [p/p]\\
+      O m     & Save this article in {\bf mail} format. [p/p]\\
+      O r     & Save this article in {\bf rmail} format. [p/p]\\
+      O v     & Save this article in {\bf vm} format. [p/p]\\
+      O p     & ($\mid$) {\bf Pipe} this article to a shell command. [p/p]\\
+      O P     & \textbf{Print} this article using Muttprint. [p/p]\\
+    \end{keys}
+    }
+  }
+
+\newcommand{\PostReplyetc}{% formerly \Ssubmap
+  {\esamepage
+    These commands put you in a separate news or mail buffer. See the section
+    about composing messages for more information.\\*
+                                %After
+                                %editing the article, send it by pressing C-c C-c.  If you are in a
+                                %foreign group and want to post the article using the foreign server, give
+                                %a prefix to C-c C-c.\\*
+    \begin{keys}{S O m}
+      S p     & (a) {\bf Post} an article to this group.\\
+      S f     & (f) Post a {\bf followup} to this article.\\
+      S F     & (F) Post a {\bf followup} and include the original. [p/p]\\
+      S o p   & Forward this article as a {\bf post} to a newsgroup.\\
+      S M-c   & Complain about excessive crossposting to
+      article's author. [p/p]\\
+                                %
+      S m     & (m) Send a {\bf mail} to some other person.\\
+      S r     & (r) Mail a {\bf reply} to the author of this article.\\
+      S R     & (R) Mail a {\bf reply} and include the original. [p/p]\\
+      S B r   & Like S r but ignore the Reply-To: header.\\
+      S B R   & Like S R but ignore the Reply-To: header.\\
+      S w     & Mail a {\bf wide} reply to this article.\\
+      S W     & Mail a {\bf wide} reply to this article and include
+      the original.\\
+      S v     & Mail a {\bf very} wide reply to this article.\\
+      S V     & Mail a {\bf very} wide reply to this article and include the original.\\
+      S o m   & (C-c C-f) Forward this article by {\bf mail} to a person.\\
+      S D b   & Resend {\bf bounced} mail.\\
+      S D r   & {\bf Resend} mail to a different person.\\
+      S D e   & {\bf Edit} and resend.\\
+                                %
+      S n     & Post a followup via {\bf news} even if you got the message
+      through mail.\\
+      S N     & Post a followup via {\bf news} and include the original mail.
+      [p/p]\\
+                                %
+      S c     & (C) {\bf Cancel} this article (only works if it is
+      your own). [p/p]\\
+      S s     & {\bf Supersede} this article with a new one (only for own
+      articles).\\
+                                %
+      S O m   & Digest these series and forward by {\bf mail}. [p/p]\\
+      S O p   & Digest these series and forward as a {\bf post} to a newsgroup.
+      [p/p]\\
+                                %
+      S u     & {\bf Uuencode} a file and post it as a series.\\
+    \end{keys}
+    If you want to cancel or supersede an article you just posted (before it
+    has appeared on the server), go to the *post-news* buffer, change
+    `Message-ID' to `Cancel' or `Supersedes' and send again with C-c C-c.
+    }}
+
+\newcommand{\Threading}{% formerly \Tsubmap
+  {\esamepage
+    \begin{keys}{T M-\#}
+      T \#    & Mark this thread with the process mark.\\
+      T M-\#  & Remove process-marks from this thread.\\
+                                %
+      T t     & Re-{\bf thread} the current article's thread.\\
+      T \^{}  & Make the current article child of the marked (or previous) one.\\
+                                % movement
+      T n     & (M-C-f, M-down) Go to the {\bf next} thread. [distance]\\
+      T p     & (M-C-b, M-up) Go to the {\bf previous} thread. [distance]\\
+      T d     & {\bf Descend} this thread. [distance]\\
+      T u     & Ascend this thread ({\bf up}-thread). [distance]\\
+      T o     & Go to the top of this thread.\\
+                                %
+      T s     & {\bf Show} the thread hidden under this article.\\
+      T h     & {\bf Hide} this (sub)thread.\\
+                                %
+      T i     & {\bf Increase} the score of this thread.\\
+      T l     & (M-C-l) {\bf Lower} the score of this thread.\\
+                                %
+      T k     & (M-C-k) {\bf Kill} the current (sub)thread. [Negative prefix:
+      tick it, positive prefix: unmark it.]\\
+                                %
+      T H     & {\bf Hide} all threads.\\
+      T S     & {\bf Show} all hidden threads.\\
+      T T     & (M-C-t) {\bf Toggle} threading.\\
+    \end{keys}
+    }
+  }
+
+\newcommand{\Scoring}{% formerly \Vsubmap
+  {\esamepage
+    Read about Adaptive Scoring in the online info.\\*
+    \begin{keys}{\bf A p m l}
+      V a     & {\bf Add} a new score entry, specifying all elements.\\
+      V c     & Specify a new score file as {\bf current}.\\
+      V e     & {\bf Edit} the current score alist.\\
+      V f     & Edit a score {\bf file} and make it the current one.\\
+      V m     & {\bf Mark} all articles below a given score as read.\\
+      V s     & Set the {\bf score} of this article.\\
+      V t     & Display all score rules applied to this article ({\bf track}).\\
+      W w     & List {\bf words} used in scoring.\\
+      V x     & {\bf Expunge} all low-scored articles. [score]\\
+      V C     & {\bf Customize} current score file with a user-friendly
+      interface.\\
+      V F     & {\bf Flush} the cache of score files.\\
+      V R     & {\bf Re-score} the summary buffer.\\
+      V S     & Display the {\bf score} of this article.\\
+      \bf A p m l& Make a scoring entry based on this article.\\
+    \end{keys}
+    The four letters stand for:\\*
+    \quad \B{A}ction: I)ncrease, L)ower;\\*
+    \quad \B{p}art: a)uthor (from), s)ubject, x)refs (cross-post), d)ate, l)ines,
+    message-i)d, t)references (parent), f)ollowup, b)ody, h)ead (all headers);\\*
+    \quad \B{m}atch type:\\*
+    \qquad string: s)ubstring, e)xact, r)egexp, f)uzzy,\\*
+    \qquad date: b)efore, a)t, n)this,\\*
+    \qquad number: $<$, =, $>$;\\*
+    \quad \B{l}ifetime: t)emporary, p)ermanent, i)mmediate.
+
+    If you type the second letter in uppercase, the remaining two are assumed
+    to be s)ubstring and t)emporary.
+    If you type the third letter in uppercase, the last one is assumed to be
+    t)emporary.
+
+    \quad Extra keys for manual editing of a score file:\\*
+    \begin{keys}{C-c C-c}
+      C-c C-c & Finish editing the score file.\\
+      C-c C-d & Insert the current {\bf date} as number of days.\\
+    \end{keys}
+    }
+  }
+
+\newcommand{\ExtractSeries}{% formerly \Xsubmap
+  {\esamepage
+    Gnus recognizes if the current article is part of a series (multipart
+    posting whose parts are identified by numbers in their subjects, e.g.{}
+    1/10\dots10/10) and processes the series accordingly. You can mark and
+    process more than one series at a time. If the posting contains any
+    archives, they are expanded and gathered in a new group.\\*
+    \begin{keys}{X p}
+      X b     & Un-{\bf binhex} these series. [p/p]\\
+      X o     & Simply {\bf output} these series (no decoding). [p/p]\\
+      X p     & Unpack these {\bf postscript} series. [p/p]\\
+      X s     & Un-{\bf shar} these series. [p/p]\\
+      X u     & {\bf Uudecode} these series. [p/p]\\
+    \end{keys}
+
+    Each one of these commands has four variants:\\*
+    \begin{keys}{X v \bf Z}
+      X   \bf z & Decode these series. [p/p]\\
+      X   \bf Z & Decode and save these series. [p/p]\\
+      X v \bf z & Decode and view these series. [p/p]\\
+      X v \bf Z & Decode, save and view these series. [p/p]\\
+    \end{keys}
+    where {\bf z} or {\bf Z} identifies the decoding method (b, o, p, s, u).
+
+    An alternative binding for the most-often used of these commands is\\*
+    \begin{keys}{C-c C-v C-v}
+      C-c C-v C-v & (X v u) Uudecode and view these series. [p/p]\\
+    \end{keys}
+    }}
+
+\newcommand{\ExitSummary}{% formerly \Zsubmap
+  {\esamepage
+    \begin{keys}{Z G}
+      Z Z     & (q, Z Q) Exit this group.\\
+      Z E     & (Q) {\bf Exit} without updating the group information.\\
+                                %
+      Z c     & (c) Mark all unticked articles as read ({\bf catch-up}) and exit.\\
+      Z C     & Mark all articles as read ({\bf catch-up}) and exit.\\
+                                %
+      Z n     & Mark all articles as read and go to the {\bf next} group.\\
+      Z N     & Exit and go to {\bf the} next group.\\
+      Z P     & Exit and go to the {\bf previous} group.\\
+                                %
+      Z G     & (M-g) Check for new articles in this group ({\bf get}).\\
+      Z R     & (C-x C-s) Exit this group, and then enter it again ({\bf reenter}).
+      [Prefix: select all articles, read and unread.]\\
+      Z s     & Update and save the dribble buffer. [Prefix: save .newsrc* as well]\\
+    \end{keys}
+    }
+  }
+
+\newcommand{\MsgCompositionGeneral}{%
+  Press C-c ? in the composition-buffer to get this information.\\*
+  {\esamepage
+    \begin{keys}{C-c C-m}
+                                % sending
+      C-c C-c & Send message and exit. [Prefix: send via foreign server]\\
+      C-c C-s & Send message. [Prefix: send via foreign server]\\
+      C-c C-d & Don't send message (save as \textbf{draft}).\\
+      C-c C-k & \textbf{Kill} message-buffer.\\
+      C-c C-m & {\bf Mail} reply to the address near point.
+      [Prefix: include the original]\\
+                                % modify headers/body
+      C-c C-o & Sort headers.\\
+      C-c C-e & \textbf{Elide} region.\\
+      C-c C-v & Kill everything outside region.\\
+      C-c C-r & Do a \textbf{Rot-13} on the body.\\
+      C-c C-w & Insert signature (from `message-signature-file').\\
+      C-c C-z & Kill everything up to signature.\\
+      C-c C-y & \textbf{Yank} original message.\\
+      C-c C-q & Fill the yanked message.\\
+      C-c M-C-y & \textbf{Yank} a buffer and quote it.\\
+      M-RET   & Insert four newlines and format quoted text. [Prefix:
+      justify as well]\\
+      C-c M-r & \textbf{Rename} message buffer. [Prefix: ask for new name]\\
+    \end{keys}
+    }
+  }
+
+\newcommand{\MsgCompositionMovementArticle}{%
+  The following functions create the header-field if necessary.\\*
+  {\esamepage
+    \begin{keys}{C-c C-f C-u}
+      C-c TAB & Move to \textbf{signature}.\\
+      C-c C-b & Move to \textbf{body}.\\
+      C-c C-f C-t & (C-c C-t) Move to \textbf{To:}.\\
+      C-c C-f C-c & Move to \textbf{Cc:}.\\
+      C-c C-f C-b & Move to \textbf{Bcc:}.\\
+      C-c C-f C-w & Move to \textbf{Fcc:}.\\
+      C-c C-f C-s & Move to \textbf{Subject:}.\\
+      C-c C-f C-r & Move to \textbf{Reply-To:}.\\
+      C-c C-f C-f & Move to \textbf{Followup-To:}.\\
+      C-c C-f C-n & (C-c C-n) Move to \textbf{Newsgroups:}.\\
+      C-c C-f C-u & Move to \textbf{Summary:}.\\
+      C-c C-f C-k & Move to \textbf{Keywords:}.\\
+      C-c C-f C-d & Move to \textbf{Distribution:}.\\
+      C-c C-f C-m & Move to \textbf{Mail-Followup-To:}.\\
+      C-c C-f C-o & Move to \textbf{From:}.\\
+      C-c C-f C-a & Insert a reasonable \textbf{Mail-Followup-To:} for
+      an unsubscribed list. [Prefix: include addresses in \textbf{Cc:}]\\
+      C-c C-f TAB & (C-c C-u) Move to \textbf{Importance:}.\\
+      C-c M-n     & Insert \textbf{Disposition-Notification-To:}
+      (request receipt).\\
+    \end{keys}
+    }
+  }
+
+\newcommand{\MsgCompositionMML}{%
+  {\esamepage
+    \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). [Prefix: show raw MIME preview]\\
+      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.\\
+      C-c C-m c s & Encrypt message using \textbf{S/MIME}.\\
+      C-c C-m c o & Encrypt message using PGP.\\
+      C-c C-m c p & Encrypt message using \textbf{PGP/MIME}.\\
+      C-c C-m s s & Sign message using \textbf{S/MIME}.\\
+      C-c C-m s o & Sign message using PGP.\\
+      C-c C-m s p & Sign message using \textbf{PGP/MIME}.\\
+      C-c C-m C-n & Remove security related MML tags from message.\\
+                                % TODO: narrow headers (C-c C-m n) ?
+    \end{keys}
+    }
+  }
+
+%% TODO:
+\newcommand{\ServerMode}{%
+  {\esamepage
+    To enter this mode, press \^{} while in Group mode.\\*
+    \begin{keys}{SPC}
+      SPC     & (RET) Browse this server.\\
+      a       & {\bf Add} a new server.\\
+      c       & {\bf Copy} this server.\\
+      e       & {\bf Edit} a server.\\
+      k       & {\bf Kill} this server. [scope]\\
+      l       & {\bf List} all servers.\\
+      q       & Return to the group buffer ({\bf quit}).\\
+      s       & Request that the server scan its sources for new articles.\\
+      g       & Request that the server regenerate its data.\\
+      y       & {\bf Yank} the previously killed server.\\
+      O       & Try to {\bf open} a connection to this server.\\
+      C       & {\bf Close} connection to this server.\\
+      D       & Mark this server as unreachable ({\bf deny}).\\
+      M-o     & {\bf Open} the connection to all servers.\\
+      M-c     & {\bf Close} the connection to all servers.\\
+      R       & Make all denied servers into closed servers.\\
+      L       & Set server status to offline.\\
+    \end{keys}
+    }
+  }
+
+\newcommand{\BrowseServer}{%
+  {\esamepage
+    To enter this mode, press `B' while in Group mode.\\*
+    \begin{keys}{RET}
+      RET     & Enter the current group.\\
+      SPC     & Enter the current group and display the first article.\\
+      ?       & Give a very short help message.\\
+      n       & Go to the {\bf next} group. [distance]\\
+      p       & Go to the {\bf previous} group. [distance]\\
+      q       & (l) {\bf Quit} browse mode.\\
+      u       & Subscribe to the current group. [scope]\\
+    \end{keys}
+    }
+  }
+
+\newcommand{\GroupUnplugged}{%
+  {\esamepage
+    \begin{keys}{J S}
+      J j & Toggle plugged-state.\\
+      J s & Fetch articles from all groups for offline-reading.\\
+      J u & Fetch all eligible articles from this group.\\
+      J S & \textbf{Send} all sendable messages in the drafts group.\\
+                                %
+      J c & Enter \textbf{category} buffer.\\
+      J a & \textbf{Add} this group to an Agent category [p/p].\\
+      J r & \textbf{Remove} this group from its Agent category [p/p].\\
+      J Y & Synchronize flags changed while unplugged with remote server.\\
+    \end{keys}
+    }
+  }
+
+\newcommand{\SummaryUnplugged}{%
+  {\esamepage
+    \begin{keys}{J M-\#}
+      J \#   & \textbf{Mark} the article for downloading.\\
+      J M-\# & \textbf{Unmark} the article for downloading.\\
+      @      & \textbf{Toggle} whether to download the article.\\
+      J c    & Mark all undownloaded articles as read (\textbf{catch-up}).\\
+      J u    & Download all downloadable articles from group.\\
+    \end{keys}
+    }
+  }
+
+\newcommand{\ServerUnplugged}{%
+  {\esamepage
+    \begin{keys}{J a}
+      J a & \textbf{Add} the current server to the list of servers covered
+      by the agent.\\
+      J r & \textbf{Remove} the current server from the list of servers covered
+      by the agent.\\
+    \end{keys}
+    }
+  }
+
+% end   {gnusref} % % % % % % % % % % % % % % % % % % % % % % % % % %
+
+
+% o some things might not be updated: scoring and server modes, maybe more
+% o Gnus Unplugged category-buffer commands need to be written
+
+\begin{document}
+
+\ifthenelse{\isundefined{\booklettrue}}{ % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  \raggedbottom\raggedright
+  \twocolumn
+  % use \tiny to shrink it to 4 pages (needs a high-resolution printer though)
+  % \tiny
+  \scriptsize
+  \pagestyle{plain}
+  \Title
+  \par
+  \Logo{refcard}
+}{
+  \setcounter{page}{0}
+  \thispagestyle{empty}
+  \vspace*{\fill}
+  \Title
+  \vspace{0.4in}
+  \Logo{booklet}
+  \vspace*{\fill}
+  \pagebreak
+}%ifbooklet% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% TODO: how does this work ?
+%\tableofcontents
+
+\Notes
+%
+
+\section*{Group-Mode}
+\GroupModeGeneral
+    \subsection*{Group Subscribedness-Levels}
+    \GroupLevels
+    \subsection*{List Groups}
+    \ListGroups
+    \subsection*{Create/Edit Foreign Groups}
+    \CreateEditGroups
+    \ifthenelse{\isundefined{\booklettrue}}{}{\pagebreak}
+    \subsection*{Unsubscribe, Kill and Yank Groups}
+    \SubscribeKillYankGroups
+    \subsection*{Mark Groups}
+    \MarkGroups
+    \subsection*{Group-Unplugged}
+    \GroupUnplugged
+% topics in group-mode
+    \subsection*{Group Topics}
+    \GroupTopicsGeneral
+    \subsubsection*{Topic Sorting}
+    \TopicSorting
+
+% \ifthenelse{\isundefined{\booklettrue}}{}{\pagebreak}
+
+% summary-mode
+\section*{Summary Mode}
+\SummaryModeGeneral
+    \subsection*{Select Articles}
+    \SelectArticles
+%
+    \ifthenelse{\isundefined{\booklettrue}}{}{\pagebreak}
+    \subsection*{Threading}
+    \Threading
+%
+    \subsection*{Limiting}
+    \Limiting
+    \subsection*{Sort the Summary-Buffer}
+    \SortSummary
+    \subsection*{Score (Value) Commands}
+    \Scoring
+
+\ifthenelse{\isundefined{\booklettrue}}{% ifcard %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  \subsection*{Output Articles}
+  \OutputArticles
+  \subsection*{Extract Series (Uudecode etc)}
+  \ExtractSeries
+}{}%ifcard% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+    \subsection*{MIME operations from the Summary-Buffer}
+    \MIMESummary
+
+\ifthenelse{\isundefined{\booklettrue}}{}{% ifbooklet %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  \subsection*{Extract Series (Uudecode etc)}
+  \ExtractSeries
+  \subsection*{Output Articles}
+  \OutputArticles
+}%ifbooklet% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%
+    \subsection*{Post, Followup, Reply, Forward, Cancel}
+    \PostReplyetc
+
+\ifthenelse{\isundefined{\booklettrue}}{\newpage}{}% newpage ifcard
+
+      \subsection*{Message Composition}
+
+    \MsgCompositionGeneral
+        \subsubsection*{Jumping in message-buffer}
+        \MsgCompositionMovementArticle
+        \subsubsection*{Attachments/MML}
+        \MsgCompositionMML
+% marking articles
+    \subsection*{Mark Articles}
+    \MarkArticlesGeneral
+        \subsubsection*{Mark Based on Score}
+        \MarkByScore
+        \subsubsection*{The Process Mark}
+        \ProcessMark
+        \subsubsection*{Mark Indication-Characters}
+        \MarkCharacters
+%
+%\ifthenelse{\isundefined{\booklettrue}}{\newpage}{}%
+    \newpage
+    \subsection*{Summary-Unplugged}
+    \SummaryUnplugged
+    \subsection*{Mail-Group Commands}
+    \MailGroups
+    \subsection*{Draft-Group Commands}
+    \DraftGroup
+% exiting
+    \subsection*{Exit the Summary-Buffer}
+    \ExitSummary
+%
+%
+\section*{Article Mode (reading)}
+\ArticleModeGeneral
+    \subsection*{Wash the Article-Buffer}
+    \WashArticle
+    \subsubsection*{Blank Lines and Whitespace}
+    \BlankAndWhitespace
+    \subsubsection*{Picons, X-faces, Smileys}
+    \Picons
+    \subsubsection*{Time and Date}
+    \TimeAndDate
+    \ifthenelse{\isundefined{\booklettrue}}{}{\pagebreak}
+    \subsection*{Hide/Highlight Parts of the Article}
+    \HideHighlightArticle
+    \subsection*{MIME operations from the Article-Buffer (reading)}
+    \MIMEArticleMode
+%
+%
+\ifthenelse{\isundefined{\booklettrue}}{\pagebreak}{}%
+\section*{Server Mode}
+\ServerMode
+    \subsection*{Unplugged-Server}
+    \ServerUnplugged
+%
+%
+\section*{Browse Server Mode}
+\BrowseServer
+
+%\pagebreak
+\vspace*{\fill}
+\Copyright
+
+\end{document}
+
+%%% Local Variables:
+%%% mode: latex
+%%% TeX-master: t
+%%% End:
diff --git a/xemacs-packages/gnus/texi/gnus.texi b/xemacs-packages/gnus/texi/gnus.texi
new file mode 100644 (file)
index 0000000..b664c80
--- /dev/null
@@ -0,0 +1,30723 @@
+\input texinfo
+
+@include gnus-overrides.texi
+
+@setfilename gnus.info
+@settitle Gnus Manual
+@include docstyle.texi
+@syncodeindex fn cp
+@syncodeindex vr cp
+@syncodeindex pg cp
+
+@copying
+Copyright @copyright{} 1995--2016 Free Software Foundation, Inc.
+
+@quotation
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 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''.
+
+(a) The FSF's Back-Cover Text is: ``You have the freedom to copy and
+modify this GNU manual.''
+@end quotation
+@end copying
+
+@iftex
+@iflatex
+\documentclass[twoside,a4paper,openright,11pt]{book}
+\usepackage[latin1]{inputenc}
+\usepackage{pagestyle}
+\usepackage{epsfig}
+\usepackage{pixidx}
+\input{gnusconfig.tex}
+
+\ifx\pdfoutput\undefined
+\else
+\usepackage[pdftex,bookmarks,colorlinks=true]{hyperref}
+\usepackage{thumbpdf}
+\pdfcompresslevel=9
+\fi
+
+\makeindex
+\begin{document}
+
+% Adjust ../Makefile.in if you change the following line:
+\newcommand{\gnusversionname}{Ma Gnus v0.14}
+\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]{{\gnusselectttfont{}#1}}
+\newcommand{\gnuscode}[1]{\gnustt{#1}}
+\newcommand{\gnusasis}[1]{\gnustt{#1}}
+\newcommand{\gnusurl}[1]{\gnustt{#1}}
+\newcommand{\gnuscommand}[1]{\gnustt{#1}}
+\newcommand{\gnusenv}[1]{\gnustt{#1}}
+\newcommand{\gnussamp}[1]{``{\fontencoding{OT1}\gnusselectttfont{}#1}''}
+\newcommand{\gnuslisp}[1]{\gnustt{#1}}
+\newcommand{\gnuskbd}[1]{`\gnustt{#1}'}
+\newcommand{\gnuskey}[1]{`\gnustt{#1}'}
+\newcommand{\gnusfile}[1]{`\gnustt{#1}'}
+\newcommand{\gnusdfn}[1]{\textit{#1}}
+\newcommand{\gnusi}[1]{\textit{#1}}
+\newcommand{\gnusr}[1]{\textrm{#1}}
+\newcommand{\gnusstrong}[1]{\textbf{#1}}
+\newcommand{\gnusemph}[1]{\textit{#1}}
+\newcommand{\gnusvar}[1]{{\fontsize{10pt}{10}\selectfont\textsl{\textsf{#1}}}}
+\newcommand{\gnussc}[1]{\textsc{#1}}
+\newcommand{\gnustitle}[1]{{\huge\textbf{#1}}}
+\newcommand{\gnusversion}[1]{{\small\textit{#1}}}
+\newcommand{\gnusauthor}[1]{{\large\textbf{#1}}}
+\newcommand{\gnusresult}[1]{\gnustt{=> #1}}
+\newcommand{\gnusacronym}[1]{\textsc{#1}}
+\newcommand{\gnusemail}[1]{\textit{#1}}
+
+\newcommand{\gnusbullet}{{${\bullet}$}}
+\newcommand{\gnusdollar}{\$}
+\newcommand{\gnusampersand}{\&}
+\newcommand{\gnuspercent}{\%}
+\newcommand{\gnushash}{\#}
+\newcommand{\gnushat}{\symbol{"5E}}
+\newcommand{\gnusunderline}{\symbol{"5F}}
+\newcommand{\gnusnot}{$\neg$}
+\newcommand{\gnustilde}{\symbol{"7E}}
+\newcommand{\gnusless}{{$<$}}
+\newcommand{\gnusgreater}{{$>$}}
+\newcommand{\gnusbraceleft}{{$>$}}
+\newcommand{\gnusbraceright}{{$>$}}
+
+\newcommand{\gnushead}{\raisebox{-1cm}{\epsfig{figure=ps/gnus-head,height=1cm}}}
+\newcommand{\gnusinteresting}{
+\marginpar[\mbox{}\hfill\gnushead]{\gnushead}
+}
+
+\newcommand{\gnuscleardoublepage}{\ifodd\count0\mbox{}\clearpage\thispagestyle{empty}\mbox{}\clearpage\else\clearpage\fi}
+
+\newcommand{\gnuspagechapter}[1]{
+{\mbox{}}
+}
+
+\newdimen{\gnusdimen}
+\gnusdimen 0pt
+
+\newcommand{\gnuschapter}[2]{
+\gnuscleardoublepage
+\ifdim \gnusdimen = 0pt\setcounter{page}{1}\pagestyle{gnus}\pagenumbering{arabic} \gnusdimen 1pt\fi
+\chapter{#2}
+\renewcommand{\gnussectionname}{}
+\renewcommand{\gnuschaptername}{#2}
+\thispagestyle{empty}
+\hspace*{-2cm}
+\begin{picture}(500,500)(0,0)
+\put(480,350){\makebox(0,0)[tr]{#1}}
+\put(40,300){\makebox(500,50)[bl]{{\Huge\bf{#2}}}}
+\end{picture}
+\clearpage
+}
+
+\newcommand{\gnusfigure}[3]{
+\begin{figure}
+\mbox{}\ifodd\count0\hspace*{-0.8cm}\else\hspace*{-3cm}\fi\begin{picture}(440,#2)
+#3
+\end{picture}
+\caption{#1}
+\end{figure}
+}
+
+\newcommand{\gnusicon}[1]{
+\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]{
+\margindex{\epsfig{figure=#1,width=2cm}}
+}
+
+\newcommand{\gnusxface}[2]{
+\margindex{\epsfig{figure=#1,width=1cm}\epsfig{figure=#2,width=1cm}}
+}
+
+\newcommand{\gnussmiley}[2]{
+\margindex{\makebox[2cm]{\hfill\epsfig{figure=#1,width=0.5cm}\hfill\epsfig{figure=#2,width=0.5cm}\hfill}}
+}
+
+\newcommand{\gnusitemx}[1]{\mbox{}\vspace*{-\itemsep}\vspace*{-\parsep}\item#1}
+
+\newcommand{\gnussection}[1]{
+\renewcommand{\gnussectionname}{#1}
+\section{#1}
+}
+
+\newenvironment{codelist}%
+{\begin{list}{}{
+}
+}{\end{list}}
+
+\newenvironment{asislist}%
+{\begin{list}{}{
+}
+}{\end{list}}
+
+\newenvironment{kbdlist}%
+{\begin{list}{}{
+\labelwidth=0cm
+}
+}{\end{list}}
+
+\newenvironment{dfnlist}%
+{\begin{list}{}{
+}
+}{\end{list}}
+
+\newenvironment{stronglist}%
+{\begin{list}{}{
+}
+}{\end{list}}
+
+\newenvironment{samplist}%
+{\begin{list}{}{
+}
+}{\end{list}}
+
+\newenvironment{varlist}%
+{\begin{list}{}{
+}
+}{\end{list}}
+
+\newenvironment{emphlist}%
+{\begin{list}{}{
+}
+}{\end{list}}
+
+\newlength\gnusheadtextwidth
+\setlength{\gnusheadtextwidth}{\headtextwidth}
+\addtolength{\gnusheadtextwidth}{1cm}
+
+\newpagestyle{gnuspreamble}%
+{
+{
+\ifodd\count0
+{
+\hspace*{-0.23cm}\underline{\makebox[\gnusheadtextwidth]{\mbox{}}\textbf{\hfill\roman{page}}}
+}
+\else
+{
+\hspace*{-3.25cm}\underline{\makebox[\gnusheadtextwidth]{\textbf{\roman{page}\hfill\mbox{}}}
+}
+}
+\fi
+}
+}
+{
+\ifodd\count0
+\mbox{} \hfill
+\raisebox{-0.5cm}{\epsfig{figure=ps/gnus-big-logo,height=1cm}}
+\else
+\raisebox{-0.5cm}{\epsfig{figure=ps/gnus-big-logo,height=1cm}}
+\hfill \mbox{}
+\fi
+}
+
+\newpagestyle{gnusindex}%
+{
+{
+\ifodd\count0
+{
+\hspace*{-0.23cm}\underline{\makebox[\gnusheadtextwidth]{\textbf{\gnuschaptername\hfill\arabic{page}}}}
+}
+\else
+{
+\hspace*{-3.25cm}\underline{\makebox[\gnusheadtextwidth]{\textbf{\arabic{page}\hfill\gnuschaptername}}}
+}
+\fi
+}
+}
+{
+\ifodd\count0
+\mbox{} \hfill
+\raisebox{-0.5cm}{\epsfig{figure=ps/gnus-big-logo,height=1cm}}
+\else
+\raisebox{-0.5cm}{\epsfig{figure=ps/gnus-big-logo,height=1cm}}
+\hfill \mbox{}
+\fi
+}
+
+\newpagestyle{gnus}%
+{
+{
+\ifodd\count0
+{
+\makebox[12cm]{\hspace*{3.1cm}\underline{\makebox[\gnusheadtextwidth]{\textbf{\arabic{chapter}.\arabic{section}} \textbf{\gnussectionname\hfill\arabic{page}}}}}
+}
+\else
+{
+\makebox[12cm]{\hspace*{-2.95cm}\underline{\makebox[\gnusheadtextwidth]{\textbf{\arabic{page}\hfill\gnuschaptername}}}}
+}
+\fi
+}
+}
+{
+\ifodd\count0
+\mbox{} \hfill
+\raisebox{-0.5cm}{\epsfig{figure=ps/gnus-big-logo,height=1cm}}
+\else
+\raisebox{-0.5cm}{\epsfig{figure=ps/gnus-big-logo,height=1cm}}
+\hfill \mbox{}
+\fi
+}
+
+\pagenumbering{roman}
+\pagestyle{gnuspreamble}
+
+@end iflatex
+@end iftex
+
+@iftex
+@iflatex
+
+\begin{titlepage}
+{
+
+%\addtolength{\oddsidemargin}{-5cm}
+%\addtolength{\evensidemargin}{-5cm}
+\parindent=0cm
+\addtolength{\textheight}{2cm}
+
+\gnustitle{\gnustitlename}\hfill\gnusversion{\gnusversionname}\\
+\rule{15cm}{1mm}\\
+\vfill
+\hspace*{0cm}\epsfig{figure=ps/gnus-big-logo,height=15cm}
+\vfill
+\rule{15cm}{1mm}\\
+\gnusauthor{by Lars Magne Ingebrigtsen}
+\newpage
+}
+
+\mbox{}
+\vfill
+
+\thispagestyle{empty}
+
+@c @insertcopying
+\newpage
+\end{titlepage}
+@end iflatex
+@end iftex
+
+@dircategory Emacs network features
+@direntry
+* Gnus: (gnus).                 The newsreader Gnus.
+@end direntry
+@iftex
+@finalout
+@end iftex
+
+
+@titlepage
+@ifset WEBHACKDEVEL
+@title Gnus Manual (DEVELOPMENT VERSION)
+@end ifset
+@ifclear WEBHACKDEVEL
+@title Gnus Manual
+@end ifclear
+
+@author by Lars Magne Ingebrigtsen
+@page
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+
+@summarycontents
+@contents
+
+@node Top
+@top The Gnus Newsreader
+
+@ifinfo
+
+You can read news (and mail) from within Emacs by using Gnus.  The news
+can be gotten by any nefarious means you can think of---@acronym{NNTP}, local
+spool or your mbox file.  All at the same time, if you want to push your
+luck.
+
+@c Adjust ../Makefile.in if you change the following line:
+This manual corresponds to Ma Gnus v0.14
+
+@ifnottex
+@insertcopying
+@end ifnottex
+
+@end ifinfo
+
+@iftex
+
+@iflatex
+\tableofcontents
+\gnuscleardoublepage
+@end iflatex
+
+Gnus is the advanced, self-documenting, customizable, extensible
+unreal-time newsreader for GNU Emacs.
+
+Oops.  That sounds oddly familiar, so let's start over again to avoid
+being accused of plagiarism:
+
+Gnus is a message-reading laboratory.  It will let you look at just
+about anything as if it were a newsgroup.  You can read mail with it,
+you can browse directories with it, you can @code{ftp} with it---you
+can even read news with it!
+
+Gnus tries to empower people who read news the same way Emacs empowers
+people who edit text.  Gnus sets no limits to what the user should be
+allowed to do.  Users are encouraged to extend Gnus to make it behave
+like they want it to behave.  A program should not control people;
+people should be empowered to do what they want by using (or abusing)
+the program.
+
+@c Adjust ../Makefile.in if you change the following line:
+This manual corresponds to Ma Gnus v0.14
+
+@heading Other related manuals
+@itemize
+@item Message manual: Composing messages
+@item Emacs-MIME:     Composing messages; @acronym{MIME}-specific parts.
+@item Sieve:          Managing Sieve scripts in Emacs.
+@item EasyPG:         @acronym{PGP/MIME} with Gnus.
+@item SASL:           @acronym{SASL} authentication in Emacs.
+@end itemize
+
+@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.
+* Searching::                Mail and News search engines.
+* Various::                  General purpose settings.
+* The End::                  Farewell and goodbye.
+* Appendices::               Terminology, Emacs intro, @acronym{FAQ}, History, Internals.
+* GNU Free Documentation License:: The license for this documentation.
+* Index::                    Variable, function and concept index.
+* Key Index::                Key Index.
+
+@c Doesn't work right in html.
+@c FIXME Do this in a more standard way.
+@ifinfo
+Other related manuals
+
+* Message:(message).         Composing messages.
+* Emacs-MIME:(emacs-mime).   Composing messages; @acronym{MIME}-specific parts.
+* Sieve:(sieve).             Managing Sieve scripts in Emacs.
+* EasyPG:(epa).              @acronym{PGP/MIME} with Gnus.
+* SASL:(sasl).               @acronym{SASL} authentication in Emacs.
+@end ifinfo
+
+@detailmenu
+ --- The Detailed Node Listing ---
+
+Starting Gnus
+
+* Finding the News::            Choosing a method for getting news.
+* 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.
+
+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.
+* 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.
+* Non-ASCII Group Names::       Accessing groups of non-English names.
+* 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 Mode Line Specification::  The group buffer mode line.
+* Group Highlighting::          Having nice colors in the group buffer.
+
+Group Topics
+
+* 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.
+
+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.
+* Sieve Commands::              Managing Sieve scripts.
+
+Summary Buffer
+
+* Summary Buffer Format::       Deciding how the summary buffer is to look.
+* Summary Maneuvering::         Moving around the summary buffer.
+* Choosing Articles::           Reading articles.
+* Paging the Article::          Scrolling the current article.
+* Reply Followup and Post::     Posting articles.
+* Delayed Articles::            Send articles at a later time.
+* Marking Articles::            Marking articles as read, expirable, etc.
+* Limiting::                    You can limit the summary buffer.
+* Threading::                   How threads are made.
+* Sorting the Summary Buffer::  How articles and threads are sorted.
+* Asynchronous Fetching::       Gnus might be able to pre-fetch articles.
+* Article Caching::             You may store articles in a cache.
+* Persistent Articles::         Making articles expiry-resistant.
+* Sticky Articles::             Article buffers that are not reused.
+* Article Backlog::             Having already read articles hang around.
+* Saving Articles::             Ways of customizing article saving.
+* Decoding Articles::           Gnus can treat series of (uu)encoded articles.
+* Article Treatment::           The article buffer can be mangled at will.
+* MIME Commands::               Doing MIMEy things with the articles.
+* Charsets::                    Character set issues.
+* Article Commands::            Doing various things with the article buffer.
+* Summary Sorting::             Sorting the summary buffer in various ways.
+* Finding the Parent::          No child support?  Get the parent.
+* Alternative Approaches::      Reading using non-default summaries.
+* 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,
+                                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.
+
+Choosing Articles
+
+* 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::
+
+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.
+
+Threading
+
+* 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@dots{} 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?
+
+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.
+
+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 Header::              Doing various header transformations.
+* Article Buttons::             Click on URLs, Message-IDs, addresses and the like.
+* Article Button Levels::       Controlling appearance of buttons.
+* Article Date::                Grumble, UT!
+* Article Display::             Display various stuff---X-Face, Picons, Smileys, Gravatars
+* Article Signature::           What is a signature?
+* Article Miscellanea::         Various other stuff.
+
+Alternative Approaches
+
+* Pick and Read::               First mark articles and then read them.
+* Binary Groups::               Auto-decode all articles.
+
+Various Summary Stuff
+
+* 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 @acronym{MIME} before reading them.
+* HTML::                        Reading @acronym{HTML} messages.
+* 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 and mail via?
+* POP before SMTP::             You cannot send a mail unless you read a mail.
+* 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?
+* Signing and encrypting::      How to compose secure messages.
+
+Select Methods
+
+* Server Buffer::               Making and editing virtual servers.
+* Getting News::                Reading USENET news with Gnus.
+* Using IMAP::                  Reading mail from @acronym{IMAP}.
+* Getting Mail::                Reading your personal mail with Gnus.
+* Browsing the Web::            Getting messages from a plethora of Web sources.
+* Other Sources::               Reading directories, files.
+* Combined Groups::             Combining groups into one group.
+* Email Based Diary::           Using mails to manage diary events in Gnus.
+* 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.
+
+Getting News
+
+* NNTP::                        Reading news from an @acronym{NNTP} server.
+* News Spool::                  Reading news from the local spool.
+
+@acronym{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 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 cruft 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.
+
+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.
+
+Choosing a Mail Back End
+
+* Unix Mail Box::               Using the (quite) standard Un*x mbox.
+* Babyl::                       Babyl was used by older versions of Rmail.
+* Mail Spool::                  Store your mail in a private spool?
+* MH Spool::                    An mhspool-like back end.
+* Maildir::                     Another one-file-per-message format.
+* Mail Folders::                Having one file for each group.
+* Comparing Mail Back Ends::    An in-depth looks at pros and cons.
+
+Browsing the Web
+
+* Archiving Mail::
+* Web Searches::                Creating groups from articles that match a string.
+* RSS::                         Reading RDF site summary.
+
+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.
+* Mail-To-News Gateways::       Posting articles via mail-to-news gateways.
+* The Empty Backend::           The backend that never has any news.
+
+Document Groups
+
+* Document Server Internals::   How to add your own document types.
+
+Combined Groups
+
+* Virtual Groups::              Combining articles from many groups.
+
+Email Based Diary
+
+* The NNDiary Back End::        Basic setup and usage.
+* The Gnus Diary Library::      Utility toolkit on top of nndiary.
+* Sending or Not Sending::      A final note on sending diary messages.
+
+The NNDiary Back End
+
+* Diary Messages::              What makes a message valid for nndiary.
+* Running NNDiary::             NNDiary has two modes of operation.
+* Customizing NNDiary::         Bells and whistles.
+
+The Gnus Diary Library
+
+* Diary Summary Line Format::           A nicer summary buffer line format.
+* Diary Articles Sorting::              A nicer way to sort messages.
+* Diary Headers Generation::            Not doing it manually.
+* Diary Group Parameters::              Not handling them manually.
+
+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 Visuals::               Ways that the agent may effect your summary buffer.
+* Agent as Cache::              The Agent is a big cache too.
+* Agent Expiry::                How to make old articles go away.
+* Agent Regeneration::          How to recover from lost connections and other accidents.
+* Agent and flags::             How the Agent maintains flags.
+* Agent and IMAP::              How to use the Agent with @acronym{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.
+
+Agent Commands
+
+* Group Agent Commands::        Configure groups and fetch their contents.
+* Summary Agent Commands::      Manually select then fetch specific articles.
+* Server Agent Commands::       Select the servers that are supported by the agent.
+
+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 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.
+* Advanced Scoring::            Using logical expressions to build score rules.
+* Score Decays::                It can be useful to let scores wither away.
+
+Advanced Scoring
+
+* Advanced Scoring Syntax::     A definition.
+* Advanced Scoring Examples::   What they look like.
+* Advanced Scoring Tips::       Getting the most out of it.
+
+Searching
+
+* nnir::                        Searching with various engines.
+* nnmairix::                    Searching with Mairix.
+
+nnir
+
+* What is nnir?::               What does nnir do.
+* Basic Usage::                 How to perform simple searches.
+* Setting up nnir::             How to set up nnir.
+
+Setting up nnir
+
+* Associating Engines::         How to associate engines.
+
+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.
+* Mode Lines::                  Displaying information in the mode lines.
+* Highlighting and Menus::      Making buffers look all nice and cozy.
+* Daemons::                     Gnus can do things behind your back.
+* Undo::                        Some actions can be undone.
+* Predicate Specifiers::        Specifying predicates.
+* 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::        Simple ways to avoid unsolicited commercial email.
+* Spam Package::                A package for filtering and processing spam.
+* The Gnus Registry::           A package for tracking messages by Message-ID.
+* Other modes::                 Interaction with other modes.
+* 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.
+* Positioning Point::           Moving point to a position after an operation.
+* Tabulation::                  Tabulating your output.
+* Wide Characters::             Dealing with wide characters.
+
+Image Enhancements
+
+* X-Face::                      Display a funky, teensy black-and-white image.
+* Face::                        Display a funkier, teensier colored image.
+* Smileys::                     Show all those happy faces the way they were
+                                  meant to be shown.
+* Picons::                      How to display pictures of what you're reading.
+* Gravatars::                   Display the avatar of people you read.
+* XVarious::                    Other XEmacsy Gnusey variables.
+
+Thwarting Email Spam
+
+* The problem of spam::         Some background, and some solutions
+* Anti-Spam Basics::            Simple steps to reduce the amount of spam.
+* SpamAssassin::                How to use external anti-spam tools.
+* Hashcash::                    Reduce spam by burning CPU time.
+
+Spam Package
+
+* Spam Package Introduction::
+* Filtering Incoming Mail::
+* Detecting Spam in Groups::
+* Spam and Ham Processors::
+* Spam Package Configuration Examples::
+* Spam Back Ends::
+* Extending the Spam package::
+* Spam Statistics Package::
+
+Spam Statistics Package
+
+* Creating a spam-stat dictionary::
+* Splitting mail using spam-stat::
+* Low-level interface to the spam-stat dictionary::
+
+Appendices
+
+* 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::  The Gnus FAQ
+
+History
+
+* Gnus Versions::               What Gnus versions 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.
+* Oort Gnus::                   It's big.  It's far out.  Gnus 5.10/5.11.
+* No Gnus::                     Very punny.  Gnus 5.12/5.13
+* Ma Gnus::                     Celebrating 25 years of Gnus.
+
+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.
+
+Gnus Reference Guide
+
+* 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.
+
+Emacs for Heathens
+
+* Keystrokes::                  Entering text and executing commands.
+* Emacs Lisp::                  The built-in Emacs programming language.
+
+@end detailmenu
+@end menu
+
+@node Starting Up
+@chapter Starting Gnus
+@cindex starting up
+
+If you haven't used Emacs much before using Gnus, read @ref{Emacs for
+Heathens} first.
+
+@kindex M-x gnus
+@findex gnus
+If your system administrator has set things up properly, starting Gnus
+and reading news is extremely easy---you just type @kbd{M-x gnus} in
+your Emacs.  If not, you should customize the variable
+@code{gnus-select-method} as described in @ref{Finding the News}.  For a
+minimal setup for posting should also customize the variables
+@code{user-full-name} and @code{user-mail-address}.
+
+@findex gnus-other-frame
+@kindex M-x gnus-other-frame
+If you want to start Gnus in a different frame, you can use the command
+@kbd{M-x gnus-other-frame} instead.
+
+If things do not go smoothly at startup, you have to twiddle some
+variables in your @file{~/.gnus.el} file.  This file is similar to
+@file{~/.emacs}, but is read when Gnus starts.
+
+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 Server is Down::    How can I read my mail then?
+* Slave Gnusae::          You can have more than one Gnus active at a time.
+* 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
+
+
+@node Finding the News
+@section Finding the News
+@cindex finding news
+
+First of all, you should know that there is a special buffer called
+@file{*Server*} that lists all the servers Gnus knows about.  You can
+press @kbd{^} from the Group buffer to see it.  In the Server buffer,
+you can press @kbd{RET} on a defined server to see all the groups it
+serves (subscribed or not!).  You can also add or delete servers, edit
+a foreign server's definition, agentize or de-agentize a server, and
+do many other neat things.  @xref{Server Buffer}.
+@xref{Foreign Groups}.  @xref{Agent Basics}.
+
+@vindex gnus-select-method
+@c @head
+The @code{gnus-select-method} variable says where Gnus should look for
+news.  This variable should be a list where the first element says
+@dfn{how} and the second element says @dfn{where}.  This method is your
+native method.  All groups not fetched with this method are
+secondary or foreign groups.
+
+For instance, if the @samp{news.somewhere.edu} @acronym{NNTP} server is where
+you want to get your daily dosage of news from, you'd say:
+
+@lisp
+(setq gnus-select-method '(nntp "news.somewhere.edu"))
+@end lisp
+
+If you want to read directly from the local spool, say:
+
+@lisp
+(setq gnus-select-method '(nnspool ""))
+@end lisp
+
+If you can use a local spool, you probably should, as it will almost
+certainly be much faster.  But do not use the local spool if your
+server is running Leafnode (which is a simple, standalone private news
+server); in this case, use @code{(nntp "localhost")}.
+
+@vindex gnus-nntpserver-file
+@cindex NNTPSERVER
+@cindex @acronym{NNTP} server
+If this variable is not set, Gnus will take a look at the
+@env{NNTPSERVER} environment variable.  If that variable isn't set,
+Gnus will see whether @code{gnus-nntpserver-file}
+(@file{/etc/nntpserver} by default) has any opinions on the matter.
+If that fails as well, Gnus will try to use the machine running Emacs
+as an @acronym{NNTP} server.  That's a long shot, though.
+
+@findex gnus-group-browse-foreign-server
+@kindex B (Group)
+However, if you use one @acronym{NNTP} server regularly and are just
+interested in a couple of groups from a different server, you would be
+better served by using the @kbd{B} command in the group buffer.  It will
+let you have a look at what groups are available, and you can subscribe
+to any of the groups you want to.  This also makes @file{.newsrc}
+maintenance much tidier.  @xref{Foreign Groups}.
+
+@vindex gnus-secondary-select-methods
+@c @head
+A slightly different approach to foreign groups is to set the
+@code{gnus-secondary-select-methods} variable.  The select methods
+listed in this variable are in many ways just as native as the
+@code{gnus-select-method} server.  They will also be queried for active
+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} back end to read your mail,
+you would typically set this variable to
+
+@lisp
+(setq gnus-secondary-select-methods '((nnmbox "")))
+@end lisp
+
+
+
+@node The Server is Down
+@section The Server is Down
+@cindex server errors
+
+If the default server is down, Gnus will understandably have some
+problems starting.  However, if you have some mail groups in addition to
+the news groups, you may want to start Gnus anyway.
+
+Gnus, being the trusting sort of program, will ask whether to proceed
+without a native select method if that server can't be contacted.  This
+will happen whether the server doesn't actually exist (i.e., you have
+given the wrong address) or the server has just momentarily taken ill
+for some reason or other.  If you decide to continue and have no foreign
+groups, you'll find it difficult to actually do anything in the group
+buffer.  But, hey, that's your problem.  Blllrph!
+
+@findex gnus-no-server
+@kindex M-x gnus-no-server
+@c @head
+If you know that the server is definitely down, or you just want to read
+your mail without bothering with the server at all, you can use the
+@code{gnus-no-server} command to start Gnus.  That might come in handy
+if you're in a hurry as well.  This command will not attempt to contact
+your primary server---instead, it will just activate all groups on level
+1 and 2.  (You should preferably keep no native groups on those two
+levels.)  Also @pxref{Group Levels}.
+
+
+@node Slave Gnusae
+@section Slave Gnusae
+@cindex slave
+
+You might want to run more than one Emacs with more than one Gnus at the
+same time.  If you are using different @file{.newsrc} files (e.g., if you
+are using the two different Gnusae to read from two different servers),
+that is no problem whatsoever.  You just do it.
+
+The problem appears when you want to run two Gnusae that use the same
+@file{.newsrc} file.
+
+To work around that problem some, we here at the Think-Tank at the Gnus
+Towers have come up with a new concept: @dfn{Masters} and
+@dfn{slaves}.  (We have applied for a patent on this concept, and have
+taken out a copyright on those words.  If you wish to use those words in
+conjunction with each other, you have to send $1 per usage instance to
+me.  Usage of the patent (@dfn{Master/Slave Relationships In Computer
+Applications}) will be much more expensive, of course.)
+
+@findex gnus-slave
+Anyway, you start one Gnus up the normal way with @kbd{M-x gnus} (or
+however you do it).  Each subsequent slave Gnusae should be started with
+@kbd{M-x gnus-slave}.  These slaves won't save normal @file{.newsrc}
+files, but instead save @dfn{slave files} that contain information only
+on what groups have been read in the slave session.  When a master Gnus
+starts, it will read (and delete) these slave files, incorporating all
+information from them.  (The slave files will be read in the sequence
+they were created, so the latest changes will have precedence.)
+
+Information from the slave files has, of course, precedence over the
+information in the normal (i.e., master) @file{.newsrc} file.
+
+If the @file{.newsrc*} files have not been saved in the master when the
+slave starts, you may be prompted as to whether to read an auto-save
+file.  If you answer ``yes'', the unsaved changes to the master will be
+incorporated into the slave.  If you answer ``no'', the slave may see some
+messages as unread that have been read in the master.
+
+
+
+@node New Groups
+@section New Groups
+@cindex new groups
+@cindex subscription
+
+@vindex gnus-check-new-newsgroups
+If you are satisfied that you really never want to see any new groups,
+you can set @code{gnus-check-new-newsgroups} to @code{nil}.  This will
+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 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.
+@end menu
+
+
+@node Checking New Groups
+@subsection Checking New Groups
+
+Gnus normally determines whether a group is new or not by comparing
+the list of groups from the active file(s) with the lists of
+subscribed and dead groups.  This isn't a particularly fast method.
+If @code{gnus-check-new-newsgroups} is @code{ask-server}, Gnus will
+ask the server for new groups since the last time.  This is both
+faster and cheaper.  This also means that you can get rid of the list
+of killed groups (@pxref{Group Levels}) altogether, so you may set
+@code{gnus-save-killed-list} to @code{nil}, which will save time both
+at startup, at exit, and all over.  Saves disk space, too.  Why isn't
+this the default, then?  Unfortunately, not all servers support this
+command.
+
+I bet I know what you're thinking now: How do I find out whether my
+server supports @code{ask-server}?  No?  Good, because I don't have a
+fail-safe answer.  I would suggest just setting this variable to
+@code{ask-server} and see whether any new groups appear within the next
+few days.  If any do, then it works.  If none do, then it doesn't
+work.  I could write a function to make Gnus guess whether the server
+supports @code{ask-server}, but it would just be a guess.  So I won't.
+You could @code{telnet} to the server and say @code{HELP} and see
+whether it lists @samp{NEWGROUPS} among the commands it understands.  If
+it does, then it might work.  (But there are servers that lists
+@samp{NEWGROUPS} without supporting the function properly.)
+
+This variable can also be a list of select methods.  If so, Gnus will
+issue an @code{ask-server} command to each of the select methods, and
+subscribe them (or not) using the normal methods.  This might be handy
+if you are monitoring a few servers for new groups.  A side effect is
+that startup will take much longer, so you can meditate while waiting.
+Use the mantra ``dingnusdingnusdingnus'' to achieve permanent bliss.
+
+
+@node Subscription Methods
+@subsection Subscription Methods
+
+@vindex gnus-subscribe-newsgroup-method
+What Gnus does when it encounters a new group is determined by the
+@code{gnus-subscribe-newsgroup-method} variable.
+
+This variable should contain a function.  This function will be called
+with the name of the new group as the only parameter.
+
+Some handy pre-fab functions are:
+
+@table @code
+
+@item gnus-subscribe-zombies
+@vindex gnus-subscribe-zombies
+Make all new groups zombies (@pxref{Group Levels}).  This is the
+default.  You can browse the zombies later (with @kbd{A z}) and either
+kill them all off properly (with @kbd{S z}), or subscribe to them
+(with @kbd{u}).
+
+@item gnus-subscribe-randomly
+@vindex gnus-subscribe-randomly
+Subscribe all new groups in arbitrary order.  This really means that all
+new groups will be added at ``the top'' of the group buffer.
+
+@item gnus-subscribe-alphabetically
+@vindex gnus-subscribe-alphabetically
+Subscribe all new groups in alphabetical order.
+
+@item gnus-subscribe-hierarchically
+@vindex gnus-subscribe-hierarchically
+Subscribe all new groups hierarchically.  The difference between this
+function and @code{gnus-subscribe-alphabetically} is slight.
+@code{gnus-subscribe-alphabetically} will subscribe new groups in a strictly
+alphabetical fashion, while this function will enter groups into its
+hierarchy.  So if you want to have the @samp{rec} hierarchy before the
+@samp{comp} hierarchy, this function will not mess that configuration
+up.  Or something like that.
+
+@item gnus-subscribe-interactively
+@vindex gnus-subscribe-interactively
+Subscribe new groups interactively.  This means that Gnus will ask
+you about @strong{all} new groups.  The groups you choose to subscribe
+to will be subscribed hierarchically.
+
+@item gnus-subscribe-killed
+@vindex gnus-subscribe-killed
+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
+parameter (@pxref{Topic Parameters}).  For instance, a @code{subscribe}
+topic parameter that looks like
+
+@example
+"nnml"
+@end example
+
+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
+top-level topic.
+
+@end table
+
+@vindex gnus-subscribe-hierarchical-interactive
+A closely related variable is
+@code{gnus-subscribe-hierarchical-interactive}.  (That's quite a
+mouthful.)  If this variable is non-@code{nil}, Gnus will ask you in a
+hierarchical fashion whether to subscribe to new groups or not.  Gnus
+will ask you for each sub-hierarchy whether you want to descend the
+hierarchy or not.
+
+One common mistake is to set the variable a few paragraphs above
+(@code{gnus-subscribe-newsgroup-method}) to
+@code{gnus-subscribe-hierarchical-interactive}.  This is an error.  This
+will not work.  This is ga-ga.  So don't do it.
+
+
+@node Filtering New Groups
+@subsection Filtering New Groups
+
+A nice and portable way to control which new newsgroups should be
+subscribed (or ignored) is to put an @dfn{options} line at the start of
+the @file{.newsrc} file.  Here's an example:
+
+@example
+options -n !alt.all !rec.all sci.all
+@end example
+
+@vindex gnus-subscribe-options-newsgroup-method
+This line obviously belongs to a serious-minded intellectual scientific
+person (or she may just be plain old boring), because it says that all
+groups that have names beginning with @samp{alt} and @samp{rec} should
+be ignored, and all groups with names beginning with @samp{sci} should
+be subscribed.  Gnus will not use the normal subscription method for
+subscribing these groups.
+@code{gnus-subscribe-options-newsgroup-method} is used instead.  This
+variable defaults to @code{gnus-subscribe-alphabetically}.
+
+The ``options -n'' format is very simplistic.  The syntax above is all
+that is supports: you can force-subscribe hierarchies, or you can
+deny hierarchies, and that's it.
+
+@vindex gnus-options-not-subscribe
+@vindex gnus-options-subscribe
+If you don't want to mess with your @file{.newsrc} file, you can just
+set the two variables @code{gnus-options-subscribe} and
+@code{gnus-options-not-subscribe}.  These two variables do exactly the
+same as the @file{.newsrc} @samp{options -n} trick.  Both are regexps,
+and if the new group matches the former, it will be unconditionally
+subscribed, and if it matches the latter, it will be ignored.
+
+@vindex gnus-auto-subscribed-groups
+Yet another variable that meddles here is
+@code{gnus-auto-subscribed-groups}.  It works exactly like
+@code{gnus-options-subscribe}, and is therefore really superfluous,
+but I 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 back ends (@code{nnml}, @code{nnbabyl},
+@code{nnfolder}, @code{nnmbox}, @code{nnmh}, @code{nnimap}, and
+@code{nnmaildir}) subscribed.  If you don't like that, just set this
+variable to @code{nil}.
+
+@vindex gnus-auto-subscribed-categories
+As if that wasn't enough, @code{gnus-auto-subscribed-categories} also
+allows you to specify that new groups should be subscribed based on the
+category their select methods belong to.  The default is @samp{(mail
+post-mail)}, meaning that all new groups from mail-like backends
+should be subscribed automatically.
+
+New groups that match these variables are subscribed using
+@code{gnus-subscribe-options-newsgroup-method}.
+
+
+@node Changing Servers
+@section Changing Servers
+@cindex changing servers
+
+Sometimes it is necessary to move from one @acronym{NNTP} server to another.
+This happens very rarely, but perhaps you change jobs, or one server is
+very flaky and you want to use another.
+
+Changing the server is pretty easy, right?  You just change
+@code{gnus-select-method} to point to the new server?
+
+@emph{Wrong!}
+
+Article numbers are not (in any way) kept synchronized between different
+@acronym{NNTP} servers, and the only way Gnus keeps track of what articles
+you have read is by keeping track of article numbers.  So when you
+change @code{gnus-select-method}, your @file{.newsrc} file becomes
+worthless.
+
+@kindex M-x gnus-group-clear-data-on-native-groups
+@findex gnus-group-clear-data-on-native-groups
+You can use the @kbd{M-x gnus-group-clear-data-on-native-groups}
+command to clear out all data that you have on your native groups.
+Use with caution.
+
+@kindex M-x gnus-group-clear-data
+@findex gnus-group-clear-data
+Clear the data from the current group only---nix out marks and the
+list of read articles (@code{gnus-group-clear-data}).
+
+After changing servers, you @strong{must} move the cache hierarchy away,
+since the cached articles will have wrong article numbers, which will
+affect which articles Gnus thinks are read.
+@code{gnus-group-clear-data-on-native-groups} will ask you if you want
+to have it done automatically; for @code{gnus-group-clear-data}, you
+can use @kbd{M-x gnus-cache-move-cache} (but beware, it will move the
+cache for all groups).
+
+
+@node Startup Files
+@section Startup Files
+@cindex startup files
+@cindex .newsrc
+@cindex .newsrc.el
+@cindex .newsrc.eld
+
+Most common Unix news readers use a shared startup file called
+@file{.newsrc}.  This file contains all the information about what
+groups are subscribed, and which articles in these groups have been
+read.
+
+Things got a bit more complicated with @sc{gnus}.  In addition to
+keeping the @file{.newsrc} file updated, it also used a file called
+@file{.newsrc.el} for storing all the information that didn't fit into
+the @file{.newsrc} file.  (Actually, it also duplicated everything in
+the @file{.newsrc} file.)  @sc{gnus} would read whichever one of these
+files was the most recently saved, which enabled people to swap between
+@sc{gnus} and other newsreaders.
+
+That was kinda silly, so Gnus went one better: In addition to the
+@file{.newsrc} and @file{.newsrc.el} files, Gnus also has a file called
+@file{.newsrc.eld}.  It will read whichever of these files that are most
+recent, but it will never write a @file{.newsrc.el} file.  You should
+never delete the @file{.newsrc.eld} file---it contains much information
+not stored in the @file{.newsrc} file.
+
+@vindex gnus-save-newsrc-file
+@vindex gnus-read-newsrc-file
+You can turn off writing the @file{.newsrc} file by setting
+@code{gnus-save-newsrc-file} to @code{nil}, which means you can delete
+the file and save some space, as well as exiting from Gnus faster.
+However, this will make it impossible to use other newsreaders than
+Gnus.  But hey, who would want to, right?  Similarly, setting
+@code{gnus-read-newsrc-file} to @code{nil} makes Gnus ignore the
+@file{.newsrc} file and any @file{.newsrc-SERVER} files, which can be
+convenient if you use a different news reader occasionally, and you
+want to read a different subset of the available groups with that
+news reader.
+
+@vindex gnus-save-killed-list
+If @code{gnus-save-killed-list} (default @code{t}) is @code{nil}, Gnus
+will not save the list of killed groups to the startup file.  This will
+save both time (when starting and quitting) and space (on disk).  It
+will also mean that Gnus has no record of what groups are new or old,
+so the automatic new groups subscription methods become meaningless.
+You should always set @code{gnus-check-new-newsgroups} to @code{nil} or
+@code{ask-server} if you set this variable to @code{nil} (@pxref{New
+Groups}).  This variable can also be a regular expression.  If that's
+the case, remove all groups that do not match this regexp before
+saving.  This can be useful in certain obscure situations that involve
+several servers where not all servers support @code{ask-server}.
+
+@vindex gnus-startup-file
+@vindex gnus-backup-startup-file
+@vindex version-control
+The @code{gnus-startup-file} variable says where the startup files are.
+The default value is @file{~/.newsrc}, with the Gnus (El Dingo) startup
+file being whatever that one is, with a @samp{.eld} appended.
+If you want to keep multiple numbered backups of this file, set
+@code{gnus-backup-startup-file}.  It respects the same values as the
+@code{version-control} variable.
+
+@vindex gnus-save-newsrc-hook
+@vindex gnus-save-quick-newsrc-hook
+@vindex gnus-save-standard-newsrc-hook
+@code{gnus-save-newsrc-hook} is called before saving any of the newsrc
+files, while @code{gnus-save-quick-newsrc-hook} is called just before
+saving the @file{.newsrc.eld} file, and
+@code{gnus-save-standard-newsrc-hook} is called just before saving the
+@file{.newsrc} file.  The latter two are commonly used to turn version
+control on or off.  Version control is on by default when saving the
+startup files.  If you want to turn backup creation off, say something like:
+
+@lisp
+(defun turn-off-backup ()
+  (set (make-local-variable 'backup-inhibited) t))
+
+(add-hook 'gnus-save-quick-newsrc-hook 'turn-off-backup)
+(add-hook 'gnus-save-standard-newsrc-hook 'turn-off-backup)
+@end lisp
+
+@vindex gnus-init-file
+@vindex gnus-site-init-file
+When Gnus starts, it will read the @code{gnus-site-init-file}
+(@file{.../site-lisp/gnus-init} by default) and @code{gnus-init-file}
+(@file{~/.gnus} by default) files.  These are normal Emacs Lisp files
+and can be used to avoid cluttering your @file{~/.emacs} and
+@file{site-init} files with Gnus stuff.  Gnus will also check for files
+with the same names as these, but with @file{.elc} and @file{.el}
+suffixes.  In other words, if you have set @code{gnus-init-file} to
+@file{~/.gnus}, it will look for @file{~/.gnus.elc}, @file{~/.gnus.el},
+and finally @file{~/.gnus} (in this order).  If Emacs was invoked with
+the @option{-q} or @option{--no-init-file} options (@pxref{Initial
+Options, ,Initial Options, emacs, The Emacs Manual}), Gnus doesn't read
+@code{gnus-init-file}.
+
+
+@node Auto Save
+@section Auto Save
+@cindex dribble file
+@cindex auto-save
+
+Whenever you do something that changes the Gnus data (reading articles,
+catching up, killing/subscribing groups), the change is added to a
+special @dfn{dribble buffer}.  This buffer is auto-saved the normal
+Emacs way.  If your Emacs should crash before you have saved the
+@file{.newsrc} files, all changes you have made can be recovered from
+this file.
+
+If Gnus detects this file at startup, it will ask the user whether to
+read it.  The auto save file is deleted whenever the real startup file is
+saved.
+
+@vindex gnus-use-dribble-file
+If @code{gnus-use-dribble-file} is @code{nil}, Gnus won't create and
+maintain a dribble buffer.  The default is @code{t}.
+
+@vindex gnus-dribble-directory
+Gnus will put the dribble file(s) in @code{gnus-dribble-directory}.  If
+this variable is @code{nil}, which it is by default, Gnus will dribble
+into the directory where the @file{.newsrc} file is located.  (This is
+normally the user's home directory.)  The dribble file will get the same
+file permissions as the @file{.newsrc} file.
+
+@vindex gnus-always-read-dribble-file
+If @code{gnus-always-read-dribble-file} is non-@code{nil}, Gnus will
+read the dribble file on startup without querying the user.
+
+
+@node The Active File
+@section The Active File
+@cindex active file
+@cindex ignored groups
+
+When Gnus starts, or indeed whenever it tries to determine whether new
+articles have arrived, it reads the active file.  This is a very large
+file that lists all the active groups and articles on the server.
+
+@vindex gnus-ignored-newsgroups
+Before examining the active file, Gnus deletes all lines that match the
+regexp @code{gnus-ignored-newsgroups}.  This is done primarily to reject
+any groups with bogus names, but you can use this variable to make Gnus
+ignore hierarchies you aren't ever interested in.  However, this is not
+recommended.  In fact, it's highly discouraged.  Instead, @pxref{New
+Groups} for an overview of other variables that can be used instead.
+
+@c This variable is
+@c @code{nil} by default, and will slow down active file handling somewhat
+@c if you set it to anything else.
+
+@vindex gnus-read-active-file
+@c @head
+The active file can be rather Huge, so if you have a slow network, you
+can set @code{gnus-read-active-file} to @code{nil} to prevent Gnus from
+reading the active file.  This variable is @code{some} by default.
+
+Gnus will try to make do by getting information just on the groups that
+you actually subscribe to.
+
+Note that if you subscribe to lots and lots of groups, setting this
+variable to @code{nil} will probably make Gnus slower, not faster.  At
+present, having this variable @code{nil} will slow Gnus down
+considerably, unless you read news over a 2400 baud modem.
+
+This variable can also have the value @code{some}.  Gnus will then
+attempt to read active info only on the subscribed groups.  On some
+servers this is quite fast (on sparkling, brand new INN servers that
+support the @code{LIST ACTIVE group} command), on others this isn't fast
+at all.  In any case, @code{some} should be faster than @code{nil}, and
+is certainly faster than @code{t} over slow lines.
+
+Some news servers (old versions of Leafnode and old versions of INN, for
+instance) do not support the @code{LIST ACTIVE group}.  For these
+servers, @code{nil} is probably the most efficient value for this
+variable.
+
+If this variable is @code{nil}, Gnus will ask for group info in total
+lock-step, which isn't very fast.  If it is @code{some} and you use an
+@acronym{NNTP} server, Gnus will pump out commands as fast as it can, and
+read all the replies in one swoop.  This will normally result in better
+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.
+
+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.
+
+Note that this variable also affects active file retrieval from
+secondary select methods.
+
+
+@node Startup Variables
+@section Startup Variables
+
+@table @code
+
+@item gnus-load-hook
+@vindex gnus-load-hook
+A hook run while Gnus is being loaded.  Note that this hook will
+normally be run just once in each Emacs session, no matter how many
+times you start Gnus.
+
+@item gnus-before-startup-hook
+@vindex gnus-before-startup-hook
+A hook called as the first thing when Gnus is started.
+
+@item gnus-before-resume-hook
+@vindex gnus-before-resume-hook
+A hook called as the first thing when Gnus is resumed after a suspend.
+
+@item gnus-startup-hook
+@vindex gnus-startup-hook
+A hook run as the very last thing after starting up Gnus
+
+@item gnus-started-hook
+@vindex gnus-started-hook
+A hook that is run as the very last thing after starting up Gnus
+successfully.
+
+@item gnus-setup-news-hook
+@vindex gnus-setup-news-hook
+A hook that is run after reading the @file{.newsrc} file(s), but before
+generating the group buffer.
+
+@item gnus-check-bogus-newsgroups
+@vindex gnus-check-bogus-newsgroups
+If non-@code{nil}, Gnus will check for and delete all bogus groups at
+startup.  A @dfn{bogus group} is a group that you have in your
+@file{.newsrc} file, but doesn't exist on the news server.  Checking for
+bogus groups can take quite a while, so to save time and resources it's
+best to leave this option off, and do the checking for bogus groups once
+in a while from the group buffer instead (@pxref{Group Maintenance}).
+
+@item gnus-inhibit-startup-message
+@vindex gnus-inhibit-startup-message
+If non-@code{nil}, the startup message won't be displayed.  That way,
+your boss might not notice as easily that you are reading news instead
+of doing your job.  Note that this variable is used before
+@file{~/.gnus.el} is loaded, so it should be set in @file{.emacs} instead.
+
+@item gnus-no-groups-message
+@vindex gnus-no-groups-message
+Message displayed by Gnus when no groups are available.
+
+@item gnus-use-backend-marks
+@vindex gnus-use-backend-marks
+If non-@code{nil}, Gnus will store article marks both in the
+@file{.newsrc.eld} file and in the backends.  This will slow down
+group operation some.
+
+@end table
+
+
+@node Group Buffer
+@chapter Group Buffer
+@cindex group buffer
+
+@c Alex Schroeder suggests to rearrange this as follows:
+@c
+@c <kensanata> ok, just save it for reference.  I'll go to bed in a minute.
+@c   1. Selecting a Group, 2. (new) Finding a Group, 3. Group Levels,
+@c   4. Subscription Commands, 5. Group Maneuvering, 6. Group Data,
+@c   7. Group Score, 8. Group Buffer Format
+@c <kensanata> Group Levels should have more information on levels 5 to 9.  I
+@c   suggest to split the 4th paragraph ("Gnus considers groups...") as follows:
+@c <kensanata> First, "Gnus considers groups... (default 9)."
+@c <kensanata> New, a table summarizing what levels 1 to 9 mean.
+@c <kensanata> Third, "Gnus treats subscribed ... reasons of efficiency"
+@c <kensanata> Then expand the next paragraph or add some more to it.
+@c    This short one sentence explains levels 1 and 2, therefore I understand
+@c    that I should keep important news at 3 and boring news at 4.
+@c    Say so!  Then go on to explain why I should bother with levels 6 to 9.
+@c    Maybe keep those that you don't want to read temporarily at 6,
+@c    those that you never want to read at 8, those that offend your
+@c    human rights at 9...
+
+
+The @dfn{group buffer} lists all (or parts) of the available groups.  It
+is the first buffer shown when Gnus starts, and will never be killed as
+long as Gnus is active.
+
+@iftex
+@iflatex
+\gnusfigure{The Group Buffer}{320}{
+\put(75,50){\epsfig{figure=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}}
+\put(40,58){\vector(1,0){30}}
+\put(200,28){\makebox(0,0)[t]{Native select method}}
+\put(200,26){\vector(-1,2){15}}
+}
+@end iflatex
+@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.
+* 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.
+* Non-ASCII Group Names::       Accessing groups of non-English names.
+* Misc Group Stuff::            Other stuff that you can to do.
+@end menu
+
+
+@node Group Buffer Format
+@section Group Buffer Format
+
+@menu
+* Group Line Specification::    Deciding how the group buffer is to look.
+* Group Mode Line Specification::  The group buffer mode line.
+* Group Highlighting::          Having nice colors in the group buffer.
+@end menu
+
+You can customize the Group Mode tool bar, see @kbd{M-x
+customize-apropos RET gnus-group-tool-bar}.  This feature is only
+available in Emacs.
+
+The tool bar icons are now (de)activated correctly depending on the
+cursor position.  Therefore, moving around in the Group Buffer is
+slower.  You can disable this via the variable
+@code{gnus-group-update-tool-bar}.  Its default value depends on your
+Emacs version.
+
+@node Group Line Specification
+@subsection Group Line Specification
+@cindex group buffer format
+
+The default format of the group buffer is nice and dull, but you can
+make it as exciting and ugly as you feel like.
+
+Here's a couple of example group lines:
+
+@example
+     25: news.announce.newusers
+ *    0: alt.fan.andrea-dworkin
+@end example
+
+Quite simple, huh?
+
+You can see that there are 25 unread articles in
+@samp{news.announce.newusers}.  There are no unread articles, but some
+ticked articles, in @samp{alt.fan.andrea-dworkin} (see that little
+asterisk at the beginning of the line?).
+
+@vindex gnus-group-line-format
+You can change that format to whatever you want by fiddling with the
+@code{gnus-group-line-format} variable.  This variable works along the
+lines of a @code{format} specification, which is pretty much the same as
+a @code{printf} specifications, for those of you who use (feh!) C@.
+@xref{Formatting Variables}.
+
+@samp{%M%S%5y:%B%(%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.  @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
+instead of wasting time reading news.)
+
+Here's a list of all available format characters:
+
+@table @samp
+
+@item M
+An asterisk if the group only has marked articles.
+
+@item S
+Whether the group is subscribed.
+
+@item L
+Level of subscribedness.
+
+@item N
+Number of unread articles.
+
+@item I
+Number of dormant articles.
+
+@item T
+Number of ticked articles.
+
+@item R
+Number of read articles.
+
+@item U
+Number of unseen articles.
+
+@item t
+Estimated total number of articles.  (This is really @var{max-number}
+minus @var{min-number} plus 1.)
+
+Gnus uses this estimation because the @acronym{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.
+
+The nnml backend (@pxref{Mail Spool}) has a feature called ``group
+compaction'' which circumvents this deficiency: the idea is to
+renumber all articles from 1, removing all gaps between numbers, hence
+getting a correct total count.  Other backends may support this in the
+future.  In order to keep your total article count relatively up to
+date, you might want to compact your groups (or even directly your
+server) from time to time. @xref{Misc Group Stuff}, @xref{Server Commands}.
+
+@item y
+Number of unread, unticked, non-dormant articles.
+
+@item i
+Number of ticked and dormant articles.
+
+@item g
+Full group name.
+
+@item G
+Group name.
+
+@item C
+Group comment (@pxref{Group Parameters}) or group name if there is no
+comment element in the group parameters.
+
+@item D
+Newsgroup description.  You need to read the group descriptions
+before these will appear, and to do that, you either have to set
+@code{gnus-read-active-file} or use the group buffer @kbd{M-d}
+command.
+
+@item o
+@samp{m} if moderated.
+
+@item O
+@samp{(m)} if moderated.
+
+@item s
+Select method.
+
+@item B
+If the summary buffer for the group is open or not.
+
+@item n
+Select from where.
+
+@item z
+A string that looks like @samp{<%s:%n>} if a foreign select method is
+used.
+
+@item P
+Indentation based on the level of the topic (@pxref{Group Topics}).
+
+@item c
+@vindex gnus-group-uncollapsed-levels
+Short (collapsed) group name.  The @code{gnus-group-uncollapsed-levels}
+variable says how many levels to leave at the end of the group name.
+The default is 1---this will mean that group names like
+@samp{gnu.emacs.gnus} will be shortened to @samp{g.e.gnus}.
+
+@item m
+@vindex gnus-new-mail-mark
+@cindex %
+@samp{%} (@code{gnus-new-mail-mark}) if there has arrived new mail to
+the group lately.
+
+@item p
+@samp{#} (@code{gnus-process-mark}) if the group is process marked.
+
+@item d
+A string that says when you last read the group (@pxref{Group
+Timestamp}).
+
+@item F
+The disk space used by the articles fetched by both the cache and
+agent.  The value is automatically scaled to bytes(B), kilobytes(K),
+megabytes(M), or gigabytes(G) to minimize the column width.  A format
+of %7F is sufficient for a fixed-width column.
+
+@item u
+User defined specifier.  The next character in the format string should
+be a letter.  Gnus will call the function
+@code{gnus-user-format-function-}@samp{X}, where @samp{X} is the letter
+following @samp{%u}.  The function will be passed a single dummy
+parameter as argument.  The function should return a string, which will
+be inserted into the buffer just like information from any other
+specifier.
+@end table
+
+@cindex *
+All the ``number-of'' specs will be filled with an asterisk (@samp{*})
+if no info is available---for instance, if it is a non-activated foreign
+group, or a bogus native group.
+
+
+@node Group Mode Line Specification
+@subsection Group Mode Line Specification
+@cindex group mode line
+
+@vindex gnus-group-mode-line-format
+The mode line can be changed by setting
+@code{gnus-group-mode-line-format} (@pxref{Mode Line Formatting}).  It
+doesn't understand that many format specifiers:
+
+@table @samp
+@item S
+The native news server.
+@item M
+The native select method.
+@end table
+
+
+@node Group Highlighting
+@subsection Group Highlighting
+@cindex highlighting
+@cindex group highlighting
+
+@vindex gnus-group-highlight
+Highlighting in the group buffer is controlled by the
+@code{gnus-group-highlight} variable.  This is an alist with elements
+that look like @code{(@var{form} . @var{face})}.  If @var{form} evaluates to
+something non-@code{nil}, the @var{face} will be used on the line.
+
+Here's an example value for this variable that might look nice if the
+background is dark:
+
+@lisp
+(cond (window-system
+       (setq custom-background-mode 'light)
+       (defface my-group-face-1
+         '((t (:foreground "Red" :bold t))) "First group face")
+       (defface my-group-face-2
+         '((t (:foreground "DarkSeaGreen4" :bold t)))
+         "Second group face")
+       (defface my-group-face-3
+         '((t (:foreground "Green4" :bold t))) "Third group face")
+       (defface my-group-face-4
+         '((t (:foreground "SteelBlue" :bold t))) "Fourth group face")
+       (defface my-group-face-5
+         '((t (:foreground "Blue" :bold t))) "Fifth group face")))
+
+(setq gnus-group-highlight
+      '(((> unread 200) . my-group-face-1)
+        ((and (< level 3) (zerop unread)) . my-group-face-2)
+        ((< level 3) . my-group-face-3)
+        ((zerop unread) . my-group-face-4)
+        (t . my-group-face-5)))
+@end lisp
+
+Also @pxref{Faces and Fonts}.
+
+Variables that are dynamically bound when the forms are evaluated
+include:
+
+@table @code
+@item group
+The group name.
+@item unread
+The number of unread articles in the group.
+@item method
+The select method.
+@item mailp
+Whether the group is a mail group.
+@item level
+The level of the group.
+@item score
+The score of the group.
+@item ticked
+The number of ticked articles in the group.
+@item total
+The total number of articles in the group.  Or rather,
+@var{max-number} minus @var{min-number} plus one.
+@item topic
+When using the topic minor mode, this variable is bound to the current
+topic being inserted.
+@end table
+
+When the forms are @code{eval}ed, point is at the beginning of the line
+of the group in question, so you can use many of the normal Gnus
+functions for snarfing info on the group.
+
+@vindex gnus-group-update-hook
+@findex gnus-group-highlight-line
+@code{gnus-group-update-hook} is called when a group line is changed.
+It will not be called when @code{gnus-visual} is @code{nil}.
+
+
+@node Group Maneuvering
+@section Group Maneuvering
+@cindex group movement
+
+All movement commands understand the numeric prefix and will behave as
+expected, hopefully.
+
+@table @kbd
+
+@item n
+@kindex n (Group)
+@findex gnus-group-next-unread-group
+Go to the next group that has unread articles
+(@code{gnus-group-next-unread-group}).
+
+@item p
+@itemx DEL
+@kindex DEL (Group)
+@kindex p (Group)
+@findex gnus-group-prev-unread-group
+Go to the previous group that has unread articles
+(@code{gnus-group-prev-unread-group}).
+
+@item N
+@kindex N (Group)
+@findex gnus-group-next-group
+Go to the next group (@code{gnus-group-next-group}).
+
+@item P
+@kindex P (Group)
+@findex gnus-group-prev-group
+Go to the previous group (@code{gnus-group-prev-group}).
+
+@item M-n
+@kindex M-n (Group)
+@findex gnus-group-next-unread-group-same-level
+Go to the next unread group on the same (or lower) level
+(@code{gnus-group-next-unread-group-same-level}).
+
+@item M-p
+@kindex M-p (Group)
+@findex gnus-group-prev-unread-group-same-level
+Go to the previous unread group on the same (or lower) level
+(@code{gnus-group-prev-unread-group-same-level}).
+@end table
+
+Three commands for jumping to groups:
+
+@table @kbd
+
+@item j
+@kindex j (Group)
+@findex gnus-group-jump-to-group
+Jump to a group (and make it visible if it isn't already)
+(@code{gnus-group-jump-to-group}).  Killed groups can be jumped to, just
+like living groups.
+
+@item ,
+@kindex , (Group)
+@findex gnus-group-best-unread-group
+Jump to the unread group with the lowest level
+(@code{gnus-group-best-unread-group}).
+
+@item .
+@kindex . (Group)
+@findex gnus-group-first-unread-group
+Jump to the first group with unread articles
+(@code{gnus-group-first-unread-group}).
+@end table
+
+@vindex gnus-group-goto-unread
+If @code{gnus-group-goto-unread} is @code{nil}, all the movement
+commands will move to the next group, not the next unread group.  Even
+the commands that say they move to the next unread group.  The default
+is @code{t}.
+
+@vindex gnus-summary-next-group-on-exit
+If @code{gnus-summary-next-group-on-exit} is @code{t}, when a summary is
+exited, the point in the group buffer is moved to the next unread group.
+Otherwise, the point is set to the group just exited.  The default is
+@code{t}.
+
+@node Selecting a Group
+@section Selecting a Group
+@cindex group selection
+
+@table @kbd
+
+@item SPACE
+@kindex SPACE (Group)
+@findex gnus-group-read-group
+Select the current group, switch to the summary buffer and display the
+first unread article (@code{gnus-group-read-group}).  If there are no
+unread articles in the group, or if you give a non-numerical prefix to
+this command, Gnus will offer to fetch all the old articles in this
+group from the server.  If you give a numerical prefix @var{n}, @var{n}
+determines the number of articles Gnus will fetch.  If @var{n} is
+positive, Gnus fetches the @var{n} newest articles, if @var{n} is
+negative, Gnus fetches the @code{abs(@var{n})} oldest articles.
+
+Thus, @kbd{SPC} enters the group normally, @kbd{C-u SPC} offers old
+articles, @kbd{C-u 4 2 SPC} fetches the 42 newest articles, and @kbd{C-u
+- 4 2 SPC} fetches the 42 oldest ones.
+
+When you are in the group (in the Summary buffer), you can type
+@kbd{M-g} to fetch new articles, or @kbd{C-u M-g} to also show the old
+ones.
+
+@item RET
+@kindex RET (Group)
+@findex gnus-group-select-group
+Select the current group and switch to the summary buffer
+(@code{gnus-group-select-group}).  Takes the same arguments as
+@code{gnus-group-read-group}---the only difference is that this command
+does not display the first unread article automatically upon group
+entry.
+
+@item M-RET
+@kindex M-RET (Group)
+@findex gnus-group-quick-select-group
+This does the same as the command above, but tries to do it with the
+minimum amount of fuzz (@code{gnus-group-quick-select-group}).  No
+scoring/killing will be performed, there will be no highlights and no
+expunging.  This might be useful if you're in a real hurry and have to
+enter some humongous group.  If you give a 0 prefix to this command
+(i.e., @kbd{0 M-RET}), Gnus won't even generate the summary buffer,
+which is useful if you want to toggle threading before generating the
+summary buffer (@pxref{Summary Generation Commands}).
+
+@item M-SPACE
+@kindex M-SPACE (Group)
+@findex gnus-group-visible-select-group
+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 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
+(@code{gnus-group-select-group-ephemerally}).  Even threading has been
+turned off.  Everything you do in the group after selecting it in this
+manner will have no permanent effects.
+
+@end table
+
+@vindex gnus-large-newsgroup
+The @code{gnus-large-newsgroup} variable says what Gnus should
+consider to be a big group.  If it is @code{nil}, no groups are
+considered big.  The default value is 200.  If the group has more
+(unread and/or ticked) articles than this, Gnus will query the user
+before entering the group.  The user can then specify how many
+articles should be fetched from the server.  If the user specifies a
+negative number (@var{-n}), the @var{n} oldest articles will be
+fetched.  If it is positive, the @var{n} articles that have arrived
+most recently will be fetched.
+
+@vindex gnus-large-ephemeral-newsgroup
+@code{gnus-large-ephemeral-newsgroup} is the same as
+@code{gnus-large-newsgroup}, but is only used for ephemeral
+newsgroups.
+
+@vindex gnus-newsgroup-maximum-articles
+In groups in some news servers, there might be a big gap between a few
+very old articles that will never be expired and the recent ones.  In
+such a case, the server will return the data like @code{(1 . 30000000)}
+for the @code{LIST ACTIVE group} command, for example.  Even if there
+are actually only the articles 1--10 and 29999900--30000000, Gnus doesn't
+know it at first and prepares for getting 30000000 articles.  However,
+it will consume hundreds megabytes of memories and might make Emacs get
+stuck as the case may be.  If you use such news servers, set the
+variable @code{gnus-newsgroup-maximum-articles} to a positive number.
+The value means that Gnus ignores articles other than this number of the
+latest ones in every group.  For instance, the value 10000 makes Gnus
+get only the articles 29990001--30000000 (if the latest article number is
+30000000 in a group).  Note that setting this variable to a number might
+prevent you from reading very old articles.  The default value of the
+variable @code{gnus-newsgroup-maximum-articles} is @code{nil}, which
+means Gnus never ignores old articles.
+
+@vindex gnus-select-group-hook
+@vindex gnus-auto-select-first
+@vindex gnus-auto-select-subject
+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 controlled by the
+@code{gnus-auto-select-subject} variable.  Valid values for this
+variable are:
+
+@table @code
+
+@item unread
+Place point on the subject line of the first unread article.
+
+@item first
+Place point on the subject line of the first article.
+
+@item unseen
+Place point on the subject line of the first unseen article.
+
+@item unseen-or-unread
+Place point on the subject line of the first unseen article, and if
+there is no such article, place point on the subject line of the first
+unread article.
+
+@item best
+Place point on the subject line of 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 the
+@code{gnus-auto-select-first} variable to @code{nil} in
+@code{gnus-select-group-hook}, which is called when a group is
+selected.
+
+
+@node Subscription Commands
+@section Subscription Commands
+@cindex subscription
+
+The following commands allow for managing your subscriptions in the
+Group buffer.  If you want to subscribe to many groups, it's probably
+more convenient to go to the @ref{Server Buffer}, and choose the
+server there using @kbd{RET} or @kbd{SPC}.  Then you'll have the
+commands listed in @ref{Browse Foreign Server} at hand.
+
+@table @kbd
+
+@item S t
+@itemx u
+@kindex S t (Group)
+@kindex u (Group)
+@findex gnus-group-unsubscribe-current-group
+@c @icon{gnus-group-unsubscribe}
+Toggle subscription to the current group
+(@code{gnus-group-unsubscribe-current-group}).
+
+@item S s
+@itemx U
+@kindex S s (Group)
+@kindex U (Group)
+@findex gnus-group-unsubscribe-group
+Prompt for a group to subscribe, and then subscribe it.  If it was
+subscribed already, unsubscribe it instead
+(@code{gnus-group-unsubscribe-group}).
+
+@item S k
+@itemx C-k
+@kindex S k (Group)
+@kindex C-k (Group)
+@findex gnus-group-kill-group
+@c @icon{gnus-group-kill-group}
+Kill the current group (@code{gnus-group-kill-group}).
+
+@item S y
+@itemx C-y
+@kindex S y (Group)
+@kindex C-y (Group)
+@findex gnus-group-yank-group
+Yank the last killed group (@code{gnus-group-yank-group}).
+
+@item C-x C-t
+@kindex C-x C-t (Group)
+@findex gnus-group-transpose-groups
+Transpose two groups (@code{gnus-group-transpose-groups}).  This isn't
+really a subscription command, but you can use it instead of a
+kill-and-yank sequence sometimes.
+
+@item S w
+@itemx C-w
+@kindex S w (Group)
+@kindex C-w (Group)
+@findex gnus-group-kill-region
+Kill all groups in the region (@code{gnus-group-kill-region}).
+
+@item S z
+@kindex S z (Group)
+@findex gnus-group-kill-all-zombies
+Kill all zombie groups (@code{gnus-group-kill-all-zombies}).
+
+@item S C-k
+@kindex S C-k (Group)
+@findex gnus-group-kill-level
+Kill all groups on a certain level (@code{gnus-group-kill-level}).
+These groups can't be yanked back after killing, so this command should
+be used with some caution.  The only time where this command comes in
+really handy is when you have a @file{.newsrc} with lots of unsubscribed
+groups that you want to get rid off.  @kbd{S C-k} on level 7 will
+kill off all unsubscribed groups that do not have message numbers in the
+@file{.newsrc} file.
+
+@end table
+
+Also @pxref{Group Levels}.
+
+
+@node Group Data
+@section Group Data
+
+@table @kbd
+
+@item c
+@kindex c (Group)
+@findex gnus-group-catchup-current
+@vindex gnus-group-catchup-group-hook
+@c @icon{gnus-group-catchup-current}
+Mark all unticked articles in this group as read
+(@code{gnus-group-catchup-current}).
+@code{gnus-group-catchup-group-hook} is called when catching up a group from
+the group buffer.
+
+@item C
+@kindex C (Group)
+@findex gnus-group-catchup-current-all
+Mark all articles in this group, even the ticked ones, as read
+(@code{gnus-group-catchup-current-all}).
+
+@item M-c
+@kindex M-c (Group)
+@findex gnus-group-clear-data
+Clear the data from the current group---nix out marks and the list of
+read articles (@code{gnus-group-clear-data}).
+
+@item M-x gnus-group-clear-data-on-native-groups
+@kindex M-x gnus-group-clear-data-on-native-groups
+@findex gnus-group-clear-data-on-native-groups
+If you have switched from one @acronym{NNTP} server to another, all your marks
+and read ranges have become worthless.  You can use this command to
+clear out all data that you have on your native groups.  Use with
+caution.
+
+@end table
+
+
+@node Group Levels
+@section Group Levels
+@cindex group level
+@cindex level
+
+All groups have a level of @dfn{subscribedness}.  For instance, if a
+group is on level 2, it is more subscribed than a group on level 5.  You
+can ask Gnus to just list groups on a given level or lower
+(@pxref{Listing Groups}), or to just check for new articles in groups on
+a given level or lower (@pxref{Scanning New Messages}).
+
+Remember:  The higher the level of the group, the less important it is.
+
+@table @kbd
+
+@item S l
+@kindex S l (Group)
+@findex gnus-group-set-current-level
+Set the level of the current group.  If a numeric prefix is given, the
+next @var{n} groups will have their levels set.  The user will be
+prompted for a level.
+@end table
+
+@vindex gnus-level-killed
+@vindex gnus-level-zombie
+@vindex gnus-level-unsubscribed
+@vindex gnus-level-subscribed
+Gnus considers groups from levels 1 to
+@code{gnus-level-subscribed} (inclusive) (default 5) to be subscribed,
+@code{gnus-level-subscribed} (exclusive) and
+@code{gnus-level-unsubscribed} (inclusive) (default 7) to be
+unsubscribed, @code{gnus-level-zombie} to be zombies (walking dead)
+(default 8) and @code{gnus-level-killed} to be killed (completely dead)
+(default 9).  Gnus treats subscribed and unsubscribed groups exactly the
+same, but zombie and killed groups store no information on what articles
+you have read, etc.  This distinction between dead and living
+groups isn't done because it is nice or clever, it is done purely for
+reasons of efficiency.
+
+It is recommended that you keep all your mail groups (if any) on quite
+low levels (e.g., 1 or 2).
+
+Maybe the following description of the default behavior of Gnus helps to
+understand what these levels are all about.  By default, Gnus shows you
+subscribed nonempty groups, but by hitting @kbd{L} you can have it show
+empty subscribed groups and unsubscribed groups, too.  Type @kbd{l} to
+go back to showing nonempty subscribed groups again.  Thus, unsubscribed
+groups are hidden, in a way.
+
+@cindex zombie groups
+Zombie and killed groups are similar to unsubscribed groups in that they
+are hidden by default.  But they are different from subscribed and
+unsubscribed groups in that Gnus doesn't ask the news server for
+information (number of messages, number of unread messages) on zombie
+and killed groups.  Normally, you use @kbd{C-k} to kill the groups you
+aren't interested in.  If most groups are killed, Gnus is faster.
+
+Why does Gnus distinguish between zombie and killed groups?  Well, when
+a new group arrives on the server, Gnus by default makes it a zombie
+group.  This means that you are normally not bothered with new groups,
+but you can type @kbd{A z} to get a list of all new groups.  Subscribe
+the ones you like and kill the ones you don't want.  (@kbd{A k} shows a
+list of killed groups.)
+
+If you want to play with the level variables, you should show some care.
+Set them once, and don't touch them ever again.  Better yet, don't touch
+them at all unless you know exactly what you're doing.
+
+@vindex gnus-level-default-unsubscribed
+@vindex gnus-level-default-subscribed
+Two closely related variables are @code{gnus-level-default-subscribed}
+(default 3) and @code{gnus-level-default-unsubscribed} (default 6),
+which are the levels that new groups will be put on if they are
+(un)subscribed.  These two variables should, of course, be inside the
+relevant valid ranges.
+
+@vindex gnus-keep-same-level
+If @code{gnus-keep-same-level} is non-@code{nil}, some movement commands
+will only move to groups of the same level (or lower).  In
+particular, going from the last article in one group to the next group
+will go to the next group of the same level (or lower).  This might be
+handy if you want to read the most important groups before you read the
+rest.
+
+If this variable is @code{best}, Gnus will make the next newsgroup the
+one with the best level.
+
+@vindex gnus-group-default-list-level
+All groups with a level less than or equal to
+@code{gnus-group-default-list-level} will be listed in the group buffer
+by default.
+This variable can also be a function.  In that case, that function will
+be called and the result will be used as value.
+
+
+@vindex gnus-group-list-inactive-groups
+If @code{gnus-group-list-inactive-groups} is non-@code{nil}, non-active
+groups will be listed along with the unread groups.  This variable is
+@code{t} by default.  If it is @code{nil}, inactive groups won't be
+listed.
+
+@vindex gnus-group-use-permanent-levels
+If @code{gnus-group-use-permanent-levels} is non-@code{nil}, once you
+give a level prefix to @kbd{g} or @kbd{l}, all subsequent commands will
+use this level as the ``work'' level.
+
+@vindex gnus-activate-level
+Gnus will normally just activate (i.e., query the server about) groups
+on level @code{gnus-activate-level} or less.  If you don't want to
+activate unsubscribed groups, for instance, you might set this variable
+to 5.  The default is 6.
+
+
+@node Group Score
+@section Group Score
+@cindex group score
+@cindex group rank
+@cindex rank
+
+You would normally keep important groups on high levels, but that scheme
+is somewhat restrictive.  Don't you wish you could have Gnus sort the
+group buffer according to how often you read groups, perhaps?  Within
+reason?
+
+This is what @dfn{group score} is for.  You can have Gnus assign a score
+to each group through the mechanism described below.  You can then sort
+the group buffer based on this score.  Alternatively, you can sort on
+score and then level.  (Taken together, the level and the score is
+called the @dfn{rank} of the group.  A group that is on level 4 and has
+a score of 1 has a higher rank than a group on level 5 that has a score
+of 300.  (The level is the most significant part and the score is the
+least significant part.))
+
+@findex gnus-summary-bubble-group
+If you want groups you read often to get higher scores than groups you
+read seldom you can add the @code{gnus-summary-bubble-group} function to
+the @code{gnus-summary-exit-hook} hook.  This will result (after
+sorting) in a bubbling sort of action.  If you want to see that in
+action after each summary exit, you can add
+@code{gnus-group-sort-groups-by-rank} or
+@code{gnus-group-sort-groups-by-score} to the same hook, but that will
+slow things down somewhat.
+
+
+@node Marking Groups
+@section Marking Groups
+@cindex marking groups
+
+If you want to perform some command on several groups, and they appear
+subsequently in the group buffer, you would normally just give a
+numerical prefix to the command.  Most group commands will then do your
+bidding on those groups.
+
+However, if the groups are not in sequential order, you can still
+perform a command on several groups.  You simply mark the groups first
+with the process mark and then execute the command.
+
+@table @kbd
+
+@item #
+@kindex # (Group)
+@itemx M m
+@kindex M m (Group)
+@findex gnus-group-mark-group
+Set the mark on the current group (@code{gnus-group-mark-group}).
+
+@item M-#
+@kindex M-# (Group)
+@itemx M u
+@kindex M u (Group)
+@findex gnus-group-unmark-group
+Remove the mark from the current group
+(@code{gnus-group-unmark-group}).
+
+@item M U
+@kindex M U (Group)
+@findex gnus-group-unmark-all-groups
+Remove the mark from all groups (@code{gnus-group-unmark-all-groups}).
+
+@item M w
+@kindex M w (Group)
+@findex gnus-group-mark-region
+Mark all groups between point and mark (@code{gnus-group-mark-region}).
+
+@item M b
+@kindex M b (Group)
+@findex gnus-group-mark-buffer
+Mark all groups in the buffer (@code{gnus-group-mark-buffer}).
+
+@item M r
+@kindex M r (Group)
+@findex gnus-group-mark-regexp
+Mark all groups that match some regular expression
+(@code{gnus-group-mark-regexp}).
+@end table
+
+Also @pxref{Process/Prefix}.
+
+@findex gnus-group-universal-argument
+If you want to execute some command on all groups that have been marked
+with the process mark, you can use the @kbd{M-&}
+(@code{gnus-group-universal-argument}) command.  It will prompt you for
+the command to be executed.
+
+
+@node Foreign Groups
+@section Foreign Groups
+@cindex foreign groups
+
+If you recall how to subscribe to servers (@pxref{Finding the News})
+you will remember that @code{gnus-secondary-select-methods} and
+@code{gnus-select-method} let you write a definition in Emacs Lisp of
+what servers you want to see when you start up.  The alternate
+approach is to use foreign servers and groups.  ``Foreign'' here means
+they are not coming from the select methods.  All foreign server
+configuration and subscriptions are stored only in the
+@file{~/.newsrc.eld} file.
+
+Below are some group mode commands for making and editing general foreign
+groups, as well as commands to ease the creation of a few
+special-purpose groups.  All these commands insert the newly created
+groups under point---@code{gnus-subscribe-newsgroup-method} is not
+consulted.
+
+Changes from the group editing commands are stored in
+@file{~/.newsrc.eld} (@code{gnus-startup-file}).  An alternative is the
+variable @code{gnus-parameters}, @xref{Group Parameters}.
+
+@table @kbd
+
+@item G m
+@kindex G m (Group)
+@findex gnus-group-make-group
+@cindex making groups
+Make a new group (@code{gnus-group-make-group}).  Gnus will prompt you
+for a name, a method and possibly an @dfn{address}.  For an easier way
+to subscribe to @acronym{NNTP} groups (@pxref{Browse Foreign Server}).
+
+@item G M
+@kindex G M (Group)
+@findex gnus-group-read-ephemeral-group
+Make an ephemeral group (@code{gnus-group-read-ephemeral-group}).  Gnus
+will prompt you for a name, a method and an @dfn{address}.
+
+@item G r
+@kindex G r (Group)
+@findex gnus-group-rename-group
+@cindex renaming groups
+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 back ends.
+
+@item G c
+@kindex G c (Group)
+@cindex customizing
+@findex gnus-group-customize
+Customize the group parameters (@code{gnus-group-customize}).
+
+@item G e
+@kindex G e (Group)
+@findex gnus-group-edit-group-method
+@cindex renaming groups
+Enter a buffer where you can edit the select method of the current
+group (@code{gnus-group-edit-group-method}).
+
+@item G p
+@kindex G p (Group)
+@findex gnus-group-edit-group-parameters
+Enter a buffer where you can edit the group parameters
+(@code{gnus-group-edit-group-parameters}).
+
+@item G E
+@kindex G E (Group)
+@findex gnus-group-edit-group
+Enter a buffer where you can edit the group info
+(@code{gnus-group-edit-group}).
+
+@item G d
+@kindex G d (Group)
+@findex gnus-group-make-directory-group
+@cindex nndir
+Make a directory group (@pxref{Directory Groups}).  You will be prompted
+for a directory name (@code{gnus-group-make-directory-group}).
+
+@item G h
+@kindex G h (Group)
+@cindex help group
+@findex gnus-group-make-help-group
+Make the Gnus help group (@code{gnus-group-make-help-group}).
+
+@item G D
+@kindex G D (Group)
+@findex gnus-group-enter-directory
+@cindex nneething
+Read an arbitrary directory as if it were a newsgroup with the
+@code{nneething} back end (@code{gnus-group-enter-directory}).
+@xref{Anything Groups}.
+
+@item G f
+@kindex G f (Group)
+@findex gnus-group-make-doc-group
+@cindex ClariNet Briefs
+@cindex nndoc
+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{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
+@kindex G u (Group)
+@vindex gnus-useful-groups
+@findex gnus-group-make-useful-group
+Create one of the groups mentioned in @code{gnus-useful-groups}
+(@code{gnus-group-make-useful-group}).
+
+@item G w
+@kindex G w (Group)
+@findex gnus-group-make-web-group
+@cindex Google
+@cindex nnweb
+@cindex gmane
+Make an ephemeral group based on a web search
+(@code{gnus-group-make-web-group}).  If you give a prefix to this
+command, make a solid group instead.  You will be prompted for the
+search engine type and the search string.  Valid search engine types
+include @code{google}, @code{dejanews}, and @code{gmane}.
+@xref{Web Searches}.
+
+If you use the @code{google} search engine, you can limit the search
+to a particular group by using a match string like
+@samp{shaving group:alt.sysadmin.recovery}.
+
+@item G R
+@kindex G R (Group)
+@findex gnus-group-make-rss-group
+Make a group based on an @acronym{RSS} feed
+(@code{gnus-group-make-rss-group}).  You will be prompted for an URL@.
+@xref{RSS}.
+
+@item G DEL
+@kindex G DEL (Group)
+@findex gnus-group-delete-group
+This function will delete the current group
+(@code{gnus-group-delete-group}).  If given a prefix, this function will
+actually delete all the articles in the group, and forcibly remove the
+group itself from the face of the Earth.  Use a prefix only if you are
+absolutely sure of what you are doing.  This command can't be used on
+read-only groups (like @code{nntp} groups), though.
+
+@item G V
+@kindex G V (Group)
+@findex gnus-group-make-empty-virtual
+Make a new, fresh, empty @code{nnvirtual} group
+(@code{gnus-group-make-empty-virtual}).  @xref{Virtual Groups}.
+
+@item G v
+@kindex G v (Group)
+@findex gnus-group-add-to-virtual
+Add the current group to an @code{nnvirtual} group
+(@code{gnus-group-add-to-virtual}).  Uses the process/prefix convention.
+@end table
+
+@xref{Select Methods}, for more information on the various select
+methods.
+
+@vindex gnus-activate-foreign-newsgroups
+If @code{gnus-activate-foreign-newsgroups} is a positive number,
+Gnus will check all foreign groups with this level or lower at startup.
+This might take quite a while, especially if you subscribe to lots of
+groups from different @acronym{NNTP} servers.  Also @pxref{Group Levels};
+@code{gnus-activate-level} also affects activation of foreign
+newsgroups.
+
+
+The following commands create ephemeral groups.  They can be called not
+only from the Group buffer, but in any Gnus buffer.
+
+@table @code
+@item gnus-read-ephemeral-gmane-group
+@findex gnus-read-ephemeral-gmane-group
+@vindex gnus-gmane-group-download-format
+Read an ephemeral group on Gmane.org.  The articles are downloaded via
+HTTP using the URL specified by @code{gnus-gmane-group-download-format}.
+Gnus will prompt you for a group name, the start article number and an
+the article range.
+
+@item gnus-read-ephemeral-gmane-group-url
+@findex gnus-read-ephemeral-gmane-group-url
+This command is similar to @code{gnus-read-ephemeral-gmane-group}, but
+the group name and the article number and range are constructed from a
+given @acronym{URL}.  Supported @acronym{URL} formats include:
+@indicateurl{http://thread.gmane.org/gmane.foo.bar/12300/focus=12399},
+@indicateurl{http://thread.gmane.org/gmane.foo.bar/12345/},
+@indicateurl{http://article.gmane.org/gmane.foo.bar/12345/},
+@indicateurl{http://permalink.gmane.org/gmane.foo.bar/12345/}, and
+@indicateurl{http://news.gmane.org/group/gmane.foo.bar/thread=12345}.
+
+@item gnus-read-ephemeral-emacs-bug-group
+@findex gnus-read-ephemeral-emacs-bug-group
+Read an Emacs bug report in an ephemeral group.  Gnus will prompt for a
+bug number.  The default is the number at point.  The @acronym{URL} is
+specified in @code{gnus-bug-group-download-format-alist}.
+
+@item gnus-read-ephemeral-debian-bug-group
+@findex gnus-read-ephemeral-debian-bug-group
+Read a Debian bug report in an ephemeral group.  Analog to
+@code{gnus-read-ephemeral-emacs-bug-group}.
+@end table
+
+Some of these command are also useful for article buttons, @xref{Article
+Buttons}.
+
+Here is an example:
+@lisp
+(require 'gnus-art)
+(add-to-list
+ 'gnus-button-alist
+ '("#\\([0-9]+\\)\\>" 1
+   (string-match "\\<emacs\\>" (or gnus-newsgroup-name ""))
+   gnus-read-ephemeral-emacs-bug-group 1))
+@end lisp
+
+
+@node Group Parameters
+@section Group Parameters
+@cindex group parameters
+
+The group parameters store information local to a particular group.
+
+Use the @kbd{G p} or the @kbd{G c} command to edit group parameters of a
+group.  (@kbd{G p} presents you with a Lisp-based interface, @kbd{G c}
+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}).
+Additionally, you can set group parameters via the
+@code{gnus-parameters} variable, see below.
+
+Here's an example group parameter list:
+
+@example
+((to-address . "ding@@gnus.org")
+ (auto-expire . t))
+@end example
+
+We see that each element consists of a ``dotted pair''---the thing before
+the dot is the key, while the thing after the dot is the value.  All the
+parameters have this form @emph{except} local variable specs, which are
+not dotted pairs, but proper lists.
+
+Some parameters have correspondent customizable variables, each of which
+is an alist of regexps and values.
+
+The following group parameters can be used:
+
+@table @code
+@item to-address
+@cindex to-address
+Address used by when doing followups and new posts.
+
+@example
+(to-address . "some@@where.com")
+@end example
+
+This is primarily useful in mail groups that represent closed mailing
+lists---mailing lists where it's expected that everybody that writes to
+the mailing list is subscribed to it.  Since using this parameter
+ensures that the mail only goes to the mailing list itself, it means
+that members won't receive two copies of your followups.
+
+Using @code{to-address} will actually work whether the group is foreign
+or not.  Let's say there's a group on the server that is called
+@samp{fa.4ad-l}.  This is a real newsgroup, but the server has gotten
+the articles from a mail-to-news gateway.  Posting directly to this
+group is therefore impossible---you have to send mail to the mailing
+list address instead.
+
+See also @code{gnus-parameter-to-address-alist}.
+
+@item to-list
+@cindex to-list
+Address used when doing @kbd{a} in that group.
+
+@example
+(to-list . "some@@where.com")
+@end example
+
+It is totally ignored
+when doing a followup---except that if it is present in a news group,
+you'll get mail group semantics when doing @kbd{f}.
+
+If you do an @kbd{a} command in a mail group and you have neither a
+@code{to-list} group parameter nor a @code{to-address} group parameter,
+then a @code{to-list} group parameter will be added automatically upon
+sending the message if @code{gnus-add-to-list} is set to @code{t}.
+@vindex gnus-add-to-list
+
+@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}.
+
+@anchor{subscribed}
+@item subscribed
+@cindex subscribed
+@cindex Mail-Followup-To
+@findex gnus-find-subscribed-addresses
+If this parameter is set to @code{t}, Gnus will consider the
+to-address and to-list parameters for this group as addresses of
+mailing lists you are subscribed to.  Giving Gnus this information is
+(only) a first step in getting it to generate correct Mail-Followup-To
+headers for your posts to these lists.  The second step is to put the
+following in your @file{.gnus.el}
+
+@lisp
+(setq message-subscribed-address-functions
+      '(gnus-find-subscribed-addresses))
+@end lisp
+
+@xref{Mailing Lists, ,Mailing Lists, message, The Message Manual}, for
+a complete treatment of available MFT support.
+
+@item visible
+@cindex visible
+If the group parameter list has the element @code{(visible . t)},
+that group will always be visible in the Group buffer, regardless
+of whether it has any unread articles.
+
+This parameter cannot be set via @code{gnus-parameters}.  See
+@code{gnus-permanently-visible-groups} as an alternative.
+
+@item broken-reply-to
+@cindex broken-reply-to
+Elements like @code{(broken-reply-to . t)} signals that @code{Reply-To}
+headers in this group are to be ignored, and for the header to be hidden
+if @code{reply-to} is part of @code{gnus-boring-article-headers}.  This
+can be useful if you're reading a mailing list group where the listserv
+has inserted @code{Reply-To} headers that point back to the listserv
+itself.  That is broken behavior.  So there!
+
+@item to-group
+@cindex to-group
+Elements like @code{(to-group . "some.group.name")} means that all
+posts in that group will be sent to @code{some.group.name}.
+
+@item newsgroup
+@cindex newsgroup
+If you have @code{(newsgroup . t)} in the group parameter list, Gnus
+will treat all responses as if they were responses to news articles.
+This can be useful if you have a mail group that's really a mirror of a
+news group.
+
+@item gcc-self
+@cindex gcc-self
+If @code{(gcc-self . t)} is present in the group parameter list, newly
+composed messages will be @code{gcc}d to the current group.  If
+@code{(gcc-self . none)} is present, no @code{Gcc:} header will be
+generated, if @code{(gcc-self . "group")} is present, this string will
+be inserted literally as a @code{Gcc:} header.  It should be a group
+name.  The @code{gcc-self} value may also be a list of strings and
+@code{t}, e.g., @code{(gcc-self "group1" "group2" t)} means to
+@code{gcc} the newly composed message into the groups @code{"group1"}
+and @code{"group2"}, and into the current group.  The @code{gcc-self}
+parameter takes precedence over any default @code{Gcc} rules as
+described later (@pxref{Archived Messages}), with the exception for
+messages to resend.
+
+@strong{Caveat}: Adding @code{(gcc-self . t)} to the parameter list of
+@code{nntp} groups (or the like) isn't valid.  An @code{nntp} server
+doesn't accept articles.
+
+@item auto-expire
+@cindex auto-expire
+@cindex expiring mail
+If the group parameter has an element that looks like @code{(auto-expire
+. t)}, all articles read will be marked as expirable.  For an
+alternative approach, @pxref{Expiring Mail}.
+
+See also @code{gnus-auto-expirable-newsgroups}.
+
+@item total-expire
+@cindex total-expire
+@cindex expiring mail
+If the group parameter has an element that looks like
+@code{(total-expire . t)}, all read articles will be put through the
+expiry process, even if they are not marked as expirable.  Use with
+caution.  Unread, ticked and dormant articles are not eligible for
+expiry.
+
+See also @code{gnus-total-expirable-newsgroups}.
+
+@item expiry-wait
+@cindex expiry-wait
+@vindex nnmail-expiry-wait-function
+If the group parameter has an element that looks like
+@code{(expiry-wait . 10)}, this value will override any
+@code{nnmail-expiry-wait} and @code{nnmail-expiry-wait-function}
+(@pxref{Expiring Mail}) when expiring expirable messages.  The value
+can either be a number of days (not necessarily an integer) or the
+symbols @code{never} or @code{immediate}.
+
+@item expiry-target
+@cindex expiry-target
+Where expired messages end up.  This parameter overrides
+@code{nnmail-expiry-target}.
+
+@item score-file
+@cindex score file group parameter
+Elements that look like @code{(score-file . "file")} will make
+@file{file} into the current score file for the group in question.  All
+interactive score entries will be put into this file.
+
+@item adapt-file
+@cindex adapt file group parameter
+Elements that look like @code{(adapt-file . "file")} will make
+@file{file} into the current adaptive file for the group in question.
+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:
+
+@table @code
+@item all
+Display all articles, both read and unread.
+
+@item an integer
+Display the last @var{integer} articles in the group.  This is the same as
+entering the group with @kbd{C-u @var{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 [unread]
+Display only unread 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{unread}, @code{dormant}, @code{expire}, @code{reply},
+@code{killed}, @code{bookmark}, @code{score}, @code{save},
+@code{cache}, @code{forward}, and @code{unseen}.
+
+@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.  You can display comments in the
+group line (@pxref{Group Line Specification}).
+
+@item charset
+@cindex charset
+Elements that look like @code{(charset . iso-8859-1)} will make
+@code{iso-8859-1} the default charset; that is, the charset that will be
+used for all articles that do not specify a charset.
+
+See also @code{gnus-group-charset-alist}.
+
+@item ignored-charsets
+@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
+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
+the group name (of course).  Style elements in this group parameter will
+take precedence over the ones found in @code{gnus-posting-styles}.
+
+For instance, if you want a funky name and signature in this group only,
+instead of hacking @code{gnus-posting-styles}, you could put something
+like this in the group parameters:
+
+@example
+(posting-style
+  (name "Funky Name")
+  ("X-Message-SMTP-Method" "smtp smtp.example.org 587")
+  ("X-My-Header" "Funky Value")
+  (signature "Funky Signature"))
+@end example
+
+If you're using topics to organize your group buffer
+(@pxref{Group Topics}), note that posting styles can also be set in
+the topics parameters.  Posting styles in topic parameters apply to all
+groups in this topic.  More precisely, the posting-style settings for a
+group result from the hierarchical merging of all posting-style
+entries in the parameters of this group and all the topics it belongs
+to.
+
+
+@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 mail-source
+@cindex mail-source
+If it is set, and the setting of @code{mail-sources} includes a
+@code{group} mail source (@pxref{Mail Sources}), the value is a
+mail source for this group.
+
+@item banner
+@cindex banner
+An item like @code{(banner . @var{regexp})} causes any part of an article
+that matches the regular expression @var{regexp} to be stripped.  Instead of
+@var{regexp}, 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 @samp{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
+
+To generate tests for multiple email-addresses use a group parameter
+like @code{(sieve address "sender" ("name@@one.org" else@@two.org"))}.
+When generating a sieve script (@pxref{Sieve Commands}) Sieve code
+like the following is generated:
+
+@example
+if address "sender" ["name@@one.org", "else@@two.org"] @{
+        fileinto "INBOX.list.sieve";
+@}
+@end example
+
+You can also use regexp expansions in the rules:
+
+@example
+(sieve header :regex "list-id" "<c++std-\\1.accu.org>")
+@end example
+
+See @pxref{Sieve Commands} for commands and variables that might be of
+interest in relation to the sieve parameter.
+
+The Sieve language is described in RFC 3028.  @xref{Top, Emacs Sieve,
+Top, sieve, Emacs Sieve}.
+
+@item (agent parameters)
+If the agent has been enabled, you can set any of its parameters to
+control the behavior of the agent in individual groups.  See Agent
+Parameters in @ref{Category Syntax}.  Most users will choose to set
+agent parameters in either an agent category or group topic to
+minimize the configuration effort.
+
+@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},
+you could put @code{(gnus-show-threads nil)} in the group parameters of
+that group.  @code{gnus-show-threads} will be made into a local variable
+in the summary buffer you enter, and the form @code{nil} will be
+@code{eval}ed there.
+
+Note that this feature sets the variable locally to the summary buffer
+if and only if @var{variable} has been bound as a variable.  Otherwise,
+only evaluating the form will take place.  So, you may want to bind the
+variable in advance using @code{defvar} or other if the result of the
+form needs to be set to it.
+
+But some variables are evaluated in the article buffer, or in the
+message buffer (of a reply or followup or otherwise newly created
+message).  As a workaround, it might help to add the variable in
+question to @code{gnus-newsgroup-variables}.  @xref{Various Summary
+Stuff}.  So if you want to set @code{message-from-style} via the group
+parameters, then you may need the following statement elsewhere in your
+@file{~/.gnus.el} file:
+
+@lisp
+(add-to-list 'gnus-newsgroup-variables 'message-from-style)
+@end lisp
+
+@vindex gnus-list-identifiers
+A use for this feature is to remove a mailing list identifier tag in
+the subject fields of articles.  E.g., if the news group
+
+@example
+nntp+news.gnus.org:gmane.text.docbook.apps
+@end example
+
+has the tag @samp{DOC-BOOK-APPS:} in the subject of all articles, this
+tag can be removed from the article subjects in the summary buffer for
+the group by putting @code{(gnus-list-identifiers "DOCBOOK-APPS:")}
+into the group parameters for the group.
+
+This can also be used as a group-specific hook function.  If you want to
+hear a beep when you enter a group, you could put something like
+@code{(dummy-variable (ding))} in the parameters of that group.  If
+@code{dummy-variable} has been bound (see above), it will be set to the
+(meaningless) result of the @code{(ding)} form.
+
+Alternatively, since the VARIABLE becomes local to the group, this
+pattern can be used to temporarily change a hook.  For example, if the
+following is added to a group parameter
+
+@lisp
+(gnus-summary-prepared-hook
+  (lambda nil (local-set-key "d" (local-key-binding "n"))))
+@end lisp
+
+when the group is entered, the 'd' key will not mark the article as
+expired.
+
+@end table
+
+@vindex gnus-parameters
+Group parameters can be set via the @code{gnus-parameters} variable too.
+But some variables, such as @code{visible}, have no effect (For this
+case see @code{gnus-permanently-visible-groups} as an alternative.).
+For example:
+
+@lisp
+(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 lisp
+
+All clauses that matches the group name will be used, but the last
+setting ``wins''.  So if you have two clauses that both match the
+group name, and both set, say @code{display}, the last setting will
+override the first.
+
+Parameters that are strings will be subjected to regexp substitution,
+as the @code{to-group} example shows.
+
+@vindex gnus-parameters-case-fold-search
+By default, whether comparing the group name and one of those regexps
+specified in @code{gnus-parameters} is done in a case-sensitive manner
+or a case-insensitive manner depends on the value of
+@code{case-fold-search} at the time when the comparison is done.  The
+value of @code{case-fold-search} is typically @code{t}; it means, for
+example, the element @code{("INBOX\\.FOO" (total-expire . t))} might be
+applied to both the @samp{INBOX.FOO} group and the @samp{INBOX.foo}
+group.  If you want to make those regexps always case-sensitive, set the
+value of the @code{gnus-parameters-case-fold-search} variable to
+@code{nil}.  Otherwise, set it to @code{t} if you want to compare them
+always in a case-insensitive manner.
+
+You can define different sorting to different groups via
+@code{gnus-parameters}.  Here is an example to sort an @acronym{NNTP}
+group by reverse date to see the latest news at the top and an
+@acronym{RSS} group by subject.  In this example, the first group is the
+Debian daily news group @code{gmane.linux.debian.user.news} from
+news.gmane.org.  The @acronym{RSS} group corresponds to the Debian
+weekly news RSS feed
+@url{http://packages.debian.org/unstable/newpkg_main.en.rdf},
+@xref{RSS}.
+
+@lisp
+(setq
+ gnus-parameters
+ '(("nntp.*gmane\\.debian\\.user\\.news"
+    (gnus-show-threads nil)
+    (gnus-article-sort-functions '((not gnus-article-sort-by-date)))
+    (gnus-use-adaptive-scoring nil)
+    (gnus-use-scoring nil))
+   ("nnrss.*debian"
+    (gnus-show-threads nil)
+    (gnus-article-sort-functions 'gnus-article-sort-by-subject)
+    (gnus-use-adaptive-scoring nil)
+    (gnus-use-scoring t)
+    (gnus-score-find-score-files-function 'gnus-score-find-single)
+    (gnus-summary-line-format "%U%R%z%d %I%(%[ %s %]%)\n"))))
+@end lisp
+
+
+@node Listing Groups
+@section Listing Groups
+@cindex group listing
+
+These commands all list various slices of the groups available.
+
+@table @kbd
+
+@item l
+@itemx A s
+@kindex A s (Group)
+@kindex l (Group)
+@findex gnus-group-list-groups
+List all groups that have unread articles
+(@code{gnus-group-list-groups}).  If the numeric prefix is used, this
+command will list only groups of level ARG and lower.  By default, it
+only lists groups of level five (i.e.,
+@code{gnus-group-default-list-level}) or lower (i.e., just subscribed
+groups).
+
+@item L
+@itemx A u
+@kindex A u (Group)
+@kindex L (Group)
+@findex gnus-group-list-all-groups
+List all groups, whether they have unread articles or not
+(@code{gnus-group-list-all-groups}).  If the numeric prefix is used,
+this command will list only groups of level ARG and lower.  By default,
+it lists groups of level seven or lower (i.e., just subscribed and
+unsubscribed groups).
+
+@item A l
+@kindex A l (Group)
+@findex gnus-group-list-level
+List all unread groups on a specific level
+(@code{gnus-group-list-level}).  If given a prefix, also list the groups
+with no unread articles.
+
+@item A k
+@kindex A k (Group)
+@findex gnus-group-list-killed
+List all killed groups (@code{gnus-group-list-killed}).  If given a
+prefix argument, really list all groups that are available, but aren't
+currently (un)subscribed.  This could entail reading the active file
+from the server.
+
+@item A z
+@kindex A z (Group)
+@findex gnus-group-list-zombies
+List all zombie groups (@code{gnus-group-list-zombies}).
+
+@item A m
+@kindex A m (Group)
+@findex gnus-group-list-matching
+List all unread, subscribed groups with names that match a regexp
+(@code{gnus-group-list-matching}).
+
+@item A M
+@kindex A M (Group)
+@findex gnus-group-list-all-matching
+List groups that match a regexp (@code{gnus-group-list-all-matching}).
+
+@item A A
+@kindex A A (Group)
+@findex gnus-group-list-active
+List absolutely all groups in the active file(s) of the
+server(s) you are connected to (@code{gnus-group-list-active}).  This
+might very well take quite a while.  It might actually be a better idea
+to do a @kbd{A M} to list all matching, and just give @samp{.} as the
+thing to match on.  Also note that this command may list groups that
+don't exist (yet)---these will be listed as if they were killed groups.
+Take the output with some grains of salt.
+
+@item A a
+@kindex A a (Group)
+@findex gnus-group-apropos
+List all groups that have names that match a regexp
+(@code{gnus-group-apropos}).
+
+@item A d
+@kindex A d (Group)
+@findex gnus-group-description-apropos
+List all groups that have names or descriptions that match a regexp
+(@code{gnus-group-description-apropos}).
+
+@item A c
+@kindex A c (Group)
+@findex gnus-group-list-cached
+List all groups with cached articles (@code{gnus-group-list-cached}).
+
+@item A ?
+@kindex A ? (Group)
+@findex gnus-group-list-dormant
+List all groups with dormant articles (@code{gnus-group-list-dormant}).
+
+@item A !
+@kindex A ! (Group)
+@findex gnus-group-list-ticked
+List all groups with ticked articles (@code{gnus-group-list-ticked}).
+
+@item A /
+@kindex A / (Group)
+@findex gnus-group-list-limit
+Further limit groups within the current selection
+(@code{gnus-group-list-limit}).  If you've first limited to groups
+with dormant articles with @kbd{A ?}, you can then further limit with
+@kbd{A / c}, which will then limit to groups with cached articles,
+giving you the groups that have both dormant articles and cached
+articles.
+
+@item A f
+@kindex A f (Group)
+@findex gnus-group-list-flush
+Flush groups from the current selection (@code{gnus-group-list-flush}).
+
+@item A p
+@kindex A p (Group)
+@findex gnus-group-list-plus
+List groups plus the current selection (@code{gnus-group-list-plus}).
+
+@end table
+
+@vindex gnus-permanently-visible-groups
+@cindex visible group parameter
+Groups that match the @code{gnus-permanently-visible-groups} regexp will
+always be shown, whether they have unread articles or not.  You can also
+add the @code{visible} element to the group parameters in question to
+get the same effect.
+
+@vindex gnus-list-groups-with-ticked-articles
+Groups that have just ticked articles in it are normally listed in the
+group buffer.  If @code{gnus-list-groups-with-ticked-articles} is
+@code{nil}, these groups will be treated just like totally empty
+groups.  It is @code{t} by default.
+
+
+@node Sorting Groups
+@section Sorting Groups
+@cindex sorting groups
+
+@kindex C-c C-s (Group)
+@findex gnus-group-sort-groups
+@vindex gnus-group-sort-function
+The @kbd{C-c C-s} (@code{gnus-group-sort-groups}) command sorts the
+group buffer according to the function(s) given by the
+@code{gnus-group-sort-function} variable.  Available sorting functions
+include:
+
+@table @code
+
+@item gnus-group-sort-by-alphabet
+@findex gnus-group-sort-by-alphabet
+Sort the group names alphabetically.  This is the default.
+
+@item gnus-group-sort-by-real-name
+@findex gnus-group-sort-by-real-name
+Sort the group alphabetically on the real (unprefixed) group names.
+
+@item gnus-group-sort-by-level
+@findex gnus-group-sort-by-level
+Sort by group level.
+
+@item gnus-group-sort-by-score
+@findex gnus-group-sort-by-score
+Sort by group score.  @xref{Group Score}.
+
+@item gnus-group-sort-by-rank
+@findex gnus-group-sort-by-rank
+Sort by group score and then the group level.  The level and the score
+are, when taken together, the group's @dfn{rank}.  @xref{Group Score}.
+
+@item gnus-group-sort-by-unread
+@findex gnus-group-sort-by-unread
+Sort by number of unread articles.
+
+@item gnus-group-sort-by-method
+@findex gnus-group-sort-by-method
+Sort alphabetically on the select method.
+
+@item gnus-group-sort-by-server
+@findex gnus-group-sort-by-server
+Sort alphabetically on the Gnus server name.
+
+
+@end table
+
+@code{gnus-group-sort-function} can also be a list of sorting
+functions.  In that case, the most significant sort key function must be
+the last one.
+
+
+There are also a number of commands for sorting directly according to
+some sorting criteria:
+
+@table @kbd
+@item G S a
+@kindex G S a (Group)
+@findex gnus-group-sort-groups-by-alphabet
+Sort the group buffer alphabetically by group name
+(@code{gnus-group-sort-groups-by-alphabet}).
+
+@item G S u
+@kindex G S u (Group)
+@findex gnus-group-sort-groups-by-unread
+Sort the group buffer by the number of unread articles
+(@code{gnus-group-sort-groups-by-unread}).
+
+@item G S l
+@kindex G S l (Group)
+@findex gnus-group-sort-groups-by-level
+Sort the group buffer by group level
+(@code{gnus-group-sort-groups-by-level}).
+
+@item G S v
+@kindex G S v (Group)
+@findex gnus-group-sort-groups-by-score
+Sort the group buffer by group score
+(@code{gnus-group-sort-groups-by-score}).  @xref{Group Score}.
+
+@item G S r
+@kindex G S r (Group)
+@findex gnus-group-sort-groups-by-rank
+Sort the group buffer by group rank
+(@code{gnus-group-sort-groups-by-rank}).  @xref{Group Score}.
+
+@item G S m
+@kindex G S m (Group)
+@findex gnus-group-sort-groups-by-method
+Sort the group buffer alphabetically by back end name@*
+(@code{gnus-group-sort-groups-by-method}).
+
+@item G S n
+@kindex G S n (Group)
+@findex gnus-group-sort-groups-by-real-name
+Sort the group buffer alphabetically by real (unprefixed) group name
+(@code{gnus-group-sort-groups-by-real-name}).
+
+@end table
+
+All the commands below obey the process/prefix convention
+(@pxref{Process/Prefix}).
+
+When given a symbolic prefix (@pxref{Symbolic Prefixes}), all these
+commands will sort in reverse order.
+
+You can also sort a subset of the groups:
+
+@table @kbd
+@item G P a
+@kindex G P a (Group)
+@findex gnus-group-sort-selected-groups-by-alphabet
+Sort the groups alphabetically by group name
+(@code{gnus-group-sort-selected-groups-by-alphabet}).
+
+@item G P u
+@kindex G P u (Group)
+@findex gnus-group-sort-selected-groups-by-unread
+Sort the groups by the number of unread articles
+(@code{gnus-group-sort-selected-groups-by-unread}).
+
+@item G P l
+@kindex G P l (Group)
+@findex gnus-group-sort-selected-groups-by-level
+Sort the groups by group level
+(@code{gnus-group-sort-selected-groups-by-level}).
+
+@item G P v
+@kindex G P v (Group)
+@findex gnus-group-sort-selected-groups-by-score
+Sort the groups by group score
+(@code{gnus-group-sort-selected-groups-by-score}).  @xref{Group Score}.
+
+@item G P r
+@kindex G P r (Group)
+@findex gnus-group-sort-selected-groups-by-rank
+Sort the groups by group rank
+(@code{gnus-group-sort-selected-groups-by-rank}).  @xref{Group Score}.
+
+@item G P m
+@kindex G P m (Group)
+@findex gnus-group-sort-selected-groups-by-method
+Sort the groups alphabetically by back end name@*
+(@code{gnus-group-sort-selected-groups-by-method}).
+
+@item G P n
+@kindex G P n (Group)
+@findex gnus-group-sort-selected-groups-by-real-name
+Sort the groups alphabetically by real (unprefixed) group name
+(@code{gnus-group-sort-selected-groups-by-real-name}).
+
+@item G P s
+@kindex G P s (Group)
+@findex gnus-group-sort-selected-groups
+Sort the groups according to @code{gnus-group-sort-function}.
+
+@end table
+
+And finally, note that you can use @kbd{C-k} and @kbd{C-y} to manually
+move groups around.
+
+
+@node Group Maintenance
+@section Group Maintenance
+@cindex bogus groups
+
+@table @kbd
+@item b
+@kindex b (Group)
+@findex gnus-group-check-bogus-groups
+Find bogus groups and delete them
+(@code{gnus-group-check-bogus-groups}).
+
+@item F
+@kindex F (Group)
+@findex gnus-group-find-new-groups
+Find new groups and process them (@code{gnus-group-find-new-groups}).
+With 1 @kbd{C-u}, use the @code{ask-server} method to query the server
+for new groups.  With 2 @kbd{C-u}'s, use most complete method possible
+to query the server for new groups, and subscribe the new groups as
+zombies.
+
+@item C-c C-x
+@kindex C-c C-x (Group)
+@findex gnus-group-expire-articles
+@cindex expiring mail
+Run all expirable articles in the current group through the expiry
+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 C-M-x
+@kindex C-c C-M-x (Group)
+@findex gnus-group-expire-all-groups
+@cindex expiring mail
+Run all expirable articles in all groups through the expiry process
+(@code{gnus-group-expire-all-groups}).
+
+@end table
+
+
+@node Browse Foreign Server
+@section Browse Foreign Server
+@cindex foreign servers
+@cindex browsing servers
+
+@table @kbd
+@item B
+@kindex B (Group)
+@findex gnus-group-browse-foreign-server
+You will be queried for a select method and a server name.  Gnus will
+then attempt to contact this server and let you browse the groups there
+(@code{gnus-group-browse-foreign-server}).
+@end table
+
+@findex gnus-browse-mode
+A new buffer with a list of available groups will appear.  This buffer
+will use the @code{gnus-browse-mode}.  This buffer looks a bit (well,
+a lot) like a normal group buffer.
+
+Here's a list of keystrokes available in the browse mode:
+
+@table @kbd
+@item n
+@kindex n (Browse)
+@findex gnus-group-next-group
+Go to the next group (@code{gnus-group-next-group}).
+
+@item p
+@kindex p (Browse)
+@findex gnus-group-prev-group
+Go to the previous group (@code{gnus-group-prev-group}).
+
+@item SPACE
+@kindex SPACE (Browse)
+@findex gnus-browse-read-group
+Enter the current group and display the first article
+(@code{gnus-browse-read-group}).
+
+@item RET
+@kindex RET (Browse)
+@findex gnus-browse-select-group
+Enter the current group (@code{gnus-browse-select-group}).
+
+@item u
+@kindex u (Browse)
+@findex gnus-browse-unsubscribe-current-group
+@vindex gnus-browse-subscribe-newsgroup-method
+Unsubscribe to the current group, or, as will be the case here,
+subscribe to it (@code{gnus-browse-unsubscribe-current-group}).  You
+can affect the way the new group is entered into the Group buffer
+using the variable @code{gnus-browse-subscribe-newsgroup-method}.  See
+@pxref{Subscription Methods} for available options.
+
+@item l
+@itemx q
+@kindex q (Browse)
+@kindex l (Browse)
+@findex gnus-browse-exit
+Exit browse mode (@code{gnus-browse-exit}).
+
+@item d
+@kindex d (Browse)
+@findex gnus-browse-describe-group
+Describe the current group (@code{gnus-browse-describe-group}).
+
+@item ?
+@kindex ? (Browse)
+@findex gnus-browse-describe-briefly
+Describe browse mode briefly (well, there's not much to describe, is
+there) (@code{gnus-browse-describe-briefly}).
+
+@item DEL
+@kindex DEL (Browse)
+@findex gnus-browse-delete-group
+This function will delete the current group
+(@code{gnus-browse-delete-group}).  If given a prefix, this function
+will actually delete all the articles in the group, and forcibly
+remove the group itself from the face of the Earth.  Use a prefix only
+if you are absolutely sure of what you are doing.
+@end table
+
+
+@node Exiting Gnus
+@section Exiting Gnus
+@cindex exiting Gnus
+
+Yes, Gnus is ex(c)iting.
+
+@table @kbd
+@item z
+@kindex z (Group)
+@findex gnus-group-suspend
+Suspend Gnus (@code{gnus-group-suspend}).  This doesn't really exit Gnus,
+but it kills all buffers except the Group buffer.  I'm not sure why this
+is a gain, but then who am I to judge?
+
+@item q
+@kindex q (Group)
+@findex gnus-group-exit
+@c @icon{gnus-group-exit}
+Quit Gnus (@code{gnus-group-exit}).
+
+@item Q
+@kindex Q (Group)
+@findex gnus-group-quit
+Quit Gnus without saving the @file{.newsrc} files (@code{gnus-group-quit}).
+The dribble file will be saved, though (@pxref{Auto Save}).
+@end table
+
+@vindex gnus-exit-gnus-hook
+@vindex gnus-suspend-gnus-hook
+@vindex gnus-after-exiting-gnus-hook
+@code{gnus-suspend-gnus-hook} is called when you suspend Gnus and
+@code{gnus-exit-gnus-hook} is called when you quit Gnus, while
+@code{gnus-after-exiting-gnus-hook} is called as the final item when
+exiting Gnus.
+
+Note:
+
+@quotation
+Miss Lisa Cannifax, while sitting in English class, felt her feet go
+numbly heavy and herself fall into a hazy trance as the boy sitting
+behind her drew repeated lines with his pencil across the back of her
+plastic chair.
+@end quotation
+
+
+@node Group Topics
+@section Group Topics
+@cindex topics
+
+If you read lots and lots of groups, it might be convenient to group
+them hierarchically according to topics.  You put your Emacs groups over
+here, your sex groups over there, and the rest (what, two groups or so?)
+you put in some misc section that you never bother with anyway.  You can
+even group the Emacs sex groups as a sub-topic to either the Emacs
+groups or the sex groups---or both!  Go wild!
+
+@iftex
+@iflatex
+\gnusfigure{Group Topics}{400}{
+\put(75,50){\epsfig{figure=ps/group-topic,height=9cm}}
+}
+@end iflatex
+@end iftex
+
+Here's an example:
+
+@example
+Gnus
+  Emacs -- I wuw it!
+     3: comp.emacs
+     2: alt.religion.emacs
+    Naughty Emacs
+     452: alt.sex.emacs
+       0: comp.talk.emacs.recovery
+  Misc
+     8: comp.binaries.fractals
+    13: comp.sources.unix
+@end example
+
+@findex gnus-topic-mode
+@kindex t (Group)
+To get this @emph{fab} functionality you simply turn on (ooh!) the
+@code{gnus-topic} minor mode---type @kbd{t} in the group buffer.  (This
+is a toggling command.)
+
+Go ahead, just try it.  I'll still be here when you get back.  La de
+dum@dots{} Nice tune, that@dots{} la la la@dots{} 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.  Put the following line in your
+@file{~/.gnus.el} file:
+
+@lisp
+(add-hook 'gnus-group-mode-hook 'gnus-topic-mode)
+@end lisp
+
+@menu
+* 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 Commands
+@subsection Topic Commands
+@cindex topic commands
+
+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
+@kindex T n (Topic)
+@findex gnus-topic-create-topic
+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
+Move the current group to some other topic
+(@code{gnus-topic-move-group}).  This command uses the process/prefix
+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}).
+
+@item T c
+@kindex T c (Topic)
+@findex gnus-topic-copy-group
+Copy the current group to some other topic
+(@code{gnus-topic-copy-group}).  This command uses the process/prefix
+convention (@pxref{Process/Prefix}).
+
+@item T h
+@kindex T h (Topic)
+@findex gnus-topic-hide-topic
+Hide the current topic (@code{gnus-topic-hide-topic}).  If given
+a prefix, hide the topic permanently.
+
+@item T s
+@kindex T s (Topic)
+@findex gnus-topic-show-topic
+Show the current topic (@code{gnus-topic-show-topic}).  If given
+a prefix, show the topic permanently.
+
+@item T D
+@kindex T D (Topic)
+@findex gnus-topic-remove-group
+Remove a group from the current topic (@code{gnus-topic-remove-group}).
+This command is mainly useful if you have the same group in several
+topics and wish to remove it from one of the topics.  You may also
+remove a group from all topics, but in that case, Gnus will add it to
+the root topic the next time you start Gnus.  In fact, all new groups
+(which, naturally, don't belong to any topic) will show up in the root
+topic.
+
+This command uses the process/prefix convention
+(@pxref{Process/Prefix}).
+
+@item T M
+@kindex T M (Topic)
+@findex gnus-topic-move-matching
+Move all groups that match some regular expression to a topic
+(@code{gnus-topic-move-matching}).
+
+@item T C
+@kindex T C (Topic)
+@findex gnus-topic-copy-matching
+Copy all groups that match some regular expression to a topic
+(@code{gnus-topic-copy-matching}).
+
+@item T H
+@kindex T H (Topic)
+@findex gnus-topic-toggle-display-empty-topics
+Toggle hiding empty topics
+(@code{gnus-topic-toggle-display-empty-topics}).
+
+@item T #
+@kindex T # (Topic)
+@findex gnus-topic-mark-topic
+Mark all groups in the current topic with the process mark
+(@code{gnus-topic-mark-topic}).  This command works recursively on
+sub-topics unless given a prefix.
+
+@item T M-#
+@kindex T M-# (Topic)
+@findex gnus-topic-unmark-topic
+Remove the process mark from all groups in the current topic
+(@code{gnus-topic-unmark-topic}).  This command works recursively on
+sub-topics unless given a prefix.
+
+@item C-c C-x
+@kindex C-c C-x (Topic)
+@findex gnus-topic-expire-articles
+@cindex expiring mail
+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)
+@findex gnus-topic-rename
+Rename a topic (@code{gnus-topic-rename}).
+
+@item T DEL
+@kindex T DEL (Topic)
+@findex gnus-topic-delete
+Delete an empty topic (@code{gnus-topic-delete}).
+
+@item A T
+@kindex A T (Topic)
+@findex gnus-topic-list-active
+List all groups that Gnus knows about in a topics-ified way
+(@code{gnus-topic-list-active}).
+
+@item T M-n
+@kindex T M-n (Topic)
+@findex gnus-topic-goto-next-topic
+Go to the next topic (@code{gnus-topic-goto-next-topic}).
+
+@item T M-p
+@kindex T M-p (Topic)
+@findex gnus-topic-goto-previous-topic
+Go to the previous topic (@code{gnus-topic-goto-previous-topic}).
+
+@item G p
+@kindex G p (Topic)
+@findex gnus-topic-edit-parameters
+@cindex group parameters
+@cindex topic parameters
+@cindex parameters
+Edit the topic parameters (@code{gnus-topic-edit-parameters}).
+@xref{Topic 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
+
+You can sort the groups in each topic individually with the following
+commands:
+
+
+@table @kbd
+@item T S a
+@kindex T S a (Topic)
+@findex gnus-topic-sort-groups-by-alphabet
+Sort the current topic alphabetically by group name
+(@code{gnus-topic-sort-groups-by-alphabet}).
+
+@item T S u
+@kindex T S u (Topic)
+@findex gnus-topic-sort-groups-by-unread
+Sort the current topic by the number of unread articles
+(@code{gnus-topic-sort-groups-by-unread}).
+
+@item T S l
+@kindex T S l (Topic)
+@findex gnus-topic-sort-groups-by-level
+Sort the current topic by group level
+(@code{gnus-topic-sort-groups-by-level}).
+
+@item T S v
+@kindex T S v (Topic)
+@findex gnus-topic-sort-groups-by-score
+Sort the current topic by group score
+(@code{gnus-topic-sort-groups-by-score}).  @xref{Group Score}.
+
+@item T S r
+@kindex T S r (Topic)
+@findex gnus-topic-sort-groups-by-rank
+Sort the current topic by group rank
+(@code{gnus-topic-sort-groups-by-rank}).  @xref{Group Score}.
+
+@item T S m
+@kindex T S m (Topic)
+@findex gnus-topic-sort-groups-by-method
+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}).
+
+@item T S s
+@kindex T S s (Topic)
+@findex gnus-topic-sort-groups
+Sort the current topic according to the function(s) given by the
+@code{gnus-group-sort-function} variable
+(@code{gnus-topic-sort-groups}).
+
+@end table
+
+When given a prefix argument, all these commands will sort in reverse
+order.  @xref{Sorting Groups}, for more information about group
+sorting.
+
+
+@node Topic Topology
+@subsection Topic Topology
+@cindex topic topology
+@cindex topology
+
+So, let's have a look at an example group buffer:
+
+@example
+@group
+Gnus
+  Emacs -- I wuw it!
+     3: comp.emacs
+     2: alt.religion.emacs
+    Naughty Emacs
+     452: alt.sex.emacs
+       0: comp.talk.emacs.recovery
+  Misc
+     8: comp.binaries.fractals
+    13: comp.sources.unix
+@end group
+@end example
+
+So, here we have one top-level topic (@samp{Gnus}), two topics under
+that, and one sub-topic under one of the sub-topics.  (There is always
+just one (1) top-level topic).  This topology can be expressed as
+follows:
+
+@lisp
+(("Gnus" visible)
+ (("Emacs -- I wuw it!" visible)
+  (("Naughty Emacs" visible)))
+ (("Misc" visible)))
+@end lisp
+
+@vindex gnus-topic-topology
+This is in fact how the variable @code{gnus-topic-topology} would look
+for the display above.  That variable is saved in the @file{.newsrc.eld}
+file, and shouldn't be messed with manually---unless you really want
+to.  Since this variable is read from the @file{.newsrc.eld} file,
+setting it in any other startup files will have no effect.
+
+This topology shows what topics are sub-topics of what topics (right),
+and which topics are visible.  Two settings are currently
+allowed---@code{visible} and @code{invisible}.
+
+
+@node Topic Parameters
+@subsection Topic Parameters
+@cindex topic parameters
+
+All groups in a topic will inherit group parameters from the parent
+(and ancestor) topic parameters.  All valid group parameters are valid
+topic parameters (@pxref{Group Parameters}).  When the agent is
+enabled, all agent parameters (See Agent Parameters in @ref{Category
+Syntax}) are also valid topic parameters.
+
+In addition, the following parameters are only valid as topic
+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
+value should be a regexp to match the groups that should go in that
+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
+
+Group parameters (of course) override topic parameters, and topic
+parameters in sub-topics override topic parameters in super-topics.  You
+know.  Normal inheritance rules.  (@dfn{Rules} is here a noun, not a
+verb, although you may feel free to disagree with me here.)
+
+@example
+@group
+Gnus
+  Emacs
+     3: comp.emacs
+     2: alt.religion.emacs
+   452: alt.sex.emacs
+    Relief
+     452: alt.sex.emacs
+       0: comp.talk.emacs.recovery
+  Misc
+     8: comp.binaries.fractals
+    13: comp.sources.unix
+   452: alt.sex.emacs
+@end group
+@end example
+
+The @samp{Emacs} topic has the topic parameter @code{(score-file
+. "emacs.SCORE")}; the @samp{Relief} topic has the topic parameter
+@code{(score-file . "relief.SCORE")}; and the @samp{Misc} topic has the
+topic parameter @code{(score-file . "emacs.SCORE")}.  In addition,
+@* @samp{alt.religion.emacs} has the group parameter @code{(score-file
+. "religion.SCORE")}.
+
+Now, when you enter @samp{alt.sex.emacs} in the @samp{Relief} topic, you
+will get the @file{relief.SCORE} home score file.  If you enter the same
+group in the @samp{Emacs} topic, you'll get the @file{emacs.SCORE} home
+score file.  If you enter the group @samp{alt.religion.emacs}, you'll
+get the @file{religion.SCORE} home score file.
+
+This seems rather simple and self-evident, doesn't it?  Well, yes.  But
+there are some problems, especially with the @code{total-expiry}
+parameter.  Say you have a mail group in two topics; one with
+@code{total-expiry} and one without.  What happens when you do @kbd{M-x
+gnus-expire-all-expirable-groups}?  Gnus has no way of telling which one
+of these topics you mean to expire articles from, so anything may
+happen.  In fact, I hereby declare that it is @dfn{undefined} what
+happens.  You just have to be careful if you do stuff like that.
+
+
+@node Non-ASCII Group Names
+@section Accessing groups of non-English names
+@cindex non-ascii group names
+
+There are some news servers that provide groups of which the names are
+expressed with their native languages in the world.  For instance, in a
+certain news server there are some newsgroups of which the names are
+spelled in Chinese, where people are talking in Chinese.  You can, of
+course, subscribe to such news groups using Gnus.  Currently Gnus
+supports non-@acronym{ASCII} group names not only with the @code{nntp}
+back end but also with the @code{nnml} back end and the @code{nnrss}
+back end.
+
+Every such group name is encoded by a certain charset in the server
+side (in an @acronym{NNTP} server its administrator determines the
+charset, but for groups in the other back ends it is determined by you).
+Gnus has to display the decoded ones for you in the group buffer and the
+article buffer, and needs to use the encoded ones when communicating
+with servers.  However, Gnus doesn't know what charset is used for each
+non-@acronym{ASCII} group name.  The following two variables are just
+the ones for telling Gnus what charset should be used for each group:
+
+@table @code
+@item gnus-group-name-charset-method-alist
+@vindex gnus-group-name-charset-method-alist
+An alist of select methods and charsets.  The default value is
+@code{nil}.  The names of groups in the server specified by that select
+method are all supposed to use the corresponding charset.  For example:
+
+@lisp
+(setq gnus-group-name-charset-method-alist
+      '(((nntp "news.com.cn") . cn-gb-2312)))
+@end lisp
+
+Charsets specified for groups with this variable are preferred to the
+ones specified for the same groups with the
+@code{gnus-group-name-charset-group-alist} variable (see below).
+
+A select method can be very long, like:
+
+@lisp
+(nntp "gmane"
+      (nntp-address "news.gmane.org")
+      (nntp-end-of-line "\n")
+      (nntp-open-connection-function
+       nntp-open-via-rlogin-and-telnet)
+      (nntp-via-rlogin-command "ssh")
+      (nntp-via-rlogin-command-switches
+       ("-C" "-t" "-e" "none"))
+      (nntp-via-address @dots{}))
+@end lisp
+
+In that case, you can truncate it into @code{(nntp "gmane")} in this
+variable.  That is, it is enough to contain only the back end name and
+the server name.
+
+@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.
+@code{((".*" . utf-8))} is the default value if UTF-8 is supported,
+otherwise the default is @code{nil}.  For example:
+
+@lisp
+(setq gnus-group-name-charset-group-alist
+      '(("\\.com\\.cn:" . cn-gb-2312)
+        (".*" . utf-8)))
+@end lisp
+
+Note that this variable is ignored if the match is made with
+@code{gnus-group-name-charset-method-alist}.
+@end table
+
+Those two variables are used also to determine the charset for encoding
+and decoding non-@acronym{ASCII} group names that are in the back ends
+other than @code{nntp}.  It means that it is you who determine it.  If
+you do nothing, the charset used for group names in those back ends will
+all be @code{utf-8} because of the last element of
+@code{gnus-group-name-charset-group-alist}.
+
+There is one more important variable for non-@acronym{ASCII} group
+names:
+
+@table @code
+@item nnmail-pathname-coding-system
+@vindex nnmail-pathname-coding-system
+The value of this variable should be a coding system or @code{nil}.  The
+default is @code{nil} in Emacs, or is the aliasee of the coding system
+named @code{file-name} (a certain coding system of which an alias is
+@code{file-name}) in XEmacs.
+
+The @code{nnml} back end, the @code{nnrss} back end, the agent, and
+the cache use non-@acronym{ASCII} group names in those files and
+directories.  This variable overrides the value of
+@code{file-name-coding-system} which specifies the coding system used
+when encoding and decoding those file names and directory names.
+
+In XEmacs (with the @code{mule} feature), @code{file-name-coding-system}
+is the only means to specify the coding system used to encode and decode
+file names.  On the other hand, Emacs uses the value of
+@code{default-file-name-coding-system} if @code{file-name-coding-system}
+is @code{nil} or it is bound to the value of
+@code{nnmail-pathname-coding-system} which is @code{nil}.
+
+Normally the value of @code{default-file-name-coding-system} in Emacs or
+@code{nnmail-pathname-coding-system} in XEmacs is initialized according
+to the locale, so you will need to do nothing if the value is suitable
+to encode and decode non-@acronym{ASCII} group names.
+
+The value of this variable (or @code{default-file-name-coding-system})
+does not necessarily need to be the same value that is determined by
+@code{gnus-group-name-charset-method-alist} and
+@code{gnus-group-name-charset-group-alist}.
+
+If @code{default-file-name-coding-system} or this variable is
+initialized by default to @code{iso-latin-1} for example, although you
+want to subscribe to the groups spelled in Chinese, that is the most
+typical case where you have to customize
+@code{nnmail-pathname-coding-system}.  The @code{utf-8} coding system is
+a good candidate for it.  Otherwise, you may change the locale in your
+system so that @code{default-file-name-coding-system} or this variable
+may be initialized to an appropriate value.
+@end table
+
+Note that when you copy or move articles from a non-@acronym{ASCII}
+group to another group, the charset used to encode and decode group
+names should be the same in both groups.  Otherwise the Newsgroups
+header will be displayed incorrectly in the article buffer.
+
+
+@node Misc Group Stuff
+@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.
+* Sieve Commands::              Managing Sieve scripts.
+@end menu
+
+@table @kbd
+
+@item v
+@kindex v (Group)
+@cindex keys, reserved for users (Group)
+The key @kbd{v} is reserved for users.  You can bind it to some
+command or better use it as a prefix key.  For example:
+
+@lisp
+(define-key gnus-group-mode-map (kbd "v j d")
+  (lambda ()
+    (interactive)
+    (gnus-group-jump-to-group "nndraft:drafts")))
+@end lisp
+
+On keys reserved for users in Emacs and on keybindings in general
+@xref{Keymaps, Keymaps, , emacs, The Emacs Editor}.
+
+@item ^
+@kindex ^ (Group)
+@findex gnus-group-enter-server-mode
+Enter the server buffer (@code{gnus-group-enter-server-mode}).
+@xref{Server Buffer}.
+
+@item a
+@kindex a (Group)
+@findex gnus-group-post-news
+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}).  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.
+
+@item G z
+@kindex G z (Group)
+@findex gnus-group-compact-group
+
+Compact the group under point (@code{gnus-group-compact-group}).
+Currently implemented only in nnml (@pxref{Mail Spool}).  This removes
+gaps between article numbers, hence getting a correct total article
+count.
+
+@end table
+
+Variables for the group buffer:
+
+@table @code
+
+@item gnus-group-mode-hook
+@vindex gnus-group-mode-hook
+is called after the group buffer has been
+created.
+
+@item gnus-group-prepare-hook
+@vindex gnus-group-prepare-hook
+is called after the group buffer is
+generated.  It may be used to modify the buffer in some strange,
+unnatural way.
+
+@item gnus-group-prepared-hook
+@vindex gnus-group-prepare-hook
+is called as the very last thing after the group buffer has been
+generated.  It may be used to move point around, for instance.
+
+@item gnus-permanently-visible-groups
+@vindex gnus-permanently-visible-groups
+Groups matching this regexp will always be listed in the group buffer,
+whether they are empty or not.
+
+@end table
+
+@node Scanning New Messages
+@subsection Scanning New Messages
+@cindex new messages
+@cindex scanning new news
+
+@table @kbd
+
+@item g
+@kindex g (Group)
+@findex gnus-group-get-new-news
+@c @icon{gnus-group-get-new-news}
+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
+back end(s).
+
+@item M-g
+@kindex M-g (Group)
+@findex gnus-group-get-new-news-this-group
+@vindex gnus-goto-next-group-when-activating
+@c @icon{gnus-group-get-new-news-this-group}
+Check whether new articles have arrived in the current group
+(@code{gnus-group-get-new-news-this-group}).
+@code{gnus-goto-next-group-when-activating} says whether this command is
+to move point to the next group or not.  It is @code{t} by default.
+
+@findex gnus-activate-all-groups
+@cindex activating groups
+@item C-c M-g
+@kindex C-c M-g (Group)
+Activate absolutely all groups (@code{gnus-activate-all-groups}).
+
+@item R
+@kindex R (Group)
+@cindex restarting
+@findex gnus-group-restart
+Restart Gnus (@code{gnus-group-restart}).  This saves the @file{.newsrc}
+file(s), closes the connection to all servers, clears up all run-time
+Gnus variables, and then starts Gnus all over again.
+
+@end table
+
+@vindex gnus-get-new-news-hook
+@code{gnus-get-new-news-hook} is run just before checking for new news.
+
+@vindex gnus-after-getting-new-news-hook
+@code{gnus-after-getting-new-news-hook} is run after checking for new
+news.
+
+
+@node Group Information
+@subsection Group Information
+@cindex group information
+@cindex information on groups
+
+@table @kbd
+
+
+@item H d
+@itemx C-c C-d
+@c @icon{gnus-group-describe-group}
+@kindex H d (Group)
+@kindex C-c C-d (Group)
+@cindex describing groups
+@cindex group description
+@findex gnus-group-describe-group
+Describe the current group (@code{gnus-group-describe-group}).  If given
+a prefix, force Gnus to re-read the description from the server.
+
+@item M-d
+@kindex M-d (Group)
+@findex gnus-group-describe-all-groups
+Describe all groups (@code{gnus-group-describe-all-groups}).  If given a
+prefix, force Gnus to re-read the description file from the server.
+
+@item H v
+@itemx V
+@kindex V (Group)
+@kindex H v (Group)
+@cindex version
+@findex gnus-version
+Display current Gnus version numbers (@code{gnus-version}).
+
+@item ?
+@kindex ? (Group)
+@findex gnus-group-describe-briefly
+Give a very short help message (@code{gnus-group-describe-briefly}).
+
+@item C-c C-i
+@kindex C-c C-i (Group)
+@cindex info
+@cindex manual
+@findex gnus-info-find-node
+Go to the Gnus info node (@code{gnus-info-find-node}).
+@end table
+
+
+@node Group Timestamp
+@subsection Group Timestamp
+@cindex timestamps
+@cindex group timestamps
+
+It can be convenient to let Gnus keep track of when you last read a
+group.  To set the ball rolling, you should add
+@code{gnus-group-set-timestamp} to @code{gnus-select-group-hook}:
+
+@lisp
+(add-hook 'gnus-select-group-hook 'gnus-group-set-timestamp)
+@end lisp
+
+After doing this, each time you enter a group, it'll be recorded.
+
+This information can be displayed in various ways---the easiest is to
+use the @samp{%d} spec in the group line format:
+
+@lisp
+(setq gnus-group-line-format
+      "%M\%S\%p\%P\%5y: %(%-40,40g%) %d\n")
+@end lisp
+
+This will result in lines looking like:
+
+@example
+*        0: mail.ding                                19961002T012943
+         0: custom                                   19961002T012713
+@end example
+
+As you can see, the date is displayed in compact ISO 8601 format.  This
+may be a bit too much, so to just display the date, you could say
+something like:
+
+@lisp
+(setq gnus-group-line-format
+      "%M\%S\%p\%P\%5y: %(%-40,40g%) %6,6~(cut 2)d\n")
+@end lisp
+
+If you would like greater control of the time format, you can use a
+user-defined format spec.  Something like the following should do the
+trick:
+
+@lisp
+(setq gnus-group-line-format
+      "%M\%S\%p\%P\%5y: %(%-40,40g%) %ud\n")
+(defun gnus-user-format-function-d (headers)
+  (let ((time (gnus-group-timestamp gnus-tmp-group)))
+    (if time
+        (format-time-string "%b %d  %H:%M" time)
+      "")))
+@end lisp
+
+To see what variables are dynamically bound (like
+@code{gnus-tmp-group}), you have to look at the source code.  The
+variable names aren't guaranteed to be stable over Gnus versions,
+either.
+
+
+@node File Commands
+@subsection File Commands
+@cindex file commands
+
+@table @kbd
+
+@item r
+@kindex r (Group)
+@findex gnus-group-read-init-file
+@vindex gnus-init-file
+@cindex reading init file
+Re-read the init file (@code{gnus-init-file}, which defaults to
+@file{~/.gnus.el}) (@code{gnus-group-read-init-file}).
+
+@item s
+@kindex s (Group)
+@findex gnus-group-save-newsrc
+@cindex saving .newsrc
+Save the @file{.newsrc.eld} file (and @file{.newsrc} if wanted)
+(@code{gnus-group-save-newsrc}).  If given a prefix, force saving the
+file(s) whether Gnus thinks it is necessary or not.
+
+@c @item Z
+@c @kindex Z (Group)
+@c @findex gnus-group-clear-dribble
+@c Clear the dribble buffer (@code{gnus-group-clear-dribble}).
+
+@end table
+
+
+@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 transferred 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-@code{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 @code{nil}.  (When
+@code{gnus-sieve-crosspost} is non-@code{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, Emacs Sieve, 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
+
+A line for each article is displayed in the summary buffer.  You can
+move around, read articles, post articles and reply to articles.
+
+The most common way to a summary buffer is to select a group from the
+group buffer (@pxref{Selecting a Group}).
+
+You can have as many summary buffers open as you wish.
+
+You can customize the Summary Mode tool bar, see @kbd{M-x
+customize-apropos RET gnus-summary-tool-bar}.  This feature is only
+available in Emacs.
+
+@kindex v (Summary)
+@cindex keys, reserved for users (Summary)
+The key @kbd{v} is reserved for users.  You can bind it to some
+command or better use it as a prefix key.  For example:
+@lisp
+(define-key gnus-summary-mode-map (kbd "v -") "LrS") ;; lower subthread
+@end lisp
+
+@menu
+* Summary Buffer Format::       Deciding how the summary buffer is to look.
+* Summary Maneuvering::         Moving around the summary buffer.
+* Choosing Articles::           Reading articles.
+* Paging the Article::          Scrolling the current article.
+* Reply Followup and Post::     Posting articles.
+* Delayed Articles::            Send articles at a later time.
+* Marking Articles::            Marking articles as read, expirable, etc.
+* Limiting::                    You can limit the summary buffer.
+* Threading::                   How threads are made.
+* Sorting the Summary Buffer::  How articles and threads are sorted.
+* Asynchronous Fetching::       Gnus might be able to pre-fetch articles.
+* Article Caching::             You may store articles in a cache.
+* Persistent Articles::         Making articles expiry-resistant.
+* Sticky Articles::             Article buffers that are not reused.
+* Article Backlog::             Having already read articles hang around.
+* Saving Articles::             Ways of customizing article saving.
+* Decoding Articles::           Gnus can treat series of (uu)encoded articles.
+* Article Treatment::           The article buffer can be mangled at will.
+* MIME Commands::               Doing MIMEy things with the articles.
+* Charsets::                    Character set issues.
+* Article Commands::            Doing various things with the article buffer.
+* Summary Sorting::             Sorting the summary buffer in various ways.
+* Finding the Parent::          No child support?  Get the parent.
+* Alternative Approaches::      Reading using non-default summaries.
+* 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,
+                                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.
+@end menu
+
+
+@node Summary Buffer Format
+@section Summary Buffer Format
+@cindex summary buffer format
+
+@iftex
+@iflatex
+\gnusfigure{The Summary Buffer}{180}{
+\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.
+@end menu
+
+@findex mail-extract-address-components
+@findex gnus-extract-address-components
+@vindex gnus-extract-address-components
+Gnus will use the value of the @code{gnus-extract-address-components}
+variable as a function for getting the name and address parts of a
+@code{From} header.  Two pre-defined functions exist:
+@code{gnus-extract-address-components}, which is the default, quite
+fast, and too simplistic solution; and
+@code{mail-extract-address-components}, which works very nicely, but is
+slower.  The default function will return the wrong answer in 5% of the
+cases.  If this is unacceptable to you, use the other function instead:
+
+@lisp
+(setq gnus-extract-address-components
+      'mail-extract-address-components)
+@end lisp
+
+@vindex gnus-summary-same-subject
+@code{gnus-summary-same-subject} is a string indicating that the current
+article has the same subject as the previous.  This string will be used
+with those specs that require it.  The default is @code{""}.
+
+
+@node Summary Buffer Lines
+@subsection Summary Buffer Lines
+
+@vindex gnus-summary-line-format
+You can change the format of the lines in the summary buffer by changing
+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}).
+
+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 default string is @samp{%U%R%z%I%(%[%4L: %-23,23f%]%) %s\n}.
+
+The following format specification characters and extended format
+specification(s) are understood:
+
+@table @samp
+@item N
+Article number.
+@item S
+Subject string.  List identifiers stripped,
+@code{gnus-list-identifiers}.  @xref{Article Hiding}.
+@item s
+Subject if the article is the root of the thread or the previous article
+had a different subject, @code{gnus-summary-same-subject} otherwise.
+(@code{gnus-summary-same-subject} defaults to @code{""}.)
+@item F
+Full @code{From} header.
+@item n
+The name (from the @code{From} header).
+@item f
+The name, @code{To} header or the @code{Newsgroups} header (@pxref{To
+From Newsgroups}).
+@item a
+The name (from the @code{From} header).  This differs from the @code{n}
+spec in that it uses the function designated by the
+@code{gnus-extract-address-components} variable, which is slower, but
+may be more thorough.
+@item A
+The address (from the @code{From} header).  This works the same way as
+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).
+@item k
+Pretty-printed version of the number of characters in the article;
+for example, @samp{1.2k} or @samp{0.4M}.
+@item I
+Indentation based on thread level (@pxref{Customizing Threading}).
+@item B
+A complex trn-style thread tree, showing response-connecting trace
+lines.  A thread could be drawn like this:
+
+@example
+>
++->
+| +->
+| | \->
+| |   \->
+| \->
++->
+\->
+@end example
+
+You can customize the appearance with the following options.  Note
+that it is possible to make the thread display look really neat by
+replacing the default @acronym{ASCII} characters with graphic
+line-drawing glyphs.
+@table @code
+@item gnus-sum-thread-tree-root
+@vindex gnus-sum-thread-tree-root
+Used for the root of a thread.  If @code{nil}, use subject
+instead.  The default is @samp{> }.
+
+@item gnus-sum-thread-tree-false-root
+@vindex gnus-sum-thread-tree-false-root
+Used for the false root of a thread (@pxref{Loose Threads}).  If
+@code{nil}, use subject instead.  The default is @samp{> }.
+
+@item gnus-sum-thread-tree-single-indent
+@vindex gnus-sum-thread-tree-single-indent
+Used for a thread with just one message.  If @code{nil}, use subject
+instead.  The default is @samp{}.
+
+@item gnus-sum-thread-tree-vertical
+@vindex gnus-sum-thread-tree-vertical
+Used for drawing a vertical line.  The default is @samp{| }.
+
+@item gnus-sum-thread-tree-indent
+@vindex gnus-sum-thread-tree-indent
+Used for indenting.  The default is @samp{  }.
+
+@item gnus-sum-thread-tree-leaf-with-other
+@vindex gnus-sum-thread-tree-leaf-with-other
+Used for a leaf with brothers.  The default is @samp{+-> }.
+
+@item gnus-sum-thread-tree-single-leaf
+@vindex gnus-sum-thread-tree-single-leaf
+Used for a leaf without brothers.  The default is @samp{\-> }
+
+@end table
+
+@item T
+Nothing if the article is a root and lots of spaces if it isn't (it
+pushes everything after it off the screen).
+@item [
+Opening bracket, which is normally @samp{[}, but can also be @samp{<}
+for adopted articles (@pxref{Customizing Threading}).
+@item ]
+Closing bracket, which is normally @samp{]}, but can also be @samp{>}
+for adopted articles.
+@item >
+One space for each thread level.
+@item <
+Twenty minus thread level spaces.
+@item U
+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.  @xref{Other Marks}.
+
+@item i
+Score as a number (@pxref{Scoring}).
+@item z
+@vindex gnus-summary-zcore-fuzz
+Zcore, @samp{+} if above the default level and @samp{-} if below the
+default level.  If the difference between
+@code{gnus-summary-default-score} and the score is less than
+@code{gnus-summary-zcore-fuzz}, this spec will not be used.
+@item V
+Total thread score.
+@item x
+@code{Xref}.
+@item D
+@code{Date}.
+@item d
+The @code{Date} in @code{DD-MMM} format.
+@item o
+The @code{Date} in @var{YYYYMMDD}@code{T}@var{HHMMSS} format.
+@item M
+@code{Message-ID}.
+@item r
+@code{References}.
+@item t
+Number of articles in the current sub-thread.  Using this spec will slow
+down summary buffer generation somewhat.
+@item e
+An @samp{=} (@code{gnus-not-empty-thread-mark}) will be displayed if the
+article has any children.
+@item P
+The line number.
+@item O
+Download mark.
+@item *
+Desired cursor position (instead of after first colon).
+@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
+@code{gnus-user-format-function-@var{x}}, where @var{x} is the letter
+following @samp{%u}.  The function will be passed the current header as
+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''
+that.  This means that it is invalid to have these specs after a
+variable-length spec.  Well, you might not be arrested, but your summary
+buffer will look strange, which is bad enough.
+
+The smart choice is to have these specs as far to the left as possible.
+(Isn't that the case with everything, though?  But I digress.)
+
+This restriction may disappear in later versions of Gnus.
+
+
+@node To From Newsgroups
+@subsection To From Newsgroups
+@cindex To
+@cindex Newsgroups
+
+In some groups (particularly in archive groups), the @code{From} header
+isn't very interesting, since all the articles there are written by
+you.  To display the information in the @code{To} or @code{Newsgroups}
+headers instead, you need to decide three things: What information to
+gather; where to display it; and when to display it.
+
+@enumerate
+@item
+@vindex gnus-extra-headers
+The reading of extra header information is controlled by the
+@code{gnus-extra-headers}.  This is a list of header symbols.  For
+instance:
+
+@lisp
+(setq gnus-extra-headers
+      '(To Newsgroups X-Newsreader))
+@end lisp
+
+This will result in Gnus trying to obtain these three headers, and
+storing it in header structures for later easy retrieval.
+
+@item
+@findex gnus-extra-header
+The value of these extra headers can be accessed via the
+@code{gnus-extra-header} function.  Here's a format line spec that will
+access the @code{X-Newsreader} header:
+
+@example
+"%~(form (gnus-extra-header 'X-Newsreader))@@"
+@end example
+
+@item
+@vindex gnus-ignored-from-addresses
+The @code{gnus-ignored-from-addresses} variable says when the @samp{%f}
+summary line spec returns the @code{To}, @code{Newsreader} or
+@code{From} header.  If this regexp matches the contents of the
+@code{From} header, the value of the @code{To} or @code{Newsreader}
+headers are used instead.
+
+To distinguish regular articles from those where the @code{From} field
+has been swapped, a string is prefixed to the @code{To} or
+@code{Newsgroups} header in the summary line.  By default the string is
+@samp{-> } for @code{To} and @samp{=> } for @code{Newsgroups}, you can
+customize these strings with @code{gnus-summary-to-prefix} and
+@code{gnus-summary-newsgroup-prefix}.
+
+@end enumerate
+
+@vindex nnmail-extra-headers
+A related variable is @code{nnmail-extra-headers}, which controls when
+to include extra headers when generating overview (@acronym{NOV}) files.
+If you have old overview files, you should regenerate them after
+changing this variable, by entering the server buffer using @kbd{^},
+and then @kbd{g} on the appropriate mail server (e.g., nnml) to cause
+regeneration.
+
+@vindex gnus-summary-line-format
+You also have to instruct Gnus to display the data by changing the
+@code{%n} spec to the @code{%f} spec in the
+@code{gnus-summary-line-format} variable.
+
+In summary, you'd typically put something like the following in
+@file{~/.gnus.el}:
+
+@lisp
+(setq gnus-extra-headers
+      '(To Newsgroups))
+(setq nnmail-extra-headers gnus-extra-headers)
+(setq gnus-summary-line-format
+      "%U%R%z%I%(%[%4L: %-23,23f%]%) %s\n")
+(setq gnus-ignored-from-addresses
+      "Your Name Here")
+@end lisp
+
+(The values listed above are the default values in Gnus.  Alter them
+to fit your needs.)
+
+A note for news server administrators, or for users who wish to try to
+convince their news server administrator to provide some additional
+support:
+
+The above is mostly useful for mail groups, where you have control over
+the @acronym{NOV} files that are created.  However, if you can persuade your
+nntp admin to add (in the usual implementation, notably INN):
+
+@example
+Newsgroups:full
+@end example
+
+to the end of her @file{overview.fmt} file, then you can use that just
+as you would the extra headers from the mail groups.
+
+
+@node Summary Buffer Mode Line
+@subsection Summary Buffer Mode Line
+
+@vindex gnus-summary-mode-line-format
+You can also change the format of the summary mode bar (@pxref{Mode Line
+Formatting}).  Set @code{gnus-summary-mode-line-format} to whatever you
+like.  The default is @samp{Gnus: %%b [%A] %Z}.
+
+Here are the elements you can play with:
+
+@table @samp
+@item G
+Group name.
+@item p
+Unprefixed group name.
+@item A
+Current article number.
+@item z
+Current article score.
+@item V
+Gnus version.
+@item U
+Number of unread articles in this group.
+@item e
+Number of unread articles in this group that aren't displayed in the
+summary buffer.
+@item Z
+A string with the number of unread and unselected articles represented
+either as @samp{<%U(+%e) more>} if there are both unread and unselected
+articles, and just as @samp{<%U more>} if there are just unread articles
+and no unselected ones.
+@item g
+Shortish group name.  For instance, @samp{rec.arts.anime} will be
+shortened to @samp{r.a.anime}.
+@item S
+Subject of the current article.
+@item u
+User-defined spec (@pxref{User-Defined Specs}).
+@item s
+Name of the current score file (@pxref{Scoring}).
+@item d
+Number of dormant articles (@pxref{Unread Articles}).
+@item t
+Number of ticked articles (@pxref{Unread Articles}).
+@item r
+Number of articles that have been marked as read in this session.
+@item E
+Number of articles expunged by the score files.
+@end table
+
+
+@node Summary Highlighting
+@subsection Summary Highlighting
+
+@table @code
+
+@item gnus-visual-mark-article-hook
+@vindex gnus-visual-mark-article-hook
+This hook is run after selecting an article.  It is meant to be used for
+highlighting the article in some way.  It is not run if
+@code{gnus-visual} is @code{nil}.
+
+@item gnus-summary-update-hook
+@vindex gnus-summary-update-hook
+This hook is called when a summary line is changed.  It is not run if
+@code{gnus-visual} is @code{nil}.
+
+@item gnus-summary-selected-face
+@vindex gnus-summary-selected-face
+This is the face (or @dfn{font} as some people call it) used to
+highlight the current article in the summary buffer.
+
+@item gnus-summary-highlight
+@vindex gnus-summary-highlight
+Summary lines are highlighted according to this variable, which is a
+list where the elements are of the format @code{(@var{form}
+. @var{face})}.  If you would, for instance, like ticked articles to be
+italic and high-scored articles to be bold, you could set this variable
+to something like
+@lisp
+(((eq mark gnus-ticked-mark) . italic)
+ ((> score default) . bold))
+@end lisp
+As you may have guessed, if @var{form} returns a non-@code{nil} value,
+@var{face} will be applied to the line.
+@end table
+
+
+@node Summary Maneuvering
+@section Summary Maneuvering
+@cindex summary movement
+
+All the straight movement commands understand the numeric prefix and
+behave pretty much as you'd expect.
+
+None of these commands select articles.
+
+@table @kbd
+@item G M-n
+@itemx M-n
+@kindex M-n (Summary)
+@kindex G M-n (Summary)
+@findex gnus-summary-next-unread-subject
+Go to the next summary line of an unread article
+(@code{gnus-summary-next-unread-subject}).
+
+@item G M-p
+@itemx M-p
+@kindex M-p (Summary)
+@kindex G M-p (Summary)
+@findex gnus-summary-prev-unread-subject
+Go to the previous summary line of an unread article
+(@code{gnus-summary-prev-unread-subject}).
+
+@item G g
+@kindex G g (Summary)
+@findex gnus-summary-goto-subject
+Ask for an article number and then go to the summary line of that article
+without displaying the article (@code{gnus-summary-goto-subject}).
+@end table
+
+If Gnus asks you to press a key to confirm going to the next group, you
+can use the @kbd{C-n} and @kbd{C-p} keys to move around the group
+buffer, searching for the next group to read without actually returning
+to the group buffer.
+
+Variables related to summary movement:
+
+@table @code
+
+@vindex gnus-auto-select-next
+@item gnus-auto-select-next
+If you issue one of the movement commands (like @kbd{n}) and there are
+no more unread articles after the current one, Gnus will offer to go to
+the next group.  If this variable is @code{t} and the next group is
+empty, Gnus will exit summary mode and return to the group buffer.  If
+this variable is neither @code{t} nor @code{nil}, Gnus will select the
+next group with unread articles.  As a special case, if this variable
+is @code{quietly}, Gnus will select the next group without asking for
+confirmation.  If this variable is @code{almost-quietly}, the same
+will happen only if you are located on the last article in the group.
+Finally, if this variable is @code{slightly-quietly}, the @kbd{Z n}
+command will go to the next group without confirmation.  Also
+@pxref{Group Levels}.
+
+@item gnus-auto-select-same
+@vindex gnus-auto-select-same
+If non-@code{nil}, all the movement commands will try to go to the next
+article with the same subject as the current.  (@dfn{Same} here might
+mean @dfn{roughly equal}.  See @code{gnus-summary-gather-subject-limit}
+for details (@pxref{Customizing Threading}).)  If there are no more
+articles with the same subject, go to the first unread article.
+
+This variable is not particularly useful if you use a threaded display.
+
+@item gnus-summary-check-current
+@vindex gnus-summary-check-current
+If non-@code{nil}, all the ``unread'' movement commands will not proceed
+to the next (or previous) article if the current article is unread.
+Instead, they will choose the current article.
+
+@item gnus-auto-center-summary
+@vindex gnus-auto-center-summary
+If non-@code{nil}, Gnus will keep the point in the summary buffer
+centered at all times.  This makes things quite tidy, but if you have a
+slow network connection, or simply do not like this un-Emacsism, you can
+set this variable to @code{nil} to get the normal Emacs scrolling
+action.  This will also inhibit horizontal re-centering of the summary
+buffer, which might make it more inconvenient to read extremely long
+threads.
+
+This variable can also be a number.  In that case, center the window at
+the given number of lines from the top.
+
+@item gnus-summary-stop-at-end-of-message
+@vindex gnus-summary-stop-at-end-of-message
+If non-@code{nil}, don't go to the next article when hitting
+@kbd{SPC}, and you're at the end of the article.
+
+@end table
+
+
+@node Choosing Articles
+@section Choosing Articles
+@cindex selecting articles
+
+@menu
+* Choosing Commands::           Commands for choosing articles.
+* Choosing Variables::          Variables that influence these commands.
+@end menu
+
+
+@node Choosing Commands
+@subsection Choosing Commands
+
+None of the following movement commands understand the numeric prefix,
+and they all select and display an article.
+
+If you want to fetch new articles or redisplay the group, see
+@ref{Exiting the Summary Buffer}.
+
+@table @kbd
+@item SPACE
+@kindex SPACE (Summary)
+@findex gnus-summary-next-page
+Select the current article, or, if that one's read already, the next
+unread article (@code{gnus-summary-next-page}).
+
+If you have an article window open already and you press @kbd{SPACE}
+again, the article will be scrolled.  This lets you conveniently
+@kbd{SPACE} through an entire newsgroup.  @xref{Paging the Article}.
+
+@item G n
+@itemx n
+@kindex n (Summary)
+@kindex G n (Summary)
+@findex gnus-summary-next-unread-article
+@c @icon{gnus-summary-next-unread}
+Go to next unread article (@code{gnus-summary-next-unread-article}).
+
+@item G p
+@itemx p
+@kindex p (Summary)
+@findex gnus-summary-prev-unread-article
+@c @icon{gnus-summary-prev-unread}
+Go to previous unread article (@code{gnus-summary-prev-unread-article}).
+
+@item G N
+@itemx N
+@kindex N (Summary)
+@kindex G N (Summary)
+@findex gnus-summary-next-article
+Go to the next article (@code{gnus-summary-next-article}).
+
+@item G P
+@itemx P
+@kindex P (Summary)
+@kindex G P (Summary)
+@findex gnus-summary-prev-article
+Go to the previous article (@code{gnus-summary-prev-article}).
+
+@item G C-n
+@kindex G C-n (Summary)
+@findex gnus-summary-next-same-subject
+Go to the next article with the same subject
+(@code{gnus-summary-next-same-subject}).
+
+@item G C-p
+@kindex G C-p (Summary)
+@findex gnus-summary-prev-same-subject
+Go to the previous article with the same subject
+(@code{gnus-summary-prev-same-subject}).
+
+@item G f
+@itemx .
+@kindex G f  (Summary)
+@kindex .  (Summary)
+@findex gnus-summary-first-unread-article
+Go to the first unread article
+(@code{gnus-summary-first-unread-article}).
+
+@item G b
+@itemx ,
+@kindex G b (Summary)
+@kindex , (Summary)
+@findex 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
+@kindex l (Summary)
+@kindex G l (Summary)
+@findex gnus-summary-goto-last-article
+Go to the previous article read (@code{gnus-summary-goto-last-article}).
+
+@item G o
+@kindex G o (Summary)
+@findex gnus-summary-pop-article
+@cindex history
+@cindex article history
+Pop an article off the summary history and go to this article
+(@code{gnus-summary-pop-article}).  This command differs from the
+command above in that you can pop as many previous articles off the
+history as you like, while @kbd{l} toggles the two last read articles.
+For a somewhat related issue (if you use these commands a lot),
+@pxref{Article Backlog}.
+
+@item G j
+@itemx j
+@kindex j (Summary)
+@kindex G j (Summary)
+@findex gnus-summary-goto-article
+Ask for an article number or @code{Message-ID}, and then go to that
+article (@code{gnus-summary-goto-article}).
+
+@end table
+
+
+@node Choosing Variables
+@subsection Choosing Variables
+
+Some variables relevant for moving and selecting articles:
+
+@table @code
+@item gnus-auto-extend-newsgroup
+@vindex gnus-auto-extend-newsgroup
+All the movement commands will try to go to the previous (or next)
+article, even if that article isn't displayed in the Summary buffer if
+this variable is non-@code{nil}.  Gnus will then fetch the article from
+the server and display it in the article buffer.
+
+@item gnus-select-article-hook
+@vindex gnus-select-article-hook
+This hook is called whenever an article is selected.  The default is
+@code{nil}.  If you would like each article to be saved in the Agent as
+you read it, putting @code{gnus-agent-fetch-selected-article} on this
+hook will do so.
+
+@item gnus-mark-article-hook
+@vindex gnus-mark-article-hook
+@findex gnus-summary-mark-unread-as-read
+@findex gnus-summary-mark-read-and-unread-as-read
+@findex gnus-unread-mark
+This hook is called whenever an article is selected.  It is intended to
+be used for marking articles as read.  The default value is
+@code{gnus-summary-mark-read-and-unread-as-read}, and will change the
+mark of almost any article you read to @code{gnus-read-mark}.  The only
+articles not affected by this function are ticked, dormant, and
+expirable articles.  If you'd instead like to just have unread articles
+marked as read, you can use @code{gnus-summary-mark-unread-as-read}
+instead.  It will leave marks like @code{gnus-low-score-mark},
+@code{gnus-del-mark} (and so on) alone.
+
+@end table
+
+
+@node Paging the Article
+@section Scrolling the Article
+@cindex article scrolling
+
+@table @kbd
+
+@item SPACE
+@kindex SPACE (Summary)
+@findex gnus-summary-next-page
+Pressing @kbd{SPACE} will scroll the current article forward one page,
+or, if you have come to the end of the current article, will choose the
+next article (@code{gnus-summary-next-page}).
+
+@vindex gnus-article-boring-faces
+@vindex gnus-article-skip-boring
+If @code{gnus-article-skip-boring} is non-@code{nil} and the rest of
+the article consists only of citations and signature, then it will be
+skipped; the next article will be shown instead.  You can customize
+what is considered uninteresting with
+@code{gnus-article-boring-faces}.  You can manually view the article's
+pages, no matter how boring, using @kbd{C-M-v}.
+
+@item DEL
+@kindex DEL (Summary)
+@findex gnus-summary-prev-page
+Scroll the current article back one page (@code{gnus-summary-prev-page}).
+
+@item RET
+@kindex RET (Summary)
+@findex gnus-summary-scroll-up
+Scroll the current article one line forward
+(@code{gnus-summary-scroll-up}).
+
+@item M-RET
+@kindex M-RET (Summary)
+@findex gnus-summary-scroll-down
+Scroll the current article one line backward
+(@code{gnus-summary-scroll-down}).
+
+@item A g
+@itemx g
+@kindex A g (Summary)
+@kindex g (Summary)
+@findex gnus-summary-show-article
+@vindex gnus-summary-show-article-charset-alist
+(Re)fetch the current article (@code{gnus-summary-show-article}).  If
+given a prefix, show a completely ``raw'' article, just the way it
+came from the server.  If given a prefix twice (i.e., @kbd{C-u C-u
+g'}), fetch the current article, but don't run any of the article
+treatment functions.
+
+@cindex charset, view article with different charset
+If given a numerical prefix, you can do semi-manual charset stuff.
+@kbd{C-u 0 g cn-gb-2312 RET} will decode the message as if it were
+encoded in the @code{cn-gb-2312} charset.  If you have
+
+@lisp
+(setq gnus-summary-show-article-charset-alist
+      '((1 . cn-gb-2312)
+        (2 . big5)))
+@end lisp
+
+then you can say @kbd{C-u 1 g} to get the same effect.
+
+@item A <
+@itemx <
+@kindex < (Summary)
+@kindex A < (Summary)
+@findex gnus-summary-beginning-of-article
+Scroll to the beginning of the article
+(@code{gnus-summary-beginning-of-article}).
+
+@item A >
+@itemx >
+@kindex > (Summary)
+@kindex A > (Summary)
+@findex gnus-summary-end-of-article
+Scroll to the end of the article (@code{gnus-summary-end-of-article}).
+
+@item A s
+@itemx s
+@kindex A s (Summary)
+@kindex s (Summary)
+@findex gnus-summary-isearch-article
+Perform an isearch in the article buffer
+(@code{gnus-summary-isearch-article}).
+
+@item h
+@kindex h (Summary)
+@findex gnus-summary-select-article-buffer
+Select the article buffer (@code{gnus-summary-select-article-buffer}).
+
+@end table
+
+
+@node Reply Followup and Post
+@section Reply, Followup and Post
+
+@menu
+* Summary Mail Commands::       Sending mail.
+* Summary Post Commands::       Sending news.
+* Summary Message Commands::    Other Message-related commands.
+* Canceling and Superseding::
+@end menu
+
+
+@node Summary Mail Commands
+@subsection Summary Mail Commands
+@cindex mail
+@cindex composing mail
+
+Commands for composing a mail message:
+
+@table @kbd
+
+@item S r
+@itemx r
+@kindex S r (Summary)
+@kindex r (Summary)
+@findex gnus-summary-reply
+@c @icon{gnus-summary-mail-reply}
+@c @icon{gnus-summary-reply}
+Mail a reply to the author of the current article
+(@code{gnus-summary-reply}).
+
+@item S R
+@itemx R
+@kindex R (Summary)
+@kindex S R (Summary)
+@findex gnus-summary-reply-with-original
+@c @icon{gnus-summary-reply-with-original}
+Mail a reply to the author of the current article and include the
+original message (@code{gnus-summary-reply-with-original}).  This
+command uses the process/prefix convention.
+
+@item S w
+@kindex S w (Summary)
+@findex gnus-summary-wide-reply
+Mail a wide reply to the author of the current article
+(@code{gnus-summary-wide-reply}).  A @dfn{wide reply} is a reply that
+goes out to all people listed in the @code{To}, @code{From} (or
+@code{Reply-to}) and @code{Cc} headers.  If @code{Mail-Followup-To} is
+present, that's used instead.
+
+@item S W
+@kindex S W (Summary)
+@findex gnus-summary-wide-reply-with-original
+Mail a 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, but only uses the headers from the
+first article to determine the recipients.
+
+@item S L
+@kindex S L (Summary)
+@findex gnus-summary-reply-to-list-with-original
+When replying to a message from a mailing list, send a reply to that
+message to the mailing list, and include the original message
+(@code{gnus-summary-reply-to-list-with-original}).
+
+@item S v
+@kindex S v (Summary)
+@findex gnus-summary-very-wide-reply
+Mail a very wide reply to the author of the current article
+(@code{gnus-summary-wide-reply}).  A @dfn{very wide reply} is a reply
+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 V
+@kindex S V (Summary)
+@findex gnus-summary-very-wide-reply-with-original
+Mail a very wide reply to the author of the current article and include the
+original message (@code{gnus-summary-very-wide-reply-with-original}).  This
+command uses the process/prefix convention.
+
+@item S B r
+@kindex S B r (Summary)
+@findex gnus-summary-reply-broken-reply-to
+Mail a reply to the author of the current article but ignore the
+@code{Reply-To} field (@code{gnus-summary-reply-broken-reply-to}).
+If you need this because a mailing list incorrectly sets a
+@code{Reply-To} header pointing to the list, you probably want to set
+the @code{broken-reply-to} group parameter instead, so things will work
+correctly.  @xref{Group Parameters}.
+
+@item S B R
+@kindex S B R (Summary)
+@findex gnus-summary-reply-broken-reply-to-with-original
+Mail a reply to the author of the current article and include the
+original message but ignore the @code{Reply-To} field
+(@code{gnus-summary-reply-broken-reply-to-with-original}).
+
+@item S o m
+@itemx C-c C-f
+@kindex S o m (Summary)
+@kindex C-c C-f (Summary)
+@findex gnus-summary-mail-forward
+@c @icon{gnus-summary-mail-forward}
+Forward the current article to some other person
+(@code{gnus-summary-mail-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
+message and forward directly inline; if the prefix is 2, forward message
+as an rfc822 @acronym{MIME} section; if the prefix is 3, decode message and
+forward as an rfc822 @acronym{MIME} section; if the prefix is 4, forward message
+directly inline; otherwise, the message is forwarded as no prefix given
+but use the flipped value of (@code{message-forward-as-mime}).  By
+default, the message is decoded and forwarded as an rfc822 @acronym{MIME}
+section.
+
+@item S m
+@itemx m
+@kindex m (Summary)
+@kindex S m (Summary)
+@findex gnus-summary-mail-other-window
+@c @icon{gnus-summary-mail-originate}
+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
+@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)
+@findex gnus-summary-resend-bounced-mail
+@cindex bouncing mail
+If you have sent a mail, but the mail was bounced back to you for some
+reason (wrong address, transient failure), you can use this command to
+resend that bounced mail (@code{gnus-summary-resend-bounced-mail}).  You
+will be popped into a mail buffer where you can edit the headers before
+sending the mail off again.  If you give a prefix to this command, and
+the bounced mail is a reply to some other mail, Gnus will try to fetch
+that mail and display it for easy perusal of its headers.  This might
+very well fail, though.
+
+@item S D r
+@kindex S D r (Summary)
+@findex gnus-summary-resend-message
+Not to be confused with the previous command,
+@code{gnus-summary-resend-message} will prompt you for an address to
+send the current message off to, and then send it to that place.  The
+headers of the message won't be altered---but lots of headers that say
+@code{Resent-To}, @code{Resent-From} and so on will be added.  This
+means that you actually send a mail to someone that has a @code{To}
+header that (probably) points to yourself.  This will confuse people.
+So, natcherly you'll only do that if you're really eVIl.
+
+This command is mainly used if you have several accounts and want to
+ship a mail to a different account of yours.  (If you're both
+@code{root} and @code{postmaster} and get a mail for @code{postmaster}
+to the @code{root} account, you may want to resend it to
+@code{postmaster}.  Ordnung muss sein!
+
+This command understands the process/prefix convention
+(@pxref{Process/Prefix}).
+
+@item S D e
+@kindex S D e (Summary)
+@findex gnus-summary-resend-message-edit
+
+Like the previous command, but will allow you to edit the message as
+if it were a new message before resending.
+
+@item S O m
+@kindex S O m (Summary)
+@findex gnus-uu-digest-mail-forward
+Digest the current series (@pxref{Decoding Articles}) and forward the
+result using mail (@code{gnus-uu-digest-mail-forward}).  This command
+uses the process/prefix convention (@pxref{Process/Prefix}).
+
+@item S M-c
+@kindex S M-c (Summary)
+@findex gnus-summary-mail-crosspost-complaint
+@cindex crossposting
+@cindex excessive crossposting
+Send a complaint about excessive crossposting to the author of the
+current article (@code{gnus-summary-mail-crosspost-complaint}).
+
+@findex gnus-crosspost-complaint
+This command is provided as a way to fight back against the current
+crossposting pandemic that's sweeping Usenet.  It will compose a reply
+using the @code{gnus-crosspost-complaint} variable as a preamble.  This
+command understands the process/prefix convention
+(@pxref{Process/Prefix}) and will prompt you before sending each mail.
+
+@end table
+
+Also @xref{Header Commands, ,Header Commands, message, The Message
+Manual}, for more information.
+
+
+@node Summary Post Commands
+@subsection Summary Post Commands
+@cindex post
+@cindex composing news
+
+Commands for posting a news article:
+
+@table @kbd
+@item S p
+@itemx a
+@kindex a (Summary)
+@kindex S p (Summary)
+@findex gnus-summary-post-news
+@c @icon{gnus-summary-post-news}
+Prepare for posting an article (@code{gnus-summary-post-news}).  By
+default, post to the current group.  If given a prefix, disable that.
+If the prefix is 1, prompt for another group instead.
+
+@item S f
+@itemx f
+@kindex f (Summary)
+@kindex S f (Summary)
+@findex gnus-summary-followup
+@c @icon{gnus-summary-followup}
+Post a followup to the current article (@code{gnus-summary-followup}).
+
+@item S F
+@itemx F
+@kindex S F (Summary)
+@kindex F (Summary)
+@c @icon{gnus-summary-followup-with-original}
+@findex gnus-summary-followup-with-original
+Post a followup to the current article and include the original message
+(@code{gnus-summary-followup-with-original}).  This command uses the
+process/prefix convention.
+
+@item S n
+@kindex S n (Summary)
+@findex gnus-summary-followup-to-mail
+Post a followup to the current article via news, even if you got the
+message through mail (@code{gnus-summary-followup-to-mail}).
+
+@item S N
+@kindex S N (Summary)
+@findex gnus-summary-followup-to-mail-with-original
+Post a followup to the current article via news, even if you got the
+message through mail and include the original message
+(@code{gnus-summary-followup-to-mail-with-original}).  This command uses
+the process/prefix convention.
+
+@item S o p
+@kindex S o p (Summary)
+@findex gnus-summary-post-forward
+Forward the current article to a newsgroup
+(@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
+message and forward directly inline; if the prefix is 2, forward message
+as an rfc822 @acronym{MIME} section; if the prefix is 3, decode message and
+forward as an rfc822 @acronym{MIME} section; if the prefix is 4, forward message
+directly inline; otherwise, the message is forwarded as no prefix given
+but use the flipped value of (@code{message-forward-as-mime}).  By
+default, the message is decoded and forwarded as an rfc822 @acronym{MIME} section.
+
+@item S O p
+@kindex S O p (Summary)
+@findex gnus-uu-digest-post-forward
+@cindex digests
+@cindex making digests
+Digest the current series and forward the result to a newsgroup
+(@code{gnus-uu-digest-post-forward}).  This command uses the
+process/prefix convention.
+
+@item S u
+@kindex S u (Summary)
+@findex gnus-uu-post-news
+@c @icon{gnus-uu-post-news}
+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 @xref{Header Commands, ,Header Commands, message, The Message
+Manual}, for more information.
+
+
+@node Summary Message Commands
+@subsection Summary Message Commands
+
+@table @kbd
+@item S y
+@kindex S y (Summary)
+@findex gnus-summary-yank-message
+Yank the current article into an already existing Message composition
+buffer (@code{gnus-summary-yank-message}).  This command prompts for
+what message buffer you want to yank into, and understands the
+process/prefix convention (@pxref{Process/Prefix}).
+
+@end table
+
+
+@node Canceling and Superseding
+@subsection Canceling Articles
+@cindex canceling articles
+@cindex superseding articles
+
+Have you ever written something, and then decided that you really,
+really, really wish you hadn't posted that?
+
+Well, you can't cancel mail, but you can cancel posts.
+
+@findex gnus-summary-cancel-article
+@kindex C (Summary)
+@c @icon{gnus-summary-cancel-article}
+Find the article you wish to cancel (you can only cancel your own
+articles, so don't try any funny stuff).  Then press @kbd{C} or @kbd{S
+c} (@code{gnus-summary-cancel-article}).  Your article will be
+canceled---machines all over the world will be deleting your article.
+This command uses the process/prefix convention (@pxref{Process/Prefix}).
+
+Be aware, however, that not all sites honor cancels, so your article may
+live on here and there, while most sites will delete the article in
+question.
+
+Gnus will use the ``current'' select method when canceling.  If you
+want to use the standard posting method, use the @samp{a} symbolic
+prefix (@pxref{Symbolic Prefixes}).
+
+Gnus ensures that only you can cancel your own messages using a
+@code{Cancel-Lock} header (@pxref{Canceling News, Canceling News, ,
+message, Message Manual}).
+
+If you discover that you have made some mistakes and want to do some
+corrections, you can post a @dfn{superseding} article that will replace
+your original article.
+
+@findex gnus-summary-supersede-article
+@kindex S (Summary)
+Go to the original article and press @kbd{S s}
+(@code{gnus-summary-supersede-article}).  You will be put in a buffer
+where you can edit the article all you want before sending it off the
+usual way.
+
+The same goes for superseding as for canceling, only more so: Some
+sites do not honor superseding.  On those sites, it will appear that you
+have posted almost the same article twice.
+
+If you have just posted the article, and change your mind right away,
+there is a trick you can use to cancel/supersede the article without
+waiting for the article to appear on your site first.  You simply return
+to the post buffer (which is called @file{*sent ...*}).  There you will
+find the article you just posted, with all the headers intact.  Change
+the @code{Message-ID} header to a @code{Cancel} or @code{Supersedes}
+header by substituting one of those words for the word
+@code{Message-ID}.  Then just press @kbd{C-c C-c} to send the article as
+you would do normally.  The previous article will be
+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{YYYY-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.
+
+@findex gnus-delay-send-queue
+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 @code{gnus-delay-send-queue} in
+@code{gnus-get-new-news-hook}.  But it accepts the optional second
+argument @code{no-check}.  If it is non-@code{nil},
+@code{gnus-get-new-news-hook} is not changed.  The optional first
+argument is ignored.
+
+For example, @code{(gnus-delay-initialize nil t)} means to do nothing.
+Presumably, you want to use the demon for sending due delayed articles.
+Just don't forget to set that up :-)
+@end table
+
+When delaying an article with @kbd{C-c C-j}, Message mode will
+automatically add a @code{"Date"} header with the current time.  In
+many cases you probably want the @code{"Date"} header to reflect the
+time the message is sent instead.  To do this, you have to delete
+@code{Date} from @code{message-draft-headers}.
+
+
+@node Marking Articles
+@section Marking Articles
+@cindex article marking
+@cindex article ticking
+@cindex marks
+
+There are several marks you can set on an article.
+
+You have marks that decide the @dfn{readedness} (whoo, neato-keano
+neologism ohoy!) of the article.  Alphabetic marks generally mean
+@dfn{read}, while non-alphabetic characters generally mean @dfn{unread}.
+
+In addition, you also have marks that do not affect readedness.
+
+@ifinfo
+There's a plethora of commands for manipulating these marks.
+@end ifinfo
+
+@menu
+* 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.
+@end menu
+
+
+@node Unread Articles
+@subsection Unread Articles
+
+The following marks mark articles as (kinda) unread, in one form or
+other.
+
+@table @samp
+@item !
+@vindex gnus-ticked-mark
+Marked as ticked (@code{gnus-ticked-mark}).
+
+@dfn{Ticked articles} are articles that will remain visible always.  If
+you see an article that you find interesting, or you want to put off
+reading it, or replying to it, until sometime later, you'd typically
+tick it.  However, articles can be expired (from news servers by the
+news server software, Gnus itself never expires ticked messages), so if
+you want to keep an article forever, you'll have to make it persistent
+(@pxref{Persistent Articles}).
+
+@item ?
+@vindex gnus-dormant-mark
+Marked as dormant (@code{gnus-dormant-mark}).
+
+@dfn{Dormant articles} will only appear in the summary buffer if there
+are followups to it.  If you want to see them even if they don't have
+followups, you can use the @kbd{/ D} command (@pxref{Limiting}).
+Otherwise (except for the visibility issue), they are just like ticked
+messages.
+
+@item SPACE
+@vindex gnus-unread-mark
+Marked as unread (@code{gnus-unread-mark}).
+
+@dfn{Unread articles} are articles that haven't been read at all yet.
+@end table
+
+
+@node Read Articles
+@subsection Read Articles
+@cindex expirable mark
+
+All the following marks mark articles as read.
+
+@table @samp
+
+@item r
+@vindex gnus-del-mark
+These are articles that the user has marked as read with the @kbd{d}
+command manually, more or less (@code{gnus-del-mark}).
+
+@item R
+@vindex gnus-read-mark
+Articles that have actually been read (@code{gnus-read-mark}).
+
+@item O
+@vindex gnus-ancient-mark
+Articles that were marked as read in previous sessions and are now
+@dfn{old} (@code{gnus-ancient-mark}).
+
+@item K
+@vindex gnus-killed-mark
+Marked as killed (@code{gnus-killed-mark}).
+
+@item X
+@vindex gnus-kill-file-mark
+Marked as killed by kill files (@code{gnus-kill-file-mark}).
+
+@item Y
+@vindex gnus-low-score-mark
+Marked as read by having too low a score (@code{gnus-low-score-mark}).
+
+@item C
+@vindex gnus-catchup-mark
+Marked as read by a catchup (@code{gnus-catchup-mark}).
+
+@item G
+@vindex gnus-canceled-mark
+Canceled article (@code{gnus-canceled-mark})
+
+@item Q
+@vindex gnus-sparse-mark
+Sparsely reffed article (@code{gnus-sparse-mark}).  @xref{Customizing
+Threading}.
+
+@item M
+@vindex gnus-duplicate-mark
+Article marked as read by duplicate suppression
+(@code{gnus-duplicate-mark}).  @xref{Duplicate Suppression}.
+
+@end table
+
+All these marks just mean that the article is marked as read, really.
+They are interpreted differently when doing adaptive scoring, though.
+
+One more special mark, though:
+
+@table @samp
+@item E
+@vindex gnus-expirable-mark
+Marked as expirable (@code{gnus-expirable-mark}).
+
+Marking articles as @dfn{expirable} (or have them marked as such
+automatically) doesn't make much sense in normal groups---a user doesn't
+control expiring of news articles, but in mail groups, for instance,
+articles marked as @dfn{expirable} can be deleted by Gnus at
+any time.
+@end table
+
+
+@node Other Marks
+@subsection Other Marks
+@cindex process mark
+@cindex bookmarks
+
+There are some marks that have nothing to do with whether the article is
+read or not.
+
+@itemize @bullet
+
+@item
+You can set a bookmark in the current article.  Say you are reading a
+long thesis on cats' urinary tracts, and have to go home for dinner
+before you've finished reading the thesis.  You can then set a bookmark
+in the article, and Gnus will jump to this bookmark the next time it
+encounters the article.  @xref{Setting Marks}.
+
+@item
+@vindex gnus-replied-mark
+All articles that you have replied to or made a followup to (i.e., have
+answered) will be marked with an @samp{A} in the second column
+(@code{gnus-replied-mark}).
+
+@item
+@vindex gnus-forwarded-mark
+All articles that you have forwarded will be marked with an @samp{F} in
+the second column (@code{gnus-forwarded-mark}).
+
+@item
+@vindex gnus-cached-mark
+Articles stored in the article cache will be marked with an @samp{*} in
+the second column (@code{gnus-cached-mark}).  @xref{Article Caching}.
+
+@item
+@vindex gnus-saved-mark
+Articles ``saved'' (in some manner or other; not necessarily
+religiously) are marked with an @samp{S} in the second column
+(@code{gnus-saved-mark}).
+
+@item
+@vindex gnus-unseen-mark
+Articles that haven't been seen before in Gnus by the user are marked
+with a @samp{.} in the second column (@code{gnus-unseen-mark}).
+
+@item
+@vindex gnus-downloaded-mark
+When using the Gnus agent (@pxref{Agent Basics}), articles may be
+downloaded for unplugged (offline) viewing.  If you are using the
+@samp{%O} spec, these articles get the @samp{+} mark in that spec.
+(The variable @code{gnus-downloaded-mark} controls which character to
+use.)
+
+@item
+@vindex gnus-undownloaded-mark
+When using the Gnus agent (@pxref{Agent Basics}), some articles might
+not have been downloaded.  Such articles cannot be viewed while you
+are unplugged (offline).  If you are using the @samp{%O} spec, these
+articles get the @samp{-} mark in that spec.  (The variable
+@code{gnus-undownloaded-mark} controls which character to use.)
+
+@item
+@vindex gnus-downloadable-mark
+The Gnus agent (@pxref{Agent Basics}) downloads some articles
+automatically, but it is also possible to explicitly mark articles for
+download, even if they would not be downloaded automatically.  Such
+explicitly-marked articles get the @samp{%} mark in the first column.
+(The variable @code{gnus-downloadable-mark} controls which character to
+use.)
+
+@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
+marked with @code{gnus-not-empty-thread-mark} and
+@code{gnus-empty-thread-mark} in the third column, respectively.
+
+@item
+@vindex gnus-process-mark
+Finally we have the @dfn{process mark} (@code{gnus-process-mark}).  A
+variety of commands react to the presence of the process mark.  For
+instance, @kbd{X u} (@code{gnus-uu-decode-uu}) will uudecode and view
+all articles that have been marked with the process mark.  Articles
+marked with the process mark have a @samp{#} in the second column.
+
+@end itemize
+
+You might have noticed that most of these ``non-readedness'' marks
+appear in the second column by default.  So if you have a cached, saved,
+replied article that you have process-marked, what will that look like?
+
+Nothing much.  The precedence rules go as follows: process -> cache ->
+replied -> saved.  So if the article is in the cache and is replied,
+you'll only see the cache mark and not the replied mark.
+
+
+@node Setting Marks
+@subsection Setting Marks
+@cindex setting marks
+
+All the marking commands understand the numeric prefix.
+
+@table @kbd
+@item M c
+@itemx M-u
+@kindex M c (Summary)
+@kindex M-u (Summary)
+@findex gnus-summary-clear-mark-forward
+@cindex mark as unread
+Clear all readedness-marks from the current article
+(@code{gnus-summary-clear-mark-forward}).  In other words, mark the
+article as unread.
+
+@item M t
+@itemx !
+@kindex ! (Summary)
+@kindex M t (Summary)
+@findex gnus-summary-tick-article-forward
+Tick the current article (@code{gnus-summary-tick-article-forward}).
+@xref{Article Caching}.
+
+@item M ?
+@itemx ?
+@kindex ? (Summary)
+@kindex M ? (Summary)
+@findex gnus-summary-mark-as-dormant
+Mark the current article as dormant
+(@code{gnus-summary-mark-as-dormant}).  @xref{Article Caching}.
+
+@item M d
+@itemx d
+@kindex M d (Summary)
+@kindex d (Summary)
+@findex gnus-summary-mark-as-read-forward
+Mark the current article as read
+(@code{gnus-summary-mark-as-read-forward}).
+
+@item D
+@kindex D (Summary)
+@findex gnus-summary-mark-as-read-backward
+Mark the current article as read and move point to the previous line
+(@code{gnus-summary-mark-as-read-backward}).
+
+@item M k
+@itemx k
+@kindex k (Summary)
+@kindex M k (Summary)
+@findex gnus-summary-kill-same-subject-and-select
+Mark all articles that have the same subject as the current one as read,
+and then select the next unread article
+(@code{gnus-summary-kill-same-subject-and-select}).
+
+@item M K
+@itemx C-k
+@kindex M K (Summary)
+@kindex C-k (Summary)
+@findex gnus-summary-kill-same-subject
+Mark all articles that have the same subject as the current one as read
+(@code{gnus-summary-kill-same-subject}).
+
+@item M C
+@kindex M C (Summary)
+@findex gnus-summary-catchup
+@c @icon{gnus-summary-catchup}
+Mark all unread articles as read (@code{gnus-summary-catchup}).
+
+@item M C-c
+@kindex M C-c (Summary)
+@findex gnus-summary-catchup-all
+Mark all articles in the group as read---even the ticked and dormant
+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 (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
+Mark all articles between point and mark as read
+(@code{gnus-summary-mark-region-as-read}).
+
+@item M V k
+@kindex M V k (Summary)
+@findex gnus-summary-kill-below
+Kill all articles with scores below the default score (or below the
+numeric prefix) (@code{gnus-summary-kill-below}).
+
+@item M e
+@itemx E
+@kindex M e (Summary)
+@kindex E (Summary)
+@findex gnus-summary-mark-as-expirable
+Mark the current article as expirable
+(@code{gnus-summary-mark-as-expirable}).
+
+@item M b
+@kindex M b (Summary)
+@findex gnus-summary-set-bookmark
+Set a bookmark in the current article
+(@code{gnus-summary-set-bookmark}).
+
+@item M B
+@kindex M B (Summary)
+@findex gnus-summary-remove-bookmark
+Remove the bookmark from the current article
+(@code{gnus-summary-remove-bookmark}).
+
+@item M V c
+@kindex M V c (Summary)
+@findex gnus-summary-clear-above
+Clear all marks from articles with scores over the default score (or
+over the numeric prefix) (@code{gnus-summary-clear-above}).
+
+@item M V u
+@kindex M V u (Summary)
+@findex gnus-summary-tick-above
+Tick all articles with scores over the default score (or over the
+numeric prefix) (@code{gnus-summary-tick-above}).
+
+@item M V m
+@kindex M V m (Summary)
+@findex gnus-summary-mark-above
+Prompt for a mark, and mark all articles with scores over the default
+score (or over the numeric prefix) with this mark
+(@code{gnus-summary-clear-above}).
+@end table
+
+@vindex gnus-summary-goto-unread
+The @code{gnus-summary-goto-unread} variable controls what action should
+be taken after setting a mark.  If non-@code{nil}, point will move to
+the next/previous unread article.  If @code{nil}, point will just move
+one line up or down.  As a special case, if this variable is
+@code{never}, all the marking commands as well as other commands (like
+@kbd{SPACE}) will move to the next article, whether it is unread or not.
+The default is @code{t}.
+
+
+@node Generic Marking Commands
+@subsection Generic Marking Commands
+
+Some people would like the command that ticks an article (@kbd{!}) to
+go to the next article.  Others would like it to go to the next unread
+article.  Yet others would like it to stay on the current article.
+And even though I haven't heard of anybody wanting it to go to the
+previous (unread) article, I'm sure there are people that want that as
+well.
+
+Multiply these five behaviors with five different marking commands, and
+you get a potentially complex set of variable to control what each
+command should do.
+
+To sidestep that mess, Gnus provides commands that do all these
+different things.  They can be found on the @kbd{M M} map in the summary
+buffer.  Type @kbd{M M C-h} to see them all---there are too many of them
+to list in this manual.
+
+While you can use these commands directly, most users would prefer
+altering the summary mode keymap.  For instance, if you would like the
+@kbd{!} command to go to the next article instead of the next unread
+article, you could say something like:
+
+@lisp
+@group
+(add-hook 'gnus-summary-mode-hook 'my-alter-summary-map)
+(defun my-alter-summary-map ()
+  (local-set-key "!" 'gnus-summary-put-mark-as-ticked-next))
+@end group
+@end lisp
+
+@noindent
+or
+
+@lisp
+(defun my-alter-summary-map ()
+  (local-set-key "!" "MM!n"))
+@end lisp
+
+
+@node Setting Process Marks
+@subsection Setting Process Marks
+@cindex setting process marks
+
+Process marks are displayed as @code{#} in the summary buffer, and are
+used for marking articles in such a way that other commands will
+process these articles.  For instance, if you process mark four
+articles and then use the @kbd{*} command, Gnus will enter these four
+articles into the cache.  For more information,
+@pxref{Process/Prefix}.
+
+@table @kbd
+
+@item M P p
+@itemx #
+@kindex # (Summary)
+@kindex M P p (Summary)
+@findex gnus-summary-mark-as-processable
+Mark the current article with the process mark
+(@code{gnus-summary-mark-as-processable}).
+@findex gnus-summary-unmark-as-processable
+
+@item M P u
+@itemx M-#
+@kindex M P u (Summary)
+@kindex M-# (Summary)
+Remove the process mark, if any, from the current article
+(@code{gnus-summary-unmark-as-processable}).
+
+@item M P U
+@kindex M P U (Summary)
+@findex gnus-summary-unmark-all-processable
+Remove the process mark from all articles
+(@code{gnus-summary-unmark-all-processable}).
+
+@item M P i
+@kindex M P i (Summary)
+@findex gnus-uu-invert-processable
+Invert the list of process marked articles
+(@code{gnus-uu-invert-processable}).
+
+@item M P R
+@kindex M P R (Summary)
+@findex gnus-uu-mark-by-regexp
+Mark articles that have a @code{Subject} header that matches a regular
+expression (@code{gnus-uu-mark-by-regexp}).
+
+@item M P G
+@kindex M P G (Summary)
+@findex gnus-uu-unmark-by-regexp
+Unmark articles that have a @code{Subject} header that matches a regular
+expression (@code{gnus-uu-unmark-by-regexp}).
+
+@item M P r
+@kindex M P r (Summary)
+@findex gnus-uu-mark-region
+Mark articles in region (@code{gnus-uu-mark-region}).
+
+@item M P g
+@kindex M P g (Summary)
+@findex gnus-uu-unmark-region
+Unmark articles in region (@code{gnus-uu-unmark-region}).
+
+@item M P t
+@kindex M P t (Summary)
+@findex gnus-uu-mark-thread
+Mark all articles in the current (sub)thread
+(@code{gnus-uu-mark-thread}).
+
+@item M P T
+@kindex M P T (Summary)
+@findex gnus-uu-unmark-thread
+Unmark all articles in the current (sub)thread
+(@code{gnus-uu-unmark-thread}).
+
+@item M P v
+@kindex M P v (Summary)
+@findex gnus-uu-mark-over
+Mark all articles that have a score above the prefix argument
+(@code{gnus-uu-mark-over}).
+
+@item M P s
+@kindex M P s (Summary)
+@findex gnus-uu-mark-series
+Mark all articles in the current series (@code{gnus-uu-mark-series}).
+
+@item M P S
+@kindex M P S (Summary)
+@findex gnus-uu-mark-sparse
+Mark all series that have already had some articles marked
+(@code{gnus-uu-mark-sparse}).
+
+@item M P a
+@kindex M P a (Summary)
+@findex gnus-uu-mark-all
+Mark all articles in series order (@code{gnus-uu-mark-all}).
+
+@item M P b
+@kindex M P b (Summary)
+@findex gnus-uu-mark-buffer
+Mark all articles in the buffer in the order they appear
+(@code{gnus-uu-mark-buffer}).
+
+@item M P k
+@kindex M P k (Summary)
+@findex gnus-summary-kill-process-mark
+Push the current process mark set onto the stack and unmark all articles
+(@code{gnus-summary-kill-process-mark}).
+
+@item M P y
+@kindex M P y (Summary)
+@findex gnus-summary-yank-process-mark
+Pop the previous process mark set from the stack and restore it
+(@code{gnus-summary-yank-process-mark}).
+
+@item M P w
+@kindex M P w (Summary)
+@findex gnus-summary-save-process-mark
+Push the current process mark set onto the stack
+(@code{gnus-summary-save-process-mark}).
+
+@end table
+
+Also see the @kbd{&} command in @ref{Searching for Articles}, for how to
+set process marks based on article body contents.
+
+
+@node Limiting
+@section Limiting
+@cindex limiting
+
+It can be convenient to limit the summary buffer to just show some
+subset of the articles currently in the group.  The effect most limit
+commands have is to remove a few (or many) articles from the summary
+buffer.
+
+Limiting commands work on subsets of the articles already fetched from
+the servers.  These commands don't query the server for additional
+articles.
+
+@table @kbd
+
+@item / /
+@itemx / s
+@kindex / / (Summary)
+@findex gnus-summary-limit-to-subject
+Limit the summary buffer to articles that match some 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}).  If given a prefix, exclude
+matching articles.
+
+@item / R
+@kindex / R (Summary)
+@findex gnus-summary-limit-to-recipient
+Limit the summary buffer to articles that match some recipient
+(@code{gnus-summary-limit-to-recipient}).  If given a prefix, exclude
+matching articles.
+
+@item / A
+@kindex / A (Summary)
+@findex gnus-summary-limit-to-address
+Limit the summary buffer to articles in which contents of From, To or Cc
+header match a given address (@code{gnus-summary-limit-to-address}).  If
+given a prefix, exclude matching articles.
+
+@item / S
+@kindex / S (Summary)
+@findex gnus-summary-limit-to-singletons
+Limit the summary buffer to articles that aren't part of any displayed
+threads (@code{gnus-summary-limit-to-singletons}).  If given a prefix,
+limit to articles that are part of displayed threads.
+
+@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}).  If given a prefix, exclude
+matching articles.
+
+@item / u
+@itemx x
+@kindex / u (Summary)
+@kindex x (Summary)
+@findex gnus-summary-limit-to-unread
+Limit the summary buffer to articles not marked as read
+(@code{gnus-summary-limit-to-unread}).  If given a prefix, limit the
+buffer to articles strictly unread.  This means that ticked and
+dormant articles will also be excluded.
+
+@item / m
+@kindex / m (Summary)
+@findex gnus-summary-limit-to-marks
+Ask for a mark and then limit to all articles that have been marked
+with that mark (@code{gnus-summary-limit-to-marks}).
+
+@item / t
+@kindex / t (Summary)
+@findex gnus-summary-limit-to-age
+Ask for a number and then limit the summary buffer to articles older than (or equal to) that number of days
+(@code{gnus-summary-limit-to-age}).  If given a prefix, limit to
+articles younger than that number of days.
+
+@item / n
+@kindex / n (Summary)
+@findex gnus-summary-limit-to-articles
+With prefix @samp{n}, limit the summary buffer to the next @samp{n}
+articles.  If not given a prefix, use the process marked articles
+instead.  (@code{gnus-summary-limit-to-articles}).
+
+@item / w
+@kindex / w (Summary)
+@findex gnus-summary-pop-limit
+Pop the previous limit off the stack and restore it
+(@code{gnus-summary-pop-limit}).  If given a prefix, pop all limits off
+the stack.
+
+@item / .
+@kindex / . (Summary)
+@findex gnus-summary-limit-to-unseen
+Limit the summary buffer to the unseen articles
+(@code{gnus-summary-limit-to-unseen}).
+
+@item / v
+@kindex / v (Summary)
+@findex gnus-summary-limit-to-score
+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-predicate
+Limit the summary buffer to articles that satisfy the @code{display}
+group parameter predicate
+(@code{gnus-summary-limit-to-display-predicate}).  @xref{Group
+Parameters}, for more on this predicate.
+
+@item / r
+@kindex / r (Summary)
+@findex gnus-summary-limit-to-replied
+Limit the summary buffer to replied articles
+(@code{gnus-summary-limit-to-replied}).  If given a prefix, exclude
+replied articles.
+
+@item / E
+@itemx M S
+@kindex M S (Summary)
+@kindex / E (Summary)
+@findex gnus-summary-limit-include-expunged
+Include all expunged articles in the limit
+(@code{gnus-summary-limit-include-expunged}).
+
+@item / D
+@kindex / D (Summary)
+@findex gnus-summary-limit-include-dormant
+Include all dormant articles in the limit
+(@code{gnus-summary-limit-include-dormant}).
+
+@item / *
+@kindex / * (Summary)
+@findex gnus-summary-limit-include-cached
+Include all cached articles in the limit
+(@code{gnus-summary-limit-include-cached}).
+
+@item / d
+@kindex / d (Summary)
+@findex gnus-summary-limit-exclude-dormant
+Exclude all dormant articles from the limit
+(@code{gnus-summary-limit-exclude-dormant}).
+
+@item / M
+@kindex / M (Summary)
+@findex gnus-summary-limit-exclude-marks
+Exclude all marked articles (@code{gnus-summary-limit-exclude-marks}).
+
+@item / T
+@kindex / T (Summary)
+@findex gnus-summary-limit-include-thread
+Include all the articles in the current thread in the limit.
+
+@item / c
+@kindex / c (Summary)
+@findex gnus-summary-limit-exclude-childless-dormant
+Exclude all dormant articles that have no children from the limit@*
+(@code{gnus-summary-limit-exclude-childless-dormant}).
+
+@item / C
+@kindex / C (Summary)
+@findex gnus-summary-limit-mark-excluded-as-read
+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 / b
+@kindex / b (Summary)
+@findex gnus-summary-limit-to-bodies
+Limit the summary buffer to articles that have bodies that match a
+certain regexp (@code{gnus-summary-limit-to-bodies}).  If given a
+prefix, reverse the limit.  This command is quite slow since it
+requires selecting each article to find the matches.
+
+@item / h
+@kindex / h (Summary)
+@findex gnus-summary-limit-to-headers
+Like the previous command, only limit to headers instead
+(@code{gnus-summary-limit-to-headers}).
+
+@end table
+
+
+The following commands aren't limiting commands, but use the @kbd{/}
+prefix as well.
+
+@table @kbd
+@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
+
+
+@node Threading
+@section Threading
+@cindex threading
+@cindex article threading
+
+Gnus threads articles by default.  @dfn{To thread} is to put responses
+to articles directly after the articles they respond to---in a
+hierarchical fashion.
+
+Threading is done by looking at the @code{References} headers of the
+articles.  In a perfect world, this would be enough to build pretty
+trees, but unfortunately, the @code{References} header is often broken
+or simply missing.  Weird news propagation exacerbates the problem,
+so one has to employ other heuristics to get pleasing results.  A
+plethora of approaches exists, as detailed in horrible detail in
+@ref{Customizing Threading}.
+
+First, a quick overview of the concepts:
+
+@table @dfn
+@item root
+The top-most article in a thread; the first article in the thread.
+
+@item thread
+A tree-like article structure.
+
+@item sub-thread
+A small(er) section of this tree-like structure.
+
+@item loose threads
+Threads often lose their roots due to article expiry, or due to the root
+already having been read in a previous session, and not displayed in the
+summary buffer.  We then typically have many sub-threads that really
+belong to one thread, but are without connecting roots.  These are
+called loose threads.
+
+@item thread gathering
+An attempt to gather loose threads into bigger threads.
+
+@item sparse threads
+A thread where the missing articles have been ``guessed'' at, and are
+displayed as empty lines in the summary buffer.
+
+@end table
+
+
+@menu
+* Customizing Threading::       Variables you can change to affect the threading.
+* Thread Commands::             Thread based commands in the summary buffer.
+@end menu
+
+
+@node Customizing Threading
+@subsection Customizing Threading
+@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@dots{} but you were wrong!
+@end menu
+
+
+@node Loose Threads
+@subsubsection Loose Threads
+@cindex <
+@cindex >
+@cindex loose threads
+
+@table @code
+@item gnus-summary-make-false-root
+@vindex gnus-summary-make-false-root
+If non-@code{nil}, Gnus will gather all loose subtrees into one big tree
+and create a dummy root at the top.  (Wait a minute.  Root at the top?
+Yup.)  Loose subtrees occur when the real root has expired, or you've
+read or killed the root in a previous session.
+
+When there is no real root of a thread, Gnus will have to fudge
+something.  This variable says what fudging method Gnus should use.
+There are four possible values:
+
+@iftex
+@iflatex
+\gnusfigure{The Summary Buffer}{390}{
+\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
+
+@cindex adopting articles
+
+@table @code
+
+@item adopt
+Gnus will make the first of the orphaned articles the parent.  This
+parent will adopt all the other articles.  The adopted articles will be
+marked as such by pointy brackets (@samp{<>}) instead of the standard
+square brackets (@samp{[]}).  This is the default method.
+
+@item dummy
+@vindex gnus-summary-dummy-line-format
+@vindex gnus-summary-make-false-root-always
+Gnus will create a dummy summary line that will pretend to be the
+parent.  This dummy line does not correspond to any real article, so
+selecting it will just select the first real article after the dummy
+article.  @code{gnus-summary-dummy-line-format} is used to specify the
+format of the dummy roots.  It accepts only one format spec:  @samp{S},
+which is the subject of the article.  @xref{Formatting Variables}.
+If you want all threads to have a dummy root, even the non-gathered
+ones, set @code{gnus-summary-make-false-root-always} to @code{t}.
+
+@item empty
+Gnus won't actually make any article the parent, but simply leave the
+subject field of all orphans except the first empty.  (Actually, it will
+use @code{gnus-summary-same-subject} as the subject (@pxref{Summary
+Buffer Format}).)
+
+@item none
+Don't make any article parent at all.  Just gather the threads and
+display them after one another.
+
+@item nil
+Don't gather loose threads.
+@end table
+
+@item gnus-summary-gather-subject-limit
+@vindex gnus-summary-gather-subject-limit
+Loose threads are gathered by comparing subjects of articles.  If this
+variable is @code{nil}, Gnus requires an exact match between the
+subjects of the loose threads before gathering them into one big
+super-thread.  This might be too strict a requirement, what with the
+presence of stupid newsreaders that chop off long subject lines.  If
+you think so, set this variable to, say, 20 to require that only the
+first 20 characters of the subjects have to match.  If you set this
+variable to a really low number, you'll find that Gnus will gather
+everything in sight into one thread, which isn't very helpful.
+
+@cindex fuzzy article gathering
+If you set this variable to the special value @code{fuzzy}, Gnus will
+use a fuzzy string comparison algorithm on the subjects (@pxref{Fuzzy
+Matching}).
+
+@item gnus-simplify-subject-fuzzy-regexp
+@vindex gnus-simplify-subject-fuzzy-regexp
+This can either be a regular expression or list of regular expressions
+that match strings that will be removed from subjects if fuzzy subject
+simplification is used.
+
+@item gnus-simplify-ignored-prefixes
+@vindex gnus-simplify-ignored-prefixes
+If you set @code{gnus-summary-gather-subject-limit} to something as low
+as 10, you might consider setting this variable to something sensible:
+
+@c Written by Michael Ernst <mernst@cs.rice.edu>
+@lisp
+(setq gnus-simplify-ignored-prefixes
+      (concat
+       "\\`\\[?\\("
+       (mapconcat
+        'identity
+        '("looking"
+          "wanted" "followup" "summary\\( of\\)?"
+          "help" "query" "problem" "question"
+          "answer" "reference" "announce"
+          "How can I" "How to" "Comparison of"
+          ;; ...
+          )
+        "\\|")
+       "\\)\\s *\\("
+       (mapconcat 'identity
+                  '("for" "for reference" "with" "about")
+                  "\\|")
+       "\\)?\\]?:?[ \t]*"))
+@end lisp
+
+All words that match this regexp will be removed before comparing two
+subjects.
+
+@item gnus-simplify-subject-functions
+@vindex gnus-simplify-subject-functions
+If non-@code{nil}, this variable overrides
+@code{gnus-summary-gather-subject-limit}.  This variable should be a
+list of functions to apply to the @code{Subject} string iteratively to
+arrive at the simplified version of the string.
+
+Useful functions to put in this list include:
+
+@table @code
+@item gnus-simplify-subject-re
+@findex gnus-simplify-subject-re
+Strip the leading @samp{Re:}.
+
+@item gnus-simplify-subject-fuzzy
+@findex gnus-simplify-subject-fuzzy
+Simplify fuzzily.
+
+@item gnus-simplify-whitespace
+@findex gnus-simplify-whitespace
+Remove excessive whitespace.
+
+@item gnus-simplify-all-whitespace
+@findex gnus-simplify-all-whitespace
+Remove all whitespace.
+@end table
+
+You may also write your own functions, of course.
+
+
+@item gnus-summary-gather-exclude-subject
+@vindex gnus-summary-gather-exclude-subject
+Since loose thread gathering is done on subjects only, that might lead
+to many false hits, especially with certain common subjects like
+@samp{} and @samp{(none)}.  To make the situation slightly better,
+you can use the regexp @code{gnus-summary-gather-exclude-subject} to say
+what subjects should be excluded from the gathering process.@*
+The default is @samp{^ *$\\|^(none)$}.
+
+@item gnus-summary-thread-gathering-function
+@vindex gnus-summary-thread-gathering-function
+Gnus gathers threads by looking at @code{Subject} headers.  This means
+that totally unrelated articles may end up in the same ``thread'', which
+is confusing.  An alternate approach is to look at all the
+@code{Message-ID}s in all the @code{References} headers to find matches.
+This will ensure that no gathered threads ever include unrelated
+articles, but it also means that people who have posted with broken
+newsreaders won't be gathered properly.  The choice is yours---plague or
+cholera:
+
+@table @code
+@item gnus-gather-threads-by-subject
+@findex gnus-gather-threads-by-subject
+This function is the default gathering function and looks at
+@code{Subject}s exclusively.
+
+@item gnus-gather-threads-by-references
+@findex gnus-gather-threads-by-references
+This function looks at @code{References} headers exclusively.
+@end table
+
+If you want to test gathering by @code{References}, you could say
+something like:
+
+@lisp
+(setq gnus-summary-thread-gathering-function
+      'gnus-gather-threads-by-references)
+@end lisp
+
+@end table
+
+
+@node Filling In Threads
+@subsubsection Filling In Threads
+
+@table @code
+@item gnus-fetch-old-headers
+@vindex gnus-fetch-old-headers
+If non-@code{nil}, Gnus will attempt to build old threads by fetching
+more old headers---headers to articles marked as read.  If you 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 back end you are using carries overview
+files---this would normally be @code{nntp}, @code{nnspool},
+@code{nnml}, and @code{nnmaildir}.  Also remember that if the root of
+the thread has been expired by the server, there's not much Gnus can
+do about that.
+
+This variable can also be set to @code{invisible}.  This won't have any
+visible effects, but is useful if you use the @kbd{A T} command a lot
+(@pxref{Finding the Parent}).
+
+The server has to support @acronym{NOV} for any of this to work.
+
+@cindex Gmane, gnus-fetch-old-headers
+This feature can seriously impact performance it ignores all locally
+cached header entries.  Setting it to @code{t} for groups for a server
+that doesn't expire articles (such as news.gmane.org), leads to very
+slow summary generation.
+
+@item gnus-fetch-old-ephemeral-headers
+@vindex gnus-fetch-old-ephemeral-headers
+Same as @code{gnus-fetch-old-headers}, but only used for ephemeral
+newsgroups.
+
+@item gnus-build-sparse-threads
+@vindex gnus-build-sparse-threads
+Fetching old headers can be slow.  A low-rent similar effect can be
+gotten by setting this variable to @code{some}.  Gnus will then look at
+the complete @code{References} headers of all articles and try to string
+together articles that belong in the same thread.  This will leave
+@dfn{gaps} in the threading display where Gnus guesses that an article
+is missing from the thread.  (These gaps appear like normal summary
+lines.  If you select a gap, Gnus will try to fetch the article in
+question.)  If this variable is @code{t}, Gnus will display all these
+``gaps'' without regard for whether they are useful for completing the
+thread or not.  Finally, if this variable is @code{more}, Gnus won't cut
+off sparse leaf nodes that don't lead anywhere.  This variable is
+@code{nil} by default.
+
+@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 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.
+
+If you don't use those, then it's safe to leave this as the default
+@code{nil}.  If you want to use this variable, it should be a regexp
+that matches the group name, or @code{t} for all groups.
+
+@end table
+
+
+@node More Threading
+@subsubsection More Threading
+
+@table @code
+@item gnus-show-threads
+@vindex gnus-show-threads
+If this variable is @code{nil}, no threading will be done, and all of
+the rest of the variables here will have no effect.  Turning threading
+off will speed group selection up a bit, but it is sure to make reading
+slower and more awkward.
+
+@item gnus-thread-hide-subtree
+@vindex gnus-thread-hide-subtree
+If non-@code{nil}, all threads will be hidden when the summary buffer is
+generated.
+
+This can also be a predicate specifier (@pxref{Predicate Specifiers}).
+Available predicates are @code{gnus-article-unread-p} and
+@code{gnus-article-unseen-p}.
+
+Here's an example:
+
+@lisp
+(setq gnus-thread-hide-subtree
+      '(or gnus-article-unread-p
+           gnus-article-unseen-p))
+@end lisp
+
+(It's a pretty nonsensical example, since all unseen articles are also
+unread, but you get my drift.)
+
+
+@item gnus-thread-expunge-below
+@vindex gnus-thread-expunge-below
+All threads that have a total score (as defined by
+@code{gnus-thread-score-function}) less than this number will be
+expunged.  This variable is @code{nil} by default, which means that no
+threads are expunged.
+
+@item gnus-thread-hide-killed
+@vindex gnus-thread-hide-killed
+if you kill a thread and this variable is non-@code{nil}, the subtree
+will be hidden.
+
+@item gnus-thread-ignore-subject
+@vindex gnus-thread-ignore-subject
+Sometimes somebody changes the subject in the middle of a thread.  If
+this variable is non-@code{nil}, which is the default, the subject
+change is ignored.  If it is @code{nil}, a change in the subject will
+result in a new thread.
+
+@item gnus-thread-indent-level
+@vindex gnus-thread-indent-level
+This is a number that says how much each sub-thread should be indented.
+The default is 4.
+
+@item gnus-sort-gathered-threads-function
+@vindex gnus-sort-gathered-threads-function
+Sometimes, particularly with mailing lists, the order in which mails
+arrive locally is not necessarily the same as the order in which they
+arrived on the mailing list.  Consequently, when sorting sub-threads
+using the default @code{gnus-thread-sort-by-number}, responses can end
+up appearing before the article to which they are responding to.
+Setting this variable to an alternate value
+(e.g., @code{gnus-thread-sort-by-date}), in a group's parameters or in an
+appropriate hook (e.g., @code{gnus-summary-generate-hook}) can produce a
+more logical sub-thread ordering in such instances.
+
+@end table
+
+
+@node Low-Level Threading
+@subsubsection Low-Level Threading
+
+@table @code
+
+@item gnus-parse-headers-hook
+@vindex gnus-parse-headers-hook
+Hook run before parsing any headers.
+
+@item gnus-alter-header-function
+@vindex gnus-alter-header-function
+If non-@code{nil}, this function will be called to allow alteration of
+article header structures.  The function is called with one parameter,
+the article header vector, which it may alter in any way.  For instance,
+if you have a mail-to-news gateway which alters the @code{Message-ID}s
+in systematic ways (by adding prefixes and such), you can use this
+variable to un-scramble the @code{Message-ID}s so that they are more
+meaningful.  Here's one example:
+
+@lisp
+(setq gnus-alter-header-function 'my-alter-message-id)
+
+(defun my-alter-message-id (header)
+  (let ((id (mail-header-id header)))
+    (when (string-match
+           "\\(<[^<>@@]*\\)\\.?cygnus\\..*@@\\([^<>@@]*>\\)" id)
+      (mail-header-set-id
+       (concat (match-string 1 id) "@@" (match-string 2 id))
+       header))))
+@end lisp
+
+@end table
+
+
+@node Thread Commands
+@subsection Thread Commands
+@cindex thread commands
+
+@table @kbd
+
+@item T k
+@itemx C-M-k
+@kindex T 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,
+remove all marks instead.  If the prefix argument is negative, tick
+articles instead.
+
+@item T l
+@itemx C-M-l
+@kindex T l (Summary)
+@kindex C-M-l (Summary)
+@findex gnus-summary-lower-thread
+Lower the score of the current (sub-)thread
+(@code{gnus-summary-lower-thread}).
+
+@item T i
+@kindex T i (Summary)
+@findex gnus-summary-raise-thread
+Increase the score of the current (sub-)thread
+(@code{gnus-summary-raise-thread}).
+
+@item T #
+@kindex T # (Summary)
+@findex gnus-uu-mark-thread
+Set the process mark on the current (sub-)thread
+(@code{gnus-uu-mark-thread}).
+
+@item T M-#
+@kindex T M-# (Summary)
+@findex gnus-uu-unmark-thread
+Remove the process mark from the current (sub-)thread
+(@code{gnus-uu-unmark-thread}).
+
+@item T T
+@kindex T T (Summary)
+@findex gnus-summary-toggle-threads
+Toggle threading (@code{gnus-summary-toggle-threads}).
+
+@item T s
+@kindex T s (Summary)
+@findex gnus-summary-show-thread
+Expose the (sub-)thread hidden under the current article, if any@*
+(@code{gnus-summary-show-thread}).
+
+@item T h
+@kindex T h (Summary)
+@findex gnus-summary-hide-thread
+Hide the current (sub-)thread (@code{gnus-summary-hide-thread}).
+
+@item T S
+@kindex T S (Summary)
+@findex gnus-summary-show-all-threads
+Expose all hidden threads (@code{gnus-summary-show-all-threads}).
+
+@item T H
+@kindex T H (Summary)
+@findex gnus-summary-hide-all-threads
+Hide all threads (@code{gnus-summary-hide-all-threads}).
+
+@item T t
+@kindex T t (Summary)
+@findex gnus-summary-rethread-current
+Re-thread the current article's thread
+(@code{gnus-summary-rethread-current}).  This works even when the
+summary buffer is otherwise unthreaded.
+
+@item T ^
+@kindex T ^ (Summary)
+@findex gnus-summary-reparent-thread
+Make the current article the child of the marked (or previous) article
+(@code{gnus-summary-reparent-thread}).
+
+@item T M-^
+@kindex T M-^ (Summary)
+@findex gnus-summary-reparent-children
+Make the current article the parent of the marked articles
+(@code{gnus-summary-reparent-children}).
+
+@end table
+
+The following commands are thread movement commands.  They all
+understand the numeric prefix.
+
+@table @kbd
+
+@item T n
+@kindex T n (Summary)
+@itemx C-M-f
+@kindex C-M-n (Summary)
+@itemx M-down
+@kindex M-down (Summary)
+@findex gnus-summary-next-thread
+Go to the next thread (@code{gnus-summary-next-thread}).
+
+@item T p
+@kindex T p (Summary)
+@itemx C-M-b
+@kindex C-M-p (Summary)
+@itemx M-up
+@kindex M-up (Summary)
+@findex gnus-summary-prev-thread
+Go to the previous thread (@code{gnus-summary-prev-thread}).
+
+@item T d
+@kindex T d (Summary)
+@findex gnus-summary-down-thread
+Descend the thread (@code{gnus-summary-down-thread}).
+
+@item T u
+@kindex T u (Summary)
+@findex gnus-summary-up-thread
+Ascend the thread (@code{gnus-summary-up-thread}).
+
+@item T o
+@kindex T o (Summary)
+@findex gnus-summary-top-thread
+Go to the top of the thread (@code{gnus-summary-top-thread}).
+@end table
+
+@vindex gnus-thread-operation-ignore-subject
+If you ignore subject while threading, you'll naturally end up with
+threads that have several different subjects in them.  If you then issue
+a command like @kbd{T k} (@code{gnus-summary-kill-thread}) you might not
+wish to kill the entire thread, but just those parts of the thread that
+have the same subject as the current article.  If you like this idea,
+you can fiddle with @code{gnus-thread-operation-ignore-subject}.  If it
+is non-@code{nil} (which it is by default), subjects will be ignored
+when doing thread commands.  If this variable is @code{nil}, articles in
+the same thread with different subjects will not be included in the
+operation in question.  If this variable is @code{fuzzy}, only articles
+that have subjects fuzzily equal will be included (@pxref{Fuzzy
+Matching}).
+
+
+@node Sorting the Summary Buffer
+@section Sorting the Summary Buffer
+
+@findex gnus-thread-sort-by-total-score
+@findex gnus-thread-sort-by-date
+@findex gnus-thread-sort-by-score
+@findex gnus-thread-sort-by-subject
+@findex gnus-thread-sort-by-author
+@findex gnus-thread-sort-by-recipient
+@findex gnus-thread-sort-by-number
+@findex gnus-thread-sort-by-random
+@vindex gnus-thread-sort-functions
+@findex gnus-thread-sort-by-most-recent-number
+@findex gnus-thread-sort-by-most-recent-date
+If you are using a threaded summary display, you can sort the threads by
+setting @code{gnus-thread-sort-functions}, which can be either a single
+function, a list of functions, or a list containing functions and
+@code{(not some-function)} elements.
+
+By default, sorting is done on article numbers.  Ready-made sorting
+predicate functions include @code{gnus-thread-sort-by-number},
+@code{gnus-thread-sort-by-author}, @code{gnus-thread-sort-by-recipient},
+@code{gnus-thread-sort-by-subject},
+@code{gnus-thread-sort-by-date},
+@code{gnus-thread-sort-by-score},
+@code{gnus-thread-sort-by-most-recent-number},
+@code{gnus-thread-sort-by-most-recent-date},
+@code{gnus-thread-sort-by-random} and
+@code{gnus-thread-sort-by-total-score}.
+
+Each function takes two threads and returns non-@code{nil} if the first
+thread should be sorted before the other.  Note that sorting really is
+normally done by looking only at the roots of each thread.  Exceptions
+to this rule are @code{gnus-thread-sort-by-most-recent-number} and
+@code{gnus-thread-sort-by-most-recent-date}.
+
+If you use more than one function, the primary sort key should be the
+last function in the list.  You should probably always include
+@code{gnus-thread-sort-by-number} in the list of sorting
+functions---preferably first.  This will ensure that threads that are
+equal with respect to the other sort criteria will be displayed in
+ascending article order.
+
+If you would like to sort by reverse score, then by subject, and finally
+by number, you could do something like:
+
+@lisp
+(setq gnus-thread-sort-functions
+      '(gnus-thread-sort-by-number
+        gnus-thread-sort-by-subject
+        (not gnus-thread-sort-by-total-score)))
+@end lisp
+
+The threads that have highest score will be displayed first in the
+summary buffer.  When threads have the same score, they will be sorted
+alphabetically.  The threads that have the same score and the same
+subject will be sorted by number, which is (normally) the sequence in
+which the articles arrived.
+
+If you want to sort by score and then reverse arrival order, you could
+say something like:
+
+@lisp
+(setq gnus-thread-sort-functions
+      '((not gnus-thread-sort-by-number)
+        gnus-thread-sort-by-score))
+@end lisp
+
+By default, threads including their subthreads are sorted according to
+the value of @code{gnus-thread-sort-functions}.  By customizing
+@code{gnus-subthread-sort-functions} you can define a custom sorting
+order for subthreads.  This allows for example to sort threads from
+high score to low score in the summary buffer, but to have subthreads
+still sorted chronologically from old to new without taking their
+score into account.
+
+@vindex gnus-thread-score-function
+The function in the @code{gnus-thread-score-function} variable (default
+@code{+}) is used for calculating the total score of a thread.  Useful
+functions might be @code{max}, @code{min}, or squared means, or whatever
+tickles your fancy.
+
+@findex gnus-article-sort-functions
+@findex gnus-article-sort-by-date
+@findex gnus-article-sort-by-most-recent-date
+@findex gnus-article-sort-by-score
+@findex gnus-article-sort-by-subject
+@findex gnus-article-sort-by-author
+@findex gnus-article-sort-by-random
+@findex gnus-article-sort-by-number
+@findex gnus-article-sort-by-most-recent-number
+If you are using an unthreaded display for some strange reason or
+other, you have to fiddle with the @code{gnus-article-sort-functions}
+variable.  It is very similar to the
+@code{gnus-thread-sort-functions}, except that it uses slightly
+different functions for article comparison.  Available sorting
+predicate functions are @code{gnus-article-sort-by-number},
+@code{gnus-article-sort-by-author},
+@code{gnus-article-sort-by-subject}, @code{gnus-article-sort-by-date},
+@code{gnus-article-sort-by-random}, and
+@code{gnus-article-sort-by-score}.
+
+If you want to sort an unthreaded summary display by subject, you could
+say something like:
+
+@lisp
+(setq gnus-article-sort-functions
+      '(gnus-article-sort-by-number
+        gnus-article-sort-by-subject))
+@end lisp
+
+You can define group specific sorting via @code{gnus-parameters},
+@xref{Group Parameters}.
+
+
+@node Asynchronous Fetching
+@section Asynchronous Article Fetching
+@cindex asynchronous article fetching
+@cindex article pre-fetch
+@cindex pre-fetch
+
+If you read your news from an @acronym{NNTP} server that's far away, the
+network latencies may make reading articles a chore.  You have to wait
+for a while after pressing @kbd{n} to go to the next article before the
+article appears.  Why can't Gnus just go ahead and fetch the article
+while you are reading the previous one?  Why not, indeed.
+
+First, some caveats.  There are some pitfalls to using asynchronous
+article fetching, especially the way Gnus does it.
+
+Let's say you are reading article 1, which is short, and article 2 is
+quite long, and you are not interested in reading that.  Gnus does not
+know this, so it goes ahead and fetches article 2.  You decide to read
+article 3, but since Gnus is in the process of fetching article 2, the
+connection is blocked.
+
+To avoid these situations, Gnus will open two (count 'em two)
+connections to the server.  Some people may think this isn't a very nice
+thing to do, but I don't see any real alternatives.  Setting up that
+extra connection takes some time, so Gnus startup will be slower.
+
+Gnus will fetch more articles than you will read.  This will mean that
+the link between your machine and the @acronym{NNTP} server will become more
+loaded than if you didn't use article pre-fetch.  The server itself will
+also become more loaded---both with the extra article requests, and the
+extra connection.
+
+Ok, so now you know that you shouldn't really use this thing@dots{} unless
+you really want to.
+
+@vindex gnus-asynchronous
+Here's how:  Set @code{gnus-asynchronous} to @code{t}.  The rest should
+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 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.
+
+@vindex gnus-async-prefetch-article-p
+@findex gnus-async-unread-p
+There are probably some articles that you don't want to pre-fetch---read
+articles, for instance.  The @code{gnus-async-prefetch-article-p}
+variable controls whether an article is to be pre-fetched.  This
+function should return non-@code{nil} when the article in question is
+to be pre-fetched.  The default is @code{gnus-async-unread-p}, which
+returns @code{nil} on read articles.  The function is called with an
+article data structure as the only parameter.
+
+If, for instance, you wish to pre-fetch only unread articles shorter
+than 100 lines, you could say something like:
+
+@lisp
+(defun my-async-short-unread-p (data)
+  "Return non-nil for short, unread articles."
+  (and (gnus-data-unread-p data)
+       (< (mail-header-lines (gnus-data-header data))
+          100)))
+
+(setq gnus-async-prefetch-article-p 'my-async-short-unread-p)
+@end lisp
+
+These functions will be called many, many times, so they should
+preferably be short and sweet to avoid slowing down Gnus too much.
+It's probably a good idea to byte-compile things like this.
+
+@vindex gnus-async-post-fetch-function
+@findex gnus-html-prefetch-images
+After an article has been prefetched, this
+@code{gnus-async-post-fetch-function} will be called.  The buffer will
+be narrowed to the region of the article that was fetched.  A useful
+value would be @code{gnus-html-prefetch-images}, which will prefetch
+and store images referenced in the article, so that you don't have to
+wait for them to be fetched when you read the article.  This is useful
+for @acronym{HTML} messages that have external images.
+
+@vindex gnus-prefetched-article-deletion-strategy
+Articles have to be removed from the asynch buffer sooner or later.  The
+@code{gnus-prefetched-article-deletion-strategy} says when to remove
+articles.  This is a list that may contain the following elements:
+
+@table @code
+@item read
+Remove articles when they are read.
+
+@item exit
+Remove articles when exiting the group.
+@end table
+
+The default value is @code{(read exit)}.
+
+@c @vindex gnus-use-header-prefetch
+@c If @code{gnus-use-header-prefetch} is non-@code{nil}, prefetch articles
+@c from the next group.
+
+
+@node Article Caching
+@section Article Caching
+@cindex article caching
+@cindex caching
+
+If you have an @emph{extremely} slow @acronym{NNTP} connection, you may
+consider turning article caching on.  Each article will then be stored
+locally under your home directory.  As you may surmise, this could
+potentially use @emph{huge} amounts of disk space, as well as eat up all
+your inodes so fast it will make your head swim.  In vodka.
+
+Used carefully, though, it could be just an easier way to save articles.
+
+@vindex gnus-use-long-file-name
+@vindex gnus-cache-directory
+@vindex gnus-use-cache
+To turn caching on, set @code{gnus-use-cache} to @code{t}.  By default,
+all articles ticked or marked as dormant will then be copied
+over to your local cache (@code{gnus-cache-directory}).  Whether this
+cache is flat or hierarchical is controlled by the
+@code{gnus-use-long-file-name} variable, as usual.
+
+When re-selecting a ticked or dormant article, it will be fetched from the
+cache instead of from the server.  As articles in your cache will never
+expire, this might serve as a method of saving articles while still
+keeping them where they belong.  Just mark all articles you want to save
+as dormant, and don't worry.
+
+When an article is marked as read, is it removed from the cache.
+
+@vindex gnus-cache-remove-articles
+@vindex gnus-cache-enter-articles
+The entering/removal of articles from the cache is controlled by the
+@code{gnus-cache-enter-articles} and @code{gnus-cache-remove-articles}
+variables.  Both are lists of symbols.  The first is @code{(ticked
+dormant)} by default, meaning that ticked and dormant articles will be
+put in the cache.  The latter is @code{(read)} by default, meaning that
+articles marked as read are removed from the cache.  Possibly
+symbols in these two lists are @code{ticked}, @code{dormant},
+@code{unread} and @code{read}.
+
+@findex gnus-jog-cache
+So where does the massive article-fetching and storing come into the
+picture?  The @code{gnus-jog-cache} command will go through all
+subscribed newsgroups, request all unread articles, score them, and
+store them in the cache.  You should only ever, ever ever ever, use this
+command if 1) your connection to the @acronym{NNTP} server is really, really,
+really slow and 2) you have a really, really, really huge disk.
+Seriously.  One way to cut down on the number of articles downloaded is
+to score unwanted articles down and have them marked as read.  They will
+not then be downloaded by this command.
+
+@vindex gnus-uncacheable-groups
+@vindex gnus-cacheable-groups
+It is likely that you do not want caching on all groups.  For instance,
+if your @code{nnml} mail is located under your home directory, it makes no
+sense to cache it somewhere else under your home directory.  Unless you
+feel that it's neat to use twice as much space.
+
+To limit the caching, you could set @code{gnus-cacheable-groups} to a
+regexp of groups to cache, @samp{^nntp} for instance, or set the
+@code{gnus-uncacheable-groups} regexp to @samp{^nnml}, for instance.
+Both variables are @code{nil} by default.  If a group matches both
+variables, the group is not cached.
+
+@findex gnus-cache-generate-nov-databases
+@findex gnus-cache-generate-active
+@vindex gnus-cache-active-file
+The cache stores information on what articles it contains in its active
+file (@code{gnus-cache-active-file}).  If this file (or any other parts
+of the cache) becomes all messed up for some reason or other, Gnus
+offers two functions that will try to set things right.  @kbd{M-x
+gnus-cache-generate-nov-databases} will (re)build all the @acronym{NOV}
+files, and @kbd{gnus-cache-generate-active} will (re)generate the active
+file.
+
+@findex gnus-cache-move-cache
+@code{gnus-cache-move-cache} will move your whole
+@code{gnus-cache-directory} to some other location.  You get asked to
+where, isn't that cool?
+
+@node Persistent Articles
+@section Persistent Articles
+@cindex persistent articles
+
+Closely related to article caching, we have @dfn{persistent articles}.
+In fact, it's just a different way of looking at caching, and much more
+useful in my opinion.
+
+Say you're reading a newsgroup, and you happen on to some valuable gem
+that you want to keep and treasure forever.  You'd normally just save it
+(using one of the many saving commands) in some file.  The problem with
+that is that it's just, well, yucky.  Ideally you'd prefer just having
+the article remain in the group where you found it forever; untouched by
+the expiry going on at the news server.
+
+This is what a @dfn{persistent article} is---an article that just won't
+be deleted.  It's implemented using the normal cache functions, but
+you use two explicit commands for managing persistent articles:
+
+@table @kbd
+
+@item *
+@kindex * (Summary)
+@findex gnus-cache-enter-article
+Make the current article persistent (@code{gnus-cache-enter-article}).
+
+@item M-*
+@kindex M-* (Summary)
+@findex gnus-cache-remove-article
+Remove the current article from the persistent articles
+(@code{gnus-cache-remove-article}).  This will normally delete the
+article.
+@end table
+
+Both these commands understand the process/prefix convention.
+
+To avoid having all ticked articles (and stuff) entered into the cache,
+you should set @code{gnus-use-cache} to @code{passive} if you're just
+interested in persistent articles:
+
+@lisp
+(setq gnus-use-cache 'passive)
+@end lisp
+
+@node Sticky Articles
+@section Sticky Articles
+@cindex sticky articles
+
+When you select an article the current article buffer will be reused
+according to the value of the variable
+@code{gnus-single-article-buffer}.  If its value is non-@code{nil} (the
+default) all articles reuse the same article buffer.  Else each group
+has its own article buffer.
+
+This implies that it's not possible to have more than one article buffer
+in a group at a time.  But sometimes you might want to display all the
+latest emails from your mother, your father, your aunt, your uncle and
+your 17 cousins to coordinate the next Christmas party.
+
+That's where sticky articles come in handy.  A sticky article buffer
+basically is a normal article buffer, but it won't be reused when you
+select another article.  You can make an article sticky with:
+
+@table @kbd
+@item A S
+@kindex A S (Summary)
+@findex gnus-sticky-article
+Make the current article sticky.  If a prefix arg is given, ask for a
+name for this sticky article buffer.
+@end table
+
+To close a sticky article buffer you can use these commands:
+
+@table @kbd
+@item q
+@kindex q (Article)
+@findex bury-buffer
+Puts this sticky article buffer at the end of the list of all buffers.
+
+@item k
+@kindex k (Article)
+@findex gnus-kill-sticky-article-buffer
+Kills this sticky article buffer.
+@end table
+
+To kill all sticky article buffers you can use:
+
+@defun gnus-kill-sticky-article-buffers ARG
+Kill all sticky article buffers.
+If a prefix ARG is given, ask for confirmation.
+@end defun
+
+@node Article Backlog
+@section Article Backlog
+@cindex backlog
+@cindex article backlog
+
+If you have a slow connection, but the idea of using caching seems
+unappealing to you (and it is, really), you can help the situation some
+by switching on the @dfn{backlog}.  This is where Gnus will buffer
+already read articles so that it doesn't have to re-fetch articles
+you've already read.  This only helps if you are in the habit of
+re-selecting articles you've recently read, of course.  If you never do
+that, turning the backlog on will slow Gnus down a little bit, and
+increase memory usage some.
+
+@vindex gnus-keep-backlog
+If you set @code{gnus-keep-backlog} to a number @var{n}, Gnus will store
+at most @var{n} old articles in a buffer for later re-fetching.  If this
+variable is non-@code{nil} and is not a number, Gnus will store
+@emph{all} read articles, which means that your Emacs will grow without
+bound before exploding and taking your machine down with you.  I put
+that in there just to keep y'all on your toes.
+
+The default value is 20.
+
+
+@node Saving Articles
+@section Saving Articles
+@cindex saving articles
+
+Gnus can save articles in a number of ways.  Below is the documentation
+for saving articles in a fairly straight-forward fashion (i.e., little
+processing of the article is done before it is saved).  For a different
+approach (uudecoding, unsharing) you should use @code{gnus-uu}
+(@pxref{Decoding Articles}).
+
+For the commands listed here, the target is a file.  If you want to
+save to a group, see the @kbd{B c} (@code{gnus-summary-copy-article})
+command (@pxref{Mail Group Commands}).
+
+@vindex gnus-save-all-headers
+If @code{gnus-save-all-headers} is non-@code{nil}, Gnus will not delete
+unwanted headers before saving the article.
+
+@vindex gnus-saved-headers
+If the preceding variable is @code{nil}, all headers that match the
+@code{gnus-saved-headers} regexp will be kept, while the rest will be
+deleted before saving.
+
+@table @kbd
+
+@item O o
+@itemx o
+@kindex O o (Summary)
+@kindex o (Summary)
+@findex gnus-summary-save-article
+@c @icon{gnus-summary-save-article}
+Save the current article using the default article saver
+(@code{gnus-summary-save-article}).
+
+@item O m
+@kindex O m (Summary)
+@findex gnus-summary-save-article-mail
+Save the current article in a Unix mail box (mbox) file
+(@code{gnus-summary-save-article-mail}).
+
+@item O r
+@kindex O r (Summary)
+@findex gnus-summary-save-article-rmail
+Save the current article in Rmail format
+(@code{gnus-summary-save-article-rmail}).  This is mbox since Emacs 23,
+Babyl in older versions.
+
+@item O f
+@kindex O f (Summary)
+@findex gnus-summary-save-article-file
+@c @icon{gnus-summary-save-article-file}
+Save the current article in plain file format
+(@code{gnus-summary-save-article-file}).
+
+@item O F
+@kindex O F (Summary)
+@findex gnus-summary-write-article-file
+Write the current article in plain file format, overwriting any previous
+file contents (@code{gnus-summary-write-article-file}).
+
+@item O b
+@kindex O b (Summary)
+@findex gnus-summary-save-article-body-file
+Save the current article body in plain file format
+(@code{gnus-summary-save-article-body-file}).
+
+@item O h
+@kindex O h (Summary)
+@findex gnus-summary-save-article-folder
+Save the current article in mh folder format
+(@code{gnus-summary-save-article-folder}).
+
+@item O v
+@kindex O v (Summary)
+@findex gnus-summary-save-article-vm
+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
+@vindex gnus-summary-pipe-output-default-command
+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}).
+If given a symbolic prefix (@pxref{Symbolic Prefixes}), include the
+complete headers in the piped output.  The symbolic prefix @code{r} is
+special; it lets this command pipe a raw article including all headers.
+The @code{gnus-summary-pipe-output-default-command} variable can be set
+to a string containing the default command and options (default
+@code{nil}).
+
+@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 @uref{http://muttprint.sourceforge.net/,
+Muttprint}.  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
+All these commands use the process/prefix convention
+(@pxref{Process/Prefix}).  If you save bunches of articles using these
+functions, you might get tired of being prompted for files to save each
+and every article in.  The prompting action is controlled by
+the @code{gnus-prompt-before-saving} variable, which is @code{always} by
+default, giving you that excessive prompting action you know and
+loathe.  If you set this variable to @code{t} instead, you'll be prompted
+just once for each series of articles you save.  If you like to really
+have Gnus do all your thinking for you, you can even set this variable
+to @code{nil}, which means that you will never be prompted for files to
+save articles in.  Gnus will simply save all the articles in the default
+files.
+
+
+@vindex gnus-default-article-saver
+You can customize the @code{gnus-default-article-saver} variable to make
+Gnus do what you want it to.  You can use any of the eight ready-made
+functions below, or you can create your own.
+
+@table @code
+
+@item gnus-summary-save-in-rmail
+@findex gnus-summary-save-in-rmail
+@vindex gnus-rmail-save-name
+@findex gnus-plain-save-name
+This is the default format, that used by the Rmail package.  Since Emacs
+23, Rmail uses standard mbox format.  Before this, it used the
+@dfn{Babyl} format.  Accordingly, this command writes mbox format since
+Emacs 23, unless appending to an existing Babyl file.  In older versions
+of Emacs, it always uses Babyl format.  Uses the function in the
+@code{gnus-rmail-save-name} variable to get a file name to save the
+article in.  The default is @code{gnus-plain-save-name}.
+
+@item gnus-summary-save-in-mail
+@findex gnus-summary-save-in-mail
+@vindex gnus-mail-save-name
+Save in a Unix mail (mbox) file.  Uses the function in the
+@code{gnus-mail-save-name} variable to get a file name to save the
+article in.  The default is @code{gnus-plain-save-name}.
+
+@item gnus-summary-save-in-file
+@findex gnus-summary-save-in-file
+@vindex gnus-file-save-name
+@findex gnus-numeric-save-name
+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
+@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-body-to-file
+@findex gnus-summary-write-body-to-file
+Write the article body 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-in-folder
+@findex gnus-summary-save-in-folder
+@findex gnus-folder-save-name
+@findex gnus-Folder-save-name
+@vindex gnus-folder-save-name
+@cindex rcvstore
+@cindex MH folders
+Save the article to an MH folder using @code{rcvstore} from the MH
+library.  Uses the function in the @code{gnus-folder-save-name} variable
+to get a file name to save the article in.  The default is
+@code{gnus-folder-save-name}, but you can also use
+@code{gnus-Folder-save-name}, which creates capitalized names.
+
+@item gnus-summary-save-in-vm
+@findex gnus-summary-save-in-vm
+Save the article in a VM folder.  You have to have the VM mail
+reader to use this setting.
+
+@item gnus-summary-save-in-pipe
+@findex gnus-summary-save-in-pipe
+Pipe the article to a shell command.  This function takes optional two
+arguments COMMAND and RAW@.  Valid values for COMMAND include:
+
+@itemize @bullet
+@item a string@*
+The executable command name and possibly arguments.
+@item @code{nil}@*
+You will be prompted for the command in the minibuffer.
+@item the symbol @code{default}@*
+It will be replaced with the command which the variable
+@code{gnus-summary-pipe-output-default-command} holds or the command
+last used for saving.
+@end itemize
+
+Non-@code{nil} value for RAW overrides @code{:decode} and
+@code{:headers} properties (see below) and the raw article including all
+headers will be piped.
+@end table
+
+The symbol of each function may have the following properties:
+
+@table @code
+@item :decode
+The value non-@code{nil} means save decoded articles.  This is
+meaningful only with @code{gnus-summary-save-in-file},
+@code{gnus-summary-save-body-in-file},
+@code{gnus-summary-write-to-file},
+@code{gnus-summary-write-body-to-file}, and
+@code{gnus-summary-save-in-pipe}.
+
+@item :function
+The value specifies an alternative function which appends, not
+overwrites, articles to a file.  This implies that when saving many
+articles at a time, @code{gnus-prompt-before-saving} is bound to
+@code{t} and all articles are saved in a single file.  This is
+meaningful only with @code{gnus-summary-write-to-file} and
+@code{gnus-summary-write-body-to-file}.
+
+@item :headers
+The value specifies the symbol of a variable of which the value
+specifies headers to be saved.  If it is omitted,
+@code{gnus-save-all-headers} and @code{gnus-saved-headers} control what
+headers should be saved.
+@end table
+
+@vindex gnus-article-save-directory
+All of these functions, except for the last one, will save the article
+in the @code{gnus-article-save-directory}, which is initialized from the
+@env{SAVEDIR} environment variable.  This is @file{~/News/} by
+default.
+
+As you can see above, the functions use different functions to find a
+suitable name of a file to save the article in.  Below is a list of
+available functions that generate names:
+
+@table @code
+
+@item gnus-Numeric-save-name
+@findex gnus-Numeric-save-name
+File names like @file{~/News/Alt.andrea-dworkin/45}.
+
+@item gnus-numeric-save-name
+@findex gnus-numeric-save-name
+File names like @file{~/News/alt.andrea-dworkin/45}.
+
+@item gnus-Plain-save-name
+@findex gnus-Plain-save-name
+File names like @file{~/News/Alt.andrea-dworkin}.
+
+@item gnus-plain-save-name
+@findex gnus-plain-save-name
+File names like @file{~/News/alt.andrea-dworkin}.
+
+@item gnus-sender-save-name
+@findex gnus-sender-save-name
+File names like @file{~/News/larsi}.
+@end table
+
+@vindex gnus-split-methods
+You can have Gnus suggest where to save articles by plonking a regexp into
+the @code{gnus-split-methods} alist.  For instance, if you would like to
+save articles related to Gnus in the file @file{gnus-stuff}, and articles
+related to VM in @file{vm-stuff}, you could set this variable to something
+like:
+
+@lisp
+(("^Subject:.*gnus\\|^Newsgroups:.*gnus" "gnus-stuff")
+ ("^Subject:.*vm\\|^Xref:.*vm" "vm-stuff")
+ (my-choosing-function "../other-dir/my-stuff")
+ ((equal gnus-newsgroup-name "mail.misc") "mail-stuff"))
+@end lisp
+
+We see that this is a list where each element is a list that has two
+elements---the @dfn{match} and the @dfn{file}.  The match can either be
+a string (in which case it is used as a regexp to match on the article
+head); it can be a symbol (which will be called as a function with the
+group name as a parameter); or it can be a list (which will be
+@code{eval}ed).  If any of these actions have a non-@code{nil} result,
+the @dfn{file} will be used as a default prompt.  In addition, the
+result of the operation itself will be used if the function or form
+called returns a string or a list of strings.
+
+You basically end up with a list of file names that might be used when
+saving the current article.  (All ``matches'' will be used.)  You will
+then be prompted for what you really want to use as a name, with file
+name completion over the results from applying this variable.
+
+This variable is @code{((gnus-article-archive-name))} by default, which
+means that Gnus will look at the articles it saves for an
+@code{Archive-name} line and use that as a suggestion for the file
+name.
+
+Here's an example function to clean up file names somewhat.  If you have
+lots of mail groups called things like
+@samp{nnml:mail.whatever}, you may want to chop off the beginning of
+these group names before creating the file name to save to.  The
+following will do just that:
+
+@lisp
+(defun my-save-name (group)
+  (when (string-match "^nnml:mail." group)
+    (substring group (match-end 0))))
+
+(setq gnus-split-methods
+      '((gnus-article-archive-name)
+        (my-save-name)))
+@end lisp
+
+
+@vindex gnus-use-long-file-name
+Finally, you have the @code{gnus-use-long-file-name} variable.  If it is
+@code{nil}, all the preceding functions will replace all periods
+(@samp{.}) in the group names with slashes (@samp{/})---which means that
+the functions will generate hierarchies of directories instead of having
+all the files in the top level directory
+(@file{~/News/alt/andrea-dworkin} instead of
+@file{~/News/alt.andrea-dworkin}.)  This variable is @code{t} by default
+on most systems.  However, for historical reasons, this is @code{nil} on
+Xenix and usg-unix-v machines by default.
+
+This function also affects kill and score file names.  If this variable
+is a list, and the list contains the element @code{not-score}, long file
+names will not be used for score files, if it contains the element
+@code{not-save}, long file names will not be used for saving, and if it
+contains the element @code{not-kill}, long file names will not be used
+for kill files.
+
+If you'd like to save articles in a hierarchy that looks something like
+a spool, you could
+
+@lisp
+(setq gnus-use-long-file-name '(not-save)) ; @r{to get a hierarchy}
+(setq gnus-default-article-saver
+      'gnus-summary-save-in-file)          ; @r{no encoding}
+@end lisp
+
+Then just save with @kbd{o}.  You'd then read this hierarchy with
+ephemeral @code{nneething} groups---@kbd{G D} in the group buffer, and
+the top level directory as the argument (@file{~/News/}).  Then just walk
+around to the groups/directories with @code{nneething}.
+
+
+@node Decoding Articles
+@section Decoding Articles
+@cindex decoding articles
+
+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?
+@end menu
+
+@cindex series
+@cindex article series
+All these functions use the process/prefix convention
+(@pxref{Process/Prefix}) for finding out what articles to work on, with
+the extension that a ``single article'' means ``a single series''.  Gnus
+can find out by itself what articles belong to a series, decode all the
+articles and unpack/view/save the resulting file(s).
+
+Gnus guesses what articles are in the series according to the following
+simplish rule: The subjects must be (nearly) identical, except for the
+last two numbers of the line.  (Spaces are largely ignored, however.)
+
+For example: If you choose a subject called @samp{cat.gif (2/3)}, Gnus
+will find all the articles that match the regexp @samp{^cat.gif
+([0-9]+/[0-9]+).*$}.
+
+Subjects that are non-standard, like @samp{cat.gif (2/3) Part 6 of a
+series}, will not be properly recognized by any of the automatic viewing
+commands, and you have to mark the articles manually with @kbd{#}.
+
+
+@node Uuencoded Articles
+@subsection Uuencoded Articles
+@cindex uudecode
+@cindex uuencoded articles
+
+@table @kbd
+
+@item X u
+@kindex X u (Summary)
+@findex gnus-uu-decode-uu
+@c @icon{gnus-uu-decode-uu}
+Uudecodes the current series (@code{gnus-uu-decode-uu}).
+
+@item X U
+@kindex X U (Summary)
+@findex gnus-uu-decode-uu-and-save
+Uudecodes and saves the current series
+(@code{gnus-uu-decode-uu-and-save}).
+
+@item X v u
+@kindex X v u (Summary)
+@findex gnus-uu-decode-uu-view
+Uudecodes and views the current series (@code{gnus-uu-decode-uu-view}).
+
+@item X v U
+@kindex X v U (Summary)
+@findex gnus-uu-decode-uu-and-save-view
+Uudecodes, views and saves the current series
+(@code{gnus-uu-decode-uu-and-save-view}).
+
+@end table
+
+Remember that these all react to the presence of articles marked with
+the process mark.  If, for instance, you'd like to decode and save an
+entire newsgroup, you'd typically do @kbd{M P a}
+(@code{gnus-uu-mark-all}) and then @kbd{X U}
+(@code{gnus-uu-decode-uu-and-save}).
+
+All this is very much different from how @code{gnus-uu} worked with
+@sc{gnus 4.1}, where you had explicit keystrokes for everything under
+the sun.  This version of @code{gnus-uu} generally assumes that you mark
+articles in some way (@pxref{Setting Process Marks}) and then press
+@kbd{X u}.
+
+@vindex gnus-uu-notify-files
+Note: When trying to decode articles that have names matching
+@code{gnus-uu-notify-files}, which is hard-coded to
+@samp{[Cc][Ii][Nn][Dd][Yy][0-9]+.\\(gif\\|jpg\\)}, @code{gnus-uu} will
+automatically post an article on @samp{comp.unix.wizards} saying that
+you have just viewed the file in question.  This feature can't be turned
+off.
+
+
+@node Shell Archives
+@subsection Shell Archives
+@cindex unshar
+@cindex shell archives
+@cindex shared articles
+
+Shell archives (``shar files'') used to be a popular way to distribute
+sources, but it isn't used all that much today.  In any case, we have
+some commands to deal with these:
+
+@table @kbd
+
+@item X s
+@kindex X s (Summary)
+@findex gnus-uu-decode-unshar
+Unshars the current series (@code{gnus-uu-decode-unshar}).
+
+@item X S
+@kindex X S (Summary)
+@findex gnus-uu-decode-unshar-and-save
+Unshars and saves the current series (@code{gnus-uu-decode-unshar-and-save}).
+
+@item X v s
+@kindex X v s (Summary)
+@findex gnus-uu-decode-unshar-view
+Unshars and views the current series (@code{gnus-uu-decode-unshar-view}).
+
+@item X v S
+@kindex X v S (Summary)
+@findex gnus-uu-decode-unshar-and-save-view
+Unshars, views and saves the current series
+(@code{gnus-uu-decode-unshar-and-save-view}).
+@end table
+
+
+@node PostScript Files
+@subsection PostScript Files
+@cindex PostScript
+
+@table @kbd
+
+@item X p
+@kindex X p (Summary)
+@findex gnus-uu-decode-postscript
+Unpack the current PostScript series (@code{gnus-uu-decode-postscript}).
+
+@item X P
+@kindex X P (Summary)
+@findex gnus-uu-decode-postscript-and-save
+Unpack and save the current PostScript series
+(@code{gnus-uu-decode-postscript-and-save}).
+
+@item X v p
+@kindex X v p (Summary)
+@findex gnus-uu-decode-postscript-view
+View the current PostScript series
+(@code{gnus-uu-decode-postscript-view}).
+
+@item X v P
+@kindex X v P (Summary)
+@findex gnus-uu-decode-postscript-and-save-view
+View and save the current PostScript series
+(@code{gnus-uu-decode-postscript-and-save-view}).
+@end table
+
+
+@node Other Files
+@subsection Other Files
+
+@table @kbd
+@item X o
+@kindex X o (Summary)
+@findex gnus-uu-decode-save
+Save the current series
+(@code{gnus-uu-decode-save}).
+
+@item X b
+@kindex X b (Summary)
+@findex gnus-uu-decode-binhex
+Unbinhex the current series (@code{gnus-uu-decode-binhex}).  This
+doesn't really work yet.
+
+@item X Y
+@kindex X Y (Summary)
+@findex gnus-uu-decode-yenc
+yEnc-decode the current series and save it (@code{gnus-uu-decode-yenc}).
+@end table
+
+
+@node Decoding Variables
+@subsection Decoding Variables
+
+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.
+@end menu
+
+
+@node Rule Variables
+@subsubsection Rule Variables
+@cindex rule variables
+
+Gnus uses @dfn{rule variables} to decide how to view a file.  All these
+variables are of the form
+
+@lisp
+      (list '(regexp1 command2)
+            '(regexp2 command2)
+            ...)
+@end lisp
+
+@table @code
+
+@item gnus-uu-user-view-rules
+@vindex gnus-uu-user-view-rules
+@cindex sox
+This variable is consulted first when viewing files.  If you wish to use,
+for instance, @code{sox} to convert an @file{.au} sound file, you could
+say something like:
+@lisp
+(setq gnus-uu-user-view-rules
+      (list '("\\\\.au$" "sox %s -t .aiff > /dev/audio")))
+@end lisp
+
+@item gnus-uu-user-view-rules-end
+@vindex gnus-uu-user-view-rules-end
+This variable is consulted if Gnus couldn't make any matches from the
+user and default view rules.
+
+@item gnus-uu-user-archive-rules
+@vindex gnus-uu-user-archive-rules
+This variable can be used to say what commands should be used to unpack
+archives.
+@end table
+
+
+@node Other Decode Variables
+@subsubsection Other Decode Variables
+
+@table @code
+@vindex gnus-uu-grabbed-file-functions
+
+@item gnus-uu-grabbed-file-functions
+All functions in this list will be called right after each file has been
+successfully decoded---so that you can move or view files right away,
+and don't have to wait for all files to be decoded before you can do
+anything.  Ready-made functions you can put in this list are:
+
+@table @code
+
+@item gnus-uu-grab-view
+@findex gnus-uu-grab-view
+View the file.
+
+@item gnus-uu-grab-move
+@findex gnus-uu-grab-move
+Move the file (if you're using a saving function.)
+@end table
+
+@item gnus-uu-be-dangerous
+@vindex gnus-uu-be-dangerous
+Specifies what to do if unusual situations arise during decoding.  If
+@code{nil}, be as conservative as possible.  If @code{t}, ignore things
+that didn't work, and overwrite existing files.  Otherwise, ask each
+time.
+
+@item gnus-uu-ignore-files-by-name
+@vindex gnus-uu-ignore-files-by-name
+Files with name matching this regular expression won't be viewed.
+
+@item gnus-uu-ignore-files-by-type
+@vindex gnus-uu-ignore-files-by-type
+Files with a @acronym{MIME} type matching this variable won't be viewed.
+Note that Gnus tries to guess what type the file is based on the name.
+@code{gnus-uu} is not a @acronym{MIME} package (yet), so this is slightly
+kludgy.
+
+@item gnus-uu-tmp-dir
+@vindex gnus-uu-tmp-dir
+Where @code{gnus-uu} does its work.
+
+@item gnus-uu-do-not-unpack-archives
+@vindex gnus-uu-do-not-unpack-archives
+Non-@code{nil} means that @code{gnus-uu} won't peek inside archives
+looking for files to display.
+
+@item gnus-uu-view-and-save
+@vindex gnus-uu-view-and-save
+Non-@code{nil} means that the user will always be asked to save a file
+after viewing it.
+
+@item gnus-uu-ignore-default-view-rules
+@vindex gnus-uu-ignore-default-view-rules
+Non-@code{nil} means that @code{gnus-uu} will ignore the default viewing
+rules.
+
+@item gnus-uu-ignore-default-archive-rules
+@vindex gnus-uu-ignore-default-archive-rules
+Non-@code{nil} means that @code{gnus-uu} will ignore the default archive
+unpacking commands.
+
+@item gnus-uu-kill-carriage-return
+@vindex gnus-uu-kill-carriage-return
+Non-@code{nil} means that @code{gnus-uu} will strip all carriage returns
+from articles.
+
+@item gnus-uu-unmark-articles-not-decoded
+@vindex gnus-uu-unmark-articles-not-decoded
+Non-@code{nil} means that @code{gnus-uu} will mark unsuccessfully
+decoded articles as unread.
+
+@item gnus-uu-correct-stripped-uucode
+@vindex gnus-uu-correct-stripped-uucode
+Non-@code{nil} means that @code{gnus-uu} will @emph{try} to fix
+uuencoded files that have had trailing spaces deleted.
+
+@item gnus-uu-pre-uudecode-hook
+@vindex gnus-uu-pre-uudecode-hook
+Hook run before sending a message to @code{uudecode}.
+
+@item gnus-uu-view-with-metamail
+@vindex gnus-uu-view-with-metamail
+@cindex metamail
+Non-@code{nil} means that @code{gnus-uu} will ignore the viewing
+commands defined by the rule variables and just fudge a @acronym{MIME}
+content type based on the file name.  The result will be fed to
+@code{metamail} for viewing.
+
+@item gnus-uu-save-in-digest
+@vindex gnus-uu-save-in-digest
+Non-@code{nil} means that @code{gnus-uu}, when asked to save without
+decoding, will save in digests.  If this variable is @code{nil},
+@code{gnus-uu} will just save everything in a file without any
+embellishments.  The digesting almost conforms to RFC 1153---no easy way
+to specify any meaningful volume and issue numbers were found, so I
+simply dropped them.
+
+@end table
+
+
+@node Uuencoding and Posting
+@subsubsection Uuencoding and Posting
+
+@table @code
+
+@item gnus-uu-post-include-before-composing
+@vindex gnus-uu-post-include-before-composing
+Non-@code{nil} means that @code{gnus-uu} will ask for a file to encode
+before you compose the article.  If this variable is @code{t}, you can
+either include an encoded file with @kbd{C-c C-i} or have one included
+for you when you post the article.
+
+@item gnus-uu-post-length
+@vindex gnus-uu-post-length
+Maximum length of an article.  The encoded file will be split into how
+many articles it takes to post the entire file.
+
+@item gnus-uu-post-threaded
+@vindex gnus-uu-post-threaded
+Non-@code{nil} means that @code{gnus-uu} will post the encoded file in a
+thread.  This may not be smart, as no other decoder I have seen is able
+to follow threads when collecting uuencoded articles.  (Well, I have
+seen one package that does that---@code{gnus-uu}, but somehow, I don't
+think that counts@dots{}) Default is @code{nil}.
+
+@item gnus-uu-post-separate-description
+@vindex gnus-uu-post-separate-description
+Non-@code{nil} means that the description will be posted in a separate
+article.  The first article will typically be numbered (0/x).  If this
+variable is @code{nil}, the description the user enters will be included
+at the beginning of the first article, which will be numbered (1/x).
+Default is @code{t}.
+
+@end table
+
+
+@node Viewing Files
+@subsection Viewing Files
+@cindex viewing files
+@cindex pseudo-articles
+
+After decoding, if the file is some sort of archive, Gnus will attempt
+to unpack the archive and see if any of the files in the archive can be
+viewed.  For instance, if you have a gzipped tar file @file{pics.tar.gz}
+containing the files @file{pic1.jpg} and @file{pic2.gif}, Gnus will
+uncompress and de-tar the main file, and then view the two pictures.
+This unpacking process is recursive, so if the archive contains archives
+of archives, it'll all be unpacked.
+
+Finally, Gnus will normally insert a @dfn{pseudo-article} for each
+extracted file into the summary buffer.  If you go to these
+``articles'', you will be prompted for a command to run (usually Gnus
+will make a suggestion), and then the command will be run.
+
+@vindex gnus-view-pseudo-asynchronously
+If @code{gnus-view-pseudo-asynchronously} is @code{nil}, Emacs will wait
+until the viewing is done before proceeding.
+
+@vindex gnus-view-pseudos
+If @code{gnus-view-pseudos} is @code{automatic}, Gnus will not insert
+the pseudo-articles into the summary buffer, but view them
+immediately.  If this variable is @code{not-confirm}, the user won't even
+be asked for a confirmation before viewing is done.
+
+@vindex gnus-view-pseudos-separately
+If @code{gnus-view-pseudos-separately} is non-@code{nil}, one
+pseudo-article will be created for each file to be viewed.  If
+@code{nil}, all files that use the same viewing command will be given as
+a list of parameters to that command.
+
+@vindex gnus-insert-pseudo-articles
+If @code{gnus-insert-pseudo-articles} is non-@code{nil}, insert
+pseudo-articles when decoding.  It is @code{t} by default.
+
+So; there you are, reading your @emph{pseudo-articles} in your
+@emph{virtual newsgroup} from the @emph{virtual server}; and you think:
+Why isn't anything real anymore?  How did we get here?
+
+
+@node Article Treatment
+@section Article Treatment
+
+Reading through this huge manual, you may have quite forgotten that the
+object of newsreaders is to actually, like, read what people have
+written.  Reading articles.  Unfortunately, people are quite bad at
+writing, so there are tons of functions and variables to make reading
+these articles easier.
+
+@menu
+* 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 Header::              Doing various header transformations.
+* Article Buttons::             Click on URLs, Message-IDs, addresses and the like.
+* Article Button Levels::       Controlling appearance of buttons.
+* Article Date::                Grumble, UT!
+* Article Display::             Display various stuff:
+                                X-Face, Picons, Gravatars, Smileys.
+* Article Signature::           What is a signature?
+* Article Miscellanea::         Various other stuff.
+@end menu
+
+
+@node Article Highlighting
+@subsection Article Highlighting
+@cindex highlighting
+
+Not only do you want your article buffer to look like fruit salad, but
+you want it to look like technicolor fruit salad.
+
+@table @kbd
+
+@item W H a
+@kindex W H a (Summary)
+@findex gnus-article-highlight
+@findex gnus-article-maybe-highlight
+Do much highlighting of the current article
+(@code{gnus-article-highlight}).  This function highlights header, cited
+text, the signature, and adds buttons to the body and the head.
+
+@item W H h
+@kindex W H h (Summary)
+@findex gnus-article-highlight-headers
+@vindex gnus-header-face-alist
+Highlight the headers (@code{gnus-article-highlight-headers}).  The
+highlighting will be done according to the @code{gnus-header-face-alist}
+variable, which is a list where each element has the form
+@code{(@var{regexp} @var{name} @var{content})}.
+@var{regexp} is a regular expression for matching the
+header, @var{name} is the face used for highlighting the header name
+(@pxref{Faces and Fonts}) and @var{content} is the face for highlighting
+the header value.  The first match made will be used.  Note that
+@var{regexp} shouldn't have @samp{^} prepended---Gnus will add one.
+
+@item W H c
+@kindex W H c (Summary)
+@findex gnus-article-highlight-citation
+Highlight cited text (@code{gnus-article-highlight-citation}).
+
+Some variables to customize the citation highlights:
+
+@table @code
+@vindex gnus-cite-parse-max-size
+
+@item gnus-cite-parse-max-size
+If the article size in bytes is bigger than this variable (which is
+25000 by default), no citation highlighting will be performed.
+
+@item gnus-cite-max-prefix
+@vindex gnus-cite-max-prefix
+Maximum possible length for a citation prefix (default 20).
+
+@item gnus-cite-face-list
+@vindex gnus-cite-face-list
+List of faces used for highlighting citations (@pxref{Faces and Fonts}).
+When there are citations from multiple articles in the same message,
+Gnus will try to give each citation from each article its own face.
+This should make it easier to see who wrote what.
+
+@item gnus-supercite-regexp
+@vindex gnus-supercite-regexp
+Regexp matching normal Supercite attribution lines.
+
+@item gnus-supercite-secondary-regexp
+@vindex gnus-supercite-secondary-regexp
+Regexp matching mangled Supercite attribution lines.
+
+@item gnus-cite-minimum-match-count
+@vindex gnus-cite-minimum-match-count
+Minimum number of identical prefixes we have to see before we believe
+that it's a citation.
+
+@item gnus-cite-attribution-prefix
+@vindex gnus-cite-attribution-prefix
+Regexp matching the beginning of an attribution line.
+
+@item gnus-cite-attribution-suffix
+@vindex gnus-cite-attribution-suffix
+Regexp matching the end of an attribution line.
+
+@item gnus-cite-attribution-face
+@vindex gnus-cite-attribution-face
+Face used for attribution lines.  It is merged with the face for the
+cited text belonging to the attribution.
+
+@item gnus-cite-ignore-quoted-from
+@vindex gnus-cite-ignore-quoted-from
+If non-@code{nil}, no citation highlighting will be performed on lines
+beginning with @samp{>From }.  Those lines may have been quoted by MTAs
+in order not to mix up with the envelope From line.  The default value
+is @code{t}.
+
+@end table
+
+
+@item W H s
+@kindex W H s (Summary)
+@vindex gnus-signature-separator
+@vindex gnus-signature-face
+@findex gnus-article-highlight-signature
+Highlight the signature (@code{gnus-article-highlight-signature}).
+Everything after @code{gnus-signature-separator} (@pxref{Article
+Signature}) in an article will be considered a signature and will be
+highlighted with @code{gnus-signature-face}, which is @code{italic} by
+default.
+
+@end table
+
+@xref{Customizing Articles}, for how to highlight articles automatically.
+
+
+@node Article Fontisizing
+@subsection Article Fontisizing
+@cindex emphasis
+@cindex article emphasis
+
+@findex gnus-article-emphasize
+@kindex W e (Summary)
+People commonly add emphasis to words in news articles by writing things
+like @samp{_this_} or @samp{*this*} or @samp{/this/}.  Gnus can make
+this look nicer by running the article through the @kbd{W e}
+(@code{gnus-article-emphasize}) command.
+
+@vindex gnus-emphasis-alist
+How the emphasis is computed is controlled by the
+@code{gnus-emphasis-alist} variable.  This is an alist where the first
+element is a regular expression to be matched.  The second is a number
+that says what regular expression grouping is used to find the entire
+emphasized word.  The third is a number that says what regexp grouping
+should be displayed and highlighted.  (The text between these two
+groupings will be hidden.)  The fourth is the face used for
+highlighting.
+
+@lisp
+(setq gnus-emphasis-alist
+      '(("_\\(\\w+\\)_" 0 1 gnus-emphasis-underline)
+        ("\\*\\(\\w+\\)\\*" 0 1 gnus-emphasis-bold)))
+@end lisp
+
+@cindex slash
+@cindex asterisk
+@cindex underline
+@cindex /
+@cindex *
+
+@vindex gnus-emphasis-underline
+@vindex gnus-emphasis-bold
+@vindex gnus-emphasis-italic
+@vindex gnus-emphasis-underline-bold
+@vindex gnus-emphasis-underline-italic
+@vindex gnus-emphasis-bold-italic
+@vindex gnus-emphasis-underline-bold-italic
+By default, there are seven rules, and they use the following faces:
+@code{gnus-emphasis-bold}, @code{gnus-emphasis-italic},
+@code{gnus-emphasis-underline}, @code{gnus-emphasis-bold-italic},
+@code{gnus-emphasis-underline-italic},
+@code{gnus-emphasis-underline-bold}, and
+@code{gnus-emphasis-underline-bold-italic}.
+
+If you want to change these faces, you can either use @kbd{M-x
+customize}, or you can use @code{copy-face}.  For instance, if you want
+to make @code{gnus-emphasis-italic} use a red face instead, you could
+say something like:
+
+@lisp
+(copy-face 'red 'gnus-emphasis-italic)
+@end lisp
+
+@vindex gnus-group-highlight-words-alist
+
+If you want to highlight arbitrary words, you can use the
+@code{gnus-group-highlight-words-alist} variable, which uses the same
+syntax as @code{gnus-emphasis-alist}.  The @code{highlight-words} group
+parameter (@pxref{Group Parameters}) can also be used.
+
+@xref{Customizing Articles}, for how to fontize articles automatically.
+
+
+@node Article Hiding
+@subsection Article Hiding
+@cindex article hiding
+
+Or rather, hiding certain things in each article.  There usually is much
+too much cruft in most articles.
+
+@table @kbd
+
+@item W W a
+@kindex W W a (Summary)
+@findex gnus-article-hide
+Do quite a lot of hiding on the article buffer
+(@kbd{gnus-article-hide}).  In particular, this function will hide
+headers, @acronym{PGP}, cited text and the signature.
+
+@item W W h
+@kindex W W h (Summary)
+@findex gnus-article-hide-headers
+Hide headers (@code{gnus-article-hide-headers}).  @xref{Hiding
+Headers}.
+
+@item W W b
+@kindex W W b (Summary)
+@findex gnus-article-hide-boring-headers
+Hide headers that aren't particularly interesting
+(@code{gnus-article-hide-boring-headers}).  @xref{Hiding Headers}.
+
+@item W W s
+@kindex W W s (Summary)
+@findex gnus-article-hide-signature
+Hide signature (@code{gnus-article-hide-signature}).  @xref{Article
+Signature}.
+
+@item W W l
+@kindex W W l (Summary)
+@findex gnus-article-hide-list-identifiers
+@vindex gnus-list-identifiers
+Strip list identifiers specified in @code{gnus-list-identifiers}.  These
+are strings some mailing list servers add to the beginning of all
+@code{Subject} headers---for example, @samp{[zebra 4711]}.  Any leading
+@samp{Re: } is skipped before stripping.  @code{gnus-list-identifiers}
+may not contain @code{\\(..\\)}.
+
+@table @code
+
+@item gnus-list-identifiers
+@vindex gnus-list-identifiers
+A regular expression that matches list identifiers to be removed from
+subject.  This can also be a list of regular expressions.
+
+@end table
+
+@item W W P
+@kindex W W P (Summary)
+@findex gnus-article-hide-pem
+Hide @acronym{PEM} (privacy enhanced messages) cruft
+(@code{gnus-article-hide-pem}).
+
+@item W W B
+@kindex W W B (Summary)
+@findex gnus-article-strip-banner
+@vindex gnus-article-banner-alist
+@vindex gnus-article-address-banner-alist
+@cindex banner
+@cindex OneList
+@cindex stripping advertisements
+@cindex advertisements
+Strip the banner specified by the @code{banner} group parameter
+(@code{gnus-article-strip-banner}).  This is mainly used to hide those
+annoying banners and/or signatures that some mailing lists and moderated
+groups adds to all the messages.  The way to use this function is to add
+the @code{banner} group parameter (@pxref{Group Parameters}) to the
+group you want banners stripped from.  The parameter either be a string,
+which will be interpreted as a regular expression matching text to be
+removed, or the symbol @code{signature}, meaning that the (last)
+signature should be removed, or other symbol, meaning that the
+corresponding regular expression in @code{gnus-article-banner-alist} is
+used.
+
+For instance:
+
+@lisp
+(setq gnus-article-banner-alist
+      ((googleGroups .
+       "^\n*--~--~---------\\(.+\n\\)+")))
+@end lisp
+
+Regardless of a group, you can hide things like advertisements only when
+the sender of an article has a certain mail address specified in
+@code{gnus-article-address-banner-alist}.
+
+@table @code
+
+@item gnus-article-address-banner-alist
+@vindex gnus-article-address-banner-alist
+Alist of mail addresses and banners.  Each element has the form
+@code{(@var{address} . @var{banner})}, where @var{address} is a regexp
+matching a mail address in the From header, @var{banner} is one of a
+symbol @code{signature}, an item in @code{gnus-article-banner-alist},
+a regexp and @code{nil}.  If @var{address} matches author's mail
+address, it will remove things like advertisements.  For example, if a
+sender has the mail address @samp{hail@@yoo-hoo.co.jp} and there is a
+banner something like @samp{Do You Yoo-hoo!?} in all articles he
+sends, you can use the following element to remove them:
+
+@lisp
+("@@yoo-hoo\\.co\\.jp\\'" .
+ "\n_+\nDo You Yoo-hoo!\\?\n.*\n.*\n")
+@end lisp
+
+@end table
+
+@item W W c
+@kindex W W c (Summary)
+@findex gnus-article-hide-citation
+Hide citation (@code{gnus-article-hide-citation}).  Some variables for
+customizing the hiding:
+
+@table @code
+
+@item gnus-cited-opened-text-button-line-format
+@itemx gnus-cited-closed-text-button-line-format
+@vindex gnus-cited-closed-text-button-line-format
+@vindex gnus-cited-opened-text-button-line-format
+Gnus adds buttons to show where the cited text has been hidden, and to
+allow toggle hiding the text.  The format of the variable is specified
+by these format-like variable (@pxref{Formatting Variables}).  These
+specs are valid:
+
+@table @samp
+@item b
+Starting point of the hidden text.
+@item e
+Ending point of the hidden text.
+@item l
+Number of characters in the hidden region.
+@item n
+Number of lines of hidden text.
+@end table
+
+@item gnus-cited-lines-visible
+@vindex gnus-cited-lines-visible
+The number of lines at the beginning of the cited text to leave
+shown.  This can also be a cons cell with the number of lines at the top
+and bottom of the text, respectively, to remain visible.
+
+@end table
+
+@item W W C-c
+@kindex W W C-c (Summary)
+@findex gnus-article-hide-citation-maybe
+
+Hide citation (@code{gnus-article-hide-citation-maybe}) depending on the
+following two variables:
+
+@table @code
+@item gnus-cite-hide-percentage
+@vindex gnus-cite-hide-percentage
+If the cited text is of a bigger percentage than this variable (default
+50), hide the cited text.
+
+@item gnus-cite-hide-absolute
+@vindex gnus-cite-hide-absolute
+The cited text must have at least this length (default 10) before it
+is hidden.
+@end table
+
+@item W W C
+@kindex W W C (Summary)
+@findex gnus-article-hide-citation-in-followups
+Hide cited text in articles that aren't roots
+(@code{gnus-article-hide-citation-in-followups}).  This isn't very
+useful as an interactive command, but might be a handy function to stick
+have happen automatically (@pxref{Customizing Articles}).
+
+@end table
+
+All these ``hiding'' commands are toggles, but if you give a negative
+prefix to these commands, they will show what they have previously
+hidden.  If you give a positive prefix, they will always hide.
+
+Also @pxref{Article Highlighting} for further variables for
+citation customization.
+
+@xref{Customizing Articles}, for how to hide article elements
+automatically.
+
+
+@node Article Washing
+@subsection Article Washing
+@cindex washing
+@cindex article washing
+
+We call this ``article washing'' for a really good reason.  Namely, the
+@kbd{A} key was taken, so we had to use the @kbd{W} key instead.
+
+@dfn{Washing} is defined by us as ``changing something from something to
+something else'', but normally results in something looking better.
+Cleaner, perhaps.
+
+@xref{Customizing Articles}, if you want to change how Gnus displays
+articles by default.
+
+@table @kbd
+
+@item C-u g
+This is not really washing, it's sort of the opposite of washing.  If
+you type this, you see the article exactly as it exists on disk or on
+the server.
+
+@item g
+Force redisplaying of the current article
+(@code{gnus-summary-show-article}).  This is also not really washing.
+If you type this, you see the article without any previously applied
+interactive Washing functions but with all default treatments
+(@pxref{Customizing Articles}).
+
+@item W l
+@kindex W l (Summary)
+@findex gnus-summary-stop-page-breaking
+Remove page breaks from the current article
+(@code{gnus-summary-stop-page-breaking}).  @xref{Misc Article}, for page
+delimiters.
+
+@item W r
+@kindex W r (Summary)
+@findex gnus-summary-caesar-message
+@c @icon{gnus-summary-caesar-message}
+Do a Caesar rotate (rot13) on the article buffer
+(@code{gnus-summary-caesar-message}).
+Unreadable articles that tell you to read them with Caesar rotate or rot13.
+(Typically offensive jokes and such.)
+
+It's commonly called ``rot13'' because each letter is rotated 13
+positions in the alphabet, e.g., @samp{B} (letter #2) -> @samp{O} (letter
+#15).  It is sometimes referred to as ``Caesar rotate'' because Caesar
+is rumored to have employed this form of, uh, somewhat weak encryption.
+
+@item W m
+@kindex W m (Summary)
+@findex gnus-summary-morse-message
+Morse decode the article buffer (@code{gnus-summary-morse-message}).
+
+@item W i
+@kindex W i (Summary)
+@findex gnus-summary-idna-message
+Decode IDNA encoded domain names in the current articles.  IDNA
+encoded domain names looks like @samp{xn--bar}.  If a string remain
+unencoded after running invoking this, it is likely an invalid IDNA
+string (@samp{xn--bar} is invalid).  You must have GNU Libidn
+(@url{http://www.gnu.org/software/libidn/}) installed for this command
+to work.
+
+@item W t
+@item t
+@kindex W t (Summary)
+@kindex t (Summary)
+@findex gnus-summary-toggle-header
+Toggle whether to display all headers in the article buffer
+(@code{gnus-summary-toggle-header}).
+
+@item W v
+@kindex W v (Summary)
+@findex gnus-summary-verbose-headers
+Toggle whether to display all headers in the article buffer permanently
+(@code{gnus-summary-verbose-headers}).
+
+@item W o
+@kindex W o (Summary)
+@findex gnus-article-treat-overstrike
+Treat overstrike (@code{gnus-article-treat-overstrike}).
+
+@item W d
+@kindex W d (Summary)
+@findex gnus-article-treat-dumbquotes
+@vindex gnus-article-dumbquotes-map
+@cindex Smartquotes
+@cindex M****s*** sm*rtq**t*s
+@cindex Latin 1
+Treat M****s*** sm*rtq**t*s according to
+@code{gnus-article-dumbquotes-map}
+(@code{gnus-article-treat-dumbquotes}).  Note that this function guesses
+whether a character is a sm*rtq**t* or not, so it should only be used
+interactively.
+
+Sm*rtq**t*s are M****s***'s unilateral extension to the character map in
+an attempt to provide more quoting characters.  If you see something
+like @code{\222} or @code{\264} where you're expecting some kind of
+apostrophe or quotation mark, then try this wash.
+
+@item W U
+@kindex W U (Summary)
+@findex gnus-article-treat-non-ascii
+@cindex Unicode
+@cindex Non-@acronym{ASCII}
+Translate many non-@acronym{ASCII} characters into their
+@acronym{ASCII} equivalents (@code{gnus-article-treat-non-ascii}).
+This is mostly useful if you're on a terminal that has a limited font
+and doesn't show accented characters, ``advanced'' punctuation, and the
+like.  For instance, @samp{»} is translated into @samp{>>}, and so on.
+
+@item W Y f
+@kindex W Y f (Summary)
+@findex gnus-article-outlook-deuglify-article
+@cindex Outlook Express
+Full deuglify of broken Outlook (Express) articles: Treat dumbquotes,
+unwrap lines, repair attribution and rearrange citation.
+(@code{gnus-article-outlook-deuglify-article}).
+
+@item W Y u
+@kindex W Y u (Summary)
+@findex gnus-article-outlook-unwrap-lines
+@vindex gnus-outlook-deuglify-unwrap-min
+@vindex gnus-outlook-deuglify-unwrap-max
+Unwrap lines that appear to be wrapped citation lines.  You can control
+what lines will be unwrapped by frobbing
+@code{gnus-outlook-deuglify-unwrap-min} and
+@code{gnus-outlook-deuglify-unwrap-max}, indicating the minimum and
+maximum length of an unwrapped citation line.
+(@code{gnus-article-outlook-unwrap-lines}).
+
+@item W Y a
+@kindex W Y a (Summary)
+@findex gnus-article-outlook-repair-attribution
+Repair a broken attribution line.@*
+(@code{gnus-article-outlook-repair-attribution}).
+
+@item W Y c
+@kindex W Y c (Summary)
+@findex gnus-article-outlook-rearrange-citation
+Repair broken citations by rearranging the text.
+(@code{gnus-article-outlook-rearrange-citation}).
+
+@item W w
+@kindex W w (Summary)
+@findex gnus-article-fill-cited-article
+Do word wrap (@code{gnus-article-fill-cited-article}).
+
+You can give the command a numerical prefix to specify the width to use
+when filling.
+
+@item W Q
+@kindex W Q (Summary)
+@findex gnus-article-fill-long-lines
+Fill long lines (@code{gnus-article-fill-long-lines}).
+
+@item W C
+@kindex W C (Summary)
+@findex gnus-article-capitalize-sentences
+Capitalize the first word in each sentence
+(@code{gnus-article-capitalize-sentences}).
+
+@item W c
+@kindex W c (Summary)
+@findex gnus-article-remove-cr
+Translate CRLF pairs (i.e., @samp{^M}s on the end of the lines) into LF
+(this takes care of DOS line endings), and then translate any remaining
+CRs into LF (this takes care of Mac line endings)
+(@code{gnus-article-remove-cr}).
+
+@item W q
+@kindex W q (Summary)
+@findex gnus-article-de-quoted-unreadable
+Treat quoted-printable (@code{gnus-article-de-quoted-unreadable}).
+Quoted-Printable is one common @acronym{MIME} encoding employed when
+sending non-@acronym{ASCII} (i.e., 8-bit) articles.  It typically
+makes strings like @samp{déjà vu} look like @samp{d=E9j=E0 vu},
+which doesn't look very readable to me.  Note that 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)
+@findex gnus-article-de-base64-unreadable
+Treat base64 (@code{gnus-article-de-base64-unreadable}).  Base64 is
+one common @acronym{MIME} encoding employed when sending
+non-@acronym{ASCII} (i.e., 8-bit) articles.  Note that 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 Z
+@kindex W Z (Summary)
+@findex gnus-article-decode-HZ
+Treat HZ or HZP (@code{gnus-article-decode-HZ}).  HZ (or HZP) is one
+common encoding employed when sending Chinese articles.  It typically
+makes strings look like @samp{~@{<:Ky2;S@{#,NpJ)l6HK!#~@}}.
+
+@item W A
+@kindex W A (Summary)
+@findex gnus-article-treat-ansi-sequences
+@cindex @acronym{ANSI} control sequences
+Translate @acronym{ANSI} SGR control sequences into overlays or
+extents (@code{gnus-article-treat-ansi-sequences}).  @acronym{ANSI}
+sequences are used in some Chinese hierarchies for highlighting.
+
+@item W u
+@kindex W u (Summary)
+@findex gnus-article-unsplit-urls
+Remove newlines from within URLs.  Some mailers insert newlines into
+outgoing email messages to keep lines short.  This reformatting can
+split long URLs onto multiple lines.  Repair those URLs by removing
+the newlines (@code{gnus-article-unsplit-urls}).
+
+@item W h
+@kindex W h (Summary)
+@findex gnus-article-wash-html
+Treat @acronym{HTML} (@code{gnus-article-wash-html}).  Note that this is
+usually done automatically by Gnus if the message in question has a
+@code{Content-Type} header that says that the message is @acronym{HTML}.
+
+If a prefix is given, a charset will be asked for.  If it is a number,
+the charset defined in @code{gnus-summary-show-article-charset-alist}
+(@pxref{Paging the Article}) will be used.
+
+The default is to use the function specified by
+@code{mm-text-html-renderer} (@pxref{Display Customization, ,Display
+Customization, emacs-mime, The Emacs MIME Manual}) to convert the
+@acronym{HTML}.  Pre-defined functions you can use include:
+
+@table @code
+@item shr
+Use Gnus simple html renderer.
+
+@item gnus-w3m
+Use Gnus rendered based on w3m.
+
+@item w3m
+Use @uref{http://emacs-w3m.namazu.org/, emacs-w3m}.
+
+@item w3m-standalone
+Use @uref{http://w3m.sourceforge.net/, w3m}.
+
+@item links
+Use @uref{http://links.sf.net/, Links}.
+
+@item lynx
+Use @uref{http://lynx.isc.org/, Lynx}.
+
+@item html2text
+Use html2text---a simple @acronym{HTML} converter included with Gnus.
+
+@end table
+
+@item W b
+@kindex W b (Summary)
+@findex gnus-article-add-buttons
+Add clickable buttons to the article (@code{gnus-article-add-buttons}).
+@xref{Article Buttons}.
+
+@item W B
+@kindex W B (Summary)
+@findex gnus-article-add-buttons-to-head
+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 @acronym{PGP} public key of
+the maintainer to your keyring to verify the
+message.@footnote{@acronym{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 (@acronym{PGP}, @acronym{PGP/MIME} or
+@acronym{S/MIME}) message
+(@code{gnus-summary-force-verify-and-decrypt}). @xref{Security}.
+
+@item W a
+@kindex W a (Summary)
+@findex gnus-article-strip-headers-in-body
+Strip headers like the @code{X-No-Archive} header from the beginning of
+article bodies (@code{gnus-article-strip-headers-in-body}).
+
+@item W E l
+@kindex W E l (Summary)
+@findex gnus-article-strip-leading-blank-lines
+Remove all blank lines from the beginning of the article
+(@code{gnus-article-strip-leading-blank-lines}).
+
+@item W E m
+@kindex W E m (Summary)
+@findex gnus-article-strip-multiple-blank-lines
+Replace all blank lines with empty lines and then all multiple empty
+lines with a single empty line.
+(@code{gnus-article-strip-multiple-blank-lines}).
+
+@item W E t
+@kindex W E t (Summary)
+@findex gnus-article-remove-trailing-blank-lines
+Remove all blank lines at the end of the article
+(@code{gnus-article-remove-trailing-blank-lines}).
+
+@item W E a
+@kindex W E a (Summary)
+@findex gnus-article-strip-blank-lines
+Do all the three commands above
+(@code{gnus-article-strip-blank-lines}).
+
+@item W E A
+@kindex W E A (Summary)
+@findex gnus-article-strip-all-blank-lines
+Remove all blank lines
+(@code{gnus-article-strip-all-blank-lines}).
+
+@item W E s
+@kindex W E s (Summary)
+@findex gnus-article-strip-leading-space
+Remove all white space from the beginning of all lines of the article
+body (@code{gnus-article-strip-leading-space}).
+
+@item W E e
+@kindex W E e (Summary)
+@findex gnus-article-strip-trailing-space
+Remove all white space from the end of all lines of the article
+body (@code{gnus-article-strip-trailing-space}).
+
+@end table
+
+@xref{Customizing Articles}, for how to wash articles automatically.
+
+
+@node Article Header
+@subsection Article Header
+
+These commands perform various transformations of article header.
+
+@table @kbd
+
+@item W G u
+@kindex W G u (Summary)
+@findex gnus-article-treat-unfold-headers
+Unfold folded header lines (@code{gnus-article-treat-unfold-headers}).
+
+@item W G n
+@kindex W G 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 G f
+@kindex W G f (Summary)
+@findex gnus-article-treat-fold-headers
+Fold all the message headers
+(@code{gnus-article-treat-fold-headers}).
+
+@item W E w
+@kindex W E w (Summary)
+@findex gnus-article-remove-leading-whitespace
+Remove excessive whitespace from all headers
+(@code{gnus-article-remove-leading-whitespace}).
+
+@end table
+
+
+@node Article Buttons
+@subsection Article Buttons
+@cindex buttons
+
+People often include references to other stuff in articles, and it would
+be nice if Gnus could just fetch whatever it is that people talk about
+with the minimum of fuzz when you hit @kbd{RET} or use the middle mouse
+button on these references.
+
+@vindex gnus-button-man-handler
+Gnus adds @dfn{buttons} to certain standard references by default:
+Well-formed URLs, mail addresses, Message-IDs, Info links, man pages and
+Emacs or Gnus related references.  This is controlled by two variables,
+one that handles article bodies and one that handles article heads:
+
+@table @code
+
+@item gnus-button-alist
+@vindex gnus-button-alist
+This is an alist where each entry has this form:
+
+@lisp
+(@var{regexp} @var{button-par} @var{use-p} @var{function} @var{data-par})
+@end lisp
+
+@table @var
+
+@item regexp
+All text that match this regular expression (case insensitive) will be
+considered an external reference.  Here's a typical regexp that matches
+embedded URLs: @samp{<URL:\\([^\n\r>]*\\)>}.  This can also be a
+variable containing a regexp, useful variables to use include
+@code{gnus-button-url-regexp} and @code{gnus-button-mid-or-mail-regexp}.
+
+@item button-par
+Gnus has to know which parts of the matches is to be highlighted.  This
+is a number that says what sub-expression of the regexp is to be
+highlighted.  If you want it all highlighted, you use 0 here.
+
+@item use-p
+This form will be @code{eval}ed, and if the result is non-@code{nil},
+this is considered a match.  This is useful if you want extra sifting to
+avoid false matches.  Often variables named
+@code{gnus-button-@var{*}-level} are used here, @xref{Article Button
+Levels}, but any other form may be used too.
+
+@c @code{use-p} is @code{eval}ed only if @code{regexp} matches.
+
+@item function
+This function will be called when you click on this button.
+
+@item data-par
+As with @var{button-par}, this is a sub-expression number, but this one
+says which part of the match is to be sent as data to @var{function}.
+
+@end table
+
+So the full entry for buttonizing URLs is then
+
+@lisp
+("<URL:\\([^\n\r>]*\\)>" 0 t gnus-button-url 1)
+@end lisp
+
+@item gnus-header-button-alist
+@vindex gnus-header-button-alist
+This is just like the other alist, except that it is applied to the
+article head only, and that each entry has an additional element that is
+used to say what headers to apply the buttonize coding to:
+
+@lisp
+(@var{header} @var{regexp} @var{button-par} @var{use-p} @var{function} @var{data-par})
+@end lisp
+
+@var{header} is a regular expression.
+@end table
+
+@subsubsection Related variables and functions
+
+@table @code
+@item gnus-button-@var{*}-level
+@xref{Article Button Levels}.
+
+@c Stuff related to gnus-button-browse-level
+
+@item gnus-button-url-regexp
+@vindex gnus-button-url-regexp
+A regular expression that matches embedded URLs.  It is used in the
+default values of the variables above.
+
+@c Stuff related to gnus-button-man-level
+
+@item gnus-button-man-handler
+@vindex gnus-button-man-handler
+The function to use for displaying man pages.  It must take at least one
+argument with a string naming the man page.
+
+@c Stuff related to gnus-button-message-level
+
+@item gnus-button-mid-or-mail-regexp
+@vindex gnus-button-mid-or-mail-regexp
+Regular expression that matches a message ID or a mail address.
+
+@item gnus-button-prefer-mid-or-mail
+@vindex gnus-button-prefer-mid-or-mail
+This variable determines what to do when the button on a string as
+@samp{foo123@@bar.invalid} is pushed.  Strings like this can be either a
+message ID or a mail address.  If it is one of the symbols @code{mid} or
+@code{mail}, Gnus will always assume that the string is a message ID or
+a mail address, respectively.  If this variable is set to the symbol
+@code{ask}, always query the user what to do.  If it is a function, this
+function will be called with the string as its only argument.  The
+function must return @code{mid}, @code{mail}, @code{invalid} or
+@code{ask}.  The default value is the function
+@code{gnus-button-mid-or-mail-heuristic}.
+
+@item gnus-button-mid-or-mail-heuristic
+@findex gnus-button-mid-or-mail-heuristic
+Function that guesses whether its argument is a message ID or a mail
+address.  Returns @code{mid} if it's a message IDs, @code{mail} if
+it's a mail address, @code{ask} if unsure and @code{invalid} if the
+string is invalid.
+
+@item gnus-button-mid-or-mail-heuristic-alist
+@vindex gnus-button-mid-or-mail-heuristic-alist
+An alist of @code{(RATE . REGEXP)} pairs used by the function
+@code{gnus-button-mid-or-mail-heuristic}.
+
+@c Misc stuff
+
+@item gnus-article-button-face
+@vindex gnus-article-button-face
+Face used on buttons.
+
+@item gnus-article-mouse-face
+@vindex gnus-article-mouse-face
+Face used when the mouse cursor is over a button.
+
+@end table
+
+@xref{Customizing Articles}, for how to buttonize articles automatically.
+
+
+@node Article Button Levels
+@subsection Article button levels
+@cindex button levels
+The higher the value of the variables @code{gnus-button-@var{*}-level},
+the more buttons will appear.  If the level is zero, no corresponding
+buttons are displayed.  With the default value (which is 5) you should
+already see quite a lot of buttons.  With higher levels, you will see
+more buttons, but you may also get more false positives.  To avoid them,
+you can set the variables @code{gnus-button-@var{*}-level} local to
+specific groups (@pxref{Group Parameters}).  Here's an example for the
+variable @code{gnus-parameters}:
+
+@lisp
+;; @r{increase @code{gnus-button-*-level} in some groups:}
+(setq gnus-parameters
+      '(("\\<\\(emacs\\|gnus\\)\\>" (gnus-button-emacs-level 10))
+        ("\\<unix\\>"               (gnus-button-man-level 10))
+        ("\\<tex\\>"                (gnus-button-tex-level 10))))
+@end lisp
+
+@table @code
+
+@item gnus-button-browse-level
+@vindex gnus-button-browse-level
+Controls the display of references to message IDs, mail addresses and
+news URLs.  Related variables and functions include
+@code{gnus-button-url-regexp}, @code{browse-url}, and
+@code{browse-url-browser-function}.
+
+@item gnus-button-emacs-level
+@vindex gnus-button-emacs-level
+Controls the display of Emacs or Gnus references.  Related functions are
+@code{gnus-button-handle-custom},
+@code{gnus-button-handle-describe-function},
+@code{gnus-button-handle-describe-variable},
+@code{gnus-button-handle-symbol},
+@code{gnus-button-handle-describe-key},
+@code{gnus-button-handle-apropos},
+@code{gnus-button-handle-apropos-command},
+@code{gnus-button-handle-apropos-variable},
+@code{gnus-button-handle-apropos-documentation}, and
+@code{gnus-button-handle-library}.
+
+@item gnus-button-man-level
+@vindex gnus-button-man-level
+Controls the display of references to (Unix) man pages.
+See @code{gnus-button-man-handler}.
+
+@item gnus-button-message-level
+@vindex gnus-button-message-level
+Controls the display of message IDs, mail addresses and news URLs.
+Related variables and functions include
+@code{gnus-button-mid-or-mail-regexp},
+@code{gnus-button-prefer-mid-or-mail},
+@code{gnus-button-mid-or-mail-heuristic}, and
+@code{gnus-button-mid-or-mail-heuristic-alist}.
+
+@end table
+
+
+@node Article Date
+@subsection Article Date
+
+The date is most likely generated in some obscure timezone you've never
+heard of, so it's quite nice to be able to find out what the time was
+when the article was sent.
+
+@table @kbd
+
+@item W T u
+@kindex W T u (Summary)
+@findex gnus-article-date-ut
+Display the date in UT (aka. GMT, aka ZULU)
+(@code{gnus-article-date-ut}).
+
+@item W T i
+@kindex W T i (Summary)
+@findex gnus-article-date-iso8601
+@cindex ISO 8601
+Display the date in international format, aka. ISO 8601
+(@code{gnus-article-date-iso8601}).
+
+@item W T l
+@kindex W T l (Summary)
+@findex gnus-article-date-local
+Display the date in the local timezone (@code{gnus-article-date-local}).
+
+@item W T p
+@kindex W T p (Summary)
+@findex gnus-article-date-english
+Display the date in a format that's easily pronounceable in English
+(@code{gnus-article-date-english}).
+
+@item W T s
+@kindex W T s (Summary)
+@vindex gnus-article-time-format
+@findex gnus-article-date-user
+@findex format-time-string
+Display the date using a user-defined format
+(@code{gnus-article-date-user}).  The format is specified by the
+@code{gnus-article-time-format} variable, and is a string that's passed
+to @code{format-time-string}.  See the documentation of that variable
+for a list of possible format specs.
+
+@item W T e
+@kindex W T e (Summary)
+@findex gnus-article-date-lapsed
+@findex gnus-start-date-timer
+@findex gnus-stop-date-timer
+Say how much time has elapsed between the article was posted and now
+(@code{gnus-article-date-lapsed}).  It looks something like:
+
+@example
+Date: 6 weeks, 4 days, 1 hour, 3 minutes, 8 seconds ago
+@end example
+
+To make this line updated continually, set the
+@code{gnus-article-update-date-headers} variable to the frequency in
+seconds (the default is @code{nil}).
+
+@item W T o
+@kindex W T o (Summary)
+@findex gnus-article-date-original
+Display the original date (@code{gnus-article-date-original}).  This can
+be useful if you normally use some other conversion function and are
+worried that it might be doing something totally wrong.  Say, claiming
+that the article was posted in 1854.  Although something like that is
+@emph{totally} impossible.  Don't you trust me?  *titter*
+
+@end table
+
+@xref{Customizing Articles}, for how to display the date in your
+preferred format automatically.
+
+
+@node Article Display
+@subsection Article Display
+@cindex picons
+@cindex x-face
+@cindex smileys
+@cindex gravatars
+
+These commands add various frivolous display gimmicks 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}).
+
+@code{Face} headers are small colored images supplied by the message
+headers (@pxref{Face}).
+
+Smileys are those little @samp{:-)} symbols that people like to litter
+their messages with (@pxref{Smileys}).
+
+Picons, on the other hand, reside on your own system, and Gnus will
+try to match the headers to what you have (@pxref{Picons}).
+
+Gravatars reside on-line and are fetched from
+@uref{http://www.gravatar.com/} (@pxref{Gravatars}).
+
+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 d
+@kindex W D d (Summary)
+@findex gnus-article-display-face
+Display a @code{Face} in the @code{From} header.
+(@code{gnus-article-display-face}).
+
+@item W D s
+@kindex W D s (Summary)
+@findex gnus-treat-smiley
+Display smileys (@code{gnus-treat-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-newsgroups-picon}).
+
+@item W D g
+@kindex W D g (Summary)
+@findex gnus-treat-from-gravatar
+Gravatarify the @code{From} header (@code{gnus-treat-from-gravatar}).
+
+@item W D h
+@kindex W D h (Summary)
+@findex gnus-treat-mail-gravatar
+Gravatarify all mail headers (i.e., @code{Cc}, @code{To})
+(@code{gnus-treat-from-gravatar}).
+
+@item W D D
+@kindex W D D (Summary)
+@findex gnus-article-remove-images
+Remove all images from the article buffer
+(@code{gnus-article-remove-images}).
+
+@item W D W
+@kindex W D W (Summary)
+@findex gnus-html-show-images
+If you're reading an @acronym{HTML} article rendered with
+@code{gnus-article-html}, then you can insert any blocked images in
+the buffer with this command.
+(@code{gnus-html-show-images}).
+
+@end table
+
+
+
+@node Article Signature
+@subsection Article Signature
+@cindex signatures
+@cindex article signature
+
+@vindex gnus-signature-separator
+Each article is divided into two parts---the head and the body.  The
+body can be divided into a signature part and a text part.  The variable
+that says what is to be considered a signature is
+@code{gnus-signature-separator}.  This is normally the standard
+@samp{^-- $} as mandated by son-of-RFC 1036.  However, many people use
+non-standard signature separators, so this variable can also be a list
+of regular expressions to be tested, one by one.  (Searches are done
+from the end of the body towards the beginning.)  One likely value is:
+
+@lisp
+(setq gnus-signature-separator
+      '("^-- $"         ; @r{The standard}
+        "^-- *$"        ; @r{A common mangling}
+        "^-------*$"    ; @r{Many people just use a looong}
+                        ; @r{line of dashes.  Shame!}
+        "^ *--------*$" ; @r{Double-shame!}
+        "^________*$"   ; @r{Underscores are also popular}
+        "^========*$")) ; @r{Pervert!}
+@end lisp
+
+The more permissive you are, the more likely it is that you'll get false
+positives.
+
+@vindex gnus-signature-limit
+@code{gnus-signature-limit} provides a limit to what is considered a
+signature when displaying articles.
+
+@enumerate
+@item
+If it is an integer, no signature may be longer (in characters) than
+that integer.
+@item
+If it is a floating point number, no signature may be longer (in lines)
+than that number.
+@item
+If it is a function, the function will be called without any parameters,
+and if it returns @code{nil}, there is no signature in the buffer.
+@item
+If it is a string, it will be used as a regexp.  If it matches, the text
+in question is not a signature.
+@end enumerate
+
+This variable can also be a list where the elements may be of the types
+listed above.  Here's an example:
+
+@lisp
+(setq gnus-signature-limit
+      '(200.0 "^---*Forwarded article"))
+@end lisp
+
+This means that if there are more than 200 lines after the signature
+separator, or the text after the signature separator is matched by
+the regular expression @samp{^---*Forwarded article}, then it isn't a
+signature after all.
+
+
+@node Article Miscellanea
+@subsection Article Miscellanea
+
+@table @kbd
+@item A t
+@kindex A t (Summary)
+@findex gnus-article-babel
+Translate the article from one language to another
+(@code{gnus-article-babel}).
+
+@end table
+
+
+@node MIME Commands
+@section MIME Commands
+@cindex MIME decoding
+@cindex attachments
+@cindex viewing attachments
+
+The following commands all understand the numerical prefix.  For
+instance, @kbd{3 K v} means ``view the third @acronym{MIME} part''.
+
+@table @kbd
+@item b
+@itemx K v
+@kindex b (Summary)
+@kindex K v (Summary)
+View the @acronym{MIME} part.
+
+@item K o
+@kindex K o (Summary)
+Save the @acronym{MIME} part.
+
+@item K O
+@kindex K O (Summary)
+Prompt for a file name, then save the @acronym{MIME} part and strip it
+from the article.  The stripped @acronym{MIME} object will be referred
+via the message/external-body @acronym{MIME} type.
+
+@item K r
+@kindex K r (Summary)
+Replace the @acronym{MIME} part with an external body.
+
+@item K d
+@kindex K d (Summary)
+Delete the @acronym{MIME} part and add some information about the
+removed part.
+
+@item K c
+@kindex K c (Summary)
+Copy the @acronym{MIME} part.
+
+@item K e
+@kindex K e (Summary)
+View the @acronym{MIME} part externally.
+
+@item K i
+@kindex K i (Summary)
+View the @acronym{MIME} part internally.
+
+@item K |
+@kindex K | (Summary)
+Pipe the @acronym{MIME} part to an external command.
+@end table
+
+The rest of these @acronym{MIME} commands do not use the numerical prefix in
+the same manner:
+
+@table @kbd
+@item K H
+@kindex K H (Summary)
+@findex gnus-article-browse-html-article
+View @samp{text/html} parts of the current article with a WWW browser.
+Inline images embedded in a message using the @code{cid} scheme, as they
+are generally considered to be safe, will be processed properly.  The
+message header is added to the beginning of every @acronym{HTML} part
+unless the prefix argument is given.
+
+Warning: Spammers use links to images (using the @code{http} scheme) in
+@acronym{HTML} articles to verify whether you have read the message.  As
+this command passes the @acronym{HTML} content to the browser without
+eliminating these ``web bugs'' you should only use it for mails from
+trusted senders.
+
+If you always want to display @acronym{HTML} parts in the browser, set
+@code{mm-text-html-renderer} to @code{nil}.
+
+This command creates temporary files to pass @acronym{HTML} contents
+including images if any to the browser, and deletes them when exiting
+the group (if you want).
+
+@item K b
+@kindex K b (Summary)
+Make all the @acronym{MIME} parts have buttons in front of them.  This is
+mostly useful if you wish to save (or perform other actions) on inlined
+parts.
+
+@item W M h
+@kindex W M h (Summary)
+@findex gnus-mime-buttonize-attachments-in-header
+@vindex gnus-mime-display-attachment-buttons-in-header
+Display @acronym{MIME} part buttons in the end of the header of an
+article (@code{gnus-mime-buttonize-attachments-in-header}).  This
+command toggles the display.  Note that buttons to be added to the
+header are only the ones that aren't inlined in the body.  If you want
+those buttons always to be displayed, set
+@code{gnus-mime-display-attachment-buttons-in-header} to non-@code{nil}.
+The default is @code{t}.  To change the appearance of buttons, customize
+@code{gnus-header-face-alist}.
+
+@item K m
+@kindex K m (Summary)
+@findex gnus-summary-repair-multipart
+Some multipart messages are transmitted with missing or faulty headers.
+This command will attempt to ``repair'' these messages so that they can
+be viewed in a more pleasant manner
+(@code{gnus-summary-repair-multipart}).
+
+@item X m
+@kindex X m (Summary)
+@findex gnus-summary-save-parts
+Save all parts matching a @acronym{MIME} type to a directory
+(@code{gnus-summary-save-parts}).  Understands the process/prefix
+convention (@pxref{Process/Prefix}).
+
+@item M-t
+@kindex M-t (Summary)
+@findex gnus-summary-toggle-display-buttonized
+Toggle the buttonized display of the article buffer
+(@code{gnus-summary-toggle-display-buttonized}).
+
+@item W M w
+@kindex W M w (Summary)
+@findex gnus-article-decode-mime-words
+Decode RFC 2047-encoded words in the article headers
+(@code{gnus-article-decode-mime-words}).
+
+@item W M c
+@kindex W M c (Summary)
+@findex gnus-article-decode-charset
+Decode encoded article bodies as well as charsets
+(@code{gnus-article-decode-charset}).
+
+This command looks in the @code{Content-Type} header to determine the
+charset.  If there is no such header in the article, you can give it a
+prefix, which will prompt for the charset to decode as.  In regional
+groups where people post using some common encoding (but do not
+include @acronym{MIME} headers), you can set the @code{charset} group/topic
+parameter to the required charset (@pxref{Group Parameters}).
+
+@item W M v
+@kindex W M v (Summary)
+@findex gnus-mime-view-all-parts
+View all the @acronym{MIME} parts in the current article
+(@code{gnus-mime-view-all-parts}).
+
+@end table
+
+Relevant variables:
+
+@table @code
+@item gnus-ignored-mime-types
+@vindex gnus-ignored-mime-types
+This is a list of regexps.  @acronym{MIME} types that match a regexp from
+this list will be completely ignored by Gnus.  The default value is
+@code{nil}.
+
+To have all Vcards be ignored, you'd say something like this:
+
+@lisp
+(setq gnus-ignored-mime-types
+      '("text/x-vcard"))
+@end lisp
+
+@item gnus-article-loose-mime
+@vindex gnus-article-loose-mime
+If non-@code{nil}, Gnus won't require the @samp{MIME-Version} header
+before interpreting the message as a @acronym{MIME} message.  This helps
+when reading messages from certain broken mail user agents.  The
+default is @code{t}.
+
+@item gnus-article-emulate-mime
+@vindex gnus-article-emulate-mime
+@cindex uuencode
+@cindex yEnc
+There are other, non-@acronym{MIME} encoding methods used.  The most common
+is @samp{uuencode}, but yEncode is also getting to be popular.  If
+this variable is non-@code{nil}, Gnus will look in message bodies to
+see if it finds these encodings, and if so, it'll run them through the
+Gnus @acronym{MIME} machinery.  The default is @code{t}.  Only
+single-part yEnc encoded attachments can be decoded.  There's no support
+for encoding in Gnus.
+
+@item gnus-unbuttonized-mime-types
+@vindex gnus-unbuttonized-mime-types
+This is a list of regexps.  @acronym{MIME} types that match a regexp from
+this list won't have @acronym{MIME} buttons inserted unless they aren't
+displayed or this variable is overridden by
+@code{gnus-buttonized-mime-types}.  The default value is
+@code{(".*/.*")}.  This variable is only used when
+@code{gnus-inhibit-mime-unbuttonizing} is @code{nil}.
+
+@item gnus-buttonized-mime-types
+@vindex gnus-buttonized-mime-types
+This is a list of regexps.  @acronym{MIME} types that match a regexp from
+this list will have @acronym{MIME} buttons inserted unless they aren't
+displayed.  This variable overrides
+@code{gnus-unbuttonized-mime-types}.  The default value is @code{nil}.
+This variable is only used when @code{gnus-inhibit-mime-unbuttonizing}
+is @code{nil}.
+
+E.g., to see security buttons but no other buttons, you could set this
+variable to @code{("multipart/signed")} and leave
+@code{gnus-unbuttonized-mime-types} at the default value.
+
+You could also add @code{"multipart/alternative"} to this list to
+display radio buttons that allow you to choose one of two media types
+those mails include.  See also @code{mm-discouraged-alternatives}
+(@pxref{Display Customization, ,Display Customization, emacs-mime, The
+Emacs MIME Manual}).
+
+@item gnus-inhibit-mime-unbuttonizing
+@vindex gnus-inhibit-mime-unbuttonizing
+If this is non-@code{nil}, then all @acronym{MIME} parts get buttons.  The
+default value is @code{nil}.
+
+@item gnus-article-mime-part-function
+@vindex gnus-article-mime-part-function
+For each @acronym{MIME} part, this function will be called with the @acronym{MIME}
+handle as the parameter.  The function is meant to be used to allow
+users to gather information from the article (e.g., add Vcard info to
+the bbdb database) or to do actions based on parts (e.g., automatically
+save all jpegs into some directory).
+
+Here's an example function the does the latter:
+
+@lisp
+(defun my-save-all-jpeg-parts (handle)
+  (when (equal (car (mm-handle-type handle)) "image/jpeg")
+    (with-temp-buffer
+      (insert (mm-get-part handle))
+      (write-region (point-min) (point-max)
+                    (read-file-name "Save jpeg to: ")))))
+(setq gnus-article-mime-part-function
+      'my-save-all-jpeg-parts)
+@end lisp
+
+@vindex gnus-mime-multipart-functions
+@item gnus-mime-multipart-functions
+Alist of @acronym{MIME} multipart types and functions to handle them.
+
+@vindex gnus-mime-display-multipart-alternative-as-mixed
+@item gnus-mime-display-multipart-alternative-as-mixed
+Display "multipart/alternative" parts as "multipart/mixed".
+
+@vindex gnus-mime-display-multipart-related-as-mixed
+@item gnus-mime-display-multipart-related-as-mixed
+Display "multipart/related" parts as "multipart/mixed".
+
+If displaying @samp{text/html} is discouraged, see
+@code{mm-discouraged-alternatives}, images or other material inside a
+"multipart/related" part might be overlooked when this variable is
+@code{nil}.  @ref{Display Customization, Display Customization, ,
+emacs-mime, Emacs-Mime Manual}.
+
+@vindex gnus-mime-display-multipart-as-mixed
+@item gnus-mime-display-multipart-as-mixed
+Display "multipart" parts as "multipart/mixed".  If @code{t}, it
+overrides @code{nil} values of
+@code{gnus-mime-display-multipart-alternative-as-mixed} and
+@code{gnus-mime-display-multipart-related-as-mixed}.
+
+@vindex mm-file-name-rewrite-functions
+@item mm-file-name-rewrite-functions
+List of functions used for rewriting file names of @acronym{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.el} file.
+
+@end table
+
+
+@node Charsets
+@section Charsets
+@cindex charsets
+
+People use different charsets, and we have @acronym{MIME} to let us know what
+charsets they use.  Or rather, we wish we had.  Many people use
+newsreaders and mailers that do not understand or use @acronym{MIME}, and
+just send out messages without saying what character sets they use.  To
+help a bit with this, some local news hierarchies have policies that say
+what character set is the default.  For instance, the @samp{fj}
+hierarchy uses @code{iso-2022-jp}.
+
+@vindex gnus-group-charset-alist
+This knowledge is encoded in the @code{gnus-group-charset-alist}
+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.
+
+@vindex gnus-newsgroup-ignored-charsets
+In addition, some people do use soi-disant @acronym{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
+@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 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
+determine which charsets should not be encoded using the @acronym{MIME}
+encodings.  For instance, some hierarchies discourage using
+quoted-printable header encoding.
+
+This variable is an alist of regexps and permitted unencoded charsets
+for posting.  Each element of the alist has the form @code{(}@var{test
+header body-list}@code{)}, where:
+
+@table @var
+@item test
+is either a regular expression matching the newsgroup header or a
+variable to query,
+@item header
+is the charset which may be left unencoded in the header (@code{nil}
+means encode all charsets),
+@item body-list
+is a list of charsets which may be encoded using 8bit content-transfer
+encoding in the body, or one of the special values @code{nil} (always
+encode using quoted-printable) or @code{t} (always use 8bit).
+@end table
+
+@cindex Russian
+@cindex koi8-r
+@cindex koi8-u
+@cindex iso-8859-5
+@cindex coding system aliases
+@cindex preferred charset
+
+@xref{Encoding Customization, , Encoding Customization, emacs-mime,
+The Emacs MIME Manual}, for additional variables that control which
+MIME charsets are used when sending messages.
+
+Other charset tricks that may be useful, although not Gnus-specific:
+
+If there are several @acronym{MIME} charsets that encode the same Emacs
+charset, you can choose what charset to use by saying the following:
+
+@lisp
+(put-charset-property 'cyrillic-iso8859-5
+                      'preferred-coding-system 'koi8-r)
+@end lisp
+
+This means that Russian will be encoded using @code{koi8-r} instead of
+the default @code{iso-8859-5} @acronym{MIME} charset.
+
+If you want to read messages in @code{koi8-u}, you can cheat and say
+
+@lisp
+(define-coding-system-alias 'koi8-u 'koi8-r)
+@end lisp
+
+This will almost do the right thing.
+
+And finally, to read charsets like @code{windows-1251}, you can say
+something like
+
+@lisp
+(codepage-setup 1251)
+(define-coding-system-alias 'windows-1251 'cp1251)
+@end lisp
+
+
+@node Article Commands
+@section Article Commands
+
+@table @kbd
+
+@item A P
+@cindex PostScript
+@cindex printing
+@kindex A P (Summary)
+@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.  An alternative way to print
+article is to use Muttprint (@pxref{Saving Articles}).
+
+@item A C
+@vindex gnus-fetch-partial-articles
+@findex gnus-summary-show-complete-article
+If @code{<backend>-fetch-partial-articles} is non-@code{nil}, Gnus will
+fetch partial articles, if the backend it fetches them from supports
+it.  Currently only @code{nnimap} does.  If you're looking at a
+partial article, and want to see the complete article instead, then
+the @kbd{A C} command (@code{gnus-summary-show-complete-article}) will
+do so.
+
+@end table
+
+
+@node Summary Sorting
+@section Summary Sorting
+@cindex summary sorting
+
+You can have the summary buffer sorted in various ways, even though I
+can't really see why you'd want that.
+
+@table @kbd
+
+@item C-c C-s C-n
+@kindex C-c C-s C-n (Summary)
+@findex gnus-summary-sort-by-number
+Sort by article number (@code{gnus-summary-sort-by-number}).
+
+@item C-c C-s C-m C-n
+@kindex C-c C-s C-n (Summary)
+@findex gnus-summary-sort-by-most-recent-number
+Sort by most recent article number
+(@code{gnus-summary-sort-by-most-recent-number}).
+
+@item C-c C-s C-a
+@kindex C-c C-s C-a (Summary)
+@findex gnus-summary-sort-by-author
+Sort by author (@code{gnus-summary-sort-by-author}).
+
+@item C-c C-s C-t
+@kindex C-c C-s C-t (Summary)
+@findex gnus-summary-sort-by-recipient
+Sort by recipient (@code{gnus-summary-sort-by-recipient}).
+
+@item C-c C-s C-s
+@kindex C-c C-s C-s (Summary)
+@findex gnus-summary-sort-by-subject
+Sort by subject (@code{gnus-summary-sort-by-subject}).
+
+@item C-c C-s C-d
+@kindex C-c C-s C-d (Summary)
+@findex gnus-summary-sort-by-date
+Sort by date (@code{gnus-summary-sort-by-date}).
+
+@item C-c C-s C-m C-d
+@kindex C-c C-s C-m C-d (Summary)
+@findex gnus-summary-sort-by-most-recent-date
+Sort by most recent date (@code{gnus-summary-sort-by-most-recent-date}).
+
+@item C-c C-s C-l
+@kindex C-c C-s C-l (Summary)
+@findex gnus-summary-sort-by-lines
+Sort by lines (@code{gnus-summary-sort-by-lines}).
+
+@item C-c C-s C-c
+@kindex C-c C-s C-c (Summary)
+@findex gnus-summary-sort-by-chars
+Sort by article length (@code{gnus-summary-sort-by-chars}).
+
+@item C-c C-s C-i
+@kindex C-c C-s C-i (Summary)
+@findex gnus-summary-sort-by-score
+Sort by score (@code{gnus-summary-sort-by-score}).
+
+@item C-c C-s C-r
+@kindex C-c C-s C-r (Summary)
+@findex gnus-summary-sort-by-random
+Randomize (@code{gnus-summary-sort-by-random}).
+
+@item C-c C-s C-o
+@kindex C-c C-s C-o (Summary)
+@findex gnus-summary-sort-by-original
+Sort using the default sorting method
+(@code{gnus-summary-sort-by-original}).
+@end table
+
+These functions will work both when you use threading and when you don't
+use threading.  In the latter case, all summary lines will be sorted,
+line by line.  In the former case, sorting will be done on a
+root-by-root basis, which might not be what you were looking for.  To
+toggle whether to use threading, type @kbd{T T} (@pxref{Thread
+Commands}).
+
+If a prefix argument if given, the sort order is reversed.
+
+
+@node Finding the Parent
+@section Finding the Parent
+@cindex parent articles
+@cindex referring articles
+
+@table @kbd
+@item ^
+@kindex ^ (Summary)
+@findex gnus-summary-refer-parent-article
+If you'd like to read the parent of the current article, and it is not
+displayed in the summary buffer, you might still be able to.  That is,
+if the current group is fetched by @acronym{NNTP}, the parent hasn't expired
+and the @code{References} in the current article are not mangled, you
+can just press @kbd{^} or @kbd{A r}
+(@code{gnus-summary-refer-parent-article}).  If everything goes well,
+you'll get the parent.  If the parent is already displayed in the
+summary buffer, point will just move to this article.
+
+If given a positive numerical prefix, fetch that many articles back into
+the ancestry.  If given a negative numerical prefix, fetch just that
+ancestor.  So if you say @kbd{3 ^}, Gnus will fetch the parent, the
+grandparent and the great-grandparent of the current article.  If you say
+@kbd{-3 ^}, Gnus will only fetch the great-grandparent of the current
+article.
+
+@item A R (Summary)
+@findex gnus-summary-refer-references
+@kindex A R (Summary)
+Fetch all articles mentioned in the @code{References} header of the
+article (@code{gnus-summary-refer-references}).
+
+@item A T (Summary)
+@findex gnus-summary-refer-thread
+@kindex A T (Summary)
+Display the full thread where the current article appears
+(@code{gnus-summary-refer-thread}).  This command has to fetch all the
+headers in the current group to work, so it usually takes a while.  If
+you do it often, you may consider setting @code{gnus-fetch-old-headers}
+to @code{invisible} (@pxref{Filling In Threads}).  This won't have any
+visible effects normally, but it'll make this command work a whole lot
+faster.  Of course, it'll make group entry somewhat slow.
+
+@vindex gnus-refer-thread-limit
+The @code{gnus-refer-thread-limit} variable says how many old (i.e.,
+articles before the first displayed in the current group) headers to
+fetch when doing this command.  The default is 200.  If @code{t}, all
+the available headers will be fetched.  This variable can be overridden
+by giving the @kbd{A T} command a numerical prefix.
+
+@item M-^ (Summary)
+@findex gnus-summary-refer-article
+@kindex M-^ (Summary)
+@cindex Message-ID
+@cindex fetching by Message-ID
+You can also ask Gnus for an arbitrary article, no matter what group it
+belongs to.  @kbd{M-^} (@code{gnus-summary-refer-article}) will ask you
+for a @code{Message-ID}, which is one of those long, hard-to-read
+thingies that look something like @samp{<38o6up$6f2@@hymir.ifi.uio.no>}.
+You have to get it all exactly right.  No fuzzy searches, I'm afraid.
+
+Gnus looks for the @code{Message-ID} in the headers that have already
+been fetched, but also tries all the select methods specified by
+@code{gnus-refer-article-method} if it is not found.
+@end table
+
+@vindex gnus-refer-article-method
+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 @acronym{NNTP} method.  It
+would, perhaps, be best if the @acronym{NNTP} server you consult is the one
+updating the spool you are reading from, but that's not really
+necessary.
+
+It can also be a list of select methods, as well as the special symbol
+@code{current}, which means to use the current select method.  If it
+is a list, Gnus will try all the methods in the list until it finds a
+match.
+
+Here's an example setting that will first try the current method, and
+then ask Google if that fails:
+
+@lisp
+(setq gnus-refer-article-method
+      '(current
+        (nnweb "google" (nnweb-type google))))
+@end lisp
+
+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},
+@code{nnbabyl}, @code{nnmaildir}, @code{nnml}, are able to locate
+articles from any groups, while @code{nnfolder}, and @code{nnimap} are
+only able to locate articles that have been posted to the current
+group.  @code{nnmh} does not support this at all.
+
+Fortunately, the special @code{nnregistry} back end is able to locate
+articles in any groups, regardless of their back end (@pxref{Registry
+Article Refer Method, fetching by @code{Message-ID} using the
+registry}).
+
+@node Alternative Approaches
+@section Alternative Approaches
+
+Different people like to read news using different methods.  This being
+Gnus, we offer a small selection of minor modes for the summary buffers.
+
+@menu
+* Pick and Read::               First mark articles and then read them.
+* Binary Groups::               Auto-decode all articles.
+@end menu
+
+
+@node Pick and Read
+@subsection Pick and Read
+@cindex pick and read
+
+Some newsreaders (like @code{nn} and, uhm, @code{Netnews} on VM/CMS) use
+a two-phased reading interface.  The user first marks in a summary
+buffer the articles she wants to read.  Then she starts reading the
+articles with just an article buffer displayed.
+
+@findex gnus-pick-mode
+@kindex M-x gnus-pick-mode
+Gnus provides a summary buffer minor mode that allows
+this---@code{gnus-pick-mode}.  This basically means that a few process
+mark commands become one-keystroke commands to allow easy marking, and
+it provides one additional command for switching to the summary buffer.
+
+Here are the available keystrokes when using pick mode:
+
+@table @kbd
+@item .
+@kindex . (Pick)
+@findex gnus-pick-article-or-thread
+Pick the article or thread on the current line
+(@code{gnus-pick-article-or-thread}).  If the variable
+@code{gnus-thread-hide-subtree} is true, then this key selects the
+entire thread when used at the first article of the thread.  Otherwise,
+it selects just the article.  If given a numerical prefix, go to that
+thread or article and pick it.  (The line number is normally displayed
+at the beginning of the summary pick lines.)
+
+@item SPACE
+@kindex SPACE (Pick)
+@findex gnus-pick-next-page
+Scroll the summary buffer up one page (@code{gnus-pick-next-page}).  If
+at the end of the buffer, start reading the picked articles.
+
+@item u
+@kindex u (Pick)
+@findex gnus-pick-unmark-article-or-thread.
+Unpick the thread or article
+(@code{gnus-pick-unmark-article-or-thread}).  If the variable
+@code{gnus-thread-hide-subtree} is true, then this key unpicks the
+thread if used at the first article of the thread.  Otherwise it unpicks
+just the article.  You can give this key a numerical prefix to unpick
+the thread or article at that line.
+
+@item RET
+@kindex RET (Pick)
+@findex gnus-pick-start-reading
+@vindex gnus-pick-display-summary
+Start reading the picked articles (@code{gnus-pick-start-reading}).  If
+given a prefix, mark all unpicked articles as read first.  If
+@code{gnus-pick-display-summary} is non-@code{nil}, the summary buffer
+will still be visible when you are reading.
+
+@end table
+
+All the normal summary mode commands are still available in the
+pick-mode, with the exception of @kbd{u}.  However @kbd{!} is available
+which is mapped to the same function
+@code{gnus-summary-tick-article-forward}.
+
+If this sounds like a good idea to you, you could say:
+
+@lisp
+(add-hook 'gnus-summary-mode-hook 'gnus-pick-mode)
+@end lisp
+
+@vindex gnus-pick-mode-hook
+@code{gnus-pick-mode-hook} is run in pick minor mode buffers.
+
+@vindex gnus-mark-unpicked-articles-as-read
+If @code{gnus-mark-unpicked-articles-as-read} is non-@code{nil}, mark
+all unpicked articles as read.  The default is @code{nil}.
+
+@vindex gnus-summary-pick-line-format
+The summary line format in pick mode is slightly different from the
+standard format.  At the beginning of each line the line number is
+displayed.  The pick mode line format is controlled by the
+@code{gnus-summary-pick-line-format} variable (@pxref{Formatting
+Variables}).  It accepts the same format specs that
+@code{gnus-summary-line-format} does (@pxref{Summary Buffer Lines}).
+
+
+@node Binary Groups
+@subsection Binary Groups
+@cindex binary groups
+
+@findex gnus-binary-mode
+@kindex M-x gnus-binary-mode
+If you spend much time in binary groups, you may grow tired of hitting
+@kbd{X u}, @kbd{n}, @kbd{RET} all the time.  @kbd{M-x gnus-binary-mode}
+is a minor mode for summary buffers that makes all ordinary Gnus article
+selection functions uudecode series of articles and display the result
+instead of just displaying the articles the normal way.
+
+@kindex g (Binary)
+@findex gnus-binary-show-article
+The only way, in fact, to see the actual articles is the @kbd{g}
+command, when you have turned on this mode
+(@code{gnus-binary-show-article}).
+
+@vindex gnus-binary-mode-hook
+@code{gnus-binary-mode-hook} is called in binary minor mode buffers.
+
+
+@node Tree Display
+@section Tree Display
+@cindex trees
+
+@vindex gnus-use-trees
+If you don't like the normal Gnus summary display, you might try setting
+@code{gnus-use-trees} to @code{t}.  This will create (by default) an
+additional @dfn{tree buffer}.  You can execute all summary mode commands
+in the tree buffer.
+
+There are a few variables to customize the tree display, of course:
+
+@table @code
+@item gnus-tree-mode-hook
+@vindex gnus-tree-mode-hook
+A hook called in all tree mode buffers.
+
+@item gnus-tree-mode-line-format
+@vindex gnus-tree-mode-line-format
+A format string for the mode bar in the tree mode buffers (@pxref{Mode
+Line Formatting}).  The default is @samp{Gnus: %%b %S %Z}.  For a list
+of valid specs, @pxref{Summary Buffer Mode Line}.
+
+@item gnus-selected-tree-face
+@vindex gnus-selected-tree-face
+Face used for highlighting the selected article in the tree buffer.  The
+default is @code{modeline}.
+
+@item gnus-tree-line-format
+@vindex gnus-tree-line-format
+A format string for the tree nodes.  The name is a bit of a misnomer,
+though---it doesn't define a line, but just the node.  The default value
+is @samp{%(%[%3,3n%]%)}, which displays the first three characters of
+the name of the poster.  It is vital that all nodes are of the same
+length, so you @emph{must} use @samp{%4,4n}-like specifiers.
+
+Valid specs are:
+
+@table @samp
+@item n
+The name of the poster.
+@item f
+The @code{From} header.
+@item N
+The number of the article.
+@item [
+The opening bracket.
+@item ]
+The closing bracket.
+@item s
+The subject.
+@end table
+
+@xref{Formatting Variables}.
+
+Variables related to the display are:
+
+@table @code
+@item gnus-tree-brackets
+@vindex gnus-tree-brackets
+This is used for differentiating between ``real'' articles and
+``sparse'' articles.  The format is
+@example
+((@var{real-open} . @var{real-close})
+ (@var{sparse-open} . @var{sparse-close})
+ (@var{dummy-open} . @var{dummy-close}))
+@end example
+and the default is @code{((?[ . ?]) (?( . ?)) (?@{ . ?@}) (?< . ?>))}.
+
+@item gnus-tree-parent-child-edges
+@vindex gnus-tree-parent-child-edges
+This is a list that contains the characters used for connecting parent
+nodes to their children.  The default is @code{(?- ?\\ ?|)}.
+
+@end table
+
+@item gnus-tree-minimize-window
+@vindex gnus-tree-minimize-window
+If this variable is non-@code{nil}, Gnus will try to keep the tree
+buffer as small as possible to allow more room for the other Gnus
+windows.  If this variable is a number, the tree buffer will never be
+higher than that number.  The default is @code{t}.  Note that if you
+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
+@findex gnus-generate-vertical-tree
+The function that actually generates the thread tree.  Two predefined
+functions are available: @code{gnus-generate-horizontal-tree} and
+@code{gnus-generate-vertical-tree} (which is the default).
+
+@end table
+
+Here's an example from a horizontal tree buffer:
+
+@example
+@{***@}-(***)-[odd]-[Gun]
+     |      \[Jan]
+     |      \[odd]-[Eri]
+     |      \(***)-[Eri]
+     |            \[odd]-[Paa]
+     \[Bjo]
+     \[Gun]
+     \[Gun]-[Jor]
+@end example
+
+Here's the same thread displayed in a vertical tree buffer:
+
+@example
+@group
+@{***@}
+  |--------------------------\-----\-----\
+(***)                         [Bjo] [Gun] [Gun]
+  |--\-----\-----\                          |
+[odd] [Jan] [odd] (***)                   [Jor]
+  |           |     |--\
+[Gun]       [Eri] [Eri] [odd]
+                          |
+                        [Paa]
+@end group
+@end example
+
+If you're using horizontal trees, it might be nice to display the trees
+side-by-side with the summary buffer.  You could add something like the
+following to your @file{~/.gnus.el} file:
+
+@lisp
+(setq gnus-use-trees t
+      gnus-generate-tree-function 'gnus-generate-horizontal-tree
+      gnus-tree-minimize-window nil)
+(gnus-add-configuration
+ '(article
+   (vertical 1.0
+             (horizontal 0.25
+                         (summary 0.75 point)
+                         (tree 1.0))
+             (article 1.0))))
+@end lisp
+
+@xref{Window Layout}.
+
+
+@node Mail Group Commands
+@section Mail Group Commands
+@cindex mail group commands
+
+Some commands only make sense in mail groups.  If these commands are
+invalid in the current group, they will raise a hell and let you know.
+
+All these commands (except the expiry and edit commands) use the
+process/prefix convention (@pxref{Process/Prefix}).
+
+@table @kbd
+
+@item B e
+@kindex B e (Summary)
+@findex gnus-summary-expire-articles
+@cindex expiring mail
+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 C-M-e
+@kindex B C-M-e (Summary)
+@findex gnus-summary-expire-articles-now
+@cindex expiring mail
+Delete all the expirable articles in the group
+(@code{gnus-summary-expire-articles-now}).  This means that @strong{all}
+articles eligible for expiry in the current group will
+disappear forever into that big @file{/dev/null} in the sky.
+
+@item B DEL
+@kindex B DEL (Summary)
+@cindex deleting mail
+@findex gnus-summary-delete-article
+@c @icon{gnus-summary-mail-delete}
+Delete the mail article.  This is ``delete'' as in ``delete it from your
+disk forever and ever, never to return again.'' Use with caution.
+(@code{gnus-summary-delete-article}).
+
+@item B m
+@kindex B m (Summary)
+@cindex move mail
+@findex gnus-summary-move-article
+@vindex gnus-preserve-marks
+Move the article from one mail group to another
+(@code{gnus-summary-move-article}).  Marks will be preserved if
+@code{gnus-preserve-marks} is non-@code{nil} (which is the default).
+
+@item B c
+@kindex B c (Summary)
+@cindex copy mail
+@findex gnus-summary-copy-article
+@c @icon{gnus-summary-mail-copy}
+Copy the article from one group (mail group or not) to a mail group
+(@code{gnus-summary-copy-article}).  Marks will be preserved if
+@code{gnus-preserve-marks} is non-@code{nil} (which is the default).
+
+@item B B
+@kindex B B (Summary)
+@cindex crosspost mail
+@findex gnus-summary-crosspost-article
+Crosspost the current article to some other group
+(@code{gnus-summary-crosspost-article}).  This will create a new copy of
+the article in the other group, and the Xref headers of the article will
+be properly updated.
+
+@item B i
+@kindex B i (Summary)
+@findex gnus-summary-import-article
+Import an arbitrary file into the current mail newsgroup
+(@code{gnus-summary-import-article}).  You will be prompted for a file
+name, a @code{From} header and a @code{Subject} header.
+
+@item B I
+@kindex B I (Summary)
+@findex gnus-summary-create-article
+Create an empty article in the current mail newsgroups
+(@code{gnus-summary-create-article}).  You will be prompted for a
+@code{From} header and a @code{Subject} header.
+
+@item B r
+@kindex B r (Summary)
+@findex gnus-summary-respool-article
+@vindex gnus-summary-respool-default-method
+Respool the mail article (@code{gnus-summary-respool-article}).
+@code{gnus-summary-respool-default-method} will be used as the default
+select method when respooling.  This variable is @code{nil} by default,
+which means that the current group select method will be used instead.
+Marks will be preserved if @code{gnus-preserve-marks} is non-@code{nil}
+(which is the default).
+
+@item B w
+@itemx e
+@kindex B w (Summary)
+@kindex e (Summary)
+@findex gnus-summary-edit-article
+@kindex C-c C-c (Article)
+@findex gnus-summary-edit-article-done
+Edit the current article (@code{gnus-summary-edit-article}).  To finish
+editing and make the changes permanent, type @kbd{C-c C-c}
+(@code{gnus-summary-edit-article-done}).  If you give a prefix to the
+@kbd{C-c C-c} command, Gnus won't re-highlight the article.
+
+@item B q
+@kindex B q (Summary)
+@findex gnus-summary-respool-query
+If you want to re-spool an article, you might be curious as to what group
+the article will end up in before you do the re-spooling.  This command
+will tell you (@code{gnus-summary-respool-query}).
+
+@item B t
+@kindex B t (Summary)
+@findex gnus-summary-respool-trace
+Similarly, this command will display all fancy splitting patterns used
+when respooling, if any (@code{gnus-summary-respool-trace}).
+
+@item B p
+@kindex B p (Summary)
+@findex gnus-summary-article-posted-p
+Some people have a tendency to send you ``courtesy'' copies when they
+follow up to articles you have posted.  These usually have a
+@code{Newsgroups} header in them, but not always.  This command
+(@code{gnus-summary-article-posted-p}) will try to fetch the current
+article from your news server (or rather, from
+@code{gnus-refer-article-method} or @code{gnus-select-method}) and will
+report back whether it found the article or not.  Even if it says that
+it didn't find the article, it may have been posted anyway---mail
+propagation is much faster than news propagation, and the news copy may
+just not have arrived yet.
+
+@item K E
+@kindex K E (Summary)
+@findex gnus-article-encrypt-body
+@vindex gnus-article-encrypt-protocol
+Encrypt the body of an article (@code{gnus-article-encrypt-body}).
+The body is encrypted with the encryption protocol specified by the
+variable @code{gnus-article-encrypt-protocol}.
+
+@end table
+
+@vindex gnus-move-split-methods
+@cindex moving articles
+If you move (or copy) articles regularly, you might wish to have Gnus
+suggest where to put the articles.  @code{gnus-move-split-methods} is a
+variable that uses the same syntax as @code{gnus-split-methods}
+(@pxref{Saving Articles}).  You may customize that variable to create
+suggestions you find reasonable.  (Note that
+@code{gnus-move-split-methods} uses group names where
+@code{gnus-split-methods} uses file names.)
+
+@lisp
+(setq gnus-move-split-methods
+      '(("^From:.*Lars Magne" "nnml:junk")
+        ("^Subject:.*gnus" "nnfolder:important")
+        (".*" "nnml:misc")))
+@end lisp
+
+
+@node Various Summary Stuff
+@section Various Summary Stuff
+
+@menu
+* 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
+@vindex gnus-summary-display-while-building
+@item gnus-summary-display-while-building
+If non-@code{nil}, show and update the summary buffer as it's being
+built.  If @code{t}, update the buffer after every line is inserted.
+If the value is an integer, @var{n}, update the display every @var{n}
+lines.  The default is @code{nil}.
+
+@vindex gnus-summary-display-arrow
+@item gnus-summary-display-arrow
+If non-@code{nil}, display an arrow in the fringe to indicate the
+current article.
+
+@vindex gnus-summary-mode-hook
+@item gnus-summary-mode-hook
+This hook is called when creating a summary mode buffer.
+
+@vindex gnus-summary-generate-hook
+@item gnus-summary-generate-hook
+This is called as the last thing before doing the threading and the
+generation of the summary buffer.  It's quite convenient for customizing
+the threading variables based on what data the newsgroup has.  This hook
+is called from the summary buffer after most summary buffer variables
+have been set.
+
+@vindex gnus-summary-prepare-hook
+@item gnus-summary-prepare-hook
+It is called after the summary buffer has been generated.  You might use
+it to, for instance, highlight lines or modify the look of the buffer in
+some other ungodly manner.  I don't care.
+
+@vindex gnus-summary-prepared-hook
+@item gnus-summary-prepared-hook
+A hook called as the very last thing after the summary buffer has been
+generated.
+
+@vindex gnus-summary-ignore-duplicates
+@item gnus-summary-ignore-duplicates
+When Gnus discovers two articles that have the same @code{Message-ID},
+it has to do something drastic.  No articles are allowed to have the
+same @code{Message-ID}, but this may happen when reading mail from some
+sources.  Gnus allows you to customize what happens with this variable.
+If it is @code{nil} (which is the default), Gnus will rename the
+@code{Message-ID} (for display purposes only) and display the article as
+any other article.  If this variable is @code{t}, it won't display the
+article---it'll be as if it never existed.
+
+@vindex gnus-alter-articles-to-read-function
+@item gnus-alter-articles-to-read-function
+This function, which takes two parameters (the group name and the list
+of articles to be selected), is called to allow the user to alter the
+list of articles to be selected.
+
+For instance, the following function adds the list of cached articles to
+the list in one particular group:
+
+@lisp
+(defun my-add-cached-articles (group articles)
+  (if (string= group "some.group")
+      (append gnus-newsgroup-cached articles)
+    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 expressions to be evalled (when the default
+values are not @code{nil}), that should be made global while the summary
+buffer is active.
+
+Note: The default expressions will be evaluated (using function
+@code{eval}) before assignment to the local variable rather than just
+assigned to it.  If the default expression is the symbol @code{global},
+that symbol will not be evaluated but the global value of the local
+variable will be used instead.
+
+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
+
+Also @pxref{Group Parameters}.
+
+@end table
+
+
+@node Summary Group Information
+@subsection Summary Group Information
+
+@table @kbd
+
+@item H d
+@kindex H d (Summary)
+@findex gnus-summary-describe-group
+Give a brief description of the current group
+(@code{gnus-summary-describe-group}).  If given a prefix, force
+rereading the description from the server.
+
+@item H h
+@kindex H h (Summary)
+@findex gnus-summary-describe-briefly
+Give an extremely brief description of the most important summary
+keystrokes (@code{gnus-summary-describe-briefly}).
+
+@item H i
+@kindex H i (Summary)
+@findex gnus-info-find-node
+Go to the Gnus info node (@code{gnus-info-find-node}).
+@end table
+
+
+@node Searching for Articles
+@subsection Searching for Articles
+
+@table @kbd
+
+@item M-s
+@kindex M-s (Summary)
+@findex gnus-summary-search-article-forward
+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 (raw) articles for a regexp
+(@code{gnus-summary-search-article-backward}).
+
+@item M-S
+@kindex M-S (Summary)
+@findex gnus-summary-repeat-search-article-forward
+Repeat the previous search forwards
+(@code{gnus-summary-repeat-search-article-forward}).
+
+@item M-R
+@kindex M-R (Summary)
+@findex gnus-summary-repeat-search-article-backward
+Repeat the previous search backwards
+(@code{gnus-summary-repeat-search-article-backward}).
+
+@item &
+@kindex & (Summary)
+@findex gnus-summary-execute-command
+This command will prompt you for a header, a regular expression to match
+on this field, and a command to be executed if the match is made
+(@code{gnus-summary-execute-command}).  If the header is an empty
+string, the match is done on the entire article.  If given a prefix,
+search backward instead.
+
+For instance, @kbd{& RET some.*string RET #} will put the process mark on
+all articles that have heads or bodies that match @samp{some.*string}.
+
+@item M-&
+@kindex M-& (Summary)
+@findex gnus-summary-universal-argument
+Perform any operation on all articles that have been marked with
+the process mark (@code{gnus-summary-universal-argument}).
+@end table
+
+@node Summary Generation Commands
+@subsection Summary Generation Commands
+
+@table @kbd
+
+@item Y g
+@kindex Y g (Summary)
+@findex gnus-summary-prepare
+Regenerate the current summary buffer (@code{gnus-summary-prepare}).
+
+@item Y c
+@kindex Y c (Summary)
+@findex gnus-summary-insert-cached-articles
+Pull all cached articles (for the current group) into the summary buffer
+(@code{gnus-summary-insert-cached-articles}).
+
+@item Y d
+@kindex Y d (Summary)
+@findex gnus-summary-insert-dormant-articles
+Pull all dormant articles (for the current group) into the summary buffer
+(@code{gnus-summary-insert-dormant-articles}).
+
+@item Y t
+@kindex Y t (Summary)
+@findex gnus-summary-insert-ticked-articles
+Pull all ticked articles (for the current group) into the summary buffer
+(@code{gnus-summary-insert-ticked-articles}).
+
+@end table
+
+
+@node Really Various Summary Commands
+@subsection Really Various Summary Commands
+
+@table @kbd
+
+@item A D
+@itemx C-d
+@kindex C-d (Summary)
+@kindex A D (Summary)
+@findex gnus-summary-enter-digest-group
+If the current article is a collection of other articles (for instance,
+a digest), you might use this command to enter a group based on the that
+article (@code{gnus-summary-enter-digest-group}).  Gnus will try to
+guess what article type is currently displayed unless you give a prefix
+to this command, which forces a ``digest'' interpretation.  Basically,
+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.
+
+@vindex gnus-auto-select-on-ephemeral-exit
+The variable @code{gnus-auto-select-on-ephemeral-exit} controls what
+article should be selected after exiting a digest group.  Valid values
+include:
+
+@table @code
+@item next
+Select the next article.
+
+@item next-unread
+Select the next unread article.
+
+@item next-noselect
+Move the cursor to the next article.  This is the default.
+
+@item next-unread-noselect
+Move the cursor to the next unread article.
+@end table
+
+If it has any other value or there is no next (unread) article, the
+article selected before entering to the digest group will appear.
+
+@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
+(@code{gnus-summary-read-document}).  It does this by opening several
+@code{nndoc} groups for each document, and then opening an
+@code{nnvirtual} group on top of these @code{nndoc} groups.  This
+command understands the process/prefix convention
+(@pxref{Process/Prefix}).
+
+@item C-t
+@kindex C-t (Summary)
+@findex gnus-summary-toggle-truncation
+Toggle truncation of summary lines
+(@code{gnus-summary-toggle-truncation}).  This will probably confuse the
+line centering function in the summary buffer, so it's not a good idea
+to have truncation switched off while reading articles.
+
+@item =
+@kindex = (Summary)
+@findex gnus-summary-expand-window
+Expand the summary buffer window (@code{gnus-summary-expand-window}).
+If given a prefix, force an @code{article} window configuration.
+
+@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 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}).
+
+@end table
+
+
+@node Exiting the Summary Buffer
+@section Exiting the Summary Buffer
+@cindex summary exit
+@cindex exiting groups
+
+Exiting from the summary buffer will normally update all info on the
+group and return you to the group buffer.
+
+@table @kbd
+
+@item Z Z
+@itemx Z Q
+@itemx q
+@kindex Z Z (Summary)
+@kindex Z Q (Summary)
+@kindex q (Summary)
+@findex gnus-summary-exit
+@vindex gnus-summary-exit-hook
+@vindex gnus-summary-prepare-exit-hook
+@vindex gnus-group-no-more-groups-hook
+@c @icon{gnus-summary-exit}
+Exit the current group and update all information on the group
+(@code{gnus-summary-exit}).  @code{gnus-summary-prepare-exit-hook} is
+called before doing much of the exiting, which calls
+@code{gnus-summary-expire-articles} by default.
+@code{gnus-summary-exit-hook} is called after finishing the exit
+process.  @code{gnus-group-no-more-groups-hook} is run when returning to
+group mode having no more (unread) groups.
+
+@item Z E
+@itemx Q
+@kindex Z E (Summary)
+@kindex Q (Summary)
+@findex gnus-summary-exit-no-update
+Exit the current group without updating any information on the group
+(@code{gnus-summary-exit-no-update}).
+
+@item Z c
+@itemx c
+@kindex Z c (Summary)
+@kindex c (Summary)
+@findex gnus-summary-catchup-and-exit
+@c @icon{gnus-summary-catchup-and-exit}
+Mark all unticked articles in the group as read and then exit
+(@code{gnus-summary-catchup-and-exit}).
+
+@item Z C
+@kindex Z C (Summary)
+@findex gnus-summary-catchup-all-and-exit
+Mark all articles, even the ticked ones, as read and then exit
+(@code{gnus-summary-catchup-all-and-exit}).
+
+@item Z n
+@kindex Z n (Summary)
+@findex gnus-summary-catchup-and-goto-next-group
+Mark all articles as read and go to the next group
+(@code{gnus-summary-catchup-and-goto-next-group}).
+
+@item Z p
+@kindex Z p (Summary)
+@findex gnus-summary-catchup-and-goto-prev-group
+Mark all articles as read and go to the previous group
+(@code{gnus-summary-catchup-and-goto-prev-group}).
+
+@item Z R
+@itemx C-x C-s
+@kindex Z R (Summary)
+@kindex C-x C-s (Summary)
+@findex gnus-summary-reselect-current-group
+Exit this group, and then enter it again
+(@code{gnus-summary-reselect-current-group}).  If given a prefix, select
+all articles, both read and unread.
+
+@item Z G
+@itemx M-g
+@kindex Z G (Summary)
+@kindex M-g (Summary)
+@findex gnus-summary-rescan-group
+@c @icon{gnus-summary-mail-get}
+Exit the group, check for new articles in the group, and select the
+group (@code{gnus-summary-rescan-group}).  If given a prefix, select all
+articles, both read and unread.
+
+@item Z N
+@kindex Z N (Summary)
+@findex gnus-summary-next-group
+Exit the group and go to the next group
+(@code{gnus-summary-next-group}).
+
+@item Z P
+@kindex Z P (Summary)
+@findex gnus-summary-prev-group
+Exit the group and go to the previous group
+(@code{gnus-summary-prev-group}).
+
+@item Z s
+@kindex Z s (Summary)
+@findex gnus-summary-save-newsrc
+Save the current number of read/marked articles in the dribble buffer
+and then save the dribble buffer (@code{gnus-summary-save-newsrc}).  If
+given a prefix, also save the @file{.newsrc} file(s).  Using this
+command will make exit without updating (the @kbd{Q} command) worthless.
+@end table
+
+@vindex gnus-exit-group-hook
+@code{gnus-exit-group-hook} is called when you exit the current group
+with an ``updating'' exit.  For instance @kbd{Q}
+(@code{gnus-summary-exit-no-update}) does not call this hook.
+
+@findex gnus-summary-wake-up-the-dead
+@findex gnus-dead-summary-mode
+@vindex gnus-kill-summary-on-exit
+If you're in the habit of exiting groups, and then changing your mind
+about it, you might set @code{gnus-kill-summary-on-exit} to @code{nil}.
+If you do that, Gnus won't kill the summary buffer when you exit it.
+(Quelle surprise!)  Instead it will change the name of the buffer to
+something like @file{*Dead Summary ... *} and install a minor mode
+called @code{gnus-dead-summary-mode}.  Now, if you switch back to this
+buffer, you'll find that all keys are mapped to a function called
+@code{gnus-summary-wake-up-the-dead}.  So tapping any keys in a dead
+summary buffer will result in a live, normal summary buffer.
+
+There will never be more than one dead summary buffer at any one time.
+
+@vindex gnus-use-cross-reference
+The data on the current group will be updated (which articles you have
+read, which articles you have replied to, etc.)@: when you exit the
+summary buffer.  If the @code{gnus-use-cross-reference} variable is
+@code{t} (which is the default), articles that are cross-referenced to
+this group and are marked as read, will also be marked as read in the
+other subscribed groups they were cross-posted to.  If this variable is
+neither @code{nil} nor @code{t}, the article will be marked as read in
+both subscribed and unsubscribed groups (@pxref{Crosspost Handling}).
+
+
+@node Crosspost Handling
+@section Crosspost Handling
+
+@cindex velveeta
+@cindex spamming
+Marking cross-posted articles as read ensures that you'll never have to
+read the same article more than once.  Unless, of course, somebody has
+posted it to several groups separately.  Posting the same article to
+several groups (not cross-posting) is called @dfn{spamming}, and you are
+by law required to send nasty-grams to anyone who perpetrates such a
+heinous crime.
+
+Remember: Cross-posting is kinda ok, but posting the same article
+separately to several groups is not.  Massive cross-posting (aka.
+@dfn{velveeta}) is to be avoided at all costs, and you can even use the
+@code{gnus-summary-mail-crosspost-complaint} command to complain about
+excessive crossposting (@pxref{Summary Mail Commands}).
+
+@cindex cross-posting
+@cindex Xref
+@cindex @acronym{NOV}
+One thing that may cause Gnus to not do the cross-posting thing
+correctly is if you use an @acronym{NNTP} server that supports @sc{xover}
+(which is very nice, because it speeds things up considerably) which
+does not include the @code{Xref} header in its @acronym{NOV} lines.  This is
+Evil, but all too common, alas, alack.  Gnus tries to Do The Right Thing
+even with @sc{xover} by registering the @code{Xref} lines of all
+articles you actually read, but if you kill the articles, or just mark
+them as read without reading them, Gnus will not get a chance to snoop
+the @code{Xref} lines out of these articles, and will be unable to use
+the cross reference mechanism.
+
+@cindex LIST overview.fmt
+@cindex overview.fmt
+To check whether your @acronym{NNTP} server includes the @code{Xref} header
+in its overview files, try @samp{telnet your.nntp.server nntp},
+@samp{MODE READER} on @code{inn} servers, and then say @samp{LIST
+overview.fmt}.  This may not work, but if it does, and the last line you
+get does not read @samp{Xref:full}, then you should shout and whine at
+your news admin until she includes the @code{Xref} header in the
+overview files.
+
+If you want Gnus to get the @code{Xref}s right all the time, you have to
+set @code{nntp-nov-is-evil} to @code{t}, which slows things down
+considerably.  Also @pxref{Slow/Expensive Connection}.
+
+C'est la vie.
+
+For an alternative approach, @pxref{Duplicate Suppression}.
+
+
+@node Duplicate Suppression
+@section Duplicate Suppression
+
+By default, Gnus tries to make sure that you don't have to read the same
+article more than once by utilizing the crossposting mechanism
+(@pxref{Crosspost Handling}).  However, that simple and efficient
+approach may not work satisfactory for some users for various
+reasons.
+
+@enumerate
+@item
+The @acronym{NNTP} server may fail to generate the @code{Xref} header.  This
+is evil and not very common.
+
+@item
+The @acronym{NNTP} server may fail to include the @code{Xref} header in the
+@file{.overview} data bases.  This is evil and all too common, alas.
+
+@item
+You may be reading the same group (or several related groups) from
+different @acronym{NNTP} servers.
+
+@item
+You may be getting mail that duplicates articles posted to groups.
+@end enumerate
+
+I'm sure there are other situations where @code{Xref} handling fails as
+well, but these four are the most common situations.
+
+If, and only if, @code{Xref} handling fails for you, then you may
+consider switching on @dfn{duplicate suppression}.  If you do so, Gnus
+will remember the @code{Message-ID}s of all articles you have read or
+otherwise marked as read, and then, as if by magic, mark them as read
+all subsequent times you see them---in @emph{all} groups.  Using this
+mechanism is quite likely to be somewhat inefficient, but not overly
+so.  It's certainly preferable to reading the same articles more than
+once.
+
+Duplicate suppression is not a very subtle instrument.  It's more like a
+sledge hammer than anything else.  It works in a very simple
+fashion---if you have marked an article as read, it adds this Message-ID
+to a cache.  The next time it sees this Message-ID, it will mark the
+article as read with the @samp{M} mark.  It doesn't care what group it
+saw the article in.
+
+@table @code
+@item gnus-suppress-duplicates
+@vindex gnus-suppress-duplicates
+If non-@code{nil}, suppress duplicates.
+
+@item gnus-save-duplicate-list
+@vindex gnus-save-duplicate-list
+If non-@code{nil}, save the list of duplicates to a file.  This will
+make startup and shutdown take longer, so the default is @code{nil}.
+However, this means that only duplicate articles read in a single Gnus
+session are suppressed.
+
+@item gnus-duplicate-list-length
+@vindex gnus-duplicate-list-length
+This variable says how many @code{Message-ID}s to keep in the duplicate
+suppression list.  The default is 10000.
+
+@item gnus-duplicate-file
+@vindex gnus-duplicate-file
+The name of the file to store the duplicate suppression list in.  The
+default is @file{~/News/suppression}.
+@end table
+
+If you have a tendency to stop and start Gnus often, setting
+@code{gnus-save-duplicate-list} to @code{t} is probably a good idea.  If
+you leave Gnus running for weeks on end, you may have it @code{nil}.  On
+the other hand, saving the list makes startup and shutdown much slower,
+so that means that if you stop and start Gnus often, you should set
+@code{gnus-save-duplicate-list} to @code{nil}.  Uhm.  I'll leave this up
+to you to figure out, I think.
+
+@node Security
+@section Security
+
+Gnus is able to verify signed messages or decrypt encrypted messages.
+The formats that are supported are @acronym{PGP}, @acronym{PGP/MIME}
+and @acronym{S/MIME}, however you need some external programs to get
+things to work:
+
+@enumerate
+@item
+To handle @acronym{PGP} and @acronym{PGP/MIME} messages, you have to
+install an OpenPGP implementation such as GnuPG@.  The Lisp interface
+to GnuPG included with Emacs is called EasyPG (@pxref{Top, ,EasyPG,
+epa, EasyPG Assistant user's manual}), but PGG (@pxref{Top, ,PGG, pgg,
+PGG Manual}), and Mailcrypt are also supported.
+
+@item
+To handle @acronym{S/MIME} message, you need to install OpenSSL@.  OpenSSL 0.9.6
+or newer is recommended.
+
+@end enumerate
+
+The variables that control security functionality on reading/composing
+messages include:
+
+@table @code
+@item mm-verify-option
+@vindex mm-verify-option
+Option of verifying signed parts.  @code{never}, not verify;
+@code{always}, always verify; @code{known}, only verify known
+protocols.  Otherwise, ask user.
+
+@item mm-decrypt-option
+@vindex mm-decrypt-option
+Option of decrypting encrypted parts.  @code{never}, no decryption;
+@code{always}, always decrypt; @code{known}, only decrypt known
+protocols.  Otherwise, ask user.
+
+@item mm-sign-option
+@vindex mm-sign-option
+Option of creating signed parts.  @code{nil}, use default signing
+keys; @code{guided}, ask user to select signing keys from the menu.
+
+@item mm-encrypt-option
+@vindex mm-encrypt-option
+Option of creating encrypted parts.  @code{nil}, use the first
+public-key matching the @samp{From:} header as the recipient;
+@code{guided}, ask user to select recipient keys from the menu.
+
+@item mml1991-use
+@vindex mml1991-use
+Symbol indicating elisp interface to OpenPGP implementation for
+@acronym{PGP} messages.  The default is @code{epg}, but @code{pgg},
+and @code{mailcrypt} are also supported although
+deprecated.  By default, Gnus uses the first available interface in
+this order.
+
+@item mml2015-use
+@vindex mml2015-use
+Symbol indicating elisp interface to OpenPGP implementation for
+@acronym{PGP/MIME} messages.  The default is @code{epg}, but
+@code{pgg}, and @code{mailcrypt} are also supported
+although deprecated.  By default, Gnus uses the first available
+interface in this order.
+
+@end table
+
+By default the buttons that display security information are not
+shown, because they clutter reading the actual e-mail.  You can type
+@kbd{K b} manually to display the information.  Use the
+@code{gnus-buttonized-mime-types} and
+@code{gnus-unbuttonized-mime-types} variables to control this
+permanently.  @ref{MIME Commands} for further details, and hints on
+how to customize these variables to always display security
+information.
+
+@cindex snarfing keys
+@cindex importing PGP keys
+@cindex PGP key ring import
+Snarfing OpenPGP keys (i.e., importing keys from articles into your
+key ring) is not supported explicitly through a menu item or command,
+rather Gnus do detect and label keys as @samp{application/pgp-keys},
+allowing you to specify whatever action you think is appropriate
+through the usual @acronym{MIME} infrastructure.  You can use a
+@file{~/.mailcap} entry (@pxref{mailcap, , mailcap, emacs-mime, The
+Emacs MIME Manual}) such as the following to import keys using GNU
+Privacy Guard when you click on the @acronym{MIME} button
+(@pxref{Using MIME}).
+
+@example
+application/pgp-keys; gpg --import --interactive --verbose; needsterminal
+@end example
+@noindent
+This happens to also be the default action defined in
+@code{mailcap-mime-data}.
+
+More information on how to set things for sending outgoing signed and
+encrypted messages up can be found in the message manual
+(@pxref{Security, ,Security, message, Message Manual}).
+
+@node Mailing List
+@section Mailing List
+@cindex mailing list
+@cindex RFC 2396
+
+@kindex A M (summary)
+@findex gnus-mailing-list-insinuate
+Gnus understands some mailing list fields of RFC 2369.  To enable it,
+add a @code{to-list} group parameter (@pxref{Group Parameters}),
+possibly using @kbd{A M} (@code{gnus-mailing-list-insinuate}) in the
+summary buffer.
+
+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-archive
+Browse the mailing list archive, if List-Archive field exists.
+
+@end table
+
+
+@node Article Buffer
+@chapter Article Buffer
+@cindex article buffer
+
+The articles are displayed in the article buffer, of which there is only
+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 @acronym{MIME} before reading them.
+* HTML::                        Reading @acronym{HTML} messages.
+* Customizing Articles::        Tailoring the look of the articles.
+* Article Keymap::              Keystrokes available in the article buffer.
+* Misc Article::                Other stuff.
+@end menu
+
+
+@node Hiding Headers
+@section Hiding Headers
+@cindex hiding headers
+@cindex deleting headers
+
+The top section of each article is the @dfn{head}.  (The rest is the
+@dfn{body}, but you may have guessed that already.)
+
+@vindex gnus-show-all-headers
+There is a lot of useful information in the head: the name of the person
+who wrote the article, the date it was written and the subject of the
+article.  That's well and nice, but there's also lots of information
+most people do not want to see---what systems the article has passed
+through before reaching you, the @code{Message-ID}, the
+@code{References}, etc.@: ad nauseam---and you'll probably want to get rid
+of some of those lines.  If you want to keep all those lines in the
+article buffer, you can set @code{gnus-show-all-headers} to @code{t}.
+
+Gnus provides you with two variables for sifting headers:
+
+@table @code
+
+@item gnus-visible-headers
+@vindex gnus-visible-headers
+If this variable is non-@code{nil}, it should be a regular expression
+that says what headers you wish to keep in the article buffer.  All
+headers that do not match this variable will be hidden.
+
+For instance, if you only want to see the name of the person who wrote
+the article and the subject, you'd say:
+
+@lisp
+(setq gnus-visible-headers "^From:\\|^Subject:")
+@end lisp
+
+This variable can also be a list of regexps to match headers to
+remain visible.
+
+@item gnus-ignored-headers
+@vindex gnus-ignored-headers
+This variable is the reverse of @code{gnus-visible-headers}.  If this
+variable is set (and @code{gnus-visible-headers} is @code{nil}), it
+should be a regular expression that matches all lines that you want to
+hide.  All lines that do not match this variable will remain visible.
+
+For instance, if you just want to get rid of the @code{References} line
+and the @code{Xref} line, you might say:
+
+@lisp
+(setq gnus-ignored-headers "^References:\\|^Xref:")
+@end lisp
+
+This variable can also be a list of regexps to match headers to
+be removed.
+
+Note that if @code{gnus-visible-headers} is non-@code{nil}, this
+variable will have no effect.
+
+@end table
+
+@vindex gnus-sorted-header-list
+Gnus can also sort the headers for you.  (It does this by default.)  You
+can control the sorting by setting the @code{gnus-sorted-header-list}
+variable.  It is a list of regular expressions that says in what order
+the headers are to be displayed.
+
+For instance, if you want the name of the author of the article first,
+and then the subject, you might say something like:
+
+@lisp
+(setq gnus-sorted-header-list '("^From:" "^Subject:"))
+@end lisp
+
+Any headers that are to remain visible, but are not listed in this
+variable, will be displayed in random order after all the headers listed in this variable.
+
+@findex gnus-article-hide-boring-headers
+@vindex gnus-boring-article-headers
+You can hide further boring headers by setting
+@code{gnus-treat-hide-boring-headers} to @code{head}.  What this function
+does depends on the @code{gnus-boring-article-headers} variable.  It's a
+list, but this list doesn't actually contain header names.  Instead it
+lists various @dfn{boring conditions} that Gnus can check and remove
+from sight.
+
+These conditions are:
+@table @code
+@item empty
+Remove all empty headers.
+@item followup-to
+Remove the @code{Followup-To} header if it is identical to the
+@code{Newsgroups} header.
+@item reply-to
+Remove the @code{Reply-To} header if it lists the same addresses as
+the @code{From} header, or if the @code{broken-reply-to} group
+parameter is set.
+@item newsgroups
+Remove the @code{Newsgroups} header if it only contains the current group
+name.
+@item to-address
+Remove the @code{To} header if it only contains the address identical to
+the current group's @code{to-address} parameter.
+@item to-list
+Remove the @code{To} header if it only contains the address identical to
+the current group's @code{to-list} parameter.
+@item cc-list
+Remove the @code{Cc} header if it only contains the address identical to
+the current group's @code{to-list} parameter.
+@item date
+Remove the @code{Date} header if the article is less than three days
+old.
+@item long-to
+Remove the @code{To} and/or @code{Cc} header if it is very long.
+@item many-to
+Remove all @code{To} and/or @code{Cc} headers if there are more than one.
+@end table
+
+To include these three elements, you could say something like:
+
+@lisp
+(setq gnus-boring-article-headers
+      '(empty followup-to reply-to))
+@end lisp
+
+This is also the default value for this variable.
+
+
+@node Using MIME
+@section Using MIME
+@cindex @acronym{MIME}
+
+Mime is a standard for waving your hands through the air, aimlessly,
+while people stand around yawning.
+
+@acronym{MIME}, however, is a standard for encoding your articles, aimlessly,
+while all newsreaders die of fear.
+
+@acronym{MIME} may specify what character set the article uses, the encoding
+of the characters, and it also makes it possible to embed pictures and
+other naughty stuff in innocent-looking articles.
+
+@vindex gnus-display-mime-function
+@findex gnus-display-mime
+Gnus pushes @acronym{MIME} articles through @code{gnus-display-mime-function}
+to display the @acronym{MIME} parts.  This is @code{gnus-display-mime} by
+default, which creates a bundle of clickable buttons that can be used to
+display, save and manipulate the @acronym{MIME} objects.
+
+The following commands are available when you have placed point over a
+@acronym{MIME} button:
+
+@table @kbd
+@findex gnus-article-press-button
+@item RET (Article)
+@kindex RET (Article)
+@itemx BUTTON-2 (Article)
+Toggle displaying of the @acronym{MIME} object
+(@code{gnus-article-press-button}).  If built-in viewers can not display
+the object, Gnus resorts to external viewers in the @file{mailcap}
+files.  If a viewer has the @samp{copiousoutput} specification, the
+object is displayed inline.
+
+@findex gnus-mime-view-part
+@item M-RET (Article)
+@kindex M-RET (Article)
+@itemx v (Article)
+Prompt for a method, and then view the @acronym{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 @acronym{MIME} object as if it were a different @acronym{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 @acronym{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 @acronym{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 @acronym{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 @acronym{MIME} object will be referred via the
+message/external-body @acronym{MIME} type.
+(@code{gnus-mime-save-part-and-strip}).
+
+@findex gnus-mime-replace-part
+@item r (Article)
+@kindex r (Article)
+Prompt for a file name, replace the @acronym{MIME} object with an
+external body referring to the file via the message/external-body
+@acronym{MIME} type.  (@code{gnus-mime-replace-part}).
+
+@findex gnus-mime-delete-part
+@item d (Article)
+@kindex d (Article)
+Delete the @acronym{MIME} object from the article and replace it with some
+information about the removed @acronym{MIME} object
+(@code{gnus-mime-delete-part}).
+
+@c FIXME: gnus-auto-select-part should be documented here
+
+@findex gnus-mime-copy-part
+@item c (Article)
+@kindex c (Article)
+Copy the @acronym{MIME} object to a fresh buffer and display this buffer
+(@code{gnus-mime-copy-part}).  If given a prefix, copy the raw contents
+without decoding.  If given a numerical prefix, you can do semi-manual
+charset stuff (see @code{gnus-summary-show-article-charset-alist} in
+@ref{Paging the Article}).  Compressed files like @file{.gz} and
+@file{.bz2} are automatically decompressed if
+@code{auto-compression-mode} is enabled (@pxref{Compressed Files,,
+Accessing Compressed Files, emacs, The Emacs Editor}).
+
+@findex gnus-mime-print-part
+@item p (Article)
+@kindex p (Article)
+Print the @acronym{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 @acronym{MIME} object into the buffer
+(@code{gnus-mime-inline-part}) as @samp{text/plain}.  If given a prefix, insert
+the raw contents without decoding.  If given a numerical prefix, you can
+do semi-manual charset stuff (see
+@code{gnus-summary-show-article-charset-alist} in @ref{Paging the
+Article}).  Compressed files like @file{.gz} and @file{.bz2} are
+automatically decompressed depending on @code{jka-compr} regardless of
+@code{auto-compression-mode} (@pxref{Compressed Files,, Accessing
+Compressed Files, emacs, The Emacs Editor}).
+
+@findex gnus-mime-view-part-internally
+@item E (Article)
+@kindex E (Article)
+View the @acronym{MIME} object with an internal viewer.  If no internal
+viewer is available, use an external viewer
+(@code{gnus-mime-view-part-internally}).
+
+@findex gnus-mime-view-part-externally
+@item e (Article)
+@kindex e (Article)
+View the @acronym{MIME} object with an external viewer.
+(@code{gnus-mime-view-part-externally}).
+
+@findex gnus-mime-pipe-part
+@item | (Article)
+@kindex | (Article)
+Output the @acronym{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 @acronym{MIME} object
+(@code{gnus-mime-action-on-part}).
+
+@end table
+
+Gnus will display some @acronym{MIME} objects automatically.  The way Gnus
+determines which parts to do this with is described in the Emacs
+@acronym{MIME} manual.
+
+It might be best to just use the toggling functions from the article
+buffer to avoid getting nasty surprises.  (For instance, you enter the
+group @samp{alt.sing-a-long} and, before you know it, @acronym{MIME} has
+decoded the sound file in the article and some horrible sing-a-long song
+comes screaming out your speakers, and you can't find the volume button,
+because there isn't one, and people are starting to look at you, and you
+try to stop the program, but you can't, and you can't find the program
+to control the volume, and everybody else in the room suddenly decides
+to look at you disdainfully, and you'll feel rather stupid.)
+
+Any similarity to real events and people is purely coincidental.  Ahem.
+
+Also @pxref{MIME Commands}.
+
+
+@node HTML
+@section @acronym{HTML}
+@cindex @acronym{HTML}
+
+Gnus can display @acronym{HTML} articles nicely formatted in the
+article buffer.  There are many methods for doing that, but two of
+them are kind of default methods.
+
+If your Emacs copy has been built with libxml2 support, then Gnus uses
+Emacs' built-in, plain elisp Simple HTML Renderer @code{shr}
+@footnote{@code{shr} displays colors as declared in the @acronym{HTML}
+article but tries to adjust them in order to be readable.  If you
+prefer more contrast, @xref{FAQ 4-16}.} which is also used by Emacs'
+browser EWW (@pxref{EWW, ,EWW, emacs, The Emacs Manual}).
+
+If your Emacs copy lacks libxml2 support but you have @code{w3m}
+installed on your system, Gnus uses that to render @acronym{HTML} mail
+and display the results in the article buffer (@code{gnus-w3m}).
+
+For a complete overview, consult @xref{Display Customization, ,Display
+Customization, emacs-mime, The Emacs MIME Manual}.  This section only
+describes the default method.
+
+@table @code
+@item mm-text-html-renderer
+@vindex mm-text-html-renderer
+If set to @code{shr}, Gnus uses its own simple @acronym{HTML}
+renderer.  If set to @code{gnus-w3m}, it uses @code{w3m}.
+
+@item gnus-blocked-images
+@vindex gnus-blocked-images
+External images that have @acronym{URL}s that match this regexp won't
+be fetched and displayed.  For instance, do block all @acronym{URL}s
+that have the string ``ads'' in them, do the following:
+
+@lisp
+(setq gnus-blocked-images "ads")
+@end lisp
+
+This can also be a function to be evaluated.  If so, it will be
+called with the group name as the parameter.  The default value is
+@code{gnus-block-private-groups}, which will return @samp{"."} for
+anything that isn't a newsgroup.  This means that no external images
+will be fetched as a result of reading mail, so that nobody can use
+web bugs (and the like) to track whether you've read email.
+
+Also @pxref{Misc Article} for @code{gnus-inhibit-images}.
+
+@item gnus-html-cache-directory
+@vindex gnus-html-cache-directory
+Gnus will download and cache images according to how
+@code{gnus-blocked-images} is set.  These images will be stored in
+this directory.
+
+@item gnus-html-cache-size
+@vindex gnus-html-cache-size
+When @code{gnus-html-cache-size} bytes have been used in that
+directory, the oldest files will be deleted.  The default is 500MB.
+
+@item gnus-html-frame-width
+@vindex gnus-html-frame-width
+The width to use when rendering HTML@.  The default is 70.
+
+@item gnus-max-image-proportion
+@vindex gnus-max-image-proportion
+How big pictures displayed are in relation to the window they're in.
+A value of 0.7 (the default) means that they are allowed to take up
+70% of the width and height of the window.  If they are larger than
+this, and Emacs supports it, then the images will be rescaled down to
+fit these criteria.
+
+@end table
+
+To use this, make sure that you have @code{w3m} and @code{curl}
+installed.  If you have, then Gnus should display @acronym{HTML}
+automatically.
+
+
+
+@node Customizing Articles
+@section Customizing Articles
+@cindex article customization
+
+A slew of functions for customizing how the articles are to look like
+exist.  You can call these functions interactively
+(@pxref{Article Washing}), or you can have them
+called automatically when you select the articles.
+
+To have them called automatically, you should set the corresponding
+``treatment'' variable.  For instance, to have headers hidden, you'd set
+@code{gnus-treat-hide-headers}.  Below is a list of variables that can
+be set, but first we discuss the values these variables can have.
+
+Note: Some values, while valid, make little sense.  Check the list below
+for sensible values.
+
+@enumerate
+@item
+@code{nil}: Don't do this treatment.
+
+@item
+@code{t}: Do this treatment on all body parts.
+
+@item
+@code{head}: Do the treatment on the headers.
+
+@item
+@code{first}: Do this treatment on the first body part.
+
+@item
+@code{last}: Do this treatment on the last body part.
+
+@item
+An integer: Do this treatment on all body parts that have a length less
+than this number.
+
+@item
+A list of strings: Do this treatment on all body parts that are in
+articles that are read in groups that have names that match one of the
+regexps in the list.
+
+@item
+A list where the first element is not a string:
+
+The list is evaluated recursively.  The first element of the list is a
+predicate.  The following predicates are recognized: @code{or},
+@code{and}, @code{not} and @code{typep}.  Here's an example:
+
+@lisp
+(or last
+    (typep "text/x-vcard"))
+@end lisp
+
+@item
+A function: the function is called with no arguments and should return
+@code{nil} or non-@code{nil}.  The current article is available in the
+buffer named by @code{gnus-article-buffer}.
+
+@end enumerate
+
+You may have noticed that the word @dfn{part} is used here.  This refers
+to the fact that some messages are @acronym{MIME} multipart articles that may
+be divided into several parts.  Articles that are not multiparts are
+considered to contain just a single part.
+
+@vindex gnus-article-treat-types
+Are the treatments applied to all sorts of multipart parts?  Yes, if you
+want to, but by default, only @samp{text/plain} parts are given the
+treatment.  This is controlled by the @code{gnus-article-treat-types}
+variable, which is a list of regular expressions that are matched to the
+type of the part.  This variable is ignored if the value of the
+controlling variable is a predicate list, as described above.
+
+@ifinfo
+@c Avoid sort of redundant entries in the same section for the printed
+@c manual, but add them in info to allow 'i gnus-treat-foo-bar RET' or
+@c 'i foo-bar'.
+@vindex gnus-treat-buttonize
+@vindex gnus-treat-buttonize-head
+@vindex gnus-treat-capitalize-sentences
+@vindex gnus-treat-overstrike
+@vindex gnus-treat-strip-cr
+@vindex gnus-treat-strip-headers-in-body
+@vindex gnus-treat-strip-leading-blank-lines
+@vindex gnus-treat-strip-multiple-blank-lines
+@vindex gnus-treat-strip-pem
+@vindex gnus-treat-strip-trailing-blank-lines
+@vindex gnus-treat-unsplit-urls
+@vindex gnus-treat-wash-html
+@vindex gnus-treat-date
+@vindex gnus-treat-from-picon
+@vindex gnus-treat-mail-picon
+@vindex gnus-treat-newsgroups-picon
+@vindex gnus-treat-from-gravatar
+@vindex gnus-treat-mail-gravatar
+@vindex gnus-treat-display-smileys
+@vindex gnus-treat-body-boundary
+@vindex gnus-treat-display-x-face
+@vindex gnus-treat-display-face
+@vindex gnus-treat-emphasize
+@vindex gnus-treat-fill-article
+@vindex gnus-treat-fill-long-lines
+@vindex gnus-treat-hide-boring-headers
+@vindex gnus-treat-hide-citation
+@vindex gnus-treat-hide-citation-maybe
+@vindex gnus-treat-hide-headers
+@vindex gnus-treat-hide-signature
+@vindex gnus-treat-strip-banner
+@vindex gnus-treat-strip-list-identifiers
+@vindex gnus-treat-highlight-citation
+@vindex gnus-treat-highlight-headers
+@vindex gnus-treat-highlight-signature
+@vindex gnus-treat-play-sounds
+@vindex gnus-treat-x-pgp-sig
+@vindex gnus-treat-unfold-headers
+@vindex gnus-treat-fold-headers
+@vindex gnus-treat-fold-newsgroups
+@vindex gnus-treat-leading-whitespace
+@end ifinfo
+
+The following treatment options are available.  The easiest way to
+customize this is to examine the @code{gnus-article-treat} customization
+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-buttonize (t, integer)
+@item gnus-treat-buttonize-head (head)
+
+@xref{Article Buttons}.
+
+@item gnus-treat-capitalize-sentences (t, integer)
+@item gnus-treat-overstrike (t, integer)
+@item gnus-treat-strip-cr (t, integer)
+@item gnus-treat-strip-headers-in-body (t, integer)
+@item gnus-treat-strip-leading-blank-lines (t, first, integer)
+@item gnus-treat-strip-multiple-blank-lines (t, integer)
+@item gnus-treat-strip-pem (t, last, integer)
+@item gnus-treat-strip-trailing-blank-lines (t, last, integer)
+@item gnus-treat-unsplit-urls (t, integer)
+@item gnus-treat-wash-html (t, integer)
+
+@xref{Article Washing}.
+
+@item gnus-treat-date (head)
+
+This will transform/add date headers according to the
+@code{gnus-article-date-headers} variable.  This is a list of Date
+headers to display.  The formats available are:
+
+@table @code
+@item ut
+Universal time, aka GMT, aka ZULU.
+
+@item local
+The user's local time zone.
+
+@item english
+A semi-readable English sentence.
+
+@item lapsed
+The time elapsed since the message was posted.
+
+@item combined-lapsed
+Both the original date header and a (shortened) elapsed time.
+
+@item original
+The original date header.
+
+@item iso8601
+ISO8601 format, i.e., ``2010-11-23T22:05:21''.
+
+@item user-defined
+A format done according to the @code{gnus-article-time-format}
+variable.
+
+@end table
+
+@xref{Article Date}.
+
+@item gnus-treat-from-picon (head)
+@item gnus-treat-mail-picon (head)
+@item gnus-treat-newsgroups-picon (head)
+
+@xref{Picons}.
+
+@item gnus-treat-from-gravatar (head)
+@item gnus-treat-mail-gravatar (head)
+
+@xref{Gravatars}.
+
+@item gnus-treat-display-smileys (t, integer)
+
+@item gnus-treat-body-boundary (head)
+
+@vindex gnus-body-boundary-delimiter
+Adds a delimiter between header and body, the string used as delimiter
+is controlled by @code{gnus-body-boundary-delimiter}.
+
+@xref{Smileys}.
+
+@vindex gnus-treat-display-x-face
+@item gnus-treat-display-x-face (head)
+
+@xref{X-Face}.
+
+@vindex gnus-treat-display-face
+@item gnus-treat-display-face (head)
+
+@xref{Face}.
+
+@vindex gnus-treat-emphasize
+@item gnus-treat-emphasize (t, head, integer)
+@vindex gnus-treat-fill-article
+@item gnus-treat-fill-article (t, integer)
+@vindex gnus-treat-fill-long-lines
+@item gnus-treat-fill-long-lines (t, integer)
+@vindex gnus-treat-hide-boring-headers
+@item gnus-treat-hide-boring-headers (head)
+@vindex gnus-treat-hide-citation
+@item gnus-treat-hide-citation (t, integer)
+@vindex gnus-treat-hide-citation-maybe
+@item gnus-treat-hide-citation-maybe (t, integer)
+@vindex gnus-treat-hide-headers
+@item gnus-treat-hide-headers (head)
+@vindex gnus-treat-hide-signature
+@item gnus-treat-hide-signature (t, last)
+@vindex gnus-treat-strip-banner
+@item gnus-treat-strip-banner (t, last)
+@vindex gnus-treat-strip-list-identifiers
+@item gnus-treat-strip-list-identifiers (head)
+
+@xref{Article Hiding}.
+
+@vindex gnus-treat-highlight-citation
+@item gnus-treat-highlight-citation (t, integer)
+@vindex gnus-treat-highlight-headers
+@item gnus-treat-highlight-headers (head)
+@vindex gnus-treat-highlight-signature
+@item gnus-treat-highlight-signature (t, last, integer)
+
+@xref{Article Highlighting}.
+
+@vindex gnus-treat-play-sounds
+@item gnus-treat-play-sounds
+@item gnus-treat-ansi-sequences (t)
+@vindex gnus-treat-x-pgp-sig
+@item gnus-treat-x-pgp-sig (head)
+
+@vindex gnus-treat-unfold-headers
+@item gnus-treat-unfold-headers (head)
+@vindex gnus-treat-fold-headers
+@item gnus-treat-fold-headers (head)
+@vindex gnus-treat-fold-newsgroups
+@item gnus-treat-fold-newsgroups (head)
+@vindex gnus-treat-leading-whitespace
+@item gnus-treat-leading-whitespace (head)
+
+@xref{Article Header}.
+
+
+@end table
+
+@vindex gnus-part-display-hook
+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.
+
+
+@node Article Keymap
+@section Article Keymap
+
+Most of the keystrokes in the summary buffer can also be used in the
+article buffer.  They should behave as if you typed them in the summary
+buffer, which means that you don't actually have to have a summary
+buffer displayed while reading.  You can do it all from the article
+buffer.
+
+@kindex v (Article)
+@cindex keys, reserved for users (Article)
+The key @kbd{v} is reserved for users.  You can bind it to some
+command or better use it as a prefix key.
+
+A few additional keystrokes are available:
+
+@table @kbd
+
+@item SPACE
+@kindex SPACE (Article)
+@findex gnus-article-next-page
+Scroll forwards one page (@code{gnus-article-next-page}).
+This is exactly the same as @kbd{h SPACE h}.
+
+@item DEL
+@kindex DEL (Article)
+@findex gnus-article-prev-page
+Scroll backwards one page (@code{gnus-article-prev-page}).
+This is exactly the same as @kbd{h DEL h}.
+
+@item C-c ^
+@kindex C-c ^ (Article)
+@findex gnus-article-refer-article
+If point is in the neighborhood of a @code{Message-ID} and you press
+@kbd{C-c ^}, Gnus will try to get that article from the server
+(@code{gnus-article-refer-article}).
+
+@item C-c C-m
+@kindex C-c C-m (Article)
+@findex gnus-article-mail
+Send a reply to the address near point (@code{gnus-article-mail}).  If
+given a prefix, include the mail.
+
+@item s
+@kindex s (Article)
+@findex gnus-article-show-summary
+Reconfigure the buffers so that the summary buffer becomes visible
+(@code{gnus-article-show-summary}).
+
+@item ?
+@kindex ? (Article)
+@findex gnus-article-describe-briefly
+Give a very brief description of the available keystrokes
+(@code{gnus-article-describe-briefly}).
+
+@item TAB
+@kindex TAB (Article)
+@findex gnus-article-next-button
+Go to the next button, if any (@code{gnus-article-next-button}).  This
+only makes sense if you have buttonizing turned on.
+
+@item M-TAB
+@kindex M-TAB (Article)
+@findex gnus-article-prev-button
+Go to the previous button, if any (@code{gnus-article-prev-button}).
+
+@item R
+@kindex R (Article)
+@findex gnus-article-reply-with-original
+Send a reply to the current article and yank the current article
+(@code{gnus-article-reply-with-original}).  If the region is active,
+only yank the text in the region.
+
+@item S W
+@kindex S W (Article)
+@findex gnus-article-wide-reply-with-original
+Send a wide reply to the current article and yank the current article
+(@code{gnus-article-wide-reply-with-original}).  If the region is
+active, only yank the text in the region.
+
+@item F
+@kindex F (Article)
+@findex gnus-article-followup-with-original
+Send a followup to the current article and yank the current article
+(@code{gnus-article-followup-with-original}).  If the region is active,
+only yank the text in the region.
+
+
+@end table
+
+
+@node Misc Article
+@section Misc Article
+
+@table @code
+
+@item gnus-single-article-buffer
+@vindex gnus-single-article-buffer
+@cindex article buffers, several
+If non-@code{nil}, use the same article buffer for all the groups.
+(This is the default.)  If @code{nil}, each group will have its own
+article buffer.
+
+@item gnus-widen-article-window
+@cindex gnus-widen-article-window
+If non-@code{nil}, selecting the article buffer with the @kbd{h}
+command will ``widen'' the article window to take the entire frame.
+
+@vindex gnus-article-decode-hook
+@item gnus-article-decode-hook
+@cindex @acronym{MIME}
+Hook used to decode @acronym{MIME} articles.  The default value is
+@code{(article-decode-charset article-decode-encoded-words)}
+
+@vindex gnus-article-prepare-hook
+@item gnus-article-prepare-hook
+This hook is called right after the article has been inserted into the
+article buffer.  It is mainly intended for functions that do something
+depending on the contents; it should probably not be used for changing
+the contents of the article buffer.
+
+@item gnus-article-mode-hook
+@vindex gnus-article-mode-hook
+Hook called in article mode buffers.
+
+@item gnus-article-mode-syntax-table
+@vindex gnus-article-mode-syntax-table
+Syntax table used in article buffers.  It is initialized from
+@code{text-mode-syntax-table}.
+
+@vindex gnus-article-over-scroll
+@item gnus-article-over-scroll
+If non-@code{nil}, allow scrolling the article buffer even when there
+no more new text to scroll in.  The default is @code{nil}.
+
+@vindex gnus-article-mode-line-format
+@item gnus-article-mode-line-format
+This variable is a format string along the same lines as
+@code{gnus-summary-mode-line-format} (@pxref{Summary Buffer Mode
+Line}).  It 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.  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 emphasized strings in the article buffer.
+
+@end table
+
+@item m
+The number of @acronym{MIME} parts in the article.
+
+@end table
+
+@vindex gnus-break-pages
+
+@item gnus-break-pages
+Controls whether @dfn{page breaking} is to take place.  If this variable
+is non-@code{nil}, the articles will be divided into pages whenever a
+page delimiter appears in the article.  If this variable is @code{nil},
+paging will not be done.
+
+@item gnus-page-delimiter
+@vindex gnus-page-delimiter
+This is the delimiter mentioned above.  By default, it is @samp{^L}
+(formfeed).
+
+@cindex IDNA
+@cindex internationalized domain names
+@vindex gnus-use-idna
+@item gnus-use-idna
+This variable controls whether Gnus performs IDNA decoding of
+internationalized domain names inside @samp{From}, @samp{To} and
+@samp{Cc} headers.  @xref{IDNA, ,IDNA,message, The Message Manual},
+for how to compose such messages.  This requires
+@uref{http://www.gnu.org/software/libidn/, GNU Libidn}, and this
+variable is only enabled if you have installed it.
+
+@vindex gnus-inhibit-images
+@item gnus-inhibit-images
+If this is non-@code{nil}, inhibit displaying of images inline in the
+article body.  It is effective to images that are in articles as
+@acronym{MIME} parts, and images in @acronym{HTML} articles rendered
+when @code{mm-text-html-renderer} (@pxref{Display Customization,
+,Display Customization, emacs-mime, The Emacs MIME Manual}) is
+@code{shr} or @code{gnus-w3m}.
+
+@end table
+
+
+@node Composing Messages
+@chapter Composing Messages
+@cindex composing messages
+@cindex messages
+@cindex mail
+@cindex sending mail
+@cindex reply
+@cindex followup
+@cindex post
+@cindex using gpg
+@cindex using s/mime
+@cindex using smime
+
+@kindex C-c C-c (Post)
+All commands for posting and mailing will put you in a message buffer
+where you can edit the article all you like, before you send the
+article by pressing @kbd{C-c C-c}.  @xref{Top, , Overview, message,
+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 and mail via?
+* POP before SMTP::             You cannot send a mail unless you read a mail.
+* 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?
+* Signing and encrypting::      How to compose secure messages.
+@end menu
+
+Also @pxref{Canceling and Superseding} for information on how to
+remove articles you shouldn't have posted.
+
+
+@node Mail
+@section Mail
+
+Variables for customizing outgoing mail:
+
+@table @code
+@item gnus-uu-digest-headers
+@vindex gnus-uu-digest-headers
+List of regexps to match headers included in digested messages.  The
+headers will be included in the sequence they are matched.  If
+@code{nil} include all headers.
+
+@item gnus-add-to-list
+@vindex gnus-add-to-list
+If non-@code{nil}, add a @code{to-list} group parameter to mail groups
+that have none when you do a @kbd{a}.
+
+@item gnus-confirm-mail-reply-to-news
+@vindex gnus-confirm-mail-reply-to-news
+If non-@code{nil}, Gnus will ask you for a confirmation when you are
+about to reply to news articles by mail.  If it is @code{nil}, nothing
+interferes in what you want to do.  This can also be a function
+receiving the group name as the only parameter which should return
+non-@code{nil} if a confirmation is needed, or a regular expression
+matching group names, where confirmation should be asked for.
+
+If you find yourself never wanting to reply to mail, but occasionally
+press @kbd{R} anyway, this variable might be for you.
+
+@item gnus-confirm-treat-mail-like-news
+@vindex gnus-confirm-treat-mail-like-news
+If non-@code{nil}, Gnus also requests confirmation according to
+@code{gnus-confirm-mail-reply-to-news} when replying to mail.  This is
+useful for treating mailing lists like newsgroups.
+
+@end table
+
+
+@node Posting Server
+@section Posting Server
+
+When you press those magical @kbd{C-c C-c} keys to ship off your latest
+(extremely intelligent, of course) article, where does it go?
+
+Thank you for asking.  I hate you.
+
+It can be quite complicated.
+
+@vindex gnus-post-method
+When posting news, Message usually invokes @code{message-send-news}
+(@pxref{News Variables, , News Variables, message, Message Manual}).
+Normally, Gnus will post using the same select method as you're
+reading from (which might be convenient if you're reading lots of
+groups from different private servers).  However.  If the server
+you're reading from doesn't allow posting, just reading, you probably
+want to use some other server to post your (extremely intelligent and
+fabulously interesting) articles.  You can then set the
+@code{gnus-post-method} to some other method:
+
+@lisp
+(setq gnus-post-method '(nnspool ""))
+@end lisp
+
+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 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.
+
+You can also set @code{gnus-post-method} to a list of select methods.
+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{native}.
+
+@vindex message-send-mail-function
+When sending mail, Message invokes the function specified by the
+variable @code{message-send-mail-function}.  Gnus tries to set it to a
+value suitable for your system.
+@xref{Mail Variables, ,Mail Variables,message,Message manual}, for more
+information.
+
+
+@node POP before SMTP
+@section POP before SMTP
+@cindex pop before smtp
+@findex mail-source-touch-pop
+
+Does your @acronym{ISP} use @acronym{POP}-before-@acronym{SMTP}
+authentication?  This authentication method simply requires you to
+contact the @acronym{POP} server before sending email.  To do that,
+put the following lines in your @file{~/.gnus.el} file:
+
+@lisp
+(add-hook 'message-send-mail-hook 'mail-source-touch-pop)
+@end lisp
+
+@noindent
+The @code{mail-source-touch-pop} function does @acronym{POP}
+authentication according to the value of @code{mail-sources} without
+fetching mails, just before sending a mail.  @xref{Mail Sources}.
+
+If you have two or more @acronym{POP} mail servers set in
+@code{mail-sources}, you may want to specify one of them to
+@code{mail-source-primary-source} as the @acronym{POP} mail server to be
+used for the @acronym{POP}-before-@acronym{SMTP} authentication.  If it
+is your primary @acronym{POP} mail server (i.e., you are fetching mails
+mainly from that server), you can set it permanently as follows:
+
+@lisp
+(setq mail-source-primary-source
+      '(pop :server "pop3.mail.server"
+            :password "secret"))
+@end lisp
+
+@noindent
+Otherwise, bind it dynamically only when performing the
+@acronym{POP}-before-@acronym{SMTP} authentication as follows:
+
+@lisp
+(add-hook 'message-send-mail-hook
+          (lambda ()
+            (let ((mail-source-primary-source
+                   '(pop :server "pop3.mail.server"
+                         :password "secret")))
+              (mail-source-touch-pop))))
+@end lisp
+
+
+@node Mail and Post
+@section Mail and Post
+
+Here's a list of variables relevant to both mailing and
+posting:
+
+@table @code
+@item gnus-mailing-list-groups
+@findex gnus-mailing-list-groups
+@cindex mailing lists
+
+If your news server offers groups that are really mailing lists
+gatewayed to the @acronym{NNTP} server, you can read those groups without
+problems, but you can't post/followup to them without some difficulty.
+One solution is to add a @code{to-address} to the group parameters
+(@pxref{Group Parameters}).  An easier thing to do is set the
+@code{gnus-mailing-list-groups} to a regexp that matches the groups that
+really are mailing lists.  Then, at least, followups to the mailing
+lists will work most of the time.  Posting to these groups (@kbd{a}) is
+still a pain, though.
+
+@item gnus-user-agent
+@vindex gnus-user-agent
+@cindex User-Agent
+
+This variable controls which information should be exposed in the
+User-Agent header.  It can be a list of symbols or a string.  Valid
+symbols are @code{gnus} (show Gnus version) and @code{emacs} (show Emacs
+version).  In addition to the Emacs version, you can add @code{codename}
+(show (S)XEmacs codename) or either @code{config} (show system
+configuration) or @code{type} (show system type).  If you set it to a
+string, be sure to use a valid format, see RFC 2616.
+
+@end table
+
+You may want to do spell-checking on messages that you send out.  Or, if
+you don't want to spell-check by hand, you could add automatic
+spell-checking via the @code{ispell} package:
+
+@cindex ispell
+@findex ispell-message
+@lisp
+(add-hook 'message-send-hook 'ispell-message)
+@end lisp
+
+If you want to change the @code{ispell} dictionary based on what group
+you're in, you could say something like the following:
+
+@lisp
+(add-hook 'gnus-select-group-hook
+          (lambda ()
+            (cond
+             ((string-match
+               "^de\\." (gnus-group-real-name gnus-newsgroup-name))
+              (ispell-change-dictionary "deutsch"))
+             (t
+              (ispell-change-dictionary "english")))))
+@end lisp
+
+Modify to suit your needs.
+
+@vindex gnus-message-highlight-citation
+If @code{gnus-message-highlight-citation} is @code{t}, different levels of
+citations are highlighted like in Gnus article buffers also in message
+mode buffers.
+
+@node Archived Messages
+@section Archived Messages
+@cindex archived messages
+@cindex sent messages
+
+Gnus provides a few different methods for storing the mail and news you
+send.  The default method is to use the @dfn{archive virtual server} to
+store the messages.  If you want to disable this completely, the
+@code{gnus-message-archive-group} variable should be @code{nil}.  The
+default is @code{"sent.%Y-%m"}, which gives you one archive group per month.
+
+For archiving interesting messages in a group you read, see the
+@kbd{B c} (@code{gnus-summary-copy-article}) command (@pxref{Mail
+Group Commands}).
+
+@vindex gnus-message-archive-method
+@code{gnus-message-archive-method} says what virtual server Gnus is to
+use to store sent messages.  The default is @code{"archive"}, and when
+actually being used it is expanded into:
+
+@lisp
+(nnfolder "archive"
+          (nnfolder-directory   "~/Mail/archive")
+          (nnfolder-active-file "~/Mail/archive/active")
+          (nnfolder-get-new-mail nil)
+          (nnfolder-inhibit-expiry t))
+@end lisp
+
+@quotation
+@vindex gnus-update-message-archive-method
+Note: a server like this is saved in the @file{~/.newsrc.eld} file first
+so that it may be used as a real method of the server which is named
+@code{"archive"} (that is, for the case where
+@code{gnus-message-archive-method} is set to @code{"archive"}) ever
+since.  If it once has been saved, it will never be updated by default
+even if you change the value of @code{gnus-message-archive-method}
+afterward.  Therefore, the server @code{"archive"} doesn't necessarily
+mean the @code{nnfolder} server like this at all times.  If you want the
+saved method to reflect always the value of
+@code{gnus-message-archive-method}, set the
+@code{gnus-update-message-archive-method} variable to a non-@code{nil}
+value.  The default value of this variable is @code{nil}.
+@end quotation
+
+You can, however, use any mail select method (@code{nnml},
+@code{nnmbox}, etc.).  @code{nnfolder} is a quite likable select method
+for doing this sort of thing, though.  If you don't like the default
+directory chosen, you could say something like:
+
+@lisp
+(setq gnus-message-archive-method
+      '(nnfolder "archive"
+                 (nnfolder-inhibit-expiry t)
+                 (nnfolder-active-file "~/News/sent-mail/active")
+                 (nnfolder-directory "~/News/sent-mail/")))
+@end lisp
+
+@vindex gnus-message-archive-group
+@cindex Gcc
+Gnus will insert @code{Gcc} headers in all outgoing messages that point
+to one or more group(s) on that server.  Which group to use is
+determined by the @code{gnus-message-archive-group} variable.
+
+This variable can be used to do the following:
+
+@table @asis
+@item a string
+Messages will be saved in that group.
+
+Note that you can include a select method in the group name, then the
+message will not be stored in the select method given by
+@code{gnus-message-archive-method}, but in the select method specified
+by the group name, instead.  Suppose @code{gnus-message-archive-method}
+has the default value shown above.  Then setting
+@code{gnus-message-archive-group} to @code{"foo"} means that outgoing
+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
+Messages will be saved in all those groups.
+
+@item an alist of regexps, functions and forms
+When a key ``matches'', the result is used.
+
+@item @code{nil}
+No message archiving will take place.
+@end table
+
+Let's illustrate:
+
+Just saving to a single group called @samp{MisK}:
+@lisp
+(setq gnus-message-archive-group "MisK")
+@end lisp
+
+Saving to two groups, @samp{MisK} and @samp{safe}:
+@lisp
+(setq gnus-message-archive-group '("MisK" "safe"))
+@end lisp
+
+Save to different groups based on what group you are in:
+@lisp
+(setq gnus-message-archive-group
+      '(("^alt" "sent-to-alt")
+        ("mail" "sent-to-mail")
+        (".*" "sent-to-misc")))
+@end lisp
+
+More complex stuff:
+@lisp
+(setq gnus-message-archive-group
+      '((if (message-news-p)
+            "misc-news"
+          "misc-mail")))
+@end lisp
+
+How about storing all news messages in one file, but storing all mail
+messages in one file per month:
+
+@lisp
+(setq gnus-message-archive-group
+      '((if (message-news-p)
+            "misc-news"
+          (concat "mail." (format-time-string "%Y-%m")))))
+@end lisp
+
+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,
+you can just remove the @code{Gcc} header that has been inserted.)  The
+archive group will appear in the group buffer the next time you start
+Gnus, or the next time you press @kbd{F} in the group buffer.  You can
+enter it and read the articles in it just like you'd read any other
+group.  If the group gets really big and annoying, you can simply rename
+if (using @kbd{G r} in the group buffer) to something
+nice---@samp{misc-mail-september-1995}, or whatever.  New messages will
+continue to be stored in the old (now empty) group.
+
+@table @code
+@item gnus-gcc-mark-as-read
+@vindex gnus-gcc-mark-as-read
+If non-@code{nil}, automatically mark @code{Gcc} articles as read.
+
+@item gnus-gcc-externalize-attachments
+@vindex gnus-gcc-externalize-attachments
+If @code{nil}, attach files as normal parts in Gcc copies; if a regexp
+and matches the Gcc group name, attach files as external parts; if it is
+@code{all}, attach local files as external parts; if it is other
+non-@code{nil}, the behavior is the same as @code{all}, but it may be
+changed in the future.
+
+@item gnus-gcc-self-resent-messages
+@vindex gnus-gcc-self-resent-messages
+Like the @code{gcc-self} group parameter, applied only for unmodified
+messages that @code{gnus-summary-resend-message} (@pxref{Summary Mail
+Commands}) resends.  Non-@code{nil} value of this variable takes
+precedence over any existing @code{Gcc} header.
+
+If this is @code{none}, no @code{Gcc} copy will be made.  If this is
+@code{t}, messages resent will be @code{Gcc} copied to the current
+group.  If this is a string, it specifies a group to which resent
+messages will be @code{Gcc} copied.  If this is @code{nil}, @code{Gcc}
+will be done according to existing @code{Gcc} header(s), if any.  If
+this is @code{no-gcc-self}, that is the default, resent messages will be
+@code{Gcc} copied to groups that existing @code{Gcc} header specifies,
+except for the current group.
+
+@item gnus-gcc-pre-body-encode-hook
+@vindex gnus-gcc-pre-body-encode-hook
+@itemx gnus-gcc-post-body-encode-hook
+@vindex gnus-gcc-post-body-encode-hook
+
+These hooks are run before/after encoding the message body of the Gcc
+copy of a sent message.  The current buffer (when the hook is run)
+contains the message including the message header.  Changes made to
+the message will only affect the Gcc copy, but not the original
+message.  You can use these hooks to edit the copy (and influence
+subsequent transformations), e.g., remove MML secure tags
+(@pxref{Signing and encrypting}).
+
+@end table
+
+
+@node Posting Styles
+@section Posting Styles
+@cindex posting styles
+@cindex styles
+
+All them variables, they make my head swim.
+
+So what if you want a different @code{Organization} and signature based
+on what groups you post to?  And you post both from your home machine
+and your work machine, and you want different @code{From} lines, and so
+on?
+
+@vindex gnus-posting-styles
+One way to do stuff like that is to write clever hooks that change the
+variables you need to have changed.  That's a bit boring, so somebody
+came up with the bright idea of letting the user specify these things in
+a handy alist.  Here's an example of a @code{gnus-posting-styles}
+variable:
+
+@lisp
+((".*"
+  (signature "Peace and happiness")
+  (organization "What me?"))
+ ("^comp"
+  (signature "Death to everybody"))
+ ("comp.emacs.i-love-it"
+  (organization "Emacs is it")))
+@end lisp
+
+As you might surmise from this example, this alist consists of several
+@dfn{styles}.  Each style will be applicable if the first element
+``matches'', in some form or other.  The entire alist will be iterated
+over, from the beginning towards the end, and each match will be
+applied, which means that attributes in later styles that match override
+the same attributes in earlier matching styles.  So
+@samp{comp.programming.literate} will have the @samp{Death to everybody}
+signature and the @samp{What me?} @code{Organization} header.
+
+The first element in each style is called the @code{match}.  If it's a
+string, then Gnus will try to regexp match it against the group name.
+If it is the form @code{(header @var{match} @var{regexp})}, then Gnus
+will look in the original article for a header whose name is
+@var{match} and compare that @var{regexp}.  @var{match} and
+@var{regexp} are strings.  (The original article is the one you are
+replying or following up to.  If you are not composing a reply or a
+followup, then there is nothing to match against.)  If the
+@code{match} is a function symbol, that function will be called with
+no arguments.  If it's a variable symbol, then the variable will be
+referenced.  If it's a list, then that list will be @code{eval}ed.  In
+any case, if this returns a non-@code{nil} value, then the style is
+said to @dfn{match}.
+
+Each style may contain an arbitrary amount of @dfn{attributes}.  Each
+attribute consists of a @code{(@var{name} @var{value})} pair.  In
+addition, you can also use the @code{(@var{name} :file @var{value})}
+form or the @code{(@var{name} :value @var{value})} form.  Where
+@code{:file} signifies @var{value} represents a file name and its
+contents should be used as the attribute value, @code{:value} signifies
+@var{value} does not represent a file name explicitly.  The attribute
+name can be one of:
+
+@itemize @bullet
+@item @code{signature}
+@item @code{signature-file}
+@item @code{x-face-file}
+@item @code{address}, overriding @code{user-mail-address}
+@item @code{name}, overriding @code{(user-full-name)}
+@item @code{body}
+@end itemize
+
+Note that the @code{signature-file} attribute honors the variable
+@code{message-signature-directory}.
+
+The attribute name can also be a string or a symbol.  In that case,
+this will be used as a header name, and the value will be inserted in
+the headers of the article; if the value is @code{nil}, the header
+name will be removed.  If the attribute name is @code{eval}, the form
+is evaluated, and the result is thrown away.
+
+The attribute value can be a string, a function with zero arguments
+(the return value will be used), a variable (its value will be used)
+or a list (it will be @code{eval}ed and the return value will be
+used).  The functions and sexps are called/@code{eval}ed in the
+message buffer that is being set up.  The headers of the current
+article are available through the @code{message-reply-headers}
+variable, which is a vector of the following headers: number subject
+from date id references chars lines xref extra.
+
+In the case of a string value, if the @code{match} is a regular
+expression, or if it takes the form @code{(header @var{match}
+@var{regexp})}, a @samp{gnus-match-substitute-replacement} is proceed
+on the value to replace the positional parameters @samp{\@var{n}} by
+the corresponding parenthetical matches (see @xref{Replacing Match,,
+Replacing the Text that Matched, elisp, The Emacs Lisp Reference
+Manual}.)
+
+@vindex message-reply-headers
+
+If you wish to check whether the message you are about to compose is
+meant to be a news article or a mail message, you can check the values
+of the @code{message-news-p} and @code{message-mail-p} functions.
+
+@findex message-mail-p
+@findex message-news-p
+
+So here's a new example:
+
+@lisp
+(setq gnus-posting-styles
+      '((".*"
+         (signature-file "~/.signature")
+         (name "User Name")
+         (x-face-file "~/.xface")
+         (x-url (getenv "WWW_HOME"))
+         (organization "People's Front Against MWM"))
+        ("^rec.humor"
+         (signature my-funny-signature-randomizer))
+        ((equal (system-name) "gnarly")  ;; @r{A form}
+         (signature my-quote-randomizer))
+        (message-news-p        ;; @r{A function symbol}
+         (signature my-news-signature))
+        (window-system         ;; @r{A value symbol}
+         ("X-Window-System" (format "%s" window-system)))
+        ;; @r{If I'm replying to Larsi, set the Organization header.}
+        ((header "from" "larsi.*org")
+         (Organization "Somewhere, Inc."))
+        ;; @r{Reply to a message from the same subaddress the message}
+        ;; @r{was sent to.}
+        ((header "x-original-to" "me\\(\\+.+\\)@@example.org")
+         (address "me\\1@@example.org"))
+        ((posting-from-work-p) ;; @r{A user defined function}
+         (signature-file "~/.work-signature")
+         (address "user@@bar.foo")
+         (body "You are fired.\n\nSincerely, your boss.")
+         ("X-Message-SMTP-Method" "smtp smtp.example.org 587")
+         (organization "Important Work, Inc"))
+        ("nnml:.*"
+         (From (with-current-buffer gnus-article-buffer
+                 (message-fetch-field "to"))))
+        ("^nn.+:"
+         (signature-file "~/.mail-signature"))))
+@end lisp
+
+The @samp{nnml:.*} rule means that you use the @code{To} address as the
+@code{From} address in all your outgoing replies, which might be handy
+if you fill many roles.
+You may also use @code{message-alternative-emails} instead.
+@xref{Message Headers, ,Message Headers, message, Message Manual}.
+
+Of particular interest in the ``work-mail'' style is the
+@samp{X-Message-SMTP-Method} header.  It specifies how to send the
+outgoing email.  You may want to sent certain emails through certain
+@acronym{SMTP} servers due to company policies, for instance.
+@xref{Mail Variables, ,Message Variables, message, Message Manual}.
+
+
+@node Drafts
+@section Drafts
+@cindex drafts
+
+If you are writing a message (mail or news) and suddenly remember that
+you have a steak in the oven (or some pesto in the food processor, you
+craaazy vegetarians), you'll probably wish there was a method to save
+the message you are writing so that you can continue editing it some
+other day, and send it when you feel its finished.
+
+Well, don't worry about it.  Whenever you start composing a message of
+some sort using the Gnus mail and post commands, the buffer you get will
+automatically associate to an article in a special @dfn{draft} group.
+If you save the buffer the normal way (@kbd{C-x C-s}, for instance), the
+article will be saved there.  (Auto-save files also go to the draft
+group.)
+
+@cindex nndraft
+@vindex nndraft-directory
+The draft group is a special group (which is implemented as an
+@code{nndraft} group, if you absolutely have to know) called
+@samp{nndraft:drafts}.  The variable @code{nndraft-directory} says where
+@code{nndraft} is to store its files.  What makes this group special is
+that you can't tick any articles in it or mark any articles as
+read---all articles in the group are permanently unread.
+
+If the group doesn't exist, it will be created and you'll be subscribed
+to it.  The only way to make it disappear from the Group buffer is to
+unsubscribe it.  The special properties of the draft group comes from
+a group property (@pxref{Group Parameters}), and if lost the group
+behaves like any other group.  This means the commands below will not
+be available.  To restore the special properties of the group, the
+simplest way is to kill the group, using @kbd{C-k}, and restart
+Gnus.  The group is automatically created again with the
+correct parameters.  The content of the group is not lost.
+
+@c @findex gnus-dissociate-buffer-from-draft
+@c @kindex C-c M-d (Mail)
+@c @kindex C-c M-d (Post)
+@c @findex gnus-associate-buffer-with-draft
+@c @kindex C-c C-d (Mail)
+@c @kindex C-c C-d (Post)
+@c If you're writing some super-secret message that you later want to
+@c encode with PGP before sending, you may wish to turn the auto-saving
+@c (and association with the draft group) off.  You never know who might be
+@c interested in reading all your extremely valuable and terribly horrible
+@c and interesting secrets.  The @kbd{C-c M-d}
+@c (@code{gnus-dissociate-buffer-from-draft}) command does that for you.
+@c If you change your mind and want to turn the auto-saving back on again,
+@c @kbd{C-c C-d} (@code{gnus-associate-buffer-with-draft} does that.
+@c
+@c @vindex gnus-use-draft
+@c To leave association with the draft group off by default, set
+@c @code{gnus-use-draft} to @code{nil}.  It is @code{t} by default.
+
+@findex gnus-draft-edit-message
+@kindex D e (Draft)
+When you want to continue editing the article, you simply enter the
+draft group and push @kbd{D e} (@code{gnus-draft-edit-message}) to do
+that.  You will be placed in a buffer where you left off.
+
+Rejected articles will also be put in this draft group (@pxref{Rejected
+Articles}).
+
+@findex gnus-draft-send-all-messages
+@kindex D s (Draft)
+@findex gnus-draft-send-message
+@kindex D S (Draft)
+If you have lots of rejected messages you want to post (or mail) without
+doing further editing, you can use the @kbd{D s} command
+(@code{gnus-draft-send-message}).  This command understands the
+process/prefix convention (@pxref{Process/Prefix}).  The @kbd{D S}
+command (@code{gnus-draft-send-all-messages}) will ship off all messages
+in the buffer.
+
+@findex gnus-draft-toggle-sending
+@kindex D t (Draft)
+If you have some messages that you wish not to send, you can use the
+@kbd{D t} (@code{gnus-draft-toggle-sending}) command to mark the message
+as unsendable.  This is a toggling command.
+
+Finally, if you want to delete a draft, use the normal @kbd{B DEL}
+command (@pxref{Mail Group Commands}).
+
+
+@node Rejected Articles
+@section Rejected Articles
+@cindex rejected articles
+
+Sometimes a news server will reject an article.  Perhaps the server
+doesn't like your face.  Perhaps it just feels miserable.  Perhaps
+@emph{there be demons}.  Perhaps you have included too much cited text.
+Perhaps the disk is full.  Perhaps the server is down.
+
+These situations are, of course, totally beyond the control of Gnus.
+(Gnus, of course, loves the way you look, always feels great, has angels
+fluttering around inside of it, doesn't care about how much cited text
+you include, never runs full and never goes down.)  So Gnus saves these
+articles until some later time when the server feels better.
+
+The rejected articles will automatically be put in a special draft group
+(@pxref{Drafts}).  When the server comes back up again, you'd then
+typically enter that group and send all the articles off.
+
+@node Signing and encrypting
+@section Signing and encrypting
+@cindex using gpg
+@cindex using s/mime
+@cindex using smime
+
+Gnus can digitally sign and encrypt your messages, using vanilla
+@acronym{PGP} format or @acronym{PGP/MIME} or @acronym{S/MIME}.  For
+decoding such messages, see the @code{mm-verify-option} and
+@code{mm-decrypt-option} options (@pxref{Security}).
+
+@vindex gnus-message-replysign
+@vindex gnus-message-replyencrypt
+@vindex gnus-message-replysignencrypted
+Often, you would like to sign replies to people who send you signed
+messages.  Even more often, you might want to encrypt messages which
+are in reply to encrypted messages.  Gnus offers
+@code{gnus-message-replysign} to enable the former, and
+@code{gnus-message-replyencrypt} for the latter.  In addition, setting
+@code{gnus-message-replysignencrypted} (on by default) will sign
+automatically encrypted messages.
+
+Instructing @acronym{MML} to perform security operations on a
+@acronym{MIME} part is done using the @kbd{C-c C-m s} key map for
+signing and the @kbd{C-c C-m c} key map for encryption, as follows.
+
+@table @kbd
+
+@item C-c C-m s s
+@kindex C-c C-m s s (Message)
+@findex mml-secure-message-sign-smime
+
+Digitally sign current message using @acronym{S/MIME}.
+
+@item C-c C-m s o
+@kindex C-c C-m s o (Message)
+@findex mml-secure-message-sign-pgp
+
+Digitally sign current message using @acronym{PGP}.
+
+@item C-c C-m s p
+@kindex C-c C-m s p (Message)
+@findex mml-secure-message-sign-pgp
+
+Digitally sign current message using @acronym{PGP/MIME}.
+
+@item C-c C-m c s
+@kindex C-c C-m c s (Message)
+@findex mml-secure-message-encrypt-smime
+
+Digitally encrypt current message using @acronym{S/MIME}.
+
+@item C-c C-m c o
+@kindex C-c C-m c o (Message)
+@findex mml-secure-message-encrypt-pgp
+
+Digitally encrypt current message using @acronym{PGP}.
+
+@item C-c C-m c p
+@kindex C-c C-m c p (Message)
+@findex mml-secure-message-encrypt-pgpmime
+
+Digitally encrypt current message using @acronym{PGP/MIME}.
+
+@item C-c C-m C-n
+@kindex C-c C-m C-n (Message)
+@findex mml-unsecure-message
+Remove security related @acronym{MML} tags from message.
+
+@end table
+
+@xref{Security, ,Security, message, Message Manual}, for more information.
+
+@node Select Methods
+@chapter Select Methods
+@cindex foreign groups
+@cindex select methods
+
+A @dfn{foreign group} is a group not read by the usual (or
+default) means.  It could be, for instance, a group from a different
+@acronym{NNTP} server, it could be a virtual group, or it could be your own
+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 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 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 back end will recognize the
+group as.
+
+For instance, the group @samp{soc.motss} on the @acronym{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}
+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.
+* Using IMAP::                  Reading mail from @acronym{IMAP}.
+* Getting Mail::                Reading your personal mail with Gnus.
+* Browsing the Web::            Getting messages from a plethora of Web sources.
+* Other Sources::               Reading directories, files.
+* Combined Groups::             Combining groups into one group.
+* Email Based Diary::           Using mails to manage diary events in Gnus.
+* Gnus Unplugged::              Reading news and mail offline.
+@end menu
+
+
+@node Server Buffer
+@section Server Buffer
+
+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 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
+back end represents a virtual server.
+
+For instance, the @code{nntp} back end may be used to connect to several
+different actual @acronym{NNTP} servers, or, perhaps, to many different ports
+on the same actual @acronym{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
+complicated---say, for instance, that you want to read from the
+@acronym{NNTP} server @samp{news.funet.fi} on port number 13, which
+hangs if queried for @acronym{NOV} headers and has a buggy select.  Ahem.
+Anyway, if you had to specify that for each group that used this
+server, that would be too much work, so Gnus offers a way of naming
+select methods, which is what you do in the server buffer.
+
+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.
+@end menu
+
+@vindex gnus-server-mode-hook
+@code{gnus-server-mode-hook} is run when creating the server buffer.
+
+
+@node Server Buffer Format
+@subsection Server Buffer Format
+@cindex server buffer format
+
+@vindex gnus-server-line-format
+You can change the look of the server buffer lines by changing the
+@code{gnus-server-line-format} variable.  This is a @code{format}-like
+variable, with some simple extensions:
+
+@table @samp
+
+@item h
+How the news is fetched---the back end name.
+
+@item n
+The name of this server.
+
+@item w
+Where the news is to be fetched from---the address.
+
+@item s
+The opened/closed/denied status of the server.
+
+@item a
+Whether this server is agentized.
+@end table
+
+@vindex gnus-server-mode-line-format
+The mode line can also be customized by using the
+@code{gnus-server-mode-line-format} variable (@pxref{Mode Line
+Formatting}).  The following specs are understood:
+
+@table @samp
+@item S
+Server name.
+
+@item M
+Server method.
+@end table
+
+Also @pxref{Formatting Variables}.
+
+
+@node Server Commands
+@subsection Server Commands
+@cindex server commands
+
+@table @kbd
+
+@item v
+@kindex v (Server)
+@cindex keys, reserved for users (Server)
+The key @kbd{v} is reserved for users.  You can bind it to some
+command or better use it as a prefix key.
+
+@item a
+@kindex a (Server)
+@findex gnus-server-add-server
+Add a new server (@code{gnus-server-add-server}).
+
+@item e
+@kindex e (Server)
+@findex gnus-server-edit-server
+Edit a server (@code{gnus-server-edit-server}).
+
+@item S
+@kindex S (Server)
+@findex gnus-server-show-server
+Show the definition of a server (@code{gnus-server-show-server}).
+
+@item SPACE
+@kindex SPACE (Server)
+@findex gnus-server-read-server
+Browse the current server (@code{gnus-server-read-server}).
+
+@item q
+@kindex q (Server)
+@findex gnus-server-exit
+Return to the group buffer (@code{gnus-server-exit}).
+
+@item k
+@kindex k (Server)
+@findex gnus-server-kill-server
+Kill the current server (@code{gnus-server-kill-server}).
+
+@item y
+@kindex y (Server)
+@findex gnus-server-yank-server
+Yank the previously killed server (@code{gnus-server-yank-server}).
+
+@item c
+@kindex c (Server)
+@findex gnus-server-copy-server
+Copy the current server (@code{gnus-server-copy-server}).
+
+@item l
+@kindex l (Server)
+@findex gnus-server-list-servers
+List all servers (@code{gnus-server-list-servers}).
+
+@item s
+@kindex s (Server)
+@findex gnus-server-scan-server
+Request that the server scan its sources for new articles
+(@code{gnus-server-scan-server}).  This is mainly sensible with mail
+servers.
+
+@item g
+@kindex g (Server)
+@findex gnus-server-regenerate-server
+Request that the server regenerate all its data structures
+(@code{gnus-server-regenerate-server}).  This can be useful if you have
+a mail back end that has gotten out of sync.
+
+@item z
+@kindex z (Server)
+@findex gnus-server-compact-server
+
+Compact all groups in the server under point
+(@code{gnus-server-compact-server}).  Currently implemented only in
+nnml (@pxref{Mail Spool}).  This removes gaps between article numbers,
+hence getting a correct total article count.
+
+@end table
+
+Some more commands for closing, disabling, and re-opening servers are
+listed in @ref{Unavailable Servers}.
+
+
+@node Example Methods
+@subsection Example Methods
+
+Most select methods are pretty simple and self-explanatory:
+
+@lisp
+(nntp "news.funet.fi")
+@end lisp
+
+Reading directly from the spool is even simpler:
+
+@lisp
+(nnspool "")
+@end lisp
+
+As you can see, the first element in a select method is the name of the
+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
+@code{(@var{variable} @var{form})} pairs.
+
+To go back to the first example---imagine that you want to read from
+port 15 on that machine.  This is what the select method should
+look like then:
+
+@lisp
+(nntp "news.funet.fi" (nntp-port-number 15))
+@end lisp
+
+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 back end that reads a spool-like structure.  Say
+you have two structures that you wish to access: One is your private
+mail spool, and the other is a public one.  Here's the possible spec for
+your private mail:
+
+@lisp
+(nnmh "private" (nnmh-directory "~/private/mail/"))
+@end lisp
+
+(This server is then called @samp{private}, but you may have guessed
+that.)
+
+Here's the method for a public spool:
+
+@lisp
+(nnmh "public"
+      (nnmh-directory "/usr/information/spool/")
+      (nnmh-get-new-mail nil))
+@end lisp
+
+@cindex proxy
+@cindex firewall
+
+If you are behind a firewall and only have access to the @acronym{NNTP}
+server from the firewall machine, you can instruct Gnus to @code{rlogin}
+on the firewall machine and connect with
+@uref{http://netcat.sourceforge.net/, netcat} from there to the
+@acronym{NNTP} server.
+Doing this can be rather fiddly, but your virtual server definition
+should probably look something like this:
+
+@lisp
+(nntp "firewall"
+      (nntp-open-connection-function nntp-open-via-rlogin-and-netcat)
+      (nntp-via-address "the.firewall.machine")
+      (nntp-address "the.real.nntp.host"))
+@end lisp
+
+If you want to use the wonderful @code{ssh} program to provide a
+compressed connection over the modem line, you could add the following
+configuration to the example above:
+
+@lisp
+      (nntp-via-rlogin-command "ssh")
+@end lisp
+
+See also @code{nntp-via-rlogin-command-switches}.  Here's an example for
+an indirect connection:
+
+@lisp
+(setq gnus-select-method
+      '(nntp "indirect"
+             (nntp-address "news.server.example")
+             (nntp-via-user-name "intermediate_user_name")
+             (nntp-via-address "intermediate.host.example")
+             (nntp-via-rlogin-command "ssh")
+             (nntp-via-rlogin-command-switches ("-C"))
+             (nntp-open-connection-function nntp-open-via-rlogin-and-netcat)))
+@end lisp
+
+This means that you have to have set up @code{ssh-agent} correctly to
+provide automatic authorization, of course.
+
+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
+netcat connection to the news server as follows:
+
+@lisp
+(nntp "outside"
+      (nntp-pre-command "runsocks")
+      (nntp-open-connection-function nntp-open-netcat-stream)
+      (nntp-address "the.news.server"))
+@end lisp
+
+
+@node Creating a Virtual Server
+@subsection Creating a Virtual Server
+
+If you're saving lots of articles in the cache by using persistent
+articles, you may want to create a virtual server to read the cache.
+
+First you need to add a new server.  The @kbd{a} command does that.  It
+would probably be best to use @code{nnml} to read the cache.  You
+could also use @code{nnspool} or @code{nnmh}, though.
+
+Type @kbd{a nnml RET cache RET}.
+
+You should now have a brand new @code{nnml} virtual server called
+@samp{cache}.  You now need to edit it to have the right definitions.
+Type @kbd{e} to edit the server.  You'll be entered into a buffer that
+will contain the following:
+
+@lisp
+(nnml "cache")
+@end lisp
+
+Change that to:
+
+@lisp
+(nnml "cache"
+         (nnml-directory "~/News/cache/")
+         (nnml-active-file "~/News/cache/active"))
+@end lisp
+
+Type @kbd{C-c C-c} to return to the server buffer.  If you now press
+@kbd{RET} over this virtual server, you should be entered into a browse
+buffer, and you should be able to enter any of the groups displayed.
+
+
+@node Server Variables
+@subsection Server Variables
+@cindex server variables
+@cindex server parameters
+
+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
+won't change the ``derived'' variables.
+
+This typically affects directory and file variables.  For instance,
+@code{nnml-directory} is @file{~/Mail/} by default, and all @code{nnml}
+directory variables are initialized from that variable, so
+@code{nnml-active-file} will be @file{~/Mail/active}.  If you define a
+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 back end, see each back end's section later in this
+manual, but here's an example @code{nnml} definition:
+
+@lisp
+(nnml "public"
+      (nnml-directory "~/my-mail/")
+      (nnml-active-file "~/my-mail/active")
+      (nnml-newsgroups-file "~/my-mail/newsgroups"))
+@end lisp
+
+Server variables are often called @dfn{server parameters}.
+
+@node Servers and Methods
+@subsection Servers and Methods
+
+Wherever you would normally use a select method
+(e.g., @code{gnus-secondary-select-method}, in the group select method,
+when browsing a foreign server) you can use a virtual server name
+instead.  This could potentially save lots of typing.  And it's nice all
+over.
+
+
+@node Unavailable Servers
+@subsection Unavailable Servers
+
+If a server seems to be unreachable, Gnus will mark that server as
+@code{denied}.  That means that any subsequent attempt to make contact
+with that server will just be ignored.  ``It can't be opened,'' Gnus
+will tell you, without making the least effort to see whether that is
+actually the case or not.
+
+That might seem quite naughty, but it does make sense most of the time.
+Let's say you have 10 groups subscribed to on server
+@samp{nephelococcygia.com}.  This server is located somewhere quite far
+away from you and the machine is quite slow, so it takes 1 minute just
+to find out that it refuses connection to you today.  If Gnus were to
+attempt to do that 10 times, you'd be quite annoyed, so Gnus won't
+attempt to do that.  Once it has gotten a single ``connection refused'',
+it will regard that server as ``down''.
+
+So, what happens if the machine was only feeling unwell temporarily?
+How do you test to see whether the machine has come up again?
+
+You jump to the server buffer (@pxref{Server Buffer}) and poke it
+with the following commands:
+
+@table @kbd
+
+@item O
+@kindex O (Server)
+@findex gnus-server-open-server
+Try to establish connection to the server on the current line
+(@code{gnus-server-open-server}).
+
+@item C
+@kindex C (Server)
+@findex gnus-server-close-server
+Close the connection (if any) to the server
+(@code{gnus-server-close-server}).
+
+@item D
+@kindex D (Server)
+@findex gnus-server-deny-server
+Mark the current server as unreachable
+(@code{gnus-server-deny-server}).
+
+@item M-o
+@kindex M-o (Server)
+@findex gnus-server-open-all-servers
+Open the connections to all servers in the buffer
+(@code{gnus-server-open-all-servers}).
+
+@item M-c
+@kindex M-c (Server)
+@findex gnus-server-close-all-servers
+Close the connections to all servers in the buffer
+(@code{gnus-server-close-all-servers}).
+
+@item R
+@kindex R (Server)
+@findex gnus-server-remove-denials
+Remove all marks to whether Gnus was denied connection from any servers
+(@code{gnus-server-remove-denials}).
+
+@item c
+@kindex c (Server)
+@findex gnus-server-copy-server
+Copy a server and give it a new name
+(@code{gnus-server-copy-server}).  This can be useful if you have a
+complex method definition, and want to use the same definition towards
+a different (physical) server.
+
+@item L
+@kindex L (Server)
+@findex gnus-server-offline-server
+Set server status to offline (@code{gnus-server-offline-server}).
+
+@end table
+
+
+@node Getting News
+@section Getting News
+@cindex reading news
+@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 @acronym{NNTP} server,
+or it can read from a local spool.
+
+@menu
+* NNTP::                        Reading news from an @acronym{NNTP} server.
+* News Spool::                  Reading news from the local spool.
+@end menu
+
+
+@node NNTP
+@subsection NNTP
+@cindex nntp
+
+Subscribing to a foreign group from an @acronym{NNTP} server is rather easy.
+You just specify @code{nntp} as method and the address of the @acronym{NNTP}
+server as the, uhm, address.
+
+If the @acronym{NNTP} server is located at a non-standard port, setting the
+third element of the select method to this port number should allow you
+to connect to the right port.  You'll have to edit the group info for
+that (@pxref{Foreign Groups}).
+
+The name of the foreign group can be the same as a native group.  In
+fact, you can subscribe to the same group from as many different servers
+you feel like.  There will be no name collisions.
+
+The following variables can be used to create a virtual @code{nntp}
+server:
+
+@table @code
+
+@item nntp-server-opened-hook
+@vindex nntp-server-opened-hook
+@cindex @sc{mode reader}
+@cindex authinfo
+@cindex authentication
+@cindex nntp authentication
+@findex nntp-send-authinfo
+@findex nntp-send-mode-reader
+is run after a connection has been made.  It can be used to send
+commands to the @acronym{NNTP} server after it has been contacted.  By
+default it sends the command @code{MODE READER} to the server with the
+@code{nntp-send-mode-reader} function.  This function should always be
+present in this hook.
+
+@item nntp-authinfo-function
+@vindex nntp-authinfo-function
+@findex nntp-send-authinfo
+@vindex nntp-authinfo-file
+This function will be used to send @samp{AUTHINFO} to the @acronym{NNTP}
+server.  The default function is @code{nntp-send-authinfo}, which looks
+through your @file{~/.authinfo} (or whatever you've set the
+@code{nntp-authinfo-file} variable to) for applicable entries.  If none
+are found, it will prompt you for a login name and a password.  The
+format of the @file{~/.authinfo} file is (almost) the same as the
+@code{ftp} @file{~/.netrc} file, which is defined in the @code{ftp}
+manual page, but here are the salient facts:
+
+@enumerate
+@item
+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.
+
+The valid tokens include @samp{machine}, @samp{login}, @samp{password},
+@samp{default}.  In addition Gnus introduces two new tokens, not present
+in the original @file{.netrc}/@code{ftp} syntax, namely @samp{port} and
+@samp{force}.  (This is the only way the @file{.authinfo} file format
+deviates from the @file{.netrc} file format.)  @samp{port} is used to
+indicate what port on the server the credentials apply to and
+@samp{force} is explained below.
+
+@end enumerate
+
+Here's an example file:
+
+@example
+machine news.uio.no login larsi password geheimnis
+machine nntp.ifi.uio.no login larsi force yes
+@end example
+
+The token/value pairs may appear in any order; @samp{machine} doesn't
+have to be first, for instance.
+
+In this example, both login name and password have been supplied for the
+former server, while the latter has only the login name listed, and the
+user will be prompted for the password.  The latter also has the
+@samp{force} tag, which means that the authinfo will be sent to the
+@var{nntp} server upon connection; the default (i.e., when there is not
+@samp{force} tag) is to not send authinfo to the @var{nntp} server
+until the @var{nntp} server asks for it.
+
+You can also add @samp{default} lines that will apply to all servers
+that don't have matching @samp{machine} lines.
+
+@example
+default force yes
+@end example
+
+This will force sending @samp{AUTHINFO} commands to all servers not
+previously mentioned.
+
+Remember to not leave the @file{~/.authinfo} file world-readable.
+
+@item nntp-server-action-alist
+@vindex nntp-server-action-alist
+This is a list of regexps to match on server types and actions to be
+taken when matches are made.  For instance, if you want Gnus to beep
+every time you connect to innd, you could say something like:
+
+@lisp
+(setq nntp-server-action-alist
+      '(("innd" (ding))))
+@end lisp
+
+You probably don't want to do that, though.
+
+The default value is
+
+@lisp
+'(("nntpd 1\\.5\\.11t"
+   (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
+nntpd 1.5.11t, since that command chokes that server, I've been told.
+
+@item nntp-maximum-request
+@vindex nntp-maximum-request
+If the @acronym{NNTP} server doesn't support @acronym{NOV} headers, this back end
+will collect headers by sending a series of @code{head} commands.  To
+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.
+
+@item nntp-connection-timeout
+@vindex nntp-connection-timeout
+If you have lots of foreign @code{nntp} groups that you connect to
+regularly, you're sure to have problems with @acronym{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} back end should wait for a
+connection before giving up.  If it is @code{nil}, which is the default,
+no timeouts are done.
+
+@item nntp-nov-is-evil
+@vindex nntp-nov-is-evil
+If the @acronym{NNTP} server does not support @acronym{NOV}, you could set this
+variable to @code{t}, but @code{nntp} usually checks automatically whether @acronym{NOV}
+can be used.
+
+@item nntp-xover-commands
+@vindex nntp-xover-commands
+@cindex @acronym{NOV}
+@cindex XOVER
+List of strings used as commands to fetch @acronym{NOV} lines from a
+server.  The default value of this variable is @code{("XOVER"
+"XOVERVIEW")}.
+
+@item nntp-nov-gap
+@vindex nntp-nov-gap
+@code{nntp} normally sends just one big request for @acronym{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 @acronym{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-xref-number-is-evil
+@vindex nntp-xref-number-is-evil
+When Gnus refers to an article having the @code{Message-ID} that a user
+specifies or having the @code{Message-ID} of the parent article of the
+current one (@pxref{Finding the Parent}), Gnus sends a @code{HEAD}
+command to the @acronym{NNTP} server to know where it is, and the server
+returns the data containing the pairs of a group and an article number
+in the @code{Xref} header.  Gnus normally uses the article number to
+refer to the article if the data shows that that article is in the
+current group, while it uses the @code{Message-ID} otherwise.  However,
+some news servers, e.g., ones running Diablo, run multiple engines
+having the same articles but article numbers are not kept synchronized
+between them.  In that case, the article number that appears in the
+@code{Xref} header varies by which engine is chosen, so you cannot refer
+to the parent article that is in the current group, for instance.  If
+you connect to such a server, set this variable to a non-@code{nil}
+value, and Gnus never uses article numbers.  For example:
+
+@lisp
+(setq gnus-select-method
+      '(nntp "newszilla"
+             (nntp-address "newszilla.example.com")
+             (nntp-xref-number-is-evil t)
+             @dots{}))
+@end lisp
+
+The default value of this server variable is @code{nil}.
+
+@item nntp-prepare-server-hook
+@vindex nntp-prepare-server-hook
+A hook run before attempting to connect to an @acronym{NNTP} server.
+
+@item nntp-record-commands
+@vindex nntp-record-commands
+If non-@code{nil}, @code{nntp} will log all commands it sends to the
+@acronym{NNTP} server (along with a timestamp) in the @file{*nntp-log*}
+buffer.  This is useful if you are debugging a Gnus/@acronym{NNTP} connection
+that doesn't seem to work.
+
+@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.
+Seven pre-made functions are supplied.  These functions can be grouped
+in two categories: direct connection functions (four pre-made), and
+indirect ones (three pre-made).
+
+@item nntp-never-echoes-commands
+@vindex nntp-never-echoes-commands
+Non-@code{nil} means the nntp server never echoes commands.  It is
+reported that some nntps server doesn't echo commands.  So, you may want
+to set this to non-@code{nil} in the method for such a server setting
+@code{nntp-open-connection-function} to @code{nntp-open-ssl-stream} for
+example.  The default value is @code{nil}.  Note that the
+@code{nntp-open-connection-functions-never-echo-commands} variable
+overrides the @code{nil} value of this variable.
+
+@item nntp-open-connection-functions-never-echo-commands
+@vindex nntp-open-connection-functions-never-echo-commands
+List of functions that never echo commands.  Add or set a function which
+you set to @code{nntp-open-connection-function} to this list if it does
+not echo commands.  Note that a non-@code{nil} value of the
+@code{nntp-never-echoes-commands} variable overrides this variable.  The
+default value is @code{(nntp-open-network-stream)}.
+
+@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:
+
+@lisp
+(add-hook 'nntp-prepare-post-hook 'canlock-insert-header)
+@end lisp
+
+Note that not all servers support the recommended ID@.  This works for
+INN versions 2.3.0 and later, for instance.
+
+@item nntp-server-list-active-group
+If @code{nil}, then always use @samp{GROUP} instead of @samp{LIST
+ACTIVE}.  This is usually slower, but on misconfigured servers that
+don't update their active files often, this can help.
+
+
+@end table
+
+@menu
+* Direct Functions::            Connecting directly to the server.
+* Indirect Functions::          Connecting indirectly to the server.
+* Common Variables::            Understood by several connection functions.
+@end menu
+
+
+@node Direct Functions
+@subsubsection Direct Functions
+@cindex direct connection functions
+
+These functions are called direct because they open a direct connection
+between your machine and the @acronym{NNTP} server.  The behavior of these
+functions is also affected by commonly understood variables
+(@pxref{Common Variables}).
+
+@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.  If both Emacs and the server supports it, the
+connection will be upgraded to an encrypted @acronym{STARTTLS}
+connection automatically.
+
+@item network-only
+The same as the above, but don't do automatic @acronym{STARTTLS} upgrades.
+
+@findex nntp-open-tls-stream
+@item nntp-open-tls-stream
+Opens a connection to a server over a @dfn{secure} channel.  To use
+this you must have @uref{http://www.gnu.org/software/gnutls/, GnuTLS}
+installed.  You then define a server as follows:
+
+@lisp
+;; @r{"nntps" is port 563 and is predefined in our @file{/etc/services}}
+;; @r{however, @samp{gnutls-cli -p} doesn't like named ports.}
+;;
+(nntp "snews.bar.com"
+      (nntp-open-connection-function nntp-open-tls-stream)
+      (nntp-port-number 563)
+      (nntp-address "snews.bar.com"))
+@end lisp
+
+@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 @uref{http://www.openssl.org, OpenSSL}
+@ignore
+@c Defunct URL, ancient package, so don't mention it.
+or @uref{ftp://ftp.psy.uq.oz.au/pub/Crypto/SSL, SSLeay}
+@end ignore
+installed.  You then define a server as follows:
+
+@lisp
+;; @r{"snews" is port 563 and is predefined in our @file{/etc/services}}
+;; @r{however, @samp{openssl s_client -port} doesn't like named ports.}
+;;
+(nntp "snews.bar.com"
+      (nntp-open-connection-function nntp-open-ssl-stream)
+      (nntp-port-number 563)
+      (nntp-address "snews.bar.com"))
+@end lisp
+
+@findex nntp-open-netcat-stream
+@item nntp-open-netcat-stream
+Opens a connection to an @acronym{NNTP} server using the @code{netcat}
+program.  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-netcat-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.
+
+@findex nntp-open-telnet-stream
+@item nntp-open-telnet-stream
+Like @code{nntp-open-netcat-stream}, but uses @code{telnet} rather than
+@code{netcat}.  @code{telnet} is a bit less robust because of things
+like line-end-conversion, but sometimes netcat is simply
+not available.  The previous example would turn into:
+
+@lisp
+(nntp "socksified"
+      (nntp-pre-command "runsocks")
+      (nntp-open-connection-function nntp-open-telnet-stream)
+      (nntp-address "the.news.server")
+      (nntp-end-of-line "\n"))
+@end lisp
+@end table
+
+
+@node Indirect Functions
+@subsubsection Indirect Functions
+@cindex indirect connection functions
+
+These functions are called indirect because they connect to an
+intermediate host before actually connecting to the @acronym{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}).
+
+@table @code
+@item nntp-open-via-rlogin-and-netcat
+@findex nntp-open-via-rlogin-and-netcat
+Does an @samp{rlogin} on a remote system, and then uses @code{netcat} to connect
+to the real @acronym{NNTP} server from there.  This is useful for instance if
+you need to connect to a firewall machine first.
+
+@code{nntp-open-via-rlogin-and-netcat}-specific variables:
+
+@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.
+
+@item nntp-via-rlogin-command-switches
+@vindex nntp-via-rlogin-command-switches
+List of strings to be used as the switches to
+@code{nntp-via-rlogin-command}.  The default is @code{nil}.  If you use
+@samp{ssh} for @code{nntp-via-rlogin-command}, you may set this to
+@samp{("-C")} in order to compress all data connections.
+@end table
+
+@item nntp-open-via-rlogin-and-telnet
+@findex nntp-open-via-rlogin-and-telnet
+Does essentially the same, but uses @code{telnet} instead of @samp{netcat}
+to connect to the real @acronym{NNTP} server from the intermediate host.
+@code{telnet} is a bit less robust because of things like
+line-end-conversion, but sometimes @code{netcat} is simply not available.
+
+@code{nntp-open-via-rlogin-and-telnet}-specific variables:
+
+@table @code
+@item nntp-telnet-command
+@vindex nntp-telnet-command
+Command used to connect to the real @acronym{NNTP} server from the
+intermediate host.  The default is @samp{telnet}.
+
+@item nntp-telnet-switches
+@vindex nntp-telnet-switches
+List of strings to be used as the switches to the
+@code{nntp-telnet-command} command.  The default is @code{("-8")}.
+
+@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.
+
+@item nntp-via-rlogin-command-switches
+@vindex nntp-via-rlogin-command-switches
+List of strings to be used as the switches to
+@code{nntp-via-rlogin-command}.  If you use @samp{ssh},  you may need to set
+this to @samp{("-t" "-e" "none")} or @samp{("-C" "-t" "-e" "none")} if
+the telnet command requires a pseudo-tty allocation on an intermediate
+host.  The default is @code{nil}.
+@end table
+
+Note that you may want to change the value for @code{nntp-end-of-line}
+to @samp{\n} (@pxref{Common Variables}).
+
+@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.
+
+@code{nntp-open-via-telnet-and-telnet}-specific variables:
+
+@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?}.
+
+@end table
+
+Note that you may want to change the value for @code{nntp-end-of-line}
+to @samp{\n} (@pxref{Common Variables}).
+@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 (the values of the following variables will be used as the
+default if each virtual @code{nntp} server doesn't specify those server
+variables individually).
+
+@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},
+@code{nntp-open-tls-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 @acronym{NNTP} server.
+
+@item nntp-port-number
+@vindex nntp-port-number
+Port number to connect to the @acronym{NNTP} server.  The default is
+@samp{nntp}.  If you use @acronym{NNTP} over
+@acronym{TLS}/@acronym{SSL}, you may want to use integer ports rather
+than named ports (i.e., use @samp{563} instead of @samp{snews} or
+@samp{nntps}), because external @acronym{TLS}/@acronym{SSL} tools may
+not work with named ports.
+
+@item nntp-end-of-line
+@vindex nntp-end-of-line
+String to use as end-of-line marker when talking to the @acronym{NNTP}
+server.  This is @samp{\r\n} by default, but should be @samp{\n} when
+using a non native telnet connection function.
+
+@item nntp-netcat-command
+@vindex nntp-netcat-command
+Command to use when connecting to the @acronym{NNTP} server through
+@samp{netcat}.  This is @emph{not} for an intermediate host.  This is
+just for the real @acronym{NNTP} server.  The default is
+@samp{nc}.
+
+@item nntp-netcat-switches
+@vindex nntp-netcat-switches
+A list of switches to pass to @code{nntp-netcat-command}.  The default
+is @samp{()}.
+
+@end table
+
+@node News Spool
+@subsection News Spool
+@cindex nnspool
+@cindex news spool
+
+Subscribing to a foreign group from the local spool is extremely easy,
+and might be useful, for instance, to speed up reading groups that
+contain very big articles---@samp{alt.binaries.pictures.furniture}, for
+instance.
+
+Anyway, you just specify @code{nnspool} as the method and @code{""} (or
+anything else) as the address.
+
+If you have access to a local spool, you should probably use that as the
+native select method (@pxref{Finding the News}).  It is normally faster
+than using an @code{nntp} select method, but might not be.  It depends.
+You just have to try to find out what's best at your site.
+
+@table @code
+
+@item nnspool-inews-program
+@vindex nnspool-inews-program
+Program used to post an article.
+
+@item nnspool-inews-switches
+@vindex nnspool-inews-switches
+Parameters given to the inews program when posting an article.
+
+@item nnspool-spool-directory
+@vindex nnspool-spool-directory
+Where @code{nnspool} looks for the articles.  This is normally
+@file{/usr/spool/news/}.
+
+@item nnspool-nov-directory
+@vindex nnspool-nov-directory
+Where @code{nnspool} will look for @acronym{NOV} files.  This is normally@*
+@file{/usr/spool/news/over.view/}.
+
+@item nnspool-lib-dir
+@vindex nnspool-lib-dir
+Where the news lib dir is (@file{/usr/lib/news/} by default).
+
+@item nnspool-active-file
+@vindex nnspool-active-file
+The name of the active file.
+
+@item nnspool-newsgroups-file
+@vindex nnspool-newsgroups-file
+The name of the group descriptions file.
+
+@item nnspool-history-file
+@vindex nnspool-history-file
+The name of the news history file.
+
+@item nnspool-active-times-file
+@vindex nnspool-active-times-file
+The name of the active date file.
+
+@item nnspool-nov-is-evil
+@vindex nnspool-nov-is-evil
+If non-@code{nil}, @code{nnspool} won't try to use any @acronym{NOV} files
+that it finds.
+
+@item nnspool-sift-nov-with-sed
+@vindex nnspool-sift-nov-with-sed
+@cindex sed
+If non-@code{nil}, which is the default, use @code{sed} to get the
+relevant portion from the overview file.  If @code{nil},
+@code{nnspool} will load the entire file into a buffer and process it
+there.
+
+@end table
+
+
+@node Using IMAP
+@section Using IMAP
+@cindex imap
+
+The most popular mail backend is probably @code{nnimap}, which
+provides access to @acronym{IMAP} servers.  @acronym{IMAP} servers
+store mail remotely, so the client doesn't store anything locally.
+This means that it's a convenient choice when you're reading your mail
+from different locations, or with different user agents.
+
+@menu
+* Connecting to an IMAP Server::     Getting started with @acronym{IMAP}.
+* Customizing the IMAP Connection::  Variables for @acronym{IMAP} connection.
+* Client-Side IMAP Splitting::       Put mail in the correct mail box.
+* Support for IMAP Extensions::      Getting extensions and labels from servers.
+@end menu
+
+
+@node Connecting to an IMAP Server
+@subsection Connecting to an IMAP Server
+
+Connecting to an @acronym{IMAP} can be very easy.  Type @kbd{B} in the
+group buffer, or (if your primary interest is reading email), say
+something like:
+
+@example
+(setq gnus-select-method
+      '(nnimap "imap.gmail.com"))
+@end example
+
+You'll be prompted for a user name and password.  If you grow tired of
+that, then add the following to your @file{~/.authinfo} file:
+
+@example
+machine imap.gmail.com login <username> password <password> port imap
+@end example
+
+That should basically be it for most users.
+
+
+@node Customizing the IMAP Connection
+@subsection Customizing the IMAP Connection
+
+Here's an example method that's more complex:
+
+@example
+(nnimap "imap.gmail.com"
+        (nnimap-inbox "INBOX")
+        (nnimap-split-methods default)
+        (nnimap-expunge t)
+        (nnimap-stream ssl))
+@end example
+
+@table @code
+@item nnimap-address
+The address of the server, like @samp{imap.gmail.com}.
+
+@item nnimap-server-port
+If the server uses a non-standard port, that can be specified here.  A
+typical port would be @code{"imap"} or @code{"imaps"}.
+
+@item nnimap-stream
+How @code{nnimap} should connect to the server.  Possible values are:
+
+@table @code
+@item undecided
+This is the default, and this first tries the @code{ssl} setting, and
+then tries the @code{network} setting.
+
+@item ssl
+This uses standard @acronym{TLS}/@acronym{SSL} connections.
+
+@item network
+Non-encrypted and unsafe straight socket connection, but will upgrade
+to encrypted @acronym{STARTTLS} if both Emacs and the server
+supports it.
+
+@item starttls
+Encrypted @acronym{STARTTLS} over the normal @acronym{IMAP} port.
+
+@item shell
+If you need to tunnel via other systems to connect to the server, you
+can use this option, and customize @code{nnimap-shell-program} to be
+what you need.
+
+@item plain
+Non-encrypted and unsafe straight socket connection.
+@acronym{STARTTLS} will not be used even if it is available.
+
+@end table
+
+@item nnimap-authenticator
+Some @acronym{IMAP} servers allow anonymous logins.  In that case,
+this should be set to @code{anonymous}.  If this variable isn't set,
+the normal login methods will be used.  If you wish to specify a
+specific login method to be used, you can set this variable to either
+@code{login} (the traditional @acronym{IMAP} login method),
+@code{plain} or @code{cram-md5}.
+
+@item nnimap-expunge
+If non-@code{nil}, expunge articles after deleting them.  This is always done
+if the server supports UID EXPUNGE, but it's not done by default on
+servers that doesn't support that command.
+
+@item nnimap-streaming
+Virtually all @acronym{IMAP} server support fast streaming of data.
+If you have problems connecting to the server, try setting this to
+@code{nil}.
+
+@item nnimap-fetch-partial-articles
+If non-@code{nil}, fetch partial articles from the server.  If set to
+a string, then it's interpreted as a regexp, and parts that have
+matching types will be fetched.  For instance, @samp{"text/"} will
+fetch all textual parts, while leaving the rest on the server.
+
+@item nnimap-record-commands
+If non-@code{nil}, record all @acronym{IMAP} commands in the
+@samp{"*imap log*"} buffer.
+
+@end table
+
+
+@node Client-Side IMAP Splitting
+@subsection Client-Side IMAP Splitting
+
+Many people prefer to do the sorting/splitting of mail into their mail
+boxes on the @acronym{IMAP} server.  That way they don't have to
+download the mail they're not all that interested in.
+
+If you do want to do client-side mail splitting, then the following
+variables are relevant:
+
+@table @code
+@item nnimap-inbox
+This is the @acronym{IMAP} mail box that will be scanned for new
+mail.  This can also be a list of mail box names.
+
+@item nnimap-split-methods
+Uses the same syntax as @code{nnmail-split-methods} (@pxref{Splitting
+Mail}), except the symbol @code{default}, which means that it should
+use the value of the @code{nnmail-split-methods} variable.
+
+@item nnimap-split-fancy
+Uses the same syntax as @code{nnmail-split-fancy}.
+
+@item nnimap-unsplittable-articles
+List of flag symbols to ignore when doing splitting.  That is,
+articles that have these flags won't be considered when splitting.
+The default is @samp{(%Deleted %Seen)}.
+
+@end table
+
+Here's a complete example @code{nnimap} backend with a client-side
+``fancy'' splitting method:
+
+@example
+(nnimap "imap.example.com"
+        (nnimap-inbox "INBOX")
+        (nnimap-split-methods
+         (| ("MailScanner-SpamCheck" "spam" "spam.detected")
+            (to "foo@@bar.com" "foo")
+            "undecided")))
+@end example
+
+
+@node Support for IMAP Extensions
+@subsection Support for IMAP Extensions
+
+@cindex Gmail
+@cindex X-GM-LABELS
+@cindex IMAP labels
+
+If you're using Google's Gmail, you may want to see your Gmail labels
+when reading your mail.  Gnus can give you this information if you ask
+for @samp{X-GM-LABELS} in the variable @code{gnus-extra-headers}. For
+example:
+
+@example
+(setq gnus-extra-headers
+      '(To Newsgroups X-GM-LABELS))
+@end example
+
+This will result in Gnus storing your labels in message header
+structures for later use.  The content is always a parenthesized
+(possible empty) list.
+
+
+
+@node Getting Mail
+@section Getting Mail
+@cindex reading mail
+@cindex mail
+
+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 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 cruft 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.
+@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
+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
+it behave that way, you can, but it's an uphill battle.
+
+Gnus, by default, handles all its groups using the same approach.  This
+approach is very newsreaderly---you enter a group, see the new/unread
+messages, and when you read the messages, they get marked as read, and
+you don't see them any more.  (Unless you explicitly ask for them.)
+
+In particular, you do not do anything explicitly to delete messages.
+
+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
+the news administrator; for mail, the expire process is controlled by
+you.  The expire process for mail is covered in depth in @ref{Expiring
+Mail}.
+
+What many Gnus users find, after using it a while for both news and
+mail, is that the transport mechanism has very little to do with how
+they want to treat a message.
+
+Many people subscribe to several mailing lists.  These are transported
+via @acronym{SMTP}, and are therefore mail.  But we might go for weeks without
+answering, or even reading these messages very carefully.  We may not
+need to save them because if we should need to read one again, they are
+archived somewhere else.
+
+Some people have local news groups which have only a handful of readers.
+These are transported via @acronym{NNTP}, and are therefore news.  But we may need
+to read and answer a large fraction of the messages very carefully in
+order to do our work.  And there may not be an archive, so we may need
+to save the interesting messages the same way we would personal mail.
+
+The important distinction turns out to be not the transport mechanism,
+but other factors such as how interested we are in the subject matter,
+or how easy it is to retrieve the message if we need to read it again.
+
+Gnus provides many options for sorting mail into ``groups'' which behave
+like newsgroups, and for treating each group (whether mail or news)
+differently.
+
+Some users never get comfortable using the Gnus (ahem) paradigm and wish
+that Gnus should grow up and be a male, er, mail reader.  It is possible
+to whip Gnus into a more mailreaderly being, but, as said before, it's
+not easy.  People who prefer proper mail readers should try @sc{vm}
+instead, which is an excellent, and proper, mail reader.
+
+I don't mean to scare anybody off, but I want to make it clear that you
+may be required to learn a new way of thinking about messages.  After
+you've been subjected to The Gnus Way, you will come to love it.  I can
+guarantee it.  (At least the guy who sold me the Emacs Subliminal
+Brain-Washing Functions that I've put into Gnus did guarantee it.  You
+Will Be Assimilated.  You Love Gnus.  You Love The Gnus Mail Way.
+You Do.)
+
+
+@node Getting Started Reading Mail
+@subsection Getting Started Reading Mail
+
+It's quite easy to use Gnus to read your new mail.  You just plonk the
+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'' back end), you could put the following in your @file{~/.gnus.el} file:
+
+@lisp
+(setq gnus-secondary-select-methods '((nnml "")))
+@end lisp
+
+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 @file{~/Mail/} by default.  The new group that will
+be created (@samp{mail.misc}) will be subscribed, and you can read it
+like any other group.
+
+You will probably want to split the mail into several groups, though:
+
+@lisp
+(setq nnmail-split-methods
+      '(("junk" "^From:.*Lars Ingebrigtsen")
+        ("crazy" "^Subject:.*die\\|^Organization:.*flabby")
+        ("other" "")))
+@end lisp
+
+This will result in three new @code{nnml} mail groups being created:
+@samp{nnml:junk}, @samp{nnml:crazy}, and @samp{nnml:other}.  All the
+mail that doesn't fit into the first two groups will be placed in the
+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 Back End} and @pxref{Expiring Mail}.
+
+
+@node Splitting Mail
+@subsection Splitting Mail
+@cindex splitting mail
+@cindex mail splitting
+@cindex mail filtering (splitting)
+
+@vindex nnmail-split-methods
+The @code{nnmail-split-methods} variable says how the incoming mail is
+to be split into groups.
+
+@lisp
+(setq nnmail-split-methods
+  '(("mail.junk" "^From:.*Lars Ingebrigtsen")
+    ("mail.crazy" "^Subject:.*die\\|^Organization:.*flabby")
+    ("mail.other" "")))
+@end lisp
+
+This variable is a list of lists, where the first element of each of
+these lists is the name of the mail group (they do not have to be called
+something beginning with @samp{mail}, by the way), and the second
+element is a regular expression used on the header of each mail to
+determine if it belongs in this mail group.  The first string may
+contain @samp{\\1} forms, like the ones used by @code{replace-match} to
+insert sub-expressions from the matched text.  For instance:
+
+@lisp
+("list.\\1" "From:.* \\(.*\\)-list@@majordomo.com")
+@end lisp
+
+@noindent
+In that case, @code{nnmail-split-lowercase-expanded} controls whether
+the inserted text should be made lowercase.  @xref{Fancy Mail Splitting}.
+
+The second element can also be a function.  In that case, it will be
+called narrowed to the headers with the first element of the rule as the
+argument.  It should return a non-@code{nil} value if it thinks that the
+mail belongs in that group.
+
+@cindex @samp{bogus} group
+The last of these groups should always be a general one, and the regular
+expression should @emph{always} be @samp{""} so that it matches any mails
+that haven't been matched by any of the other regexps.  (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''.)  If no rule matched, the mail
+will end up in the @samp{bogus} group.  When new groups are created by
+splitting mail, you may want to run @code{gnus-group-find-new-groups} to
+see the new groups.  This also applies to the @samp{bogus} group.
+
+If you like to tinker with this yourself, you can set this variable to a
+function of your choice.  This function will be called without any
+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.
+
+This variable can also be a fancy split method.  For the syntax,
+see @ref{Fancy Mail Splitting}.
+
+Note that the mail back ends are free to maul the poor, innocent,
+incoming headers all they want to.  They all add @code{Lines} headers;
+some add @code{X-Gnus-Group} headers; most rename the Unix mbox
+@code{From<SPACE>} line to something else.
+
+@vindex nnmail-crosspost
+The mail 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.
+
+@vindex nnmail-crosspost-link-function
+@cindex crosspost
+@cindex links
+@code{nnmh} and @code{nnml} makes crossposts by creating hard links to
+the crossposted articles.  However, not all file systems support hard
+links.  If that's the case for you, set
+@code{nnmail-crosspost-link-function} to @code{copy-file}.  (This
+variable is @code{add-name-to-file} by default.)
+
+@kindex M-x nnmail-split-history
+@findex nnmail-split-history
+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}).
+
+@vindex nnmail-split-header-length-limit
+Header lines longer than the value of
+@code{nnmail-split-header-length-limit} are excluded from the split
+function.
+
+@vindex nnmail-mail-splitting-decodes
+@vindex nnmail-mail-splitting-charset
+By default, splitting does not decode headers, so you can not match on
+non-@acronym{ASCII} strings.  But it is useful if you want to match
+articles based on the raw header data.  To enable it, set the
+@code{nnmail-mail-splitting-decodes} variable to a non-@code{nil} value.
+In addition, the value of the @code{nnmail-mail-splitting-charset}
+variable is used for decoding non-@acronym{MIME} encoded string when
+@code{nnmail-mail-splitting-decodes} is non-@code{nil}.  The default
+value is @code{nil} which means not to decode non-@acronym{MIME} encoded
+string.  A suitable value for you will be @code{undecided} or be the
+charset used normally in mails you are interested in.
+
+@vindex nnmail-resplit-incoming
+By default, splitting is performed on all incoming messages.  If you
+specify a @code{directory} entry for the variable @code{mail-sources}
+(@pxref{Mail Source Specifiers}), however, then splitting does
+@emph{not} happen by default.  You can set the variable
+@code{nnmail-resplit-incoming} to a non-@code{nil} value to make
+splitting happen even in this case.  (This variable has no effect on
+other kinds of entries.)
+
+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
+all the mail you get from your boss.  And then you accidentally
+unsubscribe from the group.  Gnus will still put all the mail from your
+boss in the unsubscribed group, and so, when your boss mails you ``Have
+that report ready by Monday or you're fired!'', you'll never see it and,
+come Tuesday, you'll still believe that you're gainfully employed while
+you really should be out collecting empty bottles to save up for next
+month's rent money.
+
+
+@node Mail Sources
+@subsection Mail Sources
+
+Mail can be gotten from many different sources---the mail spool, from
+a @acronym{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 Functions::
+* Mail Source Customization::   Some variables that influence things.
+* Fetching Mail::               Using the mail source specifiers.
+@end menu
+
+
+@node Mail Source Specifiers
+@subsubsection Mail Source Specifiers
+@cindex POP
+@cindex mail server
+@cindex procmail
+@cindex mail spool
+@cindex mail source
+
+You tell Gnus how to fetch mail by setting @code{mail-sources}
+(@pxref{Fetching Mail}) to a @dfn{mail source specifier}.
+
+Here's an example:
+
+@lisp
+(pop :server "pop3.mailserver.com" :user "myname")
+@end lisp
+
+As can be observed, a mail source specifier is a list where the first
+element is a @dfn{mail source type}, followed by an arbitrary number of
+@dfn{keywords}.  Keywords that are not explicitly specified are given
+default values.
+
+The @code{mail-sources} is global for all mail groups.  You can specify
+an additional mail source for a particular group by including the
+@code{group} mail specifier in @code{mail-sources}, and setting a
+@code{mail-source} group parameter (@pxref{Group Parameters}) specifying
+a single mail source.  When this is used, @code{mail-sources} is
+typically just @code{(group)}; the @code{mail-source} parameter for a
+group might look like this:
+
+@lisp
+(mail-source . (file :path "home/user/spools/foo.spool"))
+@end lisp
+
+This means that the group's (and only this group's) messages will be
+fetched from the spool file @samp{/user/spools/foo.spool}.
+
+The following mail source types are available:
+
+@table @code
+@item file
+Get mail from a single file; typically from the mail spool.
+
+Keywords:
+
+@table @code
+@item :path
+The file name.  Defaults to the value of the @env{MAIL}
+environment variable or the value of @code{rmail-spool-directory}
+(usually something like @file{/usr/mail/spool/user-name}).
+
+@item :prescript
+@itemx :postscript
+Script run before/after fetching mail.
+@end table
+
+An example file mail source:
+
+@lisp
+(file :path "/usr/spool/mail/user-name")
+@end lisp
+
+Or using the default file name:
+
+@lisp
+(file)
+@end lisp
+
+If the mail spool file is not located on the local machine, it's best
+to use @acronym{POP} or @acronym{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.
+
+If it's impossible to set up a proper server, you can use ssh instead.
+
+@lisp
+(setq mail-sources
+      '((file :prescript "ssh host bin/getmail >%t")))
+@end lisp
+
+The @samp{getmail} script would look something like the following:
+
+@example
+#!/bin/sh
+#  getmail - move mail from spool to stdout
+#  flu@@iki.fi
+
+MOVEMAIL=/usr/lib/emacs/20.3/i386-redhat-linux/movemail
+TMP=$HOME/Mail/tmp
+rm -f $TMP; $MOVEMAIL $MAIL $TMP >/dev/null && cat $TMP
+@end example
+
+Alter this script to fit the @samp{movemail} and temporary
+file you want to use.
+
+
+@item directory
+@vindex nnmail-scan-directory-mail-source-once
+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, there is a one-to-one correspondence between files in that
+directory and groups, so that 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-@code{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.
+
+@vindex nnmail-resplit-incoming
+There is also the variable @code{nnmail-resplit-incoming}, if you set
+that to a non-@code{nil} value, then the normal splitting process is
+applied to all the files from the directory, @ref{Splitting Mail}.
+
+Keywords:
+
+@table @code
+@item :path
+The name of the directory where the files are.  There is no default
+value.
+
+@item :suffix
+Only files ending with this suffix are used.  The default is
+@samp{.spool}.
+
+@item :predicate
+Only files that have this predicate return non-@code{nil} are returned.
+The default is @code{identity}.  This is used as an additional
+filter---only files that have the right suffix @emph{and} satisfy this
+predicate are considered.
+
+@item :prescript
+@itemx :postscript
+Script run before/after fetching mail.
+
+@end table
+
+An example directory mail source:
+
+@lisp
+(directory :path "/home/user-name/procmail-dir/"
+           :suffix ".prcml")
+@end lisp
+
+@item pop
+Get mail from a @acronym{POP} server.
+
+Keywords:
+
+@table @code
+@item :server
+The name of the @acronym{POP} server.  The default is taken from the
+@env{MAILHOST} environment variable.
+
+@item :port
+The port number of the @acronym{POP} server.  This can be a number (e.g.,
+@samp{:port 1234}) or a string (e.g., @samp{:port "pop3"}).  If it is a
+string, it should be a service name as listed in @file{/etc/services} on
+Unix systems.  The default is @samp{"pop3"}.  On some systems you might
+need to specify it as @samp{"pop-3"} instead.
+
+@item :user
+The user name to give to the @acronym{POP} server.  The default is the login
+name.
+
+@item :password
+The password to give to the @acronym{POP} server.  If not specified,
+the user is prompted.
+
+@item :program
+The program to use to fetch mail from the @acronym{POP} server.  This
+should be a @code{format}-like string.  Here's an example:
+
+@example
+fetchmail %u@@%s -P %p %t
+@end example
+
+The valid format specifier characters are:
+
+@table @samp
+@item t
+The name of the file the mail is to be moved to.  This must always be
+included in this string.
+
+@item s
+The name of the server.
+
+@item P
+The port number of the server.
+
+@item u
+The user name to use.
+
+@item p
+The password to use.
+@end table
+
+The values used for these specs are taken from the values you give the
+corresponding keywords.
+
+@item :prescript
+A script to be run before fetching the mail.  The syntax is the same as
+the @code{:program} keyword.  This can also be a function to be run.
+
+One popular way to use this is to set up an SSH tunnel to access the
+@acronym{POP} server.  Here's an example:
+
+@lisp
+(pop :server "127.0.0.1"
+     :port 1234
+     :user "foo"
+     :password "secret"
+     :prescript
+     "nohup ssh -f -L 1234:pop.server:110 remote.host sleep 3600 &")
+@end lisp
+
+@item :postscript
+A script to be run after fetching the mail.  The syntax is the same as
+the @code{:program} keyword.  This can also be a function to be run.
+
+@item :function
+The function to use to fetch mail from the @acronym{POP} server.  The
+function is called with one parameter---the name of the file where the
+mail should be moved to.
+
+@item :authentication
+This can be either the symbol @code{password} or the symbol @code{apop}
+and says what authentication scheme to use.  The default is
+@code{password}.
+
+@item :leave
+Non-@code{nil} if the mail is to be left on the @acronym{POP} server
+after fetching.  Only the built-in @code{pop3-movemail} program (the
+default) supports this keyword.
+
+If this is a number, leave mails on the server for this many days since
+you first checked new mails.  In that case, mails once fetched will
+never be fetched again by the @acronym{UIDL} control.  If this is
+@code{nil} (the default), mails will be deleted on the server right
+after fetching.  If this is neither @code{nil} nor a number, all mails
+will be left on the server, and you will end up getting the same mails
+again and again.
+
+@vindex pop3-uidl-file
+The @code{pop3-uidl-file} variable specifies the file to which the
+@acronym{UIDL} data are locally stored.  The default value is
+@file{~/.pop3-uidl}.
+
+Note that @acronym{POP} servers maintain no state information between
+sessions, so what the client believes is there and what is actually
+there may not match up.  If they do not, then you may get duplicate
+mails or the whole thing can fall apart and leave you with a corrupt
+mailbox.
+
+@end table
+
+@findex pop3-movemail
+@vindex pop3-leave-mail-on-server
+If the @code{:program} and @code{:function} keywords aren't specified,
+@code{pop3-movemail} will be used.
+
+Here are some examples for getting mail from a @acronym{POP} server.
+
+Fetch from the default @acronym{POP} server, using the default user
+name, and default fetcher:
+
+@lisp
+(pop)
+@end lisp
+
+Fetch from a named server with a named user and password:
+
+@lisp
+(pop :server "my.pop.server"
+     :user "user-name" :password "secret")
+@end lisp
+
+Leave mails on the server for 14 days:
+
+@lisp
+(pop :server "my.pop.server"
+     :user "user-name" :password "secret"
+     :leave 14)
+@end lisp
+
+Use @samp{movemail} to move the mail:
+
+@lisp
+(pop :program "movemail po:%u %t %p")
+@end lisp
+
+@item maildir
+Get mail from a maildir.  This is a type of mailbox that is supported by
+at least qmail and postfix, where each file in a special directory
+contains exactly one mail.
+
+Keywords:
+
+@table @code
+@item :path
+The name of the directory where the mails are stored.  The default is
+taken from the @env{MAILDIR} environment variable or
+@file{~/Maildir/}.
+@item :subdirs
+The subdirectories of the Maildir.  The default is
+@samp{("new" "cur")}.
+
+@c If you sometimes look at your mail through a pop3 daemon before fetching
+@c them with Gnus, you may also have to fetch your mails from the
+@c @code{cur} directory inside the maildir, like in the first example
+@c below.
+
+You can also get mails from remote hosts (because maildirs don't suffer
+from locking problems).
+
+@end table
+
+Two example maildir mail sources:
+
+@lisp
+(maildir :path "/home/user-name/Maildir/"
+         :subdirs ("cur" "new"))
+@end lisp
+
+@lisp
+(maildir :path "/user@@remotehost.org:~/Maildir/"
+         :subdirs ("new"))
+@end lisp
+
+@item imap
+Get mail from a @acronym{IMAP} server.  If you don't want to use
+@acronym{IMAP} as intended, as a network mail reading protocol (i.e.,
+with nnimap), for some reason or other, Gnus let you treat it similar
+to a @acronym{POP} server and fetches articles from a given
+@acronym{IMAP} mailbox.  @xref{Using IMAP}, for more information.
+
+Keywords:
+
+@table @code
+@item :server
+The name of the @acronym{IMAP} server.  The default is taken from the
+@env{MAILHOST} environment variable.
+
+@item :port
+The port number of the @acronym{IMAP} server.  The default is @samp{143}, or
+@samp{993} for @acronym{TLS}/@acronym{SSL} connections.
+
+@item :user
+The user name to give to the @acronym{IMAP} server.  The default is the login
+name.
+
+@item :password
+The password to give to the @acronym{IMAP} server.  If not specified, the user is
+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{gssapi}, @samp{kerberos4}, @samp{starttls}, @samp{tls},
+@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{gssapi}, @samp{kerberos4}, @samp{digest-md5},
+@samp{cram-md5}, @samp{anonymous} or the default @samp{login}.
+
+@item :program
+When using the @samp{shell} :stream, the contents of this variable is
+mapped into the @code{imap-shell-program} variable.  This should be a
+@code{format}-like string (or list of strings).  Here's an example:
+
+@example
+ssh %s imapd
+@end example
+
+Make sure nothing is interfering with the output of the program, e.g.,
+don't forget to redirect the error output to the void.  The valid format
+specifier characters are:
+
+@table @samp
+@item s
+The name of the server.
+
+@item l
+User name from @code{imap-default-user}.
+
+@item p
+The port number of the server.
+@end table
+
+The values used for these specs are taken from the values you give the
+corresponding keywords.
+
+@item :mailbox
+The name of the mailbox to get mail from.  The default is @samp{INBOX}
+which normally is the mailbox which receives incoming mail. Instead of
+a single mailbox, this can be a list of mailboxes to fetch mail from.
+
+@item :predicate
+The predicate used to find articles to fetch.  The default, @samp{UNSEEN
+UNDELETED}, is probably the best choice for most people, but if you
+sometimes peek in your mailbox with a @acronym{IMAP} client and mark some
+articles as read (or; SEEN) you might want to set this to @samp{1:*}.
+Then all articles in the mailbox is fetched, no matter what.  For a
+complete list of predicates, see RFC 2060 section 6.4.4.
+
+@item :fetchflag
+How to flag fetched articles on the server, the default @samp{\Deleted}
+will mark them as deleted, an alternative would be @samp{\Seen} which
+would simply mark them as read.  These are the two most likely choices,
+but more flags are defined in RFC 2060 section 2.3.2.
+
+@item :dontexpunge
+If non-@code{nil}, don't remove all articles marked as deleted in the
+mailbox after finishing the fetch.
+
+@end table
+
+An example @acronym{IMAP} mail source:
+
+@lisp
+(imap :server "mail.mycorp.com"
+      :stream kerberos4
+      :fetchflag "\\Seen")
+@end lisp
+
+@item group
+Get the actual mail source from the @code{mail-source} group parameter,
+@xref{Group Parameters}.
+
+@end table
+
+@table @dfn
+@item Common Keywords
+Common keywords can be used in any type of mail source.
+
+Keywords:
+
+@table @code
+@item :plugged
+If non-@code{nil}, fetch the mail even when Gnus is unplugged.  If you
+use directory source to get mail, you can specify it as in this
+example:
+
+@lisp
+(setq mail-sources
+      '((directory :path "/home/pavel/.Spool/"
+                   :suffix ""
+                   :plugged t)))
+@end lisp
+
+Gnus will then fetch your mail even when you are unplugged.  This is
+useful when you use local mail and news.
+
+@end table
+@end table
+
+@node Mail Source Functions
+@subsubsection Function Interface
+
+Some of the above keywords specify a Lisp function to be executed.
+For each keyword @code{:foo}, the Lisp variable @code{foo} is bound to
+the value of the keyword while the function is executing.  For example,
+consider the following mail-source setting:
+
+@lisp
+(setq mail-sources '((pop :user "jrl"
+                          :server "pophost" :function fetchfunc)))
+@end lisp
+
+While the function @code{fetchfunc} is executing, the symbol @code{user}
+is bound to @code{"jrl"}, and the symbol @code{server} is bound to
+@code{"pophost"}.  The symbols @code{port}, @code{password},
+@code{program}, @code{prescript}, @code{postscript}, @code{function},
+and @code{authentication} are also bound (to their default values).
+
+See above for a list of keywords for each type of mail source.
+
+
+@node Mail Source Customization
+@subsubsection Mail Source Customization
+
+The following is a list of variables that influence how the mail is
+fetched.  You would normally not need to set or change any of these
+variables.
+
+@table @code
+@item mail-source-crash-box
+@vindex mail-source-crash-box
+File where mail will be stored while processing it.  The default is@*
+@file{~/.emacs-mail-crash-box}.
+
+@cindex Incoming*
+@item mail-source-delete-incoming
+@vindex mail-source-delete-incoming
+If non-@code{nil}, delete incoming files after handling them.  If
+@code{t}, delete the files immediately, if @code{nil}, never delete any
+files.  If a positive number, delete files older than number of days
+(the deletion will only happen when receiving new mail).  You may also
+set @code{mail-source-delete-incoming} to @code{nil} and call
+@code{mail-source-delete-old-incoming} from a hook or interactively.
+@code{mail-source-delete-incoming} defaults to @code{10} in alpha Gnusae
+and @code{2} in released Gnusae.  @xref{Gnus Development}.
+
+@item mail-source-delete-old-incoming-confirm
+@vindex mail-source-delete-old-incoming-confirm
+If non-@code{nil}, ask for confirmation before deleting old incoming
+files.  This variable only applies when
+@code{mail-source-delete-incoming} is a positive number.
+
+@item mail-source-ignore-errors
+@vindex mail-source-ignore-errors
+If non-@code{nil}, ignore errors when reading mail from a mail source.
+
+@item mail-source-directory
+@vindex mail-source-directory
+Directory where incoming mail source files (if any) will be stored.  The
+default is @file{~/Mail/}.  At present, the only thing this is used for
+is to say where the incoming files will be stored if the variable
+@code{mail-source-delete-incoming} is @code{nil} or a number.
+
+@item mail-source-incoming-file-prefix
+@vindex mail-source-incoming-file-prefix
+Prefix for file name for storing incoming mail.  The default is
+@file{Incoming}, in which case files will end up with names like
+@file{Incoming30630D_} or @file{Incoming298602ZD}.  This is really only
+relevant if @code{mail-source-delete-incoming} is @code{nil} or a
+number.
+
+@item mail-source-default-file-modes
+@vindex mail-source-default-file-modes
+All new mail files will get this file mode.  The default is @code{#o600}.
+
+@item mail-source-movemail-program
+@vindex mail-source-movemail-program
+If non-@code{nil}, name of program for fetching new mail.  If
+@code{nil}, @code{movemail} in @var{exec-directory}.
+
+@end table
+
+
+@node Fetching Mail
+@subsubsection Fetching Mail
+
+@vindex mail-sources
+The way to actually tell Gnus where to get new mail from is to set
+@code{mail-sources} to a list of mail source specifiers
+(@pxref{Mail Source Specifiers}).
+
+If this variable is @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
+@acronym{POP} mail server, you'd say something like:
+
+@lisp
+(setq mail-sources
+      '((file)
+        (pop :server "pop3.mail.server"
+             :password "secret")))
+@end lisp
+
+Or, if you don't want to use any of the keyword defaults:
+
+@lisp
+(setq mail-sources
+      '((file :path "/var/spool/mail/user-name")
+        (pop :server "pop3.mail.server"
+             :user "user-name"
+             :port "pop3"
+             :password "secret")))
+@end lisp
+
+
+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 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 Back End Variables
+@subsection Mail Back End Variables
+
+These variables are (for the most part) pertinent to all the various
+mail back ends.
+
+@table @code
+@vindex nnmail-read-incoming-hook
+@item nnmail-read-incoming-hook
+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
+@item nnmail-split-hook
+@findex gnus-article-decode-encoded-words
+@cindex RFC 1522 decoding
+@cindex RFC 2047 decoding
+Hook run in the buffer where the mail headers of each message is kept
+just before the splitting based on these headers is done.  The hook is
+free to modify the buffer contents in any way it sees fit---the buffer
+is discarded after the splitting has been done, and no changes performed
+in the buffer will show up in any files.
+@code{gnus-article-decode-encoded-words} is one likely function to add
+to this hook.
+
+@vindex nnmail-pre-get-new-mail-hook
+@vindex nnmail-post-get-new-mail-hook
+@item nnmail-pre-get-new-mail-hook
+@itemx nnmail-post-get-new-mail-hook
+These are two useful hooks executed when treating new incoming
+mail---@code{nnmail-pre-get-new-mail-hook} (is called just before
+starting to handle the new mail) and
+@code{nnmail-post-get-new-mail-hook} (is called when the mail handling
+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 'nnmail-pre-get-new-mail-hook
+          (lambda () (set-default-file-modes #o700)))
+
+(add-hook 'nnmail-post-get-new-mail-hook
+          (lambda () (set-default-file-modes #o775)))
+@end lisp
+
+@item nnmail-use-long-file-names
+@vindex nnmail-use-long-file-names
+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} 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
+@vindex nnmail-delete-file-function
+@findex delete-file
+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 back end (via @code{Gcc}, for instance) into the mail duplication
+discovery cache.  The default is @code{nil}.
+
+@item nnmail-cache-ignore-groups
+@vindex nnmail-cache-ignore-groups
+This can be a regular expression or a list of regular expressions.
+Group names that match any of the regular expressions will never be
+recorded in the @code{Message-ID} cache.
+
+This can be useful, for example, when using Fancy Splitting
+(@pxref{Fancy Mail Splitting}) together with the function
+@code{nnmail-split-fancy-with-parent}.
+
+@end table
+
+
+@node Fancy Mail Splitting
+@subsection Fancy Mail Splitting
+@cindex mail splitting
+@cindex fancy mail splitting
+
+@vindex nnmail-split-fancy
+@findex nnmail-split-fancy
+If the rather simple, standard method for specifying how to split mail
+doesn't allow you to do what you want, you can set
+@code{nnmail-split-methods} to @code{nnmail-split-fancy}.  Then you can
+play with the @code{nnmail-split-fancy} variable.
+
+Let's look at an example value of this variable first:
+
+@lisp
+;; @r{Messages from the mailer daemon are not crossposted to any of}
+;; @r{the ordinary groups.  Warnings are put in a separate group}
+;; @r{from real errors.}
+(| ("from" mail (| ("subject" "warn.*" "mail.warning")
+                   "mail.misc"))
+   ;; @r{Non-error messages are crossposted to all relevant}
+   ;; @r{groups, but we don't crosspost between the group for the}
+   ;; @r{(ding) list and the group for other (ding) related mail.}
+   (& (| (any "ding@@ifi\\.uio\\.no" "ding.list")
+         ("subject" "ding" "ding.misc"))
+      ;; @r{Other mailing lists@dots{}}
+      (any "procmail@@informatik\\.rwth-aachen\\.de" "procmail.list")
+      (any "SmartList@@informatik\\.rwth-aachen\\.de" "SmartList.list")
+      ;; @r{Both lists below have the same suffix, so prevent}
+      ;; @r{cross-posting to mkpkg.list of messages posted only to}
+      ;; @r{the bugs- list, but allow cross-posting when the}
+      ;; @r{message was really cross-posted.}
+      (any "bugs-mypackage@@somewhere" "mypkg.bugs")
+      (any "mypackage@@somewhere" - "bugs-mypackage" "mypkg.list")
+      ;; @r{People@dots{}}
+      (any "larsi@@ifi\\.uio\\.no" "people.Lars_Magne_Ingebrigtsen"))
+   ;; @r{Unmatched mail goes to the catch all group.}
+   "misc.misc")
+@end lisp
+
+This variable has the format of a @dfn{split}.  A split is a
+(possibly) recursive structure where each split may contain other
+splits.  Here are the possible split syntaxes:
+
+@table @code
+
+@item group
+If the split is a string, that will be taken as a group name.  Normal
+regexp match expansion will be done.  See below for examples.
+
+@c Don't fold this line.
+@item (@var{field} @var{value} [- @var{restrict} [@dots{}] ] @var{split} [@var{invert-partial}])
+The split can be a list containing at least three elements.  If the
+first element @var{field} (a regexp matching a header) contains
+@var{value} (also a regexp) then store the message as specified by
+@var{split}.
+
+If @var{restrict} (yet another regexp) matches some string after
+@var{field} and before the end of the matched @var{value}, the
+@var{split} is ignored.  If none of the @var{restrict} clauses match,
+@var{split} is processed.
+
+The last element @var{invert-partial} is optional.  If it is
+non-@code{nil}, the match-partial-words behavior controlled by the
+variable @code{nnmail-split-fancy-match-partial-words} (see below) is
+be inverted.  (New in Gnus 5.10.7)
+
+@item (| @var{split} @dots{})
+If the split is a list, and the first element is @code{|} (vertical
+bar), then process each @var{split} until one of them matches.  A
+@var{split} is said to match if it will cause the mail message to be
+stored in one or more groups.
+
+@item (& @var{split} @dots{})
+If the split is a list, and the first element is @code{&}, then
+process all @var{split}s in the list.
+
+@item junk
+If the split is the symbol @code{junk}, then don't save (i.e., delete)
+this message.  Use with extreme caution.
+
+@item (: @var{function} @var{arg1} @var{arg2} @dots{})
+If the split is a list, and the first element is @samp{:}, then the
+second element will be called as a function with @var{args} given as
+arguments.  The function should return a @var{split}.
+
+@cindex body split
+For instance, the following function could be used to split based on the
+body of the messages:
+
+@lisp
+(defun split-on-body ()
+  (save-excursion
+    (save-restriction
+      (widen)
+      (goto-char (point-min))
+      (when (re-search-forward "Some.*string" nil t)
+        "string.group"))))
+@end lisp
+
+The buffer is narrowed to the header of the message in question when
+@var{function} is run.  That's why @code{(widen)} needs to be called
+after @code{save-excursion} and @code{save-restriction} in the example
+above.  Also note that with the nnimap backend, message bodies will
+not be downloaded by default.  You need to set
+@code{nnimap-split-download-body} to @code{t} to do that
+(@pxref{Client-Side IMAP Splitting}).
+
+@item (! @var{func} @var{split})
+If the split is a list, and the first element is @code{!}, then
+@var{split} will be processed, and @var{func} will be called as a
+function with the result of @var{split} as argument.  @var{func}
+should return a split.
+
+@item nil
+If the split is @code{nil}, it is ignored.
+
+@end table
+
+In these splits, @var{field} must match a complete field name.
+
+Normally, @var{value} in these splits must match a complete @emph{word}
+according to the fundamental mode syntax table.  In other words, all
+@var{value}'s will be implicitly surrounded by @code{\<...\>} markers,
+which are word delimiters.  Therefore, if you use the following split,
+for example,
+
+@example
+(any "joe" "joemail")
+@end example
+
+@noindent
+messages sent from @samp{joedavis@@foo.org} will normally not be filed
+in @samp{joemail}.  If you want to alter this behavior, you can use any
+of the following three ways:
+
+@enumerate
+@item
+@vindex nnmail-split-fancy-match-partial-words
+You can set the @code{nnmail-split-fancy-match-partial-words} variable
+to non-@code{nil} in order to ignore word boundaries and instead the
+match becomes more like a grep.  This variable controls whether partial
+words are matched during fancy splitting.  The default value is
+@code{nil}.
+
+Note that it influences all @var{value}'s in your split rules.
+
+@item
+@var{value} beginning with @code{.*} ignores word boundaries in front of
+a word.  Similarly, if @var{value} ends with @code{.*}, word boundaries
+in the rear of a word will be ignored.  For example, the @var{value}
+@code{"@@example\\.com"} does not match @samp{foo@@example.com} but
+@code{".*@@example\\.com"} does.
+
+@item
+You can set the @var{invert-partial} flag in your split rules of the
+@samp{(@var{field} @var{value} @dots{})} types, aforementioned in this
+section.  If the flag is set, word boundaries on both sides of a word
+are ignored even if @code{nnmail-split-fancy-match-partial-words} is
+@code{nil}.  Contrarily, if the flag is set, word boundaries are not
+ignored even if @code{nnmail-split-fancy-match-partial-words} is
+non-@code{nil}.  (New in Gnus 5.10.7)
+@end enumerate
+
+@vindex nnmail-split-abbrev-alist
+@var{field} and @var{value} can also be Lisp symbols, in that case
+they are expanded as specified by the variable
+@code{nnmail-split-abbrev-alist}.  This is an alist of cons cells,
+where the @sc{car} of a cell contains the key, and the @sc{cdr}
+contains the associated value.  Predefined entries in
+@code{nnmail-split-abbrev-alist} include:
+
+@table @code
+@item from
+Matches the @samp{From}, @samp{Sender} and @samp{Resent-From} fields.
+@item to
+Matches the @samp{To}, @samp{Cc}, @samp{Apparently-To},
+@samp{Resent-To} and @samp{Resent-Cc} fields.
+@item any
+Is the union of the @code{from} and @code{to} entries.
+@end table
+
+@vindex nnmail-split-fancy-syntax-table
+@code{nnmail-split-fancy-syntax-table} is the syntax table in effect
+when all this splitting is performed.
+
+If you want to have Gnus create groups dynamically based on some
+information in the headers (i.e., do @code{replace-match}-like
+substitutions in the group names), you can say things like:
+
+@example
+(any "debian-\\b\\(\\w+\\)@@lists.debian.org" "mail.debian.\\1")
+@end example
+
+In this example, messages sent to @samp{debian-foo@@lists.debian.org}
+will be filed in @samp{mail.debian.foo}.
+
+If the string contains the element @samp{\\&}, then the previously
+matched string will be substituted.  Similarly, the elements @samp{\\1}
+up to @samp{\\9} will be substituted with the text matched by the
+groupings 1 through 9.
+
+@vindex nnmail-split-lowercase-expanded
+Where @code{nnmail-split-lowercase-expanded} controls whether the
+lowercase of the matched string should be used for the substitution.
+Setting it as non-@code{nil} is useful to avoid the creation of multiple
+groups when users send to an address using different case
+(i.e., mailing-list@@domain vs Mailing-List@@Domain).  The default value
+is @code{t}.
+
+@findex nnmail-split-fancy-with-parent
+@code{nnmail-split-fancy-with-parent} is a function which allows you to
+split followups into the same groups their parents are in.  Sometimes
+you can't make splitting rules for all your mail.  For example, your
+boss might send you personal mail regarding different projects you are
+working on, and as you can't tell your boss to put a distinguishing
+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}
+and @code{nnmail-cache-accepted-message-ids} to a non-@code{nil}
+value.  And then you can include @code{nnmail-split-fancy-with-parent}
+using the colon feature, like so:
+@lisp
+(setq nnmail-treat-duplicates 'warn     ; @r{or @code{delete}}
+      nnmail-cache-accepted-message-ids t
+      nnmail-split-fancy
+      '(| (: nnmail-split-fancy-with-parent)
+          ;; @r{other splits go here}
+        ))
+@end lisp
+
+This feature works as follows: when @code{nnmail-treat-duplicates} is
+non-@code{nil}, Gnus records the message id of every message it sees
+in the file specified by the variable
+@code{nnmail-message-id-cache-file}, together with the group it is in
+(the group is omitted for non-mail 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 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
+messages goes into the new group.
+
+Also see the variable @code{nnmail-cache-ignore-groups} if you don't
+want certain groups to be recorded in the cache.  For example, if all
+outgoing messages are written to an ``outgoing'' group, you could set
+@code{nnmail-cache-ignore-groups} to match that group name.
+Otherwise, answers to all your messages would end up in the
+``outgoing'' group.
+
+
+@node Group Mail Splitting
+@subsection Group Mail Splitting
+@cindex mail splitting
+@cindex group mail splitting
+
+@findex gnus-group-split
+If you subscribe to dozens of mailing lists but you don't want to
+maintain mail splitting rules manually, group mail splitting is for you.
+You just have to set @code{to-list} and/or @code{to-address} in group
+parameters or group customization and set @code{nnmail-split-methods} to
+@code{gnus-group-split}.  This splitting function will scan all groups
+for those parameters and split mail accordingly, i.e., messages posted
+from or to the addresses specified in the parameters @code{to-list} or
+@code{to-address} of a mail group will be stored in that group.
+
+Sometimes, mailing lists have multiple addresses, and you may want mail
+splitting to recognize them all: just set the @code{extra-aliases} group
+parameter to the list of additional addresses and it's done.  If you'd
+rather use a regular expression, set @code{split-regexp}.
+
+All these parameters in a group will be used to create an
+@code{nnmail-split-fancy} split, in which the @var{field} is @samp{any},
+the @var{value} is a single regular expression that matches
+@code{to-list}, @code{to-address}, all of @code{extra-aliases} and all
+matches of @code{split-regexp}, and the @var{split} is the name of the
+group.  @var{restrict}s are also supported: just set the
+@code{split-exclude} parameter to a list of regular expressions.
+
+If you can't get the right split to be generated using all these
+parameters, or you just need something fancier, you can set the
+parameter @code{split-spec} to an @code{nnmail-split-fancy} split.  In
+this case, all other aforementioned parameters will be ignored by
+@code{gnus-group-split}.  In particular, @code{split-spec} may be set to
+@code{nil}, in which case the group will be ignored by
+@code{gnus-group-split}.
+
+@vindex gnus-group-split-default-catch-all-group
+@code{gnus-group-split} will do cross-posting on all groups that match,
+by defining a single @code{&} fancy split containing one split for each
+group.  If a message doesn't match any split, it will be stored in the
+group named in @code{gnus-group-split-default-catch-all-group}, unless
+some group has @code{split-spec} set to @code{catch-all}, in which case
+that group is used as the catch-all group.  Even though this variable is
+often used just to name a group, it may also be set to an arbitrarily
+complex fancy split (after all, a group name is a fancy split), and this
+may be useful to split mail that doesn't go to any mailing list to
+personal mail folders.  Note that this fancy split is added as the last
+element of a @code{|} split list that also contains a @code{&} split
+with the rules extracted from group parameters.
+
+It's time for an example.  Assume the following group parameters have
+been defined:
+
+@example
+nnml:mail.bar:
+((to-address . "bar@@femail.com")
+ (split-regexp . ".*@@femail\\.com"))
+nnml:mail.foo:
+((to-list . "foo@@nowhere.gov")
+ (extra-aliases "foo@@localhost" "foo-redist@@home")
+ (split-exclude "bugs-foo" "rambling-foo")
+ (admin-address . "foo-request@@nowhere.gov"))
+nnml:mail.others:
+((split-spec . catch-all))
+@end example
+
+Setting @code{nnmail-split-methods} to @code{gnus-group-split} will
+behave as if @code{nnmail-split-fancy} had been selected and variable
+@code{nnmail-split-fancy} had been set as follows:
+
+@lisp
+(| (& (any "\\(bar@@femail\\.com\\|.*@@femail\\.com\\)" "mail.bar")
+      (any "\\(foo@@nowhere\\.gov\\|foo@@localhost\\|foo-redist@@home\\)"
+           - "bugs-foo" - "rambling-foo" "mail.foo"))
+   "mail.others")
+@end lisp
+
+@findex gnus-group-split-fancy
+If you'd rather not use group splitting for all your mail groups, you
+may use it for only some of them, by using @code{nnmail-split-fancy}
+splits like this:
+
+@lisp
+(: gnus-group-split-fancy @var{groups} @var{no-crosspost} @var{catch-all})
+@end lisp
+
+@var{groups} may be a regular expression or a list of group names whose
+parameters will be scanned to generate the output split.
+@var{no-crosspost} can be used to disable cross-posting; in this case, a
+single @code{|} split will be output.  @var{catch-all} is the fall back
+fancy split, used like @code{gnus-group-split-default-catch-all-group}.
+If @var{catch-all} is @code{nil}, or if @code{split-regexp} matches the
+empty string in any selected group, no catch-all split will be issued.
+Otherwise, if some group has @code{split-spec} set to @code{catch-all},
+this group will override the value of the @var{catch-all} argument.
+
+@findex gnus-group-split-setup
+Unfortunately, scanning all groups and their parameters can be quite
+slow, especially considering that it has to be done for every message.
+But don't despair!  The function @code{gnus-group-split-setup} can be
+used to enable @code{gnus-group-split} in a much more efficient way.  It
+sets @code{nnmail-split-methods} to @code{nnmail-split-fancy} and sets
+@code{nnmail-split-fancy} to the split produced by
+@code{gnus-group-split-fancy}.  Thus, the group parameters are only
+scanned once, no matter how many messages are split.
+
+@findex gnus-group-split-update
+However, if you change group parameters, you'd have to update
+@code{nnmail-split-fancy} manually.  You can do it by running
+@code{gnus-group-split-update}.  If you'd rather have it updated
+automatically, just tell @code{gnus-group-split-setup} to do it for
+you.  For example, add to your @file{~/.gnus.el}:
+
+@lisp
+(gnus-group-split-setup @var{auto-update} @var{catch-all})
+@end lisp
+
+If @var{auto-update} is non-@code{nil}, @code{gnus-group-split-update}
+will be added to @code{nnmail-pre-get-new-mail-hook}, so you won't ever
+have to worry about updating @code{nnmail-split-fancy} again.  If you
+don't omit @var{catch-all} (it's optional, equivalent to @code{nil}),
+@code{gnus-group-split-default-catch-all-group} will be set to its
+value.
+
+@vindex gnus-group-split-updated-hook
+Because you may want to change @code{nnmail-split-fancy} after it is set
+by @code{gnus-group-split-update}, this function will run
+@code{gnus-group-split-updated-hook} just before finishing.
+
+@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
+back ends, you'll probably wish to have that old mail incorporated into
+your mail groups.
+
+Doing so can be quite easy.
+
+To take an example: You're reading mail using @code{nnml}
+(@pxref{Mail Spool}), and have set @code{nnmail-split-methods} to a
+satisfactory value (@pxref{Splitting Mail}).  You have an old Unix mbox
+file filled with important, but old, mail.  You want to move it into
+your @code{nnml} groups.
+
+Here's how:
+
+@enumerate
+@item
+Go to the group buffer.
+
+@item
+Type @kbd{G f} and give the file name to the mbox file when prompted to create an
+@code{nndoc} group from the mbox file (@pxref{Foreign Groups}).
+
+@item
+Type @kbd{SPACE} to enter the newly created group.
+
+@item
+Type @kbd{M P b} to process-mark all articles in this group's buffer
+(@pxref{Setting Process Marks}).
+
+@item
+Type @kbd{B r} to respool all the process-marked articles, and answer
+@samp{nnml} when prompted (@pxref{Mail Group Commands}).
+@end enumerate
+
+All the mail messages in the mbox file will now also be spread out over
+all your @code{nnml} groups.  Try entering them and check whether things
+have gone without a glitch.  If things look ok, you may consider
+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
+back end to another.  Just respool all the mail in the old mail groups
+using the new mail back end.
+
+
+@node Expiring Mail
+@subsection Expiring Mail
+@cindex article expiry
+@cindex expiring mail
+
+Traditional mail readers have a tendency to remove mail articles when
+you mark them as read, in some way.  Gnus takes a fundamentally
+different approach to mail reading.
+
+Gnus basically considers mail just to be news that has been received in
+a rather peculiar manner.  It does not think that it has the power to
+actually change the mail, or delete any mail messages.  If you enter a
+mail group, and mark articles as ``read'', or kill them in some other
+fashion, the mail articles will still exist on the system.  I repeat:
+Gnus will not delete your old, read mail.  Unless you ask it to, of
+course.
+
+To make Gnus get rid of your unwanted mail, you have to mark the
+articles as @dfn{expirable}.  (With the default key bindings, this means
+that you have to type @kbd{E}.)  This does not mean that the articles
+will disappear right away, however.  In general, a mail article will be
+deleted from your system if, 1) it is marked as expirable, AND 2) it is
+more than one week old.  If you do not mark an article as expirable, it
+will remain on your system until hell freezes over.  This bears
+repeating one more time, with some spurious capitalizations: IF you do
+NOT mark articles as EXPIRABLE, Gnus will NEVER delete those ARTICLES.
+
+@vindex gnus-auto-expirable-marks
+You do not have to mark articles as expirable by hand.  Gnus provides
+two features, called ``auto-expire'' and ``total-expire'', that can help you
+with this.  In a nutshell, ``auto-expire'' means that Gnus hits @kbd{E}
+for you when you select an article.  And ``total-expire'' means that Gnus
+considers all articles as expirable that are read.  So, in addition to
+the articles marked @samp{E}, also the articles marked @samp{r},
+@samp{R}, @samp{O}, @samp{K}, @samp{Y} (and so on) are considered
+expirable.  @code{gnus-auto-expirable-marks} has the full list of
+these marks.
+
+When should either auto-expire or total-expire be used?  Most people
+who are subscribed to mailing lists split each list into its own group
+and then turn on auto-expire or total-expire for those groups.
+(@xref{Splitting Mail}, for more information on splitting each list
+into its own group.)
+
+Which one is better, auto-expire or total-expire?  It's not easy to
+answer.  Generally speaking, auto-expire is probably faster.  Another
+advantage of auto-expire is that you get more marks to work with: for
+the articles that are supposed to stick around, you can still choose
+between tick and dormant and read marks.  But with total-expire, you
+only have dormant and ticked to choose from.  The advantage of
+total-expire is that it works well with adaptive scoring (@pxref{Adaptive
+Scoring}).  Auto-expire works with normal scoring but not with adaptive
+scoring.
+
+@vindex gnus-auto-expirable-newsgroups
+Groups that match the regular expression
+@code{gnus-auto-expirable-newsgroups} will have all articles that you
+read marked as expirable automatically.  All articles marked as
+expirable have an @samp{E} in the first column in the summary buffer.
+
+By default, if you have auto expiry switched on, Gnus will mark all the
+articles you read as expirable, no matter if they were read or unread
+before.  To avoid having articles marked as read marked as expirable
+automatically, you can put something like the following in your
+@file{~/.gnus.el} file:
+
+@vindex gnus-mark-article-hook
+@lisp
+(remove-hook 'gnus-mark-article-hook
+             'gnus-summary-mark-read-and-unread-as-read)
+(add-hook 'gnus-mark-article-hook 'gnus-summary-mark-unread-as-read)
+@end lisp
+
+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
+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
+articles you have read to disappear after a while:
+
+@lisp
+(setq gnus-auto-expirable-newsgroups
+      "mail.nonsense-list\\|mail.nice-list")
+@end lisp
+
+Another way to have auto-expiry happen is to have the element
+@code{auto-expire} in the group parameters of the group.
+
+If you use adaptive scoring (@pxref{Adaptive Scoring}) and
+auto-expiring, you'll have problems.  Auto-expiring and adaptive scoring
+don't really mix very well.
+
+@vindex nnmail-expiry-wait
+The @code{nnmail-expiry-wait} variable supplies the default time an
+expirable article has to live.  Gnus starts counting days from when the
+message @emph{arrived}, not from when it was sent.  The default is seven
+days.
+
+Gnus also supplies a function that lets you fine-tune how long articles
+are to live, based on what group they are in.  Let's say you want to
+have one month expiry period in the @samp{mail.private} group, a one day
+expiry period in the @samp{mail.junk} group, and a six day expiry period
+everywhere else:
+
+@vindex nnmail-expiry-wait-function
+@lisp
+(setq nnmail-expiry-wait-function
+      (lambda (group)
+       (cond ((string= group "mail.private")
+               31)
+             ((string= group "mail.junk")
+               1)
+             ((string= group "important")
+               'never)
+             (t
+               6))))
+@end lisp
+
+The group names this function is fed are ``unadorned'' group
+names---no @samp{nnml:} prefixes and the like.
+
+The @code{nnmail-expiry-wait} variable and
+@code{nnmail-expiry-wait-function} function can either be a number (not
+necessarily an integer) or one of the symbols @code{immediate} or
+@code{never}.
+
+You can also use the @code{expiry-wait} group parameter to selectively
+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}.
+
+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
+expire the final article in a mail newsgroup.  This is to make life
+easier for procmail users.
+
+@vindex gnus-total-expirable-newsgroups
+By the way: That line up there, about Gnus never expiring non-expirable
+articles, is a lie.  If you put @code{total-expire} in the group
+parameters, articles will not be marked as expirable, but all read
+articles will be put through the expiry process.  Use with extreme
+caution.  Even more dangerous is the
+@code{gnus-total-expirable-newsgroups} variable.  All groups that match
+this regexp will have all read articles put through the expiry process,
+which means that @emph{all} old mail articles in the groups in question
+will be deleted after a while.  Use with extreme caution, and don't come
+crying to me when you discover that the regexp you used matched the
+wrong group and all your important mail has disappeared.  Be a
+@emph{man}!  Or a @emph{woman}!  Whatever you feel more comfortable
+with!  So there!
+
+Most people make most of their mail groups total-expirable, though.
+
+@vindex gnus-inhibit-user-auto-expire
+If @code{gnus-inhibit-user-auto-expire} is non-@code{nil}, user marking
+commands will not mark an article as expirable, even if the group has
+auto-expire turned on.
+
+@vindex gnus-mark-copied-or-moved-articles-as-expirable
+The expirable marks of articles will be removed when copying or moving
+them to a group in which auto-expire is not turned on.  This is for
+preventing articles from being expired unintentionally.  On the other
+hand, to a group that has turned auto-expire on, the expirable marks of
+articles that are copied or moved will not be changed by default.  I.e.,
+when copying or moving to such a group, articles that were expirable
+will be left expirable and ones that were not expirable will not be
+marked as expirable.  So, even though in auto-expire groups, some
+articles will never get expired (unless you read them again).  If you
+don't side with that behavior that unexpirable articles may be mixed
+into auto-expire groups, you can set
+@code{gnus-mark-copied-or-moved-articles-as-expirable} to a
+non-@code{nil} value.  In that case, articles that have been read will
+be marked as expirable automatically when being copied or moved to a
+group that has auto-expire turned on.  The default value is @code{nil}.
+
+
+@node Washing Mail
+@subsection Washing Mail
+@cindex mail washing
+@cindex list server brain damage
+@cindex incoming mail treatment
+
+Mailers and list servers are notorious for doing all sorts of really,
+really stupid things with mail.  ``Hey, RFC 822 doesn't explicitly
+prohibit us from adding the string @code{wE aRe ElItE!!!!!1!!} to the
+end of all lines passing through our server, so let's do that!!!!1!''
+Yes, but RFC 822 wasn't designed to be read by morons.  Things that were
+considered to be self-evident were not discussed.  So.  Here we are.
+
+Case in point:  The German version of Microsoft Exchange adds @samp{AW:
+} to the subjects of replies instead of @samp{Re: }.  I could pretend to
+be shocked and dismayed by this, but I haven't got the energy.  It is to
+laugh.
+
+Gnus provides a plethora of functions for washing articles while
+displaying them, but it might be nicer to do the filtering before
+storing the mail to disk.  For that purpose, we have three hooks and
+various functions that can be put in these hooks.
+
+@table @code
+@item nnmail-prepare-incoming-hook
+@vindex nnmail-prepare-incoming-hook
+This hook is called before doing anything with the mail and is meant for
+grand, sweeping gestures.  It is called in a buffer that contains all
+the new, incoming mail.  Functions to be used include:
+
+@table @code
+@item nnheader-ms-strip-cr
+@findex nnheader-ms-strip-cr
+Remove trailing carriage returns from each line.  This is default on
+Emacs running on MS machines.
+
+@end table
+
+@item nnmail-prepare-incoming-header-hook
+@vindex nnmail-prepare-incoming-header-hook
+This hook is called narrowed to each header.  It can be used when
+cleaning up the headers.  Functions that can be used include:
+
+@table @code
+@item nnmail-remove-leading-whitespace
+@findex nnmail-remove-leading-whitespace
+Clear leading white space that ``helpful'' listservs have added to the
+headers to make them look nice.  Aaah.
+
+(Note that this function works on both the header on the body of all
+messages, so it is a potentially dangerous function to use (if a body
+of a message contains something that looks like a header line).  So
+rather than fix the bug, it is of course the right solution to make it
+into a feature by documenting it.)
+
+@item nnmail-remove-list-identifiers
+@findex nnmail-remove-list-identifiers
+Some list servers add an identifier---for example, @samp{(idm)}---to the
+beginning of all @code{Subject} headers.  I'm sure that's nice for
+people who use stone age mail readers.  This function will remove
+strings that match the @code{nnmail-list-identifiers} regexp, which can
+also be a list of regexp.  @code{nnmail-list-identifiers} may not contain
+@code{\\(..\\)}.
+
+For instance, if you want to remove the @samp{(idm)} and the
+@samp{nagnagnag} identifiers:
+
+@lisp
+(setq nnmail-list-identifiers
+      '("(idm)" "nagnagnag"))
+@end lisp
+
+This can also be done non-destructively with
+@code{gnus-list-identifiers}, @xref{Article Hiding}.
+
+@item nnmail-remove-tabs
+@findex nnmail-remove-tabs
+Translate all @samp{TAB} characters into @samp{SPACE} characters.
+
+@item nnmail-ignore-broken-references
+@findex nnmail-ignore-broken-references
+@c @findex nnmail-fix-eudora-headers
+@cindex Eudora
+@cindex Pegasus
+Some mail user agents (e.g., Eudora and Pegasus) produce broken
+@code{References} headers, but correct @code{In-Reply-To} headers.  This
+function will get rid of the @code{References} header if the headers
+contain a line matching the regular expression
+@code{nnmail-broken-references-mailers}.
+
+@end table
+
+@item nnmail-prepare-incoming-message-hook
+@vindex nnmail-prepare-incoming-message-hook
+This hook is called narrowed to each message.  Functions to be used
+include:
+
+@table @code
+@item article-de-quoted-unreadable
+@findex article-de-quoted-unreadable
+Decode Quoted Readable encoding.
+
+@end table
+@end table
+
+
+@node Duplicates
+@subsection Duplicates
+
+@vindex nnmail-treat-duplicates
+@vindex nnmail-message-id-cache-length
+@vindex nnmail-message-id-cache-file
+@cindex duplicate mails
+If you are a member of a couple of mailing lists, you will sometimes
+receive two copies of the same mail.  This can be quite annoying, so
+@code{nnmail} checks for and treats any duplicates it might find.  To do
+this, it keeps a cache of old @code{Message-ID}s:
+@code{nnmail-message-id-cache-file}, which is @file{~/.nnmail-cache} by
+default.  The approximate maximum number of @code{Message-ID}s stored
+there is controlled by the @code{nnmail-message-id-cache-length}
+variable, which is 1000 by default.  (So 1000 @code{Message-ID}s will be
+stored.)  If all this sounds scary to you, you can set
+@code{nnmail-treat-duplicates} to @code{warn} (which is what it is by
+default), and @code{nnmail} won't delete duplicate mails.  Instead it
+will insert a warning into the head of the mail saying that it thinks
+that this is a duplicate of a different message.
+
+This variable can also be a function.  If that's the case, the function
+will be called from a buffer narrowed to the message in question with
+the @code{Message-ID} as a parameter.  The function must return either
+@code{nil}, @code{warn}, or @code{delete}.
+
+You can turn this feature off completely by setting the variable to
+@code{nil}.
+
+If you want all the duplicate mails to be put into a special
+@dfn{duplicates} group, you could do that using the normal mail split
+methods:
+
+@lisp
+(setq nnmail-split-fancy
+      '(| ;; @r{Messages duplicates go to a separate group.}
+        ("gnus-warning" "duplicat\\(e\\|ion\\) of message" "duplicate")
+        ;; @r{Message from daemons, postmaster, and the like to another.}
+        (any mail "mail.misc")
+        ;; @r{Other rules.}
+        [...] ))
+@end lisp
+@noindent
+Or something like:
+@lisp
+(setq nnmail-split-methods
+      '(("duplicates" "^Gnus-Warning:.*duplicate")
+        ;; @r{Other rules.}
+        [...]))
+@end lisp
+
+Here's a neat feature: If you know that the recipient reads her mail
+with Gnus, and that she has @code{nnmail-treat-duplicates} set to
+@code{delete}, you can send her as many insults as you like, just by
+using a @code{Message-ID} of a mail that you know that she's already
+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 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 back ends will ever attempt to read incoming
+mail, which should help.
+
+@vindex nnbabyl-get-new-mail
+@vindex nnmbox-get-new-mail
+@vindex nnml-get-new-mail
+@vindex nnmh-get-new-mail
+@vindex nnfolder-get-new-mail
+This might be too much, if, for instance, you are reading mail quite
+happily with @code{nnml} and just want to peek at some old (pre-Emacs
+23) Rmail 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 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 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 six 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 possibly the fastest) is @code{nnml} (@pxref{Mail
+Spool}).
+
+@menu
+* Unix Mail Box::               Using the (quite) standard Un*x mbox.
+* Babyl::                       Babyl was used by older versions of Rmail.
+* Mail Spool::                  Store your mail in a private spool?
+* MH Spool::                    An mhspool-like back end.
+* Maildir::                     Another one-file-per-message format.
+* nnmaildir Group Parameters::
+* Article Identification::
+* NOV Data::
+* Article Marks::
+* Mail Folders::                Having one file for each group.
+* Comparing Mail Back Ends::    An in-depth looks at pros and cons.
+@end menu
+
+
+
+@node Unix Mail Box
+@subsubsection Unix Mail Box
+@cindex nnmbox
+@cindex unix mail box
+
+@vindex nnmbox-active-file
+@vindex nnmbox-mbox-file
+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.
+
+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.  Default is
+@file{~/mbox}.
+
+@item nnmbox-active-file
+@vindex nnmbox-active-file
+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.  Default is @code{t}.
+@end table
+
+
+@node Babyl
+@subsubsection Babyl
+@cindex nnbabyl
+
+@vindex nnbabyl-active-file
+@vindex nnbabyl-mbox-file
+The @dfn{nnbabyl} back end will use a Babyl mail box to store mail.
+@code{nnbabyl} will add extra headers to each mail article to say which
+group it belongs in.
+
+Virtual server settings:
+
+@table @code
+@item nnbabyl-mbox-file
+@vindex nnbabyl-mbox-file
+The name of the Babyl file.  The default is @file{~/RMAIL}
+
+@item nnbabyl-active-file
+@vindex nnbabyl-active-file
+The name of the active file for the Babyl file.  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.  Default is
+@code{t}
+@end table
+
+
+@node Mail Spool
+@subsubsection Mail Spool
+@cindex nnml
+@cindex mail @acronym{NOV} spool
+
+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 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/}.
+
+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 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,
+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 back end when it comes to article
+splitting.  It has to create lots of files, and it also generates
+@acronym{NOV} databases for the incoming mails.  This makes it possibly the
+fastest back end when it comes to reading mail.
+
+Virtual server settings:
+
+@table @code
+@item nnml-directory
+@vindex nnml-directory
+All @code{nnml} directories will be placed under this directory.  The
+default is the value of @code{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 default is
+@file{~/Mail/active}.
+
+@item nnml-newsgroups-file
+@vindex nnml-newsgroups-file
+The @code{nnml} group descriptions file.  @xref{Newsgroups File
+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.  The default is
+@code{t}.
+
+@item nnml-nov-is-evil
+@vindex nnml-nov-is-evil
+If non-@code{nil}, this back end will ignore any @acronym{NOV} files.  The
+default is @code{nil}.
+
+@item nnml-nov-file-name
+@vindex nnml-nov-file-name
+The name of the @acronym{NOV} files.  The default is @file{.overview}.
+
+@item nnml-prepare-save-mail-hook
+@vindex nnml-prepare-save-mail-hook
+Hook run narrowed to an article before saving.
+
+@item nnml-use-compressed-files
+@vindex nnml-use-compressed-files
+If non-@code{nil}, @code{nnml} will allow using compressed message
+files.  This requires @code{auto-compression-mode} to be enabled
+(@pxref{Compressed Files, ,Compressed Files, emacs, The Emacs Manual}).
+If the value of @code{nnml-use-compressed-files} is a string, it is used
+as the file extension specifying the compression program.  You can set it
+to @samp{.bz2} if your Emacs supports it.  A value of @code{t} is
+equivalent to @samp{.gz}.
+
+@item nnml-compressed-files-size-threshold
+@vindex nnml-compressed-files-size-threshold
+Default size threshold for compressed message files.  Message files with
+bodies larger than that many characters will be automatically compressed
+if @code{nnml-use-compressed-files} is non-@code{nil}.
+
+@end table
+
+@findex nnml-generate-nov-databases
+If your @code{nnml} groups and @acronym{NOV} files get totally out of
+whack, you can do a complete update by typing @kbd{M-x
+nnml-generate-nov-databases}.  This command will trawl through the
+entire @code{nnml} hierarchy, looking at each and every article, so it
+might take a while to complete.  A better interface to this
+functionality can be found in the server buffer (@pxref{Server
+Commands}).
+
+
+@node MH Spool
+@subsubsection MH Spool
+@cindex nnmh
+@cindex mh-e mail spool
+
+@code{nnmh} is just like @code{nnml}, except that is doesn't generate
+@acronym{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.  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.  The default is
+@code{t}.
+
+@item nnmh-be-safe
+@vindex nnmh-be-safe
+If non-@code{nil}, @code{nnmh} will go to ridiculous lengths to make
+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}.  The default is @code{nil}.
+@end table
+
+
+@node Maildir
+@subsubsection Maildir
+@cindex nnmaildir
+@cindex maildir
+
+@code{nnmaildir} stores mail in the maildir format, with each maildir
+corresponding to a group in Gnus.  This format is documented here:
+@uref{http://cr.yp.to/proto/maildir.html} and here:
+@uref{http://www.qmail.org/man/man5/maildir.html}.  @code{nnmaildir}
+also stores extra information in the @file{.nnmaildir/} directory
+within a maildir.
+
+Maildir format was designed to allow concurrent deliveries and
+reading, without needing locks.  With other back ends, you would have
+your mail delivered to a spool of some kind, and then you would
+configure Gnus to split mail from that spool into your groups.  You
+can still do that with @code{nnmaildir}, but the more common
+configuration is to have your mail delivered directly to the maildirs
+that appear as group in Gnus.
+
+@code{nnmaildir} is designed to be perfectly reliable: @kbd{C-g} will
+never corrupt its data in memory, and @code{SIGKILL} will never
+corrupt its data in the filesystem.
+
+@code{nnmaildir} stores article marks and @acronym{NOV} data in each
+maildir.  So you can copy a whole maildir from one Gnus setup to
+another, and you will keep your marks.
+
+Virtual server settings:
+
+@table @code
+@item directory
+For each of your @code{nnmaildir} servers (it's very unlikely that
+you'd need more than one), you need to create a directory and populate
+it with maildirs or symlinks to maildirs (and nothing else; do not
+choose a directory already used for other purposes).  Each maildir
+will be represented in Gnus as a newsgroup on that server; the
+filename of the symlink will be the name of the group.  Any filenames
+in the directory starting with @samp{.} are ignored.  The directory is
+scanned when you first start Gnus, and each time you type @kbd{g} in
+the group buffer; if any maildirs have been removed or added,
+@code{nnmaildir} notices at these times.
+
+The value of the @code{directory} parameter should be a Lisp form
+which is processed by @code{eval} and @code{expand-file-name} to get
+the path of the directory for this server.  The form is @code{eval}ed
+only when the server is opened; the resulting string is used until the
+server is closed.  (If you don't know about forms and @code{eval},
+don't worry---a simple string will work.)  This parameter is not
+optional; you must specify it.  I don't recommend using
+@code{"~/Mail"} or a subdirectory of it; several other parts of Gnus
+use that directory by default for various things, and may get confused
+if @code{nnmaildir} uses it too.  @code{"~/.nnmaildir"} is a typical
+value.
+
+@item target-prefix
+This should be a Lisp form which is processed by @code{eval} and
+@code{expand-file-name}.  The form is @code{eval}ed only when the
+server is opened; the resulting string is used until the server is
+closed.
+
+When you create a group on an @code{nnmaildir} server, the maildir is
+created with @code{target-prefix} prepended to its name, and a symlink
+pointing to that maildir is created, named with the plain group name.
+So if @code{directory} is @code{"~/.nnmaildir"} and
+@code{target-prefix} is @code{"../maildirs/"}, then when you create
+the group @code{foo}, @code{nnmaildir} will create
+@file{~/.nnmaildir/../maildirs/foo} as a maildir, and will create
+@file{~/.nnmaildir/foo} as a symlink pointing to
+@file{../maildirs/foo}.
+
+You can set @code{target-prefix} to a string without any slashes to
+create both maildirs and symlinks in the same @code{directory}; in
+this case, any maildirs found in @code{directory} whose names start
+with @code{target-prefix} will not be listed as groups (but the
+symlinks pointing to them will be).
+
+As a special case, if @code{target-prefix} is @code{""} (the default),
+then when you create a group, the maildir will be created in
+@code{directory} without a corresponding symlink.  Beware that you
+cannot use @code{gnus-group-delete-group} on such groups without the
+@code{force} argument.
+
+@item directory-files
+This should be a function with the same interface as
+@code{directory-files} (such as @code{directory-files} itself).  It is
+used to scan the server's @code{directory} for maildirs.  This
+parameter is optional; the default is
+@code{nnheader-directory-files-safe} if
+@code{nnheader-directory-files-is-safe} is @code{nil}, and
+@code{directory-files} otherwise.
+(@code{nnheader-directory-files-is-safe} is checked only once when the
+server is opened; if you want to check it each time the directory is
+scanned, you'll have to provide your own function that does that.)
+
+@item get-new-mail
+If non-@code{nil}, then after scanning for new mail in the group
+maildirs themselves as usual, this server will also incorporate mail
+the conventional Gnus way, from @code{mail-sources} according to
+@code{nnmail-split-methods} or @code{nnmail-split-fancy}.  The default
+value is @code{nil}.
+
+Do @emph{not} use the same maildir both in @code{mail-sources} and as
+an @code{nnmaildir} group.  The results might happen to be useful, but
+that would be by chance, not by design, and the results might be
+different in the future.  If your split rules create new groups,
+remember to supply a @code{create-directory} server parameter.
+@end table
+
+@node nnmaildir Group Parameters
+@subsubsection Group parameters
+
+@code{nnmaildir} uses several group parameters.  It's safe to ignore
+all this; the default behavior for @code{nnmaildir} is the same as the
+default behavior for other mail back ends: articles are deleted after
+one week, etc.  Except for the expiry parameters, all this
+functionality is unique to @code{nnmaildir}, so you can ignore it if
+you're just trying to duplicate the behavior you already have with
+another back end.
+
+If the value of any of these parameters is a vector, the first element
+is evaluated as a Lisp form and the result is used, rather than the
+original value.  If the value is not a vector, the value itself is
+evaluated as a Lisp form.  (This is why these parameters use names
+different from those of other, similar parameters supported by other
+back ends: they have different, though similar, meanings.)  (For
+numbers, strings, @code{nil}, and @code{t}, you can ignore the
+@code{eval} business again; for other values, remember to use an extra
+quote and wrap the value in a vector when appropriate.)
+
+@table @code
+@item expire-age
+An integer specifying the minimum age, in seconds, of an article
+before it will be expired, or the symbol @code{never} to specify that
+articles should never be expired.  If this parameter is not set,
+@code{nnmaildir} falls back to the usual
+@code{nnmail-expiry-wait}(@code{-function}) variables (the
+@code{expiry-wait} group parameter overrides @code{nnmail-expiry-wait}
+and makes @code{nnmail-expiry-wait-function} ineffective).  If you
+wanted a value of 3 days, you could use something like @code{[(* 3 24
+60 60)]}; @code{nnmaildir} will evaluate the form and use the result.
+An article's age is measured starting from the article file's
+modification time.  Normally, this is the same as the article's
+delivery time, but editing an article makes it younger.  Moving an
+article (other than via expiry) may also make an article younger.
+
+@item expire-group
+If this is set to a string such as a full Gnus group name, like
+@example
+"backend+server.address.string:group.name"
+@end example
+and if it is not the name of the same group that the parameter belongs
+to, then articles will be moved to the specified group during expiry
+before being deleted.  @emph{If this is set to an @code{nnmaildir}
+group, the article will be just as old in the destination group as it
+was in the source group.}  So be careful with @code{expire-age} in the
+destination group.  If this is set to the name of the same group that
+the parameter belongs to, then the article is not expired at all.  If
+you use the vector form, the first element is evaluated once for each
+article.  So that form can refer to
+@code{nnmaildir-article-file-name}, etc., to decide where to put the
+article.  @emph{Even if this parameter is not set, @code{nnmaildir}
+does not fall back to the @code{expiry-target} group parameter or the
+@code{nnmail-expiry-target} variable.}
+
+@item read-only
+If this is set to @code{t}, @code{nnmaildir} will treat the articles
+in this maildir as read-only.  This means: articles are not renamed
+from @file{new/} into @file{cur/}; articles are only found in
+@file{new/}, not @file{cur/}; articles are never deleted; articles
+cannot be edited.  @file{new/} is expected to be a symlink to the
+@file{new/} directory of another maildir---e.g., a system-wide mailbox
+containing a mailing list of common interest.  Everything in the
+maildir outside @file{new/} is @emph{not} treated as read-only, so for
+a shared mailbox, you do still need to set up your own maildir (or
+have write permission to the shared mailbox); your maildir just won't
+contain extra copies of the articles.
+
+@item directory-files
+A function with the same interface as @code{directory-files}.  It is
+used to scan the directories in the maildir corresponding to this
+group to find articles.  The default is the function specified by the
+server's @code{directory-files} parameter.
+
+@item distrust-Lines:
+If non-@code{nil}, @code{nnmaildir} will always count the lines of an
+article, rather than use the @code{Lines:} header field.  If
+@code{nil}, the header field will be used if present.
+
+@item always-marks
+A list of mark symbols, such as @code{['(read expire)]}.  Whenever
+Gnus asks @code{nnmaildir} for article marks, @code{nnmaildir} will
+say that all articles have these marks, regardless of whether the
+marks stored in the filesystem say so.  This is a proof-of-concept
+feature that will probably be removed eventually; it ought to be done
+in Gnus proper, or abandoned if it's not worthwhile.
+
+@item never-marks
+A list of mark symbols, such as @code{['(tick expire)]}.  Whenever
+Gnus asks @code{nnmaildir} for article marks, @code{nnmaildir} will
+say that no articles have these marks, regardless of whether the marks
+stored in the filesystem say so.  @code{never-marks} overrides
+@code{always-marks}.  This is a proof-of-concept feature that will
+probably be removed eventually; it ought to be done in Gnus proper, or
+abandoned if it's not worthwhile.
+
+@item nov-cache-size
+An integer specifying the size of the @acronym{NOV} memory cache.  To
+speed things up, @code{nnmaildir} keeps @acronym{NOV} data in memory
+for a limited number of articles in each group.  (This is probably not
+worthwhile, and will probably be removed in the future.)  This
+parameter's value is noticed only the first time a group is seen after
+the server is opened---i.e., when you first start Gnus, typically.
+The @acronym{NOV} cache is never resized until the server is closed
+and reopened.  The default is an estimate of the number of articles
+that would be displayed in the summary buffer: a count of articles
+that are either marked with @code{tick} or not marked with
+@code{read}, plus a little extra.
+@end table
+
+@node Article Identification
+@subsubsection Article identification
+Articles are stored in the @file{cur/} subdirectory of each maildir.
+Each article file is named like @code{uniq:info}, where @code{uniq}
+contains no colons.  @code{nnmaildir} ignores, but preserves, the
+@code{:info} part.  (Other maildir readers typically use this part of
+the filename to store marks.)  The @code{uniq} part uniquely
+identifies the article, and is used in various places in the
+@file{.nnmaildir/} subdirectory of the maildir to store information
+about the corresponding article.  The full pathname of an article is
+available in the variable @code{nnmaildir-article-file-name} after you
+request the article in the summary buffer.
+
+@node NOV Data
+@subsubsection NOV data
+An article identified by @code{uniq} has its @acronym{NOV} data (used
+to generate lines in the summary buffer) stored in
+@code{.nnmaildir/nov/uniq}.  There is no
+@code{nnmaildir-generate-nov-databases} function.  (There isn't much
+need for it---an article's @acronym{NOV} data is updated automatically
+when the article or @code{nnmail-extra-headers} has changed.)  You can
+force @code{nnmaildir} to regenerate the @acronym{NOV} data for a
+single article simply by deleting the corresponding @acronym{NOV}
+file, but @emph{beware}: this will also cause @code{nnmaildir} to
+assign a new article number for this article, which may cause trouble
+with @code{seen} marks, the Agent, and the cache.
+
+@node Article Marks
+@subsubsection Article marks
+An article identified by @code{uniq} is considered to have the mark
+@code{flag} when the file @file{.nnmaildir/marks/flag/uniq} exists.
+When Gnus asks @code{nnmaildir} for a group's marks, @code{nnmaildir}
+looks for such files and reports the set of marks it finds.  When Gnus
+asks @code{nnmaildir} to store a new set of marks, @code{nnmaildir}
+creates and deletes the corresponding files as needed.  (Actually,
+rather than create a new file for each mark, it just creates hard
+links to @file{.nnmaildir/markfile}, to save inodes.)
+
+You can invent new marks by creating a new directory in
+@file{.nnmaildir/marks/}.  You can tar up a maildir and remove it from
+your server, untar it later, and keep your marks.  You can add and
+remove marks yourself by creating and deleting mark files.  If you do
+this while Gnus is running and your @code{nnmaildir} server is open,
+it's best to exit all summary buffers for @code{nnmaildir} groups and
+type @kbd{s} in the group buffer first, and to type @kbd{g} or
+@kbd{M-g} in the group buffer afterwards.  Otherwise, Gnus might not
+pick up the changes, and might undo them.
+
+
+@node Mail Folders
+@subsubsection Mail Folders
+@cindex nnfolder
+@cindex mbox folders
+@cindex mail folders
+
+@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.
+
+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 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 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.  The
+default is @code{t}
+
+@item nnfolder-save-buffer-hook
+@vindex nnfolder-save-buffer-hook
+@cindex backup files
+Hook run before saving the folders.  Note that Emacs does the normal
+backup renaming of files even with the @code{nnfolder} buffers.  If
+you wish to switch this off, you could say something like the
+following in your @file{.emacs} file:
+
+@lisp
+(defun turn-off-backup ()
+  (set (make-local-variable 'backup-inhibited) t))
+
+(add-hook 'nnfolder-save-buffer-hook 'turn-off-backup)
+@end lisp
+
+@item nnfolder-delete-mail-hook
+@vindex nnfolder-delete-mail-hook
+Hook run in a buffer narrowed to the message that is to be deleted.
+This function can be used to copy the message to somewhere else, or to
+extract some information from it before removing it.
+
+@item nnfolder-nov-is-evil
+@vindex nnfolder-nov-is-evil
+If non-@code{nil}, this back end will ignore any @acronym{NOV} files.  The
+default is @code{nil}.
+
+@item nnfolder-nov-file-suffix
+@vindex nnfolder-nov-file-suffix
+The extension for @acronym{NOV} files.  The default is @file{.nov}.
+
+@item nnfolder-nov-directory
+@vindex nnfolder-nov-directory
+The directory where the @acronym{NOV} files should be stored.  If
+@code{nil}, @code{nnfolder-directory} is used.
+
+@end table
+
+
+@findex nnfolder-generate-active-file
+@kindex M-x nnfolder-generate-active-file
+If you have lots of @code{nnfolder}-like files you'd like to read with
+@code{nnfolder}, you can use the @kbd{M-x nnfolder-generate-active-file}
+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 Back Ends
+@subsubsection Comparing Mail Back Ends
+
+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 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
+typically done by @acronym{NNTP} these days, once upon a midnight dreary, everyone
+in the world got at Usenet by running a reader on the machine where the
+articles lay (the machine which today we call an @acronym{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} 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 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:
+
+@table @code
+@item nnmbox
+
+UNIX systems have historically had a single, very common, and well-defined
+format.  All messages arrive in a single @dfn{spool file}, and
+they are delineated by a line whose regular expression matches
+@samp{^From_}.  (My notational use of @samp{_} is to indicate a space,
+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 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
+fast to move into place, but slow to parse, when Gnus has to look at
+what's where.
+
+@item nnbabyl
+
+Once upon a time, there was the DEC-10 and DEC-20, running operating
+systems called TOPS and related things, and the usual (only?) mail
+reading environment was a thing called Babyl.  I don't know what format
+was used for mail landing on the system, but Babyl had its own internal
+format to which mail was converted, primarily involving creating a
+spool-file-like entity with a scheme for inserting Babyl-specific
+headers and status bits above the top of each message in the file.
+Rmail was Emacs's first mail reader, it was written by Richard Stallman,
+and Stallman came out of that TOPS/Babyl environment, so he wrote Rmail
+to understand the mail files folks already had in existence.  Gnus (and
+VM, for that matter) continue to support this format because it's
+perceived as having some good qualities in those mailer-specific
+headers/status bits stuff.  Rmail itself still exists as well, of
+course, and is still maintained within Emacs.  Since Emacs 23, it
+uses standard mbox format rather than Babyl.
+
+Both of the above forms leave your mail in a single file on your
+file system, and they must parse that entire file each time you take a
+look at your mail.
+
+@item nnml
+
+@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,
+and is then cut up into individual message files, 1:1.  It maintains a
+Usenet-style active file (analogous to what one finds in an INN- or
+CNews-based news system in (for instance) @file{/var/lib/news/active},
+or what is returned via the @samp{NNTP LIST} verb) and also creates
+@dfn{overview} files for efficient group entry, as has been defined for
+@acronym{NNTP} servers for some years now.  It is slower in mail-splitting,
+due to the creation of lots of files, updates to the @code{nnml} active
+file, and additions to overview files on a per-message basis, but it is
+extremely fast on access because of what amounts to the indexing support
+provided by the active file and overviews.
+
+@code{nnml} costs @dfn{inodes} in a big way; that is, it soaks up the
+resource which defines available places in the file system to put new
+files.  Sysadmins take a dim view of heavy inode occupation within
+tight, shared file systems.  But if you live on a personal machine where
+the file system is your own and space is not at a premium, @code{nnml}
+wins big.
+
+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.
+
+@item nnmh
+
+The Rand MH mail-reading system has been around UNIX systems for a very
+long time; it operates by splitting one's spool file of messages into
+individual files, but with little or no indexing support---@code{nnmh}
+is considered to be semantically equivalent to ``@code{nnml} without
+active file or overviews''.  This is arguably the worst choice, because
+one gets the slowness of individual file creation married to the
+slowness of access parsing when learning what's new in one's groups.
+
+@item nnfolder
+
+Basically the effect of @code{nnfolder} is @code{nnmbox} (the first
+method described above) on a per-group basis.  That is, @code{nnmbox}
+itself puts @emph{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
+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 back end all over.
+
+@item nnmaildir
+
+For configuring expiry and other things, @code{nnmaildir} uses
+incompatible group parameters, slightly different from those of other
+mail back ends.
+
+@code{nnmaildir} is largely similar to @code{nnml}, with some notable
+differences.  Each message is stored in a separate file, but the
+filename is unrelated to the article number in Gnus. @code{nnmaildir}
+also stores the equivalent of @code{nnml}'s overview files in one file
+per article, so it uses about twice as many inodes as @code{nnml}.
+(Use @code{df -i} to see how plentiful your inode supply is.)  If this
+slows you down or takes up very much space, a non-block-structured
+file system.
+
+Since maildirs don't require locking for delivery, the maildirs you use
+as groups can also be the maildirs your mail is directly delivered to.
+This means you can skip Gnus' mail splitting if your mail is already
+organized into different mailboxes during delivery.  A @code{directory}
+entry in @code{mail-sources} would have a similar effect, but would
+require one set of mailboxes for spooling deliveries (in mbox format,
+thus damaging message bodies), and another set to be used as groups (in
+whatever format you like).  A maildir has a built-in spool, in the
+@code{new/} subdirectory.  Beware that currently, mail moved from
+@code{new/} to @code{cur/} instead of via mail splitting will not
+undergo treatment such as duplicate checking.
+
+@code{nnmaildir} stores article marks for a given group in the
+corresponding maildir, in a way designed so that it's easy to manipulate
+them from outside Gnus.  You can tar up a maildir, unpack it somewhere
+else, and still have your marks.
+
+@code{nnmaildir} uses a significant amount of memory to speed things up.
+(It keeps in memory some of the things that @code{nnml} stores in files
+and that @code{nnmh} repeatedly parses out of message files.)  If this
+is a problem for you, you can set the @code{nov-cache-size} group
+parameter to something small (0 would probably not work, but 1 probably
+would) to make it use less memory.  This caching will probably be
+removed in the future.
+
+Startup is likely to be slower with @code{nnmaildir} than with other
+back ends.  Everything else is likely to be faster, depending in part
+on your file system.
+
+@code{nnmaildir} does not use @code{nnoo}, so you cannot use @code{nnoo}
+to write an @code{nnmaildir}-derived back end.
+
+@end table
+
+
+@node Browsing the Web
+@section Browsing the Web
+@cindex web
+@cindex browsing the web
+@cindex www
+@cindex http
+
+Web-based discussion forums are getting more and more popular.  On many
+subjects, the web-based forums have become the most important forums,
+eclipsing the importance of mailing lists and news groups.  The reason
+is easy to understand---they are friendly to new users; you just point
+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
+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
+to do it instead?
+
+Gnus has been getting a bit of a collection of back ends for providing
+interfaces to these sources.
+
+@menu
+* Archiving Mail::
+* Web Searches::                Creating groups from articles that match a string.
+* RSS::                         Reading RDF site summary.
+@end menu
+
+The main caveat with all these web sources is that they probably won't
+work for a very long time.  Gleaning information from the @acronym{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
+are often down, unavailable or just plain too slow to be fun.  In those
+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 @code{nnml}, @code{nnfolder}, and
+@code{nnmaildir}, 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 @file{.newsrc.eld} deity
+though.)
+
+To archive an entire @code{nnml}, @code{nnfolder}, or @code{nnmaildir}
+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 interfere with overwriting data, so you may want to shut down Gnus
+before you restore the data.
+
+@node Web Searches
+@subsection Web Searches
+@cindex nnweb
+@cindex Google
+@cindex dejanews
+@cindex gmane
+@cindex Usenet searches
+@cindex searching the Usenet
+
+It's, like, too neat to search the Usenet for articles that match a
+string, but it, like, totally @emph{sucks}, like, totally, to use one of
+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} 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
+Groups}) will do this in an easy-to-use fashion.
+
+@code{nnweb} groups don't really lend themselves to being solid
+groups---they have a very fleeting idea of article numbers.  In fact,
+each time you enter an @code{nnweb} group (not even changing the search
+pattern), you are likely to get the articles ordered in a different
+manner.  Not even using duplicate suppression (@pxref{Duplicate
+Suppression}) will help, since @code{nnweb} doesn't even know the
+@code{Message-ID} of the articles before reading them using some search
+engines (Google, for instance).  The only possible way to keep track
+of which articles you've read is by scoring on the @code{Date}
+header---mark all articles posted before the last date you read the
+group as read.
+
+If the search engine changes its output substantially, @code{nnweb}
+won't be able to parse it and will fail.  One could hardly fault the Web
+providers if they were to do this---their @emph{raison d'être} is to
+make money off of advertisements, not to provide services to the
+community.  Since @code{nnweb} washes the ads off all the articles, one
+might think that the providers might be somewhat miffed.  We'll see.
+
+Virtual server variables:
+
+@table @code
+@item nnweb-type
+@vindex nnweb-type
+What search engine type is being used.  The currently supported types
+are @code{google}, @code{dejanews}, and @code{gmane}.  Note that
+@code{dejanews} is an alias to @code{google}.
+
+@item nnweb-search
+@vindex nnweb-search
+The search string to feed to the search engine.
+
+@item nnweb-max-hits
+@vindex nnweb-max-hits
+Advisory maximum number of hits per search to display.  The default is
+999.
+
+@item nnweb-type-definition
+@vindex nnweb-type-definition
+Type-to-definition alist.  This alist says what @code{nnweb} should do
+with the various search engine types.  The following elements must be
+present:
+
+@table @code
+@item article
+Function to decode the article and provide something that Gnus
+understands.
+
+@item map
+Function to create an article number to message header and URL alist.
+
+@item search
+Function to send the search string to the search engine.
+
+@item address
+The address the aforementioned function should send the search string
+to.
+
+@item id
+Format string URL to fetch an article by @code{Message-ID}.
+@end table
+
+@end table
+
+
+@node RSS
+@subsection RSS
+@cindex nnrss
+@cindex RSS
+
+Some web sites have an RDF Site Summary (@acronym{RSS}).
+@acronym{RSS} is a format for summarizing headlines from news related
+sites (such as BBC or CNN).  But basically anything list-like can be
+presented as an @acronym{RSS} feed: weblogs, changelogs or recent
+changes to a wiki (e.g., @url{http://cliki.net/site/recent-changes}).
+
+@acronym{RSS} has a quite regular and nice interface, and it's
+possible to get the information Gnus needs to keep groups updated.
+
+Note: you had better use Emacs which supports the @code{utf-8} coding
+system because @acronym{RSS} uses UTF-8 for encoding non-@acronym{ASCII}
+text by default.  It is also used by default for non-@acronym{ASCII}
+group names.
+
+@kindex G R (Group)
+Use @kbd{G R} from the group buffer to subscribe to a feed---you will be
+prompted for the location, the title and the description of the feed.
+The title, which allows any characters, will be used for the group name
+and the name of the group data file.  The description can be omitted.
+
+An easy way to get started with @code{nnrss} is to say something like
+the following in the group buffer: @kbd{B nnrss RET RET y}, then
+subscribe to groups.
+
+The @code{nnrss} back end saves the group data file in
+@code{nnrss-directory} (see below) for each @code{nnrss} group.  File
+names containing non-@acronym{ASCII} characters will be encoded by the
+coding system specified with the @code{nnmail-pathname-coding-system}
+variable or other.  Also @xref{Non-ASCII Group Names}, for more
+information.
+
+The @code{nnrss} back end generates @samp{multipart/alternative}
+@acronym{MIME} articles in which each contains a @samp{text/plain} part
+and a @samp{text/html} part.
+
+@cindex OPML
+You can also use the following commands to import and export your
+subscriptions from a file in @acronym{OPML} format (Outline Processor
+Markup Language).
+
+@defun nnrss-opml-import file
+Prompt for an @acronym{OPML} file, and subscribe to each feed in the
+file.
+@end defun
+
+@defun nnrss-opml-export
+Write your current @acronym{RSS} subscriptions to a buffer in
+@acronym{OPML} format.
+@end defun
+
+The following @code{nnrss} variables can be altered:
+
+@table @code
+@item nnrss-directory
+@vindex nnrss-directory
+The directory where @code{nnrss} stores its files.  The default is
+@file{~/News/rss/}.
+
+@item nnrss-file-coding-system
+@vindex nnrss-file-coding-system
+The coding system used when reading and writing the @code{nnrss} groups
+data files.  The default is the value of
+@code{mm-universal-coding-system} (which defaults to @code{emacs-mule}
+in Emacs or @code{escape-quoted} in XEmacs).
+
+@item nnrss-ignore-article-fields
+@vindex nnrss-ignore-article-fields
+Some feeds update constantly article fields during their publications,
+e.g., to indicate the number of comments.  However, if there is
+a difference between the local article and the distant one, the latter
+is considered to be new.  To avoid this and discard some fields, set this
+variable to the list of fields to be ignored.  The default is
+@code{'(slash:comments)}.
+
+@item nnrss-use-local
+@vindex nnrss-use-local
+@findex nnrss-generate-download-script
+If you set @code{nnrss-use-local} to @code{t}, @code{nnrss} will read
+the feeds from local files in @code{nnrss-directory}.  You can use
+the command @code{nnrss-generate-download-script} to generate a
+download script using @command{wget}.
+@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
+        (progn
+          (browse-url (cdr url))
+          (gnus-summary-mark-as-read-forward 1))
+      (gnus-summary-scroll-up arg))))
+
+(eval-after-load "gnus"
+  #'(define-key gnus-summary-mode-map
+      (kbd "<RET>") 'browse-nnrss-url))
+(add-to-list 'nnmail-extra-headers nnrss-url-field)
+@end lisp
+
+Even if you have added @samp{text/html} to the
+@code{mm-discouraged-alternatives} variable (@pxref{Display
+Customization, ,Display Customization, emacs-mime, The Emacs MIME
+Manual}) since you don't want to see @acronym{HTML} parts, it might be
+more useful especially in @code{nnrss} groups to display
+@samp{text/html} parts.  Here's an example of setting
+@code{mm-discouraged-alternatives} as a group parameter (@pxref{Group
+Parameters}) in order to display @samp{text/html} parts only in
+@code{nnrss} groups:
+
+@lisp
+;; @r{Set the default value of @code{mm-discouraged-alternatives}.}
+(eval-after-load "gnus-sum"
+  '(add-to-list
+    'gnus-newsgroup-variables
+    '(mm-discouraged-alternatives
+      . '("text/html" "image/.*"))))
+
+;; @r{Display @samp{text/html} parts in @code{nnrss} groups.}
+(add-to-list
+ 'gnus-parameters
+ '("\\`nnrss:" (mm-discouraged-alternatives nil)))
+@end lisp
+
+
+@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.
+
+@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.
+* Mail-To-News Gateways::       Posting articles via mail-to-news gateways.
+* The Empty Backend::           The backend that never has any news.
+@end menu
+
+
+@node Directory Groups
+@subsection Directory Groups
+@cindex nndir
+@cindex directory groups
+
+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.
+
+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.
+
+@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!
+
+@code{nndir} will use @acronym{NOV} files if they are present.
+
+@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}.
+
+
+@node Anything Groups
+@subsection Anything Groups
+@cindex nneething
+
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+Some variables:
+
+@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 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 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 Document Groups
+@subsection Document Groups
+@cindex nndoc
+@cindex documentation group
+@cindex help group
+
+@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
+@item babyl
+The Babyl format.
+
+@cindex mbox
+@cindex Unix mbox
+@item mbox
+The standard Unix mbox file.
+
+@cindex MMDF mail box
+@item mmdf
+The MMDF mail box format.
+
+@item news
+Several news articles appended into a file.
+
+@cindex rnews batch files
+@item rnews
+The rnews batch transport format.
+
+@item nsmail
+Netscape mail boxes.
+
+@item mime-parts
+@acronym{MIME} multipart messages.
+
+@item standard-digest
+The standard (RFC 1153) digest format.
+
+@item mime-digest
+A @acronym{MIME} digest of messages.
+
+@item lanl-gov-announce
+Announcement messages from LANL Gov Announce.
+
+@cindex git commit messages
+@item git
+@code{git} commit messages.
+
+@cindex forwarded messages
+@item rfc822-forward
+A message forwarded according to RFC822.
+
+@item outlook
+The Outlook mail box.
+
+@item oe-dbx
+The Outlook Express dbx mail box.
+
+@item exim-bounce
+A bounce message from the Exim MTA.
+
+@item forward
+A message forwarded according to informal rules.
+
+@item rfc934
+An RFC934-forwarded message.
+
+@item mailman
+A mailman digest.
+
+@item clari-briefs
+A digest of Clarinet brief news items.
+
+@item slack-digest
+Non-standard digest format---matches most things, but does it badly.
+
+@item mail-in-mail
+The last resort.
+@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.
+
+@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 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!
+
+Virtual server variables:
+
+@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}, @code{mailman}, and @code{mail-in-mail} or @code{guess}.
+
+@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.
+@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}.
+
+First, here's an example document type definition:
+
+@example
+(mmdf
+ (article-begin .  "^\^A\^A\^A\^A\n")
+ (body-end .  "^\^A\^A\^A\^A\n"))
+@end example
+
+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:
+
+@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.  To do more
+complicated things that cannot be dealt with a simple regexp, you can
+use @code{article-begin-function} instead of this.
+
+@item article-begin-function
+If present, this should be a function that moves point to the beginning
+of each article.  This setting overrides @code{article-begin}.
+
+@item head-begin
+If present, this should be a regexp that matches the head of the
+article.  To do more complicated things that cannot be dealt with a
+simple regexp, you can use @code{head-begin-function} instead of this.
+
+@item head-begin-function
+If present, this should be a function that moves point to the head of
+the article.  This setting overrides @code{head-begin}.
+
+@item head-end
+This should match the end of the head of the article.  It defaults to
+@samp{^$}---the empty line.
+
+@item body-begin
+This should match the beginning of the body of the article.  It defaults
+to @samp{^\n}.  To do more complicated things that cannot be dealt with
+a simple regexp, you can use @code{body-begin-function} instead of this.
+
+@item body-begin-function
+If present, this function should move point to the beginning of the body
+of the article.  This setting overrides @code{body-begin}.
+
+@item body-end
+If present, this should match the end of the body of the article.  To do
+more complicated things that cannot be dealt with a simple regexp, you
+can use @code{body-end-function} instead of this.
+
+@item body-end-function
+If present, this function should move point to the end of the body of
+the article.  This setting overrides @code{body-end}.
+
+@item file-begin
+If present, this should match the beginning of the file.  All text
+before this regexp will be totally ignored.
+
+@item file-end
+If present, this should match the end of the file.  All text after this
+regexp will be totally ignored.
+
+@end table
+
+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:
+
+@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.
+
+@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.
+
+@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.
+
+@item generate-article-function
+If present, this function is called to generate an entire article that
+Gnus can understand.  It is called with the article number as a
+parameter when requesting all articles.
+
+@item dissection-function
+If present, this function is called to dissect a document by itself,
+overriding @code{first-article}, @code{article-begin},
+@code{article-begin-function}, @code{head-begin},
+@code{head-begin-function}, @code{head-end}, @code{body-begin},
+@code{body-begin-function}, @code{body-end}, @code{body-end-function},
+@code{file-begin}, and @code{file-end}.
+
+@end table
+
+Let's look at the most complicated example I can come up with---standard
+digests:
+
+@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
+
+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.
+
+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-@var{type}-type-p} is called for a given type @var{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.
+
+
+@node Mail-To-News Gateways
+@subsection Mail-To-News Gateways
+@cindex mail-to-news gateways
+@cindex gateways
+
+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.
+
+Note that you can't read anything from this back end---it can only be
+used to post with.
+
+Server variables:
+
+@table @code
+@item nngateway-address
+@vindex nngateway-address
+This is the address of the mail-to-news gateway.
+
+@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:
+
+@example
+Newsgroups: alt.religion.emacs
+@end example
+
+will get this @code{To} header inserted:
+
+@example
+To: alt-religion-emacs@@GATEWAY
+@end example
+
+The following pre-defined functions exist:
+
+@findex nngateway-simple-header-transformation
+@table @code
+
+@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}.
+@end table
+
+@end table
+
+Here's an example:
+
+@lisp
+(setq gnus-post-method
+      '(nngateway
+        "mail2news@@replay.com"
+        (nngateway-header-transformation
+         nngateway-mail2news-header-transformation)))
+@end lisp
+
+So, to use this, simply say something like:
+
+@lisp
+(setq gnus-post-method '(nngateway "GATEWAY.ADDRESS"))
+@end lisp
+
+
+@node The Empty Backend
+@subsection The Empty Backend
+@cindex nnnil
+
+@code{nnnil} is a backend that can be used as a placeholder if you
+have to specify a backend somewhere, but don't really want to.  The
+classical example is if you don't want to have a primary select
+methods, but want to only use secondary ones:
+
+@lisp
+(setq gnus-select-method '(nnnil ""))
+(setq gnus-secondary-select-methods
+      '((nnimap "foo")
+        (nnml "")))
+@end lisp
+
+
+@node Combined Groups
+@section Combined Groups
+
+Gnus allows combining a mixture of all the other group types into bigger
+groups.
+
+@menu
+* Virtual Groups::              Combining articles from many groups.
+@end menu
+
+
+@node Virtual Groups
+@subsection Virtual Groups
+@cindex nnvirtual
+@cindex virtual groups
+@cindex merging groups
+
+An @dfn{nnvirtual group} is really nothing more than a collection of
+other groups.
+
+For instance, if you are tired of reading many small groups, you can
+put them all in one big group, and then grow tired of reading one
+big, unwieldy group.  The joys of computing!
+
+You specify @code{nnvirtual} as the method.  The address should be a
+regexp to match component groups.
+
+All marks in the virtual group will stick to the articles in the
+component groups.  So if you tick an article in a virtual group, the
+article will also be ticked in the component group from whence it
+came.  (And vice versa---marks from the component groups will also be
+shown in the virtual group.).  To create an empty virtual group, run
+@kbd{G V} (@code{gnus-group-make-empty-virtual}) in the group buffer
+and edit the method regexp with @kbd{M-e}
+(@code{gnus-group-edit-group-method})
+
+Here's an example @code{nnvirtual} method that collects all Andrea Dworkin
+newsgroups into one, big, happy newsgroup:
+
+@lisp
+(nnvirtual "^alt\\.fan\\.andrea-dworkin$\\|^rec\\.dworkin.*")
+@end lisp
+
+The component groups can be native or foreign; everything should work
+smoothly, but if your computer explodes, it was probably my fault.
+
+Collecting the same group from several servers might actually be a good
+idea if users have set the Distribution header to limit distribution.
+If you would like to read @samp{soc.motss} both from a server in Japan
+and a server in Norway, you could use the following as the group regexp:
+
+@example
+"^nntp\\+server\\.jp:soc\\.motss$\\|^nntp\\+server\\.no:soc\\.motss$"
+@end example
+
+(Remember, though, that if you're creating the group with @kbd{G m}, you
+shouldn't double the backslashes, and you should leave off the quote
+characters at the beginning and the end of the string.)
+
+This should work kinda smoothly---all articles from both groups should
+end up in this one, and there should be no duplicates.  Threading (and
+the rest) will still work as usual, but there might be problems with the
+sequence of articles.  Sorting on date might be an option here
+(@pxref{Selecting a Group}).
+
+One limitation, however---all groups included in a virtual
+group have to be alive (i.e., subscribed or unsubscribed).  Killed or
+zombie groups can't be component groups for @code{nnvirtual} groups.
+
+@vindex nnvirtual-always-rescan
+If the @code{nnvirtual-always-rescan} variable is non-@code{nil} (which
+is the default), @code{nnvirtual} will always scan groups for unread
+articles when entering a virtual group.  If this variable is @code{nil}
+and you read articles in a component group after the virtual group has
+been activated, the read articles from the component group will show up
+when you enter the virtual group.  You'll also see this effect if you
+have two virtual groups that have a component group in common.  If
+that's the case, you should set this variable to @code{t}.  Or you can
+just tap @code{M-g} on the virtual group every time before 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 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 back end.  (Just to be on the safe side.)
+
+@kbd{C-c C-n} in the message buffer will insert the @code{Newsgroups}
+line from the article you respond to in these cases.
+
+@code{nnvirtual} groups do not inherit anything but articles and marks
+from component groups---group parameters, for instance, are not
+inherited.
+
+
+@node Email Based Diary
+@section Email Based Diary
+@cindex diary
+@cindex email based diary
+@cindex calendar
+
+This section describes a special mail back end called @code{nndiary},
+and its companion library @code{gnus-diary}.  It is ``special'' in the
+sense that it is not meant to be one of the standard alternatives for
+reading mail with Gnus.  See @ref{Choosing a Mail Back End} for that.
+Instead, it is used to treat @emph{some} of your mails in a special way,
+namely, as event reminders.
+
+Here is a typical scenario:
+
+@itemize @bullet
+@item
+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.
+@item
+So you send a ``reminder'' message (actually, a diary one) to yourself.
+@item
+You forget all about it and keep on getting and reading new mail, as usual.
+@item
+From time to time, as you type @kbd{g} in the group buffer and as the date
+is getting closer, the message will pop up again to remind you of your
+appointment, just as if it were new and unread.
+@item
+Read your ``new'' messages, this one included, and start dreaming again
+of the night you're gonna have.
+@item
+Once the date is over (you actually fell asleep just after dinner), the
+message will be automatically deleted if it is marked as expirable.
+@end itemize
+
+The Gnus Diary back end has the ability to handle regular appointments
+(that wouldn't ever be deleted) as well as punctual ones, operates as a
+real mail back end and is configurable in many ways.  All of this is
+explained in the sections below.
+
+@menu
+* The NNDiary Back End::        Basic setup and usage.
+* The Gnus Diary Library::      Utility toolkit on top of nndiary.
+* Sending or Not Sending::      A final note on sending diary messages.
+@end menu
+
+
+@node The NNDiary Back End
+@subsection The NNDiary Back End
+@cindex nndiary
+@cindex the nndiary back end
+
+@code{nndiary} is a back end very similar to @code{nnml} (@pxref{Mail
+Spool}).  Actually, it could appear as a mix of @code{nnml} and
+@code{nndraft}.  If you know @code{nnml}, you're already familiar with
+the message storing scheme of @code{nndiary}: one file per message, one
+directory per group.
+
+  Before anything, there is one requirement to be able to run
+@code{nndiary} properly: you @emph{must} use the group timestamp feature
+of Gnus.  This adds a timestamp to each group's parameters.  @ref{Group
+Timestamp} to see how it's done.
+
+@menu
+* Diary Messages::              What makes a message valid for nndiary.
+* Running NNDiary::             NNDiary has two modes of operation.
+* Customizing NNDiary::         Bells and whistles.
+@end menu
+
+@node Diary Messages
+@subsubsection Diary Messages
+@cindex nndiary messages
+@cindex nndiary mails
+
+@code{nndiary} messages are just normal ones, except for the mandatory
+presence of 7 special headers.  These headers are of the form
+@code{X-Diary-<something>}, @code{<something>} being one of
+@code{Minute}, @code{Hour}, @code{Dom}, @code{Month}, @code{Year},
+@code{Time-Zone} and @code{Dow}.  @code{Dom} means ``Day of Month'', and
+@code{dow} means ``Day of Week''.  These headers actually behave like
+crontab specifications and define the event date(s):
+
+@itemize @bullet
+@item
+For all headers except the @code{Time-Zone} one, a header value is
+either a star (meaning all possible values), or a list of fields
+(separated by a comma).
+@item
+A field is either an integer, or a range.
+@item
+A range is two integers separated by a dash.
+@item
+Possible integer values are 0--59 for @code{Minute}, 0--23 for
+@code{Hour}, 1--31 for @code{Dom}, 1--12 for @code{Month}, above 1971
+for @code{Year} and 0--6 for @code{Dow} (0 meaning Sunday).
+@item
+As a special case, a star in either @code{Dom} or @code{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.
+@item
+The @code{Time-Zone} header is special in that it can only have one
+value (@code{GMT}, for instance).  A star doesn't mean ``all possible
+values'' (because it makes no sense), but ``the current local time
+zone''.  Most of the time, you'll be using a star here.  However, for a
+list of available time zone values, see the variable
+@code{nndiary-headers}.
+@end itemize
+
+As a concrete example, here are the diary headers to add to your message
+for specifying ``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'll let you find
+what to do then):
+
+@example
+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: *
+@end example
+
+@node Running NNDiary
+@subsubsection Running NNDiary
+@cindex running nndiary
+@cindex nndiary operation modes
+
+@code{nndiary} has two modes of operation: ``traditional'' (the default)
+and ``autonomous''.  In traditional mode, @code{nndiary} does not get new
+mail by itself.  You have to move (@kbd{B m}) or copy (@kbd{B c}) mails
+from your primary mail back end to nndiary groups in order to handle them
+as diary messages.  In autonomous mode, @code{nndiary} retrieves its own
+mail and handles it independently from your primary mail back end.
+
+One should note that Gnus is not inherently designed to allow several
+``master'' mail back ends at the same time.  However, this does make
+sense with @code{nndiary}: you really want to send and receive diary
+messages to your diary groups directly.  So, @code{nndiary} supports
+being sort of a ``second primary mail back end'' (to my knowledge, it is
+the only back end offering this feature).  However, there is a limitation
+(which I hope to fix some day): respooling doesn't work in autonomous
+mode.
+
+In order to use @code{nndiary} in autonomous mode, you have several
+things to do:
+
+@itemize @bullet
+@item
+Allow @code{nndiary} to retrieve new mail by itself.  Put the following
+line in your @file{~/.gnus.el} file:
+
+@lisp
+(setq nndiary-get-new-mail t)
+@end lisp
+@item
+You must arrange for diary messages (those containing @code{X-Diary-*}
+headers) to be split in a private folder @emph{before} Gnus treat them.
+Again, this is needed because Gnus cannot (yet ?) properly handle
+multiple primary mail back ends.  Getting those messages from a separate
+source will compensate this misfeature to some extent.
+
+As an example, here's my procmailrc entry to store diary files in
+@file{~/.nndiary} (the default @code{nndiary} mail source file):
+
+@example
+:0 HD :
+* ^X-Diary
+.nndiary
+@end example
+@end itemize
+
+Once this is done, you might want to customize the following two options
+that affect the diary mail retrieval and splitting processes:
+
+@defvar nndiary-mail-sources
+This is the diary-specific replacement for the standard
+@code{mail-sources} variable.  It obeys the same syntax, and defaults to
+@code{(file :path "~/.nndiary")}.
+@end defvar
+
+@defvar nndiary-split-methods
+This is the diary-specific replacement for the standard
+@code{nnmail-split-methods} variable.  It obeys the same syntax.
+@end defvar
+
+  Finally, you may add a permanent @code{nndiary} virtual server
+(something like @code{(nndiary "diary")} should do) to your
+@code{gnus-secondary-select-methods}.
+
+  Hopefully, almost everything (see the TODO section in
+@file{nndiary.el}) will work as expected when you restart Gnus: in
+autonomous mode, typing @kbd{g} and @kbd{M-g} in the group buffer, will
+also get your new diary mails and split them according to your
+diary-specific rules, @kbd{F} will find your new diary groups etc.
+
+@node Customizing NNDiary
+@subsubsection Customizing NNDiary
+@cindex customizing nndiary
+@cindex nndiary customization
+
+Now that @code{nndiary} is up and running, it's time to customize it.
+The custom group is called @code{nndiary} (no, really ?!).  You should
+browse it to figure out which options you'd like to tweak.  The following
+two variables are probably the only ones you will want to change:
+
+@defvar nndiary-reminders
+This is the list of times when you want to be reminded of your
+appointments (e.g., 3 weeks before, then 2 days before, then 1 hour
+before and that's it).  Remember that ``being reminded'' means that the
+diary message will pop up as brand new and unread again when you get new
+mail.
+@end defvar
+
+@defvar nndiary-week-starts-on-monday
+Rather self-explanatory.  Otherwise, Sunday is assumed (this is the
+default).
+@end defvar
+
+
+@node The Gnus Diary Library
+@subsection The Gnus Diary Library
+@cindex gnus-diary
+@cindex the gnus diary library
+
+Using @code{nndiary} manually (I mean, writing the headers by hand and
+so on) would be rather boring.  Fortunately, there is a library called
+@code{gnus-diary} written on top of @code{nndiary}, that does many
+useful things for you.
+
+  In order to use it, add the following line to your @file{~/.gnus.el} file:
+
+@lisp
+(require 'gnus-diary)
+@end lisp
+
+  Also, you shouldn't use any @code{gnus-user-format-function-[d|D]}
+(@pxref{Summary Buffer Lines}).  @code{gnus-diary} provides both of these
+(sorry if you used them before).
+
+
+@menu
+* Diary Summary Line Format::           A nicer summary buffer line format.
+* Diary Articles Sorting::              A nicer way to sort messages.
+* Diary Headers Generation::            Not doing it manually.
+* Diary Group Parameters::              Not handling them manually.
+@end menu
+
+@node Diary Summary Line Format
+@subsubsection Diary Summary Line Format
+@cindex diary summary buffer line
+@cindex diary summary line format
+
+Displaying diary messages in standard summary line format (usually
+something like @samp{From Joe: Subject}) is pretty useless.  Most of
+the time, you're the one who wrote the message, and you mostly want to
+see the event's date.
+
+  @code{gnus-diary} provides two supplemental user formats to be used in
+summary line formats.  @code{D} corresponds to a formatted time string
+for the next occurrence of the event (e.g., ``Sat, Sep 22 01, 12:00''),
+while @code{d} corresponds to an approximate remaining time until the
+next occurrence of the event (e.g., ``in 6 months, 1 week'').
+
+  For example, here's how Joe's birthday is displayed in my
+@code{nndiary+diary:birthdays} summary buffer (note that the message is
+expirable, but will never be deleted, as it specifies a periodic event):
+
+@example
+   E  Sat, Sep 22 01, 12:00: Joe's birthday (in 6 months, 1 week)
+@end example
+
+In order to get something like the above, you would normally add the
+following line to your diary groups'parameters:
+
+@lisp
+(gnus-summary-line-format "%U%R%z %uD: %(%s%) (%ud)\n")
+@end lisp
+
+However, @code{gnus-diary} does it automatically (@pxref{Diary Group
+Parameters}).  You can however customize the provided summary line format
+with the following user options:
+
+@defvar gnus-diary-summary-line-format
+Defines the summary line format used for diary groups (@pxref{Summary
+Buffer Lines}).  @code{gnus-diary} uses it to automatically update the
+diary groups'parameters.
+@end defvar
+
+@defvar gnus-diary-time-format
+Defines the format to display dates in diary summary buffers.  This is
+used by the @code{D} user format.  See the docstring for details.
+@end defvar
+
+@defvar gnus-diary-delay-format-function
+Defines the format function to use for displaying delays (remaining
+times) in diary summary buffers.  This is used by the @code{d} user
+format.  There are currently built-in functions for English and French;
+you can also define your own.  See the docstring for details.
+@end defvar
+
+@node Diary Articles Sorting
+@subsubsection Diary Articles Sorting
+@cindex diary articles sorting
+@cindex diary summary lines sorting
+@findex gnus-summary-sort-by-schedule
+@findex gnus-thread-sort-by-schedule
+@findex gnus-article-sort-by-schedule
+
+@code{gnus-diary} provides new sorting functions (@pxref{Sorting the
+Summary Buffer} ) called @code{gnus-summary-sort-by-schedule},
+@code{gnus-thread-sort-by-schedule} and
+@code{gnus-article-sort-by-schedule}.  These functions let you organize
+your diary summary buffers from the closest event to the farthest one.
+
+@code{gnus-diary} automatically installs
+@code{gnus-summary-sort-by-schedule} as a menu item in the summary
+buffer's ``sort'' menu, and the two others as the primary (hence
+default) sorting functions in the group parameters (@pxref{Diary Group
+Parameters}).
+
+@node Diary Headers Generation
+@subsubsection Diary Headers Generation
+@cindex diary headers generation
+@findex gnus-diary-check-message
+
+@code{gnus-diary} provides a function called
+@code{gnus-diary-check-message} to help you handle the @code{X-Diary-*}
+headers.  This function ensures that the current message contains all the
+required diary headers, and prompts you for values or corrections if
+needed.
+
+  This function is hooked into the @code{nndiary} back end, so that
+moving or copying an article to a diary group will trigger it
+automatically.  It is also bound to @kbd{C-c C-f d} in
+@code{message-mode} and @code{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 or validity.  That way,
+you can very easily reschedule an already valid diary message, for
+instance.
+
+@node Diary Group Parameters
+@subsubsection Diary Group Parameters
+@cindex diary group parameters
+
+When you create a new diary group, or visit one, @code{gnus-diary}
+automatically checks your group parameters and if needed, sets the
+summary line format to the diary-specific value, installs the
+diary-specific sorting functions, and also adds the different
+@code{X-Diary-*} headers to the group's posting-style.  It is then easier
+to send a diary message, because if you use @kbd{C-u a} or @kbd{C-u m}
+on a diary group to prepare a message, these headers will be inserted
+automatically (although not filled with proper values yet).
+
+@node Sending or Not Sending
+@subsection Sending or Not Sending
+
+Well, assuming you've read all of the above, here are two final notes on
+mail sending with @code{nndiary}:
+
+@itemize @bullet
+@item
+@code{nndiary} is a @emph{real} mail back end.  You really send real diary
+messages for real.  This means for instance that you can give
+appointments to anybody (provided they use Gnus and @code{nndiary}) by
+sending the diary message to them as well.
+@item
+However, since @code{nndiary} also has a @code{request-post} method, you
+can also use @kbd{C-u a} instead of @kbd{C-u m} on a diary group and the
+message won't actually be sent; just stored locally in the group.  This
+comes in very handy for private appointments.
+@end itemize
+
+@node Gnus Unplugged
+@section Gnus Unplugged
+@cindex offline
+@cindex unplugged
+@cindex agent
+@cindex Gnus agent
+@cindex Gnus unplugged
+
+In olden times (ca. February '88), people used to run their newsreaders
+on big machines with permanent connections to the net.  News transport
+was dealt with by news servers, and all the newsreaders had to do was to
+read news.  Believe it or not.
+
+Nowadays most people read news and mail at home, and use some sort of
+modem to connect to the net.  To avoid running up huge phone bills, it
+would be nice to have a way to slurp down all the news and mail, hang up
+the phone, read for several hours, and then upload any responses you
+have to make.  And then you repeat the procedure.
+
+Of course, you can use news servers for doing this as well.  I've used
+@code{inn} together with @code{slurp}, @code{pop} and @code{sendmail}
+for some years, but doing that's a bore.  Moving the news server
+functionality up to the newsreader makes sense if you're the only person
+reading news on a machine.
+
+Setting up Gnus as an ``offline'' newsreader is quite simple.  In
+fact, you don't have to configure anything as the agent is now enabled
+by default (@pxref{Agent Variables, gnus-agent}).
+
+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 Visuals::               Ways that the agent may effect your summary buffer.
+* Agent as Cache::              The Agent is a big cache too.
+* Agent Expiry::                How to make old articles go away.
+* Agent Regeneration::          How to recover from lost connections and other accidents.
+* Agent and flags::             How the Agent maintains flags.
+* Agent and IMAP::              How to use the Agent with @acronym{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
+
+
+@node Agent Basics
+@subsection Agent Basics
+
+First, let's get some terminology out of the way.
+
+The Gnus Agent is said to be @dfn{unplugged} when you have severed the
+connection to the net (and notified the Agent that this is the case).
+When the connection to the net is up again (and Gnus knows this), the
+Agent is @dfn{plugged}.
+
+The @dfn{local} machine is the one you're running on, and which isn't
+connected to the net continuously.
+
+@dfn{Downloading} means fetching things from the net to your local
+machine.  @dfn{Uploading} is doing the opposite.
+
+You know that Gnus gives you all the opportunity you'd ever want for
+shooting yourself in the foot.  Some people call it flexibility.  Gnus
+is also customizable to a great extent, which means that the user has a
+say on how Gnus behaves.  Other newsreaders might unconditionally shoot
+you in your foot, but with Gnus, you have a choice!
+
+Gnus is never really in plugged or unplugged state.  Rather, it applies
+that state to each server individually.  This means that some servers
+can be plugged while others can be unplugged.  Additionally, some
+servers can be ignored by the Agent altogether (which means that
+they're kinda like plugged always).
+
+So when you unplug the Agent and then wonder why is Gnus opening a
+connection to the Net, the next step to do is to look whether all
+servers are agentized.  If there is an unagentized server, you found
+the culprit.
+
+Another thing is the @dfn{offline} state.  Sometimes, servers aren't
+reachable.  When Gnus notices this, it asks you whether you want the
+server to be switched to offline state.  If you say yes, then the
+server will behave somewhat as if it was unplugged, except that Gnus
+will ask you whether you want to switch it back online again.
+
+Let's take a typical Gnus session using the Agent.
+
+@itemize @bullet
+
+@item
+@findex gnus-unplugged
+You start Gnus with @code{gnus-unplugged}.  This brings up the Gnus
+Agent in a disconnected state.  You can read all the news that you have
+already fetched while in this mode.
+
+@item
+You then decide to see whether any new news has arrived.  You connect
+your machine to the net (using PPP or whatever), and then hit @kbd{J j}
+to make Gnus become @dfn{plugged} and use @kbd{g} to check for new mail
+as usual.  To check for new mail in unplugged mode (@pxref{Mail
+Source Specifiers}).
+
+@item
+You can then read the new news immediately, or you can download the
+news onto your local machine.  If you want to do the latter, you press
+@kbd{g} to check if there are any new news and then @kbd{J s} to fetch
+all the eligible articles in all the groups.  (To let Gnus know which
+articles you want to download, @pxref{Agent Categories}).
+
+@item
+After fetching the articles, you press @kbd{J j} to make Gnus become
+unplugged again, and you shut down the PPP thing (or whatever).  And
+then you read the news offline.
+
+@item
+And then you go to step 2.
+@end itemize
+
+Here are some things you should do the first time (or so) that you use
+the Agent.
+
+@itemize @bullet
+
+@item
+Decide which servers should be covered by the Agent.  If you have a mail
+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} on the server (or servers) that you wish to have covered by the
+Agent (@pxref{Server Agent Commands}), or @kbd{J r} on automatically
+added servers you do not wish to have covered by the Agent.  By default,
+no servers are agentized.
+
+@item
+Decide on download policy.  It's fairly simple once you decide whether
+you are going to use agent categories, topic parameters, and/or group
+parameters to implement your policy.  If you're new to gnus, it
+is probably best to start with a category, @xref{Agent Categories}.
+
+Both topic parameters (@pxref{Topic Parameters}) and agent categories
+(@pxref{Agent Categories}) provide for setting a policy that applies
+to multiple groups.  Which you use is entirely up to you.  Topic
+parameters do override categories so, if you mix the two, you'll have
+to take that into account.  If you have a few groups that deviate from
+your policy, you can use group parameters (@pxref{Group Parameters}) to
+configure them.
+
+@item
+Uhm@dots{} that's it.
+@end itemize
+
+
+@node Agent Categories
+@subsection Agent Categories
+
+One of the main reasons to integrate the news transport layer into the
+newsreader is to allow greater control over what articles to download.
+There's not much point in downloading huge amounts of articles, just to
+find out that you're not interested in reading any of them.  It's better
+to be somewhat more conservative in choosing what to download, and then
+mark the articles for downloading manually if it should turn out that
+you're interested in the articles anyway.
+
+One of the more effective methods for controlling what is to be
+downloaded is to create a @dfn{category} and then assign some (or all)
+groups to this category.  Groups that do not belong in any other
+category belong to the @code{default} category.  Gnus has its own
+buffer for creating and managing categories.
+
+If you prefer, you can also use group parameters (@pxref{Group
+Parameters}) and topic parameters (@pxref{Topic Parameters}) for an
+alternative approach to controlling the agent.  The only real
+difference is that categories are specific to the agent (so there is
+less to learn) while group and topic parameters include the kitchen
+sink.
+
+Since you can set agent parameters in several different places we have
+a rule to decide which source to believe.  This rule specifies that
+the parameter sources are checked in the following order: group
+parameters, topic parameters, agent category, and finally customizable
+variables.  So you can mix all of these sources to produce a wide range
+of behavior, just don't blame me if you don't remember where you put
+your settings.
+
+@menu
+* Category Syntax::             What a category looks like.
+* Category Buffer::             A buffer for maintaining categories.
+* Category Variables::          Customize'r'Us.
+@end menu
+
+
+@node Category Syntax
+@subsubsection Category Syntax
+
+A category consists of a name, the list of groups belonging to the
+category, and a number of optional parameters that override the
+customizable variables.  The complete list of agent parameters are
+listed below.
+
+@cindex Agent Parameters
+@table @code
+@item agent-groups
+The list of groups that are in this category.
+
+@item agent-predicate
+A predicate which (generally) gives a rough outline of which articles
+are eligible for downloading; and
+
+@item agent-score
+a score rule which (generally) gives you a finer granularity when
+deciding what articles to download.  (Note that this @dfn{download
+score} is not necessarily related to normal scores.)
+
+@item agent-enable-expiration
+a boolean indicating whether the agent should expire old articles in
+this group.  Most groups should be expired to conserve disk space.  In
+fact, its probably safe to say that the gnus.* hierarchy contains the
+only groups that should not be expired.
+
+@item agent-days-until-old
+an integer indicating the number of days that the agent should wait
+before deciding that a read article is safe to expire.
+
+@item agent-low-score
+an integer that overrides the value of @code{gnus-agent-low-score}.
+
+@item agent-high-score
+an integer that overrides the value of @code{gnus-agent-high-score}.
+
+@item agent-short-article
+an integer that overrides the value of
+@code{gnus-agent-short-article}.
+
+@item agent-long-article
+an integer that overrides the value of @code{gnus-agent-long-article}.
+
+@item agent-enable-undownloaded-faces
+a symbol indicating whether the summary buffer should display
+undownloaded articles using the @code{gnus-summary-*-undownloaded-face}
+faces.  Any symbol other than @code{nil} will enable the use of
+undownloaded faces.
+@end table
+
+The name of a category can not be changed once the category has been
+created.
+
+Each category maintains a list of groups that are exclusive members of
+that category.  The exclusivity rule is automatically enforced, add a
+group to a new category and it is automatically removed from its old
+category.
+
+A predicate in its simplest form can be a single predicate such as
+@code{true} or @code{false}.  These two will download every available
+article or nothing respectively.  In the case of these two special
+predicates an additional score rule is superfluous.
+
+Predicates of @code{high} or @code{low} download articles in respect of
+their scores in relationship to @code{gnus-agent-high-score} and
+@code{gnus-agent-low-score} as described below.
+
+To gain even finer control of what is to be regarded eligible for
+download a predicate can consist of a number of predicates with logical
+operators sprinkled in between.
+
+Perhaps some examples are in order.
+
+Here's a simple predicate.  (It's the default predicate, in fact, used
+for all groups that don't belong to any other category.)
+
+@lisp
+short
+@end lisp
+
+Quite simple, eh?  This predicate is true if and only if the article is
+short (for some value of ``short'').
+
+Here's a more complex predicate:
+
+@lisp
+(or high
+    (and
+     (not low)
+     (not long)))
+@end lisp
+
+This means that an article should be downloaded if it has a high score,
+or if the score is not low and the article is not long.  You get the
+drift.
+
+The available logical operators are @code{or}, @code{and} and
+@code{not}.  (If you prefer, you can use the more ``C''-ish operators
+@samp{|}, @code{&} and @code{!} instead.)
+
+The following predicates are pre-defined, but if none of these fit what
+you want to do, you can write your own.
+
+When evaluating each of these predicates, the named constant will be
+bound to the value determined by calling
+@code{gnus-agent-find-parameter} on the appropriate parameter.  For
+example, gnus-agent-short-article will be bound to
+@code{(gnus-agent-find-parameter group 'agent-short-article)}.  This
+means that you can specify a predicate in your category then tune that
+predicate to individual groups.
+
+@table @code
+@item short
+True if the article is shorter than @code{gnus-agent-short-article}
+lines; default 100.
+
+@item long
+True if the article is longer than @code{gnus-agent-long-article}
+lines; default 200.
+
+@item low
+True if the article has a download score less than
+@code{gnus-agent-low-score}; default 0.
+
+@item high
+True if the article has a download score greater than
+@code{gnus-agent-high-score}; default 0.
+
+@item spam
+True if the Gnus Agent guesses that the article is spam.  The
+heuristics may change over time, but at present it just computes a
+checksum and sees whether articles match.
+
+@item true
+Always true.
+
+@item false
+Always false.
+@end table
+
+If you want to create your own predicate function, here's what you have
+to know:  The functions are called with no parameters, but the
+@code{gnus-headers} and @code{gnus-score} dynamic variables are bound to
+useful values.
+
+For example, you could decide that you don't want to download articles
+that were posted more than a certain number of days ago (e.g., posted
+more than @code{gnus-agent-expire-days} ago) you might write a function
+something along the lines of the following:
+
+@lisp
+(defun my-article-old-p ()
+  "Say whether an article is old."
+  (< (time-to-days (date-to-time (mail-header-date gnus-headers)))
+     (- (time-to-days (current-time)) gnus-agent-expire-days)))
+@end lisp
+
+with the predicate then defined as:
+
+@lisp
+(not my-article-old-p)
+@end lisp
+
+or you could append your predicate to the predefined
+@code{gnus-category-predicate-alist} in your @file{~/.gnus.el} or
+wherever.
+
+@lisp
+(require 'gnus-agent)
+(setq  gnus-category-predicate-alist
+  (append gnus-category-predicate-alist
+         '((old . my-article-old-p))))
+@end lisp
+
+and simply specify your predicate as:
+
+@lisp
+(not old)
+@end lisp
+
+If/when using something like the above, be aware that there are many
+misconfigured systems/mailers out there and so an article's date is not
+always a reliable indication of when it was posted.  Hell, some people
+just don't give a damn.
+
+The above predicates apply to @emph{all} the groups which belong to the
+category.  However, if you wish to have a specific predicate for an
+individual group within a category, or you're just too lazy to set up a
+new category, you can enter a group's individual predicate in its group
+parameters like so:
+
+@lisp
+(agent-predicate . short)
+@end lisp
+
+This is the group/topic parameter equivalent of the agent category default.
+Note that when specifying a single word predicate like this, the
+@code{agent-predicate} specification must be in dotted pair notation.
+
+The equivalent of the longer example from above would be:
+
+@lisp
+(agent-predicate or high (and (not low) (not long)))
+@end lisp
+
+The outer parenthesis required in the category specification are not
+entered here as, not being in dotted pair notation, the value of the
+predicate is assumed to be a list.
+
+
+Now, the syntax of the download score is the same as the syntax of
+normal score files, except that all elements that require actually
+seeing the article itself are verboten.  This means that only the
+following headers can be scored on: @code{Subject}, @code{From},
+@code{Date}, @code{Message-ID}, @code{References}, @code{Chars},
+@code{Lines}, and @code{Xref}.
+
+As with predicates, the specification of the @code{download score rule}
+to use in respect of a group can be in either the category definition if
+it's to be applicable to all groups in therein, or a group's parameters
+if it's to be specific to that group.
+
+In both of these places the @code{download score rule} can take one of
+three forms:
+
+@enumerate
+@item
+Score rule
+
+This has the same syntax as a normal Gnus score file except only a
+subset of scoring keywords are available as mentioned above.
+
+example:
+
+@itemize @bullet
+@item
+Category specification
+
+@lisp
+(("from"
+       ("Lars Ingebrigtsen" 1000000 nil s))
+("lines"
+       (500 -100 nil <)))
+@end lisp
+
+@item
+Group/Topic Parameter specification
+
+@lisp
+(agent-score ("from"
+                   ("Lars Ingebrigtsen" 1000000 nil s))
+             ("lines"
+                   (500 -100 nil <)))
+@end lisp
+
+Again, note the omission of the outermost parenthesis here.
+@end itemize
+
+@item
+Agent score file
+
+These score files must @emph{only} contain the permitted scoring
+keywords stated above.
+
+example:
+
+@itemize @bullet
+@item
+Category specification
+
+@lisp
+("~/News/agent.SCORE")
+@end lisp
+
+or perhaps
+
+@lisp
+("~/News/agent.SCORE" "~/News/agent.group.SCORE")
+@end lisp
+
+@item
+Group Parameter specification
+
+@lisp
+(agent-score "~/News/agent.SCORE")
+@end lisp
+
+Additional score files can be specified as above.  Need I say anything
+about parenthesis?
+@end itemize
+
+@item
+Use @code{normal} score files
+
+If you don't want to maintain two sets of scoring rules for a group, and
+your desired @code{downloading} criteria for a group are the same as your
+@code{reading} criteria then you can tell the agent to refer to your
+@code{normal} score files when deciding what to download.
+
+These directives in either the category definition or a group's
+parameters will cause the agent to read in all the applicable score
+files for a group, @emph{filtering out} those sections that do not
+relate to one of the permitted subset of scoring keywords.
+
+@itemize @bullet
+@item
+Category Specification
+
+@lisp
+file
+@end lisp
+
+@item
+Group Parameter specification
+
+@lisp
+(agent-score . file)
+@end lisp
+@end itemize
+@end enumerate
+
+@node Category Buffer
+@subsubsection Category Buffer
+
+You'd normally do all category maintenance from the category buffer.
+When you enter it for the first time (with the @kbd{J c} command from
+the group buffer), you'll only see the @code{default} category.
+
+The following commands are available in this buffer:
+
+@table @kbd
+@item q
+@kindex q (Category)
+@findex gnus-category-exit
+Return to the group buffer (@code{gnus-category-exit}).
+
+@item e
+@kindex e (Category)
+@findex gnus-category-customize-category
+Use a customization buffer to set all of the selected category's
+parameters at one time (@code{gnus-category-customize-category}).
+
+@item k
+@kindex k (Category)
+@findex gnus-category-kill
+Kill the current category (@code{gnus-category-kill}).
+
+@item c
+@kindex c (Category)
+@findex gnus-category-copy
+Copy the current category (@code{gnus-category-copy}).
+
+@item a
+@kindex a (Category)
+@findex gnus-category-add
+Add a new category (@code{gnus-category-add}).
+
+@item p
+@kindex p (Category)
+@findex gnus-category-edit-predicate
+Edit the predicate of the current category
+(@code{gnus-category-edit-predicate}).
+
+@item g
+@kindex g (Category)
+@findex gnus-category-edit-groups
+Edit the list of groups belonging to the current category
+(@code{gnus-category-edit-groups}).
+
+@item s
+@kindex s (Category)
+@findex gnus-category-edit-score
+Edit the download score rule of the current category
+(@code{gnus-category-edit-score}).
+
+@item l
+@kindex l (Category)
+@findex gnus-category-list
+List all the categories (@code{gnus-category-list}).
+@end table
+
+
+@node Category Variables
+@subsubsection Category Variables
+
+@table @code
+@item gnus-category-mode-hook
+@vindex gnus-category-mode-hook
+Hook run in category buffers.
+
+@item gnus-category-line-format
+@vindex gnus-category-line-format
+Format of the lines in the category buffer (@pxref{Formatting
+Variables}).  Valid elements are:
+
+@table @samp
+@item c
+The name of the category.
+
+@item g
+The number of groups in the category.
+@end table
+
+@item gnus-category-mode-line-format
+@vindex gnus-category-mode-line-format
+Format of the category mode line (@pxref{Mode Line Formatting}).
+
+@item gnus-agent-short-article
+@vindex gnus-agent-short-article
+Articles that have fewer lines than this are short.  Default 100.
+
+@item gnus-agent-long-article
+@vindex gnus-agent-long-article
+Articles that have more lines than this are long.  Default 200.
+
+@item gnus-agent-low-score
+@vindex gnus-agent-low-score
+Articles that have a score lower than this have a low score.  Default
+0.
+
+@item gnus-agent-high-score
+@vindex gnus-agent-high-score
+Articles that have a score higher than this have a high score.  Default
+0.
+
+@item gnus-agent-expire-days
+@vindex gnus-agent-expire-days
+The number of days that a @samp{read} article must stay in the agent's
+local disk before becoming eligible for expiration (While the name is
+the same, this doesn't mean expiring the article on the server.  It
+just means deleting the local copy of the article).  What is also
+important to understand is that the counter starts with the time the
+article was written to the local disk and not the time the article was
+read.
+Default 7.
+
+@item gnus-agent-enable-expiration
+@vindex gnus-agent-enable-expiration
+Determines whether articles in a group are, by default, expired or
+retained indefinitely.  The default is @code{ENABLE} which means that
+you'll have to disable expiration when desired.  On the other hand,
+you could set this to @code{DISABLE}.  In that case, you would then
+have to enable expiration in selected groups.
+
+@end table
+
+
+@node Agent Commands
+@subsection Agent Commands
+@findex gnus-agent-toggle-plugged
+@kindex J j (Agent)
+
+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
+toggles the plugged/unplugged state of the Gnus Agent.
+
+
+@menu
+* Group Agent Commands::        Configure groups and fetch their contents.
+* Summary Agent Commands::      Manually select then fetch specific articles.
+* Server Agent Commands::       Select the servers that are supported by the agent.
+@end menu
+
+
+
+
+@node Group Agent Commands
+@subsubsection Group Agent Commands
+
+@table @kbd
+@item J u
+@kindex J u (Agent Group)
+@findex gnus-agent-fetch-groups
+Fetch all eligible articles in the current group
+(@code{gnus-agent-fetch-groups}).
+
+@item J c
+@kindex J c (Agent Group)
+@findex gnus-enter-category-buffer
+Enter the Agent category buffer (@code{gnus-enter-category-buffer}).
+
+@item J s
+@kindex J s (Agent Group)
+@findex gnus-agent-fetch-session
+Fetch all eligible articles in all groups
+(@code{gnus-agent-fetch-session}).
+
+@item J S
+@kindex J S (Agent Group)
+@findex gnus-group-send-queue
+Send all sendable messages in the queue group
+(@code{gnus-group-send-queue}).  @xref{Drafts}.
+
+@item J a
+@kindex J a (Agent Group)
+@findex gnus-agent-add-group
+Add the current group to an Agent category
+(@code{gnus-agent-add-group}).  This command understands the
+process/prefix convention (@pxref{Process/Prefix}).
+
+@item J r
+@kindex J r (Agent Group)
+@findex gnus-agent-remove-group
+Remove the current group from its category, if any
+(@code{gnus-agent-remove-group}).  This command understands the
+process/prefix convention (@pxref{Process/Prefix}).
+
+@item J Y
+@kindex J Y (Agent Group)
+@findex gnus-agent-synchronize-flags
+Synchronize flags changed while unplugged with remote server, if any.
+
+
+@end table
+
+
+@node Summary Agent Commands
+@subsubsection Summary Agent Commands
+
+@table @kbd
+@item J #
+@kindex J # (Agent Summary)
+@findex gnus-agent-mark-article
+Mark the article for downloading (@code{gnus-agent-mark-article}).
+
+@item J M-#
+@kindex J M-# (Agent Summary)
+@findex gnus-agent-unmark-article
+Remove the downloading mark from the article
+(@code{gnus-agent-unmark-article}).
+
+@cindex %
+@item @@
+@kindex @@ (Agent Summary)
+@findex gnus-agent-toggle-mark
+Toggle whether to download the article
+(@code{gnus-agent-toggle-mark}).  The download mark is @samp{%} by
+default.
+
+@item J c
+@kindex J c (Agent Summary)
+@findex gnus-agent-catchup
+Mark all articles as read (@code{gnus-agent-catchup}) that are neither cached, downloaded, nor downloadable.
+
+@item J S
+@kindex J S (Agent Summary)
+@findex gnus-agent-fetch-group
+Download all eligible (@pxref{Agent Categories}) articles in this group.
+(@code{gnus-agent-fetch-group}).
+
+@item J s
+@kindex J s (Agent Summary)
+@findex gnus-agent-summary-fetch-series
+Download all processable articles in this group.
+(@code{gnus-agent-summary-fetch-series}).
+
+@item J u
+@kindex J u (Agent Summary)
+@findex gnus-agent-summary-fetch-group
+Download all downloadable articles in the current group
+(@code{gnus-agent-summary-fetch-group}).
+
+@end table
+
+
+@node Server Agent Commands
+@subsubsection Server Agent Commands
+
+@table @kbd
+@item J a
+@kindex J a (Agent Server)
+@findex gnus-agent-add-server
+Add the current server to the list of servers covered by the Gnus Agent
+(@code{gnus-agent-add-server}).
+
+@item J r
+@kindex J r (Agent Server)
+@findex gnus-agent-remove-server
+Remove the current server from the list of servers covered by the Gnus
+Agent (@code{gnus-agent-remove-server}).
+
+@end table
+
+
+@node Agent Visuals
+@subsection Agent Visuals
+
+If you open a summary while unplugged and, Gnus knows from the group's
+active range that there are more articles than the headers currently
+stored in the Agent, you may see some articles whose subject looks
+something like @samp{[Undownloaded article #####]}.  These are
+placeholders for the missing headers.  Aside from setting a mark,
+there is not much that can be done with one of these placeholders.
+When Gnus finally gets a chance to fetch the group's headers, the
+placeholders will automatically be replaced by the actual headers.
+You can configure the summary buffer's maneuvering to skip over the
+placeholders if you care (See @code{gnus-auto-goto-ignores}).
+
+While it may be obvious to all, the only headers and articles
+available while unplugged are those headers and articles that were
+fetched into the Agent while previously plugged.  To put it another
+way, ``If you forget to fetch something while plugged, you might have a
+less than satisfying unplugged session''.  For this reason, the Agent
+adds two visual effects to your summary buffer.  These effects display
+the download status of each article so that you always know which
+articles will be available when unplugged.
+
+The first visual effect is the @samp{%O} spec.  If you customize
+@code{gnus-summary-line-format} to include this specifier, you will add
+a single character field that indicates an article's download status.
+Articles that have been fetched into either the Agent or the Cache,
+will display @code{gnus-downloaded-mark} (defaults to @samp{+}).  All
+other articles will display @code{gnus-undownloaded-mark} (defaults to
+@samp{-}).  If you open a group that has not been agentized, a space
+(@samp{ }) will be displayed.
+
+The second visual effect are the undownloaded faces.  The faces, there
+are three indicating the article's score (low, normal, high), seem to
+result in a love/hate response from many Gnus users.  The problem is
+that the face selection is controlled by a list of condition tests and
+face names (See @code{gnus-summary-highlight}).  Each condition is
+tested in the order in which it appears in the list so early
+conditions have precedence over later conditions.  All of this means
+that, if you tick an undownloaded article, the article will continue
+to be displayed in the undownloaded face rather than the ticked face.
+
+If you use the Agent as a cache (to avoid downloading the same article
+each time you visit it or to minimize your connection time), the
+undownloaded face will probably seem like a good idea.  The reason
+being that you do all of our work (marking, reading, deleting) with
+downloaded articles so the normal faces always appear.  For those
+users using the agent to improve online performance by caching the NOV
+database (most users since 5.10.2), the undownloaded faces may appear
+to be an absolutely horrible idea.  The issue being that, since none
+of their articles have been fetched into the Agent, all of the
+normal faces will be obscured by the undownloaded faces.
+
+If you would like to use the undownloaded faces, you must enable the
+undownloaded faces by setting the @code{agent-enable-undownloaded-faces}
+group parameter to @code{t}.  This parameter, like all other agent
+parameters, may be set on an Agent Category (@pxref{Agent Categories}),
+a Group Topic (@pxref{Topic Parameters}), or an individual group
+(@pxref{Group Parameters}).
+
+The one problem common to all users using the agent is how quickly it
+can consume disk space.  If you using the agent on many groups, it is
+even more difficult to effectively recover disk space.  One solution
+is the @samp{%F} format available in @code{gnus-group-line-format}.
+This format will display the actual disk space used by articles
+fetched into both the agent and cache.  By knowing which groups use
+the most space, users know where to focus their efforts when ``agent
+expiring'' articles.
+
+@node Agent as Cache
+@subsection Agent as Cache
+
+When Gnus is plugged, it is not efficient to download headers or
+articles from the server again, if they are already stored in the
+Agent.  So, Gnus normally only downloads headers once, and stores them
+in the Agent.  These headers are later used when generating the summary
+buffer, regardless of whether you are plugged or unplugged.  Articles
+are not cached in the Agent by default though (that would potentially
+consume lots of disk space), but if you have already downloaded an
+article into the Agent, Gnus will not download the article from the
+server again but use the locally stored copy instead.
+
+If you so desire, you can configure the agent (see @code{gnus-agent-cache}
+@pxref{Agent Variables}) to always download headers and articles while
+plugged.  Gnus will almost certainly be slower, but it will be kept
+synchronized with the server.  That last point probably won't make any
+sense if you are using a nntp or nnimap back end.
+
+@node Agent Expiry
+@subsection Agent Expiry
+
+@vindex gnus-agent-expire-days
+@findex gnus-agent-expire
+@kindex M-x gnus-agent-expire
+@kindex M-x gnus-agent-expire-group
+@findex gnus-agent-expire-group
+@cindex agent expiry
+@cindex Gnus agent expiry
+@cindex expiry, in Gnus agent
+
+The Agent back end, @code{nnagent}, doesn't handle expiry.  Well, at
+least it doesn't handle it like other back ends.  Instead, there are
+special @code{gnus-agent-expire} and @code{gnus-agent-expire-group}
+commands that will expire all read articles that are older than
+@code{gnus-agent-expire-days} days.  They can be run whenever you feel
+that you're running out of space.  Neither are particularly fast or
+efficient, and it's not a particularly good idea to interrupt them (with
+@kbd{C-g} or anything else) once you've started one of them.
+
+Note that other functions might run @code{gnus-agent-expire} for you
+to keep the agent synchronized with the group.
+
+The agent parameter @code{agent-enable-expiration} may be used to
+prevent expiration in selected groups.
+
+@vindex gnus-agent-expire-all
+If @code{gnus-agent-expire-all} is non-@code{nil}, the agent
+expiration commands will expire all articles---unread, read, ticked
+and dormant.  If @code{nil} (which is the default), only read articles
+are eligible for expiry, and unread, ticked and dormant articles will
+be kept indefinitely.
+
+If you find that some articles eligible for expiry are never expired,
+perhaps some Gnus Agent files are corrupted.  There's are special
+commands, @code{gnus-agent-regenerate} and
+@code{gnus-agent-regenerate-group}, to fix possible problems.
+
+@node Agent Regeneration
+@subsection Agent Regeneration
+
+@cindex agent regeneration
+@cindex Gnus agent regeneration
+@cindex regeneration
+
+The local data structures used by @code{nnagent} may become corrupted
+due to certain exceptional conditions.  When this happens,
+@code{nnagent} functionality may degrade or even fail.  The solution
+to this problem is to repair the local data structures by removing all
+internal inconsistencies.
+
+For example, if your connection to your server is lost while
+downloaded articles into the agent, the local data structures will not
+know about articles successfully downloaded prior to the connection
+failure.  Running @code{gnus-agent-regenerate} or
+@code{gnus-agent-regenerate-group} will update the data structures
+such that you don't need to download these articles a second time.
+
+@findex gnus-agent-regenerate
+@kindex M-x gnus-agent-regenerate
+The command @code{gnus-agent-regenerate} will perform
+@code{gnus-agent-regenerate-group} on every agentized group.  While
+you can run @code{gnus-agent-regenerate} in any buffer, it is strongly
+recommended that you first close all summary buffers.
+
+@findex gnus-agent-regenerate-group
+@kindex M-x gnus-agent-regenerate-group
+The command @code{gnus-agent-regenerate-group} uses the local copies
+of individual articles to repair the local @acronym{NOV}(header) database.  It
+then updates the internal data structures that document which articles
+are stored locally.  An optional argument will mark articles in the
+agent as unread.
+
+@node Agent and flags
+@subsection Agent and flags
+
+The Agent works with any Gnus back end including those, such as
+nnimap, that store flags (read, ticked, etc.)@: on the server.  Sadly,
+the Agent does not actually know which backends keep their flags in
+the backend server rather than in @file{.newsrc}.  This means that the
+Agent, while unplugged or disconnected, will always record all changes
+to the flags in its own files.
+
+When you plug back in, Gnus will then check to see if you have any
+changed any flags and ask if you wish to synchronize these with the
+server.  This behavior is customizable by @code{gnus-agent-synchronize-flags}.
+
+@vindex gnus-agent-synchronize-flags
+If @code{gnus-agent-synchronize-flags} is @code{nil}, the Agent will
+never automatically synchronize flags.  If it is @code{ask}, which is
+the default, the Agent will check if you made any changes and if so
+ask if you wish to synchronize these when you re-connect.  If it has
+any other value, all flags will be synchronized automatically.
+
+If you do not wish to synchronize flags automatically when you
+re-connect, you can do it manually with the
+@code{gnus-agent-synchronize-flags} command that is bound to @kbd{J Y}
+in the group buffer.
+
+Technical note: the synchronization algorithm does not work by ``pushing''
+all local flags to the server, but rather by incrementally updated the
+server view of flags by changing only those flags that were changed by
+the user.  Thus, if you set one flag on an article, quit the group then
+re-select the group and remove the flag; the flag will be set and
+removed from the server when you ``synchronize''.  The queued flag
+operations can be found in the per-server @code{flags} file in the Agent
+directory.  It's emptied when you synchronize flags.
+
+@node Agent and IMAP
+@subsection Agent and IMAP
+
+The Agent works with any Gnus back end, including nnimap.  However,
+since there are some conceptual differences between @acronym{NNTP} and
+@acronym{IMAP}, this section (should) provide you with some information to
+make Gnus Agent work smoother as a @acronym{IMAP} Disconnected Mode client.
+
+Some things are currently not implemented in the Agent that you'd might
+expect from a disconnected @acronym{IMAP} client, including:
+
+@itemize @bullet
+
+@item
+Copying/moving articles into nnimap groups when unplugged.
+
+@item
+Creating/deleting nnimap groups when unplugged.
+
+@end itemize
+
+@node Outgoing Messages
+@subsection Outgoing Messages
+
+By default, when Gnus is unplugged, all outgoing messages (both mail
+and news) are stored in the draft group ``queue'' (@pxref{Drafts}).
+You can view them there after posting, and edit them at will.
+
+You can control the circumstances under which outgoing mail is queued
+(see @code{gnus-agent-queue-mail}, @pxref{Agent Variables}).  Outgoing
+news is always queued when Gnus is unplugged, and never otherwise.
+
+You can send the messages either from the draft group with the special
+commands available there, or you can use the @kbd{J S} command in the
+group buffer to send all the sendable messages in the draft group.
+Posting news will only work when Gnus is plugged, but you can send
+mail at any time.
+
+If sending mail while unplugged does not work for you and you worry
+about hitting @kbd{J S} by accident when unplugged, you can have Gnus
+ask you to confirm your action (see
+@code{gnus-agent-prompt-send-queue}, @pxref{Agent Variables}).
+
+@node Agent Variables
+@subsection Agent Variables
+
+@table @code
+@item gnus-agent
+@vindex gnus-agent
+Is the agent enabled?  The default is @code{t}.  When first enabled,
+the agent will use @code{gnus-agent-auto-agentize-methods} to
+automatically mark some back ends as agentized.  You may change which
+back ends are agentized using the agent commands in the server buffer.
+
+To enter the server buffer, use the @kbd{^}
+(@code{gnus-group-enter-server-mode}) command in the group buffer.
+
+
+@item gnus-agent-directory
+@vindex gnus-agent-directory
+Where the Gnus Agent will store its files.  The default is
+@file{~/News/agent/}.
+
+@item gnus-agent-handle-level
+@vindex gnus-agent-handle-level
+Groups on levels (@pxref{Group Levels}) higher than this variable will
+be ignored by the Agent.  The default is @code{gnus-level-subscribed},
+which means that only subscribed group will be considered by the Agent
+by default.
+
+@item gnus-agent-plugged-hook
+@vindex gnus-agent-plugged-hook
+Hook run when connecting to the network.
+
+@item gnus-agent-unplugged-hook
+@vindex gnus-agent-unplugged-hook
+Hook run when disconnecting from the network.
+
+@item gnus-agent-fetched-hook
+@vindex gnus-agent-fetched-hook
+Hook run when finished fetching articles.
+
+@item gnus-agent-cache
+@vindex gnus-agent-cache
+Variable to control whether use the locally stored @acronym{NOV} and
+articles when plugged, e.g., essentially using the Agent as a cache.
+The default is non-@code{nil}, which means to use the Agent as a cache.
+
+@item gnus-agent-go-online
+@vindex gnus-agent-go-online
+If @code{gnus-agent-go-online} is @code{nil}, the Agent will never
+automatically switch offline servers into online status.  If it is
+@code{ask}, the default, the Agent will ask if you wish to switch
+offline servers into online status when you re-connect.  If it has any
+other value, all offline servers will be automatically switched into
+online status.
+
+@item gnus-agent-mark-unread-after-downloaded
+@vindex gnus-agent-mark-unread-after-downloaded
+If @code{gnus-agent-mark-unread-after-downloaded} is non-@code{nil},
+mark articles as unread after downloading.  This is usually a safe
+thing to do as the newly downloaded article has obviously not been
+read.  The default is @code{t}.
+
+@item gnus-agent-synchronize-flags
+@vindex gnus-agent-synchronize-flags
+If @code{gnus-agent-synchronize-flags} is @code{nil}, the Agent will
+never automatically synchronize flags.  If it is @code{ask}, which is
+the default, the Agent will check if you made any changes and if so
+ask if you wish to synchronize these when you re-connect.  If it has
+any other value, all flags will be synchronized automatically.
+
+@item gnus-agent-consider-all-articles
+@vindex gnus-agent-consider-all-articles
+If @code{gnus-agent-consider-all-articles} is non-@code{nil}, the
+agent will let the agent predicate decide whether articles need to be
+downloaded or not, for all articles.  When @code{nil}, the default,
+the agent will only let the predicate decide whether unread articles
+are downloaded or not.  If you enable this, you may also want to look
+into the agent expiry settings (@pxref{Category Variables}), so that
+the agent doesn't download articles which the agent will later expire,
+over and over again.
+
+@item gnus-agent-max-fetch-size
+@vindex gnus-agent-max-fetch-size
+The agent fetches articles into a temporary buffer prior to parsing
+them into individual files.  To avoid exceeding the max. buffer size,
+the agent alternates between fetching and parsing until all articles
+have been fetched.  @code{gnus-agent-max-fetch-size} provides a size
+limit to control how often the cycling occurs.  A large value improves
+performance.  A small value minimizes the time lost should the
+connection be lost while fetching (You may need to run
+@code{gnus-agent-regenerate-group} to update the group's state.
+However, all articles parsed prior to losing the connection will be
+available while unplugged).  The default is 10M so it is unusual to
+see any cycling.
+
+@item gnus-server-unopen-status
+@vindex gnus-server-unopen-status
+Perhaps not an Agent variable, but closely related to the Agent, this
+variable says what will happen if Gnus cannot open a server.  If the
+Agent is enabled, the default, @code{nil}, makes Gnus ask the user
+whether to deny the server or whether to unplug the agent.  If the
+Agent is disabled, Gnus always simply deny the server.  Other choices
+for this variable include @code{denied} and @code{offline} the latter
+is only valid if the Agent is used.
+
+@item gnus-auto-goto-ignores
+@vindex gnus-auto-goto-ignores
+Another variable that isn't an Agent variable, yet so closely related
+that most will look for it here, this variable tells the summary
+buffer how to maneuver around undownloaded (only headers stored in the
+agent) and unfetched (neither article nor headers stored) articles.
+
+The valid values are @code{nil} (maneuver to any article),
+@code{undownloaded} (maneuvering while unplugged ignores articles that
+have not been fetched), @code{always-undownloaded} (maneuvering always
+ignores articles that have not been fetched), @code{unfetched}
+(maneuvering ignores articles whose headers have not been fetched).
+
+@item gnus-agent-queue-mail
+@vindex gnus-agent-queue-mail
+When @code{gnus-agent-queue-mail} is @code{always}, Gnus will always
+queue mail rather than sending it straight away.  When @code{t}, Gnus
+will queue mail when unplugged only.  When @code{nil}, never queue
+mail.  The default is @code{t}.
+
+@item gnus-agent-prompt-send-queue
+@vindex gnus-agent-prompt-send-queue
+When @code{gnus-agent-prompt-send-queue} is non-@code{nil} Gnus will
+prompt you to confirm that you really wish to proceed if you hit
+@kbd{J S} while unplugged.  The default is @code{nil}.
+
+@item gnus-agent-auto-agentize-methods
+@vindex gnus-agent-auto-agentize-methods
+If you have never used the Agent before (or more technically, if
+@file{~/News/agent/lib/servers} does not exist), Gnus will
+automatically agentize a few servers for you.  This variable control
+which back ends should be auto-agentized.  It is typically only useful
+to agentize remote back ends.  The auto-agentizing has the same effect
+as running @kbd{J a} on the servers (@pxref{Server Agent Commands}).
+If the file exist, you must manage the servers manually by adding or
+removing them, this variable is only applicable the first time you
+start Gnus.  The default is @samp{nil}.
+
+@end table
+
+
+@node Example Setup
+@subsection Example Setup
+
+If you don't want to read this manual, and you have a fairly standard
+setup, you may be able to use something like the following as your
+@file{~/.gnus.el} file to get started.
+
+@lisp
+;; @r{Define how Gnus is to fetch news.  We do this over @acronym{NNTP}}
+;; @r{from your ISP's server.}
+(setq gnus-select-method '(nntp "news.your-isp.com"))
+
+;; @r{Define how Gnus is to read your mail.  We read mail from}
+;; @r{your ISP's @acronym{POP} server.}
+(setq mail-sources '((pop :server "pop.your-isp.com")))
+
+;; @r{Say how Gnus is to store the mail.  We use nnml groups.}
+(setq gnus-secondary-select-methods '((nnml "")))
+
+;; @r{Make Gnus into an offline newsreader.}
+;; (gnus-agentize) ; @r{The obsolete setting.}
+;; (setq gnus-agent t) ; @r{Now the default.}
+@end lisp
+
+That should be it, basically.  Put that in your @file{~/.gnus.el} file,
+edit to suit your needs, start up PPP (or whatever), and type @kbd{M-x
+gnus}.
+
+If this is the first time you've run Gnus, you will be subscribed
+automatically to a few default newsgroups.  You'll probably want to
+subscribe to more groups, and to do that, you have to query the
+@acronym{NNTP} server for a complete list of groups with the @kbd{A A}
+command.  This usually takes quite a while, but you only have to do it
+once.
+
+After reading and parsing a while, you'll be presented with a list of
+groups.  Subscribe to the ones you want to read with the @kbd{u}
+command.  @kbd{l} to make all the killed groups disappear after you've
+subscribe to all the groups you want to read.  (@kbd{A k} will bring
+back all the killed groups.)
+
+You can now read the groups at once, or you can download the articles
+with the @kbd{J s} command.  And then read the rest of this manual to
+find out which of the other gazillion things you want to customize.
+
+
+@node Batching Agents
+@subsection Batching Agents
+@findex gnus-agent-batch
+
+Having the Gnus Agent fetch articles (and post whatever messages you've
+written) is quite easy once you've gotten things set up properly.  The
+following shell script will do everything that is necessary:
+
+You can run a complete batch command from the command line with the
+following incantation:
+
+@example
+#!/bin/sh
+emacs -batch -l ~/.emacs -l ~/.gnus.el -f gnus-agent-batch >/dev/null 2>&1
+@end example
+
+
+@node Agent Caveats
+@subsection Agent Caveats
+
+The Gnus Agent doesn't seem to work like most other offline
+newsreaders.  Here are some common questions that some imaginary people
+may ask:
+
+@table @dfn
+@item If I read an article while plugged, do they get entered into the Agent?
+
+@strong{No}.  If you want this behavior, add
+@code{gnus-agent-fetch-selected-article} to
+@code{gnus-select-article-hook}.
+
+@item If I read an article while plugged, and the article already exists in
+the Agent, will it get downloaded once more?
+
+@strong{No}, unless @code{gnus-agent-cache} is @code{nil}.
+
+@end table
+
+In short, when Gnus is unplugged, it only looks into the locally stored
+articles; when it's plugged, it talks to your ISP and may also use the
+locally stored articles.
+
+
+@node Scoring
+@chapter Scoring
+@cindex scoring
+
+Other people use @dfn{kill files}, but we here at Gnus Towers like
+scoring better than killing, so we'd rather switch than fight.  They do
+something completely different as well, so sit up straight and pay
+attention!
+
+@vindex gnus-summary-mark-below
+All articles have a default score (@code{gnus-summary-default-score}),
+which is 0 by default.  This score may be raised or lowered either
+interactively or by score files.  Articles that have a score lower than
+@code{gnus-summary-mark-below} are marked as read.
+
+Gnus will read any @dfn{score files} that apply to the current group
+before generating the summary buffer.
+
+There are several commands in the summary buffer that insert score
+entries based on the current article.  You can, for instance, ask Gnus to
+lower or increase the score of all articles with a certain subject.
+
+There are two sorts of scoring entries: Permanent and temporary.
+Temporary score entries are self-expiring entries.  Any entries that are
+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 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.
+* Advanced Scoring::            Using logical expressions to build score rules.
+* Score Decays::                It can be useful to let scores wither away.
+@end menu
+
+
+@node Summary Score Commands
+@section Summary Score Commands
+@cindex score commands
+
+The score commands that alter score entries do not actually modify real
+score files.  That would be too inefficient.  Gnus maintains a cache of
+previously loaded score files, one of which is considered the
+@dfn{current score file alist}.  The score commands simply insert
+entries into this list, and upon group exit, this list is saved.
+
+The current score file is by default the group's local score file, even
+if no such score file actually exists.  To insert score commands into
+some other score file (e.g., @file{all.SCORE}), you must first make this
+score file the current one.
+
+General score commands that don't actually change the score file:
+
+@table @kbd
+
+@item V s
+@kindex V s (Summary)
+@findex gnus-summary-set-score
+Set the score of the current article (@code{gnus-summary-set-score}).
+
+@item V S
+@kindex V S (Summary)
+@findex gnus-summary-current-score
+Display the score of the current article
+(@code{gnus-summary-current-score}).
+
+@item V t
+@kindex V t (Summary)
+@findex gnus-score-find-trace
+Display all score rules that have been used on the current article
+(@code{gnus-score-find-trace}).  In the @file{*Score Trace*} buffer, you
+may type @kbd{e} to edit score file corresponding to the score rule on
+current line and @kbd{f} to format (@code{gnus-score-pretty-print}) the
+score file and edit it.
+
+@item V w
+@kindex V w (Summary)
+@findex gnus-score-find-favourite-words
+List words used in scoring (@code{gnus-score-find-favourite-words}).
+
+@item V R
+@kindex V R (Summary)
+@findex gnus-summary-rescore
+Run the current summary through the scoring process
+(@code{gnus-summary-rescore}).  This might be useful if you're playing
+around with your score files behind Gnus' back and want to see the
+effect you're having.
+
+@item V c
+@kindex V c (Summary)
+@findex gnus-score-change-score-file
+Make a different score file the current
+(@code{gnus-score-change-score-file}).
+
+@item V e
+@kindex V e (Summary)
+@findex gnus-score-edit-current-scores
+Edit the current score file (@code{gnus-score-edit-current-scores}).
+You will be popped into a @code{gnus-score-mode} buffer (@pxref{Score
+File Editing}).
+
+@item V f
+@kindex V f (Summary)
+@findex gnus-score-edit-file
+Edit a score file and make this score file the current one
+(@code{gnus-score-edit-file}).
+
+@item V F
+@kindex V F (Summary)
+@findex gnus-score-flush-cache
+Flush the score cache (@code{gnus-score-flush-cache}).  This is useful
+after editing score files.
+
+@item V C
+@kindex V C (Summary)
+@findex gnus-score-customize
+Customize a score file in a visually pleasing manner
+(@code{gnus-score-customize}).
+
+@end table
+
+The rest of these commands modify the local score file.
+
+@table @kbd
+
+@item V m
+@kindex V m (Summary)
+@findex gnus-score-set-mark-below
+Prompt for a score, and mark all articles with a score below this as
+read (@code{gnus-score-set-mark-below}).
+
+@item V x
+@kindex V x (Summary)
+@findex gnus-score-set-expunge-below
+Prompt for a score, and add a score rule to the current score file to
+expunge all articles below this score
+(@code{gnus-score-set-expunge-below}).
+@end table
+
+The keystrokes for actually making score entries follow a very regular
+pattern, so there's no need to list all the commands.  (Hundreds of
+them.)
+
+@findex gnus-summary-increase-score
+@findex gnus-summary-lower-score
+
+@enumerate
+@item
+The first key is either @kbd{I} (upper case i) for increasing the score
+or @kbd{L} for lowering the score.
+@item
+The second key says what header you want to score on.  The following
+keys are available:
+@table @kbd
+
+@item a
+Score on the author name.
+
+@item s
+Score on the subject line.
+
+@item x
+Score on the @code{Xref} line---i.e., the cross-posting line.
+
+@item r
+Score on the @code{References} line.
+
+@item d
+Score on the date.
+
+@item l
+Score on the number of lines.
+
+@item i
+Score on the @code{Message-ID} header.
+
+@item e
+Score on an ``extra'' header, that is, one of those in gnus-extra-headers,
+if your @acronym{NNTP} server tracks additional header data in overviews.
+
+@item f
+Score on followups---this matches the author name, and adds scores to
+the followups to this author.  (Using this key leads to the creation of
+@file{ADAPT} files.)
+
+@item b
+Score on the body.
+
+@item h
+Score on the head.
+
+@item t
+Score on thread.  (Using this key leads to the creation of @file{ADAPT}
+files.)
+
+@end table
+
+@item
+The third key is the match type.  Which match types are valid depends on
+what headers you are scoring on.
+
+@table @code
+
+@item strings
+
+@table @kbd
+
+@item e
+Exact matching.
+
+@item s
+Substring matching.
+
+@item f
+Fuzzy matching (@pxref{Fuzzy Matching}).
+
+@item r
+Regexp matching
+@end table
+
+@item date
+@table @kbd
+
+@item b
+Before date.
+
+@item a
+After date.
+
+@item n
+This date.
+@end table
+
+@item number
+@table @kbd
+
+@item <
+Less than number.
+
+@item =
+Equal to number.
+
+@item >
+Greater than number.
+@end table
+@end table
+
+@item
+The fourth and usually final key says whether this is a temporary (i.e.,
+expiring) score entry, or a permanent (i.e., non-expiring) score entry,
+or whether it is to be done immediately, without adding to the score
+file.
+@table @kbd
+
+@item t
+Temporary score entry.
+
+@item p
+Permanent score entry.
+
+@item i
+Immediately scoring.
+@end table
+
+@item
+If you are scoring on @samp{e} (extra) headers, you will then be prompted for
+the header name on which you wish to score.  This must be a header named
+in gnus-extra-headers, and @samp{TAB} completion is available.
+
+@end enumerate
+
+So, let's say you want to increase the score on the current author with
+exact matching permanently: @kbd{I a e p}.  If you want to lower the
+score based on the subject line, using substring matching, and make a
+temporary score entry: @kbd{L s s t}.  Pretty easy.
+
+To make things a bit more complicated, there are shortcuts.  If you use
+a capital letter on either the second or third keys, Gnus will use
+defaults for the remaining one or two keystrokes.  The defaults are
+``substring'' and ``temporary''.  So @kbd{I A} is the same as @kbd{I a s
+t}, and @kbd{I a R} is the same as @kbd{I a r t}.
+
+These functions take both the numerical prefix and the symbolic prefix
+(@pxref{Symbolic Prefixes}).  A numerical prefix says how much to lower
+(or increase) the score of the article.  A symbolic prefix of @code{a}
+says to use the @file{all.SCORE} file for the command instead of the
+current score file.
+
+@vindex gnus-score-mimic-keymap
+The @code{gnus-score-mimic-keymap} says whether these commands will
+pretend they are keymaps or not.
+
+
+@node Group Score Commands
+@section Group Score Commands
+@cindex group score commands
+
+There aren't many of these as yet, I'm afraid.
+
+@table @kbd
+
+@item W e
+@kindex W e (Group)
+@findex gnus-score-edit-all-score
+Edit the apply-to-all-groups all.SCORE file.  You will be popped into
+a @code{gnus-score-mode} buffer (@pxref{Score File Editing}).
+
+@item W f
+@kindex W f (Group)
+@findex gnus-score-flush-cache
+Gnus maintains a cache of score alists to avoid having to reload them
+all the time.  This command will flush the cache
+(@code{gnus-score-flush-cache}).
+
+@end table
+
+You can do scoring from the command line by saying something like:
+
+@findex gnus-batch-score
+@cindex batch scoring
+@example
+$ emacs -batch -l ~/.emacs -l ~/.gnus.el -f gnus-batch-score
+@end example
+
+
+@node Score Variables
+@section Score Variables
+@cindex score variables
+
+@table @code
+
+@item gnus-use-scoring
+@vindex gnus-use-scoring
+If @code{nil}, Gnus will not check for score files, and will not, in
+general, do any score-related work.  This is @code{t} by default.
+
+@item gnus-kill-killed
+@vindex gnus-kill-killed
+If this variable is @code{nil}, Gnus will never apply score files to
+articles that have already been through the kill process.  While this
+may save you lots of time, it also means that if you apply a kill file
+to a group, and then change the kill file and want to run it over you
+group again to kill more articles, it won't work.  You have to set this
+variable to @code{t} to do that.  (It is @code{t} by default.)
+
+@item gnus-kill-files-directory
+@vindex gnus-kill-files-directory
+All kill and score files will be stored in this directory, which is
+initialized from the @env{SAVEDIR} environment variable by default.
+This is @file{~/News/} by default.
+
+@item gnus-score-file-suffix
+@vindex gnus-score-file-suffix
+Suffix to add to the group name to arrive at the score file name
+(@file{SCORE} by default.)
+
+@item gnus-score-uncacheable-files
+@vindex gnus-score-uncacheable-files
+@cindex score cache
+All score files are normally cached to avoid excessive re-loading of
+score files.  However, this might make your Emacs grow big and
+bloated, so this regexp can be used to weed out score files unlikely
+to be needed again.  It would be a bad idea to deny caching of
+@file{all.SCORE}, while it might be a good idea to not cache
+@file{comp.infosystems.www.authoring.misc.ADAPT}.  In fact, this
+variable is @samp{ADAPT$} by default, so no adaptive score files will
+be cached.
+
+@item gnus-save-score
+@vindex gnus-save-score
+If you have really complicated score files, and do lots of batch
+scoring, then you might set this variable to @code{t}.  This will make
+Gnus save the scores into the @file{.newsrc.eld} file.
+
+If you do not set this to @code{t}, then manual scores (like those set
+with @kbd{V s} (@code{gnus-summary-set-score})) will not be preserved
+across group visits.
+
+@item gnus-score-interactive-default-score
+@vindex gnus-score-interactive-default-score
+Score used by all the interactive raise/lower commands to raise/lower
+score with.  Default is 1000, which may seem excessive, but this is to
+ensure that the adaptive scoring scheme gets enough room to play with.
+We don't want the small changes from the adaptive scoring to overwrite
+manually entered data.
+
+@item gnus-summary-default-score
+@vindex gnus-summary-default-score
+Default score of an article, which is 0 by default.
+
+@item gnus-summary-expunge-below
+@vindex gnus-summary-expunge-below
+Don't display the summary lines of articles that have scores lower than
+this variable.  This is @code{nil} by default, which means that no
+articles will be hidden.  This variable is local to the summary buffers,
+and has to be set from @code{gnus-summary-mode-hook}.
+
+@item gnus-score-over-mark
+@vindex gnus-score-over-mark
+Mark (in the third column) used for articles with a score over the
+default.  Default is @samp{+}.
+
+@item gnus-score-below-mark
+@vindex gnus-score-below-mark
+Mark (in the third column) used for articles with a score below the
+default.  Default is @samp{-}.
+
+@item gnus-score-find-score-files-function
+@vindex gnus-score-find-score-files-function
+Function used to find score files for the current group.  This function
+is called with the name of the group as the argument.
+
+Predefined functions available are:
+@table @code
+
+@item gnus-score-find-single
+@findex gnus-score-find-single
+Only apply the group's own score file.
+
+@item gnus-score-find-bnews
+@findex gnus-score-find-bnews
+Apply all score files that match, using bnews syntax.  This is the
+default.  If the current group is @samp{gnu.emacs.gnus}, for instance,
+@file{all.emacs.all.SCORE}, @file{not.alt.all.SCORE} and
+@file{gnu.all.SCORE} would all apply.  In short, the instances of
+@samp{all} in the score file names are translated into @samp{.*}, and
+then a regexp match is done.
+
+This means that if you have some score entries that you want to apply to
+all groups, then you put those entries in the @file{all.SCORE} file.
+
+The score files are applied in a semi-random order, although Gnus will
+try to apply the more general score files before the more specific score
+files.  It does this by looking at the number of elements in the score
+file names---discarding the @samp{all} elements.
+
+@item gnus-score-find-hierarchical
+@findex gnus-score-find-hierarchical
+Apply all score files from all the parent groups.  This means that you
+can't have score files like @file{all.SCORE}, but you can have
+@file{SCORE}, @file{comp.SCORE} and @file{comp.emacs.SCORE} for each
+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 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)
+@end example
+
+@item gnus-score-expiry-days
+@vindex gnus-score-expiry-days
+This variable says how many days should pass before an unused score file
+entry is expired.  If this variable is @code{nil}, no score file entries
+are expired.  It's 7 by default.
+
+@item gnus-update-score-entry-dates
+@vindex gnus-update-score-entry-dates
+If this variable is non-@code{nil}, temporary score entries that have
+been triggered (matched) will have their dates updated.  (This is how Gnus
+controls expiry---all non-matched-entries will become too old while
+matched entries will stay fresh and young.)  However, if you set this
+variable to @code{nil}, even matched entries will grow old and will
+have to face that oh-so grim reaper.
+
+@item gnus-score-after-write-file-function
+@vindex gnus-score-after-write-file-function
+Function called with the name of the score file just written.
+
+@item gnus-score-thread-simplify
+@vindex gnus-score-thread-simplify
+If this variable is non-@code{nil}, article subjects will be
+simplified for subject scoring purposes in the same manner as with
+threading---according to the current value of
+@code{gnus-simplify-subject-functions}.  If the scoring entry uses
+@code{substring} or @code{exact} matching, the match will also be
+simplified in this manner.
+
+@end table
+
+
+@node Score File Format
+@section Score File Format
+@cindex score file format
+
+A score file is an @code{emacs-lisp} file that normally contains just a
+single form.  Casual users are not expected to edit these files;
+everything can be changed from the summary buffer.
+
+Anyway, if you'd like to dig into it yourself, here's an example:
+
+@lisp
+(("from"
+  ("Lars Ingebrigtsen" -10000)
+  ("Per Abrahamsen")
+  ("larsi\\|lmi" -50000 nil R))
+ ("subject"
+  ("Ding is Badd" nil 728373))
+ ("xref"
+  ("alt.politics" -1000 728372 s))
+ ("lines"
+  (2 -100 nil <))
+ (mark 0)
+ (expunge -1000)
+ (mark-and-expunge -10)
+ (read-only nil)
+ (orphan -10)
+ (adapt t)
+ (files "/hom/larsi/News/gnu.SCORE")
+ (exclude-files "all.SCORE")
+ (local (gnus-newsgroup-auto-expire t)
+        (gnus-summary-make-false-root empty))
+ (eval (ding)))
+@end lisp
+
+This example demonstrates most score file elements.  @xref{Advanced
+Scoring}, for a different approach.
+
+Even though this looks much like Lisp code, nothing here is actually
+@code{eval}ed.  The Lisp reader is used to read this form, though, so it
+has to be valid syntactically, if not semantically.
+
+Six keys are supported by this alist:
+
+@table @code
+
+@item STRING
+If the key is a string, it is the name of the header to perform the
+match on.  Scoring can only be performed on these eight headers:
+@code{From}, @code{Subject}, @code{References}, @code{Message-ID},
+@code{Xref}, @code{Lines}, @code{Chars} and @code{Date}.  In addition to
+these headers, there are three strings to tell Gnus to fetch the entire
+article and do the match on larger parts of the article: @code{Body}
+will perform the match on the body of the article, @code{Head} will
+perform the match on the head of the article, and @code{All} will
+perform the match on the entire article.  Note that using any of these
+last three keys will slow down group entry @emph{considerably}.  The
+final ``header'' you can score on is @code{Followup}.  These score
+entries will result in new score entries being added for all follow-ups
+to articles that matches these score entries.
+
+Following this key is an arbitrary number of score entries, where each
+score entry has one to four elements.
+@enumerate
+
+@item
+The first element is the @dfn{match element}.  On most headers this will
+be a string, but on the Lines and Chars headers, this must be an
+integer.
+
+@item
+If the second element is present, it should be a number---the @dfn{score
+element}.  This number should be an integer in the neginf to posinf
+interval.  This number is added to the score of the article if the match
+is successful.  If this element is not present, the
+@code{gnus-score-interactive-default-score} number will be used
+instead.  This is 1000 by default.
+
+@item
+If the third element is present, it should be a number---the @dfn{date
+element}.  This date says when the last time this score entry matched,
+which provides a mechanism for expiring the score entries.  It this
+element is not present, the score entry is permanent.  The date is
+represented by the number of days since December 31, 1 BCE.
+
+@item
+If the fourth element is present, it should be a symbol---the @dfn{type
+element}.  This element specifies what function should be used to see
+whether this score entry matches the article.  What match types that can
+be used depends on what header you wish to perform the match on.
+@table @dfn
+
+@item From, Subject, References, Xref, Message-ID
+For most header types, there are the @code{r} and @code{R} (regexp), as
+well as @code{s} and @code{S} (substring) types, and @code{e} and
+@code{E} (exact match), and @code{w} (word match) types.  If this
+element is not present, Gnus will assume that substring matching should
+be used.  @code{R}, @code{S}, and @code{E} differ from the others in
+that the matches will be done in a case-sensitive manner.  All these
+one-letter types are really just abbreviations for the @code{regexp},
+@code{string}, @code{exact}, and @code{word} types, which you can use
+instead, if you feel like.
+
+@item Extra
+Just as for the standard string overview headers, if you are using
+gnus-extra-headers, you can score on these headers' values.  In this
+case, there is a 5th element in the score entry, being the name of the
+header to be scored.  The following entry is useful in your
+@file{all.SCORE} file in case of spam attacks from a single origin
+host, if your @acronym{NNTP} server tracks @samp{NNTP-Posting-Host} in
+overviews:
+
+@lisp
+("111.222.333.444" -1000 nil s
+ "NNTP-Posting-Host")
+@end lisp
+
+@item Lines, Chars
+These two headers use different match types: @code{<}, @code{>},
+@code{=}, @code{>=} and @code{<=}.
+
+These predicates are true if
+
+@example
+(PREDICATE HEADER MATCH)
+@end example
+
+evaluates to non-@code{nil}.  For instance, the advanced match
+@code{("lines" 4 <)} (@pxref{Advanced Scoring}) will result in the
+following form:
+
+@lisp
+(< header-value 4)
+@end lisp
+
+Or to put it another way: When using @code{<} on @code{Lines} with 4 as
+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 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.
+
+@item Date
+For the Date header we have three kinda silly match types:
+@code{before}, @code{at} and @code{after}.  I can't really imagine this
+ever being useful, but, like, it would feel kinda silly not to provide
+this function.  Just in case.  You never know.  Better safe than sorry.
+Once burnt, twice shy.  Don't judge a book by its cover.  Never not have
+sex on a first date.  (I have been told that at least one person, and I
+quote, ``found this function indispensable'', however.)
+
+@cindex ISO8601
+@cindex date
+A more useful match type is @code{regexp}.  With it, you can match the
+date string using a regular expression.  The date is normalized to
+ISO8601 compact format first---@var{YYYYMMDD}@code{T}@var{HHMMSS}.  If
+you want to match all articles that have been posted on April 1st in
+every year, you could use @samp{....0401.........} as a match string,
+for instance.  (Note that the date is kept in its original time zone, so
+this will match articles that were posted when it was April 1st where
+the article was posted from.  Time zones are such wholesome fun for the
+whole family, eh?)
+
+@item Head, Body, All
+These three match keys use the same match types as the @code{From} (etc.)@:
+header uses.
+
+@item Followup
+This match key is somewhat special, in that it will match the
+@code{From} header, and affect the score of not only the matching
+articles, but also all followups to the matching articles.  This allows
+you to increase the score of followups to your own articles, or
+decrease the score of followups to the articles of some known
+trouble-maker.  Uses the same match types as the @code{From} header
+uses.  (Using this match key will lead to creation of @file{ADAPT}
+files.)
+
+@item Thread
+This match key works along the same lines as the @code{Followup} match
+key.  If you say that you want to score on a (sub-)thread started by an
+article with a @code{Message-ID} @var{x}, then you add a @samp{thread}
+match.  This will add a new @samp{thread} match for each article that
+has @var{x} in its @code{References} header.  (These new @samp{thread}
+matches will use the @code{Message-ID}s of these matching articles.)
+This will ensure that you can raise/lower the score of an entire thread,
+even though some articles in the thread may not have complete
+@code{References} headers.  Note that using this may lead to
+nondeterministic scores of the articles in the thread.  (Using this match
+key will lead to creation of @file{ADAPT} files.)
+@end table
+@end enumerate
+
+@cindex score file atoms
+@item mark
+The value of this entry should be a number.  Any articles with a score
+lower than this number will be marked as read.
+
+@item expunge
+The value of this entry should be a number.  Any articles with a score
+lower than this number will be removed from the summary buffer.
+
+@item mark-and-expunge
+The value of this entry should be a number.  Any articles with a score
+lower than this number will be marked as read and removed from the
+summary buffer.
+
+@item thread-mark-and-expunge
+The value of this entry should be a number.  All articles that belong to
+a thread that has a total score below this number will be marked as read
+and removed from the summary buffer.  @code{gnus-thread-score-function}
+says how to compute the total score for a thread.
+
+@item files
+The value of this entry should be any number of file names.  These files
+are assumed to be score files as well, and will be loaded the same way
+this one was.
+
+@item exclude-files
+The clue of this entry should be any number of files.  These files will
+not be loaded, even though they would normally be so, for some reason or
+other.
+
+@item eval
+The value of this entry will be @code{eval}ed.  This element will be
+ignored when handling global score files.
+
+@item read-only
+Read-only score files will not be updated or saved.  Global score files
+should feature this atom (@pxref{Global Score Files}).  (Note:
+@dfn{Global} here really means @dfn{global}; not your personal
+apply-to-all-groups score files.)
+
+@item orphan
+The value of this entry should be a number.  Articles that do not have
+parents will get this number added to their scores.  Imagine you follow
+some high-volume newsgroup, like @samp{comp.lang.c}.  Most likely you
+will only follow a few of the threads, also want to see any new threads.
+
+You can do this with the following two score file entries:
+
+@example
+        (orphan -500)
+        (mark-and-expunge -100)
+@end example
+
+When you enter the group the first time, you will only see the new
+threads.  You then raise the score of the threads that you find
+interesting (with @kbd{I T} or @kbd{I S}), and ignore (@kbd{c y}) the
+rest.  Next time you enter the group, you will see new articles in the
+interesting threads, plus any new threads.
+
+I.e., the orphan score atom is for high-volume groups where a few
+interesting threads which can't be found automatically by ordinary
+scoring rules exist.
+
+@item adapt
+This entry controls the adaptive scoring.  If it is @code{t}, the
+default adaptive scoring rules will be used.  If it is @code{ignore}, no
+adaptive scoring will be performed on this group.  If it is a list, this
+list will be used as the adaptive scoring rules.  If it isn't present,
+or is something other than @code{t} or @code{ignore}, the default
+adaptive scoring rules will be used.  If you want to use adaptive
+scoring on most groups, you'd set @code{gnus-use-adaptive-scoring} to
+@code{t}, and insert an @code{(adapt ignore)} in the groups where you do
+not want adaptive scoring.  If you only want adaptive scoring in a few
+groups, you'd set @code{gnus-use-adaptive-scoring} to @code{nil}, and
+insert @code{(adapt t)} in the score files of the groups where you want
+it.
+
+@item adapt-file
+All adaptive score entries will go to the file named by this entry.  It
+will also be applied when entering the group.  This atom might be handy
+if you want to adapt on several groups at once, using the same adaptive
+file for a number of groups.
+
+@item local
+@cindex local variables
+The value of this entry should be a list of @code{(@var{var}
+@var{value})} pairs.  Each @var{var} will be made buffer-local to the
+current summary buffer, and set to the value specified.  This is a
+convenient, if somewhat strange, way of setting variables in some
+groups if you don't like hooks much.  Note that the @var{value} won't
+be evaluated.
+@end table
+
+
+@node Score File Editing
+@section Score File Editing
+
+You normally enter all scoring commands from the summary buffer, but you
+might feel the urge to edit them by hand as well, so we've supplied you
+with a mode for that.
+
+It's simply a slightly customized @code{emacs-lisp} mode, with these
+additional commands:
+
+@table @kbd
+
+@item C-c C-c
+@kindex C-c C-c (Score)
+@findex gnus-score-edit-exit
+Save the changes you have made and return to the summary buffer
+(@code{gnus-score-edit-exit}).
+
+@item C-c C-d
+@kindex C-c C-d (Score)
+@findex gnus-score-edit-insert-date
+Insert the current date in numerical format
+(@code{gnus-score-edit-insert-date}).  This is really the day number, if
+you were wondering.
+
+@item C-c C-p
+@kindex C-c C-p (Score)
+@findex gnus-score-pretty-print
+The adaptive score files are saved in an unformatted fashion.  If you
+intend to read one of these files, you want to @dfn{pretty print} it
+first.  This command (@code{gnus-score-pretty-print}) does that for
+you.
+
+@end table
+
+Type @kbd{M-x gnus-score-mode} to use this mode.
+
+@vindex gnus-score-mode-hook
+@code{gnus-score-menu-hook} is run in score mode buffers.
+
+In the summary buffer you can use commands like @kbd{V f}, @kbd{V e} and
+@kbd{V t} to begin editing score files.
+
+
+@node Adaptive Scoring
+@section Adaptive Scoring
+@cindex adaptive scoring
+
+If all this scoring is getting you down, Gnus has a way of making it all
+happen automatically---as if by magic.  Or rather, as if by artificial
+stupidity, to be precise.
+
+@vindex gnus-use-adaptive-scoring
+When you read an article, or mark an article as read, or kill an
+article, you leave marks behind.  On exit from the group, Gnus can sniff
+these marks and add score elements depending on what marks it finds.
+You turn on this ability by setting @code{gnus-use-adaptive-scoring} to
+@code{t} or @code{(line)}.  If you want score adaptively on separate
+words appearing in the subjects, you should set this variable to
+@code{(word)}.  If you want to use both adaptive methods, set this
+variable to @code{(word line)}.
+
+@vindex gnus-default-adaptive-score-alist
+To give you complete control over the scoring process, you can customize
+the @code{gnus-default-adaptive-score-alist} variable.  For instance, it
+might look something like this:
+
+@lisp
+(setq gnus-default-adaptive-score-alist
+  '((gnus-unread-mark)
+    (gnus-ticked-mark (from 4))
+    (gnus-dormant-mark (from 5))
+    (gnus-del-mark (from -4) (subject -1))
+    (gnus-read-mark (from 4) (subject 2))
+    (gnus-expirable-mark (from -1) (subject -1))
+    (gnus-killed-mark (from -1) (subject -3))
+    (gnus-kill-file-mark)
+    (gnus-ancient-mark)
+    (gnus-low-score-mark)
+    (gnus-catchup-mark (from -1) (subject -1))))
+@end lisp
+
+As you see, each element in this alist has a mark as a key (either a
+variable name or a ``real'' mark---a character).  Following this key is
+a arbitrary number of header/score pairs.  If there are no header/score
+pairs following the key, no adaptive scoring will be done on articles
+that have that key as the article mark.  For instance, articles with
+@code{gnus-unread-mark} in the example above will not get adaptive score
+entries.
+
+Each article can have only one mark, so just a single of these rules
+will be applied to each article.
+
+To take @code{gnus-del-mark} as an example---this alist says that all
+articles that have that mark (i.e., are marked with @samp{e}) will have a
+score entry added to lower based on the @code{From} header by -4, and
+lowered by @code{Subject} by -1.  Change this to fit your prejudices.
+
+If you have marked 10 articles with the same subject with
+@code{gnus-del-mark}, the rule for that mark will be applied ten times.
+That means that that subject will get a score of ten times -1, which
+should be, unless I'm much mistaken, -10.
+
+If you have auto-expirable (mail) groups (@pxref{Expiring Mail}), all
+the read articles will be marked with the @samp{E} mark.  This'll
+probably make adaptive scoring slightly impossible, so auto-expiring and
+adaptive scoring doesn't really mix very well.
+
+The headers you can score on are @code{from}, @code{subject},
+@code{message-id}, @code{references}, @code{xref}, @code{lines},
+@code{chars} and @code{date}.  In addition, you can score on
+@code{followup}, which will create an adaptive score entry that matches
+on the @code{References} header using the @code{Message-ID} of the
+current article, thereby matching the following thread.
+
+If you use this scheme, you should set the score file atom @code{mark}
+to something small---like -300, perhaps, to avoid having small random
+changes result in articles getting marked as read.
+
+After using adaptive scoring for a week or so, Gnus should start to
+become properly trained and enhance the authors you like best, and kill
+the authors you like least, without you having to say so explicitly.
+
+You can control what groups the adaptive scoring is to be performed on
+by using the score files (@pxref{Score File Format}).  This will also
+let you use different rules in different groups.
+
+@vindex gnus-adaptive-file-suffix
+The adaptive score entries will be put into a file where the name is the
+group name with @code{gnus-adaptive-file-suffix} appended.  The default
+is @file{ADAPT}.
+
+@vindex gnus-adaptive-pretty-print
+Adaptive score files can get huge and are not meant to be edited by
+human hands.  If @code{gnus-adaptive-pretty-print} is @code{nil} (the
+default) those files will not be written in a human readable way.
+
+@vindex gnus-score-exact-adapt-limit
+When doing adaptive scoring, substring or fuzzy matching would probably
+give you the best results in most cases.  However, if the header one
+matches is short, the possibility for false positives is great, so if
+the length of the match is less than
+@code{gnus-score-exact-adapt-limit}, exact matching will be used.  If
+this variable is @code{nil}, exact matching will always be used to avoid
+this problem.
+
+@vindex gnus-default-adaptive-word-score-alist
+As mentioned above, you can adapt either on individual words or entire
+headers.  If you adapt on words, the
+@code{gnus-default-adaptive-word-score-alist} variable says what score
+each instance of a word should add given a mark.
+
+@lisp
+(setq gnus-default-adaptive-word-score-alist
+      `((,gnus-read-mark . 30)
+        (,gnus-catchup-mark . -10)
+        (,gnus-killed-mark . -20)
+        (,gnus-del-mark . -15)))
+@end lisp
+
+This is the default value.  If you have adaption on words enabled, every
+word that appears in subjects of articles marked with
+@code{gnus-read-mark} will result in a score rule that increase the
+score with 30 points.
+
+@vindex gnus-default-ignored-adaptive-words
+@vindex gnus-ignored-adaptive-words
+Words that appear in the @code{gnus-default-ignored-adaptive-words} list
+will be ignored.  If you wish to add more words to be ignored, use the
+@code{gnus-ignored-adaptive-words} list instead.
+
+@vindex gnus-adaptive-word-length-limit
+Some may feel that short words shouldn't count when doing adaptive
+scoring.  If so, you may set @code{gnus-adaptive-word-length-limit} to
+an integer.  Words shorter than this number will be ignored.  This
+variable defaults to @code{nil}.
+
+@vindex gnus-adaptive-word-syntax-table
+When the scoring is done, @code{gnus-adaptive-word-syntax-table} is the
+syntax table in effect.  It is similar to the standard syntax table, but
+it considers numbers to be non-word-constituent characters.
+
+@vindex gnus-adaptive-word-minimum
+If @code{gnus-adaptive-word-minimum} is set to a number, the adaptive
+word scoring process will never bring down the score of an article to
+below this number.  The default is @code{nil}.
+
+@vindex gnus-adaptive-word-no-group-words
+If @code{gnus-adaptive-word-no-group-words} is set to @code{t}, gnus
+won't adaptively word score any of the words in the group name.  Useful
+for groups like @samp{comp.editors.emacs}, where most of the subject
+lines contain the word @samp{emacs}.
+
+After using this scheme for a while, it might be nice to write a
+@code{gnus-psychoanalyze-user} command to go through the rules and see
+what words you like and what words you don't like.  Or perhaps not.
+
+Note that the adaptive word scoring thing is highly experimental and is
+likely to change in the future.  Initial impressions seem to indicate
+that it's totally useless as it stands.  Some more work (involving more
+rigorous statistical methods) will have to be done to make this useful.
+
+
+@node Home Score File
+@section Home Score File
+
+The score file where new score file entries will go is called the
+@dfn{home score file}.  This is normally (and by default) the score file
+for the group itself.  For instance, the home score file for
+@samp{gnu.emacs.gnus} is @file{gnu.emacs.gnus.SCORE}.
+
+However, this may not be what you want.  It is often convenient to share
+a common home score file among many groups---all @samp{emacs} groups
+could perhaps use the same home score file.
+
+@vindex gnus-home-score-file
+The variable that controls this is @code{gnus-home-score-file}.  It can
+be:
+
+@enumerate
+@item
+A string.  Then this file will be used as the home score file for all
+groups.
+
+@item
+A function.  The result of this function will be used as the home score
+file.  The function will be called with the name of the group as the
+parameter.
+
+@item
+A list.  The elements in this list can be:
+
+@enumerate
+@item
+@code{(@var{regexp} @var{file-name})}.  If the @var{regexp} matches the
+group name, the @var{file-name} will be used as the home score file.
+
+@item
+A function.  If the function returns non-@code{nil}, the result will
+be used as the home score file.  The function will be called with the
+name of the group as the parameter.
+
+@item
+A string.  Use the string as the home score file.
+@end enumerate
+
+The list will be traversed from the beginning towards the end looking
+for matches.
+
+@end enumerate
+
+So, if you want to use just a single score file, you could say:
+
+@lisp
+(setq gnus-home-score-file
+      "my-total-score-file.SCORE")
+@end lisp
+
+If you want to use @file{gnu.SCORE} for all @samp{gnu} groups and
+@file{rec.SCORE} for all @samp{rec} groups (and so on), you can say:
+
+@findex gnus-hierarchial-home-score-file
+@lisp
+(setq gnus-home-score-file
+      'gnus-hierarchial-home-score-file)
+@end lisp
+
+This is a ready-made function provided for your convenience.
+Other functions include
+
+@table @code
+@item gnus-current-home-score-file
+@findex gnus-current-home-score-file
+Return the ``current'' regular score file.  This will make scoring
+commands add entry to the ``innermost'' matching score file.
+
+@end table
+
+If you want to have one score file for the @samp{emacs} groups and
+another for the @samp{comp} groups, while letting all other groups use
+their own home score files:
+
+@lisp
+(setq gnus-home-score-file
+      ;; @r{All groups that match the regexp @code{"\\.emacs"}}
+      '(("\\.emacs" "emacs.SCORE")
+        ;; @r{All the comp groups in one score file}
+        ("^comp" "comp.SCORE")))
+@end lisp
+
+@vindex gnus-home-adapt-file
+@code{gnus-home-adapt-file} works exactly the same way as
+@code{gnus-home-score-file}, but says what the home adaptive score file
+is instead.  All new adaptive file entries will go into the file
+specified by this variable, and the same syntax is allowed.
+
+In addition to using @code{gnus-home-score-file} and
+@code{gnus-home-adapt-file}, you can also use group parameters
+(@pxref{Group Parameters}) and topic parameters (@pxref{Topic
+Parameters}) to achieve much the same.  Group and topic parameters take
+precedence over this variable.
+
+
+@node Followups To Yourself
+@section Followups To Yourself
+
+Gnus offers two commands for picking out the @code{Message-ID} header in
+the current buffer.  Gnus will then add a score rule that scores using
+this @code{Message-ID} on the @code{References} header of other
+articles.  This will, in effect, increase the score of all articles that
+respond to the article in the current buffer.  Quite useful if you want
+to easily note when people answer what you've said.
+
+@table @code
+
+@item gnus-score-followup-article
+@findex gnus-score-followup-article
+This will add a score to articles that directly follow up your own
+article.
+
+@item gnus-score-followup-thread
+@findex gnus-score-followup-thread
+This will add a score to all articles that appear in a thread ``below''
+your own article.
+@end table
+
+@vindex message-sent-hook
+These two functions are both primarily meant to be used in hooks like
+@code{message-sent-hook}, like this:
+@lisp
+(add-hook 'message-sent-hook 'gnus-score-followup-thread)
+@end lisp
+
+
+If you look closely at your own @code{Message-ID}, you'll notice that
+the first two or three characters are always the same.  Here's two of
+mine:
+
+@example
+<x6u3u47icf.fsf@@eyesore.no>
+<x6sp9o7ibw.fsf@@eyesore.no>
+@end example
+
+So ``my'' ident on this machine is @samp{x6}.  This can be
+exploited---the following rule will raise the score on all followups to
+myself:
+
+@lisp
+("references"
+ ("<x6[0-9a-z]+\\.fsf\\(_-_\\)?@@.*eyesore\\.no>"
+  1000 nil r))
+@end lisp
+
+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.
+
+@vindex gnus-inhibit-slow-scoring
+You can inhibit this slow scoring on headers or body by setting the
+variable @code{gnus-inhibit-slow-scoring}.  If
+@code{gnus-inhibit-slow-scoring} is regexp, slow scoring is inhibited if
+the group matches the regexp.  If it is @code{t}, slow scoring on it is
+inhibited for all groups.
+
+Now, there's not much you can do about the slowness for news groups, but for
+mail groups, you have greater control.  In @ref{To From Newsgroups},
+it's explained in greater detail what this mechanism does, but here's
+a cookbook example for @code{nnml} on how to allow scoring on the
+@samp{To} and @samp{Cc} headers.
+
+Put the following in your @file{~/.gnus.el} file.
+
+@lisp
+(setq gnus-extra-headers '(To Cc Newsgroups Keywords)
+      nnmail-extra-headers gnus-extra-headers)
+@end lisp
+
+Restart Gnus and rebuild your @code{nnml} overview files with the
+@kbd{M-x nnml-generate-nov-databases} command.  This will take a long
+time if you have much mail.
+
+Now you can score on @samp{To} and @samp{Cc} as ``extra headers'' like
+so: @kbd{I e s p To RET <your name> RET}.
+
+See?  Simple.
+
+
+@node Scoring Tips
+@section Scoring Tips
+@cindex scoring tips
+
+@table @dfn
+
+@item Crossposts
+@cindex crossposts
+@cindex scoring crossposts
+If you want to lower the score of crossposts, the line to match on is
+the @code{Xref} header.
+@lisp
+("xref" (" talk.politics.misc:" -1000))
+@end lisp
+
+@item Multiple crossposts
+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))
+@end lisp
+
+@item Matching on the body
+This is generally not a very good idea---it takes a very long time.
+Gnus actually has to fetch each individual article from the server.  But
+you might want to anyway, I guess.  Even though there are three match
+keys (@code{Head}, @code{Body} and @code{All}), you should choose one
+and stick with it in each score file.  If you use any two, each article
+will be fetched @emph{twice}.  If you want to match a bit on the
+@code{Head} and a bit on the @code{Body}, just use @code{All} for all
+the matches.
+
+@item Marking as read
+You will probably want to mark articles that have scores below a certain
+number as read.  This is most easily achieved by putting the following
+in your @file{all.SCORE} file:
+@lisp
+((mark -100))
+@end lisp
+You may also consider doing something similar with @code{expunge}.
+
+@item Negated character classes
+If you say stuff like @code{[^abcd]*}, you may get unexpected results.
+That will match newlines, which might lead to, well, The Unknown.  Say
+@code{[^abcd\n]*} instead.
+@end table
+
+
+@node Reverse Scoring
+@section Reverse Scoring
+@cindex reverse scoring
+
+If you want to keep just articles that have @samp{Sex with Emacs} in the
+subject header, and expunge all other articles, you could put something
+like this in your score file:
+
+@lisp
+(("subject"
+  ("Sex with Emacs" 2))
+ (mark 1)
+ (expunge 1))
+@end lisp
+
+So, you raise all articles that match @samp{Sex with Emacs} and mark the
+rest as read, and expunge them to boot.
+
+
+@node Global Score Files
+@section Global Score Files
+@cindex global score files
+
+Sure, other newsreaders have ``global kill files''.  These are usually
+nothing more than a single kill file that applies to all groups, stored
+in the user's home directory.  Bah!  Puny, weak newsreaders!
+
+What I'm talking about here are Global Score Files.  Score files from
+all over the world, from users everywhere, uniting all nations in one
+big, happy score file union!  Ange-score!  New and untested!
+
+@vindex gnus-global-score-files
+All you have to do to use other people's score files is to set the
+@code{gnus-global-score-files} variable.  One entry for each score file,
+or each score file directory.  Gnus will decide by itself what score
+files are applicable to which group.
+
+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,
+say this:
+
+@lisp
+(setq gnus-global-score-files
+      '("/ftp@@ftp.gnus.org:/pub/larsi/ding/score/soc.motss.SCORE"
+        "/ftp@@ftp.some-where:/pub/score/"))
+@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
+use the @code{gnus-score-search-global-directories} command.
+
+Note that, at present, using this option will slow down group entry
+somewhat.  (That is---a lot.)
+
+If you want to start maintaining score files for other people to use,
+just put your score file up for anonymous ftp and announce it to the
+world.  Become a retro-moderator!  Participate in the retro-moderator
+wars sure to ensue, where retro-moderators battle it out for the
+sympathy of the people, luring them to use their score files on false
+premises!  Yay!  The net is saved!
+
+Here are some tips for the would-be retro-moderator, off the top of my
+head:
+
+@itemize @bullet
+
+@item
+Articles heavily crossposted are probably junk.
+@item
+To lower a single inappropriate article, lower by @code{Message-ID}.
+@item
+Particularly brilliant authors can be raised on a permanent basis.
+@item
+Authors that repeatedly post off-charter for the group can safely be
+lowered out of existence.
+@item
+Set the @code{mark} and @code{expunge} atoms to obliterate the nastiest
+articles completely.
+
+@item
+Use expiring score entries to keep the size of the file down.  You
+should probably have a long expiry period, though, as some sites keep
+old articles for a long time.
+@end itemize
+
+@dots{} I wonder whether other newsreaders will support global score files
+in the future.  @emph{Snicker}.  Yup, any day now, newsreaders like Blue
+Wave, xrn and 1stReader are bound to implement scoring.  Should we start
+holding our breath yet?
+
+
+@node Kill Files
+@section Kill Files
+@cindex kill files
+
+Gnus still supports those pesky old kill files.  In fact, the kill file
+entries can now be expiring, which is something I wrote before Daniel
+Quinlan thought of doing score files, so I've left the code in there.
+
+In short, kill processing is a lot slower (and I do mean @emph{a lot})
+than score processing, so it might be a good idea to rewrite your kill
+files into score files.
+
+Anyway, a kill file is a normal @code{emacs-lisp} file.  You can put any
+forms into this file, which means that you can use kill files as some
+sort of primitive hook function to be run on group entry, even though
+that isn't a very good idea.
+
+Normal kill files look like this:
+
+@lisp
+(gnus-kill "From" "Lars Ingebrigtsen")
+(gnus-kill "Subject" "ding")
+(gnus-expunge "X")
+@end lisp
+
+This will mark every article written by me as read, and remove the
+marked articles from the summary buffer.  Very useful, you'll agree.
+
+Other programs use a totally different kill file syntax.  If Gnus
+encounters what looks like a @code{rn} kill file, it will take a stab at
+interpreting it.
+
+Two summary functions for editing a @sc{gnus} kill file:
+
+@table @kbd
+
+@item M-k
+@kindex M-k (Summary)
+@findex gnus-summary-edit-local-kill
+Edit this group's kill file (@code{gnus-summary-edit-local-kill}).
+
+@item M-K
+@kindex M-K (Summary)
+@findex gnus-summary-edit-global-kill
+Edit the general kill file (@code{gnus-summary-edit-global-kill}).
+@end table
+
+Two group mode functions for editing the kill files:
+
+@table @kbd
+
+@item M-k
+@kindex M-k (Group)
+@findex gnus-group-edit-local-kill
+Edit this group's kill file (@code{gnus-group-edit-local-kill}).
+
+@item M-K
+@kindex M-K (Group)
+@findex gnus-group-edit-global-kill
+Edit the general kill file (@code{gnus-group-edit-global-kill}).
+@end table
+
+Kill file variables:
+
+@table @code
+@item gnus-kill-file-name
+@vindex gnus-kill-file-name
+A kill file for the group @samp{soc.motss} is normally called
+@file{soc.motss.KILL}.  The suffix appended to the group name to get
+this file name is detailed by the @code{gnus-kill-file-name} variable.
+The ``global'' kill file (not in the score file sense of ``global'', of
+course) is just called @file{KILL}.
+
+@vindex gnus-kill-save-kill-file
+@item gnus-kill-save-kill-file
+If this variable is non-@code{nil}, Gnus will save the
+kill file after processing, which is necessary if you use expiring
+kills.
+
+@item gnus-apply-kill-hook
+@vindex gnus-apply-kill-hook
+@findex gnus-apply-kill-file-unless-scored
+@findex gnus-apply-kill-file
+A hook called to apply kill files to a group.  It is
+@code{(gnus-apply-kill-file)} by default.  If you want to ignore the
+kill file if you have a score file for the same group, you can set this
+hook to @code{(gnus-apply-kill-file-unless-scored)}.  If you don't want
+kill files to be processed, you should set this variable to @code{nil}.
+
+@item gnus-kill-file-mode-hook
+@vindex gnus-kill-file-mode-hook
+A hook called in kill-file mode buffers.
+
+@end table
+
+
+@node Converting Kill Files
+@section Converting Kill Files
+@cindex kill files
+@cindex converting kill files
+
+If you have loads of old kill files, you may want to convert them into
+score files.  If they are ``regular'', you can use
+the @file{gnus-kill-to-score.el} package; if not, you'll have to do it
+by hand.
+
+The kill to score conversion package isn't included in Emacs by default.
+You can fetch it from the contrib directory of the Gnus distribution or
+from
+@uref{http://heim.ifi.uio.no/~larsi/ding-various/gnus-kill-to-score.el}.
+
+If your old kill files are very complex---if they contain more
+non-@code{gnus-kill} forms than not, you'll have to convert them by
+hand.  Or just let them be as they are.  Gnus will still use them as
+before.
+
+
+@node Advanced Scoring
+@section Advanced Scoring
+
+Scoring on Subjects and From headers is nice enough, but what if you're
+really interested in what a person has to say only when she's talking
+about a particular subject?  Or what if you really don't want to
+read what person A has to say when she's following up to person B, but
+want to read what she says when she's following up to person C?
+
+By using advanced scoring rules you may create arbitrarily complex
+scoring patterns.
+
+@menu
+* Advanced Scoring Syntax::     A definition.
+* Advanced Scoring Examples::   What they look like.
+* Advanced Scoring Tips::       Getting the most out of it.
+@end menu
+
+
+@node Advanced Scoring Syntax
+@subsection Advanced Scoring Syntax
+
+Ordinary scoring rules have a string as the first element in the rule.
+Advanced scoring rules have a list as the first element.  The second
+element is the score to be applied if the first element evaluated to a
+non-@code{nil} value.
+
+These lists may consist of three logical operators, one redirection
+operator, and various match operators.
+
+Logical operators:
+
+@table @code
+@item &
+@itemx and
+This logical operator will evaluate each of its arguments until it finds
+one that evaluates to @code{false}, and then it'll stop.  If all arguments
+evaluate to @code{true} values, then this operator will return
+@code{true}.
+
+@item |
+@itemx or
+This logical operator will evaluate each of its arguments until it finds
+one that evaluates to @code{true}.  If no arguments are @code{true},
+then this operator will return @code{false}.
+
+@item !
+@itemx not
+@itemx ¬
+This logical operator only takes a single argument.  It returns the
+logical negation of the value of its argument.
+
+@end table
+
+There is an @dfn{indirection operator} that will make its arguments
+apply to the ancestors of the current article being scored.  For
+instance, @code{1-} will make score rules apply to the parent of the
+current article.  @code{2-} will make score rules apply to the
+grandparent of the current article.  Alternatively, you can write
+@code{^^}, where the number of @code{^}s (carets) says how far back into
+the ancestry you want to go.
+
+Finally, we have the match operators.  These are the ones that do the
+real work.  Match operators are header name strings followed by a match
+and a match type.  A typical match operator looks like @samp{("from"
+"Lars Ingebrigtsen" s)}.  The header names are the same as when using
+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:
+
+@example
+@group
+((&
+  ("from" "Lars Ingebrigtsen")
+  ("subject" "Gnus"))
+ 1000)
+@end group
+@end example
+
+Quite simple, huh?
+
+When he writes long articles, he sometimes has something nice to say:
+
+@example
+((&
+  ("from" "Lars Ingebrigtsen")
+  (|
+   ("subject" "Gnus")
+   ("lines" 100 >)))
+ 1000)
+@end example
+
+However, when he responds to things written by Reig Eigil Logge, you
+really don't want to read what he's written:
+
+@example
+((&
+  ("from" "Lars Ingebrigtsen")
+  (1- ("from" "Reig Eigil Logge")))
+ -100000)
+@end example
+
+Everybody that follows up Redmondo when he writes about disappearing
+socks should have their scores raised, but only when they talk about
+white socks.  However, when Lars talks about socks, it's usually not
+very interesting:
+
+@example
+((&
+  (1-
+   (&
+    ("from" "redmondo@@.*no" r)
+    ("body" "disappearing.*socks" t)))
+  (! ("from" "Lars Ingebrigtsen"))
+  ("body" "white.*socks"))
+ 1000)
+@end example
+
+Suppose you're reading a high volume group and you're only interested
+in replies.  The plan is to score down all articles that don't have
+subject that begin with "Re:", "Fw:" or "Fwd:" and then score up all
+parents of articles that have subjects that begin with reply marks.
+
+@example
+((! ("subject" "re:\\|fwd?:" r))
+  -200)
+((1- ("subject" "re:\\|fwd?:" r))
+  200)
+@end example
+
+The possibilities are endless.
+
+@node Advanced Scoring Tips
+@subsection Advanced Scoring Tips
+
+The @code{&} and @code{|} logical operators do short-circuit logic.
+That is, they stop processing their arguments when it's clear what the
+result of the operation will be.  For instance, if one of the arguments
+of an @code{&} evaluates to @code{false}, there's no point in evaluating
+the rest of the arguments.  This means that you should put slow matches
+(@samp{body}, @samp{header}) last and quick matches (@samp{from},
+@samp{subject}) first.
+
+The indirection arguments (@code{1-} and so on) will make their
+arguments work on previous generations of the thread.  If you say
+something like:
+
+@example
+...
+(1-
+ (1-
+  ("from" "lars")))
+...
+@end example
+
+Then that means ``score on the from header of the grandparent of the
+current article''.  An indirection is quite fast, but it's better to say:
+
+@example
+(1-
+ (&
+  ("from" "Lars")
+  ("subject" "Gnus")))
+@end example
+
+than it is to say:
+
+@example
+(&
+ (1- ("from" "Lars"))
+ (1- ("subject" "Gnus")))
+@end example
+
+
+@node Score Decays
+@section Score Decays
+@cindex score decays
+@cindex decays
+
+You may find that your scores have a tendency to grow without
+bounds, especially if you're using adaptive scoring.  If scores get too
+big, they lose all meaning---they simply max out and it's difficult to
+use them in any sensible way.
+
+@vindex gnus-decay-scores
+@findex gnus-decay-score
+@vindex gnus-decay-score-function
+Gnus provides a mechanism for decaying scores to help with this problem.
+When score files are loaded and @code{gnus-decay-scores} is
+non-@code{nil}, Gnus will run the score files through the decaying
+mechanism thereby lowering the scores of all non-permanent score rules.
+If @code{gnus-decay-scores} is a regexp, only score files matching this
+regexp are treated.  E.g., you may set it to @samp{\\.ADAPT\\'} if only
+@emph{adaptive} score files should be decayed.  The decay itself if
+performed by the @code{gnus-decay-score-function} function, which is
+@code{gnus-decay-score} by default.  Here's the definition of that
+function:
+
+@lisp
+(defun gnus-decay-score (score)
+  "Decay SCORE according to `gnus-score-decay-constant'
+and `gnus-score-decay-scale'."
+  (let ((n (- score
+              (* (if (< score 0) -1 1)
+                 (min (abs score)
+                      (max gnus-score-decay-constant
+                           (* (abs score)
+                              gnus-score-decay-scale)))))))
+    (if (and (featurep 'xemacs)
+             ;; XEmacs's floor can handle only the floating point
+             ;; number below the half of the maximum integer.
+             (> (abs n) (lsh -1 -2)))
+        (string-to-number
+         (car (split-string (number-to-string n) "\\.")))
+      (floor n))))
+@end lisp
+
+@vindex gnus-score-decay-scale
+@vindex gnus-score-decay-constant
+@code{gnus-score-decay-constant} is 3 by default and
+@code{gnus-score-decay-scale} is 0.05.  This should cause the following:
+
+@enumerate
+@item
+Scores between -3 and 3 will be set to 0 when this function is called.
+
+@item
+Scores with magnitudes between 3 and 60 will be shrunk by 3.
+
+@item
+Scores with magnitudes greater than 60 will be shrunk by 5% of the
+score.
+@end enumerate
+
+If you don't like this decay function, write your own.  It is called
+with the score to be decayed as its only parameter, and it should return
+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.
+
+@node Searching
+@chapter Searching
+@cindex searching
+
+FIXME: Add a brief overview of Gnus search capabilities.  A brief
+comparison of nnir, nnmairix, contrib/gnus-namazu would be nice
+as well.
+
+This chapter describes tools for searching groups and servers for
+articles matching a query and then retrieving those articles.  Gnus
+provides a simpler mechanism for searching through articles in a summary buffer
+to find those matching a pattern. @xref{Searching for Articles}.
+
+@menu
+* nnir::                     Searching with various engines.
+* nnmairix::                 Searching with Mairix.
+@end menu
+
+@node nnir
+@section nnir
+@cindex nnir
+
+This section describes how to use @code{nnir} to search for articles
+within gnus.
+
+@menu
+* What is nnir?::               What does @code{nnir} do?
+* Basic Usage::                 How to perform simple searches.
+* Setting up nnir::             How to set up @code{nnir}.
+@end menu
+
+@node What is nnir?
+@subsection What is nnir?
+
+@code{nnir} is a Gnus interface to a number of tools for searching
+through mail and news repositories.  Different backends (like
+@code{nnimap} and @code{nntp}) work with different tools (called
+@dfn{engines} in @code{nnir} lingo), but all use the same basic search
+interface.
+
+The @code{nnimap} and @code{gmane} search engines should work with no
+configuration.  Other engines require a local index that needs to be
+created and maintained outside of Gnus.
+
+
+@node Basic Usage
+@subsection Basic Usage
+
+In the group buffer typing @kbd{G G} will search the group on the
+current line by calling @code{gnus-group-make-nnir-group}.  This prompts
+for a query string, creates an ephemeral @code{nnir} group containing
+the articles that match this query, and takes you to a summary buffer
+showing these articles.  Articles may then be read, moved and deleted
+using the usual commands.
+
+The @code{nnir} group made in this way is an @code{ephemeral} group,
+and some changes are not permanent: aside from reading, moving, and
+deleting, you can't act on the original article.  But there is an
+alternative: you can @emph{warp} (i.e., jump) to the original group
+for the article on the current line with @kbd{A W}, aka
+@code{gnus-warp-to-article}.  Even better, the function
+@code{gnus-summary-refer-thread}, bound by default in summary buffers
+to @kbd{A T}, will first warp to the original group before it works
+its magic and includes all the articles in the thread.  From here you
+can read, move and delete articles, but also copy them, alter article
+marks, whatever.  Go nuts.
+
+You say you want to search more than just the group on the current line?
+No problem: just process-mark the groups you want to search.  You want
+even more?  Calling for an nnir search with the cursor on a topic heading
+will search all the groups under that heading.
+
+Still not enough?  OK, in the server buffer
+@code{gnus-group-make-nnir-group} (now bound to @kbd{G}) will search all
+groups from the server on the current line.  Too much?  Want to ignore
+certain groups when searching, like spam groups?  Just customize
+@code{nnir-ignored-newsgroups}.
+
+One more thing: individual search engines may have special search
+features.  You can access these special features by giving a prefix-arg
+to @code{gnus-group-make-nnir-group}.  If you are searching multiple
+groups with different search engines you will be prompted for the
+special search features for each engine separately.
+
+
+@node Setting up nnir
+@subsection Setting up nnir
+
+To set up nnir you may need to do some prep work.  Firstly, you may need
+to configure the search engines you plan to use.  Some of them, like
+@code{imap} and @code{gmane}, need no special configuration.  Others,
+like @code{namazu} and @code{swish}, require configuration as described
+below.  Secondly, you need to associate a search engine with a server or
+a backend.
+
+If you just want to use the @code{imap} engine to search @code{nnimap}
+servers, and the @code{gmane} engine to search @code{gmane} then you
+don't have to do anything.  But you might want to read the details of the
+query language anyway.
+
+@menu
+* Associating Engines::                 How to associate engines.
+* The imap Engine::                     Imap configuration and usage.
+* The gmane Engine::                    Gmane configuration and usage.
+* The swish++ Engine::                  Swish++ configuration and usage.
+* The swish-e Engine::                  Swish-e configuration and usage.
+* The namazu Engine::                   Namazu configuration and usage.
+* The notmuch Engine::                  Notmuch configuration and usage.
+* The hyrex Engine::                    Hyrex configuration and usage.
+* Customizations::                      User customizable settings.
+@end menu
+
+@node Associating Engines
+@subsubsection Associating Engines
+
+
+When searching a group, @code{nnir} needs to know which search engine to
+use.  You can configure a given server to use a particular engine by
+setting the server variable @code{nnir-search-engine} to the engine
+name.  For example to use the @code{namazu} engine to search the server
+named @code{home} you can use
+
+@lisp
+(setq gnus-secondary-select-methods
+      '((nnml "home"
+         (nnimap-address "localhost")
+         (nnir-search-engine namazu))))
+@end lisp
+
+Alternatively you might want to use a particular engine for all servers
+with a given backend.  For example, you might want to use the @code{imap}
+engine for all servers using the @code{nnimap} backend.  In this case you
+can customize the variable @code{nnir-method-default-engines}.  This is
+an alist of pairs of the form @code{(backend . engine)}.  By default this
+variable is set to use the @code{imap} engine for all servers using the
+@code{nnimap} backend, and the @code{gmane} backend for @code{nntp}
+servers.  (Don't worry, the @code{gmane} search engine won't actually try
+to search non-gmane @code{nntp} servers.)  But if you wanted to use
+@code{namazu} for all your servers with an @code{nnimap} backend you
+could change this to
+
+@lisp
+'((nnimap . namazu)
+  (nntp . gmane))
+@end lisp
+
+@node The imap Engine
+@subsubsection The imap Engine
+
+The @code{imap} engine requires no configuration.
+
+Queries using the @code{imap} engine follow a simple query language.
+The search is always case-insensitive and supports the following
+features (inspired by the Google search input language):
+
+@table @samp
+
+@item Boolean query operators
+AND, OR, and NOT are supported, and parentheses can be used to control
+operator precedence, e.g., (emacs OR xemacs) AND linux.  Note that
+operators must be written with all capital letters to be
+recognized.  Also preceding a term with a @minus{} sign is equivalent
+to NOT term.
+
+@item Automatic AND queries
+If you specify multiple words then they will be treated as an AND
+expression intended to match all components.
+
+@item Phrase searches
+If you wrap your query in double-quotes then it will be treated as a
+literal string.
+
+@end table
+
+By default the whole message will be searched.  The query can be limited
+to a specific part of a message by using a prefix-arg.  After inputting
+the query this will prompt (with completion) for a message part.
+Choices include ``Whole message'', ``Subject'', ``From'', and
+``To''.  Any unrecognized input is interpreted as a header name.  For
+example, typing @kbd{Message-ID} in response to this prompt will limit
+the query to the Message-ID header.
+
+Finally selecting ``Imap'' will interpret the query as a raw
+@acronym{IMAP} search query.  The format of such queries can be found in
+RFC3501.
+
+If you don't like the default of searching whole messages you can
+customize @code{nnir-imap-default-search-key}.  For example to use
+@acronym{IMAP} queries by default
+
+@lisp
+(setq nnir-imap-default-search-key "Imap")
+@end lisp
+
+@node The gmane Engine
+@subsubsection The gmane Engine
+
+The @code{gmane} engine requires no configuration.
+
+Gmane queries follow a simple query language:
+
+@table @samp
+@item Boolean query operators
+AND, OR, NOT (or AND NOT), and XOR are supported, and brackets can be
+used to control operator precedence, e.g., (emacs OR xemacs) AND linux.
+Note that operators must be written with all capital letters to be
+recognized.
+
+@item Required and excluded terms
++ and @minus{} can be used to require or exclude terms, e.g., football
+@minus{}american
+
+@item Unicode handling
+The search engine converts all text to utf-8, so searching should work
+in any language.
+
+@item Stopwords
+Common English words (like 'the' and 'a') are ignored by default.  You
+can override this by prefixing such words with a + (e.g., +the) or
+enclosing the word in quotes (e.g., "the").
+
+@end table
+
+The query can be limited to articles by a specific author using a
+prefix-arg.  After inputting the query this will prompt for an author
+name (or part of a name) to match.
+
+@node The swish++ Engine
+@subsubsection The swish++ Engine
+
+FIXME: Say something more here.
+
+Documentation for swish++ may be found at the swish++ sourceforge page:
+@uref{http://swishplusplus.sourceforge.net}
+
+@table @code
+
+@item nnir-swish++-program
+The name of the swish++ executable.  Defaults to @code{search}
+
+@item nnir-swish++-additional-switches
+A list of strings to be given as additional arguments to
+swish++.  @code{nil} by default.
+
+@item nnir-swish++-remove-prefix
+The prefix to remove from each file name returned by swish++ in order
+to get a group name.  By default this is @code{$HOME/Mail}.
+
+@end table
+
+@node The swish-e Engine
+@subsubsection The swish-e Engine
+
+FIXME: Say something more here.
+
+Documentation for swish-e may be found at the swish-e homepage
+@uref{http://swish-e.org}
+
+@table @code
+
+@item nnir-swish-e-program
+The name of the swish-e search program.  Defaults to @code{swish-e}.
+
+@item nnir-swish-e-additional-switches
+A list of strings to be given as additional arguments to
+swish-e.  @code{nil} by default.
+
+@item nnir-swish-e-remove-prefix
+The prefix to remove from each file name returned by swish-e in order
+to get a group name.  By default this is @code{$HOME/Mail}.
+
+@end table
+
+@node The namazu Engine
+@subsubsection The namazu Engine
+
+Using the namazu engine requires creating and maintaining index files.
+One directory should contain all the index files, and nnir must be told
+where to find them by setting the @code{nnir-namazu-index-directory}
+variable.
+
+To work correctly the @code{nnir-namazu-remove-prefix} variable must
+also be correct.  This is the prefix to remove from each file name
+returned by Namazu in order to get a proper group name (albeit with @samp{/}
+instead of @samp{.}).
+
+For example, suppose that Namazu returns file names such as
+@samp{/home/john/Mail/mail/misc/42}.  For this example, use the
+following setting: @code{(setq nnir-namazu-remove-prefix
+"/home/john/Mail/")} Note the trailing slash.  Removing this prefix from
+the directory gives @samp{mail/misc/42}.  @code{nnir} knows to remove
+the @samp{/42} and to replace @samp{/} with @samp{.} to arrive at the
+correct group name @samp{mail.misc}.
+
+Extra switches may be passed to the namazu search command by setting the
+variable @code{nnir-namazu-additional-switches}.  It is particularly
+important not to pass any any switches to namazu that will change the
+output format.  Good switches to use include @option{--sort},
+@option{--ascending}, @option{--early} and @option{--late}.
+Refer to the Namazu documentation for further
+information on valid switches.
+
+Mail must first be indexed with the @command{mknmz} program.  Read the
+documentation for namazu to create a configuration file.  Here is an
+example:
+
+@cartouche
+@example
+ package conf;  # Don't remove this line!
+
+ # Paths which will not be indexed. Don't use '^' or '$' anchors.
+ $EXCLUDE_PATH = "spam|sent";
+
+ # Header fields which should be searchable. case-insensitive
+ $REMAIN_HEADER = "from|date|message-id|subject";
+
+ # Searchable fields. case-insensitive
+ $SEARCH_FIELD = "from|date|message-id|subject";
+
+ # The max length of a word.
+ $WORD_LENG_MAX = 128;
+
+ # The max length of a field.
+ $MAX_FIELD_LENGTH = 256;
+@end example
+@end cartouche
+
+For this example, mail is stored in the directories @samp{~/Mail/mail/},
+@samp{~/Mail/lists/} and @samp{~/Mail/archive/}, so to index them go to
+the index directory set in @code{nnir-namazu-index-directory} and issue
+the following command:
+
+@example
+mknmz --mailnews ~/Mail/archive/ ~/Mail/mail/ ~/Mail/lists/
+@end example
+
+For maximum searching efficiency you might want to have a cron job run
+this command periodically, say every four hours.
+
+
+@node The notmuch Engine
+@subsubsection The notmuch Engine
+
+@table @code
+@item nnir-notmuch-program
+The name of the notmuch search executable.  Defaults to
+@samp{notmuch}.
+
+@item nnir-notmuch-additional-switches
+A list of strings, to be given as additional arguments to notmuch.
+
+@item nnir-notmuch-remove-prefix
+The prefix to remove from each file name returned by notmuch in order
+to get a group name (albeit with @samp{/} instead of @samp{.}).  This
+is a regular expression.
+
+@end table
+
+
+@node The hyrex Engine
+@subsubsection The hyrex Engine
+This engine is obsolete.
+
+@node Customizations
+@subsubsection Customizations
+
+@table @code
+
+@item nnir-method-default-engines
+Alist of pairs of server backends and search engines.  The default
+associations are
+@example
+(nnimap . imap)
+(nntp . gmane)
+@end example
+
+@item nnir-ignored-newsgroups
+A regexp to match newsgroups in the active file that should be skipped
+when searching all groups on a server.
+
+@item nnir-summary-line-format
+The format specification to be used for lines in an nnir summary buffer.
+All the items from @code{gnus-summary-line-format} are available, along with
+three items unique to nnir summary buffers:
+
+@example
+%Z    Search retrieval score value (integer)
+%G    Article original full group name (string)
+%g    Article original short group name (string)
+@end example
+
+If @code{nil} (the default) this will use @code{gnus-summary-line-format}.
+
+@item nnir-retrieve-headers-override-function
+If non-@code{nil}, a function that retrieves article headers rather than using
+the gnus built-in function.  This function takes an article list and
+group as arguments and populates the @code{nntp-server-buffer} with the
+retrieved headers.  It should then return either 'nov or 'headers
+indicating the retrieved header format.  Failure to retrieve headers
+should return @code{nil}.
+
+If this variable is @code{nil}, or if the provided function returns
+@code{nil} for a search result, @code{gnus-retrieve-headers} will be
+called instead."
+
+
+@end table
+
+
+@node nnmairix
+@section nnmairix
+
+@cindex mairix
+@cindex nnmairix
+This paragraph describes how to set up mairix and the back end
+@code{nnmairix} for indexing and searching your mail from within
+Gnus.  Additionally, you can create permanent ``smart'' groups which are
+bound to mairix searches and are automatically updated.
+
+@menu
+* About mairix::                About the mairix mail search engine
+* nnmairix requirements::       What you will need for using nnmairix
+* What nnmairix does::          What does nnmairix actually do?
+* Setting up mairix::           Set up your mairix installation
+* Configuring nnmairix::        Set up the nnmairix back end
+* nnmairix keyboard shortcuts:: List of available keyboard shortcuts
+* Propagating marks::           How to propagate marks from nnmairix groups
+* nnmairix tips and tricks::    Some tips, tricks and examples
+* nnmairix caveats::            Some more stuff you might want to know
+@end menu
+
+@c FIXME: The markup in this section might need improvement.
+@c E.g., adding @samp, @var, @file, @command, etc.
+@c Cf. (info "(texinfo)Indicating")
+
+@node About mairix
+@subsection About mairix
+
+Mairix is a tool for indexing and searching words in locally stored
+mail.  It was written by Richard Curnow and is licensed under the
+GPL@.  Mairix comes with most popular GNU/Linux distributions, but it also
+runs under Windows (with cygwin), Mac OS X and Solaris.  The homepage can
+be found at
+@uref{http://www.rpcurnow.force9.co.uk/mairix/index.html}
+
+Though mairix might not be as flexible as other search tools like
+swish++ or namazu, which you can use via the @code{nnir} back end, it
+has the prime advantage of being incredibly fast.  On current systems, it
+can easily search through headers and message bodies of thousands and
+thousands of mails in well under a second.  Building the database
+necessary for searching might take a minute or two, but only has to be
+done once fully.  Afterwards, the updates are done incrementally and
+therefore are really fast, too.  Additionally, mairix is very easy to set
+up.
+
+For maximum speed though, mairix should be used with mails stored in
+@code{Maildir} or @code{MH} format (this includes the @code{nnml} back
+end), although it also works with mbox.  Mairix presents the search
+results by populating a @emph{virtual} maildir/MH folder with symlinks
+which point to the ``real'' message files (if mbox is used, copies are
+made).  Since mairix already presents search results in such a virtual
+mail folder, it is very well suited for using it as an external program
+for creating @emph{smart} mail folders, which represent certain mail
+searches.
+
+@node nnmairix requirements
+@subsection nnmairix requirements
+
+Mairix searches local mail---that means, mairix absolutely must have
+direct access to your mail folders.  If your mail resides on another
+server (e.g., an @acronym{IMAP} server) and you happen to have shell
+access, @code{nnmairix} supports running mairix remotely, e.g., via ssh.
+
+Additionally, @code{nnmairix} only supports the following Gnus back
+ends: @code{nnml}, @code{nnmaildir}, and @code{nnimap}.  You must use
+one of these back ends for using @code{nnmairix}.  Other back ends, like
+@code{nnmbox}, @code{nnfolder} or @code{nnmh}, won't work.
+
+If you absolutely must use mbox and still want to use @code{nnmairix},
+you can set up a local @acronym{IMAP} server, which you then access via
+@code{nnimap}.  This is a rather massive setup for accessing some mbox
+files, so just change to MH or Maildir already...  However, if you're
+really, really passionate about using mbox, you might want to look into
+the package @file{mairix.el}, which comes with Emacs 23.
+
+@node What nnmairix does
+@subsection What nnmairix does
+
+The back end @code{nnmairix} enables you to call mairix from within Gnus,
+either to query mairix with a search term or to update the
+database.  While visiting a message in the summary buffer, you can use
+several pre-defined shortcuts for calling mairix, e.g., to quickly
+search for all mails from the sender of the current message or to
+display the whole thread associated with the message, even if the
+mails are in different folders.
+
+Additionally, you can create permanent @code{nnmairix} groups which are bound
+to certain mairix searches.  This way, you can easily create a group
+containing mails from a certain sender, with a certain subject line or
+even for one specific thread based on the Message-ID@.  If you check for
+new mail in these folders (e.g., by pressing @kbd{g} or @kbd{M-g}), they
+automatically update themselves by calling mairix.
+
+You might ask why you need @code{nnmairix} at all, since mairix already
+creates the group, populates it with links to the mails so that you can
+then access it with Gnus, right?  Well, this @emph{might} work, but often
+does not---at least not without problems.  Most probably you will get
+strange article counts, and sometimes you might see mails which Gnus
+claims have already been canceled and are inaccessible.  This is due to
+the fact that Gnus isn't really amused when things are happening behind
+its back.  Another problem can be the mail back end itself, e.g., if you
+use mairix with an @acronym{IMAP} server (I had Dovecot complaining
+about corrupt index files when mairix changed the contents of the search
+group).  Using @code{nnmairix} should circumvent these problems.
+
+@code{nnmairix} is not really a mail back end---it's actually more like
+a wrapper, sitting between a ``real'' mail back end where mairix stores
+the searches and the Gnus front end.  You can choose between three
+different mail back ends for the mairix folders: @code{nnml},
+@code{nnmaildir} or @code{nnimap}.  @code{nnmairix} will call the mairix
+binary so that the search results are stored in folders named
+@code{zz_mairix-<NAME>-<NUMBER>} on this mail back end, but it will
+present these folders in the Gnus front end only with @code{<NAME>}.
+You can use an existing mail back end where you already store your mail,
+but if you're uncomfortable with @code{nnmairix} creating new mail
+groups alongside your other mail, you can also create, e.g., a new
+@code{nnmaildir} or @code{nnml} server exclusively for mairix, but then
+make sure those servers do not accidentally receive your new mail
+(@pxref{nnmairix caveats}).  A special case exists if you want to use
+mairix remotely on an IMAP server with @code{nnimap}---here the mairix
+folders and your other mail must be on the same @code{nnimap} back end.
+
+@node Setting up mairix
+@subsection Setting up mairix
+
+First: create a backup of your mail folders (@pxref{nnmairix caveats}).
+
+Setting up mairix is easy: simply create a @file{.mairixrc} file with
+(at least) the following entries:
+
+@example
+# Your Maildir/MH base folder
+base=~/Maildir
+@end example
+
+This is the base folder for your mails.  All the following directories
+are relative to this base folder.  If you want to use @code{nnmairix}
+with @code{nnimap}, this base directory has to point to the mail
+directory where the @acronym{IMAP} server stores the mail folders!
+
+@example
+maildir= ... your maildir folders which should be indexed ...
+mh= ... your nnml/mh folders which should be indexed ...
+mbox = ... your mbox files which should be indexed ...
+@end example
+
+This specifies all your mail folders and mbox files (relative to the
+base directory!) you want to index with mairix.  Note that the
+@code{nnml} back end saves mails in MH format, so you have to put those
+directories in the @code{mh} line.  See the example at the end of this
+section and mairixrc's man-page for further details.
+
+@example
+omit=zz_mairix-*
+@end example
+
+@vindex nnmairix-group-prefix
+This should make sure that you don't accidentally index the mairix
+search results.  You can change the prefix of these folders with the
+variable @code{nnmairix-group-prefix}.
+
+@example
+mformat= ... 'maildir' or 'mh' ...
+database= ... location of database file ...
+@end example
+
+The @code{format} setting specifies the output format for the mairix
+search folder.  Set this to @code{mh} if you want to access search results
+with @code{nnml}.  Otherwise choose @code{maildir}.
+
+To summarize, here is my shortened @file{.mairixrc} file as an example:
+
+@example
+base=~/Maildir
+maildir=.personal:.work:.logcheck:.sent
+mh=../Mail/nnml/*...
+mbox=../mboxmail/mailarchive_year*
+mformat=maildir
+omit=zz_mairix-*
+database=~/.mairixdatabase
+@end example
+
+In this case, the base directory is @file{~/Maildir}, where all my Maildir
+folders are stored.  As you can see, the folders are separated by
+colons.  If you wonder why every folder begins with a dot: this is
+because I use Dovecot as @acronym{IMAP} server, which again uses
+@code{Maildir++} folders.  For testing nnmairix, I also have some
+@code{nnml} mail, which is saved in @file{~/Mail/nnml}.  Since this has
+to be specified relative to the @code{base} directory, the @code{../Mail}
+notation is needed.  Note that the line ends in @code{*...}, which means
+to recursively scan all files under this directory.  Without the three
+dots, the wildcard @code{*} will not work recursively.  I also have some
+old mbox files with archived mail lying around in @file{~/mboxmail}.
+The other lines should be obvious.
+
+See the man page for @code{mairixrc} for details and further options,
+especially regarding wildcard usage, which may be a little different
+than you are used to.
+
+Now simply call @code{mairix} to create the index for the first time.
+Note that this may take a few minutes, but every following index will do
+the updates incrementally and hence is very fast.
+
+@node Configuring nnmairix
+@subsection Configuring nnmairix
+
+In group mode, type @kbd{G b c}
+(@code{nnmairix-create-server-and-default-group}).  This will ask you for all
+necessary information and create a @code{nnmairix} server as a foreign
+server.  You will have to specify the following:
+
+@itemize @bullet
+
+@item
+The @strong{name} of the @code{nnmairix} server---choose whatever you
+want.
+
+@item
+The name of the @strong{back end server} where mairix should store its
+searches.  This must be a full server name, like @code{nnml:mymail}.
+Just hit @kbd{TAB} to see the available servers.  Currently, servers
+which are accessed through @code{nnmaildir}, @code{nnimap} and
+@code{nnml} are supported.  As explained above, for locally stored
+mails, this can be an existing server where you store your mails.
+However, you can also create, e.g., a new @code{nnmaildir} or @code{nnml}
+server exclusively for @code{nnmairix} in your secondary select methods
+(@pxref{Finding the News}).  If you use a secondary @code{nnml} server
+just for mairix, make sure that you explicitly set the server variable
+@code{nnml-get-new-mail} to @code{nil}, or you might lose mail
+(@pxref{nnmairix caveats}).  If you want to use mairix remotely on an
+@acronym{IMAP} server, you have to choose the corresponding
+@code{nnimap} server here.
+
+@item
+@vindex nnmairix-mairix-search-options
+The @strong{command} to call the mairix binary.  This will usually just
+be @code{mairix}, but you can also choose something like @code{ssh
+SERVER mairix} if you want to call mairix remotely, e.g., on your
+@acronym{IMAP} server.  If you want to add some default options to
+mairix, you could do this here, but better use the variable
+@code{nnmairix-mairix-search-options} instead.
+
+@item
+The name of the @strong{default search group}.  This will be the group
+where all temporary mairix searches are stored, i.e., all searches which
+are not bound to permanent @code{nnmairix} groups.  Choose whatever you
+like.
+
+@item
+If the mail back end is @code{nnimap} or @code{nnmaildir}, you will be
+asked if you work with @strong{Maildir++}, i.e., with hidden maildir
+folders (=beginning with a dot).  For example, you have to answer
+@samp{yes} here if you work with the Dovecot @acronym{IMAP}
+server.  Otherwise, you should answer @samp{no} here.
+
+@end itemize
+
+@node nnmairix keyboard shortcuts
+@subsection nnmairix keyboard shortcuts
+
+In group mode:
+
+@table @kbd
+
+@item G b c
+@kindex G b c (Group)
+@findex nnmairix-create-server-and-default-group
+Creates @code{nnmairix} server and default search group for this server
+(@code{nnmairix-create-server-and-default-group}).  You should have done
+this by now (@pxref{Configuring nnmairix}).
+
+@item G b s
+@kindex G b s (Group)
+@findex nnmairix-search
+Prompts for query which is then sent to the mairix binary.  Search
+results are put into the default search group which is automatically
+displayed (@code{nnmairix-search}).
+
+@item G b m
+@kindex G b m (Group)
+@findex nnmairix-widget-search
+Allows you to create a mairix search or a permanent group more
+comfortably using graphical widgets, similar to a customization
+group.  Just try it to see how it works (@code{nnmairix-widget-search}).
+
+@item G b i
+@kindex G b i (Group)
+@findex nnmairix-search-interactive
+Another command for creating a mairix query more comfortably, but uses
+only the minibuffer (@code{nnmairix-search-interactive}).
+
+@item G b g
+@kindex G b g (Group)
+@findex nnmairix-create-search-group
+Creates a permanent group which is associated with a search query
+(@code{nnmairix-create-search-group}).  The @code{nnmairix} back end
+automatically calls mairix when you update this group with @kbd{g} or
+@kbd{M-g}.
+
+@item G b q
+@kindex G b q (Group)
+@findex nnmairix-group-change-query-this-group
+Changes the search query for the @code{nnmairix} group under cursor
+(@code{nnmairix-group-change-query-this-group}).
+
+@item G b t
+@kindex G b t (Group)
+@findex nnmairix-group-toggle-threads-this-group
+Toggles the 'threads' parameter for the @code{nnmairix} group under cursor,
+i.e., if you want see the whole threads of the found messages
+(@code{nnmairix-group-toggle-threads-this-group}).
+
+@item G b u
+@kindex G b u (Group)
+@findex nnmairix-update-database
+@vindex nnmairix-mairix-update-options
+Calls mairix binary for updating the database
+(@code{nnmairix-update-database}).  The default parameters are @code{-F}
+and @code{-Q} for making this as fast as possible (see variable
+@code{nnmairix-mairix-update-options} for defining these default
+options).
+
+@item G b r
+@kindex G b r (Group)
+@findex nnmairix-group-toggle-readmarks-this-group
+Keep articles in this @code{nnmairix} group always read or unread, or leave the
+marks unchanged (@code{nnmairix-group-toggle-readmarks-this-group}).
+
+@item G b d
+@kindex G b d (Group)
+@findex nnmairix-group-delete-recreate-this-group
+Recreate @code{nnmairix} group on the ``real'' mail back end
+(@code{nnmairix-group-delete-recreate-this-group}).  You can do this if
+you always get wrong article counts with a @code{nnmairix} group.
+
+@item G b a
+@kindex G b a (Group)
+@findex nnmairix-group-toggle-allowfast-this-group
+Toggles the @code{allow-fast} parameters for group under cursor
+(@code{nnmairix-group-toggle-allowfast-this-group}).  The default
+behavior of @code{nnmairix} is to do a mairix search every time you
+update or enter the group.  With the @code{allow-fast} parameter set,
+mairix will only be called when you explicitly update the group, but not
+upon entering.  This makes entering the group faster, but it may also
+lead to dangling symlinks if something changed between updating and
+entering the group which is not yet in the mairix database.
+
+@item G b p
+@kindex G b p (Group)
+@findex nnmairix-group-toggle-propmarks-this-group
+Toggle marks propagation for this group
+(@code{nnmairix-group-toggle-propmarks-this-group}).  (@pxref{Propagating
+marks}).
+
+@item G b o
+@kindex G b o (Group)
+@findex nnmairix-propagate-marks
+Manually propagate marks (@code{nnmairix-propagate-marks}); needed only when
+@code{nnmairix-propagate-marks-upon-close} is set to @code{nil}.
+
+@end table
+
+In summary mode:
+
+@table @kbd
+
+@item $ m
+@kindex $ m (Summary)
+@findex nnmairix-widget-search-from-this-article
+Allows you to create a mairix query or group based on the current
+message using graphical widgets (same as @code{nnmairix-widget-search})
+(@code{nnmairix-widget-search-from-this-article}).
+
+@item $ g
+@kindex $ g (Summary)
+@findex nnmairix-create-search-group-from-message
+Interactively creates a new search group with query based on the current
+message, but uses the minibuffer instead of graphical widgets
+(@code{nnmairix-create-search-group-from-message}).
+
+@item $ t
+@kindex $ t (Summary)
+@findex nnmairix-search-thread-this-article
+Searches thread for the current article
+(@code{nnmairix-search-thread-this-article}).  This is effectively a
+shortcut for calling @code{nnmairix-search} with @samp{m:msgid} of the
+current article and enabled threads.
+
+@item $ f
+@kindex $ f (Summary)
+@findex nnmairix-search-from-this-article
+Searches all messages from sender of the current article
+(@code{nnmairix-search-from-this-article}).  This is a shortcut for
+calling @code{nnmairix-search} with @samp{f:From}.
+
+@item $ o
+@kindex $ o (Summary)
+@findex nnmairix-goto-original-article
+(Only in @code{nnmairix} groups!) Tries determine the group this article
+originally came from and displays the article in this group, so that,
+e.g., replying to this article the correct posting styles/group
+parameters are applied (@code{nnmairix-goto-original-article}).  This
+function will use the registry if available, but can also parse the
+article file name as a fallback method.
+
+@item $ u
+@kindex $ u (Summary)
+@findex nnmairix-remove-tick-mark-original-article
+Remove possibly existing tick mark from original article
+(@code{nnmairix-remove-tick-mark-original-article}).  (@pxref{nnmairix
+tips and tricks}).
+
+@end table
+
+@node Propagating marks
+@subsection Propagating marks
+
+First of: you really need a patched mairix binary for using the marks
+propagation feature efficiently.  Otherwise, you would have to update
+the mairix database all the time.  You can get the patch at
+
+@uref{http://www.randomsample.de/mairix-maildir-patch.tar}
+
+You need the mairix v0.21 source code for this patch; everything else
+is explained in the accompanied readme file.  If you don't want to use
+marks propagation, you don't have to apply these patches, but they also
+fix some annoyances regarding changing maildir flags, so it might still
+be useful to you.
+
+With the patched mairix binary, you can use @code{nnmairix} as an
+alternative to mail splitting (@pxref{Fancy Mail Splitting}).  For
+example, instead of splitting all mails from @samp{david@@foobar.com}
+into a group, you can simply create a search group with the query
+@samp{f:david@@foobar.com}.  This is actually what ``smart folders'' are
+all about: simply put everything in one mail folder and dynamically
+create searches instead of splitting.  This is more flexible, since you
+can dynamically change your folders any time you want to.  This also
+implies that you will usually read your mails in the @code{nnmairix}
+groups instead of your ``real'' mail groups.
+
+There is one problem, though: say you got a new mail from
+@samp{david@@foobar.com}; it will now show up in two groups, the
+``real'' group (your INBOX, for example) and in the @code{nnmairix}
+search group (provided you have updated the mairix database).  Now you
+enter the @code{nnmairix} group and read the mail.  The mail will be
+marked as read, but only in the @code{nnmairix} group---in the ``real''
+mail group it will be still shown as unread.
+
+You could now catch up the mail group (@pxref{Group Data}), but this is
+tedious and error prone, since you may overlook mails you don't have
+created @code{nnmairix} groups for.  Of course, you could first use
+@code{nnmairix-goto-original-article} (@pxref{nnmairix keyboard
+shortcuts}) and then read the mail in the original group, but that's
+even more cumbersome.
+
+Clearly, the easiest way would be if marks could somehow be
+automatically set for the original article.  This is exactly what
+@emph{marks propagation} is about.
+
+Marks propagation is inactive by default.  You can activate it for a
+certain @code{nnmairix} group with
+@code{nnmairix-group-toggle-propmarks-this-group} (bound to @kbd{G b
+p}).  This function will warn you if you try to use it with your default
+search group; the reason is that the default search group is used for
+temporary searches, and it's easy to accidentally propagate marks from
+this group.  However, you can ignore this warning if you really want to.
+
+With marks propagation enabled, all the marks you set in a @code{nnmairix}
+group should now be propagated to the original article.  For example,
+you can now tick an article (by default with @kbd{!}) and this mark should
+magically be set for the original article, too.
+
+A few more remarks which you may or may not want to know:
+
+@vindex nnmairix-propagate-marks-upon-close
+Marks will not be set immediately, but only upon closing a group.  This
+not only makes marks propagation faster, it also avoids problems with
+dangling symlinks when dealing with maildir files (since changing flags
+will change the file name).  You can also control when to propagate marks
+via @code{nnmairix-propagate-marks-upon-close} (see the doc-string for
+details).
+
+Obviously, @code{nnmairix} will have to look up the original group for every
+article you want to set marks for.  If available, @code{nnmairix} will first
+use the registry for determining the original group.  The registry is very
+fast, hence you should really, really enable the registry when using
+marks propagation.  If you don't have to worry about RAM and disc space,
+set @code{gnus-registry-max-entries} to a large enough value; to be on
+the safe side, choose roughly the amount of mails you index with mairix.
+
+@vindex nnmairix-only-use-registry
+If you don't want to use the registry or the registry hasn't seen the
+original article yet, @code{nnmairix} will use an additional mairix
+search for determining the file name of the article.  This, of course, is
+way slower than the registry---if you set hundreds or even thousands of
+marks this way, it might take some time.  You can avoid this situation by
+setting @code{nnmairix-only-use-registry} to @code{t}.
+
+Maybe you also want to propagate marks the other way round, i.e., if you
+tick an article in a "real" mail group, you'd like to have the same
+article in a @code{nnmairix} group ticked, too.  For several good
+reasons, this can only be done efficiently if you use maildir.  To
+immediately contradict myself, let me mention that it WON'T work with
+@code{nnmaildir}, since @code{nnmaildir} stores the marks externally and
+not in the file name.  Therefore, propagating marks to @code{nnmairix}
+groups will usually only work if you use an IMAP server which uses
+maildir as its file format.
+
+@vindex nnmairix-propagate-marks-to-nnmairix-groups
+If you work with this setup, just set
+@code{nnmairix-propagate-marks-to-nnmairix-groups} to @code{t} and see what
+happens.  If you don't like what you see, just set it to @code{nil} again.
+One problem might be that you get a wrong number of unread articles; this
+usually happens when you delete or expire articles in the original
+groups.  When this happens, you can recreate the @code{nnmairix} group on
+the back end using @kbd{G b d}.
+
+@node nnmairix tips and tricks
+@subsection nnmairix tips and tricks
+
+@itemize
+@item
+Checking Mail
+
+@findex nnmairix-update-groups
+I put all my important mail groups at group level 1.  The mairix groups
+have group level 5, so they do not get checked at start up (@pxref{Group
+Levels}).
+
+I use the following to check for mails:
+
+@lisp
+(defun my-check-mail-mairix-update (level)
+  (interactive "P")
+  ;; if no prefix given, set level=1
+  (gnus-group-get-new-news (or level 1))
+  (nnmairix-update-groups "mairixsearch" t t)
+  (gnus-group-list-groups))
+
+(define-key gnus-group-mode-map "g" 'my-check-mail-mairix-update)
+@end lisp
+
+Instead of @samp{"mairixsearch"} use the name of your @code{nnmairix}
+server.  See the doc string for @code{nnmairix-update-groups} for
+details.
+
+@item
+Example: search group for ticked articles
+
+For example, you can create a group for all ticked articles, where the
+articles always stay unread:
+
+Hit @kbd{G b g}, enter group name (e.g., @samp{important}), use
+@samp{F:f} as query and do not include threads.
+
+Now activate marks propagation for this group by using @kbd{G b p}.  Then
+activate the always-unread feature by using @kbd{G b r} twice.
+
+So far so good---but how do you remove the tick marks in the @code{nnmairix}
+group?  There are two options: You may simply use
+@code{nnmairix-remove-tick-mark-original-article} (bound to @kbd{$ u}) to remove
+tick marks from the original article.  The other possibility is to set
+@code{nnmairix-propagate-marks-to-nnmairix-groups} to @code{t}, but see the above
+comments about this option.  If it works for you, the tick marks should
+also exist in the @code{nnmairix} group and you can remove them as usual,
+e.g., by marking an article as read.
+
+When you have removed a tick mark from the original article, this
+article should vanish from the @code{nnmairix} group after you have updated the
+mairix database and updated the group.  Fortunately, there is a function
+for doing exactly that: @code{nnmairix-update-groups}.  See the previous code
+snippet and the doc string for details.
+
+@item
+Dealing with auto-subscription of mail groups
+
+As described before, all @code{nnmairix} groups are in fact stored on
+the mail back end in the form @samp{zz_mairix-<NAME>-<NUMBER>}.  You can
+see them when you enter the back end server in the server buffer.  You
+should not subscribe these groups!  Unfortunately, these groups will
+usually get @emph{auto-subscribed} when you use @code{nnmaildir} or
+@code{nnml}, i.e., you will suddenly see groups of the form
+@samp{zz_mairix*} pop up in your group buffer.  If this happens to you,
+simply kill these groups with C-k.  For avoiding this, turn off
+auto-subscription completely by setting the variable
+@code{gnus-auto-subscribed-groups} to @code{nil} (@pxref{Filtering New
+Groups}), or if you like to keep this feature use the following kludge
+for turning it off for all groups beginning with @samp{zz_}:
+
+@lisp
+(setq gnus-auto-subscribed-groups
+      "^\\(nnml\\|nnfolder\\|nnmbox\\|nnmh\\|nnbabyl\\|nnmaildir\\).*:\\([^z]\\|z$\\|\\z[^z]\\|zz$\\|zz[^_]\\|zz_$\\).*")
+@end lisp
+
+@end itemize
+
+@node nnmairix caveats
+@subsection nnmairix caveats
+
+@itemize
+@item
+You can create a secondary @code{nnml} server just for nnmairix, but then
+you have to explicitly set the corresponding server variable
+@code{nnml-get-new-mail} to @code{nil}.  Otherwise, new mail might get
+put into this secondary server (and would never show up again).  Here's
+an example server definition:
+
+@lisp
+(nnml "mairix" (nnml-directory "mairix") (nnml-get-new-mail nil))
+@end lisp
+
+(The @code{nnmaildir} back end also has a server variable
+@code{get-new-mail}, but its default value is @code{nil}, so you don't
+have to explicitly set it if you use a @code{nnmaildir} server just for
+mairix.)
+
+@item
+If you use the Gnus registry: don't use the registry with
+@code{nnmairix} groups (put them in
+@code{gnus-registry-unfollowed-groups}; this is the default).  Be
+@emph{extra careful} if you use
+@code{gnus-registry-split-fancy-with-parent}; mails which are split
+into @code{nnmairix} groups are usually gone for good as soon as you
+check the group for new mail (yes, it has happened to me...).
+
+@item
+Therefore: @emph{Never ever} put ``real'' mails into @code{nnmairix}
+groups (you shouldn't be able to, anyway).
+
+@item
+If you use the Gnus agent (@pxref{Gnus Unplugged}): don't agentize
+@code{nnmairix} groups (though I have no idea what happens if you do).
+
+@item
+mairix does only support us-ascii characters.
+
+@item
+@code{nnmairix} uses a rather brute force method to force Gnus to
+completely reread the group on the mail back end after mairix was
+called---it simply deletes and re-creates the group on the mail
+back end.  So far, this has worked for me without any problems, and I
+don't see how @code{nnmairix} could delete other mail groups than its
+own, but anyway: you really should have a backup of your mail
+folders.
+
+@item
+All necessary information is stored in the group parameters
+(@pxref{Group Parameters}).  This has the advantage that no active file
+is needed, but also implies that when you kill a @code{nnmairix} group,
+it is gone for good.
+
+@item
+@findex nnmairix-purge-old-groups
+If you create and kill a lot of @code{nnmairix} groups, the
+``zz_mairix-*'' groups will accumulate on the mail back end server.  To
+delete old groups which are no longer needed, call
+@code{nnmairix-purge-old-groups}.  Note that this assumes that you don't
+save any ``real'' mail in folders of the form
+@code{zz_mairix-<NAME>-<NUMBER>}.  You can change the prefix of
+@code{nnmairix} groups by changing the variable
+@code{nnmairix-group-prefix}.
+
+@item
+The following only applies if you @emph{don't} use the mentioned patch
+for mairix (@pxref{Propagating marks}):
+
+A problem can occur when using @code{nnmairix} with maildir folders and
+comes with the fact that maildir stores mail flags like @samp{Seen} or
+@samp{Replied} by appending chars @samp{S} and @samp{R} to the message
+file name, respectively.  This implies that currently you would have to
+update the mairix database not only when new mail arrives, but also when
+mail flags are changing.  The same applies to new mails which are indexed
+while they are still in the @samp{new} folder but then get moved to
+@samp{cur} when Gnus has seen the mail.  If you don't update the database
+after this has happened, a mairix query can lead to symlinks pointing to
+non-existing files.  In Gnus, these messages will usually appear with
+``(none)'' entries in the header and can't be accessed.  If this happens
+to you, using @kbd{G b u} and updating the group will usually fix this.
+
+@end itemize
+
+@iftex
+@iflatex
+@chapter Message
+@include message.texi
+@chapter Emacs MIME
+@include emacs-mime.texi
+@chapter Sieve
+@include sieve.texi
+@chapter EasyPG
+@include epa.texi
+@chapter SASL
+@include sasl.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.
+* Window Layout::               Configuring the Gnus buffer windows.
+* Faces and Fonts::             How to change how faces look.
+* Mode Lines::                  Displaying information in the mode lines.
+* Highlighting and Menus::      Making buffers look all nice and cozy.
+* Daemons::                     Gnus can do things behind your back.
+* Undo::                        Some actions can be undone.
+* Predicate Specifiers::        Specifying predicates.
+* Moderation::                  What to do if you're a moderator.
+* Fetching a Group::            Starting Gnus just to read a group.
+* Image Enhancements::          Modern versions of Emacs/XEmacs can display images.
+* Fuzzy Matching::              What's the big fuzz?
+* Thwarting Email Spam::        Simple ways to avoid unsolicited commercial email.
+* Spam Package::                A package for filtering and processing spam.
+* The Gnus Registry::           A package for tracking messages by Message-ID.
+* Other modes::                 Interaction with other modes.
+* Various Various::             Things that are really various.
+@end menu
+
+
+@node Process/Prefix
+@section Process/Prefix
+@cindex process/prefix convention
+
+Many functions, among them functions for moving, decoding and saving
+articles, use what is known as the @dfn{Process/Prefix convention}.
+
+This is a method for figuring out what articles the user wants the
+command to be performed on.
+
+It goes like this:
+
+If the numeric prefix is N, perform the operation on the next N
+articles, starting with the current one.  If the numeric prefix is
+negative, perform the operation on the previous N articles, starting
+with the current one.
+
+@vindex transient-mark-mode
+If @code{transient-mark-mode} in non-@code{nil} and the region is
+active, all articles in the region will be worked upon.
+
+If there is no numeric prefix, but some articles are marked with the
+process mark, perform the operation on the articles marked with
+the process mark.
+
+If there is neither a numeric prefix nor any articles marked with the
+process mark, just perform the operation on the current article.
+
+Quite simple, really, but it needs to be made clear so that surprises
+are avoided.
+
+Commands that react to the process mark will push the current list of
+process marked articles onto a stack and will then clear all process
+marked articles.  You can restore the previous configuration with the
+@kbd{M P y} command (@pxref{Setting Process Marks}).
+
+@vindex gnus-summary-goto-unread
+One thing that seems to shock & horrify lots of people is that, for
+instance, @kbd{3 d} does exactly the same as @kbd{d} @kbd{d} @kbd{d}.
+Since each @kbd{d} (which marks the current article as read) by default
+goes to the next unread article after marking, this means that @kbd{3 d}
+will mark the next three unread articles as read, no matter what the
+summary buffer looks like.  Set @code{gnus-summary-goto-unread} to
+@code{nil} for a more straightforward action.
+
+Many commands do not use the process/prefix convention.  All commands
+that do explicitly say so in this manual.  To apply the process/prefix
+convention to commands that do not use it, you can use the @kbd{M-&}
+command.  For instance, to mark all the articles in the group as
+expirable, you could say @kbd{M P b M-& E}.
+
+
+@node Interactive
+@section Interactive
+@cindex interaction
+
+@table @code
+
+@item gnus-novice-user
+@vindex gnus-novice-user
+If this variable is non-@code{nil}, you are either a newcomer to the
+World of Usenet, or you are very cautious, which is a nice thing to be,
+really.  You will be given questions of the type ``Are you sure you want
+to do this?'' before doing anything dangerous.  This is @code{t} by
+default.
+
+@item gnus-expert-user
+@vindex gnus-expert-user
+If this variable is non-@code{nil}, you will seldom be asked any
+questions by Gnus.  It will simply assume you know what you're doing,
+no matter how strange.  For example, quitting Gnus, exiting a group
+without an update, catching up with a group, deleting expired
+articles, and replying by mail to a news message will not require
+confirmation.
+
+@item gnus-interactive-catchup
+@vindex gnus-interactive-catchup
+Require confirmation before catching up a group if non-@code{nil}.  It
+is @code{t} by default.
+
+@item gnus-interactive-exit
+@vindex gnus-interactive-exit
+If non-@code{nil}, require a confirmation when exiting Gnus.  If
+@code{quiet}, update any active summary buffers automatically without
+querying.  The default value is @code{t}.
+@end table
+
+
+@node Symbolic Prefixes
+@section Symbolic Prefixes
+@cindex symbolic prefixes
+
+Quite a lot of Emacs commands react to the (numeric) prefix.  For
+instance, @kbd{C-u 4 C-f} moves point four characters forward, and
+@kbd{C-u 9 0 0 I s s p} adds a permanent @code{Subject} substring score
+rule of 900 to the current article.
+
+This is all nice and well, but what if you want to give a command some
+additional information?  Well, what most commands do is interpret the
+``raw'' prefix in some special way.  @kbd{C-u 0 C-x C-s} means that one
+doesn't want a backup file to be created when saving the current buffer,
+for instance.  But what if you want to save without making a backup
+file, and you want Emacs to flash lights and play a nice tune at the
+same time?  You can't, and you're probably perfectly happy that way.
+
+@kindex M-i (Summary)
+@findex gnus-symbolic-argument
+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 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
+hurt, but it doesn't do any good either.  Currently not many Gnus
+functions make use of the symbolic prefix.
+
+If you're interested in how Gnus implements this, @pxref{Extended
+Interactive}.
+
+
+@node Formatting Variables
+@section Formatting Variables
+@cindex formatting variables
+
+Throughout this manual you've probably noticed lots of variables called
+things like @code{gnus-group-line-format} and
+@code{gnus-summary-mode-line-format}.  These control how Gnus is to
+output lines in the various buffers.  There's quite a lot of them.
+Fortunately, they all use the same syntax, so there's not that much to
+be annoyed by.
+
+Here's an example format spec (from the group buffer): @samp{%M%S%5y:
+%(%g%)\n}.  We see that it is indeed extremely ugly, and that there are
+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.
+* 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:
+@code{gnus-group-line-format}, @code{gnus-summary-line-format},
+@code{gnus-server-line-format}, @code{gnus-topic-line-format},
+@code{gnus-group-mode-line-format},
+@code{gnus-summary-mode-line-format},
+@code{gnus-article-mode-line-format},
+@code{gnus-server-mode-line-format}, and
+@code{gnus-summary-pick-line-format}.
+
+All these format variables can also be arbitrary elisp forms.  In that
+case, they will be @code{eval}ed to insert the required lines.
+
+@kindex M-x gnus-update-format
+@findex gnus-update-format
+Gnus includes a command to help you while creating your own format
+specs.  @kbd{M-x gnus-update-format} will @code{eval} the current form,
+update the spec in question and pop you to a buffer where you can
+examine the resulting Lisp code to be run to generate the line.
+
+
+
+@node Formatting Basics
+@subsection Formatting Basics
+
+Each @samp{%} element will be replaced by some string or other when the
+buffer in question is generated.  @samp{%5y} means ``insert the @samp{y}
+spec, and pad with spaces to get a 5-character field''.
+
+As with normal C and Emacs Lisp formatting strings, the numerical
+modifier between the @samp{%} and the formatting type character will
+@dfn{pad} the output so that it is always at least that long.
+@samp{%5y} will make the field always (at least) five characters wide by
+padding with spaces to the left.  If you say @samp{%-5y}, it will pad to
+the right instead.
+
+You may also wish to limit the length of the field to protect against
+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
+
+Mode line formatting variables (e.g.,
+@code{gnus-summary-mode-line-format}) follow the same rules as other,
+buffer line oriented formatting variables (@pxref{Formatting Basics})
+with the following two differences:
+
+@enumerate
+
+@item
+There must be no newline (@samp{\n}) at the end.
+
+@item
+The special @samp{%%b} spec can be used to display the buffer name.
+Well, it's no spec at all, really---@samp{%%} is just a way to quote
+@samp{%} to allow it to pass through the formatting machinery unmangled,
+so that Emacs receives @samp{%b}, which is something the Emacs mode line
+display interprets to mean ``show the buffer name''.  For a full list of
+mode line specs Emacs understands, see the documentation of the
+@code{mode-line-format} variable.
+
+@end enumerate
+
+
+@node Advanced Formatting
+@subsection Advanced Formatting
+
+It is frequently useful to post-process the fields in some way.
+Padding, limiting, cutting off parts and suppressing certain values can
+be achieved by using @dfn{tilde modifiers}.  A typical tilde spec might
+look like @samp{%~(cut 3)~(ignore "0")y}.
+
+These are the valid modifiers:
+
+@table @code
+@item pad
+@itemx pad-left
+Pad the field to the left with spaces until it reaches the required
+length.
+
+@item pad-right
+Pad the field to the right with spaces until it reaches the required
+length.
+
+@item max
+@itemx max-left
+Cut off characters from the left until it reaches the specified length.
+
+@item max-right
+Cut off characters from the right until it reaches the specified
+length.
+
+@item cut
+@itemx cut-left
+Cut off the specified number of characters from the left.
+
+@item cut-right
+Cut off the specified number of characters from the right.
+
+@item ignore
+Return an empty string if the field is equal to the specified value.
+
+@item form
+Use the specified form as the field value when the @samp{@@} spec is
+used.
+
+Here's an example:
+
+@lisp
+"~(form (current-time-string))@@"
+@end lisp
+
+@end table
+
+Let's take an example.  The @samp{%o} spec in the summary mode lines
+will return a date in compact ISO8601 format---@samp{19960809T230410}.
+This is quite a mouthful, so we want to shave off the century number and
+the time, leaving us with a six-character date.  That would be
+@samp{%~(cut-left 2)~(max-right 6)~(pad 6)o}.  (Cutting is done before
+maxing, and we need the padding to ensure that the date is never less
+than 6 characters to make it look nice in columns.)
+
+Ignoring is done first; then cutting; then maxing; and then as the very
+last operation, padding.
+
+
+@node User-Defined Specs
+@subsection User-Defined Specs
+
+All the specs allow for inserting user defined specifiers---@samp{u}.
+The next character in the format string should be a letter.  Gnus
+will call the function @code{gnus-user-format-function-}@samp{X}, where
+@samp{X} is the letter following @samp{%u}.  The function will be passed
+a single parameter---what the parameter means depends on what buffer
+it's being called from.  The function should return a string, which will
+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
+given here will be evaluated to yield the current line number, and then
+inserted.
+
+
+@node Formatting Fonts
+@subsection Formatting Fonts
+
+@cindex %(, %)
+@vindex gnus-mouse-face
+There are specs for highlighting, and these are shared by all the format
+variables.  Text inside the @samp{%(} and @samp{%)} specifiers will get
+the special @code{mouse-face} property set, which means that it will be
+highlighted (with @code{gnus-mouse-face}) when you put the mouse pointer
+over it.
+
+@cindex %@{, %@}
+@vindex gnus-face-0
+Text inside the @samp{%@{} and @samp{%@}} specifiers will have their
+normal faces set using @code{gnus-face-0}, which is @code{bold} by
+default.  If you say @samp{%1@{}, you'll get @code{gnus-face-1} instead,
+and so on.  Create as many faces as you wish.  The same goes for the
+@code{mouse-face} specs---you can say @samp{%3(hello%)} to have
+@samp{hello} mouse-highlighted with @code{gnus-mouse-face-3}.
+
+@cindex %<<, %>>, guillemets
+@c @cindex %<<, %>>, %«, %», guillemets
+@vindex gnus-balloon-face-0
+Text inside the @samp{%<<} and @samp{%>>} specifiers will get the
+special @code{balloon-help} property set to
+@code{gnus-balloon-face-0}.  If you say @samp{%1<<}, you'll get
+@code{gnus-balloon-face-1} and so on.  The @code{gnus-balloon-face-*}
+variables should be either strings or symbols naming functions that
+return a string.  When the mouse passes over text with this property
+set, a balloon window will appear and display the string.  Please
+refer to @ref{Tooltips, ,Tooltips, emacs, The Emacs Manual},
+(in Emacs) or the doc string of @code{balloon-help-mode} (in
+XEmacs) for more information on this.  (For technical reasons, the
+guillemets have been approximated as @samp{<<} and @samp{>>} in this
+paragraph.)
+
+Here's an alternative recipe for the group buffer:
+
+@lisp
+;; @r{Create three face types.}
+(setq gnus-face-1 'bold)
+(setq gnus-face-3 'italic)
+
+;; @r{We want the article count to be in}
+;; @r{a bold and green face.  So we create}
+;; @r{a new face called @code{my-green-bold}.}
+(copy-face 'bold 'my-green-bold)
+;; @r{Set the color.}
+(set-face-foreground 'my-green-bold "ForestGreen")
+(setq gnus-face-2 'my-green-bold)
+
+;; @r{Set the new & fancy format.}
+(setq gnus-group-line-format
+      "%M%S%3@{%5y%@}%2[:%] %(%1@{%g%@}%)\n")
+@end lisp
+
+I'm sure you'll be able to use this scheme to create totally unreadable
+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 behavior 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{%*} specifier.  If you
+put a @samp{%*} 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
+
+Fixed width 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 countries, that's not true.
+
+@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
+prettier.  The default value under XEmacs is @code{t} but @code{nil}
+for Emacs.
+
+
+@node Window Layout
+@section Window Layout
+@cindex window layout
+
+No, there's nothing here about X, so be quiet.
+
+@vindex gnus-use-full-window
+If @code{gnus-use-full-window} non-@code{nil}, Gnus will delete all
+other windows and occupy the entire Emacs screen by itself.  It is
+@code{t} by default.
+
+Setting this variable to @code{nil} kinda works, but there are
+glitches.  Use at your own peril.
+
+@vindex gnus-buffer-configuration
+@code{gnus-buffer-configuration} describes how much space each Gnus
+buffer should be given.  Here's an excerpt of this variable:
+
+@lisp
+((group (vertical 1.0 (group 1.0 point)))
+ (article (vertical 1.0 (summary 0.25 point)
+                        (article 1.0))))
+@end lisp
+
+This is an alist.  The @dfn{key} is a symbol that names some action or
+other.  For instance, when displaying the group buffer, the window
+configuration function will use @code{group} as the key.  A full list of
+possible names is listed below.
+
+The @dfn{value} (i.e., the @dfn{split}) says how much space each buffer
+should occupy.  To take the @code{article} split as an example:
+
+@lisp
+(article (vertical 1.0 (summary 0.25 point)
+                       (article 1.0)))
+@end lisp
+
+This @dfn{split} says that the summary buffer should occupy 25% of upper
+half of the screen, and that it is placed over the article buffer.  As
+you may have noticed, 100% + 25% is actually 125% (yup, I saw y'all
+reaching for that calculator there).  However, the special number
+@code{1.0} is used to signal that this buffer should soak up all the
+rest of the space available after the rest of the buffers have taken
+whatever they need.  There should be only one buffer with the @code{1.0}
+size spec per split.
+
+Point will be put in the buffer that has the optional third element
+@code{point}.  In a @code{frame} split, the last subsplit having a leaf
+split where the tag @code{frame-focus} is a member (i.e., is the third or
+fourth element in the list, depending on whether the @code{point} tag is
+present) gets focus.
+
+Here's a more complicated example:
+
+@lisp
+(article (vertical 1.0 (group 4)
+                       (summary 0.25 point)
+                       (article 1.0)))
+@end lisp
+
+If the size spec is an integer instead of a floating point number,
+then that number will be used to say how many lines a buffer should
+occupy, not a percentage.
+
+If the @dfn{split} looks like something that can be @code{eval}ed (to be
+precise---if the @code{car} of the split is a function or a subr), this
+split will be @code{eval}ed.  If the result is non-@code{nil}, it will
+be used as a split.
+
+Not complicated enough for you?  Well, try this on for size:
+
+@lisp
+(article (horizontal 1.0
+             (vertical 0.5
+                 (group 1.0))
+             (vertical 1.0
+                 (summary 0.25 point)
+                 (article 1.0))))
+@end lisp
+
+Whoops.  Two buffers with the mystery 100% tag.  And what's that
+@code{horizontal} thingie?
+
+If the first element in one of the split is @code{horizontal}, Gnus will
+split the window horizontally, giving you two windows side-by-side.
+Inside each of these strips you may carry on all you like in the normal
+fashion.  The number following @code{horizontal} says what percentage of
+the screen is to be given to this strip.
+
+For each split, there @emph{must} be one element that has the 100% tag.
+The splitting is never accurate, and this buffer will eat any leftover
+lines from the splits.
+
+To be slightly more formal, here's a definition of what a valid split
+may look like:
+
+@example
+@group
+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 group
+@end example
+
+The limitations are that the @code{frame} split can only appear as the
+top-level split.  @var{form} should be an Emacs Lisp form that should
+return a valid split.  We see that each split is fully recursive, and
+may contain any number of @code{vertical} and @code{horizontal} splits.
+
+@vindex gnus-window-min-width
+@vindex gnus-window-min-height
+@cindex window height
+@cindex window width
+Finding the right sizes can be a bit complicated.  No window may be less
+than @code{gnus-window-min-height} (default 1) characters high, and all
+windows must be at least @code{gnus-window-min-width} (default 1)
+characters wide.  Gnus will try to enforce this before applying the
+splits.  If you want to use the normal Emacs window width/height limit,
+you can just set these two variables to @code{nil}.
+
+If you're not familiar with Emacs terminology, @code{horizontal} and
+@code{vertical} splits may work the opposite way of what you'd expect.
+Windows inside a @code{horizontal} split are shown side-by-side, and
+windows within a @code{vertical} split are shown above each other.
+
+@findex gnus-configure-frame
+If you want to experiment with window placement, a good tip is to call
+@code{gnus-configure-frame} directly with a split.  This is the function
+that does all the real work when splitting buffers.  Below is a pretty
+nonsensical configuration with 5 windows; two for the group buffer and
+three for the article buffer.  (I said it was nonsensical.)  If you
+@code{eval} the statement below, you can get an idea of how that would
+look straight away, without going through the normal Gnus channels.
+Play with it until you're satisfied, and then use
+@code{gnus-add-configuration} to add your new creation to the buffer
+configuration list.
+
+@lisp
+(gnus-configure-frame
+ '(horizontal 1.0
+    (vertical 10
+      (group 1.0)
+      (article 0.3 point))
+    (vertical 1.0
+      (article 1.0)
+      (horizontal 4
+        (group 1.0)
+        (article 10)))))
+@end lisp
+
+You might want to have several frames as well.  No prob---just use the
+@code{frame} split:
+
+@lisp
+(gnus-configure-frame
+ '(frame 1.0
+         (vertical 1.0
+                   (summary 0.25 point frame-focus)
+                   (article 1.0))
+         (vertical ((height . 5) (width . 15)
+                    (user-position . t)
+                    (left . -1) (top . 1))
+                   (picon 1.0))))
+
+@end lisp
+
+This split will result in the familiar summary/article window
+configuration in the first (or ``main'') frame, while a small additional
+frame will be created where picons will be shown.  As you can see,
+instead of the normal @code{1.0} top-level spec, each additional split
+should have a frame parameter alist as the size spec.
+@xref{Frame Parameters, , Frame Parameters, elisp, The GNU Emacs Lisp
+Reference Manual}.  Under XEmacs, a frame property list will be
+accepted, too---for instance, @code{(height 5 width 15 left -1 top 1)}
+is such a plist.
+The list of all possible keys for @code{gnus-buffer-configuration} can
+be found in its default value.
+
+Note that the @code{message} key is used for both
+@code{gnus-group-mail} and @code{gnus-summary-mail-other-window}.  If
+it is desirable to distinguish between the two, something like this
+might be used:
+
+@lisp
+(message (horizontal 1.0
+                     (vertical 1.0 (message 1.0 point))
+                     (vertical 0.24
+                               (if (buffer-live-p gnus-summary-buffer)
+                                   '(summary 0.5))
+                               (group 1.0))))
+@end lisp
+
+One common desire for a multiple frame split is to have a separate frame
+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))))
+@end lisp
+
+@findex gnus-add-configuration
+Since the @code{gnus-buffer-configuration} variable is so long and
+complicated, there's a function you can use to ease changing the config
+of a single setting: @code{gnus-add-configuration}.  If, for instance,
+you want to change the @code{article} setting, you could say:
+
+@lisp
+(gnus-add-configuration
+ '(article (vertical 1.0
+               (group 4)
+               (summary .25 point)
+               (article 1.0))))
+@end lisp
+
+You'd typically stick these @code{gnus-add-configuration} calls in your
+@file{~/.gnus.el} file or in some startup hook---they should be run after
+Gnus has been loaded.
+
+@vindex gnus-always-force-window-configuration
+If all windows mentioned in the configuration are already visible, Gnus
+won't change the window configuration.  If you always want to force the
+``right'' window configuration, you can set
+@code{gnus-always-force-window-configuration} to non-@code{nil}.
+
+If you're using tree displays (@pxref{Tree Display}), and the tree
+window is displayed vertically next to another window, you may also want
+to fiddle with @code{gnus-tree-minimize-window} to avoid having the
+windows resized.
+
+@subsection Window Configuration Names
+
+Here's a list of most of the currently known window configurations,
+and when they're used:
+
+@table @code
+@item group
+The group buffer.
+
+@item summary
+Entering a group and showing only the summary.
+
+@item article
+Selecting an article.
+
+@item server
+The server buffer.
+
+@item browse
+Browsing groups from the server buffer.
+
+@item message
+Composing a (new) message.
+
+@item only-article
+Showing only the article buffer.
+
+@item edit-article
+Editing an article.
+
+@item edit-form
+Editing group parameters and the like.
+
+@item edit-score
+Editing a server definition.
+
+@item post
+Composing a news message.
+
+@item reply
+Replying or following up an article without yanking the text.
+
+@item forward
+Forwarding a message.
+
+@item reply-yank
+Replying or following up an article with yanking the text.
+
+@item mail-bound
+Bouncing a message.
+
+@item pipe
+Sending an article to an external process.
+
+@item bug
+Sending a bug report.
+
+@item score-trace
+Displaying the score trace.
+
+@item score-words
+Displaying the score words.
+
+@item split-trace
+Displaying the split trace.
+
+@item compose-bounce
+Composing a bounce message.
+
+@item mml-preview
+Previewing a @acronym{MIME} part.
+
+@end table
+
+
+@subsection Example Window Configurations
+
+@itemize @bullet
+@item
+Narrow left hand side occupied by group buffer.  Right hand side split
+between summary buffer (top one-sixth) and article buffer (bottom).
+
+@ifinfo
+@example
++---+---------+
+| G | Summary |
+| r +---------+
+| o |         |
+| u | Article |
+| p |         |
++---+---------+
+@end example
+@end ifinfo
+
+@lisp
+(gnus-add-configuration
+ '(article
+   (horizontal 1.0
+               (vertical 25 (group 1.0))
+               (vertical 1.0
+                         (summary 0.16 point)
+                         (article 1.0)))))
+
+(gnus-add-configuration
+ '(summary
+   (horizontal 1.0
+               (vertical 25 (group 1.0))
+               (vertical 1.0 (summary 1.0 point)))))
+@end lisp
+
+@end itemize
+
+
+@node Faces and Fonts
+@section Faces and Fonts
+@cindex faces
+@cindex fonts
+@cindex colors
+
+Fiddling with fonts and faces used to be very difficult, but these days
+it is very simple.  You simply say @kbd{M-x customize-face}, pick out
+the face you want to alter, and alter it via the standard Customize
+interface.
+
+
+@node Mode Lines
+@section Mode Lines
+@cindex mode lines
+
+@vindex gnus-updated-mode-lines
+@code{gnus-updated-mode-lines} says what buffers should keep their mode
+lines updated.  It is a list of symbols.  Supported symbols include
+@code{group}, @code{article}, @code{summary}, @code{server},
+@code{browse}, and @code{tree}.  If the corresponding symbol is present,
+Gnus will keep that mode line updated with information that may be
+pertinent.  If this variable is @code{nil}, screen refresh may be
+quicker.
+
+@cindex display-time
+
+@vindex gnus-mode-non-string-length
+By default, Gnus displays information on the current article in the mode
+lines of the summary and article buffers.  The information Gnus wishes
+to display (e.g., the subject of the article) is often longer than the
+mode lines, and therefore have to be cut off at some point.  The
+@code{gnus-mode-non-string-length} variable says how long the other
+elements on the line is (i.e., the non-info part).  If you put
+additional elements on the mode line (e.g., a clock), you should modify
+this variable:
+
+@c Hook written by Francesco Potortì <pot@cnuce.cnr.it>
+@lisp
+(add-hook 'display-time-hook
+          (lambda () (setq gnus-mode-non-string-length
+                           (+ 21
+                              (if line-number-mode 5 0)
+                              (if column-number-mode 4 0)
+                              (length display-time-string)))))
+@end lisp
+
+If this variable is @code{nil} (which is the default), the mode line
+strings won't be chopped off, and they won't be padded either.  Note
+that the default is unlikely to be desirable, as even the percentage
+complete in the buffer may be crowded off the mode line; the user should
+configure this variable appropriately for her configuration.
+
+
+@node Highlighting and Menus
+@section Highlighting and Menus
+@cindex visual
+@cindex highlighting
+@cindex menus
+
+@vindex gnus-visual
+The @code{gnus-visual} variable controls most of the Gnus-prettifying
+aspects.  If @code{nil}, Gnus won't attempt to create menus or use fancy
+colors or fonts.  This will also inhibit loading the @file{gnus-vis.el}
+file.
+
+This variable can be a list of visual properties that are enabled.  The
+following elements are valid, and are all included by default:
+
+@table @code
+@item group-highlight
+Do highlights in the group buffer.
+@item summary-highlight
+Do highlights in the summary buffer.
+@item article-highlight
+Do highlights in the article buffer.
+@item highlight
+Turn on highlighting in all buffers.
+@item group-menu
+Create menus in the group buffer.
+@item summary-menu
+Create menus in the summary buffers.
+@item article-menu
+Create menus in the article buffer.
+@item browse-menu
+Create menus in the browse buffer.
+@item server-menu
+Create menus in the server buffer.
+@item score-menu
+Create menus in the score buffers.
+@item menu
+Create menus in all buffers.
+@end table
+
+So if you only want highlighting in the article buffer and menus in all
+buffers, you could say something like:
+
+@lisp
+(setq gnus-visual '(article-highlight menu))
+@end lisp
+
+If you want highlighting only and no menus whatsoever, you'd say:
+
+@lisp
+(setq gnus-visual '(highlight))
+@end lisp
+
+If @code{gnus-visual} is @code{t}, highlighting and menus will be used
+in all Gnus buffers.
+
+Other general variables that influence the look of all buffers include:
+
+@table @code
+@item gnus-mouse-face
+@vindex gnus-mouse-face
+This is the face (i.e., font) used for mouse highlighting in Gnus.  No
+mouse highlights will be done if @code{gnus-visual} is @code{nil}.
+
+@end table
+
+There are hooks associated with the creation of all the different menus:
+
+@table @code
+
+@item gnus-article-menu-hook
+@vindex gnus-article-menu-hook
+Hook called after creating the article mode menu.
+
+@item gnus-group-menu-hook
+@vindex gnus-group-menu-hook
+Hook called after creating the group mode menu.
+
+@item gnus-summary-menu-hook
+@vindex gnus-summary-menu-hook
+Hook called after creating the summary mode menu.
+
+@item gnus-server-menu-hook
+@vindex gnus-server-menu-hook
+Hook called after creating the server mode menu.
+
+@item gnus-browse-menu-hook
+@vindex gnus-browse-menu-hook
+Hook called after creating the browse mode menu.
+
+@item gnus-score-menu-hook
+@vindex gnus-score-menu-hook
+Hook called after creating the score mode menu.
+
+@end table
+
+
+@node Daemons
+@section Daemons
+@cindex demons
+@cindex daemons
+
+Gnus, being larger than any program ever written (allegedly), does lots
+of strange stuff that you may wish to have done while you're not
+present.  For instance, you may want it to check for new mail once in a
+while.  Or you may want it to close down all connections to all servers
+when you leave Emacs idle.  And stuff like that.
+
+Gnus will let you do stuff like that by defining various
+@dfn{handlers}.  Each handler consists of three elements:  A
+@var{function}, a @var{time}, and an @var{idle} parameter.
+
+Here's an example of a handler that closes connections when Emacs has
+been idle for thirty minutes:
+
+@lisp
+(gnus-demon-close-connections nil 30)
+@end lisp
+
+Here's a handler that scans for @acronym{PGP} headers every hour when
+Emacs is idle:
+
+@lisp
+(gnus-demon-scan-pgp 60 t)
+@end lisp
+
+This @var{time} parameter and that @var{idle} parameter work together
+in a strange, but wonderful fashion.  Basically, if @var{idle} is
+@code{nil}, then the function will be called every @var{time} minutes.
+
+If @var{idle} is @code{t}, then the function will be called after
+@var{time} minutes only if Emacs is idle.  So if Emacs is never idle,
+the function will never be called.  But once Emacs goes idle, the
+function will be called every @var{time} minutes.
+
+If @var{idle} is a number and @var{time} is a number, the function will
+be called every @var{time} minutes only when Emacs has been idle for
+@var{idle} minutes.
+
+If @var{idle} is a number and @var{time} is @code{nil}, the function
+will be called once every time Emacs has been idle for @var{idle}
+minutes.
+
+And if @var{time} is a string, it should look like @samp{07:31}, and
+the function will then be called once every day somewhere near that
+time.  Modified by the @var{idle} parameter, of course.
+
+@vindex gnus-demon-timestep
+(When I say ``minute'' here, I really mean @code{gnus-demon-timestep}
+seconds.  This is 60 by default.  If you change that variable,
+all the timings in the handlers will be affected.)
+
+So, if you want to add a handler, you could put something like this in
+your @file{~/.gnus.el} file:
+
+@findex gnus-demon-add-handler
+@lisp
+(gnus-demon-add-handler 'gnus-demon-close-connections 30 t)
+@end lisp
+
+@findex gnus-demon-add-scanmail
+@findex gnus-demon-add-rescan
+@findex gnus-demon-add-scan-timestamps
+@findex gnus-demon-add-disconnection
+Some ready-made functions to do this have been created:
+@code{gnus-demon-add-disconnection},
+@code{gnus-demon-add-nntp-close-connection},
+@code{gnus-demon-add-scan-timestamps}, @code{gnus-demon-add-rescan}, and
+@code{gnus-demon-add-scanmail}.  Just put those functions in your
+@file{~/.gnus.el} if you want those abilities.
+
+@findex gnus-demon-init
+@findex gnus-demon-cancel
+@vindex gnus-demon-handlers
+If you add handlers to @code{gnus-demon-handlers} directly, you should
+run @code{gnus-demon-init} to make the changes take hold.  To cancel all
+daemons, you can use the @code{gnus-demon-cancel} function.
+
+Note that adding daemons can be pretty naughty if you over do it.  Adding
+functions that scan all news and mail from all servers every two seconds
+is a sure-fire way of getting booted off any respectable system.  So
+behave.
+
+
+@node Undo
+@section Undo
+@cindex undo
+
+It is very useful to be able to undo actions one has done.  In normal
+Emacs buffers, it's easy enough---you just push the @code{undo} button.
+In Gnus buffers, however, it isn't that simple.
+
+The things Gnus displays in its buffer is of no value whatsoever to
+Gnus---it's all just data designed to look nice to the user.
+Killing a group in the group buffer with @kbd{C-k} makes the line
+disappear, but that's just a side-effect of the real action---the
+removal of the group in question from the internal Gnus structures.
+Undoing something like that can't be done by the normal Emacs
+@code{undo} function.
+
+Gnus tries to remedy this somewhat by keeping track of what the user
+does and coming up with actions that would reverse the actions the user
+takes.  When the user then presses the @code{undo} key, Gnus will run
+the code to reverse the previous action, or the previous actions.
+However, not all actions are easily reversible, so Gnus currently offers
+a few key functions to be undoable.  These include killing groups,
+yanking groups, and changing the list of read articles of groups.
+That's it, really.  More functions may be added in the future, but each
+added function means an increase in data to be stored, so Gnus will
+never be totally undoable.
+
+@findex gnus-undo-mode
+@vindex gnus-use-undo
+@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{C-M-_} key performs the @code{gnus-undo}
+command, which should feel kinda like the normal Emacs @code{undo}
+command.
+
+
+@node Predicate Specifiers
+@section Predicate Specifiers
+@cindex predicate specifiers
+
+Some Gnus variables are @dfn{predicate specifiers}.  This is a special
+form that allows flexible specification of predicates without having
+to type all that much.
+
+These specifiers are lists consisting of functions, symbols and lists.
+
+Here's an example:
+
+@lisp
+(or gnus-article-unseen-p
+    gnus-article-unread-p)
+@end lisp
+
+The available symbols are @code{or}, @code{and} and @code{not}.  The
+functions all take one parameter.
+
+@findex gnus-make-predicate
+Internally, Gnus calls @code{gnus-make-predicate} on these specifiers
+to create a function that can be called.  This input parameter to this
+function will be passed along to all the functions in the predicate
+specifier.
+
+
+@node Moderation
+@section Moderation
+@cindex moderation
+
+If you are a moderator, you can use the @file{gnus-mdrtn.el} package.
+It is not included in the standard Gnus package.  Write a mail to
+@samp{larsi@@gnus.org} and state what group you moderate, and you'll
+get a copy.
+
+The moderation package is implemented as a minor mode for summary
+buffers.  Put
+
+@lisp
+(add-hook 'gnus-summary-mode-hook 'gnus-moderate)
+@end lisp
+
+in your @file{~/.gnus.el} file.
+
+If you are the moderator of @samp{rec.zoofle}, this is how it's
+supposed to work:
+
+@enumerate
+@item
+You split your incoming mail by matching on
+@samp{Newsgroups:.*rec.zoofle}, which will put all the to-be-posted
+articles in some mail group---for instance, @samp{nnml:rec.zoofle}.
+
+@item
+You enter that group once in a while and post articles using the @kbd{e}
+(edit-and-post) or @kbd{s} (just send unedited) commands.
+
+@item
+If, while reading the @samp{rec.zoofle} newsgroup, you happen upon some
+articles that weren't approved by you, you can cancel them with the
+@kbd{c} command.
+@end enumerate
+
+To use moderation mode in these two groups, say:
+
+@lisp
+(setq gnus-moderated-list
+      "^nnml:rec.zoofle$\\|^rec.zoofle$")
+@end lisp
+
+
+@node Fetching a Group
+@section Fetching a Group
+@cindex fetching a group
+
+@findex gnus-fetch-group
+It is sometimes convenient to be able to just say ``I want to read this
+group and I don't care whether Gnus has been started or not''.  This is
+perhaps more useful for people who write code than for users, but the
+command @code{gnus-fetch-group} provides this functionality in any case.
+It takes the group name as a parameter.
+
+
+@node Image Enhancements
+@section Image Enhancements
+
+XEmacs, as well as Emacs 21@footnote{Emacs 21 on MS Windows doesn't
+support images, Emacs 22 does.} and up, are able to display pictures and
+stuff, so Gnus has taken advantage of that.
+
+@menu
+* X-Face::                      Display a funky, teensy black-and-white image.
+* Face::                        Display a funkier, teensier colored image.
+* Smileys::                     Show all those happy faces the way they were meant to be shown.
+* Picons::                      How to display pictures of what you're reading.
+* Gravatars::                   Display the avatar of people you read.
+* XVarious::                    Other XEmacsy Gnusey variables.
+@end menu
+
+
+@node X-Face
+@subsection X-Face
+@cindex x-face
+
+@code{X-Face} headers describe a 48x48 pixel black-and-white (1 bit
+depth) 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
+@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}
+
+Viewing an @code{X-Face} header either requires an Emacs that has
+@samp{compface} support (which most XEmacs versions have), or that you
+have suitable conversion or display programs installed.  If your Emacs
+has image support the default action is to display the face before the
+@code{From} header.  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, see below.  For XEmacs it's
+faster if XEmacs has been compiled with @code{X-Face} support.  The
+default action under Emacs without image support is to fork off the
+@code{display} program.
+
+On a GNU/Linux system, the @code{display} program is included in the
+ImageMagick package.  For external conversion programs look for packages
+with names like @code{netpbm}, @code{libgr-progs} and @code{compface}.
+On Windows, you may use the packages @code{netpbm} and @code{compface}
+from @url{http://gnuwin32.sourceforge.net}.  You need to add the
+@code{bin} directory to your @code{PATH} environment variable.
+@c In fact only the following DLLs and binaries seem to be required:
+@c compface1.dll uncompface.exe libnetpbm10.dll icontopbm.exe
+
+The variable @code{gnus-article-x-face-command} controls which programs
+are used to display the @code{X-Face} header.  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 @code{gnus-article-x-face-too-ugly} (which is a regexp) matches the
+@code{From} header, the face will not be shown.
+
+(Note: @code{x-face} is used in the variable/function names, not
+@code{xface}).
+
+@noindent
+Face and variable:
+
+@table @code
+@item gnus-x-face
+@vindex gnus-x-face
+Face to show X-Face.  The colors from this face are used as the
+foreground and background colors of the displayed X-Faces.  The
+default colors are black and white.
+
+@item gnus-face-properties-alist
+@vindex gnus-face-properties-alist
+Alist of image types and properties applied to Face (@pxref{Face}) and
+X-Face images.  The default value is @code{((pbm . (:face gnus-x-face))
+(png . nil))} for Emacs or @code{((xface . (:face gnus-x-face)))} for
+XEmacs.  Here are examples:
+
+@lisp
+;; Specify the altitude of Face and X-Face images in the From header.
+(setq gnus-face-properties-alist
+      '((pbm . (:face gnus-x-face :ascent 80))
+        (png . (:ascent 80))))
+
+;; Show Face and X-Face images as pressed buttons.
+(setq gnus-face-properties-alist
+      '((pbm . (:face gnus-x-face :relief -2))
+        (png . (:relief -2))))
+@end lisp
+
+@pxref{Image Descriptors, ,Image Descriptors, elisp, The Emacs Lisp
+Reference Manual} for the valid properties for various image types.
+Currently, @code{pbm} is used for X-Face images and @code{png} is used
+for Face images in Emacs.  Only the @code{:face} property is effective
+on the @code{xface} image type in XEmacs if it is built with the
+@samp{libcompface} library.
+@end table
+
+If you use posting styles, you can use an @code{x-face-file} entry in
+@code{gnus-posting-styles}, @xref{Posting Styles}.  If you don't, Gnus
+provides a few convenience functions and variables to allow easier
+insertion of X-Face headers in outgoing messages.  You also need the
+above mentioned ImageMagick, netpbm or other image conversion packages
+(depending the values of the variables below) for these functions.
+
+@findex gnus-random-x-face
+@vindex gnus-convert-pbm-to-x-face-command
+@vindex gnus-x-face-directory
+@code{gnus-random-x-face} goes through all the @samp{pbm} files in
+@code{gnus-x-face-directory} and picks one at random, and then
+converts it to the X-Face format by using the
+@code{gnus-convert-pbm-to-x-face-command} shell command.  The
+@samp{pbm} files should be 48x48 pixels big.  It returns the X-Face
+header data as a string.
+
+@findex gnus-insert-random-x-face-header
+@code{gnus-insert-random-x-face-header} calls
+@code{gnus-random-x-face} and inserts a @samp{X-Face} header with the
+randomly generated data.
+
+@findex gnus-x-face-from-file
+@vindex gnus-convert-image-to-x-face-command
+@code{gnus-x-face-from-file} takes a GIF file as the parameter, and then
+converts the file to X-Face format by using the
+@code{gnus-convert-image-to-x-face-command} shell command.
+
+Here's how you would typically use the first function.  Put something
+like the following in your @file{~/.gnus.el} file:
+
+@lisp
+(setq message-required-news-headers
+      (nconc message-required-news-headers
+             (list '(X-Face . gnus-random-x-face))))
+@end lisp
+
+Using the last function would be something like this:
+
+@lisp
+(setq message-required-news-headers
+      (nconc message-required-news-headers
+             (list '(X-Face . (lambda ()
+                                (gnus-x-face-from-file
+                                 "~/My-face.gif"))))))
+@end lisp
+
+
+@node Face
+@subsection Face
+@cindex face
+
+@c #### FIXME: faces and x-faces' implementations should really be harmonized.
+
+@code{Face} headers are essentially a funkier version of @code{X-Face}
+ones.  They describe a 48x48 pixel colored image that's supposed to
+represent the author of the message.
+
+@cindex face
+@findex gnus-article-display-face
+The contents of a @code{Face} header must be a base64 encoded PNG image.
+See @uref{http://quimby.gnus.org/circus/face/} for the precise
+specifications.
+
+The @code{gnus-face-properties-alist} variable affects the appearance of
+displayed Face images.  @xref{X-Face}.
+
+Viewing a @code{Face} header requires an Emacs that is able to display
+PNG images.
+@c Maybe add this:
+@c (if (featurep 'xemacs)
+@c     (featurep 'png)
+@c   (image-type-available-p 'png))
+
+Gnus provides a few convenience functions and variables to allow
+easier insertion of Face headers in outgoing messages.
+
+@findex gnus-convert-png-to-face
+@code{gnus-convert-png-to-face} takes a 48x48 PNG image, no longer than
+726 bytes long, and converts it to a face.
+
+@findex gnus-face-from-file
+@vindex gnus-convert-image-to-face-command
+@code{gnus-face-from-file} takes a JPEG file as the parameter, and then
+converts the file to Face format by using the
+@code{gnus-convert-image-to-face-command} shell command.
+
+Here's how you would typically use this function.  Put something like the
+following in your @file{~/.gnus.el} file:
+
+@lisp
+(setq message-required-news-headers
+      (nconc message-required-news-headers
+             (list '(Face . (lambda ()
+                              (gnus-face-from-file "~/face.jpg"))))))
+@end lisp
+
+
+@node Smileys
+@subsection Smileys
+@cindex smileys
+
+@iftex
+@iflatex
+\gnusfig{-3cm}{0.5cm}{\epsfig{figure=ps/BigFace,height=20cm}}
+\input{smiley}
+@end iflatex
+@end iftex
+
+@dfn{Smiley} is a package separate from Gnus, but since Gnus is
+currently the only package that uses Smiley, it is documented here.
+
+In short---to use Smiley in Gnus, put the following in your
+@file{~/.gnus.el} file:
+
+@lisp
+(setq gnus-treat-display-smileys t)
+@end lisp
+
+Smiley maps text smiley faces---@samp{:-)}, @samp{8-)}, @samp{:-(} and
+the like---to pictures and displays those instead of the text smiley
+faces.  The conversion is controlled by a list of regexps that matches
+text and maps that to file names.
+
+@vindex smiley-regexp-alist
+The alist used is specified by the @code{smiley-regexp-alist}
+variable.  The first item in each element is the regexp to be matched;
+the second element is the regexp match group that is to be replaced by
+the picture; and the third element is the name of the file to be
+displayed.
+
+The following variables customize the appearance of the smileys:
+
+@table @code
+
+@item smiley-style
+@vindex smiley-style
+Specifies the smiley style.  Predefined smiley styles include
+@code{low-color} (small 13x14 pixel, three-color images), @code{medium}
+(more colorful images, 16x16 pixel), and @code{grayscale} (grayscale
+images, 14x14 pixel).  The default depends on the height of the default
+face.
+
+@item smiley-data-directory
+@vindex smiley-data-directory
+Where Smiley will look for smiley faces files.  You shouldn't set this
+variable anymore.  Customize @code{smiley-style} instead.
+
+@item gnus-smiley-file-types
+@vindex gnus-smiley-file-types
+List of suffixes on smiley file names to try.
+
+@end table
+
+
+@node Picons
+@subsection Picons
+
+@iftex
+@iflatex
+\include{picons}
+@end iflatex
+@end iftex
+
+So@dots{}  You want to slow down your news reader even more!  This is a
+good way to do so.  It's also a great way to impress people staring
+over your shoulder as you read news.
+
+What are Picons?  To quote directly from the Picons Web site:
+
+@iftex
+@iflatex
+\margindex{}
+@end iflatex
+@end iftex
+
+@quotation
+@dfn{Picons} is short for ``personal icons''.  They're small,
+constrained images used to represent users and domains on the net,
+organized into databases so that the appropriate image for a given
+e-mail address can be found.  Besides users and domains, there are picon
+databases for Usenet newsgroups and weather forecasts.  The picons are
+in either monochrome @code{XBM} format or color @code{XPM} and
+@code{GIF} formats.
+@end quotation
+
+@vindex gnus-picon-databases
+For instructions on obtaining and installing the picons databases,
+point your Web browser at
+@uref{http://www.cs.indiana.edu/picons/ftp/index.html}.
+
+If you are using Debian GNU/Linux, saying @samp{apt-get install
+picons.*} will install the picons where Gnus can find them.
+
+To enable displaying picons, simply make sure that
+@code{gnus-picon-databases} points to the directory containing the
+Picons databases.
+
+@vindex gnus-picon-style
+The variable @code{gnus-picon-style} controls how picons are displayed.
+If @code{inline}, the textual representation is replaced.  If
+@code{right}, picons are added right to the textual representation.
+
+@vindex gnus-picon-properties
+The value of the variable @code{gnus-picon-properties} is a list of
+properties applied to picons.
+
+The following variables offer control over where things are located.
+
+@table @code
+
+@item gnus-picon-databases
+@vindex gnus-picon-databases
+The location of the picons database.  This is a list of directories
+containing the @file{news}, @file{domains}, @file{users} (and so on)
+subdirectories.  Defaults to @code{("/usr/lib/picon"
+"/usr/local/faces")}.
+
+@item gnus-picon-news-directories
+@vindex gnus-picon-news-directories
+List of subdirectories to search in @code{gnus-picon-databases} for
+newsgroups faces.  @code{("news")} is the default.
+
+@item gnus-picon-user-directories
+@vindex gnus-picon-user-directories
+List of subdirectories to search in @code{gnus-picon-databases} for user
+faces.  @code{("users" "usenix" "local" "misc")} is the default.
+
+@item gnus-picon-domain-directories
+@vindex gnus-picon-domain-directories
+List of subdirectories to search in @code{gnus-picon-databases} for
+domain name faces.  Defaults to @code{("domains")}.  Some people may
+want to add @samp{"unknown"} to this list.
+
+@item gnus-picon-file-types
+@vindex gnus-picon-file-types
+Ordered list of suffixes on picon file names to try.  Defaults to
+@code{("xpm" "gif" "xbm")} minus those not built-in your Emacs.
+
+@item gnus-picon-inhibit-top-level-domains
+@vindex gnus-picon-inhibit-top-level-domains
+If non-@code{nil} (which is the default), don't display picons for
+things like @samp{.net} and @samp{.de}, which aren't usually very
+interesting.
+
+@end table
+
+@node Gravatars
+@subsection Gravatars
+
+@iftex
+@iflatex
+\include{gravatars}
+@end iflatex
+@end iftex
+
+A gravatar is an image registered to an e-mail address.
+
+You can submit yours on-line at @uref{http://www.gravatar.com}.
+
+The following variables offer control over how things are displayed.
+
+@table @code
+
+@item gnus-gravatar-size
+@vindex gnus-gravatar-size
+The size in pixels of gravatars.  Gravatars are always square, so one
+number for the size is enough.
+
+@item gnus-gravatar-properties
+@vindex gnus-gravatar-properties
+List of image properties applied to Gravatar images.
+
+@item gnus-gravatar-too-ugly
+@vindex gnus-gravatar-too-ugly
+Regexp that matches mail addresses or names of people of which avatars
+should not be displayed, or @code{nil}.  It default to the value of
+@code{gnus-article-x-face-too-ugly} (@pxref{X-Face}).
+
+@end table
+
+If you want to see them in the From field, set:
+@lisp
+(setq gnus-treat-from-gravatar 'head)
+@end lisp
+
+If you want to see them in the Cc and To fields, set:
+
+@lisp
+(setq gnus-treat-mail-gravatar 'head)
+@end lisp
+
+
+@node XVarious
+@subsection Various XEmacs Variables
+
+@table @code
+@item gnus-xmas-glyph-directory
+@vindex gnus-xmas-glyph-directory
+This is where Gnus will look for pictures.  Gnus will normally
+auto-detect this directory, but you may set it manually if you have an
+unusual directory structure.
+
+@item gnus-xmas-modeline-glyph
+@vindex gnus-xmas-modeline-glyph
+A glyph displayed in all Gnus mode lines.  It is a tiny gnu head by
+default.
+
+@end table
+
+@subsubsection Toolbar
+
+@table @code
+
+@item gnus-use-toolbar
+@vindex gnus-use-toolbar
+This variable specifies the position to display the toolbar.  If
+@code{nil}, don't display toolbars.  If it is non-@code{nil}, it should
+be one of the symbols @code{default}, @code{top}, @code{bottom},
+@code{right}, and @code{left}.  @code{default} means to use the default
+toolbar, the rest mean to display the toolbar on the place which those
+names show.  The default is @code{default}.
+
+@item gnus-toolbar-thickness
+@vindex gnus-toolbar-thickness
+Cons of the height and the width specifying the thickness of a toolbar.
+The height is used for the toolbar displayed on the top or the bottom,
+the width is used for the toolbar displayed on the right or the left.
+The default is that of the default toolbar.
+
+@item gnus-group-toolbar
+@vindex gnus-group-toolbar
+The toolbar in the group buffer.
+
+@item gnus-summary-toolbar
+@vindex gnus-summary-toolbar
+The toolbar in the summary buffer.
+
+@item gnus-summary-mail-toolbar
+@vindex gnus-summary-mail-toolbar
+The toolbar in the summary buffer of mail groups.
+
+@end table
+
+@iftex
+@iflatex
+\margindex{}
+@end iflatex
+@end iftex
+
+
+@node Fuzzy Matching
+@section Fuzzy Matching
+@cindex fuzzy matching
+
+Gnus provides @dfn{fuzzy matching} of @code{Subject} lines when doing
+things like scoring, thread gathering and thread comparison.
+
+As opposed to regular expression matching, fuzzy matching is very fuzzy.
+It's so fuzzy that there's not even a definition of what @dfn{fuzziness}
+means, and the implementation has changed over time.
+
+Basically, it tries to remove all noise from lines before comparing.
+@samp{Re: }, parenthetical remarks, white space, and so on, are filtered
+out of the strings before comparing the results.  This often leads to
+adequate results---even when faced with strings generated by text
+manglers masquerading as newsreaders.
+
+
+@node Thwarting Email Spam
+@section Thwarting Email Spam
+@cindex email spam
+@cindex spam
+@cindex UCE
+@cindex unsolicited commercial email
+
+In these last days of the Usenet, commercial vultures are hanging about
+and grepping through news like crazy to find email addresses they can
+foist off their scams and products to.  As a reaction to this, many
+people have started putting nonsense addresses into their @code{From}
+lines.  I think this is counterproductive---it makes it difficult for
+people to send you legitimate mail in response to things you write, as
+well as making it difficult to see who wrote what.  This rewriting may
+perhaps be a bigger menace than the unsolicited commercial email itself
+in the end.
+
+The biggest problem I have with email spam is that it comes in under
+false pretenses.  I press @kbd{g} and Gnus merrily informs me that I
+have 10 new emails.  I say ``Golly gee!  Happy is me!'' and select the
+mail group, only to find two pyramid schemes, seven advertisements
+(``New!  Miracle tonic for growing full, lustrous hair on your toes!'')
+and one mail asking me to repent and find some god.
+
+This is annoying.  Here's what you can do about it.
+
+@menu
+* The problem of spam::         Some background, and some solutions
+* Anti-Spam Basics::            Simple steps to reduce the amount of spam.
+* SpamAssassin::                How to use external anti-spam tools.
+* Hashcash::                    Reduce spam by burning CPU time.
+@end menu
+
+@node The problem of spam
+@subsection The problem of spam
+@cindex email spam
+@cindex spam filtering approaches
+@cindex filtering approaches, spam
+@cindex UCE
+@cindex unsolicited commercial email
+
+First, some background on spam.
+
+If you have access to e-mail, you are familiar with spam (technically
+termed @acronym{UCE}, Unsolicited Commercial E-mail).  Simply put, it
+exists because e-mail delivery is very cheap compared to paper mail,
+so only a very small percentage of people need to respond to an UCE to
+make it worthwhile to the advertiser.  Ironically, one of the most
+common spams is the one offering a database of e-mail addresses for
+further spamming.  Senders of spam are usually called @emph{spammers},
+but terms like @emph{vermin}, @emph{scum}, @emph{sociopaths}, and
+@emph{morons} are in common use as well.
+
+Spam comes from a wide variety of sources.  It is simply impossible to
+dispose of all spam without discarding useful messages.  A good
+example is the TMDA system, which requires senders
+unknown to you to confirm themselves as legitimate senders before
+their e-mail can reach you.  Without getting into the technical side
+of TMDA, a downside is clearly that e-mail from legitimate sources may
+be discarded if those sources can't or won't confirm themselves
+through the TMDA system.  Another problem with TMDA is that it
+requires its users to have a basic understanding of e-mail delivery
+and processing.
+
+The simplest approach to filtering spam is filtering, at the mail
+server or when you sort through incoming mail.  If you get 200 spam
+messages per day from @samp{random-address@@vmadmin.com}, you block
+@samp{vmadmin.com}.  If you get 200 messages about @samp{VIAGRA}, you
+discard all messages with @samp{VIAGRA} in the message.  If you get
+lots of spam from Bulgaria, for example, you try to filter all mail
+from Bulgarian IPs.
+
+This, unfortunately, is a great way to discard legitimate e-mail.  The
+risks of blocking a whole country (Bulgaria, Norway, Nigeria, China,
+etc.)@: or even a continent (Asia, Africa, Europe, etc.)@: from contacting
+you should be obvious, so don't do it if you have the choice.
+
+In another instance, the very informative and useful RISKS digest has
+been blocked by overzealous mail filters because it @strong{contained}
+words that were common in spam messages.  Nevertheless, in isolated
+cases, with great care, direct filtering of mail can be useful.
+
+Another approach to filtering e-mail is the distributed spam
+processing, for instance DCC implements such a system.  In essence,
+@var{N} systems around the world agree that a machine @var{X} in
+Ghana, Estonia, or California is sending out spam e-mail, and these
+@var{N} systems enter @var{X} or the spam e-mail from @var{X} into a
+database.  The criteria for spam detection vary---it may be the number
+of messages sent, the content of the messages, and so on.  When a user
+of the distributed processing system wants to find out if a message is
+spam, he consults one of those @var{N} systems.
+
+Distributed spam processing works very well against spammers that send
+a large number of messages at once, but it requires the user to set up
+fairly complicated checks.  There are commercial and free distributed
+spam processing systems.  Distributed spam processing has its risks as
+well.  For instance legitimate e-mail senders have been accused of
+sending spam, and their web sites and mailing lists have been shut
+down for some time because of the incident.
+
+The statistical approach to spam filtering is also popular.  It is
+based on a statistical analysis of previous spam messages.  Usually
+the analysis is a simple word frequency count, with perhaps pairs of
+words or 3-word combinations thrown into the mix.  Statistical
+analysis of spam works very well in most of the cases, but it can
+classify legitimate e-mail as spam in some cases.  It takes time to
+run the analysis, the full message must be analyzed, and the user has
+to store the database of spam analysis.  Statistical analysis on the
+server is gaining popularity.  This has the advantage of letting the
+user Just Read Mail, but has the disadvantage that it's harder to tell
+the server that it has misclassified mail.
+
+Fighting spam is not easy, no matter what anyone says.  There is no
+magic switch that will distinguish Viagra ads from Mom's e-mails.
+Even people are having a hard time telling spam apart from non-spam,
+because spammers are actively looking to fool us into thinking they
+are Mom, essentially.  Spamming is irritating, irresponsible, and
+idiotic behavior from a bunch of people who think the world owes them
+a favor.  We hope the following sections will help you in fighting the
+spam plague.
+
+@node Anti-Spam Basics
+@subsection Anti-Spam Basics
+@cindex email spam
+@cindex spam
+@cindex UCE
+@cindex unsolicited commercial email
+
+One way of dealing with spam is having Gnus split out all spam into a
+@samp{spam} mail group (@pxref{Splitting Mail}).
+
+First, pick one (1) valid mail address that you can be reached at, and
+put it in your @code{From} header of all your news articles.  (I've
+chosen @samp{larsi@@trym.ifi.uio.no}, but for many addresses on the form
+@samp{larsi+usenet@@ifi.uio.no} will be a better choice.  Ask your
+sysadmin whether your sendmail installation accepts keywords in the local
+part of the mail address.)
+
+@lisp
+(setq message-default-news-headers
+      "From: Lars Magne Ingebrigtsen <larsi@@trym.ifi.uio.no>\n")
+@end lisp
+
+Then put the following split rule in @code{nnmail-split-fancy}
+(@pxref{Fancy Mail Splitting}):
+
+@lisp
+(...
+ (to "larsi@@trym.ifi.uio.no"
+     (| ("subject" "re:.*" "misc")
+        ("references" ".*@@.*" "misc")
+        "spam"))
+ ...)
+@end lisp
+
+This says that all mail to this address is suspect, but if it has a
+@code{Subject} that starts with a @samp{Re:} or has a @code{References}
+header, it's probably ok.  All the rest goes to the @samp{spam} group.
+(This idea probably comes from Tim Pierce.)
+
+In addition, many mail spammers talk directly to your @acronym{SMTP} server
+and do not include your email address explicitly in the @code{To}
+header.  Why they do this is unknown---perhaps it's to thwart this
+thwarting scheme?  In any case, this is trivial to deal with---you just
+put anything not addressed to you in the @samp{spam} group by ending
+your fancy split rule in this way:
+
+@lisp
+(
+ ...
+ (to "larsi" "misc")
+ "spam")
+@end lisp
+
+In my experience, this will sort virtually everything into the right
+group.  You still have to check the @samp{spam} group from time to time to
+check for legitimate mail, though.  If you feel like being a good net
+citizen, you can even send off complaints to the proper authorities on
+each unsolicited commercial email---at your leisure.
+
+This works for me.  It allows people an easy way to contact me (they can
+just press @kbd{r} in the usual way), and I'm not bothered at all with
+spam.  It's a win-win situation.  Forging @code{From} headers to point
+to non-existent domains is yucky, in my opinion.
+
+Be careful with this approach.  Spammers are wise to it.
+
+
+@node SpamAssassin
+@subsection SpamAssassin, Vipul's Razor, DCC, etc
+@cindex SpamAssassin
+@cindex Vipul's Razor
+@cindex DCC
+
+The days where the hints in the previous section were sufficient in
+avoiding spam are coming to an end.  There are many tools out there
+that claim to reduce the amount of spam you get.  This section could
+easily become outdated fast, as new products replace old, but
+fortunately most of these tools seem to have similar interfaces.  Even
+though this section will use SpamAssassin as an example, it should be
+easy to adapt it to most other tools.
+
+Note that this section does not involve the @code{spam.el} package,
+which is discussed in the next section.  If you don't care for all
+the features of @code{spam.el}, you can make do with these simple
+recipes.
+
+If the tool you are using is not installed on the mail server, you
+need to invoke it yourself.  Ideas on how to use the
+@code{:postscript} mail source parameter (@pxref{Mail Source
+Specifiers}) follow.
+
+@lisp
+(setq mail-sources
+      '((file :prescript "formail -bs spamassassin < /var/mail/%u")
+        (pop :user "jrl"
+             :server "pophost"
+             :postscript
+             "mv %t /tmp/foo; formail -bs spamc < /tmp/foo > %t")))
+@end lisp
+
+Once you manage to process your incoming spool somehow, thus making
+the mail contain, e.g., a header indicating it is spam, you are ready to
+filter it out.  Using normal split methods (@pxref{Splitting Mail}):
+
+@lisp
+(setq nnmail-split-methods '(("spam"  "^X-Spam-Flag: YES")
+                             ...))
+@end lisp
+
+Or using fancy split methods (@pxref{Fancy Mail Splitting}):
+
+@lisp
+(setq nnmail-split-methods 'nnmail-split-fancy
+      nnmail-split-fancy '(| ("X-Spam-Flag" "YES" "spam")
+                             ...))
+@end lisp
+
+Some people might not like the idea of piping the mail through various
+programs using a @code{:prescript} (if some program is buggy, you
+might lose all mail).  If you are one of them, another solution is to
+call the external tools during splitting.  Example fancy split method:
+
+@lisp
+(setq nnmail-split-fancy '(| (: kevin-spamassassin)
+                             ...))
+(defun kevin-spamassassin ()
+  (save-excursion
+    (save-restriction
+      (widen)
+      (if (eq 1 (call-process-region (point-min) (point-max)
+                                     "spamc" nil nil nil "-c"))
+          "spam"))))
+@end lisp
+
+Note that with the nnimap back end, message bodies will not be
+downloaded by default.  You need to set
+@code{nnimap-split-download-body} to @code{t} to do that
+(@pxref{Client-Side IMAP Splitting}).
+
+That is about it.  As some spam is likely to get through anyway, you
+might want to have a nifty function to call when you happen to read
+spam.  And here is the nifty function:
+
+@lisp
+(defun my-gnus-raze-spam ()
+  "Submit SPAM to Vipul's Razor, then mark it as expirable."
+  (interactive)
+  (gnus-summary-save-in-pipe "razor-report -f -d" t)
+  (gnus-summary-mark-as-expirable 1))
+@end lisp
+
+@node Hashcash
+@subsection Hashcash
+@cindex hashcash
+
+A novel technique to fight spam is to require senders to do something
+costly and demonstrably unique for each message they send.  This has
+the obvious drawback that you cannot rely on everyone in the world
+using this technique, since it is not part of the Internet standards,
+but it may be useful in smaller communities.
+
+While the tools in the previous section work well in practice, they
+work only because the tools are constantly maintained and updated as
+new form of spam appears.  This means that a small percentage of spam
+will always get through.  It also means that somewhere, someone needs
+to read lots of spam to update these tools.  Hashcash avoids that, but
+instead prefers that everyone you contact through e-mail supports the
+scheme.  You can view the two approaches as pragmatic vs dogmatic.
+The approaches have their own advantages and disadvantages, but as
+often in the real world, a combination of them is stronger than either
+one of them separately.
+
+@cindex X-Hashcash
+The ``something costly'' is to burn CPU time, more specifically to
+compute a hash collision up to a certain number of bits.  The
+resulting hashcash cookie is inserted in a @samp{X-Hashcash:} header.
+For more details, and for the external application @code{hashcash} you
+need to install to use this feature, see
+@uref{http://www.hashcash.org/}.  Even more information can be found
+at @uref{http://www.camram.org/}.
+
+If you wish to generate hashcash for each message you send, you can
+customize @code{message-generate-hashcash} (@pxref{Mail Headers, ,Mail
+Headers,message, The Message Manual}), as in:
+
+@lisp
+(setq message-generate-hashcash t)
+@end lisp
+
+You will need to set up some additional variables as well:
+
+@table @code
+
+@item hashcash-default-payment
+@vindex hashcash-default-payment
+This variable indicates the default number of bits the hash collision
+should consist of.  By default this is 20.  Suggested useful values
+include 17 to 29.
+
+@item hashcash-payment-alist
+@vindex hashcash-payment-alist
+Some receivers may require you to spend burn more CPU time than the
+default.  This variable contains a list of @samp{(@var{addr}
+@var{amount})} cells, where @var{addr} is the receiver (email address
+or newsgroup) and @var{amount} is the number of bits in the collision
+that is needed.  It can also contain @samp{(@var{addr} @var{string}
+@var{amount})} cells, where the @var{string} is the string to use
+(normally the email address or newsgroup name is used).
+
+@item hashcash-path
+@vindex hashcash-path
+Where the @code{hashcash} binary is installed.  This variable should
+be automatically set by @code{executable-find}, but if it's @code{nil}
+(usually because the @code{hashcash} binary is not in your path)
+you'll get a warning when you check hashcash payments and an error
+when you generate hashcash payments.
+
+@end table
+
+Gnus can verify hashcash cookies, although this can also be done by
+hand customized mail filtering scripts.  To verify a hashcash cookie
+in a message, use the @code{mail-check-payment} function in the
+@code{hashcash.el} library.  You can also use the @code{spam.el}
+package with the @code{spam-use-hashcash} back end to validate hashcash
+cookies in incoming mail and filter mail accordingly (@pxref{Anti-spam
+Hashcash Payments}).
+
+@node Spam Package
+@section Spam Package
+@cindex spam filtering
+@cindex spam
+
+The Spam package provides Gnus with a centralized mechanism for
+detecting and filtering spam.  It filters new mail, and processes
+messages according to whether they are spam or ham.  (@dfn{Ham} is the
+name used throughout this manual to indicate non-spam messages.)
+
+@menu
+* Spam Package Introduction::
+* Filtering Incoming Mail::
+* Detecting Spam in Groups::
+* Spam and Ham Processors::
+* Spam Package Configuration Examples::
+* Spam Back Ends::
+* Extending the Spam package::
+* Spam Statistics Package::
+@end menu
+
+@node Spam Package Introduction
+@subsection Spam Package Introduction
+@cindex spam filtering
+@cindex spam filtering sequence of events
+@cindex spam
+
+You must read this section to understand how the Spam package works.
+Do not skip, speed-read, or glance through this section.
+
+Make sure you read the section on the @code{spam.el} sequence of
+events.  See @xref{Extending the Spam package}.
+
+@cindex spam-initialize
+@vindex spam-use-stat
+To use the Spam package, you @strong{must} first run the function
+@code{spam-initialize}:
+
+@example
+(spam-initialize)
+@end example
+
+This autoloads @code{spam.el} and installs the various hooks necessary
+to let the Spam package do its job.  In order to make use of the Spam
+package, you have to set up certain group parameters and variables,
+which we will describe below.  All of the variables controlling the
+Spam package can be found in the @samp{spam} customization group.
+
+There are two ``contact points'' between the Spam package and the rest
+of Gnus: checking new mail for spam, and leaving a group.
+
+Checking new mail for spam is done in one of two ways: while splitting
+incoming mail, or when you enter a group.
+
+The first way, checking for spam while splitting incoming mail, is
+suited to mail back ends such as @code{nnml} or @code{nnimap}, where
+new mail appears in a single spool file.  The Spam package processes
+incoming mail, and sends mail considered to be spam to a designated
+``spam'' group.  @xref{Filtering Incoming Mail}.
+
+The second way is suited to back ends such as @code{nntp}, which have
+no incoming mail spool, or back ends where the server is in charge of
+splitting incoming mail.  In this case, when you enter a Gnus group,
+the unseen or unread messages in that group are checked for spam.
+Detected spam messages are marked as spam.  @xref{Detecting Spam in
+Groups}.
+
+@cindex spam back ends
+In either case, you have to tell the Spam package what method to use
+to detect spam messages.  There are several methods, or @dfn{spam back
+ends} (not to be confused with Gnus back ends!) to choose from: spam
+``blacklists'' and ``whitelists'', dictionary-based filters, and so
+forth.  @xref{Spam Back Ends}.
+
+In the Gnus summary buffer, messages that have been identified as spam
+always appear with a @samp{$} symbol.
+
+The Spam package divides Gnus groups into three categories: ham
+groups, spam groups, and unclassified groups.  You should mark each of
+the groups you subscribe to as either a ham group or a spam group,
+using the @code{spam-contents} group parameter (@pxref{Group
+Parameters}).  Spam groups have a special property: when you enter a
+spam group, all unseen articles are marked as spam.  Thus, mail split
+into a spam group is automatically marked as spam.
+
+Identifying spam messages is only half of the Spam package's job.  The
+second half comes into play whenever you exit a group buffer.  At this
+point, the Spam package does several things:
+
+First, it calls @dfn{spam and ham processors} to process the articles
+according to whether they are spam or ham.  There is a pair of spam
+and ham processors associated with each spam back end, and what the
+processors do depends on the back end.  At present, the main role of
+spam and ham processors is for dictionary-based spam filters: they add
+the contents of the messages in the group to the filter's dictionary,
+to improve its ability to detect future spam.  The @code{spam-process}
+group parameter specifies what spam processors to use.  @xref{Spam and
+Ham Processors}.
+
+If the spam filter failed to mark a spam message, you can mark it
+yourself, so that the message is processed as spam when you exit the
+group:
+
+@table @kbd
+@item $
+@itemx M-d
+@itemx M s x
+@itemx S x
+@kindex $ (Summary)
+@kindex M-d (Summary)
+@kindex S x (Summary)
+@kindex M s x (Summary)
+@findex gnus-summary-mark-as-spam
+@findex gnus-summary-mark-as-spam
+Mark current article as spam, showing it with the @samp{$} mark
+(@code{gnus-summary-mark-as-spam}).
+@end table
+
+@noindent
+Similarly, you can unmark an article if it has been erroneously marked
+as spam.  @xref{Setting Marks}.
+
+Normally, a ham message found in a non-ham group is not processed as
+ham---the rationale is that it should be moved into a ham group for
+further processing (see below).  However, you can force these articles
+to be processed as ham by setting
+@code{spam-process-ham-in-spam-groups} and
+@code{spam-process-ham-in-nonham-groups}.
+
+@vindex gnus-ham-process-destinations
+@vindex gnus-spam-process-destinations
+The second thing that the Spam package does when you exit a group is
+to move ham articles out of spam groups, and spam articles out of ham
+groups.  Ham in a spam group is moved to the group specified by the
+variable @code{gnus-ham-process-destinations}, or the group parameter
+@code{ham-process-destination}.  Spam in a ham group is moved to the
+group specified by the variable @code{gnus-spam-process-destinations},
+or the group parameter @code{spam-process-destination}.  If these
+variables are not set, the articles are left in their current group.
+If an article cannot be moved (e.g., with a read-only backend such
+as @acronym{NNTP}), it is copied.
+
+If an article is moved to another group, it is processed again when
+you visit the new group.  Normally, this is not a problem, but if you
+want each article to be processed only once, load the
+@code{gnus-registry.el} package and set the variable
+@code{spam-log-to-registry} to @code{t}.  @xref{Spam Package
+Configuration Examples}.
+
+Normally, spam groups ignore @code{gnus-spam-process-destinations}.
+However, if you set @code{spam-move-spam-nonspam-groups-only} to
+@code{nil}, spam will also be moved out of spam groups, depending on
+the @code{spam-process-destination} parameter.
+
+The final thing the Spam package does is to mark spam articles as
+expired, which is usually the right thing to do.
+
+If all this seems confusing, don't worry.  Soon it will be as natural
+as typing Lisp one-liners on a neural interface@dots{} err, sorry, that's
+50 years in the future yet.  Just trust us, it's not so bad.
+
+@node Filtering Incoming Mail
+@subsection Filtering Incoming Mail
+@cindex spam filtering
+@cindex spam filtering incoming mail
+@cindex spam
+
+To use the Spam package to filter incoming mail, you must first set up
+fancy mail splitting.  @xref{Fancy Mail Splitting}.  The Spam package
+defines a special splitting function that you can add to your fancy
+split variable (either @code{nnmail-split-fancy} or
+@code{nnimap-split-fancy}, depending on your mail back end):
+
+@example
+(: spam-split)
+@end example
+
+@vindex spam-split-group
+@noindent
+The @code{spam-split} function scans incoming mail according to your
+chosen spam back end(s), and sends messages identified as spam to a
+spam group.  By default, the spam group is a group named @samp{spam},
+but you can change this by customizing @code{spam-split-group}.  Make
+sure the contents of @code{spam-split-group} are an unqualified group
+name.  For instance, in an @code{nnimap} server @samp{your-server},
+the value @samp{spam} means @samp{nnimap+your-server:spam}.  The value
+@samp{nnimap+server:spam} is therefore wrong---it gives the group
+@samp{nnimap+your-server:nnimap+server:spam}.
+
+@code{spam-split} does not modify the contents of messages in any way.
+
+@vindex nnimap-split-download-body
+Note for IMAP users: if you use the @code{spam-check-bogofilter},
+@code{spam-check-ifile}, and @code{spam-check-stat} spam back ends,
+you should also set the variable @code{nnimap-split-download-body} to
+@code{t}.  These spam back ends are most useful when they can ``scan''
+the full message body.  By default, the nnimap back end only retrieves
+the message headers; @code{nnimap-split-download-body} tells it to
+retrieve the message bodies as well.  We don't set this by default
+because it will slow @acronym{IMAP} down, and that is not an
+appropriate decision to make on behalf of the user.  @xref{Client-Side
+IMAP Splitting}.
+
+You have to specify one or more spam back ends for @code{spam-split}
+to use, by setting the @code{spam-use-*} variables.  @xref{Spam Back
+Ends}.  Normally, @code{spam-split} simply uses all the spam back ends
+you enabled in this way.  However, you can tell @code{spam-split} to
+use only some of them.  Why this is useful?  Suppose you are using the
+@code{spam-use-regex-headers} and @code{spam-use-blackholes} spam back
+ends, and the following split rule:
+
+@example
+ nnimap-split-fancy '(|
+                      (any "ding" "ding")
+                      (: spam-split)
+                      ;; @r{default mailbox}
+                      "mail")
+@end example
+
+@noindent
+The problem is that you want all ding messages to make it to the ding
+folder.  But that will let obvious spam (for example, spam detected by
+SpamAssassin, and @code{spam-use-regex-headers}) through, when it's
+sent to the ding list.  On the other hand, some messages to the ding
+list are from a mail server in the blackhole list, so the invocation
+of @code{spam-split} can't be before the ding rule.
+
+The solution is to let SpamAssassin headers supersede ding rules, and
+perform the other @code{spam-split} rules (including a second
+invocation of the regex-headers check) after the ding rule.  This is
+done by passing a parameter to @code{spam-split}:
+
+@example
+nnimap-split-fancy
+      '(|
+        ;; @r{spam detected by @code{spam-use-regex-headers} goes to @samp{regex-spam}}
+        (: spam-split "regex-spam" 'spam-use-regex-headers)
+        (any "ding" "ding")
+        ;; @r{all other spam detected by spam-split goes to @code{spam-split-group}}
+        (: spam-split)
+        ;; @r{default mailbox}
+        "mail")
+@end example
+
+@noindent
+This lets you invoke specific @code{spam-split} checks depending on
+your particular needs, and target the results of those checks to a
+particular spam group.  You don't have to throw all mail into all the
+spam tests.  Another reason why this is nice is that messages to
+mailing lists you have rules for don't have to have resource-intensive
+blackhole checks performed on them.  You could also specify different
+spam checks for your nnmail split vs. your nnimap split.  Go crazy.
+
+You should set the @code{spam-use-*} variables for whatever spam back
+ends you intend to use.  The reason is that when loading
+@file{spam.el}, some conditional loading is done depending on what
+@code{spam-use-xyz} variables you have set.  @xref{Spam Back Ends}.
+
+@c @emph{TODO: spam.el needs to provide a uniform way of training all the
+@c statistical databases.  Some have that functionality built-in, others
+@c don't.}
+
+@node Detecting Spam in Groups
+@subsection Detecting Spam in Groups
+
+To detect spam when visiting a group, set the group's
+@code{spam-autodetect} and @code{spam-autodetect-methods} group
+parameters.  These are accessible with @kbd{G c} or @kbd{G p}, as
+usual (@pxref{Group Parameters}).
+
+You should set the @code{spam-use-*} variables for whatever spam back
+ends you intend to use.  The reason is that when loading
+@file{spam.el}, some conditional loading is done depending on what
+@code{spam-use-xyz} variables you have set.
+
+By default, only unseen articles are processed for spam.  You can
+force Gnus to recheck all messages in the group by setting the
+variable @code{spam-autodetect-recheck-messages} to @code{t}.
+
+If you use the @code{spam-autodetect} method of checking for spam, you
+can specify different spam detection methods for different groups.
+For instance, the @samp{ding} group may have @code{spam-use-BBDB} as
+the autodetection method, while the @samp{suspect} group may have the
+@code{spam-use-blacklist} and @code{spam-use-bogofilter} methods
+enabled.  Unlike with @code{spam-split}, you don't have any control
+over the @emph{sequence} of checks, but this is probably unimportant.
+
+@node Spam and Ham Processors
+@subsection Spam and Ham Processors
+@cindex spam filtering
+@cindex spam filtering variables
+@cindex spam variables
+@cindex spam
+
+@vindex gnus-spam-process-newsgroups
+Spam and ham processors specify special actions to take when you exit
+a group buffer.  Spam processors act on spam messages, and ham
+processors on ham messages.  At present, the main role of these
+processors is to update the dictionaries of dictionary-based spam back
+ends such as Bogofilter (@pxref{Bogofilter}) and the Spam Statistics
+package (@pxref{Spam Statistics Filtering}).
+
+The spam and ham processors that apply to each group are determined by
+the group's@code{spam-process} group parameter.  If this group
+parameter is not defined, they are determined by the variable
+@code{gnus-spam-process-newsgroups}.
+
+@vindex gnus-spam-newsgroup-contents
+Gnus learns from the spam you get.  You have to collect your spam in
+one or more spam groups, and set or customize the variable
+@code{spam-junk-mailgroups} as appropriate.  You can also declare
+groups to contain spam by setting their group parameter
+@code{spam-contents} to @code{gnus-group-spam-classification-spam}, or
+by customizing the corresponding variable
+@code{gnus-spam-newsgroup-contents}.  The @code{spam-contents} group
+parameter and the @code{gnus-spam-newsgroup-contents} variable can
+also be used to declare groups as @emph{ham} groups if you set their
+classification to @code{gnus-group-spam-classification-ham}.  If
+groups are not classified by means of @code{spam-junk-mailgroups},
+@code{spam-contents}, or @code{gnus-spam-newsgroup-contents}, they are
+considered @emph{unclassified}.  All groups are unclassified by
+default.
+
+@vindex gnus-spam-mark
+@cindex $
+In spam groups, all messages are considered to be spam by default:
+they get the @samp{$} mark (@code{gnus-spam-mark}) when you enter the
+group.  If you have seen a message, had it marked as spam, then
+unmarked it, it won't be marked as spam when you enter the group
+thereafter.  You can disable that behavior, so all unread messages
+will get the @samp{$} mark, if you set the
+@code{spam-mark-only-unseen-as-spam} parameter to @code{nil}.  You
+should remove the @samp{$} mark when you are in the group summary
+buffer for every message that is not spam after all.  To remove the
+@samp{$} mark, you can use @kbd{M-u} to ``unread'' the article, or
+@kbd{d} for declaring it read the non-spam way.  When you leave a
+group, all spam-marked (@samp{$}) articles are sent to a spam
+processor which will study them as spam samples.
+
+Messages may also be deleted in various other ways, and unless
+@code{ham-marks} group parameter gets overridden below, marks @samp{R}
+and @samp{r} for default read or explicit delete, marks @samp{X} and
+@samp{K} for automatic or explicit kills, as well as mark @samp{Y} for
+low scores, are all considered to be associated with articles which
+are not spam.  This assumption might be false, in particular if you
+use kill files or score files as means for detecting genuine spam, you
+should then adjust the @code{ham-marks} group parameter.
+
+@defvar ham-marks
+You can customize this group or topic parameter to be the list of
+marks you want to consider ham.  By default, the list contains the
+deleted, read, killed, kill-filed, and low-score marks (the idea is
+that these articles have been read, but are not spam).  It can be
+useful to also include the tick mark in the ham marks.  It is not
+recommended to make the unread mark a ham mark, because it normally
+indicates a lack of classification.  But you can do it, and we'll be
+happy for you.
+@end defvar
+
+@defvar spam-marks
+You can customize this group or topic parameter to be the list of
+marks you want to consider spam.  By default, the list contains only
+the spam mark.  It is not recommended to change that, but you can if
+you really want to.
+@end defvar
+
+When you leave @emph{any} group, regardless of its
+@code{spam-contents} classification, all spam-marked articles are sent
+to a spam processor, which will study these as spam samples.  If you
+explicit kill a lot, you might sometimes end up with articles marked
+@samp{K} which you never saw, and which might accidentally contain
+spam.  Best is to make sure that real spam is marked with @samp{$},
+and nothing else.
+
+@vindex gnus-ham-process-destinations
+When you leave a @emph{spam} group, all spam-marked articles are
+marked as expired after processing with the spam processor.  This is
+not done for @emph{unclassified} or @emph{ham} groups.  Also, any
+@strong{ham} articles in a spam group will be moved to a location
+determined by either the @code{ham-process-destination} group
+parameter or a match in the @code{gnus-ham-process-destinations}
+variable, which is a list of regular expressions matched with group
+names (it's easiest to customize this variable with @kbd{M-x
+customize-variable @key{RET} gnus-ham-process-destinations}).  Each
+group name list is a standard Lisp list, if you prefer to customize
+the variable manually.  If the @code{ham-process-destination}
+parameter is not set, ham articles are left in place.  If the
+@code{spam-mark-ham-unread-before-move-from-spam-group} parameter is
+set, the ham articles are marked as unread before being moved.
+
+If ham can not be moved---because of a read-only back end such as
+@acronym{NNTP}, for example, it will be copied.
+
+Note that you can use multiples destinations per group or regular
+expression!  This enables you to send your ham to a regular mail
+group and to a @emph{ham training} group.
+
+When you leave a @emph{ham} group, all ham-marked articles are sent to
+a ham processor, which will study these as non-spam samples.
+
+@vindex spam-process-ham-in-spam-groups
+By default the variable @code{spam-process-ham-in-spam-groups} is
+@code{nil}.  Set it to @code{t} if you want ham found in spam groups
+to be processed.  Normally this is not done, you are expected instead
+to send your ham to a ham group and process it there.
+
+@vindex spam-process-ham-in-nonham-groups
+By default the variable @code{spam-process-ham-in-nonham-groups} is
+@code{nil}.  Set it to @code{t} if you want ham found in non-ham (spam
+or unclassified) groups to be processed.  Normally this is not done,
+you are expected instead to send your ham to a ham group and process
+it there.
+
+@vindex gnus-spam-process-destinations
+When you leave a @emph{ham} or @emph{unclassified} group, all
+@strong{spam} articles are moved to a location determined by either
+the @code{spam-process-destination} group parameter or a match in the
+@code{gnus-spam-process-destinations} variable, which is a list of
+regular expressions matched with group names (it's easiest to
+customize this variable with @kbd{M-x customize-variable @key{RET}
+gnus-spam-process-destinations}).  Each group name list is a standard
+Lisp list, if you prefer to customize the variable manually.  If the
+@code{spam-process-destination} parameter is not set, the spam
+articles are only expired.  The group name is fully qualified, meaning
+that if you see @samp{nntp:servername} before the group name in the
+group buffer then you need it here as well.
+
+If spam can not be moved---because of a read-only back end such as
+@acronym{NNTP}, for example, it will be copied.
+
+Note that you can use multiples destinations per group or regular
+expression!  This enables you to send your spam to multiple @emph{spam
+training} groups.
+
+@vindex spam-log-to-registry
+The problem with processing ham and spam is that Gnus doesn't track
+this processing by default.  Enable the @code{spam-log-to-registry}
+variable so @code{spam.el} will use @code{gnus-registry.el} to track
+what articles have been processed, and avoid processing articles
+multiple times.  Keep in mind that if you limit the number of registry
+entries, this won't work as well as it does without a limit.
+
+@vindex spam-mark-only-unseen-as-spam
+Set this variable if you want only unseen articles in spam groups to
+be marked as spam.  By default, it is set.  If you set it to
+@code{nil}, unread articles will also be marked as spam.
+
+@vindex spam-mark-ham-unread-before-move-from-spam-group
+Set this variable if you want ham to be unmarked before it is moved
+out of the spam group.  This is very useful when you use something
+like the tick mark @samp{!} to mark ham---the article will be placed
+in your @code{ham-process-destination}, unmarked as if it came fresh
+from the mail server.
+
+@vindex spam-autodetect-recheck-messages
+When autodetecting spam, this variable tells @code{spam.el} whether
+only unseen articles or all unread articles should be checked for
+spam.  It is recommended that you leave it off.
+
+@node Spam Package Configuration Examples
+@subsection Spam Package Configuration Examples
+@cindex spam filtering
+@cindex spam filtering configuration examples
+@cindex spam configuration examples
+@cindex spam
+
+@subsubheading Ted's setup
+
+From Ted Zlatanov <tzz@@lifelogs.com>.
+@example
+;; @r{for @code{gnus-registry-split-fancy-with-parent} and spam autodetection}
+;; @r{see @file{gnus-registry.el} for more information}
+(gnus-registry-initialize)
+(spam-initialize)
+
+(setq
+ spam-log-to-registry t     ; @r{for spam autodetection}
+ spam-use-BBDB t
+ spam-use-regex-headers t   ; @r{catch X-Spam-Flag (SpamAssassin)}
+ ;; @r{all groups with @samp{spam} in the name contain spam}
+ gnus-spam-newsgroup-contents
+  '(("spam" gnus-group-spam-classification-spam))
+ ;; @r{see documentation for these}
+ spam-move-spam-nonspam-groups-only nil
+ spam-mark-only-unseen-as-spam t
+ spam-mark-ham-unread-before-move-from-spam-group t
+ ;; @r{understand what this does before you copy it to your own setup!}
+ ;; @r{for nnimap you'll probably want to set nnimap-split-methods, see the manual}
+ nnimap-split-fancy '(|
+                      ;; @r{trace references to parents and put in their group}
+                      (: gnus-registry-split-fancy-with-parent)
+                      ;; @r{this will catch server-side SpamAssassin tags}
+                      (: spam-split 'spam-use-regex-headers)
+                      (any "ding" "ding")
+                      ;; @r{note that spam by default will go to @samp{spam}}
+                      (: spam-split)
+                      ;; @r{default mailbox}
+                      "mail"))
+
+;; @r{my parameters, set with @kbd{G p}}
+
+;; @r{all nnml groups, and all nnimap groups except}
+;; @r{@samp{nnimap+mail.lifelogs.com:train} and}
+;; @r{@samp{nnimap+mail.lifelogs.com:spam}: any spam goes to nnimap training,}
+;; @r{because it must have been detected manually}
+
+((spam-process-destination . "nnimap+mail.lifelogs.com:train"))
+
+;; @r{all @acronym{NNTP} groups}
+;; @r{autodetect spam with the blacklist and ham with the BBDB}
+((spam-autodetect-methods spam-use-blacklist spam-use-BBDB)
+;; @r{send all spam to the training group}
+ (spam-process-destination . "nnimap+mail.lifelogs.com:train"))
+
+;; @r{only some @acronym{NNTP} groups, where I want to autodetect spam}
+((spam-autodetect . t))
+
+;; @r{my nnimap @samp{nnimap+mail.lifelogs.com:spam} group}
+
+;; @r{this is a spam group}
+((spam-contents gnus-group-spam-classification-spam)
+
+ ;; @r{any spam (which happens when I enter for all unseen messages,}
+ ;; @r{because of the @code{gnus-spam-newsgroup-contents} setting above), goes to}
+ ;; @r{@samp{nnimap+mail.lifelogs.com:train} unless I mark it as ham}
+
+ (spam-process-destination "nnimap+mail.lifelogs.com:train")
+
+ ;; @r{any ham goes to my @samp{nnimap+mail.lifelogs.com:mail} folder, but}
+ ;; @r{also to my @samp{nnimap+mail.lifelogs.com:trainham} folder for training}
+
+ (ham-process-destination "nnimap+mail.lifelogs.com:mail"
+                          "nnimap+mail.lifelogs.com:trainham")
+ ;; @r{in this group, only @samp{!} marks are ham}
+ (ham-marks
+  (gnus-ticked-mark))
+ ;; @r{remembers senders in the blacklist on the way out---this is}
+ ;; @r{definitely not needed, it just makes me feel better}
+ (spam-process (gnus-group-spam-exit-processor-blacklist)))
+
+;; @r{Later, on the @acronym{IMAP} server I use the @samp{train} group for training}
+;; @r{SpamAssassin to recognize spam, and the @samp{trainham} group fora}
+;; @r{recognizing ham---but Gnus has nothing to do with it.}
+
+@end example
+
+@subsubheading Using @code{spam.el} on an IMAP server with a statistical filter on the server
+From Reiner Steib <reiner.steib@@gmx.de>.
+
+My provider has set up bogofilter (in combination with @acronym{DCC}) on
+the mail server (@acronym{IMAP}).  Recognized spam goes to
+@samp{spam.detected}, the rest goes through the normal filter rules,
+i.e., to @samp{some.folder} or to @samp{INBOX}.  Training on false
+positives or negatives is done by copying or moving the article to
+@samp{training.ham} or @samp{training.spam} respectively.  A cron job on
+the server feeds those to bogofilter with the suitable ham or spam
+options and deletes them from the @samp{training.ham} and
+@samp{training.spam} folders.
+
+With the following entries in @code{gnus-parameters}, @code{spam.el}
+does most of the job for me:
+
+@lisp
+   ("nnimap:spam\\.detected"
+    (gnus-article-sort-functions '(gnus-article-sort-by-chars))
+    (ham-process-destination "nnimap:INBOX" "nnimap:training.ham")
+    (spam-contents gnus-group-spam-classification-spam))
+   ("nnimap:\\(INBOX\\|other-folders\\)"
+    (spam-process-destination . "nnimap:training.spam")
+    (spam-contents gnus-group-spam-classification-ham))
+@end lisp
+
+@itemize
+
+@item @b{The Spam folder:}
+
+In the folder @samp{spam.detected}, I have to check for false positives
+(i.e., legitimate mails, that were wrongly judged as spam by
+bogofilter or DCC).
+
+Because of the @code{gnus-group-spam-classification-spam} entry, all
+messages are marked as spam (with @code{$}).  When I find a false
+positive, I mark the message with some other ham mark
+(@code{ham-marks}, @ref{Spam and Ham Processors}).  On group exit,
+those messages are copied to both groups, @samp{INBOX} (where I want
+to have the article) and @samp{training.ham} (for training bogofilter)
+and deleted from the @samp{spam.detected} folder.
+
+The @code{gnus-article-sort-by-chars} entry simplifies detection of
+false positives for me.  I receive lots of worms (sweN, @dots{}), that all
+have a similar size.  Grouping them by size (i.e., chars) makes finding
+other false positives easier.  (Of course worms aren't @i{spam}
+(@acronym{UCE}, @acronym{UBE}) strictly speaking.  Anyhow, bogofilter is
+an excellent tool for filtering those unwanted mails for me.)
+
+@item @b{Ham folders:}
+
+In my ham folders, I just hit @kbd{S x}
+(@code{gnus-summary-mark-as-spam}) whenever I see an unrecognized spam
+mail (false negative).  On group exit, those messages are moved to
+@samp{training.spam}.
+@end itemize
+
+@subsubheading Reporting spam articles in Gmane groups with @code{spam-report.el}
+
+From Reiner Steib <reiner.steib@@gmx.de>.
+
+With following entry in @code{gnus-parameters}, @kbd{S x}
+(@code{gnus-summary-mark-as-spam}) marks articles in @code{gmane.*}
+groups as spam and reports the to Gmane at group exit:
+
+@lisp
+   ("^gmane\\."
+    (spam-process (gnus-group-spam-exit-processor-report-gmane)))
+@end lisp
+
+Additionally, I use @code{(setq spam-report-gmane-use-article-number nil)}
+because I don't read the groups directly from news.gmane.org, but
+through my local news server (leafnode).  I.e., the article numbers are
+not the same as on news.gmane.org, thus @code{spam-report.el} has to check
+the @code{X-Report-Spam} header to find the correct number.
+
+@node Spam Back Ends
+@subsection Spam Back Ends
+@cindex spam back ends
+
+The spam package offers a variety of back ends for detecting spam.
+Each back end defines a set of methods for detecting spam
+(@pxref{Filtering Incoming Mail}, @pxref{Detecting Spam in Groups}),
+and a pair of spam and ham processors (@pxref{Spam and Ham
+Processors}).
+
+@menu
+* Blacklists and Whitelists::
+* BBDB Whitelists::
+* Gmane Spam Reporting::
+* Anti-spam Hashcash Payments::
+* Blackholes::
+* Regular Expressions Header Matching::
+* Bogofilter::
+* SpamAssassin back end::
+* ifile spam filtering::
+* Spam Statistics Filtering::
+* SpamOracle::
+@end menu
+
+@node Blacklists and Whitelists
+@subsubsection Blacklists and Whitelists
+@cindex spam filtering
+@cindex whitelists, spam filtering
+@cindex blacklists, spam filtering
+@cindex spam
+
+@defvar spam-use-blacklist
+
+Set this variable to @code{t} if you want to use blacklists when
+splitting incoming mail.  Messages whose senders are in the blacklist
+will be sent to the @code{spam-split-group}.  This is an explicit
+filter, meaning that it acts only on mail senders @emph{declared} to
+be spammers.
+
+@end defvar
+
+@defvar spam-use-whitelist
+
+Set this variable to @code{t} if you want to use whitelists when
+splitting incoming mail.  Messages whose senders are not in the
+whitelist will be sent to the next spam-split rule.  This is an
+explicit filter, meaning that unless someone is in the whitelist, their
+messages are not assumed to be spam or ham.
+
+@end defvar
+
+@defvar spam-use-whitelist-exclusive
+
+Set this variable to @code{t} if you want to use whitelists as an
+implicit filter, meaning that every message will be considered spam
+unless the sender is in the whitelist.  Use with care.
+
+@end defvar
+
+@defvar gnus-group-spam-exit-processor-blacklist
+
+Add this symbol to a group's @code{spam-process} parameter by
+customizing the group parameters or the
+@code{gnus-spam-process-newsgroups} variable.  When this symbol is
+added to a group's @code{spam-process} parameter, the senders of
+spam-marked articles will be added to the blacklist.
+
+@emph{WARNING}
+
+Instead of the obsolete
+@code{gnus-group-spam-exit-processor-blacklist}, it is recommended
+that you use @code{(spam spam-use-blacklist)}.  Everything will work
+the same way, we promise.
+
+@end defvar
+
+@defvar gnus-group-ham-exit-processor-whitelist
+
+Add this symbol to a group's @code{spam-process} parameter by
+customizing the group parameters or the
+@code{gnus-spam-process-newsgroups} variable.  When this symbol is
+added to a group's @code{spam-process} parameter, the senders of
+ham-marked articles in @emph{ham} groups will be added to the
+whitelist.
+
+@emph{WARNING}
+
+Instead of the obsolete
+@code{gnus-group-ham-exit-processor-whitelist}, it is recommended
+that you use @code{(ham spam-use-whitelist)}.  Everything will work
+the same way, we promise.
+
+@end defvar
+
+Blacklists are lists of regular expressions matching addresses you
+consider to be spam senders.  For instance, to block mail from any
+sender at @samp{vmadmin.com}, you can put @samp{vmadmin.com} in your
+blacklist.  You start out with an empty blacklist.  Blacklist entries
+use the Emacs regular expression syntax.
+
+Conversely, whitelists tell Gnus what addresses are considered
+legitimate.  All messages from whitelisted addresses are considered
+non-spam.  Also see @ref{BBDB Whitelists}.  Whitelist entries use the
+Emacs regular expression syntax.
+
+The blacklist and whitelist file locations can be customized with the
+@code{spam-directory} variable (@file{~/News/spam} by default), or
+the @code{spam-whitelist} and @code{spam-blacklist} variables
+directly.  The whitelist and blacklist files will by default be in the
+@code{spam-directory} directory, named @file{whitelist} and
+@file{blacklist} respectively.
+
+@node BBDB Whitelists
+@subsubsection BBDB Whitelists
+@cindex spam filtering
+@cindex BBDB whitelists, spam filtering
+@cindex BBDB, spam filtering
+@cindex spam
+
+@defvar spam-use-BBDB
+
+Analogous to @code{spam-use-whitelist} (@pxref{Blacklists and
+Whitelists}), but uses the BBDB as the source of whitelisted
+addresses, without regular expressions.  You must have the BBDB loaded
+for @code{spam-use-BBDB} to work properly.  Messages whose senders are
+not in the BBDB will be sent to the next spam-split rule.  This is an
+explicit filter, meaning that unless someone is in the BBDB, their
+messages are not assumed to be spam or ham.
+
+@end defvar
+
+@defvar spam-use-BBDB-exclusive
+
+Set this variable to @code{t} if you want to use the BBDB as an
+implicit filter, meaning that every message will be considered spam
+unless the sender is in the BBDB@.  Use with care.  Only sender
+addresses in the BBDB will be allowed through; all others will be
+classified as spammers.
+
+While @code{spam-use-BBDB-exclusive} @emph{can} be used as an alias
+for @code{spam-use-BBDB} as far as @code{spam.el} is concerned, it is
+@emph{not} a separate back end.  If you set
+@code{spam-use-BBDB-exclusive} to @code{t}, @emph{all} your BBDB splitting
+will be exclusive.
+
+@end defvar
+
+@defvar gnus-group-ham-exit-processor-BBDB
+
+Add this symbol to a group's @code{spam-process} parameter by
+customizing the group parameters or the
+@code{gnus-spam-process-newsgroups} variable.  When this symbol is
+added to a group's @code{spam-process} parameter, the senders of
+ham-marked articles in @emph{ham} groups will be added to the
+BBDB.
+
+@emph{WARNING}
+
+Instead of the obsolete
+@code{gnus-group-ham-exit-processor-BBDB}, it is recommended
+that you use @code{(ham spam-use-BBDB)}.  Everything will work
+the same way, we promise.
+
+@end defvar
+
+@node Gmane Spam Reporting
+@subsubsection Gmane Spam Reporting
+@cindex spam reporting
+@cindex Gmane, spam reporting
+@cindex Gmane, spam reporting
+@cindex spam
+
+@defvar gnus-group-spam-exit-processor-report-gmane
+
+Add this symbol to a group's @code{spam-process} parameter by
+customizing the group parameters or the
+@code{gnus-spam-process-newsgroups} variable.  When this symbol is
+added to a group's @code{spam-process} parameter, the spam-marked
+articles groups will be reported to the Gmane administrators via a
+HTTP request.
+
+Gmane can be found at @uref{http://gmane.org}.
+
+@emph{WARNING}
+
+Instead of the obsolete
+@code{gnus-group-spam-exit-processor-report-gmane}, it is recommended
+that you use @code{(spam spam-use-gmane)}.  Everything will work the
+same way, we promise.
+
+@end defvar
+
+@defvar spam-report-gmane-use-article-number
+
+This variable is @code{t} by default.  Set it to @code{nil} if you are
+running your own news server, for instance, and the local article
+numbers don't correspond to the Gmane article numbers.  When
+@code{spam-report-gmane-use-article-number} is @code{nil},
+@code{spam-report.el} will fetch the number from the article headers.
+
+@end defvar
+
+@defvar spam-report-user-mail-address
+
+Mail address exposed in the User-Agent spam reports to Gmane.  It allows
+the Gmane administrators to contact you in case of misreports.  The
+default is @code{user-mail-address}.
+
+@end defvar
+
+@node Anti-spam Hashcash Payments
+@subsubsection Anti-spam Hashcash Payments
+@cindex spam filtering
+@cindex hashcash, spam filtering
+@cindex spam
+
+@defvar spam-use-hashcash
+
+Similar to @code{spam-use-whitelist} (@pxref{Blacklists and
+Whitelists}), but uses hashcash tokens for whitelisting messages
+instead of the sender address.  Messages without a hashcash payment
+token will be sent to the next spam-split rule.  This is an explicit
+filter, meaning that unless a hashcash token is found, the messages
+are not assumed to be spam or ham.
+
+@end defvar
+
+@node Blackholes
+@subsubsection Blackholes
+@cindex spam filtering
+@cindex blackholes, spam filtering
+@cindex spam
+
+@defvar spam-use-blackholes
+
+This option is disabled by default.  You can let Gnus consult the
+blackhole-type distributed spam processing systems (DCC, for instance)
+when you set this option.  The variable @code{spam-blackhole-servers}
+holds the list of blackhole servers Gnus will consult.  The current
+list is fairly comprehensive, but make sure to let us know if it
+contains outdated servers.
+
+The blackhole check uses the @code{dig.el} package, but you can tell
+@code{spam.el} to use @code{dns.el} instead for better performance if
+you set @code{spam-use-dig} to @code{nil}.  It is not recommended at
+this time to set @code{spam-use-dig} to @code{nil} despite the
+possible performance improvements, because some users may be unable to
+use it, but you can try it and see if it works for you.
+
+@end defvar
+
+@defvar spam-blackhole-servers
+
+The list of servers to consult for blackhole checks.
+
+@end defvar
+
+@defvar spam-blackhole-good-server-regex
+
+A regular expression for IPs that should not be checked against the
+blackhole server list.  When set to @code{nil}, it has no effect.
+
+@end defvar
+
+@defvar spam-use-dig
+
+Use the @code{dig.el} package instead of the @code{dns.el} package.
+The default setting of @code{t} is recommended.
+
+@end defvar
+
+Blackhole checks are done only on incoming mail.  There is no spam or
+ham processor for blackholes.
+
+@node Regular Expressions Header Matching
+@subsubsection Regular Expressions Header Matching
+@cindex spam filtering
+@cindex regular expressions header matching, spam filtering
+@cindex spam
+
+@defvar spam-use-regex-headers
+
+This option is disabled by default.  You can let Gnus check the
+message headers against lists of regular expressions when you set this
+option.  The variables @code{spam-regex-headers-spam} and
+@code{spam-regex-headers-ham} hold the list of regular expressions.
+Gnus will check against the message headers to determine if the
+message is spam or ham, respectively.
+
+@end defvar
+
+@defvar spam-regex-headers-spam
+
+The list of regular expressions that, when matched in the headers of
+the message, positively identify it as spam.
+
+@end defvar
+
+@defvar spam-regex-headers-ham
+
+The list of regular expressions that, when matched in the headers of
+the message, positively identify it as ham.
+
+@end defvar
+
+Regular expression header checks are done only on incoming mail.
+There is no specific spam or ham processor for regular expressions.
+
+@node Bogofilter
+@subsubsection Bogofilter
+@cindex spam filtering
+@cindex bogofilter, spam filtering
+@cindex spam
+
+@defvar spam-use-bogofilter
+
+Set this variable if you want @code{spam-split} to use Eric Raymond's
+speedy Bogofilter.
+
+With a minimum of care for associating the @samp{$} mark for spam
+articles only, Bogofilter training all gets fairly automatic.  You
+should do this until you get a few hundreds of articles in each
+category, spam or not.  The command @kbd{S t} in summary mode, either
+for debugging or for curiosity, shows the @emph{spamicity} score of
+the current article (between 0.0 and 1.0).
+
+Bogofilter determines if a message is spam based on a specific
+threshold.  That threshold can be customized, consult the Bogofilter
+documentation.
+
+If the @code{bogofilter} executable is not in your path, Bogofilter
+processing will be turned off.
+
+You should not enable this if you use @code{spam-use-bogofilter-headers}.
+
+@end defvar
+
+@table @kbd
+@item M s t
+@itemx S t
+@kindex M s t
+@kindex S t
+@findex spam-bogofilter-score
+Get the Bogofilter spamicity score (@code{spam-bogofilter-score}).
+@end table
+
+@defvar spam-use-bogofilter-headers
+
+Set this variable if you want @code{spam-split} to use Eric Raymond's
+speedy Bogofilter, looking only at the message headers.  It works
+similarly to @code{spam-use-bogofilter}, but the @code{X-Bogosity} header
+must be in the message already.  Normally you would do this with a
+procmail recipe or something similar; consult the Bogofilter
+installation documents for details.
+
+You should not enable this if you use @code{spam-use-bogofilter}.
+
+@end defvar
+
+@defvar gnus-group-spam-exit-processor-bogofilter
+Add this symbol to a group's @code{spam-process} parameter by
+customizing the group parameters or the
+@code{gnus-spam-process-newsgroups} variable.  When this symbol is
+added to a group's @code{spam-process} parameter, spam-marked articles
+will be added to the Bogofilter spam database.
+
+@emph{WARNING}
+
+Instead of the obsolete
+@code{gnus-group-spam-exit-processor-bogofilter}, it is recommended
+that you use @code{(spam spam-use-bogofilter)}.  Everything will work
+the same way, we promise.
+@end defvar
+
+@defvar gnus-group-ham-exit-processor-bogofilter
+Add this symbol to a group's @code{spam-process} parameter by
+customizing the group parameters or the
+@code{gnus-spam-process-newsgroups} variable.  When this symbol is
+added to a group's @code{spam-process} parameter, the ham-marked
+articles in @emph{ham} groups will be added to the Bogofilter database
+of non-spam messages.
+
+@emph{WARNING}
+
+Instead of the obsolete
+@code{gnus-group-ham-exit-processor-bogofilter}, it is recommended
+that you use @code{(ham spam-use-bogofilter)}.  Everything will work
+the same way, we promise.
+@end defvar
+
+@defvar spam-bogofilter-database-directory
+
+This is the directory where Bogofilter will store its databases.  It
+is not specified by default, so Bogofilter will use its own default
+database directory.
+
+@end defvar
+
+The Bogofilter mail classifier is similar to @command{ifile} in intent and
+purpose.  A ham and a spam processor are provided, plus the
+@code{spam-use-bogofilter} and @code{spam-use-bogofilter-headers}
+variables to indicate to spam-split that Bogofilter should either be
+used, or has already been used on the article.  The 0.9.2.1 version of
+Bogofilter was used to test this functionality.
+
+@node SpamAssassin back end
+@subsubsection SpamAssassin back end
+@cindex spam filtering
+@cindex spamassassin, spam filtering
+@cindex spam
+
+@defvar spam-use-spamassassin
+
+Set this variable if you want @code{spam-split} to use SpamAssassin.
+
+SpamAssassin assigns a score to each article based on a set of rules
+and tests, including a Bayesian filter.  The Bayesian filter can be
+trained by associating the @samp{$} mark for spam articles.  The
+spam score can be viewed by using the command @kbd{S t} in summary
+mode.
+
+If you set this variable, each article will be processed by
+SpamAssassin when @code{spam-split} is called.  If your mail is
+preprocessed by SpamAssassin, and you want to just use the
+SpamAssassin headers, set @code{spam-use-spamassassin-headers}
+instead.
+
+You should not enable this if you use
+@code{spam-use-spamassassin-headers}.
+
+@end defvar
+
+@defvar spam-use-spamassassin-headers
+
+Set this variable if your mail is preprocessed by SpamAssassin and
+want @code{spam-split} to split based on the SpamAssassin headers.
+
+You should not enable this if you use @code{spam-use-spamassassin}.
+
+@end defvar
+
+@defvar spam-spamassassin-program
+
+This variable points to the SpamAssassin executable.  If you have
+@code{spamd} running, you can set this variable to the @code{spamc}
+executable for faster processing.  See the SpamAssassin documentation
+for more information on @code{spamd}/@code{spamc}.
+
+@end defvar
+
+SpamAssassin is a powerful and flexible spam filter that uses a wide
+variety of tests to identify spam.  A ham and a spam processors are
+provided, plus the @code{spam-use-spamassassin} and
+@code{spam-use-spamassassin-headers} variables to indicate to
+spam-split that SpamAssassin should be either used, or has already
+been used on the article.  The 2.63 version of SpamAssassin was used
+to test this functionality.
+
+@node ifile spam filtering
+@subsubsection ifile spam filtering
+@cindex spam filtering
+@cindex ifile, spam filtering
+@cindex spam
+
+@defvar spam-use-ifile
+
+Enable this variable if you want @code{spam-split} to use @command{ifile}, a
+statistical analyzer similar to Bogofilter.
+
+@end defvar
+
+@defvar spam-ifile-all-categories
+
+Enable this variable if you want @code{spam-use-ifile} to give you all
+the ifile categories, not just spam/non-spam.  If you use this, make
+sure you train ifile as described in its documentation.
+
+@end defvar
+
+@defvar spam-ifile-spam-category
+
+This is the category of spam messages as far as ifile is concerned.
+The actual string used is irrelevant, but you probably want to leave
+the default value of @samp{spam}.
+@end defvar
+
+@defvar spam-ifile-database
+
+This is the filename for the ifile database.  It is not specified by
+default, so ifile will use its own default database name.
+
+@end defvar
+
+The ifile mail classifier is similar to Bogofilter in intent and
+purpose.  A ham and a spam processor are provided, plus the
+@code{spam-use-ifile} variable to indicate to spam-split that ifile
+should be used.  The 1.2.1 version of ifile was used to test this
+functionality.
+
+@node Spam Statistics Filtering
+@subsubsection Spam Statistics Filtering
+@cindex spam filtering
+@cindex spam-stat, spam filtering
+@cindex spam-stat
+@cindex spam
+
+This back end uses the Spam Statistics Emacs Lisp package to perform
+statistics-based filtering (@pxref{Spam Statistics Package}).  Before
+using this, you may want to perform some additional steps to
+initialize your Spam Statistics dictionary.  @xref{Creating a
+spam-stat dictionary}.
+
+@defvar spam-use-stat
+
+@end defvar
+
+@defvar gnus-group-spam-exit-processor-stat
+Add this symbol to a group's @code{spam-process} parameter by
+customizing the group parameters or the
+@code{gnus-spam-process-newsgroups} variable.  When this symbol is
+added to a group's @code{spam-process} parameter, the spam-marked
+articles will be added to the spam-stat database of spam messages.
+
+@emph{WARNING}
+
+Instead of the obsolete
+@code{gnus-group-spam-exit-processor-stat}, it is recommended
+that you use @code{(spam spam-use-stat)}.  Everything will work
+the same way, we promise.
+@end defvar
+
+@defvar gnus-group-ham-exit-processor-stat
+Add this symbol to a group's @code{spam-process} parameter by
+customizing the group parameters or the
+@code{gnus-spam-process-newsgroups} variable.  When this symbol is
+added to a group's @code{spam-process} parameter, the ham-marked
+articles in @emph{ham} groups will be added to the spam-stat database
+of non-spam messages.
+
+@emph{WARNING}
+
+Instead of the obsolete
+@code{gnus-group-ham-exit-processor-stat}, it is recommended
+that you use @code{(ham spam-use-stat)}.  Everything will work
+the same way, we promise.
+@end defvar
+
+This enables @code{spam.el} to cooperate with @file{spam-stat.el}.
+@file{spam-stat.el} provides an internal (Lisp-only) spam database,
+which unlike ifile or Bogofilter does not require external programs.
+A spam and a ham processor, and the @code{spam-use-stat} variable for
+@code{spam-split} are provided.
+
+@node SpamOracle
+@subsubsection Using SpamOracle with Gnus
+@cindex spam filtering
+@cindex SpamOracle
+@cindex spam
+
+An easy way to filter out spam is to use SpamOracle.  SpamOracle is an
+statistical mail filtering tool written by Xavier Leroy and needs to be
+installed separately.
+
+There are several ways to use SpamOracle with Gnus.  In all cases, your
+mail is piped through SpamOracle in its @emph{mark} mode.  SpamOracle will
+then enter an @samp{X-Spam} header indicating whether it regards the
+mail as a spam mail or not.
+
+One possibility is to run SpamOracle as a @code{:prescript} from the
+@xref{Mail Source Specifiers}, (@pxref{SpamAssassin}).  This method has
+the advantage that the user can see the @emph{X-Spam} headers.
+
+The easiest method is to make @file{spam.el} (@pxref{Spam Package})
+call SpamOracle.
+
+@vindex spam-use-spamoracle
+To enable SpamOracle usage by @code{spam.el}, set the variable
+@code{spam-use-spamoracle} to @code{t} and configure the
+@code{nnmail-split-fancy} or @code{nnimap-split-fancy}.  @xref{Spam
+Package}.  In this example the @samp{INBOX} of an nnimap server is
+filtered using SpamOracle.  Mails recognized as spam mails will be
+moved to @code{spam-split-group}, @samp{Junk} in this case.  Ham
+messages stay in @samp{INBOX}:
+
+@example
+(setq spam-use-spamoracle t
+      spam-split-group "Junk"
+      ;; @r{for nnimap you'll probably want to set nnimap-split-methods, see the manual}
+      nnimap-split-inbox '("INBOX")
+      nnimap-split-fancy '(| (: spam-split) "INBOX"))
+@end example
+
+@defvar spam-use-spamoracle
+Set to @code{t} if you want Gnus to enable spam filtering using
+SpamOracle.
+@end defvar
+
+@defvar spam-spamoracle-binary
+Gnus uses the SpamOracle binary called @file{spamoracle} found in the
+user's PATH@.  Using the variable @code{spam-spamoracle-binary}, this
+can be customized.
+@end defvar
+
+@defvar spam-spamoracle-database
+By default, SpamOracle uses the file @file{~/.spamoracle.db} as a database to
+store its analysis.  This is controlled by the variable
+@code{spam-spamoracle-database} which defaults to @code{nil}.  That means
+the default SpamOracle database will be used.  In case you want your
+database to live somewhere special, set
+@code{spam-spamoracle-database} to this path.
+@end defvar
+
+SpamOracle employs a statistical algorithm to determine whether a
+message is spam or ham.  In order to get good results, meaning few
+false hits or misses, SpamOracle needs training.  SpamOracle learns
+the characteristics of your spam mails.  Using the @emph{add} mode
+(training mode) one has to feed good (ham) and spam mails to
+SpamOracle.  This can be done by pressing @kbd{|} in the Summary
+buffer and pipe the mail to a SpamOracle process or using
+@file{spam.el}'s spam- and ham-processors, which is much more
+convenient.  For a detailed description of spam- and ham-processors,
+@xref{Spam Package}.
+
+@defvar gnus-group-spam-exit-processor-spamoracle
+Add this symbol to a group's @code{spam-process} parameter by
+customizing the group parameter or the
+@code{gnus-spam-process-newsgroups} variable.  When this symbol is added
+to a group's @code{spam-process} parameter, spam-marked articles will be
+sent to SpamOracle as spam samples.
+
+@emph{WARNING}
+
+Instead of the obsolete
+@code{gnus-group-spam-exit-processor-spamoracle}, it is recommended
+that you use @code{(spam spam-use-spamoracle)}.  Everything will work
+the same way, we promise.
+@end defvar
+
+@defvar gnus-group-ham-exit-processor-spamoracle
+Add this symbol to a group's @code{spam-process} parameter by
+customizing the group parameter or the
+@code{gnus-spam-process-newsgroups} variable.  When this symbol is added
+to a group's @code{spam-process} parameter, the ham-marked articles in
+@emph{ham} groups will be sent to the SpamOracle as samples of ham
+messages.
+
+@emph{WARNING}
+
+Instead of the obsolete
+@code{gnus-group-ham-exit-processor-spamoracle}, it is recommended
+that you use @code{(ham spam-use-spamoracle)}.  Everything will work
+the same way, we promise.
+@end defvar
+
+@emph{Example:} These are the Group Parameters of a group that has been
+classified as a ham group, meaning that it should only contain ham
+messages.
+@example
+ ((spam-contents gnus-group-spam-classification-ham)
+  (spam-process ((ham spam-use-spamoracle)
+                 (spam spam-use-spamoracle))))
+@end example
+For this group the @code{spam-use-spamoracle} is installed for both
+ham and spam processing.  If the group contains spam message
+(e.g., because SpamOracle has not had enough sample messages yet) and
+the user marks some messages as spam messages, these messages will be
+processed by SpamOracle.  The processor sends the messages to
+SpamOracle as new samples for spam.
+
+@node Extending the Spam package
+@subsection Extending the Spam package
+@cindex spam filtering
+@cindex spam elisp package, extending
+@cindex extending the spam elisp package
+
+Say you want to add a new back end called blackbox.  For filtering
+incoming mail, provide the following:
+
+@enumerate
+
+@item
+Code
+
+@lisp
+(defvar spam-use-blackbox nil
+  "True if blackbox should be used.")
+@end lisp
+
+Write @code{spam-check-blackbox} if Blackbox can check incoming mail.
+
+Write @code{spam-blackbox-register-routine} and
+@code{spam-blackbox-unregister-routine} using the bogofilter
+register/unregister routines as a start, or other register/unregister
+routines more appropriate to Blackbox, if Blackbox can
+register/unregister spam and ham.
+
+@item
+Functionality
+
+The @code{spam-check-blackbox} function should return @samp{nil} or
+@code{spam-split-group}, observing the other conventions.  See the
+existing @code{spam-check-*} functions for examples of what you can
+do, and stick to the template unless you fully understand the reasons
+why you aren't.
+
+@end enumerate
+
+For processing spam and ham messages, provide the following:
+
+@enumerate
+
+@item
+Code
+
+Note you don't have to provide a spam or a ham processor.  Only
+provide them if Blackbox supports spam or ham processing.
+
+Also, ham and spam processors are being phased out as single
+variables.  Instead the form @code{(spam spam-use-blackbox)} or
+@code{(ham spam-use-blackbox)} is favored.  For now, spam/ham
+processor variables are still around but they won't be for long.
+
+@lisp
+(defvar gnus-group-spam-exit-processor-blackbox "blackbox-spam"
+  "The Blackbox summary exit spam processor.
+Only applicable to spam groups.")
+
+(defvar gnus-group-ham-exit-processor-blackbox "blackbox-ham"
+  "The whitelist summary exit ham processor.
+Only applicable to non-spam (unclassified and ham) groups.")
+
+@end lisp
+
+@item
+Gnus parameters
+
+Add
+@lisp
+(const :tag "Spam: Blackbox" (spam spam-use-blackbox))
+(const :tag "Ham: Blackbox"  (ham spam-use-blackbox))
+@end lisp
+to the @code{spam-process} group parameter in @code{gnus.el}.  Make
+sure you do it twice, once for the parameter and once for the
+variable customization.
+
+Add
+@lisp
+(variable-item spam-use-blackbox)
+@end lisp
+to the @code{spam-autodetect-methods} group parameter in
+@code{gnus.el} if Blackbox can check incoming mail for spam contents.
+
+Finally, use the appropriate @code{spam-install-*-backend} function in
+@code{spam.el}.  Here are the available functions.
+
+
+@enumerate
+
+@item
+@code{spam-install-backend-alias}
+
+This function will simply install an alias for a back end that does
+everything like the original back end.  It is currently only used to
+make @code{spam-use-BBDB-exclusive} act like @code{spam-use-BBDB}.
+
+@item
+@code{spam-install-nocheck-backend}
+
+This function installs a back end that has no check function, but can
+register/unregister ham or spam.  The @code{spam-use-gmane} back end is
+such a back end.
+
+@item
+@code{spam-install-checkonly-backend}
+
+This function will install a back end that can only check incoming mail
+for spam contents.  It can't register or unregister messages.
+@code{spam-use-blackholes} and @code{spam-use-hashcash} are such
+back ends.
+
+@item
+@code{spam-install-statistical-checkonly-backend}
+
+This function installs a statistical back end (one which requires the
+full body of a message to check it) that can only check incoming mail
+for contents.  @code{spam-use-regex-body} is such a filter.
+
+@item
+@code{spam-install-statistical-backend}
+
+This function install a statistical back end with incoming checks and
+registration/unregistration routines.  @code{spam-use-bogofilter} is
+set up this way.
+
+@item
+@code{spam-install-backend}
+
+This is the most normal back end installation, where a back end that can
+check and register/unregister messages is set up without statistical
+abilities.  The @code{spam-use-BBDB} is such a back end.
+
+@item
+@code{spam-install-mover-backend}
+
+Mover back ends are internal to @code{spam.el} and specifically move
+articles around when the summary is exited.  You will very probably
+never install such a back end.
+@end enumerate
+
+@end enumerate
+
+@node Spam Statistics Package
+@subsection Spam Statistics Package
+@cindex Paul Graham
+@cindex Graham, Paul
+@cindex naive Bayesian spam filtering
+@cindex Bayesian spam filtering, naive
+@cindex spam filtering, naive Bayesian
+
+Paul Graham has written an excellent essay about spam filtering using
+statistics: @uref{http://www.paulgraham.com/spam.html,A Plan for
+Spam}.  In it he describes the inherent deficiency of rule-based
+filtering as used by SpamAssassin, for example: Somebody has to write
+the rules, and everybody else has to install these rules.  You are
+always late.  It would be much better, he argues, to filter mail based
+on whether it somehow resembles spam or non-spam.  One way to measure
+this is word distribution.  He then goes on to describe a solution
+that checks whether a new mail resembles any of your other spam mails
+or not.
+
+The basic idea is this:  Create a two collections of your mail, one
+with spam, one with non-spam.  Count how often each word appears in
+either collection, weight this by the total number of mails in the
+collections, and store this information in a dictionary.  For every
+word in a new mail, determine its probability to belong to a spam or a
+non-spam mail.  Use the 15 most conspicuous words, compute the total
+probability of the mail being spam.  If this probability is higher
+than a certain threshold, the mail is considered to be spam.
+
+The Spam Statistics package adds support to Gnus for this kind of
+filtering.  It can be used as one of the back ends of the Spam package
+(@pxref{Spam Package}), or by itself.
+
+Before using the Spam Statistics package, you need to set it up.
+First, you need two collections of your mail, one with spam, one with
+non-spam.  Then you need to create a dictionary using these two
+collections, and save it.  And last but not least, you need to use
+this dictionary in your fancy mail splitting rules.
+
+@menu
+* Creating a spam-stat dictionary::
+* Splitting mail using spam-stat::
+* Low-level interface to the spam-stat dictionary::
+@end menu
+
+@node Creating a spam-stat dictionary
+@subsubsection Creating a spam-stat dictionary
+
+Before you can begin to filter spam based on statistics, you must
+create these statistics based on two mail collections, one with spam,
+one with non-spam.  These statistics are then stored in a dictionary
+for later use.  In order for these statistics to be meaningful, you
+need several hundred emails in both collections.
+
+Gnus currently supports only the nnml back end for automated dictionary
+creation.  The nnml back end stores all mails in a directory, one file
+per mail.  Use the following:
+
+@defun spam-stat-process-spam-directory
+Create spam statistics for every file in this directory.  Every file
+is treated as one spam mail.
+@end defun
+
+@defun spam-stat-process-non-spam-directory
+Create non-spam statistics for every file in this directory.  Every
+file is treated as one non-spam mail.
+@end defun
+
+Usually you would call @code{spam-stat-process-spam-directory} on a
+directory such as @file{~/Mail/mail/spam} (this usually corresponds to
+the group @samp{nnml:mail.spam}), and you would call
+@code{spam-stat-process-non-spam-directory} on a directory such as
+@file{~/Mail/mail/misc} (this usually corresponds to the group
+@samp{nnml:mail.misc}).
+
+When you are using @acronym{IMAP}, you won't have the mails available
+locally, so that will not work.  One solution is to use the Gnus Agent
+to cache the articles.  Then you can use directories such as
+@file{"~/News/agent/nnimap/mail.yourisp.com/personal_spam"} for
+@code{spam-stat-process-spam-directory}.  @xref{Agent as Cache}.
+
+@defvar spam-stat
+This variable holds the hash-table with all the statistics---the
+dictionary we have been talking about.  For every word in either
+collection, this hash-table stores a vector describing how often the
+word appeared in spam and often it appeared in non-spam mails.
+@end defvar
+
+If you want to regenerate the statistics from scratch, you need to
+reset the dictionary.
+
+@defun spam-stat-reset
+Reset the @code{spam-stat} hash-table, deleting all the statistics.
+@end defun
+
+When you are done, you must save the dictionary.  The dictionary may
+be rather large.  If you will not update the dictionary incrementally
+(instead, you will recreate it once a month, for example), then you
+can reduce the size of the dictionary by deleting all words that did
+not appear often enough or that do not clearly belong to only spam or
+only non-spam mails.
+
+@defun spam-stat-reduce-size
+Reduce the size of the dictionary.  Use this only if you do not want
+to update the dictionary incrementally.
+@end defun
+
+@defun spam-stat-save
+Save the dictionary.
+@end defun
+
+@defvar spam-stat-file
+The filename used to store the dictionary.  This defaults to
+@file{~/.spam-stat.el}.
+@end defvar
+
+@node Splitting mail using spam-stat
+@subsubsection Splitting mail using spam-stat
+
+This section describes how to use the Spam statistics
+@emph{independently} of the @xref{Spam Package}.
+
+First, add the following to your @file{~/.gnus.el} file:
+
+@lisp
+(require 'spam-stat)
+(spam-stat-load)
+@end lisp
+
+This will load the necessary Gnus code, and the dictionary you
+created.
+
+Next, you need to adapt your fancy splitting rules:  You need to
+determine how to use @code{spam-stat}.  The following examples are for
+the nnml back end.  Using the nnimap back end works just as well.  Just
+use @code{nnimap-split-fancy} instead of @code{nnmail-split-fancy}.
+
+In the simplest case, you only have two groups, @samp{mail.misc} and
+@samp{mail.spam}.  The following expression says that mail is either
+spam or it should go into @samp{mail.misc}.  If it is spam, then
+@code{spam-stat-split-fancy} will return @samp{mail.spam}.
+
+@lisp
+(setq nnmail-split-fancy
+      `(| (: spam-stat-split-fancy)
+          "mail.misc"))
+@end lisp
+
+@defvar spam-stat-split-fancy-spam-group
+The group to use for spam.  Default is @samp{mail.spam}.
+@end defvar
+
+If you also filter mail with specific subjects into other groups, use
+the following expression.  Only mails not matching the regular
+expression are considered potential spam.
+
+@lisp
+(setq nnmail-split-fancy
+      `(| ("Subject" "\\bspam-stat\\b" "mail.emacs")
+          (: spam-stat-split-fancy)
+          "mail.misc"))
+@end lisp
+
+If you want to filter for spam first, then you must be careful when
+creating the dictionary.  Note that @code{spam-stat-split-fancy} must
+consider both mails in @samp{mail.emacs} and in @samp{mail.misc} as
+non-spam, therefore both should be in your collection of non-spam
+mails, when creating the dictionary!
+
+@lisp
+(setq nnmail-split-fancy
+      `(| (: spam-stat-split-fancy)
+          ("Subject" "\\bspam-stat\\b" "mail.emacs")
+          "mail.misc"))
+@end lisp
+
+You can combine this with traditional filtering.  Here, we move all
+HTML-only mails into the @samp{mail.spam.filtered} group.  Note that since
+@code{spam-stat-split-fancy} will never see them, the mails in
+@samp{mail.spam.filtered} should be neither in your collection of spam mails,
+nor in your collection of non-spam mails, when creating the
+dictionary!
+
+@lisp
+(setq nnmail-split-fancy
+      `(| ("Content-Type" "text/html" "mail.spam.filtered")
+          (: spam-stat-split-fancy)
+          ("Subject" "\\bspam-stat\\b" "mail.emacs")
+          "mail.misc"))
+@end lisp
+
+
+@node Low-level interface to the spam-stat dictionary
+@subsubsection Low-level interface to the spam-stat dictionary
+
+The main interface to using @code{spam-stat}, are the following functions:
+
+@defun spam-stat-buffer-is-spam
+Called in a buffer, that buffer is considered to be a new spam mail.
+Use this for new mail that has not been processed before.
+@end defun
+
+@defun spam-stat-buffer-is-no-spam
+Called in a buffer, that buffer is considered to be a new non-spam
+mail.  Use this for new mail that has not been processed before.
+@end defun
+
+@defun spam-stat-buffer-change-to-spam
+Called in a buffer, that buffer is no longer considered to be normal
+mail but spam.  Use this to change the status of a mail that has
+already been processed as non-spam.
+@end defun
+
+@defun spam-stat-buffer-change-to-non-spam
+Called in a buffer, that buffer is no longer considered to be spam but
+normal mail.  Use this to change the status of a mail that has already
+been processed as spam.
+@end defun
+
+@defun spam-stat-save
+Save the hash table to the file.  The filename used is stored in the
+variable @code{spam-stat-file}.
+@end defun
+
+@defun spam-stat-load
+Load the hash table from a file.  The filename used is stored in the
+variable @code{spam-stat-file}.
+@end defun
+
+@defun spam-stat-score-word
+Return the spam score for a word.
+@end defun
+
+@defun spam-stat-score-buffer
+Return the spam score for a buffer.
+@end defun
+
+@defun spam-stat-split-fancy
+Use this function for fancy mail splitting.  Add the rule @samp{(:
+spam-stat-split-fancy)} to @code{nnmail-split-fancy}
+@end defun
+
+Make sure you load the dictionary before using it.  This requires the
+following in your @file{~/.gnus.el} file:
+
+@lisp
+(require 'spam-stat)
+(spam-stat-load)
+@end lisp
+
+Typical test will involve calls to the following functions:
+
+@smallexample
+Reset: (setq spam-stat (make-hash-table :test 'equal))
+Learn spam: (spam-stat-process-spam-directory "~/Mail/mail/spam")
+Learn non-spam: (spam-stat-process-non-spam-directory "~/Mail/mail/misc")
+Save table: (spam-stat-save)
+File size: (nth 7 (file-attributes spam-stat-file))
+Number of words: (hash-table-count spam-stat)
+Test spam: (spam-stat-test-directory "~/Mail/mail/spam")
+Test non-spam: (spam-stat-test-directory "~/Mail/mail/misc")
+Reduce table size: (spam-stat-reduce-size)
+Save table: (spam-stat-save)
+File size: (nth 7 (file-attributes spam-stat-file))
+Number of words: (hash-table-count spam-stat)
+Test spam: (spam-stat-test-directory "~/Mail/mail/spam")
+Test non-spam: (spam-stat-test-directory "~/Mail/mail/misc")
+@end smallexample
+
+Here is how you would create your dictionary:
+
+@smallexample
+Reset: (setq spam-stat (make-hash-table :test 'equal))
+Learn spam: (spam-stat-process-spam-directory "~/Mail/mail/spam")
+Learn non-spam: (spam-stat-process-non-spam-directory "~/Mail/mail/misc")
+Repeat for any other non-spam group you need...
+Reduce table size: (spam-stat-reduce-size)
+Save table: (spam-stat-save)
+@end smallexample
+
+@node The Gnus Registry
+@section The Gnus Registry
+@cindex registry
+@cindex split
+@cindex track
+
+The Gnus registry is a package that tracks messages by their
+Message-ID across all backends.  This allows Gnus users to do several
+cool things, be the envy of the locals, get free haircuts, and be
+experts on world issues.  Well, maybe not all of those, but the
+features are pretty cool.
+
+Although they will be explained in detail shortly, here's a quick list
+of said features in case your attention span is...  never mind.
+
+@enumerate
+@item
+Split messages to their parent
+
+This keeps discussions in the same group.  You can use the subject and
+the sender in addition to the Message-ID@.  Several strategies are
+available.
+
+@item
+Refer to messages by ID
+
+Commands like @code{gnus-summary-refer-parent-article} can take
+advantage of the registry to jump to the referred article, regardless
+of the group the message is in.
+
+@item
+Store custom flags and keywords
+
+The registry can store custom flags and keywords for a message.  For
+instance, you can mark a message ``To-Do'' this way and the flag will
+persist whether the message is in the nnimap, nnml, nnmaildir,
+etc.@: backends.
+
+@item
+Store arbitrary data
+
+Through a simple ELisp API, the registry can remember any data for a
+message.  A built-in inverse map, when activated, allows quick lookups
+of all messages matching a particular set of criteria.
+@end enumerate
+
+@menu
+* Gnus Registry Setup::
+* Registry Article Refer Method::
+* Fancy splitting to parent::
+* Store custom flags and keywords::
+* Store arbitrary data::
+@end menu
+
+@node Gnus Registry Setup
+@subsection Gnus Registry Setup
+
+Fortunately, setting up the Gnus registry is pretty easy:
+
+@lisp
+(setq gnus-registry-max-entries 2500)
+
+(gnus-registry-initialize)
+@end lisp
+
+This adds registry saves to Gnus newsrc saves (which happen on exit
+and when you press @kbd{s} from the @file{*Group*} buffer.  It also
+adds registry calls to article actions in Gnus (copy, move, etc.)@: so
+it's not easy to undo the initialization.  See
+@code{gnus-registry-initialize} for the gory details.
+
+Here are other settings used by the author of the registry (understand
+what they do before you copy them blindly).
+
+@lisp
+(setq
+ gnus-registry-split-strategy 'majority
+ gnus-registry-ignored-groups '(("nntp" t)
+                                ("nnrss" t)
+                                ("spam" t)
+                                ("train" t))
+ gnus-registry-max-entries 500000
+ ;; this is the default
+ gnus-registry-track-extra '(sender subject))
+@end lisp
+
+They say: keep a lot of messages around, track messages by sender and
+subject (not just parent Message-ID), and when the registry splits
+incoming mail, use a majority rule to decide where messages should go
+if there's more than one possibility.  In addition, the registry
+should ignore messages in groups that match ``nntp'', ``nnrss'',
+``spam'', or ``train.''
+
+You are doubtless impressed by all this, but you ask: ``I am a Gnus
+user, I customize to live.  Give me more.''  Here you go, these are
+the general settings.
+
+@defvar gnus-registry-unfollowed-groups
+The groups that will not be followed by
+@code{gnus-registry-split-fancy-with-parent}.  They will still be
+remembered by the registry.  This is a list of regular expressions.
+By default any group name that ends with ``delayed'', ``drafts'',
+``queue'', or ``INBOX'', belongs to the nnmairix backend, or contains
+the word ``archive'' is not followed.
+@end defvar
+
+@defvar gnus-registry-max-entries
+The number (an integer or @code{nil} for unlimited) of entries the
+registry will keep.  If the registry has reached or exceeded this
+size, it will reject insertion of new entries.
+@end defvar
+
+@defvar gnus-registry-prune-factor
+This option (a float between 0 and 1) controls how much the registry
+is cut back during pruning.  In order to prevent constant pruning, the
+registry will be pruned back to less than
+@code{gnus-registry-max-entries}.  This option controls exactly how
+much less: the target is calculated as the maximum number of entries
+minus the maximum number times this factor.  The default is 0.1:
+i.e., if your registry is limited to 50000 entries, pruning will try to
+cut back to 45000 entries.  Entries with keys marked as precious will
+not be pruned.
+@end defvar
+
+@defvar gnus-registry-default-sort-function
+This option specifies how registry entries are sorted during pruning.
+If a function is given, it should sort least valuable entries first,
+as pruning starts from the beginning of the list.  The default value
+is @code{gnus-registry-sort-by-creation-time}, which proposes the
+oldest entries for pruning.  Set to nil to perform no sorting, which
+will speed up the pruning process.
+@end defvar
+
+@defvar gnus-registry-cache-file
+The file where the registry will be stored between Gnus sessions.  By
+default the file name is @code{.gnus.registry.eieio} in the same
+directory as your @code{.newsrc.eld}.
+@end defvar
+
+@node Registry Article Refer Method
+@subsection Fetching by @code{Message-ID} Using the Registry
+
+The registry knows how to map each @code{Message-ID} to the group it's
+in.  This can be leveraged to enhance the ``article refer method'',
+the thing that tells Gnus how to look up an article given its
+Message-ID (@pxref{Finding the Parent}).
+
+@vindex nnregistry
+@vindex gnus-refer-article-method
+
+The @code{nnregistry} refer method does exactly that.  It has the
+advantage that an article may be found regardless of the group it's
+in---provided its @code{Message-ID} is known to the registry.  It can
+be enabled by augmenting the start-up file with something along these
+lines:
+
+@example
+;; Keep enough entries to have a good hit rate when referring to an
+;; article using the registry.  Use long group names so that Gnus
+;; knows where the article is.
+(setq gnus-registry-max-entries 2500)
+
+(gnus-registry-initialize)
+
+(setq gnus-refer-article-method
+      '(current
+        (nnregistry)
+        (nnweb "gmane" (nnweb-type gmane))))
+@end example
+
+The example above instructs Gnus to first look up the article in the
+current group, or, alternatively, using the registry, and finally, if
+all else fails, using Gmane.
+
+@node Fancy splitting to parent
+@subsection Fancy splitting to parent
+
+Simply put, this lets you put followup e-mail where it belongs.
+
+Every message has a Message-ID, which is unique, and the registry
+remembers it.  When the message is moved or copied, the registry will
+notice this and offer the new group as a choice to the splitting
+strategy.
+
+When a followup is made, usually it mentions the original message's
+Message-ID in the headers.  The registry knows this and uses that
+mention to find the group where the original message lives.  You only
+have to put a rule like this:
+
+@lisp
+(setq nnimap-my-split-fancy '(|
+
+      ;; split to parent: you need this
+      (: gnus-registry-split-fancy-with-parent)
+
+      ;; other rules, as an example
+      (: spam-split)
+      ;; default mailbox
+      "mail")
+@end lisp
+
+in your fancy split setup.  In addition, you may want to customize the
+following variables.
+
+@defvar gnus-registry-track-extra
+This is a list of symbols, so it's best to change it from the
+Customize interface.  By default it's @code{(subject sender recipient)},
+which may work for you.  It can be annoying if your mail flow is large
+and people don't stick to the same groups.
+
+When you decide to stop tracking any of those extra data, you can use
+the command @code{gnus-registry-remove-extra-data} to purge it from
+the existing registry entries.
+@end defvar
+
+@defvar gnus-registry-split-strategy
+This is a symbol, so it's best to change it from the Customize
+interface.  By default it's @code{nil}, but you may want to set it to
+@code{majority} or @code{first} to split by sender or subject based on
+the majority of matches or on the first found.  I find @code{majority}
+works best.
+@end defvar
+
+@node Store custom flags and keywords
+@subsection Store custom flags and keywords
+
+The registry lets you set custom flags and keywords per message.  You
+can use the Gnus->Registry Marks menu or the @kbd{M M x} keyboard
+shortcuts, where @code{x} is the first letter of the mark's name.
+
+@defvar gnus-registry-marks
+The custom marks that the registry can use.  You can modify the
+default list, if you like.  If you do, you'll have to exit Emacs
+before they take effect (you can also unload the registry and reload
+it or evaluate the specific macros you'll need, but you probably don't
+want to bother).  Use the Customize interface to modify the list.
+
+By default this list has the @code{Important}, @code{Work},
+@code{Personal}, @code{To-Do}, and @code{Later} marks.  They all have
+keyboard shortcuts like @kbd{M M i} for Important, using the first
+letter.
+@end defvar
+
+@defun gnus-registry-mark-article
+Call this function to mark an article with a custom registry mark.  It
+will offer the available marks for completion.
+@end defun
+
+You can use @code{defalias} to install a summary line formatting
+function that will show the registry marks.  There are two flavors of
+this function, either showing the marks as single characters, using
+their @code{:char} property, or showing the marks as full strings.
+
+@lisp
+;; show the marks as single characters (see the :char property in
+;; 'gnus-registry-marks'):
+;; (defalias 'gnus-user-format-function-M 'gnus-registry-article-marks-to-chars)
+
+;; show the marks by name (see 'gnus-registry-marks'):
+;; (defalias 'gnus-user-format-function-M 'gnus-registry-article-marks-to-names)
+@end lisp
+
+
+@node Store arbitrary data
+@subsection Store arbitrary data
+
+The registry has a simple API that uses a Message-ID as the key to
+store arbitrary data (as long as it can be converted to a list for
+storage).
+
+@defun gnus-registry-set-id-key (id key value)
+Store @code{value} under @code{key} for message @code{id}.
+@end defun
+
+@defun gnus-registry-get-id-key (id key)
+Get the data under @code{key} for message @code{id}.
+@end defun
+
+@defvar gnus-registry-extra-entries-precious
+If any extra entries are precious, their presence will make the
+registry keep the whole entry forever, even if there are no groups for
+the Message-ID and if the size limit of the registry is reached.  By
+default this is just @code{(marks)} so the custom registry marks are
+precious.
+@end defvar
+
+@node Other modes
+@section Interaction with other modes
+
+@subsection Dired
+@cindex dired
+
+@code{gnus-dired-minor-mode} provides some useful functions for dired
+buffers.  It is enabled with
+@lisp
+(add-hook 'dired-mode-hook 'turn-on-gnus-dired-mode)
+@end lisp
+
+@table @kbd
+@item C-c C-m C-a
+@findex gnus-dired-attach
+@cindex attachments, selection via dired
+Send dired's marked files as an attachment (@code{gnus-dired-attach}).
+You will be prompted for a message buffer.
+
+@item C-c C-m C-l
+@findex gnus-dired-find-file-mailcap
+Visit a file according to the appropriate mailcap entry
+(@code{gnus-dired-find-file-mailcap}).  With prefix, open file in a new
+buffer.
+
+@item C-c C-m C-p
+@findex gnus-dired-print
+Print file according to the mailcap entry (@code{gnus-dired-print}).  If
+there is no print command, print in a PostScript image.
+@end table
+
+@node Various Various
+@section Various Various
+@cindex mode lines
+@cindex highlights
+
+@table @code
+
+@item gnus-home-directory
+@vindex gnus-home-directory
+All Gnus file and directory variables will be initialized from this
+variable, which defaults to @file{~/}.
+
+@item gnus-directory
+@vindex gnus-directory
+Most Gnus storage file and directory variables will be initialized from
+this variable, which defaults to the @env{SAVEDIR} environment
+variable, or @file{~/News/} if that variable isn't set.
+
+Note that Gnus is mostly loaded when the @file{~/.gnus.el} file is read.
+This means that other directory variables that are initialized from this
+variable won't be set properly if you set this variable in
+@file{~/.gnus.el}.  Set this variable in @file{.emacs} instead.
+
+@item gnus-default-directory
+@vindex gnus-default-directory
+Not related to the above variable at all---this variable says what the
+default directory of all Gnus buffers should be.  If you issue commands
+like @kbd{C-x C-f}, the prompt you'll get starts in the current buffer's
+default directory.  If this variable is @code{nil} (which is the
+default), the default directory will be the default directory of the
+buffer you were in when you started Gnus.
+
+@item gnus-verbose
+@vindex gnus-verbose
+This variable is an integer between zero and ten.  The higher the value,
+the more messages will be displayed.  If this variable is zero, Gnus
+will never flash any messages, if it is seven (which is the default),
+most important messages will be shown, and if it is ten, Gnus won't ever
+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 back ends instead of Gnus proper.
+
+@item gnus-add-timestamp-to-message
+@vindex gnus-add-timestamp-to-message
+This variable controls whether to add timestamps to messages that are
+controlled by @code{gnus-verbose} and @code{gnus-verbose-backends} and
+are issued.  The default value is @code{nil} which means never to add
+timestamp.  If it is @code{log}, add timestamps to only the messages
+that go into the @file{*Messages*} buffer (in XEmacs, it is the
+@w{@file{ *Message-Log*}} buffer).  If it is neither @code{nil} nor
+@code{log}, add timestamps not only to log messages but also to the ones
+displayed in the echo area.
+
+@item nnheader-max-head-length
+@vindex nnheader-max-head-length
+When the back ends read straight heads of articles, they all try to read
+as little as possible.  This variable (default 8192) specifies
+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 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}.
+
+@item nnheader-head-chop-length
+@vindex nnheader-head-chop-length
+This variable (default 2048) says how big a piece of each article to
+read when doing the operation described above.
+
+@item nnheader-file-name-translation-alist
+@vindex nnheader-file-name-translation-alist
+@cindex file names
+@cindex invalid characters in file names
+@cindex characters in file names
+This is an alist that says how to translate characters in file names.
+For instance, if @samp{:} is invalid as a file character in file names
+on your system (you OS/2 user you), you could say something like:
+
+@lisp
+@group
+(setq nnheader-file-name-translation-alist
+      '((?: . ?_)))
+@end group
+@end lisp
+
+In fact, this is the default value for this variable on OS/2 and MS
+Windows (phooey) systems.
+
+@item gnus-hidden-properties
+@vindex gnus-hidden-properties
+This is a list of properties to use to hide ``invisible'' text.  It is
+@code{(invisible t intangible t)} by default on most systems, which
+makes invisible text invisible and intangible.
+
+@item gnus-parse-headers-hook
+@vindex gnus-parse-headers-hook
+A hook called before parsing headers.  It can be used, for instance, to
+gather statistics on the headers fetched, or perhaps you'd like to prune
+some headers.  I don't see why you'd want that, though.
+
+@item gnus-shell-command-separator
+@vindex gnus-shell-command-separator
+String used to separate two shell commands.  The default is @samp{;}.
+
+@item gnus-invalid-group-regexp
+@vindex gnus-invalid-group-regexp
+
+Regexp to match ``invalid'' group names when querying user for a group
+name.  The default value catches some @strong{really} invalid group
+names who could possibly mess up Gnus internally (like allowing
+@samp{:} in a group name, which is normally used to delimit method and
+group).
+
+@acronym{IMAP} users might want to allow @samp{/} in group names though.
+
+@item gnus-safe-html-newsgroups
+@vindex gnus-safe-html-newsgroups
+Groups in which links in html articles are considered all safe.  The
+value may be a regexp matching those groups, a list of group names, or
+@code{nil}.  This overrides @code{mm-w3m-safe-url-regexp}.  The default
+value is @code{"\\`nnrss[+:]"}.  This is effective only when emacs-w3m
+renders html articles, i.e., in the case @code{mm-text-html-renderer} is
+set to @code{w3m}.  @xref{Display Customization, ,Display Customization,
+emacs-mime, The Emacs MIME Manual}.
+
+@end table
+
+@node The End
+@chapter The End
+
+Well, that's the manual---you can get on with your life now.  Keep in
+touch.  Say hello to your cats from me.
+
+My @strong{ghod}---I just can't stand goodbyes.  Sniffle.
+
+Ol' Charles Reznikoff said it pretty well, so I leave the floor to him:
+
+@quotation
+@strong{Te Deum}
+
+@sp 1
+Not because of victories @*
+I sing,@*
+having none,@*
+but for the common sunshine,@*
+the breeze,@*
+the largess of the spring.
+
+@sp 1
+Not for victory@*
+but for the day's work done@*
+as well as I was able;@*
+not for a seat upon the dais@*
+but at the common table.@*
+@end quotation
+
+
+@node Appendices
+@chapter Appendices
+
+@menu
+* 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::  The Gnus FAQ
+@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{mail-lib}, @samp{xemacs-base},
+@samp{eterm}, @samp{sh-script}, @samp{net-utils}, @samp{os-utils},
+@samp{dired}, @samp{mh-e}, @samp{sieve}, @samp{ps-print},
+@samp{pgg}, @samp{mailcrypt}, @samp{ecrypto}, and @samp{sasl}.
+
+
+@node History
+@section History
+
+@cindex history
+@sc{gnus} was written by Masanobu @sc{Umeda}.  When autumn crept up in
+'94, Lars Magne Ingebrigtsen grew bored and decided to rewrite Gnus.
+
+If you want to investigate the person responsible for this outrage,
+you can point your (feh!) web browser to
+@uref{http://quimby.gnus.org/}.  This is also the primary
+distribution point for the new and spiffy versions of Gnus, and is
+known as The Site That Destroys Newsrcs And Drives People Mad.
+
+During the first extended alpha period of development, the new Gnus was
+called ``(ding) Gnus''.  @dfn{(ding)} is, of course, short for
+@dfn{ding is not Gnus}, which is a total and utter lie, but who cares?
+(Besides, the ``Gnus'' in this abbreviation should probably be
+pronounced ``news'' as @sc{Umeda} intended, which makes it a more
+appropriate name, don't you think?)
+
+In any case, after spending all that energy on coming up with a new and
+spunky name, we decided that the name was @emph{too} spunky, so we
+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.
+* 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
+
+
+@node Gnus Versions
+@subsection Gnus Versions
+@cindex ding Gnus
+@cindex September Gnus
+@cindex Red Gnus
+@cindex Quassia Gnus
+@cindex Pterodactyl Gnus
+@cindex Oort Gnus
+@cindex No Gnus
+@cindex Ma Gnus
+@cindex Gnus versions
+
+The first ``proper'' release of Gnus 5 was done in November 1995 when it
+was included in the Emacs 19.30 distribution (132 (ding) Gnus releases
+plus 15 Gnus 5.0 releases).
+
+In May 1996 the next Gnus generation (aka. ``September Gnus'' (after 99
+releases)) was released under the name ``Gnus 5.2'' (40 releases).
+
+On July 28th 1996 work on Red Gnus was begun, and it was released on
+January 25th 1997 (after 84 releases) as ``Gnus 5.4'' (67 releases).
+
+On September 13th 1997, Quassia Gnus was started and lasted 37 releases.
+It was released as ``Gnus 5.6'' on March 8th 1998 (46 releases).
+
+Gnus 5.6 begat Pterodactyl Gnus on August 29th 1998 and was released as
+``Gnus 5.8'' (after 99 releases and a CVS repository) on December 3rd
+1999.
+
+On the 26th of October 2000, Oort Gnus was begun and was released as
+Gnus 5.10 on May 1st 2003 (24 releases).
+
+On the January 4th 2004, No Gnus was begun.
+
+On April 19, 2010 Gnus development was moved to Git.  See
+http://git.gnus.org for details (http://www.gnus.org will be updated
+with the information when possible).
+
+On the January 31th 2012, Ma Gnus was begun.
+
+If you happen upon a version of Gnus that has a prefixed name---``(ding)
+Gnus'', ``September Gnus'', ``Red Gnus'', ``Quassia Gnus'',
+``Pterodactyl Gnus'', ``Oort Gnus'', ``No Gnus'', ``Ma Gnus''---don't
+panic.  Don't let it know that you're frightened.  Back away.  Slowly.
+Whatever you do, don't run.  Walk away, calmly, until you're out of
+its reach.  Find a proper released version of Gnus and snuggle up to
+that instead.
+
+
+@node Why?
+@subsection Why?
+
+What's the point of Gnus?
+
+I want to provide a ``rad'', ``happening'', ``way cool'' and ``hep''
+newsreader, that lets you do anything you can think of.  That was my
+original motivation, but while working on Gnus, it has become clear to
+me that this generation of newsreaders really belong in the stone age.
+Newsreaders haven't developed much since the infancy of the net.  If the
+volume continues to rise with the current rate of increase, all current
+newsreaders will be pretty much useless.  How do you deal with
+newsgroups that have thousands of new articles each day?  How do you
+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 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.
+
+May Gnus never be complete.  @kbd{C-u 100 M-x all-hail-emacs} and
+@kbd{C-u 100 M-x all-hail-xemacs}.
+
+
+@node Compatibility
+@subsection Compatibility
+
+@cindex compatibility
+Gnus was designed to be fully compatible with @sc{gnus}.  Almost all key
+bindings have been kept.  More key bindings have been added, of course,
+but only in one or two obscure cases have old bindings been changed.
+
+Our motto is:
+@quotation
+@cartouche
+@center In a cloud bones of steel.
+@end cartouche
+@end quotation
+
+All commands have kept their names.  Some internal functions have changed
+their names.
+
+The @code{gnus-uu} package has changed drastically.  @xref{Decoding
+Articles}.
+
+One major compatibility question is the presence of several summary
+buffers.  All variables relevant while reading a group are
+buffer-local to the summary buffer they belong in.  Although many
+important variables have their values copied into their global
+counterparts whenever a command is executed in the summary buffer, this
+change might lead to incorrect values being used unless you are careful.
+
+All code that relies on knowledge of @sc{gnus} internals will probably
+fail.  To take two examples: Sorting @code{gnus-newsrc-alist} (or
+changing it in any way, as a matter of fact) is strictly verboten.  Gnus
+maintains a hash table that points to the entries in this alist (which
+speeds up many functions), and changing the alist directly will lead to
+peculiar results.
+
+@cindex hilit19
+@cindex highlighting
+Old hilit19 code does not work at all.  In fact, you should probably
+remove all hilit code from all Gnus hooks
+(@code{gnus-group-prepare-hook} and @code{gnus-summary-prepare-hook}).
+Gnus provides various integrated functions for highlighting.  These are
+faster and more accurate.  To make life easier for everybody, Gnus will
+by default remove all hilit calls from all hilit hooks.  Uncleanliness!
+Away!
+
+Packages like @code{expire-kill} will no longer work.  As a matter of
+fact, you should probably remove all old @sc{gnus} packages (and other
+code) when you start using Gnus.  More likely than not, Gnus already
+does what you have written code to make @sc{gnus} do.  (Snicker.)
+
+Even though old methods of doing things are still supported, only the
+new methods are documented in this manual.  If you detect a new method of
+doing something while reading this manual, that does not mean you have
+to stop doing it the old way.
+
+Gnus understands all @sc{gnus} startup files.
+
+@kindex M-x gnus-bug
+@findex gnus-bug
+@cindex reporting bugs
+@cindex bugs
+Overall, a casual user who hasn't written much code that depends on
+@sc{gnus} internals should suffer no problems.  If problems occur,
+please let me know by issuing that magic command @kbd{M-x gnus-bug}.
+
+@vindex gnus-bug-create-help-buffer
+If you are in the habit of sending bug reports @emph{very} often, you
+may find the helpful help buffer annoying after a while.  If so, set
+@code{gnus-bug-create-help-buffer} to @code{nil} to avoid having it pop
+up at you.
+
+
+@node Conformity
+@subsection Conformity
+
+No rebels without a clue here, ma'am.  We conform to all standards known
+to (wo)man.  Except for those standards and/or conventions we disagree
+with, of course.
+
+@table @strong
+
+@item RFC (2)822
+@cindex RFC 822
+@cindex RFC 2822
+There are no known breaches of this standard.
+
+@item RFC 1036
+@cindex RFC 1036
+There are no known breaches of this standard, either.
+
+@item Son-of-RFC 1036
+@cindex Son-of-RFC 1036
+We do have some breaches to this one.
+
+@table @emph
+
+@item X-Newsreader
+@itemx User-Agent
+These are considered to be ``vanity headers'', while I consider them
+to be consumer information.  After seeing so many badly formatted
+articles coming from @code{tin} and @code{Netscape} I know not to use
+either of those for posting articles.  I would not have known that if
+it wasn't for the @code{X-Newsreader} header.
+@end table
+
+@item USEFOR
+@cindex USEFOR
+USEFOR is an IETF working group writing a successor to RFC 1036, based
+on Son-of-RFC 1036.  They have produced a number of drafts proposing
+various changes to the format of news articles.  The Gnus towers will
+look into implementing the changes when the draft is accepted as an RFC.
+
+@item MIME---RFC 2045--2049 etc
+@cindex @acronym{MIME}
+All the various @acronym{MIME} RFCs are supported.
+
+@item Disposition Notifications---RFC 2298
+Message Mode is able to request notifications from the receiver.
+
+@item PGP---RFC 1991 and RFC 2440
+@cindex RFC 1991
+@cindex RFC 2440
+RFC 1991 is the original @acronym{PGP} message specification,
+published as an informational RFC@.  RFC 2440 was the follow-up, now
+called Open PGP, and put on the Standards Track.  Both document a
+non-@acronym{MIME} aware @acronym{PGP} format.  Gnus supports both
+encoding (signing and encryption) and decoding (verification and
+decryption).
+
+@item PGP/MIME---RFC 2015/3156
+RFC 2015 (superseded by 3156 which references RFC 2440 instead of RFC
+1991) describes the @acronym{MIME}-wrapping around the RFC 1991/2440 format.
+Gnus supports both encoding and decoding.
+
+@item S/MIME---RFC 2633
+RFC 2633 describes the @acronym{S/MIME} format.
+
+@item IMAP---RFC 1730/2060, RFC 2195, RFC 2086, RFC 2359, RFC 2595, RFC 1731
+RFC 1730 is @acronym{IMAP} version 4, updated somewhat by RFC 2060
+(@acronym{IMAP} 4 revision 1).  RFC 2195 describes CRAM-MD5
+authentication for @acronym{IMAP}.  RFC 2086 describes access control
+lists (ACLs) for @acronym{IMAP}.  RFC 2359 describes a @acronym{IMAP}
+protocol enhancement.  RFC 2595 describes the proper @acronym{TLS}
+integration (STARTTLS) with @acronym{IMAP}.  RFC 1731 describes the
+GSSAPI/Kerberos4 mechanisms for @acronym{IMAP}.
+
+@end table
+
+If you ever notice Gnus acting non-compliant with regards to the texts
+mentioned above, don't hesitate to drop a note to Gnus Towers and let us
+know.
+
+
+@node Emacsen
+@subsection Emacsen
+@cindex Emacsen
+@cindex XEmacs
+@cindex Mule
+@cindex Emacs
+
+This version of Gnus should work on:
+
+@itemize @bullet
+
+@item
+Emacs 23.1 and up.
+
+@item
+XEmacs 21.4 and up.
+
+@end itemize
+
+This Gnus version will absolutely not work on any Emacsen older than
+that.  Not reliably, at least.  Older versions of Gnus may work on older
+Emacs versions.  Particularly, Gnus 5.10.8 should also work on Emacs
+20.7 and XEmacs 21.1.
+
+@c No-merge comment: The paragraph added in v5-10 here must not be
+@c synced here!
+
+@node Gnus Development
+@subsection Gnus Development
+
+Gnus is developed in a two-phased cycle.  The first phase involves much
+discussion on the development mailing list @samp{ding@@gnus.org}, where people
+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
+unstable and should not be used by casual users.  Gnus alpha releases
+have names like ``Oort Gnus'' and ``No Gnus''.  @xref{Gnus Versions}.
+
+After futzing around for 10--100 alpha releases, Gnus is declared
+@dfn{frozen}, and only bug fixes are applied.  Gnus loses the prefix,
+and is called things like ``Gnus 5.10.1'' instead.  Normal people are
+supposed to be able to use these, and these are mostly discussed on the
+@samp{gnu.emacs.gnus} newsgroup.  This newgroup is mirrored to the
+mailing list @samp{info-gnus-english@@gnu.org} which is carried on Gmane
+as @samp{gmane.emacs.gnus.user}.  These releases are finally integrated
+in Emacs.
+
+@cindex Incoming*
+@vindex mail-source-delete-incoming
+Some variable defaults differ between alpha Gnusae and released Gnusae,
+in particular, @code{mail-source-delete-incoming}.  This is to prevent
+lossage of mail if an alpha release hiccups while handling the mail.
+@xref{Mail Source Customization}.
+
+The division of discussion between the ding mailing list and the Gnus
+newsgroup is not purely based on publicity concerns.  It's true that
+having people write about the horrible things that an alpha Gnus release
+can do (sometimes) in a public forum may scare people off, but more
+importantly, talking about new experimental features that have been
+introduced may confuse casual users.  New features are frequently
+introduced, fiddled with, and judged to be found wanting, and then
+either discarded or totally rewritten.  People reading the mailing list
+usually keep up with these rapid changes, while people on the newsgroup
+can't be assumed to do so.
+
+So if you have problems with or questions about the alpha versions,
+direct those to the ding mailing list @samp{ding@@gnus.org}.  This list
+is also available on Gmane as @samp{gmane.emacs.gnus.general}.
+
+@cindex Incoming*
+@vindex mail-source-delete-incoming
+Some variable defaults differ between alpha Gnusae and released Gnusae,
+in particular, @code{mail-source-delete-incoming}.  This is to prevent
+lossage of mail if an alpha release hiccups while handling the mail.
+@xref{Mail Source Customization}.
+
+@node Contributors
+@subsection Contributors
+@cindex contributors
+
+The new Gnus version couldn't have been done without the help of all the
+people on the (ding) mailing list.  Every day for over a year I have
+gotten billions of nice bug reports from them, filling me with joy,
+every single one of them.  Smooches.  The people on the list have been
+tried beyond endurance, what with my ``oh, that's a neat idea <type
+type>, yup, I'll release it right away <ship off> no wait, that doesn't
+work at all <type type>, yup, I'll ship that one off right away <ship
+off> no, wait, that absolutely does not work'' policy for releases.
+Micro$oft---bah.  Amateurs.  I'm @emph{much} worse.  (Or is that
+``worser''? ``much worser''?  ``worsest''?)
+
+I would like to take this opportunity to thank the Academy for@dots{}  oops,
+wrong show.
+
+@itemize @bullet
+
+@item
+Masanobu @sc{Umeda}---the writer of the original @sc{gnus}.
+
+@item
+Shenghuo Zhu---uudecode.el, mm-uu.el, rfc1843.el,
+nnwarchive and many, many other things connected with @acronym{MIME} and
+other types of en/decoding, as well as general bug fixing, new
+functionality and stuff.
+
+@item
+Per Abrahamsen---custom, scoring, highlighting and @sc{soup} code (as
+well as numerous other things).
+
+@item
+Luis Fernandes---design and graphics.
+
+@item
+Joe Reiss---creator of the smiley faces.
+
+@item
+Justin Sheehy---the @acronym{FAQ} maintainer.
+
+@item
+Erik Naggum---help, ideas, support, code and stuff.
+
+@item
+Wes Hardaker---@file{gnus-picon.el} and the manual section on
+@dfn{picons} (@pxref{Picons}).
+
+@item
+Kim-Minh Kaplan---further work on the picon code.
+
+@item
+Brad Miller---@file{gnus-gl.el} and the GroupLens manual section.
+
+@item
+Sudish Joseph---innumerable bug fixes.
+
+@item
+Ilja Weis---@file{gnus-topic.el}.
+
+@item
+Steven L. Baur---lots and lots and lots of bug detection and fixes.
+
+@item
+Vladimir Alexiev---the refcard and reference booklets.
+
+@item
+Felix Lee & Jamie Zawinski---I stole some pieces from the XGnus
+distribution by Felix Lee and JWZ.
+
+@item
+Scott Byer---@file{nnfolder.el} enhancements & rewrite.
+
+@item
+Peter Mutsaers---orphan article scoring code.
+
+@item
+Ken Raeburn---POP mail support.
+
+@item
+Hallvard B Furuseth---various bits and pieces, especially dealing with
+.newsrc files.
+
+@item
+Brian Edmonds---@file{gnus-bbdb.el}.
+
+@item
+David Moore---rewrite of @file{nnvirtual.el} and many other things.
+
+@item
+Kevin Davidson---came up with the name @dfn{ding}, so blame him.
+
+@item
+François Pinard---many, many interesting and thorough bug reports, as
+well as autoconf support.
+
+@end itemize
+
+This manual was proof-read by Adrian Aichner, with Ricardo Nassif, Mark
+Borges, and Jost Krieger proof-reading parts of the manual.
+
+The following people have contributed many patches and suggestions:
+
+Christopher Davis,
+Andrew Eskilsson,
+Kai Grossjohann,
+Kevin Greiner,
+Jesper Harder,
+Paul Jarc,
+Simon Josefsson,
+David K@aa{}gedal,
+Richard Pieri,
+Fabrice Popineau,
+Daniel Quinlan,
+Michael Shields,
+Reiner Steib,
+Jason L. Tibbitts, III,
+Jack Vinson,
+Katsumi Yamaoka, @c Yamaoka
+and
+Teodor Zlatanov.
+
+Also thanks to the following for patches and stuff:
+
+Jari Aalto,
+Adrian Aichner,
+Vladimir Alexiev,
+Russ Allbery,
+Peter Arius,
+Matt Armstrong,
+Marc Auslander,
+Miles Bader,
+Alexei V. Barantsev,
+Frank Bennett,
+Robert Bihlmeyer,
+Chris Bone,
+Mark Borges,
+Mark Boyns,
+Lance A. Brown,
+Rob Browning,
+Kees de Bruin,
+Martin Buchholz,
+Joe Buehler,
+Kevin Buhr,
+Alastair Burt,
+Joao Cachopo,
+Zlatko Calusic,
+Massimo Campostrini,
+Castor,
+David Charlap,
+Dan Christensen,
+Kevin Christian,
+Jae-you Chung, @c ?
+James H. Cloos, Jr.,
+Laura Conrad,
+Michael R. Cook,
+Glenn Coombs,
+Andrew J. Cosgriff,
+Neil Crellin,
+Frank D. Cringle,
+Geoffrey T. Dairiki,
+Andre Deparade,
+Ulrik Dickow,
+Dave Disser,
+Rui-Tao Dong, @c ?
+Joev Dubach,
+Michael Welsh Duggan,
+Dave Edmondson,
+Paul Eggert,
+Mark W. Eichin,
+Karl Eichwalder,
+Enami Tsugutomo, @c Enami
+Michael Ernst,
+Luc Van Eycken,
+Sam Falkner,
+Nelson Jose dos Santos Ferreira,
+Sigbjorn Finne,
+Sven Fischer,
+Paul Fisher,
+Decklin Foster,
+Gary D. Foster,
+Paul Franklin,
+Guy Geens,
+Arne Georg Gleditsch,
+David S. Goldberg,
+Michelangelo Grigni,
+Dale Hagglund,
+D. Hall,
+Magnus Hammerin,
+Kenichi Handa, @c Handa
+Raja R. Harinath,
+Yoshiki Hayashi, @c Hayashi
+P. E. Jareth Hein,
+Hisashige Kenji, @c Hisashige
+Scott Hofmann,
+Tassilo Horn,
+Marc Horowitz,
+Gunnar Horrigmo,
+Richard Hoskins,
+Brad Howes,
+Miguel de Icaza,
+François Felix Ingrand,
+Tatsuya Ichikawa, @c Ichikawa
+Ishikawa Ichiro, @c Ishikawa
+Lee Iverson,
+Iwamuro Motonori, @c Iwamuro
+Rajappa Iyer,
+Andreas Jaeger,
+Adam P. Jenkins,
+Randell Jesup,
+Fred Johansen,
+Gareth Jones,
+Greg Klanderman,
+Karl Kleinpaste,
+Michael Klingbeil,
+Peter Skov Knudsen,
+Shuhei Kobayashi, @c Kobayashi
+Petr Konecny,
+Koseki Yoshinori, @c Koseki
+Thor Kristoffersen,
+Jens Lautenbacher,
+Martin Larose,
+Seokchan Lee, @c Lee
+Joerg Lenneis,
+Carsten Leonhardt,
+James LewisMoss,
+Christian Limpach,
+Markus Linnala,
+Dave Love,
+Mike McEwan,
+Tonny Madsen,
+Shlomo Mahlab,
+Nat Makarevitch,
+Istvan Marko,
+David Martin,
+Jason R. Mastaler,
+Gordon Matzigkeit,
+Timo Metzemakers,
+Richard Mlynarik,
+Lantz Moore,
+Morioka Tomohiko, @c Morioka
+Erik Toubro Nielsen,
+Hrvoje Niksic,
+Andy Norman,
+Fred Oberhauser,
+C. R. Oldham,
+Alexandre Oliva,
+Ken Olstad,
+Masaharu Onishi, @c Onishi
+Hideki Ono, @c Ono
+Ettore Perazzoli,
+William Perry,
+Stephen Peters,
+Jens-Ulrik Holger Petersen,
+Ulrich Pfeifer,
+Matt Pharr,
+Andy Piper,
+John McClary Prevost,
+Bill Pringlemeir,
+Mike Pullen,
+Jim Radford,
+Colin Rafferty,
+Lasse Rasinen,
+Lars Balker Rasmussen,
+Joe Reiss,
+Renaud Rioboo,
+Roland B. Roberts,
+Bart Robinson,
+Christian von Roques,
+Markus Rost,
+Jason Rumney,
+Wolfgang Rupprecht,
+Jay Sachs,
+Dewey M. Sasser,
+Conrad Sauerwald,
+Loren Schall,
+Dan Schmidt,
+Ralph Schleicher,
+Philippe Schnoebelen,
+Andreas Schwab,
+Randal L. Schwartz,
+Danny Siu,
+Matt Simmons,
+Paul D. Smith,
+Jeff Sparkes,
+Toby Speight,
+Michael Sperber,
+Darren Stalder,
+Richard Stallman,
+Greg Stark,
+Sam Steingold,
+Paul Stevenson,
+Jonas Steverud,
+Paul Stodghill,
+Kiyokazu Suto, @c Suto
+Kurt Swanson,
+Samuel Tardieu,
+Teddy,
+Chuck Thompson,
+Tozawa Akihiko, @c Tozawa
+Philippe Troin,
+James Troup,
+Trung Tran-Duc,
+Jack Twilley,
+Aaron M. Ucko,
+Aki Vehtari,
+Didier Verna,
+Vladimir Volovich,
+Jan Vroonhof,
+Stefan Waldherr,
+Pete Ware,
+Barry A. Warsaw,
+Christoph Wedler,
+Joe Wells,
+Lee Willis,
+and
+Lloyd Zusman.
+
+
+For a full overview of what each person has done, the ChangeLogs
+included in the Gnus alpha distributions should give ample reading
+(550kB and counting).
+
+Apologies to everybody that I've forgotten, of which there are many, I'm
+sure.
+
+Gee, that's quite a list of people.  I guess that must mean that there
+actually are people who are using Gnus.  Who'd'a thunk it!
+
+
+@node New Features
+@subsection New Features
+@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.
+* Oort Gnus::                   It's big.  It's far out.  Gnus 5.10/5.11.
+* No Gnus::                     Very punny.  Gnus 5.12/5.13.
+* Ma Gnus::                     Celebrating 25 years of Gnus.
+@end menu
+
+These lists are, of course, just @emph{short} overviews of the
+@emph{most} important new features.  No, really.  There are tons more.
+Yes, we have feeping creaturism in full effect.
+
+@node ding Gnus
+@subsubsection (ding) Gnus
+
+New features in Gnus 5.0/5.1:
+
+@itemize @bullet
+
+@item
+The look of all buffers can be changed by setting format-like variables
+(@pxref{Group Buffer Format} and @pxref{Summary Buffer Format}).
+
+@item
+Local spool and several @acronym{NNTP} servers can be used at once
+(@pxref{Select Methods}).
+
+@item
+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 back ends implement a convenient mail expiry scheme
+(@pxref{Expiring Mail}).
+
+@item
+Gnus can use various strategies for gathering threads that have lost
+their roots (thereby gathering loose sub-threads into one thread) or it
+can go back and retrieve enough headers to build a complete thread
+(@pxref{Customizing Threading}).
+
+@item
+Killed groups can be displayed in the group buffer, and you can read
+them as well (@pxref{Listing Groups}).
+
+@item
+Gnus can do partial group updates---you do not have to retrieve the
+entire active file just to check for new articles in a few groups
+(@pxref{The Active File}).
+
+@item
+Gnus implements a sliding scale of subscribedness to groups
+(@pxref{Group Levels}).
+
+@item
+You can score articles according to any number of criteria
+(@pxref{Scoring}).  You can even get Gnus to find out how to score
+articles for you (@pxref{Adaptive Scoring}).
+
+@item
+Gnus maintains a dribble buffer that is auto-saved the normal Emacs
+manner, so it should be difficult to lose much data on what you have
+read if your machine should go down (@pxref{Auto Save}).
+
+@item
+Gnus now has its own startup file (@file{~/.gnus.el}) to avoid
+cluttering up the @file{.emacs} file.
+
+@item
+You can set the process mark on both groups and articles and perform
+operations on all the marked items (@pxref{Process/Prefix}).
+
+@item
+You can list subsets of groups according to, well, anything
+(@pxref{Listing Groups}).
+
+@item
+You can browse foreign servers and subscribe to groups from those
+servers (@pxref{Browse Foreign Server}).
+
+@item
+Gnus can fetch articles, asynchronously, on a second connection to the
+server (@pxref{Asynchronous Fetching}).
+
+@item
+You can cache articles locally (@pxref{Article Caching}).
+
+@item
+The uudecode functions have been expanded and generalized
+(@pxref{Decoding Articles}).
+
+@item
+You can still post uuencoded articles, which was a little-known feature
+of @sc{gnus}' past (@pxref{Uuencoding and Posting}).
+
+@item
+Fetching parents (and other articles) now actually works without
+glitches (@pxref{Finding the Parent}).
+
+@item
+Gnus can fetch @acronym{FAQ}s and group descriptions (@pxref{Group Information}).
+
+@item
+Digests (and other files) can be used as the basis for groups
+(@pxref{Document Groups}).
+
+@item
+Articles can be highlighted and customized (@pxref{Customizing
+Articles}).
+
+@item
+URLs and other external references can be buttonized (@pxref{Article
+Buttons}).
+
+@item
+You can do lots of strange stuff with the Gnus window & frame
+configuration (@pxref{Window Layout}).
+
+@end itemize
+
+
+@node September Gnus
+@subsubsection September Gnus
+
+@iftex
+@iflatex
+\gnusfig{-28cm}{0cm}{\epsfig{figure=ps/september,height=20cm}}
+@end iflatex
+@end iftex
+
+New features in Gnus 5.2/5.3:
+
+@itemize @bullet
+
+@item
+A new message composition mode is used.  All old customization variables
+for @code{mail-mode}, @code{rnews-reply-mode} and @code{gnus-msg} are
+now obsolete.
+
+@item
+Gnus is now able to generate @dfn{sparse} threads---threads where
+missing articles are represented by empty nodes (@pxref{Customizing
+Threading}).
+
+@lisp
+(setq gnus-build-sparse-threads 'some)
+@end lisp
+
+@item
+Outgoing articles are stored on a special archive server
+(@pxref{Archived Messages}).
+
+@item
+Partial thread regeneration now happens when articles are
+referred.
+
+@item
+Gnus can make use of GroupLens predictions.
+
+@item
+Picons (personal icons) can be displayed under XEmacs (@pxref{Picons}).
+
+@item
+A @code{trn}-like tree buffer can be displayed (@pxref{Tree Display}).
+
+@lisp
+(setq gnus-use-trees t)
+@end lisp
+
+@item
+An @code{nn}-like pick-and-read minor mode is available for the summary
+buffers (@pxref{Pick and Read}).
+
+@lisp
+(add-hook 'gnus-summary-mode-hook 'gnus-pick-mode)
+@end lisp
+
+@item
+In binary groups you can use a special binary minor mode (@pxref{Binary
+Groups}).
+
+@item
+Groups can be grouped in a folding topic hierarchy (@pxref{Group
+Topics}).
+
+@lisp
+(add-hook 'gnus-group-mode-hook 'gnus-topic-mode)
+@end lisp
+
+@item
+Gnus can re-send and bounce mail (@pxref{Summary Mail Commands}).
+
+@item
+Groups can now have a score, and bubbling based on entry frequency
+is possible (@pxref{Group Score}).
+
+@lisp
+(add-hook 'gnus-summary-exit-hook 'gnus-summary-bubble-group)
+@end lisp
+
+@item
+Groups can be process-marked, and commands can be performed on
+groups of groups (@pxref{Marking Groups}).
+
+@item
+Caching is possible in virtual groups.
+
+@item
+@code{nndoc} now understands all kinds of digests, mail boxes, rnews
+news batches, ClariNet briefs collections, and just about everything
+else (@pxref{Document Groups}).
+
+@item
+Gnus has a new back end (@code{nnsoup}) to create/read SOUP packets.
+
+@item
+The Gnus cache is much faster.
+
+@item
+Groups can be sorted according to many criteria (@pxref{Sorting
+Groups}).
+
+@item
+New group parameters have been introduced to set list-addresses and
+expiry times (@pxref{Group Parameters}).
+
+@item
+All formatting specs allow specifying faces to be used
+(@pxref{Formatting Fonts}).
+
+@item
+There are several more commands for setting/removing/acting on process
+marked articles on the @kbd{M P} submap (@pxref{Setting Process Marks}).
+
+@item
+The summary buffer can be limited to show parts of the available
+articles based on a wide range of criteria.  These commands have been
+bound to keys on the @kbd{/} submap (@pxref{Limiting}).
+
+@item
+Articles can be made persistent with the @kbd{*} command
+(@pxref{Persistent Articles}).
+
+@item
+All functions for hiding article elements are now toggles.
+
+@item
+Article headers can be buttonized (@pxref{Article Washing}).
+
+@item
+All mail back ends support fetching articles by @code{Message-ID}.
+
+@item
+Duplicate mail can now be treated properly (@pxref{Duplicates}).
+
+@item
+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{Window
+Layout}).
+
+@item
+Mail can be re-scanned by a daemonic process (@pxref{Daemons}).
+@iftex
+@iflatex
+\marginpar[\mbox{}\hfill\epsfig{figure=ps/fseptember,height=5cm}]{\epsfig{figure=ps/fseptember,height=5cm}}
+@end iflatex
+@end iftex
+
+@item
+Groups can be made permanently visible (@pxref{Listing Groups}).
+
+@lisp
+(setq gnus-permanently-visible-groups "^nnml:")
+@end lisp
+
+@item
+Many new hooks have been introduced to make customizing easier.
+
+@item
+Gnus respects the @code{Mail-Copies-To} header.
+
+@item
+Threads can be gathered by looking at the @code{References} header
+(@pxref{Customizing Threading}).
+
+@lisp
+(setq gnus-summary-thread-gathering-function
+      'gnus-gather-threads-by-references)
+@end lisp
+
+@item
+Read articles can be stored in a special backlog buffer to avoid
+refetching (@pxref{Article Backlog}).
+
+@lisp
+(setq gnus-keep-backlog 50)
+@end lisp
+
+@item
+A clean copy of the current article is always stored in a separate
+buffer to allow easier treatment.
+
+@item
+Gnus can suggest where to save articles (@pxref{Saving Articles}).
+
+@item
+Gnus doesn't have to do as much prompting when saving (@pxref{Saving
+Articles}).
+
+@lisp
+(setq gnus-prompt-before-saving t)
+@end lisp
+
+@item
+@code{gnus-uu} can view decoded files asynchronously while fetching
+articles (@pxref{Other Decode Variables}).
+
+@lisp
+(setq gnus-uu-grabbed-file-functions 'gnus-uu-grab-view)
+@end lisp
+
+@item
+Filling in the article buffer now works properly on cited text
+(@pxref{Article Washing}).
+
+@item
+Hiding cited text adds buttons to toggle hiding, and how much
+cited text to hide is now customizable (@pxref{Article Hiding}).
+
+@lisp
+(setq gnus-cited-lines-visible 2)
+@end lisp
+
+@item
+Boring headers can be hidden (@pxref{Article Hiding}).
+
+@item
+Default scoring values can now be set from the menu bar.
+
+@item
+Further syntax checking of outgoing articles have been added.
+
+@end itemize
+
+
+@node Red Gnus
+@subsubsection Red Gnus
+
+New features in Gnus 5.4/5.5:
+
+@iftex
+@iflatex
+\gnusfig{-5.5cm}{-4cm}{\epsfig{figure=ps/red,height=20cm}}
+@end iflatex
+@end iftex
+
+@itemize @bullet
+
+@item
+@file{nntp.el} has been totally rewritten in an asynchronous fashion.
+
+@item
+Article prefetching functionality has been moved up into
+Gnus (@pxref{Asynchronous Fetching}).
+
+@item
+Scoring can now be performed with logical operators like @code{and},
+@code{or}, @code{not}, and parent redirection (@pxref{Advanced
+Scoring}).
+
+@item
+Article washing status can be displayed in the
+article mode line (@pxref{Misc Article}).
+
+@item
+@file{gnus.el} has been split into many smaller files.
+
+@item
+Suppression of duplicate articles based on Message-ID can be done
+(@pxref{Duplicate Suppression}).
+
+@lisp
+(setq gnus-suppress-duplicates t)
+@end lisp
+
+@item
+New variables for specifying what score and adapt files are to be
+considered home score and adapt files (@pxref{Home Score File}) have
+been added.
+
+@item
+@code{nndoc} was rewritten to be easily extensible (@pxref{Document
+Server Internals}).
+
+@item
+Groups can inherit group parameters from parent topics (@pxref{Topic
+Parameters}).
+
+@item
+Article editing has been revamped and is now actually usable.
+
+@item
+Signatures can be recognized in more intelligent fashions
+(@pxref{Article Signature}).
+
+@item
+Summary pick mode has been made to look more @code{nn}-like.  Line
+numbers are displayed and the @kbd{.} command can be used to pick
+articles (@code{Pick and Read}).
+
+@item
+Commands for moving the @file{.newsrc.eld} from one server to
+another have been added (@pxref{Changing Servers}).
+
+@item
+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{C-M-_}
+(@pxref{Undo}).
+
+@item
+Scoring can be done on words using the new score type @code{w}
+(@pxref{Score File Format}).
+
+@item
+Adaptive scoring can be done on a Subject word-by-word basis
+(@pxref{Adaptive Scoring}).
+
+@lisp
+(setq gnus-use-adaptive-scoring '(word))
+@end lisp
+
+@item
+Scores can be decayed (@pxref{Score Decays}).
+
+@lisp
+(setq gnus-decay-scores t)
+@end lisp
+
+@item
+Scoring can be performed using a regexp on the Date header.  The Date is
+normalized to compact ISO 8601 format first (@pxref{Score File Format}).
+
+@item
+A new command has been added to remove all data on articles from
+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{C-M-d}
+(@pxref{Really Various Summary Commands}).
+
+@item
+Process mark sets can be pushed and popped (@pxref{Setting Process
+Marks}).
+
+@item
+A new mail-to-news back end makes it possible to post even when the @acronym{NNTP}
+server doesn't allow posting (@pxref{Mail-To-News Gateways}).
+
+@item
+A new back end for reading searches from Web search engines
+(@dfn{DejaNews}, @dfn{Alta Vista}, @dfn{InReference}) has been added
+(@pxref{Web Searches}).
+
+@item
+Groups inside topics can now be sorted using the standard sorting
+functions, and each topic can be sorted independently (@pxref{Topic
+Sorting}).
+
+@item
+Subsets of the groups can be sorted independently (@code{Sorting
+Groups}).
+
+@item
+Cached articles can be pulled into the groups (@pxref{Summary Generation
+Commands}).
+@iftex
+@iflatex
+\marginpar[\mbox{}\hfill\epsfig{figure=ps/fred,width=3cm}]{\epsfig{figure=ps/fred,width=3cm}}
+@end iflatex
+@end iftex
+
+@item
+Score files are now applied in a more reliable order (@pxref{Score
+Variables}).
+
+@item
+Reports on where mail messages end up can be generated (@pxref{Splitting
+Mail}).
+
+@item
+More hooks and functions have been added to remove junk from incoming
+mail before saving the mail (@pxref{Washing Mail}).
+
+@item
+Emphasized text can be properly fontisized:
+
+@end itemize
+
+
+@node Quassia Gnus
+@subsubsection Quassia Gnus
+
+New features in Gnus 5.6:
+
+@itemize @bullet
+
+@item
+New functionality for using Gnus as an offline newsreader has been
+added.  A plethora of new commands and modes have been added.
+@xref{Gnus Unplugged}, for the full story.
+
+@item
+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.
+
+@item
+@code{gnus-alter-header-function} can now be used to alter header
+values.
+
+@item
+@code{gnus-summary-goto-article} now accept Message-IDs.
+
+@item
+A new Message command for deleting text in the body of a message
+outside the region: @kbd{C-c C-v}.
+
+@item
+You can now post to component group in @code{nnvirtual} groups with
+@kbd{C-u C-c C-c}.
+
+@item
+ @code{nntp-rlogin-program}---new variable to ease customization.
+
+@item
+@code{C-u C-c C-c} in @code{gnus-article-edit-mode} will now inhibit
+re-highlighting of the article buffer.
+
+@item
+New element in @code{gnus-boring-article-headers}---@code{long-to}.
+
+@item
+@kbd{M-i} symbolic prefix command.  @xref{Symbolic Prefixes}, for
+details.
+
+@item
+@kbd{L} and @kbd{I} in the summary buffer now take the symbolic prefix
+@kbd{a} to add the score rule to the @file{all.SCORE} file.
+
+@item
+@code{gnus-simplify-subject-functions} variable to allow greater
+control over simplification.
+
+@item
+@kbd{A T}---new command for fetching the current thread.
+
+@item
+@kbd{/ T}---new command for including the current thread in the
+limit.
+
+@item
+@kbd{M-RET} is a new Message command for breaking cited text.
+
+@item
+@samp{\\1}-expressions are now valid in @code{nnmail-split-methods}.
+
+@item
+The @code{custom-face-lookup} function has been removed.
+If you used this function in your initialization files, you must
+rewrite them to use @code{face-spec-set} instead.
+
+@item
+Canceling now uses the current select method.  Symbolic prefix
+@kbd{a} forces normal posting method.
+
+@item
+New command to translate M******** sm*rtq**t*s into proper
+text---@kbd{W d}.
+
+@item
+For easier debugging of @code{nntp}, you can set
+@code{nntp-record-commands} to a non-@code{nil} value.
+
+@item
+@code{nntp} now uses @file{~/.authinfo}, a @file{.netrc}-like file, for
+controlling where and how to send @sc{authinfo} to @acronym{NNTP} servers.
+
+@item
+A command for editing group parameters from the summary buffer
+has been added.
+
+@item
+A history of where mails have been split is available.
+
+@item
+A new article date command has been added---@code{article-date-iso8601}.
+
+@item
+Subjects can be simplified when threading by setting
+@code{gnus-score-thread-simplify}.
+
+@item
+A new function for citing in Message has been
+added---@code{message-cite-original-without-signature}.
+
+@item
+@code{article-strip-all-blank-lines}---new article command.
+
+@item
+A new Message command to kill to the end of the article has
+been added.
+
+@item
+A minimum adaptive score can be specified by using the
+@code{gnus-adaptive-word-minimum} variable.
+
+@item
+The ``lapsed date'' article header can be kept continually
+updated by the @code{gnus-start-date-timer} command.
+
+@item
+Web listserv archives can be read with the @code{nnlistserv} back end.
+
+@item
+Old dejanews archives can now be read by @code{nnweb}.
+
+@end itemize
+
+@node Pterodactyl Gnus
+@subsubsection Pterodactyl Gnus
+
+New features in Gnus 5.8:
+
+@itemize @bullet
+
+@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
+
+@lisp
+(setq nnmail-use-procmail t)
+(setq nnmail-spool-file 'procmail)
+(setq nnmail-procmail-directory "~/mail/incoming/")
+(setq nnmail-procmail-suffix "\\.in")
+@end lisp
+
+this now has changed to
+
+@lisp
+(setq mail-sources
+      '((directory :path "~/mail/incoming/"
+                   :suffix ".in")))
+@end lisp
+
+@xref{Mail Source Specifiers}.
+
+@item
+Gnus is now a @acronym{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
+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
+called to position point.
+
+@item
+The user can now decide which extra headers should be included in
+summary buffers and @acronym{NOV} files.
+
+@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
+subtly different manner.
+
+@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 @acronym{IMAP} mail via @code{nnimap}.
+
+@end itemize
+
+@node Oort Gnus
+@subsubsection Oort Gnus
+@cindex Oort Gnus
+
+New features in Gnus 5.10:
+
+@itemize @bullet
+
+@item Installation changes
+@c ***********************
+
+@itemize @bullet
+@item
+Upgrading from previous (stable) version if you have used Oort.
+
+If you have tried Oort (the unstable Gnus branch leading to this
+release) but went back to a stable version, be careful when upgrading to
+this version.  In particular, you will probably want to remove all
+@file{.marks} (nnml) and @file{.mrk} (nnfolder) files, so that flags are
+read from your @file{.newsrc.eld} instead of from the
+@file{.marks}/@file{.mrk} file where this release store flags.  See a
+later entry for more information about marks.  Note that downgrading
+isn't save in general.
+
+@item
+Lisp files are now installed in @file{.../site-lisp/gnus/} by default.
+It defaulted to @file{.../site-lisp/} formerly.  In addition to this,
+the new installer issues a warning if other Gnus installations which
+will shadow the latest one are detected.  You can then remove those
+shadows manually or remove them using @code{make
+remove-installed-shadows}.
+
+@item
+New @file{make.bat} for compiling and installing Gnus under MS Windows
+
+Use @file{make.bat} if you want to install Gnus under MS Windows, the
+first argument to the batch-program should be the directory where
+@file{xemacs.exe} respectively @file{emacs.exe} is located, if you want
+to install Gnus after compiling it, give @file{make.bat} @code{/copy} as
+the second parameter.
+
+@file{make.bat} has been rewritten from scratch, it now features
+automatic recognition of XEmacs and Emacs, generates
+@file{gnus-load.el}, checks if errors occur while compilation and
+generation of info files and reports them at the end of the build
+process.  It now uses @code{makeinfo} if it is available and falls
+back to @file{infohack.el} otherwise.  @file{make.bat} should now
+install all files which are necessary to run Gnus and be generally a
+complete replacement for the @code{configure; make; make install}
+cycle used under Unix systems.
+
+The new @file{make.bat} makes @file{make-x.bat} and @file{xemacs.mak}
+superfluous, so they have been removed.
+
+@item
+@file{~/News/overview/} not used.
+
+As a result of the following change, the @file{~/News/overview/}
+directory is not used any more.  You can safely delete the entire
+hierarchy.
+
+@c FIXME: 'gnus-load' is mentioned in README, which is not included in
+@c the repository.  We should find a better place for this item.
+@item
+@code{(require 'gnus-load)}
+
+If you use a stand-alone Gnus distribution, you'd better add
+@code{(require 'gnus-load)} into your @file{~/.emacs} after adding the Gnus
+lisp directory into load-path.
+
+File @file{gnus-load.el} contains autoload commands, functions and variables,
+some of which may not be included in distributions of Emacsen.
+
+@end itemize
+
+@item New packages and libraries within Gnus
+@c *****************************************
+
+@itemize @bullet
+
+@item
+The revised Gnus @acronym{FAQ} is included in the manual,
+@xref{Frequently Asked Questions}.
+
+@item
+@acronym{TLS} wrapper shipped with Gnus
+
+@acronym{TLS}/@acronym{SSL} is now supported in @acronym{IMAP} and
+@acronym{NNTP} via @file{tls.el} and GnuTLS.
+
+@item
+Improved anti-spam features.
+
+Gnus is now able to take out spam from your mail and news streams
+using a wide variety of programs and filter rules.  Among the supported
+methods are RBL blocklists, bogofilter and white/blacklists.  Hooks
+for easy use of external packages such as SpamAssassin and Hashcash
+are also new.  @ref{Thwarting Email Spam} and @ref{Spam Package}.
+@c FIXME: @xref{Spam Package}?.  Should this be under Misc?
+
+@item
+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 @kbd{D g} from the Group
+buffer, and then uploaded to the server using @kbd{C-c C-l} in the
+generated Sieve buffer.  @xref{Sieve Commands}, and the new Sieve
+manual @ref{Top, , Top, sieve, Emacs Sieve}.
+
+@end itemize
+
+@item Changes in group mode
+@c ************************
+
+@itemize @bullet
+
+@item
+@code{gnus-group-read-ephemeral-group} can be called interactively,
+using @kbd{G M}.
+
+@item
+Retrieval of charters and control messages
+
+There are new commands for fetching newsgroup charters (@kbd{H c}) and
+control messages (@kbd{H C}).
+
+@item
+The new variable @code{gnus-parameters} can be used to set group parameters.
+
+Earlier this was done only via @kbd{G p} (or @kbd{G c}), which stored
+the parameters in @file{~/.newsrc.eld}, but via this variable you can
+enjoy the powers of customize, and simplified backups since you set the
+variable in @file{~/.gnus.el} instead of @file{~/.newsrc.eld}.  The
+variable maps regular expressions matching group names to group
+parameters, a'la:
+@lisp
+(setq gnus-parameters
+      '(("mail\\..*"
+         (gnus-show-threads nil)
+         (gnus-use-scoring nil))
+        ("^nnimap:\\(foo.bar\\)$"
+         (to-group . "\\1"))))
+@end lisp
+
+@item
+Unread count correct in nnimap groups.
+
+The estimated number of unread articles in the group buffer should now
+be correct for nnimap groups.  This is achieved by calling
+@code{nnimap-fixup-unread-after-getting-new-news} from the
+@code{gnus-setup-news-hook} (called on startup) and
+@code{gnus-after-getting-new-news-hook} (called after getting new
+mail).  If you have modified those variables from the default, you may
+want to add @code{nnimap-fixup-unread-after-getting-new-news} again.  If
+you were happy with the estimate and want to save some (minimal) time
+when getting new mail, remove the function.
+
+@item
+Group names are treated as UTF-8 by default.
+
+This is supposedly what USEFOR wanted to migrate to.  See
+@code{gnus-group-name-charset-group-alist} and
+@code{gnus-group-name-charset-method-alist} for customization.
+
+@item
+@code{gnus-group-charset-alist} and
+@code{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
+variables should change those regexps accordingly.  For example:
+@lisp
+("^han\\>" euc-kr) -> ("\\(^\\|:\\)han\\>" euc-kr)
+@end lisp
+
+@item
+Old intermediate incoming mail files (@file{Incoming*}) are deleted
+after a couple of days, not immediately.  @xref{Mail Source
+Customization}.  (New in Gnus 5.10.10 / Emacs 22.2)
+
+@end itemize
+
+@item Changes in summary and article mode
+@c **************************************
+
+@itemize @bullet
+
+@item
+@kbd{F} (@code{gnus-article-followup-with-original}) and @kbd{R}
+(@code{gnus-article-reply-with-original}) only yank the text in the
+region if the region is active.
+
+@item
+In draft groups, @kbd{e} is now bound to @code{gnus-draft-edit-message}.
+Use @kbd{B w} for @code{gnus-summary-edit-article} instead.
+
+@item
+Article Buttons
+
+More buttons for URLs, mail addresses, Message-IDs, Info links, man
+pages and Emacs or Gnus related references.  @xref{Article Buttons}.  The
+variables @code{gnus-button-@var{*}-level} can be used to control the
+appearance of all article buttons.  @xref{Article Button Levels}.
+
+@item
+Single-part yenc encoded attachments can be decoded.
+
+@item
+Picons
+
+The picons code has been reimplemented to work in GNU Emacs---some of
+the previous options have been removed or renamed.
+
+Picons are small ``personal icons'' representing users, domain and
+newsgroups, which can be displayed in the Article buffer.
+@xref{Picons}.
+
+@item
+If the new option @code{gnus-treat-body-boundary} is non-@code{nil}, a
+boundary line is drawn at the end of the headers.
+
+@item
+Signed article headers (X-PGP-Sig) can be verified with @kbd{W p}.
+
+@item
+The Summary Buffer uses an arrow in the fringe to indicate the current
+article.  Use @code{(setq gnus-summary-display-arrow nil)} to disable it.
+
+@item
+Warn about email replies to news
+
+Do you often find yourself replying to news by email by mistake?  Then
+the new option @code{gnus-confirm-mail-reply-to-news} is just the thing for
+you.
+
+@item
+If the new option @code{gnus-summary-display-while-building} is
+non-@code{nil}, the summary buffer is shown and updated as it's being
+built.
+
+@item
+Gnus supports RFC 2369 mailing list headers, and adds a number of
+related commands in mailing list groups.  @xref{Mailing List}.
+
+@item
+The Date header can be displayed in a format that can be read aloud
+in English.  @xref{Article Date}.
+
+@item
+diffs are automatically highlighted in groups matching
+@code{mm-uu-diff-groups-regexp}
+
+@item
+Better handling of Microsoft citation styles
+
+Gnus now tries to recognize the mangled header block that some Microsoft
+mailers use to indicate that the rest of the message is a citation, even
+though it is not quoted in any way.  The variable
+@code{gnus-cite-unsightly-citation-regexp} matches the start of these
+citations.
+
+The new command @kbd{W Y f}
+(@code{gnus-article-outlook-deuglify-article}) allows deuglifying broken
+Outlook (Express) articles.
+
+@item
+@code{gnus-article-skip-boring}
+
+If you set @code{gnus-article-skip-boring} to @code{t}, then Gnus will
+not scroll down to show you a page that contains only boring text,
+which by default means cited text and signature.  You can customize
+what is skippable using @code{gnus-article-boring-faces}.
+
+This feature is especially useful if you read many articles that
+consist of a little new content at the top with a long, untrimmed
+message cited below.
+
+@item
+Smileys (@samp{:-)}, @samp{;-)} etc.)@: are now displayed graphically in
+Emacs too.
+
+Put @code{(setq gnus-treat-display-smileys nil)} in @file{~/.gnus.el} to
+disable it.
+
+@item
+Face headers handling.  @xref{Face}.
+
+@item
+In the summary buffer, the new command @kbd{/ N} inserts new messages
+and @kbd{/ o} inserts old messages.
+
+@item
+Gnus decodes morse encoded messages if you press @kbd{W m}.
+
+@item
+@code{gnus-summary-line-format}
+
+The default value changed to @samp{%U%R%z%I%(%[%4L: %-23,23f%]%)
+%s\n}.  Moreover @code{gnus-extra-headers},
+@code{nnmail-extra-headers} and @code{gnus-ignored-from-addresses}
+changed their default so that the users name will be replaced by the
+recipient's name or the group name posting to for @acronym{NNTP}
+groups.
+
+@item
+Deleting of attachments.
+
+The command @code{gnus-mime-save-part-and-strip} (bound to @kbd{C-o}
+on @acronym{MIME} buttons) saves a part and replaces the part with an
+external one.  @code{gnus-mime-delete-part} (bound to @kbd{d} on
+@acronym{MIME} buttons) removes a part.  It works only on back ends
+that support editing.
+
+@item
+@code{gnus-default-charset}
+
+The default value is determined from the
+@code{current-language-environment} variable, instead of
+@code{iso-8859-1}.  Also the @samp{.*} item in
+@code{gnus-group-charset-alist} is removed.
+
+@item
+Printing capabilities are enhanced.
+
+Gnus supports Muttprint natively with @kbd{O P} from the Summary and
+Article buffers.  Also, each individual @acronym{MIME} part can be
+printed using @kbd{p} on the @acronym{MIME} button.
+
+@item
+Extended format specs.
+
+Format spec @samp{%&user-date;} is added into
+@code{gnus-summary-line-format-alist}.  Also, user defined extended
+format specs are supported.  The extended format specs look like
+@samp{%u&foo;}, which invokes function
+@code{gnus-user-format-function-@var{foo}}.  Because @samp{&} is used as the
+escape character, old user defined format @samp{%u&} is no longer supported.
+
+@item
+@kbd{/ *} (@code{gnus-summary-limit-include-cached}) is rewritten.
+@c FIXME: Was this a user-visible change?
+
+It was aliased to @kbd{Y c}
+(@code{gnus-summary-insert-cached-articles}).  The new function filters
+out other articles.
+
+@item
+Some limiting commands accept a @kbd{C-u} prefix to negate the match.
+
+If @kbd{C-u} is used on subject, author or extra headers, i.e., @kbd{/
+s}, @kbd{/ a}, and @kbd{/ x}
+(@code{gnus-summary-limit-to-@{subject,author,extra@}}) respectively, the
+result will be to display all articles that do not match the expression.
+
+@item
+Gnus inlines external parts (message/external).
+
+@end itemize
+
+@item Changes in Message mode and related Gnus features
+@c ****************************************************
+
+@itemize @bullet
+
+@item
+Delayed articles
+
+You can delay the sending of a message with @kbd{C-c C-j} in the Message
+buffer.  The messages are delivered at specified time.  This is useful
+for sending yourself reminders.  @xref{Delayed Articles}.
+
+@item
+If the new option @code{nnml-use-compressed-files} is non-@code{nil},
+the nnml back end allows compressed message files.
+
+@item
+The new option @code{gnus-gcc-mark-as-read} automatically marks
+Gcc articles as read.
+
+@item
+Externalizing of attachments
+
+If @code{gnus-gcc-externalize-attachments} or
+@code{message-fcc-externalize-attachments} is non-@code{nil}, attach
+local files as external parts.
+
+@item
+The envelope sender address can be customized when using Sendmail.
+@xref{Mail Variables, Mail Variables,, message, Message Manual}.
+
+@item
+Gnus no longer generate the Sender: header automatically.
+
+Earlier it was generated when the user configurable email address was
+different from the Gnus guessed default user address.  As the guessing
+algorithm is rarely correct these days, and (more controversially) the
+only use of the Sender: header was to check if you are entitled to
+cancel/supersede news (which is now solved by Cancel Locks instead,
+see another entry), generation of the header has been disabled by
+default.  See the variables @code{message-required-headers},
+@code{message-required-news-headers}, and
+@code{message-required-mail-headers}.
+
+@item
+Features from third party @file{message-utils.el} added to @file{message.el}.
+
+Message now asks if you wish to remove @samp{(was: <old subject>)} from
+subject lines (see @code{message-subject-trailing-was-query}).  @kbd{C-c
+M-m} and @kbd{C-c M-f} inserts markers indicating included text.
+@kbd{C-c C-f a} adds a X-No-Archive: header.  @kbd{C-c C-f x} inserts
+appropriate headers and a note in the body for cross-postings and
+followups (see the variables @code{message-cross-post-@var{*}}).
+
+@item
+References and X-Draft-From headers are no longer generated when you
+start composing messages and @code{message-generate-headers-first} is
+@code{nil}.
+
+@item
+Easy inclusion of X-Faces headers.  @xref{X-Face}.
+
+@item
+Group Carbon Copy (GCC) quoting
+
+To support groups that contains SPC and other weird characters, groups
+are quoted before they are placed in the Gcc: header.  This means
+variables such as @code{gnus-message-archive-group} should no longer
+contain quote characters to make groups containing SPC work.  Also, if
+you are using the string @samp{nnml:foo, nnml:bar} (indicating Gcc
+into two groups) you must change it to return the list
+@code{("nnml:foo" "nnml:bar")}, otherwise the Gcc: line will be quoted
+incorrectly.  Note that returning the string @samp{nnml:foo, nnml:bar}
+was incorrect earlier, it just didn't generate any problems since it
+was inserted directly.
+
+@item
+@code{message-insinuate-rmail}
+
+@c FIXME should that not be 'message-user-agent?
+Adding @code{(message-insinuate-rmail)} and @code{(setq
+mail-user-agent 'gnus-user-agent)} in @file{.emacs} convinces Rmail to
+compose, reply and forward messages in message-mode, where you can
+enjoy the power of @acronym{MML}.
+
+@item
+@code{message-minibuffer-local-map}
+
+The line below enables BBDB in resending a message:
+@lisp
+(define-key message-minibuffer-local-map [(tab)]
+  'bbdb-complete-name)
+@end lisp
+
+@item
+@code{gnus-posting-styles}
+
+Add a new format of match like
+@lisp
+((header "to" "larsi.*org")
+ (Organization "Somewhere, Inc."))
+@end lisp
+The old format like the lines below is obsolete, but still accepted.
+@lisp
+(header "to" "larsi.*org"
+        (Organization "Somewhere, Inc."))
+@end lisp
+
+@item
+@code{message-ignored-news-headers} and @code{message-ignored-mail-headers}
+
+@samp{X-Draft-From} and @samp{X-Gnus-Agent-Meta-Information} have been
+added into these two variables.  If you customized those, perhaps you
+need add those two headers too.
+
+@item
+Gnus supports the ``format=flowed'' (RFC 2646) parameter.  On
+composing messages, it is enabled by @code{use-hard-newlines}.
+Decoding format=flowed was present but not documented in earlier
+versions.
+
+@item
+The option @code{mm-fill-flowed} can be used to disable treatment of
+``format=flowed'' messages.  Also, flowed text is disabled when sending
+inline PGP signed messages.  @xref{Flowed text, , Flowed text,
+emacs-mime, The Emacs MIME Manual}.  (New in Gnus 5.10.7)
+@c This entry is also present in the node "No Gnus".
+
+@item
+Gnus supports the generation of RFC 2298 Disposition Notification requests.
+
+This is invoked with the @kbd{C-c M-n} key binding from message mode.
+
+@item
+Message supports the Importance: (RFC 2156) header.
+
+In the message buffer, @kbd{C-c C-f C-i} or @kbd{C-c C-u} cycles through
+the valid values.
+
+@item
+Gnus supports Cancel Locks in News.
+
+This means a header @samp{Cancel-Lock} is inserted in news posting.  It is
+used to determine if you wrote an article or not (for canceling and
+superseding).  Gnus generates a random password string the first time
+you post a message, and saves it in your @file{~/.emacs} using the Custom
+system.  While the variable is called @code{canlock-password}, it is not
+security sensitive data.  Publishing your canlock string on the web
+will not allow anyone to be able to anything she could not already do.
+The behavior can be changed by customizing @code{message-insert-canlock}.
+
+@item
+Gnus supports @acronym{PGP} (RFC 1991/2440), @acronym{PGP/MIME} (RFC
+2015/3156) and @acronym{S/MIME} (RFC 2630--2633).
+
+It needs an external @acronym{S/MIME} and OpenPGP implementation, but no
+additional Lisp libraries.  This add several menu items to the
+Attachments menu, and @kbd{C-c RET} key bindings, when composing
+messages.  This also obsoletes @code{gnus-article-hide-pgp-hook}.
+
+@item
+@acronym{MML} (Mime compose) prefix changed from @kbd{M-m} to @kbd{C-c
+C-m}.
+
+This change was made to avoid conflict with the standard binding of
+@code{back-to-indentation}, which is also useful in message mode.
+
+@item
+The default for @code{message-forward-show-mml} changed to the symbol
+@code{best}.
+
+The behavior for the @code{best} value is to show @acronym{MML} (i.e.,
+convert to @acronym{MIME}) when appropriate.  @acronym{MML} will not be
+used when forwarding signed or encrypted messages, as the conversion
+invalidate the digital signature.
+
+@item
+If @code{auto-compression-mode} is enabled, attachments are automatically
+decompressed when activated.
+@c FIXME: Does this affect article or message mode?
+
+@item
+Support for non-@acronym{ASCII} domain names
+
+Message supports non-@acronym{ASCII} domain names in From:, To: and
+Cc: and will query you whether to perform encoding when you try to
+send a message.  The variable @code{message-use-idna} controls this.
+Gnus will also decode non-@acronym{ASCII} domain names in From:, To:
+and Cc: when you view a message.  The variable @code{gnus-use-idna}
+controls this.
+
+@item You can now drag and drop attachments to the Message buffer.
+See @code{mml-dnd-protocol-alist} and @code{mml-dnd-attach-options}.
+@xref{MIME, ,MIME, message, Message Manual}.
+@c New in 5.10.9 / 5.11 (Emacs 22.1)
+
+@item @code{auto-fill-mode} is enabled by default in Message mode.
+See @code{message-fill-column}.  @xref{Various Message Variables, ,
+Message Headers, message, Message Manual}.
+@c New in Gnus 5.10.12 / 5.11 (Emacs 22.3)
+
+@end itemize
+
+@item Changes in back ends
+@c ***********************
+
+@itemize @bullet
+@item
+Gnus can display RSS newsfeeds as a newsgroup.  @xref{RSS}.
+
+@item
+The nndoc back end now supports mailman digests and exim bounces.
+
+@item
+Gnus supports Maildir groups.
+
+Gnus includes a new back end @file{nnmaildir.el}.  @xref{Maildir}.
+
+@item
+The nnml and nnfolder back ends store marks for each groups.
+
+This makes it possible to take backup of nnml/nnfolder servers/groups
+separately of @file{~/.newsrc.eld}, while preserving marks.  It also
+makes it possible to share articles and marks between users (without
+sharing the @file{~/.newsrc.eld} file) within, e.g., a department.  It
+works by storing the marks stored in @file{~/.newsrc.eld} in a per-group
+file @file{.marks} (for nnml) and @file{@var{groupname}.mrk} (for
+nnfolder, named @var{groupname}).  If the nnml/nnfolder is moved to
+another machine, Gnus will automatically use the @file{.marks} or
+@file{.mrk} file instead of the information in @file{~/.newsrc.eld}.
+The new server variables @code{nnml-marks-is-evil} and
+@code{nnfolder-marks-is-evil} can be used to disable this feature.
+
+@end itemize
+
+@item Appearance
+@c *************
+
+@itemize @bullet
+
+@item
+The menu bar item (in Group and Summary buffer) named ``Misc'' has
+been renamed to ``Gnus''.
+
+@item
+The menu bar item (in Message mode) named ``@acronym{MML}'' has been
+renamed to ``Attachments''.  Note that this menu also contains security
+related stuff, like signing and encryption (@pxref{Security, Security,,
+message, Message Manual}).
+
+@item
+The tool bars have been updated to use GNOME icons in Group, Summary and
+Message mode.  You can also customize the tool bars: @kbd{M-x
+customize-apropos RET -tool-bar$} should get you started.  This is a new
+feature in Gnus 5.10.10.  (Only for Emacs, not in XEmacs.)
+
+@item The tool bar icons are now (de)activated correctly
+in the group buffer, see the variable @code{gnus-group-update-tool-bar}.
+Its default value depends on your Emacs version.  This is a new feature
+in Gnus 5.10.9.
+@end itemize
+
+
+@item Miscellaneous changes
+@c ************************
+
+@itemize @bullet
+
+@item
+@code{gnus-agent}
+
+The Gnus Agent has seen a major updated and is now enabled by default,
+and all nntp and nnimap servers from @code{gnus-select-method} and
+@code{gnus-secondary-select-method} are agentized by default.  Earlier
+only the server in @code{gnus-select-method} was agentized by the
+default, and the agent was disabled by default.  When the agent is
+enabled, headers are now also retrieved from the Agent cache instead
+of the back ends when possible.  Earlier this only happened in the
+unplugged state.  You can enroll or remove servers with @kbd{J a} and
+@kbd{J r} in the server buffer.  Gnus will not download articles into
+the Agent cache, unless you instruct it to do so, though, by using
+@kbd{J u} or @kbd{J s} from the Group buffer.  You revert to the old
+behavior of having the Agent disabled with @code{(setq gnus-agent
+nil)}.  Note that putting @code{(gnus-agentize)} in @file{~/.gnus.el}
+is not needed any more.
+
+@item
+Gnus reads the @acronym{NOV} and articles in the Agent if plugged.
+
+If one reads an article while plugged, and the article already exists
+in the Agent, it won't get downloaded once more.  @code{(setq
+gnus-agent-cache nil)} reverts to the old behavior.
+
+@item
+Dired integration
+
+@code{gnus-dired-minor-mode} (see @ref{Other modes}) installs key
+bindings in dired buffers to send a file as an attachment, open a file
+using the appropriate mailcap entry, and print a file using the mailcap
+entry.
+
+@item
+The format spec @code{%C} for positioning point has changed to @code{%*}.
+
+@item
+@code{gnus-slave-unplugged}
+
+A new command which starts Gnus offline in slave mode.
+
+@end itemize
+
+@end itemize
+
+@node No Gnus
+@subsubsection No Gnus
+@cindex No Gnus
+
+New features in No Gnus:
+@c FIXME: Gnus 5.12?
+
+@include gnus-news.texi
+
+@node Ma Gnus
+@subsubsection Ma Gnus
+@cindex Ma Gnus
+
+I'm sure there will be lots of text here.  It's really spelled 真
+Gnus.
+
+New features in Ma Gnus:
+
+@itemize @bullet
+
+@item Installation changes
+@c ***********************
+
+@itemize @bullet
+@item
+Lisp source files and info files to be installed will be compressed by
+gzip by default.
+
+If you don't want those files to be compressed, use the configure option
+@samp{--without-compress-install}.  Lisp source files that don't have
+the compiled elc version in the installation directory will not be
+compressed.
+
+@end itemize
+
+@item Changes in summary and article mode
+@c **************************************
+
+@itemize @bullet
+
+@item
+By default, @acronym{MIME} part buttons for attachments (if any) will
+appear in the end of the article header in addition to the bottom of the
+article body, so you can easily find them without scrolling the article
+again and again.  @xref{MIME Commands}.
+
+@end itemize
+
+@item Changes in Message mode and related Gnus features
+@c ****************************************************
+
+@itemize @bullet
+
+@item
+The new hooks @code{gnus-gcc-pre-body-encode-hook} and
+@code{gnus-gcc-post-body-encode-hook} are run before/after encoding
+the message body of the Gcc copy of a sent message.  See
+@xref{Archived Messages}.
+
+@end itemize
+
+@end itemize
+
+@iftex
+
+@page
+@node The Manual
+@section The Manual
+@cindex colophon
+@cindex manual
+
+This manual was generated from a TeXinfo file and then run through
+either @code{texi2dvi}
+@iflatex
+or my own home-brewed TeXinfo to \LaTeX\ transformer,
+and then run through @code{latex} and @code{dvips}
+@end iflatex
+to get what you hold in your hands now.
+
+The following conventions have been used:
+
+@enumerate
+
+@item
+This is a @samp{string}
+
+@item
+This is a @kbd{keystroke}
+
+@item
+This is a @file{file}
+
+@item
+This is a @code{symbol}
+
+@end enumerate
+
+So if I were to say ``set @code{flargnoze} to @samp{yes}'', that would
+mean:
+
+@lisp
+(setq flargnoze "yes")
+@end lisp
+
+If I say ``set @code{flumphel} to @code{yes}'', that would mean:
+
+@lisp
+(setq flumphel 'yes)
+@end lisp
+
+@samp{yes} and @code{yes} are two @emph{very} different things---don't
+ever get them confused.
+
+@iflatex
+@c @head
+Of course, everything in this manual is of vital interest, so you should
+read it all.  Several times.  However, if you feel like skimming the
+manual, look for that gnu head you should see in the margin over
+there---it means that what's being discussed is of more importance than
+the rest of the stuff.  (On the other hand, if everything is infinitely
+important, how can anything be more important than that?  Just one more
+of the mysteries of this world, I guess.)
+@end iflatex
+
+@end iftex
+
+
+@node On Writing Manuals
+@section On Writing Manuals
+
+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
+implementation.  Writing the documentation and writing the code go 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
+started with Gnus.
+
+That would be a totally different book, that should be written using the
+reference manual as source material.  It would look quite different.
+
+
+@page
+@node Terminology
+@section Terminology
+
+@cindex terminology
+@table @dfn
+
+@item news
+@cindex news
+This is what you are supposed to use this thing for---reading news.
+News is generally fetched from a nearby @acronym{NNTP} server, and is
+generally publicly available to everybody.  If you post news, the entire
+world is likely to read just what you have written, and they'll all
+snigger mischievously.  Behind your back.
+
+@item mail
+@cindex mail
+Everything that's delivered to you personally is mail.  Some news/mail
+readers (like Gnus) blur the distinction between mail and news, but
+there is a difference.  Mail is private.  News is public.  Mailing is
+not posting, and replying is not following up.
+
+@item reply
+@cindex reply
+Send a mail to the person who has written what you are reading.
+
+@item follow up
+@cindex follow up
+Post an article to the current newsgroup responding to the article you
+are reading.
+
+@item back end
+@cindex back end
+Gnus considers mail and news to be mostly the same, really.  The only
+difference is how to access the actual articles.  News articles are
+commonly fetched via the protocol @acronym{NNTP}, whereas mail
+messages could be read from a file on the local disk.  The internal
+architecture of Gnus thus comprises a ``front end'' and a number of
+``back ends''.  Internally, when you enter a group (by hitting
+@key{RET}, say), you thereby invoke a function in the front end in
+Gnus.  The front end then ``talks'' to a back end and says things like
+``Give me the list of articles in the foo group'' or ``Show me article
+number 4711''.
+
+So a back end mainly defines either a protocol (the @code{nntp} back
+end accesses news via @acronym{NNTP}, the @code{nnimap} back end
+accesses mail via @acronym{IMAP}) or a file format and directory
+layout (the @code{nnspool} back end accesses news via the common
+``spool directory'' format, the @code{nnml} back end access mail via a
+file format and directory layout that's quite similar).
+
+Gnus does not handle the underlying media, so to speak---this is all
+done by the back ends.  A back end is a collection of functions to
+access the articles.
+
+However, sometimes the term ``back end'' is also used where ``server''
+would have been more appropriate.  And then there is the term ``select
+method'' which can mean either.  The Gnus terminology can be quite
+confusing.
+
+@item native
+@cindex native
+Gnus will always use one method (and back end) as the @dfn{native}, or
+default, way of getting news.  Groups from the native select method
+have names like @samp{gnu.emacs.gnus}.
+
+@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 back ends
+for getting news.  Foreign groups have names like
+@samp{nntp+news.gmane.org:gmane.emacs.gnus.devel}.
+
+@item secondary
+@cindex secondary
+Secondary back ends are somewhere half-way between being native and
+being foreign, but they mostly act like they are native, but they, too
+have names like @samp{nntp+news.gmane.org:gmane.emacs.gnus.devel}.
+
+@item article
+@cindex article
+A message that has been posted as news.
+
+@item mail message
+@cindex mail message
+A message that has been mailed.
+
+@item message
+@cindex message
+A mail message or news article
+
+@item head
+@cindex head
+The top part of a message, where administrative information (etc.)@: is
+put.
+
+@item body
+@cindex body
+The rest of an article.  Everything not in the head is in the
+body.
+
+@item header
+@cindex header
+A line from the head of an article.
+
+@item headers
+@cindex headers
+A collection of such lines, or a collection of heads.  Or even a
+collection of @acronym{NOV} lines.
+
+@item @acronym{NOV}
+@cindex @acronym{NOV}
+@acronym{NOV} stands for News OverView, which is a type of news server
+header which provide datas containing the condensed header information
+of articles.  They are produced by the server itself; in the @code{nntp}
+back end Gnus uses the ones that the @acronym{NNTP} server makes, but
+Gnus makes them by itself for some backends (in particular, @code{nnml}).
+
+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.
+
+The @acronym{NOV} data consist of one or more text lines (@pxref{Text
+Lines, ,Motion by Text Lines, elisp, The Emacs Lisp Reference Manual})
+where each line has the header information of one article.  The header
+information is a tab-separated series of the header's contents including
+an article number, a subject, an author, a date, a message-id,
+references, etc.
+
+Those data enable Gnus to generate summary lines quickly.  However, if
+the server does not support @acronym{NOV} or you disable it purposely or
+for some reason, Gnus will try to generate the header information by
+parsing each article's headers one by one.  It will take time.
+Therefore, it is not usually a good idea to set nn*-nov-is-evil
+(@pxref{Slow/Expensive Connection}) to a non-@code{nil} value unless you
+know that the server makes wrong @acronym{NOV} data.
+
+@item level
+@cindex levels
+Each group is subscribed at some @dfn{level} or other (1--9).  The ones
+that have a lower level are ``more'' subscribed than the groups with a
+higher level.  In fact, groups on levels 1--5 are considered
+@dfn{subscribed}; 6--7 are @dfn{unsubscribed}; 8 are @dfn{zombies}; and 9
+are @dfn{killed}.  Commands for listing groups and scanning for new
+articles will all use the numeric prefix as @dfn{working level}.
+
+@item killed groups
+@cindex killed groups
+No information on killed groups is stored or updated, which makes killed
+groups much easier to handle than subscribed groups.
+
+@item zombie groups
+@cindex zombie groups
+Just like killed groups, only slightly less dead.
+
+@item active file
+@cindex active file
+The news server has to keep track of what articles it carries, and what
+groups exist.  All this information in stored in the active file, which
+is rather large, as you might surmise.
+
+@item bogus groups
+@cindex bogus groups
+A group that exists in the @file{.newsrc} file, but isn't known to the
+server (i.e.,  it isn't in the active file), is a @emph{bogus group}.
+This means that the group probably doesn't exist (any more).
+
+@item activating
+@cindex activating groups
+The act of asking the server for info on a group and computing the
+number of unread articles is called @dfn{activating the group}.
+Un-activated groups are listed with @samp{*} in the group buffer.
+
+@item spool
+@cindex spool
+News servers store their articles locally in one fashion or other.
+One old-fashioned storage method is to have just one file per
+article.  That's called a ``traditional spool''.
+
+@item server
+@cindex server
+A machine one can connect to and get news (or mail) from.
+
+@item select method
+@cindex select method
+A structure that specifies the back end, the server and the virtual
+server settings.
+
+@item virtual server
+@cindex virtual server
+A named select method.  Since a select method defines all there is to
+know about connecting to a (physical) server, taking the thing as a
+whole is a virtual server.
+
+@item washing
+@cindex washing
+Taking a buffer and running it through a filter of some sort.  The
+result will (more often than not) be cleaner and more pleasing than the
+original.
+
+@item ephemeral groups
+@cindex ephemeral groups
+@cindex temporary groups
+Most groups store data on what articles you have read.  @dfn{Ephemeral}
+groups are groups that will have no data stored---when you exit the
+group, it'll disappear into the aether.
+
+@item solid groups
+@cindex solid groups
+This is the opposite of ephemeral groups.  All groups listed in the
+group buffer are solid groups.
+
+@item sparse articles
+@cindex sparse articles
+These are article placeholders shown in the summary buffer when
+@code{gnus-build-sparse-threads} has been switched on.
+
+@item threading
+@cindex threading
+To put responses to articles directly after the articles they respond
+to---in a hierarchical fashion.
+
+@item root
+@cindex root
+@cindex thread root
+The first article in a thread is the root.  It is the ancestor of all
+articles in the thread.
+
+@item parent
+@cindex parent
+An article that has responses.
+
+@item child
+@cindex child
+An article that responds to a different article---its parent.
+
+@item digest
+@cindex digest
+A collection of messages in one file.  The most common digest format is
+specified by RFC 1153.
+
+@item splitting
+@cindex splitting, terminology
+@cindex mail sorting
+@cindex mail filtering (splitting)
+The action of sorting your emails according to certain rules.  Sometimes
+incorrectly called mail filtering.
+
+@end table
+
+
+@page
+@node Customization
+@section Customization
+@cindex general customization
+
+All variables are properly documented elsewhere in this manual.  This
+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.
+@end menu
+
+
+@node Slow/Expensive Connection
+@subsection Slow/Expensive Connection
+
+If you run Emacs on a machine locally, and get your news from a machine
+over some very thin strings, you want to cut down on the amount of data
+Gnus has to get from the server.
+
+@table @code
+
+@item gnus-read-active-file
+Set this to @code{nil}, which will inhibit Gnus from requesting the
+entire active file from the server.  This file is often very large.  You
+also have to set @code{gnus-check-new-newsgroups} and
+@code{gnus-check-bogus-newsgroups} to @code{nil} to make sure that Gnus
+doesn't suddenly decide to fetch the active file anyway.
+
+@item gnus-nov-is-evil
+@vindex gnus-nov-is-evil
+Usually this one must @emph{always} be @code{nil} (which is the
+default).  If, for example, you wish to not use @acronym{NOV}
+(@pxref{Terminology}) with the @code{nntp} back end (@pxref{Crosspost
+Handling}), set @code{nntp-nov-is-evil} to a non-@code{nil} value
+instead of setting this.  But you normally do not need to set
+@code{nntp-nov-is-evil} since Gnus by itself will detect whether the
+@acronym{NNTP} server supports @acronym{NOV}.  Anyway, grabbing article
+headers from the @acronym{NNTP} server will not be very fast if you tell
+Gnus not to use @acronym{NOV}.
+
+As the variables for the other back ends, there are
+@code{nndiary-nov-is-evil}, @code{nndir-nov-is-evil},
+@code{nnfolder-nov-is-evil}, @code{nnimap-nov-is-evil},
+@code{nnml-nov-is-evil}, and @code{nnspool-nov-is-evil}.  Note that a
+non-@code{nil} value for @code{gnus-nov-is-evil} overrides all those
+variables.
+@end table
+
+
+@node Slow Terminal Connection
+@subsection Slow Terminal Connection
+
+Let's say you use your home computer for dialing up the system that runs
+Emacs and Gnus.  If your modem is slow, you want to reduce (as much as
+possible) the amount of data sent over the wires.
+
+@table @code
+
+@item gnus-auto-center-summary
+Set this to @code{nil} to inhibit Gnus from re-centering the summary
+buffer all the time.  If it is @code{vertical}, do only vertical
+re-centering.  If it is neither @code{nil} nor @code{vertical}, do both
+horizontal and vertical recentering.
+
+@item gnus-visible-headers
+Cut down on the headers included in the articles to the
+minimum.  You can, in fact, make do without them altogether---most of the
+useful data is in the summary buffer, anyway.  Set this variable to
+@samp{^NEVVVVER} or @samp{From:}, or whatever you feel you need.
+
+Use the following to enable all the available hiding features:
+@lisp
+(setq gnus-treat-hide-headers 'head
+      gnus-treat-hide-signature t
+      gnus-treat-hide-citation t)
+@end lisp
+
+@item gnus-use-full-window
+By setting this to @code{nil}, you can make all the windows smaller.
+While this doesn't really cut down much generally, it means that you
+have to see smaller portions of articles before deciding that you didn't
+want to read them anyway.
+
+@item gnus-thread-hide-subtree
+If this is non-@code{nil}, all threads in the summary buffer will be
+hidden initially.
+
+
+@item gnus-updated-mode-lines
+If this is @code{nil}, Gnus will not put information in the buffer mode
+lines, which might save some time.
+@end table
+
+
+@node Little Disk Space
+@subsection Little Disk Space
+@cindex disk space
+
+The startup files can get rather large, so you may want to cut their
+sizes a bit if you are running out of space.
+
+@table @code
+
+@item gnus-save-newsrc-file
+If this is @code{nil}, Gnus will never save @file{.newsrc}---it will
+only save @file{.newsrc.eld}.  This means that you will not be able to
+use any other newsreaders than Gnus.  This variable is @code{t} by
+default.
+
+@item gnus-read-newsrc-file
+If this is @code{nil}, Gnus will never read @file{.newsrc}---it will
+only read @file{.newsrc.eld}.  This means that you will not be able to
+use any other newsreaders than Gnus.  This variable is @code{t} by
+default.
+
+@item gnus-save-killed-list
+If this is @code{nil}, Gnus will not save the list of dead groups.  You
+should also set @code{gnus-check-new-newsgroups} to @code{ask-server}
+and @code{gnus-check-bogus-newsgroups} to @code{nil} if you set this
+variable to @code{nil}.  This variable is @code{t} by default.
+
+@end table
+
+
+@node Slow Machine
+@subsection Slow Machine
+@cindex slow machine
+
+If you have a slow machine, or are just really impatient, there are a
+few things you can do to make Gnus run faster.
+
+Set @code{gnus-check-new-newsgroups} and
+@code{gnus-check-bogus-newsgroups} to @code{nil} to make startup faster.
+
+Set @code{gnus-show-threads}, @code{gnus-use-cross-reference} and
+@code{gnus-nov-is-evil} to @code{nil} to make entering and exiting the
+summary buffer faster.  Also @pxref{Slow/Expensive Connection}.
+
+
+@page
+@node Troubleshooting
+@section Troubleshooting
+@cindex troubleshooting
+
+Gnus works @emph{so} well straight out of the box---I can't imagine any
+problems, really.
+
+Ahem.
+
+@enumerate
+
+@item
+Make sure your computer is switched on.
+
+@item
+Make sure that you really load the current Gnus version.  If you have
+been running @sc{gnus}, you need to exit Emacs and start it up again before
+Gnus will work.
+
+@item
+Try doing an @kbd{M-x gnus-version}.  If you get something that looks
+like @c
+@samp{Ma Gnus v0.14} @c Adjust ../Makefile.in if you change this line!
+@c
+you have the right files loaded.  Otherwise you have some old @file{.el}
+files lying around.  Delete these.
+
+@item
+Read the help group (@kbd{G h} in the group buffer) for a
+@acronym{FAQ} and a how-to.
+
+@item
+@vindex max-lisp-eval-depth
+Gnus works on many recursive structures, and in some extreme (and very
+rare) cases Gnus may recurse down ``too deeply'' and Emacs will beep at
+you.  If this happens to you, set @code{max-lisp-eval-depth} to 500 or
+something like that.
+@end enumerate
+
+If all else fails, report the problem as a bug.
+
+@cindex bugs
+@cindex reporting bugs
+
+@kindex M-x gnus-bug
+@findex gnus-bug
+If you find a bug in Gnus, you can report it with the @kbd{M-x gnus-bug}
+command.  @kbd{M-x set-variable RET debug-on-error RET t RET}, and send
+me the backtrace.  I will fix bugs, but I can only fix them if you send
+me a precise description as to how to reproduce the bug.
+
+You really can never be too detailed in a bug report.  Always use the
+@kbd{M-x gnus-bug} command when you make bug reports, even if it creates
+a 10Kb mail each time you use it, and even if you have sent me your
+environment 500 times before.  I don't care.  I want the full info each
+time.
+
+It is also important to remember that I have no memory whatsoever.  If
+you send a bug report, and I send you a reply, and then you just send
+back ``No, it's not! Moron!'', I will have no idea what you are
+insulting me about.  Always over-explain everything.  It's much easier
+for all of us---if I don't have all the information I need, I will just
+mail you and ask for more info, and everything takes more time.
+
+If the problem you're seeing is very visual, and you can't quite explain
+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}.
+
+@cindex edebug
+If you want to debug your problem further before reporting, possibly
+in order to solve the problem yourself and send a patch, you can use
+edebug.  Debugging Lisp code is documented in the Elisp manual
+(@pxref{Debugging, , Debugging Lisp Programs, elisp, The GNU Emacs
+Lisp Reference Manual}).  To get you started with edebug, consider if
+you discover some weird behavior when pressing @kbd{c}, the first
+step is to do @kbd{C-h k c} and click on the hyperlink (Emacs only) in
+the documentation buffer that leads you to the function definition,
+then press @kbd{M-x edebug-defun RET} with point inside that function,
+return to Gnus and press @kbd{c} to invoke the code.  You will be
+placed in the lisp buffer and can single step using @kbd{SPC} and
+evaluate expressions using @kbd{M-:} or inspect variables using
+@kbd{C-h v}, abort execution with @kbd{q}, and resume execution with
+@kbd{c} or @kbd{g}.
+
+@cindex elp
+@cindex profile
+@cindex slow
+Sometimes, a problem do not directly generate an elisp error but
+manifests itself by causing Gnus to be very slow.  In these cases, you
+can use @kbd{M-x toggle-debug-on-quit} and press @kbd{C-g} when things are
+slow, and then try to analyze the backtrace (repeating the procedure
+helps isolating the real problem areas).
+
+A fancier approach is to use the elisp profiler, ELP@.  The profiler is
+(or should be) fully documented elsewhere, but to get you started
+there are a few steps that need to be followed.  First, instrument the
+part of Gnus you are interested in for profiling, e.g., @kbd{M-x
+elp-instrument-package RET gnus} or @kbd{M-x elp-instrument-package
+RET message}.  Then perform the operation that is slow and press
+@kbd{M-x elp-results}.  You will then see which operations that takes
+time, and can debug them further.  If the entire operation takes much
+longer than the time spent in the slowest function in the profiler
+output, you probably profiled the wrong part of Gnus.  To reset
+profiling statistics, use @kbd{M-x elp-reset-all}.  @kbd{M-x
+elp-restore-all} is supposed to remove profiling, but given the
+complexities and dynamic code generation in Gnus, it might not always
+work perfectly.
+
+@cindex gnu.emacs.gnus
+@cindex ding mailing list
+If you just need help, you are better off asking on
+@samp{gnu.emacs.gnus}.  I'm not very helpful.  You can also ask on
+@email{ding@@gnus.org, the ding mailing list}.  Write to
+@email{ding-request@@gnus.org} to subscribe.
+
+
+@page
+@node Gnus Reference Guide
+@section Gnus Reference Guide
+
+It is my hope that other people will figure out smart stuff that Gnus
+can do, and that other people will write those smart things as well.  To
+facilitate that I thought it would be a good idea to describe the inner
+workings of Gnus.  And some of the not-so-inner workings, while I'm at
+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
+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.
+* 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
+
+
+@node Gnus Utility Functions
+@subsection Gnus Utility Functions
+@cindex Gnus utility functions
+@cindex utility functions
+@cindex functions
+@cindex internal variables
+
+When writing small functions to be run from hooks (and stuff), it's
+vital to have access to the Gnus internal functions and variables.
+Below is a list of the most common ones.
+
+@table @code
+
+@item gnus-newsgroup-name
+@vindex gnus-newsgroup-name
+This variable holds the name of the current newsgroup.
+
+@item gnus-find-method-for-group
+@findex gnus-find-method-for-group
+A function that returns the select method for @var{group}.
+
+@item gnus-group-real-name
+@findex gnus-group-real-name
+Takes a full (prefixed) Gnus group name, and returns the unprefixed
+name.
+
+@item gnus-group-prefixed-name
+@findex gnus-group-prefixed-name
+Takes an unprefixed group name and a select method, and returns the full
+(prefixed) Gnus group name.
+
+@item gnus-get-info
+@findex gnus-get-info
+Returns the group info list for @var{group} (@pxref{Group Info}).
+
+@item gnus-group-unread
+@findex gnus-group-unread
+The number of unread articles in @var{group}, or @code{t} if that is
+unknown.
+
+@item gnus-active
+@findex gnus-active
+The active entry (i.e., a cons cell containing the lowest and highest
+article numbers) for @var{group}.
+
+@item gnus-set-active
+@findex gnus-set-active
+Set the active entry for @var{group}.
+
+@item gnus-add-current-to-buffer-list
+@findex gnus-add-current-to-buffer-list
+Adds the current buffer to the list of buffers to be killed on Gnus
+exit.
+
+@item gnus-continuum-version
+@findex gnus-continuum-version
+Takes a Gnus version string as a parameter and returns a floating point
+number.  Earlier versions will always get a lower number than later
+versions.
+
+@item gnus-group-read-only-p
+@findex gnus-group-read-only-p
+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 back end.
+
+@item gnus-ephemeral-group-p
+@findex gnus-ephemeral-group-p
+Says whether @var{group} is ephemeral or not.
+
+@item gnus-server-to-method
+@findex gnus-server-to-method
+Returns the select method corresponding to @var{server}.
+
+@item gnus-server-equal
+@findex gnus-server-equal
+Says whether two virtual servers are essentially equal.  For instance,
+two virtual servers may have server parameters in different order, but
+this function will consider them equal.
+
+@item gnus-group-native-p
+@findex gnus-group-native-p
+Says whether @var{group} is native or not.
+
+@item gnus-group-secondary-p
+@findex gnus-group-secondary-p
+Says whether @var{group} is secondary or not.
+
+@item gnus-group-foreign-p
+@findex gnus-group-foreign-p
+Says whether @var{group} is foreign or not.
+
+@item gnus-group-find-parameter
+@findex gnus-group-find-parameter
+Returns the parameter list of @var{group} (@pxref{Group Parameters}).
+If given a second parameter, returns the value of that parameter for
+@var{group}.
+
+@item gnus-group-set-parameter
+@findex gnus-group-set-parameter
+Takes three parameters; @var{group}, @var{parameter} and @var{value}.
+
+@item gnus-narrow-to-body
+@findex gnus-narrow-to-body
+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 back end
+@var{group} comes from supports @var{function}, return non-@code{nil}.
+
+@lisp
+(gnus-check-backend-function "request-scan" "nnml:misc")
+@result{} t
+@end lisp
+
+@item gnus-read-method
+@findex gnus-read-method
+Prompts the user for a select method.
+
+@end table
+
+
+@node Back End Interface
+@subsection Back End Interface
+
+Gnus doesn't know anything about @acronym{NNTP}, spools, mail or virtual
+groups.  It only knows how to talk to @dfn{virtual servers}.  A virtual
+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 back end---say @code{nntp}---on
+something, it will normally include a virtual server name in the
+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.
+
+Note that a virtual server name has no relation to some physical server
+name.  Take this example:
+
+@lisp
+(nntp "odd-one"
+      (nntp-address "ifi.uio.no")
+      (nntp-port-number 4324))
+@end lisp
+
+Here the virtual server name is @samp{odd-one} while the name of
+the physical server is @samp{ifi.uio.no}.
+
+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},
+which must be present, and @dfn{optional functions}, which Gnus will
+always check for presence before attempting to call 'em.
+
+All these functions are expected to return data in the buffer
+@code{nntp-server-buffer} (@samp{ *nntpd*}), which is somewhat
+unfortunately named, but we'll have to live with it.  When I talk about
+@dfn{resulting data}, I always refer to the data in that buffer.  When I
+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 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.
+
+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.
+
+Note that by convention, back ends are named @code{nnsomething}, but
+Gnus also comes with some @code{nnnotbackends}, such as
+@file{nnheader.el}, @file{nnmail.el} and @file{nnoo.el}.
+
+In the examples and definitions I will refer to the imaginary back end
+@code{nnchoke}.
+
+@cindex @code{nnchoke}
+
+@menu
+* 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 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 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 @acronym{NOV} lines, and the result
+value should either be @code{headers} or @code{nov} to reflect this.
+This might later be expanded to @code{various}, which will be a mixture
+of HEADs and @acronym{NOV} lines, but this is currently not supported by Gnus.
+
+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 back end finds it
+cumbersome to follow the request.  If this is non-@code{nil} and not a
+number, do maximum fetches.
+
+Here's an example HEAD:
+
+@example
+221 1056 Article retrieved.
+Path: ifi.uio.no!sturles
+From: sturles@@ifi.uio.no (Sturle Sunde)
+Newsgroups: ifi.discussion
+Subject: Re: Something very droll
+Date: 27 Oct 1994 14:02:57 +0100
+Organization: Dept. of Informatics, University of Oslo, Norway
+Lines: 26
+Message-ID: <38o8e1$a0o@@holmenkollen.ifi.uio.no>
+References: <38jdmq$4qu@@visbur.ifi.uio.no>
+NNTP-Posting-Host: holmenkollen.ifi.uio.no
+.
+@end example
+
+So a @code{headers} return value would imply that there's a number of
+these in the data buffer.
+
+Here's a BNF definition of such a buffer:
+
+@example
+headers        = *head
+head           = error / valid-head
+error-message  = [ "4" / "5" ] 2number " " <error message> eol
+valid-head     = valid-message *header "." eol
+valid-message  = "221 " <number> " Article retrieved." eol
+header         = <text> eol
+@end example
+
+@cindex BNF
+(The version of BNF used here is the one used in RFC822.)
+
+If the return value is @code{nov}, the data buffer should contain
+@dfn{network overview database} lines.  These are basically fields
+separated by tabs.
+
+@example
+nov-buffer = *nov-line
+nov-line   = field 7*8[ <TAB> field ] eol
+field      = <text except TAB>
+@end example
+
+For a closer look at what should be in those fields,
+@pxref{Headers}.
+
+
+@item (nnchoke-open-server SERVER &optional DEFINITIONS)
+
+@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 back end
+may then choose to refuse further attempts at connecting to this
+server.  In fact, it should do so.
+
+If the server is opened already, this function should return a
+non-@code{nil} value.  There should be no data returned.
+
+
+@item (nnchoke-close-server &optional SERVER)
+
+Close connection to @var{server} and free all resources connected
+to it.  Return @code{nil} if the server couldn't be closed for some
+reason.
+
+There should be no data returned.
+
+
+@item (nnchoke-request-close)
+
+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.
+
+There should be no data returned.
+
+
+@item (nnchoke-server-opened &optional SERVER)
+
+If @var{server} is the current virtual server, and the connection to the
+physical server is alive, then this function should return a
+non-@code{nil} value.  This function should under no circumstances
+attempt to reconnect to a server we have lost connection to.
+
+There should be no data returned.
+
+
+@item (nnchoke-status-message &optional SERVER)
+
+This function should return the last error message from @var{server}.
+
+There should be no data returned.
+
+
+@item (nnchoke-request-article ARTICLE &optional GROUP SERVER TO-BUFFER)
+
+The result data from this function should be the article specified by
+@var{article}.  This might either be a @code{Message-ID} or a number.
+It is optional whether to implement retrieval by @code{Message-ID}, but
+it would be nice if that were possible.
+
+If @var{to-buffer} is non-@code{nil}, the result data should be returned
+in this buffer instead of the normal data buffer.  This is to make it
+possible to avoid copying large amounts of data from one buffer to
+another, while Gnus mainly requests articles to be inserted directly
+into its article buffer.
+
+If it is at all possible, this function should return a cons cell where
+the @code{car} is the group name the article was fetched from, and the @code{cdr} is
+the article number.  This will enable Gnus to find out what the real
+group and article numbers are when fetching articles by
+@code{Message-ID}.  If this isn't possible, @code{t} should be returned
+on successful article retrieval.
+
+
+@item (nnchoke-request-group GROUP &optional SERVER FAST INFO)
+
+Get data on @var{group}.  This function also has the side effect of
+making @var{group} the current group.
+
+If @var{fast}, don't bother to return useful data, just make @var{group}
+the current group.
+
+If @var{info}, it allows the backend to update the group info
+structure.
+
+Here's an example of some result data and a definition of the same:
+
+@example
+211 56 1000 1059 ifi.discussion
+@end example
+
+The first number is the status, which should be 211.  Next is the
+total number of articles in the group, the lowest article number, the
+highest article number, and finally the group name.  Note that the total
+number of articles may be less than one might think while just
+considering the highest and lowest article numbers, but some articles
+may have been canceled.  Gnus just discards the total-number, so
+whether one should take the bother to generate it properly (if that is a
+problem) is left as an exercise to the reader.  If the group contains no
+articles, the lowest article number should be reported as 1 and the
+highest as 0.
+
+@example
+group-status = [ error / info ] eol
+error        = [ "4" / "5" ] 2<number> " " <Error message>
+info         = "211 " 3* [ <number> " " ] <string>
+@end example
+
+
+@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 back ends.
+
+There should be no data returned.
+
+
+@item (nnchoke-request-list &optional SERVER)
+
+Return a list of all groups available on @var{server}.  And that means
+@emph{all}.
+
+Here's an example from a server that only carries two groups:
+
+@example
+ifi.test 0000002200 0000002000 y
+ifi.discussion 3324 3300 n
+@end example
+
+On each line we have a group name, then the highest article number in
+that group, the lowest article number, and finally a flag.  If the group
+contains no articles, the lowest article number should be reported as 1
+and the highest as 0.
+
+@example
+active-file = *active-line
+active-line = name " " <number> " " <number> " " flags eol
+name        = <string>
+flags       = "n" / "y" / "m" / "x" / "j" / "=" name
+@end example
+
+The flag says whether the group is read-only (@samp{n}), is moderated
+(@samp{m}), is dead (@samp{x}), is aliased to some other group
+(@samp{=other-group}) or none of the above (@samp{y}).
+
+
+@item (nnchoke-request-post &optional SERVER)
+
+This function should post the current buffer.  It might return whether
+the posting was successful or not, but that's not required.  If, for
+instance, the posting is done asynchronously, it has generally not been
+completed by the time this function concludes.  In that case, this
+function should set up some kind of sentinel to beep the user loud and
+clear if the posting could not be completed.
+
+There should be no result data from this function.
+
+@end table
+
+
+@node Optional Back End Functions
+@subsubsection Optional Back End Functions
+
+@table @code
+
+@item (nnchoke-retrieve-groups GROUPS &optional SERVER)
+
+@var{groups} is a list of groups, and this function should request data
+on all those groups.  How it does it is of no concern to Gnus, but it
+should attempt to do this in a speedy fashion.
+
+The return value of this function can be either @code{active} or
+@code{group}, which says what the format of the result data is.  The
+former is in the same format as the data from
+@code{nnchoke-request-list}, while the latter is a buffer full of lines
+in the same format as @code{nnchoke-request-group} gives.
+
+@example
+group-buffer = *active-line / *group-status
+@end example
+
+
+@item (nnchoke-request-update-info GROUP INFO &optional SERVER)
+
+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 a non-@code{nil} value (exceptionally,
+@code{nntp-request-update-info} always returns @code{nil} not to waste
+the network resources).
+
+There should be no result data from this function.
+
+
+@item (nnchoke-request-type GROUP &optional ARTICLE)
+
+When the user issues commands for ``sending news'' (@kbd{F} in the
+summary buffer, for instance), Gnus has to know whether the article the
+user is following up on is news or mail.  This function should return
+@code{news} if @var{article} in @var{group} is news, @code{mail} if it
+is mail and @code{unknown} if the type can't be decided.  (The
+@var{article} parameter is necessary in @code{nnvirtual} groups which
+might very well combine mail groups and news groups.)  Both @var{group}
+and @var{article} may be @code{nil}.
+
+There should be no result data from this function.
+
+
+@item (nnchoke-request-set-mark GROUP ACTION &optional SERVER)
+
+Set/remove/add marks on articles.  Normally Gnus handles the article
+marks (such as read, ticked, expired etc.)@: internally, and store them in
+@file{~/.newsrc.eld}.  Some back ends (such as @acronym{IMAP}) however carry
+all information about the articles on the server, so Gnus need to
+propagate the mark information to the server.
+
+@var{action} is a list of mark setting requests, having this format:
+
+@example
+(RANGE ACTION MARK)
+@end example
+
+@var{range} is a range of articles you wish to update marks on.
+@var{action} is @code{add} or @code{del}, used to add marks or remove
+marks (preserving all marks not mentioned).  @var{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}, and
+@code{forward}, 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
+@code{tick} mark on article 1 and, later in the list, a request to
+remove the mark on the same article, the mark should in fact be removed.
+
+An example action list:
+
+@example
+(((5 12 30) 'del '(tick))
+ ((10 . 90) 'add '(read expire))
+ ((92 94) 'del '(read)))
+@end example
+
+The function should return a range of articles it wasn't able to set the
+mark on (currently not used for anything).
+
+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 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 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
+it---if a component group is auto-expirable, marking an article as read
+in the virtual group should result in the article being marked as
+expirable.
+
+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 back end check for incoming articles, in one way or
+another.  A mail back end will typically read the spool file or query
+the @acronym{POP} server when this function is invoked.  The
+@var{group} doesn't have 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.
+
+There should be no result data from this function.
+
+
+@item (nnchoke-request-group-description GROUP &optional SERVER)
+
+The result data from this function should be a description of
+@var{group}.
+
+@example
+description-line = name <TAB> description eol
+name             = <string>
+description      = <text>
+@end example
+
+@item (nnchoke-request-list-newsgroups &optional SERVER)
+
+The result data from this function should be the description of all
+groups available on the server.
+
+@example
+description-buffer = *description-line
+@end example
+
+
+@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
+(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 @code{nnml} and the like are probably safe.  But for
+back ends like @code{nntp}, where the groups have been created by the
+server, it is quite likely that there can be many groups.
+
+
+@item (nnchoke-request-create-group GROUP &optional SERVER)
+
+This function should create an empty group with name @var{group}.
+
+There should be no return data.
+
+
+@item (nnchoke-request-expire-articles ARTICLES &optional GROUP SERVER FORCE)
+
+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 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.
+
+This function should return a list of articles that it did not/was not
+able to delete.
+
+There should be no result data returned.
+
+
+@item (nnchoke-request-move-article ARTICLE GROUP SERVER ACCEPT-FORM &optional LAST)
+
+This function should move @var{article} (which is a number) from
+@var{group} by calling @var{accept-form}.
+
+This function should ready the article in question for moving by
+removing any header lines it has added to the article, and generally
+should ``tidy up'' the article.  Then it should @code{eval}
+@var{accept-form} in the buffer where the ``tidy'' article is.  This
+will do the actual copying.  If this @code{eval} returns a
+non-@code{nil} value, the article should be removed.
+
+If @var{last} is @code{nil}, that means that there is a high likelihood
+that there will be more requests issued shortly, so that allows some
+optimizations.
+
+The function should return a cons where the @code{car} is the group name and
+the @code{cdr} is the article number that the article was entered as.
+
+There should be no data returned.
+
+
+@item (nnchoke-request-accept-article GROUP &optional SERVER LAST)
+
+This function takes the current buffer and inserts it into @var{group}.
+If @var{last} in @code{nil}, that means that there will be more calls to
+this function in short order.
+
+The function should return a cons where the @code{car} is the group name and
+the @code{cdr} is the article number that the article was entered as.
+
+The group should exist before the back end is asked to accept the
+article for that group.
+
+There should be no data returned.
+
+
+@item (nnchoke-request-replace-article ARTICLE GROUP BUFFER)
+
+This function should remove @var{article} (which is a number) from
+@var{group} and insert @var{buffer} there instead.
+
+There should be no data returned.
+
+
+@item (nnchoke-request-delete-group GROUP FORCE &optional SERVER)
+
+This function should delete @var{group}.  If @var{force}, it should
+really delete all the articles in the group, and then delete the group
+itself.  (If there is such a thing as ``the group itself''.)
+
+There should be no data returned.
+
+
+@item (nnchoke-request-rename-group GROUP NEW-NAME &optional SERVER)
+
+This function should rename @var{group} into @var{new-name}.  All
+articles in @var{group} should move to @var{new-name}.
+
+There should be no data returned.
+
+@end table
+
+
+@node Error Messaging
+@subsubsection Error Messaging
+
+@findex nnheader-report
+@findex nnheader-get-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 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}.
+
+@lisp
+(nnheader-report 'nnchoke "You did something totally bogus")
+
+(nnheader-report 'nnchoke "Could not request group %s" group)
+@end lisp
+
+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 back end in question.  This function
+takes one argument---the server symbol.
+
+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 Back Ends
+@subsubsection Writing New Back Ends
+
+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
+@code{nnml}, but it has no concept of ``groups'', and it doesn't allow
+editing articles.
+
+It would make sense if it were possible to ``inherit'' functions from
+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 back ends declare their public variables and functions by using a
+package called @code{nnoo}.
+
+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
+
+@item nnoo-declare
+This macro declares the first parameter to be a child of the subsequent
+parameters.  For instance:
+
+@lisp
+(nnoo-declare nndir
+  nnml nnmh)
+@end lisp
+
+@code{nndir} has declared here that it intends to inherit functions from
+both @code{nnml} and @code{nnmh}.
+
+@item defvoo
+This macro is equivalent to @code{defvar}, but registers the variable as
+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 back ends to map the variable to when executing
+a function in those back ends.
+
+@lisp
+(defvoo nndir-directory nil
+  "Where nndir will look for groups."
+  nnml-current-directory nnmh-current-directory)
+@end lisp
+
+This means that @code{nnml-current-directory} will be set to
+@code{nndir-directory} when an @code{nnml} function is called on behalf
+of @code{nndir}.  (The same with @code{nnmh}.)
+
+@item nnoo-define-basics
+This macro defines some common functions that almost all back ends should
+have.
+
+@lisp
+(nnoo-define-basics nndir)
+@end lisp
+
+@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 back ends can inherit it.
+
+@item nnoo-map-functions
+This macro allows mapping of functions from the current back end to
+functions from the parent back ends.
+
+@lisp
+(nnoo-map-functions nndir
+  (nnml-retrieve-headers 0 nndir-current-group 0 0)
+  (nnmh-request-article 0 nndir-current-group 0 0))
+@end lisp
+
+This means that when @code{nndir-retrieve-headers} is called, the first,
+third, and fourth parameters will be passed on to
+@code{nnml-retrieve-headers}, while the second parameter is set to the
+value of @code{nndir-current-group}.
+
+@item nnoo-import
+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.
+
+@lisp
+(nnoo-import nndir
+  (nnmh
+   nnmh-request-list
+   nnmh-request-newgroups)
+  (nnml))
+@end lisp
+
+This means that calls to @code{nndir-request-list} should just be passed
+on to @code{nnmh-request-list}, while all public functions from
+@code{nnml} that haven't been defined in @code{nndir} yet should be
+defined now.
+
+@end table
+
+Below is a slightly shortened version of the @code{nndir} back end.
+
+@lisp
+;;; @r{nndir.el --- single directory newsgroup access for Gnus}
+;; @r{Copyright (C) 1995,1996 Free Software Foundation, Inc.}
+
+;;; @r{Code:}
+
+(require 'nnheader)
+(require 'nnmh)
+(require 'nnml)
+(require 'nnoo)
+(eval-when-compile (require 'cl))
+
+(nnoo-declare nndir
+  nnml nnmh)
+
+(defvoo nndir-directory nil
+  "Where nndir will look for groups."
+  nnml-current-directory nnmh-current-directory)
+
+(defvoo nndir-nov-is-evil nil
+  "*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-top-directory nil nil nnml-directory nnmh-directory)
+(defvoo nndir-get-new-mail nil nil nnml-get-new-mail nnmh-get-new-mail)
+
+(defvoo nndir-status-string "" nil nnmh-status-string)
+(defconst nndir-version "nndir 1.0")
+
+;;; @r{Interface functions.}
+
+(nnoo-define-basics nndir)
+
+(deffoo nndir-open-server (server &optional defs)
+  (setq nndir-directory
+        (or (cadr (assq 'nndir-directory defs))
+            server))
+  (unless (assq 'nndir-directory defs)
+    (push `(nndir-directory ,server) defs))
+  (push `(nndir-current-group
+          ,(file-name-nondirectory
+            (directory-file-name nndir-directory)))
+        defs)
+  (push `(nndir-top-directory
+          ,(file-name-directory (directory-file-name nndir-directory)))
+        defs)
+  (nnoo-change-server 'nndir server defs))
+
+(nnoo-map-functions nndir
+  (nnml-retrieve-headers 0 nndir-current-group 0 0)
+  (nnmh-request-article 0 nndir-current-group 0 0)
+  (nnmh-request-group nndir-current-group 0 0)
+  (nnmh-close-group nndir-current-group 0))
+
+(nnoo-import nndir
+  (nnmh
+   nnmh-status-message
+   nnmh-request-list
+   nnmh-request-newgroups))
+
+(provide 'nndir)
+@end lisp
+
+
+@node Hooking New Back Ends Into Gnus
+@subsubsection Hooking New Back Ends Into Gnus
+
+@vindex gnus-valid-select-methods
+@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 back end into the @code{gnus-valid-select-methods} variable.
+
+@code{gnus-declare-backend} takes two parameters---the back end name and
+an arbitrary number of @dfn{abilities}.
+
+Here's an example:
+
+@lisp
+(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 back end---followups should (probably) go via mail.
+@item post
+This is a newsish back end---followups should (probably) go via news.
+@item post-mail
+This back end supports both mail and news.
+@item none
+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 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 back ends like
+@code{nntp}, but not @code{nnmbox}, for instance.
+@end table
+
+
+@node Mail-like Back Ends
+@subsubsection Mail-like Back Ends
+
+One of the things that separate the mail back ends from the rest of the
+back ends is the heavy dependence by most of the mail back ends on
+common functions in @file{nnmail.el}.  For instance, here's the
+definition of @code{nnml-request-scan}:
+
+@lisp
+(deffoo nnml-request-scan (&optional group server)
+  (setq nnml-article-file-alist nil)
+  (nnmail-get-new-mail 'nnml 'nnml-save-nov nnml-directory group))
+@end lisp
+
+It simply calls @code{nnmail-get-new-mail} with a few parameters,
+and @code{nnmail} takes care of all the moving and splitting of the
+mail.
+
+This function takes four parameters.
+
+@table @var
+@item method
+This should be a symbol to designate which back end is responsible for
+the call.
+
+@item exit-function
+This function should be called after the splitting has been performed.
+
+@item temp-directory
+Where the temporary files should be stored.
+
+@item group
+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{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{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
+(("a-group" (1 . 10))
+ ("some-group" (34 . 39)))
+@end example
+
+
+@node Score File Syntax
+@subsection Score File Syntax
+
+Score files are meant to be easily parsable, but yet extremely
+malleable.  It was decided that something that had the same read syntax
+as an Emacs Lisp list would fit that spec.
+
+Here's a typical score file:
+
+@lisp
+(("summary"
+  ("Windows 95" -10000 nil s)
+  ("Gnus"))
+ ("from"
+  ("Lars" -1000))
+ (mark -100))
+@end lisp
+
+BNF definition of a score file:
+
+@example
+score-file      = "" / "(" *element ")"
+element         = rule / atom
+rule            = string-rule / number-rule / date-rule
+string-rule     = "(" quote string-header quote space *string-match ")"
+number-rule     = "(" quote number-header quote space *number-match ")"
+date-rule       = "(" quote date-header quote space *date-match ")"
+quote           = <ascii 34>
+string-header   = "subject" / "from" / "references" / "message-id" /
+                  "xref" / "body" / "head" / "all" / "followup"
+number-header   = "lines" / "chars"
+date-header     = "date"
+string-match    = "(" quote <string> quote [ "" / [ space score [ "" /
+                  space date [ "" / [ space string-match-t ] ] ] ] ] ")"
+score           = "nil" / <integer>
+date            = "nil" / <natural number>
+string-match-t  = "nil" / "s" / "substring" / "S" / "Substring" /
+                  "r" / "regex" / "R" / "Regex" /
+                  "e" / "exact" / "E" / "Exact" /
+                  "f" / "fuzzy" / "F" / "Fuzzy"
+number-match    = "(" <integer> [ "" / [ space score [ "" /
+                  space date [ "" / [ space number-match-t ] ] ] ] ] ")"
+number-match-t  = "nil" / "=" / "<" / ">" / ">=" / "<="
+date-match      = "(" quote <string> quote [ "" / [ space score [ "" /
+                  space date [ "" / [ space date-match-t ] ] ] ] ")"
+date-match-t    = "nil" / "at" / "before" / "after"
+atom            = "(" [ required-atom / optional-atom ] ")"
+required-atom   = mark / expunge / mark-and-expunge / files /
+                  exclude-files / read-only / touched
+optional-atom   = adapt / local / eval
+mark            = "mark" space nil-or-number
+nil-or-number   = "nil" / <integer>
+expunge         = "expunge" space nil-or-number
+mark-and-expunge = "mark-and-expunge" space nil-or-number
+files           = "files" *[ space <string> ]
+exclude-files   = "exclude-files" *[ space <string> ]
+read-only       = "read-only" [ space "nil" / space "t" ]
+adapt        = "adapt" [ space "ignore" / space "t" / space adapt-rule ]
+adapt-rule      = "(" *[ <string> *[ "(" <string> <integer> ")" ] ")"
+local           = "local" *[ space "(" <string> space <form> ")" ]
+eval            = "eval" space <form>
+space           = *[ " " / <TAB> / <NEWLINE> ]
+@end example
+
+Any unrecognized elements in a score file should be ignored, but not
+discarded.
+
+As you can see, white space is needed, but the type and amount of white
+space is irrelevant.  This means that formatting of the score file is
+left up to the programmer---if it's simpler to just spew it all out on
+one looong line, then that's ok.
+
+The meaning of the various atoms are explained elsewhere in this
+manual (@pxref{Score File Format}).
+
+
+@node Headers
+@subsection Headers
+
+Internally Gnus uses a format for storing article headers that
+corresponds to the @acronym{NOV} format in a mysterious fashion.  One could
+almost suspect that the author looked at the @acronym{NOV} specification and
+just shamelessly @emph{stole} the entire thing, and one would be right.
+
+@dfn{Header} is a severely overloaded term.  ``Header'' is used in
+RFC 1036 to talk about lines in the head of an article (e.g.,
+@code{From}).  It is used by many people as a synonym for
+``head''---``the header and the body''.  (That should be avoided, in my
+opinion.)  And Gnus uses a format internally that it calls ``header'',
+which is what I'm talking about here.  This is a 9-element vector,
+basically, with each header (ouch) having one slot.
+
+These slots are, in order: @code{number}, @code{subject}, @code{from},
+@code{date}, @code{id}, @code{references}, @code{chars}, @code{lines},
+@code{xref}, and @code{extra}.  There are macros for accessing and
+setting these slots---they all have predictable names beginning with
+@code{mail-header-} and @code{mail-header-set-}, respectively.
+
+All these slots contain strings, except the @code{extra} slot, which
+contains an alist of header/value pairs (@pxref{To From Newsgroups}).
+
+
+@node Ranges
+@subsection Ranges
+
+@sc{gnus} introduced a concept that I found so useful that I've started
+using it a lot and have elaborated on it greatly.
+
+The question is simple: If you have a large amount of objects that are
+identified by numbers (say, articles, to take a @emph{wild} example)
+that you want to qualify as being ``included'', a normal sequence isn't
+very useful.  (A 200,000 length sequence is a bit long-winded.)
+
+The solution is as simple as the question: You just collapse the
+sequence.
+
+@example
+(1 2 3 4 5 6 10 11 12)
+@end example
+
+is transformed into
+
+@example
+((1 . 6) (10 . 12))
+@end example
+
+To avoid having those nasty @samp{(13 . 13)} elements to denote a
+lonesome object, a @samp{13} is a valid element:
+
+@example
+((1 . 6) 7 (10 . 12))
+@end example
+
+This means that comparing two ranges to find out whether they are equal
+is slightly tricky:
+
+@example
+((1 . 5) 7 8 (10 . 12))
+@end example
+
+and
+
+@example
+((1 . 5) (7 . 8) (10 . 12))
+@end example
+
+are equal.  In fact, any non-descending list is a range:
+
+@example
+(1 2 3 4 5)
+@end example
+
+is a perfectly valid range, although a pretty long-winded one.  This is
+also valid:
+
+@example
+(1 . 5)
+@end example
+
+and is equal to the previous range.
+
+Here's a BNF definition of ranges.  Of course, one must remember the
+semantic requirement that the numbers are non-descending.  (Any number
+of repetition of the same number is allowed, but apt to disappear in
+range handling.)
+
+@example
+range           = simple-range / normal-range
+simple-range    = "(" number " . " number ")"
+normal-range    = "(" start-contents ")"
+contents        = "" / simple-range *[ " " contents ] /
+                  number *[ " " contents ]
+@end example
+
+Gnus currently uses ranges to keep track of read articles and article
+marks.  I plan on implementing a number of range operators in C if The
+Powers That Be are willing to let me.  (I haven't asked yet, because I
+need to do some more thinking on what operators I need to make life
+totally range-based without ever having to convert back to normal
+sequences.)
+
+
+@node Group Info
+@subsection Group Info
+
+Gnus stores all permanent info on groups in a @dfn{group info} list.
+This list is from three to six elements (or more) long and exhaustively
+describes the group.
+
+Here are two example group infos; one is a very simple group while the
+second is a more complex one:
+
+@example
+("no.group" 5 ((1 . 54324)))
+
+("nnml:my.mail" 3 ((1 . 5) 9 (20 . 55))
+                ((tick (15 . 19)) (replied 3 6 (19 . 3)))
+                (nnml "")
+                ((auto-expire . t) (to-address . "ding@@gnus.org")))
+@end example
+
+The first element is the @dfn{group name}---as Gnus knows the group,
+anyway.  The second element is the @dfn{subscription level}, which
+normally is a small integer.  (It can also be the @dfn{rank}, which is a
+cons cell where the @code{car} is the level and the @code{cdr} is the
+score.)  The third element is a list of ranges of read articles.  The
+fourth element is a list of lists of article marks of various kinds.
+The fifth element is the select method (or virtual server, if you like).
+The sixth element is a list of @dfn{group parameters}, which is what
+this section is about.
+
+Any of the last three elements may be missing if they are not required.
+In fact, the vast majority of groups will normally only have the first
+three elements, which saves quite a lot of cons cells.
+
+Here's a BNF definition of the group info format:
+
+@example
+info          = "(" group space ralevel space read
+                [ "" / [ space marks-list [ "" / [ space method [ "" /
+                space parameters ] ] ] ] ] ")"
+group         = quote <string> quote
+ralevel       = rank / level
+level         = <integer in the range of 1 to inf>
+rank          = "(" level "." score ")"
+score         = <integer in the range of 1 to inf>
+read          = range
+marks-lists   = nil / "(" *marks ")"
+marks         = "(" <string> range ")"
+method        = "(" <string> *elisp-forms ")"
+parameters    = "(" *elisp-forms ")"
+@end example
+
+Actually that @samp{marks} rule is a fib.  A @samp{marks} is a
+@samp{<string>} consed on to a @samp{range}, but that's a bitch to say
+in pseudo-BNF.
+
+If you have a Gnus info and want to access the elements, Gnus offers a
+series of macros for getting/setting these elements.
+
+@table @code
+@item gnus-info-group
+@itemx gnus-info-set-group
+@findex gnus-info-group
+@findex gnus-info-set-group
+Get/set the group name.
+
+@item gnus-info-rank
+@itemx gnus-info-set-rank
+@findex gnus-info-rank
+@findex gnus-info-set-rank
+Get/set the group rank (@pxref{Group Score}).
+
+@item gnus-info-level
+@itemx gnus-info-set-level
+@findex gnus-info-level
+@findex gnus-info-set-level
+Get/set the group level.
+
+@item gnus-info-score
+@itemx gnus-info-set-score
+@findex gnus-info-score
+@findex gnus-info-set-score
+Get/set the group score (@pxref{Group Score}).
+
+@item gnus-info-read
+@itemx gnus-info-set-read
+@findex gnus-info-read
+@findex gnus-info-set-read
+Get/set the ranges of read articles.
+
+@item gnus-info-marks
+@itemx gnus-info-set-marks
+@findex gnus-info-marks
+@findex gnus-info-set-marks
+Get/set the lists of ranges of marked articles.
+
+@item gnus-info-method
+@itemx gnus-info-set-method
+@findex gnus-info-method
+@findex gnus-info-set-method
+Get/set the group select method.
+
+@item gnus-info-params
+@itemx gnus-info-set-params
+@findex gnus-info-params
+@findex gnus-info-set-params
+Get/set the group parameters.
+@end table
+
+All the getter functions take one parameter---the info list.  The setter
+functions take two parameters---the info list and the new value.
+
+The last three elements in the group info aren't mandatory, so it may be
+necessary to extend the group info before setting the element.  If this
+is necessary, you can just pass on a non-@code{nil} third parameter to
+the three final setter functions to have this happen automatically.
+
+
+@node Extended Interactive
+@subsection Extended Interactive
+@cindex interactive
+@findex gnus-interactive
+
+Gnus extends the standard Emacs @code{interactive} specification
+slightly to allow easy use of the symbolic prefix (@pxref{Symbolic
+Prefixes}).  Here's an example of how this is used:
+
+@lisp
+(defun gnus-summary-increase-score (&optional score symp)
+  (interactive (gnus-interactive "P\ny"))
+  ...
+  )
+@end lisp
+
+The best thing to do would have been to implement
+@code{gnus-interactive} as a macro which would have returned an
+@code{interactive} form, but this isn't possible since Emacs checks
+whether a function is interactive or not by simply doing an @code{assq}
+on the lambda form.  So, instead we have @code{gnus-interactive}
+function that takes a string and returns values that are usable to
+@code{interactive}.
+
+This function accepts (almost) all normal @code{interactive} specs, but
+adds a few more.
+
+@table @samp
+@item y
+@vindex gnus-current-prefix-symbol
+The current symbolic prefix---the @code{gnus-current-prefix-symbol}
+variable.
+
+@item Y
+@vindex gnus-current-prefix-symbols
+A list of the current symbolic prefixes---the
+@code{gnus-current-prefix-symbol} variable.
+
+@item A
+The current article number---the @code{gnus-summary-article-number}
+function.
+
+@item H
+The current article header---the @code{gnus-summary-article-header}
+function.
+
+@item g
+The current group name---the @code{gnus-group-group-name}
+function.
+
+@end table
+
+
+@node Emacs/XEmacs Code
+@subsection Emacs/XEmacs Code
+@cindex XEmacs
+@cindex Emacsen
+
+While Gnus runs under Emacs, XEmacs and Mule, I decided that one of the
+platforms must be the primary one.  I chose Emacs.  Not because I don't
+like XEmacs or Mule, but because it comes first alphabetically.
+
+This means that Gnus will byte-compile under Emacs with nary a warning,
+while XEmacs will pump out gigabytes of warnings while byte-compiling.
+As I use byte-compilation warnings to help me root out trivial errors in
+Gnus, that's very useful.
+
+I've also consistently used Emacs function interfaces, but have used
+Gnusey aliases for the functions.  To take an example:  Emacs defines a
+@code{run-at-time} function while XEmacs defines a @code{start-itimer}
+function.  I then define a function called @code{gnus-run-at-time} that
+takes the same parameters as the Emacs @code{run-at-time}.  When running
+Gnus under Emacs, the former function is just an alias for the latter.
+However, when running under XEmacs, the former is an alias for the
+following function:
+
+@lisp
+(defun gnus-xmas-run-at-time (time repeat function &rest args)
+  (start-itimer
+   "gnus-run-at-time"
+   `(lambda ()
+      (,function ,@@args))
+   time repeat))
+@end lisp
+
+This sort of thing has been done for bunches of functions.  Gnus does
+not redefine any native Emacs functions while running under XEmacs---it
+does this @code{defalias} thing with Gnus equivalents instead.  Cleaner
+all over.
+
+In the cases where the XEmacs function interface was obviously cleaner,
+I used it instead.  For example @code{gnus-region-active-p} is an alias
+for @code{region-active-p} in XEmacs, whereas in Emacs it is a function.
+
+Of course, I could have chosen XEmacs as my native platform and done
+mapping functions the other way around.  But I didn't.  The performance
+hit these indirections impose on Gnus under XEmacs should be slight.
+
+
+@node Various File Formats
+@subsection Various File Formats
+
+@menu
+* Active File Format::          Information on articles and groups available.
+* Newsgroups File Format::      Group descriptions.
+@end menu
+
+
+@node Active File Format
+@subsubsection Active File Format
+
+The active file lists all groups available on the server in
+question.  It also lists the highest and lowest current article numbers
+in each group.
+
+Here's an excerpt from a typical active file:
+
+@example
+soc.motss 296030 293865 y
+alt.binaries.pictures.fractals 3922 3913 n
+comp.sources.unix 1605 1593 m
+comp.binaries.ibm.pc 5097 5089 y
+no.general 1000 900 y
+@end example
+
+Here's a pseudo-BNF definition of this file:
+
+@example
+active      = *group-line
+group-line  = group spc high-number spc low-number spc flag <NEWLINE>
+group       = <non-white-space string>
+spc         = " "
+high-number = <non-negative integer>
+low-number  = <positive integer>
+flag        = "y" / "n" / "m" / "j" / "x" / "=" group
+@end example
+
+For a full description of this file, see the manual pages for
+@samp{innd}, in particular @samp{active(5)}.
+
+
+@node Newsgroups File Format
+@subsubsection Newsgroups File Format
+
+The newsgroups file lists groups along with their descriptions.  Not all
+groups on the server have to be listed,  and not all groups in the file
+have to exist on the server.  The file is meant purely as information to
+the user.
+
+The format is quite simple; a group name, a tab, and the description.
+Here's the definition:
+
+@example
+newsgroups    = *line
+line          = group tab description <NEWLINE>
+group         = <non-white-space string>
+tab           = <TAB>
+description   = <string>
+@end example
+
+
+@page
+@node Emacs for Heathens
+@section Emacs for Heathens
+
+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{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
+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.
+@end menu
+
+
+@node Keystrokes
+@subsection Keystrokes
+
+@itemize @bullet
+@item
+Q: What is an experienced Emacs user?
+
+@item
+A: A person who wishes that the terminal had pedals.
+@end itemize
+
+Yes, when you use Emacs, you are apt to use the control key, the shift
+key and the meta key a lot.  This is very annoying to some people
+(notably @code{vi}le users), and the rest of us just love the hell out
+of it.  Just give up and submit.  Emacs really does stand for
+``Escape-Meta-Alt-Control-Shift'', and not ``Editing Macros'', as you
+may have heard from other disreputable sources (like the Emacs author).
+
+The shift keys are normally located near your pinky fingers, and are
+normally used to get capital letters and stuff.  You probably use it all
+the time.  The control key is normally marked ``CTRL'' or something like
+that.  The meta key is, funnily enough, never marked as such on any
+keyboard.  The one I'm currently at has a key that's marked ``Alt'',
+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{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{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
+meta key.  In that case you can use the ``escape'' key.  Then @kbd{M-k}
+means ``press escape, release escape, press @kbd{k}''.  That's much more
+work than if you have a meta key, so if that's the case, I respectfully
+suggest you get a real keyboard with a meta key.  You can't live without
+it.
+
+
+
+@node Emacs Lisp
+@subsection Emacs Lisp
+
+Emacs is the King of Editors because it's really a Lisp interpreter.
+Each and every key you tap runs some Emacs Lisp code snippet, and since
+Emacs Lisp is an interpreted language, that means that you can configure
+any key to run any arbitrary code.  You just, like, do it.
+
+Gnus is written in Emacs Lisp, and is run as a bunch of interpreted
+functions.  (These are byte-compiled for speed, but it's still
+interpreted.)  If you decide that you don't like the way Gnus does
+certain things, it's trivial to have it do something a different way.
+(Well, at least if you know how to write Lisp code.)  However, that's
+beyond the scope of this manual, so we are simply going to talk about
+some common constructs that you normally use in your @file{~/.gnus.el}
+file to customize Gnus.  (You can also use the @file{~/.emacs} file, but
+in order to set things of Gnus up, it is much better to use the
+@file{~/.gnus.el} file, @xref{Startup Files}.)
+
+If you want to set the variable @code{gnus-florgbnize} to four (4), you
+write the following:
+
+@lisp
+(setq gnus-florgbnize 4)
+@end lisp
+
+This function (really ``special form'') @code{setq} is the one that can
+set a variable to some value.  This is really all you need to know.  Now
+you can go and fill your @file{~/.gnus.el} file with lots of these to
+change how Gnus works.
+
+If you have put that thing in your @file{~/.gnus.el} file, it will be
+read and @code{eval}ed (which is Lisp-ese for ``run'') the next time you
+start Gnus.  If you want to change the variable right away, simply say
+@kbd{C-x C-e} after the closing parenthesis.  That will @code{eval} the
+previous ``form'', which is a simple @code{setq} statement here.
+
+Go ahead---just try it, if you're located at your Emacs.  After you
+@kbd{C-x C-e}, you will see @samp{4} appear in the echo area, which
+is the return value of the form you @code{eval}ed.
+
+Some pitfalls:
+
+If the manual says ``set @code{gnus-read-active-file} to @code{some}'',
+that means:
+
+@lisp
+(setq gnus-read-active-file 'some)
+@end lisp
+
+On the other hand, if the manual says ``set @code{gnus-nntp-server-file} to
+@samp{/etc/nntpserver}'', that means:
+
+@lisp
+(setq gnus-nntp-server-file "/etc/nntpserver")
+@end lisp
+
+So be careful not to mix up strings (the latter) with symbols (the
+former).  The manual is unambiguous, but it can be confusing.
+
+@page
+@include gnus-faq.texi
+
+@node GNU Free Documentation License
+@chapter GNU Free Documentation License
+@include doclicense.texi
+
+@node Index
+@chapter Index
+@printindex cp
+
+@node Key Index
+@chapter Key Index
+@printindex ky
+
+@bye
+
+@iftex
+@iflatex
+\end{document}
+@end iflatex
+@end iftex
+
+@c Local Variables:
+@c mode: texinfo
+@c coding: utf-8
+@c End:
diff --git a/xemacs-packages/gnus/texi/gnusconfig.tex.in b/xemacs-packages/gnus/texi/gnusconfig.tex.in
new file mode 100644 (file)
index 0000000..4989104
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/herds/convol11.pnm b/xemacs-packages/gnus/texi/herds/convol11.pnm
new file mode 100644 (file)
index 0000000..2f21812
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/herds/convol5.pnm b/xemacs-packages/gnus/texi/herds/convol5.pnm
new file mode 100644 (file)
index 0000000..e164bd9
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/herds/gnus-herd-bw.png b/xemacs-packages/gnus/texi/herds/gnus-herd-bw.png
new file mode 100644 (file)
index 0000000..8ed5904
Binary files /dev/null and b/xemacs-packages/gnus/texi/herds/gnus-herd-bw.png differ
diff --git a/xemacs-packages/gnus/texi/herds/gnus-herd-new.png b/xemacs-packages/gnus/texi/herds/gnus-herd-new.png
new file mode 100644 (file)
index 0000000..b0dacd1
Binary files /dev/null and b/xemacs-packages/gnus/texi/herds/gnus-herd-new.png differ
diff --git a/xemacs-packages/gnus/texi/herds/new-herd-1.png b/xemacs-packages/gnus/texi/herds/new-herd-1.png
new file mode 100644 (file)
index 0000000..775d493
Binary files /dev/null and b/xemacs-packages/gnus/texi/herds/new-herd-1.png differ
diff --git a/xemacs-packages/gnus/texi/herds/new-herd-2.png b/xemacs-packages/gnus/texi/herds/new-herd-2.png
new file mode 100644 (file)
index 0000000..19b2fbc
Binary files /dev/null and b/xemacs-packages/gnus/texi/herds/new-herd-2.png differ
diff --git a/xemacs-packages/gnus/texi/herds/new-herd-3.png b/xemacs-packages/gnus/texi/herds/new-herd-3.png
new file mode 100644 (file)
index 0000000..1d36d23
Binary files /dev/null and b/xemacs-packages/gnus/texi/herds/new-herd-3.png differ
diff --git a/xemacs-packages/gnus/texi/herds/new-herd-4.png b/xemacs-packages/gnus/texi/herds/new-herd-4.png
new file mode 100644 (file)
index 0000000..23ccb23
Binary files /dev/null and b/xemacs-packages/gnus/texi/herds/new-herd-4.png differ
diff --git a/xemacs-packages/gnus/texi/herds/new-herd-5.png b/xemacs-packages/gnus/texi/herds/new-herd-5.png
new file mode 100644 (file)
index 0000000..aa85f31
Binary files /dev/null and b/xemacs-packages/gnus/texi/herds/new-herd-5.png differ
diff --git a/xemacs-packages/gnus/texi/herds/new-herd-6.png b/xemacs-packages/gnus/texi/herds/new-herd-6.png
new file mode 100644 (file)
index 0000000..df103ed
Binary files /dev/null and b/xemacs-packages/gnus/texi/herds/new-herd-6.png differ
diff --git a/xemacs-packages/gnus/texi/herds/new-herd-7.png b/xemacs-packages/gnus/texi/herds/new-herd-7.png
new file mode 100644 (file)
index 0000000..c5e29a7
Binary files /dev/null and b/xemacs-packages/gnus/texi/herds/new-herd-7.png differ
diff --git a/xemacs-packages/gnus/texi/herds/new-herd-8.png b/xemacs-packages/gnus/texi/herds/new-herd-8.png
new file mode 100644 (file)
index 0000000..94dea5a
Binary files /dev/null and b/xemacs-packages/gnus/texi/herds/new-herd-8.png differ
diff --git a/xemacs-packages/gnus/texi/herds/new-herd-9.png b/xemacs-packages/gnus/texi/herds/new-herd-9.png
new file mode 100644 (file)
index 0000000..dc26eb4
Binary files /dev/null and b/xemacs-packages/gnus/texi/herds/new-herd-9.png differ
diff --git a/xemacs-packages/gnus/texi/herds/new-herd-section.png b/xemacs-packages/gnus/texi/herds/new-herd-section.png
new file mode 100644 (file)
index 0000000..662a982
Binary files /dev/null and b/xemacs-packages/gnus/texi/herds/new-herd-section.png differ
diff --git a/xemacs-packages/gnus/texi/herds/new-herd.png b/xemacs-packages/gnus/texi/herds/new-herd.png
new file mode 100644 (file)
index 0000000..c021e9b
Binary files /dev/null and b/xemacs-packages/gnus/texi/herds/new-herd.png differ
diff --git a/xemacs-packages/gnus/texi/herds/new-herd2.png b/xemacs-packages/gnus/texi/herds/new-herd2.png
new file mode 100644 (file)
index 0000000..6e1a8fd
Binary files /dev/null and b/xemacs-packages/gnus/texi/herds/new-herd2.png differ
diff --git a/xemacs-packages/gnus/texi/infohack.el b/xemacs-packages/gnus/texi/infohack.el
new file mode 100644 (file)
index 0000000..403e072
--- /dev/null
@@ -0,0 +1,196 @@
+;;; infohack.el --- a hack to format info file.
+;; Copyright (C) 2001-2016 Free Software Foundation, Inc.
+
+;; Author: Shenghuo Zhu <zsh@cs.rochester.edu>
+;; Keywords: info
+
+;; 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 3, 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.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'texinfmt)
+
+(if (fboundp 'texinfo-copying)
+    nil
+  ;; Support @copying and @insertcopying for Emacs 21.3 and lesser and
+  ;; XEmacs.
+  (defvar texinfo-copying-text ""
+    "Text of the copyright notice and copying permissions.")
+
+  (defun texinfo-copying ()
+    "Copy the copyright notice and copying permissions from the Texinfo file,
+as indicated by the @copying ... @end copying command;
+insert the text with the @insertcopying command."
+    (let ((beg (progn (beginning-of-line) (point)))
+         (end  (progn (re-search-forward "^@end copying[ \t]*\n") (point))))
+      (setq texinfo-copying-text
+           (buffer-substring-no-properties
+            (save-excursion (goto-char beg) (forward-line 1) (point))
+            (save-excursion (goto-char end) (forward-line -1) (point))))
+      (delete-region beg end)))
+
+  (defun texinfo-insertcopying ()
+    "Insert the copyright notice and copying permissions from the Texinfo file,
+which are indicated by the @copying ... @end copying command."
+    (insert (concat "\n" texinfo-copying-text)))
+
+  (defadvice texinfo-format-scan (before expand-@copying-section activate)
+    "Extract @copying and replace @insertcopying with it."
+    (goto-char (point-min))
+    (when (search-forward "@copying" nil t)
+      (texinfo-copying))
+    (while (search-forward "@insertcopying" nil t)
+      (delete-region (match-beginning 0) (match-end 0))
+      (texinfo-insertcopying))))
+
+(if (fboundp 'texinfo-format-comma)
+    nil
+  (put 'comma 'texinfo-format 'texinfo-format-comma)
+  (defun texinfo-format-comma ()
+    (texinfo-parse-arg-discard)
+    (insert ",")
+    (put-text-property (1- (point)) (point) 'ignore t))
+
+  ;; Redefine this function so as to work for @comma
+  (defun texinfo-format-parse-args ()
+    (let ((start (1- (point)))
+         next beg end
+         args)
+      (search-forward "{")
+      (save-excursion
+       (texinfo-format-expand-region
+        (point)
+        (save-excursion (up-list 1) (1- (point)))))
+      ;; The following does not handle cross references of the form:
+      ;; `@xref{bullet, , @code{@@bullet}@{@}}.' because the
+      ;; re-search-forward finds the first right brace after the second
+      ;; comma.
+      (while (/= (preceding-char) ?\})
+       (skip-chars-forward " \t\n")
+       (setq beg (point))
+;;;    (re-search-forward "[},]")
+       ;; Ignore commas that are derived from @comma{}.
+       (while (and (re-search-forward "[},]" nil t)
+                   (get-text-property (match-beginning 0) 'ignore)))
+;;;
+       (setq next (point))
+       (forward-char -1)
+       (skip-chars-backward " \t\n")
+       (setq end (point))
+       (cond ((< beg end)
+              (goto-char beg)
+              (while (search-forward "\n" end t)
+                (replace-match " "))))
+       (push (if (> end beg) (buffer-substring-no-properties beg end))
+             args)
+       (goto-char next))
+      ;;(if (eolp) (forward-char 1))
+      (setq texinfo-command-end (point))
+      (nreverse args))))
+
+(defun infohack-remove-unsupported ()
+  (goto-char (point-min))
+  (while (re-search-forward "@\\(end \\)?ifnottex" nil t) 
+    (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-replace-unsupported ()
+  (goto-char (point-min))
+  (while (search-forward "@indicateurl{" nil t)
+    (replace-match "@url{")))
+
+(defun infohack-include-files ()
+  "Insert @include files."
+  (goto-char (point-min))
+  (set-syntax-table texinfo-format-syntax-table)
+  (let (start texinfo-command-end filename)
+    (while (re-search-forward "^@include" nil t)
+      (setq start (match-beginning 0)
+           texinfo-command-end (point)
+           filename (texinfo-parse-line-arg))
+      (delete-region start (point-at-bol 2))
+      (message "Reading included file: %s" filename)
+      (save-excursion
+       (save-restriction
+         (narrow-to-region
+          (point)
+          (+ (point) (car (cdr (insert-file-contents filename)))))
+         (goto-char (point-min))
+         ;; Remove `@setfilename' line from included file, if any,
+         ;; so @setfilename command not duplicated.
+         (if (re-search-forward "^@setfilename" (point-at-eol 100) t)
+             (delete-region (point-at-bol 1)
+                            (point-at-bol 2))))))))
+
+(defun infohack (file)
+  (let ((dest-directory default-directory)
+       (max-lisp-eval-depth (max max-lisp-eval-depth 600))
+       coding-system)
+    ;; Emacs 21.3 doesn't support @documentencoding
+    (unless (get 'documentencoding 'texinfo-format)
+      (put 'documentencoding 'texinfo-format 
+          'texinfo-discard-line-with-args))
+    (find-file file)
+    (setq buffer-read-only nil)
+    (setq coding-system buffer-file-coding-system)
+    (infohack-remove-unsupported)
+    (infohack-include-files)
+    (infohack-replace-unsupported)
+    (texinfo-every-node-update) 
+    (texinfo-format-buffer t) ;; Don't save any file.
+    (setq default-directory dest-directory)
+    (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) (if (boundp 'Info-split-threshold)
+    ;;                        (+ 50000 Info-split-threshold)
+    ;;                      100000))
+    ;;   (Info-split))
+    (save-buffer)))
+
+(eval-and-compile
+  (when (string-match "windows-nt\\|os/2\\|emx\\|cygwin"
+                      (symbol-name system-type))
+    (defun subst-char-in-region (START END FROMCHAR TOCHAR &optional NOUNDO)
+      "From START to END, replace FROMCHAR with TOCHAR each time it occurs.
+If optional arg NOUNDO is non-nil, don't record this change for undo
+and don't mark the buffer as really changed.
+Both characters must have the same length of multi-byte form."
+      (let ((original-buffer-undo-list buffer-undo-list)
+            (modified (buffer-modified-p)))
+        (if NOUNDO
+            (setq buffer-undo-list t))
+        (goto-char START)
+        (let ((from (char-to-string FROMCHAR))
+              (to (char-to-string TOCHAR)))
+          (while (search-forward from END t)
+            (replace-match to t t)))
+        (if NOUNDO
+            (progn (setq buffer-undo-list original-buffer-undo-list)
+                   (set-buffer-modidifed-p modified)))))))
+
+(defun batch-makeinfo ()
+  "Emacs makeinfo in batch mode."
+  (infohack (car command-line-args-left))
+  (setq command-line-args-left nil))
+
+;;; infohack.el ends here
diff --git a/xemacs-packages/gnus/texi/message.texi b/xemacs-packages/gnus/texi/message.texi
new file mode 100644 (file)
index 0000000..b5e7916
--- /dev/null
@@ -0,0 +1,2687 @@
+\input texinfo                  @c -*-texinfo-*-
+
+@include gnus-overrides.texi
+
+@setfilename message.info
+@settitle Message Manual
+@include docstyle.texi
+@synindex fn cp
+@synindex vr cp
+@synindex pg cp
+@copying
+This file documents Message, the Emacs message composition mode.
+
+Copyright @copyright{} 1996--2016 Free Software Foundation, Inc.
+
+@quotation
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 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''.
+
+(a) The FSF's Back-Cover Text is: ``You have the freedom to copy and
+modify this GNU manual.''
+@end quotation
+@end copying
+
+@dircategory Emacs network features
+@direntry
+* Message: (message).           Mail and news composition mode that
+                                  goes with Gnus.
+@end direntry
+@iftex
+@finalout
+@end iftex
+
+@titlepage
+@ifset WEBHACKDEVEL
+@title Message Manual (DEVELOPMENT VERSION)
+@end ifset
+@ifclear WEBHACKDEVEL
+@title Message Manual
+@end ifclear
+
+@author by Lars Magne Ingebrigtsen
+@page
+
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+
+@summarycontents
+@contents
+
+@node Top
+@top Message
+
+@ifnottex
+@insertcopying
+@end ifnottex
+
+All message composition from Gnus (both mail and news) takes place in
+Message mode buffers.
+
+@menu
+* Interface::         Setting up message buffers.
+* Commands::          Commands you can execute in message mode buffers.
+* Variables::         Customizing the message buffers.
+* Compatibility::     Making Message backwards compatible.
+* Appendices::        More technical things.
+* GNU Free Documentation License:: The license for this documentation.
+* Index::             Variable, function and concept index.
+* Key Index::         List of Message mode keys.
+@end menu
+
+@c Adjust ../Makefile.in if you change the following lines:
+Message is distributed with Gnus.  The Gnus distribution
+@c
+corresponding to this manual is Ma Gnus v0.14
+
+
+@node Interface
+@chapter Interface
+
+When a program (or a person) wants to respond to a message---reply,
+follow up, forward, cancel---the program (or person) should just put
+point in the buffer where the message is and call the required command.
+@code{Message} will then pop up a new @code{message} mode buffer with
+appropriate headers filled out, and the user can edit the message before
+sending it.
+
+@menu
+* New Mail Message::     Editing a brand new mail message.
+* New News Message::     Editing a brand new news message.
+* Reply::                Replying via mail.
+* Wide Reply::           Responding to all people via mail.
+* Followup::             Following up via news.
+* Canceling News::       Canceling a news article.
+* Superseding::          Superseding a message.
+* Forwarding::           Forwarding a message via news or mail.
+* Resending::            Resending a mail message.
+* Bouncing::             Bouncing a mail message.
+* Mailing Lists::        Send mail to mailing lists.
+@end menu
+
+You can customize the Message Mode tool bar, see @kbd{M-x
+customize-apropos RET message-tool-bar}.  This feature is only available
+in Emacs.
+
+@node New Mail Message
+@section New Mail Message
+
+@findex message-mail
+The @code{message-mail} command pops up a new message buffer.
+
+Two optional parameters are accepted: The first will be used as the
+@code{To} header and the second as the @code{Subject} header.  If these
+are @code{nil}, those two headers will be empty.
+
+
+@node New News Message
+@section New News Message
+
+@findex message-news
+The @code{message-news} command pops up a new message buffer.
+
+This function accepts two optional parameters.  The first will be used
+as the @code{Newsgroups} header and the second as the @code{Subject}
+header.  If these are @code{nil}, those two headers will be empty.
+
+
+@node Reply
+@section Reply
+
+@findex message-reply
+The @code{message-reply} function pops up a message buffer that's a
+reply to the message in the current buffer.
+
+@vindex message-reply-to-function
+Message uses the normal methods to determine where replies are to go
+(@pxref{Responses}), but you can change the behavior to suit your needs
+by fiddling with the @code{message-reply-to-function} variable.
+
+If you want the replies to go to the @code{Sender} instead of the
+@code{From}, you could do something like this:
+
+@lisp
+(setq message-reply-to-function
+      (lambda ()
+       (cond ((equal (mail-fetch-field "from") "somebody")
+               (list (cons 'To (mail-fetch-field "sender"))))
+             (t
+              nil))))
+@end lisp
+
+This function will be called narrowed to the head of the article that is
+being replied to.
+
+As you can see, this function should return a list.  In this case, it
+returns @code{((To . "Whom"))} if it has an opinion as to what the To
+header should be.  If it does not, it should just return @code{nil}, and
+the normal methods for determining the To header will be used.
+
+Each list element should be a cons, where the @sc{car} should be the
+name of a header (e.g., @code{Cc}) and the @sc{cdr} should be the header
+value (e.g., @samp{larsi@@ifi.uio.no}).  All these headers will be
+inserted into the head of the outgoing mail.
+
+
+@node Wide Reply
+@section Wide Reply
+
+@findex message-wide-reply
+The @code{message-wide-reply} pops up a message buffer that's a wide
+reply to the message in the current buffer.  A @dfn{wide reply} is a
+reply that goes out to all people listed in the @code{To}, @code{From}
+(or @code{Reply-to}) and @code{Cc} headers.
+
+@vindex message-wide-reply-to-function
+Message uses the normal methods to determine where wide replies are to go,
+but you can change the behavior to suit your needs by fiddling with the
+@code{message-wide-reply-to-function}.  It is used in the same way as
+@code{message-reply-to-function} (@pxref{Reply}).
+
+@vindex message-dont-reply-to-names
+Addresses that match the @code{message-dont-reply-to-names} regular
+expression (or list of regular expressions) will be removed from the
+@code{Cc} header. A value of @code{nil} means exclude your name only.
+
+@vindex message-prune-recipient-rules
+@code{message-prune-recipient-rules} is used to prune the addresses
+used when doing a wide reply.  It's meant to be used to remove
+duplicate addresses and the like.  It's a list of lists, where the
+first element is a regexp to match the address to trigger the rule,
+and the second is a regexp that will be expanded based on the first,
+to match addresses to be pruned.
+
+It's complicated to explain, but it's easy to use.
+
+For instance, if you get an email from @samp{foo@@example.org}, but
+@samp{foo@@zot.example.org} is also in the @code{Cc} list, then your
+wide reply will go out to both these addresses, since they are unique.
+
+To avoid this, do something like the following:
+
+@lisp
+(setq message-prune-recipient-rules
+      '(("^\\([^@@]+\\)@@\\(.*\\)" "\\1@@.*[.]\\2")))
+@end lisp
+
+If, for instance, you want all wide replies that involve messages from
+@samp{cvs@@example.org} to go to that address, and nowhere else (i.e.,
+remove all other recipients if @samp{cvs@@example.org} is in the
+recipient list:
+
+@lisp
+(setq message-prune-recipient-rules
+      '(("cvs@@example.org" ".")))
+@end lisp
+
+@vindex message-wide-reply-confirm-recipients
+If @code{message-wide-reply-confirm-recipients} is non-@code{nil} you
+will be asked to confirm that you want to reply to multiple
+recipients.  The default is @code{nil}.
+
+@node Followup
+@section Followup
+
+@findex message-followup
+The @code{message-followup} command pops up a message buffer that's a
+followup to the message in the current buffer.
+
+@vindex message-followup-to-function
+Message uses the normal methods to determine where followups are to go,
+but you can change the behavior to suit your needs by fiddling with the
+@code{message-followup-to-function}.  It is used in the same way as
+@code{message-reply-to-function} (@pxref{Reply}).
+
+@vindex message-use-followup-to
+The @code{message-use-followup-to} variable says what to do about
+@code{Followup-To} headers.  If it is @code{use}, always use the value.
+If it is @code{ask} (which is the default), ask whether to use the
+value.  If it is @code{t}, use the value unless it is @samp{poster}.  If
+it is @code{nil}, don't use the value.
+
+
+@node Canceling News
+@section Canceling News
+
+@findex message-cancel-news
+The @code{message-cancel-news} command cancels the article in the
+current buffer.
+
+@vindex message-cancel-message
+The value of @code{message-cancel-message} is inserted in the body of
+the cancel message.  The default is @samp{I am canceling my own
+article.}.
+
+@cindex Cancel Locks
+@vindex message-insert-canlock
+@cindex canlock
+When Message posts news messages, it inserts @code{Cancel-Lock}
+headers by default.  This is a cryptographic header that ensures that
+only you can cancel your own messages, which is nice.  The downside
+is that if you lose your @file{.emacs} file (which is where Gnus
+stores the secret cancel lock password (which is generated
+automatically the first time you use this feature)), you won't be
+able to cancel your message.  If you want to manage a password yourself,
+you can put something like the following in your @file{~/.gnus.el} file:
+
+@lisp
+(setq canlock-password "geheimnis"
+      canlock-password-for-verify canlock-password)
+@end lisp
+
+Whether to insert the header or not is controlled by the
+@code{message-insert-canlock} variable.
+
+Not many news servers respect the @code{Cancel-Lock} header yet, but
+this is expected to change in the future.
+
+
+@node Superseding
+@section Superseding
+
+@findex message-supersede
+The @code{message-supersede} command pops up a message buffer that will
+supersede the message in the current buffer.
+
+@vindex message-ignored-supersedes-headers
+Headers matching the @code{message-ignored-supersedes-headers} are
+removed before popping up the new message buffer.  The default is@*
+@samp{^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:\\|^X-Hashcash:\\|@*
+^X-Payment:\\|^Approved:}.
+
+
+
+@node Forwarding
+@section Forwarding
+
+@findex message-forward
+The @code{message-forward} command pops up a message buffer to forward
+the message in the current buffer.  If given a prefix, forward using
+news.
+
+@table @code
+@item message-forward-ignored-headers
+@vindex message-forward-ignored-headers
+In non-@code{nil}, all headers that match this regexp will be deleted
+when forwarding a message.
+
+@item message-forward-included-headers
+@vindex message-forward-included-headers
+In non-@code{nil}, only headers that match this regexp will be kept
+when forwarding a message.
+
+@item message-make-forward-subject-function
+@vindex message-make-forward-subject-function
+A list of functions that are called to generate a subject header for
+forwarded messages.  The subject generated by the previous function is
+passed into each successive function.
+
+The provided functions are:
+
+@table @code
+@item message-forward-subject-author-subject
+@findex message-forward-subject-author-subject
+Source of article (author or newsgroup), in brackets followed by the
+subject.
+
+@item message-forward-subject-fwd
+Subject of article with @samp{Fwd:} prepended to it.
+@end table
+
+@item message-wash-forwarded-subjects
+@vindex message-wash-forwarded-subjects
+If this variable is @code{t}, the subjects of forwarded messages have
+the evidence of previous forwards (such as @samp{Fwd:}, @samp{Re:},
+@samp{(fwd)}) removed before the new subject is
+constructed.  The default value is @code{nil}.
+
+@item message-forward-as-mime
+@vindex message-forward-as-mime
+If this variable is @code{t} (the default), forwarded messages are
+included as inline @acronym{MIME} RFC822 parts.  If it's @code{nil}, forwarded
+messages will just be copied inline to the new message, like previous,
+non @acronym{MIME}-savvy versions of Gnus would do.
+
+@item message-forward-before-signature
+@vindex message-forward-before-signature
+If non-@code{nil}, put forwarded message before signature, else after.
+
+@end table
+
+
+@node Resending
+@section Resending
+
+@findex message-resend
+The @code{message-resend} command will prompt the user for an address
+and resend the message in the current buffer to that address.
+
+@vindex message-ignored-resent-headers
+Headers that match the @code{message-ignored-resent-headers} regexp will
+be removed before sending the message.
+
+
+@node Bouncing
+@section Bouncing
+
+@findex message-bounce
+The @code{message-bounce} command will, if the current buffer contains a
+bounced mail message, pop up a message buffer stripped of the bounce
+information.  A @dfn{bounced message} is typically a mail you've sent
+out that has been returned by some @code{mailer-daemon} as
+undeliverable.
+
+@vindex message-ignored-bounced-headers
+Headers that match the @code{message-ignored-bounced-headers} regexp
+will be removed before popping up the buffer.  The default is
+@samp{^\\(Received\\|Return-Path\\|Delivered-To\\):}.
+
+
+@node Mailing Lists
+@section Mailing Lists
+
+@cindex Mail-Followup-To
+Sometimes while posting to mailing lists, the poster needs to direct
+followups to the post to specific places.  The Mail-Followup-To (MFT)
+was created to enable just this.  Three example scenarios where this is
+useful:
+
+@itemize @bullet
+@item
+A mailing list poster can use MFT to express that responses should be
+sent to just the list, and not the poster as well.  This will happen
+if the poster is already subscribed to the list.
+
+@item
+A mailing list poster can use MFT to express that responses should be
+sent to the list and the poster as well.  This will happen if the poster
+is not subscribed to the list.
+
+@item
+If a message is posted to several mailing lists, MFT 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.
+
+@end itemize
+
+Gnus honors the MFT header in other's messages (i.e., while following
+up to someone else's post) and also provides support for generating
+sensible MFT headers for outgoing messages as well.
+
+@c @menu
+@c * Honoring an MFT post::        What to do when one already exists
+@c * Composing with a MFT header:: Creating one from scratch.
+@c @end menu
+
+@c @node Composing with a MFT header
+@subsection  Composing a correct MFT header automagically
+
+The first step in getting Gnus to automagically generate a MFT header
+in posts you make is to give Gnus a list of the mailing lists
+addresses you are subscribed to.  You can do this in more than one
+way.  The following variables would come in handy.
+
+@table @code
+
+@vindex message-subscribed-addresses
+@item message-subscribed-addresses
+This should be a list of addresses the user is subscribed to.  Its
+default value is @code{nil}.  Example:
+@lisp
+(setq message-subscribed-addresses
+      '("ding@@gnus.org" "bing@@noose.org"))
+@end lisp
+
+@vindex message-subscribed-regexps
+@item message-subscribed-regexps
+This should be a list of regexps denoting the addresses of mailing
+lists subscribed to.  Default value is @code{nil}.  Example: If you
+want to achieve the same result as above:
+@lisp
+(setq message-subscribed-regexps
+      '("\\(ding@@gnus\\)\\|\\(bing@@noose\\)\\.org")
+@end lisp
+
+@vindex message-subscribed-address-functions
+@item message-subscribed-address-functions
+This can be a list of functions to be called (one at a time!!) to
+determine the value of MFT headers.  It is advisable that these
+functions not take any arguments.  Default value is @code{nil}.
+
+There is a pre-defined function in Gnus that is a good candidate for
+this variable.  @code{gnus-find-subscribed-addresses} is a function
+that returns a list of addresses corresponding to the groups that have
+the @code{subscribed} (@pxref{Group Parameters, ,Group Parameters,
+gnus, The Gnus Manual}) group parameter set to a non-@code{nil} value.
+This is how you would do it.
+
+@lisp
+(setq message-subscribed-address-functions
+      '(gnus-find-subscribed-addresses))
+@end lisp
+
+@vindex message-subscribed-address-file
+@item message-subscribed-address-file
+You might be one organized human freak and have a list of addresses of
+all subscribed mailing lists in a separate file!  Then you can just
+set this variable to the name of the file and life would be good.
+
+@end table
+
+You can use one or more of the above variables.  All their values are
+``added'' in some way that works :-)
+
+Now you are all set.  Just start composing a message as you normally do.
+And just send it; as always.  Just before the message is sent out, Gnus'
+MFT generation thingy kicks in and checks if the message already has a
+MFT field.  If there is one, it is left alone.  (Except if it's empty;
+in that case, the field is removed and is not replaced with an
+automatically generated one.  This lets you disable MFT generation on a
+per-message basis.)  If there is none, then the list of recipient
+addresses (in the To: and Cc: headers) is checked to see if one of them
+is a list address you are subscribed to.  If none of them is a list
+address, then no MFT is generated; otherwise, a MFT is added to the
+other headers and set to the value of all addresses in To: and Cc:
+
+@kindex C-c C-f C-a
+@findex message-generate-unsubscribed-mail-followup-to
+@kindex C-c C-f C-m
+@findex message-goto-mail-followup-to
+Hm.  ``So'', you ask, ``what if I send an email to a list I am not
+subscribed to?  I want my MFT to say that I want an extra copy.''  (This
+is supposed to be interpreted by others the same way as if there were no
+MFT, but you can use an explicit MFT to override someone else's
+to-address group parameter.)  The function
+@code{message-generate-unsubscribed-mail-followup-to} might come in
+handy.  It is bound to @kbd{C-c C-f C-a} by default.  In any case, you
+can insert a MFT of your own choice; @kbd{C-c C-f C-m}
+(@code{message-goto-mail-followup-to}) will help you get started.
+
+@c @node Honoring an MFT post
+@subsection Honoring an MFT post
+
+@vindex message-use-mail-followup-to
+When you followup to a post on a mailing list, and the post has a MFT
+header, Gnus' action will depend on the value of the variable
+@code{message-use-mail-followup-to}.  This variable can be one of:
+
+@table @code
+@item use
+ Always honor MFTs.  The To: and Cc: headers in your followup will be
+ derived from the MFT header of the original post.  This is the default.
+
+@item nil
+ Always dishonor MFTs (just ignore the darned thing)
+
+@item ask
+Gnus will prompt you for an action.
+
+@end table
+
+It is considered good netiquette to honor MFT, as it is assumed the
+fellow who posted a message knows where the followups need to go
+better than you do.
+
+@node Commands
+@chapter Commands
+
+@menu
+* Buffer Entry::        Commands after entering a Message buffer.
+* Header Commands::     Commands for moving headers or changing headers.
+* Movement::            Moving around in message buffers.
+* Insertion::           Inserting things into message buffers.
+* MIME::                @acronym{MIME} considerations.
+* IDNA::                Non-@acronym{ASCII} domain name considerations.
+* Security::            Signing and encrypting messages.
+* Various Commands::    Various things.
+* Sending::             Actually sending the message.
+* Mail Aliases::        How to use mail aliases.
+* Spelling::            Having Emacs check your spelling.
+@end menu
+
+
+@node Buffer Entry
+@section Buffer Entry
+@cindex undo
+@kindex C-_
+
+You most often end up in a Message buffer when responding to some other
+message of some sort.  Message does lots of handling of quoted text, and
+may remove signatures, reformat the text, or the like---depending on
+which used settings you're using.  Message usually gets things right,
+but sometimes it stumbles.  To help the user unwind these stumblings,
+Message sets the undo boundary before each major automatic action it
+takes.  If you press the undo key (usually located at @kbd{C-_}) a few
+times, you will get back the un-edited message you're responding to.
+
+
+@node Header Commands
+@section Header Commands
+
+@subsection Commands for moving to headers
+
+These following commands move to the header in question.  If it doesn't
+exist, it will be inserted.
+
+@table @kbd
+
+@item C-c ?
+@kindex C-c ?
+@findex describe-mode
+Describe the message mode.
+
+@item C-c C-f C-t
+@kindex C-c C-f C-t
+@findex message-goto-to
+Go to the @code{To} header (@code{message-goto-to}).
+
+@item C-c C-f C-o
+@kindex C-c C-f C-o
+@findex message-goto-from
+Go to the @code{From} header (@code{message-goto-from}).  (The ``o''
+in the key binding is for Originator.)
+
+@item C-c C-f C-b
+@kindex C-c C-f C-b
+@findex message-goto-bcc
+Go to the @code{Bcc} header (@code{message-goto-bcc}).
+
+@item C-c C-f C-w
+@kindex C-c C-f C-w
+@findex message-goto-fcc
+Go to the @code{Fcc} header (@code{message-goto-fcc}).
+
+@item C-c C-f C-c
+@kindex C-c C-f C-c
+@findex message-goto-cc
+Go to the @code{Cc} header (@code{message-goto-cc}).
+
+@item C-c C-f C-s
+@kindex C-c C-f C-s
+@findex message-goto-subject
+Go to the @code{Subject} header (@code{message-goto-subject}).
+
+@item C-c C-f C-r
+@kindex C-c C-f C-r
+@findex message-goto-reply-to
+Go to the @code{Reply-To} header (@code{message-goto-reply-to}).
+
+@item C-c C-f C-n
+@kindex C-c C-f C-n
+@findex message-goto-newsgroups
+Go to the @code{Newsgroups} header (@code{message-goto-newsgroups}).
+
+@item C-c C-f C-d
+@kindex C-c C-f C-d
+@findex message-goto-distribution
+Go to the @code{Distribution} header (@code{message-goto-distribution}).
+
+@item C-c C-f C-f
+@kindex C-c C-f C-f
+@findex message-goto-followup-to
+Go to the @code{Followup-To} header (@code{message-goto-followup-to}).
+
+@item C-c C-f C-k
+@kindex C-c C-f C-k
+@findex message-goto-keywords
+Go to the @code{Keywords} header (@code{message-goto-keywords}).
+
+@item C-c C-f C-u
+@kindex C-c C-f C-u
+@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 C-c C-f C-a
+@kindex C-c C-f C-a
+@findex message-generate-unsubscribed-mail-followup-to
+Insert a reasonable @samp{Mail-Followup-To:} header
+(@pxref{Mailing Lists}) in a post to an
+unsubscribed list.  When making original posts to a mailing list you are
+not subscribed to, you have to type in a @samp{Mail-Followup-To:} header
+by hand.  The contents, usually, are the addresses of the list and your
+own address.  This function inserts such a header automatically.  It
+fetches the contents of the @samp{To:} header in the current mail
+buffer, and appends the current @code{user-mail-address}.
+
+If the optional argument @code{include-cc} is non-@code{nil}, the
+addresses in the @samp{Cc:} header are also put into the
+@samp{Mail-Followup-To:} header.
+
+@end table
+
+@subsection  Commands to change headers
+
+@table @kbd
+
+@item C-c C-o
+@kindex C-c C-o
+@findex message-sort-headers
+@vindex message-header-format-alist
+Sort headers according to @code{message-header-format-alist}
+(@code{message-sort-headers}).
+
+@item C-c C-t
+@kindex C-c C-t
+@findex message-insert-to
+Insert a @code{To} header that contains the @code{Reply-To} or
+@code{From} header of the message you're following up
+(@code{message-insert-to}).
+
+@item C-c C-n
+@kindex C-c C-n
+@findex message-insert-newsgroups
+Insert a @code{Newsgroups} header that reflects the @code{Followup-To}
+or @code{Newsgroups} header of the article you're replying to
+(@code{message-insert-newsgroups}).
+
+@item C-c C-l
+@kindex C-c C-l
+@findex message-to-list-only
+Send a message to the list only.  Remove all addresses but the list
+address from @code{To:} and @code{Cc:} headers.
+
+@item C-c M-n
+@kindex C-c M-n
+@findex message-insert-disposition-notification-to
+Insert a request for a disposition
+notification.  (@code{message-insert-disposition-notification-to}).
+This means that if the recipient supports RFC 2298 she might send you a
+notification that she received the message.
+
+@item M-x message-insert-importance-high
+@kindex M-x message-insert-importance-high
+@findex message-insert-importance-high
+@cindex Importance
+Insert an @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
+@cindex Importance
+Insert an @samp{Importance} header with a value of @samp{low}, deleting
+headers if necessary.
+
+@item C-c C-f s
+@kindex C-c C-f s
+@findex message-change-subject
+@cindex Subject
+Change the current @samp{Subject} header.  Ask for new @samp{Subject}
+header and append @samp{(was: <Old Subject>)}.  The old subject can be
+stripped on replying, see @code{message-subject-trailing-was-query}
+(@pxref{Message Headers}).
+
+@item C-c C-f x
+@kindex C-c C-f x
+@findex message-cross-post-followup-to
+@vindex message-cross-post-default
+@vindex message-cross-post-note-function
+@cindex X-Post
+@cindex cross-post
+Set up the @samp{FollowUp-To} header with a target newsgroup for a
+cross-post, add that target newsgroup to the @samp{Newsgroups} header if
+it is not a member of @samp{Newsgroups}, and insert a note in the body.
+If @code{message-cross-post-default} is @code{nil} or if this command is
+called with a prefix-argument, only the @samp{FollowUp-To} header will
+be set but the target newsgroup will not be added to the
+@samp{Newsgroups} header.  The function to insert a note is controlled
+by the @code{message-cross-post-note-function} variable.
+
+@item C-c C-f t
+@kindex C-c C-f t
+@findex message-reduce-to-to-cc
+Replace contents of @samp{To} header with contents of @samp{Cc}
+header (or the @samp{Bcc} header, if there is no @samp{Cc} header).
+
+@item C-c C-f w
+@kindex C-c C-f w
+@findex message-insert-wide-reply
+Insert @samp{To} and @samp{Cc} headers as if you were doing a wide
+reply even if the message was not made for a wide reply first.
+
+@item C-c C-f a
+@kindex C-c C-f a
+@findex message-add-archive-header
+@vindex message-archive-header
+@vindex message-archive-note
+@cindex X-No-Archive
+Insert @samp{X-No-Archive: Yes} in the header and a note in the body.
+The header and the note can be customized using
+@code{message-archive-header} and @code{message-archive-note}.  When
+called with a prefix argument, ask for a text to insert.  If you don't
+want the note in the body, set @code{message-archive-note} to
+@code{nil}.
+
+@end table
+
+
+@node Movement
+@section Movement
+
+@table @kbd
+@item C-c C-b
+@kindex C-c C-b
+@findex message-goto-body
+Move to the beginning of the body of the message
+(@code{message-goto-body}).
+
+@item C-c C-i
+@kindex C-c C-i
+@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
+@vindex 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.)  This behavior can be disabled by toggling
+the variable @code{message-beginning-of-line}.
+
+@end table
+
+
+@node Insertion
+@section Insertion
+
+@table @kbd
+
+@item C-c C-y
+@kindex C-c C-y
+@findex message-yank-original
+Yank the message that's being replied to into the message buffer
+(@code{message-yank-original}).
+
+@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}).
+
+@item C-c C-q
+@kindex C-c C-q
+@findex message-fill-yanked-message
+Fill the yanked message (@code{message-fill-yanked-message}).  Warning:
+Can severely mess up the yanked text if its quoting conventions are
+strange.  You'll quickly get a feel for when it's safe, though.  Anyway,
+just remember that @kbd{C-x u} (@code{undo}) is available and you'll be
+all right.
+
+@item C-c C-w
+@kindex C-c C-w
+@findex message-insert-signature
+Insert a signature at the end of the buffer
+(@code{message-insert-signature}).
+
+@item C-c M-h
+@kindex C-c M-h
+@findex message-insert-headers
+Insert the message headers (@code{message-insert-headers}).
+
+@item C-c M-m
+@kindex C-c M-m
+@findex message-mark-inserted-region
+Mark some region in the current article with enclosing tags.  See
+@code{message-mark-insert-begin} and @code{message-mark-insert-end}.
+When called with a prefix argument, use slrn style verbatim marks
+(@samp{#v+} and @samp{#v-}).
+
+@item C-c M-f
+@kindex C-c M-f
+@findex message-mark-insert-file
+Insert a file in the current article with enclosing tags.
+See @code{message-mark-insert-begin} and @code{message-mark-insert-end}.
+When called with a prefix argument, use slrn style verbatim marks
+(@samp{#v+} and @samp{#v-}).
+
+@end table
+
+
+@node MIME
+@section MIME
+@cindex MML
+@cindex MIME
+@cindex multipart
+@cindex attachment
+
+Message is a @acronym{MIME}-compliant posting agent.  The user generally
+doesn't have to do anything to make the @acronym{MIME} happen---Message will
+automatically add the @code{Content-Type} and
+@code{Content-Transfer-Encoding} headers.
+
+@findex mml-attach-file
+@kindex C-c C-a
+The most typical thing users want to use the multipart things in
+@acronym{MIME} for is to add ``attachments'' to mail they send out.
+This can be done with the @kbd{C-c C-a} command (@kbd{M-x mml-attach-file}),
+which will prompt for a file name and a @acronym{MIME} type.
+
+@vindex mml-dnd-protocol-alist
+@vindex mml-dnd-attach-options
+If your Emacs supports drag and drop, you can also drop the file in the
+Message buffer.  The variable @code{mml-dnd-protocol-alist} specifies
+what kind of action is done when you drop a file into the Message
+buffer.  The variable @code{mml-dnd-attach-options} controls which
+@acronym{MIME} options you want to specify when dropping a file.  If it
+is a list, valid members are @code{type}, @code{description} and
+@code{disposition}.  @code{disposition} implies @code{type}.  If it is
+@code{nil}, don't ask for options.  If it is @code{t}, ask the user
+whether or not to specify options.
+
+You can also create arbitrarily complex multiparts using the @acronym{MML}
+language (@pxref{Composing, , Composing, emacs-mime, The Emacs MIME
+Manual}).
+
+@node IDNA
+@section IDNA
+@cindex IDNA
+@cindex internationalized domain names
+@cindex non-ascii domain names
+
+@acronym{IDNA} is a standard way to encode non-@acronym{ASCII} domain
+names into a readable @acronym{ASCII} string.  The details can be
+found in RFC 3490.
+
+Message is a @acronym{IDNA}-compliant posting agent.  The user
+generally doesn't have to do anything to make the @acronym{IDNA}
+happen---Message will encode non-@acronym{ASCII} domain names in @code{From},
+@code{To}, and @code{Cc} headers automatically.
+
+Until @acronym{IDNA} becomes more well known, Message queries you
+whether @acronym{IDNA} encoding of the domain name really should
+occur.  Some users might not be aware that domain names can contain
+non-@acronym{ASCII} now, so this gives them a safety net if they accidentally
+typed a non-@acronym{ASCII} domain name.
+
+@vindex message-use-idna
+The @code{message-use-idna} variable control whether @acronym{IDNA} is
+used.  If the variable is @code{nil} no @acronym{IDNA} encoding will
+ever happen, if it is set to the symbol @code{ask} the user will be
+queried, and if set to @code{t} (which is the default if @acronym{IDNA}
+is fully available) @acronym{IDNA} encoding happens automatically.
+
+@findex message-idna-to-ascii-rhs
+If you want to experiment with the @acronym{IDNA} encoding, you can
+invoke @kbd{M-x message-idna-to-ascii-rhs RET} in the message buffer
+to have the non-@acronym{ASCII} domain names encoded while you edit
+the message.
+
+Note that you must have @uref{http://www.gnu.org/software/libidn/, GNU
+Libidn} installed in order to use this functionality.
+
+@node Security
+@section Security
+@cindex Security
+@cindex S/MIME
+@cindex PGP
+@cindex PGP/MIME
+@cindex sign
+@cindex encrypt
+@cindex secure
+
+By default, e-mails are transmitted without any protection around the
+Internet, which implies that they can be read and changed by lots of
+different parties.  In particular, they are analyzed under bulk
+surveillance, which violates basic human rights.  To defend those
+rights, digital self-defense is necessary (in addition to legal
+changes), and encryption and digital signatures are powerful
+techniques for self-defense.  In essence, encryption ensures that
+only the intended recipient will be able to read a message, while
+digital signatures make sure that modifications to messages can be
+detected by the recipient.
+
+Nowadays, there are two major incompatible e-mail encryption
+standards, namely @acronym{OpenPGP} and @acronym{S/MIME}.  Both of
+these standards are implemented by the @uref{https://www.gnupg.org/,
+GNU Privacy Guard (GnuPG)}, which needs to be installed as external
+software in addition to GNU Emacs.  Before you can start to encrypt,
+decrypt, and sign messages, you need to create a so-called key-pair,
+which consists of a private key and a public key.  Your @emph{public} key
+(also known as @emph{certificate}, in particular with @acronym{S/MIME}), is
+used by others (a) to encrypt messages intended for you and (b) to verify
+digital signatures created by you.  In contrast, you use your @emph{private}
+key (a) to decrypt messages and (b) to sign messages.  (You may want to
+think of your public key as an open safe that you offer to others such
+that they can deposit messages and lock the door, while your private
+key corresponds to the opening combination for the safe.)
+
+Thus, you need to perform the following steps for e-mail encryption,
+typically outside Emacs.  See, for example, the
+@uref{https://www.gnupg.org/gph/en/manual.html, The GNU Privacy
+Handbook} for details covering the standard @acronym{OpenPGP} with
+@acronym{GnuPG}.
+@enumerate
+@item
+Install GnuPG.
+@item
+Create a key-pair for your own e-mail address.
+@item
+Distribute your public key, e.g., via upload to key servers.
+@item
+Import the public keys for the recipients to which you want to send
+encrypted e-mails.
+@end enumerate
+
+Whether to use the standard @acronym{OpenPGP} or @acronym{S/MIME} is
+beyond the scope of this documentation.  Actually, you can use one
+standard for one set of recipients and the other standard for
+different recipients (depending their preferences or capabilities).
+
+In case you are not familiar with all those acronyms: The standard
+@acronym{OpenPGP} is also called @acronym{PGP} (Pretty Good Privacy).
+The command line tools offered by @acronym{GnuPG} for
+@acronym{OpenPGP} are called @command{gpg} and @command{gpg2}, while
+the one for @acronym{S/MIME} is called @command{gpgsm}.  An
+alternative, but discouraged, tool for @acronym{S/MIME} is
+@command{openssl}.  To make matters worse, e-mail messages can be
+formed in two different ways with @acronym{OpenPGP}, namely
+@acronym{PGP} (RFC 1991/4880) and @acronym{PGP/MIME} (RFC 2015/3156).
+
+The good news, however, is the following: In GNU Emacs, Message
+supports all those variants, comes with reasonable defaults that can
+be customized according to your needs, and invokes the proper command
+line tools behind the scenes for encryption, decryption, as well as
+creation and verification of digital signatures.
+
+Message uses the @acronym{MML} language for the creation of signed
+and/or encrypted messages as explained in the following.
+
+
+@menu
+* Signing and encryption::      Signing and encrypting commands.
+* Using S/MIME::                Using S/MIME
+* Using OpenPGP::               Using OpenPGP
+* Passphrase caching::          How to cache passphrases
+* PGP Compatibility::           Compatibility with older implementations
+* Encrypt-to-self::             Reading your own encrypted messages
+* Bcc Warning::                 Do not use encryption with Bcc headers
+@end menu
+
+@node Signing and encryption
+@subsection Signing and encrypting commands
+
+Instructing @acronym{MML} to perform security operations on a
+@acronym{MIME} part is done using the @kbd{C-c C-m s} key map for
+signing and the @kbd{C-c C-m c} key map for encryption, as follows.
+@table @kbd
+
+@item C-c C-m s s
+@kindex C-c C-m s s
+@findex mml-secure-message-sign-smime
+
+Digitally sign current message using @acronym{S/MIME}.
+
+@item C-c C-m s o
+@kindex C-c C-m s o
+@findex mml-secure-message-sign-pgp
+
+Digitally sign current message using @acronym{PGP}.
+
+@item C-c C-m s p
+@kindex C-c C-m s p
+@findex mml-secure-message-sign-pgpmime
+
+Digitally sign current message using @acronym{PGP/MIME}.
+
+@item C-c C-m c s
+@kindex C-c C-m c s
+@findex mml-secure-message-encrypt-smime
+
+Digitally encrypt current message using @acronym{S/MIME}.
+
+@item C-c C-m c o
+@kindex C-c C-m c o
+@findex mml-secure-message-encrypt-pgp
+
+Digitally encrypt current message using @acronym{PGP}.
+
+@item C-c C-m c p
+@kindex C-c C-m c p
+@findex mml-secure-message-encrypt-pgpmime
+
+Digitally encrypt current message using @acronym{PGP/MIME}.
+
+@item C-c C-m C-n
+@kindex C-c C-m C-n
+@findex mml-unsecure-message
+Remove security related @acronym{MML} tags from message.
+
+@end table
+
+These commands do not immediately sign or encrypt the message, they
+merely insert the proper @acronym{MML} secure tag to instruct the
+@acronym{MML} engine to perform that operation when the message is
+actually sent.  They may perform other operations too, such as locating
+and retrieving a @acronym{S/MIME} certificate of the person you wish to
+send encrypted mail to.  When the mml parsing engine converts your
+@acronym{MML} into a properly encoded @acronym{MIME} message, the secure
+tag will be replaced with either a part or a multipart tag.  If your
+message contains other mml parts, a multipart tag will be used; if no
+other parts are present in your message a single part tag will be used.
+This way, message mode will do the Right Thing (TM) with
+signed/encrypted multipart messages.
+
+Since signing and especially encryption often is used when sensitive
+information is sent, you may want to have some way to ensure that your
+mail is actually signed or encrypted.  After invoking the above
+sign/encrypt commands, it is possible to preview the raw article by
+using @kbd{C-u C-c RET P} (@code{mml-preview}).  Then you can
+verify that your long rant about what your ex-significant other or
+whomever actually did with that funny looking person at that strange
+party the other night, actually will be sent encrypted.
+
+@emph{Note!}  Neither @acronym{PGP/MIME} nor @acronym{S/MIME} encrypt/signs
+RFC822 headers.  They only operate on the @acronym{MIME} object.  Keep this
+in mind before sending mail with a sensitive Subject line.
+
+By default, when encrypting a message, Gnus will use the
+``signencrypt'' mode, which means the message is both signed and
+encrypted.  If you would like to disable this for a particular
+message, give the @code{mml-secure-message-encrypt-*} command a prefix
+argument, e.g., @kbd{C-u C-c C-m c p}.
+
+Actually using the security commands above is not very difficult.  At
+least not compared with making sure all involved programs talk with each
+other properly.  Thus, we now describe what external libraries or
+programs are required to make things work, and some small general hints.
+
+@node Using S/MIME
+@subsection Using S/MIME
+
+@acronym{S/MIME} requires an external implementation, such as
+@uref{https://www.gnupg.org/, GNU Privacy Guard} or
+@uref{https://www.openssl.org/, OpenSSL}.  The default Emacs interface
+to the S/MIME implementation is EasyPG (@pxref{Top,,EasyPG Assistant
+User's Manual, epa, EasyPG Assistant User's Manual}), which has been
+included in Emacs since version 23 and which relies on the command
+line tool @command{gpgsm} provided by @acronym{GnuPG}.  That tool
+implements certificate management, including certificate revocation
+and expiry, while such tasks need to be performed manually, if OpenSSL
+is used.
+
+The choice between EasyPG and OpenSSL is controlled by the variable
+@code{mml-smime-use}, which needs to be set to the value @code{epg}
+for EasyPG.  Depending on your version of Emacs that value may be the
+default; if not, you can either customize that variable or place the
+following line in your @file{.emacs} file (that line needs to be
+placed above other code related to message/gnus/encryption):
+
+@lisp
+(require 'epg)
+@end lisp
+
+Moreover, you may want to customize the variables
+@code{mml-default-encrypt-method} and
+@code{mml-default-sign-method} to the string @code{"smime"}.
+
+That's all if you want to use S/MIME with EasyPG, and that's the
+recommended way of using S/MIME with Message.
+
+If you think about using OpenSSL instead of EasyPG, please read the
+BUGS section in the manual for the @command{smime} command coming with
+OpenSSL first.  If you still want to use OpenSSL, the following
+applies.
+
+@emph{Note!}  The remainder of this section assumes you have a basic
+familiarity with modern cryptography, @acronym{S/MIME}, various PKCS
+standards, OpenSSL and so on.
+
+The @acronym{S/MIME} support in Message (and @acronym{MML}) can use
+OpenSSL@.  OpenSSL performs the actual @acronym{S/MIME} sign/encrypt
+operations.  OpenSSL can be found 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
+@acronym{MIME} separators so you may wish to avoid it if you would like
+to avoid being regarded as someone who send strange mail.  (Although by
+sending @acronym{S/MIME} messages you've probably already lost that
+contest.)
+
+To be able to send encrypted mail, a personal certificate is not
+required.  Message (@acronym{MML}) need a certificate for the person to whom you
+wish to communicate with though.  You're asked for this when you type
+@kbd{C-c C-m c s}.  Currently there are two ways to retrieve this
+certificate, from a local file or from DNS@.  If you chose a local
+file, it need to contain a X.509 certificate in @acronym{PEM} format.
+If you chose DNS, you're asked for the domain name where the
+certificate is stored, the default is a good guess.  To my belief,
+Message (@acronym{MML}) is the first mail agent in the world to support
+retrieving @acronym{S/MIME} certificates from DNS, so you're not
+likely to find very many certificates out there.  At least there
+should be one, stored at the domain @code{simon.josefsson.org}.  LDAP
+is a more popular method of distributing certificates, support for it
+is planned.  (Meanwhile, you can use @code{ldapsearch} from the
+command line to retrieve a certificate into a file and use it.)
+
+As for signing messages, OpenSSL can't perform signing operations
+without some kind of configuration.  Especially, you need to tell it
+where your private key and your certificate is stored.  @acronym{MML}
+uses an Emacs interface to OpenSSL, aptly named @code{smime.el}, and it
+contain a @code{custom} group used for this configuration.  So, try
+@kbd{M-x customize-group RET smime RET} and look around.
+
+Currently there is no support for talking to a CA (or RA) to create
+your own certificate.  None is planned either.  You need to do this
+manually with OpenSSL or using some other program.  I used Netscape
+and got a free @acronym{S/MIME} certificate from one of the big CA's on the
+net.  Netscape is able to export your private key and certificate in
+PKCS #12 format.  Use OpenSSL to convert this into a plain X.509
+certificate in PEM format as follows.
+
+@example
+$ openssl pkcs12 -in ns.p12 -clcerts -nodes > key+cert.pem
+@end example
+
+The @file{key+cert.pem} file should be pointed to from the
+@code{smime-keys} variable.  You should now be able to send signed mail.
+
+@emph{Note!}  Your private key is now stored unencrypted in the file,
+so take care in handling it.  Storing encrypted keys on the disk are
+supported, and Gnus will ask you for a passphrase before invoking
+OpenSSL@.  Read the OpenSSL documentation for how to achieve this.  If
+you use unencrypted keys (e.g., if they are on a secure storage, or if
+you are on a secure single user machine) simply press @code{RET} at
+the passphrase prompt.
+
+@node Using OpenPGP
+@subsection Using OpenPGP
+
+Use of OpenPGP requires an external software, such
+as @uref{https://www.gnupg.org/, GNU Privacy Guard}.  Pre-OpenPGP
+implementations such as PGP 2.x and PGP 5.x are also supported.  The
+default Emacs interface to the PGP implementation is EasyPG
+(@pxref{Top,,EasyPG Assistant User's Manual, epa, EasyPG Assistant
+User's Manual}), but PGG (@pxref{Top, ,PGG, pgg, PGG Manual}) and
+Mailcrypt are also supported.  @xref{PGP Compatibility}.
+
+As stated earlier, messages encrypted with OpenPGP can be formatted
+according to two different standards, namely @acronym{PGP} or
+@acronym{PGP/MIME}.  The variables
+@code{mml-default-encrypt-method} and
+@code{mml-default-sign-method} determine which variant to prefer,
+@acronym{PGP/MIME} by default.
+
+@node Passphrase caching
+@subsection Passphrase caching
+
+@cindex gpg-agent
+Message with EasyPG internally calls GnuPG (the @command{gpg} or
+@command{gpgsm} command) to perform
+data encryption, and in certain cases (decrypting or signing for
+example), @command{gpg}/@command{gpgsm} requires user's passphrase.
+Currently the recommended way to supply your passphrase is to use the
+@command{gpg-agent} program.
+
+In particular, the @command{gpg-agent} program supports passphrase
+caching so that you do not need to enter your passphrase for every
+decryption/sign operation.  @xref{Agent Options, , , gnupg, Using the
+GNU Privacy Guard}.
+
+How to use @command{gpg-agent} in Emacs depends on your version of
+GnuPG.  With GnuPG version 2.1, @command{gpg-agent} is started
+automatically if necessary.  With older versions you may need to run
+the following command from the shell before starting Emacs.
+
+@example
+eval `gpg-agent --daemon`
+@end example
+
+This will invoke @command{gpg-agent} and set the environment variable
+@code{GPG_AGENT_INFO} to allow @command{gpg} to communicate with it.
+It might be good idea to put this command in your @file{.xsession} or
+@file{.bash_profile}.  @xref{Invoking GPG-AGENT, , , gnupg, Using the
+GNU Privacy Guard}.
+
+Once your @command{gpg-agent} is set up, it will ask you for a
+passphrase as needed for @command{gpg}.  Under the X Window System,
+you will see a new passphrase input dialog appear.  The dialog is
+provided by PIN Entry (the @command{pinentry} command), reasonably
+recent versions of which can also cooperate with Emacs on a text
+console.  If that does not work, you may need to put a passphrase into
+gpg-agent's cache beforehand.  The following command does the trick.
+
+@example
+gpg --use-agent --sign < /dev/null > /dev/null
+@end example
+
+@node PGP Compatibility
+@subsection Compatibility with older implementations
+
+@vindex gpg-temp-directory
+Note, if you are using the @code{gpg.el} you must make sure that the
+directory specified by @code{gpg-temp-directory} have permissions
+0700.
+
+Creating your own key is described in detail in the documentation of
+your PGP implementation, so we refer to it.
+
+If you have imported your old PGP 2.x key into GnuPG, and want to send
+signed and encrypted messages to your fellow PGP 2.x users, you'll
+discover that the receiver cannot understand what you send. One
+solution is to use PGP 2.x instead (e.g., if you use @code{pgg}, set
+@code{pgg-default-scheme} to @code{pgp}). You could also convince your
+fellow PGP 2.x users to convert to GnuPG@.
+@vindex mml-signencrypt-style-alist
+As a final workaround, you can make the sign and encryption work in
+two steps; separately sign, then encrypt a message.  If you would like
+to change this behavior you can customize the
+@code{mml-signencrypt-style-alist} variable.  For example:
+
+@lisp
+(setq mml-signencrypt-style-alist '(("smime" separate)
+                                    ("pgp" separate)
+                                    ("pgpauto" separate)
+                                    ("pgpmime" separate)))
+@end lisp
+
+This causes to sign and encrypt in two passes, thus generating a
+message that can be understood by PGP version 2.
+
+(Refer to @uref{http://www.gnupg.org/gph/en/pgp2x.html} for more
+information about the problem.)
+
+@node Encrypt-to-self
+@subsection Encrypt-to-self
+
+By default, messages are encrypted to all recipients (@code{To},
+@code{Cc}, @code{Bcc} headers).  Thus, you will not be able to decrypt
+your own messages.  To make sure that messages are also encrypted to
+your own key(s), several alternative solutions exist:
+@enumerate
+@item
+Use the @code{encrypt-to} option in the file @file{gpg.conf} (for
+OpenPGP) or @file{gpgsm.conf} (for @acronym{S/MIME} with EasyPG).
+@xref{Invoking GPG, , , gnupg, Using the GNU Privacy Guard}, or
+@xref{Invoking GPGSM, , , gnupg, Using the GNU Privacy Guard}.
+@item
+Include your own e-mail address (for which you created a key-pair)
+among the recipients.
+@item
+Customize the variable @code{mml-secure-openpgp-encrypt-to-self} (for
+OpenPGP) or @code{mml-secure-smime-encrypt-to-self} (for
+@acronym{S/MIME} with EasyPG).
+@end enumerate
+
+@node Bcc Warning
+@subsection Bcc Warning
+
+The @code{Bcc} header is meant to hide recipients of messages.
+However, when encrypted messages are used, the e-mail addresses of all
+@code{Bcc}-headers are given away to all recipients without
+warning, which is a bug, see
+@uref{https://debbugs.gnu.org/cgi/bugreport.cgi?bug=18718}.
+
+
+@node Various Commands
+@section Various Commands
+
+@table @kbd
+
+@item C-c C-r
+@kindex C-c C-r
+@findex message-caesar-buffer-body
+Caesar rotate (aka. rot13) the current message
+(@code{message-caesar-buffer-body}).  If narrowing is in effect, just
+rotate the visible portion of the buffer.  A numerical prefix says how
+many places to rotate the text.  The default is 13.
+
+@item C-c C-e
+@kindex C-c C-e
+@findex message-elide-region
+@vindex message-elide-ellipsis
+Elide the text between point and mark (@code{message-elide-region}).
+The text is killed and replaced with the contents of the variable
+@code{message-elide-ellipsis}.  The default value is to use an ellipsis
+(@samp{[...]}).
+
+This is a format-spec string, and you can use @samp{%l} to say how
+many lines were removed, and @samp{%c} to say how many characters were
+removed.
+
+@item C-c M-k
+@kindex C-c M-k
+@findex message-kill-address
+Kill the address under point.
+
+@item C-c C-z
+@kindex C-c C-z
+@findex message-kill-to-signature
+Kill all the text up to the signature, or if that's missing, up to the
+end of the message (@code{message-kill-to-signature}).
+
+@item C-c C-v
+@kindex C-c C-v
+@findex message-delete-not-region
+Delete all text in the body of the message that is outside the region
+(@code{message-delete-not-region}).
+
+@item M-RET
+@kindex M-RET
+@findex message-newline-and-reformat
+Insert four newlines, and then reformat if inside quoted text.
+
+Here's an example:
+
+@example
+> This is some quoted text.  And here's more quoted text.
+@end example
+
+If point is before @samp{And} and you press @kbd{M-RET}, you'll get:
+
+@example
+> This is some quoted text.
+
+*
+
+> And here's more quoted text.
+@end example
+
+@samp{*} says where point will be placed.
+
+@item C-c M-r
+@kindex C-c M-r
+@findex message-rename-buffer
+Rename the buffer (@code{message-rename-buffer}).  If given a prefix,
+prompt for a new buffer name.
+
+@item TAB
+@kindex TAB
+@findex message-tab
+@vindex message-tab-body-function
+If @code{message-tab-body-function} is non-@code{nil}, execute the
+function it specifies.  Otherwise use the function bound to @kbd{TAB} in
+@code{text-mode-map} or @code{global-map}.
+
+@end table
+
+
+@node Sending
+@section Sending
+
+@table @kbd
+@item C-c C-c
+@kindex C-c C-c
+@findex message-send-and-exit
+Send the message and bury the current buffer
+(@code{message-send-and-exit}).
+
+@item C-c C-s
+@kindex C-c C-s
+@findex message-send
+Send the message (@code{message-send}).
+
+@item C-c C-d
+@kindex C-c C-d
+@findex message-dont-send
+Bury the message buffer and exit (@code{message-dont-send}).
+
+@item C-c C-k
+@kindex C-c C-k
+@findex message-kill-buffer
+Kill the message buffer and exit (@code{message-kill-buffer}).
+
+@end table
+
+
+
+@node Mail Aliases
+@section Mail Aliases
+@cindex mail aliases
+@cindex aliases
+@cindex completion
+@cindex ecomplete
+
+@vindex message-mail-alias-type
+The @code{message-mail-alias-type} variable controls what type of mail
+alias expansion to use.  Currently two forms are supported:
+@code{mailabbrev} and @code{ecomplete}.  If this variable is
+@code{nil}, no mail alias expansion will be performed.
+
+@code{mailabbrev} works by parsing the @file{/etc/mailrc} and
+@file{~/.mailrc} files.  These files look like:
+
+@example
+alias lmi "Lars Magne Ingebrigtsen <larsi@@ifi.uio.no>"
+alias ding "ding@@ifi.uio.no (ding mailing list)"
+@end example
+
+After adding lines like this to your @file{~/.mailrc} file, you should
+be able to just write @samp{lmi} in the @code{To} or @code{Cc} (and so
+on) headers and press @kbd{SPC} to expand the alias.
+
+No expansion will be performed upon sending of the message---all
+expansions have to be done explicitly.
+
+If you're using @code{ecomplete}, all addresses from @code{To} and
+@code{Cc} headers will automatically be put into the
+@file{~/.ecompleterc} file.  When you enter text in the @code{To} and
+@code{Cc} headers, @code{ecomplete} will check out the values stored
+there and ``electrically'' say what completions are possible.  To
+choose one of these completions, use the @kbd{M-n} command to move
+down to the list.  Use @kbd{M-n} and @kbd{M-p} to move down and up the
+list, and @kbd{RET} to choose a completion.
+
+@node Spelling
+@section Spelling
+@cindex spelling
+@findex ispell-message
+
+There are two popular ways to have Emacs spell-check your messages:
+@code{ispell} and @code{flyspell}.  @code{ispell} is the older and
+probably more popular package.  You typically first write the message,
+and then run the entire thing through @code{ispell} and fix all the
+typos.  To have this happen automatically when you send a message, put
+something like the following in your @file{.emacs} file:
+
+@lisp
+(add-hook 'message-send-hook 'ispell-message)
+@end lisp
+
+@vindex ispell-message-dictionary-alist
+If you're in the habit of writing in different languages, this can be
+controlled by the @code{ispell-message-dictionary-alist} variable:
+
+@lisp
+(setq ispell-message-dictionary-alist
+      '(("^Newsgroups:.*\\bde\\." . "deutsch8")
+        (".*" . "default")))
+@end lisp
+
+@code{ispell} depends on having the external @samp{ispell} command
+installed.
+
+The other popular method is using @code{flyspell}.  This package checks
+your spelling while you're writing, and marks any mis-spelled words in
+various ways.
+
+To use @code{flyspell}, put something like the following in your
+@file{.emacs} file:
+
+@lisp
+(defun my-message-setup-routine ()
+  (flyspell-mode 1))
+(add-hook 'message-setup-hook 'my-message-setup-routine)
+@end lisp
+
+@code{flyspell} depends on having the external @samp{ispell} command
+installed.
+
+
+@node Variables
+@chapter Variables
+
+@menu
+* Message Headers::             General message header stuff.
+* Mail Headers::                Customizing mail headers.
+* 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.
+* Message Actions::             Actions to be performed when exiting.
+@end menu
+
+
+@node Message Headers
+@section Message Headers
+
+Message is quite aggressive on the message generation front.  It has to
+be---it's a combined news and mail agent.  To be able to send combined
+messages, it has to generate all headers itself (instead of letting the
+mail/news system do it) to ensure that mail and news copies of messages
+look sufficiently similar.
+
+@table @code
+
+@item message-generate-headers-first
+@vindex message-generate-headers-first
+If @code{t}, generate all required headers before starting to
+compose the message.  This can also be a list of headers to generate:
+
+@lisp
+(setq message-generate-headers-first
+      '(References))
+@end lisp
+
+@vindex message-required-headers
+The variables @code{message-required-headers},
+@code{message-required-mail-headers} and
+@code{message-required-news-headers} specify which headers are
+required.
+
+Note that some headers will be removed and re-generated before posting,
+because of the variable @code{message-deletable-headers} (see below).
+
+@item message-draft-headers
+@vindex message-draft-headers
+When running Message from Gnus, the message buffers are associated
+with a draft group.  @code{message-draft-headers} says which headers
+should be generated when a draft is written to the draft group.
+
+@item message-from-style
+@vindex message-from-style
+Specifies how @code{From} headers should look.  There are four valid
+values:
+
+@table @code
+@item nil
+Just the address---@samp{king@@grassland.com}.
+
+@item parens
+@samp{king@@grassland.com (Elvis Parsley)}.
+
+@item angles
+@samp{Elvis Parsley <king@@grassland.com>}.
+
+@item default
+Look like @code{angles} if that doesn't require quoting, and
+@code{parens} if it does.  If even @code{parens} requires quoting, use
+@code{angles} anyway.
+
+@end table
+
+@item message-deletable-headers
+@vindex message-deletable-headers
+Headers in this list that were previously generated by Message will be
+deleted before posting.  Let's say you post an article.  Then you decide
+to post it again to some other group, you naughty boy, so you jump back
+to the @file{*post-buf*} buffer, edit the @code{Newsgroups} line, and
+ship it off again.  By default, this variable makes sure that the old
+generated @code{Message-ID} is deleted, and a new one generated.  If
+this isn't done, the entire empire would probably crumble, anarchy would
+prevail, and cats would start walking on two legs and rule the world.
+Allegedly.
+
+@item message-default-headers
+@vindex message-default-headers
+Header lines to be inserted in outgoing messages before you edit the
+message, so you can edit or delete their lines. If set to a string, it
+is directly inserted. If set to a function, it is called and its
+result is inserted.
+
+@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
+failed to grasp this fact, and have ``internationalized'' their software
+to use abominations like @samp{Aw: } (``antwort'') or @samp{Sv: }
+(``svar'') instead, which is meaningless and evil.  However, you may
+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
+      (concat
+       "^[ \t]*"
+         "\\("
+           "\\("
+             "[Aa][Nn][Tt][Ww]\\.?\\|"     ; antw
+             "[Aa][Ww]\\|"                 ; aw
+             "[Ff][Ww][Dd]?\\|"            ; fwd
+             "[Oo][Dd][Pp]\\|"             ; odp
+             "[Rr][Ee]\\|"                 ; re
+             "[Rr][\311\351][Ff]\\.?\\|"   ; ref
+             "[Ss][Vv]"                    ; sv
+           "\\)"
+           "\\(\\[[0-9]*\\]\\)"
+           "*:[ \t]*"
+         "\\)"
+       "*[ \t]*"
+       ))
+@end lisp
+
+@item message-subject-trailing-was-query
+@vindex message-subject-trailing-was-query
+@vindex message-subject-trailing-was-ask-regexp
+@vindex message-subject-trailing-was-regexp
+Controls what to do with trailing @samp{(was: <old subject>)} in subject
+lines.  If @code{nil}, leave the subject unchanged.  If it is the symbol
+@code{ask}, query the user what to do.  In this case, the subject is
+matched against @code{message-subject-trailing-was-ask-regexp}.  If
+@code{message-subject-trailing-was-query} is @code{t}, always strip the
+trailing old subject.  In this case,
+@code{message-subject-trailing-was-regexp} is used.
+
+@item message-alternative-emails
+@vindex message-alternative-emails
+Regexp matching alternative email addresses.  The first address in the
+To, Cc or From headers of the original article matching this variable is
+used as the From field of outgoing messages, replacing the default From
+value.
+
+For example, if you have two secondary email addresses john@@home.net
+and john.doe@@work.com and want to use them in the From field when
+composing a reply to a message addressed to one of them, you could set
+this variable like this:
+
+@lisp
+(setq message-alternative-emails
+      (regexp-opt '("john@@home.net" "john.doe@@work.com")))
+@end lisp
+
+This variable has precedence over posting styles and anything that runs
+off @code{message-setup-hook}.
+
+@item message-allow-no-recipients
+@vindex message-allow-no-recipients
+Specifies what to do when there are no recipients other than
+@code{Gcc} or @code{Fcc}.  If it is @code{always}, the posting is
+allowed.  If it is @code{never}, the posting is not allowed.  If it is
+@code{ask} (the default), you are prompted.
+
+@item message-hidden-headers
+@vindex message-hidden-headers
+A regexp, a list of regexps, or a list where the first element is
+@code{not} and the rest are regexps.  It says which headers to keep
+hidden when composing a message.
+
+@lisp
+(setq message-hidden-headers
+      '(not "From" "Subject" "To" "Cc" "Newsgroups"))
+@end lisp
+
+Headers are hidden using narrowing, you can use @kbd{M-x widen} to
+expose them in the buffer.
+
+@item message-header-synonyms
+@vindex message-header-synonyms
+A list of lists of header synonyms.  E.g., if this list contains a
+member list with elements @code{Cc} and @code{To}, then
+@code{message-carefully-insert-headers} will not insert a @code{To}
+header when the message is already @code{Cc}ed to the recipient.
+
+@end table
+
+
+@node Mail Headers
+@section Mail Headers
+
+@table @code
+@item message-required-mail-headers
+@vindex message-required-mail-headers
+@xref{News Headers}, for the syntax of this variable.  It is
+@code{(From Subject Date (optional . In-Reply-To) Message-ID
+(optional . User-Agent))} by default.
+
+@item message-ignored-mail-headers
+@vindex message-ignored-mail-headers
+Regexp of headers to be removed before mailing.  The default is@*
+@samp{^[GF]cc:\\|^Resent-Fcc:\\|^Xref:\\|^X-Draft-From:\\|@*
+^X-Gnus-Agent-Meta-Information:}.
+
+@item message-default-mail-headers
+@vindex message-default-mail-headers
+This string is inserted at the end of the headers in all message
+buffers that are initialized as mail.
+
+@item message-generate-hashcash
+@vindex message-generate-hashcash
+Variable that indicates whether @samp{X-Hashcash} headers
+should be computed for the message.  @xref{Hashcash, ,Hashcash,gnus,
+The Gnus Manual}.  If @code{opportunistic}, only generate the headers
+when it doesn't lead to the user having to wait.
+
+@end table
+
+
+@node Mail Variables
+@section Mail Variables
+
+@table @code
+@item message-send-mail-function
+@vindex message-send-mail-function
+@findex message-send-mail-function
+@findex message-send-mail-with-sendmail
+@findex message-send-mail-with-mh
+@findex message-send-mail-with-qmail
+@findex message-smtpmail-send-it
+@findex smtpmail-send-it
+@findex feedmail-send-it
+@findex message-send-mail-with-mailclient
+Function used to send the current buffer as mail.  The default is
+@code{message-send-mail-with-sendmail}, or @code{smtpmail-send-it}
+according to the system.  Other valid values include
+@code{message-send-mail-with-mailclient},
+@code{message-send-mail-with-mh}, @code{message-send-mail-with-qmail},
+@code{message-smtpmail-send-it} and @code{feedmail-send-it}.
+
+The function
+@code{message-send-mail-with-sendmail} pipes your article to the
+@code{sendmail} binary for further queuing and sending.  When your local
+system is not configured for sending mail using @code{sendmail}, and you
+have access to a remote @acronym{SMTP} server, you can set
+@code{message-send-mail-function} to @code{smtpmail-send-it} and make
+sure to setup the @code{smtpmail} package correctly.  An example:
+
+@lisp
+(setq message-send-mail-function 'smtpmail-send-it
+      smtpmail-default-smtp-server "YOUR SMTP HOST")
+@end lisp
+
+To the thing similar to this, there is
+@code{message-smtpmail-send-it}.  It is useful if your @acronym{ISP}
+requires the @acronym{POP}-before-@acronym{SMTP} authentication.
+@xref{POP before SMTP, , POP before SMTP, gnus, The Gnus Manual}.
+
+@cindex X-Message-SMTP-Method
+If you have a complex @acronym{SMTP} setup, and want some messages to
+go via one mail server, and other messages to go through another, you
+can use the @samp{X-Message-SMTP-Method} header.  These are the
+supported values:
+
+@table @samp
+@item smtpmail
+
+@example
+X-Message-SMTP-Method: smtp smtp.fsf.org 587
+@end example
+
+This will send the message via @samp{smtp.fsf.org}, using port 587.
+
+@example
+X-Message-SMTP-Method: smtp smtp.fsf.org 587 other-user
+@end example
+
+This is the same as the above, but uses @samp{other-user} as the user
+name when authenticating.  This is handy if you have several
+@acronym{SMTP} accounts on the same server.
+
+@item sendmail
+
+@example
+X-Message-SMTP-Method: sendmail
+@end example
+
+This will send the message via the locally installed sendmail/exim/etc
+installation.
+
+@end table
+
+@item message-mh-deletable-headers
+@vindex message-mh-deletable-headers
+Most versions of MH doesn't like being fed messages that contain the
+headers in this variable.  If this variable is non-@code{nil} (which is
+the default), these headers will be removed before mailing when sending
+messages via MH@.  Set it to @code{nil} if your MH can handle these
+headers.
+
+@item message-qmail-inject-program
+@vindex message-qmail-inject-program
+@cindex qmail
+Location of the qmail-inject program.
+
+@item message-qmail-inject-args
+@vindex message-qmail-inject-args
+Arguments passed to qmail-inject programs.
+This should be a list of strings, one string for each argument.  It
+may also be a function.
+
+E.g., if you wish to set the envelope sender address so that bounces
+go to the right place or to deal with listserv's usage of that address, you
+might set this variable to @code{'("-f" "you@@some.where")}.
+
+@item message-sendmail-f-is-evil
+@vindex message-sendmail-f-is-evil
+@cindex sendmail
+Non-@code{nil} means don't add @samp{-f username} to the sendmail
+command line.  Doing so would be even more evil than leaving it out.
+
+@item message-sendmail-envelope-from
+@vindex message-sendmail-envelope-from
+When @code{message-sendmail-f-is-evil} is @code{nil}, this specifies
+the address to use in the @acronym{SMTP} envelope.  If it is
+@code{nil}, use @code{user-mail-address}.  If it is the symbol
+@code{header}, use the @samp{From} header of the message.
+
+@item message-mailer-swallows-blank-line
+@vindex message-mailer-swallows-blank-line
+Set this to non-@code{nil} if the system's mailer runs the header and
+body together.  (This problem exists on SunOS 4 when sendmail is run
+in remote mode.)  The value should be an expression to test whether
+the problem will actually occur.
+
+@item message-send-mail-partially-limit
+@vindex message-send-mail-partially-limit
+@cindex split large message
+The limitation of messages sent as message/partial.  The lower bound
+of message size in characters, beyond which the message should be sent
+in several parts.  If it is @code{nil} (which is the default), the
+size is unlimited.
+
+@end table
+
+
+@node News Headers
+@section News Headers
+
+@vindex message-required-news-headers
+@code{message-required-news-headers} a list of header symbols.  These
+headers will either be automatically generated, or, if that's
+impossible, they will be prompted for.  The following symbols are valid:
+
+@table @code
+
+@item From
+@cindex From
+@findex user-full-name
+@findex user-mail-address
+This required header will be filled out with the result of the
+@code{message-make-from} function, which depends on the
+@code{message-from-style}, @code{user-full-name},
+@code{user-mail-address} variables.
+
+@item Subject
+@cindex Subject
+This required header will be prompted for if not present already.
+
+@item Newsgroups
+@cindex Newsgroups
+This required header says which newsgroups the article is to be posted
+to.  If it isn't present already, it will be prompted for.
+
+@item Organization
+@cindex organization
+@vindex message-user-organization
+@vindex message-user-organization-file
+This optional header will be filled out depending on the
+@code{message-user-organization} variable.
+@code{message-user-organization-file} will be used if this variable is
+@code{t}.  This variable can also be a string (in which case this string
+will be used), or it can be a function (which will be called with no
+parameters and should return a string to be used).
+
+@item Lines
+@cindex Lines
+This optional header will be computed by Message.
+
+@item Message-ID
+@cindex Message-ID
+@vindex message-user-fqdn
+@vindex mail-host-address
+@vindex user-mail-address
+@findex system-name
+@cindex Sun
+@cindex i-did-not-set--mail-host-address--so-tickle-me
+This required header will be generated by Message.  A unique ID will be
+created based on the date, time, user name (for the local part) and the
+domain part.  For the domain part, message will look (in this order) at
+@code{message-user-fqdn}, @code{system-name}, @code{mail-host-address}
+and @code{message-user-mail-address} (i.e., @code{user-mail-address})
+until a probably valid fully qualified domain name (FQDN) was found.
+
+@item User-Agent
+@cindex User-Agent
+This optional header will be filled out according to the
+@code{message-newsreader} local variable.
+
+@item In-Reply-To
+This optional header is filled out using the @code{Date} and @code{From}
+header of the article being replied to.
+
+@item Expires
+@cindex Expires
+@vindex message-expires
+This extremely optional header will be inserted according to the
+@code{message-expires} variable.  It is highly deprecated and shouldn't
+be used unless you know what you're doing.
+
+@item Distribution
+@cindex Distribution
+@vindex message-distribution-function
+This optional header is filled out according to the
+@code{message-distribution-function} variable.  It is a deprecated and
+much misunderstood header.
+
+@item Path
+@cindex path
+@vindex message-user-path
+This extremely optional header should probably never be used.
+However, some @emph{very} old servers require that this header is
+present.  @code{message-user-path} further controls how this
+@code{Path} header is to look.  If it is @code{nil}, use the server name
+as the leaf node.  If it is a string, use the string.  If it is neither
+a string nor @code{nil}, use the user name only.  However, it is highly
+unlikely that you should need to fiddle with this variable at all.
+@end table
+
+@cindex Mime-Version
+In addition, you can enter conses into this list.  The @sc{car} of this cons
+should be a symbol.  This symbol's name is the name of the header, and
+the @sc{cdr} can either be a string to be entered verbatim as the value of
+this header, or it can be a function to be called.  This function should
+take no arguments, and return a string to be inserted.  For
+instance, if you want to insert @code{Mime-Version: 1.0}, you should
+enter @code{(Mime-Version . "1.0")} into the list.
+
+If the list contains a cons where the @sc{car} of the cons is
+@code{optional}, the @sc{cdr} of this cons will only be inserted if it is
+non-@code{nil}.
+
+If you want to delete an entry from this list, the following Lisp
+snippet might be useful.  Adjust accordingly if you want to remove
+another element.
+
+@lisp
+(setq message-required-news-headers
+      (delq 'Message-ID message-required-news-headers))
+@end lisp
+
+Other variables for customizing outgoing news articles:
+
+@table @code
+
+@item message-syntax-checks
+@vindex message-syntax-checks
+Controls what syntax checks should not be performed on outgoing posts.
+To disable checking of long signatures, for instance, add
+
+@lisp
+(signature . disabled)
+@end lisp
+
+to this list.
+
+Valid checks are:
+
+@table @code
+@item approved
+@cindex approved
+Check whether the article has an @code{Approved} header, which is
+something only moderators should include.
+@item continuation-headers
+Check whether there are continuation header lines that don't begin with
+whitespace.
+@item control-chars
+Check for invalid characters.
+@item empty
+Check whether the article is empty.
+@item existing-newsgroups
+Check whether the newsgroups mentioned in the @code{Newsgroups} and
+@code{Followup-To} headers exist.
+@item from
+Check whether the @code{From} header seems nice.
+@item illegible-text
+Check whether there is any non-printable character in the body.
+@item invisible-text
+Check whether there is any invisible text in the buffer.
+@item long-header-lines
+Check for too long header lines.
+@item long-lines
+@cindex long lines
+Check for too long lines in the body.
+@item message-id
+Check whether the @code{Message-ID} looks syntactically ok.
+@item multiple-headers
+Check for the existence of multiple equal headers.
+@item new-text
+Check whether there is any new text in the messages.
+@item newsgroups
+Check whether the @code{Newsgroups} header exists and is not empty.
+@item quoting-style
+Check whether text follows last quoted portion.
+@item repeated-newsgroups
+Check whether the @code{Newsgroups} and @code{Followup-to} headers
+contains repeated group names.
+@item reply-to
+Check whether the @code{Reply-To} header looks ok.
+@item sender
+@cindex Sender
+Insert a new @code{Sender} header if the @code{From} header looks odd.
+@item sendsys
+@cindex sendsys
+Check for the existence of version and sendsys commands.
+@item shoot
+Check whether the domain part of the @code{Message-ID} header looks ok.
+@item shorten-followup-to
+Check whether to add a @code{Followup-to} header to shorten the number
+of groups to post to.
+@item signature
+Check the length of the signature.
+@item size
+Check for excessive size.
+@item subject
+Check whether the @code{Subject} header exists and is not empty.
+@item subject-cmsg
+Check the subject for commands.
+@item valid-newsgroups
+Check whether the @code{Newsgroups} and @code{Followup-to} headers
+are valid syntactically.
+@end table
+
+All these conditions are checked by default, except for @code{sender}
+for which the check is disabled by default if
+@code{message-insert-canlock} is non-@code{nil} (@pxref{Canceling News}).
+
+@item message-ignored-news-headers
+@vindex message-ignored-news-headers
+Regexp of headers to be removed before posting.  The default is@*
+@samp{^NNTP-Posting-Host:\\|^Xref:\\|^[BGF]cc:\\|^Resent-Fcc:\\|@*
+^X-Draft-From:\\|^X-Gnus-Agent-Meta-Information:}.
+
+@item message-default-news-headers
+@vindex message-default-news-headers
+This string is inserted at the end of the headers in all message
+buffers that are initialized as news.
+
+@end table
+
+
+@node News Variables
+@section News Variables
+
+@table @code
+@item message-send-news-function
+@vindex message-send-news-function
+Function used to send the current buffer as news.  The default is
+@code{message-send-news}.
+
+@item message-post-method
+@vindex message-post-method
+Gnusish @dfn{select method} (see the Gnus manual for details) used for
+posting a prepared news message.
+
+@end table
+
+
+@node Insertion Variables
+@section Insertion Variables
+
+@table @code
+@item message-cite-style
+@vindex message-cite-style
+The overall style to be used when replying to messages. This controls
+things like where the reply should be put relative to the original,
+how the citation is formatted, where the signature goes, etc.
+
+Value is either @code{nil} (no variable overrides) or a let-style list
+of pairs @code{(VARIABLE VALUE)} to override default values.
+
+See @code{gnus-posting-styles} to set this variable for specific
+groups. Presets to impersonate popular mail agents are available in the
+@code{message-cite-style-*} variables.
+
+@item message-cite-reply-position
+@vindex message-cite-reply-position
+Where the reply should be positioned. Available styles are
+@code{traditional} to reply inline, @code{above} for top-posting, and
+@code{below} for bottom-posting
+
+@item message-ignored-cited-headers
+@vindex message-ignored-cited-headers
+All headers that match this regexp will be removed from yanked
+messages.  The default is @samp{.}, which means that all headers will be
+removed.
+
+@item message-cite-prefix-regexp
+@vindex message-cite-prefix-regexp
+Regexp matching the longest possible citation prefix on a line.
+
+@item message-citation-line-function
+@vindex message-citation-line-function
+@cindex attribution line
+Function called to insert the citation line.  The default is
+@code{message-insert-citation-line}, which will lead to citation lines
+that look like:
+
+@example
+Hallvard B Furuseth <h.b.furuseth@@usit.uio.no> writes:
+@end example
+
+@c FIXME: Add 'message-insert-formatted-citation-line' and
+@c 'message-citation-line-format'.
+
+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 @samp{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, The Gnus Manual}, 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 lines
+which use @code{message-yank-cited-prefix} and empty lines which use
+@code{message-yank-empty-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 an article which contains 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-yank-empty-prefix
+@vindex message-yank-empty-prefix
+@cindex yanking
+@cindex quoting
+When yanking text from an article, each empty line will be prefixed with
+the contents of this variable.  The default is @samp{>}.  You can set
+this variable to an empty string to split the cited text into paragraphs
+automatically.  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 message-cite-original-without-signature
+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.
+
+@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-mark-insert-begin
+@vindex message-mark-insert-begin
+String to mark the beginning of some inserted text.
+
+@item message-mark-insert-end
+@vindex message-mark-insert-end
+String to mark the end of some inserted text.
+
+@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.
+If a path is specified, the value of
+@code{message-signature-directory} is ignored, even if set.
+The default is @file{~/.signature}.
+
+@item message-signature-directory
+@vindex message-signature-directory
+Name of directory containing signature files.  Comes in handy if you
+have many such files, handled via Gnus posting styles for instance.
+If @code{nil} (the default), @code{message-signature-file} is expected
+to specify the directory if needed.
+
+
+@item message-signature-insert-empty-line
+@vindex message-signature-insert-empty-line
+If @code{t} (the default value) an empty line is inserted before the
+signature separator.
+
+@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 @acronym{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
+
+@table @code
+@item message-default-charset
+@vindex message-default-charset
+@cindex charset
+Symbol naming a @acronym{MIME} charset.  Non-@acronym{ASCII} characters
+in messages are assumed to be encoded using this charset.  The default
+is @code{iso-8859-1} on non-@sc{mule} Emacsen; otherwise @code{nil},
+which means ask the user.  (This variable is used only on non-@sc{mule}
+Emacsen.)  @xref{Charset Translation, , Charset Translation, emacs-mime,
+Emacs MIME Manual}, for details on the @sc{mule}-to-@acronym{MIME}
+translation process.
+
+@item message-fill-column
+@vindex message-fill-column
+@cindex auto-fill
+Local value for the column beyond which automatic line-wrapping should
+happen for message buffers.  If non-@code{nil} (the default), also turn on
+auto-fill in message buffers.
+
+@item message-signature-separator
+@vindex message-signature-separator
+Regexp matching the signature separator.  It is @samp{^-- *$} by
+default.
+
+@item mail-header-separator
+@vindex mail-header-separator
+String used to separate the headers from the body.  It is @samp{--text
+follows this line--} by default.
+
+@item message-directory
+@vindex message-directory
+Directory used by many mailish things.  The default is @file{~/Mail/}.
+All other mail file variables are derived from @code{message-directory}.
+
+@item message-auto-save-directory
+@vindex message-auto-save-directory
+Directory where Message auto-saves buffers if Gnus isn't running.  If
+@code{nil}, Message won't auto-save.  The default is @file{~/Mail/drafts/}.
+
+@item message-signature-setup-hook
+@vindex message-signature-setup-hook
+Hook run when initializing the message buffer.  It is run after the
+headers have been inserted but before the signature has been inserted.
+
+@item message-setup-hook
+@vindex message-setup-hook
+Hook run as the last thing when the message buffer has been initialized,
+but before yanked text is inserted.
+
+@item message-header-setup-hook
+@vindex message-header-setup-hook
+Hook called narrowed to the headers after initializing the headers.
+
+For instance, if you're running Gnus and wish to insert a
+@samp{Mail-Copies-To} header in all your news articles and all messages
+you send to mailing lists, you could do something like the following:
+
+@lisp
+(defun my-message-header-setup-hook ()
+  (let ((group (or gnus-newsgroup-name "")))
+    (when (or (message-fetch-field "newsgroups")
+              (gnus-group-find-parameter group 'to-address)
+              (gnus-group-find-parameter group 'to-list))
+      (insert "Mail-Copies-To: never\n"))))
+
+(add-hook 'message-header-setup-hook
+          'my-message-header-setup-hook)
+@end lisp
+
+@item message-send-hook
+@vindex message-send-hook
+Hook run before sending messages.
+
+If you want to add certain headers before sending, you can use the
+@code{message-add-header} function in this hook.  For instance:
+@findex message-add-header
+
+@lisp
+(add-hook 'message-send-hook 'my-message-add-content)
+(defun my-message-add-content ()
+  (message-add-header "X-In-No-Sense: Nonsense")
+  (message-add-header "X-Whatever: no"))
+@end lisp
+
+This function won't add the header if the header is already present.
+
+@item message-send-mail-hook
+@vindex message-send-mail-hook
+Hook run before sending mail messages.  This hook is run very late:
+just before the message is actually sent as mail.
+
+@item message-send-news-hook
+@vindex message-send-news-hook
+Hook run before sending news messages.  This hook is run very late:
+just before the message is actually sent as news.
+
+@item message-sent-hook
+@vindex message-sent-hook
+Hook run after sending messages.
+
+@item message-cancel-hook
+@vindex message-cancel-hook
+Hook run when canceling news articles.
+
+@item message-mode-syntax-table
+@vindex message-mode-syntax-table
+Syntax table used in message mode buffers.
+
+@item message-cite-articles-with-x-no-archive
+@vindex message-cite-articles-with-x-no-archive
+If non-@code{nil}, don't strip quoted text from articles that have
+@samp{X-No-Archive} set.  Even if this variable isn't set, you can
+undo the stripping by hitting the @code{undo} keystroke.
+
+@item message-strip-special-text-properties
+@vindex message-strip-special-text-properties
+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.
+
+@item message-send-method-alist
+@vindex message-send-method-alist
+@findex message-mail-p
+@findex message-news-p
+@findex message-send-via-mail
+@findex message-send-via-news
+Alist of ways to send outgoing messages.  Each element has the form:
+
+@lisp
+(@var{type} @var{predicate} @var{function})
+@end lisp
+
+@table @var
+@item type
+A symbol that names the method.
+
+@item predicate
+A function called without any parameters to determine whether the
+message is a message of type @var{type}.  The function will be called in
+the buffer where the message is.
+
+@item function
+A function to be called if @var{predicate} returns non-@code{nil}.
+@var{function} is called with one parameter---the prefix.
+@end table
+
+The default is:
+
+@lisp
+((news message-news-p message-send-via-news)
+ (mail message-mail-p message-send-via-mail))
+@end lisp
+
+The @code{message-news-p} function returns non-@code{nil} if the message
+looks like news, and the @code{message-send-via-news} function sends the
+message according to the @code{message-send-news-function} variable
+(@pxref{News Variables}).  The @code{message-mail-p} function returns
+non-@code{nil} if the message looks like mail, and the
+@code{message-send-via-mail} function sends the message according to the
+@code{message-send-mail-function} variable (@pxref{Mail Variables}).
+
+All the elements in this alist will be tried in order, so a message
+containing both a valid @samp{Newsgroups} header and a valid @samp{To}
+header, for example, will be sent as news, and then as mail.
+@end table
+
+
+
+@node Sending Variables
+@section Sending Variables
+
+@table @code
+
+@item message-fcc-handler-function
+@vindex message-fcc-handler-function
+A function called to save outgoing articles.  This function will be
+called with the name of the file to store the article in.  The default
+function is @code{message-output} which saves in Unix mailbox format.
+
+@item message-courtesy-message
+@vindex message-courtesy-message
+When sending combined messages, this string is inserted at the start of
+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"}.
+
+@item message-fcc-externalize-attachments
+@vindex message-fcc-externalize-attachments
+If @code{nil}, attach files as normal parts in Fcc copies; if it is
+non-@code{nil}, attach local files as external parts.
+
+@item message-interactive
+@vindex message-interactive
+If non-@code{nil} wait for and display errors when sending a message;
+if @code{nil} let the mailer mail back a message to report errors.
+
+@item message-confirm-send
+@vindex message-confirm-send
+When non-@code{nil}, Gnus will ask for confirmation when sending a
+message.
+
+@end table
+
+
+@node Message Buffers
+@section Message Buffers
+
+Message will generate new buffers with unique buffer names when you
+request a message buffer.  When you send the message, the buffer isn't
+normally killed off.  Its name is changed and a certain number of old
+message buffers are kept alive.
+
+@table @code
+@item message-generate-new-buffers
+@vindex message-generate-new-buffers
+Controls whether to create a new message buffer to compose a message.
+Valid values include:
+
+@table @code
+@item nil
+Generate the buffer name in the Message way (e.g., *mail*, *news*, *mail
+to whom*, *news on group*, etc.)@: and continue editing in the existing
+buffer of that name.  If there is no such buffer, it will be newly
+created.
+
+@item unique
+@item t
+Create the new buffer with the name generated in the Message way.
+
+@item unsent
+Similar to @code{unique} but the buffer name begins with "*unsent ".
+
+@item standard
+Similar to @code{nil} but the buffer name is simpler like *mail
+message*.
+@end table
+@table @var
+@item function
+If this is a function, call that function with three parameters: The
+type, the To address and the group name (any of these may be
+@code{nil}).  The function should return the new buffer name.
+@end table
+
+The default value is @code{unsent}.
+
+@item message-max-buffers
+@vindex message-max-buffers
+This variable says how many old message buffers to keep.  If there are
+more message buffers than this, the oldest buffer will be killed.  The
+default is 10.  If this variable is @code{nil}, no old message buffers
+will ever be killed.
+
+@item message-send-rename-function
+@vindex message-send-rename-function
+After sending a message, the buffer is renamed from, for instance,
+@samp{*reply to Lars*} to @samp{*sent reply to Lars*}.  If you don't
+like this, set this variable to a function that renames the buffer in a
+manner you like.  If you don't want to rename the buffer at all, you can
+say:
+
+@lisp
+(setq message-send-rename-function 'ignore)
+@end lisp
+
+@item message-kill-buffer-on-exit
+@findex message-kill-buffer-on-exit
+If non-@code{nil}, kill the buffer immediately on exit.
+
+@end table
+
+
+@node Message Actions
+@section Message Actions
+
+When Message is being used from a news/mail reader, the reader is likely
+to want to perform some task after the message has been sent.  Perhaps
+return to the previous window configuration or mark an article as
+replied.
+
+@vindex message-kill-actions
+@vindex message-postpone-actions
+@vindex message-exit-actions
+@vindex message-send-actions
+The user may exit from the message buffer in various ways.  The most
+common is @kbd{C-c C-c}, which sends the message and exits.  Other
+possibilities are @kbd{C-c C-s} which just sends the message, @kbd{C-c
+C-d} which postpones the message editing and buries the message buffer,
+and @kbd{C-c C-k} which kills the message buffer.  Each of these actions
+have lists associated with them that contains actions to be executed:
+@code{message-send-actions}, @code{message-exit-actions},
+@code{message-postpone-actions}, and @code{message-kill-actions}.
+
+Message provides a function to interface with these lists:
+@code{message-add-action}.  The first parameter is the action to be
+added, and the rest of the arguments are which lists to add this action
+to.  Here's an example from Gnus:
+
+@lisp
+  (message-add-action
+   `(set-window-configuration ,(current-window-configuration))
+   'exit 'postpone 'kill)
+@end lisp
+
+This restores the Gnus window configuration when the message buffer is
+killed, postponed or exited.
+
+An @dfn{action} can be either: a normal function, or a list where the
+@sc{car} is a function and the @sc{cdr} is the list of arguments, or
+a form to be @code{eval}ed.
+
+
+@node Compatibility
+@chapter Compatibility
+@cindex compatibility
+
+Message uses virtually only its own variables---older @code{mail-}
+variables aren't consulted.  To force Message to take those variables
+into account, you can put the following in your @file{.emacs} file:
+
+@lisp
+(require 'messcompat)
+@end lisp
+
+This will initialize many Message variables from the values in the
+corresponding mail variables.
+
+
+@node Appendices
+@chapter Appendices
+
+@menu
+* Responses::          Standard rules for determining where responses go.
+@end menu
+
+
+@node Responses
+@section Responses
+
+To determine where a message is to go, the following algorithm is used
+by default.
+
+@table @dfn
+@item reply
+A @dfn{reply} is when you want to respond @emph{just} to the person who
+sent the message via mail.  There will only be one recipient.  To
+determine who the recipient will be, the following headers are
+consulted, in turn:
+
+@table @code
+@item Reply-To
+
+@item From
+@end table
+
+
+@item wide reply
+A @dfn{wide reply} is a mail response that includes @emph{all} entities
+mentioned in the message you are responding to.  All mailboxes from the
+following headers will be concatenated to form the outgoing
+@code{To}/@code{Cc} headers:
+
+@table @code
+@item From
+(unless there's a @code{Reply-To}, in which case that is used instead).
+
+@item Cc
+
+@item To
+@end table
+
+If a @code{Mail-Copies-To} header is present, it will also be included
+in the list of mailboxes.  If this header is @samp{never}, that means
+that the @code{From} (or @code{Reply-To}) mailbox will be suppressed.
+
+
+@item followup
+A @dfn{followup} is a response sent via news.  The following headers
+(listed in order of precedence) determine where the response is to be
+sent:
+
+@table @code
+
+@item Followup-To
+
+@item Newsgroups
+
+@end table
+
+If a @code{Mail-Copies-To} header is present, it will be used as the
+basis of the new @code{Cc} header, except if this header is
+@samp{never}.
+
+@end table
+
+
+@node GNU Free Documentation License
+@chapter GNU Free Documentation License
+@include doclicense.texi
+
+@node Index
+@chapter Index
+@printindex cp
+
+@node Key Index
+@chapter Key Index
+@printindex ky
+
+@bye
+
+@c End:
diff --git a/xemacs-packages/gnus/texi/misc/ered.tif b/xemacs-packages/gnus/texi/misc/ered.tif
new file mode 100644 (file)
index 0000000..4b64018
Binary files /dev/null and b/xemacs-packages/gnus/texi/misc/ered.tif differ
diff --git a/xemacs-packages/gnus/texi/misc/eseptember.tif b/xemacs-packages/gnus/texi/misc/eseptember.tif
new file mode 100644 (file)
index 0000000..b75ae6c
Binary files /dev/null and b/xemacs-packages/gnus/texi/misc/eseptember.tif differ
diff --git a/xemacs-packages/gnus/texi/misc/fred.tif b/xemacs-packages/gnus/texi/misc/fred.tif
new file mode 100644 (file)
index 0000000..e04f262
Binary files /dev/null and b/xemacs-packages/gnus/texi/misc/fred.tif differ
diff --git a/xemacs-packages/gnus/texi/misc/fseptember.tif b/xemacs-packages/gnus/texi/misc/fseptember.tif
new file mode 100644 (file)
index 0000000..6583c2b
Binary files /dev/null and b/xemacs-packages/gnus/texi/misc/fseptember.tif differ
diff --git a/xemacs-packages/gnus/texi/misc/larsi.png b/xemacs-packages/gnus/texi/misc/larsi.png
new file mode 100644 (file)
index 0000000..d8b5b27
Binary files /dev/null and b/xemacs-packages/gnus/texi/misc/larsi.png differ
diff --git a/xemacs-packages/gnus/texi/misc/red.png b/xemacs-packages/gnus/texi/misc/red.png
new file mode 100644 (file)
index 0000000..e646e00
Binary files /dev/null and b/xemacs-packages/gnus/texi/misc/red.png differ
diff --git a/xemacs-packages/gnus/texi/misc/red.ps b/xemacs-packages/gnus/texi/misc/red.ps
new file mode 100644 (file)
index 0000000..26148e9
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/misc/september.png b/xemacs-packages/gnus/texi/misc/september.png
new file mode 100644 (file)
index 0000000..1e5539e
Binary files /dev/null and b/xemacs-packages/gnus/texi/misc/september.png differ
diff --git a/xemacs-packages/gnus/texi/pagestyle.sty b/xemacs-packages/gnus/texi/pagestyle.sty
new file mode 100644 (file)
index 0000000..3e3f9e2
--- /dev/null
@@ -0,0 +1,82 @@
+
+\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}}
+\def \newdoublepagestyle#1#2#3#4#5{\@namedef{ps@#1}{\def\@evenhead{#2}%
+        \def\@oddhead{#3}%
+        \def\@evenfoot{#4}%
+        \def\@oddfoot{#5}}}
+
+\newlength{\headtextwidth}
+\setlength{\headtextwidth}{\textwidth}
+\addtolength{\headtextwidth}{2cm}
+\newlength{\headetextwidth}
+\setlength{\headetextwidth}{\headtextwidth}
+\addtolength{\headetextwidth}{-0.5cm}
+\newlength{\headotextwidth}
+\setlength{\headotextwidth}{\headtextwidth}
+\addtolength{\headotextwidth}{-0.35cm}
+\def\outputpage{%
+  \let \protect \noexpand
+  \shipout \vbox{%
+    \set@typeset@protect
+    \aftergroup\set@typeset@protect
+    \@shipoutsetup
+    \@begindvi
+    \vskip \topmargin
+    \moveright\@themargin \vbox {%
+      \setbox\@tempboxa \vbox to\headheight{%
+        \vfil
+        \color@hbox
+          \normalcolor
+          \hb@xt@ \headtextwidth {%
+            \let \label \@gobble
+            \let \index \@gobble
+            \let \glossary \@gobble %% 21 Jun 91
+            \@thehead
+            }%
+        \color@endbox
+        }%                        %% 22 Feb 87
+      \ifodd\c@page
+         \dp\@tempboxa \z@
+         \box\@tempboxa \mbox{} \\
+         \ifx \@oddhead\@empty\else
+   %      \rule{\headotextwidth}{0.5pt}
+         \fi
+      \else
+         \hskip -2.2cm
+         \dp\@tempboxa \z@
+         \box\@tempboxa \mbox{}
+        \\\mbox{}
+         \vskip 2pt
+         \hskip -2.0cm 
+         \ifx \@oddhead\@empty\else
+    %     \rule{\headetextwidth}{0.5pt}
+         \fi
+      \fi  
+      \vskip \headsep
+      \box\@outputbox
+      \baselineskip \footskip
+      \color@hbox
+        \normalcolor
+        \hb@xt@\textwidth{%
+          \let \label \@gobble
+          \let \index \@gobble      %% 22 Feb 87
+          \let \glossary \@gobble   %% 21 Jun 91
+          \@thefoot
+          }%
+      \color@endbox
+      }%
+    }%
+  \global \@colht \textheight
+  \stepcounter{page}%
+  \let\firstmark\botmark
+}
+
+\def\@makechapterhead#1{\gnuspagechapter{#1}}
+
+\setcounter{tocdepth}{3}
+\setcounter{secnumdepth}{3}
diff --git a/xemacs-packages/gnus/texi/picons/att.png b/xemacs-packages/gnus/texi/picons/att.png
new file mode 100644 (file)
index 0000000..f0473ee
Binary files /dev/null and b/xemacs-packages/gnus/texi/picons/att.png differ
diff --git a/xemacs-packages/gnus/texi/picons/berkeley.png b/xemacs-packages/gnus/texi/picons/berkeley.png
new file mode 100644 (file)
index 0000000..e22efcb
Binary files /dev/null and b/xemacs-packages/gnus/texi/picons/berkeley.png differ
diff --git a/xemacs-packages/gnus/texi/picons/caltech.png b/xemacs-packages/gnus/texi/picons/caltech.png
new file mode 100644 (file)
index 0000000..68ae3e9
Binary files /dev/null and b/xemacs-packages/gnus/texi/picons/caltech.png differ
diff --git a/xemacs-packages/gnus/texi/picons/canada.png b/xemacs-packages/gnus/texi/picons/canada.png
new file mode 100644 (file)
index 0000000..2c747a8
Binary files /dev/null and b/xemacs-packages/gnus/texi/picons/canada.png differ
diff --git a/xemacs-packages/gnus/texi/picons/cr.png b/xemacs-packages/gnus/texi/picons/cr.png
new file mode 100644 (file)
index 0000000..d53d2db
Binary files /dev/null and b/xemacs-packages/gnus/texi/picons/cr.png differ
diff --git a/xemacs-packages/gnus/texi/picons/cygnus.xbm b/xemacs-packages/gnus/texi/picons/cygnus.xbm
new file mode 100644 (file)
index 0000000..c69b5ae
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/picons/gnu.xbm b/xemacs-packages/gnus/texi/picons/gnu.xbm
new file mode 100644 (file)
index 0000000..b540df5
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/picons/gov.xbm b/xemacs-packages/gnus/texi/picons/gov.xbm
new file mode 100644 (file)
index 0000000..99f2449
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/picons/laurie.png b/xemacs-packages/gnus/texi/picons/laurie.png
new file mode 100644 (file)
index 0000000..0793f9a
Binary files /dev/null and b/xemacs-packages/gnus/texi/picons/laurie.png differ
diff --git a/xemacs-packages/gnus/texi/picons/mit.png b/xemacs-packages/gnus/texi/picons/mit.png
new file mode 100644 (file)
index 0000000..e297591
Binary files /dev/null and b/xemacs-packages/gnus/texi/picons/mit.png differ
diff --git a/xemacs-packages/gnus/texi/picons/nasa.png b/xemacs-packages/gnus/texi/picons/nasa.png
new file mode 100644 (file)
index 0000000..1679857
Binary files /dev/null and b/xemacs-packages/gnus/texi/picons/nasa.png differ
diff --git a/xemacs-packages/gnus/texi/picons/qmw.xbm b/xemacs-packages/gnus/texi/picons/qmw.xbm
new file mode 100644 (file)
index 0000000..1eb5621
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/picons/rms.png b/xemacs-packages/gnus/texi/picons/rms.png
new file mode 100644 (file)
index 0000000..10dfc25
Binary files /dev/null and b/xemacs-packages/gnus/texi/picons/rms.png differ
diff --git a/xemacs-packages/gnus/texi/picons/ruu.xbm b/xemacs-packages/gnus/texi/picons/ruu.xbm
new file mode 100644 (file)
index 0000000..c44ebcb
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/picons/seuu.xbm b/xemacs-packages/gnus/texi/picons/seuu.xbm
new file mode 100644 (file)
index 0000000..341f175
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/picons/stanford.png b/xemacs-packages/gnus/texi/picons/stanford.png
new file mode 100644 (file)
index 0000000..b3f5dec
Binary files /dev/null and b/xemacs-packages/gnus/texi/picons/stanford.png differ
diff --git a/xemacs-packages/gnus/texi/picons/sun.png b/xemacs-packages/gnus/texi/picons/sun.png
new file mode 100644 (file)
index 0000000..f010f16
Binary files /dev/null and b/xemacs-packages/gnus/texi/picons/sun.png differ
diff --git a/xemacs-packages/gnus/texi/picons/ubc.xbm b/xemacs-packages/gnus/texi/picons/ubc.xbm
new file mode 100644 (file)
index 0000000..51dda39
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/picons/ufl.png b/xemacs-packages/gnus/texi/picons/ufl.png
new file mode 100644 (file)
index 0000000..9521710
Binary files /dev/null and b/xemacs-packages/gnus/texi/picons/ufl.png differ
diff --git a/xemacs-packages/gnus/texi/picons/uio.png b/xemacs-packages/gnus/texi/picons/uio.png
new file mode 100644 (file)
index 0000000..66ff8b0
Binary files /dev/null and b/xemacs-packages/gnus/texi/picons/uio.png differ
diff --git a/xemacs-packages/gnus/texi/picons/unit.png b/xemacs-packages/gnus/texi/picons/unit.png
new file mode 100644 (file)
index 0000000..1dea18d
Binary files /dev/null and b/xemacs-packages/gnus/texi/picons/unit.png differ
diff --git a/xemacs-packages/gnus/texi/picons/upenn.xbm b/xemacs-packages/gnus/texi/picons/upenn.xbm
new file mode 100644 (file)
index 0000000..c9b8894
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/picons/wesleyan.xbm b/xemacs-packages/gnus/texi/picons/wesleyan.xbm
new file mode 100644 (file)
index 0000000..e3b7a86
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/picons/yale.xbm b/xemacs-packages/gnus/texi/picons/yale.xbm
new file mode 100644 (file)
index 0000000..9915964
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/pixidx.sty b/xemacs-packages/gnus/texi/pixidx.sty
new file mode 100644 (file)
index 0000000..13be2e5
--- /dev/null
@@ -0,0 +1,229 @@
+% SHOWIDX DOCUMENT-STYLE OPTION - released 16 June 1991
+%    for LaTeX version 2.09
+% Copyright (C) 1985, 1988, 1989, 1991 by Leslie Lamport
+% Modified by Lars Ingebrigtsen 1993
+%
+% Prints \index entries in outer margin. For use with book or report
+% style.  Note: makes \flushbottom the default.
+
+\typeout{Document style option `showidx' - released 16 June 1991}
+\typeout{Modified for use in eyesore.}
+
+\newbox\eye@boxa
+\newbox\eye@boxb
+\newbox\eye@boxc
+\newbox\eye@boxd
+\newbox\eye@boxe
+\newbox\eye@boxf
+\newbox\eye@boxg
+\newbox\eye@box
+\newbox\new@box
+
+  \global \setbox \eye@boxa \hbox{}
+  \global \setbox \eye@boxb \hbox{}
+  \global \setbox \eye@boxc \hbox{}
+  \global \setbox \eye@boxd \hbox{}
+  \global \setbox \eye@boxe \hbox{}
+  \global \setbox \eye@boxf \hbox{}
+  \global \setbox \eye@boxg \hbox{}
+
+\newdimen\eye@boxadim \global\eye@boxadim\z@
+\newdimen\eye@boxbdim \global\eye@boxbdim\z@
+\newdimen\eye@boxcdim \global\eye@boxcdim\z@
+\newdimen\eye@boxddim \global\eye@boxddim\z@
+\newdimen\eye@boxedim \global\eye@boxedim\z@
+\newdimen\eye@boxfdim \global\eye@boxfdim\z@
+\newdimen\eye@boxgdim \global\eye@boxgdim\z@
+
+\newdimen\gnus@horiz \global\gnus@horiz\z@
+\newdimen\gnus@vert \global\gnus@vert\z@
+
+
+\newdimen\eye@height
+\global\eye@height\textheight
+% \global\advance\eye@height 8cm
+
+\newdimen\eyeins@height
+\global\eyeins@height\z@
+
+\newdimen\eye@adjust
+\global\eye@adjust 0cm
+
+\newinsert\indexbox
+\dimen\indexbox=\maxdimen
+
+\newinsert\gnusbox
+\dimen\gnusbox=\maxdimen
+
+\newdimen\eye@dim
+\newdimen\new@dim
+\newdimen\doinsert
+
+\newdimen\eye@strutd
+\def\eye@strut#1{%
+  \eye@strutd#1
+  \advance\eye@strutd\eye@adjust
+  \advance\eye@strutd -1mm
+  \raisebox{-\eye@strutd}[0pt][0pt]{\rule{1mm}{\eye@strutd}}
+}
+
+\newdimen\eye@tmpd
+\newbox\eye@tmpba
+\newbox\eye@tmpbb
+\def\eye@insbox#1#2#3{%
+  \eye@dim#2
+  \advance\eye@dim\ht#3
+  \advance\eye@dim\eye@adjust
+  \ifdim \eye@dim < \eye@height 
+    \global#2\eye@dim
+    \global\setbox#1
+       \hbox{\unhbox#1
+%             \eye@strut{\ht#3}
+             \unhbox#3
+             \vrule \@height 1cm \@width\z@}
+    \setbox #3 \hbox{}
+  \fi}
+
+\def\@showidx#1{
+  \setbox\new@box\hbox{#1}
+  % \typeout{Vi er i showidx.}
+  \new@dim\z@
+  \ifdim \ht\new@box > \z@
+    \eye@insbox\eye@boxa\eye@boxadim\new@box 
+    \ifdim \ht\new@box > \z@
+    \eye@insbox\eye@boxb\eye@boxbdim\new@box 
+    \ifdim \ht\new@box > \z@
+    \eye@insbox\eye@boxc\eye@boxcdim\new@box 
+    \ifdim \ht\new@box > \z@
+    \eye@insbox\eye@boxd\eye@boxddim\new@box 
+    \ifdim \ht\new@box > \z@
+    \eye@insbox\eye@boxe\eye@boxedim\new@box 
+    \ifdim \ht\new@box > \z@
+    \eye@insbox\eye@boxf\eye@boxfdim\new@box 
+    \ifdim \ht\new@box > \z@
+    \eye@insbox\eye@boxg\eye@boxgdim\new@box 
+    \ifdim \ht\new@box > \z@
+    \else
+      \typeout{Discarding index.}
+    \fi\fi\fi\fi\fi\fi\fi
+  \fi
+
+    \doinsert \z@
+    \ifdim \eyeins@height > \z@
+      \eye@dim\eyeins@height
+      \advance\eye@dim\eye@boxadim
+      \ifdim \eye@dim < \eye@height 
+         \global\eyeins@height\eye@dim
+         \doinsert 1pt
+      \fi
+   \else
+     \doinsert 1pt
+     \global\eyeins@height\eye@boxadim
+   \fi
+
+  \ifdim \ht\eye@boxa > \z@
+  
+    \ifdim \doinsert > \z@
+%      \typeout{Vi inserter i indexbox.}
+      \insert\indexbox{
+         \small
+         \hsize\marginparwidth
+         \hangindent\marginparsep 
+         \parindent\z@
+         \parfillskip\@flushglue
+         \everypar{}\let\par\@@par 
+         \lineskip\normallineskip
+         \baselineskip .8\normalbaselineskip
+         \ifodd\c@page\raggedleft\else\raggedright\fi
+         \leavevmode
+         \relax
+         \unhbox\eye@boxa
+         \relax
+      }
+      \global \setbox \eye@boxa \copy\eye@boxb
+      \global \setbox \eye@boxb \copy\eye@boxc
+      \global \setbox \eye@boxc \copy\eye@boxd
+      \global \setbox \eye@boxd \copy\eye@boxe
+      \global \setbox \eye@boxe \copy\eye@boxf
+      \global \setbox \eye@boxf \copy\eye@boxg
+      \global \setbox \eye@boxg \hbox{}
+      \global \eye@boxadim\eye@boxbdim
+      \global \eye@boxbdim\eye@boxcdim
+      \global \eye@boxcdim\eye@boxddim
+      \global \eye@boxddim\eye@boxedim
+      \global \eye@boxedim\eye@boxfdim
+      \global \eye@boxfdim\eye@boxgdim
+      \global \eye@boxgdim\z@
+    \fi
+  \fi
+
+}
+
+\def\@rightidx{\hskip\columnwidth \hskip\marginparsep}
+\def\@leftidx{\hskip-\marginparsep \hskip-\marginparwidth}
+
+\def\@mkidx{
+
+%  \typeout{Vi er i mkidx 1.}
+
+  \vbox to \z@{
+    \vskip \gnus@vert
+    \hbox{
+      \hskip \gnus@horiz
+      \box\gnusbox
+    }\vss
+  }
+  \vbox to \z@{ 
+    \ifdim \eyeins@height < \textheight
+      \eye@dim \textheight
+      \advance \eye@dim -\eyeins@height
+%      \vskip \eye@dim
+    \else 
+      \eye@dim \eye@height
+      \advance \eye@dim -3cm
+      \ifdim \eyeins@height > \eye@dim
+      %   \vskip -3cm
+    \fi\fi
+    \hbox{
+      \ifodd\c@page \@rightidx \else \@leftidx \fi
+      \box\indexbox
+    }\vss
+  }
+
+  \global\eyeins@height\z@
+
+}
+
+\def\raggedbottom{\def\@textbottom{\vskip
+      \z@ plus.0001fil}\let\@texttop\@mkidx}
+\def\flushbottom{\let\@textbottom\relax \let\@texttop\@mkidx}
+
+\def\margindex#1{\@bsphack
+\begingroup\@sanitize\catcode32=10\relax\@showidx{#1}
+ \endgroup\@esphack}
+
+\def\@gnusfig#1{
+  \insert\gnusbox{
+     \small
+     \hsize\textwidth
+     \hangindent\marginparsep 
+     \parindent\z@
+     \parfillskip\@flushglue
+     \everypar{}\let\par\@@par 
+     \lineskip\normallineskip
+     \baselineskip .8\normalbaselineskip
+     \ifodd\c@page\raggedleft\else\raggedright\fi
+     \leavevmode
+     \relax
+     #1
+     \relax
+  }
+}
+
+\def\gnusfig#1#2#3{\@bsphack
+\begingroup\@sanitize\catcode32=10\relax\@gnusfig{#3}\global\gnus@horiz#1 \global\gnus@vert#2
+ \endgroup\@esphack}
+
+\flushbottom
+
+\endinput
diff --git a/xemacs-packages/gnus/texi/postamble.tex b/xemacs-packages/gnus/texi/postamble.tex
new file mode 100644 (file)
index 0000000..f4f6bf3
--- /dev/null
@@ -0,0 +1,50 @@
+\gnuscleardoublepage
+
+\pagestyle{gnusindex}
+
+\renewcommand\indexname{Key Index}
+\renewcommand{\gnuschaptername}{Key Index}
+\input{gnus.kind}
+\gnuscleardoublepage
+
+\renewcommand\indexname{Function and Variable Index}
+\renewcommand{\gnuschaptername}{Function and Variable Index}
+\input{gnus.gind}
+\gnuscleardoublepage
+\thispagestyle{empty}
+
+\renewcommand\indexname{Concept Index}
+\renewcommand{\gnuschaptername}{Concept Index}
+\input{gnus.cind}
+
+\mbox{}
+%\thispagestyle{empty}\mbox{}\clearpage\thispagestyle{empty}\mbox{}\clearpage
+\ifodd\count0\else\thispagestyle{empty}\clearpage\fi
+\mbox{}
+\thispagestyle{empty}
+\vfill
+
+This manual was written by Lars Magne Ingebrigtsen (1968 --- ) who
+resides in Oslo, Norway and poses as a student, but doesn't get much
+studying done, for some strange reason or other.  When not worshipping
+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=ps/larsi,height=2cm}]{\vspace*{-2.2cm}\epsfig{figure=ps/larsi,height=2.5cm}}
+
+Graphics by Luis Fernandes.  \gnususefonts{}
+
+\clearpage
+\mbox{}
+\thispagestyle{empty}
+\begin{picture}(500,500)(0,0)
+\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/xemacs-packages/gnus/texi/ps/Makefile.in b/xemacs-packages/gnus/texi/ps/Makefile.in
new file mode 100644 (file)
index 0000000..2ad49eb
--- /dev/null
@@ -0,0 +1,215 @@
+prefix = @prefix@
+datarootdir = @datarootdir@
+infodir = @infodir@
+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
+       rm -f Makefile
+
+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/xemacs-packages/gnus/texi/ps/gnus-big-logo.eps b/xemacs-packages/gnus/texi/ps/gnus-big-logo.eps
new file mode 100644 (file)
index 0000000..ea713d8
--- /dev/null
@@ -0,0 +1,212 @@
+%!PS-Adobe-2.0 EPSF-1.2
+%%Creator: Adobe Illustrator 88(TM) format generated by CorelTRACE Version 2.0C
+%%Title:  /home/menja/c/larsi/rgnus/texi/ps/eegnu.eps
+%%BoundingBox: 0 0 890.3 909.7
+%%CreationDate: Fri Oct 11 14:59:05 1996
+%%DocumentFonts:
+%%ColorUsage: B & W
+%%TileBox: 0 0 890.3 909.7
+%%EndComments
+% 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
+%%EndProlog
+%%BeginSetup
+%%EndSetup
+1 i
+2 J
+0 j
+4 M
+[]0 d
+
+%%Note: traced as Normal_Outline
+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
+%%Trailer
+end
+showpage
diff --git a/xemacs-packages/gnus/texi/ps/gnus-head.eps b/xemacs-packages/gnus/texi/ps/gnus-head.eps
new file mode 100644 (file)
index 0000000..cb74c10
--- /dev/null
@@ -0,0 +1,149 @@
+%!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-head.eps
+%%BoundingBox: 0 0 430.6 312.5
+%%CreationDate: Sat Feb  3 13:06:12 1996
+%%DocumentFonts:
+%%ColorUsage: B & W
+%%TileBox: 0 0 430.6 312.5
+%%EndComments
+% 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
+%%EndProlog
+%%BeginSetup
+%%EndSetup
+1 i
+2 J
+0 j
+4 M
+[]0 d
+
+%%Note: traced as Normal_Outline
+0 g
+267.8 10.0 m
+291.8 50.8 294.2 95.0 278.8 136.8 C
+270.2 147.3 264.9 154.5 252.4 156.9 C
+227.0 119.5 L
+256.3 98.8 267.3 63.3 264.0 12.4 C
+264.4 10.5 265.9 9.1 265.9 9.1 C
+265.9 9.1 267.8 10.0 267.8 10.0 C
+f
+0 g
+79.2 40.3 m
+116.6 43.6 150.2 75.3 180.9 103.6 C
+197.2 121.4 204.0 133.4 217.9 150.7 C
+216.4 151.2 215.0 152.1 213.1 152.1 C
+178.0 128.6 147.3 81.1 102.2 86.8 C
+98.4 88.8 95.0 89.2 92.6 92.1 C
+87.3 120.4 126.2 159.8 141.1 182.8 C
+148.8 193.4 159.3 203.0 159.8 217.4 C
+131.0 190.0 98.8 140.6 71.5 90.7 C
+65.2 76.3 58.0 67.6 63.3 53.7 C
+68.6 45.1 70.5 43.2 79.2 40.3 C
+f
+0 g
+355.6 161.2 m
+376.3 159.3 388.3 171.8 404.6 184.3 C
+412.3 201.1 422.4 223.2 423.3 237.6 C
+416.6 234.2 410.8 229.4 405.1 217.4 C
+399.8 211.6 386.8 206.8 378.7 207.8 C
+334.0 206.4 308.1 288.4 252.4 297.1 C
+236.1 299.5 229.9 291.8 214.5 285.6 C
+203.0 270.2 L
+193.4 281.7 175.2 306.7 147.8 303.3 C
+115.2 279.8 101.2 238.5 57.6 230.8 C
+42.7 235.2 26.8 240.9 21.1 253.4 C
+19.6 257.7 19.6 260.1 16.8 262.5 C
+14.4 259.2 12.9 257.7 11.5 253.4 C
+20.1 231.8 12.4 207.8 31.6 190.5 C
+45.6 184.8 60.4 188.1 74.8 201.6 C
+103.6 220.3 113.2 256.3 142.5 259.2 C
+164.1 248.1 178.5 237.1 189.1 214.0 C
+208.8 241.9 L
+225.6 253.4 243.8 250.0 262.0 241.4 C
+294.2 215.0 325.9 167.5 355.6 161.2 C
+f
+%%Trailer
+end
+showpage
diff --git a/xemacs-packages/gnus/texi/sasl.texi b/xemacs-packages/gnus/texi/sasl.texi
new file mode 100644 (file)
index 0000000..9df2963
--- /dev/null
@@ -0,0 +1,275 @@
+\input texinfo                  @c -*-texinfo-*-
+
+@include gnus-overrides.texi
+
+@setfilename sasl.info
+
+@set VERSION 0.2
+@settitle Emacs SASL Library @value{VERSION}
+@include docstyle.texi
+
+@copying
+This file describes the Emacs SASL library, version @value{VERSION}.
+
+Copyright @copyright{} 2000, 2004--2016 Free Software Foundation, Inc.
+
+@quotation
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 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''.
+
+(a) The FSF's Back-Cover Text is: ``You have the freedom to copy and
+modify this GNU manual.''
+@end quotation
+@end copying
+
+@dircategory Emacs network features
+@direntry
+* SASL: (sasl).                 The Emacs SASL library.
+@end direntry
+
+
+@titlepage
+@ifset WEBHACKDEVEL
+@title Emacs SASL Library @value{VERSION} (DEVELOPMENT VERSION)
+@end ifset
+@ifclear WEBHACKDEVEL
+@title Emacs SASL Library @value{VERSION}
+@end ifclear
+
+@author by Daiki Ueno
+@page
+
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+
+
+@node Top
+@top Emacs SASL
+
+SASL is a common interface to share several authentication mechanisms between
+applications using different protocols.
+
+@ifnottex
+@insertcopying
+@end ifnottex
+
+@menu
+* Overview::                    What Emacs SASL library is.
+* How to use::                  Adding authentication support to your applications.
+* Data types::
+* Back end drivers::             Writing your own drivers.
+* GNU Free Documentation License::  The license for this documentation.
+* Index::
+* Function Index::
+* Variable Index::
+@end menu
+
+@node Overview
+@chapter Overview
+
+@sc{sasl} is short for @dfn{Simple Authentication and Security Layer}.
+This standard is documented in RFC2222.  It provides a simple method for
+adding authentication support to various application protocols.
+
+The toplevel interface of this library is inspired by Java @sc{sasl}
+Application Program Interface.  It defines an abstraction over a series
+of authentication mechanism drivers (@ref{Back end drivers}).
+
+Back end drivers are designed to be close as possible to the
+authentication mechanism.  You can access the additional configuration
+information anywhere from the implementation.
+
+@node How to use
+@chapter How to use
+
+(Not yet written).
+
+To use Emacs SASL library, please evaluate following expression at the
+beginning of your application program.
+
+@lisp
+(require 'sasl)
+@end lisp
+
+If you want to check existence of sasl.el at runtime, instead you
+can list autoload settings for functions you want.
+
+@node Data types
+@chapter Data types
+
+There are three data types to be used for carrying a negotiated
+security layer---a mechanism, a client parameter and an authentication
+step.
+
+@menu
+* Mechanisms::
+* Clients::
+* Steps::
+@end menu
+
+@node Mechanisms
+@section Mechanisms
+
+A mechanism (@code{sasl-mechanism} object) is a schema of the @sc{sasl}
+authentication mechanism driver.
+
+@defvar sasl-mechanisms
+A list of mechanism names.
+@end defvar
+
+@defun sasl-find-mechanism mechanisms
+
+Retrieve an appropriate mechanism.
+This function compares @var{mechanisms} and @code{sasl-mechanisms} then
+returns appropriate @code{sasl-mechanism} object.
+
+@example
+(let ((sasl-mechanisms '("CRAM-MD5" "DIGEST-MD5")))
+  (setq mechanism (sasl-find-mechanism server-supported-mechanisms)))
+@end example
+
+@end defun
+
+@defun sasl-mechanism-name mechanism
+Return name of mechanism, a string.
+@end defun
+
+If you want to write an authentication mechanism driver (@ref{Back end
+drivers}), use @code{sasl-make-mechanism} and modify
+@code{sasl-mechanisms} and @code{sasl-mechanism-alist} correctly.
+
+@defun sasl-make-mechanism name steps
+Allocate a @code{sasl-mechanism} object.
+This function takes two parameters---name of the mechanism, and a list
+of authentication functions.
+
+@example
+(defconst sasl-anonymous-steps
+  '(identity                            ;no initial response
+    sasl-anonymous-response))
+
+(put 'sasl-anonymous 'sasl-mechanism
+     (sasl-make-mechanism "ANONYMOUS" sasl-anonymous-steps))
+@end example
+
+@end defun
+
+@node Clients
+@section Clients
+
+A client (@code{sasl-client} object) initialized with four
+parameters---a mechanism, a user name, name of the service and name of
+the server.
+
+@defun sasl-make-client mechanism name service server
+Prepare a @code{sasl-client} object.
+@end defun
+
+@defun sasl-client-mechanism client
+Return the mechanism (@code{sasl-mechanism} object) of client.
+@end defun
+
+@defun sasl-client-name client
+Return the authorization name of client, a string.
+@end defun
+
+@defun sasl-client-service client
+Return the service name of client, a string.
+@end defun
+
+@defun sasl-client-server client
+Return the server name of client, a string.
+@end defun
+
+If you want to specify additional configuration properties, please use
+@code{sasl-client-set-property}.
+
+@defun sasl-client-set-property client property value
+Add the given property/value to client.
+@end defun
+
+@defun sasl-client-property client property
+Return the value of the property of client.
+@end defun
+
+@defun sasl-client-set-properties client plist
+Destructively set the properties of client.
+The second argument is the new property list.
+@end defun
+
+@defun sasl-client-properties client
+Return the whole property list of client configuration.
+@end defun
+
+@node Steps
+@section Steps
+
+A step (@code{sasl-step} object) is an abstraction of authentication
+``step'' which holds the response value and the next entry point for the
+authentication process (the latter is not accessible).
+
+@defun sasl-step-data step
+Return the data which @var{step} holds, a string.
+@end defun
+
+@defun sasl-step-set-data step data
+Store @var{data} string to @var{step}.
+@end defun
+
+To get the initial response, you should call the function
+@code{sasl-next-step} with the second argument @code{nil}.
+
+@example
+(setq name (sasl-mechanism-name mechanism))
+@end example
+
+At this point we could send the command which starts a SASL
+authentication protocol exchange.  For example,
+
+@example
+(process-send-string
+ process
+ (if (sasl-step-data step)              ;initial response
+     (format "AUTH %s %s\r\n" name (base64-encode-string (sasl-step-data step) t))
+   (format "AUTH %s\r\n" name)))
+@end example
+
+To go on with the authentication process, all you have to do is call
+@code{sasl-next-step} consecutively.
+
+@defun sasl-next-step client step
+Perform the authentication step.
+At the first time @var{step} should be set to @code{nil}.
+@end defun
+
+@node Back end drivers
+@chapter Back end drivers
+
+(Not yet written).
+
+@node GNU Free Documentation License
+@appendix GNU Free Documentation License
+@include doclicense.texi
+
+@node Index
+@unnumbered Index
+@printindex cp
+
+@node Function Index
+@unnumbered Function Index
+@printindex fn
+
+@node Variable Index
+@unnumbered Variable Index
+@printindex vr
+
+@summarycontents
+@contents
+@bye
+
+@c End:
diff --git a/xemacs-packages/gnus/texi/screen/group-topic.png b/xemacs-packages/gnus/texi/screen/group-topic.png
new file mode 100644 (file)
index 0000000..6f4ad01
Binary files /dev/null and b/xemacs-packages/gnus/texi/screen/group-topic.png differ
diff --git a/xemacs-packages/gnus/texi/screen/group.png b/xemacs-packages/gnus/texi/screen/group.png
new file mode 100644 (file)
index 0000000..4b4620f
Binary files /dev/null and b/xemacs-packages/gnus/texi/screen/group.png differ
diff --git a/xemacs-packages/gnus/texi/screen/server.png b/xemacs-packages/gnus/texi/screen/server.png
new file mode 100644 (file)
index 0000000..67f2bd4
Binary files /dev/null and b/xemacs-packages/gnus/texi/screen/server.png differ
diff --git a/xemacs-packages/gnus/texi/screen/summary-adopt.png b/xemacs-packages/gnus/texi/screen/summary-adopt.png
new file mode 100644 (file)
index 0000000..54e508f
Binary files /dev/null and b/xemacs-packages/gnus/texi/screen/summary-adopt.png differ
diff --git a/xemacs-packages/gnus/texi/screen/summary-article-c-ug.png b/xemacs-packages/gnus/texi/screen/summary-article-c-ug.png
new file mode 100644 (file)
index 0000000..8f224bf
Binary files /dev/null and b/xemacs-packages/gnus/texi/screen/summary-article-c-ug.png differ
diff --git a/xemacs-packages/gnus/texi/screen/summary-article.png b/xemacs-packages/gnus/texi/screen/summary-article.png
new file mode 100644 (file)
index 0000000..d265dca
Binary files /dev/null and b/xemacs-packages/gnus/texi/screen/summary-article.png differ
diff --git a/xemacs-packages/gnus/texi/screen/summary-dummy.png b/xemacs-packages/gnus/texi/screen/summary-dummy.png
new file mode 100644 (file)
index 0000000..308f244
Binary files /dev/null and b/xemacs-packages/gnus/texi/screen/summary-dummy.png differ
diff --git a/xemacs-packages/gnus/texi/screen/summary-empty.png b/xemacs-packages/gnus/texi/screen/summary-empty.png
new file mode 100644 (file)
index 0000000..2f2ec6a
Binary files /dev/null and b/xemacs-packages/gnus/texi/screen/summary-empty.png differ
diff --git a/xemacs-packages/gnus/texi/screen/summary-none.png b/xemacs-packages/gnus/texi/screen/summary-none.png
new file mode 100644 (file)
index 0000000..9f8f43e
Binary files /dev/null and b/xemacs-packages/gnus/texi/screen/summary-none.png differ
diff --git a/xemacs-packages/gnus/texi/screen/summary-unthreaded.png b/xemacs-packages/gnus/texi/screen/summary-unthreaded.png
new file mode 100644 (file)
index 0000000..2e5ddbb
Binary files /dev/null and b/xemacs-packages/gnus/texi/screen/summary-unthreaded.png differ
diff --git a/xemacs-packages/gnus/texi/screen/summary.png b/xemacs-packages/gnus/texi/screen/summary.png
new file mode 100644 (file)
index 0000000..7cfcc0e
Binary files /dev/null and b/xemacs-packages/gnus/texi/screen/summary.png differ
diff --git a/xemacs-packages/gnus/texi/sieve.texi b/xemacs-packages/gnus/texi/sieve.texi
new file mode 100644 (file)
index 0000000..0b794fb
--- /dev/null
@@ -0,0 +1,366 @@
+\input texinfo                  @c -*-texinfo-*-
+
+@include gnus-overrides.texi
+
+@setfilename sieve.info
+@settitle Emacs Sieve Manual
+@include docstyle.texi
+@synindex fn cp
+@synindex vr cp
+@synindex pg cp
+
+@copying
+This file documents the Emacs Sieve package, for server-side mail filtering.
+
+Copyright @copyright{} 2001--2016 Free Software Foundation, Inc.
+
+@quotation
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 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''.
+
+(a) The FSF's Back-Cover Text is: ``You have the freedom to copy and
+modify this GNU manual.''
+@end quotation
+@end copying
+
+@dircategory Emacs network features
+@direntry
+* Sieve: (sieve).               Managing Sieve scripts in Emacs.
+@end direntry
+@iftex
+@finalout
+@end iftex
+@setchapternewpage odd
+
+@titlepage
+@ifset WEBHACKDEVEL
+@title Emacs Sieve Manual (DEVELOPMENT VERSION)
+@end ifset
+@ifclear WEBHACKDEVEL
+@title Emacs Sieve Manual
+@end ifclear
+
+@author by Simon Josefsson
+@page
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+
+@summarycontents
+@contents
+
+@node Top
+@top Sieve Support for Emacs
+
+This 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.
+
+@ifnottex
+@insertcopying
+@end ifnottex
+
+@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.
+* GNU Free Documentation License:: The license for this documentation.
+* 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 '("\\.s\\(v\\|iv\\|ieve\\)\\'" . 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 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. @xref{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 successfully contacted, the Manage Sieve buffer
+looks something like:
+
+@example
+Server  : mailserver:sieve
+
+2 scripts on server, press RET on a script name edits it, or
+press RET on <new script> to create a new script.
+        <new script>
+ ACTIVE .sieve
+        template.siv
+@end example
+
+One of the scripts are highlighted, and standard point navigation
+commands (@kbd{<up>}, @kbd{<down>} etc.)@: can be used to navigate the
+list.
+
+The following commands are available in the Manage Sieve buffer:
+
+@table @kbd
+
+@item m
+@kindex m
+@findex sieve-activate
+Activates the currently highlighted script.
+
+@item u
+@kindex u
+@findex sieve-deactivate
+Deactivates the currently highlighted script.
+
+@item C-M-?
+@kindex C-M-?
+@findex sieve-deactivate-all
+Deactivates all scripts.
+
+@item r
+@kindex r
+@findex sieve-remove
+Remove currently highlighted script.
+
+@item RET
+@item mouse-2
+@item f
+@kindex RET
+@kindex mouse-2
+@kindex f
+@findex sieve-edit-script
+Bury the server buffer and download the currently highlighted script
+into a new buffer for editing in Sieve mode (@pxref{Sieve Mode}).
+
+@item o
+@kindex o
+@findex sieve-edit-script-other-window
+Create a new buffer in another window containing the currently
+highlighted script for editing in Sieve mode (@pxref{Sieve Mode}).
+
+@item q
+@kindex q
+@findex sieve-bury-buffer
+Bury the Manage Sieve buffer without closing the connection.
+
+@item ?
+@item h
+@kindex ?
+@kindex h
+@findex sieve-help
+Displays help in the minibuffer.
+
+@item Q
+@kindex Q
+@findex sieve-manage-quit
+Quit Manage Sieve and close the connection.
+
+@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 has a
+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-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-@code{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 supports.
+
+@item sieve-manage-listscripts
+@findex sieve-manage-listscripts
+List scripts on the server.
+
+@item sieve-manage-havespace
+@findex sieve-manage-havespace
+Return non-@code{nil} if the server has room 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 RFC5804
+A Protocol for Remotely Managing Sieve Scripts
+
+@end table
+
+@node GNU Free Documentation License
+@appendix GNU Free Documentation License
+@include doclicense.texi
+
+@node Index
+@unnumbered Index
+@printindex cp
+
+@bye
+
+@c End:
diff --git a/xemacs-packages/gnus/texi/smilies/BigFace.tif b/xemacs-packages/gnus/texi/smilies/BigFace.tif
new file mode 100644 (file)
index 0000000..e073e01
Binary files /dev/null and b/xemacs-packages/gnus/texi/smilies/BigFace.tif differ
diff --git a/xemacs-packages/gnus/texi/smilies/FaceAngry.xpm b/xemacs-packages/gnus/texi/smilies/FaceAngry.xpm
new file mode 100644 (file)
index 0000000..32fec93
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/smilies/FaceDevilish.xpm b/xemacs-packages/gnus/texi/smilies/FaceDevilish.xpm
new file mode 100644 (file)
index 0000000..ee88aed
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/smilies/FaceGoofy.xpm b/xemacs-packages/gnus/texi/smilies/FaceGoofy.xpm
new file mode 100644 (file)
index 0000000..62d7de8
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/smilies/FaceGrinning.xpm b/xemacs-packages/gnus/texi/smilies/FaceGrinning.xpm
new file mode 100644 (file)
index 0000000..072d505
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/smilies/FaceHappy.xpm b/xemacs-packages/gnus/texi/smilies/FaceHappy.xpm
new file mode 100644 (file)
index 0000000..07f1214
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/smilies/FaceIronic.xpm b/xemacs-packages/gnus/texi/smilies/FaceIronic.xpm
new file mode 100644 (file)
index 0000000..677ee25
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/smilies/FaceKOed.xpm b/xemacs-packages/gnus/texi/smilies/FaceKOed.xpm
new file mode 100644 (file)
index 0000000..ed51b19
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/smilies/FaceNyah.xpm b/xemacs-packages/gnus/texi/smilies/FaceNyah.xpm
new file mode 100644 (file)
index 0000000..320cfe0
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/smilies/FaceSad.xpm b/xemacs-packages/gnus/texi/smilies/FaceSad.xpm
new file mode 100644 (file)
index 0000000..ced9a02
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/smilies/FaceStartled.xpm b/xemacs-packages/gnus/texi/smilies/FaceStartled.xpm
new file mode 100644 (file)
index 0000000..75739c9
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/smilies/FaceStraight.xpm b/xemacs-packages/gnus/texi/smilies/FaceStraight.xpm
new file mode 100644 (file)
index 0000000..4298065
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/smilies/FaceTalking.xpm b/xemacs-packages/gnus/texi/smilies/FaceTalking.xpm
new file mode 100644 (file)
index 0000000..2295be8
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/smilies/FaceTasty.xpm b/xemacs-packages/gnus/texi/smilies/FaceTasty.xpm
new file mode 100644 (file)
index 0000000..968e493
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/smilies/FaceWinking.xpm b/xemacs-packages/gnus/texi/smilies/FaceWinking.xpm
new file mode 100644 (file)
index 0000000..25d62ef
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/smilies/FaceWry.xpm b/xemacs-packages/gnus/texi/smilies/FaceWry.xpm
new file mode 100644 (file)
index 0000000..db6010d
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/smilies/FaceYukky.xpm b/xemacs-packages/gnus/texi/smilies/FaceYukky.xpm
new file mode 100644 (file)
index 0000000..0d3de33
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/smilies/WideFaceAse1.xbm b/xemacs-packages/gnus/texi/smilies/WideFaceAse1.xbm
new file mode 100644 (file)
index 0000000..1a5a589
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/smilies/WideFaceAse2.xbm b/xemacs-packages/gnus/texi/smilies/WideFaceAse2.xbm
new file mode 100644 (file)
index 0000000..4c7fcb6
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/smilies/WideFaceAse3.xbm b/xemacs-packages/gnus/texi/smilies/WideFaceAse3.xbm
new file mode 100644 (file)
index 0000000..0960e77
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/smilies/WideFaceSmile.xbm b/xemacs-packages/gnus/texi/smilies/WideFaceSmile.xbm
new file mode 100644 (file)
index 0000000..c4cc3bc
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/smilies/WideFaceWeep.xbm b/xemacs-packages/gnus/texi/smilies/WideFaceWeep.xbm
new file mode 100644 (file)
index 0000000..4353148
--- /dev/null
@@ -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/xemacs-packages/gnus/texi/splitindex b/xemacs-packages/gnus/texi/splitindex
new file mode 100755 (executable)
index 0000000..cfd568c
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+match='M-x |(Group)|(Summary)|(Article)|(Server)|(Browse)|(Post)|(Mail)|(Score)|(Binary)|(Topic)|(Pick)'
+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/xemacs-packages/gnus/texi/texi2latex.el b/xemacs-packages/gnus/texi/texi2latex.el
new file mode 100644 (file)
index 0000000..91ccda6
--- /dev/null
@@ -0,0 +1,420 @@
+;;; texi2latex.el --- convert a texi file into a LaTeX file.
+;; Copyright (C) 1996, 2004, 2008 Lars Magne Ingebrigtsen
+
+(require 'cl)
+
+(defun latexi-discard-until (string)
+  (let ((beg (match-beginning 0)))
+    (unless (re-search-forward (concat "^@end +" string "[ \t]*\n") nil t)
+      (error "No end: %s" string))
+    (delete-region beg (match-end 0))))
+
+(defun latexi-strip-line ()
+  (delete-region (progn (beginning-of-line) (point))
+                (progn (forward-line 1) (point))))
+
+(defun latexi-switch-line (command arg)
+  (latexi-strip-line)
+  (insert (format "\\%s{%s}\n" command arg)))
+
+(defun latexi-index-command (command arg)
+  (latexi-strip-line)
+  (insert (format "\\gnus%sindex{%s}\n" 
+                 (if (equal command "kindex") "k" "")
+                 arg)))
+
+(defun latexi-begin-command (command)
+  (latexi-strip-line)
+  (insert (format "\\begin{%s}\n" command)))
+
+(defun latexi-exchange-command (command arg)
+  (delete-region (match-beginning 0) (match-end 0))
+  (insert (format "\\%s{%s}" command arg)))
+
+(defun latexi-translate ()
+  "Translate."
+  (interactive)
+  (latexi-translate-file "gnus")
+  (latexi-translate-file "gnus-faq")
+  (latexi-translate-file "message" t)
+  (latexi-translate-file "emacs-mime" t)
+  (latexi-translate-file "sieve" t)
+  (latexi-translate-file "pgg" t)
+  (latexi-translate-file "sasl" t)
+  (latexi-translate-file "gnus-news" t))
+
+(defun latexi-translate-file (file &optional as-a-chapter)
+  "Translate file a LaTeX file."
+  (let ((item-string "")
+       (item-stack nil)
+       (list-stack nil)
+       (latexi-buffer (get-buffer-create "*LaTeXi*"))
+       verbatim
+       (regexp 
+        (concat 
+           "@\\([^{} \t\n]+\\)"
+           "\\(\\( +\\(.*$\\)\\|[ \t]*$\\)\\|{\\([^}]*\\)}\\)"))
+       (cur (find-file-noselect (concat (or (getenv "srcdir") ".") 
+                                        "/" file ".texi")))
+       (times 3)
+       (chapter 0)
+       command arg)
+    (pop-to-buffer latexi-buffer)
+    (buffer-disable-undo)
+    (erase-buffer)
+    (insert-buffer-substring cur)
+    (goto-char (point-min))
+    (when (search-forward "@copying" nil t)
+      (latexi-copying))
+    (while (search-forward "@insertcopying" nil t)
+      (delete-region (match-beginning 0) (match-end 0))
+      (latexi-insertcopying))
+    (goto-char (point-min))
+    (latexi-strip-line)
+    (latexi-translate-string "@'e" "\\'{e}")
+    (latexi-translate-string "@`a" "\\`{a}")
+    (latexi-translate-string "@,{c}" "\\c{c}")
+    (latexi-translate-string "@aa{}" "{\\aa}")
+    (latexi-translate-string "@\"{@dotless{i}}" "ï")
+    (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}")
+    (latexi-translate-string "@file{c:\\myhome}" "@file{c:\\gnusbackslash{}myhome}")
+;    (while (re-search-forward "{\"[^\"]*\\(\\\\\\)[^\"]*\"}\\\\" nil t)
+;      (replace-match "\\verb+\\\\+ " t t))
+    (while (not (zerop (decf times)))
+      (goto-char (point-min))
+      (while (re-search-forward regexp nil t)
+       (setq command (match-string 1))
+       (if (match-beginning 3)
+           (progn
+             (setq arg (or (match-string 4) ""))
+             (save-match-data
+               (when (string-match "[ \t]+$" arg)
+                 (setq arg (substring arg 0 (match-beginning 0)))))
+             (cond 
+              ((member command '("c" "comment"))
+               (if (string-match "@icon" (or arg ""))
+                   (progn
+                     (beginning-of-line)
+                     (delete-region (point) (+ (point) 4))
+                     (insert "\\gnus"))
+                 (delete-region (match-beginning 0) 
+                                (progn (end-of-line) (point))))
+               (if (equal arg "@head")
+                   (insert "\\gnusinteresting")))
+              ((member command '("setfilename" "set"
+                                 "synindex" "setchapternewpage"
+                                 "summarycontents" "bye"
+                                 "top" "iftex" "cartouche" 
+                                 "iflatex" "finalout" "vskip"
+                                 "dircategory" "group" "syncodeindex"
+                                 "documentencoding"))
+               (latexi-strip-line))
+              ((member command '("menu" "tex" "ifinfo" "ignore" 
+                                 "ifnottex" "direntry"))
+               (latexi-discard-until command))
+              ((member command '("subsection" "subsubsection"))
+               (if as-a-chapter
+                   (latexi-switch-line (format "sub%s" command) arg)
+                 (latexi-switch-line command arg)))
+              ((member command '("heading"))
+               (if as-a-chapter
+                   (latexi-switch-line "subsection*" arg)
+                 (latexi-switch-line "section*" arg)))
+              ((member command '("subheading"))
+               (if as-a-chapter
+                   (latexi-switch-line "subsubsection*" arg)
+                 (latexi-switch-line "subsection*" arg)))
+              ((member command '("subsubheading"))
+               (if as-a-chapter
+                   (latexi-switch-line "subsubsubsection*" arg)
+                 (latexi-switch-line "subsubsection*" arg)))
+              ((member command '("chapter"))
+               (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"))
+               (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 '("*"))
+               (delete-char -2)
+               (insert "\\\\"))
+              ((equal command "sp")
+               (replace-match "" t t))
+              ((equal command ":")
+               (replace-match "" t t))
+              ((member command '("deffn" "defvar" "defun"))
+               (replace-match "" t t))
+              ((equal command "node")
+               (latexi-strip-line)
+               (unless (string-match "Index" arg)
+                 (insert (format "\\label{%s}\n" arg))))
+              ((equal command "contents")
+               (latexi-strip-line)
+               ;;(insert (format "\\tableofcontents\n" arg))
+               )
+              ((member command '("titlepage"))
+               (latexi-begin-command command))
+              ((member command '("lisp" "example" "smallexample" "display"))
+               (latexi-strip-line)
+               (insert (format "\\begin{verbatim}\n"))
+               (setq verbatim (point)))
+              ((member command '("center"))
+               (latexi-strip-line)
+               (insert (format "\\begin{%s}%s\\end{%s}\n"
+                               command arg command)))
+              ((member command '("end"))
+               (cond
+                ((member arg '("titlepage"))
+                 (latexi-strip-line)
+                 (insert (format "\\end{%s}\n" arg)))
+                ((equal arg "quotation")
+                 (latexi-strip-line)
+                 (insert (format "\\end{verse}\n")))
+                ((member arg '("lisp" "example" "smallexample" "display"))
+                 (latexi-strip-line)
+                 (save-excursion
+                   (save-restriction
+                     (narrow-to-region verbatim (point))
+                     (goto-char (point-min))
+                     (while (search-forward "@{" nil t)
+                       (replace-match "{" t t))
+                     (goto-char (point-min))
+                     (while (search-forward "@}" nil t)
+                       (replace-match "}" t t))))
+                 (setq verbatim nil)
+                 (insert "\\end{verbatim}\n"))
+                ((member arg '("table"))
+                 (setq item-string (pop item-stack))
+                 (latexi-strip-line)
+                 (insert (format "\\end{%slist}\n" (pop list-stack))))
+                ((member arg '("itemize" "enumerate"))
+                 (setq item-string (pop item-stack))
+                 (latexi-strip-line)
+                 (insert (format "\\end{%s}\n" arg)))
+                ((member arg '("iflatex" "iftex" "cartouche" "group"))
+                 (latexi-strip-line))
+                ((member arg '("deffn" "defvar" "defun"))
+                 (latexi-strip-line))
+                (t
+                 (error "Unknown end arg: %s" arg))))
+              ((member command '("table"))
+               (push item-string item-stack)
+               (push (substring arg 1) list-stack)
+               (setq item-string 
+                     (format "[@%s{%%s}]" (car list-stack)))
+               (latexi-strip-line)
+               (insert (format "\\begin{%slist}\n" (car list-stack))))
+              ((member command '("itemize" "enumerate"))
+               (push item-string item-stack)
+               (cond 
+                ((member arg '("@bullet"))
+                 (setq item-string "[\\gnusbullet]"))
+                (t
+                 (setq item-string "")))
+               (latexi-strip-line)
+               (insert (format "\\begin{%s}\n" command)))
+              ((member command '("item"))
+               (latexi-strip-line)
+               (insert (format "\\%s%s\n" command (format item-string arg))))
+              ((equal command "itemx")
+               (latexi-strip-line)
+               (insert (format "\\gnusitemx{%s}\n" (format item-string arg))))
+              ((eq (aref command 0) ?@)
+               (goto-char (match-beginning 0))
+               (delete-char 2)
+               (insert "duppat{}"))
+              ((equal command "settitle")
+               (latexi-strip-line)
+               (if (not as-a-chapter)
+                   (insert 
+                    (format "\\newcommand{\\gnustitlename}{%s}\n" arg))))
+              ((equal command "title")
+               (latexi-strip-line)
+               (insert (format "\\gnustitlename{%s}\n" arg)))
+              ((equal command "author")
+               (latexi-strip-line)
+               (insert (format "\\gnusauthor{%s}\n" arg)))
+              ((equal command "quotation")
+               (latexi-begin-command "verse"))
+              ((equal command "page")
+               (latexi-strip-line)
+               (insert "\\newpage\n"))
+              ((equal command "'s")
+               (goto-char (match-beginning 0))
+               (delete-char 1))
+              ((equal command "include")
+               (latexi-strip-line)
+               (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 
+               ;; (format 
+               ;;  "\\begin{theindex}\\input{gnus.%s}\\end{theindex}\n" arg))
+               )
+              (t
+               (error "Unknown command (file %s line %d): %s"
+                      file
+                      (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 '("ref" "xref" "pxref"))
+           (latexi-exchange-command (concat "gnus" command) arg))
+          ((member command '("sc" "file" "dfn" "emph" "kbd" "key" "uref"
+                             "code" "samp" "var" "strong" "i"
+                             "result" "email" "env" "r" "command" "asis"
+                             "url"))
+           (goto-char (match-beginning 0))
+           (delete-char 1)
+           (insert "\\gnus"))
+          ((member command '("acronym"))
+           (latexi-exchange-command (concat "gnus" command) (downcase arg)))
+          ((member command '("copyright" "footnote" "TeX"))
+           (goto-char (match-beginning 0))
+           (delete-char 1)
+           (insert "\\"))
+          ((member command '("dots"))
+           (goto-char (match-beginning 0))
+           (delete-region (match-beginning 0) (match-end 0))
+           (insert "..."))
+          ((eq (aref command 0) ?@)
+           (goto-char (match-beginning 0))
+           (delete-char 2)
+           (insert "duppat{}"))
+          (t
+           (error "Unknown command (file %s line %d): %s"
+                  file
+                  (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{}")
+    (latexi-translate-string "#" "\\gnushash{}")
+    (latexi-translate-string "^" "\\gnushat{}")
+    (latexi-translate-string "~" "\\gnustilde{}")
+    (latexi-translate-string "_" "\\gnusunderline{}")
+    (latexi-translate-string "¬" "\\gnusnot{}")
+    (goto-char (point-min))
+    (while (search-forward "duppat{}" nil t)
+      (replace-match "@" t t))
+    (latexi-translate-string "@@" "@")
+    (latexi-translate-string "<" "\\gnusless{}")
+    (latexi-translate-string ">" "\\gnusgreater{}")
+    (goto-char (point-min))
+    (search-forward "label{Top}" nil t)
+    (while (re-search-forward "\\\\[ntr]\\b" nil t)
+      (when (save-match-data
+             (or (not (save-excursion
+                        (search-backward "begin{verbatim}" nil t)))
+                 (> (save-excursion
+                      (search-backward "end{verbatim"))
+                    (save-excursion
+                      (search-backward "begin{verbatim}")))))
+       (goto-char (match-beginning 0))
+       (delete-char 1)
+       (insert "\\gnusbackslash{}")))
+    (latexi-translate-string "\\\\" "\\gnusbackslash{}")
+    (goto-char (point-min))
+    (while (re-search-forward "\\\\[][{}]" nil t)
+      (goto-char (match-beginning 0))
+      (delete-char 1))
+    (latexi-contributors)
+    (let ((coding-system-for-write 'iso-8859-1))
+      (write-region (point-min) (point-max) (concat file ".latexi")))))
+
+(defun latexi-translate-string (in out)
+  (let (yes)
+    (goto-char (point-min))
+    (search-forward "label{Top}" nil t)
+    (while (search-forward in nil t)
+      (when (save-match-data
+             (or (not (save-excursion
+                        (search-backward "begin{verbatim}" nil t)))
+                 (> (save-excursion
+                      (re-search-backward "end{verbatim}\\|end{verse}"))
+                    (save-excursion
+                      (re-search-backward
+                       "begin{verbatim}\\|begin{verse}")))))
+       (replace-match out t t)))))
+
+(defun latexi-contributors ()
+  (goto-char (point-min))
+  (when (re-search-forward "^Also thanks to the following" nil t)
+    (forward-line 2)
+    (narrow-to-region
+     (point)
+     (1- (search-forward "\n\n")))
+    (when (re-search-backward "^and" nil t)
+      (latexi-strip-line))
+    (goto-char (point-min))
+    (while (re-search-forward "[.,] *$" nil t)
+      (replace-match "" t t))
+    (goto-char (point-min))
+    (let (names)
+      (while (not (eobp))
+       (push (buffer-substring (point) (progn (end-of-line) (point)))
+             names)
+       (forward-line 1))
+      (delete-region (point-min) (point-max))
+      (insert "\\begin{tabular}{lll}\n")
+      (setq names (nreverse (delete "" names)))
+      (while names
+       (insert (pop names) " & " (or (pop names) "\\mbox{}") 
+               " & " (or (pop names) "\\mbox{}") 
+               "\\\\\n"))
+      (insert "\\end{tabular}\n")
+      (widen))))
+
+(defvar latexi-copying-text ""
+  "Text of the copyright notice and copying permissions.")
+
+(defun latexi-copying ()
+  "Copy the copyright notice and copying permissions from the Texinfo file,
+as indicated by the @copying ... @end copying command;
+insert the text with the @insertcopying command."
+  (let ((beg (progn (beginning-of-line) (point)))
+       (end  (progn (re-search-forward "^@end copying[ \t]*\n") (point))))
+    (setq latexi-copying-text
+         (buffer-substring-no-properties
+          (save-excursion (goto-char beg) (forward-line 1) (point))
+          (save-excursion (goto-char end) (forward-line -1) (point))))
+    (delete-region beg end)))
+
+(defun latexi-insertcopying ()
+  "Insert the copyright notice and copying permissions from the Texinfo file,
+which are indicated by the @copying ... @end copying command."
+  (insert (concat "\n" latexi-copying-text)))
diff --git a/xemacs-packages/gnus/texi/xface/abrahamsen.png b/xemacs-packages/gnus/texi/xface/abrahamsen.png
new file mode 100644 (file)
index 0000000..20a1206
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/abrahamsen.png differ
diff --git a/xemacs-packages/gnus/texi/xface/aichner.png b/xemacs-packages/gnus/texi/xface/aichner.png
new file mode 100644 (file)
index 0000000..1636565
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/aichner.png differ
diff --git a/xemacs-packages/gnus/texi/xface/blanks.png b/xemacs-packages/gnus/texi/xface/blanks.png
new file mode 100644 (file)
index 0000000..0776a29
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/blanks.png differ
diff --git a/xemacs-packages/gnus/texi/xface/cosgriff.png b/xemacs-packages/gnus/texi/xface/cosgriff.png
new file mode 100644 (file)
index 0000000..59acc3f
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/cosgriff.png differ
diff --git a/xemacs-packages/gnus/texi/xface/drazen.png b/xemacs-packages/gnus/texi/xface/drazen.png
new file mode 100644 (file)
index 0000000..dffeffe
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/drazen.png differ
diff --git a/xemacs-packages/gnus/texi/xface/gertzfield.png b/xemacs-packages/gnus/texi/xface/gertzfield.png
new file mode 100644 (file)
index 0000000..576789e
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/gertzfield.png differ
diff --git a/xemacs-packages/gnus/texi/xface/goldberg.png b/xemacs-packages/gnus/texi/xface/goldberg.png
new file mode 100644 (file)
index 0000000..e2fe139
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/goldberg.png differ
diff --git a/xemacs-packages/gnus/texi/xface/graf.png b/xemacs-packages/gnus/texi/xface/graf.png
new file mode 100644 (file)
index 0000000..d2e19d3
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/graf.png differ
diff --git a/xemacs-packages/gnus/texi/xface/hardaker.png b/xemacs-packages/gnus/texi/xface/hardaker.png
new file mode 100644 (file)
index 0000000..ac88bd8
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/hardaker.png differ
diff --git a/xemacs-packages/gnus/texi/xface/hedbor.png b/xemacs-packages/gnus/texi/xface/hedbor.png
new file mode 100644 (file)
index 0000000..5672039
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/hedbor.png differ
diff --git a/xemacs-packages/gnus/texi/xface/ingrand.png b/xemacs-packages/gnus/texi/xface/ingrand.png
new file mode 100644 (file)
index 0000000..2403259
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/ingrand.png differ
diff --git a/xemacs-packages/gnus/texi/xface/kaplan.png b/xemacs-packages/gnus/texi/xface/kaplan.png
new file mode 100644 (file)
index 0000000..106bb5e
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/kaplan.png differ
diff --git a/xemacs-packages/gnus/texi/xface/karlheg.png b/xemacs-packages/gnus/texi/xface/karlheg.png
new file mode 100644 (file)
index 0000000..022eb68
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/karlheg.png differ
diff --git a/xemacs-packages/gnus/texi/xface/kleinpaste.png b/xemacs-packages/gnus/texi/xface/kleinpaste.png
new file mode 100644 (file)
index 0000000..e25e698
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/kleinpaste.png differ
diff --git a/xemacs-packages/gnus/texi/xface/kyle.png b/xemacs-packages/gnus/texi/xface/kyle.png
new file mode 100644 (file)
index 0000000..7354ebc
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/kyle.png differ
diff --git a/xemacs-packages/gnus/texi/xface/love.png b/xemacs-packages/gnus/texi/xface/love.png
new file mode 100644 (file)
index 0000000..cc28c3b
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/love.png differ
diff --git a/xemacs-packages/gnus/texi/xface/moll.png b/xemacs-packages/gnus/texi/xface/moll.png
new file mode 100644 (file)
index 0000000..b50e97f
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/moll.png differ
diff --git a/xemacs-packages/gnus/texi/xface/niksic.png b/xemacs-packages/gnus/texi/xface/niksic.png
new file mode 100644 (file)
index 0000000..9e3839a
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/niksic.png differ
diff --git a/xemacs-packages/gnus/texi/xface/olsen.png b/xemacs-packages/gnus/texi/xface/olsen.png
new file mode 100644 (file)
index 0000000..45df40e
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/olsen.png differ
diff --git a/xemacs-packages/gnus/texi/xface/patch.png b/xemacs-packages/gnus/texi/xface/patch.png
new file mode 100644 (file)
index 0000000..33af321
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/patch.png differ
diff --git a/xemacs-packages/gnus/texi/xface/petersen.png b/xemacs-packages/gnus/texi/xface/petersen.png
new file mode 100644 (file)
index 0000000..2a83017
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/petersen.png differ
diff --git a/xemacs-packages/gnus/texi/xface/pjf.png b/xemacs-packages/gnus/texi/xface/pjf.png
new file mode 100644 (file)
index 0000000..e3d7f09
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/pjf.png differ
diff --git a/xemacs-packages/gnus/texi/xface/riocreux.png b/xemacs-packages/gnus/texi/xface/riocreux.png
new file mode 100644 (file)
index 0000000..fa4c915
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/riocreux.png differ
diff --git a/xemacs-packages/gnus/texi/xface/schauer.png b/xemacs-packages/gnus/texi/xface/schauer.png
new file mode 100644 (file)
index 0000000..a776767
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/schauer.png differ
diff --git a/xemacs-packages/gnus/texi/xface/simmonmt.png b/xemacs-packages/gnus/texi/xface/simmonmt.png
new file mode 100644 (file)
index 0000000..b3df919
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/simmonmt.png differ
diff --git a/xemacs-packages/gnus/texi/xface/simmons.png b/xemacs-packages/gnus/texi/xface/simmons.png
new file mode 100644 (file)
index 0000000..39e52fd
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/simmons.png differ
diff --git a/xemacs-packages/gnus/texi/xface/siu.png b/xemacs-packages/gnus/texi/xface/siu.png
new file mode 100644 (file)
index 0000000..d140e31
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/siu.png differ
diff --git a/xemacs-packages/gnus/texi/xface/smb.png b/xemacs-packages/gnus/texi/xface/smb.png
new file mode 100644 (file)
index 0000000..e890698
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/smb.png differ
diff --git a/xemacs-packages/gnus/texi/xface/sobek.png b/xemacs-packages/gnus/texi/xface/sobek.png
new file mode 100644 (file)
index 0000000..3c838ef
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/sobek.png differ
diff --git a/xemacs-packages/gnus/texi/xface/thomas.png b/xemacs-packages/gnus/texi/xface/thomas.png
new file mode 100644 (file)
index 0000000..0c42c8f
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/thomas.png differ
diff --git a/xemacs-packages/gnus/texi/xface/valdis.png b/xemacs-packages/gnus/texi/xface/valdis.png
new file mode 100644 (file)
index 0000000..715d08d
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/valdis.png differ
diff --git a/xemacs-packages/gnus/texi/xface/verna1.png b/xemacs-packages/gnus/texi/xface/verna1.png
new file mode 100644 (file)
index 0000000..d84f149
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/verna1.png differ
diff --git a/xemacs-packages/gnus/texi/xface/verna2.png b/xemacs-packages/gnus/texi/xface/verna2.png
new file mode 100644 (file)
index 0000000..fc2f5e5
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/verna2.png differ
diff --git a/xemacs-packages/gnus/texi/xface/yamaoka.png b/xemacs-packages/gnus/texi/xface/yamaoka.png
new file mode 100644 (file)
index 0000000..f406744
Binary files /dev/null and b/xemacs-packages/gnus/texi/xface/yamaoka.png differ
diff --git a/xemacs-packages/gnus/todo b/xemacs-packages/gnus/todo
new file mode 100644 (file)
index 0000000..853edfe
--- /dev/null
@@ -0,0 +1,1280 @@
+;; Also know as the "wish list".  Some are done. For the others, no
+;; promise when to be implemented.
+
+* Use a new custom type (`define-widget') for posting-style in `gnus-cus.el'
+  (G c) and for `gnus-posting-styles'.  Maybe some allowed types are still
+  missing.
+
+* Add proper doc strings to functions and variables explained in the manual
+  (info "(gnus)Gnus Utility Functions")
+
+* Add Message-IDs or URLs refering to relevant discussions on lists and
+  newsgroups.
+
+* Use nicer tool bar icons from GNOME
+
+  Done for Emacs (The GNOME icons won't fit into standard XEmacs icons,
+  IMHO. -- rsteib) in group, summary and message mode.
+
+  Some modes might also deserve improved tool bars:
+
+  - gnus-draft-mode
+
+  - mml-preview buffer:
+
+    . zap most buttons; except print, customize (?) and help
+
+    . "exit" should just kill the buffer
+
+  - gnus-server-mode: Add some commands from the Connections and Server
+    menu.
+
+  - gnus-browse-mode (could borrow some icons from gnus-group-mode)
+
+  (See http://article.gmane.org/gmane.emacs.gnus.general/62147).
+
+* Maybe Gnus should support the LIST SUBSCRIPTIONS, see RFC 2980.
+
+* Merge `message-extra-wide-headers' and ` message-header-synonyms'?
+
+* Maybe texi/emacs-mime.texi could be divided into user-visible stuff and
+  reference manual for the MIME library.
+
+  Related: Bill Wohler's article on mh-e-user.
+  http://thread.gmane.org/29067.1138078896@olgas.newt.com
+
+* Fix `change servers' command, see David Kastrup's message.
+  http://thread.gmane.org/x54qewqxz4.fsf@lola.goethe.zz
+
+* texi/gnus-coding.texi should be fixed.
+
+* gnus-topic-kill-region
+  From Colin Marquardt <colin.marquardt@usa.alcatel.com>
+
+  I noticed that when re-arranging topics, C-k yanks a topic just fine
+  (runs gnus-topic-kill-group).
+
+  However, my habit is to do marking and the yanking the region, so I
+  would run C-w on the marked topic. But C-w runs
+  gnus-group-kill-region and doesn't yank the topic (for groups it
+  works fine).
+
+  So could we have a gnus-topic-kill-region, or a
+  gnus-group-kill-region which handles topics as well?
+
+* Speed up sorting in summary buffer if there is a limit.
+
+  Suggested by Daniel Ortmann <ortmann@isl.net>.
+
+* Investigate the memory usage of Gnus. 
+
+  But it does seem strange that Gnus would use some 15meg for this.  I
+  think that is worth investigating.  I suspect that bugs or bad
+  design are causing waste; they could be in Gnus, or in Emacs. -- RMS
+
+* Google group digest
+
+  The result of Google group search return a thread. Is it a digest
+  format?
+
+* NOV caching.
+
+  Implement NOV caching with Gnus Agent.
+
+* 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.
+
+* Parsing of the subscription notice to stash away details like what
+   address you're subscribed to the list under (and automatically send
+   mail to the list using that address, when you send mail inside the list
+   group), what address to mail to unsubscribe, and the list info message
+   if available.  Hitting the "get FAQ" command inside a mailing list
+   group should display that stashed copy of the info message.
+
+* Some help in coming up with good split rules for mailing lists, as
+   automated as possible.  Splitting on To and Cc is almost always not
+   what I want, since it can misfile messages and since if I'm cc'd on
+   list mail I want to get both copies, one in my personal mailbox and one
+   in the list mailbox.  I know other people handle it other ways, but I
+   prefer it that way.  Accordingly, some way to semi-automatically
+   generate split rules based on Sender, Mailing-List, Return-Path,
+   X-Loop, and all of the other random headers that often work would be
+   very cool.
+
+* Agent:
+
+* A better interface to the agent download scoring rules, like the one
+  for the other scoring rules.
+
+* Editing of messages in the agents cache.
+  
+* Support for encrypted folders. Even if the mail arrives unencrypted
+  Gnus should be able to encrypt the *folder* for added safety. This
+  should go for both Gnus' own folders and the folders Gnus reads from
+  (e.g. /var/spool/mail/${USER}). All backends this makes sense for.
+
+  [John Wiegley's article <200011030445.VAA08277@localhost.dynodns.net>,
+   posted on gnu.emacs.gnus does this.
+   Also, gnus-article-encrypt `K E' encrypts the article body.]
+
+* Splitting .newsrc.eld so the history is in one file and the
+  configuration is in another. To help those that reads at two
+  locations (e.g. work and home) and want to have the same
+  configuration.
+
+* Additional article marking, and an ability to affect marks placed
+  during e.g. mail acquisition.  I want to be able to notice the
+  subject "fast money" or "web traffic", automatically mark it with a
+  `$', and score it into oblivion.  (But I fear that wanting to change
+  marks with mail-source-* and nnmail-* functions will represent a
+  philosophical conflict with the rest of Gnus' management of article
+  marks.  mail-source-* and nnmail-* currently hack around with files
+  under ~/Mail and leave traces in ~/Mail/active, but don't affect
+  things stored in .newsrc.eld.)
+
+* A much better interface to nnmail-split-methods.  I don't know how
+  I'd like this done, but I know that the current method of manually
+  hacking regexps is pretty untenable for new users.  My boss, who is
+  tenured faculty at CMU and CEO & CTO at JPRC, and whose research
+  work has involved Lisp for the last 25 years, is trying to implant
+  himself in a Gnus mail environment, and this is a big sticking point
+  even for him.
+
+* PGP-supported encryption of entire nnml & nnmh groups.  There are
+  people with whom I exchange mail routinely who don't send w/PGP, but
+  I'd really rather that the content not be left lying around
+  unencrypted.  Hook into article acquisition the way jka-compr
+  supposedly does, to auto-decrypt every message read.
+
+  [See Support for encrypted folders.]
+
+* Baby's First Mail In Gnus.  Some set of functions that the
+  new-to-mail-in-Gnus user can invoke which will query the user
+  appropriately for the basic information required to establish mail
+  handling, leaving the appropriate traces in .gnus.  Perhaps a
+  customize buffer would be appropriate.
+  - Where does your mail come from?
+  - If some server, what is your POP/IMAP protocol identity?
+  - What is your identity when sending mail, as opposed to posting to
+    Usenet?
+  - Here are some basic concepts of mail groups (list a few:
+    personal mail, company-wide mail, mailing lists, garbage dumps,
+    receptacles for outbound copies of what one sends; which ones do
+    you want to instantiate, and what mail should land in each?
+    [/viz./ problem of nnmail-split-methods interface.]
+
+  [Probably `assistant.el' will provide this.  But it's development is
+  stalled.]
+
+* Manual ordering of articles in an nnml folder.
+
+  That is, keystrokes to move articles (or whole threads) up or down
+  in the *Summary* buffer relative to the other articles.  The order
+  would be persistent (e.g., across gnus sessions).
+
+  With this ability, an nnml folder would make for a good to-do list.
+
+* Since many uses Gnus to store to do lists I think it is time for an
+  nntodo. (I know Kai already written one, maybe use that for a start?)
+
+* nnsql backend, which would allow messages or folders to be imported
+  in a local (My|Postgre|?)SQL RDBMS.
+
+* "posting profiles" ideally accessible from a popup menu; allowing
+  choice between predefined profiles of
+  from,name,organization,etc. Example: I'm at home, but need to reply
+  to a work mail; i can hit 'R', then use this command to switch to my
+  'work' profile for purposes of this one reply. (This might already
+  be possible with current Gnus, but I don't think so.)
+
+* Better handling of the mail retrieving / splitting feature:
+  - the variables <backend>-get-new-mail should not exist anymore. Mail
+    retrieving should be a separate matter.
+  - we should be able to split mails to groups AND backends at the same time.
+  - meanwhile, we should still be able to associate certain mail sources with
+    certain backends.
+
+* More article marks (like '!' or '?').
+  Maybe user defined marks that can be displayed as any choosen charakter,
+  so one could do things like limiting on, to do whatever one likes with
+  these articles.
+
+* Allow article editing in groups which do not support it, but
+  emulating it via deleting the old article and entering the new one
+  into the group.  This would be very useful to support `T ^' (say) in
+  nnimap groups.
+
+* Allow user to specify which kinds of groups should be displayed.
+  For example, I want to display all the groups that are displayed
+  now, plus those which have cached messages in them.  (Gnus does
+  display those with ticked messages but not those with
+  cached-but-unticked ones.)  This would become even more important
+  when we allow labels.
+
+* Create new data type `article identifier' and use that instead of
+  article numbers.  A first implementation could offer something like
+  (num . 4711) but this could be extended.  This would be useful for
+  using servers with *really* large numbers -- there we could have a
+  bignum type.  It might also be useful for the nnweb and nnultimate
+  thingies where article identifiers are not really numbers.
+
+* Allow use of digests to keep related articles.  Normally, you use
+  groups to group together articles which are thematically related.
+  But sometimes, you have so many themes that this becomes
+  impractical.  WIBNI I could have digests in a group, and there was a
+  way to add a new article to one of the digests in that group?
+
+  Or maybe what I really want is a way to tell Gnus that a specific
+  thread should always be hidden (as in `T h') by default, while most
+  other threads are not hidden by default.  Hm.
+
+* New backend nnbabylfolder.  There is also nnbabyl which is like
+  nnmbox but uses babyl format, but there is no babyl format
+  equivalent of nnfolder.
+
+* Make movement commands in summary buffer independent of `move after
+  mark' behavior when marking articles.  Currently, if you don't want
+  `E' to move to the next unread article, you have to set
+  gnus-summary-goto-unread to nil, and then there is no way to move to
+  the next or previous unread article.
+
+  This one has two sub-tasks.  Providing the commands is one thing,
+  finding out useful key bindings for them is another.  I think we
+  could provide the commands first while not changing the behavior of
+  the key bindings; then different people can experiment with
+  different key binding schemes until we find something which suits
+  many people.
+
+* `Move to next/previous/first article' is a misnomer, since ticked
+  articles are also unread but not moved to by these commands.  Should
+  the terminology be fixed or the documentation, or what?
+
+* Allow sorting of threads by newest article rather than by root of
+  thread.  Consider the following thread structure:
+
+    root1       Jan 1
+      leaf1     Jan 4
+    root2       Jan 2
+      leaf2     Jan 3
+
+  These two threads are sorted this way because root1 is older than
+  root2.  I want an option to sort them the other way round because
+  leaf1 is newer than leaf2.
+
+* Improve editing of MIME messages.  I would like to use html-mode to
+  edit the body of a text/html message, and enriched-mode for
+  text/enriched messages, and so on.  This should go for multipart
+  messages as well.  This is probably a hard one since Emacs currently
+  does not allow several major modes per buffer.  But maybe it would
+  be nice to hack Emacs to provide this infrastructure so that Gnus
+  can make use of it?  This would also make it possible to provide
+  nifty commands for editing the headers, for example, rather than
+  relying on commands which do the same thing everywhere.
+  message-x.el is really just a half-assed attempt at doing it, and
+  while it is useful, that's not the way it should be done.
+
+  I think Francisco Potort\e,Al\e(B already did something like this?
+
+* Provide commands for editing MML tags.  For example, there could be
+  a command mml-add-tag-attribute which prompts me for an attribute
+  name (with completion, from the set filename, type, ...), and then
+  for a value.  (This is like `C-c +' in psgml.)  Or there could be a
+  command which showed me all the attributes in an MML tag and allows
+  me to use TAB to move between them, and then to edit each attribute
+  value.  (This is like `C-c C-a' in psgml.)
+
+* Have Gnus automagically set group parameters for mailing list
+  groups.  For example, if I have a splitting rule that automatically
+  sorts ding@gnus.org into mail.ding, then Gnus should clue in, set
+  the to-list parameter to 'ding@gnus.org', and set total-expire.
+  (This is probably Hard (TM).  And of course the user should be able
+  to configure what parameters exactly get set.)
+
+* Along the same lines, automagically detect broken reply-to's.  (But
+  don't auto-detect users legitimately setting a reply-to header that
+  points back to the list.)
+
+* Make it easier to change parameters on a set of groups,
+  e.g. set/clear gcc-self on process-marked groups.
+
+* Make it easier/possible to migrate between primary select-methods,
+  if that concept is going to be kept.  Right now I have only one
+  group on my primary server, and I'd kind of like to change from nntp
+  to nnml, but apparently this doesn't work well.
+
+* Make it possible to refer to uniquely-named groups without
+  select-method prefix (e.g. mail.misc instead of nnml:mail.misc).
+
+* Annotations as discussed last autumn. Be able to make comments to
+  articles for all backends. The comments maybe should go into a
+  seperate "backend", like nndraft.
+
+* Catchup on a topic and all its subtopics. I.e. do "c y" when on a
+  topic line in *Group*.
+
+* Better/more advanced subject washing in *Summary*, see my
+  js-gnus-simplify-subject-function I posted earlier this winter.
+
+;; From Newest Features node. Some are not done.
+
+* I would like the zombie-page to contain an URL to the source of the
+latest version of gnus or some explanation on where to find it.
+
+*  A way to continue editing the latest Message composition.
+
+*  facep is not declared.
+
+* Include a section in the manual on why the number of articles isn't
+the same in the group buffer and on the SPC prompt.
+
+*  Interacting with rmail fcc isn't easy.
+
+*       Hypermail:
+      http://www.uwsg.indiana.edu/hypermail/linux/kernel/9610/index.html
+
+   [w3 or nnwarchive?]
+
+* `^-- ' is made into - in LaTeX.
+
+*  when expunging articles on low score, the sparse nodes keep
+ hanging on?
+
+*  starting the first time seems to hang Gnus on some systems.  Does
+ NEWGROUPS answer too fast?
+
+*  nndir doesn't read gzipped files.
+
+*  when moving mail from a procmail spool to the crash-box, the
+ crash-box is only appropriate to one specific group.
+
+*  nnmh-be-safe means that crossposted articles will be marked as
+ unread.
+
+*  Orphan score entries don't show on "V t" score trace
+
+*  when clearing out data, the cache data should also be reset.
+
+* rewrite gnus-summary-limit-children to be non-recursive to avoid
+exceeding lisp nesting on huge groups.
+
+*  expunged articles are counted when computing scores.
+
+*  ticked articles aren't easy to read in pick mode - `n' and stuff
+ just skips past them.  Read articles are the same.
+
+*  topics that contain just groups with ticked articles aren't
+ displayed.
+
+*  nndoc should always allocate unique Message-IDs.
+
+*  If there are mail groups the first time you use Gnus, Gnus'll
+ make the mail groups killed.
+
+*  no "no news is good news" when using topics.
+
+*  when doing crosspost marking, the cache has to be consulted and
+ articles have to be removed.
+
+*  nnweb should fetch complete articles when they are split into
+ several parts.
+
+*  scoring on head immediate doesn't work.
+
+*  finding short score file names takes forever.
+
+*  canceling articles in foreign groups.
+
+*  nntp-open-rlogin no longer works.
+
+*  C-u C-x C-s (Summary) switches to the group buffer.
+
+*  move nnmail-split-history out to the backends.
+
+*  using a virtual server name as `gnus-select-method' doesn't work?
+
+*  when killing/yanking a group from one topic to another in a
+ slave, the master will yank it first to one topic and then add it
+ to another.  Perhaps.
+
+*  warn user about `=' redirection of a group in the active file?
+
+*  take over the XEmacs menubar and offer a toggle between the XEmacs
+ bar and the Gnus bar.
+
+*       push active file and NOV file parsing down into C code.
+      `(canonize-message-id id)'
+      `(mail-parent-message-id references n)'
+      `(parse-news-nov-line &optional dependency-hashtb)'
+      `(parse-news-nov-region beg end &optional dependency-hashtb fullp)'
+      `(parse-news-active-region beg end hashtb)'
+
+*  nnml .overview directory with splits.
+
+*  asynchronous cache
+
+*  postponed commands.
+
+*  the selected article show have its Subject displayed in its
+ summary line.
+
+*  when entering groups, get the real number of unread articles from
+ the server?
+
+*  sort after gathering threads - make false roots have the headers
+ of the oldest orphan with a 0 article number?
+
+*  nndoc groups should inherit the score files of their parents?
+ Also inherit copy prompts and save files.
+
+*  command to start up Gnus (if not running) and enter a mail mode
+ buffer.
+
+*  allow editing the group description from the group buffer for
+ backends that support that.
+
+* gnus-hide,show-all-topics
+
+*  groups and sub-topics should be allowed to mingle inside each
+ topic, and not just list all subtopics at the end.
+
+*  a command to remove all read articles that are not needed to
+ connect threads - `gnus-summary-limit-to-sparse-unread'?
+
+*  a variable to turn off limiting/cutting of threads in the tree
+ buffer.
+
+*  a variable to limit how many files are uudecoded.
+
+*  add zombie groups to a special "New Groups" topic.
+
+*  server mode command: close/open all connections
+
+*  put a file date in gnus-score-alist and check whether the file
+ has been changed before using it.
+
+*  on exit from a digest group, go to the next article in the parent
+ group.
+
+*  hide (sub)threads with low score.
+
+*  when expiring, remove all marks from expired articles.
+
+*  gnus-summary-limit-to-body
+
+*  a regexp alist that says what level groups are to be subscribed
+ on.  Eg. - `(("nnml:" . 1))'.
+
+*  allow newlines in <URL:> urls, but remove them before using the
+ URL.
+
+*  If there is no From line, the mail backends should fudge one from
+ the "From " line.
+
+*  fuzzy simplifying should strip all non-alpha-numerical info from
+ subject lines.
+
+*  nntp-ping-before-connect
+
+*  command to check whether NOV is evil.  "list overview.fmt".
+
+*  when entering a group, Gnus should look through the score files
+ very early for `local' atoms and set those local variables.
+
+*  topics are always yanked before groups, and that's not good.
+
+*  (set-extent-property extent 'help-echo "String to display in
+ minibuf") to display help in the minibuffer on buttons under
+ XEmacs.
+
+*  stop using invisible text properties and start using overlays
+ instead
+
+*  go from one group to the next; everything is expunged; go to the
+ next group instead of going to the group buffer.
+
+*  gnus-renumber-cache - to renumber the cache using "low" numbers.
+
+*  record topic changes in the dribble buffer.
+
+*  `nnfolder-generate-active-file' should look at the folders it
+ finds and generate proper active ranges.
+
+*  nneething-look-in-files-for-article-heads variable to control
+ whether nneething should sniff all files in the directories.
+
+*  gnus-fetch-article - start Gnus, enter group, display article
+
+*  gnus-dont-move-articles-to-same-group variable when respooling.
+
+*  when messages are crossposted between several auto-expirable
+ groups, articles aren't properly marked as expirable.
+
+*  nneething should allow deletion/moving.
+
+*  TAB on the last button should go to the first button.
+
+*  if the car of an element in `mail-split-methods' is a function,
+ and the function returns non-nil, use that as the name of the
+ group(s) to save mail in.
+
+*  command for listing all score files that have been applied.
+
+*  a command in the article buffer to return to `summary' config.
+
+*  `gnus-always-post-using-current-server' - variable to override
+ `C-c C-c' when posting.
+
+*  nnmail-group-spool-alist - says where each group should use as a
+ spool file.
+
+*  when an article is crossposted to an auto-expirable group, the
+ article should be marker as expirable.
+
+*  article mode command/menu for "send region as URL to browser".
+
+*  on errors, jump to info nodes that explain the error.  For
+ instance, on invalid From headers, or on error messages from the
+ nntp server.
+
+*  when gathering threads, make the article that has no "Re: " the
+ parent.  Also consult Date headers.
+
+*  a token in splits to call shrink-window-if-larger-than-buffer
+
+*  `1 0 A M' to do matches on the active hashtb.
+
+*  duplicates - command to remove Gnus-Warning header, use the read
+ Message-ID, delete the "original".
+
+*  when replying to several messages at once, put the "other"
+ message-ids into a See-Also header.
+
+*  support ProleText:
+ <URL:http://proletext.clari.net/prole/proletext.html>
+
+*  generate font names dynamically.
+
+*  score file mode auto-alist.
+
+*  allow nndoc to change/add/delete things from documents.  Implement
+ methods for each format for adding an article to the document.
+
+*  `gnus-fetch-old-headers' `all' value to incorporate absolutely
+ all headers there is.
+
+*  function like `|', but concatenate all marked articles and pipe
+ them to the process.
+
+*  cache the list of killed (or active) groups in a separate file.
+ Update the file whenever we read the active file or the list of
+ killed groups in the .eld file reaches a certain length.
+
+*  function for starting to edit a file to put into the current mail
+ group.
+
+*  "ghettozie" - score on Xref header and nix it out after using it
+ to avoid marking as read in other groups it has been crossposted
+ to.
+
+*  look at procmail splitting.  The backends should create the
+ groups automatically if a spool file exists for that group.
+
+*  function for backends to register themselves with Gnus.
+
+*  when replying to several process-marked articles, have all the
+ From end up in Cc headers?  Variable to toggle.
+
+*  command to delete a crossposted mail article from all groups it
+ has been mailed to.
+
+*  `B c' and `B m' should be crosspost aware.
+
+*  hide-pgp should also hide PGP public key blocks.
+
+*  Command in the group buffer to respool process-marked groups.
+
+*  `gnus-summary-find-matching' should accept pseudo-"headers" like
+ "body", "head" and "all"
+
+*  Process-marking all groups in a topic should process-mark groups
+ in subtopics as well.
+
+*  Add non-native groups to the list of killed groups when killing
+ them.
+
+If this entry is about non-foreign non-native groups, then it was
+actually a bug that prevented them from being inserted into
+gnus-killed-list:
+<http://article.gmane.org/gmane.emacs.gnus.general/63383/>
+
+*  nntp-suggest-kewl-config to probe the nntp server and suggest
+ variable settings.
+
+*  add edit and forward secondary marks.
+
+*  nnml shouldn't visit its .overview files.
+
+*  allow customizing sorting within gathered threads.
+
+*  `B q' shouldn't select the current article.
+
+*  nnmbox should support a newsgroups file for descriptions.
+
+*  Be able to specify whether the saving commands save the original
+ or the formatted article.
+
+*  a command to reparent with the child process-marked (cf. `T ^'.).
+
+*  I think the possibility to send a password with nntp-open-rlogin
+ should be a feature in Red Gnus.
+
+*  The `Z n' command should be possible to execute from a mouse
+ click.
+
+*  more limiting functions - date, etc.
+
+   We have `gnus-summary-limit-to-age'.  What's missing?  Maybe enter a date?
+
+*  be able to limit on a random header; on body; using reverse
+ matches.
+
+*  a group parameter (`absofucking-total-expiry') that will make
+ Gnus expire even unread articles.
+
+*  variable to disable password fetching when opening by
+ nntp-open-telnet.
+
+*  manual: more example servers - nntp with rlogin, telnet
+
+*  checking for bogus groups should clean topic alists as well.
+
+*  canceling articles in foreign groups.
+
+*  article number in folded topics isn't properly updated by Xref
+ handling.
+
+*  Movement in the group buffer to the next unread group should go
+ to the next closed topic with unread messages if no group can be
+ found.
+
+*  Extensive info pages generated on the fly with help everywhere -
+ in the "*Gnus edit*" buffers, for instance.
+
+*  Topic movement commands - like thread movement.  Up, down,
+ forward, next.
+
+*  a way to say that all groups within a specific topic comes from a
+ particular server?  Hm.
+
+*  `gnus-article-fill-if-long-lines' - a function to fill the
+ article buffer if there are any looong lines there.
+
+*  `T h' should jump to the parent topic and fold it.
+
+*  a command to create an ephemeral nndoc group out of a file, and
+ then splitting it/moving it to some other group/backend.
+
+*  It should also probably be possible to delimit what
+ `gnus-jog-cache' does - for instance, work on just some groups, or
+ on some levels, and entering just articles that have a score
+ higher than a certain number.
+
+*  nnfolder should append to the folder instead of re-writing the
+ entire folder to disk when accepting new messages.
+
+*  a backend for reading collections of babyl files nnbabylfolder?
+
+*  a command for making the native groups into foreign groups.
+
+*  server mode command for clearing read marks from all groups from
+ a server.
+
+*  when following up multiple articles, include all To, Cc, etc
+ headers from all articles.
+
+*  a command for deciding what the total score of the current thread
+ is.  Also a way to highlight based on this.
+
+*  command to show and edit group scores
+
+*  a gnus-tree-minimize-horizontal to minimize tree buffers
+ horizontally.
+
+*  command to generate nnml overview file for one group.
+
+*  `C-u C-u a' - prompt for many crossposted groups.
+
+*  keep track of which mail groups have received new articles (in
+ this session).  Be able to generate a report and perhaps do some
+ marking in the group buffer.
+
+*  gnus-build-sparse-threads to a number - build only sparse threads
+ that are of that length.
+
+*  have nnmh respect mh's unseen sequence in .mh_profile.
+
+*  cache the newsgroups descriptions locally.
+
+*  asynchronous posting under nntp.
+
+*  be able to control word adaptive scoring from the score files.
+
+*  a variable to make `C-c C-c' post using the "current" select
+ method.
+
+*  `limit-exclude-low-scored-articles'.
+
+*  if `gnus-summary-show-thread' is a number, hide threads that have
+ a score lower than this number.
+
+*  split newsgroup subscription variable up into "order" and
+ "method".
+
+*  buttonize ange-ftp file names.
+
+*  a command to make a duplicate copy of the current article so that
+ each copy can be edited separately.
+
+*  nnweb should allow fetching from the local nntp server.
+
+*  record the sorting done in the summary buffer so that it can be
+ repeated when limiting/regenerating the buffer.
+
+*  nnml-generate-nov-databses should generate for all nnml servers.
+
+*  when the user does commands in the group buffer, check the
+ modification time of the .newsrc.eld file and use
+ ask-user-about-supersession-threat.  Also warn when trying to save
+ .newsrc.eld and it has changed.
+
+*  M-g on a topic will display all groups with 0 articles in the
+ topic.
+
+*  command to remove all topic stuff.
+
+*  allow exploding incoming digests when reading incoming mail and
+ splitting the resulting digests.
+
+*  command to nix out all nnoo state information.
+
+*  nnmail-process-alist that calls functions if group names matches
+ an alist - before saving.
+
+*  use buffer-invisibility-spec everywhere for hiding text.
+
+*  variable to activate each group before entering them to get the
+ (new) number of articles.  `gnus-activate-before-entering'.
+
+*  command to fetch a Message-ID from any buffer, even starting Gnus
+ first if necessary.
+
+*  when posting and checking whether a group exists or not, just ask
+ the nntp server instead of relying on the active hashtb.
+
+*  buttonize the output of `C-c C-a' in an apropos-like way.
+
+*  `G p' should understand process/prefix, and allow editing of
+ several groups at once.
+
+*  command to create an ephemeral nnvirtual group that matches some
+ regexp(s).
+
+*  it should be possible to score "thread" on the From header.
+
+*  hitting RET on a "gnus-uu-archive" pseudo article should unpack
+ it.
+
+*  `B i' should display the article at once in the summary buffer.
+
+*  remove the "*" mark at once when unticking an article.
+
+*  `M-s' should highlight the matching text.
+
+*  when checking for duplicated mails, use Resent-Message-ID if
+ present.
+
+*  killing and yanking groups in topics should be better.  If
+ killing one copy of a group that exists in multiple topics, only
+ that copy should be removed.  Yanking should insert the copy, and
+ yanking topics should be possible to be interspersed with the
+ other yankings.
+
+*  command for enter a group just to read the cached articles.  A
+ way to say "ignore the nntp connection; just read from the cache."
+
+*  a way to hide all "inner" cited text, leaving just the most
+ recently cited text.
+
+*  nnvirtual should be asynchronous.
+
+*  after editing an article, gnus-original-article-buffer should be
+ invalidated.
+
+*  there should probably be a way to make Gnus not connect to the
+ server and just read the articles in the server
+
+*  allow a `set-default' (or something) to change the default value
+ of nnoo variables.
+
+*  a command to import group infos from a .newsrc.eld file.
+
+*  groups from secondary servers have the entire select method
+ listed in each group info.
+
+*  a command for just switching from the summary buffer to the group
+ buffer.
+
+*  a way to specify that some incoming mail washing functions should
+ only be applied to some groups.
+
+*  Message `C-f C-t' should ask the user whether to heed
+ mail-copies-to: never.
+
+*  new group parameter - `post-to-server' that says to post using
+ the current server.  Also a variable to do the same.
+
+*  the slave dribble files should auto-save to the slave file names.
+
+*  a group parameter that says what articles to display on group
+ entry, based on article marks.
+
+*  a way to visually distinguish slave Gnusae from masters.  (Whip
+ instead of normal logo?)
+
+*  Use DJ Bernstein "From " quoting/dequoting, where applicable.
+
+*  Why is hide-citation-maybe and hide-citation different?  Also
+ clear up info.
+
+*  group user-defined meta-parameters.
+
+ From: John Griffith <griffith@sfs.nphil.uni-tuebingen.de>
+
+*  I like the option for trying to retrieve the FAQ for a group and
+ I was thinking it would be great if for those newsgroups that had
+ archives you could also try to read the archive for that group.
+ Part of the problem is that archives are spread all over the net,
+ unlike FAQs.  What would be best I suppose is to find the one
+ closest to your site.
+
+ In any case, there is a list of general news group archives at
+ ftp://ftp.neosoft.com/pub/users/claird/news.lists/newsgroup_archives.html
+
+*      From: Jason L Tibbitts III <tibbs@hpc.uh.edu>
+      (add-hook 'gnus-select-group-hook
+       (lambda ()
+         (gnus-group-add-parameter group
+            (cons 'gnus-group-date-last-entered (list (current-time-string))))))
+
+      (defun gnus-user-format-function-d (headers)
+       "Return the date the group was last read."
+       (cond ((car (gnus-group-get-parameter gnus-tmp-group 'gnus-group-date-last-entered)))
+           (t "")))
+
+*  tanken var at n\e,Ae\e(Br du bruker `gnus-startup-file' som prefix (FOO)
+ til \e,Ae\e(B lete opp en fil FOO-SERVER, FOO-SERVER.el, FOO-SERVER.eld,
+ kan du la den v\e,Af\e(Bre en liste hvor du bruker hvert element i listen
+ som FOO, istedet.  da kunne man hatt forskjellige serveres
+ startup-filer forskjellige steder.
+
+* LMI> Well, nnbabyl could alter the group info to heed labels like
+ LMI> answered and read, I guess.
+
+ It could also keep them updated (the same for the Status: header of
+ unix mbox files).
+
+ They could be used like this:
+
+      `M l <name> RET' add label <name> to current message.
+      `M u <name> RET' remove label <name> from current message.
+      `/ l <expr> RET' limit summary buffer according to <expr>.
+
+      <expr> would be a boolean expression on the labels, e.g.
+
+      `/ l bug & !fixed RET'
+
+ would show all the messages which are labeled `bug' but not labeled
+ `fixed'.
+
+ One could also imagine the labels being used for highlighting, or
+ affect the summary line format.
+
+* Sender: abraham@dina.kvl.dk
+
+ I'd like a gnus-find-file which work like find file, except that it
+ would recognize things that looks like messages or folders:
+
+ - If it is a directory containing numbered files, create an nndir
+ summary buffer.
+
+ - For other directories, create a nneething summary buffer.
+
+ - For files matching "\\`From ", create a nndoc/mbox summary.
+
+ - For files matching "\\`BABYL OPTIONS:", create a nndoc/baby
+ summary.
+
+ - For files matching "\\`[^ \t\n]+:", create an *Article* buffer.
+
+ - For other files, just find them normally.
+
+ I'd like `nneething' to use this function, so it would work on a
+ directory potentially containing mboxes or babyl files.
+
+* Currently, I get prompted:
+
+ decend into sci?  - type y decend into sci.something ?  - type n
+ decend into ucd?
+
+ The problem above is that since there is really only one
+ subsection of science, shouldn't it prompt you for only descending
+ sci.something?  If there was a sci.somethingelse group or section,
+ then it should prompt for sci? first the sci.something? then
+ sci.somethingelse?...
+
+* Ja, det burde v\e,Af\e(Bre en m\e,Ae\e(Bte \e,Ae\e(B si slikt.  Kanskje en ny variabel?
+ `gnus-use-few-score-files'?  S\e,Ae\e(B kunne score-regler legges til den
+ "mest" lokale score-fila.  F. eks. ville no-gruppene betjenes av
+ "no.all.SCORE", osv.
+
+* What i want is for Gnus to treat any sequence or combination of
+ the following as a single spoiler warning and hide it all,
+ replacing it with a "Next Page" button:
+
+ ^L's
+
+ more than n blank lines
+
+ more than m identical lines (which should be replaced with button
+ to show them)
+
+ any whitespace surrounding any of the above
+
+* Well, we could allow a new value to `gnus-thread-ignore-subject' -
+ `spaces', or something.  (We could even default to that.)  And then
+ subjects that differ in white space only could be considered the
+ "same" subject for threading purposes.
+
+* Modes to preprocess the contents (e.g. jka-compr) use the second
+ form "(REGEXP FUNCTION NON-NIL)" while ordinary modes (e.g. tex)
+ use the first form "(REGEXP . FUNCTION)", so you could use it to
+ distinguish between those two types of modes. (auto-modes-alist,
+ insert-file-contents-literally.)
+
+*  Under XEmacs - do funny article marks: tick - thumb tack killed -
+ skull soup - bowl of soup score below - dim light bulb score over
+ - bright light bulb
+
+* Yes. I think the algorithm is as follows:
+
+      Group-mode
+
+        show-list-of-articles-in-group
+             if (key-pressed == SPACE)
+                     if (no-more-articles-in-group-to-select)
+                             if (articles-selected)
+                                     start-reading-selected-articles;
+                             junk-unread-articles;
+                             next-group;
+                      else
+                             show-next-page;
+
+              else if (key-pressed = '.')
+                     if (consolidated-menus)         # same as hide-thread in Gnus
+                             select-thread-under-cursor;
+                     else
+                             select-article-under-cursor;
+
+
+      Article-mode
+             if (key-pressed == SPACE)
+                     if (more-pages-in-article)
+                             next-page;
+                     else if (more-selected-articles-to-read)
+                             next-article;
+                     else
+                             next-group;
+
+* My precise need here would have been to limit files to Incoming*.
+ One could think of some `nneething-only-files' variable, but I
+ guess it would have been unacceptable if one was using many
+ unrelated such nneething groups.
+
+ A more useful approach would be to, in response to the `G D'
+ prompt, be allowed to say something like: `~/.mail/Incoming*',
+ somewhat limiting the top-level directory only (in case
+ directories would be matched by the wildcard expression).
+
+*    Take a look at w3-menu.el in the Emacs-W3 distribution - this
+ works out really well.  Each menu is 'named' by a symbol that
+ would be on a gnus-*-menus (where * would be whatever, but at
+ least group, summary, and article versions) variable.
+
+ So for gnus-summary-menus, I would set to '(sort mark dispose ...)
+
+ A value of '1' would just put _all_ the menus in a single 'GNUS'
+ menu in the main menubar.  This approach works really well for
+ Emacs-W3 and VM.
+
+*  nndoc should take care to create unique Message-IDs for all its
+ articles.
+
+*  gnus-score-followup-article only works when you have a summary
+ buffer active.  Make it work when posting from the group buffer as
+ well.  (message-sent-hook).
+
+*  * Enhancements to Gnus:
+
+ Add two commands:
+
+ * gnus-servers (gnus-start-server-buffer?)-enters Gnus and goes
+ straight to the server buffer, without opening any connections to
+    servers first.
+
+ * gnus-server-read-server-newsrc-produces a buffer very similar to
+    the group buffer, but with only groups from that server listed;
+    quitting this buffer returns to the server buffer.
+
+*  add a command to check the integrity of an nnfolder folder - go
+ through the article numbers and see that there are no duplicates,
+ and stuff.
+
+*  a command to give all relevant info on an article, including all
+ secondary marks.
+
+*  when doing `-request-accept-article', the backends should do the
+ nnmail duplicate checking.
+
+*  cache the newsgroups file locally to avoid reloading it all the
+ time.
+
+*  a command to import a buffer into a group.
+
+*  point in the article buffer doesn't always go to the beginning of
+ the buffer when selecting new articles.
+
+*  a command to process mark all unread articles.
+
+*  `gnus-gather-threads-by-references-and-subject' - first do
+ gathering by references, and then go through the dummy roots and
+ do more gathering by subject.
+
+*  gnus-uu-mark-in-numerical-order - process mark articles in
+ article numerical order.
+
+*  (gnus-thread-total-score  (gnus-id-to-thread (mail-header-id
+ (gnus-summary-article-header)))) bind to a key.
+
+*  sorting by score is wrong when using sparse threads.
+
+*  a command to fetch an arbitrary article - without having to be in
+ the summary buffer.
+
+*  a new nncvs backend.  Each group would show an article, using
+ version branches as threading, checkin date as the date, etc.
+
+* A Date scoring type that will match if the article is less than a certain
+ number of days old. With - < > = (etc) that take floating point numbers and
+ match on the age of the article.
+
+*  use the summary toolbar in the article buffer.
+
+*  a command to fetch all articles that are less than X days old.
+
+*  in pick mode, `q' should save the list of selected articles in the
+ group info.  The next time the group is selected, these articles
+ will automatically get the process mark.
+
+*  Isn't it possible to (also?) allow M-^ to automatically try the
+ default server if it fails on the current server?  (controlled by a
+ user variable, (nil, t, 'ask)).
+
+ [Done by `gnus-refer-article-method'?]
+
+*  a new variable to control which selection commands should be
+ unselecting.  `first', `best', `next', `prev', `next-unread',
+ `prev-unread' are candidates.
+
+*  `x' should retain any sortings that have been performed.
+
+*  allow the user to specify the precedence of the secondary marks.
+ Also allow them to be displayed separately.
+
+*  gnus-summary-save-in-pipe should concatenate the results from the
+ processes when doing a process marked pipe.
+
+*  a new match type, like Followup, but which adds Thread matches on
+ all articles that match a certain From header.
+
+*  a function that can be read from kill-emacs-query-functions to
+ offer saving living summary buffers.
+
+*  a function for selecting a particular group which will contain
+ the articles listed in a list of article numbers/id's.
+
+*       (add-hook 'gnus-exit-query-functions
+      '(lambda ()
+        (if (and (file-exists-p nnmail-spool-file)
+                 (> (nnheader-file-size nnmail-spool-file) 0))
+            (yes-or-no-p "New mail has arrived.  Quit Gnus anyways? ")
+            (y-or-n-p "Are you sure you want to quit Gnus? "))))
+
+*  gnus-article-hide-pgp Selv ville jeg nok ha valgt \e,Ae\e(B slette den
+ dersom teksten matcher
+      "\\(This\s+\\)?[^ ]+ has been automatically signed by"
+ og det er maks hundre tegn mellom match-end og ---linja.  Men -det-
+ er min type heuristikk og langt fra alles.
+
+*  `gnus-subscribe-sorted' - insert new groups where they would have
+ been sorted to if `gnus-group-sort-function' were run.
+
+*  gnus-(group,summary)-highlight should respect any `face' text
+ props set on the lines.
+
+*  nndraft-request-group should tally auto-save files.
+
+*  implement nntp-retry-on-break and nntp-command-timeout.
+
+*  gnus-article-highlight-limit that says when not to highlight
+ (long) articles.
+
+* Interrupting the agent fetching of articles should save articles.
+ Have the Agent write out articles, one by one, as it retrieves
+ them, to avoid having to re-fetch them all if Emacs should crash
+ while fetching.
+
+*  command to open a digest group, and copy all the articles there
+ to the current group.
+
+*  handle 480/381 authinfo requests separately.
+
+*  command to display all dormant articles.
+
+*  gnus-auto-select-next makeover - list of things it should do.
+
+*  a score match type that adds scores matching on From if From has
+ replied to something someone else has said.
+
+* `T v' - make all process-marked articles the children of the
+ current article.
+
+* Switch from initial text to the new default text mechanism.
+
+* How about making it possible to expire local articles?  Will it be
+ possible to make various constraints on when an article can be
+ expired, e.g. (read), (age > 14 days), or the more interesting
+ (read & age > 14 days)?
+
+* New limit command--limit to articles that have a certain string in
+ the head or body.
+
+* Allow breaking lengthy NNTP commands.
+
+* gnus-article-highlight-limit, to disable highlighting in big
+ articles.
+
+* A command to send a mail to the admin-address group param.
+
+* Allow Gnus Agent scoring to use normal score files.
+
+* Rething the Agent active file thing.  `M-g' doesn't update the
+ active file, for instance.
+
+* With dummy roots, `^' and then selecing the first article in any
+ other dummy thread will make Gnus highlight the dummy root instead
+ of the first article.
+
+* Propagate all group properties (marks, article numbers, etc) up to
+ the topics for displaying.
+
+* gnus-posting-styles doesn't work in drafts.
+
+* gnus-summary-limit-include-cached is slow when there are many
+ articles in the cache, since it regenerates big parts of the
+ summary buffer for each article.
+
+* Group parameters and summary commands for un/subscribing to mailing
+ lists.
+
+* Introduce nnmail-home-directory.
+
+* gnus-fetch-group and friends should exit Gnus when the user exits
+ the group.
+
+* Crossposted articles should "inherit" the % or  mark from the other
+ groups it has been crossposted to, or something.  (Agent.)
+
+* If point is on a group that appears multiple times in topics, and
+ you press `l', point will move to the first instance of the group.
+
+* A spec for the group line format to display the number of
+ agent-downloaded articles in the group.
+
+* Some nntp servers never respond when posting, so there should be a
+ timeout for all commands.
+
+* When stading on a topic line and `t'-ing, point goes to the last
+ line.  It should go somewhere else.
+
+*  When `#F', do:
+
+      Subject: Answer to your mails 01.01.1999-01.05.1999
+       --text follows this line--
+      Sorry I killfiled you...
+
+      Under the subject "foo", you wrote on 01.01.1999:
+      > bar
+      Under the subject "foo1", you wrote on 01.01.1999:
+      > bar 1
+
+* Allow "orphan" scores in the Agent scoring.
+
+  [done?]
+
+*          - Edit article's summary line.
+         - End edit
+         - Sort lines in buffer by subject
+
+         --> the old subject line appears in Summary buffer, not the one that was
+         just changed to.
+
+* Remove list identifiers from the subject in the summary when doing
+ `^' and the like.
+
+* nnweb should include the "get whole article" article when getting
+ articles.
+
+* Perhaps there should be a command to "attach" a buffer of comments
+ to a message?  That is, `B WHATEVER', you're popped into a buffer,
+ write something, end with `C-c C-c', and then the thing you've
+ written gets to be the child of the message you're commenting.
+
+* Handle external-body parts.
+
+  [done for some access types]
+
+* When renaming a group name, nnmail-split-history does not get the
+ group name renamed.
+
+* Allow mail splitting on bodies when using advanced mail splitting.
+
+       (body "whatever.text")
+
+* Solve the halting problem.
+
+\f
+;; Local Variables:
+;; mode: outline
+;; coding: iso-2022-7bit
+;; paragraph-separate: "[      \f]*$"
+;; End:
diff --git a/xemacs-packages/gnus/www/ChangeLog b/xemacs-packages/gnus/www/ChangeLog
new file mode 100644 (file)
index 0000000..64eaf93
--- /dev/null
@@ -0,0 +1,36 @@
+2011-03-16  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * git.gnus.org/index.html: Updates about the CACert certificate.
+
+2011-03-02  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * git.gnus.org/index.html: Adjust icon to gnus-icon.png.
+
+2011-03-02  Adam Sjøgren  <asjo@koldfront.dk>
+
+       * git.gnus.org/gnus-icon.png: Add icon.
+
+2011-03-01  Adam Sjøgren  <asjo@koldfront.dk>
+
+       * git.gnus.org/gnus-cgit.png: Add logo.
+       * git.gnus.org/index.html: Use it.  Add information about the
+       gnus-html.git repository.
+
+2010-04-20  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * git.gnus.org/index.html: Tell about the cgit repository.
+
+2010-04-19  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * git.gnus.org/index.html: Tell about server setup.  Tell about
+       commit cvslog@quimby.gnus.org address.  Tell about subject prefix.
+       Tell about git-http-backend again.  Tell about the other commit
+       ding-commits@quimby.gnus.org address.
+
+2010-04-18  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * git.gnus.org/index.html: Fix 'comit' typos.
+
+2010-04-17  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * git.gnus.org/index.html: Added index.html for git.gnus.org.
diff --git a/xemacs-packages/gnus/www/git.gnus.org/gnus-cgit.png b/xemacs-packages/gnus/www/git.gnus.org/gnus-cgit.png
new file mode 100644 (file)
index 0000000..86c5ee9
Binary files /dev/null and b/xemacs-packages/gnus/www/git.gnus.org/gnus-cgit.png differ
diff --git a/xemacs-packages/gnus/www/git.gnus.org/gnus-icon.png b/xemacs-packages/gnus/www/git.gnus.org/gnus-icon.png
new file mode 100644 (file)
index 0000000..2a528b6
Binary files /dev/null and b/xemacs-packages/gnus/www/git.gnus.org/gnus-icon.png differ
diff --git a/xemacs-packages/gnus/www/git.gnus.org/index.html b/xemacs-packages/gnus/www/git.gnus.org/index.html
new file mode 100644 (file)
index 0000000..d841844
--- /dev/null
@@ -0,0 +1,77 @@
+<HTML> 
+<HEAD> 
+<link rel="icon" href="gnus-icon.png" type="image/png" />
+<TITLE>Gnus Git Repo</TITLE> 
+</HEAD> 
+<BODY>
+<a href="https://git.gnus.org/gnus.git">The writeable repository</a>
+<a href="/gnus.git">The read-only repository</a>
+<a href="/cgit/gnus.git/">A cgit web interface to the read-only repository</a>
+<hr>
+<a href="https://git.gnus.org/gnus-html.git">The writeable HTML repository</a>
+<a href="/gnus-html.git">The read-only HTML repository</a>
+<a href="/cgit/gnus-html.git/">A cgit web interface to the read-only HTML repository</a>
+
+<hr>
+Instructions for checking Gnus out:<p>
+    The server uses packed refs.  Make sure your version of Git
+    can handle them (1.7.0.4 and later definitely do).  
+<p>
+    <ul>
+      <li>Public access:<pre>git clone http://git.gnus.org/gnus.git</pre></li>
+      <li>Committer access (note the SSL certificate is signed with CACert.org and you <b>may</b> need to import their certificate bundle):
+        <i>(note: prepend <pre>GIT_SSL_NO_VERIFY=1 </pre> to each of the commands below to disable SSL verification if you can't import the CACert certificates.)</i>
+<pre>
+# this will print lots of debugging info
+GIT_CURL_VERBOSE=1 git clone https://git.gnus.org/gnus.git
+
+# this will be less verbose and probably OK
+git clone https://git.gnus.org/gnus.git
+
+# this will be necessary if you have to use a proxy
+HTTPS_PROXY=proxy.example.com:8080 git clone https://git.gnus.org/gnus.git
+
+# repeat the same steps for https://git.gnus.org/gnus-html.git if you want the HTML pages
+
+cd gnus
+       </pre>
+
+<pre>
+# if you needed GIT_SSL_NO_VERIFY above, do this to tell git not to check the certificate
+# DO NOT DO THIS UNLESS YOU ABSOLUTELY NEED IT!!!  git config http.sslVerify false
+</pre>
+
+       The committer should also have a <b>~/.netrc</b> file that says
+       <pre>machine git.gnus.org login yourlogin password yourpassword</pre>
+       <p>
+         If your password has a space in it or if you are a rebel,
+         use <pre>https://yourlogin:yourpassword@git.gnus.org/gnus.git</pre>
+         as the address and you won't need a <b>~/.netrc</b> file.
+         It's not recommended.
+       <p>
+         Also the server config says
+<pre>
+[receive]
+        denyDeletes = true
+        denyNonFastForwards = true
+</pre> 
+so that will, we hope, prevent unfortunate accidents.
+       <p>
+       Send e-mail
+       to <a href="mailto:tzz@lifelogs.com">tzz@lifelogs.com</a> to
+       get access, especially if you had CVS committer access
+       already.
+
+      </li>
+      <li>Server setup: Apache 2 using git-http-backend.  Commits go
+       to <b>cvslog@quimby.gnus.org</b>
+       and <b>ding-commits@quimby.gnus.org</b>, prefixed
+       with <b>[git] </b> and the envelope sender
+       is <b>git-logger</b>.  There are two (HTTP and HTTPS) Apache 2
+       servers but they both run git-http-backend so "smart" clients
+       are faster for committers and anonymous readers.
+      </li>
+    </ul>
+
+
+</BODY></HTML>